Compare commits

..

No commits in common. "8d63eb270b28346b353fc209d06b62790b9347f3" and "c10c3ec280cecb0058bcfd22b7a6980fee0ff696" have entirely different histories.

8 changed files with 1619 additions and 99 deletions

3
.gitignore vendored
View File

@ -1 +1,2 @@
/.venv /node_modules

View File

@ -2,12 +2,12 @@
```text ```text
GET /api/ws GET /api/ws
GET /api/cc/{uuid}/keypad/code GET /api/{uuid}/keypad/code
GET /api/cc/{uuid}/keypad/get_user_info/{uid} GET /api/{uuid}/keypad/get_user_info/{uid}
POST /api/cc/{uuid}/keypad/log/door_open/{uid} POST /api/{uuid}/keypad/log/door_open/{uid}
POST /api/cc/{uuid}/keypad/set_code POST /api/{uuid}/keypad/set_code
POST /api/cc/{uuid}/core/reboot POST /api/{uuid}/core/reboot
POST /api/cc/{uuid}/core/update POST /api/{uuid}/core/update
``` ```
## websocket ## websocket

1533
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

24
package.json Normal file
View File

@ -0,0 +1,24 @@
{
"name": "rtmc-be",
"version": "1.0.0",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"description": "",
"devDependencies": {
"@types/express": "^4.17.21",
"@types/knex": "^0.15.2",
"@types/node": "^22.5.0",
"@types/ws": "^8.5.12",
"typescript": "^5.5.4"
},
"dependencies": {
"express": "^4.19.2",
"knex": "^3.1.0",
"pug": "^3.0.3",
"ws": "^8.18.0"
}
}

View File

@ -1,8 +0,0 @@
[tool.pylint.'MESSAGES CONTROL']
disable = [
"line-too-long",
"unnecessary-semicolon",
"trailing-newlines",
"missing-docstring"
]

113
server.py
View File

@ -1,98 +1,47 @@
import asyncio import asyncio
import string
import secrets
import json import json
import websockets from websockets import serve
clients = { clients = {
"FD3ZJFHQ7r": { "FD3ZJFHQ7r" : {
"doorOpen": False, "doorOpen" : False,
"lockdown": False, "lockdown" : False,
"lastOpened": 1, #unix timestamp "lastOpened" : 1, #unix timestamp
"secLevel": 1, "secLevel" : 1,
"openedBy": "user" "openedBy" : "user"
} }
} }
def rand_id(): async def echo(websocket):
return ''.join(secrets.choice(string.ascii_letters + string.digits) for _ in range(16)) print("Connection established")
authenticated = False
await websocket.send(json.dumps({
"type" : "SAuthReq"
}))
class WsClient: async for msg in websocket:
def __init__(self, ws): msg_json = json.loads(msg)
self.ws = ws if authenticated == False:
self.module_info = {} if msg_json["type"] == "CAuth":
self.pcid = None if msg_json["token"] in clients:
await websocket.send(json.dumps({
def send(self, message): "type" : "SAuthStatus",
self.ws.send(json.dumps(message)) "failed" : False,
"reason" : "Authentication Successful"
}))
authenticated = True
class WebSocketHandler: else:
def __init__(self): await websocket.send(json.dumps({
self.clients = {} "type" : "SAuthStatus",
"failed" : True,
def on_message(self, client, message): "reason" : "Invalid token"
message_type = message.get('type') }))
# Route messages based on type using match-case
match message_type:
case "CAuth":
client.pcid = message["pcid"]
case "CLog":
print(f"[CC] [{message["level"]}] {message["msg"]}")
case "CModule":
match message["module"]:
case "keypad":
self.handle_keypad_msg(client, message["message"]);
def handle_keypad_msg(self, client: WsClient, message):
match message["type"]:
case "CDoorOpened":
print(f"[CC][KEYPAD] Door was opened on {message["time"]} {"manually" if message["manual"] else ""}")
case "CGetUserStat":
client.send({
"type": "SUserStat",
# user info
})
case "CGetDoorStat":
stats = {}
for pc in self.clients:
i = pc.module_info["keypad"]
stats[pc.uid] = i if i else {}
client.send({
"type": "CDoorStat",
"stats": stats
})
async def new_client(self, ws):
uid = rand_id()
self.clients[uid] = WsClient(ws)
self.clients[uid].send({
"type" : "SAuthReq"
})
async for msg_t in ws:
msg = json.loads(msg_t)
self.on_message(self.clients[uid], msg)
def stop(self):
for c in self.clients:
c.ws.close()
async def main(): async def main():
wsh = WebSocketHandler() async with serve(echo, "localhost", 8765):
async with websockets.serve(wsh.new_client, "localhost", 8765):
await asyncio.get_running_loop().create_future() await asyncio.get_running_loop().create_future()
asyncio.run(main()) asyncio.run(main())

0
src/index.ts Normal file
View File

21
tsconfig.json Normal file
View File

@ -0,0 +1,21 @@
{
"$schema": "http://json.schemastore.org/tsconfig",
"compilerOptions": {
"typeRoots": ["./node_modules/@types", "./src/types"],
"strict": true,
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "NodeNext",
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"types": [""],
"noEmit": true,
"isolatedModules": true,
"noImplicitAny": true,
"alwaysStrict": true,
"outDir": "build",
},
"include": [
"src/**/*.ts",
]
}