diff --git a/lib.go b/lib.go index 866700a..fa98476 100644 --- a/lib.go +++ b/lib.go @@ -58,12 +58,21 @@ type ChatMessage struct { func c_StartCwtch(dir_c *C.char, len C.int, tor_c *C.char, torLen C.int) int8 { dir := C.GoStringN(dir_c, len) tor := C.GoStringN(tor_c, torLen) - return StartCwtch(dir, tor) + return int8(StartCwtch(dir, tor)) } -func StartCwtch(appDir string, torPath string) int8 { +// StartCwtch starts cwtch in the library and initlaizes all data structures +// GetAppbusEvents is always safe to use +// the rest of functions are unsafe until the CwtchStarted event has been received indicating StartCwtch has completed +// returns: +// 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) + // 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" { fh, err := os.Open(torPath) if err != nil { @@ -73,7 +82,11 @@ func StartCwtch(appDir string, torPath string) int8 { } _ = fh.Close() } + go _startCwtch(appDir, torPath) + return 0 +} +func _startCwtch(appDir string, torPath string) { // Exclude Tapir wire Messages (We need a TRACE level) log.ExcludeFromPattern("service.go") @@ -100,8 +113,8 @@ func StartCwtch(appDir string, torPath string) int8 { acn, err := tor.NewTorACNWithAuth(path.Join(appDir, "/.tor"), torPath, controlPort, tor.HashedPasswordAuthenticator{Password: base64.StdEncoding.EncodeToString(key)}) if err != nil { log.Errorf("\nError connecting to Tor replacing with ErrorACN: %v\n", err) - // Replace the nil acn with a stub that will do nothing but report this error to the user... - acn = new(utils.ErrorACN) + eventHandler.PublishAppEvent(event.NewEventList(utils.CwtchStartError, event.Error, err)) + return } globalACN = acn newApp := app.NewApp(acn, appDir) @@ -111,7 +124,7 @@ func StartCwtch(appDir string, torPath string) int8 { newApp.GetPrimaryBus().Subscribe(utils.SetLoggingLevel, acnQueue) newApp.GetPrimaryBus().Subscribe(event.AppError, acnQueue) - eventHandler = utils.NewEventHandler(newApp) + eventHandler.HandleApp(newApp) peer.DefaultEventsToHandle = []event.Type{ event.EncryptedGroupMessage, @@ -137,7 +150,7 @@ func StartCwtch(appDir string, torPath string) int8 { // 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") - return 0 + application.GetPrimaryBus().Publish(event.NewEvent(utils.CwtchStarted, map[event.Field]string{})) } //export c_ReconnectCwtchForeground @@ -154,20 +167,6 @@ func ReconnectCwtchForeground() { } } -//export c_ACNEvents -func c_ACNEvents() *C.char { - return C.CString(ACNEvents()) -} - -func ACNEvents() string { - select { - case myevent := <-acnQueue.OutChan(): - return fmt.Sprintf("%v", myevent) - default: - return "" - } -} - //export c_SendAppEvent // A generic method for Rebroadcasting App Events from a UI func c_SendAppEvent(json_ptr *C.char, json_len C.int) { @@ -305,20 +304,6 @@ func GetAppBusEvent() string { return json } -//export c_GetProfileRepaintEvent -func c_GetProfileRepaintEvent() int8 { - if GetProfileRepaintEvent() { - return 1 - } else { - return 0 - } -} - -func GetProfileRepaintEvent() bool { - <-acnQueue.OutChan() - return true -} - type Profile struct { Name string `json:"name"` Onion string `json:"onion"` @@ -356,17 +341,6 @@ func CreateProfile(nick, pass string) { application.CreatePeer(nick, pass) } -//export c_SelectProfile -func c_SelectProfile(onion_ptr *C.char, onion_len C.int) *C.char { - return C.CString(SelectProfile(C.GoStringN(onion_ptr, onion_len))) -} - -func SelectProfile(onion string) string { - contactEventsQueue = event.NewQueue() - application.GetEventBus(onion).Subscribe(event.PeerStateChange, contactEventsQueue) - return "" -} - //export c_LoadProfiles func c_LoadProfiles(passwordPtr *C.char, passwordLen C.int) { LoadProfiles(C.GoStringN(passwordPtr, passwordLen)) diff --git a/utils/errorACN.go b/utils/errorACN.go deleted file mode 100644 index b7ca14f..0000000 --- a/utils/errorACN.go +++ /dev/null @@ -1,50 +0,0 @@ -package utils - -import ( - "errors" - "git.openprivacy.ca/openprivacy/connectivity" - "git.openprivacy.ca/openprivacy/log" - "net" -) - -// ErrorACN is a stub ACN handler used when no other valid ACN can be found. This is a critical error and as such -// this is only used when the only course of action is to close Cwtch and fix the underlying discovery problem... -type ErrorACN struct { -} - -func (e ErrorACN) GetBootstrapStatus() (int, string) { - return -1, "could not find tor" -} - -func (e ErrorACN) WaitTillBootstrapped() { - // instant -} - -func (e ErrorACN) SetStatusCallback(callback func(int, string)) { - callback(-1, "could not find tor please restart cwtch with an active Tor in path") -} - -func (e ErrorACN) Restart() { - // does nothing - log.Errorf("Called Restart() on ErrorACN, which does nothing") -} - -func (e ErrorACN) Open(hostname string) (net.Conn, string, error) { - return nil, "", errors.New("could not find tor") -} - -func (e ErrorACN) Listen(identity connectivity.PrivateKey, port int) (connectivity.ListenService, error) { - return nil, errors.New("could not find tor") -} - -func (e ErrorACN) GetPID() (int, error) { - return 0, errors.New("could not find tor") -} - -func (e ErrorACN) GetVersion() string { - return "could not find tor" -} - -func (e ErrorACN) Close() { - // does nothing -} diff --git a/utils/eventHandler.go b/utils/eventHandler.go index 6a919a5..9eb35c1 100644 --- a/utils/eventHandler.go +++ b/utils/eventHandler.go @@ -23,21 +23,31 @@ type EventHandler struct { app app.Application appBusQueue event.Queue profileEvents chan EventProfileEnvelope - profileQueues map[string]event.Queue } -func NewEventHandler(application app.Application) *EventHandler { - appBusQueue := event.NewQueue() - application.GetPrimaryBus().Subscribe(event.NewPeer, appBusQueue) - application.GetPrimaryBus().Subscribe(event.PeerError, appBusQueue) - application.GetPrimaryBus().Subscribe(event.PeerDeleted, appBusQueue) - application.GetPrimaryBus().Subscribe(event.AppError, appBusQueue) - application.GetPrimaryBus().Subscribe(event.ACNStatus, appBusQueue) - application.GetPrimaryBus().Subscribe(event.ReloadDone, appBusQueue) - application.GetPrimaryBus().Subscribe(event.ACNVersion, appBusQueue) - application.GetPrimaryBus().Subscribe(UpdateGlobalSettings, appBusQueue) - return &EventHandler{app: application, appBusQueue: appBusQueue, profileQueues: make(map[string]event.Queue), profileEvents: make(chan EventProfileEnvelope)} +func NewEventHandler() *EventHandler { + eh := &EventHandler{app: nil, appBusQueue: event.NewQueue(), profileQueues: make(map[string]event.Queue), 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 +// Main use: to signal an error before a cwtch app could be created +func (eh *EventHandler) PublishAppEvent(event event.Event) { + eh.appBusQueue.Publish(event) +} + +func (eh *EventHandler) HandleApp(application app.Application) { + eh.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.AppError, eh.appBusQueue) + application.GetPrimaryBus().Subscribe(event.ACNStatus, eh.appBusQueue) + application.GetPrimaryBus().Subscribe(event.ReloadDone, eh.appBusQueue) + application.GetPrimaryBus().Subscribe(event.ACNVersion, eh.appBusQueue) + application.GetPrimaryBus().Subscribe(UpdateGlobalSettings, eh.appBusQueue) + application.GetPrimaryBus().Subscribe(CwtchStarted, eh.appBusQueue) } func (eh *EventHandler) GetNextEvent() string { @@ -211,7 +221,9 @@ func (eh *EventHandler) handleProfileEvent(ev *EventProfileEnvelope) string { log.Debugf("New Profile Event to Handle: %v", ev) switch ev.Event.EventType { - /*case event.NetworkStatus: + /* + 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) @@ -228,31 +240,12 @@ func (eh *EventHandler) handleProfileEvent(ev *EventProfileEnvelope) string { ev.Event.Data["Picture"] = ph.GetProfilePic(ev.Event.Data["RemotePeer"]) case event.PeerAcknowledgement: // No enrichement required - //Acknowledge(ev.Event.Data[event.RemotePeer], ev.Event.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: handle := ev.Event.Data[event.RemotePeer] err := EnrichNewPeer(handle, ph, ev) if err != nil { return "" } - /* - 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.GroupCreated: // This event should only happen after we have validated the invite, as such the error // condition *should* never happen. @@ -291,45 +284,20 @@ func (eh *EventHandler) handleProfileEvent(ev *EventProfileEnvelope) string { } } - /*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]) + case event.NewRetValMessageFromPeer: + // auto handled event means the setting is already done, we're just deciding if we need to tell the UI + onion := ev.Event.Data[event.RemotePeer] + scope := ev.Event.Data[event.Scope] + path := ev.Event.Data[event.Path] + //val := ev.Event.Data[event.Data] + exists, _ := strconv.ParseBool(ev.Event.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) + if _, exists := peer.GetContactAttribute(onion, attr.GetLocalScope(path)); exists { + // we have a locally set ovverride, don't pass this remote set public scope update to UI + return "" } } - - 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 - */ } json, _ := json.Marshal(unwrap(ev)) diff --git a/utils/settings.go b/utils/settings.go index b068571..87f7e35 100644 --- a/utils/settings.go +++ b/utils/settings.go @@ -12,6 +12,8 @@ import ( ) const ( + CwtchStarted = event.Type("CwtchStarted") + CwtchStartError = event.Type("CwtchStartError") UpdateGlobalSettings = event.Type("UpdateGlobalSettings") )