feat: implement /s5/debug/download_urls/:cid
This commit is contained in:
parent
32be5fe6e1
commit
7248570e6b
|
@ -44,5 +44,8 @@ func getRoutes(h *s5.HttpHandler, portal interfaces.Portal) map[string]jape.Hand
|
||||||
// Pins API
|
// Pins API
|
||||||
"POST /s5/pin/:cid": s5.AuthMiddleware(h.AccountPin, portal),
|
"POST /s5/pin/:cid": s5.AuthMiddleware(h.AccountPin, portal),
|
||||||
"DELETE /s5/delete/:cid": s5.AuthMiddleware(h.AccountPinDelete, portal),
|
"DELETE /s5/delete/:cid": s5.AuthMiddleware(h.AccountPinDelete, portal),
|
||||||
|
|
||||||
|
// Debug API
|
||||||
|
"/s5/debug/download_urls/:cid": s5.AuthMiddleware(h.DebugDownloadUrls, portal),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,11 +9,15 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"git.lumeweb.com/LumeWeb/libs5-go/encoding"
|
"git.lumeweb.com/LumeWeb/libs5-go/encoding"
|
||||||
|
s5interfaces "git.lumeweb.com/LumeWeb/libs5-go/interfaces"
|
||||||
"git.lumeweb.com/LumeWeb/libs5-go/metadata"
|
"git.lumeweb.com/LumeWeb/libs5-go/metadata"
|
||||||
|
s5storage "git.lumeweb.com/LumeWeb/libs5-go/storage"
|
||||||
"git.lumeweb.com/LumeWeb/libs5-go/types"
|
"git.lumeweb.com/LumeWeb/libs5-go/types"
|
||||||
"git.lumeweb.com/LumeWeb/portal/db/models"
|
"git.lumeweb.com/LumeWeb/portal/db/models"
|
||||||
"git.lumeweb.com/LumeWeb/portal/interfaces"
|
"git.lumeweb.com/LumeWeb/portal/interfaces"
|
||||||
|
"git.lumeweb.com/LumeWeb/portal/protocols"
|
||||||
emailverifier "github.com/AfterShip/email-verifier"
|
emailverifier "github.com/AfterShip/email-verifier"
|
||||||
|
"github.com/samber/lo"
|
||||||
"github.com/vmihailenco/msgpack/v5"
|
"github.com/vmihailenco/msgpack/v5"
|
||||||
"go.sia.tech/jape"
|
"go.sia.tech/jape"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
|
@ -38,6 +42,7 @@ const (
|
||||||
errFailedToDelPin = "Failed to delete pin"
|
errFailedToDelPin = "Failed to delete pin"
|
||||||
errFailedToAddPin = "Failed to add pin"
|
errFailedToAddPin = "Failed to add pin"
|
||||||
errorNotMultiform = "Not a multipart form"
|
errorNotMultiform = "Not a multipart form"
|
||||||
|
errFetchingUrls = "Error fetching urls"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -57,6 +62,7 @@ var (
|
||||||
errFailedToDelPinErr = errors.New(errFailedToDelPin)
|
errFailedToDelPinErr = errors.New(errFailedToDelPin)
|
||||||
errFailedToAddPinErr = errors.New(errFailedToAddPin)
|
errFailedToAddPinErr = errors.New(errFailedToAddPin)
|
||||||
errNotMultiformErr = errors.New(errorNotMultiform)
|
errNotMultiformErr = errors.New(errorNotMultiform)
|
||||||
|
errFetchingUrlsErr = errors.New(errFetchingUrls)
|
||||||
)
|
)
|
||||||
|
|
||||||
type HttpHandler struct {
|
type HttpHandler struct {
|
||||||
|
@ -854,6 +860,95 @@ func (h *HttpHandler) DirectoryUpload(jc jape.Context) {
|
||||||
jc.Encode(&AppUploadResponse{CID: cidStr})
|
jc.Encode(&AppUploadResponse{CID: cidStr})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *HttpHandler) DebugDownloadUrls(jc jape.Context) {
|
||||||
|
var cid string
|
||||||
|
if jc.DecodeParam("cid", &cid) != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
decodedCid, err := encoding.CIDFromString(cid)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
_ = jc.Error(errFetchingUrlsErr, http.StatusInternalServerError)
|
||||||
|
h.portal.Logger().Error(errFetchingUrls, zap.Error(err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
node := h.getNode()
|
||||||
|
|
||||||
|
dlUriProvider := s5storage.NewStorageLocationProvider(node, &decodedCid.Hash, types.StorageLocationTypeFull, types.StorageLocationTypeFile, types.StorageLocationTypeBridge)
|
||||||
|
|
||||||
|
err = dlUriProvider.Start()
|
||||||
|
if err != nil {
|
||||||
|
_ = jc.Error(errFetchingUrlsErr, http.StatusInternalServerError)
|
||||||
|
h.portal.Logger().Error(errFetchingUrls, zap.Error(err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = dlUriProvider.Next()
|
||||||
|
if err != nil {
|
||||||
|
_ = jc.Error(errFetchingUrlsErr, http.StatusInternalServerError)
|
||||||
|
h.portal.Logger().Error(errFetchingUrls, zap.Error(err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
locations, err := node.GetCachedStorageLocations(&decodedCid.Hash, []types.StorageLocationType{
|
||||||
|
types.StorageLocationTypeFull, types.StorageLocationTypeFile, types.StorageLocationTypeBridge,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
_ = jc.Error(errFetchingUrlsErr, http.StatusInternalServerError)
|
||||||
|
h.portal.Logger().Error(errFetchingUrls, zap.Error(err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
availableNodes := lo.Keys[string, s5interfaces.StorageLocation](locations)
|
||||||
|
|
||||||
|
availableNodesIds := make([]*encoding.NodeId, len(availableNodes))
|
||||||
|
|
||||||
|
for i, nodeIdStr := range availableNodes {
|
||||||
|
nodeId, err := encoding.DecodeNodeId(nodeIdStr)
|
||||||
|
if err != nil {
|
||||||
|
_ = jc.Error(errFetchingUrlsErr, http.StatusInternalServerError)
|
||||||
|
h.portal.Logger().Error(errFetchingUrls, zap.Error(err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
availableNodesIds[i] = nodeId
|
||||||
|
}
|
||||||
|
|
||||||
|
sorted, err := node.Services().P2P().SortNodesByScore(availableNodesIds)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
_ = jc.Error(errFetchingUrlsErr, http.StatusInternalServerError)
|
||||||
|
h.portal.Logger().Error(errFetchingUrls, zap.Error(err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
output := make([]string, len(sorted))
|
||||||
|
|
||||||
|
for i, nodeId := range sorted {
|
||||||
|
nodeIdStr, err := nodeId.ToString()
|
||||||
|
if err != nil {
|
||||||
|
_ = jc.Error(errFetchingUrlsErr, http.StatusInternalServerError)
|
||||||
|
h.portal.Logger().Error(errFetchingUrls, zap.Error(err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
output[i] = locations[nodeIdStr].BytesURL()
|
||||||
|
}
|
||||||
|
|
||||||
|
jc.ResponseWriter.WriteHeader(http.StatusOK)
|
||||||
|
_, _ = jc.ResponseWriter.Write([]byte(strings.Join(output, "\n")))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *HttpHandler) getNode() s5interfaces.Node {
|
||||||
|
proto, _ := h.portal.ProtocolRegistry().Get("s5")
|
||||||
|
protoInstance := proto.(*protocols.S5Protocol)
|
||||||
|
|
||||||
|
return protoInstance.Node()
|
||||||
|
}
|
||||||
|
|
||||||
func setAuthCookie(jwt string, jc jape.Context) {
|
func setAuthCookie(jwt string, jc jape.Context) {
|
||||||
authCookie := http.Cookie{
|
authCookie := http.Cookie{
|
||||||
Name: "s5-auth-token",
|
Name: "s5-auth-token",
|
||||||
|
|
Loading…
Reference in New Issue