diff --git a/bindings/ud.go b/bindings/ud.go index d167e145daf1e110bf0728cf13bc28c54287538a..5415f33d56c4893d6deb6338bb01ac7722c6405b 100644 --- a/bindings/ud.go +++ b/bindings/ud.go @@ -9,6 +9,7 @@ package bindings import ( "encoding/json" + "fmt" "github.com/pkg/errors" jww "github.com/spf13/jwalterweatherman" "gitlab.com/elixxir/client/single" @@ -420,6 +421,120 @@ func LookupUD(e2eID int, udContact []byte, cb UdLookupCallback, return json.Marshal(sr) } +//////////////////////////////////////////////////////////////////////////////// +// User Discovery Lookup // +//////////////////////////////////////////////////////////////////////////////// + +// UdMultiLookupCallback contains the callback called by MultiLookupUD that returns the +// contacts which match the passed in IDs. +// +// Parameters: +// - contactListJSON - the JSON marshalled bytes of []contact.Contact, or nil +// if an error occurs. +// +// JSON Example: +// { +// "<xxc(2)F8dL9EC6gy+RMJuk3R+Au6eGExo02Wfio5cacjBcJRwDEgB7Ugdw/BAr6RkCABkWAFV1c2VybmFtZTA7c4LzV05sG+DMt+rFB0NIJg==xxc>", +// "<xxc(2)eMhAi/pYkW5jCmvKE5ZaTglQb+fTo1D8NxVitr5CCFADEgB7Ugdw/BAr6RoCABkWAFV1c2VybmFtZTE7fElAa7z3IcrYrrkwNjMS2w==xxc>", +// "<xxc(2)d7RJTu61Vy1lDThDMn8rYIiKSe1uXA/RCvvcIhq5Yg4DEgB7Ugdw/BAr6RsCABkWAFV1c2VybmFtZTI7N3XWrxIUpR29atpFMkcR6A==xxc>" +// } +// - err - any errors that occurred in the multilookup. +type UdMultiLookupCallback interface { + Callback(contactListJSON []byte, err error) +} + +type lookupResp struct { + id *id.ID + contact contact.Contact + err error +} + +// MultiLookupUD returns the public key of all passed in IDs as known by the +// user discovery system or returns by the timeout. +// +// Parameters: +// - e2eID - e2e object ID in the tracker +// - udContact - the marshalled bytes of the contact.Contact object +// - lookupIds - JSON marshalled list of []*id.ID object for the users that +// MultiLookupUD will look up. +// - singleRequestParams - the JSON marshalled bytes of single.RequestParams +// +// Returns: +// - []byte - the JSON marshalled bytes of the SingleUseSendReport object, +// which can be passed into Cmix.WaitForRoundResult to see if the send +// succeeded. +func MultiLookupUD(e2eID int, udContact []byte, cb UdMultiLookupCallback, + lookupIds []byte, singleRequestParamsJSON []byte) error { + + // Get user from singleton + user, err := e2eTrackerSingleton.get(e2eID) + if err != nil { + return err + } + + c, err := contact.Unmarshal(udContact) + if err != nil { + return err + } + + var idList []*id.ID + err = json.Unmarshal(lookupIds, &idList) + if err != nil { + return err + } + + var p single.RequestParams + err = json.Unmarshal(singleRequestParamsJSON, &p) + if err != nil { + return err + } + + respCh := make(chan lookupResp, len(idList)) + for _, uid := range idList { + localID := uid.DeepCopy() + callback := func(c contact.Contact, err error) { + respCh <- lookupResp{ + id: localID, + contact: c, + err: err, + } + } + go func() { + _, _, err := ud.Lookup(user.api, c, callback, localID, p) + if err != nil { + respCh <- lookupResp{ + id: localID, + contact: contact.Contact{}, + err: err, + } + } + }() + + } + + go func() { + var contactList []contact.Contact + var errorString string + for numReturned := 0; numReturned < len(idList); numReturned++ { + response := <-respCh + if response.err != nil { + contactList = append(contactList, response.contact) + } else { + errorString = errorString + fmt.Sprintf("Failed to lookup id %s: %+v", response.id, response.err) + } + } + + marshalled, err := json.Marshal(contactList) + if err != nil { + cb.Callback(nil, err) + } else { + cb.Callback(marshalled, errors.New(errorString)) + } + }() + + return nil +} + //////////////////////////////////////////////////////////////////////////////// // User Discovery Search // ////////////////////////////////////////////////////////////////////////////////