1
0
mirror of https://github.com/Mrs4s/MiraiGo.git synced 2025-05-04 11:07:40 +08:00

client: use TCP method to upload group file

This commit is contained in:
wdvxdr 2023-02-17 18:01:43 +08:00
parent f630205782
commit 1ec3bbf188
4 changed files with 70 additions and 98 deletions

View File

@ -27,12 +27,13 @@ type Transaction struct {
} }
func (bdh *Transaction) encrypt(key []byte) error { func (bdh *Transaction) encrypt(key []byte) error {
if bdh.Encrypt { if !bdh.Encrypt {
if len(key) == 0 { return nil
return errors.New("session key not found. maybe miss some packet?")
}
bdh.Ext = binary.NewTeaCipher(key).Encrypt(bdh.Ext)
} }
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 return nil
} }
@ -88,7 +89,16 @@ func uploadBDH(s *Session, addr Addr, trans *Transaction) ([]byte, error) {
} }
ch := md5.Sum(chunk) ch := md5.Sum(chunk)
head, _ := proto.Marshal(&pb.ReqDataHighwayHead{ head, _ := proto.Marshal(&pb.ReqDataHighwayHead{
MsgBasehead: s.dataHighwayHead(_REQ_CMD_DATA, 4096, trans.CommandID, 2052), 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{ MsgSeghead: &pb.SegHead{
Filesize: trans.Size, Filesize: trans.Size,
Dataoffset: int64(offset), Dataoffset: int64(offset),
@ -100,8 +110,8 @@ func uploadBDH(s *Session, addr Addr, trans *Transaction) ([]byte, error) {
ReqExtendinfo: trans.Ext, ReqExtendinfo: trans.Ext,
}) })
offset += rl offset += rl
frame := newFrame(head, chunk) buffers := frame(head, chunk)
_, err = frame.WriteTo(conn) _, err = buffers.WriteTo(conn)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "write conn error") return nil, errors.Wrap(err, "write conn error")
} }
@ -190,7 +200,16 @@ func uploadBDHMultiThread(s *Session, addr Addr, trans *Transaction) ([]byte, er
} }
ch := md5.Sum(chunk) ch := md5.Sum(chunk)
head, _ := proto.Marshal(&pb.ReqDataHighwayHead{ head, _ := proto.Marshal(&pb.ReqDataHighwayHead{
MsgBasehead: s.dataHighwayHead(_REQ_CMD_DATA, 4096, trans.CommandID, 2052), 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{ MsgSeghead: &pb.SegHead{
Filesize: trans.Size, Filesize: trans.Size,
Dataoffset: off, Dataoffset: off,
@ -201,8 +220,8 @@ func uploadBDHMultiThread(s *Session, addr Addr, trans *Transaction) ([]byte, er
}, },
ReqExtendinfo: trans.Ext, ReqExtendinfo: trans.Ext,
}) })
frame := newFrame(head, chunk) buffers := frame(head, chunk)
_, err = frame.WriteTo(conn) _, err = buffers.WriteTo(conn)
if err != nil { if err != nil {
return errors.Wrap(err, "write conn error") return errors.Wrap(err, "write conn error")
} }

View File

@ -7,7 +7,7 @@ import (
var etx = []byte{0x29} var etx = []byte{0x29}
// newFrame 包格式 // frame 包格式
// //
// - STX: 0x28(40) // - STX: 0x28(40)
// - head length // - head length
@ -17,7 +17,7 @@ var etx = []byte{0x29}
// - ETX: 0x29(41) // - ETX: 0x29(41)
// //
// 节省内存, 可被go runtime优化为writev操作 // 节省内存, 可被go runtime优化为writev操作
func newFrame(head []byte, body []byte) net.Buffers { func frame(head []byte, body []byte) net.Buffers {
buffers := make(net.Buffers, 4) buffers := make(net.Buffers, 4)
// buffer0 format: // buffer0 format:
// - STX // - STX

View File

@ -1,11 +1,8 @@
package highway package highway
import ( import (
"crypto/md5"
"fmt" "fmt"
"io"
"net" "net"
"net/http"
"sync/atomic" "sync/atomic"
"github.com/pkg/errors" "github.com/pkg/errors"
@ -42,6 +39,11 @@ type Session struct {
SsoAddr []Addr SsoAddr []Addr
seq int32 seq int32
/*
idleMu sync.Mutex
idleCount int
idle *idle
*/
} }
const highwayMaxResponseSize int32 = 1024 * 100 // 100k const highwayMaxResponseSize int32 = 1024 * 100 // 100k
@ -58,94 +60,25 @@ func (s *Session) AppendAddr(ip, port uint32) {
s.SsoAddr = append(s.SsoAddr, addr) s.SsoAddr = append(s.SsoAddr, addr)
} }
func (s *Session) UploadExciting(trans Transaction) ([]byte, error) {
return s.retry(uploadExciting, &trans)
}
func uploadExciting(s *Session, addr Addr, trans *Transaction) ([]byte, error) {
url := fmt.Sprintf("http://%v/cgi-bin/httpconn?htcmd=0x6FF0087&Uin=%v", addr.String(), s.Uin)
var rspExt []byte
var offset int64
const chunkSize = 524288
chunk := make([]byte, chunkSize)
for {
chunk = chunk[:chunkSize]
rl, err := io.ReadFull(trans.Body, chunk)
if rl == 0 {
break
}
if err == io.ErrUnexpectedEOF {
chunk = chunk[:rl]
}
ch := md5.Sum(chunk)
head, _ := proto.Marshal(&pb.ReqDataHighwayHead{
MsgBasehead: s.dataHighwayHead(_REQ_CMD_DATA, 0, trans.CommandID, 0),
MsgSeghead: &pb.SegHead{
Filesize: trans.Size,
Dataoffset: offset,
Datalength: int32(rl),
Serviceticket: trans.Ticket,
Md5: ch[:],
FileMd5: trans.Sum,
},
ReqExtendinfo: trans.Ext,
})
offset += int64(rl)
frame := newFrame(head, chunk)
req, _ := http.NewRequest(http.MethodPost, url, &frame)
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")
req.ContentLength = int64(len(head) + len(chunk) + 10)
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()
_ = r.ReadInt32()
h := r.ReadBytes(int(hl))
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 (s *Session) nextSeq() int32 { func (s *Session) nextSeq() int32 {
return atomic.AddInt32(&s.seq, 2) return atomic.AddInt32(&s.seq, 2)
} }
func (s *Session) dataHighwayHead(cmd string, flag, cmdID, locale int32) *pb.DataHighwayHead {
return &pb.DataHighwayHead{
Version: 1,
Uin: s.Uin,
Command: cmd,
Seq: s.nextSeq(),
Appid: s.AppID,
Dataflag: flag,
CommandId: cmdID,
LocaleId: locale,
}
}
func (s *Session) sendHeartbreak(conn net.Conn) error { func (s *Session) sendHeartbreak(conn net.Conn) error {
head, _ := proto.Marshal(&pb.ReqDataHighwayHead{ head, _ := proto.Marshal(&pb.ReqDataHighwayHead{
MsgBasehead: s.dataHighwayHead(_REQ_CMD_HEART_BREAK, 4096, 0, 2052), 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,
},
}) })
frame := newFrame(head, nil) buffers := frame(head, nil)
_, err := frame.WriteTo(conn) _, err := buffers.WriteTo(conn)
return err return err
} }
@ -179,3 +112,23 @@ func readResponse(r *binary.NetworkReader) (*pb.RspDataHighwayHead, error) {
} }
return rsp, nil return rsp, nil
} }
/*
const maxIdleConn = 5
type idle struct {
conn net.Conn
delay int64
next *idle
}
// getConn ...
func (s *Session) getConn() net.Conn {
s.idleMu.Lock()
defer s.idleMu.Unlock()
conn := s.idle.conn
s.idle = s.idle.next
return conn
}
*/

View File

@ -147,7 +147,7 @@ func (c *QQClient) UploadFile(target message.Source, file *LocalFile) error {
if target.SourceType == message.SourcePrivate { if target.SourceType == message.SourcePrivate {
input.CommandID = 69 input.CommandID = 69
} }
if _, err := c.highwaySession.UploadExciting(input); err != nil { if _, err := c.highwaySession.UploadBDH(input); err != nil {
return errors.Wrap(err, "upload failed") return errors.Wrap(err, "upload failed")
} }
} }