Compare commits
No commits in common. "8ebd9b78ecfddb40e95ab497a86ee1411e2e45cd" and "416592d7dfd1cc587000c9d15f5c6b4cc88de6fa" have entirely different histories.
8ebd9b78ec
...
416592d7df
5
server/.gitignore
vendored
5
server/.gitignore
vendored
@ -117,9 +117,6 @@ dist
|
||||
# DynamoDB Local files
|
||||
.dynamodb/
|
||||
|
||||
# DB local files
|
||||
.db
|
||||
|
||||
# TernJS port file
|
||||
.tern-port
|
||||
|
||||
@ -131,4 +128,4 @@ dist
|
||||
.yarn/unplugged
|
||||
.yarn/build-state.yml
|
||||
.yarn/install-state.gz
|
||||
.pnp.*
|
||||
.pnp.*
|
@ -31,11 +31,14 @@ class APIMethods {
|
||||
info (con, req, cb) {
|
||||
if (!req.fields) req.fields = "*";
|
||||
if (!req.fieldsExtSource) req.fieldsExtSource = "*";
|
||||
const cacheKey = `${req.fields}\u0000${req.fieldsExtSource}`;
|
||||
|
||||
const cache = this.info.cache[cacheKey];
|
||||
const cache = this.info.cache[
|
||||
JSON.stringify({
|
||||
f: req.fields, e: req.fieldsExtSource
|
||||
})
|
||||
];
|
||||
|
||||
if (cache) {
|
||||
console.debug("CACHE!");
|
||||
return cb({ result: cache, trace_id: req.trace_id, ended: true });
|
||||
}
|
||||
|
||||
@ -52,7 +55,11 @@ class APIMethods {
|
||||
if (!fields[k]) serverInfo.extSource[k] = undefined;
|
||||
});
|
||||
}
|
||||
this.info.cache[cacheKey] = serverInfo;
|
||||
this.info.cache[
|
||||
JSON.stringify({
|
||||
f: req.fields, e: req.fieldsExtSource
|
||||
})
|
||||
] = serverInfo;
|
||||
|
||||
cb({ result: serverInfo, trace_id: req.trace_id, ended: true });
|
||||
}
|
||||
@ -97,35 +104,6 @@ class APIMethods {
|
||||
});
|
||||
}
|
||||
|
||||
async characters (con, req, cb) {
|
||||
const authedMethod = this.authed;
|
||||
const isAuthed = await (new Promise((rs, rj) => {
|
||||
authedMethod(con, req, ({ result, ended }) => {
|
||||
if (ended)
|
||||
return rs(result);
|
||||
});
|
||||
}));
|
||||
|
||||
if (!isAuthed) {
|
||||
return cb({
|
||||
error: "require authorize",
|
||||
trace_id: req.trace_id,
|
||||
ended: true
|
||||
});
|
||||
}
|
||||
|
||||
// getting characters
|
||||
const user = global.authed.get(con);
|
||||
const result = (await user.getCharacters())
|
||||
.map(character => {
|
||||
return character;
|
||||
});
|
||||
|
||||
cb({
|
||||
result, trace_id: req.trace_id, ended: true
|
||||
});
|
||||
}
|
||||
|
||||
/*setSession (isEncrypted, address, { key, counter }, cb) {
|
||||
if (!global.config.server.secureMode)
|
||||
return cb({ error: "Encryption is off by configuration file into server" });
|
||||
|
@ -13,7 +13,7 @@ module.exports.registerToken = function (user) {
|
||||
token = module.exports();
|
||||
} while (global.authed.tokens[token] !== undefined);
|
||||
global.authed.tokens[token] = user;
|
||||
// TODO: Потом добавить регистрацию в БД!
|
||||
// (!) Потом добавить регистрацию в БД!
|
||||
|
||||
return token;
|
||||
};
|
||||
|
@ -9,46 +9,26 @@
|
||||
* * 5 - root
|
||||
*/
|
||||
|
||||
const ACCESS_LEVELS = {
|
||||
"-1": "banned",
|
||||
0: "user",
|
||||
1: "helper",
|
||||
2: "moderator",
|
||||
3: "admin",
|
||||
4: "superadmin",
|
||||
5: "root",
|
||||
};
|
||||
|
||||
class AccessLevel {
|
||||
static validate (value) {
|
||||
const access = Object.fromEntries(Object.keys(ACCESS_LEVELS)
|
||||
.map(level => [level, true]));
|
||||
return (
|
||||
Number.isInteger(value) &&
|
||||
access["" + value] === true
|
||||
);
|
||||
}
|
||||
|
||||
constructor (accessLevel) {
|
||||
if (!this.__proto__.constructor.validate(accessLevel))
|
||||
throw new Error(
|
||||
`Invalid access level: ${accessLevel}`,
|
||||
);
|
||||
this.code = accessLevel;
|
||||
}
|
||||
|
||||
get accessName () {
|
||||
return ACCESS_LEVELS[""+this.code]
|
||||
}
|
||||
}
|
||||
|
||||
class User {
|
||||
constructor (name, accessLevel) {
|
||||
constructor(name, accessLevel) {
|
||||
if (
|
||||
typeof accessLevel !== "number" ||
|
||||
{
|
||||
"-1": true,
|
||||
0: true,
|
||||
1: true,
|
||||
2: true,
|
||||
3: true,
|
||||
4: true,
|
||||
5: true,
|
||||
}["" + accessLevel] !== true
|
||||
) {
|
||||
throw new Error(
|
||||
`Invalid access level: ${accessLevel} (must be ranged from -1 to 5)`,
|
||||
);
|
||||
}
|
||||
this.name = name;
|
||||
if (accessLevel instanceof AccessLevel)
|
||||
this.accessLevel = accessLevel;
|
||||
else
|
||||
this.accessLevel = new AccessLevel(accessLevel);
|
||||
this.accessLevel = accessLevel;
|
||||
}
|
||||
|
||||
static async getUserByName(name) {
|
||||
@ -61,15 +41,8 @@ class User {
|
||||
User.cache[name] = user;
|
||||
return user;
|
||||
}
|
||||
// TODO: Потом добавить чтение из БД
|
||||
//return null;
|
||||
|
||||
const userdata = await global.database.getUserRowByName(name);
|
||||
if (!userdata)
|
||||
return null;
|
||||
const user = new User(userdata.username, userdata.accessLevel);
|
||||
User.cache[name] = user;
|
||||
return user;
|
||||
// Потом добавить чтение из БД
|
||||
return null;
|
||||
}
|
||||
|
||||
static getByToken(token) {
|
||||
@ -77,27 +50,13 @@ class User {
|
||||
return user ?? null;
|
||||
}
|
||||
|
||||
getUserForAPI(getFullInfo = false, fields = "*") {
|
||||
const getted = {
|
||||
getUserForAPI(getFullInfo = false) {
|
||||
return {
|
||||
username: this.name,
|
||||
accessLevel: this.accessLevel.code,
|
||||
accessLevel: this.accessLevel,
|
||||
};
|
||||
|
||||
if (fields !== "*") {
|
||||
const selected = Object.fromEntries(fields.split(/\s*,\s*/g).map(field => [field, true]));
|
||||
for (let field in getted) {
|
||||
if (!selected[field])
|
||||
getted[field] = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
return getted;
|
||||
}
|
||||
|
||||
async getCharacters () {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
User.cache = {};
|
||||
|
||||
module.exports = { User, AccessLevel };
|
||||
module.exports = { User };
|
||||
|
@ -18,8 +18,7 @@
|
||||
},
|
||||
"database": {
|
||||
"dialect": "sqlite",
|
||||
"storage": "./data.db",
|
||||
"logging": false
|
||||
"path": "./data"
|
||||
},
|
||||
"ai": {
|
||||
"apiType": "kobold"
|
||||
|
@ -1,124 +0,0 @@
|
||||
const { DataTypes } = require("sequelize");
|
||||
const { AccessLevel } = require("../api/utils/user");
|
||||
const logger = require("../logger");
|
||||
const bcrypt = require("bcrypt");
|
||||
|
||||
/*const SALT_ROUNDS = Math.round(Math.r) + 6;
|
||||
const BCRYPT_SALT = bcrypt.genSaltSync(SALT_ROUNDS);*/
|
||||
function getSalt () {
|
||||
//return bcrypt.genSaltSync(10);
|
||||
return bcrypt.genSaltSync(Math.round(Math.random() * 4) + 6);
|
||||
}
|
||||
|
||||
module.exports = async function (sequelize, dbObj) {
|
||||
const dbModel = {
|
||||
users: sequelize.define("users", {
|
||||
id: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: false,
|
||||
autoIncrement: true,
|
||||
primaryKey: true,
|
||||
comment: "ID of user",
|
||||
},
|
||||
username: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false,
|
||||
unique: true,
|
||||
comment: "Username of user",
|
||||
validate: {
|
||||
not: /null/iu,
|
||||
},
|
||||
},
|
||||
accessLevel: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: false,
|
||||
defaultValue: false,
|
||||
comment: "access level of user",
|
||||
get: function () {
|
||||
return new AccessLevel(this.getDataValue("accessLevel"));
|
||||
},
|
||||
set: function (value) {
|
||||
if (value instanceof AccessLevel)
|
||||
return this.setDataValue("accessLevel", value.code);
|
||||
if (Number.isInteger(value)) {
|
||||
if (AccessLevel.validate(value))
|
||||
return this.setDataValue("accessLevel", value);
|
||||
}
|
||||
throw new TypeError("accessLevel must be AccessLevel object or integer");
|
||||
//this.setDataValue('inventory', JSON.stringify(value));
|
||||
},
|
||||
},
|
||||
password: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false,
|
||||
unique: false,
|
||||
comment: "Hash code of password",
|
||||
set: function (value) {
|
||||
const hash = bcrypt.hashSync(value, getSalt());
|
||||
this.setDataValue('password', hash);
|
||||
},
|
||||
get: function () {
|
||||
const checkHash = this.getDataValue("password");
|
||||
return async function (password) {
|
||||
return await new Promise((rs, rj) => {
|
||||
bcrypt.compare(password, checkHash, (err, res) => {
|
||||
if (err)
|
||||
return rs(false);
|
||||
logger.debug("isRes is", res);
|
||||
rs(res);
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
},
|
||||
isActivate: {
|
||||
type: DataTypes.BOOLEAN,
|
||||
allowNull: false,
|
||||
defaultValue: true,
|
||||
comment: "Is user activated",
|
||||
},
|
||||
}),
|
||||
|
||||
userCharacters: sequelize.define("userCharacters", {
|
||||
id: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: false,
|
||||
autoIncrement: true,
|
||||
primaryKey: true,
|
||||
comment: "ID of character",
|
||||
},
|
||||
name: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false,
|
||||
unique: true,
|
||||
comment: "Name of character",
|
||||
},
|
||||
ownerId: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: false,
|
||||
comment: "ID of character's owner",
|
||||
},
|
||||
}),
|
||||
};
|
||||
|
||||
dbModel.userCharacters.belongsTo(dbModel.users, {
|
||||
foreignKey: "ownerId", // field in userCharacters
|
||||
targetKey: "id", // field in users
|
||||
onDelete: "CASCADE", // If delete user, characters will be deleted
|
||||
onUpdate: "CASCADE",
|
||||
});
|
||||
dbModel.users.hasMany(dbModel.userCharacters, {
|
||||
foreignKey: "ownerId", // field ownerId
|
||||
sourceKey: "id",
|
||||
});
|
||||
|
||||
await sequelize.authenticate();
|
||||
const initPromise = Object.entries(dbModel).map(async ([tableName, table]) => {
|
||||
logger.log(`* init table: ${tableName}`);
|
||||
await table.sync({ alter: true });
|
||||
const rows = await table.findAll();
|
||||
await dbObj.cache[tableName]?.(rows, table);
|
||||
logger.log(`* inited: ${tableName}`);
|
||||
});
|
||||
await Promise.all(initPromise);
|
||||
};
|
@ -1,89 +0,0 @@
|
||||
const { Sequelize } = require("sequelize");
|
||||
const dbModel = require("./dbModel");
|
||||
const logger = require("../logger");
|
||||
|
||||
class DatabaseCache {
|
||||
async users (rows, table) {
|
||||
// Add root user only where root user is activated
|
||||
if (global.config.rootuser.activated) {
|
||||
const isRootHasOnDB = rows.find(x => x.username === global.config.rootuser.login);
|
||||
const rootLevel = 5; // TODO: replace it to AccessLevel.root in future
|
||||
|
||||
if (!isRootHasOnDB) {
|
||||
await table.create({
|
||||
username: global.config.rootuser.login,
|
||||
accessLevel: rootLevel,
|
||||
password: "",
|
||||
});
|
||||
return await this.users((
|
||||
await table.findAll()
|
||||
), table);
|
||||
} else if (!rows.find(x => x.username === global.config.rootuser.login && x.accessLevel.code === rootLevel)) {
|
||||
throw new Error(`Username ${
|
||||
global.config.rootuser.login
|
||||
} is busy`);
|
||||
}
|
||||
}
|
||||
this.users.rows = rows;
|
||||
this.users.byUsername = new Object();
|
||||
this.users.byId = new Object();
|
||||
|
||||
for (let row of rows) {
|
||||
this.users.byUsername[row.username] = row;
|
||||
this.users.byId[row.id] = row;
|
||||
}
|
||||
|
||||
// Add user info
|
||||
this.users.add = async (row, isCreate = false) => {
|
||||
if (isCreate)
|
||||
await table.create(row);
|
||||
|
||||
let addedData = null;
|
||||
if (row.username)
|
||||
addedData = await table.findAll({
|
||||
where: {
|
||||
username: row.username
|
||||
}
|
||||
})[0];
|
||||
else if (row.id)
|
||||
addedData = await table.findAll({
|
||||
where: {
|
||||
id: row.id
|
||||
}
|
||||
})[0];
|
||||
|
||||
if (!addedData) throw new Error("Invalid row information");
|
||||
this.users.rows.push(addedData);
|
||||
// By keys
|
||||
this.users.byUsername[addedData.username] = addedData;
|
||||
this.users.byId[addedData.id] = addedData;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Database {
|
||||
constructor(sequlizeData) {
|
||||
this.sequlize = new Sequelize(sequlizeData);
|
||||
}
|
||||
|
||||
async init(fromHandler = false) {
|
||||
global.server.toggleLock(true);
|
||||
this.cache = new DatabaseCache();
|
||||
await dbModel(this.sequlize, this);
|
||||
global.server.toggleLock(false);
|
||||
if (!fromHandler)
|
||||
global.server.on("config.update", async ({
|
||||
oldConfig, newConfig
|
||||
}) => {
|
||||
if (JSON.stringify(oldConfig.database) !== JSON.stringify(newConfig.database))
|
||||
await this.init(true);
|
||||
});
|
||||
}
|
||||
|
||||
// Return ROW of 'users' table by username
|
||||
async getUserRowByName (name) {
|
||||
return this.cache.users.byUsername[name];
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Database;
|
@ -5,31 +5,31 @@ module.exports = function (req, res) {
|
||||
if (req.query.encrypted === undefined || req.query.server === undefined)
|
||||
return res.status(400).send(`<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Error</title>
|
||||
<meta charset="utf-8">
|
||||
</head>
|
||||
<body class="bg text-white">
|
||||
<h1>[400] Error</h1><hr/><p>unuse required params</p>
|
||||
</body>
|
||||
<head>
|
||||
<title>Error</title>
|
||||
<meta charset="utf-8">
|
||||
</head>
|
||||
<body class="bg text-white">
|
||||
<h1>[400] Error</h1><hr/><p>unuse required params</p>
|
||||
</body>
|
||||
</html>`);
|
||||
res.send(`<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Connection: ${serverAddress}</title>
|
||||
<meta charset="utf-8">
|
||||
</head>
|
||||
<body class="bg text-white">
|
||||
<div id="js-required">
|
||||
<h1>Error: Javascript off</h1><hr/>
|
||||
<p>Javascript is required for the site to work, enable it in your browser settings</p>
|
||||
</div>
|
||||
<script>
|
||||
document.getElementById("js-required").innerHTML = "<p>Loading...</p>";
|
||||
</script>
|
||||
<head>
|
||||
<title>Connection: ${serverAddress}</title>
|
||||
<meta charset="utf-8">
|
||||
</head>
|
||||
<body class="bg text-white">
|
||||
<div id="js-required">
|
||||
<h1>Error: Javascript off</h1><hr/>
|
||||
<p>Javascript is required for the site to work, enable it in your browser settings</p>
|
||||
</div>
|
||||
<script>
|
||||
document.getElementById("js-required").innerHTML = "<p>Loading...</p>";
|
||||
</script>
|
||||
<script src="/bootstrap/bootstrap.bundle.min.js" defer></script>
|
||||
<script src="/js/jquery-3.7.1.min.js" defer></script>
|
||||
<script src="/js/connect/main.js" type="module" defer></script>
|
||||
</body>
|
||||
</body>
|
||||
</html>`);
|
||||
};
|
||||
}
|
@ -4,20 +4,17 @@ const path = require("path");
|
||||
const router = express.Router();
|
||||
|
||||
router.get("/", (req, res) => {
|
||||
res.send(
|
||||
fs.readFileSync(path.join(__dirname, "pages/index.html")).toString("utf-8"),
|
||||
);
|
||||
res.send(
|
||||
fs.readFileSync(path.join(__dirname, "pages/index.html")).toString("utf-8")
|
||||
);
|
||||
});
|
||||
|
||||
router.get("/connect", (req, res) => {
|
||||
res.send(
|
||||
fs.readFileSync(path.join(__dirname, "pages/connect.html"))
|
||||
.toString("utf-8"),
|
||||
);
|
||||
res.send(
|
||||
fs.readFileSync(path.join(__dirname, "pages/connect.html")).toString("utf-8")
|
||||
);
|
||||
});
|
||||
|
||||
router.get("/*", (req, res) =>
|
||||
res.status(404).send("<p><b>404:</b> Not finded.</p>"),
|
||||
);
|
||||
router.get("/*", (req, res) => res.status(404).send("<p><b>404:</b> Not finded.</p>"));
|
||||
|
||||
module.exports = router;
|
||||
|
@ -7,51 +7,48 @@ const connectArea = require("./connect-router");
|
||||
const api = require("./web-api/api-router");
|
||||
|
||||
module.exports = (address, port) => {
|
||||
const app = express();
|
||||
logger.log("Static in", path.join(__dirname, "public"));
|
||||
|
||||
const app = express();
|
||||
logger.log("Static in", path.join(__dirname, "public"));
|
||||
|
||||
app.use((req, res, next) => {
|
||||
// logger.log("HTTP headers:", req.headers);
|
||||
if (global.server.isLocked) {
|
||||
res.set("Content-Type", "plain/text");
|
||||
return res.send("Server temporary on reload");
|
||||
}
|
||||
next();
|
||||
});
|
||||
|
||||
app.use(express.static(path.join(__dirname, "public")));
|
||||
|
||||
app.use(express.static(path.join(__dirname, "public")));
|
||||
|
||||
app.use("/fl_dir", flDir);
|
||||
app.use("/api", api);
|
||||
|
||||
app.use("/fl_dir", flDir);
|
||||
app.use("/api", api);
|
||||
|
||||
app.get("/connect-area", connectArea);
|
||||
|
||||
app.use("/*", (req, res) => {
|
||||
res.send(`<!DOCTYPE html>
|
||||
|
||||
app.use("/*", (req, res) => {
|
||||
res.send(`<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>AI Adventure Labs</title>
|
||||
<meta charset="utf-8">
|
||||
</head>
|
||||
<body class="bg text-white">
|
||||
<div id="js-required">
|
||||
<h1>Error: Javascript off</h1><hr/>
|
||||
<p>Javascript is required for the site to work, enable it in your browser settings</p>
|
||||
</div>
|
||||
<script>
|
||||
document.getElementById("js-required").innerHTML = "<p>Loading...</p>";
|
||||
</script>
|
||||
<script src="/bootstrap/bootstrap.bundle.min.js" defer></script>
|
||||
<head>
|
||||
<title>AI Adventure Labs</title>
|
||||
<meta charset="utf-8">
|
||||
</head>
|
||||
<body class="bg text-white">
|
||||
<div id="js-required">
|
||||
<h1>Error: Javascript off</h1><hr/>
|
||||
<p>Javascript is required for the site to work, enable it in your browser settings</p>
|
||||
</div>
|
||||
<script>
|
||||
document.getElementById("js-required").innerHTML = "<p>Loading...</p>";
|
||||
</script>
|
||||
<script src="/bootstrap/bootstrap.bundle.min.js" defer></script>
|
||||
<script src="/fl_framework/index.js" defer></script>
|
||||
<script src="/js/translate.js" defer></script>
|
||||
<script src="/js/jsencrypt.js" defer></script>
|
||||
<script src="/js/main.js" defer></script>
|
||||
</body>
|
||||
</body>
|
||||
</html>`);
|
||||
});
|
||||
});
|
||||
|
||||
app.listen(port, address, (err) => {
|
||||
if (err) throw err;
|
||||
logger.log(`HTTP page successful runned at port ${port}`);
|
||||
});
|
||||
app.listen(port, address, (err) => {
|
||||
if (err)
|
||||
throw err;
|
||||
logger.log(`HTTP page successful runned at port ${port}`);
|
||||
});
|
||||
};
|
||||
|
@ -83,12 +83,6 @@ class ApiMethods extends ProtoApiMethods {
|
||||
gtf
|
||||
});
|
||||
}
|
||||
|
||||
async characters () {
|
||||
return await super._protoMethod({
|
||||
method: "characters"
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class ApiHTML {
|
||||
@ -108,9 +102,6 @@ class ApiHTML {
|
||||
|
||||
document.getElementById("server.area").innerHTML = '';
|
||||
$(document.getElementById("server.area")).append(ServerAuth.mainMenuForm);
|
||||
// JS-Events
|
||||
const charactersEvents = await this.api.methods.characters();
|
||||
console.debug({ charactersEvents });
|
||||
}
|
||||
|
||||
async renderAuth (authMode, bgUrl = null, favicon = null) {
|
||||
|
@ -1,29 +1,26 @@
|
||||
// cookie parser function
|
||||
function getCookies() {
|
||||
return Object.fromEntries(
|
||||
document.cookie
|
||||
.split(/\s{0,};\s{0,}/gimu)
|
||||
.map((i) => i.split(/\s{0,}=\s{0,}/gimu)),
|
||||
);
|
||||
function getCookies () {
|
||||
return Object.fromEntries(document.cookie.split(/\s{0,};\s{0,}/gmiu).map(i => i.split(/\s{0,}=\s{0,}/gmiu)));
|
||||
}
|
||||
|
||||
// translate function
|
||||
function translate(page) {
|
||||
[...document.getElementsByClassName("translate")].forEach((translateEl) => {
|
||||
function translate (page) {
|
||||
[...document.getElementsByClassName("translate")].forEach(translateEl => {
|
||||
// console.log(translateEl.id);
|
||||
const result = tr(page, translateEl.id);
|
||||
// console.log(result);
|
||||
if (result) translateEl.innerHTML = result;
|
||||
const result = tr(page, translateEl.id);
|
||||
// console.log(result);
|
||||
if (result)
|
||||
translateEl.innerHTML = result;
|
||||
});
|
||||
|
||||
[...document.getElementsByClassName("linked-btn")].forEach((el) => {
|
||||
|
||||
[...document.getElementsByClassName("linked-btn")].forEach(el => {
|
||||
el.style.cursor = "pointer";
|
||||
});
|
||||
}
|
||||
|
||||
// Get random integer number function
|
||||
function randint(min, max) {
|
||||
return Math.ceil(Math.random() * (max - min) + min);
|
||||
return Math.ceil((Math.random() * (max - min)) + min);
|
||||
}
|
||||
|
||||
// Get traceId for requests to server
|
||||
@ -35,12 +32,10 @@ function getTraceId() {
|
||||
}
|
||||
|
||||
// load styles
|
||||
document.head.innerHTML +=
|
||||
'\\n <link href="/bootstrap/bootstrap.min.css" rel="stylesheet">';
|
||||
document.head.innerHTML += '\\n <link href="/bootstrap/bootstrap.min.css" rel="stylesheet">';
|
||||
document.head.innerHTML += '\\n <link href="/css/main.css" rel="stylesheet">';
|
||||
document.head.innerHTML +=
|
||||
'\\n <link href="/font-awesome/css/all.css" rel="stylesheet">';
|
||||
document.head.innerHTML += '\\n <link rel="icon" href="/favicon.png">';
|
||||
document.head.innerHTML += '\\n <link href="/font-awesome/css/all.css" rel="stylesheet">';
|
||||
document.head.innerHTML += '\\n <link rel="icon" href="/favicon.png">'
|
||||
|
||||
// load main page
|
||||
document.body.innerHTML = `<nav id="navbar-main" class="navbar navbar-expand-lg navbar-dark bg-dark"><div class="container-fluid">
|
||||
@ -64,16 +59,13 @@ document.body.innerHTML = `<nav id="navbar-main" class="navbar navbar-expand-lg
|
||||
|
||||
</div>`;
|
||||
|
||||
function checkContentWarning(successfulHandler) {
|
||||
const warnModal = new bootstrap.Modal(
|
||||
document.getElementById("warningModal"),
|
||||
{},
|
||||
);
|
||||
document.getElementById("accept-denial-btn").onclick = () => {
|
||||
function checkContentWarning (successfulHandler) {
|
||||
const warnModal = new bootstrap.Modal(document.getElementById('warningModal'), {});
|
||||
document.getElementById('accept-denial-btn').onclick = () => {
|
||||
document.cookie = "cw=1";
|
||||
successfulHandler?.();
|
||||
};
|
||||
|
||||
|
||||
const cookies = getCookies();
|
||||
if (!cookies.cw) {
|
||||
warnModal.show();
|
||||
@ -85,17 +77,17 @@ function checkContentWarning(successfulHandler) {
|
||||
// Fl Handlers
|
||||
fl.bindLoad("/connect", () => {
|
||||
translate("/connect");
|
||||
|
||||
function initNewConnectionOpen() {
|
||||
|
||||
function initNewConnectionOpen () {
|
||||
if (initNewConnectionOpen.interval)
|
||||
clearInterval(initNewConnectionOpen.interval);
|
||||
document.getElementById("custom-conn-address").value = "";
|
||||
document.getElementById("custom-conn-port").value = 80;
|
||||
document.getElementById("custom-conn-encryption").checked = false;
|
||||
document.getElementById("custom-connect-btn").disabled = true;
|
||||
|
||||
|
||||
const connButton = document.getElementById("custom-connect-btn");
|
||||
|
||||
|
||||
initNewConnectionOpen.interval = setInterval(() => {
|
||||
const address = document.getElementById("custom-conn-address");
|
||||
// address.value
|
||||
@ -104,7 +96,7 @@ fl.bindLoad("/connect", () => {
|
||||
const isWSS = document.getElementById("custom-conn-encryption");
|
||||
// isWSS.checked
|
||||
// connButton.disabled
|
||||
|
||||
|
||||
if (address.value.match(/^wss:\/\//)) {
|
||||
address.value = address.value.slice(6);
|
||||
isWSS.checked = true;
|
||||
@ -114,30 +106,25 @@ fl.bindLoad("/connect", () => {
|
||||
isWSS.checked = false;
|
||||
}
|
||||
if (address.value.match(/:[0-9]{1,5}$/)) {
|
||||
const portSelected = +address.value
|
||||
.match(/:[0-9]{1,5}$/)
|
||||
.at(0)
|
||||
.slice(1);
|
||||
address.value = address.value.slice(
|
||||
0,
|
||||
-1 * (":" + portSelected).length,
|
||||
);
|
||||
const portSelected = +(address.value.match(/:[0-9]{1,5}$/).at(0).slice(1,));
|
||||
address.value = address.value.slice(0, -1 * (":"+portSelected).length);
|
||||
port.value = portSelected;
|
||||
document.getElementById("custom-conn-port").focus();
|
||||
}
|
||||
|
||||
|
||||
if (!port.value) {
|
||||
port.value = 80;
|
||||
}
|
||||
if (+port.value < 0) port.value = 0;
|
||||
if (+port.value > 65535) port.value = 65535;
|
||||
|
||||
if (+port.value < 0)
|
||||
port.value = 0;
|
||||
if (+port.value > 65535)
|
||||
port.value = 65535;
|
||||
|
||||
connButton.disabled = !address.value;
|
||||
}, 50);
|
||||
|
||||
|
||||
connButton.onclick = () => {
|
||||
const serverlist =
|
||||
JSON.parse(localStorage.getItem("savedServers") ?? "null") ?? [];
|
||||
const serverlist = JSON.parse(localStorage.getItem("savedServers") ?? "null") ?? [];
|
||||
serverlist.push({
|
||||
address: document.getElementById("custom-conn-address").value,
|
||||
port: +document.getElementById("custom-conn-port").value,
|
||||
@ -145,54 +132,40 @@ fl.bindLoad("/connect", () => {
|
||||
});
|
||||
localStorage.setItem("savedServers", JSON.stringify(serverlist));
|
||||
connectServers();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function connectServers() {
|
||||
document.getElementById("loading-servers").innerHTML =
|
||||
`<center><p>${tr("/connect", "loading") ?? "Loading..."}</p></center>`;
|
||||
|
||||
|
||||
function connectServers () {
|
||||
document.getElementById("loading-servers").innerHTML = `<center><p>${tr("/connect", "loading") ?? "Loading..."}</p></center>`;
|
||||
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.open("GET", "/api/active-servers.json", true);
|
||||
|
||||
|
||||
xhr.onerror = () => {
|
||||
document.getElementById("loading-servers").innerHTML = `<center>
|
||||
<h3>${tr("/connect", "connection-failed") ?? "Connection failed"}</h3><hr>
|
||||
<button type="button" class="btn btn-primary translate" id="retry-connecting">${tr("/connect", "retry-connecting") ?? "Retry"}</button>
|
||||
</center>`;
|
||||
document.getElementById("retry-connecting").onclick = () =>
|
||||
connectServers();
|
||||
};
|
||||
|
||||
document.getElementById("retry-connecting").onclick = () => connectServers();
|
||||
}
|
||||
|
||||
xhr.onload = async () => {
|
||||
if (xhr.status === 200) {
|
||||
const localServers = (
|
||||
JSON.parse(localStorage.getItem("savedServers") ?? "null") ?? []
|
||||
).map((x) => {
|
||||
x.fromLocal = true;
|
||||
return x;
|
||||
});
|
||||
|
||||
const servers = localServers.concat(
|
||||
JSON.parse(xhr.response).result.map((x) => {
|
||||
x.fromLocal = false;
|
||||
return x;
|
||||
}),
|
||||
);
|
||||
const localServers = (JSON.parse(localStorage.getItem("savedServers") ?? "null") ?? []).map(x => { x.fromLocal = true; return x });
|
||||
|
||||
const servers = localServers.concat(JSON.parse(xhr.response).result.map(x => { x.fromLocal = false; return x }));
|
||||
const serversByItemID = new Object();
|
||||
const serversByAddress = new Object();
|
||||
const items = [];
|
||||
const itemIDs = [];
|
||||
const mp = servers.map(async (serverItem) => {
|
||||
const mp = servers.map(async serverItem => {
|
||||
const promise = new Promise((resolve, reject) => {
|
||||
console.log("serverItem:", serverItem);
|
||||
const trace_id = getTraceId();
|
||||
const socket = new WebSocket(
|
||||
`${!serverItem.tls ? "ws" : "wss"}://${serverItem.address}:${serverItem.port}`,
|
||||
);
|
||||
const socket = new WebSocket(`${!serverItem.tls ? "ws" : "wss"}://${serverItem.address}:${serverItem.port}`);
|
||||
let ping = new Date();
|
||||
socket.onopen = () => {
|
||||
ping = new Date() - ping;
|
||||
ping = (new Date()) - ping;
|
||||
socket.onmessage = (ev) => {
|
||||
const data = JSON.parse(ev.data).result;
|
||||
console.debug("data:", data);
|
||||
@ -203,31 +176,22 @@ fl.bindLoad("/connect", () => {
|
||||
deleteID: `remove-con:${serverItem.address}:${serverItem.port}`,
|
||||
address: `${serverItem.address}:${serverItem.port}`,
|
||||
});
|
||||
serversByItemID[
|
||||
`con-btn-to:${data.tag}:${serverItem.address}:${serverItem.port}`
|
||||
] = { data, serverItem };
|
||||
serversByAddress[`${serverItem.address}:${serverItem.port}`] = {
|
||||
data,
|
||||
serverItem,
|
||||
};
|
||||
resolve(
|
||||
items.push(`<tr${!data.tls ? ' style="background-color: #7F6003"' : ""}>
|
||||
serversByItemID[`con-btn-to:${data.tag}:${serverItem.address}:${serverItem.port}`] = { data, serverItem };
|
||||
serversByAddress[`${serverItem.address}:${serverItem.port}`] = { data, serverItem };
|
||||
resolve(items.push(`<tr${!data.tls ? ' style="background-color: #7F6003"' : ""}>
|
||||
<td${!data.tls ? ' style="background-color: #7F6003"' : ""}>${data.name}</td>
|
||||
<td${!data.tls ? ' style="background-color: #7F6003"' : ""}>${serverItem.address}:${serverItem.port}</td>
|
||||
<td${!data.tls ? ' style="background-color: #7F6003"' : ""}>${!data.tls ? '<font color="red"><i class="fas fa-exclamation-triangle"></i></font>' : '<font color="green"><i class="fas fa-lock"></i></font>'}</td>
|
||||
<td${!data.tls ? ' style="background-color: #7F6003"' : ""}>${ping}</td>
|
||||
<td${!data.tls ? ' style="background-color: #7F6003"' : ""}><button class="btn btn-secondary" id="con-btn-to:${data.tag}:${serverItem.address}:${serverItem.port}">${tr("/connect", "connect-to-server-btn") ?? "Connect"}</button></td>
|
||||
<td${!data.tls ? ' style="background-color: #7F6003"' : ""}><button class="btn btn-outline-danger" id="remove-con:${serverItem.address}:${serverItem.port}"${!serverItem.fromLocal ? " disabled" : ""}><i class="fas fa-trash"></i></button></td>
|
||||
</tr>`),
|
||||
);
|
||||
<td${!data.tls ? ' style="background-color: #7F6003"' : ""}><button class="btn btn-outline-danger" id="remove-con:${serverItem.address}:${serverItem.port}"${!serverItem.fromLocal ? ' disabled' : ''}><i class="fas fa-trash"></i></button></td>
|
||||
</tr>`));
|
||||
};
|
||||
socket.send(
|
||||
JSON.stringify({
|
||||
method: "info",
|
||||
fields: "name,tag",
|
||||
trace_id,
|
||||
}),
|
||||
);
|
||||
socket.send(JSON.stringify({
|
||||
method: "info",
|
||||
fields: "name,tag",
|
||||
trace_id
|
||||
}));
|
||||
};
|
||||
socket.onerror = (err) => {
|
||||
console.error(err);
|
||||
@ -235,30 +199,23 @@ fl.bindLoad("/connect", () => {
|
||||
deleteID: `remove-con:${serverItem.address}:${serverItem.port}`,
|
||||
address: `${serverItem.address}:${serverItem.port}`,
|
||||
});
|
||||
serversByAddress[`${serverItem.address}:${serverItem.port}`] = {
|
||||
serverItem,
|
||||
};
|
||||
resolve(
|
||||
items.push(`<tr>
|
||||
serversByAddress[`${serverItem.address}:${serverItem.port}`] = { serverItem };
|
||||
resolve(items.push(`<tr>
|
||||
<td style="background-color: #7F0000"><font color="red">${tr("/connect", "offline-server") ?? "Offline"}</font></td>
|
||||
<td style="background-color: #7F0000">${serverItem.address}:${serverItem.port}</td>
|
||||
<td style="background-color: #7F0000"><font color="red"><i class="fas fa-exclamation-triangle"></i></font></td>
|
||||
<td style="background-color: #7F0000"><font color="red">${tr("/connect", "offline-server") ?? "Offline"}</font></td>
|
||||
<td style="background-color: #7F0000"><button class="btn btn-danger" disabled>${tr("/connect", "offline-server") ?? "Offline"}</button></td>
|
||||
<td style="background-color: #7F0000"><button class="btn btn-outline-danger" id="remove-con:${serverItem.address}:${serverItem.port}"${!serverItem.fromLocal ? " disabled" : ""}><i class="fas fa-trash"></i></button></td>
|
||||
</tr>`),
|
||||
);
|
||||
<td style="background-color: #7F0000"><button class="btn btn-outline-danger" id="remove-con:${serverItem.address}:${serverItem.port}"${!serverItem.fromLocal ? ' disabled' : ''}><i class="fas fa-trash"></i></button></td>
|
||||
</tr>`));
|
||||
};
|
||||
});
|
||||
return await promise;
|
||||
});
|
||||
|
||||
|
||||
await Promise.all(mp);
|
||||
items.push(
|
||||
`<tr><td colspan="6"><center><button class="btn btn-primary" id="conn-to-custom">${tr("/connect", "add-custon-server") ?? "Connect to custom server"}</button></center></td></tr>`,
|
||||
);
|
||||
document.getElementById("loading-servers").innerHTML =
|
||||
`<table class="table table-dark">
|
||||
items.push(`<tr><td colspan="6"><center><button class="btn btn-primary" id="conn-to-custom">${tr("/connect", "add-custon-server") ?? "Connect to custom server"}</button></center></td></tr>`);
|
||||
document.getElementById("loading-servers").innerHTML = `<table class="table table-dark">
|
||||
<thead>
|
||||
<th scope="col">${tr("/connect", "server-name-tbl") ?? "Name"}</th>
|
||||
<th scope="col">${tr("/connect", "server-address") ?? "Address"}</th>
|
||||
@ -271,111 +228,92 @@ fl.bindLoad("/connect", () => {
|
||||
${items.join("\n")}
|
||||
</tbody>
|
||||
</table>`;
|
||||
|
||||
itemIDs.forEach((btn) => {
|
||||
|
||||
itemIDs.forEach(btn => {
|
||||
//console.log("btn:", btn);
|
||||
if (btn.itemID)
|
||||
document.getElementById(btn.itemID).onclick = () => {
|
||||
checkContentWarning(() => {
|
||||
const serverInfo = serversByItemID[btn.itemID].serverItem;
|
||||
window.open(
|
||||
`/connect-area?server=${serverInfo.address}:${serverInfo.port}&encrypted=${serverInfo.tls ? "true" : "false"}`,
|
||||
);
|
||||
window.open(`/connect-area?server=${serverInfo.address}:${serverInfo.port}&encrypted=${serverInfo.tls ? "true" : "false"}`);
|
||||
});
|
||||
};
|
||||
|
||||
document.getElementById(btn.deleteID).onclick = () => {
|
||||
const serverInfo = serversByAddress[btn.address].serverItem;
|
||||
console.log("serverInfo:", serverInfo);
|
||||
const savedServers = (
|
||||
JSON.parse(localStorage.getItem("savedServers") ?? "null") ?? []
|
||||
).filter((server) => {
|
||||
return !(
|
||||
server.address === serverInfo.address &&
|
||||
server.port === serverInfo.port
|
||||
);
|
||||
});
|
||||
const savedServers = (JSON.parse(localStorage.getItem("savedServers") ?? "null") ?? [])
|
||||
.filter(server => {
|
||||
return !(server.address === serverInfo.address && server.port === serverInfo.port)
|
||||
});
|
||||
localStorage.setItem("savedServers", JSON.stringify(savedServers));
|
||||
connectServers();
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
document.getElementById("conn-to-custom").onclick = function () {
|
||||
const connectModal = new bootstrap.Modal(
|
||||
document.getElementById("connectModal"),
|
||||
{},
|
||||
);
|
||||
const connectModal = new bootstrap.Modal(document.getElementById('connectModal'), {});
|
||||
initNewConnectionOpen();
|
||||
connectModal.show();
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
xhr.send();
|
||||
}
|
||||
|
||||
|
||||
const cookies = getCookies();
|
||||
console.log(cookies);
|
||||
const cookiesModal = new bootstrap.Modal(
|
||||
document.getElementById("cookiesModal"),
|
||||
{},
|
||||
);
|
||||
|
||||
const cookiesModal = new bootstrap.Modal(document.getElementById('cookiesModal'), {});
|
||||
|
||||
if (!cookies.accept_cookies) {
|
||||
cookiesModal.show();
|
||||
} else {
|
||||
connectServers();
|
||||
}
|
||||
|
||||
|
||||
document.getElementById("accept-cookie-btn").onclick = () => {
|
||||
document.cookie = "accept_cookies=1";
|
||||
connectServers();
|
||||
};
|
||||
|
||||
|
||||
/*document.getElementById("enable-cookie-cnt").onclick = () => {
|
||||
cookiesModal.show();
|
||||
};*/
|
||||
});
|
||||
|
||||
fl.bindLoad("", () => {
|
||||
translate("/");
|
||||
translate("/");
|
||||
// carousel
|
||||
|
||||
function onMouse(condition) {
|
||||
function onMouse (condition) {
|
||||
return;
|
||||
[...document.getElementsByClassName("card-img")].forEach((img) => {
|
||||
[...document.getElementsByClassName("card-img")].forEach(img => {
|
||||
img.style.filter = `blur(${!condition ? 5 : 0}px)`;
|
||||
});
|
||||
}
|
||||
|
||||
onMouse(false);
|
||||
|
||||
[...document.getElementsByClassName("carousel-item")].forEach((item) => {
|
||||
[...document.getElementsByClassName("carousel-item")].forEach(item => {
|
||||
item.onmouseout = () => onMouse(false);
|
||||
item.onmouseover = () => onMouse(true);
|
||||
});
|
||||
|
||||
[...document.getElementsByClassName("btn-card")].forEach((item) => {
|
||||
[...document.getElementsByClassName("btn-card")].forEach(item => {
|
||||
item.onmouseout = () => onMouse(true);
|
||||
item.onmouseover = () => onMouse(false);
|
||||
});
|
||||
|
||||
const interval = setInterval(() => {
|
||||
const navbarHeight = +document.getElementById("navbar-main")?.offsetHeight;
|
||||
const navbarHeight = +(document.getElementById("navbar-main")?.offsetHeight);
|
||||
/*if (document.getElementById('main_img1')?.src) {
|
||||
document.getElementById('main_img1').src = window.screen.availWidth / window.screen.availHeight > 1.45 ? "/assets/hello/1.png" : "/assets/hello/m/1.png";
|
||||
document.getElementById('main_img2').src = window.screen.availWidth / window.screen.availHeight > 1.45 ? "/assets/hello/2.png" : "/assets/hello/m/2.png";
|
||||
document.getElementById('main_img3').src = window.screen.availWidth / window.screen.availHeight > 1.45 ? "/assets/hello/3.png" : "/assets/hello/m/3.png";
|
||||
}*/
|
||||
const selectedCSS = Object.entries(document.styleSheets).filter(
|
||||
([key, cssFileObject]) =>
|
||||
cssFileObject.href === `${location.origin}/css/main.css`,
|
||||
)[0][1];
|
||||
Object.entries(selectedCSS.rules).filter(
|
||||
([key, rule]) =>
|
||||
rule.selectorText ==
|
||||
".carousel > .carousel-inner > .carousel-item > img",
|
||||
)[0][1].style.height = `calc(100vh - ${navbarHeight}px)`;
|
||||
const selectedCSS = Object.entries(document.styleSheets).filter(([key, cssFileObject]) => cssFileObject.href === `${location.origin}/css/main.css`)[0][1];
|
||||
Object.entries(selectedCSS.rules).filter(([key, rule]) => rule.selectorText == '.carousel > .carousel-inner > .carousel-item > img')[0][1].style.height = `calc(100vh - ${navbarHeight}px)`;
|
||||
// console.log('ok');
|
||||
}, 1);
|
||||
|
||||
|
@ -12,69 +12,57 @@ const metaTranslate = {
|
||||
};
|
||||
|
||||
const translationTree = {
|
||||
"/": {
|
||||
"en-US": {
|
||||
"intro-1": "Welcome to Adventure AI Labs!",
|
||||
"description-1":
|
||||
"Embark on an unforgettable adventure with your favorite characters and friends! Visit familiar and unfamiliar locations..",
|
||||
"button-1": '<i class="fas fa-users"></i> Start the adventure',
|
||||
"/": {
|
||||
"en-US": {
|
||||
"intro-1": "Welcome to Adventure AI Labs!",
|
||||
"description-1": "Embark on an unforgettable adventure with your favorite characters and friends! Visit familiar and unfamiliar locations..",
|
||||
"button-1": '<i class="fas fa-users"></i> Start the adventure',
|
||||
|
||||
"intro-2": "Become a gamemaster",
|
||||
"description-2":
|
||||
"Or you can become the gamemaster of the party and lead the plot of the characters and players like a creator god who tells an amazing story.",
|
||||
"button-2": '<i class="fas fa-book"></i> Documentation',
|
||||
"intro-2": "Become a gamemaster",
|
||||
"description-2": "Or you can become the gamemaster of the party and lead the plot of the characters and players like a creator god who tells an amazing story.",
|
||||
"button-2": '<i class="fas fa-book"></i> Documentation',
|
||||
|
||||
"intro-3": "Needed a more gold..",
|
||||
"description-3":
|
||||
"The project exists purely on a voluntary basis and the enthusiasm of the author, so if you want to help financially, then it will be very cool (:",
|
||||
"button-3": '<i class="fab fa-bitcoin"></i> Donate',
|
||||
},
|
||||
"ru-RU": {
|
||||
"intro-1": "Добро пожаловать в Adventure AI Labs!",
|
||||
"description-1":
|
||||
"Отправьтесь в незабываемое приключение вместе со своими любимыми персонажами и друзьями! Посетите знакомые и незнакомые вам локации..",
|
||||
"button-1": '<i class="fas fa-users"></i> Начать приключение',
|
||||
"intro-3": "Needed a more gold..",
|
||||
"description-3": "The project exists purely on a voluntary basis and the enthusiasm of the author, so if you want to help financially, then it will be very cool (:",
|
||||
"button-3": '<i class="fab fa-bitcoin"></i> Donate',
|
||||
},
|
||||
"ru-RU": {
|
||||
"intro-1": "Добро пожаловать в Adventure AI Labs!",
|
||||
"description-1": "Отправьтесь в незабываемое приключение вместе со своими любимыми персонажами и друзьями! Посетите знакомые и незнакомые вам локации..",
|
||||
"button-1": '<i class="fas fa-users"></i> Начать приключение',
|
||||
|
||||
"intro-2": "Стань мастером партии",
|
||||
"description-2":
|
||||
"Либо же ты можешь стать мастером партии и вести сюжет персонажей и игроков словно бог-творец, который рассказывает удивительную историю.",
|
||||
"button-2": '<i class="fas fa-book"></i> Документация',
|
||||
"intro-2": "Стань мастером партии",
|
||||
"description-2": "Либо же ты можешь стать мастером партии и вести сюжет персонажей и игроков словно бог-творец, который рассказывает удивительную историю.",
|
||||
"button-2": '<i class="fas fa-book"></i> Документация',
|
||||
|
||||
"intro-3": "Нужно больше золота..",
|
||||
"description-3":
|
||||
"Проект существует сугубо на добровольном начале и энтузиазме автора, поэтому если вы захотите помочь финансово, то это будет очень круто (:",
|
||||
"button-3": '<i class="fab fa-bitcoin"></i> Задонатить',
|
||||
},
|
||||
},
|
||||
"/connect": {
|
||||
"en-US": {
|
||||
title: "Server list",
|
||||
"intro-3": "Нужно больше золота..",
|
||||
"description-3": "Проект существует сугубо на добровольном начале и энтузиазме автора, поэтому если вы захотите помочь финансово, то это будет очень круто (:",
|
||||
"button-3": '<i class="fab fa-bitcoin"></i> Задонатить',
|
||||
}
|
||||
},
|
||||
"/connect": {
|
||||
"en-US": {
|
||||
title: "Server list",
|
||||
"enable-cookie-cnt": "Enable Cookie!",
|
||||
"enable-cookie-text-cnt":
|
||||
"To work with servers, accept the cookie agreement",
|
||||
"enable-cookie-text-cnt": "To work with servers, accept the cookie agreement",
|
||||
"accept-cookie-show-btn": "Show",
|
||||
|
||||
exampleModalLabel: '<i class="fas fa-cookie"></i> Accept cookies',
|
||||
cookiesText:
|
||||
"We are obliged to warn you that the AI Adventure Labs protocol client uses cookies for: authorization, storage of session keys and user consent to the use of cookies",
|
||||
"accept-cookie-btn": "Accept",
|
||||
|
||||
exampleModalLabel: "<i class=\"fas fa-cookie\"></i> Accept cookies",
|
||||
cookiesText: "We are obliged to warn you that the AI Adventure Labs protocol client uses cookies for: authorization, storage of session keys and user consent to the use of cookies",
|
||||
"accept-cookie-btn": "Accept",
|
||||
loading: "Loading of servers...",
|
||||
|
||||
titleDenial:
|
||||
'<i class="fas fa-exclamation-triangle"></i> Denial of responsibility',
|
||||
denialText:
|
||||
"The server data does not belong to a centrally moderated foundation, community or individual, as well as to the developer of the software, program interface (protocol client), or protocol developer. Any content posted on servers is posted by the server administrator and can be absolutely anything. <b>You assume all risks for the content and connect to the server at your own peril and risk!</b>",
|
||||
|
||||
titleDenial: '<i class="fas fa-exclamation-triangle"></i> Denial of responsibility',
|
||||
denialText: 'The server data does not belong to a centrally moderated foundation, community or individual, as well as to the developer of the software, program interface (protocol client), or protocol developer. Any content posted on servers is posted by the server administrator and can be absolutely anything. <b>You assume all risks for the content and connect to the server at your own peril and risk!</b>',
|
||||
"accept-denial-btn": "Accept",
|
||||
|
||||
titleCustomServerConnect:
|
||||
'<i class="fas fa-wifi"></i> Connect to remote server',
|
||||
titleCustomConnect: "Connection Data",
|
||||
addressCustomConnect:
|
||||
"Enter address of server (without ws(s):// and port)",
|
||||
portCustomConnect: "Enter port of server",
|
||||
tlsCustomConnect: "Check this if server use TLS (wss:// connection):",
|
||||
|
||||
titleCustomServerConnect: '<i class="fas fa-wifi"></i> Connect to remote server',
|
||||
titleCustomConnect: 'Connection Data',
|
||||
addressCustomConnect: 'Enter address of server (without ws(s):// and port)',
|
||||
portCustomConnect: 'Enter port of server',
|
||||
tlsCustomConnect: 'Check this if server use TLS (wss:// connection):',
|
||||
"custom-connect-btn": "Connect",
|
||||
|
||||
|
||||
"server-name-tbl": "Name",
|
||||
"server-address": "Address",
|
||||
"server-encryption": "Encryprtion",
|
||||
@ -86,33 +74,28 @@ const translationTree = {
|
||||
"connection-failed": "Connection failed",
|
||||
"retry-connecting": "Retry",
|
||||
},
|
||||
"ru-RU": {
|
||||
title: "Список серверов",
|
||||
"ru-RU": {
|
||||
title: "Список серверов",
|
||||
"enable-cookie-cnt": "Примите соглашение о Cookie!",
|
||||
"enable-cookie-text-cnt":
|
||||
"Для работы с серверами, примите соглашение об использовании файлов Cookie",
|
||||
"enable-cookie-text-cnt": "Для работы с серверами, примите соглашение об использовании файлов Cookie",
|
||||
"accept-cookie-show-btn": "Посмотреть",
|
||||
|
||||
exampleModalLabel: '<i class="fas fa-cookie"></i> Вопрос с печеньками',
|
||||
cookiesText:
|
||||
"Мы обязаны вас предупредить, что клиент протокола AI Adventure Labs использует файлы куки для: авторизации, хранения ключей сессии и согласия пользователя на использование куки",
|
||||
"accept-cookie-btn": "Принять",
|
||||
|
||||
exampleModalLabel: "<i class=\"fas fa-cookie\"></i> Вопрос с печеньками",
|
||||
cookiesText: "Мы обязаны вас предупредить, что клиент протокола AI Adventure Labs использует файлы куки для: авторизации, хранения ключей сессии и согласия пользователя на использование куки",
|
||||
"accept-cookie-btn": "Принять",
|
||||
loading: "Загрузка серверов...",
|
||||
|
||||
titleDenial:
|
||||
'<i class="fas fa-exclamation-triangle"></i> Отказ от отвественности',
|
||||
denialText:
|
||||
"Данные сервера не принадлежат централизованно-модерируемому фонду, сообществу или частному лицу, а также разработчику программного обеспечения, програмного интерфейса (клиента протокола), разработчику протокола. Любой размещённый на серверах контент размещается администратором сервера и может быть абсолютно любым. <b>Все риски за контент вы берёте полностью на себя и подключаетесь к серверу на свой страх и риск!</b>",
|
||||
|
||||
titleDenial: '<i class="fas fa-exclamation-triangle"></i> Отказ от отвественности',
|
||||
denialText: 'Данные сервера не принадлежат централизованно-модерируемому фонду, сообществу или частному лицу, а также разработчику программного обеспечения, програмного интерфейса (клиента протокола), разработчику протокола. Любой размещённый на серверах контент размещается администратором сервера и может быть абсолютно любым. <b>Все риски за контент вы берёте полностью на себя и подключаетесь к серверу на свой страх и риск!</b>',
|
||||
"accept-denial-btn": "Принять",
|
||||
|
||||
titleCustomServerConnect:
|
||||
'<i class="fas fa-wifi"></i> Прямое подключение к серверу',
|
||||
titleCustomConnect: "Данные подключения",
|
||||
addressCustomConnect: "Адрес сервера (без порта и ws(s)://)",
|
||||
portCustomConnect: "Порт сервера",
|
||||
tlsCustomConnect: "Использовать защищённое соединение (TLS) (wss://):",
|
||||
|
||||
titleCustomServerConnect: '<i class="fas fa-wifi"></i> Прямое подключение к серверу',
|
||||
titleCustomConnect: 'Данные подключения',
|
||||
addressCustomConnect: 'Адрес сервера (без порта и ws(s)://)',
|
||||
portCustomConnect: 'Порт сервера',
|
||||
tlsCustomConnect: 'Использовать защищённое соединение (TLS) (wss://):',
|
||||
"custom-connect-btn": "Подключиться",
|
||||
|
||||
|
||||
"server-name-tbl": "Имя сервера",
|
||||
"server-address": "Адрес",
|
||||
"server-encryption": "Шифрование",
|
||||
@ -123,40 +106,33 @@ const translationTree = {
|
||||
"connect-to-server-btn": "Подключиться",
|
||||
"connection-failed": "Соединение оборвалось",
|
||||
"retry-connecting": "Повторить попытку",
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
"/connect-area": {
|
||||
"en-US": {},
|
||||
"ru-RU": {},
|
||||
},
|
||||
};
|
||||
"ru-RU": {}
|
||||
}
|
||||
}
|
||||
|
||||
Object.entries(translationTree).forEach(([page, langs]) => {
|
||||
Object.entries(langs).forEach(([lang]) => {
|
||||
translationTree[page][lang] = {
|
||||
...translationTree[page][lang],
|
||||
...metaTranslate[lang],
|
||||
};
|
||||
translationTree[page][lang] = {...translationTree[page][lang], ...metaTranslate[lang]};
|
||||
});
|
||||
});
|
||||
|
||||
console.log(translationTree);
|
||||
|
||||
const simpleLangTags = {
|
||||
ru: "ru-RU",
|
||||
en: "en-US",
|
||||
"ru": "ru-RU",
|
||||
"en": "en-US",
|
||||
};
|
||||
|
||||
function tr(page, id) {
|
||||
let lang = navigator.language || navigator.userLanguage;
|
||||
lang =
|
||||
lang.split("-").length === 1 ? (simpleLangTags[lang] ?? "en-US") : lang;
|
||||
function tr (page, id) {
|
||||
let lang = navigator.language || navigator.userLanguage;
|
||||
lang = lang.split("-").length === 1 ? (simpleLangTags[lang] ?? "en-US") : lang;
|
||||
// Britains sucks, Sir Keir Starmer (Sir Dicksucker) is faggot, he is sucking a muslim's dicks.
|
||||
if (lang === "en-UK") lang = "en-US";
|
||||
// console.log("lang is", lang);
|
||||
return (
|
||||
translationTree[page]?.[lang]?.[id] ??
|
||||
translationTree[page]?.["en-US"][id] ??
|
||||
null
|
||||
);
|
||||
if (lang === "en-UK")
|
||||
lang = "en-US";
|
||||
// console.log("lang is", lang);
|
||||
return (translationTree[page]?.[lang]?.[id] ?? translationTree[page]?.["en-US"][id]) ?? null
|
||||
}
|
||||
|
@ -1,12 +1,6 @@
|
||||
class Logger {
|
||||
static log (...p) {
|
||||
console.log("[", new Date(), "]:", ...p);
|
||||
}
|
||||
static warn (...p) {
|
||||
console.warn("[", new Date(), "]:", ...p);
|
||||
}
|
||||
static debug (...p) {
|
||||
console.debug("[", new Date(), "]:", ...p);
|
||||
}
|
||||
static wslog (...p) {
|
||||
// return;
|
||||
|
1597
server/package-lock.json
generated
1597
server/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -1,17 +1,13 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"aes-js": "^3.1.2",
|
||||
"bcrypt": "^6.0.0",
|
||||
"crypto": "^1.0.1",
|
||||
"express": "^4.19.2",
|
||||
"fs": "^0.0.1-security",
|
||||
"https": "^1.0.0",
|
||||
"md5": "^2.3.0",
|
||||
"net": "^1.0.2",
|
||||
"path": "^0.12.7",
|
||||
"selfsigned": "^2.4.1",
|
||||
"sequelize": "^6.37.7",
|
||||
"sqlite3": "^5.1.7",
|
||||
"ws": "^7.5.10"
|
||||
},
|
||||
"name": "ai-adventure-labs-server",
|
||||
|
@ -4,8 +4,6 @@ const parser = require("./packet-parser");
|
||||
const frontend = require("./frontend");
|
||||
const websocket = require("./ws-handler");
|
||||
const crypt = require("./crypt");
|
||||
const Database = require("./database");
|
||||
|
||||
const EventEmitter = require("events");
|
||||
const net = require("net");
|
||||
const fs = require("fs");
|
||||
@ -13,29 +11,10 @@ const path = require("path");
|
||||
|
||||
const { API } = require("./api");
|
||||
|
||||
// So.. what part of the WeakMap/Server class made you think
|
||||
// Oh! Developer of this AI client agrees that
|
||||
// [Object Server].isLocked can be writeable?
|
||||
const isLockedServer = new WeakMap();
|
||||
|
||||
class Server extends EventEmitter {
|
||||
constructor() {
|
||||
super();
|
||||
this.on("config.update", ({ oldConfig, newConfig }) => {});
|
||||
//this.isLocked = false;
|
||||
isLockedServer.set(this, false);
|
||||
}
|
||||
|
||||
set isLocked (_) {
|
||||
throw new Error("isLocked not writeable");
|
||||
}
|
||||
|
||||
get isLocked () {
|
||||
return isLockedServer.get(this);
|
||||
}
|
||||
|
||||
toggleLock (mode = true) {
|
||||
isLockedServer.set(this, !!mode);
|
||||
}
|
||||
|
||||
run(address, port) {
|
||||
@ -206,8 +185,7 @@ const defaultConfigData = {
|
||||
},
|
||||
database: {
|
||||
dialect: "sqlite",
|
||||
storage: "./data.db",
|
||||
logging: false
|
||||
path: "./data",
|
||||
},
|
||||
ai: {
|
||||
apiType: "kobold",
|
||||
@ -221,12 +199,63 @@ const defaultConfigData = {
|
||||
|
||||
global.server = new Server();
|
||||
cfgHandle(global.server, defaultConfigData, logger);
|
||||
global.database = new Database(global.config.database);
|
||||
global.database.init()
|
||||
.then(() => {
|
||||
logger.log("Current config:", global.config);
|
||||
global.server.run(global.config.server.address, global.config.server.port);
|
||||
})
|
||||
.catch((err) => {
|
||||
throw err;
|
||||
|
||||
logger.log("Current config:", global.config);
|
||||
|
||||
global.server.run(global.config.server.address, global.config.server.port);
|
||||
|
||||
/*
|
||||
if (global.config.server.secureMode) {
|
||||
async function initEncryption () {
|
||||
const datadir = global.config.server["ssl-path"] ?? path.join(__dirname, "/encryption");
|
||||
|
||||
function generate () {
|
||||
logger.log("Generate new keys...");
|
||||
global.openSSH = crypt.generateOpenSSH({
|
||||
commonName: global.config.server.info.name
|
||||
}, {
|
||||
days: 365,
|
||||
pkcs7: true,
|
||||
clientCertificate: true,
|
||||
clientCertificateCN: "AI Adventure Labs",
|
||||
algorithm: 'sha256',
|
||||
keySize: 2048,
|
||||
});
|
||||
fs.writeFileSync(path.join(datadir, "public.pem"), global.openSSH.public_key.bytes);
|
||||
fs.writeFileSync(path.join(datadir, "private.pem"), global.openSSH.private_key.bytes);
|
||||
fs.writeFileSync(path.join(datadir, "cert.crt"), global.openSSH.cert);
|
||||
}
|
||||
|
||||
const readFilePromise = new Promise((resolve, reject) => {
|
||||
fs.readFile(path.join(datadir, "public.pem"), (err, public_key) => {
|
||||
if (err) {
|
||||
return resolve(generate());
|
||||
}
|
||||
try {
|
||||
public_key = new crypt.CryptKey(public_key);
|
||||
const private_key = new crypt.CryptKey(fs.readFileSync(path.join(datadir, "private.pem")));
|
||||
const cert = fs.readFileSync(path.join(datadir, "cert.crt"));
|
||||
|
||||
global.openSSH = new crypt.OpenSSH({
|
||||
public_key, private_key, cert
|
||||
});
|
||||
resolve();
|
||||
} catch (_) {
|
||||
resolve(generate());
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
await readFilePromise;
|
||||
|
||||
logger.log(`loaded from ${datadir}`);
|
||||
};
|
||||
initEncryption().then(() => {
|
||||
server.run(global.config.server.address, global.config.server.port);
|
||||
}).catch(e => {
|
||||
throw e;
|
||||
});
|
||||
}
|
||||
else
|
||||
server.run(global.config.server.address, global.config.server.port);
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user