Contents

offskylab/swift-nebula-client

> [!WARNING]

Overview

swift-nebula-client provides the client-side entities for connecting to a Nebula network:

| Type | Role | |------|------| | RoguePlanet | RPC client — calls remote service methods and waits for results | | Comet | Async producer — enqueues tasks into a broker namespace | | Subscriber | Pub-sub consumer — receives events pushed from Galaxy | | Moon | Typed proxy over RoguePlanet with dynamic method call syntax |

Connection to the network always starts via Ingress, which handles service discovery and routing to the appropriate Stellar node.


Installation

// Package.swift
dependencies: [
    .package(url: "https://github.com/gradyzhuo/swift-nebula-client.git", from: "0.1.0"),
],
targets: [
    .target(name: "MyTarget", dependencies: [
        .product(name: "NebulaClient", package: "swift-nebula-client"),
    ]),
]

Usage

RPC — RoguePlanet

Connect to Ingress and call a remote method directly:

import NebulaClient

let planet = try await NebulaClient.planet(
    connecting: "nmtp://localhost:6224/production/ml/embedding",
    service: "w2v"
)

// Raw call — returns Data?
let data = try await planet.call(method: "wordVector", arguments: [
    .wrap(key: "word", value: "hello")
])

// Typed call
struct VectorResult: Decodable { let vector: [Float] }
let result = try await planet.call(method: "wordVector", as: VectorResult.self)

RPC — Moon (dynamic syntax)

Moon wraps a RoguePlanet and lets you call methods like function calls:

import NebulaClient

let moon = try await NebulaClient.moon(
    connecting: "nmtp://localhost:6224/production/ml/embedding",
    service: "w2v"
)

// Dynamic call — returns Data?
let data = try await moon.wordVector(word: "hello")

// Typed call
let result: VectorResult = try await moon.wordVector.call(as: VectorResult.self, word: "hello")

Async Messaging — Comet

Enqueue tasks into a broker namespace without waiting for the result:

import NebulaClient

let comet = try await NebulaClient.comet(
    connecting: "nmtp://localhost:6224/production/orders"
)

try await comet.enqueue(
    service: "orderService",
    method: "process",
    arguments: [
        .wrap(key: "orderID", value: "ORD-1001"),
        .wrap(key: "amount",  value: 49.99),
    ]
)

Pub-Sub — Subscriber

Subscribe to a broker topic and receive events pushed from Galaxy:

import NebulaClient
import NIO

let ingressAddress = try SocketAddress.makeAddressResolvingHost("127.0.0.1", port: 6224)
let ingressClient = try await IngressClient.connect(to: ingressAddress)

let subscriber = try await Subscriber(
    ingressClient: ingressClient,
    topic: "production.orders",
    subscription: "fulfillment"
)

for await event in await subscriber.events {
    print("\(event.service).\(event.method)", event.arguments.toArguments().toDictionary())
}

Connection Model

RoguePlanet / Comet / Subscriber


    IngressClient  ──── find(namespace:) ────▶  Galaxy

        │◀──── stellarAddress ─────────────────────┘


    StellarClient  ──── call / enqueue ────▶  Stellar
  • Normal path: connect to Ingress → get Stellar address → call Stellar directly
  • Failover: Stellar unreachable → notify Ingress → get next Stellar → reconnect

Relationship to Nebula

swift-nmtp           transport protocol layer

swift-nebula        ← server framework (Galaxy, Stellar, Ingress)

swift-nebula-client ← this repo — Swift client SDK

swift-nebula-client only depends on swift-nmtp. It has no dependency on swift-nebula, allowing the client to stay lightweight and enabling other language SDKs to implement the same protocol independently.


Requirements

  • Swift 6.0+
  • macOS 13+

Dependencies

License

Apache License 2.0

Package Metadata

Repository: offskylab/swift-nebula-client

Default branch: main

README: README.md