Compare commits
10 Commits
b21a425e24
...
b44b12f85e
Author | SHA1 | Date |
---|---|---|
Derrick Hammer | b44b12f85e | |
Derrick Hammer | 90e4ce6408 | |
Derrick Hammer | b48db1d8c4 | |
Derrick Hammer | 73bc836cbc | |
Derrick Hammer | 118c679f76 | |
Derrick Hammer | a93add8f70 | |
Derrick Hammer | 2dae0c8687 | |
Derrick Hammer | 488f8737c0 | |
Derrick Hammer | 8f3af2084c | |
Derrick Hammer | 6ceefc11cf |
23
cid/cid.go
23
cid/cid.go
|
@ -3,6 +3,7 @@ package cid
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
|
"encoding/hex"
|
||||||
"errors"
|
"errors"
|
||||||
"github.com/multiformats/go-multibase"
|
"github.com/multiformats/go-multibase"
|
||||||
)
|
)
|
||||||
|
@ -14,7 +15,18 @@ type CID struct {
|
||||||
Size uint64
|
Size uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
func Encode(hash [32]byte, size uint64) (string, error) {
|
func (c CID) StringHash() string {
|
||||||
|
return hex.EncodeToString(c.Hash[:])
|
||||||
|
}
|
||||||
|
|
||||||
|
func Encode(hash []byte, size uint64) (string, error) {
|
||||||
|
var hashBytes [32]byte
|
||||||
|
copy(hashBytes[:], hash)
|
||||||
|
|
||||||
|
return EncodeFixed(hashBytes, size)
|
||||||
|
}
|
||||||
|
|
||||||
|
func EncodeFixed(hash [32]byte, size uint64) (string, error) {
|
||||||
sizeBytes := make([]byte, 8)
|
sizeBytes := make([]byte, 8)
|
||||||
binary.LittleEndian.PutUint64(sizeBytes, size)
|
binary.LittleEndian.PutUint64(sizeBytes, size)
|
||||||
|
|
||||||
|
@ -24,6 +36,15 @@ func Encode(hash [32]byte, size uint64) (string, error) {
|
||||||
return multibase.Encode(multibase.Base58BTC, prefixedHash)
|
return multibase.Encode(multibase.Base58BTC, prefixedHash)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func EncodeString(hash string, size uint64) (string, error) {
|
||||||
|
hashBytes, err := hex.DecodeString(hash)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return Encode(hashBytes, size)
|
||||||
|
}
|
||||||
|
|
||||||
func Valid(cid string) (bool, error) {
|
func Valid(cid string) (bool, error) {
|
||||||
_, err := maybeDecode(cid)
|
_, err := maybeDecode(cid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package service
|
package controller
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/ed25519"
|
"crypto/ed25519"
|
||||||
|
@ -14,7 +14,7 @@ import (
|
||||||
"reflect"
|
"reflect"
|
||||||
)
|
)
|
||||||
|
|
||||||
type AccountService struct {
|
type AccountController struct {
|
||||||
Ctx iris.Context
|
Ctx iris.Context
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,7 +64,7 @@ func hashPassword(password string) (string, error) {
|
||||||
return string(hashedPassword), nil
|
return string(hashedPassword), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *AccountService) PostRegister() {
|
func (a *AccountController) PostRegister() {
|
||||||
var r RegisterRequest
|
var r RegisterRequest
|
||||||
|
|
||||||
if err := a.Ctx.ReadJSON(&r); err != nil {
|
if err := a.Ctx.ReadJSON(&r); err != nil {
|
|
@ -1,4 +1,4 @@
|
||||||
package service
|
package controller
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/ed25519"
|
"crypto/ed25519"
|
||||||
|
@ -22,7 +22,7 @@ func init() {
|
||||||
blocklist = jwt.NewBlocklist(1 * time.Hour)
|
blocklist = jwt.NewBlocklist(1 * time.Hour)
|
||||||
}
|
}
|
||||||
|
|
||||||
type AuthService struct {
|
type AuthController struct {
|
||||||
Ctx iris.Context
|
Ctx iris.Context
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,7 +132,7 @@ func generateAndSaveChallengeToken(accountID uint, maxAge time.Duration) (string
|
||||||
}
|
}
|
||||||
|
|
||||||
// PostLogin handles the POST /api/auth/login request to authenticate a user and return a JWT token.
|
// PostLogin handles the POST /api/auth/login request to authenticate a user and return a JWT token.
|
||||||
func (a *AuthService) PostLogin() {
|
func (a *AuthController) PostLogin() {
|
||||||
var r LoginRequest
|
var r LoginRequest
|
||||||
|
|
||||||
// Read the login request from the client.
|
// Read the login request from the client.
|
||||||
|
@ -169,7 +169,7 @@ func (a *AuthService) PostLogin() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// PostChallenge handles the POST /api/auth/pubkey/challenge request to generate a challenge for a user's public key.
|
// PostChallenge handles the POST /api/auth/pubkey/challenge request to generate a challenge for a user's public key.
|
||||||
func (a *AuthService) PostPubkeyChallenge() {
|
func (a *AuthController) PostPubkeyChallenge() {
|
||||||
var r LoginRequest
|
var r LoginRequest
|
||||||
|
|
||||||
// Read the login request from the client.
|
// Read the login request from the client.
|
||||||
|
@ -200,7 +200,7 @@ func (a *AuthService) PostPubkeyChallenge() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// PostKeyLogin handles the POST /api/auth/pubkey/login request to authenticate a user using a public key challenge and return a JWT token.
|
// PostKeyLogin handles the POST /api/auth/pubkey/login request to authenticate a user using a public key challenge and return a JWT token.
|
||||||
func (a *AuthService) PostPubkeyLogin() {
|
func (a *AuthController) PostPubkeyLogin() {
|
||||||
var r PubkeyLoginRequest
|
var r PubkeyLoginRequest
|
||||||
|
|
||||||
// Read the key login request from the client.
|
// Read the key login request from the client.
|
||||||
|
@ -268,7 +268,7 @@ func (a *AuthService) PostPubkeyLogin() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// PostLogout handles the POST /api/auth/logout request to invalidate a JWT token.
|
// PostLogout handles the POST /api/auth/logout request to invalidate a JWT token.
|
||||||
func (a *AuthService) PostLogout() {
|
func (a *AuthController) PostLogout() {
|
||||||
var r LogoutRequest
|
var r LogoutRequest
|
||||||
|
|
||||||
// Read the logout request from the client.
|
// Read the logout request from the client.
|
|
@ -0,0 +1,88 @@
|
||||||
|
package controller
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"git.lumeweb.com/LumeWeb/portal/cid"
|
||||||
|
"git.lumeweb.com/LumeWeb/portal/service/files"
|
||||||
|
"github.com/kataras/iris/v12"
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
type FilesController struct {
|
||||||
|
Ctx iris.Context
|
||||||
|
}
|
||||||
|
type UploadResponse struct {
|
||||||
|
Cid string `json:"cid"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FilesController) PostUpload() {
|
||||||
|
ctx := f.Ctx
|
||||||
|
|
||||||
|
file, meta, err := f.Ctx.FormFile("file")
|
||||||
|
if internalErrorCustom(ctx, err, errors.New("invalid file data")) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
upload, err := files.Upload(file)
|
||||||
|
|
||||||
|
if internalError(ctx, err) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
cidString, err := cid.EncodeString(upload.Hash, uint64(meta.Size))
|
||||||
|
|
||||||
|
if internalError(ctx, err) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
_ = ctx.JSON(&UploadResponse{Cid: cidString})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FilesController) GetDownloadBy(cidString string) {
|
||||||
|
ctx := f.Ctx
|
||||||
|
|
||||||
|
_, err := cid.Valid(cidString)
|
||||||
|
if sendError(ctx, err, iris.StatusBadRequest) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
cidObject, _ := cid.Decode(cidString)
|
||||||
|
hashHex := cidObject.StringHash()
|
||||||
|
|
||||||
|
if internalError(ctx, err) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
download, err := files.Download(hashHex)
|
||||||
|
if internalError(ctx, err) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = ctx.StreamWriter(func(w io.Writer) error {
|
||||||
|
_, err = io.Copy(w, download)
|
||||||
|
_ = download.(io.Closer).Close()
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
internalError(ctx, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func sendErrorCustom(ctx iris.Context, err error, customError error, irisError int) bool {
|
||||||
|
if err != nil {
|
||||||
|
if customError != nil {
|
||||||
|
err = customError
|
||||||
|
}
|
||||||
|
ctx.StopWithError(irisError, err)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
func internalError(ctx iris.Context, err error) bool {
|
||||||
|
return sendErrorCustom(ctx, err, nil, iris.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
func internalErrorCustom(ctx iris.Context, err error, customError error) bool {
|
||||||
|
return sendErrorCustom(ctx, err, customError, iris.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
func sendError(ctx iris.Context, err error, irisError int) bool {
|
||||||
|
return sendErrorCustom(ctx, err, nil, irisError)
|
||||||
|
}
|
18
main.go
18
main.go
|
@ -3,16 +3,18 @@ package main
|
||||||
import (
|
import (
|
||||||
"embed"
|
"embed"
|
||||||
"git.lumeweb.com/LumeWeb/portal/config"
|
"git.lumeweb.com/LumeWeb/portal/config"
|
||||||
|
"git.lumeweb.com/LumeWeb/portal/controller"
|
||||||
"git.lumeweb.com/LumeWeb/portal/db"
|
"git.lumeweb.com/LumeWeb/portal/db"
|
||||||
_ "git.lumeweb.com/LumeWeb/portal/docs"
|
_ "git.lumeweb.com/LumeWeb/portal/docs"
|
||||||
"git.lumeweb.com/LumeWeb/portal/renterd"
|
"git.lumeweb.com/LumeWeb/portal/renterd"
|
||||||
"git.lumeweb.com/LumeWeb/portal/service"
|
"git.lumeweb.com/LumeWeb/portal/service/files"
|
||||||
"git.lumeweb.com/LumeWeb/portal/validator"
|
"git.lumeweb.com/LumeWeb/portal/validator"
|
||||||
"github.com/iris-contrib/swagger"
|
"github.com/iris-contrib/swagger"
|
||||||
"github.com/iris-contrib/swagger/swaggerFiles"
|
"github.com/iris-contrib/swagger/swaggerFiles"
|
||||||
"github.com/kataras/iris/v12"
|
"github.com/kataras/iris/v12"
|
||||||
"github.com/kataras/iris/v12/mvc"
|
"github.com/kataras/iris/v12/mvc"
|
||||||
"log"
|
"log"
|
||||||
|
"net/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Embed a directory of static files for serving from the app's root path
|
// Embed a directory of static files for serving from the app's root path
|
||||||
|
@ -45,7 +47,7 @@ func main() {
|
||||||
|
|
||||||
renterd.Ready()
|
renterd.Ready()
|
||||||
|
|
||||||
service.InitFiles()
|
files.Init()
|
||||||
|
|
||||||
// Create a new Iris app instance
|
// Create a new Iris app instance
|
||||||
app := iris.New()
|
app := iris.New()
|
||||||
|
@ -61,19 +63,23 @@ func main() {
|
||||||
api := app.Party("/api")
|
api := app.Party("/api")
|
||||||
v1 := api.Party("/v1")
|
v1 := api.Party("/v1")
|
||||||
|
|
||||||
// Register the AccountService with the MVC framework and attach it to the "/api/account" path
|
// Register the AccountController with the MVC framework and attach it to the "/api/account" path
|
||||||
mvc.Configure(v1.Party("/account"), func(app *mvc.Application) {
|
mvc.Configure(v1.Party("/account"), func(app *mvc.Application) {
|
||||||
app.Handle(new(service.AccountService))
|
app.Handle(new(controller.AccountController))
|
||||||
})
|
})
|
||||||
|
|
||||||
mvc.Configure(v1.Party("/auth"), func(app *mvc.Application) {
|
mvc.Configure(v1.Party("/auth"), func(app *mvc.Application) {
|
||||||
app.Handle(new(service.AuthService))
|
app.Handle(new(controller.AuthController))
|
||||||
})
|
})
|
||||||
|
|
||||||
mvc.Configure(v1.Party("/files"), func(app *mvc.Application) {
|
mvc.Configure(v1.Party("/files"), func(app *mvc.Application) {
|
||||||
app.Handle(new(service.FilesService))
|
app.Handle(new(controller.FilesController))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
tus := initTus()
|
||||||
|
|
||||||
|
app.Any(API_PATH+"{fileparam:path}", iris.FromStd(http.StripPrefix(API_PATH, tus)))
|
||||||
|
|
||||||
swaggerConfig := swagger.Config{
|
swaggerConfig := swagger.Config{
|
||||||
// The url pointing to API definition.
|
// The url pointing to API definition.
|
||||||
URL: "http://localhost:8080/swagger/doc.json",
|
URL: "http://localhost:8080/swagger/doc.json",
|
||||||
|
|
|
@ -0,0 +1,112 @@
|
||||||
|
package files
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"encoding/hex"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"git.lumeweb.com/LumeWeb/portal/bao"
|
||||||
|
"git.lumeweb.com/LumeWeb/portal/db"
|
||||||
|
"git.lumeweb.com/LumeWeb/portal/model"
|
||||||
|
"git.lumeweb.com/LumeWeb/portal/renterd"
|
||||||
|
"github.com/go-resty/resty/v2"
|
||||||
|
"io"
|
||||||
|
"lukechampine.com/blake3"
|
||||||
|
)
|
||||||
|
|
||||||
|
var client *resty.Client
|
||||||
|
|
||||||
|
func Init() {
|
||||||
|
client = resty.New()
|
||||||
|
client.SetBaseURL(renterd.GetApiAddr() + "/api")
|
||||||
|
client.SetBasicAuth("", renterd.GetAPIPassword())
|
||||||
|
client.SetDisableWarn(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Upload(r io.ReadSeeker) (model.Upload, error) {
|
||||||
|
var upload model.Upload
|
||||||
|
|
||||||
|
hasher := blake3.New(0, nil)
|
||||||
|
|
||||||
|
_, err := io.Copy(hasher, r)
|
||||||
|
if err != nil {
|
||||||
|
return upload, err
|
||||||
|
}
|
||||||
|
|
||||||
|
hashBytes := hasher.Sum(nil)
|
||||||
|
hashHex := hex.EncodeToString(hashBytes[:])
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return upload, err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = r.Seek(0, io.SeekStart)
|
||||||
|
if err != nil {
|
||||||
|
return upload, err
|
||||||
|
}
|
||||||
|
|
||||||
|
result := db.Get().Where("hash = ?", hashHex).First(&upload)
|
||||||
|
if (result.Error != nil && result.Error.Error() != "record not found") || result.RowsAffected > 0 {
|
||||||
|
err := result.Row().Scan(&upload)
|
||||||
|
if err != nil {
|
||||||
|
return upload, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
objectExistsResult, err := client.R().Get(fmt.Sprintf("/worker/objects/%s", hashHex))
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return upload, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if objectExistsResult.StatusCode() != 404 {
|
||||||
|
return upload, errors.New("file already exists in network, but missing in database")
|
||||||
|
}
|
||||||
|
|
||||||
|
tree, err := bao.ComputeBaoTree(bufio.NewReader(r))
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return upload, err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = r.Seek(0, io.SeekStart)
|
||||||
|
if err != nil {
|
||||||
|
return upload, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ret, err := client.R().SetBody(r).Put(fmt.Sprintf("/worker/objects/%s", hashHex))
|
||||||
|
if ret.StatusCode() != 200 {
|
||||||
|
err = errors.New(string(ret.Body()))
|
||||||
|
return upload, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ret, err = client.R().SetBody(tree).Put(fmt.Sprintf("/worker/objects/%s.obao", hashHex))
|
||||||
|
if ret.StatusCode() != 200 {
|
||||||
|
err = errors.New(string(ret.Body()))
|
||||||
|
return upload, err
|
||||||
|
}
|
||||||
|
|
||||||
|
upload = model.Upload{
|
||||||
|
Hash: hashHex,
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = db.Get().Create(&upload).Error; err != nil {
|
||||||
|
return upload, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return upload, nil
|
||||||
|
}
|
||||||
|
func Download(hash string) (io.Reader, error) {
|
||||||
|
result := db.Get().Table("uploads").Where("hash = ?", hash).Row()
|
||||||
|
|
||||||
|
if result.Err() != nil {
|
||||||
|
return nil, result.Err()
|
||||||
|
}
|
||||||
|
|
||||||
|
fetch, err := client.R().SetDoNotParseResponse(true).Get(fmt.Sprintf("/worker/objects/%s", hash))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return fetch.RawBody(), nil
|
||||||
|
}
|
|
@ -1,190 +0,0 @@
|
||||||
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())
|
|
||||||
client.SetDisableWarn(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *FilesService) PostUpload() {
|
|
||||||
ctx := f.Ctx
|
|
||||||
|
|
||||||
file, meta, err := f.Ctx.FormFile("file")
|
|
||||||
if internalErrorCustom(ctx, err, errors.New("invalid file data")) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
buf, err := io.ReadAll(file)
|
|
||||||
if internalError(ctx, err) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if internalErrorCustom(ctx, err, errors.New("failed to read file data")) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
hashBytes := blake3.Sum256(buf)
|
|
||||||
hashHex := hex.EncodeToString(hashBytes[:])
|
|
||||||
fileCid, err := cid.Encode(hashBytes, uint64(meta.Size))
|
|
||||||
|
|
||||||
if internalError(ctx, err) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = file.Seek(0, io.SeekStart)
|
|
||||||
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(bytes.NewReader(buf))
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
if internalError(ctx, err) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
ret, err := client.R().SetBody(buf).Put(fmt.Sprintf("/worker/objects/%s", hashHex))
|
|
||||||
if ret.StatusCode() != 200 {
|
|
||||||
err = errors.New(string(ret.Body()))
|
|
||||||
}
|
|
||||||
if internalError(ctx, err) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
ret, err = client.R().SetBody(tree).Put(fmt.Sprintf("/worker/objects/%s.obao", hashHex))
|
|
||||||
if ret.StatusCode() != 200 {
|
|
||||||
err = errors.New(string(ret.Body()))
|
|
||||||
}
|
|
||||||
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 (f *FilesService) GetDownload() {
|
|
||||||
ctx := f.Ctx
|
|
||||||
|
|
||||||
cidString := ctx.URLParam("cid")
|
|
||||||
|
|
||||||
_, err := cid.Valid(cidString)
|
|
||||||
if sendError(ctx, err, iris.StatusBadRequest) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
cidObject, _ := cid.Decode(cidString)
|
|
||||||
hashHex := hex.EncodeToString(cidObject.Hash[:])
|
|
||||||
|
|
||||||
result := db.Get().Table("uploads").Where("hash = ?", hashHex).Row()
|
|
||||||
|
|
||||||
if result.Err() != nil {
|
|
||||||
sendError(ctx, result.Err(), iris.StatusNotFound)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
fetch, err := client.R().SetDoNotParseResponse(true).Get(fmt.Sprintf("/worker/objects/%s", hashHex))
|
|
||||||
if err != nil {
|
|
||||||
if fetch.StatusCode() == 404 {
|
|
||||||
sendError(ctx, err, iris.StatusNotFound)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
internalError(ctx, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.Header("Transfer-Encoding", "chunked")
|
|
||||||
|
|
||||||
if internalError(ctx, err) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
err = ctx.StreamWriter(func(w io.Writer) error {
|
|
||||||
_, err = io.Copy(w, fetch.RawBody())
|
|
||||||
_ = fetch.RawBody().Close()
|
|
||||||
return err
|
|
||||||
})
|
|
||||||
internalError(ctx, err)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func sendErrorCustom(ctx iris.Context, err error, customError error, irisError int) bool {
|
|
||||||
if err != nil {
|
|
||||||
if customError != nil {
|
|
||||||
err = customError
|
|
||||||
}
|
|
||||||
ctx.StopWithError(irisError, err)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
func internalError(ctx iris.Context, err error) bool {
|
|
||||||
return sendErrorCustom(ctx, err, nil, iris.StatusInternalServerError)
|
|
||||||
}
|
|
||||||
func internalErrorCustom(ctx iris.Context, err error, customError error) bool {
|
|
||||||
return sendErrorCustom(ctx, err, customError, iris.StatusInternalServerError)
|
|
||||||
}
|
|
||||||
func sendError(ctx iris.Context, err error, irisError int) bool {
|
|
||||||
return sendErrorCustom(ctx, err, nil, irisError)
|
|
||||||
}
|
|
Loading…
Reference in New Issue