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

Make singleton track groups rather than groupChat manager

parent 8d8c869b
Branches
Tags
2 merge requests!510Release,!320Make singleton track groups rather than groupChat manager
...@@ -22,57 +22,57 @@ import ( ...@@ -22,57 +22,57 @@ import (
) )
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Group Chat Singleton Tracker // // Group Singleton Tracker //
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// groupChatTrackerSingleton is used to track GroupChat objects so that they can be // groupTrackerSingleton is used to track Group objects so that they can be
// referenced by ID back over the bindings. // referenced by ID back over the bindings.
var groupChatTrackerSingleton = &groupChatTracker{ var groupTrackerSingleton = &groupTracker{
tracked: make(map[int]*GroupChat), tracked: make(map[int]*Group),
count: 0, count: 0,
} }
// groupChatTracker is a singleton used to keep track of extant GroupChat objects, // groupTracker is a singleton used to keep track of extant Group objects,
// preventing race conditions created by passing it over the bindings. // preventing race conditions created by passing it over the bindings.
type groupChatTracker struct { type groupTracker struct {
tracked map[int]*GroupChat tracked map[int]*Group
count int count int
mux sync.RWMutex mux sync.RWMutex
} }
// make create a GroupChat from a groupChat.Wrapper, assigns it a unique ID, and // make create a Group from a groupStore.Group, assigns it a unique ID, and
// adds it to the groupChatTracker. // adds it to the groupChatTracker.
func (ut *groupChatTracker) make(gcInt gc.GroupChat) *GroupChat { func (ut *groupTracker) make(g gs.Group) *Group {
ut.mux.Lock() ut.mux.Lock()
defer ut.mux.Unlock() defer ut.mux.Unlock()
id := ut.count id := ut.count
ut.count++ ut.count++
ut.tracked[id] = &GroupChat{ ut.tracked[id] = &Group{
m: gc.NewWrapper(gcInt), g: g,
id: id, id: id,
} }
return ut.tracked[id] return ut.tracked[id]
} }
// get an GroupChat from the groupChatTracker given its ID. // get a Group from the groupChatTracker given its ID.
func (ut *groupChatTracker) get(id int) (*GroupChat, error) { func (ut *groupTracker) get(id int) (*Group, error) {
ut.mux.RLock() ut.mux.RLock()
defer ut.mux.RUnlock() defer ut.mux.RUnlock()
c, exist := ut.tracked[id] g, exist := ut.tracked[id]
if !exist { if !exist {
return nil, errors.Errorf( return nil, errors.Errorf(
"Cannot get GroupChat for ID %d, does not exist", id) "Cannot get Group for ID %d, does not exist", id)
} }
return c, nil return g, nil
} }
// delete removes a GroupChat from the groupChatTracker. // delete removes a Group from the groupTracker.
func (ut *groupChatTracker) delete(id int) { func (ut *groupTracker) delete(id int) {
ut.mux.Lock() ut.mux.Lock()
defer ut.mux.Unlock() defer ut.mux.Unlock()
...@@ -86,32 +86,16 @@ func (ut *groupChatTracker) delete(id int) { ...@@ -86,32 +86,16 @@ func (ut *groupChatTracker) delete(id int) {
// GroupChat is a binding-layer group chat manager. // GroupChat is a binding-layer group chat manager.
type GroupChat struct { type GroupChat struct {
m *gc.Wrapper m *gc.Wrapper
id int
}
// GroupRequest is a bindings-layer interface that handles a group reception.
//
// Parameters:
// - payload - a byte serialized representation of a group.
type GroupRequest interface {
Callback(payload Group)
} }
// LoadOrNewGroupChat creates a bindings-layer group chat manager. // LoadOrNewGroupChat creates a bindings-layer group chat manager.
// //
// Parameters: // Parameters:
// - e2eID - e2e object ID in the tracker. // - e2eID - e2e object ID in the tracker.
// - groupID - GroupChat object ID in the tracker, given from previous call
// to LoadOrNewGroupChat.
// - requestFunc - a callback to handle group chat requests. // - requestFunc - a callback to handle group chat requests.
// - processor - the group chat message processor. // - processor - the group chat message processor.
func LoadOrNewGroupChat(e2eID, groupID int, requestFunc GroupRequest, func LoadOrNewGroupChat(e2eID int,
processor GroupChatProcessor) (*GroupChat, error) { requestFunc GroupRequest, processor GroupChatProcessor) (*GroupChat, error) {
// Retrieve from singleton
groupChat, err := groupChatTrackerSingleton.get(groupID)
if err == nil { // If present, return group chat manager from singleton
return groupChat, nil
}
// Get user from singleton // Get user from singleton
user, err := e2eTrackerSingleton.get(e2eID) user, err := e2eTrackerSingleton.get(e2eID)
...@@ -121,12 +105,8 @@ func LoadOrNewGroupChat(e2eID, groupID int, requestFunc GroupRequest, ...@@ -121,12 +105,8 @@ func LoadOrNewGroupChat(e2eID, groupID int, requestFunc GroupRequest,
// Construct a wrapper for the request callback // Construct a wrapper for the request callback
requestCb := func(g gs.Group) { requestCb := func(g gs.Group) {
//fixme: review this to see if should be json marshaled. newGroup := groupTrackerSingleton.make(g)
// At the moment, groupStore.DhKeyList is an unsupported requestFunc.Callback(newGroup.id)
// type, it would need a MarshalJson method. If we JSON marshal, change
// JoinGroup implementation and docstring accordingly.
// As for now, it's matching the construction as defined pre-restructure.
requestFunc.Callback(Group{g: g})
} }
// Construct a group chat manager // Construct a group chat manager
...@@ -137,12 +117,8 @@ func LoadOrNewGroupChat(e2eID, groupID int, requestFunc GroupRequest, ...@@ -137,12 +117,8 @@ func LoadOrNewGroupChat(e2eID, groupID int, requestFunc GroupRequest,
} }
// Construct wrapper // Construct wrapper
return groupChatTrackerSingleton.make(gcInt), nil wrapper := gc.NewWrapper(gcInt)
} return &GroupChat{m: wrapper}, nil
// GetID returns the groupChatTracker ID for the GroupChat object.
func (g *GroupChat) GetID() int {
return g.id
} }
// MakeGroup creates a new Group and sends a group request to all members in the // MakeGroup creates a new Group and sends a group request to all members in the
...@@ -226,9 +202,22 @@ func (g *GroupChat) ResendRequest(groupId []byte) ([]byte, error) { ...@@ -226,9 +202,22 @@ func (g *GroupChat) ResendRequest(groupId []byte) ([]byte, error) {
// JoinGroup allows a user to join a group when a request is received. // JoinGroup allows a user to join a group when a request is received.
// //
// Parameters: // Parameters:
// - group - a bindings-level Group object. This is received by GroupRequest.Callback. // - trackedGroupId - the ID to retrieve the Group object within the backend's
func (g *GroupChat) JoinGroup(group Group) error { // tracking system.
return g.m.JoinGroup(group.g) func (g *GroupChat) JoinGroup(trackedGroupId int) error {
// Retrieve group from singleton
grp, err := groupTrackerSingleton.get(trackedGroupId)
if err != nil {
return err
}
// Join group
err = g.m.JoinGroup(grp.g)
if err != nil {
return err
}
return nil
} }
// LeaveGroup deletes a group so a user no longer has access. // LeaveGroup deletes a group so a user no longer has access.
...@@ -288,26 +277,21 @@ func (g *GroupChat) GetGroups() ([]byte, error) { ...@@ -288,26 +277,21 @@ func (g *GroupChat) GetGroups() ([]byte, error) {
return json.Marshal(groupIds) return json.Marshal(groupIds)
} }
// GetGroup returns the group with the group ID. If no group exists, then the // GetGroup returns the Group with the tracked ID from the backend's Group tracker.
// error "failed to find group" is returned.
// //
// Parameters: // Parameters:
// - groupId - the byte data representing a group ID. // - trackedGroupId - the ID to retrieve the Group object within the backend's
// This can be pulled from a marshalled GroupReport. // tracking system.
// Returns: // Returns:
// - Group - the bindings-layer representation of a Group. // - Group - the bindings-layer representation of a group.
func (g *GroupChat) GetGroup(groupId []byte) (*Group, error) { func (g *GroupChat) GetGroup(trackedGroupId int) (*Group, error) {
groupID, err := id.Unmarshal(groupId) // Retrieve group from singleton
group, err := groupTrackerSingleton.get(trackedGroupId)
if err != nil { if err != nil {
return nil, errors.Errorf("Failed to unmarshal group ID: %+v", err) return nil, err
}
grp, exists := g.m.GetGroup(groupID)
if !exists {
return nil, errors.New("failed to find group")
} }
return &Group{g: grp}, nil return group, nil
} }
// NumGroups returns the number of groups the user is a part of. // NumGroups returns the number of groups the user is a part of.
...@@ -323,6 +307,7 @@ func (g *GroupChat) NumGroups() int { ...@@ -323,6 +307,7 @@ func (g *GroupChat) NumGroups() int {
// group chat. // group chat.
type Group struct { type Group struct {
g gs.Group g gs.Group
id int
} }
// GetName returns the name set by the user for the group. // GetName returns the name set by the user for the group.
...@@ -369,9 +354,18 @@ func (g *Group) Serialize() []byte { ...@@ -369,9 +354,18 @@ func (g *Group) Serialize() []byte {
} }
////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////
// Group Chat Processor // Callbacks
////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////
// GroupRequest is a bindings-layer interface that handles a group reception.
//
// Parameters:
// - trackedGroupId - the ID to retrieve the Group object within the backend's
// tracking system.
type GroupRequest interface {
Callback(trackedGroupId int)
}
// GroupChatProcessor manages the handling of received group chat messages. // GroupChatProcessor manages the handling of received group chat messages.
type GroupChatProcessor interface { type GroupChatProcessor interface {
Process(decryptedMessage, msg, receptionId []byte, ephemeralId, Process(decryptedMessage, msg, receptionId []byte, ephemeralId,
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment