2016-01-02 02:08:28 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"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"
|
|
|
|
"github.com/s-rah/go-ricochet/utils"
|
2016-06-27 01:56:23 +00:00
|
|
|
"log"
|
2017-05-02 23:33:51 +00:00
|
|
|
"time"
|
2016-01-02 02:08:28 +00:00
|
|
|
)
|
|
|
|
|
2016-11-08 23:12:50 +00:00
|
|
|
// EchoBotService is an example service which simply echoes back what a client
|
|
|
|
// sends it.
|
2017-05-02 23:33:51 +00:00
|
|
|
type RicochetEchoBot struct {
|
|
|
|
connection.AutoConnectionHandler
|
|
|
|
messages chan string
|
2016-02-29 00:18:25 +00:00
|
|
|
}
|
2016-01-02 02:08:28 +00:00
|
|
|
|
2017-05-02 23:33:51 +00:00
|
|
|
func (echobot *RicochetEchoBot) ContactRequest(name string, message string) string {
|
|
|
|
return "Pending"
|
2016-10-09 00:51:13 +00:00
|
|
|
}
|
|
|
|
|
2017-05-02 23:33:51 +00:00
|
|
|
func (echobot *RicochetEchoBot) ContactRequestRejected() {
|
|
|
|
}
|
|
|
|
func (echobot *RicochetEchoBot) ContactRequestAccepted() {
|
|
|
|
}
|
|
|
|
func (echobot *RicochetEchoBot) ContactRequestError() {
|
|
|
|
}
|
|
|
|
|
|
|
|
func (echobot *RicochetEchoBot) ChatMessage(messageID uint32, when time.Time, message string) bool {
|
|
|
|
echobot.messages <- message
|
2016-06-27 01:56:23 +00:00
|
|
|
return true
|
2016-02-29 00:18:25 +00:00
|
|
|
}
|
2016-01-02 02:08:28 +00:00
|
|
|
|
2017-09-25 20:01:07 +00:00
|
|
|
func (echobot *RicochetEchoBot) ChatMessageAck(messageID uint32, accepted bool) {
|
2017-05-02 23:33:51 +00:00
|
|
|
|
2016-02-29 00:18:25 +00:00
|
|
|
}
|
2016-01-02 02:08:28 +00:00
|
|
|
|
2017-05-02 23:33:51 +00:00
|
|
|
func (echobot *RicochetEchoBot) Connect(privateKeyFile string, hostname string) {
|
|
|
|
|
|
|
|
privateKey, _ := utils.LoadPrivateKeyFromFile(privateKeyFile)
|
|
|
|
echobot.messages = make(chan string)
|
|
|
|
|
2017-09-16 13:46:28 +00:00
|
|
|
echobot.Init()
|
2017-05-02 23:33:51 +00:00
|
|
|
echobot.RegisterChannelHandler("im.ricochet.contact.request", func() channels.Handler {
|
|
|
|
contact := new(channels.ContactRequestChannel)
|
|
|
|
contact.Handler = echobot
|
|
|
|
return contact
|
|
|
|
})
|
|
|
|
echobot.RegisterChannelHandler("im.ricochet.chat", func() channels.Handler {
|
|
|
|
chat := new(channels.ChatChannel)
|
|
|
|
chat.Handler = echobot
|
|
|
|
return chat
|
|
|
|
})
|
|
|
|
|
|
|
|
rc, _ := goricochet.Open(hostname)
|
2017-07-04 18:29:11 +00:00
|
|
|
known, err := connection.HandleOutboundConnection(rc).ProcessAuthAsClient(privateKey)
|
2017-05-02 23:33:51 +00:00
|
|
|
if err == nil {
|
|
|
|
|
|
|
|
go rc.Process(echobot)
|
|
|
|
|
|
|
|
if !known {
|
Fix and document safety problems with Connection.Do
There were several issues with the Do function that made it nearly
impossible to write safe code.
First, Do cannot be called recursively -- it will deadlock. There is
actually no way to implement a safe and recursive Do (or mutex) in Go,
because there is no primitive that will identify the current goroutine.
RequestOpenChannel used Do internally, which made it impossible to open
channels safely in many circumstances. That has been removed, so all
calls to RequestOpenChannel must be changed to happen under Do now.
Do now has more documentation and a new rule: no code exposed through
API can use Do, unless it has sole custody of the connection (such as
ProcessAuthAsClient).
Related to that problem, Do was impossible to call from inside handlers
(or anything else on the process goroutine) -- it would again just
deadlock. This is resolved by wrapping calls into user code to continue
handling invocations of Do (and only those) while the handler is
executing.
There is a third issue with connection close, but it will be addressed
in a separate commit
And finally, because it's impossible to timeout or interrupt a call to
Do, I also added a DoContext method that takes a go Context, which is
also passed through to the called function.
2017-09-16 19:38:00 +00:00
|
|
|
err := rc.Do(func() error {
|
2017-09-20 19:43:05 +00:00
|
|
|
_,err := rc.RequestOpenChannel("im.ricochet.contact.request",
|
|
|
|
&channels.ContactRequestChannel{
|
|
|
|
Handler: echobot,
|
|
|
|
Name: "EchoBot",
|
|
|
|
Message: "I LIVE 😈😈!!!!",
|
|
|
|
})
|
Fix and document safety problems with Connection.Do
There were several issues with the Do function that made it nearly
impossible to write safe code.
First, Do cannot be called recursively -- it will deadlock. There is
actually no way to implement a safe and recursive Do (or mutex) in Go,
because there is no primitive that will identify the current goroutine.
RequestOpenChannel used Do internally, which made it impossible to open
channels safely in many circumstances. That has been removed, so all
calls to RequestOpenChannel must be changed to happen under Do now.
Do now has more documentation and a new rule: no code exposed through
API can use Do, unless it has sole custody of the connection (such as
ProcessAuthAsClient).
Related to that problem, Do was impossible to call from inside handlers
(or anything else on the process goroutine) -- it would again just
deadlock. This is resolved by wrapping calls into user code to continue
handling invocations of Do (and only those) while the handler is
executing.
There is a third issue with connection close, but it will be addressed
in a separate commit
And finally, because it's impossible to timeout or interrupt a call to
Do, I also added a DoContext method that takes a go Context, which is
also passed through to the called function.
2017-09-16 19:38:00 +00:00
|
|
|
return err
|
|
|
|
})
|
2017-05-02 23:33:51 +00:00
|
|
|
if err != nil {
|
|
|
|
log.Printf("could not contact %s", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Fix and document safety problems with Connection.Do
There were several issues with the Do function that made it nearly
impossible to write safe code.
First, Do cannot be called recursively -- it will deadlock. There is
actually no way to implement a safe and recursive Do (or mutex) in Go,
because there is no primitive that will identify the current goroutine.
RequestOpenChannel used Do internally, which made it impossible to open
channels safely in many circumstances. That has been removed, so all
calls to RequestOpenChannel must be changed to happen under Do now.
Do now has more documentation and a new rule: no code exposed through
API can use Do, unless it has sole custody of the connection (such as
ProcessAuthAsClient).
Related to that problem, Do was impossible to call from inside handlers
(or anything else on the process goroutine) -- it would again just
deadlock. This is resolved by wrapping calls into user code to continue
handling invocations of Do (and only those) while the handler is
executing.
There is a third issue with connection close, but it will be addressed
in a separate commit
And finally, because it's impossible to timeout or interrupt a call to
Do, I also added a DoContext method that takes a go Context, which is
also passed through to the called function.
2017-09-16 19:38:00 +00:00
|
|
|
rc.Do(func() error {
|
|
|
|
_, err := rc.RequestOpenChannel("im.ricochet.chat", &channels.ChatChannel{Handler: echobot})
|
|
|
|
return err
|
|
|
|
})
|
2017-05-02 23:33:51 +00:00
|
|
|
for {
|
|
|
|
message := <-echobot.messages
|
|
|
|
log.Printf("Received Message: %s", message)
|
|
|
|
rc.Do(func() error {
|
|
|
|
log.Printf("Finding Chat Channel")
|
|
|
|
channel := rc.Channel("im.ricochet.chat", channels.Outbound)
|
|
|
|
if channel != nil {
|
|
|
|
log.Printf("Found Chat Channel")
|
2017-09-23 22:29:46 +00:00
|
|
|
chatchannel, ok := channel.Handler.(*channels.ChatChannel)
|
2017-05-02 23:33:51 +00:00
|
|
|
if ok {
|
|
|
|
chatchannel.SendMessage(message)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
log.Printf("Could not find chat channel")
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
}
|
2016-01-02 02:08:28 +00:00
|
|
|
}
|
2016-06-27 01:56:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func main() {
|
2017-05-02 23:33:51 +00:00
|
|
|
echoBot := new(RicochetEchoBot)
|
|
|
|
echoBot.Connect("private_key", "oqf7z4ot6kuejgam")
|
2016-01-02 02:08:28 +00:00
|
|
|
}
|