Standard library · Network

net/websocket

A two way connection that stays open between browser and server, with rooms for broadcasting.

import net.websocket

A WebSocket is a connection that stays open after one HTTP request, and either side sends a message whenever it likes; for live chat, notifications and games. The server takes connections with Listen and Accept, and a client connects with Dial.

To serve several clients, read each connection in its own thread and use a Hub to send a message to every member of a room.

Types

Server

struct Server
A WebSocket server.
NameTypeDescription
fdi64 = -1The socket descriptor.
portint = 0The port.
net-websocket-Echo.salam
import net.websocket

mut server := websocket.Server {}

func responder():
    mut conn := websocket.Accept(server)
    until websocket.IsOpen(conn):
        m := websocket.Receive(conn)
        if websocket.IsText(m):
            _ := websocket.SendText(conn, "echo: " + m.text)
        else websocket.IsBinary(m):
            _ := websocket.SendBinaryBytes(conn, m.data, m.len)
        else websocket.IsClose(m):
            break
        end
    end
    websocket.Close(conn)
end

func main:
    server = websocket.Listen(0)
    println websocket.Ok(server), websocket.Port(server) > 0
    t := spawn(responder)
    mut c := websocket.Dial("127.0.0.1", websocket.Port(server), "/chat")
    println websocket.IsOpen(c), c.path, c.client
    _ := websocket.SendText(c, "hello")
    println websocket.ReceiveText(c)
    _ := websocket.SendBinary(c, "abc")
    m := websocket.Poll(c, 2000)
    println m.kind == websocket.BINARY, m.len
    _ := websocket.Ping(c, "p")
    m2 := websocket.Poll(c, 2000)
    println websocket.IsPong(m2), m2.kind == websocket.PONG
    m3 := websocket.Poll(c, 50)
    println m3.kind == websocket.TIMEOUT
    websocket.Close(c)
    join(t)
    websocket.CloseServer(server)
    println websocket.NONE, websocket.TEXT, websocket.CLOSE, websocket.PING
end
Outputtrue true true /chat true echo: hello true 3 true true true 0 1 8 9

Conn

struct Conn
One WebSocket connection, on the server or the client side.
NameTypeDescription
fdi64 = -1The socket descriptor.
openbool = falseThe connection is open.
pathstr = ""The path that was asked for, such as /chat.
clientbool = falseThis is the client side; a client sends its frames masked.
bufvoid*The receive buffer.
blenint = 0The length of the data in the buffer.
bcapint = 0The buffer capacity.
securebool = falseIt is encrypted.
tls_idxint = -1The internal TLS index.
hdrstr = ""The handshake headers.
accstr = ""The text of a multi frame message being gathered.
acc_kindint = 0The kind of the multi frame message.
fragmentedbool = falseA multi frame message is on its way.
binvoid*The buffer of a binary message.
binlenint = 0Its length.
bincapint = 0Its capacity.

The example for this item is shown with the ones above: net-websocket-Echo.salam

Message

struct Message
One received message.
NameTypeDescription
kindint = 0The message kind; one of the constants above.
textstr = ""The text of a text message.
datavoid*The data of a binary message.
lenint = 0The length of the data.

The example for this item is shown with the ones above: net-websocket-Echo.salam

RoomMembers

struct RoomMembers
The members of one room.
NameTypeDescription
itemsVectorThe connections.
net-websocket-Hub.salam
import net.websocket

mut server := websocket.Server {}
mut sides := Vector {} as Vector<websocket.Conn>

func acceptor():
    repeat 2:
        sides.push(websocket.Accept(server))
    end
end

func main:
    server = websocket.Listen(0)
    port := websocket.Port(server)
    t := spawn(acceptor)
    mut a := websocket.Dial("127.0.0.1", port, "/room")
    mut b := websocket.DialWith("127.0.0.1", port, "/room", "X-Name: b\r\n")
    join(t)
    mut hub := websocket.NewHub()
    each side in sides:
        websocket.Register(hub, "lobby", side)
    end
    println websocket.RoomSize(hub, "lobby"), hub.rooms.size()
    println websocket.Broadcast(hub, "lobby", "welcome")
    println websocket.ReceiveText(a), websocket.ReceiveText(b)
    println websocket.BroadcastBinary(hub, "lobby", "xy")
    println websocket.Receive(a).len
    websocket.Unregister(hub, "lobby", sides[0])
    println websocket.RoomSize(hub, "lobby")
    websocket.Stop(a)
    websocket.Close(b)
    websocket.CloseServer(server)
end
Output2 1 2 welcome welcome 2 2 1

Hub

struct Hub
A hub: it groups connections into rooms so one message reaches every member of a room; for chat.
NameTypeDescription
roomsHashMapThe rooms and their members.

The example for this item is shown with the ones above: net-websocket-Hub.salam

Constants and variables

NONE

const NONE: i32 = 0
There is no message.

The example for this item is shown with the ones above: net-websocket-Echo.salam

BINARY

const BINARY: i32 = 2
A binary message.

The example for this item is shown with the ones above: net-websocket-Echo.salam

CLOSE

const CLOSE: i32 = 8
The other side closed the connection.

The example for this item is shown with the ones above: net-websocket-Echo.salam

TIMEOUT

const TIMEOUT: i32 = 100
No message arrived within the timeout.

The example for this item is shown with the ones above: net-websocket-Echo.salam

Functions

AcceptKey

func AcceptKey(key: str): str
Builds the handshake accept key from the client key (RFC 6455).
net-websocket-Handshake.salam
import net.websocket
import str

func main:
    println websocket.AcceptKey("dGhlIHNhbXBsZSBub25jZQ==")
    request := websocket.HandshakeRequest("example.com", "/chat", "dGhlIHNhbXBsZSBub25jZQ==")
    println str.Split(request, "\r\n")[0]
    request2 := websocket.HandshakeRequestWith("example.com", "/chat", "dGhlIHNhbXBsZSBub25jZQ==", "Authorization: Bearer x\r\n")
    println str.Contains(request2, "Authorization: Bearer x")
    response := websocket.HandshakeResponse(request)
    println str.Split(response, "\r\n")[0]
    println str.Contains(response, "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=")
end
Outputs3pPLMBiTxaQ9kYGzzhZRbK+xOo= GET /chat HTTP/1.1 true HTTP/1.1 101 Switching Protocols true

HandshakeResponse

func HandshakeResponse(request: str): str
The 101 response of the server to one handshake request.

The example for this item is shown with the ones above: net-websocket-Handshake.salam

HandshakeRequest

func HandshakeRequest(host: str, path: str, key: str): str
The text of the client handshake request.

The example for this item is shown with the ones above: net-websocket-Handshake.salam

HandshakeRequestWith

func HandshakeRequestWith(host: str, path: str, key: str, extra: str): str
A handshake request with extra headers.

The example for this item is shown with the ones above: net-websocket-Handshake.salam

Listen

func Listen(port: int): Server
A WebSocket server on the given port; zero means a free port.

The example for this item is shown with the ones above: net-websocket-Echo.salam

Ok

func Ok(srv: Server): bool
The server was created properly.

The example for this item is shown with the ones above: net-websocket-Echo.salam

Port

func Port(srv: Server): int
The server port.

The example for this item is shown with the ones above: net-websocket-Echo.salam

CloseServer

func CloseServer(srv: Server)
Closes the server.

The example for this item is shown with the ones above: net-websocket-Echo.salam

Accept

func Accept(srv: Server): Conn
Accepts the next client and completes the WebSocket handshake.

The example for this item is shown with the ones above: net-websocket-Echo.salam

LoadWSSConfig

func LoadWSSConfig(cert_file: str, key_file: str)
Loads the TLS certificate and key for accepting secure connections.
net-websocket-WSS.salam
import net.websocket

func main:
    mut a := websocket.DialWSS("echo.example.com", 443, "/")
    mut b := websocket.DialWSSWith("echo.example.com", 443, "/", "Origin: https://salamlang.ir\r\n")
    mut c := websocket.DialWSSUnverified("localhost", 8443, "/", "")
    println websocket.IsOpen(a), websocket.IsOpen(b), websocket.IsOpen(c)
    websocket.LoadWSSConfig("cert.pem", "key.pem")
    s := websocket.Listen(8443)
    mut conn := websocket.AcceptWSS(s)
    _ := websocket.SendText(conn, "hello")
    websocket.Close(conn)
end

AcceptWSS

func AcceptWSS(srv: Server): Conn
Accepts a secure (wss) connection.

The example for this item is shown with the ones above: net-websocket-WSS.salam

Dial

func Dial(host: str, port: int, path: str): Conn
Connects to a WebSocket server.

The example for this item is shown with the ones above: net-websocket-Echo.salam

DialWith

func DialWith(host: str, port: int, path: str, extra: str): Conn
The same, with extra headers; every header has to end with \r\n.

The example for this item is shown with the ones above: net-websocket-Hub.salam

DialWSS

func DialWSS(host: str, port: int, path: str): Conn
A secure (wss) connection.

The example for this item is shown with the ones above: net-websocket-WSS.salam

DialWSSWith

func DialWSSWith(host: str, port: int, path: str, extra: str): Conn
A secure connection with extra headers.

The example for this item is shown with the ones above: net-websocket-WSS.salam

DialWSSUnverified

func DialWSSUnverified(host: str, port: int, path: str, extra: str): Conn
A secure connection without verifying the certificate; for testing with a self signed certificate only.

The example for this item is shown with the ones above: net-websocket-WSS.salam

IsOpen

func IsOpen(c &: Conn): bool
The connection is open.

The example for this item is shown with the ones above: net-websocket-Echo.salam

Receive

func Receive(c &: Conn): Message
Takes the next message, waiting for it. It answers pings by itself.

The example for this item is shown with the ones above: net-websocket-Echo.salam

Poll

func Poll(c &: Conn, timeout_ms: int): Message
The same, up to the timeout; when nothing arrives the message kind is TIMEOUT.

The example for this item is shown with the ones above: net-websocket-Echo.salam

ReceiveText

func ReceiveText(c &: Conn): str
The text of the next text message.

The example for this item is shown with the ones above: net-websocket-Echo.salam

IsText

func IsText(m: Message): bool
The message is a text one.

The example for this item is shown with the ones above: net-websocket-Echo.salam

IsBinary

func IsBinary(m: Message): bool
The message is a binary one.

The example for this item is shown with the ones above: net-websocket-Echo.salam

IsClose

func IsClose(m: Message): bool
The message is a close.

The example for this item is shown with the ones above: net-websocket-Echo.salam

IsPong

func IsPong(m: Message): bool
The message is a ping reply.

The example for this item is shown with the ones above: net-websocket-Echo.salam

SendText

func SendText(c &: Conn, msg: str): int
Sends a text message.

The example for this item is shown with the ones above: net-websocket-Echo.salam

SendBinary

func SendBinary(c &: Conn, data: str): int
Sends a binary message from the bytes of a string.

The example for this item is shown with the ones above: net-websocket-Echo.salam

SendBinaryBytes

func SendBinaryBytes(c &: Conn, ptr: void*, n: int): int
Sends a binary message from memory.

The example for this item is shown with the ones above: net-websocket-Echo.salam

Ping

func Ping(c &: Conn, data: str): int
Sends a ping; the other side should send a pong back.

The example for this item is shown with the ones above: net-websocket-Echo.salam

Close

func Close(c &: Conn)
Sends the close frame and closes the connection.

The example for this item is shown with the ones above: net-websocket-Echo.salam

Stop

func Stop(c &: Conn)
Drops the connection without a close frame.

The example for this item is shown with the ones above: net-websocket-Hub.salam

NewHub

func NewHub(): Hub
An empty hub.

The example for this item is shown with the ones above: net-websocket-Hub.salam

Register

func Register(h &: Hub, room: str, c: Conn)
Adds a connection to a room.

The example for this item is shown with the ones above: net-websocket-Hub.salam

Unregister

func Unregister(h &: Hub, room: str, c: Conn)
Takes a connection out of a room.

The example for this item is shown with the ones above: net-websocket-Hub.salam

RoomSize

func RoomSize(h: Hub, room: str): int
The number of members in a room.

The example for this item is shown with the ones above: net-websocket-Hub.salam

Broadcast

func Broadcast(h &: Hub, room: str, msg: str): int
Sends a text message to every member of a room and returns how many got it.

The example for this item is shown with the ones above: net-websocket-Hub.salam

BroadcastBinary

func BroadcastBinary(h &: Hub, room: str, data: str): int
Sends a binary message to every member.

The example for this item is shown with the ones above: net-websocket-Hub.salam