package handlers import ( "cwtch.im/cwtch/app" "cwtch.im/cwtch/app/plugins" "cwtch.im/cwtch/event" "cwtch.im/cwtch/model" "cwtch.im/cwtch/model/attr" peerC "cwtch.im/cwtch/peer" "cwtch.im/cwtch/protocol/connections" "cwtch.im/ui/go/constants" "cwtch.im/ui/go/the" "cwtch.im/ui/go/ui" "encoding/hex" "git.openprivacy.ca/openprivacy/log" "strconv" "time" ) func PeerHandler(onion string, uiManager ui.Manager, subscribed chan bool) { peer := the.CwtchApp.GetPeer(onion) upgradeSchema(peer) eventBus := the.CwtchApp.GetEventBus(onion) q := event.NewQueue() eventBus.Subscribe(event.NewMessageFromPeer, q) eventBus.Subscribe(event.PeerAcknowledgement, q) eventBus.Subscribe(event.NewMessageFromGroup, q) eventBus.Subscribe(event.NewGroupInvite, q) eventBus.Subscribe(event.SendMessageToGroupError, q) eventBus.Subscribe(event.SendMessageToPeerError, q) eventBus.Subscribe(event.ServerStateChange, q) eventBus.Subscribe(event.PeerStateChange, q) eventBus.Subscribe(event.PeerCreated, q) eventBus.Subscribe(event.NetworkStatus, q) eventBus.Subscribe(event.ChangePasswordSuccess, q) eventBus.Subscribe(event.ChangePasswordError, q) eventBus.Subscribe(event.NewRetValMessageFromPeer, q) subscribed <- true for { e := q.Next() switch e.EventType { case event.NetworkStatus: online, _ := peer.GetAttribute(attr.GetLocalScope(constants.PeerOnline)) if e.Data[event.Status] == plugins.NetworkCheckSuccess && online == event.False { peer.SetAttribute(attr.GetLocalScope(constants.PeerOnline), event.True) uiManager.UpdateNetworkStatus(true) // TODO we may have to reinitialize the peer } else if e.Data[event.Status] == plugins.NetworkCheckError && online == event.True { peer.SetAttribute(attr.GetLocalScope(constants.PeerOnline), event.False) uiManager.UpdateNetworkStatus(false) } case event.NewMessageFromPeer: //event.TimestampReceived, event.RemotePeer, event.Data ts, _ := time.Parse(time.RFC3339Nano, e.Data[event.TimestampReceived]) uiManager.StoreAndNotify(peer, e.Data[event.RemotePeer], e.Data[event.Data], ts, onion) case event.PeerAcknowledgement: uiManager.Acknowledge(e.Data[event.RemotePeer], e.Data[event.EventID]) case event.NewMessageFromGroup: //event.TimestampReceived, event.TimestampSent, event.Data, event.GroupID, event.RemotePeer ts, _ := time.Parse(time.RFC3339Nano, e.Data[event.TimestampSent]) uiManager.AddMessage(e.Data[event.GroupID], e.Data[event.RemotePeer], e.Data[event.Data], e.Data[event.RemotePeer] == peer.GetOnion(), hex.EncodeToString([]byte(e.Data[event.Signature])), ts, true) case event.NewGroupInvite: gid, err := peer.ProcessInvite(e.Data[event.GroupInvite], e.Data[event.RemotePeer]) group := peer.GetGroup(gid) if err == nil && group != nil { uiManager.AddContact(gid) } case event.PeerCreated: onion := e.Data[event.RemotePeer] uiManager.AddContact(onion) case event.SendMessageToGroupError: uiManager.AddSendMessageError(e.Data[event.GroupServer], e.Data[event.Signature], e.Data[event.Error]) case event.SendMessageToPeerError: uiManager.AddSendMessageError(e.Data[event.RemotePeer], e.Data[event.EventID], e.Data[event.Error]) case event.PeerStateChange: cxnState := connections.ConnectionStateToType[e.Data[event.ConnectionState]] // New connection established if cxnState == connections.AUTHENTICATED { // if it's not in the peer it's new if contact := peer.GetContact(e.Data[event.RemotePeer]); contact == nil { // Contact does not exist, we will add them peer.AddContact(e.Data[event.RemotePeer], e.Data[event.RemotePeer], model.AuthUnknown) uiManager.AddContact(e.Data[event.RemotePeer]) } } // if it's in the.PeerHandler its either existing and needs an update or not in the UI and needs to be added if contact := peer.GetContact(e.Data[event.RemotePeer]); contact != nil { contact.State = e.Data[event.ConnectionState] uiManager.UpdateContactStatus(contact.Onion, int(cxnState), false) if cxnState == connections.AUTHENTICATED { peer.SendGetValToPeer(e.Data[event.RemotePeer], attr.PublicScope, constants.Name) peer.SendGetValToPeer(e.Data[event.RemotePeer], attr.PublicScope, constants.Picture) } } case event.NewRetValMessageFromPeer: onion := e.Data[event.RemotePeer] scope := e.Data[event.Scope] path := e.Data[event.Path] val := e.Data[event.Data] exists, _ := strconv.ParseBool(e.Data[event.Exists]) if exists && scope == attr.PublicScope { switch path { case constants.Name: peer.SetContactAttribute(onion, attr.GetPeerScope(constants.Name), val) uiManager.UpdateContactDisplayName(onion) case constants.Picture: peer.SetContactAttribute(onion, attr.GetPeerScope(constants.Picture), val) uiManager.UpdateContactPicture(onion) } } case event.ServerStateChange: serverOnion := e.Data[event.GroupServer] state := connections.ConnectionStateToType[e.Data[event.ConnectionState]] groups := peer.GetGroups() for _, groupID := range groups { group := peer.GetGroup(groupID) if group != nil && group.GroupServer == serverOnion { group.State = e.Data[event.ConnectionState] loading := false if state == connections.AUTHENTICATED { loading = true } uiManager.UpdateContactStatus(groupID, int(state), loading) uiManager.UpdateContactStatus(serverOnion, int(state), loading) } } case event.DeletePeer: log.Infof("PeerHandler got DeletePeer, SHUTTING down!\n") uiManager.ReloadProfiles() return case event.ChangePasswordSuccess: peer.SetAttribute(app.AttributeTag, constants.ProfileTypeV1Password) uiManager.ChangePasswordResponse(false) case event.ChangePasswordError: uiManager.ChangePasswordResponse(true) } } } func upgradeSchema(p peerC.CwtchPeer) { schemaVerVal, exists := p.GetAttribute(constants.SchemaVersion) if !exists { schemaVerVal = "0" } schemaVer, err := strconv.Atoi(schemaVerVal) if err != nil { schemaVer = 0 } if schemaVer < 1 { upgradeSchema1(p) } } func upgradeSchema1(p peerC.CwtchPeer) { log.Infof("UpgradeSchema 1\n") p.SetAttribute(attr.GetPublicScope(constants.Name), p.GetName()) if picture, exists := p.GetAttribute("picture"); exists { p.SetAttribute(attr.GetPublicScope(constants.Picture), ui.ImageToString(ui.NewImage(picture, ui.TypeImageDistro))) } if locale, exists := p.GetAttribute("settings.locale"); exists { p.SetAttribute(attr.GetSettingsScope(constants.LocaleSetting), locale) } if zoom, exists := p.GetAttribute("settings.zoom"); exists { p.SetAttribute(attr.GetSettingsScope(constants.ZoomSetting), zoom) } if blockunknown, exists := p.GetAttribute("settings.blockunknownpeers"); exists { p.SetAttribute(attr.GetSettingsScope(constants.BlockUnknownPeersSetting), blockunknown) } for _, contactID := range p.GetContacts() { if nick, exists := p.GetContactAttribute(contactID, "nick"); exists { p.SetContactAttribute(contactID, attr.GetLocalScope(constants.Name), nick) } if picture, exists := p.GetContactAttribute(contactID, "picture"); exists { p.SetContactAttribute(contactID, attr.GetLocalScope(constants.Picture), ui.ImageToString(ui.NewImage(picture, ui.TypeImageDistro))) } if lastRead, exists := p.GetContactAttribute(contactID, "last-read"); exists { p.SetContactAttribute(contactID, attr.GetLocalScope(constants.LastRead), lastRead) } } for _, gID := range p.GetGroups() { if nick, exists := p.GetGroupAttribute(gID, "nick"); exists { p.SetGroupAttribute(gID, attr.GetLocalScope(constants.Name), nick) } if picture, exists := p.GetGroupAttribute(gID, "picture"); exists { p.SetGroupAttribute(gID, attr.GetLocalScope(constants.Picture), ui.ImageToString(ui.NewImage(picture, ui.TypeImageDistro))) } if lastRead, exists := p.GetGroupAttribute(gID, "last-read"); exists { p.SetGroupAttribute(gID, attr.GetLocalScope(constants.LastRead), lastRead) } } p.SetAttribute(constants.SchemaVersion, "1") }