- start two peers alice, bob
- make alice requests contact with bob
- they send messages
- they shutdown
- verify (and fix) no threads leaked
- verify messages
- add inbound connection handler to chatChannelHandler
- add Open and AcceptAllContactHandler to application
After the RequestOpenChannel changes, it's now possible to specify the
name and message of an outbound request as variables of the channel handler,
instead implementing an interface method to return them.
Also added the SendResponse method, which is necessary to respond to an
inbound request that was in the Pending state.
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.
ChatChannel didn't return the message ID for sent messages, which made
using the returned ACKs impossible. The SendMessage method now returns
the uin32 messageID.
Also, SendMessage didn't support the TimeDelta field for messages, which
is used for queued or resent messages. This is now available as
SendMessageWithTime.
And finally, the ChatMessageAck callback didn't indicate if mesasges
were accepted or not, which is part of the protocol. That was added as a
field, which is unfortunately a breaking API change, but I've made
enough of those lately to not feel guilty about it.
There are few situations where a pointer to an interface is useful in
Go, and this isn't one. Interfaces can hold types by value or pointer,
so long as that type fulfills the interface.