Skip to content

Commit

Permalink
Merge pull request #237 from jpmorganchase/git-example
Browse files Browse the repository at this point in the history
WebsocketHost HTTP support + GIT example
  • Loading branch information
texodus authored Sep 12, 2018
2 parents ccce81e + 4dde770 commit 46eeb85
Show file tree
Hide file tree
Showing 7 changed files with 109 additions and 18 deletions.
3 changes: 1 addition & 2 deletions packages/perspective-examples/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
"copy:src-csv": "cp src/csv/* build",
"copy:src-css": "cp src/css/* build",
"copy:src-js": "cp src/js/* build",
"host": "http-server build/",
"host": "node build/node_remote.js",
"clean": "find build -mindepth 1 -delete"
},
"repository": {
Expand Down Expand Up @@ -67,7 +67,6 @@
"chart.js": "^2.7.1",
"css-loader": "^0.28.7",
"documentation": "^5.3.3",
"http-server": "^0.10.0",
"jest": "^22.0.4",
"less": "^2.7.2",
"less-loader": "^4.0.5",
Expand Down
4 changes: 2 additions & 2 deletions packages/perspective-examples/src/html/remote.html
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@

window.addEventListener('WebComponentsReady', function () {
var elem = document.getElementById('view1');
var worker = perspective.worker('ws://localhost:3000');
elem.load(worker.open('superstore.arrow'));
var worker = perspective.worker(window.location.origin.replace('http', 'ws'));
elem.load(worker.open('data_source_one'));
});

</script>
Expand Down
20 changes: 20 additions & 0 deletions packages/perspective-examples/src/js/node_git_history.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/******************************************************************************
*
* Copyright (c) 2017, the Perspective Authors.
*
* This file is part of the Perspective library, distributed under the terms of
* the Apache License 2.0. The full license can be found in the LICENSE file.
*
*/

const {WebSocketHost} = require("@jpmorganchase/perspective/build/perspective.node.js");
const exec = require('child_process').exec;

function execute(command, callback){
exec(command, function(error, stdout){ callback(stdout); });
};

execute(`git log --date=iso --pretty=format:'"%h","%an","%aD","%s","%ae"'`, log => {
const host = new WebSocketHost({rootDir: __dirname});
host.open("data_source_one", "Hash,Name,Date,Message,Email\n" + log);
});
6 changes: 3 additions & 3 deletions packages/perspective-examples/src/js/node_remote.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
const {WebSocketHost} = require("@jpmorganchase/perspective/build/perspective.node.js");
const fs = require("fs");

const host = new WebSocketHost(3000);
const arr = fs.readFileSync(__dirname +'/superstore.arrow');
const host = new WebSocketHost({rootDir: __dirname});
const arr = fs.readFileSync(__dirname + '/superstore.arrow');

host.open("superstore.arrow", arr);
host.open("data_source_one", arr);
22 changes: 22 additions & 0 deletions packages/perspective-viewer/src/js/computed_column.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,26 @@ const day_bucket = function (val) {
return +date;
}

const week_bucket = function (val) {
let date = new Date(val);
let day = date.getDay();
let diff = date.getDate() - day + (day == 0 ? -6 : 1);
date.setHours(0);
date.setMinutes(0);
date.setSeconds(0);
date.setDate(diff);
return +date;
}

const month_bucket = function (val) {
let date = new Date(val);
date.setHours(0);
date.setMinutes(0);
date.setSeconds(0);
date.setDate(1);
return +date;
}

// Eslint complains here because we don't do anything, but actually we globally
// register this class as a CustomElement
@bindTemplate(template) // eslint-disable-next-line no-unused-vars
Expand All @@ -69,6 +89,8 @@ class ComputedColumn extends HTMLElement {
'month_of_year': new Computation('month_of_year', 'date', 'string', month_of_year),
'hour_bucket': new Computation('hour_bucket', 'date', 'date', hour_bucket),
'day_bucket': new Computation('day_bucket', 'date', 'date', day_bucket),
'week_bucket': new Computation('week_bucket', 'date', 'date', week_bucket),
'month_bucket': new Computation('month_bucket', 'date', 'date', month_bucket),
'uppercase': new Computation('uppercase', 'string', 'string', x => x.toUpperCase()),
'lowercase': new Computation('lowercase', 'string', 'string', x => x.toLowerCase()),
'length': new Computation('length', 'string', 'integer', x => x.length),
Expand Down
16 changes: 9 additions & 7 deletions packages/perspective/src/cpp/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1037,13 +1037,15 @@ main(int argc, char** argv)
std::cout << "Perspective initialized successfully" << std::endl;
EM_ASM({

if (self.dispatchEvent && !self._perspective_initialized && self.document) {
self._perspective_initialized = true;
var event = self.document.createEvent("Event");
event.initEvent("perspective-ready", false, true);
self.dispatchEvent(event);
} else if (!self.document && typeof self !== "undefined") {
self.postMessage({});
if (typeof self !== "undefined") {
if (self.dispatchEvent && !self._perspective_initialized && self.document) {
self._perspective_initialized = true;
var event = self.document.createEvent("Event");
event.initEvent("perspective-ready", false, true);
self.dispatchEvent(event);
} else if (!self.document && self.postMessage) {
self.postMessage({});
}
}

});
Expand Down
56 changes: 52 additions & 4 deletions packages/perspective/src/js/perspective.node.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,12 @@ import buffer from "../../obj/psp.sync.wasm";

const perspective = require('./perspective.js');

const fs = require('fs');
const http = require("http");
const WebSocket = require('ws');

const path = require('path');

const load_perspective = require("../../obj/psp.sync.js").load_perspective;

let Module = load_perspective({
Expand All @@ -26,14 +30,49 @@ module.exports = perspective(Module);
let CLIENT_ID_GEN = 0;

/**
* A Server instance for a remote perspective.
* A WebSocket server instance for a remote perspective, and convenience HTTP
* file server for easy hosting.
*/
class WebSocketHost extends module.exports.Host {

constructor(port = 8080) {
constructor({port, rootDir}) {
port = port || 8080;
rootDir = rootDir || "./";
super();
this.REQS = {};
this._wss = new WebSocket.Server({port: port, perMessageDeflate: true});

const server = http.createServer(function (request, response) {
var filePath = rootDir + request.url;
var extname = path.extname(filePath);
var contentType = {
'.js': 'text/javascript',
'.css': 'text/css',
'.json': 'application/json',
'.arrow': 'arraybuffer',
'.wasm': 'application/wasm'
}[extname] || 'text/html';

fs.readFile(filePath, function(error, content) {
if (error) {
if(error.code == 'ENOENT'){
console.error(`404 ${request.url}`);
response.writeHead(404);
response.end(content, 'utf-8');
} else {
console.error(`500 ${request.url}`);
response.writeHead(500);
response.end();
}
} else {
console.log(`200 ${request.url}`);
response.writeHead(200, { 'Content-Type': contentType });
response.end(content, extname === '.arrow' ? 'user-defined' : 'utf-8');
}
});

});

this.REQS = {};
this._wss = new WebSocket.Server({noServer: true, perMessageDeflate: true});
this._wss.on('connection', ws => {
ws.id = CLIENT_ID_GEN++;
ws.on('message', msg => {
Expand All @@ -50,6 +89,15 @@ class WebSocketHost extends module.exports.Host {
});
ws.on('error', console.error);
});

server.on('upgrade', function upgrade(request, socket, head) {
console.log('200 *** websocket upgrade ***');
this._wss.handleUpgrade(request, socket, head, function done (sock) {
this._wss.emit('connection', sock, request);
}.bind(this));
}.bind(this));

server.listen(port);
console.log(`Listening on port ${port}`);
}

Expand Down

0 comments on commit 46eeb85

Please sign in to comment.