Skip to content
Snippets Groups Projects
Commit b5c88b43 authored by Josh Brooks's avatar Josh Brooks
Browse files

WIP: Implement Notifications for bindings

parent 4cd1cdce
No related branches found
No related tags found
Loading
...@@ -7,67 +7,130 @@ ...@@ -7,67 +7,130 @@
package bindings package bindings
// FIXME: This is the old NotificationsForMe code that needs to be fixed import (
/* "encoding/json"
type NotificationForMeReport struct { "gitlab.com/elixxir/primitives/notifications"
ForMe bool )
Type string
Source []byte // NotificationReports is a list of NotificationReport's. This will be returned
} // via NotificationsForMe as a JSON marshalled byte data.
//
// Example JSON:
//
// [
// {
// "ForMe": true,
// "Type": "e2e",
// "Source": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD"
// },
// {
// "ForMe": true,
// "Type": "e2e",
// "Source": "AAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD"
// },
// {
// "ForMe": true,
// "Type": "e2e",
// "Source": "AAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD"
// }
//]
type NotificationReports []NotificationReport
type ManyNotificationForMeReport struct { // NotificationReport is the bindings' representation for notifications for
Many []*NotificationForMeReport // this user.
//
// Example NotificationReport JSON:
//
// {
// "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.
// todo iterate over this docstring, ensure descriptions/sources are accurate
type NotificationReport struct {
// ForMe determines whether this value is for the user. If it is
// false, this report may be ignored.
ForMe bool
// Type is the type of notification. The list can be seen
Type string
// Source is the source of the notification.
Source []byte
} }
// NotificationsForMe Check if a notification received is for me // NotificationsForMe parses the received notification data to determine which
// It returns a NotificationForMeReport which contains a ForMe bool stating if it is for the caller, // notifications are for this user. // This returns the JSON-marshalled
// a Type, and a source. These are as follows: // NotificationReports.
// TYPE SOURCE DESCRIPTION //
// "default" recipient user ID A message with no association // Parameters:
// "request" sender user ID A channel request has been received // - e2eID - e2e object ID in the tracker
// "reset" sender user ID A channel reset has been received // - notificationCSV - the notification data received from the
// "confirm" sender user ID A channel request has been accepted // notifications' server.
// "silent" sender user ID A message which should not be notified on //
// "e2e" sender user ID reception of an E2E message // Returns:
// "group" group ID reception of a group chat message // - []byte - A JSON marshalled NotificationReports. Some NotificationReport's
// "endFT" sender user ID Last message sent confirming end of file transfer // within in this structure may have their NotificationReport.ForMe
// "groupRQ" sender user ID Request from sender to join a group chat // set to false. These may be ignored.
func NotificationsForMe(notifCSV, preimages string) (*ManyNotificationForMeReport, error) { func NotificationsForMe(e2eId int, notificationCSV string) ([]byte, error) {
// Handle deserialization of preimages // Retrieve user
var preimageList []edge.Preimage user, err := e2eTrackerSingleton.get(e2eId)
if err := json.Unmarshal([]byte(preimages), &preimageList); err != nil { if err != nil {
return nil, errors.WithMessagef(err, "Failed to unmarshal the " + return nil, err
"preimages list, cannot check if notification is for me")
} }
list, err := notifications.DecodeNotificationsCSV(notifCSV) // Retrieve the services for this user
serviceMap := user.api.GetCmix().GetServices()
services := serviceMap[*user.api.GetReceptionIdentity().ID]
// Decode notifications' server data
notificationList, err := notifications.DecodeNotificationsCSV(notificationCSV)
if err != nil { if err != nil {
return nil, err return nil, err
} }
notifList := make([]*NotificationForMeReport, len(list)) // Construct a report list
reportList := make([]*NotificationReport, len(notificationList))
for i, notifData := range list { // Iterate over data provided by server
notifList[i] = &NotificationForMeReport{ for i := range notificationList {
ForMe: false, notifData := notificationList[i]
Type: "",
Source: nil, // Iterate over all services
} for j := range services {
// check if any preimages match with the passed in data // Pull data from services and from notification data
for _, preimage := range preimageList { service := services[j]
if fingerprint.CheckIdentityFpFromMessageHash(notifData.IdentityFP, notifData.MessageHash, preimage.Data) { messageHash := notifData.MessageHash
notifList[i] = &NotificationForMeReport{ 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, ForMe: true,
Type: preimage.Type, Type: service.Tag,
Source: preimage.Source, Source: service.Identifier,
} }
break
} }
} }
} }
return &ManyNotificationForMeReport{notifList}, nil return json.Marshal(reportList)
}*/ }
// RegisterForNotifications allows a client to register for push notifications. // RegisterForNotifications allows a client to register for push notifications.
// The token is a firebase messaging token. // The token is a firebase messaging token.
......
package bindings
import (
"encoding/json"
"fmt"
"gitlab.com/elixxir/client/e2e/ratchet"
"gitlab.com/xx_network/primitives/id"
"testing"
)
func TestNotificationReport(t *testing.T) {
reports := []NotificationReport{}
for i := 0; i < 3; i++ {
nr := NotificationReport{
ForMe: true,
Type: ratchet.E2e,
Source: id.NewIdFromUInt(uint64(i), id.User, t).Bytes(),
}
reports = append(reports, nr)
}
nrs := NotificationReports(reports)
marshal, _ := json.Marshal(nrs)
fmt.Printf("%s\n", marshal)
}
...@@ -176,6 +176,9 @@ type Client interface { ...@@ -176,6 +176,9 @@ type Client interface {
// running. Multiple trackTriggers can be registered. // running. Multiple trackTriggers can be registered.
TrackServices(tracker message.ServicesTracker) TrackServices(tracker message.ServicesTracker)
// GetServices retrieves the message.ServiceList.
GetServices() message.ServiceList
/* === In inProcess ===================================================== */ /* === In inProcess ===================================================== */
/* It is possible to receive a message over cMix before the fingerprints or /* It is possible to receive a message over cMix before the fingerprints or
triggers are registered. As a result, when handling fails, messages are triggers are registered. As a result, when handling fails, messages are
......
...@@ -43,6 +43,7 @@ type Handler interface { ...@@ -43,6 +43,7 @@ type Handler interface {
DeleteService(clientID *id.ID, toDelete Service, response Processor) DeleteService(clientID *id.ID, toDelete Service, response Processor)
DeleteClientService(clientID *id.ID) DeleteClientService(clientID *id.ID)
TrackServices(triggerTracker ServicesTracker) TrackServices(triggerTracker ServicesTracker)
GetServices() ServiceList
} }
type handler struct { type handler struct {
......
...@@ -20,13 +20,17 @@ func (sm *ServicesManager) TrackServices(tracker ServicesTracker) { ...@@ -20,13 +20,17 @@ func (sm *ServicesManager) TrackServices(tracker ServicesTracker) {
sm.trackers = append(sm.trackers, tracker) sm.trackers = append(sm.trackers, tracker)
} }
// triggerServiceTracking triggers the tracking of services. Is it called when a // GetServices retrieves the ServiceList from the ServicesManager.
// service is added or removed. // This is effectively a serializing of the
func (sm *ServicesManager) triggerServiceTracking() { // ServicesManager's internal tmap.
if len(sm.trackers) == 0 { func (sm *ServicesManager) GetServices() ServiceList {
return sm.Mutex.Lock()
} defer sm.Mutex.Unlock()
return sm.getServices()
}
// getServices is the non-thread-safe version of GetServices.
func (sm *ServicesManager) getServices() ServiceList {
services := make(ServiceList) services := make(ServiceList)
for uid, tmap := range sm.tmap { for uid, tmap := range sm.tmap {
tList := make([]Service, 0, len(tmap)) tList := make([]Service, 0, len(tmap))
...@@ -35,6 +39,18 @@ func (sm *ServicesManager) triggerServiceTracking() { ...@@ -35,6 +39,18 @@ func (sm *ServicesManager) triggerServiceTracking() {
} }
services[uid] = tList services[uid] = tList
} }
return services
}
// triggerServiceTracking triggers the tracking of services. Is it called when a
// service is added or removed.
func (sm *ServicesManager) triggerServiceTracking() {
sm.Mutex.Lock()
if len(sm.trackers) == 0 {
return
}
services := sm.GetServices()
sm.Mutex.Unlock()
for _, callback := range sm.trackers { for _, callback := range sm.trackers {
go callback(services) go callback(services)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment