Add rate limits and note quota
This commit is contained in:
parent
78fb73a25a
commit
ef86aaddb0
|
@ -0,0 +1,26 @@
|
|||
user:
|
||||
normal:
|
||||
a: 1500
|
||||
m: 50
|
||||
chains:
|
||||
userset:
|
||||
interval: 1800000,
|
||||
num: 1000
|
||||
|
||||
crown:
|
||||
normal:
|
||||
a: 600
|
||||
m: 50
|
||||
chains:
|
||||
userset:
|
||||
interval: 1800000,
|
||||
num: 1000
|
||||
|
||||
admin:
|
||||
normal:
|
||||
a: 120
|
||||
m: 16.6666666667
|
||||
chains:
|
||||
userset:
|
||||
interval: 1800000,
|
||||
num: 1000
|
|
@ -1,35 +0,0 @@
|
|||
module.exports = Object.seal({
|
||||
chat: {
|
||||
lobby: {
|
||||
amount: 4,
|
||||
time: 4000
|
||||
},
|
||||
normal: {
|
||||
amount: 4,
|
||||
time: 4000
|
||||
},
|
||||
insane: {
|
||||
amount: 10,
|
||||
time: 4000
|
||||
}
|
||||
},
|
||||
chown: {
|
||||
amount: 10,
|
||||
time: 5000
|
||||
},
|
||||
userset: {
|
||||
amount: 30,
|
||||
time: 30 * 60000
|
||||
},
|
||||
room: {
|
||||
time: 500
|
||||
},
|
||||
cursor: {
|
||||
time: 16,
|
||||
amount: 10
|
||||
},
|
||||
kickban: {
|
||||
amount: 2,
|
||||
time: 1000
|
||||
}
|
||||
});
|
|
@ -1,37 +0,0 @@
|
|||
[
|
||||
"68.106.138.210",
|
||||
"154.28.188.216",
|
||||
"154.28.188.214",
|
||||
"154.28.188.217",
|
||||
"154.28.188.215",
|
||||
"154.28.188.213",
|
||||
"154.28.188.212",
|
||||
"154.28.188.220",
|
||||
"154.28.188.219",
|
||||
"154.28.188.218",
|
||||
"154.28.188.222",
|
||||
"154.28.188.223",
|
||||
"154.28.188.221",
|
||||
"154.28.188.224",
|
||||
"154.28.188.226",
|
||||
"154.28.188.225",
|
||||
"177.54.145.61",
|
||||
"213.6.141.146",
|
||||
"103.23.101.30",
|
||||
"210.245.51.15",
|
||||
"91.237.161.211",
|
||||
"213.136.89.190",
|
||||
"177.137.168.132",
|
||||
"92.86.33.126",
|
||||
"138.97.236.2",
|
||||
"119.243.95.62",
|
||||
"49.51.74.19",
|
||||
"31.128.248.1",
|
||||
"185.220.102.245",
|
||||
"61.41.9.213",
|
||||
"103.25.120.138",
|
||||
"46.8.247.3",
|
||||
"45.70.84.46",
|
||||
"46.0.205.175",
|
||||
"36.94.126.50"
|
||||
]
|
|
@ -1,3 +0,0 @@
|
|||
const ColorEncoder = require("./src/ColorEncoder");
|
||||
|
||||
// console.log(ColorEncoder.getTimeColor(new Date("Dec 30 1970")).toHexa());
|
|
@ -1,28 +0,0 @@
|
|||
module.exports = Object.seal({
|
||||
port: 8443,
|
||||
motd: "humongous clement",
|
||||
_id_PrivateKey: process.env.SALT,
|
||||
|
||||
// defaultLobbyColor: "#19b4b9",
|
||||
// defaultLobbyColor2: "#801014",
|
||||
defaultLobbyColor: "#76b0db",
|
||||
defaultLobbyColor2: "#276491",
|
||||
// defaultLobbyColor: "#9900ff",
|
||||
// defaultLobbyColor2: "#5900af",
|
||||
|
||||
defaultUsername: "Anonymous",
|
||||
adminpass: process.env.ADMINPASS,
|
||||
ssl: process.env.SSL,
|
||||
serveFiles: true,
|
||||
defaultRoomSettings: {
|
||||
// color: "#3b5054",
|
||||
// color2: "#001014",
|
||||
|
||||
color: "#480505",
|
||||
crownsolo: false,
|
||||
visible: true
|
||||
},
|
||||
|
||||
hostDevFiles: true,
|
||||
enableMPPCloneBot: false
|
||||
});
|
|
@ -1,16 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<coverage generated="1656215259556" clover="3.2.0">
|
||||
<project timestamp="1656215259556" name="All files">
|
||||
<metrics statements="7" coveredstatements="7" conditionals="0" coveredconditionals="0" methods="2" coveredmethods="2" elements="9" coveredelements="9" complexity="0" loc="7" ncloc="7" packages="1" files="1" classes="1"/>
|
||||
<file name="Crown.js" path="Z:\mpp-server\src\Crown.js">
|
||||
<metrics statements="7" coveredstatements="7" conditionals="0" coveredconditionals="0" methods="2" coveredmethods="2"/>
|
||||
<line num="3" count="3" type="stmt"/>
|
||||
<line num="4" count="3" type="stmt"/>
|
||||
<line num="5" count="3" type="stmt"/>
|
||||
<line num="6" count="3" type="stmt"/>
|
||||
<line num="10" count="3" type="stmt"/>
|
||||
<line num="17" count="6" type="stmt"/>
|
||||
<line num="21" count="1" type="stmt"/>
|
||||
</file>
|
||||
</project>
|
||||
</coverage>
|
|
@ -1,2 +0,0 @@
|
|||
{"Z:\\mpp-server\\src\\Crown.js": {"path":"Z:\\mpp-server\\src\\Crown.js","statementMap":{"0":{"start":{"line":3,"column":8},"end":{"line":3,"column":32}},"1":{"start":{"line":4,"column":8},"end":{"line":4,"column":26}},"2":{"start":{"line":5,"column":8},"end":{"line":5,"column":31}},"3":{"start":{"line":6,"column":8},"end":{"line":9,"column":9}},"4":{"start":{"line":10,"column":8},"end":{"line":13,"column":9}},"5":{"start":{"line":17,"column":8},"end":{"line":17,"column":55}},"6":{"start":{"line":21,"column":0},"end":{"line":21,"column":23}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":2,"column":4},"end":{"line":2,"column":5}},"loc":{"start":{"line":2,"column":26},"end":{"line":14,"column":5}},"line":2},"1":{"name":"(anonymous_1)","decl":{"start":{"line":16,"column":4},"end":{"line":16,"column":5}},"loc":{"start":{"line":16,"column":31},"end":{"line":18,"column":5}},"line":16}},"branchMap":{},"s":{"0":3,"1":3,"2":3,"3":3,"4":3,"5":6,"6":1},"f":{"0":3,"1":6},"b":{},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"40c7ee2fa87e854156e60f42bacf48fffd8b89df"}
|
||||
}
|
|
@ -1,151 +0,0 @@
|
|||
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<title>Code coverage report for Crown.js</title>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="stylesheet" href="prettify.css" />
|
||||
<link rel="stylesheet" href="base.css" />
|
||||
<link rel="shortcut icon" type="image/x-icon" href="favicon.png" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<style type='text/css'>
|
||||
.coverage-summary .sorter {
|
||||
background-image: url(sort-arrow-sprite.png);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class='wrapper'>
|
||||
<div class='pad1'>
|
||||
<h1><a href="index.html">All files</a> Crown.js</h1>
|
||||
<div class='clearfix'>
|
||||
|
||||
<div class='fl pad1y space-right2'>
|
||||
<span class="strong">100% </span>
|
||||
<span class="quiet">Statements</span>
|
||||
<span class='fraction'>7/7</span>
|
||||
</div>
|
||||
|
||||
|
||||
<div class='fl pad1y space-right2'>
|
||||
<span class="strong">100% </span>
|
||||
<span class="quiet">Branches</span>
|
||||
<span class='fraction'>0/0</span>
|
||||
</div>
|
||||
|
||||
|
||||
<div class='fl pad1y space-right2'>
|
||||
<span class="strong">100% </span>
|
||||
<span class="quiet">Functions</span>
|
||||
<span class='fraction'>2/2</span>
|
||||
</div>
|
||||
|
||||
|
||||
<div class='fl pad1y space-right2'>
|
||||
<span class="strong">100% </span>
|
||||
<span class="quiet">Lines</span>
|
||||
<span class='fraction'>7/7</span>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
<p class="quiet">
|
||||
Press <em>n</em> or <em>j</em> to go to the next uncovered block, <em>b</em>, <em>p</em> or <em>k</em> for the previous block.
|
||||
</p>
|
||||
<template id="filterTemplate">
|
||||
<div class="quiet">
|
||||
Filter:
|
||||
<input oninput="onInput()" type="search" id="fileSearch">
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
<div class='status-line high'></div>
|
||||
<pre><table class="coverage">
|
||||
<tr><td class="line-count quiet"><a name='L1'></a><a href='#L1'>1</a>
|
||||
<a name='L2'></a><a href='#L2'>2</a>
|
||||
<a name='L3'></a><a href='#L3'>3</a>
|
||||
<a name='L4'></a><a href='#L4'>4</a>
|
||||
<a name='L5'></a><a href='#L5'>5</a>
|
||||
<a name='L6'></a><a href='#L6'>6</a>
|
||||
<a name='L7'></a><a href='#L7'>7</a>
|
||||
<a name='L8'></a><a href='#L8'>8</a>
|
||||
<a name='L9'></a><a href='#L9'>9</a>
|
||||
<a name='L10'></a><a href='#L10'>10</a>
|
||||
<a name='L11'></a><a href='#L11'>11</a>
|
||||
<a name='L12'></a><a href='#L12'>12</a>
|
||||
<a name='L13'></a><a href='#L13'>13</a>
|
||||
<a name='L14'></a><a href='#L14'>14</a>
|
||||
<a name='L15'></a><a href='#L15'>15</a>
|
||||
<a name='L16'></a><a href='#L16'>16</a>
|
||||
<a name='L17'></a><a href='#L17'>17</a>
|
||||
<a name='L18'></a><a href='#L18'>18</a>
|
||||
<a name='L19'></a><a href='#L19'>19</a>
|
||||
<a name='L20'></a><a href='#L20'>20</a>
|
||||
<a name='L21'></a><a href='#L21'>21</a>
|
||||
<a name='L22'></a><a href='#L22'>22</a>
|
||||
<a name='L23'></a><a href='#L23'>23</a></td><td class="line-coverage quiet"><span class="cline-any cline-neutral"> </span>
|
||||
<span class="cline-any cline-neutral"> </span>
|
||||
<span class="cline-any cline-yes">3x</span>
|
||||
<span class="cline-any cline-yes">3x</span>
|
||||
<span class="cline-any cline-yes">3x</span>
|
||||
<span class="cline-any cline-yes">3x</span>
|
||||
<span class="cline-any cline-neutral"> </span>
|
||||
<span class="cline-any cline-neutral"> </span>
|
||||
<span class="cline-any cline-neutral"> </span>
|
||||
<span class="cline-any cline-yes">3x</span>
|
||||
<span class="cline-any cline-neutral"> </span>
|
||||
<span class="cline-any cline-neutral"> </span>
|
||||
<span class="cline-any cline-neutral"> </span>
|
||||
<span class="cline-any cline-neutral"> </span>
|
||||
<span class="cline-any cline-neutral"> </span>
|
||||
<span class="cline-any cline-neutral"> </span>
|
||||
<span class="cline-any cline-yes">6x</span>
|
||||
<span class="cline-any cline-neutral"> </span>
|
||||
<span class="cline-any cline-neutral"> </span>
|
||||
<span class="cline-any cline-neutral"> </span>
|
||||
<span class="cline-any cline-yes">1x</span>
|
||||
<span class="cline-any cline-neutral"> </span>
|
||||
<span class="cline-any cline-neutral"> </span></td><td class="text"><pre class="prettyprint lang-js">class Crown {
|
||||
constructor (id, _id) {
|
||||
this.participantId = id;
|
||||
this.userId = _id;
|
||||
this.time = Date.now();
|
||||
this.startPos = {
|
||||
x: 50,
|
||||
y: 50
|
||||
}
|
||||
this.endPos = {
|
||||
x: Crown.generateRandomPos(),
|
||||
y: Crown.generateRandomPos()
|
||||
}
|
||||
}
|
||||
|
||||
static generateRandomPos() {
|
||||
return Math.floor(Math.random() * 10000) / 100;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Crown;
|
||||
|
||||
</pre></td></tr></table></pre>
|
||||
|
||||
<div class='push'></div><!-- for sticky footer -->
|
||||
</div><!-- /wrapper -->
|
||||
<div class='footer quiet pad2 space-top1 center small'>
|
||||
Code coverage generated by
|
||||
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
|
||||
at Sat Jun 25 2022 23:47:39 GMT-0400 (Eastern Daylight Time)
|
||||
</div>
|
||||
<script src="prettify.js"></script>
|
||||
<script>
|
||||
window.onload = function () {
|
||||
prettyPrint();
|
||||
};
|
||||
</script>
|
||||
<script src="sorter.js"></script>
|
||||
<script src="block-navigation.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,224 +0,0 @@
|
|||
body, html {
|
||||
margin:0; padding: 0;
|
||||
height: 100%;
|
||||
}
|
||||
body {
|
||||
font-family: Helvetica Neue, Helvetica, Arial;
|
||||
font-size: 14px;
|
||||
color:#333;
|
||||
}
|
||||
.small { font-size: 12px; }
|
||||
*, *:after, *:before {
|
||||
-webkit-box-sizing:border-box;
|
||||
-moz-box-sizing:border-box;
|
||||
box-sizing:border-box;
|
||||
}
|
||||
h1 { font-size: 20px; margin: 0;}
|
||||
h2 { font-size: 14px; }
|
||||
pre {
|
||||
font: 12px/1.4 Consolas, "Liberation Mono", Menlo, Courier, monospace;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
-moz-tab-size: 2;
|
||||
-o-tab-size: 2;
|
||||
tab-size: 2;
|
||||
}
|
||||
a { color:#0074D9; text-decoration:none; }
|
||||
a:hover { text-decoration:underline; }
|
||||
.strong { font-weight: bold; }
|
||||
.space-top1 { padding: 10px 0 0 0; }
|
||||
.pad2y { padding: 20px 0; }
|
||||
.pad1y { padding: 10px 0; }
|
||||
.pad2x { padding: 0 20px; }
|
||||
.pad2 { padding: 20px; }
|
||||
.pad1 { padding: 10px; }
|
||||
.space-left2 { padding-left:55px; }
|
||||
.space-right2 { padding-right:20px; }
|
||||
.center { text-align:center; }
|
||||
.clearfix { display:block; }
|
||||
.clearfix:after {
|
||||
content:'';
|
||||
display:block;
|
||||
height:0;
|
||||
clear:both;
|
||||
visibility:hidden;
|
||||
}
|
||||
.fl { float: left; }
|
||||
@media only screen and (max-width:640px) {
|
||||
.col3 { width:100%; max-width:100%; }
|
||||
.hide-mobile { display:none!important; }
|
||||
}
|
||||
|
||||
.quiet {
|
||||
color: #7f7f7f;
|
||||
color: rgba(0,0,0,0.5);
|
||||
}
|
||||
.quiet a { opacity: 0.7; }
|
||||
|
||||
.fraction {
|
||||
font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace;
|
||||
font-size: 10px;
|
||||
color: #555;
|
||||
background: #E8E8E8;
|
||||
padding: 4px 5px;
|
||||
border-radius: 3px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
div.path a:link, div.path a:visited { color: #333; }
|
||||
table.coverage {
|
||||
border-collapse: collapse;
|
||||
margin: 10px 0 0 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
table.coverage td {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
vertical-align: top;
|
||||
}
|
||||
table.coverage td.line-count {
|
||||
text-align: right;
|
||||
padding: 0 5px 0 20px;
|
||||
}
|
||||
table.coverage td.line-coverage {
|
||||
text-align: right;
|
||||
padding-right: 10px;
|
||||
min-width:20px;
|
||||
}
|
||||
|
||||
table.coverage td span.cline-any {
|
||||
display: inline-block;
|
||||
padding: 0 5px;
|
||||
width: 100%;
|
||||
}
|
||||
.missing-if-branch {
|
||||
display: inline-block;
|
||||
margin-right: 5px;
|
||||
border-radius: 3px;
|
||||
position: relative;
|
||||
padding: 0 4px;
|
||||
background: #333;
|
||||
color: yellow;
|
||||
}
|
||||
|
||||
.skip-if-branch {
|
||||
display: none;
|
||||
margin-right: 10px;
|
||||
position: relative;
|
||||
padding: 0 4px;
|
||||
background: #ccc;
|
||||
color: white;
|
||||
}
|
||||
.missing-if-branch .typ, .skip-if-branch .typ {
|
||||
color: inherit !important;
|
||||
}
|
||||
.coverage-summary {
|
||||
border-collapse: collapse;
|
||||
width: 100%;
|
||||
}
|
||||
.coverage-summary tr { border-bottom: 1px solid #bbb; }
|
||||
.keyline-all { border: 1px solid #ddd; }
|
||||
.coverage-summary td, .coverage-summary th { padding: 10px; }
|
||||
.coverage-summary tbody { border: 1px solid #bbb; }
|
||||
.coverage-summary td { border-right: 1px solid #bbb; }
|
||||
.coverage-summary td:last-child { border-right: none; }
|
||||
.coverage-summary th {
|
||||
text-align: left;
|
||||
font-weight: normal;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.coverage-summary th.file { border-right: none !important; }
|
||||
.coverage-summary th.pct { }
|
||||
.coverage-summary th.pic,
|
||||
.coverage-summary th.abs,
|
||||
.coverage-summary td.pct,
|
||||
.coverage-summary td.abs { text-align: right; }
|
||||
.coverage-summary td.file { white-space: nowrap; }
|
||||
.coverage-summary td.pic { min-width: 120px !important; }
|
||||
.coverage-summary tfoot td { }
|
||||
|
||||
.coverage-summary .sorter {
|
||||
height: 10px;
|
||||
width: 7px;
|
||||
display: inline-block;
|
||||
margin-left: 0.5em;
|
||||
background: url(sort-arrow-sprite.png) no-repeat scroll 0 0 transparent;
|
||||
}
|
||||
.coverage-summary .sorted .sorter {
|
||||
background-position: 0 -20px;
|
||||
}
|
||||
.coverage-summary .sorted-desc .sorter {
|
||||
background-position: 0 -10px;
|
||||
}
|
||||
.status-line { height: 10px; }
|
||||
/* yellow */
|
||||
.cbranch-no { background: yellow !important; color: #111; }
|
||||
/* dark red */
|
||||
.red.solid, .status-line.low, .low .cover-fill { background:#C21F39 }
|
||||
.low .chart { border:1px solid #C21F39 }
|
||||
.highlighted,
|
||||
.highlighted .cstat-no, .highlighted .fstat-no, .highlighted .cbranch-no{
|
||||
background: #C21F39 !important;
|
||||
}
|
||||
/* medium red */
|
||||
.cstat-no, .fstat-no, .cbranch-no, .cbranch-no { background:#F6C6CE }
|
||||
/* light red */
|
||||
.low, .cline-no { background:#FCE1E5 }
|
||||
/* light green */
|
||||
.high, .cline-yes { background:rgb(230,245,208) }
|
||||
/* medium green */
|
||||
.cstat-yes { background:rgb(161,215,106) }
|
||||
/* dark green */
|
||||
.status-line.high, .high .cover-fill { background:rgb(77,146,33) }
|
||||
.high .chart { border:1px solid rgb(77,146,33) }
|
||||
/* dark yellow (gold) */
|
||||
.status-line.medium, .medium .cover-fill { background: #f9cd0b; }
|
||||
.medium .chart { border:1px solid #f9cd0b; }
|
||||
/* light yellow */
|
||||
.medium { background: #fff4c2; }
|
||||
|
||||
.cstat-skip { background: #ddd; color: #111; }
|
||||
.fstat-skip { background: #ddd; color: #111 !important; }
|
||||
.cbranch-skip { background: #ddd !important; color: #111; }
|
||||
|
||||
span.cline-neutral { background: #eaeaea; }
|
||||
|
||||
.coverage-summary td.empty {
|
||||
opacity: .5;
|
||||
padding-top: 4px;
|
||||
padding-bottom: 4px;
|
||||
line-height: 1;
|
||||
color: #888;
|
||||
}
|
||||
|
||||
.cover-fill, .cover-empty {
|
||||
display:inline-block;
|
||||
height: 12px;
|
||||
}
|
||||
.chart {
|
||||
line-height: 0;
|
||||
}
|
||||
.cover-empty {
|
||||
background: white;
|
||||
}
|
||||
.cover-full {
|
||||
border-right: none !important;
|
||||
}
|
||||
pre.prettyprint {
|
||||
border: none !important;
|
||||
padding: 0 !important;
|
||||
margin: 0 !important;
|
||||
}
|
||||
.com { color: #999 !important; }
|
||||
.ignore-none { color: #999; font-weight: normal; }
|
||||
|
||||
.wrapper {
|
||||
min-height: 100%;
|
||||
height: auto !important;
|
||||
height: 100%;
|
||||
margin: 0 auto -48px;
|
||||
}
|
||||
.footer, .push {
|
||||
height: 48px;
|
||||
}
|
|
@ -1,87 +0,0 @@
|
|||
/* eslint-disable */
|
||||
var jumpToCode = (function init() {
|
||||
// Classes of code we would like to highlight in the file view
|
||||
var missingCoverageClasses = ['.cbranch-no', '.cstat-no', '.fstat-no'];
|
||||
|
||||
// Elements to highlight in the file listing view
|
||||
var fileListingElements = ['td.pct.low'];
|
||||
|
||||
// We don't want to select elements that are direct descendants of another match
|
||||
var notSelector = ':not(' + missingCoverageClasses.join('):not(') + ') > '; // becomes `:not(a):not(b) > `
|
||||
|
||||
// Selecter that finds elements on the page to which we can jump
|
||||
var selector =
|
||||
fileListingElements.join(', ') +
|
||||
', ' +
|
||||
notSelector +
|
||||
missingCoverageClasses.join(', ' + notSelector); // becomes `:not(a):not(b) > a, :not(a):not(b) > b`
|
||||
|
||||
// The NodeList of matching elements
|
||||
var missingCoverageElements = document.querySelectorAll(selector);
|
||||
|
||||
var currentIndex;
|
||||
|
||||
function toggleClass(index) {
|
||||
missingCoverageElements
|
||||
.item(currentIndex)
|
||||
.classList.remove('highlighted');
|
||||
missingCoverageElements.item(index).classList.add('highlighted');
|
||||
}
|
||||
|
||||
function makeCurrent(index) {
|
||||
toggleClass(index);
|
||||
currentIndex = index;
|
||||
missingCoverageElements.item(index).scrollIntoView({
|
||||
behavior: 'smooth',
|
||||
block: 'center',
|
||||
inline: 'center'
|
||||
});
|
||||
}
|
||||
|
||||
function goToPrevious() {
|
||||
var nextIndex = 0;
|
||||
if (typeof currentIndex !== 'number' || currentIndex === 0) {
|
||||
nextIndex = missingCoverageElements.length - 1;
|
||||
} else if (missingCoverageElements.length > 1) {
|
||||
nextIndex = currentIndex - 1;
|
||||
}
|
||||
|
||||
makeCurrent(nextIndex);
|
||||
}
|
||||
|
||||
function goToNext() {
|
||||
var nextIndex = 0;
|
||||
|
||||
if (
|
||||
typeof currentIndex === 'number' &&
|
||||
currentIndex < missingCoverageElements.length - 1
|
||||
) {
|
||||
nextIndex = currentIndex + 1;
|
||||
}
|
||||
|
||||
makeCurrent(nextIndex);
|
||||
}
|
||||
|
||||
return function jump(event) {
|
||||
if (
|
||||
document.getElementById('fileSearch') === document.activeElement &&
|
||||
document.activeElement != null
|
||||
) {
|
||||
// if we're currently focused on the search input, we don't want to navigate
|
||||
return;
|
||||
}
|
||||
|
||||
switch (event.which) {
|
||||
case 78: // n
|
||||
case 74: // j
|
||||
goToNext();
|
||||
break;
|
||||
case 66: // b
|
||||
case 75: // k
|
||||
case 80: // p
|
||||
goToPrevious();
|
||||
break;
|
||||
}
|
||||
};
|
||||
})();
|
||||
window.addEventListener('keydown', jumpToCode);
|
Binary file not shown.
Before Width: | Height: | Size: 540 B |
|
@ -1,116 +0,0 @@
|
|||
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<title>Code coverage report for All files</title>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="stylesheet" href="prettify.css" />
|
||||
<link rel="stylesheet" href="base.css" />
|
||||
<link rel="shortcut icon" type="image/x-icon" href="favicon.png" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<style type='text/css'>
|
||||
.coverage-summary .sorter {
|
||||
background-image: url(sort-arrow-sprite.png);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class='wrapper'>
|
||||
<div class='pad1'>
|
||||
<h1>All files</h1>
|
||||
<div class='clearfix'>
|
||||
|
||||
<div class='fl pad1y space-right2'>
|
||||
<span class="strong">100% </span>
|
||||
<span class="quiet">Statements</span>
|
||||
<span class='fraction'>7/7</span>
|
||||
</div>
|
||||
|
||||
|
||||
<div class='fl pad1y space-right2'>
|
||||
<span class="strong">100% </span>
|
||||
<span class="quiet">Branches</span>
|
||||
<span class='fraction'>0/0</span>
|
||||
</div>
|
||||
|
||||
|
||||
<div class='fl pad1y space-right2'>
|
||||
<span class="strong">100% </span>
|
||||
<span class="quiet">Functions</span>
|
||||
<span class='fraction'>2/2</span>
|
||||
</div>
|
||||
|
||||
|
||||
<div class='fl pad1y space-right2'>
|
||||
<span class="strong">100% </span>
|
||||
<span class="quiet">Lines</span>
|
||||
<span class='fraction'>7/7</span>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
<p class="quiet">
|
||||
Press <em>n</em> or <em>j</em> to go to the next uncovered block, <em>b</em>, <em>p</em> or <em>k</em> for the previous block.
|
||||
</p>
|
||||
<template id="filterTemplate">
|
||||
<div class="quiet">
|
||||
Filter:
|
||||
<input oninput="onInput()" type="search" id="fileSearch">
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
<div class='status-line high'></div>
|
||||
<div class="pad1">
|
||||
<table class="coverage-summary">
|
||||
<thead>
|
||||
<tr>
|
||||
<th data-col="file" data-fmt="html" data-html="true" class="file">File</th>
|
||||
<th data-col="pic" data-type="number" data-fmt="html" data-html="true" class="pic"></th>
|
||||
<th data-col="statements" data-type="number" data-fmt="pct" class="pct">Statements</th>
|
||||
<th data-col="statements_raw" data-type="number" data-fmt="html" class="abs"></th>
|
||||
<th data-col="branches" data-type="number" data-fmt="pct" class="pct">Branches</th>
|
||||
<th data-col="branches_raw" data-type="number" data-fmt="html" class="abs"></th>
|
||||
<th data-col="functions" data-type="number" data-fmt="pct" class="pct">Functions</th>
|
||||
<th data-col="functions_raw" data-type="number" data-fmt="html" class="abs"></th>
|
||||
<th data-col="lines" data-type="number" data-fmt="pct" class="pct">Lines</th>
|
||||
<th data-col="lines_raw" data-type="number" data-fmt="html" class="abs"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody><tr>
|
||||
<td class="file high" data-value="Crown.js"><a href="Crown.js.html">Crown.js</a></td>
|
||||
<td data-value="100" class="pic high">
|
||||
<div class="chart"><div class="cover-fill cover-full" style="width: 100%"></div><div class="cover-empty" style="width: 0%"></div></div>
|
||||
</td>
|
||||
<td data-value="100" class="pct high">100%</td>
|
||||
<td data-value="7" class="abs high">7/7</td>
|
||||
<td data-value="100" class="pct high">100%</td>
|
||||
<td data-value="0" class="abs high">0/0</td>
|
||||
<td data-value="100" class="pct high">100%</td>
|
||||
<td data-value="2" class="abs high">2/2</td>
|
||||
<td data-value="100" class="pct high">100%</td>
|
||||
<td data-value="7" class="abs high">7/7</td>
|
||||
</tr>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class='push'></div><!-- for sticky footer -->
|
||||
</div><!-- /wrapper -->
|
||||
<div class='footer quiet pad2 space-top1 center small'>
|
||||
Code coverage generated by
|
||||
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
|
||||
at Sat Jun 25 2022 23:47:39 GMT-0400 (Eastern Daylight Time)
|
||||
</div>
|
||||
<script src="prettify.js"></script>
|
||||
<script>
|
||||
window.onload = function () {
|
||||
prettyPrint();
|
||||
};
|
||||
</script>
|
||||
<script src="sorter.js"></script>
|
||||
<script src="block-navigation.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1 +0,0 @@
|
|||
.pln{color:#000}@media screen{.str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.pun,.opn,.clo{color:#660}.tag{color:#008}.atn{color:#606}.atv{color:#080}.dec,.var{color:#606}.fun{color:red}}@media print,projection{.str{color:#060}.kwd{color:#006;font-weight:bold}.com{color:#600;font-style:italic}.typ{color:#404;font-weight:bold}.lit{color:#044}.pun,.opn,.clo{color:#440}.tag{color:#006;font-weight:bold}.atn{color:#404}.atv{color:#060}}pre.prettyprint{padding:2px;border:1px solid #888}ol.linenums{margin-top:0;margin-bottom:0}li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style-type:none}li.L1,li.L3,li.L5,li.L7,li.L9{background:#eee}
|
File diff suppressed because one or more lines are too long
Binary file not shown.
Before Width: | Height: | Size: 209 B |
|
@ -1,196 +0,0 @@
|
|||
/* eslint-disable */
|
||||
var addSorting = (function() {
|
||||
'use strict';
|
||||
var cols,
|
||||
currentSort = {
|
||||
index: 0,
|
||||
desc: false
|
||||
};
|
||||
|
||||
// returns the summary table element
|
||||
function getTable() {
|
||||
return document.querySelector('.coverage-summary');
|
||||
}
|
||||
// returns the thead element of the summary table
|
||||
function getTableHeader() {
|
||||
return getTable().querySelector('thead tr');
|
||||
}
|
||||
// returns the tbody element of the summary table
|
||||
function getTableBody() {
|
||||
return getTable().querySelector('tbody');
|
||||
}
|
||||
// returns the th element for nth column
|
||||
function getNthColumn(n) {
|
||||
return getTableHeader().querySelectorAll('th')[n];
|
||||
}
|
||||
|
||||
function onFilterInput() {
|
||||
const searchValue = document.getElementById('fileSearch').value;
|
||||
const rows = document.getElementsByTagName('tbody')[0].children;
|
||||
for (let i = 0; i < rows.length; i++) {
|
||||
const row = rows[i];
|
||||
if (
|
||||
row.textContent
|
||||
.toLowerCase()
|
||||
.includes(searchValue.toLowerCase())
|
||||
) {
|
||||
row.style.display = '';
|
||||
} else {
|
||||
row.style.display = 'none';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// loads the search box
|
||||
function addSearchBox() {
|
||||
var template = document.getElementById('filterTemplate');
|
||||
var templateClone = template.content.cloneNode(true);
|
||||
templateClone.getElementById('fileSearch').oninput = onFilterInput;
|
||||
template.parentElement.appendChild(templateClone);
|
||||
}
|
||||
|
||||
// loads all columns
|
||||
function loadColumns() {
|
||||
var colNodes = getTableHeader().querySelectorAll('th'),
|
||||
colNode,
|
||||
cols = [],
|
||||
col,
|
||||
i;
|
||||
|
||||
for (i = 0; i < colNodes.length; i += 1) {
|
||||
colNode = colNodes[i];
|
||||
col = {
|
||||
key: colNode.getAttribute('data-col'),
|
||||
sortable: !colNode.getAttribute('data-nosort'),
|
||||
type: colNode.getAttribute('data-type') || 'string'
|
||||
};
|
||||
cols.push(col);
|
||||
if (col.sortable) {
|
||||
col.defaultDescSort = col.type === 'number';
|
||||
colNode.innerHTML =
|
||||
colNode.innerHTML + '<span class="sorter"></span>';
|
||||
}
|
||||
}
|
||||
return cols;
|
||||
}
|
||||
// attaches a data attribute to every tr element with an object
|
||||
// of data values keyed by column name
|
||||
function loadRowData(tableRow) {
|
||||
var tableCols = tableRow.querySelectorAll('td'),
|
||||
colNode,
|
||||
col,
|
||||
data = {},
|
||||
i,
|
||||
val;
|
||||
for (i = 0; i < tableCols.length; i += 1) {
|
||||
colNode = tableCols[i];
|
||||
col = cols[i];
|
||||
val = colNode.getAttribute('data-value');
|
||||
if (col.type === 'number') {
|
||||
val = Number(val);
|
||||
}
|
||||
data[col.key] = val;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
// loads all row data
|
||||
function loadData() {
|
||||
var rows = getTableBody().querySelectorAll('tr'),
|
||||
i;
|
||||
|
||||
for (i = 0; i < rows.length; i += 1) {
|
||||
rows[i].data = loadRowData(rows[i]);
|
||||
}
|
||||
}
|
||||
// sorts the table using the data for the ith column
|
||||
function sortByIndex(index, desc) {
|
||||
var key = cols[index].key,
|
||||
sorter = function(a, b) {
|
||||
a = a.data[key];
|
||||
b = b.data[key];
|
||||
return a < b ? -1 : a > b ? 1 : 0;
|
||||
},
|
||||
finalSorter = sorter,
|
||||
tableBody = document.querySelector('.coverage-summary tbody'),
|
||||
rowNodes = tableBody.querySelectorAll('tr'),
|
||||
rows = [],
|
||||
i;
|
||||
|
||||
if (desc) {
|
||||
finalSorter = function(a, b) {
|
||||
return -1 * sorter(a, b);
|
||||
};
|
||||
}
|
||||
|
||||
for (i = 0; i < rowNodes.length; i += 1) {
|
||||
rows.push(rowNodes[i]);
|
||||
tableBody.removeChild(rowNodes[i]);
|
||||
}
|
||||
|
||||
rows.sort(finalSorter);
|
||||
|
||||
for (i = 0; i < rows.length; i += 1) {
|
||||
tableBody.appendChild(rows[i]);
|
||||
}
|
||||
}
|
||||
// removes sort indicators for current column being sorted
|
||||
function removeSortIndicators() {
|
||||
var col = getNthColumn(currentSort.index),
|
||||
cls = col.className;
|
||||
|
||||
cls = cls.replace(/ sorted$/, '').replace(/ sorted-desc$/, '');
|
||||
col.className = cls;
|
||||
}
|
||||
// adds sort indicators for current column being sorted
|
||||
function addSortIndicators() {
|
||||
getNthColumn(currentSort.index).className += currentSort.desc
|
||||
? ' sorted-desc'
|
||||
: ' sorted';
|
||||
}
|
||||
// adds event listeners for all sorter widgets
|
||||
function enableUI() {
|
||||
var i,
|
||||
el,
|
||||
ithSorter = function ithSorter(i) {
|
||||
var col = cols[i];
|
||||
|
||||
return function() {
|
||||
var desc = col.defaultDescSort;
|
||||
|
||||
if (currentSort.index === i) {
|
||||
desc = !currentSort.desc;
|
||||
}
|
||||
sortByIndex(i, desc);
|
||||
removeSortIndicators();
|
||||
currentSort.index = i;
|
||||
currentSort.desc = desc;
|
||||
addSortIndicators();
|
||||
};
|
||||
};
|
||||
for (i = 0; i < cols.length; i += 1) {
|
||||
if (cols[i].sortable) {
|
||||
// add the click event handler on the th so users
|
||||
// dont have to click on those tiny arrows
|
||||
el = getNthColumn(i).querySelector('.sorter').parentElement;
|
||||
if (el.addEventListener) {
|
||||
el.addEventListener('click', ithSorter(i));
|
||||
} else {
|
||||
el.attachEvent('onclick', ithSorter(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// adds sorting functionality to the UI
|
||||
return function() {
|
||||
if (!getTable()) {
|
||||
return;
|
||||
}
|
||||
cols = loadColumns();
|
||||
loadData();
|
||||
addSearchBox();
|
||||
addSortIndicators();
|
||||
enableUI();
|
||||
};
|
||||
})();
|
||||
|
||||
window.addEventListener('load', addSorting);
|
|
@ -1,20 +0,0 @@
|
|||
TN:
|
||||
SF:src\Crown.js
|
||||
FN:2,(anonymous_0)
|
||||
FN:16,(anonymous_1)
|
||||
FNF:2
|
||||
FNH:2
|
||||
FNDA:3,(anonymous_0)
|
||||
FNDA:6,(anonymous_1)
|
||||
DA:3,3
|
||||
DA:4,3
|
||||
DA:5,3
|
||||
DA:6,3
|
||||
DA:10,3
|
||||
DA:17,6
|
||||
DA:21,1
|
||||
LF:7
|
||||
LH:7
|
||||
BRF:0
|
||||
BRH:0
|
||||
end_of_record
|
|
@ -1,72 +0,0 @@
|
|||
// dotenv
|
||||
require('dotenv').config();
|
||||
|
||||
// call new Server
|
||||
global.WebSocket = require('ws');
|
||||
global.EventEmitter = require('events').EventEmitter;
|
||||
global.fs = require('fs');
|
||||
const AsyncConsole = require('asyncconsole');
|
||||
|
||||
global.isString = function(a) {
|
||||
return typeof a === 'string';
|
||||
}
|
||||
|
||||
global.isBool = function(a) {
|
||||
return typeof a === 'boolean';
|
||||
}
|
||||
|
||||
global.isObj = function(a) {
|
||||
return typeof a === "object" && !Array.isArray(a) && a !== null;
|
||||
}
|
||||
|
||||
let Server = require("./src/Server.js");
|
||||
let config = require('./config');
|
||||
Server.start(config);
|
||||
global.SERVER = Server;
|
||||
|
||||
// doesn't work with pm2
|
||||
|
||||
/*
|
||||
let console = process.platform == 'win32' ? new AsyncConsole("", input => {
|
||||
try {
|
||||
console.log(JSON.stringify(eval(input)));
|
||||
} catch(e) {
|
||||
console.log(e.toString());
|
||||
}
|
||||
}) : {};
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// dev environment
|
||||
|
||||
if (config.hostDevFiles) {
|
||||
let express_logger = new (require("./src/Logger"))("Express Server");
|
||||
const express = require('express');
|
||||
const app = express();
|
||||
const path = require('path');
|
||||
var http = require('http');
|
||||
|
||||
let dir = path.join(__dirname, 'mpp.hri7566.info');
|
||||
app.use(express.static(path.join(__dirname, dir)));
|
||||
|
||||
app.get('*', (req, res, next) => {
|
||||
let file = path.join(dir, req.path);
|
||||
if (fs.existsSync(file) && !file.endsWith('/') && !file.endsWith('\\')) {
|
||||
res.sendFile(file);
|
||||
} else {
|
||||
res.sendFile(path.join(dir, 'index.html'));
|
||||
}
|
||||
});
|
||||
|
||||
const express_port = 8075;
|
||||
|
||||
http.createServer(app).listen(express_port);
|
||||
}
|
||||
|
||||
if (config.enableMPPCloneBot) {
|
||||
require('./mppclonebot');
|
||||
}
|
|
@ -1,231 +0,0 @@
|
|||
const Client = require('mppclone-client');
|
||||
const Logger = require('./src/Logger');
|
||||
const { EventEmitter } = require('events');
|
||||
|
||||
const token = process.env.MPPCLONE_TOKEN;
|
||||
|
||||
class Command {
|
||||
static commands = {};
|
||||
|
||||
static getUsage(us, prefix) {
|
||||
return us.split('%PREFIX%').join(prefix);
|
||||
}
|
||||
|
||||
constructor(cmd, desc, usage, minargs, func, minrank, hidden) {
|
||||
this.cmd = typeof cmd == 'object' ? cmd : [cmd];
|
||||
this.desc = desc || "No description";
|
||||
this.usage = usage || "No usage";
|
||||
this.minargs = minargs || 0;
|
||||
this.func = func;
|
||||
this.minrank = minrank || 0;
|
||||
this.hidden = hidden || false;
|
||||
|
||||
Command.commands[this.cmd[0]] = this;
|
||||
}
|
||||
}
|
||||
|
||||
class Rank {
|
||||
static ranks = {};
|
||||
|
||||
static user_ranks = {};
|
||||
|
||||
static setRank(_id, rank) {
|
||||
Rank.user_ranks[_id] = rank;
|
||||
}
|
||||
|
||||
static getRank(_id) {
|
||||
return Rank.user_ranks[_id];
|
||||
}
|
||||
|
||||
constructor(name, desc, minrank) {
|
||||
this.name = name;
|
||||
this.desc = desc;
|
||||
this.minrank = minrank;
|
||||
|
||||
Rank.ranks[name] = this;
|
||||
}
|
||||
}
|
||||
|
||||
new Rank("User", "Default rank", 0);
|
||||
new Rank("Mod", "Moderator rank", 1);
|
||||
new Rank("Admin", "Administrator rank", 2);
|
||||
new Rank("Owner", "Owner rank", 3);
|
||||
|
||||
class Prefix {
|
||||
static prefixes = {};
|
||||
|
||||
static hasAnyPrefix(str) {
|
||||
for (let i in Prefix.prefixes) {
|
||||
if (str.startsWith(Prefix.prefixes[i].prefix)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static getPrefixFromString(str) {
|
||||
for (let i in Prefix.prefixes) {
|
||||
if (str.startsWith(Prefix.prefixes[i].prefix)) {
|
||||
return Prefix.prefixes[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
constructor(id, prefix) {
|
||||
this.id = id;
|
||||
this.prefix = prefix;
|
||||
|
||||
Prefix.prefixes[id] = this;
|
||||
}
|
||||
}
|
||||
|
||||
class Bot extends EventEmitter {
|
||||
constructor(cl) {
|
||||
super();
|
||||
|
||||
this.logger = new Logger('MPPClone Bot');
|
||||
|
||||
this.client = cl;
|
||||
this.bindEventListeners();
|
||||
|
||||
this.userset = {
|
||||
name: 'mpp.hri7566.info [indev]', // TODO change this name
|
||||
color: '#76b0db'
|
||||
};
|
||||
|
||||
this.chatBuffer = [];
|
||||
this.chatBufferCycleCounter = 0;
|
||||
|
||||
this.chatBufferCycle();
|
||||
|
||||
this.client.start();
|
||||
this.client.setChannel('✧𝓓𝓔𝓥 𝓡𝓸𝓸𝓶✧');
|
||||
}
|
||||
|
||||
bindEventListeners() {
|
||||
this.client.on('a', msg => {
|
||||
this.emit('receiveChat', msg);
|
||||
});
|
||||
|
||||
this.client.on('ch', msg => {
|
||||
this.emit('resetName', msg);
|
||||
})
|
||||
|
||||
this.client.on('hi', msg => {
|
||||
this.emit('online', msg);
|
||||
});
|
||||
|
||||
this.client.on('t', msg => {
|
||||
this.emit('resetName', msg);
|
||||
});
|
||||
|
||||
this.on('resetName', () => {
|
||||
if (this.client.getOwnParticipant().name !== this.userset.name || this.client.getOwnParticipant().color !== this.userset.color) {
|
||||
this.client.sendArray([{
|
||||
m: 'userset',
|
||||
set: this.userset
|
||||
}]);
|
||||
}
|
||||
});
|
||||
|
||||
this.on('receiveChat', msg => {
|
||||
if (Prefix.hasAnyPrefix(msg.a)) {
|
||||
msg.prefix = Prefix.getPrefixFromString(msg.a);
|
||||
this.emit('runCommand', msg);
|
||||
}
|
||||
});
|
||||
|
||||
this.on('addToChatBuffer', msg => {
|
||||
this.chatBuffer.push(msg);
|
||||
});
|
||||
|
||||
this.on('runCommand', msg => {
|
||||
if (!msg.prefix) return;
|
||||
|
||||
msg.args = msg.a.split(' ');
|
||||
msg.cmd = msg.args[0].substring(msg.prefix.prefix.length).trim();
|
||||
msg.argcat = msg.a.substring(msg.args[0].length).trim();
|
||||
|
||||
let rank = Rank.getRank(msg.p._id);
|
||||
if (!rank) {
|
||||
rank = Rank.ranks['User'];
|
||||
Rank.setRank(msg.p._id, rank);
|
||||
}
|
||||
|
||||
msg.rank = rank;
|
||||
|
||||
for (let cmd of Object.values(Command.commands)) {
|
||||
if (!cmd.cmd.includes(msg.cmd)) continue;
|
||||
console.log(msg.cmd, cmd.cmd);
|
||||
if (msg.args.length < cmd.minargs) return;
|
||||
if (msg.rank.id < cmd.minrank) return;
|
||||
|
||||
try {
|
||||
let out = cmd.func(msg);
|
||||
if (!out) return;
|
||||
|
||||
out = out.split('\n').join(' ').split('\t').join(' ').split('\r').join(' ');
|
||||
|
||||
if (out !== '') {
|
||||
this.emit('addToChatBuffer', {
|
||||
m: 'a',
|
||||
message: out,
|
||||
p: msg.p._id
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
this.emit('addToChatBuffer', {
|
||||
m: 'a',
|
||||
message: 'An error has occurred.',
|
||||
p: msg.p._id
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.on('online', () => {
|
||||
this.logger.log('Connected');
|
||||
});
|
||||
}
|
||||
|
||||
async chatBufferCycle() {
|
||||
if (this.chatBuffer.length <= 0) {
|
||||
setTimeout(() => {
|
||||
this.chatBufferCycle();
|
||||
});
|
||||
return;
|
||||
}
|
||||
this.chatBufferCycleCounter++;
|
||||
let time = 0;
|
||||
if (this.chatBufferCycleCounter > 4) {
|
||||
time += 1000;
|
||||
}
|
||||
setTimeout(() => {
|
||||
let nextMessage = this.chatBuffer.shift();
|
||||
this.client.sendArray([nextMessage]);
|
||||
this.chatBufferCycle();
|
||||
this.chatBufferCycleCounter--;
|
||||
}, time);
|
||||
}
|
||||
}
|
||||
|
||||
new Prefix('hmpp!', 'hmpp!');
|
||||
new Prefix('h!', 'h!');
|
||||
|
||||
new Command(['help', 'cmds', 'h'], 'List all commands', '%PREFIX%help', 0, (msg) => {
|
||||
let cmds = 'Commands: ';
|
||||
for (let cmd of Object.values(Command.commands)) {
|
||||
if (cmd.hidden) continue;
|
||||
cmds += `${cmd.cmd[0]}, `;
|
||||
}
|
||||
cmds = cmds.substring(0, cmds.length - 2).trim();
|
||||
return cmds;
|
||||
}, 0, false);
|
||||
|
||||
new Command(['users'], 'See how many users are online', `%PREFIX%users`, 0, (msg) => {
|
||||
console.log(SERVER.connections.size);
|
||||
return `There are ${SERVER.connections.size} users on HMPP.`;
|
||||
}, 0, false);
|
||||
|
||||
let cl = new Client("wss://mppclone.com:8443", token);
|
||||
|
||||
let bot = new Bot(cl);
|
|
@ -1,5 +0,0 @@
|
|||
{
|
||||
"ignore": [
|
||||
"**/*.json"
|
||||
]
|
||||
}
|
1823
oldfloat/yarn.lock
1823
oldfloat/yarn.lock
File diff suppressed because it is too large
Load Diff
|
@ -1,848 +0,0 @@
|
|||
const createKeccakHash = require("keccak");
|
||||
const Crown = require("./Crown.js");
|
||||
const Database = require("./Database.js");
|
||||
const Logger = require("./Logger.js");
|
||||
const Quota = require("./Quota.js");
|
||||
const RoomSettings = require("./RoomSettings.js");
|
||||
const ftc = require("fancy-text-converter");
|
||||
const Notification = require("./Notification");
|
||||
const Color = require("./Color");
|
||||
const { getTimeColor } = require("./ColorEncoder.js");
|
||||
const { InternalBot } = require("./InternalBot");
|
||||
|
||||
function ansiRegex({ onlyFirst = false } = {}) {
|
||||
const pattern = [
|
||||
"[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)",
|
||||
"(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-nq-uy=><~]))"
|
||||
].join("|");
|
||||
|
||||
return new RegExp(pattern, onlyFirst ? undefined : "g");
|
||||
}
|
||||
|
||||
const LOGGER_PARTICIPANT = {
|
||||
name: "Logger",
|
||||
color: "#72f1b8",
|
||||
_id: "logger",
|
||||
id: "logger"
|
||||
};
|
||||
|
||||
const SERVER_PARTICIPANT = {
|
||||
name: "mpp",
|
||||
color: "#ffffff",
|
||||
_id: "0",
|
||||
id: "0"
|
||||
};
|
||||
|
||||
const LOGGING_CHANNEL = "lolwutsecretloggingchannel";
|
||||
const BAN_CHANNEL = "test/awkward";
|
||||
|
||||
class Channel extends EventEmitter {
|
||||
static loggingChannel = LOGGING_CHANNEL;
|
||||
static loggerParticipant = LOGGER_PARTICIPANT;
|
||||
static serverParticipant = SERVER_PARTICIPANT;
|
||||
static banChannel = BAN_CHANNEL;
|
||||
|
||||
constructor(server, _id, settings, cl) {
|
||||
super();
|
||||
this.logger = new Logger(`Room - ${_id}`);
|
||||
this._id = _id;
|
||||
this.server = server;
|
||||
this.crown;
|
||||
this.crowndropped = false;
|
||||
|
||||
if (this.isLobby(this._id)) {
|
||||
this.settings = new RoomSettings(this.server.lobbySettings);
|
||||
// this.settings.lobby = true;
|
||||
// this.settings.color = this.server.lobbySettings.color;
|
||||
// this.settings.color2 = this.server.lobbySettings.color2;
|
||||
} else {
|
||||
this.settings = new RoomSettings(settings, "user");
|
||||
}
|
||||
|
||||
this.chatmsgs = [];
|
||||
this.ppl = new Map();
|
||||
this.connections = [];
|
||||
this.bindEventListeners();
|
||||
this.server.channels.set(_id, this);
|
||||
this.bans = new Map();
|
||||
this.flags = {};
|
||||
this.destroyed = false;
|
||||
|
||||
this.logger.log("Created");
|
||||
|
||||
if (this._id == LOGGING_CHANNEL) {
|
||||
if (cl.user.hasFlag("admin")) {
|
||||
delete this.crown;
|
||||
|
||||
Logger.buffer.forEach(str => {
|
||||
this.chatmsgs.push({
|
||||
m: "a",
|
||||
p: LOGGER_PARTICIPANT,
|
||||
a: str.replace(ansiRegex(), "")
|
||||
});
|
||||
});
|
||||
|
||||
Logger.on("buffer update", str => {
|
||||
this.chatmsgs.push({
|
||||
m: "a",
|
||||
p: LOGGER_PARTICIPANT,
|
||||
a: str.replace(ansiRegex(), "")
|
||||
});
|
||||
|
||||
this.sendChatArray();
|
||||
});
|
||||
|
||||
this.emit("update");
|
||||
|
||||
let c = new Color(LOGGER_PARTICIPANT.color);
|
||||
c.add(-0x40, -0x40, -0x40);
|
||||
|
||||
let c2 = new Color(c.toHexa());
|
||||
c2.add(-0x40, -0x40, -0x40);
|
||||
|
||||
this.settings = RoomSettings.changeSettings(
|
||||
{
|
||||
color: c.toHexa(),
|
||||
color2: c2.toHexa(),
|
||||
chat: true,
|
||||
crownsolo: true,
|
||||
lobby: false,
|
||||
owner_id: LOGGER_PARTICIPANT._id
|
||||
},
|
||||
true
|
||||
);
|
||||
} else {
|
||||
cl.setChannel("test/awkward");
|
||||
}
|
||||
} else {
|
||||
Database.getRoomSettings(this._id, (err, set) => {
|
||||
if (err) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.settings = RoomSettings.changeSettings(
|
||||
this.settings,
|
||||
true
|
||||
);
|
||||
this.chatmsgs = set.chat;
|
||||
this.sendChatArray();
|
||||
this.setData();
|
||||
});
|
||||
}
|
||||
|
||||
if (this.isLobby(this._id)) {
|
||||
this.colorInterval = setInterval(() => {
|
||||
this.setDefaultLobbyColorBasedOnDate();
|
||||
}, 5000);
|
||||
this.setDefaultLobbyColorBasedOnDate();
|
||||
}
|
||||
}
|
||||
|
||||
setChatArray(arr) {
|
||||
this.chatmsgs = arr || [];
|
||||
this.sendArray([
|
||||
{
|
||||
m: "c",
|
||||
c: this.chatmsgs.slice(-1 * 32)
|
||||
}
|
||||
]);
|
||||
this.setData();
|
||||
}
|
||||
|
||||
sendChatArray() {
|
||||
this.connections.forEach(cl => {
|
||||
cl.sendArray([
|
||||
{
|
||||
m: "c",
|
||||
c: this.chatmsgs.slice(-1 * 32)
|
||||
}
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
||||
setDefaultLobbyColorBasedOnDate() {
|
||||
let col = getTimeColor();
|
||||
let col2 = new Color(col.r - 0x40, col.g - 0x40, col.b - 0x40);
|
||||
|
||||
if (!this.settings) {
|
||||
this.settings = new RoomSettings(this.server.lobbySettings);
|
||||
}
|
||||
|
||||
this.settings.changeSettings({
|
||||
color: col.toHexa(),
|
||||
color2: col.toHexa()
|
||||
});
|
||||
|
||||
for (let key in this.settings) {
|
||||
this.server.lobbySettings[key] = this.settings[key];
|
||||
}
|
||||
|
||||
this.emit("update");
|
||||
}
|
||||
|
||||
join(cl, set) {
|
||||
//this stuff is complicated
|
||||
let otheruser = this.connections.find(a => a.user._id == cl.user._id);
|
||||
if (!otheruser) {
|
||||
// we don't exist yet
|
||||
// create id hash
|
||||
let participantId = createKeccakHash("keccak256")
|
||||
.update(Math.random().toString() + cl.ip)
|
||||
.digest("hex")
|
||||
.substr(0, 24);
|
||||
|
||||
// set id
|
||||
cl.user.id = participantId;
|
||||
cl.participantId = participantId;
|
||||
|
||||
// init quotas (TODO pass type of room in?)
|
||||
cl.initParticipantQuotas();
|
||||
|
||||
// no users / already had crown? give crown
|
||||
if (
|
||||
(this.connections.length == 0 &&
|
||||
Array.from(this.ppl.values()).length == 0 &&
|
||||
this.isLobby(this._id) == false) ||
|
||||
(this.crown &&
|
||||
(this.crown.userId == cl.user._id ||
|
||||
this.settings["owner_id"] == cl.user._id))
|
||||
) {
|
||||
// user owns the room
|
||||
// we need to switch the crown to them
|
||||
//cl.quotas.a.setParams(Quota.PARAMS_A_CROWNED);
|
||||
this.emit("add crown", {
|
||||
participantId: cl.participantId,
|
||||
userId: cl.user._id
|
||||
});
|
||||
|
||||
this.crowndropped = false;
|
||||
// this.settings = new RoomSettings(set, 'user');
|
||||
} else {
|
||||
//cl.quotas.a.setParams(Quota.PARAMS_A_NORMAL);
|
||||
|
||||
if (this.isLobby(this._id) && this.settings.lobby !== true) {
|
||||
// fix lobby setting
|
||||
this.settings.changeSettings({ lobby: true });
|
||||
// this.settings.visible = true;
|
||||
// this.settings.crownsolo = false;
|
||||
// this.settings.lobby = true;
|
||||
// this.settings.color = this.server.lobbySettings.color;
|
||||
// this.settings.color2 = this.server.lobbySettings.color2;
|
||||
} else {
|
||||
if (!this.isLobby) {
|
||||
if (typeof set == "undefined") {
|
||||
if (typeof this.settings == "undefined") {
|
||||
this.settings = new RoomSettings(
|
||||
this.server.defaultRoomSettings,
|
||||
"user"
|
||||
);
|
||||
} else {
|
||||
this.settings = new RoomSettings(
|
||||
cl.channel.settings,
|
||||
"user"
|
||||
);
|
||||
}
|
||||
} else {
|
||||
this.settings = new RoomSettings(set, "user");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.ppl.set(participantId, cl);
|
||||
|
||||
this.connections.push(cl);
|
||||
|
||||
cl.sendArray([
|
||||
{
|
||||
m: "c",
|
||||
c: this.chatmsgs.slice(-1 * 32)
|
||||
}
|
||||
]);
|
||||
|
||||
// this.updateCh(cl, this.settings);
|
||||
|
||||
if (!cl.user.hasFlag("hidden", true)) {
|
||||
this.sendArray(
|
||||
[
|
||||
{
|
||||
m: "p",
|
||||
_id: cl.user._id,
|
||||
name: cl.user.name,
|
||||
color: cl.user.color,
|
||||
id: cl.participantId,
|
||||
x: this.ppl.get(cl.participantId).x || 200,
|
||||
y: this.ppl.get(cl.participantId).y || 100
|
||||
}
|
||||
],
|
||||
cl,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
this.updateCh(cl, this.settings);
|
||||
} else {
|
||||
cl.user.id = otheruser.participantId;
|
||||
cl.participantId = otheruser.participantId;
|
||||
cl.quotas = otheruser.quotas;
|
||||
this.connections.push(cl);
|
||||
cl.sendArray([
|
||||
{
|
||||
m: "c",
|
||||
c: this.chatmsgs.slice(-1 * 32)
|
||||
}
|
||||
]);
|
||||
this.updateCh(cl, this.settings);
|
||||
}
|
||||
}
|
||||
|
||||
remove(p) {
|
||||
// remove user
|
||||
if (!p) return;
|
||||
if (!p.user) return;
|
||||
let otheruser = this.connections.filter(a => a.user._id == p.user._id);
|
||||
if (!(otheruser.length > 1)) {
|
||||
this.ppl.delete(p.participantId);
|
||||
this.connections.splice(
|
||||
this.connections.findIndex(
|
||||
a => a.connectionid == p.connectionid
|
||||
),
|
||||
1
|
||||
);
|
||||
this.sendArray(
|
||||
[
|
||||
{
|
||||
m: "bye",
|
||||
p: p.participantId
|
||||
}
|
||||
],
|
||||
p,
|
||||
false
|
||||
);
|
||||
if (this.crown)
|
||||
if (this.crown.userId == p.user._id && !this.crowndropped) {
|
||||
this.chown();
|
||||
}
|
||||
this.updateCh();
|
||||
} else {
|
||||
this.connections.splice(
|
||||
this.connections.findIndex(
|
||||
a => a.connectionid == p.connectionid
|
||||
),
|
||||
1
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
updateCh(cl, set) {
|
||||
//update channel for all people in channel
|
||||
if (Array.from(this.ppl.values()).length <= 0) {
|
||||
setTimeout(() => {
|
||||
this.destroy();
|
||||
}, 3000);
|
||||
return;
|
||||
}
|
||||
|
||||
this.connections.forEach(usr => {
|
||||
let u = this.fetchChannelData(usr, cl);
|
||||
this.server.connections.get(usr.connectionid).sendArray([u]);
|
||||
});
|
||||
|
||||
this.server.updateChannelList([this.fetchChannelData()]);
|
||||
}
|
||||
|
||||
updateParticipant(pid, options) {
|
||||
let p;
|
||||
|
||||
Array.from(this.ppl).map(rpg => {
|
||||
if (rpg[1].user._id == pid) p = rpg[1];
|
||||
});
|
||||
|
||||
if (typeof p == "undefined") return;
|
||||
|
||||
options.name ? (p.user.name = options.name) : {};
|
||||
options._id ? (p.user._id = options._id) : {};
|
||||
options.color ? (p.user.color = options.color) : {};
|
||||
|
||||
this.connections
|
||||
.filter(ofo => ofo.participantId == p.participantId)
|
||||
.forEach(usr => {
|
||||
options.name ? (usr.user.name = options.name) : {};
|
||||
options._id ? (usr.user._id = options._id) : {};
|
||||
options.color ? (usr.user.color = options.color) : {};
|
||||
});
|
||||
|
||||
if (!p.hidden) {
|
||||
this.sendArray([
|
||||
{
|
||||
color: p.user.color,
|
||||
id: p.participantId,
|
||||
m: "p",
|
||||
name: p.user.name,
|
||||
x: p.x || 200,
|
||||
y: p.y || 100,
|
||||
_id: p.user._id
|
||||
}
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
destroy() {
|
||||
//destroy room
|
||||
if (this.destroyed) return;
|
||||
if (this.ppl.size > 0) return;
|
||||
if (this._id == "lobby") return;
|
||||
this.destroyed = true;
|
||||
this._id;
|
||||
this.logger.log(`Deleted room ${this._id}`);
|
||||
this.settings = undefined;
|
||||
this.ppl;
|
||||
this.connnections;
|
||||
this.chatmsgs;
|
||||
this.server.channels.delete(this._id);
|
||||
}
|
||||
|
||||
sendArray(arr, not, onlythisparticipant) {
|
||||
this.connections.forEach(usr => {
|
||||
if (
|
||||
!not ||
|
||||
(usr.participantId != not.participantId &&
|
||||
!onlythisparticipant) ||
|
||||
(usr.connectionid != not.connectionid && onlythisparticipant)
|
||||
) {
|
||||
try {
|
||||
let cl = this.server.connections.get(usr.connectionid);
|
||||
if (!cl) return;
|
||||
this.server.connections
|
||||
.get(usr.connectionid)
|
||||
.sendArray(arr);
|
||||
} catch (e) {
|
||||
this.logger.error(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fetchChannelData(usr, cl) {
|
||||
let chppl = [];
|
||||
|
||||
[...this.ppl.values()].forEach(c => {
|
||||
if (cl) {
|
||||
if (c.hidden == true && c.user._id !== cl.user._id) {
|
||||
// client is hidden and we are that client
|
||||
return;
|
||||
} else if (c.user._id == cl.user._id) {
|
||||
// let u = {
|
||||
// _id: c.user._id,
|
||||
// name: c.user.name + ' [HIDDEN]',
|
||||
// color: c.user.color,
|
||||
// id: c.participantId
|
||||
// }
|
||||
// chppl.push(u);
|
||||
}
|
||||
}
|
||||
let u = {
|
||||
_id: c.user._id,
|
||||
name: c.user.name,
|
||||
color: c.user.color,
|
||||
id: c.participantId
|
||||
};
|
||||
chppl.push(u);
|
||||
});
|
||||
|
||||
let data = {
|
||||
m: "ch",
|
||||
p: "ofo",
|
||||
ch: {
|
||||
count: chppl.length,
|
||||
crown: this.crown,
|
||||
settings: this.settings,
|
||||
_id: this._id
|
||||
},
|
||||
ppl: chppl
|
||||
};
|
||||
|
||||
if (cl) {
|
||||
if (usr.connectionid == cl.connectionid) {
|
||||
data.p = cl.participantId;
|
||||
} else {
|
||||
delete data.p;
|
||||
}
|
||||
} else {
|
||||
delete data.p;
|
||||
}
|
||||
|
||||
if (data.ch.crown == null) {
|
||||
delete data.ch.crown;
|
||||
} else {
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
verifyColor(strColor) {
|
||||
var test2 = /^#[0-9A-F]{6}$/i.test(strColor);
|
||||
if (test2 == true) {
|
||||
return strColor;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
isLobby(_id) {
|
||||
if (_id.startsWith("lobby")) {
|
||||
if (_id == "lobby") {
|
||||
return true;
|
||||
}
|
||||
|
||||
let lobbynum = _id.split("lobby")[1];
|
||||
if (!(parseInt(lobbynum).toString() == lobbynum)) return false;
|
||||
|
||||
for (let i in lobbynum) {
|
||||
if (parseInt(lobbynum[i]) >= 0) {
|
||||
if (parseInt(i) + 1 == lobbynum.length) return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else if (
|
||||
_id.startsWith("test/") ||
|
||||
_id.toLowerCase().includes("grant")
|
||||
) {
|
||||
if (_id == "test/") {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
chown(id) {
|
||||
let prsn = this.ppl.get(id);
|
||||
if (prsn) {
|
||||
this.crown = new Crown(id, prsn.user._id);
|
||||
this.crowndropped = false;
|
||||
} else {
|
||||
if (this.crown) {
|
||||
this.crown = new Crown(id, this.crown.userId);
|
||||
this.crowndropped = true;
|
||||
}
|
||||
}
|
||||
|
||||
this.updateCh();
|
||||
}
|
||||
|
||||
setCoords(p, x, y) {
|
||||
if (p.participantId && this.ppl.get(p.participantId)) {
|
||||
x ? (this.ppl.get(p.participantId).x = x) : {};
|
||||
y ? (this.ppl.get(p.participantId).y = y) : {};
|
||||
this.sendArray(
|
||||
[
|
||||
{
|
||||
m: "m",
|
||||
id: p.participantId,
|
||||
x: this.ppl.get(p.participantId).x,
|
||||
y: this.ppl.get(p.participantId).y
|
||||
}
|
||||
],
|
||||
p,
|
||||
false
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
chat(p, msg) {
|
||||
if (msg.message.length > 512) return;
|
||||
|
||||
if (p.participantId == 0) {
|
||||
let message = {};
|
||||
|
||||
message.m = "a";
|
||||
message.t = Date.now();
|
||||
message.a = msg.message;
|
||||
|
||||
if (message.a.length > 0 && message.a.length <= 512) {
|
||||
message.p = {
|
||||
color: "#ffffff",
|
||||
id: "0",
|
||||
name: "mpp",
|
||||
_id: "0"
|
||||
};
|
||||
|
||||
this.sendArray([message]);
|
||||
|
||||
this.chatmsgs.push(message);
|
||||
this.setData();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let filter = ["AMIGHTYWIND", "CHECKLYHQ"];
|
||||
let regexp = new RegExp("\\b(" + filter.join("|") + ")\\b", "i");
|
||||
if (regexp.test(msg.message.split(" ").join(""))) return;
|
||||
|
||||
let prsn = this.ppl.get(p.participantId);
|
||||
if (!prsn) return;
|
||||
let message = {};
|
||||
message.m = "a";
|
||||
message.a = msg.message;
|
||||
|
||||
if (prsn.user.hasFlag("chat_curse_1")) {
|
||||
if (prsn.user.flags["chat_curse_1"] != false)
|
||||
message.a = message.a
|
||||
.split(/[aeiou]/)
|
||||
.join("o")
|
||||
.split(/[AEIOU]/)
|
||||
.join("O");
|
||||
}
|
||||
|
||||
if (prsn.user.hasFlag("chat_curse_2")) {
|
||||
}
|
||||
|
||||
message.p = {
|
||||
color: p.user.color,
|
||||
id: p.participantId,
|
||||
name: p.user.name,
|
||||
_id: p.user._id
|
||||
};
|
||||
|
||||
message.t = Date.now();
|
||||
|
||||
this.sendArray([message]);
|
||||
this.chatmsgs.push(message);
|
||||
this.setData();
|
||||
|
||||
InternalBot.emit("receive message", message, prsn, this);
|
||||
}
|
||||
|
||||
adminChat(str) {
|
||||
this.chat(
|
||||
{
|
||||
participantId: 0
|
||||
},
|
||||
{
|
||||
message: str
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
hasUser(id) {
|
||||
// return this.ppl.has(id);
|
||||
for (const p of this.ppl.values()) {
|
||||
if (p.id == id) return true;
|
||||
}
|
||||
}
|
||||
|
||||
playNote(cl, note) {
|
||||
if (cl.user.hasFlag("mute", true)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (cl.user.hasFlag("mute")) {
|
||||
if (Array.isArray(cl.user.flags["mute"])) {
|
||||
if (cl.user.flags["mute"].includes(this._id)) return;
|
||||
}
|
||||
}
|
||||
|
||||
let vol;
|
||||
|
||||
if (cl.user.hasFlag("volume")) {
|
||||
vol = Math.round(cl.user.flags["volume"]) / 100;
|
||||
}
|
||||
|
||||
if (typeof vol == "number") {
|
||||
for (let no of note.n) {
|
||||
if (no.v) {
|
||||
if (vol == 0) {
|
||||
no.v = vol;
|
||||
} else {
|
||||
no.v *= vol;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.sendArray(
|
||||
[
|
||||
{
|
||||
m: "n",
|
||||
n: note.n,
|
||||
p: cl.participantId,
|
||||
t: note.t
|
||||
}
|
||||
],
|
||||
cl,
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
kickban(_id, ms) {
|
||||
ms = parseInt(ms);
|
||||
|
||||
if (ms >= 1000 * 60 * 60) return;
|
||||
if (ms < 0) return;
|
||||
|
||||
ms = Math.round(ms / 1000) * 1000;
|
||||
|
||||
let user = this.connections.find(usr => usr.user._id == _id);
|
||||
if (!user) return;
|
||||
let asd = true;
|
||||
let pthatbanned = this.ppl.get(this.crown.participantId);
|
||||
|
||||
this.connections
|
||||
.filter(usr => usr.participantId == user.participantId)
|
||||
.forEach(u => {
|
||||
user.bantime = Math.floor(Math.floor(ms / 1000) / 60);
|
||||
user.bannedtime = Date.now();
|
||||
user.msbanned = ms;
|
||||
|
||||
this.bans.set(user.user._id, user);
|
||||
|
||||
//if (this.crown && (this.crown.userId)) {
|
||||
u.setChannel(Channel.banChannel, {});
|
||||
|
||||
if (asd)
|
||||
new Notification(this.server, {
|
||||
id: "",
|
||||
title: "Notice",
|
||||
text: `Banned from "${this._id}" for ${Math.floor(
|
||||
Math.floor(ms / 1000) / 60
|
||||
)} minutes.`,
|
||||
duration: 7000,
|
||||
target: "#room",
|
||||
class: "short",
|
||||
targetUser: user.participantId,
|
||||
targetChannel: "all",
|
||||
cl: user
|
||||
}).send();
|
||||
new Notification(this.server, {
|
||||
id: "",
|
||||
title: "Notice",
|
||||
text: `Banned from "${this._id}" for ${Math.floor(
|
||||
Math.floor(ms / 1000) / 60
|
||||
)} minutes.`,
|
||||
duration: 7000,
|
||||
target: "#room",
|
||||
class: "short",
|
||||
targetUser: user.participantId,
|
||||
targetChannel: "all",
|
||||
cl: user
|
||||
}).send();
|
||||
if (asd)
|
||||
new Notification(this.server, {
|
||||
id: "",
|
||||
class: "short",
|
||||
target: "#room",
|
||||
title: "Notice",
|
||||
text: `${pthatbanned.user.name} banned ${
|
||||
user.user.name
|
||||
} from the channel for ${Math.floor(
|
||||
Math.floor(ms / 1000) / 60
|
||||
)} minutes.`,
|
||||
duration: 7000,
|
||||
targetChannel: "room",
|
||||
cl: pthatbanned
|
||||
}).send();
|
||||
if (this.crown && this.crown.userId == _id) {
|
||||
new Notification(this.server, {
|
||||
id: "",
|
||||
class: "short",
|
||||
target: "#room",
|
||||
title: "Certificate of Award",
|
||||
text: `Let it be known that ${user.user.name} kickbanned him/her self.`,
|
||||
targetChannel: "room",
|
||||
duration: 7000,
|
||||
cl: pthatbanned
|
||||
}).send();
|
||||
}
|
||||
//}
|
||||
});
|
||||
}
|
||||
|
||||
unban(_id) {
|
||||
let ban = this.bans.get(_id);
|
||||
if (!ban) return;
|
||||
if (ban.bantime) {
|
||||
delete ban.bantime;
|
||||
}
|
||||
|
||||
if (ban.bannedtime) {
|
||||
delete ban.bannedtime;
|
||||
}
|
||||
|
||||
this.bans.delete(ban.user._id);
|
||||
}
|
||||
|
||||
bindEventListeners() {
|
||||
this.on("bye", participant => {
|
||||
this.remove(participant);
|
||||
});
|
||||
|
||||
this.on("m", msg => {
|
||||
let p = this.ppl.get(msg.p);
|
||||
if (!p) return;
|
||||
this.setCoords(p, msg.x, msg.y);
|
||||
});
|
||||
|
||||
this.on("a", (participant, msg) => {
|
||||
this.chat(participant, msg);
|
||||
});
|
||||
|
||||
this.on("update", (cl, set) => {
|
||||
this.updateCh(cl, set);
|
||||
});
|
||||
|
||||
this.on("remove crown", () => {
|
||||
this.crown = undefined;
|
||||
delete this.crown;
|
||||
this.emit("update");
|
||||
});
|
||||
|
||||
this.on("add crown", msg => {
|
||||
this.crown = new Crown(msg.participantId, msg.userId);
|
||||
this.emit("update");
|
||||
});
|
||||
|
||||
this.on("kickban", msg => {
|
||||
if (!msg._id) return;
|
||||
if (!msg.ms) msg.ms = 30 * 60 * 1000;
|
||||
this.kickban(msg._id, msg.ms);
|
||||
});
|
||||
}
|
||||
|
||||
verifySet(_id, msg) {
|
||||
if (typeof msg.set !== "object") {
|
||||
msg.set = {
|
||||
visible: true,
|
||||
color: this.server.defaultSettings.color,
|
||||
chat: true,
|
||||
crownsolo: false
|
||||
};
|
||||
}
|
||||
|
||||
msg.set = RoomSettings.changeSettings(msg.set);
|
||||
|
||||
if (typeof msg.set.lobby !== "undefined") {
|
||||
if (msg.set.lobby == true) {
|
||||
if (!this.isLobby(_id)) delete msg.set.lobby;
|
||||
} else {
|
||||
if (this.isLobby(_id)) {
|
||||
msg.set = this.server.lobbySettings;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setData() {
|
||||
Database.setRoomSettings(this._id, this.settings, this.chatmsgs);
|
||||
}
|
||||
|
||||
hasFlag(flag, val) {
|
||||
if (!val) return this.flags.hasOwnProperty(flag);
|
||||
return this.flags.hasOwnProperty(flag) && this.flags[flag] == val;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Channel;
|
353
oldsrc/Client.js
353
oldsrc/Client.js
|
@ -1,353 +0,0 @@
|
|||
const Channel = require("./Channel.js");
|
||||
const Quota = require("./Quota.js");
|
||||
const quotas = require("../Quotas");
|
||||
const { RateLimit, RateLimitChain } = require("./Ratelimit.js");
|
||||
const User = require("./User.js");
|
||||
const Database = require("./Database.js");
|
||||
const { EventEmitter } = require("events");
|
||||
|
||||
class Client extends EventEmitter {
|
||||
/**
|
||||
* Server-side client representation
|
||||
* @param {*} ws WebSocket object
|
||||
* @param {*} req WebSocket request
|
||||
* @param {*} server Server
|
||||
*/
|
||||
constructor(ws, req, server) {
|
||||
super();
|
||||
EventEmitter.call(this);
|
||||
this.connectionid = server.connectionid;
|
||||
this.server = server;
|
||||
this.participantId;
|
||||
this.channel;
|
||||
this.isSubscribedToAdminStream = false;
|
||||
this.adminStreamInterval;
|
||||
|
||||
this.staticQuotas = {
|
||||
room: new RateLimit(quotas.room.time)
|
||||
};
|
||||
|
||||
this.quotas = {};
|
||||
this.ws = ws;
|
||||
this.req = req;
|
||||
this.ip = req.connection.remoteAddress.replace("::ffff:", "");
|
||||
this.hidden = false;
|
||||
|
||||
Database.getUserData(this, server).then(data => {
|
||||
this.user = new User(this, data);
|
||||
this.destroied = false;
|
||||
this.bindEventListeners();
|
||||
require("./Message.js")(this);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if user is connected
|
||||
* @returns boolean
|
||||
*/
|
||||
isConnected() {
|
||||
return this.ws && this.ws.readyState === WebSocket.OPEN;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if user is connecting
|
||||
* @returns boolean
|
||||
*/
|
||||
isConnecting() {
|
||||
return this.ws && this.ws.readyState === WebSocket.CONNECTING;
|
||||
}
|
||||
|
||||
/**
|
||||
* Move user to channel
|
||||
* @param {string} _id User ID
|
||||
* @param {*} settings Settings object
|
||||
* @returns undefined
|
||||
*/
|
||||
setChannel(_id, settings) {
|
||||
if (this.channel && this.channel._id == _id) return;
|
||||
if (this.server.channels.get(_id)) {
|
||||
let ch = this.server.channels.get(_id, settings);
|
||||
let userbanned = ch.bans.get(this.user._id);
|
||||
|
||||
if (
|
||||
userbanned &&
|
||||
Date.now() - userbanned.bannedtime >= userbanned.msbanned
|
||||
) {
|
||||
ch.bans.delete(userbanned.user._id);
|
||||
userbanned = undefined;
|
||||
}
|
||||
|
||||
if (userbanned) {
|
||||
new Notification(this.server, {
|
||||
targetUser: this.participantId,
|
||||
targetChannel: all,
|
||||
title: "Notice",
|
||||
text: `Currently banned from "${_id}" for ${Math.ceil(
|
||||
Math.floor(
|
||||
(userbanned.msbanned -
|
||||
(Date.now() - userbanned.bannedtime)) /
|
||||
1000
|
||||
) / 60
|
||||
)} minutes.`,
|
||||
duration: 7000,
|
||||
id: "",
|
||||
target: "#room",
|
||||
class: "short",
|
||||
cl: this
|
||||
}).send();
|
||||
this.setChannel(Channel.banChannel, settings);
|
||||
return;
|
||||
}
|
||||
|
||||
let channel = this.channel;
|
||||
if (channel) this.channel.emit("bye", this);
|
||||
if (channel) this.channel.updateCh(this);
|
||||
|
||||
this.channel = this.server.channels.get(_id);
|
||||
this.channel.join(this);
|
||||
} else {
|
||||
let room = new Channel(this.server, _id, settings, this);
|
||||
this.server.channels.set(_id, room);
|
||||
if (this.channel) this.channel.emit("bye", this);
|
||||
this.channel = this.server.channels.get(_id);
|
||||
this.channel.join(this, settings);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send data to client
|
||||
* @param {any[]} arr Array of messages
|
||||
*/
|
||||
sendArray(arr) {
|
||||
if (this.isConnected()) {
|
||||
//console.log(`SEND: `, JSON.colorStringify(arr));
|
||||
this.ws.send(JSON.stringify(arr));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set username in database
|
||||
* @param {string} name Username
|
||||
* @param {boolean} admin Is admin?
|
||||
* @returns undefined
|
||||
*/
|
||||
userset(name, admin) {
|
||||
if (name.length > 40 && !admin) return;
|
||||
|
||||
if (this.quotas.userset) {
|
||||
if (!this.quotas.userset.attempt()) return;
|
||||
}
|
||||
|
||||
if (!this.user.hasFlag("freeze_name", true) || admin) {
|
||||
this.user.name = name;
|
||||
|
||||
if (!this.user.hasFlag("freeze_name", true)) {
|
||||
Database.getUserData(this, this.server).then(usr => {
|
||||
Database.updateUser(this.user._id, this.user);
|
||||
|
||||
this.server.channels.forEach(channel => {
|
||||
channel.updateParticipant(this.user._id, {
|
||||
name: name
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set rate limits
|
||||
*/
|
||||
initParticipantQuotas() {
|
||||
this.quotas = {
|
||||
//"chat": new Quota(Quota.PARAMS_A_NORMAL),
|
||||
chat: {
|
||||
lobby: new RateLimitChain(
|
||||
quotas.chat.lobby.amount,
|
||||
quotas.chat.lobby.time
|
||||
),
|
||||
normal: new RateLimitChain(
|
||||
quotas.chat.normal.amount,
|
||||
quotas.chat.normal.time
|
||||
),
|
||||
insane: new RateLimitChain(
|
||||
quotas.chat.insane.amount,
|
||||
quotas.chat.insane.time
|
||||
)
|
||||
},
|
||||
cursor: new RateLimitChain(
|
||||
quotas.cursor.amount,
|
||||
quotas.cursor.time
|
||||
),
|
||||
chown: new RateLimitChain(quotas.chown.amount, quotas.chown.time),
|
||||
userset: new RateLimitChain(
|
||||
quotas.userset.amount,
|
||||
quotas.userset.time
|
||||
),
|
||||
kickban: new RateLimitChain(
|
||||
quotas.kickban.amount,
|
||||
quotas.kickban.time
|
||||
),
|
||||
// note: new Quota(Quota.PARAMS_LOBBY),
|
||||
note: new RateLimitChain(5, 5000),
|
||||
chset: new Quota(Quota.PARAMS_USED_A_LOT),
|
||||
"+ls": new Quota(Quota.PARAMS_USED_A_LOT),
|
||||
"-ls": new Quota(Quota.PARAMS_USED_A_LOT)
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop the client
|
||||
*/
|
||||
destroy() {
|
||||
if (this.user) {
|
||||
let lastClient = true;
|
||||
|
||||
for (const cl of this.server.connections.values()) {
|
||||
if (cl.user) {
|
||||
if (cl.user._id == this.user._id) {
|
||||
lastClient = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (lastClient) this.user.stopFlagEvents();
|
||||
}
|
||||
|
||||
this.ws.close();
|
||||
|
||||
if (this.channel) {
|
||||
this.channel.emit("bye", this);
|
||||
}
|
||||
this.user;
|
||||
this.participantId;
|
||||
this.channel;
|
||||
this.server.roomlisteners.delete(this.connectionid);
|
||||
this.connectionid;
|
||||
this.server.connections.delete(this.connectionid);
|
||||
this.destroied = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal
|
||||
*/
|
||||
bindEventListeners() {
|
||||
this.ws.on("message", (evt, admin) => {
|
||||
try {
|
||||
if (typeof evt !== "string") evt = evt.toJSON();
|
||||
let transmission = JSON.parse(evt);
|
||||
for (let msg of transmission) {
|
||||
if (typeof msg !== "object" || msg == null || msg == NaN)
|
||||
return;
|
||||
if (!msg.hasOwnProperty("m")) return;
|
||||
if (!this.server.legit_m.includes(msg.m)) return;
|
||||
this.emit(msg.m, msg, !!admin);
|
||||
//console.log(`RECIEVE: `, JSON.colorStringify(msg));
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
// this.destroy();
|
||||
}
|
||||
});
|
||||
|
||||
this.ws.on("close", () => {
|
||||
if (!this.destroied) {
|
||||
this.destroy();
|
||||
}
|
||||
});
|
||||
|
||||
this.ws.addEventListener("error", err => {
|
||||
console.error(err);
|
||||
if (!this.destroied) {
|
||||
this.destroy();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Send admin data bus message
|
||||
*/
|
||||
sendAdminData() {
|
||||
let data = {};
|
||||
data.m = "data";
|
||||
|
||||
let channels = [];
|
||||
this.server.channels.forEach(ch => {
|
||||
let ppl = [];
|
||||
const chdata = ch.fetchChannelData();
|
||||
|
||||
for (let p of chdata.ppl) {
|
||||
ppl.push({
|
||||
user: p
|
||||
});
|
||||
}
|
||||
|
||||
channels.push({
|
||||
chat: ch.chatmsgs.slice(-1 * 32),
|
||||
participants: ppl
|
||||
});
|
||||
});
|
||||
|
||||
let users = [];
|
||||
let clients = [];
|
||||
this.server.connections.forEach(cl => {
|
||||
if (!cl.user) return;
|
||||
let c = {
|
||||
ip: cl.ip,
|
||||
participantId: cl.participantId,
|
||||
userId: cl.user._id
|
||||
};
|
||||
clients.push(c);
|
||||
let u = {
|
||||
p: {
|
||||
_id: cl.user._id,
|
||||
name: cl.user.name,
|
||||
color: cl.user.color,
|
||||
flags: cl.user.flags
|
||||
// inventory: cl.user.inventory
|
||||
},
|
||||
id: cl.participantId
|
||||
};
|
||||
|
||||
users.push(u);
|
||||
});
|
||||
|
||||
data.channelManager = {
|
||||
loggingChannel: Channel.loggingChannel,
|
||||
loggerParticipant: Channel.loggerParticipant,
|
||||
channels
|
||||
};
|
||||
|
||||
data.clientManager = {
|
||||
users,
|
||||
clients
|
||||
};
|
||||
|
||||
data.uptime = Date.now() - this.server.startTime;
|
||||
data.config = this.server.config;
|
||||
if (this.user) {
|
||||
data.p = {
|
||||
_id: this.user._id,
|
||||
name: this.user.name,
|
||||
color: this.user.color,
|
||||
flags: this.user.flags
|
||||
// inventory: this.user.inventory
|
||||
};
|
||||
}
|
||||
|
||||
this.sendArray([data]);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {Channel} ch
|
||||
* @param {Client} cl If this is present, only this client's user data will be sent(?)
|
||||
*/
|
||||
sendChannelUpdate(ch, cl) {
|
||||
let msg = ch.fetchChannelData(this, cl);
|
||||
this.sendArray([msg]);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Client;
|
1046
oldsrc/Color.js
1046
oldsrc/Color.js
File diff suppressed because it is too large
Load Diff
|
@ -1,98 +0,0 @@
|
|||
const Color = require("./Color");
|
||||
|
||||
function hashCode(str) {
|
||||
// java String#hashCode
|
||||
var hash = 0;
|
||||
for (var i = 0; i < str.length; i++) {
|
||||
hash = str.charCodeAt(i) + ((hash << 5) - hash);
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
function intToRGB(i) {
|
||||
var c = (i & 0x00ffffff).toString(16).toUpperCase();
|
||||
|
||||
return "00000".substring(0, 6 - c.length) + c;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an HSL color value to RGB. Conversion formula
|
||||
* adapted from http://en.wikipedia.org/wiki/HSL_color_space.
|
||||
* Assumes h, s, and l are contained in the set [0, 1] and
|
||||
* returns r, g, and b in the set [0, 255].
|
||||
*
|
||||
* @param {number} h The hue
|
||||
* @param {number} s The saturation
|
||||
* @param {number} l The lightness
|
||||
* @return {Array} The RGB representation
|
||||
*/
|
||||
function hslToRgb(h, s, l) {
|
||||
var r, g, b;
|
||||
|
||||
if (s == 0) {
|
||||
r = g = b = l; // achromatic
|
||||
} else {
|
||||
var hue2rgb = function hue2rgb(p, q, t) {
|
||||
if (t < 0) t += 1;
|
||||
if (t > 1) t -= 1;
|
||||
if (t < 1 / 6) return p + (q - p) * 6 * t;
|
||||
if (t < 1 / 2) return q;
|
||||
if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
|
||||
return p;
|
||||
};
|
||||
|
||||
var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
|
||||
var p = 2 * l - q;
|
||||
r = hue2rgb(p, q, h + 1 / 3);
|
||||
g = hue2rgb(p, q, h);
|
||||
b = hue2rgb(p, q, h - 1 / 3);
|
||||
}
|
||||
|
||||
return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)];
|
||||
}
|
||||
|
||||
function getTimeColor(currentDate = new Date()) {
|
||||
// get day of year as a number from 1-365
|
||||
let newYearsDay = new Date(currentDate.getFullYear());
|
||||
let differenceInTime =
|
||||
currentDate -
|
||||
newYearsDay +
|
||||
(newYearsDay.getTimezoneOffset() - currentDate.getTimezoneOffset()) *
|
||||
60 *
|
||||
1000;
|
||||
let oneDayInMS = 1000 * 60 * 60 * 24;
|
||||
let dayOfYear = Math.ceil(differenceInTime / oneDayInMS);
|
||||
dayOfYear %= 365;
|
||||
|
||||
// console.log(dayOfYear);
|
||||
|
||||
// get hour
|
||||
let hours = currentDate.getHours();
|
||||
let seconds = currentDate.getSeconds();
|
||||
|
||||
// get a hue based on time of day and day of year
|
||||
let h = dayOfYear / 365;
|
||||
let s = (hours + 1) / (24 / 3);
|
||||
// let s = 1;
|
||||
let l = 0.15 + Math.floor(((hours + 12) / 60) * 1000) / 1000;
|
||||
|
||||
if (l > 1 / 3) l = 1 / 3;
|
||||
if (s > 0.75) s = 0.75;
|
||||
|
||||
// const h = (Date.now() % 360) / 360;
|
||||
// const s = 1;
|
||||
// const l = 0.5;
|
||||
|
||||
// convert to rgb
|
||||
let [r, g, b] = hslToRgb(h, s, l);
|
||||
|
||||
let col = new Color(r, g, b);
|
||||
return col;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
hashCode,
|
||||
intToRGB,
|
||||
getTimeColor,
|
||||
hslToRgb
|
||||
};
|
|
@ -1,29 +0,0 @@
|
|||
const ung = require("unique-names-generator");
|
||||
|
||||
const ung_config = {
|
||||
dictionaries: [ung.names],
|
||||
separator: " ",
|
||||
length: 1
|
||||
};
|
||||
|
||||
class Cow {
|
||||
static generateRandomName() {
|
||||
return ung.uniqueNamesGenerator(ung_config);
|
||||
}
|
||||
|
||||
constructor() {
|
||||
this["display_name"] = Cow.generateRandomName();
|
||||
this["emoji"] = "🐄";
|
||||
this["count"] = 1;
|
||||
}
|
||||
|
||||
toString() {
|
||||
return `${this.emoji}${this.display_name}${
|
||||
this.count > 1 ? `(x${this.count})` : ""
|
||||
}`;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
Cow
|
||||
};
|
|
@ -1,22 +0,0 @@
|
|||
class Crown {
|
||||
constructor (id, _id) {
|
||||
this.participantId = id;
|
||||
this.userId = _id;
|
||||
this.time = Date.now();
|
||||
this.startPos = {
|
||||
x: 50,
|
||||
y: 50
|
||||
}
|
||||
this.endPos = {
|
||||
x: Crown.generateRandomPos(),
|
||||
y: Crown.generateRandomPos()
|
||||
}
|
||||
}
|
||||
|
||||
static generateRandomPos() {
|
||||
return Math.floor(Math.random() * 10000) / 100;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Crown;
|
||||
|
|
@ -1,215 +0,0 @@
|
|||
const fs = require("fs");
|
||||
const { promisify } = require("util");
|
||||
const createKeccakHash = require("keccak");
|
||||
const ColorEncoder = require("./ColorEncoder");
|
||||
const UserModel = require("./UserModel");
|
||||
const mongoose = require("mongoose");
|
||||
const level = require("level");
|
||||
const { db } = require("./UserModel");
|
||||
const Logger = require("./Logger");
|
||||
|
||||
const logger = new Logger("Database");
|
||||
|
||||
mongoose.connect(
|
||||
process.env.MONGO_URL,
|
||||
{
|
||||
useNewUrlParser: true,
|
||||
useUnifiedTopology: true,
|
||||
connectTimeoutMS: 1000
|
||||
},
|
||||
err => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
logger.error("Unable to connect to database service");
|
||||
process.exit(1);
|
||||
}
|
||||
logger.log("Connected to Mongo");
|
||||
}
|
||||
);
|
||||
|
||||
// TODO implement this with an if statement instead
|
||||
fs.mkdirSync("db/", {
|
||||
recursive: true
|
||||
});
|
||||
|
||||
class Database {
|
||||
static userdb;
|
||||
static roomdb;
|
||||
static bandb;
|
||||
static utildb;
|
||||
|
||||
static async load() {
|
||||
logger.log("Initializing level stores...");
|
||||
this.userdb = mongoose.connection;
|
||||
this.roomdb = level("db/rooms.db");
|
||||
this.bandb = level("db/ban.db");
|
||||
this.utildb = level("db/util.db");
|
||||
logger.log("Level stores initialized");
|
||||
|
||||
// const writeFile = promisify(fs.writeFile);
|
||||
// const readdir = promisify(fs.readdir);
|
||||
|
||||
// let files = await readdir("src/db/");
|
||||
// if (!files.includes("users.json")) {
|
||||
// await writeFile('src/db/users.json', JSON.stringify(this.default_db, null, 2))
|
||||
// this.userdb = new Map(Object.entries(require("./db/users.json")));
|
||||
// } else {
|
||||
// this.userdb = new Map(Object.entries(require("./db/users.json")));
|
||||
// }
|
||||
}
|
||||
|
||||
static async getUserData(cl, server) {
|
||||
if (!this.userdb) {
|
||||
await this.load();
|
||||
}
|
||||
|
||||
let _id = createKeccakHash("keccak256")
|
||||
.update(cl.server._id_Private_Key + cl.ip)
|
||||
.digest("hex")
|
||||
.substr(0, 24);
|
||||
|
||||
let user = await UserModel.findById(_id).exec();
|
||||
|
||||
if (user == null) {
|
||||
user = await this.createUser(_id);
|
||||
}
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
static async createUser(_id) {
|
||||
if (!this.userdb) {
|
||||
await this.load();
|
||||
}
|
||||
|
||||
let user = new UserModel({
|
||||
name: "Anonymous",
|
||||
_id: _id,
|
||||
color: "#" + ColorEncoder.intToRGB(ColorEncoder.hashCode(_id)),
|
||||
flags: {}
|
||||
});
|
||||
|
||||
user.save();
|
||||
return user;
|
||||
}
|
||||
|
||||
static async updateUser(_id, data) {
|
||||
if (!this.userdb) {
|
||||
await this.load();
|
||||
}
|
||||
|
||||
let user = await UserModel.findOne({ _id: _id }).exec();
|
||||
|
||||
user.name = data.name;
|
||||
user._id = data._id;
|
||||
user.flags = data.flags;
|
||||
user.color = data.color;
|
||||
|
||||
await user.save();
|
||||
}
|
||||
|
||||
static async wipe() {
|
||||
if (!this.userdb) {
|
||||
await this.load();
|
||||
}
|
||||
|
||||
await UserModel.find({}, (err, docs) => {
|
||||
docs.forEach(doc => {
|
||||
doc.remove();
|
||||
});
|
||||
}).exec();
|
||||
}
|
||||
|
||||
static strMapToObj(strMap) {
|
||||
return [...strMap.entries()].reduce(
|
||||
(obj, [key, value]) => ((obj[key] = value), obj),
|
||||
{}
|
||||
);
|
||||
}
|
||||
|
||||
static getRoomSettings(_id, cb) {
|
||||
let key = "room~" + _id;
|
||||
|
||||
roomSettings;
|
||||
|
||||
this.roomdb.get(key, (err, value) => {
|
||||
if (err || !value || value == "") {
|
||||
cb(err, value);
|
||||
return;
|
||||
}
|
||||
cb(undefined, value);
|
||||
});
|
||||
}
|
||||
|
||||
static setRoomSettings(_id, roomSettings, chat) {
|
||||
let roomData = new RoomDataModel(roomSettings, chat);
|
||||
let key = "room~" + _id;
|
||||
this.roomdb.put(key, JSON.stringify(roomData));
|
||||
}
|
||||
|
||||
static getRoomSettings(_id, cb) {
|
||||
let key = "room~" + _id;
|
||||
this.roomdb.get(key, (err, value) => {
|
||||
if (err) {
|
||||
cb(err);
|
||||
return;
|
||||
}
|
||||
let settings = JSON.parse(value);
|
||||
cb(err, settings);
|
||||
});
|
||||
}
|
||||
|
||||
static deleteRoomSettings(_id) {
|
||||
if (!this.bandb) return this.load();
|
||||
this.roomdb.del("room~" + _id);
|
||||
}
|
||||
|
||||
static addIPBan(ip) {
|
||||
if (!this.bandb) return this.load();
|
||||
this.bandb.put("ipban~" + ip, true);
|
||||
}
|
||||
|
||||
static removeIPBan(ip) {
|
||||
if (!this.bandb) return this.load();
|
||||
this.bandb.del("ipban~" + ip);
|
||||
}
|
||||
|
||||
static isIPBanned(ip, cb) {
|
||||
if (!this.bandb) {
|
||||
// FIXME this was causing a crash :/ maybe it should be async instead of return false?
|
||||
this.load();
|
||||
return false;
|
||||
}
|
||||
|
||||
this.roomdb.get("ipban~" + ip, (err, value) => {
|
||||
if (err) {
|
||||
return false;
|
||||
}
|
||||
|
||||
console.log("ban:", value);
|
||||
|
||||
if (value == true) return true;
|
||||
});
|
||||
}
|
||||
|
||||
static utilSet(key, value) {
|
||||
return this.utildb.put(key, value);
|
||||
}
|
||||
|
||||
static utilGet(key) {
|
||||
return this.utildb.get(key);
|
||||
}
|
||||
|
||||
static utilDel(key) {
|
||||
return this.utildb.del(key);
|
||||
}
|
||||
}
|
||||
|
||||
class RoomDataModel {
|
||||
constructor(settings, chat) {
|
||||
this.settings = settings;
|
||||
this.chat = chat;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Database;
|
|
@ -1,301 +0,0 @@
|
|||
const Logger = require("../Logger");
|
||||
const Color = require("../Color");
|
||||
const { Cow } = require("../Cow");
|
||||
const Database = require("../Database");
|
||||
|
||||
class Command {
|
||||
static commands = [];
|
||||
|
||||
static logger = new Logger("Command Handler");
|
||||
|
||||
static handleCommand(cl, ch, c, usedPrefix, args, argcat, p, isAdmin) {
|
||||
for (let cmd of this.commands) {
|
||||
let aliasCheck = false;
|
||||
|
||||
aliasLoop: for (let alias of cmd.aliases) {
|
||||
if (c.toLowerCase() == alias.toLowerCase()) {
|
||||
aliasCheck = true;
|
||||
break aliasLoop;
|
||||
}
|
||||
}
|
||||
|
||||
if (!aliasCheck) continue;
|
||||
if (!isAdmin && cmd.permLevel == "admin")
|
||||
return ch.adminChat(
|
||||
`You don't have permission to use this command.`
|
||||
);
|
||||
if (args.length - 1 < cmd.minargs)
|
||||
return ch.adminChat(
|
||||
`Not enough arguments. Usage: ${this.getUsage(
|
||||
cmd.usage,
|
||||
usedPrefix
|
||||
)}`
|
||||
);
|
||||
|
||||
try {
|
||||
const out = cmd.func(cl, ch, {
|
||||
c,
|
||||
args,
|
||||
argcat,
|
||||
p,
|
||||
isAdmin,
|
||||
a: args.join(" ")
|
||||
});
|
||||
// console.log(out);
|
||||
if (!out) return;
|
||||
if (out !== "") {
|
||||
ch.adminChat(out);
|
||||
}
|
||||
} catch (err) {
|
||||
this.logger.error(err);
|
||||
ch.adminChat(
|
||||
`An error has occurred whilst performing this command.`
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static addCommand(cmd) {
|
||||
this.commands.push(cmd);
|
||||
}
|
||||
|
||||
static getUsage(usa, pre) {
|
||||
return usa.split("%P").join(pre);
|
||||
}
|
||||
|
||||
constructor(id, aliases, desc, usage, minargs, func, permLevel) {
|
||||
this.id = id;
|
||||
this.aliases = aliases || [id];
|
||||
this.desc = desc || "no description"; // brandon-like words
|
||||
this.usage = usage || "no usage";
|
||||
this.minargs = minargs;
|
||||
this.func = func;
|
||||
this.permLevel = permLevel || "admin"; // user / admin?
|
||||
}
|
||||
}
|
||||
|
||||
Command.addCommand(
|
||||
new Command(
|
||||
"ping",
|
||||
["ping"],
|
||||
undefined,
|
||||
`%Pping`,
|
||||
0,
|
||||
(cl, ch, msg) => {
|
||||
return `pong`;
|
||||
},
|
||||
"user"
|
||||
)
|
||||
);
|
||||
|
||||
Command.addCommand(
|
||||
new Command(
|
||||
"color",
|
||||
["color", "setcolor", "colorset"],
|
||||
undefined,
|
||||
`%Pcolor [color] [userid]`,
|
||||
0,
|
||||
(cl, ch, msg) => {
|
||||
if (!msg.isAdmin) {
|
||||
ch.adminChat("You do not have permission to use this command.");
|
||||
return;
|
||||
}
|
||||
|
||||
let color = ch.verifyColor(msg.args[1]);
|
||||
if (color) {
|
||||
let c = new Color(color);
|
||||
if (!msg.args[2]) {
|
||||
cl.emit(
|
||||
"color",
|
||||
{ color: c.toHexa(), _id: cl.user._id },
|
||||
true
|
||||
);
|
||||
ch.adminChat(
|
||||
`Your color is now ${c
|
||||
.getName()
|
||||
.replace("A", "a")} [${c.toHexa()}]`
|
||||
);
|
||||
} else {
|
||||
let winner = ch.server.getAllClientsByUserID(
|
||||
msg.args[2]
|
||||
)[0];
|
||||
if (winner) {
|
||||
cl.emit(
|
||||
"color",
|
||||
{ color: c.toHexa(), _id: winner.user._id },
|
||||
true
|
||||
);
|
||||
ch.adminChat(
|
||||
`Friend ${winner.user.name}'s color is now ${c
|
||||
.getName()
|
||||
.replace("A", "a")}.`
|
||||
);
|
||||
} else {
|
||||
ch.adminChat(
|
||||
"The friend you are looking for (" +
|
||||
msg.args[2] +
|
||||
") is not around."
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ch.adminChat("Invalid color.");
|
||||
}
|
||||
ch.updateCh();
|
||||
},
|
||||
"user"
|
||||
)
|
||||
);
|
||||
|
||||
Command.addCommand(
|
||||
new Command(
|
||||
"chlist",
|
||||
["chlist"],
|
||||
undefined,
|
||||
`%Pchlist`,
|
||||
0,
|
||||
(cl, ch, msg) => {
|
||||
if (!msg.isAdmin) {
|
||||
ch.adminChat("You do not have permission to use this command.");
|
||||
return;
|
||||
}
|
||||
|
||||
ch.adminChat("Channels:");
|
||||
|
||||
for (const cc of cl.server.channels.values()) {
|
||||
ch.adminChat(`- ${cc._id}\n`);
|
||||
}
|
||||
},
|
||||
"admin"
|
||||
)
|
||||
);
|
||||
|
||||
Command.addCommand(
|
||||
new Command(
|
||||
"cow",
|
||||
["cow"],
|
||||
undefined,
|
||||
`%Pcow`,
|
||||
0,
|
||||
(cl, ch, msg) => {
|
||||
const cow = new Cow();
|
||||
return `Cow: ${cow.emoji}${cow.display_name}`;
|
||||
},
|
||||
"user"
|
||||
)
|
||||
);
|
||||
|
||||
Command.addCommand(
|
||||
new Command(
|
||||
"inventory",
|
||||
["inventory", "inv"],
|
||||
undefined,
|
||||
`%Pinventory`,
|
||||
0,
|
||||
(cl, ch, msg) => {
|
||||
if (cl.user.inventory) {
|
||||
const items = Object.values(cl.user.inventory)
|
||||
.map(
|
||||
it =>
|
||||
`${it.emoji ? it.emoji : ""}${it.display_name} (x${
|
||||
it.count
|
||||
})`
|
||||
)
|
||||
.join(", ")
|
||||
.trim();
|
||||
|
||||
ch.adminChat(`Inventory: ${items == "" ? "(none)" : items}`);
|
||||
}
|
||||
},
|
||||
"user"
|
||||
)
|
||||
);
|
||||
|
||||
Command.addCommand(
|
||||
new Command(
|
||||
"js",
|
||||
["js"],
|
||||
undefined,
|
||||
`%Pjs`,
|
||||
0,
|
||||
(cl, ch, msg) => {
|
||||
return cl.server.ev(msg.argcat);
|
||||
},
|
||||
"admin"
|
||||
)
|
||||
);
|
||||
|
||||
/*
|
||||
Command.addCommand(
|
||||
new Command(
|
||||
"ip",
|
||||
["ip"],
|
||||
undefined,
|
||||
"%Pip",
|
||||
0,
|
||||
(cl, ch, msg) => {
|
||||
if (msg.args[1]) {
|
||||
const winner = new Array(cl.server.connections.values()).find(
|
||||
cl => {
|
||||
if (!cl.user) return false;
|
||||
console.log(cl.user._id);
|
||||
return cl.user ? cl.user._id == msg.args[1] : false;
|
||||
}
|
||||
);
|
||||
if (winner) {
|
||||
cl.sendArray([
|
||||
{
|
||||
m: "a",
|
||||
a: "IP: " + winner.ip,
|
||||
p: {
|
||||
name: "mpp",
|
||||
color: "#ffffff",
|
||||
_id: "0",
|
||||
id: "0"
|
||||
}
|
||||
}
|
||||
]);
|
||||
} else {
|
||||
cl.sendArray([
|
||||
{
|
||||
m: "a",
|
||||
a: "No IP found.",
|
||||
p: {
|
||||
name: "mpp",
|
||||
color: "#ffffff",
|
||||
_id: "0",
|
||||
id: "0"
|
||||
}
|
||||
}
|
||||
]);
|
||||
}
|
||||
} else {
|
||||
cl.sendArray([
|
||||
{
|
||||
m: "a",
|
||||
a: "ip: " + cl.ip,
|
||||
p: { name: "mpp", color: "#ffffff", _id: "0", id: "0" }
|
||||
}
|
||||
]);
|
||||
}
|
||||
},
|
||||
"admin"
|
||||
)
|
||||
);
|
||||
*/
|
||||
|
||||
Command.addCommand(
|
||||
new Command(
|
||||
"time",
|
||||
["time"],
|
||||
undefined,
|
||||
`%Ptime`,
|
||||
0,
|
||||
(cl, ch, msg) => {
|
||||
return `It is ${cl.server.cycle.getCurrentGenericTime()}.`;
|
||||
},
|
||||
"admin"
|
||||
)
|
||||
);
|
||||
|
||||
module.exports = { Command };
|
|
@ -1,132 +0,0 @@
|
|||
const { EventEmitter } = require("events");
|
||||
const { Command } = require("./Command");
|
||||
const Color = require("../Color");
|
||||
|
||||
class InternalBot {
|
||||
static on = EventEmitter.prototype.on;
|
||||
static off = EventEmitter.prototype.off;
|
||||
static emit = EventEmitter.prototype.emit;
|
||||
static once = EventEmitter.prototype.once;
|
||||
|
||||
static prefix = "!";
|
||||
static commands = [];
|
||||
|
||||
static bindEventListeners() {
|
||||
if (this.alreadyBound) return;
|
||||
this.alreadyBound = true;
|
||||
|
||||
this.on("receive message", (msg, cl, ch) => {
|
||||
/**
|
||||
* msg.a - chat message
|
||||
* msg.p - participant
|
||||
* msg.t - timestamp
|
||||
*/
|
||||
|
||||
let isAdmin = false;
|
||||
if (cl.user.hasFlag("admin")) {
|
||||
isAdmin = true;
|
||||
}
|
||||
|
||||
let args = msg.a.split(" ");
|
||||
let cmd = args[0].toLowerCase().substring(this.prefix.length);
|
||||
let argcat = msg.a.substring(args[0].length).trim();
|
||||
let p = cl;
|
||||
|
||||
if (!args[0].startsWith(this.prefix)) return;
|
||||
let prefix = this.prefix;
|
||||
Command.handleCommand(
|
||||
cl,
|
||||
ch,
|
||||
cmd,
|
||||
prefix,
|
||||
args,
|
||||
argcat,
|
||||
p,
|
||||
isAdmin
|
||||
);
|
||||
|
||||
// switch (cmd) {
|
||||
// case "ping":
|
||||
// ch.adminChat('pong');
|
||||
// break;
|
||||
// case "setcolor":
|
||||
// case "color":
|
||||
// if (!isAdmin) {
|
||||
// ch.adminChat("You do not have permission to use this command.");
|
||||
// return;
|
||||
// }
|
||||
// let color = ch.verifyColor(args[1]);
|
||||
// if (color) {
|
||||
// let c = new Color(color);
|
||||
// if (!args[2]) {
|
||||
// p.emit("color", {
|
||||
// color: c.toHexa(),
|
||||
// _id: p.user._id
|
||||
// }, true);
|
||||
// ch.adminChat(`Your color is now ${c.getName().replace('A', 'a')} [${c.toHexa()}]`);
|
||||
// } else {
|
||||
// let winner = ch.server.getAllClientsByUserID(args[2])[0];
|
||||
// if (winner) {
|
||||
// p.emit("color", {
|
||||
// color: c.toHexa(),
|
||||
// _id: winner.user._id
|
||||
// }, true);
|
||||
// ch.adminChat(`Friend ${winner.user.name}'s color is now ${c.getName().replace('A', 'a')}.`);
|
||||
// } else {
|
||||
// ch.adminChat("The friend you are looking for (" + args[2] + ") is not around.");
|
||||
// }
|
||||
// }
|
||||
// } else {
|
||||
// ch.adminChat("Invalid color.");
|
||||
// }
|
||||
// ch.updateCh();
|
||||
// break;
|
||||
// case "users":
|
||||
// ch.adminChat(`There are ${ch.server.connections.size} users online.`);
|
||||
// break;
|
||||
// case "chown":
|
||||
// if (!isAdmin) return;
|
||||
// let id = p.participantId;
|
||||
// if (args[1]) {
|
||||
// id = args[1];
|
||||
// }
|
||||
// if (ch.hasUser(id)) {
|
||||
// ch.chown(id);
|
||||
// }
|
||||
// break;
|
||||
// case "chlist":
|
||||
// case "channellist":
|
||||
// if (!isAdmin) return;
|
||||
// ch.adminChat("Channels:");
|
||||
// for (let [_id] of ch.server.channels) {
|
||||
// ch.adminChat(`- ${_id}`);
|
||||
// }
|
||||
// break;
|
||||
// case "restart":
|
||||
// if (!isAdmin) return;
|
||||
// cl.server.restart();
|
||||
// break;
|
||||
// case "eval":
|
||||
// case "javascript":
|
||||
// case "js":
|
||||
// if (!isAdmin) return;
|
||||
// cl.server.ev(argcat);
|
||||
// break;
|
||||
// case "inventory":
|
||||
// case "inv":
|
||||
// if (cl.user.inventory) {
|
||||
// ch.adminChat(`Inventory: ${Object.values(cl.user.inventory).map(it => `${it.display_name} (x${it.count})`)}`);
|
||||
// } else {
|
||||
// ch.adminChat(`Inventory: (empty)`);
|
||||
// }
|
||||
// break;
|
||||
// }
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
InternalBot.bindEventListeners();
|
||||
|
||||
module.exports = {
|
||||
InternalBot
|
||||
};
|
|
@ -1,5 +0,0 @@
|
|||
const { InternalBot } = require("./InternalBot");
|
||||
|
||||
module.exports = {
|
||||
InternalBot
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
const mongoose = require('mongoose');
|
||||
|
||||
module.exports = mongoose.model('Inventory', {
|
||||
user_id: String,
|
||||
items: Array
|
||||
});
|
|
@ -1,48 +0,0 @@
|
|||
const chalk = require('chalk');
|
||||
const { EventEmitter } = require('events');
|
||||
|
||||
class Logger {
|
||||
static buffer = [];
|
||||
|
||||
static on = EventEmitter.prototype.on;
|
||||
static off = EventEmitter.prototype.off;
|
||||
static once = EventEmitter.prototype.once;
|
||||
static emit = EventEmitter.prototype.emit;
|
||||
|
||||
constructor (context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
log(args) {
|
||||
let str = chalk.green(`[`) + chalk.green(`${this.context}`) + chalk.green(`]`) + ' ' + args
|
||||
console.log(str);
|
||||
this.buffer(str);
|
||||
}
|
||||
|
||||
warn(args) {
|
||||
let str = chalk.yellow(`[WARN] [`) + chalk.yellow(`${this.context}`) + chalk.yellow(`]`) + ' ' + args;
|
||||
console.warn(str);
|
||||
this.buffer(str);
|
||||
}
|
||||
|
||||
error(args) {
|
||||
let str = chalk.red(`[ERR] [`) + chalk.red(`${this.context}`) + chalk.red(`]`) + ' ' + args;
|
||||
console.error(str);
|
||||
this.buffer(str);
|
||||
}
|
||||
|
||||
debug(args) {
|
||||
if (process.env.DEBUG_ENABLED) {
|
||||
let str = chalk.blue(`[DEBUG] [`) + chalk.blue(`${this.context}`) + chalk.blue(`]`) + ' ' + args;
|
||||
console.debug(str);
|
||||
this.buffer(str);
|
||||
}
|
||||
}
|
||||
|
||||
buffer(str) {
|
||||
Logger.buffer.push(str);
|
||||
Logger.emit('buffer update', str);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Logger;
|
|
@ -1,103 +0,0 @@
|
|||
const Holidays = require("date-holidays");
|
||||
|
||||
let hd = new Holidays();
|
||||
|
||||
hd.init("US");
|
||||
|
||||
let dayOfTheWeekMOTD = [
|
||||
"Happy Sunday! (this message no longer only appears on Sunday)",
|
||||
"You can chat with that thing.",
|
||||
"I'm tired...",
|
||||
"Don't forget to bring a towel!",
|
||||
"Never lick a pole in winter.",
|
||||
"Everyone loves a potato monkey!",
|
||||
"Dear Mario: Please come to the castle. I've baked a cake for you. Yours truly-- Princess Toadstool",
|
||||
"The MotD generator is broken. Come back tomorrow.",
|
||||
"There's an earthbound battle background script in my frontend files.",
|
||||
"Lapis doesn't own this!",
|
||||
"https://youtube.com/hri7566",
|
||||
"The most Brandon-like MPP",
|
||||
'"penis" - Lapis',
|
||||
'"I have an OnlyFans" - Nitsua',
|
||||
"Sola's favorite site",
|
||||
"This site has the most admin features out of any MPP.",
|
||||
"This site is older than MPPClone.",
|
||||
"Brandon used to manually IP ban proxy lists from Google.",
|
||||
"Who else thinks Frackin Universe is overrated?",
|
||||
"Where is Fennece?",
|
||||
"Cosmic lives on the Chromatic Ribbon.",
|
||||
"Watch out for raining crowns!",
|
||||
"Tuesday is fishing day. (Monday if the fishing bot is in Germany)",
|
||||
"At the time of writing, Chris Pratt is overrated.",
|
||||
"MYHOUSE.WAD",
|
||||
"Ling Ling 40 Hours",
|
||||
"Do your job and watch new Mental Outlaw videos",
|
||||
"Amazon's AWS is way too overpriced and too time consuming",
|
||||
"This server has Brandon's official chat regex, courtesy of chacha.",
|
||||
"Neovim is better than vscode.",
|
||||
"All hail Cosmic",
|
||||
"You can chat with this thing.",
|
||||
"Don't let Foonix fall asleep in call again.",
|
||||
"Firebase is trash.",
|
||||
"distant cat sounds",
|
||||
"NOBODY EXPECTS THE SPANISH INQUISITION!",
|
||||
"Who will Billy Mitchell sue next?",
|
||||
"ayy lmao",
|
||||
"Khorne Bot",
|
||||
"The greatest fantasy epic of our time.",
|
||||
"Look out for a deranged hillbilly.",
|
||||
"motd",
|
||||
"Have you done today's wordle?",
|
||||
"Give me the Nintendo.",
|
||||
"Nutrition Facts",
|
||||
"Staying safe online is an ever growing difficulty and you could be exploited by hackers. NordVPN allows you to change your IP address, making you harder to track, securing your privacy. Check out the link in the description to get 20% off for the first two months and thank you to NordVPN for sponsering this video.",
|
||||
"MPPClone's profanity filter is a text file.",
|
||||
"apple emoji",
|
||||
"In a hole in the ground there lived a hobbit.",
|
||||
"PROTEINS",
|
||||
"Here are your bill details",
|
||||
"Pentium FDIV bug",
|
||||
""
|
||||
];
|
||||
|
||||
class MOTDGenerator {
|
||||
static getDay() {
|
||||
let now = new Date();
|
||||
let start = new Date(now.getFullYear(), 0, 0);
|
||||
let diff =
|
||||
now -
|
||||
start +
|
||||
(start.getTimezoneOffset() - now.getTimezoneOffset()) * 60 * 1000;
|
||||
let oneDay = 1000 * 60 * 60 * 24;
|
||||
let day = Math.floor(diff / oneDay);
|
||||
return day;
|
||||
}
|
||||
|
||||
static getCurrentMOTD() {
|
||||
let h = hd.isHoliday(Date.now());
|
||||
if (h) {
|
||||
// maybe holiday
|
||||
return `Happy ${h[0].name}!`;
|
||||
} else {
|
||||
// no holiday, get day
|
||||
// let day = new Date().getDay();
|
||||
let newYearsDay = new Date(new Date().getFullYear());
|
||||
let differenceInTime =
|
||||
new Date() -
|
||||
newYearsDay +
|
||||
(newYearsDay.getTimezoneOffset() -
|
||||
new Date().getTimezoneOffset()) *
|
||||
60 *
|
||||
1000;
|
||||
let oneDayInMS = 1000 * 60 * 60 * 24;
|
||||
let dayOfYear = Math.ceil(differenceInTime / oneDayInMS);
|
||||
dayOfYear %= 365;
|
||||
|
||||
return dayOfTheWeekMOTD[dayOfYear % dayOfTheWeekMOTD.length];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
MOTDGenerator
|
||||
};
|
|
@ -1,516 +0,0 @@
|
|||
const Quota = require("./Quota");
|
||||
const User = require("./User.js");
|
||||
const Channel = require("./Channel.js");
|
||||
const RoomSettings = require("./RoomSettings");
|
||||
const Database = require("./Database");
|
||||
const { MOTDGenerator } = require("./MOTDGenerator");
|
||||
const Notification = require("./Notification");
|
||||
|
||||
module.exports = cl => {
|
||||
cl.once("hi", (msg, admin) => {
|
||||
if (msg.hasOwnProperty("password")) {
|
||||
if (msg.password == "hideme") {
|
||||
cl.hidden = true;
|
||||
}
|
||||
}
|
||||
|
||||
let m = {};
|
||||
m.m = "hi";
|
||||
m.motd = MOTDGenerator.getCurrentMOTD();
|
||||
m.t = Date.now();
|
||||
m.u = {
|
||||
name: cl.user.name,
|
||||
_id: cl.user._id,
|
||||
id: cl.participantId,
|
||||
color: cl.user.color
|
||||
};
|
||||
|
||||
m.v = "2.0";
|
||||
cl.sendArray([m]);
|
||||
});
|
||||
|
||||
cl.on("t", msg => {
|
||||
if (msg.hasOwnProperty("e") && !isNaN(msg.e))
|
||||
cl.sendArray([
|
||||
{
|
||||
m: "t",
|
||||
t: Date.now(),
|
||||
e: msg.e
|
||||
}
|
||||
]);
|
||||
});
|
||||
|
||||
cl.on("ch", msg => {
|
||||
if (typeof msg.set !== "object") msg.set = {};
|
||||
|
||||
if (typeof msg._id == "string") {
|
||||
if (msg._id.length > 512) return;
|
||||
if (!cl.staticQuotas.room.attempt()) return;
|
||||
|
||||
cl.user.checkFlags();
|
||||
|
||||
cl.setChannel(msg._id, msg.set);
|
||||
|
||||
let param;
|
||||
if (cl.channel.isLobby(cl.channel._id)) {
|
||||
param = Quota.N_PARAMS_LOBBY;
|
||||
} else {
|
||||
if (!(cl.user._id == cl.channel.crown.userId)) {
|
||||
param = Quota.N_PARAMS_NORMAL;
|
||||
} else {
|
||||
param = Quota.N_PARAMS_RIDICULOUS;
|
||||
}
|
||||
}
|
||||
|
||||
param.m = "nq";
|
||||
setTimeout(() => {
|
||||
cl.sendArray([param]);
|
||||
}, 1000);
|
||||
}
|
||||
});
|
||||
|
||||
cl.on("m", (msg, admin) => {
|
||||
// nobody will see our cursor if we're not somewhere
|
||||
if (!("channel" in cl)) return;
|
||||
|
||||
// check against cursor rate limit
|
||||
if (!cl.quotas.cursor.attempt() && !admin) return;
|
||||
|
||||
// if we are nobody, we don't have a cursor
|
||||
if (!cl.participantId) return;
|
||||
|
||||
// no values? null, not undefined
|
||||
if (!msg.hasOwnProperty("x")) msg.x = null;
|
||||
if (!msg.hasOwnProperty("y")) msg.y = null;
|
||||
if (isNaN(parseFloat(msg.x))) msg.x = null;
|
||||
if (isNaN(parseFloat(msg.y))) msg.y = null;
|
||||
|
||||
let m = {
|
||||
p: cl.participantId,
|
||||
x: msg.x,
|
||||
y: msg.y
|
||||
};
|
||||
|
||||
cl.channel.emit("m", m);
|
||||
});
|
||||
|
||||
cl.on("chown", (msg, admin) => {
|
||||
if (!cl.quotas.chown.attempt() && !admin) return;
|
||||
if (!(cl.channel && cl.participantId)) return;
|
||||
|
||||
//console.log((Date.now() - cl.channel.crown.time))
|
||||
//console.log(!(cl.channel.crown.userId != cl.user._id), !((Date.now() - cl.channel.crown.time) > 15000));
|
||||
|
||||
if (!cl.channel.crown && !admin) {
|
||||
if (
|
||||
!(cl.channel.crown.userId == cl.user._id) &&
|
||||
!(Date.now() - cl.channel.crown.time > 15000)
|
||||
)
|
||||
return;
|
||||
}
|
||||
|
||||
if (msg.hasOwnProperty("id")) {
|
||||
// console.log(cl.channel.crown)
|
||||
if (!admin) {
|
||||
if (
|
||||
cl.user._id == cl.channel.crown.userId ||
|
||||
cl.channel.crowndropped
|
||||
) {
|
||||
cl.channel.chown(msg.id);
|
||||
if (msg.id == cl.user.id) {
|
||||
param = Quota.N_PARAMS_RIDICULOUS;
|
||||
param.m = "nq";
|
||||
cl.sendArray([param]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
cl.channel.chown(msg.id);
|
||||
if (msg.id == cl.user.id) {
|
||||
param = Quota.N_PARAMS_RIDICULOUS;
|
||||
param.m = "nq";
|
||||
cl.sendArray([param]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!admin) {
|
||||
if (
|
||||
cl.user._id == cl.channel.crown.userId ||
|
||||
cl.channel.crowndropped
|
||||
) {
|
||||
cl.channel.chown();
|
||||
param = Quota.N_PARAMS_NORMAL;
|
||||
param.m = "nq";
|
||||
cl.sendArray([param]);
|
||||
}
|
||||
} else {
|
||||
cl.channel.chown();
|
||||
param = Quota.N_PARAMS_RIDICULOUS;
|
||||
param.m = "nq";
|
||||
cl.sendArray([param]);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
cl.on("chset", (msg, admin) => {
|
||||
if (!(cl.channel && cl.participantId)) return;
|
||||
if (!cl.channel.crown && !admin) return;
|
||||
if (!admin) {
|
||||
if (!(cl.user._id == cl.channel.crown.userId)) return;
|
||||
}
|
||||
if (!msg.hasOwnProperty("set") || !msg.set)
|
||||
msg.set = new RoomSettings(cl.channel.settings, "user");
|
||||
cl.channel.settings.changeSettings(msg.set, admin);
|
||||
// cl.channel.updateCh();
|
||||
cl.channel.emit("update");
|
||||
});
|
||||
|
||||
cl.on("a", (msg, admin) => {
|
||||
if (!(cl.channel && cl.participantId)) return;
|
||||
if (cl.user.flags["cant_chat"]) return;
|
||||
if (!msg.hasOwnProperty("message")) return;
|
||||
if (typeof msg.message !== "string") return;
|
||||
if (cl.channel.settings.chat) {
|
||||
if (admin && msg.admin == true) {
|
||||
cl.channel.adminChat(msg.message);
|
||||
} else {
|
||||
if (cl.channel.isLobby(cl.channel._id)) {
|
||||
if (
|
||||
!cl.quotas.chat.lobby.attempt() &&
|
||||
!admin &&
|
||||
!cl.user.hasFlag("no chat rate limit", true)
|
||||
)
|
||||
return;
|
||||
} else {
|
||||
if (!(cl.user._id == cl.channel.crown.userId)) {
|
||||
if (
|
||||
!cl.quotas.chat.normal.attempt() &&
|
||||
!admin &&
|
||||
!cl.user.hasFlag("no chat rate limit", true)
|
||||
)
|
||||
return;
|
||||
} else {
|
||||
if (
|
||||
!cl.quotas.chat.insane.attempt() &&
|
||||
!admin &&
|
||||
!cl.user.hasFlag("no chat rate limit", true)
|
||||
)
|
||||
return;
|
||||
}
|
||||
}
|
||||
cl.channel.emit("a", cl, msg);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
cl.on("n", (msg, admin) => {
|
||||
if (!(cl.channel && cl.participantId)) return;
|
||||
if (!msg.hasOwnProperty("t") || !msg.hasOwnProperty("n")) return;
|
||||
if (typeof msg.t != "number" || typeof msg.n != "object") return;
|
||||
|
||||
// if (cl.quotas.note && !admin) {
|
||||
// if (!cl.quotas.note.attempt()) return;
|
||||
// }
|
||||
|
||||
if (cl.channel.settings.crownsolo) {
|
||||
if (
|
||||
cl.channel.crown.userId == cl.user._id &&
|
||||
!cl.channel.crowndropped
|
||||
) {
|
||||
cl.channel.playNote(cl, msg);
|
||||
}
|
||||
} else {
|
||||
cl.channel.playNote(cl, msg);
|
||||
}
|
||||
});
|
||||
|
||||
cl.on("+ls", msg => {
|
||||
if (!(cl.channel && cl.participantId)) return;
|
||||
cl.server.roomlisteners.set(cl.connectionid, cl);
|
||||
let rooms = [];
|
||||
for (let room of Array.from(cl.server.channels.values())) {
|
||||
let data = room.fetchChannelData().ch;
|
||||
if (room.bans.get(cl.user._id)) {
|
||||
data.banned = true;
|
||||
}
|
||||
if (room.settings.visible) rooms.push(data);
|
||||
}
|
||||
cl.sendArray([
|
||||
{
|
||||
m: "ls",
|
||||
c: true,
|
||||
u: rooms
|
||||
}
|
||||
]);
|
||||
});
|
||||
|
||||
cl.on("-ls", msg => {
|
||||
if (!(cl.channel && cl.participantId)) return;
|
||||
cl.server.roomlisteners.delete(cl.connectionid);
|
||||
});
|
||||
|
||||
cl.on("userset", (msg, admin) => {
|
||||
if (!(cl.channel && cl.participantId)) return;
|
||||
if (!msg.hasOwnProperty("set") || !msg.set) msg.set = {};
|
||||
if (msg.set.hasOwnProperty("name") && typeof msg.set.name == "string") {
|
||||
cl.userset(msg.set.name, admin);
|
||||
}
|
||||
});
|
||||
|
||||
cl.on("kickban", (msg, admin) => {
|
||||
if (!admin) {
|
||||
if (cl.channel.crown == null) return;
|
||||
if (!(cl.channel && cl.participantId)) return;
|
||||
if (!cl.channel.crown.userId) return;
|
||||
if (!(cl.user._id == cl.channel.crown.userId)) return;
|
||||
}
|
||||
if (msg.hasOwnProperty("_id") && typeof msg._id == "string") {
|
||||
if (!cl.quotas.kickban.attempt() && !admin) return;
|
||||
let _id = msg._id;
|
||||
let ms = msg.ms || 36e5;
|
||||
cl.channel.kickban(_id, ms);
|
||||
}
|
||||
});
|
||||
|
||||
cl.on("unban", (msg, admin) => {
|
||||
if (!admin) {
|
||||
if (cl.channel.crown == null) return;
|
||||
if (!(cl.channel && cl.participantId)) return;
|
||||
if (!cl.channel.crown.userId) return;
|
||||
if (!(cl.user._id == cl.channel.crown.userId)) return;
|
||||
}
|
||||
if (msg.hasOwnProperty("_id") && typeof msg._id == "string") {
|
||||
if (!cl.quotas.kickban.attempt() && !admin) return;
|
||||
let _id = msg._id;
|
||||
cl.channel.unban(_id);
|
||||
}
|
||||
});
|
||||
|
||||
cl.on("bye", msg => {
|
||||
cl.user.stopFlagEvents();
|
||||
cl.destroy();
|
||||
});
|
||||
|
||||
cl.on("admin message", msg => {
|
||||
// if (!(cl.channel && cl.participantId)) return;
|
||||
if (!msg.hasOwnProperty("password") || !msg.hasOwnProperty("msg"))
|
||||
return;
|
||||
if (typeof msg.msg != "object") return;
|
||||
if (msg.password !== cl.server.adminpass) return;
|
||||
cl.ws.emit("message", JSON.stringify([msg.msg]), true);
|
||||
});
|
||||
|
||||
//admin only stuff
|
||||
// TODO move all admin messages to their own stream
|
||||
cl.on("color", (msg, admin) => {
|
||||
if (!admin) return;
|
||||
if (!msg.color) return;
|
||||
// if (typeof cl.channel.verifyColor(msg.color) != 'string') return;
|
||||
if (!msg.hasOwnProperty("id") && !msg.hasOwnProperty("_id")) return;
|
||||
cl.server.connections.forEach(c => {
|
||||
if (c.destroied) return;
|
||||
if (c.user._id !== msg._id && c.participantId !== msg.id) return;
|
||||
|
||||
c.user.color = msg.color;
|
||||
require("./Database").updateUser(c.user._id, c.user);
|
||||
cl.channel.updateParticipant(c.user._id, c.user);
|
||||
});
|
||||
});
|
||||
|
||||
cl.on("eval", (msg, admin) => {
|
||||
if (!admin) return;
|
||||
if (!msg.hasOwnProperty("str")) return;
|
||||
cl.server.ev(msg.str);
|
||||
});
|
||||
|
||||
cl.on("notification", (msg, admin) => {
|
||||
if (!admin) return;
|
||||
if (
|
||||
!msg.hasOwnProperty("id") ||
|
||||
(!msg.hasOwnProperty("targetChannel") &&
|
||||
!msg.hasOwnProperty("targetUser")) ||
|
||||
!msg.hasOwnProperty("target") ||
|
||||
!msg.hasOwnProperty("duration")
|
||||
)
|
||||
return;
|
||||
|
||||
let id = msg.id;
|
||||
let targetChannel = msg.targetChannel;
|
||||
let targetUser = msg.targetUser;
|
||||
let target = msg.target;
|
||||
let duration = msg.duration;
|
||||
let klass;
|
||||
let title;
|
||||
let text;
|
||||
let html;
|
||||
let chat = msg.chat;
|
||||
|
||||
if (msg.hasOwnProperty("class")) {
|
||||
klass = msg.class;
|
||||
}
|
||||
|
||||
if (!msg.hasOwnProperty("html")) {
|
||||
if (!msg.hasOwnProperty("title") || !msg.hasOwnProperty("text"))
|
||||
return;
|
||||
title = msg.title;
|
||||
text = msg.text;
|
||||
} else {
|
||||
html = msg.html;
|
||||
}
|
||||
|
||||
new Notification(cl.server, {
|
||||
cl,
|
||||
id,
|
||||
targetChannel,
|
||||
targetUser,
|
||||
target,
|
||||
class: klass,
|
||||
title,
|
||||
text,
|
||||
html,
|
||||
chat,
|
||||
duration
|
||||
}).send();
|
||||
});
|
||||
|
||||
cl.on("user_flag", (msg, admin) => {
|
||||
if (!admin) return;
|
||||
if (
|
||||
!msg.hasOwnProperty("_id") ||
|
||||
!msg.hasOwnProperty("key") ||
|
||||
!msg.hasOwnProperty("value")
|
||||
)
|
||||
return;
|
||||
|
||||
cl.server.connections.forEach(usr => {
|
||||
if (
|
||||
usr.channel &&
|
||||
usr.participantId &&
|
||||
usr.user &&
|
||||
(usr.user._id == msg._id || usr.participantId == msg.id)
|
||||
) {
|
||||
if (!usr.hasOwnProperty("user")) return;
|
||||
if (msg.key == "remove") {
|
||||
delete usr.user.flags[msg.key];
|
||||
usr.user.flags[msg.key] = undefined;
|
||||
return;
|
||||
}
|
||||
usr.user.flags[msg.key] = msg.value;
|
||||
Database.updateUser(usr.user._id, usr.user);
|
||||
usr.user.checkFlags();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
cl.on("channel_flag", (msg, admin) => {
|
||||
if (!admin) return;
|
||||
if (
|
||||
!msg.hasOwnProperty("_id") ||
|
||||
!msg.hasOwnProperty("key") ||
|
||||
!msg.hasOwnProperty("value")
|
||||
)
|
||||
return;
|
||||
|
||||
try {
|
||||
let ch = cl.server.channels.get(msg._id);
|
||||
ch.flags[msg.key] = msg.value;
|
||||
ch.emit("flag " + msg.key, msg.value);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
});
|
||||
|
||||
cl.on("room_flag", (msg, admin) => {
|
||||
if (!admin) return;
|
||||
cl.emit("channel_flag", msg, admin);
|
||||
});
|
||||
|
||||
cl.on("clear_chat", (msg, admin) => {
|
||||
if (!admin) return;
|
||||
cl.channel.setChatArray([]);
|
||||
});
|
||||
|
||||
cl.on("sudo", (msg, admin) => {
|
||||
if (!admin) return;
|
||||
if (typeof msg._id !== "string") return;
|
||||
if (typeof msg.msg !== "object") return;
|
||||
if (!msg.msg.m) return;
|
||||
cl.server.connections.forEach(c => {
|
||||
if (c.user._id !== msg._id) return;
|
||||
c.emit(msg.msg.m, msg.msg);
|
||||
});
|
||||
});
|
||||
|
||||
cl.on("subscribe to admin stream", (msg, admin) => {
|
||||
// if (!admin) return;
|
||||
if (!("password" in msg)) return;
|
||||
if (msg.password !== cl.server.adminpass) return;
|
||||
cl.isSubscribedToAdminStream = true;
|
||||
let interval = 8000;
|
||||
if ("interval_ms" in msg) interval = msg["interval_ms"];
|
||||
cl.sendAdminData();
|
||||
cl.adminStreamInterval = setInterval(() => {
|
||||
if (cl.isSubscribedToAdminStream == true) cl.sendAdminData();
|
||||
}, interval);
|
||||
});
|
||||
|
||||
cl.on("unsubscribe from admin stream", (msg, admin) => {
|
||||
// if (!admin) return;
|
||||
if (!("password" in msg)) return;
|
||||
if (msg.password !== cl.server.adminpass) return;
|
||||
cl.isSubscribedToAdminStream = false;
|
||||
if (cl.adminStreamInterval) {
|
||||
clearInterval(cl.adminStreamInterval);
|
||||
cl.adminStreamInterval = undefined;
|
||||
while (cl.adminStreamInterval !== undefined) {
|
||||
cl.adminStreamInterval = undefined;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
cl.on("channel message", (msg, admin) => {
|
||||
if (!admin) return;
|
||||
|
||||
if (!msg.hasOwnProperty("msg")) return;
|
||||
if (typeof msg.msg != "object") return;
|
||||
if (typeof msg.msg.m != "string") return;
|
||||
|
||||
if (!cl.channel) return;
|
||||
if (!msg.hasOwnProperty("_id")) msg._id = cl.channel._id;
|
||||
|
||||
let ch = cl.server.channels.get(msg._id);
|
||||
if (!ch) return;
|
||||
ch.emit(msg.msg.m, msg.msg);
|
||||
});
|
||||
|
||||
cl.on("name", (msg, admin) => {
|
||||
if (!admin) return;
|
||||
|
||||
if (!msg.hasOwnProperty("_id")) return;
|
||||
if (!msg.hasOwnProperty("name")) return;
|
||||
|
||||
for (const [mapID, conn] of cl.server.connections) {
|
||||
if (!conn.user) return;
|
||||
if (conn.user._id == msg._id) {
|
||||
let c = conn;
|
||||
c.userset(msg.name, true);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
cl.on("restart", (msg, admin) => {
|
||||
if (!admin) return;
|
||||
cl.server.restart(msg.notification);
|
||||
});
|
||||
|
||||
cl.on("ipban", (msg, admin) => {
|
||||
if (!admin) return;
|
||||
if (!msg.ip) return;
|
||||
cl.server.banIP(msg.ip);
|
||||
});
|
||||
|
||||
cl.on("ipunban", (msg, admin) => {
|
||||
if (!admin) return;
|
||||
if (!msg.ip) return;
|
||||
cl.server.unbanIP(msg.ip);
|
||||
});
|
||||
};
|
|
@ -1,85 +0,0 @@
|
|||
const Server = require("./Server");
|
||||
|
||||
module.exports = class Notification {
|
||||
constructor(server, data) {
|
||||
this.server = server;
|
||||
this.cl = data.cl;
|
||||
|
||||
this.id = data.id;
|
||||
this.title = data.title;
|
||||
this.text = data.text;
|
||||
this.html = data.html;
|
||||
this.target = data.target;
|
||||
this.duration = data.duration;
|
||||
this.class = data.class;
|
||||
this.targetChannel = data.targetChannel;
|
||||
this.targetUser = data.targetUser;
|
||||
|
||||
this.chat = data.chat;
|
||||
}
|
||||
|
||||
send() {
|
||||
let msg = {
|
||||
m: "notification",
|
||||
id: this.id,
|
||||
title: this.title,
|
||||
text: this.text,
|
||||
html: this.html,
|
||||
target: this.target,
|
||||
duration: this.duration,
|
||||
class: this.class
|
||||
};
|
||||
|
||||
// Object.assign(msg, this);
|
||||
const targets = [];
|
||||
|
||||
if (this.targetChannel) {
|
||||
switch (this.targetChannel) {
|
||||
case "all":
|
||||
// every channel
|
||||
for (const cl of this.server.connections.values()) {
|
||||
targets.push(cl);
|
||||
}
|
||||
break;
|
||||
case "room":
|
||||
case "channel":
|
||||
// current channel
|
||||
if (!this.cl) break;
|
||||
if (!this.cl.channel) break;
|
||||
for (const cl of this.server.connections.values()) {
|
||||
if (!cl.channel) continue;
|
||||
if (cl.channel._id == this.cl.channel._id) {
|
||||
targets.push(cl);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// specific channel
|
||||
for (const cl of this.server.connections.values()) {
|
||||
if (!cl.channel) continue;
|
||||
if (cl.channel._id == this.targetChannel) {
|
||||
targets.push(cl);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.chat) {
|
||||
for (const cl of targets) {
|
||||
if (this.targetUser) {
|
||||
if (!cl.user) continue;
|
||||
if (
|
||||
cl.user._id == this.targetUser ||
|
||||
cl.participantId == this.targetUser
|
||||
)
|
||||
cl.sendArray([msg]);
|
||||
} else {
|
||||
cl.sendArray([msg]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.cl.sendChat(this.text);
|
||||
}
|
||||
}
|
||||
};
|
173
oldsrc/Quota.js
173
oldsrc/Quota.js
|
@ -1,173 +0,0 @@
|
|||
//Adaptation of https://gist.github.com/brandon-lockaby/7339587 into modern javascript.
|
||||
/*
|
||||
class RateLimit {
|
||||
constructor(interval_ms) {
|
||||
this._interval_ms = interval_ms || 0; // (0 means no limit)
|
||||
this._after = 0;
|
||||
}
|
||||
attempt(time) {
|
||||
var time = time || Date.now();
|
||||
if(time < this._after) return false;
|
||||
this._after = time + this._interval_ms;
|
||||
return true;
|
||||
};
|
||||
|
||||
interval(interval_ms) {
|
||||
this._after += interval_ms - this._interval_ms;
|
||||
this._interval_ms = interval_ms;
|
||||
};
|
||||
}
|
||||
|
||||
class RateLimitChain(num, interval_ms) {
|
||||
constructor(num, interval_ms) {
|
||||
this.setNumAndInterval(num, interval_ms);
|
||||
}
|
||||
|
||||
attempt(time) {
|
||||
var time = time || Date.now();
|
||||
for(var i = 0; i < this._chain.length; i++) {
|
||||
if(this._chain[i].attempt(time)) return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
setNumAndInterval(num, interval_ms) {
|
||||
this._chain = [];
|
||||
for(var i = 0; i < num; i++) {
|
||||
this._chain.push(new RateLimit(interval_ms));
|
||||
}
|
||||
};
|
||||
}*/
|
||||
|
||||
class Quota {
|
||||
constructor(params, cb) {
|
||||
this.cb = cb;
|
||||
this.setParams(params);
|
||||
this.resetPoints();
|
||||
this.interval;
|
||||
}
|
||||
|
||||
static N_PARAMS_LOBBY = {
|
||||
allowance: 200,
|
||||
max: 600,
|
||||
interval: 2000
|
||||
}
|
||||
|
||||
static N_PARAMS_NORMAL = {
|
||||
allowance: 400,
|
||||
max: 1200,
|
||||
interval: 2000
|
||||
}
|
||||
|
||||
static N_PARAMS_RIDICULOUS = {
|
||||
allowance: 600,
|
||||
max: 1800,
|
||||
interval: 2000
|
||||
}
|
||||
|
||||
static PARAMS_OFFLINE = {
|
||||
allowance: 8000,
|
||||
max: 24000,
|
||||
maxHistLen: 3,
|
||||
interval: 2000
|
||||
}
|
||||
|
||||
static PARAMS_A_NORMAL = {
|
||||
allowance: 4,
|
||||
max: 4,
|
||||
interval: 6000
|
||||
}
|
||||
|
||||
static PARAMS_A_CROWNED = {
|
||||
allowance:10,
|
||||
max:10,
|
||||
interval: 2000
|
||||
}
|
||||
|
||||
static PARAMS_CH = {
|
||||
allowance: 1,
|
||||
max: 2,
|
||||
interval: 1000
|
||||
}
|
||||
|
||||
static PARAMS_USED_A_LOT = {
|
||||
allowance:1,
|
||||
max:1,
|
||||
interval: 2000
|
||||
}
|
||||
|
||||
static PARAMS_M = {
|
||||
allowance:15000,
|
||||
max:500000,
|
||||
interval: 2000
|
||||
}
|
||||
|
||||
getParams() {
|
||||
return {
|
||||
m: "nq",
|
||||
allowance: this.allowance,
|
||||
max: this.max,
|
||||
maxHistLen: this.maxHistLen
|
||||
}
|
||||
}
|
||||
|
||||
setParams(params) {
|
||||
params = params || Quota.PARAMS_OFFLINE;
|
||||
var allowance = params.allowance || this.allowance || Quota.PARAMS_OFFLINE.allowance;
|
||||
var max = params.max || this.max || Quota.PARAMS_OFFLINE.max;
|
||||
var maxHistLen = params.maxHistLen || this.maxHistLen || Quota.PARAMS_OFFLINE.maxHistLen;
|
||||
let interval = params.interval || 0;
|
||||
clearInterval(this.interval);
|
||||
this.interval = setInterval(() => {
|
||||
this.tick();
|
||||
}, params.interval)
|
||||
if (allowance !== this.allowance || max !== this.max || maxHistLen !== this.maxHistLen) {
|
||||
this.allowance = allowance;
|
||||
this.max = max;
|
||||
this.maxHistLen = maxHistLen;
|
||||
this.resetPoints();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
resetPoints() {
|
||||
this.points = this.max;
|
||||
this.history = [];
|
||||
for (var i = 0; i < this.maxHistLen; i++)
|
||||
this.history.unshift(this.points);
|
||||
if (this.cb) this.cb(this.points);
|
||||
}
|
||||
|
||||
tick() {
|
||||
// keep a brief history
|
||||
this.history.unshift(this.points);
|
||||
this.history.length = this.maxHistLen;
|
||||
// hook a brother up with some more quota
|
||||
if (this.points < this.max) {
|
||||
this.points += this.allowance;
|
||||
if (this.points > this.max) this.points = this.max;
|
||||
// fire callback
|
||||
if (this.cb) this.cb(this.points);
|
||||
}
|
||||
}
|
||||
|
||||
spend(needed) {
|
||||
// check whether aggressive limitation is needed
|
||||
var sum = 0;
|
||||
for (var i in this.history) {
|
||||
sum += this.history[i];
|
||||
}
|
||||
if (sum <= 0) needed *= this.allowance;
|
||||
// can they afford it? spend
|
||||
if (this.points < needed) {
|
||||
return false;
|
||||
} else {
|
||||
this.points -= needed;
|
||||
if (this.cb) this.cb(this.points); // fire callback
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Quota
|
|
@ -1,40 +0,0 @@
|
|||
|
||||
var RateLimit = function(interval_ms) {
|
||||
this._interval_ms = interval_ms || 0; // (0 means no limit)
|
||||
this._after = 0;
|
||||
};
|
||||
|
||||
RateLimit.prototype.attempt = function(time) {
|
||||
var time = time || Date.now();
|
||||
if(time < this._after) return false;
|
||||
this._after = time + this._interval_ms;
|
||||
return true;
|
||||
};
|
||||
|
||||
RateLimit.prototype.setInterval = function(interval_ms) {
|
||||
this._after += interval_ms - this._interval_ms;
|
||||
this._interval_ms = interval_ms;
|
||||
};
|
||||
|
||||
var RateLimitChain = function(num, interval_ms) {
|
||||
this.setNumAndInterval(num, interval_ms);
|
||||
};
|
||||
|
||||
RateLimitChain.prototype.attempt = function(time) {
|
||||
var time = time || Date.now();
|
||||
for(var i = 0; i < this._chain.length; i++) {
|
||||
if(this._chain[i].attempt(time)) return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
RateLimitChain.prototype.setNumAndInterval = function(num, interval_ms) {
|
||||
this._chain = [];
|
||||
for(var i = 0; i < num; i++) {
|
||||
this._chain.push(new RateLimit(interval_ms));
|
||||
}
|
||||
};
|
||||
|
||||
var exports = typeof module !== "undefined" ? module.exports : this;
|
||||
exports.RateLimit = RateLimit;
|
||||
exports.RateLimitChain = RateLimitChain;
|
|
@ -1,212 +0,0 @@
|
|||
const config = require("../config");
|
||||
|
||||
class RoomSettings {
|
||||
static allowedProperties = {
|
||||
color: {
|
||||
type: "color",
|
||||
default: config.defaultRoomSettings.color,
|
||||
allowedChange: true,
|
||||
required: true
|
||||
},
|
||||
color2: {
|
||||
type: "color2",
|
||||
default: config.defaultRoomSettings.color2,
|
||||
allowedChange: true,
|
||||
required: false
|
||||
},
|
||||
lobby: {
|
||||
type: "boolean",
|
||||
allowedChange: false,
|
||||
required: false
|
||||
},
|
||||
visible: {
|
||||
type: "boolean",
|
||||
default: true,
|
||||
allowedChange: true,
|
||||
required: true
|
||||
},
|
||||
chat: {
|
||||
type: "boolean",
|
||||
default: true,
|
||||
allowedChange: true,
|
||||
required: true
|
||||
},
|
||||
owner_id: {
|
||||
type: "string",
|
||||
allowedChange: false,
|
||||
required: false
|
||||
},
|
||||
crownsolo: {
|
||||
type: "boolean",
|
||||
default: false,
|
||||
allowedChange: true,
|
||||
required: true
|
||||
},
|
||||
"no cussing": {
|
||||
type: "boolean",
|
||||
allowedChange: true,
|
||||
required: false
|
||||
},
|
||||
"lyrical notes": {
|
||||
type: "boolean",
|
||||
allowedChange: false,
|
||||
required: false
|
||||
}
|
||||
};
|
||||
|
||||
constructor(set, context) {
|
||||
Object.keys(RoomSettings.allowedProperties).forEach(key => {
|
||||
if (
|
||||
typeof RoomSettings.allowedProperties[key].default !==
|
||||
"undefined"
|
||||
) {
|
||||
if (this[key] !== RoomSettings.allowedProperties[key].default) {
|
||||
this[key] = RoomSettings.allowedProperties[key].default;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Object.keys(RoomSettings.allowedProperties).forEach(key => {
|
||||
if (RoomSettings.allowedProperties[key].required == true) {
|
||||
if (typeof this[key] == "undefined") {
|
||||
this[key] = RoomSettings.allowedProperties[key].default;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (typeof set !== "undefined") {
|
||||
Object.keys(set).forEach(key => {
|
||||
if (typeof set[key] == "undefined") return;
|
||||
if (
|
||||
Object.keys(RoomSettings.allowedProperties).indexOf(key) !==
|
||||
-1
|
||||
) {
|
||||
if (typeof context == "undefined") {
|
||||
this[key] = this.verifyPropertyType(
|
||||
key,
|
||||
set[key],
|
||||
RoomSettings.allowedProperties[key].type
|
||||
);
|
||||
} else {
|
||||
if (context == "user") {
|
||||
if (
|
||||
RoomSettings.allowedProperties[key]
|
||||
.allowedChange
|
||||
) {
|
||||
this[key] = this.verifyPropertyType(
|
||||
key,
|
||||
set[key],
|
||||
RoomSettings.allowedProperties[key].type
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
verifyPropertyType(key, pr, type) {
|
||||
let ret;
|
||||
|
||||
if (typeof RoomSettings.allowedProperties[key] !== "object") return;
|
||||
|
||||
switch (type) {
|
||||
case "color":
|
||||
if (/^#[0-9a-f]{6}$/i.test(pr)) {
|
||||
ret = pr;
|
||||
} else {
|
||||
ret = RoomSettings.allowedProperties[key].default;
|
||||
}
|
||||
break;
|
||||
case "color2":
|
||||
if (/^#[0-9a-f]{6}$/i.test(pr)) {
|
||||
ret = pr;
|
||||
} else {
|
||||
ret = RoomSettings.allowedProperties[key].default;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (typeof pr == type) {
|
||||
ret = pr;
|
||||
} else if (
|
||||
typeof RoomSettings.allowedProperties[key].default !==
|
||||
"undefined"
|
||||
) {
|
||||
ret = RoomSettings.allowedProperties[key].default;
|
||||
} else {
|
||||
ret = undefined;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
changeSettings(set) {
|
||||
Object.keys(set).forEach(key => {
|
||||
if (RoomSettings.allowedProperties[key].allowedChange) {
|
||||
this[key] = this.verifyPropertyType(
|
||||
key,
|
||||
set[key],
|
||||
RoomSettings.allowedProperties[key].type
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static changeSettings(set, admin) {
|
||||
Object.keys(set).forEach(key => {
|
||||
if (
|
||||
RoomSettings.allowedProperties[key].allowedChange ||
|
||||
admin == true
|
||||
) {
|
||||
set[key] = RoomSettings.verifyPropertyType(
|
||||
key,
|
||||
set[key],
|
||||
RoomSettings.allowedProperties[key].type
|
||||
);
|
||||
}
|
||||
});
|
||||
return set;
|
||||
}
|
||||
|
||||
static verifyPropertyType(key, pr, type) {
|
||||
let ret;
|
||||
|
||||
if (typeof RoomSettings.allowedProperties[key] !== "object") return;
|
||||
|
||||
switch (type) {
|
||||
case "color":
|
||||
if (/^#[0-9a-f]{6}$/i.test(pr)) {
|
||||
ret = pr;
|
||||
} else {
|
||||
ret = RoomSettings.allowedProperties[key].default;
|
||||
}
|
||||
break;
|
||||
case "color2":
|
||||
if (/^#[0-9a-f]{6}$/i.test(pr)) {
|
||||
ret = pr;
|
||||
} else {
|
||||
ret = RoomSettings.allowedProperties[key].default;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (typeof pr == type) {
|
||||
ret = pr;
|
||||
} else if (
|
||||
typeof RoomSettings.allowedProperties[key].default !==
|
||||
"undefined"
|
||||
) {
|
||||
ret = RoomSettings.allowedProperties[key].default;
|
||||
} else {
|
||||
ret = undefined;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = RoomSettings;
|
230
oldsrc/Server.js
230
oldsrc/Server.js
|
@ -1,230 +0,0 @@
|
|||
const Client = require("./Client.js");
|
||||
const banned = require("../banned.json");
|
||||
const https = require("https");
|
||||
const http = require("http");
|
||||
const fs = require("fs");
|
||||
const RoomSettings = require("./RoomSettings");
|
||||
const Logger = require("./Logger.js");
|
||||
const Notification = require("./Notification");
|
||||
const Database = require("./Database.js");
|
||||
|
||||
class Server {
|
||||
static on = EventEmitter.prototype.on;
|
||||
static off = EventEmitter.prototype.off;
|
||||
static emit = EventEmitter.prototype.emit;
|
||||
static once = EventEmitter.prototype.once;
|
||||
|
||||
static startTime = Date.now();
|
||||
|
||||
static start(config) {
|
||||
// super();
|
||||
// EventEmitter.call(this);
|
||||
|
||||
this.logger = new Logger("Server");
|
||||
|
||||
if (config.ssl == "true") {
|
||||
this.https_server = https.createServer({
|
||||
key: fs.readFileSync("ssl/privkey.pem", "utf8"),
|
||||
cert: fs.readFileSync("ssl/cert.pem"),
|
||||
ca: fs.readFileSync("ssl/chain.pem")
|
||||
});
|
||||
|
||||
this.wss = new WebSocket.Server({
|
||||
server: this.https_server,
|
||||
backlog: 100,
|
||||
verifyClient: info => {
|
||||
const ip = info.req.connection.remoteAddress.replace(
|
||||
"::ffff:",
|
||||
""
|
||||
);
|
||||
if (
|
||||
!ip.match(
|
||||
/^((25[0-5]|(2[0-4]|1\d|[1-9]|)\d)\.){3}(25[0-5]|(2[0-4]|1\d|[1-9]|)\d)$/gi
|
||||
)
|
||||
)
|
||||
return false;
|
||||
if (banned.includes(ip)) return false;
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
this.https_server.listen(config.port, "0.0.0.0");
|
||||
} else {
|
||||
this.wss = new WebSocket.Server({
|
||||
port: config.port,
|
||||
backlog: 100,
|
||||
verifyClient: info => {
|
||||
const ip = info.req.connection.remoteAddress.replace(
|
||||
"::ffff:",
|
||||
""
|
||||
);
|
||||
if (banned.includes(ip)) return false;
|
||||
if (Database.isIPBanned(ip)) return false;
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
this.defaultUsername = config.defaultUsername;
|
||||
this.defaultRoomSettings = new RoomSettings(config.defaultRoomSettings);
|
||||
|
||||
this.lobbySettings = new RoomSettings(config.defaultRoomSettings);
|
||||
this.lobbySettings.lobby = true;
|
||||
this.lobbySettings.color = config.defaultLobbyColor || "#9900ff";
|
||||
this.lobbySettings.color2 = config.defaultLobbyColor2 || "#9900ff";
|
||||
|
||||
this.logger.log(`Server started on port ${config.port}`);
|
||||
this.connectionid = 0;
|
||||
this.connections = new Map();
|
||||
this.roomlisteners = new Map();
|
||||
this.channels = new Map();
|
||||
this.cycle = require("./cycle");
|
||||
|
||||
this.specialIntervals = {};
|
||||
|
||||
this.wss.on("connection", (ws, req) => {
|
||||
// console.log("socket connected");
|
||||
this.connections.set(
|
||||
++this.connectionid,
|
||||
new Client(ws, req, this)
|
||||
);
|
||||
});
|
||||
|
||||
this.legit_m = [
|
||||
"a",
|
||||
"bye",
|
||||
"hi",
|
||||
"ch",
|
||||
"+ls",
|
||||
"-ls",
|
||||
"m",
|
||||
"n",
|
||||
"devices",
|
||||
"t",
|
||||
"chset",
|
||||
"userset",
|
||||
"chown",
|
||||
"kickban",
|
||||
"unban",
|
||||
"admin message",
|
||||
"color",
|
||||
"eval",
|
||||
"notification",
|
||||
"user_flag",
|
||||
"room_flag",
|
||||
"clear_chat",
|
||||
"sudo",
|
||||
"subscribe to admin stream",
|
||||
"unsubscribe from admin stream",
|
||||
"data",
|
||||
"channel message",
|
||||
"channel_flag",
|
||||
"name",
|
||||
"restart",
|
||||
"ipban",
|
||||
"ipunban"
|
||||
];
|
||||
|
||||
// this.welcome_motd = config.motd || "You agree to read this message.";
|
||||
|
||||
this._id_Private_Key = config._id_PrivateKey || "amogus";
|
||||
|
||||
this.adminpass = config.adminpass || "123123sucks";
|
||||
}
|
||||
|
||||
static updateChannelList(channelDataArray) {
|
||||
const listData = [];
|
||||
|
||||
for (let chm of Object.values(channelDataArray)) {
|
||||
if (!chm.ch.settings.visible) return;
|
||||
listData.push(chm.ch);
|
||||
}
|
||||
|
||||
for (let cl of Array.from(this.roomlisteners.values())) {
|
||||
if (cl.destroied) {
|
||||
cl = undefined;
|
||||
return;
|
||||
}
|
||||
|
||||
for (const ch of Object.values(listData)) {
|
||||
const c = this.channels.get(ch._id);
|
||||
if (!c) continue;
|
||||
ch.banned = typeof c.bans.get(cl.user._id) !== "undefined";
|
||||
}
|
||||
|
||||
cl.sendArray([
|
||||
{
|
||||
m: "ls",
|
||||
c: false,
|
||||
u: listData
|
||||
}
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
static ev(str) {
|
||||
let out = "";
|
||||
try {
|
||||
out = eval(str);
|
||||
} catch (err) {
|
||||
out = err;
|
||||
}
|
||||
// console.log(out);
|
||||
return `(${typeof out}) ${out}`;
|
||||
}
|
||||
|
||||
static getClient(id) {
|
||||
return this.connections.get(id);
|
||||
}
|
||||
|
||||
static getClientByParticipantID(id) {
|
||||
for (let cl of Array.from(this.connections.values())) {
|
||||
if (cl.participantID == id) return cl;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static getAllClientsByUserID(_id) {
|
||||
let out = [];
|
||||
for (let cl of Array.from(this.connections.values())) {
|
||||
if (cl.user._id == _id) out.push(cl);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
static restart(
|
||||
notif = {
|
||||
m: "notification",
|
||||
id: "server-restart",
|
||||
title: "Notice",
|
||||
text: "The server will restart in a few moments.",
|
||||
target: "#piano",
|
||||
duration: 20000,
|
||||
class: "classic",
|
||||
targetChannel: "all"
|
||||
}
|
||||
) {
|
||||
let n = new Notification(this, notif);
|
||||
n.send();
|
||||
|
||||
setTimeout(() => {
|
||||
process.exit();
|
||||
}, n.duration || 20000);
|
||||
}
|
||||
|
||||
static banIP(ip) {
|
||||
Database.addIPBan(ip);
|
||||
|
||||
for (const cl of this.connections.values()) {
|
||||
if (cl.ip == ip) {
|
||||
cl.destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static unbanIP(ip) {
|
||||
Database.removeIPBan(ip);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Server;
|
131
oldsrc/User.js
131
oldsrc/User.js
|
@ -1,131 +0,0 @@
|
|||
const Database = require("./Database");
|
||||
const { Cow } = require("./Cow");
|
||||
|
||||
function hslToHex(h, s, l) {
|
||||
l /= 100;
|
||||
const a = (s * Math.min(l, 1 - l)) / 100;
|
||||
const f = n => {
|
||||
const k = (n + h / 30) % 12;
|
||||
const color = l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1);
|
||||
return Math.round(255 * color)
|
||||
.toString(16)
|
||||
.padStart(2, "0");
|
||||
};
|
||||
return `#${f(0)}${f(8)}${f(4)}`;
|
||||
}
|
||||
|
||||
class User {
|
||||
constructor(cl, data) {
|
||||
this.name = data.name;
|
||||
this.cl = cl;
|
||||
this._id = data._id;
|
||||
this.color = data.color;
|
||||
this.flags =
|
||||
typeof data.flags == "object"
|
||||
? data.flags
|
||||
: {
|
||||
volume: 100,
|
||||
"no chat rate limit": false,
|
||||
freeze_name: false
|
||||
};
|
||||
|
||||
this.inventory = {};
|
||||
}
|
||||
|
||||
getPublicUser() {
|
||||
let t = {};
|
||||
t.name = this.name;
|
||||
t.color = this.color;
|
||||
t._id = this._id;
|
||||
return t;
|
||||
}
|
||||
|
||||
checkFlags() {
|
||||
if (typeof this.cl.server.specialIntervals[this._id] == "undefined") {
|
||||
this.cl.server.specialIntervals[this._id] = {};
|
||||
}
|
||||
|
||||
if (this.hasFlag("rainbow", true)) {
|
||||
if (
|
||||
!this.cl.server.specialIntervals[this._id].hasOwnProperty(
|
||||
"rainbow"
|
||||
)
|
||||
) {
|
||||
let h = Math.floor(Math.random() * 360);
|
||||
let s = 50;
|
||||
let l = 50;
|
||||
|
||||
let hvel = 5;
|
||||
let svel = 1;
|
||||
let lvel = 0.5;
|
||||
|
||||
this.cl.server.specialIntervals[this._id].rainbow = setInterval(
|
||||
() => {
|
||||
hvel = Math.floor(Math.random() * 10);
|
||||
h += hvel;
|
||||
if (h > 360) h = 0;
|
||||
|
||||
s += svel;
|
||||
if (s >= 100 || s <= 50) {
|
||||
svel = -svel;
|
||||
}
|
||||
|
||||
l += lvel;
|
||||
if (l >= 75 || l <= 25) {
|
||||
lvel = -lvel;
|
||||
}
|
||||
|
||||
this.color = hslToHex(h, s, l);
|
||||
// Database.updateUser(this._id, this);
|
||||
|
||||
// this.cl.channel.updateParticipant(this._id, this);
|
||||
for (const ch of this.cl.server.channels.values()) {
|
||||
if (ch.hasUser(this.cl.id)) {
|
||||
ch.updateParticipant(this._id, this);
|
||||
}
|
||||
}
|
||||
},
|
||||
1000 / 15
|
||||
);
|
||||
}
|
||||
} else if (this.hasFlag("rainbow", false)) {
|
||||
this.stopFlagEvents();
|
||||
}
|
||||
}
|
||||
|
||||
stopFlagEvents() {
|
||||
let ints = this.cl.server.specialIntervals[this._id];
|
||||
if (!ints) {
|
||||
this.cl.server.specialIntervals[this._id] = {};
|
||||
ints = this.cl.server.specialIntervals[this._id];
|
||||
}
|
||||
if ("rainbow" in ints) {
|
||||
clearInterval(this.cl.server.specialIntervals[this._id].rainbow);
|
||||
delete this.cl.server.specialIntervals[this._id].rainbow;
|
||||
}
|
||||
}
|
||||
|
||||
hasFlag(flag, val) {
|
||||
if (!val) return this.flags.hasOwnProperty(flag);
|
||||
return this.flags.hasOwnProperty(flag) && this.flags[flag] == val;
|
||||
}
|
||||
|
||||
setFlag(flag, val) {
|
||||
if (typeof this.flags[flag] == "undefined") {
|
||||
this.flags[flag] = val;
|
||||
}
|
||||
}
|
||||
|
||||
static updateUserModel(cl, user) {
|
||||
let u2 = new User(cl, user);
|
||||
if (typeof u2 == "undefined") return;
|
||||
|
||||
for (let id in Object.keys(u2)) {
|
||||
if (!user.hasOwnProperty(id)) {
|
||||
user[id] = u2[id];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = User;
|
|
@ -1,8 +0,0 @@
|
|||
const mongoose = require('mongoose');
|
||||
|
||||
module.exports = mongoose.model('User', {
|
||||
name: String,
|
||||
_id: String,
|
||||
color: String,
|
||||
flags: Object
|
||||
});
|
|
@ -1,37 +0,0 @@
|
|||
const Database = require("./Database");
|
||||
|
||||
module.exports = class Cycle {
|
||||
static startOfDay = 0;
|
||||
static time = this.startOfDay;
|
||||
static endOfDay = 24;
|
||||
|
||||
static cycleInterval = setInterval(() => {
|
||||
try {
|
||||
this.time = Database.utilGet("time");
|
||||
} catch (err) {
|
||||
this.time = 0;
|
||||
}
|
||||
|
||||
this.time++;
|
||||
|
||||
if (this.time > this.endOfDay) {
|
||||
this.time = this.startOfDay;
|
||||
}
|
||||
|
||||
Database.utilSet("time", this.time);
|
||||
}, 60 * 1000);
|
||||
|
||||
static getCurrentTime() {
|
||||
return this.time;
|
||||
}
|
||||
|
||||
static getCurrentGenericTime() {
|
||||
if (this.time < 2) return "late night";
|
||||
if (this.time < 6) return "dawn";
|
||||
if (this.time < 12) return "morning";
|
||||
if (this.time < 14) return "day";
|
||||
if (this.time < 18) return "evening";
|
||||
if (this.time < 20) return "dusk";
|
||||
return "night";
|
||||
}
|
||||
};
|
|
@ -1,131 +0,0 @@
|
|||
// var Client = require("../multiplayerpiano/static/Client.js");
|
||||
const Client = require("../../mpp.hri7566.info/Client.js");
|
||||
var level = require("level");
|
||||
var fs = require("fs");
|
||||
var crypto = require("crypto");
|
||||
|
||||
process.stdout.write(
|
||||
"\n********************************START********************************\n"
|
||||
);
|
||||
|
||||
// var client = new Client("wss://www.multiplayerpiano.com");
|
||||
var client = new Client("wss://mpp.hri7566.info:8443");
|
||||
// var client = new Client("ws://127.0.0.1:8443");
|
||||
client.on("connect", function () {
|
||||
console.log("connected");
|
||||
});
|
||||
client.on("hi", function () {
|
||||
console.log("hi");
|
||||
fs.readFile("./password.txt", function (err, data) {
|
||||
if (err) throw err;
|
||||
var password = new String(data).trim();
|
||||
|
||||
client.sendArray([
|
||||
{
|
||||
m: "subscribe to admin stream",
|
||||
password: password,
|
||||
interval_ms: 10000000
|
||||
}
|
||||
]);
|
||||
|
||||
var BATTLE_CHANNEL = "test/:)";
|
||||
var BATTLE_DURATION = 7000;
|
||||
|
||||
function spoop_text(message) {
|
||||
var old = message;
|
||||
message = "";
|
||||
for (var i = 0; i < old.length; i++) {
|
||||
if (Math.random() < 0.9) {
|
||||
message += String.fromCharCode(
|
||||
old.charCodeAt(i) + Math.floor(Math.random() * 20 - 10)
|
||||
);
|
||||
//message[i] = String.fromCharCode(Math.floor(Math.random() * 255));
|
||||
} else {
|
||||
message += old[i];
|
||||
}
|
||||
}
|
||||
return message;
|
||||
}
|
||||
|
||||
client.on("data", function (msg) {
|
||||
console.log("data");
|
||||
for (var i = 0; i < msg.channelManager.channels.length; i++) {
|
||||
var channel = msg.channelManager.channels[i];
|
||||
if (channel._id == BATTLE_CHANNEL) {
|
||||
console.log("sending messages");
|
||||
client.sendArray([
|
||||
{
|
||||
m: "admin message",
|
||||
password: password,
|
||||
msg: {
|
||||
m: "notification",
|
||||
id: "ebbattle",
|
||||
targetChannel: client.channel._id,
|
||||
duration: "7000",
|
||||
class: "short",
|
||||
html: `<p></p>`
|
||||
}
|
||||
}
|
||||
]);
|
||||
|
||||
setTimeout(() => {
|
||||
client.sendArray([
|
||||
{
|
||||
m: "admin message",
|
||||
password: password,
|
||||
msg: {
|
||||
m: "notification",
|
||||
id: "ebbattle",
|
||||
targetChannel: client.channel._id,
|
||||
duration: "7000",
|
||||
class: "short",
|
||||
html:
|
||||
`<script>` +
|
||||
stop.toString() +
|
||||
`</script>`
|
||||
}
|
||||
}
|
||||
]);
|
||||
}, BATTLE_DURATION);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function start() {
|
||||
var ebcanv = `<canvas id="ebbattle" style="
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
image-rendering: pixelated;
|
||||
">`;
|
||||
$("body").append(ebcanv);
|
||||
|
||||
/*
|
||||
var canvas = document.getElementById("ebbattle");
|
||||
var ctx = canvas.getContext("2d");
|
||||
*/
|
||||
|
||||
globalThis.params = {
|
||||
layer1: 182,
|
||||
layer2: 181
|
||||
};
|
||||
|
||||
var ebbattlescript = document.createElement("script");
|
||||
ebbattlescript.src = "ebbattle/index.js";
|
||||
ebbattlescript.type = "module";
|
||||
ebbattlescript.module = true;
|
||||
console.log(ebbattlescript);
|
||||
$("head").append(ebbattlescript);
|
||||
}
|
||||
|
||||
client.start();
|
||||
|
||||
function stop() {
|
||||
window.location.reload();
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,192 +0,0 @@
|
|||
// var Client = require("../multiplayerpiano/static/Client.js");
|
||||
const Client = require("../../mpp.hri7566.info/Client.js");
|
||||
var level = require("level");
|
||||
var fs = require("fs");
|
||||
var crypto = require("crypto");
|
||||
|
||||
process.stdout.write(
|
||||
"\n********************************START********************************\n"
|
||||
);
|
||||
|
||||
// var client = new Client("wss://www.multiplayerpiano.com");
|
||||
var client = new Client("wss://mpp.hri7566.info:8443");
|
||||
client.start();
|
||||
client.on("connect", function () {
|
||||
console.log("connected");
|
||||
});
|
||||
client.on("hi", function () {
|
||||
fs.readFile("./password.txt", function (err, data) {
|
||||
if (err) throw err;
|
||||
var password = new String(data).trim();
|
||||
|
||||
client.sendArray([
|
||||
{
|
||||
m: "subscribe to admin stream",
|
||||
password: password,
|
||||
interval_ms: 10000000
|
||||
}
|
||||
]);
|
||||
|
||||
var SPOOP_CHANNEL = "test/:)";
|
||||
var SPOOP_DURATION = 7000;
|
||||
|
||||
function spoop_text(message) {
|
||||
var old = message;
|
||||
message = "";
|
||||
for (var i = 0; i < old.length; i++) {
|
||||
if (Math.random() < 0.9) {
|
||||
message += String.fromCharCode(
|
||||
old.charCodeAt(i) + Math.floor(Math.random() * 20 - 10)
|
||||
);
|
||||
//message[i] = String.fromCharCode(Math.floor(Math.random() * 255));
|
||||
} else {
|
||||
message += old[i];
|
||||
}
|
||||
}
|
||||
return message;
|
||||
}
|
||||
|
||||
client.on("data", function (msg) {
|
||||
console.log("data");
|
||||
for (var i = 0; i < msg.channelManager.channels.length; i++) {
|
||||
var channel = msg.channelManager.channels[i];
|
||||
if (1) {
|
||||
//if(channel._id === SPOOP_CHANNEL) {
|
||||
var participants = channel.participants;
|
||||
var users = {};
|
||||
for (var j = 0; j < participants.length; j++) {
|
||||
var part = participants[j];
|
||||
users[part.user._id] = part.user;
|
||||
}
|
||||
for (var j in users) {
|
||||
client.sendArray([
|
||||
{
|
||||
m: "admin message",
|
||||
password: password,
|
||||
msg: {
|
||||
m: "name",
|
||||
_id: users[j]._id,
|
||||
name: spoop_text(users[j].name)
|
||||
}
|
||||
}
|
||||
]);
|
||||
client.sendArray([
|
||||
{
|
||||
m: "admin message",
|
||||
password: password,
|
||||
msg: {
|
||||
m: "color",
|
||||
_id: users[j]._id,
|
||||
color: "#000000"
|
||||
}
|
||||
}
|
||||
]);
|
||||
client.sendArray([
|
||||
{
|
||||
m: "admin message",
|
||||
password: password,
|
||||
msg: {
|
||||
m: "user_flag",
|
||||
_id: users[j]._id,
|
||||
key: "chat_curse_1",
|
||||
value: 1
|
||||
}
|
||||
}
|
||||
]);
|
||||
client.sendArray([
|
||||
{
|
||||
m: "admin message",
|
||||
password: password,
|
||||
msg: {
|
||||
m: "user_flag",
|
||||
_id: users[j]._id,
|
||||
key: "chat_curse_2",
|
||||
value: 1
|
||||
}
|
||||
}
|
||||
]);
|
||||
client.sendArray([
|
||||
{
|
||||
m: "admin message",
|
||||
password: password,
|
||||
msg: {
|
||||
m: "user_flag",
|
||||
_id: users[j]._id,
|
||||
key: "freeze_name",
|
||||
value: 1
|
||||
}
|
||||
}
|
||||
]);
|
||||
/*client.sendArray([{m: "admin message", password: password,
|
||||
msg: {"m": "notification", "class":"short","targetChannel":SPOOP_CHANNEL,"html":"<style>.cursor{width:100000px;height:100000px;margin-left:-50000px;margin-top:-50000px}</style>","duration":SPOOP_DURATION}}]);*/
|
||||
}
|
||||
setTimeout(function () {
|
||||
for (var j in users) {
|
||||
client.sendArray([
|
||||
{
|
||||
m: "admin message",
|
||||
password: password,
|
||||
msg: {
|
||||
m: "name",
|
||||
_id: users[j]._id,
|
||||
name: users[j].name
|
||||
}
|
||||
}
|
||||
]);
|
||||
client.sendArray([
|
||||
{
|
||||
m: "admin message",
|
||||
password: password,
|
||||
msg: {
|
||||
m: "color",
|
||||
_id: users[j]._id,
|
||||
color: users[j].color
|
||||
}
|
||||
}
|
||||
]);
|
||||
client.sendArray([
|
||||
{
|
||||
m: "admin message",
|
||||
password: password,
|
||||
msg: {
|
||||
m: "user_flag",
|
||||
_id: users[j]._id,
|
||||
key: "chat_curse_1",
|
||||
value: 0
|
||||
}
|
||||
}
|
||||
]);
|
||||
client.sendArray([
|
||||
{
|
||||
m: "admin message",
|
||||
password: password,
|
||||
msg: {
|
||||
m: "user_flag",
|
||||
_id: users[j]._id,
|
||||
key: "chat_curse_2",
|
||||
value: 0
|
||||
}
|
||||
}
|
||||
]);
|
||||
client.sendArray([
|
||||
{
|
||||
m: "admin message",
|
||||
password: password,
|
||||
msg: {
|
||||
m: "user_flag",
|
||||
_id: users[j]._id,
|
||||
key: "freeze_name",
|
||||
value: 0
|
||||
}
|
||||
}
|
||||
]);
|
||||
}
|
||||
setTimeout(function () {
|
||||
process.exit();
|
||||
}, 1000);
|
||||
}, SPOOP_DURATION);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,3 +1,4 @@
|
|||
export class Gateway {
|
||||
public hasProcessedHi: boolean = false;
|
||||
public hasSentDevices: boolean = false;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import { createColor, createID, createUserID } from "../util/id";
|
||||
import { decoder, encoder } from "../util/helpers";
|
||||
import EventEmitter from "events";
|
||||
import {
|
||||
ChannelInfo,
|
||||
|
@ -15,8 +14,12 @@ import { loadConfig } from "../util/config";
|
|||
import { Gateway } from "./Gateway";
|
||||
import { Channel, channelList } from "../channel/Channel";
|
||||
import { ServerWebSocket } from "bun";
|
||||
import { findSocketByUserID, socketsBySocketID } from "./server";
|
||||
import { socketsBySocketID } from "./server";
|
||||
import { Logger } from "../util/Logger";
|
||||
import { RateLimitConstructorList, RateLimitList } from "./ratelimit/config";
|
||||
import { adminLimits } from "./ratelimit/limits/admin";
|
||||
import { userLimits } from "./ratelimit/limits/user";
|
||||
import { NoteQuota } from "./ratelimit/NoteQuota";
|
||||
|
||||
interface UsersConfig {
|
||||
defaultName: string;
|
||||
|
@ -42,6 +45,9 @@ export class Socket extends EventEmitter {
|
|||
|
||||
public gateway = new Gateway();
|
||||
|
||||
public rateLimits: RateLimitList | undefined;
|
||||
public noteQuota = new NoteQuota(this.onQuota);
|
||||
|
||||
public desiredChannel: {
|
||||
_id: string | undefined;
|
||||
set: Partial<ChannelSettings> | undefined;
|
||||
|
@ -88,6 +94,12 @@ export class Socket extends EventEmitter {
|
|||
}
|
||||
|
||||
this.loadUser();
|
||||
|
||||
// TODO Permissions
|
||||
let isAdmin = false;
|
||||
|
||||
this.setRateLimits(isAdmin ? adminLimits : userLimits);
|
||||
|
||||
this.bindEventListeners();
|
||||
}
|
||||
|
||||
|
@ -330,4 +342,31 @@ export class Socket extends EventEmitter {
|
|||
]);
|
||||
}
|
||||
}
|
||||
|
||||
public setRateLimits(list: RateLimitConstructorList) {
|
||||
this.rateLimits = {
|
||||
normal: {},
|
||||
chains: {}
|
||||
} as RateLimitList;
|
||||
|
||||
for (const key of Object.keys(list.normal)) {
|
||||
(this.rateLimits.normal as any)[key] = (list.normal as any)[key]();
|
||||
}
|
||||
|
||||
for (const key of Object.keys(list.chains)) {
|
||||
(this.rateLimits.chains as any)[key] = (list.chains as any)[key]();
|
||||
}
|
||||
|
||||
// Send note quota
|
||||
this.sendArray([
|
||||
{
|
||||
m: "nq",
|
||||
allowance: this.noteQuota.allowance,
|
||||
max: this.noteQuota.max,
|
||||
maxHistLen: this.noteQuota.maxHistLen
|
||||
}
|
||||
]);
|
||||
}
|
||||
|
||||
public onQuota(points: number) {}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,8 @@ import { ServerEventListener } from "../../../../util/types";
|
|||
export const a: ServerEventListener<"a"> = {
|
||||
id: "a",
|
||||
callback: (msg, socket) => {
|
||||
// Send chat message
|
||||
// Chat message
|
||||
if (!socket.rateLimits?.normal.a.attempt()) return;
|
||||
const ch = socket.getCurrentChannel();
|
||||
if (!ch) return;
|
||||
|
||||
|
|
|
@ -3,6 +3,8 @@ import { ServerEventListener } from "../../../../util/types";
|
|||
export const devices: ServerEventListener<"devices"> = {
|
||||
id: "devices",
|
||||
callback: (msg, socket) => {
|
||||
// List of MIDI Devices
|
||||
if (socket.gateway.hasSentDevices) return;
|
||||
socket.gateway.hasSentDevices = true;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -3,7 +3,9 @@ import { ServerEventListener } from "../../../../util/types";
|
|||
export const hi: ServerEventListener<"hi"> = {
|
||||
id: "hi",
|
||||
callback: (msg, socket) => {
|
||||
// Handshake message
|
||||
// TODO Hi message tokens
|
||||
if (socket.gateway.hasProcessedHi) return;
|
||||
let part = socket.getParticipant();
|
||||
|
||||
if (!part) {
|
||||
|
@ -28,5 +30,7 @@ export const hi: ServerEventListener<"hi"> = {
|
|||
}
|
||||
}
|
||||
]);
|
||||
|
||||
socket.gateway.hasProcessedHi = true;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -3,6 +3,8 @@ import { ServerEventListener } from "../../../../util/types";
|
|||
export const m: ServerEventListener<"m"> = {
|
||||
id: "m",
|
||||
callback: (msg, socket) => {
|
||||
// Cursor movement
|
||||
if (!socket.rateLimits?.normal.m.attempt()) return;
|
||||
if (!msg.x || !msg.y) return;
|
||||
socket.setCursorPos(msg.x, msg.y);
|
||||
}
|
||||
|
|
|
@ -4,6 +4,8 @@ export const userset: ServerEventListener<"userset"> = {
|
|||
id: "userset",
|
||||
callback: (msg, socket) => {
|
||||
// Change username/color
|
||||
if (!socket.rateLimits?.chains.userset.attempt()) return;
|
||||
if (!msg.set.name && !msg.set.color) return;
|
||||
socket.userset(msg.set.name, msg.set.color);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -0,0 +1,105 @@
|
|||
export class NoteQuota {
|
||||
public allowance = 8000;
|
||||
public max = 24000;
|
||||
public maxHistLen = 3;
|
||||
public points = 24000;
|
||||
public history = new Array<number>();
|
||||
|
||||
public static PARAMS_LOBBY = { allowance: 200, max: 600 };
|
||||
public static PARAMS_NORMAL = { allowance: 400, max: 1200 };
|
||||
public static PARAMS_RIDICULOUS = { allowance: 600, max: 1800 };
|
||||
public static PARAMS_OFFLINE = {
|
||||
allowance: 8000,
|
||||
max: 24000,
|
||||
maxHistLen: 3
|
||||
};
|
||||
|
||||
constructor(public cb: (points: number) => void) {
|
||||
this.setParams();
|
||||
this.resetPoints();
|
||||
}
|
||||
|
||||
public getParams() {
|
||||
return {
|
||||
m: "nq",
|
||||
allowance: this.allowance,
|
||||
max: this.max,
|
||||
maxHistLen: this.maxHistLen
|
||||
};
|
||||
}
|
||||
|
||||
public setParams(
|
||||
params: {
|
||||
allowance: number;
|
||||
max: number;
|
||||
maxHistLen: number;
|
||||
} = NoteQuota.PARAMS_OFFLINE
|
||||
) {
|
||||
let allowance: number =
|
||||
params.allowance ||
|
||||
this.allowance ||
|
||||
NoteQuota.PARAMS_OFFLINE.allowance;
|
||||
let max = params.max || this.max || NoteQuota.PARAMS_OFFLINE.max;
|
||||
let maxHistLen =
|
||||
params.maxHistLen ||
|
||||
this.maxHistLen ||
|
||||
NoteQuota.PARAMS_OFFLINE.maxHistLen;
|
||||
|
||||
if (
|
||||
allowance !== this.allowance ||
|
||||
max !== this.max ||
|
||||
maxHistLen !== this.maxHistLen
|
||||
) {
|
||||
this.allowance = allowance;
|
||||
this.max = max;
|
||||
this.maxHistLen = maxHistLen;
|
||||
|
||||
this.resetPoints();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public resetPoints() {
|
||||
this.points = this.max;
|
||||
this.history = [];
|
||||
|
||||
for (let i = 0; i < this.maxHistLen; i++) {
|
||||
this.history.unshift(this.points);
|
||||
}
|
||||
|
||||
if (this.cb) {
|
||||
this.cb(this.points);
|
||||
}
|
||||
}
|
||||
|
||||
public tick() {
|
||||
this.history.unshift(this.points);
|
||||
this.history.length = this.maxHistLen;
|
||||
|
||||
if (this.points < this.max) {
|
||||
this.points += this.allowance;
|
||||
if (this.points > this.max) this.points = this.max;
|
||||
if (this.cb) this.cb(this.points);
|
||||
}
|
||||
}
|
||||
|
||||
public spend(needed: number) {
|
||||
let sum = 0;
|
||||
|
||||
for (const i in this.history) {
|
||||
sum += this.history[i];
|
||||
}
|
||||
|
||||
if (sum <= 0) needed *= this.allowance;
|
||||
|
||||
if (this.points < needed) {
|
||||
return false;
|
||||
} else {
|
||||
this.points -= needed;
|
||||
if (this.cb) this.cb(this.points);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
export class RateLimit {
|
||||
public after: number = 0;
|
||||
constructor(private interval_ms: number = 0) {}
|
||||
|
||||
public attempt(time: number = Date.now()) {
|
||||
if (time < this.after) return false;
|
||||
|
||||
this.after = time + this.interval_ms;
|
||||
return true;
|
||||
}
|
||||
|
||||
public setInterval(interval_ms: number) {
|
||||
this.after += interval_ms - this.interval_ms;
|
||||
this.interval_ms = interval_ms;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
import { RateLimit } from "./RateLimit";
|
||||
|
||||
export class RateLimitChain {
|
||||
public chain: RateLimit[] = [];
|
||||
|
||||
constructor(num: number, interval_ms: number) {
|
||||
this.setNumAndInterval(num, interval_ms);
|
||||
}
|
||||
|
||||
public attempt(time: number = Date.now()) {
|
||||
for (let i = 0; i < this.chain.length; i++) {
|
||||
if (this.chain[i].attempt(time)) return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public setNumAndInterval(num: number, interval_ms: number) {
|
||||
this.chain = [];
|
||||
|
||||
for (let i = 0; i < num; i++) {
|
||||
this.chain.push(new RateLimit(interval_ms));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
import { loadConfig } from "../../util/config";
|
||||
import { RateLimit } from "./RateLimit";
|
||||
import { RateLimitChain } from "./RateLimitChain";
|
||||
|
||||
export interface RateLimitConfigList<
|
||||
RL = number,
|
||||
RLC = { num: number; interval: number }
|
||||
> {
|
||||
normal: {
|
||||
m: RL;
|
||||
a: RL;
|
||||
};
|
||||
|
||||
chains: {
|
||||
userset: RLC;
|
||||
};
|
||||
}
|
||||
|
||||
export type RateLimitConstructorList = RateLimitConfigList<
|
||||
() => RateLimit,
|
||||
() => RateLimitChain
|
||||
>;
|
||||
|
||||
export type RateLimitList = RateLimitConfigList<RateLimit, RateLimitChain>;
|
||||
|
||||
export interface RateLimitsConfig {
|
||||
user: RateLimitConfigList;
|
||||
crown: RateLimitConfigList;
|
||||
admin: RateLimitConfigList;
|
||||
}
|
||||
|
||||
export const config = loadConfig<RateLimitsConfig>("config/ratelimits.yml", {
|
||||
user: {
|
||||
normal: {
|
||||
a: 6000 / 4,
|
||||
m: 1000 / 20
|
||||
},
|
||||
chains: {
|
||||
userset: {
|
||||
interval: 1000 * 60 * 30,
|
||||
num: 1000
|
||||
}
|
||||
}
|
||||
},
|
||||
crown: {
|
||||
normal: {
|
||||
a: 6000 / 10,
|
||||
m: 1000 / 20
|
||||
},
|
||||
chains: {
|
||||
userset: {
|
||||
interval: 1000 * 60 * 30,
|
||||
num: 1000
|
||||
}
|
||||
}
|
||||
},
|
||||
admin: {
|
||||
normal: {
|
||||
a: 6000 / 50,
|
||||
m: 1000 / 60
|
||||
},
|
||||
chains: {
|
||||
userset: {
|
||||
interval: 1000 * 60 * 30,
|
||||
num: 1000
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
|
@ -0,0 +1,17 @@
|
|||
import { RateLimit } from "../RateLimit";
|
||||
import { RateLimitChain } from "../RateLimitChain";
|
||||
import { RateLimitConstructorList, config } from "../config";
|
||||
|
||||
export const adminLimits: RateLimitConstructorList = {
|
||||
normal: {
|
||||
a: () => new RateLimit(config.admin.normal.a),
|
||||
m: () => new RateLimit(config.admin.normal.m)
|
||||
},
|
||||
chains: {
|
||||
userset: () =>
|
||||
new RateLimitChain(
|
||||
config.admin.chains.userset.interval,
|
||||
config.admin.chains.userset.num
|
||||
)
|
||||
}
|
||||
};
|
|
@ -0,0 +1,17 @@
|
|||
import { RateLimit } from "../RateLimit";
|
||||
import { RateLimitChain } from "../RateLimitChain";
|
||||
import { RateLimitConstructorList, config } from "../config";
|
||||
|
||||
export const crownLimits: RateLimitConstructorList = {
|
||||
normal: {
|
||||
a: () => new RateLimit(config.crown.normal.a),
|
||||
m: () => new RateLimit(config.crown.normal.m)
|
||||
},
|
||||
chains: {
|
||||
userset: () =>
|
||||
new RateLimitChain(
|
||||
config.crown.chains.userset.interval,
|
||||
config.crown.chains.userset.num
|
||||
)
|
||||
}
|
||||
};
|
|
@ -0,0 +1,17 @@
|
|||
import { RateLimit } from "../RateLimit";
|
||||
import { RateLimitChain } from "../RateLimitChain";
|
||||
import { RateLimitConstructorList, config } from "../config";
|
||||
|
||||
export const userLimits: RateLimitConstructorList = {
|
||||
normal: {
|
||||
a: () => new RateLimit(config.user.normal.a),
|
||||
m: () => new RateLimit(config.user.normal.m)
|
||||
},
|
||||
chains: {
|
||||
userset: () =>
|
||||
new RateLimitChain(
|
||||
config.user.chains.userset.interval,
|
||||
config.user.chains.userset.num
|
||||
)
|
||||
}
|
||||
};
|
Loading…
Reference in New Issue