forked from cwtch.im/cwtch
Merge branch 'storageRW' of dan/cwtch into master
This commit is contained in:
commit
5429cc6deb
83
app/app.go
83
app/app.go
|
@ -3,8 +3,10 @@ package app
|
||||||
import (
|
import (
|
||||||
"cwtch.im/cwtch/event"
|
"cwtch.im/cwtch/event"
|
||||||
"cwtch.im/cwtch/peer"
|
"cwtch.im/cwtch/peer"
|
||||||
|
"cwtch.im/cwtch/protocol/connections"
|
||||||
"cwtch.im/cwtch/storage"
|
"cwtch.im/cwtch/storage"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"git.openprivacy.ca/openprivacy/libricochet-go/identity"
|
||||||
|
|
||||||
"git.openprivacy.ca/openprivacy/libricochet-go/connectivity"
|
"git.openprivacy.ca/openprivacy/libricochet-go/connectivity"
|
||||||
"git.openprivacy.ca/openprivacy/libricochet-go/log"
|
"git.openprivacy.ca/openprivacy/libricochet-go/log"
|
||||||
|
@ -16,12 +18,13 @@ import (
|
||||||
|
|
||||||
type application struct {
|
type application struct {
|
||||||
peers map[string]peer.CwtchPeer
|
peers map[string]peer.CwtchPeer
|
||||||
|
storage map[string]storage.ProfileStore
|
||||||
|
engines map[string]connections.Engine
|
||||||
|
eventBuses map[string]*event.Manager
|
||||||
acn connectivity.ACN
|
acn connectivity.ACN
|
||||||
directory string
|
directory string
|
||||||
mutex sync.Mutex
|
mutex sync.Mutex
|
||||||
primaryonion string
|
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
|
// Application is a full cwtch peer application. It allows management, usage and storage of multiple peers
|
||||||
|
@ -32,20 +35,18 @@ type Application interface {
|
||||||
PrimaryIdentity() peer.CwtchPeer
|
PrimaryIdentity() peer.CwtchPeer
|
||||||
GetPeer(onion string) peer.CwtchPeer
|
GetPeer(onion string) peer.CwtchPeer
|
||||||
ListPeers() map[string]string
|
ListPeers() map[string]string
|
||||||
|
GetEventBus(onion string) *event.Manager
|
||||||
LaunchPeers()
|
LaunchPeers()
|
||||||
|
|
||||||
EventBus() *event.Manager
|
ShutdownPeer(string)
|
||||||
|
|
||||||
Shutdown()
|
Shutdown()
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewApp creates a new app with some environment awareness and initializes a Tor Manager
|
// NewApp creates a new app with some environment awareness and initializes a Tor Manager
|
||||||
func NewApp(acn connectivity.ACN, appDirectory string) Application {
|
func NewApp(acn connectivity.ACN, appDirectory string) Application {
|
||||||
log.Debugf("NewApp(%v)\n", appDirectory)
|
log.Debugf("NewApp(%v)\n", appDirectory)
|
||||||
app := &application{peers: make(map[string]peer.CwtchPeer), storage: make(map[string]storage.ProfileStore), directory: appDirectory, acn: acn}
|
app := &application{peers: make(map[string]peer.CwtchPeer), storage: make(map[string]storage.ProfileStore), engines: make(map[string]connections.Engine), eventBuses: make(map[string]*event.Manager), directory: appDirectory, acn: acn}
|
||||||
os.Mkdir(path.Join(app.directory, "profiles"), 0700)
|
os.Mkdir(path.Join(app.directory, "profiles"), 0700)
|
||||||
app.eventBus = new(event.Manager)
|
|
||||||
app.eventBus.Initialize()
|
|
||||||
return app
|
return app
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,19 +54,31 @@ func NewApp(acn connectivity.ACN, appDirectory string) Application {
|
||||||
func (app *application) CreatePeer(name string, password string) (peer.CwtchPeer, error) {
|
func (app *application) CreatePeer(name string, password string) (peer.CwtchPeer, error) {
|
||||||
log.Debugf("CreatePeer(%v)\n", name)
|
log.Debugf("CreatePeer(%v)\n", name)
|
||||||
|
|
||||||
|
eventBus := new(event.Manager)
|
||||||
|
eventBus.Initialize()
|
||||||
|
|
||||||
profile := storage.NewProfile(name)
|
profile := storage.NewProfile(name)
|
||||||
profileStore := storage.NewProfileStore(app.eventBus, path.Join(app.directory, "profiles", profile.LocalID), password, profile)
|
profileStore := storage.NewProfileWriterStore(eventBus, path.Join(app.directory, "profiles", profile.LocalID), password, profile)
|
||||||
pc := profileStore.GetProfileCopy()
|
pc := profileStore.GetProfileCopy()
|
||||||
p := peer.FromProfile(pc)
|
p := peer.FromProfile(pc)
|
||||||
p.Init(app.acn, app.eventBus)
|
|
||||||
_, exists := app.peers[p.GetProfile().Onion]
|
_, exists := app.peers[p.GetProfile().Onion]
|
||||||
if exists {
|
if exists {
|
||||||
p.Shutdown()
|
profileStore.Shutdown()
|
||||||
|
eventBus.Shutdown()
|
||||||
return nil, fmt.Errorf("Error: profile for onion %v already exists", p.GetProfile().Onion)
|
return nil, fmt.Errorf("Error: profile for onion %v already exists", p.GetProfile().Onion)
|
||||||
}
|
}
|
||||||
|
p.Init(app.acn, eventBus)
|
||||||
|
|
||||||
|
blockedPeers := profile.BlockedPeers()
|
||||||
|
// TODO: Would be nice if ProtocolEngine did not need to explicitly be given the Private Key.
|
||||||
|
identity := identity.InitializeV3(profile.Name, &profile.Ed25519PrivateKey, &profile.Ed25519PublicKey)
|
||||||
|
engine := connections.NewProtocolEngine(identity, profile.Ed25519PrivateKey, app.acn, eventBus, blockedPeers)
|
||||||
|
|
||||||
app.mutex.Lock()
|
app.mutex.Lock()
|
||||||
app.peers[p.GetProfile().Onion] = p
|
app.peers[p.GetProfile().Onion] = p
|
||||||
app.storage[p.GetProfile().Onion] = profileStore
|
app.storage[p.GetProfile().Onion] = profileStore
|
||||||
|
app.engines[p.GetProfile().Onion] = engine
|
||||||
|
app.eventBuses[p.GetProfile().Onion] = eventBus
|
||||||
app.mutex.Unlock()
|
app.mutex.Unlock()
|
||||||
|
|
||||||
return p, nil
|
return p, nil
|
||||||
|
@ -79,8 +92,10 @@ func (app *application) LoadProfiles(password string) error {
|
||||||
|
|
||||||
for _, file := range files {
|
for _, file := range files {
|
||||||
|
|
||||||
// TODO: Per profile eventBus
|
eventBus := new(event.Manager)
|
||||||
profileStore := storage.NewProfileStore(app.eventBus, path.Join(app.directory, "profiles", file.Name()), password, nil)
|
eventBus.Initialize()
|
||||||
|
|
||||||
|
profileStore := storage.NewProfileWriterStore(eventBus, path.Join(app.directory, "profiles", file.Name()), password, nil)
|
||||||
err = profileStore.Load()
|
err = profileStore.Load()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
|
@ -91,16 +106,23 @@ func (app *application) LoadProfiles(password string) error {
|
||||||
_, exists := app.peers[profile.Onion]
|
_, exists := app.peers[profile.Onion]
|
||||||
if exists {
|
if exists {
|
||||||
profileStore.Shutdown()
|
profileStore.Shutdown()
|
||||||
|
eventBus.Shutdown()
|
||||||
log.Errorf("profile for onion %v already exists", profile.Onion)
|
log.Errorf("profile for onion %v already exists", profile.Onion)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
peer := peer.FromProfile(profile)
|
peer := peer.FromProfile(profile)
|
||||||
peer.Init(app.acn, app.eventBus)
|
peer.Init(app.acn, eventBus)
|
||||||
|
|
||||||
|
blockedPeers := profile.BlockedPeers()
|
||||||
|
identity := identity.InitializeV3(profile.Name, &profile.Ed25519PrivateKey, &profile.Ed25519PublicKey)
|
||||||
|
engine := connections.NewProtocolEngine(identity, profile.Ed25519PrivateKey, app.acn, eventBus, blockedPeers)
|
||||||
|
|
||||||
app.mutex.Lock()
|
app.mutex.Lock()
|
||||||
app.peers[profile.Onion] = peer
|
app.peers[profile.Onion] = peer
|
||||||
app.storage[profile.Onion] = profileStore
|
app.storage[profile.Onion] = profileStore
|
||||||
|
app.engines[profile.Onion] = engine
|
||||||
|
app.eventBuses[profile.Onion] = eventBus
|
||||||
if app.primaryonion == "" {
|
if app.primaryonion == "" {
|
||||||
app.primaryonion = profile.Onion
|
app.primaryonion = profile.Onion
|
||||||
}
|
}
|
||||||
|
@ -109,10 +131,13 @@ func (app *application) LoadProfiles(password string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LaunchPeers starts each peer Listening and connecting to peers and groups
|
||||||
func (app *application) LaunchPeers() {
|
func (app *application) LaunchPeers() {
|
||||||
for _, p := range app.peers {
|
for _, p := range app.peers {
|
||||||
if !p.IsStarted() {
|
if !p.IsStarted() {
|
||||||
p.Listen()
|
p.Listen()
|
||||||
|
p.StartPeersConnections()
|
||||||
|
p.StartGroupConnections()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -139,20 +164,34 @@ func (app *application) GetPeer(onion string) peer.CwtchPeer {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// GetEventBus returns a cwtchPeer's event bus
|
||||||
// GetTorStatus returns tor control port bootstrap-phase status info in a map
|
func (app *application) GetEventBus(onion string) *event.Manager {
|
||||||
func (app *application) GetTorStatus() (map[string]string, error) {
|
if manager, ok := app.eventBuses[onion]; ok {
|
||||||
return app.torManager.GetStatus()
|
return manager
|
||||||
}*/
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Fetch the app's event manager
|
// ShutdownPeer shuts down a peer and removes it from the app's management
|
||||||
func (app *application) EventBus() *event.Manager {
|
func (app *application) ShutdownPeer(onion string) {
|
||||||
return app.eventBus
|
app.mutex.Lock()
|
||||||
|
defer app.mutex.Unlock()
|
||||||
|
app.eventBuses[onion].Shutdown()
|
||||||
|
delete(app.eventBuses, onion)
|
||||||
|
app.peers[onion].Shutdown()
|
||||||
|
delete(app.peers, onion)
|
||||||
|
app.engines[onion].Shutdown()
|
||||||
|
delete(app.engines, onion)
|
||||||
|
app.storage[onion].Shutdown()
|
||||||
|
delete(app.storage, onion)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Shutdown shutsdown all peers of an app and then the tormanager
|
// Shutdown shutsdown all peers of an app and then the tormanager
|
||||||
func (app *application) Shutdown() {
|
func (app *application) Shutdown() {
|
||||||
for _, peer := range app.peers {
|
for id, peer := range app.peers {
|
||||||
peer.Shutdown()
|
peer.Shutdown()
|
||||||
|
app.engines[id].Shutdown()
|
||||||
|
app.storage[id].Shutdown()
|
||||||
|
app.eventBuses[id].Shutdown()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,16 +11,16 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func waitForPeerServerConnection(peer peer.CwtchPeer, server string) error {
|
func waitForPeerGroupConnection(peer peer.CwtchPeer, groupID string) error {
|
||||||
for {
|
for {
|
||||||
servers := peer.GetServers()
|
_, ok := peer.GetProfile().Groups[groupID]
|
||||||
state, ok := servers[server]
|
|
||||||
if ok {
|
if ok {
|
||||||
|
state := peer.GetGroupState(groupID)
|
||||||
if state == connections.FAILED {
|
if state == connections.FAILED {
|
||||||
return errors.New("Connection to server " + server + " failed!")
|
return errors.New("Connection to group " + groupID + " failed!")
|
||||||
}
|
}
|
||||||
if state != connections.AUTHENTICATED {
|
if state != connections.AUTHENTICATED {
|
||||||
fmt.Printf("peer %v waiting to authenticate with server %v, current state: %v\n", peer.GetProfile().Onion, server, connections.ConnectionStateName[state])
|
fmt.Printf("peer %v waiting to authenticate with group %v 's server, current state: %v\n", peer.GetProfile().Onion, groupID, connections.ConnectionStateName[state])
|
||||||
time.Sleep(time.Second * 10)
|
time.Sleep(time.Second * 10)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -57,7 +57,7 @@ func main() {
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = waitForPeerServerConnection(botPeer, serverAddr)
|
err = waitForPeerGroupConnection(botPeer, groupID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("Could not connect to server %v: %v\n", serverAddr, err)
|
fmt.Printf("Could not connect to server %v: %v\n", serverAddr, err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
|
|
|
@ -6,7 +6,6 @@ import (
|
||||||
|
|
||||||
"bytes"
|
"bytes"
|
||||||
"cwtch.im/cwtch/model"
|
"cwtch.im/cwtch/model"
|
||||||
"cwtch.im/cwtch/protocol/connections"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"git.openprivacy.ca/openprivacy/libricochet-go/connectivity"
|
"git.openprivacy.ca/openprivacy/libricochet-go/connectivity"
|
||||||
"git.openprivacy.ca/openprivacy/libricochet-go/log"
|
"git.openprivacy.ca/openprivacy/libricochet-go/log"
|
||||||
|
@ -45,8 +44,8 @@ var suggestionsSelectedProfile = []prompt.Suggest{
|
||||||
{Text: "/invite", Description: "invite a new contact"},
|
{Text: "/invite", Description: "invite a new contact"},
|
||||||
{Text: "/invite-to-group", Description: "invite an existing contact to join an existing group"},
|
{Text: "/invite-to-group", Description: "invite an existing contact to join an existing group"},
|
||||||
{Text: "/accept-invite", Description: "accept the invite of a group"},
|
{Text: "/accept-invite", Description: "accept the invite of a group"},
|
||||||
{Text: "/list-servers", Description: "retrieve a list of servers and their connection status"},
|
/*{Text: "/list-servers", Description: "retrieve a list of servers and their connection status"},
|
||||||
{Text: "/list-peers", Description: "retrieve a list of peers and their connection status"},
|
{Text: "/list-peers", Description: "retrieve a list of peers and their connection status"},*/
|
||||||
{Text: "/export-group", Description: "export a group invite: prints as a string"},
|
{Text: "/export-group", Description: "export a group invite: prints as a string"},
|
||||||
{Text: "/trust", Description: "trust a peer"},
|
{Text: "/trust", Description: "trust a peer"},
|
||||||
{Text: "/block", Description: "block a peer - you will no longer see messages or connect to this peer"},
|
{Text: "/block", Description: "block a peer - you will no longer see messages or connect to this peer"},
|
||||||
|
@ -60,8 +59,8 @@ var usages = map[string]string{
|
||||||
"/list-profiles": "",
|
"/list-profiles": "",
|
||||||
"/select-profile": "/select-profile [onion]",
|
"/select-profile": "/select-profile [onion]",
|
||||||
"/quit": "",
|
"/quit": "",
|
||||||
"/list-servers": "",
|
/* "/list-servers": "",
|
||||||
"/list-peers": "",
|
"/list-peers": "",*/
|
||||||
"/list-contacts": "",
|
"/list-contacts": "",
|
||||||
"/list-groups": "",
|
"/list-groups": "",
|
||||||
"/select-group": "/select-group [groupid]",
|
"/select-group": "/select-group [groupid]",
|
||||||
|
@ -424,7 +423,7 @@ func main() {
|
||||||
} else {
|
} else {
|
||||||
fmt.Printf("Error inviting peer, usage: %s\n", usages[commands[0]])
|
fmt.Printf("Error inviting peer, usage: %s\n", usages[commands[0]])
|
||||||
}
|
}
|
||||||
case "/list-peers":
|
/*case "/list-peers":
|
||||||
peers := peer.GetPeers()
|
peers := peer.GetPeers()
|
||||||
for p, s := range peers {
|
for p, s := range peers {
|
||||||
fmt.Printf("Name: %v Status: %v\n", p, connections.ConnectionStateName[s])
|
fmt.Printf("Name: %v Status: %v\n", p, connections.ConnectionStateName[s])
|
||||||
|
@ -433,7 +432,7 @@ func main() {
|
||||||
servers := peer.GetServers()
|
servers := peer.GetServers()
|
||||||
for s, st := range servers {
|
for s, st := range servers {
|
||||||
fmt.Printf("Name: %v Status: %v\n", s, connections.ConnectionStateName[st])
|
fmt.Printf("Name: %v Status: %v\n", s, connections.ConnectionStateName[st])
|
||||||
}
|
}*/
|
||||||
case "/list-contacts":
|
case "/list-contacts":
|
||||||
contacts := peer.GetContacts()
|
contacts := peer.GetContacts()
|
||||||
for _, onion := range contacts {
|
for _, onion := range contacts {
|
||||||
|
|
|
@ -84,6 +84,14 @@ const (
|
||||||
// Key [eg "nick"]
|
// Key [eg "nick"]
|
||||||
// Data [eg "open privacy board"]
|
// Data [eg "open privacy board"]
|
||||||
SetGroupAttribute = Type("SetGroupAttribute")
|
SetGroupAttribute = Type("SetGroupAttribute")
|
||||||
|
|
||||||
|
// RemotePeer
|
||||||
|
// ConnectionState
|
||||||
|
PeerStateChange = Type("PeerStateChange")
|
||||||
|
|
||||||
|
// GroupServer
|
||||||
|
// ConnectionState
|
||||||
|
ServerStateChange = Type("GroupStateChange")
|
||||||
)
|
)
|
||||||
|
|
||||||
// Field defines common event attributes
|
// Field defines common event attributes
|
||||||
|
@ -106,6 +114,8 @@ const (
|
||||||
|
|
||||||
ProfileName = Field("ProfileName")
|
ProfileName = Field("ProfileName")
|
||||||
|
|
||||||
|
ConnectionState = Field("ConnectionState")
|
||||||
|
|
||||||
Key = Field("Key")
|
Key = Field("Key")
|
||||||
Data = Field("Data")
|
Data = Field("Data")
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,7 @@ type Manager struct {
|
||||||
events chan Event
|
events chan Event
|
||||||
mapMutex sync.Mutex
|
mapMutex sync.Mutex
|
||||||
internal chan bool
|
internal chan bool
|
||||||
|
closed bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize sets up the Manager.
|
// Initialize sets up the Manager.
|
||||||
|
@ -31,6 +32,7 @@ func (em *Manager) Initialize() {
|
||||||
em.subscribers = make(map[Type][]chan Event)
|
em.subscribers = make(map[Type][]chan Event)
|
||||||
em.events = make(chan Event)
|
em.events = make(chan Event)
|
||||||
em.internal = make(chan bool)
|
em.internal = make(chan bool)
|
||||||
|
em.closed = false
|
||||||
go em.eventBus()
|
go em.eventBus()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,7 +46,7 @@ func (em *Manager) Subscribe(eventType Type, eventChannel chan Event) {
|
||||||
|
|
||||||
// Publish takes an Event and sends it to the internal eventBus where it is distributed to all Subscribers
|
// Publish takes an Event and sends it to the internal eventBus where it is distributed to all Subscribers
|
||||||
func (em *Manager) Publish(event Event) {
|
func (em *Manager) Publish(event Event) {
|
||||||
if event.EventType != "" {
|
if event.EventType != "" && em.closed != true {
|
||||||
em.events <- event
|
em.events <- event
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -83,6 +85,7 @@ func (em *Manager) eventBus() {
|
||||||
// Shutdown triggers, and waits for, the internal eventBus goroutine to finish
|
// Shutdown triggers, and waits for, the internal eventBus goroutine to finish
|
||||||
func (em *Manager) Shutdown() {
|
func (em *Manager) Shutdown() {
|
||||||
em.events <- Event{}
|
em.events <- Event{}
|
||||||
|
em.closed = true
|
||||||
// wait for eventBus to finish
|
// wait for eventBus to finish
|
||||||
<-em.internal
|
<-em.internal
|
||||||
close(em.events)
|
close(em.events)
|
||||||
|
|
|
@ -29,6 +29,7 @@ type Group struct {
|
||||||
Attributes map[string]string
|
Attributes map[string]string
|
||||||
lock sync.Mutex
|
lock sync.Mutex
|
||||||
LocalID string
|
LocalID string
|
||||||
|
State string `json:"-"`
|
||||||
unacknowledgedMessages []Message
|
unacknowledgedMessages []Message
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,7 @@ type PublicProfile struct {
|
||||||
Attributes map[string]string
|
Attributes map[string]string
|
||||||
Timeline Timeline
|
Timeline Timeline
|
||||||
LocalID string // used by storage engine
|
LocalID string // used by storage engine
|
||||||
|
State string `json:"-"`
|
||||||
lock sync.Mutex
|
lock sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -186,6 +187,18 @@ func (p *Profile) BlockPeer(onion string) (err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BlockedPeers calculates a list of Peers who have been Blocked.
|
||||||
|
func (p *Profile) BlockedPeers() []string {
|
||||||
|
blockedPeers := []string{}
|
||||||
|
for _, contact := range p.GetContacts() {
|
||||||
|
c, _ := p.GetContact(contact)
|
||||||
|
if c.Blocked {
|
||||||
|
blockedPeers = append(blockedPeers, c.Onion)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return blockedPeers
|
||||||
|
}
|
||||||
|
|
||||||
// TrustPeer sets a contact to trusted
|
// TrustPeer sets a contact to trusted
|
||||||
func (p *Profile) TrustPeer(onion string) (err error) {
|
func (p *Profile) TrustPeer(onion string) (err error) {
|
||||||
p.lock.Lock()
|
p.lock.Lock()
|
||||||
|
|
|
@ -5,11 +5,11 @@ import (
|
||||||
"cwtch.im/cwtch/model"
|
"cwtch.im/cwtch/model"
|
||||||
"cwtch.im/cwtch/protocol"
|
"cwtch.im/cwtch/protocol"
|
||||||
"cwtch.im/cwtch/protocol/connections"
|
"cwtch.im/cwtch/protocol/connections"
|
||||||
|
"encoding/base32"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"git.openprivacy.ca/openprivacy/libricochet-go/connectivity"
|
"git.openprivacy.ca/openprivacy/libricochet-go/connectivity"
|
||||||
"git.openprivacy.ca/openprivacy/libricochet-go/identity"
|
|
||||||
"git.openprivacy.ca/openprivacy/libricochet-go/log"
|
"git.openprivacy.ca/openprivacy/libricochet-go/log"
|
||||||
"github.com/golang/protobuf/proto"
|
"github.com/golang/protobuf/proto"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -24,7 +24,6 @@ type cwtchPeer struct {
|
||||||
shutdown bool
|
shutdown bool
|
||||||
started bool
|
started bool
|
||||||
|
|
||||||
engine connections.Engine
|
|
||||||
queue *event.Queue
|
queue *event.Queue
|
||||||
eventBus *event.Manager
|
eventBus *event.Manager
|
||||||
}
|
}
|
||||||
|
@ -47,9 +46,7 @@ type CwtchPeer interface {
|
||||||
SendMessageToGroupTracked(string, string) (string, error)
|
SendMessageToGroupTracked(string, string) (string, error)
|
||||||
|
|
||||||
GetProfile() *model.Profile
|
GetProfile() *model.Profile
|
||||||
|
GetPeerState(string) connections.ConnectionState
|
||||||
GetPeers() map[string]connections.ConnectionState
|
|
||||||
GetServers() map[string]connections.ConnectionState
|
|
||||||
|
|
||||||
StartGroup(string) (string, []byte, error)
|
StartGroup(string) (string, []byte, error)
|
||||||
|
|
||||||
|
@ -57,13 +54,16 @@ type CwtchPeer interface {
|
||||||
ExportGroup(string) (string, error)
|
ExportGroup(string) (string, error)
|
||||||
|
|
||||||
GetGroup(string) *model.Group
|
GetGroup(string) *model.Group
|
||||||
|
GetGroupState(string) connections.ConnectionState
|
||||||
GetGroups() []string
|
GetGroups() []string
|
||||||
AddContact(nick, onion string, publickey []byte, trusted bool)
|
AddContact(nick, onion string, trusted bool)
|
||||||
GetContacts() []string
|
GetContacts() []string
|
||||||
GetContact(string) *model.PublicProfile
|
GetContact(string) *model.PublicProfile
|
||||||
|
|
||||||
IsStarted() bool
|
IsStarted() bool
|
||||||
Listen()
|
Listen()
|
||||||
|
StartPeersConnections()
|
||||||
|
StartGroupConnections()
|
||||||
Shutdown()
|
Shutdown()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,19 +90,8 @@ func (cp *cwtchPeer) Init(acn connectivity.ACN, eventBus *event.Manager) {
|
||||||
cp.eventBus = eventBus
|
cp.eventBus = eventBus
|
||||||
cp.eventBus.Subscribe(event.EncryptedGroupMessage, cp.queue.EventChannel)
|
cp.eventBus.Subscribe(event.EncryptedGroupMessage, cp.queue.EventChannel)
|
||||||
cp.eventBus.Subscribe(event.NewGroupInvite, cp.queue.EventChannel)
|
cp.eventBus.Subscribe(event.NewGroupInvite, cp.queue.EventChannel)
|
||||||
|
cp.eventBus.Subscribe(event.ServerStateChange, cp.queue.EventChannel)
|
||||||
// Calculate a list of Peers who have been Blocked.
|
cp.eventBus.Subscribe(event.PeerStateChange, cp.queue.EventChannel)
|
||||||
blockedPeers := []string{}
|
|
||||||
for _, contact := range cp.Profile.GetContacts() {
|
|
||||||
c, _ := cp.Profile.GetContact(contact)
|
|
||||||
if c.Blocked {
|
|
||||||
blockedPeers = append(blockedPeers, c.Onion)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Would be nice if ProtocolEngine did not need to explicitly be given the Private Key.
|
|
||||||
identity := identity.InitializeV3(cp.Profile.Name, &cp.Profile.Ed25519PrivateKey, &cp.Profile.Ed25519PublicKey)
|
|
||||||
cp.engine = connections.NewProtocolEngine(identity, cp.Profile.Ed25519PrivateKey, acn, eventBus, blockedPeers)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ImportGroup intializes a group from an imported source rather than a peer invite
|
// ImportGroup intializes a group from an imported source rather than a peer invite
|
||||||
|
@ -175,8 +164,9 @@ func (cp *cwtchPeer) GetGroup(groupID string) *model.Group {
|
||||||
return cp.Profile.GetGroupByGroupID(groupID)
|
return cp.Profile.GetGroupByGroupID(groupID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cp *cwtchPeer) AddContact(nick, onion string, publickey []byte, trusted bool) {
|
func (cp *cwtchPeer) AddContact(nick, onion string, trusted bool) {
|
||||||
pp := &model.PublicProfile{Name: nick, Ed25519PublicKey: publickey, Trusted: trusted, Blocked: false, Onion: onion, Attributes: map[string]string{"nick": nick}}
|
decodedPub, _ := base32.StdEncoding.DecodeString(strings.ToUpper(onion))
|
||||||
|
pp := &model.PublicProfile{Name: nick, Ed25519PublicKey: decodedPub, Trusted: trusted, Blocked: false, Onion: onion, Attributes: map[string]string{"nick": nick}}
|
||||||
cp.Profile.AddContact(onion, pp)
|
cp.Profile.AddContact(onion, pp)
|
||||||
pd, _ := json.Marshal(pp)
|
pd, _ := json.Marshal(pp)
|
||||||
cp.eventBus.Publish(event.NewEvent(event.PeerCreated, map[event.Field]string{
|
cp.eventBus.Publish(event.NewEvent(event.PeerCreated, map[event.Field]string{
|
||||||
|
@ -201,6 +191,14 @@ func (cp *cwtchPeer) GetProfile() *model.Profile {
|
||||||
return cp.Profile
|
return cp.Profile
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (cp *cwtchPeer) GetPeerState(onion string) connections.ConnectionState {
|
||||||
|
return connections.ConnectionStateType[cp.Profile.Contacts[onion].State]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cp *cwtchPeer) GetGroupState(groupid string) connections.ConnectionState {
|
||||||
|
return connections.ConnectionStateType[cp.Profile.Groups[groupid].State]
|
||||||
|
}
|
||||||
|
|
||||||
// PeerWithOnion is the entry point for cwtchPeer relationships
|
// PeerWithOnion is the entry point for cwtchPeer relationships
|
||||||
func (cp *cwtchPeer) PeerWithOnion(onion string) *connections.PeerPeerConnection {
|
func (cp *cwtchPeer) PeerWithOnion(onion string) *connections.PeerPeerConnection {
|
||||||
cp.eventBus.Publish(event.NewEvent(event.PeerRequest, map[event.Field]string{event.RemotePeer: onion}))
|
cp.eventBus.Publish(event.NewEvent(event.PeerRequest, map[event.Field]string{event.RemotePeer: onion}))
|
||||||
|
@ -255,16 +253,6 @@ func (cp *cwtchPeer) SendMessageToPeer(onion string, message string) string {
|
||||||
return event.EventID
|
return event.EventID
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPeers returns a list of peer connections.
|
|
||||||
func (cp *cwtchPeer) GetPeers() map[string]connections.ConnectionState {
|
|
||||||
return cp.engine.GetPeers()
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetServers returns a list of server connections
|
|
||||||
func (cp *cwtchPeer) GetServers() map[string]connections.ConnectionState {
|
|
||||||
return cp.engine.GetServers()
|
|
||||||
}
|
|
||||||
|
|
||||||
// TrustPeer sets an existing peer relationship to trusted
|
// TrustPeer sets an existing peer relationship to trusted
|
||||||
func (cp *cwtchPeer) TrustPeer(peer string) error {
|
func (cp *cwtchPeer) TrustPeer(peer string) error {
|
||||||
err := cp.Profile.TrustPeer(peer)
|
err := cp.Profile.TrustPeer(peer)
|
||||||
|
@ -298,14 +286,34 @@ func (cp *cwtchPeer) RejectInvite(groupID string) {
|
||||||
cp.Profile.RejectInvite(groupID)
|
cp.Profile.RejectInvite(groupID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Listen makes the peer open a listening port to accept incoming connections (and be detactably online)
|
||||||
func (cp *cwtchPeer) Listen() {
|
func (cp *cwtchPeer) Listen() {
|
||||||
cp.eventBus.Publish(event.NewEvent(event.ProtocolEngineStartListen, map[event.Field]string{}))
|
cp.eventBus.Publish(event.NewEvent(event.ProtocolEngineStartListen, map[event.Field]string{}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// StartGroupConnections attempts to connect to all group servers (thus initiating reconnect attempts in the conectionsmanager)
|
||||||
|
func (cp *cwtchPeer) StartPeersConnections() {
|
||||||
|
for _, contact := range cp.GetContacts() {
|
||||||
|
cp.PeerWithOnion(contact)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// StartPeerConnections attempts to connect to all peers (thus initiating reconnect attempts in the conectionsmanager)
|
||||||
|
func (cp *cwtchPeer) StartGroupConnections() {
|
||||||
|
joinedServers := map[string]bool{}
|
||||||
|
for _, groupID := range cp.GetGroups() {
|
||||||
|
// Only send a join server packet if we haven't joined this server yet...
|
||||||
|
group := cp.GetGroup(groupID)
|
||||||
|
if joined := joinedServers[groupID]; group.Accepted && !joined {
|
||||||
|
cp.JoinServer(group.GroupServer)
|
||||||
|
joinedServers[group.GroupServer] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Shutdown kills all connections and cleans up all goroutines for the peer
|
// Shutdown kills all connections and cleans up all goroutines for the peer
|
||||||
func (cp *cwtchPeer) Shutdown() {
|
func (cp *cwtchPeer) Shutdown() {
|
||||||
cp.shutdown = true
|
cp.shutdown = true
|
||||||
cp.engine.Shutdown()
|
|
||||||
cp.queue.Shutdown()
|
cp.queue.Shutdown()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -328,6 +336,16 @@ func (cp *cwtchPeer) eventHandler() {
|
||||||
var groupInvite protocol.GroupChatInvite
|
var groupInvite protocol.GroupChatInvite
|
||||||
proto.Unmarshal([]byte(ev.Data[event.GroupInvite]), &groupInvite)
|
proto.Unmarshal([]byte(ev.Data[event.GroupInvite]), &groupInvite)
|
||||||
cp.Profile.ProcessInvite(&groupInvite, ev.Data[event.RemotePeer])
|
cp.Profile.ProcessInvite(&groupInvite, ev.Data[event.RemotePeer])
|
||||||
|
case event.PeerStateChange:
|
||||||
|
if _, exists := cp.Profile.Contacts[ev.Data[event.RemotePeer]]; exists {
|
||||||
|
cp.Profile.Contacts[ev.Data[event.RemotePeer]].State = ev.Data[event.ConnectionState]
|
||||||
|
}
|
||||||
|
case event.ServerStateChange:
|
||||||
|
for _, group := range cp.Profile.Groups {
|
||||||
|
if group.GroupServer == ev.Data[event.GroupServer] {
|
||||||
|
group.State = ev.Data[event.ConnectionState]
|
||||||
|
}
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
if ev.EventType != "" {
|
if ev.EventType != "" {
|
||||||
log.Errorf("peer event handler received an event it was not subscribed for: %v", ev.EventType)
|
log.Errorf("peer event handler received an event it was not subscribed for: %v", ev.EventType)
|
||||||
|
|
|
@ -42,12 +42,12 @@ func (m *Manager) ManagePeerConnection(host string, engine Engine) *PeerPeerConn
|
||||||
}
|
}
|
||||||
|
|
||||||
// ManageServerConnection creates a new ServerConnection for Host with the given callback handler.
|
// ManageServerConnection creates a new ServerConnection for Host with the given callback handler.
|
||||||
func (m *Manager) ManageServerConnection(host string, messageHandler func(string, *protocol.GroupMessage), closedHandler func(string)) {
|
func (m *Manager) ManageServerConnection(host string, engine Engine, messageHandler func(string, *protocol.GroupMessage), closedHandler func(string)) {
|
||||||
m.lock.Lock()
|
m.lock.Lock()
|
||||||
|
|
||||||
psc, exists := m.serverConnections[host]
|
psc, exists := m.serverConnections[host]
|
||||||
|
|
||||||
newPsc := NewPeerServerConnection(m.acn, host)
|
newPsc := NewPeerServerConnection(engine, host)
|
||||||
newPsc.GroupMessageHandler = messageHandler
|
newPsc.GroupMessageHandler = messageHandler
|
||||||
newPsc.CloseHandler = closedHandler
|
newPsc.CloseHandler = closedHandler
|
||||||
go newPsc.Run()
|
go newPsc.Run()
|
||||||
|
@ -60,28 +60,6 @@ func (m *Manager) ManageServerConnection(host string, messageHandler func(string
|
||||||
m.lock.Unlock()
|
m.lock.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPeers returns a map of all peer connections with their state
|
|
||||||
func (m *Manager) GetPeers() map[string]ConnectionState {
|
|
||||||
rm := make(map[string]ConnectionState)
|
|
||||||
m.lock.Lock()
|
|
||||||
for onion, ppc := range m.peerConnections {
|
|
||||||
rm[onion] = ppc.GetState()
|
|
||||||
}
|
|
||||||
m.lock.Unlock()
|
|
||||||
return rm
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetServers returns a map of all server connections with their state.
|
|
||||||
func (m *Manager) GetServers() map[string]ConnectionState {
|
|
||||||
rm := make(map[string]ConnectionState)
|
|
||||||
m.lock.Lock()
|
|
||||||
for onion, psc := range m.serverConnections {
|
|
||||||
rm[onion] = psc.GetState()
|
|
||||||
}
|
|
||||||
m.lock.Unlock()
|
|
||||||
return rm
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetPeerPeerConnectionForOnion safely returns a given peer connection
|
// GetPeerPeerConnectionForOnion safely returns a given peer connection
|
||||||
func (m *Manager) GetPeerPeerConnectionForOnion(host string) (ppc *PeerPeerConnection) {
|
func (m *Manager) GetPeerPeerConnectionForOnion(host string) (ppc *PeerPeerConnection) {
|
||||||
m.lock.Lock()
|
m.lock.Lock()
|
||||||
|
@ -103,7 +81,6 @@ func (m *Manager) AttemptReconnections() {
|
||||||
maxTimeout := time.Minute * 5
|
maxTimeout := time.Minute * 5
|
||||||
// nearly instant first run, next few runs will prolly be too quick to have any FAILED and will gracefully slow to MAX after that
|
// nearly instant first run, next few runs will prolly be too quick to have any FAILED and will gracefully slow to MAX after that
|
||||||
timeout := time.Millisecond * 500
|
timeout := time.Millisecond * 500
|
||||||
|
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-time.After(timeout):
|
case <-time.After(timeout):
|
||||||
|
|
|
@ -45,6 +45,7 @@ type engine struct {
|
||||||
type Engine interface {
|
type Engine interface {
|
||||||
Identity() identity.Identity
|
Identity() identity.Identity
|
||||||
ACN() connectivity.ACN
|
ACN() connectivity.ACN
|
||||||
|
EventManager() *event.Manager
|
||||||
|
|
||||||
GetPeerHandler(string) *CwtchPeerHandler
|
GetPeerHandler(string) *CwtchPeerHandler
|
||||||
ContactRequest(string, string) string
|
ContactRequest(string, string) string
|
||||||
|
@ -52,9 +53,6 @@ type Engine interface {
|
||||||
LookupContact(string, rsa.PublicKey) (bool, bool)
|
LookupContact(string, rsa.PublicKey) (bool, bool)
|
||||||
LookupContactV3(string, ed25519.PublicKey) (bool, bool)
|
LookupContactV3(string, ed25519.PublicKey) (bool, bool)
|
||||||
|
|
||||||
GetPeers() map[string]ConnectionState
|
|
||||||
GetServers() map[string]ConnectionState
|
|
||||||
|
|
||||||
Shutdown()
|
Shutdown()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,6 +92,10 @@ func (e *engine) Identity() identity.Identity {
|
||||||
return e.identity
|
return e.identity
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e *engine) EventManager() *event.Manager {
|
||||||
|
return e.eventManager
|
||||||
|
}
|
||||||
|
|
||||||
// eventHandler process events from other subsystems
|
// eventHandler process events from other subsystems
|
||||||
func (e *engine) eventHandler() {
|
func (e *engine) eventHandler() {
|
||||||
for {
|
for {
|
||||||
|
@ -244,7 +246,7 @@ func (e *engine) finishedFetch(server string) {
|
||||||
|
|
||||||
// joinServer manages a new server connection with the given onion address
|
// joinServer manages a new server connection with the given onion address
|
||||||
func (e *engine) joinServer(onion string) {
|
func (e *engine) joinServer(onion string) {
|
||||||
e.connectionsManager.ManageServerConnection(onion, e.receiveGroupMessage, e.finishedFetch)
|
e.connectionsManager.ManageServerConnection(onion, e, e.receiveGroupMessage, e.finishedFetch)
|
||||||
}
|
}
|
||||||
|
|
||||||
// sendMessageToGroup attempts to sent the given message to the given group id.
|
// sendMessageToGroup attempts to sent the given message to the given group id.
|
||||||
|
@ -264,16 +266,6 @@ func (e *engine) sendMessageToGroup(server string, ct []byte, sig []byte) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPeers returns a list of peer connections.
|
|
||||||
func (e *engine) GetPeers() map[string]ConnectionState {
|
|
||||||
return e.connectionsManager.GetPeers()
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetServers returns a list of server connections
|
|
||||||
func (e *engine) GetServers() map[string]ConnectionState {
|
|
||||||
return e.connectionsManager.GetServers()
|
|
||||||
}
|
|
||||||
|
|
||||||
// CwtchPeerInstance encapsulates incoming peer connections
|
// CwtchPeerInstance encapsulates incoming peer connections
|
||||||
type CwtchPeerInstance struct {
|
type CwtchPeerInstance struct {
|
||||||
rai *application.Instance
|
rai *application.Instance
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package connections
|
package connections
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"cwtch.im/cwtch/event"
|
||||||
"cwtch.im/cwtch/protocol/connections/peer"
|
"cwtch.im/cwtch/protocol/connections/peer"
|
||||||
"errors"
|
"errors"
|
||||||
"git.openprivacy.ca/openprivacy/libricochet-go"
|
"git.openprivacy.ca/openprivacy/libricochet-go"
|
||||||
|
@ -28,6 +29,14 @@ func NewPeerPeerConnection(peerhostname string, protocolEngine Engine) *PeerPeer
|
||||||
return ppc
|
return ppc
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ppc *PeerPeerConnection) setState(state ConnectionState) {
|
||||||
|
ppc.state = state
|
||||||
|
ppc.protocolEngine.EventManager().Publish(event.NewEvent(event.PeerStateChange, map[event.Field]string{
|
||||||
|
event.RemotePeer: string(ppc.PeerHostname),
|
||||||
|
event.ConnectionState: ConnectionStateName[state],
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
// GetState returns the current connection state
|
// GetState returns the current connection state
|
||||||
func (ppc *PeerPeerConnection) GetState() ConnectionState {
|
func (ppc *PeerPeerConnection) GetState() ConnectionState {
|
||||||
return ppc.state
|
return ppc.state
|
||||||
|
@ -78,14 +87,14 @@ func (ppc *PeerPeerConnection) WaitTilAuthenticated() {
|
||||||
|
|
||||||
// Run manages the setup and teardown of a peer->peer connection
|
// Run manages the setup and teardown of a peer->peer connection
|
||||||
func (ppc *PeerPeerConnection) Run() error {
|
func (ppc *PeerPeerConnection) Run() error {
|
||||||
ppc.state = CONNECTING
|
ppc.setState(CONNECTING)
|
||||||
rc, err := goricochet.Open(ppc.protocolEngine.ACN(), ppc.PeerHostname)
|
rc, err := goricochet.Open(ppc.protocolEngine.ACN(), ppc.PeerHostname)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
ppc.connection = rc
|
ppc.connection = rc
|
||||||
ppc.state = CONNECTED
|
ppc.setState(CONNECTED)
|
||||||
_, err := connection.HandleOutboundConnection(ppc.connection).ProcessAuthAsV3Client(ppc.protocolEngine.Identity())
|
_, err := connection.HandleOutboundConnection(ppc.connection).ProcessAuthAsV3Client(ppc.protocolEngine.Identity())
|
||||||
if err == nil {
|
if err == nil {
|
||||||
ppc.state = AUTHENTICATED
|
ppc.setState(AUTHENTICATED)
|
||||||
go func() {
|
go func() {
|
||||||
ppc.connection.Do(func() error {
|
ppc.connection.Do(func() error {
|
||||||
ppc.connection.RequestOpenChannel("im.cwtch.peer", &peer.CwtchPeerChannel{Handler: ppc.protocolEngine.GetPeerHandler(ppc.PeerHostname)})
|
ppc.connection.RequestOpenChannel("im.cwtch.peer", &peer.CwtchPeerChannel{Handler: ppc.protocolEngine.GetPeerHandler(ppc.PeerHostname)})
|
||||||
|
@ -101,13 +110,13 @@ func (ppc *PeerPeerConnection) Run() error {
|
||||||
ppc.connection.Process(ppc)
|
ppc.connection.Process(ppc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ppc.state = FAILED
|
ppc.setState(FAILED)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close closes the connection
|
// Close closes the connection
|
||||||
func (ppc *PeerPeerConnection) Close() {
|
func (ppc *PeerPeerConnection) Close() {
|
||||||
ppc.state = KILLED
|
ppc.setState(KILLED)
|
||||||
if ppc.connection != nil {
|
if ppc.connection != nil {
|
||||||
ppc.connection.Close()
|
ppc.connection.Close()
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package connections
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
|
"cwtch.im/cwtch/event"
|
||||||
"cwtch.im/cwtch/protocol"
|
"cwtch.im/cwtch/protocol"
|
||||||
"cwtch.im/cwtch/protocol/connections/fetch"
|
"cwtch.im/cwtch/protocol/connections/fetch"
|
||||||
"cwtch.im/cwtch/protocol/connections/listen"
|
"cwtch.im/cwtch/protocol/connections/listen"
|
||||||
|
@ -10,7 +11,6 @@ import (
|
||||||
"git.openprivacy.ca/openprivacy/libricochet-go"
|
"git.openprivacy.ca/openprivacy/libricochet-go"
|
||||||
"git.openprivacy.ca/openprivacy/libricochet-go/channels"
|
"git.openprivacy.ca/openprivacy/libricochet-go/channels"
|
||||||
"git.openprivacy.ca/openprivacy/libricochet-go/connection"
|
"git.openprivacy.ca/openprivacy/libricochet-go/connection"
|
||||||
"git.openprivacy.ca/openprivacy/libricochet-go/connectivity"
|
|
||||||
"git.openprivacy.ca/openprivacy/libricochet-go/identity"
|
"git.openprivacy.ca/openprivacy/libricochet-go/identity"
|
||||||
"git.openprivacy.ca/openprivacy/libricochet-go/log"
|
"git.openprivacy.ca/openprivacy/libricochet-go/log"
|
||||||
"golang.org/x/crypto/ed25519"
|
"golang.org/x/crypto/ed25519"
|
||||||
|
@ -23,16 +23,16 @@ type PeerServerConnection struct {
|
||||||
Server string
|
Server string
|
||||||
state ConnectionState
|
state ConnectionState
|
||||||
connection *connection.Connection
|
connection *connection.Connection
|
||||||
acn connectivity.ACN
|
protocolEngine Engine
|
||||||
|
|
||||||
GroupMessageHandler func(string, *protocol.GroupMessage)
|
GroupMessageHandler func(string, *protocol.GroupMessage)
|
||||||
CloseHandler func(string)
|
CloseHandler func(string)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewPeerServerConnection creates a new Peer->Server outbound connection
|
// NewPeerServerConnection creates a new Peer->Server outbound connection
|
||||||
func NewPeerServerConnection(acn connectivity.ACN, serverhostname string) *PeerServerConnection {
|
func NewPeerServerConnection(engine Engine, serverhostname string) *PeerServerConnection {
|
||||||
psc := new(PeerServerConnection)
|
psc := new(PeerServerConnection)
|
||||||
psc.acn = acn
|
psc.protocolEngine = engine
|
||||||
psc.Server = serverhostname
|
psc.Server = serverhostname
|
||||||
psc.Init()
|
psc.Init()
|
||||||
return psc
|
return psc
|
||||||
|
@ -43,6 +43,14 @@ func (psc *PeerServerConnection) GetState() ConnectionState {
|
||||||
return psc.state
|
return psc.state
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (psc *PeerServerConnection) setState(state ConnectionState) {
|
||||||
|
psc.state = state
|
||||||
|
psc.protocolEngine.EventManager().Publish(event.NewEvent(event.ServerStateChange, map[event.Field]string{
|
||||||
|
event.GroupServer: string(psc.Server),
|
||||||
|
event.ConnectionState: ConnectionStateName[state],
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
// WaitTilAuthenticated waits until the underlying connection is authenticated
|
// WaitTilAuthenticated waits until the underlying connection is authenticated
|
||||||
func (psc *PeerServerConnection) WaitTilAuthenticated() {
|
func (psc *PeerServerConnection) WaitTilAuthenticated() {
|
||||||
for {
|
for {
|
||||||
|
@ -56,15 +64,15 @@ func (psc *PeerServerConnection) WaitTilAuthenticated() {
|
||||||
// Run manages the setup and teardown of a peer server connection
|
// Run manages the setup and teardown of a peer server connection
|
||||||
func (psc *PeerServerConnection) Run() error {
|
func (psc *PeerServerConnection) Run() error {
|
||||||
log.Infof("Connecting to %v", psc.Server)
|
log.Infof("Connecting to %v", psc.Server)
|
||||||
rc, err := goricochet.Open(psc.acn, psc.Server)
|
rc, err := goricochet.Open(psc.protocolEngine.ACN(), psc.Server)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
psc.connection = rc
|
psc.connection = rc
|
||||||
psc.state = CONNECTED
|
psc.setState(CONNECTED)
|
||||||
pub, priv, err := ed25519.GenerateKey(rand.Reader)
|
pub, priv, err := ed25519.GenerateKey(rand.Reader)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
_, err := connection.HandleOutboundConnection(psc.connection).ProcessAuthAsV3Client(identity.InitializeV3("cwtchpeer", &priv, &pub))
|
_, err := connection.HandleOutboundConnection(psc.connection).ProcessAuthAsV3Client(identity.InitializeV3("cwtchpeer", &priv, &pub))
|
||||||
if err == nil {
|
if err == nil {
|
||||||
psc.state = AUTHENTICATED
|
psc.setState(AUTHENTICATED)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
psc.connection.Do(func() error {
|
psc.connection.Do(func() error {
|
||||||
|
@ -81,7 +89,7 @@ func (psc *PeerServerConnection) Run() error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
psc.state = FAILED
|
psc.setState(FAILED)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -128,7 +136,7 @@ func (psc *PeerServerConnection) SendGroupMessage(gm *protocol.GroupMessage) err
|
||||||
|
|
||||||
// Close shuts down the connection (freeing the handler goroutines)
|
// Close shuts down the connection (freeing the handler goroutines)
|
||||||
func (psc *PeerServerConnection) Close() {
|
func (psc *PeerServerConnection) Close() {
|
||||||
psc.state = KILLED
|
psc.setState(KILLED)
|
||||||
if psc.connection != nil {
|
if psc.connection != nil {
|
||||||
psc.connection.Close()
|
psc.connection.Close()
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package connections
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
|
"cwtch.im/cwtch/event"
|
||||||
"cwtch.im/cwtch/protocol"
|
"cwtch.im/cwtch/protocol"
|
||||||
"cwtch.im/cwtch/server/fetch"
|
"cwtch.im/cwtch/server/fetch"
|
||||||
"cwtch.im/cwtch/server/send"
|
"cwtch.im/cwtch/server/send"
|
||||||
|
@ -75,7 +76,11 @@ func TestPeerServerConnection(t *testing.T) {
|
||||||
<-listenChan
|
<-listenChan
|
||||||
onionAddr := identity.Hostname()
|
onionAddr := identity.Hostname()
|
||||||
|
|
||||||
psc := NewPeerServerConnection(connectivity.LocalProvider(), "127.0.0.1:5451|"+onionAddr)
|
manager := &event.Manager{}
|
||||||
|
manager.Initialize()
|
||||||
|
engine := NewProtocolEngine(identity, priv, connectivity.LocalProvider(), manager, nil)
|
||||||
|
|
||||||
|
psc := NewPeerServerConnection(engine, "127.0.0.1:5451|"+onionAddr)
|
||||||
numcalls := 0
|
numcalls := 0
|
||||||
psc.GroupMessageHandler = func(s string, gm *protocol.GroupMessage) {
|
psc.GroupMessageHandler = func(s string, gm *protocol.GroupMessage) {
|
||||||
numcalls++
|
numcalls++
|
||||||
|
|
|
@ -20,4 +20,8 @@ const (
|
||||||
var (
|
var (
|
||||||
// ConnectionStateName allows conversion of states to their string representations
|
// ConnectionStateName allows conversion of states to their string representations
|
||||||
ConnectionStateName = []string{"Disconnected", "Connecting", "Connected", "Authenticated", "Failed", "Killed"}
|
ConnectionStateName = []string{"Disconnected", "Connecting", "Connected", "Authenticated", "Failed", "Killed"}
|
||||||
|
|
||||||
|
// ConnectionStateType allows conversion of strings to their state type
|
||||||
|
ConnectionStateType = map[string]ConnectionState{"Disconnected": DISCONNECTED, "Connecting": CONNECTING,
|
||||||
|
"Connected": CONNECTED, "Authenticated": AUTHENTICATED, "Failed": FAILED, "Killed": KILLED}
|
||||||
)
|
)
|
||||||
|
|
|
@ -21,6 +21,7 @@ type profileStore struct {
|
||||||
profile *model.Profile
|
profile *model.Profile
|
||||||
eventManager *event.Manager
|
eventManager *event.Manager
|
||||||
queue *event.Queue
|
queue *event.Queue
|
||||||
|
writer bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// ProfileStore is an interface to managing the storage of Cwtch Profiles
|
// ProfileStore is an interface to managing the storage of Cwtch Profiles
|
||||||
|
@ -30,11 +31,11 @@ type ProfileStore interface {
|
||||||
GetProfileCopy() *model.Profile
|
GetProfileCopy() *model.Profile
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewProfileStore returns a profile store backed by a filestore listening for events and saving them
|
// NewProfileWriterStore returns a profile store backed by a filestore listening for events and saving them
|
||||||
// directory should be $appDir/profiles/$rand
|
// directory should be $appDir/profiles/$rand
|
||||||
func NewProfileStore(eventManager *event.Manager, directory, password string, profile *model.Profile) ProfileStore {
|
func NewProfileWriterStore(eventManager *event.Manager, directory, password string, profile *model.Profile) ProfileStore {
|
||||||
os.Mkdir(directory, 0700)
|
os.Mkdir(directory, 0700)
|
||||||
ps := &profileStore{fs: NewFileStore(directory, profileFilename, password), password: password, directory: directory, profile: profile, eventManager: eventManager, streamStores: map[string]StreamStore{}}
|
ps := &profileStore{fs: NewFileStore(directory, profileFilename, password), password: password, directory: directory, profile: profile, eventManager: eventManager, streamStores: map[string]StreamStore{}, writer: true}
|
||||||
ps.queue = event.NewEventQueue(100)
|
ps.queue = event.NewEventQueue(100)
|
||||||
if profile != nil {
|
if profile != nil {
|
||||||
ps.save()
|
ps.save()
|
||||||
|
@ -55,6 +56,15 @@ func NewProfileStore(eventManager *event.Manager, directory, password string, pr
|
||||||
return ps
|
return ps
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewProfileReaderStore returns a profile store backed by a filestore
|
||||||
|
// directory should be $appDir/profiles/$rand
|
||||||
|
func NewProfileReaderStore(directory, password string, profile *model.Profile) ProfileStore {
|
||||||
|
os.Mkdir(directory, 0700)
|
||||||
|
ps := &profileStore{fs: NewFileStore(directory, profileFilename, password), password: password, directory: directory, profile: profile, eventManager: nil, streamStores: map[string]StreamStore{}, writer: true}
|
||||||
|
|
||||||
|
return ps
|
||||||
|
}
|
||||||
|
|
||||||
// NewProfile creates a new profile for use in the profile store.
|
// NewProfile creates a new profile for use in the profile store.
|
||||||
func NewProfile(name string) *model.Profile {
|
func NewProfile(name string) *model.Profile {
|
||||||
profile := model.GenerateNewProfile(name)
|
profile := model.GenerateNewProfile(name)
|
||||||
|
@ -62,9 +72,12 @@ func NewProfile(name string) *model.Profile {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ps *profileStore) save() error {
|
func (ps *profileStore) save() error {
|
||||||
|
if ps.writer {
|
||||||
bytes, _ := json.Marshal(ps.profile)
|
bytes, _ := json.Marshal(ps.profile)
|
||||||
return ps.fs.Save(bytes)
|
return ps.fs.Save(bytes)
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Load instantiates a cwtchPeer from the file store
|
// Load instantiates a cwtchPeer from the file store
|
||||||
func (ps *profileStore) Load() error {
|
func (ps *profileStore) Load() error {
|
||||||
|
@ -181,5 +194,7 @@ func (ps *profileStore) eventHandler() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ps *profileStore) Shutdown() {
|
func (ps *profileStore) Shutdown() {
|
||||||
|
if ps.queue != nil {
|
||||||
ps.queue.Shutdown()
|
ps.queue.Shutdown()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@ func TestProfileStoreWriteRead(t *testing.T) {
|
||||||
eventBus := new(event.Manager)
|
eventBus := new(event.Manager)
|
||||||
eventBus.Initialize()
|
eventBus.Initialize()
|
||||||
profile := NewProfile(testProfileName)
|
profile := NewProfile(testProfileName)
|
||||||
ps1 := NewProfileStore(eventBus, testingDir, password, profile)
|
ps1 := NewProfileWriterStore(eventBus, testingDir, password, profile)
|
||||||
|
|
||||||
eventBus.Publish(event.NewEvent(event.SetAttribute, map[event.Field]string{event.Key: testKey, event.Data: testVal}))
|
eventBus.Publish(event.NewEvent(event.SetAttribute, map[event.Field]string{event.Key: testKey, event.Data: testVal}))
|
||||||
time.Sleep(1 * time.Second)
|
time.Sleep(1 * time.Second)
|
||||||
|
@ -50,7 +50,7 @@ func TestProfileStoreWriteRead(t *testing.T) {
|
||||||
|
|
||||||
ps1.Shutdown()
|
ps1.Shutdown()
|
||||||
|
|
||||||
ps2 := NewProfileStore(eventBus, testingDir, password, nil)
|
ps2 := NewProfileWriterStore(eventBus, testingDir, password, nil)
|
||||||
err = ps2.Load()
|
err = ps2.Load()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Error createing profileStore: %v\n", err)
|
t.Errorf("Error createing profileStore: %v\n", err)
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package testing
|
package testing
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"cwtch.im/cwtch/event"
|
app2 "cwtch.im/cwtch/app"
|
||||||
"cwtch.im/cwtch/model"
|
"cwtch.im/cwtch/model"
|
||||||
"cwtch.im/cwtch/peer"
|
"cwtch.im/cwtch/peer"
|
||||||
"cwtch.im/cwtch/protocol/connections"
|
"cwtch.im/cwtch/protocol/connections"
|
||||||
|
@ -55,16 +55,17 @@ func serverCheck(t *testing.T, serverAddr string) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func waitForPeerServerConnection(t *testing.T, peer peer.CwtchPeer, server string) {
|
func waitForPeerGroupConnection(t *testing.T, peer peer.CwtchPeer, groupID string) {
|
||||||
for {
|
for {
|
||||||
servers := peer.GetServers()
|
_, ok := peer.GetProfile().Groups[groupID]
|
||||||
state, ok := servers[server]
|
|
||||||
if ok {
|
if ok {
|
||||||
|
state := peer.GetGroupState(groupID)
|
||||||
|
//log.Infof("Waiting for Peer %v to join group %v - state: %v\n", peer.GetProfile().Name, groupID, state)
|
||||||
if state == connections.FAILED {
|
if state == connections.FAILED {
|
||||||
t.Fatalf("%v could not connect to %v", peer.GetProfile().Onion, server)
|
t.Fatalf("%v could not connect to %v", peer.GetProfile().Onion, groupID)
|
||||||
}
|
}
|
||||||
if state != connections.AUTHENTICATED {
|
if state != connections.AUTHENTICATED {
|
||||||
fmt.Printf("peer %v waiting connect to server %v, currently: %v\n", peer.GetProfile().Onion, server, connections.ConnectionStateName[state])
|
fmt.Printf("peer %v waiting connect to group %v, currently: %v\n", peer.GetProfile().Onion, groupID, connections.ConnectionStateName[state])
|
||||||
time.Sleep(time.Second * 5)
|
time.Sleep(time.Second * 5)
|
||||||
continue
|
continue
|
||||||
} else {
|
} else {
|
||||||
|
@ -78,9 +79,11 @@ func waitForPeerServerConnection(t *testing.T, peer peer.CwtchPeer, server strin
|
||||||
|
|
||||||
func waitForPeerPeerConnection(t *testing.T, peera peer.CwtchPeer, peerb peer.CwtchPeer) {
|
func waitForPeerPeerConnection(t *testing.T, peera peer.CwtchPeer, peerb peer.CwtchPeer) {
|
||||||
for {
|
for {
|
||||||
peers := peera.GetPeers()
|
//peers := peera.GetPeers()
|
||||||
state, ok := peers[peerb.GetProfile().Onion]
|
_, ok := peera.GetProfile().Contacts[peerb.GetProfile().Onion]
|
||||||
if ok {
|
if ok {
|
||||||
|
state := peera.GetPeerState(peerb.GetProfile().Onion)
|
||||||
|
//log.Infof("Waiting for Peer %v to peer with peer: %v - state: %v\n", peera.GetProfile().Name, peerb.GetProfile().Name, state)
|
||||||
if state == connections.FAILED {
|
if state == connections.FAILED {
|
||||||
t.Fatalf("%v could not connect to %v", peera.GetProfile().Onion, peerb.GetProfile().Onion)
|
t.Fatalf("%v could not connect to %v", peera.GetProfile().Onion, peerb.GetProfile().Onion)
|
||||||
}
|
}
|
||||||
|
@ -132,35 +135,33 @@ func TestCwtchPeerIntegration(t *testing.T) {
|
||||||
|
|
||||||
numGoRoutinesPostServer := runtime.NumGoroutine()
|
numGoRoutinesPostServer := runtime.NumGoroutine()
|
||||||
|
|
||||||
|
app := app2.NewApp(acn, "./storage")
|
||||||
|
|
||||||
// ***** cwtchPeer setup *****
|
// ***** cwtchPeer setup *****
|
||||||
|
|
||||||
// It's important that each Peer have their own EventBus
|
// It's important that each Peer have their own EventBus
|
||||||
aliceEventBus := new(event.Manager)
|
/*aliceEventBus := new(event.Manager)
|
||||||
aliceEventBus.Initialize()
|
aliceEventBus.Initialize()
|
||||||
bobEventBus := new(event.Manager)
|
bobEventBus := new(event.Manager)
|
||||||
bobEventBus.Initialize()
|
bobEventBus.Initialize()
|
||||||
carolEventBus := new(event.Manager)
|
carolEventBus := new(event.Manager)
|
||||||
carolEventBus.Initialize()
|
carolEventBus.Initialize()*/
|
||||||
|
|
||||||
fmt.Println("Creating Alice...")
|
fmt.Println("Creating Alice...")
|
||||||
alice := peer.NewCwtchPeer("Alice")
|
alice, _ := app.CreatePeer("alice", "asdfasdf")
|
||||||
alice.Init(acn, aliceEventBus)
|
|
||||||
alice.Listen()
|
|
||||||
fmt.Println("Alice created:", alice.GetProfile().Onion)
|
fmt.Println("Alice created:", alice.GetProfile().Onion)
|
||||||
|
|
||||||
fmt.Println("Creating Bob...")
|
fmt.Println("Creating Bob...")
|
||||||
bob := peer.NewCwtchPeer("Bob")
|
bob, _ := app.CreatePeer("bob", "asdfasdf")
|
||||||
bob.Init(acn, bobEventBus)
|
|
||||||
bob.Listen()
|
|
||||||
fmt.Println("Bob created:", bob.GetProfile().Onion)
|
fmt.Println("Bob created:", bob.GetProfile().Onion)
|
||||||
|
|
||||||
fmt.Println("Creating Carol...")
|
fmt.Println("Creating Carol...")
|
||||||
carol := peer.NewCwtchPeer("Carol")
|
carol, _ := app.CreatePeer("Carol", "asdfasdf")
|
||||||
carol.Init(acn, carolEventBus)
|
|
||||||
carol.Listen()
|
|
||||||
fmt.Println("Carol created:", carol.GetProfile().Onion)
|
fmt.Println("Carol created:", carol.GetProfile().Onion)
|
||||||
|
|
||||||
fmt.Println("Waiting for Alice, Bob, and Carol to connection with onion network...")
|
app.LaunchPeers()
|
||||||
|
|
||||||
|
fmt.Println("Waiting for Alice, Bob, and Carol to connect with onion network...")
|
||||||
time.Sleep(time.Second * 90)
|
time.Sleep(time.Second * 90)
|
||||||
numGoRoutinesPostPeerStart := runtime.NumGoroutine()
|
numGoRoutinesPostPeerStart := runtime.NumGoroutine()
|
||||||
|
|
||||||
|
@ -175,8 +176,10 @@ func TestCwtchPeerIntegration(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println("Alice peering with Bob...")
|
fmt.Println("Alice peering with Bob...")
|
||||||
|
alice.AddContact("Bob", bob.GetProfile().Onion, false) // Add contact so we can track connection state
|
||||||
alice.PeerWithOnion(bob.GetProfile().Onion)
|
alice.PeerWithOnion(bob.GetProfile().Onion)
|
||||||
fmt.Println("Alice peering with Carol...")
|
fmt.Println("Alice peering with Carol...")
|
||||||
|
alice.AddContact("Carol", carol.GetProfile().Onion, false)
|
||||||
alice.PeerWithOnion(carol.GetProfile().Onion)
|
alice.PeerWithOnion(carol.GetProfile().Onion)
|
||||||
|
|
||||||
fmt.Println("Alice joining server...")
|
fmt.Println("Alice joining server...")
|
||||||
|
@ -185,10 +188,10 @@ func TestCwtchPeerIntegration(t *testing.T) {
|
||||||
bob.JoinServer(serverAddr)
|
bob.JoinServer(serverAddr)
|
||||||
|
|
||||||
fmt.Println("Waiting for alice to join server...")
|
fmt.Println("Waiting for alice to join server...")
|
||||||
waitForPeerServerConnection(t, alice, serverAddr)
|
waitForPeerGroupConnection(t, alice, groupID)
|
||||||
|
|
||||||
fmt.Println("Waiting for bob to join server...")
|
//fmt.Println("Waiting for bob to join server...")
|
||||||
waitForPeerServerConnection(t, bob, serverAddr)
|
//waitForPeerGroupConnection(t, bob, groupID)
|
||||||
|
|
||||||
fmt.Println("Waiting for alice and Bob to peer...")
|
fmt.Println("Waiting for alice and Bob to peer...")
|
||||||
waitForPeerPeerConnection(t, alice, bob)
|
waitForPeerPeerConnection(t, alice, bob)
|
||||||
|
@ -217,35 +220,9 @@ func TestCwtchPeerIntegration(t *testing.T) {
|
||||||
|
|
||||||
numGoRoutinesPostServerConnect := runtime.NumGoroutine()
|
numGoRoutinesPostServerConnect := runtime.NumGoroutine()
|
||||||
|
|
||||||
// ***** Fill up message history of server ******
|
|
||||||
|
|
||||||
/*
|
|
||||||
// filler group will be used to fill up the servers message history a bit to stress test fetch later for carol
|
|
||||||
fillerGroupId, _, err := alice.Profile.StartGroup(serverAddr)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Failed to init filler group: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Println("Alice filling message history of server...")
|
|
||||||
for i := 0; i < 100; i++ {
|
|
||||||
|
|
||||||
go func (x int) {
|
|
||||||
time.Sleep(time.Second * time.Duration(x))
|
|
||||||
err := alice.SendMessageToGroup(fillerGroupId, aliceLines[0])
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println("SEND", x, "ERROR:", err)
|
|
||||||
} else {
|
|
||||||
fmt.Println("SEND", x, " SUCCESS!")
|
|
||||||
}
|
|
||||||
}(i)
|
|
||||||
}
|
|
||||||
|
|
||||||
time.Sleep(time.Second * 110)
|
|
||||||
*/
|
|
||||||
// Wait for them to join the server
|
// Wait for them to join the server
|
||||||
waitForPeerServerConnection(t, alice, serverAddr)
|
waitForPeerGroupConnection(t, alice, groupID)
|
||||||
waitForPeerServerConnection(t, bob, serverAddr)
|
waitForPeerGroupConnection(t, bob, groupID)
|
||||||
//numGouRoutinesPostServerConnect := runtime.NumGoroutine()
|
//numGouRoutinesPostServerConnect := runtime.NumGoroutine()
|
||||||
|
|
||||||
// ***** Conversation *****
|
// ***** Conversation *****
|
||||||
|
@ -291,14 +268,13 @@ func TestCwtchPeerIntegration(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println("Shutting down Alice...")
|
fmt.Println("Shutting down Alice...")
|
||||||
alice.Shutdown()
|
app.ShutdownPeer(alice.GetProfile().Onion)
|
||||||
aliceEventBus.Shutdown()
|
|
||||||
time.Sleep(time.Second * 5)
|
time.Sleep(time.Second * 5)
|
||||||
numGoRoutinesPostAlice := runtime.NumGoroutine()
|
numGoRoutinesPostAlice := runtime.NumGoroutine()
|
||||||
|
|
||||||
fmt.Println("Carol joining server...")
|
fmt.Println("Carol joining server...")
|
||||||
carol.JoinServer(serverAddr)
|
carol.JoinServer(serverAddr)
|
||||||
waitForPeerServerConnection(t, carol, serverAddr)
|
waitForPeerGroupConnection(t, carol, groupID)
|
||||||
numGoRotinesPostCarolConnect := runtime.NumGoroutine()
|
numGoRotinesPostCarolConnect := runtime.NumGoroutine()
|
||||||
|
|
||||||
fmt.Println("Bob> ", bobLines[2])
|
fmt.Println("Bob> ", bobLines[2])
|
||||||
|
@ -380,8 +356,7 @@ func TestCwtchPeerIntegration(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println("Shutting down Bob...")
|
fmt.Println("Shutting down Bob...")
|
||||||
bob.Shutdown()
|
app.ShutdownPeer(bob.GetProfile().Onion)
|
||||||
bobEventBus.Shutdown()
|
|
||||||
time.Sleep(time.Second * 3)
|
time.Sleep(time.Second * 3)
|
||||||
numGoRoutinesPostBob := runtime.NumGoroutine()
|
numGoRoutinesPostBob := runtime.NumGoroutine()
|
||||||
if server != nil {
|
if server != nil {
|
||||||
|
@ -392,8 +367,7 @@ func TestCwtchPeerIntegration(t *testing.T) {
|
||||||
numGoRoutinesPostServerShutdown := runtime.NumGoroutine()
|
numGoRoutinesPostServerShutdown := runtime.NumGoroutine()
|
||||||
|
|
||||||
fmt.Println("Shutting down Carol...")
|
fmt.Println("Shutting down Carol...")
|
||||||
carol.Shutdown()
|
app.ShutdownPeer(carol.GetProfile().Onion)
|
||||||
carolEventBus.Shutdown()
|
|
||||||
time.Sleep(time.Second * 3)
|
time.Sleep(time.Second * 3)
|
||||||
numGoRoutinesPostCarol := runtime.NumGoroutine()
|
numGoRoutinesPostCarol := runtime.NumGoroutine()
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue