You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

151 lines
4.1 KiB

package server
import (
"cwtch.im/cwtch/model"
"errors"
"fmt"
"git.openprivacy.ca/openprivacy/connectivity"
"git.openprivacy.ca/openprivacy/log"
"io/ioutil"
"path"
"sync"
)
// Servers is an interface to manage multiple Cwtch servers
// Unlike a standalone server, server's dirs will be under one "$CwtchDir/servers" and use a cwtch style localID to obscure
// what servers are hosted. Users are of course free to use a default password. This means Config file will be encrypted
// with cwtch/storage/v1/file_enc and monitor files will not be generated
type Servers interface {
LoadServers(password string) ([]string, error)
CreateServer(password string) (Server, error)
GetServer(onion string) Server
ListServers() []string
DeleteServer(onion string, currentPassword string) error
LaunchServer(string)
StopServer(string)
Stop()
Destroy()
}
type servers struct {
lock sync.Mutex
servers map[string]Server
directory string
acn connectivity.ACN
}
// NewServers returns a Servers interface to manage a collection of servers
// expecting directory: $CWTCH_HOME/servers
func NewServers(acn connectivity.ACN, directory string) Servers {
return &servers{acn: acn, directory: directory, servers: make(map[string]Server)}
}
// LoadServers will attempt to load any servers in the servers directory that are encrypted with the supplied password
// returns a list of onions identifiers for servers loaded or an error
func (s *servers) LoadServers(password string) ([]string, error) {
s.lock.Lock()
defer s.lock.Unlock()
dirs, err := ioutil.ReadDir(s.directory)
if err != nil {
return nil, fmt.Errorf("error: cannot read server directory: %v", err)
}
loadedServers := []string{}
for _, dir := range dirs {
newConfig, err := LoadConfig(path.Join(s.directory, dir.Name()), ServerConfigFile, true, password)
if err == nil {
if _, exists := s.servers[newConfig.Onion()]; !exists {
log.Debugf("Loaded config, building server for %s\n", newConfig.Onion())
server := NewServer(newConfig)
s.servers[server.Onion()] = server
loadedServers = append(loadedServers, server.Onion())
}
}
}
return loadedServers, nil
}
// CreateServer creates a new server and stores it, also returns an interface to it
func (s *servers) CreateServer(password string) (Server, error) {
newLocalID := model.GenerateRandomID()
directory := path.Join(s.directory, newLocalID)
config, err := CreateConfig(directory, ServerConfigFile, true, password, false)
if err != nil {
return nil, err
}
server := NewServer(config)
s.lock.Lock()
defer s.lock.Unlock()
s.servers[server.Onion()] = server
return server, nil
}
// GetServer returns a server interface for the supplied onion
func (s *servers) GetServer(onion string) Server {
s.lock.Lock()
defer s.lock.Unlock()
return s.servers[onion]
}
// ListServers returns a list of server onion identifies this servers struct is managing
func (s *servers) ListServers() []string {
s.lock.Lock()
defer s.lock.Unlock()
list := []string{}
for onion := range s.servers {
list = append(list, onion)
}
return list
}
// DeleteServer delete's the requested server (assuming the passwords match
func (s *servers) DeleteServer(onion string, password string) error {
s.lock.Lock()
defer s.lock.Unlock()
server := s.servers[onion]
if server != nil {
err := server.Delete(password)
if err == nil {
delete(s.servers, onion)
}
return err
}
return errors.New("server not found")
}
// LaunchServer Run() the specified server
func (s *servers) LaunchServer(onion string) {
s.lock.Lock()
defer s.lock.Unlock()
if server, exists := s.servers[onion]; exists {
server.Run(s.acn)
}
}
// StopServer stops the specified server
func (s *servers) StopServer(onion string) {
s.lock.Lock()
defer s.lock.Unlock()
if server, exists := s.servers[onion]; exists {
server.Stop()
}
}
// Stop stops all the servers
func (s *servers) Stop() {
s.lock.Lock()
defer s.lock.Unlock()
for _, server := range s.servers {
server.Stop()
}
}
// Destroy destroys all the servers
func (s *servers) Destroy() {
s.lock.Lock()
defer s.lock.Unlock()
for _, server := range s.servers {
server.Destroy()
}
}