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/alicebot/alicebot.go

113 lines
3.2 KiB
Go

package alicebot
import (
"crypto/rand"
"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"
"git.openprivacy.ca/openprivacy/libricochet-go/identity"
"git.openprivacy.ca/openprivacy/libricochet-go/log"
"golang.org/x/crypto/ed25519"
"os"
"time"
)
// NewAliceBot creates a new AliceBot and establishes a connection to the given onion server.
func NewAliceBot(acn connectivity.ACN, onion string) AliceBot {
alice := new(alicebot)
alice.messages = make(map[uint32]string)
var err error
alice.pub, alice.priv, err = ed25519.GenerateKey(rand.Reader)
if err != nil {
log.Errorf("[alice] error generating key: %v", err)
os.Exit(1)
}
rc, err := goricochet.Open(acn, onion)
if err != nil {
log.Errorf("[alice] error connecting to echobot: %v", err)
os.Exit(1)
}
_, err = connection.HandleOutboundConnection(rc).ProcessAuthAsV3Client(identity.InitializeV3("alice", &alice.priv, &alice.pub))
if err != nil {
log.Errorf("[alice] failed to authenticate connection: %v", err)
os.Exit(1)
}
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.Infof("[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.Errorf("failed requestopenchannel: %v", err)
os.Exit(1)
}
return nil
})
return alice
}
type alicebot struct {
messages map[uint32]string
pub ed25519.PublicKey
priv ed25519.PrivateKey
mID int
rc *connection.Connection
}
// AliceBot is an interface for alicebot, allowing callers to send and receive messages.
type AliceBot interface {
channels.ChatChannelHandler
SendMessage(string)
}
// SendMessage can be called to send a message to EchoBot
func (ab *alicebot) SendMessage(message string) {
// The following code opens (or creates) a new im.ricochet.chat channel to the connected service
// and sends a message.
log.Infof("[alice] sending...")
ab.rc.Do(func() error {
channel := ab.rc.Channel("im.ricochet.chat", channels.Outbound)
id, err := channels.SendMessageOnChatChannel(channel, message)
if err == nil {
ab.messages[id] = message
}
return err
})
}
// OpenInbound is called when EchoBot attempts to open a channel with AliceBot
func (ab *alicebot) OpenInbound() {
log.Infof("[alice] inbound connection established")
}
// ChatMessage is called whenever AliceBot receives a message from EchoBot
func (ab *alicebot) ChatMessage(messageID uint32, when time.Time, message string) bool {
log.Infof("[alice] got message from echobot: %s", message)
return true
}
// ChatMessageAck is called whenever AliceBot received an acknowledgement of a previously sent message.
func (ab *alicebot) ChatMessageAck(messageID uint32, accepted bool) {
log.Infof("[alice] message \"%s\" ack'd", ab.messages[messageID])
}