Skip to content

Commit

Permalink
Push all source files
Browse files Browse the repository at this point in the history
  • Loading branch information
sturmgeisty committed Apr 13, 2024
0 parents commit fb99183
Show file tree
Hide file tree
Showing 18 changed files with 2,466 additions and 0 deletions.
674 changes: 674 additions & 0 deletions LICENSE

Large diffs are not rendered by default.

86 changes: 86 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@

# RoSocket

Roblox websocket support made possible thru a server and a roblox module.
Http requests must be enabled for this to work. To enable them, make sure your game is published, then head over to the topbar > **FILE** > **Game Settings** > **Security** > _Allow HTTP Requests_. If you want to self-host the server source on a server of your choice, then after build is successfull (or just manually grab the RBXM), find the **"Reader"** module which is a descendant of RoSocket module, and change "SOCKET_SERVER_URL" to the URL of your server.

## Installation

Wally:

```toml
[dependencies]
Socket = "RoSocket/rosocket@1.0.0"
```

Roblox Model:
Click [here](https://create.roblox.com/store/asset/17132752732/RoSocket) or
Download from [Releases](https://github.com/RoSocket/rosocket/releases)


## API

**Functions:**

```Lua
function RoSocket.Connect(socket: string): () -> ()
```

**Socket:**
```Lua
function socket.Disconnect(...: any): (boolean) -> (boolean)
function socket.Send(msg: string?): (boolean) -> (boolean)
RBXScriptSignal socket.OnDisconnect()
RBXScriptSignal socket.OnMessageReceived(msg: string?)
RBXScriptSignal socket.OnErrorReceived(err: string?)
string socket.UUID -- Universal Unique Identifier
string socket.Socket -- Socket link (e.g: wss://hello.com)
string socket.binaryType -- buffer (doesn't modify way of requests)
string socket.readyState -- OPEN/CLOSED
object socket.Messages
object socket.Errors
```

**Keys:**

```Lua
Version: "1.0.0"
```

## Simple Example

```Lua
local RoSocket = require(script.RoSocket)

-- Http service requests should be enabled for this to work, and a correct server should be set in the Reader module.
local Success, Socket = pcall(RoSocket.Connect, "wss://echo.websocket.org")
if Success ~= false then
print(`Socket's Universal Unique Identifier: {Socket.UUID}`) -- ...
print(`Socket's URL is: {Socket.Socket}`) -- wss://echo.websocket.org
print(`Socket's state is: {Socket.readyState}`) -- OPEN
print(`Socket's binary Type is: {Socket.binaryType}`) -- buffer (read-only)
print(`Socket's amount of messages: {#Socket.Messages}`)
print(`Socket's amount of errors: {#Socket.Errors}`)
Socket.OnDisconnect:Connect(function(...: any?)
warn(`Socket {Socket.Socket} was disconnected!`)
end)
Socket.OnMessageReceived:Connect(function(msg: string?)
warn(`Message from {Socket.Socket}: {tostring(msg)}`)
end)
Socket.OnErrorReceived:Connect(function(err: string?)
error(`Error from {Socket.Socket}: {tostring(err)}`)
end)
local Suc1 = Socket.Send("Hello World!") -- First message
print(`Socket first message {Suc1 == true and "has been sent successfully!" or "has failed to send!"}`)
local Suc2 = Socket.Send("Hello World!") -- Repeated message
print(`Socket repeated message {Suc2 == true and "has been sent successfully!" or "has failed to send!"}`)
local Suc3 = Socket.Send("Goodbye World!") -- Second message
print(`Socket second message {Suc3 == true and "has been sent successfully!" or "has failed to send!"}`)
Socket.Disconnect()
Socket.Send("Hello World!") -- Throws a warning in the output saying you can't send messages to a disconnected socket
print(`Socket's state is: {Socket.readyState}`) -- CLOSED
print(`Socket's amount of messages: {#Socket.Messages}`)
else
warn("Failed to connect to websocket!")
end
```
10 changes: 10 additions & 0 deletions aftman.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# This file lists tools managed by Aftman, a cross-platform toolchain manager.
# For more information, see https://github.com/LPGhatguy/aftman

# To add a new tool, add an entry to this table.
[tools]
rojo = "rojo-rbx/rojo@7.3.0"
run-in-roblox = "rojo-rbx/run-in-roblox@0.3.0"
wally = "upliftgames/wally@0.3.2"
selene = "Kampfkarren/selene@0.25.0"
stylua = "JohnnyMorganz/stylua@0.18.1"
6 changes: 6 additions & 0 deletions default.project.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"name": "RoSocket",
"tree": {
"$path": "src"
}
}
15 changes: 15 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"name": "RoSocket/rosocket",
"version": "1.0.0",
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/RoSocket/rosocket.git"
},
"contributors": [
"sturmgeisty"
],
"bugs": {
"url": "https://github.com/RoSocket/rosocket/issues"
}
}
1 change: 1 addition & 0 deletions selene.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
std = "roblox"
137 changes: 137 additions & 0 deletions server/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
const express = require('express');
const WebSocket = require('ws');

const app = express();
app.use(express.json());
const port = 6214;

const connections = {};

function isValidWebSocketURL(url) {
return url.startsWith("wss://");
}

function generateUUID() {
return Math.random().toString(36).substring(2, 10);
} // TODO: remove this and use uuid npm package

function handleWebSocketConnection(UUID, socket) {
socket.on('message', (message) => {
if (connections[UUID]) {
const messageString = message.toString();
connections[UUID].messages.push({
id: generateUUID(),
message: messageString,
step: connections[UUID].messages.length + 1
});
}
});
socket.on('error', (error) => {
console.error(`WebSocket error for UUID: ${UUID}`, error);
if (connections[UUID]) {
connections[UUID].errors.push({
id: generateUUID(),
message: error,
step: connections[UUID].errors.length + 1
});
}
});
}


app.post('/connect', async (req, res) => {
const { Socket } = req.body;
if (!Socket) {
return res.status(400).json({ success: false, error: "No WebSocket URL provided!" });
}
if (!isValidWebSocketURL(Socket)) {
return res.status(400).json({ success: false, error: "Invalid WebSocket URL" });
}

const UUID = generateUUID();
const socket = new WebSocket(Socket);

try {
await new Promise((resolve, reject) => {
socket.on('error', (error) => {
console.error(`WebSocket error for UUID: ${UUID}`, error);
reject(error);
});
socket.on('open', () => {
resolve();
});
});
} catch (error) {
return res.status(500).json({ success: false, error: "WebSocket connection error" });
}

connections[UUID] = { socket: socket, messages: [] };
handleWebSocketConnection(UUID, socket);

res.json({ UUID, Socket, success: true });
});


app.post('/disconnect', (req, res) => {
const { UUID } = req.body;
if (!UUID) {
return res.status(400).json({ success: false, error: "No UUID provided!" });
}
if (!connections[UUID]) {
return res.status(404).json({ success: false, error: "UUID not found" });
}

connections[UUID].socket.close();
delete connections[UUID];

res.json({ UUID, success: true });
});

app.post('/validation', (req, res) => {
const { UUID } = req.body;
if (!UUID) {
return res.status(400).json({ success: false, error: "No UUID provided!" });
}

res.json({ isValid: !!connections[UUID] });
});

app.post('/send', (req, res) => {
const { UUID, Message } = req.body;
if (!UUID || !Message) {
return res.status(400).json({ success: false, error: "UUID or Message not provided!" });
}
if (!connections[UUID] || connections[UUID].socket.readyState !== WebSocket.OPEN) {
return res.status(404).json({ success: false, error: "Invalid UUID or WebSocket connection closed" });
}

connections[UUID].socket.send(Message);
res.json(true);
});

app.post('/get', (req, res) => {
const { UUID } = req.body;
if (!UUID) {
return res.status(400).json({ success: false, error: "No UUID provided!" });
}
if (!connections[UUID]) {
return res.status(404).json({ success: false, error: "Invalid UUID" });
}

res.json(connections[UUID].messages);
});
app.post('/errors', (req, res) => {
const { UUID } = req.body;
if (!UUID) {
return res.status(400).json({ success: false, error: "No UUID provided!" });
}
if (!connections[UUID]) {
return res.status(404).json({ success: false, error: "Invalid UUID" });
}

res.json(connections[UUID].errors);
});

app.listen(port, () => {
console.log(`Server running on port ${port}`);
});
Loading

0 comments on commit fb99183

Please sign in to comment.