diff --git a/api/send.go b/api/send.go index 1dce603cf5fcdd5b762180b01dbf938eff73bebd..e1a9bd231e8cc0c8b5747532c44a88c41ab7c6d4 100644 --- a/api/send.go +++ b/api/send.go @@ -1,6 +1,7 @@ package api import ( + "github.com/pkg/errors" jww "github.com/spf13/jwalterweatherman" "gitlab.com/elixxir/client/interfaces/message" "gitlab.com/elixxir/client/interfaces/params" @@ -47,10 +48,13 @@ func (c *Client) SendCMIX(msg format.Message, param params.CMIX) (id.Round, // for the current cMix network. // FIXME: this is weird and shouldn't be necessary, but it is. func (c *Client) NewCMIXMessage(recipient *id.ID, - contents []byte) format.Message { + contents []byte) (format.Message, error) { primeSize := len(c.storage.Cmix().GetGroup().GetPBytes()) msg := format.NewMessage(primeSize) + if len(contents) > msg.ContentsSize() { + return format.Message{}, errors.New("Contents to long for cmix") + } msg.SetContents(contents) msg.SetRecipientID(recipient) - return msg + return msg, nil } diff --git a/bindings/callback.go b/bindings/callback.go new file mode 100644 index 0000000000000000000000000000000000000000..6ff0dc52502f57a89c591b4c3ee3eb612020e6a6 --- /dev/null +++ b/bindings/callback.go @@ -0,0 +1,53 @@ +package bindings + +import ( + "gitlab.com/elixxir/client/interfaces" + "gitlab.com/elixxir/client/switchboard" + "gitlab.com/elixxir/comms/network/dataStructures" + "gitlab.com/xx_network/primitives/id" +) + +// Listener provides a callback to hear a message +// An object implementing this interface can be called back when the client +// gets a message of the type that the regi sterer specified at registration +// time. +type Listener interface { + // Hear is called to receive a message in the UI + Hear(message Message) + // Returns a name, used for debugging + Name() string +} + +// RoundEventHandler handles round events happening on the cMix network. +type RoundEventCallback interface { + EventCallback(rid int, state byte, timedOut bool) +} + +// Generic Unregister - a generic return used for all callbacks which can be +// unregistered +// Interface which allows the un-registration of a listener +type Unregister struct { + f func() +} + +//Call unregisters a callback +func (u Unregister) Unregister() { + u.f() +} + +//creates an unregister interface for listeners +func newListenerUnregister(lid switchboard.ListenerID, sw interfaces.Switchboard) Unregister { + f := func() { + sw.Unregister(lid) + } + return Unregister{f: f} +} + +//creates an unregister interface for round events +func newRoundUnregister(rid id.Round, ec *dataStructures.EventCallback, + re interfaces.RoundEvents) Unregister { + f := func() { + re.Remove(rid, ec) + } + return Unregister{f: f} +} diff --git a/bindings/client.go b/bindings/client.go index 6b1d88a8103167e0e4afb8f49a98a2b8498858a2..bb1f0714addc8acf17c6d55cb8bcb775cf0610eb 100644 --- a/bindings/client.go +++ b/bindings/client.go @@ -10,6 +10,8 @@ import ( "github.com/pkg/errors" "gitlab.com/elixxir/client/api" "gitlab.com/elixxir/client/interfaces/message" + "gitlab.com/elixxir/comms/mixmessages" + "gitlab.com/elixxir/primitives/states" "gitlab.com/xx_network/primitives/id" "time" ) @@ -127,13 +129,17 @@ func (c *Client) RegisterNetworkHealthCB(nhc NetworkHealthCallback) { // RegisterListener records and installs a listener for messages // matching specific uid, msgType, and/or username +// Returns a ListenerUnregister interface which can be +// +// Message Types can be found in client/interfaces/message/type.go +// Make sure to not conflict with ANY default message types func (c *Client) RegisterListener(uid []byte, msgType int, - listener Listener) (ListenerID, error) { + listener Listener) (Unregister, error) { name := listener.Name() u, err := id.Unmarshal(uid) if err != nil { - return ListenerID{}, err + return Unregister{}, err } mt := message.Type(msgType) @@ -143,20 +149,53 @@ func (c *Client) RegisterListener(uid []byte, msgType int, lid := c.api.GetSwitchboard().RegisterFunc(name, u, mt, f) - return ListenerID{id: lid}, nil -} - -// Unregister removes the listener with the specified ID so it will no -// longer get called -func (c *Client) UnregisterListener(lid ListenerID) { - c.api.GetSwitchboard().Unregister(lid.id) + return newListenerUnregister(lid, c.api.GetSwitchboard()), nil } // RegisterRoundEventsHandler registers a callback interface for round // events. -func (c *Client) RegisterRoundEventsHandler(hdlr RoundEventHandler) { +// The rid is the round the event attaches to +// The timeoutMS is the number of milliseconds until the event fails, and the +// validStates are a list of states (one per byte) on which the event gets +// triggered +// States: +// 0x00 - PENDING (Never seen by client) +// 0x01 - PRECOMPUTING +// 0x02 - STANDBY +// 0x03 - QUEUED +// 0x04 - REALTIME +// 0x05 - COMPLETED +// 0x06 - FAILED +// These states are defined in elixxir/primitives/states/state.go +func (c *Client) RegisterRoundEventsHandler(rid int, cb RoundEventCallback, + timeoutMS int, validStates []byte) Unregister { + + rcb := func(ri *mixmessages.RoundInfo, timedOut bool) { + cb.EventCallback(int(ri.ID), byte(ri.State), timedOut) + } + + timeout := time.Duration(timeoutMS) * time.Millisecond + + vStates := make([]states.Round, len(validStates)) + for i, s := range validStates { + vStates[i] = states.Round(s) + } + + roundID := id.Round(rid) + + ec := c.api.GetRoundEvents().AddRoundEvent(roundID, rcb, timeout, vStates...) + + return newRoundUnregister(roundID, ec, c.api.GetRoundEvents()) +} + +// Returns a user object from which all information about the current user +// can be gleaned +func (c *Client) GetUser() User { + return c.GetUser() } + + /* // SearchWithHandler is a non-blocking search that also registers // a callback interface for user disovery events. @@ -204,4 +243,4 @@ func (b *BindingsClient) SendCMIX(payload, recipient []byte) (int, error) { func (b *BindingsClient) Search(data, separator string, searchTypes []byte) ContactList { return nil -} +}*/ diff --git a/bindings/interfaces.go b/bindings/interfaces.go index 166d4f562aa55462b0524dd102b824298da3880a..cc571caa80e8fc9f4a7b4d16a839f67cb4b1269e 100644 --- a/bindings/interfaces.go +++ b/bindings/interfaces.go @@ -6,6 +6,8 @@ package bindings +import "gitlab.com/xx_network/primitives/id" + // Client is defined inside the api package. At minimum, it implements all of // functionality defined here. A Client handles all network connectivity, key // generation, and storage for a given cryptographic identity on the cmix @@ -173,19 +175,6 @@ type AuthEventHandler interface { HandleRequest(contact Contact, payload []byte) } -// RoundList contains a list of contacts -type RoundList interface { - // GetLen returns the number of contacts in the list - GetLen() int - // GetRoundID returns the round ID at index i - GetRoundID(i int) int -} - -// RoundEventHandler handles round events happening on the cMix network. -type RoundEventHandler interface { - HandleEvent(id int, state byte) -} - // UserDiscoveryHandler handles search results against the user discovery agent. type UserDiscoveryHandler interface { HandleSearchResults(results ContactList) diff --git a/bindings/listener.go b/bindings/listener.go deleted file mode 100644 index 05376d83dba6788adb5946e6e9005a63aedc4192..0000000000000000000000000000000000000000 --- a/bindings/listener.go +++ /dev/null @@ -1,32 +0,0 @@ -package bindings - -import "gitlab.com/elixxir/client/switchboard" - -// Listener provides a callback to hear a message -// An object implementing this interface can be called back when the client -// gets a message of the type that the regi sterer specified at registration -// time. -type Listener interface { - // Hear is called to receive a message in the UI - Hear(message Message) - // Returns a name, used for debugging - Name() string -} - -// id object returned when a listener is created and is used to delete it from -// the system. Beyond calling unregister it has no uses. -type ListenerID struct { - id switchboard.ListenerID -} - -func (lid ListenerID) GetUserID() []byte { - return lid.id.GetUserID().Bytes() -} - -func (lid ListenerID) GetMessageType() int { - return int(lid.id.GetMessageType()) -} - -func (lid ListenerID) GetName() string { - return lid.id.GetName() -} diff --git a/bindings/params.go b/bindings/params.go new file mode 100644 index 0000000000000000000000000000000000000000..7da57c5eca6c9af4b7c10169b61534c58b80831b --- /dev/null +++ b/bindings/params.go @@ -0,0 +1,12 @@ +package bindings + +type Params interface { + GetString(key string) (string, error) + SetString(key, value string) + GetInt(key string) (int, error) + SetInt(key string, value int) + GetFloat(key string) (float64, error) + SetFloat(key, value string) + GetParams(key string) (Params, error) + SetParams(key string, p Params) +} diff --git a/bindings/roundList.go b/bindings/roundList.go new file mode 100644 index 0000000000000000000000000000000000000000..20c8c35b4c193abe61fac8a459566c4e1cc13e6d --- /dev/null +++ b/bindings/roundList.go @@ -0,0 +1,15 @@ +package bindings + +import "gitlab.com/xx_network/primitives/id" + +type roundList struct { + list []id.Round +} + +// RoundList contains a list of contacts +type RoundList interface { + // Len returns the number of contacts in the list + Len() int + // Get returns the round ID at index i + Get(i int) int +} diff --git a/bindings/send.go b/bindings/send.go new file mode 100644 index 0000000000000000000000000000000000000000..7e5a7b436f6a7e268f434fe052ac96d3c5fe98e7 --- /dev/null +++ b/bindings/send.go @@ -0,0 +1,50 @@ +package bindings + +import ( + "gitlab.com/elixxir/client/interfaces/params" + "gitlab.com/xx_network/primitives/id" +) + +// SendCMIX sends a "raw" CMIX message payload to the provided +// recipient. Note that both SendE2E and SendUnsafe call SendCMIX. +// Returns the round ID of the round the payload was sent or an error +// if it fails. + +// This will return an error if: +// - the recipient ID is invalid +// - the contents are too long for the message structure +// - the message cannot be sent + +// This will return the round the message was sent on if it is successfully sent +// This can be used to register a round event to learn about message delivery. +// on failure a round id of -1 is returned +func (c *Client) SendCmix(recipient, contents []byte) (int, error) { + u, err := id.Unmarshal(recipient) + if err != nil { + return -1, err + } + + msg, err := c.api.NewCMIXMessage(u, contents) + if err != nil { + return -1, err + } + + rid, err := c.api.SendCMIX(msg, params.GetDefaultCMIX()) + if err != nil { + return -1, err + } + return int(rid), err +} + +// SendUnsafe sends an unencrypted payload to the provided recipient +// with the provided msgType. Returns the list of rounds in which parts +// of the message were sent or an error if it fails. +// NOTE: Do not use this function unless you know what you are doing. +// This function always produces an error message in client logging. +// +// Message Types can be found in client/interfaces/message/type.go +// Make sure to not conflict with ANY default message types +func (c *Client) SendUnsafe(recipient, payload []byte, + messageType int) (RoundList, error) { + +}