From 2e94dd8ab378fa01bd5a232da9a7cd48da9f0ec5 Mon Sep 17 00:00:00 2001 From: chyroc Date: Tue, 9 Jan 2024 14:45:48 +0800 Subject: [PATCH] feat: websocket callback event --- lark_ws/cache.go | 43 +++ lark_ws/client.go | 157 ++++++++ lark_ws/conn.go | 88 +++++ lark_ws/endpoint.go | 78 ++++ lark_ws/go.mod | 13 + lark_ws/go.sum | 39 ++ lark_ws/log.go | 39 ++ lark_ws/message.go | 153 ++++++++ lark_ws/pbbp2.pb.go | 893 ++++++++++++++++++++++++++++++++++++++++++++ lark_ws/response.go | 67 ++++ lark_ws/types.go | 71 ++++ lark_ws/version.go | 18 + 12 files changed, 1659 insertions(+) create mode 100644 lark_ws/cache.go create mode 100644 lark_ws/client.go create mode 100644 lark_ws/conn.go create mode 100644 lark_ws/endpoint.go create mode 100644 lark_ws/go.mod create mode 100644 lark_ws/go.sum create mode 100644 lark_ws/log.go create mode 100644 lark_ws/message.go create mode 100644 lark_ws/pbbp2.pb.go create mode 100644 lark_ws/response.go create mode 100644 lark_ws/types.go create mode 100644 lark_ws/version.go diff --git a/lark_ws/cache.go b/lark_ws/cache.go new file mode 100644 index 00000000..33743d5b --- /dev/null +++ b/lark_ws/cache.go @@ -0,0 +1,43 @@ +package lark_ws + +import ( + "sync" + "time" +) + +type cache struct { + values sync.Map +} + +func newCache() *cache { + return &cache{ + values: sync.Map{}, + } +} + +func (r *cache) get(key string) (interface{}, bool) { + val, ok := r.values.Load(key) + if !ok { + return nil, false + } + item := val.(*cacheItem) + if item.expired.Before(time.Now()) { + r.values.Delete(key) + return nil, false + } + return item.val, true +} + +func (r *cache) set(key string, val interface{}) { + r.values.Store(key, &cacheItem{ + val: val, + + // https://open.feishu.cn/document/server-docs/event-subscription-guide/overview + expired: time.Now().Add(time.Hour), + }) +} + +type cacheItem struct { + val interface{} + expired time.Time +} diff --git a/lark_ws/client.go b/lark_ws/client.go new file mode 100644 index 00000000..094c752f --- /dev/null +++ b/lark_ws/client.go @@ -0,0 +1,157 @@ +package lark_ws + +import ( + "context" + "fmt" + "math/rand" + "net/http" + "net/url" + "runtime/debug" + "strconv" + "sync" + "time" + + "github.com/chyroc/lark" + "github.com/gorilla/websocket" +) + +type Client struct { + Lark *lark.Lark + wsDialer *websocket.Dialer + conn *websocket.Conn + connURL *url.URL + serviceID string + connID string + autoReconnect bool // 是否自动重连,默认开启 + reconnectNonce int // 首次重连抖动,单位秒 + reconnectCount int // 重连次数,负数无限次 + reconnectInterval time.Duration // 重连间隔 + pingInterval time.Duration // Ping间隔 + cache *cache + mu sync.Mutex +} + +type ClientOption func(cli *Client) + +func WithAutoReconnect(b bool) ClientOption { + return func(cli *Client) { + cli.autoReconnect = b + } +} + +func New(larkCli *lark.Lark, opts ...ClientOption) *Client { + cli := &Client{ + Lark: larkCli, + wsDialer: &websocket.Dialer{ + Proxy: http.ProxyFromEnvironment, + HandshakeTimeout: 45 * time.Second, + }, + conn: nil, + connURL: nil, + serviceID: "", + connID: "", + autoReconnect: true, + reconnectNonce: 30, + reconnectCount: -1, + reconnectInterval: 2 * time.Minute, + pingInterval: 2 * time.Minute, + cache: newCache(), + mu: sync.Mutex{}, + } + + for _, opt := range opts { + opt(cli) + } + + return cli +} + +func (c *Client) Start(ctx context.Context) (err error) { + err = c.connect(ctx) + if err != nil { + c.logError(ctx, "connect failed, err: %s", err) + if !isRetryErr(err) { + return + } + c.disconnect(ctx) + if c.autoReconnect { + if err = c.reconnect(ctx); err != nil { + return err + } + } else { + return err + } + } + go c.pingLoop(ctx) + select {} +} + +func (c *Client) reconnect(ctx context.Context) (err error) { + // 首次重连随机抖动 + if c.reconnectNonce > 0 { + rand.Seed(time.Now().UnixNano()) + num := rand.Intn(c.reconnectNonce * 1000) + time.Sleep(time.Duration(num) * time.Millisecond) + } + + if c.reconnectCount >= 0 { + for i := 0; i < c.reconnectCount; i++ { + success, err := c.tryConnect(ctx, i) + if success || err != nil { + return err + } + time.Sleep(c.reconnectInterval) + } + return fmt.Errorf("unable to connect to server after %d retries", c.reconnectCount) + } else { + i := 0 + for { + success, err := c.tryConnect(ctx, i) + if success || err != nil { + return err + } + time.Sleep(c.reconnectInterval) + i += 1 + } + } +} + +func (c *Client) tryConnect(ctx context.Context, cnt int) (bool, error) { + c.logInfo(ctx, "trying to reconnect: %d", cnt+1) + err := c.connect(ctx) + if err == nil { + return true, nil + } else if !isRetryErr(err) { + return false, err + } else { + c.logError(ctx, "connect failed, err: %v", err) + return false, nil + } +} + +func (c *Client) pingLoop(ctx context.Context) { + defer func() { + if e := recover(); e != nil { + c.logWarn(ctx, "ping loop panic, panic: %v, stack: %s", e, string(debug.Stack())) + } + // TODO: 短时间内一直 panic, 退出 + go c.pingLoop(ctx) + }() + + for { + // TODO: 锁 + if c.conn != nil { + i, _ := strconv.ParseInt(c.serviceID, 10, 32) + frame := newPingFrame(int32(i)) + bs, _ := frame.Marshal() + + err := c.writeMessage(websocket.BinaryMessage, bs) + if err != nil { + c.logWarn(ctx, "ping failed, err: %v", err) + } else { + c.logDebug(ctx, "ping success") + } + } + time.Sleep(c.pingInterval) + } +} diff --git a/lark_ws/conn.go b/lark_ws/conn.go new file mode 100644 index 00000000..83f9f6aa --- /dev/null +++ b/lark_ws/conn.go @@ -0,0 +1,88 @@ +package lark_ws + +import ( + "context" + "errors" + "net/http" + "strconv" + + "github.com/chyroc/lark" +) + +func (c *Client) connect(ctx context.Context) (err error) { + c.mu.Lock() + defer c.mu.Unlock() + + if c.conn != nil { + return + } + + endpoint, err := c.getEndpoint(ctx) + if err != nil { + return + } + if err := c.saveURL(endpoint.URL); err != nil { + return err + } + c.saveClientConfig(endpoint.ClientConfig) + + conn, resp, err := c.wsDialer.Dial(endpoint.URL, nil) + if err != nil && resp == nil { + return err + } + if resp.StatusCode != http.StatusSwitchingProtocols { + return parseWebsocketErr("Callback", "ConnWebsocket", resp) + } + c.conn = conn + + c.logInfo(ctx, "connected to %s", endpoint.URL) + + go c.receiveMessageLoop(ctx) + + return +} + +func (c *Client) disconnect(ctx context.Context) { + c.mu.Lock() + defer c.mu.Unlock() + + if c.conn == nil { + return + } + + _ = c.conn.Close() + c.conn = nil + c.connURL = nil + c.connID = "" + c.serviceID = "" + c.logInfo(ctx, "disconnected to %s", c.connURL) +} + +const ( + codeForbidden = 403 + codeAuthFailed = 514 + codeExceedConnLimit = 1000040350 +) + +func isRetryErr(err error) bool { + var e *lark.Error + if errors.As(err, &e) { + return e.Code != codeForbidden && e.Code != codeExceedConnLimit + } + return true +} + +func parseWebsocketErr(scope, funcName string, resp *http.Response) error { + code, _ := strconv.ParseInt(resp.Header.Get("Handshake-Status"), 10, 64) + msg := resp.Header.Get("Handshake-Msg") + switch code { + case codeAuthFailed: + authCode, _ := strconv.ParseInt(resp.Header.Get("Handshake-Autherrcode"), 10, 64) + if authCode != 0 { + return lark.NewError(scope, funcName, authCode, msg) + } + return lark.NewError(scope, funcName, code, msg) + default: + return lark.NewError(scope, funcName, code, msg) + } +} diff --git a/lark_ws/endpoint.go b/lark_ws/endpoint.go new file mode 100644 index 00000000..c41025bc --- /dev/null +++ b/lark_ws/endpoint.go @@ -0,0 +1,78 @@ +package lark_ws + +import ( + "context" + "fmt" + "net/http" + "net/url" + "time" + + "github.com/chyroc/lark" +) + +// endpoint ... +type endpoint struct { + URL string `json:"URL,omitempty"` + ClientConfig *endpointClientConfig `json:"ClientConfig,omitempty"` +} + +// endpointClientConfig ... +type endpointClientConfig struct { + ReconnectCount int `json:"ReconnectCount,omitempty"` + ReconnectInterval int `json:"ReconnectInterval,omitempty"` + ReconnectNonce int `json:"ReconnectNonce,omitempty"` + PingInterval int `json:"PingInterval,omitempty"` +} + +func (c *Client) getEndpoint(ctx context.Context) (*endpoint, error) { + type GenerateCallbackWebsocketEndpointReq struct { + AppID string `json:"AppID,omitempty"` + AppSecret string `json:"AppSecret,omitempty"` + Locale string `query:"locale" json:"-"` + } + type GenerateCallbackWebsocketEndpointResp struct { + Code int64 `json:"code,omitempty"` + Msg string `json:"msg,omitempty"` + Data *endpoint `json:"data,omitempty"` + } + req := &lark.RawRequestReq{ + Scope: "Callback", + API: "GenerateCallbackWebsocketEndpoint", + Method: http.MethodPost, + URL: c.Lark.OpenBaseURL() + "/callback/ws/endpoint", + Body: GenerateCallbackWebsocketEndpointReq{ + AppID: c.Lark.AppID(), + AppSecret: c.Lark.AppSecret(), + Locale: "zh", + }, + MethodOption: &lark.MethodOption{}, + } + resp := &GenerateCallbackWebsocketEndpointResp{} + _, err := c.Lark.RawRequest(ctx, req, resp) + if err != nil { + return nil, err + } + return resp.Data, nil +} + +func (c *Client) saveURL(endpointURL string) error { + u, err := url.Parse(endpointURL) + if err != nil { + return fmt.Errorf("ws: invalid conn url: '%s'", endpointURL) + } + connID := u.Query().Get("device_id") + serviceID := u.Query().Get("service_id") + + c.connID = connID + c.serviceID = serviceID + c.connURL = u + + return nil +} + +func (c *Client) saveClientConfig(conf *endpointClientConfig) { + c.reconnectCount = conf.ReconnectCount + c.reconnectInterval = time.Duration(conf.ReconnectInterval) * time.Second + c.reconnectNonce = conf.ReconnectNonce + c.pingInterval = time.Duration(conf.PingInterval) * time.Second +} diff --git a/lark_ws/go.mod b/lark_ws/go.mod new file mode 100644 index 00000000..a894049d --- /dev/null +++ b/lark_ws/go.mod @@ -0,0 +1,13 @@ +module github.com/chyroc/lark/lark_ws + +go 1.20 + +replace github.com/chyroc/lark => ../ + +require ( + github.com/chyroc/lark v0.0.112 + github.com/gogo/protobuf v1.3.2 + github.com/gorilla/websocket v1.5.1 +) + +require golang.org/x/net v0.17.0 // indirect diff --git a/lark_ws/go.sum b/lark_ws/go.sum new file mode 100644 index 00000000..9eed687d --- /dev/null +++ b/lark_ws/go.sum @@ -0,0 +1,39 @@ +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= +github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= +golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/lark_ws/log.go b/lark_ws/log.go new file mode 100644 index 00000000..5cc54a49 --- /dev/null +++ b/lark_ws/log.go @@ -0,0 +1,39 @@ +package lark_ws + +import ( + "context" + + "github.com/chyroc/lark" +) + +func (c *Client) logError(ctx context.Context, msg string, args ...interface{}) { + if len(args) == 0 { + c.Lark.Log(ctx, lark.LogLevelError, "[lark] Websocket "+msg) + return + } + c.Lark.Log(ctx, lark.LogLevelError, "[lark] Websocket "+msg, args...) +} + +func (c *Client) logWarn(ctx context.Context, msg string, args ...interface{}) { + if len(args) == 0 { + c.Lark.Log(ctx, lark.LogLevelWarn, "[lark] Websocket "+msg) + return + } + c.Lark.Log(ctx, lark.LogLevelWarn, "[lark] Websocket "+msg, args...) +} + +func (c *Client) logInfo(ctx context.Context, msg string, args ...interface{}) { + if len(args) == 0 { + c.Lark.Log(ctx, lark.LogLevelInfo, "[lark] Websocket "+msg) + return + } + c.Lark.Log(ctx, lark.LogLevelInfo, "[lark] Websocket "+msg, args...) +} + +func (c *Client) logDebug(ctx context.Context, msg string, args ...interface{}) { + if len(args) == 0 { + c.Lark.Log(ctx, lark.LogLevelDebug, "[lark] Websocket "+msg) + return + } + c.Lark.Log(ctx, lark.LogLevelDebug, "[lark] Websocket "+msg, args...) +} diff --git a/lark_ws/message.go b/lark_ws/message.go new file mode 100644 index 00000000..1f46573e --- /dev/null +++ b/lark_ws/message.go @@ -0,0 +1,153 @@ +package lark_ws + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "runtime/debug" + "time" + + ws "github.com/gorilla/websocket" +) + +func (c *Client) receiveMessageLoop(ctx context.Context) { + defer func() { + if err := recover(); err != nil { + c.logError(ctx, "receive message loop panic, err: %v, stack: %s", err, string(debug.Stack())) + } + c.disconnect(ctx) + if c.autoReconnect { + if err := c.reconnect(ctx); err != nil { + c.logError(ctx, err.Error()) + } + } + }() + + for { + if c.conn == nil { + c.logError(ctx, "connection is closed, receive message loop exit") + return + } + + messageType, msg, err := c.conn.ReadMessage() + if err != nil { + c.logError(ctx, "receive message failed, err: %v", err) + return + } + + if messageType != ws.BinaryMessage { + c.logWarn(ctx, "receive unknown message, message_type: %d, message: %s", messageType, msg) + continue + } + + go c.handleMessage(ctx, msg) + } +} + +func (c *Client) handleMessage(ctx context.Context, msg []byte) { + defer func() { + if err := recover(); err != nil { + c.logError(ctx, "handle message panic, err: %v, stack: %s", err, string(debug.Stack())) + } + }() + + var frame Frame + if err := frame.Unmarshal(msg); err != nil { + c.logError(ctx, "unmarshal message failed, error: %v", err) + return + } + + switch frameType(frame.Method) { + case frameTypeControl: + c.handleControlFrame(ctx, frame) + case frameTypeData: + c.handleDataFrame(ctx, frame) + default: + } +} + +func (c *Client) handleControlFrame(ctx context.Context, frame Frame) { + hs := wsHeader(frame.Headers) + t := hs.GetString("type") + + switch messageType(t) { + case messageTypePong: + c.logDebug(ctx, "receive pong") + if len(frame.Payload) == 0 { + return + } + conf := &endpointClientConfig{} + if err := json.Unmarshal(frame.Payload, conf); err != nil { + c.logWarn(ctx, "unmarshal client config failed, err: %v", err) + return + } + c.saveClientConfig(conf) + default: + } +} + +func (c *Client) handleDataFrame(ctx context.Context, frame Frame) { + hs := wsHeader(frame.Headers) + sum := hs.GetInt("sum") // 拆包数, 未拆包为 1 + seq := hs.GetInt("seq") // 包序号, 未拆包为 0 + msgID := hs.GetString("message_id") + traceID := hs.GetString("trace_id") + type_ := hs.GetString("type") + + pl := frame.Payload + if sum > 1 { + if pl = c.combine(msgID, sum, seq, pl); pl == nil { + return + } + } + + c.logDebug(ctx, "receive message, message_type: %s, message_id: %s, trace_id: %s, payload: %s", type_, msgID, traceID, pl) + + start := time.Now().UnixMilli() + switch messageType(type_) { + case messageTypeEvent: + c.Lark.EventCallback.ListenCallback(ctx, bytes.NewReader(pl), c.newHTTPResponse(ctx, frame, start)) + case messageTypeCard: + c.Lark.EventCallback.ListenCallback(ctx, bytes.NewReader(pl), c.newHTTPResponse(ctx, frame, start)) + default: + return + } +} + +func (c *Client) combine(msgID string, sum, seq int, bs []byte) []byte { + val, ok := c.cache.get(msgID) + if !ok { + buf := make([][]byte, sum) + buf[seq] = bs + c.cache.set(msgID, buf) + return nil + } + + buf := val.([][]byte) + buf[seq] = bs + capacity := 0 + for _, v := range buf { + if len(v) == 0 { + c.cache.set(msgID, buf) + return nil + } + capacity += len(v) + } + + pl := make([]byte, 0, capacity) + for _, v := range buf { + pl = append(pl, v...) + } + + return pl +} + +func (c *Client) writeMessage(messageType int, data []byte) error { + c.mu.Lock() + defer c.mu.Unlock() + if c.conn == nil { + return fmt.Errorf("connection is closed") + } + return c.conn.WriteMessage(messageType, data) +} diff --git a/lark_ws/pbbp2.pb.go b/lark_ws/pbbp2.pb.go new file mode 100644 index 00000000..e00a0cf0 --- /dev/null +++ b/lark_ws/pbbp2.pb.go @@ -0,0 +1,893 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: pbbp2.proto + +package lark_ws + +import ( + fmt "fmt" + io "io" + math "math" + math_bits "math/bits" + + _ "github.com/gogo/protobuf/gogoproto" + github_com_gogo_protobuf_proto "github.com/gogo/protobuf/proto" + proto "github.com/gogo/protobuf/proto" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +type Header struct { + Key string `protobuf:"bytes,1,req,name=key" json:"key"` + Value string `protobuf:"bytes,2,req,name=value" json:"value"` +} + +func (m *Header) Reset() { *m = Header{} } +func (m *Header) String() string { return proto.CompactTextString(m) } +func (*Header) ProtoMessage() {} +func (*Header) Descriptor() ([]byte, []int) { + return fileDescriptor_05d5aa6290a36d5d, []int{0} +} +func (m *Header) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Header) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Header.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *Header) XXX_Merge(src proto.Message) { + xxx_messageInfo_Header.Merge(m, src) +} +func (m *Header) XXX_Size() int { + return m.Size() +} +func (m *Header) XXX_DiscardUnknown() { + xxx_messageInfo_Header.DiscardUnknown(m) +} + +var xxx_messageInfo_Header proto.InternalMessageInfo + +func (m *Header) GetKey() string { + if m != nil { + return m.Key + } + return "" +} + +func (m *Header) GetValue() string { + if m != nil { + return m.Value + } + return "" +} + +// message frame +type Frame struct { + SeqID uint64 `protobuf:"varint,1,req,name=SeqID" json:"SeqID"` + LogID uint64 `protobuf:"varint,2,req,name=LogID" json:"LogID"` + Service int32 `protobuf:"varint,3,req,name=service" json:"service"` + Method int32 `protobuf:"varint,4,req,name=method" json:"method"` + Headers []Header `protobuf:"bytes,5,rep,name=headers" json:"headers"` + PayloadEncoding string `protobuf:"bytes,6,opt,name=payload_encoding" json:"payload_encoding"` + PayloadType string `protobuf:"bytes,7,opt,name=payload_type" json:"payload_type"` + Payload []byte `protobuf:"bytes,8,opt,name=payload" json:"payload"` + LogIDNew string `protobuf:"bytes,9,opt,name=LogIDNew" json:"LogIDNew"` +} + +func (m *Frame) Reset() { *m = Frame{} } +func (m *Frame) String() string { return proto.CompactTextString(m) } +func (*Frame) ProtoMessage() {} +func (*Frame) Descriptor() ([]byte, []int) { + return fileDescriptor_05d5aa6290a36d5d, []int{1} +} +func (m *Frame) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Frame) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Frame.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *Frame) XXX_Merge(src proto.Message) { + xxx_messageInfo_Frame.Merge(m, src) +} +func (m *Frame) XXX_Size() int { + return m.Size() +} +func (m *Frame) XXX_DiscardUnknown() { + xxx_messageInfo_Frame.DiscardUnknown(m) +} + +var xxx_messageInfo_Frame proto.InternalMessageInfo + +func (m *Frame) GetSeqID() uint64 { + if m != nil { + return m.SeqID + } + return 0 +} + +func (m *Frame) GetLogID() uint64 { + if m != nil { + return m.LogID + } + return 0 +} + +func (m *Frame) GetService() int32 { + if m != nil { + return m.Service + } + return 0 +} + +func (m *Frame) GetMethod() int32 { + if m != nil { + return m.Method + } + return 0 +} + +func (m *Frame) GetHeaders() []Header { + if m != nil { + return m.Headers + } + return nil +} + +func (m *Frame) GetPayloadEncoding() string { + if m != nil { + return m.PayloadEncoding + } + return "" +} + +func (m *Frame) GetPayloadType() string { + if m != nil { + return m.PayloadType + } + return "" +} + +func (m *Frame) GetPayload() []byte { + if m != nil { + return m.Payload + } + return nil +} + +func (m *Frame) GetLogIDNew() string { + if m != nil { + return m.LogIDNew + } + return "" +} + +func init() { + proto.RegisterType((*Header)(nil), "pbbp2.Header") + proto.RegisterType((*Frame)(nil), "pbbp2.Frame") +} + +func init() { proto.RegisterFile("pbbp2.proto", fileDescriptor_05d5aa6290a36d5d) } + +var fileDescriptor_05d5aa6290a36d5d = []byte{ + // 266 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x2e, 0x48, 0x4a, 0x2a, + 0x30, 0xd2, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0x05, 0x73, 0xa4, 0xb8, 0xd2, 0xf3, 0xd3, + 0xf3, 0x21, 0x42, 0x4a, 0x06, 0x5c, 0x6c, 0x1e, 0xa9, 0x89, 0x29, 0xa9, 0x45, 0x42, 0x82, 0x5c, + 0xcc, 0xd9, 0xa9, 0x95, 0x12, 0x8c, 0x0a, 0x4c, 0x1a, 0x9c, 0x4e, 0x2c, 0x27, 0xee, 0xc9, 0x33, + 0x08, 0x09, 0x73, 0xb1, 0x96, 0x25, 0xe6, 0x94, 0xa6, 0x4a, 0x30, 0x21, 0x04, 0x95, 0xde, 0x33, + 0x72, 0xb1, 0xba, 0x15, 0x25, 0xe6, 0xa6, 0x82, 0xa4, 0x83, 0x53, 0x0b, 0x3d, 0x5d, 0xc0, 0x7a, + 0x58, 0x10, 0x7a, 0x7c, 0xf2, 0xd3, 0x3d, 0x5d, 0xc0, 0x7a, 0x60, 0x82, 0xa2, 0x5c, 0xec, 0xc5, + 0xa9, 0x45, 0x65, 0x99, 0xc9, 0xa9, 0x12, 0xcc, 0x0a, 0x4c, 0x1a, 0xac, 0x50, 0x61, 0x11, 0x2e, + 0xb6, 0xdc, 0xd4, 0x92, 0x8c, 0xfc, 0x14, 0x09, 0x16, 0x24, 0x51, 0x15, 0x2e, 0xf6, 0x0c, 0xb0, + 0x93, 0x8a, 0x25, 0x58, 0x15, 0x98, 0x35, 0xb8, 0x8d, 0x78, 0xf5, 0x20, 0x9e, 0x80, 0x38, 0x14, + 0xaa, 0x4a, 0x8e, 0x4b, 0xa0, 0x20, 0xb1, 0x32, 0x27, 0x3f, 0x31, 0x25, 0x3e, 0x35, 0x2f, 0x39, + 0x3f, 0x25, 0x33, 0x2f, 0x5d, 0x82, 0x4d, 0x81, 0x11, 0xee, 0x76, 0x29, 0x2e, 0x1e, 0x98, 0x7c, + 0x49, 0x65, 0x41, 0xaa, 0x04, 0x3b, 0x92, 0x9c, 0x28, 0x17, 0x3b, 0x54, 0x4e, 0x82, 0x43, 0x81, + 0x51, 0x83, 0x07, 0x2a, 0x2c, 0xc6, 0xc5, 0x01, 0x76, 0xba, 0x5f, 0x6a, 0xb9, 0x04, 0x27, 0x42, + 0xb9, 0x93, 0xc4, 0x89, 0x47, 0x72, 0x8c, 0x17, 0x1e, 0xc9, 0x31, 0x3e, 0x78, 0x24, 0xc7, 0x38, + 0xe1, 0xb1, 0x1c, 0xc3, 0x85, 0xc7, 0x72, 0x0c, 0x37, 0x1e, 0xcb, 0x31, 0x00, 0x02, 0x00, 0x00, + 0xff, 0xff, 0x8b, 0x46, 0x71, 0x52, 0x5e, 0x01, 0x00, 0x00, +} + +func (m *Header) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Header) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Header) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + i -= len(m.Value) + copy(dAtA[i:], m.Value) + i = encodeVarintPbbp2(dAtA, i, uint64(len(m.Value))) + i-- + dAtA[i] = 0x12 + i -= len(m.Key) + copy(dAtA[i:], m.Key) + i = encodeVarintPbbp2(dAtA, i, uint64(len(m.Key))) + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *Frame) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Frame) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Frame) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + i -= len(m.LogIDNew) + copy(dAtA[i:], m.LogIDNew) + i = encodeVarintPbbp2(dAtA, i, uint64(len(m.LogIDNew))) + i-- + dAtA[i] = 0x4a + if m.Payload != nil { + i -= len(m.Payload) + copy(dAtA[i:], m.Payload) + i = encodeVarintPbbp2(dAtA, i, uint64(len(m.Payload))) + i-- + dAtA[i] = 0x42 + } + i -= len(m.PayloadType) + copy(dAtA[i:], m.PayloadType) + i = encodeVarintPbbp2(dAtA, i, uint64(len(m.PayloadType))) + i-- + dAtA[i] = 0x3a + i -= len(m.PayloadEncoding) + copy(dAtA[i:], m.PayloadEncoding) + i = encodeVarintPbbp2(dAtA, i, uint64(len(m.PayloadEncoding))) + i-- + dAtA[i] = 0x32 + if len(m.Headers) > 0 { + for iNdEx := len(m.Headers) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Headers[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintPbbp2(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x2a + } + } + i = encodeVarintPbbp2(dAtA, i, uint64(m.Method)) + i-- + dAtA[i] = 0x20 + i = encodeVarintPbbp2(dAtA, i, uint64(m.Service)) + i-- + dAtA[i] = 0x18 + i = encodeVarintPbbp2(dAtA, i, uint64(m.LogID)) + i-- + dAtA[i] = 0x10 + i = encodeVarintPbbp2(dAtA, i, uint64(m.SeqID)) + i-- + dAtA[i] = 0x8 + return len(dAtA) - i, nil +} + +func encodeVarintPbbp2(dAtA []byte, offset int, v uint64) int { + offset -= sovPbbp2(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *Header) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Key) + n += 1 + l + sovPbbp2(uint64(l)) + l = len(m.Value) + n += 1 + l + sovPbbp2(uint64(l)) + return n +} + +func (m *Frame) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + n += 1 + sovPbbp2(uint64(m.SeqID)) + n += 1 + sovPbbp2(uint64(m.LogID)) + n += 1 + sovPbbp2(uint64(m.Service)) + n += 1 + sovPbbp2(uint64(m.Method)) + if len(m.Headers) > 0 { + for _, e := range m.Headers { + l = e.Size() + n += 1 + l + sovPbbp2(uint64(l)) + } + } + l = len(m.PayloadEncoding) + n += 1 + l + sovPbbp2(uint64(l)) + l = len(m.PayloadType) + n += 1 + l + sovPbbp2(uint64(l)) + if m.Payload != nil { + l = len(m.Payload) + n += 1 + l + sovPbbp2(uint64(l)) + } + l = len(m.LogIDNew) + n += 1 + l + sovPbbp2(uint64(l)) + return n +} + +func sovPbbp2(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozPbbp2(x uint64) (n int) { + return sovPbbp2(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *Header) Unmarshal(dAtA []byte) error { + var hasFields [1]uint64 + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPbbp2 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Header: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Header: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Key", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPbbp2 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthPbbp2 + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthPbbp2 + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Key = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + hasFields[0] |= uint64(0x00000001) + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Value", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPbbp2 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthPbbp2 + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthPbbp2 + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Value = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + hasFields[0] |= uint64(0x00000002) + default: + iNdEx = preIndex + skippy, err := skipPbbp2(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthPbbp2 + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + if hasFields[0]&uint64(0x00000001) == 0 { + return github_com_gogo_protobuf_proto.NewRequiredNotSetError("key") + } + if hasFields[0]&uint64(0x00000002) == 0 { + return github_com_gogo_protobuf_proto.NewRequiredNotSetError("value") + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Frame) Unmarshal(dAtA []byte) error { + var hasFields [1]uint64 + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPbbp2 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Frame: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Frame: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field SeqID", wireType) + } + m.SeqID = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPbbp2 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.SeqID |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + hasFields[0] |= uint64(0x00000001) + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field LogID", wireType) + } + m.LogID = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPbbp2 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.LogID |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + hasFields[0] |= uint64(0x00000002) + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Service", wireType) + } + m.Service = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPbbp2 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Service |= int32(b&0x7F) << shift + if b < 0x80 { + break + } + } + hasFields[0] |= uint64(0x00000004) + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Method", wireType) + } + m.Method = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPbbp2 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Method |= int32(b&0x7F) << shift + if b < 0x80 { + break + } + } + hasFields[0] |= uint64(0x00000008) + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Headers", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPbbp2 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthPbbp2 + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthPbbp2 + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Headers = append(m.Headers, Header{}) + if err := m.Headers[len(m.Headers)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PayloadEncoding", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPbbp2 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthPbbp2 + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthPbbp2 + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.PayloadEncoding = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PayloadType", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPbbp2 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthPbbp2 + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthPbbp2 + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.PayloadType = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 8: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Payload", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPbbp2 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthPbbp2 + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthPbbp2 + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Payload = append(m.Payload[:0], dAtA[iNdEx:postIndex]...) + if m.Payload == nil { + m.Payload = []byte{} + } + iNdEx = postIndex + case 9: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field LogIDNew", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPbbp2 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthPbbp2 + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthPbbp2 + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.LogIDNew = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipPbbp2(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthPbbp2 + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + if hasFields[0]&uint64(0x00000001) == 0 { + return github_com_gogo_protobuf_proto.NewRequiredNotSetError("SeqID") + } + if hasFields[0]&uint64(0x00000002) == 0 { + return github_com_gogo_protobuf_proto.NewRequiredNotSetError("LogID") + } + if hasFields[0]&uint64(0x00000004) == 0 { + return github_com_gogo_protobuf_proto.NewRequiredNotSetError("service") + } + if hasFields[0]&uint64(0x00000008) == 0 { + return github_com_gogo_protobuf_proto.NewRequiredNotSetError("method") + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipPbbp2(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowPbbp2 + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowPbbp2 + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowPbbp2 + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthPbbp2 + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupPbbp2 + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthPbbp2 + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthPbbp2 = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowPbbp2 = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupPbbp2 = fmt.Errorf("proto: unexpected end of group") +) diff --git a/lark_ws/response.go b/lark_ws/response.go new file mode 100644 index 00000000..f28156aa --- /dev/null +++ b/lark_ws/response.go @@ -0,0 +1,67 @@ +package lark_ws + +import ( + "context" + "encoding/json" + "net/http" + "strconv" + "time" + + "github.com/gorilla/websocket" +) + +type httpResponse struct { + c *Client + ctx context.Context + frame Frame + start int64 + status int +} + +func (c *Client) newHTTPResponse(ctx context.Context, frame Frame, start int64) *httpResponse { + return &httpResponse{ + c: c, + ctx: ctx, + frame: frame, + start: start, + status: http.StatusOK, + } +} + +func (r *httpResponse) Header() http.Header { + return http.Header{} +} + +func (r *httpResponse) Write(bytes []byte) (int, error) { + return r.writeToWebsocket(bytes) +} + +func (r *httpResponse) WriteHeader(statusCode int) { + r.status = statusCode +} + +func (r *httpResponse) writeToWebsocket(bs []byte) (int, error) { + hs := wsHeader(r.frame.Headers) + msgID := hs.GetString("message_id") + traceID := hs.GetString("trace_id") + type_ := hs.GetString("type") + + frame := r.frame + end := time.Now().UnixMilli() + hs.Add("biz_rt", strconv.FormatInt(end-r.start, 10)) // 业务处理耗时, ms + + resp := &responseMessage{ + StatusCode: r.status, + Data: bs, + } + p, _ := json.Marshal(resp) + frame.Payload = p + frame.Headers = hs + bs, _ = frame.Marshal() + err := r.c.writeMessage(websocket.BinaryMessage, bs) + if err != nil { + r.c.logError(r.ctx, "response message failed, type: %s, message_id: %s, trace_id: %s, err: %v", type_, msgID, traceID, err) + return 0, err + } + return len(bs), nil +} diff --git a/lark_ws/types.go b/lark_ws/types.go new file mode 100644 index 00000000..42f5fc7c --- /dev/null +++ b/lark_ws/types.go @@ -0,0 +1,71 @@ +package lark_ws + +import "strconv" + +type messageType string + +const ( + messageTypeEvent messageType = "event" + messageTypeCard messageType = "card" + messageTypePing messageType = "ping" + messageTypePong messageType = "pong" +) + +type frameType int + +const ( + frameTypeControl frameType = 0 + frameTypeData frameType = 1 +) + +type wsHeader []Header + +func (h wsHeader) GetString(key string) string { + for _, header := range h { + if header.Key == key { + return header.Value + } + } + + return "" +} + +func (h wsHeader) GetInt(key string) int { + for _, header := range h { + if header.Key == key { + if val, err := strconv.Atoi(header.Value); err == nil { + return val + } + } + } + + return 0 +} + +func (h *wsHeader) Add(key, value string) { + header := Header{ + Key: key, + Value: value, + } + *h = append(*h, header) +} + +// responseMessage 上行响应消息结构, 置于 Frame.Payload +type responseMessage struct { + StatusCode int `json:"code"` + Headers map[string]string `json:"headers"` + Data []byte `json:"data"` +} + +func newPingFrame(serviceID int32) *Frame { + return &Frame{ + Method: int32(frameTypeControl), + Service: serviceID, + Headers: []Header{ + { + Key: "type", + Value: string(messageTypePing), + }, + }, + } +} diff --git a/lark_ws/version.go b/lark_ws/version.go new file mode 100644 index 00000000..0ef6f603 --- /dev/null +++ b/lark_ws/version.go @@ -0,0 +1,18 @@ +/** + * Copyright 2022 chyroc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package lark_ws + +const version = "v0.0.1"