Page MenuHomeDevCentral

D2186.id5500.diff
No OneTemporary

D2186.id5500.diff

diff --git a/.arcconfig b/.arcconfig
new file mode 100644
--- /dev/null
+++ b/.arcconfig
@@ -0,0 +1,4 @@
+{
+ "phabricator.uri": "https://devcentral.nasqueron.org",
+ "repository.callsign": "APIDS"
+}
diff --git a/.arclint b/.arclint
new file mode 100644
--- /dev/null
+++ b/.arclint
@@ -0,0 +1,30 @@
+{
+ "linters": {
+ "chmod": {
+ "type": "chmod"
+ },
+ "filename": {
+ "type": "filename"
+ },
+ "jshint-node": {
+ "type": "jshint",
+ "include": [
+ "(\\.js$)"
+ ]
+ },
+ "json": {
+ "type": "json",
+ "include": [
+ "(^\\.arcconfig$)",
+ "(^\\.arclint$)",
+ "(\\.json$)"
+ ]
+ },
+ "merge-conflict": {
+ "type": "merge-conflict"
+ },
+ "spelling": {
+ "type": "spelling"
+ }
+ }
+}
diff --git a/.gitignore b/.gitignore
new file mode 100644
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+node_modules/
+package-lock.json
diff --git a/.jshintrc b/.jshintrc
new file mode 100644
--- /dev/null
+++ b/.jshintrc
@@ -0,0 +1,15 @@
+{
+ "esversion": 6,
+ "node": true,
+ "bitwise": true,
+ "curly": true,
+ "eqeqeq": true,
+ "futurehostile": true,
+ "maxparams": 3,
+ "noarg": true,
+ "nocomma": true,
+ "nonew": true,
+ "regexpu": true,
+ "strict": "global",
+ "trailingcomma": true
+}
diff --git a/app.js b/app.js
new file mode 100644
--- /dev/null
+++ b/app.js
@@ -0,0 +1,23 @@
+/* -------------------------------------------------------------
+ Nasqueron API - datasources
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ Author: Sébastien Santoro aka Dereckson
+ Licence: BSD-2-Clause
+ ------------------------------------------------------------- */
+
+"use strict";
+
+const express = require('express');
+const logger = require('morgan');
+
+const app = express();
+
+app.use(logger('dev', {
+ skip: function (req, res) {
+ return res.statusCode < 400;
+ },
+}));
+
+module.exports = app;
+
+app.use('/', require('./routes'));
diff --git a/bin/www b/bin/www
new file mode 100755
--- /dev/null
+++ b/bin/www
@@ -0,0 +1,87 @@
+#!/usr/bin/env node
+
+/**
+ * Module dependencies.
+ */
+const app = require('../app');
+const debug = require('debug')('api-datasources:server');
+const http = require('http');
+
+/**
+ * Get port from environment and store in Express.
+ */
+const port = normalizePort(process.env.PORT || '80');
+app.set('port', port);
+
+/**
+ * Create HTTP server.
+ */
+const server = http.createServer(app);
+
+/**
+ * Listen on provided port, on all network interfaces.
+ */
+
+server.listen(port);
+server.on('error', onError);
+server.on('listening', onListening);
+
+/**
+ * Normalize a port into a number, string, or false.
+ */
+
+function normalizePort(val) {
+ const port = parseInt(val, 10);
+
+ if (isNaN(port)) {
+ // named pipe
+ return val;
+ }
+
+ if (port >= 0) {
+ // port number
+ return port;
+ }
+
+ return false;
+}
+
+/**
+ * Event listener for HTTP server "error" event.
+ */
+
+function onError(error) {
+ if (error.syscall !== 'listen') {
+ throw error;
+ }
+
+ const bind = typeof port === 'string'
+ ? 'Pipe ' + port
+ : 'Port ' + port;
+
+ // handle specific listen errors with friendly messages
+ switch (error.code) {
+ case 'EACCES':
+ console.error(bind + ' requires elevated privileges');
+ process.exit(1);
+ break;
+ case 'EADDRINUSE':
+ console.error(bind + ' is already in use');
+ process.exit(1);
+ break;
+ default:
+ throw error;
+ }
+}
+
+/**
+ * Event listener for HTTP server "listening" event.
+ */
+
+function onListening() {
+ const addr = server.address();
+ const bind = typeof addr === 'string'
+ ? 'pipe ' + addr
+ : 'port ' + addr.port;
+ console.log('Listening on ' + bind);
+}
diff --git a/controllers/dev/openfire/changelog.js b/controllers/dev/openfire/changelog.js
new file mode 100644
--- /dev/null
+++ b/controllers/dev/openfire/changelog.js
@@ -0,0 +1,74 @@
+/* -------------------------------------------------------------
+ Nasqueron API - datasources
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ Author: Sébastien Santoro aka Dereckson
+ Licence: BSD-2-Clause
+ ------------------------------------------------------------- */
+
+"use strict";
+
+const fetchExternalPageAndParseDOMTask = require("../../../tasks/fetchExternalPageAndParseDOMTask");
+
+/* -------------------------------------------------------------
+ Settings
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+const URL = "http://download.igniterealtime.org/openfire/docs/latest/changelog.html";
+
+/* -------------------------------------------------------------
+ * Parse changelog
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+class ChangeLogParser {
+ constructor() {
+ this.entries = [];
+ }
+
+ parse($) {
+ const that = this;
+
+ $("h2").each(function () {
+ const heading = $(this).text();
+ if (heading.includes(" -- ")) {
+ that.parseEntry(heading.trim());
+ }
+ });
+
+ return this;
+ }
+
+ static parseDate(date) {
+ return Date.parse(date) / 1000;
+ }
+
+ parseEntry(entry) {
+ const fragments = entry.split(" -- ");
+ this.entries.push({
+ date: ChangeLogParser.parseDate(fragments[1]),
+ version: fragments[0],
+ });
+ }
+
+ get changelog() {
+ return this.entries;
+ }
+
+ static ToJSON(dom) {
+ return JSON.stringify(new ChangeLogParser()
+ .parse(dom)
+ .changelog
+ );
+ }
+}
+
+/* -------------------------------------------------------------
+ Handle request
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+exports.get = function(req, res) {
+ let task = new fetchExternalPageAndParseDOMTask(URL, function(res, dom) {
+ res.send(ChangeLogParser.ToJSON(dom));
+ });
+
+ task.run(res);
+};
diff --git a/package.json b/package.json
new file mode 100644
--- /dev/null
+++ b/package.json
@@ -0,0 +1,31 @@
+{
+ "name": "nasqueron-api-datasources",
+ "version": "0.0.1",
+ "private": true,
+ "scripts": {
+ "start": "node ./bin/www",
+ "dev-start": "nodemon bin/www"
+ },
+ "repository": {
+ "type": "git",
+ "url": "https://devcentral.nasqueron.org/source/api-datasources.git"
+ },
+ "keywords": [
+ "nasqueron",
+ "api",
+ "datasources"
+ ],
+ "author": "Sébastien Santoro <dereckson@espace-win.org>",
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "cheerio": "^1.0.0-rc.3",
+ "debug": "~2.6.9",
+ "express": "^4.17.1",
+ "htmlparser2": "^4.0.0",
+ "morgan": "~1.9.1",
+ "domhandler": "latest"
+ },
+ "devDependencies": {
+ "nodemon": "^2.0.2"
+ }
+}
diff --git a/routes.js b/routes.js
new file mode 100644
--- /dev/null
+++ b/routes.js
@@ -0,0 +1,70 @@
+/* -------------------------------------------------------------
+ Nasqueron API - datasources
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ Author: Sébastien Santoro aka Dereckson
+ Licence: BSD-2-Clause
+ ------------------------------------------------------------- */
+
+"use strict";
+
+const express = require('express');
+const router = express.Router();
+const app = require('./app');
+
+/* -------------------------------------------------------------
+ Datasources
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+const datasources = [
+ {
+ url: "dev/openfire/changelog",
+ controller: "/dev/openfire/changelog.js",
+ description: "Openfire changelog",
+ },
+];
+
+function formatDatasources(base_url) {
+ return datasources.map(function (item) {
+ return {
+ "description": item.description,
+ "URL": base_url + item.url,
+ };
+ });
+}
+
+/* -------------------------------------------------------------
+ Routes
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+function isPortRequired(protocol, port) {
+ return (protocol === "http" && port !== 80) ||
+ (protocol === "https" && port !== 443);
+}
+
+function getUrl(req) {
+ const port = app.get("port");
+ let url = req.protocol + "://" + req.hostname;
+
+ if (isPortRequired(req.protocol, port)) {
+ url += ":" + port;
+ }
+
+ url += req.url;
+
+ return url;
+}
+
+router.get('/', function(req, res) {
+ let url = getUrl(req);
+
+ res.send(JSON.stringify(formatDatasources(url)));
+});
+
+datasources.forEach(function (datasource) {
+ router.get('/' + datasource.url, function (req, res) {
+ require("./controllers/" + datasource.controller)
+ .get(req, res);
+ });
+});
+
+module.exports = router;
diff --git a/tasks/fetchExternalPageAndParseDOMTask.js b/tasks/fetchExternalPageAndParseDOMTask.js
new file mode 100644
--- /dev/null
+++ b/tasks/fetchExternalPageAndParseDOMTask.js
@@ -0,0 +1,60 @@
+/* -------------------------------------------------------------
+ Nasqueron API - datasources
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ Author: Sébastien Santoro aka Dereckson
+ Licence: BSD-2-Clause
+ ------------------------------------------------------------- */
+
+"use strict";
+
+const cheerio = require('cheerio');
+const domhandler = require("domhandler");
+const htmlparser2 = require('htmlparser2');
+const http = require("http");
+
+/* -------------------------------------------------------------
+ * :: Handle DOM operations
+ * :: Fetch HTML page and send it to parser
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+class fetchExternalPageAndParseDOMTask {
+ constructor(url, sendResponseCallBack) {
+ this.url = url;
+ this.sendResponse = sendResponseCallBack;
+ }
+
+ run(res) {
+ const parser = this.getParser(res);
+ this.fetchExternalPage(res, parser);
+ }
+
+ getParser (res) {
+ let that = this;
+
+ return new htmlparser2.Parser(new domhandler.DomHandler(function(error, dom) {
+ if (error) {
+ console.error("DOM error: " + error);
+ res.status(500).end("Can't parse changelog.");
+ return;
+ }
+
+ that.sendResponse(res, cheerio.load(dom));
+ }));
+ }
+
+ fetchExternalPage (res, parser) {
+ http.get(this.url, function(externalResponse) {
+ if (externalResponse.statusCode !== 200) {
+ console.error("Error: " + externalResponse.statusMessage);
+ res.status(500).end("Can't fetch changelog.");
+ return;
+ }
+
+ externalResponse.setEncoding('utf8');
+ externalResponse.on('data', (chunk) => { parser.write(chunk); });
+ externalResponse.on('end', () => { parser.end(); });
+ });
+ }
+}
+
+module.exports = fetchExternalPageAndParseDOMTask;

File Metadata

Mime Type
text/plain
Expires
Tue, Nov 19, 16:20 (20 h, 55 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2252708
Default Alt Text
D2186.id5500.diff (10 KB)

Event Timeline