From 06c74ce03343cabf52d0d5b83f211852cccc9cf0 Mon Sep 17 00:00:00 2001 From: mangotree Date: Tue, 15 Dec 2020 20:10:49 +0800 Subject: [PATCH] feat: add drive upload file/media api Change-Id: Ib78028e02d382cc847705c7dd6b8c07043f788d4 --- README.md | 3 +- README.zh.md | 3 +- sample/api/drive.go | 136 ++++++++++++++++ service/drive/v1/api.go | 324 ++++++++++++++++++++++++++++++++++++++ service/drive/v1/model.go | 65 ++++++++ 5 files changed, 529 insertions(+), 2 deletions(-) create mode 100644 sample/api/drive.go create mode 100644 service/drive/v1/api.go create mode 100644 service/drive/v1/model.go diff --git a/README.md b/README.md index d1fc2d1f..9f24b7c5 100644 --- a/README.md +++ b/README.md @@ -76,7 +76,8 @@ $ go get -u github.com/larksuite/oapi-sdk-go | Image | v4 | [service/image](service/image)|[sample/api/image.go](sample/api/image.go)| | Contact | v3 | [service/contact](service/contact) | [sample/api/contact.go](sample/api/contact.go) | | Calendar | v4 | [service/calendar](service/calendar)|[sample/api/calendar.go](sample/api/calendar.go)| - + | Drive | v1 | [service/drive](service/drive)|[sample/api/drive.go](sample/api/drive.go)| + - Instructions for use(For`No business API SDK is generated`the processing method) - For`App Store application`, when acquiring`app_access_token`, you need `app_ticket` to start the event subscription service(`Module event`) diff --git a/README.zh.md b/README.zh.md index bf941041..d8f095bd 100644 --- a/README.zh.md +++ b/README.zh.md @@ -82,7 +82,8 @@ $ go get -u github.com/larksuite/oapi-sdk-go | 图片 | v4 | [service/image](service/image)|[sample/api/image.go](sample/api/image.go)| | 通讯录 | v3 | [service/contact](service/contact)|[sample/api/contact.go](sample/api/contact.go)| | 日历 | v4 | [service/calendar](service/calendar)|[sample/api/calendar.go](sample/api/calendar.go)| - + | 云空间文件 | v1 | [service/drive](service/drive)|[sample/api/drive.go](sample/api/drive.go)| + - 使用说明(对于`没有生成业务API SDK`的处理方式) - 对于`应用商店应用`,在获取`app_access_token`时,需要 `app_ticket`,需要启动事件订阅服务(`模块event`) diff --git a/sample/api/drive.go b/sample/api/drive.go new file mode 100644 index 00000000..f4b245d0 --- /dev/null +++ b/sample/api/drive.go @@ -0,0 +1,136 @@ +package main + +import ( + "context" + "crypto/rand" + "fmt" + "github.com/larksuite/oapi-sdk-go/api/core/request" + "github.com/larksuite/oapi-sdk-go/api/core/response" + "github.com/larksuite/oapi-sdk-go/core" + "github.com/larksuite/oapi-sdk-go/core/test" + "github.com/larksuite/oapi-sdk-go/core/tools" + drivev1 "github.com/larksuite/oapi-sdk-go/service/drive/v1" + "hash/adler32" + "io" +) + +var driveService = drivev1.NewService(test.GetInternalConf("online")) + +func main() { + testFileUploadAll() + testFileUploadPart() +} +func createRandomFileData(size int64) []byte { + randomData := make([]byte, size) + io.ReadFull(rand.Reader, randomData) + return randomData +} + +func testFileUploadAll() { + coreCtx := core.WarpContext(context.Background()) + reqCall := driveService.Files.UploadAll(coreCtx, request.SetUserAccessToken("[user_access_token]")) + + reqCall.SetParentType("explorer") + reqCall.SetParentNode("[folder_token]") + reqCall.SetFileName(fmt.Sprintf("[file_name]")) + reqCall.SetSize(1024) + + fileContent := createRandomFileData(1024) + reqCall.SetChecksum(fmt.Sprintf("%d", adler32.Checksum(fileContent))) + file := request.NewFile() + file.SetContent(fileContent) + reqCall.SetFile(file) + + result, err := reqCall.Do() + fmt.Printf("request_id:%s", coreCtx.GetRequestID()) + fmt.Printf("http status code:%d", coreCtx.GetHTTPStatusCode()) + if err != nil { + e := err.(*response.Error) + fmt.Println(tools.Prettify(e)) + return + } + fmt.Printf("reault:%s", tools.Prettify(result)) + + if len(result.FileToken) == 0 { + fmt.Printf("file token is empty") + return + } +} + +func testFileUploadPart() { + coreCtx := core.WarpContext(context.Background()) + userAccessTokenOptFn := request.SetUserAccessToken("[user_access_token]") + fileSize := 1024 + + // upload prepare + uploadPrepareReqCall := driveService.Files.UploadPrepare(coreCtx, &drivev1.UploadInfo{ + FileName: fmt.Sprintf("[file_name]"), + ParentType: "explorer", + ParentNode: "[folder_token]", + Size: fileSize, + }, userAccessTokenOptFn) + + uploadPrepareResult, err := uploadPrepareReqCall.Do() + fmt.Printf("[upload prepare] request_id:%s", coreCtx.GetRequestID()) + fmt.Printf("[upload prepare] http status code:%d", coreCtx.GetHTTPStatusCode()) + if err != nil { + e := err.(*response.Error) + fmt.Println(tools.Prettify(e)) + return + } + + fmt.Printf("[upload prepare] reault:%s", tools.Prettify(uploadPrepareResult)) + + // upload part + uploadedBlockNum := 0 + for i := 0; i < uploadPrepareResult.BlockNum; i++ { + uploadPartReqCall := driveService.Files.UploadPart(coreCtx, userAccessTokenOptFn) + uploadPartReqCall.SetUploadId(uploadPrepareResult.UploadId) + uploadPartReqCall.SetSeq(i) + //uploadPartReqCall.Set + // 最后一块 + blockSize := uploadPrepareResult.BlockSize + if i == (uploadPrepareResult.BlockNum - 1) { + blockSize = fileSize - (i * uploadPrepareResult.BlockNum) + } + uploadPartReqCall.SetSize(blockSize) + fileContent := createRandomFileData(int64(blockSize)) + file := request.NewFile().SetContent(fileContent) + + uploadPartReqCall.SetFile(file) + uploadPartReqCall.SetChecksum(fmt.Sprintf("%d", adler32.Checksum(fileContent))) + + result, err := uploadPartReqCall.Do() + fmt.Printf("[upload part[%d]] request_id:%s", i, coreCtx.GetRequestID()) + fmt.Printf("[upload part[%d]] http status code:%d", i, coreCtx.GetHTTPStatusCode()) + if err != nil { + e := err.(*response.Error) + fmt.Println(tools.Prettify(e)) + return + } + uploadedBlockNum++ + fmt.Printf("[upload part[%d]] reault:%s", i, tools.Prettify(result)) + } + + // upload finish + uploadFinishReqCall := driveService.Files.UploadFinish(coreCtx, &drivev1.FileUploadFinishReqBody{ + UploadId: uploadPrepareResult.UploadId, + BlockNum: uploadedBlockNum, + }, userAccessTokenOptFn) + + uploadFinishResult, err := uploadFinishReqCall.Do() + fmt.Printf("[upload finish] request_id:%s", coreCtx.GetRequestID()) + fmt.Printf("[upload finish] http status code:%d", coreCtx.GetHTTPStatusCode()) + if err != nil { + e := err.(*response.Error) + fmt.Println(tools.Prettify(e)) + return + } + + fmt.Printf("[upload finish] reault:%s", tools.Prettify(uploadFinishResult)) + + if len(uploadFinishResult.FileToken) == 0 { + fmt.Printf("file token is empty") + return + } +} diff --git a/service/drive/v1/api.go b/service/drive/v1/api.go new file mode 100644 index 00000000..43690e52 --- /dev/null +++ b/service/drive/v1/api.go @@ -0,0 +1,324 @@ +// Code generated by lark suite oapi sdk gen +package v1 + +import ( + "github.com/larksuite/oapi-sdk-go/api" + "github.com/larksuite/oapi-sdk-go/api/core/request" + "github.com/larksuite/oapi-sdk-go/api/core/response" + "github.com/larksuite/oapi-sdk-go/core" + "github.com/larksuite/oapi-sdk-go/core/config" + "path" +) + +const serviceBasePath = "drive/v1" + +type Service struct { + conf *config.Config + basePath string + Medias *MediaService + Files *FileService +} + +func NewService(conf *config.Config) *Service { + s := &Service{ + conf: conf, + basePath: serviceBasePath, + } + s.Medias = newMediaService(s) + s.Files = newFileService(s) + return s +} + +type MediaService struct { + service *Service +} + +func newMediaService(service *Service) *MediaService { + return &MediaService{ + service: service, + } +} + +type FileService struct { + service *Service +} + +func newFileService(service *Service) *FileService { + return &FileService{ + service: service, + } +} + +type MediaUploadPrepareReqCall struct { + ctx *core.Context + medias *MediaService + body *UploadInfo + + optFns []request.OptFn +} + +func (rc *MediaUploadPrepareReqCall) Do() (*MediaUploadPrepareResult, error) { + httpPath := path.Join(rc.medias.service.basePath, "medias/upload_prepare") + var result = &MediaUploadPrepareResult{} + req := request.NewRequest(httpPath, "POST", + []request.AccessTokenType{request.AccessTokenTypeUser}, rc.body, result, rc.optFns...) + err := api.Send(rc.ctx, rc.medias.service.conf, req) + return result, err +} + +func (medias *MediaService) UploadPrepare(ctx *core.Context, body *UploadInfo, optFns ...request.OptFn) *MediaUploadPrepareReqCall { + return &MediaUploadPrepareReqCall{ + ctx: ctx, + medias: medias, + body: body, + optFns: optFns, + } +} + +type FileUploadPrepareReqCall struct { + ctx *core.Context + files *FileService + body *UploadInfo + + optFns []request.OptFn +} + +func (rc *FileUploadPrepareReqCall) Do() (*FileUploadPrepareResult, error) { + httpPath := path.Join(rc.files.service.basePath, "files/upload_prepare") + var result = &FileUploadPrepareResult{} + req := request.NewRequest(httpPath, "POST", + []request.AccessTokenType{request.AccessTokenTypeUser}, rc.body, result, rc.optFns...) + err := api.Send(rc.ctx, rc.files.service.conf, req) + return result, err +} + +func (files *FileService) UploadPrepare(ctx *core.Context, body *UploadInfo, optFns ...request.OptFn) *FileUploadPrepareReqCall { + return &FileUploadPrepareReqCall{ + ctx: ctx, + files: files, + body: body, + optFns: optFns, + } +} + +type MediaUploadPartReqCall struct { + ctx *core.Context + medias *MediaService + body *request.FormData + + optFns []request.OptFn +} + +func (rc *MediaUploadPartReqCall) SetUploadId(uploadId string) { + rc.body.AddParam("upload_id", uploadId) +} +func (rc *MediaUploadPartReqCall) SetSeq(seq int) { + rc.body.AddParam("seq", seq) +} +func (rc *MediaUploadPartReqCall) SetSize(size int) { + rc.body.AddParam("size", size) +} +func (rc *MediaUploadPartReqCall) SetChecksum(checksum string) { + rc.body.AddParam("checksum", checksum) +} +func (rc *MediaUploadPartReqCall) SetFile(file *request.File) { + rc.body.AddFile("file", file) +} +func (rc *MediaUploadPartReqCall) Do() (*response.NoData, error) { + httpPath := path.Join(rc.medias.service.basePath, "medias/upload_part") + var result = &response.NoData{} + req := request.NewRequest(httpPath, "POST", + []request.AccessTokenType{request.AccessTokenTypeUser}, rc.body, result, rc.optFns...) + err := api.Send(rc.ctx, rc.medias.service.conf, req) + return result, err +} + +func (medias *MediaService) UploadPart(ctx *core.Context, optFns ...request.OptFn) *MediaUploadPartReqCall { + return &MediaUploadPartReqCall{ + ctx: ctx, + medias: medias, + body: request.NewFormData(), + optFns: optFns, + } +} + +type FileUploadPartReqCall struct { + ctx *core.Context + files *FileService + body *request.FormData + + optFns []request.OptFn +} + +func (rc *FileUploadPartReqCall) SetUploadId(uploadId string) { + rc.body.AddParam("upload_id", uploadId) +} +func (rc *FileUploadPartReqCall) SetSeq(seq int) { + rc.body.AddParam("seq", seq) +} +func (rc *FileUploadPartReqCall) SetSize(size int) { + rc.body.AddParam("size", size) +} +func (rc *FileUploadPartReqCall) SetChecksum(checksum string) { + rc.body.AddParam("checksum", checksum) +} +func (rc *FileUploadPartReqCall) SetFile(file *request.File) { + rc.body.AddFile("file", file) +} +func (rc *FileUploadPartReqCall) Do() (*response.NoData, error) { + httpPath := path.Join(rc.files.service.basePath, "files/upload_part") + var result = &response.NoData{} + req := request.NewRequest(httpPath, "POST", + []request.AccessTokenType{request.AccessTokenTypeUser}, rc.body, result, rc.optFns...) + err := api.Send(rc.ctx, rc.files.service.conf, req) + return result, err +} + +func (files *FileService) UploadPart(ctx *core.Context, optFns ...request.OptFn) *FileUploadPartReqCall { + return &FileUploadPartReqCall{ + ctx: ctx, + files: files, + body: request.NewFormData(), + optFns: optFns, + } +} + +type FileUploadFinishReqCall struct { + ctx *core.Context + files *FileService + body *FileUploadFinishReqBody + + optFns []request.OptFn +} + +func (rc *FileUploadFinishReqCall) Do() (*FileUploadFinishResult, error) { + httpPath := path.Join(rc.files.service.basePath, "files/upload_finish") + var result = &FileUploadFinishResult{} + req := request.NewRequest(httpPath, "POST", + []request.AccessTokenType{request.AccessTokenTypeUser}, rc.body, result, rc.optFns...) + err := api.Send(rc.ctx, rc.files.service.conf, req) + return result, err +} + +func (files *FileService) UploadFinish(ctx *core.Context, body *FileUploadFinishReqBody, optFns ...request.OptFn) *FileUploadFinishReqCall { + return &FileUploadFinishReqCall{ + ctx: ctx, + files: files, + body: body, + optFns: optFns, + } +} + +type MediaUploadFinishReqCall struct { + ctx *core.Context + medias *MediaService + body *MediaUploadFinishReqBody + + optFns []request.OptFn +} + +func (rc *MediaUploadFinishReqCall) Do() (*MediaUploadFinishResult, error) { + httpPath := path.Join(rc.medias.service.basePath, "medias/upload_finish") + var result = &MediaUploadFinishResult{} + req := request.NewRequest(httpPath, "POST", + []request.AccessTokenType{request.AccessTokenTypeUser}, rc.body, result, rc.optFns...) + err := api.Send(rc.ctx, rc.medias.service.conf, req) + return result, err +} + +func (medias *MediaService) UploadFinish(ctx *core.Context, body *MediaUploadFinishReqBody, optFns ...request.OptFn) *MediaUploadFinishReqCall { + return &MediaUploadFinishReqCall{ + ctx: ctx, + medias: medias, + body: body, + optFns: optFns, + } +} + +type MediaUploadAllReqCall struct { + ctx *core.Context + medias *MediaService + body *request.FormData + + optFns []request.OptFn +} + +func (rc *MediaUploadAllReqCall) SetFileName(fileName string) { + rc.body.AddParam("file_name", fileName) +} +func (rc *MediaUploadAllReqCall) SetParentType(parentType string) { + rc.body.AddParam("parent_type", parentType) +} +func (rc *MediaUploadAllReqCall) SetParentNode(parentNode string) { + rc.body.AddParam("parent_node", parentNode) +} +func (rc *MediaUploadAllReqCall) SetSize(size int) { + rc.body.AddParam("size", size) +} +func (rc *MediaUploadAllReqCall) SetChecksum(checksum string) { + rc.body.AddParam("checksum", checksum) +} +func (rc *MediaUploadAllReqCall) SetFile(file *request.File) { + rc.body.AddFile("file", file) +} +func (rc *MediaUploadAllReqCall) Do() (*MediaUploadAllResult, error) { + httpPath := path.Join(rc.medias.service.basePath, "medias/upload_all") + var result = &MediaUploadAllResult{} + req := request.NewRequest(httpPath, "POST", + []request.AccessTokenType{request.AccessTokenTypeUser}, rc.body, result, rc.optFns...) + err := api.Send(rc.ctx, rc.medias.service.conf, req) + return result, err +} + +func (medias *MediaService) UploadAll(ctx *core.Context, optFns ...request.OptFn) *MediaUploadAllReqCall { + return &MediaUploadAllReqCall{ + ctx: ctx, + medias: medias, + body: request.NewFormData(), + optFns: optFns, + } +} + +type FileUploadAllReqCall struct { + ctx *core.Context + files *FileService + body *request.FormData + + optFns []request.OptFn +} + +func (rc *FileUploadAllReqCall) SetFileName(fileName string) { + rc.body.AddParam("file_name", fileName) +} +func (rc *FileUploadAllReqCall) SetParentType(parentType string) { + rc.body.AddParam("parent_type", parentType) +} +func (rc *FileUploadAllReqCall) SetParentNode(parentNode string) { + rc.body.AddParam("parent_node", parentNode) +} +func (rc *FileUploadAllReqCall) SetSize(size int) { + rc.body.AddParam("size", size) +} +func (rc *FileUploadAllReqCall) SetChecksum(checksum string) { + rc.body.AddParam("checksum", checksum) +} +func (rc *FileUploadAllReqCall) SetFile(file *request.File) { + rc.body.AddFile("file", file) +} +func (rc *FileUploadAllReqCall) Do() (*FileUploadAllResult, error) { + httpPath := path.Join(rc.files.service.basePath, "files/upload_all") + var result = &FileUploadAllResult{} + req := request.NewRequest(httpPath, "POST", + []request.AccessTokenType{request.AccessTokenTypeUser}, rc.body, result, rc.optFns...) + err := api.Send(rc.ctx, rc.files.service.conf, req) + return result, err +} + +func (files *FileService) UploadAll(ctx *core.Context, optFns ...request.OptFn) *FileUploadAllReqCall { + return &FileUploadAllReqCall{ + ctx: ctx, + files: files, + body: request.NewFormData(), + optFns: optFns, + } +} diff --git a/service/drive/v1/model.go b/service/drive/v1/model.go new file mode 100644 index 00000000..653006cd --- /dev/null +++ b/service/drive/v1/model.go @@ -0,0 +1,65 @@ +// Code generated by lark suite oapi sdk gen +package v1 + +type Media struct { + FileToken string `json:"file_token,omitempty"` + FileName string `json:"file_name,omitempty"` + Size int `json:"size,omitempty"` + MimeType string `json:"mime_type,omitempty"` +} +type File struct { + FileToken string `json:"file_token,omitempty"` + FileName string `json:"file_name,omitempty"` + Size int `json:"size,omitempty"` + MimeType string `json:"mime_type,omitempty"` +} + +type UserId struct { + UserId string `json:"user_id,omitempty"` + OpenId string `json:"open_id,omitempty"` + UnionId string `json:"union_id,omitempty"` +} +type UploadInfo struct { + FileName string `json:"file_name,omitempty"` + ParentType string `json:"parent_type,omitempty"` + ParentNode string `json:"parent_node,omitempty"` + Size int `json:"size,omitempty"` +} + +type MediaUploadPrepareResult struct { + UploadId string `json:"upload_id,omitempty"` + BlockSize int `json:"block_size,omitempty"` + BlockNum int `json:"block_num,omitempty"` +} + +type FileUploadPrepareResult struct { + UploadId string `json:"upload_id,omitempty"` + BlockSize int `json:"block_size,omitempty"` + BlockNum int `json:"block_num,omitempty"` +} + +type FileUploadFinishReqBody struct { + UploadId string `json:"upload_id,omitempty"` + BlockNum int `json:"block_num,omitempty"` +} + +type FileUploadFinishResult struct { + FileToken string `json:"file_token,omitempty"` +} + +type MediaUploadFinishReqBody struct { + UploadId string `json:"upload_id,omitempty"` + BlockNum int `json:"block_num,omitempty"` +} + +type MediaUploadFinishResult struct { + FileToken string `json:"file_token,omitempty"` +} + +type MediaUploadAllResult struct { + FileToken string `json:"file_token,omitempty"` +} + +type FileUploadAllResult struct { + FileToken string `json:"file_token,omitempty"` +}