2019-06-05 20:40:55 +00:00
package app
import (
2019-08-02 01:09:01 +00:00
"cwtch.im/cwtch/app/plugins"
2019-06-05 20:40:55 +00:00
"cwtch.im/cwtch/event"
"cwtch.im/cwtch/model"
"cwtch.im/cwtch/protocol/connections"
"cwtch.im/cwtch/storage"
2019-08-08 18:39:38 +00:00
"cwtch.im/tapir/primitives"
2020-02-10 22:09:24 +00:00
"git.openprivacy.ca/openprivacy/connectivity"
"git.openprivacy.ca/openprivacy/log"
2019-06-05 20:40:55 +00:00
"path"
2019-07-10 20:30:24 +00:00
"strconv"
2019-12-13 19:34:59 +00:00
"sync"
2019-06-05 20:40:55 +00:00
)
type applicationService struct {
applicationBridge
2019-07-10 20:30:24 +00:00
appletACN
2019-08-02 01:09:01 +00:00
appletPlugins
2019-06-05 20:40:55 +00:00
storage map [ string ] storage . ProfileStore
engines map [ string ] connections . Engine
2019-12-13 19:34:59 +00:00
asmutex sync . Mutex
2019-06-05 20:40:55 +00:00
}
// 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 {
2019-07-10 20:30:24 +00:00
appService := & applicationService { storage : make ( map [ string ] storage . ProfileStore ) , engines : make ( map [ string ] connections . Engine ) , applicationBridge : applicationBridge { applicationCore : * newAppCore ( appDirectory ) , bridge : bridge } }
2019-07-19 17:27:50 +00:00
2019-09-26 23:43:34 +00:00
appService . appletACN . init ( acn , appService . getACNStatusHandler ( ) )
2019-06-05 20:40:55 +00:00
appService . handle = appService . handleEvent
go appService . listen ( )
2019-06-21 21:50:43 +00:00
log . Infoln ( "Created new App Service" )
2019-06-05 20:40:55 +00:00
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 ]
2019-12-10 23:45:43 +00:00
tag := ev . Data [ event . Data ]
as . createPeer ( profileName , password , tag )
case event . DeletePeer :
onion := ev . Data [ event . Identity ]
as . deletePeer ( onion )
message := event . IPCMessage { Dest : DestApp , Message : * ev }
as . bridge . Write ( & message )
2019-08-02 01:09:01 +00:00
case event . AddPeerPlugin :
onion := ev . Data [ event . Identity ]
pluginID , _ := strconv . Atoi ( ev . Data [ event . Data ] )
2019-10-31 23:05:01 +00:00
as . AddPlugin ( onion , plugins . PluginID ( pluginID ) , as . eventBuses [ onion ] , as . acn )
2019-06-05 20:40:55 +00:00
case event . LoadProfiles :
password := ev . Data [ event . Password ]
as . loadProfiles ( password )
2019-07-19 17:27:50 +00:00
case event . ReloadClient :
for _ , storage := range as . storage {
2020-01-13 22:11:00 +00:00
peerMsg := * storage . GetNewPeerMessage ( )
peerMsg . Data [ event . Status ] = event . StorageRunning
2020-11-02 22:35:11 +00:00
peerMsg . Data [ event . Created ] = event . False
2020-01-13 22:11:00 +00:00
message := event . IPCMessage { Dest : DestApp , Message : peerMsg }
2019-07-19 17:27:50 +00:00
as . bridge . Write ( & message )
}
message := event . IPCMessage { Dest : DestApp , Message : event . NewEventList ( event . ReloadDone ) }
as . bridge . Write ( & message )
case event . ReloadPeer :
onion := ev . Data [ event . Identity ]
events := as . storage [ onion ] . GetStatusMessages ( )
for _ , ev := range events {
message := event . IPCMessage { Dest : onion , Message : * ev }
as . bridge . Write ( & message )
}
2019-09-26 23:43:34 +00:00
case event . GetACNStatus :
prog , status := as . acn . GetBootstrapStatus ( )
as . getACNStatusHandler ( ) ( prog , status )
2019-07-19 17:27:50 +00:00
case event . ShutdownPeer :
onion := ev . Data [ event . Identity ]
as . ShutdownPeer ( onion )
2019-06-05 20:40:55 +00:00
}
}
2019-12-10 23:45:43 +00:00
func ( as * applicationService ) createPeer ( name , password , tag string ) {
2019-06-05 20:40:55 +00:00
log . Infof ( "app Service create peer %v %v\n" , name , password )
2019-11-30 02:11:12 +00:00
profile , err := as . applicationCore . CreatePeer ( name )
2019-06-05 20:40:55 +00:00
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
}
2019-12-10 23:45:43 +00:00
if tag != "" {
profile . SetAttribute ( AttributeTag , tag )
}
2020-01-13 22:11:00 +00:00
profileStore := storage . CreateProfileWriterStore ( as . eventBuses [ profile . Onion ] , path . Join ( as . directory , "profiles" , profile . LocalID ) , password , profile )
2019-06-05 20:40:55 +00:00
2020-06-16 00:16:04 +00:00
peerAuthorizations := profile . ContactsAuthorizations ( )
2019-06-05 20:40:55 +00:00
// TODO: Would be nice if ProtocolEngine did not need to explicitly be given the Private Key.
2019-08-08 18:39:38 +00:00
identity := primitives . InitializeIdentity ( profile . Name , & profile . Ed25519PrivateKey , & profile . Ed25519PublicKey )
2020-06-16 00:16:04 +00:00
engine := connections . NewProtocolEngine ( identity , profile . Ed25519PrivateKey , as . acn , as . eventBuses [ profile . Onion ] , peerAuthorizations )
2019-06-05 20:40:55 +00:00
as . storage [ profile . Onion ] = profileStore
as . engines [ profile . Onion ] = engine
2020-01-13 22:11:00 +00:00
peerMsg := * profileStore . GetNewPeerMessage ( )
2020-11-02 22:35:11 +00:00
peerMsg . Data [ event . Created ] = event . True
2020-01-13 22:11:00 +00:00
peerMsg . Data [ event . Status ] = event . StorageNew
message := event . IPCMessage { Dest : DestApp , Message : peerMsg }
2019-06-05 20:40:55 +00:00
as . bridge . Write ( & message )
}
func ( as * applicationService ) loadProfiles ( password string ) {
count := 0
2019-07-19 17:27:50 +00:00
as . applicationCore . LoadProfiles ( password , false , func ( profile * model . Profile , profileStore storage . ProfileStore ) {
2019-07-06 00:46:51 +00:00
as . eventBuses [ profile . Onion ] = event . IPCEventManagerFrom ( as . bridge , profile . Onion , as . eventBuses [ profile . Onion ] )
2019-07-19 17:27:50 +00:00
2020-06-16 00:16:04 +00:00
peerAuthorizations := profile . ContactsAuthorizations ( )
2019-08-08 18:39:38 +00:00
identity := primitives . InitializeIdentity ( profile . Name , & profile . Ed25519PrivateKey , & profile . Ed25519PublicKey )
2020-06-16 00:16:04 +00:00
engine := connections . NewProtocolEngine ( identity , profile . Ed25519PrivateKey , as . acn , as . eventBuses [ profile . Onion ] , peerAuthorizations )
2019-12-13 19:34:59 +00:00
as . asmutex . Lock ( )
2019-06-05 20:40:55 +00:00
as . storage [ profile . Onion ] = profileStore
as . engines [ profile . Onion ] = engine
2019-12-13 19:34:59 +00:00
as . asmutex . Unlock ( )
2020-01-13 22:11:00 +00:00
peerMsg := * profileStore . GetNewPeerMessage ( )
2020-11-02 22:35:11 +00:00
peerMsg . Data [ event . Created ] = event . False
2020-01-13 22:11:00 +00:00
peerMsg . Data [ event . Status ] = event . StorageNew
message := event . IPCMessage { Dest : DestApp , Message : peerMsg }
2019-06-05 20:40:55 +00:00
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 )
}
}
2019-09-26 23:43:34 +00:00
func ( as * applicationService ) getACNStatusHandler ( ) func ( int , string ) {
return func ( progress int , status string ) {
progStr := strconv . Itoa ( progress )
as . bridge . Write ( & event . IPCMessage { Dest : DestApp , Message : event . NewEventList ( event . ACNStatus , event . Progreess , progStr , event . Status , status ) } )
2020-02-03 18:46:15 +00:00
as . applicationCore . coremutex . Lock ( )
defer as . applicationCore . coremutex . Unlock ( )
2019-09-26 23:43:34 +00:00
for _ , bus := range as . eventBuses {
bus . Publish ( event . NewEventList ( event . ACNStatus , event . Progreess , progStr , event . Status , status ) )
}
}
}
2019-12-10 23:45:43 +00:00
func ( as * applicationService ) deletePeer ( onion string ) {
2019-12-13 19:34:59 +00:00
as . asmutex . Lock ( )
defer as . asmutex . Unlock ( )
2019-12-10 23:45:43 +00:00
as . appletPlugins . ShutdownPeer ( onion )
as . plugins . Delete ( onion )
as . engines [ onion ] . Shutdown ( )
delete ( as . engines , onion )
as . storage [ onion ] . Shutdown ( )
as . storage [ onion ] . Delete ( )
delete ( as . storage , onion )
as . applicationCore . DeletePeer ( onion )
}
2019-07-19 17:27:50 +00:00
func ( as * applicationService ) ShutdownPeer ( onion string ) {
as . engines [ onion ] . Shutdown ( )
delete ( as . engines , onion )
as . storage [ onion ] . Shutdown ( )
delete ( as . storage , onion )
as . eventBuses [ onion ] . Shutdown ( )
delete ( as . eventBuses , onion )
}
2019-06-05 20:40:55 +00:00
// Shutdown shuts down the application Service and all peer related backend parts
func ( as * applicationService ) Shutdown ( ) {
2019-10-31 23:05:01 +00:00
log . Debugf ( "shutting down application service..." )
as . appletPlugins . Shutdown ( )
2019-06-05 20:40:55 +00:00
for id := range as . engines {
2019-10-31 23:05:01 +00:00
log . Debugf ( "shutting down application service peer engine %v" , id )
2019-07-19 17:27:50 +00:00
as . ShutdownPeer ( id )
2019-06-05 20:40:55 +00:00
}
}