Skip to content
Snippets Groups Projects
Commit f9c187ea authored by Jake Taylor's avatar Jake Taylor
Browse files

add restlike connection impl

parent 9adbcd08
No related branches found
No related tags found
3 merge requests!510Release,!220Xx 3916/restlike conn,!207WIP: Client Restructure
////////////////////////////////////////////////////////////////////////////////
// Copyright © 2022 Privategrity Corporation /
// /
// All rights reserved. /
////////////////////////////////////////////////////////////////////////////////
package connect
import (
"github.com/pkg/errors"
jww "github.com/spf13/jwalterweatherman"
"gitlab.com/elixxir/client/catalog"
"gitlab.com/elixxir/client/connect"
"gitlab.com/elixxir/client/e2e"
"gitlab.com/elixxir/client/e2e/receive"
"gitlab.com/elixxir/client/restlike"
"google.golang.org/protobuf/proto"
)
// processor is the reception handler for a RestServer
type connectReceiver struct {
conn connect.Connection
endpoints *restlike.Endpoints
}
// Hear handles connect.Connection message reception for a RestServer
// Automatically responds to invalid endpoint requests
func (c connectReceiver) Hear(item receive.Message) {
// Unmarshal the request payload
newMessage := &restlike.Message{}
err := proto.Unmarshal(item.Payload, newMessage)
if err != nil {
jww.ERROR.Printf("Unable to unmarshal restlike message: %+v", err)
return
}
var respondErr error
if cb, err := c.endpoints.Get(restlike.URI(newMessage.GetUri()), restlike.Method(newMessage.GetMethod())); err == nil {
// Send the payload to the proper Callback if it exists and singleRespond with the result
respondErr = connRespond(cb(newMessage), c.conn)
} else {
// If no callback, automatically send an error response
respondErr = connRespond(&restlike.Message{Error: err.Error()}, c.conn)
}
if respondErr != nil {
jww.ERROR.Printf("Unable to singleRespond to request: %+v", err)
}
}
// connRespond to connect.Connection with the given Message
func connRespond(response *restlike.Message, conn connect.Connection) error {
payload, err := proto.Marshal(response)
if err != nil {
return errors.Errorf("unable to marshal restlike response message: %+v", err)
}
// TODO: Parameterize params and timeout
_, _, _, err = conn.SendE2E(catalog.XxMessage, payload, e2e.GetDefaultParams())
if err != nil {
return errors.Errorf("unable to send restlike response message: %+v", err)
}
return nil
}
// Name is used for debugging
func (c connectReceiver) Name() string {
return "Restlike"
}
////////////////////////////////////////////////////////////////////////////////
// Copyright © 2022 Privategrity Corporation /
// /
// All rights reserved. /
////////////////////////////////////////////////////////////////////////////////
package connect
import (
jww "github.com/spf13/jwalterweatherman"
"gitlab.com/elixxir/client/catalog"
"gitlab.com/elixxir/client/connect"
"gitlab.com/elixxir/client/e2e"
"gitlab.com/elixxir/client/restlike"
"gitlab.com/elixxir/crypto/cyclic"
"gitlab.com/xx_network/crypto/csprng"
"google.golang.org/protobuf/proto"
)
// Request allows for making REST-like requests to a RestServer using connect.Connection
// Can be used as stateful or declared inline without state
type Request struct {
Net connect.Connection
Rng csprng.Source
E2eGrp *cyclic.Group
}
// Request provides several Method of sending Data to the given URI
// and blocks until the Message is returned
func (s *Request) Request(method restlike.Method, path restlike.URI,
content restlike.Data, headers *restlike.Headers, e2eParams e2e.Params) (*restlike.Message, error) {
// Build the Message
newMessage := &restlike.Message{
Content: content,
Headers: headers,
Method: uint32(method),
Uri: string(path),
}
msg, err := proto.Marshal(newMessage)
if err != nil {
return nil, err
}
// Build callback for the response
signalChannel := make(chan *restlike.Message, 1)
cb := func(msg *restlike.Message) {
signalChannel <- msg
}
s.Net.RegisterListener(catalog.XxMessage, response{responseCallback: cb})
// Transmit the Message
_, _, _, err = s.Net.SendE2E(catalog.XxMessage, msg, e2eParams)
if err != nil {
return nil, err
}
// Block waiting for single-use response
jww.DEBUG.Printf("Restlike waiting for connect response from %s...",
s.Net.GetPartner().PartnerId().String())
newResponse := <-signalChannel
jww.DEBUG.Printf("Restlike connect response received from %s",
s.Net.GetPartner().PartnerId().String())
return newResponse, nil
}
// AsyncRequest provides several Method of sending Data to the given URI
// and will return the Message to the given Callback when received
func (s *Request) AsyncRequest(method restlike.Method, path restlike.URI,
content restlike.Data, headers *restlike.Headers, cb restlike.RequestCallback, e2eParams e2e.Params) error {
// Build the Message
newMessage := &restlike.Message{
Content: content,
Headers: headers,
Method: uint32(method),
Uri: string(path),
}
msg, err := proto.Marshal(newMessage)
if err != nil {
return err
}
// Build callback for the response
s.Net.RegisterListener(catalog.XxMessage, response{responseCallback: cb})
// Transmit the Message
_, _, _, err = s.Net.SendE2E(catalog.XxMessage, msg, e2eParams)
return err
}
////////////////////////////////////////////////////////////////////////////////
// Copyright © 2022 Privategrity Corporation /
// /
// All rights reserved. /
////////////////////////////////////////////////////////////////////////////////
package connect
import (
"gitlab.com/elixxir/client/e2e/receive"
"gitlab.com/elixxir/client/restlike"
"google.golang.org/protobuf/proto"
)
// response is the response handler for a Request
type response struct {
responseCallback restlike.RequestCallback
}
// Hear handles for connect.Connection message responses for a Request
func (r response) Hear(item receive.Message) {
newMessage := &restlike.Message{}
// Unmarshal the payload
err := proto.Unmarshal(item.Payload, newMessage)
if err != nil {
newMessage.Error = err.Error()
}
// Send the response payload to the responseCallback
r.responseCallback(newMessage)
}
// Name is used for debugging
func (r response) Name() string {
return "Restlike"
}
////////////////////////////////////////////////////////////////////////////////
// Copyright © 2022 Privategrity Corporation /
// /
// All rights reserved. /
////////////////////////////////////////////////////////////////////////////////
package connect
import (
"gitlab.com/elixxir/client/catalog"
"gitlab.com/elixxir/client/cmix"
"gitlab.com/elixxir/client/connect"
"gitlab.com/elixxir/client/restlike"
"gitlab.com/elixxir/crypto/cyclic"
"gitlab.com/elixxir/crypto/fastRNG"
"gitlab.com/xx_network/primitives/id"
)
// Server implements the RestServer interface using connect.Connection
type Server struct {
receptionId *id.ID
endpoints *restlike.Endpoints
}
// NewServer builds a RestServer with connect.Connection and
// the provided arguments, then registers necessary external services
func NewServer(receptionId *id.ID, privKey *cyclic.Int,
rng *fastRNG.StreamGenerator, grp *cyclic.Group, net cmix.Client, p connect.Params) (*Server, error) {
newServer := &Server{
receptionId: receptionId,
endpoints: restlike.NewEndpoints(),
}
// Callback for connection requests
cb := func(conn connect.Connection) {
handler := connectReceiver{endpoints: newServer.endpoints, conn: conn}
conn.RegisterListener(catalog.XxMessage, handler)
}
// Build the connection listener
err := connect.StartServer(cb, receptionId, privKey, rng, grp, net, p)
if err != nil {
return nil, err
}
return newServer, nil
}
// GetEndpoints returns the association of a Callback with
// a specific URI and a variety of different REST Method
func (c *Server) GetEndpoints() *restlike.Endpoints {
return c.endpoints
}
// Close the internal RestServer endpoints and external services
func (c *Server) Close() {
// Clear all internal endpoints
c.endpoints = nil
// TODO: Destroy external services
}
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
// All rights reserved. / // All rights reserved. /
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
package restlike package single
import ( import (
"github.com/pkg/errors" "github.com/pkg/errors"
...@@ -12,6 +12,7 @@ import ( ...@@ -12,6 +12,7 @@ import (
"gitlab.com/elixxir/client/cmix" "gitlab.com/elixxir/client/cmix"
"gitlab.com/elixxir/client/cmix/identity/receptionID" "gitlab.com/elixxir/client/cmix/identity/receptionID"
"gitlab.com/elixxir/client/cmix/rounds" "gitlab.com/elixxir/client/cmix/rounds"
"gitlab.com/elixxir/client/restlike"
"gitlab.com/elixxir/client/single" "gitlab.com/elixxir/client/single"
"google.golang.org/protobuf/proto" "google.golang.org/protobuf/proto"
"time" "time"
...@@ -19,14 +20,14 @@ import ( ...@@ -19,14 +20,14 @@ import (
// processor is the reception handler for a RestServer // processor is the reception handler for a RestServer
type singleReceiver struct { type singleReceiver struct {
endpoints *Endpoints endpoints *restlike.Endpoints
} }
// Callback is the handler for single-use message reception for a RestServer // Callback is the handler for single-use message reception for a RestServer
// Automatically responds to invalid endpoint requests // Automatically responds to invalid endpoint requests
func (s *singleReceiver) Callback(req *single.Request, receptionId receptionID.EphemeralIdentity, rounds []rounds.Round) { func (s *singleReceiver) Callback(req *single.Request, receptionId receptionID.EphemeralIdentity, rounds []rounds.Round) {
// Unmarshal the request payload // Unmarshal the request payload
newMessage := &Message{} newMessage := &restlike.Message{}
err := proto.Unmarshal(req.GetPayload(), newMessage) err := proto.Unmarshal(req.GetPayload(), newMessage)
if err != nil { if err != nil {
jww.ERROR.Printf("Unable to unmarshal restlike message: %+v", err) jww.ERROR.Printf("Unable to unmarshal restlike message: %+v", err)
...@@ -34,20 +35,20 @@ func (s *singleReceiver) Callback(req *single.Request, receptionId receptionID.E ...@@ -34,20 +35,20 @@ func (s *singleReceiver) Callback(req *single.Request, receptionId receptionID.E
} }
var respondErr error var respondErr error
if cb, err := s.endpoints.Get(URI(newMessage.GetUri()), Method(newMessage.GetMethod())); err == nil { if cb, err := s.endpoints.Get(restlike.URI(newMessage.GetUri()), restlike.Method(newMessage.GetMethod())); err == nil {
// Send the payload to the proper Callback if it exists and respond with the result // Send the payload to the proper Callback if it exists and singleRespond with the result
respondErr = respond(cb(newMessage), req) respondErr = singleRespond(cb(newMessage), req)
} else { } else {
// If no callback, automatically send an error response // If no callback, automatically send an error response
respondErr = respond(&Message{Error: err.Error()}, req) respondErr = singleRespond(&restlike.Message{Error: err.Error()}, req)
} }
if respondErr != nil { if respondErr != nil {
jww.ERROR.Printf("Unable to respond to request: %+v", err) jww.ERROR.Printf("Unable to singleRespond to request: %+v", err)
} }
} }
// respond to a single.Request with the given Message // singleRespond to a single.Request with the given Message
func respond(response *Message, req *single.Request) error { func singleRespond(response *restlike.Message, req *single.Request) error {
payload, err := proto.Marshal(response) payload, err := proto.Marshal(response)
if err != nil { if err != nil {
return errors.Errorf("unable to marshal restlike response message: %+v", err) return errors.Errorf("unable to marshal restlike response message: %+v", err)
......
...@@ -4,17 +4,18 @@ ...@@ -4,17 +4,18 @@
// All rights reserved. / // All rights reserved. /
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
package restlike package single
import ( import (
"gitlab.com/elixxir/client/cmix/identity/receptionID" "gitlab.com/elixxir/client/cmix/identity/receptionID"
"gitlab.com/elixxir/client/restlike"
"gitlab.com/elixxir/client/single" "gitlab.com/elixxir/client/single"
"testing" "testing"
) )
// Test failure of proto unmarshal // Test failure of proto unmarshal
func TestSingleReceiver_Callback_FailUnmarshal(t *testing.T) { func TestSingleReceiver_Callback_FailUnmarshal(t *testing.T) {
ep := &Endpoints{endpoints: make(map[URI]map[Method]Callback)} ep := restlike.NewEndpoints()
receiver := singleReceiver{endpoints: ep} receiver := singleReceiver{endpoints: ep}
testReq := single.BuildTestRequest(make([]byte, 0), t) testReq := single.BuildTestRequest(make([]byte, 0), t)
......
...@@ -4,11 +4,12 @@ ...@@ -4,11 +4,12 @@
// All rights reserved. / // All rights reserved. /
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
package restlike package single
import ( import (
jww "github.com/spf13/jwalterweatherman" jww "github.com/spf13/jwalterweatherman"
"gitlab.com/elixxir/client/catalog" "gitlab.com/elixxir/client/catalog"
"gitlab.com/elixxir/client/restlike"
"gitlab.com/elixxir/client/single" "gitlab.com/elixxir/client/single"
"gitlab.com/elixxir/crypto/contact" "gitlab.com/elixxir/crypto/contact"
"gitlab.com/elixxir/crypto/cyclic" "gitlab.com/elixxir/crypto/cyclic"
...@@ -16,9 +17,9 @@ import ( ...@@ -16,9 +17,9 @@ import (
"google.golang.org/protobuf/proto" "google.golang.org/protobuf/proto"
) )
// SingleRequest allows for making REST-like requests to a RestServer using single-use messages // Request allows for making REST-like requests to a RestServer using single-use messages
// Can be used as stateful or declared inline without state // Can be used as stateful or declared inline without state
type SingleRequest struct { type Request struct {
Net single.Cmix Net single.Cmix
Rng csprng.Source Rng csprng.Source
E2eGrp *cyclic.Group E2eGrp *cyclic.Group
...@@ -26,10 +27,10 @@ type SingleRequest struct { ...@@ -26,10 +27,10 @@ type SingleRequest struct {
// Request provides several Method of sending Data to the given URI // Request provides several Method of sending Data to the given URI
// and blocks until the Message is returned // and blocks until the Message is returned
func (s *SingleRequest) Request(recipient contact.Contact, method Method, path URI, func (s *Request) Request(recipient contact.Contact, method restlike.Method, path restlike.URI,
content Data, headers *Headers, singleParams single.RequestParams) (*Message, error) { content restlike.Data, headers *restlike.Headers, singleParams single.RequestParams) (*restlike.Message, error) {
// Build the Message // Build the Message
newMessage := &Message{ newMessage := &restlike.Message{
Content: content, Content: content,
Headers: headers, Headers: headers,
Method: uint32(method), Method: uint32(method),
...@@ -41,14 +42,14 @@ func (s *SingleRequest) Request(recipient contact.Contact, method Method, path U ...@@ -41,14 +42,14 @@ func (s *SingleRequest) Request(recipient contact.Contact, method Method, path U
} }
// Build callback for the single-use response // Build callback for the single-use response
signalChannel := make(chan *Message, 1) signalChannel := make(chan *restlike.Message, 1)
cb := func(msg *Message) { cb := func(msg *restlike.Message) {
signalChannel <- msg signalChannel <- msg
} }
// Transmit the Message // Transmit the Message
_, _, err = single.TransmitRequest(recipient, catalog.RestLike, msg, _, _, err = single.TransmitRequest(recipient, catalog.RestLike, msg,
&singleResponse{responseCallback: cb}, singleParams, s.Net, s.Rng, s.E2eGrp) &response{responseCallback: cb}, singleParams, s.Net, s.Rng, s.E2eGrp)
if err != nil { if err != nil {
return nil, err return nil, err
} }
...@@ -63,10 +64,10 @@ func (s *SingleRequest) Request(recipient contact.Contact, method Method, path U ...@@ -63,10 +64,10 @@ func (s *SingleRequest) Request(recipient contact.Contact, method Method, path U
// AsyncRequest provides several Method of sending Data to the given URI // AsyncRequest provides several Method of sending Data to the given URI
// and will return the Message to the given Callback when received // and will return the Message to the given Callback when received
func (s *SingleRequest) AsyncRequest(recipient contact.Contact, method Method, path URI, func (s *Request) AsyncRequest(recipient contact.Contact, method restlike.Method, path restlike.URI,
content Data, headers *Headers, cb RequestCallback, singleParams single.RequestParams) error { content restlike.Data, headers *restlike.Headers, cb restlike.RequestCallback, singleParams single.RequestParams) error {
// Build the Message // Build the Message
newMessage := &Message{ newMessage := &restlike.Message{
Content: content, Content: content,
Headers: headers, Headers: headers,
Method: uint32(method), Method: uint32(method),
...@@ -79,6 +80,6 @@ func (s *SingleRequest) AsyncRequest(recipient contact.Contact, method Method, p ...@@ -79,6 +80,6 @@ func (s *SingleRequest) AsyncRequest(recipient contact.Contact, method Method, p
// Transmit the Message // Transmit the Message
_, _, err = single.TransmitRequest(recipient, catalog.RestLike, msg, _, _, err = single.TransmitRequest(recipient, catalog.RestLike, msg,
&singleResponse{responseCallback: cb}, singleParams, s.Net, s.Rng, s.E2eGrp) &response{responseCallback: cb}, singleParams, s.Net, s.Rng, s.E2eGrp)
return err return err
} }
...@@ -4,22 +4,23 @@ ...@@ -4,22 +4,23 @@
// All rights reserved. / // All rights reserved. /
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
package restlike package single
import ( import (
"gitlab.com/elixxir/client/cmix/identity/receptionID" "gitlab.com/elixxir/client/cmix/identity/receptionID"
"gitlab.com/elixxir/client/cmix/rounds" "gitlab.com/elixxir/client/cmix/rounds"
"gitlab.com/elixxir/client/restlike"
"google.golang.org/protobuf/proto" "google.golang.org/protobuf/proto"
) )
// processor is the response handler for a Request // response is the response handler for a Request
type singleResponse struct { type response struct {
responseCallback RequestCallback responseCallback restlike.RequestCallback
} }
// Callback is the handler for single-use message responses for a Request // Callback is the handler for single-use message responses for a Request
func (s *singleResponse) Callback(payload []byte, receptionID receptionID.EphemeralIdentity, rounds []rounds.Round, err error) { func (s *response) Callback(payload []byte, receptionID receptionID.EphemeralIdentity, rounds []rounds.Round, err error) {
newMessage := &Message{} newMessage := &restlike.Message{}
// Handle response errors // Handle response errors
if err != nil { if err != nil {
......
...@@ -4,12 +4,13 @@ ...@@ -4,12 +4,13 @@
// All rights reserved. / // All rights reserved. /
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
package restlike package single
import ( import (
"bytes" "bytes"
"github.com/pkg/errors" "github.com/pkg/errors"
"gitlab.com/elixxir/client/cmix/identity/receptionID" "gitlab.com/elixxir/client/cmix/identity/receptionID"
"gitlab.com/elixxir/client/restlike"
"google.golang.org/protobuf/proto" "google.golang.org/protobuf/proto"
"testing" "testing"
"time" "time"
...@@ -17,13 +18,13 @@ import ( ...@@ -17,13 +18,13 @@ import (
// Test happy path // Test happy path
func TestSingleResponse_Callback(t *testing.T) { func TestSingleResponse_Callback(t *testing.T) {
resultChan := make(chan *Message, 1) resultChan := make(chan *restlike.Message, 1)
cb := func(input *Message) { cb := func(input *restlike.Message) {
resultChan <- input resultChan <- input
} }
testPath := "test/path" testPath := "test/path"
testMethod := Get testMethod := restlike.Get
testMessage := &Message{ testMessage := &restlike.Message{
Content: []byte("test"), Content: []byte("test"),
Headers: nil, Headers: nil,
Method: uint32(testMethod), Method: uint32(testMethod),
...@@ -31,7 +32,7 @@ func TestSingleResponse_Callback(t *testing.T) { ...@@ -31,7 +32,7 @@ func TestSingleResponse_Callback(t *testing.T) {
Error: "", Error: "",
} }
response := singleResponse{cb} response := response{cb}
testPayload, err := proto.Marshal(testMessage) testPayload, err := proto.Marshal(testMessage)
if err != nil { if err != nil {
...@@ -57,11 +58,11 @@ func TestSingleResponse_Callback(t *testing.T) { ...@@ -57,11 +58,11 @@ func TestSingleResponse_Callback(t *testing.T) {
// Test error input path // Test error input path
func TestSingleResponse_Callback_Err(t *testing.T) { func TestSingleResponse_Callback_Err(t *testing.T) {
resultChan := make(chan *Message, 1) resultChan := make(chan *restlike.Message, 1)
cb := func(input *Message) { cb := func(input *restlike.Message) {
resultChan <- input resultChan <- input
} }
response := singleResponse{cb} response := response{cb}
response.Callback(nil, receptionID.EphemeralIdentity{}, nil, errors.New("test")) response.Callback(nil, receptionID.EphemeralIdentity{}, nil, errors.New("test"))
...@@ -77,11 +78,11 @@ func TestSingleResponse_Callback_Err(t *testing.T) { ...@@ -77,11 +78,11 @@ func TestSingleResponse_Callback_Err(t *testing.T) {
// Test proto error path // Test proto error path
func TestSingleResponse_Callback_ProtoErr(t *testing.T) { func TestSingleResponse_Callback_ProtoErr(t *testing.T) {
resultChan := make(chan *Message, 1) resultChan := make(chan *restlike.Message, 1)
cb := func(input *Message) { cb := func(input *restlike.Message) {
resultChan <- input resultChan <- input
} }
response := singleResponse{cb} response := response{cb}
response.Callback([]byte("test"), receptionID.EphemeralIdentity{}, nil, nil) response.Callback([]byte("test"), receptionID.EphemeralIdentity{}, nil, nil)
......
...@@ -4,62 +4,43 @@ ...@@ -4,62 +4,43 @@
// All rights reserved. / // All rights reserved. /
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
package restlike package single
import ( import (
"gitlab.com/elixxir/client/catalog" "gitlab.com/elixxir/client/catalog"
"gitlab.com/elixxir/client/restlike"
"gitlab.com/elixxir/client/single" "gitlab.com/elixxir/client/single"
"gitlab.com/elixxir/crypto/cyclic" "gitlab.com/elixxir/crypto/cyclic"
"gitlab.com/xx_network/primitives/id" "gitlab.com/xx_network/primitives/id"
) )
// RestServer allows for clients to make REST-like requests this client // Server implements the RestServer interface using single-use
type RestServer interface { type Server struct {
// RegisterEndpoint allows the association of a Callback with
// a specific URI and a variety of different REST Method
RegisterEndpoint(path URI, method Method, cb Callback) error
// UnregisterEndpoint removes the Callback associated with
// a specific URI and REST Method
UnregisterEndpoint(path URI, method Method) error
// Close the internal RestServer endpoints and external services
Close()
}
// singleServer implements the RestServer interface using single-use
type singleServer struct {
receptionId *id.ID receptionId *id.ID
listener single.Listener listener single.Listener
endpoints *Endpoints endpoints *restlike.Endpoints
} }
// NewSingleServer builds a RestServer with single-use and // NewServer builds a RestServer with single-use and
// the provided arguments, then registers necessary external services // the provided arguments, then registers necessary external services
func NewSingleServer(receptionId *id.ID, privKey *cyclic.Int, net single.ListenCmix, e2eGrp *cyclic.Group) RestServer { func NewServer(receptionId *id.ID, privKey *cyclic.Int, net single.ListenCmix, e2eGrp *cyclic.Group) *Server {
newServer := &singleServer{ newServer := &Server{
receptionId: receptionId, receptionId: receptionId,
endpoints: &Endpoints{endpoints: make(map[URI]map[Method]Callback)}, endpoints: restlike.NewEndpoints(),
} }
newServer.listener = single.Listen(catalog.RestLike, receptionId, privKey, newServer.listener = single.Listen(catalog.RestLike, receptionId, privKey,
net, e2eGrp, &singleReceiver{newServer.endpoints}) net, e2eGrp, &singleReceiver{newServer.endpoints})
return newServer return newServer
} }
// RegisterEndpoint allows the association of a Callback with // GetEndpoints returns the association of a Callback with
// a specific URI and a variety of different REST Method // a specific URI and a variety of different REST Method
func (r *singleServer) RegisterEndpoint(path URI, method Method, cb Callback) error { func (r *Server) GetEndpoints() *restlike.Endpoints {
return r.endpoints.Add(path, method, cb) return r.endpoints
}
// UnregisterEndpoint removes the Callback associated with
// a specific URI and REST Method
func (r *singleServer) UnregisterEndpoint(path URI, method Method) error {
return r.endpoints.Remove(path, method)
} }
// Close the internal RestServer endpoints and external services // Close the internal RestServer endpoints and external services
func (r *singleServer) Close() { func (r *Server) Close() {
// Clear all internal endpoints // Clear all internal endpoints
r.endpoints = nil r.endpoints = nil
// Destroy external services // Destroy external services
......
...@@ -68,6 +68,11 @@ type Endpoints struct { ...@@ -68,6 +68,11 @@ type Endpoints struct {
sync.RWMutex sync.RWMutex
} }
// NewEndpoints returns a new Endpoints object
func NewEndpoints() *Endpoints {
return &Endpoints{endpoints: make(map[URI]map[Method]Callback)}
}
// Add a new Endpoint // Add a new Endpoint
// Returns an error if Endpoint already exists // Returns an error if Endpoint already exists
func (e *Endpoints) Add(path URI, method Method, cb Callback) error { func (e *Endpoints) Add(path URI, method Method, cb Callback) error {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment