2018-04-30 21:47:21 +00:00
|
|
|
package app
|
|
|
|
|
|
|
|
import (
|
2022-10-03 20:05:36 +00:00
|
|
|
"cwtch.im/cwtch/app/plugins"
|
|
|
|
"cwtch.im/cwtch/event"
|
2023-01-05 21:52:43 +00:00
|
|
|
"cwtch.im/cwtch/extensions"
|
|
|
|
"cwtch.im/cwtch/functionality/filesharing"
|
2023-07-25 18:12:39 +00:00
|
|
|
"cwtch.im/cwtch/functionality/servers"
|
2022-10-03 20:05:36 +00:00
|
|
|
"cwtch.im/cwtch/model"
|
|
|
|
"cwtch.im/cwtch/model/attr"
|
|
|
|
"cwtch.im/cwtch/model/constants"
|
|
|
|
"cwtch.im/cwtch/peer"
|
|
|
|
"cwtch.im/cwtch/protocol/connections"
|
2023-03-06 21:06:15 +00:00
|
|
|
"cwtch.im/cwtch/settings"
|
2022-10-03 20:05:36 +00:00
|
|
|
"cwtch.im/cwtch/storage"
|
|
|
|
"git.openprivacy.ca/openprivacy/connectivity"
|
|
|
|
"git.openprivacy.ca/openprivacy/log"
|
|
|
|
"os"
|
|
|
|
path "path/filepath"
|
|
|
|
"strconv"
|
|
|
|
"sync"
|
2018-04-30 21:47:21 +00:00
|
|
|
)
|
|
|
|
|
2018-09-21 18:53:10 +00:00
|
|
|
type application struct {
|
2022-10-03 20:05:36 +00:00
|
|
|
eventBuses map[string]event.Manager
|
|
|
|
directory string
|
2022-08-29 01:19:32 +00:00
|
|
|
|
2023-05-01 21:13:39 +00:00
|
|
|
peers map[string]peer.CwtchPeer
|
|
|
|
acn connectivity.ACN
|
|
|
|
plugins sync.Map //map[string] []plugins.Plugin
|
2022-08-29 01:19:32 +00:00
|
|
|
|
2023-04-20 19:18:54 +00:00
|
|
|
engines map[string]connections.Engine
|
|
|
|
appBus event.Manager
|
2023-04-28 21:00:15 +00:00
|
|
|
eventQueue event.Queue
|
2023-04-20 19:18:54 +00:00
|
|
|
appmutex sync.Mutex
|
|
|
|
engineHooks connections.EngineHooks
|
2023-01-25 20:32:26 +00:00
|
|
|
|
2023-03-06 21:06:15 +00:00
|
|
|
settings *settings.GlobalSettingsFile
|
2018-09-21 18:53:10 +00:00
|
|
|
}
|
|
|
|
|
2023-02-28 18:00:32 +00:00
|
|
|
func (app *application) IsFeatureEnabled(experiment string) bool {
|
2023-04-17 19:05:02 +00:00
|
|
|
globalSettings := app.ReadSettings()
|
|
|
|
if globalSettings.ExperimentsEnabled {
|
|
|
|
if status, exists := globalSettings.Experiments[experiment]; exists {
|
2023-02-28 18:00:32 +00:00
|
|
|
return status
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2018-09-21 18:53:10 +00:00
|
|
|
// Application is a full cwtch peer application. It allows management, usage and storage of multiple peers
|
|
|
|
type Application interface {
|
2022-10-03 20:05:36 +00:00
|
|
|
LoadProfiles(password string)
|
2023-02-21 23:55:14 +00:00
|
|
|
CreateProfile(name string, password string, autostart bool)
|
2023-04-20 20:32:36 +00:00
|
|
|
InstallEngineHooks(engineHooks connections.EngineHooks)
|
2022-10-03 20:05:36 +00:00
|
|
|
ImportProfile(exportedCwtchFile string, password string) (peer.CwtchPeer, error)
|
2023-02-27 22:05:52 +00:00
|
|
|
EnhancedImportProfile(exportedCwtchFile string, password string) string
|
2023-02-21 23:55:14 +00:00
|
|
|
DeleteProfile(onion string, currentPassword string)
|
2022-10-03 20:05:36 +00:00
|
|
|
AddPeerPlugin(onion string, pluginID plugins.PluginID)
|
2018-09-21 18:53:10 +00:00
|
|
|
|
2022-10-03 20:05:36 +00:00
|
|
|
GetPrimaryBus() event.Manager
|
|
|
|
GetEventBus(onion string) event.Manager
|
|
|
|
QueryACNStatus()
|
|
|
|
QueryACNVersion()
|
2019-06-05 20:40:55 +00:00
|
|
|
|
2022-12-03 23:48:09 +00:00
|
|
|
ActivateEngines(doListn, doPeers, doServers bool)
|
2023-02-21 23:55:14 +00:00
|
|
|
ActivatePeerEngine(onion string)
|
2022-10-03 20:05:36 +00:00
|
|
|
DeactivatePeerEngine(onion string)
|
2022-08-29 01:19:32 +00:00
|
|
|
|
2023-03-06 21:06:15 +00:00
|
|
|
ReadSettings() settings.GlobalSettings
|
|
|
|
UpdateSettings(settings settings.GlobalSettings)
|
2023-02-28 18:00:32 +00:00
|
|
|
IsFeatureEnabled(experiment string) bool
|
2023-01-25 20:32:26 +00:00
|
|
|
|
2022-10-03 20:05:36 +00:00
|
|
|
ShutdownPeer(string)
|
|
|
|
Shutdown()
|
2019-06-05 20:40:55 +00:00
|
|
|
|
2022-10-03 20:05:36 +00:00
|
|
|
GetPeer(onion string) peer.CwtchPeer
|
|
|
|
ListProfiles() []string
|
2019-06-05 20:40:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// LoadProfileFn is the function signature for a function in an app that loads a profile
|
2021-11-09 23:47:33 +00:00
|
|
|
type LoadProfileFn func(profile peer.CwtchPeer)
|
2019-06-05 20:40:55 +00:00
|
|
|
|
2023-03-06 21:06:15 +00:00
|
|
|
func LoadAppSettings(appDirectory string) *settings.GlobalSettingsFile {
|
2022-10-03 20:05:36 +00:00
|
|
|
log.Debugf("NewApp(%v)\n", appDirectory)
|
|
|
|
os.MkdirAll(path.Join(appDirectory, "profiles"), 0700)
|
2021-12-17 19:42:55 +00:00
|
|
|
|
2023-01-25 20:32:26 +00:00
|
|
|
// Note: we basically presume this doesn't fail. If the file doesn't exist we create it, and as such the
|
|
|
|
// only plausible error conditions are related to file create e.g. low disk space. If that is the case then
|
|
|
|
// many other parts of Cwtch are likely to fail also.
|
2023-04-17 19:05:02 +00:00
|
|
|
globalSettingsFile, err := settings.InitGlobalSettingsFile(appDirectory, DefactoPasswordForUnencryptedProfiles)
|
2023-01-25 20:32:26 +00:00
|
|
|
if err != nil {
|
2023-04-17 19:33:31 +00:00
|
|
|
log.Errorf("error initializing global globalSettingsFile file %s. Global globalSettingsFile might not be loaded or saved", err)
|
2023-01-25 20:32:26 +00:00
|
|
|
}
|
2023-04-17 19:05:02 +00:00
|
|
|
return globalSettingsFile
|
2023-02-21 23:55:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// NewApp creates a new app with some environment awareness and initializes a Tor Manager
|
2023-04-20 20:32:36 +00:00
|
|
|
func NewApp(acn connectivity.ACN, appDirectory string, settings *settings.GlobalSettingsFile) Application {
|
2023-01-25 20:32:26 +00:00
|
|
|
|
2023-04-28 21:00:15 +00:00
|
|
|
app := &application{engines: make(map[string]connections.Engine), eventBuses: make(map[string]event.Manager), directory: appDirectory, appBus: event.NewEventManager(), settings: settings, eventQueue: event.NewQueue()}
|
2022-10-03 20:05:36 +00:00
|
|
|
app.peers = make(map[string]peer.CwtchPeer)
|
2023-04-20 20:36:43 +00:00
|
|
|
app.engineHooks = connections.DefaultEngineHooks{}
|
2022-10-03 20:05:36 +00:00
|
|
|
app.acn = acn
|
|
|
|
statusHandler := app.getACNStatusHandler()
|
|
|
|
acn.SetStatusCallback(statusHandler)
|
|
|
|
acn.SetVersionCallback(app.getACNVersionHandler())
|
|
|
|
prog, status := acn.GetBootstrapStatus()
|
|
|
|
statusHandler(prog, status)
|
2019-07-10 20:30:24 +00:00
|
|
|
|
2023-04-28 21:00:15 +00:00
|
|
|
app.GetPrimaryBus().Subscribe(event.ACNStatus, app.eventQueue)
|
|
|
|
go app.eventHandler()
|
|
|
|
|
2022-10-03 20:05:36 +00:00
|
|
|
return app
|
2018-04-30 21:47:21 +00:00
|
|
|
}
|
|
|
|
|
2023-04-20 20:32:36 +00:00
|
|
|
func (app *application) InstallEngineHooks(engineHooks connections.EngineHooks) {
|
2023-04-20 20:38:54 +00:00
|
|
|
app.appmutex.Lock()
|
|
|
|
defer app.appmutex.Unlock()
|
2023-04-20 20:32:36 +00:00
|
|
|
app.engineHooks = engineHooks
|
|
|
|
}
|
|
|
|
|
2023-03-06 21:06:15 +00:00
|
|
|
func (app *application) ReadSettings() settings.GlobalSettings {
|
2023-01-25 20:32:26 +00:00
|
|
|
app.appmutex.Lock()
|
|
|
|
defer app.appmutex.Unlock()
|
|
|
|
return app.settings.ReadGlobalSettings()
|
|
|
|
}
|
|
|
|
|
2023-03-06 21:06:15 +00:00
|
|
|
func (app *application) UpdateSettings(settings settings.GlobalSettings) {
|
2023-01-25 20:32:26 +00:00
|
|
|
// don't allow any other application changes while settings update
|
|
|
|
app.appmutex.Lock()
|
|
|
|
defer app.appmutex.Unlock()
|
|
|
|
app.settings.WriteGlobalSettings(settings)
|
|
|
|
|
|
|
|
for _, profile := range app.peers {
|
|
|
|
profile.UpdateExperiments(settings.ExperimentsEnabled, settings.Experiments)
|
2023-02-27 21:31:32 +00:00
|
|
|
|
|
|
|
// Explicitly toggle blocking/unblocking of unknown connections for profiles
|
|
|
|
// that have been loaded.
|
|
|
|
if settings.BlockUnknownConnections {
|
|
|
|
profile.BlockUnknownConnections()
|
|
|
|
} else {
|
|
|
|
profile.AllowUnknownConnections()
|
|
|
|
}
|
2023-03-06 21:06:15 +00:00
|
|
|
|
|
|
|
profile.NotifySettingsUpdate(settings)
|
2023-01-25 20:32:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-29 01:19:32 +00:00
|
|
|
// ListProfiles returns a map of onions to their profile's Name
|
|
|
|
func (app *application) ListProfiles() []string {
|
2022-10-03 20:05:36 +00:00
|
|
|
var keys []string
|
|
|
|
|
2023-05-01 21:13:39 +00:00
|
|
|
app.appmutex.Lock()
|
|
|
|
defer app.appmutex.Unlock()
|
2022-10-03 20:05:36 +00:00
|
|
|
for handle := range app.peers {
|
|
|
|
keys = append(keys, handle)
|
|
|
|
}
|
|
|
|
return keys
|
2022-08-29 01:19:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// GetPeer returns a cwtchPeer for a given onion address
|
|
|
|
func (app *application) GetPeer(onion string) peer.CwtchPeer {
|
2023-05-02 20:45:19 +00:00
|
|
|
app.appmutex.Lock()
|
|
|
|
defer app.appmutex.Unlock()
|
2023-04-17 19:05:02 +00:00
|
|
|
if profile, ok := app.peers[onion]; ok {
|
|
|
|
return profile
|
2022-10-03 20:05:36 +00:00
|
|
|
}
|
|
|
|
return nil
|
2022-08-29 01:19:32 +00:00
|
|
|
}
|
|
|
|
|
2023-04-17 19:05:02 +00:00
|
|
|
func (app *application) AddPlugin(peerid string, id plugins.PluginID, bus event.Manager, acn connectivity.ACN) {
|
|
|
|
if _, exists := app.plugins.Load(peerid); !exists {
|
|
|
|
app.plugins.Store(peerid, []plugins.Plugin{})
|
2022-10-03 20:05:36 +00:00
|
|
|
}
|
|
|
|
|
2023-04-17 19:05:02 +00:00
|
|
|
pluginsinf, _ := app.plugins.Load(peerid)
|
2022-10-03 20:05:36 +00:00
|
|
|
peerPlugins := pluginsinf.([]plugins.Plugin)
|
|
|
|
|
2022-12-03 00:23:11 +00:00
|
|
|
for _, plugin := range peerPlugins {
|
|
|
|
if plugin.Id() == id {
|
|
|
|
log.Errorf("trying to add second instance of plugin %v to peer %v", id, peerid)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-03 20:05:36 +00:00
|
|
|
newp, err := plugins.Get(id, bus, acn, peerid)
|
|
|
|
if err == nil {
|
|
|
|
newp.Start()
|
|
|
|
peerPlugins = append(peerPlugins, newp)
|
|
|
|
log.Debugf("storing plugin for %v %v", peerid, peerPlugins)
|
2023-04-17 19:05:02 +00:00
|
|
|
app.plugins.Store(peerid, peerPlugins)
|
2022-10-03 20:05:36 +00:00
|
|
|
} else {
|
|
|
|
log.Errorf("error adding plugin: %v", err)
|
|
|
|
}
|
2022-08-29 01:19:32 +00:00
|
|
|
}
|
|
|
|
|
2023-02-21 23:55:14 +00:00
|
|
|
func (app *application) CreateProfile(name string, password string, autostart bool) {
|
|
|
|
autostartVal := constants.True
|
|
|
|
if !autostart {
|
|
|
|
autostartVal = constants.False
|
|
|
|
}
|
|
|
|
tagVal := constants.ProfileTypeV1Password
|
|
|
|
if password == DefactoPasswordForUnencryptedProfiles {
|
|
|
|
tagVal = constants.ProfileTypeV1DefaultPassword
|
|
|
|
}
|
|
|
|
|
|
|
|
app.CreatePeer(name, password, map[attr.ZonedPath]string{
|
|
|
|
attr.ProfileZone.ConstructZonedPath(constants.Tag): tagVal,
|
|
|
|
attr.ProfileZone.ConstructZonedPath(constants.PeerAutostart): autostartVal,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2023-02-27 21:31:32 +00:00
|
|
|
func (app *application) setupPeer(profile peer.CwtchPeer) {
|
|
|
|
eventBus := event.NewEventManager()
|
|
|
|
app.eventBuses[profile.GetOnion()] = eventBus
|
|
|
|
|
|
|
|
// Initialize the Peer with the Given Event Bus
|
|
|
|
app.peers[profile.GetOnion()] = profile
|
|
|
|
profile.Init(app.eventBuses[profile.GetOnion()])
|
|
|
|
|
|
|
|
// Update the Peer with the Most Recent Experiment State...
|
2023-04-17 19:05:02 +00:00
|
|
|
globalSettings := app.settings.ReadGlobalSettings()
|
|
|
|
profile.UpdateExperiments(globalSettings.ExperimentsEnabled, globalSettings.Experiments)
|
2023-02-27 21:31:32 +00:00
|
|
|
app.registerHooks(profile)
|
|
|
|
|
|
|
|
// Register the Peer With Application Plugins..
|
|
|
|
app.AddPeerPlugin(profile.GetOnion(), plugins.CONNECTIONRETRY) // Now Mandatory
|
2023-04-03 19:44:28 +00:00
|
|
|
app.AddPeerPlugin(profile.GetOnion(), plugins.HEARTBEAT) // Now Mandatory
|
2023-02-27 21:31:32 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2022-12-10 19:50:22 +00:00
|
|
|
func (app *application) CreatePeer(name string, password string, attributes map[attr.ZonedPath]string) {
|
2022-10-03 20:05:36 +00:00
|
|
|
app.appmutex.Lock()
|
|
|
|
defer app.appmutex.Unlock()
|
2021-11-09 23:47:33 +00:00
|
|
|
|
2022-10-03 20:05:36 +00:00
|
|
|
profileDirectory := path.Join(app.directory, "profiles", model.GenerateRandomID())
|
2021-11-09 23:47:33 +00:00
|
|
|
|
2022-10-03 20:05:36 +00:00
|
|
|
profile, err := peer.CreateEncryptedStorePeer(profileDirectory, name, password)
|
|
|
|
if err != nil {
|
|
|
|
log.Errorf("Error Creating Peer: %v", err)
|
|
|
|
app.appBus.Publish(event.NewEventList(event.PeerError, event.Error, err.Error()))
|
|
|
|
return
|
|
|
|
}
|
2019-06-05 20:40:55 +00:00
|
|
|
|
2023-02-27 21:31:32 +00:00
|
|
|
app.setupPeer(profile)
|
2018-09-21 18:53:10 +00:00
|
|
|
|
2022-12-10 19:50:22 +00:00
|
|
|
for zp, val := range attributes {
|
|
|
|
zone, key := attr.ParseZone(zp.ToString())
|
|
|
|
profile.SetScopedZonedAttribute(attr.LocalScope, zone, key, val)
|
2022-10-03 20:05:36 +00:00
|
|
|
}
|
2022-12-10 19:50:22 +00:00
|
|
|
|
2022-10-03 20:05:36 +00:00
|
|
|
app.appBus.Publish(event.NewEvent(event.NewPeer, map[event.Field]string{event.Identity: profile.GetOnion(), event.Created: event.True}))
|
2019-12-10 23:45:43 +00:00
|
|
|
}
|
|
|
|
|
2023-02-21 23:55:14 +00:00
|
|
|
func (app *application) DeleteProfile(onion string, password string) {
|
|
|
|
log.Debugf("DeleteProfile called on %v\n", onion)
|
2022-10-03 20:05:36 +00:00
|
|
|
app.appmutex.Lock()
|
|
|
|
defer app.appmutex.Unlock()
|
2019-12-10 23:45:43 +00:00
|
|
|
|
2023-04-21 21:21:49 +00:00
|
|
|
// short circuit to prevent nil-pointer panic if this function is called twice (or incorrectly)
|
|
|
|
if app.peers[onion] == nil {
|
|
|
|
log.Errorf("shutdownPeer called with invalid onion %v", onion)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2023-02-27 21:31:32 +00:00
|
|
|
// allow a blank password to delete "unencrypted" accounts...
|
|
|
|
if password == "" {
|
|
|
|
password = DefactoPasswordForUnencryptedProfiles
|
|
|
|
}
|
|
|
|
|
2022-10-03 20:05:36 +00:00
|
|
|
if app.peers[onion].CheckPassword(password) {
|
2022-10-25 20:59:05 +00:00
|
|
|
// soft-shutdown
|
|
|
|
app.peers[onion].Shutdown()
|
|
|
|
// delete the underlying storage
|
2022-10-03 20:05:36 +00:00
|
|
|
app.peers[onion].Delete()
|
2022-10-25 20:59:05 +00:00
|
|
|
// hard shutdown / remove from app
|
|
|
|
app.shutdownPeer(onion)
|
2021-12-17 19:42:55 +00:00
|
|
|
|
2022-10-03 20:05:36 +00:00
|
|
|
// Shutdown and Remove the Engine
|
|
|
|
log.Debugf("Delete peer for %v Done\n", onion)
|
|
|
|
app.appBus.Publish(event.NewEventList(event.PeerDeleted, event.Identity, onion))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
app.appBus.Publish(event.NewEventList(event.AppError, event.Error, event.PasswordMatchError, event.Identity, onion))
|
2019-12-10 23:45:43 +00:00
|
|
|
}
|
|
|
|
|
2019-08-02 01:09:01 +00:00
|
|
|
func (app *application) AddPeerPlugin(onion string, pluginID plugins.PluginID) {
|
2022-10-03 20:05:36 +00:00
|
|
|
app.AddPlugin(onion, pluginID, app.eventBuses[onion], app.acn)
|
2019-08-02 01:09:01 +00:00
|
|
|
}
|
|
|
|
|
2022-03-08 21:45:26 +00:00
|
|
|
func (app *application) ImportProfile(exportedCwtchFile string, password string) (peer.CwtchPeer, error) {
|
2022-10-03 20:05:36 +00:00
|
|
|
profileDirectory := path.Join(app.directory, "profiles")
|
|
|
|
profile, err := peer.ImportProfile(exportedCwtchFile, profileDirectory, password)
|
|
|
|
if profile != nil || err == nil {
|
|
|
|
app.installProfile(profile)
|
|
|
|
}
|
|
|
|
return profile, err
|
2022-03-08 21:45:26 +00:00
|
|
|
}
|
|
|
|
|
2023-02-27 22:05:52 +00:00
|
|
|
func (app *application) EnhancedImportProfile(exportedCwtchFile string, password string) string {
|
|
|
|
_, err := app.ImportProfile(exportedCwtchFile, password)
|
|
|
|
if err == nil {
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
return err.Error()
|
|
|
|
}
|
|
|
|
|
2019-06-05 20:40:55 +00:00
|
|
|
// LoadProfiles takes a password and attempts to load any profiles it can from storage with it and create Peers for them
|
2021-12-17 19:42:55 +00:00
|
|
|
func (app *application) LoadProfiles(password string) {
|
2022-10-03 20:05:36 +00:00
|
|
|
count := 0
|
|
|
|
migrating := false
|
|
|
|
|
|
|
|
files, err := os.ReadDir(path.Join(app.directory, "profiles"))
|
|
|
|
if err != nil {
|
|
|
|
log.Errorf("error: cannot read profiles directory: %v", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, file := range files {
|
|
|
|
// Attempt to load an encrypted database
|
|
|
|
profileDirectory := path.Join(app.directory, "profiles", file.Name())
|
|
|
|
profile, err := peer.FromEncryptedDatabase(profileDirectory, password)
|
|
|
|
loaded := false
|
|
|
|
if err == nil {
|
|
|
|
// return the load the profile...
|
|
|
|
log.Infof("loading profile from new-type storage database...")
|
|
|
|
loaded = app.installProfile(profile)
|
|
|
|
} else { // On failure attempt to load a legacy profile
|
|
|
|
profileStore, err := storage.LoadProfileWriterStore(profileDirectory, password)
|
|
|
|
if err != nil {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
log.Infof("found legacy profile. importing to new database structure...")
|
|
|
|
legacyProfile := profileStore.GetProfileCopy(true)
|
|
|
|
if !migrating {
|
|
|
|
migrating = true
|
|
|
|
app.appBus.Publish(event.NewEventList(event.StartingStorageMiragtion))
|
|
|
|
}
|
|
|
|
|
|
|
|
cps, err := peer.CreateEncryptedStore(profileDirectory, password)
|
|
|
|
if err != nil {
|
|
|
|
log.Errorf("error creating encrypted store: %v", err)
|
|
|
|
}
|
|
|
|
profile := peer.ImportLegacyProfile(legacyProfile, cps)
|
|
|
|
loaded = app.installProfile(profile)
|
|
|
|
}
|
|
|
|
if loaded {
|
|
|
|
count++
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if count == 0 {
|
|
|
|
message := event.NewEventList(event.AppError, event.Error, event.AppErrLoaded0)
|
|
|
|
app.appBus.Publish(message)
|
|
|
|
}
|
|
|
|
if migrating {
|
|
|
|
app.appBus.Publish(event.NewEventList(event.DoneStorageMigration))
|
|
|
|
}
|
2021-12-17 19:42:55 +00:00
|
|
|
}
|
|
|
|
|
2023-01-05 21:52:43 +00:00
|
|
|
func (app *application) registerHooks(profile peer.CwtchPeer) {
|
|
|
|
// Register Hooks
|
|
|
|
profile.RegisterHook(extensions.ProfileValueExtension{})
|
2023-04-17 19:05:02 +00:00
|
|
|
profile.RegisterHook(new(filesharing.Functionality))
|
2023-03-06 21:06:15 +00:00
|
|
|
profile.RegisterHook(new(filesharing.ImagePreviewsFunctionality))
|
2023-07-25 18:12:39 +00:00
|
|
|
profile.RegisterHook(new(servers.Functionality))
|
2023-03-13 19:46:15 +00:00
|
|
|
// Ensure that Profiles have the Most Up to Date Settings...
|
|
|
|
profile.NotifySettingsUpdate(app.settings.ReadGlobalSettings())
|
2023-01-05 21:52:43 +00:00
|
|
|
}
|
|
|
|
|
2021-12-17 19:42:55 +00:00
|
|
|
// installProfile takes a profile and if it isn't loaded in the app, installs it and returns true
|
|
|
|
func (app *application) installProfile(profile peer.CwtchPeer) bool {
|
2022-10-03 20:05:36 +00:00
|
|
|
app.appmutex.Lock()
|
|
|
|
defer app.appmutex.Unlock()
|
|
|
|
|
|
|
|
// Only attempt to finalize the profile if we don't have one loaded...
|
|
|
|
if app.peers[profile.GetOnion()] == nil {
|
2023-02-27 21:31:32 +00:00
|
|
|
app.setupPeer(profile)
|
2023-02-27 20:07:19 +00:00
|
|
|
// Finalize the Creation of Peer / Notify any Interfaces..
|
2022-10-03 20:05:36 +00:00
|
|
|
app.appBus.Publish(event.NewEvent(event.NewPeer, map[event.Field]string{event.Identity: profile.GetOnion(), event.Created: event.False}))
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
// Otherwise shutdown the connections
|
|
|
|
profile.Shutdown()
|
|
|
|
return false
|
2019-06-05 20:40:55 +00:00
|
|
|
}
|
|
|
|
|
2022-12-03 23:48:09 +00:00
|
|
|
// ActivateEngines launches all peer engines
|
|
|
|
func (app *application) ActivateEngines(doListen, doPeers, doServers bool) {
|
|
|
|
log.Debugf("ActivateEngines")
|
2022-09-26 01:28:04 +00:00
|
|
|
|
|
|
|
for _, profile := range app.peers {
|
2023-04-20 19:18:54 +00:00
|
|
|
app.engines[profile.GetOnion()], _ = profile.GenerateProtocolEngine(app.acn, app.eventBuses[profile.GetOnion()], app.engineHooks)
|
2022-12-03 23:48:09 +00:00
|
|
|
app.eventBuses[profile.GetOnion()].Publish(event.NewEventList(event.ProtocolEngineCreated))
|
2022-09-26 01:28:04 +00:00
|
|
|
}
|
2022-12-03 23:48:09 +00:00
|
|
|
app.QueryACNStatus()
|
2022-09-26 01:28:04 +00:00
|
|
|
|
|
|
|
if doListen {
|
|
|
|
for _, profile := range app.peers {
|
2022-12-03 00:23:11 +00:00
|
|
|
log.Debugf(" Listen for %v", profile.GetOnion())
|
2022-09-26 01:28:04 +00:00
|
|
|
profile.Listen()
|
|
|
|
}
|
|
|
|
}
|
2022-12-03 00:23:11 +00:00
|
|
|
|
|
|
|
if doPeers || doServers {
|
2022-09-26 01:28:04 +00:00
|
|
|
for _, profile := range app.peers {
|
2022-12-03 00:23:11 +00:00
|
|
|
log.Debugf(" Start Connections for %v doPeers:%v doServers:%v", profile.GetOnion(), doPeers, doServers)
|
|
|
|
profile.StartConnections(doPeers, doServers)
|
2022-09-26 01:28:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-04-17 19:05:02 +00:00
|
|
|
// ActivatePeerEngine creates a peer engine for use with an ACN, should be called once the underlying ACN is online
|
2023-02-21 23:55:14 +00:00
|
|
|
func (app *application) ActivatePeerEngine(onion string) {
|
2022-10-03 20:05:36 +00:00
|
|
|
profile := app.GetPeer(onion)
|
|
|
|
if profile != nil {
|
2022-12-05 04:08:41 +00:00
|
|
|
if _, exists := app.engines[onion]; !exists {
|
2023-05-16 22:41:08 +00:00
|
|
|
log.Debugf("restartFlow: Creating a New Protocol Engine...")
|
2023-04-20 19:18:54 +00:00
|
|
|
app.engines[profile.GetOnion()], _ = profile.GenerateProtocolEngine(app.acn, app.eventBuses[profile.GetOnion()], app.engineHooks)
|
2022-12-05 04:08:41 +00:00
|
|
|
app.eventBuses[profile.GetOnion()].Publish(event.NewEventList(event.ProtocolEngineCreated))
|
|
|
|
app.QueryACNStatus()
|
2023-02-21 23:55:14 +00:00
|
|
|
if true {
|
2022-12-05 04:08:41 +00:00
|
|
|
profile.Listen()
|
|
|
|
}
|
2023-02-21 23:55:14 +00:00
|
|
|
profile.StartConnections(true, true)
|
2022-10-03 20:05:36 +00:00
|
|
|
}
|
|
|
|
}
|
2022-08-29 01:19:32 +00:00
|
|
|
}
|
|
|
|
|
2022-09-10 17:36:28 +00:00
|
|
|
// DeactivatePeerEngine shutsdown and cleans up a peer engine, should be called when an underlying ACN goes offline
|
2022-08-29 01:19:32 +00:00
|
|
|
func (app *application) DeactivatePeerEngine(onion string) {
|
2022-10-03 20:05:36 +00:00
|
|
|
if engine, exists := app.engines[onion]; exists {
|
|
|
|
engine.Shutdown()
|
|
|
|
delete(app.engines, onion)
|
|
|
|
}
|
2022-08-29 01:19:32 +00:00
|
|
|
}
|
|
|
|
|
2019-06-05 20:40:55 +00:00
|
|
|
// GetPrimaryBus returns the bus the Application uses for events that aren't peer specific
|
|
|
|
func (app *application) GetPrimaryBus() event.Manager {
|
2022-10-03 20:05:36 +00:00
|
|
|
return app.appBus
|
2018-04-30 21:47:21 +00:00
|
|
|
}
|
|
|
|
|
2019-05-15 20:12:11 +00:00
|
|
|
// GetEventBus returns a cwtchPeer's event bus
|
2021-12-17 19:42:55 +00:00
|
|
|
func (app *application) GetEventBus(onion string) event.Manager {
|
2022-10-03 20:05:36 +00:00
|
|
|
if manager, ok := app.eventBuses[onion]; ok {
|
|
|
|
return manager
|
|
|
|
}
|
|
|
|
return nil
|
2019-05-15 20:12:11 +00:00
|
|
|
}
|
2018-10-05 23:27:57 +00:00
|
|
|
|
2019-09-26 23:43:34 +00:00
|
|
|
func (app *application) getACNStatusHandler() func(int, string) {
|
2022-10-03 20:05:36 +00:00
|
|
|
return func(progress int, status string) {
|
|
|
|
progStr := strconv.Itoa(progress)
|
|
|
|
app.appmutex.Lock()
|
|
|
|
app.appBus.Publish(event.NewEventList(event.ACNStatus, event.Progress, progStr, event.Status, status))
|
|
|
|
for _, bus := range app.eventBuses {
|
|
|
|
bus.Publish(event.NewEventList(event.ACNStatus, event.Progress, progStr, event.Status, status))
|
|
|
|
}
|
|
|
|
app.appmutex.Unlock()
|
|
|
|
}
|
2019-09-26 23:43:34 +00:00
|
|
|
}
|
|
|
|
|
2022-08-04 05:20:54 +00:00
|
|
|
func (app *application) getACNVersionHandler() func(string) {
|
2022-10-03 20:05:36 +00:00
|
|
|
return func(version string) {
|
|
|
|
app.appmutex.Lock()
|
|
|
|
defer app.appmutex.Unlock()
|
|
|
|
app.appBus.Publish(event.NewEventList(event.ACNVersion, event.Data, version))
|
|
|
|
}
|
2022-08-04 05:20:54 +00:00
|
|
|
}
|
|
|
|
|
2019-09-26 23:43:34 +00:00
|
|
|
func (app *application) QueryACNStatus() {
|
2022-10-03 20:05:36 +00:00
|
|
|
prog, status := app.acn.GetBootstrapStatus()
|
|
|
|
app.getACNStatusHandler()(prog, status)
|
2019-09-26 23:43:34 +00:00
|
|
|
}
|
|
|
|
|
2020-12-01 03:25:17 +00:00
|
|
|
func (app *application) QueryACNVersion() {
|
2022-10-03 20:05:36 +00:00
|
|
|
version := app.acn.GetVersion()
|
|
|
|
app.appBus.Publish(event.NewEventList(event.ACNVersion, event.Data, version))
|
2020-12-01 03:25:17 +00:00
|
|
|
}
|
|
|
|
|
2023-04-28 21:00:15 +00:00
|
|
|
func (app *application) eventHandler() {
|
|
|
|
acnStatus := -1
|
|
|
|
for {
|
|
|
|
e := app.eventQueue.Next()
|
|
|
|
switch e.EventType {
|
|
|
|
case event.ACNStatus:
|
|
|
|
newAcnStatus, err := strconv.Atoi(e.Data[event.Progress])
|
|
|
|
if err != nil {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
if newAcnStatus == 100 {
|
|
|
|
if acnStatus != 100 {
|
|
|
|
for _, onion := range app.ListProfiles() {
|
|
|
|
profile := app.GetPeer(onion)
|
|
|
|
if profile != nil {
|
|
|
|
autostart, exists := profile.GetScopedZonedAttribute(attr.LocalScope, attr.ProfileZone, constants.PeerAutostart)
|
|
|
|
if !exists || autostart == "true" {
|
|
|
|
app.ActivatePeerEngine(onion)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if acnStatus == 100 {
|
|
|
|
// just fell offline
|
|
|
|
for _, onion := range app.ListProfiles() {
|
|
|
|
app.DeactivatePeerEngine(onion)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
acnStatus = newAcnStatus
|
|
|
|
|
|
|
|
default:
|
|
|
|
// invalid event, signifies shutdown
|
|
|
|
if e.EventType == "" {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-15 20:12:11 +00:00
|
|
|
// ShutdownPeer shuts down a peer and removes it from the app's management
|
|
|
|
func (app *application) ShutdownPeer(onion string) {
|
2022-10-03 20:05:36 +00:00
|
|
|
app.appmutex.Lock()
|
|
|
|
defer app.appmutex.Unlock()
|
|
|
|
app.shutdownPeer(onion)
|
2022-08-29 01:19:32 +00:00
|
|
|
}
|
|
|
|
|
2022-09-10 17:36:28 +00:00
|
|
|
// shutdownPeer mutex unlocked helper shutdown peer
|
2022-08-29 01:19:32 +00:00
|
|
|
func (app *application) shutdownPeer(onion string) {
|
2023-04-21 21:21:49 +00:00
|
|
|
|
|
|
|
// short circuit to prevent nil-pointer panic if this function is called twice (or incorrectly)
|
|
|
|
if app.eventBuses[onion] == nil || app.peers[onion] == nil {
|
|
|
|
log.Errorf("shutdownPeer called with invalid onion %v", onion)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-10-03 20:05:36 +00:00
|
|
|
app.eventBuses[onion].Publish(event.NewEventList(event.ShutdownPeer, event.Identity, onion))
|
|
|
|
app.eventBuses[onion].Shutdown()
|
|
|
|
delete(app.eventBuses, onion)
|
|
|
|
app.peers[onion].Shutdown()
|
|
|
|
delete(app.peers, onion)
|
|
|
|
if _, ok := app.engines[onion]; ok {
|
|
|
|
app.engines[onion].Shutdown()
|
|
|
|
delete(app.engines, onion)
|
|
|
|
}
|
|
|
|
log.Debugf("shutting down plugins for %v", onion)
|
|
|
|
pluginsI, ok := app.plugins.Load(onion)
|
|
|
|
if ok {
|
2023-04-17 19:05:02 +00:00
|
|
|
appPlugins := pluginsI.([]plugins.Plugin)
|
|
|
|
for _, plugin := range appPlugins {
|
2022-10-03 20:05:36 +00:00
|
|
|
plugin.Shutdown()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
app.plugins.Delete(onion)
|
2019-01-19 23:16:38 +00:00
|
|
|
}
|
|
|
|
|
2022-08-29 01:19:32 +00:00
|
|
|
// Shutdown shutsdown all peers of an app
|
2018-09-21 18:53:10 +00:00
|
|
|
func (app *application) Shutdown() {
|
2022-10-03 20:05:36 +00:00
|
|
|
app.appmutex.Lock()
|
|
|
|
defer app.appmutex.Unlock()
|
|
|
|
for id := range app.peers {
|
|
|
|
log.Debugf("Shutting Down Peer %v", id)
|
|
|
|
app.shutdownPeer(id)
|
|
|
|
}
|
|
|
|
log.Debugf("Shutting Down App")
|
2023-04-28 21:00:15 +00:00
|
|
|
app.eventQueue.Shutdown()
|
2022-10-03 20:05:36 +00:00
|
|
|
app.appBus.Shutdown()
|
|
|
|
log.Debugf("Shut Down Complete")
|
2018-04-30 21:47:21 +00:00
|
|
|
}
|