Page Menu
Home
DevCentral
Search
Configure Global Search
Log In
Files
F3755541
D2186.id5500.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
10 KB
Referenced Files
None
Subscribers
None
D2186.id5500.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D2186: Initial release
Attached
Detach File
Event Timeline
Log In to Comment