diff --git a/client/group_file.go b/client/group_file.go index c43c90e4..65060217 100644 --- a/client/group_file.go +++ b/client/group_file.go @@ -3,18 +3,15 @@ package client import ( "encoding/hex" "fmt" - "math/rand" "os" "runtime/debug" "github.com/pkg/errors" - "github.com/Mrs4s/MiraiGo/client/internal/highway" "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/proto" - "github.com/Mrs4s/MiraiGo/utils" + "github.com/Mrs4s/MiraiGo/message" ) type ( @@ -53,8 +50,6 @@ type ( } ) -var fsWaiter = utils.NewUploadWaiter() - func init() { decoders["OidbSvc.0x6d8_1"] = decodeOIDB6d81Response decoders["OidbSvc.0x6d6_0"] = decodeOIDB6d60Response @@ -160,80 +155,21 @@ func (fs *GroupFileSystem) GetFilesByFolder(folderID string) ([]*GroupFile, []*G } 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) if err != nil { return errors.Wrap(err, "open file error") } defer func() { _ = file.Close() }() - f := &FileResource{ - FileName: name, - Body: file, + f := &LocalFile{ + FileName: name, + Body: file, + RemoteFolder: folderId, } - f.init() - i, err := fs.client.sendAndWait(fs.client.buildGroupFileUploadReqPacket(folderId, fs.GroupCode, f)) - if err != nil { - return errors.Wrap(err, "query upload failed") + target := message.Source{ + SourceType: message.SourceGroup, + PrimaryID: fs.GroupCode, } - rsp := i.(*oidb.UploadFileRspBody) - if !rsp.BoolFileExist.Unwrap() { - if len(rsp.UploadIpLanV4) == 0 { - return errors.New("server requires unsupported ftn upload") - } - ext, _ := proto.Marshal(&exciting.FileUploadExt{ - Unknown1: proto.Int32(100), - Unknown2: proto.Int32(1), - Entry: &exciting.FileUploadEntry{ - BusiBuff: &exciting.ExcitingBusiInfo{ - BusId: rsp.BusId, - SenderUin: proto.Some(fs.client.Uin), - ReceiverUin: proto.Some(fs.GroupCode), - GroupCode: proto.Some(fs.GroupCode), - }, - FileEntry: &exciting.ExcitingFileEntry{ - FileSize: proto.Some(f.size), - Md5: f.md5, - Sha1: f.sha1, - FileId: []byte(rsp.FileId.Unwrap()), - 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: proto.Some(name)}, - Host: &exciting.ExcitingHostConfig{Hosts: []*exciting.ExcitingHostInfo{ - { - Url: &exciting.ExcitingUrlInfo{ - Unknown: proto.Int32(1), - Host: proto.Some(rsp.UploadIpLanV4[0]), - }, - Port: rsp.UploadPort, - }, - }}, - }, - Unknown3: proto.Int32(0), - }) - input := highway.Transaction{ - CommandID: 71, - Body: file, - Size: f.size, - Sum: f.md5, - Ticket: fs.client.highwaySession.SigSession, - Ext: ext, - } - if _, err = fs.client.highwaySession.UploadExciting(input); err != nil { - return errors.Wrap(err, "upload failed") - } - } - _, pkt := fs.client.buildGroupFileFeedsRequest(fs.GroupCode, rsp.FileId.Unwrap(), rsp.BusId.Unwrap(), rand.Int31()) - return fs.client.sendPacket(pkt) + return fs.client._UploadFile(target, f) } func (fs *GroupFileSystem) GetDownloadUrl(file *GroupFile) string { @@ -271,13 +207,13 @@ func (fs *GroupFileSystem) DeleteFile(parentFolderID, fileId string, busId int32 return i.(string) } -func (c *QQClient) buildGroupFileUploadReqPacket(parentFolderID string, groupCode int64, file *FileResource) (uint16, []byte) { +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(parentFolderID), + 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), @@ -437,7 +373,16 @@ func decodeOIDB6d60Response(_ *QQClient, _ *network.IncomingPacketInfo, payload if err != nil { return nil, err } - return rsp.UploadFileRsp, nil + u := rsp.UploadFileRsp + r := &fileUploadRsp{ + 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 } func decodeOIDB6d7Response(_ *QQClient, _ *network.IncomingPacketInfo, payload []byte) (any, error) { diff --git a/client/upload_file.go b/client/upload_file.go index 5574f602..c986198c 100644 --- a/client/upload_file.go +++ b/client/upload_file.go @@ -5,6 +5,7 @@ import ( "crypto/sha1" "fmt" "io" + "math/rand" "github.com/pkg/errors" @@ -14,32 +15,34 @@ import ( "github.com/Mrs4s/MiraiGo/client/pb/exciting" "github.com/Mrs4s/MiraiGo/internal/proto" "github.com/Mrs4s/MiraiGo/message" + "github.com/Mrs4s/MiraiGo/utils" ) func init() { decoders["OfflineFilleHandleSvr.pb_ftn_CMD_REQ_APPLY_UPLOAD_V3-1700"] = decodePrivateFileUploadReq } -type FileResource struct { - FileName string - Body io.ReadSeeker // FileResource content body - size int64 - md5 []byte - sha1 []byte +type LocalFile struct { + FileName string + Body io.ReadSeeker // LocalFile content body + RemoteFolder string + size int64 + md5 []byte + sha1 []byte } type fileUploadRsp struct { - existed bool - busid int32 - uuid []byte - uploadKey []byte + Existed bool + BusID int32 + Uuid []byte + UploadKey []byte // upload group file need UploadIpLanV4 []string UploadPort int32 } -func (f *FileResource) init() { +func (f *LocalFile) init() { md5H := md5.New() sha1H := sha1.New() @@ -52,28 +55,35 @@ func (f *FileResource) init() { f.sha1 = sha1H.Sum(nil) } -func (c *QQClient) _UploadFile(target message.Source, file *FileResource) error { +var fsWaiter = utils.NewUploadWaiter() + +func (c *QQClient) _UploadFile(target message.Source, file *LocalFile) error { file.init() // 同文件等待其他线程上传 fkey := string(file.sha1) fsWaiter.Wait(fkey) defer fsWaiter.Done(fkey) - var rsp *fileUploadRsp + var seq uint16 + var pkt []byte if target.SourceType == message.SourcePrivate { - i, err := c.sendAndWait(c.buildPrivateFileUploadReqPacket(target, file)) - if err != nil { - return err - } - rsp = i.(*fileUploadRsp) + seq, pkt = c.buildPrivateFileUploadReqPacket(target, file) + } else { + seq, pkt = c.buildGroupFileUploadReqPacket(target.PrimaryID, file) } - if !rsp.existed { + i, err := c.sendAndWait(seq, pkt) + if err != nil { + return errors.Wrap(err, "query upload failed") + } + rsp := i.(*fileUploadRsp) + + if !rsp.Existed { ext := &exciting.FileUploadExt{ Unknown1: proto.Int32(100), Unknown2: proto.Int32(2), Entry: &exciting.FileUploadEntry{ BusiBuff: &exciting.ExcitingBusiInfo{ - BusId: proto.Int32(rsp.busid), + BusId: proto.Int32(rsp.BusID), SenderUin: proto.Some(c.Uin), ReceiverUin: proto.Some(target.PrimaryID), GroupCode: proto.Int64(0), @@ -82,8 +92,8 @@ func (c *QQClient) _UploadFile(target message.Source, file *FileResource) error FileSize: proto.Some(file.size), Md5: file.md5, Sha1: file.sha1, - FileId: rsp.uuid, - UploadKey: rsp.uploadKey, + FileId: rsp.Uuid, + UploadKey: rsp.UploadKey, }, ClientInfo: &exciting.ExcitingClientInfo{ ClientType: proto.Int32(2), @@ -133,10 +143,14 @@ func (c *QQClient) _UploadFile(target message.Source, file *FileResource) error return errors.Wrap(err, "upload failed") } } - return nil + if target.SourceType == message.SourceGroup { + _, pkt := c.buildGroupFileFeedsRequest(target.PrimaryID, string(rsp.Uuid), rsp.BusID, rand.Int31()) + return c.sendPacket(pkt) + } + return errors.New("not implemented") } -func (c *QQClient) buildPrivateFileUploadReqPacket(target message.Source, file *FileResource) (uint16, []byte) { +func (c *QQClient) buildPrivateFileUploadReqPacket(target message.Source, file *LocalFile) (uint16, []byte) { req := cmd0x346.C346ReqBody{ Cmd: 1700, Seq: c.nextFriendSeq(), @@ -167,10 +181,10 @@ func decodePrivateFileUploadReq(_ *QQClient, _ *network.IncomingPacketInfo, payl } v3 := rsp.ApplyUploadRspV3 r := &fileUploadRsp{ - existed: v3.BoolFileExist, - busid: 3, - uuid: v3.Uuid, - uploadKey: v3.MediaPlateformUploadKey, + Existed: v3.BoolFileExist, + BusID: 3, + Uuid: v3.Uuid, + UploadKey: v3.MediaPlateformUploadKey, } return r, nil }