Skip to content
Snippets Groups Projects
Select Git revision
  • 930e66a05c1ac490d92dbb060cbef2a211133e78
  • release default protected
  • 11-22-implement-kv-interface-defined-in-collectiveversionedkvgo
  • hotfix/TestHostPool_UpdateNdf_AddFilter
  • XX-4719/announcementChannels
  • xx-4717/logLevel
  • jonah/noob-channel
  • master protected
  • XX-4707/tagDiskJson
  • xx-4698/notification-retry
  • hotfix/notifylockup
  • syncNodes
  • hotfix/localCB
  • XX-4677/NewChanManagerMobile
  • XX-4689/DmSync
  • duplicatePrefix
  • XX-4601/HavenInvites
  • finalizedUICallbacks
  • XX-4673/AdminKeySync
  • debugNotifID
  • anne/test
  • v4.7.5
  • v4.7.4
  • v4.7.3
  • v4.7.2
  • v4.7.1
  • v4.6.3
  • v4.6.1
  • v4.5.0
  • v4.4.4
  • v4.3.11
  • v4.3.8
  • v4.3.7
  • v4.3.6
  • v4.3.5
  • v4.2.0
  • v4.3.0
  • v4.3.4
  • v4.3.3
  • v4.3.2
  • v4.3.1
41 results

single.go

  • single.go 8.43 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"
    
    	"gitlab.com/elixxir/client/cmix/identity/receptionID"
    	"gitlab.com/elixxir/client/cmix/rounds"
    	"gitlab.com/elixxir/client/single"
    	"gitlab.com/elixxir/crypto/contact"
    	"gitlab.com/xx_network/primitives/id"
    )
    
    ////////////////////////////////////////////////////////////////////////////////
    // Public Wrapper Methods                                                     //
    ////////////////////////////////////////////////////////////////////////////////
    
    // TransmitSingleUse transmits payload to recipient via single-use.
    //
    // Parameters:
    //  - e2eID - ID of the e2e object in the tracker
    //  - recipient - marshalled contact.Contact object
    //  - tag - identifies the single-use message
    //  - payload - message contents
    //  - paramsJSON - JSON marshalled single.RequestParams
    //  - responseCB - the callback that will be called when a response is received
    //
    // Returns:
    //  - []byte - the JSON marshalled bytes of the SingleUseSendReport object,
    //    which can be passed into WaitForRoundResult to see if the send succeeded.
    func TransmitSingleUse(e2eID int, recipient []byte, tag string, payload,
    	paramsJSON []byte, responseCB SingleUseResponse) ([]byte, error) {
    	e2eCl, err := e2eTrackerSingleton.get(e2eID)
    	if err != nil {
    		return nil, err
    	}
    
    	recipientContact, err := contact.Unmarshal(recipient)
    	if err != nil {
    		return nil, err
    	}
    
    	rcb := &singleUseResponse{response: responseCB}
    
    	params, err := parseSingleUseParams(paramsJSON)
    	if err != nil {
    		return nil, err
    	}
    
    	rids, eid, err := single.TransmitRequest(recipientContact, tag, payload,
    		rcb, params, e2eCl.api.GetCmix(), e2eCl.api.GetRng().GetStream(),
    		e2eCl.api.GetStorage().GetE2EGroup())
    
    	if err != nil {
    		return nil, err
    	}
    	sr := SingleUseSendReport{
    		EphID:       eid.EphId.Int64(),
    		ReceptionID: eid.Source,
    		RoundsList:  makeRoundsList(rids...),
    		RoundURL:    getRoundURL(rids[0]),
    	}
    	return json.Marshal(sr)
    }
    
    // Listen starts a single-use listener on a given tag using the passed in E2e
    // object and SingleUseCallback func.
    //
    // Parameters:
    //  - e2eID - ID of the e2e object in the tracker
    //  - tag - identifies the single-use message
    //  - cb - the callback that will be called when a response is received
    //
    // Returns:
    //  - Stopper - an interface containing a function used to stop the listener
    func Listen(e2eID int, tag string, cb SingleUseCallback) (Stopper, error) {
    	e2eCl, err := e2eTrackerSingleton.get(e2eID)
    	if err != nil {
    		return nil, err
    	}
    
    	suListener := singleUseListener{scb: cb}
    	dhPk, err := e2eCl.api.GetReceptionIdentity().GetDHKeyPrivate()
    	if err != nil {
    		return nil, err
    	}
    	l := single.Listen(tag, e2eCl.api.GetReceptionIdentity().ID, dhPk,
    		e2eCl.api.GetCmix(), e2eCl.api.GetStorage().GetE2EGroup(), suListener)
    	return &stopper{l: l}, nil
    }
    
    // JSON Types
    
    // SingleUseSendReport is the bindings-layer struct used to represent
    // information returned by single.TransmitRequest.
    //
    // SingleUseSendReport JSON example:
    //  {
    //   "Rounds":[1,5,9],
    //   "RoundURL": "https://dashboard.xx.network/rounds/25?xxmessenger=true",
    //   "EphID":1655533,
    //   "ReceptionID":"emV6aW1hAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD"}
    //  }
    type SingleUseSendReport struct {
    	RoundsList
    	RoundURL    string
    	ReceptionID *id.ID
    	EphID       int64
    }
    
    // SingleUseResponseReport is the bindings-layer struct used to represent
    // information passed to the single.Response callback interface in response to
    // single.TransmitRequest.
    //
    // SingleUseResponseReport JSON example:
    //  {
    //   "Rounds":[1,5,9],
    //   "RoundURL": "https://dashboard.xx.network/rounds/25?xxmessenger=true",
    //   "Payload":"rSuPD35ELWwm5KTR9ViKIz/r1YGRgXIl5792SF8o8piZzN6sT4Liq4rUU/nfOPvQEjbfWNh/NYxdJ72VctDnWw==",
    //   "EphID":1655533,
    //   "ReceptionID":"emV6aW1hAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD"},
    //   "Err":"",
    //  }
    type SingleUseResponseReport struct {
    	RoundsList
    	RoundURL    string
    	Payload     []byte
    	ReceptionID *id.ID
    	EphID       int64
    	Err         error
    }
    
    // SingleUseCallbackReport is the bindings-layer struct used to represent
    // single -use messages received by a callback passed into single.Listen.
    //
    // SingleUseCallbackReport JSON example:
    //    {
    //      "Rounds":[1,5,9],
    //      "RoundURL": "https://dashboard.xx.network/rounds/25?xxmessenger=true",
    //      "Payload":"rSuPD35ELWwm5KTR9ViKIz/r1YGRgXIl5792SF8o8piZzN6sT4Liq4rUU/nfOPvQEjbfWNh/NYxdJ72VctDnWw==",
    //      "Partner":"emV6aW1hAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD",
    //      "EphID":1655533,
    //      "ReceptionID":"emV6aW1hAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD"}
    //    }
    type SingleUseCallbackReport struct {
    	RoundsList
    	RoundURL    string
    	Payload     []byte
    	Partner     *id.ID
    	EphID       int64
    	ReceptionID *id.ID
    }
    
    ////////////////////////////////////////////////////////////////////////////////
    // Function Types                                                             //
    ////////////////////////////////////////////////////////////////////////////////
    
    // Stopper is a public interface returned by Listen, allowing users to stop the
    // registered listener.
    type Stopper interface {
    	Stop()
    }
    
    // SingleUseCallback func is passed into Listen and called when messages are
    // received.
    //
    // Parameters:
    //  - callbackReport - the JSON marshalled bytes of the SingleUseCallbackReport
    //    object, which can be passed into Cmix.WaitForRoundResult to see if the
    //    send operation succeeded.
    type SingleUseCallback interface {
    	Callback(callbackReport []byte, err error)
    }
    
    // SingleUseResponse is the public facing callback function passed by bindings
    // clients into TransmitSingleUse.
    //
    // Parameters:
    //  - callbackReport - the JSON marshalled bytes of the SingleUseResponseReport
    //    object, which can be passed into Cmix.WaitForRoundResult to see if the
    //    send operation succeeded.
    type SingleUseResponse interface {
    	Callback(responseReport []byte, err error)
    }
    
    ////////////////////////////////////////////////////////////////////////////////
    // Callback Wrappers                                                          //
    ////////////////////////////////////////////////////////////////////////////////
    
    /* Listener Struct */
    
    // singleUseListener is the internal struct used to wrap a SingleUseCallback
    // function, which matches the single.Receiver interface.
    type singleUseListener struct {
    	scb SingleUseCallback
    }
    
    // Callback is called whenever a single-use message is heard by the listener
    // and translates the info to a SingleUseCallbackReport that is marshalled and
    // passed to bindings.
    func (sl singleUseListener) Callback(
    	req *single.Request, eid receptionID.EphemeralIdentity, rl []rounds.Round) {
    	var rids []id.Round
    	for _, r := range rl {
    		rids = append(rids, r.ID)
    	}
    
    	// Todo: what other info from req needs to get to bindings
    	scr := SingleUseCallbackReport{
    		Payload:     req.GetPayload(),
    		RoundsList:  makeRoundsList(rids...),
    		RoundURL:    getRoundURL(rids[0]),
    		Partner:     req.GetPartner(),
    		EphID:       eid.EphId.Int64(),
    		ReceptionID: eid.Source,
    	}
    
    	sl.scb.Callback(json.Marshal(scr))
    }
    
    /* Listener stopper */
    
    // stopper is the internal struct backing the Stopper interface, allowing us
    // to pass the listener Stop method to the bindings layer.
    type stopper struct {
    	l single.Listener
    }
    
    func (s *stopper) Stop() {
    	s.l.Stop()
    }
    
    /* Response Struct */
    
    // singleUseResponse is the private struct backing SingleUseResponse, which
    // subscribes to the single.Response interface.
    type singleUseResponse struct {
    	response SingleUseResponse
    }
    
    // Callback builds a SingleUseSendReport and passes the JSON marshalled version
    // into the callback.
    func (sr singleUseResponse) Callback(payload []byte,
    	receptionID receptionID.EphemeralIdentity, rounds []rounds.Round, err error) {
    	var rids []id.Round
    	for _, r := range rounds {
    		rids = append(rids, r.ID)
    	}
    	sendReport := SingleUseResponseReport{
    		RoundsList:  makeRoundsList(rids...),
    		RoundURL:    getRoundURL(rids[0]),
    		ReceptionID: receptionID.Source,
    		EphID:       receptionID.EphId.Int64(),
    		Payload:     payload,
    		Err:         err,
    	}
    	sr.response.Callback(json.Marshal(&sendReport))
    }