1
0
mirror of https://github.com/Mrs4s/MiraiGo.git synced 2025-07-08 15:18:32 +00:00

Compare commits

13 Commits

Author SHA1 Message Date
a54f4d82f5 feat: move msg&channel proto to yaprotoc gen 2021-11-12 10:43:12 +08:00
0f149a925f Merge branch 'master' into reflection-based-protobuf
# Conflicts:
#	client/builders.go
#	client/global.go
2021-11-11 19:32:13 +08:00
44393e904d Merge branch 'master' into reflection-based-protobuf
# Conflicts:
#	client/builders.go
#	client/global.go
2021-11-11 19:17:09 +08:00
055f034b9e dep: update proto gen 2021-11-07 13:14:05 +08:00
e7f07499f3 rf: use yaprotoc generate proto 2021-11-07 10:15:31 +08:00
d1fd299faa refactor: use new protobuf impl oidb 2021-11-05 22:16:58 +08:00
f0bceae09f refactor: use new protobuf impl oidb0x8fc 2021-11-05 20:44:11 +08:00
a105f65e45 refactor: use new protobuf impl oidb0x8a7 2021-11-05 20:13:54 +08:00
a8760a5821 refactor: use new protobuf impl oidb0x6d9 2021-11-05 20:05:57 +08:00
b0fd43cea1 refactor: use new protobuf impl oidb0x6d6 & oidb0x6d7 2021-11-03 02:33:19 +08:00
28da394096 refactor: use new protobuf impl oidb0x6d8 2021-11-03 02:00:12 +08:00
8e5ac24d32 dep: update proto code gen 2021-11-02 21:56:09 +08:00
b7b13c64b4 refactor: use new protobuf impl oidb0x88d 2021-11-02 03:28:10 +08:00
325 changed files with 60347 additions and 20221 deletions

View File

@ -1,70 +0,0 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL"
on:
push:
branches: [ master ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ master ]
schedule:
- cron: '27 14 * * 1'
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
strategy:
fail-fast: false
matrix:
language: [ 'go' ]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
# Learn more about CodeQL language support at https://git.io/codeql-language-support
steps:
- name: Checkout repository
uses: actions/checkout@v2
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# queries: ./path/to/local/query, your-org/your-repo/queries@main
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v1
# Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language
#- run: |
# make bootstrap
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1

View File

@ -2,9 +2,9 @@ name: Go
on: on:
push: push:
branches: [ master, typeparam ] branches: [ master ]
pull_request: pull_request:
branches: [ master, typeparam ] branches: [ master ]
jobs: jobs:
@ -16,7 +16,7 @@ jobs:
- name: Set up Go 1.x - name: Set up Go 1.x
uses: actions/setup-go@v2 uses: actions/setup-go@v2
with: with:
go-version: '1.20' go-version: ^1.13
- name: Check out code into the Go module directory - name: Check out code into the Go module directory
uses: actions/checkout@v2 uses: actions/checkout@v2

View File

@ -14,7 +14,7 @@ jobs:
- name: Set up Go 1.x - name: Set up Go 1.x
uses: actions/setup-go@v2 uses: actions/setup-go@v2
with: with:
go-version: 1.19 go-version: ^1.13
- name: Check out code into the Go module directory - name: Check out code into the Go module directory
uses: actions/checkout@v2 uses: actions/checkout@v2

1
.gitignore vendored
View File

@ -1,3 +1,2 @@
.idea .idea
vendor/ vendor/
.DS_Store

View File

@ -1,52 +0,0 @@
.PHONY: protoc-gen-golite-version clean install-protoc-plugin proto
.DEFAULT_GOAL := proto
PROTO_DIR=client/pb
PROTO_OUTPUT_PATH=client
PROTO_IMPORT_PATH=client
PROTO_FILES := \
$(PROTO_DIR)/*.proto \
$(PROTO_DIR)/channel/*.proto \
$(PROTO_DIR)/cmd0x3f6/*.proto \
$(PROTO_DIR)/cmd0x6ff/*.proto \
$(PROTO_DIR)/cmd0x346/*.proto \
$(PROTO_DIR)/cmd0x352/*.proto \
$(PROTO_DIR)/cmd0x388/*.proto \
$(PROTO_DIR)/exciting/*.proto \
$(PROTO_DIR)/faceroam/*.proto \
$(PROTO_DIR)/highway/*.proto \
$(PROTO_DIR)/longmsg/*.proto \
$(PROTO_DIR)/msf/*.proto \
$(PROTO_DIR)/msg/*.proto \
$(PROTO_DIR)/msgtype0x210/*.proto \
$(PROTO_DIR)/multimsg/*.proto \
$(PROTO_DIR)/notify/*.proto \
$(PROTO_DIR)/oidb/*.proto \
$(PROTO_DIR)/profilecard/*.proto \
$(PROTO_DIR)/pttcenter/*.proto \
$(PROTO_DIR)/qweb/*.proto \
$(PROTO_DIR)/richmedia/*.proto \
$(PROTO_DIR)/structmsg/*.proto \
$(PROTO_DIR)/web/*.proto
PROTOC_GEN_GOLITE_VERSION := \
$(shell grep "github.com/RomiChan/protobuf" go.mod | awk -F v '{print "v"$$2}')
protoc-gen-golite-version:
@echo "Use protoc-gen-golite version: $(PROTOC_GEN_GOLITE_VERSION)"
clean:
find . -name "*.pb.go" | xargs rm -f
install-protoc-plugin: protoc-gen-golite-version
go install github.com/RomiChan/protobuf/cmd/protoc-gen-golite@$(PROTOC_GEN_GOLITE_VERSION)
proto: install-protoc-plugin
protoc --golite_out=$(PROTO_OUTPUT_PATH) --golite_opt=paths=source_relative -I=$(PROTO_IMPORT_PATH) $(PROTO_FILES)
fmt:
go vet -stdmethods=false ./...
.EXPORT_ALL_VARIABLES:
GO111MODULE = on

View File

@ -1,34 +1,22 @@
# MiraiGo # MiraiGo
qq-android 协议的golang实现 移植于 [mirai](https://github.com/mamoe/mirai) qq-android协议的golang实现 移植于mirai
## 使用前声明 # 警告
本项目为协议实现,不推荐直接使用。 本项目为协议实现,api非常原始不推荐使用。
CQHTTP 用户建议使用基于 [go-cqhttp](https://github.com/Mrs4s/go-cqhttp) 框架开发。 建议基于 [go-cqhttp](https://github.com/Mrs4s/go-cqhttp) 使用框架开发。
同时提供原生框架 [MiraiGo-Template](https://github.com/Logiase/MiraiGo-Template) 进行开发。 同时提供不基于 CQHTTP 的原生框架 [MiraiGo-Template](https://github.com/Logiase/MiraiGo-Template) 进行开发。
## 使用方法 # 已完成功能/开发计划
#### 登录
```bash
go get -u github.com/Mrs4s/MiraiGo
```
## 支持的功能
## 协议支持
<details>
<summary>已完成功能/开发计划列表</summary>
**登录**
- [x] 账号密码登录 - [x] 账号密码登录
- [x] 二维码登录 - [x] 二维码登录
- [x] 验证码提交 - [x] 验证码提交
- [x] 设备锁验证 - [x] 设备锁验证
- [x] 错误信息解析 - [x] 错误信息解析
**消息类型** #### 消息类型
- [x] 文本 - [x] 文本
- [x] 图片 - [x] 图片
- [x] 语音 - [x] 语音
@ -42,14 +30,14 @@ go get -u github.com/Mrs4s/MiraiGo
- [x] 合并转发 - [x] 合并转发
- [x] 群文件(上传与接收信息) - [x] 群文件(上传与接收信息)
**事件** #### 事件
- [x] 好友消息 - [x] 好友消息
- [x] 群消息 - [x] 群消息
- [x] 临时会话消息 - [x] 临时会话消息
- [x] 登录号加群 - [x] 登录号加群
- [x] 登录号退群(包含T出) - [x] 登录号退群(包含T出)
- [x] 新成员进群/退群 - [x] 新成员进群/退群
- [x] 群/好友消息撤回 - [x] 群/好友消息撤回
- [x] 群禁言 - [x] 群禁言
- [x] 群成员权限变更 - [x] 群成员权限变更
- [x] 收到邀请进群通知 - [x] 收到邀请进群通知
@ -57,11 +45,10 @@ go get -u github.com/Mrs4s/MiraiGo
- [x] 新好友 - [x] 新好友
- [x] 新好友请求 - [x] 新好友请求
- [x] 客户端离线 - [x] 客户端离线
- [x] 群提示 (戳一戳/运气王等) - [x] 群提示 (戳一戳/运气王等)
**主动操作** #### 主动操作
> 为防止滥用,将不支持主动邀请新成员进群
_为防止滥用不支持主动邀请新成员进群_
- [x] 发送群消息 - [x] 发送群消息
- [x] 发送好友消息 - [x] 发送好友消息
@ -85,14 +72,11 @@ _为防止滥用不支持主动邀请新成员进群_
- [x] 戳一戳群友 - [x] 戳一戳群友
- [x] 获取陌生人信息 - [x] 获取陌生人信息
</details> #### 敏感操作
> 由于[QQ钱包支付用户服务协议](https://www.tenpay.com/v2/html5/basic/public/agreement/protocol_mqq_pay.shtml), 将不支持一切有关QQ钱包的协议
### 不支持的协议
**基于 [QQ钱包支付用户服务协议](https://www.tenpay.com/v2/html5/basic/public/agreement/protocol_mqq_pay.shtml) 不支持一切有关QQ钱包的协议**
>4.13 您不得利用本服务实施下列任一的行为: >4.13 您不得利用本服务实施下列任一的行为:
>\ >\
> 9 **侵害QQ钱包支付服务系統** > 9 **侵害QQ钱包支付服务系統**
- [ ] ~~QQ钱包协议(收款/付款等)~~ - [ ] ~~QQ钱包协议(收款/付款等)~~

View File

@ -1,15 +1,15 @@
package jce package jce
import ( import (
"bytes"
goBinary "encoding/binary" goBinary "encoding/binary"
"io"
"math" "math"
"reflect"
"github.com/Mrs4s/MiraiGo/utils"
) )
type JceReader struct { type JceReader struct {
buf []byte buf *bytes.Reader
off int
} }
type HeadData struct { type HeadData struct {
@ -18,38 +18,30 @@ type HeadData struct {
} }
func NewJceReader(data []byte) *JceReader { func NewJceReader(data []byte) *JceReader {
return &JceReader{buf: data} buf := bytes.NewReader(data)
return &JceReader{buf: buf}
} }
func (r *JceReader) readHead() HeadData { func (r *JceReader) readHead() (hd HeadData, l int32) {
hd, l := r.peakHead() b, _ := r.buf.ReadByte()
r.off += l
return hd
}
func (r *JceReader) peakHead() (hd HeadData, l int) {
b := r.buf[r.off]
hd.Type = b & 0xF hd.Type = b & 0xF
hd.Tag = int(uint(b) >> 4) hd.Tag = (int(b) & 0xF0) >> 4
l = 1 if hd.Tag == 15 {
if hd.Tag == 0xF { b, _ = r.buf.ReadByte()
b = r.buf[r.off+1] hd.Tag = int(b) & 0xFF
hd.Tag = int(uint(b)) return hd, 2
l = 2
} }
return hd, 1
}
func (r *JceReader) peakHead() (h HeadData, l int32) {
h, l = r.readHead()
_, _ = r.buf.Seek(int64(-l), io.SeekCurrent)
return return
} }
func (r *JceReader) skipHead() {
l := 1
if int(uint(r.buf[r.off])>>4) == 0xF {
l = 2
}
r.off += l
}
func (r *JceReader) skip(l int) { func (r *JceReader) skip(l int) {
r.off += l r.readBytes(l)
} }
func (r *JceReader) skipField(t byte) { func (r *JceReader) skipField(t byte) {
@ -63,9 +55,10 @@ func (r *JceReader) skipField(t byte) {
case 3, 5: case 3, 5:
r.skip(8) r.skip(8)
case 6: case 6:
r.skip(int(r.readByte())) b, _ := r.buf.ReadByte()
r.skip(int(b))
case 7: case 7:
r.skip(int(r.readUInt32())) r.skip(int(r.readInt32()))
case 8: case 8:
s := r.ReadInt32(0) s := r.ReadInt32(0)
for i := 0; i < int(s)*2; i++ { for i := 0; i < int(s)*2; i++ {
@ -77,7 +70,7 @@ func (r *JceReader) skipField(t byte) {
r.skipNextField() r.skipNextField()
} }
case 13: case 13:
r.skipHead() r.readHead()
s := r.ReadInt32(0) s := r.ReadInt32(0)
r.skip(int(s)) r.skip(int(s))
case 10: case 10:
@ -86,7 +79,7 @@ func (r *JceReader) skipField(t byte) {
} }
func (r *JceReader) skipNextField() { func (r *JceReader) skipNextField() {
hd := r.readHead() hd, _ := r.readHead()
r.skipField(hd.Type) r.skipField(hd.Type)
} }
@ -96,65 +89,73 @@ func (r *JceReader) SkipField(c int) {
} }
} }
func (r *JceReader) readBytes(n int) []byte { func (r *JceReader) readBytes(len int) []byte {
if r.off+n > len(r.buf) { if len == 0 {
panic("readBytes: EOF") return nil
}
b := make([]byte, len)
_, err := r.buf.Read(b)
if err != nil {
panic(err)
} }
b := make([]byte, n)
r.off += copy(b, r.buf[r.off:])
return b return b
} }
func (r *JceReader) readByte() byte { func (r *JceReader) readByte() byte {
if r.off >= len(r.buf) { b, err := r.buf.ReadByte()
panic("readByte: EOF") if err != nil {
panic(err)
} }
b := r.buf[r.off]
r.off++
return b return b
} }
func (r *JceReader) readUInt16() uint16 { func (r *JceReader) readUInt16() uint16 {
b := make([]byte, 2) f, _ := r.buf.ReadByte()
r.off += copy(b, r.buf[r.off:]) s, err := r.buf.ReadByte()
return goBinary.BigEndian.Uint16(b) if err != nil {
panic(err)
}
return uint16((int32(f) << 8) + int32(s))
} }
func (r *JceReader) readUInt32() uint32 { func (r *JceReader) readInt32() int32 {
b := make([]byte, 4) b := r.readBytes(4)
r.off += copy(b, r.buf[r.off:]) return int32(goBinary.BigEndian.Uint32(b))
return goBinary.BigEndian.Uint32(b)
} }
func (r *JceReader) readUInt64() uint64 { func (r *JceReader) readInt64() int64 {
b := make([]byte, 8) b := r.readBytes(8)
r.off += copy(b, r.buf[r.off:]) return int64(goBinary.BigEndian.Uint64(b))
return goBinary.BigEndian.Uint64(b)
} }
func (r *JceReader) readFloat32() float32 { func (r *JceReader) readFloat32() float32 {
return math.Float32frombits(r.readUInt32()) b := r.readInt32()
return math.Float32frombits(uint32(b))
} }
func (r *JceReader) readFloat64() float64 { func (r *JceReader) readFloat64() float64 {
return math.Float64frombits(r.readUInt64()) b := r.readInt64()
return math.Float64frombits(uint64(b))
} }
func (r *JceReader) skipToTag(tag int) bool { func (r *JceReader) skipToTag(tag int) bool {
hd, l := r.peakHead() for {
for tag > hd.Tag && hd.Type != 11 { hd, l := r.peakHead()
r.skip(l) if tag <= hd.Tag || hd.Type == 11 {
return tag == hd.Tag
}
r.skip(int(l))
r.skipField(hd.Type) r.skipField(hd.Type)
hd, l = r.peakHead()
} }
return tag == hd.Tag
} }
func (r *JceReader) skipToStructEnd() { func (r *JceReader) skipToStructEnd() {
hd := r.readHead() for {
for hd.Type != 11 { hd, _ := r.readHead()
r.skipField(hd.Type) r.skipField(hd.Type)
hd = r.readHead() if hd.Type == 11 {
return
}
} }
} }
@ -162,7 +163,7 @@ func (r *JceReader) ReadByte(tag int) byte {
if !r.skipToTag(tag) { if !r.skipToTag(tag) {
return 0 return 0
} }
hd := r.readHead() hd, _ := r.readHead()
switch hd.Type { switch hd.Type {
case 12: case 12:
return 0 return 0
@ -181,7 +182,7 @@ func (r *JceReader) ReadInt16(tag int) int16 {
if !r.skipToTag(tag) { if !r.skipToTag(tag) {
return 0 return 0
} }
hd := r.readHead() hd, _ := r.readHead()
switch hd.Type { switch hd.Type {
case 12: case 12:
return 0 return 0
@ -198,7 +199,7 @@ func (r *JceReader) ReadInt32(tag int) int32 {
if !r.skipToTag(tag) { if !r.skipToTag(tag) {
return 0 return 0
} }
hd := r.readHead() hd, _ := r.readHead()
switch hd.Type { switch hd.Type {
case 12: case 12:
return 0 return 0
@ -207,7 +208,7 @@ func (r *JceReader) ReadInt32(tag int) int32 {
case 1: case 1:
return int32(r.readUInt16()) return int32(r.readUInt16())
case 2: case 2:
return int32(r.readUInt32()) return r.readInt32()
default: default:
return 0 return 0
} }
@ -217,7 +218,7 @@ func (r *JceReader) ReadInt64(tag int) int64 {
if !r.skipToTag(tag) { if !r.skipToTag(tag) {
return 0 return 0
} }
hd := r.readHead() hd, _ := r.readHead()
switch hd.Type { switch hd.Type {
case 12: case 12:
return 0 return 0
@ -226,9 +227,9 @@ func (r *JceReader) ReadInt64(tag int) int64 {
case 1: case 1:
return int64(int16(r.readUInt16())) return int64(int16(r.readUInt16()))
case 2: case 2:
return int64(r.readUInt32()) return int64(r.readInt32())
case 3: case 3:
return int64(r.readUInt64()) return r.readInt64()
default: default:
return 0 return 0
} }
@ -238,7 +239,7 @@ func (r *JceReader) ReadFloat32(tag int) float32 {
if !r.skipToTag(tag) { if !r.skipToTag(tag) {
return 0 return 0
} }
hd := r.readHead() hd, _ := r.readHead()
switch hd.Type { switch hd.Type {
case 12: case 12:
return 0 return 0
@ -253,7 +254,7 @@ func (r *JceReader) ReadFloat64(tag int) float64 {
if !r.skipToTag(tag) { if !r.skipToTag(tag) {
return 0 return 0
} }
hd := r.readHead() hd, _ := r.readHead()
switch hd.Type { switch hd.Type {
case 12: case 12:
return 0 return 0
@ -270,12 +271,12 @@ func (r *JceReader) ReadString(tag int) string {
if !r.skipToTag(tag) { if !r.skipToTag(tag) {
return "" return ""
} }
hd := r.readHead() hd, _ := r.readHead()
switch hd.Type { switch hd.Type {
case 6: case 6:
return utils.B2S(r.readBytes(int(r.readByte()))) return string(r.readBytes(int(r.readByte())))
case 7: case 7:
return utils.B2S(r.readBytes(int(r.readUInt32()))) return string(r.readBytes(int(r.readInt32())))
default: default:
return "" return ""
} }
@ -285,7 +286,7 @@ func (r *JceReader) ReadBytes(tag int) []byte {
if !r.skipToTag(tag) { if !r.skipToTag(tag) {
return nil return nil
} }
hd := r.readHead() hd, _ := r.readHead()
switch hd.Type { switch hd.Type {
case 9: case 9:
s := r.ReadInt32(0) s := r.ReadInt32(0)
@ -295,32 +296,13 @@ func (r *JceReader) ReadBytes(tag int) []byte {
} }
return b return b
case 13: case 13:
r.skipHead() r.readHead()
return r.readBytes(int(r.ReadInt32(0))) return r.readBytes(int(r.ReadInt32(0)))
default: default:
return nil return nil
} }
} }
func (r *JceReader) ReadByteArrArr(tag int) (baa [][]byte) {
if !r.skipToTag(tag) {
return nil
}
hd := r.readHead()
switch hd.Type {
case 9:
s := r.ReadInt32(0)
baa = make([][]byte, s)
for i := 0; i < int(s); i++ {
baa[i] = r.ReadBytes(0)
}
return baa
default:
return nil
}
}
/*
// ReadAny Read any type via tag, unsupported JceStruct // ReadAny Read any type via tag, unsupported JceStruct
func (r *JceReader) ReadAny(tag int) interface{} { func (r *JceReader) ReadAny(tag int) interface{} {
if !r.skipToTag(tag) { if !r.skipToTag(tag) {
@ -333,17 +315,17 @@ func (r *JceReader) ReadAny(tag int) interface{} {
case 1: case 1:
return r.readUInt16() return r.readUInt16()
case 2: case 2:
return r.readUInt32() return r.readInt32()
case 3: case 3:
return r.readUInt64() return r.readInt64()
case 4: case 4:
return r.readFloat32() return r.readFloat32()
case 5: case 5:
return r.readFloat64() return r.readFloat64()
case 6: case 6:
return utils.B2S(r.readBytes(int(r.readByte()))) return string(r.readBytes(int(r.readByte())))
case 7: case 7:
return utils.B2S(r.readBytes(int(r.readUInt32()))) return string(r.readBytes(int(r.readInt32())))
case 8: case 8:
s := r.ReadInt32(0) s := r.ReadInt32(0)
m := make(map[interface{}]interface{}) m := make(map[interface{}]interface{})
@ -361,19 +343,18 @@ func (r *JceReader) ReadAny(tag int) interface{} {
case 12: case 12:
return 0 return 0
case 13: case 13:
r.skipHead() r.readHead()
return r.readBytes(int(r.ReadInt32(0))) return r.readBytes(int(r.ReadInt32(0)))
default: default:
return nil return nil
} }
} }
*/
func (r *JceReader) ReadJceStruct(obj IJceStruct, tag int) { func (r *JceReader) ReadJceStruct(obj IJceStruct, tag int) {
if !r.skipToTag(tag) { if !r.skipToTag(tag) {
return return
} }
hd := r.readHead() hd, _ := r.readHead()
if hd.Type != 10 { if hd.Type != 10 {
return return
} }
@ -381,365 +362,41 @@ func (r *JceReader) ReadJceStruct(obj IJceStruct, tag int) {
r.skipToStructEnd() r.skipToStructEnd()
} }
func (r *JceReader) ReadMapStrStr(tag int) map[string]string {
if !r.skipToTag(tag) {
return nil
}
hd := r.readHead()
switch hd.Type {
case 8:
s := r.ReadInt32(0)
m := make(map[string]string, s)
for i := 0; i < int(s); i++ {
m[r.ReadString(0)] = r.ReadString(1)
}
return m
default:
return nil
}
}
func (r *JceReader) ReadMapStrByte(tag int) map[string][]byte {
if !r.skipToTag(tag) {
return nil
}
hd := r.readHead()
switch hd.Type {
case 8:
s := r.ReadInt32(0)
m := make(map[string][]byte, s)
for i := 0; i < int(s); i++ {
m[r.ReadString(0)] = r.ReadBytes(1)
}
return m
default:
return nil
}
}
func (r *JceReader) ReadMapIntVipInfo(tag int) map[int]*VipInfo {
if !r.skipToTag(tag) {
return nil
}
r.skipHead()
hd := r.readHead()
switch hd.Type {
case 8:
s := r.ReadInt32(0)
m := make(map[int]*VipInfo, s)
for i := 0; i < int(s); i++ {
k := r.ReadInt64(0)
v := new(VipInfo)
r.readHead()
v.ReadFrom(r)
r.skipToStructEnd()
m[int(k)] = v
}
r.skipToStructEnd()
return m
default:
r.skipToStructEnd()
return nil
}
}
func (r *JceReader) ReadMapStrMapStrByte(tag int) map[string]map[string][]byte {
if !r.skipToTag(tag) {
return nil
}
hd := r.readHead()
switch hd.Type {
case 8:
s := r.ReadInt32(0)
m := make(map[string]map[string][]byte, s)
for i := 0; i < int(s); i++ {
m[r.ReadString(0)] = r.ReadMapStrByte(1)
}
return m
default:
return nil
}
}
/*
func (r *JceReader) ReadMap(i interface{}, tag int) { func (r *JceReader) ReadMap(i interface{}, tag int) {
r.readMap(reflect.ValueOf(i), tag) v := reflect.ValueOf(i)
} if v.Kind() != reflect.Map {
return
func (r *JceReader) readMap(v reflect.Value, tag int) { }
if v.Kind() != reflect.Map || !r.skipToTag(tag) { if !r.skipToTag(tag) {
return return
} }
t := v.Type() t := v.Type()
kt := t.Key() kt := t.Key()
vt := t.Elem()
r.skipHead()
s := r.ReadInt32(0)
// map with string key or string value is very common.
// specialize for string
if kt.Kind() == reflect.String && vt.Kind() == reflect.String {
for i := 0; i < int(s); i++ {
kv := reflect.ValueOf(r.ReadString(0))
vv := reflect.ValueOf(r.ReadString(1))
v.SetMapIndex(kv, vv)
}
return
}
if kt.Kind() == reflect.String {
vv := reflect.New(vt)
for i := 0; i < int(s); i++ {
kv := reflect.ValueOf(r.ReadString(0))
r.readObject(vv, 1)
v.SetMapIndex(kv, vv.Elem())
}
return
}
kv := reflect.New(kt) kv := reflect.New(kt)
vt := t.Elem()
vv := reflect.New(vt) vv := reflect.New(vt)
r.readHead()
s := r.ReadInt32(0)
for i := 0; i < int(s); i++ { for i := 0; i < int(s); i++ {
r.readObject(kv, 0) r.ReadObject(kv.Interface(), 0)
r.readObject(vv, 1) r.ReadObject(vv.Interface(), 1)
v.SetMapIndex(kv.Elem(), vv.Elem()) v.SetMapIndex(kv.Elem(), vv.Elem())
} }
} }
*/
func (r *JceReader) ReadFileStorageServerInfos(tag int) []FileStorageServerInfo {
if !r.skipToTag(tag) {
return nil
}
hd := r.readHead()
switch hd.Type {
case 9:
s := r.ReadInt32(0)
sl := make([]FileStorageServerInfo, s)
for i := 0; i < int(s); i++ {
r.skipHead()
sl[i].ReadFrom(r)
r.skipToStructEnd()
}
return sl
default:
return nil
}
}
func (r *JceReader) ReadBigDataIPLists(tag int) []BigDataIPList {
if !r.skipToTag(tag) {
return nil
}
hd := r.readHead()
switch hd.Type {
case 9:
s := r.ReadInt32(0)
sl := make([]BigDataIPList, s)
for i := 0; i < int(s); i++ {
r.skipHead()
sl[i].ReadFrom(r)
r.skipToStructEnd()
}
return sl
default:
return nil
}
}
func (r *JceReader) ReadBigDataIPInfos(tag int) []BigDataIPInfo {
if !r.skipToTag(tag) {
return nil
}
hd := r.readHead()
switch hd.Type {
case 9:
s := r.ReadInt32(0)
sl := make([]BigDataIPInfo, s)
for i := 0; i < int(s); i++ {
r.skipHead()
sl[i].ReadFrom(r)
r.skipToStructEnd()
}
return sl
default:
return nil
}
}
func (r *JceReader) ReadOnlineInfos(tag int) []OnlineInfo {
if !r.skipToTag(tag) {
return nil
}
hd := r.readHead()
switch hd.Type {
case 9:
s := r.ReadInt32(0)
sl := make([]OnlineInfo, s)
for i := 0; i < int(s); i++ {
r.skipHead()
sl[i].ReadFrom(r)
r.skipToStructEnd()
}
return sl
default:
return nil
}
}
func (r *JceReader) ReadInstanceInfos(tag int) []InstanceInfo {
if !r.skipToTag(tag) {
return nil
}
hd := r.readHead()
switch hd.Type {
case 9:
s := r.ReadInt32(0)
sl := make([]InstanceInfo, s)
for i := 0; i < int(s); i++ {
r.skipHead()
sl[i].ReadFrom(r)
r.skipToStructEnd()
}
return sl
default:
return nil
}
}
func (r *JceReader) ReadSsoServerInfos(tag int) []SsoServerInfo {
if !r.skipToTag(tag) {
return nil
}
hd := r.readHead()
switch hd.Type {
case 9:
s := r.ReadInt32(0)
sl := make([]SsoServerInfo, s)
for i := 0; i < int(s); i++ {
r.skipHead()
sl[i].ReadFrom(r)
r.skipToStructEnd()
}
return sl
default:
return nil
}
}
func (r *JceReader) ReadFriendInfos(tag int) []FriendInfo {
if !r.skipToTag(tag) {
return nil
}
hd := r.readHead()
switch hd.Type {
case 9:
s := r.ReadInt32(0)
sl := make([]FriendInfo, s)
for i := 0; i < int(s); i++ {
r.skipHead()
sl[i].ReadFrom(r)
r.skipToStructEnd()
}
return sl
default:
return nil
}
}
func (r *JceReader) ReadTroopNumbers(tag int) []TroopNumber {
if !r.skipToTag(tag) {
return nil
}
hd := r.readHead()
switch hd.Type {
case 9:
s := r.ReadInt32(0)
sl := make([]TroopNumber, s)
for i := 0; i < int(s); i++ {
r.skipHead()
sl[i].ReadFrom(r)
r.skipToStructEnd()
}
return sl
default:
return nil
}
}
func (r *JceReader) ReadTroopMemberInfos(tag int) []TroopMemberInfo {
if !r.skipToTag(tag) {
return nil
}
hd := r.readHead()
switch hd.Type {
case 9:
s := r.ReadInt32(0)
sl := make([]TroopMemberInfo, s)
for i := 0; i < int(s); i++ {
r.skipHead()
sl[i].ReadFrom(r)
r.skipToStructEnd()
}
return sl
default:
return nil
}
}
func (r *JceReader) ReadPushMessageInfos(tag int) []PushMessageInfo {
if !r.skipToTag(tag) {
return nil
}
hd := r.readHead()
switch hd.Type {
case 9:
s := r.ReadInt32(0)
sl := make([]PushMessageInfo, s)
for i := 0; i < int(s); i++ {
r.skipHead()
sl[i].ReadFrom(r)
r.skipToStructEnd()
}
return sl
default:
return nil
}
}
func (r *JceReader) ReadSvcDevLoginInfos(tag int) []SvcDevLoginInfo {
if !r.skipToTag(tag) {
return nil
}
hd := r.readHead()
switch hd.Type {
case 9:
s := r.ReadInt32(0)
sl := make([]SvcDevLoginInfo, s)
for i := 0; i < int(s); i++ {
r.skipHead()
sl[i].ReadFrom(r)
r.skipToStructEnd()
}
return sl
default:
return nil
}
}
/*
func (r *JceReader) ReadSlice(i interface{}, tag int) { func (r *JceReader) ReadSlice(i interface{}, tag int) {
r.readSlice(reflect.ValueOf(i), tag) t := reflect.TypeOf(i)
} v := reflect.ValueOf(i).Elem()
if t.Kind() != reflect.Ptr || t.Elem().Kind() != reflect.Slice {
func (r *JceReader) readSlice(v reflect.Value, tag int) {
t := v.Type()
if t.Kind() != reflect.Ptr || t.Elem().Kind() != reflect.Slice || !r.skipToTag(tag) {
return return
} }
v = v.Elem()
t = t.Elem() t = t.Elem()
if !r.skipToTag(tag) {
return
}
hd, _ := r.readHead() hd, _ := r.readHead()
if hd.Type == 9 { if hd.Type == 9 {
s := r.ReadInt32(0) s := r.ReadInt32(0)
@ -747,65 +404,56 @@ func (r *JceReader) readSlice(v reflect.Value, tag int) {
t = t.Elem() t = t.Elem()
val := reflect.New(t) val := reflect.New(t)
for i := 0; i < int(s); i++ { for i := 0; i < int(s); i++ {
r.readObject(val, 0) r.ReadObject(val.Interface(), 0)
sv.Index(i).Set(val.Elem()) sv.Index(i).Set(val.Elem())
} }
v.Set(sv) v.Set(sv)
} }
if hd.Type == 13 && t.Elem().Kind() == reflect.Uint8 { if hd.Type == 13 && t.Elem().Kind() == reflect.Uint8 {
r.skipHead() r.readHead()
arr := r.readBytes(int(r.ReadInt32(0))) arr := r.readBytes(int(r.ReadInt32(0)))
v.SetBytes(arr) v.SetBytes(arr)
} }
} }
func (r *JceReader) ReadObject(i interface{}, tag int) { func (r *JceReader) ReadObject(i interface{}, tag int) {
r.readObject(reflect.ValueOf(i), tag) va := reflect.ValueOf(i)
} if va.Kind() != reflect.Ptr || va.IsNil() {
func (r *JceReader) readObject(v reflect.Value, tag int) {
if v.Kind() != reflect.Ptr || v.IsNil() {
return return
} }
elemType := v.Type().Elem() if ve := va.Elem(); ve.Kind() == reflect.Map {
if elemType.Kind() == reflect.Map { ve.Set(reflect.MakeMap(ve.Type()))
elem := v.Elem() r.ReadMap(ve.Interface(), tag)
elem.Set(reflect.MakeMap(elem.Type()))
r.readMap(elem, tag)
return
} else if elemType.Kind() == reflect.Slice && // *[]byte
elemType.Elem().Kind() == reflect.Uint8 {
elem := v.Elem()
elem.SetBytes(r.ReadBytes(tag))
return return
} }
switch o := i.(type) {
switch elemType.Kind() { case *byte:
case reflect.Uint8, reflect.Int8: *o = r.ReadByte(tag)
*(*uint8)(pointerOf(v)) = r.ReadByte(tag) case *bool:
case reflect.Bool: *o = r.ReadBool(tag)
*(*bool)(pointerOf(v)) = r.ReadBool(tag) case *int16:
case reflect.Uint16, reflect.Int16: *o = r.ReadInt16(tag)
*(*int16)(pointerOf(v)) = r.ReadInt16(tag) case *int:
case reflect.Uint32, reflect.Int32: *o = int(r.ReadInt32(tag))
*(*int32)(pointerOf(v)) = r.ReadInt32(tag) case *int32:
case reflect.Uint64, reflect.Int64: *o = r.ReadInt32(tag)
*(*int64)(pointerOf(v)) = r.ReadInt64(tag) case *int64:
case reflect.String: *o = r.ReadInt64(tag)
*(*string)(pointerOf(v)) = r.ReadString(tag) case *float32:
*o = r.ReadFloat32(tag)
default: case *float64:
// other cases *o = r.ReadFloat64(tag)
switch o := v.Interface().(type) { case *string:
case IJceStruct: *o = r.ReadString(tag)
r.skipHead() case *[]byte:
o.ReadFrom(r) r.ReadSlice(o, tag)
r.skipToStructEnd() case IJceStruct:
case *float32: r.readHead()
*o = r.ReadFloat32(tag) o.ReadFrom(r)
case *float64: r.skipToStructEnd()
*o = r.ReadFloat64(tag)
}
} }
} }
*/
func (r *JceReader) ReadAvailable() []byte {
return r.readBytes(r.buf.Len())
}

View File

@ -1,27 +1,22 @@
package jce package jce
import ( import (
"crypto/rand" "math/rand"
"reflect"
"strconv"
"sync"
"testing" "testing"
"unsafe"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
func TestJceReader_ReadSlice(t *testing.T) { func TestJceReader_ReadSlice(t *testing.T) {
s := make([][]byte, 50) s := make([]int64, 50)
for i := range s { for i := range s {
b := make([]byte, 64) s[i] = rand.Int63()
_, _ = rand.Read(b)
s[i] = b
} }
w := NewJceWriter() w := NewJceWriter()
w.WriteBytesSlice(s, 1) w.WriteObject(s, 1)
r := NewJceReader(w.Bytes()) r := NewJceReader(w.Bytes())
result := r.ReadByteArrArr(1) var result []int64
r.ReadSlice(&result, 1)
assert.Equal(t, s, result) assert.Equal(t, s, result)
} }
@ -40,9 +35,10 @@ func BenchmarkJceReader_ReadSlice(b *testing.B) {
src := w.Bytes() src := w.Bytes()
b.SetBytes(int64(len(src))) b.SetBytes(int64(len(src)))
b.StartTimer() b.StartTimer()
result := make([]BigDataIPInfo, 0)
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
r := NewJceReader(src) r := NewJceReader(src)
_ = r.ReadBigDataIPInfos(1) r.ReadSlice(&result, 1)
} }
} }
@ -63,13 +59,12 @@ var req = RequestDataVersion2{
"5": { "5": {
"123": []byte(`123`), "123": []byte(`123`),
}, },
}, }}
}
func TestRequestDataVersion2_ReadFrom(t *testing.T) { func TestRequestDataVersion2_ReadFrom(t *testing.T) {
// todo(wdv): fuzz test // todo(wdv): fuzz test
w := NewJceWriter() w := NewJceWriter()
w.writeMapStrMapStrBytes(req.Map, 0) w.WriteObject(req.Map, 0)
src := w.Bytes() src := w.Bytes()
result := RequestDataVersion2{} result := RequestDataVersion2{}
result.ReadFrom(NewJceReader(src)) result.ReadFrom(NewJceReader(src))
@ -78,7 +73,7 @@ func TestRequestDataVersion2_ReadFrom(t *testing.T) {
func BenchmarkRequestDataVersion2_ReadFrom(b *testing.B) { func BenchmarkRequestDataVersion2_ReadFrom(b *testing.B) {
w := NewJceWriter() w := NewJceWriter()
w.writeMapStrMapStrBytes(req.Map, 0) w.WriteObject(req.Map, 0)
src := w.Bytes() src := w.Bytes()
b.SetBytes(int64(len(src))) b.SetBytes(int64(len(src)))
result := &RequestDataVersion2{} result := &RequestDataVersion2{}
@ -98,210 +93,3 @@ func TestJceReader_ReadBytes(t *testing.T) {
assert.Equal(t, b, rb) assert.Equal(t, b, rb)
} }
func (w *JceWriter) WriteObject(i any, tag byte) {
t := reflect.TypeOf(i)
if t.Kind() == reflect.Map {
w.WriteMap(i, tag)
return
}
if t.Kind() == reflect.Slice {
if b, ok := i.([]byte); ok {
w.WriteBytes(b, tag)
return
}
w.WriteSlice(i, tag)
return
}
switch o := i.(type) {
case byte:
w.WriteByte(o, tag)
case bool:
w.WriteBool(o, tag)
case int16:
w.WriteInt16(o, tag)
case int32:
w.WriteInt32(o, tag)
case int64:
w.WriteInt64(o, tag)
case float32:
w.WriteFloat32(o, tag)
case float64:
w.WriteFloat64(o, tag)
case string:
w.WriteString(o, tag)
case IJceStruct:
w.WriteJceStruct(o, tag)
}
}
func (w *JceWriter) writeObject(v reflect.Value, tag byte) {
k := v.Kind()
if k == reflect.Map {
switch o := v.Interface().(type) {
case map[string]string:
w.writeMapStrStr(o, tag)
case map[string][]byte:
w.writeMapStrBytes(o, tag)
case map[string]map[string][]byte:
w.writeMapStrMapStrBytes(o, tag)
default:
w.writeMap(v, tag)
}
return
}
if k == reflect.Slice {
switch o := v.Interface().(type) {
case []byte:
w.WriteBytes(o, tag)
case []IJceStruct:
w.WriteJceStructSlice(o, tag)
default:
w.writeSlice(v, tag)
}
return
}
switch k {
case reflect.Uint8, reflect.Int8:
w.WriteByte(*(*byte)(pointerOf(v)), tag)
case reflect.Uint16, reflect.Int16:
w.WriteInt16(*(*int16)(pointerOf(v)), tag)
case reflect.Uint32, reflect.Int32:
w.WriteInt32(*(*int32)(pointerOf(v)), tag)
case reflect.Uint64, reflect.Int64:
w.WriteInt64(*(*int64)(pointerOf(v)), tag)
case reflect.String:
w.WriteString(v.String(), tag)
default:
switch o := v.Interface().(type) {
case IJceStruct:
w.WriteJceStruct(o, tag)
case float32:
w.WriteFloat32(o, tag)
case float64:
w.WriteFloat64(o, tag)
}
}
}
type decoder struct {
index int
id int
}
var decoderCache = sync.Map{}
// WriteJceStructRaw 写入 Jce 结构体
func (w *JceWriter) WriteJceStructRaw(s any) {
t := reflect.TypeOf(s)
if t.Kind() != reflect.Ptr {
return
}
t = t.Elem()
v := reflect.ValueOf(s).Elem()
var jceDec []decoder
dec, ok := decoderCache.Load(t)
if ok { // 从缓存中加载
jceDec = dec.([]decoder)
} else { // 初次反射
jceDec = make([]decoder, 0, t.NumField())
for i := 0; i < t.NumField(); i++ {
field := t.Field(i)
strId := field.Tag.Get("jceId")
if strId == "" {
continue
}
id, err := strconv.Atoi(strId)
if err != nil {
continue
}
jceDec = append(jceDec, decoder{
index: i,
id: id,
})
}
decoderCache.Store(t, jceDec) // 存入缓存
}
for _, dec := range jceDec {
obj := v.Field(dec.index)
w.writeObject(obj, byte(dec.id))
}
}
func (w *JceWriter) WriteJceStruct(s IJceStruct, tag byte) {
w.writeHead(10, tag)
w.WriteJceStructRaw(s)
w.writeHead(11, 0)
}
func (w *JceWriter) WriteSlice(i any, tag byte) {
va := reflect.ValueOf(i)
if va.Kind() != reflect.Slice {
panic("JceWriter.WriteSlice: not a slice")
}
w.writeSlice(va, tag)
}
func (w *JceWriter) writeSlice(slice reflect.Value, tag byte) {
if slice.Kind() != reflect.Slice {
return
}
w.writeHead(9, tag)
if slice.Len() == 0 {
w.writeHead(12, 0) // w.WriteInt32(0, 0)
return
}
w.WriteInt32(int32(slice.Len()), 0)
for i := 0; i < slice.Len(); i++ {
v := slice.Index(i)
w.writeObject(v, 0)
}
}
func (w *JceWriter) WriteJceStructSlice(l []IJceStruct, tag byte) {
w.writeHead(9, tag)
if len(l) == 0 {
w.writeHead(12, 0) // w.WriteInt32(0, 0)
return
}
w.WriteInt32(int32(len(l)), 0)
for _, v := range l {
w.WriteJceStruct(v, 0)
}
}
func (w *JceWriter) WriteMap(m any, tag byte) {
va := reflect.ValueOf(m)
if va.Kind() != reflect.Map {
panic("JceWriter.WriteMap: not a map")
}
w.writeMap(va, tag)
}
func (w *JceWriter) writeMap(m reflect.Value, tag byte) {
if m.IsNil() {
w.writeHead(8, tag)
w.writeHead(12, 0) // w.WriteInt32(0, 0)
return
}
if m.Kind() != reflect.Map {
return
}
w.writeHead(8, tag)
w.WriteInt32(int32(m.Len()), 0)
iter := m.MapRange()
for iter.Next() {
w.writeObject(iter.Key(), 0)
w.writeObject(iter.Value(), 1)
}
}
type value struct {
typ unsafe.Pointer
data unsafe.Pointer
flag uintptr
}
func pointerOf(v reflect.Value) unsafe.Pointer {
return (*value)(unsafe.Pointer(&v)).data
}

View File

@ -1,11 +1,10 @@
package jce package jce
type IJceStruct interface { type IJceStruct interface {
ToBytes() []byte // ToBytes() []byte
ReadFrom(*JceReader) ReadFrom(*JceReader)
} }
//go:generate go run github.com/Mrs4s/MiraiGo/internal/generator/jce_gen -file=structs.go -o structs_tobytes.go
type ( type (
RequestPacket struct { RequestPacket struct {
IVersion int16 `jceId:"1"` IVersion int16 `jceId:"1"`
@ -75,6 +74,7 @@ type (
} }
SvcReqRegister struct { SvcReqRegister struct {
IJceStruct
Uin int64 `jceId:"0"` Uin int64 `jceId:"0"`
Bid int64 `jceId:"1"` Bid int64 `jceId:"1"`
ConnType byte `jceId:"2"` ConnType byte `jceId:"2"`
@ -139,6 +139,7 @@ type (
} }
SvcReqRegisterNew struct { SvcReqRegisterNew struct {
IJceStruct
RequestOptional int64 `jceId:"0"` RequestOptional int64 `jceId:"0"`
C2CMsg IJceStruct `jceId:"1"` // SvcReqGetMsgV2 C2CMsg IJceStruct `jceId:"1"` // SvcReqGetMsgV2
GroupMsg IJceStruct `jceId:"2"` // SvcReqPullGroupMsgSeq GroupMsg IJceStruct `jceId:"2"` // SvcReqPullGroupMsgSeq
@ -172,6 +173,7 @@ type (
} }
PullGroupSeqParam struct { PullGroupSeqParam struct {
IJceStruct
GroupCode int64 `jceId:"0"` GroupCode int64 `jceId:"0"`
LastSeqId int64 `jceId:"1"` LastSeqId int64 `jceId:"1"`
} }
@ -249,6 +251,7 @@ type (
} }
SvcRespPushMsg struct { SvcRespPushMsg struct {
IJceStruct
Uin int64 `jceId:"0"` Uin int64 `jceId:"0"`
DelInfos []IJceStruct `jceId:"1"` DelInfos []IJceStruct `jceId:"1"`
Svrip int32 `jceId:"2"` Svrip int32 `jceId:"2"`
@ -296,6 +299,7 @@ type (
} }
FriendListRequest struct { FriendListRequest struct {
IJceStruct
Reqtype int32 `jceId:"0"` Reqtype int32 `jceId:"0"`
IfReflush byte `jceId:"1"` IfReflush byte `jceId:"1"`
Uin int64 `jceId:"2"` Uin int64 `jceId:"2"`
@ -377,6 +381,7 @@ type (
} }
TroopListRequest struct { TroopListRequest struct {
IJceStruct
Uin int64 `jceId:"0"` Uin int64 `jceId:"0"`
GetMSFMsgFlag byte `jceId:"1"` GetMSFMsgFlag byte `jceId:"1"`
Cookies []byte `jceId:"2"` Cookies []byte `jceId:"2"`
@ -427,6 +432,7 @@ type (
} }
TroopMemberListRequest struct { TroopMemberListRequest struct {
IJceStruct
Uin int64 `jceId:"0"` Uin int64 `jceId:"0"`
GroupCode int64 `jceId:"1"` GroupCode int64 `jceId:"1"`
NextUin int64 `jceId:"2"` NextUin int64 `jceId:"2"`
@ -476,6 +482,7 @@ type (
} }
ModifyGroupCardRequest struct { ModifyGroupCardRequest struct {
IJceStruct
Zero int64 `jceId:"0"` Zero int64 `jceId:"0"`
GroupCode int64 `jceId:"1"` GroupCode int64 `jceId:"1"`
NewSeq int64 `jceId:"2"` NewSeq int64 `jceId:"2"`
@ -494,6 +501,7 @@ type (
} }
SummaryCardReq struct { SummaryCardReq struct {
IJceStruct
Uin int64 `jceId:"0"` Uin int64 `jceId:"0"`
ComeFrom int32 `jceId:"1"` ComeFrom int32 `jceId:"1"`
QzoneFeedTimestamp int64 `jceId:"2"` QzoneFeedTimestamp int64 `jceId:"2"`
@ -515,6 +523,7 @@ type (
} }
SummaryCardReqSearch struct { SummaryCardReqSearch struct {
IJceStruct
Keyword string `jceId:"0"` Keyword string `jceId:"0"`
CountryCode string `jceId:"1"` CountryCode string `jceId:"1"`
Version int32 `jceId:"2"` Version int32 `jceId:"2"`
@ -522,40 +531,56 @@ type (
} }
DelFriendReq struct { DelFriendReq struct {
IJceStruct
Uin int64 `jceId:"0"` Uin int64 `jceId:"0"`
DelUin int64 `jceId:"1"` DelUin int64 `jceId:"1"`
DelType byte `jceId:"2"` DelType byte `jceId:"2"`
Version int32 `jceId:"3"` Version int32 `jceId:"3"`
} }
VipInfo struct {
Open byte `jceId:"0"` // 1 为开通
Type int32 `jceId:"1"` // 1 为年费
Level int32 `jceId:"2"`
}
) )
func (pkt *RequestPacket) ToBytes() []byte {
w := NewJceWriter()
w.WriteJceStructRaw(pkt)
return w.Bytes()
}
func (pkt *RequestPacket) ReadFrom(r *JceReader) { func (pkt *RequestPacket) ReadFrom(r *JceReader) {
pkt.SBuffer = []byte{}
pkt.Context = make(map[string]string)
pkt.Status = make(map[string]string)
pkt.IVersion = r.ReadInt16(1) pkt.IVersion = r.ReadInt16(1)
pkt.CPacketType = r.ReadByte(2) pkt.CPacketType = r.ReadByte(2)
pkt.IMessageType = r.ReadInt32(3) pkt.IMessageType = r.ReadInt32(3)
pkt.IRequestId = r.ReadInt32(4) pkt.IRequestId = r.ReadInt32(4)
pkt.SServantName = r.ReadString(5) pkt.SServantName = r.ReadString(5)
pkt.SFuncName = r.ReadString(6) pkt.SFuncName = r.ReadString(6)
pkt.SBuffer = r.ReadBytes(7) r.ReadSlice(&pkt.SBuffer, 7)
pkt.ITimeout = r.ReadInt32(8) pkt.ITimeout = r.ReadInt32(8)
// r.ReadMap(pkt.Context, 9) r.ReadMap(pkt.Context, 9)
pkt.Context = r.ReadMapStrStr(9) r.ReadMap(pkt.Status, 10)
// r.ReadMap(pkt.Status, 10) }
pkt.Status = r.ReadMapStrStr(10)
func (pkt *RequestDataVersion3) ToBytes() []byte {
w := NewJceWriter()
w.WriteJceStructRaw(pkt)
return w.Bytes()
} }
func (pkt *RequestDataVersion3) ReadFrom(r *JceReader) { func (pkt *RequestDataVersion3) ReadFrom(r *JceReader) {
pkt.Map = r.ReadMapStrByte(0) pkt.Map = make(map[string][]byte)
r.ReadMap(pkt.Map, 0)
}
func (pkt *RequestDataVersion2) ToBytes() []byte {
w := NewJceWriter()
w.WriteJceStructRaw(pkt)
return w.Bytes()
} }
func (pkt *RequestDataVersion2) ReadFrom(r *JceReader) { func (pkt *RequestDataVersion2) ReadFrom(r *JceReader) {
pkt.Map = r.ReadMapStrMapStrByte(0) pkt.Map = make(map[string]map[string][]byte)
r.ReadMap(pkt.Map, 0)
} }
func (pkt *SsoServerInfo) ReadFrom(r *JceReader) { func (pkt *SsoServerInfo) ReadFrom(r *JceReader) {
@ -565,15 +590,22 @@ func (pkt *SsoServerInfo) ReadFrom(r *JceReader) {
} }
func (pkt *FileStoragePushFSSvcList) ReadFrom(r *JceReader) { func (pkt *FileStoragePushFSSvcList) ReadFrom(r *JceReader) {
pkt.UploadList = r.ReadFileStorageServerInfos(0) pkt.UploadList = []FileStorageServerInfo{}
pkt.PicDownloadList = r.ReadFileStorageServerInfos(1) pkt.PicDownloadList = []FileStorageServerInfo{}
pkt.GPicDownloadList = r.ReadFileStorageServerInfos(2) pkt.GPicDownloadList = []FileStorageServerInfo{}
pkt.QZoneProxyServiceList = r.ReadFileStorageServerInfos(3) pkt.QZoneProxyServiceList = []FileStorageServerInfo{}
pkt.UrlEncodeServiceList = r.ReadFileStorageServerInfos(4) pkt.UrlEncodeServiceList = []FileStorageServerInfo{}
pkt.BigDataChannel = &BigDataChannel{} pkt.BigDataChannel = &BigDataChannel{}
pkt.VipEmotionList = []FileStorageServerInfo{}
pkt.C2CPicDownList = []FileStorageServerInfo{}
r.ReadSlice(&pkt.UploadList, 0)
r.ReadSlice(&pkt.PicDownloadList, 1)
r.ReadSlice(&pkt.GPicDownloadList, 2)
r.ReadSlice(&pkt.QZoneProxyServiceList, 3)
r.ReadSlice(&pkt.UrlEncodeServiceList, 4)
r.ReadJceStruct(pkt.BigDataChannel, 5) r.ReadJceStruct(pkt.BigDataChannel, 5)
pkt.VipEmotionList = r.ReadFileStorageServerInfos(6) r.ReadSlice(&pkt.VipEmotionList, 6)
pkt.C2CPicDownList = r.ReadFileStorageServerInfos(7) r.ReadSlice(&pkt.C2CPicDownList, 7)
pkt.PttList = r.ReadBytes(10) pkt.PttList = r.ReadBytes(10)
} }
@ -583,7 +615,8 @@ func (pkt *FileStorageServerInfo) ReadFrom(r *JceReader) {
} }
func (pkt *BigDataChannel) ReadFrom(r *JceReader) { func (pkt *BigDataChannel) ReadFrom(r *JceReader) {
pkt.IPLists = r.ReadBigDataIPLists(0) pkt.IPLists = []BigDataIPList{}
r.ReadSlice(&pkt.IPLists, 0)
pkt.SigSession = r.ReadBytes(1) pkt.SigSession = r.ReadBytes(1)
pkt.KeySession = r.ReadBytes(2) pkt.KeySession = r.ReadBytes(2)
pkt.SigUin = r.ReadInt64(3) pkt.SigUin = r.ReadInt64(3)
@ -592,8 +625,9 @@ func (pkt *BigDataChannel) ReadFrom(r *JceReader) {
} }
func (pkt *BigDataIPList) ReadFrom(r *JceReader) { func (pkt *BigDataIPList) ReadFrom(r *JceReader) {
pkt.IPList = []BigDataIPInfo{}
pkt.ServiceType = r.ReadInt64(0) pkt.ServiceType = r.ReadInt64(0)
pkt.IPList = r.ReadBigDataIPInfos(1) r.ReadSlice(&pkt.IPList, 1)
pkt.FragmentSize = r.ReadInt64(3) pkt.FragmentSize = r.ReadInt64(3)
} }
@ -603,6 +637,12 @@ func (pkt *BigDataIPInfo) ReadFrom(r *JceReader) {
pkt.Port = r.ReadInt64(2) pkt.Port = r.ReadInt64(2)
} }
func (pkt *SvcReqRegister) ToBytes() []byte {
w := NewJceWriter()
w.WriteJceStructRaw(pkt)
return w.Bytes()
}
func (pkt *SvcRespRegister) ReadFrom(r *JceReader) { func (pkt *SvcRespRegister) ReadFrom(r *JceReader) {
pkt.Uin = r.ReadInt64(0) pkt.Uin = r.ReadInt64(0)
pkt.Bid = r.ReadInt64(1) pkt.Bid = r.ReadInt64(1)
@ -624,6 +664,24 @@ func (pkt *SvcRespRegister) ReadFrom(r *JceReader) {
pkt.ExtOnlineStatus = r.ReadInt64(17) pkt.ExtOnlineStatus = r.ReadInt64(17)
} }
func (pkt *FriendListRequest) ToBytes() []byte {
w := NewJceWriter()
w.WriteJceStructRaw(pkt)
return w.Bytes()
}
func (pkt *SummaryCardReq) ToBytes() []byte {
w := NewJceWriter()
w.WriteJceStructRaw(pkt)
return w.Bytes()
}
func (pkt *SummaryCardReqSearch) ToBytes() []byte {
w := NewJceWriter()
w.WriteJceStructRaw(pkt)
return w.Bytes()
}
func (pkt *FriendInfo) ReadFrom(r *JceReader) { func (pkt *FriendInfo) ReadFrom(r *JceReader) {
pkt.FriendUin = r.ReadInt64(0) pkt.FriendUin = r.ReadInt64(0)
pkt.GroupId = r.ReadByte(1) pkt.GroupId = r.ReadByte(1)
@ -634,7 +692,14 @@ func (pkt *FriendInfo) ReadFrom(r *JceReader) {
pkt.Nick = r.ReadString(14) pkt.Nick = r.ReadString(14)
pkt.Network = r.ReadByte(20) pkt.Network = r.ReadByte(20)
pkt.NetworkType = r.ReadInt32(24) pkt.NetworkType = r.ReadInt32(24)
pkt.CardID = r.ReadBytes(41) pkt.CardID = []byte{}
r.ReadObject(&pkt.CardID, 41)
}
func (pkt *TroopListRequest) ToBytes() []byte {
w := NewJceWriter()
w.WriteJceStructRaw(pkt)
return w.Bytes()
} }
func (pkt *TroopNumber) ReadFrom(r *JceReader) { func (pkt *TroopNumber) ReadFrom(r *JceReader) {
@ -647,6 +712,12 @@ func (pkt *TroopNumber) ReadFrom(r *JceReader) {
pkt.MaxGroupMemberNum = r.ReadInt64(29) pkt.MaxGroupMemberNum = r.ReadInt64(29)
} }
func (pkt *TroopMemberListRequest) ToBytes() []byte {
w := NewJceWriter()
w.WriteJceStructRaw(pkt)
return w.Bytes()
}
func (pkt *TroopMemberInfo) ReadFrom(r *JceReader) { func (pkt *TroopMemberInfo) ReadFrom(r *JceReader) {
pkt.MemberUin = r.ReadInt64(0) pkt.MemberUin = r.ReadInt64(0)
pkt.FaceId = r.ReadInt16(1) pkt.FaceId = r.ReadInt16(1)
@ -679,7 +750,8 @@ func (pkt *PushMessageInfo) ReadFrom(r *JceReader) {
func (pkt *SvcDevLoginInfo) ReadFrom(r *JceReader) { func (pkt *SvcDevLoginInfo) ReadFrom(r *JceReader) {
pkt.AppId = r.ReadInt64(0) pkt.AppId = r.ReadInt64(0)
pkt.Guid = r.ReadBytes(1) pkt.Guid = []byte{}
r.ReadSlice(&pkt.Guid, 1)
pkt.LoginTime = r.ReadInt64(2) pkt.LoginTime = r.ReadInt64(2)
pkt.LoginPlatform = r.ReadInt64(3) pkt.LoginPlatform = r.ReadInt64(3)
pkt.LoginLocation = r.ReadString(4) pkt.LoginLocation = r.ReadString(4)
@ -691,6 +763,7 @@ func (pkt *SvcDevLoginInfo) ReadFrom(r *JceReader) {
} }
func (pkt *SvcRespParam) ReadFrom(r *JceReader) { func (pkt *SvcRespParam) ReadFrom(r *JceReader) {
pkt.OnlineInfos = []OnlineInfo{}
pkt.PCStat = r.ReadInt32(0) pkt.PCStat = r.ReadInt32(0)
pkt.IsSupportC2CRoamMsg = r.ReadInt32(1) pkt.IsSupportC2CRoamMsg = r.ReadInt32(1)
pkt.IsSupportDataLine = r.ReadInt32(2) pkt.IsSupportDataLine = r.ReadInt32(2)
@ -698,7 +771,7 @@ func (pkt *SvcRespParam) ReadFrom(r *JceReader) {
pkt.IsSupportViewPCFile = r.ReadInt32(4) pkt.IsSupportViewPCFile = r.ReadInt32(4)
pkt.PcVersion = r.ReadInt32(5) pkt.PcVersion = r.ReadInt32(5)
pkt.RoamFlag = r.ReadInt64(6) pkt.RoamFlag = r.ReadInt64(6)
pkt.OnlineInfos = r.ReadOnlineInfos(7) r.ReadSlice(&pkt.OnlineInfos, 7)
pkt.PCClientType = r.ReadInt32(8) pkt.PCClientType = r.ReadInt32(8)
} }
@ -724,6 +797,7 @@ func (pkt *OnlineInfo) ReadFrom(r *JceReader) {
} }
func (pkt *SvcReqMSFLoginNotify) ReadFrom(r *JceReader) { func (pkt *SvcReqMSFLoginNotify) ReadFrom(r *JceReader) {
pkt.InstanceList = []InstanceInfo{}
pkt.AppId = r.ReadInt64(0) pkt.AppId = r.ReadInt64(0)
pkt.Status = r.ReadByte(1) pkt.Status = r.ReadByte(1)
pkt.Tablet = r.ReadByte(2) pkt.Tablet = r.ReadByte(2)
@ -732,7 +806,7 @@ func (pkt *SvcReqMSFLoginNotify) ReadFrom(r *JceReader) {
pkt.Info = r.ReadString(5) pkt.Info = r.ReadString(5)
pkt.ProductType = r.ReadInt64(6) pkt.ProductType = r.ReadInt64(6)
pkt.ClientType = r.ReadInt64(7) pkt.ClientType = r.ReadInt64(7)
pkt.InstanceList = r.ReadInstanceInfos(8) r.ReadSlice(&pkt.InstanceList, 8)
} }
func (pkt *InstanceInfo) ReadFrom(r *JceReader) { func (pkt *InstanceInfo) ReadFrom(r *JceReader) {
@ -743,8 +817,32 @@ func (pkt *InstanceInfo) ReadFrom(r *JceReader) {
pkt.ClientType = r.ReadInt64(4) pkt.ClientType = r.ReadInt64(4)
} }
func (pkt *VipInfo) ReadFrom(r *JceReader) { func (pkt *SvcRespPushMsg) ToBytes() []byte {
pkt.Open = r.ReadByte(0) w := NewJceWriter()
pkt.Type = r.ReadInt32(1) w.WriteJceStructRaw(pkt)
pkt.Level = r.ReadInt32(2) return w.Bytes()
}
func (pkt *ModifyGroupCardRequest) ToBytes() []byte {
w := NewJceWriter()
w.WriteJceStructRaw(pkt)
return w.Bytes()
}
func (pkt *SvcReqGetDevLoginInfo) ToBytes() []byte {
w := NewJceWriter()
w.WriteJceStructRaw(pkt)
return w.Bytes()
}
func (pkt *SvcReqRegisterNew) ToBytes() []byte {
w := NewJceWriter()
w.WriteJceStructRaw(pkt)
return w.Bytes()
}
func (pkt *DelFriendReq) ToBytes() []byte {
w := NewJceWriter()
w.WriteJceStructRaw(pkt)
return w.Bytes()
} }

View File

@ -1,760 +0,0 @@
// Code generated by internal/generator/jce_gen; DO NOT EDIT.
package jce
func (pkt *RequestPacket) ToBytes() []byte {
w := NewJceWriter()
w.WriteInt16(pkt.IVersion, 1)
w.WriteByte(pkt.CPacketType, 2)
w.WriteInt32(pkt.IMessageType, 3)
w.WriteInt32(pkt.IRequestId, 4)
w.WriteString(pkt.SServantName, 5)
w.WriteString(pkt.SFuncName, 6)
w.WriteBytes(pkt.SBuffer, 7)
w.WriteInt32(pkt.ITimeout, 8)
w.writeMapStrStr(pkt.Context, 9)
w.writeMapStrStr(pkt.Status, 10)
return w.Bytes()
}
func (pkt *RequestDataVersion3) ToBytes() []byte {
w := NewJceWriter()
w.writeMapStrBytes(pkt.Map, 0)
return w.Bytes()
}
func (pkt *RequestDataVersion2) ToBytes() []byte {
w := NewJceWriter()
w.writeMapStrMapStrBytes(pkt.Map, 0)
return w.Bytes()
}
func (pkt *SsoServerInfo) ToBytes() []byte {
w := NewJceWriter()
w.WriteString(pkt.Server, 1)
w.WriteInt32(pkt.Port, 2)
w.WriteString(pkt.Location, 8)
return w.Bytes()
}
func (pkt *FileStoragePushFSSvcList) ToBytes() []byte {
w := NewJceWriter()
{ // write pkt.UploadList tag=0
w.writeHead(9, 0)
if len(pkt.UploadList) == 0 {
w.writeHead(12, 0) // w.WriteInt32(0, 0)
} else {
w.WriteInt32(int32(len(pkt.UploadList)), 0)
for _, i := range pkt.UploadList {
w.writeHead(10, 0)
w.buf.Write(i.ToBytes())
w.writeHead(11, 0)
}
}
}
{ // write pkt.PicDownloadList tag=1
w.writeHead(9, 1)
if len(pkt.PicDownloadList) == 0 {
w.writeHead(12, 0) // w.WriteInt32(0, 0)
} else {
w.WriteInt32(int32(len(pkt.PicDownloadList)), 0)
for _, i := range pkt.PicDownloadList {
w.writeHead(10, 0)
w.buf.Write(i.ToBytes())
w.writeHead(11, 0)
}
}
}
{ // write pkt.GPicDownloadList tag=2
w.writeHead(9, 2)
if len(pkt.GPicDownloadList) == 0 {
w.writeHead(12, 0) // w.WriteInt32(0, 0)
} else {
w.WriteInt32(int32(len(pkt.GPicDownloadList)), 0)
for _, i := range pkt.GPicDownloadList {
w.writeHead(10, 0)
w.buf.Write(i.ToBytes())
w.writeHead(11, 0)
}
}
}
{ // write pkt.QZoneProxyServiceList tag=3
w.writeHead(9, 3)
if len(pkt.QZoneProxyServiceList) == 0 {
w.writeHead(12, 0) // w.WriteInt32(0, 0)
} else {
w.WriteInt32(int32(len(pkt.QZoneProxyServiceList)), 0)
for _, i := range pkt.QZoneProxyServiceList {
w.writeHead(10, 0)
w.buf.Write(i.ToBytes())
w.writeHead(11, 0)
}
}
}
{ // write pkt.UrlEncodeServiceList tag=4
w.writeHead(9, 4)
if len(pkt.UrlEncodeServiceList) == 0 {
w.writeHead(12, 0) // w.WriteInt32(0, 0)
} else {
w.WriteInt32(int32(len(pkt.UrlEncodeServiceList)), 0)
for _, i := range pkt.UrlEncodeServiceList {
w.writeHead(10, 0)
w.buf.Write(i.ToBytes())
w.writeHead(11, 0)
}
}
}
{ // write BigDataChannel tag=5
w.writeHead(10, 5)
w.buf.Write(pkt.BigDataChannel.ToBytes())
w.writeHead(11, 0)
}
{ // write pkt.VipEmotionList tag=6
w.writeHead(9, 6)
if len(pkt.VipEmotionList) == 0 {
w.writeHead(12, 0) // w.WriteInt32(0, 0)
} else {
w.WriteInt32(int32(len(pkt.VipEmotionList)), 0)
for _, i := range pkt.VipEmotionList {
w.writeHead(10, 0)
w.buf.Write(i.ToBytes())
w.writeHead(11, 0)
}
}
}
{ // write pkt.C2CPicDownList tag=7
w.writeHead(9, 7)
if len(pkt.C2CPicDownList) == 0 {
w.writeHead(12, 0) // w.WriteInt32(0, 0)
} else {
w.WriteInt32(int32(len(pkt.C2CPicDownList)), 0)
for _, i := range pkt.C2CPicDownList {
w.writeHead(10, 0)
w.buf.Write(i.ToBytes())
w.writeHead(11, 0)
}
}
}
w.WriteBytes(pkt.PttList, 10)
return w.Bytes()
}
func (pkt *FileStorageServerInfo) ToBytes() []byte {
w := NewJceWriter()
w.WriteString(pkt.Server, 1)
w.WriteInt32(pkt.Port, 2)
return w.Bytes()
}
func (pkt *BigDataChannel) ToBytes() []byte {
w := NewJceWriter()
{ // write pkt.IPLists tag=0
w.writeHead(9, 0)
if len(pkt.IPLists) == 0 {
w.writeHead(12, 0) // w.WriteInt32(0, 0)
} else {
w.WriteInt32(int32(len(pkt.IPLists)), 0)
for _, i := range pkt.IPLists {
w.writeHead(10, 0)
w.buf.Write(i.ToBytes())
w.writeHead(11, 0)
}
}
}
w.WriteBytes(pkt.SigSession, 1)
w.WriteBytes(pkt.KeySession, 2)
w.WriteInt64(pkt.SigUin, 3)
w.WriteInt32(pkt.ConnectFlag, 4)
w.WriteBytes(pkt.PbBuf, 5)
return w.Bytes()
}
func (pkt *BigDataIPList) ToBytes() []byte {
w := NewJceWriter()
w.WriteInt64(pkt.ServiceType, 0)
{ // write pkt.IPList tag=1
w.writeHead(9, 1)
if len(pkt.IPList) == 0 {
w.writeHead(12, 0) // w.WriteInt32(0, 0)
} else {
w.WriteInt32(int32(len(pkt.IPList)), 0)
for _, i := range pkt.IPList {
w.writeHead(10, 0)
w.buf.Write(i.ToBytes())
w.writeHead(11, 0)
}
}
}
w.WriteInt64(pkt.FragmentSize, 3)
return w.Bytes()
}
func (pkt *BigDataIPInfo) ToBytes() []byte {
w := NewJceWriter()
w.WriteInt64(pkt.Type, 0)
w.WriteString(pkt.Server, 1)
w.WriteInt64(pkt.Port, 2)
return w.Bytes()
}
func (pkt *SvcReqRegister) ToBytes() []byte {
w := NewJceWriter()
w.WriteInt64(pkt.Uin, 0)
w.WriteInt64(pkt.Bid, 1)
w.WriteByte(pkt.ConnType, 2)
w.WriteString(pkt.Other, 3)
w.WriteInt32(pkt.Status, 4)
w.WriteByte(pkt.OnlinePush, 5)
w.WriteByte(pkt.IsOnline, 6)
w.WriteByte(pkt.IsShowOnline, 7)
w.WriteByte(pkt.KickPC, 8)
w.WriteByte(pkt.KickWeak, 9)
w.WriteInt64(pkt.Timestamp, 10)
w.WriteInt64(pkt.IOSVersion, 11)
w.WriteByte(pkt.NetType, 12)
w.WriteString(pkt.BuildVer, 13)
w.WriteByte(pkt.RegType, 14)
w.WriteBytes(pkt.DevParam, 15)
w.WriteBytes(pkt.Guid, 16)
w.WriteInt32(pkt.LocaleId, 17)
w.WriteByte(pkt.SilentPush, 18)
w.WriteString(pkt.DevName, 19)
w.WriteString(pkt.DevType, 20)
w.WriteString(pkt.OSVer, 21)
w.WriteByte(pkt.OpenPush, 22)
w.WriteInt64(pkt.LargeSeq, 23)
w.WriteInt64(pkt.LastWatchStartTime, 24)
w.WriteInt64(pkt.OldSSOIp, 26)
w.WriteInt64(pkt.NewSSOIp, 27)
w.WriteString(pkt.ChannelNo, 28)
w.WriteInt64(pkt.CPID, 29)
w.WriteString(pkt.VendorName, 30)
w.WriteString(pkt.VendorOSName, 31)
w.WriteString(pkt.IOSIdfa, 32)
w.WriteBytes(pkt.B769, 33)
w.WriteByte(pkt.IsSetStatus, 34)
w.WriteBytes(pkt.ServerBuf, 35)
w.WriteByte(pkt.SetMute, 36)
w.WriteInt64(pkt.ExtOnlineStatus, 38)
w.WriteInt32(pkt.BatteryStatus, 39)
return w.Bytes()
}
func (pkt *SvcRespRegister) ToBytes() []byte {
w := NewJceWriter()
w.WriteInt64(pkt.Uin, 0)
w.WriteInt64(pkt.Bid, 1)
w.WriteByte(pkt.ReplyCode, 2)
w.WriteString(pkt.Result, 3)
w.WriteInt64(pkt.ServerTime, 4)
w.WriteByte(pkt.LogQQ, 5)
w.WriteByte(pkt.NeedKik, 6)
w.WriteByte(pkt.UpdateFlag, 7)
w.WriteInt64(pkt.Timestamp, 8)
w.WriteByte(pkt.CrashFlag, 9)
w.WriteString(pkt.ClientIp, 10)
w.WriteInt32(pkt.ClientPort, 11)
w.WriteInt32(pkt.HelloInterval, 12)
w.WriteInt32(pkt.LargeSeq, 13)
w.WriteByte(pkt.LargeSeqUpdate, 14)
w.WriteBytes(pkt.D769RspBody, 15)
w.WriteInt32(pkt.Status, 16)
w.WriteInt64(pkt.ExtOnlineStatus, 17)
w.WriteInt64(pkt.ClientBatteryGetInterval, 18)
w.WriteInt64(pkt.ClientAutoStatusInterval, 19)
return w.Bytes()
}
func (pkt *SvcReqRegisterNew) ToBytes() []byte {
w := NewJceWriter()
w.WriteInt64(pkt.RequestOptional, 0)
{ // write C2CMsg tag=1
w.writeHead(10, 1)
w.buf.Write(pkt.C2CMsg.ToBytes())
w.writeHead(11, 0)
}
{ // write GroupMsg tag=2
w.writeHead(10, 2)
w.buf.Write(pkt.GroupMsg.ToBytes())
w.writeHead(11, 0)
}
w.WriteByte(pkt.DisGroupMsgFilter, 14)
w.WriteByte(pkt.GroupMask, 15)
w.WriteInt64(pkt.EndSeq, 16)
w.WriteBytes(pkt.O769Body, 20)
return w.Bytes()
}
func (pkt *SvcReqGetMsgV2) ToBytes() []byte {
w := NewJceWriter()
w.WriteInt64(pkt.Uin, 0)
w.WriteInt32(pkt.DateTime, 1)
w.WriteByte(pkt.RecivePic, 4)
w.WriteInt16(pkt.Ability, 6)
w.WriteByte(pkt.Channel, 9)
w.WriteByte(pkt.Inst, 16)
w.WriteByte(pkt.ChannelEx, 17)
w.WriteBytes(pkt.SyncCookie, 18)
w.WriteInt64(int64(pkt.SyncFlag), 19)
w.WriteByte(pkt.RambleFlag, 20)
w.WriteInt64(pkt.GeneralAbi, 26)
w.WriteBytes(pkt.PubAccountCookie, 27)
return w.Bytes()
}
func (pkt *SvcReqPullGroupMsgSeq) ToBytes() []byte {
w := NewJceWriter()
{ // write pkt.GroupInfo tag=0
w.writeHead(9, 0)
if len(pkt.GroupInfo) == 0 {
w.writeHead(12, 0) // w.WriteInt32(0, 0)
} else {
w.WriteInt32(int32(len(pkt.GroupInfo)), 0)
for _, i := range pkt.GroupInfo {
w.writeHead(10, 0)
w.buf.Write(i.ToBytes())
w.writeHead(11, 0)
}
}
}
w.WriteByte(pkt.VerifyType, 1)
w.WriteInt32(pkt.Filter, 2)
return w.Bytes()
}
func (pkt *PullGroupSeqParam) ToBytes() []byte {
w := NewJceWriter()
w.WriteInt64(pkt.GroupCode, 0)
w.WriteInt64(pkt.LastSeqId, 1)
return w.Bytes()
}
func (pkt *SvcRespParam) ToBytes() []byte {
w := NewJceWriter()
w.WriteInt32(pkt.PCStat, 0)
w.WriteInt32(pkt.IsSupportC2CRoamMsg, 1)
w.WriteInt32(pkt.IsSupportDataLine, 2)
w.WriteInt32(pkt.IsSupportPrintable, 3)
w.WriteInt32(pkt.IsSupportViewPCFile, 4)
w.WriteInt32(pkt.PcVersion, 5)
w.WriteInt64(pkt.RoamFlag, 6)
{ // write pkt.OnlineInfos tag=7
w.writeHead(9, 7)
if len(pkt.OnlineInfos) == 0 {
w.writeHead(12, 0) // w.WriteInt32(0, 0)
} else {
w.WriteInt32(int32(len(pkt.OnlineInfos)), 0)
for _, i := range pkt.OnlineInfos {
w.writeHead(10, 0)
w.buf.Write(i.ToBytes())
w.writeHead(11, 0)
}
}
}
w.WriteInt32(pkt.PCClientType, 8)
return w.Bytes()
}
func (pkt *RequestPushNotify) ToBytes() []byte {
w := NewJceWriter()
w.WriteInt64(pkt.Uin, 0)
w.WriteByte(pkt.Type, 1)
w.WriteString(pkt.Service, 2)
w.WriteString(pkt.Cmd, 3)
w.WriteBytes(pkt.NotifyCookie, 4)
w.WriteInt32(pkt.MsgType, 5)
w.WriteInt32(pkt.UserActive, 6)
w.WriteInt32(pkt.GeneralFlag, 7)
w.WriteInt64(pkt.BindedUin, 8)
return w.Bytes()
}
func (pkt *OnlineInfo) ToBytes() []byte {
w := NewJceWriter()
w.WriteInt32(pkt.InstanceId, 0)
w.WriteInt32(pkt.ClientType, 1)
w.WriteInt32(pkt.OnlineStatus, 2)
w.WriteInt32(pkt.PlatformId, 3)
w.WriteString(pkt.SubPlatform, 4)
w.WriteInt64(pkt.UClientType, 5)
return w.Bytes()
}
func (pkt *SvcReqMSFLoginNotify) ToBytes() []byte {
w := NewJceWriter()
w.WriteInt64(pkt.AppId, 0)
w.WriteByte(pkt.Status, 1)
w.WriteByte(pkt.Tablet, 2)
w.WriteInt64(pkt.Platform, 3)
w.WriteString(pkt.Title, 4)
w.WriteString(pkt.Info, 5)
w.WriteInt64(pkt.ProductType, 6)
w.WriteInt64(pkt.ClientType, 7)
{ // write pkt.InstanceList tag=8
w.writeHead(9, 8)
if len(pkt.InstanceList) == 0 {
w.writeHead(12, 0) // w.WriteInt32(0, 0)
} else {
w.WriteInt32(int32(len(pkt.InstanceList)), 0)
for _, i := range pkt.InstanceList {
w.writeHead(10, 0)
w.buf.Write(i.ToBytes())
w.writeHead(11, 0)
}
}
}
return w.Bytes()
}
func (pkt *InstanceInfo) ToBytes() []byte {
w := NewJceWriter()
w.WriteInt32(pkt.AppId, 0)
w.WriteByte(pkt.Tablet, 1)
w.WriteInt64(pkt.Platform, 2)
w.WriteInt64(pkt.ProductType, 3)
w.WriteInt64(pkt.ClientType, 4)
return w.Bytes()
}
func (pkt *PushMessageInfo) ToBytes() []byte {
w := NewJceWriter()
w.WriteInt64(pkt.FromUin, 0)
w.WriteInt64(pkt.MsgTime, 1)
w.WriteInt16(pkt.MsgType, 2)
w.WriteInt16(pkt.MsgSeq, 3)
w.WriteString(pkt.Msg, 4)
w.WriteInt32(pkt.RealMsgTime, 5)
w.WriteBytes(pkt.VMsg, 6)
w.WriteInt64(pkt.AppShareID, 7)
w.WriteBytes(pkt.MsgCookies, 8)
w.WriteBytes(pkt.AppShareCookie, 9)
w.WriteInt64(pkt.MsgUid, 10)
w.WriteInt64(pkt.LastChangeTime, 11)
w.WriteInt64(pkt.FromInstId, 14)
w.WriteBytes(pkt.RemarkOfSender, 15)
w.WriteString(pkt.FromMobile, 16)
w.WriteString(pkt.FromName, 17)
return w.Bytes()
}
func (pkt *SvcRespPushMsg) ToBytes() []byte {
w := NewJceWriter()
w.WriteInt64(pkt.Uin, 0)
{ // write pkt.DelInfos tag=1
w.writeHead(9, 1)
if len(pkt.DelInfos) == 0 {
w.writeHead(12, 0) // w.WriteInt32(0, 0)
} else {
w.WriteInt32(int32(len(pkt.DelInfos)), 0)
for _, i := range pkt.DelInfos {
w.writeHead(10, 0)
w.buf.Write(i.ToBytes())
w.writeHead(11, 0)
}
}
}
w.WriteInt32(pkt.Svrip, 2)
w.WriteBytes(pkt.PushToken, 3)
w.WriteInt32(pkt.ServiceType, 4)
return w.Bytes()
}
func (pkt *SvcReqGetDevLoginInfo) ToBytes() []byte {
w := NewJceWriter()
w.WriteBytes(pkt.Guid, 0)
w.WriteString(pkt.AppName, 1)
w.WriteInt64(pkt.LoginType, 2)
w.WriteInt64(pkt.Timestamp, 3)
w.WriteInt64(pkt.NextItemIndex, 4)
w.WriteInt64(pkt.RequireMax, 5)
w.WriteInt64(pkt.GetDevListType, 6)
return w.Bytes()
}
func (pkt *DelMsgInfo) ToBytes() []byte {
w := NewJceWriter()
w.WriteInt64(pkt.FromUin, 0)
w.WriteInt64(pkt.MsgTime, 1)
w.WriteInt16(pkt.MsgSeq, 2)
w.WriteBytes(pkt.MsgCookies, 3)
w.WriteInt16(pkt.Cmd, 4)
w.WriteInt64(pkt.MsgType, 5)
w.WriteInt64(pkt.AppId, 6)
w.WriteInt64(pkt.SendTime, 7)
w.WriteInt32(pkt.SsoSeq, 8)
w.WriteInt32(pkt.SsoIp, 9)
w.WriteInt32(pkt.ClientIp, 10)
return w.Bytes()
}
func (pkt *FriendListRequest) ToBytes() []byte {
w := NewJceWriter()
w.WriteInt32(pkt.Reqtype, 0)
w.WriteByte(pkt.IfReflush, 1)
w.WriteInt64(pkt.Uin, 2)
w.WriteInt16(pkt.StartIndex, 3)
w.WriteInt16(pkt.FriendCount, 4)
w.WriteByte(pkt.GroupId, 5)
w.WriteByte(pkt.IfGetGroupInfo, 6)
w.WriteByte(pkt.GroupStartIndex, 7)
w.WriteByte(pkt.GroupCount, 8)
w.WriteByte(pkt.IfGetMSFGroup, 9)
w.WriteByte(pkt.IfShowTermType, 10)
w.WriteInt64(pkt.Version, 11)
w.WriteInt64Slice(pkt.UinList, 12)
w.WriteInt32(pkt.AppType, 13)
w.WriteByte(pkt.IfGetDOVId, 14)
w.WriteByte(pkt.IfGetBothFlag, 15)
w.WriteBytes(pkt.D50, 16)
w.WriteBytes(pkt.D6B, 17)
w.WriteInt64Slice(pkt.SnsTypeList, 18)
return w.Bytes()
}
func (pkt *FriendInfo) ToBytes() []byte {
w := NewJceWriter()
w.WriteInt64(pkt.FriendUin, 0)
w.WriteByte(pkt.GroupId, 1)
w.WriteInt16(pkt.FaceId, 2)
w.WriteString(pkt.Remark, 3)
w.WriteByte(pkt.QQType, 4)
w.WriteByte(pkt.Status, 5)
w.WriteByte(pkt.MemberLevel, 6)
w.WriteByte(pkt.IsMqqOnLine, 7)
w.WriteByte(pkt.QQOnlineState, 8)
w.WriteByte(pkt.IsIphoneOnline, 9)
w.WriteByte(pkt.DetailStatusFlag, 10)
w.WriteByte(pkt.QQOnlineStateV2, 11)
w.WriteString(pkt.ShowName, 12)
w.WriteByte(pkt.IsRemark, 13)
w.WriteString(pkt.Nick, 14)
w.WriteByte(pkt.SpecialFlag, 15)
w.WriteBytes(pkt.IMGroupID, 16)
w.WriteBytes(pkt.MSFGroupID, 17)
w.WriteInt32(pkt.TermType, 18)
w.WriteByte(pkt.Network, 20)
w.WriteBytes(pkt.Ring, 21)
w.WriteInt64(pkt.AbiFlag, 22)
w.WriteInt64(pkt.FaceAddonId, 23)
w.WriteInt32(pkt.NetworkType, 24)
w.WriteInt64(pkt.VipFont, 25)
w.WriteInt32(pkt.IconType, 26)
w.WriteString(pkt.TermDesc, 27)
w.WriteInt64(pkt.ColorRing, 28)
w.WriteByte(pkt.ApolloFlag, 29)
w.WriteInt64(pkt.ApolloTimestamp, 30)
w.WriteByte(pkt.Sex, 31)
w.WriteInt64(pkt.FounderFont, 32)
w.WriteString(pkt.EimId, 33)
w.WriteString(pkt.EimMobile, 34)
w.WriteByte(pkt.OlympicTorch, 35)
w.WriteInt64(pkt.ApolloSignTime, 36)
w.WriteInt64(pkt.LaviUin, 37)
w.WriteInt64(pkt.TagUpdateTime, 38)
w.WriteInt64(pkt.GameLastLoginTime, 39)
w.WriteInt64(pkt.GameAppId, 40)
w.WriteBytes(pkt.CardID, 41)
w.WriteInt64(pkt.BitSet, 42)
w.WriteByte(pkt.KingOfGloryFlag, 43)
w.WriteInt64(pkt.KingOfGloryRank, 44)
w.WriteString(pkt.MasterUin, 45)
w.WriteInt64(pkt.LastMedalUpdateTime, 46)
w.WriteInt64(pkt.FaceStoreId, 47)
w.WriteInt64(pkt.FontEffect, 48)
w.WriteString(pkt.DOVId, 49)
w.WriteInt64(pkt.BothFlag, 50)
w.WriteByte(pkt.CentiShow3DFlag, 51)
w.WriteBytes(pkt.IntimateInfo, 52)
w.WriteByte(pkt.ShowNameplate, 53)
w.WriteByte(pkt.NewLoverDiamondFlag, 54)
w.WriteBytes(pkt.ExtSnsFrdData, 55)
w.WriteBytes(pkt.MutualMarkData, 56)
return w.Bytes()
}
func (pkt *TroopListRequest) ToBytes() []byte {
w := NewJceWriter()
w.WriteInt64(pkt.Uin, 0)
w.WriteByte(pkt.GetMSFMsgFlag, 1)
w.WriteBytes(pkt.Cookies, 2)
w.WriteInt64Slice(pkt.GroupInfo, 3)
w.WriteByte(pkt.GroupFlagExt, 4)
w.WriteInt32(pkt.Version, 5)
w.WriteInt64(pkt.CompanyId, 6)
w.WriteInt64(pkt.VersionNum, 7)
w.WriteByte(pkt.GetLongGroupName, 8)
return w.Bytes()
}
func (pkt *TroopNumber) ToBytes() []byte {
w := NewJceWriter()
w.WriteInt64(pkt.GroupUin, 0)
w.WriteInt64(pkt.GroupCode, 1)
w.WriteByte(pkt.Flag, 2)
w.WriteInt64(pkt.GroupInfoSeq, 3)
w.WriteString(pkt.GroupName, 4)
w.WriteString(pkt.GroupMemo, 5)
w.WriteInt64(pkt.GroupFlagExt, 6)
w.WriteInt64(pkt.GroupRankSeq, 7)
w.WriteInt64(pkt.CertificationType, 8)
w.WriteInt64(pkt.ShutUpTimestamp, 9)
w.WriteInt64(pkt.MyShutUpTimestamp, 10)
w.WriteInt64(pkt.CmdUinUinFlag, 11)
w.WriteInt64(pkt.AdditionalFlag, 12)
w.WriteInt64(pkt.GroupTypeFlag, 13)
w.WriteInt64(pkt.GroupSecType, 14)
w.WriteInt64(pkt.GroupSecTypeInfo, 15)
w.WriteInt64(pkt.GroupClassExt, 16)
w.WriteInt64(pkt.AppPrivilegeFlag, 17)
w.WriteInt64(pkt.SubscriptionUin, 18)
w.WriteInt64(pkt.MemberNum, 19)
w.WriteInt64(pkt.MemberNumSeq, 20)
w.WriteInt64(pkt.MemberCardSeq, 21)
w.WriteInt64(pkt.GroupFlagExt3, 22)
w.WriteInt64(pkt.GroupOwnerUin, 23)
w.WriteByte(pkt.IsConfGroup, 24)
w.WriteByte(pkt.IsModifyConfGroupFace, 25)
w.WriteByte(pkt.IsModifyConfGroupName, 26)
w.WriteInt64(pkt.CmdUinJoinTime, 27)
w.WriteInt64(pkt.CompanyId, 28)
w.WriteInt64(pkt.MaxGroupMemberNum, 29)
w.WriteInt64(pkt.CmdUinGroupMask, 30)
w.WriteInt64(pkt.GuildAppId, 31)
w.WriteInt64(pkt.GuildSubType, 32)
w.WriteInt64(pkt.CmdUinRingtoneID, 33)
w.WriteInt64(pkt.CmdUinFlagEx2, 34)
return w.Bytes()
}
func (pkt *TroopMemberListRequest) ToBytes() []byte {
w := NewJceWriter()
w.WriteInt64(pkt.Uin, 0)
w.WriteInt64(pkt.GroupCode, 1)
w.WriteInt64(pkt.NextUin, 2)
w.WriteInt64(pkt.GroupUin, 3)
w.WriteInt64(pkt.Version, 4)
w.WriteInt64(pkt.ReqType, 5)
w.WriteInt64(pkt.GetListAppointTime, 6)
w.WriteByte(pkt.RichCardNameVer, 7)
return w.Bytes()
}
func (pkt *TroopMemberInfo) ToBytes() []byte {
w := NewJceWriter()
w.WriteInt64(pkt.MemberUin, 0)
w.WriteInt16(pkt.FaceId, 1)
w.WriteByte(pkt.Age, 2)
w.WriteByte(pkt.Gender, 3)
w.WriteString(pkt.Nick, 4)
w.WriteByte(pkt.Status, 5)
w.WriteString(pkt.ShowName, 6)
w.WriteString(pkt.Name, 8)
w.WriteString(pkt.Memo, 12)
w.WriteString(pkt.AutoRemark, 13)
w.WriteInt64(pkt.MemberLevel, 14)
w.WriteInt64(pkt.JoinTime, 15)
w.WriteInt64(pkt.LastSpeakTime, 16)
w.WriteInt64(pkt.CreditLevel, 17)
w.WriteInt64(pkt.Flag, 18)
w.WriteInt64(pkt.FlagExt, 19)
w.WriteInt64(pkt.Point, 20)
w.WriteByte(pkt.Concerned, 21)
w.WriteByte(pkt.Shielded, 22)
w.WriteString(pkt.SpecialTitle, 23)
w.WriteInt64(pkt.SpecialTitleExpireTime, 24)
w.WriteString(pkt.Job, 25)
w.WriteByte(pkt.ApolloFlag, 26)
w.WriteInt64(pkt.ApolloTimestamp, 27)
w.WriteInt64(pkt.GlobalGroupLevel, 28)
w.WriteInt64(pkt.TitleId, 29)
w.WriteInt64(pkt.ShutUpTimestap, 30)
w.WriteInt64(pkt.GlobalGroupPoint, 31)
w.WriteByte(pkt.RichCardNameVer, 33)
w.WriteInt64(pkt.VipType, 34)
w.WriteInt64(pkt.VipLevel, 35)
w.WriteInt64(pkt.BigClubLevel, 36)
w.WriteInt64(pkt.BigClubFlag, 37)
w.WriteInt64(pkt.Nameplate, 38)
w.WriteBytes(pkt.GroupHonor, 39)
return w.Bytes()
}
func (pkt *ModifyGroupCardRequest) ToBytes() []byte {
w := NewJceWriter()
w.WriteInt64(pkt.Zero, 0)
w.WriteInt64(pkt.GroupCode, 1)
w.WriteInt64(pkt.NewSeq, 2)
{ // write pkt.UinInfo tag=3
w.writeHead(9, 3)
if len(pkt.UinInfo) == 0 {
w.writeHead(12, 0) // w.WriteInt32(0, 0)
} else {
w.WriteInt32(int32(len(pkt.UinInfo)), 0)
for _, i := range pkt.UinInfo {
w.writeHead(10, 0)
w.buf.Write(i.ToBytes())
w.writeHead(11, 0)
}
}
}
return w.Bytes()
}
func (pkt *UinInfo) ToBytes() []byte {
w := NewJceWriter()
w.WriteInt64(pkt.Uin, 0)
w.WriteInt64(pkt.Flag, 1)
w.WriteString(pkt.Name, 2)
w.WriteByte(pkt.Gender, 3)
w.WriteString(pkt.Phone, 4)
w.WriteString(pkt.Email, 5)
w.WriteString(pkt.Remark, 6)
return w.Bytes()
}
func (pkt *SummaryCardReq) ToBytes() []byte {
w := NewJceWriter()
w.WriteInt64(pkt.Uin, 0)
w.WriteInt32(pkt.ComeFrom, 1)
w.WriteInt64(pkt.QzoneFeedTimestamp, 2)
w.WriteByte(pkt.IsFriend, 3)
w.WriteInt64(pkt.GroupCode, 4)
w.WriteInt64(pkt.GroupUin, 5)
w.WriteInt64(pkt.GetControl, 8)
w.WriteInt32(pkt.AddFriendSource, 9)
w.WriteBytes(pkt.SecureSig, 10)
w.WriteBytesSlice(pkt.ReqServices, 14)
w.WriteInt64(pkt.TinyId, 15)
w.WriteInt64(pkt.LikeSource, 16)
w.WriteByte(pkt.ReqMedalWallInfo, 18)
w.WriteInt64Slice(pkt.Req0x5ebFieldId, 19)
w.WriteByte(pkt.ReqNearbyGodInfo, 20)
w.WriteByte(pkt.ReqExtendCard, 22)
return w.Bytes()
}
func (pkt *SummaryCardReqSearch) ToBytes() []byte {
w := NewJceWriter()
w.WriteString(pkt.Keyword, 0)
w.WriteString(pkt.CountryCode, 1)
w.WriteInt32(pkt.Version, 2)
w.WriteBytesSlice(pkt.ReqServices, 3)
return w.Bytes()
}
func (pkt *DelFriendReq) ToBytes() []byte {
w := NewJceWriter()
w.WriteInt64(pkt.Uin, 0)
w.WriteInt64(pkt.DelUin, 1)
w.WriteByte(pkt.DelType, 2)
w.WriteInt32(pkt.Version, 3)
return w.Bytes()
}
func (pkt *VipInfo) ToBytes() []byte {
w := NewJceWriter()
w.WriteByte(pkt.Open, 0)
w.WriteInt32(pkt.Type, 1)
w.WriteInt32(pkt.Level, 2)
return w.Bytes()
}

View File

@ -3,7 +3,9 @@ package jce
import ( import (
"bytes" "bytes"
goBinary "encoding/binary" goBinary "encoding/binary"
"math" "reflect"
"strconv"
"sync"
) )
type JceWriter struct { type JceWriter struct {
@ -14,16 +16,18 @@ func NewJceWriter() *JceWriter {
return &JceWriter{buf: new(bytes.Buffer)} return &JceWriter{buf: new(bytes.Buffer)}
} }
func (w *JceWriter) writeHead(t, tag byte) { func (w *JceWriter) writeHead(t byte, tag int) {
if tag < 0xF { if tag < 15 {
w.buf.WriteByte(tag<<4 | t) b := byte(tag<<4) | t
} else { w.buf.WriteByte(b)
w.buf.WriteByte(0xF0 | t) } else if tag < 256 {
w.buf.WriteByte(tag) b := 0xF0 | t
w.buf.WriteByte(b)
w.buf.WriteByte(byte(tag))
} }
} }
func (w *JceWriter) WriteByte(b, tag byte) *JceWriter { func (w *JceWriter) WriteByte(b byte, tag int) *JceWriter {
if b == 0 { if b == 0 {
w.writeHead(12, tag) w.writeHead(12, tag)
} else { } else {
@ -33,116 +37,78 @@ func (w *JceWriter) WriteByte(b, tag byte) *JceWriter {
return w return w
} }
func (w *JceWriter) WriteBool(b bool, tag byte) { func (w *JceWriter) WriteBool(b bool, tag int) {
var by byte var by byte = 0
if b { if b {
by = 1 by = 1
} }
w.WriteByte(by, tag) w.WriteByte(by, tag)
} }
func (w *JceWriter) WriteInt16(n int16, tag byte) { func (w *JceWriter) WriteInt16(n int16, tag int) {
switch { if n >= -128 && n <= 127 {
case n >= -128 && n <= 127:
w.WriteByte(byte(n), tag) w.WriteByte(byte(n), tag)
default: return
w.putInt16(n, tag)
} }
}
//go:nosplit
func (w *JceWriter) putInt16(n int16, tag byte) {
w.writeHead(1, tag) w.writeHead(1, tag)
var buf [2]byte _ = goBinary.Write(w.buf, goBinary.BigEndian, n)
goBinary.BigEndian.PutUint16(buf[:], uint16(n))
w.buf.Write(buf[:])
} }
func (w *JceWriter) WriteInt32(n int32, tag byte) *JceWriter { func (w *JceWriter) WriteInt32(n int32, tag int) *JceWriter {
switch { if n >= -32768 && n <= 32767 { // ? if ((n >= 32768) && (n <= 32767))
case n >= -128 && n <= 127: w.WriteInt16(int16(n), tag)
w.WriteByte(byte(n), tag) return w
case n >= -32768 && n <= 32767:
w.putInt16(int16(n), tag)
default:
w.putInt32(n, tag)
} }
return w
}
//go:nosplit
func (w *JceWriter) putInt32(n int32, tag byte) {
w.writeHead(2, tag) w.writeHead(2, tag)
var buf [4]byte _ = goBinary.Write(w.buf, goBinary.BigEndian, n)
goBinary.BigEndian.PutUint32(buf[:], uint32(n))
w.buf.Write(buf[:])
}
func (w *JceWriter) WriteInt64(n int64, tag byte) *JceWriter {
switch {
case n >= -128 && n <= 127:
w.WriteByte(byte(n), tag)
case n >= -32768 && n <= 32767:
w.putInt16(int16(n), tag)
case n >= -2147483648 && n <= 2147483647:
w.putInt32(int32(n), tag)
default:
w.putInt64(n, tag)
}
return w return w
} }
//go:nosplit func (w *JceWriter) WriteInt64(n int64, tag int) *JceWriter {
func (w *JceWriter) putInt64(n int64, tag byte) { if n >= -2147483648 && n <= 2147483647 {
return w.WriteInt32(int32(n), tag)
}
w.writeHead(3, tag) w.writeHead(3, tag)
var buf [8]byte _ = goBinary.Write(w.buf, goBinary.BigEndian, n)
goBinary.BigEndian.PutUint64(buf[:], uint64(n)) return w
w.buf.Write(buf[:])
} }
//go:nosplit func (w *JceWriter) WriteFloat32(n float32, tag int) {
func (w *JceWriter) WriteFloat32(n float32, tag byte) {
w.writeHead(4, tag) w.writeHead(4, tag)
var buf [4]byte _ = goBinary.Write(w.buf, goBinary.BigEndian, n)
goBinary.BigEndian.PutUint32(buf[:], math.Float32bits(n))
w.buf.Write(buf[:])
} }
//go:nosplit func (w *JceWriter) WriteFloat64(n float64, tag int) {
func (w *JceWriter) WriteFloat64(n float64, tag byte) {
w.writeHead(5, tag) w.writeHead(5, tag)
var buf [8]byte _ = goBinary.Write(w.buf, goBinary.BigEndian, n)
goBinary.BigEndian.PutUint64(buf[:], math.Float64bits(n))
w.buf.Write(buf[:])
} }
func (w *JceWriter) WriteString(s string, tag byte) *JceWriter { func (w *JceWriter) WriteString(s string, tag int) *JceWriter {
if len(s) > 255 { by := []byte(s)
if len(by) > 255 {
w.writeHead(7, tag) w.writeHead(7, tag)
var buf [4]byte _ = goBinary.Write(w.buf, goBinary.BigEndian, int32(len(by)))
goBinary.BigEndian.PutUint32(buf[:], uint32(len(s))) w.buf.Write(by)
w.buf.Write(buf[:])
w.buf.WriteString(s)
return w return w
} }
w.writeHead(6, tag) w.writeHead(6, tag)
w.buf.WriteByte(byte(len(s))) w.buf.WriteByte(byte(len(by)))
w.buf.WriteString(s) w.buf.Write(by)
return w return w
} }
func (w *JceWriter) WriteBytes(l []byte, tag byte) *JceWriter { func (w *JceWriter) WriteBytes(l []byte, tag int) *JceWriter {
w.writeHead(13, tag) w.writeHead(13, tag)
w.buf.WriteByte(0) // w.writeHead(0, 0) w.writeHead(0, 0)
w.WriteInt32(int32(len(l)), 0) w.WriteInt32(int32(len(l)), 0)
w.buf.Write(l) w.buf.Write(l)
return w return w
} }
func (w *JceWriter) WriteInt64Slice(l []int64, tag byte) { func (w *JceWriter) WriteInt64Slice(l []int64, tag int) {
w.writeHead(9, tag) w.writeHead(9, tag)
if len(l) == 0 { if len(l) == 0 {
w.writeHead(12, 0) // w.WriteInt32(0, 0) w.WriteInt32(0, 0)
return return
} }
w.WriteInt32(int32(len(l)), 0) w.WriteInt32(int32(len(l)), 0)
@ -151,58 +117,141 @@ func (w *JceWriter) WriteInt64Slice(l []int64, tag byte) {
} }
} }
func (w *JceWriter) WriteBytesSlice(l [][]byte, tag byte) { func (w *JceWriter) WriteSlice(i interface{}, tag int) {
va := reflect.ValueOf(i)
if va.Kind() != reflect.Slice {
return
}
w.writeHead(9, tag)
if va.Len() == 0 {
w.WriteInt32(0, 0)
return
}
w.WriteInt32(int32(va.Len()), 0)
for i := 0; i < va.Len(); i++ {
v := va.Index(i)
w.WriteObject(v.Interface(), 0)
}
}
func (w *JceWriter) WriteJceStructSlice(l []IJceStruct, tag int) {
w.writeHead(9, tag) w.writeHead(9, tag)
if len(l) == 0 { if len(l) == 0 {
w.writeHead(12, 0) // w.WriteInt32(0, 0) w.WriteInt32(0, 0)
return return
} }
w.WriteInt32(int32(len(l)), 0) w.WriteInt32(int32(len(l)), 0)
for _, v := range l { for _, v := range l {
w.WriteBytes(v, 0) w.WriteJceStruct(v, 0)
} }
} }
func (w *JceWriter) writeMapStrStr(m map[string]string, tag byte) { func (w *JceWriter) WriteMap(m interface{}, tag int) {
if m == nil { if m == nil {
w.writeHead(8, tag) w.writeHead(8, tag)
w.writeHead(12, 0) // w.WriteInt32(0, 0) w.WriteInt32(0, 0)
return
}
va := reflect.ValueOf(m)
if va.Kind() != reflect.Map {
return return
} }
w.writeHead(8, tag) w.writeHead(8, tag)
w.WriteInt32(int32(len(m)), 0) w.WriteInt32(int32(va.Len()), 0)
for k, v := range m { iter := va.MapRange()
w.WriteString(k, 0) for iter.Next() {
w.WriteString(v, 1) w.WriteObject(iter.Key().Interface(), 0)
w.WriteObject(iter.Value().Interface(), 1)
} }
} }
func (w *JceWriter) writeMapStrBytes(m map[string][]byte, tag byte) { func (w *JceWriter) WriteObject(i interface{}, tag int) {
if m == nil { t := reflect.TypeOf(i)
w.writeHead(8, tag) if t.Kind() == reflect.Map {
w.writeHead(12, 0) // w.WriteInt32(0, 0) w.WriteMap(i, tag)
return return
} }
w.writeHead(8, tag) if t.Kind() == reflect.Slice {
w.WriteInt32(int32(len(m)), 0) if b, ok := i.([]byte); ok {
for k, v := range m { w.WriteBytes(b, tag)
w.WriteString(k, 0) return
w.WriteBytes(v, 1) }
w.WriteSlice(i, tag)
return
}
switch o := i.(type) {
case byte:
w.WriteByte(o, tag)
case bool:
w.WriteBool(o, tag)
case int16:
w.WriteInt16(o, tag)
case int32:
w.WriteInt32(o, tag)
case int64:
w.WriteInt64(o, tag)
case float32:
w.WriteFloat32(o, tag)
case float64:
w.WriteFloat64(o, tag)
case string:
w.WriteString(o, tag)
case IJceStruct:
w.WriteJceStruct(o, tag)
} }
} }
func (w *JceWriter) writeMapStrMapStrBytes(m map[string]map[string][]byte, tag byte) { type decoder struct {
if m == nil { index int
w.writeHead(8, tag) id int
w.writeHead(12, 0) // w.WriteInt32(0, 0) }
var decoderCache = sync.Map{}
// WriteJceStructRaw 写入 Jce 结构体
func (w *JceWriter) WriteJceStructRaw(s interface{}) {
t := reflect.TypeOf(s)
reflect.ValueOf(s).Interface()
if t.Kind() != reflect.Ptr {
return return
} }
w.writeHead(8, tag) t = t.Elem()
w.WriteInt32(int32(len(m)), 0) v := reflect.ValueOf(s).Elem()
for k, v := range m { var jceDec []decoder
w.WriteString(k, 0) dec, ok := decoderCache.Load(t)
w.writeMapStrBytes(v, 1) if ok { // 从缓存中加载
jceDec = dec.([]decoder)
} else { // 初次反射
jceDec = make([]decoder, 0, t.NumField())
for i := 0; i < t.NumField(); i++ {
field := t.Field(i)
strId := field.Tag.Get("jceId")
if strId == "" {
continue
}
id, err := strconv.Atoi(strId)
if err != nil {
continue
}
jceDec = append(jceDec, decoder{
index: i,
id: id,
})
}
decoderCache.Store(t, jceDec) // 存入缓存
} }
for _, dec := range jceDec {
obj := v.Field(dec.index).Interface()
if obj != nil {
w.WriteObject(obj, dec.id)
}
}
}
func (w *JceWriter) WriteJceStruct(s IJceStruct, tag int) {
w.writeHead(10, tag)
w.WriteJceStructRaw(s)
w.writeHead(11, 0)
} }
func (w *JceWriter) Bytes() []byte { func (w *JceWriter) Bytes() []byte {

View File

@ -9,10 +9,10 @@ import (
var globalBytes []byte var globalBytes []byte
func BenchmarkJceWriter_WriteMap(b *testing.B) { func BenchmarkJceWriter_WriteMap(b *testing.B) {
x := globalBytes var x = globalBytes
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
w := NewJceWriter() w := NewJceWriter()
w.writeMapStrMapStrBytes(req.Map, 0) w.WriteMap(req.Map, 0)
x = w.Bytes() x = w.Bytes()
} }
globalBytes = x globalBytes = x
@ -39,16 +39,20 @@ var reqPacket1 = &RequestPacket{
} }
func BenchmarkJceWriter_WriteJceStructRaw(b *testing.B) { func BenchmarkJceWriter_WriteJceStructRaw(b *testing.B) {
x := globalBytes var x = globalBytes
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
_ = reqPacket1.ToBytes() w := NewJceWriter()
w.WriteJceStructRaw(reqPacket1)
x = w.Bytes()
} }
globalBytes = x globalBytes = x
b.SetBytes(int64(len(globalBytes))) b.SetBytes(int64(len(globalBytes)))
} }
func TestJceWriter_WriteJceStructRaw(t *testing.T) { func TestJceWriter_WriteJceStructRaw(t *testing.T) {
r := NewJceReader(reqPacket1.ToBytes()) w := NewJceWriter()
w.WriteJceStructRaw(reqPacket1)
r := NewJceReader(w.Bytes())
var reqPacket2 RequestPacket var reqPacket2 RequestPacket
reqPacket2.ReadFrom(r) reqPacket2.ReadFrom(r)
assert.Equal(t, reqPacket1, &reqPacket2) assert.Equal(t, reqPacket1, &reqPacket2)

View File

@ -2,37 +2,39 @@ package binary
import ( import (
"bytes" "bytes"
"compress/gzip"
"compress/zlib"
"sync" "sync"
"github.com/klauspost/compress/gzip"
"github.com/klauspost/compress/zlib"
) )
var bufferPool = sync.Pool{ var bufferPool = sync.Pool{
New: func() any { New: func() interface{} {
return new(Writer) return new(Writer)
}, },
} }
// SelectWriter 从池中取出一个 Writer // NewWriter 从池中取出一个 Writer
func SelectWriter() *Writer { func NewWriter() *Writer {
// 因为 bufferPool 定义有 New 函数 w := bufferPool.Get().(*Writer)
// 所以 bufferPool.Get() 永不为 nil if w == nil {
// 不用判空 return new(Writer)
return bufferPool.Get().(*Writer) }
return w
} }
// PutWriter 将 Writer 放回池中 // PutWriter 将 Writer 放回池中
func PutWriter(w *Writer) { func PutWriter(w *Writer) {
// See https://golang.org/issue/23199 // See https://golang.org/issue/23199
const maxSize = 32 * 1024 const maxSize = 1 << 16
if (*bytes.Buffer)(w).Cap() < maxSize { // 对于大Buffer直接丢弃 if w.Cap() < maxSize { // 对于大Buffer直接丢弃
w.Reset() w.Reset()
bufferPool.Put(w) bufferPool.Put(w)
} }
} }
var gzipPool = sync.Pool{ var gzipPool = sync.Pool{
New: func() any { New: func() interface{} {
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
w := gzip.NewWriter(buf) w := gzip.NewWriter(buf)
return &GzipWriter{ return &GzipWriter{
@ -64,7 +66,7 @@ type zlibWriter struct {
} }
var zlibPool = sync.Pool{ var zlibPool = sync.Pool{
New: func() any { New: func() interface{} {
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
w := zlib.NewWriter(buf) w := zlib.NewWriter(buf)
return &zlibWriter{ return &zlibWriter{
@ -89,3 +91,38 @@ func releaseZlibWriter(w *zlibWriter) {
zlibPool.Put(w) zlibPool.Put(w)
} }
} }
const size256k = 256 * 1024
var b256kPool = sync.Pool{
New: func() interface{} {
return make128kSlicePointer()
},
}
// Get256KBytes 获取一个128k大小 []byte
func Get256KBytes() *[]byte {
buf := b256kPool.Get().(*[]byte)
if buf == nil {
return make128kSlicePointer()
}
if cap(*buf) < size256k {
return make128kSlicePointer()
}
*buf = (*buf)[:size256k]
return buf
}
// Put256KBytes 放回一个128k大小 []byte
func Put256KBytes(b *[]byte) {
if cap(*b) < size256k || cap(*b) > 2*size256k { // 太大或太小的 []byte 不要放入
return
}
*b = (*b)[:cap(*b)]
b256kPool.Put(b)
}
func make128kSlicePointer() *[]byte {
data := make([]byte, size256k)
return &data
}

92
binary/protobuf.go Normal file
View File

@ -0,0 +1,92 @@
package binary
import (
"bytes"
"encoding/binary"
"math"
)
type DynamicProtoMessage map[uint64]interface{}
type encoder struct {
bytes.Buffer
}
func (msg DynamicProtoMessage) Encode() []byte {
en := &encoder{}
for id, value := range msg {
key := id << 3
switch v := value.(type) {
case bool:
en.uvarint(key | 0)
vi := uint64(0)
if v {
vi = 1
}
en.uvarint(vi)
case int:
en.uvarint(key | 0)
en.svarint(int64(v))
case int32:
en.uvarint(key | 0)
en.svarint(int64(v))
case int64:
en.uvarint(key | 0)
en.svarint(v)
case uint32:
en.uvarint(key | 0)
en.uvarint(uint64(v))
case uint64:
en.uvarint(key | 0)
en.uvarint(v)
case float32:
en.uvarint(key | 5)
en.u32(math.Float32bits(v))
case float64:
en.uvarint(key | 1)
en.u64(math.Float64bits(v))
case string:
en.uvarint(key | 2)
b := []byte(v)
en.uvarint(uint64(len(b)))
_, _ = en.Write(b)
case []uint64:
for i := 0; i < len(v); i++ {
en.uvarint(key | 0)
en.uvarint(v[i])
}
case []byte:
en.uvarint(key | 2)
en.uvarint(uint64(len(v)))
_, _ = en.Write(v)
case DynamicProtoMessage:
en.uvarint(key | 2)
b := v.Encode()
en.uvarint(uint64(len(b)))
_, _ = en.Write(b)
}
}
return en.Bytes()
}
func (en *encoder) uvarint(v uint64) {
var b [binary.MaxVarintLen64]byte
n := binary.PutUvarint(b[:], v)
_, _ = en.Write(b[:n])
}
func (en *encoder) svarint(v int64) {
en.uvarint(uint64(v)<<1 ^ uint64(v>>63))
}
func (en *encoder) u32(v uint32) {
var b [4]byte
binary.LittleEndian.PutUint32(b[:], v)
_, _ = en.Write(b[:])
}
func (en *encoder) u64(v uint64) {
var b [8]byte
binary.LittleEndian.PutUint64(b[:], v)
_, _ = en.Write(b[:])
}

View File

@ -1,7 +1,6 @@
package proto package binary
import ( import (
"bytes"
"math" "math"
"testing" "testing"
) )
@ -9,7 +8,7 @@ import (
func benchEncoderUvarint(b *testing.B, v uint64) { func benchEncoderUvarint(b *testing.B, v uint64) {
e := encoder{} e := encoder{}
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
e.buf = e.buf[:0] e.Reset()
e.uvarint(v) e.uvarint(v)
} }
} }
@ -17,7 +16,7 @@ func benchEncoderUvarint(b *testing.B, v uint64) {
func benchEncoderSvarint(b *testing.B, v int64) { func benchEncoderSvarint(b *testing.B, v int64) {
e := encoder{} e := encoder{}
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
e.buf = e.buf[:0] e.Reset()
e.svarint(v) e.svarint(v)
} }
} }
@ -45,15 +44,3 @@ func Benchmark_encoder_svarint(b *testing.B) {
benchEncoderSvarint(b, math.MaxInt64) benchEncoderSvarint(b, math.MaxInt64)
}) })
} }
func TestDynamicMessage_Encode(t *testing.T) {
input := DynamicMessage{
1: 2,
3: 4,
}
got := input.Encode()
expected := []byte{1 << 3, 2, 3 << 3, 4}
if !bytes.Equal(got, expected) {
t.Fatalf("expected %v but got %v", expected, got)
}
}

View File

@ -17,6 +17,8 @@ type NetworkReader struct {
conn net.Conn conn net.Conn
} }
type TlvMap map[uint16][]byte
// --- ByteStream reader --- // --- ByteStream reader ---
func NewReader(data []byte) *Reader { func NewReader(data []byte) *Reader {
@ -50,20 +52,17 @@ func (r *Reader) ReadBytesShort() []byte {
} }
func (r *Reader) ReadUInt16() uint16 { func (r *Reader) ReadUInt16() uint16 {
b := make([]byte, 2) b := r.ReadBytes(2)
_, _ = r.buf.Read(b)
return binary.BigEndian.Uint16(b) return binary.BigEndian.Uint16(b)
} }
func (r *Reader) ReadInt32() int32 { func (r *Reader) ReadInt32() int32 {
b := make([]byte, 4) b := r.ReadBytes(4)
_, _ = r.buf.Read(b)
return int32(binary.BigEndian.Uint32(b)) return int32(binary.BigEndian.Uint32(b))
} }
func (r *Reader) ReadInt64() int64 { func (r *Reader) ReadInt64() int64 {
b := make([]byte, 8) b := r.ReadBytes(8)
_, _ = r.buf.Read(b)
return int64(binary.BigEndian.Uint64(b)) return int64(binary.BigEndian.Uint64(b))
} }
@ -72,10 +71,6 @@ func (r *Reader) ReadString() string {
return utils.B2S(data) return utils.B2S(data)
} }
func (r *Reader) ReadInt32Bytes() []byte {
return r.ReadBytes(int(r.ReadInt32() - 4))
}
func (r *Reader) ReadStringShort() string { func (r *Reader) ReadStringShort() string {
data := r.ReadBytes(int(r.ReadUInt16())) data := r.ReadBytes(int(r.ReadUInt16()))
return utils.B2S(data) return utils.B2S(data)
@ -90,12 +85,39 @@ func (r *Reader) ReadAvailable() []byte {
return r.ReadBytes(r.buf.Len()) return r.ReadBytes(r.buf.Len())
} }
func (r *Reader) ReadTlvMap(tagSize int) (m TlvMap) {
defer func() {
if r := recover(); r != nil {
// TODO: error
}
}()
m = make(map[uint16][]byte)
for {
if r.Len() < tagSize {
return m
}
var k uint16
if tagSize == 1 {
k = uint16(r.ReadByte())
} else if tagSize == 2 {
k = r.ReadUInt16()
} else if tagSize == 4 {
k = uint16(r.ReadInt32())
}
if k == 255 {
return m
}
m[k] = r.ReadBytes(int(r.ReadUInt16()))
}
}
func (r *Reader) Len() int { func (r *Reader) Len() int {
return r.buf.Len() return r.buf.Len()
} }
func (r *Reader) Index() int64 { func (tlv TlvMap) Exists(key uint16) bool {
return r.buf.Size() _, ok := tlv[key]
return ok
} }
// --- Network reader --- // --- Network reader ---
@ -123,8 +145,7 @@ func (r *NetworkReader) ReadBytes(len int) ([]byte, error) {
} }
func (r *NetworkReader) ReadInt32() (int32, error) { func (r *NetworkReader) ReadInt32() (int32, error) {
b := make([]byte, 4) b, err := r.ReadBytes(4)
_, err := r.conn.Read(b)
if err != nil { if err != nil {
return 0, err return 0, err
} }

View File

@ -2,142 +2,158 @@ package binary
import ( import (
"encoding/binary" "encoding/binary"
_ "unsafe" // required by go:linkname "math/rand"
"unsafe"
) )
func xorQ(a, b []byte, c []byte) { // MAGIC
*(*uint64)(unsafe.Pointer(&c[0])) =
*(*uint64)(unsafe.Pointer(&a[0])) ^ *(*uint64)(unsafe.Pointer(&b[0]))
}
type TEA [4]uint32 type TEA [4]uint32
// Encrypt tea 加密 // Encrypt tea 加密
// http://bbs.chinaunix.net/thread-583468-1-1.html // http://bbs.chinaunix.net/thread-583468-1-1.html
// 感谢xichen大佬对TEA的解释 // 感谢xichen大佬对TEA的解释
func (t TEA) Encrypt(src []byte) (dst []byte) { func (t *TEA) Encrypt(src []byte) (dst []byte) {
lens := len(src) lens := len(src)
fill := 10 - (lens+1)%8 fill := 10 - (lens+1)%8
tmp1 := make([]byte, 8) // 非纯src的数据
tmp2 := make([]byte, 8)
dst = make([]byte, fill+lens+7) dst = make([]byte, fill+lens+7)
// for i := 0; i < fill; i++ {
// dst[i] = ' '
// } // For test purpose
_, _ = rand.Read(dst[0:fill])
dst[0] = byte(fill-3) | 0xF8 // 存储pad长度 dst[0] = byte(fill-3) | 0xF8 // 存储pad长度
copy(dst[fill:], src) in := 0 // 位置
// #1
var iv1, iv2, holder uint64 if fill < 8 {
for i := 0; i < len(dst); i += 8 { in = 8 - fill
block := binary.BigEndian.Uint64(dst[i:]) copy(dst[fill:8], src[:in])
holder = block ^ iv1
iv1 = t.encode(holder)
iv1 ^= iv2
iv2 = holder
binary.BigEndian.PutUint64(dst[i:], iv1)
} }
copy(tmp2, dst[0:8])
t.encode(dst[0:8], dst[0:8])
out := 8 // 位置
// #2
if fill > 8 {
copy(dst[fill:out+8], src[:16-fill])
xorQ(dst[8:16], dst[0:8], dst[8:16]) // 与前一次结果xor
copy(tmp1, dst[8:16])
t.encode(dst[8:16], dst[8:16])
xorQ(dst[8:16], tmp2, dst[8:16]) // 与前一次数据xor
copy(tmp2, tmp1)
in = 16 - fill
out = 16
}
// #3+或#4+
lens -= 8
for in < lens {
xorQ(src[in:in+8], dst[out-8:out], dst[out:out+8]) // 与前一次结果xor
copy(tmp1, dst[out:out+8])
t.encode(dst[out:out+8], dst[out:out+8])
xorQ(dst[out:out+8], tmp2, dst[out:out+8]) // 与前一次数据xor
copy(tmp2, tmp1)
in += 8
out += 8
}
tmp3 := make([]byte, 8)
copy(tmp3, src[in:])
xorQ(tmp3, dst[out-8:out], dst[out:out+8]) // 与前一次结果xor
t.encode(dst[out:out+8], dst[out:out+8])
xorQ(dst[out:out+8], tmp2, dst[out:out+8]) // 与前一次数据xor
return dst return dst
} }
func (t TEA) Decrypt(data []byte) []byte { func (t *TEA) Decrypt(data []byte) []byte {
if len(data) < 16 || len(data)%8 != 0 { if len(data) < 16 || len(data)%8 != 0 {
return nil return nil
} }
dst := make([]byte, len(data)) dst := make([]byte, len(data))
var iv1, iv2, holder uint64 copy(dst, data)
for i := 0; i < len(dst); i += 8 { t.decode(dst[0:8], dst[0:8])
iv1 = binary.BigEndian.Uint64(data[i:]) tmp := make([]byte, 8)
iv2 ^= iv1 copy(tmp, dst[0:8])
iv2 = t.decode(iv2) for in := 8; in < len(data); in += 8 {
binary.BigEndian.PutUint64(dst[i:], iv2^holder) xorQ(dst[in:in+8], tmp, dst[in:in+8])
holder = iv1 t.decode(dst[in:in+8], dst[in:in+8])
xorQ(dst[in:in+8], data[in-8:in], dst[in:in+8])
xorQ(dst[in:in+8], data[in-8:in], tmp)
} }
return dst[dst[0]&7+3 : len(data)-7] return dst[dst[0]&7+3 : len(data)-7]
} }
//go:nosplit //go:nosplit
func (t *TEA) encode(n uint64) uint64 { func unpack(data []byte) (v0, v1 uint32) {
v0, v1 := uint32(n>>32), uint32(n) v1 = uint32(data[7]) | uint32(data[6])<<8 | uint32(data[5])<<16 | uint32(data[4])<<24
t0, t1, t2, t3 := t[0], t[1], t[2], t[3] v0 = uint32(data[3]) | uint32(data[2])<<8 | uint32(data[1])<<16 | uint32(data[0])<<24
return v0, v1
}
v0 += (v1 + 0x9e3779b9) ^ (v1<<4 + t0) ^ (v1>>5 + t1) //go:nosplit
v1 += (v0 + 0x9e3779b9) ^ (v0<<4 + t2) ^ (v0>>5 + t3) func repack(data []byte, v0, v1 uint32) {
v0 += (v1 + 0x3c6ef372) ^ (v1<<4 + t0) ^ (v1>>5 + t1) _ = data[7] // early bounds check to guarantee safety of writes below
v1 += (v0 + 0x3c6ef372) ^ (v0<<4 + t2) ^ (v0>>5 + t3) data[0] = byte(v0 >> 24)
v0 += (v1 + 0xdaa66d2b) ^ (v1<<4 + t0) ^ (v1>>5 + t1) data[1] = byte(v0 >> 16)
v1 += (v0 + 0xdaa66d2b) ^ (v0<<4 + t2) ^ (v0>>5 + t3) data[2] = byte(v0 >> 8)
v0 += (v1 + 0x78dde6e4) ^ (v1<<4 + t0) ^ (v1>>5 + t1) data[3] = byte(v0)
v1 += (v0 + 0x78dde6e4) ^ (v0<<4 + t2) ^ (v0>>5 + t3)
v0 += (v1 + 0x1715609d) ^ (v1<<4 + t0) ^ (v1>>5 + t1)
v1 += (v0 + 0x1715609d) ^ (v0<<4 + t2) ^ (v0>>5 + t3)
v0 += (v1 + 0xb54cda56) ^ (v1<<4 + t0) ^ (v1>>5 + t1)
v1 += (v0 + 0xb54cda56) ^ (v0<<4 + t2) ^ (v0>>5 + t3)
v0 += (v1 + 0x5384540f) ^ (v1<<4 + t0) ^ (v1>>5 + t1)
v1 += (v0 + 0x5384540f) ^ (v0<<4 + t2) ^ (v0>>5 + t3)
v0 += (v1 + 0xf1bbcdc8) ^ (v1<<4 + t0) ^ (v1>>5 + t1)
v1 += (v0 + 0xf1bbcdc8) ^ (v0<<4 + t2) ^ (v0>>5 + t3)
v0 += (v1 + 0x8ff34781) ^ (v1<<4 + t0) ^ (v1>>5 + t1)
v1 += (v0 + 0x8ff34781) ^ (v0<<4 + t2) ^ (v0>>5 + t3)
v0 += (v1 + 0x2e2ac13a) ^ (v1<<4 + t0) ^ (v1>>5 + t1)
v1 += (v0 + 0x2e2ac13a) ^ (v0<<4 + t2) ^ (v0>>5 + t3)
v0 += (v1 + 0xcc623af3) ^ (v1<<4 + t0) ^ (v1>>5 + t1)
v1 += (v0 + 0xcc623af3) ^ (v0<<4 + t2) ^ (v0>>5 + t3)
v0 += (v1 + 0x6a99b4ac) ^ (v1<<4 + t0) ^ (v1>>5 + t1)
v1 += (v0 + 0x6a99b4ac) ^ (v0<<4 + t2) ^ (v0>>5 + t3)
v0 += (v1 + 0x08d12e65) ^ (v1<<4 + t0) ^ (v1>>5 + t1)
v1 += (v0 + 0x08d12e65) ^ (v0<<4 + t2) ^ (v0>>5 + t3)
v0 += (v1 + 0xa708a81e) ^ (v1<<4 + t0) ^ (v1>>5 + t1)
v1 += (v0 + 0xa708a81e) ^ (v0<<4 + t2) ^ (v0>>5 + t3)
v0 += (v1 + 0x454021d7) ^ (v1<<4 + t0) ^ (v1>>5 + t1)
v1 += (v0 + 0x454021d7) ^ (v0<<4 + t2) ^ (v0>>5 + t3)
v0 += (v1 + 0xe3779b90) ^ (v1<<4 + t0) ^ (v1>>5 + t1)
v1 += (v0 + 0xe3779b90) ^ (v0<<4 + t2) ^ (v0>>5 + t3)
return uint64(v0)<<32 | uint64(v1) data[4] = byte(v1 >> 24)
data[5] = byte(v1 >> 16)
data[6] = byte(v1 >> 8)
data[7] = byte(v1)
}
var sumTable = [0x10]uint32{
0x9e3779b9,
0x3c6ef372,
0xdaa66d2b,
0x78dde6e4,
0x1715609d,
0xb54cda56,
0x5384540f,
0xf1bbcdc8,
0x8ff34781,
0x2e2ac13a,
0xcc623af3,
0x6a99b4ac,
0x08d12e65,
0xa708a81e,
0x454021d7,
0xe3779b90,
}
//go:nosplit
func (t *TEA) encode(src, dst []byte) {
v0, v1 := unpack(src)
for i := 0; i < 0x10; i++ {
v0 += ((v1 << 4) + t[0]) ^ (v1 + sumTable[i]) ^ ((v1 >> 5) + t[1])
v1 += ((v0 << 4) + t[2]) ^ (v0 + sumTable[i]) ^ ((v0 >> 5) + t[3])
}
repack(dst, v0, v1)
} }
// 每次8字节 // 每次8字节
//
//go:nosplit //go:nosplit
func (t *TEA) decode(n uint64) uint64 { func (t *TEA) decode(src, dst []byte) {
v0, v1 := uint32(n>>32), uint32(n) v0, v1 := unpack(src)
t0, t1, t2, t3 := t[0], t[1], t[2], t[3] for i := 0xf; i >= 0; i-- {
v1 -= ((v0 << 4) + t[2]) ^ (v0 + sumTable[i]) ^ ((v0 >> 5) + t[3])
v1 -= (v0 + 0xe3779b90) ^ (v0<<4 + t2) ^ (v0>>5 + t3) v0 -= ((v1 << 4) + t[0]) ^ (v1 + sumTable[i]) ^ ((v1 >> 5) + t[1])
v0 -= (v1 + 0xe3779b90) ^ (v1<<4 + t0) ^ (v1>>5 + t1) }
v1 -= (v0 + 0x454021d7) ^ (v0<<4 + t2) ^ (v0>>5 + t3) repack(dst, v0, v1)
v0 -= (v1 + 0x454021d7) ^ (v1<<4 + t0) ^ (v1>>5 + t1)
v1 -= (v0 + 0xa708a81e) ^ (v0<<4 + t2) ^ (v0>>5 + t3)
v0 -= (v1 + 0xa708a81e) ^ (v1<<4 + t0) ^ (v1>>5 + t1)
v1 -= (v0 + 0x08d12e65) ^ (v0<<4 + t2) ^ (v0>>5 + t3)
v0 -= (v1 + 0x08d12e65) ^ (v1<<4 + t0) ^ (v1>>5 + t1)
v1 -= (v0 + 0x6a99b4ac) ^ (v0<<4 + t2) ^ (v0>>5 + t3)
v0 -= (v1 + 0x6a99b4ac) ^ (v1<<4 + t0) ^ (v1>>5 + t1)
v1 -= (v0 + 0xcc623af3) ^ (v0<<4 + t2) ^ (v0>>5 + t3)
v0 -= (v1 + 0xcc623af3) ^ (v1<<4 + t0) ^ (v1>>5 + t1)
v1 -= (v0 + 0x2e2ac13a) ^ (v0<<4 + t2) ^ (v0>>5 + t3)
v0 -= (v1 + 0x2e2ac13a) ^ (v1<<4 + t0) ^ (v1>>5 + t1)
v1 -= (v0 + 0x8ff34781) ^ (v0<<4 + t2) ^ (v0>>5 + t3)
v0 -= (v1 + 0x8ff34781) ^ (v1<<4 + t0) ^ (v1>>5 + t1)
v1 -= (v0 + 0xf1bbcdc8) ^ (v0<<4 + t2) ^ (v0>>5 + t3)
v0 -= (v1 + 0xf1bbcdc8) ^ (v1<<4 + t0) ^ (v1>>5 + t1)
v1 -= (v0 + 0x5384540f) ^ (v0<<4 + t2) ^ (v0>>5 + t3)
v0 -= (v1 + 0x5384540f) ^ (v1<<4 + t0) ^ (v1>>5 + t1)
v1 -= (v0 + 0xb54cda56) ^ (v0<<4 + t2) ^ (v0>>5 + t3)
v0 -= (v1 + 0xb54cda56) ^ (v1<<4 + t0) ^ (v1>>5 + t1)
v1 -= (v0 + 0x1715609d) ^ (v0<<4 + t2) ^ (v0>>5 + t3)
v0 -= (v1 + 0x1715609d) ^ (v1<<4 + t0) ^ (v1>>5 + t1)
v1 -= (v0 + 0x78dde6e4) ^ (v0<<4 + t2) ^ (v0>>5 + t3)
v0 -= (v1 + 0x78dde6e4) ^ (v1<<4 + t0) ^ (v1>>5 + t1)
v1 -= (v0 + 0xdaa66d2b) ^ (v0<<4 + t2) ^ (v0>>5 + t3)
v0 -= (v1 + 0xdaa66d2b) ^ (v1<<4 + t0) ^ (v1>>5 + t1)
v1 -= (v0 + 0x3c6ef372) ^ (v0<<4 + t2) ^ (v0>>5 + t3)
v0 -= (v1 + 0x3c6ef372) ^ (v1<<4 + t0) ^ (v1>>5 + t1)
v1 -= (v0 + 0x9e3779b9) ^ (v0<<4 + t2) ^ (v0>>5 + t3)
v0 -= (v1 + 0x9e3779b9) ^ (v1<<4 + t0) ^ (v1>>5 + t1)
return uint64(v0)<<32 | uint64(v1)
} }
//go:nosplit //go:nosplit
func NewTeaCipher(key []byte) (t TEA) { func NewTeaCipher(key []byte) *TEA {
if len(key) != 16 { if len(key) != 16 {
return TEA{} return nil
} }
t[3] = binary.BigEndian.Uint32(key[12:16]) t := new(TEA)
t[2] = binary.BigEndian.Uint32(key[8:12]) t[3] = binary.BigEndian.Uint32(key[12:])
t[1] = binary.BigEndian.Uint32(key[4:8]) t[2] = binary.BigEndian.Uint32(key[8:])
t[0] = binary.BigEndian.Uint32(key[:4]) t[1] = binary.BigEndian.Uint32(key[4:])
t[0] = binary.BigEndian.Uint32(key[0:])
return t return t
} }

View File

@ -110,11 +110,7 @@ func BenchmarkTEAen(b *testing.B) {
benchEncrypt(b, data) benchEncrypt(b, data)
}) })
b.Run("4K", func(b *testing.B) { b.Run("4K", func(b *testing.B) {
data := make([]byte, 1024*4) data := make([]byte, 4096)
benchEncrypt(b, data)
})
b.Run("32K", func(b *testing.B) {
data := make([]byte, 1024*32)
benchEncrypt(b, data) benchEncrypt(b, data)
}) })
} }
@ -132,20 +128,4 @@ func BenchmarkTEAde(b *testing.B) {
data := make([]byte, 4096) data := make([]byte, 4096)
benchDecrypt(b, data) benchDecrypt(b, data)
}) })
b.Run("32K", func(b *testing.B) {
data := make([]byte, 1024*32)
benchDecrypt(b, data)
})
}
func BenchmarkTEA_encode(b *testing.B) {
for i := 0; i < b.N; i++ {
testTEA.encode(114514)
}
}
func BenchmarkTEA_decode(b *testing.B) {
for i := 0; i < b.N; i++ {
testTEA.decode(114514)
}
} }

View File

@ -2,12 +2,14 @@ package binary
import ( import (
"bytes" "bytes"
"compress/gzip"
"compress/zlib"
binary2 "encoding/binary" binary2 "encoding/binary"
"encoding/hex" "encoding/hex"
"io"
"net" "net"
"github.com/klauspost/compress/gzip"
"github.com/klauspost/compress/zlib"
"github.com/Mrs4s/MiraiGo/utils" "github.com/Mrs4s/MiraiGo/utils"
) )
@ -33,7 +35,7 @@ func ZlibUncompress(src []byte) []byte {
var out bytes.Buffer var out bytes.Buffer
r, _ := zlib.NewReader(b) r, _ := zlib.NewReader(b)
defer r.Close() defer r.Close()
_, _ = out.ReadFrom(r) io.Copy(&out, r)
return out.Bytes() return out.Bytes()
} }
@ -41,8 +43,7 @@ func ZlibCompress(data []byte) []byte {
zw := acquireZlibWriter() zw := acquireZlibWriter()
_, _ = zw.w.Write(data) _, _ = zw.w.Write(data)
_ = zw.w.Close() _ = zw.w.Close()
ret := make([]byte, len(zw.buf.Bytes())) ret := append([]byte(nil), zw.buf.Bytes()...)
copy(ret, zw.buf.Bytes())
releaseZlibWriter(zw) releaseZlibWriter(zw)
return ret return ret
} }
@ -51,8 +52,7 @@ func GZipCompress(data []byte) []byte {
gw := AcquireGzipWriter() gw := AcquireGzipWriter()
_, _ = gw.Write(data) _, _ = gw.Write(data)
_ = gw.Close() _ = gw.Close()
ret := make([]byte, len(gw.buf.Bytes())) ret := append([]byte(nil), gw.buf.Bytes()...)
copy(ret, gw.buf.Bytes())
ReleaseGzipWriter(gw) ReleaseGzipWriter(gw)
return ret return ret
} }
@ -62,7 +62,7 @@ func GZipUncompress(src []byte) []byte {
var out bytes.Buffer var out bytes.Buffer
r, _ := gzip.NewReader(b) r, _ := gzip.NewReader(b)
defer r.Close() defer r.Close()
_, _ = out.ReadFrom(r) _, _ = io.Copy(&out, r)
return out.Bytes() return out.Bytes()
} }
@ -98,13 +98,28 @@ func AppendUUID(dst []byte, uuid []byte) []byte {
return dst return dst
} }
func ToIPV4Address(arr []byte) string {
ip := (net.IP)(arr)
return ip.String()
}
func UInt32ToIPV4Address(i uint32) string { func UInt32ToIPV4Address(i uint32) string {
ip := net.IP{0, 0, 0, 0} ip := net.IP{0, 0, 0, 0}
binary2.LittleEndian.PutUint32(ip, i) binary2.LittleEndian.PutUint32(ip, i)
return ip.String() return ip.String()
} }
func ToBytes(i any) []byte { func ToChunkedBytesF(b []byte, size int, f func([]byte)) {
r := NewReader(b)
for r.Len() >= size {
f(r.ReadBytes(size))
}
if r.Len() > 0 {
f(r.ReadAvailable())
}
}
func ToBytes(i interface{}) []byte {
return NewWriterF(func(w *Writer) { return NewWriterF(func(w *Writer) {
// TODO: more types // TODO: more types
switch t := i.(type) { switch t := i.(type) {

View File

@ -4,49 +4,21 @@ import (
"bytes" "bytes"
"encoding/binary" "encoding/binary"
"encoding/hex" "encoding/hex"
"github.com/Mrs4s/MiraiGo/utils"
) )
// Writer 写入 // Writer 写入
type Writer bytes.Buffer type Writer bytes.Buffer
func NewWriterF(f func(writer *Writer)) []byte { func NewWriterF(f func(writer *Writer)) []byte {
w := SelectWriter() w := NewWriter()
f(w) f(w)
b := make([]byte, len(w.Bytes())) b := append([]byte(nil), w.Bytes()...)
copy(b, w.Bytes()) PutWriter(w)
w.put()
return b return b
} }
// OpenWriterF must call func cl to close
func OpenWriterF(f func(*Writer)) (b []byte, cl func()) {
w := SelectWriter()
f(w)
return w.Bytes(), w.put
}
func (w *Writer) FillUInt16() (pos int) {
pos = w.Len()
(*bytes.Buffer)(w).Write([]byte{0, 0})
return
}
func (w *Writer) WriteUInt16At(pos int, v uint16) {
newdata := (*bytes.Buffer)(w).Bytes()[pos:]
binary.BigEndian.PutUint16(newdata, v)
}
func (w *Writer) FillUInt32() (pos int) {
pos = w.Len()
(*bytes.Buffer)(w).Write([]byte{0, 0, 0, 0})
return
}
func (w *Writer) WriteUInt32At(pos int, v uint32) {
newdata := (*bytes.Buffer)(w).Bytes()[pos:]
binary.BigEndian.PutUint32(newdata, v)
}
func (w *Writer) Write(b []byte) { func (w *Writer) Write(b []byte) {
(*bytes.Buffer)(w).Write(b) (*bytes.Buffer)(w).Write(b)
} }
@ -79,13 +51,13 @@ func (w *Writer) WriteUInt64(v uint64) {
} }
func (w *Writer) WriteString(v string) { func (w *Writer) WriteString(v string) {
w.WriteUInt32(uint32(len(v) + 4)) payload := utils.S2B(v)
(*bytes.Buffer)(w).WriteString(v) w.WriteUInt32(uint32(len(payload) + 4))
w.Write(payload)
} }
func (w *Writer) WriteStringShort(v string) { func (w *Writer) WriteStringShort(v string) {
w.WriteUInt16(uint16(len(v))) w.WriteBytesShort(utils.S2B(v))
(*bytes.Buffer)(w).WriteString(v)
} }
func (w *Writer) WriteBool(b bool) { func (w *Writer) WriteBool(b bool) {
@ -97,13 +69,36 @@ func (w *Writer) WriteBool(b bool) {
} }
func (w *Writer) EncryptAndWrite(key []byte, data []byte) { func (w *Writer) EncryptAndWrite(key []byte, data []byte) {
w.Write(NewTeaCipher(key).Encrypt(data)) tea := NewTeaCipher(key)
ed := tea.Encrypt(data)
w.Write(ed)
} }
func (w *Writer) WriteIntLvPacket(offset int, f func(*Writer)) { func (w *Writer) WriteIntLvPacket(offset int, f func(writer *Writer)) {
pos := w.FillUInt32() data := NewWriterF(f)
f(w) w.WriteUInt32(uint32(len(data) + offset))
w.WriteUInt32At(pos, uint32(w.Len()+offset-pos-4)) w.Write(data)
}
func (w *Writer) WriteUniPacket(commandName string, sessionId, extraData, body []byte) {
w1 := NewWriter()
{ // WriteIntLvPacket
w1.WriteString(commandName)
w1.WriteUInt32(8)
w1.Write(sessionId)
if len(extraData) == 0 {
w1.WriteUInt32(0x04)
} else {
w1.WriteUInt32(uint32(len(extraData) + 4))
w1.Write(extraData)
}
}
data := w1.Bytes()
w.WriteUInt32(uint32(len(data) + 4))
w.Write(data)
PutWriter(w1)
w.WriteUInt32(uint32(len(body) + 4)) // WriteIntLvPacket
w.Write(body)
} }
func (w *Writer) WriteBytesShort(data []byte) { func (w *Writer) WriteBytesShort(data []byte) {
@ -119,14 +114,14 @@ func (w *Writer) WriteTlvLimitedSize(data []byte, limit int) {
w.WriteBytesShort(data[:limit]) w.WriteBytesShort(data[:limit])
} }
func (w *Writer) Len() int {
return (*bytes.Buffer)(w).Len()
}
func (w *Writer) Bytes() []byte { func (w *Writer) Bytes() []byte {
return (*bytes.Buffer)(w).Bytes() return (*bytes.Buffer)(w).Bytes()
} }
func (w *Writer) Cap() int {
return (*bytes.Buffer)(w).Cap()
}
func (w *Writer) Reset() { func (w *Writer) Reset() {
(*bytes.Buffer)(w).Reset() (*bytes.Buffer)(w).Reset()
} }
@ -134,7 +129,3 @@ func (w *Writer) Reset() {
func (w *Writer) Grow(n int) { func (w *Writer) Grow(n int) {
(*bytes.Buffer)(w).Grow(n) (*bytes.Buffer)(w).Grow(n)
} }
func (w *Writer) put() {
PutWriter(w)
}

View File

@ -1,7 +1,7 @@
package binary package binary
import ( import (
"crypto/rand" "math/rand"
"testing" "testing"
) )
@ -49,51 +49,3 @@ func BenchmarkNewWriterF128_5(b *testing.B) {
} }
}) })
} }
func BenchmarkOpenWriterF128(b *testing.B) {
test := make([]byte, 128)
rand.Read(test)
b.StartTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
_, close := OpenWriterF(func(w *Writer) {
w.Write(test)
})
close()
}
})
}
func BenchmarkOpenWriterF128_3(b *testing.B) {
test := make([]byte, 128)
rand.Read(test)
b.StartTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
_, close := OpenWriterF(func(w *Writer) {
w.Write(test)
w.Write(test)
w.Write(test)
})
close()
}
})
}
func BenchmarkOpenWriterF128_5(b *testing.B) {
test := make([]byte, 128)
rand.Read(test)
b.StartTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
_, close := OpenWriterF(func(w *Writer) {
w.Write(test)
w.Write(test)
w.Write(test)
w.Write(test)
w.Write(test)
})
close()
}
})
}

View File

@ -1,11 +1,8 @@
package client package client
import ( import "github.com/Mrs4s/MiraiGo/internal/protobuf/data/msg"
"github.com/Mrs4s/MiraiGo/client/internal/network"
"github.com/Mrs4s/MiraiGo/client/pb/msg"
)
var privateMsgDecoders = map[int32]func(*QQClient, *msg.Message, *network.Packet){ var privateMsgDecoders = map[int32]func(*QQClient, *msg.Message, *incomingPacketInfo){
9: privateMessageDecoder, 10: privateMessageDecoder, 31: privateMessageDecoder, 9: privateMessageDecoder, 10: privateMessageDecoder, 31: privateMessageDecoder,
79: privateMessageDecoder, 97: privateMessageDecoder, 120: privateMessageDecoder, 79: privateMessageDecoder, 97: privateMessageDecoder, 120: privateMessageDecoder,
132: privateMessageDecoder, 133: privateMessageDecoder, 166: privateMessageDecoder, 132: privateMessageDecoder, 133: privateMessageDecoder, 166: privateMessageDecoder,
@ -13,21 +10,21 @@ var privateMsgDecoders = map[int32]func(*QQClient, *msg.Message, *network.Packet
208: privatePttDecoder, 208: privatePttDecoder,
} }
var nonSvcNotifyTroopSystemMsgDecoders = map[int32]func(*QQClient, *msg.Message, *network.Packet){ var nonSvcNotifyTroopSystemMsgDecoders = map[int32]func(*QQClient, *msg.Message, *incomingPacketInfo){
36: troopSystemMessageDecoder, 85: troopSystemMessageDecoder, 36: troopSystemMessageDecoder, 85: troopSystemMessageDecoder,
} }
var troopSystemMsgDecoders = map[int32]func(*QQClient, *msg.Message, *network.Packet){ var troopSystemMsgDecoders = map[int32]func(*QQClient, *msg.Message, *incomingPacketInfo){
35: troopSystemMessageDecoder, 37: troopSystemMessageDecoder, 35: troopSystemMessageDecoder, 37: troopSystemMessageDecoder,
45: troopSystemMessageDecoder, 46: troopSystemMessageDecoder, 84: troopSystemMessageDecoder, 45: troopSystemMessageDecoder, 46: troopSystemMessageDecoder, 84: troopSystemMessageDecoder,
86: troopSystemMessageDecoder, 87: troopSystemMessageDecoder, 86: troopSystemMessageDecoder, 87: troopSystemMessageDecoder,
} // IsSvcNotify } // IsSvcNotify
var sysMsgDecoders = map[int32]func(*QQClient, *msg.Message, *network.Packet){ var sysMsgDecoders = map[int32]func(*QQClient, *msg.Message, *incomingPacketInfo){
187: systemMessageDecoder, 188: systemMessageDecoder, 189: systemMessageDecoder, 187: systemMessageDecoder, 188: systemMessageDecoder, 189: systemMessageDecoder,
190: systemMessageDecoder, 191: systemMessageDecoder, 190: systemMessageDecoder, 191: systemMessageDecoder,
} // IsSvcNotify } // IsSvcNotify
var otherDecoders = map[int32]func(*QQClient, *msg.Message, *network.Packet){ var otherDecoders = map[int32]func(*QQClient, *msg.Message, *incomingPacketInfo){
33: troopAddMemberBroadcastDecoder, 529: msgType0x211Decoder, 33: troopAddMemberBroadcastDecoder, 529: msgType0x211Decoder,
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,18 +1,20 @@
package client package client
//go:generate go run github.com/Mrs4s/MiraiGo/internal/generator/c2c_switcher //go:generate go run cmd/c2c_switcher.go
import ( import (
"fmt" "fmt"
"sync/atomic"
"time" "time"
protobuf "github.com/segmentio/encoding/proto"
"github.com/Mrs4s/MiraiGo/binary"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/Mrs4s/MiraiGo/binary"
"github.com/Mrs4s/MiraiGo/client/internal/network"
"github.com/Mrs4s/MiraiGo/client/pb" "github.com/Mrs4s/MiraiGo/client/pb"
"github.com/Mrs4s/MiraiGo/client/pb/msg" "github.com/Mrs4s/MiraiGo/internal/protobuf/data/msg"
"github.com/Mrs4s/MiraiGo/internal/proto"
) )
type ( type (
@ -28,21 +30,21 @@ type (
) )
const ( const (
GroupSource TempSessionSource = iota // 来自群聊 GroupSource TempSessionSource = 0 // 来自群聊
ConsultingSource // 来自QQ咨询 ConsultingSource TempSessionSource = 1 // 来自QQ咨询
SearchSource // 来自查找 SearchSource TempSessionSource = 2 // 来自查找
MovieSource // 来自QQ电影 MovieSource TempSessionSource = 3 // 来自QQ电影
HotChatSource // 来自热聊 HotChatSource TempSessionSource = 4 // 来自热聊
SystemMessageSource // 来自验证消息 SystemMessageSource TempSessionSource = 6 // 来自验证消息
MultiChatSource // 来自多人聊天 MultiChatSource TempSessionSource = 7 // 来自多人聊天
DateSource // 来自约会 DateSource TempSessionSource = 8 // 来自约会
AddressBookSource // 来自通讯录 AddressBookSource TempSessionSource = 9 // 来自通讯录
) )
func (c *QQClient) c2cMessageSyncProcessor(rsp *msg.GetMessageResponse, info network.RequestParams) { func (c *QQClient) c2cMessageSyncProcessor(rsp *msg.GetMessageResponse, info *incomingPacketInfo) {
c.sig.SyncCookie = rsp.SyncCookie c.syncCookie = rsp.SyncCookie
c.sig.PubAccountCookie = rsp.PubAccountCookie c.pubAccountCookie = rsp.PubAccountCookie
// c.msgCtrlBuf = rsp.MsgCtrlBuf c.msgCtrlBuf = rsp.MsgCtrlBuf
if rsp.UinPairMsgs == nil { if rsp.UinPairMsgs == nil {
return return
} }
@ -51,17 +53,17 @@ func (c *QQClient) c2cMessageSyncProcessor(rsp *msg.GetMessageResponse, info net
for _, pMsg := range pairMsg.Messages { for _, pMsg := range pairMsg.Messages {
// delete message // delete message
delItem := &pb.MessageItem{ delItem := &pb.MessageItem{
FromUin: pMsg.Head.FromUin.Unwrap(), FromUin: pMsg.Head.GetFromUin(),
ToUin: pMsg.Head.ToUin.Unwrap(), ToUin: pMsg.Head.GetToUin(),
MsgType: pMsg.Head.MsgType.Unwrap(), MsgType: pMsg.Head.GetMsgType(),
MsgSeq: pMsg.Head.MsgSeq.Unwrap(), MsgSeq: pMsg.Head.GetMsgSeq(),
MsgUid: pMsg.Head.MsgUid.Unwrap(), MsgUid: pMsg.Head.GetMsgUid(),
} }
delItems = append(delItems, delItem) delItems = append(delItems, delItem)
if pMsg.Head.ToUin.Unwrap() != c.Uin { if pMsg.Head.GetToUin() != c.Uin {
continue continue
} }
if (int64(pairMsg.LastReadTime.Unwrap()) & 4294967295) > int64(pMsg.Head.MsgTime.Unwrap()) { if (int64(pairMsg.GetLastReadTime()) & 4294967295) > int64(pMsg.Head.GetMsgTime()) {
continue continue
} }
c.commMsgProcessor(pMsg, info) c.commMsgProcessor(pMsg, info)
@ -70,43 +72,43 @@ func (c *QQClient) c2cMessageSyncProcessor(rsp *msg.GetMessageResponse, info net
if delItems != nil { if delItems != nil {
_, _ = c.sendAndWait(c.buildDeleteMessageRequestPacket(delItems)) _, _ = c.sendAndWait(c.buildDeleteMessageRequestPacket(delItems))
} }
if rsp.SyncFlag.Unwrap() != msg.SyncFlag_STOP { if rsp.GetSyncFlag() != msg.SyncFlag_STOP {
c.debug("continue sync with flag: %v", rsp.SyncFlag) c.Debug("continue sync with flag: %v", *rsp.SyncFlag)
seq, pkt := c.buildGetMessageRequestPacket(rsp.SyncFlag.Unwrap(), time.Now().Unix()) seq, pkt := c.buildGetMessageRequestPacket(rsp.GetSyncFlag(), time.Now().Unix())
_, _ = c.sendAndWait(seq, pkt, info) _, _ = c.sendAndWait(seq, pkt, info.Params)
} }
} }
func (c *QQClient) commMsgProcessor(pMsg *msg.Message, info network.RequestParams) { func (c *QQClient) commMsgProcessor(pMsg *msg.Message, info *incomingPacketInfo) {
strKey := fmt.Sprintf("%d%d%d%d", pMsg.Head.FromUin.Unwrap(), pMsg.Head.ToUin.Unwrap(), pMsg.Head.MsgSeq.Unwrap(), pMsg.Head.MsgUid.Unwrap()) strKey := fmt.Sprintf("%d%d%d%d", pMsg.Head.GetFromUin(), pMsg.Head.GetToUin(), pMsg.Head.GetMsgSeq(), pMsg.Head.GetMsgUid())
if _, ok := c.msgSvcCache.GetAndUpdate(strKey, time.Hour); ok { if _, ok := c.msgSvcCache.GetAndUpdate(strKey, time.Hour); ok {
c.debug("c2c msg %v already exists in cache. skip.", pMsg.Head.MsgUid.Unwrap()) c.Debug("c2c msg %v already exists in cache. skip.", pMsg.Head.GetMsgUid())
return return
} }
c.msgSvcCache.Add(strKey, unit{}, time.Hour) c.msgSvcCache.Add(strKey, "", time.Hour)
if c.lastC2CMsgTime > int64(pMsg.Head.MsgTime.Unwrap()) && (c.lastC2CMsgTime-int64(pMsg.Head.MsgTime.Unwrap())) > 60*10 { if c.lastC2CMsgTime > int64(pMsg.Head.GetMsgTime()) && (c.lastC2CMsgTime-int64(pMsg.Head.GetMsgTime())) > 60*10 {
c.debug("c2c msg filtered by time. lastMsgTime: %v msgTime: %v", c.lastC2CMsgTime, pMsg.Head.MsgTime.Unwrap()) c.Debug("c2c msg filtered by time. lastMsgTime: %v msgTime: %v", c.lastC2CMsgTime, pMsg.Head.GetMsgTime())
return return
} }
c.lastC2CMsgTime = int64(pMsg.Head.MsgTime.Unwrap()) c.lastC2CMsgTime = int64(pMsg.Head.GetMsgTime())
if info.Bool("init") { if info.Params.bool("init") {
return return
} }
if decoder, _ := peekC2CDecoder(pMsg.Head.MsgType.Unwrap()); decoder != nil { if decoder, _ := peekC2CDecoder(pMsg.Head.GetMsgType()); decoder != nil {
decoder(c, pMsg, info) decoder(c, pMsg, info)
} else { } else {
c.debug("unknown msg type on c2c processor: %v - %v", pMsg.Head.MsgType.Unwrap(), pMsg.Head.C2CCmd.Unwrap()) c.Debug("unknown msg type on c2c processor: %v - %v", pMsg.Head.GetMsgType(), pMsg.Head.GetC2CCmd())
} }
} }
func privateMessageDecoder(c *QQClient, pMsg *msg.Message, _ network.RequestParams) { func privateMessageDecoder(c *QQClient, pMsg *msg.Message, _ *incomingPacketInfo) {
switch pMsg.Head.C2CCmd.Unwrap() { switch pMsg.Head.GetC2CCmd() {
case 11, 175: // friend msg case 11, 175: // friend msg
if pMsg.Head.FromUin.Unwrap() == c.Uin { if pMsg.Head.GetFromUin() == c.Uin {
for { for {
frdSeq := c.friendSeq.Load() frdSeq := atomic.LoadInt32(&c.friendSeq)
if frdSeq < pMsg.Head.MsgSeq.Unwrap() { if frdSeq < pMsg.Head.GetMsgSeq() {
if c.friendSeq.CompareAndSwap(frdSeq, pMsg.Head.MsgSeq.Unwrap()) { if atomic.CompareAndSwapInt32(&c.friendSeq, frdSeq, pMsg.Head.GetMsgSeq()) {
break break
} }
} else { } else {
@ -117,67 +119,53 @@ func privateMessageDecoder(c *QQClient, pMsg *msg.Message, _ network.RequestPara
if pMsg.Body.RichText == nil || pMsg.Body.RichText.Elems == nil { if pMsg.Body.RichText == nil || pMsg.Body.RichText.Elems == nil {
return return
} }
if pMsg.Head.GetFromUin() == c.Uin {
// handle fragmented message c.dispatchPrivateMessageSelf(c.parsePrivateMessage(pMsg))
if pMsg.Content != nil && pMsg.Content.PkgNum.Unwrap() > 1 {
seq := pMsg.Content.DivSeq.Unwrap()
builder := c.messageBuilder(seq)
builder.append(pMsg)
if builder.len() < pMsg.Content.PkgNum.Unwrap() {
// continue to receive other fragments
return
}
c.msgBuilders.Delete(seq)
pMsg = builder.build()
}
if pMsg.Head.FromUin.Unwrap() == c.Uin {
c.SelfPrivateMessageEvent.dispatch(c, c.parsePrivateMessage(pMsg))
return return
} }
c.PrivateMessageEvent.dispatch(c, c.parsePrivateMessage(pMsg)) c.dispatchPrivateMessage(c.parsePrivateMessage(pMsg))
default: default:
c.debug("unknown c2c cmd on private msg decoder: %v", pMsg.Head.C2CCmd.Unwrap()) c.Debug("unknown c2c cmd on private msg decoder: %v", pMsg.Head.GetC2CCmd())
} }
} }
func privatePttDecoder(c *QQClient, pMsg *msg.Message, _ network.RequestParams) { func privatePttDecoder(c *QQClient, pMsg *msg.Message, _ *incomingPacketInfo) {
if pMsg.Body == nil || pMsg.Body.RichText == nil || pMsg.Body.RichText.Ptt == nil { if pMsg.Body == nil || pMsg.Body.RichText == nil || pMsg.Body.RichText.Ptt == nil {
return return
} }
// if len(pMsg.Body.RichText.Ptt.Reserve) != 0 { if len(pMsg.Body.RichText.Ptt.Reserve) != 0 {
// m := binary.NewReader(pMsg.Body.RichText.Ptt.Reserve[1:]).ReadTlvMap(1) // m := binary.NewReader(pMsg.Body.RichText.Ptt.Reserve[1:]).ReadTlvMap(1)
// T3 -> timestamp T8 -> voiceType T9 -> voiceLength T10 -> PbReserveStruct // T3 -> timestamp T8 -> voiceType T9 -> voiceLength T10 -> PbReserveStruct
//} }
c.PrivateMessageEvent.dispatch(c, c.parsePrivateMessage(pMsg)) c.dispatchPrivateMessage(c.parsePrivateMessage(pMsg))
} }
func tempSessionDecoder(c *QQClient, pMsg *msg.Message, _ network.RequestParams) { func tempSessionDecoder(c *QQClient, pMsg *msg.Message, _ *incomingPacketInfo) {
if pMsg.Head.C2CTmpMsgHead == nil || pMsg.Body == nil { if pMsg.Head.C2CTmpMsgHead == nil || pMsg.Body == nil {
return return
} }
if (pMsg.Head.MsgType.Unwrap() == 529 && pMsg.Head.C2CCmd.Unwrap() == 6) || pMsg.Body.RichText != nil { if (pMsg.Head.GetMsgType() == 529 && pMsg.Head.GetC2CCmd() == 6) || pMsg.Body.RichText != nil {
genTempSessionInfo := func() *TempSessionInfo { genTempSessionInfo := func() *TempSessionInfo {
if pMsg.Head.C2CTmpMsgHead.ServiceType.Unwrap() == 0 { if pMsg.Head.C2CTmpMsgHead.GetServiceType() == 0 {
group := c.FindGroup(pMsg.Head.C2CTmpMsgHead.GroupCode.Unwrap()) group := c.FindGroup(pMsg.Head.C2CTmpMsgHead.GetGroupCode())
if group == nil { if group == nil {
return nil return nil
} }
return &TempSessionInfo{ return &TempSessionInfo{
Source: GroupSource, Source: GroupSource,
GroupCode: group.Code, GroupCode: group.Code,
Sender: pMsg.Head.FromUin.Unwrap(), Sender: pMsg.Head.GetFromUin(),
client: c, client: c,
} }
} }
info := &TempSessionInfo{ info := &TempSessionInfo{
Source: 0, Source: 0,
Sender: pMsg.Head.FromUin.Unwrap(), Sender: pMsg.Head.GetFromUin(),
sig: pMsg.Head.C2CTmpMsgHead.Sig, sig: pMsg.Head.C2CTmpMsgHead.Sig,
client: c, client: c,
} }
switch pMsg.Head.C2CTmpMsgHead.ServiceType.Unwrap() { switch pMsg.Head.C2CTmpMsgHead.GetServiceType() {
case 1: case 1:
info.Source = MultiChatSource info.Source = MultiChatSource
case 130: case 130:
@ -198,41 +186,41 @@ func tempSessionDecoder(c *QQClient, pMsg *msg.Message, _ network.RequestParams)
return return
} }
/* /*
group := c.FindGroup(pMsg.Head.C2CTmpMsgHead.GroupCode.Unwrap()) group := c.FindGroup(pMsg.Head.C2CTmpMsgHead.GetGroupCode())
if group == nil { if group == nil {
return return
} }
*/ */
if pMsg.Head.FromUin.Unwrap() == c.Uin { if pMsg.Head.GetFromUin() == c.Uin {
return return
} }
c.TempMessageEvent.dispatch(c, &TempMessageEvent{ c.dispatchTempMessage(&TempMessageEvent{
Message: c.parseTempMessage(pMsg), Message: c.parseTempMessage(pMsg),
Session: session, Session: session,
}) })
} }
} }
func troopAddMemberBroadcastDecoder(c *QQClient, pMsg *msg.Message, _ network.RequestParams) { func troopAddMemberBroadcastDecoder(c *QQClient, pMsg *msg.Message, _ *incomingPacketInfo) {
groupJoinLock.Lock() groupJoinLock.Lock()
defer groupJoinLock.Unlock() defer groupJoinLock.Unlock()
group := c.FindGroupByUin(pMsg.Head.FromUin.Unwrap()) group := c.FindGroupByUin(pMsg.Head.GetFromUin())
if pMsg.Head.AuthUin.Unwrap() == c.Uin { if pMsg.Head.GetAuthUin() == c.Uin {
if group == nil && c.ReloadGroupList() == nil { if group == nil && c.ReloadGroupList() == nil {
c.GroupJoinEvent.dispatch(c, c.FindGroupByUin(pMsg.Head.FromUin.Unwrap())) c.dispatchJoinGroupEvent(c.FindGroupByUin(pMsg.Head.GetFromUin()))
} }
} else { } else {
if group != nil && group.FindMember(pMsg.Head.AuthUin.Unwrap()) == nil { if group != nil && group.FindMember(pMsg.Head.GetAuthUin()) == nil {
mem, err := c.GetMemberInfo(group.Code, pMsg.Head.AuthUin.Unwrap()) mem, err := c.GetMemberInfo(group.Code, pMsg.Head.GetAuthUin())
if err != nil { if err != nil {
c.debug("failed to fetch new member info: %v", err) c.Debug("error to fetch new member info: %v", err)
return return
} }
group.Update(func(info *GroupInfo) { group.Update(func(info *GroupInfo) {
info.Members = append(info.Members, mem) info.Members = append(info.Members, mem)
info.sort() info.sort()
}) })
c.GroupMemberJoinEvent.dispatch(c, &MemberJoinGroupEvent{ c.dispatchNewMemberEvent(&MemberJoinGroupEvent{
Group: group, Group: group,
Member: mem, Member: mem,
}) })
@ -240,13 +228,13 @@ func troopAddMemberBroadcastDecoder(c *QQClient, pMsg *msg.Message, _ network.Re
} }
} }
func systemMessageDecoder(c *QQClient, _ *msg.Message, _ network.RequestParams) { func systemMessageDecoder(c *QQClient, _ *msg.Message, _ *incomingPacketInfo) {
_, pkt := c.buildSystemMsgNewFriendPacket() _, pkt := c.buildSystemMsgNewFriendPacket()
_ = c.sendPacket(pkt) _ = c.sendPacket(pkt)
} }
func troopSystemMessageDecoder(c *QQClient, pMsg *msg.Message, info network.RequestParams) { func troopSystemMessageDecoder(c *QQClient, pMsg *msg.Message, info *incomingPacketInfo) {
if !info.Bool("used_reg_proxy") && pMsg.Head.MsgType.Unwrap() != 85 && pMsg.Head.MsgType.Unwrap() != 36 { if !info.Params.bool("used_reg_proxy") && pMsg.Head.GetMsgType() != 85 && pMsg.Head.GetMsgType() != 36 {
c.exceptAndDispatchGroupSysMsg() c.exceptAndDispatchGroupSysMsg()
} }
if len(pMsg.Body.MsgContent) == 0 { if len(pMsg.Body.MsgContent) == 0 {
@ -254,31 +242,31 @@ func troopSystemMessageDecoder(c *QQClient, pMsg *msg.Message, info network.Requ
} }
reader := binary.NewReader(pMsg.Body.MsgContent) reader := binary.NewReader(pMsg.Body.MsgContent)
groupCode := uint32(reader.ReadInt32()) groupCode := uint32(reader.ReadInt32())
if info := c.FindGroup(int64(groupCode)); info != nil && pMsg.Head.GroupName.Unwrap() != "" && info.Name != pMsg.Head.GroupName.Unwrap() { if info := c.FindGroup(int64(groupCode)); info != nil && pMsg.Head.GetGroupName() != "" && info.Name != pMsg.Head.GetGroupName() {
c.debug("group %v name updated. %v -> %v", groupCode, info.Name, pMsg.Head.GroupName.Unwrap()) c.Debug("group %v name updated. %v -> %v", groupCode, info.Name, pMsg.Head.GetGroupName())
info.Name = pMsg.Head.GroupName.Unwrap() info.Name = pMsg.Head.GetGroupName()
} }
} }
func msgType0x211Decoder(c *QQClient, pMsg *msg.Message, info network.RequestParams) { func msgType0x211Decoder(c *QQClient, pMsg *msg.Message, info *incomingPacketInfo) {
if pMsg.Head.C2CCmd.Unwrap() == 6 || pMsg.Head.C2CTmpMsgHead != nil { if pMsg.Head.GetC2CCmd() == 6 || pMsg.Head.C2CTmpMsgHead != nil {
tempSessionDecoder(c, pMsg, info) tempSessionDecoder(c, pMsg, info)
} }
sub4 := msg.SubMsgType0X4Body{} sub4 := msg.SubMsgType0X4Body{}
if err := proto.Unmarshal(pMsg.Body.MsgContent, &sub4); err != nil { if err := protobuf.Unmarshal(pMsg.Body.MsgContent, &sub4); err != nil {
err = errors.Wrap(err, "unmarshal sub msg 0x4 error") err = errors.Wrap(err, "unmarshal sub msg 0x4 error")
c.error("unmarshal sub msg 0x4 error: %v", err) c.Error("unmarshal sub msg 0x4 error: %v", err)
return return
} }
if sub4.NotOnlineFile != nil && sub4.NotOnlineFile.Subcmd.Unwrap() == 1 { // subcmd: 1 -> sendPacket, 2-> recv if sub4.NotOnlineFile != nil && sub4.NotOnlineFile.GetSubcmd() == 1 { // subcmd: 1 -> sendPacket, 2-> recv
rsp, err := c.sendAndWait(c.buildOfflineFileDownloadRequestPacket(sub4.NotOnlineFile.FileUuid)) // offline_file.go rsp, err := c.sendAndWait(c.buildOfflineFileDownloadRequestPacket(sub4.NotOnlineFile.FileUuid)) // offline_file.go
if err != nil { if err != nil {
return return
} }
c.OfflineFileEvent.dispatch(c, &OfflineFileEvent{ c.dispatchOfflineFileEvent(&OfflineFileEvent{
FileName: string(sub4.NotOnlineFile.FileName), FileName: string(sub4.NotOnlineFile.FileName),
FileSize: sub4.NotOnlineFile.FileSize.Unwrap(), FileSize: sub4.NotOnlineFile.GetFileSize(),
Sender: pMsg.Head.FromUin.Unwrap(), Sender: pMsg.Head.GetFromUin(),
DownloadUrl: rsp.(string), DownloadUrl: rsp.(string),
}) })
} }

View File

@ -1,22 +1,21 @@
// Code generated by internal/generator/c2c_switcher DO NOT EDIT. // Code generated by client/c2c_switcher.go DO NOT EDIT.
package client package client
import ( import (
"github.com/Mrs4s/MiraiGo/client/internal/network" "github.com/Mrs4s/MiraiGo/internal/protobuf/data/msg"
"github.com/Mrs4s/MiraiGo/client/pb/msg"
) )
const ( const (
UnknownDecoder = iota UnknownDecoder = iota
nonSvcNotifyTroopSystemMsgDecoders
otherDecoders
privateMsgDecoders privateMsgDecoders
sysMsgDecoders nonSvcNotifyTroopSystemMsgDecoders
troopSystemMsgDecoders troopSystemMsgDecoders
sysMsgDecoders
otherDecoders
) )
func peekC2CDecoder(msgType int32) (decoder func(*QQClient, *msg.Message, network.RequestParams), decoderType uint8) { func peekC2CDecoder(msgType int32) (decoder func(*QQClient, *msg.Message, *incomingPacketInfo), decoderType uint8) {
switch msgType { switch msgType {
case 9: case 9:
return privateMessageDecoder, privateMsgDecoders return privateMessageDecoder, privateMsgDecoders

View File

@ -3,29 +3,28 @@ package client
import ( import (
"crypto/md5" "crypto/md5"
"fmt" "fmt"
"math"
"math/rand" "math/rand"
"net/netip" "net"
"sort" "sort"
"strconv"
"sync" "sync"
"sync/atomic" "sync/atomic"
"time" "time"
"github.com/Mrs4s/MiraiGo/internal/crypto"
packets2 "github.com/Mrs4s/MiraiGo/internal/packets"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/RomiChan/syncx"
"github.com/Mrs4s/MiraiGo/binary" "github.com/Mrs4s/MiraiGo/binary"
"github.com/Mrs4s/MiraiGo/client/internal/auth" "github.com/Mrs4s/MiraiGo/binary/jce"
"github.com/Mrs4s/MiraiGo/client/internal/highway" "github.com/Mrs4s/MiraiGo/internal/protobuf/data/msg"
"github.com/Mrs4s/MiraiGo/client/internal/intern"
"github.com/Mrs4s/MiraiGo/client/internal/network"
"github.com/Mrs4s/MiraiGo/client/internal/oicq"
"github.com/Mrs4s/MiraiGo/client/pb/msg"
"github.com/Mrs4s/MiraiGo/message" "github.com/Mrs4s/MiraiGo/message"
"github.com/Mrs4s/MiraiGo/utils" "github.com/Mrs4s/MiraiGo/utils"
) )
//go:generate go run github.com/a8m/syncmap -o "handler_map_gen.go" -pkg client -name HandlerMap "map[uint16]*handlerInfo"
type QQClient struct { type QQClient struct {
Uin int64 Uin int64
PasswordMd5 [16]byte PasswordMd5 [16]byte
@ -34,97 +33,108 @@ type QQClient struct {
once sync.Once once sync.Once
// option // option
AllowSlider bool AllowSlider bool
UseFragmentMessage bool
// account info // account info
Online atomic.Bool
Nickname string Nickname string
Age uint16 Age uint16
Gender uint16 Gender uint16
FriendList []*FriendInfo FriendList []*FriendInfo
GroupList []*GroupInfo GroupList []*GroupInfo
OnlineClients []*OtherClientInfo OnlineClients []*OtherClientInfo
Online bool
QiDian *QiDianAccountInfo QiDian *QiDianAccountInfo
GuildService *GuildService GuildService *GuildService
// protocol public field // protocol public field
SequenceId atomic.Int32 SequenceId int32
SessionId []byte OutGoingPacketSessionId []byte
TCP *network.TCPClient // todo: combine other protocol state into one struct RandomKey []byte
ConnectTime time.Time TCP *utils.TCPListener
ConnectTime time.Time
transport *network.Transport
oicq *oicq.Codec
logger Logger
// internal state // internal state
handlers syncx.Map[uint16, *handlerInfo] handlers HandlerMap
waiters syncx.Map[string, func(any, error)] waiters sync.Map
initServerOnce sync.Once servers []*net.TCPAddr
servers []netip.AddrPort
currServerIndex int currServerIndex int
retryTimes int retryTimes int
version *versionInfo
deviceInfo *DeviceInfo
alive bool alive bool
ecdh *crypto.EncryptECDH
// tlv cache
t104 []byte
t174 []byte
g []byte
t402 []byte
t150 []byte
t149 []byte
t528 []byte
t530 []byte
randSeed []byte // t403
rollbackSig []byte
// sync info
syncCookie []byte
pubAccountCookie []byte
msgCtrlBuf []byte
ksid []byte
// session info // session info
qwebSeq atomic.Int64 sigInfo *loginSigInfo
sig *auth.SigInfo bigDataSession *bigDataSessionInfo
highwaySession *highway.Session dpwd []byte
// pwdFlag bool timeDiff int64
// timeDiff int64 pwdFlag bool
// address // address
// otherSrvAddrs []string srvSsoAddrs []string
// fileStorageInfo *jce.FileStoragePushFSSvcList otherSrvAddrs []string
fileStorageInfo *jce.FileStoragePushFSSvcList
// event handles
eventHandlers eventHandlers
PrivateMessageEvent EventHandle[*message.PrivateMessage]
TempMessageEvent EventHandle[*TempMessageEvent]
GroupMessageEvent EventHandle[*message.GroupMessage]
SelfPrivateMessageEvent EventHandle[*message.PrivateMessage]
SelfGroupMessageEvent EventHandle[*message.GroupMessage]
GroupMuteEvent EventHandle[*GroupMuteEvent]
GroupMessageRecalledEvent EventHandle[*GroupMessageRecalledEvent]
FriendMessageRecalledEvent EventHandle[*FriendMessageRecalledEvent]
GroupJoinEvent EventHandle[*GroupInfo]
GroupLeaveEvent EventHandle[*GroupLeaveEvent]
GroupMemberJoinEvent EventHandle[*MemberJoinGroupEvent]
GroupMemberLeaveEvent EventHandle[*MemberLeaveGroupEvent]
MemberCardUpdatedEvent EventHandle[*MemberCardUpdatedEvent]
GroupNameUpdatedEvent EventHandle[*GroupNameUpdatedEvent]
GroupMemberPermissionChangedEvent EventHandle[*MemberPermissionChangedEvent]
GroupInvitedEvent EventHandle[*GroupInvitedRequest]
UserWantJoinGroupEvent EventHandle[*UserJoinGroupRequest]
NewFriendEvent EventHandle[*NewFriendEvent]
NewFriendRequestEvent EventHandle[*NewFriendRequest]
DisconnectedEvent EventHandle[*ClientDisconnectedEvent]
GroupNotifyEvent EventHandle[INotifyEvent]
FriendNotifyEvent EventHandle[INotifyEvent]
MemberSpecialTitleUpdatedEvent EventHandle[*MemberSpecialTitleUpdatedEvent]
GroupDigestEvent EventHandle[*GroupDigestEvent]
OtherClientStatusChangedEvent EventHandle[*OtherClientStatusChangedEvent]
OfflineFileEvent EventHandle[*OfflineFileEvent]
GroupDisbandEvent EventHandle[*GroupDisbandEvent]
DeleteFriendEvent EventHandle[*DeleteFriendEvent]
// message state // message state
msgSvcCache *utils.Cache[unit] lastMessageSeq int32
msgSvcCache *utils.Cache
lastC2CMsgTime int64 lastC2CMsgTime int64
transCache *utils.Cache[unit] transCache *utils.Cache
lastLostMsg string
groupSysMsgCache *GroupSystemMessages groupSysMsgCache *GroupSystemMessages
msgBuilders syncx.Map[int32, *messageBuilder] groupMsgBuilders sync.Map
onlinePushCache *utils.Cache[unit] onlinePushCache *utils.Cache
requestPacketRequestID int32
groupSeq int32
friendSeq int32
heartbeatEnabled bool heartbeatEnabled bool
requestPacketRequestID atomic.Int32 groupDataTransSeq int32
groupSeq atomic.Int32 highwayApplyUpSeq int32
friendSeq atomic.Int32 eventHandlers *eventHandlers
highwayApplyUpSeq atomic.Int32
groupListLock sync.Mutex groupListLock sync.Mutex
} }
type loginSigInfo struct {
loginBitmap uint64
tgt []byte
tgtKey []byte
srmToken []byte // study room manager | 0x16a
t133 []byte
encryptedA1 []byte
userStKey []byte
userStWebSig []byte
sKey []byte
sKeyExpiredTime int64
d2 []byte
d2Key []byte
wtSessionTicketKey []byte
deviceToken []byte
psKeyMap map[string][]byte
pt4TokenMap map[string][]byte
}
type QiDianAccountInfo struct { type QiDianAccountInfo struct {
MasterUin int64 MasterUin int64
ExtName string ExtName string
@ -135,19 +145,12 @@ type QiDianAccountInfo struct {
} }
type handlerInfo struct { type handlerInfo struct {
fun func(i any, err error) fun func(i interface{}, err error)
dynamic bool dynamic bool
params network.RequestParams params requestParams
} }
func (h *handlerInfo) getParams() network.RequestParams { var decoders = map[string]func(*QQClient, *incomingPacketInfo, []byte) (interface{}, error){
if h == nil {
return nil
}
return h.params
}
var decoders = map[string]func(*QQClient, *network.Packet) (any, error){
"wtlogin.login": decodeLoginResponse, "wtlogin.login": decodeLoginResponse,
"wtlogin.exchange_emp": decodeExchangeEmpResponse, "wtlogin.exchange_emp": decodeExchangeEmpResponse,
"wtlogin.trans_emp": decodeTransEmpResponse, "wtlogin.trans_emp": decodeTransEmpResponse,
@ -156,7 +159,6 @@ var decoders = map[string]func(*QQClient, *network.Packet) (any, error){
"MessageSvc.PushNotify": decodeSvcNotify, "MessageSvc.PushNotify": decodeSvcNotify,
"OnlinePush.ReqPush": decodeOnlinePushReqPacket, "OnlinePush.ReqPush": decodeOnlinePushReqPacket,
"OnlinePush.PbPushTransMsg": decodeOnlinePushTransPacket, "OnlinePush.PbPushTransMsg": decodeOnlinePushTransPacket,
"OnlinePush.SidTicketExpired": decodeSidExpiredPacket,
"ConfigPushSvc.PushReq": decodePushReqPacket, "ConfigPushSvc.PushReq": decodePushReqPacket,
"MessageSvc.PbGetMsg": decodeMessageSvcPacket, "MessageSvc.PbGetMsg": decodeMessageSvcPacket,
"MessageSvc.PushForceOffline": decodeForceOfflinePacket, "MessageSvc.PushForceOffline": decodeForceOfflinePacket,
@ -166,12 +168,18 @@ var decoders = map[string]func(*QQClient, *network.Packet) (any, error){
"friendlist.GetTroopListReqV2": decodeGroupListResponse, "friendlist.GetTroopListReqV2": decodeGroupListResponse,
"friendlist.GetTroopMemberListReq": decodeGroupMemberListResponse, "friendlist.GetTroopMemberListReq": decodeGroupMemberListResponse,
"group_member_card.get_group_member_card_info": decodeGroupMemberInfoResponse, "group_member_card.get_group_member_card_info": decodeGroupMemberInfoResponse,
"PttStore.GroupPttUp": decodeGroupPttStoreResponse,
"LongConn.OffPicUp": decodeOffPicUpResponse, "LongConn.OffPicUp": decodeOffPicUpResponse,
"ProfileService.Pb.ReqSystemMsgNew.Group": decodeSystemMsgGroupPacket, "ProfileService.Pb.ReqSystemMsgNew.Group": decodeSystemMsgGroupPacket,
"ProfileService.Pb.ReqSystemMsgNew.Friend": decodeSystemMsgFriendPacket, "ProfileService.Pb.ReqSystemMsgNew.Friend": decodeSystemMsgFriendPacket,
"OidbSvc.0xd79": decodeWordSegmentation, "OidbSvc.0xd79": decodeWordSegmentation,
"OidbSvc.0x990": decodeTranslateResponse, "OidbSvc.0x990": decodeTranslateResponse,
"SummaryCard.ReqSummaryCard": decodeSummaryCardResponse, "SummaryCard.ReqSummaryCard": decodeSummaryCardResponse,
"LightAppSvc.mini_app_info.GetAppInfoById": decodeAppInfoResponse,
}
func init() {
rand.Seed(time.Now().UTC().UnixNano())
} }
// NewClient create new qq client // NewClient create new qq client
@ -180,58 +188,94 @@ func NewClient(uin int64, password string) *QQClient {
} }
func NewClientEmpty() *QQClient { func NewClientEmpty() *QQClient {
return NewClientMd5(0, [16]byte{}) return NewClient(0, "")
} }
func NewClientMd5(uin int64, passwordMd5 [16]byte) *QQClient { func NewClientMd5(uin int64, passwordMd5 [16]byte) *QQClient {
cli := &QQClient{ cli := &QQClient{
Uin: uin, Uin: uin,
PasswordMd5: passwordMd5, PasswordMd5: passwordMd5,
AllowSlider: true, SequenceId: 0x3635,
TCP: &network.TCPClient{}, AllowSlider: true,
sig: &auth.SigInfo{ RandomKey: make([]byte, 16),
OutPacketSessionID: []byte{0x02, 0xB0, 0x5B, 0x8B}, OutGoingPacketSessionId: []byte{0x02, 0xB0, 0x5B, 0x8B},
}, TCP: &utils.TCPListener{},
msgSvcCache: utils.NewCache[unit](time.Second * 15), sigInfo: &loginSigInfo{},
transCache: utils.NewCache[unit](time.Second * 15), requestPacketRequestID: 1921334513,
onlinePushCache: utils.NewCache[unit](time.Second * 15), groupSeq: int32(rand.Intn(20000)),
alive: true, friendSeq: 22911,
highwaySession: new(highway.Session), highwayApplyUpSeq: 77918,
eventHandlers: &eventHandlers{},
msgSvcCache: utils.NewCache(time.Second * 15),
transCache: utils.NewCache(time.Second * 15),
onlinePushCache: utils.NewCache(time.Second * 15),
servers: []*net.TCPAddr{},
alive: true,
ecdh: crypto.NewEcdh(),
} }
cli.transport = &network.Transport{Sig: cli.sig}
cli.oicq = oicq.NewCodec(cli.Uin)
{ // init atomic values
cli.SequenceId.Store(int32(rand.Intn(100000)))
cli.requestPacketRequestID.Store(1921334513)
cli.groupSeq.Store(int32(rand.Intn(20000)))
cli.friendSeq.Store(22911)
cli.highwayApplyUpSeq.Store(77918)
}
cli.highwaySession.Uin = strconv.FormatInt(cli.Uin, 10)
cli.GuildService = &GuildService{c: cli} cli.GuildService = &GuildService{c: cli}
cli.ecdh.FetchPubKey(uin)
cli.UseDevice(SystemDeviceInfo)
sso, err := getSSOAddress()
if err == nil && len(sso) > 0 {
cli.servers = append(sso, cli.servers...)
}
adds, err := net.LookupIP("msfwifi.3g.qq.com") // host servers
if err == nil && len(adds) > 0 {
var hostAddrs []*net.TCPAddr
for _, addr := range adds {
hostAddrs = append(hostAddrs, &net.TCPAddr{
IP: addr,
Port: 8080,
})
}
cli.servers = append(hostAddrs, cli.servers...)
}
if len(cli.servers) == 0 {
cli.servers = []*net.TCPAddr{ // default servers
{IP: net.IP{42, 81, 172, 81}, Port: 80},
{IP: net.IP{114, 221, 148, 59}, Port: 14000},
{IP: net.IP{42, 81, 172, 147}, Port: 443},
{IP: net.IP{125, 94, 60, 146}, Port: 80},
{IP: net.IP{114, 221, 144, 215}, Port: 80},
{IP: net.IP{42, 81, 172, 22}, Port: 80},
}
}
pings := make([]int64, len(cli.servers))
wg := sync.WaitGroup{}
wg.Add(len(cli.servers))
for i := range cli.servers {
go func(index int) {
defer wg.Done()
p, err := qualityTest(cli.servers[index].String())
if err != nil {
pings[index] = 9999
return
}
pings[index] = p
}(i)
}
wg.Wait()
sort.Slice(cli.servers, func(i, j int) bool {
return pings[i] < pings[j]
})
if len(cli.servers) > 3 {
cli.servers = cli.servers[0 : len(cli.servers)/2] // 保留ping值中位数以上的server
}
cli.TCP.PlannedDisconnect(cli.plannedDisconnect) cli.TCP.PlannedDisconnect(cli.plannedDisconnect)
cli.TCP.UnexpectedDisconnect(cli.unexpectedDisconnect) cli.TCP.UnexpectedDisconnect(cli.unexpectedDisconnect)
rand.Read(cli.RandomKey)
return cli return cli
} }
func (c *QQClient) version() *auth.AppVersion { func (c *QQClient) UseDevice(info *DeviceInfo) {
return c.transport.Version c.version = genVersionInfo(info.Protocol)
} c.ksid = []byte(fmt.Sprintf("|%s|A8.2.7.27f6ea96", info.IMEI))
c.deviceInfo = info
func (c *QQClient) Device() *DeviceInfo {
return c.transport.Device
}
func (c *QQClient) UseDevice(info *auth.Device) {
c.transport.Version = info.Protocol.Version()
c.transport.Device = info
c.highwaySession.AppID = int32(c.version().AppId)
c.sig.Ksid = []byte(fmt.Sprintf("|%s|A8.2.7.27f6ea96", info.IMEI))
} }
func (c *QQClient) Release() { func (c *QQClient) Release() {
if c.Online.Load() { if c.Online {
c.Disconnect() c.Disconnect()
} }
c.alive = false c.alive = false
@ -239,7 +283,7 @@ func (c *QQClient) Release() {
// Login send login request // Login send login request
func (c *QQClient) Login() (*LoginResponse, error) { func (c *QQClient) Login() (*LoginResponse, error) {
if c.Online.Load() { if c.Online {
return nil, ErrAlreadyOnline return nil, ErrAlreadyOnline
} }
err := c.connect() err := c.connect()
@ -253,13 +297,13 @@ func (c *QQClient) Login() (*LoginResponse, error) {
} }
l := rsp.(LoginResponse) l := rsp.(LoginResponse)
if l.Success { if l.Success {
err = c.init(false) _ = c.init(false)
} }
return &l, err return &l, nil
} }
func (c *QQClient) TokenLogin(token []byte) error { func (c *QQClient) TokenLogin(token []byte) error {
if c.Online.Load() { if c.Online {
return ErrAlreadyOnline return ErrAlreadyOnline
} }
err := c.connect() err := c.connect()
@ -269,18 +313,18 @@ func (c *QQClient) TokenLogin(token []byte) error {
{ {
r := binary.NewReader(token) r := binary.NewReader(token)
c.Uin = r.ReadInt64() c.Uin = r.ReadInt64()
c.sig.D2 = r.ReadBytesShort() c.sigInfo.d2 = r.ReadBytesShort()
c.sig.D2Key = r.ReadBytesShort() c.sigInfo.d2Key = r.ReadBytesShort()
c.sig.TGT = r.ReadBytesShort() c.sigInfo.tgt = r.ReadBytesShort()
c.sig.SrmToken = r.ReadBytesShort() c.sigInfo.srmToken = r.ReadBytesShort()
c.sig.T133 = r.ReadBytesShort() c.sigInfo.t133 = r.ReadBytesShort()
c.sig.EncryptedA1 = r.ReadBytesShort() c.sigInfo.encryptedA1 = r.ReadBytesShort()
c.oicq.WtSessionTicketKey = r.ReadBytesShort() c.sigInfo.wtSessionTicketKey = r.ReadBytesShort()
c.sig.OutPacketSessionID = r.ReadBytesShort() c.OutGoingPacketSessionId = r.ReadBytesShort()
// SystemDeviceInfo.TgtgtKey = r.ReadBytesShort() // SystemDeviceInfo.TgtgtKey = r.ReadBytesShort()
c.Device().TgtgtKey = r.ReadBytesShort() c.deviceInfo.TgtgtKey = r.ReadBytesShort()
} }
_, err = c.sendAndWait(c.buildRequestChangeSigPacket(true)) _, err = c.sendAndWait(c.buildRequestChangeSigPacket())
if err != nil { if err != nil {
return err return err
} }
@ -288,18 +332,14 @@ func (c *QQClient) TokenLogin(token []byte) error {
} }
func (c *QQClient) FetchQRCode() (*QRCodeLoginResponse, error) { func (c *QQClient) FetchQRCode() (*QRCodeLoginResponse, error) {
return c.FetchQRCodeCustomSize(3, 4, 2) if c.Online {
}
func (c *QQClient) FetchQRCodeCustomSize(size, margin, ecLevel uint32) (*QRCodeLoginResponse, error) {
if c.Online.Load() {
return nil, ErrAlreadyOnline return nil, ErrAlreadyOnline
} }
err := c.connect() err := c.connect()
if err != nil { if err != nil {
return nil, err return nil, err
} }
i, err := c.sendAndWait(c.buildQRCodeFetchRequestPacket(size, margin, ecLevel)) i, err := c.sendAndWait(c.buildQRCodeFetchRequestPacket())
if err != nil { if err != nil {
return nil, errors.Wrap(err, "fetch qrcode error") return nil, errors.Wrap(err, "fetch qrcode error")
} }
@ -321,9 +361,9 @@ func (c *QQClient) QRCodeLogin(info *QRCodeLoginInfo) (*LoginResponse, error) {
} }
rsp := i.(LoginResponse) rsp := i.(LoginResponse)
if rsp.Success { if rsp.Success {
err = c.init(false) _ = c.init(false)
} }
return &rsp, err return &rsp, nil
} }
// SubmitCaptcha send captcha to server // SubmitCaptcha send captcha to server
@ -336,9 +376,9 @@ func (c *QQClient) SubmitCaptcha(result string, sign []byte) (*LoginResponse, er
} }
l := rsp.(LoginResponse) l := rsp.(LoginResponse)
if l.Success { if l.Success {
err = c.init(false) _ = c.init(false)
} }
return &l, err return &l, nil
} }
func (c *QQClient) SubmitTicket(ticket string) (*LoginResponse, error) { func (c *QQClient) SubmitTicket(ticket string) (*LoginResponse, error) {
@ -350,9 +390,9 @@ func (c *QQClient) SubmitTicket(ticket string) (*LoginResponse, error) {
} }
l := rsp.(LoginResponse) l := rsp.(LoginResponse)
if l.Success { if l.Success {
err = c.init(false) _ = c.init(false)
} }
return &l, err return &l, nil
} }
func (c *QQClient) SubmitSMS(code string) (*LoginResponse, error) { func (c *QQClient) SubmitSMS(code string) (*LoginResponse, error) {
@ -363,34 +403,33 @@ func (c *QQClient) SubmitSMS(code string) (*LoginResponse, error) {
} }
l := rsp.(LoginResponse) l := rsp.(LoginResponse)
if l.Success { if l.Success {
err = c.init(false) _ = c.init(false)
} }
return &l, err return &l, nil
} }
func (c *QQClient) RequestSMS() bool { func (c *QQClient) RequestSMS() bool {
rsp, err := c.sendAndWait(c.buildSMSRequestPacket()) rsp, err := c.sendAndWait(c.buildSMSRequestPacket())
if err != nil { if err != nil {
c.error("request sms error: %v", err) c.Error("request sms error: %v", err)
return false return false
} }
return rsp.(LoginResponse).Error == SMSNeededError return rsp.(LoginResponse).Error == SMSNeededError
} }
func (c *QQClient) init(tokenLogin bool) error { func (c *QQClient) init(tokenLogin bool) error {
if len(c.sig.G) == 0 { if len(c.g) == 0 {
c.warning("device lock is disabled. HTTP API may fail.") c.Warning("device lock is disable. http api may fail.")
} }
c.highwaySession.Uin = strconv.FormatInt(c.Uin, 10)
if err := c.registerClient(); err != nil { if err := c.registerClient(); err != nil {
return errors.Wrap(err, "register error") return errors.Wrap(err, "register error")
} }
if tokenLogin { if tokenLogin {
notify := make(chan struct{}, 2) notify := make(chan struct{})
d := c.waitPacket("StatSvc.ReqMSFOffline", func(i any, err error) { d := c.waitPacket("StatSvc.ReqMSFOffline", func(i interface{}, err error) {
notify <- struct{}{} notify <- struct{}{}
}) })
d2 := c.waitPacket("MessageSvc.PushForceOffline", func(i any, err error) { d2 := c.waitPacket("MessageSvc.PushForceOffline", func(i interface{}, err error) {
notify <- struct{}{} notify <- struct{}{}
}) })
select { select {
@ -408,12 +447,12 @@ func (c *QQClient) init(tokenLogin bool) error {
go c.doHeartbeat() go c.doHeartbeat()
} }
_ = c.RefreshStatus() _ = c.RefreshStatus()
if c.version().Protocol == auth.QiDian { if c.version.Protocol == QiDian {
_, _ = c.sendAndWait(c.buildLoginExtraPacket()) // 小登录 _, _ = c.sendAndWait(c.buildLoginExtraPacket()) // 小登录
_, _ = c.sendAndWait(c.buildConnKeyRequestPacket()) // big data key 如果等待 config push 的话时间来不及 _, _ = c.sendAndWait(c.buildConnKeyRequestPacket()) // big data key 如果等待 config push 的话时间来不及
} }
seq, pkt := c.buildGetMessageRequestPacket(msg.SyncFlag_START, time.Now().Unix()) seq, pkt := c.buildGetMessageRequestPacket(msg.SyncFlag_START, time.Now().Unix())
_, _ = c.sendAndWait(seq, pkt, network.RequestParams{"used_reg_proxy": true, "init": true}) _, _ = c.sendAndWait(seq, pkt, requestParams{"used_reg_proxy": true, "init": true})
c.syncChannelFirstView() c.syncChannelFirstView()
return nil return nil
} }
@ -421,15 +460,15 @@ func (c *QQClient) init(tokenLogin bool) error {
func (c *QQClient) GenToken() []byte { func (c *QQClient) GenToken() []byte {
return binary.NewWriterF(func(w *binary.Writer) { return binary.NewWriterF(func(w *binary.Writer) {
w.WriteUInt64(uint64(c.Uin)) w.WriteUInt64(uint64(c.Uin))
w.WriteBytesShort(c.sig.D2) w.WriteBytesShort(c.sigInfo.d2)
w.WriteBytesShort(c.sig.D2Key) w.WriteBytesShort(c.sigInfo.d2Key)
w.WriteBytesShort(c.sig.TGT) w.WriteBytesShort(c.sigInfo.tgt)
w.WriteBytesShort(c.sig.SrmToken) w.WriteBytesShort(c.sigInfo.srmToken)
w.WriteBytesShort(c.sig.T133) w.WriteBytesShort(c.sigInfo.t133)
w.WriteBytesShort(c.sig.EncryptedA1) w.WriteBytesShort(c.sigInfo.encryptedA1)
w.WriteBytesShort(c.oicq.WtSessionTicketKey) w.WriteBytesShort(c.sigInfo.wtSessionTicketKey)
w.WriteBytesShort(c.sig.OutPacketSessionID) w.WriteBytesShort(c.OutGoingPacketSessionId)
w.WriteBytesShort(c.Device().TgtgtKey) w.WriteBytesShort(c.deviceInfo.TgtgtKey)
}) })
} }
@ -478,7 +517,7 @@ func (c *QQClient) ReloadFriendList() error {
// 当使用普通QQ时: 请求好友列表 // 当使用普通QQ时: 请求好友列表
// 当使用企点QQ时: 请求外部联系人列表 // 当使用企点QQ时: 请求外部联系人列表
func (c *QQClient) GetFriendList() (*FriendListResponse, error) { func (c *QQClient) GetFriendList() (*FriendListResponse, error) {
if c.version().Protocol == auth.QiDian { if c.version.Protocol == QiDian {
rsp, err := c.getQiDianAddressDetailList() rsp, err := c.getQiDianAddressDetailList()
if err != nil { if err != nil {
return nil, err return nil, err
@ -503,6 +542,71 @@ func (c *QQClient) GetFriendList() (*FriendListResponse, error) {
return r, nil return r, nil
} }
func (c *QQClient) GetForwardMessage(resID string) *message.ForwardMessage {
m := c.DownloadForwardMessage(resID)
if m == nil {
return nil
}
var (
item *msg.PbMultiMsgItem
ret = &message.ForwardMessage{Nodes: []*message.ForwardNode{}}
)
for _, iter := range m.Items {
if iter.GetFileName() == m.FileName {
item = iter
}
}
if item == nil || item.Buffer == nil {
return nil
}
for _, m := range item.Buffer.Msg {
ret.Nodes = append(ret.Nodes, &message.ForwardNode{
SenderId: m.Head.GetFromUin(),
SenderName: func() string {
if m.Head.GetMsgType() == 82 && m.Head.GroupInfo != nil {
return m.Head.GroupInfo.GetGroupCard()
}
return m.Head.GetFromNick()
}(),
Time: m.Head.GetMsgTime(),
Message: message.ParseMessageElems(m.Body.RichText.Elems),
})
}
return ret
}
func (c *QQClient) DownloadForwardMessage(resId string) *message.ForwardElement {
i, err := c.sendAndWait(c.buildMultiApplyDownPacket(resId))
if err != nil {
return nil
}
multiMsg := i.(*msg.PbMultiMsgTransmit)
if multiMsg.PbItemList == nil {
return nil
}
var pv string
for i := 0; i < int(math.Min(4, float64(len(multiMsg.Msg)))); i++ {
m := multiMsg.Msg[i]
pv += fmt.Sprintf(`<title size="26" color="#777777">%s: %s</title>`,
func() string {
if m.Head.GetMsgType() == 82 && m.Head.GroupInfo != nil {
return m.Head.GroupInfo.GetGroupCard()
}
return m.Head.GetFromNick()
}(),
message.ToReadableString(
message.ParseMessageElems(multiMsg.Msg[i].Body.RichText.Elems),
),
)
}
return genForwardTemplate(
resId, pv, "群聊的聊天记录", "[聊天记录]", "聊天记录",
fmt.Sprintf("查看 %d 条转发消息", len(multiMsg.Msg)),
time.Now().UnixNano(),
multiMsg.PbItemList,
)
}
func (c *QQClient) SendGroupPoke(groupCode, target int64) { func (c *QQClient) SendGroupPoke(groupCode, target int64) {
_, _ = c.sendAndWait(c.buildGroupPokePacket(groupCode, target)) _, _ = c.sendAndWait(c.buildGroupPokePacket(groupCode, target))
} }
@ -527,7 +631,6 @@ func (c *QQClient) GetGroupList() ([]*GroupInfo, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
interner := intern.NewStringInterner()
r := rsp.([]*GroupInfo) r := rsp.([]*GroupInfo)
wg := sync.WaitGroup{} wg := sync.WaitGroup{}
batch := 50 batch := 50
@ -540,12 +643,11 @@ func (c *QQClient) GetGroupList() ([]*GroupInfo, error) {
for j := i; j < k; j++ { for j := i; j < k; j++ {
go func(g *GroupInfo, wg *sync.WaitGroup) { go func(g *GroupInfo, wg *sync.WaitGroup) {
defer wg.Done() defer wg.Done()
m, err := c.getGroupMembers(g, interner) m, err := c.GetGroupMembers(g)
if err != nil { if err != nil {
return return
} }
g.Members = m g.Members = m
g.Name = interner.Intern(g.Name)
}(r[j], &wg) }(r[j], &wg)
} }
wg.Wait() wg.Wait()
@ -554,11 +656,6 @@ func (c *QQClient) GetGroupList() ([]*GroupInfo, error) {
} }
func (c *QQClient) GetGroupMembers(group *GroupInfo) ([]*GroupMemberInfo, error) { func (c *QQClient) GetGroupMembers(group *GroupInfo) ([]*GroupMemberInfo, error) {
interner := intern.NewStringInterner()
return c.getGroupMembers(group, interner)
}
func (c *QQClient) getGroupMembers(group *GroupInfo, interner *intern.StringInterner) ([]*GroupMemberInfo, error) {
var nextUin int64 var nextUin int64
var list []*GroupMemberInfo var list []*GroupMemberInfo
for { for {
@ -567,7 +664,7 @@ func (c *QQClient) getGroupMembers(group *GroupInfo, interner *intern.StringInte
return nil, err return nil, err
} }
if data == nil { if data == nil {
return nil, errors.New("group members list is unavailable: rsp is nil") return nil, errors.New("group member list unavailable: rsp is nil")
} }
rsp := data.(*groupMemberListResponse) rsp := data.(*groupMemberListResponse)
nextUin = rsp.NextUin nextUin = rsp.NextUin
@ -576,9 +673,6 @@ func (c *QQClient) getGroupMembers(group *GroupInfo, interner *intern.StringInte
if m.Uin == group.OwnerUin { if m.Uin == group.OwnerUin {
m.Permission = Owner m.Permission = Owner
} }
m.CardName = interner.Intern(m.CardName)
m.Nickname = interner.Intern(m.Nickname)
m.SpecialTitle = interner.Intern(m.SpecialTitle)
} }
list = append(list, rsp.list...) list = append(list, rsp.list...)
if nextUin == 0 { if nextUin == 0 {
@ -599,12 +693,6 @@ func (c *QQClient) GetMemberInfo(groupCode, memberUin int64) (*GroupMemberInfo,
} }
func (c *QQClient) FindFriend(uin int64) *FriendInfo { func (c *QQClient) FindFriend(uin int64) *FriendInfo {
if uin == c.Uin {
return &FriendInfo{
Uin: uin,
Nickname: c.Nickname,
}
}
for _, t := range c.FriendList { for _, t := range c.FriendList {
f := t f := t
if f.Uin == uin { if f.Uin == uin {
@ -641,7 +729,7 @@ func (c *QQClient) FindGroup(code int64) *GroupInfo {
return nil return nil
} }
func (c *QQClient) SolveGroupJoinRequest(i any, accept, block bool, reason string) { func (c *QQClient) SolveGroupJoinRequest(i interface{}, accept, block bool, reason string) {
if accept { if accept {
block = false block = false
reason = "" reason = ""
@ -669,11 +757,11 @@ func (c *QQClient) SolveFriendRequest(req *NewFriendRequest, accept bool) {
} }
func (c *QQClient) getSKey() string { func (c *QQClient) getSKey() string {
if c.sig.SKeyExpiredTime < time.Now().Unix() && len(c.sig.G) > 0 { if c.sigInfo.sKeyExpiredTime < time.Now().Unix() && len(c.g) > 0 {
c.debug("skey expired. refresh...") c.Debug("skey expired. refresh...")
_, _ = c.sendAndWait(c.buildRequestTgtgtNopicsigPacket()) _, _ = c.sendAndWait(c.buildRequestTgtgtNopicsigPacket())
} }
return string(c.sig.SKey) return string(c.sigInfo.sKey)
} }
func (c *QQClient) getCookies() string { func (c *QQClient) getCookies() string {
@ -683,7 +771,7 @@ func (c *QQClient) getCookies() string {
func (c *QQClient) getCookiesWithDomain(domain string) string { func (c *QQClient) getCookiesWithDomain(domain string) string {
cookie := c.getCookies() cookie := c.getCookies()
if psKey, ok := c.sig.PsKeyMap[domain]; ok { if psKey, ok := c.sigInfo.psKeyMap[domain]; ok {
return fmt.Sprintf("%s p_uin=o%d; p_skey=%s;", cookie, c.Uin, psKey) return fmt.Sprintf("%s p_uin=o%d; p_skey=%s;", cookie, c.Uin, psKey)
} else { } else {
return cookie return cookie
@ -714,6 +802,10 @@ func (c *QQClient) updateGroupName(groupCode int64, newName string) {
_, _ = c.sendAndWait(c.buildGroupNameUpdatePacket(groupCode, newName)) _, _ = c.sendAndWait(c.buildGroupNameUpdatePacket(groupCode, newName))
} }
func (c *QQClient) updateGroupMemo(groupCode int64, newMemo string) {
_, _ = c.sendAndWait(c.buildGroupMemoUpdatePacket(groupCode, newMemo))
}
func (c *QQClient) groupMuteAll(groupCode int64, mute bool) { func (c *QQClient) groupMuteAll(groupCode int64, mute bool) {
_, _ = c.sendAndWait(c.buildGroupMuteAllPacket(groupCode, mute)) _, _ = c.sendAndWait(c.buildGroupMuteAllPacket(groupCode, mute))
} }
@ -726,8 +818,8 @@ func (c *QQClient) quitGroup(groupCode int64) {
_, _ = c.sendAndWait(c.buildQuitGroupPacket(groupCode)) _, _ = c.sendAndWait(c.buildQuitGroupPacket(groupCode))
} }
func (c *QQClient) KickGroupMembers(groupCode int64, msg string, block bool, memberUins ...int64) { func (c *QQClient) kickGroupMember(groupCode, memberUin int64, msg string, block bool) {
_, _ = c.sendAndWait(c.buildGroupKickPacket(groupCode, msg, block, memberUins...)) _, _ = c.sendAndWait(c.buildGroupKickPacket(groupCode, memberUin, msg, block))
} }
func (g *GroupInfo) removeMember(uin int64) { func (g *GroupInfo) removeMember(uin int64) {
@ -742,73 +834,59 @@ func (g *GroupInfo) removeMember(uin int64) {
}) })
} }
func (c *QQClient) setGroupAnonymous(groupCode int64, enable bool) { func (c *QQClient) SetCustomServer(servers []*net.TCPAddr) {
_, _ = c.sendAndWait(c.buildSetGroupAnonymous(groupCode, enable))
}
// UpdateProfile 修改个人资料
func (c *QQClient) UpdateProfile(profile ProfileDetailUpdate) {
_, _ = c.sendAndWait(c.buildUpdateProfileDetailPacket(profile))
}
func (c *QQClient) SetCustomServer(servers []netip.AddrPort) {
c.servers = append(servers, c.servers...) c.servers = append(servers, c.servers...)
} }
/*
func (c *QQClient) SendGroupGift(groupCode, uin uint64, gift message.GroupGift) {
_, packet := c.sendGroupGiftPacket(groupCode, uin, gift)
_ = c.sendPacket(packet)
}
*/
func (c *QQClient) registerClient() error { func (c *QQClient) registerClient() error {
_, err := c.sendAndWait(c.buildClientRegisterPacket()) _, err := c.sendAndWait(c.buildClientRegisterPacket())
if err == nil { if err == nil {
c.Online.Store(true) c.Online = true
} }
return err return err
} }
func (c *QQClient) nextSeq() uint16 { func (c *QQClient) nextSeq() uint16 {
seq := c.SequenceId.Add(1) return uint16(atomic.AddInt32(&c.SequenceId, 1) & 0x7FFF)
if seq > 1000000 {
seq = int32(rand.Intn(100000)) + 60000
c.SequenceId.Store(seq)
}
return uint16(seq)
} }
func (c *QQClient) nextPacketSeq() int32 { func (c *QQClient) nextPacketSeq() int32 {
return c.requestPacketRequestID.Add(2) return atomic.AddInt32(&c.requestPacketRequestID, 2)
} }
func (c *QQClient) nextGroupSeq() int32 { func (c *QQClient) nextGroupSeq() int32 {
return c.groupSeq.Add(2) return atomic.AddInt32(&c.groupSeq, 2)
} }
func (c *QQClient) nextFriendSeq() int32 { func (c *QQClient) nextFriendSeq() int32 {
return c.friendSeq.Add(1) return atomic.AddInt32(&c.friendSeq, 1)
} }
func (c *QQClient) nextQWebSeq() int64 { func (c *QQClient) nextGroupDataTransSeq() int32 {
return c.qwebSeq.Add(1) return atomic.AddInt32(&c.groupDataTransSeq, 2)
} }
func (c *QQClient) nextHighwayApplySeq() int32 { func (c *QQClient) nextHighwayApplySeq() int32 {
return c.highwayApplyUpSeq.Add(2) return atomic.AddInt32(&c.highwayApplyUpSeq, 2)
} }
func (c *QQClient) doHeartbeat() { func (c *QQClient) doHeartbeat() {
c.heartbeatEnabled = true c.heartbeatEnabled = true
times := 0 times := 0
for c.Online.Load() { for c.Online {
time.Sleep(time.Second * 30) time.Sleep(time.Second * 30)
seq := c.nextSeq() seq := c.nextSeq()
req := network.Request{ sso := packets2.BuildSsoPacket(seq, c.version.AppId, c.version.SubAppId, "Heartbeat.Alive", c.deviceInfo.IMEI, []byte{}, c.OutGoingPacketSessionId, []byte{}, c.ksid)
Type: network.RequestTypeLogin, packet := packets2.BuildLoginPacket(c.Uin, 0, []byte{}, sso, []byte{})
EncryptType: network.EncryptTypeNoEncrypt,
SequenceID: int32(seq),
Uin: c.Uin,
CommandName: "Heartbeat.Alive",
Body: EmptyBytes,
}
packet := c.transport.PackPacket(&req)
_, err := c.sendAndWait(seq, packet) _, err := c.sendAndWait(seq, packet)
if errors.Is(err, network.ErrConnectionClosed) { if errors.Is(err, utils.ErrConnectionClosed) {
continue continue
} }
times++ times++

View File

@ -12,7 +12,7 @@ import (
"text/template" "text/template"
) )
const codeTemplate = `// Code generated by internal/generator/c2c_switcher DO NOT EDIT. const codeTemplate = `// Code generated by client/c2c_switcher.go DO NOT EDIT.
package client package client
@ -27,7 +27,7 @@ const (
{{end}} {{end}}
) )
func peekC2CDecoder(msgType int32) (decoder func(*QQClient, *msg.Message, network.RequestParams), decoderType uint8) { func peekC2CDecoder(msgType int32) (decoder func(*QQClient, *msg.Message, *incomingPacketInfo), decoderType uint8) {
switch msgType { switch msgType {
{{range .Decoders}} case {{.Id}}: {{range .Decoders}} case {{.Id}}:
return {{.Func}}, {{.DecoderType}} return {{.Func}}, {{.DecoderType}}
@ -93,9 +93,6 @@ func main() {
} }
} }
} }
sort.Slice(sf.Consts, func(i, j int) bool {
return sf.Consts[i] < sf.Consts[j]
})
sort.Sort(sf.Decoders) sort.Sort(sf.Decoders)
f, _ := os.OpenFile("c2c_switch.go", os.O_WRONLY|os.O_CREATE|os.O_SYNC|os.O_TRUNC, 0o644) f, _ := os.OpenFile("c2c_switch.go", os.O_WRONLY|os.O_CREATE|os.O_SYNC|os.O_TRUNC, 0o644)

View File

@ -2,28 +2,29 @@ package client
import ( import (
"crypto/md5" "crypto/md5"
"encoding/hex"
"fmt" "fmt"
"net/netip" "net"
"strconv" "strconv"
"strings" "strings"
"sync" "sync"
"time" "time"
"github.com/pkg/errors" "github.com/pkg/errors"
protobuf "github.com/segmentio/encoding/proto"
"google.golang.org/protobuf/proto"
"github.com/Mrs4s/MiraiGo/binary" "github.com/Mrs4s/MiraiGo/binary"
"github.com/Mrs4s/MiraiGo/binary/jce" "github.com/Mrs4s/MiraiGo/binary/jce"
"github.com/Mrs4s/MiraiGo/client/internal/auth"
"github.com/Mrs4s/MiraiGo/client/internal/network"
"github.com/Mrs4s/MiraiGo/client/internal/tlv"
"github.com/Mrs4s/MiraiGo/client/pb" "github.com/Mrs4s/MiraiGo/client/pb"
"github.com/Mrs4s/MiraiGo/client/pb/cmd0x352" "github.com/Mrs4s/MiraiGo/client/pb/cmd0x352"
"github.com/Mrs4s/MiraiGo/client/pb/cmd0x6ff" "github.com/Mrs4s/MiraiGo/client/pb/cmd0x6ff"
"github.com/Mrs4s/MiraiGo/client/pb/msg"
"github.com/Mrs4s/MiraiGo/client/pb/oidb"
"github.com/Mrs4s/MiraiGo/client/pb/profilecard" "github.com/Mrs4s/MiraiGo/client/pb/profilecard"
"github.com/Mrs4s/MiraiGo/client/pb/qweb"
"github.com/Mrs4s/MiraiGo/client/pb/structmsg" "github.com/Mrs4s/MiraiGo/client/pb/structmsg"
"github.com/Mrs4s/MiraiGo/internal/proto" "github.com/Mrs4s/MiraiGo/internal/protobuf/data/msg"
"github.com/Mrs4s/MiraiGo/internal/protobuf/data/oidb"
"github.com/Mrs4s/MiraiGo/internal/protobuf/data/oidb/oidb0xd79"
"github.com/Mrs4s/MiraiGo/utils" "github.com/Mrs4s/MiraiGo/utils"
) )
@ -33,46 +34,38 @@ var (
) )
// wtlogin.login // wtlogin.login
func decodeLoginResponse(c *QQClient, pkt *network.Packet) (any, error) { func decodeLoginResponse(c *QQClient, _ *incomingPacketInfo, payload []byte) (interface{}, error) {
reader := binary.NewReader(pkt.Payload) reader := binary.NewReader(payload)
reader.ReadUInt16() // sub command reader.ReadUInt16() // sub command
t := reader.ReadByte() t := reader.ReadByte()
reader.ReadUInt16() reader.ReadUInt16()
m, err := tlv.NewDecoder(2, 2).DecodeRecordMap(reader.ReadAvailable()) m := reader.ReadTlvMap(2)
if err != nil {
return nil, err
}
if m.Exists(0x402) { if m.Exists(0x402) {
c.sig.Dpwd = []byte(utils.RandomString(16)) c.dpwd = []byte(utils.RandomString(16))
c.sig.T402 = m[0x402] c.t402 = m[0x402]
h := md5.Sum(append(append(c.Device().Guid, c.sig.Dpwd...), c.sig.T402...)) h := md5.Sum(append(append(c.deviceInfo.Guid, c.dpwd...), c.t402...))
c.sig.G = h[:] c.g = h[:]
} }
if m.Exists(0x546) {
c.sig.T547 = auth.CalcPow(m[0x546])
}
// c.logger.Info("login response %v", t)
if t == 0 { // login success if t == 0 { // login success
// if t150, ok := m[0x150]; ok { if t150, ok := m[0x150]; ok {
// c.t150 = t150 c.t150 = t150
// }
// if t161, ok := m[0x161]; ok {
// c.decodeT161(t161)
// }
if m.Exists(0x403) {
c.sig.RandSeed = m[0x403]
} }
c.decodeT119(m[0x119], c.Device().TgtgtKey) if t161, ok := m[0x161]; ok {
c.decodeT161(t161)
}
if m.Exists(0x403) {
c.randSeed = m[0x403]
}
c.decodeT119(m[0x119], c.deviceInfo.TgtgtKey)
return LoginResponse{ return LoginResponse{
Success: true, Success: true,
}, nil }, nil
} }
if t == 2 { if t == 2 {
c.sig.T104 = m[0x104] c.t104 = m[0x104]
if m.Exists(0x192) { if m.Exists(0x192) {
return LoginResponse{ return LoginResponse{
Success: false, Success: false,
Code: t,
VerifyUrl: string(m[0x192]), VerifyUrl: string(m[0x192]),
Error: SliderNeededError, Error: SliderNeededError,
}, nil }, nil
@ -84,7 +77,6 @@ func decodeLoginResponse(c *QQClient, pkt *network.Packet) (any, error) {
sign := imgData.ReadBytes(int(signLen)) sign := imgData.ReadBytes(int(signLen))
return LoginResponse{ return LoginResponse{
Success: false, Success: false,
Code: t,
Error: NeedCaptcha, Error: NeedCaptcha,
CaptchaImage: imgData.ReadAvailable(), CaptchaImage: imgData.ReadAvailable(),
CaptchaSign: sign, CaptchaSign: sign,
@ -92,7 +84,6 @@ func decodeLoginResponse(c *QQClient, pkt *network.Packet) (any, error) {
} else { } else {
return LoginResponse{ return LoginResponse{
Success: false, Success: false,
Code: t,
Error: UnknownLoginError, Error: UnknownLoginError,
}, nil }, nil
} }
@ -101,7 +92,6 @@ func decodeLoginResponse(c *QQClient, pkt *network.Packet) (any, error) {
if t == 40 { if t == 40 {
return LoginResponse{ return LoginResponse{
Success: false, Success: false,
Code: t,
ErrorMessage: "账号被冻结", ErrorMessage: "账号被冻结",
Error: UnknownLoginError, Error: UnknownLoginError,
}, nil }, nil
@ -109,18 +99,16 @@ func decodeLoginResponse(c *QQClient, pkt *network.Packet) (any, error) {
if t == 160 || t == 239 { if t == 160 || t == 239 {
if t174, ok := m[0x174]; ok { // 短信验证 if t174, ok := m[0x174]; ok { // 短信验证
c.sig.T104 = m[0x104] c.t104 = m[0x104]
c.sig.T174 = t174 c.t174 = t174
c.sig.RandSeed = m[0x403] c.randSeed = m[0x403]
phone := func() string { phone := func() string {
r := binary.NewReader(m[0x178]) r := binary.NewReader(m[0x178])
r.ReadStringShort() return r.ReadStringLimit(int(r.ReadInt32()))
return r.ReadStringShort()
}() }()
if t204, ok := m[0x204]; ok { // 同时支持扫码验证 ? if t204, ok := m[0x204]; ok { // 同时支持扫码验证 ?
return LoginResponse{ return LoginResponse{
Success: false, Success: false,
Code: t,
Error: SMSOrVerifyNeededError, Error: SMSOrVerifyNeededError,
VerifyUrl: string(t204), VerifyUrl: string(t204),
SMSPhone: phone, SMSPhone: phone,
@ -129,7 +117,6 @@ func decodeLoginResponse(c *QQClient, pkt *network.Packet) (any, error) {
} }
return LoginResponse{ return LoginResponse{
Success: false, Success: false,
Code: t,
Error: SMSNeededError, Error: SMSNeededError,
SMSPhone: phone, SMSPhone: phone,
ErrorMessage: string(m[0x17e]), ErrorMessage: string(m[0x17e]),
@ -137,10 +124,9 @@ func decodeLoginResponse(c *QQClient, pkt *network.Packet) (any, error) {
} }
if _, ok := m[0x17b]; ok { // 二次验证 if _, ok := m[0x17b]; ok { // 二次验证
c.sig.T104 = m[0x104] c.t104 = m[0x104]
return LoginResponse{ return LoginResponse{
Success: false, Success: false,
Code: t,
Error: SMSNeededError, Error: SMSNeededError,
}, nil }, nil
} }
@ -148,7 +134,6 @@ func decodeLoginResponse(c *QQClient, pkt *network.Packet) (any, error) {
if t204, ok := m[0x204]; ok { // 扫码验证 if t204, ok := m[0x204]; ok { // 扫码验证
return LoginResponse{ return LoginResponse{
Success: false, Success: false,
Code: t,
Error: UnsafeDeviceError, Error: UnsafeDeviceError,
VerifyUrl: string(t204), VerifyUrl: string(t204),
ErrorMessage: "", ErrorMessage: "",
@ -158,14 +143,13 @@ func decodeLoginResponse(c *QQClient, pkt *network.Packet) (any, error) {
if t == 162 { if t == 162 {
return LoginResponse{ return LoginResponse{
Code: t,
Error: TooManySMSRequestError, Error: TooManySMSRequestError,
}, nil }, nil
} }
if t == 204 { if t == 204 {
c.sig.T104 = m[0x104] c.t104 = m[0x104]
c.sig.RandSeed = m[0x403] c.randSeed = m[0x403]
return c.sendAndWait(c.buildDeviceLockLoginPacket()) return c.sendAndWait(c.buildDeviceLockLoginPacket())
} // drive lock } // drive lock
@ -175,7 +159,6 @@ func decodeLoginResponse(c *QQClient, pkt *network.Packet) (any, error) {
t149r.ReadStringShort() // title t149r.ReadStringShort() // title
return LoginResponse{ return LoginResponse{
Success: false, Success: false,
Code: t,
Error: OtherLoginError, Error: OtherLoginError,
ErrorMessage: t149r.ReadStringShort(), ErrorMessage: t149r.ReadStringShort(),
}, nil }, nil
@ -187,29 +170,28 @@ func decodeLoginResponse(c *QQClient, pkt *network.Packet) (any, error) {
t146r.ReadStringShort() // title t146r.ReadStringShort() // title
return LoginResponse{ return LoginResponse{
Success: false, Success: false,
Code: t,
Error: OtherLoginError, Error: OtherLoginError,
ErrorMessage: t146r.ReadStringShort(), ErrorMessage: t146r.ReadStringShort(),
}, nil }, nil
} }
c.debug("unknown login response: %v", t) c.Debug("unknown login response: %v", t)
for k, v := range m { for k, v := range m {
c.debug("Type: %d Value: %x", k, v) c.Debug("Type: %v Value: %v", strconv.FormatInt(int64(k), 16), hex.EncodeToString(v))
} }
return nil, errors.Errorf("unknown login response: %v", t) // ? return nil, errors.Errorf("unknown login response: %v", t) // ?
} }
// StatSvc.register // StatSvc.register
func decodeClientRegisterResponse(c *QQClient, pkt *network.Packet) (any, error) { func decodeClientRegisterResponse(c *QQClient, _ *incomingPacketInfo, payload []byte) (interface{}, error) {
request := &jce.RequestPacket{} request := &jce.RequestPacket{}
request.ReadFrom(jce.NewJceReader(pkt.Payload)) request.ReadFrom(jce.NewJceReader(payload))
data := &jce.RequestDataVersion2{} data := &jce.RequestDataVersion2{}
data.ReadFrom(jce.NewJceReader(request.SBuffer)) data.ReadFrom(jce.NewJceReader(request.SBuffer))
svcRsp := &jce.SvcRespRegister{} svcRsp := &jce.SvcRespRegister{}
svcRsp.ReadFrom(jce.NewJceReader(data.Map["SvcRespRegister"]["QQService.SvcRespRegister"][1:])) svcRsp.ReadFrom(jce.NewJceReader(data.Map["SvcRespRegister"]["QQService.SvcRespRegister"][1:]))
if svcRsp.Result != "" || svcRsp.ReplyCode != 0 { if svcRsp.Result != "" || svcRsp.ReplyCode != 0 {
if svcRsp.Result != "" { if svcRsp.Result != "" {
c.error("reg error: %v", svcRsp.Result) c.Error("reg error: %v", svcRsp.Result)
} }
return nil, errors.New("reg failed") return nil, errors.New("reg failed")
} }
@ -217,34 +199,32 @@ func decodeClientRegisterResponse(c *QQClient, pkt *network.Packet) (any, error)
} }
// wtlogin.exchange_emp // wtlogin.exchange_emp
func decodeExchangeEmpResponse(c *QQClient, pkt *network.Packet) (any, error) { func decodeExchangeEmpResponse(c *QQClient, _ *incomingPacketInfo, payload []byte) (interface{}, error) {
reader := binary.NewReader(pkt.Payload) reader := binary.NewReader(payload)
cmd := reader.ReadUInt16() cmd := reader.ReadUInt16()
t := reader.ReadByte() t := reader.ReadByte()
reader.ReadUInt16() reader.ReadUInt16()
m, err := tlv.NewDecoder(2, 2).DecodeRecordMap(reader.ReadAvailable()) m := reader.ReadTlvMap(2)
if err != nil {
return nil, err
}
if t != 0 { if t != 0 {
return nil, errors.Errorf("exchange_emp failed: %v", t) c.Error("exchange_emp error: %v", t)
return nil, errors.New("exchange_emp failed")
} }
if cmd == 15 { if cmd == 15 {
c.decodeT119R(m[0x119]) c.decodeT119R(m[0x119])
} }
if cmd == 11 { if cmd == 11 {
h := md5.Sum(c.sig.D2Key) h := md5.Sum(c.sigInfo.d2Key)
c.decodeT119(m[0x119], h[:]) c.decodeT119(m[0x119], h[:])
} }
return nil, nil return nil, nil
} }
// wtlogin.trans_emp // wtlogin.trans_emp
func decodeTransEmpResponse(c *QQClient, pkt *network.Packet) (any, error) { func decodeTransEmpResponse(c *QQClient, _ *incomingPacketInfo, payload []byte) (interface{}, error) {
if len(pkt.Payload) < 48 { if len(payload) < 48 {
return nil, errors.New("missing payload length") return nil, errors.New("missing payload length")
} }
reader := binary.NewReader(pkt.Payload) reader := binary.NewReader(payload)
reader.ReadBytes(5) // trans req head reader.ReadBytes(5) // trans req head
reader.ReadByte() reader.ReadByte()
reader.ReadUInt16() reader.ReadUInt16()
@ -265,10 +245,7 @@ func decodeTransEmpResponse(c *QQClient, pkt *network.Packet) (any, error) {
} }
sig := body.ReadBytesShort() sig := body.ReadBytesShort()
body.ReadUInt16() body.ReadUInt16()
m, err := tlv.NewDecoder(2, 2).DecodeRecordMap(body.ReadAvailable()) m := body.ReadTlvMap(2)
if err != nil {
return nil, err
}
if m.Exists(0x17) { if m.Exists(0x17) {
return &QRCodeLoginResponse{ return &QRCodeLoginResponse{
State: QRCodeImageFetch, State: QRCodeImageFetch,
@ -308,17 +285,13 @@ func decodeTransEmpResponse(c *QQClient, pkt *network.Packet) (any, error) {
return nil, errors.Errorf("wtlogin.trans_emp sub cmd 0x12 error: %v", code) return nil, errors.Errorf("wtlogin.trans_emp sub cmd 0x12 error: %v", code)
} }
c.Uin = body.ReadInt64() c.Uin = body.ReadInt64()
c.highwaySession.Uin = strconv.FormatInt(c.Uin, 10)
body.ReadInt32() // sig create time body.ReadInt32() // sig create time
body.ReadUInt16() body.ReadUInt16()
m, err := tlv.NewDecoder(2, 2).DecodeRecordMap(body.ReadAvailable()) m := body.ReadTlvMap(2)
if err != nil {
return nil, err
}
if !m.Exists(0x18) || !m.Exists(0x1e) || !m.Exists(0x19) { if !m.Exists(0x18) || !m.Exists(0x1e) || !m.Exists(0x19) {
return nil, errors.New("wtlogin.trans_emp sub cmd 0x12 error: tlv error") return nil, errors.New("wtlogin.trans_emp sub cmd 0x12 error: tlv error")
} }
c.Device().TgtgtKey = m[0x1e] c.deviceInfo.TgtgtKey = m[0x1e]
return &QRCodeLoginResponse{State: QRCodeConfirmed, LoginInfo: &QRCodeLoginInfo{ return &QRCodeLoginResponse{State: QRCodeConfirmed, LoginInfo: &QRCodeLoginInfo{
tmpPwd: m[0x18], tmpPwd: m[0x18],
tmpNoPicSig: m[0x19], tmpNoPicSig: m[0x19],
@ -329,9 +302,9 @@ func decodeTransEmpResponse(c *QQClient, pkt *network.Packet) (any, error) {
} }
// ConfigPushSvc.PushReq // ConfigPushSvc.PushReq
func decodePushReqPacket(c *QQClient, pkt *network.Packet) (any, error) { func decodePushReqPacket(c *QQClient, _ *incomingPacketInfo, payload []byte) (interface{}, error) {
request := &jce.RequestPacket{} request := &jce.RequestPacket{}
request.ReadFrom(jce.NewJceReader(pkt.Payload)) request.ReadFrom(jce.NewJceReader(payload))
data := &jce.RequestDataVersion2{} data := &jce.RequestDataVersion2{}
data.ReadFrom(jce.NewJceReader(request.SBuffer)) data.ReadFrom(jce.NewJceReader(request.SBuffer))
r := jce.NewJceReader(data.Map["PushReq"]["ConfigPush.PushReq"][1:]) r := jce.NewJceReader(data.Map["PushReq"]["ConfigPush.PushReq"][1:])
@ -341,18 +314,19 @@ func decodePushReqPacket(c *QQClient, pkt *network.Packet) (any, error) {
switch t { switch t {
case 1: case 1:
ssoPkt := jce.NewJceReader(jceBuf) ssoPkt := jce.NewJceReader(jceBuf)
servers := ssoPkt.ReadSsoServerInfos(1) servers := []jce.SsoServerInfo{}
ssoPkt.ReadSlice(&servers, 1)
if len(servers) > 0 { if len(servers) > 0 {
var adds []netip.AddrPort var adds []*net.TCPAddr
for _, s := range servers { for _, s := range servers {
if strings.Contains(s.Server, "com") { if strings.Contains(s.Server, "com") {
continue continue
} }
c.debug("got new server addr: %v location: %v", s.Server, s.Location) c.Debug("got new server addr: %v location: %v", s.Server, s.Location)
addr, err := netip.ParseAddr(s.Server) adds = append(adds, &net.TCPAddr{
if err == nil { IP: net.ParseIP(s.Server),
adds = append(adds, netip.AddrPortFrom(addr, uint16(s.Port))) Port: int(s.Port),
} })
} }
f := true f := true
for _, e := range c.eventHandlers.serverUpdatedHandlers { for _, e := range c.eventHandlers.serverUpdatedHandlers {
@ -371,51 +345,50 @@ func decodePushReqPacket(c *QQClient, pkt *network.Packet) (any, error) {
fmtPkt := jce.NewJceReader(jceBuf) fmtPkt := jce.NewJceReader(jceBuf)
list := &jce.FileStoragePushFSSvcList{} list := &jce.FileStoragePushFSSvcList{}
list.ReadFrom(fmtPkt) list.ReadFrom(fmtPkt)
c.debug("got file storage svc push.") c.Debug("got file storage svc push.")
// c.fileStorageInfo = list c.fileStorageInfo = list
rsp := cmd0x6ff.C501RspBody{} rsp := cmd0x6ff.C501RspBody{}
if err := proto.Unmarshal(list.BigDataChannel.PbBuf, &rsp); err == nil && rsp.RspBody != nil { if err := proto.Unmarshal(list.BigDataChannel.PbBuf, &rsp); err == nil && rsp.RspBody != nil {
c.highwaySession.SigSession = rsp.RspBody.SigSession c.bigDataSession = &bigDataSessionInfo{
c.highwaySession.SessionKey = rsp.RspBody.SessionKey SigSession: rsp.RspBody.SigSession,
SessionKey: rsp.RspBody.SessionKey,
}
for _, srv := range rsp.RspBody.Addrs { for _, srv := range rsp.RspBody.Addrs {
if srv.ServiceType.Unwrap() == 10 { if srv.GetServiceType() == 10 {
for _, addr := range srv.Addrs { for _, addr := range srv.Addrs {
c.highwaySession.AppendAddr(addr.Ip.Unwrap(), addr.Port.Unwrap()) c.srvSsoAddrs = append(c.srvSsoAddrs, fmt.Sprintf("%v:%v", binary.UInt32ToIPV4Address(addr.GetIp()), addr.GetPort()))
} }
} }
/* if srv.GetServiceType() == 21 {
if srv.ServiceType.Unwrap() == 21 { for _, addr := range srv.Addrs {
for _, addr := range srv.Addrs { c.otherSrvAddrs = append(c.otherSrvAddrs, fmt.Sprintf("%v:%v", binary.UInt32ToIPV4Address(addr.GetIp()), addr.GetPort()))
c.otherSrvAddrs = append(c.otherSrvAddrs, fmt.Sprintf("%v:%v", binary.UInt32ToIPV4Address(addr.Ip.Unwrap()), addr.Port.Unwrap()))
}
} }
}
*/
} }
} }
} }
} }
seq := r.ReadInt64(3) seq := r.ReadInt64(3)
_, resp := c.buildConfPushRespPacket(t, seq, jceBuf) _, pkt := c.buildConfPushRespPacket(t, seq, jceBuf)
return nil, c.sendPacket(resp) return nil, c.sendPacket(pkt)
} }
// MessageSvc.PbGetMsg // MessageSvc.PbGetMsg
func decodeMessageSvcPacket(c *QQClient, pkt *network.Packet) (any, error) { func decodeMessageSvcPacket(c *QQClient, info *incomingPacketInfo, payload []byte) (interface{}, error) {
rsp := msg.GetMessageResponse{} rsp := msg.GetMessageResponse{}
err := proto.Unmarshal(pkt.Payload, &rsp) err := protobuf.Unmarshal(payload, &rsp)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
c.c2cMessageSyncProcessor(&rsp, pkt.Params) c.c2cMessageSyncProcessor(&rsp, info)
return nil, nil return nil, nil
} }
// MessageSvc.PushNotify // MessageSvc.PushNotify
func decodeSvcNotify(c *QQClient, pkt *network.Packet) (any, error) { func decodeSvcNotify(c *QQClient, _ *incomingPacketInfo, payload []byte) (interface{}, error) {
request := &jce.RequestPacket{} request := &jce.RequestPacket{}
request.ReadFrom(jce.NewJceReader(pkt.Payload[4:])) request.ReadFrom(jce.NewJceReader(payload[15:]))
data := &jce.RequestDataVersion2{} data := &jce.RequestDataVersion2{}
data.ReadFrom(jce.NewJceReader(request.SBuffer)) data.ReadFrom(jce.NewJceReader(request.SBuffer))
if len(data.Map) == 0 { if len(data.Map) == 0 {
@ -440,9 +413,9 @@ func decodeSvcNotify(c *QQClient, pkt *network.Packet) (any, error) {
} }
// SummaryCard.ReqSummaryCard // SummaryCard.ReqSummaryCard
func decodeSummaryCardResponse(_ *QQClient, pkt *network.Packet) (any, error) { func decodeSummaryCardResponse(_ *QQClient, _ *incomingPacketInfo, payload []byte) (interface{}, error) {
request := &jce.RequestPacket{} request := &jce.RequestPacket{}
request.ReadFrom(jce.NewJceReader(pkt.Payload)) request.ReadFrom(jce.NewJceReader(payload))
data := &jce.RequestDataVersion2{} data := &jce.RequestDataVersion2{}
data.ReadFrom(jce.NewJceReader(request.SBuffer)) data.ReadFrom(jce.NewJceReader(request.SBuffer))
rsp := func() *jce.JceReader { rsp := func() *jce.JceReader {
@ -452,35 +425,18 @@ func decodeSummaryCardResponse(_ *QQClient, pkt *network.Packet) (any, error) {
return jce.NewJceReader(data.Map["RespSummaryCard"]["SummaryCard_Old.RespSummaryCard"][1:]) return jce.NewJceReader(data.Map["RespSummaryCard"]["SummaryCard_Old.RespSummaryCard"][1:])
}() }()
info := &SummaryCardInfo{ info := &SummaryCardInfo{
Sex: rsp.ReadByte(1), Sex: rsp.ReadByte(1),
Age: rsp.ReadByte(2), Age: rsp.ReadByte(2),
Nickname: rsp.ReadString(3), Nickname: rsp.ReadString(3),
Level: rsp.ReadInt32(5), Level: rsp.ReadInt32(5),
City: rsp.ReadString(7), City: rsp.ReadString(7),
Sign: rsp.ReadString(8), Sign: rsp.ReadString(8),
Mobile: rsp.ReadString(11), Mobile: rsp.ReadString(11),
Uin: rsp.ReadInt64(23), Uin: rsp.ReadInt64(23),
LoginDays: rsp.ReadInt64(36),
} }
vipInfo := rsp.ReadMapIntVipInfo(29) // 1 -> vip, 3 -> svip services := [][]byte{}
if v1, v3 := vipInfo[1], vipInfo[3]; v1 != nil || v3 != nil { rsp.ReadSlice(&services, 46)
if v1.Open != 0 {
info.VipLevel = fmt.Sprintf("vip%d", v1.Level)
}
if v3.Open != 0 {
info.VipLevel = fmt.Sprintf("svip%d", v3.Level)
}
}
richSign := rsp.ReadBytes(32)
records, _ := tlv.NewDecoder(1, 1).Decode(richSign)
for _, r := range records {
if r.Tag == 3 {
info.Sign = string(r.Value)
}
}
info.LoginDays = rsp.ReadInt64(36)
services := rsp.ReadByteArrArr(46)
readService := func(buf []byte) (*profilecard.BusiComm, []byte) { readService := func(buf []byte) (*profilecard.BusiComm, []byte) {
r := binary.NewReader(buf) r := binary.NewReader(buf)
r.ReadByte() r.ReadByte()
@ -494,11 +450,11 @@ func decodeSummaryCardResponse(_ *QQClient, pkt *network.Packet) (any, error) {
} }
for _, buf := range services { for _, buf := range services {
comm, payload := readService(buf) comm, payload := readService(buf)
if comm.Service.Unwrap() == 16 { if comm.GetService() == 16 {
rsp := profilecard.GateVaProfileGateRsp{} rsp := profilecard.GateVaProfileGateRsp{}
_ = proto.Unmarshal(payload, &rsp) _ = proto.Unmarshal(payload, &rsp)
if rsp.QidInfo != nil { if rsp.QidInfo != nil {
info.Qid = rsp.QidInfo.Qid.Unwrap() info.Qid = rsp.QidInfo.GetQid()
} }
} }
} }
@ -506,14 +462,15 @@ func decodeSummaryCardResponse(_ *QQClient, pkt *network.Packet) (any, error) {
} }
// friendlist.getFriendGroupList // friendlist.getFriendGroupList
func decodeFriendGroupListResponse(_ *QQClient, pkt *network.Packet) (any, error) { func decodeFriendGroupListResponse(_ *QQClient, _ *incomingPacketInfo, payload []byte) (interface{}, error) {
request := &jce.RequestPacket{} request := &jce.RequestPacket{}
request.ReadFrom(jce.NewJceReader(pkt.Payload)) request.ReadFrom(jce.NewJceReader(payload))
data := &jce.RequestDataVersion3{} data := &jce.RequestDataVersion3{}
data.ReadFrom(jce.NewJceReader(request.SBuffer)) data.ReadFrom(jce.NewJceReader(request.SBuffer))
r := jce.NewJceReader(data.Map["FLRESP"][1:]) r := jce.NewJceReader(data.Map["FLRESP"][1:])
totalFriendCount := r.ReadInt16(5) totalFriendCount := r.ReadInt16(5)
friends := r.ReadFriendInfos(7) friends := make([]jce.FriendInfo, 0)
r.ReadSlice(&friends, 7)
l := make([]*FriendInfo, 0, len(friends)) l := make([]*FriendInfo, 0, len(friends))
for _, f := range friends { for _, f := range friends {
l = append(l, &FriendInfo{ l = append(l, &FriendInfo{
@ -531,9 +488,9 @@ func decodeFriendGroupListResponse(_ *QQClient, pkt *network.Packet) (any, error
} }
// friendlist.delFriend // friendlist.delFriend
func decodeFriendDeleteResponse(_ *QQClient, pkt *network.Packet) (any, error) { func decodeFriendDeleteResponse(_ *QQClient, _ *incomingPacketInfo, payload []byte) (interface{}, error) {
request := &jce.RequestPacket{} request := &jce.RequestPacket{}
request.ReadFrom(jce.NewJceReader(pkt.Payload)) request.ReadFrom(jce.NewJceReader(payload))
data := &jce.RequestDataVersion3{} data := &jce.RequestDataVersion3{}
data.ReadFrom(jce.NewJceReader(request.SBuffer)) data.ReadFrom(jce.NewJceReader(request.SBuffer))
r := jce.NewJceReader(data.Map["DFRESP"][1:]) r := jce.NewJceReader(data.Map["DFRESP"][1:])
@ -544,20 +501,23 @@ func decodeFriendDeleteResponse(_ *QQClient, pkt *network.Packet) (any, error) {
} }
// friendlist.GetTroopListReqV2 // friendlist.GetTroopListReqV2
func decodeGroupListResponse(c *QQClient, pkt *network.Packet) (any, error) { func decodeGroupListResponse(c *QQClient, _ *incomingPacketInfo, payload []byte) (interface{}, error) {
request := &jce.RequestPacket{} request := &jce.RequestPacket{}
request.ReadFrom(jce.NewJceReader(pkt.Payload)) request.ReadFrom(jce.NewJceReader(payload))
data := &jce.RequestDataVersion3{} data := &jce.RequestDataVersion3{}
data.ReadFrom(jce.NewJceReader(request.SBuffer)) data.ReadFrom(jce.NewJceReader(request.SBuffer))
r := jce.NewJceReader(data.Map["GetTroopListRespV2"][1:]) r := jce.NewJceReader(data.Map["GetTroopListRespV2"][1:])
vecCookie := r.ReadBytes(4) vecCookie := []byte{}
groups := r.ReadTroopNumbers(5) groups := []jce.TroopNumber{}
r.ReadSlice(&vecCookie, 4)
r.ReadSlice(&groups, 5)
l := make([]*GroupInfo, 0, len(groups)) l := make([]*GroupInfo, 0, len(groups))
for _, g := range groups { for _, g := range groups {
l = append(l, &GroupInfo{ l = append(l, &GroupInfo{
Uin: g.GroupUin, Uin: g.GroupUin,
Code: g.GroupCode, Code: g.GroupCode,
Name: g.GroupName, Name: g.GroupName,
Memo: g.GroupMemo,
OwnerUin: g.GroupOwnerUin, OwnerUin: g.GroupOwnerUin,
MemberCount: uint16(g.MemberNum), MemberCount: uint16(g.MemberNum),
MaxMemberCount: uint16(g.MaxGroupMemberNum), MaxMemberCount: uint16(g.MaxGroupMemberNum),
@ -575,31 +535,34 @@ func decodeGroupListResponse(c *QQClient, pkt *network.Packet) (any, error) {
} }
// friendlist.GetTroopMemberListReq // friendlist.GetTroopMemberListReq
func decodeGroupMemberListResponse(_ *QQClient, pkt *network.Packet) (any, error) { func decodeGroupMemberListResponse(_ *QQClient, _ *incomingPacketInfo, payload []byte) (interface{}, error) {
request := &jce.RequestPacket{} request := &jce.RequestPacket{}
request.ReadFrom(jce.NewJceReader(pkt.Payload)) request.ReadFrom(jce.NewJceReader(payload))
data := &jce.RequestDataVersion3{} data := &jce.RequestDataVersion3{}
data.ReadFrom(jce.NewJceReader(request.SBuffer)) data.ReadFrom(jce.NewJceReader(request.SBuffer))
r := jce.NewJceReader(data.Map["GTMLRESP"][1:]) r := jce.NewJceReader(data.Map["GTMLRESP"][1:])
members := r.ReadTroopMemberInfos(3) members := make([]jce.TroopMemberInfo, 0)
r.ReadSlice(&members, 3)
next := r.ReadInt64(4) next := r.ReadInt64(4)
l := make([]*GroupMemberInfo, 0, len(members)) l := make([]*GroupMemberInfo, 0, len(members))
for _, m := range members { for _, m := range members {
permission := Member
if m.Flag&1 != 0 {
permission = Administrator
}
l = append(l, &GroupMemberInfo{ l = append(l, &GroupMemberInfo{
Uin: m.MemberUin, Uin: m.MemberUin,
Nickname: m.Nick, Nickname: m.Nick,
Gender: m.Gender, Gender: m.Gender,
CardName: m.Name, CardName: m.Name,
Level: uint16(m.MemberLevel), Level: uint16(m.MemberLevel),
JoinTime: m.JoinTime, JoinTime: m.JoinTime,
LastSpeakTime: m.LastSpeakTime, LastSpeakTime: m.LastSpeakTime,
SpecialTitle: m.SpecialTitle, SpecialTitle: m.SpecialTitle,
ShutUpTimestamp: m.ShutUpTimestap, SpecialTitleExpireTime: m.SpecialTitleExpireTime,
Permission: permission, ShutUpTimestamp: m.ShutUpTimestap,
Permission: func() MemberPermission {
if m.Flag == 1 {
return Administrator
}
return Member
}(),
}) })
} }
return &groupMemberListResponse{ return &groupMemberListResponse{
@ -609,103 +572,105 @@ func decodeGroupMemberListResponse(_ *QQClient, pkt *network.Packet) (any, error
} }
// group_member_card.get_group_member_card_info // group_member_card.get_group_member_card_info
func decodeGroupMemberInfoResponse(c *QQClient, pkt *network.Packet) (any, error) { func decodeGroupMemberInfoResponse(c *QQClient, _ *incomingPacketInfo, payload []byte) (interface{}, error) {
rsp := pb.GroupMemberRspBody{} rsp := pb.GroupMemberRspBody{}
if err := proto.Unmarshal(pkt.Payload, &rsp); err != nil { if err := proto.Unmarshal(payload, &rsp); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
if rsp.MemInfo == nil || (rsp.MemInfo.Nick == nil && rsp.MemInfo.Age == 0) { if rsp.MemInfo == nil || (rsp.MemInfo.Nick == nil && rsp.MemInfo.Age == 0) {
return nil, errors.WithStack(ErrMemberNotFound) return nil, errors.WithStack(ErrMemberNotFound)
} }
group := c.FindGroup(rsp.GroupCode) group := c.FindGroup(rsp.GroupCode)
permission := Member
if rsp.MemInfo.Uin == group.OwnerUin {
permission = Owner
}
if rsp.MemInfo.Role == 2 {
permission = Administrator
}
return &GroupMemberInfo{ return &GroupMemberInfo{
Group: group, Group: group,
Uin: rsp.MemInfo.Uin, Uin: rsp.MemInfo.Uin,
Gender: byte(rsp.MemInfo.Sex), Gender: byte(rsp.MemInfo.Sex),
Nickname: string(rsp.MemInfo.Nick), Nickname: string(rsp.MemInfo.Nick),
CardName: string(rsp.MemInfo.Card), CardName: string(rsp.MemInfo.Card),
Level: uint16(rsp.MemInfo.Level), Level: uint16(rsp.MemInfo.Level),
JoinTime: rsp.MemInfo.Join, JoinTime: rsp.MemInfo.Join,
LastSpeakTime: rsp.MemInfo.LastSpeak, LastSpeakTime: rsp.MemInfo.LastSpeak,
SpecialTitle: string(rsp.MemInfo.SpecialTitle), SpecialTitle: string(rsp.MemInfo.SpecialTitle),
Permission: permission, SpecialTitleExpireTime: int64(rsp.MemInfo.SpecialTitleExpireTime),
Permission: func() MemberPermission {
if rsp.MemInfo.Uin == group.OwnerUin {
return Owner
}
if rsp.MemInfo.Role == 2 {
return Administrator
}
return Member
}(),
}, nil }, nil
} }
// LongConn.OffPicUp // LongConn.OffPicUp
func decodeOffPicUpResponse(_ *QQClient, pkt *network.Packet) (any, error) { func decodeOffPicUpResponse(_ *QQClient, _ *incomingPacketInfo, payload []byte) (interface{}, error) {
rsp := cmd0x352.RspBody{} rsp := cmd0x352.RspBody{}
if err := proto.Unmarshal(pkt.Payload, &rsp); err != nil { if err := proto.Unmarshal(payload, &rsp); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
if rsp.FailMsg != nil { if rsp.GetFailMsg() != nil {
return &imageUploadResponse{ return &imageUploadResponse{
ResultCode: -1, ResultCode: -1,
Message: string(rsp.FailMsg), Message: string(rsp.FailMsg),
}, nil }, nil
} }
if rsp.Subcmd.Unwrap() != 1 || len(rsp.TryupImgRsp) == 0 { if rsp.GetSubcmd() != 1 || len(rsp.GetTryupImgRsp()) == 0 {
return &imageUploadResponse{ return &imageUploadResponse{
ResultCode: -2, ResultCode: -2,
}, nil }, nil
} }
imgRsp := rsp.TryupImgRsp[0] imgRsp := rsp.GetTryupImgRsp()[0]
if imgRsp.Result.Unwrap() != 0 { if imgRsp.GetResult() != 0 {
return &imageUploadResponse{ return &imageUploadResponse{
ResultCode: int32(imgRsp.Result.Unwrap()), ResultCode: int32(*imgRsp.Result),
Message: string(imgRsp.FailMsg), Message: string(imgRsp.GetFailMsg()),
}, nil }, nil
} }
if imgRsp.FileExit.Unwrap() { if imgRsp.GetFileExit() {
return &imageUploadResponse{ return &imageUploadResponse{
IsExists: true, IsExists: true,
ResourceId: string(imgRsp.UpResid), ResourceId: string(imgRsp.GetUpResid()),
}, nil }, nil
} }
return &imageUploadResponse{ return &imageUploadResponse{
ResourceId: string(imgRsp.UpResid), ResourceId: string(imgRsp.GetUpResid()),
UploadKey: imgRsp.UpUkey, UploadKey: imgRsp.GetUpUkey(),
UploadIp: imgRsp.UpIp, UploadIp: imgRsp.GetUpIp(),
UploadPort: imgRsp.UpPort, UploadPort: imgRsp.GetUpPort(),
}, nil }, nil
} }
// OnlinePush.PbPushTransMsg // OnlinePush.PbPushTransMsg
func decodeOnlinePushTransPacket(c *QQClient, pkt *network.Packet) (any, error) { func decodeOnlinePushTransPacket(c *QQClient, _ *incomingPacketInfo, payload []byte) (interface{}, error) {
info := msg.TransMsgInfo{} info := msg.TransMsgInfo{}
err := proto.Unmarshal(pkt.Payload, &info) err := protobuf.Unmarshal(payload, &info)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
data := binary.NewReader(info.MsgData) data := binary.NewReader(info.MsgData)
idStr := strconv.FormatInt(info.MsgUid.Unwrap(), 10) idStr := strconv.FormatInt(info.GetMsgUid(), 10)
if _, ok := c.transCache.Get(idStr); ok { if _, ok := c.transCache.Get(idStr); ok {
return nil, nil return nil, nil
} }
c.transCache.Add(idStr, unit{}, time.Second*15) c.transCache.Add(idStr, "", time.Second*15)
if info.MsgType.Unwrap() == 34 { if info.GetMsgType() == 34 {
data.ReadInt32() data.ReadInt32()
data.ReadByte() data.ReadByte()
target := int64(uint32(data.ReadInt32())) target := int64(uint32(data.ReadInt32()))
typ := int32(data.ReadByte()) typ := int32(data.ReadByte())
operator := int64(uint32(data.ReadInt32())) operator := int64(uint32(data.ReadInt32()))
if g := c.FindGroupByUin(info.FromUin.Unwrap()); g != nil { if g := c.FindGroupByUin(info.GetFromUin()); g != nil {
groupLeaveLock.Lock() groupLeaveLock.Lock()
defer groupLeaveLock.Unlock() defer groupLeaveLock.Unlock()
switch typ { switch typ {
case 0x02: case 0x02:
if target == c.Uin { if target == c.Uin {
c.GroupLeaveEvent.dispatch(c, &GroupLeaveEvent{Group: g}) c.dispatchLeaveGroupEvent(&GroupLeaveEvent{Group: g})
} else if m := g.FindMember(target); m != nil { } else if m := g.FindMember(target); m != nil {
g.removeMember(target) g.removeMember(target)
c.GroupMemberLeaveEvent.dispatch(c, &MemberLeaveGroupEvent{ c.dispatchMemberLeaveEvent(&MemberLeaveGroupEvent{
Group: g, Group: g,
Member: m, Member: m,
}) })
@ -715,13 +680,13 @@ func decodeOnlinePushTransPacket(c *QQClient, pkt *network.Packet) (any, error)
return nil, err return nil, err
} }
if target == c.Uin { if target == c.Uin {
c.GroupLeaveEvent.dispatch(c, &GroupLeaveEvent{ c.dispatchLeaveGroupEvent(&GroupLeaveEvent{
Group: g, Group: g,
Operator: g.FindMember(operator), Operator: g.FindMember(operator),
}) })
} else if m := g.FindMember(target); m != nil { } else if m := g.FindMember(target); m != nil {
g.removeMember(target) g.removeMember(target)
c.GroupMemberLeaveEvent.dispatch(c, &MemberLeaveGroupEvent{ c.dispatchMemberLeaveEvent(&MemberLeaveGroupEvent{
Group: g, Group: g,
Member: m, Member: m,
Operator: g.FindMember(operator), Operator: g.FindMember(operator),
@ -730,7 +695,7 @@ func decodeOnlinePushTransPacket(c *QQClient, pkt *network.Packet) (any, error)
case 0x82: case 0x82:
if m := g.FindMember(target); m != nil { if m := g.FindMember(target); m != nil {
g.removeMember(target) g.removeMember(target)
c.GroupMemberLeaveEvent.dispatch(c, &MemberLeaveGroupEvent{ c.dispatchMemberLeaveEvent(&MemberLeaveGroupEvent{
Group: g, Group: g,
Member: m, Member: m,
}) })
@ -738,25 +703,16 @@ func decodeOnlinePushTransPacket(c *QQClient, pkt *network.Packet) (any, error)
case 0x83: case 0x83:
if m := g.FindMember(target); m != nil { if m := g.FindMember(target); m != nil {
g.removeMember(target) g.removeMember(target)
c.GroupMemberLeaveEvent.dispatch(c, &MemberLeaveGroupEvent{ c.dispatchMemberLeaveEvent(&MemberLeaveGroupEvent{
Group: g, Group: g,
Member: m, Member: m,
Operator: g.FindMember(operator), Operator: g.FindMember(operator),
}) })
} }
case 0x01, 0x81: // kosbot add: 群解散. 暂时这样 See https://github.com/lz1998/ricq/blob/064ddddca19aa0410e2514852e3a151fd9913371/ricq-core/src/command/online_push/decoder.rs#L86
c.GroupDisbandEvent.dispatch(c, &GroupDisbandEvent{
Group: g,
Operator: g.FindMember(operator),
Time: int64(info.MsgTime.Unwrap()),
})
if err = c.ReloadGroupList(); err != nil {
return nil, err
}
} }
} }
} }
if info.MsgType.Unwrap() == 44 { if info.GetMsgType() == 44 {
data.ReadBytes(5) data.ReadBytes(5)
var4 := int32(data.ReadByte()) var4 := int32(data.ReadByte())
var5 := int64(0) var5 := int64(0)
@ -764,17 +720,19 @@ func decodeOnlinePushTransPacket(c *QQClient, pkt *network.Packet) (any, error)
if var4 != 0 && var4 != 1 { if var4 != 0 && var4 != 1 {
var5 = int64(uint32(data.ReadInt32())) var5 = int64(uint32(data.ReadInt32()))
} }
if g := c.FindGroupByUin(info.FromUin.Unwrap()); g != nil { if g := c.FindGroupByUin(info.GetFromUin()); g != nil {
if var5 == 0 && data.Len() == 1 { if var5 == 0 && data.Len() == 1 {
newPermission := Member newPermission := func() MemberPermission {
if data.ReadByte() == 1 { if data.ReadByte() == 1 {
newPermission = Administrator return Administrator
} }
return Member
}()
mem := g.FindMember(target) mem := g.FindMember(target)
if mem.Permission != newPermission { if mem.Permission != newPermission {
old := mem.Permission old := mem.Permission
mem.Permission = newPermission mem.Permission = newPermission
c.GroupMemberPermissionChangedEvent.dispatch(c, &MemberPermissionChangedEvent{ c.dispatchPermissionChanged(&MemberPermissionChangedEvent{
Group: g, Group: g,
Member: mem, Member: mem,
OldPermission: old, OldPermission: old,
@ -788,9 +746,9 @@ func decodeOnlinePushTransPacket(c *QQClient, pkt *network.Packet) (any, error)
} }
// ProfileService.Pb.ReqSystemMsgNew.Friend // ProfileService.Pb.ReqSystemMsgNew.Friend
func decodeSystemMsgFriendPacket(c *QQClient, pkt *network.Packet) (any, error) { func decodeSystemMsgFriendPacket(c *QQClient, _ *incomingPacketInfo, payload []byte) (interface{}, error) {
rsp := structmsg.RspSystemMsgNew{} rsp := structmsg.RspSystemMsgNew{}
if err := proto.Unmarshal(pkt.Payload, &rsp); err != nil { if err := proto.Unmarshal(payload, &rsp); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
if len(rsp.Friendmsgs) == 0 { if len(rsp.Friendmsgs) == 0 {
@ -798,7 +756,7 @@ func decodeSystemMsgFriendPacket(c *QQClient, pkt *network.Packet) (any, error)
} }
st := rsp.Friendmsgs[0] st := rsp.Friendmsgs[0]
if st.Msg != nil { if st.Msg != nil {
c.NewFriendRequestEvent.dispatch(c, &NewFriendRequest{ c.dispatchNewFriendRequest(&NewFriendRequest{
RequestId: st.MsgSeq, RequestId: st.MsgSeq,
Message: st.Msg.MsgAdditional, Message: st.Msg.MsgAdditional,
RequesterUin: st.ReqUin, RequesterUin: st.ReqUin,
@ -810,33 +768,36 @@ func decodeSystemMsgFriendPacket(c *QQClient, pkt *network.Packet) (any, error)
} }
// MessageSvc.PushForceOffline // MessageSvc.PushForceOffline
func decodeForceOfflinePacket(c *QQClient, pkt *network.Packet) (any, error) { func decodeForceOfflinePacket(c *QQClient, _ *incomingPacketInfo, payload []byte) (interface{}, error) {
request := &jce.RequestPacket{} request := &jce.RequestPacket{}
request.ReadFrom(jce.NewJceReader(pkt.Payload)) request.ReadFrom(jce.NewJceReader(payload))
data := &jce.RequestDataVersion2{} data := &jce.RequestDataVersion2{}
data.ReadFrom(jce.NewJceReader(request.SBuffer)) data.ReadFrom(jce.NewJceReader(request.SBuffer))
r := jce.NewJceReader(data.Map["req_PushForceOffline"]["PushNotifyPack.RequestPushForceOffline"][1:]) r := jce.NewJceReader(data.Map["req_PushForceOffline"]["PushNotifyPack.RequestPushForceOffline"][1:])
tips := r.ReadString(2) tips := r.ReadString(2)
c.Disconnect() c.Disconnect()
go c.DisconnectedEvent.dispatch(c, &ClientDisconnectedEvent{Message: tips}) go c.dispatchDisconnectEvent(&ClientDisconnectedEvent{Message: tips})
return nil, nil return nil, nil
} }
// StatSvc.ReqMSFOffline // StatSvc.ReqMSFOffline
func decodeMSFOfflinePacket(c *QQClient, _ *network.Packet) (any, error) { func decodeMSFOfflinePacket(c *QQClient, _ *incomingPacketInfo, _ []byte) (interface{}, error) {
// c.lastLostMsg = "服务器端强制下线." // c.lastLostMsg = "服务器端强制下线."
c.Disconnect() c.Disconnect()
// 这个decoder不能消耗太多时间, event另起线程处理 // 这个decoder不能消耗太多时间, event另起线程处理
go c.DisconnectedEvent.dispatch(c, &ClientDisconnectedEvent{Message: "服务端强制下线."}) go c.dispatchDisconnectEvent(&ClientDisconnectedEvent{Message: "服务端强制下线."})
return nil, nil return nil, nil
} }
// OidbSvc.0xd79 // OidbSvc.0xd79
func decodeWordSegmentation(_ *QQClient, pkt *network.Packet) (any, error) { func decodeWordSegmentation(_ *QQClient, _ *incomingPacketInfo, payload []byte) (interface{}, error) {
rsp := oidb.D79RspBody{} pkg := oidb.OIDBSSOPkg{}
err := unpackOIDBPackage(pkt.Payload, &rsp) rsp := &oidb0xd79.RspBody{}
if err != nil { if err := protobuf.Unmarshal(payload, &pkg); err != nil {
return nil, err return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
}
if err := protobuf.Unmarshal(pkg.Bodybuffer, rsp); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
if rsp.Content != nil { if rsp.Content != nil {
return rsp.Content.SliceContent, nil return rsp.Content.SliceContent, nil
@ -844,21 +805,6 @@ func decodeWordSegmentation(_ *QQClient, pkt *network.Packet) (any, error) {
return nil, errors.New("no word received") return nil, errors.New("no word received")
} }
func decodeSidExpiredPacket(c *QQClient, pkt *network.Packet) (any, error) {
/*
_, err := c.sendAndWait(c.buildRequestChangeSigPacket(true))
if err != nil {
return nil, errors.Wrap(err, "resign client error")
}
if err = c.registerClient(); err != nil {
return nil, errors.Wrap(err, "register error")
}
_ = c.sendPacket(c.uniPacketWithSeq(i.SequenceId, "OnlinePush.SidTicketExpired", EmptyBytes))
*/
return nil, nil
}
/* unused
// LightAppSvc.mini_app_info.GetAppInfoById // LightAppSvc.mini_app_info.GetAppInfoById
func decodeAppInfoResponse(_ *QQClient, _ *incomingPacketInfo, payload []byte) (interface{}, error) { func decodeAppInfoResponse(_ *QQClient, _ *incomingPacketInfo, payload []byte) (interface{}, error) {
pkg := qweb.QWebRsp{} pkg := qweb.QWebRsp{}
@ -866,16 +812,15 @@ func decodeAppInfoResponse(_ *QQClient, _ *incomingPacketInfo, payload []byte) (
if err := proto.Unmarshal(payload, &pkg); err != nil { if err := proto.Unmarshal(payload, &pkg); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
if pkg.RetCode.Unwrap() != 0 { if pkg.RetCode != 0 {
return nil, errors.New(pkg.ErrMsg.Unwrap()) return nil, errors.New(pkg.ErrMsg)
} }
if err := proto.Unmarshal(pkg.BusiBuff, &rsp); err != nil { if err := proto.Unmarshal(pkg.BusiBuff, &rsp); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
return rsp.AppInfo, nil return rsp.AppInfo, nil
} }
*/
func ignoreDecoder(_ *QQClient, _ *network.Packet) (any, error) { func ignoreDecoder(_ *QQClient, _ *incomingPacketInfo, _ []byte) (interface{}, error) {
return nil, nil return nil, nil
} }

View File

@ -4,7 +4,6 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/Mrs4s/MiraiGo/binary/jce" "github.com/Mrs4s/MiraiGo/binary/jce"
"github.com/Mrs4s/MiraiGo/client/internal/auth"
"github.com/Mrs4s/MiraiGo/message" "github.com/Mrs4s/MiraiGo/message"
) )
@ -23,11 +22,10 @@ type (
UserOnlineStatus int UserOnlineStatus int
ClientProtocol = auth.ProtocolType ClientProtocol int
LoginResponse struct { LoginResponse struct {
Success bool Success bool
Code byte
Error LoginError Error LoginError
// Captcha info // Captcha info
@ -78,7 +76,6 @@ type (
Mobile string Mobile string
LoginDays int64 LoginDays int64
Qid string Qid string
VipLevel string
} }
OtherClientInfo struct { OtherClientInfo struct {
@ -177,6 +174,11 @@ type (
client *QQClient client *QQClient
} }
LogEvent struct {
Type string
Message string
}
ServerUpdatedEvent struct { ServerUpdatedEvent struct {
Servers []jce.SsoServerInfo Servers []jce.SsoServerInfo
} }
@ -192,17 +194,6 @@ type (
DownloadUrl string DownloadUrl string
} }
GroupDisbandEvent struct {
Group *GroupInfo
Time int64
Operator *GroupMemberInfo
}
DeleteFriendEvent struct {
Uin int64
Nickname string
}
// GroupDigest 群精华消息 // GroupDigest 群精华消息
GroupDigest struct { GroupDigest struct {
GroupCode int64 `json:"group_code,string"` GroupCode int64 `json:"group_code,string"`
@ -230,42 +221,15 @@ type (
} }
GuildMessageReactionsUpdatedEvent struct { GuildMessageReactionsUpdatedEvent struct {
OperatorId uint64 // OperatorId 操作者TinyId, 删除贴表情的事件下不会有值 OperatorId uint64 // OperatorId 操作者TinyId, 删除贴表情的事件下不会有值
EmojiId int32 // EmojiId 被贴的表情, 只有自身消息被贴表情才会有值 EmojiId int32 // EmojiId 被贴的表情, 只有自身消息被贴表情才会有值
GuildId uint64 GuildId uint64
ChannelId uint64 ChannelId uint64
MessageId uint64 MessageId uint64
// MessageSenderUin int64 // MessageSenderUin 被贴表情的消息发送者QQ号 MessageSenderUin int64 // MessageSenderUin 被贴表情的消息发送者QQ号
CurrentReactions []*message.GuildMessageEmojiReaction CurrentReactions []*message.GuildMessageEmojiReaction
} }
GuildChannelUpdatedEvent struct {
OperatorId uint64
GuildId uint64
ChannelId uint64
OldChannelInfo *ChannelInfo
NewChannelInfo *ChannelInfo
}
GuildMessageRecalledEvent struct {
OperatorId uint64
GuildId uint64
ChannelId uint64
MessageId uint64
RecallTime int64
}
GuildChannelOperationEvent struct {
OperatorId uint64
GuildId uint64
ChannelInfo *ChannelInfo
}
MemberJoinGuildEvent struct {
Guild *GuildInfo
Member *GuildMemberInfo
}
OcrResponse struct { OcrResponse struct {
Texts []*TextDetection `json:"texts"` Texts []*TextDetection `json:"texts"`
Language string `json:"language"` Language string `json:"language"`
@ -293,6 +257,33 @@ type (
list []*GroupMemberInfo list []*GroupMemberInfo
} }
imageUploadResponse struct {
UploadKey []byte
UploadIp []uint32
UploadPort []uint32
ResourceId string
Message string
FileId int64
Width int32
Height int32
ResultCode int32
IsExists bool
}
pttUploadResponse struct {
ResultCode int32
Message string
IsExists bool
ResourceId string
UploadKey []byte
UploadIp []string
UploadPort []uint32
FileKey []byte
FileId int64
}
groupMessageReceiptEvent struct { groupMessageReceiptEvent struct {
Rand int32 Rand int32
Seq int32 Seq int32
@ -303,12 +294,8 @@ type (
SigSession []byte SigSession []byte
SessionKey []byte SessionKey []byte
} }
// unit is an alias for struct{}, like `()` in rust
unit = struct{}
) )
//go:generate stringer -type=LoginError
const ( const (
NeedCaptcha LoginError = 1 NeedCaptcha LoginError = 1
OtherLoginError LoginError = 3 OtherLoginError LoginError = 3
@ -355,13 +342,11 @@ const (
Administrator MemberPermission = 2 Administrator MemberPermission = 2
Member MemberPermission = 3 Member MemberPermission = 3
Unset = auth.Unset AndroidPhone ClientProtocol = 1
AndroidPhone = auth.AndroidPhone IPad ClientProtocol = 2
AndroidWatch = auth.AndroidWatch AndroidWatch ClientProtocol = 3
MacOS = auth.MacOS MacOS ClientProtocol = 4
QiDian = auth.QiDian QiDian ClientProtocol = 5
IPad = auth.IPad
AndroidPad = auth.AndroidPad
) )
func (r *UserJoinGroupRequest) Accept() { func (r *UserJoinGroupRequest) Accept() {

View File

@ -2,77 +2,72 @@ package client
import ( import (
"fmt" "fmt"
"reflect"
"runtime/debug" "runtime/debug"
"sync" "sync"
"github.com/Mrs4s/MiraiGo/message" "github.com/Mrs4s/MiraiGo/message"
) )
// protected all EventHandle, since write is very rare, use
// only one lock to save memory
var eventMu sync.RWMutex
type EventHandle[T any] struct {
// QQClient?
handlers []func(client *QQClient, event T)
}
func (handle *EventHandle[T]) Subscribe(handler func(client *QQClient, event T)) {
eventMu.Lock()
defer eventMu.Unlock()
// shrink the slice
newHandlers := make([]func(client *QQClient, event T), len(handle.handlers)+1)
copy(newHandlers, handle.handlers)
newHandlers[len(handle.handlers)] = handler
handle.handlers = newHandlers
}
func (handle *EventHandle[T]) dispatch(client *QQClient, event T) {
eventMu.RLock()
defer func() {
eventMu.RUnlock()
if pan := recover(); pan != nil {
fmt.Printf("event error: %v\n%s", pan, debug.Stack())
}
}()
for _, handler := range handle.handlers {
handler(client, event)
}
if len(client.eventHandlers.subscribedEventHandlers) > 0 {
for _, h := range client.eventHandlers.subscribedEventHandlers {
ht := reflect.TypeOf(h)
for i := 0; i < ht.NumMethod(); i++ {
method := ht.Method(i)
if method.Type.NumIn() != 3 {
continue
}
if method.Type.In(1) != reflect.TypeOf(client) || method.Type.In(2) != reflect.TypeOf(event) {
continue
}
method.Func.Call([]reflect.Value{reflect.ValueOf(h), reflect.ValueOf(client), reflect.ValueOf(event)})
}
}
}
}
type eventHandlers struct { type eventHandlers struct {
// todo: move to event handle privateMessageHandlers []func(*QQClient, *message.PrivateMessage)
tempMessageHandlers []func(*QQClient, *TempMessageEvent)
groupMessageHandlers []func(*QQClient, *message.GroupMessage)
selfPrivateMessageHandlers []func(*QQClient, *message.PrivateMessage)
selfGroupMessageHandlers []func(*QQClient, *message.GroupMessage)
guildChannelMessageHandlers []func(*QQClient, *message.GuildChannelMessage) guildChannelMessageHandlers []func(*QQClient, *message.GuildChannelMessage)
guildMessageReactionsUpdatedHandlers []func(*QQClient, *GuildMessageReactionsUpdatedEvent) guildMessageReactionsUpdatedHandlers []func(*QQClient, *GuildMessageReactionsUpdatedEvent)
guildMessageRecalledHandlers []func(*QQClient, *GuildMessageRecalledEvent) groupMuteEventHandlers []func(*QQClient, *GroupMuteEvent)
guildChannelUpdatedHandlers []func(*QQClient, *GuildChannelUpdatedEvent) groupRecalledHandlers []func(*QQClient, *GroupMessageRecalledEvent)
guildChannelCreatedHandlers []func(*QQClient, *GuildChannelOperationEvent) friendRecalledHandlers []func(*QQClient, *FriendMessageRecalledEvent)
guildChannelDestroyedHandlers []func(*QQClient, *GuildChannelOperationEvent) joinGroupHandlers []func(*QQClient, *GroupInfo)
memberJoinedGuildHandlers []func(*QQClient, *MemberJoinGuildEvent) leaveGroupHandlers []func(*QQClient, *GroupLeaveEvent)
memberJoinedHandlers []func(*QQClient, *MemberJoinGroupEvent)
serverUpdatedHandlers []func(*QQClient, *ServerUpdatedEvent) bool memberLeavedHandlers []func(*QQClient, *MemberLeaveGroupEvent)
subscribedEventHandlers []any memberCardUpdatedHandlers []func(*QQClient, *MemberCardUpdatedEvent)
groupMessageReceiptHandlers sync.Map groupNameUpdatedHandlers []func(*QQClient, *GroupNameUpdatedEvent)
permissionChangedHandlers []func(*QQClient, *MemberPermissionChangedEvent)
groupInvitedHandlers []func(*QQClient, *GroupInvitedRequest)
joinRequestHandlers []func(*QQClient, *UserJoinGroupRequest)
friendRequestHandlers []func(*QQClient, *NewFriendRequest)
newFriendHandlers []func(*QQClient, *NewFriendEvent)
disconnectHandlers []func(*QQClient, *ClientDisconnectedEvent)
logHandlers []func(*QQClient, *LogEvent)
serverUpdatedHandlers []func(*QQClient, *ServerUpdatedEvent) bool
groupNotifyHandlers []func(*QQClient, INotifyEvent)
friendNotifyHandlers []func(*QQClient, INotifyEvent)
memberTitleUpdatedHandlers []func(*QQClient, *MemberSpecialTitleUpdatedEvent)
offlineFileHandlers []func(*QQClient, *OfflineFileEvent)
otherClientStatusChangedHandlers []func(*QQClient, *OtherClientStatusChangedEvent)
groupDigestHandlers []func(*QQClient, *GroupDigestEvent)
groupMessageReceiptHandlers sync.Map
} }
func (c *QQClient) SubscribeEventHandler(handler any) { func (c *QQClient) OnPrivateMessage(f func(*QQClient, *message.PrivateMessage)) {
c.eventHandlers.subscribedEventHandlers = append(c.eventHandlers.subscribedEventHandlers, handler) c.eventHandlers.privateMessageHandlers = append(c.eventHandlers.privateMessageHandlers, f)
}
func (c *QQClient) OnPrivateMessageF(filter func(*message.PrivateMessage) bool, f func(*QQClient, *message.PrivateMessage)) {
c.OnPrivateMessage(func(client *QQClient, msg *message.PrivateMessage) {
if filter(msg) {
f(client, msg)
}
})
}
func (c *QQClient) OnTempMessage(f func(*QQClient, *TempMessageEvent)) {
c.eventHandlers.tempMessageHandlers = append(c.eventHandlers.tempMessageHandlers, f)
}
func (c *QQClient) OnGroupMessage(f func(*QQClient, *message.GroupMessage)) {
c.eventHandlers.groupMessageHandlers = append(c.eventHandlers.groupMessageHandlers, f)
}
func (c *QQClient) OnSelfPrivateMessage(f func(*QQClient, *message.PrivateMessage)) {
c.eventHandlers.selfPrivateMessageHandlers = append(c.eventHandlers.selfPrivateMessageHandlers, f)
}
func (c *QQClient) OnSelfGroupMessage(f func(*QQClient, *message.GroupMessage)) {
c.eventHandlers.selfGroupMessageHandlers = append(c.eventHandlers.selfGroupMessageHandlers, f)
} }
func (s *GuildService) OnGuildChannelMessage(f func(*QQClient, *message.GuildChannelMessage)) { func (s *GuildService) OnGuildChannelMessage(f func(*QQClient, *message.GuildChannelMessage)) {
@ -83,30 +78,99 @@ func (s *GuildService) OnGuildMessageReactionsUpdated(f func(*QQClient, *GuildMe
s.c.eventHandlers.guildMessageReactionsUpdatedHandlers = append(s.c.eventHandlers.guildMessageReactionsUpdatedHandlers, f) s.c.eventHandlers.guildMessageReactionsUpdatedHandlers = append(s.c.eventHandlers.guildMessageReactionsUpdatedHandlers, f)
} }
func (s *GuildService) OnGuildMessageRecalled(f func(*QQClient, *GuildMessageRecalledEvent)) { func (c *QQClient) OnGroupMuted(f func(*QQClient, *GroupMuteEvent)) {
s.c.eventHandlers.guildMessageRecalledHandlers = append(s.c.eventHandlers.guildMessageRecalledHandlers, f) c.eventHandlers.groupMuteEventHandlers = append(c.eventHandlers.groupMuteEventHandlers, f)
} }
func (s *GuildService) OnGuildChannelUpdated(f func(*QQClient, *GuildChannelUpdatedEvent)) { func (c *QQClient) OnJoinGroup(f func(*QQClient, *GroupInfo)) {
s.c.eventHandlers.guildChannelUpdatedHandlers = append(s.c.eventHandlers.guildChannelUpdatedHandlers, f) c.eventHandlers.joinGroupHandlers = append(c.eventHandlers.joinGroupHandlers, f)
} }
func (s *GuildService) OnGuildChannelCreated(f func(*QQClient, *GuildChannelOperationEvent)) { func (c *QQClient) OnLeaveGroup(f func(*QQClient, *GroupLeaveEvent)) {
s.c.eventHandlers.guildChannelCreatedHandlers = append(s.c.eventHandlers.guildChannelCreatedHandlers, f) c.eventHandlers.leaveGroupHandlers = append(c.eventHandlers.leaveGroupHandlers, f)
} }
func (s *GuildService) OnGuildChannelDestroyed(f func(*QQClient, *GuildChannelOperationEvent)) { func (c *QQClient) OnGroupMemberJoined(f func(*QQClient, *MemberJoinGroupEvent)) {
s.c.eventHandlers.guildChannelDestroyedHandlers = append(s.c.eventHandlers.guildChannelDestroyedHandlers, f) c.eventHandlers.memberJoinedHandlers = append(c.eventHandlers.memberJoinedHandlers, f)
} }
func (s *GuildService) OnMemberJoinedGuild(f func(*QQClient, *MemberJoinGuildEvent)) { func (c *QQClient) OnGroupMemberLeaved(f func(*QQClient, *MemberLeaveGroupEvent)) {
s.c.eventHandlers.memberJoinedGuildHandlers = append(s.c.eventHandlers.memberJoinedGuildHandlers, f) c.eventHandlers.memberLeavedHandlers = append(c.eventHandlers.memberLeavedHandlers, f)
}
func (c *QQClient) OnGroupMemberCardUpdated(f func(*QQClient, *MemberCardUpdatedEvent)) {
c.eventHandlers.memberCardUpdatedHandlers = append(c.eventHandlers.memberCardUpdatedHandlers, f)
}
func (c *QQClient) OnGroupNameUpdated(f func(*QQClient, *GroupNameUpdatedEvent)) {
c.eventHandlers.groupNameUpdatedHandlers = append(c.eventHandlers.groupNameUpdatedHandlers, f)
}
func (c *QQClient) OnGroupMemberPermissionChanged(f func(*QQClient, *MemberPermissionChangedEvent)) {
c.eventHandlers.permissionChangedHandlers = append(c.eventHandlers.permissionChangedHandlers, f)
}
func (c *QQClient) OnGroupMessageRecalled(f func(*QQClient, *GroupMessageRecalledEvent)) {
c.eventHandlers.groupRecalledHandlers = append(c.eventHandlers.groupRecalledHandlers, f)
}
func (c *QQClient) OnFriendMessageRecalled(f func(*QQClient, *FriendMessageRecalledEvent)) {
c.eventHandlers.friendRecalledHandlers = append(c.eventHandlers.friendRecalledHandlers, f)
}
func (c *QQClient) OnGroupInvited(f func(*QQClient, *GroupInvitedRequest)) {
c.eventHandlers.groupInvitedHandlers = append(c.eventHandlers.groupInvitedHandlers, f)
}
func (c *QQClient) OnUserWantJoinGroup(f func(*QQClient, *UserJoinGroupRequest)) {
c.eventHandlers.joinRequestHandlers = append(c.eventHandlers.joinRequestHandlers, f)
}
func (c *QQClient) OnNewFriendRequest(f func(*QQClient, *NewFriendRequest)) {
c.eventHandlers.friendRequestHandlers = append(c.eventHandlers.friendRequestHandlers, f)
}
func (c *QQClient) OnNewFriendAdded(f func(*QQClient, *NewFriendEvent)) {
c.eventHandlers.newFriendHandlers = append(c.eventHandlers.newFriendHandlers, f)
}
func (c *QQClient) OnDisconnected(f func(*QQClient, *ClientDisconnectedEvent)) {
c.eventHandlers.disconnectHandlers = append(c.eventHandlers.disconnectHandlers, f)
} }
func (c *QQClient) OnServerUpdated(f func(*QQClient, *ServerUpdatedEvent) bool) { func (c *QQClient) OnServerUpdated(f func(*QQClient, *ServerUpdatedEvent) bool) {
c.eventHandlers.serverUpdatedHandlers = append(c.eventHandlers.serverUpdatedHandlers, f) c.eventHandlers.serverUpdatedHandlers = append(c.eventHandlers.serverUpdatedHandlers, f)
} }
func (c *QQClient) OnReceivedOfflineFile(f func(*QQClient, *OfflineFileEvent)) {
c.eventHandlers.offlineFileHandlers = append(c.eventHandlers.offlineFileHandlers, f)
}
func (c *QQClient) OnOtherClientStatusChanged(f func(*QQClient, *OtherClientStatusChangedEvent)) {
c.eventHandlers.otherClientStatusChangedHandlers = append(c.eventHandlers.otherClientStatusChangedHandlers, f)
}
func (c *QQClient) OnLog(f func(*QQClient, *LogEvent)) {
c.eventHandlers.logHandlers = append(c.eventHandlers.logHandlers, f)
}
func (c *QQClient) OnGroupNotify(f func(*QQClient, INotifyEvent)) {
c.eventHandlers.groupNotifyHandlers = append(c.eventHandlers.groupNotifyHandlers, f)
}
func (c *QQClient) OnFriendNotify(f func(*QQClient, INotifyEvent)) {
c.eventHandlers.friendNotifyHandlers = append(c.eventHandlers.friendNotifyHandlers, f)
}
func (c *QQClient) OnMemberSpecialTitleUpdated(f func(*QQClient, *MemberSpecialTitleUpdatedEvent)) {
c.eventHandlers.memberTitleUpdatedHandlers = append(c.eventHandlers.memberTitleUpdatedHandlers, f)
}
// OnGroupDigest 群精华消息事件注册
func (c *QQClient) OnGroupDigest(f func(*QQClient, *GroupDigestEvent)) {
c.eventHandlers.groupDigestHandlers = append(c.eventHandlers.groupDigestHandlers, f)
}
func NewUinFilterPrivate(uin int64) func(*message.PrivateMessage) bool { func NewUinFilterPrivate(uin int64) func(*message.PrivateMessage) bool {
return func(msg *message.PrivateMessage) bool { return func(msg *message.PrivateMessage) bool {
return msg.Sender.Uin == uin return msg.Sender.Uin == uin
@ -121,6 +185,61 @@ func (c *QQClient) onGroupMessageReceipt(id string, f ...func(*QQClient, *groupM
c.eventHandlers.groupMessageReceiptHandlers.LoadOrStore(id, f[0]) c.eventHandlers.groupMessageReceiptHandlers.LoadOrStore(id, f[0])
} }
func (c *QQClient) dispatchPrivateMessage(msg *message.PrivateMessage) {
if msg == nil {
return
}
for _, f := range c.eventHandlers.privateMessageHandlers {
cover(func() {
f(c, msg)
})
}
}
func (c *QQClient) dispatchTempMessage(e *TempMessageEvent) {
if e == nil {
return
}
for _, f := range c.eventHandlers.tempMessageHandlers {
cover(func() {
f(c, e)
})
}
}
func (c *QQClient) dispatchGroupMessage(msg *message.GroupMessage) {
if msg == nil {
return
}
for _, f := range c.eventHandlers.groupMessageHandlers {
cover(func() {
f(c, msg)
})
}
}
func (c *QQClient) dispatchPrivateMessageSelf(msg *message.PrivateMessage) {
if msg == nil {
return
}
for _, f := range c.eventHandlers.selfPrivateMessageHandlers {
cover(func() {
f(c, msg)
})
}
}
func (c *QQClient) dispatchGroupMessageSelf(msg *message.GroupMessage) {
if msg == nil {
return
}
for _, f := range c.eventHandlers.selfGroupMessageHandlers {
cover(func() {
f(c, msg)
})
}
}
func (c *QQClient) dispatchGuildChannelMessage(msg *message.GuildChannelMessage) { func (c *QQClient) dispatchGuildChannelMessage(msg *message.GuildChannelMessage) {
if msg == nil { if msg == nil {
return return
@ -143,55 +262,110 @@ func (c *QQClient) dispatchGuildMessageReactionsUpdatedEvent(e *GuildMessageReac
} }
} }
func (c *QQClient) dispatchGuildMessageRecalledEvent(e *GuildMessageRecalledEvent) { func (c *QQClient) dispatchGroupMuteEvent(e *GroupMuteEvent) {
if e == nil { if e == nil {
return return
} }
for _, f := range c.eventHandlers.guildMessageRecalledHandlers { for _, f := range c.eventHandlers.groupMuteEventHandlers {
cover(func() { cover(func() {
f(c, e) f(c, e)
}) })
} }
} }
func (c *QQClient) dispatchGuildChannelUpdatedEvent(e *GuildChannelUpdatedEvent) { func (c *QQClient) dispatchGroupMessageRecalledEvent(e *GroupMessageRecalledEvent) {
if e == nil { if e == nil {
return return
} }
for _, f := range c.eventHandlers.guildChannelUpdatedHandlers { for _, f := range c.eventHandlers.groupRecalledHandlers {
cover(func() { cover(func() {
f(c, e) f(c, e)
}) })
} }
} }
func (c *QQClient) dispatchGuildChannelCreatedEvent(e *GuildChannelOperationEvent) { func (c *QQClient) dispatchFriendMessageRecalledEvent(e *FriendMessageRecalledEvent) {
if e == nil { if e == nil {
return return
} }
for _, f := range c.eventHandlers.guildChannelCreatedHandlers { for _, f := range c.eventHandlers.friendRecalledHandlers {
cover(func() { cover(func() {
f(c, e) f(c, e)
}) })
} }
} }
func (c *QQClient) dispatchGuildChannelDestroyedEvent(e *GuildChannelOperationEvent) { func (c *QQClient) dispatchJoinGroupEvent(group *GroupInfo) {
if group == nil {
return
}
for _, f := range c.eventHandlers.joinGroupHandlers {
cover(func() {
f(c, group)
})
}
}
func (c *QQClient) dispatchLeaveGroupEvent(e *GroupLeaveEvent) {
if e == nil { if e == nil {
return return
} }
for _, f := range c.eventHandlers.guildChannelDestroyedHandlers { for _, f := range c.eventHandlers.leaveGroupHandlers {
cover(func() { cover(func() {
f(c, e) f(c, e)
}) })
} }
} }
func (c *QQClient) dispatchMemberJoinedGuildEvent(e *MemberJoinGuildEvent) { func (c *QQClient) dispatchNewMemberEvent(e *MemberJoinGroupEvent) {
if e == nil { if e == nil {
return return
} }
for _, f := range c.eventHandlers.memberJoinedGuildHandlers { for _, f := range c.eventHandlers.memberJoinedHandlers {
cover(func() {
f(c, e)
})
}
}
func (c *QQClient) dispatchMemberLeaveEvent(e *MemberLeaveGroupEvent) {
if e == nil {
return
}
for _, f := range c.eventHandlers.memberLeavedHandlers {
cover(func() {
f(c, e)
})
}
}
func (c *QQClient) dispatchMemberCardUpdatedEvent(e *MemberCardUpdatedEvent) {
if e == nil {
return
}
for _, f := range c.eventHandlers.memberCardUpdatedHandlers {
cover(func() {
f(c, e)
})
}
}
func (c *QQClient) dispatchGroupNameUpdatedEvent(e *GroupNameUpdatedEvent) {
if e == nil {
return
}
for _, f := range c.eventHandlers.groupNameUpdatedHandlers {
cover(func() {
f(c, e)
})
}
}
func (c *QQClient) dispatchPermissionChanged(e *MemberPermissionChangedEvent) {
if e == nil {
return
}
for _, f := range c.eventHandlers.permissionChangedHandlers {
cover(func() { cover(func() {
f(c, e) f(c, e)
}) })
@ -199,12 +373,144 @@ func (c *QQClient) dispatchMemberJoinedGuildEvent(e *MemberJoinGuildEvent) {
} }
func (c *QQClient) dispatchGroupMessageReceiptEvent(e *groupMessageReceiptEvent) { func (c *QQClient) dispatchGroupMessageReceiptEvent(e *groupMessageReceiptEvent) {
c.eventHandlers.groupMessageReceiptHandlers.Range(func(_, f any) bool { c.eventHandlers.groupMessageReceiptHandlers.Range(func(_, f interface{}) bool {
go f.(func(*QQClient, *groupMessageReceiptEvent))(c, e) go f.(func(*QQClient, *groupMessageReceiptEvent))(c, e)
return true return true
}) })
} }
func (c *QQClient) dispatchGroupInvitedEvent(e *GroupInvitedRequest) {
if e == nil {
return
}
for _, f := range c.eventHandlers.groupInvitedHandlers {
cover(func() {
f(c, e)
})
}
}
func (c *QQClient) dispatchJoinGroupRequest(r *UserJoinGroupRequest) {
if r == nil {
return
}
for _, f := range c.eventHandlers.joinRequestHandlers {
cover(func() {
f(c, r)
})
}
}
func (c *QQClient) dispatchNewFriendRequest(r *NewFriendRequest) {
if r == nil {
return
}
for _, f := range c.eventHandlers.friendRequestHandlers {
cover(func() {
f(c, r)
})
}
}
func (c *QQClient) dispatchNewFriendEvent(e *NewFriendEvent) {
if e == nil {
return
}
for _, f := range c.eventHandlers.newFriendHandlers {
cover(func() {
f(c, e)
})
}
}
func (c *QQClient) dispatchGroupNotifyEvent(e INotifyEvent) {
if e == nil {
return
}
for _, f := range c.eventHandlers.groupNotifyHandlers {
cover(func() {
f(c, e)
})
}
}
func (c *QQClient) dispatchFriendNotifyEvent(e INotifyEvent) {
if e == nil {
return
}
for _, f := range c.eventHandlers.friendNotifyHandlers {
cover(func() {
f(c, e)
})
}
}
func (c *QQClient) dispatchMemberSpecialTitleUpdateEvent(e *MemberSpecialTitleUpdatedEvent) {
if e == nil {
return
}
for _, f := range c.eventHandlers.memberTitleUpdatedHandlers {
cover(func() {
f(c, e)
})
}
}
func (c *QQClient) dispatchDisconnectEvent(e *ClientDisconnectedEvent) {
if e == nil {
return
}
for _, f := range c.eventHandlers.disconnectHandlers {
cover(func() {
f(c, e)
})
}
}
func (c *QQClient) dispatchOfflineFileEvent(e *OfflineFileEvent) {
if e == nil {
return
}
for _, f := range c.eventHandlers.offlineFileHandlers {
cover(func() {
f(c, e)
})
}
}
func (c *QQClient) dispatchOtherClientStatusChangedEvent(e *OtherClientStatusChangedEvent) {
if e == nil {
return
}
for _, f := range c.eventHandlers.otherClientStatusChangedHandlers {
cover(func() {
f(c, e)
})
}
}
func (c *QQClient) dispatchGroupDigestEvent(e *GroupDigestEvent) {
if e == nil {
return
}
for _, f := range c.eventHandlers.groupDigestHandlers {
cover(func() {
f(c, e)
})
}
}
func (c *QQClient) dispatchLogEvent(e *LogEvent) {
if e == nil {
return
}
for _, f := range c.eventHandlers.logHandlers {
cover(func() {
f(c, e)
})
}
}
func cover(f func()) { func cover(f func()) {
defer func() { defer func() {
if pan := recover(); pan != nil { if pan := recover(); pan != nil {

View File

@ -3,11 +3,12 @@ package client
import ( import (
"fmt" "fmt"
"github.com/pkg/errors" "github.com/Mrs4s/MiraiGo/internal/packets"
"github.com/pkg/errors"
"google.golang.org/protobuf/proto"
"github.com/Mrs4s/MiraiGo/client/internal/network"
"github.com/Mrs4s/MiraiGo/client/pb/faceroam" "github.com/Mrs4s/MiraiGo/client/pb/faceroam"
"github.com/Mrs4s/MiraiGo/internal/proto"
) )
type CustomFace struct { type CustomFace struct {
@ -28,22 +29,24 @@ func (c *QQClient) GetCustomFaces() ([]*CustomFace, error) {
} }
func (c *QQClient) buildFaceroamRequestPacket() (uint16, []byte) { func (c *QQClient) buildFaceroamRequestPacket() (uint16, []byte) {
seq := c.nextSeq()
payload, _ := proto.Marshal(&faceroam.FaceroamReqBody{ payload, _ := proto.Marshal(&faceroam.FaceroamReqBody{
Comm: &faceroam.PlatInfo{ Comm: &faceroam.PlatInfo{
Implat: proto.Int64(109), Implat: proto.Int64(109),
Osver: proto.String(string(c.Device().Version.Release)), Osver: proto.String(string(c.deviceInfo.Version.Release)),
Mqqver: proto.Some(c.version().SortVersionName), Mqqver: &c.version.SortVersionName,
}, },
Uin: proto.Uint64(uint64(c.Uin)), Uin: proto.Uint64(uint64(c.Uin)),
SubCmd: proto.Uint32(1), SubCmd: proto.Uint32(1),
ReqUserInfo: &faceroam.ReqUserInfo{}, ReqUserInfo: &faceroam.ReqUserInfo{},
}) })
return c.uniPacket("Faceroam.OpReq", payload) packet := packets.BuildUniPacket(c.Uin, seq, "Faceroam.OpReq", 1, c.OutGoingPacketSessionId, EmptyBytes, c.sigInfo.d2Key, payload)
return seq, packet
} }
func decodeFaceroamResponse(c *QQClient, pkt *network.Packet) (any, error) { func decodeFaceroamResponse(c *QQClient, _ *incomingPacketInfo, payload []byte) (interface{}, error) {
rsp := faceroam.FaceroamRspBody{} rsp := faceroam.FaceroamRspBody{}
if err := proto.Unmarshal(pkt.Payload, &rsp); err != nil { if err := proto.Unmarshal(payload, &rsp); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
if rsp.RspUserInfo == nil { if rsp.RspUserInfo == nil {
@ -53,7 +56,7 @@ func decodeFaceroamResponse(c *QQClient, pkt *network.Packet) (any, error) {
for i := len(rsp.RspUserInfo.Filename) - 1; i >= 0; i-- { for i := len(rsp.RspUserInfo.Filename) - 1; i >= 0; i-- {
res[len(rsp.RspUserInfo.Filename)-1-i] = &CustomFace{ res[len(rsp.RspUserInfo.Filename)-1-i] = &CustomFace{
ResId: rsp.RspUserInfo.Filename[i], ResId: rsp.RspUserInfo.Filename[i],
Url: fmt.Sprintf("https://p.qpic.cn/%s/%d/%s/0", rsp.RspUserInfo.Bid.Unwrap(), c.Uin, rsp.RspUserInfo.Filename[i]), Url: fmt.Sprintf("https://p.qpic.cn/%s/%d/%s/0", rsp.RspUserInfo.GetBid(), c.Uin, rsp.RspUserInfo.Filename[i]),
} }
} }
return res, nil return res, nil

View File

@ -2,126 +2,456 @@ package client
import ( import (
"crypto/md5" "crypto/md5"
crand "crypto/rand"
"encoding/hex" "encoding/hex"
"encoding/json"
"fmt" "fmt"
"math/rand" "math/rand"
"net" "net"
"net/netip"
"sort" "sort"
"strconv" "strconv"
"strings" "strings"
"sync"
"time" "time"
"github.com/pkg/errors" "github.com/pkg/errors"
protobuf "github.com/segmentio/encoding/proto"
"google.golang.org/protobuf/proto"
"github.com/Mrs4s/MiraiGo/binary" "github.com/Mrs4s/MiraiGo/binary"
"github.com/Mrs4s/MiraiGo/binary/jce" "github.com/Mrs4s/MiraiGo/binary/jce"
"github.com/Mrs4s/MiraiGo/client/internal/auth" devinfo "github.com/Mrs4s/MiraiGo/client/pb"
"github.com/Mrs4s/MiraiGo/client/pb/msg" "github.com/Mrs4s/MiraiGo/internal/protobuf/data/msg"
"github.com/Mrs4s/MiraiGo/client/pb/oidb" "github.com/Mrs4s/MiraiGo/internal/protobuf/data/oidb"
"github.com/Mrs4s/MiraiGo/internal/proto" proto2 "github.com/Mrs4s/MiraiGo/internal/protobuf/proto"
"github.com/Mrs4s/MiraiGo/message" "github.com/Mrs4s/MiraiGo/message"
"github.com/Mrs4s/MiraiGo/utils" "github.com/Mrs4s/MiraiGo/utils"
) )
type ( type (
DeviceInfo = auth.Device DeviceInfo struct {
Version = auth.OSVersion Display []byte
) Product []byte
Device []byte
var EmptyBytes = make([]byte, 0) Board []byte
Brand []byte
func GenRandomDevice() *DeviceInfo { Model []byte
r := make([]byte, 16) Bootloader []byte
crand.Read(r) FingerPrint []byte
const numberRange = "0123456789" BootId []byte
ProcVersion []byte
var device = &DeviceInfo{ BaseBand []byte
Product: []byte("mirai"), SimInfo []byte
Device: []byte("mirai"), OSType []byte
Board: []byte("mirai"), MacAddress []byte
Brand: []byte("mamoe"), IpAddress []byte
Model: []byte("mirai"), WifiBSSID []byte
Bootloader: []byte("unknown"), WifiSSID []byte
BootId: []byte("cb886ae2-00b6-4d68-a230-787f111d12c7"), IMSIMd5 []byte
ProcVersion: []byte("Linux version 3.0.31-cb886ae2 (android-build@xxx.xxx.xxx.xxx.com)"), IMEI string
BaseBand: EmptyBytes, AndroidId []byte
SimInfo: []byte("T-Mobile"), APN []byte
OSType: []byte("android"), VendorName []byte
MacAddress: []byte("00:50:56:C0:00:08"), VendorOSName []byte
IpAddress: []byte{10, 0, 1, 3}, // 10.0.1.3 Guid []byte
WifiBSSID: []byte("00:50:56:C0:00:08"), TgtgtKey []byte
WifiSSID: []byte("<unknown ssid>"), Protocol ClientProtocol
IMEI: "468356291846738", Version *Version
AndroidId: []byte("MIRAI.123456.001"),
APN: []byte("wifi"),
VendorName: []byte("MIUI"),
VendorOSName: []byte("mirai"),
Protocol: AndroidPad,
Version: &Version{
Incremental: []byte("5891938"),
Release: []byte("10"),
CodeName: []byte("REL"),
SDK: 29,
},
} }
device.Display = []byte("MIRAI." + utils.RandomStringRange(6, numberRange) + ".001") Version struct {
device.FingerPrint = []byte("mamoe/mirai/mirai:10/MIRAI.200122.001/" + utils.RandomStringRange(7, numberRange) + ":user/release-keys") Incremental []byte
device.BootId = binary.GenUUID(r) Release []byte
device.ProcVersion = []byte("Linux version 3.0.31-" + utils.RandomString(8) + " (android-build@xxx.xxx.xxx.xxx.com)") CodeName []byte
crand.Read(r) Sdk uint32
}
DeviceInfoFile struct {
Display string `json:"display"`
Product string `json:"product"`
Device string `json:"device"`
Board string `json:"board"`
Model string `json:"model"`
FingerPrint string `json:"finger_print"`
BootId string `json:"boot_id"`
ProcVersion string `json:"proc_version"`
Protocol int `json:"protocol"` // 0: Pad 1: Phone 2: Watch
IMEI string `json:"imei"`
Brand string `json:"brand"`
Bootloader string `json:"bootloader"`
BaseBand string `json:"base_band"`
Version *VersionFile `json:"version"`
SimInfo string `json:"sim_info"`
OsType string `json:"os_type"`
MacAddress string `json:"mac_address"`
IpAddress []int32 `json:"ip_address"`
WifiBSSID string `json:"wifi_bssid"`
WifiSSID string `json:"wifi_ssid"`
ImsiMd5 string `json:"imsi_md5"`
AndroidId string `json:"android_id"`
Apn string `json:"apn"`
VendorName string `json:"vendor_name"`
VendorOSName string `json:"vendor_os_name"`
}
VersionFile struct {
Incremental string `json:"incremental"`
Release string `json:"release"`
Codename string `json:"codename"`
Sdk uint32 `json:"sdk"`
}
groupMessageBuilder struct {
MessageSlices []*msg.Message
}
versionInfo struct {
ApkSign []byte
ApkId string
SortVersionName string
SdkVersion string
AppId uint32
SubAppId uint32
BuildTime uint32
SSOVersion uint32
MiscBitmap uint32
SubSigmap uint32
MainSigMap uint32
Protocol ClientProtocol
}
incomingPacketInfo struct {
CommandName string
SequenceId uint16
Params requestParams
}
requestParams map[string]interface{}
)
var SystemDeviceInfo = &DeviceInfo{
Display: []byte("MIRAI.123456.001"),
Product: []byte("mirai"),
Device: []byte("mirai"),
Board: []byte("mirai"),
Brand: []byte("mamoe"),
Model: []byte("mirai"),
Bootloader: []byte("unknown"),
FingerPrint: []byte("mamoe/mirai/mirai:10/MIRAI.200122.001/1234567:user/release-keys"),
BootId: []byte("cb886ae2-00b6-4d68-a230-787f111d12c7"),
ProcVersion: []byte("Linux version 3.0.31-cb886ae2 (android-build@xxx.xxx.xxx.xxx.com)"),
BaseBand: []byte{},
SimInfo: []byte("T-Mobile"),
OSType: []byte("android"),
MacAddress: []byte("00:50:56:C0:00:08"),
IpAddress: []byte{10, 0, 1, 3}, // 10.0.1.3
WifiBSSID: []byte("00:50:56:C0:00:08"),
WifiSSID: []byte("<unknown ssid>"),
IMEI: "468356291846738",
AndroidId: []byte("MIRAI.123456.001"),
APN: []byte("wifi"),
VendorName: []byte("MIUI"),
VendorOSName: []byte("mirai"),
Protocol: IPad,
Version: &Version{
Incremental: []byte("5891938"),
Release: []byte("10"),
CodeName: []byte("REL"),
Sdk: 29,
},
}
var (
EmptyBytes = []byte{}
NumberRange = "0123456789"
)
func init() {
r := make([]byte, 16)
rand.Read(r)
t := md5.Sum(r) t := md5.Sum(r)
device.IMSIMd5 = t[:] SystemDeviceInfo.IMSIMd5 = t[:]
device.IMEI = GenIMEI() SystemDeviceInfo.GenNewGuid()
SystemDeviceInfo.GenNewTgtgtKey()
}
func GenRandomDevice() {
r := make([]byte, 16)
rand.Read(r)
SystemDeviceInfo.Display = []byte("MIRAI." + utils.RandomStringRange(6, NumberRange) + ".001")
SystemDeviceInfo.FingerPrint = []byte("mamoe/mirai/mirai:10/MIRAI.200122.001/" + utils.RandomStringRange(7, NumberRange) + ":user/release-keys")
SystemDeviceInfo.BootId = binary.GenUUID(r)
SystemDeviceInfo.ProcVersion = []byte("Linux version 3.0.31-" + utils.RandomString(8) + " (android-build@xxx.xxx.xxx.xxx.com)")
rand.Read(r)
t := md5.Sum(r)
SystemDeviceInfo.IMSIMd5 = t[:]
SystemDeviceInfo.IMEI = GenIMEI()
r = make([]byte, 8) r = make([]byte, 8)
crand.Read(r) rand.Read(r)
hex.Encode(device.AndroidId, r) hex.Encode(SystemDeviceInfo.AndroidId, r)
device.GenNewGuid() SystemDeviceInfo.GenNewGuid()
device.GenNewTgtgtKey() SystemDeviceInfo.GenNewTgtgtKey()
device.RequestQImei() }
return device
func genVersionInfo(p ClientProtocol) *versionInfo {
switch p {
case AndroidPhone: // Dumped by mirai from qq android v8.8.38
return &versionInfo{
ApkId: "com.tencent.mobileqq",
AppId: 537100432,
SubAppId: 537100432,
SortVersionName: "8.8.38",
BuildTime: 1634310940,
ApkSign: []byte{0xA6, 0xB7, 0x45, 0xBF, 0x24, 0xA2, 0xC2, 0x77, 0x52, 0x77, 0x16, 0xF6, 0xF3, 0x6E, 0xB6, 0x8D},
SdkVersion: "6.0.0.2487",
SSOVersion: 16,
MiscBitmap: 184024956,
SubSigmap: 0x10400,
MainSigMap: 34869472,
Protocol: p,
}
case AndroidWatch:
return &versionInfo{
ApkId: "com.tencent.qqlite",
AppId: 537064446,
SubAppId: 537064446,
SortVersionName: "2.0.5",
BuildTime: 1559564731,
ApkSign: []byte{0xA6, 0xB7, 0x45, 0xBF, 0x24, 0xA2, 0xC2, 0x77, 0x52, 0x77, 0x16, 0xF6, 0xF3, 0x6E, 0xB6, 0x8D},
SdkVersion: "6.0.0.236",
SSOVersion: 5,
MiscBitmap: 16252796,
SubSigmap: 0x10400,
MainSigMap: 34869472,
Protocol: p,
}
case IPad:
return &versionInfo{
ApkId: "com.tencent.minihd.qq",
AppId: 537097188,
SubAppId: 537097188,
SortVersionName: "8.8.35",
BuildTime: 1595836208,
ApkSign: []byte{170, 57, 120, 244, 31, 217, 111, 249, 145, 74, 102, 158, 24, 100, 116, 199},
SdkVersion: "6.0.0.2433",
SSOVersion: 12,
MiscBitmap: 150470524,
SubSigmap: 66560,
MainSigMap: 1970400,
Protocol: p,
}
case MacOS:
return &versionInfo{
ApkId: "com.tencent.minihd.qq",
AppId: 537064315,
SubAppId: 537064315,
SortVersionName: "5.8.9",
BuildTime: 1595836208,
ApkSign: []byte{170, 57, 120, 244, 31, 217, 111, 249, 145, 74, 102, 158, 24, 100, 116, 199},
SdkVersion: "6.0.0.2433",
SSOVersion: 12,
MiscBitmap: 150470524,
SubSigmap: 66560,
MainSigMap: 1970400,
Protocol: p,
}
case QiDian:
return &versionInfo{
ApkId: "com.tencent.qidian",
AppId: 537061386,
SubAppId: 537036590,
SortVersionName: "3.8.6",
BuildTime: 1556628836,
ApkSign: []byte{160, 30, 236, 171, 133, 233, 227, 186, 43, 15, 106, 21, 140, 133, 92, 41},
SdkVersion: "6.0.0.2365",
SSOVersion: 5,
MiscBitmap: 49807228,
SubSigmap: 66560,
MainSigMap: 34869472,
Protocol: p,
}
}
return nil
}
func (info *DeviceInfo) ToJson() []byte {
f := &DeviceInfoFile{
Display: string(info.Display),
Product: string(info.Product),
Device: string(info.Device),
Board: string(info.Board),
Model: string(info.Model),
FingerPrint: string(info.FingerPrint),
BootId: string(info.BootId),
ProcVersion: string(info.ProcVersion),
IMEI: info.IMEI,
Brand: string(info.Brand),
Bootloader: string(info.Bootloader),
BaseBand: string(info.BaseBand),
AndroidId: string(info.AndroidId),
Version: &VersionFile{
Incremental: string(info.Version.Incremental),
Release: string(info.Version.Release),
Codename: string(info.Version.CodeName),
Sdk: info.Version.Sdk,
},
SimInfo: string(info.SimInfo),
OsType: string(info.OSType),
MacAddress: string(info.MacAddress),
IpAddress: []int32{int32(info.IpAddress[0]), int32(info.IpAddress[1]), int32(info.IpAddress[2]), int32(info.IpAddress[3])},
WifiBSSID: string(info.WifiBSSID),
WifiSSID: string(info.WifiSSID),
ImsiMd5: hex.EncodeToString(info.IMSIMd5),
Apn: string(info.APN),
VendorName: string(info.VendorName),
VendorOSName: string(info.VendorOSName),
Protocol: func() int {
switch info.Protocol {
case IPad:
return 0
case AndroidPhone:
return 1
case AndroidWatch:
return 2
case MacOS:
return 3
case QiDian:
return 4
}
return 0
}(),
}
d, _ := json.Marshal(f)
return d
}
func (info *DeviceInfo) ReadJson(d []byte) error {
var f DeviceInfoFile
if err := json.Unmarshal(d, &f); err != nil {
return errors.Wrap(err, "failed to unmarshal json message")
}
SetIfNotEmpty := func(trg *[]byte, str string) {
if str != "" {
*trg = []byte(str)
}
}
SetIfNotEmpty(&info.Display, f.Display)
SetIfNotEmpty(&info.Product, f.Product)
SetIfNotEmpty(&info.Device, f.Device)
SetIfNotEmpty(&info.Board, f.Board)
SetIfNotEmpty(&info.Brand, f.Brand)
SetIfNotEmpty(&info.Model, f.Model)
SetIfNotEmpty(&info.Bootloader, f.Bootloader)
SetIfNotEmpty(&info.FingerPrint, f.FingerPrint)
SetIfNotEmpty(&info.BootId, f.BootId)
SetIfNotEmpty(&info.ProcVersion, f.ProcVersion)
SetIfNotEmpty(&info.BaseBand, f.BaseBand)
SetIfNotEmpty(&info.SimInfo, f.SimInfo)
SetIfNotEmpty(&info.OSType, f.OsType)
SetIfNotEmpty(&info.MacAddress, f.MacAddress)
if len(f.IpAddress) == 4 {
info.IpAddress = []byte{byte(f.IpAddress[0]), byte(f.IpAddress[1]), byte(f.IpAddress[2]), byte(f.IpAddress[3])}
}
SetIfNotEmpty(&info.WifiBSSID, f.WifiBSSID)
SetIfNotEmpty(&info.WifiSSID, f.WifiSSID)
if len(f.ImsiMd5) != 0 {
imsiMd5, err := hex.DecodeString(f.ImsiMd5)
if err != nil {
info.IMSIMd5 = imsiMd5
}
}
if f.IMEI != "" {
info.IMEI = f.IMEI
}
SetIfNotEmpty(&info.APN, f.Apn)
SetIfNotEmpty(&info.VendorName, f.VendorName)
SetIfNotEmpty(&info.VendorOSName, f.VendorOSName)
SetIfNotEmpty(&info.AndroidId, f.AndroidId)
if f.AndroidId == "" {
info.AndroidId = info.Display // ?
}
switch f.Protocol {
case 1:
info.Protocol = AndroidPhone
case 2:
info.Protocol = AndroidWatch
case 3:
info.Protocol = MacOS
case 4:
info.Protocol = QiDian
default:
info.Protocol = IPad
}
SystemDeviceInfo.GenNewGuid()
SystemDeviceInfo.GenNewTgtgtKey()
return nil
}
func (info *DeviceInfo) GenNewGuid() {
t := md5.Sum(append(info.AndroidId, info.MacAddress...))
info.Guid = t[:]
}
func (info *DeviceInfo) GenNewTgtgtKey() {
r := make([]byte, 16)
rand.Read(r)
h := md5.New()
h.Write(r)
h.Write(info.Guid)
info.TgtgtKey = h.Sum(nil)
}
func (info *DeviceInfo) GenDeviceInfoData() []byte {
m := &devinfo.DeviceInfo{
Bootloader: string(info.Bootloader),
ProcVersion: string(info.ProcVersion),
Codename: string(info.Version.CodeName),
Incremental: string(info.Version.Incremental),
Fingerprint: string(info.FingerPrint),
BootId: string(info.BootId),
AndroidId: string(info.AndroidId),
BaseBand: string(info.BaseBand),
InnerVersion: string(info.Version.Incremental),
}
data, err := proto.Marshal(m)
if err != nil {
panic(errors.Wrap(err, "failed to unmarshal protobuf message"))
}
return data
} }
func GenIMEI() string { func GenIMEI() string {
sum := 0 // the control sum of digits sum := 0 // the control sum of digits
var final strings.Builder var final strings.Builder
randGen := rand.New(rand.NewSource(time.Now().UnixNano())) randSrc := rand.NewSource(time.Now().UnixNano())
randGen := rand.New(randSrc)
for i := 0; i < 14; i++ { // generating all the base digits for i := 0; i < 14; i++ { // generating all the base digits
toAdd := randGen.Intn(10) toAdd := randGen.Intn(10)
final.WriteString(strconv.Itoa(toAdd))
if (i+1)%2 == 0 { // special proc for every 2nd one if (i+1)%2 == 0 { // special proc for every 2nd one
toAdd *= 2 toAdd *= 2
if toAdd >= 10 { if toAdd >= 10 {
toAdd = (toAdd % 10) + 1 toAdd = (toAdd % 10) + 1
} }
} }
sum += toAdd // and even add them here! sum += toAdd
final.WriteString(fmt.Sprintf("%d", toAdd)) // and even printing them here!
} }
ctrlDigit := (sum * 9) % 10 // calculating the control digit ctrlDigit := (sum * 9) % 10 // calculating the control digit
final.WriteString(strconv.Itoa(ctrlDigit)) final.WriteString(fmt.Sprintf("%d", ctrlDigit))
return final.String() return final.String()
} }
func UpdateAppVersion(protocolType auth.ProtocolType, data []byte) error { func getSSOAddress() ([]*net.TCPAddr, error) {
if _, ok := auth.AppVersions[protocolType]; !ok { protocol := genVersionInfo(SystemDeviceInfo.Protocol)
return errors.New("unknown protocol type: " + strconv.Itoa(int(protocolType)))
}
return auth.AppVersions[protocolType].UpdateFromJson(data)
}
func getSSOAddress(device *auth.Device) ([]netip.AddrPort, error) {
protocol := device.Protocol.Version()
key, _ := hex.DecodeString("F0441F5FF42DA58FDCF7949ABA62D411") key, _ := hex.DecodeString("F0441F5FF42DA58FDCF7949ABA62D411")
payload := jce.NewJceWriter(). // see ServerConfig.d payload := jce.NewJceWriter(). // see ServerConfig.d
WriteInt64(0, 1).WriteInt64(0, 2).WriteByte(1, 3). WriteInt64(0, 1).WriteInt64(0, 2).WriteByte(1, 3).
WriteString("00000", 4).WriteInt32(100, 5). WriteString("00000", 4).WriteInt32(100, 5).
WriteInt32(int32(protocol.AppId), 6).WriteString(device.IMEI, 7). WriteInt32(int32(protocol.AppId), 6).WriteString(SystemDeviceInfo.IMEI, 7).
WriteInt64(0, 8).WriteInt64(0, 9).WriteInt64(0, 10). WriteInt64(0, 8).WriteInt64(0, 9).WriteInt64(0, 10).
WriteInt64(0, 11).WriteByte(0, 12).WriteInt64(0, 13).Bytes() WriteInt64(0, 11).WriteByte(0, 12).WriteInt64(0, 13).WriteByte(1, 14).Bytes()
buf := &jce.RequestDataVersion3{ buf := &jce.RequestDataVersion3{
Map: map[string][]byte{"HttpServerListReq": packUniRequestData(payload)}, Map: map[string][]byte{"HttpServerListReq": packUniRequestData(payload)},
} }
@ -131,15 +461,12 @@ func getSSOAddress(device *auth.Device) ([]netip.AddrPort, error) {
SFuncName: "HttpServerListReq", SFuncName: "HttpServerListReq",
SBuffer: buf.ToBytes(), SBuffer: buf.ToBytes(),
} }
b, cl := binary.OpenWriterF(func(w *binary.Writer) { tea := binary.NewTeaCipher(key)
rsp, err := utils.HttpPostBytes("https://configsvr.msf.3g.qq.com/configsvr/serverlist.jsp", tea.Encrypt(binary.NewWriterF(func(w *binary.Writer) {
w.WriteIntLvPacket(0, func(w *binary.Writer) { w.WriteIntLvPacket(0, func(w *binary.Writer) {
w.Write(pkt.ToBytes()) w.Write(pkt.ToBytes())
}) })
}) })))
tea := binary.NewTeaCipher(key)
encpkt := tea.Encrypt(b)
cl()
rsp, err := utils.HttpPostBytes("https://configsvr.msf.3g.qq.com/configsvr/serverlist.jsp?mType=getssolist", encpkt)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "unable to fetch server list") return nil, errors.Wrap(err, "unable to fetch server list")
} }
@ -148,16 +475,17 @@ func getSSOAddress(device *auth.Device) ([]netip.AddrPort, error) {
rspPkt.ReadFrom(jce.NewJceReader(tea.Decrypt(rsp)[4:])) rspPkt.ReadFrom(jce.NewJceReader(tea.Decrypt(rsp)[4:]))
data.ReadFrom(jce.NewJceReader(rspPkt.SBuffer)) data.ReadFrom(jce.NewJceReader(rspPkt.SBuffer))
reader := jce.NewJceReader(data.Map["HttpServerListRes"][1:]) reader := jce.NewJceReader(data.Map["HttpServerListRes"][1:])
servers := reader.ReadSsoServerInfos(2) servers := []jce.SsoServerInfo{}
adds := make([]netip.AddrPort, 0, len(servers)) reader.ReadSlice(&servers, 2)
adds := make([]*net.TCPAddr, 0, len(servers))
for _, s := range servers { for _, s := range servers {
if strings.Contains(s.Server, "com") { if strings.Contains(s.Server, "com") {
continue continue
} }
ip, ok := netip.AddrFromSlice(net.ParseIP(s.Server)) adds = append(adds, &net.TCPAddr{
if ok { IP: net.ParseIP(s.Server),
adds = append(adds, netip.AddrPortFrom(ip, uint16(s.Port))) Port: int(s.Port),
} })
} }
return adds, nil return adds, nil
} }
@ -170,46 +498,47 @@ func qualityTest(addr string) (int64, error) {
return 0, errors.Wrap(err, "failed to connect to server during quality test") return 0, errors.Wrap(err, "failed to connect to server during quality test")
} }
_ = conn.Close() _ = conn.Close()
return time.Since(start).Milliseconds(), nil end := time.Now()
return end.Sub(start).Milliseconds(), nil
} }
func (c *QQClient) parsePrivateMessage(msg *msg.Message) *message.PrivateMessage { func (c *QQClient) parsePrivateMessage(msg *msg.Message) *message.PrivateMessage {
friend := c.FindFriend(msg.Head.FromUin.Unwrap()) friend := c.FindFriend(msg.Head.GetFromUin())
var sender *message.Sender var sender *message.Sender
if friend != nil { if friend == nil {
sender = &message.Sender{
Uin: msg.Head.GetFromUin(),
Nickname: msg.Head.GetFromNick(),
}
} else {
sender = &message.Sender{ sender = &message.Sender{
Uin: friend.Uin, Uin: friend.Uin,
Nickname: friend.Nickname, Nickname: friend.Nickname,
IsFriend: true, IsFriend: true,
} }
} else {
sender = &message.Sender{
Uin: msg.Head.FromUin.Unwrap(),
Nickname: msg.Head.FromNick.Unwrap(),
}
} }
ret := &message.PrivateMessage{ ret := &message.PrivateMessage{
Id: msg.Head.MsgSeq.Unwrap(), Id: msg.Head.GetMsgSeq(),
Target: msg.Head.ToUin.Unwrap(), Target: msg.Head.GetToUin(),
Time: msg.Head.MsgTime.Unwrap(), Time: msg.Head.GetMsgTime(),
Sender: sender, Sender: sender,
Self: c.Uin, Self: c.Uin,
Elements: func() []message.IMessageElement { Elements: func() []message.IMessageElement {
// if msg.Body.RichText.Ptt != nil { if msg.Body.RichText.Ptt != nil {
// return []message.IMessageElement{ return []message.IMessageElement{
// &message.VoiceElement{ &message.VoiceElement{
// Name: msg.Body.RichText.Ptt.FileName.Unwrap(), Name: msg.Body.RichText.Ptt.GetFileName(),
// Md5: msg.Body.RichText.Ptt.FileMd5, Md5: msg.Body.RichText.Ptt.FileMd5,
// Size: msg.Body.RichText.Ptt.FileSize.Unwrap(), Size: msg.Body.RichText.Ptt.GetFileSize(),
// Url: string(msg.Body.RichText.Ptt.DownPara), Url: string(msg.Body.RichText.Ptt.DownPara),
// }, },
// } }
// } }
return message.ParseMessageElems(msg.Body.RichText.Elems) return message.ParseMessageElems(msg.Body.RichText.Elems)
}(), }(),
} }
if msg.Body.RichText.Attr != nil { if msg.Body.RichText.Attr != nil {
ret.InternalId = msg.Body.RichText.Attr.Random.Unwrap() ret.InternalId = msg.Body.RichText.Attr.GetRandom()
} }
return ret return ret
} }
@ -217,23 +546,23 @@ func (c *QQClient) parsePrivateMessage(msg *msg.Message) *message.PrivateMessage
func (c *QQClient) parseTempMessage(msg *msg.Message) *message.TempMessage { func (c *QQClient) parseTempMessage(msg *msg.Message) *message.TempMessage {
var groupCode int64 var groupCode int64
var groupName string var groupName string
group := c.FindGroupByUin(msg.Head.C2CTmpMsgHead.GroupUin.Unwrap()) group := c.FindGroupByUin(msg.Head.C2CTmpMsgHead.GetGroupUin())
sender := &message.Sender{ sender := &message.Sender{
Uin: msg.Head.FromUin.Unwrap(), Uin: msg.Head.GetFromUin(),
Nickname: "Unknown", Nickname: "Unknown",
IsFriend: false, IsFriend: false,
} }
if group != nil { if group != nil {
groupCode = group.Code groupCode = group.Code
groupName = group.Name groupName = group.Name
mem := group.FindMember(msg.Head.FromUin.Unwrap()) mem := group.FindMember(msg.Head.GetFromUin())
if mem != nil { if mem != nil {
sender.Nickname = mem.Nickname sender.Nickname = mem.Nickname
sender.CardName = mem.CardName sender.CardName = mem.CardName
} }
} }
return &message.TempMessage{ return &message.TempMessage{
Id: msg.Head.MsgSeq.Unwrap(), Id: msg.Head.GetMsgSeq(),
GroupCode: groupCode, GroupCode: groupCode,
GroupName: groupName, GroupName: groupName,
Self: c.Uin, Self: c.Uin,
@ -242,59 +571,32 @@ func (c *QQClient) parseTempMessage(msg *msg.Message) *message.TempMessage {
} }
} }
func (c *QQClient) messageBuilder(seq int32) *messageBuilder { func (b *groupMessageBuilder) build() *msg.Message {
actual, ok := c.msgBuilders.Load(seq) sort.Slice(b.MessageSlices, func(i, j int) bool {
if !ok { return b.MessageSlices[i].Content.GetPkgIndex() < b.MessageSlices[j].Content.GetPkgIndex()
builder := &messageBuilder{}
actual, _ = c.msgBuilders.LoadOrStore(seq, builder)
time.AfterFunc(time.Minute, func() {
c.msgBuilders.Delete(seq) // delete avoid memory leak
})
}
return actual
}
type messageBuilder struct {
lock sync.Mutex
slices []*msg.Message
}
func (b *messageBuilder) append(msg *msg.Message) {
b.lock.Lock()
defer b.lock.Unlock()
b.slices = append(b.slices, msg)
}
func (b *messageBuilder) len() int32 {
b.lock.Lock()
x := len(b.slices)
b.lock.Unlock()
return int32(x)
}
func (b *messageBuilder) build() *msg.Message {
b.lock.Lock()
defer b.lock.Unlock()
sort.Slice(b.slices, func(i, j int) bool {
return b.slices[i].Content.PkgIndex.Unwrap() < b.slices[j].Content.PkgIndex.Unwrap()
}) })
base := b.slices[0] base := b.MessageSlices[0]
for _, m := range b.slices[1:] { for _, m := range b.MessageSlices[1:] {
base.Body.RichText.Elems = append(base.Body.RichText.Elems, m.Body.RichText.Elems...) base.Body.RichText.Elems = append(base.Body.RichText.Elems, m.Body.RichText.Elems...)
} }
return base return base
} }
func packUniRequestData(data []byte) []byte { func packUniRequestData(data []byte) (r []byte) {
r := make([]byte, 0, len(data)+2) r = append([]byte{0x0A}, data...)
r = append(r, 0x0a)
r = append(r, data...)
r = append(r, 0x0B) r = append(r, 0x0B)
return r return
} }
func genForwardTemplate(resID, preview, summary string, ts int64, items []*msg.PbMultiMsgItem) *message.ForwardElement { func genForwardTemplate(resID, preview, title, brief, source, summary string, ts int64, items []*msg.PbMultiMsgItem) *message.ForwardElement {
template := forwardDisplay(resID, strconv.FormatInt(ts, 10), preview, summary) template := fmt.Sprintf(`<?xml version='1.0' encoding='UTF-8'?><msg serviceID="35" templateID="1" action="viewMultiMsg" brief="%s" m_resid="%s" m_fileName="%d" tSum="3" sourceMsgId="0" url="" flag="3" adverSign="0" multiMsgFlag="0"><item layout="1"><title color="#000000" size="34">%s</title> %s<hr></hr><summary size="26" color="#808080">%s</summary></item><source name="%s"></source></msg>`,
brief, resID, ts, title, preview, summary, source,
)
for _, item := range items {
if item.GetFileName() == "MultiMsg" {
*item.FileName = strconv.FormatInt(ts, 10)
}
}
return &message.ForwardElement{ return &message.ForwardElement{
FileName: strconv.FormatInt(ts, 10), FileName: strconv.FormatInt(ts, 10),
Content: template, Content: template,
@ -303,59 +605,116 @@ func genForwardTemplate(resID, preview, summary string, ts int64, items []*msg.P
} }
} }
func (c *QQClient) getWebDeviceInfo() (i string) { func genLongTemplate(resID, brief string, ts int64) *message.ServiceElement {
qimei := strings.ToLower(utils.RandomString(36)) limited := func() string {
i += fmt.Sprintf("i=%v&imsi=&mac=%v&m=%v&o=%v&", c.Device().IMEI, utils.B2S(c.Device().MacAddress), utils.B2S(c.Device().Device), utils.B2S(c.Device().Version.Release)) if len(brief) > 30 {
i += fmt.Sprintf("a=%v&sd=0&c64=0&sc=1&p=1080*2210&aid=%v&", c.Device().Version.SDK, c.Device().IMEI) return brief[:30] + "…"
i += fmt.Sprintf("f=%v&mm=%v&cf=%v&cc=%v&", c.Device().Brand, 5629 /* Total Memory*/, 1725 /* CPU Frequency */, 8 /* CPU Core Count */) }
i += fmt.Sprintf("qimei=%v&qimei36=%v&", qimei, qimei) return brief
i += "sharpP=1&n=wifi&support_xsj_live=true&client_mod=default&timezone=Asia/Shanghai&material_sdk_version=2.9.0&vh265=null&refreshrate=60" }()
return template := fmt.Sprintf(`<?xml version='1.0' encoding='UTF-8' standalone='yes' ?><msg serviceID="35" templateID="1" action="viewMultiMsg" brief="%s" m_resid="%s" m_fileName="%d" sourceMsgId="0" url="" flag="3" adverSign="0" multiMsgFlag="1"> <item layout="1"> <title>%s</title> <hr hidden="false" style="0"/> <summary>点击查看完整消息</summary> </item> <source name="聊天记录" icon="" action="" appid="-1"/> </msg>`,
} utils.XmlEscape(limited), resID, ts, utils.XmlEscape(limited),
)
var oidbSSOPool = sync.Pool{} return &message.ServiceElement{
Id: 35,
func getOidbSSOPackage() *oidb.OIDBSSOPkg { Content: template,
g := oidbSSOPool.Get() ResId: resID,
if g == nil { SubType: "Long",
return new(oidb.OIDBSSOPkg)
} }
return g.(*oidb.OIDBSSOPkg)
} }
func (c *QQClient) packOIDBPackage(cmd, serviceType int32, body []byte) []byte { func (p requestParams) bool(k string) bool {
pkg := getOidbSSOPackage() if p == nil {
defer oidbSSOPool.Put(pkg) return false
*pkg = oidb.OIDBSSOPkg{ }
Command: cmd, i, ok := p[k]
ServiceType: serviceType, if !ok {
return false
}
return i.(bool)
}
func (p requestParams) int32(k string) int32 {
if p == nil {
return 0
}
i, ok := p[k]
if !ok {
return 0
}
return i.(int32)
}
func (c *QQClient) packOIDBPackage(cmd, serviceType uint32, body []byte) []byte {
pkg := &oidb.OIDBSSOPkg{
Command: &cmd,
ServiceType: &serviceType,
Bodybuffer: body, Bodybuffer: body,
ClientVersion: "Android " + c.version().SortVersionName, ClientVersion: proto.String("Android " + c.version.SortVersionName),
} }
r, _ := proto.Marshal(pkg) r, _ := pkg.Marshal()
return r return r
} }
func (c *QQClient) packOIDBPackageDynamically(cmd, serviceType int32, msg proto.DynamicMessage) []byte { func (c *QQClient) packOIDBPackageDynamically(cmd, serviceType uint32, msg binary.DynamicProtoMessage) []byte {
return c.packOIDBPackage(cmd, serviceType, msg.Encode()) return c.packOIDBPackage(cmd, serviceType, msg.Encode())
} }
func (c *QQClient) packOIDBPackageProto(cmd, serviceType int32, msg proto.Message) []byte { func (c *QQClient) packOIDBPackageProto(cmd, serviceType uint32, msg proto.Message) []byte {
b, _ := proto.Marshal(msg) b, _ := proto.Marshal(msg)
return c.packOIDBPackage(cmd, serviceType, b) return c.packOIDBPackage(cmd, serviceType, b)
} }
func unpackOIDBPackage(payload []byte, rsp proto.Message) error { func (c *QQClient) packOIDBPackageProto2(cmd, serviceType uint32, msg proto2.Message) []byte {
pkg := getOidbSSOPackage() b, _ := msg.Marshal()
defer oidbSSOPool.Put(pkg) return c.packOIDBPackage(cmd, serviceType, b)
if err := proto.Unmarshal(payload, pkg); err != nil { }
func (c *QQClient) unpackOIDBPackage(buff []byte, payload interface{}) error {
pkg := new(oidb.OIDBSSOPkg)
if err := protobuf.Unmarshal(buff, pkg); err != nil {
return errors.Wrap(err, "failed to unmarshal protobuf message") return errors.Wrap(err, "failed to unmarshal protobuf message")
} }
if pkg.Result != 0 { if pkg.GetResult() != 0 {
return errors.Errorf("oidb result unsuccessful: %v msg: %v", pkg.Result, pkg.ErrorMsg) return errors.Errorf("oidb result unsuccessful: %v msg: %v", pkg.GetResult(), pkg.GetErrorMsg())
} }
if err := proto.Unmarshal(pkg.Bodybuffer, rsp); err != nil { if err := protobuf.Unmarshal(pkg.Bodybuffer, payload); err != nil {
return errors.Wrap(err, "failed to unmarshal protobuf message") return errors.Wrap(err, "failed to unmarshal protobuf message")
} }
return nil return nil
} }
func (c *QQClient) Error(msg string, args ...interface{}) {
c.dispatchLogEvent(&LogEvent{
Type: "ERROR",
Message: fmt.Sprintf(msg, args...),
})
}
func (c *QQClient) Warning(msg string, args ...interface{}) {
c.dispatchLogEvent(&LogEvent{
Type: "WARNING",
Message: fmt.Sprintf(msg, args...),
})
}
func (c *QQClient) Info(msg string, args ...interface{}) {
c.dispatchLogEvent(&LogEvent{
Type: "INFO",
Message: fmt.Sprintf(msg, args...),
})
}
func (c *QQClient) Debug(msg string, args ...interface{}) {
c.dispatchLogEvent(&LogEvent{
Type: "DEBUG",
Message: fmt.Sprintf(msg, args...),
})
}
func (c *QQClient) Trace(msg string, args ...interface{}) {
c.dispatchLogEvent(&LogEvent{
Type: "TRACE",
Message: fmt.Sprintf(msg, args...),
})
}

View File

@ -1,17 +1,27 @@
package client package client
import ( import (
"crypto/sha1"
"encoding/hex" "encoding/hex"
"fmt" "fmt"
"io"
"math/rand"
"os" "os"
"runtime/debug" "runtime/debug"
"github.com/pkg/errors" "github.com/pkg/errors"
protobuf "github.com/segmentio/encoding/proto"
"google.golang.org/protobuf/proto"
"github.com/Mrs4s/MiraiGo/client/internal/network" "github.com/Mrs4s/MiraiGo/client/pb/exciting"
"github.com/Mrs4s/MiraiGo/client/pb/oidb" "github.com/Mrs4s/MiraiGo/internal/packets"
"github.com/Mrs4s/MiraiGo/internal/proto" "github.com/Mrs4s/MiraiGo/internal/protobuf/data/group_file_common"
"github.com/Mrs4s/MiraiGo/message" "github.com/Mrs4s/MiraiGo/internal/protobuf/data/oidb"
"github.com/Mrs4s/MiraiGo/internal/protobuf/data/oidb/oidb0x6d6"
"github.com/Mrs4s/MiraiGo/internal/protobuf/data/oidb/oidb0x6d7"
"github.com/Mrs4s/MiraiGo/internal/protobuf/data/oidb/oidb0x6d8"
"github.com/Mrs4s/MiraiGo/internal/protobuf/data/oidb/oidb0x6d9"
"github.com/Mrs4s/MiraiGo/utils"
) )
type ( type (
@ -50,13 +60,13 @@ type (
} }
) )
var fsWaiter = utils.NewUploadWaiter()
func init() { func init() {
decoders["OidbSvc.0x6d8_1"] = decodeOIDB6d81Response decoders["OidbSvc.0x6d8_1"] = decodeOIDB6d81Response
decoders["OidbSvc.0x6d6_0"] = decodeOIDB6d60Response decoders["OidbSvc.0x6d6_0"] = decodeOIDB6d60Response
decoders["OidbSvc.0x6d6_2"] = decodeOIDB6d62Response decoders["OidbSvc.0x6d6_2"] = decodeOIDB6d62Response
decoders["OidbSvc.0x6d6_3"] = decodeOIDB6d63Response decoders["OidbSvc.0x6d6_3"] = decodeOIDB6d63Response
decoders["OidbSvc.0x6d6_4"] = decodeOIDB6d64Response
decoders["OidbSvc.0x6d6_5"] = decodeOIDB6d65Response
decoders["OidbSvc.0x6d7_0"] = decodeOIDB6d7Response decoders["OidbSvc.0x6d7_0"] = decodeOIDB6d7Response
decoders["OidbSvc.0x6d7_1"] = decodeOIDB6d7Response decoders["OidbSvc.0x6d7_1"] = decodeOIDB6d7Response
decoders["OidbSvc.0x6d7_2"] = decodeOIDB6d7Response decoders["OidbSvc.0x6d7_2"] = decodeOIDB6d7Response
@ -66,7 +76,7 @@ func init() {
func (c *QQClient) GetGroupFileSystem(groupCode int64) (fs *GroupFileSystem, err error) { func (c *QQClient) GetGroupFileSystem(groupCode int64) (fs *GroupFileSystem, err error) {
defer func() { defer func() {
if pan := recover(); pan != nil { if pan := recover(); pan != nil {
c.error("get group fs error: %v\n%s", pan, debug.Stack()) c.Error("get group fs error: %v\n%s", pan, debug.Stack())
err = errors.New("fs error") err = errors.New("fs error")
} }
}() }()
@ -79,8 +89,8 @@ func (c *QQClient) GetGroupFileSystem(groupCode int64) (fs *GroupFileSystem, err
return nil, e return nil, e
} }
fs = &GroupFileSystem{ fs = &GroupFileSystem{
FileCount: rsp.(*oidb.D6D8RspBody).FileCountRsp.AllFileCount.Unwrap(), FileCount: rsp.(*oidb0x6d8.RspBody).GroupFileCntRsp.GetAllFileCount(),
LimitCount: rsp.(*oidb.D6D8RspBody).FileCountRsp.LimitCount.Unwrap(), LimitCount: rsp.(*oidb0x6d8.RspBody).GroupFileCntRsp.GetLimitCount(),
GroupCode: groupCode, GroupCode: groupCode,
client: c, client: c,
} }
@ -88,8 +98,8 @@ func (c *QQClient) GetGroupFileSystem(groupCode int64) (fs *GroupFileSystem, err
if err != nil { if err != nil {
return nil, err return nil, err
} }
fs.TotalSpace = rsp.(*oidb.D6D8RspBody).GroupSpaceRsp.TotalSpace.Unwrap() fs.TotalSpace = rsp.(*oidb0x6d8.RspBody).GroupSpaceRsp.GetTotalSpace()
fs.UsedSpace = rsp.(*oidb.D6D8RspBody).GroupSpaceRsp.UsedSpace.Unwrap() fs.UsedSpace = rsp.(*oidb0x6d8.RspBody).GroupSpaceRsp.GetUsedSpace()
return fs, nil return fs, nil
} }
@ -99,7 +109,7 @@ func (c *QQClient) GetGroupFileUrl(groupCode int64, fileId string, busId int32)
return "" return ""
} }
url := i.(string) url := i.(string)
url += fmt.Sprintf("?fname=%x", fileId) url += "?fname=" + hex.EncodeToString([]byte(fileId))
return url return url
} }
@ -116,7 +126,7 @@ func (fs *GroupFileSystem) GetFilesByFolder(folderID string) ([]*GroupFile, []*G
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
rsp := i.(*oidb.D6D8RspBody) rsp := i.(*oidb0x6d8.RspBody)
if rsp.FileListInfoRsp == nil { if rsp.FileListInfoRsp == nil {
break break
} }
@ -124,54 +134,108 @@ func (fs *GroupFileSystem) GetFilesByFolder(folderID string) ([]*GroupFile, []*G
if item.FileInfo != nil { if item.FileInfo != nil {
files = append(files, &GroupFile{ files = append(files, &GroupFile{
GroupCode: fs.GroupCode, GroupCode: fs.GroupCode,
FileId: item.FileInfo.FileId.Unwrap(), FileId: item.FileInfo.GetFileId(),
FileName: item.FileInfo.FileName.Unwrap(), FileName: item.FileInfo.GetFileName(),
BusId: int32(item.FileInfo.BusId.Unwrap()), BusId: int32(item.FileInfo.GetBusId()),
FileSize: int64(item.FileInfo.FileSize.Unwrap()), FileSize: int64(item.FileInfo.GetFileSize()),
UploadTime: int64(item.FileInfo.UploadTime.Unwrap()), UploadTime: int64(item.FileInfo.GetUploadTime()),
DeadTime: int64(item.FileInfo.DeadTime.Unwrap()), DeadTime: int64(item.FileInfo.GetDeadTime()),
ModifyTime: int64(item.FileInfo.ModifyTime.Unwrap()), ModifyTime: int64(item.FileInfo.GetModifyTime()),
DownloadTimes: int64(item.FileInfo.DownloadTimes.Unwrap()), DownloadTimes: int64(item.FileInfo.GetDownloadTimes()),
Uploader: int64(item.FileInfo.UploaderUin.Unwrap()), Uploader: int64(item.FileInfo.GetUploaderUin()),
UploaderName: item.FileInfo.UploaderName.Unwrap(), UploaderName: item.FileInfo.GetUploaderName(),
}) })
} }
if item.FolderInfo != nil { if item.FolderInfo != nil {
folders = append(folders, &GroupFolder{ folders = append(folders, &GroupFolder{
GroupCode: fs.GroupCode, GroupCode: fs.GroupCode,
FolderId: item.FolderInfo.FolderId.Unwrap(), FolderId: item.FolderInfo.GetFolderId(),
FolderName: item.FolderInfo.FolderName.Unwrap(), FolderName: item.FolderInfo.GetFolderName(),
CreateTime: int64(item.FolderInfo.CreateTime.Unwrap()), CreateTime: int64(item.FolderInfo.GetCreateTime()),
Creator: int64(item.FolderInfo.CreateUin.Unwrap()), Creator: int64(item.FolderInfo.GetCreateUin()),
CreatorName: item.FolderInfo.CreatorName.Unwrap(), CreatorName: item.FolderInfo.GetCreatorName(),
TotalFileCount: item.FolderInfo.TotalFileCount.Unwrap(), TotalFileCount: item.FolderInfo.GetTotalFileCount(),
}) })
} }
} }
if rsp.FileListInfoRsp.IsEnd.Unwrap() { if rsp.FileListInfoRsp.GetIsEnd() {
break break
} }
startIndex = rsp.FileListInfoRsp.NextIndex.Unwrap() startIndex = rsp.FileListInfoRsp.GetNextIndex()
} }
return files, folders, nil return files, folders, nil
} }
func (fs *GroupFileSystem) UploadFile(p, name, folderId string) error { func (fs *GroupFileSystem) UploadFile(p, name, folderId string) error {
// 同文件等待其他线程上传
fsWaiter.Wait(p)
defer fsWaiter.Done(p)
file, err := os.OpenFile(p, os.O_RDONLY, 0o666) file, err := os.OpenFile(p, os.O_RDONLY, 0o666)
if err != nil { if err != nil {
return errors.Wrap(err, "open file error") return errors.Wrap(err, "open file error")
} }
defer func() { _ = file.Close() }() defer func() { _ = file.Close() }()
f := &LocalFile{ md5Hash, size := utils.ComputeMd5AndLength(file)
FileName: name, _, _ = file.Seek(0, io.SeekStart)
Body: file, sha1H := sha1.New()
RemoteFolder: folderId, _, _ = io.Copy(sha1H, file)
sha1Hash := sha1H.Sum(nil)
_, _ = file.Seek(0, io.SeekStart)
i, err := fs.client.sendAndWait(fs.client.buildGroupFileUploadReqPacket(folderId, name, fs.GroupCode, size, md5Hash, sha1Hash))
if err != nil {
return errors.Wrap(err, "query upload failed")
} }
target := message.Source{ rsp := i.(*oidb0x6d6.UploadFileRspBody)
SourceType: message.SourceGroup, if rsp.GetFileExist() {
PrimaryID: fs.GroupCode, _, pkt := fs.client.buildGroupFileFeedsRequest(fs.GroupCode, rsp.GetFileId(), int32(rsp.GetBusId()), rand.Int31())
return fs.client.sendPacket(pkt)
} }
return fs.client.UploadFile(target, f) if len(rsp.UploadIpLanV4) == 0 {
return errors.New("server requires unsupported ftn upload")
}
ext, _ := proto.Marshal(&exciting.GroupFileUploadExt{
Unknown1: proto.Int32(100),
Unknown2: proto.Int32(1),
Entry: &exciting.GroupFileUploadEntry{
BusiBuff: &exciting.ExcitingBusiInfo{
BusId: proto.Int32(int32(rsp.GetBusId())),
SenderUin: &fs.client.Uin,
ReceiverUin: &fs.GroupCode,
GroupCode: &fs.GroupCode,
},
FileEntry: &exciting.ExcitingFileEntry{
FileSize: &size,
Md5: md5Hash,
Sha1: sha1Hash,
FileId: []byte(rsp.GetFileId()),
UploadKey: rsp.CheckKey,
},
ClientInfo: &exciting.ExcitingClientInfo{
ClientType: proto.Int32(2),
AppId: proto.String(fmt.Sprint(fs.client.version.AppId)),
TerminalType: proto.Int32(2),
ClientVer: proto.String("9e9c09dc"),
Unknown: proto.Int32(4),
},
FileNameInfo: &exciting.ExcitingFileNameInfo{FileName: &name},
Host: &exciting.ExcitingHostConfig{Hosts: []*exciting.ExcitingHostInfo{
{
Url: &exciting.ExcitingUrlInfo{
Unknown: proto.Int32(1),
Host: &rsp.UploadIpLanV4[0],
},
Port: proto.Int32(int32(rsp.GetUploadPort())),
},
}},
},
Unknown3: proto.Int32(0),
})
if _, err = fs.client.excitingUploadStream(file, 71, fs.client.bigDataSession.SigSession, ext); err != nil {
return errors.Wrap(err, "upload failed")
}
_, pkt := fs.client.buildGroupFileFeedsRequest(fs.GroupCode, rsp.GetFileId(), int32(rsp.GetBusId()), rand.Int31())
return fs.client.sendPacket(pkt)
} }
func (fs *GroupFileSystem) GetDownloadUrl(file *GroupFile) string { func (fs *GroupFileSystem) GetDownloadUrl(file *GroupFile) string {
@ -209,274 +273,225 @@ func (fs *GroupFileSystem) DeleteFile(parentFolderID, fileId string, busId int32
return i.(string) return i.(string)
} }
// RenameFile 重命名群文件,需要管理权限或者是自己发的文件. func (c *QQClient) buildGroupFileUploadReqPacket(parentFolderID, fileName string, groupCode, fileSize int64, md5, sha1 []byte) (uint16, []byte) {
// 返回错误, 空为重命名成功 seq := c.nextSeq()
func (fs *GroupFileSystem) RenameFile(parentFolderID, fileId string, busId int32, newFileName string) string { body := &oidb0x6d6.ReqBody{UploadFileReq: &oidb0x6d6.UploadFileReqBody{
i, err := fs.client.sendAndWait(fs.client.buildGroupFileRenameReqPacket(fs.GroupCode, parentFolderID, fileId, busId, newFileName)) GroupCode: proto.Uint64(uint64(groupCode)),
if err != nil { AppId: proto.Uint32(3),
return err.Error() BusId: proto.Uint32(102),
} Entrance: proto.Uint32(5),
return i.(string) ParentFolderId: &parentFolderID,
} FileName: &fileName,
LocalPath: proto.String("/storage/emulated/0/Pictures/files/s/" + fileName),
// MoveFile 移动群文件,需要管理权限或者是自己发的文件. FileSize: proto.Uint64(uint64(fileSize)),
// 返回错误, 空为移动成功 Sha: sha1,
func (fs *GroupFileSystem) MoveFile(parentFolderID, fileId string, busId int32, DestFolderId string) string { Md5: md5,
i, err := fs.client.sendAndWait(fs.client.buildGroupFileMoveReqPacket(fs.GroupCode, parentFolderID, fileId, busId, DestFolderId))
if err != nil {
return err.Error()
}
return i.(string)
}
func (c *QQClient) buildGroupFileUploadReqPacket(groupCode int64, file *LocalFile) (uint16, []byte) {
body := &oidb.D6D6ReqBody{UploadFileReq: &oidb.UploadFileReqBody{
GroupCode: proto.Some(groupCode),
AppId: proto.Int32(3),
BusId: proto.Int32(102),
Entrance: proto.Int32(5),
ParentFolderId: proto.Some(file.RemoteFolder),
FileName: proto.Some(file.FileName),
LocalPath: proto.String("/storage/emulated/0/Pictures/files/s/" + file.FileName),
Int64FileSize: proto.Some(file.size),
Sha: file.sha1,
Md5: file.md5,
SupportMultiUpload: proto.Bool(true), SupportMultiUpload: proto.Bool(true),
}} }}
payload := c.packOIDBPackageProto(1750, 0, body) payload := c.packOIDBPackageProto2(1750, 0, body)
return c.uniPacket("OidbSvc.0x6d6_0", payload) packet := packets.BuildUniPacket(c.Uin, seq, "OidbSvc.0x6d6_0", 1, c.OutGoingPacketSessionId, EmptyBytes, c.sigInfo.d2Key, payload)
return seq, packet
} }
func (c *QQClient) buildGroupFileFeedsRequest(groupCode int64, fileID string, busId, msgRand int32) (uint16, []byte) { func (c *QQClient) buildGroupFileFeedsRequest(groupCode int64, fileID string, busId, msgRand int32) (uint16, []byte) {
req := c.packOIDBPackageProto(1753, 4, &oidb.D6D9ReqBody{FeedsInfoReq: &oidb.FeedsReqBody{ seq := c.nextSeq()
req := c.packOIDBPackageProto2(1753, 4, &oidb0x6d9.ReqBody{FeedsInfoReq: &oidb0x6d9.FeedsReqBody{
GroupCode: proto.Uint64(uint64(groupCode)), GroupCode: proto.Uint64(uint64(groupCode)),
AppId: proto.Uint32(3), AppId: proto.Uint32(3),
FeedsInfoList: []*oidb.GroupFileFeedsInfo{{ FeedsInfoList: []*group_file_common.FeedsInfo{{
FileId: proto.Some(fileID), FileId: &fileID,
FeedFlag: proto.Uint32(1), FeedFlag: proto.Uint32(1),
BusId: proto.Uint32(uint32(busId)), BusId: proto.Uint32(uint32(busId)),
MsgRandom: proto.Uint32(uint32(msgRand)), MsgRandom: proto.Uint32(uint32(msgRand)),
}}, }},
}}) }})
return c.uniPacket("OidbSvc.0x6d9_4", req) packet := packets.BuildUniPacket(c.Uin, seq, "OidbSvc.0x6d9_4", 1, c.OutGoingPacketSessionId, EmptyBytes, c.sigInfo.d2Key, req)
return seq, packet
} }
// OidbSvc.0x6d8_1 // OidbSvc.0x6d8_1
func (c *QQClient) buildGroupFileListRequestPacket(groupCode int64, folderID string, startIndex uint32) (uint16, []byte) { func (c *QQClient) buildGroupFileListRequestPacket(groupCode int64, folderID string, startIndex uint32) (uint16, []byte) {
body := &oidb.D6D8ReqBody{FileListInfoReq: &oidb.GetFileListReqBody{ seq := c.nextSeq()
body := &oidb0x6d8.ReqBody{FileListInfoReq: &oidb0x6d8.GetFileListReqBody{
GroupCode: proto.Uint64(uint64(groupCode)), GroupCode: proto.Uint64(uint64(groupCode)),
AppId: proto.Uint32(3), AppId: proto.Uint32(3),
FolderId: proto.Some(folderID), FolderId: &folderID,
FileCount: proto.Uint32(20), FileCount: proto.Uint32(20),
AllFileCount: proto.Uint32(0), AllFileCount: proto.Uint32(0),
ReqFrom: proto.Uint32(3), ReqFrom: proto.Uint32(3),
SortBy: proto.Uint32(1), SortBy: proto.Uint32(1),
FilterCode: proto.Uint32(0), FilterCode: proto.Uint32(0),
Uin: proto.Uint64(0), Uin: proto.Uint64(0),
StartIndex: proto.Some(startIndex), StartIndex: &startIndex,
Context: EmptyBytes, Context: EmptyBytes,
}} }}
payload := c.packOIDBPackageProto(1752, 1, body) payload := c.packOIDBPackageProto2(1752, 1, body)
return c.uniPacket("OidbSvc.0x6d8_1", payload) packet := packets.BuildUniPacket(c.Uin, seq, "OidbSvc.0x6d8_1", 1, c.OutGoingPacketSessionId, EmptyBytes, c.sigInfo.d2Key, payload)
return seq, packet
} }
func (c *QQClient) buildGroupFileCountRequestPacket(groupCode int64) (uint16, []byte) { func (c *QQClient) buildGroupFileCountRequestPacket(groupCode int64) (uint16, []byte) {
body := &oidb.D6D8ReqBody{ seq := c.nextSeq()
GroupFileCountReq: &oidb.GetFileCountReqBody{ body := &oidb0x6d8.ReqBody{GroupFileCntReq: &oidb0x6d8.GetFileCountReqBody{
GroupCode: proto.Uint64(uint64(groupCode)), GroupCode: proto.Uint64(uint64(groupCode)),
AppId: proto.Uint32(3), AppId: proto.Uint32(3),
BusId: proto.Uint32(0), BusId: proto.Uint32(0),
}, }}
} payload := c.packOIDBPackageProto2(1752, 2, body)
payload := c.packOIDBPackageProto(1752, 2, body) packet := packets.BuildUniPacket(c.Uin, seq, "OidbSvc.0x6d8_1", 1, c.OutGoingPacketSessionId, EmptyBytes, c.sigInfo.d2Key, payload)
return c.uniPacket("OidbSvc.0x6d8_1", payload) return seq, packet
} }
func (c *QQClient) buildGroupFileSpaceRequestPacket(groupCode int64) (uint16, []byte) { func (c *QQClient) buildGroupFileSpaceRequestPacket(groupCode int64) (uint16, []byte) {
body := &oidb.D6D8ReqBody{GroupSpaceReq: &oidb.GetSpaceReqBody{ seq := c.nextSeq()
body := &oidb0x6d8.ReqBody{GroupSpaceReq: &oidb0x6d8.GetSpaceReqBody{
GroupCode: proto.Uint64(uint64(groupCode)), GroupCode: proto.Uint64(uint64(groupCode)),
AppId: proto.Uint32(3), AppId: proto.Uint32(3),
}} }}
payload := c.packOIDBPackageProto(1752, 3, body) payload := c.packOIDBPackageProto2(1752, 3, body)
return c.uniPacket("OidbSvc.0x6d8_1", payload) packet := packets.BuildUniPacket(c.Uin, seq, "OidbSvc.0x6d8_1", 1, c.OutGoingPacketSessionId, EmptyBytes, c.sigInfo.d2Key, payload)
return seq, packet
} }
func (c *QQClient) buildGroupFileCreateFolderPacket(groupCode int64, parentFolder, name string) (uint16, []byte) { func (c *QQClient) buildGroupFileCreateFolderPacket(groupCode int64, parentFolder, name string) (uint16, []byte) {
payload := c.packOIDBPackageProto(1751, 0, &oidb.D6D7ReqBody{CreateFolderReq: &oidb.CreateFolderReqBody{ seq := c.nextSeq()
payload := c.packOIDBPackageProto2(1751, 0, &oidb0x6d7.ReqBody{CreateFolderReq: &oidb0x6d7.CreateFolderReqBody{
GroupCode: proto.Uint64(uint64(groupCode)), GroupCode: proto.Uint64(uint64(groupCode)),
AppId: proto.Uint32(3), AppId: proto.Uint32(3),
ParentFolderId: proto.Some(parentFolder), ParentFolderId: &parentFolder,
FolderName: proto.Some(name), FolderName: &name,
}}) }})
return c.uniPacket("OidbSvc.0x6d7_0", payload) packet := packets.BuildUniPacket(c.Uin, seq, "OidbSvc.0x6d7_0", 1, c.OutGoingPacketSessionId, EmptyBytes, c.sigInfo.d2Key, payload)
return seq, packet
} }
func (c *QQClient) buildGroupFileRenameFolderPacket(groupCode int64, folderId, newName string) (uint16, []byte) { func (c *QQClient) buildGroupFileRenameFolderPacket(groupCode int64, folderId, newName string) (uint16, []byte) {
payload := c.packOIDBPackageProto(1751, 2, &oidb.D6D7ReqBody{RenameFolderReq: &oidb.RenameFolderReqBody{ seq := c.nextSeq()
payload := c.packOIDBPackageProto2(1751, 2, &oidb0x6d7.ReqBody{RenameFolderReq: &oidb0x6d7.RenameFolderReqBody{
GroupCode: proto.Uint64(uint64(groupCode)), GroupCode: proto.Uint64(uint64(groupCode)),
AppId: proto.Uint32(3), AppId: proto.Uint32(3),
FolderId: proto.String(folderId), FolderId: proto.String(folderId),
NewFolderName: proto.String(newName), NewFolderName: proto.String(newName),
}}) }})
return c.uniPacket("OidbSvc.0x6d7_2", payload) packet := packets.BuildUniPacket(c.Uin, seq, "OidbSvc.0x6d7_2", 1, c.OutGoingPacketSessionId, EmptyBytes, c.sigInfo.d2Key, payload)
return seq, packet
} }
func (c *QQClient) buildGroupFileDeleteFolderPacket(groupCode int64, folderId string) (uint16, []byte) { func (c *QQClient) buildGroupFileDeleteFolderPacket(groupCode int64, folderId string) (uint16, []byte) {
payload := c.packOIDBPackageProto(1751, 1, &oidb.D6D7ReqBody{DeleteFolderReq: &oidb.DeleteFolderReqBody{ seq := c.nextSeq()
payload := c.packOIDBPackageProto2(1751, 1, &oidb0x6d7.ReqBody{DeleteFolderReq: &oidb0x6d7.DeleteFolderReqBody{
GroupCode: proto.Uint64(uint64(groupCode)), GroupCode: proto.Uint64(uint64(groupCode)),
AppId: proto.Uint32(3), AppId: proto.Uint32(3),
FolderId: proto.String(folderId), FolderId: proto.String(folderId),
}}) }})
return c.uniPacket("OidbSvc.0x6d7_1", payload) packet := packets.BuildUniPacket(c.Uin, seq, "OidbSvc.0x6d7_1", 1, c.OutGoingPacketSessionId, EmptyBytes, c.sigInfo.d2Key, payload)
return seq, packet
} }
// OidbSvc.0x6d6_2 // OidbSvc.0x6d6_2
func (c *QQClient) buildGroupFileDownloadReqPacket(groupCode int64, fileId string, busId int32) (uint16, []byte) { func (c *QQClient) buildGroupFileDownloadReqPacket(groupCode int64, fileId string, busId int32) (uint16, []byte) {
body := &oidb.D6D6ReqBody{ seq := c.nextSeq()
DownloadFileReq: &oidb.DownloadFileReqBody{ body := &oidb0x6d6.ReqBody{
GroupCode: proto.Some(groupCode), DownloadFileReq: &oidb0x6d6.DownloadFileReqBody{
AppId: proto.Int32(3), GroupCode: proto.Uint64(uint64(groupCode)),
BusId: proto.Some(busId), AppId: proto.Uint32(3),
FileId: proto.Some(fileId), BusId: proto.Uint32(uint32(busId)),
FileId: &fileId,
}, },
} }
payload := c.packOIDBPackageProto(1750, 2, body) payload := c.packOIDBPackageProto2(1750, 2, body)
return c.uniPacket("OidbSvc.0x6d6_2", payload) packet := packets.BuildUniPacket(c.Uin, seq, "OidbSvc.0x6d6_2", 1, c.OutGoingPacketSessionId, EmptyBytes, c.sigInfo.d2Key, payload)
return seq, packet
} }
func (c *QQClient) buildGroupFileDeleteReqPacket(groupCode int64, parentFolderId, fileId string, busId int32) (uint16, []byte) { func (c *QQClient) buildGroupFileDeleteReqPacket(groupCode int64, parentFolderId, fileId string, busId int32) (uint16, []byte) {
body := &oidb.D6D6ReqBody{DeleteFileReq: &oidb.DeleteFileReqBody{ seq := c.nextSeq()
GroupCode: proto.Some(groupCode), body := &oidb0x6d6.ReqBody{DeleteFileReq: &oidb0x6d6.DeleteFileReqBody{
AppId: proto.Int32(3), GroupCode: proto.Uint64(uint64(groupCode)),
BusId: proto.Some(busId), AppId: proto.Uint32(3),
ParentFolderId: proto.Some(parentFolderId), BusId: proto.Uint32(uint32(busId)),
FileId: proto.Some(fileId), ParentFolderId: &parentFolderId,
FileId: &fileId,
}} }}
payload := c.packOIDBPackageProto(1750, 3, body) payload := c.packOIDBPackageProto2(1750, 3, body)
return c.uniPacket("OidbSvc.0x6d6_3", payload) packet := packets.BuildUniPacket(c.Uin, seq, "OidbSvc.0x6d6_3", 1, c.OutGoingPacketSessionId, EmptyBytes, c.sigInfo.d2Key, payload)
return seq, packet
} }
func (c *QQClient) buildGroupFileRenameReqPacket(groupCode int64, parentFolderId string, fileId string, busId int32, newFileName string) (uint16, []byte) { func decodeOIDB6d81Response(_ *QQClient, _ *incomingPacketInfo, payload []byte) (interface{}, error) {
body := &oidb.D6D6ReqBody{RenameFileReq: &oidb.RenameFileReqBody{ pkg := oidb.OIDBSSOPkg{}
GroupCode: proto.Some(groupCode), rsp := oidb0x6d8.RspBody{}
AppId: proto.Int32(5), if err := protobuf.Unmarshal(payload, &pkg); err != nil {
BusId: proto.Some(busId), return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
FileId: proto.Some(fileId), }
ParentFolderId: proto.Some(parentFolderId), if err := protobuf.Unmarshal(pkg.Bodybuffer, &rsp); err != nil {
NewFileName: proto.Some(newFileName), return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
}}
payload := c.packOIDBPackageProto(1750, 4, body)
return c.uniPacket("OidbSvc.0x6d6_4", payload)
}
func (c *QQClient) buildGroupFileMoveReqPacket(groupCode int64, parentFolderId string, fileId string, busId int32, DestFolderId string) (uint16, []byte) {
body := &oidb.D6D6ReqBody{MoveFileReq: &oidb.MoveFileReqBody{
GroupCode: proto.Some(groupCode),
AppId: proto.Int32(5),
BusId: proto.Some(busId),
FileId: proto.Some(fileId),
ParentFolderId: proto.Some(parentFolderId),
DestFolderId: proto.Some(DestFolderId),
}}
payload := c.packOIDBPackageProto(1750, 5, body)
return c.uniPacket("OidbSvc.0x6d6_5", payload)
}
// GroupFileListRespPacket
func decodeOIDB6d81Response(_ *QQClient, pkt *network.Packet) (any, error) {
rsp := oidb.D6D8RspBody{}
err := unpackOIDBPackage(pkt.Payload, &rsp)
if err != nil {
return nil, err
} }
return &rsp, nil return &rsp, nil
} }
// OidbSvc.0x6d6_2 GroupFileDownloadRespPacket // OidbSvc.0x6d6_2
func decodeOIDB6d62Response(_ *QQClient, pkt *network.Packet) (any, error) { func decodeOIDB6d62Response(_ *QQClient, _ *incomingPacketInfo, payload []byte) (interface{}, error) {
rsp := oidb.D6D6RspBody{} pkg := oidb.OIDBSSOPkg{}
err := unpackOIDBPackage(pkt.Payload, &rsp) rsp := oidb0x6d6.RspBody{}
if err != nil { if err := protobuf.Unmarshal(payload, &pkg); err != nil {
return nil, err return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
}
if err := protobuf.Unmarshal(pkg.Bodybuffer, &rsp); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
if rsp.DownloadFileRsp.DownloadUrl == nil { if rsp.DownloadFileRsp.DownloadUrl == nil {
return nil, errors.New(rsp.DownloadFileRsp.ClientWording.Unwrap()) return nil, errors.New(rsp.DownloadFileRsp.GetClientWording())
} }
ip := rsp.DownloadFileRsp.DownloadIp.Unwrap() ip := rsp.DownloadFileRsp.GetDownloadIp()
url := hex.EncodeToString(rsp.DownloadFileRsp.DownloadUrl) url := hex.EncodeToString(rsp.DownloadFileRsp.DownloadUrl)
return fmt.Sprintf("http://%s/ftn_handler/%s/", ip, url), nil return fmt.Sprintf("http://%s/ftn_handler/%s/", ip, url), nil
} }
// GroupFileDeleteRespPacket func decodeOIDB6d63Response(_ *QQClient, _ *incomingPacketInfo, payload []byte) (interface{}, error) {
func decodeOIDB6d63Response(_ *QQClient, pkt *network.Packet) (any, error) { pkg := oidb.OIDBSSOPkg{}
rsp := oidb.D6D6RspBody{} rsp := oidb0x6d6.RspBody{}
err := unpackOIDBPackage(pkt.Payload, &rsp) if err := protobuf.Unmarshal(payload, &pkg); err != nil {
if err != nil { return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
return nil, err
} }
return rsp.DeleteFileRsp.ClientWording.Unwrap(), nil if err := protobuf.Unmarshal(pkg.Bodybuffer, &rsp); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
}
if rsp.DeleteFileRsp == nil {
return "", nil
}
return rsp.DeleteFileRsp.GetClientWording(), nil
} }
// GroupFileUploadRespPacket func decodeOIDB6d60Response(_ *QQClient, _ *incomingPacketInfo, payload []byte) (interface{}, error) {
func decodeOIDB6d60Response(_ *QQClient, pkt *network.Packet) (any, error) { pkg := oidb.OIDBSSOPkg{}
rsp := oidb.D6D6RspBody{} rsp := oidb0x6d6.RspBody{}
err := unpackOIDBPackage(pkt.Payload, &rsp) if err := protobuf.Unmarshal(payload, &pkg); err != nil {
if err != nil { return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
return nil, err
} }
u := rsp.UploadFileRsp if err := protobuf.Unmarshal(pkg.Bodybuffer, &rsp); err != nil {
r := &fileUploadRsp{ return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
Existed: u.BoolFileExist.Unwrap(),
BusID: u.BusId.Unwrap(),
Uuid: []byte(u.FileId.Unwrap()),
UploadKey: u.CheckKey,
UploadIpLanV4: u.UploadIpLanV4,
UploadPort: u.UploadPort.Unwrap(),
} }
return r, nil return rsp.UploadFileRsp, nil
} }
// GroupFileCreateFolderPacket, GroupFileDeleteFolderPacket, GroupFileRenameFolderPacket func decodeOIDB6d7Response(_ *QQClient, _ *incomingPacketInfo, payload []byte) (interface{}, error) {
func decodeOIDB6d7Response(_ *QQClient, pkt *network.Packet) (any, error) { pkg := oidb.OIDBSSOPkg{}
rsp := oidb.D6D7RspBody{} rsp := oidb0x6d7.RspBody{}
err := unpackOIDBPackage(pkt.Payload, &rsp) if err := protobuf.Unmarshal(payload, &pkg); err != nil {
if err != nil { return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
return nil, err
} }
if createRsp := rsp.CreateFolderRsp; createRsp != nil { if err := protobuf.Unmarshal(pkg.Bodybuffer, &rsp); err != nil {
if retCode := createRsp.RetCode.Unwrap(); retCode != 0 { return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
return nil, errors.Errorf("create folder error: %v", retCode)
}
} }
if renameRsp := rsp.RenameFolderRsp; renameRsp != nil { if rsp.CreateFolderRsp != nil && rsp.CreateFolderRsp.GetRetCode() != 0 {
if retCode := renameRsp.RetCode.Unwrap(); retCode != 0 { return nil, errors.Errorf("create folder error: %v", rsp.CreateFolderRsp.GetRetCode())
return nil, errors.Errorf("rename folder error: %v", retCode)
}
} }
if deleteRsp := rsp.DeleteFolderRsp; deleteRsp != nil { if rsp.RenameFolderRsp != nil && rsp.RenameFolderRsp.GetRetCode() != 0 {
if retCode := deleteRsp.RetCode.Unwrap(); retCode != 0 { return nil, errors.Errorf("rename folder error: %v", rsp.CreateFolderRsp.GetRetCode())
return nil, errors.Errorf("delete folder error: %v", retCode) }
} if rsp.DeleteFolderRsp != nil && rsp.DeleteFolderRsp.GetRetCode() != 0 {
return nil, errors.Errorf("delete folder error: %v", rsp.CreateFolderRsp.GetRetCode())
} }
return nil, nil return nil, nil
} }
// GroupFileRenameRespPacket
func decodeOIDB6d64Response(_ *QQClient, pkt *network.Packet) (any, error) {
rsp := oidb.D6D6RspBody{}
err := unpackOIDBPackage(pkt.Payload, &rsp)
if err != nil {
return nil, err
}
return rsp.RenameFileRsp.ClientWording.Unwrap(), nil
}
// GroupFileMoveRespPacket
func decodeOIDB6d65Response(_ *QQClient, pkt *network.Packet) (any, error) {
rsp := oidb.D6D6RspBody{}
err := unpackOIDBPackage(pkt.Payload, &rsp)
if err != nil {
return nil, err
}
return rsp.MoveFileRsp.ClientWording.Unwrap(), nil
}

View File

@ -1,24 +1,24 @@
package client package client
import ( import (
"bytes"
"encoding/json" "encoding/json"
"fmt" "fmt"
"math/rand" "math/rand"
"net/http"
"net/url" "net/url"
"sort" "sort"
"strings" "strings"
"sync" "sync"
"github.com/pkg/errors" "github.com/pkg/errors"
protobuf "github.com/segmentio/encoding/proto"
"google.golang.org/protobuf/proto"
"github.com/Mrs4s/MiraiGo/binary" "github.com/Mrs4s/MiraiGo/binary"
"github.com/Mrs4s/MiraiGo/binary/jce" "github.com/Mrs4s/MiraiGo/binary/jce"
"github.com/Mrs4s/MiraiGo/client/internal/network"
"github.com/Mrs4s/MiraiGo/client/pb/oidb"
"github.com/Mrs4s/MiraiGo/client/pb/profilecard" "github.com/Mrs4s/MiraiGo/client/pb/profilecard"
"github.com/Mrs4s/MiraiGo/internal/proto" "github.com/Mrs4s/MiraiGo/internal/packets"
"github.com/Mrs4s/MiraiGo/internal/protobuf/data/oidb"
"github.com/Mrs4s/MiraiGo/internal/protobuf/data/oidb/oidb0x88d"
"github.com/Mrs4s/MiraiGo/utils" "github.com/Mrs4s/MiraiGo/utils"
) )
@ -27,6 +27,7 @@ type (
Uin int64 Uin int64
Code int64 Code int64
Name string Name string
Memo string
OwnerUin int64 OwnerUin int64
GroupCreateTime uint32 GroupCreateTime uint32
GroupLevel uint32 GroupLevel uint32
@ -42,17 +43,18 @@ type (
} }
GroupMemberInfo struct { GroupMemberInfo struct {
Group *GroupInfo Group *GroupInfo
Uin int64 Uin int64
Nickname string Gender byte
CardName string Nickname string
JoinTime int64 CardName string
LastSpeakTime int64 Level uint16
SpecialTitle string JoinTime int64
ShutUpTimestamp int64 LastSpeakTime int64
Permission MemberPermission SpecialTitle string
Level uint16 SpecialTitleExpireTime int64
Gender byte ShutUpTimestamp int64
Permission MemberPermission
} }
// GroupSearchInfo 通过搜索得到的群信息 // GroupSearchInfo 通过搜索得到的群信息
@ -78,12 +80,13 @@ func (c *QQClient) GetGroupInfo(groupCode int64) (*GroupInfo, error) {
// OidbSvc.0x88d_0 // OidbSvc.0x88d_0
func (c *QQClient) buildGroupInfoRequestPacket(groupCode int64) (uint16, []byte) { func (c *QQClient) buildGroupInfoRequestPacket(groupCode int64) (uint16, []byte) {
body := &oidb.D88DReqBody{ seq := c.nextSeq()
AppId: proto.Uint32(c.version().AppId), body := &oidb0x88d.ReqBody{
ReqGroupInfo: []*oidb.ReqGroupInfo{ Appid: proto.Uint32(c.version.AppId),
Stzreqgroupinfo: []*oidb0x88d.ReqGroupInfo{
{ {
GroupCode: proto.Uint64(uint64(groupCode)), GroupCode: proto.Uint64(uint64(groupCode)),
Stgroupinfo: &oidb.D88DGroupInfo{ Stgroupinfo: &oidb0x88d.GroupInfo{
GroupOwner: proto.Uint64(0), GroupOwner: proto.Uint64(0),
GroupUin: proto.Uint64(0), GroupUin: proto.Uint64(0),
GroupCreateTime: proto.Uint32(0), GroupCreateTime: proto.Uint32(0),
@ -103,8 +106,8 @@ func (c *QQClient) buildGroupInfoRequestPacket(groupCode int64) (uint16, []byte)
GroupGrade: proto.Uint32(0), GroupGrade: proto.Uint32(0),
ActiveMemberNum: proto.Uint32(0), ActiveMemberNum: proto.Uint32(0),
HeadPortraitSeq: proto.Uint32(0), HeadPortraitSeq: proto.Uint32(0),
MsgHeadPortrait: &oidb.D88DGroupHeadPortrait{}, HeadPortrait: &oidb0x88d.GroupHeadPortrait{},
StGroupExInfo: &oidb.D88DGroupExInfoOnly{}, StGroupExInfo: &oidb0x88d.GroupExInfoOnly{},
GroupSecLevel: proto.Uint32(0), GroupSecLevel: proto.Uint32(0),
CmduinPrivilege: proto.Uint32(0), CmduinPrivilege: proto.Uint32(0),
NoFingerOpenFlag: proto.Uint32(0), NoFingerOpenFlag: proto.Uint32(0),
@ -114,8 +117,9 @@ func (c *QQClient) buildGroupInfoRequestPacket(groupCode int64) (uint16, []byte)
}, },
PcClientVersion: proto.Uint32(0), PcClientVersion: proto.Uint32(0),
} }
payload := c.packOIDBPackageProto(2189, 0, body) payload := c.packOIDBPackageProto2(2189, 0, body)
return c.uniPacket("OidbSvc.0x88d_0", payload) packet := packets.BuildUniPacket(c.Uin, seq, "OidbSvc.0x88d_0", 1, c.OutGoingPacketSessionId, EmptyBytes, c.sigInfo.d2Key, payload)
return seq, packet
} }
// SearchGroupByKeyword 通过关键词搜索陌生群组 // SearchGroupByKeyword 通过关键词搜索陌生群组
@ -129,6 +133,7 @@ func (c *QQClient) SearchGroupByKeyword(keyword string) ([]GroupSearchInfo, erro
// SummaryCard.ReqSearch // SummaryCard.ReqSearch
func (c *QQClient) buildGroupSearchPacket(keyword string) (uint16, []byte) { func (c *QQClient) buildGroupSearchPacket(keyword string) (uint16, []byte) {
seq := c.nextSeq()
comm, _ := proto.Marshal(&profilecard.BusiComm{ comm, _ := proto.Marshal(&profilecard.BusiComm{
Ver: proto.Int32(1), Ver: proto.Int32(1),
Seq: proto.Int32(rand.Int31()), Seq: proto.Int32(rand.Int31()),
@ -140,7 +145,7 @@ func (c *QQClient) buildGroupSearchPacket(keyword string) (uint16, []byte) {
search, _ := proto.Marshal(&profilecard.AccountSearch{ search, _ := proto.Marshal(&profilecard.AccountSearch{
Start: proto.Int32(0), Start: proto.Int32(0),
End: proto.Uint32(4), End: proto.Uint32(4),
Keyword: proto.Some(keyword), Keyword: &keyword,
Highlight: []string{keyword}, Highlight: []string{keyword},
UserLocation: &profilecard.Location{ UserLocation: &profilecard.Location{
Latitude: proto.Float64(0), Latitude: proto.Float64(0),
@ -177,13 +182,14 @@ func (c *QQClient) buildGroupSearchPacket(keyword string) (uint16, []byte) {
Context: make(map[string]string), Context: make(map[string]string),
Status: make(map[string]string), Status: make(map[string]string),
} }
return c.uniPacket("SummaryCard.ReqSearch", pkt.ToBytes()) packet := packets.BuildUniPacket(c.Uin, seq, "SummaryCard.ReqSearch", 1, c.OutGoingPacketSessionId, []byte{}, c.sigInfo.d2Key, pkt.ToBytes())
return seq, packet
} }
// SummaryCard.ReqSearch // SummaryCard.ReqSearch
func decodeGroupSearchResponse(_ *QQClient, pkt *network.Packet) (any, error) { func decodeGroupSearchResponse(_ *QQClient, _ *incomingPacketInfo, payload []byte) (interface{}, error) {
request := &jce.RequestPacket{} request := &jce.RequestPacket{}
request.ReadFrom(jce.NewJceReader(pkt.Payload)) request.ReadFrom(jce.NewJceReader(payload))
data := &jce.RequestDataVersion2{} data := &jce.RequestDataVersion2{}
data.ReadFrom(jce.NewJceReader(request.SBuffer)) data.ReadFrom(jce.NewJceReader(request.SBuffer))
if len(data.Map["RespHead"]["SummaryCard.RespHead"]) > 20 { if len(data.Map["RespHead"]["SummaryCard.RespHead"]) > 20 {
@ -191,8 +197,7 @@ func decodeGroupSearchResponse(_ *QQClient, pkt *network.Packet) (any, error) {
} }
rsp := data.Map["RespSearch"]["SummaryCard.RespSearch"][1:] rsp := data.Map["RespSearch"]["SummaryCard.RespSearch"][1:]
r := jce.NewJceReader(rsp) r := jce.NewJceReader(rsp)
// rspService := r.ReadAny(2).([]interface{})[0].([]byte) rspService := r.ReadAny(2).([]interface{})[0].([]byte)
rspService := r.ReadByteArrArr(2)[0]
sr := binary.NewReader(rspService) sr := binary.NewReader(rspService)
sr.ReadByte() sr.ReadByte()
ld1 := sr.ReadInt32() ld1 := sr.ReadInt32()
@ -206,11 +211,11 @@ func decodeGroupSearchResponse(_ *QQClient, pkt *network.Packet) (any, error) {
return nil, errors.Wrap(err, "get search result failed") return nil, errors.Wrap(err, "get search result failed")
} }
var ret []GroupSearchInfo var ret []GroupSearchInfo
for _, g := range searchRsp.List { for _, g := range searchRsp.GetList() {
ret = append(ret, GroupSearchInfo{ ret = append(ret, GroupSearchInfo{
Code: int64(g.Code.Unwrap()), Code: int64(g.GetCode()),
Name: g.Name.Unwrap(), Name: g.GetName(),
Memo: g.Brief.Unwrap(), Memo: g.GetBrief(),
}) })
} }
return ret, nil return ret, nil
@ -219,48 +224,38 @@ func decodeGroupSearchResponse(_ *QQClient, pkt *network.Packet) (any, error) {
} }
// OidbSvc.0x88d_0 // OidbSvc.0x88d_0
func decodeGroupInfoResponse(c *QQClient, pkt *network.Packet) (any, error) { func decodeGroupInfoResponse(c *QQClient, _ *incomingPacketInfo, payload []byte) (interface{}, error) {
rsp := oidb.D88DRspBody{} pkg := oidb.OIDBSSOPkg{}
err := unpackOIDBPackage(pkt.Payload, &rsp) rsp := oidb0x88d.RspBody{}
if err != nil { if err := protobuf.Unmarshal(payload, &pkg); err != nil {
return nil, err return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
if len(rsp.RspGroupInfo) == 0 { if err := protobuf.Unmarshal(pkg.Bodybuffer, &rsp); err != nil {
return nil, errors.New(string(rsp.StrErrorInfo)) return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
info := rsp.RspGroupInfo[0] if len(rsp.Stzrspgroupinfo) == 0 {
if info.GroupInfo == nil { return nil, errors.New(string(rsp.Errorinfo))
}
info := rsp.Stzrspgroupinfo[0]
if info.Stgroupinfo == nil {
return nil, errors.New("group info not found") return nil, errors.New("group info not found")
} }
return &GroupInfo{ return &GroupInfo{
Uin: int64(info.GroupInfo.GroupUin.Unwrap()), Uin: int64(*info.Stgroupinfo.GroupUin),
Code: int64(info.GroupCode.Unwrap()), Code: int64(*info.GroupCode),
Name: string(info.GroupInfo.GroupName), Name: string(info.Stgroupinfo.GroupName),
GroupCreateTime: info.GroupInfo.GroupCreateTime.Unwrap(), Memo: string(info.Stgroupinfo.GroupMemo),
GroupLevel: info.GroupInfo.GroupLevel.Unwrap(), GroupCreateTime: *info.Stgroupinfo.GroupCreateTime,
OwnerUin: int64(info.GroupInfo.GroupOwner.Unwrap()), GroupLevel: *info.Stgroupinfo.GroupLevel,
MemberCount: uint16(info.GroupInfo.GroupMemberNum.Unwrap()), OwnerUin: int64(*info.Stgroupinfo.GroupOwner),
MaxMemberCount: uint16(info.GroupInfo.GroupMemberMaxNum.Unwrap()), MemberCount: uint16(*info.Stgroupinfo.GroupMemberNum),
MaxMemberCount: uint16(*info.Stgroupinfo.GroupMemberMaxNum),
Members: []*GroupMemberInfo{}, Members: []*GroupMemberInfo{},
LastMsgSeq: int64(info.GroupInfo.GroupCurMsgSeq.Unwrap()), LastMsgSeq: int64(info.Stgroupinfo.GetGroupCurMsgSeq()),
client: c, client: c,
}, nil }, nil
} }
func (c *QQClient) uploadGroupHeadPortrait(groupCode int64, img []byte) error {
url := fmt.Sprintf("http://htdata3.qq.com/cgi-bin/httpconn?htcmd=0x6ff0072&ver=5520&ukey=%v&range=0&uin=%v&seq=23&groupuin=%v&filetype=3&imagetype=5&userdata=0&subcmd=1&subver=101&clip=0_0_0_0&filesize=%v",
c.getSKey(), c.Uin, groupCode, len(img))
req, _ := http.NewRequest(http.MethodPost, url, bytes.NewReader(img))
req.Header["User-Agent"] = []string{"Dalvik/2.1.0 (Linux; U; Android 7.1.2; PCRT00 Build/N2G48H)"}
req.Header["Content-Type"] = []string{"multipart/form-data;boundary=****"}
rsp, err := http.DefaultClient.Do(req)
if err != nil {
return errors.Wrap(err, "failed to upload group head portrait")
}
rsp.Body.Close()
return nil
}
func (g *GroupInfo) UpdateName(newName string) { func (g *GroupInfo) UpdateName(newName string) {
if g.AdministratorOrOwner() && newName != "" && strings.Count(newName, "") <= 20 { if g.AdministratorOrOwner() && newName != "" && strings.Count(newName, "") <= 20 {
g.client.updateGroupName(g.Code, newName) g.client.updateGroupName(g.Code, newName)
@ -268,6 +263,13 @@ func (g *GroupInfo) UpdateName(newName string) {
} }
} }
func (g *GroupInfo) UpdateMemo(newMemo string) {
if g.AdministratorOrOwner() {
g.client.updateGroupMemo(g.Code, newMemo)
g.Memo = newMemo
}
}
func (g *GroupInfo) UpdateGroupHeadPortrait(img []byte) { func (g *GroupInfo) UpdateGroupHeadPortrait(img []byte) {
if g.AdministratorOrOwner() { if g.AdministratorOrOwner() {
_ = g.client.uploadGroupHeadPortrait(g.Uin, img) _ = g.client.uploadGroupHeadPortrait(g.Uin, img)
@ -318,7 +320,7 @@ func (g *GroupInfo) AdministratorOrOwner() bool {
} }
func (g *GroupInfo) FindMember(uin int64) *GroupMemberInfo { func (g *GroupInfo) FindMember(uin int64) *GroupMemberInfo {
r := g.Read(func(info *GroupInfo) any { r := g.Read(func(info *GroupInfo) interface{} {
return info.FindMemberWithoutLock(uin) return info.FindMemberWithoutLock(uin)
}) })
if r == nil { if r == nil {
@ -350,7 +352,7 @@ func (g *GroupInfo) Update(f func(*GroupInfo)) {
f(g) f(g)
} }
func (g *GroupInfo) Read(f func(*GroupInfo) any) any { func (g *GroupInfo) Read(f func(*GroupInfo) interface{}) interface{} {
g.lock.RLock() g.lock.RLock()
defer g.lock.RUnlock() defer g.lock.RUnlock()
return f(g) return f(g)
@ -389,7 +391,7 @@ func (m *GroupMemberInfo) EditSpecialTitle(title string) {
func (m *GroupMemberInfo) Kick(msg string, block bool) error { func (m *GroupMemberInfo) Kick(msg string, block bool) error {
if m.Uin != m.Group.client.Uin && m.Manageable() { if m.Uin != m.Group.client.Uin && m.Manageable() {
m.Group.client.KickGroupMembers(m.Group.Code, msg, block, m.Uin) m.Group.client.kickGroupMember(m.Group.Code, m.Uin, msg, block)
return nil return nil
} else { } else {
return errors.New("not manageable") return errors.New("not manageable")
@ -408,12 +410,6 @@ func (m *GroupMemberInfo) Mute(time uint32) error {
} }
} }
func (g *GroupInfo) SetAnonymous(enable bool) {
if g.AdministratorOrOwner() {
g.client.setGroupAnonymous(g.Code, enable)
}
}
func (m *GroupMemberInfo) Manageable() bool { func (m *GroupMemberInfo) Manageable() bool {
if m.Uin == m.Group.client.Uin { if m.Uin == m.Group.client.Uin {
return true return true

View File

@ -4,6 +4,7 @@ import (
"bytes" "bytes"
"encoding/base64" "encoding/base64"
"encoding/json" "encoding/json"
"fmt"
"math" "math"
"math/rand" "math/rand"
"strconv" "strconv"
@ -11,14 +12,17 @@ import (
"time" "time"
"github.com/pkg/errors" "github.com/pkg/errors"
protobuf "github.com/segmentio/encoding/proto"
"google.golang.org/protobuf/proto"
"github.com/Mrs4s/MiraiGo/client/internal/network"
"github.com/Mrs4s/MiraiGo/client/pb/cmd0x388"
"github.com/Mrs4s/MiraiGo/client/pb/longmsg" "github.com/Mrs4s/MiraiGo/client/pb/longmsg"
"github.com/Mrs4s/MiraiGo/client/pb/msg"
"github.com/Mrs4s/MiraiGo/client/pb/multimsg" "github.com/Mrs4s/MiraiGo/client/pb/multimsg"
"github.com/Mrs4s/MiraiGo/client/pb/oidb" "github.com/Mrs4s/MiraiGo/internal/packets"
"github.com/Mrs4s/MiraiGo/internal/proto" "github.com/Mrs4s/MiraiGo/internal/protobuf/data/msg"
"github.com/Mrs4s/MiraiGo/internal/protobuf/data/oidb"
"github.com/Mrs4s/MiraiGo/internal/protobuf/data/oidb/oidb0x8a7"
"github.com/Mrs4s/MiraiGo/internal/protobuf/data/oidb/oidb0x8fc"
"github.com/Mrs4s/MiraiGo/internal/protobuf/data/oidb/oidb0xeac"
"github.com/Mrs4s/MiraiGo/message" "github.com/Mrs4s/MiraiGo/message"
"github.com/Mrs4s/MiraiGo/utils" "github.com/Mrs4s/MiraiGo/utils"
) )
@ -33,18 +37,40 @@ func init() {
} }
// SendGroupMessage 发送群消息 // SendGroupMessage 发送群消息
func (c *QQClient) SendGroupMessage(groupCode int64, m *message.SendingMessage) *message.GroupMessage { func (c *QQClient) SendGroupMessage(groupCode int64, m *message.SendingMessage, f ...bool) *message.GroupMessage {
useFram := false
if len(f) > 0 {
useFram = f[0]
}
imgCount := 0 imgCount := 0
for _, e := range m.Elements { for _, e := range m.Elements {
switch e.Type() { switch e.Type() {
case message.Image: case message.Image:
imgCount++ imgCount++
case message.Reply:
useFram = false
} }
} }
msgLen := message.EstimateLength(m.Elements) msgLen := message.EstimateLength(m.Elements)
if msgLen > message.MaxMessageSize || imgCount > 50 { if msgLen > 5000 || imgCount > 50 {
return nil return nil
} }
if !useFram && (msgLen > 100 || imgCount > 2) {
ret := c.sendGroupMessage(groupCode, false,
&message.SendingMessage{Elements: []message.IMessageElement{
c.uploadGroupLongMessage(groupCode,
message.NewForwardMessage().AddNode(&message.ForwardNode{
SenderId: c.Uin,
SenderName: c.Nickname,
Time: int32(time.Now().Unix()),
Message: m.Elements,
}),
),
}},
)
ret.Elements = m.Elements
return ret
}
return c.sendGroupMessage(groupCode, false, m) return c.sendGroupMessage(groupCode, false, m)
} }
@ -58,7 +84,7 @@ func (c *QQClient) SendGroupForwardMessage(groupCode int64, m *message.ForwardEl
// GetGroupMessages 从服务器获取历史信息 // GetGroupMessages 从服务器获取历史信息
func (c *QQClient) GetGroupMessages(groupCode, beginSeq, endSeq int64) ([]*message.GroupMessage, error) { func (c *QQClient) GetGroupMessages(groupCode, beginSeq, endSeq int64) ([]*message.GroupMessage, error) {
seq, pkt := c.buildGetGroupMsgRequest(groupCode, beginSeq, endSeq) seq, pkt := c.buildGetGroupMsgRequest(groupCode, beginSeq, endSeq)
i, err := c.sendAndWait(seq, pkt, network.RequestParams{"raw": false}) i, err := c.sendAndWait(seq, pkt, requestParams{"raw": false})
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -96,7 +122,7 @@ func (c *QQClient) sendGroupMessage(groupCode int64, forward bool, m *message.Se
serviceFlag = false serviceFlag = false
} }
} }
if !forward && serviceFlag && c.UseFragmentMessage && (imgCount > 1 || message.EstimateLength(m.Elements) > 100) { if !forward && serviceFlag && (imgCount > 1 || message.EstimateLength(m.Elements) > 100) {
div := int32(rand.Uint32()) div := int32(rand.Uint32())
fragmented := m.ToFragmented() fragmented := m.ToFragmented()
for i, elems := range fragmented { for i, elems := range fragmented {
@ -138,6 +164,51 @@ func (c *QQClient) sendGroupMessage(groupCode int64, forward bool, m *message.Se
} }
} }
func (c *QQClient) uploadGroupLongMessage(groupCode int64, m *message.ForwardMessage) *message.ServiceElement {
if m.Length() >= 200 {
return nil
}
ts := time.Now().UnixNano()
seq := c.nextGroupSeq()
data, hash := m.CalculateValidationData(seq, rand.Int31(), groupCode)
rsp, body, err := c.multiMsgApplyUp(groupCode, data, hash, 1)
if err != nil {
c.Error("upload long message error: %v", err)
return nil
}
for i, ip := range rsp.Uint32UpIp {
err := c.highwayUpload(uint32(ip), int(rsp.Uint32UpPort[i]), rsp.MsgSig, body, 27)
if err != nil {
c.Error("highway upload long message error: %v", err)
continue
}
return genLongTemplate(rsp.MsgResid, m.Brief(), ts)
}
c.Error("upload long message error: highway server list is empty or not available server.")
return nil
}
func (c *QQClient) UploadGroupForwardMessage(groupCode int64, m *message.ForwardMessage) *message.ForwardElement {
if m.Length() > 200 {
return nil
}
ts := time.Now().UnixNano()
seq := c.nextGroupSeq()
data, hash, items := m.CalculateValidationDataForward(seq, rand.Int31(), groupCode)
rsp, body, err := c.multiMsgApplyUp(groupCode, data, hash, 2)
if err != nil {
return nil
}
for i, ip := range rsp.Uint32UpIp {
err := c.highwayUpload(uint32(ip), int(rsp.Uint32UpPort[i]), rsp.MsgSig, body, 27)
if err != nil {
continue
}
return genForwardTemplate(rsp.MsgResid, m.Preview(), "群聊的聊天记录", "[聊天记录]", "聊天记录", fmt.Sprintf("查看 %d 条转发消息", m.Length()), ts, items)
}
return nil
}
func (c *QQClient) multiMsgApplyUp(groupCode int64, data []byte, hash []byte, buType int32) (*multimsg.MultiMsgApplyUpRsp, []byte, error) { func (c *QQClient) multiMsgApplyUp(groupCode int64, data []byte, hash []byte, buType int32) (*multimsg.MultiMsgApplyUpRsp, []byte, error) {
i, err := c.sendAndWait(c.buildMultiApplyUpPacket(data, hash, buType, utils.ToGroupUin(groupCode))) i, err := c.sendAndWait(c.buildMultiApplyUpPacket(data, hash, buType, utils.ToGroupUin(groupCode)))
if err != nil { if err != nil {
@ -163,6 +234,7 @@ func (c *QQClient) multiMsgApplyUp(groupCode int64, data []byte, hash []byte, bu
// MessageSvc.PbSendMsg // MessageSvc.PbSendMsg
func (c *QQClient) buildGroupSendingPacket(groupCode int64, r, pkgNum, pkgIndex, pkgDiv int32, forward bool, m []message.IMessageElement) (uint16, []byte) { func (c *QQClient) buildGroupSendingPacket(groupCode int64, r, pkgNum, pkgIndex, pkgDiv int32, forward bool, m []message.IMessageElement) (uint16, []byte) {
seq := c.nextSeq()
var ptt *message.GroupVoiceElement var ptt *message.GroupVoiceElement
if len(m) > 0 { if len(m) > 0 {
if p, ok := m[0].(*message.GroupVoiceElement); ok { if p, ok := m[0].(*message.GroupVoiceElement); ok {
@ -171,8 +243,8 @@ func (c *QQClient) buildGroupSendingPacket(groupCode int64, r, pkgNum, pkgIndex,
} }
} }
req := &msg.SendMessageRequest{ req := &msg.SendMessageRequest{
RoutingHead: &msg.RoutingHead{Grp: &msg.Grp{GroupCode: proto.Some(groupCode)}}, RoutingHead: &msg.RoutingHead{Grp: &msg.Grp{GroupCode: &groupCode}},
ContentHead: &msg.ContentHead{PkgNum: proto.Some(pkgNum), PkgIndex: proto.Some(pkgIndex), DivSeq: proto.Some(pkgDiv)}, ContentHead: &msg.ContentHead{PkgNum: &pkgNum, PkgIndex: &pkgIndex, DivSeq: &pkgDiv},
MsgBody: &msg.MessageBody{ MsgBody: &msg.MessageBody{
RichText: &msg.RichText{ RichText: &msg.RichText{
Elems: message.ToProtoElems(m, true), Elems: message.ToProtoElems(m, true),
@ -185,7 +257,7 @@ func (c *QQClient) buildGroupSendingPacket(groupCode int64, r, pkgNum, pkgIndex,
}, },
}, },
MsgSeq: proto.Int32(c.nextGroupSeq()), MsgSeq: proto.Int32(c.nextGroupSeq()),
MsgRand: proto.Some(r), MsgRand: &r,
SyncCookie: EmptyBytes, SyncCookie: EmptyBytes,
MsgVia: proto.Int32(1), MsgVia: proto.Int32(1),
MsgCtrl: func() *msg.MsgCtrl { MsgCtrl: func() *msg.MsgCtrl {
@ -195,117 +267,126 @@ func (c *QQClient) buildGroupSendingPacket(groupCode int64, r, pkgNum, pkgIndex,
return nil return nil
}(), }(),
} }
payload, _ := proto.Marshal(req) payload, _ := protobuf.Marshal(req)
return c.uniPacket("MessageSvc.PbSendMsg", payload) packet := packets.BuildUniPacket(c.Uin, seq, "MessageSvc.PbSendMsg", 1, c.OutGoingPacketSessionId, EmptyBytes, c.sigInfo.d2Key, payload)
return seq, packet
} }
func (c *QQClient) buildGetGroupMsgRequest(groupCode, beginSeq, endSeq int64) (uint16, []byte) { func (c *QQClient) buildGetGroupMsgRequest(groupCode, beginSeq, endSeq int64) (uint16, []byte) {
seq := c.nextSeq()
req := &msg.GetGroupMsgReq{ req := &msg.GetGroupMsgReq{
GroupCode: proto.Uint64(uint64(groupCode)), GroupCode: proto.Uint64(uint64(groupCode)),
BeginSeq: proto.Uint64(uint64(beginSeq)), BeginSeq: proto.Uint64(uint64(beginSeq)),
EndSeq: proto.Uint64(uint64(endSeq)), EndSeq: proto.Uint64(uint64(endSeq)),
PublicGroup: proto.Bool(false), PublicGroup: proto.Bool(false),
} }
payload, _ := proto.Marshal(req) payload, _ := protobuf.Marshal(req)
return c.uniPacket("MessageSvc.PbGetGroupMsg", payload) packet := packets.BuildUniPacket(c.Uin, seq, "MessageSvc.PbGetGroupMsg", 1, c.OutGoingPacketSessionId, EmptyBytes, c.sigInfo.d2Key, payload)
return seq, packet
} }
func (c *QQClient) buildAtAllRemainRequestPacket(groupCode int64) (uint16, []byte) { func (c *QQClient) buildAtAllRemainRequestPacket(groupCode int64) (uint16, []byte) {
payload := c.packOIDBPackageProto(2215, 0, &oidb.D8A7ReqBody{ seq := c.nextSeq()
payload := c.packOIDBPackageProto2(2215, 0, &oidb0x8a7.ReqBody{
SubCmd: proto.Uint32(1), SubCmd: proto.Uint32(1),
LimitIntervalTypeForUin: proto.Uint32(2), LimitIntervalTypeForUin: proto.Uint32(2),
LimitIntervalTypeForGroup: proto.Uint32(1), LimitIntervalTypeForGroup: proto.Uint32(1),
Uin: proto.Uint64(uint64(c.Uin)), Uin: proto.Uint64(uint64(c.Uin)),
GroupCode: proto.Uint64(uint64(groupCode)), GroupCode: proto.Uint64(uint64(groupCode)),
}) })
return c.uniPacket("OidbSvc.0x8a7_0", payload) packet := packets.BuildUniPacket(c.Uin, seq, "OidbSvc.0x8a7_0", 1, c.OutGoingPacketSessionId, EmptyBytes, c.sigInfo.d2Key, payload)
return seq, packet
} }
// OnlinePush.PbPushGroupMsg // OnlinePush.PbPushGroupMsg
func decodeGroupMessagePacket(c *QQClient, packet *network.Packet) (any, error) { func decodeGroupMessagePacket(c *QQClient, _ *incomingPacketInfo, payload []byte) (interface{}, error) {
pkt := msg.PushMessagePacket{} pkt := msg.PushMessagePacket{}
err := proto.Unmarshal(packet.Payload, &pkt) err := protobuf.Unmarshal(payload, &pkt)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
if pkt.Message.Head.FromUin.Unwrap() == c.Uin { if pkt.Message.Head.GetFromUin() == c.Uin {
c.dispatchGroupMessageReceiptEvent(&groupMessageReceiptEvent{ c.dispatchGroupMessageReceiptEvent(&groupMessageReceiptEvent{
Rand: pkt.Message.Body.RichText.Attr.Random.Unwrap(), Rand: pkt.Message.Body.RichText.Attr.GetRandom(),
Seq: pkt.Message.Head.MsgSeq.Unwrap(), Seq: pkt.Message.Head.GetMsgSeq(),
Msg: c.parseGroupMessage(pkt.Message), Msg: c.parseGroupMessage(pkt.Message),
}) })
} }
if pkt.Message.Content != nil && pkt.Message.Content.PkgNum.Unwrap() > 1 { if pkt.Message.Content != nil && pkt.Message.Content.GetPkgNum() > 1 {
seq := pkt.Message.Content.DivSeq.Unwrap() var builder *groupMessageBuilder
builder := c.messageBuilder(pkt.Message.Content.DivSeq.Unwrap()) i, ok := c.groupMsgBuilders.Load(pkt.Message.Content.GetDivSeq())
builder.append(pkt.Message) if !ok {
if builder.len() >= pkt.Message.Content.PkgNum.Unwrap() { builder = &groupMessageBuilder{}
c.msgBuilders.Delete(seq) c.groupMsgBuilders.Store(pkt.Message.Content.GetDivSeq(), builder)
if pkt.Message.Head.FromUin.Unwrap() == c.Uin { } else {
c.SelfGroupMessageEvent.dispatch(c, c.parseGroupMessage(builder.build())) builder = i.(*groupMessageBuilder)
}
builder.MessageSlices = append(builder.MessageSlices, pkt.Message)
if int32(len(builder.MessageSlices)) >= pkt.Message.Content.GetPkgNum() {
c.groupMsgBuilders.Delete(pkt.Message.Content.GetDivSeq())
if pkt.Message.Head.GetFromUin() == c.Uin {
c.dispatchGroupMessageSelf(c.parseGroupMessage(builder.build()))
} else { } else {
c.GroupMessageEvent.dispatch(c, c.parseGroupMessage(builder.build())) c.dispatchGroupMessage(c.parseGroupMessage(builder.build()))
} }
} }
return nil, nil return nil, nil
} }
if pkt.Message.Head.FromUin.Unwrap() == c.Uin { if pkt.Message.Head.GetFromUin() == c.Uin {
c.SelfGroupMessageEvent.dispatch(c, c.parseGroupMessage(pkt.Message)) c.dispatchGroupMessageSelf(c.parseGroupMessage(pkt.Message))
} else { } else {
c.GroupMessageEvent.dispatch(c, c.parseGroupMessage(pkt.Message)) c.dispatchGroupMessage(c.parseGroupMessage(pkt.Message))
} }
return nil, nil return nil, nil
} }
func decodeMsgSendResponse(c *QQClient, pkt *network.Packet) (any, error) { func decodeMsgSendResponse(c *QQClient, _ *incomingPacketInfo, payload []byte) (interface{}, error) {
rsp := msg.SendMessageResponse{} rsp := msg.SendMessageResponse{}
if err := proto.Unmarshal(pkt.Payload, &rsp); err != nil { if err := protobuf.Unmarshal(payload, &rsp); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
switch rsp.Result.Unwrap() { switch rsp.GetResult() {
case 0: // OK. case 0: // OK.
case 46:
c.error("sendPacket msg error: 需要使用安全设备验证")
case 55: case 55:
c.error("sendPacket msg error: %v Bot has been blocked ta.'s content", rsp.Result.Unwrap()) c.Error("sendPacket msg error: %v Bot has blocked target's content", rsp.GetResult())
default: default:
c.error("sendPacket msg error: %v %v", rsp.Result.Unwrap(), rsp.ErrMsg.Unwrap()) c.Error("sendPacket msg error: %v %v", rsp.GetResult(), rsp.GetErrMsg())
} }
return nil, nil return nil, nil
} }
func decodeGetGroupMsgResponse(c *QQClient, pkt *network.Packet) (any, error) { func decodeGetGroupMsgResponse(c *QQClient, info *incomingPacketInfo, payload []byte) (interface{}, error) {
rsp := msg.GetGroupMsgResp{} rsp := msg.GetGroupMsgResp{}
if err := proto.Unmarshal(pkt.Payload, &rsp); err != nil { if err := protobuf.Unmarshal(payload, &rsp); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
if rsp.Result.Unwrap() != 0 { if rsp.GetResult() != 0 {
c.error("get msg error: %v %v", rsp.Result.Unwrap(), rsp.Errmsg.Unwrap()) c.Error("get msg error: %v %v", rsp.GetResult(), rsp.GetErrmsg())
return nil, errors.Errorf("get msg error: %v msg: %v", rsp.Result.Unwrap(), rsp.Errmsg.Unwrap()) return nil, errors.Errorf("get msg error: %v msg: %v", rsp.GetResult(), rsp.GetErrmsg())
} }
var ret []*message.GroupMessage var ret []*message.GroupMessage
for _, m := range rsp.Msg { for _, m := range rsp.Msg {
if m.Head.FromUin.IsNone() { if m.Head.FromUin == nil {
continue continue
} }
if m.Content != nil && m.Content.PkgNum.Unwrap() > 1 && !pkt.Params.Bool("raw") { if m.Content != nil && m.Content.GetPkgNum() > 1 && !info.Params.bool("raw") {
if m.Content.PkgIndex.Unwrap() == 0 { if m.Content.GetPkgIndex() == 0 {
c.debug("build fragmented message from history") c.Debug("build fragmented message from history")
i := m.Head.MsgSeq.Unwrap() - m.Content.PkgNum.Unwrap() i := m.Head.GetMsgSeq() - m.Content.GetPkgNum()
builder := &messageBuilder{} builder := &groupMessageBuilder{}
for { for {
end := int32(math.Min(float64(i+19), float64(m.Head.MsgSeq.Unwrap()+m.Content.PkgNum.Unwrap()))) end := int32(math.Min(float64(i+19), float64(m.Head.GetMsgSeq()+m.Content.GetPkgNum())))
seq, pkt := c.buildGetGroupMsgRequest(m.Head.GroupInfo.GroupCode.Unwrap(), int64(i), int64(end)) seq, pkt := c.buildGetGroupMsgRequest(m.Head.GroupInfo.GetGroupCode(), int64(i), int64(end))
data, err := c.sendAndWait(seq, pkt, network.RequestParams{"raw": true}) data, err := c.sendAndWait(seq, pkt, requestParams{"raw": true})
if err != nil { if err != nil {
return nil, errors.Wrap(err, "build fragmented message error") return nil, errors.Wrap(err, "build fragmented message error")
} }
for _, fm := range data.([]*message.GroupMessage) { for _, fm := range data.([]*message.GroupMessage) {
if fm.OriginalObject.Content != nil && fm.OriginalObject.Content.DivSeq.Unwrap() == m.Content.DivSeq.Unwrap() { if fm.OriginalObject.Content != nil && fm.OriginalObject.Content.GetDivSeq() == m.Content.GetDivSeq() {
builder.append(fm.OriginalObject) builder.MessageSlices = append(builder.MessageSlices, fm.OriginalObject)
} }
} }
if end >= m.Head.MsgSeq.Unwrap()+m.Content.PkgNum.Unwrap() { if end >= m.Head.GetMsgSeq()+m.Content.GetPkgNum() {
break break
} }
i = end i = end
@ -323,26 +404,29 @@ func decodeGetGroupMsgResponse(c *QQClient, pkt *network.Packet) (any, error) {
return ret, nil return ret, nil
} }
func decodeAtAllRemainResponse(_ *QQClient, pkt *network.Packet) (any, error) { func decodeAtAllRemainResponse(_ *QQClient, _ *incomingPacketInfo, payload []byte) (interface{}, error) {
rsp := oidb.D8A7RspBody{} pkg := oidb.OIDBSSOPkg{}
err := unpackOIDBPackage(pkt.Payload, &rsp) rsp := oidb0x8a7.RspBody{}
if err != nil { if err := protobuf.Unmarshal(payload, &pkg); err != nil {
return nil, err return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
}
if err := protobuf.Unmarshal(pkg.Bodybuffer, &rsp); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
return &AtAllRemainInfo{ return &AtAllRemainInfo{
CanAtAll: rsp.CanAtAll.Unwrap(), CanAtAll: rsp.GetCanAtAll(),
RemainAtAllCountForGroup: rsp.RemainAtAllCountForGroup.Unwrap(), RemainAtAllCountForGroup: rsp.GetRemainAtAllCountForGroup(),
RemainAtAllCountForUin: rsp.RemainAtAllCountForUin.Unwrap(), RemainAtAllCountForUin: rsp.GetRemainAtAllCountForUin(),
}, nil }, nil
} }
func (c *QQClient) parseGroupMessage(m *msg.Message) *message.GroupMessage { func (c *QQClient) parseGroupMessage(m *msg.Message) *message.GroupMessage {
group := c.FindGroup(m.Head.GroupInfo.GroupCode.Unwrap()) group := c.FindGroup(m.Head.GroupInfo.GetGroupCode())
if group == nil { if group == nil {
c.debug("sync group %v.", m.Head.GroupInfo.GroupCode.Unwrap()) c.Debug("sync group %v.", m.Head.GroupInfo.GetGroupCode())
info, err := c.GetGroupInfo(m.Head.GroupInfo.GroupCode.Unwrap()) info, err := c.GetGroupInfo(m.Head.GroupInfo.GetGroupCode())
if err != nil { if err != nil {
c.error("failed to sync group %v : %+v", m.Head.GroupInfo.GroupCode.Unwrap(), err) c.Error("error to sync group %v : %+v", m.Head.GroupInfo.GetGroupCode(), err)
return nil return nil
} }
group = info group = info
@ -351,7 +435,7 @@ func (c *QQClient) parseGroupMessage(m *msg.Message) *message.GroupMessage {
if len(group.Members) == 0 { if len(group.Members) == 0 {
mem, err := c.GetGroupMembers(group) mem, err := c.GetGroupMembers(group)
if err != nil { if err != nil {
c.error("failed to sync group %v members : %+v", m.Head.GroupInfo.GroupCode, err) c.Error("error to sync group %v member : %+v", m.Head.GroupInfo.GroupCode, err)
return nil return nil
} }
group.Members = mem group.Members = mem
@ -374,20 +458,20 @@ func (c *QQClient) parseGroupMessage(m *msg.Message) *message.GroupMessage {
IsFriend: false, IsFriend: false,
} }
} else { } else {
mem := group.FindMember(m.Head.FromUin.Unwrap()) mem := group.FindMember(m.Head.GetFromUin())
if mem == nil { if mem == nil {
group.Update(func(_ *GroupInfo) { group.Update(func(_ *GroupInfo) {
if mem = group.FindMemberWithoutLock(m.Head.FromUin.Unwrap()); mem != nil { if mem = group.FindMemberWithoutLock(m.Head.GetFromUin()); mem != nil {
return return
} }
info, _ := c.GetMemberInfo(group.Code, m.Head.FromUin.Unwrap()) info, _ := c.GetMemberInfo(group.Code, m.Head.GetFromUin())
if info == nil { if info == nil {
return return
} }
mem = info mem = info
group.Members = append(group.Members, mem) group.Members = append(group.Members, mem)
group.sort() group.sort()
go c.GroupMemberJoinEvent.dispatch(c, &MemberJoinGroupEvent{ go c.dispatchNewMemberEvent(&MemberJoinGroupEvent{
Group: group, Group: group,
Member: info, Member: info,
}) })
@ -405,11 +489,11 @@ func (c *QQClient) parseGroupMessage(m *msg.Message) *message.GroupMessage {
} }
var g *message.GroupMessage var g *message.GroupMessage
g = &message.GroupMessage{ g = &message.GroupMessage{
Id: m.Head.MsgSeq.Unwrap(), Id: m.Head.GetMsgSeq(),
GroupCode: group.Code, GroupCode: group.Code,
GroupName: string(m.Head.GroupInfo.GroupName), GroupName: string(m.Head.GroupInfo.GroupName),
Sender: sender, Sender: sender,
Time: m.Head.MsgTime.Unwrap(), Time: m.Head.GetMsgTime(),
Elements: message.ParseMessageElems(m.Body.RichText.Elems), Elements: message.ParseMessageElems(m.Body.RichText.Elems),
OriginalObject: m, OriginalObject: m,
} }
@ -417,14 +501,14 @@ func (c *QQClient) parseGroupMessage(m *msg.Message) *message.GroupMessage {
// pre parse // pre parse
for _, elem := range m.Body.RichText.Elems { for _, elem := range m.Body.RichText.Elems {
// is rich long msg // is rich long msg
if elem.GeneralFlags != nil && elem.GeneralFlags.LongTextResid.Unwrap() != "" && len(g.Elements) == 1 { if elem.GeneralFlags != nil && elem.GeneralFlags.GetLongTextResid() != "" && len(g.Elements) == 1 {
if f := c.GetForwardMessage(elem.GeneralFlags.LongTextResid.Unwrap()); f != nil && len(f.Nodes) == 1 { if f := c.GetForwardMessage(elem.GeneralFlags.GetLongTextResid()); f != nil && len(f.Nodes) == 1 {
g = &message.GroupMessage{ g = &message.GroupMessage{
Id: m.Head.MsgSeq.Unwrap(), Id: m.Head.GetMsgSeq(),
GroupCode: group.Code, GroupCode: group.Code,
GroupName: string(m.Head.GroupInfo.GroupName), GroupName: string(m.Head.GroupInfo.GroupName),
Sender: sender, Sender: sender,
Time: m.Head.MsgTime.Unwrap(), Time: m.Head.GetMsgTime(),
Elements: f.Nodes[0].Message, Elements: f.Nodes[0].Message,
OriginalObject: m, OriginalObject: m,
} }
@ -435,11 +519,11 @@ func (c *QQClient) parseGroupMessage(m *msg.Message) *message.GroupMessage {
} }
} }
if !sender.IsAnonymous() { if !sender.IsAnonymous() {
mem := group.FindMember(m.Head.FromUin.Unwrap()) mem := group.FindMember(m.Head.GetFromUin())
groupCard := m.Head.GroupInfo.GroupCard.Unwrap() groupCard := m.Head.GroupInfo.GetGroupCard()
if extInfo != nil && len(extInfo.GroupCard) > 0 && extInfo.GroupCard[0] == 0x0A { if extInfo != nil && len(extInfo.GroupCard) > 0 && extInfo.GroupCard[0] == 0x0A {
buf := oidb.D8FCCommCardNameBuf{} buf := oidb0x8fc.CommCardNameBuf{}
if err := proto.Unmarshal(extInfo.GroupCard, &buf); err == nil && len(buf.RichCardName) > 0 { if err := protobuf.Unmarshal(extInfo.GroupCard, &buf); err == nil && len(buf.RichCardName) > 0 {
var gcard strings.Builder var gcard strings.Builder
for _, e := range buf.RichCardName { for _, e := range buf.RichCardName {
gcard.Write(e.Text) gcard.Write(e.Text)
@ -455,7 +539,7 @@ func (c *QQClient) parseGroupMessage(m *msg.Message) *message.GroupMessage {
mem.CardName = groupCard mem.CardName = groupCard
} }
if old != mem.CardName { if old != mem.CardName {
c.MemberCardUpdatedEvent.dispatch(c, &MemberCardUpdatedEvent{ go c.dispatchMemberCardUpdatedEvent(&MemberCardUpdatedEvent{
Group: group, Group: group,
OldCard: old, OldCard: old,
Member: mem, Member: mem,
@ -464,49 +548,17 @@ func (c *QQClient) parseGroupMessage(m *msg.Message) *message.GroupMessage {
} }
} }
if m.Body.RichText.Ptt != nil { if m.Body.RichText.Ptt != nil {
var url string
if len(m.Body.RichText.Ptt.DownPara) == 0 {
req := &cmd0x388.D388ReqBody{
NetType: proto.Uint32(3),
Subcmd: proto.Uint32(4),
GetpttUrlReq: []*cmd0x388.GetPttUrlReq{
{
GroupCode: proto.Uint64(uint64(m.Head.GroupInfo.GroupCode.Unwrap())),
DstUin: proto.Uint64(uint64(m.Head.ToUin.Unwrap())),
Fileid: proto.Uint64(uint64(m.Body.RichText.Ptt.FileId.Unwrap())),
FileMd5: m.Body.RichText.Ptt.FileMd5,
ReqTerm: proto.Uint32(5),
ReqPlatformType: proto.Uint32(9),
InnerIp: proto.Uint32(0),
BuType: proto.Uint32(3),
FileId: proto.Uint64(0),
FileKey: m.Body.RichText.Ptt.FileKey,
ReqTransferType: proto.Uint32(2),
IsAuto: proto.Uint32(1),
},
},
}
payload, _ := proto.Marshal(req)
rsp_raw, _ := c.sendAndWaitDynamic(c.uniPacket("PttStore.GroupPttDown", payload))
rsp := new(cmd0x388.D388RspBody)
proto.Unmarshal(rsp_raw, rsp)
resp := rsp.GetpttUrlRsp[0]
url = "http://" + string(resp.DownDomain) + string(resp.DownPara)
} else {
url = "http://grouptalk.c2c.qq.com" + string(m.Body.RichText.Ptt.DownPara)
}
g.Elements = []message.IMessageElement{ g.Elements = []message.IMessageElement{
&message.VoiceElement{ &message.VoiceElement{
Name: m.Body.RichText.Ptt.FileName.Unwrap(), Name: m.Body.RichText.Ptt.GetFileName(),
Md5: m.Body.RichText.Ptt.FileMd5, Md5: m.Body.RichText.Ptt.FileMd5,
Size: m.Body.RichText.Ptt.FileSize.Unwrap(), Size: m.Body.RichText.Ptt.GetFileSize(),
Url: url, Url: "http://grouptalk.c2c.qq.com" + string(m.Body.RichText.Ptt.DownPara),
}, },
} }
} }
if m.Body.RichText.Attr != nil { if m.Body.RichText.Attr != nil {
g.InternalId = m.Body.RichText.Attr.Random.Unwrap() g.InternalId = m.Body.RichText.Attr.GetRandom()
} }
return g return g
} }
@ -517,9 +569,9 @@ func (c *QQClient) SetEssenceMessage(groupCode int64, msgID, msgInternalId int32
if err != nil { if err != nil {
return errors.Wrap(err, "set essence msg network") return errors.Wrap(err, "set essence msg network")
} }
rsp := r.(*oidb.EACRspBody) rsp := r.(*oidb0xeac.RspBody)
if rsp.ErrorCode.Unwrap() != 0 { if rsp.GetErrorCode() != 0 {
return errors.New(rsp.Wording.Unwrap()) return errors.New(rsp.GetWording())
} }
return nil return nil
} }
@ -530,29 +582,34 @@ func (c *QQClient) DeleteEssenceMessage(groupCode int64, msgID, msgInternalId in
if err != nil { if err != nil {
return errors.Wrap(err, "set essence msg networ") return errors.Wrap(err, "set essence msg networ")
} }
rsp := r.(*oidb.EACRspBody) rsp := r.(*oidb0xeac.RspBody)
if rsp.ErrorCode.Unwrap() != 0 { if rsp.GetErrorCode() != 0 {
return errors.New(rsp.Wording.Unwrap()) return errors.New(rsp.GetWording())
} }
return nil return nil
} }
func (c *QQClient) buildEssenceMsgOperatePacket(groupCode int64, msgSeq, msgRand, opType uint32) (uint16, []byte) { func (c *QQClient) buildEssenceMsgOperatePacket(groupCode int64, msgSeq, msgRand, opType uint32) (uint16, []byte) {
seq := c.nextSeq()
commandName := "OidbSvc.0xeac_" + strconv.FormatInt(int64(opType), 10) commandName := "OidbSvc.0xeac_" + strconv.FormatInt(int64(opType), 10)
payload := c.packOIDBPackageProto(3756, int32(opType), &oidb.EACReqBody{ // serviceType 2 取消 payload := c.packOIDBPackageProto2(3756, opType, &oidb0xeac.ReqBody{ // serviceType 2 取消
GroupCode: proto.Uint64(uint64(groupCode)), GroupCode: proto.Uint64(uint64(groupCode)),
Seq: proto.Uint32(msgSeq), Seq: proto.Uint32(msgSeq),
Random: proto.Uint32(msgRand), Random: proto.Uint32(msgRand),
}) })
return c.uniPacket(commandName, payload) packet := packets.BuildUniPacket(c.Uin, seq, commandName, 1, c.OutGoingPacketSessionId, EmptyBytes, c.sigInfo.d2Key, payload)
return seq, packet
} }
// OidbSvc.0xeac_1/2 // OidbSvc.0xeac_1/2
func decodeEssenceMsgResponse(_ *QQClient, pkt *network.Packet) (any, error) { func decodeEssenceMsgResponse(_ *QQClient, _ *incomingPacketInfo, payload []byte) (interface{}, error) {
rsp := &oidb.EACRspBody{} pkg := oidb.OIDBSSOPkg{}
err := unpackOIDBPackage(pkt.Payload, &rsp) rsp := &oidb0xeac.RspBody{}
if err != nil { if err := protobuf.Unmarshal(payload, &pkg); err != nil {
return nil, err return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
}
if err := protobuf.Unmarshal(pkg.Bodybuffer, rsp); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
return rsp, nil return rsp, nil
} }

View File

@ -2,20 +2,14 @@ package client
import ( import (
"fmt" "fmt"
"math/rand"
"sort"
"strconv"
"time"
"github.com/Mrs4s/MiraiGo/client/internal/network"
"github.com/Mrs4s/MiraiGo/topic"
"github.com/Mrs4s/MiraiGo/client/pb/qweb"
"github.com/Mrs4s/MiraiGo/internal/proto"
"github.com/pkg/errors" "github.com/pkg/errors"
protobuf "github.com/segmentio/encoding/proto"
"google.golang.org/protobuf/proto"
"github.com/Mrs4s/MiraiGo/client/pb/channel" "github.com/Mrs4s/MiraiGo/binary"
"github.com/Mrs4s/MiraiGo/internal/packets"
"github.com/Mrs4s/MiraiGo/internal/protobuf/data/channel"
"github.com/Mrs4s/MiraiGo/utils" "github.com/Mrs4s/MiraiGo/utils"
) )
@ -40,9 +34,9 @@ type (
CoverUrl string CoverUrl string
AvatarUrl string AvatarUrl string
Channels []*ChannelInfo Channels []*ChannelInfo
// Bots []*GuildMemberInfo Bots []*GuildMemberInfo
// Members []*GuildMemberInfo Members []*GuildMemberInfo
// Admins []*GuildMemberInfo Admins []*GuildMemberInfo
} }
// GuildMeta 频道数据 // GuildMeta 频道数据
@ -58,14 +52,12 @@ type (
OwnerId uint64 OwnerId uint64
} }
// GuildMemberInfo 频道成员信息, 仅通过频道成员列表API获取
GuildMemberInfo struct { GuildMemberInfo struct {
TinyId uint64 TinyId uint64
Title string Title string
Nickname string Nickname string
LastSpeakTime int64 LastSpeakTime int64
Role uint64 Role int32 // 0 = member 1 = admin 2 = owner ?
RoleName string
} }
// GuildUserProfile 频道系统用户资料 // GuildUserProfile 频道系统用户资料
@ -74,19 +66,6 @@ type (
Nickname string Nickname string
AvatarUrl string AvatarUrl string
JoinTime int64 // 只有 GetGuildMemberProfileInfo 函数才会有 JoinTime int64 // 只有 GetGuildMemberProfileInfo 函数才会有
Roles []*GuildRole
}
// GuildRole 频道身份组信息
GuildRole struct {
RoleId uint64
RoleName string
ArgbColor uint32
Independent bool
Num int32
Owned bool
Disabled bool
MaxNum int32
} }
// ChannelInfo 子频道信息 // ChannelInfo 子频道信息
@ -99,8 +78,6 @@ type (
ChannelType ChannelType ChannelType ChannelType
AtAllSeq uint64 AtAllSeq uint64
Meta *ChannelMeta Meta *ChannelMeta
fetchTime int64
} }
ChannelMeta struct { ChannelMeta struct {
@ -124,14 +101,6 @@ type (
SlowModeText string SlowModeText string
} }
FetchGuildMemberListWithRoleResult struct {
Members []*GuildMemberInfo
NextIndex uint32
NextRoleId uint64
NextQueryParam string
Finished bool
}
ChannelType int32 ChannelType int32
) )
@ -139,7 +108,6 @@ const (
ChannelTypeText ChannelType = 1 ChannelTypeText ChannelType = 1
ChannelTypeVoice ChannelType = 2 ChannelTypeVoice ChannelType = 2
ChannelTypeLive ChannelType = 5 ChannelTypeLive ChannelType = 5
ChannelTypeTopic ChannelType = 7
) )
func init() { func init() {
@ -155,6 +123,25 @@ func (s *GuildService) FindGuild(guildId uint64) *GuildInfo {
return nil return nil
} }
func (g *GuildInfo) FindMember(tinyId uint64) *GuildMemberInfo {
for i := 0; i < len(g.Members); i++ {
if g.Members[i].TinyId == tinyId {
return g.Members[i]
}
}
for i := 0; i < len(g.Admins); i++ {
if g.Admins[i].TinyId == tinyId {
return g.Admins[i]
}
}
for i := 0; i < len(g.Bots); i++ {
if g.Bots[i].TinyId == tinyId {
return g.Bots[i]
}
}
return nil
}
func (g *GuildInfo) FindChannel(channelId uint64) *ChannelInfo { func (g *GuildInfo) FindChannel(channelId uint64) *ChannelInfo {
for _, c := range g.Channels { for _, c := range g.Channels {
if c.ChannelId == channelId { if c.ChannelId == channelId {
@ -164,309 +151,161 @@ func (g *GuildInfo) FindChannel(channelId uint64) *ChannelInfo {
return nil return nil
} }
func (g *GuildInfo) removeChannel(id uint64) {
i := sort.Search(len(g.Channels), func(i int) bool {
return g.Channels[i].ChannelId >= id
})
if i >= len(g.Channels) || g.Channels[i].ChannelId != id {
return
}
g.Channels = append(g.Channels[:i], g.Channels[i+1:]...)
}
func (s *GuildService) GetUserProfile(tinyId uint64) (*GuildUserProfile, error) { func (s *GuildService) GetUserProfile(tinyId uint64) (*GuildUserProfile, error) {
flags := proto.DynamicMessage{} seq := s.c.nextSeq()
flags := binary.DynamicProtoMessage{}
for i := 3; i <= 29; i++ { for i := 3; i <= 29; i++ {
flags[uint64(i)] = 1 flags[uint64(i)] = uint32(1)
} }
flags[99] = 1 flags[99] = uint32(1)
flags[100] = 1 flags[100] = uint32(1)
payload := s.c.packOIDBPackageDynamically(3976, 1, proto.DynamicMessage{ payload := s.c.packOIDBPackageDynamically(3976, 1, binary.DynamicProtoMessage{
1: flags, 1: flags,
3: tinyId, 3: tinyId,
4: 0, 4: uint32(0),
}) })
rsp, err := s.c.sendAndWaitDynamic(s.c.uniPacket("OidbSvcTrpcTcp.0xfc9_1", payload)) packet := packets.BuildUniPacket(s.c.Uin, seq, "OidbSvcTrpcTcp.0xfc9_1", 1, s.c.OutGoingPacketSessionId, []byte{}, s.c.sigInfo.d2Key, payload)
rsp, err := s.c.sendAndWaitDynamic(seq, packet)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "send packet error") return nil, errors.Wrap(err, "send packet error")
} }
body := new(channel.ChannelOidb0Xfc9Rsp) body := new(channel.ChannelOidb0Xfc9Rsp)
if err = unpackOIDBPackage(rsp, body); err != nil { if err = s.c.unpackOIDBPackage(rsp, body); err != nil {
return nil, errors.Wrap(err, "decode packet error") return nil, errors.Wrap(err, "decode packet error")
} }
// todo: 解析个性档案 // todo: 解析个性档案
return &GuildUserProfile{ return &GuildUserProfile{
TinyId: tinyId, TinyId: tinyId,
Nickname: body.Profile.Nickname.Unwrap(), Nickname: body.Profile.GetNickname(),
AvatarUrl: body.Profile.AvatarUrl.Unwrap(), AvatarUrl: body.Profile.GetAvatarUrl(),
JoinTime: body.Profile.JoinTime.Unwrap(), JoinTime: body.Profile.GetJoinTime(),
}, nil }, nil
} }
// FetchGuildMemberListWithRole 获取频道成员列表 func (s *GuildService) GetGuildMembers(guildId uint64) (bots []*GuildMemberInfo, members []*GuildMemberInfo, admins []*GuildMemberInfo, err error) {
// 第一次请求: startIndex = 0 , roleIdIndex = 2 param = ""
// 后续请求请根据上次请求的返回值进行设置
func (s *GuildService) FetchGuildMemberListWithRole(guildId, channelId uint64, startIndex uint32, roleIdIndex uint64, param string) (*FetchGuildMemberListWithRoleResult, error) {
seq := s.c.nextSeq() seq := s.c.nextSeq()
m := proto.DynamicMessage{ u1 := uint32(1)
// todo: 这个包实际上是 fetchMemberListWithRole , 可以按channel, role等规则获取成员列表, 还需要修改
payload := s.c.packOIDBPackageDynamically(3931, 1, binary.DynamicProtoMessage{ // todo: 可能还需要处理翻页的情况?
1: guildId, // guild id 1: guildId, // guild id
2: 3, 2: uint32(3),
3: 0, 3: uint32(0),
4: proto.DynamicMessage{ // unknown param, looks like flags 4: binary.DynamicProtoMessage{ // unknown param, looks like flags
1: 1, 1: u1, 2: u1, 3: u1, 4: u1, 5: u1, 6: u1, 7: u1, 8: u1, 20: u1,
2: 1,
3: 1,
4: 1,
5: 1,
6: 1,
7: 1,
8: 1,
20: 1,
}, },
6: startIndex, 6: uint32(0),
8: 50, // count 8: uint32(500), // count
12: channelId, 14: uint32(2),
} })
if param != "" { packet := packets.BuildUniPacket(s.c.Uin, seq, "OidbSvcTrpcTcp.0xf5b_1", 1, s.c.OutGoingPacketSessionId, []byte{}, s.c.sigInfo.d2Key, payload)
m[13] = param
}
m[14] = roleIdIndex
packet := s.c.uniPacketWithSeq(seq, "OidbSvcTrpcTcp.0xf5b_1", s.c.packOIDBPackageDynamically(3931, 1, m))
rsp, err := s.c.sendAndWaitDynamic(seq, packet) rsp, err := s.c.sendAndWaitDynamic(seq, packet)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "send packet error") return nil, nil, nil, errors.Wrap(err, "send packet error")
} }
body := new(channel.ChannelOidb0Xf5BRsp) body := new(channel.ChannelOidb0Xf5BRsp)
if err = unpackOIDBPackage(rsp, body); err != nil { if err = s.c.unpackOIDBPackage(rsp, body); err != nil {
return nil, errors.Wrap(err, "decode packet error") return nil, nil, nil, errors.Wrap(err, "decode packet error")
} }
var ret []*GuildMemberInfo protoToMemberInfo := func(mem *channel.GuildMemberInfo) *GuildMemberInfo {
for _, memberWithRole := range body.MemberWithRoles { return &GuildMemberInfo{
for _, mem := range memberWithRole.Members { TinyId: mem.GetTinyId(),
ret = append(ret, &GuildMemberInfo{ Title: mem.GetTitle(),
TinyId: mem.TinyId.Unwrap(), Nickname: mem.GetNickname(),
Title: mem.Title.Unwrap(), LastSpeakTime: mem.GetLastSpeakTime(),
Nickname: mem.Nickname.Unwrap(), Role: mem.GetRole(),
LastSpeakTime: mem.LastSpeakTime.Unwrap(),
Role: memberWithRole.RoleId.Unwrap(),
RoleName: memberWithRole.RoleName.Unwrap(),
})
} }
} }
for _, mem := range body.Members { for _, mem := range body.Bots {
ret = append(ret, &GuildMemberInfo{ bots = append(bots, protoToMemberInfo(mem))
TinyId: mem.TinyId.Unwrap(),
Title: mem.Title.Unwrap(),
Nickname: mem.Nickname.Unwrap(),
LastSpeakTime: mem.LastSpeakTime.Unwrap(),
Role: 1,
RoleName: "普通成员",
})
} }
return &FetchGuildMemberListWithRoleResult{ for _, mem := range body.Members {
Members: ret, members = append(members, protoToMemberInfo(mem))
NextIndex: body.NextIndex.Unwrap(), }
NextRoleId: body.NextRoleIdIndex.Unwrap(), for _, mem := range body.AdminInfo.Admins {
NextQueryParam: body.NextQueryParam.Unwrap(), admins = append(admins, protoToMemberInfo(mem))
Finished: body.NextIndex.IsNone(), }
}, nil return
} }
// FetchGuildMemberProfileInfo 获取单个频道成员资料 func (s *GuildService) GetGuildMemberProfileInfo(guildId, tinyId uint64) (*GuildUserProfile, error) {
func (s *GuildService) FetchGuildMemberProfileInfo(guildId, tinyId uint64) (*GuildUserProfile, error) {
seq := s.c.nextSeq() seq := s.c.nextSeq()
flags := proto.DynamicMessage{} flags := binary.DynamicProtoMessage{}
for i := 3; i <= 29; i++ { for i := 3; i <= 29; i++ {
flags[uint64(i)] = 1 flags[uint64(i)] = uint32(1)
} }
flags[99] = 1 flags[99] = uint32(1)
flags[100] = 1 flags[100] = uint32(1)
payload := s.c.packOIDBPackageDynamically(3976, 1, proto.DynamicMessage{ payload := s.c.packOIDBPackageDynamically(3976, 1, binary.DynamicProtoMessage{
1: flags, 1: flags,
3: tinyId, 3: tinyId,
4: guildId, 4: guildId,
}) })
packet := s.c.uniPacketWithSeq(seq, "OidbSvcTrpcTcp.0xf88_1", payload) packet := packets.BuildUniPacket(s.c.Uin, seq, "OidbSvcTrpcTcp.0xf88_1", 1, s.c.OutGoingPacketSessionId, []byte{}, s.c.sigInfo.d2Key, payload)
rsp, err := s.c.sendAndWaitDynamic(seq, packet) rsp, err := s.c.sendAndWaitDynamic(seq, packet)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "send packet error") return nil, errors.Wrap(err, "send packet error")
} }
body := new(channel.ChannelOidb0Xf88Rsp) body := new(channel.ChannelOidb0Xf88Rsp)
if err = unpackOIDBPackage(rsp, body); err != nil { if err = s.c.unpackOIDBPackage(rsp, body); err != nil {
return nil, errors.Wrap(err, "decode packet error") return nil, errors.Wrap(err, "decode packet error")
} }
roles, err := s.fetchMemberRoles(guildId, tinyId)
if err != nil {
return nil, errors.Wrap(err, "fetch roles error")
}
// todo: 解析个性档案 // todo: 解析个性档案
return &GuildUserProfile{ return &GuildUserProfile{
TinyId: tinyId, TinyId: tinyId,
Nickname: body.Profile.Nickname.Unwrap(), Nickname: body.Profile.GetNickname(),
AvatarUrl: body.Profile.AvatarUrl.Unwrap(), AvatarUrl: body.Profile.GetAvatarUrl(),
JoinTime: body.Profile.JoinTime.Unwrap(), JoinTime: body.Profile.GetJoinTime(),
Roles: roles,
}, nil }, nil
} }
func (s *GuildService) GetGuildRoles(guildId uint64) ([]*GuildRole, error) {
seq, packet := s.c.uniPacket("OidbSvcTrpcTcp.0x1019_1",
s.c.packOIDBPackageDynamically(4121, 1, proto.DynamicMessage{1: guildId}))
rsp, err := s.c.sendAndWaitDynamic(seq, packet)
if err != nil {
return nil, errors.Wrap(err, "send packet error")
}
body := new(channel.ChannelOidb0X1019Rsp)
if err = unpackOIDBPackage(rsp, body); err != nil {
return nil, errors.Wrap(err, "decode packet error")
}
roles := make([]*GuildRole, 0, len(body.Roles))
for _, role := range body.Roles {
roles = append(roles, &GuildRole{
RoleId: role.RoleId.Unwrap(),
RoleName: role.Name.Unwrap(),
ArgbColor: role.ArgbColor.Unwrap(),
Independent: role.Independent.Unwrap() == 1,
Num: role.Num.Unwrap(),
Owned: role.Owned.Unwrap() == 1,
Disabled: role.Disabled.Unwrap() == 1,
MaxNum: role.MaxNum.Unwrap(),
})
}
return roles, nil
}
func (s *GuildService) CreateGuildRole(guildId uint64, name string, color uint32, independent bool, initialUsers []uint64) (uint64, error) {
seq, packet := s.c.uniPacket("OidbSvcTrpcTcp.0x1016_1", s.c.packOIDBPackageDynamically(4118, 1, proto.DynamicMessage{
1: guildId,
2: proto.DynamicMessage{ // todo: 未知参数
1: 1,
2: 1,
3: 1,
},
3: proto.DynamicMessage{
1: name,
2: color,
3: independent,
},
4: initialUsers,
}))
rsp, err := s.c.sendAndWaitDynamic(seq, packet)
if err != nil {
return 0, errors.Wrap(err, "send packet error")
}
body := new(channel.ChannelOidb0X1016Rsp)
if err = unpackOIDBPackage(rsp, body); err != nil {
return 0, errors.Wrap(err, "decode packet error")
}
return body.RoleId.Unwrap(), nil
}
func (s *GuildService) DeleteGuildRole(guildId uint64, roleId uint64) error {
seq, packet := s.c.uniPacket("OidbSvcTrpcTcp.0x100e_1", s.c.packOIDBPackageDynamically(4110, 1, proto.DynamicMessage{
1: guildId,
2: roleId,
}))
_, err := s.c.sendAndWaitDynamic(seq, packet)
if err != nil {
return errors.Wrap(err, "send packet error")
}
return nil
}
func (s *GuildService) SetUserRoleInGuild(guildId uint64, set bool, roleId uint64, user []uint64) error { // remove => p2 = false
setOrRemove := proto.DynamicMessage{
1: roleId,
}
if set {
setOrRemove[2] = user
} else {
setOrRemove[3] = user
}
seq, packet := s.c.uniPacket("OidbSvcTrpcTcp.0x101a_1", s.c.packOIDBPackageDynamically(4122, 1, proto.DynamicMessage{
1: guildId,
2: setOrRemove,
}))
_, err := s.c.sendAndWaitDynamic(seq, packet)
if err != nil {
return errors.Wrap(err, "send packet error")
}
return nil
}
func (s *GuildService) ModifyRoleInGuild(guildId uint64, roleId uint64, name string, color uint32, indepedent bool) error {
seq, packet := s.c.uniPacket("OidbSvcTrpcTcp.0x100d_1", s.c.packOIDBPackageDynamically(4109, 1, proto.DynamicMessage{
1: guildId,
2: roleId,
3: proto.DynamicMessage{
1: 1,
2: 1,
3: 1,
},
4: proto.DynamicMessage{
1: name,
2: color,
3: indepedent,
},
}))
_, err := s.c.sendAndWaitDynamic(seq, packet)
if err != nil {
return errors.Wrap(err, "send packet error")
}
return nil
}
func (s *GuildService) FetchGuestGuild(guildId uint64) (*GuildMeta, error) { func (s *GuildService) FetchGuestGuild(guildId uint64) (*GuildMeta, error) {
payload := s.c.packOIDBPackageDynamically(3927, 9, proto.DynamicMessage{ seq := s.c.nextSeq()
1: proto.DynamicMessage{ u1 := uint32(1)
1: proto.DynamicMessage{ payload := s.c.packOIDBPackageDynamically(3927, 9, binary.DynamicProtoMessage{
2: 1, 4: 1, 5: 1, 6: 1, 7: 1, 8: 1, 11: 1, 12: 1, 13: 1, 14: 1, 45: 1, 1: binary.DynamicProtoMessage{
18: 1, 19: 1, 20: 1, 22: 1, 23: 1, 5002: 1, 5003: 1, 5004: 1, 5005: 1, 10007: 1, 1: binary.DynamicProtoMessage{
2: u1, 4: u1, 5: u1, 6: u1, 7: u1, 8: u1, 11: u1, 12: u1, 13: u1, 14: u1, 45: u1,
18: u1, 19: u1, 20: u1, 22: u1, 23: u1, 5002: u1, 5003: u1, 5004: u1, 5005: u1, 10007: u1,
}, },
2: proto.DynamicMessage{ 2: binary.DynamicProtoMessage{
3: 1, 4: 1, 6: 1, 11: 1, 14: 1, 15: 1, 16: 1, 17: 1, 3: u1, 4: u1, 6: u1, 11: u1, 14: u1, 15: u1, 16: u1, 17: u1,
}, },
}, },
2: proto.DynamicMessage{ 2: binary.DynamicProtoMessage{
1: guildId, 1: guildId,
}, },
}) })
seq, packet := s.c.uniPacket("OidbSvcTrpcTcp.0xf57_9", payload) packet := packets.BuildUniPacket(s.c.Uin, seq, "OidbSvcTrpcTcp.0xf57_9", 1, s.c.OutGoingPacketSessionId, []byte{}, s.c.sigInfo.d2Key, payload)
rsp, err := s.c.sendAndWaitDynamic(seq, packet) rsp, err := s.c.sendAndWaitDynamic(seq, packet)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "send packet error") return nil, errors.Wrap(err, "send packet error")
} }
body := new(channel.ChannelOidb0Xf57Rsp) body := new(channel.ChannelOidb0Xf57Rsp)
if err = unpackOIDBPackage(rsp, body); err != nil { if err = s.c.unpackOIDBPackage(rsp, body); err != nil {
return nil, errors.Wrap(err, "decode packet error") return nil, errors.Wrap(err, "decode packet error")
} }
return &GuildMeta{ return &GuildMeta{
GuildName: body.Rsp.Meta.Name.Unwrap(), GuildName: body.Rsp.Meta.GetName(),
GuildProfile: body.Rsp.Meta.Profile.Unwrap(), GuildProfile: body.Rsp.Meta.GetProfile(),
MaxMemberCount: body.Rsp.Meta.MaxMemberCount.Unwrap(), MaxMemberCount: body.Rsp.Meta.GetMaxMemberCount(),
MemberCount: body.Rsp.Meta.MemberCount.Unwrap(), MemberCount: body.Rsp.Meta.GetMemberCount(),
CreateTime: body.Rsp.Meta.CreateTime.Unwrap(), CreateTime: body.Rsp.Meta.GetCreateTime(),
MaxRobotCount: body.Rsp.Meta.RobotMaxNum.Unwrap(), MaxRobotCount: body.Rsp.Meta.GetRobotMaxNum(),
MaxAdminCount: body.Rsp.Meta.AdminMaxNum.Unwrap(), MaxAdminCount: body.Rsp.Meta.GetAdminMaxNum(),
OwnerId: body.Rsp.Meta.OwnerId.Unwrap(), OwnerId: body.Rsp.Meta.GetOwnerId(),
}, nil }, nil
} }
func (s *GuildService) FetchChannelList(guildId uint64) (r []*ChannelInfo, e error) { func (s *GuildService) FetchChannelList(guildId uint64) (r []*ChannelInfo, e error) {
seq, packet := s.c.uniPacket("OidbSvcTrpcTcp.0xf5d_1", seq := s.c.nextSeq()
s.c.packOIDBPackageDynamically(3933, 1, packet := packets.BuildUniPacket(s.c.Uin, seq, "OidbSvcTrpcTcp.0xf5d_1", 1, s.c.OutGoingPacketSessionId, []byte{}, s.c.sigInfo.d2Key,
proto.DynamicMessage{ s.c.packOIDBPackageDynamically(3933, 1, binary.DynamicProtoMessage{1: guildId, 3: binary.DynamicProtoMessage{1: uint32(1)}}))
1: guildId,
3: proto.DynamicMessage{
1: 1,
},
}))
rsp, err := s.c.sendAndWaitDynamic(seq, packet) rsp, err := s.c.sendAndWaitDynamic(seq, packet)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "send packet error") return nil, errors.Wrap(err, "send packet error")
} }
body := new(channel.ChannelOidb0Xf5DRsp) body := new(channel.ChannelOidb0Xf5DRsp)
if err = unpackOIDBPackage(rsp, body); err != nil { if err = s.c.unpackOIDBPackage(rsp, body); err != nil {
return nil, errors.Wrap(err, "decode packet error") return nil, errors.Wrap(err, "decode packet error")
} }
for _, info := range body.Rsp.Channels { for _, info := range body.Rsp.Channels {
@ -476,182 +315,20 @@ func (s *GuildService) FetchChannelList(guildId uint64) (r []*ChannelInfo, e err
} }
func (s *GuildService) FetchChannelInfo(guildId, channelId uint64) (*ChannelInfo, error) { func (s *GuildService) FetchChannelInfo(guildId, channelId uint64) (*ChannelInfo, error) {
seq, packet := s.c.uniPacket("OidbSvcTrpcTcp.0xf55_1", s.c.packOIDBPackageDynamically(3925, 1, proto.DynamicMessage{1: guildId, 2: channelId})) seq := s.c.nextSeq()
packet := packets.BuildUniPacket(s.c.Uin, seq, "OidbSvcTrpcTcp.0xf55_1", 1, s.c.OutGoingPacketSessionId, []byte{}, s.c.sigInfo.d2Key,
s.c.packOIDBPackageDynamically(3925, 1, binary.DynamicProtoMessage{1: guildId, 2: channelId}))
rsp, err := s.c.sendAndWaitDynamic(seq, packet) rsp, err := s.c.sendAndWaitDynamic(seq, packet)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "send packet error") return nil, errors.Wrap(err, "send packet error")
} }
body := new(channel.ChannelOidb0Xf55Rsp) body := new(channel.ChannelOidb0Xf55Rsp)
if err = unpackOIDBPackage(rsp, body); err != nil { if err = s.c.unpackOIDBPackage(rsp, body); err != nil {
return nil, errors.Wrap(err, "decode packet error") return nil, errors.Wrap(err, "decode packet error")
} }
return convertChannelInfo(body.Info), nil return convertChannelInfo(body.Info), nil
} }
func (s *GuildService) GetTopicChannelFeeds(guildId, channelId uint64) ([]*topic.Feed, error) {
guild := s.FindGuild(guildId)
if guild == nil {
return nil, errors.New("guild not found")
}
channelInfo := guild.FindChannel(channelId)
if channelInfo == nil {
return nil, errors.New("channel not found")
}
if channelInfo.ChannelType != ChannelTypeTopic {
return nil, errors.New("channel type error")
}
req, _ := proto.Marshal(&channel.StGetChannelFeedsReq{
Count: proto.Uint32(12),
From: proto.Uint32(0),
ChannelSign: &channel.StChannelSign{
GuildId: proto.Some(guildId),
ChannelId: proto.Some(channelId),
},
FeedAttchInfo: proto.String(""), // isLoadMore
})
payload, _ := proto.Marshal(&qweb.QWebReq{
Seq: proto.Int64(s.c.nextQWebSeq()),
Qua: proto.String("V1_AND_SQ_8.8.50_2324_YYB_D"),
DeviceInfo: proto.String(s.c.getWebDeviceInfo()),
BusiBuff: req,
TraceId: proto.String(fmt.Sprintf("%v_%v_%v", s.c.Uin, time.Now().Format("0102150405"), rand.Int63())),
Extinfo: []*qweb.COMMEntry{
{
Key: proto.String("fc-appid"),
Value: proto.String("96"),
},
{
Key: proto.String("environment_id"),
Value: proto.String("production"),
},
{
Key: proto.String("tiny_id"),
Value: proto.String(fmt.Sprint(s.TinyId)),
},
},
})
seq, packet := s.c.uniPacket("QChannelSvr.trpc.qchannel.commreader.ComReader.GetChannelTimelineFeeds", payload)
rsp, err := s.c.sendAndWaitDynamic(seq, packet)
if err != nil {
return nil, errors.New("send packet error")
}
pkg := new(qweb.QWebRsp)
body := new(channel.StGetChannelFeedsRsp)
if err = proto.Unmarshal(rsp, pkg); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
}
if err = proto.Unmarshal(pkg.BusiBuff, body); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
}
feeds := make([]*topic.Feed, 0, len(body.VecFeed))
for _, f := range body.VecFeed {
feeds = append(feeds, topic.DecodeFeed(f))
}
return feeds, nil
}
func (s *GuildService) PostTopicChannelFeed(guildId, channelId uint64, feed *topic.Feed) error {
guild := s.FindGuild(guildId)
if guild == nil {
return errors.New("guild not found")
}
channelInfo := guild.FindChannel(channelId)
if channelInfo == nil {
return errors.New("channel not found")
}
if channelInfo.ChannelType != ChannelTypeTopic {
return errors.New("channel type error")
}
feed.Poster = &topic.FeedPoster{
TinyIdStr: strconv.FormatUint(s.TinyId, 10),
Nickname: s.Nickname,
}
feed.GuildId = guildId
feed.ChannelId = channelId
req, _ := proto.Marshal(&channel.StPublishFeedReq{
ExtInfo: &channel.StCommonExt{
MapInfo: []*channel.CommonEntry{
{
Key: proto.String("clientkey"), Value: proto.String("GuildMain" + utils.RandomStringRange(14, "0123456789")),
},
},
},
From: proto.Int32(0),
JsonFeed: proto.String(feed.ToSendingPayload(s.c.Uin)),
})
payload, _ := proto.Marshal(&qweb.QWebReq{
Seq: proto.Int64(s.c.nextQWebSeq()),
Qua: proto.String("V1_AND_SQ_8.8.50_2324_YYB_D"),
DeviceInfo: proto.String(s.c.getWebDeviceInfo()),
BusiBuff: req,
TraceId: proto.String(fmt.Sprintf("%v_%v_%v", s.c.Uin, time.Now().Format("0102150405"), rand.Int63())),
Extinfo: []*qweb.COMMEntry{
{
Key: proto.String("fc-appid"),
Value: proto.String("96"),
},
{
Key: proto.String("environment_id"),
Value: proto.String("production"),
},
{
Key: proto.String("tiny_id"),
Value: proto.String(fmt.Sprint(s.TinyId)),
},
},
})
seq, packet := s.c.uniPacket("QChannelSvr.trpc.qchannel.commwriter.ComWriter.PublishFeed", payload)
rsp, err := s.c.sendAndWaitDynamic(seq, packet)
if err != nil {
return errors.New("send packet error")
}
pkg := new(qweb.QWebRsp)
body := new(channel.StPublishFeedRsp)
if err = proto.Unmarshal(rsp, pkg); err != nil {
return errors.Wrap(err, "failed to unmarshal protobuf message")
}
if err = proto.Unmarshal(pkg.BusiBuff, body); err != nil {
return errors.Wrap(err, "failed to unmarshal protobuf message")
}
if body.Feed != nil && body.Feed.Id.IsNone() {
return nil
}
return errors.New("post feed error")
}
func (s *GuildService) fetchMemberRoles(guildId uint64, tinyId uint64) ([]*GuildRole, error) {
seq, packet := s.c.uniPacket("OidbSvcTrpcTcp.0x1017_1", s.c.packOIDBPackageDynamically(4119, 1, proto.DynamicMessage{
1: guildId,
2: tinyId,
4: proto.DynamicMessage{
1: 1,
2: 1,
3: 1,
},
}))
rsp, err := s.c.sendAndWaitDynamic(seq, packet)
if err != nil {
return nil, errors.Wrap(err, "send packet error")
}
body := new(channel.ChannelOidb0X1017Rsp)
if err = unpackOIDBPackage(rsp, body); err != nil {
return nil, errors.Wrap(err, "decode packet error")
}
p1 := body.P1
if p1 == nil {
return nil, errors.New("packet OidbSvcTrpcTcp.0x1017_1: decode p1 error")
}
roles := make([]*GuildRole, 0, len(p1.Roles))
for _, role := range p1.Roles {
roles = append(roles, &GuildRole{
RoleId: role.RoleId.Unwrap(),
RoleName: role.Name.Unwrap(),
ArgbColor: role.ArgbColor.Unwrap(),
})
}
return roles, nil
}
/* need analysis /* need analysis
func (s *GuildService) fetchChannelListState(guildId uint64, channels []*ChannelInfo) { func (s *GuildService) fetchChannelListState(guildId uint64, channels []*ChannelInfo) {
seq := s.c.nextSeq() seq := s.c.nextSeq()
@ -659,19 +336,19 @@ func (s *GuildService) fetchChannelListState(guildId uint64, channels []*Channel
for _, info := range channels { for _, info := range channels {
ids = append(ids, info.ChannelId) ids = append(ids, info.ChannelId)
} }
payload := s.c.packOIDBPackageDynamically(4104, 1, binary.DynamicMessage{ payload := s.c.packOIDBPackageDynamically(4104, 1, binary.DynamicProtoMessage{
1: binary.DynamicMessage{ 1: binary.DynamicProtoMessage{
1: guildId, 1: guildId,
2: ids, 2: ids,
}, },
}) })
packet := packets.BuildUniPacket(s.c.Uin, seq, "OidbSvcTrpcTcp.0x1008_1", 1, s.c.SessionId, []byte{}, s.c.sigInfo.d2Key, payload) packet := packets.BuildUniPacket(s.c.Uin, seq, "OidbSvcTrpcTcp.0x1008_1", 1, s.c.OutGoingPacketSessionId, []byte{}, s.c.sigInfo.d2Key, payload)
rsp, err := s.c.sendAndWaitDynamic(seq, packet) rsp, err := s.c.sendAndWaitDynamic(seq, packet)
if err != nil { if err != nil {
return return
} }
pkg := new(oidb.OIDBSSOPkg) pkg := new(oidb.OIDBSSOPkg)
if err = proto.Unmarshal(rsp, pkg); err != nil { if err = protobuf.Unmarshal(rsp, pkg); err != nil {
return //nil, errors.Wrap(err, "failed to unmarshal protobuf message") return //nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
} }
@ -679,106 +356,108 @@ func (s *GuildService) fetchChannelListState(guildId uint64, channels []*Channel
func convertChannelInfo(info *channel.GuildChannelInfo) *ChannelInfo { func convertChannelInfo(info *channel.GuildChannelInfo) *ChannelInfo {
meta := &ChannelMeta{ meta := &ChannelMeta{
CreatorUin: info.CreatorUin.Unwrap(), CreatorUin: info.GetCreatorUin(),
CreatorTinyId: info.CreatorTinyId.Unwrap(), CreatorTinyId: info.GetCreatorTinyId(),
CreateTime: info.CreateTime.Unwrap(), CreateTime: info.GetCreateTime(),
GuildId: info.GuildId.Unwrap(), GuildId: info.GetGuildId(),
VisibleType: info.VisibleType.Unwrap(), VisibleType: info.GetVisibleType(),
CurrentSlowMode: info.CurrentSlowModeKey.Unwrap(), CurrentSlowMode: info.GetCurrentSlowModeKey(),
TalkPermission: info.TalkPermission.Unwrap(), TalkPermission: info.GetTalkPermission(),
} }
if info.TopMsg != nil { if info.TopMsg != nil {
meta.TopMessageSeq = info.TopMsg.TopMsgSeq.Unwrap() meta.TopMessageSeq = info.TopMsg.GetTopMsgSeq()
meta.TopMessageTime = info.TopMsg.TopMsgTime.Unwrap() meta.TopMessageTime = info.TopMsg.GetTopMsgTime()
meta.TopMessageOperatorId = info.TopMsg.TopMsgOperatorTinyId.Unwrap() meta.TopMessageOperatorId = info.TopMsg.GetTopMsgOperatorTinyId()
} }
for _, slow := range info.SlowModeInfos { for _, slow := range info.SlowModeInfos {
meta.SlowModes = append(meta.SlowModes, &ChannelSlowModeInfo{ meta.SlowModes = append(meta.SlowModes, &ChannelSlowModeInfo{
SlowModeKey: slow.SlowModeKey.Unwrap(), SlowModeKey: slow.GetSlowModeKey(),
SpeakFrequency: slow.SpeakFrequency.Unwrap(), SpeakFrequency: slow.GetSpeakFrequency(),
SlowModeCircle: slow.SlowModeCircle.Unwrap(), SlowModeCircle: slow.GetSlowModeCircle(),
SlowModeText: slow.SlowModeText.Unwrap(), SlowModeText: slow.GetSlowModeText(),
}) })
} }
return &ChannelInfo{ return &ChannelInfo{
ChannelId: info.ChannelId.Unwrap(), ChannelId: info.GetChannelId(),
ChannelName: info.ChannelName.Unwrap(), ChannelName: info.GetChannelName(),
NotifyType: uint32(info.FinalNotifyType.Unwrap()), NotifyType: uint32(info.GetFinalNotifyType()),
ChannelType: ChannelType(info.ChannelType.Unwrap()), ChannelType: ChannelType(info.GetChannelType()),
Meta: meta, Meta: meta,
fetchTime: time.Now().Unix(),
} }
} }
func (c *QQClient) syncChannelFirstView() { func (c *QQClient) syncChannelFirstView() {
rsp, err := c.sendAndWaitDynamic(c.buildSyncChannelFirstViewPacket()) rsp, err := c.sendAndWaitDynamic(c.buildSyncChannelFirstViewPacket())
if err != nil { if err != nil {
c.error("sync channel error: %v", err) c.Error("sync channel error: %v", err)
return return
} }
firstViewRsp := new(channel.FirstViewRsp) firstViewRsp := new(channel.FirstViewRsp)
if err = proto.Unmarshal(rsp, firstViewRsp); err != nil { if err = protobuf.Unmarshal(rsp, firstViewRsp); err != nil {
return return
} }
c.GuildService.TinyId = firstViewRsp.SelfTinyid.Unwrap() c.GuildService.TinyId = firstViewRsp.GetSelfTinyid()
c.GuildService.GuildCount = firstViewRsp.GuildCount.Unwrap() c.GuildService.GuildCount = firstViewRsp.GetGuildCount()
if self, err := c.GuildService.GetUserProfile(c.GuildService.TinyId); err == nil { if self, err := c.GuildService.GetUserProfile(c.GuildService.TinyId); err == nil {
c.GuildService.Nickname = self.Nickname c.GuildService.Nickname = self.Nickname
c.GuildService.AvatarUrl = self.AvatarUrl c.GuildService.AvatarUrl = self.AvatarUrl
} else { } else {
c.error("get self guild profile error: %v", err) c.Error("get self guild profile error: %v", err)
} }
} }
func (c *QQClient) buildSyncChannelFirstViewPacket() (uint16, []byte) { func (c *QQClient) buildSyncChannelFirstViewPacket() (uint16, []byte) {
seq := c.nextSeq()
req := &channel.FirstViewReq{ req := &channel.FirstViewReq{
LastMsgTime: proto.Uint64(0), LastMsgTime: proto.Uint64(0),
Seq: proto.Uint32(0), Seq: proto.Uint32(0),
DirectMessageFlag: proto.Uint32(1), DirectMessageFlag: proto.Uint32(1),
} }
payload, _ := proto.Marshal(req) payload, _ := protobuf.Marshal(req)
return c.uniPacket("trpc.group_pro.synclogic.SyncLogic.SyncFirstView", payload) packet := packets.BuildUniPacket(c.Uin, seq, "trpc.group_pro.synclogic.SyncLogic.SyncFirstView", 1, c.OutGoingPacketSessionId, []byte{}, c.sigInfo.d2Key, payload)
return seq, packet
} }
func decodeGuildPushFirstView(c *QQClient, pkt *network.Packet) (any, error) { func decodeGuildPushFirstView(c *QQClient, _ *incomingPacketInfo, payload []byte) (interface{}, error) {
firstViewMsg := new(channel.FirstViewMsg) firstViewMsg := new(channel.FirstViewMsg)
if err := proto.Unmarshal(pkt.Payload, firstViewMsg); err != nil { if err := protobuf.Unmarshal(payload, firstViewMsg); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
if len(firstViewMsg.GuildNodes) > 0 { if len(firstViewMsg.GuildNodes) > 0 {
c.GuildService.Guilds = []*GuildInfo{} c.GuildService.Guilds = []*GuildInfo{}
for _, guild := range firstViewMsg.GuildNodes { for _, guild := range firstViewMsg.GuildNodes {
info := &GuildInfo{ info := &GuildInfo{
GuildId: guild.GuildId.Unwrap(), GuildId: guild.GetGuildId(),
GuildCode: guild.GuildCode.Unwrap(), GuildCode: guild.GetGuildCode(),
GuildName: utils.B2S(guild.GuildName), GuildName: utils.B2S(guild.GuildName),
CoverUrl: fmt.Sprintf("https://groupprocover-76483.picgzc.qpic.cn/%v", guild.GuildId.Unwrap()), CoverUrl: fmt.Sprintf("https://groupprocover-76483.picgzc.qpic.cn/%v", guild.GetGuildId()),
AvatarUrl: fmt.Sprintf("https://groupprohead-76292.picgzc.qpic.cn/%v", guild.GuildId.Unwrap()), AvatarUrl: fmt.Sprintf("https://groupprohead-76292.picgzc.qpic.cn/%v", guild.GetGuildId()),
} }
channels, err := c.GuildService.FetchChannelList(info.GuildId) channels, err := c.GuildService.FetchChannelList(info.GuildId)
if err != nil { if err != nil {
c.warning("warning: fetch guild %v channel error %v. will use sync node to fill channel list field", guild.GuildId, err) c.Warning("waring: fetch guild %v channel error %v. will use sync node to fill channel list field", guild.GuildId, err)
for _, node := range guild.ChannelNodes { for _, node := range guild.ChannelNodes {
meta := new(channel.ChannelMsgMeta) meta := new(channel.ChannelMsgMeta)
_ = proto.Unmarshal(node.Meta, meta) _ = protobuf.Unmarshal(node.Meta, meta)
info.Channels = append(info.Channels, &ChannelInfo{ info.Channels = append(info.Channels, &ChannelInfo{
ChannelId: node.ChannelId.Unwrap(), ChannelId: node.GetChannelId(),
ChannelName: utils.B2S(node.ChannelName), ChannelName: utils.B2S(node.ChannelName),
Time: node.Time.Unwrap(), Time: node.GetTime(),
EventTime: node.EventTime.Unwrap(), EventTime: node.GetEventTime(),
NotifyType: node.NotifyType.Unwrap(), NotifyType: node.GetNotifyType(),
ChannelType: ChannelType(node.ChannelType.Unwrap()), ChannelType: ChannelType(node.GetChannelType()),
AtAllSeq: meta.AtAllSeq.Unwrap(), AtAllSeq: meta.GetAtAllSeq(),
}) })
} }
} else { } else {
info.Channels = channels info.Channels = channels
} }
// info.Bots, info.Members, info.Admins, _ = c.GuildService.GetGuildMembers(info.GuildId) info.Bots, info.Members, info.Admins, _ = c.GuildService.GetGuildMembers(info.GuildId)
c.GuildService.Guilds = append(c.GuildService.Guilds, info) c.GuildService.Guilds = append(c.GuildService.Guilds, info)
} }
} }
// if len(firstViewMsg.ChannelMsgs) > 0 { // sync msg if len(firstViewMsg.ChannelMsgs) > 0 { // sync msg
// }
}
return nil, nil return nil, nil
} }

View File

@ -1,61 +1,37 @@
package client package client
import ( import (
"sync"
"time" "time"
"github.com/pierrec/lz4/v4"
"github.com/pkg/errors" "github.com/pkg/errors"
protobuf "github.com/segmentio/encoding/proto"
"github.com/Mrs4s/MiraiGo/client/internal/network" "github.com/Mrs4s/MiraiGo/internal/packets"
"github.com/Mrs4s/MiraiGo/client/pb/channel" "github.com/Mrs4s/MiraiGo/internal/protobuf/data/channel"
"github.com/Mrs4s/MiraiGo/client/pb/msg" "github.com/Mrs4s/MiraiGo/internal/protobuf/data/msg"
"github.com/Mrs4s/MiraiGo/internal/proto" "github.com/Mrs4s/MiraiGo/internal/protobuf/proto"
) )
func init() { func init() {
decoders["MsgPush.PushGroupProMsg"] = decodeGuildEventFlowPacket decoders["MsgPush.PushGroupProMsg"] = decodeGuildEventFlowPacket
} }
var updateChanLock sync.Mutex func decodeGuildEventFlowPacket(c *QQClient, _ *incomingPacketInfo, payload []byte) (interface{}, error) {
type tipsPushInfo struct {
TinyId uint64
// TargetMessageSenderUin int64
GuildId uint64
ChannelId uint64
}
func decodeGuildEventFlowPacket(c *QQClient, pkt *network.Packet) (any, error) {
push := new(channel.MsgOnlinePush) push := new(channel.MsgOnlinePush)
if err := proto.Unmarshal(pkt.Payload, push); err != nil { if err := protobuf.Unmarshal(payload, push); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
if push.CompressFlag.Unwrap() == 1 && len(push.CompressMsg) > 0 {
press := new(channel.PressMsg)
dst := make([]byte, len(push.CompressMsg)*2)
i, err := lz4.UncompressBlock(push.CompressMsg, dst)
for times := 0; err != nil && err.Error() == "lz4: invalid source or destination buffer too short" && times < 5; times++ {
dst = append(dst, make([]byte, 1024)...)
i, err = lz4.UncompressBlock(push.CompressMsg, dst)
}
if err != nil {
return nil, errors.Wrap(err, "failed to decompress guild event packet")
}
if err = proto.Unmarshal(dst[:i], press); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
}
push.Msgs = press.Msgs
}
for _, m := range push.Msgs { for _, m := range push.Msgs {
if m.Head == nil { if m.Head.ContentHead.GetType() == 3841 {
continue type tipsPushInfo struct {
} TinyId uint64
if m.Head.ContentHead.Type.Unwrap() == 3841 { TargetMessageSenderUin int64
GuildId uint64
ChannelId uint64
}
// todo: 回头 event flow 的处理移出去重构下逻辑, 先暂时这样方便改 // todo: 回头 event flow 的处理移出去重构下逻辑, 先暂时这样方便改
var common *msg.CommonElem var common *msg.CommonElem
if m.Body != nil && m.Body.RichText != nil { if m.Body != nil {
for _, e := range m.Body.RichText.Elems { for _, e := range m.Body.RichText.Elems {
if e.CommonElem != nil { if e.CommonElem != nil {
common = e.CommonElem common = e.CommonElem
@ -63,181 +39,92 @@ func decodeGuildEventFlowPacket(c *QQClient, pkt *network.Packet) (any, error) {
} }
} }
} }
if m.Head.ContentHead.SubType.Unwrap() == 2 { // todo: tips? if m.Head.ContentHead.GetSubType() == 2 { // todo: tips?
// if common == nil { // empty tips if common == nil { // empty tips
// }
tipsInfo := &tipsPushInfo{ }
TinyId: m.Head.RoutingHead.FromTinyid.Unwrap(), tipsInfo := &tipsPushInfo{
GuildId: m.Head.RoutingHead.GuildId.Unwrap(), TinyId: m.Head.RoutingHead.GetFromTinyid(),
ChannelId: m.Head.RoutingHead.ChannelId.Unwrap(), GuildId: m.Head.RoutingHead.GetGuildId(),
ChannelId: m.Head.RoutingHead.GetChannelId(),
}
if len(m.CtrlHead.IncludeUin) > 0 {
tipsInfo.TargetMessageSenderUin = int64(m.CtrlHead.IncludeUin[0])
} }
/*
if len(m.CtrlHead.IncludeUin) > 0 {
tipsInfo.TargetMessageSenderUin = int64(m.CtrlHead.IncludeUin[0])
}
*/
return tipsInfo, nil return tipsInfo, nil
} }
if common == nil || common.ServiceType.Unwrap() != 500 { if common == nil || common.GetServiceType() != 500 {
continue continue
} }
eventBody := new(channel.EventBody) eventBody := new(channel.EventBody)
if err := proto.Unmarshal(common.PbElem, eventBody); err != nil { if err := protobuf.Unmarshal(common.PbElem, eventBody); err != nil {
c.error("failed to unmarshal guild channel event body: %v", err) c.Error("failed to unmarshal guild channel event body: %v", err)
continue continue
} }
c.processGuildEventBody(m, eventBody) if eventBody.UpdateMsg != nil {
if eventBody.UpdateMsg.GetEventType() == 1 || eventBody.UpdateMsg.GetEventType() == 2 { // todo: 撤回消息
continue
}
if eventBody.UpdateMsg.GetEventType() == 4 { // 消息贴表情更新 (包含添加或删除)
t, err := c.GuildService.pullRoamMsgByEventFlow(m.Head.RoutingHead.GetGuildId(), m.Head.RoutingHead.GetChannelId(), eventBody.UpdateMsg.GetMsgSeq(), eventBody.UpdateMsg.GetMsgSeq(), eventBody.UpdateMsg.GetEventVersion()-1)
if err != nil || len(t) == 0 {
c.Error("process guild event flow error: pull eventMsg message error: %v", err)
continue
}
// 自己的消息被贴表情会单独推送一个tips, 这里不需要解析
if t[0].Head.RoutingHead.GetFromTinyid() == c.GuildService.TinyId {
continue
}
updatedEvent := &GuildMessageReactionsUpdatedEvent{
GuildId: m.Head.RoutingHead.GetGuildId(),
ChannelId: m.Head.RoutingHead.GetChannelId(),
MessageId: t[0].Head.ContentHead.GetSeq(),
CurrentReactions: decodeGuildMessageEmojiReactions(t[0]),
}
tipsInfo, err := c.waitPacketTimeoutSyncF("MsgPush.PushGroupProMsg", time.Second, func(i interface{}) bool {
if i == nil {
return false
}
_, ok := i.(*tipsPushInfo)
return ok
})
if err == nil {
updatedEvent.OperatorId = tipsInfo.(*tipsPushInfo).TinyId
updatedEvent.MessageSenderUin = tipsInfo.(*tipsPushInfo).TargetMessageSenderUin
}
c.dispatchGuildMessageReactionsUpdatedEvent(updatedEvent)
}
}
continue continue
} }
if m.Head.ContentHead.Type.Unwrap() == 3840 { if cm := c.parseGuildChannelMessage(m); cm != nil {
if m.Head.RoutingHead.DirectMessageFlag.Unwrap() == 1 { c.dispatchGuildChannelMessage(cm)
// todo: direct message decode
continue
}
if m.Head.RoutingHead.FromTinyid.Unwrap() == c.GuildService.TinyId {
continue
}
if cm := c.GuildService.parseGuildChannelMessage(m); cm != nil {
c.dispatchGuildChannelMessage(cm)
}
} }
} }
return nil, nil return nil, nil
} }
func (c *QQClient) processGuildEventBody(m *channel.ChannelMsgContent, eventBody *channel.EventBody) { func (s *GuildService) pullRoamMsgByEventFlow(guildId, channelId, beginSeq, endSeq, eventVersion uint64) ([]*channel.ChannelMsgContent, error) {
var guild *GuildInfo payload, _ := protobuf.Marshal(&channel.ChannelMsgReq{
if m.Head.RoutingHead.GuildId.Unwrap() != 0 { ChannelParam: &channel.ChannelParam{
if guild = c.GuildService.FindGuild(m.Head.RoutingHead.GuildId.Unwrap()); guild == nil { GuildId: &guildId,
c.warning("process channel event error: guild not found.") ChannelId: &channelId,
return BeginSeq: &beginSeq,
} EndSeq: &endSeq,
Version: []uint64{eventVersion},
},
WithVersionFlag: proto.Uint32(1),
DirectMessageFlag: proto.Uint32(0),
})
seq := s.c.nextSeq()
packet := packets.BuildUniPacket(s.c.Uin, seq, "trpc.group_pro.synclogic.SyncLogic.GetChannelMsg", 1, s.c.OutGoingPacketSessionId, []byte{}, s.c.sigInfo.d2Key, payload)
rsp, err := s.c.sendAndWaitDynamic(seq, packet)
if err != nil {
return nil, errors.Wrap(err, "send packet error")
} }
switch { msgRsp := new(channel.ChannelMsgRsp)
case eventBody.CreateChan != nil: if err = protobuf.Unmarshal(rsp, msgRsp); err != nil {
for _, chanId := range eventBody.CreateChan.CreateId { return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
if guild.FindChannel(chanId.ChanId.Unwrap()) != nil {
continue
}
channelInfo, err := c.GuildService.FetchChannelInfo(guild.GuildId, chanId.ChanId.Unwrap())
if err != nil {
c.warning("process create channel event error: fetch channel info error: %v", err)
continue
}
guild.Channels = append(guild.Channels, channelInfo)
c.dispatchGuildChannelCreatedEvent(&GuildChannelOperationEvent{
OperatorId: m.Head.RoutingHead.FromTinyid.Unwrap(),
GuildId: m.Head.RoutingHead.GuildId.Unwrap(),
ChannelInfo: channelInfo,
})
}
case eventBody.DestroyChan != nil:
for _, chanId := range eventBody.DestroyChan.DeleteId {
channelInfo := guild.FindChannel(chanId.ChanId.Unwrap())
if channelInfo == nil {
continue
}
guild.removeChannel(chanId.ChanId.Unwrap())
c.dispatchGuildChannelDestroyedEvent(&GuildChannelOperationEvent{
OperatorId: m.Head.RoutingHead.FromTinyid.Unwrap(),
GuildId: guild.GuildId,
ChannelInfo: channelInfo,
})
}
case eventBody.ChangeChanInfo != nil:
updateChanLock.Lock()
defer updateChanLock.Unlock()
oldInfo := guild.FindChannel(eventBody.ChangeChanInfo.ChanId.Unwrap())
if oldInfo == nil {
info, err := c.GuildService.FetchChannelInfo(m.Head.RoutingHead.GuildId.Unwrap(), eventBody.ChangeChanInfo.ChanId.Unwrap())
if err != nil {
c.error("failed to decode channel info updated event: fetch channel info failed: %v", err)
return
}
guild.Channels = append(guild.Channels, info)
oldInfo = info
}
if time.Now().Unix()-oldInfo.fetchTime <= 2 {
return
}
newInfo, err := c.GuildService.FetchChannelInfo(m.Head.RoutingHead.GuildId.Unwrap(), eventBody.ChangeChanInfo.ChanId.Unwrap())
if err != nil {
c.error("failed to decode channel info updated event: fetch channel info failed: %v", err)
return
}
for i := range guild.Channels {
if guild.Channels[i].ChannelId == newInfo.ChannelId {
guild.Channels[i] = newInfo
break
}
}
c.dispatchGuildChannelUpdatedEvent(&GuildChannelUpdatedEvent{
OperatorId: m.Head.RoutingHead.FromTinyid.Unwrap(),
GuildId: m.Head.RoutingHead.GuildId.Unwrap(),
ChannelId: eventBody.ChangeChanInfo.ChanId.Unwrap(),
OldChannelInfo: oldInfo,
NewChannelInfo: newInfo,
})
case eventBody.JoinGuild != nil:
/* 应该不会重复推送把, 不会吧不会吧
if mem := guild.FindMember(eventBody.JoinGuild.MemberTinyid.Unwrap()); mem != nil {
c.info("ignore join guild event: member %v already exists", mem.TinyId)
return
}
*/
profile, err := c.GuildService.FetchGuildMemberProfileInfo(guild.GuildId, eventBody.JoinGuild.MemberTinyid.Unwrap())
if err != nil {
c.error("failed to decode member join guild event: get member profile error: %v", err)
return
}
info := &GuildMemberInfo{
TinyId: profile.TinyId,
Nickname: profile.Nickname,
}
// guild.Members = append(guild.Members, info)
c.dispatchMemberJoinedGuildEvent(&MemberJoinGuildEvent{
Guild: guild,
Member: info,
})
case eventBody.UpdateMsg != nil:
if eventBody.UpdateMsg.EventType.Unwrap() == 1 || eventBody.UpdateMsg.EventType.Unwrap() == 2 {
c.dispatchGuildMessageRecalledEvent(&GuildMessageRecalledEvent{
OperatorId: eventBody.UpdateMsg.OperatorTinyid.Unwrap(),
GuildId: m.Head.RoutingHead.GuildId.Unwrap(),
ChannelId: m.Head.RoutingHead.ChannelId.Unwrap(),
MessageId: eventBody.UpdateMsg.MsgSeq.Unwrap(),
RecallTime: int64(m.Head.ContentHead.Time.Unwrap()),
})
return
}
if eventBody.UpdateMsg.EventType.Unwrap() == 4 { // 消息贴表情更新 (包含添加或删除)
t, err := c.GuildService.pullChannelMessages(m.Head.RoutingHead.GuildId.Unwrap(), m.Head.RoutingHead.ChannelId.Unwrap(), eventBody.UpdateMsg.MsgSeq.Unwrap(), eventBody.UpdateMsg.MsgSeq.Unwrap(), eventBody.UpdateMsg.EventVersion.Unwrap()-1, false)
if err != nil || len(t) == 0 {
c.error("process guild event flow error: pull eventMsg message error: %v", err)
return
}
// 自己的消息被贴表情会单独推送一个tips, 这里不需要解析
if t[0].Head.RoutingHead.FromTinyid.Unwrap() == c.GuildService.TinyId {
return
}
updatedEvent := &GuildMessageReactionsUpdatedEvent{
GuildId: m.Head.RoutingHead.GuildId.Unwrap(),
ChannelId: m.Head.RoutingHead.ChannelId.Unwrap(),
MessageId: t[0].Head.ContentHead.Seq.Unwrap(),
CurrentReactions: decodeGuildMessageEmojiReactions(t[0]),
}
tipsInfo, err := c.waitPacketTimeoutSyncF("MsgPush.PushGroupProMsg", time.Second, func(i any) bool {
if i == nil {
return false
}
_, ok := i.(*tipsPushInfo)
return ok
})
if err == nil {
updatedEvent.OperatorId = tipsInfo.(*tipsPushInfo).TinyId
// updatedEvent.MessageSenderUin = tipsInfo.(*tipsPushInfo).TargetMessageSenderUin
}
c.dispatchGuildMessageReactionsUpdatedEvent(updatedEvent)
}
} }
return msgRsp.ChannelMsg.Msgs, nil
} }

View File

@ -1,40 +1,31 @@
package client package client
import ( import (
"fmt" "encoding/hex"
"io"
"math/rand" "math/rand"
"strconv" "strconv"
protobuf "github.com/segmentio/encoding/proto"
"github.com/Mrs4s/MiraiGo/client/pb/cmd0x388"
"github.com/Mrs4s/MiraiGo/internal/packets"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/Mrs4s/MiraiGo/client/internal/network" "google.golang.org/protobuf/proto"
"github.com/Mrs4s/MiraiGo/client/pb/channel"
"github.com/Mrs4s/MiraiGo/client/pb/cmd0x388" "github.com/Mrs4s/MiraiGo/internal/protobuf/data/channel"
"github.com/Mrs4s/MiraiGo/client/pb/msg" "github.com/Mrs4s/MiraiGo/internal/protobuf/data/msg"
"github.com/Mrs4s/MiraiGo/internal/proto"
"github.com/Mrs4s/MiraiGo/message" "github.com/Mrs4s/MiraiGo/message"
) )
func init() { func (s *GuildService) SendGuildChannelMessage(guildId, channelId uint64, m *message.SendingMessage) error {
decoders["ImgStore.QQMeetPicUp"] = decodeGuildImageStoreResponse
}
func (s *GuildService) SendGuildChannelMessage(guildId, channelId uint64, m *message.SendingMessage) (*message.GuildChannelMessage, error) {
mr := rand.Uint32() // 客户端似乎是生成的 u32 虽然类型是u64 mr := rand.Uint32() // 客户端似乎是生成的 u32 虽然类型是u64
for _, elem := range m.Elements {
if elem.Type() == message.At {
at := elem.(*message.AtElement)
if at.SubType == message.AtTypeGroupMember {
at.SubType = message.AtTypeGuildMember
}
}
}
req := &channel.DF62ReqBody{Msg: &channel.ChannelMsgContent{ req := &channel.DF62ReqBody{Msg: &channel.ChannelMsgContent{
Head: &channel.ChannelMsgHead{ Head: &channel.ChannelMsgHead{
RoutingHead: &channel.ChannelRoutingHead{ RoutingHead: &channel.ChannelRoutingHead{
GuildId: proto.Some(guildId), GuildId: &guildId,
ChannelId: proto.Some(channelId), ChannelId: &channelId,
FromUin: proto.Uint64(uint64(s.c.Uin)), FromUin: proto.Uint64(uint64(s.c.Uin)),
}, },
ContentHead: &channel.ChannelContentHead{ ContentHead: &channel.ChannelContentHead{
@ -48,136 +39,37 @@ func (s *GuildService) SendGuildChannelMessage(guildId, channelId uint64, m *mes
}, },
}, },
}} }}
payload, _ := proto.Marshal(req) seq := s.c.nextSeq()
seq, packet := s.c.uniPacket("MsgProxy.SendMsg", payload) payload, _ := protobuf.Marshal(req)
packet := packets.BuildUniPacket(s.c.Uin, seq, "MsgProxy.SendMsg", 1, s.c.OutGoingPacketSessionId, []byte{}, s.c.sigInfo.d2Key, payload)
rsp, err := s.c.sendAndWaitDynamic(seq, packet) rsp, err := s.c.sendAndWaitDynamic(seq, packet)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "send packet error") return errors.Wrap(err, "send packet error")
} }
body := new(channel.DF62RspBody) body := new(channel.DF62RspBody)
if err = proto.Unmarshal(rsp, body); err != nil { if err = protobuf.Unmarshal(rsp, body); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") return errors.Wrap(err, "failed to unmarshal protobuf message")
} }
if body.Result.Unwrap() != 0 { if body.GetResult() != 0 {
return nil, errors.Errorf("send channel message error: server response %v", body.Result.Unwrap()) return errors.Errorf("send channel message error: server response %v", body.GetResult())
} }
elements := m.Elements // todo: 返回 *message.GuildMessage
if body.Body != nil && body.Body.RichText != nil { return nil
elements = message.ParseMessageElems(body.Body.RichText.Elems)
}
return &message.GuildChannelMessage{
Id: body.Head.ContentHead.Seq.Unwrap(),
InternalId: body.Head.ContentHead.Random.Unwrap(),
GuildId: guildId,
ChannelId: channelId,
Time: int64(body.SendTime.Unwrap()),
Sender: &message.GuildSender{
TinyId: body.Head.RoutingHead.FromTinyid.Unwrap(),
Nickname: s.Nickname,
},
Elements: elements,
}, nil
} }
func (s *GuildService) QueryImage(guildId, channelId uint64, hash []byte, size uint64) (*message.GuildImageElement, error) { func (s *GuildService) QueryImage(guildId, channelId uint64, hash []byte, size uint64) (*message.GuildImageElement, error) {
rsp, err := s.c.sendAndWait(s.c.buildGuildImageStorePacket(guildId, channelId, hash, size)) seq := s.c.nextSeq()
if err != nil { payload, _ := protobuf.Marshal(&cmd0x388.D388ReqBody{
return nil, errors.Wrap(err, "send packet error")
}
body := rsp.(*imageUploadResponse)
if body.IsExists {
return &message.GuildImageElement{
FileId: body.FileId,
FilePath: fmt.Sprintf("%x.jpg", hash),
Size: int32(size),
DownloadIndex: body.DownloadIndex,
Width: body.Width,
Height: body.Height,
Md5: hash,
}, nil
}
return nil, errors.New("image is not exists")
}
// Deprecated: use QQClient.UploadImage instead
func (s *GuildService) UploadGuildImage(guildId, channelId uint64, img io.ReadSeeker) (*message.GuildImageElement, error) {
source := message.Source{
SourceType: message.SourceGuildChannel,
PrimaryID: int64(guildId),
SecondaryID: int64(channelId),
}
image, err := s.c.uploadGroupOrGuildImage(source, img)
if err != nil {
return nil, err
}
return image.(*message.GuildImageElement), nil
}
func (s *GuildService) PullGuildChannelMessage(guildId, channelId, beginSeq, endSeq uint64) (r []*message.GuildChannelMessage, e error) {
contents, err := s.pullChannelMessages(guildId, channelId, beginSeq, endSeq, 0, false)
if err != nil {
return nil, errors.Wrap(err, "pull channel message error")
}
for _, c := range contents {
if cm := s.parseGuildChannelMessage(c); cm != nil {
cm.Reactions = decodeGuildMessageEmojiReactions(c)
r = append(r, cm)
}
}
if len(r) == 0 {
return nil, errors.New("message not found")
}
return
}
func (s *GuildService) pullChannelMessages(guildId, channelId, beginSeq, endSeq, eventVersion uint64, direct bool) ([]*channel.ChannelMsgContent, error) {
param := &channel.ChannelParam{
GuildId: proto.Some(guildId),
ChannelId: proto.Some(channelId),
BeginSeq: proto.Some(beginSeq),
EndSeq: proto.Some(endSeq),
}
if eventVersion != 0 {
param.Version = []uint64{eventVersion}
}
withVersionFlag := uint32(0)
if eventVersion != 0 {
withVersionFlag = 1
}
directFlag := uint32(0)
if direct {
directFlag = 1
}
payload, _ := proto.Marshal(&channel.ChannelMsgReq{
ChannelParam: param,
WithVersionFlag: proto.Some(withVersionFlag),
DirectMessageFlag: proto.Some(directFlag),
})
seq, packet := s.c.uniPacket("trpc.group_pro.synclogic.SyncLogic.GetChannelMsg", payload)
rsp, err := s.c.sendAndWaitDynamic(seq, packet)
if err != nil {
return nil, errors.Wrap(err, "send packet error")
}
msgRsp := new(channel.ChannelMsgRsp)
if err = proto.Unmarshal(rsp, msgRsp); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
}
return msgRsp.ChannelMsg.Msgs, nil
}
func (c *QQClient) buildGuildImageStorePacket(guildId, channelId uint64, hash []byte, size uint64) (uint16, []byte) {
payload, _ := proto.Marshal(&cmd0x388.D388ReqBody{
NetType: proto.Uint32(3), NetType: proto.Uint32(3),
Subcmd: proto.Uint32(1), Subcmd: proto.Uint32(1),
TryupImgReq: []*cmd0x388.TryUpImgReq{ TryupImgReq: []*cmd0x388.TryUpImgReq{
{ {
GroupCode: proto.Some(channelId), GroupCode: &channelId,
SrcUin: proto.Uint64(uint64(c.Uin)), SrcUin: proto.Uint64(uint64(s.c.Uin)),
FileId: proto.Uint64(0), FileId: proto.Uint64(0),
FileMd5: hash, FileMd5: hash,
FileSize: proto.Some(size), FileSize: &size,
FileName: []byte(fmt.Sprintf("%x.jpg", hash)), FileName: []byte(hex.EncodeToString(hash) + ".jpg"),
SrcTerm: proto.Uint32(5), SrcTerm: proto.Uint32(5),
PlatformType: proto.Uint32(9), PlatformType: proto.Uint32(9),
BuType: proto.Uint32(211), BuType: proto.Uint32(211),
@ -185,20 +77,41 @@ func (c *QQClient) buildGuildImageStorePacket(guildId, channelId uint64, hash []
BuildVer: []byte("8.8.38.2266"), BuildVer: []byte("8.8.38.2266"),
AppPicType: proto.Uint32(1052), AppPicType: proto.Uint32(1052),
SrvUpload: proto.Uint32(0), SrvUpload: proto.Uint32(0),
QqmeetGuildId: proto.Some(guildId), QqmeetGuildId: &guildId,
QqmeetChannelId: proto.Some(channelId), QqmeetChannelId: &channelId,
}, },
}, },
CommandId: proto.Uint32(83), CommandId: proto.Uint32(83),
}) })
return c.uniPacket("ImgStore.QQMeetPicUp", payload) packet := packets.BuildUniPacket(s.c.Uin, seq, "ImgStore.QQMeetPicUp", 1, s.c.OutGoingPacketSessionId, []byte{}, s.c.sigInfo.d2Key, payload)
rsp, err := s.c.sendAndWaitDynamic(seq, packet)
if err != nil {
return nil, errors.Wrap(err, "send packet error")
}
body := new(cmd0x388.D388RspBody)
if err = protobuf.Unmarshal(rsp, body); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
}
if len(body.TryupImgRsp) == 0 {
return nil, errors.New("response is empty")
}
if body.TryupImgRsp[0].GetFileExit() {
return &message.GuildImageElement{
FileId: body.TryupImgRsp[0].GetFileid(),
FilePath: hex.EncodeToString(hash) + ".jpg",
Size: int32(size),
DownloadIndex: string(body.TryupImgRsp[0].GetDownloadIndex()),
Md5: hash,
}, nil
}
return nil, errors.New("image is not exists")
} }
func decodeGuildMessageEmojiReactions(content *channel.ChannelMsgContent) (r []*message.GuildMessageEmojiReaction) { func decodeGuildMessageEmojiReactions(content *channel.ChannelMsgContent) (r []*message.GuildMessageEmojiReaction) {
r = []*message.GuildMessageEmojiReaction{} r = []*message.GuildMessageEmojiReaction{}
var common *msg.CommonElem var common *msg.CommonElem
for _, elem := range content.Body.RichText.Elems { for _, elem := range content.Body.RichText.Elems {
if elem.CommonElem != nil && elem.CommonElem.ServiceType.Unwrap() == 38 { if elem.CommonElem != nil && elem.CommonElem.GetServiceType() == 38 {
common = elem.CommonElem common = elem.CommonElem
break break
} }
@ -207,21 +120,21 @@ func decodeGuildMessageEmojiReactions(content *channel.ChannelMsgContent) (r []*
return return
} }
serv38 := new(msg.MsgElemInfoServtype38) serv38 := new(msg.MsgElemInfoServtype38)
_ = proto.Unmarshal(common.PbElem, serv38) _ = protobuf.Unmarshal(common.PbElem, serv38)
if len(serv38.ReactData) > 0 { if len(serv38.ReactData) > 0 {
cnt := new(channel.MsgCnt) cnt := new(channel.MsgCnt)
_ = proto.Unmarshal(serv38.ReactData, cnt) _ = protobuf.Unmarshal(serv38.ReactData, cnt)
if len(cnt.EmojiReaction) == 0 { if len(cnt.EmojiReaction) == 0 {
return return
} }
for _, e := range cnt.EmojiReaction { for _, e := range cnt.EmojiReaction {
reaction := &message.GuildMessageEmojiReaction{ reaction := &message.GuildMessageEmojiReaction{
EmojiId: e.EmojiId.Unwrap(), EmojiId: e.GetEmojiId(),
EmojiType: e.EmojiType.Unwrap(), EmojiType: e.GetEmojiType(),
Count: int32(e.Cnt.Unwrap()), Count: int32(e.GetCnt()),
Clicked: e.IsClicked.Unwrap(), Clicked: e.GetIsClicked(),
} }
if index, err := strconv.ParseInt(e.EmojiId.Unwrap(), 10, 32); err == nil { if index, err := strconv.ParseInt(e.GetEmojiId(), 10, 32); err == nil {
reaction.Face = message.NewFace(int32(index)) reaction.Face = message.NewFace(int32(index))
} }
r = append(r, reaction) r = append(r, reaction)
@ -230,64 +143,21 @@ func decodeGuildMessageEmojiReactions(content *channel.ChannelMsgContent) (r []*
return return
} }
func decodeGuildImageStoreResponse(_ *QQClient, pkt *network.Packet) (any, error) { func (c *QQClient) parseGuildChannelMessage(msg *channel.ChannelMsgContent) *message.GuildChannelMessage {
body := new(cmd0x388.D388RspBody) guild := c.GuildService.FindGuild(msg.Head.RoutingHead.GetGuildId())
if err := proto.Unmarshal(pkt.Payload, body); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
}
if len(body.TryupImgRsp) == 0 {
return nil, errors.New("response is empty")
}
rsp := body.TryupImgRsp[0]
if rsp.Result.Unwrap() != 0 {
return &imageUploadResponse{
ResultCode: int32(rsp.Result.Unwrap()),
Message: string(rsp.FailMsg),
}, nil
}
if rsp.FileExit.Unwrap() {
resp := &imageUploadResponse{
IsExists: true,
FileId: int64(rsp.Fileid.Unwrap()),
DownloadIndex: string(rsp.DownloadIndex),
}
if rsp.ImgInfo != nil {
resp.Width = int32(rsp.ImgInfo.FileWidth.Unwrap())
resp.Height = int32(rsp.ImgInfo.FileHeight.Unwrap())
}
return resp, nil
}
return &imageUploadResponse{
FileId: int64(rsp.Fileid.Unwrap()),
UploadKey: rsp.UpUkey,
UploadIp: rsp.UpIp,
UploadPort: rsp.UpPort,
DownloadIndex: string(rsp.DownloadIndex),
}, nil
}
func (s *GuildService) parseGuildChannelMessage(msg *channel.ChannelMsgContent) *message.GuildChannelMessage {
guild := s.FindGuild(msg.Head.RoutingHead.GuildId.Unwrap())
if guild == nil { if guild == nil {
return nil // todo: sync guild info return nil // todo: sync guild info
} }
if msg.Body == nil || msg.Body.RichText == nil { // mem := guild.FindMember(msg.Head.RoutingHead.GetFromTinyid())
return nil
}
// mem := guild.FindMember(msg.Head.RoutingHead.FromTinyid.Unwrap())
memberName := msg.ExtInfo.MemberName
if memberName == nil {
memberName = msg.ExtInfo.FromNick
}
return &message.GuildChannelMessage{ return &message.GuildChannelMessage{
Id: msg.Head.ContentHead.Seq.Unwrap(), Id: msg.Head.ContentHead.GetSeq(),
InternalId: msg.Head.ContentHead.Random.Unwrap(), InternalId: msg.Body.RichText.Attr.GetRandom(),
GuildId: msg.Head.RoutingHead.GuildId.Unwrap(), GuildId: msg.Head.RoutingHead.GetGuildId(),
ChannelId: msg.Head.RoutingHead.ChannelId.Unwrap(), ChannelId: msg.Head.RoutingHead.GetChannelId(),
Time: int64(msg.Head.ContentHead.Time.Unwrap()), Time: int64(msg.Head.ContentHead.GetTime()),
Sender: &message.GuildSender{ Sender: &message.GuildSender{
TinyId: msg.Head.RoutingHead.FromTinyid.Unwrap(), TinyId: msg.Head.RoutingHead.GetFromTinyid(),
Nickname: string(memberName), Nickname: string(msg.ExtInfo.FromNick),
}, },
Elements: message.ParseMessageElems(msg.Body.RichText.Elems), Elements: message.ParseMessageElems(msg.Body.RichText.Elems),
} }

387
client/handler_map_gen.go Normal file
View File

@ -0,0 +1,387 @@
// Code generated by syncmap; DO NOT EDIT.
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package client
import (
"sync"
"sync/atomic"
"unsafe"
)
// Map is like a Go map[interface{}]interface{} but is safe for concurrent use
// by multiple goroutines without additional locking or coordination.
// Loads, stores, and deletes run in amortized constant time.
//
// The Map type is specialized. Most code should use a plain Go map instead,
// with separate locking or coordination, for better type safety and to make it
// easier to maintain other invariants along with the map content.
//
// The Map type is optimized for two common use cases: (1) when the entry for a given
// key is only ever written once but read many times, as in caches that only grow,
// or (2) when multiple goroutines read, write, and overwrite entries for disjoint
// sets of keys. In these two cases, use of a Map may significantly reduce lock
// contention compared to a Go map paired with a separate Mutex or RWMutex.
//
// The zero Map is empty and ready for use. A Map must not be copied after first use.
type HandlerMap struct {
mu sync.Mutex
// read contains the portion of the map's contents that are safe for
// concurrent access (with or without mu held).
//
// The read field itself is always safe to load, but must only be stored with
// mu held.
//
// Entries stored in read may be updated concurrently without mu, but updating
// a previously-expunged entry requires that the entry be copied to the dirty
// map and unexpunged with mu held.
read atomic.Value // readOnly
// dirty contains the portion of the map's contents that require mu to be
// held. To ensure that the dirty map can be promoted to the read map quickly,
// it also includes all of the non-expunged entries in the read map.
//
// Expunged entries are not stored in the dirty map. An expunged entry in the
// clean map must be unexpunged and added to the dirty map before a new value
// can be stored to it.
//
// If the dirty map is nil, the next write to the map will initialize it by
// making a shallow copy of the clean map, omitting stale entries.
dirty map[uint16]*entryHandlerMap
// misses counts the number of loads since the read map was last updated that
// needed to lock mu to determine whether the key was present.
//
// Once enough misses have occurred to cover the cost of copying the dirty
// map, the dirty map will be promoted to the read map (in the unamended
// state) and the next store to the map will make a new dirty copy.
misses int
}
// readOnly is an immutable struct stored atomically in the Map.read field.
type readOnlyHandlerMap struct {
m map[uint16]*entryHandlerMap
amended bool // true if the dirty map contains some key not in m.
}
// expunged is an arbitrary pointer that marks entries which have been deleted
// from the dirty map.
var expungedHandlerMap = unsafe.Pointer(new(*handlerInfo))
// An entry is a slot in the map corresponding to a particular key.
type entryHandlerMap struct {
// p points to the interface{} value stored for the entry.
//
// If p == nil, the entry has been deleted and m.dirty == nil.
//
// If p == expunged, the entry has been deleted, m.dirty != nil, and the entry
// is missing from m.dirty.
//
// Otherwise, the entry is valid and recorded in m.read.m[key] and, if m.dirty
// != nil, in m.dirty[key].
//
// An entry can be deleted by atomic replacement with nil: when m.dirty is
// next created, it will atomically replace nil with expunged and leave
// m.dirty[key] unset.
//
// An entry's associated value can be updated by atomic replacement, provided
// p != expunged. If p == expunged, an entry's associated value can be updated
// only after first setting m.dirty[key] = e so that lookups using the dirty
// map find the entry.
p unsafe.Pointer // *interface{}
}
func newEntryHandlerMap(i *handlerInfo) *entryHandlerMap {
return &entryHandlerMap{p: unsafe.Pointer(&i)}
}
// Load returns the value stored in the map for a key, or nil if no
// value is present.
// The ok result indicates whether value was found in the map.
func (m *HandlerMap) Load(key uint16) (value *handlerInfo, ok bool) {
read, _ := m.read.Load().(readOnlyHandlerMap)
e, ok := read.m[key]
if !ok && read.amended {
m.mu.Lock()
// Avoid reporting a spurious miss if m.dirty got promoted while we were
// blocked on m.mu. (If further loads of the same key will not miss, it's
// not worth copying the dirty map for this key.)
read, _ = m.read.Load().(readOnlyHandlerMap)
e, ok = read.m[key]
if !ok && read.amended {
e, ok = m.dirty[key]
// Regardless of whether the entry was present, record a miss: this key
// will take the slow path until the dirty map is promoted to the read
// map.
m.missLocked()
}
m.mu.Unlock()
}
if !ok {
return value, false
}
return e.load()
}
func (e *entryHandlerMap) load() (value *handlerInfo, ok bool) {
p := atomic.LoadPointer(&e.p)
if p == nil || p == expungedHandlerMap {
return value, false
}
return *(**handlerInfo)(p), true
}
// Store sets the value for a key.
func (m *HandlerMap) Store(key uint16, value *handlerInfo) {
read, _ := m.read.Load().(readOnlyHandlerMap)
if e, ok := read.m[key]; ok && e.tryStore(&value) {
return
}
m.mu.Lock()
read, _ = m.read.Load().(readOnlyHandlerMap)
if e, ok := read.m[key]; ok {
if e.unexpungeLocked() {
// The entry was previously expunged, which implies that there is a
// non-nil dirty map and this entry is not in it.
m.dirty[key] = e
}
e.storeLocked(&value)
} else if e, ok := m.dirty[key]; ok {
e.storeLocked(&value)
} else {
if !read.amended {
// We're adding the first new key to the dirty map.
// Make sure it is allocated and mark the read-only map as incomplete.
m.dirtyLocked()
m.read.Store(readOnlyHandlerMap{m: read.m, amended: true})
}
m.dirty[key] = newEntryHandlerMap(value)
}
m.mu.Unlock()
}
// tryStore stores a value if the entry has not been expunged.
//
// If the entry is expunged, tryStore returns false and leaves the entry
// unchanged.
func (e *entryHandlerMap) tryStore(i **handlerInfo) bool {
for {
p := atomic.LoadPointer(&e.p)
if p == expungedHandlerMap {
return false
}
if atomic.CompareAndSwapPointer(&e.p, p, unsafe.Pointer(i)) {
return true
}
}
}
// unexpungeLocked ensures that the entry is not marked as expunged.
//
// If the entry was previously expunged, it must be added to the dirty map
// before m.mu is unlocked.
func (e *entryHandlerMap) unexpungeLocked() (wasExpunged bool) {
return atomic.CompareAndSwapPointer(&e.p, expungedHandlerMap, nil)
}
// storeLocked unconditionally stores a value to the entry.
//
// The entry must be known not to be expunged.
func (e *entryHandlerMap) storeLocked(i **handlerInfo) {
atomic.StorePointer(&e.p, unsafe.Pointer(i))
}
// LoadOrStore returns the existing value for the key if present.
// Otherwise, it stores and returns the given value.
// The loaded result is true if the value was loaded, false if stored.
func (m *HandlerMap) LoadOrStore(key uint16, value *handlerInfo) (actual *handlerInfo, loaded bool) {
// Avoid locking if it's a clean hit.
read, _ := m.read.Load().(readOnlyHandlerMap)
if e, ok := read.m[key]; ok {
actual, loaded, ok := e.tryLoadOrStore(value)
if ok {
return actual, loaded
}
}
m.mu.Lock()
read, _ = m.read.Load().(readOnlyHandlerMap)
if e, ok := read.m[key]; ok {
if e.unexpungeLocked() {
m.dirty[key] = e
}
actual, loaded, _ = e.tryLoadOrStore(value)
} else if e, ok := m.dirty[key]; ok {
actual, loaded, _ = e.tryLoadOrStore(value)
m.missLocked()
} else {
if !read.amended {
// We're adding the first new key to the dirty map.
// Make sure it is allocated and mark the read-only map as incomplete.
m.dirtyLocked()
m.read.Store(readOnlyHandlerMap{m: read.m, amended: true})
}
m.dirty[key] = newEntryHandlerMap(value)
actual, loaded = value, false
}
m.mu.Unlock()
return actual, loaded
}
// tryLoadOrStore atomically loads or stores a value if the entry is not
// expunged.
//
// If the entry is expunged, tryLoadOrStore leaves the entry unchanged and
// returns with ok==false.
func (e *entryHandlerMap) tryLoadOrStore(i *handlerInfo) (actual *handlerInfo, loaded, ok bool) {
p := atomic.LoadPointer(&e.p)
if p == expungedHandlerMap {
return actual, false, false
}
if p != nil {
return *(**handlerInfo)(p), true, true
}
// Copy the interface after the first load to make this method more amenable
// to escape analysis: if we hit the "load" path or the entry is expunged, we
// shouldn't bother heap-allocating.
ic := i
for {
if atomic.CompareAndSwapPointer(&e.p, nil, unsafe.Pointer(&ic)) {
return i, false, true
}
p = atomic.LoadPointer(&e.p)
if p == expungedHandlerMap {
return actual, false, false
}
if p != nil {
return *(**handlerInfo)(p), true, true
}
}
}
// LoadAndDelete deletes the value for a key, returning the previous value if any.
// The loaded result reports whether the key was present.
func (m *HandlerMap) LoadAndDelete(key uint16) (value *handlerInfo, loaded bool) {
read, _ := m.read.Load().(readOnlyHandlerMap)
e, ok := read.m[key]
if !ok && read.amended {
m.mu.Lock()
read, _ = m.read.Load().(readOnlyHandlerMap)
e, ok = read.m[key]
if !ok && read.amended {
e, ok = m.dirty[key]
delete(m.dirty, key)
// Regardless of whether the entry was present, record a miss: this key
// will take the slow path until the dirty map is promoted to the read
// map.
m.missLocked()
}
m.mu.Unlock()
}
if ok {
return e.delete()
}
return value, false
}
// Delete deletes the value for a key.
func (m *HandlerMap) Delete(key uint16) {
m.LoadAndDelete(key)
}
func (e *entryHandlerMap) delete() (value *handlerInfo, ok bool) {
for {
p := atomic.LoadPointer(&e.p)
if p == nil || p == expungedHandlerMap {
return value, false
}
if atomic.CompareAndSwapPointer(&e.p, p, nil) {
return *(**handlerInfo)(p), true
}
}
}
// Range calls f sequentially for each key and value present in the map.
// If f returns false, range stops the iteration.
//
// Range does not necessarily correspond to any consistent snapshot of the Map's
// contents: no key will be visited more than once, but if the value for any key
// is stored or deleted concurrently, Range may reflect any mapping for that key
// from any point during the Range call.
//
// Range may be O(N) with the number of elements in the map even if f returns
// false after a constant number of calls.
func (m *HandlerMap) Range(f func(key uint16, value *handlerInfo) bool) {
// We need to be able to iterate over all of the keys that were already
// present at the start of the call to Range.
// If read.amended is false, then read.m satisfies that property without
// requiring us to hold m.mu for a long time.
read, _ := m.read.Load().(readOnlyHandlerMap)
if read.amended {
// m.dirty contains keys not in read.m. Fortunately, Range is already O(N)
// (assuming the caller does not break out early), so a call to Range
// amortizes an entire copy of the map: we can promote the dirty copy
// immediately!
m.mu.Lock()
read, _ = m.read.Load().(readOnlyHandlerMap)
if read.amended {
read = readOnlyHandlerMap{m: m.dirty}
m.read.Store(read)
m.dirty = nil
m.misses = 0
}
m.mu.Unlock()
}
for k, e := range read.m {
v, ok := e.load()
if !ok {
continue
}
if !f(k, v) {
break
}
}
}
func (m *HandlerMap) missLocked() {
m.misses++
if m.misses < len(m.dirty) {
return
}
m.read.Store(readOnlyHandlerMap{m: m.dirty})
m.dirty = nil
m.misses = 0
}
func (m *HandlerMap) dirtyLocked() {
if m.dirty != nil {
return
}
read, _ := m.read.Load().(readOnlyHandlerMap)
m.dirty = make(map[uint16]*entryHandlerMap, len(read.m))
for k, e := range read.m {
if !e.tryExpungeLocked() {
m.dirty[k] = e
}
}
}
func (e *entryHandlerMap) tryExpungeLocked() (isExpunged bool) {
p := atomic.LoadPointer(&e.p)
for p == nil {
if atomic.CompareAndSwapPointer(&e.p, nil, expungedHandlerMap) {
return true
}
p = atomic.LoadPointer(&e.p)
}
return p == expungedHandlerMap
}

499
client/highway.go Normal file
View File

@ -0,0 +1,499 @@
package client
import (
"bytes"
"crypto/md5"
binary2 "encoding/binary"
"fmt"
"io"
"net"
"net/http"
"os"
"strconv"
"sync"
"sync/atomic"
"time"
"github.com/pkg/errors"
"golang.org/x/sync/errgroup"
"google.golang.org/protobuf/proto"
"github.com/Mrs4s/MiraiGo/binary"
"github.com/Mrs4s/MiraiGo/client/pb"
"github.com/Mrs4s/MiraiGo/utils"
)
func (c *QQClient) highwayUpload(ip uint32, port int, updKey, data []byte, cmdID int32) error {
return c.highwayUploadStream(ip, port, updKey, bytes.NewReader(data), cmdID)
}
func (c *QQClient) highwayUploadStream(ip uint32, port int, updKey []byte, stream io.ReadSeeker, cmdId int32) error {
addr := net.TCPAddr{
IP: make([]byte, 4),
Port: port,
}
binary2.LittleEndian.PutUint32(addr.IP, ip)
h := md5.New()
length, _ := io.Copy(h, stream)
fh := h.Sum(nil)
const chunkSize = 8192 * 8
_, _ = stream.Seek(0, io.SeekStart)
conn, err := net.DialTCP("tcp", nil, &addr)
if err != nil {
return errors.Wrap(err, "connect error")
}
defer conn.Close()
offset := 0
reader := binary.NewNetworkReader(conn)
buf := binary.Get256KBytes()
chunk := *buf
defer binary.Put256KBytes(buf)
w := binary.NewWriter()
defer binary.PutWriter(w)
for {
chunk = chunk[:chunkSize]
rl, err := io.ReadFull(stream, chunk)
if errors.Is(err, io.EOF) {
break
}
if errors.Is(err, io.ErrUnexpectedEOF) {
chunk = chunk[:rl]
}
ch := md5.Sum(chunk)
head, _ := proto.Marshal(&pb.ReqDataHighwayHead{
MsgBasehead: &pb.DataHighwayHead{
Version: 1,
Uin: strconv.FormatInt(c.Uin, 10),
Command: "PicUp.DataUp",
Seq: c.nextGroupDataTransSeq(),
Appid: int32(c.version.AppId),
Dataflag: 4096,
CommandId: cmdId,
LocaleId: 2052,
},
MsgSeghead: &pb.SegHead{
Filesize: length,
Dataoffset: int64(offset),
Datalength: int32(rl),
Serviceticket: updKey,
Md5: ch[:],
FileMd5: fh,
},
ReqExtendinfo: EmptyBytes,
})
offset += rl
w.Reset()
w.WriteByte(40)
w.WriteUInt32(uint32(len(head)))
w.WriteUInt32(uint32(len(chunk)))
w.Write(head)
w.Write(chunk)
w.WriteByte(41)
_, err = conn.Write(w.Bytes())
if err != nil {
return errors.Wrap(err, "write conn error")
}
rspHead, _, err := highwayReadResponse(reader)
if err != nil {
return errors.Wrap(err, "highway upload error")
}
if rspHead.ErrorCode != 0 {
return errors.New("upload failed")
}
}
return nil
}
func (c *QQClient) highwayUploadByBDH(stream io.Reader, length int64, cmdId int32, ticket, sum, ext []byte, encrypt bool) ([]byte, error) {
if len(c.srvSsoAddrs) == 0 {
return nil, errors.New("srv addrs not found. maybe miss some packet?")
}
if encrypt {
if c.bigDataSession == nil || len(c.bigDataSession.SessionKey) == 0 {
return nil, errors.New("session key not found. maybe miss some packet?")
}
ext = binary.NewTeaCipher(c.bigDataSession.SessionKey).Encrypt(ext)
}
const chunkSize = 256 * 1024
conn, err := net.DialTimeout("tcp", c.srvSsoAddrs[0], time.Second*20)
if err != nil {
return nil, errors.Wrap(err, "connect error")
}
defer conn.Close()
offset := 0
reader := binary.NewNetworkReader(conn)
if err = c.highwaySendHeartbreak(conn); err != nil {
return nil, errors.Wrap(err, "echo error")
}
if _, _, err = highwayReadResponse(reader); err != nil {
return nil, errors.Wrap(err, "echo error")
}
var rspExt []byte
buf := binary.Get256KBytes()
chunk := *buf
defer binary.Put256KBytes(buf)
w := binary.NewWriter()
defer binary.PutWriter(w)
for {
chunk = chunk[:chunkSize]
rl, err := io.ReadFull(stream, chunk)
if errors.Is(err, io.EOF) {
break
}
if errors.Is(err, io.ErrUnexpectedEOF) {
chunk = chunk[:rl]
}
ch := md5.Sum(chunk)
head, _ := proto.Marshal(&pb.ReqDataHighwayHead{
MsgBasehead: &pb.DataHighwayHead{
Version: 1,
Uin: strconv.FormatInt(c.Uin, 10),
Command: "PicUp.DataUp",
Seq: c.nextGroupDataTransSeq(),
Appid: int32(c.version.AppId),
Dataflag: 4096,
CommandId: cmdId,
LocaleId: 2052,
},
MsgSeghead: &pb.SegHead{
Filesize: length,
Dataoffset: int64(offset),
Datalength: int32(rl),
Serviceticket: ticket,
Md5: ch[:],
FileMd5: sum,
},
ReqExtendinfo: ext,
})
offset += rl
w.Reset()
w.WriteByte(40)
w.WriteUInt32(uint32(len(head)))
w.WriteUInt32(uint32(len(chunk)))
w.Write(head)
w.Write(chunk)
w.WriteByte(41)
_, err = conn.Write(w.Bytes())
if err != nil {
return nil, errors.Wrap(err, "write conn error")
}
rspHead, _, err := highwayReadResponse(reader)
if err != nil {
return nil, errors.Wrap(err, "highway upload error")
}
if rspHead.ErrorCode != 0 {
return nil, errors.Errorf("upload failed: %d", rspHead.ErrorCode)
}
if rspHead.RspExtendinfo != nil {
rspExt = rspHead.RspExtendinfo
}
if rspHead.MsgSeghead != nil && rspHead.MsgSeghead.Serviceticket != nil {
ticket = rspHead.MsgSeghead.Serviceticket
}
}
return rspExt, nil
}
func (c *QQClient) highwayUploadFileMultiThreadingByBDH(path string, cmdId int32, threadCount int, ticket, ext []byte, encrypt bool) ([]byte, error) {
if len(c.srvSsoAddrs) == 0 {
return nil, errors.New("srv addrs not found. maybe miss some packet?")
}
if encrypt {
if c.bigDataSession == nil || len(c.bigDataSession.SessionKey) == 0 {
return nil, errors.New("session key not found. maybe miss some packet?")
}
ext = binary.NewTeaCipher(c.bigDataSession.SessionKey).Encrypt(ext)
}
stat, err := os.Stat(path)
if err != nil {
return nil, errors.Wrap(err, "get stat error")
}
file, err := os.OpenFile(path, os.O_RDONLY, 0o666)
if err != nil {
return nil, errors.Wrap(err, "open file error")
}
defer file.Close()
h := md5.New()
length, _ := io.Copy(h, file)
fh := h.Sum(nil)
_, _ = file.Seek(0, io.SeekStart)
if stat.Size() < 1024*1024*3 || threadCount < 2 {
return c.highwayUploadByBDH(file, length, cmdId, ticket, fh, ext, false)
}
type BlockMetaData struct {
Id int
BeginOffset int64
EndOffset int64
}
const blockSize int64 = 1024 * 512
var (
blocks []*BlockMetaData
rspExt []byte
BlockId = ^uint32(0) // -1
uploadedCount uint32
cond = sync.NewCond(&sync.Mutex{})
)
// Init Blocks
{
var temp int64 = 0
for temp+blockSize < stat.Size() {
blocks = append(blocks, &BlockMetaData{
Id: len(blocks),
BeginOffset: temp,
EndOffset: temp + blockSize,
})
temp += blockSize
}
blocks = append(blocks, &BlockMetaData{
Id: len(blocks),
BeginOffset: temp,
EndOffset: stat.Size(),
})
}
doUpload := func() error {
defer cond.Signal()
conn, err := net.DialTimeout("tcp", c.srvSsoAddrs[0], time.Second*20)
if err != nil {
return errors.Wrap(err, "connect error")
}
defer conn.Close()
chunk, _ := os.OpenFile(path, os.O_RDONLY, 0o666)
defer chunk.Close()
reader := binary.NewNetworkReader(conn)
if err = c.highwaySendHeartbreak(conn); err != nil {
return errors.Wrap(err, "echo error")
}
if _, _, err = highwayReadResponse(reader); err != nil {
return errors.Wrap(err, "echo error")
}
buffer := make([]byte, blockSize)
w := binary.NewWriter()
w.Reset()
w.Grow(600 * 1024) // 复用,600k 不要放回池中
for {
nextId := atomic.AddUint32(&BlockId, 1)
if nextId >= uint32(len(blocks)) {
break
}
block := blocks[nextId]
if block.Id == len(blocks)-1 {
cond.L.Lock()
for atomic.LoadUint32(&uploadedCount) != uint32(len(blocks))-1 {
cond.Wait()
}
cond.L.Unlock()
}
buffer = buffer[:blockSize]
_, _ = chunk.Seek(block.BeginOffset, io.SeekStart)
ri, err := io.ReadFull(chunk, buffer)
if err != nil {
if err == io.EOF {
break
}
if err == io.ErrUnexpectedEOF {
buffer = buffer[:ri]
} else {
return err
}
}
ch := md5.Sum(buffer)
head, _ := proto.Marshal(&pb.ReqDataHighwayHead{
MsgBasehead: &pb.DataHighwayHead{
Version: 1,
Uin: strconv.FormatInt(c.Uin, 10),
Command: "PicUp.DataUp",
Seq: c.nextGroupDataTransSeq(),
Appid: int32(c.version.AppId),
Dataflag: 4096,
CommandId: cmdId,
LocaleId: 2052,
},
MsgSeghead: &pb.SegHead{
Filesize: stat.Size(),
Dataoffset: block.BeginOffset,
Datalength: int32(ri),
Serviceticket: ticket,
Md5: ch[:],
FileMd5: fh,
},
ReqExtendinfo: ext,
})
w.Reset()
w.WriteByte(40)
w.WriteUInt32(uint32(len(head)))
w.WriteUInt32(uint32(len(buffer)))
w.Write(head)
w.Write(buffer)
w.WriteByte(41)
_, err = conn.Write(w.Bytes())
if err != nil {
return errors.Wrap(err, "write conn error")
}
rspHead, _, err := highwayReadResponse(reader)
if err != nil {
return errors.Wrap(err, "highway upload error")
}
if rspHead.ErrorCode != 0 {
return errors.Errorf("upload failed: %d", rspHead.ErrorCode)
}
if rspHead.RspExtendinfo != nil {
rspExt = rspHead.RspExtendinfo
}
atomic.AddUint32(&uploadedCount, 1)
}
return nil
}
group := errgroup.Group{}
for i := 0; i < threadCount; i++ {
group.Go(doUpload)
}
err = group.Wait()
return rspExt, err
}
func (c *QQClient) highwaySendHeartbreak(conn net.Conn) error {
head, _ := proto.Marshal(&pb.ReqDataHighwayHead{
MsgBasehead: &pb.DataHighwayHead{
Version: 1,
Uin: strconv.FormatInt(c.Uin, 10),
Command: "PicUp.Echo",
Seq: c.nextGroupDataTransSeq(),
Appid: int32(c.version.AppId),
Dataflag: 4096,
CommandId: 0,
LocaleId: 2052,
},
})
w := binary.NewWriter()
w.WriteByte(40)
w.WriteUInt32(uint32(len(head)))
w.WriteUInt32(0)
w.Write(head)
w.WriteByte(41)
_, err := conn.Write(w.Bytes())
binary.PutWriter(w)
return err
}
func highwayReadResponse(r *binary.NetworkReader) (*pb.RspDataHighwayHead, []byte, error) {
_, err := r.ReadByte()
if err != nil {
return nil, nil, errors.Wrap(err, "failed to read byte")
}
hl, _ := r.ReadInt32()
a2, _ := r.ReadInt32()
head, _ := r.ReadBytes(int(hl))
payload, _ := r.ReadBytes(int(a2))
_, _ = r.ReadByte()
rsp := new(pb.RspDataHighwayHead)
if err = proto.Unmarshal(head, rsp); err != nil {
return nil, nil, errors.Wrap(err, "failed to unmarshal protobuf message")
}
return rsp, payload, nil
}
func (c *QQClient) excitingUploadStream(stream io.ReadSeeker, cmdId int32, ticket, ext []byte) ([]byte, error) {
fileMd5, fileLength := utils.ComputeMd5AndLength(stream)
_, _ = stream.Seek(0, io.SeekStart)
url := fmt.Sprintf("http://%v/cgi-bin/httpconn?htcmd=0x6FF0087&uin=%v", c.srvSsoAddrs[0], c.Uin)
var (
rspExt []byte
offset int64 = 0
chunkSize = 524288
)
chunk := make([]byte, chunkSize)
w := binary.NewWriter()
w.Reset()
w.Grow(600 * 1024) // 复用,600k 不要放回池中
for {
chunk = chunk[:chunkSize]
rl, err := io.ReadFull(stream, chunk)
if err == io.EOF {
break
}
if err == io.ErrUnexpectedEOF {
chunk = chunk[:rl]
}
ch := md5.Sum(chunk)
head, _ := proto.Marshal(&pb.ReqDataHighwayHead{
MsgBasehead: &pb.DataHighwayHead{
Version: 1,
Uin: strconv.FormatInt(c.Uin, 10),
Command: "PicUp.DataUp",
Seq: c.nextGroupDataTransSeq(),
Appid: int32(c.version.AppId),
Dataflag: 0,
CommandId: cmdId,
LocaleId: 0,
},
MsgSeghead: &pb.SegHead{
Filesize: fileLength,
Dataoffset: offset,
Datalength: int32(rl),
Serviceticket: ticket,
Md5: ch[:],
FileMd5: fileMd5,
},
ReqExtendinfo: ext,
})
offset += int64(rl)
w.Reset()
w.WriteByte(40)
w.WriteUInt32(uint32(len(head)))
w.WriteUInt32(uint32(len(chunk)))
w.Write(head)
w.Write(chunk)
w.WriteByte(41)
req, _ := http.NewRequest("POST", url, bytes.NewReader(w.Bytes()))
req.Header.Set("Accept", "*/*")
req.Header.Set("Connection", "Keep-Alive")
req.Header.Set("User-Agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)")
req.Header.Set("Pragma", "no-cache")
rsp, err := http.DefaultClient.Do(req)
if err != nil {
return nil, errors.Wrap(err, "request error")
}
body, _ := io.ReadAll(rsp.Body)
_ = rsp.Body.Close()
r := binary.NewReader(body)
r.ReadByte()
hl := r.ReadInt32()
a2 := r.ReadInt32()
h := r.ReadBytes(int(hl))
r.ReadBytes(int(a2))
rspHead := new(pb.RspDataHighwayHead)
if err = proto.Unmarshal(h, rspHead); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
}
if rspHead.ErrorCode != 0 {
return nil, errors.Errorf("upload failed: %d", rspHead.ErrorCode)
}
if rspHead.RspExtendinfo != nil {
rspExt = rspHead.RspExtendinfo
}
}
return rspExt, nil
}
func (c *QQClient) uploadGroupHeadPortrait(groupCode int64, img []byte) error {
url := fmt.Sprintf(
"http://htdata3.qq.com/cgi-bin/httpconn?htcmd=0x6ff0072&ver=5520&ukey=%v&range=0&uin=%v&seq=23&groupuin=%v&filetype=3&imagetype=5&userdata=0&subcmd=1&subver=101&clip=0_0_0_0&filesize=%v",
c.getSKey(),
c.Uin,
groupCode,
len(img),
)
req, _ := http.NewRequest("POST", url, bytes.NewReader(img))
req.Header["User-Agent"] = []string{"Dalvik/2.1.0 (Linux; U; Android 7.1.2; PCRT00 Build/N2G48H)"}
req.Header["Content-Type"] = []string{"multipart/form-data;boundary=****"}
rsp, err := http.DefaultClient.Do(req)
if err != nil {
return errors.Wrap(err, "failed to upload group head portrait")
}
rsp.Body.Close()
return nil
}

View File

@ -5,21 +5,67 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"html" "html"
"io"
"mime/multipart" "mime/multipart"
"net/http" "net/http"
"net/textproto" "net/textproto"
"net/url" "net/url"
"regexp"
"strconv" "strconv"
"strings"
"github.com/pkg/errors" "github.com/pkg/errors"
"google.golang.org/protobuf/proto"
"github.com/Mrs4s/MiraiGo/binary" "github.com/Mrs4s/MiraiGo/binary"
"github.com/Mrs4s/MiraiGo/client/pb/richmedia" "github.com/Mrs4s/MiraiGo/client/pb/richmedia"
"github.com/Mrs4s/MiraiGo/internal/proto"
"github.com/Mrs4s/MiraiGo/utils" "github.com/Mrs4s/MiraiGo/utils"
) )
/* -------- VipInfo -------- */
type VipInfo struct {
Uin int64
Name string
Level int
LevelSpeed float64
VipLevel string
VipGrowthSpeed int
VipGrowthTotal int
}
func (c *QQClient) GetVipInfo(target int64) (*VipInfo, error) {
b, err := utils.HttpGetBytes(fmt.Sprintf("https://h5.vip.qq.com/p/mc/cardv2/other?platform=1&qq=%d&adtag=geren&aid=mvip.pingtai.mobileqq.androidziliaoka.fromqita", target), c.getCookiesWithDomain("h5.vip.qq.com"))
if err != nil {
return nil, err
}
ret := VipInfo{Uin: target}
b = b[bytes.Index(b, []byte(`<span class="ui-nowrap">`))+24:]
t := b[:bytes.Index(b, []byte(`</span>`))]
ret.Name = string(t)
b = b[bytes.Index(b, []byte(`<small>LV</small>`))+17:]
t = b[:bytes.Index(b, []byte(`</p>`))]
ret.Level, _ = strconv.Atoi(string(t))
b = b[bytes.Index(b, []byte(`<div class="pk-line pk-line-guest">`))+35:]
b = b[bytes.Index(b, []byte(`<p>`))+3:]
t = b[:bytes.Index(b, []byte(`<small>倍`))]
ret.LevelSpeed, _ = strconv.ParseFloat(string(t), 64)
b = b[bytes.Index(b, []byte(`<div class="pk-line pk-line-guest">`))+35:]
b = b[bytes.Index(b, []byte(`<p>`))+3:]
st := string(b[:bytes.Index(b, []byte(`</p>`))])
st = strings.Replace(st, "<small>", "", 1)
st = strings.Replace(st, "</small>", "", 1)
ret.VipLevel = st
b = b[bytes.Index(b, []byte(`<div class="pk-line pk-line-guest">`))+35:]
b = b[bytes.Index(b, []byte(`<p>`))+3:]
t = b[:bytes.Index(b, []byte(`</p>`))]
ret.VipGrowthSpeed, _ = strconv.Atoi(string(t))
b = b[bytes.Index(b, []byte(`<div class="pk-line pk-line-guest">`))+35:]
b = b[bytes.Index(b, []byte(`<p>`))+3:]
t = b[:bytes.Index(b, []byte(`</p>`))]
ret.VipGrowthTotal, _ = strconv.Atoi(string(t))
return &ret, nil
}
/* -------- GroupHonorInfo -------- */ /* -------- GroupHonorInfo -------- */
type ( type (
@ -60,20 +106,15 @@ const (
Emotion HonorType = 6 // 快乐源泉 Emotion HonorType = 6 // 快乐源泉
) )
// 匹配 window.__INITIAL_STATE__ = 后的内容
var honorRe = regexp.MustCompile(`window\.__INITIAL_STATE__\s*?=\s*?(\{.*\})`)
func (c *QQClient) GetGroupHonorInfo(groupCode int64, honorType HonorType) (*GroupHonorInfo, error) { func (c *QQClient) GetGroupHonorInfo(groupCode int64, honorType HonorType) (*GroupHonorInfo, error) {
b, err := utils.HttpGetBytes(fmt.Sprintf("https://qun.qq.com/interactive/honorlist?gc=%d&type=%d", groupCode, honorType), c.getCookiesWithDomain("qun.qq.com")) b, err := utils.HttpGetBytes(fmt.Sprintf("https://qun.qq.com/interactive/honorlist?gc=%d&type=%d", groupCode, honorType), c.getCookiesWithDomain("qun.qq.com"))
if err != nil { if err != nil {
return nil, err return nil, err
} }
matched := honorRe.FindSubmatch(b) b = b[bytes.Index(b, []byte(`window.__INITIAL_STATE__=`))+25:]
if len(matched) == 0 { b = b[:bytes.Index(b, []byte("</script>"))]
return nil, errors.New("无匹配结果")
}
ret := GroupHonorInfo{} ret := GroupHonorInfo{}
err = json.NewDecoder(bytes.NewReader(matched[1])).Decode(&ret) err = json.Unmarshal(b, &ret)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -83,14 +124,15 @@ func (c *QQClient) GetGroupHonorInfo(groupCode int64, honorType HonorType) (*Gro
/* -------- TextToSpeech -------- */ /* -------- TextToSpeech -------- */
func (c *QQClient) GetTts(text string) ([]byte, error) { func (c *QQClient) GetTts(text string) ([]byte, error) {
apiUrl := "https://textts.qq.com/cgi-bin/tts" url := "https://textts.qq.com/cgi-bin/tts"
data := fmt.Sprintf(`{"appid": "201908021016","sendUin": %v,"text": %q}`, c.Uin, text) bt, _ := json.Marshal(text)
rsp, err := utils.HttpPostBytesWithCookie(apiUrl, []byte(data), c.getCookies()) data := fmt.Sprintf(`{"appid": "201908021016","sendUin": %v,"text": %s}`, c.Uin, bt)
rsp, err := utils.HttpPostBytesWithCookie(url, []byte(data), c.getCookies())
if err != nil { if err != nil {
return nil, errors.Wrap(err, "failed to post to tts server") return nil, errors.Wrap(err, "failed to post to tts server")
} }
ttsReader := binary.NewReader(rsp) ttsReader := binary.NewReader(rsp)
ttsWriter := binary.SelectWriter() ttsWriter := binary.NewWriter()
for { for {
// 数据格式 69e(字符串) 十六进制 数据长度 0 为结尾 // 数据格式 69e(字符串) 十六进制 数据长度 0 为结尾
// 0D 0A (分隔符) payload 0D 0A // 0D 0A (分隔符) payload 0D 0A
@ -124,37 +166,6 @@ func (c *QQClient) GetTts(text string) ([]byte, error) {
/* -------- GroupNotice -------- */ /* -------- GroupNotice -------- */
type groupNoticeRsp struct {
Feeds []*GroupNoticeFeed `json:"feeds"`
Inst []*GroupNoticeFeed `json:"inst"`
}
type GroupNoticeFeed struct {
NoticeId string `json:"fid"`
SenderId uint32 `json:"u"`
PublishTime uint64 `json:"pubt"`
Message struct {
Text string `json:"text"`
Images []noticeImage `json:"pics"`
} `json:"msg"`
}
type GroupNoticeMessage struct {
NoticeId string `json:"notice_id"`
SenderId uint32 `json:"sender_id"`
PublishTime uint64 `json:"publish_time"`
Message struct {
Text string `json:"text"`
Images []GroupNoticeImage `json:"images"`
} `json:"message"`
}
type GroupNoticeImage struct {
Height string `json:"height"`
Width string `json:"width"`
ID string `json:"id"`
}
type noticePicUpResponse struct { type noticePicUpResponse struct {
ErrorCode int `json:"ec"` ErrorCode int `json:"ec"`
ErrorMessage string `json:"em"` ErrorMessage string `json:"em"`
@ -167,87 +178,37 @@ type noticeImage struct {
ID string `json:"id"` ID string `json:"id"`
} }
type noticeSendResp struct {
NoticeId string `json:"new_fid"`
}
func (c *QQClient) GetGroupNotice(groupCode int64) (l []*GroupNoticeMessage, err error) {
v := url.Values{}
v.Set("bkn", strconv.Itoa(c.getCSRFToken()))
v.Set("qid", strconv.FormatInt(groupCode, 10))
v.Set("ft", "23")
v.Set("ni", "1")
v.Set("n", "1")
v.Set("i", "1")
v.Set("log_read", "1")
v.Set("platform", "1")
v.Set("s", "-1")
v.Set("n", "20")
req, _ := http.NewRequest(http.MethodGet, "https://web.qun.qq.com/cgi-bin/announce/get_t_list?"+v.Encode(), nil)
req.Header.Set("Cookie", c.getCookies())
rsp, err := utils.Client.Do(req)
if err != nil {
return
}
defer rsp.Body.Close()
r := groupNoticeRsp{}
err = json.NewDecoder(rsp.Body).Decode(&r)
if err != nil {
return
}
return c.parseGroupNoticeJson(&r), nil
}
func (c *QQClient) parseGroupNoticeJson(s *groupNoticeRsp) []*GroupNoticeMessage {
o := make([]*GroupNoticeMessage, 0, len(s.Feeds)+len(s.Inst))
parse := func(v *GroupNoticeFeed) {
ims := make([]GroupNoticeImage, 0, len(v.Message.Images))
for i := 0; i < len(v.Message.Images); i++ {
ims = append(ims, GroupNoticeImage{
Height: v.Message.Images[i].Height,
Width: v.Message.Images[i].Width,
ID: v.Message.Images[i].ID,
})
}
o = append(o, &GroupNoticeMessage{
NoticeId: v.NoticeId,
SenderId: v.SenderId,
PublishTime: v.PublishTime,
Message: struct {
Text string `json:"text"`
Images []GroupNoticeImage `json:"images"`
}{
Text: v.Message.Text,
Images: ims,
},
})
}
for _, v := range s.Feeds {
parse(v)
}
for _, v := range s.Inst {
parse(v)
}
return o
}
func (c *QQClient) uploadGroupNoticePic(img []byte) (*noticeImage, error) { func (c *QQClient) uploadGroupNoticePic(img []byte) (*noticeImage, error) {
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
w := multipart.NewWriter(buf) w := multipart.NewWriter(buf)
_ = w.WriteField("bkn", strconv.Itoa(c.getCSRFToken())) err := w.WriteField("bkn", strconv.Itoa(c.getCSRFToken()))
_ = w.WriteField("source", "troopNotice") if err != nil {
_ = w.WriteField("m", "0") return nil, errors.Wrap(err, "write multipart<bkn> failed")
}
err = w.WriteField("source", "troopNotice")
if err != nil {
return nil, errors.Wrap(err, "write multipart<source> failed")
}
err = w.WriteField("m", "0")
if err != nil {
return nil, errors.Wrap(err, "write multipart<m> failed")
}
h := make(textproto.MIMEHeader) h := make(textproto.MIMEHeader)
h.Set("Content-Disposition", `form-data; name="pic_up"; filename="temp_uploadFile.png"`) h.Set("Content-Disposition", `form-data; name="pic_up"; filename="temp_uploadFile.png"`)
h.Set("Content-Type", "image/png") h.Set("Content-Type", "image/png")
fw, _ := w.CreatePart(h) fw, err := w.CreatePart(h)
_, _ = fw.Write(img) if err != nil {
_ = w.Close() return nil, errors.Wrap(err, "create multipart field<pic_up> failed")
req, err := http.NewRequest(http.MethodPost, "https://web.qun.qq.com/cgi-bin/announce/upload_img", buf) }
_, err = fw.Write(img)
if err != nil {
return nil, errors.Wrap(err, "write multipart<pic_up> failed")
}
err = w.Close()
if err != nil {
return nil, errors.Wrap(err, "close multipart failed")
}
req, err := http.NewRequest("POST", "https://web.qun.qq.com/cgi-bin/announce/upload_img", buf)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "new request error") return nil, errors.Wrap(err, "new request error")
} }
@ -258,8 +219,12 @@ func (c *QQClient) uploadGroupNoticePic(img []byte) (*noticeImage, error) {
return nil, errors.Wrap(err, "post error") return nil, errors.Wrap(err, "post error")
} }
defer resp.Body.Close() defer resp.Body.Close()
var res noticePicUpResponse body, err := io.ReadAll(resp.Body)
err = json.NewDecoder(resp.Body).Decode(&res) if err != nil {
return nil, errors.Wrap(err, "read body error")
}
res := noticePicUpResponse{}
err = json.Unmarshal(body, &res)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "failed to unmarshal json") return nil, errors.Wrap(err, "failed to unmarshal json")
} }
@ -275,42 +240,23 @@ func (c *QQClient) uploadGroupNoticePic(img []byte) (*noticeImage, error) {
} }
// AddGroupNoticeSimple 发群公告 // AddGroupNoticeSimple 发群公告
func (c *QQClient) AddGroupNoticeSimple(groupCode int64, text string) (noticeId string, err error) { func (c *QQClient) AddGroupNoticeSimple(groupCode int64, text string) error {
body := fmt.Sprintf(`qid=%v&bkn=%v&text=%v&pinned=0&type=1&settings={"is_show_edit_card":0,"tip_window_type":1,"confirm_required":1}`, groupCode, c.getCSRFToken(), url.QueryEscape(text)) body := fmt.Sprintf(`qid=%v&bkn=%v&text=%v&pinned=0&type=1&settings={"is_show_edit_card":0,"tip_window_type":1,"confirm_required":1}`, groupCode, c.getCSRFToken(), url.QueryEscape(text))
resp, err := utils.HttpPostBytesWithCookie("https://web.qun.qq.com/cgi-bin/announce/add_qun_notice?bkn="+fmt.Sprint(c.getCSRFToken()), []byte(body), c.getCookiesWithDomain("qun.qq.com")) _, err := utils.HttpPostBytesWithCookie("https://web.qun.qq.com/cgi-bin/announce/add_qun_notice?bkn="+fmt.Sprint(c.getCSRFToken()), []byte(body), c.getCookiesWithDomain("qun.qq.com"))
if err != nil { if err != nil {
return "", errors.Wrap(err, "request error") return errors.Wrap(err, "request error")
} }
var res noticeSendResp return nil
err = json.Unmarshal(resp, &res) }
if err != nil {
return "", errors.Wrap(err, "json unmarshal error") // AddGroupNoticeWithPic 发群公告带图片
} func (c *QQClient) AddGroupNoticeWithPic(groupCode int64, text string, pic []byte) error {
return res.NoticeId, nil img, err := c.uploadGroupNoticePic(pic)
} if err != nil {
return err
// AddGroupNoticeWithPic 发群公告带图片 }
func (c *QQClient) AddGroupNoticeWithPic(groupCode int64, text string, pic []byte) (noticeId string, err error) { body := fmt.Sprintf(`qid=%v&bkn=%v&text=%v&pinned=0&type=1&settings={"is_show_edit_card":0,"tip_window_type":1,"confirm_required":1}&pic=%v&imgWidth=%v&imgHeight=%v`, groupCode, c.getCSRFToken(), url.QueryEscape(text), img.ID, img.Width, img.Height)
img, err := c.uploadGroupNoticePic(pic) _, err = utils.HttpPostBytesWithCookie("https://web.qun.qq.com/cgi-bin/announce/add_qun_notice?bkn="+fmt.Sprint(c.getCSRFToken()), []byte(body), c.getCookiesWithDomain("qun.qq.com"))
if err != nil {
return "", err
}
body := fmt.Sprintf(`qid=%v&bkn=%v&text=%v&pinned=0&type=1&settings={"is_show_edit_card":0,"tip_window_type":1,"confirm_required":1}&pic=%v&imgWidth=%v&imgHeight=%v`, groupCode, c.getCSRFToken(), url.QueryEscape(text), img.ID, img.Width, img.Height)
resp, err := utils.HttpPostBytesWithCookie("https://web.qun.qq.com/cgi-bin/announce/add_qun_notice?bkn="+fmt.Sprint(c.getCSRFToken()), []byte(body), c.getCookiesWithDomain("qun.qq.com"))
if err != nil {
return "", errors.Wrap(err, "request error")
}
var res noticeSendResp
err = json.Unmarshal(resp, &res)
if err != nil {
return "", errors.Wrap(err, "json unmarshal error")
}
return res.NoticeId, nil
}
func (c *QQClient) DelGroupNotice(groupCode int64, fid string) error {
body := fmt.Sprintf(`fid=%s&qid=%v&bkn=%v&ft=23&op=1`, fid, groupCode, c.getCSRFToken())
_, err := utils.HttpPostBytesWithCookie("https://web.qun.qq.com/cgi-bin/announce/del_feed", []byte(body), c.getCookiesWithDomain("qun.qq.com"))
if err != nil { if err != nil {
return errors.Wrap(err, "request error") return errors.Wrap(err, "request error")
} }

View File

@ -1,22 +1,27 @@
package client package client
import ( import (
"crypto/rand" "bytes"
"encoding/hex"
"fmt" "fmt"
"image"
_ "image/gif"
"io" "io"
"math/rand"
"os"
"strings" "strings"
"time" "time"
"github.com/fumiama/imgsz"
"github.com/pkg/errors" "github.com/pkg/errors"
protobuf "github.com/segmentio/encoding/proto"
"google.golang.org/protobuf/proto"
"github.com/Mrs4s/MiraiGo/binary" "github.com/Mrs4s/MiraiGo/binary"
"github.com/Mrs4s/MiraiGo/client/internal/highway"
"github.com/Mrs4s/MiraiGo/client/internal/network"
"github.com/Mrs4s/MiraiGo/client/pb/cmd0x388" "github.com/Mrs4s/MiraiGo/client/pb/cmd0x388"
highway2 "github.com/Mrs4s/MiraiGo/client/pb/highway" "github.com/Mrs4s/MiraiGo/client/pb/highway"
"github.com/Mrs4s/MiraiGo/client/pb/oidb" "github.com/Mrs4s/MiraiGo/internal/packets"
"github.com/Mrs4s/MiraiGo/internal/proto" "github.com/Mrs4s/MiraiGo/internal/protobuf/data/oidb"
"github.com/Mrs4s/MiraiGo/internal/protobuf/data/oidb/oidb0xe07"
"github.com/Mrs4s/MiraiGo/message" "github.com/Mrs4s/MiraiGo/message"
"github.com/Mrs4s/MiraiGo/utils" "github.com/Mrs4s/MiraiGo/utils"
) )
@ -29,61 +34,17 @@ func init() {
var imgWaiter = utils.NewUploadWaiter() var imgWaiter = utils.NewUploadWaiter()
type imageUploadResponse struct { func (c *QQClient) UploadGroupImage(groupCode int64, img io.ReadSeeker) (*message.GroupImageElement, error) {
UploadKey []byte
UploadIp []uint32
UploadPort []uint32
Width int32
Height int32
Message string
DownloadIndex string
ResourceId string
FileId int64
ResultCode int32
IsExists bool
}
func (c *QQClient) UploadImage(target message.Source, img io.ReadSeeker) (message.IMessageElement, error) {
switch target.SourceType {
case message.SourceGroup, message.SourceGuildChannel, message.SourceGuildDirect:
return c.uploadGroupOrGuildImage(target, img)
case message.SourcePrivate:
return c.uploadPrivateImage(target.PrimaryID, img, 0)
default:
return nil, errors.New("unsupported target type")
}
}
func (c *QQClient) uploadGroupOrGuildImage(target message.Source, img io.ReadSeeker) (message.IMessageElement, error) {
_, _ = img.Seek(0, io.SeekStart) // safe _, _ = img.Seek(0, io.SeekStart) // safe
fh, length := utils.ComputeMd5AndLength(img) fh, length := utils.ComputeMd5AndLength(img)
_, _ = img.Seek(0, io.SeekStart) _, _ = img.Seek(0, io.SeekStart)
key := string(fh) key := hex.EncodeToString(fh)
imgWaiter.Wait(key) imgWaiter.Wait(key)
defer imgWaiter.Done(key) defer imgWaiter.Done(key)
cmd := int32(2) seq, pkt := c.buildGroupImageStorePacket(groupCode, fh, int32(length))
ext := EmptyBytes r, err := c.sendAndWait(seq, pkt)
if target.SourceType != message.SourceGroup { // guild
cmd = 83
ext = proto.DynamicMessage{
11: target.PrimaryID,
12: target.SecondaryID,
}.Encode()
}
var r any
var err error
var input highway.Transaction
switch target.SourceType {
case message.SourceGroup:
r, err = c.sendAndWait(c.buildGroupImageStorePacket(target.PrimaryID, fh, int32(length)))
case message.SourceGuildChannel, message.SourceGuildDirect:
r, err = c.sendAndWait(c.buildGuildImageStorePacket(uint64(target.PrimaryID), uint64(target.SecondaryID), fh, uint64(length)))
default:
return nil, errors.Errorf("unsupported target type %v", target.SourceType)
}
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -94,55 +55,76 @@ func (c *QQClient) uploadGroupOrGuildImage(target message.Source, img io.ReadSee
if rsp.IsExists { if rsp.IsExists {
goto ok goto ok
} }
if c.highwaySession.AddrLength() == 0 { if len(c.srvSsoAddrs) == 0 {
for i, addr := range rsp.UploadIp { for i, addr := range rsp.UploadIp {
c.highwaySession.AppendAddr(addr, rsp.UploadPort[i]) c.srvSsoAddrs = append(c.srvSsoAddrs, fmt.Sprintf("%v:%v", binary.UInt32ToIPV4Address(addr), rsp.UploadPort[i]))
} }
} }
if _, err = c.highwayUploadByBDH(img, length, 2, rsp.UploadKey, fh, EmptyBytes, false); err == nil {
input = highway.Transaction{ goto ok
CommandID: cmd,
Body: img,
Size: length,
Sum: fh,
Ticket: rsp.UploadKey,
Ext: ext,
}
_, err = c.highwaySession.Upload(input)
if err != nil {
return nil, errors.Wrap(err, "upload failed")
} }
return nil, errors.Wrap(err, "upload failed")
ok: ok:
_, _ = img.Seek(0, io.SeekStart) _, _ = img.Seek(0, io.SeekStart)
i, t, _ := imgsz.DecodeSize(img) i, _, _ := image.DecodeConfig(img)
var imageType int32 = 1000 var imageType int32 = 1000
if t == "gif" { _, _ = img.Seek(0, io.SeekStart)
tmp := make([]byte, 4)
_, _ = img.Read(tmp)
if bytes.Equal(tmp, []byte{0x47, 0x49, 0x46, 0x38}) {
imageType = 2000 imageType = 2000
} }
width := int32(i.Width) return message.NewGroupImage(binary.CalculateImageResourceId(fh), fh, rsp.FileId, int32(length), int32(i.Width), int32(i.Height), imageType), nil
height := int32(i.Height) }
if err != nil && target.SourceType != message.SourceGroup {
c.warning("warning: decode image error: %v. this image will be displayed by wrong size in pc guild client", err) func (c *QQClient) UploadGroupImageByFile(groupCode int64, path string) (*message.GroupImageElement, error) {
width = 200 img, err := os.OpenFile(path, os.O_RDONLY, 0o666)
height = 200 if err != nil {
return nil, err
} }
if target.SourceType == message.SourceGroup { defer func() { _ = img.Close() }()
return message.NewGroupImage( fh, length := utils.ComputeMd5AndLength(img)
binary.CalculateImageResourceId(fh),
fh, rsp.FileId, int32(length), key := hex.EncodeToString(fh)
int32(i.Width), int32(i.Height), imageType, imgWaiter.Wait(key)
), nil defer imgWaiter.Done(key)
seq, pkt := c.buildGroupImageStorePacket(groupCode, fh, int32(length))
r, err := c.sendAndWait(seq, pkt)
if err != nil {
return nil, err
} }
return &message.GuildImageElement{ rsp := r.(*imageUploadResponse)
FileId: rsp.FileId, if rsp.ResultCode != 0 {
FilePath: fmt.Sprintf("%x.jpg", fh), return nil, errors.New(rsp.Message)
Size: int32(length), }
DownloadIndex: rsp.DownloadIndex, if rsp.IsExists {
Width: width, goto ok
Height: height, }
ImageType: imageType, if len(c.srvSsoAddrs) == 0 {
Md5: fh, for i, addr := range rsp.UploadIp {
}, nil c.srvSsoAddrs = append(c.srvSsoAddrs, fmt.Sprintf("%v:%v", binary.UInt32ToIPV4Address(addr), rsp.UploadPort[i]))
}
}
if _, err = c.highwayUploadFileMultiThreadingByBDH(path, 2, 1, rsp.UploadKey, EmptyBytes, false); err == nil {
goto ok
}
return nil, errors.Wrap(err, "upload failed")
ok:
_, _ = img.Seek(0, io.SeekStart)
i, _, _ := image.DecodeConfig(img)
var imageType int32 = 1000
_, _ = img.Seek(0, io.SeekStart)
tmp := make([]byte, 4)
_, _ = img.Read(tmp)
if bytes.Equal(tmp, []byte{0x47, 0x49, 0x46, 0x38}) {
imageType = 2000
}
return message.NewGroupImage(binary.CalculateImageResourceId(fh), fh, rsp.FileId, int32(length), int32(i.Width), int32(i.Height), imageType), nil
}
func (c *QQClient) UploadPrivateImage(target int64, img io.ReadSeeker) (*message.FriendImageElement, error) {
return c.uploadPrivateImage(target, img, 0)
} }
func (c *QQClient) GetGroupImageDownloadUrl(fileId, groupCode int64, fileMd5 []byte) (string, error) { func (c *QQClient) GetGroupImageDownloadUrl(fileId, groupCode int64, fileMd5 []byte) (string, error) {
@ -153,23 +135,15 @@ func (c *QQClient) GetGroupImageDownloadUrl(fileId, groupCode int64, fileMd5 []b
return i.(string), nil return i.(string), nil
} }
func (c *QQClient) uploadPrivateImage(target int64, img io.ReadSeeker, count int) (message.IMessageElement, error) { func (c *QQClient) uploadPrivateImage(target int64, img io.ReadSeeker, count int) (*message.FriendImageElement, error) {
_, _ = img.Seek(0, io.SeekStart) _, _ = img.Seek(0, io.SeekStart)
count++ count++
fh, length := utils.ComputeMd5AndLength(img) fh, length := utils.ComputeMd5AndLength(img)
_, _ = img.Seek(0, io.SeekStart) _, _ = img.Seek(0, io.SeekStart)
i, _, _ := imgsz.DecodeSize(img)
_, _ = img.Seek(0, io.SeekStart)
width := int32(i.Width)
height := int32(i.Height)
e, err := c.QueryFriendImage(target, fh, int32(length)) e, err := c.QueryFriendImage(target, fh, int32(length))
if errors.Is(err, ErrNotExists) { if errors.Is(err, ErrNotExists) {
groupSource := message.Source{
SourceType: message.SourceGroup,
PrimaryID: target,
}
// use group highway upload and query again for image id. // use group highway upload and query again for image id.
if _, err = c.uploadGroupOrGuildImage(groupSource, img); err != nil { if _, err = c.UploadGroupImage(target, img); err != nil {
return nil, err return nil, err
} }
if count >= 5 { if count >= 5 {
@ -180,23 +154,21 @@ func (c *QQClient) uploadPrivateImage(target int64, img io.ReadSeeker, count int
if err != nil { if err != nil {
return nil, err return nil, err
} }
e.Height = height
e.Width = width
return e, nil return e, nil
} }
func (c *QQClient) ImageOcr(img any) (*OcrResponse, error) { func (c *QQClient) ImageOcr(img interface{}) (*OcrResponse, error) {
url := "" url := ""
switch e := img.(type) { switch e := img.(type) {
case *message.GroupImageElement: case *message.GroupImageElement:
url = e.Url url = e.Url
if b, err := utils.HTTPGetReadCloser(e.Url, ""); err == nil { if b, err := utils.HTTPGetReadCloser(e.Url, ""); err == nil {
if url, err = c.uploadOcrImage(b, e.Size, e.Md5); err != nil { if url, err = c.uploadOcrImage(b, int64(e.Size), e.Md5); err != nil {
url = e.Url url = e.Url
} }
_ = b.Close() _ = b.Close()
} }
rsp, err := c.sendAndWait(c.buildImageOcrRequestPacket(url, fmt.Sprintf("%X", e.Md5), e.Size, e.Width, e.Height)) rsp, err := c.sendAndWait(c.buildImageOcrRequestPacket(url, strings.ToUpper(hex.EncodeToString(e.Md5)), e.Size, e.Width, e.Height))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -233,7 +205,6 @@ func (c *QQClient) QueryFriendImage(target int64, hash []byte, size int32) (*mes
return &message.FriendImageElement{ return &message.FriendImageElement{
ImageId: rsp.ResourceId, ImageId: rsp.ResourceId,
Md5: hash, Md5: hash,
Size: size,
Url: "https://c2cpicdw.qpic.cn/offpic_new/0/" + rsp.ResourceId + "/0?term=2", Url: "https://c2cpicdw.qpic.cn/offpic_new/0/" + rsp.ResourceId + "/0?term=2",
}, errors.WithStack(ErrNotExists) }, errors.WithStack(ErrNotExists)
} }
@ -241,14 +212,12 @@ func (c *QQClient) QueryFriendImage(target int64, hash []byte, size int32) (*mes
ImageId: rsp.ResourceId, ImageId: rsp.ResourceId,
Md5: hash, Md5: hash,
Url: "https://c2cpicdw.qpic.cn/offpic_new/0/" + rsp.ResourceId + "/0?term=2", Url: "https://c2cpicdw.qpic.cn/offpic_new/0/" + rsp.ResourceId + "/0?term=2",
Size: size,
Height: rsp.Height,
Width: rsp.Width,
}, nil }, nil
} }
// ImgStore.GroupPicUp // ImgStore.GroupPicUp
func (c *QQClient) buildGroupImageStorePacket(groupCode int64, md5 []byte, size int32) (uint16, []byte) { func (c *QQClient) buildGroupImageStorePacket(groupCode int64, md5 []byte, size int32) (uint16, []byte) {
seq := c.nextSeq()
name := utils.RandomString(16) + ".gif" name := utils.RandomString(16) + ".gif"
req := &cmd0x388.D388ReqBody{ req := &cmd0x388.D388ReqBody{
NetType: proto.Uint32(3), NetType: proto.Uint32(3),
@ -273,10 +242,12 @@ func (c *QQClient) buildGroupImageStorePacket(groupCode int64, md5 []byte, size
Extension: EmptyBytes, Extension: EmptyBytes,
} }
payload, _ := proto.Marshal(req) payload, _ := proto.Marshal(req)
return c.uniPacket("ImgStore.GroupPicUp", payload) packet := packets.BuildUniPacket(c.Uin, seq, "ImgStore.GroupPicUp", 1, c.OutGoingPacketSessionId, EmptyBytes, c.sigInfo.d2Key, payload)
return seq, packet
} }
func (c *QQClient) buildGroupImageDownloadPacket(fileId, groupCode int64, fileMd5 []byte) (uint16, []byte) { func (c *QQClient) buildGroupImageDownloadPacket(fileId, groupCode int64, fileMd5 []byte) (uint16, []byte) {
seq := c.nextSeq()
req := &cmd0x388.D388ReqBody{ req := &cmd0x388.D388ReqBody{
NetType: proto.Uint32(3), NetType: proto.Uint32(3),
Subcmd: proto.Uint32(2), Subcmd: proto.Uint32(2),
@ -297,111 +268,109 @@ func (c *QQClient) buildGroupImageDownloadPacket(fileId, groupCode int64, fileMd
}, },
} }
payload, _ := proto.Marshal(req) payload, _ := proto.Marshal(req)
return c.uniPacket("ImgStore.GroupPicDown", payload) packet := packets.BuildUniPacket(c.Uin, seq, "ImgStore.GroupPicDown", 1, c.OutGoingPacketSessionId, EmptyBytes, c.sigInfo.d2Key, payload)
return seq, packet
} }
func (c *QQClient) uploadOcrImage(img io.Reader, size int32, sum []byte) (string, error) { func (c *QQClient) uploadOcrImage(img io.Reader, length int64, sum []byte) (string, error) {
r := make([]byte, 16) r := make([]byte, 16)
rand.Read(r) rand.Read(r)
ext, _ := proto.Marshal(&highway2.CommFileExtReq{ ext, _ := proto.Marshal(&highway.CommFileExtReq{
ActionType: proto.Uint32(0), ActionType: proto.Uint32(0),
Uuid: binary.GenUUID(r), Uuid: binary.GenUUID(r),
}) })
rsp, err := c.highwayUploadByBDH(img, length, 76, c.bigDataSession.SigSession, sum, ext, false)
rsp, err := c.highwaySession.Upload(highway.Transaction{
CommandID: 76,
Body: img,
Size: int64(size),
Sum: sum,
Ticket: c.highwaySession.SigSession,
Ext: ext,
})
if err != nil { if err != nil {
return "", errors.Wrap(err, "upload ocr image error") return "", errors.Wrap(err, "upload ocr image error")
} }
rspExt := highway2.CommFileExtRsp{} rspExt := highway.CommFileExtRsp{}
if err = proto.Unmarshal(rsp, &rspExt); err != nil { if err = proto.Unmarshal(rsp, &rspExt); err != nil {
return "", errors.Wrap(err, "error unmarshal highway resp") return "", errors.Wrap(err, "error unmarshal highway resp")
} }
return string(rspExt.DownloadUrl), nil return string(rspExt.GetDownloadUrl()), nil
} }
// OidbSvc.0xe07_0 // OidbSvc.0xe07_0
func (c *QQClient) buildImageOcrRequestPacket(url, md5 string, size, weight, height int32) (uint16, []byte) { func (c *QQClient) buildImageOcrRequestPacket(url, md5 string, size, weight, height int32) (uint16, []byte) {
body := &oidb.DE07ReqBody{ seq := c.nextSeq()
Version: 1, body := &oidb0xe07.ReqBody{
Entrance: 3, Version: proto.Uint32(1),
OcrReqBody: &oidb.OCRReqBody{ Entrance: proto.Uint32(3),
ImageUrl: url, OcrReqBody: &oidb0xe07.OCRReqBody{
OriginMd5: md5, ImageUrl: &url,
AfterCompressMd5: md5, OriginMd5: &md5,
AfterCompressFileSize: size, AfterCompressMd5: &md5,
AfterCompressWeight: weight, AfterCompressFileSize: proto.Uint32(uint32(size)),
AfterCompressHeight: height, AfterCompressWeight: proto.Uint32(uint32(weight)),
IsCut: false, AfterCompressHeight: proto.Uint32(uint32(height)),
IsCut: proto.Bool(false),
}, },
} }
b, _ := proto.Marshal(body) b, _ := body.Marshal()
payload := c.packOIDBPackage(3591, 0, b) payload := c.packOIDBPackage(3591, 0, b)
return c.uniPacket("OidbSvc.0xe07_0", payload) packet := packets.BuildUniPacket(c.Uin, seq, "OidbSvc.0xe07_0", 1, c.OutGoingPacketSessionId, EmptyBytes, c.sigInfo.d2Key, payload)
return seq, packet
} }
// ImgStore.GroupPicUp // ImgStore.GroupPicUp
func decodeGroupImageStoreResponse(_ *QQClient, packet *network.Packet) (any, error) { func decodeGroupImageStoreResponse(_ *QQClient, _ *incomingPacketInfo, payload []byte) (interface{}, error) {
pkt := cmd0x388.D388RspBody{} pkt := cmd0x388.D388RspBody{}
err := proto.Unmarshal(packet.Payload, &pkt) err := proto.Unmarshal(payload, &pkt)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
rsp := pkt.TryupImgRsp[0] rsp := pkt.TryupImgRsp[0]
if rsp.Result.Unwrap() != 0 { if rsp.GetResult() != 0 {
return &imageUploadResponse{ return &imageUploadResponse{
ResultCode: int32(rsp.Result.Unwrap()), ResultCode: int32(rsp.GetResult()),
Message: utils.B2S(rsp.FailMsg), Message: utils.B2S(rsp.GetFailMsg()),
}, nil }, nil
} }
if rsp.FileExit.Unwrap() { if rsp.GetFileExit() {
if rsp.ImgInfo != nil { if rsp.GetImgInfo() != nil {
return &imageUploadResponse{IsExists: true, FileId: int64(rsp.Fileid.Unwrap()), Width: int32(rsp.ImgInfo.FileWidth.Unwrap()), Height: int32(rsp.ImgInfo.FileHeight.Unwrap())}, nil return &imageUploadResponse{IsExists: true, FileId: int64(rsp.GetFileid()), Width: int32(rsp.ImgInfo.GetFileWidth()), Height: int32(rsp.ImgInfo.GetFileHeight())}, nil
} }
return &imageUploadResponse{IsExists: true, FileId: int64(rsp.Fileid.Unwrap())}, nil return &imageUploadResponse{IsExists: true, FileId: int64(rsp.GetFileid())}, nil
} }
return &imageUploadResponse{ return &imageUploadResponse{
FileId: int64(rsp.Fileid.Unwrap()), FileId: int64(rsp.GetFileid()),
UploadKey: rsp.UpUkey, UploadKey: rsp.UpUkey,
UploadIp: rsp.UpIp, UploadIp: rsp.GetUpIp(),
UploadPort: rsp.UpPort, UploadPort: rsp.GetUpPort(),
}, nil }, nil
} }
func decodeGroupImageDownloadResponse(_ *QQClient, pkt *network.Packet) (any, error) { func decodeGroupImageDownloadResponse(_ *QQClient, _ *incomingPacketInfo, payload []byte) (interface{}, error) {
rsp := cmd0x388.D388RspBody{} pkt := cmd0x388.D388RspBody{}
if err := proto.Unmarshal(pkt.Payload, &rsp); err != nil { if err := proto.Unmarshal(payload, &pkt); err != nil {
return nil, errors.Wrap(err, "unmarshal protobuf message error") return nil, errors.Wrap(err, "unmarshal protobuf message error")
} }
if len(rsp.GetimgUrlRsp) == 0 { if len(pkt.GetimgUrlRsp) == 0 {
return nil, errors.New("response not found") return nil, errors.New("response not found")
} }
if len(rsp.GetimgUrlRsp[0].FailMsg) != 0 { if len(pkt.GetimgUrlRsp[0].FailMsg) != 0 {
return nil, errors.New(utils.B2S(rsp.GetimgUrlRsp[0].FailMsg)) return nil, errors.New(utils.B2S(pkt.GetimgUrlRsp[0].FailMsg))
} }
return fmt.Sprintf("https://%s%s", rsp.GetimgUrlRsp[0].DownDomain, rsp.GetimgUrlRsp[0].BigDownPara), nil return "https://" + utils.B2S(pkt.GetimgUrlRsp[0].DownDomain) + utils.B2S(pkt.GetimgUrlRsp[0].BigDownPara), nil
} }
// OidbSvc.0xe07_0 // OidbSvc.0xe07_0
func decodeImageOcrResponse(_ *QQClient, pkt *network.Packet) (any, error) { func decodeImageOcrResponse(_ *QQClient, _ *incomingPacketInfo, payload []byte) (interface{}, error) {
rsp := oidb.DE07RspBody{} pkg := oidb.OIDBSSOPkg{}
err := unpackOIDBPackage(pkt.Payload, &rsp) rsp := oidb0xe07.RspBody{}
if err != nil { if err := protobuf.Unmarshal(payload, &pkg); err != nil {
return nil, err return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
if rsp.Wording != "" { if err := protobuf.Unmarshal(pkg.Bodybuffer, &rsp); err != nil {
if strings.Contains(rsp.Wording, "服务忙") { return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
}
if rsp.GetWording() != "" {
if strings.Contains(rsp.GetWording(), "服务忙") {
return nil, errors.New("未识别到文本") return nil, errors.New("未识别到文本")
} }
return nil, errors.New(rsp.Wording) return nil, errors.New(rsp.GetWording())
} }
if rsp.RetCode != 0 { if rsp.GetRetCode() != 0 {
return nil, errors.Errorf("server error, code: %v msg: %v", rsp.RetCode, rsp.ErrMsg) return nil, errors.Errorf("server error, code: %v msg: %v", rsp.RetCode, rsp.ErrMsg)
} }
texts := make([]*TextDetection, 0, len(rsp.OcrRspBody.TextDetections)) texts := make([]*TextDetection, 0, len(rsp.OcrRspBody.TextDetections))
@ -409,18 +378,18 @@ func decodeImageOcrResponse(_ *QQClient, pkt *network.Packet) (any, error) {
points := make([]*Coordinate, 0, len(text.Polygon.Coordinates)) points := make([]*Coordinate, 0, len(text.Polygon.Coordinates))
for _, c := range text.Polygon.Coordinates { for _, c := range text.Polygon.Coordinates {
points = append(points, &Coordinate{ points = append(points, &Coordinate{
X: c.X, X: c.GetX(),
Y: c.Y, Y: c.GetY(),
}) })
} }
texts = append(texts, &TextDetection{ texts = append(texts, &TextDetection{
Text: text.DetectedText, Text: text.GetDetectedText(),
Confidence: text.Confidence, Confidence: int32(text.GetConfidence()),
Coordinates: points, Coordinates: points,
}) })
} }
return &OcrResponse{ return &OcrResponse{
Texts: texts, Texts: texts,
Language: rsp.OcrRspBody.Language, Language: rsp.OcrRspBody.GetLanguage(),
}, nil }, nil
} }

View File

@ -1,261 +0,0 @@
package auth
import (
"encoding/hex"
"encoding/json"
"fmt"
"github.com/pkg/errors"
)
//go:generate stringer -type=ProtocolType -linecomment
type ProtocolType int
const (
Unset ProtocolType = iota
AndroidPhone // Android Phone
AndroidWatch // Android Watch
MacOS // MacOS
QiDian // 企点
IPad // iPad
AndroidPad // Android Pad
)
var (
AppVersions = map[ProtocolType]*AppVersion{
AndroidPhone: {
ApkId: "com.tencent.mobileqq",
AppId: 537164840,
SubAppId: 537164840,
AppKey: "0S200MNJT807V3GE",
SortVersionName: "8.9.63.11390",
BuildTime: 1685069178,
ApkSign: []byte{0xA6, 0xB7, 0x45, 0xBF, 0x24, 0xA2, 0xC2, 0x77, 0x52, 0x77, 0x16, 0xF6, 0xF3, 0x6E, 0xB6, 0x8D},
SdkVersion: "6.0.0.2546",
SSOVersion: 20,
MiscBitmap: 150470524,
SubSigmap: 0x10400,
MainSigMap: WLOGIN_A5 | WLOGIN_RESERVED | WLOGIN_STWEB | WLOGIN_A2 | WLOGIN_ST |
WLOGIN_LSKEY | WLOGIN_SKEY | WLOGIN_SIG64 | 1<<16 | WLOGIN_VKEY | WLOGIN_D2 |
WLOGIN_SID | WLOGIN_PSKEY | WLOGIN_AQSIG | WLOGIN_LHSIG | WLOGIN_PAYTOKEN, // 16724722
QUA: "V1_AND_SQ_8.9.63_4194_YYB_D",
Protocol: AndroidPhone,
},
AndroidPad: {
ApkId: "com.tencent.mobileqq",
AppId: 537164888,
SubAppId: 537164888,
AppKey: "0S200MNJT807V3GE",
SortVersionName: "8.9.63.11390",
BuildTime: 1685069178,
ApkSign: []byte{0xA6, 0xB7, 0x45, 0xBF, 0x24, 0xA2, 0xC2, 0x77, 0x52, 0x77, 0x16, 0xF6, 0xF3, 0x6E, 0xB6, 0x8D},
SdkVersion: "6.0.0.2546",
SSOVersion: 20,
MiscBitmap: 150470524,
SubSigmap: 0x10400,
MainSigMap: WLOGIN_A5 | WLOGIN_RESERVED | WLOGIN_STWEB | WLOGIN_A2 | WLOGIN_ST |
WLOGIN_LSKEY | WLOGIN_SKEY | WLOGIN_SIG64 | 1<<16 | WLOGIN_VKEY | WLOGIN_D2 |
WLOGIN_SID | WLOGIN_PSKEY | WLOGIN_AQSIG | WLOGIN_LHSIG | WLOGIN_PAYTOKEN, // 16724722
QUA: "V1_AND_SQ_8.9.63_4194_YYB_D",
Protocol: AndroidPad,
},
AndroidWatch: {
ApkId: "com.tencent.qqlite",
AppId: 537065138,
SubAppId: 537065138,
SortVersionName: "2.0.8",
BuildTime: 1559564731,
ApkSign: []byte{0xA6, 0xB7, 0x45, 0xBF, 0x24, 0xA2, 0xC2, 0x77, 0x52, 0x77, 0x16, 0xF6, 0xF3, 0x6E, 0xB6, 0x8D},
SdkVersion: "6.0.0.2365",
SSOVersion: 5,
MiscBitmap: 16252796,
SubSigmap: 0x10400,
MainSigMap: WLOGIN_A5 | WLOGIN_RESERVED | WLOGIN_STWEB | WLOGIN_A2 | WLOGIN_ST |
WLOGIN_LSKEY | WLOGIN_SKEY | WLOGIN_SIG64 | 1<<16 | WLOGIN_VKEY | WLOGIN_D2 |
WLOGIN_SID | WLOGIN_PSKEY | WLOGIN_AQSIG | WLOGIN_LHSIG | WLOGIN_PAYTOKEN, // 16724722
Protocol: AndroidWatch,
},
IPad: {
ApkId: "com.tencent.minihd.qq",
AppId: 537151363,
SubAppId: 537151363,
SortVersionName: "8.9.33.614",
BuildTime: 1595836208,
ApkSign: []byte{170, 57, 120, 244, 31, 217, 111, 249, 145, 74, 102, 158, 24, 100, 116, 199},
SdkVersion: "6.0.0.2433",
SSOVersion: 19,
MiscBitmap: 150470524,
SubSigmap: 66560,
MainSigMap: WLOGIN_STWEB | WLOGIN_A2 | WLOGIN_ST | WLOGIN_SKEY | WLOGIN_VKEY | WLOGIN_D2 | WLOGIN_SID | WLOGIN_PSKEY, // 1970400
Protocol: IPad,
},
MacOS: {
ApkId: "com.tencent.minihd.qq",
AppId: 537128930,
SubAppId: 537128930,
SortVersionName: "5.8.9",
BuildTime: 1595836208,
ApkSign: []byte{170, 57, 120, 244, 31, 217, 111, 249, 145, 74, 102, 158, 24, 100, 116, 199},
SdkVersion: "6.0.0.2433",
SSOVersion: 12,
MiscBitmap: 150470524,
SubSigmap: 66560,
MainSigMap: WLOGIN_STWEB | WLOGIN_A2 | WLOGIN_ST | WLOGIN_SKEY | WLOGIN_VKEY | WLOGIN_D2 | WLOGIN_SID | WLOGIN_PSKEY, // 1970400
Protocol: MacOS,
},
QiDian: {
ApkId: "com.tencent.qidian",
AppId: 537096038,
SubAppId: 537036590,
SortVersionName: "5.0.0",
BuildTime: 1630062176,
ApkSign: []byte{160, 30, 236, 171, 133, 233, 227, 186, 43, 15, 106, 21, 140, 133, 92, 41},
SdkVersion: "6.0.0.2484",
SSOVersion: 18,
MiscBitmap: 184024956,
SubSigmap: 66560,
MainSigMap: WLOGIN_STWEB | WLOGIN_A2 | WLOGIN_ST | WLOGIN_SKEY | WLOGIN_D2 | WLOGIN_PSKEY | WLOGIN_DA2, // 34869472
Protocol: QiDian,
},
}
)
// see oicq/wlogin_sdk/request/WtloginHelper.java class SigType
const (
_ = 1 << iota
WLOGIN_A5
_
_
WLOGIN_RESERVED
WLOGIN_STWEB
WLOGIN_A2
WLOGIN_ST
_
WLOGIN_LSKEY
_
_
WLOGIN_SKEY
WLOGIN_SIG64
WLOGIN_OPENKEY
WLOGIN_TOKEN
_
WLOGIN_VKEY
WLOGIN_D2
WLOGIN_SID
WLOGIN_PSKEY
WLOGIN_AQSIG
WLOGIN_LHSIG
WLOGIN_PAYTOKEN
WLOGIN_PF
WLOGIN_DA2
WLOGIN_QRPUSH
WLOGIN_PT4Token
)
type AppVersion struct {
ApkSign []byte
ApkId string
SortVersionName string
SdkVersion string
AppId uint32
SubAppId uint32
AppKey string
BuildTime uint32
SSOVersion uint32
MiscBitmap uint32
SubSigmap uint32
MainSigMap uint32
QUA string
Protocol ProtocolType
}
func (v *AppVersion) String() string {
return fmt.Sprintf("%s %s", v.Protocol.String(), v.SortVersionName)
}
func (v *AppVersion) UpdateFromJson(d []byte) error {
var f appVersionFile
if err := json.Unmarshal(d, &f); err != nil {
return errors.Wrap(err, "failed to unmarshal json message")
}
// 按 AppVersion 字段顺序赋值,以免遗漏
v.ApkSign, _ = hex.DecodeString(f.ApkSign)
v.ApkId = f.ApkId
v.SortVersionName = f.SortVersionName
v.SdkVersion = f.SdkVersion
v.AppId = f.AppId
v.SubAppId = f.SubAppId
v.AppKey = f.AppKey
v.BuildTime = f.BuildTime
v.SSOVersion = f.SSOVersion
v.MiscBitmap = f.MiscBitmap
v.SubSigmap = f.SubSigmap
v.MainSigMap = f.MainSigMap
v.QUA = f.QUA
v.Protocol = f.ProtocolType
return nil
}
func (i ProtocolType) Version() *AppVersion {
return AppVersions[i]
}
type SigInfo struct {
LoginBitmap uint64
TGT []byte
TGTKey []byte
SrmToken []byte // study room manager | 0x16a
T133 []byte
EncryptedA1 []byte
UserStKey []byte
UserStWebSig []byte
SKey []byte
SKeyExpiredTime int64
D2 []byte
D2Key []byte
DeviceToken []byte
PsKeyMap map[string][]byte
Pt4TokenMap map[string][]byte
// Others
OutPacketSessionID []byte
Dpwd []byte
// tlv cache
T104 []byte
T174 []byte
G []byte
T402 []byte
RandSeed []byte // t403
T547 []byte
// rollbackSig []byte
// t149 []byte
// t150 []byte
// t528 []byte
// t530 []byte
// sync info
SyncCookie []byte
PubAccountCookie []byte
Ksid []byte
// msgCtrlBuf []byte
}
type appVersionFile struct {
ApkId string `json:"apk_id"`
AppId uint32 `json:"app_id"`
SubAppId uint32 `json:"sub_app_id"`
AppKey string `json:"app_key"`
SortVersionName string `json:"sort_version_name"`
BuildTime uint32 `json:"build_time"`
ApkSign string `json:"apk_sign"` // hex encoded
SdkVersion string `json:"sdk_version"`
SSOVersion uint32 `json:"sso_version"`
MiscBitmap uint32 `json:"misc_bitmap"`
MainSigMap uint32 `json:"main_sig_map"`
SubSigmap uint32 `json:"sub_sig_map"`
QUA string `json:"qua"`
ProtocolType ProtocolType `json:"protocol_type"`
}

View File

@ -1,224 +0,0 @@
package auth
import (
"crypto/md5"
"crypto/rand"
"encoding/hex"
"encoding/json"
"github.com/pkg/errors"
"github.com/Mrs4s/MiraiGo/client/pb"
"github.com/Mrs4s/MiraiGo/internal/proto"
)
type OSVersion struct {
Incremental []byte
Release []byte
CodeName []byte
SDK uint32
}
type Device struct {
Display []byte
Product []byte
Device []byte
Board []byte
Brand []byte
Model []byte
Bootloader []byte
FingerPrint []byte
BootId []byte
ProcVersion []byte
BaseBand []byte
SimInfo []byte
OSType []byte
MacAddress []byte
IpAddress []byte
WifiBSSID []byte
WifiSSID []byte
IMSIMd5 []byte
IMEI string
AndroidId []byte
APN []byte
VendorName []byte
VendorOSName []byte
Guid []byte
TgtgtKey []byte
QImei16 string
QImei36 string
Protocol ProtocolType
Version *OSVersion
}
func (info *Device) ToJson() []byte {
f := &deviceFile{
Display: string(info.Display),
Product: string(info.Product),
Device: string(info.Device),
Board: string(info.Board),
Model: string(info.Model),
FingerPrint: string(info.FingerPrint),
BootId: string(info.BootId),
ProcVersion: string(info.ProcVersion),
IMEI: info.IMEI,
Brand: string(info.Brand),
Bootloader: string(info.Bootloader),
BaseBand: string(info.BaseBand),
AndroidId: string(info.AndroidId),
Version: &osVersionFile{
Incremental: string(info.Version.Incremental),
Release: string(info.Version.Release),
Codename: string(info.Version.CodeName),
Sdk: info.Version.SDK,
},
SimInfo: string(info.SimInfo),
OsType: string(info.OSType),
MacAddress: string(info.MacAddress),
IpAddress: []int32{int32(info.IpAddress[0]), int32(info.IpAddress[1]), int32(info.IpAddress[2]), int32(info.IpAddress[3])},
WifiBSSID: string(info.WifiBSSID),
WifiSSID: string(info.WifiSSID),
ImsiMd5: hex.EncodeToString(info.IMSIMd5),
Apn: string(info.APN),
VendorName: string(info.VendorName),
VendorOSName: string(info.VendorOSName),
Protocol: int(info.Protocol),
}
d, _ := json.Marshal(f)
return d
}
func (info *Device) ReadJson(d []byte) error {
var f deviceFile
if err := json.Unmarshal(d, &f); err != nil {
return errors.Wrap(err, "failed to unmarshal json message")
}
setIfNotEmpty := func(trg *[]byte, str string) {
if str != "" {
*trg = []byte(str)
}
}
setIfNotEmpty(&info.Display, f.Display)
setIfNotEmpty(&info.Product, f.Product)
setIfNotEmpty(&info.Device, f.Device)
setIfNotEmpty(&info.Board, f.Board)
setIfNotEmpty(&info.Brand, f.Brand)
setIfNotEmpty(&info.Model, f.Model)
setIfNotEmpty(&info.Bootloader, f.Bootloader)
setIfNotEmpty(&info.FingerPrint, f.FingerPrint)
setIfNotEmpty(&info.BootId, f.BootId)
setIfNotEmpty(&info.ProcVersion, f.ProcVersion)
setIfNotEmpty(&info.BaseBand, f.BaseBand)
setIfNotEmpty(&info.SimInfo, f.SimInfo)
setIfNotEmpty(&info.OSType, f.OsType)
setIfNotEmpty(&info.MacAddress, f.MacAddress)
if len(f.IpAddress) == 4 {
info.IpAddress = []byte{byte(f.IpAddress[0]), byte(f.IpAddress[1]), byte(f.IpAddress[2]), byte(f.IpAddress[3])}
}
setIfNotEmpty(&info.WifiBSSID, f.WifiBSSID)
setIfNotEmpty(&info.WifiSSID, f.WifiSSID)
if len(f.ImsiMd5) != 0 {
imsiMd5, err := hex.DecodeString(f.ImsiMd5)
if err != nil {
info.IMSIMd5 = imsiMd5
}
}
if f.IMEI != "" {
info.IMEI = f.IMEI
}
setIfNotEmpty(&info.APN, f.Apn)
setIfNotEmpty(&info.VendorName, f.VendorName)
setIfNotEmpty(&info.VendorOSName, f.VendorOSName)
setIfNotEmpty(&info.AndroidId, f.AndroidId)
if f.AndroidId == "" {
info.AndroidId = info.Display // ?
}
switch f.Protocol {
case 1, 2, 3, 4, 5, 6:
info.Protocol = ProtocolType(f.Protocol)
default:
info.Protocol = AndroidPad
}
v := new(OSVersion)
v.SDK = f.Version.Sdk
v.Release = []byte(f.Version.Release)
v.CodeName = []byte(f.Version.Codename)
v.Incremental = []byte(f.Version.Incremental)
info.Version = v
info.GenNewGuid()
info.GenNewTgtgtKey()
info.RequestQImei() // 应该可以缓存, 理论上同一设备每次请求都是一样的
return nil
}
func (info *Device) GenNewGuid() {
t := md5.Sum(append(info.AndroidId, info.MacAddress...))
info.Guid = t[:]
}
func (info *Device) GenNewTgtgtKey() {
r := make([]byte, 16)
rand.Read(r)
h := md5.New()
h.Write(r)
h.Write(info.Guid)
info.TgtgtKey = h.Sum(nil)
}
func (info *Device) GenDeviceInfoData() []byte {
m := &pb.DeviceInfo{
Bootloader: string(info.Bootloader),
ProcVersion: string(info.ProcVersion),
Codename: string(info.Version.CodeName),
Incremental: string(info.Version.Incremental),
Fingerprint: string(info.FingerPrint),
BootId: string(info.BootId),
AndroidId: string(info.AndroidId),
BaseBand: string(info.BaseBand),
InnerVersion: string(info.Version.Incremental),
}
data, err := proto.Marshal(m)
if err != nil {
panic(errors.Wrap(err, "failed to unmarshal protobuf message"))
}
return data
}
type deviceFile struct {
Display string `json:"display"`
Product string `json:"product"`
Device string `json:"device"`
Board string `json:"board"`
Model string `json:"model"`
FingerPrint string `json:"finger_print"`
BootId string `json:"boot_id"`
ProcVersion string `json:"proc_version"`
Protocol int `json:"protocol"` // 0: Pad 1: Phone 2: Watch
IMEI string `json:"imei"`
Brand string `json:"brand"`
Bootloader string `json:"bootloader"`
BaseBand string `json:"base_band"`
Version *osVersionFile `json:"version"`
SimInfo string `json:"sim_info"`
OsType string `json:"os_type"`
MacAddress string `json:"mac_address"`
IpAddress []int32 `json:"ip_address"`
WifiBSSID string `json:"wifi_bssid"`
WifiSSID string `json:"wifi_ssid"`
ImsiMd5 string `json:"imsi_md5"`
AndroidId string `json:"android_id"`
Apn string `json:"apn"`
VendorName string `json:"vendor_name"`
VendorOSName string `json:"vendor_os_name"`
}
type osVersionFile struct {
Incremental string `json:"incremental"`
Release string `json:"release"`
Codename string `json:"codename"`
Sdk uint32 `json:"sdk"`
}

View File

@ -1,57 +0,0 @@
package auth
import (
"bytes"
"crypto/sha256"
"math/big"
"time"
"github.com/Mrs4s/MiraiGo/binary"
)
func CalcPow(data []byte) []byte {
r := binary.NewReader(data)
a := r.ReadByte()
typ := r.ReadByte()
c := r.ReadByte()
ok := r.ReadByte() != 0
e := r.ReadUInt16()
f := r.ReadUInt16()
src := r.ReadBytesShort()
tgt := r.ReadBytesShort()
cpy := r.ReadBytesShort()
var dst []byte
var elp, cnt uint32
if typ == 2 && len(tgt) == 32 {
start := time.Now()
tmp := new(big.Int).SetBytes(src)
hash := sha256.Sum256(tmp.Bytes())
one := big.NewInt(1)
for !bytes.Equal(hash[:], tgt) {
tmp = tmp.Add(tmp, one)
hash = sha256.Sum256(tmp.Bytes())
cnt++
}
ok = true
dst = tmp.Bytes()
elp = uint32(time.Since(start).Milliseconds())
}
w := binary.SelectWriter()
w.WriteByte(a)
w.WriteByte(typ)
w.WriteByte(c)
w.WriteBool(ok)
w.WriteUInt16(e)
w.WriteUInt16(f)
w.WriteBytesShort(src)
w.WriteBytesShort(tgt)
w.WriteBytesShort(cpy)
if ok {
w.WriteBytesShort(dst)
w.WriteUInt32(elp)
w.WriteUInt32(cnt)
}
return w.Bytes()
}

View File

@ -1,29 +0,0 @@
// Code generated by "stringer -type=ProtocolType -linecomment"; DO NOT EDIT.
package auth
import "strconv"
func _() {
// An "invalid array index" compiler error signifies that the constant values have changed.
// Re-run the stringer command to generate them again.
var x [1]struct{}
_ = x[Unset-0]
_ = x[AndroidPhone-1]
_ = x[AndroidWatch-2]
_ = x[MacOS-3]
_ = x[QiDian-4]
_ = x[IPad-5]
_ = x[AndroidPad-6]
}
const _ProtocolType_name = "UnsetAndroid PhoneAndroid WatchMacOS企点iPadAndroid Pad"
var _ProtocolType_index = [...]uint8{0, 5, 18, 31, 36, 42, 46, 57}
func (i ProtocolType) String() string {
if i < 0 || i >= ProtocolType(len(_ProtocolType_index)-1) {
return "ProtocolType(" + strconv.FormatInt(int64(i), 10) + ")"
}
return _ProtocolType_name[_ProtocolType_index[i]:_ProtocolType_index[i+1]]
}

View File

@ -1,189 +0,0 @@
package auth
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"crypto/md5"
crand "crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/base64"
"encoding/hex"
"encoding/json"
"encoding/pem"
"fmt"
"math/rand"
"time"
"github.com/Mrs4s/MiraiGo/utils"
"github.com/tidwall/gjson"
)
const (
secret = "ZdJqM15EeO2zWc08"
rsaKey = `-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDEIxgwoutfwoJxcGQeedgP7FG9
qaIuS0qzfR8gWkrkTZKM2iWHn2ajQpBRZjMSoSf6+KJGvar2ORhBfpDXyVtZCKpq
LQ+FLkpncClKVIrBwv6PHyUvuCb0rIarmgDnzkfQAqVufEtR64iazGDKatvJ9y6B
9NMbHddGSAUmRTCrHQIDAQAB
-----END PUBLIC KEY-----`
)
func (info *Device) RequestQImei() {
if info.Protocol.Version().AppKey == "" {
return
}
// init params
payload, _ := json.Marshal(genRandomPayloadByDevice(info))
cryptKey := utils.RandomStringRange(16, "abcdef1234567890")
ts := time.Now().Unix() * 1000
nonce := utils.RandomStringRange(16, "abcdef1234567890")
// init rsa key and aes key
publicKey := initPublicKey()
encryptedAesKey, _ := rsa.EncryptPKCS1v15(crand.Reader, publicKey, []byte(cryptKey))
encryptedPayload := aesEncrypt(payload, []byte(cryptKey))
key := base64.StdEncoding.EncodeToString(encryptedAesKey)
params := base64.StdEncoding.EncodeToString(encryptedPayload)
postData, _ := json.Marshal(map[string]any{
"key": key,
"params": params,
"time": ts,
"nonce": nonce,
"sign": sign(key, params, fmt.Sprint(ts), nonce),
"extra": "",
})
resp, _ := utils.HttpPostBytesWithCookie("https://snowflake.qq.com/ola/android", postData, "", "application/json")
if gjson.GetBytes(resp, "code").Int() != 0 {
return
}
encryptedResponse, _ := base64.StdEncoding.DecodeString(gjson.GetBytes(resp, "data").String())
if len(encryptedResponse) == 0 {
return
}
decryptedResponse := aesDecrypt(encryptedResponse, []byte(cryptKey))
info.QImei16 = gjson.GetBytes(decryptedResponse, "q16").String()
info.QImei36 = gjson.GetBytes(decryptedResponse, "q36").String()
}
func initPublicKey() *rsa.PublicKey {
blockPub, _ := pem.Decode([]byte(rsaKey))
pub, _ := x509.ParsePKIXPublicKey(blockPub.Bytes)
return pub.(*rsa.PublicKey)
}
func sign(key, params, ts, nonce string) string {
h := md5.Sum([]byte(key + params + ts + nonce + secret))
return hex.EncodeToString(h[:])
}
func aesEncrypt(src []byte, key []byte) []byte {
block, _ := aes.NewCipher(key)
ecb := cipher.NewCBCEncrypter(block, key)
content := src
content = pkcs5Padding(content, block.BlockSize())
crypted := make([]byte, len(content))
ecb.CryptBlocks(crypted, content)
return crypted
}
func aesDecrypt(crypt []byte, key []byte) []byte {
block, _ := aes.NewCipher(key)
ecb := cipher.NewCBCDecrypter(block, key)
decrypted := make([]byte, len(crypt))
ecb.CryptBlocks(decrypted, crypt)
return pkcs5Trimming(decrypted)
}
func pkcs5Padding(ciphertext []byte, blockSize int) []byte {
padding := blockSize - len(ciphertext)%blockSize
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
return append(ciphertext, padtext...)
}
func pkcs5Trimming(encrypt []byte) []byte {
padding := encrypt[len(encrypt)-1]
return encrypt[:len(encrypt)-int(padding)]
}
func genRandomPayloadByDevice(info *Device) map[string]any {
now := time.Now()
seed := int64(0x6F4)
for _, b := range info.Guid {
seed += int64(b)
}
fixedRand := rand.New(rand.NewSource(seed))
reserved := map[string]string{
"harmony": "0",
"clone": "0",
"containe": "",
"oz": "UhYmelwouA+V2nPWbOvLTgN2/m8jwGB+yUB5v9tysQg=",
"oo": "Xecjt+9S1+f8Pz2VLSxgpw==",
"kelong": "0",
"uptimes": time.Unix(now.Unix()-fixedRand.Int63n(14400), 0).Format(time.DateTime),
"multiUser": "0",
"bod": string(info.Board),
"brd": string(info.Brand),
"dv": string(info.Device),
"firstLevel": "",
"manufact": string(info.Brand),
"name": string(info.Model),
"host": "se.infra",
"kernel": string(info.ProcVersion),
}
reservedBytes, _ := json.Marshal(reserved)
deviceType := "Phone"
if info.Protocol == AndroidPad {
deviceType = "Pad"
}
beaconId := ""
timeMonth := time.Now().Format("2006-01-") + "01"
rand1 := fixedRand.Intn(899999) + 100000
rand2 := fixedRand.Intn(899999999) + 100000000
for i := 1; i <= 40; i++ {
switch i {
case 1, 2, 13, 14, 17, 18, 21, 22, 25, 26, 29, 30, 33, 34, 37, 38:
beaconId += fmt.Sprintf("k%v:%v%v.%v", i, timeMonth, rand1, rand2)
case 3:
beaconId += "k3:0000000000000000"
case 4:
beaconId += "k4:" + utils.RandomStringRange(16, "123456789abcdef")
default:
beaconId += fmt.Sprintf("k%v:%v", i, fixedRand.Intn(10000))
}
beaconId += ";"
}
return map[string]any{
"androidId": string(info.AndroidId),
"platformId": 1,
"appKey": info.Protocol.Version().AppKey,
"appVersion": info.Protocol.Version().SortVersionName,
"beaconIdSrc": beaconId,
"brand": string(info.Brand),
"channelId": "2017",
"cid": "",
"imei": info.IMEI,
"imsi": "",
"mac": "",
"model": string(info.Model),
"networkType": "unknown",
"oaid": "",
"osVersion": "Android " + string(info.Version.Release) + ",level " + fmt.Sprint(info.Version.SDK),
"qimei": "",
"qimei36": "",
"sdkVersion": "1.2.13.6",
"audit": "",
"userId": "{}",
"packageId": info.Protocol.Version().ApkId,
"deviceType": deviceType,
"sdkName": "",
"reserved": string(reservedBytes),
}
}

View File

@ -1,224 +0,0 @@
package highway
import (
"crypto/md5"
"io"
"sync"
"sync/atomic"
"github.com/pkg/errors"
"golang.org/x/sync/errgroup"
"github.com/Mrs4s/MiraiGo/binary"
"github.com/Mrs4s/MiraiGo/client/pb"
"github.com/Mrs4s/MiraiGo/internal/proto"
)
type Transaction struct {
CommandID int32
Body io.Reader
Sum []byte // md5 sum of body
Size int64 // body size
Ticket []byte
Ext []byte
Encrypt bool
}
func (bdh *Transaction) encrypt(key []byte) error {
if !bdh.Encrypt {
return nil
}
if len(key) == 0 {
return errors.New("session key not found. maybe miss some packet?")
}
bdh.Ext = binary.NewTeaCipher(key).Encrypt(bdh.Ext)
return nil
}
func (s *Session) uploadSingle(trans Transaction) ([]byte, error) {
pc, err := s.selectConn()
if err != nil {
return nil, err
}
defer s.putIdleConn(pc)
reader := binary.NewNetworkReader(pc.conn)
const chunkSize = 128 * 1024
var rspExt []byte
offset := 0
chunk := make([]byte, chunkSize)
for {
chunk = chunk[:cap(chunk)]
rl, err := io.ReadFull(trans.Body, chunk)
if rl == 0 {
break
}
if errors.Is(err, io.ErrUnexpectedEOF) {
chunk = chunk[:rl]
}
ch := md5.Sum(chunk)
head, _ := proto.Marshal(&pb.ReqDataHighwayHead{
MsgBasehead: &pb.DataHighwayHead{
Version: 1,
Uin: s.Uin,
Command: _REQ_CMD_DATA,
Seq: s.nextSeq(),
Appid: s.AppID,
Dataflag: 4096,
CommandId: trans.CommandID,
LocaleId: 2052,
},
MsgSeghead: &pb.SegHead{
Filesize: trans.Size,
Dataoffset: int64(offset),
Datalength: int32(rl),
Serviceticket: trans.Ticket,
Md5: ch[:],
FileMd5: trans.Sum,
},
ReqExtendinfo: trans.Ext,
})
offset += rl
buffers := frame(head, chunk)
_, err = buffers.WriteTo(pc.conn)
if err != nil {
return nil, errors.Wrap(err, "write conn error")
}
rspHead, err := readResponse(reader)
if err != nil {
return nil, errors.Wrap(err, "highway upload error")
}
if rspHead.ErrorCode != 0 {
return nil, errors.Errorf("upload failed: %d", rspHead.ErrorCode)
}
if rspHead.RspExtendinfo != nil {
rspExt = rspHead.RspExtendinfo
}
if rspHead.MsgSeghead != nil && rspHead.MsgSeghead.Serviceticket != nil {
trans.Ticket = rspHead.MsgSeghead.Serviceticket
}
}
return rspExt, nil
}
func (s *Session) Upload(trans Transaction) ([]byte, error) {
// encrypt ext data
if err := trans.encrypt(s.SessionKey); err != nil {
return nil, err
}
const maxThreadCount = 4
threadCount := int(trans.Size) / (3 * 512 * 1024) // 1 thread upload 1.5 MB
if threadCount > maxThreadCount {
threadCount = maxThreadCount
}
if threadCount < 2 {
// single thread upload
return s.uploadSingle(trans)
}
// pick a address
// TODO: pick smarter
pc, err := s.selectConn()
if err != nil {
return nil, err
}
addr := pc.addr
s.putIdleConn(pc)
const blockSize int64 = 256 * 1024
var (
rspExt []byte
completedThread uint32
cond = sync.NewCond(&sync.Mutex{})
offset = int64(0)
count = (trans.Size + blockSize - 1) / blockSize
id = 0
)
doUpload := func() error {
// send signal complete uploading
defer func() {
atomic.AddUint32(&completedThread, 1)
cond.Signal()
}()
// todo: get from pool?
pc, err := s.connect(addr)
if err != nil {
return err
}
defer s.putIdleConn(pc)
reader := binary.NewNetworkReader(pc.conn)
chunk := make([]byte, blockSize)
for {
cond.L.Lock() // lock protect reading
off := offset
offset += blockSize
id++
last := int64(id) == count
if last { // last
for atomic.LoadUint32(&completedThread) != uint32(threadCount-1) {
cond.Wait()
}
} else if int64(id) > count {
cond.L.Unlock()
break
}
chunk = chunk[:blockSize]
n, err := io.ReadFull(trans.Body, chunk)
cond.L.Unlock()
if n == 0 {
break
}
if errors.Is(err, io.ErrUnexpectedEOF) {
chunk = chunk[:n]
}
ch := md5.Sum(chunk)
head, _ := proto.Marshal(&pb.ReqDataHighwayHead{
MsgBasehead: &pb.DataHighwayHead{
Version: 1,
Uin: s.Uin,
Command: _REQ_CMD_DATA,
Seq: s.nextSeq(),
Appid: s.AppID,
Dataflag: 4096,
CommandId: trans.CommandID,
LocaleId: 2052,
},
MsgSeghead: &pb.SegHead{
Filesize: trans.Size,
Dataoffset: off,
Datalength: int32(n),
Serviceticket: trans.Ticket,
Md5: ch[:],
FileMd5: trans.Sum,
},
ReqExtendinfo: trans.Ext,
})
buffers := frame(head, chunk)
_, err = buffers.WriteTo(pc.conn)
if err != nil {
return errors.Wrap(err, "write conn error")
}
rspHead, err := readResponse(reader)
if err != nil {
return errors.Wrap(err, "highway upload error")
}
if rspHead.ErrorCode != 0 {
return errors.Errorf("upload failed: %d", rspHead.ErrorCode)
}
if last && rspHead.RspExtendinfo != nil {
rspExt = rspHead.RspExtendinfo
}
}
return nil
}
group := errgroup.Group{}
for i := 0; i < threadCount; i++ {
group.Go(doUpload)
}
return rspExt, group.Wait()
}

View File

@ -1,35 +0,0 @@
package highway
import (
"encoding/binary"
"net"
)
var etx = []byte{0x29}
// frame 包格式
//
// - STX: 0x28(40)
// - head length
// - body length
// - head data
// - body data
// - ETX: 0x29(41)
//
// 节省内存, 可被go runtime优化为writev操作
func frame(head []byte, body []byte) net.Buffers {
buffers := make(net.Buffers, 4)
// buffer0 format:
// - STX
// - head length
// - body length
buffer0 := make([]byte, 9)
buffer0[0] = 0x28
binary.BigEndian.PutUint32(buffer0[1:], uint32(len(head)))
binary.BigEndian.PutUint32(buffer0[5:], uint32(len(body)))
buffers[0] = buffer0
buffers[1] = head
buffers[2] = body
buffers[3] = etx
return buffers
}

View File

@ -1,259 +0,0 @@
package highway
import (
"fmt"
"net"
"runtime"
"sync"
"sync/atomic"
"time"
"github.com/pkg/errors"
"github.com/Mrs4s/MiraiGo/binary"
"github.com/Mrs4s/MiraiGo/client/pb"
"github.com/Mrs4s/MiraiGo/internal/proto"
)
// see com/tencent/mobileqq/highway/utils/BaseConstants.java#L120-L121
const (
_REQ_CMD_DATA = "PicUp.DataUp"
_REQ_CMD_HEART_BREAK = "PicUp.Echo"
)
type Addr struct {
IP uint32
Port int
}
func (a Addr) AsNetIP() net.IP {
return net.IPv4(byte(a.IP>>24), byte(a.IP>>16), byte(a.IP>>8), byte(a.IP))
}
func (a Addr) String() string {
return fmt.Sprintf("%v:%v", binary.UInt32ToIPV4Address(a.IP), a.Port)
}
func (a Addr) empty() bool {
return a.IP == 0 || a.Port == 0
}
type Session struct {
Uin string
AppID int32
SigSession []byte
SessionKey []byte
seq int32
addrMu sync.Mutex
idx int
SsoAddr []Addr
idleMu sync.Mutex
idleCount int
idle *idle
}
const highwayMaxResponseSize int32 = 1024 * 100 // 100k
func (s *Session) AddrLength() int {
s.addrMu.Lock()
defer s.addrMu.Unlock()
return len(s.SsoAddr)
}
func (s *Session) AppendAddr(ip, port uint32) {
s.addrMu.Lock()
defer s.addrMu.Unlock()
addr := Addr{
IP: ip,
Port: int(port),
}
s.SsoAddr = append(s.SsoAddr, addr)
}
func (s *Session) nextSeq() int32 {
return atomic.AddInt32(&s.seq, 2)
}
func (s *Session) sendHeartbreak(conn net.Conn) error {
head, _ := proto.Marshal(&pb.ReqDataHighwayHead{
MsgBasehead: &pb.DataHighwayHead{
Version: 1,
Uin: s.Uin,
Command: _REQ_CMD_HEART_BREAK,
Seq: s.nextSeq(),
Appid: s.AppID,
Dataflag: 4096,
CommandId: 0,
LocaleId: 2052,
},
})
buffers := frame(head, nil)
_, err := buffers.WriteTo(conn)
return err
}
func (s *Session) ping(pc *persistConn) error {
start := time.Now()
err := s.sendHeartbreak(pc.conn)
if err != nil {
return errors.Wrap(err, "echo error")
}
if _, err = readResponse(binary.NewNetworkReader(pc.conn)); err != nil {
return errors.Wrap(err, "echo error")
}
// update delay
pc.ping = time.Since(start).Milliseconds()
return nil
}
func readResponse(r *binary.NetworkReader) (*pb.RspDataHighwayHead, error) {
_, err := r.ReadByte()
if err != nil {
return nil, errors.Wrap(err, "failed to read byte")
}
hl, _ := r.ReadInt32()
a2, _ := r.ReadInt32()
if hl > highwayMaxResponseSize || a2 > highwayMaxResponseSize {
return nil, errors.Errorf("highway response invild. head size: %v body size: %v", hl, a2)
}
head, _ := r.ReadBytes(int(hl))
_, _ = r.ReadBytes(int(a2)) // skip payload
_, _ = r.ReadByte()
rsp := new(pb.RspDataHighwayHead)
if err = proto.Unmarshal(head, rsp); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
}
return rsp, nil
}
type persistConn struct {
conn net.Conn
addr Addr
ping int64 // echo ping
}
const maxIdleConn = 7
type idle struct {
pc persistConn
next *idle
}
// getIdleConn ...
func (s *Session) getIdleConn() persistConn {
s.idleMu.Lock()
defer s.idleMu.Unlock()
// no idle
if s.idle == nil {
return persistConn{}
}
// switch the fastest idle conn
conn := s.idle.pc
s.idle = s.idle.next
s.idleCount--
if s.idleCount < 0 {
panic("idle count underflow")
}
return conn
}
func (s *Session) putIdleConn(pc persistConn) {
s.idleMu.Lock()
defer s.idleMu.Unlock()
// check persistConn
if pc.conn == nil || pc.addr.empty() {
panic("put bad idle conn")
}
cur := &idle{pc: pc}
s.idleCount++
if s.idle == nil { // quick path
s.idle = cur
return
}
// insert between pre and succ
var pre, succ *idle
succ = s.idle
for succ != nil && succ.pc.ping < pc.ping { // keep idle list sorted by delay incremental
pre = succ
succ = succ.next
}
if pre != nil {
pre.next = cur
}
cur.next = succ
// remove the slowest idle conn if idle count greater than maxIdleConn
if s.idleCount > maxIdleConn {
for cur.next != nil {
pre = cur
cur = cur.next
}
pre.next = nil
s.idleCount--
}
}
func (s *Session) connect(addr Addr) (persistConn, error) {
conn, err := net.DialTimeout("tcp", addr.String(), time.Second*3)
if err != nil {
return persistConn{}, err
}
_ = conn.(*net.TCPConn).SetKeepAlive(true)
// close conn
runtime.SetFinalizer(conn, func(conn net.Conn) {
_ = conn.Close()
})
pc := persistConn{conn: conn, addr: addr}
if err = s.ping(&pc); err != nil {
return persistConn{}, err
}
return pc, nil
}
func (s *Session) nextAddr() Addr {
s.addrMu.Lock()
defer s.addrMu.Unlock()
addr := s.SsoAddr[s.idx]
s.idx = (s.idx + 1) % len(s.SsoAddr)
return addr
}
func (s *Session) selectConn() (pc persistConn, err error) {
for { // select from idle pc
pc = s.getIdleConn()
if pc.conn == nil {
// no idle connection
break
}
err = s.ping(&pc) // ping
if err == nil {
return
}
}
try := 0
for {
addr := s.nextAddr()
pc, err = s.connect(addr)
if err == nil {
break
}
try++
if try > 5 {
break
}
}
return
}

View File

@ -1,32 +0,0 @@
package intern
import (
"sync"
)
// String Interning is a technique for reducing the memory footprint of large
// strings. It can re-use strings that are already in memory.
type StringInterner struct {
mu sync.RWMutex
strings map[string]string
}
func NewStringInterner() *StringInterner {
return &StringInterner{
strings: make(map[string]string),
}
}
func (i *StringInterner) Intern(s string) string {
i.mu.RLock()
if v, ok := i.strings[s]; ok {
i.mu.RUnlock()
return v
}
i.mu.RUnlock()
i.mu.Lock()
i.strings[s] = s
i.mu.Unlock()
return s
}

View File

@ -1,32 +0,0 @@
package network
type Packet struct {
SequenceId uint16
CommandName string
Payload []byte
Params RequestParams
}
type RequestParams map[string]any
func (p RequestParams) Bool(k string) bool {
if p == nil {
return false
}
i, ok := p[k]
if !ok {
return false
}
return i.(bool)
}
func (p RequestParams) Int32(k string) int32 {
if p == nil {
return 0
}
i, ok := p[k]
if !ok {
return 0
}
return i.(int32)
}

View File

@ -1,25 +0,0 @@
package network
type RequestType uint32
const (
RequestTypeLogin = 0x0A
RequestTypeSimple = 0x0B
)
type EncryptType uint32
const (
EncryptTypeNoEncrypt EncryptType = iota // 0x00
EncryptTypeD2Key // 0x01
EncryptTypeEmptyKey // 0x02
)
type Request struct {
Type RequestType
EncryptType EncryptType
SequenceID int32
Uin int64
CommandName string
Body []byte
}

View File

@ -1,93 +0,0 @@
package network
import (
"strconv"
"github.com/pkg/errors"
"github.com/Mrs4s/MiraiGo/binary"
)
type Response struct {
Type RequestType
EncryptType EncryptType
SequenceID int32
Uin int64
CommandName string
Body []byte
Message string
// Request is the original request that obtained this response.
// Request *Request
}
var (
ErrSessionExpired = errors.New("session expired")
ErrPacketDropped = errors.New("packet dropped")
ErrInvalidPacketType = errors.New("invalid packet type")
)
func (t *Transport) ReadResponse(head []byte) (*Response, error) {
resp := new(Response)
r := binary.NewReader(head)
resp.Type = RequestType(r.ReadInt32())
if resp.Type != RequestTypeLogin && resp.Type != RequestTypeSimple {
return resp, ErrInvalidPacketType
}
resp.EncryptType = EncryptType(r.ReadByte())
_ = r.ReadByte() // 0x00?
resp.Uin, _ = strconv.ParseInt(r.ReadString(), 10, 64)
body := r.ReadAvailable()
switch resp.EncryptType {
case EncryptTypeNoEncrypt:
// nothing to do
case EncryptTypeD2Key:
body = binary.NewTeaCipher(t.Sig.D2Key).Decrypt(body)
case EncryptTypeEmptyKey:
emptyKey := make([]byte, 16)
body = binary.NewTeaCipher(emptyKey).Decrypt(body)
}
err := t.readSSOFrame(resp, body)
return resp, err
}
func (t *Transport) readSSOFrame(resp *Response, payload []byte) error {
reader := binary.NewReader(payload)
headLen := reader.ReadInt32()
if headLen < 4 || headLen-4 > int32(reader.Len()) {
return errors.WithStack(ErrPacketDropped)
}
head := binary.NewReader(reader.ReadBytes(int(headLen) - 4))
resp.SequenceID = head.ReadInt32()
switch retCode := head.ReadInt32(); retCode {
case 0:
// ok
case -10008:
return errors.WithStack(ErrSessionExpired)
default:
return errors.Errorf("return code unsuccessful: %d", retCode)
}
resp.Message = head.ReadString()
resp.CommandName = head.ReadString()
if resp.CommandName == "Heartbeat.Alive" {
return nil
}
_ = head.ReadInt32Bytes() // session id
compressedFlag := head.ReadInt32()
bodyLen := reader.ReadInt32() - 4
body := reader.ReadAvailable()
if bodyLen > 0 && bodyLen < int32(len(body)) {
body = body[:bodyLen]
}
switch compressedFlag {
case 0, 8:
case 1:
body = binary.ZlibUncompress(body)
}
resp.Body = body
return nil
}

View File

@ -1,232 +0,0 @@
package network
import (
"strconv"
"strings"
"github.com/Mrs4s/MiraiGo/binary"
"github.com/Mrs4s/MiraiGo/client/internal/auth"
"github.com/Mrs4s/MiraiGo/client/pb"
"github.com/Mrs4s/MiraiGo/internal/proto"
"github.com/Mrs4s/MiraiGo/wrapper"
"github.com/pkg/errors"
)
// Transport is a network transport.
type Transport struct {
Sig *auth.SigInfo
Version *auth.AppVersion
Device *auth.Device
// connection
// conn *TCPClient
}
var WhiteListCommands = `
ConnAuthSvr.fast_qq_login
ConnAuthSvr.sdk_auth_api
ConnAuthSvr.sdk_auth_api_emp
FeedCloudSvr.trpc.feedcloud.commwriter.ComWriter.DoBarrage
FeedCloudSvr.trpc.feedcloud.commwriter.ComWriter.DoComment
FeedCloudSvr.trpc.feedcloud.commwriter.ComWriter.DoFollow
FeedCloudSvr.trpc.feedcloud.commwriter.ComWriter.DoLike
FeedCloudSvr.trpc.feedcloud.commwriter.ComWriter.DoPush
FeedCloudSvr.trpc.feedcloud.commwriter.ComWriter.DoReply
FeedCloudSvr.trpc.feedcloud.commwriter.ComWriter.PublishFeed
FeedCloudSvr.trpc.videocircle.circleprofile.CircleProfile.SetProfile
friendlist.addFriend
friendlist.AddFriendReq
friendlist.ModifyGroupInfoReq
MessageSvc.PbSendMsg
MsgProxy.SendMsg
OidbSvc.0x4ff_9
OidbSvc.0x4ff_9_IMCore
OidbSvc.0x56c_6
OidbSvc.0x6d9_4
OidbSvc.0x758
OidbSvc.0x758_0
OidbSvc.0x758_1
OidbSvc.0x88d_0
OidbSvc.0x89a_0
OidbSvc.0x89b_1
OidbSvc.0x8a1_0
OidbSvc.0x8a1_7
OidbSvc.0x8ba
OidbSvc.0x9fa
OidbSvc.oidb_0x758
OidbSvcTrpcTcp.0x101e_1
OidbSvcTrpcTcp.0x101e_2
OidbSvcTrpcTcp.0x1100_1
OidbSvcTrpcTcp.0x1105_1
OidbSvcTrpcTcp.0x1107_1
OidbSvcTrpcTcp.0x55f_0
OidbSvcTrpcTcp.0x6d9_4
OidbSvcTrpcTcp.0xf55_1
OidbSvcTrpcTcp.0xf57_1
OidbSvcTrpcTcp.0xf57_106
OidbSvcTrpcTcp.0xf57_9
OidbSvcTrpcTcp.0xf65_1
OidbSvcTrpcTcp.0xf65_10
OidbSvcTrpcTcp.0xf67_1
OidbSvcTrpcTcp.0xf67_5
OidbSvcTrpcTcp.0xf6e_1
OidbSvcTrpcTcp.0xf88_1
OidbSvcTrpcTcp.0xf89_1
OidbSvcTrpcTcp.0xfa5_1
ProfileService.getGroupInfoReq
ProfileService.GroupMngReq
QChannelSvr.trpc.qchannel.commwriter.ComWriter.DoComment
QChannelSvr.trpc.qchannel.commwriter.ComWriter.DoReply
QChannelSvr.trpc.qchannel.commwriter.ComWriter.PublishFeed
qidianservice.135
qidianservice.207
qidianservice.269
qidianservice.290
SQQzoneSvc.addComment
SQQzoneSvc.addReply
SQQzoneSvc.forward
SQQzoneSvc.like
SQQzoneSvc.publishmood
SQQzoneSvc.shuoshuo
trpc.group_pro.msgproxy.sendmsg
trpc.login.ecdh.EcdhService.SsoNTLoginPasswordLoginUnusualDevice
trpc.o3.ecdh_access.EcdhAccess.SsoEstablishShareKey
trpc.o3.ecdh_access.EcdhAccess.SsoSecureA2Access
trpc.o3.ecdh_access.EcdhAccess.SsoSecureA2Establish
trpc.o3.ecdh_access.EcdhAccess.SsoSecureAccess
trpc.o3.report.Report.SsoReport
trpc.passwd.manager.PasswdManager.SetPasswd
trpc.passwd.manager.PasswdManager.VerifyPasswd
trpc.qlive.relationchain_svr.RelationchainSvr.Follow
trpc.qlive.word_svr.WordSvr.NewPublicChat
trpc.qqhb.qqhb_proxy.Handler.sso_handle
trpc.springfestival.redpacket.LuckyBag.SsoSubmitGrade
wtlogin.device_lock
wtlogin.exchange_emp
wtlogin.login
wtlogin.name2uin
wtlogin.qrlogin
wtlogin.register
wtlogin.trans_emp
wtlogin_device.login
wtlogin_device.tran_sim_emp
`
func (t *Transport) packBody(req *Request, w *binary.Writer) {
pos := w.FillUInt32()
if req.Type == RequestTypeLogin {
w.WriteUInt32(uint32(req.SequenceID))
w.WriteUInt32(t.Version.AppId)
w.WriteUInt32(t.Version.SubAppId)
w.Write([]byte{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00})
tgt := t.Sig.TGT
if len(tgt) == 0 || len(tgt) == 4 {
w.WriteUInt32(0x04)
} else {
w.WriteUInt32(uint32(len(tgt) + 4))
w.Write(tgt)
}
}
w.WriteString(req.CommandName)
w.WriteUInt32(uint32(len(t.Sig.OutPacketSessionID) + 4))
w.Write(t.Sig.OutPacketSessionID)
if req.Type == RequestTypeLogin {
w.WriteString((*t.Device).IMEI)
w.WriteUInt32(0x04)
w.WriteUInt16(uint16(len(t.Sig.Ksid)) + 2)
w.Write(t.Sig.Ksid)
}
if strings.Contains(WhiteListCommands, req.CommandName) {
secSign := t.PackSecSign(req)
w.WriteUInt32(uint32(len(secSign) + 4))
w.Write(secSign)
}
w.WriteUInt32(0x04 + uint32(len(t.Device.QImei16)))
w.Write([]byte(t.Device.QImei16))
w.WriteUInt32At(pos, uint32(w.Len()-pos))
w.WriteUInt32(uint32(len(req.Body) + 4))
w.Write(req.Body)
}
func (t *Transport) PackSecSign(req *Request) []byte {
if wrapper.FekitGetSign == nil {
return []byte{}
}
sign, extra, token, err := wrapper.FekitGetSign(uint64(req.SequenceID), strconv.FormatInt(req.Uin, 10), req.CommandName, t.Version.QUA, req.Body)
if err != nil {
return []byte{}
}
m := &pb.SSOReserveField{
Flag: 0,
Qimei: t.Device.QImei16,
NewconnFlag: 0,
Uid: strconv.FormatInt(req.Uin, 10),
Imsi: 0,
NetworkType: 1,
IpStackType: 1,
MessageType: 0,
SecInfo: &pb.SsoSecureInfo{
SecSig: sign,
SecDeviceToken: token,
SecExtra: extra,
},
SsoIpOrigin: 0,
}
data, err := proto.Marshal(m)
if err != nil {
panic(errors.Wrap(err, "failed to unmarshal protobuf SSOReserveField"))
}
return data
}
// PackPacket packs a packet.
func (t *Transport) PackPacket(req *Request) []byte {
// todo(wdvxdr): combine pack packet, send packet and return the response
if len(t.Sig.D2) == 0 {
req.EncryptType = EncryptTypeEmptyKey
}
w := binary.SelectWriter()
defer binary.PutWriter(w)
pos := w.FillUInt32()
// vvv w.Write(head) vvv
w.WriteUInt32(uint32(req.Type))
w.WriteByte(byte(req.EncryptType))
switch req.Type {
case RequestTypeLogin:
switch req.EncryptType {
case EncryptTypeD2Key:
w.WriteUInt32(uint32(len(t.Sig.D2) + 4))
w.Write(t.Sig.D2)
default:
w.WriteUInt32(4)
}
case RequestTypeSimple:
w.WriteUInt32(uint32(req.SequenceID))
}
w.WriteByte(0x00)
w.WriteString(strconv.FormatInt(req.Uin, 10))
// ^^^ w.Write(head) ^^^
w2 := binary.SelectWriter()
t.packBody(req, w2)
body := w2.Bytes()
// encrypt body
switch req.EncryptType {
case EncryptTypeD2Key:
body = binary.NewTeaCipher(t.Sig.D2Key).Encrypt(body)
case EncryptTypeEmptyKey:
emptyKey := make([]byte, 16)
body = binary.NewTeaCipher(emptyKey).Encrypt(body)
}
w.Write(body)
binary.PutWriter(w2)
w.WriteUInt32At(pos, uint32(w.Len()))
return append([]byte(nil), w.Bytes()...)
}

View File

@ -1,65 +0,0 @@
package oicq
import (
"crypto/ecdh"
"crypto/md5"
"crypto/rand"
"encoding/hex"
"encoding/json"
"net/http"
"strconv"
)
// session is ecdh session in oicq.
type session struct {
SvrPublicKeyVer uint16
PublicKey []byte
ShareKey []byte
}
const serverPublicKey = "04EBCA94D733E399B2DB96EACDD3F69A8BB0F74224E2B44E3357812211D2E62EFBC91BB553098E25E33A799ADC7F76FEB208DA7C6522CDB0719A305180CC54A82E"
func newSession() *session {
e := &session{
SvrPublicKeyVer: 1,
}
key, _ := hex.DecodeString(serverPublicKey)
e.init(key)
return e
}
type pubKeyResp struct {
Meta struct {
PubKeyVer uint16 `json:"KeyVer"`
PubKey string `json:"PubKey"`
} `json:"PubKeyMeta"`
}
// fetchPubKey 从服务器获取PubKey
func (e *session) fetchPubKey(uin int64) {
resp, err := http.Get("https://keyrotate.qq.com/rotate_key?cipher_suite_ver=305&uin=" + strconv.FormatInt(uin, 10))
if err != nil {
return
}
defer func() { _ = resp.Body.Close() }()
pubKey := pubKeyResp{}
err = json.NewDecoder(resp.Body).Decode(&pubKey)
if err != nil {
return
}
e.SvrPublicKeyVer = pubKey.Meta.PubKeyVer
key, _ := hex.DecodeString(pubKey.Meta.PubKey)
e.init(key) // todo check key sign
}
func (e *session) init(svrPubKey []byte) {
p256 := ecdh.P256()
local, _ := p256.GenerateKey(rand.Reader)
remote, _ := p256.NewPublicKey(svrPubKey)
share, _ := local.ECDH(remote)
hash := md5.New()
hash.Write(share[:16])
e.ShareKey = hash.Sum(nil)
e.PublicKey = local.PublicKey().Bytes()
}

View File

@ -1,149 +0,0 @@
package oicq
import (
"crypto/rand"
goBinary "encoding/binary"
"github.com/pkg/errors"
"github.com/Mrs4s/MiraiGo/binary"
)
type Codec struct {
ecdh *session
randomKey []byte
WtSessionTicketKey []byte
}
func NewCodec(uin int64) *Codec {
c := &Codec{
ecdh: newSession(),
randomKey: make([]byte, 16),
}
rand.Read(c.randomKey)
c.ecdh.fetchPubKey(uin)
return c
}
type EncryptionMethod byte
const (
EM_ECDH EncryptionMethod = iota
EM_ST
)
type Message struct {
Uin uint32
Command uint16
EncryptionMethod EncryptionMethod
Body []byte
}
func (c *Codec) Marshal(m *Message) []byte {
w := binary.SelectWriter()
defer binary.PutWriter(w)
w.WriteByte(0x02)
w.WriteUInt16(0) // len 占位
w.WriteUInt16(8001) // version?
w.WriteUInt16(m.Command)
w.WriteUInt16(1)
w.WriteUInt32(m.Uin)
w.WriteByte(0x03)
switch m.EncryptionMethod {
case EM_ECDH:
w.WriteByte(0x87)
case EM_ST:
w.WriteByte(0x45)
}
w.WriteByte(0)
w.WriteUInt32(2)
w.WriteUInt32(0)
w.WriteUInt32(0)
switch m.EncryptionMethod {
case EM_ECDH:
w.WriteByte(0x02)
w.WriteByte(0x01)
w.Write(c.randomKey)
w.WriteUInt16(0x01_31)
w.WriteUInt16(c.ecdh.SvrPublicKeyVer)
w.WriteUInt16(uint16(len(c.ecdh.PublicKey)))
w.Write(c.ecdh.PublicKey)
w.EncryptAndWrite(c.ecdh.ShareKey, m.Body)
case EM_ST:
w.WriteByte(0x01)
w.WriteByte(0x03)
w.Write(c.randomKey)
w.WriteUInt16(0x0102)
w.WriteUInt16(0x0000)
w.EncryptAndWrite(c.randomKey, m.Body)
}
w.WriteByte(0x03)
buf := make([]byte, len(w.Bytes()))
copy(buf, w.Bytes())
goBinary.BigEndian.PutUint16(buf[1:3], uint16(len(buf)))
return buf
}
var (
ErrUnknownFlag = errors.New("unknown flag")
ErrUnknownEncryptType = errors.New("unknown encrypt type")
)
func (c *Codec) Unmarshal(data []byte) (*Message, error) {
reader := binary.NewReader(data)
if flag := reader.ReadByte(); flag != 2 {
return nil, ErrUnknownFlag
}
m := new(Message)
reader.ReadUInt16() // len
reader.ReadUInt16() // version?
m.Command = reader.ReadUInt16()
reader.ReadUInt16() // 1?
m.Uin = uint32(reader.ReadInt32())
reader.ReadByte()
encryptType := reader.ReadByte()
reader.ReadByte()
switch encryptType {
case 0:
d := reader.ReadBytes(reader.Len() - 1)
defer func() {
if pan := recover(); pan != nil {
m.Body = binary.NewTeaCipher(c.randomKey).Decrypt(d)
}
}()
m.Body = binary.NewTeaCipher(c.ecdh.ShareKey).Decrypt(d)
case 3:
d := reader.ReadBytes(reader.Len() - 1)
m.Body = binary.NewTeaCipher(c.WtSessionTicketKey).Decrypt(d)
default:
return nil, ErrUnknownEncryptType
}
return m, nil
}
type TLV struct {
Command uint16
List [][]byte
}
func (t *TLV) Marshal() []byte {
w := binary.SelectWriter()
defer binary.PutWriter(w)
w.WriteUInt16(t.Command)
w.WriteUInt16(uint16(len(t.List)))
for _, elem := range t.List {
w.Write(elem)
}
return append([]byte(nil), w.Bytes()...)
}
func (t *TLV) Append(b ...[]byte) {
t.List = append(t.List, b...)
}

View File

@ -1,105 +0,0 @@
package tlv
import (
"encoding/binary"
"github.com/pkg/errors"
)
// Record represents a Tag-Length-Value record.
type Record struct {
Tag int
Length int
Value []byte
}
type RecordMap map[int][]byte
func (rm RecordMap) Exists(key int) bool {
_, ok := rm[key]
return ok
}
var ErrMessageTooShort = errors.New("tlv: message too short")
// Decoder is a configurable TLV decoder.
type Decoder struct {
tagSize uint8
lenSize uint8
headSize uint8
}
func NewDecoder(tagSize, lenSize uint8) *Decoder {
check := func(t string, s uint8) {
switch s {
case 1, 2, 4:
// ok
default:
panic("invalid " + t)
}
}
check("tag size", tagSize)
check("len size", lenSize)
return &Decoder{tagSize: tagSize, lenSize: lenSize, headSize: tagSize + lenSize}
}
func (d *Decoder) decodeRecord(data []byte) (r Record, err error) {
tagSize := d.tagSize
lenSize := d.lenSize
headSize := int(tagSize + lenSize)
if len(data) < headSize {
err = ErrMessageTooShort
return
}
r.Tag = d.read(tagSize, data)
r.Length = d.read(lenSize, data[tagSize:])
if len(data) < headSize+r.Length {
err = ErrMessageTooShort
return
}
r.Value = data[headSize : headSize+r.Length : headSize+r.Length]
return
}
func (d *Decoder) read(size uint8, data []byte) int {
switch size {
case 1:
return int(data[0])
case 2:
return int(binary.BigEndian.Uint16(data))
case 4:
return int(binary.BigEndian.Uint32(data))
default:
panic("invalid size")
}
}
func (d *Decoder) Decode(data []byte) ([]Record, error) {
var records []Record
for len(data) > 0 {
r, err := d.decodeRecord(data)
if err != nil {
return nil, err
}
records = append(records, r)
data = data[int(d.headSize)+r.Length:]
}
return records, nil
}
func (d *Decoder) DecodeRecordMap(data []byte) (RecordMap, error) {
records, err := d.Decode(data)
if err != nil {
return nil, err
}
rm := make(RecordMap, len(records))
for _, record := range records {
rm[record.Tag] = record.Value
}
return rm, nil
}

View File

@ -1,43 +0,0 @@
package client
type Logger interface {
Info(format string, args ...any)
Warning(format string, args ...any)
Error(format string, args ...any)
Debug(format string, args ...any)
Dump(dumped []byte, format string, args ...any)
}
func (c *QQClient) SetLogger(logger Logger) {
c.logger = logger
}
func (c *QQClient) info(msg string, args ...any) {
if c.logger != nil {
c.logger.Info(msg, args...)
}
}
func (c *QQClient) warning(msg string, args ...any) {
if c.logger != nil {
c.logger.Warning(msg, args...)
}
}
func (c *QQClient) error(msg string, args ...any) {
if c.logger != nil {
c.logger.Error(msg, args...)
}
}
func (c *QQClient) debug(msg string, args ...any) {
if c.logger != nil {
c.logger.Debug(msg, args...)
}
}
func (c *QQClient) dump(msg string, data []byte, args ...any) {
if c.logger != nil {
c.logger.Dump(data, msg, args...)
}
}

View File

@ -1,43 +0,0 @@
// Code generated by "stringer -type=LoginError"; DO NOT EDIT.
package client
import "strconv"
func _() {
// An "invalid array index" compiler error signifies that the constant values have changed.
// Re-run the stringer command to generate them again.
var x [1]struct{}
_ = x[NeedCaptcha-1]
_ = x[OtherLoginError-3]
_ = x[UnsafeDeviceError-4]
_ = x[SMSNeededError-5]
_ = x[TooManySMSRequestError-6]
_ = x[SMSOrVerifyNeededError-7]
_ = x[SliderNeededError-8]
_ = x[UnknownLoginError - -1]
}
const (
_LoginError_name_0 = "UnknownLoginError"
_LoginError_name_1 = "NeedCaptcha"
_LoginError_name_2 = "OtherLoginErrorUnsafeDeviceErrorSMSNeededErrorTooManySMSRequestErrorSMSOrVerifyNeededErrorSliderNeededError"
)
var (
_LoginError_index_2 = [...]uint8{0, 15, 32, 46, 68, 90, 107}
)
func (i LoginError) String() string {
switch {
case i == -1:
return _LoginError_name_0
case i == 1:
return _LoginError_name_1
case 3 <= i && i <= 8:
i -= 3
return _LoginError_name_2[_LoginError_index_2[i]:_LoginError_index_2[i+1]]
default:
return "LoginError(" + strconv.FormatInt(int64(i), 10) + ")"
}
}

View File

@ -42,14 +42,15 @@ type (
) )
func (c *QQClient) getGtk(domain string) int { func (c *QQClient) getGtk(domain string) int {
if psKey, ok := c.sig.PsKeyMap[domain]; ok { if psKey, ok := c.sigInfo.psKeyMap[domain]; ok {
accu := 5381 accu := 5381
for _, b := range psKey { for _, b := range psKey {
accu = accu + (accu << 5) + int(b) accu = accu + (accu << 5) + int(b)
} }
return 2147483647 & accu return 2147483647 & accu
} else {
return 0
} }
return 0
} }
func (c *QQClient) GetModelShow(modelName string) ([]*ModelVariant, error) { func (c *QQClient) GetModelShow(modelName string) ([]*ModelVariant, error) {
@ -59,7 +60,7 @@ func (c *QQClient) GetModelShow(modelName string) ([]*ModelVariant, error) {
Uin: c.Uin, Uin: c.Uin,
Model: strings.ReplaceAll(url.QueryEscape(modelName), "+", "%20"), Model: strings.ReplaceAll(url.QueryEscape(modelName), "+", "%20"),
AppType: 0, AppType: 0,
IMei: c.Device().IMEI, IMei: c.deviceInfo.IMEI,
ShowInfo: true, ShowInfo: true,
ModelShow: "", ModelShow: "",
RecoverDefault: false, RecoverDefault: false,
@ -96,7 +97,7 @@ func (c *QQClient) SetModelShow(modelName string, modelShow string) error {
Uin: c.Uin, Uin: c.Uin,
Model: strings.ReplaceAll(url.QueryEscape(modelName), "+", "%20"), Model: strings.ReplaceAll(url.QueryEscape(modelName), "+", "%20"),
AppType: 0, AppType: 0,
IMei: c.Device().IMEI, IMei: c.deviceInfo.IMEI,
ShowInfo: true, ShowInfo: true,
ModelShow: strings.ReplaceAll(url.QueryEscape(modelShow), "+", "%20"), ModelShow: strings.ReplaceAll(url.QueryEscape(modelShow), "+", "%20"),
RecoverDefault: modelShow == "", RecoverDefault: modelShow == "",

View File

@ -1,25 +1,19 @@
package client package client
import ( import (
"bytes"
"crypto/md5"
"fmt" "fmt"
"math"
"math/rand" protobuf "github.com/segmentio/encoding/proto"
"strconv"
"strings" "github.com/Mrs4s/MiraiGo/internal/packets"
"time"
"github.com/pkg/errors" "github.com/pkg/errors"
"google.golang.org/protobuf/proto"
"github.com/Mrs4s/MiraiGo/binary" "github.com/Mrs4s/MiraiGo/binary"
"github.com/Mrs4s/MiraiGo/client/internal/highway"
"github.com/Mrs4s/MiraiGo/client/internal/network"
"github.com/Mrs4s/MiraiGo/client/pb/longmsg" "github.com/Mrs4s/MiraiGo/client/pb/longmsg"
"github.com/Mrs4s/MiraiGo/client/pb/msg"
"github.com/Mrs4s/MiraiGo/client/pb/multimsg" "github.com/Mrs4s/MiraiGo/client/pb/multimsg"
"github.com/Mrs4s/MiraiGo/internal/proto" "github.com/Mrs4s/MiraiGo/internal/protobuf/data/msg"
"github.com/Mrs4s/MiraiGo/message"
"github.com/Mrs4s/MiraiGo/utils" "github.com/Mrs4s/MiraiGo/utils"
) )
@ -30,6 +24,7 @@ func init() {
// MultiMsg.ApplyUp // MultiMsg.ApplyUp
func (c *QQClient) buildMultiApplyUpPacket(data, hash []byte, buType int32, groupUin int64) (uint16, []byte) { func (c *QQClient) buildMultiApplyUpPacket(data, hash []byte, buType int32, groupUin int64) (uint16, []byte) {
seq := c.nextSeq()
req := &multimsg.MultiReqBody{ req := &multimsg.MultiReqBody{
Subcmd: 1, Subcmd: 1,
TermType: 5, TermType: 5,
@ -47,13 +42,14 @@ func (c *QQClient) buildMultiApplyUpPacket(data, hash []byte, buType int32, grou
BuType: buType, BuType: buType,
} }
payload, _ := proto.Marshal(req) payload, _ := proto.Marshal(req)
return c.uniPacket("MultiMsg.ApplyUp", payload) packet := packets.BuildUniPacket(c.Uin, seq, "MultiMsg.ApplyUp", 1, c.OutGoingPacketSessionId, EmptyBytes, c.sigInfo.d2Key, payload)
return seq, packet
} }
// MultiMsg.ApplyUp // MultiMsg.ApplyUp
func decodeMultiApplyUpResponse(_ *QQClient, pkt *network.Packet) (any, error) { func decodeMultiApplyUpResponse(_ *QQClient, _ *incomingPacketInfo, payload []byte) (interface{}, error) {
body := multimsg.MultiRspBody{} body := multimsg.MultiRspBody{}
if err := proto.Unmarshal(pkt.Payload, &body); err != nil { if err := proto.Unmarshal(payload, &body); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
if len(body.MultimsgApplyupRsp) == 0 { if len(body.MultimsgApplyupRsp) == 0 {
@ -71,6 +67,7 @@ func decodeMultiApplyUpResponse(_ *QQClient, pkt *network.Packet) (any, error) {
// MultiMsg.ApplyDown // MultiMsg.ApplyDown
func (c *QQClient) buildMultiApplyDownPacket(resID string) (uint16, []byte) { func (c *QQClient) buildMultiApplyDownPacket(resID string) (uint16, []byte) {
seq := c.nextSeq()
req := &multimsg.MultiReqBody{ req := &multimsg.MultiReqBody{
Subcmd: 2, Subcmd: 2,
TermType: 5, TermType: 5,
@ -87,34 +84,26 @@ func (c *QQClient) buildMultiApplyDownPacket(resID string) (uint16, []byte) {
ReqChannelType: 2, ReqChannelType: 2,
} }
payload, _ := proto.Marshal(req) payload, _ := proto.Marshal(req)
return c.uniPacket("MultiMsg.ApplyDown", payload) packet := packets.BuildUniPacket(c.Uin, seq, "MultiMsg.ApplyDown", 1, c.OutGoingPacketSessionId, EmptyBytes, c.sigInfo.d2Key, payload)
return seq, packet
} }
// MultiMsg.ApplyDown // MultiMsg.ApplyDown
func decodeMultiApplyDownResponse(_ *QQClient, pkt *network.Packet) (any, error) { func decodeMultiApplyDownResponse(_ *QQClient, _ *incomingPacketInfo, payload []byte) (interface{}, error) {
body := multimsg.MultiRspBody{} body := multimsg.MultiRspBody{}
if err := proto.Unmarshal(pkt.Payload, &body); err != nil { if err := proto.Unmarshal(payload, &body); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
if len(body.MultimsgApplydownRsp) == 0 { if len(body.MultimsgApplydownRsp) == 0 {
return nil, errors.New("message not found") return nil, errors.New("not found")
} }
rsp := body.MultimsgApplydownRsp[0] rsp := body.MultimsgApplydownRsp[0]
prefix := func() string {
if rsp.ThumbDownPara == nil { if rsp.MsgExternInfo != nil && rsp.MsgExternInfo.ChannelType == 2 {
return nil, errors.New("message not found") return "https://ssl.htdata.qq.com"
}
var prefix string
if rsp.MsgExternInfo != nil && rsp.MsgExternInfo.ChannelType == 2 {
prefix = "https://ssl.htdata.qq.com"
} else {
ma := body.MultimsgApplydownRsp[0]
if len(rsp.Uint32DownIp) == 0 || len(ma.Uint32DownPort) == 0 {
return nil, errors.New("message not found")
} }
prefix = fmt.Sprintf("http://%s:%d", binary.UInt32ToIPV4Address(uint32(rsp.Uint32DownIp[0])), ma.Uint32DownPort[0]) return fmt.Sprintf("http://%s:%d", binary.UInt32ToIPV4Address(uint32(rsp.Uint32DownIp[0])), body.MultimsgApplydownRsp[0].Uint32DownPort[0])
} }()
b, err := utils.HttpGetBytes(fmt.Sprintf("%s%s", prefix, string(rsp.ThumbDownPara)), "") b, err := utils.HttpGetBytes(fmt.Sprintf("%s%s", prefix, string(rsp.ThumbDownPara)), "")
if err != nil { if err != nil {
return nil, errors.Wrap(err, "failed to download by multi apply down") return nil, errors.Wrap(err, "failed to download by multi apply down")
@ -140,186 +129,8 @@ func decodeMultiApplyDownResponse(_ *QQClient, pkt *network.Packet) (any, error)
} }
uc := binary.GZipUncompress(msgContent) uc := binary.GZipUncompress(msgContent)
mt := msg.PbMultiMsgTransmit{} mt := msg.PbMultiMsgTransmit{}
if err = proto.Unmarshal(uc, &mt); err != nil { if err = protobuf.Unmarshal(uc, &mt); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
return &mt, nil return &mt, nil
} }
type forwardMsgLinker struct {
items map[string]*msg.PbMultiMsgItem
}
func (l *forwardMsgLinker) link(name string) *message.ForwardMessage {
item := l.items[name]
if item == nil {
return nil
}
nodes := make([]*message.ForwardNode, 0, len(item.Buffer.Msg))
for _, m := range item.Buffer.Msg {
name := m.Head.FromNick.Unwrap()
if m.Head.MsgType.Unwrap() == 82 && m.Head.GroupInfo != nil {
name = m.Head.GroupInfo.GroupCard.Unwrap()
}
msgElems := message.ParseMessageElems(m.Body.RichText.Elems)
for i, elem := range msgElems {
if forward, ok := elem.(*message.ForwardElement); ok {
if forward.FileName != "" {
msgElems[i] = l.link(forward.FileName) // 递归处理嵌套转发
}
}
}
gid := int64(0) // 给群号一个缺省值0防止在读合并转发的私聊内容时候会报错
if m.Head.GroupInfo != nil {
gid = m.Head.GroupInfo.GroupCode.Unwrap()
}
nodes = append(nodes, &message.ForwardNode{
GroupId: gid,
SenderId: m.Head.FromUin.Unwrap(),
SenderName: name,
Time: m.Head.MsgTime.Unwrap(),
Message: msgElems,
})
}
return &message.ForwardMessage{Nodes: nodes}
}
func (c *QQClient) GetForwardMessage(resID string) *message.ForwardMessage {
m := c.DownloadForwardMessage(resID)
if m == nil {
return nil
}
linker := forwardMsgLinker{
items: make(map[string]*msg.PbMultiMsgItem),
}
for _, item := range m.Items {
linker.items[item.FileName.Unwrap()] = item
}
return linker.link("MultiMsg")
}
func (c *QQClient) DownloadForwardMessage(resId string) *message.ForwardElement {
i, err := c.sendAndWait(c.buildMultiApplyDownPacket(resId))
if err != nil {
return nil
}
multiMsg := i.(*msg.PbMultiMsgTransmit)
if multiMsg.PbItemList == nil {
return nil
}
var pv bytes.Buffer
for i := 0; i < int(math.Min(4, float64(len(multiMsg.Msg)))); i++ {
m := multiMsg.Msg[i]
sender := m.Head.FromNick.Unwrap()
if m.Head.MsgType.Unwrap() == 82 && m.Head.GroupInfo != nil {
sender = m.Head.GroupInfo.GroupCard.Unwrap()
}
brief := message.ToReadableString(message.ParseMessageElems(multiMsg.Msg[i].Body.RichText.Elems))
fmt.Fprintf(&pv, `<title size="26" color="#777777">%s: %s</title>`, sender, brief)
}
return genForwardTemplate(
resId, pv.String(),
fmt.Sprintf("查看 %d 条转发消息", len(multiMsg.Msg)),
time.Now().UnixNano(),
multiMsg.PbItemList,
)
}
func forwardDisplay(resID, fileName, preview, summary string) string {
sb := strings.Builder{}
sb.WriteString(`<?xml version='1.0' encoding='UTF-8'?><msg serviceID="35" templateID="1" action="viewMultiMsg" brief="[聊天记录]" `)
if resID != "" {
sb.WriteString(`m_resid="`)
sb.WriteString(resID)
sb.WriteString("\" ")
}
sb.WriteString(`m_fileName="`)
sb.WriteString(fileName)
sb.WriteString(`" tSum="3" sourceMsgId="0" url="" flag="3" adverSign="0" multiMsgFlag="0"><item layout="1"><title color="#000000" size="34">群聊的聊天记录</title> `)
sb.WriteString(preview)
sb.WriteString(`<hr></hr><summary size="26" color="#808080">`)
sb.WriteString(summary)
// todo: 私聊的聊天记录?
sb.WriteString(`</summary></item><source name="聊天记录"></source></msg>`)
return sb.String()
}
func (c *QQClient) NewForwardMessageBuilder(groupCode int64) *ForwardMessageBuilder {
return &ForwardMessageBuilder{
c: c,
groupCode: groupCode,
}
}
type ForwardMessageBuilder struct {
c *QQClient
groupCode int64
objs []*msg.PbMultiMsgItem
}
// NestedNode 返回一个嵌套转发节点,其内容将会被 Builder 重定位
func (builder *ForwardMessageBuilder) NestedNode() *message.ForwardElement {
filename := strconv.FormatInt(time.Now().UnixNano(), 10) // 大概率不会重复
return &message.ForwardElement{FileName: filename}
}
// Link 将真实的消息内容填充 reloc
func (builder *ForwardMessageBuilder) Link(reloc *message.ForwardElement, fmsg *message.ForwardMessage) {
seq := builder.c.nextGroupSeq()
m := fmsg.PackForwardMessage(seq, rand.Int31(), builder.groupCode)
builder.objs = append(builder.objs, &msg.PbMultiMsgItem{
FileName: proto.String(reloc.FileName),
Buffer: &msg.PbMultiMsgNew{
Msg: m,
},
})
reloc.Content = forwardDisplay("", reloc.FileName, fmsg.Preview(), fmt.Sprintf("查看 %d 条转发消息", fmsg.Length()))
}
// Main 最外层的转发消息, 调用该方法后即上传消息
func (builder *ForwardMessageBuilder) Main(m *message.ForwardMessage) *message.ForwardElement {
if m.Length() > 200 {
return nil
}
c := builder.c
seq := c.nextGroupSeq()
fm := m.PackForwardMessage(seq, rand.Int31(), builder.groupCode)
const filename = "MultiMsg"
builder.objs = append(builder.objs, &msg.PbMultiMsgItem{
FileName: proto.String(filename),
Buffer: &msg.PbMultiMsgNew{
Msg: fm,
},
})
trans := &msg.PbMultiMsgTransmit{
Msg: fm,
PbItemList: builder.objs,
}
b, _ := proto.Marshal(trans)
data := binary.GZipCompress(b)
hash := md5.Sum(data)
rsp, body, err := c.multiMsgApplyUp(builder.groupCode, data, hash[:], 2)
if err != nil {
return nil
}
content := forwardDisplay(rsp.MsgResid, utils.RandomString(32), m.Preview(), fmt.Sprintf("查看 %d 条转发消息", m.Length()))
bodyHash := md5.Sum(body)
input := highway.Transaction{
CommandID: 27,
Ticket: rsp.MsgSig,
Body: bytes.NewReader(body),
Sum: bodyHash[:],
Size: int64(len(body)),
}
_, err = c.highwaySession.Upload(input)
if err != nil {
return nil
}
return &message.ForwardElement{
FileName: filename,
Content: content,
ResId: rsp.MsgResid,
}
}

View File

@ -2,16 +2,16 @@ package client
import ( import (
"net" "net"
"net/netip"
"runtime/debug" "runtime/debug"
"sort" "strings"
"sync" "sync"
"sync/atomic"
"time" "time"
"github.com/Mrs4s/MiraiGo/internal/packets"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/Mrs4s/MiraiGo/client/internal/network"
"github.com/Mrs4s/MiraiGo/client/internal/oicq"
"github.com/Mrs4s/MiraiGo/message" "github.com/Mrs4s/MiraiGo/message"
"github.com/Mrs4s/MiraiGo/utils" "github.com/Mrs4s/MiraiGo/utils"
) )
@ -35,121 +35,62 @@ type ConnectionQualityInfo struct {
} }
func (c *QQClient) ConnectionQualityTest() *ConnectionQualityInfo { func (c *QQClient) ConnectionQualityTest() *ConnectionQualityInfo {
if !c.Online.Load() { if !c.Online {
return nil return nil
} }
r := &ConnectionQualityInfo{} r := &ConnectionQualityInfo{}
wg := sync.WaitGroup{} wg := sync.WaitGroup{}
wg.Add(2) wg.Add(2)
go func(w *sync.WaitGroup) {
currentServerAddr := c.servers[c.currServerIndex].String()
go func() {
defer wg.Done()
var err error var err error
if r.ChatServerLatency, err = qualityTest(currentServerAddr); err != nil { if r.ChatServerLatency, err = qualityTest(c.servers[c.currServerIndex].String()); err != nil {
c.error("test chat server latency error: %v", err) c.Error("test chat server latency error: %v", err)
r.ChatServerLatency = 9999 r.ChatServerLatency = 9999
} }
if addr, err := net.ResolveIPAddr("ip", "ssl.htdata.qq.com"); err == nil { if addr, err := net.ResolveIPAddr("ip", "ssl.htdata.qq.com"); err == nil {
if r.LongMessageServerLatency, err = qualityTest((&net.TCPAddr{IP: addr.IP, Port: 443}).String()); err != nil { if r.LongMessageServerLatency, err = qualityTest((&net.TCPAddr{IP: addr.IP, Port: 443}).String()); err != nil {
c.error("test long message server latency error: %v", err) c.Error("test long message server latency error: %v", err)
r.LongMessageServerLatency = 9999 r.LongMessageServerLatency = 9999
} }
} else { } else {
c.error("resolve long message server error: %v", err) c.Error("resolve long message server error: %v", err)
r.LongMessageServerLatency = 9999 r.LongMessageServerLatency = 9999
} }
if c.highwaySession.AddrLength() > 0 { if len(c.srvSsoAddrs) > 0 {
if r.SrvServerLatency, err = qualityTest(c.highwaySession.SsoAddr[0].String()); err != nil { if r.SrvServerLatency, err = qualityTest(c.srvSsoAddrs[0]); err != nil {
c.error("test srv server latency error: %v", err) c.Error("test srv server latency error: %v", err)
r.SrvServerLatency = 9999 r.SrvServerLatency = 9999
} }
} }
}()
go func() { w.Done()
defer wg.Done() }(&wg)
res := utils.RunTCPPingLoop(currentServerAddr, 10) go func(w *sync.WaitGroup) {
res := utils.RunICMPPingLoop(&net.IPAddr{IP: c.servers[c.currServerIndex].IP}, 10)
r.ChatServerPacketLoss = res.PacketsLoss r.ChatServerPacketLoss = res.PacketsLoss
if c.highwaySession.AddrLength() > 0 { if len(c.srvSsoAddrs) > 0 {
res = utils.RunTCPPingLoop(c.highwaySession.SsoAddr[0].String(), 10) res = utils.RunICMPPingLoop(&net.IPAddr{IP: net.ParseIP(strings.Split(c.srvSsoAddrs[0], ":")[0])}, 10)
r.SrvServerPacketLoss = res.PacketsLoss r.SrvServerPacketLoss = res.PacketsLoss
} }
}() w.Done()
}(&wg)
start := time.Now() start := time.Now()
if _, err := utils.HttpGetBytes("https://ssl.htdata.qq.com", ""); err == nil { if _, err := utils.HttpGetBytes("https://ssl.htdata.qq.com", ""); err == nil {
r.LongMessageServerResponseLatency = time.Since(start).Milliseconds() r.LongMessageServerResponseLatency = time.Now().Sub(start).Milliseconds()
} else { } else {
c.error("test long message server response latency error: %v", err) c.Error("test long message server response latency error: %v", err)
r.LongMessageServerResponseLatency = 9999 r.LongMessageServerResponseLatency = 9999
} }
wg.Wait() wg.Wait()
return r return r
} }
func (c *QQClient) initServers() {
if c.Device() == nil {
// must have device. Use c.UseDevice to set it!
panic("client device is nil")
}
sso, err := getSSOAddress(c.Device())
if err == nil && len(sso) > 0 {
c.servers = append(sso, c.servers...)
}
adds, err := net.LookupIP("msfwifi.3g.qq.com") // host servers
if err == nil && len(adds) > 0 {
var hostAddrs []netip.AddrPort
for _, addr := range adds {
ip, ok := netip.AddrFromSlice(addr.To4())
if ok {
hostAddrs = append(hostAddrs, netip.AddrPortFrom(ip, 8080))
}
}
c.servers = append(hostAddrs, c.servers...)
}
if len(c.servers) == 0 {
c.servers = []netip.AddrPort{ // default servers
netip.AddrPortFrom(netip.AddrFrom4([4]byte{42, 81, 172, 81}), 80),
netip.AddrPortFrom(netip.AddrFrom4([4]byte{114, 221, 148, 59}), 14000),
netip.AddrPortFrom(netip.AddrFrom4([4]byte{42, 81, 172, 147}), 443),
netip.AddrPortFrom(netip.AddrFrom4([4]byte{125, 94, 60, 146}), 80),
netip.AddrPortFrom(netip.AddrFrom4([4]byte{114, 221, 144, 215}), 80),
netip.AddrPortFrom(netip.AddrFrom4([4]byte{42, 81, 172, 22}), 80),
}
}
pings := make([]int64, len(c.servers))
wg := sync.WaitGroup{}
wg.Add(len(c.servers))
for i := range c.servers {
go func(index int) {
defer wg.Done()
p, err := qualityTest(c.servers[index].String())
if err != nil {
pings[index] = 9999
return
}
pings[index] = p
}(i)
}
wg.Wait()
sort.Slice(c.servers, func(i, j int) bool {
return pings[i] < pings[j]
})
if len(c.servers) > 3 {
c.servers = c.servers[0 : len(c.servers)/2] // 保留ping值中位数以上的server
}
}
// connect 连接到 QQClient.servers 中的服务器 // connect 连接到 QQClient.servers 中的服务器
func (c *QQClient) connect() error { func (c *QQClient) connect() error {
// init qq servers c.Info("connect to server: %v", c.servers[c.currServerIndex].String())
c.initServerOnce.Do(c.initServers) err := c.TCP.Connect(c.servers[c.currServerIndex])
addr := c.servers[c.currServerIndex].String()
c.info("connect to server: %v", addr)
err := c.TCP.Connect(addr)
c.currServerIndex++ c.currServerIndex++
if c.currServerIndex == len(c.servers) { if c.currServerIndex == len(c.servers) {
c.currServerIndex = 0 c.currServerIndex = 0
@ -159,24 +100,24 @@ func (c *QQClient) connect() error {
if c.retryTimes > len(c.servers) { if c.retryTimes > len(c.servers) {
return errors.New("All servers are unreachable") return errors.New("All servers are unreachable")
} }
c.error("connect server error: %v", err) c.Error("connect server error: %v", err)
return err return err
} }
c.once.Do(func() { c.once.Do(func() {
c.GroupMessageEvent.Subscribe(func(_ *QQClient, _ *message.GroupMessage) { c.OnGroupMessage(func(_ *QQClient, _ *message.GroupMessage) {
c.stat.MessageReceived.Add(1) atomic.AddUint64(&c.stat.MessageReceived, 1)
c.stat.LastMessageTime.Store(time.Now().Unix()) atomic.StoreInt64(&c.stat.LastMessageTime, time.Now().Unix())
}) })
c.PrivateMessageEvent.Subscribe(func(_ *QQClient, _ *message.PrivateMessage) { c.OnPrivateMessage(func(_ *QQClient, _ *message.PrivateMessage) {
c.stat.MessageReceived.Add(1) atomic.AddUint64(&c.stat.MessageReceived, 1)
c.stat.LastMessageTime.Store(time.Now().Unix()) atomic.StoreInt64(&c.stat.LastMessageTime, time.Now().Unix())
}) })
c.TempMessageEvent.Subscribe(func(_ *QQClient, _ *TempMessageEvent) { c.OnTempMessage(func(_ *QQClient, _ *TempMessageEvent) {
c.stat.MessageReceived.Add(1) atomic.AddUint64(&c.stat.MessageReceived, 1)
c.stat.LastMessageTime.Store(time.Now().Unix()) atomic.StoreInt64(&c.stat.LastMessageTime, time.Now().Unix())
}) })
c.onGroupMessageReceipt("internal", func(_ *QQClient, _ *groupMessageReceiptEvent) { c.onGroupMessageReceipt("internal", func(_ *QQClient, _ *groupMessageReceiptEvent) {
c.stat.MessageSent.Add(1) atomic.AddUint64(&c.stat.MessageSent, 1)
}) })
go c.netLoop() go c.netLoop()
}) })
@ -190,38 +131,38 @@ func (c *QQClient) quickReconnect() {
c.Disconnect() c.Disconnect()
time.Sleep(time.Millisecond * 200) time.Sleep(time.Millisecond * 200)
if err := c.connect(); err != nil { if err := c.connect(); err != nil {
c.error("connect server error: %v", err) c.Error("connect server error: %v", err)
c.DisconnectedEvent.dispatch(c, &ClientDisconnectedEvent{Message: "quick reconnect failed"}) c.dispatchDisconnectEvent(&ClientDisconnectedEvent{Message: "quick reconnect failed"})
return return
} }
if err := c.registerClient(); err != nil { if err := c.registerClient(); err != nil {
c.error("register client failed: %v", err) c.Error("register client failed: %v", err)
c.Disconnect() c.Disconnect()
c.DisconnectedEvent.dispatch(c, &ClientDisconnectedEvent{Message: "register error"}) c.dispatchDisconnectEvent(&ClientDisconnectedEvent{Message: "register error"})
return return
} }
} }
// Disconnect 中断连接, 不释放资源 // Disconnect 中断连接, 不释放资源
func (c *QQClient) Disconnect() { func (c *QQClient) Disconnect() {
c.Online.Store(false) c.Online = false
c.TCP.Close() c.TCP.Close()
} }
// sendAndWait 向服务器发送一个数据包, 并等待返回 // sendAndWait 向服务器发送一个数据包, 并等待返回
func (c *QQClient) sendAndWait(seq uint16, pkt []byte, params ...network.RequestParams) (any, error) { func (c *QQClient) sendAndWait(seq uint16, pkt []byte, params ...requestParams) (interface{}, error) {
type T struct { type T struct {
Response any Response interface{}
Error error Error error
} }
ch := make(chan T, 1) ch := make(chan T, 1)
var p network.RequestParams var p requestParams
if len(params) != 0 { if len(params) != 0 {
p = params[0] p = params[0]
} }
c.handlers.Store(seq, &handlerInfo{fun: func(i any, err error) { c.handlers.Store(seq, &handlerInfo{fun: func(i interface{}, err error) {
ch <- T{ ch <- T{
Response: i, Response: i,
Error: err, Error: err,
@ -255,9 +196,9 @@ func (c *QQClient) sendAndWait(seq uint16, pkt []byte, params ...network.Request
func (c *QQClient) sendPacket(pkt []byte) error { func (c *QQClient) sendPacket(pkt []byte) error {
err := c.TCP.Write(pkt) err := c.TCP.Write(pkt)
if err != nil { if err != nil {
c.stat.PacketLost.Add(1) atomic.AddUint64(&c.stat.PacketLost, 1)
} else { } else {
c.stat.PacketSent.Add(1) atomic.AddUint64(&c.stat.PacketSent, 1)
} }
return errors.Wrap(err, "Packet failed to sendPacket") return errors.Wrap(err, "Packet failed to sendPacket")
} }
@ -265,7 +206,7 @@ func (c *QQClient) sendPacket(pkt []byte) error {
// waitPacket // waitPacket
// 等待一个或多个数据包解析, 优先级低于 sendAndWait // 等待一个或多个数据包解析, 优先级低于 sendAndWait
// 返回终止解析函数 // 返回终止解析函数
func (c *QQClient) waitPacket(cmd string, f func(any, error)) func() { func (c *QQClient) waitPacket(cmd string, f func(interface{}, error)) func() {
c.waiters.Store(cmd, f) c.waiters.Store(cmd, f)
return func() { return func() {
c.waiters.Delete(cmd) c.waiters.Delete(cmd)
@ -274,9 +215,9 @@ func (c *QQClient) waitPacket(cmd string, f func(any, error)) func() {
// waitPacketTimeoutSyncF // waitPacketTimeoutSyncF
// 等待一个数据包解析, 优先级低于 sendAndWait // 等待一个数据包解析, 优先级低于 sendAndWait
func (c *QQClient) waitPacketTimeoutSyncF(cmd string, timeout time.Duration, filter func(any) bool) (r any, e error) { func (c *QQClient) waitPacketTimeoutSyncF(cmd string, timeout time.Duration, filter func(interface{}) bool) (r interface{}, e error) {
notifyChan := make(chan bool, 4) notifyChan := make(chan bool)
defer c.waitPacket(cmd, func(i any, err error) { defer c.waitPacket(cmd, func(i interface{}, err error) {
if filter(i) { if filter(i) {
r = i r = i
e = err e = err
@ -295,7 +236,7 @@ func (c *QQClient) waitPacketTimeoutSyncF(cmd string, timeout time.Duration, fil
// 发送数据包并返回需要解析的 response // 发送数据包并返回需要解析的 response
func (c *QQClient) sendAndWaitDynamic(seq uint16, pkt []byte) ([]byte, error) { func (c *QQClient) sendAndWaitDynamic(seq uint16, pkt []byte) ([]byte, error) {
ch := make(chan []byte, 1) ch := make(chan []byte, 1)
c.handlers.Store(seq, &handlerInfo{fun: func(i any, err error) { ch <- i.([]byte) }, dynamic: true}) c.handlers.Store(seq, &handlerInfo{fun: func(i interface{}, err error) { ch <- i.([]byte) }, dynamic: true})
err := c.sendPacket(pkt) err := c.sendPacket(pkt)
if err != nil { if err != nil {
c.handlers.Delete(seq) c.handlers.Delete(seq)
@ -310,34 +251,27 @@ func (c *QQClient) sendAndWaitDynamic(seq uint16, pkt []byte) ([]byte, error) {
} }
} }
// SendSsoPacket
// 发送签名回调包给服务器并获取返回结果供提交
func (c *QQClient) SendSsoPacket(cmd string, body []byte) ([]byte, error) {
seq, data := c.uniPacket(cmd, body)
return c.sendAndWaitDynamic(seq, data)
}
// plannedDisconnect 计划中断线事件 // plannedDisconnect 计划中断线事件
func (c *QQClient) plannedDisconnect(_ *network.TCPClient) { func (c *QQClient) plannedDisconnect(_ *utils.TCPListener) {
c.debug("planned disconnect.") c.Debug("planned disconnect.")
c.stat.DisconnectTimes.Add(1) atomic.AddUint32(&c.stat.DisconnectTimes, 1)
c.Online.Store(false) c.Online = false
} }
// unexpectedDisconnect 非预期断线事件 // unexpectedDisconnect 非预期断线事件
func (c *QQClient) unexpectedDisconnect(_ *network.TCPClient, e error) { func (c *QQClient) unexpectedDisconnect(_ *utils.TCPListener, e error) {
c.error("unexpected disconnect: %v", e) c.Error("unexpected disconnect: %v", e)
c.stat.DisconnectTimes.Add(1) atomic.AddUint32(&c.stat.DisconnectTimes, 1)
c.Online.Store(false) c.Online = false
if err := c.connect(); err != nil { if err := c.connect(); err != nil {
c.error("connect server error: %v", err) c.Error("connect server error: %v", err)
c.DisconnectedEvent.dispatch(c, &ClientDisconnectedEvent{Message: "connection dropped by server."}) c.dispatchDisconnectEvent(&ClientDisconnectedEvent{Message: "connection dropped by server."})
return return
} }
if err := c.registerClient(); err != nil { if err := c.registerClient(); err != nil {
c.error("register client failed: %v", err) c.Error("register client failed: %v", err)
c.Disconnect() c.Disconnect()
c.DisconnectedEvent.dispatch(c, &ClientDisconnectedEvent{Message: "register error"}) c.dispatchDisconnectEvent(&ClientDisconnectedEvent{Message: "register error"})
return return
} }
} }
@ -352,7 +286,7 @@ func (c *QQClient) netLoop() {
continue continue
} }
if l < 4 || l > 1024*1024*10 { // max 10MB if l < 4 || l > 1024*1024*10 { // max 10MB
c.error("parse incoming packet error: invalid packet length %v", l) c.Error("parse incoming packet error: invalid packet length %v", l)
errCount++ errCount++
if errCount > 2 { if errCount > 2 {
go c.quickReconnect() go c.quickReconnect()
@ -360,13 +294,12 @@ func (c *QQClient) netLoop() {
continue continue
} }
data, _ := c.TCP.ReadBytes(int(l) - 4) data, _ := c.TCP.ReadBytes(int(l) - 4)
resp, err := c.transport.ReadResponse(data) pkt, err := packets.ParseIncomingPacket(data, c.sigInfo.d2Key)
// pkt, err := packets.ParseIncomingPacket(data, c.sig.D2Key)
if err != nil { if err != nil {
c.error("parse incoming packet error: %v", err) c.Error("parse incoming packet error: %v", err)
if errors.Is(err, network.ErrSessionExpired) || errors.Is(err, network.ErrPacketDropped) { if errors.Is(err, packets.ErrSessionExpired) || errors.Is(err, packets.ErrPacketDropped) {
c.Disconnect() c.Disconnect()
go c.DisconnectedEvent.dispatch(c, &ClientDisconnectedEvent{Message: "session expired"}) go c.dispatchDisconnectEvent(&ClientDisconnectedEvent{Message: "session expired"})
continue continue
} }
errCount++ errCount++
@ -375,55 +308,53 @@ func (c *QQClient) netLoop() {
} }
continue continue
} }
if resp.EncryptType == network.EncryptTypeEmptyKey { if pkt.Flag2 == 2 {
m, err := c.oicq.Unmarshal(resp.Body) pkt.Payload, err = pkt.DecryptPayload(c.ecdh.InitialShareKey, c.RandomKey, c.sigInfo.wtSessionTicketKey)
if err != nil { if err != nil {
c.error("decrypt payload error: %v", err) c.Error("decrypt payload error: %v", err)
if errors.Is(err, oicq.ErrUnknownFlag) {
go c.quickReconnect()
}
continue continue
} }
resp.Body = m.Body
} }
errCount = 0 errCount = 0
c.debug("rev pkt: %v seq: %v", resp.CommandName, resp.SequenceID) c.Debug("rev pkt: %v seq: %v", pkt.CommandName, pkt.SequenceId)
c.stat.PacketReceived.Add(1) atomic.AddUint64(&c.stat.PacketReceived, 1)
pkt := &network.Packet{ go func(pkt *packets.IncomingPacket) {
SequenceId: uint16(resp.SequenceID),
CommandName: resp.CommandName,
Payload: resp.Body,
}
go func(pkt *network.Packet) {
defer func() { defer func() {
if pan := recover(); pan != nil { if pan := recover(); pan != nil {
c.error("panic on decoder %v : %v\n%s", pkt.CommandName, pan, debug.Stack()) c.Error("panic on decoder %v : %v\n%s", pkt.CommandName, pan, debug.Stack())
c.dump("packet decode error: %v - %v", pkt.Payload, pkt.CommandName, pan)
} }
}() }()
if decoder, ok := decoders[pkt.CommandName]; ok { if decoder, ok := decoders[pkt.CommandName]; ok {
// found predefined decoder // found predefined decoder
info, ok := c.handlers.LoadAndDelete(pkt.SequenceId) info, ok := c.handlers.LoadAndDelete(pkt.SequenceId)
var decoded any var decoded interface{}
decoded = pkt.Payload decoded = pkt.Payload
if info == nil || !info.dynamic { if info == nil || !info.dynamic {
pkt.Params = info.getParams() decoded, err = decoder(c, &incomingPacketInfo{
decoded, err = decoder(c, pkt) SequenceId: pkt.SequenceId,
CommandName: pkt.CommandName,
Params: func() requestParams {
if !ok {
return nil
}
return info.params
}(),
}, pkt.Payload)
if err != nil { if err != nil {
c.debug("decode pkt %v error: %+v", pkt.CommandName, err) c.Debug("decode pkt %v error: %+v", pkt.CommandName, err)
} }
} }
if ok { if ok {
info.fun(decoded, err) info.fun(decoded, err)
} else if f, ok := c.waiters.Load(pkt.CommandName); ok { // 在不存在handler的情况下触发wait } else if f, ok := c.waiters.Load(pkt.CommandName); ok { // 在不存在handler的情况下触发wait
f(decoded, err) f.(func(interface{}, error))(decoded, err)
} }
} else if f, ok := c.handlers.LoadAndDelete(pkt.SequenceId); ok { } else if f, ok := c.handlers.LoadAndDelete(pkt.SequenceId); ok {
// does not need decoder // does not need decoder
f.fun(pkt.Payload, nil) f.fun(pkt.Payload, nil)
} else { } else {
c.debug("Unhandled Command: %s\nSeq: %d\nThis message can be ignored.", pkt.CommandName, pkt.SequenceId) c.Debug("Unhandled Command: %s\nSeq: %d\nThis message can be ignored.", pkt.CommandName, pkt.SequenceId)
} }
}(pkt) }(pkt)
} }

View File

@ -62,7 +62,7 @@ func (c *QQClient) grayTipProcessor(groupCode int64, tipInfo *notify.GeneralGray
} }
} }
if sender != 0 { if sender != 0 {
c.GroupNotifyEvent.dispatch(c, &GroupPokeNotifyEvent{ c.dispatchGroupNotifyEvent(&GroupPokeNotifyEvent{
GroupCode: groupCode, GroupCode: groupCode,
Sender: sender, Sender: sender,
Receiver: receiver, Receiver: receiver,
@ -81,7 +81,7 @@ func (c *QQClient) grayTipProcessor(groupCode int64, tipInfo *notify.GeneralGray
uin, _ = strconv.ParseInt(templ.Value, 10, 64) uin, _ = strconv.ParseInt(templ.Value, 10, 64)
} }
} }
c.GroupNotifyEvent.dispatch(c, &MemberHonorChangedNotifyEvent{ c.dispatchGroupNotifyEvent(&MemberHonorChangedNotifyEvent{
GroupCode: groupCode, GroupCode: groupCode,
Honor: func() HonorType { Honor: func() HonorType {
switch tipInfo.TemplId { switch tipInfo.TemplId {
@ -127,7 +127,8 @@ func (c *QQClient) msgGrayTipProcessor(groupCode int64, tipInfo *notify.AIOGrayT
} }
} }
// 好像只能这么判断 // 好像只能这么判断
if strings.Contains(content, "头衔") { switch {
case strings.Contains(content, "头衔"):
event := &MemberSpecialTitleUpdatedEvent{GroupCode: groupCode} event := &MemberSpecialTitleUpdatedEvent{GroupCode: groupCode}
for _, cmd := range tipCmds { for _, cmd := range tipCmds {
if cmd.Command == 5 { if cmd.Command == 5 {
@ -138,13 +139,13 @@ func (c *QQClient) msgGrayTipProcessor(groupCode int64, tipInfo *notify.AIOGrayT
} }
} }
if event.Uin == 0 { if event.Uin == 0 {
c.error("process special title updated tips error: missing cmd") c.Error("process special title updated tips error: missing cmd")
return return
} }
if mem := c.FindGroup(groupCode).FindMember(event.Uin); mem != nil { if mem := c.FindGroup(groupCode).FindMember(event.Uin); mem != nil {
mem.SpecialTitle = event.NewTitle mem.SpecialTitle = event.NewTitle
} }
c.MemberSpecialTitleUpdatedEvent.dispatch(c, event) c.dispatchMemberSpecialTitleUpdateEvent(event)
} }
} }
@ -184,7 +185,6 @@ func (e *MemberHonorChangedNotifyEvent) Content() string {
return fmt.Sprintf("%s(%d) 在群 %d 里连续发消息超过7天, 获得 群聊之火 标识。", e.Nick, e.Uin, e.GroupCode) return fmt.Sprintf("%s(%d) 在群 %d 里连续发消息超过7天, 获得 群聊之火 标识。", e.Nick, e.Uin, e.GroupCode)
case Emotion: case Emotion:
return fmt.Sprintf("%s(%d) 在群聊 %d 中连续发表情包超过3天且累计数量超过20条获得 快乐源泉 标识。", e.Nick, e.Uin, e.GroupCode) return fmt.Sprintf("%s(%d) 在群聊 %d 中连续发表情包超过3天且累计数量超过20条获得 快乐源泉 标识。", e.Nick, e.Uin, e.GroupCode)
default:
return "ERROR"
} }
return "ERROR"
} }

View File

@ -1,11 +1,11 @@
package client package client
import ( import (
"github.com/Mrs4s/MiraiGo/internal/packets"
"github.com/pkg/errors" "github.com/pkg/errors"
"google.golang.org/protobuf/proto"
"github.com/Mrs4s/MiraiGo/client/internal/network"
"github.com/Mrs4s/MiraiGo/client/pb/cmd0x346" "github.com/Mrs4s/MiraiGo/client/pb/cmd0x346"
"github.com/Mrs4s/MiraiGo/internal/proto"
) )
func init() { func init() {
@ -29,22 +29,22 @@ func (c *QQClient) buildOfflineFileDownloadRequestPacket(uuid []byte) (uint16, [
}, },
} }
payload, _ := proto.Marshal(req) payload, _ := proto.Marshal(req)
packet := c.uniPacketWithSeq(seq, "OfflineFilleHandleSvr.pb_ftn_CMD_REQ_APPLY_DOWNLOAD-1200", payload) packet := packets.BuildUniPacket(c.Uin, seq, "OfflineFilleHandleSvr.pb_ftn_CMD_REQ_APPLY_DOWNLOAD-1200", 1, c.OutGoingPacketSessionId, EmptyBytes, c.sigInfo.d2Key, payload)
return seq, packet return seq, packet
} }
func decodeOfflineFileDownloadResponse(c *QQClient, pkt *network.Packet) (any, error) { func decodeOfflineFileDownloadResponse(c *QQClient, _ *incomingPacketInfo, payload []byte) (interface{}, error) {
rsp := cmd0x346.C346RspBody{} rsp := cmd0x346.C346RspBody{}
if err := proto.Unmarshal(pkt.Payload, &rsp); err != nil { if err := proto.Unmarshal(payload, &rsp); err != nil {
c.error("unmarshal cmd0x346 rsp body error: %v", err) c.Error("unmarshal cmd0x346 rsp body error: %v", err)
return nil, errors.Wrap(err, "unmarshal cmd0x346 rsp body error") return nil, errors.Wrap(err, "unmarshal cmd0x346 rsp body error")
} }
if rsp.ApplyDownloadRsp == nil { if rsp.ApplyDownloadRsp == nil {
c.error("decode apply download 1200 error: apply rsp is nil.") c.Error("decode apply download 1200 error: apply rsp is nil.")
return nil, errors.New("apply rsp is nil") return nil, errors.New("apply rsp is nil")
} }
if rsp.ApplyDownloadRsp.RetCode != 0 { if rsp.ApplyDownloadRsp.RetCode != 0 {
c.error("decode apply download 1200 error: %v", rsp.ApplyDownloadRsp.RetCode) c.Error("decode apply download 1200 error: %v", rsp.ApplyDownloadRsp.RetCode)
return nil, errors.Errorf("apply download rsp error: %d", rsp.ApplyDownloadRsp.RetCode) return nil, errors.Errorf("apply download rsp error: %d", rsp.ApplyDownloadRsp.RetCode)
} }
return "http://" + rsp.ApplyDownloadRsp.DownloadInfo.DownloadDomain + rsp.ApplyDownloadRsp.DownloadInfo.DownloadUrl, nil return "http://" + rsp.ApplyDownloadRsp.DownloadInfo.DownloadDomain + rsp.ApplyDownloadRsp.DownloadInfo.DownloadUrl, nil

View File

@ -5,15 +5,15 @@ import (
"strconv" "strconv"
"time" "time"
"github.com/Mrs4s/MiraiGo/client/pb/msgtype0x210"
"github.com/pkg/errors" "github.com/pkg/errors"
"google.golang.org/protobuf/proto"
"github.com/Mrs4s/MiraiGo/binary" "github.com/Mrs4s/MiraiGo/binary"
"github.com/Mrs4s/MiraiGo/binary/jce" "github.com/Mrs4s/MiraiGo/binary/jce"
"github.com/Mrs4s/MiraiGo/client/internal/network"
"github.com/Mrs4s/MiraiGo/client/pb" "github.com/Mrs4s/MiraiGo/client/pb"
"github.com/Mrs4s/MiraiGo/client/pb/msgtype0x210"
"github.com/Mrs4s/MiraiGo/client/pb/notify" "github.com/Mrs4s/MiraiGo/client/pb/notify"
"github.com/Mrs4s/MiraiGo/internal/proto"
) )
var msg0x210Decoders = map[int64]func(*QQClient, []byte) error{ var msg0x210Decoders = map[int64]func(*QQClient, []byte) error{
@ -23,21 +23,22 @@ var msg0x210Decoders = map[int64]func(*QQClient, []byte) error{
} }
// OnlinePush.ReqPush // OnlinePush.ReqPush
func decodeOnlinePushReqPacket(c *QQClient, pkt *network.Packet) (any, error) { func decodeOnlinePushReqPacket(c *QQClient, info *incomingPacketInfo, payload []byte) (interface{}, error) {
request := &jce.RequestPacket{} request := &jce.RequestPacket{}
request.ReadFrom(jce.NewJceReader(pkt.Payload)) request.ReadFrom(jce.NewJceReader(payload))
data := &jce.RequestDataVersion2{} data := &jce.RequestDataVersion2{}
data.ReadFrom(jce.NewJceReader(request.SBuffer)) data.ReadFrom(jce.NewJceReader(request.SBuffer))
jr := jce.NewJceReader(data.Map["req"]["OnlinePushPack.SvcReqPushMsg"][1:]) jr := jce.NewJceReader(data.Map["req"]["OnlinePushPack.SvcReqPushMsg"][1:])
msgInfos := []jce.PushMessageInfo{}
uin := jr.ReadInt64(0) uin := jr.ReadInt64(0)
msgInfos := jr.ReadPushMessageInfos(2) jr.ReadSlice(&msgInfos, 2)
_ = c.sendPacket(c.buildDeleteOnlinePushPacket(uin, 0, nil, pkt.SequenceId, msgInfos)) _ = c.sendPacket(c.buildDeleteOnlinePushPacket(uin, 0, nil, info.SequenceId, msgInfos))
for _, m := range msgInfos { for _, m := range msgInfos {
k := fmt.Sprintf("%v%v%v", m.MsgSeq, m.MsgTime, m.MsgUid) k := fmt.Sprintf("%v%v%v", m.MsgSeq, m.MsgTime, m.MsgUid)
if _, ok := c.onlinePushCache.Get(k); ok { if _, ok := c.onlinePushCache.Get(k); ok {
continue continue
} }
c.onlinePushCache.Add(k, unit{}, time.Second*30) c.onlinePushCache.Add(k, "", time.Second*30)
// 0x2dc // 0x2dc
if m.MsgType == 732 { if m.MsgType == 732 {
r := binary.NewReader(m.VMsg) r := binary.NewReader(m.VMsg)
@ -53,17 +54,7 @@ func decodeOnlinePushReqPacket(c *QQClient, pkt *network.Packet) (any, error) {
r.ReadBytes(6) r.ReadBytes(6)
target := int64(uint32(r.ReadInt32())) target := int64(uint32(r.ReadInt32()))
t := r.ReadInt32() t := r.ReadInt32()
c.dispatchGroupMuteEvent(&GroupMuteEvent{
if target != 0 {
member := c.FindGroup(groupCode).FindMember(target)
if t > 0 {
member.ShutUpTimestamp = time.Now().Add(time.Second * time.Duration(t)).Unix()
} else {
member.ShutUpTimestamp = 0
}
}
c.GroupMuteEvent.dispatch(c, &GroupMuteEvent{
GroupCode: groupCode, GroupCode: groupCode,
OperatorUin: operator, OperatorUin: operator,
TargetUin: target, TargetUin: target,
@ -78,7 +69,7 @@ func decodeOnlinePushReqPacket(c *QQClient, pkt *network.Packet) (any, error) {
if rm.MsgType == 2 { if rm.MsgType == 2 {
continue continue
} }
c.GroupMessageRecalledEvent.dispatch(c, &GroupMessageRecalledEvent{ c.dispatchGroupMessageRecalledEvent(&GroupMessageRecalledEvent{
GroupCode: groupCode, GroupCode: groupCode,
OperatorUin: b.OptMsgRecall.Uin, OperatorUin: b.OptMsgRecall.Uin,
AuthorUin: rm.AuthorUin, AuthorUin: rm.AuthorUin,
@ -92,7 +83,7 @@ func decodeOnlinePushReqPacket(c *QQClient, pkt *network.Packet) (any, error) {
} }
if b.OptMsgRedTips != nil { if b.OptMsgRedTips != nil {
if b.OptMsgRedTips.LuckyFlag == 1 { // 运气王提示 if b.OptMsgRedTips.LuckyFlag == 1 { // 运气王提示
c.GroupNotifyEvent.dispatch(c, &GroupRedBagLuckyKingNotifyEvent{ c.dispatchGroupNotifyEvent(&GroupRedBagLuckyKingNotifyEvent{
GroupCode: groupCode, GroupCode: groupCode,
Sender: int64(b.OptMsgRedTips.SenderUin), Sender: int64(b.OptMsgRedTips.SenderUin),
LuckyKing: int64(b.OptMsgRedTips.LuckyUin), LuckyKing: int64(b.OptMsgRedTips.LuckyUin),
@ -101,7 +92,7 @@ func decodeOnlinePushReqPacket(c *QQClient, pkt *network.Packet) (any, error) {
} }
if b.QqGroupDigestMsg != nil { if b.QqGroupDigestMsg != nil {
digest := b.QqGroupDigestMsg digest := b.QqGroupDigestMsg
c.GroupDigestEvent.dispatch(c, &GroupDigestEvent{ c.dispatchGroupDigestEvent(&GroupDigestEvent{
GroupCode: int64(digest.GroupCode), GroupCode: int64(digest.GroupCode),
MessageID: int32(digest.Seq), MessageID: int32(digest.Seq),
InternalMessageID: int32(digest.Random), InternalMessageID: int32(digest.Random),
@ -128,7 +119,7 @@ func decodeOnlinePushReqPacket(c *QQClient, pkt *network.Packet) (any, error) {
return nil, errors.Wrap(err, "decode online push 0x210 error") return nil, errors.Wrap(err, "decode online push 0x210 error")
} }
} else { } else {
c.debug("unknown online push 0x210 sub type 0x%v", strconv.FormatInt(subType, 16)) c.Debug("unknown online push 0x210 sub type 0x%v", strconv.FormatInt(subType, 16))
} }
} }
} }
@ -142,7 +133,7 @@ func msgType0x210Sub8ADecoder(c *QQClient, protobuf []byte) error {
} }
for _, m := range s8a.MsgInfo { for _, m := range s8a.MsgInfo {
if m.ToUin == c.Uin { if m.ToUin == c.Uin {
c.FriendMessageRecalledEvent.dispatch(c, &FriendMessageRecalledEvent{ c.dispatchFriendMessageRecalledEvent(&FriendMessageRecalledEvent{
FriendUin: m.FromUin, FriendUin: m.FromUin,
MessageId: m.MsgSeq, MessageId: m.MsgSeq,
Time: m.MsgTime, Time: m.MsgTime,
@ -162,7 +153,7 @@ func msgType0x210SubB3Decoder(c *QQClient, protobuf []byte) error {
Nickname: b3.MsgAddFrdNotify.Nick, Nickname: b3.MsgAddFrdNotify.Nick,
} }
c.FriendList = append(c.FriendList, frd) c.FriendList = append(c.FriendList, frd)
c.NewFriendEvent.dispatch(c, &NewFriendEvent{Friend: frd}) c.dispatchNewFriendEvent(&NewFriendEvent{Friend: frd})
return nil return nil
} }
@ -177,7 +168,7 @@ func msgType0x210SubD4Decoder(c *QQClient, protobuf []byte) error {
groupLeaveLock.Unlock() groupLeaveLock.Unlock()
return err return err
} }
c.GroupLeaveEvent.dispatch(c, &GroupLeaveEvent{Group: g}) c.dispatchLeaveGroupEvent(&GroupLeaveEvent{Group: g})
} }
groupLeaveLock.Unlock() groupLeaveLock.Unlock()
return nil return nil
@ -191,15 +182,15 @@ func msgType0x210Sub27Decoder(c *QQClient, protobuf []byte) error {
for _, m := range s27.ModInfos { for _, m := range s27.ModInfos {
if m.ModGroupProfile != nil { if m.ModGroupProfile != nil {
for _, info := range m.ModGroupProfile.GroupProfileInfos { for _, info := range m.ModGroupProfile.GroupProfileInfos {
if info.Field.Unwrap() == 1 { if info.GetField() == 1 {
if g := c.FindGroup(int64(m.ModGroupProfile.GroupCode.Unwrap())); g != nil { if g := c.FindGroup(int64(m.ModGroupProfile.GetGroupCode())); g != nil {
old := g.Name old := g.Name
g.Name = string(info.Value) g.Name = string(info.GetValue())
c.GroupNameUpdatedEvent.dispatch(c, &GroupNameUpdatedEvent{ c.dispatchGroupNameUpdatedEvent(&GroupNameUpdatedEvent{
Group: g, Group: g,
OldName: old, OldName: old,
NewName: g.Name, NewName: g.Name,
OperatorUin: int64(m.ModGroupProfile.CmdUin.Unwrap()), OperatorUin: int64(m.ModGroupProfile.GetCmdUin()),
}) })
} }
} }
@ -208,10 +199,6 @@ func msgType0x210Sub27Decoder(c *QQClient, protobuf []byte) error {
if m.DelFriend != nil { if m.DelFriend != nil {
frdUin := m.DelFriend.Uins[0] frdUin := m.DelFriend.Uins[0]
if frd := c.FindFriend(int64(frdUin)); frd != nil { if frd := c.FindFriend(int64(frdUin)); frd != nil {
c.DeleteFriendEvent.dispatch(c, &DeleteFriendEvent{
Uin: frd.Uin,
Nickname: frd.Nickname,
})
if err := c.ReloadFriendList(); err != nil { if err := c.ReloadFriendList(); err != nil {
return errors.Wrap(err, "failed to reload friend list") return errors.Wrap(err, "failed to reload friend list")
} }
@ -235,10 +222,7 @@ func msgType0x210Sub122Decoder(c *QQClient, protobuf []byte) error {
if sender == 0 { if sender == 0 {
return nil return nil
} }
if receiver == 0 { c.dispatchFriendNotifyEvent(&FriendPokeNotifyEvent{
receiver = c.Uin
}
c.FriendNotifyEvent.dispatch(c, &FriendPokeNotifyEvent{
Sender: sender, Sender: sender,
Receiver: receiver, Receiver: receiver,
}) })
@ -255,11 +239,11 @@ func msgType0x210Sub44Decoder(c *QQClient, protobuf []byte) error {
} }
groupJoinLock.Lock() groupJoinLock.Lock()
defer groupJoinLock.Unlock() defer groupJoinLock.Unlock()
if s44.GroupSyncMsg.GrpCode == 0 { // member sync if s44.GroupSyncMsg.GetGrpCode() != 0 { // member sync
return errors.New("invalid group code") return errors.New("invalid group code")
} }
c.debug("syncing members.") c.Debug("syncing members.")
if group := c.FindGroup(s44.GroupSyncMsg.GrpCode); group != nil { if group := c.FindGroup(s44.GroupSyncMsg.GetGrpCode()); group != nil {
group.lock.Lock() group.lock.Lock()
defer group.lock.Unlock() defer group.lock.Unlock()
@ -274,7 +258,7 @@ func msgType0x210Sub44Decoder(c *QQClient, protobuf []byte) error {
group.Members = newMem group.Members = newMem
for _, m := range newMem { for _, m := range newMem {
if lastJoinTime < m.JoinTime { if lastJoinTime < m.JoinTime {
c.GroupMemberJoinEvent.dispatch(c, &MemberJoinGroupEvent{ go c.dispatchNewMemberEvent(&MemberJoinGroupEvent{
Group: group, Group: group,
Member: m, Member: m,
}) })

View File

@ -1,44 +0,0 @@
package client
import (
"github.com/Mrs4s/MiraiGo/client/internal/network"
"github.com/Mrs4s/MiraiGo/client/internal/oicq"
)
//go:noinline
func (c *QQClient) buildOicqRequestPacket(uin int64, command uint16, body *oicq.TLV) []byte {
req := oicq.Message{
Uin: uint32(uin),
Command: command,
EncryptionMethod: oicq.EM_ECDH,
Body: body.Marshal(),
}
return c.oicq.Marshal(&req)
}
//go:noinline
func (c *QQClient) uniPacket(command string, body []byte) (uint16, []byte) {
seq := c.nextSeq()
req := network.Request{
Type: network.RequestTypeSimple,
EncryptType: network.EncryptTypeD2Key,
Uin: c.Uin,
SequenceID: int32(seq),
CommandName: command,
Body: body,
}
return seq, c.transport.PackPacket(&req)
}
//go:noinline
func (c *QQClient) uniPacketWithSeq(seq uint16, command string, body []byte) []byte {
req := network.Request{
Type: network.RequestTypeSimple,
EncryptType: network.EncryptTypeD2Key,
Uin: c.Uin,
SequenceID: int32(seq),
CommandName: command,
Body: body,
}
return c.transport.PackPacket(&req)
}

View File

@ -1,76 +0,0 @@
// Code generated by protoc-gen-golite. DO NOT EDIT.
// source: pb/channel/GuildChannelBase.proto
package channel
import (
proto "github.com/RomiChan/protobuf/proto"
)
type ChannelUserInfo struct {
ClientIdentity *ClientIdentity `protobuf:"bytes,1,opt"`
MemberType proto.Option[uint32] `protobuf:"varint,2,opt"`
Permission *ChannelUserPermission `protobuf:"bytes,3,opt"`
RoleGroups []*BaseRoleGroupInfo `protobuf:"bytes,4,rep"`
}
type ChannelUserPermission struct {
AllowReadFeed proto.Option[bool] `protobuf:"varint,1,opt"`
AllowWriteFeed proto.Option[bool] `protobuf:"varint,2,opt"`
_ [0]func()
}
type ClientIdentity struct {
ClientId proto.Option[uint32] `protobuf:"varint,1,opt"`
Desc proto.Option[string] `protobuf:"bytes,2,opt"`
_ [0]func()
}
type BaseGuildInfo struct {
GuildId proto.Option[uint64] `protobuf:"varint,1,opt"`
Name proto.Option[string] `protobuf:"bytes,2,opt"`
JoinTime proto.Option[uint64] `protobuf:"varint,3,opt"`
_ [0]func()
}
type BaseRoleGroupInfo struct {
RoleId proto.Option[uint64] `protobuf:"varint,1,opt"`
Name proto.Option[string] `protobuf:"bytes,2,opt"`
Color proto.Option[uint32] `protobuf:"varint,3,opt"`
_ [0]func()
}
type StChannelInfo struct {
Sign *StChannelSign `protobuf:"bytes,1,opt"`
Name proto.Option[string] `protobuf:"bytes,2,opt"`
IconUrl proto.Option[string] `protobuf:"bytes,3,opt"`
_ [0]func()
}
type StChannelSign struct {
GuildId proto.Option[uint64] `protobuf:"varint,1,opt"`
ChannelId proto.Option[uint64] `protobuf:"varint,2,opt"`
_ [0]func()
}
type StEmotionReactionInfo struct {
Id proto.Option[string] `protobuf:"bytes,1,opt"`
EmojiReactionList []*EmojiReaction `protobuf:"bytes,2,rep"`
}
type StCommonExt struct {
MapInfo []*CommonEntry `protobuf:"bytes,1,rep"`
AttachInfo proto.Option[string] `protobuf:"bytes,2,opt"`
MapBytesInfo []*BytesEntry `protobuf:"bytes,3,rep"`
}
type BytesEntry struct {
Key proto.Option[string] `protobuf:"bytes,1,opt"`
Value []byte `protobuf:"bytes,2,opt"`
}
type CommonEntry struct {
Key proto.Option[string] `protobuf:"bytes,1,opt"`
Value proto.Option[string] `protobuf:"bytes,2,opt"`
_ [0]func()
}

View File

@ -1,78 +0,0 @@
syntax = "proto2";
package channel;
option go_package = "github.com/Mrs4s/MiraiGo/client/pb/channel";
import "pb/channel/MsgResponsesSvr.proto";
message ChannelUserInfo {
optional ClientIdentity clientIdentity = 1;
optional uint32 memberType = 2;
optional ChannelUserPermission permission = 3;
repeated BaseRoleGroupInfo roleGroups = 4;
}
message ChannelUserPermission {
optional bool allowReadFeed = 1;
optional bool allowWriteFeed = 2;
}
message ClientIdentity {
optional uint32 clientId = 1;
optional string desc = 2;
}
message BaseGuildInfo {
optional uint64 guildId = 1;
optional string name = 2;
optional uint64 joinTime = 3;
}
message BaseRoleGroupInfo {
optional uint64 roleId = 1;
optional string name = 2;
optional uint32 color = 3;
}
message StChannelInfo {
optional StChannelSign sign = 1;
optional string name = 2;
optional string iconUrl = 3;
}
message StChannelSign {
optional uint64 guildId = 1;
optional uint64 channelId = 2;
}
/*
message StEmojiReaction {
optional string emojiId = 1;
optional uint64 emojiType = 2;
optional uint64 cnt = 3;
optional bool isClicked = 4;
optional bool isDefaultEmoji = 10001;
}
*/
message StEmotionReactionInfo {
optional string id = 1;
repeated EmojiReaction emojiReactionList = 2;
}
message StCommonExt {
repeated CommonEntry mapInfo = 1;
optional string attachInfo = 2;
repeated BytesEntry mapBytesInfo = 3;
}
message BytesEntry {
optional string key = 1;
optional bytes value = 2;
}
message CommonEntry {
optional string key = 1;
optional string value = 2;
}

View File

@ -1,686 +0,0 @@
// Code generated by protoc-gen-golite. DO NOT EDIT.
// source: pb/channel/GuildFeedCloudMeta.proto
package channel
import (
proto "github.com/RomiChan/protobuf/proto"
)
type ContentMetaData struct {
Count *RichTextContentCount `protobuf:"bytes,1,opt"`
ContentID proto.Option[int64] `protobuf:"varint,2,opt"`
_ [0]func()
}
type FeedMetaData struct {
Content *ContentMetaData `protobuf:"bytes,1,opt"`
LastModifiedTime proto.Option[uint64] `protobuf:"varint,2,opt"`
_ [0]func()
}
type FeedRedTouchTransInfo struct {
FeedId proto.Option[string] `protobuf:"bytes,1,opt"`
Author proto.Option[string] `protobuf:"bytes,2,opt"`
CreateTs proto.Option[int64] `protobuf:"varint,3,opt"`
MsgType proto.Option[int32] `protobuf:"varint,4,opt"`
PageType proto.Option[int32] `protobuf:"varint,5,opt"`
RedType proto.Option[int32] `protobuf:"varint,6,opt"`
InsertPageType proto.Option[int32] `protobuf:"varint,7,opt"`
_ [0]func()
}
type NoticeOperation struct {
Type proto.Option[uint32] `protobuf:"varint,1,opt"`
Schema proto.Option[string] `protobuf:"bytes,2,opt"`
_ [0]func()
}
type RichTextContentCount struct {
TextWord proto.Option[uint64] `protobuf:"varint,1,opt"`
At proto.Option[uint64] `protobuf:"varint,2,opt"`
Url proto.Option[uint64] `protobuf:"varint,3,opt"`
Emoji proto.Option[uint64] `protobuf:"varint,4,opt"`
Image proto.Option[uint64] `protobuf:"varint,5,opt"`
Video proto.Option[uint64] `protobuf:"varint,6,opt"`
_ [0]func()
}
type StAnimation struct {
Width proto.Option[uint32] `protobuf:"varint,1,opt"`
Height proto.Option[uint32] `protobuf:"varint,2,opt"`
AnimationUrl proto.Option[string] `protobuf:"bytes,3,opt"`
BusiData []byte `protobuf:"bytes,4,opt"`
}
type StBusiReportInfo struct {
RecomReport *StRecomReportInfo `protobuf:"bytes,1,opt"`
TraceID proto.Option[string] `protobuf:"bytes,2,opt"`
_ [0]func()
}
type StChannelShareInfo struct {
FeedID proto.Option[string] `protobuf:"bytes,1,opt"`
PosterID proto.Option[string] `protobuf:"bytes,2,opt"`
FeedPublishAt proto.Option[uint64] `protobuf:"varint,3,opt"`
ChannelSign *StChannelSign `protobuf:"bytes,4,opt"`
UpdateDurationMs proto.Option[uint64] `protobuf:"varint,5,opt"`
Sign *StChannelShareSign `protobuf:"bytes,6,opt"`
_ [0]func()
}
type StChannelShareSign struct {
CreateAt proto.Option[uint64] `protobuf:"varint,1,opt"`
Token proto.Option[string] `protobuf:"bytes,2,opt"`
_ [0]func()
}
type StCircleRankItem struct {
RankNo proto.Option[int32] `protobuf:"varint,1,opt"`
CircleName proto.Option[string] `protobuf:"bytes,2,opt"`
FuelValue proto.Option[int64] `protobuf:"varint,3,opt"`
FeedNum proto.Option[int64] `protobuf:"varint,4,opt"`
CircleID proto.Option[string] `protobuf:"bytes,5,opt"`
_ [0]func()
}
type StClientInfo struct {
Feedclientkey proto.Option[string] `protobuf:"bytes,1,opt"`
ClientMap []*CommonEntry `protobuf:"bytes,2,rep"`
}
type StComment struct {
Id proto.Option[string] `protobuf:"bytes,1,opt"`
PostUser *StUser `protobuf:"bytes,2,opt"`
CreateTime proto.Option[uint64] `protobuf:"varint,3,opt"`
Content proto.Option[string] `protobuf:"bytes,4,opt"`
ReplyCount proto.Option[uint32] `protobuf:"varint,5,opt"`
VecReply []*StReply `protobuf:"bytes,6,rep"`
BusiData []byte `protobuf:"bytes,7,opt"`
LikeInfo *StLike `protobuf:"bytes,8,opt"`
TypeFlag proto.Option[uint32] `protobuf:"varint,9,opt"`
AtUinList []string `protobuf:"bytes,10,rep"`
TypeFlag2 proto.Option[uint32] `protobuf:"varint,11,opt"`
CreateTimeNs proto.Option[uint64] `protobuf:"varint,12,opt"`
StoreExtInfo []*CommonEntry `protobuf:"bytes,13,rep"`
ThirdId proto.Option[string] `protobuf:"bytes,14,opt"`
SourceType proto.Option[uint32] `protobuf:"varint,15,opt"`
RichContents *StRichText `protobuf:"bytes,16,opt"`
}
type StDebugInfo struct {
DebugMap []*CommonEntry `protobuf:"bytes,1,rep"`
}
type StDittoFeed struct {
DittoId proto.Option[uint32] `protobuf:"varint,1,opt"`
DittoPatternId proto.Option[uint32] `protobuf:"varint,2,opt"`
DittoData []byte `protobuf:"bytes,3,opt"`
DittoDataNew []byte `protobuf:"bytes,4,opt"`
}
type StExifInfo struct {
Kvs []*CommonEntry `protobuf:"bytes,1,rep"`
}
type StExternalMedalWallInfo struct {
NeedRedPoint proto.Option[bool] `protobuf:"varint,1,opt"`
MedalInfos []*StMedalInfo `protobuf:"bytes,2,rep"`
MedalWallJumpUrl proto.Option[string] `protobuf:"bytes,3,opt"`
NeedShowEntrance proto.Option[bool] `protobuf:"varint,4,opt"`
}
type StFeed struct {
Id proto.Option[string] `protobuf:"bytes,1,opt"`
Title *StRichText `protobuf:"bytes,2,opt"`
Subtitle *StRichText `protobuf:"bytes,3,opt"`
Poster *StUser `protobuf:"bytes,4,opt"`
Videos []*StVideo `protobuf:"bytes,5,rep"`
Contents *StRichText `protobuf:"bytes,6,opt"`
CreateTime proto.Option[uint64] `protobuf:"varint,7,opt"`
EmotionReaction *StEmotionReactionInfo `protobuf:"bytes,8,opt"`
CommentCount proto.Option[uint32] `protobuf:"varint,9,opt"`
VecComment []*StComment `protobuf:"bytes,10,rep"`
Share *StShare `protobuf:"bytes,11,opt"`
VisitorInfo *StVisitor `protobuf:"bytes,12,opt"`
Images []*StImage `protobuf:"bytes,13,rep"`
PoiInfo *StPoiInfoV2 `protobuf:"bytes,14,opt"`
TagInfos []*StTagInfo `protobuf:"bytes,15,rep"`
BusiReport []byte `protobuf:"bytes,16,opt"`
OpMask []uint32 `protobuf:"varint,17,rep"`
Opinfo *StOpinfo `protobuf:"bytes,18,opt"`
ExtInfo []*CommonEntry `protobuf:"bytes,19,rep"`
PatternInfo proto.Option[string] `protobuf:"bytes,20,opt"`
ChannelInfo *StChannelInfo `protobuf:"bytes,21,opt"`
CreateTimeNs proto.Option[uint64] `protobuf:"varint,22,opt"`
Summary *StFeedSummary `protobuf:"bytes,23,opt"`
RecomInfo *StRecomInfo `protobuf:"bytes,24,opt"`
Meta *FeedMetaData `protobuf:"bytes,25,opt"`
}
type StFeedAbstract struct {
Id proto.Option[string] `protobuf:"bytes,1,opt"`
Title proto.Option[string] `protobuf:"bytes,2,opt"`
Poster *StUser `protobuf:"bytes,3,opt"`
Pic *StImage `protobuf:"bytes,4,opt"`
Type proto.Option[uint32] `protobuf:"varint,5,opt"`
CreateTime proto.Option[uint64] `protobuf:"varint,6,opt"`
Video *StVideo `protobuf:"bytes,7,opt"`
FuelNum proto.Option[uint32] `protobuf:"varint,8,opt"`
Content proto.Option[string] `protobuf:"bytes,9,opt"`
Images []*StImage `protobuf:"bytes,10,rep"`
CountInfo *StFeedCount `protobuf:"bytes,11,opt"`
}
type StFeedCount struct {
Liked proto.Option[int64] `protobuf:"varint,1,opt"`
Push proto.Option[int64] `protobuf:"varint,2,opt"`
Comment proto.Option[int64] `protobuf:"varint,3,opt"`
Visitor proto.Option[int64] `protobuf:"varint,4,opt"`
_ [0]func()
}
type StFeedSummary struct {
LayoutType proto.Option[uint32] `protobuf:"varint,1,opt"`
_ [0]func()
}
type StFollowRecomInfo struct {
FollowText proto.Option[string] `protobuf:"bytes,1,opt"`
FollowUsers []*StFollowUser `protobuf:"bytes,4,rep"`
CommFriendText proto.Option[string] `protobuf:"bytes,6,opt"`
CommGroupText proto.Option[string] `protobuf:"bytes,7,opt"`
}
type StFollowUser struct {
Uid proto.Option[uint64] `protobuf:"varint,1,opt"`
Nick proto.Option[string] `protobuf:"bytes,2,opt"`
_ [0]func()
}
type StGPSV2 struct {
Lat proto.Option[int64] `protobuf:"varint,1,opt"`
Lon proto.Option[int64] `protobuf:"varint,2,opt"`
EType proto.Option[int64] `protobuf:"varint,3,opt"`
Alt proto.Option[int64] `protobuf:"varint,4,opt"`
_ [0]func()
}
type StGuidePublishBubble struct {
Id proto.Option[string] `protobuf:"bytes,1,opt"`
BackgroundImage *StImage `protobuf:"bytes,2,opt"`
JumpUrl proto.Option[string] `protobuf:"bytes,3,opt"`
_ [0]func()
}
type StIconInfo struct {
IconUrl40 proto.Option[string] `protobuf:"bytes,1,opt"`
IconUrl100 proto.Option[string] `protobuf:"bytes,2,opt"`
IconUrl140 proto.Option[string] `protobuf:"bytes,3,opt"`
IconUrl640 proto.Option[string] `protobuf:"bytes,4,opt"`
IconUrl proto.Option[string] `protobuf:"bytes,5,opt"`
_ [0]func()
}
type StImage struct {
Width proto.Option[uint32] `protobuf:"varint,1,opt"`
Height proto.Option[uint32] `protobuf:"varint,2,opt"`
PicUrl proto.Option[string] `protobuf:"bytes,3,opt"`
VecImageUrl []*StImageUrl `protobuf:"bytes,4,rep"`
PicId proto.Option[string] `protobuf:"bytes,5,opt"`
BusiData []byte `protobuf:"bytes,6,opt"`
ImageMD5 proto.Option[string] `protobuf:"bytes,7,opt"`
LayerPicUrl proto.Option[string] `protobuf:"bytes,8,opt"`
PatternId proto.Option[string] `protobuf:"bytes,9,opt"`
DisplayIndex proto.Option[uint32] `protobuf:"varint,10,opt"`
}
type StImageUrl struct {
LevelType proto.Option[uint32] `protobuf:"varint,1,opt"`
Url proto.Option[string] `protobuf:"bytes,2,opt"`
Width proto.Option[uint32] `protobuf:"varint,3,opt"`
Height proto.Option[uint32] `protobuf:"varint,4,opt"`
BusiData []byte `protobuf:"bytes,5,opt"`
}
type StLightInteractInfo struct {
User *StUser `protobuf:"bytes,1,opt"`
Relation *StRelationInfo `protobuf:"bytes,2,opt"`
Count proto.Option[uint32] `protobuf:"varint,3,opt"`
BusiData []byte `protobuf:"bytes,4,opt"`
}
type StLike struct {
Id proto.Option[string] `protobuf:"bytes,1,opt"`
Count proto.Option[uint32] `protobuf:"varint,2,opt"`
Status proto.Option[uint32] `protobuf:"varint,3,opt"`
VecUser []*StUser `protobuf:"bytes,4,rep"`
BusiData []byte `protobuf:"bytes,5,opt"`
PostUser *StUser `protobuf:"bytes,6,opt"`
HasLikedCount proto.Option[uint32] `protobuf:"varint,7,opt"`
OwnerStatus proto.Option[uint32] `protobuf:"varint,8,opt"`
JumpUrl proto.Option[string] `protobuf:"bytes,9,opt"`
}
type StLiteBanner struct {
Icon *StImage `protobuf:"bytes,1,opt"`
Title proto.Option[string] `protobuf:"bytes,2,opt"`
JumpUrl proto.Option[string] `protobuf:"bytes,3,opt"`
ActivityID proto.Option[string] `protobuf:"bytes,4,opt"`
JsonStyle proto.Option[string] `protobuf:"bytes,5,opt"`
ExtInfo []*CommonEntry `protobuf:"bytes,6,rep"`
}
type StMaterialDataNew struct {
MaterialType proto.Option[string] `protobuf:"bytes,1,opt"`
MaterialList []*StSingleMaterial `protobuf:"bytes,2,rep"`
}
type StMedalInfo struct {
Type proto.Option[int32] `protobuf:"varint,1,opt"`
MedalName proto.Option[string] `protobuf:"bytes,2,opt"`
MedalID proto.Option[string] `protobuf:"bytes,3,opt"`
Rank proto.Option[int32] `protobuf:"varint,4,opt"`
IsHighLight proto.Option[bool] `protobuf:"varint,5,opt"`
IsNew proto.Option[bool] `protobuf:"varint,6,opt"`
JumpUrl proto.Option[string] `protobuf:"bytes,7,opt"`
IconUrl proto.Option[string] `protobuf:"bytes,8,opt"`
BackgroundUrl proto.Option[string] `protobuf:"bytes,9,opt"`
Describe proto.Option[string] `protobuf:"bytes,10,opt"`
ReportValue proto.Option[int32] `protobuf:"varint,11,opt"`
_ [0]func()
}
type StNotice struct {
PsvFeed *StFeed `protobuf:"bytes,1,opt"`
OrigineFeed *StFeed `protobuf:"bytes,2,opt"`
PattonInfo *StNoticePattonInfo `protobuf:"bytes,3,opt"`
_ [0]func()
}
type StNoticePattonInfo struct {
PattonType proto.Option[uint32] `protobuf:"varint,1,opt"`
PlainTxt *StPlainTxtInfo `protobuf:"bytes,2,opt"`
_ [0]func()
}
type StNoticeTxtInfo struct {
Content *StRichText `protobuf:"bytes,1,opt"`
ContentOfReference *StRichText `protobuf:"bytes,2,opt"`
_ [0]func()
}
type StOpinfo struct {
CreateTime []uint64 `protobuf:"varint,1,rep"`
}
type StPlainTxtInfo struct {
TxtInfo *StNoticeTxtInfo `protobuf:"bytes,1,opt"`
Operation *NoticeOperation `protobuf:"bytes,2,opt"`
_ [0]func()
}
type StPoiInfoV2 struct {
PoiId proto.Option[string] `protobuf:"bytes,1,opt"`
Name proto.Option[string] `protobuf:"bytes,2,opt"`
PoiType proto.Option[int32] `protobuf:"varint,3,opt"`
TypeName proto.Option[string] `protobuf:"bytes,4,opt"`
Address proto.Option[string] `protobuf:"bytes,5,opt"`
DistrictCode proto.Option[int32] `protobuf:"varint,6,opt"`
Gps *StGPSV2 `protobuf:"bytes,7,opt"`
Distance proto.Option[int32] `protobuf:"varint,8,opt"`
HotValue proto.Option[int32] `protobuf:"varint,9,opt"`
Phone proto.Option[string] `protobuf:"bytes,10,opt"`
Country proto.Option[string] `protobuf:"bytes,11,opt"`
Province proto.Option[string] `protobuf:"bytes,12,opt"`
City proto.Option[string] `protobuf:"bytes,13,opt"`
PoiNum proto.Option[int32] `protobuf:"varint,14,opt"`
PoiOrderType proto.Option[int32] `protobuf:"varint,15,opt"`
DefaultName proto.Option[string] `protobuf:"bytes,16,opt"`
District proto.Option[string] `protobuf:"bytes,17,opt"`
DianPingId proto.Option[string] `protobuf:"bytes,18,opt"`
DistanceText proto.Option[string] `protobuf:"bytes,19,opt"`
DisplayName proto.Option[string] `protobuf:"bytes,20,opt"`
_ [0]func()
}
type StPrePullCacheFeed struct {
Id proto.Option[string] `protobuf:"bytes,1,opt"`
Poster *StUser `protobuf:"bytes,2,opt"`
CreateTime proto.Option[uint64] `protobuf:"varint,3,opt"`
BusiTranparent []*BytesEntry `protobuf:"bytes,4,rep"`
}
type StProxyInfo struct {
CmdId proto.Option[int32] `protobuf:"varint,1,opt"`
SubCmdId proto.Option[int32] `protobuf:"varint,2,opt"`
AppProtocol proto.Option[string] `protobuf:"bytes,3,opt"`
ReqBody []byte `protobuf:"bytes,4,opt"`
}
type StRankingItem struct {
User *StUser `protobuf:"bytes,1,opt"`
Relation *StRelationInfo `protobuf:"bytes,2,opt"`
Score proto.Option[int64] `protobuf:"varint,3,opt"`
Grade proto.Option[int32] `protobuf:"varint,4,opt"`
BusiData []byte `protobuf:"bytes,5,opt"`
RankNo proto.Option[int32] `protobuf:"varint,6,opt"`
InTopicList proto.Option[int32] `protobuf:"varint,7,opt"`
}
type StRecomForward struct {
Id proto.Option[string] `protobuf:"bytes,1,opt"`
Title proto.Option[string] `protobuf:"bytes,2,opt"`
Subtitle proto.Option[string] `protobuf:"bytes,3,opt"`
Poster *StUser `protobuf:"bytes,4,opt"`
CreateTime proto.Option[uint64] `protobuf:"varint,5,opt"`
Type proto.Option[uint32] `protobuf:"varint,6,opt"`
BusiData []byte `protobuf:"bytes,7,opt"`
}
type StRecomInfo struct {
RecomReason proto.Option[string] `protobuf:"bytes,1,opt"`
RecomAttachInfo []byte `protobuf:"bytes,2,opt"`
RecomTrace proto.Option[string] `protobuf:"bytes,3,opt"`
ClientSealData []byte `protobuf:"bytes,4,opt"`
IconUrl proto.Option[string] `protobuf:"bytes,5,opt"`
RecomReasonType proto.Option[int32] `protobuf:"varint,6,opt"`
}
type StRecomReportInfo struct {
RecomInfos []*StSingleRecomReportInfo `protobuf:"bytes,1,rep"`
}
type StRelationInfo struct {
Id proto.Option[string] `protobuf:"bytes,1,opt"`
Relation proto.Option[uint32] `protobuf:"varint,2,opt"`
BusiData []byte `protobuf:"bytes,3,opt"`
RelationState proto.Option[uint32] `protobuf:"varint,4,opt"`
Score proto.Option[uint32] `protobuf:"varint,5,opt"`
IsBlock proto.Option[bool] `protobuf:"varint,6,opt"`
IsBlocked proto.Option[bool] `protobuf:"varint,7,opt"`
IsFriend proto.Option[bool] `protobuf:"varint,8,opt"`
IsUncare proto.Option[bool] `protobuf:"varint,9,opt"`
ImBitMap proto.Option[uint64] `protobuf:"varint,10,opt"`
}
type StReply struct {
Id proto.Option[string] `protobuf:"bytes,1,opt"`
PostUser *StUser `protobuf:"bytes,2,opt"`
CreateTime proto.Option[uint64] `protobuf:"varint,3,opt"`
Content proto.Option[string] `protobuf:"bytes,4,opt"`
TargetUser *StUser `protobuf:"bytes,5,opt"`
BusiData []byte `protobuf:"bytes,6,opt"`
LikeInfo *StLike `protobuf:"bytes,7,opt"`
TypeFlag proto.Option[uint32] `protobuf:"varint,8,opt"`
Modifyflag proto.Option[uint32] `protobuf:"varint,9,opt"`
AtUinList []string `protobuf:"bytes,10,rep"`
TypeFlag2 proto.Option[uint32] `protobuf:"varint,11,opt"`
CreateTimeNs proto.Option[uint64] `protobuf:"varint,12,opt"`
StoreExtInfo []*CommonEntry `protobuf:"bytes,13,rep"`
ThirdId proto.Option[string] `protobuf:"bytes,14,opt"`
TargetReplyID proto.Option[string] `protobuf:"bytes,15,opt"`
SourceType proto.Option[uint32] `protobuf:"varint,16,opt"`
RichContents *StRichText `protobuf:"bytes,17,opt"`
}
type StReportInfo struct {
Id proto.Option[string] `protobuf:"bytes,1,opt"`
BusiReport []byte `protobuf:"bytes,2,opt"`
}
type StRichText struct {
Contents []*StRichTextContent `protobuf:"bytes,1,rep"`
}
type StRichTextAtContent struct {
Type proto.Option[uint32] `protobuf:"varint,1,opt"`
GuildInfo *GuildChannelBaseGuildInfo `protobuf:"bytes,2,opt"`
RoleGroupId *GuildChannelBaseRoleGroupInfo `protobuf:"bytes,3,opt"`
User *StUser `protobuf:"bytes,4,opt"`
_ [0]func()
}
type GuildChannelBaseGuildInfo struct {
GuildId proto.Option[uint64] `protobuf:"varint,1,opt"`
Name proto.Option[string] `protobuf:"bytes,2,opt"`
JoinTime proto.Option[uint64] `protobuf:"varint,3,opt"`
_ [0]func()
}
type GuildChannelBaseRoleGroupInfo struct {
RoleId proto.Option[uint64] `protobuf:"varint,1,opt"`
Name proto.Option[string] `protobuf:"bytes,2,opt"`
Color proto.Option[uint32] `protobuf:"varint,3,opt"`
_ [0]func()
}
type StRichTextChannelContent struct {
ChannelInfo *StChannelInfo `protobuf:"bytes,1,opt"`
_ [0]func()
}
type StRichTextContent struct {
Type proto.Option[uint32] `protobuf:"varint,1,opt"`
PatternId proto.Option[string] `protobuf:"bytes,2,opt"`
TextContent *StRichTextTextContent `protobuf:"bytes,3,opt"`
AtContent *StRichTextAtContent `protobuf:"bytes,4,opt"`
UrlContent *StRichTextURLContent `protobuf:"bytes,5,opt"`
EmojiContent *StRichTextEmojiContent `protobuf:"bytes,6,opt"`
ChannelContent *StRichTextChannelContent `protobuf:"bytes,7,opt"`
_ [0]func()
}
type StRichTextEmojiContent struct {
Id proto.Option[string] `protobuf:"bytes,1,opt"`
Type proto.Option[string] `protobuf:"bytes,2,opt"`
Name proto.Option[string] `protobuf:"bytes,3,opt"`
Url proto.Option[string] `protobuf:"bytes,4,opt"`
_ [0]func()
}
type StRichTextTextContent struct {
Text proto.Option[string] `protobuf:"bytes,1,opt"`
_ [0]func()
}
type StRichTextURLContent struct {
Url proto.Option[string] `protobuf:"bytes,1,opt"`
DisplayText proto.Option[string] `protobuf:"bytes,2,opt"`
_ [0]func()
}
type StSameTopicGuideInfo struct {
IsSameTopicGuide proto.Option[uint32] `protobuf:"varint,1,opt"`
StayShowTime proto.Option[int64] `protobuf:"varint,2,opt"`
HashTag proto.Option[string] `protobuf:"bytes,3,opt"`
Words proto.Option[string] `protobuf:"bytes,4,opt"`
JumpUrl proto.Option[string] `protobuf:"bytes,5,opt"`
ReportExt proto.Option[string] `protobuf:"bytes,6,opt"`
_ [0]func()
}
type StShare struct {
Title proto.Option[string] `protobuf:"bytes,1,opt"`
Desc proto.Option[string] `protobuf:"bytes,2,opt"`
Type proto.Option[uint32] `protobuf:"varint,3,opt"`
Url proto.Option[string] `protobuf:"bytes,4,opt"`
Author *StUser `protobuf:"bytes,5,opt"`
Poster *StUser `protobuf:"bytes,6,opt"`
Videos []*StVideo `protobuf:"bytes,7,rep"`
Shorturl proto.Option[string] `protobuf:"bytes,8,opt"`
ShareCardInfo proto.Option[string] `protobuf:"bytes,9,opt"`
ShareQzoneInfo *StShareQzoneInfo `protobuf:"bytes,10,opt"`
Images []*StImage `protobuf:"bytes,11,rep"`
PublishTotalUser proto.Option[uint32] `protobuf:"varint,12,opt"`
SharedCount proto.Option[uint32] `protobuf:"varint,13,opt"`
ChannelShareInfo *StChannelShareInfo `protobuf:"bytes,14,opt"`
}
type StShareQzoneInfo struct {
Entrys []*CommonEntry `protobuf:"bytes,1,rep"`
}
type StSingleMaterial struct {
MaterialId proto.Option[string] `protobuf:"bytes,1,opt"`
_ [0]func()
}
type StSingleRecomReportInfo struct {
ReportID proto.Option[string] `protobuf:"bytes,1,opt"`
ReportData []byte `protobuf:"bytes,2,opt"`
}
type StTagInfo struct {
TagId proto.Option[string] `protobuf:"bytes,1,opt"`
TagName proto.Option[string] `protobuf:"bytes,2,opt"`
TagDec proto.Option[string] `protobuf:"bytes,3,opt"`
UserList []*StUser `protobuf:"bytes,4,rep"`
FeedList []*StFeedAbstract `protobuf:"bytes,5,rep"`
TagTotalUser proto.Option[uint32] `protobuf:"varint,6,opt"`
TagTotalFeed proto.Option[uint32] `protobuf:"varint,7,opt"`
TagWording proto.Option[string] `protobuf:"bytes,8,opt"`
TagType proto.Option[uint32] `protobuf:"varint,9,opt"`
FollowState proto.Option[uint32] `protobuf:"varint,10,opt"`
ShareInfo *StShare `protobuf:"bytes,11,opt"`
IsTop proto.Option[uint32] `protobuf:"varint,12,opt"`
IsSelected proto.Option[uint32] `protobuf:"varint,13,opt"`
UserViewHistory proto.Option[int64] `protobuf:"varint,14,opt"`
Medal *StTagMedalInfo `protobuf:"bytes,15,opt"`
Status proto.Option[uint32] `protobuf:"varint,16,opt"`
OptInfo *StTagOperateInfo `protobuf:"bytes,17,opt"`
TagBaseStatus proto.Option[uint32] `protobuf:"varint,18,opt"`
IsRecommend proto.Option[int32] `protobuf:"varint,19,opt"`
TagViewHistory proto.Option[int64] `protobuf:"varint,20,opt"`
OperateIconUrl proto.Option[string] `protobuf:"bytes,21,opt"`
TagReport proto.Option[string] `protobuf:"bytes,99,opt"`
TagIconUrl proto.Option[string] `protobuf:"bytes,100,opt"`
}
type StTagMedalInfo struct {
TagID proto.Option[string] `protobuf:"bytes,1,opt"`
TagName proto.Option[string] `protobuf:"bytes,2,opt"`
Rank proto.Option[uint64] `protobuf:"varint,3,opt"`
_ [0]func()
}
type StTagOperateInfo struct {
CreateUser proto.Option[string] `protobuf:"bytes,1,opt"`
CoverURL proto.Option[string] `protobuf:"bytes,2,opt"`
Desc proto.Option[string] `protobuf:"bytes,3,opt"`
BackgroundURL proto.Option[string] `protobuf:"bytes,4,opt"`
BannerURL proto.Option[string] `protobuf:"bytes,5,opt"`
BannerSkipLink proto.Option[string] `protobuf:"bytes,6,opt"`
ActivityStartTime proto.Option[int64] `protobuf:"varint,7,opt"`
ActivityEndTime proto.Option[int64] `protobuf:"varint,8,opt"`
RecommendReason proto.Option[string] `protobuf:"bytes,9,opt"`
IsWhite proto.Option[int32] `protobuf:"varint,10,opt"`
BeWhiteStartTime proto.Option[int64] `protobuf:"varint,11,opt"`
BeWhiteEndTime proto.Option[int64] `protobuf:"varint,12,opt"`
PublishSchema proto.Option[string] `protobuf:"bytes,13,opt"`
_ [0]func()
}
type StUnifiedTag struct {
UnifiedType proto.Option[string] `protobuf:"bytes,1,opt"`
UnifiedId proto.Option[string] `protobuf:"bytes,2,opt"`
_ [0]func()
}
type StUser struct {
Id proto.Option[string] `protobuf:"bytes,1,opt"`
Nick proto.Option[string] `protobuf:"bytes,2,opt"`
Icon *StIconInfo `protobuf:"bytes,3,opt"`
Desc proto.Option[string] `protobuf:"bytes,4,opt"`
FollowState proto.Option[uint32] `protobuf:"varint,5,opt"`
Type proto.Option[uint32] `protobuf:"varint,6,opt"`
Sex proto.Option[uint32] `protobuf:"varint,7,opt"`
Birthday proto.Option[uint64] `protobuf:"varint,8,opt"`
School proto.Option[string] `protobuf:"bytes,9,opt"`
Location proto.Option[string] `protobuf:"bytes,11,opt"`
BusiData []byte `protobuf:"bytes,12,opt"`
FrdState proto.Option[uint32] `protobuf:"varint,13,opt"`
RelationState proto.Option[uint32] `protobuf:"varint,14,opt"`
BlackState proto.Option[uint32] `protobuf:"varint,15,opt"`
Medal *StTagMedalInfo `protobuf:"bytes,16,opt"`
Constellation proto.Option[int32] `protobuf:"varint,17,opt"`
JumpUrl proto.Option[string] `protobuf:"bytes,18,opt"`
LocationCode proto.Option[string] `protobuf:"bytes,19,opt"`
ThirdId proto.Option[string] `protobuf:"bytes,20,opt"`
Company proto.Option[string] `protobuf:"bytes,21,opt"`
CertificationDesc proto.Option[string] `protobuf:"bytes,22,opt"`
DescType proto.Option[uint32] `protobuf:"varint,23,opt"`
ChannelUserInfo *GuildChannelBaseChannelUserInfo `protobuf:"bytes,24,opt"`
LoginId proto.Option[string] `protobuf:"bytes,25,opt"`
}
type GuildChannelBaseChannelUserInfo struct {
ClientIdentity *ClientIdentity `protobuf:"bytes,1,opt"`
MemberType proto.Option[uint32] `protobuf:"varint,2,opt"`
// optional ChannelUserPermission permission = 3;
RoleGroups []*GuildChannelBaseRoleGroupInfo `protobuf:"bytes,4,rep"`
}
type StUserGroupInfo struct {
Id proto.Option[string] `protobuf:"bytes,1,opt"`
Name proto.Option[string] `protobuf:"bytes,2,opt"`
UserList []*StUser `protobuf:"bytes,3,rep"`
}
type StUserRecomInfo struct {
User *StUser `protobuf:"bytes,1,opt"`
FeedList []*StFeedAbstract `protobuf:"bytes,2,rep"`
BusiData []byte `protobuf:"bytes,3,opt"`
}
type StVideo struct {
FileId proto.Option[string] `protobuf:"bytes,1,opt"`
FileSize proto.Option[uint32] `protobuf:"varint,2,opt"`
Duration proto.Option[uint32] `protobuf:"varint,3,opt"`
Width proto.Option[uint32] `protobuf:"varint,4,opt"`
Height proto.Option[uint32] `protobuf:"varint,5,opt"`
PlayUrl proto.Option[string] `protobuf:"bytes,6,opt"`
TransStatus proto.Option[uint32] `protobuf:"varint,7,opt"`
VideoPrior proto.Option[uint32] `protobuf:"varint,8,opt"`
VideoRate proto.Option[uint32] `protobuf:"varint,9,opt"`
VecVideoUrl []*StVideoUrl `protobuf:"bytes,10,rep"`
BusiData []byte `protobuf:"bytes,11,opt"`
ApprovalStatus proto.Option[uint32] `protobuf:"varint,12,opt"`
VideoSource proto.Option[uint32] `protobuf:"varint,13,opt"`
MediaQualityRank proto.Option[uint32] `protobuf:"varint,14,opt"`
MediaQualityScore proto.Option[float32] `protobuf:"fixed32,15,opt"`
VideoMD5 proto.Option[string] `protobuf:"bytes,16,opt"`
IsQuic proto.Option[uint32] `protobuf:"varint,17,opt"`
Orientation proto.Option[uint32] `protobuf:"varint,18,opt"`
Cover *StImage `protobuf:"bytes,19,opt"`
PatternId proto.Option[string] `protobuf:"bytes,20,opt"`
DisplayIndex proto.Option[uint32] `protobuf:"varint,21,opt"`
}
type StVideoUrl struct {
LevelType proto.Option[uint32] `protobuf:"varint,1,opt"`
PlayUrl proto.Option[string] `protobuf:"bytes,2,opt"`
VideoPrior proto.Option[uint32] `protobuf:"varint,3,opt"`
VideoRate proto.Option[uint32] `protobuf:"varint,4,opt"`
TransStatus proto.Option[uint32] `protobuf:"varint,5,opt"`
BusiData []byte `protobuf:"bytes,6,opt"`
HasWatermark proto.Option[bool] `protobuf:"varint,7,opt"`
}
type StVisitor struct {
ViewCount proto.Option[uint32] `protobuf:"varint,1,opt"`
BusiData []byte `protobuf:"bytes,2,opt"`
RecomCount proto.Option[uint32] `protobuf:"varint,3,opt"`
ViewDesc proto.Option[string] `protobuf:"bytes,4,opt"`
}
type StWearingMedal struct {
MedalInfos []*StWearingMedalInfo `protobuf:"bytes,1,rep"`
}
type StWearingMedalInfo struct {
Type proto.Option[int32] `protobuf:"varint,1,opt"`
MedalName proto.Option[string] `protobuf:"bytes,2,opt"`
MedalID proto.Option[string] `protobuf:"bytes,3,opt"`
_ [0]func()
}

View File

@ -1,651 +0,0 @@
syntax = "proto2";
package channel;
option go_package = "github.com/Mrs4s/MiraiGo/client/pb/channel";
import "pb/channel/GuildChannelBase.proto";
message ContentMetaData {
optional RichTextContentCount count = 1;
optional int64 ContentID = 2;
}
message FeedMetaData {
optional ContentMetaData content = 1;
optional uint64 lastModifiedTime = 2;
}
message FeedRedTouchTransInfo {
optional string feedId = 1;
optional string author = 2;
optional int64 createTs = 3;
optional int32 msgType = 4;
optional int32 pageType = 5;
optional int32 redType = 6;
optional int32 insertPageType = 7;
}
message NoticeOperation {
optional uint32 type = 1;
optional string schema = 2;
}
message RichTextContentCount {
optional uint64 textWord = 1;
optional uint64 at = 2;
optional uint64 url = 3;
optional uint64 emoji = 4;
optional uint64 image = 5;
optional uint64 video = 6;
}
message StAnimation {
optional uint32 width = 1;
optional uint32 height = 2;
optional string animationUrl = 3;
optional bytes busiData = 4;
}
message StBusiReportInfo {
optional StRecomReportInfo recomReport = 1;
optional string traceID = 2;
}
message StChannelShareInfo {
optional string feedID = 1;
optional string posterID = 2;
optional uint64 feedPublishAt = 3;
optional StChannelSign channelSign = 4;
optional uint64 updateDurationMs = 5;
optional StChannelShareSign sign = 6;
}
message StChannelShareSign {
optional uint64 createAt = 1;
optional string token = 2;
}
message StCircleRankItem {
optional int32 rankNo = 1;
optional string circleName = 2;
optional int64 fuelValue = 3;
optional int64 feedNum = 4;
optional string circleID = 5;
}
message StClientInfo {
optional string feedclientkey = 1;
repeated CommonEntry clientMap = 2;
}
message StComment {
optional string id = 1;
optional StUser postUser = 2;
optional uint64 createTime = 3;
optional string content = 4;
optional uint32 replyCount = 5;
repeated StReply vecReply = 6;
optional bytes busiData = 7;
optional StLike likeInfo = 8;
optional uint32 typeFlag = 9;
repeated string atUinList = 10;
optional uint32 typeFlag2 = 11;
optional uint64 createTimeNs = 12;
repeated CommonEntry storeExtInfo = 13;
optional string thirdId = 14;
optional uint32 sourceType = 15;
optional StRichText richContents = 16;
}
message StDebugInfo {
repeated CommonEntry debugMap = 1;
}
message StDittoFeed {
optional uint32 dittoId = 1;
optional uint32 dittoPatternId = 2;
optional bytes dittoData = 3;
optional bytes dittoDataNew = 4;
}
message StExifInfo {
repeated CommonEntry kvs = 1;
}
message StExternalMedalWallInfo {
optional bool needRedPoint = 1;
repeated StMedalInfo medalInfos = 2;
optional string medalWallJumpUrl = 3;
optional bool needShowEntrance = 4;
}
message StFeed {
optional string id = 1;
optional StRichText title = 2;
optional StRichText subtitle = 3;
optional StUser poster = 4;
repeated StVideo videos = 5;
optional StRichText contents = 6;
optional uint64 createTime = 7;
optional StEmotionReactionInfo emotionReaction = 8;
optional uint32 commentCount = 9;
repeated StComment vecComment = 10;
optional StShare share = 11;
optional StVisitor visitorInfo = 12;
repeated StImage images = 13;
optional StPoiInfoV2 poiInfo = 14;
repeated StTagInfo tagInfos = 15;
optional bytes busiReport = 16;
repeated uint32 opMask = 17;
optional StOpinfo opinfo = 18;
repeated CommonEntry extInfo = 19;
optional string patternInfo = 20;
optional StChannelInfo channelInfo = 21;
optional uint64 createTimeNs = 22;
optional StFeedSummary summary = 23;
optional StRecomInfo recomInfo = 24;
optional FeedMetaData meta = 25;
}
message StFeedAbstract {
optional string id = 1;
optional string title = 2;
optional StUser poster = 3;
optional StImage pic = 4;
optional uint32 type = 5;
optional uint64 createTime = 6;
optional StVideo video = 7;
optional uint32 fuelNum = 8;
optional string content = 9;
repeated StImage images = 10;
optional StFeedCount countInfo = 11;
}
message StFeedCount {
optional int64 liked = 1;
optional int64 push = 2;
optional int64 comment = 3;
optional int64 visitor = 4;
}
message StFeedSummary {
optional uint32 layoutType = 1;
}
message StFollowRecomInfo {
optional string followText = 1;
repeated StFollowUser followUsers = 4;
optional string commFriendText = 6;
optional string commGroupText = 7;
}
message StFollowUser {
optional uint64 uid = 1;
optional string nick = 2;
}
message StGPSV2 {
optional int64 lat = 1;
optional int64 lon = 2;
optional int64 eType = 3;
optional int64 alt = 4;
}
message StGuidePublishBubble {
optional string id = 1;
optional StImage backgroundImage = 2;
optional string jumpUrl = 3;
}
message StIconInfo {
optional string iconUrl40 = 1;
optional string iconUrl100 = 2;
optional string iconUrl140 = 3;
optional string iconUrl640 = 4;
optional string iconUrl = 5;
}
message StImage {
optional uint32 width = 1;
optional uint32 height = 2;
optional string picUrl = 3;
repeated StImageUrl vecImageUrl = 4;
optional string picId = 5;
optional bytes busiData = 6;
optional string imageMD5 = 7;
optional string layerPicUrl = 8;
optional string patternId = 9;
optional uint32 displayIndex = 10;
}
message StImageUrl {
optional uint32 levelType = 1;
optional string url = 2;
optional uint32 width = 3;
optional uint32 height = 4;
optional bytes busiData = 5;
}
message StLightInteractInfo {
optional StUser user = 1;
optional StRelationInfo relation = 2;
optional uint32 count = 3;
optional bytes busiData = 4;
}
message StLike {
optional string id = 1;
optional uint32 count = 2;
optional uint32 status = 3;
repeated StUser vecUser = 4;
optional bytes busiData = 5;
optional StUser postUser = 6;
optional uint32 hasLikedCount = 7;
optional uint32 ownerStatus = 8;
optional string jumpUrl = 9;
}
message StLiteBanner {
optional StImage icon = 1;
optional string title = 2;
optional string jumpUrl = 3;
optional string activityID = 4;
optional string jsonStyle = 5;
repeated CommonEntry extInfo = 6;
}
message StMaterialDataNew {
optional string materialType = 1;
repeated StSingleMaterial materialList = 2;
}
message StMedalInfo {
optional int32 type = 1;
optional string medalName = 2;
optional string medalID = 3;
optional int32 rank = 4;
optional bool isHighLight = 5;
optional bool isNew = 6;
optional string jumpUrl = 7;
optional string iconUrl = 8;
optional string backgroundUrl = 9;
optional string describe = 10;
optional int32 reportValue = 11;
}
message StNotice {
optional StFeed psvFeed = 1;
optional StFeed origineFeed = 2;
optional StNoticePattonInfo pattonInfo = 3;
}
message StNoticePattonInfo {
optional uint32 pattonType = 1;
optional StPlainTxtInfo plainTxt = 2;
}
message StNoticeTxtInfo {
optional StRichText content = 1;
optional StRichText contentOfReference = 2;
}
message StOpinfo {
repeated uint64 createTime = 1;
}
message StPlainTxtInfo {
optional StNoticeTxtInfo txtInfo = 1;
optional NoticeOperation operation = 2;
}
message StPoiInfoV2 {
optional string poiId = 1;
optional string name = 2;
optional int32 poiType = 3;
optional string typeName = 4;
optional string address = 5;
optional int32 districtCode = 6;
optional StGPSV2 gps = 7;
optional int32 distance = 8;
optional int32 hotValue = 9;
optional string phone = 10;
optional string country = 11;
optional string province = 12;
optional string city = 13;
optional int32 poiNum = 14;
optional int32 poiOrderType = 15;
optional string defaultName = 16;
optional string district = 17;
optional string dianPingId = 18;
optional string distanceText = 19;
optional string displayName = 20;
}
message StPrePullCacheFeed {
optional string id = 1;
optional StUser poster = 2;
optional uint64 createTime = 3;
repeated BytesEntry busiTranparent = 4;
}
message StProxyInfo {
optional int32 cmdId = 1;
optional int32 subCmdId = 2;
optional string appProtocol = 3;
optional bytes reqBody = 4;
}
message StRankingItem {
optional StUser user = 1;
optional StRelationInfo relation = 2;
optional int64 score = 3;
optional int32 grade = 4;
optional bytes busiData = 5;
optional int32 rankNo = 6;
optional int32 inTopicList = 7;
}
message StRecomForward {
optional string id = 1;
optional string title = 2;
optional string subtitle = 3;
optional StUser poster = 4;
optional uint64 createTime = 5;
optional uint32 type = 6;
optional bytes busiData = 7;
}
message StRecomInfo {
optional string recomReason = 1;
optional bytes recomAttachInfo = 2;
optional string recomTrace = 3;
optional bytes clientSealData = 4;
optional string iconUrl = 5;
optional int32 recomReasonType = 6;
}
message StRecomReportInfo {
repeated StSingleRecomReportInfo recomInfos = 1;
}
message StRelationInfo {
optional string id = 1;
optional uint32 relation = 2;
optional bytes busiData = 3;
optional uint32 relationState = 4;
optional uint32 score = 5;
optional bool isBlock = 6;
optional bool isBlocked = 7;
optional bool isFriend = 8;
optional bool isUncare = 9;
optional uint64 imBitMap = 10;
}
message StReply {
optional string id = 1;
optional StUser postUser = 2;
optional uint64 createTime = 3;
optional string content = 4;
optional StUser targetUser = 5;
optional bytes busiData = 6;
optional StLike likeInfo = 7;
optional uint32 typeFlag = 8;
optional uint32 modifyflag = 9;
repeated string atUinList = 10;
optional uint32 typeFlag2 = 11;
optional uint64 createTimeNs = 12;
repeated CommonEntry storeExtInfo = 13;
optional string thirdId = 14;
optional string targetReplyID = 15;
optional uint32 sourceType = 16;
optional StRichText richContents = 17;
}
message StReportInfo {
optional string id = 1;
optional bytes busiReport = 2;
}
message StRichText {
repeated StRichTextContent contents = 1;
}
message StRichTextAtContent {
optional uint32 type = 1;
optional GuildChannelBaseGuildInfo guildInfo = 2;
optional GuildChannelBaseRoleGroupInfo roleGroupId = 3;
optional StUser user = 4;
}
message GuildChannelBaseGuildInfo {
optional uint64 guildId = 1;
optional string name = 2;
optional uint64 joinTime = 3;
}
message GuildChannelBaseRoleGroupInfo {
optional uint64 roleId = 1;
optional string name = 2;
optional uint32 color = 3;
}
message StRichTextChannelContent {
optional StChannelInfo channelInfo = 1;
}
message StRichTextContent {
optional uint32 type = 1;
optional string patternId = 2;
optional StRichTextTextContent textContent = 3;
optional StRichTextAtContent atContent = 4;
optional StRichTextURLContent urlContent = 5;
optional StRichTextEmojiContent emojiContent = 6;
optional StRichTextChannelContent channelContent = 7;
}
message StRichTextEmojiContent {
optional string id = 1;
optional string type = 2;
optional string name = 3;
optional string url = 4;
}
message StRichTextTextContent {
optional string text = 1;
}
message StRichTextURLContent {
optional string url = 1;
optional string displayText = 2;
}
message StSameTopicGuideInfo {
optional uint32 isSameTopicGuide = 1;
optional int64 stayShowTime = 2;
optional string hashTag = 3;
optional string words = 4;
optional string jumpUrl = 5;
optional string reportExt = 6;
}
message StShare {
optional string title = 1;
optional string desc = 2;
optional uint32 type = 3;
optional string url = 4;
optional StUser author = 5;
optional StUser poster = 6;
repeated StVideo videos = 7;
optional string shorturl = 8;
optional string shareCardInfo = 9;
optional StShareQzoneInfo shareQzoneInfo = 10;
repeated StImage images = 11;
optional uint32 publishTotalUser = 12;
optional uint32 sharedCount = 13;
optional StChannelShareInfo channelShareInfo = 14;
}
message StShareQzoneInfo {
repeated CommonEntry entrys = 1;
}
message StSingleMaterial {
optional string materialId = 1;
}
message StSingleRecomReportInfo {
optional string reportID = 1;
optional bytes reportData = 2;
}
message StTagInfo {
optional string tagId = 1;
optional string tagName = 2;
optional string tagDec = 3;
repeated StUser userList = 4;
repeated StFeedAbstract feedList = 5;
optional uint32 tagTotalUser = 6;
optional uint32 tagTotalFeed = 7;
optional string tagWording = 8;
optional uint32 tagType = 9;
optional uint32 followState = 10;
optional StShare shareInfo = 11;
optional uint32 isTop = 12;
optional uint32 isSelected = 13;
optional int64 userViewHistory = 14;
optional StTagMedalInfo medal = 15;
optional uint32 status = 16;
optional StTagOperateInfo optInfo = 17;
optional uint32 tagBaseStatus = 18;
optional int32 isRecommend = 19;
optional int64 tagViewHistory = 20;
optional string operateIconUrl = 21;
optional string tagReport = 99;
optional string tagIconUrl = 100;
}
message StTagMedalInfo {
optional string tagID = 1;
optional string tagName = 2;
optional uint64 rank = 3;
}
message StTagOperateInfo {
optional string createUser = 1;
optional string coverURL = 2;
optional string desc = 3;
optional string backgroundURL = 4;
optional string bannerURL = 5;
optional string bannerSkipLink = 6;
optional int64 activityStartTime = 7;
optional int64 activityEndTime = 8;
optional string recommendReason = 9;
optional int32 isWhite = 10;
optional int64 beWhiteStartTime = 11;
optional int64 beWhiteEndTime = 12;
optional string publishSchema = 13;
}
message StUnifiedTag {
optional string unifiedType = 1;
optional string unifiedId = 2;
}
message StUser {
optional string id = 1;
optional string nick = 2;
optional StIconInfo icon = 3;
optional string desc = 4;
optional uint32 followState = 5;
optional uint32 type = 6;
optional uint32 sex = 7;
optional uint64 birthday = 8;
optional string school = 9;
optional string location = 11;
optional bytes busiData = 12;
optional uint32 frdState = 13;
optional uint32 relationState = 14;
optional uint32 blackState = 15;
optional StTagMedalInfo medal = 16;
optional int32 constellation = 17;
optional string jumpUrl = 18;
optional string locationCode = 19;
optional string thirdId = 20;
optional string company = 21;
optional string certificationDesc = 22;
optional uint32 descType = 23;
optional GuildChannelBaseChannelUserInfo channelUserInfo = 24;
optional string loginId = 25;
}
message GuildChannelBaseChannelUserInfo {
optional ClientIdentity clientIdentity = 1;
optional uint32 memberType = 2;
// optional ChannelUserPermission permission = 3;
repeated GuildChannelBaseRoleGroupInfo roleGroups = 4;
}
message StUserGroupInfo {
optional string id = 1;
optional string name = 2;
repeated StUser userList = 3;
}
message StUserRecomInfo {
optional StUser user = 1;
repeated StFeedAbstract feedList = 2;
optional bytes busiData = 3;
}
message StVideo {
optional string fileId = 1;
optional uint32 fileSize = 2;
optional uint32 duration = 3;
optional uint32 width = 4;
optional uint32 height = 5;
optional string playUrl = 6;
optional uint32 transStatus = 7;
optional uint32 videoPrior = 8;
optional uint32 videoRate = 9;
repeated StVideoUrl vecVideoUrl = 10;
optional bytes busiData = 11;
optional uint32 approvalStatus = 12;
optional uint32 videoSource = 13;
optional uint32 mediaQualityRank = 14;
optional float mediaQualityScore = 15;
optional string videoMD5 = 16;
optional uint32 isQuic = 17;
optional uint32 orientation = 18;
optional StImage cover = 19;
optional string patternId = 20;
optional uint32 displayIndex = 21;
}
message StVideoUrl {
optional uint32 levelType = 1;
optional string playUrl = 2;
optional uint32 videoPrior = 3;
optional uint32 videoRate = 4;
optional uint32 transStatus = 5;
optional bytes busiData = 6;
optional bool hasWatermark = 7;
}
message StVisitor {
optional uint32 viewCount = 1;
optional bytes busiData = 2;
optional uint32 recomCount = 3;
optional string viewDesc = 4;
}
message StWearingMedal {
repeated StWearingMedalInfo medalInfos = 1;
}
message StWearingMedalInfo {
optional int32 type = 1;
optional string medalName = 2;
optional string medalID = 3;
}

View File

@ -1,101 +0,0 @@
// Code generated by protoc-gen-golite. DO NOT EDIT.
// source: pb/channel/GuildFeedCloudRead.proto
package channel
import (
proto "github.com/RomiChan/protobuf/proto"
)
type GetNoticesReq struct {
ExtInfo *StCommonExt `protobuf:"bytes,1,opt"`
PageNum proto.Option[uint32] `protobuf:"varint,2,opt"`
AttachInfo proto.Option[string] `protobuf:"bytes,3,opt"`
_ [0]func()
}
type GetNoticesRsp struct {
ExtInfo *StCommonExt `protobuf:"bytes,1,opt"`
Notices []*StNotice `protobuf:"bytes,2,rep"`
TotalNum proto.Option[uint32] `protobuf:"varint,3,opt"`
IsFinish proto.Option[bool] `protobuf:"varint,4,opt"`
AttachInfo proto.Option[string] `protobuf:"bytes,5,opt"`
}
type NeedInsertCommentInfo struct {
CommentID proto.Option[string] `protobuf:"bytes,1,opt"`
_ [0]func()
}
type RefreshToast struct {
Text proto.Option[string] `protobuf:"bytes,1,opt"`
_ [0]func()
}
type StGetChannelFeedsReq struct {
ExtInfo *StCommonExt `protobuf:"bytes,1,opt"`
Count proto.Option[uint32] `protobuf:"varint,2,opt"`
From proto.Option[uint32] `protobuf:"varint,3,opt"`
ChannelSign *StChannelSign `protobuf:"bytes,4,opt"`
FeedAttchInfo proto.Option[string] `protobuf:"bytes,5,opt"`
_ [0]func()
}
type StGetChannelFeedsRsp struct {
ExtInfo *StCommonExt `protobuf:"bytes,1,opt"`
VecFeed []*StFeed `protobuf:"bytes,2,rep"`
IsFinish proto.Option[uint32] `protobuf:"varint,3,opt"`
User *StUser `protobuf:"bytes,4,opt"`
FeedAttchInfo proto.Option[string] `protobuf:"bytes,5,opt"`
RefreshToast *RefreshToast `protobuf:"bytes,6,opt"`
}
type StGetChannelShareFeedReq struct {
ExtInfo *StCommonExt `protobuf:"bytes,1,opt"`
From proto.Option[uint32] `protobuf:"varint,2,opt"`
ChannelShareInfo *StChannelShareInfo `protobuf:"bytes,3,opt"`
_ [0]func()
}
type StGetChannelShareFeedRsp struct {
ExtInfo *StCommonExt `protobuf:"bytes,1,opt"`
Feed *StFeed `protobuf:"bytes,2,opt"`
_ [0]func()
}
type StGetFeedCommentsReq struct {
ExtInfo *StCommonExt `protobuf:"bytes,1,opt"`
UserId proto.Option[string] `protobuf:"bytes,2,opt"`
FeedId proto.Option[string] `protobuf:"bytes,3,opt"`
ListNum proto.Option[uint32] `protobuf:"varint,4,opt"`
From proto.Option[uint32] `protobuf:"varint,5,opt"`
AttchInfo proto.Option[string] `protobuf:"bytes,6,opt"`
EntrySchema proto.Option[string] `protobuf:"bytes,7,opt"`
_ [0]func()
}
type StGetFeedCommentsRsp struct {
ExtInfo *StCommonExt `protobuf:"bytes,1,opt"`
VecComment []*StComment `protobuf:"bytes,2,rep"`
TotalNum proto.Option[uint32] `protobuf:"varint,3,opt"`
IsFinish proto.Option[uint32] `protobuf:"varint,4,opt"`
AttchInfo proto.Option[string] `protobuf:"bytes,5,opt"`
}
type StGetFeedDetailReq struct {
ExtInfo *StCommonExt `protobuf:"bytes,1,opt"`
From proto.Option[uint32] `protobuf:"varint,2,opt"`
UserId proto.Option[string] `protobuf:"bytes,3,opt"`
FeedId proto.Option[string] `protobuf:"bytes,4,opt"`
CreateTime proto.Option[uint64] `protobuf:"varint,5,opt"`
DetailType proto.Option[uint32] `protobuf:"varint,6,opt"`
ChannelSign *StChannelSign `protobuf:"bytes,7,opt"`
_ [0]func()
}
type StGetFeedDetailRsp struct {
ExtInfo *StCommonExt `protobuf:"bytes,1,opt"`
Feed *StFeed `protobuf:"bytes,2,opt"`
LoginUser *StUser `protobuf:"bytes,3,opt"`
_ [0]func()
}

View File

@ -1,93 +0,0 @@
syntax = "proto2";
package channel;
option go_package = "github.com/Mrs4s/MiraiGo/client/pb/channel";
import "pb/channel/GuildFeedCloudMeta.proto";
import "pb/channel/GuildChannelBase.proto";
message GetNoticesReq {
optional StCommonExt extInfo = 1;
optional uint32 pageNum = 2;
optional string attachInfo = 3;
}
message GetNoticesRsp {
optional StCommonExt extInfo = 1;
repeated StNotice notices = 2;
optional uint32 totalNum = 3;
optional bool isFinish = 4;
optional string attachInfo = 5;
}
message NeedInsertCommentInfo {
optional string commentID = 1;
}
message RefreshToast {
optional string text = 1;
}
message StGetChannelFeedsReq {
optional StCommonExt extInfo = 1;
optional uint32 count = 2;
optional uint32 from = 3;
optional StChannelSign channelSign = 4;
optional string feedAttchInfo = 5;
}
message StGetChannelFeedsRsp {
optional StCommonExt extInfo = 1;
repeated StFeed vecFeed = 2;
optional uint32 isFinish = 3;
optional StUser user = 4;
optional string feedAttchInfo = 5;
optional RefreshToast refreshToast = 6;
}
message StGetChannelShareFeedReq {
optional StCommonExt extInfo = 1;
optional uint32 from = 2;
optional StChannelShareInfo channelShareInfo = 3;
}
message StGetChannelShareFeedRsp {
optional StCommonExt extInfo = 1;
optional StFeed feed = 2;
}
message StGetFeedCommentsReq {
optional StCommonExt extInfo = 1;
optional string userId = 2;
optional string feedId = 3;
optional uint32 listNum = 4;
optional uint32 from = 5;
optional string attchInfo = 6;
optional string entrySchema = 7;
}
message StGetFeedCommentsRsp {
optional StCommonExt extInfo = 1;
repeated StComment vecComment = 2;
optional uint32 totalNum = 3;
optional uint32 isFinish = 4;
optional string attchInfo = 5;
}
message StGetFeedDetailReq {
optional StCommonExt extInfo = 1;
optional uint32 from = 2;
optional string userId = 3;
optional string feedId = 4;
optional uint64 createTime = 5;
optional uint32 detailType = 6;
optional StChannelSign channelSign = 7;
}
message StGetFeedDetailRsp {
optional StCommonExt extInfo = 1;
optional StFeed feed = 2;
optional StUser loginUser = 3;
}

View File

@ -1,159 +0,0 @@
// Code generated by protoc-gen-golite. DO NOT EDIT.
// source: pb/channel/GuildWriter.proto
package channel
import (
proto "github.com/RomiChan/protobuf/proto"
)
type StAlterFeedReq struct {
ExtInfo *StCommonExt `protobuf:"bytes,1,opt"`
Feed *StFeed `protobuf:"bytes,2,opt"`
BusiReqData []byte `protobuf:"bytes,3,opt"`
MBitmap proto.Option[uint64] `protobuf:"varint,4,opt"`
From proto.Option[int32] `protobuf:"varint,5,opt"`
Src proto.Option[int32] `protobuf:"varint,6,opt"`
AlterFeedExtInfo []*CommonEntry `protobuf:"bytes,7,rep"`
JsonFeed proto.Option[string] `protobuf:"bytes,8,opt"`
ClientContent *StClientContent `protobuf:"bytes,9,opt"`
}
type StAlterFeedRsp struct {
ExtInfo *StCommonExt `protobuf:"bytes,1,opt"`
Feed *StFeed `protobuf:"bytes,2,opt"`
BusiRspData []byte `protobuf:"bytes,3,opt"`
}
type StClientContent struct {
ClientImageContents []*StClientImageContent `protobuf:"bytes,1,rep"`
ClientVideoContents []*StClientVideoContent `protobuf:"bytes,2,rep"`
}
type StClientImageContent struct {
TaskId proto.Option[string] `protobuf:"bytes,1,opt"`
PicId proto.Option[string] `protobuf:"bytes,2,opt"`
Url proto.Option[string] `protobuf:"bytes,3,opt"`
_ [0]func()
}
type StClientVideoContent struct {
TaskId proto.Option[string] `protobuf:"bytes,1,opt"`
VideoId proto.Option[string] `protobuf:"bytes,2,opt"`
VideoUrl proto.Option[string] `protobuf:"bytes,3,opt"`
CoverUrl proto.Option[string] `protobuf:"bytes,4,opt"`
_ [0]func()
}
type StDelFeedReq struct {
ExtInfo *StCommonExt `protobuf:"bytes,1,opt"`
Feed *StFeed `protobuf:"bytes,2,opt"`
From proto.Option[int32] `protobuf:"varint,3,opt"`
Src proto.Option[int32] `protobuf:"varint,4,opt"`
_ [0]func()
}
type StDelFeedRsp struct {
ExtInfo *StCommonExt `protobuf:"bytes,1,opt"`
_ [0]func()
}
type StDoCommentReq struct {
ExtInfo *StCommonExt `protobuf:"bytes,1,opt"`
CommentType proto.Option[uint32] `protobuf:"varint,2,opt"`
Comment *StComment `protobuf:"bytes,3,opt"`
Feed *StFeed `protobuf:"bytes,4,opt"`
From proto.Option[int32] `protobuf:"varint,5,opt"`
BusiReqData []byte `protobuf:"bytes,6,opt"`
Src proto.Option[int32] `protobuf:"varint,7,opt"`
}
type StDoCommentRsp struct {
ExtInfo *StCommonExt `protobuf:"bytes,1,opt"`
Comment *StComment `protobuf:"bytes,2,opt"`
BusiRspData []byte `protobuf:"bytes,3,opt"`
}
type StDoLikeReq struct {
ExtInfo *StCommonExt `protobuf:"bytes,1,opt"`
LikeType proto.Option[uint32] `protobuf:"varint,2,opt"`
Like *StLike `protobuf:"bytes,3,opt"`
Feed *StFeed `protobuf:"bytes,4,opt"`
BusiReqData []byte `protobuf:"bytes,5,opt"`
Comment *StComment `protobuf:"bytes,6,opt"`
Reply *StReply `protobuf:"bytes,7,opt"`
From proto.Option[int32] `protobuf:"varint,8,opt"`
Src proto.Option[int32] `protobuf:"varint,9,opt"`
EmotionReaction *StEmotionReactionInfo `protobuf:"bytes,10,opt"`
}
type StDoLikeRsp struct {
ExtInfo *StCommonExt `protobuf:"bytes,1,opt"`
Like *StLike `protobuf:"bytes,2,opt"`
BusiRspData []byte `protobuf:"bytes,3,opt"`
EmotionReaction *StEmotionReactionInfo `protobuf:"bytes,4,opt"`
}
type StDoReplyReq struct {
ExtInfo *StCommonExt `protobuf:"bytes,1,opt"`
ReplyType proto.Option[uint32] `protobuf:"varint,2,opt"`
Reply *StReply `protobuf:"bytes,3,opt"`
Comment *StComment `protobuf:"bytes,4,opt"`
Feed *StFeed `protobuf:"bytes,5,opt"`
From proto.Option[int32] `protobuf:"varint,6,opt"`
BusiReqData []byte `protobuf:"bytes,7,opt"`
Src proto.Option[int32] `protobuf:"varint,8,opt"`
}
type StDoReplyRsp struct {
ExtInfo *StCommonExt `protobuf:"bytes,1,opt"`
Reply *StReply `protobuf:"bytes,2,opt"`
BusiRspData []byte `protobuf:"bytes,3,opt"`
}
type StDoSecurityReq struct {
ExtInfo *StCommonExt `protobuf:"bytes,1,opt"`
Feed *StFeed `protobuf:"bytes,2,opt"`
Comment *StComment `protobuf:"bytes,3,opt"`
Reply *StReply `protobuf:"bytes,4,opt"`
Poster *StUser `protobuf:"bytes,5,opt"`
SecType proto.Option[int32] `protobuf:"varint,6,opt"`
_ [0]func()
}
type StDoSecurityRsp struct {
ExtInfo *StCommonExt `protobuf:"bytes,1,opt"`
_ [0]func()
}
type StModifyFeedReq struct {
ExtInfo *StCommonExt `protobuf:"bytes,1,opt"`
Feed *StFeed `protobuf:"bytes,2,opt"`
MBitmap proto.Option[uint64] `protobuf:"varint,3,opt"`
From proto.Option[int32] `protobuf:"varint,4,opt"`
Src proto.Option[int32] `protobuf:"varint,5,opt"`
ModifyFeedExtInfo []*CommonEntry `protobuf:"bytes,6,rep"`
}
type StModifyFeedRsp struct {
ExtInfo *StCommonExt `protobuf:"bytes,1,opt"`
Feed *StFeed `protobuf:"bytes,2,opt"`
BusiRspData []byte `protobuf:"bytes,3,opt"`
}
type StPublishFeedReq struct {
ExtInfo *StCommonExt `protobuf:"bytes,1,opt"`
Feed *StFeed `protobuf:"bytes,2,opt"`
BusiReqData []byte `protobuf:"bytes,3,opt"`
From proto.Option[int32] `protobuf:"varint,4,opt"`
Src proto.Option[int32] `protobuf:"varint,5,opt"`
StoreFeedExtInfo []*CommonEntry `protobuf:"bytes,6,rep"`
JsonFeed proto.Option[string] `protobuf:"bytes,7,opt"`
ClientContent *StClientContent `protobuf:"bytes,8,opt"`
}
type StPublishFeedRsp struct {
ExtInfo *StCommonExt `protobuf:"bytes,1,opt"`
Feed *StFeed `protobuf:"bytes,2,opt"`
BusiRspData []byte `protobuf:"bytes,3,opt"`
}

View File

@ -1,154 +0,0 @@
syntax = "proto2";
package channel;
option go_package = "github.com/Mrs4s/MiraiGo/client/pb/channel";
import "pb/channel/GuildFeedCloudMeta.proto";
import "pb/channel/GuildChannelBase.proto";
message StAlterFeedReq {
optional StCommonExt extInfo = 1;
optional StFeed feed = 2;
optional bytes busiReqData = 3;
optional uint64 mBitmap = 4;
optional int32 from = 5;
optional int32 src = 6;
repeated CommonEntry alterFeedExtInfo = 7;
optional string jsonFeed = 8;
optional StClientContent clientContent = 9;
}
message StAlterFeedRsp {
optional StCommonExt extInfo = 1;
optional StFeed feed = 2;
optional bytes busiRspData = 3;
}
message StClientContent {
repeated StClientImageContent clientImageContents = 1;
repeated StClientVideoContent clientVideoContents = 2;
}
message StClientImageContent {
optional string taskId = 1;
optional string picId = 2;
optional string url = 3;
}
message StClientVideoContent {
optional string taskId = 1;
optional string videoId = 2;
optional string videoUrl = 3;
optional string coverUrl = 4;
}
message StDelFeedReq {
optional StCommonExt extInfo = 1;
optional StFeed feed = 2;
optional int32 from = 3;
optional int32 src = 4;
}
message StDelFeedRsp {
optional StCommonExt extInfo = 1;
}
message StDoCommentReq {
optional StCommonExt extInfo = 1;
optional uint32 commentType = 2;
optional StComment comment = 3;
optional StFeed feed = 4;
optional int32 from = 5;
optional bytes busiReqData = 6;
optional int32 src = 7;
}
message StDoCommentRsp {
optional StCommonExt extInfo = 1;
optional StComment comment = 2;
optional bytes busiRspData = 3;
}
message StDoLikeReq {
optional StCommonExt extInfo = 1;
optional uint32 likeType = 2;
optional StLike like = 3;
optional StFeed feed = 4;
optional bytes busiReqData = 5;
optional StComment comment = 6;
optional StReply reply = 7;
optional int32 from = 8;
optional int32 src = 9;
optional StEmotionReactionInfo emotionReaction = 10;
}
message StDoLikeRsp {
optional StCommonExt extInfo = 1;
optional StLike like = 2;
optional bytes busiRspData = 3;
optional StEmotionReactionInfo emotionReaction = 4;
}
message StDoReplyReq {
optional StCommonExt extInfo = 1;
optional uint32 replyType = 2;
optional StReply reply = 3;
optional StComment comment = 4;
optional StFeed feed = 5;
optional int32 from = 6;
optional bytes busiReqData = 7;
optional int32 src = 8;
}
message StDoReplyRsp {
optional StCommonExt extInfo = 1;
optional StReply reply = 2;
optional bytes busiRspData = 3;
}
message StDoSecurityReq {
optional StCommonExt extInfo = 1;
optional StFeed feed = 2;
optional StComment comment = 3;
optional StReply reply = 4;
optional StUser poster = 5;
optional int32 secType = 6;
}
message StDoSecurityRsp {
optional StCommonExt extInfo = 1;
}
message StModifyFeedReq {
optional StCommonExt extInfo = 1;
optional StFeed feed = 2;
optional uint64 mBitmap = 3;
optional int32 from = 4;
optional int32 src = 5;
repeated CommonEntry modifyFeedExtInfo = 6;
}
message StModifyFeedRsp {
optional StCommonExt extInfo = 1;
optional StFeed feed = 2;
optional bytes busiRspData = 3;
}
message StPublishFeedReq {
optional StCommonExt extInfo = 1;
optional StFeed feed = 2;
optional bytes busiReqData = 3;
optional int32 from = 4;
optional int32 src = 5;
repeated CommonEntry storeFeedExtInfo = 6;
optional string jsonFeed = 7;
optional StClientContent clientContent = 8;
}
message StPublishFeedRsp {
optional StCommonExt extInfo = 1;
optional StFeed feed = 2;
optional bytes busiRspData = 3;
}

View File

@ -1,61 +0,0 @@
// Code generated by protoc-gen-golite. DO NOT EDIT.
// source: pb/channel/MsgResponsesSvr.proto
package channel
import (
proto "github.com/RomiChan/protobuf/proto"
)
type BatchGetMsgRspCountReq struct {
GuildMsgList []*GuildMsg `protobuf:"bytes,1,rep"`
}
type BatchGetMsgRspCountRsp struct {
GuildMsgInfoList []*GuildMsgInfo `protobuf:"bytes,1,rep"`
}
type SvrChannelMsg struct {
ChannelId proto.Option[uint64] `protobuf:"varint,1,opt"`
Id []*MsgId `protobuf:"bytes,2,rep"`
}
type ChannelMsgInfo struct {
ChannelId proto.Option[uint64] `protobuf:"varint,1,opt"`
RespData []*MsgRespData `protobuf:"bytes,2,rep"`
}
type EmojiReaction struct {
EmojiId proto.Option[string] `protobuf:"bytes,1,opt"`
EmojiType proto.Option[uint64] `protobuf:"varint,2,opt"`
Cnt proto.Option[uint64] `protobuf:"varint,3,opt"`
IsClicked proto.Option[bool] `protobuf:"varint,4,opt"`
IsDefaultEmoji proto.Option[bool] `protobuf:"varint,10001,opt"`
_ [0]func()
}
type GuildMsg struct {
GuildId proto.Option[uint64] `protobuf:"varint,1,opt"`
ChannelMsgList []*SvrChannelMsg `protobuf:"bytes,2,rep"`
}
type GuildMsgInfo struct {
GuildId proto.Option[uint64] `protobuf:"varint,1,opt"`
ChannelMsgInfoList []*ChannelMsgInfo `protobuf:"bytes,2,rep"`
}
type MsgCnt struct {
Id *MsgId `protobuf:"bytes,1,opt"`
EmojiReaction []*EmojiReaction `protobuf:"bytes,2,rep"`
}
type MsgId struct {
Version proto.Option[uint64] `protobuf:"varint,1,opt"`
Seq proto.Option[uint64] `protobuf:"varint,2,opt"`
_ [0]func()
}
type MsgRespData struct {
Id *MsgId `protobuf:"bytes,1,opt"`
Cnt []byte `protobuf:"bytes,2,opt"`
}

View File

@ -1,146 +0,0 @@
// Code generated by protoc-gen-golite. DO NOT EDIT.
// source: pb/channel/common.proto
package channel
import (
msg "github.com/Mrs4s/MiraiGo/client/pb/msg"
proto "github.com/RomiChan/protobuf/proto"
)
type ChannelContentHead struct {
Type proto.Option[uint64] `protobuf:"varint,1,opt"`
SubType proto.Option[uint64] `protobuf:"varint,2,opt"`
Random proto.Option[uint64] `protobuf:"varint,3,opt"`
Seq proto.Option[uint64] `protobuf:"varint,4,opt"`
CntSeq proto.Option[uint64] `protobuf:"varint,5,opt"`
Time proto.Option[uint64] `protobuf:"varint,6,opt"`
Meta []byte `protobuf:"bytes,7,opt"`
}
type DirectMessageMember struct {
Uin proto.Option[uint64] `protobuf:"varint,1,opt"`
Tinyid proto.Option[uint64] `protobuf:"varint,2,opt"`
SourceGuildId proto.Option[uint64] `protobuf:"varint,3,opt"`
SourceGuildName []byte `protobuf:"bytes,4,opt"`
NickName []byte `protobuf:"bytes,5,opt"`
MemberName []byte `protobuf:"bytes,6,opt"`
NotifyType proto.Option[uint32] `protobuf:"varint,7,opt"`
}
type ChannelEvent struct {
Type proto.Option[uint64] `protobuf:"varint,1,opt"`
Version proto.Option[uint64] `protobuf:"varint,2,opt"`
OpInfo *ChannelMsgOpInfo `protobuf:"bytes,3,opt"`
_ [0]func()
}
type ChannelExtInfo struct {
FromNick []byte `protobuf:"bytes,1,opt"`
GuildName []byte `protobuf:"bytes,2,opt"`
ChannelName []byte `protobuf:"bytes,3,opt"`
Visibility proto.Option[uint32] `protobuf:"varint,4,opt"`
NotifyType proto.Option[uint32] `protobuf:"varint,5,opt"`
OfflineFlag proto.Option[uint32] `protobuf:"varint,6,opt"`
NameType proto.Option[uint32] `protobuf:"varint,7,opt"`
MemberName []byte `protobuf:"bytes,8,opt"`
Timestamp proto.Option[uint32] `protobuf:"varint,9,opt"`
EventVersion proto.Option[uint64] `protobuf:"varint,10,opt"`
Events []*ChannelEvent `protobuf:"bytes,11,rep"`
FromRoleInfo *ChannelRole `protobuf:"bytes,12,opt"`
FreqLimitInfo *ChannelFreqLimitInfo `protobuf:"bytes,13,opt"`
DirectMessageMember []*DirectMessageMember `protobuf:"bytes,14,rep"`
}
type ChannelFreqLimitInfo struct {
IsLimited proto.Option[uint32] `protobuf:"varint,1,opt"`
LeftCount proto.Option[uint32] `protobuf:"varint,2,opt"`
LimitTimestamp proto.Option[uint64] `protobuf:"varint,3,opt"`
_ [0]func()
}
type ChannelInfo struct {
Id proto.Option[uint64] `protobuf:"varint,1,opt"`
Name []byte `protobuf:"bytes,2,opt"`
Color proto.Option[uint32] `protobuf:"varint,3,opt"`
Hoist proto.Option[uint32] `protobuf:"varint,4,opt"`
}
type ChannelLoginSig struct {
Type proto.Option[uint32] `protobuf:"varint,1,opt"`
Sig []byte `protobuf:"bytes,2,opt"`
Appid proto.Option[uint32] `protobuf:"varint,3,opt"`
}
type ChannelMeta struct {
FromUin proto.Option[uint64] `protobuf:"varint,1,opt"`
LoginSig *ChannelLoginSig `protobuf:"bytes,2,opt"`
_ [0]func()
}
type ChannelMsgContent struct {
Head *ChannelMsgHead `protobuf:"bytes,1,opt"`
CtrlHead *ChannelMsgCtrlHead `protobuf:"bytes,2,opt"`
Body *msg.MessageBody `protobuf:"bytes,3,opt"`
ExtInfo *ChannelExtInfo `protobuf:"bytes,4,opt"`
_ [0]func()
}
type ChannelMsgCtrlHead struct {
IncludeUin [][]byte `protobuf:"bytes,1,rep"`
// repeated uint64 excludeUin = 2; // bytes?
// repeated uint64 featureid = 3;
OfflineFlag proto.Option[uint32] `protobuf:"varint,4,opt"`
Visibility proto.Option[uint32] `protobuf:"varint,5,opt"`
CtrlFlag proto.Option[uint64] `protobuf:"varint,6,opt"`
Events []*ChannelEvent `protobuf:"bytes,7,rep"`
Level proto.Option[uint64] `protobuf:"varint,8,opt"`
PersonalLevels []*PersonalLevel `protobuf:"bytes,9,rep"`
GuildSyncSeq proto.Option[uint64] `protobuf:"varint,10,opt"`
MemberNum proto.Option[uint32] `protobuf:"varint,11,opt"`
ChannelType proto.Option[uint32] `protobuf:"varint,12,opt"`
PrivateType proto.Option[uint32] `protobuf:"varint,13,opt"`
}
type ChannelMsgHead struct {
RoutingHead *ChannelRoutingHead `protobuf:"bytes,1,opt"`
ContentHead *ChannelContentHead `protobuf:"bytes,2,opt"`
_ [0]func()
}
type ChannelMsgMeta struct {
AtAllSeq proto.Option[uint64] `protobuf:"varint,1,opt"`
_ [0]func()
}
type ChannelMsgOpInfo struct {
OperatorTinyid proto.Option[uint64] `protobuf:"varint,1,opt"`
OperatorRole proto.Option[uint64] `protobuf:"varint,2,opt"`
Reason proto.Option[uint64] `protobuf:"varint,3,opt"`
Timestamp proto.Option[uint64] `protobuf:"varint,4,opt"`
AtType proto.Option[uint64] `protobuf:"varint,5,opt"`
_ [0]func()
}
type PersonalLevel struct {
ToUin proto.Option[uint64] `protobuf:"varint,1,opt"`
Level proto.Option[uint64] `protobuf:"varint,2,opt"`
_ [0]func()
}
type ChannelRole struct {
Id proto.Option[uint64] `protobuf:"varint,1,opt"`
Info []byte `protobuf:"bytes,2,opt"`
Flag proto.Option[uint32] `protobuf:"varint,3,opt"`
}
type ChannelRoutingHead struct {
GuildId proto.Option[uint64] `protobuf:"varint,1,opt"`
ChannelId proto.Option[uint64] `protobuf:"varint,2,opt"`
FromUin proto.Option[uint64] `protobuf:"varint,3,opt"`
FromTinyid proto.Option[uint64] `protobuf:"varint,4,opt"`
GuildCode proto.Option[uint64] `protobuf:"varint,5,opt"`
FromAppid proto.Option[uint64] `protobuf:"varint,6,opt"`
DirectMessageFlag proto.Option[uint32] `protobuf:"varint,7,opt"`
_ [0]func()
}

View File

@ -1,37 +0,0 @@
// Code generated by protoc-gen-golite. DO NOT EDIT.
// source: pb/channel/msgpush.proto
package channel
import (
proto "github.com/RomiChan/protobuf/proto"
)
type FocusInfo struct {
ChannelIdList []uint64 `protobuf:"varint,1,rep"`
}
type MsgOnlinePush struct {
Msgs []*ChannelMsgContent `protobuf:"bytes,1,rep"`
GeneralFlag proto.Option[uint32] `protobuf:"varint,2,opt"`
NeedResp proto.Option[uint32] `protobuf:"varint,3,opt"`
ServerBuf []byte `protobuf:"bytes,4,opt"`
CompressFlag proto.Option[uint32] `protobuf:"varint,5,opt"`
CompressMsg []byte `protobuf:"bytes,6,opt"`
FocusInfo *FocusInfo `protobuf:"bytes,7,opt"`
HugeFlag proto.Option[uint32] `protobuf:"varint,8,opt"`
}
type MsgPushResp struct {
ServerBuf []byte `protobuf:"bytes,1,opt"`
}
type PressMsg struct {
Msgs []*ChannelMsgContent `protobuf:"bytes,1,rep"`
}
type ServerBuf struct {
SvrIp proto.Option[uint32] `protobuf:"varint,1,opt"`
SvrPort proto.Option[uint32] `protobuf:"varint,2,opt"`
EchoKey []byte `protobuf:"bytes,3,opt"`
}

View File

@ -1,32 +0,0 @@
// Code generated by protoc-gen-golite. DO NOT EDIT.
// source: pb/channel/oidb0xf62.proto
package channel
import (
msg "github.com/Mrs4s/MiraiGo/client/pb/msg"
proto "github.com/RomiChan/protobuf/proto"
)
type DF62ReqBody struct {
Msg *ChannelMsgContent `protobuf:"bytes,1,opt"`
_ [0]func()
}
type DF62RspBody struct {
Result proto.Option[uint32] `protobuf:"varint,1,opt"`
Errmsg []byte `protobuf:"bytes,2,opt"`
SendTime proto.Option[uint32] `protobuf:"varint,3,opt"`
Head *ChannelMsgHead `protobuf:"bytes,4,opt"`
ErrType proto.Option[uint32] `protobuf:"varint,5,opt"`
TransSvrInfo *TransSvrInfo `protobuf:"bytes,6,opt"`
FreqLimitInfo *ChannelFreqLimitInfo `protobuf:"bytes,7,opt"`
Body *msg.MessageBody `protobuf:"bytes,8,opt"`
}
type TransSvrInfo struct {
SubType proto.Option[uint32] `protobuf:"varint,1,opt"`
RetCode proto.Option[int32] `protobuf:"varint,2,opt"`
ErrMsg []byte `protobuf:"bytes,3,opt"`
TransInfo []byte `protobuf:"bytes,4,opt"`
}

View File

@ -1,382 +0,0 @@
// Code generated by protoc-gen-golite. DO NOT EDIT.
// source: pb/channel/servtype.proto
package channel
import (
proto "github.com/RomiChan/protobuf/proto"
)
type AppChannelMsg struct {
Summary proto.Option[string] `protobuf:"bytes,1,opt"`
Msg proto.Option[string] `protobuf:"bytes,2,opt"`
ExpireTimeMs proto.Option[uint64] `protobuf:"varint,3,opt"`
SchemaType proto.Option[uint32] `protobuf:"varint,4,opt"`
Schema proto.Option[string] `protobuf:"bytes,5,opt"`
_ [0]func()
}
type CategoryChannelInfo struct {
ChannelIndex proto.Option[uint32] `protobuf:"varint,1,opt"`
ChannelId proto.Option[uint64] `protobuf:"varint,2,opt"`
_ [0]func()
}
type CategoryInfo struct {
CategoryIndex proto.Option[uint32] `protobuf:"varint,1,opt"`
ChannelInfo []*CategoryChannelInfo `protobuf:"bytes,2,rep"`
CategoryName []byte `protobuf:"bytes,3,opt"`
CategoryId proto.Option[uint64] `protobuf:"varint,4,opt"`
}
type ChanInfoFilter struct {
ChannelName proto.Option[uint32] `protobuf:"varint,2,opt"`
CreatorId proto.Option[uint32] `protobuf:"varint,3,opt"`
CreateTime proto.Option[uint32] `protobuf:"varint,4,opt"`
GuildId proto.Option[uint32] `protobuf:"varint,5,opt"`
MsgNotifyType proto.Option[uint32] `protobuf:"varint,6,opt"`
ChannelType proto.Option[uint32] `protobuf:"varint,7,opt"`
SpeakPermission proto.Option[uint32] `protobuf:"varint,8,opt"`
LastMsgSeq proto.Option[uint32] `protobuf:"varint,11,opt"`
LastCntMsgSeq proto.Option[uint32] `protobuf:"varint,12,opt"`
VoiceChannelInfoFilter *VoiceChannelInfoFilter `protobuf:"bytes,14,opt"`
LiveChannelInfoFilter *LiveChannelInfoFilter `protobuf:"bytes,15,opt"`
BannedSpeak proto.Option[uint32] `protobuf:"varint,16,opt"`
_ [0]func()
}
type ChangeChanInfo struct {
GuildId proto.Option[uint64] `protobuf:"varint,1,opt"`
ChanId proto.Option[uint64] `protobuf:"varint,2,opt"`
OperatorId proto.Option[uint64] `protobuf:"varint,3,opt"`
InfoSeq *MsgSeq `protobuf:"bytes,4,opt"`
UpdateType proto.Option[uint32] `protobuf:"varint,5,opt"`
ChanInfoFilter *ChanInfoFilter `protobuf:"bytes,6,opt"`
ChanInfo *ServChannelInfo `protobuf:"bytes,7,opt"`
_ [0]func()
}
type ChangeGuildInfo struct {
GuildId proto.Option[uint64] `protobuf:"varint,1,opt"`
OperatorId proto.Option[uint64] `protobuf:"varint,2,opt"`
InfoSeq *MsgSeq `protobuf:"bytes,3,opt"`
FaceSeq *MsgSeq `protobuf:"bytes,4,opt"`
UpdateType proto.Option[uint32] `protobuf:"varint,5,opt"`
GuildInfoFilter *GuildInfoFilter `protobuf:"bytes,6,opt"`
GuildInfo *GuildInfo `protobuf:"bytes,7,opt"`
_ [0]func()
}
type ChannelID struct {
ChanId proto.Option[uint64] `protobuf:"varint,1,opt"`
_ [0]func()
}
type ServChannelInfo struct {
ChannelId proto.Option[uint64] `protobuf:"varint,1,opt"`
ChannelName []byte `protobuf:"bytes,2,opt"`
CreatorId proto.Option[uint64] `protobuf:"varint,3,opt"`
CreateTime proto.Option[uint64] `protobuf:"varint,4,opt"`
GuildId proto.Option[uint64] `protobuf:"varint,5,opt"`
MsgNotifyType proto.Option[uint32] `protobuf:"varint,6,opt"`
ChannelType proto.Option[uint32] `protobuf:"varint,7,opt"`
SpeakPermission proto.Option[uint32] `protobuf:"varint,8,opt"`
LastMsgSeq *MsgSeq `protobuf:"bytes,11,opt"`
LastCntMsgSeq *MsgSeq `protobuf:"bytes,12,opt"`
VoiceChannelInfo *VoiceChannelInfo `protobuf:"bytes,14,opt"`
LiveChannelInfo *LiveChannelInfo `protobuf:"bytes,15,opt"`
BannedSpeak proto.Option[uint32] `protobuf:"varint,16,opt"`
}
type CommGrayTips struct {
BusiType proto.Option[uint64] `protobuf:"varint,1,opt"`
BusiId proto.Option[uint64] `protobuf:"varint,2,opt"`
CtrlFlag proto.Option[uint32] `protobuf:"varint,3,opt"`
TemplId proto.Option[uint64] `protobuf:"varint,4,opt"`
TemplParam []*CommGrayTips_TemplParam `protobuf:"bytes,5,rep"`
Content []byte `protobuf:"bytes,6,opt"`
TipsSeqId proto.Option[uint64] `protobuf:"varint,10,opt"`
PbReserv []byte `protobuf:"bytes,100,opt"`
}
type CreateChan struct {
GuildId proto.Option[uint64] `protobuf:"varint,1,opt"`
OperatorId proto.Option[uint64] `protobuf:"varint,3,opt"`
CreateId []*ChannelID `protobuf:"bytes,4,rep"`
}
type CreateGuild struct {
OperatorId proto.Option[uint64] `protobuf:"varint,1,opt"`
GuildId proto.Option[uint64] `protobuf:"varint,2,opt"`
_ [0]func()
}
type DestroyChan struct {
GuildId proto.Option[uint64] `protobuf:"varint,1,opt"`
OperatorId proto.Option[uint64] `protobuf:"varint,3,opt"`
DeleteId []*ChannelID `protobuf:"bytes,4,rep"`
}
type DestroyGuild struct {
OperatorId proto.Option[uint64] `protobuf:"varint,1,opt"`
GuildId proto.Option[uint64] `protobuf:"varint,2,opt"`
_ [0]func()
}
type EventBody struct {
ReadNotify *ReadNotify `protobuf:"bytes,1,opt"`
CommGrayTips *CommGrayTips `protobuf:"bytes,2,opt"`
CreateGuild *CreateGuild `protobuf:"bytes,3,opt"`
DestroyGuild *DestroyGuild `protobuf:"bytes,4,opt"`
JoinGuild *JoinGuild `protobuf:"bytes,5,opt"`
KickOffGuild *KickOffGuild `protobuf:"bytes,6,opt"`
QuitGuild *QuitGuild `protobuf:"bytes,7,opt"`
ChangeGuildInfo *ChangeGuildInfo `protobuf:"bytes,8,opt"`
CreateChan *CreateChan `protobuf:"bytes,9,opt"`
DestroyChan *DestroyChan `protobuf:"bytes,10,opt"`
ChangeChanInfo *ChangeChanInfo `protobuf:"bytes,11,opt"`
SetAdmin *SetAdmin `protobuf:"bytes,12,opt"`
SetMsgRecvType *SetMsgRecvType `protobuf:"bytes,13,opt"`
UpdateMsg *UpdateMsg `protobuf:"bytes,14,opt"`
SetTop *SetTop `protobuf:"bytes,17,opt"`
SwitchChannel *SwitchVoiceChannel `protobuf:"bytes,18,opt"`
UpdateCategory *UpdateCategory `protobuf:"bytes,21,opt"`
UpdateVoiceBlockList *UpdateVoiceBlockList `protobuf:"bytes,22,opt"`
SetMute *SetMute `protobuf:"bytes,23,opt"`
LiveStatusChangeRoom *LiveRoomStatusChangeMsg `protobuf:"bytes,24,opt"`
SwitchLiveRoom *SwitchLiveRoom `protobuf:"bytes,25,opt"`
Events []*MsgEvent `protobuf:"bytes,39,rep"`
Scheduler *SchedulerMsg `protobuf:"bytes,40,opt"`
AppChannel *AppChannelMsg `protobuf:"bytes,41,opt"`
FeedEvent *FeedEvent `protobuf:"bytes,44,opt"`
WeakMsgAppChannel *AppChannelMsg `protobuf:"bytes,46,opt"`
ReadFeedNotify *ReadFeedNotify `protobuf:"bytes,48,opt"`
}
type FeedEvent struct {
GuildId proto.Option[uint64] `protobuf:"varint,1,opt"`
ChannelId proto.Option[uint64] `protobuf:"varint,2,opt"`
FeedId proto.Option[string] `protobuf:"bytes,3,opt"`
MsgSummary proto.Option[string] `protobuf:"bytes,4,opt"`
EventTime proto.Option[uint64] `protobuf:"varint,5,opt"`
_ [0]func()
}
type ReadFeedNotify struct {
ReportTime proto.Option[uint64] `protobuf:"varint,2,opt"`
_ [0]func()
}
type GroupProStatus struct {
IsEnable proto.Option[uint32] `protobuf:"varint,1,opt"`
IsBanned proto.Option[uint32] `protobuf:"varint,2,opt"`
IsFrozen proto.Option[uint32] `protobuf:"varint,3,opt"`
_ [0]func()
}
type GuildInfo struct {
GuildCode proto.Option[uint64] `protobuf:"varint,2,opt"`
OwnerId proto.Option[uint64] `protobuf:"varint,3,opt"`
CreateTime proto.Option[uint64] `protobuf:"varint,4,opt"`
MemberMaxNum proto.Option[uint32] `protobuf:"varint,5,opt"`
MemberNum proto.Option[uint32] `protobuf:"varint,6,opt"`
GuildType proto.Option[uint32] `protobuf:"varint,7,opt"`
GuildName []byte `protobuf:"bytes,8,opt"`
RobotList []uint64 `protobuf:"varint,9,rep"`
AdminList []uint64 `protobuf:"varint,10,rep"`
RobotMaxNum proto.Option[uint32] `protobuf:"varint,11,opt"`
AdminMaxNum proto.Option[uint32] `protobuf:"varint,12,opt"`
Profile []byte `protobuf:"bytes,13,opt"`
FaceSeq proto.Option[uint64] `protobuf:"varint,14,opt"`
GuildStatus *GroupProStatus `protobuf:"bytes,15,opt"`
ChannelNum proto.Option[uint32] `protobuf:"varint,16,opt"`
MemberChangeSeq *MsgSeq `protobuf:"bytes,5002,opt"`
GuildInfoChangeSeq *MsgSeq `protobuf:"bytes,5003,opt"`
ChannelChangeSeq *MsgSeq `protobuf:"bytes,5004,opt"`
}
type GuildInfoFilter struct {
GuildCode proto.Option[uint32] `protobuf:"varint,2,opt"`
OwnerId proto.Option[uint32] `protobuf:"varint,3,opt"`
CreateTime proto.Option[uint32] `protobuf:"varint,4,opt"`
MemberMaxNum proto.Option[uint32] `protobuf:"varint,5,opt"`
MemberNum proto.Option[uint32] `protobuf:"varint,6,opt"`
GuildType proto.Option[uint32] `protobuf:"varint,7,opt"`
GuildName proto.Option[uint32] `protobuf:"varint,8,opt"`
RobotList proto.Option[uint32] `protobuf:"varint,9,opt"`
AdminList proto.Option[uint32] `protobuf:"varint,10,opt"`
RobotMaxNum proto.Option[uint32] `protobuf:"varint,11,opt"`
AdminMaxNum proto.Option[uint32] `protobuf:"varint,12,opt"`
Profile proto.Option[uint32] `protobuf:"varint,13,opt"`
FaceSeq proto.Option[uint32] `protobuf:"varint,14,opt"`
GuildStatus proto.Option[uint32] `protobuf:"varint,15,opt"`
ChannelNum proto.Option[uint32] `protobuf:"varint,16,opt"`
MemberChangeSeq proto.Option[uint32] `protobuf:"varint,5002,opt"`
GuildInfoChangeSeq proto.Option[uint32] `protobuf:"varint,5003,opt"`
ChannelChangeSeq proto.Option[uint32] `protobuf:"varint,5004,opt"`
_ [0]func()
}
type JoinGuild struct {
MemberId proto.Option[uint64] `protobuf:"varint,3,opt"`
MemberType proto.Option[uint32] `protobuf:"varint,4,opt"`
MemberTinyid proto.Option[uint64] `protobuf:"varint,5,opt"`
_ [0]func()
}
type KickOffGuild struct {
MemberId proto.Option[uint64] `protobuf:"varint,3,opt"`
SetBlack proto.Option[uint32] `protobuf:"varint,4,opt"`
MemberTinyid proto.Option[uint64] `protobuf:"varint,5,opt"`
_ [0]func()
}
type LiveChannelInfo struct {
RoomId proto.Option[uint64] `protobuf:"varint,1,opt"`
AnchorUin proto.Option[uint64] `protobuf:"varint,2,opt"`
Name []byte `protobuf:"bytes,3,opt"`
}
type LiveChannelInfoFilter struct {
IsNeedRoomId proto.Option[uint32] `protobuf:"varint,1,opt"`
IsNeedAnchorUin proto.Option[uint32] `protobuf:"varint,2,opt"`
IsNeedName proto.Option[uint32] `protobuf:"varint,3,opt"`
_ [0]func()
}
type LiveRoomStatusChangeMsg struct {
GuildId proto.Option[uint64] `protobuf:"varint,1,opt"`
ChannelId proto.Option[uint64] `protobuf:"varint,2,opt"`
RoomId proto.Option[uint64] `protobuf:"varint,3,opt"`
AnchorTinyid proto.Option[uint64] `protobuf:"varint,4,opt"`
Action proto.Option[uint32] `protobuf:"varint,5,opt"`
_ [0]func()
}
type MsgEvent struct {
Seq proto.Option[uint64] `protobuf:"varint,1,opt"`
EventType proto.Option[uint64] `protobuf:"varint,2,opt"`
EventVersion proto.Option[uint64] `protobuf:"varint,3,opt"`
_ [0]func()
}
type MsgSeq struct {
Seq proto.Option[uint64] `protobuf:"varint,1,opt"`
Time proto.Option[uint64] `protobuf:"varint,2,opt"`
_ [0]func()
}
type QuitGuild struct {
_ [0]func()
}
type ReadNotify struct {
ChannelId proto.Option[uint64] `protobuf:"varint,1,opt"`
GuildId proto.Option[uint64] `protobuf:"varint,2,opt"`
ReadMsgSeq *MsgSeq `protobuf:"bytes,3,opt"`
ReadCntMsgSeq *MsgSeq `protobuf:"bytes,4,opt"`
ReadMsgMeta []byte `protobuf:"bytes,5,opt"`
}
type SchedulerMsg struct {
CreatorHeadUrl []byte `protobuf:"bytes,1,opt"`
Wording proto.Option[string] `protobuf:"bytes,2,opt"`
ExpireTimeMs proto.Option[uint64] `protobuf:"varint,3,opt"`
}
type SetAdmin struct {
GuildId proto.Option[uint64] `protobuf:"varint,1,opt"`
ChanId proto.Option[uint64] `protobuf:"varint,2,opt"`
OperatorId proto.Option[uint64] `protobuf:"varint,3,opt"`
AdminId proto.Option[uint64] `protobuf:"varint,4,opt"`
AdminTinyid proto.Option[uint64] `protobuf:"varint,5,opt"`
OperateType proto.Option[uint32] `protobuf:"varint,6,opt"`
_ [0]func()
}
type SetMsgRecvType struct {
GuildId proto.Option[uint64] `protobuf:"varint,1,opt"`
ChanId proto.Option[uint64] `protobuf:"varint,2,opt"`
OperatorId proto.Option[uint64] `protobuf:"varint,3,opt"`
MsgNotifyType proto.Option[uint32] `protobuf:"varint,4,opt"`
_ [0]func()
}
type SetMute struct {
Action proto.Option[uint32] `protobuf:"varint,1,opt"`
TinyID proto.Option[uint64] `protobuf:"varint,2,opt"`
_ [0]func()
}
type SetTop struct {
Action proto.Option[uint32] `protobuf:"varint,1,opt"`
_ [0]func()
}
type SwitchDetail struct {
GuildId proto.Option[uint64] `protobuf:"varint,1,opt"`
ChannelId proto.Option[uint64] `protobuf:"varint,2,opt"`
Platform proto.Option[uint32] `protobuf:"varint,3,opt"`
_ [0]func()
}
type SwitchLiveRoom struct {
GuildId proto.Option[uint64] `protobuf:"varint,1,opt"`
ChannelId proto.Option[uint64] `protobuf:"varint,2,opt"`
// optional uint64 roomId = 3;
// optional uint64 tinyid = 4;
UserInfo *SwitchLiveRoomUserInfo `protobuf:"bytes,3,opt"`
Action proto.Option[uint32] `protobuf:"varint,4,opt"` // JOIN = 1 QUIT = 2
_ [0]func()
}
type SwitchLiveRoomUserInfo struct {
TinyId proto.Option[uint64] `protobuf:"varint,1,opt"`
Nickname proto.Option[string] `protobuf:"bytes,2,opt"`
_ [0]func()
}
type SwitchVoiceChannel struct {
MemberId proto.Option[uint64] `protobuf:"varint,1,opt"`
EnterDetail *SwitchDetail `protobuf:"bytes,2,opt"`
LeaveDetail *SwitchDetail `protobuf:"bytes,3,opt"`
_ [0]func()
}
type UpdateCategory struct {
CategoryInfo []*CategoryInfo `protobuf:"bytes,1,rep"`
NoClassifyCategoryInfo *CategoryInfo `protobuf:"bytes,2,opt"`
}
type UpdateMsg struct {
MsgSeq proto.Option[uint64] `protobuf:"varint,1,opt"`
OrigMsgUncountable proto.Option[bool] `protobuf:"varint,2,opt"`
EventType proto.Option[uint64] `protobuf:"varint,3,opt"`
EventVersion proto.Option[uint64] `protobuf:"varint,4,opt"`
OperatorTinyid proto.Option[uint64] `protobuf:"varint,5,opt"`
OperatorRole proto.Option[uint64] `protobuf:"varint,6,opt"`
Reason proto.Option[uint64] `protobuf:"varint,7,opt"`
Timestamp proto.Option[uint64] `protobuf:"varint,8,opt"`
_ [0]func()
}
type UpdateVoiceBlockList struct {
Action proto.Option[uint32] `protobuf:"varint,1,opt"`
ObjectTinyid proto.Option[uint64] `protobuf:"varint,2,opt"`
_ [0]func()
}
type VoiceChannelInfo struct {
MemberMaxNum proto.Option[uint32] `protobuf:"varint,1,opt"`
_ [0]func()
}
type VoiceChannelInfoFilter struct {
MemberMaxNum proto.Option[uint32] `protobuf:"varint,1,opt"`
_ [0]func()
}
type CommGrayTips_TemplParam struct {
Name []byte `protobuf:"bytes,1,opt"`
Value []byte `protobuf:"bytes,2,opt"`
}

View File

@ -1,138 +0,0 @@
// Code generated by protoc-gen-golite. DO NOT EDIT.
// source: pb/channel/synclogic.proto
package channel
import (
proto "github.com/RomiChan/protobuf/proto"
)
type ChannelMsg struct {
GuildId proto.Option[uint64] `protobuf:"varint,1,opt"`
ChannelId proto.Option[uint64] `protobuf:"varint,2,opt"`
Result proto.Option[uint32] `protobuf:"varint,3,opt"`
RspBeginSeq proto.Option[uint64] `protobuf:"varint,4,opt"`
RspEndSeq proto.Option[uint64] `protobuf:"varint,5,opt"`
Msgs []*ChannelMsgContent `protobuf:"bytes,6,rep"`
}
type ChannelMsgReq struct {
ChannelParam *ChannelParam `protobuf:"bytes,1,opt"`
WithVersionFlag proto.Option[uint32] `protobuf:"varint,2,opt"`
DirectMessageFlag proto.Option[uint32] `protobuf:"varint,3,opt"`
_ [0]func()
}
type ChannelMsgRsp struct {
Result proto.Option[uint32] `protobuf:"varint,1,opt"`
ErrMsg []byte `protobuf:"bytes,2,opt"`
ChannelMsg *ChannelMsg `protobuf:"bytes,3,opt"`
WithVersionFlag proto.Option[uint32] `protobuf:"varint,4,opt"`
GetMsgTime proto.Option[uint64] `protobuf:"varint,5,opt"`
}
type ChannelNode struct {
ChannelId proto.Option[uint64] `protobuf:"varint,1,opt"`
Seq proto.Option[uint64] `protobuf:"varint,2,opt"`
CntSeq proto.Option[uint64] `protobuf:"varint,3,opt"`
Time proto.Option[uint64] `protobuf:"varint,4,opt"`
MemberReadMsgSeq proto.Option[uint64] `protobuf:"varint,5,opt"`
MemberReadCntSeq proto.Option[uint64] `protobuf:"varint,6,opt"`
NotifyType proto.Option[uint32] `protobuf:"varint,7,opt"`
ChannelName []byte `protobuf:"bytes,8,opt"`
ChannelType proto.Option[uint32] `protobuf:"varint,9,opt"`
Meta []byte `protobuf:"bytes,10,opt"`
ReadMsgMeta []byte `protobuf:"bytes,11,opt"`
EventTime proto.Option[uint32] `protobuf:"varint,12,opt"`
}
type ChannelParam struct {
GuildId proto.Option[uint64] `protobuf:"varint,1,opt"`
ChannelId proto.Option[uint64] `protobuf:"varint,2,opt"`
BeginSeq proto.Option[uint64] `protobuf:"varint,3,opt"`
EndSeq proto.Option[uint64] `protobuf:"varint,4,opt"`
Time proto.Option[uint64] `protobuf:"varint,5,opt"`
Version []uint64 `protobuf:"varint,6,rep"`
Seqs []*MsgCond `protobuf:"bytes,7,rep"`
}
type DirectMessageSource struct {
TinyId proto.Option[uint64] `protobuf:"varint,1,opt"`
GuildId proto.Option[uint64] `protobuf:"varint,2,opt"`
GuildName []byte `protobuf:"bytes,3,opt"`
MemberName []byte `protobuf:"bytes,4,opt"`
NickName []byte `protobuf:"bytes,5,opt"`
}
type FirstViewMsg struct {
PushFlag proto.Option[uint32] `protobuf:"varint,1,opt"`
Seq proto.Option[uint32] `protobuf:"varint,2,opt"`
GuildNodes []*GuildNode `protobuf:"bytes,3,rep"`
ChannelMsgs []*ChannelMsg `protobuf:"bytes,4,rep"`
GetMsgTime proto.Option[uint64] `protobuf:"varint,5,opt"`
DirectMessageGuildNodes []*GuildNode `protobuf:"bytes,6,rep"`
}
type FirstViewReq struct {
LastMsgTime proto.Option[uint64] `protobuf:"varint,1,opt"`
UdcFlag proto.Option[uint32] `protobuf:"varint,2,opt"`
Seq proto.Option[uint32] `protobuf:"varint,3,opt"`
DirectMessageFlag proto.Option[uint32] `protobuf:"varint,4,opt"`
_ [0]func()
}
type FirstViewRsp struct {
Result proto.Option[uint32] `protobuf:"varint,1,opt"`
ErrMsg []byte `protobuf:"bytes,2,opt"`
Seq proto.Option[uint32] `protobuf:"varint,3,opt"`
UdcFlag proto.Option[uint32] `protobuf:"varint,4,opt"`
GuildCount proto.Option[uint32] `protobuf:"varint,5,opt"`
SelfTinyid proto.Option[uint64] `protobuf:"varint,6,opt"`
DirectMessageSwitch proto.Option[uint32] `protobuf:"varint,7,opt"`
DirectMessageGuildCount proto.Option[uint32] `protobuf:"varint,8,opt"`
}
type GuildNode struct {
GuildId proto.Option[uint64] `protobuf:"varint,1,opt"`
GuildCode proto.Option[uint64] `protobuf:"varint,2,opt"`
ChannelNodes []*ChannelNode `protobuf:"bytes,3,rep"`
GuildName []byte `protobuf:"bytes,4,opt"`
PeerSource *DirectMessageSource `protobuf:"bytes,5,opt"`
}
type MsgCond struct {
Seq proto.Option[uint64] `protobuf:"varint,1,opt"`
EventVersion proto.Option[uint64] `protobuf:"varint,2,opt"`
_ [0]func()
}
type MultiChannelMsg struct {
PushFlag proto.Option[uint32] `protobuf:"varint,1,opt"`
Seq proto.Option[uint32] `protobuf:"varint,2,opt"`
ChannelMsgs []*ChannelMsg `protobuf:"bytes,3,rep"`
GetMsgTime proto.Option[uint64] `protobuf:"varint,4,opt"`
}
type MultiChannelMsgReq struct {
ChannelParams []*ChannelParam `protobuf:"bytes,1,rep"`
Seq proto.Option[uint32] `protobuf:"varint,2,opt"`
DirectMessageFlag proto.Option[uint32] `protobuf:"varint,3,opt"`
}
type MultiChannelMsgRsp struct {
Result proto.Option[uint32] `protobuf:"varint,1,opt"`
ErrMsg []byte `protobuf:"bytes,2,opt"`
Seq proto.Option[uint32] `protobuf:"varint,3,opt"`
}
type ReqBody struct {
ChannelParam *ChannelParam `protobuf:"bytes,1,opt"`
DirectMessageFlag proto.Option[uint32] `protobuf:"varint,2,opt"`
_ [0]func()
}
type RspBody struct {
Result proto.Option[uint32] `protobuf:"varint,1,opt"`
ErrMsg []byte `protobuf:"bytes,2,opt"`
ChannelMsg *ChannelMsg `protobuf:"bytes,3,opt"`
}

View File

@ -1,172 +0,0 @@
// Code generated by protoc-gen-golite. DO NOT EDIT.
// source: pb/channel/unknown.proto
package channel
import (
proto "github.com/RomiChan/protobuf/proto"
)
// see sub_37628C
type ChannelOidb0Xf5BRsp struct {
GuildId proto.Option[uint64] `protobuf:"varint,1,opt"`
Bots []*GuildMemberInfo `protobuf:"bytes,4,rep"`
Members []*GuildMemberInfo `protobuf:"bytes,5,rep"`
NextIndex proto.Option[uint32] `protobuf:"varint,10,opt"`
Finished proto.Option[uint32] `protobuf:"varint,9,opt"`
NextQueryParam proto.Option[string] `protobuf:"bytes,24,opt"`
MemberWithRoles []*GuildGroupMembersInfo `protobuf:"bytes,25,rep"`
NextRoleIdIndex proto.Option[uint64] `protobuf:"varint,26,opt"`
}
type ChannelOidb0Xf88Rsp struct {
Profile *GuildUserProfile `protobuf:"bytes,1,opt"`
_ [0]func()
}
type ChannelOidb0Xfc9Rsp struct {
Profile *GuildUserProfile `protobuf:"bytes,1,opt"`
_ [0]func()
}
type ChannelOidb0Xf57Rsp struct {
Rsp *GuildMetaRsp `protobuf:"bytes,1,opt"`
_ [0]func()
}
type ChannelOidb0Xf55Rsp struct {
Info *GuildChannelInfo `protobuf:"bytes,1,opt"`
_ [0]func()
}
type ChannelOidb0Xf5DRsp struct {
Rsp *ChannelListRsp `protobuf:"bytes,1,opt"`
_ [0]func()
}
type ChannelOidb0X1017Rsp struct {
P1 *P10X1017 `protobuf:"bytes,1,opt"`
_ [0]func()
}
type P10X1017 struct {
TinyId proto.Option[uint64] `protobuf:"varint,1,opt"`
Roles []*GuildUserRole `protobuf:"bytes,3,rep"`
}
type ChannelOidb0X1019Rsp struct {
GuildId proto.Option[uint64] `protobuf:"varint,1,opt"`
Roles []*GuildRole `protobuf:"bytes,2,rep"`
}
type ChannelOidb0X1016Rsp struct {
RoleId proto.Option[uint64] `protobuf:"varint,2,opt"`
_ [0]func()
}
type GuildMetaRsp struct {
GuildId proto.Option[uint64] `protobuf:"varint,3,opt"`
Meta *GuildMeta `protobuf:"bytes,4,opt"`
_ [0]func()
}
type ChannelListRsp struct {
GuildId proto.Option[uint64] `protobuf:"varint,1,opt"`
Channels []*GuildChannelInfo `protobuf:"bytes,2,rep"` // 5: Category infos
}
type GuildGroupMembersInfo struct {
RoleId proto.Option[uint64] `protobuf:"varint,1,opt"`
Members []*GuildMemberInfo `protobuf:"bytes,2,rep"`
RoleName proto.Option[string] `protobuf:"bytes,3,opt"`
Color proto.Option[uint32] `protobuf:"varint,4,opt"`
}
// see sub_374334
type GuildMemberInfo struct {
Title proto.Option[string] `protobuf:"bytes,2,opt"`
Nickname proto.Option[string] `protobuf:"bytes,3,opt"`
LastSpeakTime proto.Option[int64] `protobuf:"varint,4,opt"` // uncertainty
Role proto.Option[int32] `protobuf:"varint,5,opt"` // uncertainty
TinyId proto.Option[uint64] `protobuf:"varint,8,opt"`
_ [0]func()
}
// 频道系统用户资料
type GuildUserProfile struct {
TinyId proto.Option[uint64] `protobuf:"varint,2,opt"`
Nickname proto.Option[string] `protobuf:"bytes,3,opt"`
AvatarUrl proto.Option[string] `protobuf:"bytes,6,opt"`
// 15: avatar url info
JoinTime proto.Option[int64] `protobuf:"varint,16,opt"` // uncertainty
_ [0]func()
}
type GuildRole struct {
RoleId proto.Option[uint64] `protobuf:"varint,1,opt"`
Name proto.Option[string] `protobuf:"bytes,2,opt"`
ArgbColor proto.Option[uint32] `protobuf:"varint,3,opt"`
Independent proto.Option[int32] `protobuf:"varint,4,opt"`
Num proto.Option[int32] `protobuf:"varint,5,opt"`
Owned proto.Option[int32] `protobuf:"varint,6,opt"` // 是否拥有 存疑
Disabled proto.Option[int32] `protobuf:"varint,7,opt"` // 权限不足或不显示
MaxNum proto.Option[int32] `protobuf:"varint,8,opt"` // 9: ?
_ [0]func()
}
type GuildUserRole struct {
RoleId proto.Option[uint64] `protobuf:"varint,1,opt"`
Name proto.Option[string] `protobuf:"bytes,2,opt"`
ArgbColor proto.Option[uint32] `protobuf:"varint,3,opt"`
Independent proto.Option[int32] `protobuf:"varint,4,opt"`
_ [0]func()
}
type GuildMeta struct {
GuildCode proto.Option[uint64] `protobuf:"varint,2,opt"`
CreateTime proto.Option[int64] `protobuf:"varint,4,opt"`
MaxMemberCount proto.Option[int64] `protobuf:"varint,5,opt"`
MemberCount proto.Option[int64] `protobuf:"varint,6,opt"`
Name proto.Option[string] `protobuf:"bytes,8,opt"`
RobotMaxNum proto.Option[int32] `protobuf:"varint,11,opt"`
AdminMaxNum proto.Option[int32] `protobuf:"varint,12,opt"`
Profile proto.Option[string] `protobuf:"bytes,13,opt"`
AvatarSeq proto.Option[int64] `protobuf:"varint,14,opt"`
OwnerId proto.Option[uint64] `protobuf:"varint,18,opt"`
CoverSeq proto.Option[int64] `protobuf:"varint,19,opt"`
ClientId proto.Option[int32] `protobuf:"varint,20,opt"`
_ [0]func()
}
type GuildChannelInfo struct {
ChannelId proto.Option[uint64] `protobuf:"varint,1,opt"`
ChannelName proto.Option[string] `protobuf:"bytes,2,opt"`
CreatorUin proto.Option[int64] `protobuf:"varint,3,opt"`
CreateTime proto.Option[int64] `protobuf:"varint,4,opt"`
GuildId proto.Option[uint64] `protobuf:"varint,5,opt"`
FinalNotifyType proto.Option[int32] `protobuf:"varint,6,opt"`
ChannelType proto.Option[int32] `protobuf:"varint,7,opt"`
TalkPermission proto.Option[int32] `protobuf:"varint,8,opt"`
// 11 - 14 : MsgInfo
CreatorTinyId proto.Option[uint64] `protobuf:"varint,15,opt"`
// 16: Member info ?
VisibleType proto.Option[int32] `protobuf:"varint,22,opt"`
TopMsg *GuildChannelTopMsgInfo `protobuf:"bytes,28,opt"`
CurrentSlowModeKey proto.Option[int32] `protobuf:"varint,31,opt"`
SlowModeInfos []*GuildChannelSlowModeInfo `protobuf:"bytes,32,rep"`
}
type GuildChannelSlowModeInfo struct {
SlowModeKey proto.Option[int32] `protobuf:"varint,1,opt"`
SpeakFrequency proto.Option[int32] `protobuf:"varint,2,opt"`
SlowModeCircle proto.Option[int32] `protobuf:"varint,3,opt"`
SlowModeText proto.Option[string] `protobuf:"bytes,4,opt"`
_ [0]func()
}
type GuildChannelTopMsgInfo struct {
TopMsgSeq proto.Option[uint64] `protobuf:"varint,1,opt"`
TopMsgTime proto.Option[int64] `protobuf:"varint,2,opt"`
TopMsgOperatorTinyId proto.Option[uint64] `protobuf:"varint,3,opt"`
_ [0]func()
}

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
syntax = "proto3"; syntax = "proto3";
option go_package = "github.com/Mrs4s/MiraiGo/client/pb/cmd0x346"; option go_package = "./;cmd0x346";
message ApplyCleanTrafficRsp { message ApplyCleanTrafficRsp {
int32 retCode = 10; int32 retCode = 10;
@ -197,8 +197,6 @@ message ApplyUploadReqV3 {
string localFilepath = 70; string localFilepath = 70;
int32 dangerLevel = 80; int32 dangerLevel = 80;
int64 totalSpace = 90; int64 totalSpace = 90;
bytes md5 = 110;
bytes _3Sha = 120;
} }
message ApplyUploadRsp { message ApplyUploadRsp {
int32 retCode = 10; int32 retCode = 10;
@ -250,7 +248,6 @@ message ApplyUploadRspV3 {
string uploadHttpsDomain = 150; string uploadHttpsDomain = 150;
string uploadDns = 160; string uploadDns = 160;
string uploadLanip = 170; string uploadLanip = 170;
bytes mediaPlateformUploadKey = 220;
} }
message DelMessageReq { message DelMessageReq {
int64 uinSender = 1; int64 uinSender = 1;
@ -364,69 +361,61 @@ message RenewFileRsp {
message C346ReqBody { message C346ReqBody {
int32 cmd = 1; int32 cmd = 1;
int32 seq = 2; int32 seq = 2;
/*
RecvListQueryReq recvListQueryReq = 3; RecvListQueryReq recvListQueryReq = 3;
SendListQueryReq sendListQueryReq = 4; SendListQueryReq sendListQueryReq = 4;
RenewFileReq renewFileReq = 5; RenewFileReq renewFileReq = 5;
RecallFileReq recallFileReq = 6; RecallFileReq recallFileReq = 6;
*/
ApplyUploadReq applyUploadReq = 7; ApplyUploadReq applyUploadReq = 7;
// ApplyUploadHitReq applyUploadHitReq = 8; ApplyUploadHitReq applyUploadHitReq = 8;
// ApplyForwardFileReq applyForwardFileReq = 9; ApplyForwardFileReq applyForwardFileReq = 9;
UploadSuccReq uploadSuccReq = 10; UploadSuccReq uploadSuccReq = 10;
// DeleteFileReq deleteFileReq = 11; DeleteFileReq deleteFileReq = 11;
// DownloadSuccReq downloadSuccReq = 12; DownloadSuccReq downloadSuccReq = 12;
// ApplyDownloadAbsReq applyDownloadAbsReq = 13; ApplyDownloadAbsReq applyDownloadAbsReq = 13;
ApplyDownloadReq applyDownloadReq = 14; ApplyDownloadReq applyDownloadReq = 14;
// ApplyListDownloadReq applyListDownloadReq = 15; ApplyListDownloadReq applyListDownloadReq = 15;
// FileQueryReq fileQueryReq = 16; FileQueryReq fileQueryReq = 16;
// ApplyCopyFromReq applyCopyFromReq = 17; ApplyCopyFromReq applyCopyFromReq = 17;
// ApplyUploadReqV2 applyUploadReqV2 = 18; ApplyUploadReqV2 applyUploadReqV2 = 18;
ApplyUploadReqV3 applyUploadReqV3 = 19; ApplyUploadReqV3 applyUploadReqV3 = 19;
//ApplyUploadHitReqV2 applyUploadHitReqV2 = 20; ApplyUploadHitReqV2 applyUploadHitReqV2 = 20;
//ApplyUploadHitReqV3 applyUploadHitReqV3 = 21; ApplyUploadHitReqV3 applyUploadHitReqV3 = 21;
int32 businessId = 101; int32 businessId = 101;
int32 clientType = 102; int32 clientType = 102;
uint32 flagSupportMediaplatform = 200; ApplyCopyToReq applyCopyToReq = 90000;
//ApplyCopyToReq applyCopyToReq = 90000;
//ApplyCleanTrafficReq applyCleanTrafficReq = 90001; empty message //ApplyCleanTrafficReq applyCleanTrafficReq = 90001; empty message
//ApplyGetTrafficReq applyGetTrafficReq = 90002; ApplyGetTrafficReq applyGetTrafficReq = 90002;
ExtensionReq extensionReq = 99999; ExtensionReq extensionReq = 99999;
} }
message C346RspBody { message C346RspBody {
int32 cmd = 1; int32 cmd = 1;
int32 seq = 2; int32 seq = 2;
/*
RecvListQueryRsp recvListQueryRsp = 3; RecvListQueryRsp recvListQueryRsp = 3;
SendListQueryRsp sendListQueryRsp = 4; SendListQueryRsp sendListQueryRsp = 4;
RenewFileRsp renewFileRsp = 5; RenewFileRsp renewFileRsp = 5;
RecallFileRsp recallFileRsp = 6; RecallFileRsp recallFileRsp = 6;
*/
ApplyUploadRsp applyUploadRsp = 7; ApplyUploadRsp applyUploadRsp = 7;
/*
ApplyUploadHitRsp applyUploadHitRsp = 8; ApplyUploadHitRsp applyUploadHitRsp = 8;
ApplyForwardFileRsp applyForwardFileRsp = 9; ApplyForwardFileRsp applyForwardFileRsp = 9;
UploadSuccRsp uploadSuccRsp = 10; UploadSuccRsp uploadSuccRsp = 10;
DeleteFileRsp deleteFileRsp = 11; DeleteFileRsp deleteFileRsp = 11;
DownloadSuccRsp downloadSuccRsp = 12; DownloadSuccRsp downloadSuccRsp = 12;
ApplyDownloadAbsRsp applyDownloadAbsRsp = 13; ApplyDownloadAbsRsp applyDownloadAbsRsp = 13;
*/
ApplyDownloadRsp applyDownloadRsp = 14; ApplyDownloadRsp applyDownloadRsp = 14;
// ApplyListDownloadRsp applyListDownloadRsp = 15; ApplyListDownloadRsp applyListDownloadRsp = 15;
// FileQueryRsp fileQueryRsp = 16; FileQueryRsp fileQueryRsp = 16;
// ApplyCopyFromRsp applyCopyFromRsp = 17; ApplyCopyFromRsp applyCopyFromRsp = 17;
// ApplyUploadRspV2 applyUploadRspV2 = 18; ApplyUploadRspV2 applyUploadRspV2 = 18;
ApplyUploadRspV3 applyUploadRspV3 = 19; ApplyUploadRspV3 applyUploadRspV3 = 19;
// ApplyUploadHitRspV2 applyUploadHitRspV2 = 20; ApplyUploadHitRspV2 applyUploadHitRspV2 = 20;
// ApplyUploadHitRspV3 applyUploadHitRspV3 = 21; ApplyUploadHitRspV3 applyUploadHitRspV3 = 21;
int32 businessId = 101; int32 businessId = 101;
int32 clientType = 102; int32 clientType = 102;
/*
ApplyCopyToRsp applyCopyToRsp = 90000; ApplyCopyToRsp applyCopyToRsp = 90000;
ApplyCleanTrafficRsp applyCleanTrafficRsp = 90001; ApplyCleanTrafficRsp applyCleanTrafficRsp = 90001;
ApplyGetTrafficRsp applyGetTrafficRsp = 90002; ApplyGetTrafficRsp applyGetTrafficRsp = 90002;
ExtensionRsp extensionRsp = 99999; ExtensionRsp extensionRsp = 99999;
*/
} }
message SendListQueryReq { message SendListQueryReq {
int64 uin = 1; int64 uin = 1;

View File

@ -1,77 +1,803 @@
// Code generated by protoc-gen-golite. DO NOT EDIT. // Code generated by protoc-gen-go. DO NOT EDIT.
// source: pb/cmd0x352/cmd0x352.proto // versions:
// protoc-gen-go v1.26.0
// protoc v3.17.1
// source: cmd0x352.proto
package cmd0x352 package cmd0x352
import ( import (
proto "github.com/RomiChan/protobuf/proto" reflect "reflect"
sync "sync"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
)
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 ReqBody struct { type ReqBody struct {
Subcmd proto.Option[uint32] `protobuf:"varint,1,opt"` state protoimpl.MessageState
TryupImgReq []*D352TryUpImgReq `protobuf:"bytes,2,rep"` sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Subcmd *uint32 `protobuf:"varint,1,opt,name=subcmd" json:"subcmd,omitempty"`
TryupImgReq []*D352TryUpImgReq `protobuf:"bytes,2,rep,name=tryupImgReq" json:"tryupImgReq,omitempty"`
// repeated GetImgUrlReq getimgUrlReq = 3; // repeated GetImgUrlReq getimgUrlReq = 3;
// repeated DelImgReq delImgReq = 4; // repeated DelImgReq delImgReq = 4;
NetType proto.Option[uint32] `protobuf:"varint,10,opt"` NetType *uint32 `protobuf:"varint,10,opt,name=netType" json:"netType,omitempty"`
}
func (x *ReqBody) Reset() {
*x = ReqBody{}
if protoimpl.UnsafeEnabled {
mi := &file_cmd0x352_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ReqBody) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ReqBody) ProtoMessage() {}
func (x *ReqBody) ProtoReflect() protoreflect.Message {
mi := &file_cmd0x352_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 ReqBody.ProtoReflect.Descriptor instead.
func (*ReqBody) Descriptor() ([]byte, []int) {
return file_cmd0x352_proto_rawDescGZIP(), []int{0}
}
func (x *ReqBody) GetSubcmd() uint32 {
if x != nil && x.Subcmd != nil {
return *x.Subcmd
}
return 0
}
func (x *ReqBody) GetTryupImgReq() []*D352TryUpImgReq {
if x != nil {
return x.TryupImgReq
}
return nil
}
func (x *ReqBody) GetNetType() uint32 {
if x != nil && x.NetType != nil {
return *x.NetType
}
return 0
} }
type RspBody struct { type RspBody struct {
Subcmd proto.Option[uint32] `protobuf:"varint,1,opt"` state protoimpl.MessageState
TryupImgRsp []*TryUpImgRsp `protobuf:"bytes,2,rep"` sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Subcmd *uint32 `protobuf:"varint,1,opt,name=subcmd" json:"subcmd,omitempty"`
TryupImgRsp []*TryUpImgRsp `protobuf:"bytes,2,rep,name=tryupImgRsp" json:"tryupImgRsp,omitempty"`
// repeated GetImgUrlRsp getimgUrlRsp = 3; // repeated GetImgUrlRsp getimgUrlRsp = 3;
NewBigchan proto.Option[bool] `protobuf:"varint,4,opt"` NewBigchan *bool `protobuf:"varint,4,opt,name=newBigchan" json:"newBigchan,omitempty"`
// repeated DelImgRsp delImgRsp = 5; // repeated DelImgRsp delImgRsp = 5;
FailMsg []byte `protobuf:"bytes,10,opt"` FailMsg []byte `protobuf:"bytes,10,opt,name=failMsg" json:"failMsg,omitempty"`
}
func (x *RspBody) Reset() {
*x = RspBody{}
if protoimpl.UnsafeEnabled {
mi := &file_cmd0x352_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *RspBody) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*RspBody) ProtoMessage() {}
func (x *RspBody) ProtoReflect() protoreflect.Message {
mi := &file_cmd0x352_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 RspBody.ProtoReflect.Descriptor instead.
func (*RspBody) Descriptor() ([]byte, []int) {
return file_cmd0x352_proto_rawDescGZIP(), []int{1}
}
func (x *RspBody) GetSubcmd() uint32 {
if x != nil && x.Subcmd != nil {
return *x.Subcmd
}
return 0
}
func (x *RspBody) GetTryupImgRsp() []*TryUpImgRsp {
if x != nil {
return x.TryupImgRsp
}
return nil
}
func (x *RspBody) GetNewBigchan() bool {
if x != nil && x.NewBigchan != nil {
return *x.NewBigchan
}
return false
}
func (x *RspBody) GetFailMsg() []byte {
if x != nil {
return x.FailMsg
}
return nil
} }
type D352TryUpImgReq struct { type D352TryUpImgReq struct {
SrcUin proto.Option[uint64] `protobuf:"varint,1,opt"` state protoimpl.MessageState
DstUin proto.Option[uint64] `protobuf:"varint,2,opt"` sizeCache protoimpl.SizeCache
FileId proto.Option[uint64] `protobuf:"varint,3,opt"` unknownFields protoimpl.UnknownFields
FileMd5 []byte `protobuf:"bytes,4,opt"`
FileSize proto.Option[uint64] `protobuf:"varint,5,opt"` SrcUin *uint64 `protobuf:"varint,1,opt,name=srcUin" json:"srcUin,omitempty"`
FileName []byte `protobuf:"bytes,6,opt"` DstUin *uint64 `protobuf:"varint,2,opt,name=dstUin" json:"dstUin,omitempty"`
SrcTerm proto.Option[uint32] `protobuf:"varint,7,opt"` FileId *uint64 `protobuf:"varint,3,opt,name=fileId" json:"fileId,omitempty"`
PlatformType proto.Option[uint32] `protobuf:"varint,8,opt"` FileMd5 []byte `protobuf:"bytes,4,opt,name=fileMd5" json:"fileMd5,omitempty"`
InnerIp proto.Option[uint32] `protobuf:"varint,9,opt"` FileSize *uint64 `protobuf:"varint,5,opt,name=fileSize" json:"fileSize,omitempty"`
AddressBook proto.Option[bool] `protobuf:"varint,10,opt"` FileName []byte `protobuf:"bytes,6,opt,name=fileName" json:"fileName,omitempty"`
Retry proto.Option[uint32] `protobuf:"varint,11,opt"` SrcTerm *uint32 `protobuf:"varint,7,opt,name=srcTerm" json:"srcTerm,omitempty"`
BuType proto.Option[uint32] `protobuf:"varint,12,opt"` PlatformType *uint32 `protobuf:"varint,8,opt,name=platformType" json:"platformType,omitempty"`
PicOriginal proto.Option[bool] `protobuf:"varint,13,opt"` InnerIp *uint32 `protobuf:"varint,9,opt,name=innerIp" json:"innerIp,omitempty"`
PicWidth proto.Option[uint32] `protobuf:"varint,14,opt"` AddressBook *bool `protobuf:"varint,10,opt,name=addressBook" json:"addressBook,omitempty"`
PicHeight proto.Option[uint32] `protobuf:"varint,15,opt"` Retry *uint32 `protobuf:"varint,11,opt,name=retry" json:"retry,omitempty"`
PicType proto.Option[uint32] `protobuf:"varint,16,opt"` BuType *uint32 `protobuf:"varint,12,opt,name=buType" json:"buType,omitempty"`
BuildVer []byte `protobuf:"bytes,17,opt"` PicOriginal *bool `protobuf:"varint,13,opt,name=picOriginal" json:"picOriginal,omitempty"`
FileIndex []byte `protobuf:"bytes,18,opt"` PicWidth *uint32 `protobuf:"varint,14,opt,name=picWidth" json:"picWidth,omitempty"`
StoreDays proto.Option[uint32] `protobuf:"varint,19,opt"` PicHeight *uint32 `protobuf:"varint,15,opt,name=picHeight" json:"picHeight,omitempty"`
TryupStepflag proto.Option[uint32] `protobuf:"varint,20,opt"` PicType *uint32 `protobuf:"varint,16,opt,name=picType" json:"picType,omitempty"`
RejectTryfast proto.Option[bool] `protobuf:"varint,21,opt"` BuildVer []byte `protobuf:"bytes,17,opt,name=buildVer" json:"buildVer,omitempty"`
SrvUpload proto.Option[uint32] `protobuf:"varint,22,opt"` FileIndex []byte `protobuf:"bytes,18,opt,name=fileIndex" json:"fileIndex,omitempty"`
TransferUrl []byte `protobuf:"bytes,23,opt"` StoreDays *uint32 `protobuf:"varint,19,opt,name=storeDays" json:"storeDays,omitempty"`
TryupStepflag *uint32 `protobuf:"varint,20,opt,name=tryupStepflag" json:"tryupStepflag,omitempty"`
RejectTryfast *bool `protobuf:"varint,21,opt,name=rejectTryfast" json:"rejectTryfast,omitempty"`
SrvUpload *uint32 `protobuf:"varint,22,opt,name=srvUpload" json:"srvUpload,omitempty"`
TransferUrl []byte `protobuf:"bytes,23,opt,name=transferUrl" json:"transferUrl,omitempty"`
}
func (x *D352TryUpImgReq) Reset() {
*x = D352TryUpImgReq{}
if protoimpl.UnsafeEnabled {
mi := &file_cmd0x352_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *D352TryUpImgReq) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*D352TryUpImgReq) ProtoMessage() {}
func (x *D352TryUpImgReq) ProtoReflect() protoreflect.Message {
mi := &file_cmd0x352_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 D352TryUpImgReq.ProtoReflect.Descriptor instead.
func (*D352TryUpImgReq) Descriptor() ([]byte, []int) {
return file_cmd0x352_proto_rawDescGZIP(), []int{2}
}
func (x *D352TryUpImgReq) GetSrcUin() uint64 {
if x != nil && x.SrcUin != nil {
return *x.SrcUin
}
return 0
}
func (x *D352TryUpImgReq) GetDstUin() uint64 {
if x != nil && x.DstUin != nil {
return *x.DstUin
}
return 0
}
func (x *D352TryUpImgReq) GetFileId() uint64 {
if x != nil && x.FileId != nil {
return *x.FileId
}
return 0
}
func (x *D352TryUpImgReq) GetFileMd5() []byte {
if x != nil {
return x.FileMd5
}
return nil
}
func (x *D352TryUpImgReq) GetFileSize() uint64 {
if x != nil && x.FileSize != nil {
return *x.FileSize
}
return 0
}
func (x *D352TryUpImgReq) GetFileName() []byte {
if x != nil {
return x.FileName
}
return nil
}
func (x *D352TryUpImgReq) GetSrcTerm() uint32 {
if x != nil && x.SrcTerm != nil {
return *x.SrcTerm
}
return 0
}
func (x *D352TryUpImgReq) GetPlatformType() uint32 {
if x != nil && x.PlatformType != nil {
return *x.PlatformType
}
return 0
}
func (x *D352TryUpImgReq) GetInnerIp() uint32 {
if x != nil && x.InnerIp != nil {
return *x.InnerIp
}
return 0
}
func (x *D352TryUpImgReq) GetAddressBook() bool {
if x != nil && x.AddressBook != nil {
return *x.AddressBook
}
return false
}
func (x *D352TryUpImgReq) GetRetry() uint32 {
if x != nil && x.Retry != nil {
return *x.Retry
}
return 0
}
func (x *D352TryUpImgReq) GetBuType() uint32 {
if x != nil && x.BuType != nil {
return *x.BuType
}
return 0
}
func (x *D352TryUpImgReq) GetPicOriginal() bool {
if x != nil && x.PicOriginal != nil {
return *x.PicOriginal
}
return false
}
func (x *D352TryUpImgReq) GetPicWidth() uint32 {
if x != nil && x.PicWidth != nil {
return *x.PicWidth
}
return 0
}
func (x *D352TryUpImgReq) GetPicHeight() uint32 {
if x != nil && x.PicHeight != nil {
return *x.PicHeight
}
return 0
}
func (x *D352TryUpImgReq) GetPicType() uint32 {
if x != nil && x.PicType != nil {
return *x.PicType
}
return 0
}
func (x *D352TryUpImgReq) GetBuildVer() []byte {
if x != nil {
return x.BuildVer
}
return nil
}
func (x *D352TryUpImgReq) GetFileIndex() []byte {
if x != nil {
return x.FileIndex
}
return nil
}
func (x *D352TryUpImgReq) GetStoreDays() uint32 {
if x != nil && x.StoreDays != nil {
return *x.StoreDays
}
return 0
}
func (x *D352TryUpImgReq) GetTryupStepflag() uint32 {
if x != nil && x.TryupStepflag != nil {
return *x.TryupStepflag
}
return 0
}
func (x *D352TryUpImgReq) GetRejectTryfast() bool {
if x != nil && x.RejectTryfast != nil {
return *x.RejectTryfast
}
return false
}
func (x *D352TryUpImgReq) GetSrvUpload() uint32 {
if x != nil && x.SrvUpload != nil {
return *x.SrvUpload
}
return 0
}
func (x *D352TryUpImgReq) GetTransferUrl() []byte {
if x != nil {
return x.TransferUrl
}
return nil
} }
type TryUpImgRsp struct { type TryUpImgRsp struct {
FileId proto.Option[uint64] `protobuf:"varint,1,opt"` state protoimpl.MessageState
ClientIp proto.Option[uint32] `protobuf:"varint,2,opt"` sizeCache protoimpl.SizeCache
Result proto.Option[uint32] `protobuf:"varint,3,opt"` unknownFields protoimpl.UnknownFields
FailMsg []byte `protobuf:"bytes,4,opt"`
FileExit proto.Option[bool] `protobuf:"varint,5,opt"` FileId *uint64 `protobuf:"varint,1,opt,name=fileId" json:"fileId,omitempty"`
ClientIp *uint32 `protobuf:"varint,2,opt,name=clientIp" json:"clientIp,omitempty"`
Result *uint32 `protobuf:"varint,3,opt,name=result" json:"result,omitempty"`
FailMsg []byte `protobuf:"bytes,4,opt,name=failMsg" json:"failMsg,omitempty"`
FileExit *bool `protobuf:"varint,5,opt,name=fileExit" json:"fileExit,omitempty"`
// optional ImgInfo imgInfo = 6; // optional ImgInfo imgInfo = 6;
UpIp []uint32 `protobuf:"varint,7,rep"` UpIp []uint32 `protobuf:"varint,7,rep,name=upIp" json:"upIp,omitempty"`
UpPort []uint32 `protobuf:"varint,8,rep"` UpPort []uint32 `protobuf:"varint,8,rep,name=upPort" json:"upPort,omitempty"`
UpUkey []byte `protobuf:"bytes,9,opt"` UpUkey []byte `protobuf:"bytes,9,opt,name=upUkey" json:"upUkey,omitempty"`
UpResid []byte `protobuf:"bytes,10,opt"` UpResid []byte `protobuf:"bytes,10,opt,name=upResid" json:"upResid,omitempty"`
UpUuid []byte `protobuf:"bytes,11,opt"` UpUuid []byte `protobuf:"bytes,11,opt,name=upUuid" json:"upUuid,omitempty"`
UpOffset proto.Option[uint64] `protobuf:"varint,12,opt"` UpOffset *uint64 `protobuf:"varint,12,opt,name=upOffset" json:"upOffset,omitempty"`
BlockSize proto.Option[uint64] `protobuf:"varint,13,opt"` BlockSize *uint64 `protobuf:"varint,13,opt,name=blockSize" json:"blockSize,omitempty"`
EncryptDstip []byte `protobuf:"bytes,14,opt"` EncryptDstip []byte `protobuf:"bytes,14,opt,name=encryptDstip" json:"encryptDstip,omitempty"`
Roamdays proto.Option[uint32] `protobuf:"varint,15,opt"` Roamdays *uint32 `protobuf:"varint,15,opt,name=roamdays" json:"roamdays,omitempty"`
// repeated IPv6Info upIp6 = 26; // repeated IPv6Info upIp6 = 26;
ClientIp6 []byte `protobuf:"bytes,27,opt"` ClientIp6 []byte `protobuf:"bytes,27,opt,name=clientIp6" json:"clientIp6,omitempty"`
ThumbDownPara []byte `protobuf:"bytes,60,opt"` ThumbDownPara []byte `protobuf:"bytes,60,opt,name=thumbDownPara" json:"thumbDownPara,omitempty"`
OriginalDownPara []byte `protobuf:"bytes,61,opt"` OriginalDownPara []byte `protobuf:"bytes,61,opt,name=originalDownPara" json:"originalDownPara,omitempty"`
DownDomain []byte `protobuf:"bytes,62,opt"` DownDomain []byte `protobuf:"bytes,62,opt,name=downDomain" json:"downDomain,omitempty"`
BigDownPara []byte `protobuf:"bytes,64,opt"` BigDownPara []byte `protobuf:"bytes,64,opt,name=bigDownPara" json:"bigDownPara,omitempty"`
BigThumbDownPara []byte `protobuf:"bytes,65,opt"` BigThumbDownPara []byte `protobuf:"bytes,65,opt,name=bigThumbDownPara" json:"bigThumbDownPara,omitempty"`
HttpsUrlFlag proto.Option[uint32] `protobuf:"varint,66,opt"` // optional TryUpInfo4Busi info4Busi = 1001; HttpsUrlFlag *uint32 `protobuf:"varint,66,opt,name=httpsUrlFlag" json:"httpsUrlFlag,omitempty"` // optional TryUpInfo4Busi info4Busi = 1001;
}
func (x *TryUpImgRsp) Reset() {
*x = TryUpImgRsp{}
if protoimpl.UnsafeEnabled {
mi := &file_cmd0x352_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *TryUpImgRsp) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*TryUpImgRsp) ProtoMessage() {}
func (x *TryUpImgRsp) ProtoReflect() protoreflect.Message {
mi := &file_cmd0x352_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 TryUpImgRsp.ProtoReflect.Descriptor instead.
func (*TryUpImgRsp) Descriptor() ([]byte, []int) {
return file_cmd0x352_proto_rawDescGZIP(), []int{3}
}
func (x *TryUpImgRsp) GetFileId() uint64 {
if x != nil && x.FileId != nil {
return *x.FileId
}
return 0
}
func (x *TryUpImgRsp) GetClientIp() uint32 {
if x != nil && x.ClientIp != nil {
return *x.ClientIp
}
return 0
}
func (x *TryUpImgRsp) GetResult() uint32 {
if x != nil && x.Result != nil {
return *x.Result
}
return 0
}
func (x *TryUpImgRsp) GetFailMsg() []byte {
if x != nil {
return x.FailMsg
}
return nil
}
func (x *TryUpImgRsp) GetFileExit() bool {
if x != nil && x.FileExit != nil {
return *x.FileExit
}
return false
}
func (x *TryUpImgRsp) GetUpIp() []uint32 {
if x != nil {
return x.UpIp
}
return nil
}
func (x *TryUpImgRsp) GetUpPort() []uint32 {
if x != nil {
return x.UpPort
}
return nil
}
func (x *TryUpImgRsp) GetUpUkey() []byte {
if x != nil {
return x.UpUkey
}
return nil
}
func (x *TryUpImgRsp) GetUpResid() []byte {
if x != nil {
return x.UpResid
}
return nil
}
func (x *TryUpImgRsp) GetUpUuid() []byte {
if x != nil {
return x.UpUuid
}
return nil
}
func (x *TryUpImgRsp) GetUpOffset() uint64 {
if x != nil && x.UpOffset != nil {
return *x.UpOffset
}
return 0
}
func (x *TryUpImgRsp) GetBlockSize() uint64 {
if x != nil && x.BlockSize != nil {
return *x.BlockSize
}
return 0
}
func (x *TryUpImgRsp) GetEncryptDstip() []byte {
if x != nil {
return x.EncryptDstip
}
return nil
}
func (x *TryUpImgRsp) GetRoamdays() uint32 {
if x != nil && x.Roamdays != nil {
return *x.Roamdays
}
return 0
}
func (x *TryUpImgRsp) GetClientIp6() []byte {
if x != nil {
return x.ClientIp6
}
return nil
}
func (x *TryUpImgRsp) GetThumbDownPara() []byte {
if x != nil {
return x.ThumbDownPara
}
return nil
}
func (x *TryUpImgRsp) GetOriginalDownPara() []byte {
if x != nil {
return x.OriginalDownPara
}
return nil
}
func (x *TryUpImgRsp) GetDownDomain() []byte {
if x != nil {
return x.DownDomain
}
return nil
}
func (x *TryUpImgRsp) GetBigDownPara() []byte {
if x != nil {
return x.BigDownPara
}
return nil
}
func (x *TryUpImgRsp) GetBigThumbDownPara() []byte {
if x != nil {
return x.BigThumbDownPara
}
return nil
}
func (x *TryUpImgRsp) GetHttpsUrlFlag() uint32 {
if x != nil && x.HttpsUrlFlag != nil {
return *x.HttpsUrlFlag
}
return 0
}
var File_cmd0x352_proto protoreflect.FileDescriptor
var file_cmd0x352_proto_rawDesc = []byte{
0x0a, 0x0e, 0x63, 0x6d, 0x64, 0x30, 0x78, 0x33, 0x35, 0x32, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x22, 0x6f, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x42, 0x6f, 0x64, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x73,
0x75, 0x62, 0x63, 0x6d, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x73, 0x75, 0x62,
0x63, 0x6d, 0x64, 0x12, 0x32, 0x0a, 0x0b, 0x74, 0x72, 0x79, 0x75, 0x70, 0x49, 0x6d, 0x67, 0x52,
0x65, 0x71, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x44, 0x33, 0x35, 0x32, 0x54,
0x72, 0x79, 0x55, 0x70, 0x49, 0x6d, 0x67, 0x52, 0x65, 0x71, 0x52, 0x0b, 0x74, 0x72, 0x79, 0x75,
0x70, 0x49, 0x6d, 0x67, 0x52, 0x65, 0x71, 0x12, 0x18, 0x0a, 0x07, 0x6e, 0x65, 0x74, 0x54, 0x79,
0x70, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x6e, 0x65, 0x74, 0x54, 0x79, 0x70,
0x65, 0x22, 0x8b, 0x01, 0x0a, 0x07, 0x52, 0x73, 0x70, 0x42, 0x6f, 0x64, 0x79, 0x12, 0x16, 0x0a,
0x06, 0x73, 0x75, 0x62, 0x63, 0x6d, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x73,
0x75, 0x62, 0x63, 0x6d, 0x64, 0x12, 0x2e, 0x0a, 0x0b, 0x74, 0x72, 0x79, 0x75, 0x70, 0x49, 0x6d,
0x67, 0x52, 0x73, 0x70, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x54, 0x72, 0x79,
0x55, 0x70, 0x49, 0x6d, 0x67, 0x52, 0x73, 0x70, 0x52, 0x0b, 0x74, 0x72, 0x79, 0x75, 0x70, 0x49,
0x6d, 0x67, 0x52, 0x73, 0x70, 0x12, 0x1e, 0x0a, 0x0a, 0x6e, 0x65, 0x77, 0x42, 0x69, 0x67, 0x63,
0x68, 0x61, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x6e, 0x65, 0x77, 0x42, 0x69,
0x67, 0x63, 0x68, 0x61, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x66, 0x61, 0x69, 0x6c, 0x4d, 0x73, 0x67,
0x18, 0x0a, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x66, 0x61, 0x69, 0x6c, 0x4d, 0x73, 0x67, 0x22,
0xad, 0x05, 0x0a, 0x0f, 0x44, 0x33, 0x35, 0x32, 0x54, 0x72, 0x79, 0x55, 0x70, 0x49, 0x6d, 0x67,
0x52, 0x65, 0x71, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x72, 0x63, 0x55, 0x69, 0x6e, 0x18, 0x01, 0x20,
0x01, 0x28, 0x04, 0x52, 0x06, 0x73, 0x72, 0x63, 0x55, 0x69, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x64,
0x73, 0x74, 0x55, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x64, 0x73, 0x74,
0x55, 0x69, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x69, 0x6c, 0x65, 0x49, 0x64, 0x18, 0x03, 0x20,
0x01, 0x28, 0x04, 0x52, 0x06, 0x66, 0x69, 0x6c, 0x65, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x66,
0x69, 0x6c, 0x65, 0x4d, 0x64, 0x35, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x66, 0x69,
0x6c, 0x65, 0x4d, 0x64, 0x35, 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x53, 0x69, 0x7a,
0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x53, 0x69, 0x7a,
0x65, 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x06, 0x20,
0x01, 0x28, 0x0c, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a,
0x07, 0x73, 0x72, 0x63, 0x54, 0x65, 0x72, 0x6d, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07,
0x73, 0x72, 0x63, 0x54, 0x65, 0x72, 0x6d, 0x12, 0x22, 0x0a, 0x0c, 0x70, 0x6c, 0x61, 0x74, 0x66,
0x6f, 0x72, 0x6d, 0x54, 0x79, 0x70, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0c, 0x70,
0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x54, 0x79, 0x70, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x69,
0x6e, 0x6e, 0x65, 0x72, 0x49, 0x70, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x69, 0x6e,
0x6e, 0x65, 0x72, 0x49, 0x70, 0x12, 0x20, 0x0a, 0x0b, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73,
0x42, 0x6f, 0x6f, 0x6b, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x61, 0x64, 0x64, 0x72,
0x65, 0x73, 0x73, 0x42, 0x6f, 0x6f, 0x6b, 0x12, 0x14, 0x0a, 0x05, 0x72, 0x65, 0x74, 0x72, 0x79,
0x18, 0x0b, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x72, 0x65, 0x74, 0x72, 0x79, 0x12, 0x16, 0x0a,
0x06, 0x62, 0x75, 0x54, 0x79, 0x70, 0x65, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x62,
0x75, 0x54, 0x79, 0x70, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x70, 0x69, 0x63, 0x4f, 0x72, 0x69, 0x67,
0x69, 0x6e, 0x61, 0x6c, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x70, 0x69, 0x63, 0x4f,
0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x69, 0x63, 0x57, 0x69,
0x64, 0x74, 0x68, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x70, 0x69, 0x63, 0x57, 0x69,
0x64, 0x74, 0x68, 0x12, 0x1c, 0x0a, 0x09, 0x70, 0x69, 0x63, 0x48, 0x65, 0x69, 0x67, 0x68, 0x74,
0x18, 0x0f, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x70, 0x69, 0x63, 0x48, 0x65, 0x69, 0x67, 0x68,
0x74, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x69, 0x63, 0x54, 0x79, 0x70, 0x65, 0x18, 0x10, 0x20, 0x01,
0x28, 0x0d, 0x52, 0x07, 0x70, 0x69, 0x63, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x62,
0x75, 0x69, 0x6c, 0x64, 0x56, 0x65, 0x72, 0x18, 0x11, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x62,
0x75, 0x69, 0x6c, 0x64, 0x56, 0x65, 0x72, 0x12, 0x1c, 0x0a, 0x09, 0x66, 0x69, 0x6c, 0x65, 0x49,
0x6e, 0x64, 0x65, 0x78, 0x18, 0x12, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x66, 0x69, 0x6c, 0x65,
0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x44, 0x61,
0x79, 0x73, 0x18, 0x13, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x44,
0x61, 0x79, 0x73, 0x12, 0x24, 0x0a, 0x0d, 0x74, 0x72, 0x79, 0x75, 0x70, 0x53, 0x74, 0x65, 0x70,
0x66, 0x6c, 0x61, 0x67, 0x18, 0x14, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0d, 0x74, 0x72, 0x79, 0x75,
0x70, 0x53, 0x74, 0x65, 0x70, 0x66, 0x6c, 0x61, 0x67, 0x12, 0x24, 0x0a, 0x0d, 0x72, 0x65, 0x6a,
0x65, 0x63, 0x74, 0x54, 0x72, 0x79, 0x66, 0x61, 0x73, 0x74, 0x18, 0x15, 0x20, 0x01, 0x28, 0x08,
0x52, 0x0d, 0x72, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x54, 0x72, 0x79, 0x66, 0x61, 0x73, 0x74, 0x12,
0x1c, 0x0a, 0x09, 0x73, 0x72, 0x76, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x16, 0x20, 0x01,
0x28, 0x0d, 0x52, 0x09, 0x73, 0x72, 0x76, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x20, 0x0a,
0x0b, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x55, 0x72, 0x6c, 0x18, 0x17, 0x20, 0x01,
0x28, 0x0c, 0x52, 0x0b, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x55, 0x72, 0x6c, 0x22,
0x81, 0x05, 0x0a, 0x0b, 0x54, 0x72, 0x79, 0x55, 0x70, 0x49, 0x6d, 0x67, 0x52, 0x73, 0x70, 0x12,
0x16, 0x0a, 0x06, 0x66, 0x69, 0x6c, 0x65, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52,
0x06, 0x66, 0x69, 0x6c, 0x65, 0x49, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e,
0x74, 0x49, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e,
0x74, 0x49, 0x70, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x03, 0x20,
0x01, 0x28, 0x0d, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x66,
0x61, 0x69, 0x6c, 0x4d, 0x73, 0x67, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x66, 0x61,
0x69, 0x6c, 0x4d, 0x73, 0x67, 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x45, 0x78, 0x69,
0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x45, 0x78, 0x69,
0x74, 0x12, 0x12, 0x0a, 0x04, 0x75, 0x70, 0x49, 0x70, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0d, 0x52,
0x04, 0x75, 0x70, 0x49, 0x70, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x70, 0x50, 0x6f, 0x72, 0x74, 0x18,
0x08, 0x20, 0x03, 0x28, 0x0d, 0x52, 0x06, 0x75, 0x70, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x16, 0x0a,
0x06, 0x75, 0x70, 0x55, 0x6b, 0x65, 0x79, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x75,
0x70, 0x55, 0x6b, 0x65, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x75, 0x70, 0x52, 0x65, 0x73, 0x69, 0x64,
0x18, 0x0a, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x75, 0x70, 0x52, 0x65, 0x73, 0x69, 0x64, 0x12,
0x16, 0x0a, 0x06, 0x75, 0x70, 0x55, 0x75, 0x69, 0x64, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0c, 0x52,
0x06, 0x75, 0x70, 0x55, 0x75, 0x69, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x70, 0x4f, 0x66, 0x66,
0x73, 0x65, 0x74, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x75, 0x70, 0x4f, 0x66, 0x66,
0x73, 0x65, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x53, 0x69, 0x7a, 0x65,
0x18, 0x0d, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x53, 0x69, 0x7a,
0x65, 0x12, 0x22, 0x0a, 0x0c, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x44, 0x73, 0x74, 0x69,
0x70, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74,
0x44, 0x73, 0x74, 0x69, 0x70, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x6f, 0x61, 0x6d, 0x64, 0x61, 0x79,
0x73, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x72, 0x6f, 0x61, 0x6d, 0x64, 0x61, 0x79,
0x73, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x70, 0x36, 0x18, 0x1b,
0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x70, 0x36, 0x12,
0x24, 0x0a, 0x0d, 0x74, 0x68, 0x75, 0x6d, 0x62, 0x44, 0x6f, 0x77, 0x6e, 0x50, 0x61, 0x72, 0x61,
0x18, 0x3c, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x74, 0x68, 0x75, 0x6d, 0x62, 0x44, 0x6f, 0x77,
0x6e, 0x50, 0x61, 0x72, 0x61, 0x12, 0x2a, 0x0a, 0x10, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61,
0x6c, 0x44, 0x6f, 0x77, 0x6e, 0x50, 0x61, 0x72, 0x61, 0x18, 0x3d, 0x20, 0x01, 0x28, 0x0c, 0x52,
0x10, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x44, 0x6f, 0x77, 0x6e, 0x50, 0x61, 0x72,
0x61, 0x12, 0x1e, 0x0a, 0x0a, 0x64, 0x6f, 0x77, 0x6e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18,
0x3e, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x64, 0x6f, 0x77, 0x6e, 0x44, 0x6f, 0x6d, 0x61, 0x69,
0x6e, 0x12, 0x20, 0x0a, 0x0b, 0x62, 0x69, 0x67, 0x44, 0x6f, 0x77, 0x6e, 0x50, 0x61, 0x72, 0x61,
0x18, 0x40, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x62, 0x69, 0x67, 0x44, 0x6f, 0x77, 0x6e, 0x50,
0x61, 0x72, 0x61, 0x12, 0x2a, 0x0a, 0x10, 0x62, 0x69, 0x67, 0x54, 0x68, 0x75, 0x6d, 0x62, 0x44,
0x6f, 0x77, 0x6e, 0x50, 0x61, 0x72, 0x61, 0x18, 0x41, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x10, 0x62,
0x69, 0x67, 0x54, 0x68, 0x75, 0x6d, 0x62, 0x44, 0x6f, 0x77, 0x6e, 0x50, 0x61, 0x72, 0x61, 0x12,
0x22, 0x0a, 0x0c, 0x68, 0x74, 0x74, 0x70, 0x73, 0x55, 0x72, 0x6c, 0x46, 0x6c, 0x61, 0x67, 0x18,
0x42, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0c, 0x68, 0x74, 0x74, 0x70, 0x73, 0x55, 0x72, 0x6c, 0x46,
0x6c, 0x61, 0x67, 0x42, 0x0d, 0x5a, 0x0b, 0x2e, 0x2f, 0x3b, 0x63, 0x6d, 0x64, 0x30, 0x78, 0x33,
0x35, 0x32,
}
var (
file_cmd0x352_proto_rawDescOnce sync.Once
file_cmd0x352_proto_rawDescData = file_cmd0x352_proto_rawDesc
)
func file_cmd0x352_proto_rawDescGZIP() []byte {
file_cmd0x352_proto_rawDescOnce.Do(func() {
file_cmd0x352_proto_rawDescData = protoimpl.X.CompressGZIP(file_cmd0x352_proto_rawDescData)
})
return file_cmd0x352_proto_rawDescData
}
var file_cmd0x352_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
var file_cmd0x352_proto_goTypes = []interface{}{
(*ReqBody)(nil), // 0: ReqBody
(*RspBody)(nil), // 1: RspBody
(*D352TryUpImgReq)(nil), // 2: D352TryUpImgReq
(*TryUpImgRsp)(nil), // 3: TryUpImgRsp
}
var file_cmd0x352_proto_depIdxs = []int32{
2, // 0: ReqBody.tryupImgReq:type_name -> D352TryUpImgReq
3, // 1: RspBody.tryupImgRsp:type_name -> TryUpImgRsp
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_cmd0x352_proto_init() }
func file_cmd0x352_proto_init() {
if File_cmd0x352_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_cmd0x352_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ReqBody); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_cmd0x352_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*RspBody); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_cmd0x352_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*D352TryUpImgReq); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_cmd0x352_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*TryUpImgRsp); 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_cmd0x352_proto_rawDesc,
NumEnums: 0,
NumMessages: 4,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_cmd0x352_proto_goTypes,
DependencyIndexes: file_cmd0x352_proto_depIdxs,
MessageInfos: file_cmd0x352_proto_msgTypes,
}.Build()
File_cmd0x352_proto = out.File
file_cmd0x352_proto_rawDesc = nil
file_cmd0x352_proto_goTypes = nil
file_cmd0x352_proto_depIdxs = nil
} }

View File

@ -1,6 +1,6 @@
syntax = "proto2"; syntax = "proto2";
option go_package = "github.com/Mrs4s/MiraiGo/client/pb/cmd0x352"; option go_package = "./;cmd0x352";
/* /*
message DelImgReq { message DelImgReq {
optional uint64 srcUin = 1; optional uint64 srcUin = 1;

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
syntax = "proto2"; syntax = "proto2";
option go_package = "github.com/Mrs4s/MiraiGo/client/pb/cmd0x388"; option go_package = "./;cmd0x388";
message DelImgReq { message DelImgReq {
optional uint64 srcUin = 1; optional uint64 srcUin = 1;

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
syntax = "proto2"; syntax = "proto2";
option go_package = "github.com/Mrs4s/MiraiGo/client/pb/cmd0x3f6"; option go_package = "./;cmd0x3f6";
message C3F6ReqBody { message C3F6ReqBody {
optional uint32 subCmd = 1; optional uint32 subCmd = 1;

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
syntax = "proto2"; syntax = "proto2";
option go_package = "github.com/Mrs4s/MiraiGo/client/pb/cmd0x6ff"; option go_package = "./;cmd0x6ff";
message C519CRMMsgHead { message C519CRMMsgHead {
optional uint32 crmSubCmd = 1; optional uint32 crmSubCmd = 1;
@ -34,7 +34,7 @@ message C519ReqBody {
optional uint32 subCmd = 1; optional uint32 subCmd = 1;
optional C519CRMMsgHead crmCommonHead = 2; optional C519CRMMsgHead crmCommonHead = 2;
optional GetAddressDetailListReqBody getAddressDetailListReqBody = 33; optional GetAddressDetailListReqBody getAddressDetailListReqBody = 33;
// optional GetNavigationMenuReqBody getNavigationMenuReq = 35; optional GetNavigationMenuReqBody getNavigationMenuReq = 35;
} }
message C519RetInfo { message C519RetInfo {
@ -44,9 +44,9 @@ message C519RetInfo {
message C519RspBody { message C519RspBody {
optional uint32 subCmd = 1; optional uint32 subCmd = 1;
// optional C519CRMMsgHead crmCommonHead = 2; optional C519CRMMsgHead crmCommonHead = 2;
optional GetAddressDetailListRspBody getAddressDetailListRspBody = 33; optional GetAddressDetailListRspBody getAddressDetailListRspBody = 33;
//optional GetNavigationMenuRspBody getNavigationMenuRsp = 35; optional GetNavigationMenuRspBody getNavigationMenuRsp = 35;
} }
message GetAddressDetailListReqBody { message GetAddressDetailListReqBody {
@ -55,7 +55,7 @@ message GetAddressDetailListReqBody {
} }
message GetAddressDetailListRspBody { message GetAddressDetailListRspBody {
//optional C519RetInfo ret = 1; optional C519RetInfo ret = 1;
optional fixed32 timestamp = 2; optional fixed32 timestamp = 2;
optional bool full = 3; optional bool full = 3;
repeated AddressDetail addressDetail = 4; repeated AddressDetail addressDetail = 4;
@ -84,13 +84,13 @@ message AddressDetail {
optional bytes fax1 = 19; optional bytes fax1 = 19;
optional bytes comment = 20; optional bytes comment = 20;
optional bytes headUrl = 21; optional bytes headUrl = 21;
//repeated AddressMobileInfo mobilePhone = 22; repeated AddressMobileInfo mobilePhone = 22;
optional bool mobilePhoneUpdated = 23; optional bool mobilePhoneUpdated = 23;
repeated AddressQQinfo qq = 24; repeated AddressQQinfo qq = 24;
optional bool qqPhoneUpdated = 25; optional bool qqPhoneUpdated = 25;
optional fixed64 modifyTime2 = 26; optional fixed64 modifyTime2 = 26;
//optional NewBizClientRegion clientRegion = 27; optional NewBizClientRegion clientRegion = 27;
//optional NewBizClientRegionCode clientRegionCode = 28; optional NewBizClientRegionCode clientRegionCode = 28;
} }
message AddressMobileInfo { message AddressMobileInfo {

View File

@ -1,48 +1,589 @@
// Code generated by protoc-gen-golite. DO NOT EDIT. // Code generated by protoc-gen-go. DO NOT EDIT.
// source: pb/cmd0x6ff/subcmd0x501.proto // versions:
// protoc-gen-go v1.26.0
// protoc v3.17.1
// source: subcmd0x501.proto
package cmd0x6ff package cmd0x6ff
import ( import (
proto "github.com/RomiChan/protobuf/proto" reflect "reflect"
sync "sync"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
)
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 C501ReqBody struct { type C501ReqBody struct {
ReqBody *SubCmd0X501ReqBody `protobuf:"bytes,1281,opt"` state protoimpl.MessageState
_ [0]func() sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
ReqBody *SubCmd0X501ReqBody `protobuf:"bytes,1281,opt,name=ReqBody" json:"ReqBody,omitempty"`
}
func (x *C501ReqBody) Reset() {
*x = C501ReqBody{}
if protoimpl.UnsafeEnabled {
mi := &file_subcmd0x501_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *C501ReqBody) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*C501ReqBody) ProtoMessage() {}
func (x *C501ReqBody) ProtoReflect() protoreflect.Message {
mi := &file_subcmd0x501_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 C501ReqBody.ProtoReflect.Descriptor instead.
func (*C501ReqBody) Descriptor() ([]byte, []int) {
return file_subcmd0x501_proto_rawDescGZIP(), []int{0}
}
func (x *C501ReqBody) GetReqBody() *SubCmd0X501ReqBody {
if x != nil {
return x.ReqBody
}
return nil
} }
type C501RspBody struct { type C501RspBody struct {
RspBody *SubCmd0X501RspBody `protobuf:"bytes,1281,opt"` state protoimpl.MessageState
_ [0]func() sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
RspBody *SubCmd0X501RspBody `protobuf:"bytes,1281,opt,name=RspBody" json:"RspBody,omitempty"`
}
func (x *C501RspBody) Reset() {
*x = C501RspBody{}
if protoimpl.UnsafeEnabled {
mi := &file_subcmd0x501_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *C501RspBody) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*C501RspBody) ProtoMessage() {}
func (x *C501RspBody) ProtoReflect() protoreflect.Message {
mi := &file_subcmd0x501_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 C501RspBody.ProtoReflect.Descriptor instead.
func (*C501RspBody) Descriptor() ([]byte, []int) {
return file_subcmd0x501_proto_rawDescGZIP(), []int{1}
}
func (x *C501RspBody) GetRspBody() *SubCmd0X501RspBody {
if x != nil {
return x.RspBody
}
return nil
} }
type SubCmd0X501ReqBody struct { type SubCmd0X501ReqBody struct {
Uin proto.Option[uint64] `protobuf:"varint,1,opt"` state protoimpl.MessageState
IdcId proto.Option[uint32] `protobuf:"varint,2,opt"` sizeCache protoimpl.SizeCache
Appid proto.Option[uint32] `protobuf:"varint,3,opt"` unknownFields protoimpl.UnknownFields
LoginSigType proto.Option[uint32] `protobuf:"varint,4,opt"`
LoginSigTicket []byte `protobuf:"bytes,5,opt"` Uin *uint64 `protobuf:"varint,1,opt,name=uin" json:"uin,omitempty"`
RequestFlag proto.Option[uint32] `protobuf:"varint,6,opt"` IdcId *uint32 `protobuf:"varint,2,opt,name=idcId" json:"idcId,omitempty"`
ServiceTypes []uint32 `protobuf:"varint,7,rep"` Appid *uint32 `protobuf:"varint,3,opt,name=appid" json:"appid,omitempty"`
Bid proto.Option[uint32] `protobuf:"varint,8,opt"` LoginSigType *uint32 `protobuf:"varint,4,opt,name=loginSigType" json:"loginSigType,omitempty"`
LoginSigTicket []byte `protobuf:"bytes,5,opt,name=loginSigTicket" json:"loginSigTicket,omitempty"`
RequestFlag *uint32 `protobuf:"varint,6,opt,name=requestFlag" json:"requestFlag,omitempty"`
ServiceTypes []uint32 `protobuf:"varint,7,rep,name=serviceTypes" json:"serviceTypes,omitempty"`
Bid *uint32 `protobuf:"varint,8,opt,name=bid" json:"bid,omitempty"`
}
func (x *SubCmd0X501ReqBody) Reset() {
*x = SubCmd0X501ReqBody{}
if protoimpl.UnsafeEnabled {
mi := &file_subcmd0x501_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *SubCmd0X501ReqBody) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*SubCmd0X501ReqBody) ProtoMessage() {}
func (x *SubCmd0X501ReqBody) ProtoReflect() protoreflect.Message {
mi := &file_subcmd0x501_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 SubCmd0X501ReqBody.ProtoReflect.Descriptor instead.
func (*SubCmd0X501ReqBody) Descriptor() ([]byte, []int) {
return file_subcmd0x501_proto_rawDescGZIP(), []int{2}
}
func (x *SubCmd0X501ReqBody) GetUin() uint64 {
if x != nil && x.Uin != nil {
return *x.Uin
}
return 0
}
func (x *SubCmd0X501ReqBody) GetIdcId() uint32 {
if x != nil && x.IdcId != nil {
return *x.IdcId
}
return 0
}
func (x *SubCmd0X501ReqBody) GetAppid() uint32 {
if x != nil && x.Appid != nil {
return *x.Appid
}
return 0
}
func (x *SubCmd0X501ReqBody) GetLoginSigType() uint32 {
if x != nil && x.LoginSigType != nil {
return *x.LoginSigType
}
return 0
}
func (x *SubCmd0X501ReqBody) GetLoginSigTicket() []byte {
if x != nil {
return x.LoginSigTicket
}
return nil
}
func (x *SubCmd0X501ReqBody) GetRequestFlag() uint32 {
if x != nil && x.RequestFlag != nil {
return *x.RequestFlag
}
return 0
}
func (x *SubCmd0X501ReqBody) GetServiceTypes() []uint32 {
if x != nil {
return x.ServiceTypes
}
return nil
}
func (x *SubCmd0X501ReqBody) GetBid() uint32 {
if x != nil && x.Bid != nil {
return *x.Bid
}
return 0
} }
type SubCmd0X501RspBody struct { type SubCmd0X501RspBody struct {
SigSession []byte `protobuf:"bytes,1,opt"` state protoimpl.MessageState
SessionKey []byte `protobuf:"bytes,2,opt"` sizeCache protoimpl.SizeCache
Addrs []*SrvAddrs `protobuf:"bytes,3,rep"` unknownFields protoimpl.UnknownFields
SigSession []byte `protobuf:"bytes,1,opt,name=sigSession" json:"sigSession,omitempty"`
SessionKey []byte `protobuf:"bytes,2,opt,name=sessionKey" json:"sessionKey,omitempty"`
Addrs []*SrvAddrs `protobuf:"bytes,3,rep,name=addrs" json:"addrs,omitempty"`
}
func (x *SubCmd0X501RspBody) Reset() {
*x = SubCmd0X501RspBody{}
if protoimpl.UnsafeEnabled {
mi := &file_subcmd0x501_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *SubCmd0X501RspBody) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*SubCmd0X501RspBody) ProtoMessage() {}
func (x *SubCmd0X501RspBody) ProtoReflect() protoreflect.Message {
mi := &file_subcmd0x501_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 SubCmd0X501RspBody.ProtoReflect.Descriptor instead.
func (*SubCmd0X501RspBody) Descriptor() ([]byte, []int) {
return file_subcmd0x501_proto_rawDescGZIP(), []int{3}
}
func (x *SubCmd0X501RspBody) GetSigSession() []byte {
if x != nil {
return x.SigSession
}
return nil
}
func (x *SubCmd0X501RspBody) GetSessionKey() []byte {
if x != nil {
return x.SessionKey
}
return nil
}
func (x *SubCmd0X501RspBody) GetAddrs() []*SrvAddrs {
if x != nil {
return x.Addrs
}
return nil
} }
type SrvAddrs struct { type SrvAddrs struct {
ServiceType proto.Option[uint32] `protobuf:"varint,1,opt"` state protoimpl.MessageState
Addrs []*IpAddr `protobuf:"bytes,2,rep"` sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
ServiceType *uint32 `protobuf:"varint,1,opt,name=serviceType" json:"serviceType,omitempty"`
Addrs []*IpAddr `protobuf:"bytes,2,rep,name=addrs" json:"addrs,omitempty"`
}
func (x *SrvAddrs) Reset() {
*x = SrvAddrs{}
if protoimpl.UnsafeEnabled {
mi := &file_subcmd0x501_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *SrvAddrs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*SrvAddrs) ProtoMessage() {}
func (x *SrvAddrs) ProtoReflect() protoreflect.Message {
mi := &file_subcmd0x501_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 SrvAddrs.ProtoReflect.Descriptor instead.
func (*SrvAddrs) Descriptor() ([]byte, []int) {
return file_subcmd0x501_proto_rawDescGZIP(), []int{4}
}
func (x *SrvAddrs) GetServiceType() uint32 {
if x != nil && x.ServiceType != nil {
return *x.ServiceType
}
return 0
}
func (x *SrvAddrs) GetAddrs() []*IpAddr {
if x != nil {
return x.Addrs
}
return nil
} }
type IpAddr struct { type IpAddr struct {
Type proto.Option[uint32] `protobuf:"varint,1,opt"` state protoimpl.MessageState
Ip proto.Option[uint32] `protobuf:"fixed32,2,opt"` sizeCache protoimpl.SizeCache
Port proto.Option[uint32] `protobuf:"varint,3,opt"` unknownFields protoimpl.UnknownFields
Area proto.Option[uint32] `protobuf:"varint,4,opt"`
_ [0]func() Type *uint32 `protobuf:"varint,1,opt,name=type" json:"type,omitempty"`
Ip *uint32 `protobuf:"fixed32,2,opt,name=ip" json:"ip,omitempty"`
Port *uint32 `protobuf:"varint,3,opt,name=port" json:"port,omitempty"`
Area *uint32 `protobuf:"varint,4,opt,name=area" json:"area,omitempty"`
}
func (x *IpAddr) Reset() {
*x = IpAddr{}
if protoimpl.UnsafeEnabled {
mi := &file_subcmd0x501_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *IpAddr) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*IpAddr) ProtoMessage() {}
func (x *IpAddr) ProtoReflect() protoreflect.Message {
mi := &file_subcmd0x501_proto_msgTypes[5]
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 IpAddr.ProtoReflect.Descriptor instead.
func (*IpAddr) Descriptor() ([]byte, []int) {
return file_subcmd0x501_proto_rawDescGZIP(), []int{5}
}
func (x *IpAddr) GetType() uint32 {
if x != nil && x.Type != nil {
return *x.Type
}
return 0
}
func (x *IpAddr) GetIp() uint32 {
if x != nil && x.Ip != nil {
return *x.Ip
}
return 0
}
func (x *IpAddr) GetPort() uint32 {
if x != nil && x.Port != nil {
return *x.Port
}
return 0
}
func (x *IpAddr) GetArea() uint32 {
if x != nil && x.Area != nil {
return *x.Area
}
return 0
}
var File_subcmd0x501_proto protoreflect.FileDescriptor
var file_subcmd0x501_proto_rawDesc = []byte{
0x0a, 0x11, 0x73, 0x75, 0x62, 0x63, 0x6d, 0x64, 0x30, 0x78, 0x35, 0x30, 0x31, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x22, 0x3d, 0x0a, 0x0b, 0x43, 0x35, 0x30, 0x31, 0x52, 0x65, 0x71, 0x42, 0x6f,
0x64, 0x79, 0x12, 0x2e, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x42, 0x6f, 0x64, 0x79, 0x18, 0x81, 0x0a,
0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x53, 0x75, 0x62, 0x43, 0x6d, 0x64, 0x30, 0x78, 0x35,
0x30, 0x31, 0x52, 0x65, 0x71, 0x42, 0x6f, 0x64, 0x79, 0x52, 0x07, 0x52, 0x65, 0x71, 0x42, 0x6f,
0x64, 0x79, 0x22, 0x3d, 0x0a, 0x0b, 0x43, 0x35, 0x30, 0x31, 0x52, 0x73, 0x70, 0x42, 0x6f, 0x64,
0x79, 0x12, 0x2e, 0x0a, 0x07, 0x52, 0x73, 0x70, 0x42, 0x6f, 0x64, 0x79, 0x18, 0x81, 0x0a, 0x20,
0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x53, 0x75, 0x62, 0x43, 0x6d, 0x64, 0x30, 0x78, 0x35, 0x30,
0x31, 0x52, 0x73, 0x70, 0x42, 0x6f, 0x64, 0x79, 0x52, 0x07, 0x52, 0x73, 0x70, 0x42, 0x6f, 0x64,
0x79, 0x22, 0xf6, 0x01, 0x0a, 0x12, 0x53, 0x75, 0x62, 0x43, 0x6d, 0x64, 0x30, 0x78, 0x35, 0x30,
0x31, 0x52, 0x65, 0x71, 0x42, 0x6f, 0x64, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x69, 0x6e, 0x18,
0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x03, 0x75, 0x69, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x64,
0x63, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x69, 0x64, 0x63, 0x49, 0x64,
0x12, 0x14, 0x0a, 0x05, 0x61, 0x70, 0x70, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52,
0x05, 0x61, 0x70, 0x70, 0x69, 0x64, 0x12, 0x22, 0x0a, 0x0c, 0x6c, 0x6f, 0x67, 0x69, 0x6e, 0x53,
0x69, 0x67, 0x54, 0x79, 0x70, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0c, 0x6c, 0x6f,
0x67, 0x69, 0x6e, 0x53, 0x69, 0x67, 0x54, 0x79, 0x70, 0x65, 0x12, 0x26, 0x0a, 0x0e, 0x6c, 0x6f,
0x67, 0x69, 0x6e, 0x53, 0x69, 0x67, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x18, 0x05, 0x20, 0x01,
0x28, 0x0c, 0x52, 0x0e, 0x6c, 0x6f, 0x67, 0x69, 0x6e, 0x53, 0x69, 0x67, 0x54, 0x69, 0x63, 0x6b,
0x65, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x46, 0x6c, 0x61,
0x67, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0x46, 0x6c, 0x61, 0x67, 0x12, 0x22, 0x0a, 0x0c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x54,
0x79, 0x70, 0x65, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0d, 0x52, 0x0c, 0x73, 0x65, 0x72, 0x76,
0x69, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x62, 0x69, 0x64, 0x18,
0x08, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x03, 0x62, 0x69, 0x64, 0x22, 0x75, 0x0a, 0x12, 0x53, 0x75,
0x62, 0x43, 0x6d, 0x64, 0x30, 0x78, 0x35, 0x30, 0x31, 0x52, 0x73, 0x70, 0x42, 0x6f, 0x64, 0x79,
0x12, 0x1e, 0x0a, 0x0a, 0x73, 0x69, 0x67, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01,
0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x73, 0x69, 0x67, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e,
0x12, 0x1e, 0x0a, 0x0a, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x4b, 0x65, 0x79, 0x18, 0x02,
0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x4b, 0x65, 0x79,
0x12, 0x1f, 0x0a, 0x05, 0x61, 0x64, 0x64, 0x72, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32,
0x09, 0x2e, 0x53, 0x72, 0x76, 0x41, 0x64, 0x64, 0x72, 0x73, 0x52, 0x05, 0x61, 0x64, 0x64, 0x72,
0x73, 0x22, 0x4b, 0x0a, 0x08, 0x53, 0x72, 0x76, 0x41, 0x64, 0x64, 0x72, 0x73, 0x12, 0x20, 0x0a,
0x0b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01,
0x28, 0x0d, 0x52, 0x0b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12,
0x1d, 0x0a, 0x05, 0x61, 0x64, 0x64, 0x72, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x07,
0x2e, 0x49, 0x70, 0x41, 0x64, 0x64, 0x72, 0x52, 0x05, 0x61, 0x64, 0x64, 0x72, 0x73, 0x22, 0x54,
0x0a, 0x06, 0x49, 0x70, 0x41, 0x64, 0x64, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65,
0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x0e, 0x0a, 0x02,
0x69, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x07, 0x52, 0x02, 0x69, 0x70, 0x12, 0x12, 0x0a, 0x04,
0x70, 0x6f, 0x72, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74,
0x12, 0x12, 0x0a, 0x04, 0x61, 0x72, 0x65, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04,
0x61, 0x72, 0x65, 0x61, 0x42, 0x0d, 0x5a, 0x0b, 0x2e, 0x2f, 0x3b, 0x63, 0x6d, 0x64, 0x30, 0x78,
0x36, 0x66, 0x66,
}
var (
file_subcmd0x501_proto_rawDescOnce sync.Once
file_subcmd0x501_proto_rawDescData = file_subcmd0x501_proto_rawDesc
)
func file_subcmd0x501_proto_rawDescGZIP() []byte {
file_subcmd0x501_proto_rawDescOnce.Do(func() {
file_subcmd0x501_proto_rawDescData = protoimpl.X.CompressGZIP(file_subcmd0x501_proto_rawDescData)
})
return file_subcmd0x501_proto_rawDescData
}
var file_subcmd0x501_proto_msgTypes = make([]protoimpl.MessageInfo, 6)
var file_subcmd0x501_proto_goTypes = []interface{}{
(*C501ReqBody)(nil), // 0: C501ReqBody
(*C501RspBody)(nil), // 1: C501RspBody
(*SubCmd0X501ReqBody)(nil), // 2: SubCmd0x501ReqBody
(*SubCmd0X501RspBody)(nil), // 3: SubCmd0x501RspBody
(*SrvAddrs)(nil), // 4: SrvAddrs
(*IpAddr)(nil), // 5: IpAddr
}
var file_subcmd0x501_proto_depIdxs = []int32{
2, // 0: C501ReqBody.ReqBody:type_name -> SubCmd0x501ReqBody
3, // 1: C501RspBody.RspBody:type_name -> SubCmd0x501RspBody
4, // 2: SubCmd0x501RspBody.addrs:type_name -> SrvAddrs
5, // 3: SrvAddrs.addrs:type_name -> IpAddr
4, // [4:4] is the sub-list for method output_type
4, // [4:4] is the sub-list for method input_type
4, // [4:4] is the sub-list for extension type_name
4, // [4:4] is the sub-list for extension extendee
0, // [0:4] is the sub-list for field type_name
}
func init() { file_subcmd0x501_proto_init() }
func file_subcmd0x501_proto_init() {
if File_subcmd0x501_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_subcmd0x501_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*C501ReqBody); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_subcmd0x501_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*C501RspBody); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_subcmd0x501_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*SubCmd0X501ReqBody); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_subcmd0x501_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*SubCmd0X501RspBody); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_subcmd0x501_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*SrvAddrs); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_subcmd0x501_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*IpAddr); 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_subcmd0x501_proto_rawDesc,
NumEnums: 0,
NumMessages: 6,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_subcmd0x501_proto_goTypes,
DependencyIndexes: file_subcmd0x501_proto_depIdxs,
MessageInfos: file_subcmd0x501_proto_msgTypes,
}.Build()
File_subcmd0x501_proto = out.File
file_subcmd0x501_proto_rawDesc = nil
file_subcmd0x501_proto_goTypes = nil
file_subcmd0x501_proto_depIdxs = nil
} }

View File

@ -1,5 +1,5 @@
syntax = "proto2"; syntax = "proto2";
option go_package = "github.com/Mrs4s/MiraiGo/client/pb/cmd0x6ff"; option go_package = "./;cmd0x6ff";
message C501ReqBody { message C501ReqBody {
optional SubCmd0x501ReqBody ReqBody = 1281; optional SubCmd0x501ReqBody ReqBody = 1281;

File diff suppressed because it is too large Load Diff

View File

@ -1,25 +1,7 @@
syntax = "proto3"; syntax = "proto3";
option go_package = "github.com/Mrs4s/MiraiGo/client/pb"; option go_package = "./;pb";
message SSOReserveField {
int32 flag = 9;
string qimei = 12;
int32 newconn_flag = 14;
string uid = 16;
int32 imsi = 18;
int32 network_type = 19;
int32 ip_stack_type = 20;
int32 message_type = 21;
SsoSecureInfo sec_info = 24;
int32 sso_ip_origin = 28;
}
message SsoSecureInfo {
bytes sec_sig = 1;
bytes sec_device_token = 2;
bytes sec_extra = 3;
}
message DeviceInfo { message DeviceInfo {
string bootloader = 1; string bootloader = 1;

View File

@ -1,72 +1,859 @@
// Code generated by protoc-gen-golite. DO NOT EDIT. // Code generated by protoc-gen-go. DO NOT EDIT.
// source: pb/exciting/group.proto // versions:
// protoc-gen-go v1.26.0
// protoc v3.17.1
// source: group.proto
package exciting package exciting
import ( import (
proto "github.com/RomiChan/protobuf/proto" reflect "reflect"
sync "sync"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
) )
type FileUploadExt struct { const (
Unknown1 proto.Option[int32] `protobuf:"varint,1,opt"` // Verify that this generated code is sufficiently up-to-date.
Unknown2 proto.Option[int32] `protobuf:"varint,2,opt"` _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
Unknown3 proto.Option[int32] `protobuf:"varint,3,opt"` // Verify that runtime/protoimpl is sufficiently up-to-date.
Entry *FileUploadEntry `protobuf:"bytes,100,opt"` _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
Unknown200 proto.Option[int32] `protobuf:"varint,200,opt"` )
_ [0]func()
type GroupFileUploadExt struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Unknown1 *int32 `protobuf:"varint,1,opt,name=unknown1" json:"unknown1,omitempty"`
Unknown2 *int32 `protobuf:"varint,2,opt,name=unknown2" json:"unknown2,omitempty"`
Entry *GroupFileUploadEntry `protobuf:"bytes,100,opt,name=entry" json:"entry,omitempty"`
Unknown3 *int32 `protobuf:"varint,3,opt,name=unknown3" json:"unknown3,omitempty"`
} }
type FileUploadEntry struct { func (x *GroupFileUploadExt) Reset() {
BusiBuff *ExcitingBusiInfo `protobuf:"bytes,100,opt"` *x = GroupFileUploadExt{}
FileEntry *ExcitingFileEntry `protobuf:"bytes,200,opt"` if protoimpl.UnsafeEnabled {
ClientInfo *ExcitingClientInfo `protobuf:"bytes,300,opt"` mi := &file_group_proto_msgTypes[0]
FileNameInfo *ExcitingFileNameInfo `protobuf:"bytes,400,opt"` ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
Host *ExcitingHostConfig `protobuf:"bytes,500,opt"` ms.StoreMessageInfo(mi)
_ [0]func() }
}
func (x *GroupFileUploadExt) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GroupFileUploadExt) ProtoMessage() {}
func (x *GroupFileUploadExt) ProtoReflect() protoreflect.Message {
mi := &file_group_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 GroupFileUploadExt.ProtoReflect.Descriptor instead.
func (*GroupFileUploadExt) Descriptor() ([]byte, []int) {
return file_group_proto_rawDescGZIP(), []int{0}
}
func (x *GroupFileUploadExt) GetUnknown1() int32 {
if x != nil && x.Unknown1 != nil {
return *x.Unknown1
}
return 0
}
func (x *GroupFileUploadExt) GetUnknown2() int32 {
if x != nil && x.Unknown2 != nil {
return *x.Unknown2
}
return 0
}
func (x *GroupFileUploadExt) GetEntry() *GroupFileUploadEntry {
if x != nil {
return x.Entry
}
return nil
}
func (x *GroupFileUploadExt) GetUnknown3() int32 {
if x != nil && x.Unknown3 != nil {
return *x.Unknown3
}
return 0
}
type GroupFileUploadEntry struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
BusiBuff *ExcitingBusiInfo `protobuf:"bytes,100,opt,name=busiBuff" json:"busiBuff,omitempty"`
FileEntry *ExcitingFileEntry `protobuf:"bytes,200,opt,name=fileEntry" json:"fileEntry,omitempty"`
ClientInfo *ExcitingClientInfo `protobuf:"bytes,300,opt,name=clientInfo" json:"clientInfo,omitempty"`
FileNameInfo *ExcitingFileNameInfo `protobuf:"bytes,400,opt,name=fileNameInfo" json:"fileNameInfo,omitempty"`
Host *ExcitingHostConfig `protobuf:"bytes,500,opt,name=host" json:"host,omitempty"`
}
func (x *GroupFileUploadEntry) Reset() {
*x = GroupFileUploadEntry{}
if protoimpl.UnsafeEnabled {
mi := &file_group_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *GroupFileUploadEntry) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GroupFileUploadEntry) ProtoMessage() {}
func (x *GroupFileUploadEntry) ProtoReflect() protoreflect.Message {
mi := &file_group_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 GroupFileUploadEntry.ProtoReflect.Descriptor instead.
func (*GroupFileUploadEntry) Descriptor() ([]byte, []int) {
return file_group_proto_rawDescGZIP(), []int{1}
}
func (x *GroupFileUploadEntry) GetBusiBuff() *ExcitingBusiInfo {
if x != nil {
return x.BusiBuff
}
return nil
}
func (x *GroupFileUploadEntry) GetFileEntry() *ExcitingFileEntry {
if x != nil {
return x.FileEntry
}
return nil
}
func (x *GroupFileUploadEntry) GetClientInfo() *ExcitingClientInfo {
if x != nil {
return x.ClientInfo
}
return nil
}
func (x *GroupFileUploadEntry) GetFileNameInfo() *ExcitingFileNameInfo {
if x != nil {
return x.FileNameInfo
}
return nil
}
func (x *GroupFileUploadEntry) GetHost() *ExcitingHostConfig {
if x != nil {
return x.Host
}
return nil
} }
type ExcitingBusiInfo struct { type ExcitingBusiInfo struct {
BusId proto.Option[int32] `protobuf:"varint,1,opt"` state protoimpl.MessageState
SenderUin proto.Option[int64] `protobuf:"varint,100,opt"` sizeCache protoimpl.SizeCache
ReceiverUin proto.Option[int64] `protobuf:"varint,200,opt"` // probable unknownFields protoimpl.UnknownFields
GroupCode proto.Option[int64] `protobuf:"varint,400,opt"` // probable
_ [0]func() BusId *int32 `protobuf:"varint,1,opt,name=busId" json:"busId,omitempty"`
SenderUin *int64 `protobuf:"varint,100,opt,name=senderUin" json:"senderUin,omitempty"`
ReceiverUin *int64 `protobuf:"varint,200,opt,name=receiverUin" json:"receiverUin,omitempty"` // probable
GroupCode *int64 `protobuf:"varint,400,opt,name=groupCode" json:"groupCode,omitempty"` // probable
}
func (x *ExcitingBusiInfo) Reset() {
*x = ExcitingBusiInfo{}
if protoimpl.UnsafeEnabled {
mi := &file_group_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ExcitingBusiInfo) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ExcitingBusiInfo) ProtoMessage() {}
func (x *ExcitingBusiInfo) ProtoReflect() protoreflect.Message {
mi := &file_group_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 ExcitingBusiInfo.ProtoReflect.Descriptor instead.
func (*ExcitingBusiInfo) Descriptor() ([]byte, []int) {
return file_group_proto_rawDescGZIP(), []int{2}
}
func (x *ExcitingBusiInfo) GetBusId() int32 {
if x != nil && x.BusId != nil {
return *x.BusId
}
return 0
}
func (x *ExcitingBusiInfo) GetSenderUin() int64 {
if x != nil && x.SenderUin != nil {
return *x.SenderUin
}
return 0
}
func (x *ExcitingBusiInfo) GetReceiverUin() int64 {
if x != nil && x.ReceiverUin != nil {
return *x.ReceiverUin
}
return 0
}
func (x *ExcitingBusiInfo) GetGroupCode() int64 {
if x != nil && x.GroupCode != nil {
return *x.GroupCode
}
return 0
} }
type ExcitingFileEntry struct { type ExcitingFileEntry struct {
FileSize proto.Option[int64] `protobuf:"varint,100,opt"` state protoimpl.MessageState
Md5 []byte `protobuf:"bytes,200,opt"` sizeCache protoimpl.SizeCache
Sha1 []byte `protobuf:"bytes,300,opt"` unknownFields protoimpl.UnknownFields
FileId []byte `protobuf:"bytes,600,opt"`
UploadKey []byte `protobuf:"bytes,700,opt"` FileSize *int64 `protobuf:"varint,100,opt,name=fileSize" json:"fileSize,omitempty"`
Md5 []byte `protobuf:"bytes,200,opt,name=md5" json:"md5,omitempty"`
Sha1 []byte `protobuf:"bytes,300,opt,name=sha1" json:"sha1,omitempty"`
FileId []byte `protobuf:"bytes,600,opt,name=fileId" json:"fileId,omitempty"`
UploadKey []byte `protobuf:"bytes,700,opt,name=uploadKey" json:"uploadKey,omitempty"`
}
func (x *ExcitingFileEntry) Reset() {
*x = ExcitingFileEntry{}
if protoimpl.UnsafeEnabled {
mi := &file_group_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ExcitingFileEntry) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ExcitingFileEntry) ProtoMessage() {}
func (x *ExcitingFileEntry) ProtoReflect() protoreflect.Message {
mi := &file_group_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 ExcitingFileEntry.ProtoReflect.Descriptor instead.
func (*ExcitingFileEntry) Descriptor() ([]byte, []int) {
return file_group_proto_rawDescGZIP(), []int{3}
}
func (x *ExcitingFileEntry) GetFileSize() int64 {
if x != nil && x.FileSize != nil {
return *x.FileSize
}
return 0
}
func (x *ExcitingFileEntry) GetMd5() []byte {
if x != nil {
return x.Md5
}
return nil
}
func (x *ExcitingFileEntry) GetSha1() []byte {
if x != nil {
return x.Sha1
}
return nil
}
func (x *ExcitingFileEntry) GetFileId() []byte {
if x != nil {
return x.FileId
}
return nil
}
func (x *ExcitingFileEntry) GetUploadKey() []byte {
if x != nil {
return x.UploadKey
}
return nil
} }
type ExcitingClientInfo struct { type ExcitingClientInfo struct {
ClientType proto.Option[int32] `protobuf:"varint,100,opt"` // probable state protoimpl.MessageState
AppId proto.Option[string] `protobuf:"bytes,200,opt"` sizeCache protoimpl.SizeCache
TerminalType proto.Option[int32] `protobuf:"varint,300,opt"` // probable unknownFields protoimpl.UnknownFields
ClientVer proto.Option[string] `protobuf:"bytes,400,opt"`
Unknown proto.Option[int32] `protobuf:"varint,600,opt"` ClientType *int32 `protobuf:"varint,100,opt,name=clientType" json:"clientType,omitempty"` // probable
_ [0]func() AppId *string `protobuf:"bytes,200,opt,name=appId" json:"appId,omitempty"`
TerminalType *int32 `protobuf:"varint,300,opt,name=terminalType" json:"terminalType,omitempty"` // probable
ClientVer *string `protobuf:"bytes,400,opt,name=clientVer" json:"clientVer,omitempty"`
Unknown *int32 `protobuf:"varint,600,opt,name=unknown" json:"unknown,omitempty"`
}
func (x *ExcitingClientInfo) Reset() {
*x = ExcitingClientInfo{}
if protoimpl.UnsafeEnabled {
mi := &file_group_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ExcitingClientInfo) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ExcitingClientInfo) ProtoMessage() {}
func (x *ExcitingClientInfo) ProtoReflect() protoreflect.Message {
mi := &file_group_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 ExcitingClientInfo.ProtoReflect.Descriptor instead.
func (*ExcitingClientInfo) Descriptor() ([]byte, []int) {
return file_group_proto_rawDescGZIP(), []int{4}
}
func (x *ExcitingClientInfo) GetClientType() int32 {
if x != nil && x.ClientType != nil {
return *x.ClientType
}
return 0
}
func (x *ExcitingClientInfo) GetAppId() string {
if x != nil && x.AppId != nil {
return *x.AppId
}
return ""
}
func (x *ExcitingClientInfo) GetTerminalType() int32 {
if x != nil && x.TerminalType != nil {
return *x.TerminalType
}
return 0
}
func (x *ExcitingClientInfo) GetClientVer() string {
if x != nil && x.ClientVer != nil {
return *x.ClientVer
}
return ""
}
func (x *ExcitingClientInfo) GetUnknown() int32 {
if x != nil && x.Unknown != nil {
return *x.Unknown
}
return 0
} }
type ExcitingFileNameInfo struct { type ExcitingFileNameInfo struct {
FileName proto.Option[string] `protobuf:"bytes,100,opt"` state protoimpl.MessageState
_ [0]func() sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
FileName *string `protobuf:"bytes,100,opt,name=fileName" json:"fileName,omitempty"`
}
func (x *ExcitingFileNameInfo) Reset() {
*x = ExcitingFileNameInfo{}
if protoimpl.UnsafeEnabled {
mi := &file_group_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ExcitingFileNameInfo) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ExcitingFileNameInfo) ProtoMessage() {}
func (x *ExcitingFileNameInfo) ProtoReflect() protoreflect.Message {
mi := &file_group_proto_msgTypes[5]
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 ExcitingFileNameInfo.ProtoReflect.Descriptor instead.
func (*ExcitingFileNameInfo) Descriptor() ([]byte, []int) {
return file_group_proto_rawDescGZIP(), []int{5}
}
func (x *ExcitingFileNameInfo) GetFileName() string {
if x != nil && x.FileName != nil {
return *x.FileName
}
return ""
} }
type ExcitingHostConfig struct { type ExcitingHostConfig struct {
Hosts []*ExcitingHostInfo `protobuf:"bytes,200,rep"` state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Hosts []*ExcitingHostInfo `protobuf:"bytes,200,rep,name=hosts" json:"hosts,omitempty"`
}
func (x *ExcitingHostConfig) Reset() {
*x = ExcitingHostConfig{}
if protoimpl.UnsafeEnabled {
mi := &file_group_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ExcitingHostConfig) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ExcitingHostConfig) ProtoMessage() {}
func (x *ExcitingHostConfig) ProtoReflect() protoreflect.Message {
mi := &file_group_proto_msgTypes[6]
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 ExcitingHostConfig.ProtoReflect.Descriptor instead.
func (*ExcitingHostConfig) Descriptor() ([]byte, []int) {
return file_group_proto_rawDescGZIP(), []int{6}
}
func (x *ExcitingHostConfig) GetHosts() []*ExcitingHostInfo {
if x != nil {
return x.Hosts
}
return nil
} }
type ExcitingHostInfo struct { type ExcitingHostInfo struct {
Url *ExcitingUrlInfo `protobuf:"bytes,1,opt"` state protoimpl.MessageState
Port proto.Option[int32] `protobuf:"varint,2,opt"` sizeCache protoimpl.SizeCache
_ [0]func() unknownFields protoimpl.UnknownFields
Url *ExcitingUrlInfo `protobuf:"bytes,1,opt,name=url" json:"url,omitempty"`
Port *int32 `protobuf:"varint,2,opt,name=port" json:"port,omitempty"`
}
func (x *ExcitingHostInfo) Reset() {
*x = ExcitingHostInfo{}
if protoimpl.UnsafeEnabled {
mi := &file_group_proto_msgTypes[7]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ExcitingHostInfo) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ExcitingHostInfo) ProtoMessage() {}
func (x *ExcitingHostInfo) ProtoReflect() protoreflect.Message {
mi := &file_group_proto_msgTypes[7]
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 ExcitingHostInfo.ProtoReflect.Descriptor instead.
func (*ExcitingHostInfo) Descriptor() ([]byte, []int) {
return file_group_proto_rawDescGZIP(), []int{7}
}
func (x *ExcitingHostInfo) GetUrl() *ExcitingUrlInfo {
if x != nil {
return x.Url
}
return nil
}
func (x *ExcitingHostInfo) GetPort() int32 {
if x != nil && x.Port != nil {
return *x.Port
}
return 0
} }
type ExcitingUrlInfo struct { type ExcitingUrlInfo struct {
Unknown proto.Option[int32] `protobuf:"varint,1,opt"` // not https? state protoimpl.MessageState
Host proto.Option[string] `protobuf:"bytes,2,opt"` sizeCache protoimpl.SizeCache
_ [0]func() unknownFields protoimpl.UnknownFields
Unknown *int32 `protobuf:"varint,1,opt,name=unknown" json:"unknown,omitempty"` // not https?
Host *string `protobuf:"bytes,2,opt,name=host" json:"host,omitempty"`
}
func (x *ExcitingUrlInfo) Reset() {
*x = ExcitingUrlInfo{}
if protoimpl.UnsafeEnabled {
mi := &file_group_proto_msgTypes[8]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ExcitingUrlInfo) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ExcitingUrlInfo) ProtoMessage() {}
func (x *ExcitingUrlInfo) ProtoReflect() protoreflect.Message {
mi := &file_group_proto_msgTypes[8]
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 ExcitingUrlInfo.ProtoReflect.Descriptor instead.
func (*ExcitingUrlInfo) Descriptor() ([]byte, []int) {
return file_group_proto_rawDescGZIP(), []int{8}
}
func (x *ExcitingUrlInfo) GetUnknown() int32 {
if x != nil && x.Unknown != nil {
return *x.Unknown
}
return 0
}
func (x *ExcitingUrlInfo) GetHost() string {
if x != nil && x.Host != nil {
return *x.Host
}
return ""
}
var File_group_proto protoreflect.FileDescriptor
var file_group_proto_rawDesc = []byte{
0x0a, 0x0b, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x95, 0x01,
0x0a, 0x12, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x46, 0x69, 0x6c, 0x65, 0x55, 0x70, 0x6c, 0x6f, 0x61,
0x64, 0x45, 0x78, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x31,
0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x75, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x31,
0x12, 0x1a, 0x0a, 0x08, 0x75, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x32, 0x18, 0x02, 0x20, 0x01,
0x28, 0x05, 0x52, 0x08, 0x75, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x32, 0x12, 0x2b, 0x0a, 0x05,
0x65, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x64, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x47, 0x72,
0x6f, 0x75, 0x70, 0x46, 0x69, 0x6c, 0x65, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x45, 0x6e, 0x74,
0x72, 0x79, 0x52, 0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x6e, 0x6b,
0x6e, 0x6f, 0x77, 0x6e, 0x33, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x75, 0x6e, 0x6b,
0x6e, 0x6f, 0x77, 0x6e, 0x33, 0x22, 0x94, 0x02, 0x0a, 0x14, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x46,
0x69, 0x6c, 0x65, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x2d,
0x0a, 0x08, 0x62, 0x75, 0x73, 0x69, 0x42, 0x75, 0x66, 0x66, 0x18, 0x64, 0x20, 0x01, 0x28, 0x0b,
0x32, 0x11, 0x2e, 0x45, 0x78, 0x63, 0x69, 0x74, 0x69, 0x6e, 0x67, 0x42, 0x75, 0x73, 0x69, 0x49,
0x6e, 0x66, 0x6f, 0x52, 0x08, 0x62, 0x75, 0x73, 0x69, 0x42, 0x75, 0x66, 0x66, 0x12, 0x31, 0x0a,
0x09, 0x66, 0x69, 0x6c, 0x65, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x18, 0xc8, 0x01, 0x20, 0x01, 0x28,
0x0b, 0x32, 0x12, 0x2e, 0x45, 0x78, 0x63, 0x69, 0x74, 0x69, 0x6e, 0x67, 0x46, 0x69, 0x6c, 0x65,
0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, 0x66, 0x69, 0x6c, 0x65, 0x45, 0x6e, 0x74, 0x72, 0x79,
0x12, 0x34, 0x0a, 0x0a, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x18, 0xac,
0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x45, 0x78, 0x63, 0x69, 0x74, 0x69, 0x6e, 0x67,
0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0a, 0x63, 0x6c, 0x69, 0x65,
0x6e, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x3a, 0x0a, 0x0c, 0x66, 0x69, 0x6c, 0x65, 0x4e, 0x61,
0x6d, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x18, 0x90, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e,
0x45, 0x78, 0x63, 0x69, 0x74, 0x69, 0x6e, 0x67, 0x46, 0x69, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65,
0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0c, 0x66, 0x69, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x49, 0x6e,
0x66, 0x6f, 0x12, 0x28, 0x0a, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x18, 0xf4, 0x03, 0x20, 0x01, 0x28,
0x0b, 0x32, 0x13, 0x2e, 0x45, 0x78, 0x63, 0x69, 0x74, 0x69, 0x6e, 0x67, 0x48, 0x6f, 0x73, 0x74,
0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x22, 0x88, 0x01, 0x0a,
0x10, 0x45, 0x78, 0x63, 0x69, 0x74, 0x69, 0x6e, 0x67, 0x42, 0x75, 0x73, 0x69, 0x49, 0x6e, 0x66,
0x6f, 0x12, 0x14, 0x0a, 0x05, 0x62, 0x75, 0x73, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05,
0x52, 0x05, 0x62, 0x75, 0x73, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x65, 0x6e, 0x64, 0x65,
0x72, 0x55, 0x69, 0x6e, 0x18, 0x64, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x73, 0x65, 0x6e, 0x64,
0x65, 0x72, 0x55, 0x69, 0x6e, 0x12, 0x21, 0x0a, 0x0b, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65,
0x72, 0x55, 0x69, 0x6e, 0x18, 0xc8, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x72, 0x65, 0x63,
0x65, 0x69, 0x76, 0x65, 0x72, 0x55, 0x69, 0x6e, 0x12, 0x1d, 0x0a, 0x09, 0x67, 0x72, 0x6f, 0x75,
0x70, 0x43, 0x6f, 0x64, 0x65, 0x18, 0x90, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x67, 0x72,
0x6f, 0x75, 0x70, 0x43, 0x6f, 0x64, 0x65, 0x22, 0x8f, 0x01, 0x0a, 0x11, 0x45, 0x78, 0x63, 0x69,
0x74, 0x69, 0x6e, 0x67, 0x46, 0x69, 0x6c, 0x65, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x1a, 0x0a,
0x08, 0x66, 0x69, 0x6c, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x18, 0x64, 0x20, 0x01, 0x28, 0x03, 0x52,
0x08, 0x66, 0x69, 0x6c, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x11, 0x0a, 0x03, 0x6d, 0x64, 0x35,
0x18, 0xc8, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x6d, 0x64, 0x35, 0x12, 0x13, 0x0a, 0x04,
0x73, 0x68, 0x61, 0x31, 0x18, 0xac, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x73, 0x68, 0x61,
0x31, 0x12, 0x17, 0x0a, 0x06, 0x66, 0x69, 0x6c, 0x65, 0x49, 0x64, 0x18, 0xd8, 0x04, 0x20, 0x01,
0x28, 0x0c, 0x52, 0x06, 0x66, 0x69, 0x6c, 0x65, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x09, 0x75, 0x70,
0x6c, 0x6f, 0x61, 0x64, 0x4b, 0x65, 0x79, 0x18, 0xbc, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09,
0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x4b, 0x65, 0x79, 0x22, 0xaa, 0x01, 0x0a, 0x12, 0x45, 0x78,
0x63, 0x69, 0x74, 0x69, 0x6e, 0x67, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x66, 0x6f,
0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x18, 0x64,
0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65,
0x12, 0x15, 0x0a, 0x05, 0x61, 0x70, 0x70, 0x49, 0x64, 0x18, 0xc8, 0x01, 0x20, 0x01, 0x28, 0x09,
0x52, 0x05, 0x61, 0x70, 0x70, 0x49, 0x64, 0x12, 0x23, 0x0a, 0x0c, 0x74, 0x65, 0x72, 0x6d, 0x69,
0x6e, 0x61, 0x6c, 0x54, 0x79, 0x70, 0x65, 0x18, 0xac, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c,
0x74, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1d, 0x0a, 0x09,
0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x56, 0x65, 0x72, 0x18, 0x90, 0x03, 0x20, 0x01, 0x28, 0x09,
0x52, 0x09, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x56, 0x65, 0x72, 0x12, 0x19, 0x0a, 0x07, 0x75,
0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x18, 0xd8, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x75,
0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x22, 0x32, 0x0a, 0x14, 0x45, 0x78, 0x63, 0x69, 0x74, 0x69,
0x6e, 0x67, 0x46, 0x69, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1a,
0x0a, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x64, 0x20, 0x01, 0x28, 0x09,
0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x3e, 0x0a, 0x12, 0x45, 0x78,
0x63, 0x69, 0x74, 0x69, 0x6e, 0x67, 0x48, 0x6f, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
0x12, 0x28, 0x0a, 0x05, 0x68, 0x6f, 0x73, 0x74, 0x73, 0x18, 0xc8, 0x01, 0x20, 0x03, 0x28, 0x0b,
0x32, 0x11, 0x2e, 0x45, 0x78, 0x63, 0x69, 0x74, 0x69, 0x6e, 0x67, 0x48, 0x6f, 0x73, 0x74, 0x49,
0x6e, 0x66, 0x6f, 0x52, 0x05, 0x68, 0x6f, 0x73, 0x74, 0x73, 0x22, 0x4a, 0x0a, 0x10, 0x45, 0x78,
0x63, 0x69, 0x74, 0x69, 0x6e, 0x67, 0x48, 0x6f, 0x73, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x22,
0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x45, 0x78,
0x63, 0x69, 0x74, 0x69, 0x6e, 0x67, 0x55, 0x72, 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x03, 0x75,
0x72, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05,
0x52, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x22, 0x3f, 0x0a, 0x0f, 0x45, 0x78, 0x63, 0x69, 0x74, 0x69,
0x6e, 0x67, 0x55, 0x72, 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x18, 0x0a, 0x07, 0x75, 0x6e, 0x6b,
0x6e, 0x6f, 0x77, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x75, 0x6e, 0x6b, 0x6e,
0x6f, 0x77, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28,
0x09, 0x52, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x42, 0x0d, 0x5a, 0x0b, 0x2e, 0x2f, 0x3b, 0x65, 0x78,
0x63, 0x69, 0x74, 0x69, 0x6e, 0x67,
}
var (
file_group_proto_rawDescOnce sync.Once
file_group_proto_rawDescData = file_group_proto_rawDesc
)
func file_group_proto_rawDescGZIP() []byte {
file_group_proto_rawDescOnce.Do(func() {
file_group_proto_rawDescData = protoimpl.X.CompressGZIP(file_group_proto_rawDescData)
})
return file_group_proto_rawDescData
}
var file_group_proto_msgTypes = make([]protoimpl.MessageInfo, 9)
var file_group_proto_goTypes = []interface{}{
(*GroupFileUploadExt)(nil), // 0: GroupFileUploadExt
(*GroupFileUploadEntry)(nil), // 1: GroupFileUploadEntry
(*ExcitingBusiInfo)(nil), // 2: ExcitingBusiInfo
(*ExcitingFileEntry)(nil), // 3: ExcitingFileEntry
(*ExcitingClientInfo)(nil), // 4: ExcitingClientInfo
(*ExcitingFileNameInfo)(nil), // 5: ExcitingFileNameInfo
(*ExcitingHostConfig)(nil), // 6: ExcitingHostConfig
(*ExcitingHostInfo)(nil), // 7: ExcitingHostInfo
(*ExcitingUrlInfo)(nil), // 8: ExcitingUrlInfo
}
var file_group_proto_depIdxs = []int32{
1, // 0: GroupFileUploadExt.entry:type_name -> GroupFileUploadEntry
2, // 1: GroupFileUploadEntry.busiBuff:type_name -> ExcitingBusiInfo
3, // 2: GroupFileUploadEntry.fileEntry:type_name -> ExcitingFileEntry
4, // 3: GroupFileUploadEntry.clientInfo:type_name -> ExcitingClientInfo
5, // 4: GroupFileUploadEntry.fileNameInfo:type_name -> ExcitingFileNameInfo
6, // 5: GroupFileUploadEntry.host:type_name -> ExcitingHostConfig
7, // 6: ExcitingHostConfig.hosts:type_name -> ExcitingHostInfo
8, // 7: ExcitingHostInfo.url:type_name -> ExcitingUrlInfo
8, // [8:8] is the sub-list for method output_type
8, // [8:8] is the sub-list for method input_type
8, // [8:8] is the sub-list for extension type_name
8, // [8:8] is the sub-list for extension extendee
0, // [0:8] is the sub-list for field type_name
}
func init() { file_group_proto_init() }
func file_group_proto_init() {
if File_group_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_group_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*GroupFileUploadExt); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_group_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*GroupFileUploadEntry); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_group_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ExcitingBusiInfo); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_group_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ExcitingFileEntry); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_group_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ExcitingClientInfo); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_group_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ExcitingFileNameInfo); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_group_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ExcitingHostConfig); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_group_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ExcitingHostInfo); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_group_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ExcitingUrlInfo); 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_group_proto_rawDesc,
NumEnums: 0,
NumMessages: 9,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_group_proto_goTypes,
DependencyIndexes: file_group_proto_depIdxs,
MessageInfos: file_group_proto_msgTypes,
}.Build()
File_group_proto = out.File
file_group_proto_rawDesc = nil
file_group_proto_goTypes = nil
file_group_proto_depIdxs = nil
} }

View File

@ -1,16 +1,15 @@
syntax = "proto2"; syntax = "proto2";
option go_package = "github.com/Mrs4s/MiraiGo/client/pb/exciting"; option go_package = "./;exciting";
message FileUploadExt { message GroupFileUploadExt {
optional int32 unknown1 = 1; optional int32 unknown1 = 1;
optional int32 unknown2 = 2; optional int32 unknown2 = 2;
optional GroupFileUploadEntry entry = 100;
optional int32 unknown3 = 3; optional int32 unknown3 = 3;
optional FileUploadEntry entry = 100;
optional int32 unknown200 = 200;
} }
message FileUploadEntry { message GroupFileUploadEntry {
optional ExcitingBusiInfo busiBuff = 100; optional ExcitingBusiInfo busiBuff = 100;
optional ExcitingFileEntry fileEntry = 200; optional ExcitingFileEntry fileEntry = 200;
optional ExcitingClientInfo clientInfo = 300; optional ExcitingClientInfo clientInfo = 300;

View File

@ -1,54 +1,662 @@
// Code generated by protoc-gen-golite. DO NOT EDIT. // Code generated by protoc-gen-go. DO NOT EDIT.
// source: pb/faceroam/faceroam.proto // versions:
// protoc-gen-go v1.26.0
// protoc v3.17.1
// source: faceroam.proto
package faceroam package faceroam
import ( import (
proto "github.com/RomiChan/protobuf/proto" reflect "reflect"
sync "sync"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
)
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 PlatInfo struct { type PlatInfo struct {
Implat proto.Option[int64] `protobuf:"varint,1,opt"` state protoimpl.MessageState
Osver proto.Option[string] `protobuf:"bytes,2,opt"` sizeCache protoimpl.SizeCache
Mqqver proto.Option[string] `protobuf:"bytes,3,opt"` unknownFields protoimpl.UnknownFields
_ [0]func()
Implat *int64 `protobuf:"varint,1,opt,name=implat" json:"implat,omitempty"`
Osver *string `protobuf:"bytes,2,opt,name=osver" json:"osver,omitempty"`
Mqqver *string `protobuf:"bytes,3,opt,name=mqqver" json:"mqqver,omitempty"`
}
func (x *PlatInfo) Reset() {
*x = PlatInfo{}
if protoimpl.UnsafeEnabled {
mi := &file_faceroam_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *PlatInfo) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*PlatInfo) ProtoMessage() {}
func (x *PlatInfo) ProtoReflect() protoreflect.Message {
mi := &file_faceroam_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 PlatInfo.ProtoReflect.Descriptor instead.
func (*PlatInfo) Descriptor() ([]byte, []int) {
return file_faceroam_proto_rawDescGZIP(), []int{0}
}
func (x *PlatInfo) GetImplat() int64 {
if x != nil && x.Implat != nil {
return *x.Implat
}
return 0
}
func (x *PlatInfo) GetOsver() string {
if x != nil && x.Osver != nil {
return *x.Osver
}
return ""
}
func (x *PlatInfo) GetMqqver() string {
if x != nil && x.Mqqver != nil {
return *x.Mqqver
}
return ""
} }
type FaceroamReqBody struct { type FaceroamReqBody struct {
Comm *PlatInfo `protobuf:"bytes,1,opt"` state protoimpl.MessageState
Uin proto.Option[uint64] `protobuf:"varint,2,opt"` sizeCache protoimpl.SizeCache
SubCmd proto.Option[uint32] `protobuf:"varint,3,opt"` unknownFields protoimpl.UnknownFields
ReqUserInfo *ReqUserInfo `protobuf:"bytes,4,opt"`
ReqDeleteItem *ReqDeleteItem `protobuf:"bytes,5,opt"` Comm *PlatInfo `protobuf:"bytes,1,opt,name=comm" json:"comm,omitempty"`
_ [0]func() Uin *uint64 `protobuf:"varint,2,opt,name=uin" json:"uin,omitempty"`
SubCmd *uint32 `protobuf:"varint,3,opt,name=subCmd" json:"subCmd,omitempty"`
ReqUserInfo *ReqUserInfo `protobuf:"bytes,4,opt,name=reqUserInfo" json:"reqUserInfo,omitempty"`
ReqDeleteItem *ReqDeleteItem `protobuf:"bytes,5,opt,name=reqDeleteItem" json:"reqDeleteItem,omitempty"`
}
func (x *FaceroamReqBody) Reset() {
*x = FaceroamReqBody{}
if protoimpl.UnsafeEnabled {
mi := &file_faceroam_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *FaceroamReqBody) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*FaceroamReqBody) ProtoMessage() {}
func (x *FaceroamReqBody) ProtoReflect() protoreflect.Message {
mi := &file_faceroam_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 FaceroamReqBody.ProtoReflect.Descriptor instead.
func (*FaceroamReqBody) Descriptor() ([]byte, []int) {
return file_faceroam_proto_rawDescGZIP(), []int{1}
}
func (x *FaceroamReqBody) GetComm() *PlatInfo {
if x != nil {
return x.Comm
}
return nil
}
func (x *FaceroamReqBody) GetUin() uint64 {
if x != nil && x.Uin != nil {
return *x.Uin
}
return 0
}
func (x *FaceroamReqBody) GetSubCmd() uint32 {
if x != nil && x.SubCmd != nil {
return *x.SubCmd
}
return 0
}
func (x *FaceroamReqBody) GetReqUserInfo() *ReqUserInfo {
if x != nil {
return x.ReqUserInfo
}
return nil
}
func (x *FaceroamReqBody) GetReqDeleteItem() *ReqDeleteItem {
if x != nil {
return x.ReqDeleteItem
}
return nil
} }
type ReqDeleteItem struct { type ReqDeleteItem struct {
Filename []string `protobuf:"bytes,1,rep"` state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Filename []string `protobuf:"bytes,1,rep,name=filename" json:"filename,omitempty"`
}
func (x *ReqDeleteItem) Reset() {
*x = ReqDeleteItem{}
if protoimpl.UnsafeEnabled {
mi := &file_faceroam_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ReqDeleteItem) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ReqDeleteItem) ProtoMessage() {}
func (x *ReqDeleteItem) ProtoReflect() protoreflect.Message {
mi := &file_faceroam_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 ReqDeleteItem.ProtoReflect.Descriptor instead.
func (*ReqDeleteItem) Descriptor() ([]byte, []int) {
return file_faceroam_proto_rawDescGZIP(), []int{2}
}
func (x *ReqDeleteItem) GetFilename() []string {
if x != nil {
return x.Filename
}
return nil
} }
type ReqUserInfo struct { type ReqUserInfo struct {
_ [0]func() state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *ReqUserInfo) Reset() {
*x = ReqUserInfo{}
if protoimpl.UnsafeEnabled {
mi := &file_faceroam_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ReqUserInfo) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ReqUserInfo) ProtoMessage() {}
func (x *ReqUserInfo) ProtoReflect() protoreflect.Message {
mi := &file_faceroam_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 ReqUserInfo.ProtoReflect.Descriptor instead.
func (*ReqUserInfo) Descriptor() ([]byte, []int) {
return file_faceroam_proto_rawDescGZIP(), []int{3}
} }
type FaceroamRspBody struct { type FaceroamRspBody struct {
Ret proto.Option[int64] `protobuf:"varint,1,opt"` state protoimpl.MessageState
Errmsg proto.Option[string] `protobuf:"bytes,2,opt"` sizeCache protoimpl.SizeCache
SubCmd proto.Option[uint32] `protobuf:"varint,3,opt"` unknownFields protoimpl.UnknownFields
RspUserInfo *RspUserInfo `protobuf:"bytes,4,opt"`
RspDeleteItem *RspDeleteItem `protobuf:"bytes,5,opt"` Ret *int64 `protobuf:"varint,1,opt,name=ret" json:"ret,omitempty"`
_ [0]func() Errmsg *string `protobuf:"bytes,2,opt,name=errmsg" json:"errmsg,omitempty"`
SubCmd *uint32 `protobuf:"varint,3,opt,name=subCmd" json:"subCmd,omitempty"`
RspUserInfo *RspUserInfo `protobuf:"bytes,4,opt,name=rspUserInfo" json:"rspUserInfo,omitempty"`
RspDeleteItem *RspDeleteItem `protobuf:"bytes,5,opt,name=rspDeleteItem" json:"rspDeleteItem,omitempty"`
}
func (x *FaceroamRspBody) Reset() {
*x = FaceroamRspBody{}
if protoimpl.UnsafeEnabled {
mi := &file_faceroam_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *FaceroamRspBody) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*FaceroamRspBody) ProtoMessage() {}
func (x *FaceroamRspBody) ProtoReflect() protoreflect.Message {
mi := &file_faceroam_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 FaceroamRspBody.ProtoReflect.Descriptor instead.
func (*FaceroamRspBody) Descriptor() ([]byte, []int) {
return file_faceroam_proto_rawDescGZIP(), []int{4}
}
func (x *FaceroamRspBody) GetRet() int64 {
if x != nil && x.Ret != nil {
return *x.Ret
}
return 0
}
func (x *FaceroamRspBody) GetErrmsg() string {
if x != nil && x.Errmsg != nil {
return *x.Errmsg
}
return ""
}
func (x *FaceroamRspBody) GetSubCmd() uint32 {
if x != nil && x.SubCmd != nil {
return *x.SubCmd
}
return 0
}
func (x *FaceroamRspBody) GetRspUserInfo() *RspUserInfo {
if x != nil {
return x.RspUserInfo
}
return nil
}
func (x *FaceroamRspBody) GetRspDeleteItem() *RspDeleteItem {
if x != nil {
return x.RspDeleteItem
}
return nil
} }
type RspDeleteItem struct { type RspDeleteItem struct {
Filename []string `protobuf:"bytes,1,rep"` state protoimpl.MessageState
Ret []int64 `protobuf:"varint,2,rep"` sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Filename []string `protobuf:"bytes,1,rep,name=filename" json:"filename,omitempty"`
Ret []int64 `protobuf:"varint,2,rep,name=ret" json:"ret,omitempty"`
}
func (x *RspDeleteItem) Reset() {
*x = RspDeleteItem{}
if protoimpl.UnsafeEnabled {
mi := &file_faceroam_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *RspDeleteItem) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*RspDeleteItem) ProtoMessage() {}
func (x *RspDeleteItem) ProtoReflect() protoreflect.Message {
mi := &file_faceroam_proto_msgTypes[5]
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 RspDeleteItem.ProtoReflect.Descriptor instead.
func (*RspDeleteItem) Descriptor() ([]byte, []int) {
return file_faceroam_proto_rawDescGZIP(), []int{5}
}
func (x *RspDeleteItem) GetFilename() []string {
if x != nil {
return x.Filename
}
return nil
}
func (x *RspDeleteItem) GetRet() []int64 {
if x != nil {
return x.Ret
}
return nil
} }
type RspUserInfo struct { type RspUserInfo struct {
Filename []string `protobuf:"bytes,1,rep"` state protoimpl.MessageState
DeleteFile []string `protobuf:"bytes,2,rep"` sizeCache protoimpl.SizeCache
Bid proto.Option[string] `protobuf:"bytes,3,opt"` unknownFields protoimpl.UnknownFields
MaxRoamSize proto.Option[uint32] `protobuf:"varint,4,opt"`
EmojiType []uint32 `protobuf:"varint,5,rep"` Filename []string `protobuf:"bytes,1,rep,name=filename" json:"filename,omitempty"`
DeleteFile []string `protobuf:"bytes,2,rep,name=deleteFile" json:"deleteFile,omitempty"`
Bid *string `protobuf:"bytes,3,opt,name=bid" json:"bid,omitempty"`
MaxRoamSize *uint32 `protobuf:"varint,4,opt,name=maxRoamSize" json:"maxRoamSize,omitempty"`
EmojiType []uint32 `protobuf:"varint,5,rep,name=emojiType" json:"emojiType,omitempty"`
}
func (x *RspUserInfo) Reset() {
*x = RspUserInfo{}
if protoimpl.UnsafeEnabled {
mi := &file_faceroam_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *RspUserInfo) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*RspUserInfo) ProtoMessage() {}
func (x *RspUserInfo) ProtoReflect() protoreflect.Message {
mi := &file_faceroam_proto_msgTypes[6]
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 RspUserInfo.ProtoReflect.Descriptor instead.
func (*RspUserInfo) Descriptor() ([]byte, []int) {
return file_faceroam_proto_rawDescGZIP(), []int{6}
}
func (x *RspUserInfo) GetFilename() []string {
if x != nil {
return x.Filename
}
return nil
}
func (x *RspUserInfo) GetDeleteFile() []string {
if x != nil {
return x.DeleteFile
}
return nil
}
func (x *RspUserInfo) GetBid() string {
if x != nil && x.Bid != nil {
return *x.Bid
}
return ""
}
func (x *RspUserInfo) GetMaxRoamSize() uint32 {
if x != nil && x.MaxRoamSize != nil {
return *x.MaxRoamSize
}
return 0
}
func (x *RspUserInfo) GetEmojiType() []uint32 {
if x != nil {
return x.EmojiType
}
return nil
}
var File_faceroam_proto protoreflect.FileDescriptor
var file_faceroam_proto_rawDesc = []byte{
0x0a, 0x0e, 0x66, 0x61, 0x63, 0x65, 0x72, 0x6f, 0x61, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x22, 0x50, 0x0a, 0x08, 0x50, 0x6c, 0x61, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x16, 0x0a, 0x06,
0x69, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x69, 0x6d,
0x70, 0x6c, 0x61, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x6f, 0x73, 0x76, 0x65, 0x72, 0x18, 0x02, 0x20,
0x01, 0x28, 0x09, 0x52, 0x05, 0x6f, 0x73, 0x76, 0x65, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x6d, 0x71,
0x71, 0x76, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6d, 0x71, 0x71, 0x76,
0x65, 0x72, 0x22, 0xc0, 0x01, 0x0a, 0x0f, 0x46, 0x61, 0x63, 0x65, 0x72, 0x6f, 0x61, 0x6d, 0x52,
0x65, 0x71, 0x42, 0x6f, 0x64, 0x79, 0x12, 0x1d, 0x0a, 0x04, 0x63, 0x6f, 0x6d, 0x6d, 0x18, 0x01,
0x20, 0x01, 0x28, 0x0b, 0x32, 0x09, 0x2e, 0x50, 0x6c, 0x61, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52,
0x04, 0x63, 0x6f, 0x6d, 0x6d, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x01,
0x28, 0x04, 0x52, 0x03, 0x75, 0x69, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x75, 0x62, 0x43, 0x6d,
0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x73, 0x75, 0x62, 0x43, 0x6d, 0x64, 0x12,
0x2e, 0x0a, 0x0b, 0x72, 0x65, 0x71, 0x55, 0x73, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x18, 0x04,
0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x52, 0x65, 0x71, 0x55, 0x73, 0x65, 0x72, 0x49, 0x6e,
0x66, 0x6f, 0x52, 0x0b, 0x72, 0x65, 0x71, 0x55, 0x73, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x12,
0x34, 0x0a, 0x0d, 0x72, 0x65, 0x71, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x49, 0x74, 0x65, 0x6d,
0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x52, 0x65, 0x71, 0x44, 0x65, 0x6c, 0x65,
0x74, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x0d, 0x72, 0x65, 0x71, 0x44, 0x65, 0x6c, 0x65, 0x74,
0x65, 0x49, 0x74, 0x65, 0x6d, 0x22, 0x2b, 0x0a, 0x0d, 0x52, 0x65, 0x71, 0x44, 0x65, 0x6c, 0x65,
0x74, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61,
0x6d, 0x65, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61,
0x6d, 0x65, 0x22, 0x0d, 0x0a, 0x0b, 0x52, 0x65, 0x71, 0x55, 0x73, 0x65, 0x72, 0x49, 0x6e, 0x66,
0x6f, 0x22, 0xb9, 0x01, 0x0a, 0x0f, 0x46, 0x61, 0x63, 0x65, 0x72, 0x6f, 0x61, 0x6d, 0x52, 0x73,
0x70, 0x42, 0x6f, 0x64, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x72, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01,
0x28, 0x03, 0x52, 0x03, 0x72, 0x65, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x65, 0x72, 0x72, 0x6d, 0x73,
0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x65, 0x72, 0x72, 0x6d, 0x73, 0x67, 0x12,
0x16, 0x0a, 0x06, 0x73, 0x75, 0x62, 0x43, 0x6d, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52,
0x06, 0x73, 0x75, 0x62, 0x43, 0x6d, 0x64, 0x12, 0x2e, 0x0a, 0x0b, 0x72, 0x73, 0x70, 0x55, 0x73,
0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x52,
0x73, 0x70, 0x55, 0x73, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0b, 0x72, 0x73, 0x70, 0x55,
0x73, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x34, 0x0a, 0x0d, 0x72, 0x73, 0x70, 0x44, 0x65,
0x6c, 0x65, 0x74, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e,
0x2e, 0x52, 0x73, 0x70, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x0d,
0x72, 0x73, 0x70, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x22, 0x3d, 0x0a,
0x0d, 0x52, 0x73, 0x70, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x12, 0x1a,
0x0a, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09,
0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x72, 0x65,
0x74, 0x18, 0x02, 0x20, 0x03, 0x28, 0x03, 0x52, 0x03, 0x72, 0x65, 0x74, 0x22, 0x9b, 0x01, 0x0a,
0x0b, 0x52, 0x73, 0x70, 0x55, 0x73, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1a, 0x0a, 0x08,
0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08,
0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x64, 0x65, 0x6c, 0x65,
0x74, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x64, 0x65,
0x6c, 0x65, 0x74, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x62, 0x69, 0x64, 0x18,
0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x62, 0x69, 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x6d, 0x61,
0x78, 0x52, 0x6f, 0x61, 0x6d, 0x53, 0x69, 0x7a, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52,
0x0b, 0x6d, 0x61, 0x78, 0x52, 0x6f, 0x61, 0x6d, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x1c, 0x0a, 0x09,
0x65, 0x6d, 0x6f, 0x6a, 0x69, 0x54, 0x79, 0x70, 0x65, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0d, 0x52,
0x09, 0x65, 0x6d, 0x6f, 0x6a, 0x69, 0x54, 0x79, 0x70, 0x65, 0x42, 0x0d, 0x5a, 0x0b, 0x2e, 0x2f,
0x3b, 0x66, 0x61, 0x63, 0x65, 0x72, 0x6f, 0x61, 0x6d,
}
var (
file_faceroam_proto_rawDescOnce sync.Once
file_faceroam_proto_rawDescData = file_faceroam_proto_rawDesc
)
func file_faceroam_proto_rawDescGZIP() []byte {
file_faceroam_proto_rawDescOnce.Do(func() {
file_faceroam_proto_rawDescData = protoimpl.X.CompressGZIP(file_faceroam_proto_rawDescData)
})
return file_faceroam_proto_rawDescData
}
var file_faceroam_proto_msgTypes = make([]protoimpl.MessageInfo, 7)
var file_faceroam_proto_goTypes = []interface{}{
(*PlatInfo)(nil), // 0: PlatInfo
(*FaceroamReqBody)(nil), // 1: FaceroamReqBody
(*ReqDeleteItem)(nil), // 2: ReqDeleteItem
(*ReqUserInfo)(nil), // 3: ReqUserInfo
(*FaceroamRspBody)(nil), // 4: FaceroamRspBody
(*RspDeleteItem)(nil), // 5: RspDeleteItem
(*RspUserInfo)(nil), // 6: RspUserInfo
}
var file_faceroam_proto_depIdxs = []int32{
0, // 0: FaceroamReqBody.comm:type_name -> PlatInfo
3, // 1: FaceroamReqBody.reqUserInfo:type_name -> ReqUserInfo
2, // 2: FaceroamReqBody.reqDeleteItem:type_name -> ReqDeleteItem
6, // 3: FaceroamRspBody.rspUserInfo:type_name -> RspUserInfo
5, // 4: FaceroamRspBody.rspDeleteItem:type_name -> RspDeleteItem
5, // [5:5] is the sub-list for method output_type
5, // [5:5] is the sub-list for method input_type
5, // [5:5] is the sub-list for extension type_name
5, // [5:5] is the sub-list for extension extendee
0, // [0:5] is the sub-list for field type_name
}
func init() { file_faceroam_proto_init() }
func file_faceroam_proto_init() {
if File_faceroam_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_faceroam_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*PlatInfo); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_faceroam_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*FaceroamReqBody); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_faceroam_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ReqDeleteItem); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_faceroam_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ReqUserInfo); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_faceroam_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*FaceroamRspBody); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_faceroam_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*RspDeleteItem); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_faceroam_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*RspUserInfo); 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_faceroam_proto_rawDesc,
NumEnums: 0,
NumMessages: 7,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_faceroam_proto_goTypes,
DependencyIndexes: file_faceroam_proto_depIdxs,
MessageInfos: file_faceroam_proto_msgTypes,
}.Build()
File_faceroam_proto = out.File
file_faceroam_proto_rawDesc = nil
file_faceroam_proto_goTypes = nil
file_faceroam_proto_depIdxs = nil
} }

View File

@ -1,6 +1,6 @@
syntax = "proto2"; syntax = "proto2";
option go_package = "github.com/Mrs4s/MiraiGo/client/pb/faceroam"; option go_package = "./;faceroam";
message PlatInfo { message PlatInfo {
optional int64 implat = 1; optional int64 implat = 1;

Some files were not shown because too many files have changed in this diff Show More