Skip to content
Snippets Groups Projects
Commit 7f0795c3 authored by Josh Brooks's avatar Josh Brooks
Browse files

Merge branch 'restructure' of git.xx.network:elixxir/client into restructure

parents 26222258 20f588be
Branches
Tags
2 merge requests!510Release,!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"
)
// receiver is the reception handler for a RestServer
type receiver struct {
conn connect.Connection
endpoints *restlike.Endpoints
}
// Hear handles connect.Connection message reception for a RestServer
// Automatically responds to invalid endpoint requests
func (c receiver) 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 = respond(cb(newMessage), c.conn)
} else {
// If no callback, automatically send an error response
respondErr = respond(&restlike.Message{Error: err.Error()}, c.conn)
}
if respondErr != nil {
jww.ERROR.Printf("Unable to singleRespond to request: %+v", err)
}
}
// respond to connect.Connection with the given Message
func respond(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
_, _, _, 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 receiver) Name() string {
return "Restlike"
}
////////////////////////////////////////////////////////////////////////////////
// Copyright © 2022 Privategrity Corporation /
// /
// All rights reserved. /
////////////////////////////////////////////////////////////////////////////////
package connect
import (
"gitlab.com/elixxir/client/e2e/receive"
"gitlab.com/elixxir/client/restlike"
"testing"
)
// Test failure of proto unmarshal
func TestSingleReceiver_Callback_FailUnmarshal(t *testing.T) {
ep := restlike.NewEndpoints()
r := receiver{endpoints: ep}
r.Hear(receive.Message{Payload: []byte("test")})
}
////////////////////////////////////////////////////////////////////////////////
// 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 (
"bytes"
"gitlab.com/elixxir/client/e2e/receive"
"gitlab.com/elixxir/client/restlike"
"google.golang.org/protobuf/proto"
"testing"
"time"
)
// Test happy path
func TestSingleResponse_Callback(t *testing.T) {
resultChan := make(chan *restlike.Message, 1)
cb := func(input *restlike.Message) {
resultChan <- input
}
testPath := "test/path"
testMethod := restlike.Get
testMessage := &restlike.Message{
Content: []byte("test"),
Headers: nil,
Method: uint32(testMethod),
Uri: testPath,
Error: "",
}
r := response{cb}
testPayload, err := proto.Marshal(testMessage)
if err != nil {
t.Errorf(err.Error())
}
r.Hear(receive.Message{Payload: testPayload})
select {
case result := <-resultChan:
if result.Uri != testPath {
t.Errorf("Mismatched uri")
}
if result.Method != uint32(testMethod) {
t.Errorf("Mismatched method")
}
if !bytes.Equal(testMessage.Content, result.Content) {
t.Errorf("Mismatched content")
}
case <-time.After(3 * time.Second):
t.Errorf("Test SingleResponse timed out!")
}
}
// Test proto error path
func TestSingleResponse_Callback_ProtoErr(t *testing.T) {
resultChan := make(chan *restlike.Message, 1)
cb := func(input *restlike.Message) {
resultChan <- input
}
r := response{cb}
r.Hear(receive.Message{Payload: []byte("test")})
select {
case result := <-resultChan:
if len(result.Error) == 0 {
t.Errorf("Expected cb proto error!")
}
case <-time.After(3 * time.Second):
t.Errorf("Test SingleResponse proto error timed out!")
}
}
////////////////////////////////////////////////////////////////////////////////
// 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 := receiver{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,21 +12,22 @@ import ( ...@@ -12,21 +12,22 @@ 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"
) )
// processor is the reception handler for a RestServer // receiver is the reception handler for a RestServer
type singleReceiver struct { type receiver 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 *receiver) 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,21 +4,22 @@ ...@@ -4,21 +4,22 @@
// 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} r := receiver{endpoints: ep}
testReq := single.BuildTestRequest(make([]byte, 0), t) testReq := single.BuildTestRequest(make([]byte, 0), t)
receiver.Callback(testReq, receptionID.EphemeralIdentity{}, nil) r.Callback(testReq, receptionID.EphemeralIdentity{}, nil)
} }
// Test happy path // Test happy path
...@@ -43,7 +44,7 @@ func TestSingleReceiver_Callback_FailUnmarshal(t *testing.T) { ...@@ -43,7 +44,7 @@ func TestSingleReceiver_Callback_FailUnmarshal(t *testing.T) {
// if err != nil { // if err != nil {
// t.Errorf(err.Error()) // t.Errorf(err.Error())
// } // }
// receiver := singleReceiver{endpoints: ep} // receiver := receiver{endpoints: ep}
// //
// testPayload, err := proto.Marshal(testMessage) // testPayload, err := proto.Marshal(testMessage)
// if err != nil { // if err != nil {
......
...@@ -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,13 +32,13 @@ func TestSingleResponse_Callback(t *testing.T) { ...@@ -31,13 +32,13 @@ func TestSingleResponse_Callback(t *testing.T) {
Error: "", Error: "",
} }
response := singleResponse{cb} r := response{cb}
testPayload, err := proto.Marshal(testMessage) testPayload, err := proto.Marshal(testMessage)
if err != nil { if err != nil {
t.Errorf(err.Error()) t.Errorf(err.Error())
} }
response.Callback(testPayload, receptionID.EphemeralIdentity{}, nil, nil) r.Callback(testPayload, receptionID.EphemeralIdentity{}, nil, nil)
select { select {
case result := <-resultChan: case result := <-resultChan:
...@@ -57,13 +58,13 @@ func TestSingleResponse_Callback(t *testing.T) { ...@@ -57,13 +58,13 @@ 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} r := response{cb}
response.Callback(nil, receptionID.EphemeralIdentity{}, nil, errors.New("test")) r.Callback(nil, receptionID.EphemeralIdentity{}, nil, errors.New("test"))
select { select {
case result := <-resultChan: case result := <-resultChan:
...@@ -77,13 +78,13 @@ func TestSingleResponse_Callback_Err(t *testing.T) { ...@@ -77,13 +78,13 @@ 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} r := response{cb}
response.Callback([]byte("test"), receptionID.EphemeralIdentity{}, nil, nil) r.Callback([]byte("test"), receptionID.EphemeralIdentity{}, nil, nil)
select { select {
case result := <-resultChan: case result := <-resultChan:
......
...@@ -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, &receiver{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