portal/storage/storage.go

151 lines
3.1 KiB
Go

package storage
import (
"bytes"
"encoding/hex"
"errors"
"git.lumeweb.com/LumeWeb/libs5-go/encoding"
"git.lumeweb.com/LumeWeb/portal/db/models"
"git.lumeweb.com/LumeWeb/portal/interfaces"
"github.com/go-resty/resty/v2"
"io"
"lukechampine.com/blake3"
)
var (
_ interfaces.StorageService = (*StorageServiceImpl)(nil)
)
type StorageServiceImpl struct {
portal interfaces.Portal
httpApi *resty.Client
}
func NewStorageService(portal interfaces.Portal) interfaces.StorageService {
return &StorageServiceImpl{
portal: portal,
httpApi: nil,
}
}
func (s StorageServiceImpl) PutFile(file io.ReadSeeker, bucket string, generateProof bool) ([]byte, error) {
hash, err := s.GetHash(file)
hashStr, err := encoding.NewMultihash(hash[:]).ToBase64Url()
if err != nil {
return nil, err
}
_, err = file.Seek(0, io.SeekStart)
if err != nil {
return nil, err
}
err = s.createBucketIfNotExists(bucket)
if err != nil {
return nil, err
}
resp, err := s.httpApi.R().
SetPathParam("path", hashStr).
SetFormData(map[string]string{
"bucket": bucket,
}).
SetBody(file).Put("/api/worker/objects/{path}")
if err != nil {
return nil, err
}
if resp.IsError() {
if resp.Error() != nil {
return nil, resp.Error().(error)
}
return nil, errors.New(resp.String())
}
return hash[:], nil
}
func (s *StorageServiceImpl) Init() {
client := resty.New()
client.SetDisableWarn(true)
client.SetBaseURL(s.portal.Config().GetString("core.sia.url"))
client.SetBasicAuth("", s.portal.Config().GetString("core.sia.key"))
s.httpApi = client
}
func (s *StorageServiceImpl) createBucketIfNotExists(bucket string) error {
resp, err := s.httpApi.R().
SetPathParam("bucket", bucket).
Get("/api/bus/bucket/{bucket}")
if err != nil {
return err
}
if resp.StatusCode() != 404 {
if resp.IsError() && resp.Error() != nil {
return resp.Error().(error)
}
} else {
resp, err := s.httpApi.R().
SetBody(map[string]string{
"name": bucket,
}).
Post("/api/bus/buckets")
if err != nil {
return err
}
if resp.IsError() && resp.Error() != nil {
return resp.Error().(error)
}
}
return nil
}
func (s *StorageServiceImpl) FileExists(hash []byte) (bool, models.Upload) {
hashStr := hex.EncodeToString(hash)
var upload models.Upload
result := s.portal.Database().Model(&models.Upload{}).Where(&models.Upload{Hash: hashStr}).First(&upload)
return result.RowsAffected > 0, upload
}
func (s *StorageServiceImpl) GetHash(file io.ReadSeeker) ([]byte, error) {
buf := bytes.NewBuffer(nil)
_, err := io.Copy(buf, file)
if err != nil {
return nil, err
}
hash := blake3.Sum256(buf.Bytes())
return hash[:], nil
}
func (s *StorageServiceImpl) CreateUpload(hash []byte, uploaderID uint, uploaderIP string, size uint64, protocol string) (*models.Upload, error) {
hashStr := hex.EncodeToString(hash)
upload := &models.Upload{
Hash: hashStr,
UserID: uploaderID,
UploaderIP: uploaderIP,
Protocol: protocol,
Size: size,
}
result := s.portal.Database().Create(upload)
if result.Error != nil {
return nil, result.Error
}
return upload, nil
}