import ballerina/io;
import ballerina/log;
import ballerina/http;
endpoint http:Listener ep {
    host:"0.0.0.0",
    port:9090
};@http:WebSocketServiceConfig {
    basePath:"/basic/ws",
    subProtocols:["xml", "json"],
    idleTimeoutInSeconds:120
}
service<http:WebSocketService> SimpleSecureServer bind ep {    string ping = "ping";
    blob pingData = ping.toBlob("UTF-8");
    onOpen (endpoint conn) {
        io:println("\nNew client connected");
        io:println("Connection ID: " + conn.id);
        io:println("Negotiated Sub protocol: " + conn.negotiatedSubProtocol);
        io:println("Is connection open: " + conn.isOpen);
        io:println("Is connection secured: " + conn.isSecure);
        io:println("Upgrade headers -> ");
    }
    onText (endpoint conn, string text, boolean more) {
        io:println("\ntext message: " + text + " & more fragments: " + more);        if (text == "ping") {
            io:println("Pinging...");
            conn -> ping(pingData) but {error e => log:printErrorCause("Error sending ping", e)};
        } else if (text == "closeMe") {
            conn -> close(1001, "You asked me to close the connection")
                         but {error e => log:printErrorCause("Error occured when closing the connection", e)};
        } else {
            conn -> pushText("You said: " + text) but {error e => log:printErrorCause("Error occured when sending text", e)};
        }
    }
    onBinary (endpoint conn, blob b) {
        io:println("\nNew binary message received");
        io:println("UTF-8 decoded binary message: " + b.toString("UTF-8"));
        conn -> pushBinary(b) but {error e => log:printErrorCause("Error occured when sending binary", e)};
    }
    onPing (endpoint conn, blob data) {
        conn -> pong(data) but {error e => log:printErrorCause("Error occured when closing the connection", e)};
    }
    onPong (endpoint conn, blob data) {
        io:println("Pong received");
    }
    onIdleTimeout (endpoint conn) {
        io:println("\nReached idle timeout");
        io:println("Closing connection " + conn.id);
        conn -> close(1001, "Connection timeout") but {error e => log:printErrorCause("Error occured when closing the connection", e)};
    }
    onClose (endpoint conn, int statusCode, string reason) {
        io:println("\nClient left with status code " + statusCode + " because " + reason);
    }
}

WebSocket Basic Sample

This program explains the basic functions of WebSocket server endpoint

import ballerina/io;
import ballerina/log;
import ballerina/http;
endpoint http:Listener ep {
    host:"0.0.0.0",
    port:9090
};

This example gives you the basic idea of WebSocket endpoint.

@http:WebSocketServiceConfig {
    basePath:"/basic/ws",
    subProtocols:["xml", "json"],
    idleTimeoutInSeconds:120
}
service<http:WebSocketService> SimpleSecureServer bind ep {
    string ping = "ping";
    blob pingData = ping.toBlob("UTF-8");
    onOpen (endpoint conn) {
        io:println("\nNew client connected");
        io:println("Connection ID: " + conn.id);
        io:println("Negotiated Sub protocol: " + conn.negotiatedSubProtocol);
        io:println("Is connection open: " + conn.isOpen);
        io:println("Is connection secured: " + conn.isSecure);
        io:println("Upgrade headers -> ");
    }

This resource is triggered after a successful client connection.

    onText (endpoint conn, string text, boolean more) {
        io:println("\ntext message: " + text + " & more fragments: " + more);

This resource is triggered when a new text frame is received from a client.

        if (text == "ping") {
            io:println("Pinging...");
            conn -> ping(pingData) but {error e => log:printErrorCause("Error sending ping", e)};
        } else if (text == "closeMe") {
            conn -> close(1001, "You asked me to close the connection")
                         but {error e => log:printErrorCause("Error occured when closing the connection", e)};
        } else {
            conn -> pushText("You said: " + text) but {error e => log:printErrorCause("Error occured when sending text", e)};
        }
    }
    onBinary (endpoint conn, blob b) {
        io:println("\nNew binary message received");
        io:println("UTF-8 decoded binary message: " + b.toString("UTF-8"));
        conn -> pushBinary(b) but {error e => log:printErrorCause("Error occured when sending binary", e)};
    }

This resource is triggered when a new binary frame is received from a client.

    onPing (endpoint conn, blob data) {
        conn -> pong(data) but {error e => log:printErrorCause("Error occured when closing the connection", e)};
    }

This resource is triggered when a ping message is received from the client. If this resource is not implemented then pong message will be sent automatically to the connected endpoint when a ping is received.

    onPong (endpoint conn, blob data) {
        io:println("Pong received");
    }

This resource is triggered when a pong message is received

    onIdleTimeout (endpoint conn) {

This resource is triggered when a particular client reaches it’s idle timeout defined in the ws:configuration annotation.

        io:println("\nReached idle timeout");
        io:println("Closing connection " + conn.id);
        conn -> close(1001, "Connection timeout") but {error e => log:printErrorCause("Error occured when closing the connection", e)};
    }

This resource will be triggered after 180 seconds if there is no activity in a given channel.

    onClose (endpoint conn, int statusCode, string reason) {
        io:println("\nClient left with status code " + statusCode + " because " + reason);
    }
}

This resource is triggered when a client connection is closed from the client side.

$ ballerina run websocket-basic-sample.bal

To run the program, put the code in websocket-basic-functions.bal and use ballerina run websocket-basic-sample.bal command.

$ var ws = new WebSocket("ws://localhost:9090/basic/ws", "xml", "my-protocol");

To check the sample,use Chrome or Firefox javascript console and run the below commands
change “xml” to another sub protocol to observe the behavior of WebSocket server.

$ ws.onmessage = function(frame) {console.log(frame.data)};
$ ws.onclose = function(frame) {console.log(frame)};
$ ws.send("hello world");

To send messages

$ ws.send("ping");

Use more advance client to check the ping pong since browser client does not have capability to send pings. But to check the the behavior when server sends a ping message to the browser client use the following command

$ ws.close(1000, "I want to go");

To close the connection

$ ws.send("closeMe");

To close connection from server side

To check the connection closure due to connection timeout wait for 120 seconds or change the timeout in configuration annotation