2017-05-02 23:33:51 +00:00
|
|
|
package application
|
|
|
|
|
|
|
|
import (
|
2017-07-04 18:29:11 +00:00
|
|
|
"crypto/rsa"
|
|
|
|
"github.com/s-rah/go-ricochet"
|
2017-05-02 23:33:51 +00:00
|
|
|
"github.com/s-rah/go-ricochet/channels"
|
|
|
|
"github.com/s-rah/go-ricochet/connection"
|
2017-07-04 18:29:11 +00:00
|
|
|
"log"
|
|
|
|
"net"
|
|
|
|
"time"
|
2017-05-02 23:33:51 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// RicochetApplication bundles many useful constructs that are
|
|
|
|
// likely standard in a ricochet application
|
|
|
|
type RicochetApplication struct {
|
2017-07-04 18:29:11 +00:00
|
|
|
contactManager ContactManagerInterface
|
|
|
|
privateKey *rsa.PrivateKey
|
|
|
|
chatMessageHandler func(*RicochetApplicationInstance, uint32, time.Time, string)
|
|
|
|
chatMessageAckHandler func(*RicochetApplicationInstance, uint32)
|
2017-07-04 18:39:19 +00:00
|
|
|
l net.Listener
|
2017-05-02 23:33:51 +00:00
|
|
|
}
|
|
|
|
|
2017-07-04 18:29:11 +00:00
|
|
|
type RicochetApplicationInstance struct {
|
|
|
|
connection.AutoConnectionHandler
|
|
|
|
connection *connection.Connection
|
|
|
|
RemoteHostname string
|
|
|
|
ChatMessageHandler func(*RicochetApplicationInstance, uint32, time.Time, string)
|
|
|
|
ChatMessageAckHandler func(*RicochetApplicationInstance, uint32)
|
2017-05-02 23:33:51 +00:00
|
|
|
}
|
|
|
|
|
2017-07-04 18:29:11 +00:00
|
|
|
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)
|
2017-05-02 23:33:51 +00:00
|
|
|
if channel != nil {
|
|
|
|
chatchannel, ok := (*channel.Handler).(*channels.ChatChannel)
|
|
|
|
if ok {
|
|
|
|
chatchannel.SendMessage(message)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
}
|
2017-07-04 18:29:11 +00:00
|
|
|
|
|
|
|
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)
|
|
|
|
}
|
|
|
|
|
2017-07-04 18:39:19 +00:00
|
|
|
func (ra *RicochetApplication) Shutdown () {
|
|
|
|
log.Printf("Closing")
|
|
|
|
ra.l.Close()
|
|
|
|
log.Printf("Closed")
|
|
|
|
}
|
|
|
|
|
2017-07-04 18:29:11 +00:00
|
|
|
func (ra *RicochetApplication) Run(l net.Listener) {
|
|
|
|
if ra.privateKey == nil || ra.contactManager == nil {
|
|
|
|
return
|
|
|
|
}
|
2017-07-04 18:39:19 +00:00
|
|
|
ra.l = l
|
|
|
|
var err error
|
|
|
|
for err == nil {
|
|
|
|
conn, err := ra.l.Accept()
|
2017-07-04 18:29:11 +00:00
|
|
|
if err == nil {
|
|
|
|
go ra.handleConnection(conn)
|
2017-07-04 18:39:19 +00:00
|
|
|
} else {
|
|
|
|
log.Printf("Closing")
|
|
|
|
return
|
2017-07-04 18:29:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|