Something went wrong on our end
-
Sydney Anne Erickson authoredSydney Anne Erickson authored
connect.go 4.65 KiB
////////////////////////////////////////////////////////////////////////////////
// Copyright © 2022 xx foundation //
// //
// Use of this source code is governed by a license that can be found in the //
// LICENSE file. //
////////////////////////////////////////////////////////////////////////////////
package bindings
import (
"encoding/json"
"sync"
"github.com/pkg/errors"
jww "github.com/spf13/jwalterweatherman"
"gitlab.com/elixxir/client/catalog"
"gitlab.com/elixxir/client/connect"
"gitlab.com/elixxir/client/xxdk"
"gitlab.com/elixxir/crypto/contact"
)
// connectionTrackerSingleton is used to track connections so that they can be
// referenced by ID back over the bindings.
var connectionTrackerSingleton = &connectionTracker{
connections: make(map[int]*Connection),
count: 0,
}
// Connection is the bindings' representation of a connect.Connection object
// that can be tracked by ID.
type Connection struct {
connection connect.Connection
id int
params xxdk.E2EParams
}
// GetId returns the Connection ID.
func (c *Connection) GetId() int {
return c.id
}
// Connect performs auth key negotiation with the given recipient and returns a
// Connection object for the newly created partner.Manager.
//
// This function is to be used sender-side and will block until the
// partner.Manager is confirmed.
//
// Parameters:
// - e2eId - ID of the E2E object in the e2e tracker
// - recipientContact - marshalled contact.Contact object
// - e2eParamsJSON - JSON marshalled byte of xxdk.E2EParams object
func (c *Cmix) Connect(e2eId int, recipientContact, e2eParamsJSON []byte) (
*Connection, error) {
if len(e2eParamsJSON) == 0 {
jww.WARN.Printf("e2e params not specified, using defaults...")
e2eParamsJSON = GetDefaultE2EParams()
}
cont, err := contact.Unmarshal(recipientContact)
if err != nil {
return nil, err
}
user, err := e2eTrackerSingleton.get(e2eId)
if err != nil {
return nil, err
}
p, err := parseE2EParams(e2eParamsJSON)
if err != nil {
return nil, err
}
connection, err := connect.Connect(cont, user.api, p)
if err != nil {
return nil, err
}
return connectionTrackerSingleton.make(connection, p), nil
}
// SendE2E is a wrapper for sending specifically to the Connection's
// partner.Manager.
//
// Returns:
// - []byte - the JSON marshalled bytes of the E2ESendReport object, which can
// be passed into Cmix.WaitForRoundResult to see if the send succeeded.
func (c *Connection) SendE2E(mt int, payload []byte) ([]byte, error) {
sendReport, err := c.connection.SendE2E(catalog.MessageType(mt), payload,
c.params.Base)
if err != nil {
return nil, err
}
sr := E2ESendReport{
RoundsList: makeRoundsList(sendReport.RoundList...),
MessageID: sendReport.MessageId.Marshal(),
Timestamp: sendReport.SentTime.UnixNano(),
KeyResidue: sendReport.KeyResidue.Marshal(),
}
return json.Marshal(&sr)
}
// Close deletes this Connection's partner.Manager and releases resources.
func (c *Connection) Close() error {
return c.connection.Close()
}
// GetPartner returns the partner.Manager for this Connection.
func (c *Connection) GetPartner() []byte {
return c.connection.GetPartner().PartnerId().Marshal()
}
// RegisterListener is used for E2E reception and allows for reading data sent
// from the partner.Manager.
func (c *Connection) RegisterListener(messageType int, newListener Listener) error {
_, err := c.connection.RegisterListener(
catalog.MessageType(messageType), listener{l: newListener})
return err
}
// connectionTracker is a singleton used to keep track of extant connections,
// allowing for race condition-free passing over the bindings.
type connectionTracker struct {
connections map[int]*Connection
count int
mux sync.RWMutex
}
// make makes a Connection, assigning it a unique ID.
func (ct *connectionTracker) make(
c connect.Connection, params xxdk.E2EParams) *Connection {
ct.mux.Lock()
defer ct.mux.Unlock()
id := ct.count
ct.count++
ct.connections[id] = &Connection{
connection: c,
id: id,
params: params,
}
return ct.connections[id]
}
// get returns a Connection given its ID.
func (ct *connectionTracker) get(id int) (*Connection, error) {
ct.mux.RLock()
defer ct.mux.RUnlock()
c, exist := ct.connections[id]
if !exist {
return nil, errors.Errorf("Cannot get Connection for ID %d, "+
"does not exist", id)
}
return c, nil
}
// delete deletes a Connection.
func (ct *connectionTracker) delete(id int) {
ct.mux.Lock()
defer ct.mux.Unlock()
delete(ct.connections, id)
}