From 3b6d4a667157919362ca5402dad5440225d9a440 Mon Sep 17 00:00:00 2001 From: Mrs4s Date: Thu, 16 Sep 2021 15:32:39 +0800 Subject: [PATCH] feat: GetUnidirectionalFriendList. --- client/client.go | 5 +- client/network.go | 55 ++-- client/pb/web/WebSsoBody.pb.go | 510 +++++++++++++++++++++++++++++++++ client/pb/web/WebSsoBody.proto | 36 +++ client/web.go | 85 ++++++ go.mod | 4 +- go.sum | 8 + 7 files changed, 684 insertions(+), 19 deletions(-) create mode 100644 client/pb/web/WebSsoBody.pb.go create mode 100644 client/pb/web/WebSsoBody.proto create mode 100644 client/web.go diff --git a/client/client.go b/client/client.go index e61008b1..8946199d 100644 --- a/client/client.go +++ b/client/client.go @@ -142,8 +142,9 @@ type QiDianAccountInfo struct { } type handlerInfo struct { - fun func(i interface{}, err error) - params requestParams + fun func(i interface{}, err error) + dynamic bool + params requestParams } var decoders = map[string]func(*QQClient, *incomingPacketInfo, []byte) (interface{}, error){ diff --git a/client/network.go b/client/network.go index aff3e8e8..bc310abd 100644 --- a/client/network.go +++ b/client/network.go @@ -92,7 +92,7 @@ func (c *QQClient) sendAndWait(seq uint16, pkt []byte, params ...requestParams) Response: i, Error: err, } - }, params: p}) + }, params: p, dynamic: false}) err := c.sendPacket(pkt) if err != nil { @@ -138,6 +138,25 @@ func (c *QQClient) waitPacket(cmd string, f func(interface{}, error)) func() { } } +// sendAndWaitDynamic +// 发送数据包并返回需要解析的 response +func (c *QQClient) sendAndWaitDynamic(seq uint16, pkt []byte) ([]byte, error) { + ch := make(chan []byte, 1) + c.handlers.Store(seq, &handlerInfo{fun: func(i interface{}, err error) { ch <- i.([]byte) }, dynamic: true}) + err := c.sendPacket(pkt) + if err != nil { + c.handlers.Delete(seq) + return nil, err + } + select { + case rsp := <-ch: + return rsp, nil + case <-time.After(time.Second * 15): + c.handlers.Delete(seq) + return nil, errors.New("Packet timed out") + } +} + // plannedDisconnect 计划中断线事件 func (c *QQClient) plannedDisconnect(_ *utils.TCPListener) { c.Debug("planned disconnect.") @@ -208,27 +227,31 @@ func (c *QQClient) netLoop() { if decoder, ok := decoders[pkt.CommandName]; ok { // found predefined decoder info, ok := c.handlers.LoadAndDelete(pkt.SequenceId) - rsp, err := decoder(c, &incomingPacketInfo{ - SequenceId: pkt.SequenceId, - CommandName: pkt.CommandName, - Params: func() requestParams { - if !ok { - return nil - } - return info.params - }(), - }, pkt.Payload) - if err != nil { - c.Debug("decode pkt %v error: %+v", pkt.CommandName, err) + var decoded interface{} + decoded = pkt.Payload + if info != nil && !info.dynamic { + decoded, err = decoder(c, &incomingPacketInfo{ + SequenceId: pkt.SequenceId, + CommandName: pkt.CommandName, + Params: func() requestParams { + if !ok { + return nil + } + return info.params + }(), + }, pkt.Payload) + if err != nil { + c.Debug("decode pkt %v error: %+v", pkt.CommandName, err) + } } if ok { - info.fun(rsp, err) + info.fun(decoded, err) } else if f, ok := c.waiters.Load(pkt.CommandName); ok { // 在不存在handler的情况下触发wait - f.(func(interface{}, error))(rsp, err) + f.(func(interface{}, error))(decoded, err) } } else if f, ok := c.handlers.LoadAndDelete(pkt.SequenceId); ok { // does not need decoder - f.fun(nil, nil) + f.fun(pkt.Payload, nil) } else { c.Debug("Unhandled Command: %s\nSeq: %d\nThis message can be ignored.", pkt.CommandName, pkt.SequenceId) } diff --git a/client/pb/web/WebSsoBody.pb.go b/client/pb/web/WebSsoBody.pb.go new file mode 100644 index 00000000..6f50226e --- /dev/null +++ b/client/pb/web/WebSsoBody.pb.go @@ -0,0 +1,510 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.27.1 +// protoc v3.14.0 +// source: WebSsoBody.proto + +package web + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type STServiceMonitItem struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Cmd *string `protobuf:"bytes,1,opt,name=cmd" json:"cmd,omitempty"` + Url *string `protobuf:"bytes,2,opt,name=url" json:"url,omitempty"` + Errcode *int32 `protobuf:"varint,3,opt,name=errcode" json:"errcode,omitempty"` + Cost *uint32 `protobuf:"varint,4,opt,name=cost" json:"cost,omitempty"` + Src *uint32 `protobuf:"varint,5,opt,name=src" json:"src,omitempty"` +} + +func (x *STServiceMonitItem) Reset() { + *x = STServiceMonitItem{} + if protoimpl.UnsafeEnabled { + mi := &file_WebSsoBody_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *STServiceMonitItem) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*STServiceMonitItem) ProtoMessage() {} + +func (x *STServiceMonitItem) ProtoReflect() protoreflect.Message { + mi := &file_WebSsoBody_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use STServiceMonitItem.ProtoReflect.Descriptor instead. +func (*STServiceMonitItem) Descriptor() ([]byte, []int) { + return file_WebSsoBody_proto_rawDescGZIP(), []int{0} +} + +func (x *STServiceMonitItem) GetCmd() string { + if x != nil && x.Cmd != nil { + return *x.Cmd + } + return "" +} + +func (x *STServiceMonitItem) GetUrl() string { + if x != nil && x.Url != nil { + return *x.Url + } + return "" +} + +func (x *STServiceMonitItem) GetErrcode() int32 { + if x != nil && x.Errcode != nil { + return *x.Errcode + } + return 0 +} + +func (x *STServiceMonitItem) GetCost() uint32 { + if x != nil && x.Cost != nil { + return *x.Cost + } + return 0 +} + +func (x *STServiceMonitItem) GetSrc() uint32 { + if x != nil && x.Src != nil { + return *x.Src + } + return 0 +} + +type STServiceMonitReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + List []*STServiceMonitItem `protobuf:"bytes,1,rep,name=list" json:"list,omitempty"` +} + +func (x *STServiceMonitReq) Reset() { + *x = STServiceMonitReq{} + if protoimpl.UnsafeEnabled { + mi := &file_WebSsoBody_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *STServiceMonitReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*STServiceMonitReq) ProtoMessage() {} + +func (x *STServiceMonitReq) ProtoReflect() protoreflect.Message { + mi := &file_WebSsoBody_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use STServiceMonitReq.ProtoReflect.Descriptor instead. +func (*STServiceMonitReq) Descriptor() ([]byte, []int) { + return file_WebSsoBody_proto_rawDescGZIP(), []int{1} +} + +func (x *STServiceMonitReq) GetList() []*STServiceMonitItem { + if x != nil { + return x.List + } + return nil +} + +type WebSsoControlData struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Frequency *uint32 `protobuf:"varint,1,opt,name=frequency" json:"frequency,omitempty"` + PackageSize *uint32 `protobuf:"varint,2,opt,name=packageSize" json:"packageSize,omitempty"` +} + +func (x *WebSsoControlData) Reset() { + *x = WebSsoControlData{} + if protoimpl.UnsafeEnabled { + mi := &file_WebSsoBody_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *WebSsoControlData) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*WebSsoControlData) ProtoMessage() {} + +func (x *WebSsoControlData) ProtoReflect() protoreflect.Message { + mi := &file_WebSsoBody_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use WebSsoControlData.ProtoReflect.Descriptor instead. +func (*WebSsoControlData) Descriptor() ([]byte, []int) { + return file_WebSsoBody_proto_rawDescGZIP(), []int{2} +} + +func (x *WebSsoControlData) GetFrequency() uint32 { + if x != nil && x.Frequency != nil { + return *x.Frequency + } + return 0 +} + +func (x *WebSsoControlData) GetPackageSize() uint32 { + if x != nil && x.PackageSize != nil { + return *x.PackageSize + } + return 0 +} + +type WebSsoRequestBody struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Version *uint32 `protobuf:"varint,1,opt,name=version" json:"version,omitempty"` + Type *uint32 `protobuf:"varint,2,opt,name=type" json:"type,omitempty"` + Data *string `protobuf:"bytes,3,opt,name=data" json:"data,omitempty"` + WebData *string `protobuf:"bytes,4,opt,name=webData" json:"webData,omitempty"` +} + +func (x *WebSsoRequestBody) Reset() { + *x = WebSsoRequestBody{} + if protoimpl.UnsafeEnabled { + mi := &file_WebSsoBody_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *WebSsoRequestBody) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*WebSsoRequestBody) ProtoMessage() {} + +func (x *WebSsoRequestBody) ProtoReflect() protoreflect.Message { + mi := &file_WebSsoBody_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use WebSsoRequestBody.ProtoReflect.Descriptor instead. +func (*WebSsoRequestBody) Descriptor() ([]byte, []int) { + return file_WebSsoBody_proto_rawDescGZIP(), []int{3} +} + +func (x *WebSsoRequestBody) GetVersion() uint32 { + if x != nil && x.Version != nil { + return *x.Version + } + return 0 +} + +func (x *WebSsoRequestBody) GetType() uint32 { + if x != nil && x.Type != nil { + return *x.Type + } + return 0 +} + +func (x *WebSsoRequestBody) GetData() string { + if x != nil && x.Data != nil { + return *x.Data + } + return "" +} + +func (x *WebSsoRequestBody) GetWebData() string { + if x != nil && x.WebData != nil { + return *x.WebData + } + return "" +} + +type WebSsoResponseBody struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Version *uint32 `protobuf:"varint,1,opt,name=version" json:"version,omitempty"` + Type *uint32 `protobuf:"varint,2,opt,name=type" json:"type,omitempty"` + Ret *uint32 `protobuf:"varint,3,opt,name=ret" json:"ret,omitempty"` + Data *string `protobuf:"bytes,4,opt,name=data" json:"data,omitempty"` + ControlData *WebSsoControlData `protobuf:"bytes,5,opt,name=controlData" json:"controlData,omitempty"` +} + +func (x *WebSsoResponseBody) Reset() { + *x = WebSsoResponseBody{} + if protoimpl.UnsafeEnabled { + mi := &file_WebSsoBody_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *WebSsoResponseBody) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*WebSsoResponseBody) ProtoMessage() {} + +func (x *WebSsoResponseBody) ProtoReflect() protoreflect.Message { + mi := &file_WebSsoBody_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use WebSsoResponseBody.ProtoReflect.Descriptor instead. +func (*WebSsoResponseBody) Descriptor() ([]byte, []int) { + return file_WebSsoBody_proto_rawDescGZIP(), []int{4} +} + +func (x *WebSsoResponseBody) GetVersion() uint32 { + if x != nil && x.Version != nil { + return *x.Version + } + return 0 +} + +func (x *WebSsoResponseBody) GetType() uint32 { + if x != nil && x.Type != nil { + return *x.Type + } + return 0 +} + +func (x *WebSsoResponseBody) GetRet() uint32 { + if x != nil && x.Ret != nil { + return *x.Ret + } + return 0 +} + +func (x *WebSsoResponseBody) GetData() string { + if x != nil && x.Data != nil { + return *x.Data + } + return "" +} + +func (x *WebSsoResponseBody) GetControlData() *WebSsoControlData { + if x != nil { + return x.ControlData + } + return nil +} + +var File_WebSsoBody_proto protoreflect.FileDescriptor + +var file_WebSsoBody_proto_rawDesc = []byte{ + 0x0a, 0x10, 0x57, 0x65, 0x62, 0x53, 0x73, 0x6f, 0x42, 0x6f, 0x64, 0x79, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x22, 0x78, 0x0a, 0x12, 0x53, 0x54, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4d, + 0x6f, 0x6e, 0x69, 0x74, 0x49, 0x74, 0x65, 0x6d, 0x12, 0x10, 0x0a, 0x03, 0x63, 0x6d, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x63, 0x6d, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, + 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, 0x18, 0x0a, 0x07, + 0x65, 0x72, 0x72, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x65, + 0x72, 0x72, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x6f, 0x73, 0x74, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x63, 0x6f, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x73, 0x72, + 0x63, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x03, 0x73, 0x72, 0x63, 0x22, 0x3c, 0x0a, 0x11, + 0x53, 0x54, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x52, 0x65, + 0x71, 0x12, 0x27, 0x0a, 0x04, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x13, 0x2e, 0x53, 0x54, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4d, 0x6f, 0x6e, 0x69, 0x74, + 0x49, 0x74, 0x65, 0x6d, 0x52, 0x04, 0x6c, 0x69, 0x73, 0x74, 0x22, 0x53, 0x0a, 0x11, 0x57, 0x65, + 0x62, 0x53, 0x73, 0x6f, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x44, 0x61, 0x74, 0x61, 0x12, + 0x1c, 0x0a, 0x09, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0d, 0x52, 0x09, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x20, 0x0a, + 0x0b, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0d, 0x52, 0x0b, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x22, + 0x6f, 0x0a, 0x11, 0x57, 0x65, 0x62, 0x53, 0x73, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x42, 0x6f, 0x64, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x12, + 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x74, 0x79, + 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, 0x18, 0x0a, 0x07, 0x77, 0x65, 0x62, 0x44, 0x61, 0x74, + 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x77, 0x65, 0x62, 0x44, 0x61, 0x74, 0x61, + 0x22, 0x9e, 0x01, 0x0a, 0x12, 0x57, 0x65, 0x62, 0x53, 0x73, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x42, 0x6f, 0x64, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, + 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, + 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x72, 0x65, 0x74, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x0d, 0x52, 0x03, 0x72, 0x65, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, 0x34, 0x0a, 0x0b, 0x63, + 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x44, 0x61, 0x74, 0x61, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x12, 0x2e, 0x57, 0x65, 0x62, 0x53, 0x73, 0x6f, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, + 0x44, 0x61, 0x74, 0x61, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x44, 0x61, 0x74, + 0x61, 0x42, 0x08, 0x5a, 0x06, 0x2e, 0x2f, 0x3b, 0x77, 0x65, 0x62, +} + +var ( + file_WebSsoBody_proto_rawDescOnce sync.Once + file_WebSsoBody_proto_rawDescData = file_WebSsoBody_proto_rawDesc +) + +func file_WebSsoBody_proto_rawDescGZIP() []byte { + file_WebSsoBody_proto_rawDescOnce.Do(func() { + file_WebSsoBody_proto_rawDescData = protoimpl.X.CompressGZIP(file_WebSsoBody_proto_rawDescData) + }) + return file_WebSsoBody_proto_rawDescData +} + +var file_WebSsoBody_proto_msgTypes = make([]protoimpl.MessageInfo, 5) +var file_WebSsoBody_proto_goTypes = []interface{}{ + (*STServiceMonitItem)(nil), // 0: STServiceMonitItem + (*STServiceMonitReq)(nil), // 1: STServiceMonitReq + (*WebSsoControlData)(nil), // 2: WebSsoControlData + (*WebSsoRequestBody)(nil), // 3: WebSsoRequestBody + (*WebSsoResponseBody)(nil), // 4: WebSsoResponseBody +} +var file_WebSsoBody_proto_depIdxs = []int32{ + 0, // 0: STServiceMonitReq.list:type_name -> STServiceMonitItem + 2, // 1: WebSsoResponseBody.controlData:type_name -> WebSsoControlData + 2, // [2:2] is the sub-list for method output_type + 2, // [2:2] is the sub-list for method input_type + 2, // [2:2] is the sub-list for extension type_name + 2, // [2:2] is the sub-list for extension extendee + 0, // [0:2] is the sub-list for field type_name +} + +func init() { file_WebSsoBody_proto_init() } +func file_WebSsoBody_proto_init() { + if File_WebSsoBody_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_WebSsoBody_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*STServiceMonitItem); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_WebSsoBody_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*STServiceMonitReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_WebSsoBody_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*WebSsoControlData); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_WebSsoBody_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*WebSsoRequestBody); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_WebSsoBody_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*WebSsoResponseBody); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_WebSsoBody_proto_rawDesc, + NumEnums: 0, + NumMessages: 5, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_WebSsoBody_proto_goTypes, + DependencyIndexes: file_WebSsoBody_proto_depIdxs, + MessageInfos: file_WebSsoBody_proto_msgTypes, + }.Build() + File_WebSsoBody_proto = out.File + file_WebSsoBody_proto_rawDesc = nil + file_WebSsoBody_proto_goTypes = nil + file_WebSsoBody_proto_depIdxs = nil +} diff --git a/client/pb/web/WebSsoBody.proto b/client/pb/web/WebSsoBody.proto new file mode 100644 index 00000000..895ccab8 --- /dev/null +++ b/client/pb/web/WebSsoBody.proto @@ -0,0 +1,36 @@ +syntax = "proto2"; + +option go_package = "./;web"; + +message STServiceMonitItem { + optional string cmd = 1; + optional string url = 2; + optional int32 errcode = 3; + optional uint32 cost = 4; + optional uint32 src = 5; +} + +message STServiceMonitReq { + repeated STServiceMonitItem list = 1; +} + +message WebSsoControlData { + optional uint32 frequency = 1; + optional uint32 packageSize = 2; +} + +message WebSsoRequestBody { + optional uint32 version = 1; + optional uint32 type = 2; + optional string data = 3; + optional string webData = 4; +} + +message WebSsoResponseBody { + optional uint32 version = 1; + optional uint32 type = 2; + optional uint32 ret = 3; + optional string data = 4; + optional WebSsoControlData controlData = 5; +} + diff --git a/client/web.go b/client/web.go new file mode 100644 index 00000000..58b02ea9 --- /dev/null +++ b/client/web.go @@ -0,0 +1,85 @@ +package client + +import ( + "encoding/base64" + "encoding/json" + "fmt" + "github.com/Mrs4s/MiraiGo/client/pb/web" + "github.com/Mrs4s/MiraiGo/protocol/packets" + "github.com/Mrs4s/MiraiGo/utils" + "github.com/pkg/errors" + "google.golang.org/protobuf/proto" + "strings" +) + +type UnidirectionalFriendInfo struct { + Uin int64 + Nickname string + Age int32 + Source string +} + +func (c *QQClient) GetUnidirectionalFriendList() (ret []*UnidirectionalFriendInfo, err error) { + webRsp := &struct { + BlockList []struct { + Uin int64 `json:"uint64_uin"` + NickBytes string `json:"bytes_nick"` + Age int32 `json:"uint32_age"` + Sex int32 `json:"uint32_sex"` + SourceBytes string `json:"bytes_source"` + } `json:"rpt_block_list"` + ErrorCode int32 `json:"ErrorCode"` + }{} + rsp, err := c.webSsoRequest("ti.qq.com", "OidbSvc.0xe17_0", fmt.Sprintf(`{"uint64_uin":%v,"uint64_top":0,"uint32_req_num":99,"bytes_cookies":""}`, c.Uin)) + if err != nil { + return nil, err + } + if err = json.Unmarshal(utils.S2B(rsp), webRsp); err != nil { + return nil, errors.Wrap(err, "unmarshal json error") + } + if webRsp.ErrorCode != 0 { + return nil, errors.Errorf("web sso request error: %v", webRsp.ErrorCode) + } + for _, block := range webRsp.BlockList { + decodeBase64String := func(str string) string { + b, err := base64.StdEncoding.DecodeString(str) + if err != nil { + return "" + } + return utils.B2S(b) + } + ret = append(ret, &UnidirectionalFriendInfo{ + Uin: block.Uin, + Nickname: decodeBase64String(block.NickBytes), + Age: block.Age, + Source: decodeBase64String(block.SourceBytes), + }) + } + return +} + +func (c *QQClient) webSsoRequest(host, webCmd, data string) (string, error) { + s := strings.Split(host, `.`) + sub := "" + for i := len(s) - 1; i >= 0; i-- { + sub += s[i] + if i != 0 { + sub += "_" + } + } + cmd := "MQUpdateSvc_" + sub + ".web." + webCmd + req, _ := proto.Marshal(&web.WebSsoRequestBody{ + Type: proto.Uint32(0), + Data: &data, + }) + seq := c.nextSeq() + rspData, err := c.sendAndWaitDynamic(seq, packets.BuildUniPacket(c.Uin, seq, cmd, 1, c.OutGoingPacketSessionId, []byte{}, c.sigInfo.d2Key, req)) + if err != nil { + return "", errors.Wrap(err, "send web sso request error") + } + rsp := &web.WebSsoResponseBody{} + if err = proto.Unmarshal(rspData, rsp); err != nil { + return "", errors.Wrap(err, "unmarshal response error") + } + return rsp.GetData(), nil +} diff --git a/go.mod b/go.mod index abe5a380..234d380e 100644 --- a/go.mod +++ b/go.mod @@ -3,9 +3,11 @@ module github.com/Mrs4s/MiraiGo go 1.16 require ( + github.com/golang/protobuf v1.5.2 // indirect github.com/pkg/errors v0.9.1 github.com/stretchr/testify v1.3.0 github.com/tidwall/gjson v1.8.1 golang.org/x/sync v0.0.0-20210220032951-036812b2e83c - google.golang.org/protobuf v1.25.0 + google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 // indirect + google.golang.org/protobuf v1.27.1 ) diff --git a/go.sum b/go.sum index 10ebeca1..97c6c9b6 100644 --- a/go.sum +++ b/go.sum @@ -16,12 +16,16 @@ github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrU github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -77,5 +81,9 @@ google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=