From 76fbd6ea7b6bdf1945b387e82479695398ccf33b Mon Sep 17 00:00:00 2001 From: jagger Date: Fri, 14 Feb 2025 18:02:51 +0800 Subject: [PATCH] add service --- apis/base_api.go | 115 +++++++++++++++++++ apis/dataset.go | 87 +++++++++++++- apis/model.go | 74 +++++++++++- apis/repo.go | 64 +++++++++++ app.go | 3 + common/client.go | 80 +++++++++++++ common/const.go | 19 ++- common/types.go | 12 ++ common/util.go | 21 ++++ go.mod | 7 +- go.sum | 127 ++++++++++++++++++++ initialize/common.go | 9 ++ model/dataset.go | 85 ++++++++++++-- model/error.go | 5 + model/model.go | 62 ++++++++++ model/repo.go | 52 +++++++++ router/router.go | 13 ++- service/dataset.go | 267 +++++++++++++++++++++++++++++++++++++++++++ service/model.go | 251 ++++++++++++++++++++++++++++++++++++++++ service/repo.go | 75 ++++++++++++ 20 files changed, 1406 insertions(+), 22 deletions(-) create mode 100644 apis/base_api.go create mode 100644 common/client.go create mode 100644 common/types.go create mode 100644 go.sum create mode 100644 initialize/common.go create mode 100644 service/dataset.go create mode 100644 service/model.go create mode 100644 service/repo.go diff --git a/apis/base_api.go b/apis/base_api.go new file mode 100644 index 0000000..f415a71 --- /dev/null +++ b/apis/base_api.go @@ -0,0 +1,115 @@ +package apis + +import ( + "github.com/gin-gonic/gin" + "github.com/gin-gonic/gin/binding" + "github.com/go-playground/locales/en" + "github.com/go-playground/locales/zh" + ut "github.com/go-playground/universal-translator" + "github.com/go-playground/validator/v10" + zht "github.com/go-playground/validator/v10/translations/zh" + "net/http" + "strconv" + "strings" +) + +type errorCode int + +const ( + Success errorCode = 200 + Failed errorCode = 500 + ParamError errorCode = 400 + NotFound errorCode = 404 + UnAuthorized errorCode = 401 +) + +var codeMsg = map[errorCode]string{ + Success: "正常", + Failed: "系统异常", + ParamError: "参数错误", + NotFound: "记录不存在", + UnAuthorized: "未授权", +} + +type Api struct { + Page int + PageSize int +} + +type Pagination struct { + List interface{} `json:"list"` + Page int `json:"page"` + PageSize int `json:"page_size"` + TotalCount int64 `json:"total_count"` +} + +var BaseApi = &Api{} + +var trans ut.Translator + +// 注册validator中文翻译 +func init() { + uni := ut.New(en.New(), zh.New()) + trans, _ = uni.GetTranslator("zh") + validate := binding.Validator.Engine().(*validator.Validate) + _ = zht.RegisterDefaultTranslations(validate, trans) +} + +func translate(err error) string { + errors, ok := err.(validator.ValidationErrors) + if !ok { + return err.Error() + } + result := make([]string, 0) + for _, err := range errors { + errMsg := err.Translate(trans) + if errMsg == "" { + continue + } + result = append(result, errMsg) + } + return strings.Join(result, ",") +} + +func (r *Api) ParsePage(ctx *gin.Context) { + page, err := strconv.Atoi(ctx.Query("page")) + if err != nil || page <= 0 { + page = 1 + } + pageSize, err := strconv.Atoi(ctx.Query("page_size")) + if err != nil || pageSize <= 0 { + pageSize = 10 + } + if pageSize > 1000 { + pageSize = 1000 + } + r.Page = page + r.PageSize = pageSize +} + +func (*Api) Index(ctx *gin.Context) { + ctx.String(http.StatusOK, "Gen Web") +} + +func (*Api) Success(ctx *gin.Context, msg string, data interface{}) { + ctx.JSON(http.StatusOK, gin.H{ + "code": Success, + "msg": msg, + "data": data, + "trace_id": ctx.GetString("trace_id"), + }) +} + +func (*Api) Failed(ctx *gin.Context, code errorCode, msg string) { + errMsg := codeMsg[code] + ": " + msg + ctx.AbortWithStatusJSON(http.StatusOK, gin.H{ + "code": code, + "msg": errMsg, + "data": nil, + "trace_id": ctx.GetString("trace_id"), + }) + if code != Success { + ctx.Set("error_code", int(code)) + ctx.Set("error_msg", msg) + } +} diff --git a/apis/dataset.go b/apis/dataset.go index f231422..283113b 100644 --- a/apis/dataset.go +++ b/apis/dataset.go @@ -2,12 +2,24 @@ package apis import ( "github.com/gin-gonic/gin" + json "github.com/json-iterator/go" "gitlink.org.cn/JointCloud/pcm-openi/common" "gitlink.org.cn/JointCloud/pcm-openi/model" + "gitlink.org.cn/JointCloud/pcm-openi/service" "net/http" "strconv" ) +type datasetApi struct { + *Api + *service.DatasetService +} + +var DatasetApi = datasetApi{ + Api: BaseApi, + DatasetService: service.NewDatasetService(), +} + func GetDatasetPublic(ctx *gin.Context) { var param model.DatasetParam if err := ctx.BindJSON(¶m); err != nil { @@ -16,13 +28,17 @@ func GetDatasetPublic(ctx *gin.Context) { } token := ctx.Query(common.ACCESSTOKEN) + if token == "" { + model.Response(ctx, 401, "access_token为必填字段", nil) + return + } reqUrl := common.OPENIPREFIX + common.DATASETPUBLIC var resp model.Dataset req := common.GetRestyRequest(common.TIMEOUT) - _, err := req. + res, err := req. SetQueryParam(common.ACCESSTOKEN, token). SetQueryParam("type", strconv.Itoa(param.Type)). SetQueryParam("q", param.Q). @@ -37,6 +53,12 @@ func GetDatasetPublic(ctx *gin.Context) { model.Response(ctx, 500, common.INVOKEERROR, err) return } + if res != nil { + if res.StatusCode() == 401 { + model.Response(ctx, 401, "access_token值无效请检查", err) + return + } + } if resp.Code != 0 { model.Response(ctx, 500, common.INVOKEERROR, err) @@ -86,7 +108,8 @@ func ExportDataset(ctx *gin.Context) { model.Response(ctx, http.StatusOK, common.SUCCESS, resp) } -func CreateDataset(ctx *gin.Context) { +func (r datasetApi) CreateDataset(ctx *gin.Context) { + var respErr model.RespErr var param model.CreateDatasetParam if err := ctx.BindJSON(¶m); err != nil { model.Response(ctx, http.StatusBadRequest, common.INVALIDPARAMS, err) @@ -100,7 +123,7 @@ func CreateDataset(ctx *gin.Context) { var resp model.CreateDataset req := common.GetRestyRequest(common.TIMEOUT) - _, err := req. + res, err := req. SetQueryParam(common.ACCESSTOKEN, token). SetPathParam("username", param.UserName). SetPathParam("reponame", param.RepoName). @@ -110,7 +133,7 @@ func CreateDataset(ctx *gin.Context) { "task": param.Task, "description": param.Description, }). - SetResult(&resp). + SetResult(&resp).SetError(&respErr). Post(reqUrl) if err != nil { @@ -118,10 +141,64 @@ func CreateDataset(ctx *gin.Context) { return } + if res != nil { + if res.StatusCode() != 200 { + errStr := json.Get(res.Body(), "message").ToString() + model.Response(ctx, 500, errStr, nil) + return + } + } + if resp.Code != 0 { model.Response(ctx, 500, resp.Message, nil) return } - + //返回创建数据集的id + ld := model.DatasetParam{ + UserName: param.UserName, + RepoName: param.RepoName, + Type: -1, + } + datasets, err := r.DatasetService.ListDatasets(token, &ld) + if err != nil { + model.Response(ctx, 500, common.INVOKEERROR, err) + } + resp.DatasetId = datasets.Data[0].Id model.Response(ctx, http.StatusOK, common.SUCCESS, resp) } + +func (r datasetApi) ListDatasets(ctx *gin.Context) { + var param model.DatasetParam + if err := ctx.ShouldBind(¶m); err != nil { + model.Response(ctx, http.StatusBadRequest, common.INVALIDPARAMS, translate(err)) + return + } + token := ctx.Query(common.ACCESSTOKEN) + if resp, err := r.DatasetService.ListDatasets(token, ¶m); err != nil { + r.Failed(ctx, Failed, err.Error()) + } else { + r.Success(ctx, "success", resp.Data) + } + return +} + +func (r datasetApi) UploadFileDatasets(ctx *gin.Context) { + // 绑定表单参数到结构体 + var param model.DatasetUploadFileParam + if err := ctx.ShouldBind(¶m); err != nil { + model.Response(ctx, http.StatusBadRequest, common.INVALIDPARAMS, translate(err)) + return + } + // 获取上传的文件 + fileHeader, err := ctx.FormFile("file") + if err != nil { + model.Response(ctx, 500, common.INVOKEERROR, err) + return + } + token := ctx.Query(common.ACCESSTOKEN) + if resp, err := r.DatasetService.UploadFile(param, token, fileHeader); err != nil { + model.Response(ctx, 500, err.Error(), resp) + } else { + model.Response(ctx, http.StatusOK, common.SUCCESS, resp) + } +} diff --git a/apis/model.go b/apis/model.go index ba66fa3..d424b6a 100644 --- a/apis/model.go +++ b/apis/model.go @@ -3,8 +3,10 @@ package apis import ( "fmt" "github.com/gin-gonic/gin" + json "github.com/json-iterator/go" "gitlink.org.cn/JointCloud/pcm-openi/common" "gitlink.org.cn/JointCloud/pcm-openi/model" + "gitlink.org.cn/JointCloud/pcm-openi/service" "io" "net/http" "net/url" @@ -12,6 +14,16 @@ import ( "strings" ) +type modelApi struct { + *Api + *service.ModelService +} + +var ModelApi = modelApi{ + Api: BaseApi, + ModelService: service.NewModelService(), +} + func CreateModel(ctx *gin.Context) { var param model.CreateModelParam if err := ctx.BindJSON(¶m); err != nil { @@ -149,7 +161,7 @@ func CreateLocalModel(ctx *gin.Context) { } req := common.GetRestyRequest(common.TIMEOUT) - _, err := req. + res, err := req. SetQueryParam(common.ACCESSTOKEN, token). SetPathParam("username", param.UserName). SetPathParam("reponame", param.RepoName). @@ -170,6 +182,13 @@ func CreateLocalModel(ctx *gin.Context) { model.Response(ctx, 500, common.INVOKEERROR, err) return } + if res != nil { + if res.StatusCode() != 200 { + errStr := json.Get(res.Body(), "message").ToString() + model.Response(ctx, 500, errStr, nil) + return + } + } if resp.Code != "0" { model.Response(ctx, 500, resp.Msg, nil) @@ -332,3 +351,56 @@ func CompleteMultipart(ctx *gin.Context) { model.Response(ctx, http.StatusOK, common.SUCCESS, resp) } + +func (r modelApi) UploadFile2Model(ctx *gin.Context) { + // 设置最大请求体大小(100 个文件 * 512 MiB = 51.2 GiB) + ctx.Request.Body = http.MaxBytesReader(ctx.Writer, ctx.Request.Body, 100<<20*512) + + // 解析 multipart form + form, err := ctx.MultipartForm() + if err != nil { + ctx.JSON(http.StatusBadRequest, gin.H{"error": "文件上传失败: " + err.Error()}) + return + } + + // 获取所有文件 + files := form.File["files"] + + // 检查文件数量 + if len(files) > 100 { + ctx.JSON(http.StatusBadRequest, gin.H{"error": "单次最多上传 100 个文件"}) + return + } + + // 检查文件名长度和文件大小 + for _, file := range files { + // 检查文件名长度 + if len(file.Filename) > 128 { + ctx.JSON(http.StatusBadRequest, gin.H{"error": "文件名不能超过 128 个字符"}) + return + } + + // 检查单个文件大小(512 MiB) + if file.Size > 512<<20 { + ctx.JSON(http.StatusBadRequest, gin.H{"error": "单个文件不能超过 512 MiB"}) + return + } + } + + // 绑定表单参数到结构体 + var param model.ModelUploadFileParam + if err := ctx.ShouldBind(¶m); err != nil { + model.Response(ctx, http.StatusBadRequest, common.INVALIDPARAMS, translate(err)) + return + } + + // 获取 token + token := ctx.Query(common.ACCESSTOKEN) + + // 调用服务层处理文件上传 + if resp, err := r.ModelService.UploadFile(param, token, files); err != nil { + model.Response(ctx, http.StatusInternalServerError, err.Error(), resp) + } else { + model.Response(ctx, http.StatusOK, common.SUCCESS, resp) + } +} diff --git a/apis/repo.go b/apis/repo.go index d4a56a0..2e80c49 100644 --- a/apis/repo.go +++ b/apis/repo.go @@ -4,9 +4,20 @@ import ( "github.com/gin-gonic/gin" "gitlink.org.cn/JointCloud/pcm-openi/common" "gitlink.org.cn/JointCloud/pcm-openi/model" + "gitlink.org.cn/JointCloud/pcm-openi/service" "net/http" ) +type repoApi struct { + *Api + *service.RepoService +} + +var RepoApi = repoApi{ + Api: BaseApi, + RepoService: service.NewRepoService(), +} + func GetRepos(ctx *gin.Context) { token := ctx.Query(common.ACCESSTOKEN) @@ -55,3 +66,56 @@ func CreateRepo(ctx *gin.Context) { model.Response(ctx, http.StatusOK, common.SUCCESS, resp) } + +// UploadFile2Repo 上传 +func (r repoApi) UploadFile2Repo(ctx *gin.Context) { + var param model.RepoUploadFileParam + if err := ctx.BindJSON(¶m); err != nil { + model.Response(ctx, http.StatusBadRequest, common.INVALIDPARAMS, translate(err)) + return + } + + token := ctx.Query(common.ACCESSTOKEN) + // 调用服务层处理文件上传 + if resp, err := r.RepoService.UploadFile(token, param); err != nil { + model.Response(ctx, http.StatusInternalServerError, err.Error(), resp) + } else { + model.Response(ctx, http.StatusOK, common.SUCCESS, resp) + } +} + +// UpdateFile2Repo 更新项目文件内容 +func (r repoApi) UpdateFile2Repo(ctx *gin.Context) { + var param model.RepoUpdateFileParam + if err := ctx.BindJSON(¶m); err != nil { + model.Response(ctx, http.StatusBadRequest, common.INVALIDPARAMS, translate(err)) + return + } + + token := ctx.Query(common.ACCESSTOKEN) + if resp, err := r.RepoService.UpdateFile(token, param); err != nil { + model.Response(ctx, http.StatusInternalServerError, err.Error(), resp) + } else { + model.Response(ctx, http.StatusOK, common.SUCCESS, resp) + } +} + +// QueryRepoFilesContent 查询文件详情 +func (r repoApi) QueryRepoFilesContent(ctx *gin.Context) { + var param model.QueryFilesContentParam + if err := ctx.ShouldBind(¶m); err != nil { + model.Response(ctx, http.StatusBadRequest, common.INVALIDPARAMS, translate(err)) + return + } + token := ctx.Query(common.ACCESSTOKEN) + if token == "" { + model.Response(ctx, 401, "access_token为必填字段", nil) + return + } + if resp, err := r.RepoService.QueryFilesContent(token, ¶m); err != nil { + model.Response(ctx, 500, err.Error(), nil) + } else { + model.Response(ctx, http.StatusOK, common.SUCCESS, resp) + } + return +} diff --git a/app.go b/app.go index 5872a50..a07fc25 100644 --- a/app.go +++ b/app.go @@ -1,10 +1,13 @@ package main import ( + "gitlink.org.cn/JointCloud/pcm-openi/initialize" "gitlink.org.cn/JointCloud/pcm-openi/router" ) func main() { + //初始化公共配置 + initialize.InitConfig() rt, _ := router.Create(nil) _ = rt.Run(":2024") } diff --git a/common/client.go b/common/client.go new file mode 100644 index 0000000..2559de2 --- /dev/null +++ b/common/client.go @@ -0,0 +1,80 @@ +package common + +import ( + "crypto/tls" + "errors" + "fmt" + "gitlink.org.cn/JointCloud/pcm-openi/model" + "net/http" + "time" + + "github.com/go-resty/resty/v2" +) + +var ( + NoRedirectClient *resty.Client + RestyClient *resty.Client + HttpClient *http.Client +) +var UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36" +var DefaultTimeout = time.Second * 300 + +func InitClient() { + NoRedirectClient = resty.New().SetRedirectPolicy( + resty.RedirectPolicyFunc(func(req *http.Request, via []*http.Request) error { + return http.ErrUseLastResponse + }), + ).SetTLSClientConfig(&tls.Config{InsecureSkipVerify: true}) + NoRedirectClient.SetHeader("user-agent", UserAgent) + + RestyClient = NewRestyClient() + HttpClient = NewHttpClient() +} + +func NewRestyClient() *resty.Client { + client := resty.New(). + SetHeader("user-agent", UserAgent). + SetRetryCount(3). + SetRetryResetReaders(true). + SetTimeout(DefaultTimeout). + SetTLSClientConfig(&tls.Config{InsecureSkipVerify: true}) + return client +} + +func NewHttpClient() *http.Client { + return &http.Client{ + Timeout: time.Hour * 48, + Transport: &http.Transport{ + Proxy: http.ProxyFromEnvironment, + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, + }, + } +} + +func Request(url string, method string, callback ReqCallback) ([]byte, error) { + respErr := &model.RespErr{} + req := RestyClient.R(). + SetHeaders(map[string]string{ + "Content-Type": "application/json", + }). + SetError(&respErr) + + if callback != nil { + callback(req) + } + + res, err := req.Execute(method, OPENIPREFIX+url) + + if err != nil { + return nil, err + } + if respErr.Message != "" { + return nil, errors.New(respErr.Message) + } + + if res.StatusCode() != http.StatusOK && res.StatusCode() != http.StatusCreated { + return nil, errors.New(fmt.Sprintf("msg: %s, status: %d", res.String(), res.StatusCode())) + } + + return res.Body(), nil +} diff --git a/common/const.go b/common/const.go index ca06227..26f73b9 100644 --- a/common/const.go +++ b/common/const.go @@ -1,6 +1,8 @@ package common const ( + MaxChunkSize int64 = 1024 * 1024 * 64 //64MB + QUESTION_MARK = "?" TIMEOUT = 10 OPENIPREFIX = "https://openi.pcl.ac.cn" @@ -9,7 +11,8 @@ const ( USERINFO = "/api/v1/user" // repo - REPO = "/api/v1/user/repos" + REPO = "/api/v1/user/repos" + RepoFile = "/api/v1/repos/{username}/{reponame}/contents/{filepath}" //上传文件到项目中、修改项目中的文件内容 // image IMAGERECOMMENDED = "/api/v1/images/recommend" @@ -22,7 +25,14 @@ const ( DATASETPUBLIC = "/api/v1/datasets/{username}/{reponame}/public_datasets" //查询公开数据集 DATASETFAVORITE = "/api/v1/datasets/{username}/{reponame}/my_favorite" //查询我收藏的数据集 DATASETEXISTEXPORT = "/api/v1/datasets/{username}/{reponame}/model/export_exist_dataset" //将用户选择的文件从训练任务结果中导出到数据集中 POST请求 - DATASETCREATE = "/api/v1/datasets/{username}/{reponame}/create" + DATASETCREATE = "/api/v1/datasets/{username}/{reponame}/create" // + BaseDatasetsUrl = "/api/v1/datasets/{username}/{reponame}" //数据集列表 //数据集基本接口 + + // datasets upload + GetChunksUrl = "/api/v1/attachments/get_chunks" //获取当前需要上传文件的chunk信息 + NewMultipartUrl = "/api/v1/attachments/new_multipart" //获取文件上传的需要的信息 + GetMultipartUrl = "/api/v1/attachments/get_multipart_url" //获取文件上传的地址 + CompleteMultipartUrl = "/api/v1/attachments/complete_multipart" //完成上传接口 //上传文件到数据集 // task TASKCREATIONREQUIRED = "/api/v1/{username}/{reponame}/ai_task/creation/required" // 查询创建任务所需资源接口 @@ -39,6 +49,9 @@ const ( MODELCREATE = "/api/v1/repos/{username}/{reponame}/modelmanage/create_new_model" //模型新增接口 MODELGETBYID = "/api/v1/repos/{username}/{reponame}/modelmanage/query_model_byId" //根据模型ID查询模型信息接口 MODELDOWNLOADBYID = "/api/v1/repos/{username}/{reponame}/modelmanage/downloadall" + QUERYMODELBYNAME = "/api/v1/repos/{username}/{reponame}/modelmanage/query_model_byName" //根据模型名称查询模型 + PageModel = "/api/v1/repos/{username}/{reponame}/modelmanage/show_model_api" //分页查询模型 + UploadFileToModel = "" //上传文件到模型记录中 // model local create MODELLOCALCREATE = "/api/v1/repos/{username}/{reponame}/modelmanage/create_local_model" //创建一条本地模型记录 @@ -55,6 +68,6 @@ const ( // error const ( INVOKEERROR = "failed to invoke" - INVALIDPARAMS = "invalid request params" + INVALIDPARAMS = "invalid Request params" NOTFOUND = "not found" ) diff --git a/common/types.go b/common/types.go new file mode 100644 index 0000000..b8dffad --- /dev/null +++ b/common/types.go @@ -0,0 +1,12 @@ +package common + +import "github.com/go-resty/resty/v2" + +type Json map[string]interface{} + +type TokenResp struct { + AccessToken string `json:"access_token"` + RefreshToken string `json:"refresh_token"` +} + +type ReqCallback func(req *resty.Request) diff --git a/common/util.go b/common/util.go index b48fad8..9f584eb 100644 --- a/common/util.go +++ b/common/util.go @@ -1,7 +1,12 @@ package common import ( + "crypto/md5" + "encoding/hex" "github.com/go-resty/resty/v2" + "io" + "mime/multipart" + "strconv" "time" ) @@ -10,3 +15,19 @@ func GetRestyRequest(timeoutSeconds int64) *resty.Request { request := client.R() return request } + +func GetFileMd5(file multipart.File) (string, error) { + hash := md5.New() + if _, err := io.Copy(hash, file); err != nil { + return "", err + } + + // 计算MD5并转换为16进制字符串 + md5Bytes := hash.Sum(nil) + md5Str := hex.EncodeToString(md5Bytes) + return md5Str, nil +} + +func Bool2String(b bool) string { + return strconv.FormatBool(b) +} diff --git a/go.mod b/go.mod index b2b061d..00989ca 100644 --- a/go.mod +++ b/go.mod @@ -3,19 +3,20 @@ module gitlink.org.cn/JointCloud/pcm-openi go 1.22.0 require ( + code.gitea.io/gitea/modules/structs v0.0.0-20190610152049-835b53fc259c github.com/gin-gonic/gin v1.9.0 + github.com/go-playground/locales v0.14.1 + github.com/go-playground/universal-translator v0.18.1 github.com/go-playground/validator/v10 v10.11.2 github.com/go-resty/resty/v2 v2.10.0 + github.com/json-iterator/go v1.1.12 ) require ( github.com/bytedance/sonic v1.8.0 // indirect github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect github.com/gin-contrib/sse v0.1.0 // indirect - github.com/go-playground/locales v0.14.1 // indirect - github.com/go-playground/universal-translator v0.18.1 // indirect github.com/goccy/go-json v0.10.0 // indirect - github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/cpuid/v2 v2.0.9 // indirect github.com/leodido/go-urn v1.2.1 // indirect github.com/mattn/go-isatty v0.0.17 // indirect diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..1ab01f8 --- /dev/null +++ b/go.sum @@ -0,0 +1,127 @@ +code.gitea.io/gitea/modules/structs v0.0.0-20190610152049-835b53fc259c h1:WwxK+8qmKYgU2pfcbCeRSqKwEPeHnW/sfmNc6pjLZC8= +code.gitea.io/gitea/modules/structs v0.0.0-20190610152049-835b53fc259c/go.mod h1:e/Ukqo229PbsSEymXfLWmNz4g04hwnFml5lW6U+0Azs= +github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= +github.com/bytedance/sonic v1.8.0 h1:ea0Xadu+sHlu7x5O3gKhRpQ1IKiMrSiHttPF0ybECuA= +github.com/bytedance/sonic v1.8.0/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= +github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= +github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= +github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= +github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-gonic/gin v1.9.0 h1:OjyFBKICoexlu99ctXNR2gg+c5pKrKMuyjgARg9qeY8= +github.com/gin-gonic/gin v1.9.0/go.mod h1:W1Me9+hsUSyj3CePGrd1/QrKJMSJ1Tu/0hFEH89961k= +github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= +github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= +github.com/go-playground/validator/v10 v10.11.2 h1:q3SHpufmypg+erIExEKUmsgmhDTyhcJ38oeKGACXohU= +github.com/go-playground/validator/v10 v10.11.2/go.mod h1:NieE624vt4SCTJtD87arVLvdmjPAeV8BQlHtMnw9D7s= +github.com/go-resty/resty/v2 v2.10.0 h1:Qla4W/+TMmv0fOeeRqzEpXPLfTUnR5HZ1+lGs+CkiCo= +github.com/go-resty/resty/v2 v2.10.0/go.mod h1:iiP/OpA0CkcL3IGt1O0+/SIItFUbkkyw5BGXiVdTu+A= +github.com/goccy/go-json v0.10.0 h1:mXKd9Qw4NuzShiRlOXKews24ufknHO7gx30lsDyokKA= +github.com/goccy/go-json v0.10.0/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4= +github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= +github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/pelletier/go-toml/v2 v2.0.6 h1:nrzqCb7j9cDFj2coyLNLaZuJTLjWjlaz6nvTvIwycIU= +github.com/pelletier/go-toml/v2 v2.0.6/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8= +github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= +github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= +github.com/ugorji/go/codec v1.2.9 h1:rmenucSohSTiyL09Y+l2OCk+FrMxGMzho2+tjr5ticU= +github.com/ugorji/go/codec v1.2.9/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +golang.org/x/arch v0.0.0-20210923205945-b76863e36670 h1:18EFjUmQOcUvxNYSkA6jO9VAiXCnxFY6NyDX0bHDmkU= +golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= +golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= +golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= +golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= +golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= diff --git a/initialize/common.go b/initialize/common.go new file mode 100644 index 0000000..94351cb --- /dev/null +++ b/initialize/common.go @@ -0,0 +1,9 @@ +package initialize + +import ( + "gitlink.org.cn/JointCloud/pcm-openi/common" +) + +func InitConfig() { + common.InitClient() +} diff --git a/model/dataset.go b/model/dataset.go index d90645c..21d3537 100644 --- a/model/dataset.go +++ b/model/dataset.go @@ -1,12 +1,12 @@ package model type DatasetParam struct { - UserName string `json:"username"` - RepoName string `json:"reponame"` - Type int `json:"type"` //type=0 GPU环境可用数据集;type=1 NPU环境可用数据集。 - Q string `json:"q,omitempty"` - Page int `json:"page"` - PageSize int `json:"pageSize"` + UserName string `json:"username" form:"username"` + RepoName string `json:"reponame" form:"reponame"` + Type int `json:"type" form:"type"` //type=0 GPU环境可用数据集;type=1 NPU环境可用数据集。 + Q string `json:"q,omitempty" form:"q"` + Page int `json:"page" form:"page"` + PageSize int `json:"pageSize" form:"pageSize"` } type Dataset struct { @@ -79,6 +79,75 @@ type CreateDatasetParam struct { } type CreateDataset struct { - Code int `json:"Code"` - Message string `json:"Message"` + Code int `json:"Code"` + Message string `json:"Message"` + DatasetId int `json:"DatasetId"` +} + +type DatasetUploadFileParam struct { + UserName string `json:"username" form:"username" binding:"required"` + RepoName string `json:"repoName" form:"repoName" binding:"required"` + DatasetId string `json:"datasetId" form:"datasetId" binding:"required"` + CustomName string `json:"customName" form:"customName" binding:"required"` //自定义名称 +} + +type GetChunksResp struct { + AttachID string `json:"attachID"` + Chunks string `json:"chunks"` + DatasetID string `json:"datasetID"` + DatasetName string `json:"datasetName"` + ModelName string `json:"modelName"` + Modeluuid string `json:"modeluuid"` + FileName string `json:"fileName"` + UploadID string `json:"uploadID"` + Uploaded string `json:"uploaded"` + Uuid string `json:"uuid"` +} + +type NewMultipartResp struct { + ResultCode string `json:"result_code"` + UploadID string `json:"uploadID"` + Uuid string `json:"uuid"` +} +type GetMultipartUrlResp struct { + Url string `json:"url"` +} + +type CompleteMultipartResp struct { + Msg string `json:"msg"` + ResultCode string `json:"result_code"` +} + +type ListDatasetsResp struct { + Code int `json:"code"` + Data []struct { + Id int `json:"id"` + Title string `json:"title"` + Status int `json:"status"` + Category string `json:"category"` + Description string `json:"description"` + DownloadTimes int `json:"downloadTimes"` + UseCount int `json:"useCount"` + NumStars int `json:"numStars"` + Recommend bool `json:"recommend"` + License string `json:"license"` + Task string `json:"task"` + ReleaseId int `json:"releaseId"` + UserId int `json:"userId"` + RepoId int `json:"repoId"` + Repo struct { + OwnerName string `json:"ownerName"` + Name string `json:"name"` + } `json:"repo"` + CreatedUnix int `json:"createdUnix"` + UpdatedUnix int `json:"updatedUnix"` + Attachments interface{} `json:"attachments"` + } `json:"data"` + Message string `json:"message"` +} + +type Err struct { + DocumentationUrl string `json:"documentation_url"` + Errors interface{} `json:"errors"` + Message string `json:"message"` } diff --git a/model/error.go b/model/error.go index 4fff570..f3d4e70 100644 --- a/model/error.go +++ b/model/error.go @@ -22,3 +22,8 @@ type Error struct { // example: you need to provide a valid access token or user credentials to access this api ErrorDescription string `json:"errorDescription"` } + +type RespErr struct { + Code string `json:"code"` + Message string `json:"message"` +} diff --git a/model/model.go b/model/model.go index f47ff13..18884b4 100644 --- a/model/model.go +++ b/model/model.go @@ -21,6 +21,11 @@ type GetByIdModelParam struct { Id string `json:"id"` } +type QueryModelParam struct { + UserName string `json:"username"` + RepoName string `json:"reponame"` +} + type DownloadByIdParam struct { UserName string `json:"username"` RepoName string `json:"reponame"` @@ -85,6 +90,7 @@ type CreateLocalModelParam struct { IsPrivate bool `json:"isPrivate,omitempty"` Description string `json:"description,omitempty"` Type int `json:"type"` + License string `json:"license"` } type CreateLocalModel struct { @@ -159,3 +165,59 @@ type CompleteMultipartParam struct { type CompleteMultipart struct { Code string `json:"result_code"` } + +type ListModelResp struct { + Count int `json:"count"` + Data []struct { + Id string `json:"id"` + Name string `json:"name"` + ModelType int `json:"modelType"` + Version string `json:"version"` + VersionCount int `json:"versionCount"` + New int `json:"new"` + Type int `json:"type"` + Size int `json:"size"` + Description string `json:"description"` + Label string `json:"label"` + Path string `json:"path"` + DownloadCount int `json:"downloadCount"` + Engine int `json:"engine"` + ComputeResource string `json:"computeResource"` + Status int `json:"status"` + StatusDesc string `json:"statusDesc"` + Accuracy string `json:"accuracy"` + AttachmentId string `json:"attachmentId"` + RepoId int `json:"repoId"` + CodeBranch string `json:"codeBranch"` + CodeCommitID string `json:"codeCommitID"` + Recommend int `json:"recommend"` + UserId int `json:"userId"` + IsPrivate bool `json:"isPrivate"` + UserName string `json:"userName"` + UserRelAvatarLink string `json:"userRelAvatarLink"` + TrainTaskInfo string `json:"trainTaskInfo"` + CreatedUnix int `json:"createdUnix"` + UpdatedUnix int `json:"updatedUnix"` + IsCanOper bool `json:"isCanOper"` + IsCanDelete bool `json:"isCanDelete"` + IsCanDownload bool `json:"isCanDownload"` + IsCollected bool `json:"isCollected"` + RepoName string `json:"repoName"` + RepoDisplayName string `json:"repoDisplayName"` + RepoOwnerName string `json:"repoOwnerName"` + DatasetInfo interface{} `json:"datasetInfo"` + ReferenceCount int `json:"referenceCount"` + CollectedCount int `json:"collectedCount"` + ModelFileList interface{} `json:"modelFileList"` + OnlineInfo interface{} `json:"onlineInfo"` + UsedCloudbrain interface{} `json:"usedCloudbrain"` + HasOnlineUrl int `json:"hasOnlineUrl"` + License string `json:"license"` + } `json:"data"` +} + +type ModelUploadFileParam struct { + UserName string `json:"username" form:"username" binding:"required"` + RepoName string `json:"repoName" form:"repoName" binding:"required"` + ModelUuid string `json:"modelUuid" form:"modelUuid" binding:"required"` +} diff --git a/model/repo.go b/model/repo.go index cc8f247..c2d8dd6 100644 --- a/model/repo.go +++ b/model/repo.go @@ -140,3 +140,55 @@ type RepoCreateParam struct { Private bool `json:"private"` Readme string `json:"readme"` } + +type RepoUploadFileParam struct { + UserName string `json:"username" form:"username" binding:"required"` + RepoName string `json:"repoName" form:"repoName" binding:"required"` + FileContents []*FileContent `json:"fileContents" form:"filePath" binding:"required"` +} + +type FileContent struct { + FilePath string `json:"filePath" form:"filePath" binding:"required"` + Content string `json:"content" form:"content" binding:"required"` + FileSha string `json:"fileSha" form:"content"` +} + +type RepoUpdateFileParam struct { + UserName string `json:"username" form:"username" binding:"required"` + RepoName string `json:"repoName" form:"repoName" binding:"required"` + FileContents []*FileContent `json:"fileContents" form:"filePath" binding:"required"` +} + +type FileContentErr struct { + Message string `json:"message"` + Url string `json:"url"` +} + +type QueryFilesContentParam struct { + UserName string `json:"username" form:"username" binding:"required"` + RepoName string `json:"repoName" form:"repoName" binding:"required"` + FilePath string `json:"filePath" form:"filePath"` +} + +type FileContentResp struct { + Name string `json:"name"` + Path string `json:"path"` + Sha string `json:"sha"` + Type string `json:"type"` + Size int `json:"size"` + Encoding string `json:"encoding"` + Content string `json:"content"` + Target interface{} `json:"target"` + Url string `json:"url"` + HtmlUrl string `json:"html_url"` + GitUrl string `json:"git_url"` + DownloadUrl string `json:"download_url"` + SubmoduleGitUrl interface{} `json:"submodule_git_url"` + Links struct { + Self string `json:"self"` + Git string `json:"git"` + Html string `json:"html"` + } `json:"_links"` + Language string `json:"language"` + FileType string `json:"fileType"` +} diff --git a/router/router.go b/router/router.go index 8dd5b52..c855fe1 100644 --- a/router/router.go +++ b/router/router.go @@ -30,19 +30,26 @@ func Create(conf *config.Configuration) (*gin.Engine, error) { user.GET("", apis.GetUserInfo) //repo + repoApi := apis.RepoApi repo := v1.Group("user") repo.GET("/repos", apis.GetRepos) repo.POST("/repos", apis.CreateRepo) + repo.POST("/repos/uploadFile", repoApi.UploadFile2Repo) //上传文件到项目中 + repo.PUT("/repos/updateFile", repoApi.UpdateFile2Repo) //修改项目文件 + repo.GET("/repos/queryFileContent", repoApi.QueryRepoFilesContent) //查询项目文件内容 //image image := v1.Group("image") image.GET("/recommend", apis.GetImageRecommended) //datasets + datasetsApi := apis.DatasetApi datasets := v1.Group("datasets") - datasets.POST("/create", apis.CreateDataset) + datasets.POST("/create", datasetsApi.CreateDataset) datasets.GET("/public", apis.GetDatasetPublic) - datasets.POST("/export", apis.ExportDataset) //将用户选择的文件从训练任务结果中导出到数据集中 + datasets.POST("/export", apis.ExportDataset) //将用户选择的文件从训练任务结果中导出到数据集中 + datasets.POST("/uploadFile", datasetsApi.UploadFileDatasets) //上传文件到数据集中 + datasets.GET("/listDatasets", datasetsApi.ListDatasets) //查询数据集列表 //tasks task := v1.Group("task") @@ -57,10 +64,12 @@ func Create(conf *config.Configuration) (*gin.Engine, error) { task.GET("/downloadAll", apis.DownloadAllById) //model + modelApi := apis.ModelApi model := v1.Group("model") model.POST("/create", apis.CreateModel) model.GET("/getById", apis.GetModelById) model.GET("/download", apis.DownloadById) + model.POST("/uploadFile", modelApi.UploadFile2Model) // model local create model.POST("/localCreate", apis.CreateLocalModel) diff --git a/service/dataset.go b/service/dataset.go new file mode 100644 index 0000000..bf7564e --- /dev/null +++ b/service/dataset.go @@ -0,0 +1,267 @@ +package service + +import ( + "errors" + "fmt" + "github.com/go-resty/resty/v2" + json "github.com/json-iterator/go" + "gitlink.org.cn/JointCloud/pcm-openi/common" + "gitlink.org.cn/JointCloud/pcm-openi/model" + "io" + "math" + "mime/multipart" + "net/http" + "strconv" +) + +type DatasetService struct { +} + +func NewDatasetService() *DatasetService { + return &DatasetService{} +} + +func (r DatasetService) ListDatasets(token string, param *model.DatasetParam) (resp *model.ListDatasetsResp, err error) { + respErr := &model.RespErr{} + _, err = common.Request(common.BaseDatasetsUrl, http.MethodGet, func(req *resty.Request) { + req.SetPathParam("username", param.UserName). + SetPathParam("reponame", param.RepoName). + SetQueryParams(map[string]string{ + common.ACCESSTOKEN: token, + "type": strconv.Itoa(param.Type), + "q": param.Q, + "page": strconv.Itoa(param.Page), + "pageSize": strconv.Itoa(param.PageSize), + }).SetError(&respErr).SetResult(&resp) + }) + if err != nil { + return nil, err + } + return +} + +// ListDatasetCurrentDatasets 查询当前项目的数据集接口 +func (r DatasetService) ListDatasetCurrentDatasets(token string, param *model.DatasetParam) (resp *model.Dataset, err error) { + respErr := &model.RespErr{} + _, err = common.Request(common.DATASETCURRENT, http.MethodGet, func(req *resty.Request) { + req.SetPathParam("username", param.UserName). + SetPathParam("reponame", param.RepoName). + SetQueryParams(map[string]string{ + common.ACCESSTOKEN: token, + "type": strconv.Itoa(param.Type), + "q": param.Q, + "page": strconv.Itoa(param.Page), + "pageSize": strconv.Itoa(param.PageSize), + }).SetError(&respErr).SetResult(&resp) + }) + if err != nil { + return nil, err + } + return +} + +func (r DatasetService) getChunks(token, md5, fileName, dataType, datasetId, size string) (resp *model.GetChunksResp, err error) { + _, err = common.Request(common.GetChunksUrl, http.MethodGet, func(req *resty.Request) { + req.SetQueryParams(map[string]string{ + "md5": md5, + "file_name": fileName, + "type": dataType, + "dataset_id": datasetId, + "size": size, + common.ACCESSTOKEN: token, + }).SetResult(&resp) + }) + if err != nil { + return nil, err + } + return +} + +// newMultipart 开启一个本地数据集文件上传 +func (r DatasetService) newMultipart(token, totalChunkCounts, md5, fileName, dataType, datasetId, size string) (resp *model.NewMultipartResp, err error) { + res, err := common.Request(common.NewMultipartUrl, http.MethodGet, func(req *resty.Request) { + req.SetQueryParams(map[string]string{ + "totalChunkCounts": totalChunkCounts, + "type": dataType, + "size": size, + "md5": md5, + "file_name": fileName, + "dataset_id": datasetId, + common.ACCESSTOKEN: token, + }).SetResult(&resp) + }) + if err != nil { + return nil, err + } + if resp.UploadID == "" || resp.Uuid == "" { + msg := json.Get(res, "msg").ToString() + return nil, fmt.Errorf(msg) + } + return +} + +// getMultipartUrl 获取数据集分片传输url +func (r DatasetService) getMultipartUrl(token, uuid, uploadID, fileName, dataType, datasetId, size, chunkNumber string) (resp *model.GetMultipartUrlResp, err error) { + res, err := common.Request(common.GetMultipartUrl, http.MethodGet, func(req *resty.Request) { + req.SetQueryParams(map[string]string{ + "uuid": uuid, + "uploadID": uploadID, + "type": dataType, + "size": size, + "chunkNumber": chunkNumber, + "file_name": fileName, + "dataset_id": datasetId, + common.ACCESSTOKEN: token, + }).SetResult(&resp) + }) + if err != nil { + return nil, err + } + if resp.Url == "" { + msg := json.Get(res, "msg").ToString() + return nil, fmt.Errorf(msg) + } + return +} + +// upLoadChunk 上传chunk +func (r DatasetService) upLoadChunk(token, url, fileName string, reader io.Reader) (err error) { + client := &http.Client{} + req, err := http.NewRequest(http.MethodPut, url, reader) + if err != nil { + return err + } + req.Header.Set("Content-Type", "") + + res, err := client.Do(req) + if err != nil { + return err + } + defer res.Body.Close() + + // 读取响应体 + _, err = io.ReadAll(res.Body) + if err != nil { + return err + } + if res.StatusCode != http.StatusOK { + return errors.New(res.Status) + } + return nil +} + +// completeMultipart 完成数据集文件上传 +func (r DatasetService) completeMultipart(token, uuid, uploadID, fileName, size, datasetId, dataType, customName string) (resp *model.CompleteMultipartResp, err error) { + _, err = common.Request(common.CompleteMultipartUrl, http.MethodPost, func(req *resty.Request) { + req.SetQueryParams(map[string]string{ + "uuid": uuid, + "uploadID": uploadID, + "file_name": fileName, + "size": size, + "dataset_id": datasetId, + "type": dataType, + "description": customName, + common.ACCESSTOKEN: token, + }).SetResult(&resp) + }) + if err != nil { + return nil, err + } + if resp.ResultCode == "-1" { + return nil, fmt.Errorf(resp.Msg) + } + return +} + +func (r DatasetService) UploadFile(param model.DatasetUploadFileParam, token string, fileHeader *multipart.FileHeader) (respId string, err error) { + datasetId := param.DatasetId + // step.1 优先计算所需信息 + dataType := "1" + uuid := "" + uploadID := "" + chunkNumber := 1 + fileName := fileHeader.Filename + fileSize := fileHeader.Size + totalChunkCounts := int(math.Ceil(float64(fileSize) / float64(common.MaxChunkSize))) + + fileSizeStr := strconv.FormatInt(fileSize, 10) + // 打开上传的文件 + file, err := fileHeader.Open() + if err != nil { + return "", errors.New(fmt.Sprintf("文件打开失败: %s", err.Error())) + } + defer file.Close() // 确保关闭文件 + md5hash, err := common.GetFileMd5(file) + if err != nil { + return "", err + } + // Get already uploaded chunks + chunks, err := r.getChunks(token, md5hash, fileName, dataType, datasetId, fileSizeStr) + if err != nil { + return "", err + } + if chunks.Uploaded == "1" { + return "", errors.New(fmt.Sprintf("该文件已上传在数据集: %s", chunks.DatasetName)) + } + if chunks.UploadID != "" && chunks.Uuid != "" { + uuid = chunks.Uuid + uploadID = chunks.UploadID + } else { + // Start a new multipart upload + newMultipart, err := r.newMultipart(token, strconv.Itoa(totalChunkCounts), md5hash, fileName, dataType, datasetId, fileSizeStr) + if err != nil { + return "", err + } + uuid = newMultipart.Uuid + uploadID = newMultipart.UploadID + } + + // Upload each chunk + for chunkNumber <= totalChunkCounts { + // Get multipart URL for the current chunk + multipartUrl, err := r.getMultipartUrl(token, uuid, uploadID, fileName, dataType, datasetId, fileSizeStr, strconv.Itoa(chunkNumber)) + if err != nil { + return "", err + } + + // Create a reader for the current chunk + chunkReader := io.NewSectionReader(file, int64(chunkNumber-1)*common.MaxChunkSize, common.MaxChunkSize) + + // Retry mechanism for uploading the current chunk + for attempt := 1; attempt <= 3; attempt++ { + err = r.upLoadChunk(token, multipartUrl.Url, fileName, chunkReader) + if err == nil { + break + } + if attempt == 3 { + return "", errors.New(fmt.Sprintf("error uploading chunk %d after 3 attempts: %s", chunkNumber, err.Error())) + } + } + chunkNumber++ + } + + // Complete the multipart upload + _, err = r.completeMultipart(token, uuid, uploadID, fileName, fileSizeStr, datasetId, dataType, param.CustomName) + if err != nil { + return "", err + } + ld := model.DatasetParam{ + UserName: param.UserName, + RepoName: param.RepoName, + Type: -1, + } + datasets, err := r.ListDatasetCurrentDatasets(token, &ld) + if err != nil { + return "", err + } + for _, datum := range datasets.Data { + for _, attachment := range datum.Attachments { + //数据集里面文件名称可重复,使用用户自定义名称做唯一区分 + if attachment.Description == param.CustomName { + respId = attachment.Uuid + return + } + } + } + return +} diff --git a/service/model.go b/service/model.go new file mode 100644 index 0000000..46b736c --- /dev/null +++ b/service/model.go @@ -0,0 +1,251 @@ +package service + +import ( + "errors" + "fmt" + "github.com/go-resty/resty/v2" + json "github.com/json-iterator/go" + "gitlink.org.cn/JointCloud/pcm-openi/common" + "gitlink.org.cn/JointCloud/pcm-openi/model" + "io" + "math" + "mime/multipart" + "net/http" + "strconv" +) + +type ModelService struct { +} + +func NewModelService() *ModelService { + return &ModelService{} +} + +func (r ModelService) CreateLocalModel(token string, param model.CreateLocalModelParam) (resp model.CreateLocalModel, err error) { + respErr := &model.RespErr{} + _, err = common.Request(common.MODELLOCALCREATE, http.MethodPost, func(req *resty.Request) { + req.SetPathParam("username", param.UserName). + SetPathParam("reponame", param.RepoName). + SetFormData(map[string]string{ + "name": param.Name, + "version": param.Version, + "engine": strconv.Itoa(param.Engine), + "label": param.Label, + "isPrivate": strconv.FormatBool(param.IsPrivate), + "description": param.Description, + "type": strconv.Itoa(param.Type), + "license": param.License, + common.ACCESSTOKEN: token, + }).SetError(respErr).SetResult(&resp) + }) + if err != nil { + return resp, err + } + return resp, nil +} + +// ListModel 分页查询模型 +func (r ModelService) ListModel(token string, param *model.QueryModelParam) (resp *model.ListModelResp, err error) { + respErr := &model.RespErr{} + _, err = common.Request(common.PageModel, http.MethodGet, func(req *resty.Request) { + req.SetPathParam("username", param.UserName). + SetPathParam("reponame", param.RepoName). + SetQueryParam(common.ACCESSTOKEN, token). + SetResult(&respErr).SetResult(&resp) + }) + if err != nil { + return resp, err + } + return resp, nil +} + +// getChunks 获取模型该文件已经上传的分片 +func (r ModelService) getChunks(token, md5, fileName, dataType, modelUuid, size string) (resp *model.GetChunksResp, err error) { + _, err = common.Request(common.MODELLOCALGETUPLOADEDCHUNKS, http.MethodGet, func(req *resty.Request) { + req.SetQueryParams(map[string]string{ + "md5": md5, + "file_name": fileName, + "type": dataType, + "modeluuid": modelUuid, + "size": size, + common.ACCESSTOKEN: token, + }).SetResult(&resp) + }) + if err != nil { + return nil, err + } + return +} + +// newMultipart 开启一个本地模型文件上传 +func (r ModelService) newMultipart(token, totalChunkCounts, md5, fileName, dataType, modelUuid, size string) (resp *model.NewMultipartResp, err error) { + res, err := common.Request(common.MODELLOCALNEWMULTIPART, http.MethodGet, func(req *resty.Request) { + req.SetQueryParams(map[string]string{ + "totalChunkCounts": totalChunkCounts, + "type": dataType, + "size": size, + "md5": md5, + "file_name": fileName, + "modeluuid": modelUuid, + common.ACCESSTOKEN: token, + }).SetResult(&resp) + }) + if err != nil { + return nil, err + } + if resp.UploadID == "" || resp.Uuid == "" { + msg := json.Get(res, "msg").ToString() + return nil, fmt.Errorf(msg) + } + return +} + +// getMultipartUrl 获取模型分片传输url +func (r ModelService) getMultipartUrl(token, uuid, uploadID, fileName, dataType, modelUuid, size, chunkNumber string) (resp *model.GetMultipartUrlResp, err error) { + res, err := common.Request(common.MODELLOCALGETMULTIPARTURL, http.MethodGet, func(req *resty.Request) { + req.SetQueryParams(map[string]string{ + "uuid": uuid, + "uploadID": uploadID, + "type": dataType, + "size": size, + "chunkNumber": chunkNumber, + "file_name": fileName, + "modeluuid": modelUuid, + common.ACCESSTOKEN: token, + }).SetResult(&resp) + }) + if err != nil { + return nil, err + } + if resp.Url == "" { + msg := json.Get(res, "msg").ToString() + return nil, fmt.Errorf(msg) + } + return +} + +// upLoadChunk 上传chunk +func (r ModelService) upLoadChunk(token string, reqUrl, fileName string, reader io.Reader) (err error) { + client := &http.Client{} + req, err := http.NewRequest(http.MethodPut, reqUrl, reader) + if err != nil { + return err + } + req.Header.Set("Content-Type", "") + + res, err := client.Do(req) + if err != nil { + return err + } + defer res.Body.Close() + + // 读取响应体 + _, err = io.ReadAll(res.Body) + if err != nil { + return err + } + if res.StatusCode != http.StatusOK { + return errors.New(res.Status) + } + return nil +} + +// completeMultipart 完成模型文件上传 +func (r ModelService) completeMultipart(token string, uuid, uploadID, fileName, size, modelUuid, dataType string) (resp *model.CompleteMultipartResp, err error) { + _, err = common.Request(common.MODELLOCALCOMPLETEMULTIPART, http.MethodPost, func(req *resty.Request) { + req.SetFormData(map[string]string{ + "uuid": uuid, + "uploadID": uploadID, + "type": dataType, + "modeluuid": modelUuid, + "file_name": fileName, + "size": size, + common.ACCESSTOKEN: token, + }).SetResult(&resp) + }) + if err != nil { + return nil, err + } + if resp.ResultCode == "-1" { + return nil, fmt.Errorf(resp.Msg) + } + return +} + +func (r ModelService) UploadFile(param model.ModelUploadFileParam, token string, fileHeaders []*multipart.FileHeader) (respId string, err error) { + modelUuid := param.ModelUuid + for _, fileHeader := range fileHeaders { + // step.1 优先计算所需信息 + dataType := "1" + uuid := "" + uploadID := "" + chunkNumber := 1 + fileName := fileHeader.Filename + fileSize := fileHeader.Size + totalChunkCounts := int(math.Ceil(float64(fileSize) / float64(common.MaxChunkSize))) + + fileSizeStr := strconv.FormatInt(fileSize, 10) + // 打开上传的文件 + file, err := fileHeader.Open() + if err != nil { + return "", errors.New(fmt.Sprintf("文件打开失败: %s", err.Error())) + } + defer file.Close() // 确保关闭文件 + md5hash, err := common.GetFileMd5(file) + if err != nil { + return "", err + } + // Get already uploaded chunks + chunks, err := r.getChunks(token, md5hash, fileName, dataType, modelUuid, fileSizeStr) + if err != nil { + return "", err + } + if chunks.Uploaded == "1" { + return "", errors.New(fmt.Sprintf("该文件已上传在模型: %s", chunks.ModelName)) + } + if chunks.UploadID != "" && chunks.Uuid != "" { + uuid = chunks.Uuid + uploadID = chunks.UploadID + } else { + // Start a new multipart upload + newMultipart, err := r.newMultipart(token, strconv.Itoa(totalChunkCounts), md5hash, fileName, dataType, modelUuid, fileSizeStr) + if err != nil { + return "", err + } + uuid = newMultipart.Uuid + uploadID = newMultipart.UploadID + } + + // Upload each chunk + for chunkNumber <= totalChunkCounts { + // Get multipart URL for the current chunk + multipartUrl, err := r.getMultipartUrl(token, uuid, uploadID, fileName, dataType, modelUuid, fileSizeStr, strconv.Itoa(chunkNumber)) + if err != nil { + return "", err + } + + // Create a reader for the current chunk + chunkReader := io.NewSectionReader(file, int64(chunkNumber-1)*common.MaxChunkSize, common.MaxChunkSize) + + // Retry mechanism for uploading the current chunk + for attempt := 1; attempt <= 3; attempt++ { + err = r.upLoadChunk(token, multipartUrl.Url, fileName, chunkReader) + if err == nil { + break + } + if attempt == 3 { + return "", errors.New(fmt.Sprintf("error uploading chunk %d after 3 attempts: %s", chunkNumber, err.Error())) + } + } + chunkNumber++ + } + + // Complete the multipart upload + _, err = r.completeMultipart(token, uuid, uploadID, fileName, fileSizeStr, modelUuid, dataType) + if err != nil { + return "", err + } + } + + return "", nil +} diff --git a/service/repo.go b/service/repo.go new file mode 100644 index 0000000..d4c9abd --- /dev/null +++ b/service/repo.go @@ -0,0 +1,75 @@ +package service + +import ( + "code.gitea.io/gitea/modules/structs" + "github.com/go-resty/resty/v2" + "gitlink.org.cn/JointCloud/pcm-openi/common" + "gitlink.org.cn/JointCloud/pcm-openi/model" + "net/http" +) + +type RepoService struct { +} + +func NewRepoService() *RepoService { + return &RepoService{} +} + +func (r RepoService) UploadFile(token string, param model.RepoUploadFileParam) (resp *structs.FileResponse, err error) { + for _, content := range param.FileContents { + respErr := &model.FileContentErr{} + body := structs.CreateFileOptions{} + //Base64编码后的文件内容 + body.Content = content.Content + _, err = common.Request(common.RepoFile, http.MethodPost, func(req *resty.Request) { + req.SetPathParam("username", param.UserName). + SetPathParam("reponame", param.RepoName). + SetPathParam("filepath", content.FilePath). + SetQueryParam(common.ACCESSTOKEN, token). + SetBody(&body).SetResult(&resp).SetError(&respErr) + }) + } + + if err != nil { + return nil, err + } + return +} + +func (r RepoService) UpdateFile(token string, param model.RepoUpdateFileParam) (resp *structs.FileResponse, err error) { + for _, content := range param.FileContents { + respErr := &model.FileContentErr{} + resp := &structs.FileResponse{} + body := structs.UpdateFileOptions{} + //Base64编码后的文件内容 + body.Content = content.Content + body.SHA = content.FileSha + _, err = common.Request(common.RepoFile, http.MethodPut, func(req *resty.Request) { + req.SetPathParam("username", param.UserName). + SetPathParam("reponame", param.RepoName). + SetPathParam("filepath", content.FilePath). + SetQueryParam(common.ACCESSTOKEN, token). + SetBody(&body).SetResult(&resp).SetError(&respErr) + }) + } + + if err != nil { + return nil, err + } + return +} + +func (r RepoService) QueryFilesContent(token string, param *model.QueryFilesContentParam) (resp interface{}, err error) { + var respErr interface{} + _, err = common.Request(common.RepoFile, http.MethodGet, func(req *resty.Request) { + req.SetPathParam("username", param.UserName). + SetPathParam("reponame", param.RepoName). + SetPathParam("filepath", param.FilePath). + SetQueryParam(common.ACCESSTOKEN, token). + SetResult(&resp).SetError(&respErr) + }) + if err != nil { + return nil, err + } + return +}