github.com/machinefi/w3bstream@v1.6.5-rc9.0.20240426031326-b8c7c4876e72/pkg/modules/robot_notifier/lark/notify_message.go (about) 1 package lark 2 3 import ( 4 "context" 5 "encoding/json" 6 "fmt" 7 "os" 8 "strings" 9 "time" 10 11 "github.com/mitchellh/mapstructure" 12 "github.com/pkg/errors" 13 14 "github.com/machinefi/w3bstream/pkg/depends/base/consts" 15 "github.com/machinefi/w3bstream/pkg/types" 16 ) 17 18 type Content struct { 19 Post map[string]ContentBody `json:"post"` 20 } 21 22 type ContentBody struct { 23 Title string `json:"title"` 24 ContentElements [][]map[string]interface{} `json:"content"` 25 } 26 27 func TagElementToMap(e TagElement) (map[string]interface{}, error) { 28 ret := map[string]interface{}{"tag": e.Tag()} 29 30 err := mapstructure.Decode(e, &ret) 31 if err != nil { 32 return nil, err 33 } 34 return ret, nil 35 } 36 37 func TagElementsToMap(elem ...TagElement) ([][]map[string]interface{}, error) { 38 ms := make([][]map[string]interface{}, 0, len(elem)) 39 for _, e := range elem { 40 m, err := TagElementToMap(e) 41 if err != nil { 42 return nil, err 43 } 44 ms = append(ms, []map[string]interface{}{m}) 45 } 46 return ms, nil 47 } 48 49 type TagElement interface { 50 Tag() string 51 } 52 53 type ElementImg struct { 54 ImageKey string `mapstructure:"image_key"` 55 W int `mapstructure:"width"` 56 H int `mapstructure:"height"` 57 } 58 59 func (v *ElementImg) Tag() string { return "img" } 60 61 type ElementText struct { 62 Text string `mapstructure:"text"` 63 } 64 65 func (v *ElementText) Tag() string { return "text" } 66 67 type ElementHref struct { 68 Text string `mapstructure:"text"` 69 Ref string `mapstructure:"href"` 70 } 71 72 func (v *ElementHref) Tag() string { return "a" } 73 74 type ElementPin struct { 75 UserID string `mapstructure:"user_id"` 76 } 77 78 func (v *ElementPin) Tag() string { return "at" } 79 80 func Build(ctx context.Context, title, level, content string) ([]byte, error) { 81 notifier, _ := types.RobotNotifierConfigFromContext(ctx) 82 if notifier == nil { 83 return nil, nil 84 } 85 ts := time.Now().UTC().Unix() 86 sign := "" 87 if notifier.SignFn != nil { 88 signature, err := notifier.SignFn(ts) 89 if err != nil { 90 return nil, errors.Wrap(err, "signature") 91 } 92 sign = signature 93 } 94 95 ms, err := TagElementsToMap( 96 &ElementText{ 97 Text: fmt.Sprintf("env: %s", notifier.Env), 98 }, 99 &ElementText{ 100 Text: fmt.Sprintf("project: %s", os.Getenv(consts.EnvProjectName)), 101 }, 102 &ElementText{ 103 Text: fmt.Sprintf("version: %s", os.Getenv(consts.EnvProjectVersion)), 104 }, 105 &ElementText{ 106 Text: content, 107 }, 108 ) 109 if err != nil { 110 return nil, errors.Wrap(err, "mapstructure") 111 } 112 113 msg := &struct { 114 Timestamp int64 `json:"timestamp,omitempty"` 115 Sign string `json:"sign,omitempty"` 116 MessageType string `json:"msg_type"` 117 Content Content `json:"content"` 118 }{ 119 Timestamp: ts, 120 Sign: sign, 121 MessageType: "post", 122 Content: Content{ 123 Post: map[string]ContentBody{ 124 "en_ch": { 125 Title: fmt.Sprintf("%s [%s]", strings.ToUpper(level), title), 126 ContentElements: ms, 127 }, 128 }, 129 }, 130 } 131 132 return json.Marshal(msg) 133 } 134 135 func ResponseHook(body []byte) error { 136 if len(body) == 0 { 137 return nil 138 } 139 140 v := &struct { 141 Code int `json:"code"` 142 Msg string `json:"msg"` 143 }{} 144 145 err := json.Unmarshal(body, v) 146 if err != nil { 147 return err 148 } 149 150 switch v.Code { 151 case 19021: 152 return ErrInvalidSignature 153 case 9499: 154 return ErrInvalidMessage 155 default: 156 if v.Code == 0 { 157 return nil 158 } else { 159 return errors.Errorf("code: %d, msg: %s", v.Code, v.Msg) 160 } 161 } 162 } 163 164 var ( 165 ErrInvalidMessage = errors.New("invalid message") 166 ErrInvalidSignature = errors.New("invalid signature") 167 )