feat: implement /s5/debug/download_urls/:cid

This commit is contained in:
Derrick Hammer 2024-01-17 15:36:21 -05:00
parent 32be5fe6e1
commit 7248570e6b
Signed by: pcfreak30
GPG Key ID: C997C339BE476FF2
2 changed files with 98 additions and 0 deletions

View File

@ -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),
} }
} }

View File

@ -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",