24 changed files with 2323 additions and 0 deletions
@ -0,0 +1,50 @@ |
|||||||
|
Recreate Love Letter as Browser Game (not for profit) |
||||||
|
|
||||||
|
Design Envisioned UI |
||||||
|
Pick Modules around it |
||||||
|
Express |
||||||
|
Socket.IO |
||||||
|
|
||||||
|
Design Data Format |
||||||
|
- Handle Multiple Games |
||||||
|
- Allow Invites to Game |
||||||
|
Design Backend |
||||||
|
Design FrontEnd |
||||||
|
Design an Invite Feature |
||||||
|
Make it reconnectable |
||||||
|
No logins, but have unique IDs |
||||||
|
Make it https |
||||||
|
Animations |
||||||
|
Design Chat |
||||||
|
Design Guide on how to play |
||||||
|
Design Bots to play against |
||||||
|
|
||||||
|
#Basic setup with socket.io + Express |
||||||
|
https://medium.com/@raj_36650/integrate-socket-io-with-node-js-express-2292ca13d891 |
||||||
|
|
||||||
|
#Guide for HTTPs on Express, SSL Cert |
||||||
|
https://medium.com/@nitinpatel_20236/how-to-create-an-https-server-on-localhost-using-express-366435d61f28 |
||||||
|
|
||||||
|
#Socket.IO handling Cleaner |
||||||
|
https://socket.io/docs/v4/server-application-structure/ |
||||||
|
|
||||||
|
#Automatic Node Reload on changes |
||||||
|
https://stackoverflow.com/questions/45622125/how-can-i-add-live-reload-to-my-nodejs-server |
||||||
|
|
||||||
|
#socket.io, socket attributes |
||||||
|
https://socket.io/docs/v4/client-socket-instance/ |
||||||
|
|
||||||
|
#MEVN stack. MongoDB, Express, VueJS, NodeJs |
||||||
|
https://vegibit.com/vue-js-express-tutorial/ |
||||||
|
https://mfikri.com/en/blog/nodejs-express-mysql-vue |
||||||
|
|
||||||
|
Install VUE Global |
||||||
|
npm install -g @vue/cli |
||||||
|
vue --version |
||||||
|
|
||||||
|
|
||||||
|
___________________________________________________________________ |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Binary file not shown.
@ -0,0 +1,20 @@ |
|||||||
|
-----BEGIN CERTIFICATE----- |
||||||
|
MIIDWzCCAkOgAwIBAgIURu8OfAXOa5Hi1BdJO2SxEgrItuMwDQYJKoZIhvcNAQEL |
||||||
|
BQAwPTELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAk1PMSEwHwYDVQQKDBhJbnRlcm5l |
||||||
|
dCBXaWRnaXRzIFB0eSBMdGQwHhcNMjIwMjI1MTcwODUzWhcNMjMwMjI1MTcwODUz |
||||||
|
WjA9MQswCQYDVQQGEwJVUzELMAkGA1UECAwCTU8xITAfBgNVBAoMGEludGVybmV0 |
||||||
|
IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB |
||||||
|
ANBWoQWSX8iyRuuMzN78ALkVLoEDGhQivpAj18n5VT4WNhpT3z7Gj2B2w6w3vsKv |
||||||
|
XN28qILNBUcApzHMCawk4XyGgkTrFQzs2jTm5DKuU6dhn7lioMNzDgRVGieBuA0N |
||||||
|
La3qa0gwem+fhJoT0Dm4tDeEoFEJeura6y0u/XRLm+uKSiLyo0tX12OYjgbbWh8Q |
||||||
|
32aE6p0QqcHdFYRnUs5iy/SLkmYoMqNBrQWGAmjkYbHhwc2LhwvWEhv6HACE8Fk7 |
||||||
|
QkAScf8V2CX/xpgqjJWgAhTp5zE/YKWQc4RH0hF2wMmVnMEDB7vmRPSuuRBlo+7y |
||||||
|
DZTMPjg5KZ3jAwfzbQOLew8CAwEAAaNTMFEwHQYDVR0OBBYEFM582p8EGMRs3IVj |
||||||
|
Q7pq20cNc+FWMB8GA1UdIwQYMBaAFM582p8EGMRs3IVjQ7pq20cNc+FWMA8GA1Ud |
||||||
|
EwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAA2d+WnGBysGoZMOkLt4hkb+ |
||||||
|
UNp6oFcGNa/kd06UuEpFinsa82JPsAZWSNDNLqzTfTaUWFXCQkIGk2k/57NXOjXZ |
||||||
|
3PhMJfjeR9jH3XRswxK9Dp8KaVyf1GTMbI6K+IKEULK/w2sOCAHEHVntIEPo5tCo |
||||||
|
P4NAEmc0woPmm4NTqHU98zRR8Mqxu+112tOg3u+f6fr1YCI4o2jJeaDRdgivFYSr |
||||||
|
V68YHq3GthzHxXLqynZBTReX8vF6fTzc7jaB79UFkgIuBwPscVYubk3PPJI0TQ38 |
||||||
|
rR7nHmC6yB60Zsg+1TuCG5czS/TZuJUMoqj3hjTXVxPTaLgnga7vBBa+Gw21OYQ= |
||||||
|
-----END CERTIFICATE----- |
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,27 @@ |
|||||||
|
-----BEGIN RSA PRIVATE KEY----- |
||||||
|
MIIEogIBAAKCAQEA0FahBZJfyLJG64zM3vwAuRUugQMaFCK+kCPXyflVPhY2GlPf |
||||||
|
PsaPYHbDrDe+wq9c3byogs0FRwCnMcwJrCThfIaCROsVDOzaNObkMq5Tp2GfuWKg |
||||||
|
w3MOBFUaJ4G4DQ0treprSDB6b5+EmhPQObi0N4SgUQl66trrLS79dEub64pKIvKj |
||||||
|
S1fXY5iOBttaHxDfZoTqnRCpwd0VhGdSzmLL9IuSZigyo0GtBYYCaORhseHBzYuH |
||||||
|
C9YSG/ocAITwWTtCQBJx/xXYJf/GmCqMlaACFOnnMT9gpZBzhEfSEXbAyZWcwQMH |
||||||
|
u+ZE9K65EGWj7vINlMw+ODkpneMDB/NtA4t7DwIDAQABAoIBAAYoWVAB2ITlCAWU |
||||||
|
PsXkat0NjDdR8SZhNIKsHIeir+tK2sSCcBm54qj2OahQaXn1lugS2GQtTRehJE/r |
||||||
|
eOm2mVeF3jnNPO0J3xUrMdlxn5VV5FOlX50HPIXSQhii097G4e+++vbCQAwmidPH |
||||||
|
/CKInAL8D4T1o8VnPQYz2lfimDQo7361mCytz0VEoPqAtXEHiyxq3ID9YZxFUGg1 |
||||||
|
XFo63IhFp7fJU+mjmDLcSmCO+IAz7avdPWRKr2Fz7tI0+AipaaZSi8M+ej0IqHZs |
||||||
|
nRzhxwVz60aVmVgdZsOfemqBR9+b9TTLSxyN4j7cjPv69w1g2pUki3rtFAuyPs/x |
||||||
|
iaifp4kCgYEA+062Qic13JvI1werJqdE/UAIbEDOt5KGHJVpLnhScwqer7q3RmCs |
||||||
|
xKZND4WJ64WfW9z+vkinswPfPgruNok/x8qVf673PGDEXimK2/jkRy0CKzLzdcHr |
||||||
|
3tgRRTcu5Ejr1u/VIV+9axcmmODlHUYAUbRDssqf80g6jy+e7ra2/YMCgYEA1DqE |
||||||
|
sCN5WJsnTnA6pjhcLcC3UQxQZ5d+iCEc/nWfYRcZsKdWh7A1xY2MDEiLWqj28x4G |
||||||
|
mtThfu1f879t/N4yasQ7QA16RBQlquY4qfBGYcwoqY5e9V4xFg6kgTl6bgdcFc7/ |
||||||
|
p7wcUm6KqD5PnxCSlOOwPlCUuPELHHXSf1YKQoUCgYBr/GGiwXiKiEJf68KmhF/H |
||||||
|
trkn0x1AkmygYa9lsXw0RM71UfUo/6edhJw+XDJsiul0Lt0j5NJywOovncDInGdU |
||||||
|
sX9V81f3kNkwYQdzCFsHHpb8+xLUefShuBSLum+i1pbIsBvUEHCzUKpcLN8mmgrP |
||||||
|
EPe6HwlmH5ZSKrNPfiHZgwKBgGCRxCDV83hzGR6jCLzr9l3HTGLvxIJut9+/mY7b |
||||||
|
/MrUFReB/Wi+sKkU8H4CYI6/Rad4qS644Wa9IqUqHSUsAir84a0StOjXdhBes7f4 |
||||||
|
Ij6MBJCqvODPnGxZ+1blzaTVanxt9Xzgps6HiEZoHBjYFKr1NBQW3KWO4SxxHHhe |
||||||
|
sUp1AoGADiduIMYTCQK9tTwzC+wi8L9ZzRzg8Bv9WoJwlOJ9UzebxZuoSE079WZy |
||||||
|
R83WGVMfrGoRvt5o5zPPjXE1OVb1ZH/zqVxMqtXyNKpkaNA3zg3B+yd0t6j7r6KF |
||||||
|
3rmR4RZQ4tvG4zSvoB6wRnQCMu5yT4Hy5UCO2okxUf/9ipkBxrI= |
||||||
|
-----END RSA PRIVATE KEY----- |
||||||
@ -0,0 +1,30 @@ |
|||||||
|
-----BEGIN ENCRYPTED PRIVATE KEY----- |
||||||
|
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 |
||||||
|
t4drORAApx1BSzNTI0xTWg== |
||||||
|
-----END ENCRYPTED PRIVATE KEY----- |
||||||
@ -0,0 +1,22 @@ |
|||||||
|
-----BEGIN CERTIFICATE----- |
||||||
|
MIIDpzCCAo+gAwIBAgIUVgja2cJarOptGTXo5bwdUx2WGLswDQYJKoZIhvcNAQEL |
||||||
|
BQAwYzELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAk1PMQswCQYDVQQHDAJLQzESMBAG |
||||||
|
A1UECgwJbG9jYWxob3N0MRIwEAYDVQQLDAlsb2NhbGhvc3QxEjAQBgNVBAMMCWxv |
||||||
|
Y2FsaG9zdDAeFw0yMjAzMjkxNzU5MjVaFw0yMjA0MjgxNzU5MjVaMGMxCzAJBgNV |
||||||
|
BAYTAlVTMQswCQYDVQQIDAJNTzELMAkGA1UEBwwCS0MxEjAQBgNVBAoMCWxvY2Fs |
||||||
|
aG9zdDESMBAGA1UECwwJbG9jYWxob3N0MRIwEAYDVQQDDAlsb2NhbGhvc3QwggEi |
||||||
|
MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDpc68E8r32hLbMPUawJZwTaQn2 |
||||||
|
RoGMHoOSzfHqOXcjF0D0QIOgeO2uMYJ6nMh4AfSKjRkOK2oJO4fknp72ArrK+S7x |
||||||
|
KVaMg6T0FaVsffFYJO8/aujUBhnEyF+dAtyveABfMrJwU+/uTuwKJAJz7wvOl+3/ |
||||||
|
7Idop49PAWo64HYlJkl3iQUuVmBL2kpyrHLNnTIT8HBKsLJVnO2IzozQnTrI0CnF |
||||||
|
PFgdqjdPyTurJYhIYRNsSL1ZpTBdWoeZPCWIjYGr9X4Om4aaAkD3bWmaPNYwIaja |
||||||
|
GwBaCfKTnGw9+EWDXrQxZfpOqVJp/19ZFTsoMGIJo0LtPRgmOwAFkjSfXwArAgMB |
||||||
|
AAGjUzBRMB0GA1UdDgQWBBRFm+iZPyUN8ZMfGfnWO3iBbas15DAfBgNVHSMEGDAW |
||||||
|
gBRFm+iZPyUN8ZMfGfnWO3iBbas15DAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3 |
||||||
|
DQEBCwUAA4IBAQDacoUJOm0Y8vm8hwqgqres3kYD2sQAYMsU146hfUeNfcRXIYYK |
||||||
|
TLFiu6/bEc+85riZerZQCDFzPcVGJT4NPTkQkofYhkPG8UpDdEH/o8kZn5icDYoX |
||||||
|
KcB/V8mOtSi+zN3Hol88XmfMkFDxeNYkUvI2vfycAE8PR21pKcnR6UROZBkMuCMC |
||||||
|
p/wJY6cmaPNKwZGaGLWqlNcOFV1xEYQnFYm3IYsBjnQslhyU4Wpnd6MiZQ3uoerk |
||||||
|
9fl4IGsu3BAkTkdAaibsnmUp4/SorvGoYi+hGJ/NvPherMjsINVP5MNH+uUqf2QT |
||||||
|
f6nor/JgODkq1BXSAYJxY4xtD6hYNm/qWh6w |
||||||
|
-----END CERTIFICATE----- |
||||||
@ -0,0 +1,28 @@ |
|||||||
|
-----BEGIN PRIVATE KEY----- |
||||||
|
MIIEwAIBADANBgkqhkiG9w0BAQEFAASCBKowggSmAgEAAoIBAQDpc68E8r32hLbM |
||||||
|
PUawJZwTaQn2RoGMHoOSzfHqOXcjF0D0QIOgeO2uMYJ6nMh4AfSKjRkOK2oJO4fk |
||||||
|
np72ArrK+S7xKVaMg6T0FaVsffFYJO8/aujUBhnEyF+dAtyveABfMrJwU+/uTuwK |
||||||
|
JAJz7wvOl+3/7Idop49PAWo64HYlJkl3iQUuVmBL2kpyrHLNnTIT8HBKsLJVnO2I |
||||||
|
zozQnTrI0CnFPFgdqjdPyTurJYhIYRNsSL1ZpTBdWoeZPCWIjYGr9X4Om4aaAkD3 |
||||||
|
bWmaPNYwIajaGwBaCfKTnGw9+EWDXrQxZfpOqVJp/19ZFTsoMGIJo0LtPRgmOwAF |
||||||
|
kjSfXwArAgMBAAECggEBANlkzfXYqod3HNbitQHxc/8rUIiTLa4y+ClsOLv6GXSH |
||||||
|
AgiyTyDPm94b4rqVZ6VBhNzE+jEUwqCoXCrMf5DuB85d75XJ/fvJ14Eo6yw1t9py |
||||||
|
Qo0W3IwcxkBWq5sGAEYyhH4iMsKhl4ue2PW0hMg7Mg6Hsq0hMROG/c//rFH5lmuO |
||||||
|
DXuTG+iaJXbQn+TT/i2aSESuXDdKFM9LfB4k4VS+OCKYxFT38fFEI/lzeABc2tsh |
||||||
|
g48PGdVgZjfcjVLzziwyG0TL7XjPuqSe4rFTTea79LTbXp/ck50ivqKT4TpdD7Ck |
||||||
|
7kPTFkrXxyg74V+brD0vpJpmu54sFU2/G0z4CDZIGOECgYEA+IOEMTIqBDFtPrEc |
||||||
|
IbBZWodfKMaOJqRq1ifypcMsZeSXNS2zjg4isdonh0WXsZXMUq04T1yh2d1MPcjP |
||||||
|
Glc16dfpsEzF/f96ujjCJ7RA+QjQQ3K8mVAfjLr9hRbrqCMVHLo5DQ+rw5Uw5C6o |
||||||
|
6z8ZeexFxLsHKh341akKi0waKHECgYEA8HwDfOhtsCySbSW65+h2y77K4s+EYyPh |
||||||
|
6V0fGrIDrUtGVkAfmkpMEpjU+qempklKt5/mFqkWkXbjGUD+vz413ZMObsXaEPKU |
||||||
|
JZ+XGuD9D80vfxqZp7w3Fjhzh8A23jYICFv3joZ0qs5M5jV67nFCW0ffh4ehD6dZ |
||||||
|
o5N/CUuMoFsCgYEAzJ8tl3xgkDdKZlZafXrA+AOC3QYwQa0bst4Ns2MzCWrg/g51 |
||||||
|
S8Bj3OFtrroknzpilKjANshlFAhdIHpZ3Kx2XedEKb/tPqi/mtnlM9/9p5AUO5Ub |
||||||
|
qXkJoUzONmma/ER2u8Kx+wkuOsp7CUdKGvlHttZO1B/TVGB9ZR/c6LluyGECgYEA |
||||||
|
v9iPB8R8TMEiBwTEeGFQ8/U+8XXPDTAA9yQcvjUpDcQxVnlNPM7spSFbNqMsJRfv |
||||||
|
DVH4QjeeE2meffUFxRch7aN1LhWUg1ShruoDp6O4/jQYIfPchJ137LgYIkHLA7Zi |
||||||
|
7hhAA2lsBR8S5cvgR/v+jcdmoT4n1M8SiZYPECE/DGUCgYEAnh5lIWpDdw2vcnW4 |
||||||
|
/lgb1I9oXRZcLIYha+WhC6PXHAUqdTAk+afefmjF1QEIgu2lYZQU28TZDcTn2OgN |
||||||
|
PVPuKItJjoTz/c6npgLABkn6dDuRfnAfFV2tj6mPmqQ70A9B8B4ql3f3tbiQOQPC |
||||||
|
ZXPCc/cVEOJnBGT7wtZTdhP6eV8= |
||||||
|
-----END PRIVATE KEY----- |
||||||
@ -0,0 +1,14 @@ |
|||||||
|
let validCharacters = ['0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'] |
||||||
|
|
||||||
|
genRandomString = (stringLength) => { |
||||||
|
let newString = '' |
||||||
|
for (let i = 0; i < stringLength; i++) { |
||||||
|
$index = Math.floor(Math.random() * 35) |
||||||
|
newString += validCharacters[$index] |
||||||
|
} |
||||||
|
return newString |
||||||
|
} |
||||||
|
|
||||||
|
module.exports = { |
||||||
|
genRandomString: genRandomString |
||||||
|
} |
||||||
@ -0,0 +1,16 @@ |
|||||||
|
// // sleep function
|
||||||
|
// const sleep = (milliseconds) => {
|
||||||
|
// const date = Date.now()
|
||||||
|
// let currentDate = null
|
||||||
|
// do {
|
||||||
|
// currentDate = Date.now()
|
||||||
|
// } while (currentDate - date < milliseconds)
|
||||||
|
// }
|
||||||
|
|
||||||
|
const sleep = (ms) => { |
||||||
|
return new Promise(resolve => setTimeout(resolve, ms)) |
||||||
|
} |
||||||
|
|
||||||
|
module.exports = { |
||||||
|
sleep: sleep |
||||||
|
} |
||||||
@ -0,0 +1,58 @@ |
|||||||
|
// Make console colors
|
||||||
|
// based on what I found here:
|
||||||
|
// https://www.kindacode.com/article/node-js-colorizing-console-log-output/
|
||||||
|
// color chart found here:
|
||||||
|
// https://en.m.wikipedia.org/wiki/ANSI_escape_code#Colors
|
||||||
|
|
||||||
|
// // red
|
||||||
|
// console.log('\x1b[31m%s\x1b[0m', 'I am red')
|
||||||
|
// // green
|
||||||
|
// console.log('\x1b[32m%s\x1b[0m', 'I am green')
|
||||||
|
// // yellow
|
||||||
|
// console.log('\x1b[33m%s\x1b[0m', 'I am yellow')
|
||||||
|
// // blue
|
||||||
|
// console.log('\x1b[34m%s\x1b[0m', 'I am blue')
|
||||||
|
// // magenta
|
||||||
|
// console.log('\x1b[35m%s\x1b[0m', 'I am magenta')
|
||||||
|
// // cyan
|
||||||
|
// console.log('\x1b[36m%s\x1b[0m', 'I am cyan')
|
||||||
|
|
||||||
|
const wrtColorRed = (text) => { |
||||||
|
console.log('\x1b[31m%s\x1b[0m', text) |
||||||
|
} |
||||||
|
const wrtColorGreen = (text) => { |
||||||
|
console.log('\x1b[32m%s\x1b[0m', text) |
||||||
|
} |
||||||
|
const wrtColorYellow = (text) => { |
||||||
|
console.log('\x1b[33m%s\x1b[0m', text) |
||||||
|
} |
||||||
|
const wrtColorBlue = (text) => { |
||||||
|
console.log('\x1b[34m%s\x1b[0m', text) |
||||||
|
} |
||||||
|
const wrtColorMagenta = (text) => { |
||||||
|
console.log('\x1b[35m%s\x1b[0m', text) |
||||||
|
} |
||||||
|
const wrtColorCyan = (text) => { |
||||||
|
console.log('\x1b[36m%s\x1b[0m', text) |
||||||
|
} |
||||||
|
const wrtErr = (text) => { //Black on Red
|
||||||
|
console.log('\x1b[30;41m%s\x1b[0m', text) |
||||||
|
} |
||||||
|
const wrtWarn = (text) => { //Black on Red
|
||||||
|
console.log('\x1b[30;43m%s\x1b[0m', text) |
||||||
|
} |
||||||
|
const wrtTest = (text) => { // Green on Black
|
||||||
|
console.log('\x1b[92;100m%s\x1b[0m', text) |
||||||
|
} |
||||||
|
|
||||||
|
module.exports = { |
||||||
|
red: wrtColorRed, |
||||||
|
green: wrtColorGreen, |
||||||
|
yellow: wrtColorYellow, |
||||||
|
blue: wrtColorBlue, |
||||||
|
magenta: wrtColorMagenta, |
||||||
|
cyan: wrtColorCyan, |
||||||
|
err: wrtErr, |
||||||
|
warn: wrtWarn, |
||||||
|
test: wrtTest, |
||||||
|
} |
||||||
@ -0,0 +1,29 @@ |
|||||||
|
// Object Definitions
|
||||||
|
class player { |
||||||
|
constructor (userid, |
||||||
|
username, |
||||||
|
gameid, |
||||||
|
lastActivity, |
||||||
|
connected) { |
||||||
|
this.userid = userid |
||||||
|
this.username = username |
||||||
|
this.gameid = gameid |
||||||
|
this.lastActivity = lastActivity |
||||||
|
this.connected = connected |
||||||
|
} |
||||||
|
} |
||||||
|
class table { |
||||||
|
} |
||||||
|
class game { |
||||||
|
} |
||||||
|
// Object Initialization
|
||||||
|
let state = { |
||||||
|
players:[], |
||||||
|
tables:[], |
||||||
|
games:[] |
||||||
|
} |
||||||
|
|
||||||
|
module.exports = { |
||||||
|
state: state, |
||||||
|
players: state.players |
||||||
|
} |
||||||
@ -0,0 +1,32 @@ |
|||||||
|
const serverConfig = require('../../config/serverConfig.js') // Server Config
|
||||||
|
const wrtColor = require('../common/wrtColor') |
||||||
|
// const { sleep } = require('./common/sleep')
|
||||||
|
|
||||||
|
function filterExpired(player) { |
||||||
|
// let diff = ((new Date())-player.lastActivity)
|
||||||
|
// console.log(`${player.username} diff: ${diff}`)
|
||||||
|
if (((new Date())-player.lastActivity) <= serverConfig.playerExpiration) { |
||||||
|
return player |
||||||
|
} else { |
||||||
|
// console.log(`Expired Session: ${player.username}`)
|
||||||
|
wrtColor.magenta(`Expired Session: ${player.username}`) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
function playerCleanup (state) { |
||||||
|
// setInterval(function() { //<--This works, but I'm concerned about Memory Leak. I need to learn more.
|
||||||
|
// console.log(state)
|
||||||
|
// state.players = state.players.filter(checkExpired)
|
||||||
|
// }, serverConfig.cleanupInterval)
|
||||||
|
|
||||||
|
//setTimeout Version self-calling function
|
||||||
|
let timerId = setTimeout(function tick() { |
||||||
|
// console.log(state)
|
||||||
|
state.players = state.players.filter(filterExpired) |
||||||
|
timerId = setTimeout(tick, serverConfig.cleanupInterval) |
||||||
|
}, serverConfig.cleanupInterval) |
||||||
|
} |
||||||
|
|
||||||
|
module.exports = { |
||||||
|
playerCleanup: playerCleanup |
||||||
|
} |
||||||
@ -0,0 +1,66 @@ |
|||||||
|
// Sends Updates to socket when players change
|
||||||
|
const wrtColor = require('../common/wrtColor') |
||||||
|
|
||||||
|
function mapRemoveLastActivityProp (player) { |
||||||
|
// Make this specific by props to remove
|
||||||
|
let {lastActivity, ...other} = player |
||||||
|
// return {
|
||||||
|
// id: player.id,
|
||||||
|
// username: player.username,
|
||||||
|
// gameid: player.gameid
|
||||||
|
// }
|
||||||
|
return other |
||||||
|
} |
||||||
|
|
||||||
|
function continuousEmitPlayers (state,io) { |
||||||
|
let previousPlayersRelevant = [] |
||||||
|
let timerId = setTimeout(function tick() { |
||||||
|
// get players excluding the "lastActivity" because it is constantly updating
|
||||||
|
playersRelevant = state.players.map(mapRemoveLastActivityProp) |
||||||
|
// console.log(playersRelevant)
|
||||||
|
// convert to string for comparison
|
||||||
|
if ((JSON.stringify(playersRelevant)) !== (JSON.stringify(previousPlayersRelevant))) { |
||||||
|
// if changes happen, emit to all sockets
|
||||||
|
// wrtColor.blue('change to Players. Push to Sockets')
|
||||||
|
io.emit('playersUpdate', playersRelevant) |
||||||
|
} |
||||||
|
previousPlayersRelevant = playersRelevant |
||||||
|
timerId = setTimeout(tick, 1000) |
||||||
|
}, 1000) |
||||||
|
} |
||||||
|
|
||||||
|
function socketGetPlayers (state,socket) { |
||||||
|
playersRelevant = state.players.map(mapRemoveLastActivityProp) |
||||||
|
socket.emit('playersUpdate', playersRelevant) |
||||||
|
} |
||||||
|
|
||||||
|
function checkValidPlayerName(players,name) { |
||||||
|
|
||||||
|
let response = { |
||||||
|
valid: true, |
||||||
|
reason: "" |
||||||
|
} |
||||||
|
|
||||||
|
// Returns True/False
|
||||||
|
// 15 character limit
|
||||||
|
// No special characters
|
||||||
|
// name not in use already
|
||||||
|
|
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
function socketRegisterPlayer (io,state,data) { |
||||||
|
wrtColor.warn('socketRegisterPlayer') |
||||||
|
console.log(data) |
||||||
|
//console.log(state.players)
|
||||||
|
io.emit('msg',{poop:"salad"}) |
||||||
|
let checkResult = checkValidPlayerName(state.players, name) |
||||||
|
console.log(checkResult) |
||||||
|
// add them to state.players
|
||||||
|
} |
||||||
|
|
||||||
|
module.exports = { |
||||||
|
continuousEmitPlayers: continuousEmitPlayers, |
||||||
|
socketGetPlayers: socketGetPlayers, |
||||||
|
socketRegisterPlayer: socketRegisterPlayer, |
||||||
|
} |
||||||
@ -0,0 +1,52 @@ |
|||||||
|
// const serverConfig = require('../config/serverConfig.js')
|
||||||
|
const wrtColor = require('./common/wrtColor') |
||||||
|
|
||||||
|
//Load Object Definitions and Initialize them
|
||||||
|
require('./objectDefinitions') |
||||||
|
let { state } = require('./objectDefinitions') |
||||||
|
|
||||||
|
|
||||||
|
// TODO: TEST FUNCTIONS
|
||||||
|
require('./testFunctions') |
||||||
|
const { addTestPlayers, addFluxPlayers } = require('./testFunctions') |
||||||
|
wrtColor.test('adding Test Players') |
||||||
|
addTestPlayers(state.players) |
||||||
|
addFluxPlayers(state) |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//--- Socket Handling ---
|
||||||
|
const { socketGetPlayers } = require('./players/playerMgmtFuncs') |
||||||
|
const { continuousEmitPlayers } = require ('./players/playerMgmtFuncs') |
||||||
|
const { socketRegisterPlayer } = require ('./players/playerMgmtFuncs') |
||||||
|
function socketHandler (io) { |
||||||
|
io.on('connection', function (socket) { |
||||||
|
//--- Connection ---
|
||||||
|
wrtColor.cyan(`socket connection established, id ${socket.id}`) |
||||||
|
|
||||||
|
//--- Register other socket event handler functions ---
|
||||||
|
socket.on('getPlayers', () => socketGetPlayers(state,socket)) |
||||||
|
socket.on('registerPlayer', (data) => socketRegisterPlayer(io,state,data)) |
||||||
|
//......//
|
||||||
|
|
||||||
|
//--- Disconnection ---
|
||||||
|
socket.on('disconnect', (reason) => { wrtColor.yellow(`socket disconnected, ${socket.id}, ${reason}`)}) |
||||||
|
}) |
||||||
|
|
||||||
|
//--- Continuous Processes for Sockets ---
|
||||||
|
continuousEmitPlayers(state,io) |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
//--- Continuous Server Side Processes ---
|
||||||
|
const { playerCleanup } = require('./players/playerCleanup') |
||||||
|
const { stateMonitor } = require('./stateMonitor') |
||||||
|
playerCleanup(state) |
||||||
|
stateMonitor(state) |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = { |
||||||
|
socketHandler: socketHandler |
||||||
|
} |
||||||
|
|
||||||
@ -0,0 +1,22 @@ |
|||||||
|
const serverConfig = require('../config/serverConfig.js') // Server Config
|
||||||
|
const wrtColor = require('./common/wrtColor') |
||||||
|
const fs = require('fs') |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function stateMonitor (state) { |
||||||
|
setInterval(function() { |
||||||
|
// Convert to string
|
||||||
|
let stateString = JSON.stringify(state, null, 2) |
||||||
|
fs.writeFile(serverConfig.stateJsonPath, stateString, (err) => { |
||||||
|
if (err) { |
||||||
|
throw err |
||||||
|
} |
||||||
|
// wrtColor.blue("state.json saved")
|
||||||
|
}) |
||||||
|
}, serverConfig.stateMonitorRate) |
||||||
|
} |
||||||
|
|
||||||
|
module.exports = { |
||||||
|
stateMonitor: stateMonitor |
||||||
|
} |
||||||
@ -0,0 +1,90 @@ |
|||||||
|
const { genRandomString } = require('./common/randomString') |
||||||
|
const serverConfig = require('../config/serverConfig.js') |
||||||
|
const wrtColor = require('./common/wrtColor') |
||||||
|
const { state } = require('./objectDefinitions') |
||||||
|
|
||||||
|
let t = new Date() |
||||||
|
let m15 = t.setSeconds(t.getSeconds()-15) |
||||||
|
let p30 = t.setSeconds(t.getSeconds()+30) |
||||||
|
let p45 = t.setSeconds(t.getSeconds()+45) |
||||||
|
let p60 = t.setSeconds(t.getSeconds()+60) |
||||||
|
|
||||||
|
|
||||||
|
function addTestPlayers(players) { |
||||||
|
players.push({ |
||||||
|
id: genRandomString(serverConfig.playerIdLength), |
||||||
|
username: 'Charlie', |
||||||
|
gameid: 222, |
||||||
|
lastActivity: p30, |
||||||
|
connected: false |
||||||
|
}) |
||||||
|
players.push({ |
||||||
|
id: genRandomString(serverConfig.playerIdLength), |
||||||
|
username: 'Dee', |
||||||
|
gameid: 222, |
||||||
|
lastActivity: p45, |
||||||
|
connected: false |
||||||
|
}) |
||||||
|
players.push({ |
||||||
|
id: genRandomString(serverConfig.playerIdLength), |
||||||
|
username: 'Dennis', |
||||||
|
gameid: 222, |
||||||
|
lastActivity: p60, |
||||||
|
connected: false |
||||||
|
}) |
||||||
|
players.push({ |
||||||
|
id: genRandomString(serverConfig.playerIdLength), |
||||||
|
username: 'Frank', |
||||||
|
gameid: 222, |
||||||
|
lastActivity: m15, |
||||||
|
connected: true |
||||||
|
}) |
||||||
|
players.push({ |
||||||
|
id: genRandomString(serverConfig.playerIdLength), |
||||||
|
username: 'Mac', |
||||||
|
gameid: 222, |
||||||
|
lastActivity: p30, |
||||||
|
connected: true |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
function addFluxPlayers (state) { |
||||||
|
// Add and remove Pondy from players every 5 seconds
|
||||||
|
setInterval(function () { |
||||||
|
// PONDY
|
||||||
|
// console.log(players)
|
||||||
|
let pondyFound = false |
||||||
|
for (let i = 0; i < state.players.length; i++) { |
||||||
|
if (state.players[i].username === 'Pondy') { |
||||||
|
pondyFound = true |
||||||
|
break |
||||||
|
} |
||||||
|
} |
||||||
|
if (pondyFound) { |
||||||
|
// wrtColor.yellow('Pondy Found, removing')
|
||||||
|
let pondyFilteredPlayers = state.players.filter( function (player) { |
||||||
|
if (player.username !== 'Pondy') { |
||||||
|
return player |
||||||
|
} |
||||||
|
}) |
||||||
|
// console.log(pondyFilteredPlayers)
|
||||||
|
state.players = pondyFilteredPlayers |
||||||
|
} else { |
||||||
|
// wrtColor.yellow('Pondy Not Found, adding')
|
||||||
|
let t = new Date() |
||||||
|
let p30 = t.setSeconds(t.getSeconds()+30) |
||||||
|
state.players.push({ |
||||||
|
id: genRandomString(serverConfig.playerIdLength), |
||||||
|
username: 'Pondy', |
||||||
|
gameid: 222, |
||||||
|
lastActivity: p30, |
||||||
|
connected: true |
||||||
|
}) |
||||||
|
} |
||||||
|
}, 5000) |
||||||
|
} |
||||||
|
|
||||||
|
module.exports = { |
||||||
|
addTestPlayers: addTestPlayers, |
||||||
|
addFluxPlayers: addFluxPlayers |
||||||
|
} |
||||||
@ -0,0 +1,18 @@ |
|||||||
|
module.exports = { |
||||||
|
// Server
|
||||||
|
certKeyPath: './cert/server.key', //Called by server.js
|
||||||
|
certPath: './cert/server.cert', //Called by server.js
|
||||||
|
httpsPort: 9000, |
||||||
|
frontEndUrl: 'https://localhost', // Vue running from https
|
||||||
|
//PlayerCleanup
|
||||||
|
cleanupInterval: 5000, // runs every 5 seconds
|
||||||
|
playerExpiration: 60000, //300000, // 5 minutes without activity before being removed
|
||||||
|
//State Monitor
|
||||||
|
stateJsonPath: './log/state.json', |
||||||
|
stateMonitorRate: 1000, |
||||||
|
//Player Settings
|
||||||
|
playersUpdateCheckRate: 500, // Rate between checks to send player updates to sockets
|
||||||
|
|
||||||
|
playerNameMaxLength: 15, |
||||||
|
playerIdLength: 6, |
||||||
|
} |
||||||
@ -0,0 +1,19 @@ |
|||||||
|
{ |
||||||
|
"name": "loveletter", |
||||||
|
"version": "1.0.0", |
||||||
|
"description": "", |
||||||
|
"main": "index.js", |
||||||
|
"scripts": { |
||||||
|
"test": "echo \"Error: no test specified\" && exit 1", |
||||||
|
"start": "node server.js", |
||||||
|
"live": "nodemon server.js --ignore ./log/" |
||||||
|
}, |
||||||
|
"author": "", |
||||||
|
"license": "ISC", |
||||||
|
"dependencies": { |
||||||
|
"cors": "^2.8.5", |
||||||
|
"express": "^4.17.3", |
||||||
|
"socket.io": "^4.4.1", |
||||||
|
"vue-router": "^4.0.13" |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,44 @@ |
|||||||
|
const path = require('path') |
||||||
|
const fs = require('fs') |
||||||
|
const express = require('express') |
||||||
|
const serverConfig = require('./config/serverConfig.js') // Server Config
|
||||||
|
const wrtColor = require('./components/common/wrtColor') |
||||||
|
|
||||||
|
//Http 80 Route traffic to the frontend VUE application running with HTTPS
|
||||||
|
const http = require('http') |
||||||
|
const httpApp = express() |
||||||
|
httpApp.all('*', (req, res) => res.redirect(301, `${serverConfig.frontEndUrl}`)) //301 - Moved Permanently
|
||||||
|
const httpServer = http.createServer(httpApp) |
||||||
|
httpServer.listen(80, () => { |
||||||
|
//console.log(`http redirectiong 80 to Vue front end at ${serverConfig.frontEndUrl}`)
|
||||||
|
wrtColor.green(`http redirectiong 80 to Vue front end at ${serverConfig.frontEndUrl}`) |
||||||
|
}) |
||||||
|
|
||||||
|
//Https to run socket.io
|
||||||
|
const https = require('https') |
||||||
|
const httpsApp = express() |
||||||
|
const keyPath = fs.readFileSync(path.resolve(__dirname, `${serverConfig.certKeyPath}`)) |
||||||
|
const certPath = fs.readFileSync(path.resolve(__dirname, `${serverConfig.certPath}`)) |
||||||
|
const servOptions = { |
||||||
|
key: keyPath, |
||||||
|
cert: certPath |
||||||
|
} |
||||||
|
const httpsServer = https.createServer(servOptions,httpsApp) |
||||||
|
httpsServer.listen(serverConfig.httpsPort, () => { |
||||||
|
//console.log(`https listening on ${serverConfig.httpsPort} to handle socket.io requests`)
|
||||||
|
wrtColor.green(`https listening on ${serverConfig.httpsPort} to handle socket.io requests`) |
||||||
|
}) |
||||||
|
|
||||||
|
// Attach Socket.IO to https server
|
||||||
|
const io = require('socket.io') (httpsServer, { |
||||||
|
cors: { //https://socket.io/docs/v3/handling-cors/
|
||||||
|
origin: `${serverConfig.frontEndUrl}`, |
||||||
|
methods: ["GET", "POST"] |
||||||
|
} |
||||||
|
}) |
||||||
|
|
||||||
|
//load gameManagement
|
||||||
|
require('./components/serverMgmt') |
||||||
|
//pass socket.io connections to socketHandler
|
||||||
|
const { socketHandler } = require('./components/serverMgmt.js') |
||||||
|
socketHandler(io) |
||||||
Loading…
Reference in new issue