This repository has been archived on 2020-04-20. You can view files and clone it, but cannot push or open issues or pull requests.
libricochet-go/application/examples/echobot/main.go

202 lines
5.3 KiB
Go
Raw Normal View History

package main
import (
2018-06-08 21:54:31 +00:00
"git.openprivacy.ca/openprivacy/libricochet-go/application"
"git.openprivacy.ca/openprivacy/libricochet-go/channels"
"golang.org/x/crypto/ed25519"
"log"
"time"
"crypto/rand"
"git.openprivacy.ca/openprivacy/libricochet-go/utils"
"git.openprivacy.ca/openprivacy/libricochet-go/identity"
"git.openprivacy.ca/openprivacy/libricochet-go"
"git.openprivacy.ca/openprivacy/libricochet-go/connection"
)
type EchoBotInstance struct {
rai *application.ApplicationInstance
ra *application.RicochetApplication
}
func (ebi *EchoBotInstance) Init(rai *application.ApplicationInstance, ra *application.RicochetApplication) {
ebi.rai = rai
ebi.ra = ra
}
// We always want bidirectional chat channels
func (ebi *EchoBotInstance) OpenInbound() {
log.Println("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
})
}
}
func (ebi *EchoBotInstance) ChatMessage(messageID uint32, when time.Time, message string) bool {
log.Printf("message from %v - %v", ebi.rai.RemoteHostname, message)
ebi.SendChatMessage(ebi.rai, ebi.rai.RemoteHostname+" "+message)
return true
}
func (ebi *EchoBotInstance) ChatMessageAck(messageID uint32, accepted bool) {
}
func (ebi *EchoBotInstance) SendChatMessage(rai *application.ApplicationInstance, message string) {
ebi.rai.Connection.Do(func() error {
channel := ebi.rai.Connection.Channel("im.ricochet.chat", channels.Outbound)
if channel != nil {
chatchannel, ok := channel.Handler.(*channels.ChatChannel)
if ok {
chatchannel.SendMessage(message)
}
} //TODO: else?
return nil
})
}
func main() {
////////////
// SERVER //
////////////
echobot := new(application.RicochetApplication)
cpubk, cprivk, err := ed25519.GenerateKey(rand.Reader)
if err != nil {
log.Fatalf("error generating random key: %v", err)
}
l, err := application.SetupOnionV3("127.0.0.1:9051", "tcp4", "", cprivk, utils.GetTorV3Hostname(cpubk), 9878)
if err != nil {
log.Fatalf("error setting up onion service: %v", err)
}
af := application.ApplicationInstanceFactory{}
af.Init()
af.AddHandler("im.ricochet.chat", func(rai *application.ApplicationInstance) func() channels.Handler {
ebi := new(EchoBotInstance)
ebi.Init(rai, echobot)
return func() channels.Handler {
chat := new(channels.ChatChannel)
chat.Handler = ebi
return chat
}
})
echobot.InitV3("echobot", identity.InitializeV3("echobot", &cprivk, &cpubk), af, new(application.AcceptAllContactManager))
log.Printf("echobot listening on %s", l.Addr().String())
go echobot.Run(l)
log.Printf("counting to five...")
time.Sleep(time.Second * 5)
////////////
// CLIENT //
////////////
//alicebot should nominally be in another package to prevent initializing it directly
alice := NewAliceBot(l.Addr().String()[:56])
alice.SendMessage("be gay")
alice.SendMessage("do crime")
// stick around and see what happens
time.Sleep(time.Second * 30)
}
func NewAliceBot(onion string) alicebot {
alice := alicebot{}
alice.messages = make(map[uint32]string)
var err error
alice.pub, alice.priv, err = ed25519.GenerateKey(rand.Reader)
if err != nil {
log.Fatalf("[alice] error generating key: %v", err)
}
rc, err := goricochet.Open(onion)
if err != nil {
log.Fatalf("[alice] error connecting to echobot: %v", err)
}
rc.TraceLog(false)
_, err = connection.HandleOutboundConnection(rc).ProcessAuthAsV3Client(identity.InitializeV3("alice", &alice.priv, &alice.pub))
if err != nil {
log.Fatalf("[alice] failed to authenticate connection: %v", err)
}
alice.rc = rc
ach := connection.AutoConnectionHandler{}
ach.Init()
ach.RegisterChannelHandler("im.ricochet.chat", func() channels.Handler {
chat := new(channels.ChatChannel)
chat.Handler = &alice
return chat
})
go alice.rc.Process(&ach)
log.Printf("[alice] requesting channel...")
alice.rc.Do(func() error {
chatchannel := channels.ChatChannel{}
chatchannel.Handler = &alice
_, err := alice.rc.RequestOpenChannel("im.ricochet.chat", &chatchannel)
if err != nil {
log.Fatalf("failed requestopenchannel: %v", err)
}
return nil
})
return alice
}
type alicebot struct {
messages map[uint32]string
pub ed25519.PublicKey
priv ed25519.PrivateKey
mID int
rc *connection.Connection
}
func (this *alicebot) SendMessage(message string) {
log.Printf("[alice] sending...")
this.rc.Do(func() error {
channel := this.rc.Channel("im.ricochet.chat", channels.Outbound)
if channel != nil {
peerchannel, ok := channel.Handler.(*channels.ChatChannel)
if ok {
log.Printf("[alice] sending '%s' to echobot", message)
this.messages[peerchannel.SendMessage(message)] = message
} else {
log.Fatalf("couldn't cast channel:")
}
} else {
log.Fatalf("couldn't create channel")
}
return nil
})
}
func (this *alicebot) OpenInbound() {
log.Printf("[alice] inbound connection established")
}
func (this *alicebot) ChatMessage(messageID uint32, when time.Time, message string) bool {
log.Printf("[alice] got message from echobot: %s", message)
return true
}
func (this *alicebot) ChatMessageAck(messageID uint32, accepted bool) {
log.Printf("[alice] message \"%s\" ack'd", this.messages[messageID])
}