Select Git revision

Jono Wenger authored
manager.go 5.53 KiB
///////////////////////////////////////////////////////////////////////////////
// Copyright © 2020 xx network SEZC //
// //
// Use of this source code is governed by a license that can be found in the //
// LICENSE file //
///////////////////////////////////////////////////////////////////////////////
package groupChat
import (
"github.com/pkg/errors"
jww "github.com/spf13/jwalterweatherman"
"gitlab.com/elixxir/client/api"
gs "gitlab.com/elixxir/client/groupChat/groupStore"
"gitlab.com/elixxir/client/interfaces"
"gitlab.com/elixxir/client/interfaces/message"
"gitlab.com/elixxir/client/interfaces/preimage"
"gitlab.com/elixxir/client/stoppable"
"gitlab.com/elixxir/client/storage"
"gitlab.com/elixxir/client/storage/edge"
"gitlab.com/elixxir/client/storage/versioned"
"gitlab.com/elixxir/crypto/cyclic"
"gitlab.com/elixxir/crypto/fastRNG"
"gitlab.com/elixxir/crypto/group"
"gitlab.com/xx_network/primitives/id"
)
const (
rawMessageBuffSize = 100
receiveStoppableName = "GroupChatReceive"
receiveListenerName = "GroupChatReceiveListener"
requestStoppableName = "GroupChatRequest"
requestListenerName = "GroupChatRequestListener"
groupStoppableName = "GroupChat"
)
// Error messages.
const (
newGroupStoreErr = "failed to create new group store: %+v"
joinGroupErr = "failed to join new group %s: %+v"
leaveGroupErr = "failed to leave group %s: %+v"
)
// Manager handles the list of groups a user is a part of.
type Manager struct {
client *api.Client
store *storage.Session
swb interfaces.Switchboard
net interfaces.NetworkManager
rng *fastRNG.StreamGenerator
gs *gs.Store
requestFunc RequestCallback
receiveFunc ReceiveCallback
}
// NewManager generates a new group chat manager. This functions satisfies the
// GroupChat interface.
func NewManager(client *api.Client, requestFunc RequestCallback,
receiveFunc ReceiveCallback) (*Manager, error) {
return newManager(
client,
client.GetUser().ReceptionID.DeepCopy(),
client.GetStorage().E2e().GetDHPublicKey(),
client.GetStorage(),
client.GetSwitchboard(),
client.GetNetworkInterface(),
client.GetRng(),
client.GetStorage().GetKV(),
requestFunc,
receiveFunc,
)
}
// newManager creates a new group chat manager from api.Client parts for easier
// testing.
func newManager(client *api.Client, userID *id.ID, userDhKey *cyclic.Int,
store *storage.Session, swb interfaces.Switchboard,
net interfaces.NetworkManager, rng *fastRNG.StreamGenerator,
kv *versioned.KV, requestFunc RequestCallback,
receiveFunc ReceiveCallback) (*Manager, error) {
// Load the group chat storage or create one if one does not exist
gStore, err := gs.NewOrLoadStore(
kv, group.Member{ID: userID, DhKey: userDhKey})
if err != nil {
return nil, errors.Errorf(newGroupStoreErr, err)
}
return &Manager{
client: client,
store: store,
swb: swb,
net: net,
rng: rng,
gs: gStore,
requestFunc: requestFunc,
receiveFunc: receiveFunc,
}, nil
}
// StartProcesses starts the reception worker.
func (m *Manager) StartProcesses() (stoppable.Stoppable, error) {
// Start group reception worker
receiveStop := stoppable.NewSingle(receiveStoppableName)
receiveChan := make(chan message.Receive, rawMessageBuffSize)
m.swb.RegisterChannel(receiveListenerName, &id.ID{},
message.Raw, receiveChan)
go m.receive(receiveChan, receiveStop)
// Start group request worker
requestStop := stoppable.NewSingle(requestStoppableName)
requestChan := make(chan message.Receive, rawMessageBuffSize)
m.swb.RegisterChannel(requestListenerName, &id.ID{},
message.GroupCreationRequest, requestChan)
go m.receiveRequest(requestChan, requestStop)
// Create a multi stoppable
multiStoppable := stoppable.NewMulti(groupStoppableName)
multiStoppable.Add(receiveStop)
multiStoppable.Add(requestStop)
return multiStoppable, nil
}
// JoinGroup adds the group to the list of group chats the user is a part of.
// An error is returned if the user is already part of the group or if the
// maximum number of groups have already been joined.
func (m Manager) JoinGroup(g gs.Group) error {
if err := m.gs.Add(g); err != nil {
return errors.Errorf(joinGroupErr, g.ID, err)
}
edgeStore := m.store.GetEdge()
edgeStore.Add(edge.Preimage{
Data: g.ID[:],
Type: preimage.Group,
Source: g.ID[:],
}, m.store.GetUser().ReceptionID)
jww.DEBUG.Printf("Joined group %q with ID %s.", g.Name, g.ID)
return nil
}
// LeaveGroup removes a group from a list of groups the user is a part of.
func (m Manager) LeaveGroup(groupID *id.ID) error {
if err := m.gs.Remove(groupID); err != nil {
return errors.Errorf(leaveGroupErr, groupID, err)
}
edgeStore := m.store.GetEdge()
err := edgeStore.Remove(edge.Preimage{
Data: groupID[:],
Type: preimage.Group,
Source: groupID[:],
}, m.store.GetUser().ReceptionID)
jww.DEBUG.Printf("Left group with ID %s.", groupID)
return err
}
// GetGroups returns a list of all registered groupChat IDs.
func (m Manager) GetGroups() []*id.ID {
jww.DEBUG.Print("Getting list of all groups.")
return m.gs.GroupIDs()
}
// GetGroup returns the group with the matching ID or returns false if none
// exist.
func (m Manager) GetGroup(groupID *id.ID) (gs.Group, bool) {
jww.DEBUG.Printf("Getting group with ID %s.", groupID)
return m.gs.Get(groupID)
}
// NumGroups returns the number of groups the user is a part of.
func (m Manager) NumGroups() int {
return m.gs.Len()
}