Skip to content
Snippets Groups Projects
Select Git revision
  • 7b0f188d59186c8d633a771444558428d9f83029
  • release default protected
  • 11-22-implement-kv-interface-defined-in-collectiveversionedkvgo
  • hotfix/TestHostPool_UpdateNdf_AddFilter
  • XX-4719/announcementChannels
  • xx-4717/logLevel
  • jonah/noob-channel
  • master protected
  • XX-4707/tagDiskJson
  • xx-4698/notification-retry
  • hotfix/notifylockup
  • syncNodes
  • hotfix/localCB
  • XX-4677/NewChanManagerMobile
  • XX-4689/DmSync
  • duplicatePrefix
  • XX-4601/HavenInvites
  • finalizedUICallbacks
  • XX-4673/AdminKeySync
  • debugNotifID
  • anne/test
  • v4.7.5
  • v4.7.4
  • v4.7.3
  • v4.7.2
  • v4.7.1
  • v4.6.3
  • v4.6.1
  • v4.5.0
  • v4.4.4
  • v4.3.11
  • v4.3.8
  • v4.3.7
  • v4.3.6
  • v4.3.5
  • v4.2.0
  • v4.3.0
  • v4.3.4
  • v4.3.3
  • v4.3.2
  • v4.3.1
41 results

send.go

Blame
  • group.go 12.26 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 bindings
    
    import (
    	"encoding/json"
    	"fmt"
    	"github.com/pkg/errors"
    	gc "gitlab.com/elixxir/client/groupChat"
    	gs "gitlab.com/elixxir/client/groupChat/groupStore"
    	"gitlab.com/elixxir/crypto/group"
    	"gitlab.com/xx_network/primitives/id"
    	"time"
    )
    
    // GroupChat object contains the group chat manager.
    type GroupChat struct {
    	m gc.GroupChat
    }
    
    // GroupRequestFunc contains a function callback that is called when a group
    // request is received.
    type GroupRequestFunc interface {
    	GroupRequestCallback(g *Group)
    }
    
    // GroupReceiveFunc contains a function callback that is called when a group
    // message is received.
    type GroupReceiveFunc interface {
    	GroupReceiveCallback(msg *GroupMessageReceive)
    }
    
    // NewGroupManager creates a new group chat manager.
    func NewGroupManager(client *Client, requestFunc GroupRequestFunc,
    	receiveFunc GroupReceiveFunc) (*GroupChat, error) {
    
    	requestCallback := func(g gs.Group) {
    		requestFunc.GroupRequestCallback(&Group{g})
    	}
    	receiveCallback := func(msg gc.MessageReceive) {
    		receiveFunc.GroupReceiveCallback(&GroupMessageReceive{msg})
    	}
    
    	// Create a new group chat manager
    	// TODO: Need things from storage, services, etc?
    	m, err := gc.NewManager(client.api, requestCallback, receiveCallback)
    	if err != nil {
    		return nil, err
    	}
    
    	return &GroupChat{m}, nil
    }
    
    // MakeGroup creates a new group and sends a group request to all members in the
    // group. The ID of the new group, the rounds the requests were sent on, and the
    // status of the sends are contained in NewGroupReport.
    func (g *GroupChat) MakeGroup(membership *IdList, name, message []byte) *NewGroupReport {
    	grp, rounds, status, err := g.m.MakeGroup(membership.list, name, message)
    	errStr := ""
    	if err != nil {
    		errStr = err.Error()
    	}
    	return &NewGroupReport{&Group{grp}, rounds, status, errStr}
    }
    
    // ResendRequest resends a group request to all members in the group. The rounds
    // they were sent on and the status of the send are contained in NewGroupReport.
    func (g *GroupChat) ResendRequest(groupIdBytes []byte) (*NewGroupReport, error) {
    	groupID, err := id.Unmarshal(groupIdBytes)
    	if err != nil {
    		return nil,
    			errors.Errorf("Failed to unmarshal group ID: %+v", err)
    	}
    
    	grp, exists := g.m.GetGroup(groupID)
    	if !exists {
    		return nil, errors.Errorf("Failed to find group %s", groupID)
    	}
    
    	rounds, status, err := g.m.ResendRequest(groupID)
    
    	errStr := ""
    	if err != nil {
    		errStr = err.Error()
    	}
    	return &NewGroupReport{&Group{grp}, rounds, status, errStr}, nil
    }
    
    // JoinGroup allows a user to join a group when they receive a request. The
    // caller must pass in the serialized bytes of a Group.
    func (g *GroupChat) JoinGroup(serializedGroupData []byte) error {
    	grp, err := gs.DeserializeGroup(serializedGroupData)
    	if err != nil {
    		return err
    	}
    	return g.m.JoinGroup(grp)
    }
    
    // LeaveGroup deletes a group so a user no longer has access.
    func (g *GroupChat) LeaveGroup(groupIdBytes []byte) error {
    	groupID, err := id.Unmarshal(groupIdBytes)
    	if err != nil {
    		return errors.Errorf("Failed to unmarshal group ID: %+v", err)
    	}
    
    	return g.m.LeaveGroup(groupID)
    }
    
    // Send sends the message to the specified group. Returns the round the messages
    // were sent on.
    func (g *GroupChat) Send(groupIdBytes, message []byte) (*GroupSendReport, error) {
    	groupID, err := id.Unmarshal(groupIdBytes)
    	if err != nil {
    		return nil, errors.Errorf("Failed to unmarshal group ID: %+v", err)
    	}
    
    	round, timestamp, msgID, err := g.m.Send(groupID, message)
    	return &GroupSendReport{round, timestamp, msgID}, err
    }
    
    // GetGroups returns an IdList containing a list of group IDs that the user is a
    // part of.
    func (g *GroupChat) GetGroups() *IdList {
    	return &IdList{g.m.GetGroups()}
    }
    
    // GetGroup returns the group with the group ID. If no group exists, then the
    // error "failed to find group" is returned.
    func (g *GroupChat) GetGroup(groupIdBytes []byte) (*Group, error) {
    	groupID, err := id.Unmarshal(groupIdBytes)
    	if err != nil {
    		return nil, errors.Errorf("Failed to unmarshal group ID: %+v", err)
    	}
    
    	grp, exists := g.m.GetGroup(groupID)
    	if !exists {
    		return nil, errors.New("failed to find group")
    	}
    
    	return &Group{grp}, nil
    }
    
    // NumGroups returns the number of groups the user is a part of.
    func (g *GroupChat) NumGroups() int {
    	return g.m.NumGroups()
    }
    
    ////
    // NewGroupReport Structure
    ////
    
    // NewGroupReport is returned when creating a new group and contains the ID of
    // the group, a list of rounds that the group requests were sent on, and the
    // status of the send.
    type NewGroupReport struct {
    	group  *Group
    	rounds []id.Round
    	status gc.RequestStatus
    	err    string
    }
    
    type GroupReportDisk struct {
    	List   []id.Round
    	GrpId  []byte
    	Status int
    }
    
    // GetGroup returns the Group.
    func (ngr *NewGroupReport) GetGroup() *Group {
    	return ngr.group
    }
    
    // GetRoundList returns the RoundList containing a list of rounds requests were
    // sent on.
    func (ngr *NewGroupReport) GetRoundList() *RoundList {
    	return &RoundList{ngr.rounds}
    }
    
    // GetStatus returns the status of the requests sent when creating a new group.
    // status = 0   an error occurred before any requests could be sent
    //          1   all requests failed to send (call Resend Group)
    //          2   some request failed and some succeeded (call Resend Group)
    //          3,  all requests sent successfully (call Resend Group)
    func (ngr *NewGroupReport) GetStatus() int {
    	return int(ngr.status)
    }
    
    // GetError returns the string of an error.
    // Will be an empty string if no error occured
    func (ngr *NewGroupReport) GetError() string {
    	return ngr.err
    }
    
    func (ngr *NewGroupReport) Marshal() ([]byte, error) {
    	grpReportDisk := GroupReportDisk{
    		List:   ngr.rounds,
    		GrpId:  ngr.group.GetID()[:],
    		Status: ngr.GetStatus(),
    	}
    	return json.Marshal(&grpReportDisk)
    }
    
    func (ngr *NewGroupReport) Unmarshal(b []byte) error {
    	grpReportDisk := GroupReportDisk{}
    	if err := json.Unmarshal(b, &grpReportDisk); err != nil {
    		return errors.New(fmt.Sprintf("Failed to unmarshal group "+
    			"report: %s", err.Error()))
    	}
    
    	grpId, err := id.Unmarshal(grpReportDisk.GrpId)
    	if err != nil {
    		return errors.New(fmt.Sprintf("Failed to unmarshal group "+
    			"id: %s", err.Error()))
    	}
    
    	ngr.group.g.ID = grpId
    	ngr.rounds = grpReportDisk.List
    	ngr.status = gc.RequestStatus(grpReportDisk.Status)
    
    	return nil
    }
    
    ////
    // NewGroupReport Structure
    ////
    
    // GroupSendReport is returned when sending a group message. It contains the
    // round ID sent on and the timestamp of the send.
    type GroupSendReport struct {
    	roundID   id.Round
    	timestamp time.Time
    	messageID group.MessageID
    }
    
    // GetRoundID returns the ID of the round that the send occurred on.
    func (gsr *GroupSendReport) GetRoundID() int64 {
    	return int64(gsr.roundID)
    }
    
    // GetTimestampNano returns the timestamp of the send in nanoseconds.
    func (gsr *GroupSendReport) GetTimestampNano() int64 {
    	return gsr.timestamp.UnixNano()
    }
    
    // GetTimestampMS returns the timestamp of the send in milliseconds.
    func (gsr *GroupSendReport) GetTimestampMS() int64 {
    	ts := uint64(gsr.timestamp.UnixNano()) / uint64(time.Millisecond)
    	return int64(ts)
    }
    
    // GetMessageID returns the ID of the round that the send occurred on.
    func (gsr *GroupSendReport) GetMessageID() []byte {
    	return gsr.messageID[:]
    }
    
    // GetRoundURL returns the URL of the round that the send occurred on.
    func (gsr *GroupSendReport) GetRoundURL() string {
    	return getRoundURL(gsr.roundID)
    }
    
    ////
    // Group Structure
    ////
    
    // Group structure contains the identifying and membership information of a
    // group chat.
    type Group struct {
    	g gs.Group
    }
    
    // GetName returns the name set by the user for the group.
    func (g *Group) GetName() []byte {
    	return g.g.Name
    }
    
    // GetID return the 33-byte unique group ID.
    func (g *Group) GetID() []byte {
    	return g.g.ID.Bytes()
    }
    
    // GetInitMessage returns initial message sent with the group request.
    func (g *Group) GetInitMessage() []byte {
    	return g.g.InitMessage
    }
    
    // GetCreatedNano returns the time the group was created in nanoseconds. This is
    // also the time the group requests were sent.
    func (g *Group) GetCreatedNano() int64 {
    	return g.g.Created.UnixNano()
    }
    
    // GetCreatedMS returns the time the group was created in milliseconds. This is
    // also the time the group requests were sent.
    func (g *Group) GetCreatedMS() int64 {
    	ts := uint64(g.g.Created.UnixNano()) / uint64(time.Millisecond)
    	return int64(ts)
    }
    
    // GetMembership returns a list of contacts, one for each member in the group.
    // The list is in order; the first contact is the leader/creator of the group.
    // All subsequent members are ordered by their ID.
    func (g *Group) GetMembership() *GroupMembership {
    	return &GroupMembership{g.g.Members}
    }
    
    // Serialize serializes the Group.
    func (g *Group) Serialize() []byte {
    	return g.g.Serialize()
    }
    
    ////
    // Membership Structure
    ////
    
    // GroupMembership structure contains a list of members that are part of a
    // group. The first member is the group leader.
    type GroupMembership struct {
    	m group.Membership
    }
    
    // Len returns the number of members in the group membership.
    func (gm *GroupMembership) Len() int {
    	return len(gm.m)
    }
    
    // Get returns the member at the index. The member at index 0 is always the
    // group leader. An error is returned if the index is out of range.
    func (gm *GroupMembership) Get(i int) (*GroupMember, error) {
    	if i < 0 || i >= gm.Len() {
    		return nil, errors.Errorf("ID list index must be between %d "+
    			"and the last element %d.", 0, gm.Len())
    	}
    	return &GroupMember{gm.m[i]}, nil
    }
    
    ////
    // Member Structure
    ////
    
    // GroupMember represents a member in the group membership list.
    type GroupMember struct {
    	group.Member
    }
    
    // GetID returns the 33-byte user ID of the member.
    func (gm GroupMember) GetID() []byte {
    	return gm.ID.Bytes()
    }
    
    // GetDhKey returns the byte representation of the public Diffie–Hellman key of
    // the member.
    func (gm *GroupMember) GetDhKey() []byte {
    	return gm.DhKey.Bytes()
    }
    
    ////
    // Message Receive Structure
    ////
    
    // GroupMessageReceive contains a group message, its ID, and its data that a
    // user receives.
    type GroupMessageReceive struct {
    	gc.MessageReceive
    }
    
    // GetGroupID returns the 33-byte group ID.
    func (gmr *GroupMessageReceive) GetGroupID() []byte {
    	return gmr.GroupID.Bytes()
    }
    
    // GetMessageID returns the message ID.
    func (gmr *GroupMessageReceive) GetMessageID() []byte {
    	return gmr.ID.Bytes()
    }
    
    // GetPayload returns the message payload.
    func (gmr *GroupMessageReceive) GetPayload() []byte {
    	return gmr.Payload
    }
    
    // GetSenderID returns the 33-byte user ID of the sender.
    func (gmr *GroupMessageReceive) GetSenderID() []byte {
    	return gmr.SenderID.Bytes()
    }
    
    // GetRecipientID returns the 33-byte user ID of the recipient.
    func (gmr *GroupMessageReceive) GetRecipientID() []byte {
    	return gmr.RecipientID.Bytes()
    }
    
    // GetEphemeralID returns the address ID of the recipient.
    func (gmr *GroupMessageReceive) GetEphemeralID() int64 {
    	return gmr.EphemeralID.Int64()
    }
    
    // GetTimestampNano returns the message timestamp in nanoseconds.
    func (gmr *GroupMessageReceive) GetTimestampNano() int64 {
    	return gmr.Timestamp.UnixNano()
    }
    
    // GetTimestampMS returns the message timestamp in milliseconds.
    func (gmr *GroupMessageReceive) GetTimestampMS() int64 {
    	ts := uint64(gmr.Timestamp.UnixNano()) / uint64(time.Millisecond)
    	return int64(ts)
    }
    
    // GetRoundID returns the ID of the round the message was sent on.
    func (gmr *GroupMessageReceive) GetRoundID() int64 {
    	return int64(gmr.RoundID)
    }
    
    // GetRoundURL returns the ID of the round the message was sent on.
    func (gmr *GroupMessageReceive) GetRoundURL() string {
    	return getRoundURL(gmr.RoundID)
    }
    
    // GetRoundTimestampNano returns the timestamp, in nanoseconds, of the round the
    // message was sent on.
    func (gmr *GroupMessageReceive) GetRoundTimestampNano() int64 {
    	return gmr.RoundTimestamp.UnixNano()
    }
    
    // GetRoundTimestampMS returns the timestamp, in milliseconds, of the round the
    // message was sent on.
    func (gmr *GroupMessageReceive) GetRoundTimestampMS() int64 {
    	ts := uint64(gmr.RoundTimestamp.UnixNano()) / uint64(time.Millisecond)
    	return int64(ts)
    }