From sgcWebSockets 4.1.6 STOMP protocol is supported.

STOMP is the Simple (or Streaming) Text Orientated Messaging Protocol. STOMP provides an interoperable wire format so that STOMP clients can communicate with any STOMP message broker to provide easy and widespread messaging interoperability among many languages, platforms and brokers.

Our STOMP client components supports following STOMP versions: 1.0, 1.1 and 1.2.

 

Use

This is Client Protocol STOMP Component, you need to drop this component in the form and select a TsgcWebSocketClient Component using Client Property.

 

Methods

  Send: The SEND frame sends a message to a destination in the messaging system.

  Subscribe: The SUBSCRIBE frame is used to register to listen to a given destination.

  UnSubscribe: The UNSUBSCRIBE frame is used to remove an existing subscription.

  ACK: ACK is used to acknowledge consumption of a message from a subscription.

  NACK: NACK is the opposite of ACK. It is used to tell the server that the client did not consume the message.

  BeginTransaction: is used to start a transaction. Transactions in this case apply to sending and acknowledging - any messages sent or acknowledged during a transaction will be processed atomically based on the transaction.

  CommitTransaction: is used to commit a transaction in progress.

  AbortTransaction: is used to roll back a transaction in progress.

  Disconnect: use to graceful shutdown connection, where the client is assured that all previous frames have been received by the server.

  

Events

  OnSTOMPConnected: this event is fired after a new connection is established.

    version : The version of the STOMP protocol the session will be using. See Protocol Negotiation for more details.

    STOMP 1.2 servers MAY set the following headers:

    heart-beat : The Heart-beating settings.

    session : A session identifier that uniquely identifies the session.

    server : A field that contains information about the STOMP server. The field MUST contain a server-name field and MAY be followed by optional comment fields delimited by a space character.

 

  OnSTOMPMessage: this event is fired when client receives a message.

  The MESSAGE frame MUST include a destination header indicating the destination the message was sent to. If the message has been sent using STOMP, this destination header SHOULD be identical to the one used in the corresponding SEND frame.

  The MESSAGE frame MUST also contain a message-id header with a unique identifier for that message and a subscription header matching the identifier of the subscription that is receiving the message.

  If the message is received from a subscription that requires explicit acknowledgment (either client or client-individual mode) then the MESSAGE frame MUST also contain an ack header with an arbitrary value. This header will be used to relate the message to a subsequent ACK or NACK frame.

  MESSAGE frames SHOULD include a content-length header and a content-type header if a body is present.

  MESSAGE frames will also include all user defined headers that were present when the message was sent to the destination in addition to the server specific headers that MAY get added to the frame.

 

  OnSTOMPReceipt: this event is fired once a server has successfully processed a client frame that requests a receipt.

  A RECEIPT frame is an acknowledgment that the corresponding client frame has been processed by the server. Since STOMP is stream based, the receipt is also a cumulative acknowledgment that all the previous frames have been received by the server. However, these previous frames may not yet be fully processed. If the client disconnects, previously received frames SHOULD continue to get processed by the server.

 

  OnSTOMPError: this event is fired  if something goes wrong.

  The ERROR frame SHOULD contain a message header with a short description of the error, and the body MAY contain more detailed information (or MAY be empty).

  If the error is related to a specific frame sent from the client, the server SHOULD add additional headers to help identify the original frame that caused the error. For example, if the frame included a receipt header, the ERROR frame SHOULD set the receipt-id header to match the value of the receipt header of the frame which the error is related to.

  ERROR frames SHOULD include a content-length header and a content-type header if a body is present.

  

Properties

 Authentication: disabled by default, if True an UserName and Password are sent to server to try user authentication.

 HeartBeat: Heart-beating can optionally be used to test the healthiness of the underlying TCP connection and to make sure that the remote end is alive and kicking. In order to enable heart-beating, each party has to declare what it can do and what it would like the other party to do. 0 means it cannot send/receive heart-beats, otherwise it is the desired number of milliseconds between heart-beats.

 Options: The name of a virtual host that the client wishes to connect to. It is recommended clients set this to the host name that the socket was established against, or to any name of their choosing. If this header does not match a known virtual host, servers supporting virtual hosting MAY select a default virtual host or reject the connection.

 Versions: Set which STOMP versions are supported.

Configure WebSocket client to connect to a websocket server is very easy, find below some examples which show how configure client, there are basically 2 methods:

 

Decode Server Parameters

ws://echo.websocket.org

Client.Host := 'echo.websocket.org;

Client.Port := 80;

Client.TLS := False;

 

wss://echo.websocket.org

Client.Host := 'echo.websocket.org';

Client.Port := 443;

Client.TLS := True;

 

wss://ws.binaryws.com/websockets/v3?app_id=1089

Client.Host := 'ws.binaryws.com';

Client.Port := 443;

Client.Options.Parameters := '/websockets/v3?app_id=1089';

 

Set URL Property (decodes server parameters automatically)

ws://echo.websocket.org

 

Client.URL := 'ws://echo.websocket.org';

 

wss://echo.websocket.org

Client.URL := 'wss://echo.websocket.org';

 

 

wss://ws.binaryws.com/websockets/v3?app_id=1089

Client.URL := 'wss://ws.binaryws.com/websockets/v3?app_Id=1089/';

 

Once websocket client is configured, just call Client.Active := True to connect to websocket server.

 

 

sgcWebSockets API Pusher components

From sgcWebSockets 4.1.5 Pusher WebSocket API is supported. 

Pusher it's an easy and reliable platform with nice features based on websocket protocol: flexible pub/sub messaging, live user lists (presence), authentication... 

Pusher WebSocket API is 7

Data is sent bidirectionally over a WebSocket as text data containing UTF8 encoded JSON (Binary WebSocket frames are not supported).

You can call Ping method to test connection to server. Essentially any messages received from the other party are considered to mean that the connection is alive. In the absence of any messages either party may check that the other side is responding by sending a ping message, to which the other party should respond with a pong.

Before you connect, you must complete following fields:

 

          Pusher.Cluster := 'eu'; // cluster where is located your pusher account

          Pusher.Key := '9c3b7ef25qe97a00116c'; // your pusher api key

          Pusher.Name := 'js'; // optional, name of your application

          Pusher.Version := '4.1';  // optional, version of your application

          Pusher.TLS := True; // if encrypted, set to True

          Pusher.Secret := '2dc792e1916ac49e6b3f'; // pusher secret string (needed for private and absence channels)

 

After a successful connection, OnPusherConnect event is raised and you get following fields:

 

  • Socket ID: A unique identifier for the connected client.

  • Timeout: The number of seconds of server inactivity after which the client should initiate a ping message (this is handled automatically by component).

 

In case of error, OnPusherError will be raised, and information about error provided. An error may be sent from Pusher in response to invalid authentication, an invalid command, etc.

 

4000-4099

Indicates an error resulting in the connection being closed by Pusher, and that attempting to reconnect using the same parameters will not succeed.

4000: Application only accepts SSL connections, reconnect using wss://

4001: Application does not exist

4003: Application disabled

4004: Application is over connection quota

4005: Path not found

4006: Invalid version string format

4007: Unsupported protocol version

4008: No protocol version supplied

 

4100-4199

Indicates an error resulting in the connection being closed by Pusher, and that the client may reconnect after 1s or more. 

4100: Over capacity

 

4200-4299

Indicates an error resulting in the connection being closed by Pusher, and that the client may reconnect immediately.

4200: Generic reconnect immediately

4201: Pong reply not received: ping was sent to the client, but no reply was received - see ping and pong messages

4202: Closed after inactivity: Client has been inactive for a long time (currently 24 hours) and client does not support ping. Please upgrade to a newer WebSocket draft or implement version 5 or above of this protocol.

 

4300-4399

Any other type of error.

4301: Client event rejected due to rate limit

 

Channels

Channels are a fundamental concept in Pusher. Each application has a number of channels, and each client can choose which channels it subscribes to.

Channels provide:

  • A way of filtering data. For example, in a chat application there may be a channel for people who want to discuss ‘dogs’

  • A way of controlling access to different streams of information. For example, a project management application would want to authorise people to get updates about ‘projectX’

It's strongly recommended that channels are used to filter your data and that it is not achieved using events. This is because all events published to a channel are sent to all subscribers, regardless of their event binding.

Channels don’t need to be explicitly created, and are instantiated on client demand. This means that creating a channel is easy. Just tell a client to subscribe to it.

There are 3 types of channels:

 

  • Public channels can be subscribed to by anyone who knows their name

  • Private channels introduce a mechanism which lets your server control access to the data you are broadcasting

  • Presence channels are an extension of private channels. They let you ‘register’ user information on subscription, and let other members of the channel know who’s online

 

Public Channels

Public channels should be used for publicly accessible data as they do not require any form authorisation in order to be subscribed to.

You can subscribe and unsubscribe from channels at any time. There’s no need to wait for the Pusher to finish connecting first.

Example: subscribe to channel "my-channel".

 

  APIPusher.Subscribe('my-channel');

 

If you are subscribed successfully OnPusherSubscribe event will be raised, if there is an error you will get a message in OnPusherError event.

All messages from subscribed channel will be received OnPusherEvent event.

  

Private Channels

Requires Indy 10.5.7 or later

Private channels should be used when access to the channel needs to be restricted in some way. In order for a user to subscribe to a private channel permission must be authorised.

Example: subscribe to channel "my-private-channel".

 

  APIPusher.Subscribe('my-private-channel', pscPrivateChannel);

 

If you are subscribed successfully OnPusherSubscribe event will be raised, if there is an error you will get a message in OnPusherError event.

All messages from subscribed channel will be received OnPusherEvent event.

 

Presence Channels

Requires Indy 10.5.7 or later

Presence channels build on the security of Private channels and expose the additional feature of an awareness of who is subscribed to that channel. This makes it extremely easy to build chat room and “who’s online” type functionality to your application. Think chat rooms, collaborators on a document, people viewing the same web page, competitors in a game, that kind of thing.

Presence channels are subscribed to from the client API in the same way as private channels but the channel name must be prefixed with presence-. As with private channels a HTTP Request is made to a configurable authentication URL to determine if the current user has permissions to access the channel.

Information on users subscribing to, and unsubscribing from a channel can then be accessed by binding to events on the presence channel and the current state of users subscribed to the channel is available via the channel.members property.

Example: subscribe to channel "my-presence-channel".

 

  APIPusher.Subscribe('my-presence-channel', pscPresenceChannel, '{"user_id":"John_Smith","user_info":{"name":"John Smith"}}');

 

If you are subscribed successfully OnPusherSubscribe event will be raised, if there is an error you will get a message in OnPusherError event.

All messages from subscribed channel will be received OnPusherEvent event.

 

 

Publish Messages

Not only you can receive messages from subscribed channels, you can send messages to other subscribed users.

Call method Publish to send a message to all subscribed users of channel.

Example: send an event to all subscribed users of "my-channel'

 

  APIPusher.Publish('my-event', 'my-channel');

 

 

Publish no more than 10 messages per second per client (connection). Any events triggered above this rate limit will be rejected by Pusher API. This is not a system issue, it is a client issue. 100 clients in a channel sending messages at this rate would each also have to be processing 1,000 messages per second! Whilst some modern browsers might be able to handle this it’s most probably not a good idea.

sgcWebSockets API Pusher components

sgcWebSockets API Bitfinex components

From sgcWebSockets 4.1.5 Bitfinex WebSocket API is supported.

Bitfinex is one of the world's largest and most advanced cryptocurrency trading platform. Users can exchange Bitcoin, Ethereum, Ripple, EOS, Bitcoin Cash, Iota, NEO, Litecoin, Ethereum Classic...

Bitfinex Websocket API version is 2.0

Each message sent and received via the Bitfinex's websocket channel is encoded in JSON format

 A symbol can be a trading pair or a margin currency:

 

  • Trading pairs symbols are formed prepending a "t" before the pair (i.e tBTCUSD, tETHUSD).

  • Margin currencies symbols are formed prepending a "f" before the currency (i.e fUSD, fBTC, ...)

  

After a successful connection, OnBitfinexConnect event is raised and you get Bitfinex API Version number as parameter.

You can call Ping method to test connection to server. 

If server sends any information, this can be handle using OnBitfinexInfoMessage event, where a Code and a Message are parameters with information about message sent by server. Example codes:

 

20051 : Stop/Restart Websocket Server (please reconnect)

20060 : Entering in Maintenance mode. Please pause any activity and resume after receiving the info message 20061 (it should take 120 seconds at most).

20061 : Maintenance ended. You can resume normal activity. It is advised to unsubscribe/subscribe again all channels.

 

In case of error, OnBitfinexError will be raised, and information about error provided. Example error codes:

 

10000 : Unknown event

10001 : Unknown pair

 

In order to change the configuration, call Configuration method and pass as a parameter one of the following flags:

 

CS_DEC_S = 8; // Enable all decimal as strings.

CS_TIME_S = 32; // Enable all times as date strings.

CS_SEQ_ALL = 65536; // Enable sequencing BETA FEATURE

CHECKSUM = 131072; // Enable checksum for every book iteration. Checks the top 25 entries for each side of book. Checksum is a signed int.

 

Subscribe Public Channels

There are channels which are public and there is no need to authenticate against server. All messages are raised OnBitfinexUpdate event.

 

SubscribeTicker

The ticker is a high level overview of the state of the market. It shows you the current best bid and ask, as well as the last trade price. It also includes information such as daily volume and how much the price has moved over the last day.

 

// Trading pairs

[

  CHANNEL_ID,

  [

    BID,

    BID_SIZE,

    ASK,

    ASK_SIZE,

    DAILY_CHANGE,

    DAILY_CHANGE_PERC,

    LAST_PRICE,

    VOLUME,

    HIGH,

    LOW

  ]

]

// Funding pairs

[

  CHANNEL_ID,

  [

    FRR,

    BID,

    BID_PERIOD,

    BID_SIZE,

    ASK,

    ASK_PERIOD,

    ASK_SIZE,

    DAILY_CHANGE,

    DAILY_CHANGE_PERC,

    LAST_PRICE,

    VOLUME,

    HIGH,

    LOW

  ]

]

 

 

SubscribeTrades

This channel sends a trade message whenever a trade occurs at Bitfinex. It includes all the pertinent details of the trade, such as price, size and time.

 

// on trading pairs (ex. tBTCUSD)

[

  CHANNEL_ID,

  [

    [

      ID,

      MTS,

      AMOUNT,

      PRICE

    ],

    ...

  ]

]

// on funding currencies (ex. fUSD)

[

  CHANNEL_ID,

  [

    [

      ID,

      MTS,

      AMOUNT,

      RATE,

      PERIOD

    ],

    ...

  ]

]

 

SubscribeOrderBook

The Order Books channel allow you to keep track of the state of the Bitfinex order book. It is provided on a price aggregated basis, with customizable precision. After receiving the response, you will receive a snapshot of the book, followed by updates upon any changes to the book.

 

// on trading pairs (ex. tBTCUSD)

[

  CHANNEL_ID,

  [

    [

      PRICE,

      COUNT,

      AMOUNT

    ],

    ...

  ]

]

  

// on funding currencies (ex. fUSD)

[

  CHANNEL_ID,

  [

    [

      RATE,

      PERIOD,

      COUNT,

      AMOUNT

    ],

    ...

  ]

]

 

SubscribeRawOrderBook

These are the most granular books.

 

// on trading pairs (ex. tBTCUSD)

[

  CHANNEL_ID,

  [

    [

      ORDER_ID,

      PRICE,

      AMOUNT

    ],

    ...

  ]

]

  

// on funding currencies (ex. fUSD)

[

  CHANNEL_ID,

  [

    [

      OFFER_ID,

      PERIOD,

      RATE,

      AMOUNT

    ],

    ...

  ]

]

 

SubscribeCandles

Provides a way to access charting candle info. Time Frames:

 

1m: one minute

5m : five minutes

15m : 15 minutes

30m : 30 minutes

1h : one hour

3h : 3 hours

6h : 6 hours

12h : 12 hours

1D : one day

7D : one week

14D : two weeks

1M : one month

 

[

  CHANNEL_ID,

  [

    [

      MTS,

      OPEN,

      CLOSE,

      HIGH,

      LOW,

      VOLUME

    ],

    ...

  ]

]

 

 

 

Subscribe Authenticated Channels

This channel allows you to keep up to date with the status of your account. You can receive updates on your positions, your balances, your orders and your trades.

 

Use Authenticate method in order to Authenticate against server and set required parameters.

Once authenticated, you will receive updates of: Orders, positions, trades, funding offers, funding credits, funding loans, wallets, balance info, margin info, funding info, funding trades...

 

 

You can request UnAuthenticate method if you want log off from server.

 

sgcWebSockets API Bitfinex components

sgcWebSockets API Blockchain components

From sgcWebSockets 4.1.5 BlockChain WebSocket API is supported. Blockchain WebSocket API allows developers to receive Real-Time notifications about new transactions and blocks.

Once WebSocket is open you can subscribe to a channel:

 

  • SubscribeTransactions: Subscribe to notifications for all new bitcoin transactions.

  • UnsubscribeTransactions: UnSubscribe to notifications for all new bitcoin transactions.

 

  • SubscribeAddress: Receive new transactions for a specific bitcoin address.

  • UnSubscribeAddress: Stop receiving new transactions for a specific bitcoin address.

 

Transactions are received OnNewTransaction Event:

 

{

    "op": "utx",

    "x": {

        "lock_time": 0,

        "ver": 1,

        "size": 192,

        "inputs": [

            {

                "sequence": 4294967295,

                "prev_out": {

                    "spent": true,

                    "tx_index": 99005468,

                    "type": 0,

                    "addr": "1BwGf3z7n2fHk6NoVJNkV32qwyAYsMhkWf",

                    "value": 65574000,

                    "n": 0,

                    "script": "76a91477f4c9ee75e449a74c21a4decfb50519cbc245b388ac"

                },

                "script": "483045022100e4ff962c292705f051c2c2fc519fa775a4d8955bce1a3e29884b2785277999ed02200b537ebd22a9f25fbbbcc9113c69c1389400703ef2017d80959ef0f1d685756c012102618e08e0c8fd4c5fe539184a30fe35a2f5fccf7ad62054cad29360d871f8187d"

            }

        ],

        "time": 1440086763,

        "tx_index": 99006637,

        "vin_sz": 1,

        "hash": "0857b9de1884eec314ecf67c040a2657b8e083e1f95e31d0b5ba3d328841fc7f",

        "vout_sz": 1,

        "relayed_by": "127.0.0.1",

        "out": [

            {

                "spent": false,

                "tx_index": 99006637,

                "type": 0,

                "addr": "1A828tTnkVFJfSvLCqF42ohZ51ksS3jJgX",

                "value": 65564000,

                "n": 0,

                "script": "76a914640cfdf7b79d94d1c980133e3587bd6053f091f388ac"

            }

        ]

    }

}

 

  • SubscribeBlocks: Receive notifications when a new block is found. Note: if the chain splits you will receive more than one notification for a specific block height.

  • UnSubscribeBlocks: Stop receiving notifications when a new block is found. Note: if the chain splits you will receive more than one notification for a specific block height.

 

Blocks are received OnNewBlock event:

 

{

    "op": "block",

    "x": {

        "txIndexes": [

            3187871,

            3187868

        ],

        "nTx": 0,

        "totalBTCSent": 0,

        "estimatedBTCSent": 0,

        "reward": 0,

        "size": 0,

        "blockIndex": 190460,

        "prevBlockIndex": 190457,

        "height": 170359,

        "hash": "00000000000006436073c07dfa188a8fa54fefadf571fd774863cda1b884b90f",

        "mrklRoot": "94e51495e0e8a0c3b78dac1220b2f35ceda8799b0a20cfa68601ed28126cfcc2",

        "version": 1,

        "time": 1331301261,

        "bits": 436942092,

        "nonce": 758889471

    }

 

}

 

sgcWebSockets API Blockchain components

From sgcWebSockets 4.1.3 a new WebSocket server is available, it's based on Microsoft HTTP Server API and it's available for Windows 8 and later. It's IOCP (Input Output Completion Ports) and asynchronous (non-blocking) based and can efficiently serve multiple clients (without using one thread per connection like Indy).

Example: if websocket connections are stablished in ws://127.0.0.1/ws url, just set server with these parameters (server requires admin rights to access to HTTP API).

 

oServer := TsgcWebSocketServer_HTTPAPI.Create(nil);

oServer.RegiseredURLs('http://127.0.0.1/ws/');

oServer.Active := True;

 

 

 

When a WebSocket server requires secure connections, you can get an error message like this when a client tries to connect to server:

 

  Error connecting with SSL. error:XXXXXXXX:SSL routines:ssl3_read_bytes:tlsv1 alert protocol version

 

This error means that your client is trying to connect using a TLS version which is not supported by server. To resolver this error you must handle OnSSLAfterCreateHandler of websocket client component and set a newer TLS version. For example: here we are setting TLS 1.2 as protocol version.

 

procedure OnSSLAfterCreateHandler(Sender: TObject; aType: TwsSSLHandler; aSSLHandler: TIdSSLIOHandlerSocketBase);
begin
   TIdServerIOHandlerSSLOpenSSL(aSSLHandler).SSLOptions.Method:= sslvTLSv1_2;
end;

 

Starting from 4.0 sgcWebSockets version, there is a new client component TsgcWebSocketClient_WinHTTP based on WinHTTP API which is not based on indy like TsgcWebSocketClient. All of them, can connect to WebSocket server, but here are some differences between these components, let's see the main features of each one.

  • Yes, requires OpenSSL
  • No, only Blocking mode
  • Yes, Requires Win8.+

 

When a connection is secure, sometimes it's interesting to get certificate info to show user company name for example. To do this, just use OnSSLGetHandler, where you can access to some SSL properties and handle OnVeryPeerEvent, where there is a parameter called Certificate, where you can get certificate info.

 

procedure OnSSLGetHandler(Sender: TObject; aType:
    TwsSSLHandler; var aSSLHandler: TIdSSLIOHandlerSocketBase);
begin
  aSSLHandler := TIdSSLIOHandlerSocketOpenSSL.Create(nil);
  TIdSSLIOHandlerSocketOpenSSL(aSSLHandler).SSLOptions.VerifyMode := [sslvrfPeer];
  TIdSSLIOHandlerSocketOpenSSL(aSSLHandler).SSLOptions.Method := sslvTLSv1;
  TIdSSLIOHandlerSocketOpenSSL(aSSLHandler).SSLOptions.Mode := sslmClient;

  TIdSSLIOHandlerSocketOpenSSL(aSSLHandler).OnVerifyPeer := OnVerifyPeerEvent;
end;


function OnVerifyPeerEvent(Certificate: TIdX509; AOk: Boolean;
    ADepth: Integer): boolean;
begin
  Result := True;

// ... read certificate properties
//  Certificate
end;