Initial commit

This commit is contained in:
Emery Hemingway 2023-04-12 18:45:30 -05:00
commit 4902e0fb3f
8 changed files with 115 additions and 0 deletions

2
.envrc Normal file
View File

@ -0,0 +1,2 @@
source_env ..
use flake nixpkgs#nimPackages.eris

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/.direnv

7
Tuprules.tup Normal file
View File

@ -0,0 +1,7 @@
include ../syndicate-nim/depends.tup
NIM_FLAGS += --path:$(TUP_CWD)/../getdns/src
NIM_FLAGS += --path:$(TUP_CWD)/../syndicate-nim/src
NIM_GROUPS += $(TUP_CWD)/<protocols>
NIM_FLAGS += --define:ssl
NIM_FLAGS += --define:traceSyndicate

13
jabber_actor.nimble Normal file
View File

@ -0,0 +1,13 @@
# Package
version = "20230412"
author = "Emery Hemingway"
description = "Jabber Syndicate actor"
license = "Unlicense"
srcDir = "src"
bin = @["jabber_actor"]
# Dependencies
requires "nim >= 1.6.10"

2
protocol.prs Normal file
View File

@ -0,0 +1,2 @@
version 1 .
XmppClient = <xmpp-client @jid string @password string @cap #!any> .

3
src/Tupfile Normal file
View File

@ -0,0 +1,3 @@
include_rules
: foreach ../*.prs |> !preserves_schema_nim |> {schema}
: jabber_actor.nim | {schema} |> !nim_bin |>

72
src/jabber_actor.nim Normal file
View File

@ -0,0 +1,72 @@
# SPDX-FileCopyrightText: ☭ Emery Hemingway
# SPDX-License-Identifier: Unlicense
import std/asyncdispatch, asyncnet, net, strutils
import syndicate
import getdns
import ./protocol
when not defined(posix): {.error: "This utility requires POSIX".}
proc checkError(r: getdns_return_t) =
if r.isBad: quit($r, QuitFailure)
type Client = ref object
context: SslContext
socket: AsyncSocket
proc close(client: Client) =
try: close(client.socket)
except CatchableError: discard # stupid
destroyContext(client.context)
proc connect(client: Client; jid: string) {.async.} =
stderr.writeLine "connecting as ", jid
var domains = rsplit(jid, '@', 1)
stderr.writeLine "domains is ", $domains
if domains.len != 2:
stderr.writeLine "invalid JID ", jid
raise newException(ValueError, "invalid JID " & jid)
var serviceProtoName = "_xmpps-client._tcp." & domains[1]
stderr.writeLine "lookup ", serviceProtoName
let dns = getdns.newContext(true)
# defer: context_destroy(dns)
dns.setResolutionType(GETDNS_RESOLUTION_STUB)
var response: Dict
checkError service_sync(dns, serviceProtoName, nil, addr response)
if response["status"].int != RESPSTATUS_GOOD:
raise newException(IOError, $response)
for srvAddr in response["srv_addresses"]:
wrapSocket(client.context, client.socket)
try:
let
host = srvAddr["domain_name"].bindata.toFqdn
port = srvAddr["port"].int.Port
stderr.writeLine "connecting to ", host, ":", port
await connect(client.socket, host, port)
stderr.writeLine "successfully connected to ", host, ":", port
break
except CatchableError as e:
stderr.writeLine "failed to connect: ", e.msg
close(client)
proc bootClient(turn: var Turn; jid, password: string; ds: Ref): Client =
result = Client(
context: newContext(protTLSv1, CVerifyNone),
socket: newAsyncSocket(),
)
asyncCheck(turn, connect(result, jid))
bootDataspace("main") do (root: Ref; turn: var Turn):
stderr.writeLine "connectStdio…"
connectStdio(root, turn)
stderr.writeLine "stdio connected"
during(turn, root, ?XmppClient) do (jid: string, password: string, ds: Ref):
let client = bootClient(turn, jid, password, ds)
do:
stderr.writeLine "retracting client"
close(client)
runForever()
{.error: "during clause not active until retraction".}

15
src/protocol.nim Normal file
View File

@ -0,0 +1,15 @@
import
std/typetraits, preserves
type
XmppClient* {.preservesRecord: "xmpp-client".} = object
`jid`*: string
`password`*: string
`cap`* {.preservesEmbedded.}: Preserve[void]
proc `$`*(x: XmppClient): string =
`$`(toPreserve(x))
proc encode*(x: XmppClient): seq[byte] =
encode(toPreserve(x))