diff --git a/.env b/.env index 924cf50..ec265b3 100644 --- a/.env +++ b/.env @@ -1,4 +1,3 @@ HOST=localhost HTTPS=true DANGEROUSLY_DISABLE_HOST_CHECK='true' -WDS_SOCKET_PORT=0 diff --git a/Dockerfile b/Dockerfile index 44e196d..49c6450 100644 --- a/Dockerfile +++ b/Dockerfile @@ -68,9 +68,10 @@ COPY /.env /home/user/.env RUN { \ echo "REACT_APP_CHAT_URL=${CHAT_URL}" ; \ echo "REACT_APP_CHAT_BASE=${CHAT_BASE}" ; \ - echo "WDS_SOCKET_PATH=${CHAT_BASE}/ws" ; \ echo "PUBLIC_URL=${CHAT_BASE}" ; \ + echo "WDS_SOCKET_PATH=/ws" ; \ echo "WDS_SOCKET_HOST=${CHAT_URL#http*://}" ; \ + echo "WDS_SOCKET_PORT=443" ; \ } | tee -a /home/user/.env COPY /server /home/user/server diff --git a/client/package-lock.json b/client/package-lock.json index 5936c61..9daea82 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -12,10 +12,10 @@ "@emotion/styled": "^11.10.6", "@mui/icons-material": "^5.11.11", "@mui/material": "^5.11.15", - "@types/jest": "^29.5.0", - "@types/node": "^18.15.11", - "@types/react": "^18.0.31", - "@types/react-dom": "^18.0.11", + "@types/jest": "^29.2.3", + "@types/node": "^18.11.10", + "@types/react": "^18.0.26", + "@types/react-dom": "^18.0.9", "fast-deep-equal": "^3.1.3", "history": "^5.3.0", "http-proxy-middleware": "^2.0.6", @@ -30,8 +30,7 @@ "react-router-dom": "^6.4.4", "react-scripts": "^5.0.1", "react-select": "^5.7.0", - "react-spinners": "^0.13.6", - "typescript": "^5.0.3" + "react-spinners": "^0.13.6" } }, "node_modules/@ampproject/remapping": { @@ -16415,15 +16414,16 @@ } }, "node_modules/typescript": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.3.tgz", - "integrity": "sha512-xv8mOEDnigb/tN9PSMTwSEqAnUvkoXMQlicOb0IUVDBSQCgBSaAAROUZYy2IcUy5qU6XajK5jjjO7TMWqBTKZA==", + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" }, "engines": { - "node": ">=12.20" + "node": ">=4.2.0" } }, "node_modules/unbox-primitive": { diff --git a/client/src/App.css b/client/src/App.css index 74b5e05..600418e 100644 --- a/client/src/App.css +++ b/client/src/App.css @@ -1,4 +1,6 @@ .App { + display: flex; + flex-direction: row; text-align: center; } @@ -13,6 +15,24 @@ } } +.Conference { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + overflow-y: auto; + display: flex; + flex-direction: row; + text-align: center; +} + +.Sidebar { + display: flex; + border: 1px solid black; + min-width: 10vwh; +} + .App-header { background-color: #282c34; min-height: 100vh; diff --git a/client/src/App.tsx b/client/src/App.tsx index 25b1e83..c83af07 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -10,6 +10,7 @@ import { import { GlobalContext, GlobalData } from "./GlobalContext"; import { PersonList } from "./PersonList"; import { Chat } from "./Chat"; +import { Actions } from "./Actions"; import "./App.css"; import equal from "fast-deep-equal"; @@ -17,7 +18,7 @@ import equal from "fast-deep-equal"; // @ts-ignore const base = process.env.REACT_APP_CHAT_BASE; -const Table = () => { +const Conference = () => { const params = useParams(); const [chatId, setChatId] = useState(params.chatId ? params.chatId : undefined); const [ws, setWs] = useState (); /* tracks full websocket lifetime */ @@ -299,8 +300,10 @@ const Table = () => { return { /* */} -
+
Test
+
+ {name === "" && } {name !== "" && } {name !== "" && }
@@ -313,6 +316,7 @@ const App = () => { const [error, setError] = useState(''); useEffect(() => { + console.log(personId, base); if (personId) { return; } @@ -325,16 +329,17 @@ const App = () => { }, }).then((res) => { if (res.status >= 400) { - const error = `Unable to connect to Ketr Ketran chat server! ` + + const error = `Unable to connect to Ketr Chat server! ` + `Try refreshing your browser in a few seconds.`; console.error(error); setError(error); } - console.log(res.headers); return res.json(); }).then((data) => { + console.log(data); setPersonId(data.person); }).catch((error) => { + console.error(error); }); }, [personId, setPersonId]); @@ -345,8 +350,8 @@ const App = () => { return ( - } path={`${base}/:chatId`} /> - } path={`${base}`} /> + } path={`${base}/:chatId`} /> + } path={`${base}`} /> ); diff --git a/development.yml b/development.yml index ee33e70..1fccd53 100644 --- a/development.yml +++ b/development.yml @@ -2,7 +2,7 @@ version: '3.1' services: ketr.chat: volumes: - - /etc/nginx/ssl:/etc/nginx/ssl:ro # Use host web keys + - /etc/letsencrypt:/etc/letsencrypt:ro # Use host web keys - ./logs:/home/user/logs # - ./db:/home/user/db # Hot mount client and server for dynamic changes in DEVELOPMENT @@ -21,5 +21,5 @@ services: - ./client/public:/home/user/client/public - ./client/src:/home/user/client/src ports: - - 127.0.0.1:19876:80 # Main app entrypoint + - 127.0.0.1:19876:443 # Main app entrypoint - 127.0.0.1:14200:4200 # shellinabox diff --git a/docker-compose.yml b/docker-compose.yml index 42b479d..bf337af 100755 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -15,8 +15,6 @@ services: volumes: - /etc/nginx/ssl:/etc/nginx/ssl:ro # Use host web keys - ./logs:/home/user/logs # - ports: - - 127.0.0.1:19876:80 ketr.chat-production: image: ketr.chat:production @@ -31,8 +29,7 @@ services: tty: true # Needed for react-scripts restart: always volumes: - - /etc/nginx/ssl:/etc/nginx/ssl:ro # Use host web keys + - /etc/letsencrypt:/etc/letsencrypt:ro # Use host web keys - ./db:/home/user/db - ports: - - 127.0.0.1:19876:80 + diff --git a/entrypoint.sh b/entrypoint.sh index 8d8954f..a949927 100755 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -29,9 +29,7 @@ if [[ -z "${DEVELOPMENT}" ]]; then else echo "Running in DEVELOPMENT mode." cd /home/user/server - npm install { while true; do npm start ; sleep 3 ; done ; } & cd /home/user/client - npm install { while true; do npm start ; sleep 3 ; done ; } fi diff --git a/production.yml b/production.yml index b5d19d2..8f5092b 100644 --- a/production.yml +++ b/production.yml @@ -3,6 +3,8 @@ version: '3.1' services: ketr.chat-production: volumes: - - /etc/nginx/ssl:/etc/nginx/ssl:ro # Use host web keys + - /etc/letsencrypt:/etc/letsencrypt:ro # Use host web keys - ./logs:/home/user/logs # - ./db:/home/user/db + ports: + - 127.0.0.1:19876:443 # Main app entrypoint \ No newline at end of file diff --git a/server/app.js b/server/app.js index 0e85e9c..683f7c5 100755 --- a/server/app.js +++ b/server/app.js @@ -50,8 +50,8 @@ if (config.has("admin")) { /* Allow loading of the app w/out being logged in */ app.use(basePath, index); -/* /chat loads the default index */ -app.use(basePath + "chat", index); +/* /chats loads the default index */ +app.use(basePath + "chats", index); /* Allow access to the 'users' API w/out being logged in */ /* @@ -67,7 +67,7 @@ app.use(function(err, req, res, next) { }); }); -app.use(`${basePath}api/v1/chat`, require("./routes/chat")); +app.use(`${basePath}api/v1/chats`, require("./routes/chat")); /* Declare the "catch all" index route last; the final route is a 404 dynamic router */ app.use(basePath, index); diff --git a/server/development.location b/server/development.location index d1d2e8d..fb8da4b 100644 --- a/server/development.location +++ b/server/development.location @@ -1,4 +1,18 @@ # DEVELOPMENT -- use npm development server on port 3000 (entrypoint.sh) +location /ws/ { + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header Host $http_host; + proxy_set_header X-NginX-Proxy true; + proxy_pass_header Set-Cookie; + proxy_pass_header P3P; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_pass https://localhost:3000/ws/; +} + location / { proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; @@ -12,4 +26,3 @@ location / { proxy_set_header Connection "upgrade"; proxy_pass https://localhost:3000/ketr.chat/; } - diff --git a/server/lib/basepath.js b/server/lib/basepath.js index 9e6d5f2..60b0e3f 100755 --- a/server/lib/basepath.js +++ b/server/lib/basepath.js @@ -1,4 +1,4 @@ -let basePath = process.env.CHAT_BASE; +let basePath = "/";//process.env.CHAT_BASE; console.log(basePath); basePath = "/" + basePath.replace(/^\/+/, "").replace(/\/+$/, "") + "/"; if (basePath == "//") { diff --git a/server/nginx.conf b/server/nginx.conf index 6c462c9..b3ff8ea 100644 --- a/server/nginx.conf +++ b/server/nginx.conf @@ -2,11 +2,14 @@ server { root /home/user; index index.html; - access_log /var/log/nginx/access.log; - error_log stderr; + listen 443 ssl; + + ssl_certificate /etc/letsencrypt/live/ketrenos.com/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/ketrenos.com/privkey.pem; + + access_log /var/log/nginx/access.log; + error_log /var/log/nginx/error.log; - autoindex on; - # proxy_pass has automatic redirect from v1 -> v1/ # Set the API redirect early in case endpoints have similar names # to other location matches. @@ -21,7 +24,7 @@ server { proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; - proxy_pass http://localhost:8911/api/v1/; + proxy_pass http://localhost:8930/api/v1/; } # Set tail-pre injection for log files diff --git a/server/routes/chat.js b/server/routes/chat.js index 2aadb2a..b4e1f1e 100755 --- a/server/routes/chat.js +++ b/server/routes/chat.js @@ -18,14 +18,17 @@ const debug = { let chatDB; +const chats = {}; +const audio = {}; + require("../db/chats").then(function(db) { chatDB = db; }); -const sessionFromColor = (chat, color) => { - for (let key in chat.sessions) { - if (chat.sessions[key].color === color) { - return chat.sessions[key]; +const sessionFromColor = (room, color) => { + for (let key in room.sessions) { + if (room.sessions[key].color === color) { + return room.sessions[key]; } } } @@ -39,14 +42,14 @@ const newPerson = (color) => { }; } -const getSession = (chat, id) => { - if (!chat.sessions) { - chat.sessions = {}; +const getSession = (room, id) => { + if (!room.sessions) { + room.sessions = {}; } /* If this session is not yet in the chat, add it and set the person's name */ - if (!(id in chat.sessions)) { - chat.sessions[id] = { + if (!(id in room.sessions)) { + room.sessions[id] = { id: `[${id.substring(0, 8)}]`, name: '', color: '', @@ -56,7 +59,7 @@ const getSession = (chat, id) => { }; } - const session = chat.sessions[id]; + const session = room.sessions[id]; session.lastActive = Date.now(); session.live = true; if (session.person) { @@ -65,8 +68,8 @@ const getSession = (chat, id) => { } /* Expire old unused sessions */ - for (let _id in chat.sessions) { - const _session = chat.sessions[_id]; + for (let _id in room.sessions) { + const _session = room.sessions[_id]; if (_session.color || _session.name || _session.person) { continue; } @@ -77,14 +80,14 @@ const getSession = (chat, id) => { const age = Date.now() - _session.lastActive; if (age > 60 * 60 * 1000) { console.log(`${_session.id}: Expiring old session ${_id}: ${age/(60 * 1000)} minutes`); - delete chat.sessions[_id]; - if (_id in chat.sessions) { + delete room.sessions[_id]; + if (_id in room.sessions) { console.log('delete DID NOT WORK!'); } } } - return chat.sessions[id]; + return room.sessions[id]; }; const loadChat = async (id) => { @@ -96,53 +99,53 @@ const loadChat = async (id) => { return chats[id]; } - let chat = await readFile(`chats/${id}`) + let room = await readFile(`chats/${id}`) .catch(() => { return; }); - if (chat) { + if (room) { try { - chat = JSON.parse(chat); + room = JSON.parse(room); console.log(`${info}: Creating backup of chats/${id}`); - await writeFile(`chats/${id}.bk`, JSON.stringify(chat)); + await writeFile(`chats/${id}.bk`, JSON.stringify(room)); } catch (error) { console.log(`Load or parse error from chats/${id}:`, error); console.log(`Attempting to load backup from chats/${id}.bk`); - chat = await readFile(`chats/${id}.bk`) + room = await readFile(`chats/${id}.bk`) .catch(() => { - console.error(error, chat); + console.error(error, room); }); - if (chat) { + if (room) { try { - chat = JSON.parse(chat); + room = JSON.parse(room); console.log(`Saving backup to chats/${id}`); - await writeFile(`chats/${id}`, JSON.stringify(chat, null, 2)); + await writeFile(`chats/${id}`, JSON.stringify(room, null, 2)); } catch (error) { console.error(error); - chat = null; + room = null; } } } } - if (!chat) { - chat = createChat(id); + if (!room) { + room = createChat(id); } /* Clear out cached names from person colors and rebuild them * from the information in the saved chat sessions */ - for (let color in chat.persons) { - delete chat.persons[color].name; - chat.persons[color].status = 'Not active'; + for (let color in room.persons) { + delete room.persons[color].name; + room.persons[color].status = 'Not active'; } /* Reconnect session person colors to the person objects */ - chat.unselected = []; - for (let id in chat.sessions) { - const session = chat.sessions[id]; - if (session.name && session.color && session.color in chat.persons) { - session.person = chat.persons[session.color]; + room.unselected = []; + for (let id in room.sessions) { + const session = room.sessions[id]; + if (session.name && session.color && session.color in room.persons) { + session.person = room.persons[session.color]; session.person.name = session.name; session.person.status = 'Active'; session.person.live = false; @@ -154,13 +157,13 @@ const loadChat = async (id) => { session.live = false; /* Populate the 'unselected' list from the session table */ - if (!chat.sessions[id].color && chat.sessions[id].name) { - chat.unselected.push(chat.sessions[id]); + if (!room.sessions[id].color && room.sessions[id].name) { + room.unselected.push(room.sessions[id]); } } - chats[id] = chat; - return chat; + chats[id] = room; + return room; }; const clearPerson = (person) => { @@ -171,7 +174,7 @@ const clearPerson = (person) => { Object.assign(person, newPerson(color)); } -const setPersonName = (chat, session, name) => { +const setPersonName = (room, session, name) => { if (session.name === name) { return; /* no-op */ } @@ -185,8 +188,8 @@ const setPersonName = (chat, session, name) => { /* Check to ensure name is not already in use */ let rejoin = false; - for (let id in chat.sessions) { - const tmp = chat.sessions[id]; + for (let id in room.sessions) { + const tmp = room.sessions[id]; if (tmp === session || !tmp.name) { continue; } @@ -197,7 +200,7 @@ const setPersonName = (chat, session, name) => { * from active session */ Object.assign(session, tmp, { ws: session.ws, id: session.id }); console.log(`${info}: ${name} has been reallocated to a new session.`); - delete chat.sessions[id]; + delete room.sessions[id]; } else { return `${name} is already taken and has been active in the last minute.`; } @@ -211,19 +214,19 @@ const setPersonName = (chat, session, name) => { } else { if (rejoin) { if (session.color) { - message = `${name} has reconnected to the chat.`; + message = `${name} has reconnected to the room.`; } else { message = `${name} has rejoined the lobby.`; } session.name = name; - if (session.ws && (chat.id in audio) - && session.name in audio[chat.id]) { - part(audio[chat.id], session); + if (session.ws && (room.id in audio) + && session.name in audio[room.id]) { + part(audio[room.id], session); } } else { message = `${session.name} has changed their name to ${name}.`; - if (session.ws && chat.id in audio) { - part(audio[chat.id], session); + if (session.ws && room.id in audio) { + part(audio[room.id], session); } } } @@ -240,38 +243,38 @@ const setPersonName = (chat, session, name) => { } if (session.ws && session.hasAudio) { - join(audio[chat.id], session, { + join(audio[room.id], session, { hasVideo: session.video ? true : false, hasAudio: session.audio ? true : false }); } console.log(`${info}: ${message}`); - addChatMessage(chat, null, message); + addChatMessage(room, null, message); /* Rebuild the unselected list */ if (!session.color) { console.log(`${info}: Adding ${session.name} to the unselected`); } - chat.unselected = []; - for (let id in chat.sessions) { - if (!chat.sessions[id].color && chat.sessions[id].name) { - chat.unselected.push(chat.sessions[id]); + room.unselected = []; + for (let id in room.sessions) { + if (!room.sessions[id].color && room.sessions[id].name) { + room.unselected.push(room.sessions[id]); } } - sendUpdateToPerson(chat, session, { + sendUpdateToPerson(room, session, { name: session.name, color: session.color, live: session.live, private: session.person }); - sendUpdateToPersons(chat, { - persons: getFilteredPersons(chat), - unselected: getFilteredUnselected(chat), - chat: chat.chat + sendUpdateToPersons(room, { + persons: getFilteredPersons(room), + unselected: getFilteredUnselected(room), + chat: room.chat }); /* Now that a name is set, send the full chat to the person */ - sendChatToPerson(chat, session); + sendChatToPerson(room, session); } const colorToWord = (color) => { @@ -285,10 +288,10 @@ const colorToWord = (color) => { } } -const getActiveCount = (chat) => { +const getActiveCount = (room) => { let active = 0; - for (let color in chat.persons) { - if (!chat.persons[color].name) { + for (let color in room.persons) { + if (!room.persons[color].name) { continue; } active++; @@ -296,7 +299,7 @@ const getActiveCount = (chat) => { return active; } -const setPersonColor = (chat, session, color) => { +const setPersonColor = (room, session, color) => { /* Selecting the same color is a NO-OP */ if (session.color === color) { return; @@ -307,21 +310,21 @@ const setPersonColor = (chat, session, color) => { return `You may only select a person when you have set your name.`; } - if (chat.state !== 'lobby') { + if (room.state !== 'lobby') { return `You may only select a person when the chat is in the lobby.`; } /* Verify selection is valid */ - if (color && !(color in chat.persons)) { + if (color && !(color in room.persons)) { return `An invalid person selection was attempted.`; } /* Verify selection is not already taken */ - if (color && chat.persons[color].status !== 'Not active') { - return `${chat.persons[color].name} already has ${colorToWord(color)}`; + if (color && room.persons[color].status !== 'Not active') { + return `${room.persons[color].name} already has ${colorToWord(color)}`; } - let active = getActiveCount(chat); + let active = getActiveCount(room); if (session.person) { /* Deselect currently active person for this session */ @@ -332,25 +335,25 @@ const setPersonColor = (chat, session, color) => { /* If the person is not selecting a color, then return */ if (!color) { - addChatMessage(chat, null, + addChatMessage(room, null, `${session.name} is no longer ${colorToWord(session.color)}.`); - chat.unselected.push(session); - chat.active = active; + room.unselected.push(session); + room.active = active; if (active === 1) { - addChatMessage(chat, null, - `There are no longer enough persons to start a chat.`); + addChatMessage(room, null, + `There are no longer enough persons to start a room.`); } - sendUpdateToPerson(chat, session, { + sendUpdateToPerson(room, session, { name: session.name, color: '', live: session.live, private: session.person }); - sendUpdateToPersons(chat, { - active: chat.active, - unselected: getFilteredUnselected(chat), - persons: getFilteredPersons(chat), - chat: chat.chat + sendUpdateToPersons(room, { + active: room.active, + unselected: getFilteredUnselected(room), + persons: getFilteredPersons(room), + chat: room.chat }); return; } @@ -360,64 +363,64 @@ const setPersonColor = (chat, session, color) => { active++; session.color = color; session.live = true; - session.person = chat.persons[color]; + session.person = room.persons[color]; session.person.name = session.name; session.person.status = `Active`; session.person.lastActive = Date.now(); session.person.live = true; - addChatMessage(chat, session, `${session.name} has chosen to play as ${colorToWord(color)}.`); + addChatMessage(room, session, `${session.name} has chosen to play as ${colorToWord(color)}.`); const update = { - persons: getFilteredPersons(chat), - chat: chat.chat + persons: getFilteredPersons(room), + chat: room.chat }; /* Rebuild the unselected list */ const unselected = []; - for (let id in chat.sessions) { - if (!chat.sessions[id].color && chat.sessions[id].name) { - unselected.push(chat.sessions[id]); + for (let id in room.sessions) { + if (!room.sessions[id].color && room.sessions[id].name) { + unselected.push(room.sessions[id]); } } - if (unselected.length !== chat.unselected.length) { - chat.unselected = unselected; - update.unselected = getFilteredUnselected(chat); + if (unselected.length !== room.unselected.length) { + room.unselected = unselected; + update.unselected = getFilteredUnselected(room); } - if (chat.active !== active) { - if (chat.active < 2 && active >= 2) { - addChatMessage(chat, null, - `There are now enough persons to start the chat.`); + if (room.active !== active) { + if (room.active < 2 && active >= 2) { + addChatMessage(room, null, + `There are now enough persons to start the room.`); } - chat.active = active; - update.active = chat.active; + room.active = active; + update.active = room.active; } - sendUpdateToPerson(chat, session, { + sendUpdateToPerson(room, session, { name: session.name, color: session.color, live: session.live, private: session.person, }); - sendUpdateToPersons(chat, update); + sendUpdateToPersons(room, update); }; -const addActivity = (chat, session, message) => { +const addActivity = (room, session, message) => { let date = Date.now(); - if (chat.activities.length && chat.activities[chat.activities.length - 1].date === date) { + if (room.activities.length && room.activities[room.activities.length - 1].date === date) { date++; } - chat.activities.push({ color: session ? session.color : '', message, date }); - if (chat.activities.length > 30) { - chat.activities.splice(0, chat.activities.length - 30); + room.activities.push({ color: session ? session.color : '', message, date }); + if (room.activities.length > 30) { + room.activities.splice(0, room.activities.length - 30); } } -const addChatMessage = (chat, session, message, isNormalChat) => { +const addChatMessage = (room, session, message, isNormalChat) => { let now = Date.now(); let lastTime = 0; - if (chat.chat.length) { - lastTime = chat.chat[chat.chat.length - 1].date; + if (room.chat.length) { + lastTime = room.chat[room.chat.length - 1].date; } if (now <= lastTime) { now = lastTime + 1; @@ -436,36 +439,36 @@ const addChatMessage = (chat, session, message, isNormalChat) => { if (session && session.color) { entry.color = session.color; } - chat.chat.push(entry); - if (chat.chat.length > 50) { - chat.chat.splice(0, chat.chat.length - 50); + room.chat.push(entry); + if (room.chat.length > 50) { + room.chat.splice(0, room.chat.length - 50); } }; -const getColorFromName = (chat, name) => { - for (let id in chat.sessions) { - if (chat.sessions[id].name === name) { - return chat.sessions[id].color; +const getColorFromName = (room, name) => { + for (let id in room.sessions) { + if (room.sessions[id].name === name) { + return room.sessions[id].color; } } return ''; }; -const getLastPersonName = (chat) => { - let index = chat.personOrder.length - 1; - for (let id in chat.sessions) { - if (chat.sessions[id].color === chat.personOrder[index]) { - return chat.sessions[id].name; +const getLastPersonName = (room) => { + let index = room.personOrder.length - 1; + for (let id in room.sessions) { + if (room.sessions[id].color === room.personOrder[index]) { + return room.sessions[id].name; } } return ''; } -const getFirstPersonName = (chat) => { +const getFirstPersonName = (room) => { let index = 0; - for (let id in chat.sessions) { - if (chat.sessions[id].color === chat.personOrder[index]) { - return chat.sessions[id].name; + for (let id in room.sessions) { + if (room.sessions[id].color === room.personOrder[index]) { + return room.sessions[id].name; } } return ''; @@ -488,10 +491,10 @@ router.put("/:id/:action/:value?", async (req, res) => { if (req.headers['private-token'] !== req.app.get('admin')) { error = `Invalid admin credentials.`; } else { - error = adminCommands(chat, action, value, req.query); + error = adminCommands(room, action, value, req.query); } if (!error) { - sendChatToPersons(chat); + sendChatToPersons(room); } else { console.log(`admin-action error: ${error}`); } @@ -500,50 +503,50 @@ router.put("/:id/:action/:value?", async (req, res) => { return res.status(400).send(error); }); -const clearTimeNotice= (chat, session) => { +const clearTimeNotice= (room, session) => { if (!session.person.turnNotice) { /* benign state; don't alert the user */ //return `You have not been idle.`; } session.person.turnNotice = ""; - sendUpdateToPerson(chat, session, { + sendUpdateToPerson(room, session, { private: session.person }); }; -const startTurnTimer = (chat, session) => { +const startTurnTimer = (room, session) => { const timeout = 90; if (!session.ws) { console.log(`${session.id}: Aborting turn timer as ${session.name} is disconnected.`); } else { console.log(`${session.id}: (Re)setting turn timer for ${session.name} to ${timeout} seconds.`); } - if (chat.turnTimer) { - clearTimeout(chat.turnTimer); + if (room.turnTimer) { + clearTimeout(room.turnTimer); } if (!session.connected) { - chat.turnTimer = 0; + room.turnTimer = 0; return; } - chat.turnTimer = setTimeout(() => { + room.turnTimer = setTimeout(() => { console.log(`${session.id}: Turn timer expired for ${session.name}`); session.person.turnNotice = 'It is still your turn.'; - sendUpdateToPerson(chat, session, { + sendUpdateToPerson(room, session, { private: session.person }); - resetTurnTimer(chat, session); + resetTurnTimer(room, session); }, timeout * 1000); } -const resetTurnTimer = (chat, session) => { - startTurnTimer(chat, session); +const resetTurnTimer = (room, session) => { + startTurnTimer(room, session); } -const stopTurnTimer = (chat) => { - if (chat.turnTimer) { +const stopTurnTimer = (room) => { + if (room.turnTimer) { console.log(`${info}: Stopping turn timer.`); - clearTimeout(chat.turnTimer); - chat.turnTimer = 0; + clearTimeout(room.turnTimer); + room.turnTimer = 0; } } @@ -562,8 +565,8 @@ const ping = (session) => { session.keepAlive = setTimeout(() => { ping(session); }, 2500); } -const wsInactive = (chat, req) => { - const session = getSession(chat, req.cookies.person); +const wsInactive = (room, req) => { + const session = getSession(room, req.cookies.person); if (session && session.ws) { console.log(`Closing WebSocket to ${session.name} due to inactivity.`); @@ -577,53 +580,53 @@ const wsInactive = (chat, req) => { } } -const setChatState = (chat, session, state) => { +const setChatState = (room, session, state) => { if (!state) { return `Invalid state.`; } if (!session.color) { - return `You must have an active person to start the chat.`; + return `You must have an active person to start the room.`; } - if (state === chat.state) { + if (state === room.state) { return; } switch (state) { case "chat-order": - if (chat.state !== 'lobby') { + if (room.state !== 'lobby') { return `You can only start the chat from the lobby.`; } - const active = getActiveCount(chat); + const active = getActiveCount(room); if (active < 2) { - return `You need at least two persons to start the chat.`; + return `You need at least two persons to start the room.`; } /* Delete any non-played colors from the person map; reduces all * code that would otherwise have to filter out persons by checking * the 'Not active' state of person.status */ - for (let key in chat.persons) { - if (chat.persons[key].status !== 'Active') { - delete chat.persons[key]; + for (let key in room.persons) { + if (room.persons[key].status !== 'Active') { + delete room.persons[key]; } } - addChatMessage(chat, null, `${session.name} requested to start the chat.`); - chat.state = state; + addChatMessage(room, null, `${session.name} requested to start the room.`); + room.state = state; - sendUpdateToPersons(chat, { - state: chat.state, - chat: chat.chat + sendUpdateToPersons(room, { + state: room.state, + chat: room.chat }); break; } } -const resetDisconnectCheck = (chat, req) => { +const resetDisconnectCheck = (room, req) => { if (req.disconnectCheck) { clearTimeout(req.disconnectCheck); } - //req.disconnectCheck = setTimeout(() => { wsInactive(chat, req) }, 20000); + //req.disconnectCheck = setTimeout(() => { wsInactive(room, req) }, 20000); } const join = (peers, session, { hasVideo, hasAudio }) => { @@ -710,14 +713,14 @@ const getName = (session) => { return session ? (session.name ? session.name : session.id) : 'Admin'; } -const saveChat = async (chat) => { +const saveChat = async (room) => { /* Shallow copy chat, filling its sessions with a shallow copy of sessions so we can then * delete the person field from them */ const reducedChat = Object.assign({}, chat, { sessions: {} }), reducedSessions = []; - for (let id in chat.sessions) { - const reduced = Object.assign({}, chat.sessions[id]); + for (let id in room.sessions) { + const reduced = Object.assign({}, room.sessions[id]); if (reduced.person) { delete reduced.person; } @@ -728,67 +731,67 @@ const saveChat = async (chat) => { delete reduced.keepAlive; } - reducedchat.sessions[id] = reduced; + reducedroom.sessions[id] = reduced; /* Do not send session-id as those are secrets */ reducedSessions.push(reduced); } - delete reducedchat.turnTimer; - delete reducedchat.unselected; + delete reducedroom.turnTimer; + delete reducedroom.unselected; /* Save per turn while debugging... */ - chat.step = chat.step ? chat.step : 0; + room.step = room.step ? room.step : 0; /* - await writeFile(`chats/${chat.id}.${chat.step++}`, JSON.stringify(reducedChat, null, 2)) + await writeFile(`chats/${room.id}.${room.step++}`, JSON.stringify(reducedChat, null, 2)) .catch((error) => { - console.error(`${session.id} Unable to write to chats/${chat.id}`); + console.error(`${session.id} Unable to write to chats/${room.id}`); console.error(error); }); */ - await writeFile(`chats/${chat.id}`, JSON.stringify(reducedChat, null, 2)) + await writeFile(`chats/${room.id}`, JSON.stringify(reducedChat, null, 2)) .catch((error) => { - console.error(`${session.id} Unable to write to chats/${chat.id}`); + console.error(`${session.id} Unable to write to chats/${room.id}`); console.error(error); }); } -const departLobby = (chat, session, color) => { +const departLobby = (room, session, color) => { const update = {}; - update.unselected = getFilteredUnselected(chat); + update.unselected = getFilteredUnselected(room); if (session.person) { session.person.live = false; - update.persons = chat.persons; + update.persons = room.persons; } if (session.name) { if (session.color) { - addChatMessage(chat, null, `${session.name} has disconnected ` + - `from the chat.`); + addChatMessage(room, null, `${session.name} has disconnected ` + + `from the room.`); } else { - addChatMessage(chat, null, `${session.name} has left the lobby.`); + addChatMessage(room, null, `${session.name} has left the lobby.`); } - update.chat = chat.chat; + update.chat = room.chat; } else { console.log(`${session.id}: departLobby - ${getName(session)} is ` + - `being removed from ${chat.id}'s sessions.`); - for (let id in chat.sessions) { - if (chat.sessions[id] === session) { - delete chat.sessions[id]; + `being removed from ${room.id}'s sessions.`); + for (let id in room.sessions) { + if (room.sessions[id] === session) { + delete room.sessions[id]; break; } } } - sendUpdateToPersons(chat, update); + sendUpdateToPersons(room, update); } const all = `[ all ]`; const info = `[ info ]`; const todo = `[ todo ]`; -const sendChatToPerson = (chat, session) => { +const sendChatToPerson = (room, session) => { console.log(`${session.id}: -> sendChatPerson:${getName(session)} - full chat`); if (!session.ws) { console.log(`${session.id}: -> sendChatPerson:: Currently no connection`); @@ -802,7 +805,7 @@ const sendChatToPerson = (chat, session) => { console.log(`${session.id}: -> sendChatPerson:${getName(session)} - only sending empty name`); update = { name: "" }; } else { - update = getFilteredChatForPerson(chat, session); + update = getFilteredChatForPerson(room, session); } session.ws.send(JSON.stringify({ @@ -811,15 +814,15 @@ const sendChatToPerson = (chat, session) => { })); }; -const sendChatToPersons = (chat) => { +const sendChatToPersons = (room) => { console.log(`${all}: -> sendChatPersons - full chat`); - for (let key in chat.sessions) { - sendChatToPerson(chat, chat.sessions[key]); + for (let key in room.sessions) { + sendChatToPerson(room, room.sessions[key]); } }; -const sendUpdateToPersons = async (chat, update) => { +const sendUpdateToPersons = async (room, update) => { /* Ensure clearing of a field actually gets sent by setting * undefined to 'false' */ @@ -829,7 +832,7 @@ const sendUpdateToPersons = async (chat, update) => { } } - calculatePoints(chat, update); + calculatePoints(room, update); if (debug.update) { console.log(`[ all ]: -> sendUpdateToPersons - `, update); @@ -842,8 +845,8 @@ const sendUpdateToPersons = async (chat, update) => { type: 'chat-update', update }); - for (let key in chat.sessions) { - const session = chat.sessions[key]; + for (let key in room.sessions) { + const session = room.sessions[key]; /* Only send person and chat data to named persons */ if (!session.name) { console.log(`${session.id}: -> sendUpdateToPersons:` + @@ -865,7 +868,7 @@ const sendUpdateToPersons = async (chat, update) => { } } -const sendUpdateToPerson = async (chat, session, update) => { +const sendUpdateToPerson = async (room, session, update) => { /* If this person does not have a name, *ONLY* send the name, regardless * of what is requested */ if (!session.name) { @@ -882,7 +885,7 @@ const sendUpdateToPerson = async (chat, session, update) => { } } - calculatePoints(chat, update); + calculatePoints(room, update); if (debug.update) { console.log(`${session.id}: -> sendUpdateToPerson:${getName(session)} - `, update); @@ -904,16 +907,16 @@ const sendUpdateToPerson = async (chat, session, update) => { } } -const getFilteredUnselected = (chat) => { - if (!chat.unselected) { +const getFilteredUnselected = (room) => { + if (!room.unselected) { return []; } - return chat.unselected + return room.unselected .filter(session => session.live) .map(session => session.name); } -const parseChatCommands = (chat, message) => { +const parseChatCommands = (room, message) => { /* Chat messages can set chat flags and fields */ const parts = message.match(/^set +([^ ]*) +(.*)$/i); if (!parts || parts.length !== 3) { @@ -922,17 +925,17 @@ const parseChatCommands = (chat, message) => { switch (parts[1].toLowerCase()) { case 'chat': if (parts[2].trim().match(/^beginner('?s)?( +layout)?/i)) { - setBeginnerChat(chat); - addChatMessage(chat, session, `${session.name} set chat board to the Beginner's Layout.`); + setBeginnerChat(room); + addChatMessage(room, session, `${session.name} set chat board to the Beginner's Layout.`); break; } const signature = parts[2].match(/^([0-9a-f]{12})-([0-9a-f]{38})-([0-9a-f]{38})/i); if (signature) { - if (setChatFromSignature(chat, signature[1], signature[2], signature[3])) { - chat.signature = parts[2]; - addChatMessage(chat, session, `${session.name} set chat board to ${parts[2]}.`); + if (setChatFromSignature(room, signature[1], signature[2], signature[3])) { + room.signature = parts[2]; + addChatMessage(room, session, `${session.name} set chat board to ${parts[2]}.`); } else { - addChatMessage(chat, session, `${session.name} requested an invalid chat board.`); + addChatMessage(room, session, `${session.name} requested an invalid chat board.`); } } break; @@ -947,13 +950,13 @@ const sendWarning = (session, warning) => { session.ws.send(JSON.stringify({ type: 'warning', warning })); } -const getFilteredPersons = (chat) => { +const getFilteredPersons = (room) => { const filtered = {}; - for (let color in chat.persons) { - const person = Object.assign({}, chat.persons[color]); + for (let color in room.persons) { + const person = Object.assign({}, room.persons[color]); filtered[color] = person; if (person.status === 'Not active') { - if (chat.state !== 'lobby') { + if (room.state !== 'lobby') { delete filtered[color]; } continue; @@ -968,29 +971,29 @@ const getFilteredPersons = (chat) => { return filtered; }; -const calculatePoints = (chat, update) => { - if (chat.state === 'winner') { +const calculatePoints = (room, update) => { + if (room.state === 'winner') { return; } /* Calculate points and determine if there is a winner */ - for (let key in chat.persons) { - const person = chat.persons[key]; + for (let key in room.persons) { + const person = room.persons[key]; if (person.status === 'Not active') { continue; } const currentPoints = person.points; person.points = 0; - if (key === chat.longestRoad) { + if (key === room.longestRoad) { person.points += 2; } - if (key === chat.largestArmy) { + if (key === room.largestArmy) { person.points += 2; } - if (key === chat.mostPorts) { + if (key === room.mostPorts) { person.points += 2; } - if (key === chat.mostDeveloped) { + if (key === room.mostDeveloped) { person.points += 2; } person.points += MAX_SETTLEMENTS - person.settlements; @@ -1015,48 +1018,48 @@ const calculatePoints = (chat, update) => { continue; } - if (person.points < getVictoryPointRule(chat)) { - update.persons = getFilteredPersons(chat); + if (person.points < getVictoryPointRule(room)) { + update.persons = getFilteredPersons(room); continue; } /* This person has enough points! Check if they are the current * person and if so, declare victory! */ console.log(`${info}: Whoa! ${person.name} has ${person.points}!`); - for (let key in chat.sessions) { - if (chat.sessions[key].color !== person.color - || chat.sessions[key].status === 'Not active') { + for (let key in room.sessions) { + if (room.sessions[key].color !== person.color + || room.sessions[key].status === 'Not active') { continue; } const message = `Wahoo! ${person.name} has ${person.points} ` + `points on their turn and has won!`; - addChatMessage(chat, null, message) + addChatMessage(room, null, message) console.log(`${info}: ${message}`); update.winner = Object.assign({}, person, { state: 'winner', - stolen: chat.stolen, - chat: chat.chat, - turns: chat.turns, - persons: chat.persons, - elapsedTime: Date.now() - chat.startTime + stolen: room.stolen, + chat: room.chat, + turns: room.turns, + persons: room.persons, + elapsedTime: Date.now() - room.startTime }); - chat.winner = update.winner; - chat.state = 'winner'; - chat.waiting = []; - stopTurnTimer(chat); - sendUpdateToPersons(chat, { - state: chat.state, - winner: chat.winner, - persons: chat.persons /* unfiltered */ + room.winner = update.winner; + room.state = 'winner'; + room.waiting = []; + stopTurnTimer(room); + sendUpdateToPersons(room, { + state: room.state, + winner: room.winner, + persons: room.persons /* unfiltered */ }); } } /* If the chat isn't in a win state, do not share development card information * with other persons */ - if (chat.state !== 'winner') { - for (let key in chat.persons) { - const person = chat.persons[key]; + if (room.state !== 'winner') { + for (let key in room.persons) { + const person = room.persons[key]; if (person.status === 'Not active') { continue; } @@ -1065,68 +1068,69 @@ const calculatePoints = (chat, update) => { } } -const clearChat = (chat, session) => { - resetChat(chat); - addChatMessage(chat, null, +const clearChat = (room, session) => { + resetChat(room); + addChatMessage(room, null, `The chat has been reset. You can play again with this board, or ` + `click 'New board' to mix things up a bit.`); - sendChatToPersons(chat); + sendChatToPersons(room); }; -const gotoLobby = (chat, session) => { - if (!chat.waiting) { - chat.waiting = []; +const gotoLobby = (room, session) => { + if (!room.waiting) { + room.waiting = []; } - const already = chat.waiting.indexOf(session.name) !== -1; + const already = room.waiting.indexOf(session.name) !== -1; const waitingFor = []; - for (let key in chat.sessions) { - if (chat.sessions[key] === session) { + for (let key in room.sessions) { + if (room.sessions[key] === session) { continue; } - if (chat.sessions[key].person && chat.waiting.indexOf(chat.sessions[key].name) == -1) { - waitingFor.push(chat.sessions[key].name); + if (room.sessions[key].person && room.waiting.indexOf(room.sessions[key].name) == -1) { + waitingFor.push(room.sessions[key].name); } } if (!already) { - chat.waiting.push(session.name); - addChatMessage(chat, null, `${session.name} has gone to the lobby.`); + room.waiting.push(session.name); + addChatMessage(room, null, `${session.name} has gone to the lobby.`); } else if (waitingFor.length !== 0) { return `You are already waiting in the lobby. ` + `${waitingFor.join(',')} still needs to go to the lobby.`; } if (waitingFor.length === 0) { - resetChat(chat); - addChatMessage(chat, null, `All persons are back to the lobby.`); - addChatMessage(chat, null, + resetChat(room); + addChatMessage(room, null, `All persons are back to the lobby.`); + addChatMessage(room, null, `The chat has been reset. You can play again with this board, or `+ `click 'New board' to mix things up a bit.`); - sendChatToPersons(chat); + sendChatToPersons(room); return; } - addChatMessage(chat, null, `Waiting for ${waitingFor.join(',')} to go to lobby.`); - sendUpdateToPersons(chat, { - chat: chat.chat + addChatMessage(room, null, `Waiting for ${waitingFor.join(',')} to go to lobby.`); + sendUpdateToPersons(room, { + chat: room.chat }); } router.ws("/ws/:id", async (ws, req) => { + console.log(`WebSocket`); if (!req.cookies || !req.cookies.person) { ws.send(JSON.stringify({ type: 'error', error: `Unable to find session cookie` })); return; } const { id } = req.params; - const chatId = id; + const roomId = id; const short = `[${req.cookies.person.substring(0, 8)}]`; ws.id = short; - console.log(`${short}: Chat ${chatId} - New connection from client.`); + console.log(`${short}: Chat ${roomId} - New connection from client.`); if (!(id in audio)) { audio[id] = {}; /* List of peer sockets using session.name as index. */ console.log(`${short}: Chat ${id} - New Chat Audio`); @@ -1138,28 +1142,28 @@ router.ws("/ws/:id", async (ws, req) => { * we may miss the first messages from clients */ ws.on('error', async (event) => { console.error(`WebSocket error: `, event.message); - const chat = await loadChat(chatId); + const chat = await loadChat(roomId); if (!chat) { return; } - const session = getSession(chat, req.cookies.person); + const session = getSession(room, req.cookies.person); session.live = false; if (session.ws) { session.ws.close(); session.ws = undefined; } - departLobby(chat, session); + departLobby(room, session); }); ws.on('close', async (event) => { console.log(`${short} - closed connection`); - const chat = await loadChat(chatId); + const chat = await loadChat(roomId); if (!chat) { return; } - const session = getSession(chat, req.cookies.person); + const session = getSession(room, req.cookies.person); if (session.person) { session.person.live = false; } @@ -1174,29 +1178,29 @@ router.ws("/ws/:id", async (ws, req) => { console.log(`${short}:WebSocket closed for ${getName(session)}`); } - departLobby(chat, session); + departLobby(room, session); /* Check for a chat in the Winner state with no more connections * and remove it */ - if (chat.state === 'lobby') { + if (room.state === 'lobby') { let dead = true; - for (let id in chat.sessions) { - if (chat.sessions[id].live && chat.sessions[id].name) { + for (let id in room.sessions) { + if (room.sessions[id].live && room.sessions[id].name) { dead = false; } } if (dead) { - console.log(`${session.id}: No more persons in ${chat.id}. ` + + console.log(`${session.id}: No more persons in ${room.id}. ` + `Removing.`); - addChatMessage(chat, null, `No more active persons in chat. ` + + addChatMessage(room, null, `No more active persons in room. ` + `It is being removed from the server.`); - sendUpdateToPersons(chat, { - chat: chat.chat + sendUpdateToPersons(room, { + chat: room.chat }); - for (let id in chat.sessions) { - if (chat.sessions[id].ws) { - chat.sessions[id].ws.close(); - delete chat.sessions[id]; + for (let id in room.sessions) { + if (room.sessions[id].ws) { + room.sessions[id].ws.close(); + delete room.sessions[id]; } } delete audio[id]; @@ -1218,8 +1222,8 @@ router.ws("/ws/:id", async (ws, req) => { console.error(`${all}: parse error`, message); return; } - const chat = await loadChat(chatId); - const session = getSession(chat, req.cookies.person); + const chat = await loadChat(roomId); + const session = getSession(room, req.cookies.person); if (!session.ws) { session.ws = ws; } @@ -1278,21 +1282,21 @@ router.ws("/ws/:id", async (ws, req) => { } break; case 'pong': - resetDisconnectCheck(chat, req); + resetDisconnectCheck(room, req); break; case 'chat-update': console.log(`${short}: <- chat-update ${getName(session)} - full chat update.`); - sendChatToPerson(chat, session); + sendChatToPerson(room, session); break; case 'person-name': console.log(`${short}: <- person-name:${getName(session)} - setPersonName - ${data.name}`) - error = setPersonName(chat, session, data.name); + error = setPersonName(room, session, data.name); if (error) { sendError(session, error); }else { - saveChat(chat); + saveChat(room); } break; @@ -1300,20 +1304,20 @@ router.ws("/ws/:id", async (ws, req) => { console.log(`${short}: <- set:${getName(session)} ${data.field} = ${data.value}`); switch (data.field) { case 'state': - warning = setChatState(chat, session, data.value); + warning = setChatState(room, session, data.value); if (warning) { sendWarning(session, warning); } else { - saveChat(chat); + saveChat(room); } break; case 'color': - warning = setPersonColor(chat, session, data.value); + warning = setPersonColor(room, session, data.value); if (warning) { sendWarning(session, warning); } else { - saveChat(chat); + saveChat(room); } break; default: @@ -1334,19 +1338,19 @@ router.ws("/ws/:id", async (ws, req) => { case 'id': case 'chat': case 'activities': - update[field] = chat[field]; + update[field] = room[field]; break; case 'name': update.name = session.name; break; case 'unselected': - update.unselected = getFilteredUnselected(chat); + update.unselected = getFilteredUnselected(room); break; case 'private': update.private = session.person; break; case 'persons': - update.persons = getFilteredPersons(chat); + update.persons = getFilteredPersons(room); break; case 'color': console.log(`${session.id}: -> Returning color as ${session.color} for ${getName(session)}`); @@ -1356,9 +1360,9 @@ router.ws("/ws/:id", async (ws, req) => { update.timestamp = Date.now(); break; default: - if (field in chat) { + if (field in room) { console.warn(`${short}: WARNING: Requested GET not-privatized/sanitized field: ${field}`); - update[field] = chat[field]; + update[field] = room[field]; } else { if (field in session) { console.warn(`${short}: WARNING: Requested GET not-sanitized session field: ${field}`); @@ -1370,15 +1374,15 @@ router.ws("/ws/:id", async (ws, req) => { break; } }); - sendUpdateToPerson(chat, session, update); + sendUpdateToPerson(room, session, update); break; case 'chat': console.log(`${short}:${id} - ${data.type} - ${data.message}`) - addChatMessage(chat, session, `${session.name}: ${data.message}`, true); - parseChatCommands(chat, data.message); - sendUpdateToPersons(chat, { chat: chat.chat }); - saveChat(chat); + addChatMessage(room, session, `${session.name}: ${data.message}`, true); + parseChatCommands(room, data.message); + sendUpdateToPersons(room, { chat: room.chat }); + saveChat(room); break; case 'media-status': @@ -1393,7 +1397,7 @@ router.ws("/ws/:id", async (ws, req) => { } if (processed) { - /* saveChat(chat); -- do not save here; only save on changes */ + /* saveChat(room); -- do not save here; only save on changes */ return; } @@ -1412,14 +1416,14 @@ router.ws("/ws/:id", async (ws, req) => { switch (data.type) { case 'clear-chat': console.log(`${short}: <- clear-chat:${getName(session)}`); - warning = clearChat(chat, session); + warning = clearChat(room, session); if (warning) { sendWarning(session, warning); } break; case 'goto-lobby': console.log(`${short}: <- goto-lobby:${getName(session)}`); - warning = gotoLobby(chat, session); + warning = gotoLobby(room, session); if (warning) { sendWarning(session, warning); } @@ -1432,12 +1436,12 @@ router.ws("/ws/:id", async (ws, req) => { /* If action was taken, persist the chat */ if (processed) { - saveChat(chat); + saveChat(room); } /* If the current person took an action, reset the session timer */ - if (processed && session.color === chat.turn.color && chat.state !== 'winner') { - resetTurnTimer(chat, session); + if (processed && session.color === room.turn.color && room.state !== 'winner') { + resetTurnTimer(room, session); } }); @@ -1445,13 +1449,13 @@ router.ws("/ws/:id", async (ws, req) => { /* This will result in the node tick moving forward; if we haven't already * setup the event handlers, a 'message' could come through prior to this * completing */ - const chat = await loadChat(chatId); - if (!chat) { + const room = await loadChat(roomId); + if (!room) { console.error(`Unable to load/create new chat for WS request.`); return; } - const session = getSession(chat, req.cookies.person); + const session = getSession(room, req.cookies.person); session.ws = ws; if (session.person) { session.person.live = true; @@ -1459,27 +1463,27 @@ router.ws("/ws/:id", async (ws, req) => { session.live = true; session.lastActive = Date.now(); if (session.name) { - sendUpdateToPersons(chat, { - persons: getFilteredPersons(chat), - unselected: getFilteredUnselected(chat) + sendUpdateToPersons(room, { + persons: getFilteredPersons(room), + unselected: getFilteredUnselected(room) }); } /* If the current turn person just rejoined, set their turn timer */ - if (chat.turn && chat.turn.color === session.color && chat.state !== 'winner') { - resetTurnTimer(chat, session); + if (room.turn && room.turn.color === session.color && room.state !== 'winner') { + resetTurnTimer(room, session); } if (session.name) { if (session.color) { - addChatMessage(chat, null, `${session.name} has reconnected to the chat.`); + addChatMessage(room, null, `${session.name} has reconnected to the room.`); } else { - addChatMessage(chat, null, `${session.name} has rejoined the lobby.`); + addChatMessage(room, null, `${session.name} has rejoined the lobby.`); } - sendUpdateToPersons(chat, { chat: chat.chat }); + sendUpdateToPersons(room, { chat: room.chat }); } - resetDisconnectCheck(chat, req); + resetDisconnectCheck(room, req); console.log(`${short}: Chat ${id} - WebSocket connect from ${getName(session)}`); /* Send initial ping to initiate communication with client */ @@ -1492,14 +1496,14 @@ router.ws("/ws/:id", async (ws, req) => { } }); -const getFilteredChatForPerson = (chat, session) => { +const getFilteredChatForPerson = (room, session) => { /* Shallow copy chat, filling its sessions with a shallow copy of * sessions so we can then delete the person field from them */ const reducedChat = Object.assign({}, chat, { sessions: {} }), reducedSessions = []; - for (let id in chat.sessions) { - const reduced = Object.assign({}, chat.sessions[id]); + for (let id in room.sessions) { + const reduced = Object.assign({}, room.sessions[id]); if (reduced.person) { delete reduced.person; } @@ -1509,7 +1513,7 @@ const getFilteredChatForPerson = (chat, session) => { if (reduced.keepAlive) { delete reduced.keepAlive; } - reducedchat.sessions[id] = reduced; + reducedroom.sessions[id] = reduced; /* Do not send session-id as those are secrets */ reducedSessions.push(reduced); @@ -1518,12 +1522,12 @@ const getFilteredChatForPerson = (chat, session) => { const person = session.person ? session.person : undefined; /* Strip out data that should not be shared with persons */ - delete reducedchat.developmentCards; + delete reducedroom.developmentCards; /* Delete the chat timer */ - delete reducedchat.turnTimer; + delete reducedroom.turnTimer; - reducedchat.unselected = getFilteredUnselected(chat); + reducedroom.unselected = getFilteredUnselected(room); return Object.assign(reducedChat, { live: true, @@ -1531,29 +1535,29 @@ const getFilteredChatForPerson = (chat, session) => { status: session.error ? session.error : "success", name: session.name, color: session.color, - order: (session.color in chat.persons) ? chat.persons[session.color].order : 0, + order: (session.color in room.persons) ? room.persons[session.color].order : 0, private: person, sessions: reducedSessions, layout: layout, - persons: getFilteredPersons(chat), + persons: getFilteredPersons(room), }); } -const resetChat = (chat) => { - Object.assign(chat, { +const resetChat = (room) => { + Object.assign(room, { startTime: Date.now(), state: 'lobby', chat: [], activities: [], - persons: chat.persons, + persons: room.persons, active: 0 }); - stopTurnTimer(chat); + stopTurnTimer(room); /* Populate the chat corner and road placement data as cleared */ for (let i = 0; i < layout.corners.length; i++) { - chat.placements.corners[i] = { + room.placements.corners[i] = { color: undefined, type: undefined }; @@ -1561,19 +1565,19 @@ const resetChat = (chat) => { /* Reset all person data, and add in any missing colors */ [ 'R', 'B', 'W', 'O' ].forEach(color => { - if (color in chat.persons) { - clearPerson(chat.persons[color]); + if (color in room.persons) { + clearPerson(room.persons[color]); } else { - chat.persons[color] = newPerson(color); + room.persons[color] = newPerson(color); } }); /* Ensure sessions are connected to person objects */ - for (let key in chat.sessions) { - const session = chat.sessions[key]; + for (let key in room.sessions) { + const session = room.sessions[key]; if (session.color) { - chat.active++; - session.person = chat.persons[session.color]; + room.active++; + session.person = room.persons[session.color]; session.person.status = 'Active'; session.person.lastActive = Date.now(); session.person.live = session.live; @@ -1597,7 +1601,7 @@ const createChat = (id) => { } console.log(`${info}: creating ${id}`); - const chat = { + const room = { id: id, persons: { O: newPerson('O'), @@ -1607,14 +1611,15 @@ const createChat = (id) => { }, sessions: {}, unselected: [], + chat: [], active: 0, }; - addChatMessage(chat, null, `New chat created: ${chat.id}`); + addChatMessage(room, null, `New chat created: ${room.id}`); - chats[chat.id] = chat; - audio[chat.id] = {}; - return chat; + chats[room.id] = room; + audio[room.id] = {}; + return room; }; /* Simple NO-OP to set session cookie so person-id can use it as the @@ -1647,12 +1652,12 @@ router.post("/:id?", async (req, res/*, next*/) => { if (id) { console.log(`[${personId.substring(0,8)}]: Attempting load of ${id}`); } else { - console.log(`[${personId.substring(0,8)}]: Creating new chat.`); + console.log(`[${personId.substring(0,8)}]: Creating new room.`); } - const chat = await loadChat(id); /* will create chat if it doesn't exist */ - console.log(`[${personId.substring(0,8)}]: ${chat.id} loaded.`); + const room = await loadChat(id); /* will create chat if it doesn't exist */ + console.log(`[${personId.substring(0,8)}]: ${room.id} loaded.`); - return res.status(200).send({ id: chat.id }); + return res.status(200).send({ id: room.id }); });