133 lines
4.6 KiB
Go
133 lines
4.6 KiB
Go
package main
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"git.openprivacy.ca/openprivacy/libricochet-go/application"
|
|
"git.openprivacy.ca/openprivacy/libricochet-go/application/examples/echobot/alicebot"
|
|
"git.openprivacy.ca/openprivacy/libricochet-go/channels"
|
|
"git.openprivacy.ca/openprivacy/libricochet-go/identity"
|
|
"git.openprivacy.ca/openprivacy/libricochet-go/log"
|
|
"time"
|
|
|
|
"git.openprivacy.ca/openprivacy/libricochet-go/connectivity"
|
|
"golang.org/x/crypto/ed25519"
|
|
"os"
|
|
)
|
|
|
|
// EchoBotInstance is an Instance of the EchoBot Application. One is created for every connected peer.
|
|
type EchoBotInstance struct {
|
|
rai *application.Instance
|
|
ra *application.RicochetApplication
|
|
}
|
|
|
|
// Init establishes an EchoBotInstance
|
|
func (ebi *EchoBotInstance) Init(rai *application.Instance, ra *application.RicochetApplication) {
|
|
ebi.rai = rai
|
|
ebi.ra = ra
|
|
}
|
|
|
|
// OpenInbound is called when AliceBot opens a ChatChannel. In this case, because we want EchoBot to respond we
|
|
// need to open a new channel in the other direction.
|
|
func (ebi *EchoBotInstance) OpenInbound() {
|
|
log.Debugln("OpenInbound() ChatChannel handler called...")
|
|
outboutChatChannel := ebi.rai.Connection.Channel("im.ricochet.chat", channels.Outbound)
|
|
if outboutChatChannel == nil {
|
|
ebi.rai.Connection.Do(func() error {
|
|
ebi.rai.Connection.RequestOpenChannel("im.ricochet.chat",
|
|
&channels.ChatChannel{
|
|
Handler: ebi,
|
|
})
|
|
return nil
|
|
})
|
|
}
|
|
}
|
|
|
|
// ChatMessage is called whenever a connected peer sends a message to EchoBot
|
|
func (ebi *EchoBotInstance) ChatMessage(messageID uint32, when time.Time, message string) bool {
|
|
log.Infof("message from %v - %v", ebi.rai.RemoteHostname, message)
|
|
ebi.SendChatMessage(ebi.rai, ebi.rai.RemoteHostname+" "+message)
|
|
return true
|
|
}
|
|
|
|
// ChatMessageAck is called whenever a connected peer acknowledges a message that EchoBot sent.
|
|
func (ebi *EchoBotInstance) ChatMessageAck(messageID uint32, accepted bool) {
|
|
|
|
}
|
|
|
|
// SendChatMessage sends a chat message to the given echobot instance
|
|
func (ebi *EchoBotInstance) SendChatMessage(rai *application.Instance, message string) {
|
|
ebi.rai.Connection.Do(func() error {
|
|
channel := ebi.rai.Connection.Channel("im.ricochet.chat", channels.Outbound)
|
|
// We are swallowing the message id and the error here, in reality you will want to handle it.
|
|
channels.SendMessageOnChatChannel(channel, message)
|
|
return nil
|
|
})
|
|
}
|
|
|
|
// main() encapsulates an entire ricochet ecosystem, from starting tor, to generating onion service keys to managing
|
|
// the launching of both the echobot server and the alicebot peer.
|
|
// In most systems you will only be handling one or two of these subsystems at any given time so this example might seem
|
|
// bloated, but we have tried to highlight the most interesting aspects to allow easy application to new domains.
|
|
func main() {
|
|
|
|
// Set up Logging.
|
|
log.SetLevel(log.LevelInfo)
|
|
log.AddEverythingFromPattern("connectivity")
|
|
|
|
// Set up Tor
|
|
acn, err := connectivity.StartTor(".", "")
|
|
if err != nil {
|
|
log.Errorf("Unable to start Tor: %v", err)
|
|
os.Exit(1)
|
|
}
|
|
defer acn.Close()
|
|
|
|
// Set up the Echobot Server
|
|
echobot := new(application.RicochetApplication)
|
|
cpubk, cprivk, err := ed25519.GenerateKey(rand.Reader)
|
|
|
|
if err != nil {
|
|
log.Errorf("Error generating keys: %v", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
// Turn on the echobot onion service in Tor.
|
|
listenService, err := acn.Listen(cprivk, application.RicochetPort)
|
|
if err != nil {
|
|
log.Errorf("error setting up onion service: %v", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
// This next section looks complicated (and it is a little), but all it is doing is allowing echobot to handle
|
|
// im.ricochet.chat type channels.
|
|
af := application.InstanceFactory{}
|
|
af.Init()
|
|
af.AddHandler("im.ricochet.chat", func(rai *application.Instance) func() channels.Handler {
|
|
ebi := new(EchoBotInstance)
|
|
ebi.Init(rai, echobot)
|
|
return func() channels.Handler {
|
|
chat := new(channels.ChatChannel)
|
|
chat.Handler = ebi
|
|
return chat
|
|
}
|
|
})
|
|
|
|
// Thee next few lines turn on echobot and make it available to listen to new connections.
|
|
// Note that we initialize a V3 identity for echobot.
|
|
echobot.Init(acn, "echobot", identity.InitializeV3("echobot", &cprivk, &cpubk), af, new(application.AcceptAllContactManager))
|
|
log.Infof("echobot listening on %v", listenService.AddressFull())
|
|
go echobot.Run(listenService)
|
|
|
|
// Now we wait a little bit for everything to wire itself together.
|
|
log.Infoln("counting to five ...")
|
|
time.Sleep(time.Second * 5)
|
|
|
|
// Finally, in these last few lines we setup an AliceBot who simply sends messages to echobot
|
|
alice := alicebot.NewAliceBot(acn, listenService.AddressIdentity())
|
|
alice.SendMessage("be gay")
|
|
alice.SendMessage("do crime")
|
|
|
|
// stick around and see what happens
|
|
time.Sleep(time.Second * 30)
|
|
}
|