package app import ( "cwtch.im/cwtch/event" "cwtch.im/cwtch/peer" "cwtch.im/cwtch/storage" "fmt" "git.openprivacy.ca/openprivacy/libricochet-go/connectivity" "git.openprivacy.ca/openprivacy/libricochet-go/log" "io/ioutil" "os" "path" "sync" ) type application struct { peers map[string]peer.CwtchPeer acn connectivity.ACN directory string mutex sync.Mutex primaryonion string storage map[string]storage.ProfileStore eventBus *event.Manager } // Application is a full cwtch peer application. It allows management, usage and storage of multiple peers type Application interface { LoadProfiles(password string) error CreatePeer(name string, password string) (peer.CwtchPeer, error) PrimaryIdentity() peer.CwtchPeer GetPeer(onion string) peer.CwtchPeer ListPeers() map[string]string LaunchPeers() EventBus() *event.Manager Shutdown() } // NewApp creates a new app with some environment awareness and initializes a Tor Manager func NewApp(acn connectivity.ACN, appDirectory string) Application { log.Debugf("NewApp(%v)\n", appDirectory) app := &application{peers: make(map[string]peer.CwtchPeer), storage: make(map[string]storage.ProfileStore), directory: appDirectory, acn: acn} os.Mkdir(path.Join(app.directory, "profiles"), 0700) app.eventBus = new(event.Manager) app.eventBus.Initialize() return app } // NewProfile creates a new cwtchPeer with a given name. func (app *application) CreatePeer(name string, password string) (peer.CwtchPeer, error) { log.Debugf("CreatePeer(%v)\n", name) profile := storage.NewProfile(name) profileStore := storage.NewProfileStore(app.eventBus, path.Join(app.directory, "profiles", profile.LocalID), password, profile) pc := profileStore.GetProfileCopy() p := peer.FromProfile(pc) p.Init(app.acn, app.eventBus) _, exists := app.peers[p.GetProfile().Onion] if exists { p.Shutdown() return nil, fmt.Errorf("Error: profile for onion %v already exists", p.GetProfile().Onion) } app.mutex.Lock() app.peers[p.GetProfile().Onion] = p app.storage[p.GetProfile().Onion] = profileStore app.mutex.Unlock() return p, nil } func (app *application) LoadProfiles(password string) error { files, err := ioutil.ReadDir(path.Join(app.directory, "profiles")) if err != nil { return fmt.Errorf("Error: cannot read profiles directory: %v", err) } for _, file := range files { // TODO: Per profile eventBus profileStore := storage.NewProfileStore(app.eventBus, path.Join(app.directory, "profiles", file.Name()), password, nil) err = profileStore.Load() if err != nil { continue } profile := profileStore.GetProfileCopy() _, exists := app.peers[profile.Onion] if exists { profileStore.Shutdown() log.Errorf("profile for onion %v already exists", profile.Onion) continue } peer := peer.FromProfile(profile) peer.Init(app.acn, app.eventBus) app.mutex.Lock() app.peers[profile.Onion] = peer app.storage[profile.Onion] = profileStore if app.primaryonion == "" { app.primaryonion = profile.Onion } app.mutex.Unlock() } return nil } func (app *application) LaunchPeers() { for _, p := range app.peers { if !p.IsStarted() { p.Listen() } } } // ListPeers returns a map of onions to their profile's Name func (app *application) ListPeers() map[string]string { keys := map[string]string{} for k, p := range app.peers { keys[k] = p.GetProfile().Name } return keys } // PrimaryIdentity returns a cwtchPeer for a given onion address func (app *application) PrimaryIdentity() peer.CwtchPeer { return app.peers[app.primaryonion] } // 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 } /* // GetTorStatus returns tor control port bootstrap-phase status info in a map func (app *application) GetTorStatus() (map[string]string, error) { return app.torManager.GetStatus() }*/ // Fetch the app's event manager func (app *application) EventBus() *event.Manager { return app.eventBus } // Shutdown shutsdown all peers of an app and then the tormanager func (app *application) Shutdown() { for _, peer := range app.peers { peer.Shutdown() } }