diff --git a/protocol.prs b/protocol.prs
index 1f158e1..957c140 100644
--- a/protocol.prs
+++ b/protocol.prs
@@ -10,6 +10,17 @@ Address =
.
Name = .
+Connection = =none / =tcp / =udp .
+Status = .
+
StatusMessage = .
+Typing = .
+
+; Asserted by the core on a friend request.
+FriendRequest = .
+
+; Asserted to the core to accept a friend request.
+FriendAccept = .
+
BootstrapNode = .
diff --git a/src/protocol.nim b/src/protocol.nim
index 351a707..7eb69d0 100644
--- a/src/protocol.nim
+++ b/src/protocol.nim
@@ -6,6 +6,10 @@ type
Name* {.preservesRecord: "name".} = object
`name`*: string
+ FriendRequest* {.preservesRecord: "request".} = object
+ `key`*: seq[byte]
+ `msg`*: string
+
FriendDataspace*[E] {.preservesRecord: "friend".} = ref object
`publicKey`*: seq[byte]
`entity`*: Preserve[E]
@@ -17,6 +21,8 @@ type
`publicKey`*: seq[byte]
`entity`*: Preserve[E]
+ Typing* {.preservesRecord: "typing".} = object
+
BootstrapNode* {.preservesRecord: "bootstrap".} = object
`publicKey`*: string
`host`*: string
@@ -25,6 +31,14 @@ type
StatusMessage* {.preservesRecord: "status-message".} = object
`msg`*: string
+ Status* {.preservesRecord: "status".} = object
+ `status`*: Connection
+
+ FriendAccept* {.preservesRecord: "accept".} = object
+ `key`*: seq[byte]
+
+ `Connection`* {.preservesOr, pure.} = enum
+ `none`, `tcp`, `udp`
CoreVersion* {.preservesRecord: "core".} = object
`major`*: int
`minor`*: int
@@ -36,9 +50,16 @@ proc `$`*[E](x: FriendDataspace[E] | ToxDataspace[E]): string =
proc encode*[E](x: FriendDataspace[E] | ToxDataspace[E]): seq[byte] =
encode(toPreserve(x, E))
-proc `$`*(x: Name | Address | BootstrapNode | StatusMessage | CoreVersion): string =
+proc `$`*(x: Name | FriendRequest | Address | Typing | BootstrapNode |
+ StatusMessage |
+ Status |
+ FriendAccept |
+ CoreVersion): string =
`$`(toPreserve(x))
-proc encode*(x: Name | Address | BootstrapNode | StatusMessage | CoreVersion): seq[
- byte] =
+proc encode*(x: Name | FriendRequest | Address | Typing | BootstrapNode |
+ StatusMessage |
+ Status |
+ FriendAccept |
+ CoreVersion): seq[byte] =
encode(toPreserve(x))
diff --git a/src/syndicate_actor_tox.nim b/src/syndicate_actor_tox.nim
index 0e99b83..75b6a52 100644
--- a/src/syndicate_actor_tox.nim
+++ b/src/syndicate_actor_tox.nim
@@ -45,13 +45,12 @@ type
core: Tox
statusCounts: array[3, int]
handles: CoreHandles
- friendRequests: Table[toxcore.PublicKey, Handle]
- friendEntities: seq[FriendEntity]
+ friends: Table[Friend, FriendEntity]
proc init(e: Entity; turn: var Turn; parent: Ref): Handle =
assert e.facet.isNil
e.facet = turn.facet
- e.ds = newRef(turn, parent.target)
+ e.ds = newDataspace(turn)
proc initCore(entity: CoreEntity; turn: var Turn; parentRef: Ref) =
assert entity.core.isNil
@@ -123,17 +122,53 @@ proc initCore(entity: CoreEntity; turn: var Turn; parentRef: Ref) =
entity.handles.statusMessage = publish(turn, entity.ds,
StatusMessage(msg: entity.core.statusMessage))
block: # Friends initialization
- var friendNums = entity.core.friends
- entity.friendEntities.setLen(friendNums.len)
- for fn in friendNums:
+ proc createFriend(turn: var Turn; fn: Friend) =
var fe = new FriendEntity
discard init(fe, turn, entity.ds)
discard publish(turn, entity.ds, FriendDataspace[Ref](
publicKey: entity.core.publicKey(fn).bytes.toSeq,
entity: fe.ds.embed))
- if fn.int > entity.friendEntities.len:
- entity.friendEntities.setLen(fn.int.succ)
- entity.friendEntities[int fn] = fe
+ fe.handles.name = publish(turn, fe.ds, Name(name: entity.core.name(fn)))
+ entity.friends[fn] = fe
+
+ for fn in entity.core.friends: createFriend(turn, fn)
+
+ entity.core.onSelfConnectionStatus do (status: toxcore.Connection):
+ run(entity.facet) do (turn: var Turn):
+ let conn = case status
+ of TOX_CONNECTION_NONE: protocol.Connection.none
+ of TOX_CONNECTION_TCP: protocol.Connection.tcp
+ of TOX_CONNECTION_UDP: protocol.Connection.udp
+ replace(turn, entity.ds, entity.handles.connectionStatus,
+ Status(status: conn))
+
+ template update[T](fe: FriendEntity; h: var Handle; a: T) =
+ run(fe.facet) do (turn: var Turn): replace(turn, fe.ds, h, a)
+
+ entity.core.onFriendName do (num: Friend; name: string):
+ let fe = entity.friends[num]
+ update(fe, fe.handles.name, Name(name: name))
+
+ entity.core.onFriendStatusMessage do (num: Friend; msg: string):
+ let fe = entity.friends[num]
+ update(fe, fe.handles.statusMessage, StatusMessage(msg: msg))
+
+ entity.core.onFriendTyping do (num: Friend; typing: bool):
+ let fe = entity.friends[num]
+ if typing:
+ update(fe, fe.handles.typing, Typing())
+ else:
+ run(fe.facet) do (turn: var Turn):
+ retract(turn, fe.handles.typing)
+
+ entity.core.onFriendRequest do (pk: PublicKey; msg: string):
+ run(entity.facet) do (turn: var Turn):
+ let reqHandle = publish(turn, entity.ds,
+ FriendRequest(key: pk.bytes.toSeq, msg: msg))
+ onPublish(turn, entity.ds, ?FriendAccept(key: pk.bytes.toSeq)) do:
+ createFriend(turn, entity.core.addFriendNoRequest(pk))
+ retract(turn, reqHandle)
+ # TODO: stop watching for the accept assertion
var alive: bool
setControlCHook do:
diff --git a/tox.config-example.pr b/tox.config-example.pr
new file mode 100644
index 0000000..569e147
--- /dev/null
+++ b/tox.config-example.pr
@@ -0,0 +1,29 @@
+>
+
+
+? ?tox> [
+ $config ? ?notifier> [
+ $tox [
+
+ ? $core [
+ ? $log !
+ ? [
+ $notifier !
+
+ ]
+ ? $friend [
+ $notifier !
+ ? [
+ $notifier !
+ ? [ $notifier ! ]
+ ]
+ ]
+ ]
+ ]
+ ]
+]