Lightstreamer.Protocol (Lightstreamer v0.1.0)

Copy Markdown View Source

Pure encoders for TLCP client requests, plus the percent-encoding shared by the whole codec.

Each function returns iodata for exactly one WebSocket text message: a request-name line and a parameter line, both CR-LF-terminated (wsok/0 being the protocol's single exception, with no parameter line at all). No sockets, no processes — Lightstreamer.Session sends what these return.

Summary

Functions

Encodes a bind_session request, rebinding an existing session onto a new WebSocket (the LOOP flow).

Encodes a create_session request.

The heartbeat pseudo-request, keeping a quiet connection alive when LS_inactivity_millis was advertised. It has no parameters, so the empty parameter line still carries its terminator.

Decodes %XX percent-encoding (either hex case) in a server-sent value.

Percent-encodes a parameter value.

Encodes a control request adding a subscription.

Encodes a control request deleting a subscription.

The wsok handshake request — the first message on every new WebSocket.

Functions

bind_session(session_id, opts \\ [])

@spec bind_session(String.t(), opts) :: iodata()
when opts: [keepalive_millis: pos_integer(), inactivity_millis: pos_integer()]

Encodes a bind_session request, rebinding an existing session onto a new WebSocket (the LOOP flow).

Options

Examples

iex> IO.iodata_to_binary(Lightstreamer.Protocol.bind_session("Sid123"))
"bind_session\r\nLS_session=Sid123\r\n"

create_session(opts \\ [])

@spec create_session(opts) :: iodata()
when opts: [
       adapter_set: String.t(),
       user: String.t(),
       password: String.t(),
       keepalive_millis: pos_integer(),
       inactivity_millis: pos_integer()
     ]

Encodes a create_session request.

Always sends the fixed LS_cid and an empty LS_supported_diffs, refusing the ^P/^T diff formats this library cannot decode.

Options

  • :adapter_set - the adapter set to open the session on (server default: "DEFAULT" when omitted)
  • :user - user credential; semantics are defined by the server's Metadata Adapter
  • :password - password credential
  • :keepalive_millis - requested keepalive interval; the server replies with the authoritative value in CONOK
  • :inactivity_millis - declared maximum client silence, committing us to outbound heartbeats

Examples

iex> IO.iodata_to_binary(Lightstreamer.Protocol.create_session(adapter_set: "DEMO"))
"create_session\r\nLS_cid=mgQkwtwdysogQz2BJ4Ji%20kOj2Bg&LS_adapter_set=DEMO&LS_supported_diffs=\r\n"

heartbeat()

@spec heartbeat() :: iodata()

The heartbeat pseudo-request, keeping a quiet connection alive when LS_inactivity_millis was advertised. It has no parameters, so the empty parameter line still carries its terminator.

Examples

iex> IO.iodata_to_binary(Lightstreamer.Protocol.heartbeat())
"heartbeat\r\n\r\n"

percent_decode(value)

@spec percent_decode(binary()) :: binary()

Decodes %XX percent-encoding (either hex case) in a server-sent value.

Examples

iex> Lightstreamer.Protocol.percent_decode("aa%7Cbb%3A%20cc")
"aa|bb: cc"

percent_encode(value)

@spec percent_encode(String.t()) :: String.t()

Percent-encodes a parameter value.

TLCP reserves exactly CR, LF, &, =, % and + in parameter values; we additionally encode space (further encoding is explicitly permitted by the protocol, and it keeps wire lines unambiguous to the eye).

Examples

iex> Lightstreamer.Protocol.percent_encode("a=b&c d")
"a%3Db%26c%20d"

subscribe(req_id, opts)

@spec subscribe(pos_integer(), opts) :: iodata()
when opts: [
       sub_id: pos_integer(),
       items: [String.t()],
       fields: [String.t()],
       mode: :merge,
       data_adapter: String.t(),
       snapshot: boolean(),
       max_frequency: :unlimited | :unfiltered | float()
     ]

Encodes a control request adding a subscription.

LS_session is omitted: on a WebSocket it defaults to the last bound session.

Options

  • :sub_id - required; client-assigned progressive subscription ID, unique within the session
  • :items - required; item names, becoming the space-separated LS_group
  • :fields - required; field names, becoming the space-separated LS_schema
  • :mode - subscription mode; only :merge in v0.1 (default :merge)
  • :data_adapter - data adapter name (server default: "DEFAULT")
  • :snapshot - whether to request the initial snapshot
  • :max_frequency - :unlimited, :unfiltered, or updates per second as a float

Examples

iex> IO.iodata_to_binary(Lightstreamer.Protocol.subscribe(1, sub_id: 1, items: ["item1"], fields: ["last_price"]))
"control\r\nLS_reqId=1&LS_op=add&LS_subId=1&LS_group=item1&LS_schema=last_price&LS_mode=MERGE\r\n"

unsubscribe(req_id, sub_id)

@spec unsubscribe(pos_integer(), pos_integer()) :: iodata()

Encodes a control request deleting a subscription.

Examples

iex> IO.iodata_to_binary(Lightstreamer.Protocol.unsubscribe(9, 2))
"control\r\nLS_reqId=9&LS_op=delete&LS_subId=2\r\n"

wsok()

@spec wsok() :: iodata()

The wsok handshake request — the first message on every new WebSocket.

Uniquely, it has no parameter line (not even an empty one).

Examples

iex> IO.iodata_to_binary(Lightstreamer.Protocol.wsok())
"wsok\r\n"