1
0
mirror of https://github.com/Mrs4s/MiraiGo.git synced 2025-05-04 19:17:38 +08:00

zap: reuse some []byte

优化单线程上传内存使用
This commit is contained in:
wdvxdr 2021-04-15 21:31:44 +08:00
parent 86e0f3327a
commit 2e64a6913d
No known key found for this signature in database
GPG Key ID: 55FF1414A69CEBA6
31 changed files with 360 additions and 248 deletions

View File

@ -1,7 +1,7 @@
package jce package jce
type IJceStruct interface { type IJceStruct interface {
//ToBytes() []byte // ToBytes() []byte
ReadFrom(*JceReader) ReadFrom(*JceReader)
} }
@ -42,8 +42,8 @@ type (
BigDataChannel *BigDataChannel `jceId:"5"` BigDataChannel *BigDataChannel `jceId:"5"`
VipEmotionList []FileStorageServerInfo `jceId:"6"` VipEmotionList []FileStorageServerInfo `jceId:"6"`
C2CPicDownList []FileStorageServerInfo `jceId:"7"` C2CPicDownList []FileStorageServerInfo `jceId:"7"`
//FmtIPInfo *FmtIPInfo `jceId:"8"` // FmtIPInfo *FmtIPInfo `jceId:"8"`
//DomainIPChannel *DomainIPChannel `jceId:"9"` // DomainIPChannel *DomainIPChannel `jceId:"9"`
PttList []byte `jceId:"10"` PttList []byte `jceId:"10"`
} }
@ -496,8 +496,8 @@ type (
IsFriend byte `jceId:"3"` IsFriend byte `jceId:"3"`
GroupCode int64 `jceId:"4"` GroupCode int64 `jceId:"4"`
GroupUin int64 `jceId:"5"` GroupUin int64 `jceId:"5"`
//Seed []byte`jceId:"6"` // Seed []byte`jceId:"6"`
//SearchName string`jceId:"7"` // SearchName string`jceId:"7"`
GetControl int64 `jceId:"8"` GetControl int64 `jceId:"8"`
AddFriendSource int32 `jceId:"9"` AddFriendSource int32 `jceId:"9"`
SecureSig []byte `jceId:"10"` SecureSig []byte `jceId:"10"`

View File

@ -243,7 +243,7 @@ func (w *JceWriter) WriteJceStructRaw(s IJceStruct) {
decoderCache.Store(ty2, jceDec) // 存入缓存 decoderCache.Store(ty2, jceDec) // 存入缓存
} }
for _, dec := range jceDec { for _, dec := range jceDec {
var obj = dec.ty.UnsafeIndirect(unsafe.Pointer(uintptr(reflect2.PtrOf(s)) + dec.offset)) // MAGIC! obj := dec.ty.UnsafeIndirect(unsafe.Pointer(uintptr(reflect2.PtrOf(s)) + dec.offset)) // MAGIC!
if obj != nil { if obj != nil {
w.WriteObject(obj, dec.id) w.WriteObject(obj, dec.id)
} }

97
binary/pool.go Normal file
View File

@ -0,0 +1,97 @@
package binary
import (
"bytes"
"compress/gzip"
"compress/zlib"
"sync"
)
var bufferPool = sync.Pool{
New: func() interface{} {
return new(Writer)
},
}
// NewWriter 从池中取出一个 Writer
func NewWriter() *Writer {
w := bufferPool.Get().(*Writer)
if w == nil {
return new(Writer)
}
return w
}
// PutBuffer 将 Writer 放回池中
func PutBuffer(w *Writer) {
// See https://golang.org/issue/23199
const maxSize = 1 << 16
if w.Cap() < maxSize { // 对于大Buffer直接丢弃
w.Reset()
bufferPool.Put(w)
}
}
type gzipWriter struct {
w *gzip.Writer
buf *bytes.Buffer
}
var gzipPool = sync.Pool{
New: func() interface{} {
buf := new(bytes.Buffer)
w := gzip.NewWriter(buf)
return &gzipWriter{
w: w,
buf: buf,
}
},
}
func acquireGzipWriter() *gzipWriter {
ret := gzipPool.Get().(*gzipWriter)
ret.buf.Reset()
ret.w.Reset(ret.buf)
return ret
}
func releaseGzipWriter(w *gzipWriter) {
// See https://golang.org/issue/23199
const maxSize = 1 << 16
if w.buf.Cap() < maxSize {
w.buf.Reset()
gzipPool.Put(w)
}
}
type zlibWriter struct {
w *zlib.Writer
buf *bytes.Buffer
}
var zlibPool = sync.Pool{
New: func() interface{} {
buf := new(bytes.Buffer)
w := zlib.NewWriter(buf)
return &zlibWriter{
w: w,
buf: buf,
}
},
}
func acquireZlibWriter() *zlibWriter {
ret := zlibPool.Get().(*zlibWriter)
ret.buf.Reset()
ret.w.Reset(ret.buf)
return ret
}
func releaseZlibWriter(w *zlibWriter) {
// See https://golang.org/issue/23199
const maxSize = 1 << 16
if w.buf.Cap() < maxSize {
w.buf.Reset()
zlibPool.Put(w)
}
}

View File

@ -13,12 +13,9 @@ func xorQ(a, b []byte, c []byte) { // MAGIC
*(*uint64)(unsafe.Pointer((*reflect.SliceHeader)(unsafe.Pointer(&b)).Data)) *(*uint64)(unsafe.Pointer((*reflect.SliceHeader)(unsafe.Pointer(&b)).Data))
} }
func isZero(a []byte) bool { // MAGIC
return *(*uint64)(unsafe.Pointer((*reflect.SliceHeader)(unsafe.Pointer(&a)).Data)) == 0
}
type TEA [4]uint32 type TEA [4]uint32
// 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) {
@ -27,9 +24,9 @@ func (t *TEA) Encrypt(src []byte) (dst []byte) {
tmp1 := make([]byte, 8) // 非纯src的数据 tmp1 := make([]byte, 8) // 非纯src的数据
tmp2 := make([]byte, 8) tmp2 := make([]byte, 8)
dst = make([]byte, fill+lens+7) dst = make([]byte, fill+lens+7)
//for i := 0; i < fill; i++ { // for i := 0; i < fill; i++ {
// dst[i] = ' ' // dst[i] = ' '
//} // For test purpose // } // For test purpose
_, _ = rand.Read(dst[0:fill]) _, _ = rand.Read(dst[0:fill])
dst[0] = byte(fill-3) | 0xF8 // 存储pad长度 dst[0] = byte(fill-3) | 0xF8 // 存储pad长度
in := 0 // 位置 in := 0 // 位置
@ -86,9 +83,6 @@ func (t *TEA) Decrypt(data []byte) []byte {
xorQ(dst[in:in+8], data[in-8:in], 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) xorQ(dst[in:in+8], data[in-8:in], tmp)
} }
//if !isZero(dst[len(data)-7:]) {
// return nil
//}
return dst[dst[0]&7+3 : len(data)-7] return dst[dst[0]&7+3 : len(data)-7]
} }

View File

@ -27,7 +27,7 @@ var sampleData = func() [][3]string {
{"LXY1226 Mrs4s", "LXY Testing~", "ab20caa63f3a6503a84f3cb28f9e26b6c18c051e995d1721"}, {"LXY1226 Mrs4s", "LXY Testing~", "ab20caa63f3a6503a84f3cb28f9e26b6c18c051e995d1721"},
} }
for i, _ := range out { for i := range out {
c, _ := hex.DecodeString(out[i][ENC]) c, _ := hex.DecodeString(out[i][ENC])
out[i][ENC] = utils.B2S(c) out[i][ENC] = utils.B2S(c)
} }

View File

@ -8,43 +8,10 @@ import (
"encoding/hex" "encoding/hex"
"io" "io"
"net" "net"
"sync"
"github.com/Mrs4s/MiraiGo/utils" "github.com/Mrs4s/MiraiGo/utils"
) )
type gzipWriter struct {
w *gzip.Writer
buf *bytes.Buffer
}
var gzipPool = sync.Pool{
New: func() interface{} {
buf := new(bytes.Buffer)
w := gzip.NewWriter(buf)
return &gzipWriter{
w: w,
buf: buf,
}
},
}
func acquireGzipWriter() *gzipWriter {
ret := gzipPool.Get().(*gzipWriter)
ret.buf.Reset()
ret.w.Reset(ret.buf)
return ret
}
func releaseGzipWriter(w *gzipWriter) {
// See https://golang.org/issue/23199
const maxSize = 1 << 15
if w.buf.Cap() < maxSize {
w.buf.Reset()
gzipPool.Put(w)
}
}
func ZlibUncompress(src []byte) []byte { func ZlibUncompress(src []byte) []byte {
b := bytes.NewReader(src) b := bytes.NewReader(src)
var out bytes.Buffer var out bytes.Buffer
@ -55,11 +22,12 @@ func ZlibUncompress(src []byte) []byte {
} }
func ZlibCompress(data []byte) []byte { func ZlibCompress(data []byte) []byte {
buf := new(bytes.Buffer) zw := acquireZlibWriter()
w := zlib.NewWriter(buf) _, _ = zw.w.Write(data)
_, _ = w.Write(data) _ = zw.w.Close()
w.Close() ret := append([]byte(nil), zw.buf.Bytes()...)
return buf.Bytes() releaseZlibWriter(zw)
return ret
} }
func GZipCompress(data []byte) []byte { func GZipCompress(data []byte) []byte {
@ -87,7 +55,6 @@ func CalculateImageResourceId(md5 []byte) string {
id = id[:37] id = id[:37]
id = append(id, "}.png"...) id = append(id, "}.png"...)
return utils.B2S(bytes.ToUpper(id)) return utils.B2S(bytes.ToUpper(id))
} }
func GenUUID(uuid []byte) []byte { func GenUUID(uuid []byte) []byte {

View File

@ -1,33 +1,13 @@
package binary package binary
import ( import (
"bytes"
"encoding/binary" "encoding/binary"
"encoding/hex" "encoding/hex"
"sync"
) )
type Writer struct { // Writer 写入
b []byte type Writer bytes.Buffer
}
var bufferPool = sync.Pool{
New: func() interface{} {
return new(Writer)
},
}
func NewWriter() *Writer {
return bufferPool.Get().(*Writer)
}
func PutBuffer(w *Writer) {
// See https://golang.org/issue/23199
const maxSize = 1 << 16
if cap(w.b) < maxSize { // 对于大Buffer直接丢弃
w.b = w.b[:0]
bufferPool.Put(w)
}
}
func NewWriterF(f func(writer *Writer)) []byte { func NewWriterF(f func(writer *Writer)) []byte {
w := NewWriter() w := NewWriter()
@ -38,7 +18,7 @@ func NewWriterF(f func(writer *Writer)) []byte {
} }
func (w *Writer) Write(b []byte) { func (w *Writer) Write(b []byte) {
w.b = append(w.b, b...) (*bytes.Buffer)(w).Write(b)
} }
func (w *Writer) WriteHex(h string) { func (w *Writer) WriteHex(h string) {
@ -47,7 +27,7 @@ func (w *Writer) WriteHex(h string) {
} }
func (w *Writer) WriteByte(b byte) { func (w *Writer) WriteByte(b byte) {
w.b = append(w.b, b) (*bytes.Buffer)(w).WriteByte(b)
} }
func (w *Writer) WriteUInt16(v uint16) { func (w *Writer) WriteUInt16(v uint16) {
@ -129,5 +109,17 @@ func (w *Writer) WriteTlvLimitedSize(data []byte, limit int) {
} }
func (w *Writer) Bytes() []byte { func (w *Writer) Bytes() []byte {
return w.b return (*bytes.Buffer)(w).Bytes()
}
func (w *Writer) Cap() int {
return (*bytes.Buffer)(w).Cap()
}
func (w *Writer) Reset() {
(*bytes.Buffer)(w).Reset()
}
func (w *Writer) Grow(n int) {
(*bytes.Buffer)(w).Grow(n)
} }

View File

@ -393,7 +393,7 @@ func (c *QQClient) buildRequestChangeSigPacket() (uint16, []byte) {
"qzone.qq.com", "vip.qq.com", "qun.qq.com", "game.qq.com", "qqweb.qq.com", "qzone.qq.com", "vip.qq.com", "qun.qq.com", "game.qq.com", "qqweb.qq.com",
"office.qq.com", "ti.qq.com", "mail.qq.com", "qzone.com", "mma.qq.com", "office.qq.com", "ti.qq.com", "mail.qq.com", "qzone.com", "mma.qq.com",
})) }))
//w.Write(tlv.T202(SystemDeviceInfo.WifiBSSID, SystemDeviceInfo.WifiSSID)) // w.Write(tlv.T202(SystemDeviceInfo.WifiBSSID, SystemDeviceInfo.WifiSSID))
}) })
sso := packets.BuildSsoPacket(seq, c.version.AppId, "wtlogin.exchange_emp", SystemDeviceInfo.IMEI, c.sigInfo.tgt, c.OutGoingPacketSessionId, req, c.ksid) sso := packets.BuildSsoPacket(seq, c.version.AppId, "wtlogin.exchange_emp", SystemDeviceInfo.IMEI, c.sigInfo.tgt, c.OutGoingPacketSessionId, req, c.ksid)
packet := packets.BuildLoginPacket(c.Uin, 2, make([]byte, 16), sso, []byte{}) packet := packets.BuildLoginPacket(c.Uin, 2, make([]byte, 16), sso, []byte{})

View File

@ -15,6 +15,9 @@ import (
"sync/atomic" "sync/atomic"
"time" "time"
jsoniter "github.com/json-iterator/go"
"github.com/pkg/errors"
"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/pb/msg" "github.com/Mrs4s/MiraiGo/client/pb/msg"
@ -22,8 +25,6 @@ import (
"github.com/Mrs4s/MiraiGo/protocol/crypto" "github.com/Mrs4s/MiraiGo/protocol/crypto"
"github.com/Mrs4s/MiraiGo/protocol/packets" "github.com/Mrs4s/MiraiGo/protocol/packets"
"github.com/Mrs4s/MiraiGo/utils" "github.com/Mrs4s/MiraiGo/utils"
jsoniter "github.com/json-iterator/go"
"github.com/pkg/errors"
) )
var json = jsoniter.ConfigFastest var json = jsoniter.ConfigFastest
@ -536,7 +537,7 @@ func (c *QQClient) ReloadFriendList() error {
// GetFriendList request friend list // GetFriendList request friend list
func (c *QQClient) GetFriendList() (*FriendListResponse, error) { func (c *QQClient) GetFriendList() (*FriendListResponse, error) {
var curFriendCount = 0 curFriendCount := 0
r := &FriendListResponse{} r := &FriendListResponse{}
for { for {
rsp, err := c.sendAndWait(c.buildFriendGroupListRequestPacket(int16(curFriendCount), 150, 0, 0)) rsp, err := c.sendAndWait(c.buildFriendGroupListRequestPacket(int16(curFriendCount), 150, 0, 0))

View File

@ -447,7 +447,7 @@ func decodeFriendGroupListResponse(_ *QQClient, _ *incomingPacketInfo, payload [
totalFriendCount := r.ReadInt16(5) totalFriendCount := r.ReadInt16(5)
friends := []jce.FriendInfo{} friends := []jce.FriendInfo{}
r.ReadSlice(&friends, 7) r.ReadSlice(&friends, 7)
var 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{
Uin: f.FriendUin, Uin: f.FriendUin,
@ -474,7 +474,7 @@ func decodeGroupListResponse(c *QQClient, _ *incomingPacketInfo, payload []byte)
groups := []jce.TroopNumber{} groups := []jce.TroopNumber{}
r.ReadSlice(&vecCookie, 4) r.ReadSlice(&vecCookie, 4)
r.ReadSlice(&groups, 5) r.ReadSlice(&groups, 5)
var 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,
@ -507,7 +507,7 @@ func decodeGroupMemberListResponse(_ *QQClient, _ *incomingPacketInfo, payload [
members := []jce.TroopMemberInfo{} members := []jce.TroopMemberInfo{}
r.ReadSlice(&members, 3) r.ReadSlice(&members, 3)
next := r.ReadInt64(4) next := r.ReadInt64(4)
var l = make([]*GroupMemberInfo, 0, len(members)) l := make([]*GroupMemberInfo, 0, len(members))
for _, m := range members { for _, m := range members {
l = append(l, &GroupMemberInfo{ l = append(l, &GroupMemberInfo{
Uin: m.MemberUin, Uin: m.MemberUin,
@ -677,7 +677,7 @@ func decodeOnlinePushTransPacket(c *QQClient, _ *incomingPacketInfo, payload []b
if info.GetMsgType() == 44 { if info.GetMsgType() == 44 {
data.ReadBytes(5) data.ReadBytes(5)
var4 := int32(data.ReadByte()) var4 := int32(data.ReadByte())
var var5 = int64(0) var5 := int64(0)
target := int64(uint32(data.ReadInt32())) target := int64(uint32(data.ReadInt32()))
if var4 != 0 && var4 != 1 { if var4 != 0 && var4 != 1 {
var5 = int64(uint32(data.ReadInt32())) var5 = int64(uint32(data.ReadInt32()))

View File

@ -3,10 +3,11 @@ package client
import ( import (
"fmt" "fmt"
"github.com/Mrs4s/MiraiGo/client/pb/faceroam"
"github.com/Mrs4s/MiraiGo/protocol/packets"
"github.com/golang/protobuf/proto" "github.com/golang/protobuf/proto"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/Mrs4s/MiraiGo/client/pb/faceroam"
"github.com/Mrs4s/MiraiGo/protocol/packets"
) )
type CustomFace struct { type CustomFace struct {

View File

@ -156,8 +156,10 @@ var SystemDeviceInfo = &DeviceInfo{
}, },
} }
var EmptyBytes = []byte{} var (
var NumberRange = "0123456789" EmptyBytes = []byte{}
NumberRange = "0123456789"
)
func init() { func init() {
r := make([]byte, 16) r := make([]byte, 16)
@ -404,7 +406,7 @@ func GenIMEI() string {
sum += toAdd sum += toAdd
final.WriteString(fmt.Sprintf("%d", toAdd)) // and even printing them here! final.WriteString(fmt.Sprintf("%d", toAdd)) // and even printing them here!
} }
var ctrlDigit = (sum * 9) % 10 // calculating the control digit ctrlDigit := (sum * 9) % 10 // calculating the control digit
final.WriteString(fmt.Sprintf("%d", ctrlDigit)) final.WriteString(fmt.Sprintf("%d", ctrlDigit))
return final.String() return final.String()
} }
@ -443,7 +445,7 @@ func getSSOAddress() ([]*net.TCPAddr, error) {
reader := jce.NewJceReader(data.Map["HttpServerListRes"][1:]) reader := jce.NewJceReader(data.Map["HttpServerListRes"][1:])
servers := []jce.SsoServerInfo{} servers := []jce.SsoServerInfo{}
reader.ReadSlice(&servers, 2) reader.ReadSlice(&servers, 2)
var adds = make([]*net.TCPAddr, 0, len(servers)) 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

View File

@ -12,11 +12,12 @@ import (
"google.golang.org/protobuf/proto" "google.golang.org/protobuf/proto"
"github.com/pkg/errors"
"github.com/Mrs4s/MiraiGo/client/pb/exciting" "github.com/Mrs4s/MiraiGo/client/pb/exciting"
"github.com/Mrs4s/MiraiGo/client/pb/oidb" "github.com/Mrs4s/MiraiGo/client/pb/oidb"
"github.com/Mrs4s/MiraiGo/protocol/packets" "github.com/Mrs4s/MiraiGo/protocol/packets"
"github.com/Mrs4s/MiraiGo/utils" "github.com/Mrs4s/MiraiGo/utils"
"github.com/pkg/errors"
) )
type ( type (
@ -173,7 +174,7 @@ func (fs *GroupFileSystem) UploadFile(p, name, folderId string) error {
defer fileSingleFlight.Delete(p) defer fileSingleFlight.Delete(p)
} }
file, err := os.OpenFile(p, os.O_RDONLY, 0666) 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")
} }

View File

@ -631,7 +631,7 @@ func (c *QQClient) GetGroupEssenceMsgList(groupCode int64) ([]GroupDigest, error
} }
rsp = rsp[bytes.Index(rsp, []byte("window.__INITIAL_STATE__={"))+25:] rsp = rsp[bytes.Index(rsp, []byte("window.__INITIAL_STATE__={"))+25:]
rsp = rsp[:bytes.Index(rsp, []byte("</script>"))] rsp = rsp[:bytes.Index(rsp, []byte("</script>"))]
var data = &struct { data := &struct {
List []GroupDigest `json:"msgList"` List []GroupDigest `json:"msgList"`
}{} }{}
err = json.Unmarshal(rsp, data) err = json.Unmarshal(rsp, data)

View File

@ -11,8 +11,9 @@ import (
"net/url" "net/url"
"strconv" "strconv"
"github.com/Mrs4s/MiraiGo/utils"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/Mrs4s/MiraiGo/utils"
) )
type noticePicUpResponse struct { type noticePicUpResponse struct {
@ -29,7 +30,7 @@ type noticeImage struct {
func (c *QQClient) uploadGroupNoticePic(img []byte) (*noticeImage, error) { func (c *QQClient) uploadGroupNoticePic(img []byte) (*noticeImage, error) {
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
var w = multipart.NewWriter(buf) w := multipart.NewWriter(buf)
err := w.WriteField("bkn", strconv.Itoa(c.getCSRFToken())) err := w.WriteField("bkn", strconv.Itoa(c.getCSRFToken()))
if err != nil { if err != nil {
return nil, errors.Wrap(err, "write multipart<bkn> failed") return nil, errors.Wrap(err, "write multipart<bkn> failed")

View File

@ -37,7 +37,7 @@ func (c *QQClient) highwayUploadStream(ip uint32, port int, updKey []byte, strea
h := md5.New() h := md5.New()
length, _ := io.Copy(h, stream) length, _ := io.Copy(h, stream)
fh := h.Sum(nil) fh := h.Sum(nil)
chunkSize := 8192 * 8 const chunkSize = 8192 * 8
_, _ = stream.Seek(0, io.SeekStart) _, _ = stream.Seek(0, io.SeekStart)
conn, err := net.DialTCP("tcp", nil, &addr) conn, err := net.DialTCP("tcp", nil, &addr)
if err != nil { if err != nil {
@ -46,8 +46,11 @@ func (c *QQClient) highwayUploadStream(ip uint32, port int, updKey []byte, strea
defer conn.Close() defer conn.Close()
offset := 0 offset := 0
reader := binary.NewNetworkReader(conn) reader := binary.NewNetworkReader(conn)
chunk := make([]byte, chunkSize)
w := binary.NewWriter()
defer binary.PutBuffer(w)
for { for {
chunk := make([]byte, chunkSize) chunk = chunk[:chunkSize]
rl, err := io.ReadFull(stream, chunk) rl, err := io.ReadFull(stream, chunk)
if errors.Is(err, io.EOF) { if errors.Is(err, io.EOF) {
break break
@ -78,14 +81,14 @@ func (c *QQClient) highwayUploadStream(ip uint32, port int, updKey []byte, strea
ReqExtendinfo: EmptyBytes, ReqExtendinfo: EmptyBytes,
}) })
offset += rl offset += rl
_, err = conn.Write(binary.NewWriterF(func(w *binary.Writer) { w.Reset()
w.WriteByte(40) w.WriteByte(40)
w.WriteUInt32(uint32(len(head))) w.WriteUInt32(uint32(len(head)))
w.WriteUInt32(uint32(len(chunk))) w.WriteUInt32(uint32(len(chunk)))
w.Write(head) w.Write(head)
w.Write(chunk) w.Write(chunk)
w.WriteByte(41) w.WriteByte(41)
})) _, err = conn.Write(w.Bytes())
if err != nil { if err != nil {
return errors.Wrap(err, "write conn error") return errors.Wrap(err, "write conn error")
} }
@ -100,7 +103,7 @@ func (c *QQClient) highwayUploadStream(ip uint32, port int, updKey []byte, strea
return nil return nil
} }
func (c *QQClient) highwayUploadByBDH(stream io.ReadSeeker, cmdId int32, ticket, ext []byte, encrypt bool) ([]byte, error) { func (c *QQClient) highwayUploadByBDH(stream io.Reader, length int64, cmdId int32, ticket, sum, ext []byte, encrypt bool) ([]byte, error) {
if len(c.srvSsoAddrs) == 0 { if len(c.srvSsoAddrs) == 0 {
return nil, errors.New("srv addrs not found. maybe miss some packet?") return nil, errors.New("srv addrs not found. maybe miss some packet?")
} }
@ -110,11 +113,7 @@ func (c *QQClient) highwayUploadByBDH(stream io.ReadSeeker, cmdId int32, ticket,
} }
ext = binary.NewTeaCipher(c.highwaySession.SessionKey).Encrypt(ext) ext = binary.NewTeaCipher(c.highwaySession.SessionKey).Encrypt(ext)
} }
h := md5.New() const chunkSize = 8192 * 16
length, _ := io.Copy(h, stream)
fh := h.Sum(nil)
chunkSize := 8192 * 16
_, _ = stream.Seek(0, io.SeekStart)
conn, err := net.DialTimeout("tcp", c.srvSsoAddrs[0], time.Second*20) conn, err := net.DialTimeout("tcp", c.srvSsoAddrs[0], time.Second*20)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "connect error") return nil, errors.Wrap(err, "connect error")
@ -129,8 +128,11 @@ func (c *QQClient) highwayUploadByBDH(stream io.ReadSeeker, cmdId int32, ticket,
return nil, errors.Wrap(err, "echo error") return nil, errors.Wrap(err, "echo error")
} }
var rspExt []byte var rspExt []byte
chunk := make([]byte, chunkSize)
w := binary.NewWriter()
defer binary.PutBuffer(w)
for { for {
chunk := make([]byte, chunkSize) chunk = chunk[:chunkSize]
rl, err := io.ReadFull(stream, chunk) rl, err := io.ReadFull(stream, chunk)
if errors.Is(err, io.EOF) { if errors.Is(err, io.EOF) {
break break
@ -156,19 +158,19 @@ func (c *QQClient) highwayUploadByBDH(stream io.ReadSeeker, cmdId int32, ticket,
Datalength: int32(rl), Datalength: int32(rl),
Serviceticket: ticket, Serviceticket: ticket,
Md5: ch[:], Md5: ch[:],
FileMd5: fh[:], FileMd5: sum,
}, },
ReqExtendinfo: ext, ReqExtendinfo: ext,
}) })
offset += rl offset += rl
_, err = conn.Write(binary.NewWriterF(func(w *binary.Writer) { w.Reset()
w.WriteByte(40) w.WriteByte(40)
w.WriteUInt32(uint32(len(head))) w.WriteUInt32(uint32(len(head)))
w.WriteUInt32(uint32(len(chunk))) w.WriteUInt32(uint32(len(chunk)))
w.Write(head) w.Write(head)
w.Write(chunk) w.Write(chunk)
w.WriteByte(41) w.WriteByte(41)
})) _, err = conn.Write(w.Bytes())
if err != nil { if err != nil {
return nil, errors.Wrap(err, "write conn error") return nil, errors.Wrap(err, "write conn error")
} }
@ -203,22 +205,23 @@ func (c *QQClient) highwayUploadFileMultiThreadingByBDH(path string, cmdId int32
if err != nil { if err != nil {
return nil, errors.Wrap(err, "get stat error") return nil, errors.Wrap(err, "get stat error")
} }
file, err := os.OpenFile(path, os.O_RDONLY, 0666) file, err := os.OpenFile(path, os.O_RDONLY, 0o666)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "open file error") return nil, errors.Wrap(err, "open file error")
} }
defer file.Close() 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 { if stat.Size() < 1024*1024*3 {
return c.highwayUploadByBDH(file, cmdId, ticket, ext, false) return c.highwayUploadByBDH(file, length, cmdId, ticket, fh, ext, false)
} }
type BlockMetaData struct { type BlockMetaData struct {
Id int Id int
BeginOffset int64 BeginOffset int64
EndOffset int64 EndOffset int64
} }
h := md5.New()
_, _ = io.Copy(h, file)
fh := h.Sum(nil)
const blockSize int64 = 1024 * 512 const blockSize int64 = 1024 * 512
var ( var (
blocks []*BlockMetaData blocks []*BlockMetaData
@ -251,7 +254,7 @@ func (c *QQClient) highwayUploadFileMultiThreadingByBDH(path string, cmdId int32
return errors.Wrap(err, "connect error") return errors.Wrap(err, "connect error")
} }
defer conn.Close() defer conn.Close()
chunk, _ := os.OpenFile(path, os.O_RDONLY, 0666) chunk, _ := os.OpenFile(path, os.O_RDONLY, 0o666)
defer chunk.Close() defer chunk.Close()
reader := binary.NewNetworkReader(conn) reader := binary.NewNetworkReader(conn)
if err = c.highwaySendHeartbreak(conn); err != nil { if err = c.highwaySendHeartbreak(conn); err != nil {
@ -278,7 +281,7 @@ func (c *QQClient) highwayUploadFileMultiThreadingByBDH(path string, cmdId int32
} }
buffer := make([]byte, blockSize) buffer := make([]byte, blockSize)
_, _ = chunk.Seek(block.BeginOffset, io.SeekStart) _, _ = chunk.Seek(block.BeginOffset, io.SeekStart)
ri, err := io.ReadFull(chunk, buffer) ri, err := io.ReadFull(chunk, buffer) // todo: reuse buffer
if err != nil { if err != nil {
if err == io.EOF { if err == io.EOF {
break break
@ -311,14 +314,15 @@ func (c *QQClient) highwayUploadFileMultiThreadingByBDH(path string, cmdId int32
}, },
ReqExtendinfo: ext, ReqExtendinfo: ext,
}) })
_, err = conn.Write(binary.NewWriterF(func(w *binary.Writer) { w := binary.NewWriter()
w.WriteByte(40) w.WriteByte(40)
w.WriteUInt32(uint32(len(head))) w.WriteUInt32(uint32(len(head)))
w.WriteUInt32(uint32(len(buffer))) w.WriteUInt32(uint32(len(buffer)))
w.Write(head) w.Write(head)
w.Write(buffer) w.Write(buffer)
w.WriteByte(41) w.WriteByte(41)
})) _, err = conn.Write(w.Bytes())
binary.PutBuffer(w)
if err != nil { if err != nil {
return errors.Wrap(err, "write conn error") return errors.Wrap(err, "write conn error")
} }
@ -364,13 +368,14 @@ func (c *QQClient) highwaySendHeartbreak(conn net.Conn) error {
LocaleId: 2052, LocaleId: 2052,
}, },
}) })
_, err := conn.Write(binary.NewWriterF(func(w *binary.Writer) { w := binary.NewWriter()
w.WriteByte(40) w.WriteByte(40)
w.WriteUInt32(uint32(len(head))) w.WriteUInt32(uint32(len(head)))
w.WriteUInt32(0) w.WriteUInt32(0)
w.Write(head) w.Write(head)
w.WriteByte(41) w.WriteByte(41)
})) _, err := conn.Write(w.Bytes())
binary.PutBuffer(w)
return err return err
} }
@ -400,8 +405,12 @@ func (c *QQClient) excitingUploadStream(stream io.ReadSeeker, cmdId int32, ticke
offset int64 = 0 offset int64 = 0
chunkSize = 524288 chunkSize = 524288
) )
chunk := make([]byte, chunkSize)
w := binary.NewWriter()
w.Reset()
w.Grow(600 * 1024) // 复用,600k 不要放回池中
for { for {
chunk := make([]byte, chunkSize) chunk = chunk[:chunkSize]
rl, err := io.ReadFull(stream, chunk) rl, err := io.ReadFull(stream, chunk)
if err == io.EOF { if err == io.EOF {
break break
@ -432,15 +441,14 @@ func (c *QQClient) excitingUploadStream(stream io.ReadSeeker, cmdId int32, ticke
ReqExtendinfo: ext, ReqExtendinfo: ext,
}) })
offset += int64(rl) offset += int64(rl)
io.Pipe() w.Reset()
req, _ := http.NewRequest("POST", url, bytes.NewReader(binary.NewWriterF(func(w *binary.Writer) { w.WriteByte(40)
w.WriteByte(40) w.WriteUInt32(uint32(len(head)))
w.WriteUInt32(uint32(len(head))) w.WriteUInt32(uint32(len(chunk)))
w.WriteUInt32(uint32(len(chunk))) w.Write(head)
w.Write(head) w.Write(chunk)
w.Write(chunk) w.WriteByte(41)
w.WriteByte(41) req, _ := http.NewRequest("POST", url, bytes.NewReader(w.Bytes()))
})))
req.Header.Set("Accept", "*/*") req.Header.Set("Accept", "*/*")
req.Header.Set("Connection", "Keep-Alive") 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("User-Agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)")
@ -504,7 +512,7 @@ func (c *QQClient) uploadGroupHeadPortrait(groupCode int64, img []byte) error {
groupCode, groupCode,
len(img), len(img),
) )
req, err := http.NewRequest("POST", url, bytes.NewReader(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["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=****"} req.Header["Content-Type"] = []string{"multipart/form-data;boundary=****"}
rsp, err := http.DefaultClient.Do(req) rsp, err := http.DefaultClient.Do(req)

View File

@ -31,9 +31,9 @@ type (
) )
const ( const (
Talkative HonorType = 1 //龙王 Talkative HonorType = 1 // 龙王
Performer HonorType = 2 //群聊之火 Performer HonorType = 2 // 群聊之火
Legend HonorType = 3 //群聊炙焰 Legend HonorType = 3 // 群聊炙焰
StrongNewbie HonorType = 5 //冒尖小春笋 StrongNewbie HonorType = 5 // 冒尖小春笋
Emotion HonorType = 6 //快乐源泉 Emotion HonorType = 6 // 快乐源泉
) )

View File

@ -13,13 +13,14 @@ import (
"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/client/pb/oidb"
"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" "github.com/Mrs4s/MiraiGo/client/pb"
"github.com/Mrs4s/MiraiGo/message" "github.com/Mrs4s/MiraiGo/message"
"github.com/Mrs4s/MiraiGo/protocol/packets" "github.com/Mrs4s/MiraiGo/protocol/packets"
"github.com/Mrs4s/MiraiGo/utils" "github.com/Mrs4s/MiraiGo/utils"
"github.com/pkg/errors"
"google.golang.org/protobuf/proto"
) )
func init() { func init() {
@ -48,7 +49,7 @@ func (c *QQClient) UploadGroupImage(groupCode int64, img io.ReadSeeker) (*messag
c.srvSsoAddrs = append(c.srvSsoAddrs, fmt.Sprintf("%v:%v", binary.UInt32ToIPV4Address(uint32(addr)), rsp.UploadPort[i])) c.srvSsoAddrs = append(c.srvSsoAddrs, fmt.Sprintf("%v:%v", binary.UInt32ToIPV4Address(uint32(addr)), rsp.UploadPort[i]))
} }
} }
if _, err = c.highwayUploadByBDH(img, 2, rsp.UploadKey, EmptyBytes, false); err == nil { if _, err = c.highwayUploadByBDH(img, length, 2, rsp.UploadKey, EmptyBytes, fh, false); err == nil {
goto ok goto ok
} }
return nil, errors.New("upload failed") return nil, errors.New("upload failed")
@ -66,7 +67,7 @@ ok:
} }
func (c *QQClient) UploadGroupImageByFile(groupCode int64, path string) (*message.GroupImageElement, error) { func (c *QQClient) UploadGroupImageByFile(groupCode int64, path string) (*message.GroupImageElement, error) {
img, err := os.OpenFile(path, os.O_RDONLY, 0666) img, err := os.OpenFile(path, os.O_RDONLY, 0o666)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -137,10 +138,11 @@ func (c *QQClient) ImageOcr(img interface{}) (*OcrResponse, error) {
switch e := img.(type) { switch e := img.(type) {
case *message.GroupImageElement: case *message.GroupImageElement:
url = e.Url url = e.Url
if b, err := utils.HttpGetBytes(e.Url, ""); err == nil { if b, err := utils.HTTPGetReadCloser(e.Url, ""); err == nil {
if url, err = c.uploadOcrImage(bytes.NewReader(b)); err != nil { if url, err = c.uploadOcrImage(b, int64(e.Size), e.Md5); err != nil {
url = e.Url url = e.Url
} }
_ = b.Close()
} }
rsp, err := c.sendAndWait(c.buildImageOcrRequestPacket(url, strings.ToUpper(hex.EncodeToString(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 {
@ -149,10 +151,11 @@ func (c *QQClient) ImageOcr(img interface{}) (*OcrResponse, error) {
return rsp.(*OcrResponse), nil return rsp.(*OcrResponse), nil
case *message.ImageElement: case *message.ImageElement:
url = e.Url url = e.Url
if b, err := utils.HttpGetBytes(e.Url, ""); err == nil { if b, err := utils.HTTPGetReadCloser(e.Url, ""); err == nil {
if url, err = c.uploadOcrImage(bytes.NewReader(b)); err != nil { if url, err = c.uploadOcrImage(b, int64(e.Size), e.Md5); err != nil {
url = e.Url url = e.Url
} }
_ = b.Close()
} }
rsp, err := c.sendAndWait(c.buildImageOcrRequestPacket(url, strings.ToUpper(hex.EncodeToString(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 {
@ -232,14 +235,14 @@ func (c *QQClient) buildGroupImageStorePacket(groupCode int64, md5 []byte, size
return seq, packet return seq, packet
} }
func (c *QQClient) uploadOcrImage(img io.ReadSeeker) (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(&highway.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, 76, c.highwaySession.SigSession, ext, false) rsp, err := c.highwayUploadByBDH(img, length, 76, c.highwaySession.SigSession, sum, ext, false)
if err != nil { if err != nil {
return "", errors.Wrap(err, "upload ocr image error") return "", errors.Wrap(err, "upload ocr image error")
} }
@ -316,9 +319,9 @@ func decodeImageOcrResponse(_ *QQClient, _ *incomingPacketInfo, payload []byte)
if rsp.RetCode != 0 { if rsp.RetCode != 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)
} }
var texts = make([]*TextDetection, 0, len(rsp.OcrRspBody.TextDetections)) texts := make([]*TextDetection, 0, len(rsp.OcrRspBody.TextDetections))
for _, text := range rsp.OcrRspBody.TextDetections { for _, text := range rsp.OcrRspBody.TextDetections {
var 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.X,

View File

@ -40,7 +40,7 @@ type (
// grayTipProcessor 提取出来专门用于处理群内 notify tips // grayTipProcessor 提取出来专门用于处理群内 notify tips
func (c *QQClient) grayTipProcessor(groupID int64, tipInfo *notify.GeneralGrayTipInfo) { func (c *QQClient) grayTipProcessor(groupID int64, tipInfo *notify.GeneralGrayTipInfo) {
if tipInfo.BusiType == 12 && tipInfo.BusiId == 1061 { if tipInfo.BusiType == 12 && tipInfo.BusiId == 1061 {
var sender = int64(0) sender := int64(0)
receiver := c.Uin receiver := c.Uin
for _, templ := range tipInfo.MsgTemplParam { for _, templ := range tipInfo.MsgTemplParam {
if templ.Name == "uin_str1" { if templ.Name == "uin_str1" {

View File

@ -7,12 +7,13 @@ import (
"github.com/Mrs4s/MiraiGo/client/pb/msgtype0x210" "github.com/Mrs4s/MiraiGo/client/pb/msgtype0x210"
"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/pb" "github.com/Mrs4s/MiraiGo/client/pb"
"github.com/Mrs4s/MiraiGo/client/pb/notify" "github.com/Mrs4s/MiraiGo/client/pb/notify"
"github.com/pkg/errors"
"google.golang.org/protobuf/proto"
) )
var msg0x210Decoders = map[int64]func(*QQClient, []byte) error{ var msg0x210Decoders = map[int64]func(*QQClient, []byte) error{
@ -90,7 +91,7 @@ func decodeOnlinePushReqPacket(c *QQClient, info *incomingPacketInfo, payload []
} }
} }
if b.QqGroupDigestMsg != nil { if b.QqGroupDigestMsg != nil {
var digest = b.QqGroupDigestMsg digest := b.QqGroupDigestMsg
c.dispatchGroupDigestEvent(&GroupDigestEvent{ c.dispatchGroupDigestEvent(&GroupDigestEvent{
GroupCode: int64(digest.GroupCode), GroupCode: int64(digest.GroupCode),
MessageID: int32(digest.Seq), MessageID: int32(digest.Seq),

View File

@ -6,10 +6,11 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/golang/protobuf/proto"
"github.com/Mrs4s/MiraiGo/client/pb/msg" "github.com/Mrs4s/MiraiGo/client/pb/msg"
"github.com/Mrs4s/MiraiGo/message" "github.com/Mrs4s/MiraiGo/message"
"github.com/Mrs4s/MiraiGo/protocol/packets" "github.com/Mrs4s/MiraiGo/protocol/packets"
"github.com/golang/protobuf/proto"
) )
func (c *QQClient) SendPrivateMessage(target int64, m *message.SendingMessage) *message.PrivateMessage { func (c *QQClient) SendPrivateMessage(target int64, m *message.SendingMessage) *message.PrivateMessage {

View File

@ -31,7 +31,7 @@ func (c *QQClient) UploadGroupPtt(groupCode int64, voice io.ReadSeeker) (*messag
fh := h.Sum(nil) fh := h.Sum(nil)
_, _ = voice.Seek(0, io.SeekStart) _, _ = voice.Seek(0, io.SeekStart)
ext := c.buildGroupPttStoreBDHExt(groupCode, fh[:], int32(length), 0, int32(length)) ext := c.buildGroupPttStoreBDHExt(groupCode, fh[:], int32(length), 0, int32(length))
rsp, err := c.highwayUploadByBDH(voice, 29, c.highwaySession.SigSession, ext, false) rsp, err := c.highwayUploadByBDH(voice, length, 29, c.highwaySession.SigSession, fh, ext, false)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -55,7 +55,8 @@ func (c *QQClient) UploadGroupPtt(groupCode int64, voice io.ReadSeeker) (*messag
GroupFileKey: pkt.MsgTryUpPttRsp[0].FileKey, GroupFileKey: pkt.MsgTryUpPttRsp[0].FileKey,
BoolValid: proto.Bool(true), BoolValid: proto.Bool(true),
PbReserve: []byte{8, 0, 40, 0, 56, 0}, PbReserve: []byte{8, 0, 40, 0, 56, 0},
}}, nil },
}, nil
} }
// UploadPrivatePtt 将语音数据使用好友语音通道上传到服务器, 返回 message.PrivateVoiceElement 可直接发送 // UploadPrivatePtt 将语音数据使用好友语音通道上传到服务器, 返回 message.PrivateVoiceElement 可直接发送
@ -65,7 +66,7 @@ func (c *QQClient) UploadPrivatePtt(target int64, voice io.ReadSeeker) (*message
fh := h.Sum(nil) fh := h.Sum(nil)
_, _ = voice.Seek(0, io.SeekStart) _, _ = voice.Seek(0, io.SeekStart)
ext := c.buildC2CPttStoreBDHExt(target, fh[:], int32(length), int32(length)) ext := c.buildC2CPttStoreBDHExt(target, fh[:], int32(length), int32(length))
rsp, err := c.highwayUploadByBDH(voice, 26, c.highwaySession.SigSession, ext, false) rsp, err := c.highwayUploadByBDH(voice, length, 26, c.highwaySession.SigSession, fh, ext, false)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -89,7 +90,8 @@ func (c *QQClient) UploadPrivatePtt(target int64, voice io.ReadSeeker) (*message
FileSize: proto.Int32(int32(length)), FileSize: proto.Int32(int32(length)),
// Reserve: constructPTTExtraInfo(1, int32(len(voice))), // todo length // Reserve: constructPTTExtraInfo(1, int32(len(voice))), // todo length
BoolValid: proto.Bool(true), BoolValid: proto.Bool(true),
}}, nil },
}, nil
} }
// UploadGroupShortVideo 将视频和封面上传到服务器, 返回 message.ShortVideoElement 可直接发送 // UploadGroupShortVideo 将视频和封面上传到服务器, 返回 message.ShortVideoElement 可直接发送
@ -117,22 +119,27 @@ func (c *QQClient) UploadGroupShortVideo(groupCode int64, video, thumb io.ReadSe
} }
ext, _ := proto.Marshal(c.buildPttGroupShortVideoProto(videoHash, thumbHash, groupCode, videoLen, thumbLen).PttShortVideoUploadReq) ext, _ := proto.Marshal(c.buildPttGroupShortVideoProto(videoHash, thumbHash, groupCode, videoLen, thumbLen).PttShortVideoUploadReq)
var hwRsp []byte var hwRsp []byte
multi := utils.MultiReadSeeker(thumb, video)
h := md5.New()
length, _ := io.Copy(h, multi)
fh := h.Sum(nil)
_, _ = multi.Seek(0, io.SeekStart)
if cache != "" { if cache != "" {
var file *os.File var file *os.File
file, err = os.OpenFile(cache, os.O_WRONLY|os.O_CREATE, 0666) file, err = os.OpenFile(cache, os.O_WRONLY|os.O_CREATE, 0o666)
cp := func() error { cp := func() error {
_, err := io.Copy(file, utils.MultiReadSeeker(thumb, video)) _, err := io.Copy(file, utils.MultiReadSeeker(thumb, video))
return err return err
} }
if err != nil || cp() != nil { if err != nil || cp() != nil {
hwRsp, err = c.highwayUploadByBDH(utils.MultiReadSeeker(thumb, video), 25, c.highwaySession.SigSession, ext, true) hwRsp, err = c.highwayUploadByBDH(multi, length, 25, c.highwaySession.SigSession, fh, ext, true)
} else { } else {
_ = file.Close() _ = file.Close()
hwRsp, err = c.highwayUploadFileMultiThreadingByBDH(cache, 25, 8, c.highwaySession.SigSession, ext, true) hwRsp, err = c.highwayUploadFileMultiThreadingByBDH(cache, 25, 8, c.highwaySession.SigSession, ext, true)
_ = os.Remove(cache) _ = os.Remove(cache)
} }
} else { } else {
hwRsp, err = c.highwayUploadByBDH(utils.MultiReadSeeker(thumb, video), 25, c.highwaySession.SigSession, ext, true) hwRsp, err = c.highwayUploadByBDH(multi, length, 25, c.highwaySession.SigSession, fh, ext, true)
} }
if err != nil { if err != nil {
return nil, errors.Wrap(err, "upload video file error") return nil, errors.Wrap(err, "upload video file error")
@ -279,7 +286,7 @@ func decodeGroupPttStoreResponse(_ *QQClient, _ *incomingPacketInfo, payload []b
if rsp.BoolFileExit { if rsp.BoolFileExit {
return pttUploadResponse{IsExists: true}, nil return pttUploadResponse{IsExists: true}, nil
} }
var ip = make([]string, 0, len(rsp.Uint32UpIp)) ip := make([]string, 0, len(rsp.Uint32UpIp))
for _, i := range rsp.Uint32UpIp { for _, i := range rsp.Uint32UpIp {
ip = append(ip, binary.UInt32ToIPV4Address(uint32(i))) ip = append(ip, binary.UInt32ToIPV4Address(uint32(i)))
} }

View File

@ -56,7 +56,7 @@ func (c *QQClient) GetAllowedClients() ([]*OtherClientInfo, error) {
return nil, err return nil, err
} }
list := i.([]jce.SvcDevLoginInfo) list := i.([]jce.SvcDevLoginInfo)
var ret = make([]*OtherClientInfo, 0, len(list)) ret := make([]*OtherClientInfo, 0, len(list))
for _, l := range list { for _, l := range list {
ret = append(ret, &OtherClientInfo{ ret = append(ret, &OtherClientInfo{
AppId: l.AppId, AppId: l.AppId,
@ -208,7 +208,8 @@ func (c *QQClient) buildSyncMsgRequestPacket() (uint16, []byte) {
Type: proto.Uint32(283), Type: proto.Uint32(283),
Version: proto.Uint32(0), Version: proto.Uint32(0),
}, },
}}) },
})
regReq := &jce.SvcReqRegisterNew{ regReq := &jce.SvcReqRegisterNew{
RequestOptional: 128 | 64 | 256 | 2 | 8192 | 16384 | 65536, RequestOptional: 128 | 64 | 256 | 2 | 8192 | 16384 | 65536,
DisGroupMsgFilter: 1, DisGroupMsgFilter: 1,

View File

@ -43,24 +43,24 @@ func (c *QQClient) decodeT119(data, ek []byte) {
} }
var ( var (
//openId []byte // openId []byte
//openKey []byte // openKey []byte
//payToken []byte // payToken []byte
//pf []byte // pf []byte
//pfkey []byte // pfkey []byte
gender uint16 = 0 gender uint16 = 0
age uint16 = 0 age uint16 = 0
nick = "" nick = ""
//a1 []byte // a1 []byte
//noPicSig []byte // noPicSig []byte
//ctime = time.Now().Unix() // ctime = time.Now().Unix()
//etime = ctime + 2160000 // etime = ctime + 2160000
psKeyMap map[string][]byte psKeyMap map[string][]byte
pt4TokenMap map[string][]byte pt4TokenMap map[string][]byte
) )
if _, ok := m[0x125]; ok { if _, ok := m[0x125]; ok {
//openId, openKey = readT125(t125) // openId, openKey = readT125(t125)
} }
if t186, ok := m[0x186]; ok { if t186, ok := m[0x186]; ok {
c.decodeT186(t186) c.decodeT186(t186)
@ -69,20 +69,20 @@ func (c *QQClient) decodeT119(data, ek []byte) {
nick, age, gender = readT11A(t11a) nick, age, gender = readT11A(t11a)
} }
if _, ok := m[0x199]; ok { if _, ok := m[0x199]; ok {
//openId, payToken = readT199(t199) // openId, payToken = readT199(t199)
} }
if _, ok := m[0x200]; ok { if _, ok := m[0x200]; ok {
//pf, pfkey = readT200(t200) // pf, pfkey = readT200(t200)
} }
if t512, ok := m[0x512]; ok { if t512, ok := m[0x512]; ok {
psKeyMap, pt4TokenMap = readT512(t512) psKeyMap, pt4TokenMap = readT512(t512)
} }
if _, ok := m[0x531]; ok { if _, ok := m[0x531]; ok {
//a1, noPicSig = readT531(t531) // a1, noPicSig = readT531(t531)
} }
if _, ok := m[0x138]; ok { if _, ok := m[0x138]; ok {
//readT138(t138) // chg time // readT138(t138) // chg time
} }
c.sigInfo = &loginSigInfo{ c.sigInfo = &loginSigInfo{

View File

@ -86,7 +86,7 @@ type ReplyElement struct {
Time int32 Time int32
Elements []IMessageElement Elements []IMessageElement
//original []*msg.Elem // original []*msg.Elem
} }
type ShortVideoElement struct { type ShortVideoElement struct {
@ -241,7 +241,7 @@ func NewReply(m *GroupMessage) *ReplyElement {
ReplySeq: m.Id, ReplySeq: m.Id,
Sender: m.Sender.Uin, Sender: m.Sender.Uin,
Time: m.Time, Time: m.Time,
//original: m.OriginalElements, // original: m.OriginalElements,
Elements: m.Elements, Elements: m.Elements,
} }
} }
@ -271,9 +271,10 @@ func NewUrlShare(url, title, content, image string) *ServiceElement {
SubType: "UrlShare", SubType: "UrlShare",
} }
} }
func NewRichXml(template string, ResId int64) *ServiceElement { func NewRichXml(template string, ResId int64) *ServiceElement {
if ResId == 0 { if ResId == 0 {
ResId = 60 //默认值60 ResId = 60 // 默认值60
} }
return &ServiceElement{ return &ServiceElement{
Id: int32(ResId), Id: int32(ResId),

View File

@ -36,7 +36,7 @@ var faceMap = map[int]string{
` `
func main() { func main() {
f, _ := os.OpenFile("face.go", os.O_WRONLY|os.O_CREATE|os.O_SYNC|os.O_TRUNC, 0755) f, _ := os.OpenFile("face.go", os.O_WRONLY|os.O_CREATE|os.O_SYNC|os.O_TRUNC, 0o755)
defer func() { _ = f.Close() }() defer func() { _ = f.Close() }()
resp, err := http.Get(faceDownloadUrl) resp, err := http.Get(faceDownloadUrl)
if err != nil { if err != nil {

View File

@ -46,7 +46,7 @@ type (
Time int32 Time int32
Elements []IMessageElement Elements []IMessageElement
OriginalObject *msg.Message OriginalObject *msg.Message
//OriginalElements []*msg.Elem // OriginalElements []*msg.Elem
} }
SendingMessage struct { SendingMessage struct {
@ -327,7 +327,7 @@ func ToProtoElems(elems []IMessageElement, generalFlags bool) (r []*msg.Elem) {
}) })
break L break L
} }
//d, _ := hex.DecodeString("08097800C80100F00100F80100900200C80200980300A00320B00300C00300D00300E803008A04020803900480808010B80400C00400") // d, _ := hex.DecodeString("08097800C80100F00100F80100900200C80200980300A00320B00300C00300D00300E803008A04020803900480808010B80400C00400")
r = append(r, &msg.Elem{ r = append(r, &msg.Elem{
GeneralFlags: &msg.GeneralFlags{ GeneralFlags: &msg.GeneralFlags{
PbReserve: []byte{ PbReserve: []byte{
@ -590,7 +590,7 @@ func (forMsg *ForwardMessage) CalculateValidationDataForward(seq, random int32,
} }
func (forMsg *ForwardMessage) packForwardMsg(seq int32, random int32, groupCode int64) []*msg.Message { func (forMsg *ForwardMessage) packForwardMsg(seq int32, random int32, groupCode int64) []*msg.Message {
var msgs = make([]*msg.Message, 0, len(forMsg.Nodes)) msgs := make([]*msg.Message, 0, len(forMsg.Nodes))
for _, node := range forMsg.Nodes { for _, node := range forMsg.Nodes {
msgs = append(msgs, &msg.Message{ msgs = append(msgs, &msg.Message{
Head: &msg.MessageHead{ Head: &msg.MessageHead{

View File

@ -8,9 +8,11 @@ import (
"google.golang.org/protobuf/proto" "google.golang.org/protobuf/proto"
) )
var imgOld = []byte{0x15, 0x36, 0x20, 0x39, 0x32, 0x6B, 0x41, 0x31, 0x00, 0x38, 0x37, 0x32, 0x66, 0x30, 0x36, 0x36, 0x30, 0x33, 0x61, 0x65, 0x31, 0x30, 0x33, 0x62, 0x37, 0x20, 0x20, 0x20, 0x20, 0x20, var imgOld = []byte{
0x15, 0x36, 0x20, 0x39, 0x32, 0x6B, 0x41, 0x31, 0x00, 0x38, 0x37, 0x32, 0x66, 0x30, 0x36, 0x36, 0x30, 0x33, 0x61, 0x65, 0x31, 0x30, 0x33, 0x62, 0x37, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x35, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7B, 0x30, 0x31, 0x45, 0x39, 0x34, 0x35, 0x31, 0x42, 0x2D, 0x37, 0x30, 0x45, 0x44, 0x20, 0x35, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7B, 0x30, 0x31, 0x45, 0x39, 0x34, 0x35, 0x31, 0x42, 0x2D, 0x37, 0x30, 0x45, 0x44,
0x2D, 0x45, 0x41, 0x45, 0x33, 0x2D, 0x42, 0x33, 0x37, 0x43, 0x2D, 0x31, 0x30, 0x31, 0x46, 0x31, 0x45, 0x45, 0x42, 0x46, 0x35, 0x42, 0x35, 0x7D, 0x2E, 0x70, 0x6E, 0x67, 0x41} 0x2D, 0x45, 0x41, 0x45, 0x33, 0x2D, 0x42, 0x33, 0x37, 0x43, 0x2D, 0x31, 0x30, 0x31, 0x46, 0x31, 0x45, 0x45, 0x42, 0x46, 0x35, 0x42, 0x35, 0x7D, 0x2E, 0x70, 0x6E, 0x67, 0x41,
}
func (e *TextElement) Pack() (r []*msg.Elem) { func (e *TextElement) Pack() (r []*msg.Elem) {
r = append(r, &msg.Elem{ r = append(r, &msg.Elem{
@ -93,7 +95,7 @@ func (e *GroupImageElement) Pack() (r []*msg.Elem) {
CustomFace: &msg.CustomFace{ CustomFace: &msg.CustomFace{
FileType: proto.Int32(66), FileType: proto.Int32(66),
Useful: proto.Int32(1), Useful: proto.Int32(1),
//Origin: 1, // Origin: 1,
BizType: proto.Int32(5), BizType: proto.Int32(5),
Width: &e.Width, Width: &e.Width,
Height: &e.Height, Height: &e.Height,
@ -103,7 +105,7 @@ func (e *GroupImageElement) Pack() (r []*msg.Elem) {
Size: &e.Size, Size: &e.Size,
Md5: e.Md5, Md5: e.Md5,
Flag: make([]byte, 4), Flag: make([]byte, 4),
//OldData: imgOld, // OldData: imgOld,
}, },
}) })
return return
@ -252,7 +254,7 @@ func (e *GroupShowPicElement) Pack() (r []*msg.Elem) {
Size: &e.Size, Size: &e.Size,
Md5: e.Md5, Md5: e.Md5,
Flag: []byte{0x11, 0x00, 0x00, 0x00}, Flag: []byte{0x11, 0x00, 0x00, 0x00},
//OldData: imgOld, // OldData: imgOld,
PbReserve: reserve, PbReserve: reserve,
}, },
}) })

View File

@ -96,7 +96,7 @@ func (e *EncryptECDH) FetchPubKey(uin int64) {
return return
} }
defer resp.Body.Close() defer resp.Body.Close()
var pubKey = pubKeyResp{} pubKey := pubKeyResp{}
err = jsoniter.NewDecoder(resp.Body).Decode(&pubKey) err = jsoniter.NewDecoder(resp.Body).Decode(&pubKey)
if err != nil { if err != nil {
return return

View File

@ -8,11 +8,13 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
) )
var ErrUnknownFlag = errors.New("unknown flag") var (
var ErrInvalidPayload = errors.New("invalid payload") ErrUnknownFlag = errors.New("unknown flag")
var ErrDecryptFailed = errors.New("decrypt failed") ErrInvalidPayload = errors.New("invalid payload")
var ErrSessionExpired = errors.New("session expired") ErrDecryptFailed = errors.New("decrypt failed")
var ErrPacketDropped = errors.New("packet dropped") ErrSessionExpired = errors.New("session expired")
ErrPacketDropped = errors.New("packet dropped")
)
type ISendingPacket interface { type ISendingPacket interface {
CommandId() uint16 CommandId() uint16
@ -109,7 +111,7 @@ func ParseIncomingPacket(payload, d2key []byte) (*IncomingPacket, error) {
flag1 := reader.ReadInt32() flag1 := reader.ReadInt32()
flag2 := reader.ReadByte() flag2 := reader.ReadByte()
if reader.ReadByte() != 0 { // flag3 if reader.ReadByte() != 0 { // flag3
//return nil, errors.WithStack(ErrUnknownFlag) // return nil, errors.WithStack(ErrUnknownFlag)
} }
reader.ReadString() // uin string reader.ReadString() // uin string
decrypted := func() (data []byte) { decrypted := func() (data []byte) {

View File

@ -3,6 +3,7 @@ package utils
import ( import (
"bytes" "bytes"
"compress/gzip" "compress/gzip"
"io"
"io/ioutil" "io/ioutil"
"net/http" "net/http"
"strings" "strings"
@ -19,32 +20,12 @@ var client = &http.Client{
// HttpGetBytes 带 cookie 的 GET 请求 // HttpGetBytes 带 cookie 的 GET 请求
func HttpGetBytes(url, cookie string) ([]byte, error) { func HttpGetBytes(url, cookie string) ([]byte, error) {
req, err := http.NewRequest("GET", url, nil) body, err := HTTPGetReadCloser(url, cookie)
defer func() { _ = body.Close() }()
if err != nil { if err != nil {
return nil, err return nil, err
} }
req.Header["User-Agent"] = []string{"QQ/8.2.0.1296 CFNetwork/1126"} return io.ReadAll(body)
req.Header["Net-Type"] = []string{"Wifi"}
if cookie != "" {
req.Header["Cookie"] = []string{cookie}
}
resp, err := client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
if strings.Contains(resp.Header.Get("Content-Encoding"), "gzip") {
buffer := bytes.NewBuffer(body)
r, _ := gzip.NewReader(buffer)
defer r.Close()
unCom, err := ioutil.ReadAll(r)
return unCom, err
}
return body, nil
} }
func HttpPostBytes(url string, data []byte) ([]byte, error) { func HttpPostBytes(url string, data []byte) ([]byte, error) {
@ -105,3 +86,52 @@ func HttpPostBytesWithCookie(url string, data []byte, cookie string, contentType
} }
return body, nil return body, nil
} }
type gzipCloser struct {
f io.Closer
r *gzip.Reader
}
// NewGzipReadCloser 从 io.ReadCloser 创建 gunzip io.ReadCloser
func NewGzipReadCloser(reader io.ReadCloser) (io.ReadCloser, error) {
gzipReader, err := gzip.NewReader(reader)
if err != nil {
return nil, err
}
return &gzipCloser{
f: reader,
r: gzipReader,
}, nil
}
// Read impls io.Reader
func (g *gzipCloser) Read(p []byte) (n int, err error) {
return g.r.Read(p)
}
// Close impls io.Closer
func (g *gzipCloser) Close() error {
_ = g.f.Close()
return g.r.Close()
}
// HTTPGetReadCloser 从 Http url 获取 io.ReadCloser
func HTTPGetReadCloser(url string, cookie string) (io.ReadCloser, error) {
req, err := http.NewRequest("GET", url, nil)
if err != nil {
return nil, err
}
req.Header["User-Agent"] = []string{"QQ/8.2.0.1296 CFNetwork/1126"}
req.Header["Net-Type"] = []string{"Wifi"}
if cookie != "" {
req.Header["Cookie"] = []string{cookie}
}
resp, err := client.Do(req)
if err != nil {
return nil, err
}
if strings.Contains(resp.Header.Get("Content-Encoding"), "gzip") {
return NewGzipReadCloser(resp.Body)
}
return resp.Body, err
}