diff --git a/go.mod b/go.mod index 85d2efd..cb209a4 100644 --- a/go.mod +++ b/go.mod @@ -12,12 +12,14 @@ require ( github.com/stretchr/testify v1.8.1 github.com/vmihailenco/msgpack/v5 v5.4.1 go.etcd.io/bbolt v1.3.8 + go.sia.tech/jape v0.11.1 go.uber.org/zap v1.26.0 nhooyr.io/websocket v1.7.1 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect + github.com/julienschmidt/httprouter v1.3.0 // indirect github.com/mr-tron/base58 v1.1.0 // indirect github.com/multiformats/go-base32 v0.0.3 // indirect github.com/multiformats/go-base36 v0.1.0 // indirect @@ -26,5 +28,6 @@ require ( go.uber.org/multierr v1.11.0 // indirect golang.org/x/net v0.17.0 // indirect golang.org/x/sys v0.15.0 // indirect + golang.org/x/tools v0.6.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/interfaces/http.go b/interfaces/http.go new file mode 100644 index 0000000..3c8b02e --- /dev/null +++ b/interfaces/http.go @@ -0,0 +1,12 @@ +package interfaces + +import ( + "github.com/julienschmidt/httprouter" +) + +//go:generate mockgen -source=http.go -destination=../mocks/interfaces/http.go -package=interfaces + +type HTTPService interface { + Service + GetHandler() *httprouter.Router +} diff --git a/interfaces/service.go b/interfaces/service.go index 78acace..49138f0 100644 --- a/interfaces/service.go +++ b/interfaces/service.go @@ -11,5 +11,6 @@ type Service interface { type Services interface { P2P() P2PService Registry() RegistryService + HTTP() HTTPService All() []Service } diff --git a/node/node.go b/node/node.go index a608bb1..a9f69e7 100644 --- a/node/node.go +++ b/node/node.go @@ -15,6 +15,7 @@ import ( "git.lumeweb.com/LumeWeb/libs5-go/types" "git.lumeweb.com/LumeWeb/libs5-go/utils" "github.com/go-resty/resty/v2" + "github.com/julienschmidt/httprouter" "github.com/vmihailenco/msgpack/v5" bolt "go.etcd.io/bbolt" "go.uber.org/zap" @@ -52,7 +53,7 @@ func NewNode(config *config.NodeConfig) interfaces.Node { hashQueryRoutingTable: structs.NewMap(), httpClient: resty.New(), } - n.services = NewServices(service.NewP2P(n), service.NewRegistry(n)) + n.services = NewServices(service.NewP2P(n), service.NewRegistry(n), service.NewHTTP(n)) return n } @@ -333,3 +334,7 @@ func (n *NodeImpl) WaitOnConnectedPeers() { func (n *NodeImpl) ConnectionTracker() *sync.WaitGroup { return &n.connections } + +func (n *NodeImpl) HTTPRouter() *httprouter.Router { + return n.services.HTTP().GetHandler() +} diff --git a/node/services.go b/node/services.go index 64b09ba..cd525eb 100644 --- a/node/services.go +++ b/node/services.go @@ -9,12 +9,18 @@ var ( type ServicesImpl struct { p2p interfaces.P2PService registry interfaces.RegistryService + http interfaces.HTTPService +} + +func (s *ServicesImpl) HTTP() interfaces.HTTPService { + return s.http } func (s *ServicesImpl) All() []interfaces.Service { services := make([]interfaces.Service, 0) services = append(services, s.p2p) services = append(services, s.registry) + services = append(services, s.http) return services } @@ -23,10 +29,11 @@ func (s *ServicesImpl) Registry() interfaces.RegistryService { return s.registry } -func NewServices(p2p interfaces.P2PService, registry interfaces.RegistryService) interfaces.Services { +func NewServices(p2p interfaces.P2PService, registry interfaces.RegistryService, http interfaces.HTTPService) interfaces.Services { return &ServicesImpl{ p2p: p2p, registry: registry, + http: http, } } diff --git a/service/http.go b/service/http.go new file mode 100644 index 0000000..f9f13d1 --- /dev/null +++ b/service/http.go @@ -0,0 +1,79 @@ +package service + +import ( + "git.lumeweb.com/LumeWeb/libs5-go/build" + "git.lumeweb.com/LumeWeb/libs5-go/interfaces" + "git.lumeweb.com/LumeWeb/libs5-go/net" + "github.com/julienschmidt/httprouter" + "go.sia.tech/jape" + "go.uber.org/zap" + "net/url" + "nhooyr.io/websocket" +) + +var _ interfaces.HTTPService = (*HTTPImpl)(nil) + +type HTTPImpl struct { + node interfaces.Node +} + +func NewHTTP(node interfaces.Node) *HTTPImpl { + return &HTTPImpl{node: node} +} + +func (h *HTTPImpl) GetHandler() *httprouter.Router { + mux := jape.Mux(map[string]jape.Handler{ + "GET /s5/version": h.versionHandler, + "GET /s5/p2p": h.p2pHandler, + }) + + return mux +} + +func (h *HTTPImpl) Node() interfaces.Node { + return h.node +} + +func (h *HTTPImpl) Start() error { + return nil +} + +func (h *HTTPImpl) Stop() error { + return nil +} + +func (h *HTTPImpl) Init() error { + return nil +} + +func (h *HTTPImpl) versionHandler(ctx jape.Context) { + _, _ = ctx.ResponseWriter.Write([]byte(build.Version)) +} +func (h *HTTPImpl) p2pHandler(ctx jape.Context) { + c, err := websocket.Accept(ctx.ResponseWriter, ctx.Request, nil) + if err != nil { + h.node.Logger().Error("error accepting websocket connection", zap.Error(err)) + return + } + + peer, err := net.CreateTransportPeer("wss", &net.TransportPeerConfig{ + Socket: c, + Uris: []*url.URL{}, + }) + + if err != nil { + h.node.Logger().Error("error creating transport peer", zap.Error(err)) + err := c.Close(websocket.StatusInternalError, "the sky is falling") + if err != nil { + h.node.Logger().Error("error closing websocket connection", zap.Error(err)) + } + return + } + go func() { + err := h.node.Services().P2P().OnNewPeer(peer, true) + if err != nil { + h.node.Logger().Error("error handling new peer", zap.Error(err)) + } + h.node.ConnectionTracker().Done() + }() +}