package app import ( "cwtch.im/cwtch/event" "cwtch.im/cwtch/model" "cwtch.im/cwtch/protocol/connections" "cwtch.im/cwtch/storage" "git.openprivacy.ca/openprivacy/libricochet-go/connectivity" "git.openprivacy.ca/openprivacy/libricochet-go/identity" "git.openprivacy.ca/openprivacy/libricochet-go/log" "path" ) const ( // DestApp should be used as a destination for IPC messages that are for the application itself an not a peer DestApp = "app" ) type applicationService struct { applicationBridge storage map[string]storage.ProfileStore engines map[string]connections.Engine } // ApplicationService is the back end of an application that manages engines and writing storage and communicates to an ApplicationClient by an IPCBridge type ApplicationService interface { Shutdown() } // NewAppService returns an ApplicationService that runs the backend of an app and communicates with a client by the supplied IPCBridge func NewAppService(acn connectivity.ACN, appDirectory string, bridge event.IPCBridge) ApplicationService { appService := &applicationService{storage: make(map[string]storage.ProfileStore), engines: make(map[string]connections.Engine), applicationBridge: applicationBridge{applicationCore: *newAppCore(acn, appDirectory), bridge: bridge}} appService.handle = appService.handleEvent // Set up IPC // attach to listener go appService.listen() return appService } func (as *applicationService) handleEvent(ev *event.Event) { log.Infof("app Service handleEvent %v\n", ev.EventType) switch ev.EventType { case event.CreatePeer: profileName := ev.Data[event.ProfileName] password := ev.Data[event.Password] as.createPeer(profileName, password) case event.LoadProfiles: password := ev.Data[event.Password] as.loadProfiles(password) } } func (as *applicationService) createPeer(name, password string) { log.Infof("app Service create peer %v %v\n", name, password) profile, err := as.applicationCore.CreatePeer(name, password) as.eventBuses[profile.Onion] = event.IPCEventManagerFrom(as.bridge, profile.Onion, as.eventBuses[profile.Onion]) if err != nil { log.Errorf("Could not create Peer: %v\n", err) message := event.IPCMessage{Dest: DestApp, Message: event.NewEventList(event.PeerError, event.Error, err.Error())} as.bridge.Write(&message) return } profileStore := storage.NewProfileWriterStore(as.eventBuses[profile.Onion], path.Join(as.directory, "profiles", profile.LocalID), password, profile) blockedPeers := profile.BlockedPeers() // TODO: Would be nice if ProtocolEngine did not need to explicitly be given the Private Key. identity := identity.InitializeV3(profile.Name, &profile.Ed25519PrivateKey, &profile.Ed25519PublicKey) engine := connections.NewProtocolEngine(identity, profile.Ed25519PrivateKey, as.acn, as.eventBuses[profile.Onion], blockedPeers) as.storage[profile.Onion] = profileStore as.engines[profile.Onion] = engine message := event.IPCMessage{Dest: DestApp, Message: event.NewEvent(event.NewPeer, map[event.Field]string{event.Identity: profile.LocalID, event.Password: password})} as.bridge.Write(&message) } func (as *applicationService) loadProfiles(password string) { count := 0 as.applicationCore.LoadProfiles(password, func(profile *model.Profile, profileStore storage.ProfileStore) { blockedPeers := profile.BlockedPeers() identity := identity.InitializeV3(profile.Name, &profile.Ed25519PrivateKey, &profile.Ed25519PublicKey) engine := connections.NewProtocolEngine(identity, profile.Ed25519PrivateKey, as.acn, as.eventBuses[profile.Onion], blockedPeers) as.mutex.Lock() as.storage[profile.Onion] = profileStore as.engines[profile.Onion] = engine as.mutex.Unlock() message := event.IPCMessage{Dest: DestApp, Message: event.NewEvent(event.NewPeer, map[event.Field]string{event.Identity: profile.LocalID, event.Password: password})} as.bridge.Write(&message) count++ }) if count == 0 { message := event.IPCMessage{Dest: DestApp, Message: event.NewEventList(event.AppError, event.Error, event.AppErrLoaded0)} as.bridge.Write(&message) } } // Shutdown shuts down the application Service and all peer related backend parts func (as *applicationService) Shutdown() { for id := range as.engines { as.engines[id].Shutdown() as.storage[id].Shutdown() as.eventBuses[id].Shutdown() } }