Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Examples/simple_chat_room.alusus
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,12 @@ module WebSocketChat {

func onWebSocketData(
conn: ptr[Http.Connection],
opcode: Int,
bits: Int,
data: CharsPtr,
len: ArchWord,
_: ptr[Void]
): Int {
if (opcode & 1) == 0 return 1;
if (bits & 0x0F) != 1 return 1; // Ignore non-text frames

def i: Int = 0;
while i < clientCount and clients(i).conn != conn {
Expand Down
4 changes: 2 additions & 2 deletions Examples/websocket_server.alusus
Original file line number Diff line number Diff line change
Expand Up @@ -133,12 +133,12 @@ module WebSocketExample {

func onWebSocketData(
connection: ptr[Http.Connection],
opcode: Int,
bits: Int,
data: CharsPtr,
dataLen: ArchWord,
userData: ptr[Void]
): Int {
if ((opcode & 0x1) == 0) {
if ((bits & 0x0F) != 1) { // Ignore non-text frames
return 1;
}

Expand Down
4 changes: 2 additions & 2 deletions Examples/مثال_خادم_ويب_سوكت.أسس
Original file line number Diff line number Diff line change
Expand Up @@ -130,12 +130,12 @@

دالة عند_بيانات_ويب_سوكت(
اتصال: مؤشر[بـننت.اتـصال]،
رمز_العملية: صـحيح،
بتات: صـحيح،
بيانات: مـؤشر_محارف،
طول_البيانات: طـبيعي_متكيف،
بيانات_المستخدم: مؤشر[فـراغ]
): صـحيح {
إذا (رمز_العملية & 1) == 0 ارجع 1؛
إذا (بتات & 0x0F) != 1 ارجع 1؛ // تجاهل الإطارات غير النصية

طـرفية.اطبع("تم استلام رسالة WebSocket: ")؛
طـرفية.اطبع(بيانات، طول_البيانات)؛
Expand Down
4 changes: 2 additions & 2 deletions Examples/مثال_غرفة_دردشة.أسس
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,12 @@

دالة عند_بيانات_ويب_سوكت(
اتصال: مؤشر[بـننت.اتـصال]،
رمز_العملية: صـحيح،
بتات: صـحيح،
بيانات: مـؤشر_محارف،
طول_البيانات: طـبيعي_متكيف،
_: مؤشر[فـراغ]
): صـحيح {
إذا (رمز_العملية & 1) == 0 أرجع 1؛
إذا (بتات & 0x0F) != 1 أرجع 1؛ // تجاهل الإطارات غير النصية

عرف ت: صـحيح = 0؛
بينما ت < عدد_العملاء و العملاء(ت).اتصال != اتصال {
Expand Down
2 changes: 1 addition & 1 deletion Http.alusus
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ module Http {
def WebSocketConnectCallback: alias ptr[func (connection: ptr[Connection], userData: ptr[Void]): Int];
def WebSocketReadyCallback: alias ptr[func (connection: ptr[Connection], userData: ptr[Void]): Void];
def WebSocketDataCallback: alias ptr[func (
connection: ptr[Connection], opcode: Int, data: CharsPtr, dataLen: ArchWord, userData: ptr[Void]
connection: ptr[Connection], bits: Int, data: CharsPtr, dataLen: ArchWord, userData: ptr[Void]
): Int];
def WebSocketCloseCallback: alias ptr[func (connection: ptr[Connection], userData: ptr[Void]): Void];

Expand Down
46 changes: 36 additions & 10 deletions websocket_documentation.ar.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ def WebSocketReadyCallback: alias ptr[func (connection: ptr[Connection], userDat
### مـنادى_بيانات_ويب_سوكت (WebSocketDataCallback)

```
عرف مـنادى_بيانات_ويب_سوكت: لقب مؤشر[دالة (اتصال: مؤشر[بـننت.اتـصال], رمز_العملية: صـحيح, بيانات: مـؤشر_محارف, طول_البيانات: صـحيح, بيانات_المستخدم: مؤشر[فـراغ]): صـحيح];
عرف مـنادى_بيانات_ويب_سوكت: لقب مؤشر[دالة (اتصال: مؤشر[بـننت.اتـصال], بتات: صـحيح, بيانات: مـؤشر_محارف, طول_البيانات: صـحيح, بيانات_المستخدم: مؤشر[فـراغ]): صـحيح];
```

<div dir=ltr>
Expand All @@ -66,12 +66,38 @@ def WebSocketDataCallback: alias ptr[func (connection: ptr[Connection], bits: In

</div>

يتم استدعاؤها عند استلام البيانات من العميل. يشير المعامل `رمز_العملية` إلى نوع الإطار:
- `1`: إطار نصي
- `2`: إطار ثنائي
- `8`: إطار إغلاق
- `9`: إطار Ping
- `10`: إطار Pong
يتم استدعاؤها عند استلام البيانات من العميل. المعامل `بتات` هو البايت الأول من رأس إطار ويب سوكت.

وفق **RFC 6455**، يحتوي هذا البايت على:

- البت 7 (`0x80`): نهائي (FIN).
- البتات 4-6 (`0x70`): بتات محجوزة، عادةً `0` ما لم تُستخدم امتدادات.
- البتات 0-3 (`0x0F`): رمز العملية (opcode).

استخرج كل جزء قبل التحقق منه:

```
عرف رمز_العملية: صـحيح = بتات & 0x0F؛
عرف نهائي: ثـنائي = (بتات & 0x80) != 0؛
```

<div dir=ltr>

```alusus
def opcode: Int = bits & 0x0F;
def fin: Bool = (bits & 0x80) != 0;
```

</div>

* قيم `رمز_العملية`:
- `1`: إطار نصي
- `2`: إطار ثنائي
- `8`: إطار إغلاق
- `9`: إطار Ping
- `10`: إطار Pong

* تكون `نهائي` قيمتها `true` عندما تكون هذه هي الإطار الأخير (أو الوحيد) من الرسالة.

### مـنادى_إغلاق_ويب_سوكت (WebSocketCloseCallback)

Expand Down Expand Up @@ -294,12 +320,12 @@ func closeWebSocket(connection: ptr[Connection]): Int;

دالة عند_بيانات_ويب_سوكت(
اتصال: مؤشر[بـننت.اتـصال]،
رمز_العملية: صـحيح،
بتات: صـحيح،
بيانات: مـؤشر_محارف،
طول_البيانات: صـحيح،
بيانات_المستخدم: مؤشر[فـراغ]
): صـحيح {
إذا رمز_العملية == 1 { // إطار نصي
إذا (بتات & 0x0F) == 1 { // إطار نصي
طـرفية.اطبع("تم الاستلام: ")؛
طـرفية.اطبع(بيانات، طول_البيانات)؛
طـرفية.اطبع("\ج")؛
Expand Down Expand Up @@ -370,7 +396,7 @@ module WebSocketExample {
};

func onData(connection: ptr[Http.Connection], bits: Int, data: CharsPtr, dataLen: Int, userData: ptr[Void]): Int {
if bits == 1 { // إطار نصي
if (bits & 0x0F) == 1 { // إطار نصي
Console.print("تم الاستلام: ");
Console.print(data, dataLen);
Console.print("\n");
Expand Down
39 changes: 32 additions & 7 deletions websocket_documentation.en.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,29 +19,48 @@ The Alusus HTTP module now includes comprehensive WebSocket support, built on to
## WebSocket Callback Types

### WebSocketConnectCallback

```alusus
def WebSocketConnectCallback: alias ptr[func (connection: ptr[Connection], userData: ptr[Void]): Int];
```
Called when a new WebSocket connection is established. Return 0 to accept the connection, non-zero to reject.

### WebSocketReadyCallback

```alusus
def WebSocketReadyCallback: alias ptr[func (connection: ptr[Connection], userData: ptr[Void]): Void];
```
Called when the WebSocket connection is ready for communication.

### WebSocketDataCallback

```alusus
def WebSocketDataCallback: alias ptr[func (connection: ptr[Connection], bits: Int, data: CharsPtr, dataLen: Int, userData: ptr[Void]): Int];
```
Called when data is received from the client. The `bits` parameter indicates the frame type:
- `1`: Text frame
- `2`: Binary frame
- `8`: Close frame
- `9`: Ping frame
- `10`: Pong frame
Called when data is received from the client. The `bits` parameter is the raw first byte of the WebSocket frame header, not the frame type by itself. Per RFC 6455, that byte packs at:

- bit 7 (`0x80`): The FIN flag.
- bits 4-6 (`0x70`): Reserved bits, usually `0` unless extensions are used.
- bits 0-3 (`0x0F`): The opcode.

Extract each piece before checking it:

```alusus
def opcode: Int = bits & 0x0F;
def fin: Bool = (bits & 0x80) != 0;
```

* `opcode` values:
- `1`: Text frame
- `2`: Binary frame
- `8`: Close frame
- `9`: Ping frame
- `10`: Pong frame

* `fin` is `true` when this is the final (or only) fragment of the message.

### WebSocketCloseCallback

```alusus
def WebSocketCloseCallback: alias ptr[func (connection: ptr[Connection], userData: ptr[Void]): Void];
```
Expand All @@ -50,6 +69,7 @@ Called when a WebSocket connection is closed.
## Core Functions

### setWebSocketHandler

```alusus
func setWebSocketHandler(
context: ptr[Context],
Expand All @@ -73,6 +93,7 @@ Registers WebSocket handlers for a specific URI path.
- `userData`: Optional user data passed to callbacks

### setWebSocketHandlerWithSubprotocols

```alusus
func setWebSocketHandlerWithSubprotocols(
context: ptr[Context],
Expand All @@ -90,6 +111,7 @@ Same as `setWebSocketHandler` but with support for WebSocket subprotocols.
## Message Sending Functions

### writeToWebSocket

```alusus
func writeToWebSocket(connection: ptr[Connection], opcode: Int, data: CharsPtr, dataLen: Int): Int;
```
Expand All @@ -103,18 +125,21 @@ Send raw WebSocket frame with specified opcode.
- `10`: Pong frame

### writeTextToWebSocket

```alusus
func writeTextToWebSocket(connection: ptr[Connection], data: CharsPtr, dataLen: Int): Int;
```
Send text message to WebSocket client.

### writeBinaryToWebSocket

```alusus
func writeBinaryToWebSocket(connection: ptr[Connection], data: CharsPtr, dataLen: Int): Int;
```
Send binary message to WebSocket client.

### closeWebSocket

```alusus
func closeWebSocket(connection: ptr[Connection]): Int;
```
Expand Down Expand Up @@ -172,7 +197,7 @@ module WebSocketExample {
};

func onData(connection: ptr[Http.Connection], bits: Int, data: CharsPtr, dataLen: Int, userData: ptr[Void]): Int {
if bits == 1 { // Text frame
if (bits & 0x0F) == 1 { // Text frame
Console.print("Received: ");
Console.print(data, dataLen);
Console.print("\n");
Expand Down