portal/protocols/s5.go

167 lines
4.1 KiB
Go
Raw Normal View History

2024-01-12 00:11:53 +00:00
package protocols
import (
2024-01-24 08:28:47 +00:00
"crypto/ed25519"
"fmt"
s5config "git.lumeweb.com/LumeWeb/libs5-go/config"
s5ed "git.lumeweb.com/LumeWeb/libs5-go/ed25519"
"git.lumeweb.com/LumeWeb/libs5-go/encoding"
s5interfaces "git.lumeweb.com/LumeWeb/libs5-go/interfaces"
s5node "git.lumeweb.com/LumeWeb/libs5-go/node"
s5storage "git.lumeweb.com/LumeWeb/libs5-go/storage"
"git.lumeweb.com/LumeWeb/libs5-go/types"
"git.lumeweb.com/LumeWeb/portal/interfaces"
bolt "go.etcd.io/bbolt"
"go.uber.org/zap"
"time"
)
var (
2024-01-24 08:28:47 +00:00
_ interfaces.Protocol = (*S5Protocol)(nil)
_ s5interfaces.ProviderStore = (*S5ProviderStore)(nil)
)
type S5Protocol struct {
2024-01-12 13:22:13 +00:00
node s5interfaces.Node
portal interfaces.Portal
}
func NewS5Protocol() *S5Protocol {
return &S5Protocol{}
}
2024-01-12 13:22:13 +00:00
func (s *S5Protocol) Initialize(portal interfaces.Portal) error {
s.portal = portal
logger := portal.Logger()
config := portal.Config()
cfg := &s5config.NodeConfig{
P2P: s5config.P2PConfig{
Network: "",
Peers: s5config.PeersConfig{Initial: []string{}},
},
2024-01-12 13:22:40 +00:00
KeyPair: s5ed.New(portal.Identity()),
DB: nil,
2024-01-12 13:22:51 +00:00
Logger: portal.Logger().Named("s5"),
HTTP: s5config.HTTPConfig{},
}
2024-01-12 04:32:31 +00:00
pconfig := config.Sub("protocol.s5")
2024-01-12 14:30:23 +00:00
if pconfig == nil {
logger.Fatal("Missing protocol.s5 config")
}
err := pconfig.Unmarshal(cfg)
if err != nil {
return err
}
2024-01-12 15:32:19 +00:00
cfg.HTTP.API.Domain = fmt.Sprintf("s5.%s", config.GetString("core.domain"))
if config.IsSet("core.externalPort") {
cfg.HTTP.API.Port = config.GetUint("core.externalPort")
} else {
cfg.HTTP.API.Port = config.GetUint("core.port")
}
2024-01-12 14:30:23 +00:00
2024-01-12 11:37:01 +00:00
dbPath := pconfig.GetString("dbPath")
if dbPath == "" {
2024-01-12 14:30:55 +00:00
logger.Fatal("protocol.s5.dbPath is required")
2024-01-12 11:37:01 +00:00
}
_, p, err := ed25519.GenerateKey(nil)
if err != nil {
2024-01-12 11:37:11 +00:00
logger.Fatal("Failed to generate key", zap.Error(err))
}
cfg.KeyPair = s5ed.New(p)
2024-01-12 11:37:01 +00:00
db, err := bolt.Open(dbPath, 0600, nil)
if err != nil {
2024-01-12 11:37:11 +00:00
logger.Fatal("Failed to open db", zap.Error(err))
}
cfg.DB = db
s.node = s5node.NewNode(cfg)
2024-01-24 08:28:47 +00:00
s.node.SetProviderStore(&S5ProviderStore{proto: s})
return nil
}
func (s *S5Protocol) Start() error {
2024-01-12 15:16:04 +00:00
err := s.node.Start()
if err != nil {
return err
}
identity, err := s.node.Services().P2P().NodeId().ToString()
if err != nil {
return err
}
s.portal.Logger().Info("S5 protocol started", zap.String("identity", identity), zap.String("network", s.node.NetworkId()), zap.String("domain", s.node.Config().HTTP.API.Domain))
2024-01-12 15:16:04 +00:00
return nil
}
func (s *S5Protocol) Node() s5interfaces.Node {
return s.node
}
2024-01-24 08:28:47 +00:00
type S5ProviderStore struct {
proto *S5Protocol
}
func (s S5ProviderStore) CanProvide(hash *encoding.Multihash, kind []types.StorageLocationType) bool {
for _, t := range kind {
switch t {
case types.StorageLocationTypeArchive, types.StorageLocationTypeFile, types.StorageLocationTypeFull:
rawHash := hash.HashBytes()
if exists, _ := s.proto.portal.Storage().FileExists(rawHash); exists {
return true
}
}
}
return false
}
func (s S5ProviderStore) Provide(hash *encoding.Multihash, kind []types.StorageLocationType) (s5interfaces.StorageLocation, error) {
for _, t := range kind {
if !s.CanProvide(hash, []types.StorageLocationType{t}) {
continue
}
switch t {
case types.StorageLocationTypeArchive:
return s5storage.NewStorageLocation(int(types.StorageLocationTypeArchive), []string{}, calculateExpiry(24*time.Hour)), nil
case types.StorageLocationTypeFile, types.StorageLocationTypeFull:
return s5storage.NewStorageLocation(int(types.StorageLocationTypeFull), []string{generateDownloadUrl(hash, s.proto.portal)}, calculateExpiry(24*time.Hour)), nil
2024-01-24 08:28:47 +00:00
}
}
hashStr, err := hash.ToString()
if err != nil {
return nil, err
}
return nil, fmt.Errorf("could not provide hash %s for types %v", hashStr, kind)
}
func calculateExpiry(duration time.Duration) int64 {
return time.Now().Add(duration).Unix()
}
2024-01-24 08:36:03 +00:00
func generateDownloadUrl(hash *encoding.Multihash, portal interfaces.Portal) string {
domain := portal.Config().GetString("core.domain")
hashStr, err := hash.ToBase64Url()
if err != nil {
portal.Logger().Error("error encoding hash", zap.Error(err))
}
2024-01-24 15:32:44 +00:00
return fmt.Sprintf("https://s5.%s/s5/download/%s", domain, hashStr)
2024-01-24 08:36:03 +00:00
}