113 lines
3.2 KiB
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])
|
|
}
|