cwtch/app/appService.go

116 lines
4.6 KiB
Go
Raw Normal View History

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"
"strconv"
)
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
appletACN
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(appDirectory), bridge: bridge}}
fn := func(progress int, status string) {
progStr := strconv.Itoa(progress)
appService.bridge.Write(&event.IPCMessage{Dest: DestApp, Message: event.NewEventList(event.ACNStatus, event.Progreess, progStr, event.Status, status)})
}
appService.appletACN.init(acn, fn)
appService.handle = appService.handleEvent
go appService.listen()
log.Infoln("Created new App Service")
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) {
as.eventBuses[profile.Onion] = event.IPCEventManagerFrom(as.bridge, profile.Onion, as.eventBuses[profile.Onion])
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()
}
}