From: Benjamin Auder <benjamin.auder@somewhere> Date: Sat, 18 Jan 2020 13:07:22 +0000 (+0100) Subject: Chat is working X-Git-Url: https://git.auder.net/variants/Chakart/doc/scripts/css/DESCRIPTION?a=commitdiff_plain;h=5c8e044f7bab43ca8573fdf631f9b87daeda3ad0;p=vchess.git Chat is working --- diff --git a/client/src/components/Chat.vue b/client/src/components/Chat.vue index 364f574c..b4970f70 100644 --- a/client/src/components/Chat.vue +++ b/client/src/components/Chat.vue @@ -1,69 +1,69 @@ <template lang="pug"> -div - div +.row + .col-sm-12.col-md-10.col-md-offset-1.col-lg-8.col-lg-offset-2 + // TODO: Chat modal sur petit écran, dans la page pour grand écran .card.smallpad h4 Chat - p(v-for="chat in chats" :class={ - "my-chatmsg": "chat.uid==user.id", - "opp-chatmsg": "opponents.any(o => o.id == chat.uid)"} - v-html="chat.msg") - input#inputChat(type="text" placeholder="st.tr['Type here']" + p(v-for="chat in chats" :class="classObject(chat)" v-html="chat.msg") + input#inputChat(type="text" :placeholder="st.tr['Type here']" @keyup.enter="sendChat") button#sendChatBtn(@click="sendChat") {{ st.tr["Send"] }} </template> <script> -// TODO: myname, opponents (optional, different style), people -// --> also show messages like "X offers draw" ? +import { store } from "@/store"; + export default { name: "my-chat", - props: ["opponents","people"], + props: ["players"], data: function() { return { + st: store.state, chats: [], //chat messages after human game }; }, -// // TODO: Chat modal sur petit écran, dans la page pour grand écran -// created: function() { -// const socketMessageListener = msg => { -// const data = JSON.parse(msg.data); -// switch (data.code) -// { -// case "newchat": -// // TODO: new chat just arrived: data contain all informations -// // (uid, name, message; no need for timestamp, we can use local time here) -// this.chats.push({msg:data.msg, author:this.oppid}); -// break; -// // TODO: distinguish these (dis)connect events from their analogs in game.js -// // TODO: implement and harmonize: opponents and people are arrays, not objects ?! -// case "connect": -// this.players.push({name:data.name, id:data.uid}); -// break; -// case "disconnect": -// const pIdx = this.players.findIndex(p => p.id == data.uid); -// this.players.splice(pIdx); -// break; -// } -// }; -// const socketCloseListener = () => { -// this.conn.addEventListener('message', socketMessageListener); -// this.conn.addEventListener('close', socketCloseListener); -// }; -// this.conn.onmessage = socketMessageListener; -// this.conn.onclose = socketCloseListener; -// }, -// methods: { -// // TODO: complete this component -// sendChat: function() { -// let chatInput = document.getElementById("input-chat"); -// const chatTxt = chatInput.value; -// chatInput.value = ""; -// this.chats.push({msg:chatTxt, author:this.myid}); -// this.conn.send(JSON.stringify({ -// code:"newchat", oppid: this.oppid, msg: chatTxt})); -// }, -//// startChat: function(e) { -//// document.getElementById("modal-chat").checked = true; -//// }, + created: function() { + const socketMessageListener = msg => { + const data = JSON.parse(msg.data); + if (data.code == "newchat") //only event at this level + { + this.chats.push({msg:data.msg, + name:data.name || "@nonymous", sid:data.sid}); + } + }; + const socketCloseListener = () => { + store.socketCloseListener(); //reinitialize connexion (in store.js) + this.st.conn.addEventListener('message', socketMessageListener); + this.st.conn.addEventListener('close', socketCloseListener); + }; + this.st.conn.onmessage = socketMessageListener; + this.st.conn.onclose = socketCloseListener; }, -}); + methods: { + classObject: function(chat) { + return { + "my-chatmsg": chat.sid == this.st.user.sid, + "opp-chatmsg": this.players.some( + p => p.sid == chat.sid && p.sid != this.st.user.sid) + }; + }, + sendChat: function() { + let chatInput = document.getElementById("inputChat"); + const chatTxt = chatInput.value; + chatInput.value = ""; + const chat = {msg:chatTxt, name: this.st.user.name || "@nonymous", + sid:this.st.user.sid}; + this.chats.push(chat); + this.st.conn.send(JSON.stringify({ + code:"newchat", msg:chatTxt, name:chat.name})); + }, + }, +}; +</script> + +<style lang="sass"> +.my-chatmsg + color: grey +.opp-chatmsg + color: black +</style> diff --git a/client/src/views/Game.vue b/client/src/views/Game.vue index 6a67400d..8fbc9d0b 100644 --- a/client/src/views/Game.vue +++ b/client/src/views/Game.vue @@ -18,13 +18,12 @@ button(@click="() => abortGame()") Abort button(@click="resign") Resign textarea(v-if="game.score=='*'" v-model="corrMsg") - Chat( + Chat(:players="game.players") </template> <!-- // ==> après, implémenter/vérifier les passages de challenges + parties en cours // observer, -// when send to chat (or a move), reach only this group (send gid along) --> <script> @@ -40,6 +39,7 @@ export default { name: 'my-game', components: { BaseGame, + Chat, }, // gameRef: to find the game in (potentially remote) storage data: function() { diff --git a/server/package-lock.json b/server/package-lock.json index 8ad645de..16d7de67 100644 --- a/server/package-lock.json +++ b/server/package-lock.json @@ -52,11 +52,11 @@ } }, "ajv": { - "version": "6.10.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz", - "integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==", + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.11.0.tgz", + "integrity": "sha512-nCprB/0syFYy9fVYU1ox1l2KN8S9I+tziH8D4zdZuLT3N6RMlGSGt5FSTpAiHB/Whv8Qs1cWHma1aMKZyaHRKA==", "requires": { - "fast-deep-equal": "^2.0.1", + "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" @@ -389,9 +389,9 @@ "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" }, "aws4": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", - "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==" + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.9.1.tgz", + "integrity": "sha512-wMHVg2EOHaMRxbzgFJ9gtjOOCrI80OHLG14rxi28XwOW8ux6IiEbRCGGGqCtdAIg4FQCbW20k9RsT4y3gJlFug==" }, "babel-runtime": { "version": "6.26.0", @@ -1652,14 +1652,14 @@ } }, "fast-deep-equal": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", - "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=" + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz", + "integrity": "sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA==" }, "fast-json-stable-stringify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", - "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" }, "file-uri-to-path": { "version": "1.0.0", @@ -2440,7 +2440,7 @@ }, "get-stream": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "resolved": "http://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", "dev": true }, @@ -2568,7 +2568,7 @@ }, "got": { "version": "6.7.1", - "resolved": "https://registry.npmjs.org/got/-/got-6.7.1.tgz", + "resolved": "http://registry.npmjs.org/got/-/got-6.7.1.tgz", "integrity": "sha1-JAzQV4WpoY5WHcG0S0HHY+8ejbA=", "dev": true, "requires": { @@ -2750,9 +2750,9 @@ }, "dependencies": { "readable-stream": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz", - "integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==", + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.5.0.tgz", + "integrity": "sha512-gSz026xs2LfxBPudDuI41V1lka8cxg64E66SGe78zJlsUofOg/yqwezdIcdfwik6B4h8LFmWPA9ef9X3FiNFLA==", "requires": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -3033,7 +3033,7 @@ }, "is-obj": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", + "resolved": "http://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=", "dev": true }, @@ -3584,9 +3584,7 @@ "nan": { "version": "2.14.0", "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", - "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==", - "dev": true, - "optional": true + "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==" }, "nanomatch": { "version": "1.2.13", @@ -3752,14 +3750,22 @@ } }, "npm-bundled": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.0.6.tgz", - "integrity": "sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g==" + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.1.tgz", + "integrity": "sha512-gqkfgGePhTpAEgUsGEgcq1rqPXA+tv/aVBlgEzfXwA1yiUJF7xtEt3CtVwOjNYQOVknDk0F20w58Fnm3EtG0fA==", + "requires": { + "npm-normalize-package-bin": "^1.0.1" + } + }, + "npm-normalize-package-bin": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz", + "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==" }, "npm-packlist": { - "version": "1.4.6", - "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.6.tgz", - "integrity": "sha512-u65uQdb+qwtGvEJh/DgQgW1Xg7sqeNbmxYyrvlNznaVTjV3E5P6F/EFjM+BVHXl7JJlsdG8A64M0XI8FI/IOlg==", + "version": "1.4.7", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.7.tgz", + "integrity": "sha512-vAj7dIkp5NhieaGZxBJB8fF4R0078rqsmhJcAfXZ6O7JJhjhPK96n5Ry1oZcfLXgfun0GWTZPOxaEyqv8GBykQ==", "requires": { "ignore-walk": "^3.0.1", "npm-bundled": "^1.0.1" @@ -4115,9 +4121,9 @@ "dev": true }, "postcss": { - "version": "7.0.23", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.23.tgz", - "integrity": "sha512-hOlMf3ouRIFXD+j2VJecwssTwbvsPGJVMzupptg+85WA+i7MwyrydmQAgY3R+m0Bc0exunhbJmijy8u8+vufuQ==", + "version": "7.0.26", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.26.tgz", + "integrity": "sha512-IY4oRjpXWYshuTDFxMVkJDtWIk2LhsTlu8bZnbEJA4+bYT16Lvpo8Qv6EvDumhYRgzjZl489pmsY3qVgJQ08nA==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -4175,9 +4181,9 @@ "dev": true }, "psl": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.4.0.tgz", - "integrity": "sha512-HZzqCGPecFLyoRj5HLfuDSKYTJkAfB5thKBIkRHtGjWwY7p1dAyveIbXIq4tO0KYfDF2tHqPUgY9SDnGm00uFw==" + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.7.0.tgz", + "integrity": "sha512-5NsSEDv8zY70ScRnOTn7bK7eanl2MvFrOrS/R6x+dBt5g1ghnj9Zv90kO8GwT8gxcu2ANyFprnFYB85IogIJOQ==" }, "pstree.remy": { "version": "1.1.7", @@ -4635,9 +4641,9 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "sanitize-html": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/sanitize-html/-/sanitize-html-1.20.1.tgz", - "integrity": "sha512-txnH8TQjaQvg2Q0HY06G6CDJLVYCpbnxrdO0WN8gjCKaU5J0KbyGYhZxx5QJg3WLZ1lB7XU9kDkfrCXUozqptA==", + "version": "1.21.1", + "resolved": "https://registry.npmjs.org/sanitize-html/-/sanitize-html-1.21.1.tgz", + "integrity": "sha512-W6enXSVphVaVbmVbzVngBthR5f5sMmhq3EfPfBlzBzp2WnX8Rnk7NGpP7KmHUc0Y3MVk9tv/+CbpdHchX9ai7g==", "requires": { "chalk": "^2.4.1", "htmlparser2": "^3.10.0", @@ -5003,20 +5009,13 @@ } }, "sqlite3": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/sqlite3/-/sqlite3-4.1.0.tgz", - "integrity": "sha512-RvqoKxq+8pDHsJo7aXxsFR18i+dU2Wp5o12qAJOV5LNcDt+fgJsc2QKKg3sIRfXrN9ZjzY1T7SNe/DFVqAXjaw==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/sqlite3/-/sqlite3-4.1.1.tgz", + "integrity": "sha512-CvT5XY+MWnn0HkbwVKJAyWEMfzpAPwnTiB3TobA5Mri44SrTovmmh499NPQP+gatkeOipqPlBLel7rn4E/PCQg==", "requires": { "nan": "^2.12.1", "node-pre-gyp": "^0.11.0", "request": "^2.87.0" - }, - "dependencies": { - "nan": { - "version": "2.14.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", - "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==" - } } }, "srcset": { @@ -5125,7 +5124,7 @@ }, "strip-eof": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "resolved": "http://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", "dev": true }, @@ -5593,9 +5592,9 @@ "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" }, "uuid": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz", - "integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==" + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" }, "v8flags": { "version": "3.1.1", diff --git a/server/package.json b/server/package.json index 6dc2d7fd..02cf8678 100644 --- a/server/package.json +++ b/server/package.json @@ -14,9 +14,9 @@ "node-cron": "^2.0.3", "nodemailer": "^5.1.1", "pug": "^2.0.4", - "sanitize-html": "^1.20.1", + "sanitize-html": "^1.21.1", "serve-favicon": "~2.5.0", - "sqlite3": "^4.1.0", + "sqlite3": "^4.1.1", "ws": "^6.2.1" }, "devDependencies": { diff --git a/server/sockets.js b/server/sockets.js index 3637c8f4..c2fd552b 100644 --- a/server/sockets.js +++ b/server/sockets.js @@ -21,13 +21,16 @@ module.exports = function(wss) { if (!!clients[sid]) return socket.send(JSON.stringify({code:"duplicate"})); clients[sid] = {sock: socket, page: query["page"]}; - const notifyRoom = (page,code) => { + const notifyRoom = (page,code,obj) => { Object.keys(clients).forEach(k => { if (k != sid && clients[k].page == page) - clients[k].sock.send(JSON.stringify({code:code,sid:sid})); + { + clients[k].sock.send(JSON.stringify(Object.assign( + {code:code}, obj))); + } }); }; - notifyRoom(query["page"],"connect"); + notifyRoom(query["page"],"connect",{sid:sid}); socket.on("message", objtxt => { let obj = JSON.parse(objtxt); if (!!obj.target && !clients[obj.target]) @@ -41,9 +44,9 @@ module.exports = function(wss) { k != sid && clients[k].page == curPage)})); break; case "pagechange": - notifyRoom(clients[sid].page, "disconnect"); + notifyRoom(clients[sid].page, "disconnect", {sid:sid}); clients[sid].page = obj.page; - notifyRoom(obj.page, "connect"); + notifyRoom(obj.page, "connect", {sid:sid}); break; case "askidentity": clients[obj.target].sock.send(JSON.stringify( @@ -82,8 +85,8 @@ module.exports = function(wss) { {code:"game", game:obj.game, from:sid})); break; case "newchat": - clients[obj.target].sock.send(JSON.stringify( - {code:"newchat",msg:obj.msg})); + notifyRoom(query["page"], "newchat", + {msg:obj.msg, name:obj.name, sid:sid}) break; // TODO: WebRTC instead in this case (most demanding?) case "newmove":