diff --git a/event/common.go b/event/common.go index aa93538..ce214f8 100644 --- a/event/common.go +++ b/event/common.go @@ -64,6 +64,12 @@ const ( // Data [serialized *model.Group] GroupCreated = Type("GroupCreated") + // RemotePeer + DeleteContact = Type("DeleteContact") + + // GroupID + DeleteGroup = Type("DeleteGroup") + // change the .Name attribute of a profile (careful - this is not a custom attribute. it is used in the underlying protocol during handshakes!) // attributes: // ProfileName [eg "erinn"] diff --git a/model/profile.go b/model/profile.go index 02c5d0c..1f7f6f4 100644 --- a/model/profile.go +++ b/model/profile.go @@ -112,6 +112,20 @@ func (p *Profile) AddContact(onion string, profile *PublicProfile) { p.lock.Unlock() } +// DeleteContact deletes a peer contact +func (p *Profile) DeleteContact(onion string) { + p.lock.Lock() + defer p.lock.Unlock() + delete(p.Contacts, onion) +} + +// DeleteGroup deletes a group +func (p *Profile) DeleteGroup(groupID string) { + p.lock.Lock() + defer p.lock.Unlock() + delete(p.Groups, groupID) +} + // RejectInvite rejects and removes a group invite func (p *Profile) RejectInvite(groupID string) { p.lock.Lock() diff --git a/peer/cwtch_peer.go b/peer/cwtch_peer.go index 0cafeac..faa9791 100644 --- a/peer/cwtch_peer.go +++ b/peer/cwtch_peer.go @@ -38,6 +38,8 @@ type CwtchPeer interface { BlockPeer(string) error AcceptInvite(string) error RejectInvite(string) + DeleteContact(string) + DeleteGroup(string) JoinServer(string) SendMessageToGroup(string, string) error @@ -201,6 +203,18 @@ func (cp *cwtchPeer) PeerWithOnion(onion string) { cp.eventBus.Publish(event.NewEvent(event.PeerRequest, map[event.Field]string{event.RemotePeer: onion})) } +// DeleteContact deletes a peer from the profile, storage, and handling +func (cp *cwtchPeer) DeleteContact(onion string) { + cp.Profile.DeleteContact(onion) + cp.eventBus.Publish(event.NewEventList(event.DeleteContact, event.RemotePeer, onion)) +} + +// DeleteGroup deletes a Group from the profile, storage, and handling +func (cp *cwtchPeer) DeleteGroup(groupID string) { + cp.Profile.DeleteGroup(groupID) + cp.eventBus.Publish(event.NewEventList(event.DeleteGroup, event.GroupID, groupID)) +} + // InviteOnionToGroup kicks off the invite process func (cp *cwtchPeer) InviteOnionToGroup(onion string, groupid string) error { group := cp.Profile.GetGroupByGroupID(groupid) diff --git a/protocol/connections/engine.go b/protocol/connections/engine.go index f6a6a26..31e1495 100644 --- a/protocol/connections/engine.go +++ b/protocol/connections/engine.go @@ -75,6 +75,8 @@ func NewProtocolEngine(identity identity.Identity, privateKey ed25519.PrivateKey engine.eventManager.Subscribe(event.JoinServer, engine.queue.EventChannel) engine.eventManager.Subscribe(event.SendMessageToGroup, engine.queue.EventChannel) engine.eventManager.Subscribe(event.SendMessageToPeer, engine.queue.EventChannel) + engine.eventManager.Subscribe(event.DeleteContact, engine.queue.EventChannel) + engine.eventManager.Subscribe(event.DeleteGroup, engine.queue.EventChannel) engine.eventManager.Subscribe(event.BlockPeer, engine.queue.EventChannel) for _, peer := range blockedPeers { @@ -108,6 +110,11 @@ func (e *engine) eventHandler() { e.sendMessageToPeer(ev.EventID, ev.Data[event.RemotePeer], event.ContextInvite, []byte(ev.Data[event.GroupInvite])) case event.JoinServer: e.joinServer(ev.Data[event.GroupServer]) + case event.DeleteContact: + onion := ev.Data[event.RemotePeer] + e.deleteConnection(onion) + case event.DeleteGroup: + // TODO: There isn't a way here to determine if other Groups are using a server connection... case event.SendMessageToGroup: e.sendMessageToGroup(ev.Data[event.GroupServer], []byte(ev.Data[event.Ciphertext]), []byte(ev.Data[event.Signature])) case event.SendMessageToPeer: @@ -254,6 +261,13 @@ func (e *engine) sendMessageToPeer(eventID string, onion string, context string, return err } +func (e *engine) deleteConnection(id string) { + conn, err := e.service.GetConnection(id) + if err == nil { + conn.Close() + } +} + // receiveGroupMessage is a callback function that processes GroupMessages from a given server func (e *engine) receiveGroupMessage(server string, gm *protocol.GroupMessage) { // Publish Event so that a Profile Engine can deal with it. diff --git a/storage/profile_store.go b/storage/profile_store.go index 8234bc8..7491662 100644 --- a/storage/profile_store.go +++ b/storage/profile_store.go @@ -56,6 +56,8 @@ func NewProfileWriterStore(eventManager event.Manager, directory, password strin ps.eventManager.Subscribe(event.NewMessageFromGroup, ps.queue.EventChannel) ps.eventManager.Subscribe(event.PeerStateChange, ps.queue.EventChannel) ps.eventManager.Subscribe(event.ServerStateChange, ps.queue.EventChannel) + ps.eventManager.Subscribe(event.DeleteContact, ps.queue.EventChannel) + ps.eventManager.Subscribe(event.DeleteGroup, ps.queue.EventChannel) return ps } @@ -233,6 +235,19 @@ func (ps *profileStore) eventHandler() { group.State = ev.Data[event.ConnectionState] } } + case event.DeleteContact: + onion := ev.Data[event.RemotePeer] + ps.profile.DeleteContact(onion) + ps.save() + case event.DeleteGroup: + groupID := ev.Data[event.GroupID] + ps.profile.DeleteGroup(groupID) + ps.save() + ss, exists := ps.streamStores[groupID] + if exists { + ss.Delete() + delete(ps.streamStores, groupID) + } default: return } diff --git a/storage/stream_store.go b/storage/stream_store.go index 15a98fa..706314c 100644 --- a/storage/stream_store.go +++ b/storage/stream_store.go @@ -34,6 +34,7 @@ type streamStore struct { type StreamStore interface { Write(message model.Message) Read() []model.Message + Delete() } // NewStreamStore returns an initialized StreamStore ready for reading and writing @@ -101,6 +102,13 @@ func (ss *streamStore) rotateFileStore() { } } +// Delete deletes all the files associated with this streamStore +func (ss *streamStore) Delete() { + for i := fileStorePartitions - 1; i >= 0; i-- { + os.Remove(path.Join(ss.storeDirectory, fmt.Sprintf("%s.%d", ss.filenameBase, i))) + } +} + // Read returns all messages from the backing file (not the buffer, which is jsut for writing to the current file) func (ss *streamStore) Read() (messages []model.Message) { ss.lock.Lock()