Skip to content
Snippets Groups Projects
Commit d5347ea1 authored by Jake Taylor's avatar Jake Taylor :lips:
Browse files

Merge branch 'hotfix/FixGroupChatBindings' into 'release'

Make singleton track groups rather than groupChat manager

See merge request !320
parents 8d8c869b 1c653f0c
No related branches found
No related tags found
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. // NewGroupChat 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 NewGroupChat(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)
// 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
...@@ -224,11 +200,26 @@ func (g *GroupChat) ResendRequest(groupId []byte) ([]byte, error) { ...@@ -224,11 +200,26 @@ 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.
// If an error is returned, handle it properly first; you may then retry later
// with the same trackedGroupId.
// //
// 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. This is received by GroupRequest.Callback.
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.
...@@ -292,22 +283,25 @@ func (g *GroupChat) GetGroups() ([]byte, error) { ...@@ -292,22 +283,25 @@ func (g *GroupChat) GetGroups() ([]byte, error) {
// error "failed to find group" is returned. // error "failed to find group" is returned.
// //
// Parameters: // Parameters:
// - groupId - the byte data representing a group ID. // - groupId - The byte data representing a group ID (a byte marshalled id.ID).
// This can be pulled from a marshalled GroupReport. // This can be pulled from a marshalled GroupReport.
// 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(groupId []byte) (*Group, error) {
// Unmarshal group ID
groupID, err := id.Unmarshal(groupId) groupID, err := id.Unmarshal(groupId)
if err != nil { if err != nil {
return nil, errors.Errorf("Failed to unmarshal group ID: %+v", err) return nil, errors.Errorf("Failed to unmarshal group ID: %+v", err)
} }
// Retrieve group from manager
grp, exists := g.m.GetGroup(groupID) grp, exists := g.m.GetGroup(groupID)
if !exists { if !exists {
return nil, errors.New("failed to find group") return nil, errors.New("failed to find group")
} }
return &Group{g: grp}, nil // Add to tracker and return Group object
return groupTrackerSingleton.make(grp), 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 +317,7 @@ func (g *GroupChat) NumGroups() int { ...@@ -323,6 +317,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.
...@@ -330,11 +325,16 @@ func (g *Group) GetName() []byte { ...@@ -330,11 +325,16 @@ func (g *Group) GetName() []byte {
return g.g.Name return g.g.Name
} }
// GetID return the 33-byte unique group ID. // GetID return the 33-byte unique group ID. This represents the id.ID object
func (g *Group) GetID() []byte { func (g *Group) GetID() []byte {
return g.g.ID.Bytes() return g.g.ID.Bytes()
} }
// GetTrackedID returns the tracked ID of the Group object. This is used by the backend tracker.
func (g *Group) GetTrackedID() int {
return g.id
}
// GetInitMessage returns initial message sent with the group request. // GetInitMessage returns initial message sent with the group request.
func (g *Group) GetInitMessage() []byte { func (g *Group) GetInitMessage() []byte {
return g.g.InitMessage return g.g.InitMessage
...@@ -369,9 +369,17 @@ func (g *Group) Serialize() []byte { ...@@ -369,9 +369,17 @@ func (g *Group) Serialize() []byte {
} }
////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////
// Group Chat Processor // Callbacks
////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////
// GroupRequest is a bindings-layer interface that handles a group reception.
//
// Parameters:
// - trackedGroupId - a bindings layer Group object.
type GroupRequest interface {
Callback(g *Group)
}
// 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