forked from jupyter/dashboards
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
WIP: Create node app to act as proxy in front of kernel gateway.
Ref jupyter#135 (c) Copyright IBM Corp. 2015
- Loading branch information
1 parent
0b05e9e
commit ba7f6ca
Showing
22 changed files
with
799 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
{ | ||
"directory": "public/components", | ||
"json": "bower.json" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
# http://editorconfig.org | ||
root = true | ||
|
||
[*] | ||
indent_style = space | ||
indent_size = 2 | ||
end_of_line = lf | ||
charset = utf-8 | ||
trim_trailing_whitespace = true | ||
insert_final_newline = true |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
node_modules/ | ||
public/components | ||
.sass-cache |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
|
||
|
||
var express = require('express'); | ||
var path = require('path'); | ||
var favicon = require('serve-favicon'); | ||
var logger = require('morgan'); | ||
var cookieParser = require('cookie-parser'); | ||
var bodyParser = require('body-parser'); | ||
var exphbs = require('express-handlebars'); | ||
var config = require('./config/config'); | ||
|
||
var routes = require('./routes/index'); | ||
var apiRoutes = require('./routes/api'); | ||
// var users = require('./routes/user'); | ||
|
||
var kernelProxy = require('./app/kernel-proxy'); | ||
|
||
var app = express(); | ||
|
||
var env = process.env.NODE_ENV || 'development'; | ||
app.locals.ENV = env; | ||
app.locals.ENV_DEVELOPMENT = env == 'development'; | ||
|
||
// view engine setup | ||
|
||
app.engine('handlebars', exphbs({ | ||
defaultLayout: 'main', | ||
partialsDir: ['views/partials/'] | ||
})); | ||
app.set('views', path.join(__dirname, 'views')); | ||
app.set('view engine', 'handlebars'); | ||
|
||
// app.use(favicon(__dirname + '/public/img/favicon.ico')); | ||
app.use(logger('dev')); | ||
app.use(bodyParser.json()); | ||
app.use(bodyParser.urlencoded({ | ||
extended: true | ||
})); | ||
app.use(cookieParser()); | ||
app.use(express.static(path.join(__dirname, 'public'))); | ||
|
||
app.use('/', routes); | ||
app.use('/api', apiRoutes); | ||
// app.use('/users', users); | ||
|
||
/// catch 404 and forward to error handler | ||
app.use(function(req, res, next) { | ||
var err = new Error('Not Found'); | ||
err.status = 404; | ||
next(err); | ||
}); | ||
|
||
/// error handlers | ||
|
||
// development error handler | ||
// will print stacktrace | ||
|
||
if (app.get('env') === 'development') { | ||
app.use(function(err, req, res, next) { | ||
res.status(err.status || 500); | ||
res.render('error', { | ||
message: err.message, | ||
error: err, | ||
title: 'error' | ||
}); | ||
}); | ||
} | ||
|
||
// production error handler | ||
// no stacktraces leaked to user | ||
app.use(function(err, req, res, next) { | ||
res.status(err.status || 500); | ||
res.render('error', { | ||
message: err.message, | ||
error: {}, | ||
title: 'error' | ||
}); | ||
}); | ||
|
||
// kernelProxy.init(config); | ||
|
||
module.exports = app; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
var Services = require('jupyter-js-services'); | ||
var request = require('request'); | ||
var Promise = require('es6-promise').Promise; | ||
var XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest; | ||
var WebSocket = require('ws'); | ||
|
||
global.XMLHttpRequest = XMLHttpRequest; | ||
global.WebSocket = WebSocket; | ||
|
||
function init(config) { | ||
var baseUrl = config.kernelGatewayUrl; | ||
baseUrl += (baseUrl[baseUrl.length - 1] === '/' ? '' : '/'); // ensure it ends in '/' | ||
|
||
// check if we need to spawn a new container or use existing one | ||
// check for a previous container, which we can reuse | ||
// var containerUrl = localStorage.getItem(CONTAINER_URL); | ||
// TODO get CONTAINER_URL from request | ||
var containerUrl = null; | ||
|
||
// TODO return CONTAINER_URL to the client | ||
return checkExistingContainer(containerUrl) | ||
.then(function(containerExists) { | ||
if (!containerExists) { | ||
console.log('spawning! [', baseUrl, ']'); | ||
return callSpawn(baseUrl); | ||
} else { | ||
return { url: containerUrl }; | ||
} | ||
}) | ||
.then(function(data) { | ||
var kernelOptions = { | ||
baseUrl: data.url, | ||
wsUrl: data.url.replace(/^http/, 'ws'), | ||
name: 'python3' | ||
}; | ||
console.log('starting new kernel at', data.url); | ||
Services.startNewKernel(kernelOptions) | ||
.then(function(kernel) { | ||
setupKernel(kernel); | ||
return true; | ||
}).catch(function(e) { | ||
console.error('Failed to create session/kernel:', e); | ||
}); | ||
}); | ||
} | ||
|
||
// generates a session URL containing a unique id | ||
function generateSessionUrl() { | ||
// TODO get path from request | ||
return window.location.pathname + '#' + generateId(); | ||
} | ||
|
||
// adapted from http://guid.us/GUID/JavaScript | ||
function generateId() { | ||
return (((1+Math.random())*0x100000000)|0).toString(16).substring(1); | ||
} | ||
|
||
// register event handlers on a new kernel | ||
function setupKernel(_kernel) { | ||
console.log('> setupKernel'); | ||
kernel = _kernel; | ||
|
||
kernel.commOpened.connect(function(_kernel, commMsg) { | ||
console.log('> commOpened'); | ||
var comm = kernel.connectToComm(commMsg.target_name, commMsg.comm_id); | ||
}); | ||
} | ||
|
||
// Spawn a new kernel container. Returns promise to container URL. | ||
function callSpawn(baseUrl) { | ||
return new Promise(function(resolve, reject) { | ||
request.post({ | ||
url: baseUrl + 'api/spawn/', | ||
json: true | ||
// body: { image_name: 'jupyter/notebook' }, // TODO remove if not necessary | ||
}, function(error, response, body) { | ||
// console.log(response); | ||
if (!error && response.statusCode >= 200 && response.statusCode < 300) { | ||
console.log(body); | ||
if (body.status === 'full') { | ||
reject('tmpnb server is full'); | ||
// throw new Error('tmpnb server is full'); | ||
} else { | ||
// test if we have a full URL (new tmpnb) or partial (old tmpnb) | ||
if (!/^http/.test(body.url)) { | ||
body.url = baseUrl + body.url; | ||
} | ||
resolve(body); | ||
} | ||
} else if (error) { | ||
reject('error spawning tmpnb container' + error); | ||
// throw new Error('error spawning tmpnb container', error); | ||
} | ||
}); | ||
}); | ||
} | ||
|
||
// Check if container at URL is valid. Returns promise to boolean value. | ||
function checkExistingContainer(url) { | ||
return new Promise(function(resolve, reject) { | ||
if (!url) { | ||
return resolve(false); // There is no existing container | ||
} | ||
|
||
url += (url[url.length - 1] === '/' ? '' : '/'); // ensure it ends in '/' | ||
|
||
request.get(url + 'api/kernels', function(error, response, body) { | ||
if (!error && response.statusCode == 200) { | ||
try { | ||
var data = JSON.parse(body); | ||
resolve(true); | ||
} catch(e) { | ||
// JSON conversion failed, most likely because response is HTML text telling us | ||
// that the container doesn't exist. Therefore, fail. | ||
resolve(false); | ||
// TODO let client know to clear local storage for CONTAINER_URL | ||
} | ||
} else if (error) { | ||
resolve(false); | ||
// TODO let client know to clear local storage for CONTAINER_URL | ||
} | ||
}); | ||
}); | ||
} | ||
|
||
module.exports = { | ||
init: init | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
#!/usr/bin/env node | ||
var app = require('../app'); | ||
|
||
app.set('port', process.env.PORT || 3000); | ||
|
||
var server = app.listen(app.get('port'), function() { | ||
console.log('Express server listening on port ' + server.address().port); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
{ | ||
"name": "node-deployed-dashboard", | ||
"version": "0.0.1", | ||
"ignore": [ | ||
"**/.*", | ||
"node_modules", | ||
"components" | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
/** | ||
* Copy to `config.js` and enter correct values. | ||
*/ | ||
|
||
module.exports = { | ||
kernelGatewayUrl: 'https://tmpnb-urth-demo.cloudet.xyz/' | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
/** | ||
* Copy to `config.js` and enter correct values. | ||
*/ | ||
|
||
module.exports = { | ||
kernelGatewayUrl: '' | ||
}; |
Oops, something went wrong.