package gothings import ( "cwtch.im/ui/go/constants" "cwtch.im/ui/go/cwutil" "cwtch.im/ui/go/gobjects" "cwtch.im/ui/go/the" "encoding/base32" "git.openprivacy.ca/openprivacy/libricochet-go/log" "runtime/debug" "strings" "sync" "time" ) type InterfaceState struct { parentGcd *GrandCentralDispatcher contacts map[string]*gobjects.Contact messages sync.Map } func NewUIState(gcd *GrandCentralDispatcher) (uis InterfaceState) { uis = InterfaceState{gcd, make(map[string]*gobjects.Contact), sync.Map{}} return } func (this *InterfaceState) AddContact(c *gobjects.Contact) { if len(c.Handle) == 32 { // ADD GROUP if _, found := this.contacts[c.Handle]; !found { this.parentGcd.AddContact(c.Handle, c.DisplayName, c.Image, c.Server, c.Badge, c.Status, c.Trusted) this.contacts[c.Handle] = c } return } else if len(c.Handle) != 56 { log.Errorf("sorry, unable to handle AddContact(%v)", c.Handle) debug.PrintStack() return } if _, found := this.contacts[c.Handle]; !found { this.contacts[c.Handle] = c this.parentGcd.AddContact(c.Handle, c.DisplayName, c.Image, c.Server, c.Badge, c.Status, c.Trusted) if the.Peer.GetContact(c.Handle) == nil { decodedPub, _ := base32.StdEncoding.DecodeString(strings.ToUpper(c.Handle)) the.Peer.AddContact(c.DisplayName, c.Handle, decodedPub, c.Trusted) go the.Peer.PeerWithOnion(c.Handle) } } } func (this *InterfaceState) GetContact(handle string) *gobjects.Contact { if _, found := this.contacts[handle]; !found { if len(handle) == 32 { group := the.Peer.GetGroup(handle) if group != nil { this.AddContact(&gobjects.Contact{ handle, handle, cwutil.RandomGroupImage(handle), group.GroupServer, 0, 0, group.Accepted, }) go the.Peer.JoinServer(group.GroupServer) } else { log.Errorf("Attempting to add non existent group to ui %v", handle) } } else { contact := the.Peer.GetContact(handle) if contact != nil && handle != contact.Onion { this.AddContact(&gobjects.Contact{ handle, handle, cwutil.RandomProfileImage(handle), "", 0, 0, false, }) } else if contact == nil { //log.Errorf("Attempting to add non existent contact to ui %v", handle) } } } return this.contacts[handle] } func (this *InterfaceState) AddSendMessageError(peer string, signature string, err string) { acklist := the.AcknowledgementIDs[peer] for _,ack := range acklist { if ack.ID == signature { ack.Error = true } } messages,_ := this.messages.Load(peer) messageList,_ := messages.([]*gobjects.Message) for _,message := range messageList { if message.MessageID == signature { message.Error = true } } log.Debugf("Received Error Sending Message: %v %v", signature, err) // FIXME: Sometimes, for the first Peer message we send our error beats our message to the UI time.Sleep(time.Second*1) this.parentGcd.GroupSendError(signature, err) } func (this *InterfaceState) AddMessage(m *gobjects.Message) { this.GetContact(m.From) _,found := this.messages.Load(m.Handle) if !found { this.messages.Store(m.Handle, make([]*gobjects.Message, 0)) } // Ack message sent to group this.parentGcd.Acknowledged(m.MessageID) // Ack personal messages // TODO: unify this with the above signature based approach if m.Message == "ack" { // If an ack, swallow the message and ack from the list. acklist := the.AcknowledgementIDs[m.From] for _,ack := range acklist { if ack.Error == false { ack.Ack = true this.parentGcd.Acknowledged(ack.ID) } } } else { messages,_ := this.messages.Load(m.Handle) messageList,_ := messages.([]*gobjects.Message) this.messages.Store(m.Handle, append(messageList, m)) // If we have this group loaded already if this.parentGcd.CurrentOpenConversation() == m.Handle { // If the message is not from the user then add it, otherwise, just acknowledge. if !m.FromMe || !m.Acknowledged { this.parentGcd.AppendMessage(m.Handle, m.From, m.DisplayName, m.Message, m.Image, m.MessageID, m.FromMe, m.Timestamp.Format(constants.TIME_FORMAT), m.Acknowledged, m.Error) } else { this.parentGcd.Acknowledged(m.MessageID) } } else { c := this.GetContact(m.Handle) if c != nil { c.Badge++ this.UpdateContact(c.Handle) } } } } func (this *InterfaceState) GetMessages(handle string) []*gobjects.Message { _,found := this.messages.Load(handle) if !found { this.messages.Store(handle, make([]*gobjects.Message, 0)) } messages,found := this.messages.Load(handle) messageList,_ := messages.([]*gobjects.Message) return messageList } func (this *InterfaceState) UpdateContact(handle string) { c, found := this.contacts[handle] if found { this.parentGcd.UpdateContact(c.Handle, c.DisplayName, c.Image, c.Server, c.Badge, c.Status, c.Trusted) } } func (this *InterfaceState) UpdateContactAttribute(handle, key, value string) { this.parentGcd.UpdateContactAttribute(handle, key, value) }