diff --git a/bindings/follow.go b/bindings/follow.go index 08a9d0bffe2ed250c076b918c76926b0e2544cfa..f739033b9314b8764ad8bd0eeab83d04e8a079b7 100644 --- a/bindings/follow.go +++ b/bindings/follow.go @@ -28,28 +28,28 @@ import ( // they are stopped if there is no internet access. // // Threads Started: -// - Network Follower (/network/follow.go) -// tracks the network events and hands them off to workers for handling. -// - Historical Round Retrieval (/network/rounds/historical.go) -// retrieves data about rounds that are too old to be stored by the client. -// - Message Retrieval Worker Group (/network/rounds/retrieve.go) -// requests all messages in a given round from the gateway of the last nodes. -// - Message Handling Worker Group (/network/message/handle.go) -// decrypts and partitions messages when signals via the Switchboard. -// - Health Tracker (/network/health), -// via the network instance, tracks the state of the network. -// - Garbled Messages (/network/message/garbled.go) -// can be signaled to check all recent messages that could be decoded. It -// uses a message store on disk for persistence. -// - Critical Messages (/network/message/critical.go) -// ensures all protocol layer mandatory messages are sent. It 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. -// - Auth Callback (/auth/callback.go) -// handles both auth confirm and requests. +// - Network Follower (/network/follow.go) +// tracks the network events and hands them off to workers for handling. +// - Historical Round Retrieval (/network/rounds/historical.go) +// retrieves data about rounds that are too old to be stored by the client. +// - Message Retrieval Worker Group (/network/rounds/retrieve.go) +// requests all messages in a given round from the gateway of the last nodes. +// - Message Handling Worker Group (/network/message/handle.go) +// decrypts and partitions messages when signals via the Switchboard. +// - Health Tracker (/network/health), +// via the network instance, tracks the state of the network. +// - Garbled Messages (/network/message/garbled.go) +// can be signaled to check all recent messages that could be decoded. It +// uses a message store on disk for persistence. +// - Critical Messages (/network/message/critical.go) +// ensures all protocol layer mandatory messages are sent. It 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. +// - Auth Callback (/auth/callback.go) +// handles both auth confirm and requests. func (c *Cmix) StartNetworkFollower(timeoutMS int) error { timeout := time.Duration(timeoutMS) * time.Millisecond return c.api.StartNetworkFollower(timeout) @@ -106,10 +106,11 @@ func (c *Cmix) ReadyToSend() bool { // is to being ready. // // Example JSON: -// { -// "IsReady": true, -// "HowClose": 0.534 -// } +// +// { +// "IsReady": true, +// "HowClose": 0.534 +// } type IsReadyInfo struct { IsReady bool HowClose float64 @@ -117,9 +118,10 @@ type IsReadyInfo struct { // NetworkFollowerStatus gets the state of the network follower. It returns a // status with the following values: -// Stopped - 0 -// Running - 2000 -// Stopping - 3000 +// +// Stopped - 0 +// Running - 2000 +// Stopping - 3000 func (c *Cmix) NetworkFollowerStatus() int { return int(c.api.NetworkFollowerStatus()) } @@ -134,11 +136,11 @@ type NodeRegistrationReport struct { // GetNodeRegistrationStatus returns the current state of node registration. // // Returns: -// - []byte - A marshalled NodeRegistrationReport containing the number of -// nodes the user is registered with and the number of nodes present in the -// NDF. -// - An error if it cannot get the node registration status. The most likely -// cause is that the network is unhealthy. +// - []byte - A marshalled NodeRegistrationReport containing the number of +// nodes the user is registered with and the number of nodes present in the +// NDF. +// - An error if it cannot get the node registration status. The most likely +// cause is that the network is unhealthy. func (c *Cmix) GetNodeRegistrationStatus() ([]byte, error) { numNodesRegistered, numNodes, err := c.api.GetNodeRegistrationStatus() if err != nil { @@ -158,11 +160,11 @@ func (c *Cmix) GetNodeRegistrationStatus() ([]byte, error) { // be a percent (0-1) of node registrations completed. // // Parameters: -// - percentReady - The percentage of nodes required to be registered with to -// be ready. This is a number between 0 and 1. +// - percentReady - The percentage of nodes required to be registered with to +// be ready. This is a number between 0 and 1. // // Returns: -// - JSON of [IsReadyInfo]. +// - JSON of [IsReadyInfo]. func (c *Cmix) IsReady(percentReady float64) ([]byte, error) { isReady, howClose := c.api.IsReady(percentReady) return json.Marshal(&IsReadyInfo{isReady, howClose}) @@ -172,8 +174,8 @@ func (c *Cmix) IsReady(percentReady float64) ([]byte, error) { // resume them. // // Parameters: -// - timeoutMS - The timeout, in milliseconds, to wait when stopping threads -// before failing. +// - timeoutMS - The timeout, in milliseconds, to wait when stopping threads +// before failing. func (c *Cmix) PauseNodeRegistrations(timeoutMS int) error { timeout := time.Duration(timeoutMS) * time.Millisecond return c.api.PauseNodeRegistrations(timeout) @@ -183,9 +185,9 @@ func (c *Cmix) PauseNodeRegistrations(timeoutMS int) error { // registrations up to the initialized maximum. // // Parameters: -// - toRun - The number of parallel node registrations. -// - timeoutMS - The timeout, in milliseconds, to wait when changing node -// registrations before failing. +// - toRun - The number of parallel node registrations. +// - timeoutMS - The timeout, in milliseconds, to wait when changing node +// registrations before failing. func (c *Cmix) ChangeNumberOfNodeRegistrations(toRun, timeoutMS int) error { timeout := time.Duration(timeoutMS) * time.Millisecond return c.api.ChangeNumberOfNodeRegistrations(toRun, timeout) @@ -212,13 +214,14 @@ func (c *Cmix) IsHealthy() bool { // conditions if multiple threads are in the process of starting or stopping. // // Returns: -// - []byte - A JSON marshalled list of all running processes. +// - []byte - A JSON marshalled list of all running processes. // // JSON Example: -// { -// "FileTransfer{BatchBuilderThread, FilePartSendingThread#0, FilePartSendingThread#1, FilePartSendingThread#2, FilePartSendingThread#3}", -// "MessageReception Worker 0" -// } +// +// { +// "FileTransfer{BatchBuilderThread, FilePartSendingThread#0, FilePartSendingThread#1, FilePartSendingThread#2, FilePartSendingThread#3}", +// "MessageReception Worker 0" +// } func (c *Cmix) GetRunningProcesses() ([]byte, error) { return json.Marshal(c.api.GetRunningProcesses()) } @@ -262,45 +265,74 @@ func (c *Cmix) RegisterClientErrorCallback(clientError ClientError) { // there is an error for the second parameter which will be non-null. // // Parameters: -// - marshalData - JSON marshalled bytes of [message.ServiceList], which is an -// array of [id.ID] and [message.Service]. -// - err - JSON unmarshalling error +// - marshalData - JSON marshalled bytes of [message.ServiceList], which is an +// array of [id.ID] and [message.Service]. +// - err - JSON unmarshalling error // // Example JSON: -// [ -// { -// "Id": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD", // bytes of id.ID encoded as base64 string -// "Services": [ -// { -// "Identifier": "AQID", // bytes encoded as base64 string -// "Tag": "TestTag 1", // string -// "Metadata": "BAUG" // bytes encoded as base64 string -// } -// ] -// }, -// { -// "Id": "AAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD", -// "Services": [ -// { -// "Identifier": "AQID", -// "Tag": "TestTag 2", -// "Metadata": "BAUG" -// } -// ] -// }, -// ] +// +// [ +// { +// "Id": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD", // bytes of id.ID encoded as base64 string +// "Services": [ +// { +// "Identifier": "AQID", // bytes encoded as base64 string +// "Tag": "TestTag 1", // string +// "Metadata": "BAUG" // bytes encoded as base64 string +// } +// ] +// }, +// { +// "Id": "AAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD", +// "Services": [ +// { +// "Identifier": "AQID", +// "Tag": "TestTag 2", +// "Metadata": "BAUG" +// } +// ] +// }, +// ] type TrackServicesCallback interface { Callback(marshalData []byte, err error) } +// TrackServicesWithIdentity will return via a callback the list of services the +// backend keeps track of for the provided identity. This may be passed into +// other bindings call which may need context on the available services for this +// single identity. This will only return services for the given identity. +// +// Parameters: +// - e2eID - e2e object ID in the tracker. +// - cb - A TrackServicesCallback, which will be passed the marshalled +// message.ServiceList. +func (c *Cmix) TrackServicesWithIdentity(e2eId int, + cb TrackServicesCallback) error { + // Retrieve the user from the tracker + user, err := e2eTrackerSingleton.get(e2eId) + if err != nil { + return err + } + + receptionId := user.api.GetReceptionIdentity().ID + c.api.GetCmix().TrackServices(func(list message.ServiceList) { + res := make(message.ServiceList) + res[*receptionId] = list[*receptionId] + cb.Callback(json.Marshal(res)) + }) + + return nil +} + // TrackServices will return via a callback the list of services the // backend keeps track of, which is formally referred to as a // [message.ServiceList]. This may be passed into other bindings call which -// may need context on the available services for this client. +// may need context on the available services for this client. This will +// provide services for all identities that the client tracks. // // Parameters: -// - cb - A TrackServicesCallback, which will be passed the marshalled -// message.ServiceList. +// - cb - A TrackServicesCallback, which will be passed the marshalled +// message.ServiceList. func (c *Cmix) TrackServices(cb TrackServicesCallback) { c.api.GetCmix().TrackServices(func(list message.ServiceList) { cb.Callback(json.Marshal(list)) diff --git a/bindings/notifications.go b/bindings/notifications.go index 217accf1163a6d12d426a0ebd90f6902f9e05244..79f9cc5110764ff1b86cd6451e22650f8e7a577a 100644 --- a/bindings/notifications.go +++ b/bindings/notifications.go @@ -17,23 +17,24 @@ import ( // via GetNotificationsReport as a JSON marshalled byte data. // // Example JSON: -// [ -// { -// "ForMe": true, // boolean -// "Type": "e2e", // string -// "Source": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD" // bytes of id.ID encoded as base64 string -// }, -// { -// "ForMe": true, -// "Type": "e2e", -// "Source": "AAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD" -// }, -// { -// "ForMe": true, -// "Type": "e2e", -// "Source": "AAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD" -// } -// ] +// +// [ +// { +// "ForMe": true, // boolean +// "Type": "e2e", // string +// "Source": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD" // bytes of id.ID encoded as base64 string +// }, +// { +// "ForMe": true, +// "Type": "e2e", +// "Source": "AAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD" +// }, +// { +// "ForMe": true, +// "Type": "e2e", +// "Source": "AAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD" +// } +// ] type NotificationReports []NotificationReport // TODO: The table in the docstring below needs to be checked for completeness @@ -44,27 +45,28 @@ type NotificationReports []NotificationReport // this user. // // Example NotificationReport JSON: -// { -// "ForMe": true, -// "Type": "e2e", -// "Source": "dGVzdGVyMTIzAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" -// } +// +// { +// "ForMe": true, +// "Type": "e2e", +// "Source": "dGVzdGVyMTIzAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" +// } // // Given the Type, the Source value will have specific contextual meanings. // Below is a table that will define the contextual meaning of the Source field // given all possible Type fields. // -// TYPE | SOURCE | DESCRIPTION -// ----------+--------------------+-------------------------------------------------------- -// "default" | recipient user ID | A message with no association. -// "request" | sender user ID | A channel request has been received, from Source. -// "reset" | sender user ID | A channel reset has been received. -// "confirm" | sender user ID | A channel request has been accepted. -// "silent" | sender user ID | A message where the user should not be notified. -// "e2e" | sender user ID | A reception of an E2E message. -// "group" | group ID | A reception of a group chat message. -// "endFT" | sender user ID | The last message sent confirming end of file transfer. -// "groupRQ" | sender user ID | A request from Source to join a group chat. +// TYPE | SOURCE | DESCRIPTION +// ----------+--------------------+-------------------------------------------------------- +// "default" | recipient user ID | A message with no association. +// "request" | sender user ID | A channel request has been received, from Source. +// "reset" | sender user ID | A channel reset has been received. +// "confirm" | sender user ID | A channel request has been accepted. +// "silent" | sender user ID | A message where the user should not be notified. +// "e2e" | sender user ID | A reception of an E2E message. +// "group" | group ID | A reception of a group chat message. +// "endFT" | sender user ID | The last message sent confirming end of file transfer. +// "groupRQ" | sender user ID | A request from Source to join a group chat. type NotificationReport struct { // ForMe determines whether this value is for the user. If it is // false, this report may be ignored. @@ -80,33 +82,27 @@ type NotificationReport struct { // NotificationReports. // // Parameters: -// - e2eID - e2e object ID in the tracker -// - notificationCSV - the notification data received from the -// notifications' server. -// - marshalledServices - the JSON-marshalled list of services the backend -// keeps track of. Refer to Cmix.TrackServices for information about this. +// - notificationCSV - the notification data received from the +// notifications' server. +// - marshalledServices - the JSON-marshalled list of services the backend +// keeps track of. Refer to Cmix.TrackServices or +// Cmix.TrackServicesWithIdentity for information about this. // // Returns: -// - []byte - A JSON marshalled NotificationReports. Some NotificationReport's -// within in this structure may have their NotificationReport.ForMe -// set to false. These may be ignored. -func GetNotificationsReport(e2eId int, notificationCSV string, +// - []byte - A JSON marshalled NotificationReports. Some NotificationReport's +// within in this structure may have their NotificationReport.ForMe +// set to false. These may be ignored. +func GetNotificationsReport(notificationCSV string, marshalledServices []byte) ([]byte, error) { - // Retrieve user - user, err := e2eTrackerSingleton.get(e2eId) - if err != nil { - return nil, err - } + // If services are retrieved using TrackServicesWithIdentity, this + // should return a single list. serviceList := message.ServiceList{} - err = json.Unmarshal(marshalledServices, &serviceList) + err := json.Unmarshal(marshalledServices, &serviceList) if err != nil { return nil, err } - // Retrieve the services for this user - services := serviceList[*user.api.GetReceptionIdentity().ID] - // Decode notifications' server data notificationList, err := notifications.DecodeNotificationsCSV(notificationCSV) if err != nil { @@ -117,24 +113,26 @@ func GetNotificationsReport(e2eId int, notificationCSV string, reportList := make([]*NotificationReport, len(notificationList)) // Iterate over data provided by server - for i := range notificationList { - notifData := notificationList[i] - - // Iterate over all services - for j := range services { - // Pull data from services and from notification data - service := services[j] - messageHash := notifData.MessageHash - hash := service.HashFromMessageHash(notifData.MessageHash) - - // Check if this notification data is recognized by - // this service, ie "ForMe" - if service.ForMeFromMessageHash(messageHash, hash) { - // Fill report list with service data - reportList[i] = &NotificationReport{ - ForMe: true, - Type: service.Tag, - Source: service.Identifier, + for _, services := range serviceList { + for i := range notificationList { + notifData := notificationList[i] + + // Iterate over all services + for j := range services { + // Pull data from services and from notification data + service := services[j] + messageHash := notifData.MessageHash + hash := service.HashFromMessageHash(notifData.MessageHash) + + // Check if this notification data is recognized by + // this service, ie "ForMe" + if service.ForMeFromMessageHash(messageHash, hash) { + // Fill report list with service data + reportList[i] = &NotificationReport{ + ForMe: true, + Type: service.Tag, + Source: service.Identifier, + } } } } @@ -147,7 +145,7 @@ func GetNotificationsReport(e2eId int, notificationCSV string, // The token is a firebase messaging token. // // Parameters: -// - e2eId - ID of the E2E object in the E2E tracker +// - e2eId - ID of the E2E object in the E2E tracker func RegisterForNotifications(e2eId int, token string) error { user, err := e2eTrackerSingleton.get(e2eId) if err != nil { @@ -160,7 +158,7 @@ func RegisterForNotifications(e2eId int, token string) error { // UnregisterForNotifications turns off notifications for this client. // // Parameters: -// - e2eId - ID of the E2E object in the E2E tracker +// - e2eId - ID of the E2E object in the E2E tracker func UnregisterForNotifications(e2eId int) error { user, err := e2eTrackerSingleton.get(e2eId) if err != nil {