mirror of
https://github.com/ENSL/ensl_gathers.git
synced 2024-11-21 20:21:05 +00:00
Fixes
* use ES Modules * Fix some bugs * add Novice Gather
This commit is contained in:
parent
68cf41c388
commit
ddb6c460ff
56 changed files with 1257 additions and 1951 deletions
|
@ -36,7 +36,7 @@ class SelectPlayerButton extends React.Component {
|
|||
onClick={this.selectPlayer}
|
||||
value={this.props.gatherer.id}
|
||||
className="btn btn-xs btn-primary team-label"> Select
|
||||
</button>;
|
||||
</button>;
|
||||
}
|
||||
return button;
|
||||
}
|
||||
|
@ -87,7 +87,7 @@ class GatherTeams extends React.Component {
|
|||
<div className="panel panel-primary panel-light-background team-marines">
|
||||
<div className="panel-heading">
|
||||
Marines
|
||||
</div>
|
||||
</div>
|
||||
<GathererList gather={this.props.gather} team="marine" />
|
||||
</div>
|
||||
</div>
|
||||
|
@ -95,7 +95,7 @@ class GatherTeams extends React.Component {
|
|||
<div className="panel panel-primary panel-light-background team-aliens">
|
||||
<div className="panel-heading">
|
||||
Aliens
|
||||
</div>
|
||||
</div>
|
||||
<GathererList gather={this.props.gather} team="alien" />
|
||||
</div>
|
||||
</div>
|
||||
|
@ -317,7 +317,7 @@ class CooloffButton extends React.Component {
|
|||
disabled="true"
|
||||
className="btn btn-success">
|
||||
Leaver Cooloff ({this.timeRemaining()})
|
||||
</button>
|
||||
</button>
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -371,15 +371,15 @@ class GatherActions extends React.Component {
|
|||
{gather.pickingPattern.map((team, index) => {
|
||||
if (team === 'alien') {
|
||||
if (index <= pickIndex) {
|
||||
return <li className="padding-y-1"><div className="pick-pattern-box alien-box-active"></div></li>
|
||||
return <li key={index} className="padding-y-1"><div className="pick-pattern-box alien-box-active"></div></li>
|
||||
} else {
|
||||
return <li className="padding-y-1"><div className="pick-pattern-box alien-box"></div></li>
|
||||
return <li key={index} className="padding-y-1"><div className="pick-pattern-box alien-box"></div></li>
|
||||
}
|
||||
} else {
|
||||
if (index <= pickIndex) {
|
||||
return <li className="padding-y-1"><div className="pick-pattern-box marine-box-active"></div></li>
|
||||
return <li key={index} className="padding-y-1"><div className="pick-pattern-box marine-box-active"></div></li>
|
||||
} else {
|
||||
return <li className="padding-y-1"><div className="pick-pattern-box marine-box"></div></li>
|
||||
return <li key={index} className="padding-y-1"><div className="pick-pattern-box marine-box"></div></li>
|
||||
}
|
||||
}
|
||||
})}
|
||||
|
@ -390,15 +390,15 @@ class GatherActions extends React.Component {
|
|||
<div>
|
||||
<div className="text-right">
|
||||
<ul className="list-inline no-bottom content-center">
|
||||
<li>
|
||||
<li key="picking">
|
||||
{pickPatternIndicator}
|
||||
</li>
|
||||
<ul className='list-inline no-bottom'>
|
||||
<li className='padding-right-0'>
|
||||
<li key="join" className='padding-right-0'>
|
||||
<JoinGatherButton gather={gather} thisGatherer={thisGatherer}
|
||||
user={user} socket={socket} />
|
||||
</li>
|
||||
<li className='padding-right-0'>
|
||||
<li key="regather" className='padding-right-0'>
|
||||
{regatherButton}
|
||||
</li>
|
||||
</ul>
|
||||
|
@ -909,8 +909,8 @@ class GathererListItem extends React.Component {
|
|||
value={gatherer.user.id}
|
||||
onClick={this.bootGatherer}>
|
||||
Boot from Gather
|
||||
</button>
|
||||
<AssumeUserIdButton socket={socket}
|
||||
</button>
|
||||
<AssumeUserIdButton socket={socket}
|
||||
gatherer={gatherer} currentUser={user} />
|
||||
</dd>
|
||||
]
|
||||
|
@ -977,7 +977,7 @@ class GathererListItem extends React.Component {
|
|||
<a href={enslUrl(gatherer)}
|
||||
className="btn btn-xs btn-primary"
|
||||
target="_blank">ENSL Profile</a>
|
||||
<a href={obsUrl(gatherer)}
|
||||
<a href={obsUrl(gatherer)}
|
||||
className="btn btn-xs btn-primary"
|
||||
target="_blank">Observatory Profile</a>
|
||||
</dd>
|
||||
|
@ -1145,7 +1145,7 @@ class GatherVotingResults extends React.Component {
|
|||
<div className="panel panel-primary">
|
||||
<div className="panel-heading">
|
||||
Game Information
|
||||
</div>
|
||||
</div>
|
||||
<div className="panel-body">
|
||||
<div className="row">
|
||||
<div className="col-md-4">
|
||||
|
|
|
@ -27,24 +27,19 @@ class InfoButton extends React.Component {
|
|||
dropdown = (
|
||||
<ul className="treeview-menu menu-open" style={{ display: "block" }}>
|
||||
<li>
|
||||
<a href="https://github.com/cblanc/sws_gathers" target="_blank">
|
||||
<a href="https://github.com/ENSL/ensl_gathers" target="_blank">
|
||||
<i className="fa fa-github"> </i> Github
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="http://steamcommunity.com/id/nslgathers" target="_blank">
|
||||
<i className="fa fa-steam-square"> </i> Steam Bot
|
||||
</a>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://www.ensl.org/gatherre" target="_blank">
|
||||
<i className="fa fa-legal"> </i> Gather Rules
|
||||
</a>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/messages" target="_blank">
|
||||
<i className="fa fa-comments"> </i> Message Archive
|
||||
</a>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
);
|
||||
|
|
|
@ -144,10 +144,10 @@ class GatherPage extends React.Component {
|
|||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = this.getInitialState();
|
||||
this.state = this.getInitialState(props);
|
||||
}
|
||||
|
||||
getInitialState = () => {
|
||||
getInitialState = (props) => {
|
||||
let updateTitle = true;
|
||||
let showEventsPanel = true;
|
||||
|
||||
|
@ -175,7 +175,7 @@ class GatherPage extends React.Component {
|
|||
user: null,
|
||||
servers: [],
|
||||
archive: [],
|
||||
socket: null,
|
||||
socket: props.socket,
|
||||
events: [],
|
||||
updateTitle: updateTitle,
|
||||
showEventsPanel: showEventsPanel,
|
||||
|
@ -491,7 +491,7 @@ class GatherPage extends React.Component {
|
|||
<ul className="sidebar-menu">
|
||||
<li className="header">
|
||||
<span className="badge">{this.state.users.length}</span> Players Online
|
||||
</li>
|
||||
</li>
|
||||
</ul>
|
||||
<UserMenu users={this.state.users} user={this.state.user}
|
||||
socket={socket} mountModal={this.mountModal} />
|
||||
|
|
|
@ -185,7 +185,6 @@ class MusicSelector extends React.Component {
|
|||
<label>Music</label>
|
||||
<select
|
||||
className="form-control"
|
||||
defaultValue={this.state.music}
|
||||
onChange={this.setMusic}
|
||||
value={this.state.music}>
|
||||
{options}
|
||||
|
@ -246,14 +245,14 @@ class SoundPanel extends MenubarMixin(React.Component) {
|
|||
mutedButton = <li>
|
||||
<a href="#" onClick={this.unMute}>
|
||||
{mutedIcon} Muted
|
||||
</a>
|
||||
</a>
|
||||
</li>;
|
||||
} else {
|
||||
mutedIcon = <i className="fa fa-volume-up fa-fw"></i>;
|
||||
mutedButton = <li>
|
||||
<a href="#" onClick={this.mute}>
|
||||
{mutedIcon} Unmuted
|
||||
</a>
|
||||
</a>
|
||||
</li>;
|
||||
}
|
||||
return (
|
||||
|
@ -266,12 +265,12 @@ class SoundPanel extends MenubarMixin(React.Component) {
|
|||
<li>
|
||||
<a href='#' onClick={this.play}>
|
||||
<i className="fa fa-play"></i> Play
|
||||
</a>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href='#' onClick={this.stop}>
|
||||
<i className="fa fa-stop"></i> Stop
|
||||
</a>
|
||||
</a>
|
||||
</li>
|
||||
<hr />
|
||||
<li>
|
||||
|
|
|
@ -39,7 +39,7 @@ class UserModal extends React.Component {
|
|||
const currentUser = this.props.currentUser;
|
||||
const user = this.props.user;
|
||||
let hiveStats;
|
||||
if (user.hive.id) {
|
||||
if (user.hive) {
|
||||
hiveStats = [
|
||||
<tr key="stats"><td><strong>Hive Stats</strong></td><td></td></tr>,
|
||||
<tr key="elo">
|
||||
|
@ -86,7 +86,7 @@ class UserModal extends React.Component {
|
|||
className={"flag flag-" + ((user.country === null) ? "eu" :
|
||||
user.country.toLowerCase())}
|
||||
alt={user.country} />
|
||||
{user.username}
|
||||
{user.username}
|
||||
</h4>
|
||||
</div>
|
||||
<div className="modal-body">
|
||||
|
@ -107,7 +107,7 @@ class UserModal extends React.Component {
|
|||
<a href={enslUrl(user)}
|
||||
className="btn btn-xs btn-primary"
|
||||
target="_blank">ENSL Profile</a>
|
||||
<a href={obsUrl({ user: user })}
|
||||
<a href={obsUrl({ user: user })}
|
||||
className="btn btn-xs btn-primary"
|
||||
target="_blank">Observatory Profile</a>
|
||||
</td>
|
||||
|
@ -282,7 +282,7 @@ class ProfileModal extends React.Component {
|
|||
<p className="add-top"><small>
|
||||
Try to give an accurate representation of your skill to raise
|
||||
the quality of your gathers
|
||||
</small></p>
|
||||
</small></p>
|
||||
</div>
|
||||
<hr />
|
||||
<div className="form-group">
|
||||
|
@ -290,12 +290,12 @@ class ProfileModal extends React.Component {
|
|||
{abilitiesForm}
|
||||
<p><small>
|
||||
Specify which lifeforms you'd like to play in the gather
|
||||
</small></p>
|
||||
</small></p>
|
||||
</div>
|
||||
<hr />
|
||||
<p className="small">
|
||||
You will need to rejoin the gather to see your updated profile
|
||||
</p>
|
||||
</p>
|
||||
<div className="form-group">
|
||||
<button
|
||||
type="submit"
|
||||
|
@ -320,7 +320,7 @@ class CurrentUser extends React.Component {
|
|||
<li>
|
||||
<a href="#" data-toggle="modal" data-target="#adminmodal">
|
||||
<i className="fa fa-magic fa-fw"></i> Administration
|
||||
</a>
|
||||
</a>
|
||||
</li>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,49 +0,0 @@
|
|||
"use strict";
|
||||
|
||||
var env = process.env.NODE_ENV || "development";
|
||||
var test = env === "test";
|
||||
|
||||
var fs = require("fs");
|
||||
var path = require("path");
|
||||
|
||||
var baseConfig = require(path.join(__dirname, path.join("environments/" + env.toLowerCase())));
|
||||
|
||||
baseConfig.steamBot = {};
|
||||
baseConfig.discordBot = {};
|
||||
|
||||
if (!test) {
|
||||
if (process.env.PORT) {
|
||||
baseConfig.port = parseInt(process.env.PORT, 10);
|
||||
}
|
||||
|
||||
if (process.env.MONGOLAB_URI) {
|
||||
baseConfig.mongo.uri = process.env.MONGOLAB_URI;
|
||||
}
|
||||
|
||||
if (process.env.RAILS_SECRET) {
|
||||
baseConfig.secret_token = process.env.RAILS_SECRET;
|
||||
}
|
||||
|
||||
if (process.env.GATHER_STEAM_ACCOUNT) {
|
||||
baseConfig.steam.bot.account_name = process.env.GATHER_STEAM_ACCOUNT;
|
||||
}
|
||||
|
||||
if (process.env.GATHER_STEAM_PASSWORD) {
|
||||
baseConfig.steam.bot.password = process.env.GATHER_STEAM_PASSWORD;
|
||||
}
|
||||
|
||||
if (process.env.STEAM_API_KEY) {
|
||||
baseConfig.steam.api_key = process.env.STEAM_API_KEY;
|
||||
}
|
||||
|
||||
if (process.env.GATHER_DISCORD_HOOK_ID) {
|
||||
baseConfig.discordBot.hook_id = process.env.GATHER_DISCORD_HOOK_ID;
|
||||
}
|
||||
|
||||
if (process.env.GATHER_DISCORD_HOOK_TOKEN) {
|
||||
baseConfig.discordBot.hook_token = process.env.GATHER_DISCORD_HOOK_TOKEN;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = baseConfig;
|
24
config/config.mjs
Normal file
24
config/config.mjs
Normal file
|
@ -0,0 +1,24 @@
|
|||
var env = process.env.NODE_ENV || "development";
|
||||
var test = env === "test";
|
||||
|
||||
var config = (await import(`./environments/${env.toLowerCase()}.mjs`)).default;
|
||||
|
||||
if (!test) {
|
||||
if (process.env.PORT) {
|
||||
config.port = parseInt(process.env.PORT, 10);
|
||||
}
|
||||
|
||||
if (process.env.MONGOLAB_URI) {
|
||||
config.mongo.uri = process.env.MONGOLAB_URI;
|
||||
}
|
||||
|
||||
if (process.env.RAILS_SECRET) {
|
||||
config.secret_token = process.env.RAILS_SECRET;
|
||||
}
|
||||
|
||||
if (process.env.STEAM_API_KEY) {
|
||||
config.steam.api_key = process.env.STEAM_API_KEY;
|
||||
}
|
||||
}
|
||||
|
||||
export default config;
|
|
@ -1,22 +0,0 @@
|
|||
"use strict";
|
||||
|
||||
var config = {
|
||||
port: 8000,
|
||||
mongo: {
|
||||
uri: "mongodb://db/swsgather_development"
|
||||
},
|
||||
secret_token: "",
|
||||
session_store_name: "_ENSL_session_key",
|
||||
ensl_url: "http://www.ensl.org/",
|
||||
ensl_rules_url: "http://www.ensl.org/articles/464",
|
||||
steam: {
|
||||
bot: {
|
||||
link: "http://steamcommunity.com/id/nslgathers",
|
||||
account_name: '',
|
||||
password: '',
|
||||
},
|
||||
api_key: '',
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = config;
|
15
config/environments/development.mjs
Normal file
15
config/environments/development.mjs
Normal file
|
@ -0,0 +1,15 @@
|
|||
var config = {
|
||||
port: 8000,
|
||||
mongo: {
|
||||
uri: "mongodb://db/swsgather_development"
|
||||
},
|
||||
secret_token: "",
|
||||
session_store_name: "_ENSL_session_key",
|
||||
ensl_url: "https://www.ensl.org",
|
||||
ensl_rules_url: "https://www.ensl.org/articles/464",
|
||||
steam: {
|
||||
api_key: '',
|
||||
}
|
||||
};
|
||||
|
||||
export default config;
|
|
@ -1,5 +1,3 @@
|
|||
"use strict";
|
||||
|
||||
var config = {
|
||||
port: 80,
|
||||
mongo: {
|
||||
|
@ -7,16 +5,11 @@ var config = {
|
|||
},
|
||||
secret_token: "",
|
||||
session_store_name: "_ENSL_session_key",
|
||||
ensl_url: "https://www.ensl.org/",
|
||||
ensl_url: "https://www.ensl.org",
|
||||
ensl_rules_url: "https://www.ensl.org/articles/464",
|
||||
steam: {
|
||||
bot: {
|
||||
link: "http://steamcommunity.com/id/nslgathers",
|
||||
account_name: '',
|
||||
password: '',
|
||||
},
|
||||
api_key: '',
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = config;
|
||||
export default config;
|
|
@ -1,5 +1,3 @@
|
|||
"use strict";
|
||||
|
||||
var config = {
|
||||
port: 80,
|
||||
mongo: {
|
||||
|
@ -7,16 +5,11 @@ var config = {
|
|||
},
|
||||
secret_token: "",
|
||||
session_store_name: "_ENSL_session_key_staging",
|
||||
ensl_url: "http://staging.ensl.org/",
|
||||
ensl_url: "http://staging.ensl.org",
|
||||
ensl_rules_url: "http://www.ensl.org/articles/464",
|
||||
steam: {
|
||||
bot: {
|
||||
link: "http://steamcommunity.com/id/nslgathers",
|
||||
account_name: '',
|
||||
password: '',
|
||||
},
|
||||
api_key: '',
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = config;
|
||||
export default config;
|
|
@ -1,5 +1,3 @@
|
|||
"use strict";
|
||||
|
||||
var config = {
|
||||
port: 9000,
|
||||
mongo: {
|
||||
|
@ -8,15 +6,10 @@ var config = {
|
|||
secret_token: "SUPERSECRETFOO",
|
||||
session_store_name: "_ENSL_session_key_staging",
|
||||
ensl_rules_url: "http://www.ensl.org/articles/464",
|
||||
ensl_url: "http://staging.ensl.org/",
|
||||
ensl_url: "http://staging.ensl.org",
|
||||
steam: {
|
||||
bot: {
|
||||
link: "http://steamcommunity.com/id/nslgathers",
|
||||
account_name: '',
|
||||
password: '',
|
||||
},
|
||||
api_key: '',
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = config;
|
||||
export default config;
|
|
@ -1,54 +0,0 @@
|
|||
"use strict";
|
||||
|
||||
var fs = require("fs");
|
||||
var path = require("path");
|
||||
var morgan = require("morgan");
|
||||
var express = require("express");
|
||||
var winston = require("winston");
|
||||
var config = require("./config.js");
|
||||
var favicon = require("serve-favicon");
|
||||
var exphbs = require("express-handlebars").engine;
|
||||
var cookieParser = require("cookie-parser");
|
||||
var env = process.env.NODE_ENV || "development";
|
||||
var pkg = JSON.parse(fs.readFileSync(path.join(__dirname, "../package.json")));
|
||||
|
||||
module.exports = app => {
|
||||
app.use((req, res, next) => {
|
||||
res.setHeader('X-GNU', 'Michael J Blanchard');
|
||||
next();
|
||||
});
|
||||
// Enforce HTTPS in production
|
||||
if (env === 'production') {
|
||||
app.use((req, res, next) => {
|
||||
res.setHeader('Strict-Transport-Security', 'max-age=2592000; includeSubdomains'); // Enforce usage of HTTPS; max-age = 30 days
|
||||
next();
|
||||
});
|
||||
}
|
||||
app.use(express.static(path.join(__dirname, '../public')));
|
||||
app.use(cookieParser());
|
||||
app.use(favicon(path.join(__dirname, '../public/favicon.ico')));
|
||||
|
||||
// // Use winston on production
|
||||
// var log;
|
||||
// if (env !== 'development') {
|
||||
// log = {
|
||||
// stream: {
|
||||
// write: (message, encoding) => {
|
||||
// winston.info(message);
|
||||
// }
|
||||
// }
|
||||
// };
|
||||
// } else {
|
||||
// log = 'dev';
|
||||
// }
|
||||
|
||||
// if (env !== 'test') app.use(morgan(log));
|
||||
|
||||
var hbs = exphbs({
|
||||
defaultLayout: 'main',
|
||||
extname: '.hbs'
|
||||
});
|
||||
|
||||
app.engine('.hbs', hbs);
|
||||
app.set('view engine', '.hbs');
|
||||
};
|
32
config/express.mjs
Normal file
32
config/express.mjs
Normal file
|
@ -0,0 +1,32 @@
|
|||
import { resolve } from "path";
|
||||
import express from "express"
|
||||
import favicon from "serve-favicon"
|
||||
import { engine as exphbs } from "express-handlebars";
|
||||
import cookieParser from "cookie-parser";
|
||||
|
||||
var env = process.env.NODE_ENV || "development";
|
||||
|
||||
export default function configureExpress(app) {
|
||||
app.use((req, res, next) => {
|
||||
res.setHeader('X-GNU', 'Michael J Blanchard');
|
||||
next();
|
||||
});
|
||||
// Enforce HTTPS in production
|
||||
if (env === 'production') {
|
||||
app.use((req, res, next) => {
|
||||
res.setHeader('Strict-Transport-Security', 'max-age=2592000; includeSubdomains'); // Enforce usage of HTTPS; max-age = 30 days
|
||||
next();
|
||||
});
|
||||
}
|
||||
app.use(express.static(resolve('public')));
|
||||
app.use(cookieParser());
|
||||
app.use(favicon(resolve('public/favicon.ico')));
|
||||
|
||||
var hbs = exphbs({
|
||||
defaultLayout: 'main',
|
||||
extname: '.hbs'
|
||||
});
|
||||
|
||||
app.engine('.hbs', hbs);
|
||||
app.set('view engine', '.hbs');
|
||||
};
|
|
@ -1,14 +1,12 @@
|
|||
"use strict";
|
||||
import winston from "winston";
|
||||
import config from "./config.mjs";
|
||||
import GatherPool from "../lib/gather/gather_pool.mjs";
|
||||
import mongoose from "mongoose";
|
||||
import cors from "cors"
|
||||
|
||||
const path = require("path");
|
||||
const winston = require("winston");
|
||||
const config = require("./config.js");
|
||||
const GatherPool = require("../lib/gather/gather_pool");
|
||||
const mongoose = require("mongoose");
|
||||
const Message = mongoose.model("Message");
|
||||
const cors = require("cors");
|
||||
|
||||
module.exports = app => {
|
||||
export default function configureRoutes(app) {
|
||||
app.use(cors());
|
||||
|
||||
app.get("/", (request, response, next) => {
|
|
@ -1,18 +1,16 @@
|
|||
"use strict";
|
||||
import winston from "winston";
|
||||
import User from "../lib/user/user.mjs";
|
||||
import config from "./config.mjs";
|
||||
import EnslClient from "../lib/ensl/client.mjs";
|
||||
import chatController from "../lib/chat/controller.mjs"
|
||||
import gatherController from "../lib/gather/controller.mjs"
|
||||
import userController from "../lib/user/controller.mjs";
|
||||
import eventController from "../lib/event/controller.mjs";
|
||||
import usersHelper from "../lib/user/helper.mjs";
|
||||
|
||||
var winston = require("winston");
|
||||
var User = require("../lib/user/user");
|
||||
var config = require("./config");
|
||||
var EnslClient = require("../lib/ensl/client");
|
||||
var chatController = require("../lib/chat/controller");
|
||||
var gatherController = require("../lib/gather/controller");
|
||||
var userController = require("../lib/user/controller");
|
||||
var eventController = require("../lib/event/controller");
|
||||
var usersHelper = require("../lib/user/helper");
|
||||
var env = process.env.NODE_ENV || "development";
|
||||
var parseCookies = EnslClient.parseCookies;
|
||||
const parseCookies = EnslClient.parseCookies;
|
||||
|
||||
var assignRandomUser = (socket, next) => {
|
||||
const assignRandomUser = (socket, next) => {
|
||||
usersHelper.getRandomUser(function (error, user) {
|
||||
if (error) {
|
||||
winston.error(error);
|
||||
|
@ -23,7 +21,7 @@ var assignRandomUser = (socket, next) => {
|
|||
});
|
||||
};
|
||||
|
||||
var assignFixedUser = (socket, next, userId) => {
|
||||
const assignFixedUser = (socket, next, userId) => {
|
||||
usersHelper.getFixedUser(userId, function (error, user) {
|
||||
if (error) {
|
||||
winston.error(error);
|
||||
|
@ -34,17 +32,17 @@ var assignFixedUser = (socket, next, userId) => {
|
|||
});
|
||||
};
|
||||
|
||||
var handleFailedAuth = (socket, next) => {
|
||||
const handleFailedAuth = (socket, next) => {
|
||||
if (process.env.RANDOM_USER) {
|
||||
return assignRandomUser(socket, next);
|
||||
} else if (process.env.FIXED_USER) {
|
||||
return assignFixedUser(socket, next, process.env.FIXED_USER);
|
||||
} else {
|
||||
} else if (process.env.FIXED_USER) {
|
||||
return assignFixedUser(socket, next, process.env.FIXED_USER);
|
||||
} else {
|
||||
return next(new Error("Authentication Failed"));
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = io => {
|
||||
export default function configureSockerIO(io) {
|
||||
var rootNamespace = io.of('/')
|
||||
|
||||
// Authentication
|
||||
|
@ -58,7 +56,7 @@ module.exports = io => {
|
|||
let session = cookies[config.session_store_name];
|
||||
|
||||
if (!session) {
|
||||
return handleFailedAuth(socket, next);
|
||||
return handleFailedAuth(socket, next);
|
||||
}
|
||||
|
||||
EnslClient.decodeSession(session, function (error, userId) {
|
|
@ -1,9 +1,6 @@
|
|||
"use strict";
|
||||
|
||||
var path = require("path");
|
||||
var winston = require("winston");
|
||||
var mongoose = require("mongoose");
|
||||
var config = require(path.join(__dirname, "../config/config.js"));
|
||||
import winston from "winston"
|
||||
import mongoose from "mongoose";
|
||||
import config from "../config/config.mjs";
|
||||
|
||||
mongoose.set('strictQuery', true);
|
||||
|
||||
|
@ -25,11 +22,9 @@ mongoose.connection.on("reconnectFailed", () => winston.error("MongoDB: Reconnec
|
|||
|
||||
mongoose.connection.on("reconnected", () => winston.info("MongoDB: Connection established"));
|
||||
|
||||
// Load models
|
||||
require(path.join(__dirname, "/models/event"));
|
||||
require(path.join(__dirname, "/models/message"));
|
||||
require(path.join(__dirname, "/models/session"));
|
||||
require(path.join(__dirname, "/models/profile"));
|
||||
require(path.join(__dirname, "/models/archivedGather"));
|
||||
|
||||
module.exports = mongoose;
|
||||
// Load Models
|
||||
import "./models/event.mjs";
|
||||
import "./models/message.mjs";
|
||||
import "./models/session.mjs";
|
||||
import "./models/profile.mjs";
|
||||
import "./models/archivedGather.mjs";
|
|
@ -1,11 +1,8 @@
|
|||
"use strict";
|
||||
|
||||
var mongoose = require("mongoose");
|
||||
var Schema = mongoose.Schema;
|
||||
import { Schema, model } from "mongoose";
|
||||
|
||||
var archivedGatherSchema = new Schema({
|
||||
createdAt: { type: Date, default: Date.now },
|
||||
gather: { type: Schema.Types.Mixed, required: true }
|
||||
gather: { type: Schema.Types.Mixed, required: true }
|
||||
});
|
||||
|
||||
archivedGatherSchema.index({ createdAt: -1 });
|
||||
|
@ -14,7 +11,7 @@ archivedGatherSchema.static({
|
|||
recent: function (callback) {
|
||||
this
|
||||
.where({})
|
||||
.sort({createdAt: -1})
|
||||
.sort({ createdAt: -1 })
|
||||
.limit(5)
|
||||
.exec(callback);
|
||||
},
|
||||
|
@ -28,4 +25,4 @@ archivedGatherSchema.static({
|
|||
}
|
||||
});
|
||||
|
||||
module.exports = mongoose.model("ArchivedGather", archivedGatherSchema);
|
||||
model("ArchivedGather", archivedGatherSchema);
|
|
@ -1,10 +1,7 @@
|
|||
"use strict";
|
||||
import { Schema, model } from "mongoose";
|
||||
import winston from "winston";
|
||||
|
||||
const mongoose = require("mongoose");
|
||||
const Schema = mongoose.Schema;
|
||||
const path = require("path");
|
||||
const pubsub = require(path.join(__dirname, "../../lib/event/pubsub.js"));
|
||||
const winston = require("winston");
|
||||
import pubsub from "../../lib/event/pubsub.mjs"
|
||||
|
||||
const eventSchema = new Schema({
|
||||
eventType: { type: String, required: true },
|
||||
|
@ -41,7 +38,7 @@ eventSchema.statics.leaver = function (user) {
|
|||
|
||||
eventSchema.statics.playerSelected = function (user, data, gather) {
|
||||
winston.info("Selection Data", JSON.stringify(user), JSON.stringify(data));
|
||||
const gatherer = gather.getGatherer({id: data.player});
|
||||
const gatherer = gather.getGatherer({ id: data.player });
|
||||
const description = `${user.username} selected ${gatherer.user.username} into ${gatherer.team} team`;
|
||||
this.create({
|
||||
eventType: "gather:select",
|
||||
|
@ -99,4 +96,4 @@ eventSchema.statics.serverVote = function (user, data, gather, servers) {
|
|||
}
|
||||
};
|
||||
|
||||
module.exports = mongoose.model('Event', eventSchema);
|
||||
model('Event', eventSchema);
|
|
@ -1,7 +1,4 @@
|
|||
"use strict";
|
||||
|
||||
var mongoose = require("mongoose");
|
||||
var Schema = mongoose.Schema;
|
||||
import { Schema, model } from "mongoose";
|
||||
|
||||
var messageSchema = new Schema({
|
||||
author: {
|
||||
|
@ -27,7 +24,7 @@ messageSchema.methods.toJson = function () {
|
|||
};
|
||||
|
||||
messageSchema.statics.list = function (options, callback) {
|
||||
let query = this.find({deleted: false})
|
||||
let query = this.find({ deleted: false })
|
||||
|
||||
if (options.before) {
|
||||
query.where({
|
||||
|
@ -37,7 +34,7 @@ messageSchema.statics.list = function (options, callback) {
|
|||
});
|
||||
}
|
||||
|
||||
return query.sort({createdAt: -1})
|
||||
return query.sort({ createdAt: -1 })
|
||||
.limit(30)
|
||||
.exec((error, messages) => {
|
||||
if (error) return callback(error);
|
||||
|
@ -45,4 +42,4 @@ messageSchema.statics.list = function (options, callback) {
|
|||
});
|
||||
};
|
||||
|
||||
module.exports = mongoose.model('Message', messageSchema);
|
||||
model('Message', messageSchema);
|
|
@ -1,7 +1,4 @@
|
|||
"use strict";
|
||||
|
||||
var mongoose = require("mongoose");
|
||||
var Schema = mongoose.Schema;
|
||||
import { model, Schema } from "mongoose";
|
||||
|
||||
var profileSchema = new Schema({
|
||||
userId: { type: Number, required: true },
|
||||
|
@ -25,10 +22,10 @@ profileSchema.static({
|
|||
findOrCreate: function (user, callback) {
|
||||
if (!user || typeof user.id !== 'number') return callback(new Error("Invalid user"));
|
||||
let self = this;
|
||||
self.findOne({userId: user.id}, (error, profile) => {
|
||||
self.findOne({ userId: user.id }, (error, profile) => {
|
||||
if (error) return callback(error);
|
||||
if (profile) return callback(null, profile);
|
||||
self.create({userId: user.id}, (error, result) => {
|
||||
self.create({ userId: user.id }, (error, result) => {
|
||||
if (error) return callback(error);
|
||||
return callback(null, result);
|
||||
});
|
||||
|
@ -45,4 +42,4 @@ profileSchema.method({
|
|||
}
|
||||
});
|
||||
|
||||
module.exports = mongoose.model("Profile", profileSchema);
|
||||
model("Profile", profileSchema);
|
|
@ -1,18 +0,0 @@
|
|||
"use strict";
|
||||
|
||||
var mongoose = require("mongoose");
|
||||
var Schema = mongoose.Schema;
|
||||
var crypto = require('crypto');
|
||||
|
||||
var keyGenerator = () => {
|
||||
return crypto.randomBytes(20).toString('hex');
|
||||
};
|
||||
|
||||
var sessionSchema = new Schema({
|
||||
userId: { type: Number, required: true },
|
||||
key: { type: String, required: true, default: keyGenerator }
|
||||
});
|
||||
|
||||
sessionSchema.index({ userId: 1 });
|
||||
|
||||
module.exports = mongoose.model("Session", sessionSchema);
|
15
db/models/session.mjs
Normal file
15
db/models/session.mjs
Normal file
|
@ -0,0 +1,15 @@
|
|||
import { model, Schema } from "mongoose";
|
||||
import { randomBytes } from "crypto";
|
||||
|
||||
var keyGenerator = () => {
|
||||
return randomBytes(20).toString('hex');
|
||||
};
|
||||
|
||||
var sessionSchema = new Schema({
|
||||
userId: { type: Number, required: true },
|
||||
key: { type: String, required: true, default: keyGenerator }
|
||||
});
|
||||
|
||||
sessionSchema.index({ userId: 1 });
|
||||
|
||||
model("Session", sessionSchema);
|
43
index.js
43
index.js
|
@ -1,43 +0,0 @@
|
|||
"use strict";
|
||||
|
||||
const env = process.env.NODE_ENV || "development";
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const express = require("express");
|
||||
const app = express();
|
||||
const server = require('http').Server(app);
|
||||
const io = require('socket.io')(server);
|
||||
const config = require(path.join(__dirname, "config/config.js"));
|
||||
|
||||
if (env === "production") require("newrelic");
|
||||
|
||||
// Load Models
|
||||
require(path.join(__dirname, "db/index"));
|
||||
|
||||
// Initialise Steam Bot
|
||||
//if (env !== "test") {
|
||||
// require(path.join(__dirname, "lib/steam/bot"))(config.steamBot);
|
||||
//}
|
||||
|
||||
//Initialise Discord Bot
|
||||
// if (env !== "test") {
|
||||
// require(path.join(__dirname, "lib/discord/bot"))(config.discordBot);
|
||||
// }
|
||||
|
||||
// Configure express
|
||||
require(path.join(__dirname, "config/express"))(app);
|
||||
|
||||
// Add routes
|
||||
require(path.join(__dirname, "config/routes"))(app);
|
||||
|
||||
// Configure socket.io server
|
||||
require(path.join(__dirname, "config/socketio"))(io);
|
||||
|
||||
server.listen(config.port);
|
||||
console.log("Listening on port", config.port);
|
||||
|
||||
module.exports = {
|
||||
app: app,
|
||||
server: server,
|
||||
io: io
|
||||
};
|
34
index.mjs
Normal file
34
index.mjs
Normal file
|
@ -0,0 +1,34 @@
|
|||
"use strict";
|
||||
|
||||
import express from "express";
|
||||
import { createServer } from "http";
|
||||
import { Server } from "socket.io";
|
||||
import config from "./config/config.mjs";
|
||||
import "./db/index.mjs";
|
||||
import configureExpress from "./config/express.mjs";
|
||||
import addRoutes from "./config/routes.mjs"
|
||||
import configureSocketIO from "./config/socketio.mjs";
|
||||
|
||||
const env = process.env.NODE_ENV || "development";
|
||||
|
||||
const app = express();
|
||||
const server = createServer(app);
|
||||
const io = new Server(server);
|
||||
|
||||
// Configure express
|
||||
configureExpress(app);
|
||||
|
||||
// Add routes
|
||||
addRoutes(app);
|
||||
|
||||
// Configure socket.io server
|
||||
configureSocketIO(io);
|
||||
|
||||
server.listen(config.port);
|
||||
console.log("Listening on port", config.port);
|
||||
|
||||
export default {
|
||||
app: app,
|
||||
server: server,
|
||||
io: io
|
||||
};
|
|
@ -1,5 +1,3 @@
|
|||
"use strict";
|
||||
|
||||
/*
|
||||
* Chatroom Controller
|
||||
*
|
||||
|
@ -14,13 +12,13 @@
|
|||
*
|
||||
*/
|
||||
|
||||
var mongoose = require("mongoose");
|
||||
var Message = mongoose.model("Message");
|
||||
var winston = require("winston");
|
||||
import { model } from "mongoose";
|
||||
import winston from "winston";
|
||||
const Message = model("Message");
|
||||
|
||||
module.exports = namespace => {
|
||||
export default namespace => {
|
||||
var broadcastUpdate = message => {
|
||||
namespace.emit("message:append", { messages: [message.toJson()]});
|
||||
namespace.emit("message:append", { messages: [message.toJson()] });
|
||||
};
|
||||
|
||||
var refreshMessages = socket => {
|
||||
|
@ -60,7 +58,7 @@ module.exports = namespace => {
|
|||
username: socket._user.username,
|
||||
avatar: socket._user.avatar
|
||||
},
|
||||
content: data.content.slice(0,255)
|
||||
content: data.content.slice(0, 255)
|
||||
}, (error, newMessage) => {
|
||||
if (error) {
|
||||
winston.error("Unable to store message. Error:", error);
|
||||
|
@ -75,7 +73,7 @@ module.exports = namespace => {
|
|||
var id = data.id;
|
||||
if (id === undefined || !socket._user.isChatAdmin()) return;
|
||||
|
||||
Message.update({_id: id}, {deleted: true}, (error, message) => {
|
||||
Message.deleteOne({ _id: id }, (error, message) => {
|
||||
if (error) {
|
||||
winston.error("An error occurred when trying to delete message:", error);
|
||||
return;
|
|
@ -1,27 +0,0 @@
|
|||
"use strict"
|
||||
|
||||
// Import the discord.js module
|
||||
const Discord = require('discord.js');
|
||||
const winston = require('winston');
|
||||
|
||||
function DiscordBot(config) {
|
||||
this.hook = new Discord.WebhookClient(config.hook_id,config.hook_token);
|
||||
this.spamProtection = {
|
||||
fillStatus: null,
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
DiscordBot.prototype.notifyChannel = function(message) {
|
||||
this.hook.send(message);
|
||||
};
|
||||
|
||||
var bot;
|
||||
|
||||
module.exports = (config) => {
|
||||
if (bot) return bot;
|
||||
if (!config) throw new Error("No credentials provided for Discord Gather Bot");
|
||||
bot = new DiscordBot(config);
|
||||
bot.notifyChannel('Gather restarted');
|
||||
return bot;
|
||||
};
|
|
@ -1,123 +0,0 @@
|
|||
"use strict";
|
||||
|
||||
var path = require("path");
|
||||
var crypto = require("crypto");
|
||||
var request = require("request");
|
||||
var logger = require("winston");
|
||||
var querystring = require('querystring');
|
||||
var config = require(path.join(__dirname, "../../config/config"));
|
||||
const SECRET_TOKEN = config.secret_token;
|
||||
const Marshal = require('marshal');
|
||||
|
||||
|
||||
const MAP_CATEGORY = 45;
|
||||
const SERVER_CATEGORY = 45;
|
||||
|
||||
function EnslClient(options) {
|
||||
if (!(this instanceof EnslClient)) {
|
||||
return new EnslClient(options);
|
||||
}
|
||||
|
||||
this.baseUrl = config.ensl_url;
|
||||
}
|
||||
|
||||
EnslClient.prototype.getUserById = function (options, callback) {
|
||||
var id = options.id;
|
||||
var url = this.baseUrl + "api/v1/users/" + id;
|
||||
return request({
|
||||
url: url,
|
||||
json: true
|
||||
}, callback);
|
||||
};
|
||||
|
||||
EnslClient.prototype.getTeamById = function (options, callback) {
|
||||
const id = options.id;
|
||||
const url = `${this.baseUrl}api/v1/teams/${id}`;
|
||||
return request({
|
||||
url: url,
|
||||
json: true
|
||||
}, callback);
|
||||
};
|
||||
|
||||
EnslClient.prototype.getServers = function (callback) {
|
||||
const url = this.baseUrl + "api/v1/servers";
|
||||
return request({
|
||||
url: url,
|
||||
json: true
|
||||
}, (error, response, data) => {
|
||||
if (error) return callback(error);
|
||||
if (response.statusCode !== 200) return callback(new Error("Non-200 status code received"));
|
||||
return callback(null, {
|
||||
servers: data.servers.filter(function (server) {
|
||||
return server.category_id === SERVER_CATEGORY;
|
||||
})
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
EnslClient.prototype.getMaps = function (callback) {
|
||||
const url = this.baseUrl + "api/v1/maps";
|
||||
return request({
|
||||
url: url,
|
||||
json: true
|
||||
}, (error, response, data) => {
|
||||
if (error) return callback(error);
|
||||
if (response.statusCode !== 200) return callback(new Error("Non-200 status code received"));
|
||||
return callback(null, {
|
||||
maps: data.maps.filter(map => {
|
||||
return map.category_id === MAP_CATEGORY;
|
||||
})
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
EnslClient.prototype.getFullAvatarUri = function (url) {
|
||||
return this.baseUrl + url.replace(/^\//, "");
|
||||
};
|
||||
|
||||
EnslClient.parseCookies = function (socket) {
|
||||
let cookieString = socket.request.headers.cookie;
|
||||
if (typeof cookieString !== 'string') return null;
|
||||
let cookies = socket.request.headers.cookie.split(";")
|
||||
.map(cookie => cookie.trim())
|
||||
.reduce((acc, cookie) => {
|
||||
let values = cookie.split("=");
|
||||
let attr = values[0];
|
||||
let val = values[1];
|
||||
if (attr && val) acc[attr] = val;
|
||||
return acc;
|
||||
}, {})
|
||||
return cookies;
|
||||
};
|
||||
|
||||
EnslClient.decodeSession = function (sessionCookie, callback) {
|
||||
if (typeof sessionCookie !== 'string') {
|
||||
return callback(new Error("Invalid cookie"), null);
|
||||
}
|
||||
|
||||
var session = sessionCookie.split("--");
|
||||
if (session.length !== 2) {
|
||||
return callback(new Error("Invalid cookie: No signature provided"), null);
|
||||
}
|
||||
|
||||
// Separate text and signature
|
||||
var text = querystring.unescape(session[0]);
|
||||
var signature = session[1];
|
||||
|
||||
// Verify signature
|
||||
if (crypto.createHmac("sha1", SECRET_TOKEN).update(text).digest('hex') !== signature) {
|
||||
return callback(new Error("Invalid cookie signature"), null);
|
||||
}
|
||||
|
||||
let railsSession = new Marshal(text, 'base64').toJSON();
|
||||
|
||||
if (isNaN(railsSession.user)) {
|
||||
return callback(new Error("Invalid cookie: User ID not found"), null);
|
||||
} else {
|
||||
return callback(null, railsSession.user);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
module.exports = EnslClient;
|
118
lib/ensl/client.mjs
Normal file
118
lib/ensl/client.mjs
Normal file
|
@ -0,0 +1,118 @@
|
|||
import { createHmac } from "crypto";
|
||||
import request from "request";
|
||||
import { unescape } from "querystring";
|
||||
import config from "../../config/config.mjs";
|
||||
import Marshal from "marshal";
|
||||
|
||||
const SECRET_TOKEN = config.secret_token;
|
||||
|
||||
const MAP_CATEGORY = 45;
|
||||
const SERVER_CATEGORY = 45;
|
||||
|
||||
class EnslClient {
|
||||
constructor(options) {
|
||||
if (!(this instanceof EnslClient)) {
|
||||
return new EnslClient(options);
|
||||
}
|
||||
|
||||
this.baseUrl = config.ensl_url;
|
||||
}
|
||||
static parseCookies(socket) {
|
||||
let cookieString = socket.request.headers.cookie;
|
||||
if (typeof cookieString !== 'string')
|
||||
return null;
|
||||
let cookies = socket.request.headers.cookie.split(";")
|
||||
.map(cookie => cookie.trim())
|
||||
.reduce((acc, cookie) => {
|
||||
let values = cookie.split("=");
|
||||
let attr = values[0];
|
||||
let val = values[1];
|
||||
if (attr && val)
|
||||
acc[attr] = val;
|
||||
return acc;
|
||||
}, {});
|
||||
return cookies;
|
||||
}
|
||||
static decodeSession(sessionCookie, callback) {
|
||||
if (typeof sessionCookie !== 'string') {
|
||||
return callback(new Error("Invalid cookie"), null);
|
||||
}
|
||||
|
||||
var session = sessionCookie.split("--");
|
||||
if (session.length !== 2) {
|
||||
return callback(new Error("Invalid cookie: No signature provided"), null);
|
||||
}
|
||||
|
||||
// Separate text and signature
|
||||
var text = unescape(session[0]);
|
||||
var signature = session[1];
|
||||
|
||||
// Verify signature
|
||||
if (createHmac("sha1", SECRET_TOKEN).update(text).digest('hex') !== signature) {
|
||||
return callback(new Error("Invalid cookie signature"), null);
|
||||
}
|
||||
|
||||
let railsSession = new Marshal(text, 'base64').toJSON();
|
||||
|
||||
if (isNaN(railsSession.user)) {
|
||||
return callback(new Error("Invalid cookie: User ID not found"), null);
|
||||
} else {
|
||||
return callback(null, railsSession.user);
|
||||
}
|
||||
}
|
||||
getUserById(options, callback) {
|
||||
var id = options.id;
|
||||
var url = this.baseUrl + "/api/v1/users/" + id;
|
||||
return request({
|
||||
url: url,
|
||||
json: true
|
||||
}, callback);
|
||||
}
|
||||
getTeamById(options, callback) {
|
||||
const id = options.id;
|
||||
const url = `${this.baseUrl}/api/v1/teams/${id}`;
|
||||
return request({
|
||||
url: url,
|
||||
json: true
|
||||
}, callback);
|
||||
}
|
||||
getServers(callback) {
|
||||
const url = this.baseUrl + "/api/v1/servers";
|
||||
return request({
|
||||
url: url,
|
||||
json: true
|
||||
}, (error, response, data) => {
|
||||
if (error)
|
||||
return callback(error);
|
||||
if (response.statusCode !== 200)
|
||||
return callback(new Error("Non-200 status code received"));
|
||||
return callback(null, {
|
||||
servers: data.servers.filter(function (server) {
|
||||
return server.category_id === SERVER_CATEGORY;
|
||||
})
|
||||
});
|
||||
});
|
||||
}
|
||||
getMaps(callback) {
|
||||
const url = this.baseUrl + "/api/v1/maps";
|
||||
return request({
|
||||
url: url,
|
||||
json: true
|
||||
}, (error, response, data) => {
|
||||
if (error)
|
||||
return callback(error);
|
||||
if (response.statusCode !== 200)
|
||||
return callback(new Error("Non-200 status code received"));
|
||||
return callback(null, {
|
||||
maps: data.maps.filter(map => {
|
||||
return map.category_id === MAP_CATEGORY;
|
||||
})
|
||||
});
|
||||
});
|
||||
}
|
||||
getFullAvatarUri(url) {
|
||||
return this.baseUrl + url;
|
||||
}
|
||||
}
|
||||
|
||||
export default EnslClient;
|
|
@ -6,10 +6,9 @@
|
|||
*
|
||||
*/
|
||||
|
||||
const winston = require("winston");
|
||||
const pubsub = require("./pubsub.js");
|
||||
import pubsub from "./pubsub.mjs";
|
||||
|
||||
module.exports = namespace => {
|
||||
export default namespace => {
|
||||
pubsub.on("newEvent", event => {
|
||||
if (!event.public) return;
|
||||
namespace.emit("event:append", {
|
|
@ -1,3 +0,0 @@
|
|||
const EventEmitter = require("events").EventEmitter;
|
||||
|
||||
module.exports = new EventEmitter();
|
5
lib/event/pubsub.mjs
Normal file
5
lib/event/pubsub.mjs
Normal file
|
@ -0,0 +1,5 @@
|
|||
import { EventEmitter } from "events";
|
||||
|
||||
const pubsub = new EventEmitter()
|
||||
|
||||
export default pubsub;
|
|
@ -17,57 +17,61 @@
|
|||
*
|
||||
*/
|
||||
|
||||
const Map = require("./map");
|
||||
const Server = require("./server");
|
||||
const mongoose = require("mongoose");
|
||||
const GatherPool = require("./gather_pool");
|
||||
import _ from "lodash";
|
||||
import winston from "winston";
|
||||
|
||||
import Map from "./map.mjs";
|
||||
import Server from "./server.mjs";
|
||||
import mongoose from "mongoose";
|
||||
import GatherPool from "./gather_pool.mjs";
|
||||
|
||||
|
||||
const ArchivedGather = mongoose.model("ArchivedGather");
|
||||
const Event = mongoose.model("Event");
|
||||
const _ = require("lodash");
|
||||
const winston = require("winston");
|
||||
const kickTimeout = 600 // sec
|
||||
|
||||
module.exports = function (namespace) {
|
||||
|
||||
export default function (namespace) {
|
||||
const emitGather = (socket, gather) => {
|
||||
socket.emit("gather:refresh", {
|
||||
gather: gather ? gather.toJson() : null,
|
||||
type: gather ? gather.type : null,
|
||||
maps: Map.list,
|
||||
});
|
||||
};
|
||||
|
||||
const removeGatherer = (gather, user) => {
|
||||
let gatherLeaver = gather.getGatherer(user);
|
||||
});
|
||||
};
|
||||
|
||||
if (!gatherLeaver) {
|
||||
winston.info(`${user.username} ${user.id} attempted to leave ${gather.type} gather, but was not in gather.`);
|
||||
return;
|
||||
}
|
||||
const removeGatherer = (gather, user) => {
|
||||
let gatherLeaver = gather.getGatherer(user);
|
||||
|
||||
if (gather.can("removeGatherer")) {
|
||||
gather.removeGatherer(user);
|
||||
}
|
||||
if (user.cooldown) gather.applyCooldown(user);
|
||||
if (!gatherLeaver) {
|
||||
winston.warn(`${user.username} ${user.id} attempted to leave ${gather.type} gather, but was not in gather.`);
|
||||
return;
|
||||
}
|
||||
|
||||
Event.leaver(gatherLeaver.user);
|
||||
refreshGather(gather.type);
|
||||
}
|
||||
if (gather.can("removeGatherer")) {
|
||||
gather.removeGatherer(user);
|
||||
}
|
||||
if (user.cooldown) gather.applyCooldown(user);
|
||||
|
||||
const removeAfkGathererTimer = (gather, user) => {
|
||||
const interval = setInterval(() => {
|
||||
console.log(gather.current)
|
||||
if (gather.getGatherer(user).user.online || gather.current !== "gathering") {
|
||||
clearInterval(interval);
|
||||
}
|
||||
const now = Date.now();
|
||||
const awayDuration = (now / 1000) - (user.lastSeen / 1000);
|
||||
if (awayDuration >= kickTimeout) {
|
||||
console.log("kicked from being afk : ");
|
||||
removeGatherer(gather, user);
|
||||
clearInterval(interval);
|
||||
}
|
||||
}, 1000)
|
||||
}
|
||||
Event.leaver(gatherLeaver.user);
|
||||
refreshGather(gather.type);
|
||||
}
|
||||
|
||||
const removeAfkGathererTimer = (gather, user) => {
|
||||
const interval = setInterval(() => {
|
||||
console.log(gather.current)
|
||||
if (gather.getGatherer(user).user.online || gather.current !== "gathering") {
|
||||
clearInterval(interval);
|
||||
}
|
||||
const now = Date.now();
|
||||
const awayDuration = (now / 1000) - (user.lastSeen / 1000);
|
||||
if (awayDuration >= kickTimeout) {
|
||||
console.log("kicked from being afk : ");
|
||||
removeGatherer(gather, user);
|
||||
clearInterval(interval);
|
||||
}
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
const refreshArchive = () => {
|
||||
ArchivedGather.recent((error, recentGathers) => {
|
||||
|
@ -87,7 +91,7 @@ module.exports = function (namespace) {
|
|||
} else {
|
||||
const refresh = gatherRefreshers[type];
|
||||
if (refresh) refresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const updateUserAsOnlineInGather = (userId) => {
|
||||
|
@ -105,15 +109,15 @@ module.exports = function (namespace) {
|
|||
for (var gatherer of gatherManager.current.gatherers) {
|
||||
if (gatherer.user.id == userId && gatherer.user.online) {
|
||||
gatherer.user.online = false;
|
||||
gatherer.user.lastSeen = Date.now();
|
||||
removeAfkGathererTimer(gatherManager.current, { ...gatherer.user, cooldown: false });
|
||||
gatherer.user.lastSeen = Date.now();
|
||||
removeAfkGathererTimer(gatherManager.current, { ...gatherer.user, cooldown: false });
|
||||
refreshGather(type);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
const gatherRefreshers = {}; // Stores debounced procedures to refresh gathers
|
||||
|
||||
|
@ -152,7 +156,7 @@ module.exports = function (namespace) {
|
|||
|
||||
// ***** Generate Test Users *****
|
||||
if (process.env.POPULATE_GATHER) {
|
||||
let helper = require("./helper");
|
||||
let helper = require("./helper.mjs");
|
||||
|
||||
GatherPool.forEach(gatherManager => {
|
||||
helper.createTestUsers({
|
||||
|
@ -160,7 +164,7 @@ module.exports = function (namespace) {
|
|||
}, refreshGather());
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
namespace.on("connection", function (socket) {
|
||||
const connectedUserId = socket._user && socket._user.id;
|
||||
|
||||
|
@ -173,7 +177,7 @@ module.exports = function (namespace) {
|
|||
maps: Map.list
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
socket.on("disconnect", () => {
|
||||
const onlineIds = Object.values(namespace.sockets).map(s => s._user.id);
|
||||
|
||||
|
@ -216,7 +220,7 @@ module.exports = function (namespace) {
|
|||
emitGather(socket, gatherManager.current)
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
socket.on("gather:leave", function (data) {
|
||||
if (!data) data = {};
|
||||
|
@ -226,7 +230,7 @@ module.exports = function (namespace) {
|
|||
if (data.gatherer) {
|
||||
// Remove gatherer defined by ID (admins only)
|
||||
if (!socket._user.isGatherAdmin()) return;
|
||||
|
||||
|
||||
removeGatherer(gather, { id: data.gatherer, cooldown: true });
|
||||
let adminName = socket._user.username;
|
||||
let playerId = data.gatherer;
|
||||
|
@ -253,7 +257,7 @@ module.exports = function (namespace) {
|
|||
}
|
||||
|
||||
// Cancel if id belongs to a leader
|
||||
let selectedPlayer = gather.getGatherer({id: playerId});
|
||||
let selectedPlayer = gather.getGatherer({ id: playerId });
|
||||
|
||||
if (selectedPlayer === null || selectedPlayer.leader) {
|
||||
return null;
|
|
@ -1,471 +0,0 @@
|
|||
"use strict";
|
||||
|
||||
/*
|
||||
* Implements Gather Model
|
||||
*
|
||||
* Gather States
|
||||
* - Gathering
|
||||
* - Election (Electing leaders)
|
||||
* - Selection (Selecting teams)
|
||||
* - Done
|
||||
*
|
||||
*/
|
||||
|
||||
const Gatherer = require("./gatherer");
|
||||
const StateMachine = require("javascript-state-machine");
|
||||
const Server = require("./server");
|
||||
// const discordBot = require("../discord/bot")();
|
||||
|
||||
function Gather (options) {
|
||||
if (options === undefined) options = {};
|
||||
if (!(this instanceof Gather)) {
|
||||
return new Gather(options);
|
||||
}
|
||||
this.gatherers = [];
|
||||
let noop = () => {};
|
||||
this.onDone = (typeof options.onDone === 'function') ?
|
||||
options.onDone : noop;
|
||||
this.onEvent = (typeof options.onEvent === 'function') ?
|
||||
options.onEvent : noop;
|
||||
this.done = {
|
||||
time: null
|
||||
};
|
||||
|
||||
this.teamSize = options.teamSize || 6;
|
||||
|
||||
// Store cooldown times for gather leaves
|
||||
this.cooldown = {};
|
||||
this.COOLDOWN_TIME = 60 * 3;// 3 Minutes
|
||||
|
||||
this.REGATHER_THRESHOLD = this.teamSize + 2;
|
||||
|
||||
this.type = options.type || "classic";
|
||||
|
||||
this.icon = options.icon || "gather icon";
|
||||
|
||||
this.name = options.name || "Classic Gather";
|
||||
|
||||
this.description = options.description || "No player requirements";
|
||||
|
||||
this.election = {
|
||||
INTERVAL: 60000, // 1 Minute
|
||||
startTime: null,
|
||||
timer: null
|
||||
};
|
||||
|
||||
if (typeof options.membershipTest === 'function') {
|
||||
this.membershipTest = options.membershipTest.bind(this);
|
||||
}
|
||||
|
||||
if (typeof options.serverMembershipTest === 'function') {
|
||||
this.serverMembershipTest = options.serverMembershipTest.bind(this);
|
||||
}
|
||||
|
||||
this.initState();
|
||||
}
|
||||
|
||||
StateMachine.create({
|
||||
target: Gather.prototype,
|
||||
events: [
|
||||
{ name: "initState", from: "none", to: "gathering" },
|
||||
{ name: "addGatherer", from: "gathering", to: "election" },
|
||||
{ name: "selectLeader", from: "election", to: "selection" },
|
||||
{ name: "electionTimeout", from: "election", to: "selection" },
|
||||
{ name: "confirmSelection", from: "selection", to: "done" },
|
||||
{
|
||||
name: "removeGatherer",
|
||||
from: ["gathering", "election", "selection"],
|
||||
to: "gathering"
|
||||
},
|
||||
{
|
||||
name: "regather",
|
||||
from: ["gathering", "election", "selection"],
|
||||
to: "gathering"
|
||||
}
|
||||
],
|
||||
callbacks: {
|
||||
// Callbacks for events
|
||||
onafterevent: function () {
|
||||
this.onEvent.apply(this, [].slice.call(arguments));
|
||||
},
|
||||
|
||||
// Gathering State
|
||||
onbeforeaddGatherer: function (event, from, to, user) {
|
||||
if (this.needsToCoolOff(user)) return false;
|
||||
if (this.failsTest(user)) return false;
|
||||
this.addUser(user);
|
||||
if (!this.lobbyFull()) {
|
||||
// if(this.gatherers.length > this.teamSize &&
|
||||
// (null === discordBot.spamProtection.fillStatus ||
|
||||
// ((new Date()).getTime() - discordBot.spamProtection.fillStatus.getTime())/1000 > 180)) {
|
||||
// discordBot.notifyChannel("Join the gather at https://gathers.ensl.org | " + this.gatherers.length + " players are already waiting!");
|
||||
// discordBot.spamProtection.fillStatus = new Date();
|
||||
// }
|
||||
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
// Election State
|
||||
onbeforeselectLeader: function (event, from, to, voter, candidate) {
|
||||
this.voteForLeader(voter, candidate);
|
||||
if (!this.leaderVotesFull()) return false;
|
||||
},
|
||||
|
||||
onenterelection: function () {
|
||||
// discordBot.notifyChannel("Gather is starting! Pick your captains at https://gathers.ensl.org");
|
||||
// Setup timer for elections
|
||||
this.startElectionCountdown();
|
||||
},
|
||||
|
||||
onleaveelection: function () {
|
||||
this.cancelElectionCountdown();
|
||||
},
|
||||
|
||||
// Selection State
|
||||
onenterselection: function () {
|
||||
// Remove all leaders and teams
|
||||
this.gatherers.forEach(gatherer => {
|
||||
gatherer.leader = false;
|
||||
gatherer.team = "lobby";
|
||||
});
|
||||
|
||||
// Assign leaders based on vote
|
||||
// 1st place alien comm
|
||||
// 2nd place marine comm
|
||||
let voteCount = {};
|
||||
this.gatherers.forEach(gatherer => { voteCount[gatherer.id] = 0 });
|
||||
this.leaderVotes().forEach(candidateId => { voteCount[candidateId]++ });
|
||||
let rank = [];
|
||||
for (let candidate in voteCount) {
|
||||
rank.push({ candidate: candidate, count: voteCount[candidate] });
|
||||
}
|
||||
rank.sort((a, b) => {
|
||||
return a.count - b.count;
|
||||
});
|
||||
this.assignAlienLeader(parseInt(rank.pop().candidate, 0));
|
||||
this.assignMarineLeader(parseInt(rank.pop().candidate, 0));
|
||||
},
|
||||
|
||||
onleaveselection: function (event, from, to, voter, candidate) {
|
||||
if (event === "removeGatherer" || event === "regather") {
|
||||
this.gatherers.forEach(gatherer => {
|
||||
gatherer.team = "lobby";
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
onbeforeconfirmSelection: function (event, from, to, leader) {
|
||||
return (this.aliens().length === this.teamSize
|
||||
&& this.marines().length === this.teamSize);
|
||||
},
|
||||
|
||||
// Remove gatherer event
|
||||
onbeforeremoveGatherer: function (event, from, to, user) {
|
||||
// Cancel transition if no gatherers have been removed
|
||||
let userCount = this.gatherers.length;
|
||||
this.removeUser(user);
|
||||
let userRemoved = userCount > this.gatherers.length;
|
||||
if (userRemoved && from !== 'gathering') this.applyCooldown(user);
|
||||
return userRemoved;
|
||||
},
|
||||
|
||||
// Set gatherer vote & if threshold met, reset gather
|
||||
onbeforeregather: function (event, from, to, user, vote) {
|
||||
let self = this;
|
||||
self.modifyGatherer(user, (gatherer) => gatherer.voteRegather(vote));
|
||||
if (self.regatherVotes() >= self.REGATHER_THRESHOLD) {
|
||||
self.resetState();
|
||||
// discordBot.notifyChannel("@here Gather was reset! Rejoin to play!");
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
// On enter done
|
||||
onenterdone: function () {
|
||||
// discordBot.notifyChannel("Picking finished! Join the server!");
|
||||
this.done.time = new Date();
|
||||
this.onDone.apply(this, [].slice.call(arguments));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Gather.prototype.lobbyFull = function () {
|
||||
return this.gatherers.length === (this.teamSize * 2);
|
||||
};
|
||||
|
||||
Gather.prototype.leaderVotesFull = function () {
|
||||
return this.leaderVotes().length === (this.teamSize * 2);
|
||||
};
|
||||
|
||||
Gather.prototype.resetState = function () {
|
||||
this.gatherers = [];
|
||||
this.cancelElectionCountdown();
|
||||
return this;
|
||||
};
|
||||
|
||||
Gather.prototype.alienLeader = function () {
|
||||
return this.gatherers.reduce((acc, gatherer) => {
|
||||
if (gatherer.team === "alien" && gatherer.leader) acc.push(gatherer);
|
||||
return acc;
|
||||
}, []).pop();
|
||||
};
|
||||
|
||||
Gather.prototype.marineLeader = function () {
|
||||
return this.gatherers.reduce((acc, gatherer) => {
|
||||
if (gatherer.team === "marine" && gatherer.leader) acc.push(gatherer);
|
||||
return acc;
|
||||
}, []).pop();
|
||||
};
|
||||
|
||||
Gather.prototype.assignMarineLeader = function (id) {
|
||||
this.modifyGatherer({id: id}, gatherer => {
|
||||
gatherer.leader = true;
|
||||
gatherer.team = "marine";
|
||||
});
|
||||
};
|
||||
|
||||
Gather.prototype.assignAlienLeader = function (id) {
|
||||
this.modifyGatherer({id: id}, gatherer => {
|
||||
gatherer.leader = true;
|
||||
gatherer.team = "alien";
|
||||
});
|
||||
};
|
||||
|
||||
Gather.prototype.containsUser = function (user) {
|
||||
return this.gatherers.some(gatherer => {
|
||||
return gatherer.id === user.id;
|
||||
});
|
||||
};
|
||||
|
||||
Gather.prototype.addUser = function (user) {
|
||||
if (this.containsUser(user)) return null;
|
||||
let gatherer = new Gatherer(user);
|
||||
this.gatherers.push(gatherer);
|
||||
return gatherer;
|
||||
};
|
||||
|
||||
Gather.prototype.removeUser = function (user) {
|
||||
this.gatherers = this.gatherers.filter(gatherer => user.id !== gatherer.id);
|
||||
};
|
||||
|
||||
Gather.prototype.modifyGatherer = function (user, callback){
|
||||
return this.gatherers
|
||||
.filter(gatherer => gatherer.id === user.id)
|
||||
.forEach(callback);
|
||||
};
|
||||
|
||||
// 08/04/20 : 1-1-1-1-1
|
||||
// 08/11/20 : 1-2-1-1-1
|
||||
// 09/21/20 : 1-1-1-2-1
|
||||
Gather.prototype.getPickingPattern = function () {
|
||||
const pickingPattern = [
|
||||
"marine",
|
||||
"alien",
|
||||
"marine",
|
||||
"alien",
|
||||
"alien",
|
||||
"marine",
|
||||
"alien",
|
||||
"marine",
|
||||
"alien",
|
||||
"marine",
|
||||
"alien",
|
||||
"marine",
|
||||
];
|
||||
|
||||
return pickingPattern;
|
||||
}
|
||||
|
||||
// Determines picking order of teams
|
||||
// Marine pick first
|
||||
Gather.prototype.pickingTurnIndex = function () {
|
||||
if (this.current !== 'selection') return null;
|
||||
|
||||
const captainCount = 2;
|
||||
const alienCount = this.aliens().length;
|
||||
const marineCount = this.marines().length;
|
||||
const alreadyPickedCount = (marineCount + alienCount) - captainCount;
|
||||
const pickingPattern = this.getPickingPattern();
|
||||
|
||||
const pickingTurn = alreadyPickedCount % pickingPattern.length;
|
||||
|
||||
// prevent any team from growing beyond the team size limit
|
||||
if (marineCount >= this.teamSize) {
|
||||
return "alien";
|
||||
} else if (alienCount >= this.teamSize) {
|
||||
return "marine";
|
||||
}
|
||||
|
||||
return pickingTurn;
|
||||
};
|
||||
|
||||
// Moves player to marine
|
||||
// Optional `mover` argument which will check mover credentials to select
|
||||
// Credentials: Must be leader, must belong to team, must be turn to pick
|
||||
Gather.prototype.moveToMarine = function (user, mover) {
|
||||
if (this.marines().length >= this.teamSize) return;
|
||||
|
||||
if (mover && this.containsUser(mover)) {
|
||||
let leader = this.getGatherer(mover);
|
||||
if (leader.team !== "marine" ||
|
||||
!leader.leader ||
|
||||
this.getPickingPattern()[this.pickingTurnIndex()] !== "marine") return;
|
||||
|
||||
if (user && this.containsUser(user)) {
|
||||
if (this.getGatherer(user).team !== "lobby") return;
|
||||
}
|
||||
}
|
||||
|
||||
this.modifyGatherer(user, gatherer => gatherer.team = "marine");
|
||||
};
|
||||
|
||||
// Moves player to alien
|
||||
// Optional `mover` argument which will check mover credentials to select
|
||||
// Credentials: Must be leader, must belong to team, must be turn to pick
|
||||
|
||||
Gather.prototype.moveToAlien = function (user, mover) {
|
||||
if (this.aliens().length >= this.teamSize) return;
|
||||
|
||||
if (mover && this.containsUser(mover)) {
|
||||
let leader = this.getGatherer(mover);
|
||||
if (leader.team !== "alien" ||
|
||||
!leader.leader ||
|
||||
this.getPickingPattern()[this.pickingTurnIndex()] !== "alien") return;
|
||||
|
||||
if (user && this.containsUser(user)) {
|
||||
if (this.getGatherer(user).team !== "lobby") return;
|
||||
}
|
||||
}
|
||||
|
||||
return this.modifyGatherer(user, gatherer => gatherer.team = "alien");
|
||||
};
|
||||
|
||||
Gather.prototype.moveToLobby = function (user) {
|
||||
this.modifyGatherer(user, gatherer => gatherer.team = "lobby");
|
||||
};
|
||||
|
||||
Gather.prototype.retrieveGroup = function (team) {
|
||||
return this.gatherers.filter(gatherer => gatherer.team === team);
|
||||
};
|
||||
|
||||
Gather.prototype.lobby = function () {
|
||||
return this.retrieveGroup("lobby");
|
||||
};
|
||||
|
||||
Gather.prototype.aliens = function () {
|
||||
return this.retrieveGroup("alien");
|
||||
};
|
||||
|
||||
Gather.prototype.marines = function () {
|
||||
return this.retrieveGroup("marine");
|
||||
};
|
||||
|
||||
Gather.prototype.electionStartTime = function () {
|
||||
return (this.election.startTime === null) ?
|
||||
null : this.election.startTime.toISOString();
|
||||
};
|
||||
|
||||
Gather.prototype.toJson = function () {
|
||||
return {
|
||||
name: this.name,
|
||||
icon: this.icon,
|
||||
description: this.description,
|
||||
type: this.type,
|
||||
gatherers: this.gatherers,
|
||||
servers: this.getServers(),
|
||||
state: this.current,
|
||||
pickingTurn: this.getPickingPattern()[this.pickingTurnIndex()],
|
||||
pickingTurnIndex: this.pickingTurnIndex(),
|
||||
pickingPattern: this.getPickingPattern().splice(0, this.getPickingPattern().length-2), //why is the picking pattern length 12 anyway ? 12 - 2 captains
|
||||
election: {
|
||||
startTime: this.electionStartTime(),
|
||||
interval: this.election.INTERVAL
|
||||
},
|
||||
teamSize: this.teamSize,
|
||||
done: {
|
||||
time: this.done.time
|
||||
},
|
||||
cooldown: this.cooldown
|
||||
}
|
||||
};
|
||||
|
||||
Gather.prototype.toggleMapVote = function (voter, mapId) {
|
||||
this.modifyGatherer(voter, gatherer => gatherer.toggleMapVote(mapId));
|
||||
};
|
||||
|
||||
Gather.prototype.toggleServerVote = function (voter, serverId) {
|
||||
this.modifyGatherer(voter, gatherer => gatherer.toggleServerVote(serverId));
|
||||
};
|
||||
|
||||
// Returns an array of IDs representing votes for leaders
|
||||
Gather.prototype.leaderVotes = function () {
|
||||
let self = this;
|
||||
return self.gatherers
|
||||
.map(gatherer => gatherer.leaderVote)
|
||||
.filter(leaderId => typeof leaderId === 'number')
|
||||
.filter(leaderId => self.containsUser({id: leaderId}));
|
||||
};
|
||||
|
||||
Gather.prototype.voteForLeader = function (voter, candidate) {
|
||||
this.modifyGatherer(voter, gatherer => gatherer.voteForLeader(candidate));
|
||||
};
|
||||
|
||||
Gather.prototype.getGatherer = function (user) {
|
||||
return this.gatherers
|
||||
.filter(gatherer => gatherer.id === user.id)
|
||||
.pop() || null;
|
||||
};
|
||||
|
||||
Gather.prototype.regatherVotes = function () {
|
||||
let self = this;
|
||||
return self.gatherers.reduce((acc, gatherer) => {
|
||||
if (gatherer.regatherVote) acc++;
|
||||
return acc;
|
||||
}, 0);
|
||||
};
|
||||
|
||||
// Initiates a timer which will push gather into next state
|
||||
Gather.prototype.startElectionCountdown = function () {
|
||||
let self = this;
|
||||
self.election.startTime = new Date();
|
||||
this.election.timer = setTimeout(() => {
|
||||
if (self.can("electionTimeout")) self.electionTimeout();
|
||||
}, self.election.INTERVAL);
|
||||
};
|
||||
|
||||
Gather.prototype.cancelElectionCountdown = function () {
|
||||
clearTimeout(this.election.timer);
|
||||
this.election.timer = null;
|
||||
this.election.startTime = null;
|
||||
};
|
||||
|
||||
Gather.prototype.applyCooldown = function (user) {
|
||||
if (user && typeof user.id === 'number') {
|
||||
let d = new Date();
|
||||
d.setUTCSeconds(d.getUTCSeconds() + this.COOLDOWN_TIME);
|
||||
this.cooldown[user.id] = d;
|
||||
}
|
||||
};
|
||||
|
||||
Gather.prototype.needsToCoolOff = function (user) {
|
||||
if (user && typeof user.id === 'number') {
|
||||
let cooldownTime = this.cooldown[user.id];
|
||||
if (cooldownTime === undefined) return false;
|
||||
return cooldownTime > new Date();
|
||||
}
|
||||
};
|
||||
|
||||
Gather.prototype.failsTest = function (user) {
|
||||
if (!this.membershipTest) return false;
|
||||
return !this.membershipTest(user);
|
||||
};
|
||||
|
||||
Gather.prototype.getServers = function () {
|
||||
if (!this.serverMembershipTest) return Server.list;
|
||||
return Server.list.filter(this.serverMembershipTest);
|
||||
};
|
||||
|
||||
module.exports = Gather;
|
444
lib/gather/gather.mjs
Normal file
444
lib/gather/gather.mjs
Normal file
|
@ -0,0 +1,444 @@
|
|||
/*
|
||||
* Implements Gather Model
|
||||
*
|
||||
* Gather States
|
||||
* - Gathering
|
||||
* - Election (Electing leaders)
|
||||
* - Selection (Selecting teams)
|
||||
* - Done
|
||||
*
|
||||
*/
|
||||
import Gatherer from "./gatherer.mjs";
|
||||
import StateMachine from "javascript-state-machine";
|
||||
import Server from "./server.mjs";
|
||||
|
||||
class Gather {
|
||||
constructor(options) {
|
||||
if (options === undefined)
|
||||
options = {};
|
||||
if (!(this instanceof Gather)) {
|
||||
return new Gather(options);
|
||||
}
|
||||
this.gatherers = [];
|
||||
let noop = () => { };
|
||||
this.onDone = (typeof options.onDone === 'function') ?
|
||||
options.onDone : noop;
|
||||
this.onEvent = (typeof options.onEvent === 'function') ?
|
||||
options.onEvent : noop;
|
||||
this.done = {
|
||||
time: null
|
||||
};
|
||||
|
||||
this.teamSize = options.teamSize || 6;
|
||||
|
||||
// Store cooldown times for gather leaves
|
||||
this.cooldown = {};
|
||||
this.COOLDOWN_TIME = 60 * 3; // 3 Minutes
|
||||
|
||||
this.REGATHER_THRESHOLD = this.teamSize + 2;
|
||||
|
||||
this.type = options.type || "classic";
|
||||
|
||||
this.icon = options.icon || "gather icon";
|
||||
|
||||
this.name = options.name || "Classic Gather";
|
||||
|
||||
this.description = options.description || "No player requirements";
|
||||
|
||||
this.election = {
|
||||
INTERVAL: 60000,
|
||||
startTime: null,
|
||||
timer: null
|
||||
};
|
||||
|
||||
if (typeof options.membershipTest === 'function') {
|
||||
this.membershipTest = options.membershipTest.bind(this);
|
||||
}
|
||||
|
||||
if (typeof options.serverMembershipTest === 'function') {
|
||||
this.serverMembershipTest = options.serverMembershipTest.bind(this);
|
||||
}
|
||||
|
||||
this.initState();
|
||||
}
|
||||
lobbyFull() {
|
||||
return this.gatherers.length === (this.teamSize * 2);
|
||||
}
|
||||
leaderVotesFull() {
|
||||
return this.leaderVotes().length === (this.teamSize * 2);
|
||||
}
|
||||
resetState() {
|
||||
this.gatherers = [];
|
||||
this.cancelElectionCountdown();
|
||||
return this;
|
||||
}
|
||||
alienLeader() {
|
||||
return this.gatherers.reduce((acc, gatherer) => {
|
||||
if (gatherer.team === "alien" && gatherer.leader)
|
||||
acc.push(gatherer);
|
||||
return acc;
|
||||
}, []).pop();
|
||||
}
|
||||
marineLeader() {
|
||||
return this.gatherers.reduce((acc, gatherer) => {
|
||||
if (gatherer.team === "marine" && gatherer.leader)
|
||||
acc.push(gatherer);
|
||||
return acc;
|
||||
}, []).pop();
|
||||
}
|
||||
assignMarineLeader(id) {
|
||||
this.modifyGatherer({ id: id }, gatherer => {
|
||||
gatherer.leader = true;
|
||||
gatherer.team = "marine";
|
||||
});
|
||||
}
|
||||
assignAlienLeader(id) {
|
||||
this.modifyGatherer({ id: id }, gatherer => {
|
||||
gatherer.leader = true;
|
||||
gatherer.team = "alien";
|
||||
});
|
||||
}
|
||||
containsUser(user) {
|
||||
return this.gatherers.some(gatherer => {
|
||||
return gatherer.id === user.id;
|
||||
});
|
||||
}
|
||||
addUser(user) {
|
||||
if (this.containsUser(user))
|
||||
return null;
|
||||
let gatherer = new Gatherer(user);
|
||||
this.gatherers.push(gatherer);
|
||||
return gatherer;
|
||||
}
|
||||
removeUser(user) {
|
||||
this.gatherers = this.gatherers.filter(gatherer => user.id !== gatherer.id);
|
||||
}
|
||||
modifyGatherer(user, callback) {
|
||||
return this.gatherers
|
||||
.filter(gatherer => gatherer.id === user.id)
|
||||
.forEach(callback);
|
||||
}
|
||||
// 08/04/20 : 1-1-1-1-1
|
||||
// 08/11/20 : 1-2-1-1-1
|
||||
// 09/21/20 : 1-1-1-2-1
|
||||
getPickingPattern() {
|
||||
const pickingPattern = [
|
||||
"marine",
|
||||
"alien",
|
||||
"marine",
|
||||
"alien",
|
||||
"alien",
|
||||
"marine",
|
||||
"alien",
|
||||
"marine",
|
||||
"alien",
|
||||
"marine",
|
||||
"alien",
|
||||
"marine",
|
||||
];
|
||||
|
||||
return pickingPattern;
|
||||
}
|
||||
// Determines picking order of teams
|
||||
// Marine pick first
|
||||
pickingTurnIndex() {
|
||||
if (this.current !== 'selection')
|
||||
return null;
|
||||
|
||||
const captainCount = 2;
|
||||
const alienCount = this.aliens().length;
|
||||
const marineCount = this.marines().length;
|
||||
const alreadyPickedCount = (marineCount + alienCount) - captainCount;
|
||||
const pickingPattern = this.getPickingPattern();
|
||||
|
||||
const pickingTurn = alreadyPickedCount % pickingPattern.length;
|
||||
|
||||
// prevent any team from growing beyond the team size limit
|
||||
if (marineCount >= this.teamSize) {
|
||||
return "alien";
|
||||
} else if (alienCount >= this.teamSize) {
|
||||
return "marine";
|
||||
}
|
||||
|
||||
return pickingTurn;
|
||||
}
|
||||
// Moves player to marine
|
||||
// Optional `mover` argument which will check mover credentials to select
|
||||
// Credentials: Must be leader, must belong to team, must be turn to pick
|
||||
moveToMarine(user, mover) {
|
||||
if (this.marines().length >= this.teamSize)
|
||||
return;
|
||||
|
||||
if (mover && this.containsUser(mover)) {
|
||||
let leader = this.getGatherer(mover);
|
||||
if (leader.team !== "marine" ||
|
||||
!leader.leader ||
|
||||
this.getPickingPattern()[this.pickingTurnIndex()] !== "marine")
|
||||
return;
|
||||
|
||||
if (user && this.containsUser(user)) {
|
||||
if (this.getGatherer(user).team !== "lobby")
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
this.modifyGatherer(user, gatherer => gatherer.team = "marine");
|
||||
}
|
||||
// Moves player to alien
|
||||
// Optional `mover` argument which will check mover credentials to select
|
||||
// Credentials: Must be leader, must belong to team, must be turn to pick
|
||||
moveToAlien(user, mover) {
|
||||
if (this.aliens().length >= this.teamSize)
|
||||
return;
|
||||
|
||||
if (mover && this.containsUser(mover)) {
|
||||
let leader = this.getGatherer(mover);
|
||||
if (leader.team !== "alien" ||
|
||||
!leader.leader ||
|
||||
this.getPickingPattern()[this.pickingTurnIndex()] !== "alien")
|
||||
return;
|
||||
|
||||
if (user && this.containsUser(user)) {
|
||||
if (this.getGatherer(user).team !== "lobby")
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
return this.modifyGatherer(user, gatherer => gatherer.team = "alien");
|
||||
}
|
||||
moveToLobby(user) {
|
||||
this.modifyGatherer(user, gatherer => gatherer.team = "lobby");
|
||||
}
|
||||
retrieveGroup(team) {
|
||||
return this.gatherers.filter(gatherer => gatherer.team === team);
|
||||
}
|
||||
lobby() {
|
||||
return this.retrieveGroup("lobby");
|
||||
}
|
||||
aliens() {
|
||||
return this.retrieveGroup("alien");
|
||||
}
|
||||
marines() {
|
||||
return this.retrieveGroup("marine");
|
||||
}
|
||||
electionStartTime() {
|
||||
return (this.election.startTime === null) ?
|
||||
null : this.election.startTime.toISOString();
|
||||
}
|
||||
toJson() {
|
||||
return {
|
||||
name: this.name,
|
||||
icon: this.icon,
|
||||
description: this.description,
|
||||
type: this.type,
|
||||
gatherers: this.gatherers,
|
||||
servers: this.getServers(),
|
||||
state: this.current,
|
||||
pickingTurn: this.getPickingPattern()[this.pickingTurnIndex()],
|
||||
pickingTurnIndex: this.pickingTurnIndex(),
|
||||
pickingPattern: this.getPickingPattern().splice(0, this.getPickingPattern().length - 2),
|
||||
election: {
|
||||
startTime: this.electionStartTime(),
|
||||
interval: this.election.INTERVAL
|
||||
},
|
||||
teamSize: this.teamSize,
|
||||
done: {
|
||||
time: this.done.time
|
||||
},
|
||||
cooldown: this.cooldown
|
||||
};
|
||||
}
|
||||
toggleMapVote(voter, mapId) {
|
||||
this.modifyGatherer(voter, gatherer => gatherer.toggleMapVote(mapId));
|
||||
}
|
||||
toggleServerVote(voter, serverId) {
|
||||
this.modifyGatherer(voter, gatherer => gatherer.toggleServerVote(serverId));
|
||||
}
|
||||
// Returns an array of IDs representing votes for leaders
|
||||
leaderVotes() {
|
||||
let self = this;
|
||||
return self.gatherers
|
||||
.map(gatherer => gatherer.leaderVote)
|
||||
.filter(leaderId => typeof leaderId === 'number')
|
||||
.filter(leaderId => self.containsUser({ id: leaderId }));
|
||||
}
|
||||
voteForLeader(voter, candidate) {
|
||||
this.modifyGatherer(voter, gatherer => gatherer.voteForLeader(candidate));
|
||||
}
|
||||
getGatherer(user) {
|
||||
return this.gatherers
|
||||
.filter(gatherer => gatherer.id === user.id)
|
||||
.pop() || null;
|
||||
}
|
||||
regatherVotes() {
|
||||
let self = this;
|
||||
return self.gatherers.reduce((acc, gatherer) => {
|
||||
if (gatherer.regatherVote)
|
||||
acc++;
|
||||
return acc;
|
||||
}, 0);
|
||||
}
|
||||
// Initiates a timer which will push gather into next state
|
||||
startElectionCountdown() {
|
||||
let self = this;
|
||||
self.election.startTime = new Date();
|
||||
this.election.timer = setTimeout(() => {
|
||||
if (self.can("electionTimeout"))
|
||||
self.electionTimeout();
|
||||
}, self.election.INTERVAL);
|
||||
}
|
||||
cancelElectionCountdown() {
|
||||
clearTimeout(this.election.timer);
|
||||
this.election.timer = null;
|
||||
this.election.startTime = null;
|
||||
}
|
||||
applyCooldown(user) {
|
||||
if (user && typeof user.id === 'number') {
|
||||
let d = new Date();
|
||||
d.setUTCSeconds(d.getUTCSeconds() + this.COOLDOWN_TIME);
|
||||
this.cooldown[user.id] = d;
|
||||
}
|
||||
}
|
||||
needsToCoolOff(user) {
|
||||
if (user && typeof user.id === 'number') {
|
||||
let cooldownTime = this.cooldown[user.id];
|
||||
if (cooldownTime === undefined)
|
||||
return false;
|
||||
return cooldownTime > new Date();
|
||||
}
|
||||
}
|
||||
failsTest(user) {
|
||||
if (!this.membershipTest)
|
||||
return false;
|
||||
return !this.membershipTest(user);
|
||||
}
|
||||
getServers() {
|
||||
if (!this.serverMembershipTest)
|
||||
return Server.list;
|
||||
return Server.list.filter(this.serverMembershipTest);
|
||||
}
|
||||
}
|
||||
|
||||
StateMachine.create({
|
||||
target: Gather.prototype,
|
||||
events: [
|
||||
{ name: "initState", from: "none", to: "gathering" },
|
||||
{ name: "addGatherer", from: "gathering", to: "election" },
|
||||
{ name: "selectLeader", from: "election", to: "selection" },
|
||||
{ name: "electionTimeout", from: "election", to: "selection" },
|
||||
{ name: "confirmSelection", from: "selection", to: "done" },
|
||||
{
|
||||
name: "removeGatherer",
|
||||
from: ["gathering", "election", "selection"],
|
||||
to: "gathering"
|
||||
},
|
||||
{
|
||||
name: "regather",
|
||||
from: ["gathering", "election", "selection"],
|
||||
to: "gathering"
|
||||
}
|
||||
],
|
||||
callbacks: {
|
||||
// Callbacks for events
|
||||
onafterevent: function () {
|
||||
this.onEvent.apply(this, [].slice.call(arguments));
|
||||
},
|
||||
|
||||
// Gathering State
|
||||
onbeforeaddGatherer: function (event, from, to, user) {
|
||||
if (this.needsToCoolOff(user)) return false;
|
||||
if (this.failsTest(user)) return false;
|
||||
this.addUser(user);
|
||||
if (!this.lobbyFull()) {
|
||||
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
// Election State
|
||||
onbeforeselectLeader: function (event, from, to, voter, candidate) {
|
||||
this.voteForLeader(voter, candidate);
|
||||
if (!this.leaderVotesFull()) return false;
|
||||
},
|
||||
|
||||
onenterelection: function () {
|
||||
// discordBot.notifyChannel("Gather is starting! Pick your captains at https://gathers.ensl.org");
|
||||
// Setup timer for elections
|
||||
this.startElectionCountdown();
|
||||
},
|
||||
|
||||
onleaveelection: function () {
|
||||
this.cancelElectionCountdown();
|
||||
},
|
||||
|
||||
// Selection State
|
||||
onenterselection: function () {
|
||||
// Remove all leaders and teams
|
||||
this.gatherers.forEach(gatherer => {
|
||||
gatherer.leader = false;
|
||||
gatherer.team = "lobby";
|
||||
});
|
||||
|
||||
// Assign leaders based on vote
|
||||
// 1st place alien comm
|
||||
// 2nd place marine comm
|
||||
let voteCount = {};
|
||||
this.gatherers.forEach(gatherer => { voteCount[gatherer.id] = 0 });
|
||||
this.leaderVotes().forEach(candidateId => { voteCount[candidateId]++ });
|
||||
let rank = [];
|
||||
for (let candidate in voteCount) {
|
||||
rank.push({ candidate: candidate, count: voteCount[candidate] });
|
||||
}
|
||||
rank.sort((a, b) => {
|
||||
return a.count - b.count;
|
||||
});
|
||||
this.assignAlienLeader(parseInt(rank.pop().candidate, 0));
|
||||
this.assignMarineLeader(parseInt(rank.pop().candidate, 0));
|
||||
},
|
||||
|
||||
onleaveselection: function (event, from, to, voter, candidate) {
|
||||
if (event === "removeGatherer" || event === "regather") {
|
||||
this.gatherers.forEach(gatherer => {
|
||||
gatherer.team = "lobby";
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
onbeforeconfirmSelection: function (event, from, to, leader) {
|
||||
return (this.aliens().length === this.teamSize
|
||||
&& this.marines().length === this.teamSize);
|
||||
},
|
||||
|
||||
// Remove gatherer event
|
||||
onbeforeremoveGatherer: function (event, from, to, user) {
|
||||
// Cancel transition if no gatherers have been removed
|
||||
let userCount = this.gatherers.length;
|
||||
this.removeUser(user);
|
||||
let userRemoved = userCount > this.gatherers.length;
|
||||
if (userRemoved && from !== 'gathering') this.applyCooldown(user);
|
||||
return userRemoved;
|
||||
},
|
||||
|
||||
// Set gatherer vote & if threshold met, reset gather
|
||||
onbeforeregather: function (event, from, to, user, vote) {
|
||||
let self = this;
|
||||
self.modifyGatherer(user, (gatherer) => gatherer.voteRegather(vote));
|
||||
if (self.regatherVotes() >= self.REGATHER_THRESHOLD) {
|
||||
self.resetState();
|
||||
// discordBot.notifyChannel("@here Gather was reset! Rejoin to play!");
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
// On enter done
|
||||
onenterdone: function () {
|
||||
// discordBot.notifyChannel("Picking finished! Join the server!");
|
||||
this.done.time = new Date();
|
||||
this.onDone.apply(this, [].slice.call(arguments));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
export default Gather;
|
|
@ -1,19 +1,18 @@
|
|||
"use strict"
|
||||
|
||||
/*
|
||||
* Implements a pool of concurrent gathers
|
||||
* (no longer a singleton class, should rename)
|
||||
*
|
||||
*/
|
||||
import _ from "lodash";
|
||||
import winston from "winston"
|
||||
import mongoose from "mongoose";
|
||||
import Gather from "./gather.mjs";
|
||||
import InvitationalGather from "./invitational_gather.mjs";
|
||||
|
||||
const _ = require("lodash");
|
||||
const Gather = require("./gather");
|
||||
const winston = require("winston");
|
||||
const mongoose = require("mongoose");
|
||||
const ArchivedGather = mongoose.model("ArchivedGather");
|
||||
const InvitationalGather = require("./invitational_gather");
|
||||
|
||||
let gatherCallbacks = {};
|
||||
let archiveUpdatedCallback = () => {};
|
||||
let archiveUpdatedCallback = () => { };
|
||||
|
||||
const GatherPool = new Map();
|
||||
const GATHER_CONFIGS = [
|
||||
|
@ -26,34 +25,28 @@ const GATHER_CONFIGS = [
|
|||
return server.name.toLowerCase().indexOf("promod") === -1;
|
||||
}
|
||||
},
|
||||
/*{
|
||||
type: "progmod",
|
||||
icon: '/progmodGather.png',
|
||||
name: "Progressive Mod Gather",
|
||||
{
|
||||
type: "novice",
|
||||
icon: "/normalGather.png",
|
||||
name: "Novice Gather",
|
||||
description: "No Requirements",
|
||||
serverMembershipTest: function (server) {
|
||||
return server.name.toLowerCase().indexOf("promod") !== -1;
|
||||
}
|
||||
},*/
|
||||
return server.name.toLowerCase().indexOf("promod") === -1;
|
||||
},
|
||||
},
|
||||
{
|
||||
type: "invitational",
|
||||
icon: "/inviteGather.png",
|
||||
name: "Invitational Gather",
|
||||
description: "Join on ensl.org/teams/949",
|
||||
// Grant invite if on a particular nsl team
|
||||
membershipTest: function (user) {
|
||||
return InvitationalGather.list.some(m => m.id === user.id);
|
||||
},
|
||||
serverMembershipTest: function (server) {
|
||||
return server.name.toLowerCase().indexOf("promod") === -1;
|
||||
},
|
||||
}
|
||||
// {
|
||||
// type: "casual",
|
||||
// name: "Casual Gather",
|
||||
// description: "No Requirements",
|
||||
// teamSize: 7
|
||||
// }
|
||||
icon: "/inviteGather.png",
|
||||
name: "Invitational Gather",
|
||||
description: "Join on ensl.org/teams/949",
|
||||
// Grant invite if on a particular nsl team
|
||||
membershipTest: function (user) {
|
||||
return InvitationalGather.list.some(m => m.id === user.id);
|
||||
},
|
||||
serverMembershipTest: function (server) {
|
||||
return server.name.toLowerCase().indexOf("promod") === -1;
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
GATHER_CONFIGS.forEach(config => {
|
||||
|
@ -79,11 +72,11 @@ GATHER_CONFIGS.forEach(config => {
|
|||
reset: function () {
|
||||
return newGather();
|
||||
},
|
||||
current: Gather(),
|
||||
current: new Gather(),
|
||||
previous: undefined,
|
||||
gatherCallbacks: {}
|
||||
};
|
||||
|
||||
|
||||
gatherManager.gatherCallbacks['onDone'] = [function () {
|
||||
rotateGather();
|
||||
}];
|
||||
|
@ -103,13 +96,13 @@ GATHER_CONFIGS.forEach(config => {
|
|||
});
|
||||
};
|
||||
|
||||
return gatherManager.current = Gather(newGatherConfig);
|
||||
return gatherManager.current = new Gather(newGatherConfig);
|
||||
};
|
||||
|
||||
const archiveGather = gather => {
|
||||
ArchivedGather.archive(gather, (error, result) => {
|
||||
if (error) return winston.error(error);
|
||||
if (archiveUpdatedCallback
|
||||
if (archiveUpdatedCallback
|
||||
&& typeof archiveUpdatedCallback === 'function') {
|
||||
archiveUpdatedCallback();
|
||||
}
|
||||
|
@ -130,4 +123,4 @@ GATHER_CONFIGS.forEach(config => {
|
|||
|
||||
// Register initial callback to reset gather when state is `done`
|
||||
|
||||
module.exports = GatherPool;
|
||||
export default GatherPool;
|
|
@ -1,69 +0,0 @@
|
|||
"use strict";
|
||||
|
||||
/*
|
||||
* Implements Gatherer
|
||||
*
|
||||
* Stores necessary information including:
|
||||
* - user data
|
||||
* - voting preferences
|
||||
* - leader status
|
||||
* - Team: "lobby" "alien" "marine"
|
||||
*/
|
||||
|
||||
var User = require("../user/user");
|
||||
|
||||
var MAX_MAP_VOTES = 2;
|
||||
var MAX_SERVER_VOTES = 2;
|
||||
|
||||
function Gatherer (user) {
|
||||
this.leaderVote = null;
|
||||
this.mapVote = [];
|
||||
this.serverVote = [];
|
||||
this.confirm = false;
|
||||
this.id = user.id;
|
||||
this.user = user;
|
||||
this.leader = false;
|
||||
this.team = "lobby";
|
||||
this.regatherVote = false;
|
||||
};
|
||||
|
||||
Gatherer.prototype.toggleMapVote = function (mapId) {
|
||||
if (this.mapVote.some(votedId => votedId === mapId)) {
|
||||
this.mapVote = this.mapVote.filter(voteId => voteId !== mapId);
|
||||
return;
|
||||
}
|
||||
this.mapVote.push(mapId);
|
||||
this.mapVote = this.mapVote.slice(this.mapVote.length - MAX_MAP_VOTES,
|
||||
this.mapVote.length);
|
||||
};
|
||||
|
||||
Gatherer.prototype.toggleServerVote = function (serverId) {
|
||||
if (this.serverVote.some(votedId => votedId === serverId)) {
|
||||
this.serverVote = this.serverVote.filter(voteId => voteId !== serverId);
|
||||
return;
|
||||
}
|
||||
this.serverVote.push(serverId);
|
||||
this.serverVote = this.serverVote.slice(this.serverVote.length -
|
||||
MAX_SERVER_VOTES, this.serverVote.length);
|
||||
};
|
||||
|
||||
Gatherer.prototype.voteForLeader = function (candidate) {
|
||||
if (candidate === null) {
|
||||
return this.leaderVote = null;
|
||||
}
|
||||
if (typeof candidate === 'number') {
|
||||
return this.leaderVote = candidate;
|
||||
}
|
||||
this.leaderVote = candidate.id;
|
||||
};
|
||||
|
||||
Gatherer.prototype.voteRegather = function (vote) {
|
||||
if (vote !== undefined && typeof vote === 'boolean') {
|
||||
return this.regatherVote = vote;
|
||||
} else {
|
||||
this.regatherVote = true;
|
||||
}
|
||||
return this.regatherVote;
|
||||
};
|
||||
|
||||
module.exports = Gatherer;
|
67
lib/gather/gatherer.mjs
Normal file
67
lib/gather/gatherer.mjs
Normal file
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* Implements Gatherer
|
||||
*
|
||||
* Stores necessary information including:
|
||||
* - user data
|
||||
* - voting preferences
|
||||
* - leader status
|
||||
* - Team: "lobby" "alien" "marine"
|
||||
*/
|
||||
|
||||
var MAX_MAP_VOTES = 2;
|
||||
var MAX_SERVER_VOTES = 2;
|
||||
|
||||
class Gatherer {
|
||||
constructor(user) {
|
||||
this.leaderVote = null;
|
||||
this.mapVote = [];
|
||||
this.serverVote = [];
|
||||
this.confirm = false;
|
||||
this.id = user.id;
|
||||
this.user = user;
|
||||
this.leader = false;
|
||||
this.team = "lobby";
|
||||
this.regatherVote = false;
|
||||
}
|
||||
toggleMapVote(mapId) {
|
||||
if (this.mapVote.some(votedId => votedId === mapId)) {
|
||||
this.mapVote = this.mapVote.filter(voteId => voteId !== mapId);
|
||||
return;
|
||||
}
|
||||
this.mapVote.push(mapId);
|
||||
this.mapVote = this.mapVote.slice(this.mapVote.length - MAX_MAP_VOTES,
|
||||
this.mapVote.length);
|
||||
}
|
||||
toggleServerVote(serverId) {
|
||||
if (this.serverVote.some(votedId => votedId === serverId)) {
|
||||
this.serverVote = this.serverVote.filter(voteId => voteId !== serverId);
|
||||
return;
|
||||
}
|
||||
this.serverVote.push(serverId);
|
||||
this.serverVote = this.serverVote.slice(this.serverVote.length -
|
||||
MAX_SERVER_VOTES, this.serverVote.length);
|
||||
}
|
||||
voteForLeader(candidate) {
|
||||
if (candidate === null) {
|
||||
return this.leaderVote = null;
|
||||
}
|
||||
if (typeof candidate === 'number') {
|
||||
return this.leaderVote = candidate;
|
||||
}
|
||||
this.leaderVote = candidate.id;
|
||||
}
|
||||
voteRegather(vote) {
|
||||
if (vote !== undefined && typeof vote === 'boolean') {
|
||||
return this.regatherVote = vote;
|
||||
} else {
|
||||
this.regatherVote = true;
|
||||
}
|
||||
return this.regatherVote;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
export default Gatherer;
|
|
@ -1,11 +1,8 @@
|
|||
"use strict";
|
||||
import { parallel } from "async";
|
||||
import { getRandomUser } from "../user/helper.mjs";
|
||||
|
||||
var User = require("../user/user");
|
||||
var client = require("../ensl/client")();
|
||||
var async = require("async");
|
||||
var getRandomUser = require("../user/helper").getRandomUser;
|
||||
|
||||
var createTestUsers = (options, callback) => {
|
||||
export const createTestUsers = (options, callback) => {
|
||||
var gather = options.gather;
|
||||
|
||||
var instructions = [];
|
||||
|
@ -21,7 +18,7 @@ var createTestUsers = (options, callback) => {
|
|||
});
|
||||
};
|
||||
|
||||
async.parallel(instructions, (error) => {
|
||||
parallel(instructions, (error) => {
|
||||
if (error) {
|
||||
console.log("Error while adding gatherers", error);
|
||||
} else {
|
||||
|
@ -36,6 +33,6 @@ var createTestUsers = (options, callback) => {
|
|||
});
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
createTestUsers: createTestUsers
|
||||
export default {
|
||||
createTestUsers
|
||||
};
|
|
@ -1,32 +0,0 @@
|
|||
"use strict";
|
||||
|
||||
const winston = require("winston");
|
||||
const env = process.env.NODE_ENV || "development";
|
||||
const client = require("../ensl/client")();
|
||||
const REFRESH_INTERVAL = 1000 * 60; // Check every minute
|
||||
const invitationalTeamId = 949;
|
||||
|
||||
function InvitationalGather () {
|
||||
|
||||
}
|
||||
|
||||
InvitationalGather.list = [];
|
||||
|
||||
InvitationalGather.updateList = function () {
|
||||
client.getTeamById({
|
||||
id: invitationalTeamId
|
||||
}, (error, result) => {
|
||||
if (error) {
|
||||
winston.error("Unable to download team list")
|
||||
winston.error(error);
|
||||
return;
|
||||
};
|
||||
InvitationalGather.list = result.body.members;
|
||||
});
|
||||
};
|
||||
|
||||
InvitationalGather.updateList();
|
||||
|
||||
setInterval(InvitationalGather.updateList, REFRESH_INTERVAL);
|
||||
|
||||
module.exports = InvitationalGather;
|
29
lib/gather/invitational_gather.mjs
Normal file
29
lib/gather/invitational_gather.mjs
Normal file
|
@ -0,0 +1,29 @@
|
|||
import winston from "winston";
|
||||
import EnslClient from "../ensl/client.mjs";
|
||||
|
||||
const env = process.env.NODE_ENV || "development";
|
||||
const client = new EnslClient();
|
||||
const REFRESH_INTERVAL = 1000 * 60; // Check every minute
|
||||
const invitationalTeamId = 949;
|
||||
|
||||
class InvitationalGather {
|
||||
static list = [];
|
||||
static updateList = function () {
|
||||
client.getTeamById({
|
||||
id: invitationalTeamId
|
||||
}, (error, result) => {
|
||||
if (error) {
|
||||
winston.error("Unable to download team list")
|
||||
winston.error(error);
|
||||
return;
|
||||
};
|
||||
InvitationalGather.list = result.body.members;
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
InvitationalGather.updateList();
|
||||
|
||||
setInterval(InvitationalGather.updateList, REFRESH_INTERVAL);
|
||||
|
||||
export default InvitationalGather;
|
|
@ -1,31 +0,0 @@
|
|||
"use strict";
|
||||
|
||||
var fs = require("fs");
|
||||
var path = require("path");
|
||||
var winston = require("winston");
|
||||
var client = require(path.join(__dirname, "../ensl/client"))();
|
||||
const mapsPath = path.join(__dirname, "../../config/data/maps.json");
|
||||
const REFRESH_INTERVAL = 1000 * 60 * 60; // Check every hour
|
||||
|
||||
function Map () {
|
||||
|
||||
}
|
||||
|
||||
Map.list = JSON.parse(fs.readFileSync(mapsPath)).maps;
|
||||
|
||||
Map.updateMapList = () => {
|
||||
client.getMaps((error, result) => {
|
||||
if (error) {
|
||||
winston.error("Unable to download server list")
|
||||
winston.error(error);
|
||||
return;
|
||||
};
|
||||
Map.list = result.maps;
|
||||
});
|
||||
};
|
||||
|
||||
Map.updateMapList();
|
||||
|
||||
setInterval(Map.updateMapList, REFRESH_INTERVAL);
|
||||
|
||||
module.exports = Map;
|
29
lib/gather/map.mjs
Normal file
29
lib/gather/map.mjs
Normal file
|
@ -0,0 +1,29 @@
|
|||
import fs from "fs";
|
||||
import {resolve} from "path";
|
||||
import winston from "winston";
|
||||
import EnslClient from "../ensl/client.mjs";
|
||||
|
||||
const client = new EnslClient();
|
||||
const mapsPath = resolve("config/data/maps.json");
|
||||
const REFRESH_INTERVAL = 1000 * 60 * 60; // Check every hour
|
||||
|
||||
|
||||
|
||||
class Map {
|
||||
static list = JSON.parse(fs.readFileSync(mapsPath)).maps;
|
||||
static updateMapList = () => {
|
||||
client.getMaps((error, result) => {
|
||||
if (error) {
|
||||
winston.error("Unable to download server list")
|
||||
winston.error(error);
|
||||
return;
|
||||
};
|
||||
Map.list = result.maps;
|
||||
});
|
||||
};
|
||||
}
|
||||
Map.updateMapList();
|
||||
|
||||
setInterval(Map.updateMapList, REFRESH_INTERVAL);
|
||||
|
||||
export default Map;
|
|
@ -1,32 +0,0 @@
|
|||
"use strict";
|
||||
|
||||
var fs = require("fs");
|
||||
var path = require("path");
|
||||
var winston = require("winston");
|
||||
var client = require(path.join(__dirname, "../ensl/client"))();
|
||||
var serverFile = path.join(__dirname, "../../config/data/servers.json");
|
||||
|
||||
const REFRESH_INTERVAL = 1000 * 60 * 60; // Check every hour
|
||||
|
||||
function Server () {
|
||||
|
||||
}
|
||||
|
||||
Server.list = JSON.parse(fs.readFileSync(serverFile)).servers;
|
||||
|
||||
Server.updateServerList = () => {
|
||||
client.getServers((error, result) => {
|
||||
if (error) {
|
||||
winston.error("Unable to download server list")
|
||||
winston.error(error);
|
||||
return;
|
||||
};
|
||||
Server.list = result.servers;
|
||||
});
|
||||
};
|
||||
|
||||
Server.updateServerList();
|
||||
|
||||
setInterval(Server.updateServerList, REFRESH_INTERVAL);
|
||||
|
||||
module.exports = Server;
|
30
lib/gather/server.mjs
Normal file
30
lib/gather/server.mjs
Normal file
|
@ -0,0 +1,30 @@
|
|||
import fs from "fs";
|
||||
import {resolve} from "path";
|
||||
import winston from "winston";
|
||||
import EnslClient from "../ensl/client.mjs";
|
||||
|
||||
const client = new EnslClient();
|
||||
const serverFile = resolve("config/data/servers.json");
|
||||
|
||||
const REFRESH_INTERVAL = 1000 * 60 * 60; // Check every hour
|
||||
|
||||
class Server {
|
||||
static list = JSON.parse(fs.readFileSync(serverFile)).servers;
|
||||
static updateServerList = () => {
|
||||
client.getServers((error, result) => {
|
||||
if (error) {
|
||||
winston.error("Unable to download server list")
|
||||
winston.error(error);
|
||||
return;
|
||||
};
|
||||
Server.list = result.servers;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Server.updateServerList();
|
||||
setInterval(Server.updateServerList, REFRESH_INTERVAL);
|
||||
|
||||
export default Server;
|
||||
|
|
@ -1,40 +0,0 @@
|
|||
"use strict";
|
||||
|
||||
const { response } = require("express");
|
||||
const path = require("path");
|
||||
const { env } = require("process");
|
||||
const request = require("request");
|
||||
const logger = require("winston");
|
||||
const UserStatisticsWrapper = require("./stats_wrapper");
|
||||
const config = require(path.join(__dirname, "../../config/config"));
|
||||
const statFile = path.join(__dirname, "../../config/data/hive_stats.json")
|
||||
|
||||
|
||||
function HiveClient(options) {
|
||||
if (!(this instanceof HiveClient)) {
|
||||
return new HiveClient(options);
|
||||
}
|
||||
}
|
||||
|
||||
HiveClient.prototype.getUserStats = function (user, callback) {
|
||||
if (!user || !user.steam.id) {
|
||||
return callback(new Error("Invalid user instance supplied"));
|
||||
}
|
||||
if (!process.env.NODE_ENV === 'production') {
|
||||
var stats = JSON.parse(fs.readFileSync(statFile));
|
||||
return callback(null, new UserStatisticsWrapper(stats["playerstats"]));
|
||||
} else {
|
||||
return request({
|
||||
url: `https://api.steampowered.com/ISteamUserStats/GetUserStatsForGame/v2/?key=${config.steam.api_key}&steamid=${user.steam.id}&appid=4920`,
|
||||
json: true
|
||||
}, (error, _response, stats) => {
|
||||
if (response.statusCode !== 200) {
|
||||
return callback(error, null);
|
||||
}
|
||||
return callback(error, new UserStatisticsWrapper(stats["playerstats"]));
|
||||
});
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
module.exports = HiveClient;
|
41
lib/hive/client.mjs
Normal file
41
lib/hive/client.mjs
Normal file
|
@ -0,0 +1,41 @@
|
|||
"use strict";
|
||||
|
||||
import { response } from "express";
|
||||
import { resolve } from "path";
|
||||
import fs from "fs";
|
||||
import request from "request";
|
||||
import UserStatisticsWrapper from "./stats_wrapper.mjs";
|
||||
import config from "../../config/config.mjs"
|
||||
const statFile = resolve("config/data/hive_stats.json")
|
||||
|
||||
|
||||
class HiveClient {
|
||||
constructor(options) {
|
||||
if (!(this instanceof HiveClient)) {
|
||||
return new HiveClient(options);
|
||||
}
|
||||
}
|
||||
getUserStats(user, callback) {
|
||||
if (!user || !user.steam.id) {
|
||||
return callback(new Error("Invalid user instance supplied"));
|
||||
}
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
return request({
|
||||
url: `https://api.steampowered.com/ISteamUserStats/GetUserStatsForGame/v2/?key=${config.steam.api_key}&steamid=${user.steam.id}&appid=4920`,
|
||||
json: true
|
||||
}, (error, _response, stats) => {
|
||||
if (response.statusCode !== 200) {
|
||||
return callback(error, null);
|
||||
}
|
||||
return callback(error, new UserStatisticsWrapper(stats["playerstats"]));
|
||||
});
|
||||
} else {
|
||||
var stats = JSON.parse(fs.readFileSync(statFile));
|
||||
return callback(null, new UserStatisticsWrapper(stats["playerstats"]));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export default HiveClient;
|
|
@ -1,29 +0,0 @@
|
|||
"use strict";
|
||||
|
||||
// UserStatistics constructor parses Steam ISteamUserStats responses into
|
||||
// unified statistical interface
|
||||
|
||||
// StatAttributes also provides default value as fallback
|
||||
const StatAttributes = {
|
||||
level: (stats, apiValue) => { stats['level'] = apiValue },
|
||||
score: (stats, apiValue) => { stats['score'] = apiValue },
|
||||
skill: (stats, apiValue) => { stats['score'] = apiValue },
|
||||
td_rounds_won_player: (stats, apiValue) => {stats['player_wins'] = apiValue },
|
||||
td_rounds_won_commander: (stats, apiValue) => {stats['comm_wins'] = apiValue },
|
||||
skill: (stats, apiValue) => {stats['skill'] = apiValue },
|
||||
comm_skill: (stats, apiValue) => {stats['comm_skill'] = apiValue },
|
||||
td_total_time_player: (stats, apiValue) => {stats['player_time'] = apiValue },
|
||||
td_total_time_commander: (stats, apiValue) => {stats['commander_time'] = apiValue },
|
||||
};
|
||||
const NoopSetter = (_stats, _apiValue) => {};
|
||||
|
||||
function UserStatisticsWrapper (apiResponse = {}) {
|
||||
this["steamId"] = apiResponse.steamID
|
||||
var stats = apiResponse.stats || {};
|
||||
for(attribute in stats) {
|
||||
var setter = StatAttributes[attribute.name] || NoopSetter;
|
||||
setter(this,attribute.value);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = UserStatisticsWrapper;
|
31
lib/hive/stats_wrapper.mjs
Normal file
31
lib/hive/stats_wrapper.mjs
Normal file
|
@ -0,0 +1,31 @@
|
|||
// UserStatistics constructor parses Steam ISteamUserStats responses into
|
||||
// unified statistical interface
|
||||
|
||||
import { stat } from "fs";
|
||||
|
||||
// StatAttributes also provides default value as fallback
|
||||
const StatAttributes = {
|
||||
level: (stats, apiValue) => { stats['level'] = apiValue },
|
||||
score: (stats, apiValue) => { stats['score'] = apiValue },
|
||||
skill: (stats, apiValue) => { stats['score'] = apiValue },
|
||||
td_rounds_won_player: (stats, apiValue) => { stats['player_wins'] = apiValue },
|
||||
td_rounds_won_commander: (stats, apiValue) => { stats['comm_wins'] = apiValue },
|
||||
skill: (stats, apiValue) => { stats['skill'] = apiValue },
|
||||
comm_skill: (stats, apiValue) => { stats['comm_skill'] = apiValue },
|
||||
td_total_time_player: (stats, apiValue) => { stats['player_time'] = apiValue },
|
||||
td_total_time_commander: (stats, apiValue) => { stats['commander_time'] = apiValue },
|
||||
};
|
||||
const NoopSetter = (_stats, _apiValue) => { };
|
||||
|
||||
class UserStatisticsWrapper {
|
||||
constructor(apiResponse = {}) {
|
||||
this["steamId"] = apiResponse.steamID;
|
||||
var stats = apiResponse.stats || [];
|
||||
stats.forEach(element => {
|
||||
var setter = StatAttributes[element.name] || NoopSetter;
|
||||
setter(this, element.value);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default UserStatisticsWrapper;
|
|
@ -1,94 +0,0 @@
|
|||
"use strict";
|
||||
|
||||
var _ = require("lodash");
|
||||
var steam = require("steam");
|
||||
var winston = require("winston");
|
||||
var password = process.env.GATHER_STEAM_PASSWORD;
|
||||
var account_name = process.env.GATHER_STEAM_ACCOUNT;
|
||||
var GatherPool = require("../gather/gather_pool");
|
||||
|
||||
function SteamBot(config) {
|
||||
let self = this;
|
||||
self.client = new steam.SteamClient();
|
||||
self.user = new steam.SteamUser(self.client);
|
||||
self.friends = new steam.SteamFriends(self.client);
|
||||
|
||||
let addToGather = (steamId, message) => {
|
||||
self.friends.sendMessage(steamId, "Added you to the gather");
|
||||
};
|
||||
|
||||
let removeFromGather = (steamId, message) => {
|
||||
self.friends.sendMessage(steamId, "Removed your from gather");
|
||||
};
|
||||
|
||||
let returnGatherInfo = (steamId, _) => {
|
||||
let gather = GatherPool.get("public").current;
|
||||
let state = gather.current.toUpperCase();
|
||||
let players = gather.gatherers.length;
|
||||
let message = "Current Gather: " + state + " (" + players + "/12 Players)";
|
||||
self.friends.sendMessage(steamId, message);
|
||||
};
|
||||
|
||||
let showHelp = (steamId, message) => {
|
||||
self.friends.sendMessage(steamId, "Bot Commands:");
|
||||
self.friends.sendMessage(steamId, "!info - Get information on current gather");
|
||||
// self.friends.sendMessage(steamId, "!join - Join current gather");
|
||||
// self.friends.sendMessage(steamId, "!leave - Leave current gather");
|
||||
};
|
||||
|
||||
let confirmFriend = steamId => {
|
||||
self.friends.addFriend(steamId);
|
||||
self.friends.sendMessage(steamId, "You're now registered on the ENSL Gather Bot. Type !help to find out how to interact");
|
||||
};
|
||||
|
||||
self.client.on("connected", () => {
|
||||
self.user.logOn(config);
|
||||
});
|
||||
|
||||
self.client.on("error", error => {
|
||||
winston.error(error);
|
||||
winston.info("Reconnecting steam bot in 5 seconds");
|
||||
setTimeout(() => {
|
||||
self.client.connect();
|
||||
}, 5000);
|
||||
});
|
||||
|
||||
self.client.on('logOnResponse', logonResp => {
|
||||
if (logonResp.eresult == steam.EResult.OK) {
|
||||
winston.info("Logged onto Steam");
|
||||
|
||||
// Go online
|
||||
self.friends.setPersonaState(steam.EPersonaState.Online);
|
||||
|
||||
// Accept backlog of friend request
|
||||
for (let friend in self.friends.friends) {
|
||||
if (self.friends.friends[friend] < 3) confirmFriend(friend);
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
self.friends.on('friend', (steamId, relationship) => {
|
||||
if (steam.EFriendRelationship.RequestRecipient === relationship) {
|
||||
confirmFriend(steamId);
|
||||
}
|
||||
});
|
||||
|
||||
self.friends.on('friendMsg', (steamId, message, EChatEntryType) => {
|
||||
winston.info(message);
|
||||
if (message.match(/^!help/i)) return showHelp(steamId, message);
|
||||
// if (message.match(/^!join/i)) return addToGather(steamId, message);
|
||||
// if (message.match(/^!leave/i)) return removeFromGather(steamId, message);
|
||||
if (message.match(/^!info/i)) return returnGatherInfo(steamId, message);
|
||||
});
|
||||
|
||||
self.client.connect();
|
||||
}
|
||||
|
||||
var bot;
|
||||
|
||||
module.exports = config => {
|
||||
if (bot) return bot;
|
||||
if (!config) throw new Error("No credentials provided for Steam Gather Bot");
|
||||
bot = new SteamBot(config);
|
||||
return bot;
|
||||
};
|
|
@ -1,5 +1,3 @@
|
|||
"use strict";
|
||||
|
||||
/*
|
||||
* User Controller
|
||||
*
|
||||
|
@ -14,24 +12,23 @@
|
|||
*
|
||||
*/
|
||||
|
||||
import winston from "winston";
|
||||
import _ from "lodash";
|
||||
|
||||
import User from "./user.mjs";
|
||||
|
||||
var userCache = {};
|
||||
var User = require("./user");
|
||||
var winston = require("winston");
|
||||
var mongoose = require("mongoose");
|
||||
var Session = mongoose.model("Session");
|
||||
var enslClient = require("../ensl/client")();
|
||||
var _ = require("lodash");
|
||||
|
||||
module.exports = namespace => {
|
||||
var refreshUsers = socket => {
|
||||
var receivers = (socket !== undefined) ? [socket] : namespace.sockets;
|
||||
export default namespace => {
|
||||
var refreshUsers = socket => {
|
||||
var receivers = (socket !== undefined) ? [socket] : namespace.sockets;
|
||||
|
||||
var newCache = {};
|
||||
for(let socketid in namespace.sockets) {
|
||||
let socket = namespace.sockets[socketid];
|
||||
var user = socket._user;
|
||||
var newCache = {};
|
||||
for (let socketid in namespace.sockets) {
|
||||
let socket = namespace.sockets[socketid];
|
||||
var user = socket._user;
|
||||
newCache[user.id] = user;
|
||||
}
|
||||
}
|
||||
|
||||
userCache = newCache;
|
||||
|
||||
|
@ -44,14 +41,14 @@ module.exports = namespace => {
|
|||
}
|
||||
|
||||
|
||||
for(let socketid in receivers) {
|
||||
let socket = receivers[socketid];
|
||||
socket.emit('users:update', {
|
||||
for (let socketid in receivers) {
|
||||
let socket = receivers[socketid];
|
||||
socket.emit('users:update', {
|
||||
count: users.length,
|
||||
users: users,
|
||||
currentUser: socket._user
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
namespace.on('connection', socket => {
|
||||
|
@ -72,7 +69,7 @@ module.exports = namespace => {
|
|||
|
||||
socket.on('users:disconnect', data => {
|
||||
const id = data.id;
|
||||
if (typeof id !== 'number' || !socket._user.admin) return;
|
||||
if (typeof id !== 'number' || !socket._user.admin) return;
|
||||
Object.values(namespace.sockets)
|
||||
.filter(socket => socket._user.id === id)
|
||||
.forEach(socket => socket.disconnect());
|
||||
|
@ -93,6 +90,6 @@ module.exports = namespace => {
|
|||
});
|
||||
});
|
||||
|
||||
socket.on('disconnect', socket => { refreshUsers(); });
|
||||
socket.on('disconnect', socket => { refreshUsers(); });
|
||||
});
|
||||
};
|
|
@ -1,8 +1,6 @@
|
|||
"use strict";
|
||||
import User from "./user.mjs";
|
||||
|
||||
const User = require("../user/user");
|
||||
|
||||
const getRandomUser = callback => {
|
||||
export const getRandomUser = callback => {
|
||||
const id = Math.floor(Math.random() * 5000) + 1;
|
||||
User.find(id, function (error, user) {
|
||||
if (error) return getRandomUser(callback);
|
||||
|
@ -10,14 +8,16 @@ const getRandomUser = callback => {
|
|||
})
|
||||
};
|
||||
|
||||
const getFixedUser = (id, callback) => {
|
||||
export const getFixedUser = (id, callback) => {
|
||||
User.find(id, function (error, user) {
|
||||
if (error) return getRandomUser(callback);
|
||||
return callback(error, user);
|
||||
})
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
|
||||
|
||||
export default {
|
||||
getRandomUser,
|
||||
getFixedUser
|
||||
};
|
115
lib/user/user.js
115
lib/user/user.js
|
@ -1,115 +0,0 @@
|
|||
"use strict";
|
||||
|
||||
/*
|
||||
* Implements User Model
|
||||
*
|
||||
*/
|
||||
|
||||
var _ = require("lodash");
|
||||
var async = require("async");
|
||||
var mongoose = require("mongoose");
|
||||
var Profile = mongoose.model("Profile");
|
||||
var steam = require('steamidconvert')();
|
||||
var enslClient = require("../ensl/client")();
|
||||
var hiveClient = require("../hive/client")();
|
||||
|
||||
function User (user) {
|
||||
this.id = user['id'];
|
||||
this.online = true;
|
||||
this.username = user['username'];
|
||||
this.country = user['country'];
|
||||
this.time_zone = user['time_zone'];
|
||||
this.avatar = enslClient.getFullAvatarUri(user['avatar']);
|
||||
this.admin = user['admin'];
|
||||
this.moderator = user['moderator'];
|
||||
this.team = user['team'];
|
||||
this.bans = user['bans'];
|
||||
if (user['steam']) {
|
||||
this.steam = {
|
||||
id: steam.convertTo64(user['steam']['id']),
|
||||
url: user['steam']['url'] || null,
|
||||
nickname: user['steam']['nickname'] || null
|
||||
};
|
||||
} else {
|
||||
this.steam = {
|
||||
id: null,
|
||||
url: null,
|
||||
nickname: null
|
||||
};
|
||||
}
|
||||
this.profile = null;
|
||||
this.hive = {
|
||||
id: null
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
User.prototype.isChatAdmin = function () {
|
||||
return this.admin || this.moderator;
|
||||
};
|
||||
|
||||
User.prototype.isGatherAdmin = function () {
|
||||
return this.admin || this.moderator;
|
||||
};
|
||||
|
||||
User.prototype.isUserAdmin = function () {
|
||||
return this.admin;
|
||||
};
|
||||
|
||||
|
||||
var allowedAttributes = ["enslo", "division", "skill", "gatherMusic"];
|
||||
var allowedAbilities = ["skulk", "lerk", "fade", "gorge", "onos", "commander"];
|
||||
User.prototype.updateProfile = function (data, callback) {
|
||||
let self = this;
|
||||
Profile.findOne({userId: self.id}, (error, profile) => {
|
||||
if (error) return callback(error);
|
||||
allowedAttributes.forEach(function (attr) {
|
||||
if (data[attr] !== undefined) profile[attr] = data[attr];
|
||||
});
|
||||
if (data.abilities) {
|
||||
allowedAbilities.forEach(function (attr) {
|
||||
let newAbility = data.abilities[attr];
|
||||
let abilities = profile.abilities;
|
||||
if (newAbility !== undefined) abilities[attr] = newAbility;
|
||||
});
|
||||
}
|
||||
profile.save(function (error, profile) {
|
||||
if (error) return callback(error);
|
||||
self.profile = profile.toJson();
|
||||
return callback(error, profile);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
User.find = function (id, callback) {
|
||||
enslClient.getUserById({
|
||||
id: id
|
||||
}, (error, response, body) => {
|
||||
if (error) return callback(error);
|
||||
if (response.statusCode !== 200) return callback(new Error("Unable to auth user against API"));
|
||||
let user = new User(body);
|
||||
async.parallel([
|
||||
// Retrieve or create user profile from local store
|
||||
callback => {
|
||||
Profile.findOrCreate(user, (error, profile) => {
|
||||
if (error) return callback(error);
|
||||
user.profile = profile.toJson();
|
||||
return callback(null, profile);
|
||||
});
|
||||
},
|
||||
callback => {
|
||||
hiveClient.getUserStats(user, (error, stats) => {
|
||||
if (error || !stats || stats.steamId === null) return callback();
|
||||
_.assign(user.hive, userStats.stats);
|
||||
return callback(null, userStats);
|
||||
});
|
||||
}
|
||||
], function (error, result) {
|
||||
if (error) return callback(error);
|
||||
return callback(null, user);
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = User;
|
125
lib/user/user.mjs
Normal file
125
lib/user/user.mjs
Normal file
|
@ -0,0 +1,125 @@
|
|||
/*
|
||||
* Implements User Model
|
||||
*
|
||||
*/
|
||||
|
||||
import _ from "lodash";
|
||||
import async from "async"
|
||||
import mongoose from "mongoose";
|
||||
import SteamConvert from "steamidconvert";
|
||||
import EnslClient from "../ensl/client.mjs";
|
||||
import HiveClient from "../hive/client.mjs";
|
||||
|
||||
const Profile = mongoose.model("Profile");
|
||||
const steam = new SteamConvert();
|
||||
const enslClient = new EnslClient();
|
||||
const hiveClient = new HiveClient();
|
||||
|
||||
class User {
|
||||
constructor(user) {
|
||||
this.id = user['id'];
|
||||
this.online = true;
|
||||
this.username = user['username'];
|
||||
this.country = user['country'];
|
||||
this.time_zone = user['time_zone'];
|
||||
this.avatar = enslClient.getFullAvatarUri(user['avatar']);
|
||||
this.admin = user['admin'];
|
||||
this.moderator = user['moderator'];
|
||||
this.team = user['team'];
|
||||
this.bans = user['bans'];
|
||||
if (user['steam']) {
|
||||
this.steam = {
|
||||
id: steam.convertTo64(user['steam']['id']),
|
||||
url: user['steam']['url'] || null,
|
||||
nickname: user['steam']['nickname'] || null
|
||||
};
|
||||
} else {
|
||||
this.steam = {
|
||||
id: null,
|
||||
url: null,
|
||||
nickname: null
|
||||
};
|
||||
}
|
||||
this.profile = null;
|
||||
this.hive = {
|
||||
id: null
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
static find(id, callback) {
|
||||
enslClient.getUserById({
|
||||
id: id
|
||||
}, (error, response, body) => {
|
||||
if (error)
|
||||
return callback(error);
|
||||
if (response.statusCode !== 200)
|
||||
return callback(new Error("Unable to auth user against API"));
|
||||
let user = new User(body);
|
||||
async.parallel([
|
||||
// Retrieve or create user profile from local store
|
||||
callback => {
|
||||
Profile.findOrCreate(user, (error, profile) => {
|
||||
if (error)
|
||||
return callback(error);
|
||||
user.profile = profile.toJson();
|
||||
return callback(null, profile);
|
||||
});
|
||||
},
|
||||
callback => {
|
||||
hiveClient.getUserStats(user, (error, stats) => {
|
||||
if (error || !stats || stats.steamId === null)
|
||||
return callback();
|
||||
_.assign(user.hive, stats);
|
||||
return callback(null, stats);
|
||||
});
|
||||
}
|
||||
], function (error, result) {
|
||||
if (error)
|
||||
return callback(error);
|
||||
return callback(null, user);
|
||||
});
|
||||
});
|
||||
}
|
||||
isChatAdmin() {
|
||||
return this.admin || this.moderator;
|
||||
}
|
||||
isGatherAdmin() {
|
||||
return this.admin || this.moderator;
|
||||
}
|
||||
isUserAdmin() {
|
||||
return this.admin;
|
||||
}
|
||||
updateProfile(data, callback) {
|
||||
let self = this;
|
||||
Profile.findOne({ userId: self.id }, (error, profile) => {
|
||||
if (error)
|
||||
return callback(error);
|
||||
allowedAttributes.forEach(function (attr) {
|
||||
if (data[attr] !== undefined)
|
||||
profile[attr] = data[attr];
|
||||
});
|
||||
if (data.abilities) {
|
||||
allowedAbilities.forEach(function (attr) {
|
||||
let newAbility = data.abilities[attr];
|
||||
let abilities = profile.abilities;
|
||||
if (newAbility !== undefined)
|
||||
abilities[attr] = newAbility;
|
||||
});
|
||||
}
|
||||
profile.save(function (error, profile) {
|
||||
if (error)
|
||||
return callback(error);
|
||||
self.profile = profile.toJson();
|
||||
return callback(error, profile);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var allowedAttributes = ["enslo", "division", "skill", "gatherMusic"];
|
||||
var allowedAbilities = ["skulk", "lerk", "fade", "gorge", "onos", "commander"];
|
||||
|
||||
|
||||
export default User;
|
427
package-lock.json
generated
427
package-lock.json
generated
|
@ -30,7 +30,6 @@
|
|||
"moment": "^2.11.2",
|
||||
"mongoose": "^6.10.1",
|
||||
"morgan": "~1.9.1",
|
||||
"newrelic": "~5.13.1",
|
||||
"perfect-scrollbar": "~0.6.10",
|
||||
"react": "^16.13.1",
|
||||
"react-autolink": "^0.2.1",
|
||||
|
@ -41,7 +40,6 @@
|
|||
"snyk": "^1.316.1",
|
||||
"socket.io": "^4.6.1",
|
||||
"socket.io-client": "^4.6.1",
|
||||
"steam": "^1.1.0",
|
||||
"steamidconvert": "~0.2.4",
|
||||
"toastr": "~2.1.4",
|
||||
"winston": "~1.0.1"
|
||||
|
@ -2645,43 +2643,6 @@
|
|||
"@jridgewell/sourcemap-codec": "1.4.14"
|
||||
}
|
||||
},
|
||||
"node_modules/@newrelic/koa": {
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/@newrelic/koa/-/koa-1.0.8.tgz",
|
||||
"integrity": "sha512-kY//FlLQkGdUIKEeGJlyY3dJRU63EG77YIa48ACMGZxQbWRd3WZMikyft33f8XScTq6WpCDo9xa0viNo8zeYkg==",
|
||||
"dependencies": {
|
||||
"methods": "^1.1.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"newrelic": ">=3.3.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@newrelic/native-metrics": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@newrelic/native-metrics/-/native-metrics-4.1.0.tgz",
|
||||
"integrity": "sha512-7CZlKMLuaYQW7mV9qVyo9b9HVe2xBnyn+kkETRJoZGs5P7gdfv9AAE3RPhtOBUopTfbmc8ju7njYadjui9J1XA==",
|
||||
"hasInstallScript": true,
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"nan": "^2.12.1",
|
||||
"semver": "^5.5.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6",
|
||||
"npm": ">=3"
|
||||
}
|
||||
},
|
||||
"node_modules/@newrelic/superagent": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@newrelic/superagent/-/superagent-1.0.3.tgz",
|
||||
"integrity": "sha512-lJbsqKa79qPLbHZsbiRaXl1jfzaXAN7zqqnLRqBY+zI/O5zcfyNngTmdi+9y+qIUq7xHYNaLsAxCXerrsoINKg==",
|
||||
"dependencies": {
|
||||
"methods": "^1.1.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"newrelic": ">=4.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@nicolo-ribaudo/chokidar-2": {
|
||||
"version": "2.1.8-no-fsevents.3",
|
||||
"resolved": "https://registry.npmjs.org/@nicolo-ribaudo/chokidar-2/-/chokidar-2-2.1.8-no-fsevents.3.tgz",
|
||||
|
@ -2689,60 +2650,6 @@
|
|||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/@protobufjs/aspromise": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz",
|
||||
"integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ=="
|
||||
},
|
||||
"node_modules/@protobufjs/base64": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz",
|
||||
"integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg=="
|
||||
},
|
||||
"node_modules/@protobufjs/codegen": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz",
|
||||
"integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg=="
|
||||
},
|
||||
"node_modules/@protobufjs/eventemitter": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz",
|
||||
"integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q=="
|
||||
},
|
||||
"node_modules/@protobufjs/fetch": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz",
|
||||
"integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==",
|
||||
"dependencies": {
|
||||
"@protobufjs/aspromise": "^1.1.1",
|
||||
"@protobufjs/inquire": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@protobufjs/float": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz",
|
||||
"integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ=="
|
||||
},
|
||||
"node_modules/@protobufjs/inquire": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz",
|
||||
"integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q=="
|
||||
},
|
||||
"node_modules/@protobufjs/path": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz",
|
||||
"integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA=="
|
||||
},
|
||||
"node_modules/@protobufjs/pool": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz",
|
||||
"integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw=="
|
||||
},
|
||||
"node_modules/@protobufjs/utf8": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz",
|
||||
"integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw=="
|
||||
},
|
||||
"node_modules/@socket.io/component-emitter": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz",
|
||||
|
@ -2903,11 +2810,6 @@
|
|||
"winston": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@tyriar/fibonacci-heap": {
|
||||
"version": "2.0.9",
|
||||
"resolved": "https://registry.npmjs.org/@tyriar/fibonacci-heap/-/fibonacci-heap-2.0.9.tgz",
|
||||
"integrity": "sha512-bYuSNomfn4hu2tPiDN+JZtnzCpSpbJ/PNeulmocDy3xN2X5OkJL65zo6rPZp65cPPhLF9vfT/dgE+RtFRCSxOA=="
|
||||
},
|
||||
"node_modules/abbrev": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
|
||||
|
@ -2974,25 +2876,6 @@
|
|||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/adm-zip": {
|
||||
"version": "0.4.16",
|
||||
"resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.16.tgz",
|
||||
"integrity": "sha512-TFi4HBKSGfIKsK5YCkKaaFG2m4PEDyViZmEwof3MTIgzimHLto6muaHVpbrljdIvIrFZzEq/p4nafOeLcYegrg==",
|
||||
"engines": {
|
||||
"node": ">=0.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/agent-base": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz",
|
||||
"integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==",
|
||||
"dependencies": {
|
||||
"es6-promisify": "^5.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ajv": {
|
||||
"version": "6.12.4",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.4.tgz",
|
||||
|
@ -3761,18 +3644,11 @@
|
|||
"ieee754": "^1.1.4"
|
||||
}
|
||||
},
|
||||
"node_modules/buffer-crc32": {
|
||||
"version": "0.2.13",
|
||||
"resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
|
||||
"integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=",
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/buffer-from": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
|
||||
"integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A=="
|
||||
"integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/buffer-xor": {
|
||||
"version": "1.0.3",
|
||||
|
@ -3784,25 +3660,6 @@
|
|||
"resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz",
|
||||
"integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug="
|
||||
},
|
||||
"node_modules/bytebuffer": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/bytebuffer/-/bytebuffer-5.0.1.tgz",
|
||||
"integrity": "sha512-IuzSdmADppkZ6DlpycMkm8l9zeEq16fWtLvunEwFiYciR/BHo4E8/xs5piFquG+Za8OWmMqHF8zuRviz2LHvRQ==",
|
||||
"dependencies": {
|
||||
"long": "~3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/bytebuffer/node_modules/long": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/long/-/long-3.2.0.tgz",
|
||||
"integrity": "sha512-ZYvPPOMqUwPoDsbJaR10iQJYnMuZhRTvHYl62ErLIEX7RgFlziSBUUvrt3OVfc47QlHHpzPZYP17g3Fv7oeJkg==",
|
||||
"engines": {
|
||||
"node": ">=0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/bytes": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz",
|
||||
|
@ -4121,20 +3978,6 @@
|
|||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="
|
||||
},
|
||||
"node_modules/concat-stream": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz",
|
||||
"integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==",
|
||||
"engines": [
|
||||
"node >= 6.0"
|
||||
],
|
||||
"dependencies": {
|
||||
"buffer-from": "^1.0.0",
|
||||
"inherits": "^2.0.3",
|
||||
"readable-stream": "^3.0.2",
|
||||
"typedarray": "^0.0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/content-disposition": {
|
||||
"version": "0.5.2",
|
||||
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz",
|
||||
|
@ -4379,11 +4222,6 @@
|
|||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/deep-is": {
|
||||
"version": "0.1.3",
|
||||
"resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz",
|
||||
"integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ="
|
||||
},
|
||||
"node_modules/define-properties": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz",
|
||||
|
@ -4899,19 +4737,6 @@
|
|||
"resolved": "https://registry.npmjs.org/es6-object-assign/-/es6-object-assign-1.1.0.tgz",
|
||||
"integrity": "sha1-wsNYJlYkfDnqEHyx5mUrb58kUjw="
|
||||
},
|
||||
"node_modules/es6-promise": {
|
||||
"version": "4.2.8",
|
||||
"resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz",
|
||||
"integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w=="
|
||||
},
|
||||
"node_modules/es6-promisify": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz",
|
||||
"integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=",
|
||||
"dependencies": {
|
||||
"es6-promise": "^4.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/escalade": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
|
||||
|
@ -4934,48 +4759,6 @@
|
|||
"node": ">=0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/escodegen": {
|
||||
"version": "1.14.3",
|
||||
"resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz",
|
||||
"integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==",
|
||||
"dependencies": {
|
||||
"esprima": "^4.0.1",
|
||||
"estraverse": "^4.2.0",
|
||||
"esutils": "^2.0.2",
|
||||
"optionator": "^0.8.1"
|
||||
},
|
||||
"bin": {
|
||||
"escodegen": "bin/escodegen.js",
|
||||
"esgenerate": "bin/esgenerate.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"source-map": "~0.6.1"
|
||||
}
|
||||
},
|
||||
"node_modules/escodegen/node_modules/esprima": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
|
||||
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
|
||||
"bin": {
|
||||
"esparse": "bin/esparse.js",
|
||||
"esvalidate": "bin/esvalidate.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/escodegen/node_modules/source-map": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/esprima": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/esprima/-/esprima-1.0.4.tgz",
|
||||
|
@ -4988,18 +4771,11 @@
|
|||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/estraverse": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
|
||||
"integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
|
||||
"engines": {
|
||||
"node": ">=4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/esutils": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
|
||||
"integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
|
@ -6011,27 +5787,6 @@
|
|||
"resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz",
|
||||
"integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM="
|
||||
},
|
||||
"node_modules/https-proxy-agent": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-3.0.1.tgz",
|
||||
"integrity": "sha512-+ML2Rbh6DAuee7d07tYGEKOEi2voWPUGan+ExdPbPW6Z3svq+JCqr0v8WmKPOkz1vOVykPCBSuobe7G8GJUtVg==",
|
||||
"dependencies": {
|
||||
"agent-base": "^4.3.0",
|
||||
"debug": "^3.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 4.5.0"
|
||||
}
|
||||
},
|
||||
"node_modules/https-proxy-agent/node_modules/debug": {
|
||||
"version": "3.2.6",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
|
||||
"integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
|
||||
"deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)",
|
||||
"dependencies": {
|
||||
"ms": "^2.1.1"
|
||||
}
|
||||
},
|
||||
"node_modules/iconv-lite": {
|
||||
"version": "0.4.24",
|
||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
|
||||
|
@ -6532,18 +6287,6 @@
|
|||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/levn": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz",
|
||||
"integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=",
|
||||
"dependencies": {
|
||||
"prelude-ls": "~1.1.2",
|
||||
"type-check": "~0.3.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/locate-path": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
|
||||
|
@ -7295,12 +7038,6 @@
|
|||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
||||
},
|
||||
"node_modules/nan": {
|
||||
"version": "2.14.1",
|
||||
"resolved": "https://registry.npmjs.org/nan/-/nan-2.14.1.tgz",
|
||||
"integrity": "sha512-isWHgVjnFjh2x2yuJ/tj3JbwoHu3UC2dX5G/88Cm24yB6YopVgxvBObDY7n5xW6ExmFhJpSEQqFPvq9zaXc8Jw==",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/nanoid": {
|
||||
"version": "3.3.3",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz",
|
||||
|
@ -7364,55 +7101,6 @@
|
|||
"resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz",
|
||||
"integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw=="
|
||||
},
|
||||
"node_modules/newrelic": {
|
||||
"version": "5.13.1",
|
||||
"resolved": "https://registry.npmjs.org/newrelic/-/newrelic-5.13.1.tgz",
|
||||
"integrity": "sha512-FRChTKLh29benj2r//8/q+nLX3oHYlaOkOAjCVkilbTpp8OwR84FFDZNWRVuocxWP+yPR6ayfPaNc0ueLp9R7g==",
|
||||
"deprecated": "This version of the New Relic Node Agent has reached the end of life.",
|
||||
"dependencies": {
|
||||
"@newrelic/koa": "^1.0.8",
|
||||
"@newrelic/superagent": "^1.0.2",
|
||||
"@tyriar/fibonacci-heap": "^2.0.7",
|
||||
"async": "^2.1.4",
|
||||
"concat-stream": "^2.0.0",
|
||||
"escodegen": "^1.11.1",
|
||||
"esprima": "^4.0.1",
|
||||
"https-proxy-agent": "^3.0.0",
|
||||
"json-stringify-safe": "^5.0.0",
|
||||
"readable-stream": "^3.1.1",
|
||||
"semver": "^5.3.0"
|
||||
},
|
||||
"bin": {
|
||||
"newrelic-naming-rules": "bin/test-naming-rules.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0.0 <13.0.0",
|
||||
"npm": ">=3.0.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@newrelic/native-metrics": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/newrelic/node_modules/async": {
|
||||
"version": "2.6.4",
|
||||
"resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz",
|
||||
"integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==",
|
||||
"dependencies": {
|
||||
"lodash": "^4.17.14"
|
||||
}
|
||||
},
|
||||
"node_modules/newrelic/node_modules/esprima": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
|
||||
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
|
||||
"bin": {
|
||||
"esparse": "bin/esparse.js",
|
||||
"esvalidate": "bin/esvalidate.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/node-browser-modules": {
|
||||
"version": "0.2.1",
|
||||
"resolved": "https://registry.npmjs.org/node-browser-modules/-/node-browser-modules-0.2.1.tgz",
|
||||
|
@ -7668,27 +7356,6 @@
|
|||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"node_modules/optionator": {
|
||||
"version": "0.8.3",
|
||||
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz",
|
||||
"integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==",
|
||||
"dependencies": {
|
||||
"deep-is": "~0.1.3",
|
||||
"fast-levenshtein": "~2.0.6",
|
||||
"levn": "~0.3.0",
|
||||
"prelude-ls": "~1.1.2",
|
||||
"type-check": "~0.3.2",
|
||||
"word-wrap": "~1.2.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/optionator/node_modules/fast-levenshtein": {
|
||||
"version": "2.0.6",
|
||||
"resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
|
||||
"integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc="
|
||||
},
|
||||
"node_modules/os-browserify": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz",
|
||||
|
@ -7896,14 +7563,6 @@
|
|||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/prelude-ls": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
|
||||
"integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=",
|
||||
"engines": {
|
||||
"node": ">= 0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/prism-media": {
|
||||
"version": "0.0.4",
|
||||
"resolved": "https://registry.npmjs.org/prism-media/-/prism-media-0.0.4.tgz",
|
||||
|
@ -7940,39 +7599,6 @@
|
|||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/protobufjs": {
|
||||
"version": "7.2.2",
|
||||
"resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.2.2.tgz",
|
||||
"integrity": "sha512-++PrQIjrom+bFDPpfmqXfAGSQs40116JRrqqyf53dymUMvvb5d/LMRyicRoF1AUKoXVS1/IgJXlEgcpr4gTF3Q==",
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"@protobufjs/aspromise": "^1.1.2",
|
||||
"@protobufjs/base64": "^1.1.2",
|
||||
"@protobufjs/codegen": "^2.0.4",
|
||||
"@protobufjs/eventemitter": "^1.1.0",
|
||||
"@protobufjs/fetch": "^1.1.0",
|
||||
"@protobufjs/float": "^1.0.2",
|
||||
"@protobufjs/inquire": "^1.1.0",
|
||||
"@protobufjs/path": "^1.1.2",
|
||||
"@protobufjs/pool": "^1.1.0",
|
||||
"@protobufjs/utf8": "^1.1.0",
|
||||
"@types/node": ">=13.7.0",
|
||||
"long": "^5.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/protobufjs/node_modules/@types/node": {
|
||||
"version": "18.14.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.14.6.tgz",
|
||||
"integrity": "sha512-93+VvleD3mXwlLI/xASjw0FzKcwzl3OdTCzm1LaRfqgS21gfFtK3zDXM5Op9TeeMsJVOaJ2VRDpT9q4Y3d0AvA=="
|
||||
},
|
||||
"node_modules/protobufjs/node_modules/long": {
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/long/-/long-5.2.1.tgz",
|
||||
"integrity": "sha512-GKSNGeNAtw8IryjjkhZxuKB3JzlcLTwjtiQCHKvqQet81I93kXslhDQruGI/QsddO83mcDToBVy7GqGS/zYf/A=="
|
||||
},
|
||||
"node_modules/proxy-addr": {
|
||||
"version": "2.0.7",
|
||||
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
|
||||
|
@ -8448,6 +8074,7 @@
|
|||
"version": "5.7.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
|
||||
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"semver": "bin/semver"
|
||||
}
|
||||
|
@ -9142,28 +8769,6 @@
|
|||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/steam": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/steam/-/steam-1.1.0.tgz",
|
||||
"integrity": "sha512-Zgg1WR/5SnO2dPBb0bEdC2SPQNlkywoB7ZUNk0HzrfXUWhk+4FbnIzTCc1yAeBZOOYb2K4ID4zZDlRo8Vqr0gg==",
|
||||
"deprecated": "this project is not maintained",
|
||||
"dependencies": {
|
||||
"adm-zip": "*",
|
||||
"buffer-crc32": "*",
|
||||
"bytebuffer": ">=3.5.5",
|
||||
"protobufjs": ">=4.0.0",
|
||||
"steam-crypto": "*"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.12"
|
||||
}
|
||||
},
|
||||
"node_modules/steam-crypto": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/steam-crypto/-/steam-crypto-0.0.1.tgz",
|
||||
"integrity": "sha1-BHexgqKx/dlBiT28wi4Ok7FKu38=",
|
||||
"deprecated": "this project is not maintained"
|
||||
},
|
||||
"node_modules/steamidconvert": {
|
||||
"version": "0.2.4",
|
||||
"resolved": "https://registry.npmjs.org/steamidconvert/-/steamidconvert-0.2.4.tgz",
|
||||
|
@ -9632,17 +9237,6 @@
|
|||
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz",
|
||||
"integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw=="
|
||||
},
|
||||
"node_modules/type-check": {
|
||||
"version": "0.3.2",
|
||||
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
|
||||
"integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=",
|
||||
"dependencies": {
|
||||
"prelude-ls": "~1.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/type-detect": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/type-detect/-/type-detect-1.0.0.tgz",
|
||||
|
@ -9683,11 +9277,6 @@
|
|||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/typedarray": {
|
||||
"version": "0.0.6",
|
||||
"resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
|
||||
"integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c="
|
||||
},
|
||||
"node_modules/uglify-js": {
|
||||
"version": "3.10.2",
|
||||
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.10.2.tgz",
|
||||
|
@ -10008,14 +9597,6 @@
|
|||
"resolved": "https://registry.npmjs.org/async/-/async-1.0.0.tgz",
|
||||
"integrity": "sha1-+PwEyjoTeErenhZBr5hXjPvWR6k="
|
||||
},
|
||||
"node_modules/word-wrap": {
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
|
||||
"integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/wordwrap": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
|
||||
|
|
|
@ -51,7 +51,6 @@
|
|||
"moment": "^2.11.2",
|
||||
"mongoose": "^6.10.1",
|
||||
"morgan": "~1.9.1",
|
||||
"newrelic": "~5.13.1",
|
||||
"perfect-scrollbar": "~0.6.10",
|
||||
"react": "^16.13.1",
|
||||
"react-autolink": "^0.2.1",
|
||||
|
@ -62,7 +61,6 @@
|
|||
"snyk": "^1.316.1",
|
||||
"socket.io": "^4.6.1",
|
||||
"socket.io-client": "^4.6.1",
|
||||
"steam": "^1.1.0",
|
||||
"steamidconvert": "~0.2.4",
|
||||
"toastr": "~2.1.4",
|
||||
"winston": "~1.0.1"
|
||||
|
|
Loading…
Reference in a new issue