Compare commits
39 Commits
Author | SHA1 | Date |
---|---|---|
Dan Ballard | 3964348dd0 | |
Sarah Jamie Lewis | ae16c7c6a5 | |
Sarah Jamie Lewis | 69f14f9bb1 | |
erinn | f1775eb975 | |
erinn | c1b7e4c75d | |
Sarah Jamie Lewis | a460b900b6 | |
Sarah Jamie Lewis | b2d8f3f34a | |
Sarah Jamie Lewis | 6c5b48311d | |
Sarah Jamie Lewis | b33c6c77dd | |
Sarah Jamie Lewis | c864bccbb9 | |
erinn | 5dddb16f2b | |
erinn | 001470257a | |
Sarah Jamie Lewis | b37f283fe3 | |
Dan Ballard | 2f495dfd62 | |
erinn | e09e9c09a7 | |
erinn | ae3aef0518 | |
Sarah Jamie Lewis | 0f53ae0062 | |
Sarah Jamie Lewis | f6eaa2d691 | |
Sarah Jamie Lewis | 8f1b1b8630 | |
Dan Ballard | e2cf1d25e3 | |
Dan Ballard | 7b3ff2c1af | |
Sarah Jamie Lewis | c6f1c4d0f9 | |
erinn | e7ef2fef4a | |
erinn | ffaca8d876 | |
Sarah Jamie Lewis | 6070d378c5 | |
Sarah Jamie Lewis | fafdb8132a | |
Sarah Jamie Lewis | 9a764b5b35 | |
Dan Ballard | 3261d18118 | |
Sarah Jamie Lewis | 08b1b19f7a | |
erinn | 204cc35e0d | |
erinn | 28011ae674 | |
erinn | eb4150c0be | |
erinn | d9f9489fa2 | |
erinn | 854dc1946f | |
Sarah Jamie Lewis | 26b0151e79 | |
Sarah Jamie Lewis | abe06912a1 | |
Dan Ballard | 11f09c95d2 | |
Dan Ballard | 9b18bef47a | |
Sarah Jamie Lewis | c5f36a9480 |
|
@ -0,0 +1,5 @@
|
|||
package constants
|
||||
|
||||
// We offer "un-passworded" profiles but our storage encrypts everything with a password. We need an agreed upon
|
||||
// password to use in that case, that the app case use behind the scenes to password and unlock with
|
||||
const DefactoPasswordForUnencryptedProfiles = "be gay do crime"
|
|
@ -91,7 +91,6 @@ func (gf *GroupFunctionality) GetServerInfo(serverOnion string, profile peer.Rea
|
|||
|
||||
// HandleImportString handles import strings for groups and servers
|
||||
func (gf *GroupFunctionality) HandleImportString(peer peer.CwtchPeer, importString string) error {
|
||||
|
||||
if strings.HasPrefix(importString, tofuBundlePrefix) {
|
||||
bundle := strings.Split(importString, "||")
|
||||
if len(bundle) == 2 {
|
||||
|
@ -114,10 +113,15 @@ func (gf *GroupFunctionality) HandleImportString(peer peer.CwtchPeer, importStri
|
|||
return features.ConstructResponse(importBundlePrefix, err.Error())
|
||||
} else if strings.HasPrefix(importString, groupPrefix) {
|
||||
//eg: torv3JFDWkXExBsZLkjvfkkuAxHsiLGZBk0bvoeJID9ItYnU=EsEBCiBhOWJhZDU1OTQ0NWI3YmM2N2YxYTM5YjkzMTNmNTczNRIgpHeNaG+6jy750eDhwLO39UX4f2xs0irK/M3P6mDSYQIaOTJjM2ttb29ibnlnaGoyenc2cHd2N2Q1N3l6bGQ3NTNhdW8zdWdhdWV6enB2ZmFrM2FoYzRiZHlkCiJAdVSSVgsksceIfHe41OJu9ZFHO8Kwv3G6F5OK3Hw4qZ6hn6SiZjtmJlJezoBH0voZlCahOU7jCOg+dsENndZxAA==
|
||||
if _, err := peer.ImportGroup(importString); err != nil {
|
||||
if gid, err := peer.ImportGroup(importString); err != nil {
|
||||
return features.ConstructResponse(importBundlePrefix, err.Error())
|
||||
} else {
|
||||
// Auto accept the group here.
|
||||
if peer.AcceptInvite(gid) != nil {
|
||||
log.Errorf("Error accepting invite: %v", err)
|
||||
}
|
||||
return features.ConstructResponse(importBundlePrefix, "success")
|
||||
}
|
||||
return features.ConstructResponse(importBundlePrefix, "success")
|
||||
}
|
||||
return features.ConstructResponse(importBundlePrefix, "invalid_group_invite_prefix")
|
||||
}
|
||||
|
|
3
go.mod
3
go.mod
|
@ -3,7 +3,8 @@ module git.openprivacy.ca/flutter/libcwtch-go
|
|||
go 1.15
|
||||
|
||||
require (
|
||||
cwtch.im/cwtch v0.8.9
|
||||
cwtch.im/cwtch v0.8.11
|
||||
git.openprivacy.ca/openprivacy/connectivity v1.4.4
|
||||
git.openprivacy.ca/openprivacy/log v1.0.2
|
||||
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22 // indirect
|
||||
)
|
||||
|
|
7
go.sum
7
go.sum
|
@ -1,5 +1,5 @@
|
|||
cwtch.im/cwtch v0.8.9 h1:aAEB3DaQp7/4yTUA7VxHpQFHJtyFETGvcuRlh1nP7FI=
|
||||
cwtch.im/cwtch v0.8.9/go.mod h1:D9dtO+WnKqdmufKSfFeFlUYaxLTfE/RtqVe1OD0kiKc=
|
||||
cwtch.im/cwtch v0.8.11 h1:nUrd6srjLxInSJ0q1JdmRBhN4RRlZRL+2vIyE/AXkfY=
|
||||
cwtch.im/cwtch v0.8.11/go.mod h1:D9dtO+WnKqdmufKSfFeFlUYaxLTfE/RtqVe1OD0kiKc=
|
||||
git.openprivacy.ca/cwtch.im/tapir v0.4.3 h1:sctSfUXHDIqaHfJPDl+5lHtmoEJolQiHTcHZGAe5Qc4=
|
||||
git.openprivacy.ca/cwtch.im/tapir v0.4.3/go.mod h1:10qEaib5x021zgyZ/97JKWsEpedH5+Vfy2CvB2V+08E=
|
||||
git.openprivacy.ca/openprivacy/bine v0.0.4 h1:CO7EkGyz+jegZ4ap8g5NWRuDHA/56KKvGySR6OBPW+c=
|
||||
|
@ -53,8 +53,9 @@ golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22 h1:RqytpXGR1iVNX7psjB3ff8y7sNFinVFvkx1c8SjBkio=
|
||||
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
|
|
198
lib.go
198
lib.go
|
@ -10,16 +10,16 @@ import (
|
|||
"cwtch.im/cwtch/model"
|
||||
"cwtch.im/cwtch/model/attr"
|
||||
"cwtch.im/cwtch/peer"
|
||||
contact "git.openprivacy.ca/flutter/libcwtch-go/features/contacts"
|
||||
"git.openprivacy.ca/flutter/libcwtch-go/features/groups"
|
||||
"git.openprivacy.ca/openprivacy/connectivity"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"git.openprivacy.ca/flutter/libcwtch-go/constants"
|
||||
contact "git.openprivacy.ca/flutter/libcwtch-go/features/contacts"
|
||||
"git.openprivacy.ca/flutter/libcwtch-go/features/groups"
|
||||
"git.openprivacy.ca/flutter/libcwtch-go/utils"
|
||||
"git.openprivacy.ca/openprivacy/connectivity"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"encoding/base64"
|
||||
"git.openprivacy.ca/openprivacy/connectivity/tor"
|
||||
|
@ -68,9 +68,10 @@ func c_StartCwtch(dir_c *C.char, len C.int, tor_c *C.char, torLen C.int) int8 {
|
|||
// message: CwtchStarted when start up is complete and app is safe to use
|
||||
// CwtchStartError message when start up fails (includes event.Error data field)
|
||||
func StartCwtch(appDir string, torPath string) int {
|
||||
eventHandler = utils.NewEventHandler()
|
||||
log.SetLevel(log.LevelInfo)
|
||||
|
||||
|
||||
log.Infof("StartCwtch(...)")
|
||||
// Quick hack check that we're being called with the correct params
|
||||
// On android a stale worker could be calling us with "last apps" directory. Best to abort fast so the app can make a new worker
|
||||
if runtime.GOOS == "android" {
|
||||
|
@ -87,12 +88,21 @@ func StartCwtch(appDir string, torPath string) int {
|
|||
}
|
||||
|
||||
func _startCwtch(appDir string, torPath string) {
|
||||
// Exclude Tapir wire Messages (We need a TRACE level)
|
||||
log.Infof("application: %v eventHandler: %v acn: %v", application, eventHandler, globalACN)
|
||||
|
||||
if application != nil {
|
||||
log.Infof("_startCwtch detected existing application; resuming instead of relaunching")
|
||||
ReconnectCwtchForeground()
|
||||
return
|
||||
}
|
||||
|
||||
// Exclude Tapir wire Messages
|
||||
//(We need a TRACE level)
|
||||
log.ExcludeFromPattern("service.go")
|
||||
|
||||
// Ensure that the application directory exists...and then initialize settings..
|
||||
os.MkdirAll(path.Join(appDir), 0700)
|
||||
utils.InitGlobalSettingsFile(appDir, "be gay do crime")
|
||||
utils.InitGlobalSettingsFile(appDir, constants.DefactoPasswordForUnencryptedProfiles)
|
||||
|
||||
log.Infof("Loading Cwtch Directory %v and tor path: %v", appDir, torPath)
|
||||
|
||||
|
@ -107,6 +117,9 @@ func _startCwtch(appDir string, torPath string) {
|
|||
panic(err)
|
||||
}
|
||||
|
||||
log.Infof("Creating new EventHandler()")
|
||||
eventHandler = utils.NewEventHandler()
|
||||
|
||||
log.Infof("making directory %v", appDir)
|
||||
os.MkdirAll(path.Join(appDir, "/.tor", "tor"), 0700)
|
||||
tor.NewTorrc().WithSocksPort(port).WithOnionTrafficOnly().WithControlPort(controlPort).WithHashedPassword(base64.StdEncoding.EncodeToString(key)).Build(filepath.Join(appDir, ".tor", "tor", "torrc"))
|
||||
|
@ -144,13 +157,14 @@ func _startCwtch(appDir string, torPath string) {
|
|||
settings := utils.ReadGlobalSettings()
|
||||
settingsJson, _ := json.Marshal(settings)
|
||||
|
||||
newApp.LoadProfiles("be gay do crime")
|
||||
newApp.LoadProfiles(constants.DefactoPasswordForUnencryptedProfiles)
|
||||
application = newApp
|
||||
|
||||
// Send global settings to the UI...
|
||||
application.GetPrimaryBus().Publish(event.NewEvent(utils.UpdateGlobalSettings, map[event.Field]string{event.Data: string(settingsJson)}))
|
||||
log.Infof("libcwtch-go application launched")
|
||||
application.GetPrimaryBus().Publish(event.NewEvent(utils.CwtchStarted, map[event.Field]string{}))
|
||||
application.QueryACNVersion()
|
||||
}
|
||||
|
||||
//export c_ReconnectCwtchForeground
|
||||
|
@ -161,10 +175,46 @@ func c_ReconnectCwtchForeground() {
|
|||
// Like StartCwtch, but StartCwtch has already been called so we don't need to restart Tor etc (probably)
|
||||
// Do need to re-send initial state tho, eg profiles that are already loaded
|
||||
func ReconnectCwtchForeground() {
|
||||
log.Infof("Reconnecting cwtchforeground")
|
||||
if application == nil {
|
||||
log.Errorf("ReconnectCwtchForeground: Application is nil, presuming stale thread, EXITING Reconnect\n")
|
||||
return
|
||||
}
|
||||
|
||||
// populate profile list
|
||||
peerList := application.ListPeers()
|
||||
for onion := range peerList {
|
||||
eventHandler.Push(event.NewEvent(event.NewPeer, map[event.Field]string{event.Identity: onion, event.Created: event.False}))
|
||||
eventHandler.Push(event.NewEvent(event.NewPeer, map[event.Field]string{event.Identity: onion, event.Created: event.False, "Reload": event.True}))
|
||||
}
|
||||
|
||||
for onion := range peerList {
|
||||
// fix peerpeercontact message counts
|
||||
contactList := application.GetPeer(onion).GetContacts()
|
||||
for _, handle := range contactList {
|
||||
totalMessages := application.GetPeer(onion).GetContact(handle).Timeline.Len() + len(application.GetPeer(onion).GetContact(handle).UnacknowledgedMessages)
|
||||
eventHandler.Push(event.NewEvent(event.MessageCounterResync, map[event.Field]string{
|
||||
event.Identity: onion,
|
||||
event.RemotePeer: handle,
|
||||
event.Data: strconv.Itoa(totalMessages),
|
||||
}))
|
||||
}
|
||||
|
||||
// fix peergroupcontact message counts
|
||||
groupList := application.GetPeer(onion).GetGroups()
|
||||
for _, groupID := range groupList {
|
||||
totalMessages := application.GetPeer(onion).GetGroup(groupID).Timeline.Len() + len(application.GetPeer(onion).GetGroup(groupID).UnacknowledgedMessages)
|
||||
eventHandler.Push(event.NewEvent(event.MessageCounterResync, map[event.Field]string{
|
||||
event.Identity: onion,
|
||||
event.GroupID: groupID,
|
||||
event.Data: strconv.Itoa(totalMessages),
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
application.GetPrimaryBus().Publish(event.NewEvent(utils.CwtchStarted, map[event.Field]string{}))
|
||||
application.QueryACNStatus()
|
||||
application.QueryACNVersion()
|
||||
}
|
||||
|
||||
//export c_SendAppEvent
|
||||
|
@ -297,10 +347,18 @@ func c_GetAppBusEvent() *C.char {
|
|||
|
||||
// GetAppBusEvent blocks until an event
|
||||
func GetAppBusEvent() string {
|
||||
log.Debugf("appbusevent called")
|
||||
for eventHandler == nil {
|
||||
log.Debugf("waiting for eventHandler != nil")
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
|
||||
var json = ""
|
||||
for json == "" {
|
||||
log.Debugf("waiting for json != ''")
|
||||
json = eventHandler.GetNextEvent()
|
||||
}
|
||||
log.Debugf("appbusevent: %v", json)
|
||||
return json
|
||||
}
|
||||
|
||||
|
@ -310,35 +368,17 @@ type Profile struct {
|
|||
ImagePath string `json:"imagePath"`
|
||||
}
|
||||
|
||||
//export c_GetProfiles
|
||||
func c_GetProfiles() *C.char {
|
||||
return C.CString(GetProfiles())
|
||||
}
|
||||
|
||||
func GetProfiles() string {
|
||||
peerList := application.ListPeers()
|
||||
profiles := make([]Profile, len(peerList))
|
||||
i := 0
|
||||
for onion := range peerList {
|
||||
name, _ := application.GetPeer(onion).GetAttribute(attr.GetPublicScope(constants.Name))
|
||||
profiles[i] = Profile{
|
||||
Name: name,
|
||||
Onion: onion,
|
||||
ImagePath: "",
|
||||
}
|
||||
i += 1
|
||||
}
|
||||
jsonBytes, _ := json.Marshal(profiles)
|
||||
return string(jsonBytes)
|
||||
}
|
||||
|
||||
//export c_CreateProfile
|
||||
func c_CreateProfile(nick_ptr *C.char, nick_len C.int, pass_ptr *C.char, pass_len C.int) {
|
||||
CreateProfile(C.GoStringN(nick_ptr, nick_len), C.GoStringN(pass_ptr, pass_len))
|
||||
}
|
||||
|
||||
func CreateProfile(nick, pass string) {
|
||||
application.CreatePeer(nick, pass)
|
||||
if pass == constants.DefactoPasswordForUnencryptedProfiles {
|
||||
application.CreateTaggedPeer(nick, pass, constants.ProfileTypeV1DefaultPassword)
|
||||
} else {
|
||||
application.CreateTaggedPeer(nick, pass, constants.ProfileTypeV1Password)
|
||||
}
|
||||
}
|
||||
|
||||
//export c_LoadProfiles
|
||||
|
@ -424,36 +464,6 @@ func BlockContact(profile, handle string) {
|
|||
}
|
||||
}
|
||||
|
||||
//export c_DebugResetContact
|
||||
func c_DebugResetContact(profilePtr *C.char, profileLen C.int, handlePtr *C.char, handleLen C.int) {
|
||||
DebugResetContact(C.GoStringN(profilePtr, profileLen), C.GoStringN(handlePtr, handleLen))
|
||||
}
|
||||
|
||||
func DebugResetContact(profile, handle string) {
|
||||
err := application.GetPeer(profile).SetContactAuthorization(handle, model.AuthUnknown)
|
||||
if err == nil {
|
||||
application.GetPrimaryBus().Publish(event.NewEvent(event.PeerStateChange, map[event.Field]string{
|
||||
ProfileOnion: profile,
|
||||
event.RemotePeer: handle,
|
||||
"authorization": string(model.AuthUnknown),
|
||||
}))
|
||||
} else {
|
||||
log.Errorf("error resetting contact: %s", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
//export c_NumMessages
|
||||
func c_NumMessages(profile_ptr *C.char, profile_len C.int, handle_ptr *C.char, handle_len C.int) (n int) {
|
||||
profile := C.GoStringN(profile_ptr, profile_len)
|
||||
handle := C.GoStringN(handle_ptr, handle_len)
|
||||
return (NumMessages(profile, handle))
|
||||
}
|
||||
|
||||
func NumMessages(profile, handle string) (n int) {
|
||||
n = len(application.GetPeer(profile).GetContact(handle).Timeline.Messages)
|
||||
return
|
||||
}
|
||||
|
||||
//export c_UpdateMessageFlags
|
||||
func c_UpdateMessageFlags(profile_ptr *C.char, profile_len C.int, handle_ptr *C.char, handle_len C.int, mIdx C.int, message_flags C.ulong) {
|
||||
profile := C.GoStringN(profile_ptr, profile_len)
|
||||
|
@ -509,24 +519,19 @@ func GetMessage(profileOnion, handle string, message_index int) string {
|
|||
if message_index < len(profile.GetContact(handle).Timeline.Messages) {
|
||||
message.Message = profile.GetContact(handle).Timeline.Messages[message_index]
|
||||
message.ContactImage = ph.GetProfilePic(handle)
|
||||
} else {
|
||||
log.Errorf("peerpeercontact getmessage out of range; sending counter resync just in case")
|
||||
eventHandler.Push(event.NewEvent(event.MessageCounterResync, map[event.Field]string{
|
||||
event.Identity: profileOnion,
|
||||
event.RemotePeer: handle,
|
||||
event.Data: strconv.Itoa(len(profile.GetContact(handle).Timeline.Messages)),
|
||||
}))
|
||||
}
|
||||
}
|
||||
bytes, _ := json.Marshal(message)
|
||||
return string(bytes)
|
||||
}
|
||||
|
||||
//export c_GetMessages
|
||||
func c_GetMessages(profile_ptr *C.char, profile_len C.int, handle_ptr *C.char, handle_len C.int, start C.int, end C.int) *C.char {
|
||||
profile := C.GoStringN(profile_ptr, profile_len)
|
||||
handle := C.GoStringN(handle_ptr, handle_len)
|
||||
return C.CString(GetMessages(profile, handle, int(start), int(end)))
|
||||
}
|
||||
|
||||
func GetMessages(profile, handle string, start, end int) string {
|
||||
messages := application.GetPeer(profile).GetContact(handle).Timeline.Messages[start:end]
|
||||
bytes, _ := json.Marshal(messages)
|
||||
return string(bytes)
|
||||
}
|
||||
|
||||
//export c_SendMessage
|
||||
func c_SendMessage(profile_ptr *C.char, profile_len C.int, handle_ptr *C.char, handle_len C.int, msg_ptr *C.char, msg_len C.int) {
|
||||
|
@ -593,15 +598,6 @@ func ResetTor() {
|
|||
globalACN.Restart()
|
||||
}
|
||||
|
||||
//export c_QueryACNVersion
|
||||
func c_QueryACNVersion() {
|
||||
QueryACNVersion()
|
||||
}
|
||||
|
||||
func QueryACNVersion() {
|
||||
application.QueryACNVersion()
|
||||
}
|
||||
|
||||
//export c_CreateGroup
|
||||
func c_CreateGroup(profile_ptr *C.char, profile_len C.int, server_ptr *C.char, server_len C.int, name_ptr *C.char, name_len C.int) {
|
||||
profile := C.GoStringN(profile_ptr, profile_len)
|
||||
|
@ -635,6 +631,12 @@ func c_DeleteProfile(profile_ptr *C.char, profile_len C.int, password_ptr *C.cha
|
|||
|
||||
// DeleteProfile deletes a profile given the right password
|
||||
func DeleteProfile(profile string, password string) {
|
||||
|
||||
// allow a blank password to delete "unencrypted" accounts...
|
||||
if password == "" {
|
||||
password = constants.DefactoPasswordForUnencryptedProfiles
|
||||
}
|
||||
|
||||
application.DeletePeer(profile, password)
|
||||
}
|
||||
|
||||
|
@ -690,7 +692,7 @@ func ImportBundle(profileOnion string, bundle string) {
|
|||
serverListForOnion := groupHandler.GetServerInfoList(profile)
|
||||
serversListBytes, _ := json.Marshal(serverListForOnion)
|
||||
eventHandler.Push(event.NewEvent(groups.UpdateServerInfo, map[event.Field]string{"ProfileOnion": profileOnion, groups.ServerList: string(serversListBytes)}))
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
eventHandler.Push(event.NewEvent(event.AppError, map[event.Field]string{event.Data: response.Error()}))
|
||||
|
@ -714,5 +716,29 @@ func SetGroupAttribute(profileOnion string, groupHandle string, key string, valu
|
|||
}
|
||||
}
|
||||
|
||||
//export c_ShutdownCwtch
|
||||
func c_ShutdownCwtch() {
|
||||
ShutdownCwtch()
|
||||
}
|
||||
|
||||
// ShutdownCwtch is a safe way to shutdown any active cwtch applications and associated ACNs
|
||||
func ShutdownCwtch() {
|
||||
if application != nil && globalACN != nil {
|
||||
// Kill the isolate
|
||||
eventHandler.Push(event.NewEvent(event.Shutdown, map[event.Field]string{}))
|
||||
|
||||
// Allow for the shutdown events to go through and then purge everything else...
|
||||
log.Infof("Shutting Down Application...")
|
||||
application.Shutdown()
|
||||
log.Infof("Shutting Down ACN...")
|
||||
globalACN.Close()
|
||||
log.Infof("Library Shutdown Complete!")
|
||||
// do not remove - important for state checks elsewhere
|
||||
application = nil
|
||||
globalACN = nil
|
||||
eventHandler = nil
|
||||
}
|
||||
}
|
||||
|
||||
// Leave as is, needed by ffi
|
||||
func main() {}
|
||||
|
|
|
@ -23,15 +23,14 @@ type EventHandler struct {
|
|||
app app.Application
|
||||
appBusQueue event.Queue
|
||||
profileEvents chan EventProfileEnvelope
|
||||
profileQueues map[string]event.Queue
|
||||
}
|
||||
|
||||
func NewEventHandler() *EventHandler {
|
||||
eh := &EventHandler{app: nil, appBusQueue: event.NewQueue(), profileQueues: make(map[string]event.Queue), profileEvents: make(chan EventProfileEnvelope)}
|
||||
eh := &EventHandler{app: nil, appBusQueue: event.NewQueue(), profileEvents: make(chan EventProfileEnvelope)}
|
||||
return eh
|
||||
}
|
||||
|
||||
// PublishAppEvent is a way for libCwtch-go to publish an event for consumption by a UI before a Cwtch app has been initalized
|
||||
// PublishAppEvent is a way for libCwtch-go to publish an event for consumption by a UI before a Cwtch app has been initialized
|
||||
// Main use: to signal an error before a cwtch app could be created
|
||||
func (eh *EventHandler) PublishAppEvent(event event.Event) {
|
||||
eh.appBusQueue.Publish(event)
|
||||
|
@ -42,6 +41,7 @@ func (eh *EventHandler) HandleApp(application app.Application) {
|
|||
application.GetPrimaryBus().Subscribe(event.NewPeer, eh.appBusQueue)
|
||||
application.GetPrimaryBus().Subscribe(event.PeerError, eh.appBusQueue)
|
||||
application.GetPrimaryBus().Subscribe(event.PeerDeleted, eh.appBusQueue)
|
||||
application.GetPrimaryBus().Subscribe(event.Shutdown, eh.appBusQueue)
|
||||
application.GetPrimaryBus().Subscribe(event.AppError, eh.appBusQueue)
|
||||
application.GetPrimaryBus().Subscribe(event.ACNStatus, eh.appBusQueue)
|
||||
application.GetPrimaryBus().Subscribe(event.ReloadDone, eh.appBusQueue)
|
||||
|
@ -64,149 +64,163 @@ func (eh *EventHandler) GetNextEvent() string {
|
|||
// handleAppBusEvent enriches AppBus events so they are usable with out further data fetches
|
||||
func (eh *EventHandler) handleAppBusEvent(e *event.Event) string {
|
||||
log.Debugf("New AppBus Event to Handle: %v", e)
|
||||
switch e.EventType {
|
||||
case event.ACNStatus:
|
||||
if e.Data[event.Progress] == "100" {
|
||||
for onion := range eh.app.ListPeers() {
|
||||
// launch a listen thread (internally this does a check that the protocol engine is not listening)
|
||||
// and as such is safe to call.
|
||||
eh.app.GetPeer(onion).Listen()
|
||||
}
|
||||
}
|
||||
case event.NewPeer:
|
||||
onion := e.Data[event.Identity]
|
||||
profile := eh.app.GetPeer(e.Data[event.Identity])
|
||||
log.Debug("New Peer Event: %v", e)
|
||||
eh.startHandlingPeer(onion)
|
||||
|
||||
if e.Data[event.Created] == event.True {
|
||||
name, _ := profile.GetAttribute(attr.GetLocalScope(constants.Name))
|
||||
profile.SetAttribute(attr.GetPublicScope(constants.Name), name)
|
||||
profile.SetAttribute(attr.GetPublicScope(constants.Picture), ImageToString(NewImage(RandomProfileImage(onion), TypeImageDistro)))
|
||||
}
|
||||
if e.Data[event.Status] != event.StorageRunning || e.Data[event.Created] == event.True {
|
||||
profile.SetAttribute(attr.GetLocalScope(constants.PeerOnline), event.False)
|
||||
eh.app.AddPeerPlugin(onion, plugins.CONNECTIONRETRY)
|
||||
eh.app.AddPeerPlugin(onion, plugins.NETWORKCHECK)
|
||||
|
||||
// If the user has chosen to block unknown profiles
|
||||
// then explicitly configure the protocol engine to do so..
|
||||
if ReadGlobalSettings().BlockUnknownConnections {
|
||||
profile.BlockUnknownConnections()
|
||||
} else {
|
||||
// For completeness
|
||||
profile.AllowUnknownConnections()
|
||||
}
|
||||
|
||||
// Start up the Profile
|
||||
profile.Listen()
|
||||
profile.StartPeersConnections()
|
||||
if _, err := groups.ExperimentGate(ReadGlobalSettings().Experiments); err == nil {
|
||||
profile.StartServerConnections()
|
||||
}
|
||||
}
|
||||
|
||||
nick, exists := profile.GetAttribute(attr.GetPublicScope(constants.Name))
|
||||
if !exists {
|
||||
nick = onion
|
||||
}
|
||||
|
||||
picVal, ok := profile.GetAttribute(attr.GetPublicScope(constants.Picture))
|
||||
if !ok {
|
||||
picVal = ImageToString(NewImage(RandomProfileImage(onion), TypeImageDistro))
|
||||
}
|
||||
pic, err := StringToImage(picVal)
|
||||
if err != nil {
|
||||
pic = NewImage(RandomProfileImage(onion), TypeImageDistro)
|
||||
}
|
||||
picPath := GetPicturePath(pic)
|
||||
|
||||
//tag, _ := profile.GetAttribute(app.AttributeTag)
|
||||
|
||||
online, _ := profile.GetAttribute(attr.GetLocalScope(constants.PeerOnline))
|
||||
|
||||
e.Data[constants.Name] = nick
|
||||
e.Data[constants.Picture] = picPath
|
||||
e.Data["Online"] = online
|
||||
|
||||
var contacts []Contact
|
||||
var servers []groups.Server
|
||||
for _, contact := range profile.GetContacts() {
|
||||
|
||||
// Only compile the server info if we have enabled the experiment...
|
||||
// Note that this means that this info can become stale if when first loaded the experiment
|
||||
// has been disabled and then is later re-enabled. As such we need to ensure that this list is
|
||||
// re-fetched when the group experiment is enabled via a dedicated ListServerInfo event...
|
||||
if profile.GetContact(contact).IsServer() {
|
||||
groupHandler, err := groups.ExperimentGate(ReadGlobalSettings().Experiments)
|
||||
if err == nil {
|
||||
servers = append(servers, groupHandler.GetServerInfo(contact, profile))
|
||||
if eh.app != nil {
|
||||
switch e.EventType {
|
||||
case event.ACNStatus:
|
||||
if e.Data[event.Progress] == "100" {
|
||||
for onion := range eh.app.ListPeers() {
|
||||
// launch a listen thread (internally this does a check that the protocol engine is not listening)
|
||||
// and as such is safe to call.
|
||||
eh.app.GetPeer(onion).Listen()
|
||||
}
|
||||
continue
|
||||
}
|
||||
case event.NewPeer:
|
||||
onion := e.Data[event.Identity]
|
||||
profile := eh.app.GetPeer(e.Data[event.Identity])
|
||||
log.Debug("New Peer Event: %v", e)
|
||||
|
||||
if e.Data["Reload"] != event.True {
|
||||
eh.startHandlingPeer(onion)
|
||||
}
|
||||
|
||||
contactInfo := profile.GetContact(contact)
|
||||
ph := NewPeerHelper(profile)
|
||||
name := ph.GetNick(contact)
|
||||
cpicPath := ph.GetProfilePic(contact)
|
||||
saveHistory, set := contactInfo.GetAttribute(event.SaveHistoryKey)
|
||||
if !set {
|
||||
saveHistory = event.DeleteHistoryDefault
|
||||
tag,isTagged := profile.GetAttribute(app.AttributeTag)
|
||||
if isTagged {
|
||||
e.Data[app.AttributeTag] = tag
|
||||
} else {
|
||||
// Assume encrypted for non-tagged profiles - this isn't always true, but all post-beta profiles
|
||||
// are tagged on creation.
|
||||
e.Data[app.AttributeTag] = constants.ProfileTypeV1Password
|
||||
}
|
||||
contacts = append(contacts, Contact{
|
||||
Name: name,
|
||||
Onion: contactInfo.Onion,
|
||||
Status: contactInfo.State,
|
||||
Picture: cpicPath,
|
||||
Authorization: string(contactInfo.Authorization),
|
||||
SaveHistory: saveHistory,
|
||||
Messages: contactInfo.Timeline.Len(),
|
||||
Unread: 0,
|
||||
LastMessage: strconv.Itoa(getLastMessageTime(&contactInfo.Timeline)),
|
||||
IsGroup: false,
|
||||
})
|
||||
|
||||
if e.Data[event.Created] == event.True {
|
||||
name, _ := profile.GetAttribute(attr.GetLocalScope(constants.Name))
|
||||
profile.SetAttribute(attr.GetPublicScope(constants.Name), name)
|
||||
profile.SetAttribute(attr.GetPublicScope(constants.Picture), ImageToString(NewImage(RandomProfileImage(onion), TypeImageDistro)))
|
||||
}
|
||||
if e.Data[event.Status] != event.StorageRunning || e.Data[event.Created] == event.True {
|
||||
profile.SetAttribute(attr.GetLocalScope(constants.PeerOnline), event.False)
|
||||
eh.app.AddPeerPlugin(onion, plugins.CONNECTIONRETRY)
|
||||
eh.app.AddPeerPlugin(onion, plugins.NETWORKCHECK)
|
||||
|
||||
// If the user has chosen to block unknown profiles
|
||||
// then explicitly configure the protocol engine to do so..
|
||||
if ReadGlobalSettings().BlockUnknownConnections {
|
||||
profile.BlockUnknownConnections()
|
||||
} else {
|
||||
// For completeness
|
||||
profile.AllowUnknownConnections()
|
||||
}
|
||||
|
||||
// Start up the Profile
|
||||
profile.Listen()
|
||||
profile.StartPeersConnections()
|
||||
if _, err := groups.ExperimentGate(ReadGlobalSettings().Experiments); err == nil {
|
||||
profile.StartServerConnections()
|
||||
}
|
||||
}
|
||||
|
||||
nick, exists := profile.GetAttribute(attr.GetPublicScope(constants.Name))
|
||||
if !exists {
|
||||
nick = onion
|
||||
}
|
||||
|
||||
picVal, ok := profile.GetAttribute(attr.GetPublicScope(constants.Picture))
|
||||
if !ok {
|
||||
picVal = ImageToString(NewImage(RandomProfileImage(onion), TypeImageDistro))
|
||||
}
|
||||
pic, err := StringToImage(picVal)
|
||||
if err != nil {
|
||||
pic = NewImage(RandomProfileImage(onion), TypeImageDistro)
|
||||
}
|
||||
picPath := GetPicturePath(pic)
|
||||
|
||||
//tag, _ := profile.GetAttribute(app.AttributeTag)
|
||||
|
||||
online, _ := profile.GetAttribute(attr.GetLocalScope(constants.PeerOnline))
|
||||
|
||||
e.Data[constants.Name] = nick
|
||||
e.Data[constants.Picture] = picPath
|
||||
e.Data["Online"] = online
|
||||
|
||||
var contacts []Contact
|
||||
var servers []groups.Server
|
||||
for _, contact := range profile.GetContacts() {
|
||||
|
||||
// Only compile the server info if we have enabled the experiment...
|
||||
// Note that this means that this info can become stale if when first loaded the experiment
|
||||
// has been disabled and then is later re-enabled. As such we need to ensure that this list is
|
||||
// re-fetched when the group experiment is enabled via a dedicated ListServerInfo event...
|
||||
if profile.GetContact(contact).IsServer() {
|
||||
groupHandler, err := groups.ExperimentGate(ReadGlobalSettings().Experiments)
|
||||
if err == nil {
|
||||
servers = append(servers, groupHandler.GetServerInfo(contact, profile))
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
contactInfo := profile.GetContact(contact)
|
||||
ph := NewPeerHelper(profile)
|
||||
name := ph.GetNick(contact)
|
||||
cpicPath := ph.GetProfilePic(contact)
|
||||
saveHistory, set := contactInfo.GetAttribute(event.SaveHistoryKey)
|
||||
if !set {
|
||||
saveHistory = event.DeleteHistoryDefault
|
||||
}
|
||||
contacts = append(contacts, Contact{
|
||||
Name: name,
|
||||
Onion: contactInfo.Onion,
|
||||
Status: contactInfo.State,
|
||||
Picture: cpicPath,
|
||||
Authorization: string(contactInfo.Authorization),
|
||||
SaveHistory: saveHistory,
|
||||
Messages: contactInfo.Timeline.Len(),
|
||||
Unread: 0,
|
||||
LastMessage: strconv.Itoa(getLastMessageTime(&contactInfo.Timeline)),
|
||||
IsGroup: false,
|
||||
})
|
||||
}
|
||||
|
||||
// We compile and send the groups regardless of the experiment flag, and hide them in the UI
|
||||
for _, groupId := range profile.GetGroups() {
|
||||
group := profile.GetGroup(groupId)
|
||||
|
||||
// Check that the group is cryptographically valid
|
||||
if !group.CheckGroup() {
|
||||
continue
|
||||
}
|
||||
|
||||
ph := NewPeerHelper(profile)
|
||||
cpicPath := ph.GetProfilePic(groupId)
|
||||
|
||||
authorization := model.AuthUnknown
|
||||
if group.Accepted {
|
||||
authorization = model.AuthApproved
|
||||
}
|
||||
|
||||
contacts = append(contacts, Contact{
|
||||
Name: ph.GetNick(groupId),
|
||||
Onion: group.GroupID,
|
||||
Status: group.State,
|
||||
Picture: cpicPath,
|
||||
Authorization: string(authorization),
|
||||
SaveHistory: event.SaveHistoryConfirmed,
|
||||
Messages: group.Timeline.Len(),
|
||||
Unread: 0,
|
||||
LastMessage: strconv.Itoa(getLastMessageTime(&group.Timeline)),
|
||||
IsGroup: true,
|
||||
GroupServer: group.GroupServer,
|
||||
})
|
||||
}
|
||||
|
||||
bytes, _ := json.Marshal(contacts)
|
||||
e.Data["ContactsJson"] = string(bytes)
|
||||
|
||||
// Marshal the server list into the new peer event...
|
||||
serversListBytes, _ := json.Marshal(servers)
|
||||
e.Data[groups.ServerList] = string(serversListBytes)
|
||||
|
||||
log.Debugf("contactsJson %v", e.Data["ContactsJson"])
|
||||
}
|
||||
|
||||
// We compile and send the groups regardless of the experiment flag, and hide them in the UI
|
||||
for _, groupId := range profile.GetGroups() {
|
||||
group := profile.GetGroup(groupId)
|
||||
|
||||
// Check that the group is cryptographically valid
|
||||
if !group.CheckGroup() {
|
||||
continue
|
||||
}
|
||||
|
||||
ph := NewPeerHelper(profile)
|
||||
cpicPath := ph.GetProfilePic(groupId)
|
||||
|
||||
authorization := model.AuthUnknown
|
||||
if group.Accepted {
|
||||
authorization = model.AuthApproved
|
||||
}
|
||||
|
||||
contacts = append(contacts, Contact{
|
||||
Name: ph.GetNick(groupId),
|
||||
Onion: group.GroupID,
|
||||
Status: group.State,
|
||||
Picture: cpicPath,
|
||||
Authorization: string(authorization),
|
||||
SaveHistory: event.SaveHistoryConfirmed,
|
||||
Messages: group.Timeline.Len(),
|
||||
Unread: 0,
|
||||
LastMessage: strconv.Itoa(getLastMessageTime(&group.Timeline)),
|
||||
IsGroup: true,
|
||||
GroupServer: group.GroupServer,
|
||||
})
|
||||
}
|
||||
|
||||
bytes, _ := json.Marshal(contacts)
|
||||
e.Data["ContactsJson"] = string(bytes)
|
||||
|
||||
// Marshal the server list into the new peer event...
|
||||
serversListBytes, _ := json.Marshal(servers)
|
||||
e.Data[groups.ServerList] = string(serversListBytes)
|
||||
|
||||
log.Infof("contactsJson %v", e.Data["ContactsJson"])
|
||||
}
|
||||
|
||||
json, _ := json.Marshal(e)
|
||||
|
@ -215,74 +229,80 @@ func (eh *EventHandler) handleAppBusEvent(e *event.Event) string {
|
|||
|
||||
// handleProfileEvent enriches Profile events so they are usable with out further data fetches
|
||||
func (eh *EventHandler) handleProfileEvent(ev *EventProfileEnvelope) string {
|
||||
if eh.app == nil {
|
||||
log.Errorf("eh.app == nil in handleProfileEvent... this shouldnt happen?")
|
||||
} else {
|
||||
peer := eh.app.GetPeer(ev.Profile)
|
||||
ph := NewPeerHelper(peer)
|
||||
log.Debugf("New Profile Event to Handle: %v", ev)
|
||||
switch ev.Event.EventType {
|
||||
|
||||
peer := eh.app.GetPeer(ev.Profile)
|
||||
ph := NewPeerHelper(peer)
|
||||
log.Debugf("New Profile Event to Handle: %v", ev)
|
||||
switch ev.Event.EventType {
|
||||
/*
|
||||
TODO: still handle this somewhere - network info from plugin Network check
|
||||
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)
|
||||
}*/
|
||||
|
||||
/*
|
||||
TODO: still handle this somewhere - network info from plugin Network check
|
||||
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
|
||||
// only needs contact nickname and picture, for displaying on popup notifications
|
||||
ev.Event.Data["Nick"] = ph.GetNick(ev.Event.Data["RemotePeer"])
|
||||
ev.Event.Data["Picture"] = ph.GetProfilePic(ev.Event.Data["RemotePeer"])
|
||||
case event.PeerAcknowledgement:
|
||||
// No enrichement required
|
||||
case event.PeerCreated:
|
||||
handle := ev.Event.Data[event.RemotePeer]
|
||||
err := EnrichNewPeer(handle, ph, ev)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
case event.GroupCreated:
|
||||
// This event should only happen after we have validated the invite, as such the error
|
||||
// condition *should* never happen.
|
||||
|
||||
groupPic := ph.GetProfilePic(ev.Event.Data[event.GroupID])
|
||||
ev.Event.Data["PicturePath"] = groupPic
|
||||
ev.Event.Data["GroupName"] = ph.GetNick(ev.Event.Data[event.GroupID])
|
||||
|
||||
case event.NewGroup:
|
||||
// This event should only happen after we have validated the invite, as such the error
|
||||
// condition *should* never happen.
|
||||
serializedInvite := ev.Event.Data[event.GroupInvite]
|
||||
if invite, err := model.ValidateInvite(serializedInvite); err == nil {
|
||||
groupPic := ph.GetProfilePic(invite.GroupID)
|
||||
ev.Event.Data["PicturePath"] = groupPic
|
||||
} else {
|
||||
log.Errorf("received a new group event which contained an invalid invite %v. this should never happen and likely means there is a bug in cwtch. Please file a ticket @ https://git.openprivcy.ca/cwtch.im/cwtch", err)
|
||||
return ""
|
||||
}
|
||||
case event.PeerStateChange:
|
||||
cxnState := connections.ConnectionStateToType()[ev.Event.Data[event.ConnectionState]]
|
||||
contact := peer.GetContact(ev.Event.Data[event.RemotePeer])
|
||||
|
||||
if cxnState == connections.AUTHENTICATED && contact == nil {
|
||||
peer.AddContact(ev.Event.Data[event.RemotePeer], ev.Event.Data[event.RemotePeer], model.AuthUnknown)
|
||||
return ""
|
||||
}
|
||||
|
||||
if contact != nil {
|
||||
// No enrichment needed
|
||||
//uiManager.UpdateContactStatus(contact.Onion, int(cxnState), false)
|
||||
if cxnState == connections.AUTHENTICATED {
|
||||
// if known and authed, get vars
|
||||
peer.SendGetValToPeer(ev.Event.Data[event.RemotePeer], attr.PublicScope, constants.Name)
|
||||
peer.SendGetValToPeer(ev.Event.Data[event.RemotePeer], attr.PublicScope, constants.Picture)
|
||||
case event.NewMessageFromPeer: //event.TimestampReceived, event.RemotePeer, event.Data
|
||||
// only needs contact nickname and picture, for displaying on popup notifications
|
||||
ev.Event.Data["Nick"] = ph.GetNick(ev.Event.Data["RemotePeer"])
|
||||
ev.Event.Data["Picture"] = ph.GetProfilePic(ev.Event.Data["RemotePeer"])
|
||||
case event.NewMessageFromGroup:
|
||||
// only needs contact nickname and picture, for displaying on popup notifications
|
||||
ev.Event.Data["Nick"] = ph.GetNick(ev.Event.Data[event.GroupID])
|
||||
ev.Event.Data["Picture"] = ph.GetProfilePic(ev.Event.Data[event.GroupID])
|
||||
case event.PeerAcknowledgement:
|
||||
// No enrichement required
|
||||
case event.PeerCreated:
|
||||
handle := ev.Event.Data[event.RemotePeer]
|
||||
err := EnrichNewPeer(handle, ph, ev)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
case event.GroupCreated:
|
||||
// This event should only happen after we have validated the invite, as such the error
|
||||
// condition *should* never happen.
|
||||
|
||||
groupPic := ph.GetProfilePic(ev.Event.Data[event.GroupID])
|
||||
ev.Event.Data["PicturePath"] = groupPic
|
||||
ev.Event.Data["GroupName"] = ph.GetNick(ev.Event.Data[event.GroupID])
|
||||
|
||||
case event.NewGroup:
|
||||
// This event should only happen after we have validated the invite, as such the error
|
||||
// condition *should* never happen.
|
||||
serializedInvite := ev.Event.Data[event.GroupInvite]
|
||||
if invite, err := model.ValidateInvite(serializedInvite); err == nil {
|
||||
groupPic := ph.GetProfilePic(invite.GroupID)
|
||||
ev.Event.Data["PicturePath"] = groupPic
|
||||
} else {
|
||||
log.Errorf("received a new group event which contained an invalid invite %v. this should never happen and likely means there is a bug in cwtch. Please file a ticket @ https://git.openprivcy.ca/cwtch.im/cwtch", err)
|
||||
return ""
|
||||
}
|
||||
case event.PeerStateChange:
|
||||
cxnState := connections.ConnectionStateToType()[ev.Event.Data[event.ConnectionState]]
|
||||
contact := peer.GetContact(ev.Event.Data[event.RemotePeer])
|
||||
|
||||
if cxnState == connections.AUTHENTICATED && contact == nil {
|
||||
peer.AddContact(ev.Event.Data[event.RemotePeer], ev.Event.Data[event.RemotePeer], model.AuthUnknown)
|
||||
return ""
|
||||
}
|
||||
|
||||
if contact != nil {
|
||||
// No enrichment needed
|
||||
//uiManager.UpdateContactStatus(contact.Onion, int(cxnState), false)
|
||||
if cxnState == connections.AUTHENTICATED {
|
||||
// if known and authed, get vars
|
||||
peer.SendGetValToPeer(ev.Event.Data[event.RemotePeer], attr.PublicScope, constants.Name)
|
||||
peer.SendGetValToPeer(ev.Event.Data[event.RemotePeer], attr.PublicScope, constants.Picture)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case event.NewRetValMessageFromPeer:
|
||||
// auto handled event means the setting is already done, we're just deciding if we need to tell the UI
|
||||
|
@ -298,6 +318,7 @@ func (eh *EventHandler) handleProfileEvent(ev *EventProfileEnvelope) string {
|
|||
return ""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
json, _ := json.Marshal(unwrap(ev))
|
||||
|
@ -335,18 +356,21 @@ func (eh *EventHandler) startHandlingPeer(onion string) {
|
|||
eventBus.Subscribe(event.ChangePasswordError, q)
|
||||
eventBus.Subscribe(event.NewRetValMessageFromPeer, q)
|
||||
eventBus.Subscribe(event.SetAttribute, q)
|
||||
eh.profileQueues[onion] = q
|
||||
|
||||
go eh.forwardProfileMessages(onion, q)
|
||||
|
||||
}
|
||||
|
||||
func (eh *EventHandler) forwardProfileMessages(onion string, q event.Queue) {
|
||||
log.Infof("Launching Forwarding Goroutine for %v", onion)
|
||||
// TODO: graceful shutdown, via an injected event of special QUIT type exiting loop/go routine
|
||||
for {
|
||||
e := q.Next()
|
||||
ev := EventProfileEnvelope{Event: e, Profile: onion}
|
||||
eh.profileEvents <- ev
|
||||
if ev.Event.EventType == event.Shutdown {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -87,6 +87,8 @@ func (p *PeerHelper) GetNick(id string) string {
|
|||
nick, exists = p.peer.GetContactAttribute(id, attr.GetPeerScope(constants.Name))
|
||||
if !exists {
|
||||
nick = "[" + id + "]"
|
||||
// re-request
|
||||
p.peer.SendGetValToPeer(id, attr.PublicScope, constants.Name)
|
||||
}
|
||||
}
|
||||
return nick
|
||||
|
@ -284,7 +286,7 @@ func EnrichNewPeer(handle string, ph *PeerHelper, ev *EventProfileEnvelope) erro
|
|||
}
|
||||
} else {
|
||||
// could be a server?
|
||||
log.Infof("sorry, unable to handle AddContact(%v)", handle)
|
||||
log.Debugf("sorry, unable to handle AddContact(%v)", handle)
|
||||
return errors.New("not a peer or group")
|
||||
}
|
||||
return nil
|
||||
|
|
|
@ -31,6 +31,8 @@ type GlobalSettings struct {
|
|||
BlockUnknownConnections bool
|
||||
StateRootPane int
|
||||
FirstTime bool
|
||||
UIColumnModePortrait string
|
||||
UIColumnModeLandscape string
|
||||
}
|
||||
|
||||
var DefaultGlobalSettings = GlobalSettings{
|
||||
|
@ -42,6 +44,8 @@ var DefaultGlobalSettings = GlobalSettings{
|
|||
StateRootPane: 0,
|
||||
FirstTime: true,
|
||||
BlockUnknownConnections: false,
|
||||
UIColumnModePortrait: "DualpaneMode.Single",
|
||||
UIColumnModeLandscape: "DualpaneMode.CopyPortrait",
|
||||
}
|
||||
|
||||
func InitGlobalSettingsFile(directory string, password string) error {
|
||||
|
|
Loading…
Reference in New Issue