diff --git a/Examples/simple_chat_room.alusus b/Examples/simple_chat_room.alusus new file mode 100644 index 0000000..359ace5 --- /dev/null +++ b/Examples/simple_chat_room.alusus @@ -0,0 +1,141 @@ +import "Srl/Console.alusus"; +import "Srl/String.alusus"; +import "Apm.alusus"; +Apm.importFile("Alusus/Http"); + +module WebSocketChat { + use Srl; + + class Client { + def conn: ptr[Http.Connection]; + }; + + def clients: array[Client, 32]; + def clientCount: Int = 0; + + + + func onWebSocketConnect(conn: ptr[Http.Connection], _: ptr[Void]): Int { + clients(clientCount).conn = conn; + clientCount += 1; + + Console.print("Client connected\n"); + return 0; + }; + + func onWebSocketReady(conn: ptr[Http.Connection], _: ptr[Void]): Void { + Http.writeWebSocketText( + conn, + "Connected to broadcast chat", + 27 + ); + }; + + func onWebSocketData( + conn: ptr[Http.Connection], + bits: Int, + data: CharsPtr, + len: Int, + _: ptr[Void] + ): Int { + if ((bits & 1) == 0) return 1; + + def i: Int = 0; + def full_data : String =""; + while i < clientCount { + if (clients(i).conn == conn) + full_data = full_data + String.format("user : %i ",i+1) ; + i +=1; + } + full_data.append(data); + i=0; + len = full_data.getLength(); + while i < clientCount { + Http.writeWebSocketText( + clients(i).conn, + full_data.buf, + len + ); + i += 1; + } + + return 1; + }; + + func onWebSocketClose(conn: ptr[Http.Connection], _: ptr[Void]): Void { + def i: Int = 0; + while i < clientCount { + if (clients(i).conn == conn) { + + def j: Int = i; + while j < clientCount - 1 { + clients(j).conn = clients(j + 1).conn; + j += 1; + } + + clientCount -= 1; + break; + } + i += 1; + } + + Console.print("Client disconnected\n"); + }; + + + + func handleHttpRequest(conn: ptr[Http.Connection]): Int { + def req : ptr[Http.RequestInfo] = Http.getRequestInfo(conn); + + if String.isEqual(req~cnt.localUri, "/websocket") return 0; + + if String.isEqual(req~cnt.localUri, "/") { + def html: CharsPtr = + "" + "

Broadcast Chat

" + "" + "" + "
" + ""; + + Http.print(conn, "HTTP/1.1 200 OK\r\n"); + Http.print(conn, "Content-Length: %d\r\n\r\n", + String.getLength(html)); + Http.print(conn, html); + return 1; + } + + return 1; + }; + + func start() { + def ctx : ptr[Http.Context] = Http.startServer(handleHttpRequest~ptr, { + "listening_ports", "8080" + }); + + Http.setWebSocketHandler( + ctx, + "/websocket", + onWebSocketConnect~ptr, + onWebSocketReady~ptr, + onWebSocketData~ptr, + onWebSocketClose~ptr + ); + + Console.print("Server running on 8080\n"); + Console.getChar(); + Http.stopServer(ctx); + }; +}; + +WebSocketChat.start(); diff --git a/Examples/websocket_server.alusus b/Examples/websocket_server.alusus index 49dbf76..7224eb4 100644 --- a/Examples/websocket_server.alusus +++ b/Examples/websocket_server.alusus @@ -8,11 +8,12 @@ module WebSocketExample { use Srl; func start() { - def context: ptr[Http.Context] = Http.startServer(handleHttpRequest~ptr, { - "document_root", ".", // Set document root - "listening_ports", "8080", // Listen on port 8080 - "websocket_timeout_ms", "3600000" - }); + def context: ptr[Http.Context] = + Http.startServer(handleHttpRequest~ptr, { + "document_root", ".", + "listening_ports", "8080", + "websocket_timeout_ms", "3600000" + }); Http.setWebSocketHandler( context, @@ -23,110 +24,136 @@ module WebSocketExample { onWebSocketClose~ptr ); - Console.print("Server with WebSocket support listening on port 8080\n"); - Console.print("HTTP: http://localhost:8080/\n"); - Console.print("WebSocket: ws://localhost:8080/websocket\n"); - Console.print("Press enter to close server."); + Console.print("Server running on port 8080\n"); + Console.print("HTTP : http://localhost:8080/\n"); + Console.print("WS : ws://localhost:8080/websocket\n"); + Console.print("Press ENTER to stop server...\n"); Console.getChar(); + Http.stopServer(context); - Console.print("Server closed.\nPress enter to exit."); + Console.print("Server stopped. Press ENTER to exit.\n"); Console.getChar(); }; func handleHttpRequest(connection: ptr[Http.Connection]): Int { - def requestInfo: ptr[Http.RequestInfo] = Http.getRequestInfo(connection); - - if String.isEqual(requestInfo~cnt.localUri, "/") { - def htmlContent: CharsPtr = - "\n" - "\n" - "WebSocket Test\n" - "\n" - "

WebSocket Test Page

\n" - "
\n" - " \n" - " \n" - " \n" - "\n" - ""; - - Http.print(connection, "HTTP/1.1 200 OK\r\n"); - Http.print(connection, "Content-Type: text/html\r\n"); - Http.print(connection, "Content-Length: %d\r\n\r\n", String.getLength(htmlContent)); - Http.print(connection, htmlContent); - } else { - Http.print(connection, "HTTP/1.1 404 Not Found\r\n"); - Http.print(connection, "Content-Type: text/plain\r\n"); - Http.print(connection, "Content-Length: 9\r\n\r\n"); - Http.print(connection, "Not Found"); - } + def req: ptr[Http.RequestInfo] = Http.getRequestInfo(connection); + + + if String.isEqual(req~cnt.localUri, "/websocket") { + return 0; + } + + + if String.isEqual(req~cnt.localUri, "/") { + + def page: CharsPtr = + "\n" + "\n" + "WebSocket Test\n" + "\n" + "

WebSocket Test

\n" + "
\n" + "\n" + "\n" + "\n" + "\n" + ""; + + Http.print(connection, "HTTP/1.1 200 OK\r\n"); + Http.print(connection, "Content-Type: text/html\r\n"); + Http.print( + connection, + "Content-Length: %d\r\n\r\n", + String.getLength(page) + ); + Http.print(connection, page); return 1; - }; + } + + + Http.print(connection, "HTTP/1.1 404 Not Found\r\n"); + Http.print(connection, "Content-Length: 9\r\n\r\nNot Found"); - func onWebSocketConnect(connection: ptr[Http.Connection], userData: ptr[Void]): Int { + return 1; +}; + + func onWebSocketConnect( + connection: ptr[Http.Connection], + userData: ptr[Void] + ): Int { Console.print("WebSocket client connected\n"); return 0; }; - func onWebSocketReady(connection: ptr[Http.Connection], userData: ptr[Void]): Void { - Console.print("WebSocket connection ready\n"); - Http.writeWebSocketText(connection, "Welcome to the WebSocket server!", 33); - }; + func onWebSocketReady( + connection: ptr[Http.Connection], + userData: ptr[Void] + ): Void { + Console.print("WebSocket ready\n"); - func onWebSocketData(connection: ptr[Http.Connection], bits: Int, data: CharsPtr, dataLen: Int, userData: ptr[Void]): Int { - Console.print("Received WebSocket message: "); - Console.print(data, dataLen); - Console.print("\n"); + def msg: CharsPtr = "Welcome to the WebSocket server!"; + Http.writeWebSocketText( + connection, + msg, + String.getLength(msg) + ); + }; - def response: array[Char, 256]; - String.assign(response~ptr, "Echo: "); - String.concat(response~ptr, data, dataLen); + func onWebSocketData( + connection: ptr[Http.Connection], + bits: Int, + data: CharsPtr, + dataLen: Int, + userData: ptr[Void] +): Int { - Http.writeWebSocketText(connection, response~ptr, String.getLength(response~ptr)); + if ((bits & 0x1) == 0) { return 1; - }; + } + + Console.print("Received: "); + Console.print(data, dataLen); + Console.print("\n"); + + def buffer: array[Char, 512]; + String.assign(buffer~ptr, "Echo: "); + String.concat(buffer~ptr, data, dataLen); + + Http.writeWebSocketText( + connection, + buffer~ptr, + String.getLength(buffer~ptr) + ); + + return 1; +}; - func onWebSocketClose(connection: ptr[Http.Connection], userData: ptr[Void]): Void { + func onWebSocketClose( + connection: ptr[Http.Connection], + userData: ptr[Void] + ): Void { Console.print("WebSocket client disconnected\n"); }; }; -WebSocketExample.start(); \ No newline at end of file +WebSocketExample.start(); diff --git a/Http.alusus b/Http.alusus index eac9c61..8cff4c0 100644 --- a/Http.alusus +++ b/Http.alusus @@ -15,7 +15,7 @@ module Http { } class Context{ - def stopFlag: int; // Should we stop event loop + }; def RequestCallback: alias ptr[func (connection: ptr[Connection]): Int];