commit 4902e0fb3f726a1079072b079146fc3392cea667 Author: Emery Hemingway Date: Wed Apr 12 18:45:30 2023 -0500 Initial commit diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..4527fad --- /dev/null +++ b/.envrc @@ -0,0 +1,2 @@ +source_env .. +use flake nixpkgs#nimPackages.eris diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7ad6275 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/.direnv diff --git a/Tuprules.tup b/Tuprules.tup new file mode 100644 index 0000000..5f25682 --- /dev/null +++ b/Tuprules.tup @@ -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)/ + +NIM_FLAGS += --define:ssl +NIM_FLAGS += --define:traceSyndicate diff --git a/jabber_actor.nimble b/jabber_actor.nimble new file mode 100644 index 0000000..c6c91c7 --- /dev/null +++ b/jabber_actor.nimble @@ -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" diff --git a/protocol.prs b/protocol.prs new file mode 100644 index 0000000..225f377 --- /dev/null +++ b/protocol.prs @@ -0,0 +1,2 @@ +version 1 . +XmppClient = . diff --git a/src/Tupfile b/src/Tupfile new file mode 100644 index 0000000..0feaf44 --- /dev/null +++ b/src/Tupfile @@ -0,0 +1,3 @@ +include_rules +: foreach ../*.prs |> !preserves_schema_nim |> {schema} +: jabber_actor.nim | {schema} |> !nim_bin |> diff --git a/src/jabber_actor.nim b/src/jabber_actor.nim new file mode 100644 index 0000000..b613269 --- /dev/null +++ b/src/jabber_actor.nim @@ -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".} diff --git a/src/protocol.nim b/src/protocol.nim new file mode 100644 index 0000000..08a55e0 --- /dev/null +++ b/src/protocol.nim @@ -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))