diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 8b4539a64849297194e3ad4dcdd9cfda251614f6..2fb9133f20c416fc081d13a3c48e21eb809067c1 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -4,7 +4,7 @@ variables: REPO_DIR: gitlab.com/elixxir REPO_NAME: client DOCKER_IMAGE: elixxirlabs/cuda-go:latest - MIN_CODE_COVERAGE: "70" + MIN_CODE_COVERAGE: "35" before_script: ## @@ -84,26 +84,26 @@ tag: - git tag $(release/client.linux64 version | grep "Elixxir Client v"| cut -d ' ' -f3) -f - git push origin_tags -f --tags -bindings: - stage: build - except: - - tags - tags: - - ios - script: - - go get -u golang.org/x/mobile/cmd/gomobile - - go get -u golang.org/x/mobile/bind - - rm -rf $HOME/go/src/gitlab.com/elixxir/client/ - - mkdir -p $HOME/go/src/gitlab.com/elixxir/client/ - - cp -r * $HOME/go/src/gitlab.com/elixxir/client/ - - GO111MODULE=on gomobile bind -target android -androidapi 21 gitlab.com/elixxir/client/bindings - - GO111MODULE=on gomobile bind -target ios gitlab.com/elixxir/client/bindings - - zip -r iOS.zip Bindings.framework - artifacts: - paths: - - iOS.zip - - bindings.aar - - bindings-sources.jar +# bindings: +# stage: build +# except: +# - tags +# tags: +# - ios +# script: +# - go get -u golang.org/x/mobile/cmd/gomobile +# - go get -u golang.org/x/mobile/bind +# - rm -rf $HOME/go/src/gitlab.com/elixxir/client/ +# - mkdir -p $HOME/go/src/gitlab.com/elixxir/client/ +# - cp -r * $HOME/go/src/gitlab.com/elixxir/client/ +# - GO111MODULE=on gomobile bind -target android -androidapi 21 gitlab.com/elixxir/client/bindings +# - GO111MODULE=on gomobile bind -target ios gitlab.com/elixxir/client/bindings +# - zip -r iOS.zip Bindings.framework +# artifacts: +# paths: +# - iOS.zip +# - bindings.aar +# - bindings-sources.jar trigger_integration: stage: trigger_integration diff --git a/api/authenticatedChannel.go b/api/authenticatedChannel.go new file mode 100644 index 0000000000000000000000000000000000000000..7c53e2389b5fd1526c02a928e1c8acd9e28b4df5 --- /dev/null +++ b/api/authenticatedChannel.go @@ -0,0 +1,28 @@ +package api + +import jww "github.com/spf13/jwalterweatherman" + +// CreateAuthenticatedChannel creates a 1-way authenticated channel +// so this user can send messages to the desired recipient Contact. +// To receive confirmation from the remote user, clients must +// register a listener to do that. +func (c *Client) CreateAuthenticatedChannel(recipient Contact, + payload []byte) error { + jww.INFO.Printf("CreateAuthenticatedChannel(%v, %v)", + recipient, payload) + return nil +} + +// RegisterAuthConfirmationCb registers a callback for channel +// authentication confirmation events. +func (c *Client) RegisterAuthConfirmationCb(cb func(contact Contact, + payload []byte)) { + jww.INFO.Printf("RegisterAuthConfirmationCb(...)") +} + +// RegisterAuthRequestCb registers a callback for channel +// authentication request events. +func (c *Client) RegisterAuthRequestCb(cb func(contact Contact, + payload []byte)) { + jww.INFO.Printf("RegisterAuthRequestCb(...)") +} diff --git a/api/client.go b/api/client.go index 346025c9bc5502bee5b28807ce43be23796c0730..b4748878c2150d67a60e792d7b94acd2650cfc5a 100644 --- a/api/client.go +++ b/api/client.go @@ -18,14 +18,13 @@ import ( "gitlab.com/elixxir/client/storage" "gitlab.com/elixxir/client/switchboard" "gitlab.com/elixxir/comms/client" - pb "gitlab.com/elixxir/comms/mixmessages" "gitlab.com/elixxir/crypto/csprng" "gitlab.com/elixxir/crypto/cyclic" "gitlab.com/elixxir/crypto/fastRNG" "gitlab.com/elixxir/crypto/large" "gitlab.com/xx_network/crypto/signature/rsa" - "gitlab.com/xx_network/primitives/id" "gitlab.com/xx_network/primitives/ndf" + "time" ) type Client struct { @@ -45,6 +44,10 @@ type Client struct { network interfaces.NetworkManager //object used to register and communicate with permissioning permissioning *permissioning.Permissioning + + //contains stopables for all running threads + runner *stoppable.Multi + status *statusTracker } // NewClient creates client storage, generates keys, connects, and registers @@ -80,6 +83,13 @@ func NewClient(ndfJSON, storageDir string, password []byte, registrationCode str //store the registration code for later use storageSess.SetRegCode(registrationCode) + //move the registration state to keys generated + err = storageSess.ForwardRegistrationStatus(storage.KeyGenComplete) + if err != nil { + return nil, errors.WithMessage(err, "Failed to denote state "+ + "change in session") + } + //execute the rest of the loading as normal return loadClient(storageSess, rngStreamGen) } @@ -115,6 +125,13 @@ func NewPrecannedClient(precannedID uint, defJSON, storageDir string, password [ // Save NDF to be used in the future storageSess.SetBaseNDF(def) + //move the registration state to keys generated + err = storageSess.ForwardRegistrationStatus(storage.KeyGenComplete) + if err != nil { + return nil, errors.WithMessage(err, "Failed to denote state "+ + "change in session") + } + //execute the rest of the loading as normal return loadClient(storageSess, rngStreamGen) } @@ -146,6 +163,8 @@ func loadClient(session *storage.Session, rngStreamGen *fastRNG.StreamGenerator) rng: rngStreamGen, comms: nil, network: nil, + runner: stoppable.NewMulti("client"), + status: newStatusTracker(), } //get the user from session @@ -166,6 +185,10 @@ func loadClient(session *storage.Session, rngStreamGen *fastRNG.StreamGenerator) //initialize permissioning c.permissioning, err = permissioning.Init(c.comms, def) + if err != nil { + return nil, errors.WithMessage(err, "failed to init "+ + "permissioning handler") + } // check the client version is up to date to the network err = c.checkVersion() @@ -175,10 +198,13 @@ func loadClient(session *storage.Session, rngStreamGen *fastRNG.StreamGenerator) //register with permissioning if necessary if c.storage.GetRegistrationStatus() == storage.KeyGenComplete { + jww.INFO.Printf("Client has not registered yet, attempting registration") err = c.registerWithPermissioning() if err != nil { + jww.ERROR.Printf("Client has failed registration: %s", err) return nil, errors.WithMessage(err, "failed to load client") } + jww.INFO.Printf("Client sucsecfully registered with the network") } // Initialize network and link it to context @@ -202,236 +228,88 @@ func loadClient(session *storage.Session, rngStreamGen *fastRNG.StreamGenerator) // tracks the network events and hands them off to workers for handling // - Historical Round Retrieval (/network/rounds/historical.go) // Retrieves data about rounds which are too old to be stored by the client -// - Message Retrieval Worker Group (/network/rounds/retreive.go) +// - Message Retrieval Worker Group (/network/rounds/retrieve.go) // Requests all messages in a given round from the gateway of the last node -// - Message Handling Worker Group (/network/message/reception.go) +// - Message Handling Worker Group (/network/message/handle.go) // Decrypts and partitions messages when signals via the Switchboard // - Health Tracker (/network/health) -func (c *Client) StartNetworkFollower() (stoppable.Stoppable, error) { +// Via the network instance tracks the state of the network +// - Garbled Messages (/network/message/garbled.go) +// Can be signaled to check all recent messages which could be be decoded +// Uses a message store on disk for persistence +// - Critical Messages (/network/message/critical.go) +// Ensures all protocol layer mandatory messages are sent +// Uses a message store on disk for persistence +// - KeyExchange Trigger (/keyExchange/trigger.go) +// Responds to sent rekeys and executes them +// - KeyExchange Confirm (/keyExchange/confirm.go) +// Responds to confirmations of successful rekey operations +func (c *Client) StartNetworkFollower() error { jww.INFO.Printf("StartNetworkFollower()") - multi := stoppable.NewMulti("client") + + err := c.status.toStarting() + if err != nil { + return errors.WithMessage(err, "Failed to Start the Network Follower") + } stopFollow, err := c.network.Follow() if err != nil { - return nil, errors.WithMessage(err, "Failed to start following "+ + return errors.WithMessage(err, "Failed to start following "+ "the network") } - multi.Add(stopFollow) + c.runner.Add(stopFollow) // Key exchange - multi.Add(keyExchange.Start(c.switchboard, c.storage, c.network)) - return multi, nil -} - - + c.runner.Add(keyExchange.Start(c.switchboard, c.storage, c.network)) -// SendE2E sends an end-to-end 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. -func (c *Client) SendE2E(payload []byte, recipient id.ID, msgType int) ( - []int, error) { - jww.INFO.Printf("SendE2E(%s, %s, %d)", payload, recipient, - msgType) - return nil, nil -} - -// 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. -func (c *Client) SendUnsafe(payload []byte, recipient id.ID, msgType int) ([]int, - error) { - jww.INFO.Printf("SendUnsafe(%s, %s, %d)", payload, recipient, - msgType) - return nil, nil -} - -// 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. -func (c *Client) SendCMIX(payload []byte, recipient id.ID) (int, error) { - jww.INFO.Printf("SendCMIX(%s, %s)", payload, recipient) - return 0, nil -} - -// RegisterListener registers a listener callback function that is called -// every time a new message matches the specified parameters. -func (c *Client) RegisterListenerCb(uid id.ID, msgType int, username string, - listenerCb func(msg Message)) { - jww.INFO.Printf("RegisterListener(%s, %d, %s, func())", uid, msgType, - username) -} - -// RegisterForNotifications allows a client to register for push -// notifications. -// Note that clients are not required to register for push notifications -// especially as these rely on third parties (i.e., Firebase *cough* -// *cough* google's palantir *cough*) that may represent a security -// risk to the user. -func (c *Client) RegisterForNotifications(token []byte) error { - jww.INFO.Printf("RegisterForNotifications(%s)", token) - // // Pull the host from the manage - // notificationBotHost, ok := cl.receptionManager.Comms.GetHost(&id.NotificationBot) - // if !ok { - // return errors.New("Failed to retrieve host for notification bot") - // } - - // // Send the register message - // _, err := cl.receptionManager.Comms.RegisterForNotifications(notificationBotHost, - // &mixmessages.NotificationToken{ - // Token: notificationToken, - // }) - // if err != nil { - // err := errors.Errorf( - // "RegisterForNotifications: Unable to register for notifications! %s", err) - // return err - // } - - return nil -} - -// UnregisterForNotifications turns of notifications for this client -func (c *Client) UnregisterForNotifications() error { - jww.INFO.Printf("UnregisterForNotifications()") - // // Pull the host from the manage - // notificationBotHost, ok := cl.receptionManager.Comms.GetHost(&id.NotificationBot) - // if !ok { - // return errors.New("Failed to retrieve host for notification bot") - // } - - // // Send the unregister message - // _, err := cl.receptionManager.Comms.UnregisterForNotifications(notificationBotHost) - // if err != nil { - // err := errors.Errorf( - // "RegisterForNotifications: Unable to register for notifications! %s", err) - // return err - // } - - return nil -} - -// Returns true if the cryptographic identity has been registered with -// the CMIX user discovery agent. -// Note that clients do not need to perform this step if they use -// out of band methods to exchange cryptographic identities -// (e.g., QR codes), but failing to be registered precludes usage -// of the user discovery mechanism (this may be preferred by user). -func (c *Client) IsRegistered() bool { - jww.INFO.Printf("IsRegistered()") - return false -} - -// RegisterIdentity registers an arbitrary username with the user -// discovery protocol. Returns an error when it cannot connect or -// the username is already registered. -func (c *Client) RegisterIdentity(username string) error { - jww.INFO.Printf("RegisterIdentity(%s)", username) - return nil -} - -// RegisterEmail makes the users email searchable after confirmation. -// It returns a registration confirmation token to be used with -// ConfirmRegistration or an error on failure. -func (c *Client) RegisterEmail(email string) ([]byte, error) { - jww.INFO.Printf("RegisterEmail(%s)", email) - return nil, nil -} - -// RegisterPhone makes the users phone searchable after confirmation. -// It returns a registration confirmation token to be used with -// ConfirmRegistration or an error on failure. -func (c *Client) RegisterPhone(phone string) ([]byte, error) { - jww.INFO.Printf("RegisterPhone(%s)", phone) - return nil, nil -} + err = c.status.toRunning() + if err != nil { + return errors.WithMessage(err, "Failed to Start the Network Follower") + } -// ConfirmRegistration sends the user discovery agent a confirmation -// token (from register Email/Phone) and code (string sent via Email -// or SMS to confirm ownership) to confirm ownership. -func (c *Client) ConfirmRegistration(token, code []byte) error { - jww.INFO.Printf("ConfirmRegistration(%s, %s)", token, code) return nil } -// GetUser returns the current user Identity for this client. This -// can be serialized into a byte stream for out-of-band sharing. -func (c *Client) GetUser() (Contact, error) { - jww.INFO.Printf("GetUser()") - return Contact{}, nil -} - -// MakeContact creates a contact from a byte stream (i.e., unmarshal's a -// Contact object), allowing out-of-band import of identities. -func (c *Client) MakeContact(contactBytes []byte) (Contact, error) { - jww.INFO.Printf("MakeContact(%s)", contactBytes) - return Contact{}, nil -} - -// GetContact returns a Contact object for the given user id, or -// an error -func (c *Client) GetContact(uid []byte) (Contact, error) { - jww.INFO.Printf("GetContact(%s)", uid) - return Contact{}, nil -} - -// Search accepts a "separator" separated list of search elements with -// an associated list of searchTypes. It returns a ContactList which -// allows you to iterate over the found contact objects. -func (c *Client) Search(data, separator string, searchTypes []byte) []Contact { - jww.INFO.Printf("Search(%s, %s, %s)", data, separator, searchTypes) +// StopNetworkFollower stops the network follower if it is running. +// It returns errors if the Follower is in the wrong status to stop or if it +// fails to stop it. +// if the network follower is running and this fails, the client object will +// most likely be in an unrecoverable state and need to be trashed. +func (c *Client) StopNetworkFollower(timeout time.Duration) error { + err := c.status.toStopping() + if err != nil { + return errors.WithMessage(err, "Failed to Stop the Network Follower") + } + err = c.runner.Close(timeout) + if err != nil { + return errors.WithMessage(err, "Failed to Stop the Network Follower") + } + c.runner = stoppable.NewMulti("client") + err = c.status.toStopped() + if err != nil { + return errors.WithMessage(err, "Failed to Stop the Network Follower") + } return nil } -// SearchWithHandler is a non-blocking search that also registers -// a callback interface for user disovery events. -func (c *Client) SearchWithCallback(data, separator string, searchTypes []byte, - cb func(results []Contact)) { - resultCh := make(chan []Contact, 1) - go func(out chan []Contact, data, separator string, srchTypes []byte) { - out <- c.Search(data, separator, srchTypes) - close(out) - }(resultCh, data, separator, searchTypes) - - go func(in chan []Contact, cb func(results []Contact)) { - select { - case contacts := <-in: - cb(contacts) - //TODO: Timer - } - }(resultCh, cb) -} - -// CreateAuthenticatedChannel creates a 1-way authenticated channel -// so this user can send messages to the desired recipient Contact. -// To receive confirmation from the remote user, clients must -// register a listener to do that. -func (c *Client) CreateAuthenticatedChannel(recipient Contact, - payload []byte) error { - jww.INFO.Printf("CreateAuthenticatedChannel(%v, %v)", - recipient, payload) - return nil +//gets the state of the network follower +func (c *Client) NetworkFollowerStatus() Status { + return c.status.get() } -// RegisterAuthConfirmationCb registers a callback for channel -// authentication confirmation events. -func (c *Client) RegisterAuthConfirmationCb(cb func(contact Contact, - payload []byte)) { - jww.INFO.Printf("RegisterAuthConfirmationCb(...)") +// Returns the switchboard for Registration +func (c *Client) GetSwitchboard() interfaces.Switchboard { + return c.switchboard } -// RegisterAuthRequestCb registers a callback for channel -// authentication request events. -func (c *Client) RegisterAuthRequestCb(cb func(contact Contact, - payload []byte)) { - jww.INFO.Printf("RegisterAuthRequestCb(...)") +// Returns the health tracker for registration and polling +func (c *Client) GetHealth() interfaces.HealthTracker { + return c.network.GetHealthTracker() } // RegisterRoundEventsCb registers a callback for round // events. -func (c *Client) RegisterRoundEventsCb( - cb func(re *pb.RoundInfo, timedOut bool)) { - jww.INFO.Printf("RegisterRoundEventsCb(...)") +func (c *Client) GetRoundEvents() interfaces.RoundEvents { + return c.network.GetInstance().GetRoundEvents() } // ----- Utility Functions ----- diff --git a/api/contact.go b/api/contact.go index 07f3e6ec0463e08d738cfceb8ce6881b66264d2f..151245d5f2c350505872957d756e9148586f9b19 100644 --- a/api/contact.go +++ b/api/contact.go @@ -6,11 +6,35 @@ package api +import jww "github.com/spf13/jwalterweatherman" + import ( "gitlab.com/xx_network/crypto/signature/rsa" "gitlab.com/xx_network/primitives/id" ) +// GetUser returns the current user Identity for this client. This +// can be serialized into a byte stream for out-of-band sharing. +func (c *Client) GetUser() (Contact, error) { + jww.INFO.Printf("GetUser()") + return Contact{}, nil +} + +// MakeContact creates a contact from a byte stream (i.e., unmarshal's a +// Contact object), allowing out-of-band import of identities. +func (c *Client) MakeContact(contactBytes []byte) (Contact, error) { + jww.INFO.Printf("MakeContact(%s)", contactBytes) + return Contact{}, nil +} + +// GetContact returns a Contact object for the given user id, or +// an error +func (c *Client) GetContact(uid []byte) (Contact, error) { + jww.INFO.Printf("GetContact(%s)", uid) + return Contact{}, nil +} + + // Contact implements the Contact interface defined in bindings/interfaces.go, type Contact struct { ID id.ID diff --git a/api/interfaces.go b/api/interfaces.go deleted file mode 100644 index 5d8c04419cde6972ac3e253bcce8924a7f6d6e68..0000000000000000000000000000000000000000 --- a/api/interfaces.go +++ /dev/null @@ -1,45 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright © 2020 Privategrity Corporation / -// / -// All rights reserved. / -//////////////////////////////////////////////////////////////////////////////// - -package api - -import ( - "gitlab.com/xx_network/primitives/id" -) - -// Message is a message received from the cMix network in the clear -// or that has been decrypted using established E2E keys. -type Message interface { - // Returns the message's sender ID, if available - GetSender() id.ID - GetSenderBytes() []byte - - // Returns the message payload/contents - // Parse this with protobuf/whatever according to the message type - GetPayload() []byte - - // Returns the message's recipient ID - // This is usually your userID but could be an ephemeral/group ID - GetRecipient() id.ID - GetRecipientBytes() []byte - - // Returns the message's type - GetMessageType() int32 - - // Returns the message's timestamp in seconds since unix epoc - GetTimestamp() int64 - // Returns the message's timestamp in ns since unix epoc - GetTimestampNano() int64 -} - -// RoundEvent contains event information for a given round. -// TODO: This is a half-baked interface and will be filled out later. -type RoundEvent interface { - // GetID returns the round ID for this round. - GetID() int - // GetStatus returns the status of this round. - GetStatus() int -} diff --git a/api/notifications.go b/api/notifications.go new file mode 100644 index 0000000000000000000000000000000000000000..119b675f86ffc0e6f76e39d2dc06d5d77f4a9612 --- /dev/null +++ b/api/notifications.go @@ -0,0 +1,51 @@ +package api + +import jww "github.com/spf13/jwalterweatherman" + +// RegisterForNotifications allows a client to register for push +// notifications. +// Note that clients are not required to register for push notifications +// especially as these rely on third parties (i.e., Firebase *cough* +// *cough* google's palantir *cough*) that may represent a security +// risk to the user. +func (c *Client) RegisterForNotifications(token []byte) error { + jww.INFO.Printf("RegisterForNotifications(%s)", token) + // // Pull the host from the manage + // notificationBotHost, ok := cl.receptionManager.Comms.GetHost(&id.NotificationBot) + // if !ok { + // return errors.New("Failed to retrieve host for notification bot") + // } + + // // Send the register message + // _, err := cl.receptionManager.Comms.RegisterForNotifications(notificationBotHost, + // &mixmessages.NotificationToken{ + // Token: notificationToken, + // }) + // if err != nil { + // err := errors.Errorf( + // "RegisterForNotifications: Unable to register for notifications! %s", err) + // return err + // } + + return nil +} + +// UnregisterForNotifications turns of notifications for this client +func (c *Client) UnregisterForNotifications() error { + jww.INFO.Printf("UnregisterForNotifications()") + // // Pull the host from the manage + // notificationBotHost, ok := cl.receptionManager.Comms.GetHost(&id.NotificationBot) + // if !ok { + // return errors.New("Failed to retrieve host for notification bot") + // } + + // // Send the unregister message + // _, err := cl.receptionManager.Comms.UnregisterForNotifications(notificationBotHost) + // if err != nil { + // err := errors.Errorf( + // "RegisterForNotifications: Unable to register for notifications! %s", err) + // return err + // } + + return nil +} diff --git a/api/send.go b/api/send.go new file mode 100644 index 0000000000000000000000000000000000000000..ee11f6da2b32656ee5ff96bc0ca9095d38459a5f --- /dev/null +++ b/api/send.go @@ -0,0 +1,42 @@ +package api + +import ( + "gitlab.com/elixxir/client/interfaces/message" + "gitlab.com/elixxir/client/interfaces/params" + "gitlab.com/elixxir/primitives/format" + "gitlab.com/xx_network/primitives/id" + jww "github.com/spf13/jwalterweatherman" +) + +//This holds all functions to send messages over the network + +// SendE2E sends an end-to-end 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. +func (c *Client) SendE2E(m message.Send, param params.E2E) ([]id.Round, error) { + jww.INFO.Printf("SendE2E(%s, %d. %v)", m.Recipient, + m.MessageType, m.Payload) + return c.network.SendE2E(m, param) +} + +// 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. +func (c *Client) SendUnsafe(m message.Send, param params.Unsafe) ([]id.Round, + error) { + jww.INFO.Printf("SendUnsafe(%s, %d. %v)", m.Recipient, + m.MessageType, m.Payload) + return c.network.SendUnsafe(m, param) +} + +// 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. +func (c *Client) SendCMIX(msg format.Message, param params.CMIX) (id.Round, + error) { + jww.INFO.Printf("SendCMIX(%v)", msg) + return c.network.SendCMIX(msg, param) +} diff --git a/api/status.go b/api/status.go new file mode 100644 index 0000000000000000000000000000000000000000..cebfac0f4a9d9958955198a95dad5e81eb7923b9 --- /dev/null +++ b/api/status.go @@ -0,0 +1,80 @@ +package api + +import ( + "fmt" + "github.com/pkg/errors" + "sync/atomic" +) + +type Status int + +const ( + Stopped Status = 0 + Starting Status = 1000 + Running Status = 2000 + Stopping Status = 3000 +) + +func (s Status) String() string { + switch s { + case Stopped: + return "Stopped" + case Starting: + return "Starting" + case Running: + return "Running" + case Stopping: + return "Stopping" + default: + return fmt.Sprintf("Unknown status %d", s) + } +} + +type statusTracker struct { + s *uint32 +} + +func newStatusTracker() *statusTracker { + s := uint32(Stopped) + return &statusTracker{s: &s} +} + +func (s *statusTracker) toStarting() error { + if !atomic.CompareAndSwapUint32(s.s, uint32(Stopped), uint32(Starting)) { + return errors.Errorf("Failed to move to '%s' status, at '%s', "+ + "must be at '%s' for transition", Starting, + Status(atomic.LoadUint32(s.s)), Stopped) + } + return nil +} + +func (s *statusTracker) toRunning() error { + if !atomic.CompareAndSwapUint32(s.s, uint32(Starting), uint32(Running)) { + return errors.Errorf("Failed to move to '%s' status, at '%s', "+ + "must be at '%s' for transition", + Running, Status(atomic.LoadUint32(s.s)), Starting) + } + return nil +} + +func (s *statusTracker) toStopping() error { + if !atomic.CompareAndSwapUint32(s.s, uint32(Running), uint32(Stopping)) { + return errors.Errorf("Failed to move to '%s' status, at '%s',"+ + " must be at '%s' for transition", Stopping, + Status(atomic.LoadUint32(s.s)), Running) + } + return nil +} + +func (s *statusTracker) toStopped() error { + if !atomic.CompareAndSwapUint32(s.s, uint32(Stopping), uint32(Stopped)) { + return errors.Errorf("Failed to move to '%s' status, at '%s',"+ + " must be at '%s' for transition", Stopped, + Status(atomic.LoadUint32(s.s)), Stopping) + } + return nil +} + +func (s *statusTracker) get() Status { + return Status(atomic.LoadUint32(s.s)) +} diff --git a/api/userDiscovery.go b/api/userDiscovery.go new file mode 100644 index 0000000000000000000000000000000000000000..3da6d21fd9aa3f7d59ff2154c9a901cdff2e86a2 --- /dev/null +++ b/api/userDiscovery.go @@ -0,0 +1,73 @@ +package api + +import jww "github.com/spf13/jwalterweatherman" + +// Returns true if the cryptographic identity has been registered with +// the CMIX user discovery agent. +// Note that clients do not need to perform this step if they use +// out of band methods to exchange cryptographic identities +// (e.g., QR codes), but failing to be registered precludes usage +// of the user discovery mechanism (this may be preferred by user). +func (c *Client) IsRegistered() bool { + jww.INFO.Printf("IsRegistered()") + return false +} + +// RegisterIdentity registers an arbitrary username with the user +// discovery protocol. Returns an error when it cannot connect or +// the username is already registered. +func (c *Client) RegisterIdentity(username string) error { + jww.INFO.Printf("RegisterIdentity(%s)", username) + return nil +} + +// RegisterEmail makes the users email searchable after confirmation. +// It returns a registration confirmation token to be used with +// ConfirmRegistration or an error on failure. +func (c *Client) RegisterEmail(email string) ([]byte, error) { + jww.INFO.Printf("RegisterEmail(%s)", email) + return nil, nil +} + +// RegisterPhone makes the users phone searchable after confirmation. +// It returns a registration confirmation token to be used with +// ConfirmRegistration or an error on failure. +func (c *Client) RegisterPhone(phone string) ([]byte, error) { + jww.INFO.Printf("RegisterPhone(%s)", phone) + return nil, nil +} + +// ConfirmRegistration sends the user discovery agent a confirmation +// token (from register Email/Phone) and code (string sent via Email +// or SMS to confirm ownership) to confirm ownership. +func (c *Client) ConfirmRegistration(token, code []byte) error { + jww.INFO.Printf("ConfirmRegistration(%s, %s)", token, code) + return nil +} + +// Search accepts a "separator" separated list of search elements with +// an associated list of searchTypes. It returns a ContactList which +// allows you to iterate over the found contact objects. +func (c *Client) Search(data, separator string, searchTypes []byte) []Contact { + jww.INFO.Printf("Search(%s, %s, %s)", data, separator, searchTypes) + return nil +} + +// SearchWithHandler is a non-blocking search that also registers +// a callback interface for user disovery events. +func (c *Client) SearchWithCallback(data, separator string, searchTypes []byte, + cb func(results []Contact)) { + resultCh := make(chan []Contact, 1) + go func(out chan []Contact, data, separator string, srchTypes []byte) { + out <- c.Search(data, separator, srchTypes) + close(out) + }(resultCh, data, separator, searchTypes) + + go func(in chan []Contact, cb func(results []Contact)) { + select { + case contacts := <-in: + cb(contacts) + //TODO: Timer + } + }(resultCh, cb) +} diff --git a/api/version.go b/api/version.go index 639329b21a87149ebf22ab49b0a5853e928db782..d8a8e2a056308b8a6f02f3b20f37bf68fa37d339 100644 --- a/api/version.go +++ b/api/version.go @@ -16,7 +16,7 @@ func (c *Client) Version() version.Version { func (c *Client) checkVersion() error { clientVersion := c.Version() - jww.INFO.Printf("Client Version: %s", clientVersion) + jww.INFO.Printf("Client Version: %s", clientVersion.String()) has, netVersion, err := c.permissioning.GetNetworkVersion() if err != nil { @@ -29,7 +29,7 @@ func (c *Client) checkVersion() error { return errors.Errorf("Client and Minimum Network Version are "+ "incompatible\n"+ "\tMinimum Network: %s\n"+ - "\tClient: %s", netVersion, clientVersion) + "\tClient: %s", netVersion.String(), clientVersion.String()) } } else { jww.WARN.Printf("Network requires no minnimim version") diff --git a/bindings/api.go b/bindings/api.go index b8351406a78d4b37e6b10553e7bf30384fbfe553..3195423f109913a399747e46fc2ba985dc4fc461 100644 --- a/bindings/api.go +++ b/bindings/api.go @@ -35,7 +35,7 @@ type BindingsClient struct { // Users of this function should delete the storage directory on error. func NewClient(network, storageDir string, password []byte) (Client, error) { // TODO: This should wrap the bindings ClientImpl, when available. - client, err := api.NewClient(network, storageDir, password) + client, err := api.NewClient(network, storageDir, password, "") if err != nil { return nil, err } diff --git a/bindings/interfaces.go b/bindings/interfaces.go index e7d3f4e272fe86cfb59a4fcce1f5d79300875889..a4fd23c45cff5af5f4d3597afd8f233828e2faeb 100644 --- a/bindings/interfaces.go +++ b/bindings/interfaces.go @@ -8,7 +8,7 @@ package bindings import ( "gitlab.com/elixxir/client/api" - "gitlab.com/elixxir/client/stoppable" + "gitlab.com/xx_network/primitives/id" ) // Client is defined inside the api package. At minimum, it implements all of @@ -121,7 +121,7 @@ type Client interface { // and returns an object for checking state and stopping those threads. // Call this when returning from sleep and close when going back to // sleep. - StartNetworkRunner() stoppable.Stoppable + StartNetworkFollower() error // RegisterRoundEventsHandler registers a callback interface for round // events. @@ -140,11 +140,11 @@ type ContactList interface { // 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 registerer specified at registration +// 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(msg api.Message) + Hear(msg Message) } // AuthEventHandler handles authentication requests initiated by @@ -189,3 +189,28 @@ type RoundEventHandler interface { type UserDiscoveryHandler interface { HandleSearchResults(results ContactList) } + +// Message is a message received from the cMix network in the clear +// or that has been decrypted using established E2E keys. +type Message interface { + // Returns the message's sender ID, if available + GetSender() id.ID + GetSenderBytes() []byte + + // Returns the message payload/contents + // Parse this with protobuf/whatever according to the message type + GetPayload() []byte + + // Returns the message's recipient ID + // This is usually your userID but could be an ephemeral/group ID + GetRecipient() id.ID + GetRecipientBytes() []byte + + // Returns the message's type + GetMessageType() int32 + + // Returns the message's timestamp in seconds since unix epoc + GetTimestamp() int64 + // Returns the message's timestamp in ns since unix epoc + GetTimestampNano() int64 +} diff --git a/cmd/root.go b/cmd/root.go index fb328b155b826d8433cc0b990927041aa0ab6a7d..480077b6289e8b88c8bd6d2f48d58a33f1d1a049 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -13,6 +13,7 @@ import ( "github.com/spf13/cobra" jww "github.com/spf13/jwalterweatherman" "github.com/spf13/viper" + "gitlab.com/elixxir/client/api" "gitlab.com/xx_network/primitives/id" "io/ioutil" "os" @@ -172,12 +173,45 @@ var rootCmd = &cobra.Command{ Short: "Runs a client for cMix anonymous communication platform", Args: cobra.NoArgs, Run: func(cmd *cobra.Command, args []string) { - if !verbose && viper.Get("verbose") != nil { - verbose = viper.GetBool("verbose") + initLog(viper.GetBool("verbose"), viper.GetString("log")) + jww.INFO.Printf(Version()) + + pass := viper.GetString("password") + storeDir := viper.GetString("session") + regCode := viper.GetString("regcode") + + var client *api.Client + if _, err := os.Stat(storeDir); os.IsNotExist(err) { + // Load NDF + ndfPath := viper.GetString("ndf") + ndfJSON, err := ioutil.ReadFile(ndfPath) + if err != nil { + jww.FATAL.Panicf(err.Error()) + } + + client, err = api.NewClient(string(ndfJSON), storeDir, + []byte(pass), regCode) + if err != nil { + jww.FATAL.Panicf("%+v", err) + } + } else { + client, err = api.LoadClient(storeDir, []byte(pass)) + if err != nil { + jww.FATAL.Panicf("%+v", err) + } } - if logPath == "" && viper.Get("logPath") != nil { - logPath = viper.GetString("logPath") + + user, err := client.GetUser() + if err != nil { + jww.FATAL.Panicf("%+v", err) } + jww.INFO.Printf("%v", user.ID) + + }, +} + +func initLog(verbose bool, logPath string) { + if logPath != "-" && logPath != "" { // Disable stdout output jww.SetStdoutOutput(ioutil.Discard) // Use log file @@ -187,10 +221,16 @@ var rootCmd = &cobra.Command{ panic(err.Error()) } jww.SetLogOutput(logOutput) - if verbose { - jww.SetLogThreshold(jww.LevelTrace) - } - }, + } + + if verbose { + jww.SetStdoutThreshold(jww.LevelTrace) + jww.SetLogThreshold(jww.LevelTrace) + } else { + jww.SetStdoutThreshold(jww.LevelInfo) + jww.SetLogThreshold(jww.LevelInfo) + } + } func isValidUser(usr []byte) (bool, *id.ID) { @@ -222,60 +262,30 @@ func init() { // Here you will define your flags and configuration settings. // Cobra supports persistent flags, which, if defined here, // will be global for your application. - rootCmd.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false, + rootCmd.Flags().BoolP("verbose", "v", false, "Verbose mode for debugging") + viper.BindPFlag("verbose", rootCmd.Flags().Lookup("verbose")) + + rootCmd.Flags().StringP("session", "s", + "", "Sets the initial username and the directory for "+ + "client storage") + viper.BindPFlag("session", rootCmd.Flags().Lookup("session")) + + rootCmd.Flags().StringP("password", "p", "", + "Password to the session file") + viper.BindPFlag("password", rootCmd.Flags().Lookup("password")) - rootCmd.PersistentFlags().BoolVarP(&noBlockingTransmission, "noBlockingTransmission", - "", false, "Sets if transmitting messages blocks or not. "+ - "Defaults to true if unset.") - rootCmd.PersistentFlags().Uint32VarP(&rateLimiting, "rateLimiting", "", - 1000, "Sets the amount of time, in ms, "+ - "that the client waits between sending messages. "+ - "set to zero to disable. "+ - "Automatically disabled if 'blockingTransmission' is false") - - rootCmd.PersistentFlags().Uint64VarP(&userId, "userid", "i", 0, - "ID to sign in as. Does not register, must be an available precanned user") - - rootCmd.PersistentFlags().StringVarP(®istrationCode, - "regcode", "r", - "", - "Registration Code with the registration server") - - rootCmd.PersistentFlags().StringVarP(&username, - "username", "E", - "", - "Username to register for User Discovery") - - rootCmd.PersistentFlags().StringVarP(&sessionFile, "sessionfile", "f", - "", "Passes a file path for loading a session. "+ - "If the file doesn't exist the code will register the user and"+ - " store it there. If not passed the session will be stored"+ - " to ram and lost when the cli finishes") - - rootCmd.PersistentFlags().StringVarP(&ndfPubKey, - "ndfPubKeyCertPath", - "p", - "", - "Path to the certificated containing the public key for the "+ - " network definition JSON file") - - rootCmd.PersistentFlags().StringVarP(&ndfPath, - "ndf", - "n", - "ndf.json", + rootCmd.Flags().StringP("ndf", "n", "ndf.json", "Path to the network definition JSON file") + viper.BindPFlag("ndf", rootCmd.Flags().Lookup("ndf")) - rootCmd.PersistentFlags().BoolVar(&skipNDFVerification, - "skipNDFVerification", - false, - "Specifies if the NDF should be loaded without the signature") + rootCmd.Flags().StringP("log", "l", "-", + "Path to the log output path (- is stdout)") + viper.BindPFlag("log", rootCmd.Flags().Lookup("log")) - rootCmd.PersistentFlags().StringVarP(&sessFilePassword, - "password", - "P", - "", - "Password to the session file") + rootCmd.Flags().StringP("regcode", "r", "", + "Registration code (optional)") + viper.BindPFlag("regcode", rootCmd.Flags().Lookup("regcode")) // Cobra also supports local flags, which will only run // when this action is called directly. @@ -307,11 +317,8 @@ func init() { "w", 1, "Denotes the number of messages the "+ "client should receive before closing") - rootCmd.Flags().StringVarP(&searchForUser, "SearchForUser", "s", "", - "Sets the email to search for to find a user with user discovery") - - rootCmd.Flags().StringVarP(&logPath, "log", "l", "", - "Print logs to specified log file, not stdout") + // rootCmd.Flags().StringVarP(&searchForUser, "SearchForUser", "s", "", + // "Sets the email to search for to find a user with user discovery") rootCmd.Flags().UintVarP(&messageTimeout, "messageTimeout", "t", 45, "The number of seconds to wait for "+ diff --git a/cmd/version.go b/cmd/version.go index c231ec50626563ba99e39fbc3b63ab50975bd7c9..309fbf6f72d85325ad547b2c1e70b3299d822e33 100644 --- a/cmd/version.go +++ b/cmd/version.go @@ -18,9 +18,11 @@ import ( // Change this value to set the version for this build const currentVersion = "1.4.0" -func printVersion() { - fmt.Printf("Elixxir Client v%s -- %s\n\n", api.SEMVER, api.GITVERSION) - fmt.Printf("Dependencies:\n\n%s\n", api.DEPENDENCIES) +func Version() string { + out := fmt.Sprintf("Elixxir Client v%s -- %s\n\n", api.SEMVER, + api.GITVERSION) + out += fmt.Sprintf("Dependencies:\n\n%s\n", api.DEPENDENCIES) + return out } func init() { @@ -33,7 +35,7 @@ var versionCmd = &cobra.Command{ Short: "Print the version and dependency information for the Elixxir binary", Long: `Print the version and dependency information for the Elixxir binary`, Run: func(cmd *cobra.Command, args []string) { - printVersion() + fmt.Printf(Version()) }, } diff --git a/go.mod b/go.mod index e5c7c5d3eab3f89ad9682624dce8c0f41f9975e9..364100667bc4b0c9a455eac2f765e256f551042a 100644 --- a/go.mod +++ b/go.mod @@ -6,26 +6,27 @@ require ( github.com/golang-collections/collections v0.0.0-20130729185459-604e922904d3 github.com/golang/protobuf v1.4.2 github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00 // indirect - github.com/pelletier/go-toml v1.6.0 // indirect + github.com/magiconair/properties v1.8.4 // indirect + github.com/mitchellh/mapstructure v1.3.3 // indirect + github.com/pelletier/go-toml v1.8.1 // indirect github.com/pkg/errors v0.9.1 github.com/smartystreets/assertions v1.0.1 // indirect - github.com/spf13/afero v1.2.2 // indirect + github.com/spf13/afero v1.4.0 // indirect github.com/spf13/cast v1.3.1 // indirect github.com/spf13/cobra v1.0.0 github.com/spf13/jwalterweatherman v1.1.0 github.com/spf13/pflag v1.0.5 // indirect - github.com/spf13/viper v1.6.2 - gitlab.com/elixxir/comms v0.0.0-20200923155248-2dd684128da1 + github.com/spf13/viper v1.7.1 + gitlab.com/elixxir/comms v0.0.0-20200924210331-d7903c023fa6 gitlab.com/elixxir/crypto v0.0.0-20200921195205-bca0178268ec - gitlab.com/elixxir/ekv v0.1.1 - gitlab.com/elixxir/primitives v0.0.0-20200916172343-37503735c7a1 - gitlab.com/xx_network/comms v0.0.0-20200923154925-b8a96380f180 + gitlab.com/elixxir/ekv v0.1.3 + gitlab.com/elixxir/primitives v0.0.0-20200915190719-f4586ec93f50 + gitlab.com/xx_network/comms v0.0.0-20200924172734-1124191b69ee gitlab.com/xx_network/crypto v0.0.0-20200812183430-c77a5281c686 gitlab.com/xx_network/primitives v0.0.0-20200915204206-eb0287ed0031 - golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a // indirect - golang.org/x/sys v0.0.0-20200828194041-157a740278f4 // indirect + golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d // indirect google.golang.org/protobuf v1.25.0 - gopkg.in/ini.v1 v1.52.0 // indirect + gopkg.in/ini.v1 v1.61.0 // indirect ) replace google.golang.org/grpc => github.com/grpc/grpc-go v1.27.1 diff --git a/go.sum b/go.sum index fbc8028b449a6520568fd35118ff1a97514ddc1d..4fa2f61b06bad217a57129bbe30eddb99db834c3 100644 --- a/go.sum +++ b/go.sum @@ -1,18 +1,39 @@ +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -22,11 +43,13 @@ github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZm github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= @@ -39,6 +62,8 @@ github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekf github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -52,6 +77,7 @@ github.com/golang/protobuf v1.4.1 h1:ZFgWrT+bLgsYPirOnRfKLYJLvssAegOj/hgyMFdJZe0 github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -60,26 +86,55 @@ github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00 h1:l5lAOZEym3oK3SQ2HBHWsJUfbNBiTXJDeW2QDxw9AQ0= github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc/grpc-go v1.27.1 h1:EluyjU5nlbuNJSEktNl600PIpzbO2OcvZWfWV1jFvKM= github.com/grpc/grpc-go v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= +github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= +github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= +github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= +github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= +github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= +github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= @@ -89,23 +144,44 @@ github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/magiconair/properties v1.8.4 h1:8KGKTcQQGm0Kv7vEbKFErAoAOFyyacLStRtQSeYtvkY= +github.com/magiconair/properties v1.8.4/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= +github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= +github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.3.3 h1:SzB1nHZ2Xi+17FP0zVQBHIZqvwRN9408fJO8h+eeNA8= +github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.6.0 h1:aetoXYr0Tv7xRU/V4B4IZJ2QcbtMUFoNb3ORp7TzIK4= github.com/pelletier/go-toml v1.6.0/go.mod h1:5N711Q9dKgbdkxHL+MEfF31hpT7l0S0s/t2kKREewys= +github.com/pelletier/go-toml v1.8.1 h1:1Nf83orprkJyknT6h7zbuEGUEjcyVlCxSUGTENmNCRM= +github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= @@ -117,7 +193,11 @@ github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= @@ -130,9 +210,17 @@ github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasO github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc= github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= +github.com/spf13/afero v1.4.0 h1:jsLTaI1zwYO3vjrzHalkVcIHXTNmdQFepW4OI8H3+x8= +github.com/spf13/afero v1.4.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.3 h1:ZlrZ4XsMRm04Fr5pSFxBgfND2EBVa1nLpiy1stUsX/8= +github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v0.0.4/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= +github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= +github.com/spf13/cobra v0.0.6/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= +github.com/spf13/cobra v0.0.7/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= github.com/spf13/cobra v1.0.0 h1:6m/oheQuQ13N9ks4hubMG6BnvwOeaJrqSPLahSnczz8= github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= @@ -141,12 +229,19 @@ github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0 github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.0.0 h1:RUA/ghS2i64rlnn4ydTfblY8Og8QzcPtCcHvgMn+w/I= +github.com/spf13/viper v1.0.0/go.mod h1:A8kyI5cUJhb8N+3pkfONlcEcZbueH6nhAm0Fq7SrnBM= +github.com/spf13/viper v1.4.0 h1:yXHLWeravcrgGyFSyCgdYpXQ9dR9c/WED3pg1RhxqEU= github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= github.com/spf13/viper v1.6.2 h1:7aKfF+e8/k68gda3LOjo5RxiUqddoFxVq4BKBPrxk5E= github.com/spf13/viper v1.6.2/go.mod h1:t3iDnF5Jlj76alVNuyFBk5oUMCvsrkbvZK0WQdfDi5k= +github.com/spf13/viper v1.7.1 h1:pM5oEahlgWv/WnHXpgbKz7iLIxRf65tye2Ci+XFK5sk= +github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= @@ -188,12 +283,16 @@ gitlab.com/elixxir/comms v0.0.0-20200916212207-60e7bd5b0913 h1:p4TLPPaMysV//lOJU gitlab.com/elixxir/comms v0.0.0-20200916212207-60e7bd5b0913/go.mod h1:yBEsOZSPyJQJvDbtlQ5L8ydy1JRgVlRoNgMDy9koQcE= gitlab.com/elixxir/comms v0.0.0-20200917172539-929fc227eb0c h1:go7/RknV7646Ie+nmQXZAa/aJ5wZBn5bpAYRB+tPens= gitlab.com/elixxir/comms v0.0.0-20200917172539-929fc227eb0c/go.mod h1:yBEsOZSPyJQJvDbtlQ5L8ydy1JRgVlRoNgMDy9koQcE= +gitlab.com/elixxir/comms v0.0.0-20200921200427-5955a0a798b9 h1:skzHNWCMh+T7Cn58/88Mikg2R8KnSWfzLV0w7SnerOs= +gitlab.com/elixxir/comms v0.0.0-20200921200427-5955a0a798b9/go.mod h1:uRr8j6yTjCslxZxbRe6k4ixACu9gAeF61JZH36OFFa0= gitlab.com/elixxir/comms v0.0.0-20200922163657-3e723b7170f6 h1:dFgfdATZuiPybonCBh0s4HeLB8Qw3Zm9EoLDRh2Eaaw= gitlab.com/elixxir/comms v0.0.0-20200922163657-3e723b7170f6/go.mod h1:yBEsOZSPyJQJvDbtlQ5L8ydy1JRgVlRoNgMDy9koQcE= -gitlab.com/elixxir/comms v0.0.0-20200922182918-25d056c28b3a h1:aBBz0LOfUulcQojWFg2sawdI0EkdRNTKU5qlPsmn+Ow= -gitlab.com/elixxir/comms v0.0.0-20200922182918-25d056c28b3a/go.mod h1:uRr8j6yTjCslxZxbRe6k4ixACu9gAeF61JZH36OFFa0= -gitlab.com/elixxir/comms v0.0.0-20200923155248-2dd684128da1 h1:bYdJzis8XR/TNBY3BWlhlRrHPIffVrFZp66gX99nH0Q= -gitlab.com/elixxir/comms v0.0.0-20200923155248-2dd684128da1/go.mod h1:uRr8j6yTjCslxZxbRe6k4ixACu9gAeF61JZH36OFFa0= +gitlab.com/elixxir/comms v0.0.0-20200924072138-2e2709483d89 h1:PQalM7pnCRzZRKvdzJ6Jwz6e8bPR9H4CURzAwqYnJPE= +gitlab.com/elixxir/comms v0.0.0-20200924072138-2e2709483d89/go.mod h1:uRr8j6yTjCslxZxbRe6k4ixACu9gAeF61JZH36OFFa0= +gitlab.com/elixxir/comms v0.0.0-20200924172854-724244a10032 h1:0RLZM1fBzp7IRrjoCQANQfXMBDr1Hmjbynme564zXG8= +gitlab.com/elixxir/comms v0.0.0-20200924172854-724244a10032/go.mod h1:9+Jj7K8HOTgBjPuiP69VtTKTv7GvAK6bWlh4lgMAqrk= +gitlab.com/elixxir/comms v0.0.0-20200924210331-d7903c023fa6 h1:ctVsHyiabgRls3esApbBemDwmQ/a0CramEmZt9RCQb8= +gitlab.com/elixxir/comms v0.0.0-20200924210331-d7903c023fa6/go.mod h1:9+Jj7K8HOTgBjPuiP69VtTKTv7GvAK6bWlh4lgMAqrk= gitlab.com/elixxir/crypto v0.0.0-20200804182833-984246dea2c4 h1:28ftZDeYEko7xptCZzeFWS1Iam95dj46TWFVVlKmw6A= gitlab.com/elixxir/crypto v0.0.0-20200804182833-984246dea2c4/go.mod h1:ucm9SFKJo+K0N2GwRRpaNr+tKXMIOVWzmyUD0SbOu2c= gitlab.com/elixxir/crypto v0.0.0-20200805174804-bdf909f2a16d/go.mod h1:cu6uNoANVLV0J6HyTL6KqVtVyh9SHU1RjJhytYlsbVQ= @@ -225,25 +324,27 @@ gitlab.com/elixxir/crypto v0.0.0-20200915211245-8a519dfcc38d h1:6D2r42dFuUm96Kje gitlab.com/elixxir/crypto v0.0.0-20200915211245-8a519dfcc38d/go.mod h1:zUczcFuZGqLchDX1sjgBo189soeDK2p5Mx+GNNrkTLI= gitlab.com/elixxir/crypto v0.0.0-20200917184612-bb2ad1c493ce h1:g8/MABMbpVUJOn2BMhZJo8Pkee4YVSriFoV5po0TDkY= gitlab.com/elixxir/crypto v0.0.0-20200917184612-bb2ad1c493ce/go.mod h1:zUczcFuZGqLchDX1sjgBo189soeDK2p5Mx+GNNrkTLI= +gitlab.com/elixxir/crypto v0.0.0-20200921191117-583f263ab715 h1:1eMAfJ1uyOVU8O3JXQSBrVYt1CLMRUBSjYYzVPI+uO0= +gitlab.com/elixxir/crypto v0.0.0-20200921191117-583f263ab715/go.mod h1:1P3IMJ6i3L+5si0PiMvoo/qQXMsEhNVjn0yMUrm3eiA= gitlab.com/elixxir/crypto v0.0.0-20200921195205-bca0178268ec h1:8dnRUCSNz7knf+K5OvmEwY181aPp5ErseJogEwgS6dY= gitlab.com/elixxir/crypto v0.0.0-20200921195205-bca0178268ec/go.mod h1:1P3IMJ6i3L+5si0PiMvoo/qQXMsEhNVjn0yMUrm3eiA= gitlab.com/elixxir/ekv v0.0.0-20200729182028-159355ea5842 h1:m1zDQ6UadpuMnV7nvnyR+DUXE3AisRnVjajTb1xZE4c= gitlab.com/elixxir/ekv v0.0.0-20200729182028-159355ea5842/go.mod h1:bXY0kgbV5BHYda4YY5/hiG5bjimGK+R3PYub5yM9C/s= gitlab.com/elixxir/ekv v0.1.1 h1:Em3rF8sv+tNbQGXbcpYzAS2blWRAP708JGhYlkN74Kg= gitlab.com/elixxir/ekv v0.1.1/go.mod h1:bXY0kgbV5BHYda4YY5/hiG5bjimGK+R3PYub5yM9C/s= +gitlab.com/elixxir/ekv v0.1.3 h1:OE+LBMIhjGUMwc6hHJzYvEPNJQV7t1vMnJyIgxUMUo8= +gitlab.com/elixxir/ekv v0.1.3/go.mod h1:e6WPUt97taFZe5PFLPb1Dupk7tqmDCTQu1kkstqJvw4= gitlab.com/elixxir/primitives v0.0.0-20200731184040-494269b53b4d/go.mod h1:OQgUZq7SjnE0b+8+iIAT2eqQF+2IFHn73tOo+aV11mg= gitlab.com/elixxir/primitives v0.0.0-20200804170709-a1896d262cd9/go.mod h1:p0VelQda72OzoUckr1O+vPW0AiFe0nyKQ6gYcmFSuF8= gitlab.com/elixxir/primitives v0.0.0-20200804182913-788f47bded40/go.mod h1:tzdFFvb1ESmuTCOl1z6+yf6oAICDxH2NPUemVgoNLxc= gitlab.com/elixxir/primitives v0.0.0-20200804231232-ad79a9e8f113/go.mod h1:tzdFFvb1ESmuTCOl1z6+yf6oAICDxH2NPUemVgoNLxc= gitlab.com/elixxir/primitives v0.0.0-20200805174810-86b366d1dd2d/go.mod h1:tzdFFvb1ESmuTCOl1z6+yf6oAICDxH2NPUemVgoNLxc= gitlab.com/elixxir/primitives v0.0.0-20200812191102-31c01f08b4dc/go.mod h1:pJx2DZk9s8vVMnLN7x0hIPngDjbNSdOP6kk3RLlRxHg= -gitlab.com/elixxir/primitives v0.0.0-20200907165319-16ed0124890b h1:d1ttSIOWxWytnTpjO9hyr4KFtv/dmDBYuK59EP0sjAQ= gitlab.com/elixxir/primitives v0.0.0-20200907165319-16ed0124890b/go.mod h1:kNp47yPqja2lHSiS4DddTvFpB/4D9dB2YKnw5c+LJCE= gitlab.com/elixxir/primitives v0.0.0-20200915190719-f4586ec93f50 h1:J0A2JsYlb0He1lTGDy+6KX3s/87uklk/pLv9FKv9yp8= gitlab.com/elixxir/primitives v0.0.0-20200915190719-f4586ec93f50/go.mod h1:kNp47yPqja2lHSiS4DddTvFpB/4D9dB2YKnw5c+LJCE= gitlab.com/elixxir/primitives v0.0.0-20200916172343-37503735c7a1 h1:51FDjTwXKVadID7xRxQxMKequpEjoKAIxaMpAn/YCP0= gitlab.com/elixxir/primitives v0.0.0-20200916172343-37503735c7a1/go.mod h1:pJx2DZk9s8vVMnLN7x0hIPngDjbNSdOP6kk3RLlRxHg= -gitlab.com/xx_network/comms v0.0.0-20200805174823-841427dd5023 h1:fQPaxyuXyH3vl8qFlFDBEx8rlEzBnXBNy74K8ItFRM4= gitlab.com/xx_network/comms v0.0.0-20200805174823-841427dd5023/go.mod h1:owEcxTRl7gsoM8c3RQ5KAm5GstxrJp5tn+6JfQ4z5Hw= gitlab.com/xx_network/comms v0.0.0-20200806235452-3a82720833ba h1:7nozLSNBX0CfP53DDiDNLJx9obhYGfGf5na0/c9rMso= gitlab.com/xx_network/comms v0.0.0-20200806235452-3a82720833ba/go.mod h1:idLzPGYig57XE7xuU93OlIF9s6NgSJj7OArQvsd5DjY= @@ -258,10 +359,9 @@ gitlab.com/xx_network/comms v0.0.0-20200910173932-bd179f5fee4f h1:ExTCqEoro7VuS1 gitlab.com/xx_network/comms v0.0.0-20200910173932-bd179f5fee4f/go.mod h1:+jEkDQKoK51WLl2ZZuxfAZkz6YFbUQ+oZfH0dt2wIF0= gitlab.com/xx_network/comms v0.0.0-20200915154643-d533291041b7 h1:lPx1wpkjNpwLaZ0pyd7/iCcdITjT+eCMmb0HXCVoIkk= gitlab.com/xx_network/comms v0.0.0-20200915154643-d533291041b7/go.mod h1:+jEkDQKoK51WLl2ZZuxfAZkz6YFbUQ+oZfH0dt2wIF0= -gitlab.com/xx_network/comms v0.0.0-20200922173551-45ad1fa27175 h1:HDmgh2Skbgv/fW1selsLDRr+hvQaK24nsthxv9nAHRM= -gitlab.com/xx_network/comms v0.0.0-20200922173551-45ad1fa27175/go.mod h1:wDPZABTOhqz+uFM75CzpGplQBRIsCQcS1EYXwker6nw= -gitlab.com/xx_network/comms v0.0.0-20200923154925-b8a96380f180 h1:TGamVmJrBj7AvLi6okQ7PQoutaBptCXMAiUqTwoiXRc= -gitlab.com/xx_network/comms v0.0.0-20200923154925-b8a96380f180/go.mod h1:wDPZABTOhqz+uFM75CzpGplQBRIsCQcS1EYXwker6nw= +gitlab.com/xx_network/comms v0.0.0-20200924172734-1124191b69ee h1:dPRaW0OxcoBlWALd5H6VUYnL/ALvT7j14kWJNBi0K7A= +gitlab.com/xx_network/comms v0.0.0-20200924172734-1124191b69ee/go.mod h1:jECvMkoYKZFooCudoZxxaf2bo1DzpWP0gCahXHdlqUM= +gitlab.com/xx_network/crypto v0.0.0-20200805231039-4aa0e350ed0a h1:BlfWGPokU6yU69O+PGGsgc5iA/P9gERbHzYUvjoYbgM= gitlab.com/xx_network/crypto v0.0.0-20200806202113-978fa1984bbf/go.mod h1:i0df/q6dDCBiscgD51fMoS2U2TBrm6LcyN822JmB5Tw= gitlab.com/xx_network/crypto v0.0.0-20200806235322-ede3c15881ce h1:gypNBUl2guESEv4MDgH+miwYqR4jPoWM8dLt2Zs5gIs= gitlab.com/xx_network/crypto v0.0.0-20200806235322-ede3c15881ce/go.mod h1:i0df/q6dDCBiscgD51fMoS2U2TBrm6LcyN822JmB5Tw= @@ -279,11 +379,17 @@ gitlab.com/xx_network/primitives v0.0.0-20200915204206-eb0287ed0031/go.mod h1:wt gitlab.com/xx_network/ring v0.0.2 h1:TlPjlbFdhtJrwvRgIg4ScdngMTaynx/ByHBRZiXCoL0= gitlab.com/xx_network/ring v0.0.2/go.mod h1:aLzpP2TiZTQut/PVHR40EJAomzugDdHXetbieRClXIM= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37 h1:cg5LA/zNPRzIXIWSCxQW10Rvpy94aQh3LT/ShoCpkHw= golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -296,26 +402,57 @@ golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a h1:vclmkQCjlDX5OydZ9wv8rBCcS0QyQY66Mpf/7BZbInM= golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200707034311-ab3426394381 h1:VXak5I6aEWmAXeQjA+QSZzlgNrpq9mjcfDemuexIKsU= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -327,21 +464,53 @@ golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6 h1:DvY3Zkh7KabQE/kfzMvYvKirS golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200828194041-157a740278f4 h1:kCCpuwSAoYJPkNc6x0xT9yTtV4oKtARo4RGBQWOfg9E= golang.org/x/sys v0.0.0-20200828194041-157a740278f4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200917073148-efd3b9a0ff20/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d h1:L/IKR6COd7ubZrs2oTnTi73IhgqJ71c9s80WsQnh0Es= +golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20200709005830-7a2ca40e9dc3 h1:JwLN1jVnmIsfE4HkDVe2AblFAbo0Z+4cjteDSOnv6oE= google.golang.org/genproto v0.0.0-20200709005830-7a2ca40e9dc3/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= @@ -364,9 +533,12 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.52.0 h1:j+Lt/M1oPPejkniCg1TkWE2J3Eh1oZTsHSXzMTzUXn4= gopkg.in/ini.v1 v1.52.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.61.0 h1:LBCdW4FmFYL4s/vDZD1RQYX7oAR6IjujCYgMdbHBR10= +gopkg.in/ini.v1 v1.61.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -378,4 +550,8 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ= gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= diff --git a/interfaces/roundEvents.go b/interfaces/roundEvents.go new file mode 100644 index 0000000000000000000000000000000000000000..a3f27f76331dec24b73cea6af6bd3c99d1a54514 --- /dev/null +++ b/interfaces/roundEvents.go @@ -0,0 +1,32 @@ +package interfaces + +import ( + ds "gitlab.com/elixxir/comms/network/dataStructures" + "gitlab.com/elixxir/primitives/states" + "gitlab.com/xx_network/primitives/id" + "time" +) + +// The round events interface allows the registration of an event which triggers +// when a round reaches one or more states + +type RoundEvents interface { + // designates a callback to call on the specified event + // rid is the id of the round the event occurs on + // callback is the callback the event is triggered on + // timeout is the amount of time before an error event is returned + // valid states are the states which the event should trigger on + AddRoundEvent(rid id.Round, callback ds.RoundEventCallback, + timeout time.Duration, validStates ...states.Round) *ds.EventCallback + + // designates a go channel to signal the specified event + // rid is the id of the round the event occurs on + // eventChan is the channel the event is triggered on + // timeout is the amount of time before an error event is returned + // valid states are the states which the event should trigger on + AddRoundEventChan(rid id.Round, eventChan chan ds.EventReturn, + timeout time.Duration, validStates ...states.Round) *ds.EventCallback + + //Allows the un-registration of a round event before it triggers + Remove(rid id.Round, e *ds.EventCallback) +} diff --git a/interfaces/switchboard.go b/interfaces/switchboard.go new file mode 100644 index 0000000000000000000000000000000000000000..3ebb9d8b23779c0d8d024d330e078dc1748c6b01 --- /dev/null +++ b/interfaces/switchboard.go @@ -0,0 +1,68 @@ +package interfaces + +import ( + "gitlab.com/elixxir/client/interfaces/message" + "gitlab.com/elixxir/client/switchboard" + "gitlab.com/xx_network/primitives/id" +) + +// public switchboard interface which only allows registration and does not +// allow speaking messages +type Switchboard interface { + // Registers a new listener. Returns the ID of the new listener. + // Keep this around if you want to be able to delete the listener later. + // + // name is used for debug printing and not checked for uniqueness + // + // user: 0 for all, or any user ID to listen for messages from a particular + // user. 0 can be id.ZeroUser or id.ZeroID + // messageType: 0 for all, or any message type to listen for messages of + // that type. 0 can be switchboard.AnyType + // newListener: something implementing the Listener interface. Do not + // pass nil to this. + // + // If a message matches multiple listeners, all of them will hear the + // message. + RegisterListener(user *id.ID, messageType message.Type, + newListener switchboard.Listener) switchboard.ListenerID + + // Registers a new listener built around the passed function. + // Returns the ID of the new listener. + // Keep this around if you want to be able to delete the listener later. + // + // name is used for debug printing and not checked for uniqueness + // + // user: 0 for all, or any user ID to listen for messages from a particular + // user. 0 can be id.ZeroUser or id.ZeroID + // messageType: 0 for all, or any message type to listen for messages of + // that type. 0 can be switchboard.AnyType + // newListener: a function implementing the ListenerFunc function type. + // Do not pass nil to this. + // + // If a message matches multiple listeners, all of them will hear the + // message. + RegisterFunc(name string, user *id.ID, messageType message.Type, + newListener switchboard.ListenerFunc) switchboard.ListenerID + + // Registers a new listener built around the passed channel. + // Returns the ID of the new listener. + // Keep this around if you want to be able to delete the listener later. + // + // name is used for debug printing and not checked for uniqueness + // + // user: 0 for all, or any user ID to listen for messages from a particular + // user. 0 can be id.ZeroUser or id.ZeroID + // messageType: 0 for all, or any message type to listen for messages of + // that type. 0 can be switchboard.AnyType + // newListener: an item channel. + // Do not pass nil to this. + // + // If a message matches multiple listeners, all of them will hear the + // message. + RegisterChannel(name string, user *id.ID, messageType message.Type, + newListener chan message.Receive) switchboard.ListenerID + + // Unregister removes the listener with the specified ID so it will no + // longer get called + Unregister(listenerID switchboard.ListenerID) +} diff --git a/network/follow.go b/network/follow.go index 0a99f3d7e6bfbc26bd3916e558700bf5f04d6eb6..40892dc565c33ddb1f30fc0318351b37f30fa052 100644 --- a/network/follow.go +++ b/network/follow.go @@ -17,7 +17,7 @@ package network // - /node/register.go for add/remove node events // - /rounds/historical.go for old round retrieval // - /rounds/retrieve.go for message retrieval -// - /message/reception.go decryption, partitioning, and signaling of messages +// - /message/handle.go decryption, partitioning, and signaling of messages // - /health/tracker.go - tracks the state of the network through the network // instance @@ -33,6 +33,7 @@ import ( "time" ) +//comms interface makes testing easier type followNetworkComms interface { GetHost(hostId *id.ID) (*connect.Host, bool) SendPoll(host *connect.Host, message *pb.GatewayPoll) (*pb.GatewayPollResponse, error) @@ -55,6 +56,7 @@ func (m *manager) followNetwork(quitCh <-chan struct{}) { } } +// executes each iteration of the follower func (m *manager) follow(rng csprng.Source, comms followNetworkComms) { //randomly select a gateway to poll @@ -109,14 +111,21 @@ func (m *manager) follow(rng csprng.Source, comms followNetworkComms) { } // ---- Round Processing ----- - //build the round checker + // check rounds using the round checker function which determines if there + // are messages waiting in rounds and then sends signals to the appropriate + // handling threads roundChecker := func(rid id.Round) bool { return m.round.Checker(rid) } - //check rounds + // get the bit vector of rounds that have been checked checkedRounds := m.Session.GetCheckedRounds() + // cleave off old state in the bit vector which is deprecated from the + // network checkedRounds.Forward(lastTrackedRound) + // loop through all rounds the client does not know about and the gateway + // does, checking the bloom filter for the user to see if there are + // messages for the user (bloom not implemented yet) checkedRounds.RangeUncheckedMasked(gwRoundsState, roundChecker, int(m.param.MaxCheckedRounds)) } diff --git a/network/health/tracker.go b/network/health/tracker.go index 88a194a250967a65119e404174d06867240662d9..3a297ba9bb26a68f8e570d4762b840cac491684e 100644 --- a/network/health/tracker.go +++ b/network/health/tracker.go @@ -9,6 +9,7 @@ package health import ( + "errors" jww "github.com/spf13/jwalterweatherman" "gitlab.com/elixxir/client/stoppable" "gitlab.com/elixxir/comms/network" @@ -24,7 +25,7 @@ type Tracker struct { channels []chan bool funcs []func(isHealthy bool) - *stoppable.Single + running bool isHealthy bool mux sync.RWMutex @@ -46,7 +47,7 @@ func newTracker(timeout time.Duration) *Tracker { channels: make([]chan bool, 0), heartbeat: make(chan network.Heartbeat, 100), isHealthy: false, - Single: stoppable.NewSingle("Health Tracker"), + running: false, } } @@ -75,13 +76,30 @@ func (t *Tracker) setHealth(h bool) { t.transmit(h) } -func (t *Tracker) Start() { - if t.Single.IsRunning() { - jww.FATAL.Panicf("Cannot start the health tracker when it " + - "is already running") +func (t *Tracker) Start() (stoppable.Stoppable, error) { + t.mux.Lock() + defer t.mux.Unlock() + if t.running { + return nil, errors.New("cannot start Health tracker threads, " + + "they are already running") } + t.running = true + + t.isHealthy = false + + stop := stoppable.NewSingle("Health Tracker") + stopCleanup := stoppable.NewCleanup(stop, func(duration time.Duration) error { + t.mux.Lock() + defer t.mux.Unlock() + t.isHealthy = false + t.transmit(false) + t.running = false + return nil + }) + + go t.start(stop.Quit()) - //go t.start(t.Quit()) + return stopCleanup, nil } // Long-running thread used to monitor and report on network health diff --git a/network/manager.go b/network/manager.go index 1482b1dba7fadc4f2cd8f07c490e0912b2cc1929..75f263b67051ad54275e8d3daab42d0cb90a2af1 100644 --- a/network/manager.go +++ b/network/manager.go @@ -87,6 +87,14 @@ func NewManager(session *storage.Session, switchboard *switchboard.Switchboard, } // StartRunners kicks off all network reception goroutines ("threads"). +// Started Threads are: +// - Network Follower (/network/follow.go) +// - Historical Round Retrieval (/network/rounds/historical.go) +// - Message Retrieval Worker Group (/network/rounds/retrieve.go) +// - Message Handling Worker Group (/network/message/handle.go) +// - Health Tracker (/network/health) +// - Garbled Messages (/network/message/garbled.go) +// - Critical Messages (/network/message/critical.go) func (m *manager) Follow() (stoppable.Stoppable, error) { if !atomic.CompareAndSwapUint32(m.running, 0, 1) { @@ -96,8 +104,11 @@ func (m *manager) Follow() (stoppable.Stoppable, error) { multi := stoppable.NewMulti("networkManager") // health tracker - m.Health.Start() - multi.Add(m.Health) + healthStop, err := m.Health.Start() + if err != nil { + return nil, errors.Errorf("failed to follow") + } + multi.Add(healthStop) // Node Updates multi.Add(node.StartRegistration(m.Instance, m.Session, m.Rng, diff --git a/network/message/critical.go b/network/message/critical.go index 164dcf52d65749a86c3845c638b6faa1482b2ab0..238d94c90549ba1c3344f62debe2e819a6c275ba 100644 --- a/network/message/critical.go +++ b/network/message/critical.go @@ -10,6 +10,14 @@ import ( "time" ) +// Critical Messages are protocol layer communications that must succeed. These +// are added to the persistent critical messages store. This thread waits for +// network access to move from unhealthy to healthy and the sends all critical +// messages. +// Health is tracked by registering with the Health +// Tracker (/network/Health/Tracker.g0) + +//Thread loop for processing critical messages func (m *Manager) processCriticalMessages(quitCh <-chan struct{}) { done := false for !done { @@ -24,6 +32,7 @@ func (m *Manager) processCriticalMessages(quitCh <-chan struct{}) { } } +// processes all critical messages func (m *Manager) criticalMessages() { critMsgs := m.Session.GetCriticalMessages() //try to send every message in the critical messages buffer in paralell diff --git a/network/message/garbled.go b/network/message/garbled.go index c4fe424b9ccda33a5e9b72c36bde9f86b509e136..169d0281c098513675635b7d60791cd0061e7fc8 100644 --- a/network/message/garbled.go +++ b/network/message/garbled.go @@ -5,6 +5,23 @@ import ( "time" ) +// Messages can arrive in the network out of order. When message handling fails +// to decrypt a message, it is added to the garbled message buffer (which is +// stored on disk) and the message decryption is retried here whenever triggered. + +// This can be triggered through the CheckGarbledMessages on the network manager +// and is used in the /keyExchange package on successful rekey triggering + +// Triggers Garbled message checking if the queue is not full +// Exposed on the network manager +func (m *Manager) CheckGarbledMessages() { + select { + case m.triggerGarbled <- struct{}{}: + default: + } +} + +//long running thread which processes garbled messages func (m *Manager) processGarbledMessages(quitCh <-chan struct{}) { done := false for !done { @@ -17,6 +34,7 @@ func (m *Manager) processGarbledMessages(quitCh <-chan struct{}) { } } +//handler for a single run of garbled messages func (m *Manager) handleGarbledMessages() { garbledMsgs := m.Session.GetGarbledMessages() e2eKv := m.Session.E2e() @@ -34,7 +52,8 @@ func (m *Manager) handleGarbledMessages() { //remove from the buffer if decryption is successful garbledMsgs.Remove(grbldMsg) //handle the successfully decrypted message - xxMsg, ok := m.partitioner.HandlePartition(sender, message.E2E, msg.GetContents()) + xxMsg, ok := m.partitioner.HandlePartition(sender, message.E2E, + msg.GetContents()) if ok { m.Switchboard.Speak(xxMsg) continue @@ -42,8 +61,8 @@ func (m *Manager) handleGarbledMessages() { } } // fail the message if any part of the decryption fails, - // unless it is our of attempts and has been in the buffer long enough, - // then remove it + // unless it is the last attempts and has been in the buffer long + // enough, in which case remove it if count == m.param.MaxChecksGarbledMessage && time.Since(timestamp) > m.param.GarbledMessageWait { garbledMsgs.Remove(grbldMsg) diff --git a/network/message/reception.go b/network/message/handler.go similarity index 93% rename from network/message/reception.go rename to network/message/handler.go index 74b60b7d79aaba2f3a03a7ade4829baa715aca33..66eb7ad268a7791dfa8e1ef0f66d4413d64381eb 100644 --- a/network/message/reception.go +++ b/network/message/handler.go @@ -9,7 +9,7 @@ import ( "time" ) -func (m *Manager) processMessages(quitCh <-chan struct{}) { +func (m *Manager) handleMessages(quitCh <-chan struct{}) { done := false for !done { select { @@ -17,7 +17,7 @@ func (m *Manager) processMessages(quitCh <-chan struct{}) { done = true case bundle := <-m.messageReception: for _, msg := range bundle.Messages { - m.receiveMessage(msg) + m.handleMessage(msg) } bundle.Finish() } @@ -25,7 +25,7 @@ func (m *Manager) processMessages(quitCh <-chan struct{}) { } -func (m *Manager) receiveMessage(ecrMsg format.Message) { +func (m *Manager) handleMessage(ecrMsg format.Message) { // We've done all the networking, now process the message fingerprint := ecrMsg.GetKeyFP() diff --git a/network/message/manager.go b/network/message/manager.go index 3d95ef04099fe5bf997d601b0a9b4205c9385281..daa398a6cfe033f7ac0d6462306617e1d5b79e5f 100644 --- a/network/message/manager.go +++ b/network/message/manager.go @@ -41,22 +41,14 @@ func (m *Manager) GetMessageReceptionChannel() chan<- Bundle { return m.messageReception } -//Gets the channel to send received messages on -func (m *Manager) CheckGarbledMessages() { - select { - case m.triggerGarbled <- struct{}{}: - default: - } -} - //Starts all worker pool func (m *Manager) StartProcessies() stoppable.Stoppable { multi := stoppable.NewMulti("MessageReception") - //create the message reception workers + //create the message handler workers for i := uint(0); i < m.param.MessageReceptionWorkerPoolSize; i++ { stop := stoppable.NewSingle(fmt.Sprintf("MessageReception Worker %v", i)) - go m.processMessages(stop.Quit()) + go m.handleMessages(stop.Quit()) multi.Add(stop) } diff --git a/network/message/sendCmix.go b/network/message/sendCmix.go index 83e76e3cec2f0048e5fd1ed5144c29f18ad854ac..c60cab6aa257d7a11d6a01666d2f0c31c2b22f4a 100644 --- a/network/message/sendCmix.go +++ b/network/message/sendCmix.go @@ -13,8 +13,15 @@ import ( "time" ) -// Internal send e2e which bypasses the network check, for use in SendE2E and -// SendUnsafe which do their own network checks +// WARNING: Potentially Unsafe +// Payloads send are not End to End encrypted, MetaData is NOT protected with +// this call, see SendE2E for End to End encryption and full privacy protection +// Internal SendCmix which bypasses the network check, will attempt to send to +// the network without checking state. It has a built in retry system which can +// be configured through the params object. +// If the message is successfully sent, the id of the round sent it is returned, +// which can be registered with the network instance to get a callback on +// its status func (m *Manager) SendCMIX(msg format.Message, param params.CMIX) (id.Round, error) { timeStart := time.Now() @@ -29,11 +36,14 @@ func (m *Manager) SendCMIX(msg format.Message, param params.CMIX) (id.Round, err //find the best round to send to, excluding roudn which have been attempted bestRound, _ := m.Instance.GetWaitingRounds().GetUpcomingRealtime(remainingTime, attempted) - topology, err := buildToplogy(bestRound.Topology) + + //build the topology + idList, err := id.NewIDListFromBytes(bestRound.Topology) if err == nil { jww.ERROR.Printf("Failed to use topology for round %v: %s", bestRound.ID, err) continue } + topology := connect.NewCircuit(idList) //get they keys for the round, reject if any nodes do not have //keying relationships @@ -101,22 +111,11 @@ func (m *Manager) SendCMIX(msg format.Message, param params.CMIX) (id.Round, err return 0, errors.New("failed to send the message") } -func buildToplogy(nodes [][]byte) (*connect.Circuit, error) { - idList := make([]*id.ID, len(nodes)) - for i, n := range nodes { - nid, err := id.Unmarshal(n) - if err != nil { - return nil, errors.WithMessagef(err, "Failed to "+ - "convert topology on node %v/%v {raw id: %v}", i, len(nodes), n) - } - idList[i] = nid - } - topology := connect.NewCircuit(idList) - return topology, nil - -} - -func handleMissingNodeKeys(instance *network.Instance, newNodeChan chan network.NodeGateway, nodes []*id.ID) { +// Signals to the node registration thread to register a node if keys are +// missing. Registration is triggered automatically when the node is first seen, +// so this should on trigger on rare events. +func handleMissingNodeKeys(instance *network.Instance, + newNodeChan chan network.NodeGateway, nodes []*id.ID) { for _, n := range nodes { ng, err := instance.GetNodeAndGateway(n) if err != nil { diff --git a/network/message/sendUnsafe.go b/network/message/sendUnsafe.go index 2cabff6fcc194bffe01fc05648af666029d079f0..92c3fbbf29f9cff68aaf585c4eca268184733d60 100644 --- a/network/message/sendUnsafe.go +++ b/network/message/sendUnsafe.go @@ -11,6 +11,15 @@ import ( "time" ) +// WARNING: Unsafe +// Payloads are not End to End encrypted, MetaData is NOT protected with +// this call, see SendE2E for End to End encryption and full privacy protection +// Internal SendUnsafe which bypasses the network check, will attempt to send to +// the network without checking state. +// This partitions payloads into multi-part messages but does NOT end to encrypt +// them +// Sends using SendCMIX and returns a list of rounds the messages are in. Will +// return an error if a single part of the message fails to send. func (m *Manager) SendUnsafe(msg message.Send, param params.Unsafe) ([]id.Round, error) { //timestamp the message diff --git a/network/node/register_test.go b/network/node/register_test.go index a005733131a134e68c600edd57e8eb8b3fa07f27..38c9ef1603f225f424e4d6ca1af2b6ade7c05ea6 100644 --- a/network/node/register_test.go +++ b/network/node/register_test.go @@ -1,19 +1,19 @@ package node import ( - "crypto/rand" - "gitlab.com/elixxir/client/stoppable" - "gitlab.com/elixxir/client/storage" + //"crypto/rand" + //"gitlab.com/elixxir/client/stoppable" + //"gitlab.com/elixxir/client/storage" pb "gitlab.com/elixxir/comms/mixmessages" - "gitlab.com/elixxir/comms/network" - "gitlab.com/elixxir/crypto/csprng" - "gitlab.com/elixxir/crypto/fastRNG" + //"gitlab.com/elixxir/comms/network" + //"gitlab.com/elixxir/crypto/csprng" + //"gitlab.com/elixxir/crypto/fastRNG" "gitlab.com/xx_network/comms/connect" - "gitlab.com/xx_network/crypto/signature/rsa" + //"gitlab.com/xx_network/crypto/signature/rsa" "gitlab.com/xx_network/primitives/id" - "gitlab.com/xx_network/primitives/ndf" - "testing" - "time" + //"gitlab.com/xx_network/primitives/ndf" + //"testing" + //"time" ) // Mock client comms object @@ -52,64 +52,65 @@ func (mcc *MockClientComms) SendConfirmNonceMessage(host *connect.Host, }, nil } -func TestRegisterNodes(t *testing.T) { - privKey, err := rsa.LoadPrivateKeyFromPem([]byte("-----BEGIN PRIVATE KEY-----\n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\nOaRA5ZbdE7g7vxKRV36jT3wvD7W+\n-----END PRIVATE KEY-----\n")) - if err != nil || privKey == nil { - t.Error("Failed to load privKey\n") - } - pub := "-----BEGIN CERTIFICATE-----\n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\n-----END CERTIFICATE-----\n" +// func TestRegisterNodes(t *testing.T) { +// privKey, err := rsa.LoadPrivateKeyFromPem([]byte("-----BEGIN PRIVATE KEY-----\n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\nOaRA5ZbdE7g7vxKRV36jT3wvD7W+\n-----END PRIVATE KEY-----\n")) +// if err != nil || privKey == nil { +// t.Error("Failed to load privKey\n") +// } +// pub := "-----BEGIN CERTIFICATE-----\n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\n-----END CERTIFICATE-----\n" - salt := make([]byte, 32) - _, err = rand.Read(salt) - if err != nil { - t.Errorf("Failed to generate salt: %+v", err) - } - //uid := id.NewIdFromString("zezima", id.User, t) - comms := NewMockClientComms() +// salt := make([]byte, 32) +// _, err = rand.Read(salt) +// if err != nil { +// t.Errorf("Failed to generate salt: %+v", err) +// } +// //uid := id.NewIdFromString("zezima", id.User, t) +// comms := NewMockClientComms() - instanceComms := &connect.ProtoComms{} - _, err = instanceComms.AddHost(&id.Permissioning, "0.0.0.0:420", []byte(pub), false, false) - if err != nil { - t.Errorf("Faield to add perm host: %+v", err) - } +// instanceComms := &connect.ProtoComms{} +// _, err = instanceComms.AddHost(&id.Permissioning, "0.0.0.0:420", []byte(pub), +// connect.GetDefaultHostParams()) +// if err != nil { +// t.Errorf("Faield to add perm host: %+v", err) +// } - sess := storage.InitTestingSession(t) +// sess := storage.InitTestingSession(t) - rng := fastRNG.NewStreamGenerator(7, 3, csprng.NewSystemRNG) +// rng := fastRNG.NewStreamGenerator(7, 3, csprng.NewSystemRNG) - stop := stoppable.NewSingle("test") - c := make(chan network.NodeGateway, 100) - go registerNodes(sess, rng, comms, stop, c) +// stop := stoppable.NewSingle("test") +// c := make(chan network.NodeGateway, 100) +// go registerNodes(sess, rng, comms, stop, c) - c <- network.NodeGateway{ - Node: ndf.Node{ - ID: id.NewIdFromString("zezima", id.Node, t).Bytes(), - Address: "0.0.0.0:420", - TlsCertificate: pub, - }, - Gateway: ndf.Gateway{ - ID: id.NewIdFromString("zezima", id.Gateway, t).Bytes(), - Address: "0.0.0.0:421", - TlsCertificate: pub, - }, - } +// c <- network.NodeGateway{ +// Node: ndf.Node{ +// ID: id.NewIdFromString("zezima", id.Node, t).Bytes(), +// Address: "0.0.0.0:420", +// TlsCertificate: pub, +// }, +// Gateway: ndf.Gateway{ +// ID: id.NewIdFromString("zezima", id.Gateway, t).Bytes(), +// Address: "0.0.0.0:421", +// TlsCertificate: pub, +// }, +// } - timeout := time.NewTimer(time.Second * 5) - select { - case <-timeout.C: - t.Errorf("Timed out waiting for request nonce channel signal") - case <-comms.request: - } +// timeout := time.NewTimer(time.Second * 5) +// select { +// case <-timeout.C: +// t.Errorf("Timed out waiting for request nonce channel signal") +// case <-comms.request: +// } - timeout.Reset(5 * time.Second) - select { - case <-timeout.C: - t.Errorf("Timed out waiting for confirm nonce channel signal") - case <-comms.confirm: - } +// timeout.Reset(5 * time.Second) +// select { +// case <-timeout.C: +// t.Errorf("Timed out waiting for confirm nonce channel signal") +// case <-comms.confirm: +// } - err = stop.Close(5 * time.Second) - if err != nil { - t.Errorf("Failed to stop registration thread: %+v", err) - } -} \ No newline at end of file +// err = stop.Close(5 * time.Second) +// if err != nil { +// t.Errorf("Failed to stop registration thread: %+v", err) +// } +// } diff --git a/network/rounds/check.go b/network/rounds/check.go index 5ac70543d0f9221742818e89764736c0a27cc1e0..74d8f0b3361fd4a569f7d347d23be856467e3b76 100644 --- a/network/rounds/check.go +++ b/network/rounds/check.go @@ -1,40 +1,47 @@ package rounds import ( + jww "github.com/spf13/jwalterweatherman" "gitlab.com/xx_network/primitives/id" ) -// getRoundChecker passes a context and the round infos received by the -// gateway to the funky round checker api to update round state. -// The returned function passes round event objects over the context -// to the rest of the message handlers for getting messages. +// the round checker is a single use function which is meant to be wrapped +// and adhere to the knownRounds checker interface. it receives a round ID and +// looks up the state of that round to determine if the client has a message +// waiting in it. +// It will return true if it can conclusively determine no message exists, +// returning false and set the round to processing if it needs further +// investigation. +// Once it determines messages might be waiting in a round, it determines +// if the information about that round is already present, if it is the data is +// sent to Message Retrieval Workers, otherwise it is sent to Historical Round +// Retrieval func (m *Manager) Checker(roundID id.Round) bool { // Set round to processing, if we can processing, count := m.p.Process(roundID) if !processing { + // if is already processing, ignore return false } + + //if the number of times the round has been checked has hit the max, drop it if count == m.params.MaxAttemptsCheckingARound { + jww.ERROR.Printf("Round %v failed the maximum number of times "+ + "(%v), stopping retrval attempt", roundID, + m.params.MaxAttemptsCheckingARound) m.p.Done(roundID) return true } - // FIXME: Spec has us SETTING processing, but not REMOVING it - // until the get messages thread completes the lookup, this - // is smell that needs refining. It seems as if there should be - // a state that lives with the round info as soon as we know - // about it that gets updated at different parts...not clear - // needs to be thought through. - //defer processing.Done(roundID) // TODO: Bloom filter lookup -- return true when we don't have - // Go get the round from the round infos, if it exists + // Go get the round from the round infos, if it exists ri, err := m.Instance.GetRound(roundID) if err != nil { - // If we didn't find it, send to historical - // rounds processor + // If we didn't find it, send to Historical Rounds Retrieval m.historicalRounds <- roundID } else { + // IF found, send to Message Retrieval Workers m.lookupRoundMessages <- ri } diff --git a/network/rounds/historical.go b/network/rounds/historical.go index c1a488555f44a825609c8670e12081e75f851042..d582ba20476126567c7cb656089031668ed806ef 100644 --- a/network/rounds/historical.go +++ b/network/rounds/historical.go @@ -15,17 +15,27 @@ import ( "time" ) +// Historical Rounds looks up the round history via random gateways. +// It batches these quests but never waits longer than +// params.HistoricalRoundsPeriod to do a lookup. +// Historical rounds receives input from: +// - Network Follower (/network/follow.go) +// Historical Rounds sends the output to: +// - Message Retrieval Workers (/network/round/retrieve.go) + +//interface to increase east of testing of historical rounds type historicalRoundsComms interface { GetHost(hostId *id.ID) (*connect.Host, bool) RequestHistoricalRounds(host *connect.Host, message *pb.HistoricalRounds) (*pb.HistoricalRoundsResponse, error) } -// ProcessHistoricalRounds analyzes round history to see if this Client -// needs to check for messages at any of the gateways which completed -// those rounds. +// Long running thread which process historical rounds +// Can be killed by sending a signal to the quit channel +// takes a comms interface to aid in testing func (m *Manager) processHistoricalRounds(comm historicalRoundsComms, quitCh <-chan struct{}) { - ticker := time.NewTicker(m.params.HistoricalRoundsPeriod) + + timerCh := make(<-chan time.Time) rng := m.Rng.GetStream() var rounds []uint64 @@ -33,30 +43,48 @@ func (m *Manager) processHistoricalRounds(comm historicalRoundsComms, quitCh <-c done := false for !done { shouldProcess := false + // wait for a quit or new round to check select { case <-quitCh: rng.Close() + // return all rounds in the queue to the input channel so they can + // be checked in the future. If the queue is full, disable them as + // processing so they are picked up from the beginning + for _, rid := range rounds { + select { + case m.historicalRounds <- id.Round(rid): + default: + m.p.NotProcessing(id.Round(rid)) + } + } done = true - case <-ticker.C: + // if the timer elapses process rounds to ensure the delay isn't too long + case <-timerCh: if len(rounds) > 0 { shouldProcess = true } + // get new round to lookup and force a lookup if case rid := <-m.historicalRounds: rounds = append(rounds, uint64(rid)) if len(rounds) > int(m.params.MaxHistoricalRounds) { shouldProcess = true + } else if len(rounds) == 1 { + //if this is the first round, start the timeout + timerCh = time.NewTimer(m.params.HistoricalRoundsPeriod).C } } if !shouldProcess { continue } + //find a gateway to request about the rounds gwHost, err := gateway.Get(m.Instance.GetPartialNdf().Get(), comm, rng) if err != nil { jww.FATAL.Panicf("Failed to track network, NDF has corrupt "+ "data: %s", err) } + //send the historical rounds request hr := &pb.HistoricalRounds{ Rounds: rounds, } @@ -65,17 +93,25 @@ func (m *Manager) processHistoricalRounds(comm historicalRoundsComms, quitCh <-c if err != nil { jww.ERROR.Printf("Failed to request historical rounds "+ "data: %s", response) - // if the check fails to resolve, break the loop so they will be + // if the check fails to resolve, break the loop and so they will be // checked again - break + timerCh = time.NewTimer(m.params.HistoricalRoundsPeriod).C + continue } + + // process the returned historical rounds. for i, roundInfo := range response.Rounds { + // The interface has missing returns returned as nil, such rounds + // need be be removes as processing so the network follower will + // pick them up in the future. if roundInfo == nil { jww.ERROR.Printf("could not retreive "+ "historical round %d", rounds[i]) + m.p.Fail(id.Round(rounds[i])) continue } - m.p.Done(id.Round(rounds[i])) + // Successfully retrieved rounds are sent to the Message + // Retrieval Workers m.lookupRoundMessages <- roundInfo } } diff --git a/network/rounds/processingRounds.go b/network/rounds/processingRounds.go index 5a9442ba16cd80fc842d600f9c95475fdb6f6364..585a7656c692cdf8e21719ffd30c4960c7cb3ebf 100644 --- a/network/rounds/processingRounds.go +++ b/network/rounds/processingRounds.go @@ -8,7 +8,7 @@ import ( ) type status struct { - count uint + failCount uint processing bool } @@ -34,16 +34,15 @@ func (pr *processing) Process(id id.Round) (bool, uint) { if rs, ok := pr.rounds[id]; ok { if rs.processing { - return false, rs.count + return false, rs.failCount } - rs.count++ rs.processing = true - return true, rs.count + return true, rs.failCount } pr.rounds[id] = &status{ - count: 0, + failCount: 0, processing: true, } @@ -62,12 +61,14 @@ func (pr *processing) IsProcessing(id id.Round) bool { return false } -// Fail sets a round's processing status to failed so that it can be retried. +// Fail sets a round's processing status to failed and increments its fail +// counter so that it can be retried. func (pr *processing) Fail(id id.Round) { pr.Lock() defer pr.Unlock() if rs, ok := pr.rounds[id]; ok { rs.processing = false + rs.failCount++ } } @@ -77,3 +78,13 @@ func (pr *processing) Done(id id.Round) { defer pr.Unlock() delete(pr.rounds, id) } + +// NotProcessing sets a round's processing status to failed so that it can be +// retried but does not increment its fail counter. +func (pr *processing) NotProcessing(id id.Round) { + pr.Lock() + defer pr.Unlock() + if rs, ok := pr.rounds[id]; ok { + rs.processing = false + } +} \ No newline at end of file diff --git a/network/rounds/processingRounds_test.go b/network/rounds/processingRounds_test.go index e57fe05e4d9ba437b5b21af052c92dd719e8bfcf..8b61ad6d76a050134a03246df47c6e7996af4ed8 100644 --- a/network/rounds/processingRounds_test.go +++ b/network/rounds/processingRounds_test.go @@ -33,10 +33,10 @@ func TestProcessing_Process(t *testing.T) { }{ {10, true, true, 0}, {10, true, false, 0}, - {10, false, true, 1}, + {10, false, true, 0}, {100, true, true, 0}, {100, true, false, 0}, - {100, false, true, 1}, + {100, false, true, 0}, } for i, d := range testData { @@ -86,6 +86,9 @@ func TestProcessing_Fail(t *testing.T) { if pr.rounds[rid].processing { t.Errorf("Fail() did not mark processing as false for round id %d.", rid) } + if pr.rounds[rid].failCount != 1 { + t.Errorf("Fail() did not increment the fail count of round id %d.", rid) + } } // Tests happy path of Done. diff --git a/network/rounds/retrieve.go b/network/rounds/retrieve.go index b6b45e7a35383e9f3dabe116733c77de12887db4..7378332ad289aa21ef45a0e2844b29428ea06235 100644 --- a/network/rounds/retrieve.go +++ b/network/rounds/retrieve.go @@ -1,7 +1,6 @@ package rounds import ( - "encoding/binary" "github.com/pkg/errors" jww "github.com/spf13/jwalterweatherman" "gitlab.com/elixxir/client/network/gateway" @@ -40,12 +39,6 @@ func (m *Manager) processMessageRetrieval(comms messageRetrievalComms, } } -// TODO: remove me when api fixed -func uint64ToBytes(i uint64) []byte { - bs := make([]byte, 8) - binary.LittleEndian.PutUint64(bs, 31415926) - return bs -} func (m *Manager) getMessagesFromGateway(roundInfo *pb.RoundInfo, comms messageRetrievalComms) (message.Bundle, error) { @@ -62,8 +55,7 @@ func (m *Manager) getMessagesFromGateway(roundInfo *pb.RoundInfo, // send the request msgReq := &pb.GetMessages{ ClientID: m.Uid.Marshal(), - //TODO: fix this, should not be a byte slice - RoundID: uint64ToBytes(uint64(rid)), + RoundID: uint64(rid), } msgResp, err := comms.RequestMessages(gwHost, msgReq) // Fail the round if an error occurs so it can be tried again later diff --git a/network/send.go b/network/send.go index 7e6aeb84e73ca0a30a1ff660aee3855dea4196a8..904776c9dceca9af15e6814ce16ccd0162e66382 100644 --- a/network/send.go +++ b/network/send.go @@ -14,7 +14,7 @@ import ( // Returns the round ID of the round the payload was sent or an error // if it fails. func (m *manager) SendCMIX(msg format.Message, param params.CMIX) (id.Round, error) { - if !m.Health.IsRunning() { + if !m.Health.IsHealthy() { return 0, errors.New("Cannot send cmix message when the " + "network is not healthy") } @@ -28,7 +28,7 @@ func (m *manager) SendCMIX(msg format.Message, param params.CMIX) (id.Round, err // NOTE: Do not use this function unless you know what you are doing. // This function always produces an error message in client logging. func (m *manager) SendUnsafe(msg message.Send, param params.Unsafe) ([]id.Round, error) { - if !m.Health.IsRunning() { + if !m.Health.IsHealthy() { return nil, errors.New("cannot send unsafe message when the " + "network is not healthy") } @@ -46,7 +46,7 @@ func (m *manager) SendUnsafe(msg message.Send, param params.Unsafe) ([]id.Round, func (m *manager) SendE2E(msg message.Send, e2eP params.E2E) ( []id.Round, error) { - if !m.Health.IsRunning() { + if !m.Health.IsHealthy() { return nil, errors.New("Cannot send e2e message when the " + "network is not healthy") } diff --git a/permissioning/permissioning.go b/permissioning/permissioning.go index 7ebb8ac90691fe57d8d089f086554fc586b38d70..3d28dca1b7da5cd75548b463e52f6e8127fe0b03 100644 --- a/permissioning/permissioning.go +++ b/permissioning/permissioning.go @@ -23,8 +23,8 @@ func Init(comms *client.Comms, def *ndf.NetworkDefinition) (*Permissioning, erro var err error //add the permissioning host to comms perm.host, err = comms.AddHost(&id.Permissioning, def.Registration.Address, - []byte(def.Registration.TlsCertificate), false, - false) + []byte(def.Registration.TlsCertificate), + connect.GetDefaultHostParams()) if err != nil { return nil, errors.WithMessage(err, "failed to create permissioning") diff --git a/permissioning/register_test.go b/permissioning/register_test.go index bdf96a3bc0a30da7f6e42b9e01982a9b2bd2bc97..3ef1040e3fc186bd4e5f800fadb1d848a6ae1488 100644 --- a/permissioning/register_test.go +++ b/permissioning/register_test.go @@ -50,7 +50,8 @@ func TestRegisterWithPermissioning(t *testing.T) { var sender MockRegistrationSender sender.succeedGetHost = true - sender.getHost, err = connect.NewHost(&id.Permissioning, "address", nil, false, false) + sender.getHost, err = connect.NewHost(&id.Permissioning, "address", nil, + connect.GetDefaultHostParams()) if err != nil { t.Fatal(err) } diff --git a/stoppable/cleanup.go b/stoppable/cleanup.go index ffe3cdae60b6c14ca081e18dce3aa0a44b21380d..a733d74bc175d09403d2a681c8108b528a31d9f2 100644 --- a/stoppable/cleanup.go +++ b/stoppable/cleanup.go @@ -37,7 +37,7 @@ func (c *Cleanup) IsRunning() bool { // Name returns the name of the stoppable denoting it has cleanup. func (c *Cleanup) Name() string { - return Name() + " with cleanup" + return c.stop.Name() + " with cleanup" } // Close stops the contained stoppable and runs the cleanup function after. The @@ -51,9 +51,9 @@ func (c *Cleanup) Close(timeout time.Duration) error { start := time.Now() // Run the stoppable - if err := Close(timeout); err != nil { + if err := c.stop.Close(timeout); err != nil { err = errors.WithMessagef(err, "Cleanup for %s not executed", - Name()) + c.stop.Name()) return } @@ -71,10 +71,10 @@ func (c *Cleanup) Close(timeout time.Duration) error { case err := <-complete: if err != nil { err = errors.WithMessagef(err, "Cleanup for %s failed", - Name()) + c.stop.Name()) } case <-timer.C: - err = errors.Errorf("Clean up for %s timeout", Name()) + err = errors.Errorf("Clean up for %s timeout", c.stop.Name()) } }) diff --git a/stoppable/multi.go b/stoppable/multi.go index a0f947d02d7a81d359435c8a53597a7bbf3fd714..061be492dd4efd2d6c618d7f9772a18fb8cc7ab7 100644 --- a/stoppable/multi.go +++ b/stoppable/multi.go @@ -43,7 +43,7 @@ func (m *Multi) Name() string { m.mux.RLock() names := m.name + ": {" for _, s := range m.stoppables { - names += Name() + ", " + names += s.Name() + ", " } if len(m.stoppables) > 0 { names = names[:len(names)-2] @@ -69,7 +69,7 @@ func (m *Multi) Close(timeout time.Duration) error { for _, stoppable := range m.stoppables { wg.Add(1) go func(stoppable Stoppable) { - if Close(timeout) != nil { + if stoppable.Close(timeout) != nil { atomic.AddUint32(&numErrors, 1) } wg.Done() diff --git a/storage/cmix/store_test.go b/storage/cmix/store_test.go index df305ebb3dd092b03a0e74ae01661a135a9faf3b..1605abe94784920bc319dbb79641571b85c6d332 100644 --- a/storage/cmix/store_test.go +++ b/storage/cmix/store_test.go @@ -14,34 +14,13 @@ import ( "gitlab.com/elixxir/ekv" "gitlab.com/xx_network/comms/connect" "gitlab.com/xx_network/primitives/id" - "os" "testing" ) -// Most of these tests use the same Store -// So keep that in mind when designing tests -var testStore *Store - -// Main testing function -func TestMain(m *testing.M) { - - kv := make(ekv.Memstore) - vkv := versioned.NewKV(kv) - - grp := cyclic.NewGroup(large.NewInt(173), large.NewInt(2)) - priv := grp.NewInt(2) - - testStore, _ = NewStore(grp, vkv, priv) - - runFunc := func() int { - return m.Run() - } - - os.Exit(runFunc()) -} - // Happy path Add/Done test func TestStore_AddRemove(t *testing.T) { + testStore, _ := makeTestStore() + nodeId := id.NewIdFromString("test", id.Node, t) key := testStore.grp.NewInt(5) @@ -60,13 +39,16 @@ func TestStore_AddRemove(t *testing.T) { // Happy path func TestLoadStore(t *testing.T) { + testStore, kv := makeTestStore() + // Add a test node key nodeId := id.NewIdFromString("test", id.Node, t) key := testStore.grp.NewInt(5) + testStore.Add(nodeId, key) // Load the store and check its attributes - store, err := LoadStore(testStore.kv) + store, err := LoadStore(kv) if err != nil { t.Errorf("Unable to load store: %+v", err) } @@ -83,6 +65,7 @@ func TestLoadStore(t *testing.T) { // Happy path func TestStore_GetRoundKeys(t *testing.T) { + testStore, _ := makeTestStore() // Set up the circuit numIds := 10 nodeIds := make([]*id.ID, numIds) @@ -107,6 +90,7 @@ func TestStore_GetRoundKeys(t *testing.T) { // Missing keys path func TestStore_GetRoundKeys_Missing(t *testing.T) { + testStore, _ := makeTestStore() // Set up the circuit numIds := 10 nodeIds := make([]*id.ID, numIds) @@ -165,3 +149,17 @@ func TestNewStore(t *testing.T) { t.Errorf("Failed to set store.kv") } } + +// Main testing function +func makeTestStore() (*Store, *versioned.KV) { + + kv := make(ekv.Memstore) + vkv := versioned.NewKV(kv) + + grp := cyclic.NewGroup(large.NewInt(173), large.NewInt(2)) + priv := grp.NewInt(2) + + testStore, _ := NewStore(grp, vkv, priv) + + return testStore, vkv +} \ No newline at end of file diff --git a/storage/regCode.go b/storage/regCode.go index c2d7c2fadf5b5556b75d6569294735e9917a833f..acc03a36051e824e40f693ab96837debe1d129fe 100644 --- a/storage/regCode.go +++ b/storage/regCode.go @@ -1,10 +1,10 @@ package storage import ( - "gitlab.com/elixxir/client/storage/versioned" "github.com/pkg/errors" - "time" jww "github.com/spf13/jwalterweatherman" + "gitlab.com/elixxir/client/storage/versioned" + "time" ) const regCodeKey = "regCode" diff --git a/switchboard/switchboard_test.go b/switchboard/switchboard_test.go index 27a7635c2ad301099a854a1945fd6d2bf54761b0..5c097cdfa05a2686fd571258c290765d62cc8741 100644 --- a/switchboard/switchboard_test.go +++ b/switchboard/switchboard_test.go @@ -155,7 +155,7 @@ func TestSwitchboard_RegisterFunc(t *testing.T) { t.Errorf("Listener is not registered by Message Type") } - Hear(message.Receive{}) + lid.listener.Hear(message.Receive{}) if !heard { t.Errorf("Func listener not registered correctly") } @@ -224,7 +224,7 @@ func TestSwitchboard_RegisterChan(t *testing.T) { t.Errorf("Listener is not registered by Message Type") } - Hear(message.Receive{}) + lid.listener.Hear(message.Receive{}) select { case <-ch: case <-time.After(5 * time.Millisecond):