Sign in

    moon-xmpp

    An XMPP client library for MoonBit

    xmpp
    Download zip
    Author
    Version
    0.12.0
    License
    MIT
    Last updated
    4 hours ago
    Downloads
    15

    #moon-xmpp

    An XMPP client library for MoonBit, implementing the client side of XMPP Core (RFC 6120) and XMPP IM (RFC 6121).

    #Status

    moon-xmpp is an entry for a MoonBit hackathon. The core session lifecycle (streams, STARTTLS, SASL, resource binding, presence, roster and presence subscription management, chat) is implemented, covered by 130+ tests, and verified end to end: against a real local XMPP server (prosody), a chat message sent from moon-xmpp arrives in the Adium GUI client on macOS, and Adium's reply is received back by moon-xmpp. Interop was also verified automatically against slixmpp, an independent Python XMPP implementation — for chat, and for roster fetches, subscription authorization, and presence broadcasts. See docs/ACCEPTANCE.md for the runs and transcripts.

    #What it does

    moon-xmpp lets MoonBit programs connect to standard XMPP servers such as ejabberd, log in securely, and exchange one-on-one chat messages that interoperate with off-the-shelf clients such as Psi, Gajim, or Conversations.

    The project's acceptance scenario — verified end to end (see Status):

    1. moon-xmpp connects to an ejabberd server, negotiates STARTTLS, authenticates with SASL, and binds a resource.
    2. It sends a chat message to another account; the message shows up in a third-party client in real time.
    3. A reply sent from that client is received by moon-xmpp.
    4. It fetches its roster and manages presence subscriptions with that client; the client's authorization request is surfaced rather than auto-answered, and once authorization is mutual, presence broadcasts flow in both directions.

    #Protocol coverage

    FeatureStandardStatus
    XML streamsRFC 6120 §4done
    STARTTLSRFC 6120 §5done
    SASL: PLAIN, SCRAM-SHA-1, SCRAM-SHA-256RFC 4422, RFC 4616, RFC 5802, RFC 7677done
    Resource bindingRFC 6120 §7done
    Initial presenceRFC 6121 §4.2done
    Roster: get, set, pushRFC 6121 §2done
    Presence subscriptionsRFC 6121 §3done
    Chat messagesRFC 6120 §8, RFC 6121 §5.2done
    JID parsing and normalizationRFC 8264done

    #Non-goals

    • Roster versioning (RFC 6121 §2.6): roster fetches always request the full list.
    • XMPP extensions (XEPs), such as SASL2 (XEP-0388), Stream Management (XEP-0198), Message Carbons (XEP-0280), or MAM (XEP-0313).
    • Server-to-server (s2s) federation and any server-side functionality — this is a client library only.

    #Installation

    moon add daqing/moon-xmpp

    Then import it in the moon.pkg of your package:

    import { "daqing/moon-xmpp" @xmpp, }

    #Usage

    The API is built on moonbitlang/async. MoonBit has no await keyword — async calls look like ordinary calls, and errors propagate implicitly (functions raising XmppError must be called from a raising context).

    ///|
    async fn main {
    let conn = @xmpp.connect(host="example.com", port=5222)
    conn.open_stream(domain="example.com")
    ignore(conn.starttls(domain="example.com"))
    ignore(conn.authenticate(jid="alice@example.com", password="secret"))
    ignore(conn.bind_resource(resource="laptop"))
    conn.send_initial_presence()
    ignore(conn.get_roster())
    ignore(conn.send_subscribe(to="bob@example.com"))
    let id = conn.send_chat(to="bob@example.com", body="Hello from MoonBit!")
    let stanza = conn.recv_stanza() // Chat / Presence / RosterPush / Subscription / Other
    }

    #Demo

    A small CLI lives in cmd/moon-xmpp. Given only credentials, it connects and drops into an interactive REPL:

    git clone https://github.com/daqing/moon-xmpp cd moon-xmpp moon run cmd/moon-xmpp -- \ --jid alice@example.com \ --password '…'

    The REPL accepts these commands:

    CommandEffect
    rosterprint the cached roster with availability
    send <jid> <message>send a chat message
    subscribe <jid>ask to see a contact's presence
    approve <jid>accept a subscription request
    unsubscribe <jid>stop receiving a contact's presence
    deny <jid>refuse a subscription request
    helplist the commands
    quitclose the session (also exit, or EOF)

    Incoming chat messages and presence broadcasts are printed while the REPL is waiting for input. See docs/REPL.md for a walkthrough of logging in, managing contacts, and sending messages.

    One-shot actions work without the REPL. Add --repl to enter it after the actions run:

    moon run cmd/moon-xmpp -- --jid alice@example.com --password '…' \ --to bob@example.com --body 'Hello from MoonBit!' moon run cmd/moon-xmpp -- --jid alice@example.com --password '…' \ --roster --subscribe bob@example.com --approve bob@example.com --repl

    The CLI connects (STARTTLS by default, --host/--port to override), logs in, binds a resource, and goes online. --roster prints the fetched roster, --subscribe asks to see a contact's presence, and --approve grants a contact's request. Incoming requests are printed and never answered automatically. Without --repl, the client keeps printing incoming stanzas until the stream ends.

    #Roadmap

    #Development

    Requires the MoonBit toolchain (moon). Targets the native backend.

    moon build # build all packages (native target) moon test # run the test suite moon fmt # format the code moon info # regenerate package interfaces

    Integration testing runs against a local XMPP server:

    scripts/prosody.sh start # or scripts/ejabberd.sh on x86 scripts/prosody.sh register alice secret123 scripts/prosody.sh register bob secret123 scripts/e2e.sh # two-direction delivery test scripts/roster.sh # roster and subscription test

    #License


    version

    fn version() -> String

    Return the version of the moon-xmpp library.

    Keep in sync with the version field in moon.mod.

    Source Files