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  )