Skip to Content
Client Lifecycle

Client Lifecycle

One-time initialization

Call KalamClient.init() once at app startup. It initializes the underlying Rust runtime.

await KalamClient.init();

Do not call KalamClient.connect(...) before init().

Creating a client

final client = await KalamClient.connect( url: 'http://localhost:8080', authProvider: () async => Auth.jwt(await getJwt()), timeout: const Duration(seconds: 30), maxRetries: 3, disableCompression: false, logLevel: Level.debug, logListener: (entry) => debugPrint(entry.toString()), );

Notes:

  • connect(...) returns a ready-to-use handle. The SDK manages the WebSocket connection lifecycle automatically.
  • Most methods use HTTP; subscriptions additionally use WebSocket under the hood.
  • With wsLazyConnect: true (the default), connect() does not open the shared WebSocket immediately.
  • On native Dart targets, the shared subscription connection defaults to MessagePack serialization for lower overhead on first subscription and live updates.

wsLazyConnect (default: true)

By default, the WebSocket connection is lazy: it is deferred until the first subscribe() call. This avoids unnecessary connections when the client is only used for HTTP queries.

Set wsLazyConnect: false to establish the connection eagerly:

final client = await KalamClient.connect( url: 'http://localhost:8080', authProvider: () async => Auth.jwt(await getJwt()), wsLazyConnect: false, // connect WebSocket immediately );

Auth refresh model

  • authProvider is the connect-time auth API.
  • connect() resolves auth once up front, and the first lazy subscribe() reuses those already-resolved credentials.
  • Use refreshAuth() to proactively re-run authProvider and push updated credentials into the client.
  • Return Auth.basic(...) if you want the SDK to perform a Basic-to-JWT exchange before first use.

Refreshing auth in place

If you provided an authProvider, you can re-fetch and push updated credentials into the client:

await client.refreshAuth(); Timer.periodic(const Duration(minutes: 55), (_) => client.refreshAuth());

With the default Auth.none() provider, refreshAuth() simply re-resolves anonymous auth.

Manual WebSocket controls

The client also exposes a few explicit shared-socket controls:

  • isConnected returns whether the shared WebSocket is currently open.
  • disconnectWebSocket() closes the shared WebSocket.
  • reconnectWebSocket() first tries a fast reconnect with the current auth already held in memory. If the server rejects that reconnect for auth reasons, the SDK refreshes auth once and retries.
final connected = await client.isConnected; if (!connected) { await client.reconnectWebSocket(); }

Mobile live-connection pattern

For Flutter apps with live screens, keep one KalamClient alive for the whole signed-in session and reconnect it when the app returns to the foreground.

class LiveClientController with WidgetsBindingObserver { final KalamClient client; LiveClientController(this.client); @override void didChangeAppLifecycleState(AppLifecycleState state) { if (state == AppLifecycleState.resumed) { client.reconnectWebSocket(); } } }

That avoids waiting for a stale socket to be detected passively and is the fastest path back to a live subscription after resume.

Connection handlers

Use connectionHandlers to receive lifecycle events (connect/disconnect/errors) and optional raw message debugging.

final client = await KalamClient.connect( url: 'http://localhost:8080', authProvider: () async => Auth.jwt(await getJwt()), connectionHandlers: ConnectionHandlers( onConnect: () => print('connected'), onDisconnect: (reason) => print('disconnected: ${reason.message}'), onError: (error) => print('error: ${error.message}'), onReceive: (message) => print('[recv] $message'), onSend: (message) => print('[send] $message'), ), );

Handlers are only active when you pass at least one callback.

Connection events are buffered on the native side while Dart pulls them. The buffer is bounded to protect mobile memory; lifecycle events keep the newest signals when the buffer is full, and high-volume onReceive / onSend debug messages may be dropped under sustained load. Use onReceive / onSend only for local debugging; avoid logging sensitive data (tokens, PII) in production.

SDK logging level and redirection

KalamClient.connect(...) accepts:

  • logLevel: Level? (from package:logger/logger.dart)
  • logListener: LogListener?

Example:

import 'package:logger/logger.dart' show Level; final client = await KalamClient.connect( url: 'http://localhost:8080', authProvider: () async => Auth.jwt(await getJwt()), logLevel: Level.info, logListener: (entry) { myLogger.i('[${entry.tag}] ${entry.message}'); }, );

If no logListener is provided, logs are emitted with print(...) and appear in flutter run/Logcat.

Disposing

Call dispose() when the client is no longer needed:

await client.dispose();

After disposing, do not call query() or subscribe() on the same instance.

If you keep a single client for the whole app lifetime, dispose it only when the app is shutting down.

Next

Last updated on