cleanup
This commit is contained in:
parent
3750a00017
commit
a3dbd9e689
4
.gitignore
vendored
4
.gitignore
vendored
@ -223,4 +223,8 @@ fabric.properties
|
|||||||
# Android studio 3.1+ serialized cache file
|
# Android studio 3.1+ serialized cache file
|
||||||
.idea/caches/build_file_checksums.ser
|
.idea/caches/build_file_checksums.ser
|
||||||
|
|
||||||
|
# SQLite
|
||||||
data/db.sqlite
|
data/db.sqlite
|
||||||
|
data/db.sqlite-shm
|
||||||
|
data/db.sqlite-wal
|
||||||
|
data/database-backups
|
@ -6,5 +6,8 @@
|
|||||||
"scanner": {
|
"scanner": {
|
||||||
"updateCron": "*/1 * * * *",
|
"updateCron": "*/1 * * * *",
|
||||||
"timeout": 2000
|
"timeout": 2000
|
||||||
|
},
|
||||||
|
"backup": {
|
||||||
|
"cron": "0 0 * * *"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,10 +15,12 @@
|
|||||||
"@types/node-cron": "^3.0.11",
|
"@types/node-cron": "^3.0.11",
|
||||||
"better-sqlite3": "^9.2.2",
|
"better-sqlite3": "^9.2.2",
|
||||||
"dns": "^0.2.2",
|
"dns": "^0.2.2",
|
||||||
|
"mcpe-ping-fixed": "^0.0.3",
|
||||||
"mcping-js": "^1.5.0",
|
"mcping-js": "^1.5.0",
|
||||||
"node-cron": "^3.0.3",
|
"node-cron": "^3.0.3",
|
||||||
"ts-node": "^10.9.2",
|
"ts-node": "^10.9.2",
|
||||||
"typescript": "^5.3.3"
|
"typescript": "^5.3.3",
|
||||||
|
"winston": "^3.11.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^20.10.6"
|
"@types/node": "^20.10.6"
|
||||||
|
199
pnpm-lock.yaml
generated
199
pnpm-lock.yaml
generated
@ -20,6 +20,9 @@ dependencies:
|
|||||||
dns:
|
dns:
|
||||||
specifier: ^0.2.2
|
specifier: ^0.2.2
|
||||||
version: 0.2.2
|
version: 0.2.2
|
||||||
|
mcpe-ping-fixed:
|
||||||
|
specifier: ^0.0.3
|
||||||
|
version: 0.0.3
|
||||||
mcping-js:
|
mcping-js:
|
||||||
specifier: ^1.5.0
|
specifier: ^1.5.0
|
||||||
version: 1.5.0
|
version: 1.5.0
|
||||||
@ -32,6 +35,9 @@ dependencies:
|
|||||||
typescript:
|
typescript:
|
||||||
specifier: ^5.3.3
|
specifier: ^5.3.3
|
||||||
version: 5.3.3
|
version: 5.3.3
|
||||||
|
winston:
|
||||||
|
specifier: ^3.11.0
|
||||||
|
version: 3.11.0
|
||||||
|
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@types/node':
|
'@types/node':
|
||||||
@ -40,6 +46,11 @@ devDependencies:
|
|||||||
|
|
||||||
packages:
|
packages:
|
||||||
|
|
||||||
|
/@colors/colors@1.6.0:
|
||||||
|
resolution: {integrity: sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==}
|
||||||
|
engines: {node: '>=0.1.90'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@cspotcode/source-map-support@0.8.1:
|
/@cspotcode/source-map-support@0.8.1:
|
||||||
resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==}
|
resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
@ -47,6 +58,14 @@ packages:
|
|||||||
'@jridgewell/trace-mapping': 0.3.9
|
'@jridgewell/trace-mapping': 0.3.9
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/@dabh/diagnostics@2.0.3:
|
||||||
|
resolution: {integrity: sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==}
|
||||||
|
dependencies:
|
||||||
|
colorspace: 1.1.4
|
||||||
|
enabled: 2.0.0
|
||||||
|
kuler: 2.0.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@jridgewell/resolve-uri@3.1.1:
|
/@jridgewell/resolve-uri@3.1.1:
|
||||||
resolution: {integrity: sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==}
|
resolution: {integrity: sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==}
|
||||||
engines: {node: '>=6.0.0'}
|
engines: {node: '>=6.0.0'}
|
||||||
@ -98,6 +117,10 @@ packages:
|
|||||||
dependencies:
|
dependencies:
|
||||||
undici-types: 5.26.5
|
undici-types: 5.26.5
|
||||||
|
|
||||||
|
/@types/triple-beam@1.3.5:
|
||||||
|
resolution: {integrity: sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/accepts@1.0.7:
|
/accepts@1.0.7:
|
||||||
resolution: {integrity: sha512-iq8ew2zitUlNcUca0wye3fYwQ6sSPItDo38oC0R+XA5KTzeXRN+GF7NjOXs3dVItj4J+gQVdpq4/qbnMb1hMHw==}
|
resolution: {integrity: sha512-iq8ew2zitUlNcUca0wye3fYwQ6sSPItDo38oC0R+XA5KTzeXRN+GF7NjOXs3dVItj4J+gQVdpq4/qbnMb1hMHw==}
|
||||||
engines: {node: '>= 0.8.0'}
|
engines: {node: '>= 0.8.0'}
|
||||||
@ -138,6 +161,14 @@ packages:
|
|||||||
resolution: {integrity: sha512-eAkdoKxU6/LkKDBzLpT+t6Ff5EtfSF4wx1WfJiPEEV7WNLnDaRXk0oVysiEPm262roaachGexwUv94WhSgN5TQ==}
|
resolution: {integrity: sha512-eAkdoKxU6/LkKDBzLpT+t6Ff5EtfSF4wx1WfJiPEEV7WNLnDaRXk0oVysiEPm262roaachGexwUv94WhSgN5TQ==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/async@0.9.0:
|
||||||
|
resolution: {integrity: sha512-XQJ3MipmCHAIBBMFfu2jaSetneOrXbSyyqeU3Nod867oNOpS+i9FEms5PWgjMxSgBybRf2IVVLtr1YfrDO+okg==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/async@3.2.5:
|
||||||
|
resolution: {integrity: sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/aws-sign@0.2.0:
|
/aws-sign@0.2.0:
|
||||||
resolution: {integrity: sha512-6P7/Ls5F6++DsKu7iacris7qq/AZSWaX+gT4dtSyUxM82ePxWxaP7Slo82ZO3ZTx6GSKxQHAQlmFvM8e+Dd8ZA==}
|
resolution: {integrity: sha512-6P7/Ls5F6++DsKu7iacris7qq/AZSWaX+gT4dtSyUxM82ePxWxaP7Slo82ZO3ZTx6GSKxQHAQlmFvM8e+Dd8ZA==}
|
||||||
dev: false
|
dev: false
|
||||||
@ -236,6 +267,19 @@ packages:
|
|||||||
verror: 1.10.1
|
verror: 1.10.1
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/bufferview@1.0.1:
|
||||||
|
resolution: {integrity: sha512-q87jdvsZ/sEngmDUvPT/PJsBGCi998c3B1U/6IN1uGg+R2HrTFJUDccXZEx6OxpuLySyBDGXc7vkSt4BXTyKxA==}
|
||||||
|
engines: {node: '>=0.8'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/bytebuffer@4.1.0:
|
||||||
|
resolution: {integrity: sha512-iUP8IfllRZiCGYACmcE7IxEfW+L1OKUEcHhXsrosqf51HnwR55THbePWeY3xAFxMlhhUa2I6x3cp5zG2vHI2YQ==}
|
||||||
|
engines: {node: '>=0.8'}
|
||||||
|
dependencies:
|
||||||
|
bufferview: 1.0.1
|
||||||
|
long: 2.4.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
/bytes@1.0.0:
|
/bytes@1.0.0:
|
||||||
resolution: {integrity: sha512-/x68VkHLeTl3/Ll8IvxdwzhrT+IyKc52e/oyHhA2RwqPqswSnjVbSddfPRwAsJtbilMAPSRWwAlpxdYsSWOTKQ==}
|
resolution: {integrity: sha512-/x68VkHLeTl3/Ll8IvxdwzhrT+IyKc52e/oyHhA2RwqPqswSnjVbSddfPRwAsJtbilMAPSRWwAlpxdYsSWOTKQ==}
|
||||||
dev: false
|
dev: false
|
||||||
@ -248,11 +292,46 @@ packages:
|
|||||||
resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==}
|
resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/color-convert@1.9.3:
|
||||||
|
resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==}
|
||||||
|
dependencies:
|
||||||
|
color-name: 1.1.3
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/color-name@1.1.3:
|
||||||
|
resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/color-name@1.1.4:
|
||||||
|
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/color-string@1.9.1:
|
||||||
|
resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==}
|
||||||
|
dependencies:
|
||||||
|
color-name: 1.1.4
|
||||||
|
simple-swizzle: 0.2.2
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/color@3.2.1:
|
||||||
|
resolution: {integrity: sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==}
|
||||||
|
dependencies:
|
||||||
|
color-convert: 1.9.3
|
||||||
|
color-string: 1.9.1
|
||||||
|
dev: false
|
||||||
|
|
||||||
/colors@0.6.2:
|
/colors@0.6.2:
|
||||||
resolution: {integrity: sha512-OsSVtHK8Ir8r3+Fxw/b4jS1ZLPXkV6ZxDRJQzeD7qo0SqMXWrHDM71DgYzPMHY8SFJ0Ao+nNU2p1MmwdzKqPrw==}
|
resolution: {integrity: sha512-OsSVtHK8Ir8r3+Fxw/b4jS1ZLPXkV6ZxDRJQzeD7qo0SqMXWrHDM71DgYzPMHY8SFJ0Ao+nNU2p1MmwdzKqPrw==}
|
||||||
engines: {node: '>=0.1.90'}
|
engines: {node: '>=0.1.90'}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/colorspace@1.1.4:
|
||||||
|
resolution: {integrity: sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==}
|
||||||
|
dependencies:
|
||||||
|
color: 3.2.1
|
||||||
|
text-hex: 1.0.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
/combined-stream@0.0.7:
|
/combined-stream@0.0.7:
|
||||||
resolution: {integrity: sha512-qfexlmLp9MyrkajQVyjEDb0Vj+KhRgR/rxLiVhaihlT+ZkX0lReqtH6Ack40CvMDERR4b5eFp3CreskpBs1Pig==}
|
resolution: {integrity: sha512-qfexlmLp9MyrkajQVyjEDb0Vj+KhRgR/rxLiVhaihlT+ZkX0lReqtH6Ack40CvMDERR4b5eFp3CreskpBs1Pig==}
|
||||||
engines: {node: '>= 0.8'}
|
engines: {node: '>= 0.8'}
|
||||||
@ -425,6 +504,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-1q/3kz+ZwmrrWpJcCCrBZ3JnBzB1BMA5EVW9nxnIP1LxDZ16Cqs9VdolqLWlExet1vU+bar3WSkAa4/YrA9bIw==}
|
resolution: {integrity: sha512-1q/3kz+ZwmrrWpJcCCrBZ3JnBzB1BMA5EVW9nxnIP1LxDZ16Cqs9VdolqLWlExet1vU+bar3WSkAa4/YrA9bIw==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/enabled@2.0.0:
|
||||||
|
resolution: {integrity: sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/end-of-stream@1.4.4:
|
/end-of-stream@1.4.4:
|
||||||
resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==}
|
resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==}
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -531,6 +614,10 @@ packages:
|
|||||||
engines: {node: '> 0.1.90'}
|
engines: {node: '> 0.1.90'}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/fecha@4.2.3:
|
||||||
|
resolution: {integrity: sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/file-uri-to-path@1.0.0:
|
/file-uri-to-path@1.0.0:
|
||||||
resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==}
|
resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==}
|
||||||
dev: false
|
dev: false
|
||||||
@ -561,6 +648,10 @@ packages:
|
|||||||
ee-first: 1.0.3
|
ee-first: 1.0.3
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/fn.name@1.1.0:
|
||||||
|
resolution: {integrity: sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/forever-agent@0.2.0:
|
/forever-agent@0.2.0:
|
||||||
resolution: {integrity: sha512-IasWSRIlfPnBZY1K9jEUK3PwsScR4mrcK+aNBJzGoPnW+S9b6f8I8ScyH4cehEOFNqnjGpP2gCaA22gqSV1xQA==}
|
resolution: {integrity: sha512-IasWSRIlfPnBZY1K9jEUK3PwsScR4mrcK+aNBJzGoPnW+S9b6f8I8ScyH4cehEOFNqnjGpP2gCaA22gqSV1xQA==}
|
||||||
dev: false
|
dev: false
|
||||||
@ -654,6 +745,15 @@ packages:
|
|||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/is-arrayish@0.3.2:
|
||||||
|
resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/is-stream@2.0.1:
|
||||||
|
resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==}
|
||||||
|
engines: {node: '>=8'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/isarray@0.0.1:
|
/isarray@0.0.1:
|
||||||
resolution: {integrity: sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==}
|
resolution: {integrity: sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==}
|
||||||
dev: false
|
dev: false
|
||||||
@ -667,6 +767,27 @@ packages:
|
|||||||
deprecated: Please use the native JSON object instead of JSON 3
|
deprecated: Please use the native JSON object instead of JSON 3
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/kuler@2.0.0:
|
||||||
|
resolution: {integrity: sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/logform@2.6.0:
|
||||||
|
resolution: {integrity: sha512-1ulHeNPp6k/LD8H91o7VYFBng5i1BDE7HoKxVbZiGFidS1Rj65qcywLxX+pVfAPoQJEjRdvKcusKwOupHCVOVQ==}
|
||||||
|
engines: {node: '>= 12.0.0'}
|
||||||
|
dependencies:
|
||||||
|
'@colors/colors': 1.6.0
|
||||||
|
'@types/triple-beam': 1.3.5
|
||||||
|
fecha: 4.2.3
|
||||||
|
ms: 2.1.3
|
||||||
|
safe-stable-stringify: 2.4.3
|
||||||
|
triple-beam: 1.4.1
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/long@2.4.0:
|
||||||
|
resolution: {integrity: sha512-ijUtjmO/n2A5PaosNG9ZGDsQ3vxJg7ZW8vsY8Kp0f2yIZWhSJvjmegV7t+9RPQKxKrvj8yKGehhS+po14hPLGQ==}
|
||||||
|
engines: {node: '>=0.6'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/lru-cache@6.0.0:
|
/lru-cache@6.0.0:
|
||||||
resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==}
|
resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
@ -678,6 +799,13 @@ packages:
|
|||||||
resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==}
|
resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/mcpe-ping-fixed@0.0.3:
|
||||||
|
resolution: {integrity: sha512-STb0fhDpFB6Z2JJGFRHIG0yat3vyI3U6QVatyY5rLlrbcfw+elP4NcpfXp9pmr5N9kQff2Chw1xsRW9sI9CXPQ==}
|
||||||
|
dependencies:
|
||||||
|
bytebuffer: 4.1.0
|
||||||
|
portfinder: 0.4.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
/mcping-js@1.5.0:
|
/mcping-js@1.5.0:
|
||||||
resolution: {integrity: sha512-CoXbpbSqE4OtJupU2lvzoKFrGerH0AoyY9YoQ98EKUOhtxfLQa+f+DFqWYUaZ451Scru1gJm/+w6d3IKJhMGvQ==}
|
resolution: {integrity: sha512-CoXbpbSqE4OtJupU2lvzoKFrGerH0AoyY9YoQ98EKUOhtxfLQa+f+DFqWYUaZ451Scru1gJm/+w6d3IKJhMGvQ==}
|
||||||
dev: false
|
dev: false
|
||||||
@ -717,6 +845,13 @@ packages:
|
|||||||
resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==}
|
resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/mkdirp@0.5.6:
|
||||||
|
resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==}
|
||||||
|
hasBin: true
|
||||||
|
dependencies:
|
||||||
|
minimist: 1.2.8
|
||||||
|
dev: false
|
||||||
|
|
||||||
/morgan@1.2.0:
|
/morgan@1.2.0:
|
||||||
resolution: {integrity: sha512-VrasIzA69dsxJm1+MVWTLTiij3kiG33XPfGiexqstHpcSvSu/Z51W+FGQyIlbc3jZZuF2PFujsjw+YQvpXz3UA==}
|
resolution: {integrity: sha512-VrasIzA69dsxJm1+MVWTLTiij3kiG33XPfGiexqstHpcSvSu/Z51W+FGQyIlbc3jZZuF2PFujsjw+YQvpXz3UA==}
|
||||||
engines: {node: '>= 0.8.0'}
|
engines: {node: '>= 0.8.0'}
|
||||||
@ -731,6 +866,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-/pc3eh7TWorTtbvXg8je4GvrvEqCfH7PA3P7iW01yL2E53FKixzgMBaQi0NOPbMJqY34cBSvR0tZtmlTkdUG4A==}
|
resolution: {integrity: sha512-/pc3eh7TWorTtbvXg8je4GvrvEqCfH7PA3P7iW01yL2E53FKixzgMBaQi0NOPbMJqY34cBSvR0tZtmlTkdUG4A==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/ms@2.1.3:
|
||||||
|
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/nan@0.3.2:
|
/nan@0.3.2:
|
||||||
resolution: {integrity: sha512-V9/Pyy5Oelv6vVJP9X+dAzU3IO19j6YXrJnODHxP2h54hTvfFQGahdsQV6Ule/UukiEJk1SkQ/aUyWUm61RBQw==}
|
resolution: {integrity: sha512-V9/Pyy5Oelv6vVJP9X+dAzU3IO19j6YXrJnODHxP2h54hTvfFQGahdsQV6Ule/UukiEJk1SkQ/aUyWUm61RBQw==}
|
||||||
dev: false
|
dev: false
|
||||||
@ -807,6 +946,12 @@ packages:
|
|||||||
wrappy: 1.0.2
|
wrappy: 1.0.2
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/one-time@1.0.0:
|
||||||
|
resolution: {integrity: sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==}
|
||||||
|
dependencies:
|
||||||
|
fn.name: 1.1.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
/optimist@0.3.7:
|
/optimist@0.3.7:
|
||||||
resolution: {integrity: sha512-TCx0dXQzVtSCg2OgY/bO9hjM9cV4XYx09TVK+s3+FhkjT6LovsLe+pPMzpWf+6yXK/hUizs2gUoTw3jHM0VaTQ==}
|
resolution: {integrity: sha512-TCx0dXQzVtSCg2OgY/bO9hjM9cV4XYx09TVK+s3+FhkjT6LovsLe+pPMzpWf+6yXK/hUizs2gUoTw3jHM0VaTQ==}
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -849,6 +994,14 @@ packages:
|
|||||||
engines: {node: '>= 0.4.0'}
|
engines: {node: '>= 0.4.0'}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/portfinder@0.4.0:
|
||||||
|
resolution: {integrity: sha512-SZ3hp61WVhwNSS0gf0Fdrx5Yb/wl35qisHuPVM1S0StV8t5XlVZmmJy7/417OELJA7t6ecEmeEzvOaBwq3kCiQ==}
|
||||||
|
engines: {node: '>= 0.8.0'}
|
||||||
|
dependencies:
|
||||||
|
async: 0.9.0
|
||||||
|
mkdirp: 0.5.6
|
||||||
|
dev: false
|
||||||
|
|
||||||
/prebuild-install@7.1.1:
|
/prebuild-install@7.1.1:
|
||||||
resolution: {integrity: sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==}
|
resolution: {integrity: sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
@ -943,6 +1096,11 @@ packages:
|
|||||||
resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
|
resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/safe-stable-stringify@2.4.3:
|
||||||
|
resolution: {integrity: sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==}
|
||||||
|
engines: {node: '>=10'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/semver@7.5.4:
|
/semver@7.5.4:
|
||||||
resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==}
|
resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
@ -990,6 +1148,12 @@ packages:
|
|||||||
simple-concat: 1.0.1
|
simple-concat: 1.0.1
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/simple-swizzle@0.2.2:
|
||||||
|
resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==}
|
||||||
|
dependencies:
|
||||||
|
is-arrayish: 0.3.2
|
||||||
|
dev: false
|
||||||
|
|
||||||
/sntp@0.1.4:
|
/sntp@0.1.4:
|
||||||
resolution: {integrity: sha512-v90tkW8VIdXwY35BJAWIpZWd/h+WC7TufizgUO2jtOY21isIo8IP85f1zJ8mKF8o77Vxo5k+GJmUZ4H6phVt1g==}
|
resolution: {integrity: sha512-v90tkW8VIdXwY35BJAWIpZWd/h+WC7TufizgUO2jtOY21isIo8IP85f1zJ8mKF8o77Vxo5k+GJmUZ4H6phVt1g==}
|
||||||
engines: {node: 0.8.x}
|
engines: {node: 0.8.x}
|
||||||
@ -1098,6 +1262,10 @@ packages:
|
|||||||
readable-stream: 3.6.2
|
readable-stream: 3.6.2
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/text-hex@1.0.0:
|
||||||
|
resolution: {integrity: sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/tinycolor@0.0.1:
|
/tinycolor@0.0.1:
|
||||||
resolution: {integrity: sha512-+CorETse1kl98xg0WAzii8DTT4ABF4R3nquhrkIbVGcw1T8JYs5Gfx9xEfGINPUZGDj9C4BmOtuKeaTtuuRolg==}
|
resolution: {integrity: sha512-+CorETse1kl98xg0WAzii8DTT4ABF4R3nquhrkIbVGcw1T8JYs5Gfx9xEfGINPUZGDj9C4BmOtuKeaTtuuRolg==}
|
||||||
engines: {node: '>=0.4.0'}
|
engines: {node: '>=0.4.0'}
|
||||||
@ -1130,6 +1298,11 @@ packages:
|
|||||||
- utf-8-validate
|
- utf-8-validate
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/triple-beam@1.4.1:
|
||||||
|
resolution: {integrity: sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==}
|
||||||
|
engines: {node: '>= 14.0.0'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/ts-node@10.9.2(@types/node@20.10.6)(typescript@5.3.3):
|
/ts-node@10.9.2(@types/node@20.10.6)(typescript@5.3.3):
|
||||||
resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==}
|
resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
@ -1224,6 +1397,15 @@ packages:
|
|||||||
extsprintf: 1.4.1
|
extsprintf: 1.4.1
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/winston-transport@4.6.0:
|
||||||
|
resolution: {integrity: sha512-wbBA9PbPAHxKiygo7ub7BYRiKxms0tpfU2ljtWzb3SjRjv5yl6Ozuy/TkXf00HTAt+Uylo3gSkNwzc4ME0wiIg==}
|
||||||
|
engines: {node: '>= 12.0.0'}
|
||||||
|
dependencies:
|
||||||
|
logform: 2.6.0
|
||||||
|
readable-stream: 3.6.2
|
||||||
|
triple-beam: 1.4.1
|
||||||
|
dev: false
|
||||||
|
|
||||||
/winston@0.7.3:
|
/winston@0.7.3:
|
||||||
resolution: {integrity: sha512-iVTT8tf9YnTyfZX+aEUj2fl6WBRet7za6vdjMeyF8SA80Vii2rreM5XH+5qmpBV9uJGj8jz8BozvTDcroVq/eA==}
|
resolution: {integrity: sha512-iVTT8tf9YnTyfZX+aEUj2fl6WBRet7za6vdjMeyF8SA80Vii2rreM5XH+5qmpBV9uJGj8jz8BozvTDcroVq/eA==}
|
||||||
engines: {node: '>= 0.6.0'}
|
engines: {node: '>= 0.6.0'}
|
||||||
@ -1237,6 +1419,23 @@ packages:
|
|||||||
stack-trace: 0.0.10
|
stack-trace: 0.0.10
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/winston@3.11.0:
|
||||||
|
resolution: {integrity: sha512-L3yR6/MzZAOl0DsysUXHVjOwv8mKZ71TrA/41EIduGpOOV5LQVodqN+QdQ6BS6PJ/RdIshZhq84P/fStEZkk7g==}
|
||||||
|
engines: {node: '>= 12.0.0'}
|
||||||
|
dependencies:
|
||||||
|
'@colors/colors': 1.6.0
|
||||||
|
'@dabh/diagnostics': 2.0.3
|
||||||
|
async: 3.2.5
|
||||||
|
is-stream: 2.0.1
|
||||||
|
logform: 2.6.0
|
||||||
|
one-time: 1.0.0
|
||||||
|
readable-stream: 3.6.2
|
||||||
|
safe-stable-stringify: 2.4.3
|
||||||
|
stack-trace: 0.0.10
|
||||||
|
triple-beam: 1.4.1
|
||||||
|
winston-transport: 4.6.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
/wordwrap@0.0.3:
|
/wordwrap@0.0.3:
|
||||||
resolution: {integrity: sha512-1tMA907+V4QmxV7dbRvb4/8MaRALK6q9Abid3ndMYnbyo8piisCmeONVqVSXqQA3KaP4SLt5b7ud6E2sqP8TFw==}
|
resolution: {integrity: sha512-1tMA907+V4QmxV7dbRvb4/8MaRALK6q9Abid3ndMYnbyo8piisCmeONVqVSXqQA3KaP4SLt5b7ud6E2sqP8TFw==}
|
||||||
engines: {node: '>=0.4.0'}
|
engines: {node: '>=0.4.0'}
|
||||||
|
153
src/database/database.ts
Normal file
153
src/database/database.ts
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
import SQLiteDatabase from "better-sqlite3";
|
||||||
|
import cron from "node-cron";
|
||||||
|
import Server, { PingResponse } from "../server/server";
|
||||||
|
import { logger } from "../utils/logger";
|
||||||
|
import { getFormattedDate } from "../utils/timeUtils";
|
||||||
|
|
||||||
|
import Config from "../../data/config.json";
|
||||||
|
import { Ping } from "../types/ping";
|
||||||
|
import { createDirectory } from "../utils/fsUtils";
|
||||||
|
|
||||||
|
const DATA_DIR = "data";
|
||||||
|
const BACKUP_DIR = `${DATA_DIR}/database-backups`;
|
||||||
|
|
||||||
|
const PINGS_TABLE = "pings";
|
||||||
|
const RECORD_TABLE = "record";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SQL Queries
|
||||||
|
*/
|
||||||
|
const CREATE_PINGS_TABLE = `
|
||||||
|
CREATE TABLE IF NOT EXISTS pings (
|
||||||
|
id INTEGER NOT NULL,
|
||||||
|
timestamp BIGINT NOT NULL,
|
||||||
|
ip TINYTEXT NOT NULL,
|
||||||
|
playerCount MEDIUMINT NOT NULL
|
||||||
|
);
|
||||||
|
`;
|
||||||
|
const CREATE_RECORD_TABLE = `
|
||||||
|
CREATE TABLE IF NOT EXISTS record (
|
||||||
|
id INTEGER PRIMARY KEY,
|
||||||
|
timestamp BIGINT NOT NULL,
|
||||||
|
ip TINYTEXT NOT NULL,
|
||||||
|
playerCount MEDIUMINT NOT NULL
|
||||||
|
);
|
||||||
|
`;
|
||||||
|
|
||||||
|
const CREATE_PINGS_INDEX = `CREATE INDEX IF NOT EXISTS ip_index ON pings (id, ip, playerCount)`;
|
||||||
|
const CREATE_TIMESTAMP_INDEX = `CREATE INDEX IF NOT EXISTS timestamp_index on PINGS (id, timestamp)`;
|
||||||
|
|
||||||
|
const INSERT_PING = `
|
||||||
|
INSERT INTO ${PINGS_TABLE} (id, timestamp, ip, playerCount)
|
||||||
|
VALUES (?, ?, ?, ?)
|
||||||
|
`;
|
||||||
|
const INSERT_RECORD = `
|
||||||
|
INSERT INTO ${RECORD_TABLE} (id, timestamp, ip, playerCount)
|
||||||
|
VALUES (?, ?, ?, ?)
|
||||||
|
ON CONFLICT(id) DO UPDATE SET
|
||||||
|
timestamp = excluded.timestamp,
|
||||||
|
playerCount = excluded.playerCount,
|
||||||
|
ip = excluded.ip
|
||||||
|
`;
|
||||||
|
|
||||||
|
const SELECT_PINGS = `
|
||||||
|
SELECT * FROM ${PINGS_TABLE} WHERE id = ? AND timestamp >= ? AND timestamp <= ?
|
||||||
|
`;
|
||||||
|
const SELECT_RECORD = `
|
||||||
|
SELECT playerCount, timestamp FROM ${RECORD_TABLE} WHERE {} = ?
|
||||||
|
`;
|
||||||
|
const SELECT_RECORD_BY_ID = SELECT_RECORD.replace("{}", "id");
|
||||||
|
const SELECT_RECORD_BY_IP = SELECT_RECORD.replace("{}", "ip");
|
||||||
|
|
||||||
|
export default class Database {
|
||||||
|
private db: SQLiteDatabase.Database;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.db = new SQLiteDatabase(`${DATA_DIR}/db.sqlite`);
|
||||||
|
this.db.pragma("journal_mode = WAL");
|
||||||
|
|
||||||
|
logger.info("Ensuring tables exist");
|
||||||
|
this.db.exec(CREATE_PINGS_TABLE); // Ensure the pings table exists
|
||||||
|
this.db.exec(CREATE_RECORD_TABLE); // Ensure the record table exists
|
||||||
|
|
||||||
|
logger.info("Ensuring indexes exist");
|
||||||
|
this.db.exec(CREATE_PINGS_INDEX); // Ensure the pings index exists
|
||||||
|
this.db.exec(CREATE_TIMESTAMP_INDEX); // Ensure the timestamp index exists
|
||||||
|
|
||||||
|
cron.schedule(Config.backup.cron, () => {
|
||||||
|
this.createBackup();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the pings for a server.
|
||||||
|
*
|
||||||
|
* @param id the server ID
|
||||||
|
* @param startTime the start time
|
||||||
|
* @param endTime the end time
|
||||||
|
* @returns the pings for the server
|
||||||
|
*/
|
||||||
|
public getPings(id: number, startTime: number, endTime: number): Ping[] | [] {
|
||||||
|
return this.db.prepare(SELECT_PINGS).all(id, startTime, endTime) as
|
||||||
|
| Ping[]
|
||||||
|
| [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the record player count for a server.
|
||||||
|
*
|
||||||
|
* @param value the server ID or IP
|
||||||
|
* @returns the record for the server
|
||||||
|
*/
|
||||||
|
public getRecord(value: any): Ping | undefined {
|
||||||
|
if (typeof value === "number") {
|
||||||
|
return this.db.prepare(SELECT_RECORD_BY_ID).get(value) as
|
||||||
|
| Ping
|
||||||
|
| undefined;
|
||||||
|
}
|
||||||
|
return this.db.prepare(SELECT_RECORD_BY_IP).get(value) as Ping | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a full backup of the database.
|
||||||
|
*/
|
||||||
|
public async createBackup() {
|
||||||
|
logger.info("Creating database backup");
|
||||||
|
createDirectory(BACKUP_DIR);
|
||||||
|
await this.db.backup(`${BACKUP_DIR}/${getFormattedDate()}.sqlite`);
|
||||||
|
logger.info("Finished creating database backup");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inserts a ping into the database.
|
||||||
|
*
|
||||||
|
* @param timestamp the timestamp of the ping
|
||||||
|
* @param ip the IP address of the server
|
||||||
|
* @param playerCount the number of players online
|
||||||
|
*/
|
||||||
|
public insertPing(server: Server, response: PingResponse) {
|
||||||
|
const { timestamp, players } = response;
|
||||||
|
const id = server.getID();
|
||||||
|
const ip = server.getIP();
|
||||||
|
const onlineCount = players.online;
|
||||||
|
|
||||||
|
const statement = this.db.prepare(INSERT_PING);
|
||||||
|
statement.run(id, timestamp, ip, onlineCount); // Insert the ping into the database
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inserts a record into the database.
|
||||||
|
*
|
||||||
|
* @param server the server to insert
|
||||||
|
* @param response the response to insert
|
||||||
|
*/
|
||||||
|
public insertRecord(server: Server, response: PingResponse) {
|
||||||
|
const { timestamp, players } = response;
|
||||||
|
const id = server.getID();
|
||||||
|
const ip = server.getIP();
|
||||||
|
const onlineCount = players.online;
|
||||||
|
|
||||||
|
const statement = this.db.prepare(INSERT_RECORD);
|
||||||
|
statement.run(id, timestamp, ip, onlineCount); // Insert the record into the database
|
||||||
|
}
|
||||||
|
}
|
16
src/index.ts
16
src/index.ts
@ -1,5 +1,21 @@
|
|||||||
|
import Database from "./database/database";
|
||||||
import Scanner from "./scanner/scanner";
|
import Scanner from "./scanner/scanner";
|
||||||
import ServerManager from "./server/serverManager";
|
import ServerManager from "./server/serverManager";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The database instance.
|
||||||
|
*/
|
||||||
|
export const database = new Database();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The server manager instance.
|
||||||
|
*/
|
||||||
export const serverManager = new ServerManager();
|
export const serverManager = new ServerManager();
|
||||||
|
|
||||||
|
// The scanner is responsible for scanning all servers
|
||||||
new Scanner();
|
new Scanner();
|
||||||
|
|
||||||
|
serverManager.getServers().forEach((server) => {
|
||||||
|
const record = database.getRecord(server.getID());
|
||||||
|
console.log(`Record for "${server.getName()}": ${record?.playerCount}`);
|
||||||
|
});
|
||||||
|
@ -1,67 +1,15 @@
|
|||||||
import Database from "better-sqlite3";
|
|
||||||
import cron from "node-cron";
|
import cron from "node-cron";
|
||||||
import { serverManager } from "..";
|
import { database, serverManager } from "..";
|
||||||
|
import Server from "../server/server";
|
||||||
|
|
||||||
import Config from "../../data/config.json";
|
import Config from "../../data/config.json";
|
||||||
import Server, { PingResponse } from "../server/server";
|
import { logger } from "../utils/logger";
|
||||||
|
|
||||||
const DATA_DIR = "data";
|
|
||||||
|
|
||||||
const PINGS_TABLE = "pings";
|
|
||||||
const RECORD_TABLE = "record";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* SQL Queries
|
|
||||||
*/
|
|
||||||
const CREATE_PINGS_TABLE = `
|
|
||||||
CREATE TABLE IF NOT EXISTS pings (
|
|
||||||
id INTEGER NOT NULL,
|
|
||||||
timestamp BIGINT NOT NULL,
|
|
||||||
ip TINYTEXT NOT NULL,
|
|
||||||
player_count MEDIUMINT NOT NULL
|
|
||||||
);
|
|
||||||
`;
|
|
||||||
const CREATE_RECORD_TABLE = `
|
|
||||||
CREATE TABLE IF NOT EXISTS record (
|
|
||||||
id INTEGER PRIMARY KEY,
|
|
||||||
timestamp BIGINT NOT NULL,
|
|
||||||
ip TINYTEXT NOT NULL,
|
|
||||||
player_count MEDIUMINT NOT NULL
|
|
||||||
);
|
|
||||||
`;
|
|
||||||
|
|
||||||
const CREATE_PINGS_INDEX = `CREATE INDEX IF NOT EXISTS ip_index ON pings (id, ip, player_count)`;
|
|
||||||
const CREATE_TIMESTAMP_INDEX = `CREATE INDEX IF NOT EXISTS timestamp_index on PINGS (id, timestamp)`;
|
|
||||||
|
|
||||||
const INSERT_PING = `
|
|
||||||
INSERT INTO ${PINGS_TABLE} (id, timestamp, ip, player_count)
|
|
||||||
VALUES (?, ?, ?, ?)
|
|
||||||
`;
|
|
||||||
const INSERT_RECORD = `
|
|
||||||
INSERT INTO ${RECORD_TABLE} (id, timestamp, ip, player_count)
|
|
||||||
VALUES (?, ?, ?, ?)
|
|
||||||
ON CONFLICT(id) DO UPDATE SET
|
|
||||||
timestamp = excluded.timestamp,
|
|
||||||
player_count = excluded.player_count,
|
|
||||||
ip = excluded.ip
|
|
||||||
`;
|
|
||||||
|
|
||||||
export default class Scanner {
|
export default class Scanner {
|
||||||
private db: Database.Database;
|
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
console.log("Loading scanner database");
|
logger.info("Loading scanner database");
|
||||||
this.db = new Database(`${DATA_DIR}/db.sqlite`);
|
|
||||||
|
|
||||||
console.log("Ensuring tables exist");
|
logger.info("Starting server scan");
|
||||||
this.db.exec(CREATE_PINGS_TABLE); // Ensure the pings table exists
|
|
||||||
this.db.exec(CREATE_RECORD_TABLE); // Ensure the record table exists
|
|
||||||
|
|
||||||
console.log("Ensuring indexes exist");
|
|
||||||
this.db.exec(CREATE_PINGS_INDEX); // Ensure the pings index exists
|
|
||||||
this.db.exec(CREATE_TIMESTAMP_INDEX); // Ensure the timestamp index exists
|
|
||||||
|
|
||||||
console.log("Starting server scan");
|
|
||||||
cron.schedule(Config.scanner.updateCron, () => {
|
cron.schedule(Config.scanner.updateCron, () => {
|
||||||
this.scanServers();
|
this.scanServers();
|
||||||
});
|
});
|
||||||
@ -71,14 +19,14 @@ export default class Scanner {
|
|||||||
* Start a server scan to ping all servers.
|
* Start a server scan to ping all servers.
|
||||||
*/
|
*/
|
||||||
private async scanServers(): Promise<void> {
|
private async scanServers(): Promise<void> {
|
||||||
console.log(`Scanning servers ${serverManager.getServers().length}`);
|
logger.info(`Scanning servers ${serverManager.getServers().length}`);
|
||||||
|
|
||||||
// ping all servers in parallel
|
// ping all servers in parallel
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
serverManager.getServers().map((server) => this.scanServer(server))
|
serverManager.getServers().map((server) => this.scanServer(server))
|
||||||
);
|
);
|
||||||
|
|
||||||
console.log("Finished scanning servers");
|
logger.info("Finished scanning servers");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -88,7 +36,7 @@ export default class Scanner {
|
|||||||
* @returns a promise that resolves when the server has been scanned
|
* @returns a promise that resolves when the server has been scanned
|
||||||
*/
|
*/
|
||||||
async scanServer(server: Server): Promise<void> {
|
async scanServer(server: Server): Promise<void> {
|
||||||
//console.log(`Scanning server ${server.getIP()} - ${server.getType()}`);
|
//logger.info(`Scanning server ${server.getIP()} - ${server.getType()}`);
|
||||||
let response;
|
let response;
|
||||||
let online = false;
|
let online = false;
|
||||||
|
|
||||||
@ -99,7 +47,7 @@ export default class Scanner {
|
|||||||
}
|
}
|
||||||
online = true;
|
online = true;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(`Failed to ping ${server.getIP()}`, err);
|
logger.info(`Failed to ping ${server.getIP()}`, err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -107,40 +55,7 @@ export default class Scanner {
|
|||||||
return; // Server is offline
|
return; // Server is offline
|
||||||
}
|
}
|
||||||
|
|
||||||
this.insertPing(server, response);
|
database.insertPing(server, response);
|
||||||
this.insertRecord(server, response);
|
database.insertRecord(server, response);
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Inserts a ping into the database.
|
|
||||||
*
|
|
||||||
* @param timestamp the timestamp of the ping
|
|
||||||
* @param ip the IP address of the server
|
|
||||||
* @param playerCount the number of players online
|
|
||||||
*/
|
|
||||||
private insertPing(server: Server, response: PingResponse): void {
|
|
||||||
const { timestamp, players } = response;
|
|
||||||
const id = server.getID();
|
|
||||||
const ip = server.getIP();
|
|
||||||
const onlineCount = players.online;
|
|
||||||
|
|
||||||
const statement = this.db.prepare(INSERT_PING);
|
|
||||||
statement.run(id, timestamp, ip, onlineCount); // Insert the ping into the database
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Inserts a record into the database.
|
|
||||||
*
|
|
||||||
* @param server the server to insert
|
|
||||||
* @param response the response to insert
|
|
||||||
*/
|
|
||||||
private insertRecord(server: Server, response: PingResponse): void {
|
|
||||||
const { timestamp, players } = response;
|
|
||||||
const id = server.getID();
|
|
||||||
const ip = server.getIP();
|
|
||||||
const onlineCount = players.online;
|
|
||||||
|
|
||||||
const statement = this.db.prepare(INSERT_RECORD);
|
|
||||||
statement.run(id, timestamp, ip, onlineCount); // Insert the record into the database
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
|
import javaPing from "mcping-js";
|
||||||
import { ResolvedServer, resolveDns } from "../utils/dnsResolver";
|
import { ResolvedServer, resolveDns } from "../utils/dnsResolver";
|
||||||
import JavaPing = require("mcping-js");
|
const bedrockPing = require("mcpe-ping-fixed"); // Doesn't have typescript definitions
|
||||||
|
|
||||||
import Config from "../../data/config.json";
|
import Config from "../../data/config.json";
|
||||||
|
|
||||||
@ -16,10 +17,10 @@ export type ServerType = "PC" | "PE";
|
|||||||
export type PingResponse = {
|
export type PingResponse = {
|
||||||
timestamp: number;
|
timestamp: number;
|
||||||
ip: string;
|
ip: string;
|
||||||
version: string;
|
version?: string;
|
||||||
players: {
|
players: {
|
||||||
online: number;
|
online: number;
|
||||||
max: number;
|
max?: number;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -27,6 +28,7 @@ type ServerOptions = {
|
|||||||
id: number;
|
id: number;
|
||||||
name: string;
|
name: string;
|
||||||
ip: string;
|
ip: string;
|
||||||
|
port?: number;
|
||||||
type: ServerType;
|
type: ServerType;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -51,6 +53,11 @@ export default class Server {
|
|||||||
*/
|
*/
|
||||||
private ip: string;
|
private ip: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The port of the server.
|
||||||
|
*/
|
||||||
|
private port: number | undefined;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The type of server.
|
* The type of server.
|
||||||
*/
|
*/
|
||||||
@ -64,10 +71,11 @@ export default class Server {
|
|||||||
hasResolved: false,
|
hasResolved: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor({ id, name, ip, type }: ServerOptions) {
|
constructor({ id, name, ip, port, type }: ServerOptions) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.ip = ip;
|
this.ip = ip;
|
||||||
|
this.port = port;
|
||||||
this.type = type;
|
this.type = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -126,7 +134,7 @@ export default class Server {
|
|||||||
port = 25565; // The default port
|
port = 25565; // The default port
|
||||||
}
|
}
|
||||||
|
|
||||||
const serverPing = new JavaPing.MinecraftServer(ip, port);
|
const serverPing = new javaPing.MinecraftServer(ip, port);
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
serverPing.ping(Config.scanner.timeout, 700, (err, res) => {
|
serverPing.ping(Config.scanner.timeout, 700, (err, res) => {
|
||||||
@ -156,7 +164,25 @@ export default class Server {
|
|||||||
private async pingPEServer(
|
private async pingPEServer(
|
||||||
server: Server
|
server: Server
|
||||||
): Promise<PingResponse | undefined> {
|
): Promise<PingResponse | undefined> {
|
||||||
return undefined;
|
return new Promise((resolve, reject) => {
|
||||||
|
bedrockPing(
|
||||||
|
server.getIP(),
|
||||||
|
server.getPort() || 19132,
|
||||||
|
(err: any, res: any) => {
|
||||||
|
if (err || res == undefined) {
|
||||||
|
return reject(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve({
|
||||||
|
timestamp: Date.now(),
|
||||||
|
ip: server.getIP(),
|
||||||
|
players: {
|
||||||
|
online: res.currentPlayers,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -186,6 +212,15 @@ export default class Server {
|
|||||||
return this.ip;
|
return this.ip;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the port of the server.
|
||||||
|
*
|
||||||
|
* @returns the port
|
||||||
|
*/
|
||||||
|
public getPort(): number | undefined {
|
||||||
|
return this.port;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the type of server.
|
* Returns the type of server.
|
||||||
*
|
*
|
||||||
|
6
src/types/ping.ts
Normal file
6
src/types/ping.ts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
export type Ping = {
|
||||||
|
id: number;
|
||||||
|
timestamp: number;
|
||||||
|
ip: string;
|
||||||
|
playerCount: number;
|
||||||
|
};
|
31
src/utils/logger.ts
Normal file
31
src/utils/logger.ts
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
import Winston, { format } from "winston";
|
||||||
|
const { colorize, timestamp, printf } = format;
|
||||||
|
|
||||||
|
interface LogInfo {
|
||||||
|
level: string;
|
||||||
|
message: string;
|
||||||
|
label?: string;
|
||||||
|
timestamp?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const customFormat = format.combine(
|
||||||
|
timestamp({ format: "YY-MM-DD HH:MM:SS" }),
|
||||||
|
printf((info: LogInfo) => {
|
||||||
|
return `[${info.timestamp}] ${info.level}: ${info.message}`;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The global logger instance.
|
||||||
|
*/
|
||||||
|
export const logger = Winston.createLogger({
|
||||||
|
transports: [
|
||||||
|
new Winston.transports.Console({
|
||||||
|
format: Winston.format.combine(colorize(), customFormat),
|
||||||
|
}),
|
||||||
|
new Winston.transports.File({
|
||||||
|
filename: `data/logs/${new Date().toISOString().slice(0, 10)}.log`,
|
||||||
|
format: Winston.format.combine(customFormat),
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
8
src/utils/timeUtils.ts
Normal file
8
src/utils/timeUtils.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
/**
|
||||||
|
* Gets the current date as YYYY-MM-DD.
|
||||||
|
*
|
||||||
|
* @returns the date
|
||||||
|
*/
|
||||||
|
export function getFormattedDate() {
|
||||||
|
return new Date().toISOString().slice(0, 10);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user