diff --git a/client/_c2c_decoders.go b/client/_c2c_decoders.go new file mode 100644 index 00000000..72a72b44 --- /dev/null +++ b/client/_c2c_decoders.go @@ -0,0 +1,30 @@ +package client + +import "github.com/Mrs4s/MiraiGo/client/pb/msg" + +var privateMsgDecoders = map[int32]func(*QQClient, *msg.Message, *incomingPacketInfo){ + 9: privateMessageDecoder, 10: privateMessageDecoder, 31: privateMessageDecoder, + 79: privateMessageDecoder, 97: privateMessageDecoder, 120: privateMessageDecoder, + 132: privateMessageDecoder, 133: privateMessageDecoder, 166: privateMessageDecoder, + 167: privateMessageDecoder, 140: tempSessionDecoder, 141: tempSessionDecoder, + 208: privatePttDecoder, +} + +var nonSvcNotifyTroopSystemMsgDecoders = map[int32]func(*QQClient, *msg.Message, *incomingPacketInfo){ + 36: troopSystemMessageDecoder, 85: troopSystemMessageDecoder, +} + +var troopSystemMsgDecoders = map[int32]func(*QQClient, *msg.Message, *incomingPacketInfo){ + 35: troopSystemMessageDecoder, 37: troopSystemMessageDecoder, + 45: troopSystemMessageDecoder, 46: troopSystemMessageDecoder, 84: troopSystemMessageDecoder, + 86: troopSystemMessageDecoder, 87: troopSystemMessageDecoder, +} // IsSvcNotify + +var sysMsgDecoders = map[int32]func(*QQClient, *msg.Message, *incomingPacketInfo){ + 187: systemMessageDecoder, 188: systemMessageDecoder, 189: systemMessageDecoder, + 190: systemMessageDecoder, 191: systemMessageDecoder, +} // IsSvcNotify + +var otherDecoders = map[int32]func(*QQClient, *msg.Message, *incomingPacketInfo){ + 33: troopAddMemberBroadcastDecoder, 529: msgType0x211Decoder, +} diff --git a/client/c2c_processor.go b/client/c2c_processor.go index bcc447c2..5888a767 100644 --- a/client/c2c_processor.go +++ b/client/c2c_processor.go @@ -1,5 +1,7 @@ package client +//go:generate go run cmd/c2c_switcher.go + import ( "fmt" "sync/atomic" @@ -13,31 +15,6 @@ import ( "google.golang.org/protobuf/proto" ) -var privateMsgDecoders = map[int32]func(*QQClient, *msg.Message, *incomingPacketInfo){ - 9: privateMessageDecoder, 10: privateMessageDecoder, 31: privateMessageDecoder, - 79: privateMessageDecoder, 97: privateMessageDecoder, 120: privateMessageDecoder, - 132: privateMessageDecoder, 133: privateMessageDecoder, 166: privateMessageDecoder, - 167: privateMessageDecoder, 140: tempSessionDecoder, 141: tempSessionDecoder, - 208: privatePttDecoder, -} - -var troopSystemMsgDecoders = map[int32]func(*QQClient, *msg.Message, *incomingPacketInfo){ - 35: troopSystemMessageDecoder, 36: troopSystemMessageDecoder, 37: troopSystemMessageDecoder, - 45: troopSystemMessageDecoder, 46: troopSystemMessageDecoder, 84: troopSystemMessageDecoder, - 85: troopSystemMessageDecoder, 86: troopSystemMessageDecoder, 87: troopSystemMessageDecoder, -} - -var sysMsgDecoders = map[int32]func(*QQClient, *msg.Message, *incomingPacketInfo){ - 187: systemMessageDecoder, 188: systemMessageDecoder, 189: systemMessageDecoder, - 190: systemMessageDecoder, 191: systemMessageDecoder, -} - -var otherDecoders = map[int32]func(*QQClient, *msg.Message, *incomingPacketInfo){ - 33: troopAddMemberBroadcastDecoder, 529: msgType0x211Decoder, -} - -var c2cDecoders = map[int32]func(*QQClient, *msg.Message, *incomingPacketInfo){} - type ( TempSessionInfo struct { Source TempSessionSource @@ -62,18 +39,6 @@ const ( AddressBookSource TempSessionSource = 9 // 来自通讯录 ) -func init() { - merge := func(m map[int32]func(*QQClient, *msg.Message, *incomingPacketInfo)) { - for k, v := range m { - c2cDecoders[k] = v - } - } - merge(privateMsgDecoders) - merge(troopSystemMsgDecoders) - merge(sysMsgDecoders) - merge(otherDecoders) -} - func (c *QQClient) c2cMessageSyncProcessor(rsp *msg.GetMessageResponse, info *incomingPacketInfo) { c.syncCookie = rsp.SyncCookie c.pubAccountCookie = rsp.PubAccountCookie @@ -127,7 +92,7 @@ func (c *QQClient) commMsgProcessor(pMsg *msg.Message, info *incomingPacketInfo) if info.Params.bool("init") { return } - if decoder, ok := c2cDecoders[pMsg.Head.GetMsgType()]; ok { + if decoder, _ := peekC2CDecoder(pMsg.Head.GetMsgType()); decoder != nil { decoder(c, pMsg, info) } else { c.Debug("unknown msg type on c2c processor: %v - %v", pMsg.Head.GetMsgType(), pMsg.Head.GetC2CCmd()) diff --git a/client/c2c_switch.go b/client/c2c_switch.go new file mode 100644 index 00000000..fb9199ec --- /dev/null +++ b/client/c2c_switch.go @@ -0,0 +1,81 @@ +// Code generated by client/c2c_switcher.go DO NOT EDIT. + +package client + +import ( + "github.com/Mrs4s/MiraiGo/client/pb/msg" +) + +const ( + UnknownDecoder = iota + privateMsgDecoders + nonSvcNotifyTroopSystemMsgDecoders + troopSystemMsgDecoders + sysMsgDecoders + otherDecoders +) + +func peekC2CDecoder(msgType int32) (decoder func(*QQClient, *msg.Message, *incomingPacketInfo), decoderType uint8) { + switch msgType { + case 9: + return privateMessageDecoder, privateMsgDecoders + case 10: + return privateMessageDecoder, privateMsgDecoders + case 31: + return privateMessageDecoder, privateMsgDecoders + case 33: + return troopAddMemberBroadcastDecoder, otherDecoders + case 35: + return troopSystemMessageDecoder, troopSystemMsgDecoders + case 36: + return troopSystemMessageDecoder, nonSvcNotifyTroopSystemMsgDecoders + case 37: + return troopSystemMessageDecoder, troopSystemMsgDecoders + case 45: + return troopSystemMessageDecoder, troopSystemMsgDecoders + case 46: + return troopSystemMessageDecoder, troopSystemMsgDecoders + case 79: + return privateMessageDecoder, privateMsgDecoders + case 84: + return troopSystemMessageDecoder, troopSystemMsgDecoders + case 85: + return troopSystemMessageDecoder, nonSvcNotifyTroopSystemMsgDecoders + case 86: + return troopSystemMessageDecoder, troopSystemMsgDecoders + case 87: + return troopSystemMessageDecoder, troopSystemMsgDecoders + case 97: + return privateMessageDecoder, privateMsgDecoders + case 120: + return privateMessageDecoder, privateMsgDecoders + case 132: + return privateMessageDecoder, privateMsgDecoders + case 133: + return privateMessageDecoder, privateMsgDecoders + case 140: + return tempSessionDecoder, privateMsgDecoders + case 141: + return tempSessionDecoder, privateMsgDecoders + case 166: + return privateMessageDecoder, privateMsgDecoders + case 167: + return privateMessageDecoder, privateMsgDecoders + case 187: + return systemMessageDecoder, sysMsgDecoders + case 188: + return systemMessageDecoder, sysMsgDecoders + case 189: + return systemMessageDecoder, sysMsgDecoders + case 190: + return systemMessageDecoder, sysMsgDecoders + case 191: + return systemMessageDecoder, sysMsgDecoders + case 208: + return privatePttDecoder, privateMsgDecoders + case 529: + return msgType0x211Decoder, otherDecoders + default: + return nil, UnknownDecoder + } +} diff --git a/client/cmd/c2c_switcher.go b/client/cmd/c2c_switcher.go new file mode 100644 index 00000000..10f49712 --- /dev/null +++ b/client/cmd/c2c_switcher.go @@ -0,0 +1,119 @@ +package main + +import ( + "bytes" + "go/ast" + "go/format" + "go/parser" + "go/token" + "os" + "sort" + "strconv" + "text/template" +) + +const codeTemplate = `// Code generated by client/c2c_switcher.go DO NOT EDIT. + +package client + +import ( +{{range .Imports}} {{.}} +{{end}} +) + +const ( + UnknownDecoder = iota +{{range .Consts}} {{.}} +{{end}} +) + +func peekC2CDecoder(msgType int32) (decoder func(*QQClient, *msg.Message, *incomingPacketInfo), decoderType uint8) { + switch msgType { +{{range .Decoders}} case {{.Id}}: + return {{.Func}}, {{.DecoderType}} +{{end}} default: + return nil, UnknownDecoder + } +}` + +type decoder struct { + Id int64 + Func string + DecoderType string +} +type DecoderSort []decoder + +func (d DecoderSort) Len() int { return len(d) } +func (d DecoderSort) Swap(i, j int) { d[i], d[j] = d[j], d[i] } +func (d DecoderSort) Less(i, j int) bool { return d[i].Id < d[j].Id } + +func main() { + type switchFile struct { + Imports []string + Consts []string + Decoders DecoderSort + } + var sf switchFile + + fset := token.NewFileSet() + astF, err := parser.ParseFile(fset, "_c2c_decoders.go", nil, parser.AllErrors|parser.ParseComments) + if err != nil { + panic(err) + } + + sf.Imports = make([]string, 0, len(astF.Imports)) + for _, imp := range astF.Imports { + sf.Imports = append(sf.Imports, imp.Path.Value) + } + + sf.Consts = make([]string, 0, len(astF.Scope.Objects)) + for _, obj := range astF.Scope.Objects { + if obj.Kind != ast.Var { + panic(`unknown non-variable in "_c2c_decoders.go"`) + } + value := obj.Decl.(*ast.ValueSpec) + sf.Consts = append(sf.Consts, obj.Name) + for _, value := range value.Values { + if value, ok := value.(*ast.CompositeLit); ok { + for _, kv := range value.Elts { + if kv, ok := kv.(*ast.KeyValueExpr); ok { + k := kv.Key.(*ast.BasicLit) + v := kv.Value.(*ast.Ident) + sf.Decoders = append(sf.Decoders, decoder{ + Id: mustParseInt(k.Value), + Func: v.Name, + DecoderType: obj.Name, + }) + } else { + panic(`unknown key value in ` + obj.Name + ` in "_c2c_decoders.go"`) + } + } + } else { + panic(`unknown non-map value in "_c2c_decoders.go"`) + } + } + } + sort.Sort(sf.Decoders) + + f, _ := os.OpenFile("c2c_switch.go", os.O_WRONLY|os.O_CREATE|os.O_SYNC|os.O_TRUNC, 0o644) + tmpl, err := template.New("template").Parse(codeTemplate) + if err != nil { + panic(err) + } + buffer := &bytes.Buffer{} + err = tmpl.Execute(buffer, &sf) + if err != nil { + panic(err) + } + source, _ := format.Source(buffer.Bytes()) + _, _ = f.Write(source) + _ = f.Close() +} + +func mustParseInt(s string) int64 { + i, err := strconv.ParseInt(s, 10, 32) + if err != nil { + panic(err) + } + return i +} diff --git a/client/decoders.go b/client/decoders.go index 6c5e4123..22602626 100644 --- a/client/decoders.go +++ b/client/decoders.go @@ -395,13 +395,16 @@ func decodeSvcNotify(c *QQClient, _ *incomingPacketInfo, payload []byte) (interf } notify := &jce.RequestPushNotify{} notify.ReadFrom(jce.NewJceReader(data.Map["req_PushNotify"]["PushNotifyPack.RequestPushNotify"][1:])) - if _, ok := troopSystemMsgDecoders[notify.MsgType]; ok && notify.MsgType != 85 && notify.MsgType != 36 { - c.exceptAndDispatchGroupSysMsg() - return nil, nil - } - if _, ok := sysMsgDecoders[notify.MsgType]; ok { - _, pkt := c.buildSystemMsgNewFriendPacket() - return nil, c.sendPacket(pkt) + if decoder, typ := peekC2CDecoder(notify.MsgType); decoder != nil { + // notify.MsgType != 85 && notify.MsgType != 36 moves to _c2c_decoders.go [nonSvcNotifyTroopSystemMsgDecoders] + if typ == troopSystemMsgDecoders { + c.exceptAndDispatchGroupSysMsg() + return nil, nil + } + if typ == sysMsgDecoders { + _, pkt := c.buildSystemMsgNewFriendPacket() + return nil, c.sendPacket(pkt) + } } _, err := c.sendAndWait(c.buildGetMessageRequestPacket(msg.SyncFlag_START, time.Now().Unix())) return nil, err