From b16beebabb254488897edde870e9588b7be5293e Mon Sep 17 00:00:00 2001 From: Derrick Hammer Date: Thu, 4 May 2023 04:18:38 -0400 Subject: [PATCH] feat: add files service with upload endpoint --- service/files_service.go | 122 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100644 service/files_service.go diff --git a/service/files_service.go b/service/files_service.go new file mode 100644 index 0000000..476438a --- /dev/null +++ b/service/files_service.go @@ -0,0 +1,122 @@ +package service + +import ( + "bytes" + "encoding/hex" + "errors" + "fmt" + "git.lumeweb.com/LumeWeb/portal/bao" + "git.lumeweb.com/LumeWeb/portal/cid" + "git.lumeweb.com/LumeWeb/portal/db" + "git.lumeweb.com/LumeWeb/portal/model" + "git.lumeweb.com/LumeWeb/portal/renterd" + "github.com/go-resty/resty/v2" + "github.com/kataras/iris/v12" + "io" + "lukechampine.com/blake3" +) + +type FilesService struct { + Ctx iris.Context +} + +var client *resty.Client + +type UploadResponse struct { + Cid string `json:"cid"` +} + +func InitFiles() { + client = resty.New() + client.SetBaseURL(renterd.GetApiAddr() + "/api") + client.SetBasicAuth("", renterd.GetAPIPassword()) +} + +func (f *FilesService) PostUpload() { + ctx := f.Ctx + + file, _, err := f.Ctx.FormFile("file") + if internalErrorCustom(ctx, err, errors.New("invalid file data")) { + return + } + + buf := new(bytes.Buffer) + _, err = buf.ReadFrom(file) + + if internalErrorCustom(ctx, err, errors.New("failed to read file data")) { + return + } + + hashBytes := blake3.Sum256(buf.Bytes()) + hashHex := hex.EncodeToString(hashBytes[:]) + fileCid, err := cid.EncodeHashSimple(hashBytes) + + if internalError(ctx, err) { + return + } + + var upload model.Upload + result := db.Get().Where("hash = ?", hashHex).First(&upload) + if (result.Error != nil && result.Error.Error() != "record not found") || result.RowsAffected > 0 { + ctx.JSON(&UploadResponse{Cid: fileCid}) + return + } + + _, err = file.Seek(0, io.SeekStart) + if internalError(ctx, err) { + return + } + + tree, err := bao.ComputeBaoTree(file) + if internalError(ctx, err) { + return + } + + objectExistsResult, err := client.R().Get(fmt.Sprintf("/worker/objects/%s", hashHex)) + + if internalError(ctx, err) { + return + } + + if objectExistsResult.StatusCode() != 404 { + ctx.JSON(&UploadResponse{Cid: fileCid}) + return + } + + ret, err := client.R().SetBody(file).Put(fmt.Sprintf("/worker/objects/%s", hashHex)) + if internalError(ctx, err) { + return + } + fmt.Println(ret) + + _, err = client.R().SetBody(tree).Put(fmt.Sprintf("/worker/objects/%s.obao", hashHex)) + if internalError(ctx, err) { + return + } + + upload = model.Upload{ + Hash: hashHex, + } + if err := db.Get().Create(&upload).Error; err != nil { + if internalError(ctx, err) { + return + } + } + + ctx.JSON(&UploadResponse{Cid: fileCid}) +} + +func internalErrorCustom(ctx iris.Context, err error, customError error) bool { + if err != nil { + if customError != nil { + err = customError + } + ctx.StopWithError(iris.StatusInternalServerError, err) + return true + } + + return false +} +func internalError(ctx iris.Context, err error) bool { + return internalErrorCustom(ctx, err, nil) +}