go-ricochet/application/application.go

135 lines
3.8 KiB
Go

package application
import (
"crypto/rsa"
"github.com/s-rah/go-ricochet"
"github.com/s-rah/go-ricochet/channels"
"github.com/s-rah/go-ricochet/connection"
"log"
"net"
"time"
)
// RicochetApplication bundles many useful constructs that are
// likely standard in a ricochet application
type RicochetApplication struct {
contactManager ContactManagerInterface
privateKey *rsa.PrivateKey
chatMessageHandler func(*RicochetApplicationInstance, uint32, time.Time, string)
chatMessageAckHandler func(*RicochetApplicationInstance, uint32)
}
type RicochetApplicationInstance struct {
connection.AutoConnectionHandler
connection *connection.Connection
RemoteHostname string
ChatMessageHandler func(*RicochetApplicationInstance, uint32, time.Time, string)
ChatMessageAckHandler func(*RicochetApplicationInstance, uint32)
}
func (rai *RicochetApplicationInstance) GetContactDetails() (string, string) {
return "EchoBot", "I LIVE 😈😈!!!!"
}
func (rai *RicochetApplicationInstance) ContactRequest(name string, message string) string {
return "Accepted"
}
func (rai *RicochetApplicationInstance) ContactRequestRejected() {
}
func (rai *RicochetApplicationInstance) ContactRequestAccepted() {
}
func (rai *RicochetApplicationInstance) ContactRequestError() {
}
func (rai *RicochetApplicationInstance) SendChatMessage(message string) {
// Technically this errors afte the second time but we can ignore it.
rai.connection.RequestOpenChannel("im.ricochet.chat", rai)
rai.connection.Do(func() error {
channel := rai.connection.Channel("im.ricochet.chat", channels.Outbound)
if channel != nil {
chatchannel, ok := (*channel.Handler).(*channels.ChatChannel)
if ok {
chatchannel.SendMessage(message)
}
}
return nil
})
}
func (rai *RicochetApplicationInstance) ChatMessage(messageID uint32, when time.Time, message string) bool {
go rai.ChatMessageHandler(rai, messageID, when, message)
return true
}
func (rai *RicochetApplicationInstance) ChatMessageAck(messageID uint32) {
rai.ChatMessageAckHandler(rai, messageID)
}
func (ra *RicochetApplication) Init(pk *rsa.PrivateKey, cm ContactManagerInterface) {
ra.privateKey = pk
ra.contactManager = cm
ra.chatMessageHandler = func(*RicochetApplicationInstance, uint32, time.Time, string) {}
ra.chatMessageAckHandler = func(*RicochetApplicationInstance, uint32) {}
}
func (ra *RicochetApplication) OnChatMessage(call func(*RicochetApplicationInstance, uint32, time.Time, string)) {
ra.chatMessageHandler = call
}
func (ra *RicochetApplication) OnChatMessageAck(call func(*RicochetApplicationInstance, uint32)) {
ra.chatMessageAckHandler = call
}
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.ProcessAuthAsServer(ra.privateKey, ra.contactManager.LookupContact)
if err != nil {
log.Printf("There was an error")
conn.Close()
return
}
rai := new(RicochetApplicationInstance)
rai.Init(ra.privateKey, "")
rai.RemoteHostname = rc.RemoteHostname
rai.connection = rc
rai.ChatMessageHandler = ra.chatMessageHandler
rai.ChatMessageAckHandler = ra.chatMessageAckHandler
rai.RegisterChannelHandler("im.ricochet.contact.request", func() channels.Handler {
contact := new(channels.ContactRequestChannel)
contact.Handler = rai
return contact
})
rai.RegisterChannelHandler("im.ricochet.chat", func() channels.Handler {
chat := new(channels.ChatChannel)
chat.Handler = rai
return chat
})
rc.Process(rai)
}
func (ra *RicochetApplication) Run(l net.Listener) {
if ra.privateKey == nil || ra.contactManager == nil {
return
}
for {
conn, err := l.Accept()
if err == nil {
go ra.handleConnection(conn)
}
}
}