Browse Source

initial commit

tags/0.1.0
Dale 1 year ago
commit
0db4ba147e
15 changed files with 9630 additions and 0 deletions
  1. +1
    -0
      .envrc
  2. +1
    -0
      .gitignore
  3. +13
    -0
      default.nix
  4. +225
    -0
      dist/server/bundle.js
  5. +41
    -0
      package.json
  6. +27
    -0
      src/lib/mastodon.ts
  7. +23
    -0
      src/lib/mumble.ts
  8. +15
    -0
      src/lib/xmpp.ts
  9. +35
    -0
      src/server.ts
  10. +97
    -0
      src/templates/index.ejs
  11. +1
    -0
      src/typings.d.ts
  12. +16
    -0
      tsconfig.json
  13. +37
    -0
      webpack.config.server.js
  14. +4374
    -0
      yarn-error.log
  15. +4724
    -0
      yarn.lock

+ 1
- 0
.envrc View File

@@ -0,0 +1 @@
use_nix

+ 1
- 0
.gitignore View File

@@ -0,0 +1 @@
node_modules/

+ 13
- 0
default.nix View File

@@ -0,0 +1,13 @@
with import <nixpkgs> {};

stdenv.mkDerivation {
name = "gensoc-status";
version = "0.1.0";
system = builtins.currentSystem;

buildInputs = [
automake autoconf m4 git bash
nodejs-10_x libpng libGL gcc
(yarn.override { nodejs = nodejs-10_x; })
];
}

+ 225
- 0
dist/server/bundle.js View File

@@ -0,0 +1,225 @@
/******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId]) {
/******/ return installedModules[moduleId].exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ i: moduleId,
/******/ l: false,
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ // Flag the module as loaded
/******/ module.l = true;
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/******/
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/
/******/ // define getter function for harmony exports
/******/ __webpack_require__.d = function(exports, name, getter) {
/******/ if(!__webpack_require__.o(exports, name)) {
/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter });
/******/ }
/******/ };
/******/
/******/ // define __esModule on exports
/******/ __webpack_require__.r = function(exports) {
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
/******/ }
/******/ Object.defineProperty(exports, '__esModule', { value: true });
/******/ };
/******/
/******/ // create a fake namespace object
/******/ // mode & 1: value is a module id, require it
/******/ // mode & 2: merge all properties of value into the ns
/******/ // mode & 4: return value when already ns object
/******/ // mode & 8|1: behave like require
/******/ __webpack_require__.t = function(value, mode) {
/******/ if(mode & 1) value = __webpack_require__(value);
/******/ if(mode & 8) return value;
/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
/******/ var ns = Object.create(null);
/******/ __webpack_require__.r(ns);
/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value });
/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
/******/ return ns;
/******/ };
/******/
/******/ // getDefaultExport function for compatibility with non-harmony modules
/******/ __webpack_require__.n = function(module) {
/******/ var getter = module && module.__esModule ?
/******/ function getDefault() { return module['default']; } :
/******/ function getModuleExports() { return module; };
/******/ __webpack_require__.d(getter, 'a', getter);
/******/ return getter;
/******/ };
/******/
/******/ // Object.prototype.hasOwnProperty.call
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "";
/******/
/******/
/******/ // Load entry module and return exports
/******/ return __webpack_require__(__webpack_require__.s = "./src/server.ts");
/******/ })
/************************************************************************/
/******/ ({

/***/ "./src/lib/mastodon.ts":
/*!*****************************!*\
!*** ./src/lib/mastodon.ts ***!
\*****************************/
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
eval("\nObject.defineProperty(exports, \"__esModule\", { value: true });\nconst axios_1 = __webpack_require__(/*! axios */ \"axios\");\nconst R = __webpack_require__(/*! ramda */ \"ramda\");\nconst tls = __webpack_require__(/*! tls */ \"tls\");\ntls.DEFAULT_ECDH_CURVE = 'auto';\nfunction getMastodonStatus(address) {\n return axios_1.default.get(`${address}/api/v1/instance`)\n .then((resp) => ({\n online: true,\n version: R.pathOr('N/A', ['data', 'version'], resp),\n totalUsers: R.pathOr(0, ['data', 'stats', 'user_count'], resp),\n totalStatuses: R.pathOr(0, ['data', 'stats', 'status_count'], resp),\n knownDomains: R.pathOr(0, ['data', 'stats', 'domain_count'], resp),\n }))\n .catch(() => ({\n online: false,\n }));\n}\nexports.default = getMastodonStatus;\n\n\n//# sourceURL=webpack:///./src/lib/mastodon.ts?");

/***/ }),

/***/ "./src/lib/mumble.ts":
/*!***************************!*\
!*** ./src/lib/mumble.ts ***!
\***************************/
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
eval("\nObject.defineProperty(exports, \"__esModule\", { value: true });\nconst GameDig = __webpack_require__(/*! gamedig */ \"gamedig\");\nconst R = __webpack_require__(/*! ramda */ \"ramda\");\nconst offlineStatus = { online: false };\nfunction getMumbleStatus(host, port = 64738) {\n return GameDig.query({\n type: 'mumbleping',\n host, port\n }).then((res) => {\n return {\n online: true,\n currentUsers: R.length(R.pathOr([], ['players'], res)),\n maxUsers: res.maxplayers,\n };\n }).catch(() => offlineStatus);\n}\nexports.default = getMumbleStatus;\n\n\n//# sourceURL=webpack:///./src/lib/mumble.ts?");

/***/ }),

/***/ "./src/lib/xmpp.ts":
/*!*************************!*\
!*** ./src/lib/xmpp.ts ***!
\*************************/
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
eval("\nObject.defineProperty(exports, \"__esModule\", { value: true });\nconst shelljs = __webpack_require__(/*! async-shelljs */ \"async-shelljs\");\nfunction getXMPPStatus(host, port = 5222) {\n return shelljs.asyncExec(`curl http://${host}:${port} --max-time 5`, { silent: true })\n .then(() => {\n return { online: true };\n }).catch(() => {\n return { online: false };\n });\n}\nexports.default = getXMPPStatus;\n\n\n//# sourceURL=webpack:///./src/lib/xmpp.ts?");

/***/ }),

/***/ "./src/server.ts":
/*!***********************!*\
!*** ./src/server.ts ***!
\***********************/
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
eval("\nObject.defineProperty(exports, \"__esModule\", { value: true });\nconst Express = __webpack_require__(/*! express */ \"express\");\nconst ejs = __webpack_require__(/*! ejs */ \"ejs\");\nconst R = __webpack_require__(/*! ramda */ \"ramda\");\nconst mumble_1 = __webpack_require__(/*! src/lib/mumble */ \"./src/lib/mumble.ts\");\nconst mastodon_1 = __webpack_require__(/*! src/lib/mastodon */ \"./src/lib/mastodon.ts\");\nconst nodecache_as_promised_1 = __webpack_require__(/*! @nrk/nodecache-as-promised */ \"@nrk/nodecache-as-promised\");\nconst xmpp_1 = __webpack_require__(/*! ./lib/xmpp */ \"./src/lib/xmpp.ts\");\nconst cache = nodecache_as_promised_1.default({ initial: {}, maxAge: 60000 });\nconst app = Express();\nconst updateMastodonStatus = () => mastodon_1.default('https://gensokyo.social');\nconst updateMumbleStatus = () => mumble_1.default('gensokyo.social');\nconst updateXMPPStatus = () => xmpp_1.default('gensokyo.social');\nconst getFromCache = () => Promise.all([\n cache.get('mastodonStatus', { worker: updateMastodonStatus, ttl: 60000 }),\n cache.get('mumbleStatus', { worker: updateMumbleStatus, ttl: 60000 }),\n cache.get('XMPPStatus', { worker: updateXMPPStatus, ttl: 60000 }),\n]).then(R.map(val => val.value));\napp.get('/', (_, res) => {\n getFromCache().then(([mastodonStatus, mumbleStatus, XMPPStatus]) => {\n ejs.renderFile('./src/templates/index.ejs', { mastodonStatus, mumbleStatus, XMPPStatus }, {}, (err, str) => {\n res.status(200).send(str);\n });\n });\n});\napp.listen(8080, () => {\n console.log('listening on 8080');\n});\n\n\n//# sourceURL=webpack:///./src/server.ts?");

/***/ }),

/***/ "@nrk/nodecache-as-promised":
/*!*********************************************!*\
!*** external "@nrk/nodecache-as-promised" ***!
\*********************************************/
/*! no static exports found */
/***/ (function(module, exports) {

eval("module.exports = require(\"@nrk/nodecache-as-promised\");\n\n//# sourceURL=webpack:///external_%22@nrk/nodecache-as-promised%22?");

/***/ }),

/***/ "async-shelljs":
/*!********************************!*\
!*** external "async-shelljs" ***!
\********************************/
/*! no static exports found */
/***/ (function(module, exports) {

eval("module.exports = require(\"async-shelljs\");\n\n//# sourceURL=webpack:///external_%22async-shelljs%22?");

/***/ }),

/***/ "axios":
/*!************************!*\
!*** external "axios" ***!
\************************/
/*! no static exports found */
/***/ (function(module, exports) {

eval("module.exports = require(\"axios\");\n\n//# sourceURL=webpack:///external_%22axios%22?");

/***/ }),

/***/ "ejs":
/*!**********************!*\
!*** external "ejs" ***!
\**********************/
/*! no static exports found */
/***/ (function(module, exports) {

eval("module.exports = require(\"ejs\");\n\n//# sourceURL=webpack:///external_%22ejs%22?");

/***/ }),

/***/ "express":
/*!**************************!*\
!*** external "express" ***!
\**************************/
/*! no static exports found */
/***/ (function(module, exports) {

eval("module.exports = require(\"express\");\n\n//# sourceURL=webpack:///external_%22express%22?");

/***/ }),

/***/ "gamedig":
/*!**************************!*\
!*** external "gamedig" ***!
\**************************/
/*! no static exports found */
/***/ (function(module, exports) {

eval("module.exports = require(\"gamedig\");\n\n//# sourceURL=webpack:///external_%22gamedig%22?");

/***/ }),

/***/ "ramda":
/*!************************!*\
!*** external "ramda" ***!
\************************/
/*! no static exports found */
/***/ (function(module, exports) {

eval("module.exports = require(\"ramda\");\n\n//# sourceURL=webpack:///external_%22ramda%22?");

/***/ }),

/***/ "tls":
/*!**********************!*\
!*** external "tls" ***!
\**********************/
/*! no static exports found */
/***/ (function(module, exports) {

eval("module.exports = require(\"tls\");\n\n//# sourceURL=webpack:///external_%22tls%22?");

/***/ })

/******/ });

+ 41
- 0
package.json View File

@@ -0,0 +1,41 @@
{
"name": "status",
"version": "0.1.0",
"description": "Status of GenSoc services",
"main": " server.ts",
"author": "Dale <deiru2k@gmail.com>",
"license": "MIT",
"private": false,
"scripts": {
"run:server": "./node_modules/.bin/webpack --config webpack.config.server.js --watch"
},
"dependencies": {
"@nrk/nodecache-as-promised": "^1.3.2",
"@xmpp/client": "^0.7.3",
"async-shelljs": "^0.1.2",
"axios": "^0.19.0",
"ejs": "^2.6.1",
"express": "^4.17.1",
"gamedig": "^2.0.14",
"promise-cache": "^0.1.8",
"ramda": "^0.26.1",
"shelljs": "^0.8.3",
"superagent": "^5.0.5"
},
"devDependencies": {
"@types/ejs": "^2.6.3",
"@types/express": "^4.16.1",
"@types/gamedig": "^1.0.0",
"@types/node": "^12.0.4",
"@types/node-xmpp-client": "^3.1.4",
"@types/ramda": "^0.26.9",
"@types/shelljs": "^0.8.5",
"@types/superagent": "^4.1.1",
"nodemon-webpack-plugin": "^4.0.8",
"ts-loader": "^6.0.2",
"typescript": "^3.5.1",
"webpack": "^4.32.2",
"webpack-cli": "^3.3.2",
"webpack-node-externals": "^1.7.2"
}
}

+ 27
- 0
src/lib/mastodon.ts View File

@@ -0,0 +1,27 @@
import axios from 'axios';
import * as R from 'ramda';
import * as tls from 'tls';

(tls as any).DEFAULT_ECDH_CURVE = 'auto';

interface MastodonStatus {
online: boolean;
totalUsers?: number;
totalStatuses?: number;
knownDomains?: number;
version?: string;
}

export default function getMastodonStatus(address: string): PromiseLike<MastodonStatus> {
return axios.get(`${address}/api/v1/instance`)
.then((resp) => ({
online: true,
version: R.pathOr('N/A', ['data', 'version'], resp),
totalUsers: R.pathOr(0, ['data', 'stats', 'user_count'], resp),
totalStatuses: R.pathOr(0, ['data', 'stats', 'status_count'], resp),
knownDomains: R.pathOr(0, ['data', 'stats', 'domain_count'], resp),
}))
.catch(() => ({
online: false,
}))
}

+ 23
- 0
src/lib/mumble.ts View File

@@ -0,0 +1,23 @@
import * as GameDig from 'gamedig';
import * as R from 'ramda';

interface MumbleStatus {
online: boolean,
currentUsers?: number,
maxUsers?: number,
}

const offlineStatus: MumbleStatus = { online: false };

export default function getMumbleStatus (host: string, port: number = 64738): PromiseLike<MumbleStatus> {
return GameDig.query({
type: 'mumbleping',
host, port
}).then((res) => {
return {
online: true,
currentUsers: R.length(R.pathOr([], ['players'], res)),
maxUsers: res.maxplayers,
}
}).catch(() => offlineStatus);
}

+ 15
- 0
src/lib/xmpp.ts View File

@@ -0,0 +1,15 @@
import axios from 'axios';
import * as shelljs from 'async-shelljs'

interface XMPPStatus {
online: boolean;
}

export default function getXMPPStatus(host: string, port: number = 5222): PromiseLike<XMPPStatus> {
return shelljs.asyncExec(`curl http://${host}:${port} --max-time 5`, { silent: true })
.then(() => {
return { online: true };
}).catch(() => {
return { online: false };
})
}

+ 35
- 0
src/server.ts View File

@@ -0,0 +1,35 @@
import * as Express from 'express';
import * as ejs from 'ejs';
import * as R from 'ramda';

import getMumbleStatus from 'src/lib/mumble';
import getMastodonStatus from 'src/lib/mastodon';
import inMemoryCache from '@nrk/nodecache-as-promised'
import getXMPPStatus from './lib/xmpp';

const cache = inMemoryCache({ initial: {}, maxAge: 60000 });
const app = Express();


const updateMastodonStatus = () => getMastodonStatus('https://gensokyo.social');
const updateMumbleStatus = () => getMumbleStatus('gensokyo.social');
const updateXMPPStatus = () => getXMPPStatus('gensokyo.social');


const getFromCache = () => Promise.all([
cache.get('mastodonStatus', { worker: updateMastodonStatus, ttl: 60000 }),
cache.get('mumbleStatus', { worker: updateMumbleStatus, ttl: 60000 }),
cache.get('XMPPStatus', { worker: updateXMPPStatus, ttl: 60000 }),
]).then(R.map(val => val.value));

app.get('/', (_, res) => {
getFromCache().then(([mastodonStatus, mumbleStatus, XMPPStatus]) => {
ejs.renderFile('./src/templates/index.ejs', { mastodonStatus, mumbleStatus, XMPPStatus}, {}, (err, str) => {
res.status(200).send(str);
});
})
});

app.listen(8080, () => {
console.log('listening on 8080')
});

+ 97
- 0
src/templates/index.ejs View File

@@ -0,0 +1,97 @@
<html>
<head>
<title>GenSoc Status</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
</head>
<body>
<div class="container mt-5">
<div class="row">
<div class="col col-md-12">
<h3>
Gensokyo.social services status page<br />
<small class="text-muted">We offer a number of services for our users. Here you can monitor their status and find useful info on how to use them</small>
</h3>
</div>
</div>
<hr />
<div class="row mt-3">
<div class="col col-md-12">
<div class="card">
<div class="card-body <% if (mastodonStatus.online) { %>bg-success<% } else { %>bg-error<% } %> text-white">
<h5 class="card-title">Mastodon is <% if (mastodonStatus.online) { %> Online <% } else { %>Offline<% } %></h5>
<p class="card-text">
Free and decentralized microblogging social network
</p>
</div>
<ul class="list-group list-group-flush">
<li class="list-group-item">
Total users: <span class="badge badge-primary"><%= mastodonStatus.totalUsers %></span>
</li>
<li class="list-group-item">
Total statuses: <span class="badge badge-primary"><%= mastodonStatus.totalStatuses %></span>
</li>
<li class="list-group-item">
Known domains: <span class="badge badge-primary"><%= mastodonStatus.knownDomains %></span>
</li>
</ul>
<div class="card-body">
<a href="https://gensokyo.social" target="_blank" class="card-link">Visit site</a>
</div>
<div class="card-body">
<a href="https://gensokyo.social/explore" target="_blank" class="card-link">Profile directory</a>
<a href="https://gensokyo.social/about/more" target="_blank" class="card-link">Rules</a>
<a href="https://gensokyo.social/terms" target="_blank" class="card-link">Terms of Service</a>
</div>
<div class="card-body">
<a href="https://fedilab.app/" target="_blank" class="card-link">Android Client</a>
<a href="https://itunes.apple.com/us/app/toot/id1229021451?mt=8" target="_blank" class="card-link">iOS Client</a>
</div>
</div>
</div>
</div>
<hr />
<div class="row mt-3">
<div class="col col-md-12">
<div class="card">
<div class="card-body <% if (mumbleStatus.online) { %>bg-success<% } else { %>bg-danger<% } %> text-white">
<h5 class="card-title">Mumble is <% if (mumbleStatus.online) { %> Online <% } else { %>Offline<% } %></h5>
<p class="card-text">
Free voice chat with positional audio and overlay support
</p>
</div>
<% if (mumbleStatus.online) { %>
<ul class="list-group list-group-flush">
<li class="list-group-item">
Current users: <span class="badge badge-primary"><%= mumbleStatus.currentUsers %> / <%= mumbleStatus.maxUsers %></span>
</li>
</ul>
<% } %>
<div class="card-body">
<span class="card-link">Server address: gensokyo.social</span>
<a href="https://wiki.mumble.info/wiki/Main_Page" target="_blank" class="card-link">Client</a>
</div>
</div>
</div>
</div>
<hr />
<div class="row mt-3 mb-5">
<div class="col col-md-12">
<div class="card">
<div class="card-body <% if (XMPPStatus.online) { %>bg-success<% } else { %>bg-danger<% } %> text-white">
<h5 class="card-title">XMPP is <% if (XMPPStatus.online) { %> Online <% } else { %>Offline<% } %></h5>
<p class="card-text">
Free and Secure decentralized messenger with strong encryption support
</p>
</div>
<div class="card-body">
<span class="card-link">Server address: gensokyo.social</span>
<a href="https://gajim.org" target="_blank" class="card-link">Desktop Client</a>
<a href="https://conversations.im" target="_blank" class="card-link">Android Client</a>
<a href="https://itunes.apple.com/us/app/monal-free-xmpp-chat/id317711500" target="_blank" class="card-link">iOS Client</a>
</div>
</div>
</div>
</div>
</div>
</body>
</html>

+ 1
- 0
src/typings.d.ts View File

@@ -0,0 +1 @@
declare module '@nrk/nodecache-as-promised';

+ 16
- 0
tsconfig.json View File

@@ -0,0 +1,16 @@
{
"compilerOptions": {
"baseUrl": ".",
"outDir": "tsDist",
"moduleResolution": "node",
"module": "commonjs",
"target": "es6",
"resolveJsonModule": true,
"typeRoots": [ "node_modules/@types", "./src/typings.d.ts" ],
"paths": {
"server/*": [ "src/server/*" ],
"client/*": [ "src/client/*" ],
"shared/*": [ "src/shared/*" ]
}
}
}

+ 37
- 0
webpack.config.server.js View File

@@ -0,0 +1,37 @@
const path = require('path');
const os = require('os');
const NodemonPlugin = require('nodemon-webpack-plugin');
const nodeExternals = require('webpack-node-externals');

module.exports = {
entry: './src/server.ts',
target: 'node',
externals: [nodeExternals()],
mode: process.env.NODE_ENV || 'development',
module: {
rules: [
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/,
},
]
},
resolve: {
extensions: ['.tsx', '.ts', '.js', '.json'],
modules: [path.resolve(__dirname, 'src'), 'node_modules'],
alias: {
src: path.join(__dirname, 'src'),
}
},
plugins: [
new NodemonPlugin(),
],
stats: {
warningsFilter: [ "node_modules" ],
},
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist/server'),
},
}

+ 4374
- 0
yarn-error.log
File diff suppressed because it is too large
View File


+ 4724
- 0
yarn.lock
File diff suppressed because it is too large
View File


Loading…
Cancel
Save