| author | Eric Roberts
<eric@devl.me> 2026-09-23 14:33:48 UTC |
| committer | Stephen Paul Weber
<singpolyma@singpolyma.net> 2026-09-23 14:40:23 UTC |
| parent | 6329d4e5753c531dd759a9fa8c21c742d3a2c583 |
| borogove/streams/XmppJsStream.hx | +15 | -4 |
| test/TestAll.hx | +3 | -0 |
| test/TestXmppJsStream.hx | +44 | -0 |
diff --git a/borogove/streams/XmppJsStream.hx b/borogove/streams/XmppJsStream.hx index 84665fd..0b5829c 100644 --- a/borogove/streams/XmppJsStream.hx +++ b/borogove/streams/XmppJsStream.hx @@ -24,6 +24,7 @@ extern class XmppJsClient { function new(options:Dynamic); function start():Promise<Dynamic>; function stop():Promise<Dynamic>; + function disconnect():Promise<Dynamic>; function on(eventName:String, callback:(Dynamic)->Void):Void; function send(stanza:XmppJsXml):Void; final NS:String; @@ -144,6 +145,7 @@ extern class XmppJsStreamFeatures { } class XmppJsStream extends GenericStream { + private final createClient:Dynamic->XmppJsClient; private var client:XmppJsClient; private var jid:XmppJsJID; private var debug = js.Browser.getLocalStorage()?.getItem("BOROGOVE_XMPP_DEBUG") == "1" || js.Syntax.code("globalThis.process?.env?.BOROGOVE_XMPP_DEBUG") == "1"; @@ -155,8 +157,9 @@ class XmppJsStream extends GenericStream { private var resumed = false; private var everConnected = false; - override public function new() { + override public function new(?createClient:Dynamic->XmppJsClient) { super(); + this.createClient = createClient ?? (options -> new XmppJsClient(options)); state = new FSM({ transitions: [ { name: "connect-requested", from: ["offline"], to: "connecting" }, @@ -246,7 +249,7 @@ class XmppJsStream extends GenericStream { final clientId = jid.resource; var credentials: Dynamic = null; - final xmpp = new XmppJsClient({ + final xmpp = createClient({ service: jid.domain, resource: jid.resource, credentials: (callback, mechanisms: Dynamic, fast: Null<{mechanism: String}>) -> { @@ -273,7 +276,8 @@ class XmppJsStream extends GenericStream { credentials = creds; return callback(creds, creds.mechanism ?? mech, new XmppJsXml("user-agent", { id: clientId })); }); - } + }, + timeout: 10_000, }); new XmppJsScramSha1(xmpp.saslFactory); xmpp.jid = this.jid; @@ -381,7 +385,14 @@ class XmppJsStream extends GenericStream { resumed = false; xmpp.start().catchError(function (err) { - trace(err); + if (err.name == 'TimeoutError') { + trace("XmppJsStream: Timed out, disconnecting."); + xmpp.disconnect(); + return; + } + + trace("XmppJsStream: Error on start", err); + if (this.state.can("connection-error")) this.state.event("connection-error", { error: err }); }); } diff --git a/test/TestAll.hx b/test/TestAll.hx index 707b619..df0c519 100644 --- a/test/TestAll.hx +++ b/test/TestAll.hx @@ -37,6 +37,9 @@ class TestAll { new TestStringUtil(), new TestUtil(), new TestXEP0393(), +#if js + new TestXmppJsStream(), +#end #if eval new TestCaps(), #else diff --git a/test/TestXmppJsStream.hx b/test/TestXmppJsStream.hx new file mode 100644 index 0000000..f40f235 --- /dev/null +++ b/test/TestXmppJsStream.hx @@ -0,0 +1,44 @@ +package test; + +import borogove.streams.XmppJsStream; +import js.lib.Promise; +import utest.Assert; +import utest.Async; + +@:access(borogove.streams.XmppJsStream) +class TestXmppJsStream extends utest.Test { + public function testTimeoutDisconnects(async:Async) { + final createFakeClient = (options:Dynamic) -> { + final client = new XmppJsClient(options); + Reflect.setField( + client, + "start", + () -> Promise.reject(timeoutError()) + ); + Reflect.setField( + client, + "disconnect", + () -> { + // I just want to check that we called disconnect. + // async.done() isn't sufficient by itself because + // my test needs at least one assertion. + Assert.isTrue(true); + async.done(); + return Promise.resolve(null); + } + ); + + return client; + }; + + final stream = new XmppJsStream(createFakeClient); + stream.connect("test@example.com/test", null); + } + + private function timeoutError() { + final error = new js.lib.Error(); + error.name = "TimeoutError"; + + return error; + } +}