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
2 merge requests!510Release,!360Implement Notifications for bindings
......@@ -7,67 +7,130 @@
package bindings
// FIXME: This is the old NotificationsForMe code that needs to be fixed
/*
type NotificationForMeReport struct {
ForMe bool
Type string
Source []byte
}
import (
"encoding/json"
"gitlab.com/elixxir/primitives/notifications"
)
// 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 {
Many []*NotificationForMeReport
// NotificationReport is the bindings' representation for notifications for
// 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
// It returns a NotificationForMeReport which contains a ForMe bool stating if it is for the caller,
// a Type, and a source. These are as follows:
// TYPE SOURCE DESCRIPTION
// "default" recipient user ID A message with no association
// "request" sender user ID A channel request has been received
// "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 which should not be notified on
// "e2e" sender user ID reception of an E2E message
// "group" group ID reception of a group chat message
// "endFT" sender user ID Last message sent confirming end of file transfer
// "groupRQ" sender user ID Request from sender to join a group chat
func NotificationsForMe(notifCSV, preimages string) (*ManyNotificationForMeReport, error) {
// Handle deserialization of preimages
var preimageList []edge.Preimage
if err := json.Unmarshal([]byte(preimages), &preimageList); err != nil {
return nil, errors.WithMessagef(err, "Failed to unmarshal the " +
"preimages list, cannot check if notification is for me")
// NotificationsForMe parses the received notification data to determine which
// notifications are for this user. // This returns the JSON-marshalled
// NotificationReports.
//
// Parameters:
// - e2eID - e2e object ID in the tracker
// - notificationCSV - the notification data received from the
// notifications' server.
//
// 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 NotificationsForMe(e2eId int, notificationCSV string) ([]byte, error) {
// Retrieve user
user, err := e2eTrackerSingleton.get(e2eId)
if err != nil {
return nil, err
}
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 {
return nil, err
}
notifList := make([]*NotificationForMeReport, len(list))
// Construct a report list
reportList := make([]*NotificationReport, len(notificationList))
for i, notifData := range list {
notifList[i] = &NotificationForMeReport{
ForMe: false,
Type: "",
Source: nil,
}
// check if any preimages match with the passed in data
for _, preimage := range preimageList {
if fingerprint.CheckIdentityFpFromMessageHash(notifData.IdentityFP, notifData.MessageHash, preimage.Data) {
notifList[i] = &NotificationForMeReport{
// 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: preimage.Type,
Source: preimage.Source,
Type: service.Tag,
Source: service.Identifier,
}
break
}
}
}
return &ManyNotificationForMeReport{notifList}, nil
}*/
return json.Marshal(reportList)
}
// RegisterForNotifications allows a client to register for push notifications.
// 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 {
// running. Multiple trackTriggers can be registered.
TrackServices(tracker message.ServicesTracker)
// GetServices retrieves the message.ServiceList.
GetServices() message.ServiceList
/* === In inProcess ===================================================== */
/* It is possible to receive a message over cMix before the fingerprints or
triggers are registered. As a result, when handling fails, messages are
......
......@@ -43,6 +43,7 @@ type Handler interface {
DeleteService(clientID *id.ID, toDelete Service, response Processor)
DeleteClientService(clientID *id.ID)
TrackServices(triggerTracker ServicesTracker)
GetServices() ServiceList
}
type handler struct {
......
......@@ -20,13 +20,17 @@ func (sm *ServicesManager) TrackServices(tracker ServicesTracker) {
sm.trackers = append(sm.trackers, tracker)
}
// triggerServiceTracking triggers the tracking of services. Is it called when a
// service is added or removed.
func (sm *ServicesManager) triggerServiceTracking() {
if len(sm.trackers) == 0 {
return
}
// GetServices retrieves the ServiceList from the ServicesManager.
// This is effectively a serializing of the
// ServicesManager's internal tmap.
func (sm *ServicesManager) GetServices() ServiceList {
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)
for uid, tmap := range sm.tmap {
tList := make([]Service, 0, len(tmap))
......@@ -35,6 +39,18 @@ func (sm *ServicesManager) triggerServiceTracking() {
}
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 {
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