Refactoring Application to remove channel handler duplications
Also simplfies application a lot, still not complete, but i like this approach much more
This commit is contained in:
parent
be62634c46
commit
1a2fb40d91
|
@ -3,98 +3,28 @@ 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"
|
||||
"github.com/s-rah/go-ricochet/identity"
|
||||
"log"
|
||||
"net"
|
||||
"sync"
|
||||
"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)
|
||||
onConnected func(*RicochetApplicationInstance)
|
||||
onLeave func(*RicochetApplicationInstance)
|
||||
l net.Listener
|
||||
instances []*RicochetApplicationInstance
|
||||
lock sync.Mutex
|
||||
contactManager ContactManagerInterface
|
||||
privateKey *rsa.PrivateKey
|
||||
l net.Listener
|
||||
instances []*ApplicationInstance
|
||||
lock sync.Mutex
|
||||
aif ApplicationInstanceFactory
|
||||
}
|
||||
|
||||
type RicochetApplicationInstance struct {
|
||||
connection.AutoConnectionHandler
|
||||
connection *connection.Connection
|
||||
RemoteHostname string
|
||||
ChatMessageHandler func(*RicochetApplicationInstance, uint32, time.Time, string)
|
||||
ChatMessageAckHandler func(*RicochetApplicationInstance, uint32)
|
||||
OnLeave func(*RicochetApplicationInstance)
|
||||
}
|
||||
|
||||
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) {
|
||||
rai.connection.Do(func() error {
|
||||
// Technically this errors afte the second time but we can ignore it.
|
||||
rai.connection.RequestOpenChannel("im.ricochet.chat",
|
||||
&channels.ChatChannel{
|
||||
Handler: rai,
|
||||
})
|
||||
|
||||
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, accepted bool) {
|
||||
rai.ChatMessageAckHandler(rai, messageID)
|
||||
}
|
||||
|
||||
func (ra *RicochetApplication) Init(pk *rsa.PrivateKey, cm ContactManagerInterface) {
|
||||
func (ra *RicochetApplication) Init(pk *rsa.PrivateKey, af ApplicationInstanceFactory, cm ContactManagerInterface) {
|
||||
ra.privateKey = pk
|
||||
ra.aif = af
|
||||
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) OnConnected(call func(*RicochetApplicationInstance)) {
|
||||
ra.onConnected = call
|
||||
}
|
||||
|
||||
func (ra *RicochetApplication) OnLeave(call func(*RicochetApplicationInstance)) {
|
||||
ra.onLeave = call
|
||||
}
|
||||
|
||||
func (ra *RicochetApplication) handleConnection(conn net.Conn) {
|
||||
|
@ -114,39 +44,17 @@ func (ra *RicochetApplication) handleConnection(conn net.Conn) {
|
|||
return
|
||||
}
|
||||
rc.TraceLog(true)
|
||||
rai := new(RicochetApplicationInstance)
|
||||
rai.Init()
|
||||
rai.RemoteHostname = rc.RemoteHostname
|
||||
rai.connection = rc
|
||||
rai.ChatMessageHandler = ra.chatMessageHandler
|
||||
rai.ChatMessageAckHandler = ra.chatMessageAckHandler
|
||||
rai.OnLeave = ra.onLeave
|
||||
|
||||
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
|
||||
})
|
||||
rai := ra.aif.GetApplicationInstance(rc)
|
||||
ra.lock.Lock()
|
||||
ra.instances = append(ra.instances, rai)
|
||||
ra.lock.Unlock()
|
||||
go ra.onConnected(rai)
|
||||
rc.Process(rai)
|
||||
}
|
||||
|
||||
func (rai *RicochetApplicationInstance) OnClosed(err error) {
|
||||
rai.OnLeave(rai)
|
||||
}
|
||||
|
||||
func (ra *RicochetApplication) Broadcast(message string) {
|
||||
func (ra *RicochetApplication) Broadcast(do func(rai *ApplicationInstance)) {
|
||||
ra.lock.Lock()
|
||||
for _, rai := range ra.instances {
|
||||
rai.SendChatMessage(message)
|
||||
do(rai)
|
||||
}
|
||||
ra.lock.Unlock()
|
||||
}
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
package application
|
||||
|
||||
import (
|
||||
"github.com/s-rah/go-ricochet/channels"
|
||||
"github.com/s-rah/go-ricochet/connection"
|
||||
)
|
||||
|
||||
// A concrete instance of a ricochet application, encapsulating a connection
|
||||
type ApplicationInstance struct {
|
||||
connection.AutoConnectionHandler
|
||||
Connection *connection.Connection
|
||||
RemoteHostname string
|
||||
}
|
||||
|
||||
// Application instance factory
|
||||
type ApplicationInstanceFactory struct {
|
||||
handlerMap map[string]func(*ApplicationInstance) func() channels.Handler
|
||||
}
|
||||
|
||||
// Init setsup an Application Factory
|
||||
func (af *ApplicationInstanceFactory) Init() {
|
||||
af.handlerMap = make(map[string]func(*ApplicationInstance) func() channels.Handler)
|
||||
}
|
||||
|
||||
// AddHandler
|
||||
func (af *ApplicationInstanceFactory) AddHandler(ctype string, chandler func(*ApplicationInstance) func() channels.Handler) {
|
||||
af.handlerMap[ctype] = chandler
|
||||
}
|
||||
|
||||
// GetApplicationInstance,
|
||||
func (af *ApplicationInstanceFactory) GetApplicationInstance(rc *connection.Connection) *ApplicationInstance {
|
||||
rai := new(ApplicationInstance)
|
||||
rai.Init()
|
||||
rai.RemoteHostname = rc.RemoteHostname
|
||||
rai.Connection = rc
|
||||
for t, h := range af.handlerMap {
|
||||
rai.RegisterChannelHandler(t, h(rai))
|
||||
}
|
||||
return rai
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"github.com/s-rah/go-ricochet/application"
|
||||
"github.com/s-rah/go-ricochet/utils"
|
||||
"log"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
commandbot := new(application.RicochetApplication)
|
||||
pk, err := utils.LoadPrivateKeyFromFile("./testing/private_key")
|
||||
|
||||
if err != nil {
|
||||
log.Fatalf("error reading private key file: %v", err)
|
||||
}
|
||||
|
||||
l, err := application.SetupOnion("127.0.0.1:9051", "", pk, 9878)
|
||||
|
||||
if err != nil {
|
||||
log.Fatalf("error setting up onion service: %v", err)
|
||||
}
|
||||
|
||||
commandbot.Init(pk, new(application.AcceptAllContactManager))
|
||||
commandbot.OnChatMessage(func(rai *application.RicochetApplicationInstance, id uint32, timestamp time.Time, message string) {
|
||||
log.Printf("message from %v - %v", rai.RemoteHostname, message)
|
||||
go echobot.Broadcast(rai.RemoteHostname + " " + message)
|
||||
})
|
||||
log.Printf("commandbot listening on %s", l.Addr().String())
|
||||
commandbot.Run(l)
|
||||
}
|
|
@ -2,11 +2,53 @@ package main
|
|||
|
||||
import (
|
||||
"github.com/s-rah/go-ricochet/application"
|
||||
"github.com/s-rah/go-ricochet/channels"
|
||||
"github.com/s-rah/go-ricochet/utils"
|
||||
"log"
|
||||
"time"
|
||||
)
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
func (ebi *EchoBotInstance) ChatMessage(messageID uint32, when time.Time, message string) bool {
|
||||
log.Printf("message from %v - %v", ebi.rai.RemoteHostname, message)
|
||||
go ebi.ra.Broadcast(func(rai *application.ApplicationInstance) {
|
||||
ebi.SendChatMessage(rai, ebi.rai.RemoteHostname+" "+message)
|
||||
})
|
||||
return true
|
||||
}
|
||||
|
||||
func (ebi *EchoBotInstance) ChatMessageAck(messageID uint32, accepted bool) {
|
||||
|
||||
}
|
||||
|
||||
func (ebi *EchoBotInstance) SendChatMessage(rai *application.ApplicationInstance, message string) {
|
||||
rai.Connection.Do(func() error {
|
||||
// Technically this errors after the second time but we can ignore it.
|
||||
rai.Connection.RequestOpenChannel("im.ricochet.chat",
|
||||
&channels.ChatChannel{
|
||||
Handler: ebi,
|
||||
})
|
||||
|
||||
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 main() {
|
||||
echobot := new(application.RicochetApplication)
|
||||
pk, err := utils.LoadPrivateKeyFromFile("./testing/private_key")
|
||||
|
@ -21,11 +63,19 @@ func main() {
|
|||
log.Fatalf("error setting up onion service: %v", err)
|
||||
}
|
||||
|
||||
echobot.Init(pk, new(application.AcceptAllContactManager))
|
||||
echobot.OnChatMessage(func(rai *application.RicochetApplicationInstance, id uint32, timestamp time.Time, message string) {
|
||||
log.Printf("message from %v - %v", rai.RemoteHostname, message)
|
||||
go echobot.Broadcast(rai.RemoteHostname + " " + message)
|
||||
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.Init(pk, af, new(application.AcceptAllContactManager))
|
||||
log.Printf("echobot listening on %s", l.Addr().String())
|
||||
echobot.Run(l)
|
||||
}
|
||||
|
|
|
@ -7,11 +7,11 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
// InvalidPacketLengthError is returned whenever ricochet receives a packet too small or too large to conform to the spec.
|
||||
// InvalidPacketLengthError is returned whenever ricochet receives a packet too small or too large to conform to the spec.
|
||||
InvalidPacketLengthError = Error("InvalidPacketLengthError")
|
||||
|
||||
|
||||
// InvalidChannelIDError channels must be between 0 and 65535
|
||||
InvalidChannelIDError = Error("InvalidChannelIDError")
|
||||
InvalidChannelIDError = Error("InvalidChannelIDError")
|
||||
)
|
||||
|
||||
// RicochetData is a structure containing the raw data and the channel it the
|
||||
|
|
Reference in New Issue