2018-04-30 21:47:21 +00:00
|
|
|
package app
|
|
|
|
|
|
|
|
import (
|
2019-08-02 01:09:01 +00:00
|
|
|
"cwtch.im/cwtch/app/plugins"
|
2019-01-04 21:44:21 +00:00
|
|
|
"cwtch.im/cwtch/event"
|
2021-11-23 22:45:25 +00:00
|
|
|
"cwtch.im/cwtch/model"
|
2021-10-15 19:38:22 +00:00
|
|
|
"cwtch.im/cwtch/model/attr"
|
2021-10-15 19:43:28 +00:00
|
|
|
"cwtch.im/cwtch/model/constants"
|
2018-05-28 18:05:06 +00:00
|
|
|
"cwtch.im/cwtch/peer"
|
2019-05-15 20:12:11 +00:00
|
|
|
"cwtch.im/cwtch/protocol/connections"
|
2018-10-06 03:50:55 +00:00
|
|
|
"cwtch.im/cwtch/storage"
|
2020-02-10 22:09:24 +00:00
|
|
|
"git.openprivacy.ca/openprivacy/connectivity"
|
|
|
|
"git.openprivacy.ca/openprivacy/log"
|
2018-07-01 18:43:05 +00:00
|
|
|
"os"
|
2021-10-07 22:40:25 +00:00
|
|
|
path "path/filepath"
|
2019-08-02 01:09:01 +00:00
|
|
|
"strconv"
|
2018-09-21 18:53:10 +00:00
|
|
|
"sync"
|
2018-04-30 21:47:21 +00:00
|
|
|
)
|
|
|
|
|
2018-09-21 18:53:10 +00:00
|
|
|
type application struct {
|
2021-12-17 19:42:55 +00:00
|
|
|
eventBuses map[string]event.Manager
|
|
|
|
directory string
|
2022-08-29 01:19:32 +00:00
|
|
|
|
|
|
|
peerLock sync.Mutex
|
|
|
|
peers map[string]peer.CwtchPeer
|
|
|
|
acn connectivity.ACN
|
|
|
|
plugins sync.Map //map[string] []plugins.Plugin
|
|
|
|
|
2019-12-12 20:21:14 +00:00
|
|
|
engines map[string]connections.Engine
|
|
|
|
appBus event.Manager
|
|
|
|
appmutex sync.Mutex
|
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 {
|
2019-06-05 20:40:55 +00:00
|
|
|
LoadProfiles(password string)
|
2019-12-10 23:45:43 +00:00
|
|
|
CreateTaggedPeer(name string, password string, tag string)
|
2022-03-08 21:45:26 +00:00
|
|
|
ImportProfile(exportedCwtchFile string, password string) (peer.CwtchPeer, error)
|
2021-06-14 23:50:35 +00:00
|
|
|
DeletePeer(onion string, currentPassword string)
|
2019-08-02 01:09:01 +00:00
|
|
|
AddPeerPlugin(onion string, pluginID plugins.PluginID)
|
2018-09-21 18:53:10 +00:00
|
|
|
|
2019-06-05 20:40:55 +00:00
|
|
|
GetPrimaryBus() event.Manager
|
|
|
|
GetEventBus(onion string) event.Manager
|
2019-09-26 23:43:34 +00:00
|
|
|
QueryACNStatus()
|
2020-12-01 03:25:17 +00:00
|
|
|
QueryACNVersion()
|
2019-06-05 20:40:55 +00:00
|
|
|
|
2022-08-29 05:20:59 +00:00
|
|
|
ActivePeerEngine(onion string, doListen, doPeers, doServers bool)
|
2022-08-29 01:19:32 +00:00
|
|
|
DeactivatePeerEngine(onion string)
|
|
|
|
|
2019-05-15 20:12:11 +00:00
|
|
|
ShutdownPeer(string)
|
2018-09-21 18:53:10 +00:00
|
|
|
Shutdown()
|
2019-06-05 20:40:55 +00:00
|
|
|
|
|
|
|
GetPeer(onion string) peer.CwtchPeer
|
2021-10-15 19:38:22 +00:00
|
|
|
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
|
|
|
|
2018-07-10 20:42:47 +00:00
|
|
|
// NewApp creates a new app with some environment awareness and initializes a Tor Manager
|
2018-11-22 18:01:04 +00:00
|
|
|
func NewApp(acn connectivity.ACN, appDirectory string) Application {
|
2018-12-04 02:52:11 +00:00
|
|
|
log.Debugf("NewApp(%v)\n", appDirectory)
|
2021-12-17 19:42:55 +00:00
|
|
|
os.MkdirAll(path.Join(appDirectory, "profiles"), 0700)
|
|
|
|
|
|
|
|
app := &application{engines: make(map[string]connections.Engine), eventBuses: make(map[string]event.Manager), directory: appDirectory, appBus: event.NewEventManager()}
|
2022-08-29 01:19:32 +00:00
|
|
|
app.peers = make(map[string]peer.CwtchPeer)
|
|
|
|
|
|
|
|
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
|
|
|
|
2018-11-10 22:14:12 +00:00
|
|
|
return app
|
2018-04-30 21:47:21 +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 {
|
|
|
|
var keys []string
|
|
|
|
|
|
|
|
app.peerLock.Lock()
|
|
|
|
defer app.peerLock.Unlock()
|
|
|
|
for handle := range app.peers {
|
|
|
|
keys = append(keys, handle)
|
|
|
|
}
|
|
|
|
return keys
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetPeer returns a cwtchPeer for a given onion address
|
|
|
|
func (app *application) GetPeer(onion string) peer.CwtchPeer {
|
|
|
|
if peer, ok := app.peers[onion]; ok {
|
|
|
|
return peer
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (ap *application) AddPlugin(peerid string, id plugins.PluginID, bus event.Manager, acn connectivity.ACN) {
|
|
|
|
if _, exists := ap.plugins.Load(peerid); !exists {
|
|
|
|
ap.plugins.Store(peerid, []plugins.Plugin{})
|
|
|
|
}
|
|
|
|
|
|
|
|
pluginsinf, _ := ap.plugins.Load(peerid)
|
|
|
|
peerPlugins := pluginsinf.([]plugins.Plugin)
|
|
|
|
|
|
|
|
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)
|
|
|
|
ap.plugins.Store(peerid, peerPlugins)
|
|
|
|
} else {
|
|
|
|
log.Errorf("error adding plugin: %v", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-10 23:45:43 +00:00
|
|
|
func (app *application) CreateTaggedPeer(name string, password string, tag string) {
|
2021-11-19 22:31:44 +00:00
|
|
|
app.appmutex.Lock()
|
|
|
|
defer app.appmutex.Unlock()
|
2021-11-09 23:47:33 +00:00
|
|
|
|
2021-11-23 22:45:25 +00:00
|
|
|
profileDirectory := path.Join(app.directory, "profiles", model.GenerateRandomID())
|
2021-11-09 23:47:33 +00:00
|
|
|
|
|
|
|
profile, err := peer.CreateEncryptedStorePeer(profileDirectory, name, password)
|
2019-06-05 20:40:55 +00:00
|
|
|
if err != nil {
|
2021-11-09 23:47:33 +00:00
|
|
|
log.Errorf("Error Creating Peer: %v", err)
|
2019-06-05 20:40:55 +00:00
|
|
|
app.appBus.Publish(event.NewEventList(event.PeerError, event.Error, err.Error()))
|
|
|
|
return
|
2018-05-01 20:44:45 +00:00
|
|
|
}
|
2019-06-05 20:40:55 +00:00
|
|
|
|
2021-11-09 23:47:33 +00:00
|
|
|
eventBus := event.NewEventManager()
|
|
|
|
app.eventBuses[profile.GetOnion()] = eventBus
|
|
|
|
profile.Init(app.eventBuses[profile.GetOnion()])
|
|
|
|
app.peers[profile.GetOnion()] = profile
|
2018-09-21 18:53:10 +00:00
|
|
|
|
2019-12-10 23:45:43 +00:00
|
|
|
if tag != "" {
|
2021-11-09 23:47:33 +00:00
|
|
|
profile.SetScopedZonedAttribute(attr.LocalScope, attr.ProfileZone, constants.Tag, tag)
|
2019-12-10 23:45:43 +00:00
|
|
|
}
|
|
|
|
|
2021-11-09 23:47:33 +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
|
|
|
}
|
|
|
|
|
2021-06-14 23:50:35 +00:00
|
|
|
func (app *application) DeletePeer(onion string, password string) {
|
2019-12-10 23:45:43 +00:00
|
|
|
log.Infof("DeletePeer called on %v\n", onion)
|
2019-12-12 20:21:14 +00:00
|
|
|
app.appmutex.Lock()
|
2019-12-13 19:34:59 +00:00
|
|
|
defer app.appmutex.Unlock()
|
2019-12-10 23:45:43 +00:00
|
|
|
|
2021-11-19 19:49:04 +00:00
|
|
|
if app.peers[onion].CheckPassword(password) {
|
2022-08-29 01:19:32 +00:00
|
|
|
app.shutdownPeer(onion)
|
2021-11-19 19:49:04 +00:00
|
|
|
app.peers[onion].Delete()
|
2021-12-17 19:42:55 +00:00
|
|
|
|
2022-08-29 01:19:32 +00:00
|
|
|
// Shutdown and Remove the Engine
|
2021-11-19 19:49:04 +00:00
|
|
|
|
|
|
|
log.Debugf("Delete peer for %v Done\n", onion)
|
|
|
|
app.appBus.Publish(event.NewEventList(event.PeerDeleted, event.Identity, onion))
|
|
|
|
return
|
|
|
|
}
|
2021-06-14 23:50:35 +00:00
|
|
|
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) {
|
2019-10-31 23:05:01 +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) {
|
|
|
|
profileDirectory := path.Join(app.directory, "profiles")
|
|
|
|
profile, err := peer.ImportProfile(exportedCwtchFile, profileDirectory, password)
|
2022-03-09 22:32:21 +00:00
|
|
|
if profile != nil || err == nil {
|
2022-03-08 21:45:26 +00:00
|
|
|
app.installProfile(profile)
|
|
|
|
}
|
|
|
|
return profile, err
|
|
|
|
}
|
|
|
|
|
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) {
|
|
|
|
count := 0
|
|
|
|
migrating := false
|
|
|
|
|
2022-09-06 19:41:52 +00:00
|
|
|
files, err := os.ReadDir(path.Join(app.directory, "profiles"))
|
2018-09-21 18:53:10 +00:00
|
|
|
if err != nil {
|
2021-12-17 19:42:55 +00:00
|
|
|
log.Errorf("error: cannot read profiles directory: %v", err)
|
|
|
|
return
|
2018-09-21 18:53:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for _, file := range files {
|
2021-11-09 23:47:33 +00:00
|
|
|
// Attempt to load an encrypted database
|
2021-12-17 19:42:55 +00:00
|
|
|
profileDirectory := path.Join(app.directory, "profiles", file.Name())
|
2021-11-09 23:47:33 +00:00
|
|
|
profile, err := peer.FromEncryptedDatabase(profileDirectory, password)
|
2021-12-17 19:42:55 +00:00
|
|
|
loaded := false
|
2021-11-09 23:47:33 +00:00
|
|
|
if err == nil {
|
|
|
|
// return the load the profile...
|
2021-11-18 23:43:58 +00:00
|
|
|
log.Infof("loading profile from new-type storage database...")
|
2021-12-17 19:42:55 +00:00
|
|
|
loaded = app.installProfile(profile)
|
2021-11-18 23:43:58 +00:00
|
|
|
} else { // On failure attempt to load a legacy profile
|
|
|
|
profileStore, err := storage.LoadProfileWriterStore(profileDirectory, password)
|
2021-11-09 23:47:33 +00:00
|
|
|
if err != nil {
|
|
|
|
continue
|
|
|
|
}
|
2021-11-18 23:43:58 +00:00
|
|
|
log.Infof("found legacy profile. importing to new database structure...")
|
2021-12-17 19:42:55 +00:00
|
|
|
legacyProfile := profileStore.GetProfileCopy(true)
|
|
|
|
if !migrating {
|
|
|
|
migrating = true
|
|
|
|
app.appBus.Publish(event.NewEventList(event.StartingStorageMiragtion))
|
|
|
|
}
|
2021-11-09 23:47:33 +00:00
|
|
|
|
2021-11-17 23:34:14 +00:00
|
|
|
cps, err := peer.CreateEncryptedStore(profileDirectory, password)
|
2021-11-17 23:59:52 +00:00
|
|
|
if err != nil {
|
|
|
|
log.Errorf("error creating encrypted store: %v", err)
|
|
|
|
}
|
2021-11-17 23:34:14 +00:00
|
|
|
profile := peer.ImportLegacyProfile(legacyProfile, cps)
|
2021-12-17 19:42:55 +00:00
|
|
|
loaded = app.installProfile(profile)
|
2021-11-09 23:47:33 +00:00
|
|
|
}
|
2021-12-17 19:42:55 +00:00
|
|
|
if loaded {
|
2021-11-17 23:34:14 +00:00
|
|
|
count++
|
|
|
|
}
|
2021-12-17 19:42:55 +00:00
|
|
|
}
|
2019-07-10 20:30:24 +00:00
|
|
|
if count == 0 {
|
|
|
|
message := event.NewEventList(event.AppError, event.Error, event.AppErrLoaded0)
|
|
|
|
app.appBus.Publish(message)
|
|
|
|
}
|
2021-12-17 19:42:55 +00:00
|
|
|
if migrating {
|
|
|
|
app.appBus.Publish(event.NewEventList(event.DoneStorageMigration))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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 {
|
|
|
|
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 {
|
|
|
|
eventBus := event.NewEventManager()
|
|
|
|
app.eventBuses[profile.GetOnion()] = eventBus
|
|
|
|
profile.Init(app.eventBuses[profile.GetOnion()])
|
|
|
|
app.peers[profile.GetOnion()] = profile
|
|
|
|
app.appBus.Publish(event.NewEvent(event.NewPeer, map[event.Field]string{event.Identity: profile.GetOnion(), event.Created: event.False}))
|
|
|
|
return true
|
|
|
|
}
|
2021-12-18 03:55:25 +00:00
|
|
|
// Otherwise shutdown the connections
|
|
|
|
profile.Shutdown()
|
|
|
|
return false
|
2019-06-05 20:40:55 +00:00
|
|
|
}
|
|
|
|
|
2022-08-29 01:19:32 +00:00
|
|
|
/// ActivePeerEngine creates a peer engine for use with an ACN, should be called once the underlying ACN is online
|
2022-08-29 05:20:59 +00:00
|
|
|
func (app *application) ActivePeerEngine(onion string, doListen, doPeers, doServers bool) {
|
2022-08-29 01:19:32 +00:00
|
|
|
profile := app.GetPeer(onion)
|
|
|
|
if profile != nil {
|
|
|
|
app.engines[profile.GetOnion()], _ = profile.GenerateProtocolEngine(app.acn, app.eventBuses[profile.GetOnion()])
|
2022-08-29 05:20:59 +00:00
|
|
|
if doListen {
|
|
|
|
profile.Listen()
|
|
|
|
}
|
|
|
|
if doPeers {
|
|
|
|
profile.StartPeersConnections()
|
|
|
|
}
|
|
|
|
if doServers {
|
|
|
|
profile.StartServerConnections()
|
|
|
|
}
|
2022-08-29 01:19:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// DeactivatePeerEngine shutsdown and cleans up a peer engine, should be called when an underlying ACN goes offline
|
|
|
|
func (app *application) DeactivatePeerEngine(onion string) {
|
|
|
|
if engine, exists := app.engines[onion]; exists {
|
|
|
|
engine.Shutdown()
|
|
|
|
delete(app.engines, onion)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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 {
|
|
|
|
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 {
|
|
|
|
if manager, ok := app.eventBuses[onion]; ok {
|
2019-05-15 20:12:11 +00:00
|
|
|
return manager
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
2018-10-05 23:27:57 +00:00
|
|
|
|
2019-09-26 23:43:34 +00:00
|
|
|
func (app *application) getACNStatusHandler() func(int, string) {
|
|
|
|
return func(progress int, status string) {
|
|
|
|
progStr := strconv.Itoa(progress)
|
2021-11-19 23:10:22 +00:00
|
|
|
app.appmutex.Lock()
|
2021-04-13 22:12:12 +00:00
|
|
|
app.appBus.Publish(event.NewEventList(event.ACNStatus, event.Progress, progStr, event.Status, status))
|
2019-09-26 23:43:34 +00:00
|
|
|
for _, bus := range app.eventBuses {
|
2021-04-13 22:12:12 +00:00
|
|
|
bus.Publish(event.NewEventList(event.ACNStatus, event.Progress, progStr, event.Status, status))
|
2019-09-26 23:43:34 +00:00
|
|
|
}
|
2021-11-19 23:10:22 +00:00
|
|
|
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) {
|
|
|
|
return func(version string) {
|
|
|
|
app.appmutex.Lock()
|
|
|
|
defer app.appmutex.Unlock()
|
|
|
|
app.appBus.Publish(event.NewEventList(event.ACNVersion, event.Data, version))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-26 23:43:34 +00:00
|
|
|
func (app *application) QueryACNStatus() {
|
|
|
|
prog, status := app.acn.GetBootstrapStatus()
|
|
|
|
app.getACNStatusHandler()(prog, status)
|
|
|
|
}
|
|
|
|
|
2020-12-01 03:25:17 +00:00
|
|
|
func (app *application) QueryACNVersion() {
|
|
|
|
version := app.acn.GetVersion()
|
|
|
|
app.appBus.Publish(event.NewEventList(event.ACNVersion, event.Data, version))
|
|
|
|
}
|
|
|
|
|
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) {
|
2019-12-12 20:21:14 +00:00
|
|
|
app.appmutex.Lock()
|
|
|
|
defer app.appmutex.Unlock()
|
2022-08-29 01:19:32 +00:00
|
|
|
app.shutdownPeer(onion)
|
|
|
|
}
|
|
|
|
|
2022-08-29 05:20:59 +00:00
|
|
|
/// shutdownPeer mutex unlocked helper shutdown peer
|
2022-08-29 01:19:32 +00:00
|
|
|
func (app *application) shutdownPeer(onion string) {
|
2022-08-29 05:20:59 +00:00
|
|
|
app.eventBuses[onion].Publish(event.NewEventList(event.ShutdownPeer, event.Identity, onion))
|
2019-05-15 20:12:11 +00:00
|
|
|
app.eventBuses[onion].Shutdown()
|
|
|
|
delete(app.eventBuses, onion)
|
|
|
|
app.peers[onion].Shutdown()
|
|
|
|
delete(app.peers, onion)
|
2022-09-08 16:19:25 +00:00
|
|
|
if _, ok := app.engines[onion]; ok {
|
|
|
|
app.engines[onion].Shutdown()
|
|
|
|
delete(app.engines, onion)
|
|
|
|
}
|
2022-08-29 01:19:32 +00:00
|
|
|
log.Debugf("shutting down plugins for %v", onion)
|
|
|
|
pluginsI, ok := app.plugins.Load(onion)
|
|
|
|
if ok {
|
|
|
|
plugins := pluginsI.([]plugins.Plugin)
|
|
|
|
for _, plugin := range plugins {
|
|
|
|
log.Debugf("shutting down plugin: %v", plugin)
|
|
|
|
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() {
|
2019-05-15 20:12:11 +00:00
|
|
|
for id, peer := range app.peers {
|
2021-06-24 01:29:23 +00:00
|
|
|
log.Debugf("Shutting Down Peer %v", id)
|
2022-03-03 23:58:41 +00:00
|
|
|
peer.Shutdown()
|
|
|
|
log.Debugf("Shutting Down Plugins for %v", id)
|
2022-08-29 01:19:32 +00:00
|
|
|
app.plugins.Range(func(k, v interface{}) bool {
|
|
|
|
log.Debugf("shutting down plugins for %v", k)
|
|
|
|
app.ShutdownPeer(k.(string))
|
|
|
|
return true
|
|
|
|
})
|
2021-06-24 01:29:23 +00:00
|
|
|
log.Debugf("Shutting Down Engines for %v", id)
|
2022-09-08 16:19:25 +00:00
|
|
|
if _, ok := app.engines[id]; ok {
|
|
|
|
app.engines[id].Shutdown()
|
|
|
|
}
|
2021-06-24 01:29:23 +00:00
|
|
|
log.Debugf("Shutting Down Bus for %v", id)
|
2019-05-15 20:12:11 +00:00
|
|
|
app.eventBuses[id].Shutdown()
|
2022-03-03 23:58:41 +00:00
|
|
|
log.Debugf("Done Shutdown for peer %v", id)
|
2018-09-21 18:53:10 +00:00
|
|
|
}
|
2021-06-24 01:29:23 +00:00
|
|
|
log.Debugf("Shutting Down App")
|
2019-06-05 20:40:55 +00:00
|
|
|
app.appBus.Shutdown()
|
2021-06-24 01:29:23 +00:00
|
|
|
log.Debugf("Shut Down Complete")
|
2018-04-30 21:47:21 +00:00
|
|
|
}
|