github.com/Mrs4s/MiraiGo@v0.0.0-20240226124653-54bdd873e3fe/client/group_file.go (about) 1 package client 2 3 import ( 4 "encoding/hex" 5 "fmt" 6 "os" 7 "runtime/debug" 8 9 "github.com/pkg/errors" 10 11 "github.com/Mrs4s/MiraiGo/client/internal/network" 12 "github.com/Mrs4s/MiraiGo/client/pb/oidb" 13 "github.com/Mrs4s/MiraiGo/internal/proto" 14 "github.com/Mrs4s/MiraiGo/message" 15 ) 16 17 type ( 18 GroupFileSystem struct { 19 FileCount uint32 `json:"file_count"` 20 LimitCount uint32 `json:"limit_count"` 21 UsedSpace uint64 `json:"used_space"` 22 TotalSpace uint64 `json:"total_space"` 23 GroupCode int64 `json:"group_id"` 24 25 client *QQClient 26 } 27 28 GroupFile struct { 29 GroupCode int64 `json:"group_id"` 30 FileId string `json:"file_id"` 31 FileName string `json:"file_name"` 32 BusId int32 `json:"busid"` 33 FileSize int64 `json:"file_size"` 34 UploadTime int64 `json:"upload_time"` 35 DeadTime int64 `json:"dead_time"` 36 ModifyTime int64 `json:"modify_time"` 37 DownloadTimes int64 `json:"download_times"` 38 Uploader int64 `json:"uploader"` 39 UploaderName string `json:"uploader_name"` 40 } 41 42 GroupFolder struct { 43 GroupCode int64 `json:"group_id"` 44 FolderId string `json:"folder_id"` 45 FolderName string `json:"folder_name"` 46 CreateTime int64 `json:"create_time"` 47 Creator int64 `json:"creator"` 48 CreatorName string `json:"creator_name"` 49 TotalFileCount uint32 `json:"total_file_count"` 50 } 51 ) 52 53 func init() { 54 decoders["OidbSvc.0x6d8_1"] = decodeOIDB6d81Response 55 decoders["OidbSvc.0x6d6_0"] = decodeOIDB6d60Response 56 decoders["OidbSvc.0x6d6_2"] = decodeOIDB6d62Response 57 decoders["OidbSvc.0x6d6_3"] = decodeOIDB6d63Response 58 decoders["OidbSvc.0x6d6_4"] = decodeOIDB6d64Response 59 decoders["OidbSvc.0x6d6_5"] = decodeOIDB6d65Response 60 decoders["OidbSvc.0x6d7_0"] = decodeOIDB6d7Response 61 decoders["OidbSvc.0x6d7_1"] = decodeOIDB6d7Response 62 decoders["OidbSvc.0x6d7_2"] = decodeOIDB6d7Response 63 decoders["OidbSvc.0x6d9_4"] = ignoreDecoder 64 } 65 66 func (c *QQClient) GetGroupFileSystem(groupCode int64) (fs *GroupFileSystem, err error) { 67 defer func() { 68 if pan := recover(); pan != nil { 69 c.error("get group fs error: %v\n%s", pan, debug.Stack()) 70 err = errors.New("fs error") 71 } 72 }() 73 g := c.FindGroup(groupCode) 74 if g == nil { 75 return nil, errors.New("group not found") 76 } 77 rsp, e := c.sendAndWait(c.buildGroupFileCountRequestPacket(groupCode)) 78 if e != nil { 79 return nil, e 80 } 81 fs = &GroupFileSystem{ 82 FileCount: rsp.(*oidb.D6D8RspBody).FileCountRsp.AllFileCount.Unwrap(), 83 LimitCount: rsp.(*oidb.D6D8RspBody).FileCountRsp.LimitCount.Unwrap(), 84 GroupCode: groupCode, 85 client: c, 86 } 87 rsp, err = c.sendAndWait(c.buildGroupFileSpaceRequestPacket(groupCode)) 88 if err != nil { 89 return nil, err 90 } 91 fs.TotalSpace = rsp.(*oidb.D6D8RspBody).GroupSpaceRsp.TotalSpace.Unwrap() 92 fs.UsedSpace = rsp.(*oidb.D6D8RspBody).GroupSpaceRsp.UsedSpace.Unwrap() 93 return fs, nil 94 } 95 96 func (c *QQClient) GetGroupFileUrl(groupCode int64, fileId string, busId int32) string { 97 i, err := c.sendAndWait(c.buildGroupFileDownloadReqPacket(groupCode, fileId, busId)) 98 if err != nil { 99 return "" 100 } 101 url := i.(string) 102 url += fmt.Sprintf("?fname=%x", fileId) 103 return url 104 } 105 106 func (fs *GroupFileSystem) Root() ([]*GroupFile, []*GroupFolder, error) { 107 return fs.GetFilesByFolder("/") 108 } 109 110 func (fs *GroupFileSystem) GetFilesByFolder(folderID string) ([]*GroupFile, []*GroupFolder, error) { 111 var startIndex uint32 = 0 112 var files []*GroupFile 113 var folders []*GroupFolder 114 for { 115 i, err := fs.client.sendAndWait(fs.client.buildGroupFileListRequestPacket(fs.GroupCode, folderID, startIndex)) 116 if err != nil { 117 return nil, nil, err 118 } 119 rsp := i.(*oidb.D6D8RspBody) 120 if rsp.FileListInfoRsp == nil { 121 break 122 } 123 for _, item := range rsp.FileListInfoRsp.ItemList { 124 if item.FileInfo != nil { 125 files = append(files, &GroupFile{ 126 GroupCode: fs.GroupCode, 127 FileId: item.FileInfo.FileId.Unwrap(), 128 FileName: item.FileInfo.FileName.Unwrap(), 129 BusId: int32(item.FileInfo.BusId.Unwrap()), 130 FileSize: int64(item.FileInfo.FileSize.Unwrap()), 131 UploadTime: int64(item.FileInfo.UploadTime.Unwrap()), 132 DeadTime: int64(item.FileInfo.DeadTime.Unwrap()), 133 ModifyTime: int64(item.FileInfo.ModifyTime.Unwrap()), 134 DownloadTimes: int64(item.FileInfo.DownloadTimes.Unwrap()), 135 Uploader: int64(item.FileInfo.UploaderUin.Unwrap()), 136 UploaderName: item.FileInfo.UploaderName.Unwrap(), 137 }) 138 } 139 if item.FolderInfo != nil { 140 folders = append(folders, &GroupFolder{ 141 GroupCode: fs.GroupCode, 142 FolderId: item.FolderInfo.FolderId.Unwrap(), 143 FolderName: item.FolderInfo.FolderName.Unwrap(), 144 CreateTime: int64(item.FolderInfo.CreateTime.Unwrap()), 145 Creator: int64(item.FolderInfo.CreateUin.Unwrap()), 146 CreatorName: item.FolderInfo.CreatorName.Unwrap(), 147 TotalFileCount: item.FolderInfo.TotalFileCount.Unwrap(), 148 }) 149 } 150 } 151 if rsp.FileListInfoRsp.IsEnd.Unwrap() { 152 break 153 } 154 startIndex = rsp.FileListInfoRsp.NextIndex.Unwrap() 155 } 156 return files, folders, nil 157 } 158 159 func (fs *GroupFileSystem) UploadFile(p, name, folderId string) error { 160 file, err := os.OpenFile(p, os.O_RDONLY, 0o666) 161 if err != nil { 162 return errors.Wrap(err, "open file error") 163 } 164 defer func() { _ = file.Close() }() 165 f := &LocalFile{ 166 FileName: name, 167 Body: file, 168 RemoteFolder: folderId, 169 } 170 target := message.Source{ 171 SourceType: message.SourceGroup, 172 PrimaryID: fs.GroupCode, 173 } 174 return fs.client.UploadFile(target, f) 175 } 176 177 func (fs *GroupFileSystem) GetDownloadUrl(file *GroupFile) string { 178 return fs.client.GetGroupFileUrl(file.GroupCode, file.FileId, file.BusId) 179 } 180 181 func (fs *GroupFileSystem) CreateFolder(parentFolder, name string) error { 182 if _, err := fs.client.sendAndWait(fs.client.buildGroupFileCreateFolderPacket(fs.GroupCode, parentFolder, name)); err != nil { 183 return errors.Wrap(err, "create folder error") 184 } 185 return nil 186 } 187 188 func (fs *GroupFileSystem) RenameFolder(folderId, newName string) error { 189 if _, err := fs.client.sendAndWait(fs.client.buildGroupFileRenameFolderPacket(fs.GroupCode, folderId, newName)); err != nil { 190 return errors.Wrap(err, "rename folder error") 191 } 192 return nil 193 } 194 195 func (fs *GroupFileSystem) DeleteFolder(folderId string) error { 196 if _, err := fs.client.sendAndWait(fs.client.buildGroupFileDeleteFolderPacket(fs.GroupCode, folderId)); err != nil { 197 return errors.Wrap(err, "rename folder error") 198 } 199 return nil 200 } 201 202 // DeleteFile 删除群文件,需要管理权限. 203 // 返回错误, 空为删除成功 204 func (fs *GroupFileSystem) DeleteFile(parentFolderID, fileId string, busId int32) string { 205 i, err := fs.client.sendAndWait(fs.client.buildGroupFileDeleteReqPacket(fs.GroupCode, parentFolderID, fileId, busId)) 206 if err != nil { 207 return err.Error() 208 } 209 return i.(string) 210 } 211 212 // RenameFile 重命名群文件,需要管理权限或者是自己发的文件. 213 // 返回错误, 空为重命名成功 214 func (fs *GroupFileSystem) RenameFile(parentFolderID, fileId string, busId int32, newFileName string) string { 215 i, err := fs.client.sendAndWait(fs.client.buildGroupFileRenameReqPacket(fs.GroupCode, parentFolderID, fileId, busId, newFileName)) 216 if err != nil { 217 return err.Error() 218 } 219 return i.(string) 220 } 221 222 // MoveFile 移动群文件,需要管理权限或者是自己发的文件. 223 // 返回错误, 空为移动成功 224 func (fs *GroupFileSystem) MoveFile(parentFolderID, fileId string, busId int32, DestFolderId string) string { 225 i, err := fs.client.sendAndWait(fs.client.buildGroupFileMoveReqPacket(fs.GroupCode, parentFolderID, fileId, busId, DestFolderId)) 226 if err != nil { 227 return err.Error() 228 } 229 return i.(string) 230 } 231 232 func (c *QQClient) buildGroupFileUploadReqPacket(groupCode int64, file *LocalFile) (uint16, []byte) { 233 body := &oidb.D6D6ReqBody{UploadFileReq: &oidb.UploadFileReqBody{ 234 GroupCode: proto.Some(groupCode), 235 AppId: proto.Int32(3), 236 BusId: proto.Int32(102), 237 Entrance: proto.Int32(5), 238 ParentFolderId: proto.Some(file.RemoteFolder), 239 FileName: proto.Some(file.FileName), 240 LocalPath: proto.String("/storage/emulated/0/Pictures/files/s/" + file.FileName), 241 Int64FileSize: proto.Some(file.size), 242 Sha: file.sha1, 243 Md5: file.md5, 244 SupportMultiUpload: proto.Bool(true), 245 }} 246 payload := c.packOIDBPackageProto(1750, 0, body) 247 return c.uniPacket("OidbSvc.0x6d6_0", payload) 248 } 249 250 func (c *QQClient) buildGroupFileFeedsRequest(groupCode int64, fileID string, busId, msgRand int32) (uint16, []byte) { 251 req := c.packOIDBPackageProto(1753, 4, &oidb.D6D9ReqBody{FeedsInfoReq: &oidb.FeedsReqBody{ 252 GroupCode: proto.Uint64(uint64(groupCode)), 253 AppId: proto.Uint32(3), 254 FeedsInfoList: []*oidb.GroupFileFeedsInfo{{ 255 FileId: proto.Some(fileID), 256 FeedFlag: proto.Uint32(1), 257 BusId: proto.Uint32(uint32(busId)), 258 MsgRandom: proto.Uint32(uint32(msgRand)), 259 }}, 260 }}) 261 return c.uniPacket("OidbSvc.0x6d9_4", req) 262 } 263 264 // OidbSvc.0x6d8_1 265 func (c *QQClient) buildGroupFileListRequestPacket(groupCode int64, folderID string, startIndex uint32) (uint16, []byte) { 266 body := &oidb.D6D8ReqBody{FileListInfoReq: &oidb.GetFileListReqBody{ 267 GroupCode: proto.Uint64(uint64(groupCode)), 268 AppId: proto.Uint32(3), 269 FolderId: proto.Some(folderID), 270 FileCount: proto.Uint32(20), 271 AllFileCount: proto.Uint32(0), 272 ReqFrom: proto.Uint32(3), 273 SortBy: proto.Uint32(1), 274 FilterCode: proto.Uint32(0), 275 Uin: proto.Uint64(0), 276 StartIndex: proto.Some(startIndex), 277 Context: EmptyBytes, 278 }} 279 payload := c.packOIDBPackageProto(1752, 1, body) 280 return c.uniPacket("OidbSvc.0x6d8_1", payload) 281 } 282 283 func (c *QQClient) buildGroupFileCountRequestPacket(groupCode int64) (uint16, []byte) { 284 body := &oidb.D6D8ReqBody{ 285 GroupFileCountReq: &oidb.GetFileCountReqBody{ 286 GroupCode: proto.Uint64(uint64(groupCode)), 287 AppId: proto.Uint32(3), 288 BusId: proto.Uint32(0), 289 }, 290 } 291 payload := c.packOIDBPackageProto(1752, 2, body) 292 return c.uniPacket("OidbSvc.0x6d8_1", payload) 293 } 294 295 func (c *QQClient) buildGroupFileSpaceRequestPacket(groupCode int64) (uint16, []byte) { 296 body := &oidb.D6D8ReqBody{GroupSpaceReq: &oidb.GetSpaceReqBody{ 297 GroupCode: proto.Uint64(uint64(groupCode)), 298 AppId: proto.Uint32(3), 299 }} 300 payload := c.packOIDBPackageProto(1752, 3, body) 301 return c.uniPacket("OidbSvc.0x6d8_1", payload) 302 } 303 304 func (c *QQClient) buildGroupFileCreateFolderPacket(groupCode int64, parentFolder, name string) (uint16, []byte) { 305 payload := c.packOIDBPackageProto(1751, 0, &oidb.D6D7ReqBody{CreateFolderReq: &oidb.CreateFolderReqBody{ 306 GroupCode: proto.Uint64(uint64(groupCode)), 307 AppId: proto.Uint32(3), 308 ParentFolderId: proto.Some(parentFolder), 309 FolderName: proto.Some(name), 310 }}) 311 return c.uniPacket("OidbSvc.0x6d7_0", payload) 312 } 313 314 func (c *QQClient) buildGroupFileRenameFolderPacket(groupCode int64, folderId, newName string) (uint16, []byte) { 315 payload := c.packOIDBPackageProto(1751, 2, &oidb.D6D7ReqBody{RenameFolderReq: &oidb.RenameFolderReqBody{ 316 GroupCode: proto.Uint64(uint64(groupCode)), 317 AppId: proto.Uint32(3), 318 FolderId: proto.String(folderId), 319 NewFolderName: proto.String(newName), 320 }}) 321 return c.uniPacket("OidbSvc.0x6d7_2", payload) 322 } 323 324 func (c *QQClient) buildGroupFileDeleteFolderPacket(groupCode int64, folderId string) (uint16, []byte) { 325 payload := c.packOIDBPackageProto(1751, 1, &oidb.D6D7ReqBody{DeleteFolderReq: &oidb.DeleteFolderReqBody{ 326 GroupCode: proto.Uint64(uint64(groupCode)), 327 AppId: proto.Uint32(3), 328 FolderId: proto.String(folderId), 329 }}) 330 return c.uniPacket("OidbSvc.0x6d7_1", payload) 331 } 332 333 // OidbSvc.0x6d6_2 334 func (c *QQClient) buildGroupFileDownloadReqPacket(groupCode int64, fileId string, busId int32) (uint16, []byte) { 335 body := &oidb.D6D6ReqBody{ 336 DownloadFileReq: &oidb.DownloadFileReqBody{ 337 GroupCode: proto.Some(groupCode), 338 AppId: proto.Int32(3), 339 BusId: proto.Some(busId), 340 FileId: proto.Some(fileId), 341 }, 342 } 343 payload := c.packOIDBPackageProto(1750, 2, body) 344 return c.uniPacket("OidbSvc.0x6d6_2", payload) 345 } 346 347 func (c *QQClient) buildGroupFileDeleteReqPacket(groupCode int64, parentFolderId, fileId string, busId int32) (uint16, []byte) { 348 body := &oidb.D6D6ReqBody{DeleteFileReq: &oidb.DeleteFileReqBody{ 349 GroupCode: proto.Some(groupCode), 350 AppId: proto.Int32(3), 351 BusId: proto.Some(busId), 352 ParentFolderId: proto.Some(parentFolderId), 353 FileId: proto.Some(fileId), 354 }} 355 payload := c.packOIDBPackageProto(1750, 3, body) 356 return c.uniPacket("OidbSvc.0x6d6_3", payload) 357 } 358 359 func (c *QQClient) buildGroupFileRenameReqPacket(groupCode int64, parentFolderId string, fileId string, busId int32, newFileName string) (uint16, []byte) { 360 body := &oidb.D6D6ReqBody{RenameFileReq: &oidb.RenameFileReqBody{ 361 GroupCode: proto.Some(groupCode), 362 AppId: proto.Int32(5), 363 BusId: proto.Some(busId), 364 FileId: proto.Some(fileId), 365 ParentFolderId: proto.Some(parentFolderId), 366 NewFileName: proto.Some(newFileName), 367 }} 368 payload := c.packOIDBPackageProto(1750, 4, body) 369 return c.uniPacket("OidbSvc.0x6d6_4", payload) 370 } 371 372 func (c *QQClient) buildGroupFileMoveReqPacket(groupCode int64, parentFolderId string, fileId string, busId int32, DestFolderId string) (uint16, []byte) { 373 body := &oidb.D6D6ReqBody{MoveFileReq: &oidb.MoveFileReqBody{ 374 GroupCode: proto.Some(groupCode), 375 AppId: proto.Int32(5), 376 BusId: proto.Some(busId), 377 FileId: proto.Some(fileId), 378 ParentFolderId: proto.Some(parentFolderId), 379 DestFolderId: proto.Some(DestFolderId), 380 }} 381 payload := c.packOIDBPackageProto(1750, 5, body) 382 return c.uniPacket("OidbSvc.0x6d6_5", payload) 383 } 384 385 // GroupFileListRespPacket 386 func decodeOIDB6d81Response(_ *QQClient, pkt *network.Packet) (any, error) { 387 rsp := oidb.D6D8RspBody{} 388 err := unpackOIDBPackage(pkt.Payload, &rsp) 389 if err != nil { 390 return nil, err 391 } 392 return &rsp, nil 393 } 394 395 // OidbSvc.0x6d6_2 GroupFileDownloadRespPacket 396 func decodeOIDB6d62Response(_ *QQClient, pkt *network.Packet) (any, error) { 397 rsp := oidb.D6D6RspBody{} 398 err := unpackOIDBPackage(pkt.Payload, &rsp) 399 if err != nil { 400 return nil, err 401 } 402 if rsp.DownloadFileRsp.DownloadUrl == nil { 403 return nil, errors.New(rsp.DownloadFileRsp.ClientWording.Unwrap()) 404 } 405 ip := rsp.DownloadFileRsp.DownloadIp.Unwrap() 406 url := hex.EncodeToString(rsp.DownloadFileRsp.DownloadUrl) 407 return fmt.Sprintf("http://%s/ftn_handler/%s/", ip, url), nil 408 } 409 410 // GroupFileDeleteRespPacket 411 func decodeOIDB6d63Response(_ *QQClient, pkt *network.Packet) (any, error) { 412 rsp := oidb.D6D6RspBody{} 413 err := unpackOIDBPackage(pkt.Payload, &rsp) 414 if err != nil { 415 return nil, err 416 } 417 return rsp.DeleteFileRsp.ClientWording.Unwrap(), nil 418 } 419 420 // GroupFileUploadRespPacket 421 func decodeOIDB6d60Response(_ *QQClient, pkt *network.Packet) (any, error) { 422 rsp := oidb.D6D6RspBody{} 423 err := unpackOIDBPackage(pkt.Payload, &rsp) 424 if err != nil { 425 return nil, err 426 } 427 u := rsp.UploadFileRsp 428 r := &fileUploadRsp{ 429 Existed: u.BoolFileExist.Unwrap(), 430 BusID: u.BusId.Unwrap(), 431 Uuid: []byte(u.FileId.Unwrap()), 432 UploadKey: u.CheckKey, 433 UploadIpLanV4: u.UploadIpLanV4, 434 UploadPort: u.UploadPort.Unwrap(), 435 } 436 return r, nil 437 } 438 439 // GroupFileCreateFolderPacket, GroupFileDeleteFolderPacket, GroupFileRenameFolderPacket 440 func decodeOIDB6d7Response(_ *QQClient, pkt *network.Packet) (any, error) { 441 rsp := oidb.D6D7RspBody{} 442 err := unpackOIDBPackage(pkt.Payload, &rsp) 443 if err != nil { 444 return nil, err 445 } 446 if createRsp := rsp.CreateFolderRsp; createRsp != nil { 447 if retCode := createRsp.RetCode.Unwrap(); retCode != 0 { 448 return nil, errors.Errorf("create folder error: %v", retCode) 449 } 450 } 451 if renameRsp := rsp.RenameFolderRsp; renameRsp != nil { 452 if retCode := renameRsp.RetCode.Unwrap(); retCode != 0 { 453 return nil, errors.Errorf("rename folder error: %v", retCode) 454 } 455 } 456 if deleteRsp := rsp.DeleteFolderRsp; deleteRsp != nil { 457 if retCode := deleteRsp.RetCode.Unwrap(); retCode != 0 { 458 return nil, errors.Errorf("delete folder error: %v", retCode) 459 } 460 } 461 return nil, nil 462 } 463 464 // GroupFileRenameRespPacket 465 func decodeOIDB6d64Response(_ *QQClient, pkt *network.Packet) (any, error) { 466 rsp := oidb.D6D6RspBody{} 467 err := unpackOIDBPackage(pkt.Payload, &rsp) 468 if err != nil { 469 return nil, err 470 } 471 return rsp.RenameFileRsp.ClientWording.Unwrap(), nil 472 } 473 474 // GroupFileMoveRespPacket 475 func decodeOIDB6d65Response(_ *QQClient, pkt *network.Packet) (any, error) { 476 rsp := oidb.D6D6RspBody{} 477 err := unpackOIDBPackage(pkt.Payload, &rsp) 478 if err != nil { 479 return nil, err 480 } 481 return rsp.MoveFileRsp.ClientWording.Unwrap(), nil 482 }