libricochet-go/application/application.go

161 lines
4.2 KiB
Go
Raw Normal View History

2017-05-02 23:33:51 +00:00
package application
import (
2018-06-08 21:54:31 +00:00
"git.openprivacy.ca/openprivacy/libricochet-go"
"git.openprivacy.ca/openprivacy/libricochet-go/channels"
"git.openprivacy.ca/openprivacy/libricochet-go/connection"
"git.openprivacy.ca/openprivacy/libricochet-go/connectivity"
2018-06-08 21:54:31 +00:00
"git.openprivacy.ca/openprivacy/libricochet-go/identity"
"log"
"net"
"sync"
2017-05-02 23:33:51 +00:00
)
const (
// RicochetPort is the default port used by ricochet applications
RicochetPort = 9878
)
2017-05-02 23:33:51 +00:00
// RicochetApplication bundles many useful constructs that are
// likely standard in a ricochet application
type RicochetApplication struct {
contactManager ContactManagerInterface
2018-09-22 20:12:08 +00:00
v3identity identity.Identity
name string
ls connectivity.ListenService
2018-11-21 23:07:57 +00:00
mn connectivity.ACN
instances []*ApplicationInstance
lock sync.Mutex
aif ApplicationInstanceFactory
2017-05-02 23:33:51 +00:00
}
// Init initializes the underlying RicochetApplication datastructure, making it ready for use
2018-11-21 23:07:57 +00:00
func (ra *RicochetApplication) Init(mn connectivity.ACN, name string, v3identity identity.Identity, af ApplicationInstanceFactory, cm ContactManagerInterface) {
ra.mn = mn
2018-09-22 20:12:08 +00:00
ra.name = name
ra.v3identity = v3identity
ra.aif = af
ra.contactManager = cm
}
2018-01-10 01:31:54 +00:00
// TODO: Reimplement OnJoin, OnLeave Events.
func (ra *RicochetApplication) handleConnection(conn net.Conn) {
rc, err := goricochet.NegotiateVersionInbound(conn)
if err != nil {
log.Printf("There was an error")
conn.Close()
return
}
ich := connection.HandleInboundConnection(rc)
err = ich.ProcessAuthAsV3Server(ra.v3identity, ra.contactManager.LookupContactV3)
2018-09-22 20:12:08 +00:00
if err != nil {
2018-09-22 20:12:08 +00:00
log.Printf("There was an error authenticating the connection: %v", err)
conn.Close()
return
}
2018-09-22 20:12:08 +00:00
rc.TraceLog(true)
rai := ra.aif.GetApplicationInstance(rc)
ra.lock.Lock()
ra.instances = append(ra.instances, rai)
ra.lock.Unlock()
rc.Process(rai)
// rc.Process ends when the connection ends.
// Remove it from the application's list of instances
ra.lock.Lock()
for i, x := range ra.instances {
if x == rai {
ra.instances = append(ra.instances[:i], ra.instances[i+1:]...)
break
}
}
ra.lock.Unlock()
}
func (ra *RicochetApplication) HandleApplicationInstance(rai *ApplicationInstance) {
ra.lock.Lock()
ra.instances = append(ra.instances, rai)
ra.lock.Unlock()
}
// Open a connection to another Ricochet peer at onionAddress. If they are unknown to use, use requestMessage (otherwise can be blank)
func (ra *RicochetApplication) Open(onionAddress string, requestMessage string) (*ApplicationInstance, error) {
rc, err := goricochet.Open(ra.mn, onionAddress)
rc.TraceLog(true)
if err != nil {
log.Printf("Error in application.Open(): %v\n", err)
return nil, err
}
2018-09-22 20:12:08 +00:00
och := connection.HandleOutboundConnection(rc)
known, err := och.ProcessAuthAsV3Client(ra.v3identity)
2018-09-22 20:12:08 +00:00
if err != nil {
log.Printf("There was an error authenticating the connection: %v", err)
return nil, err
}
rai := ra.aif.GetApplicationInstance(rc)
go rc.Process(rai)
if !known {
err := rc.Do(func() error {
_, err := rc.RequestOpenChannel("im.ricochet.contact.request",
&channels.ContactRequestChannel{
Handler: new(AcceptAllContactHandler),
Name: ra.name,
Message: requestMessage,
})
return err
})
if err != nil {
log.Printf("could not contact %s", err)
}
}
ra.HandleApplicationInstance(rai)
return rai, nil
}
func (ra *RicochetApplication) Broadcast(do func(rai *ApplicationInstance)) {
ra.lock.Lock()
for _, rai := range ra.instances {
do(rai)
}
ra.lock.Unlock()
}
// Shutdown stops a RicochetApplication, terminating all child processes and resources
func (ra *RicochetApplication) Shutdown() {
ra.lock.Lock()
ra.ls.Close()
for _, instance := range ra.instances {
instance.Connection.Conn.Close()
}
ra.lock.Unlock()
}
func (ra *RicochetApplication) ConnectionCount() int {
return len(ra.instances)
2017-07-04 18:39:19 +00:00
}
// Run handles a Listen object and Accepts and handles new connections
func (ra *RicochetApplication) Run(ls connectivity.ListenService) {
if !ra.v3identity.Initialized() || ra.contactManager == nil {
return
}
ra.ls = ls
var err error
2017-07-04 18:39:19 +00:00
for err == nil {
conn, err := ra.ls.Accept()
if err == nil {
go ra.handleConnection(conn)
2017-07-04 18:39:19 +00:00
} else {
return
}
}
}