Use contents service

Use new contents service to upload graphics, replacing the separate
websocket server.
This commit is contained in:
Juergen Hasch
2014-08-01 23:19:17 +02:00
parent c63b7c4ea4
commit dfdb11cce6
5 changed files with 267 additions and 625 deletions
+114 -125
View File
@@ -2,137 +2,126 @@
// works with images and notebook cells (MIME-type 'notebook-cell/json')
"using strict";
define( function () {
var load_ipython_extension = function () {
if (window.chrome == undefined) return;
chrome_clipboard = function() {
/* http://stackoverflow.com/questions/3231459/create-unique-id-with-javascript */
function uniqueid(){
// always start with a letter (for DOM friendlyness)
var idstr=String.fromCharCode(Math.floor((Math.random()*25)+65));
do {
// between numbers and characters (48 is 0 and 90 is Z (42-48 = 90)
var ascicode=Math.floor((Math.random()*42)+48);
if (ascicode<58 || ascicode>64){
// exclude all chars between : (58) and @ (64)
idstr+=String.fromCharCode(ascicode);
}
} while (idstr.length<32);
if (window.chrome == undefined) return;
/* http://stackoverflow.com/questions/3231459/create-unique-id-with-javascript */
function uniqueid(){
// always start with a letter (for DOM friendlyness)
var idstr=String.fromCharCode(Math.floor((Math.random()*25)+65));
do {
// between numbers and characters (48 is 0 and 90 is Z (42-48 = 90)
var ascicode=Math.floor((Math.random()*42)+48);
if (ascicode<58 || ascicode>64){
// exclude all chars between : (58) and @ (64)
idstr+=String.fromCharCode(ascicode);
}
} while (idstr.length<32);
return (idstr);
}
/* receive url of graphics from websocket */
dragdrop_event = function(evt){
console.log("Websock-Event:", evt);
var obj = $.parseJSON(evt.data);
if (obj.status == "OK") {
var new_cell = IPython.notebook.insert_cell_below('markdown');
var filename = obj.name;
var str = '<img src="' + filename + '"/>';
new_cell.set_text(str);
new_cell.rendered = false;
new_cell.render();
return (idstr);
}
}
/*
* override clipboard 'paste' and insert new cell from json data in clipboard
*/
window.addEventListener('paste', function(event){
var cell = IPython.notebook.get_selected_cell();
if (cell.mode == "command" ) {
event.preventDefault();
var items = event.clipboardData.items;
for (var i = 0; i < items.length; i++) {
console.log("items:", items[i].type);
if (items[i].type == 'notebook-cell/json') {
/* json data adds a new notebook cell */
var data = event.clipboardData.getData('notebook-cell/json');
var new_cell_data = JSON.parse(data);
var new_cell = IPython.notebook.insert_cell_below(new_cell_data.cell_type);
new_cell.fromJSON(new_cell_data);
} else if (items[i].type.indexOf('image/') !== -1) {
/* images are transferred to the server as file and linked to */
var blob = items[i].getAsFile();
var reader = new FileReader();
reader.onload = ( function(evt) {
var filename = uniqueid();
var msg = JSON.stringify({"type":"file",
"name":filename,
"path":IPython.notebook.notebook_path,
"url" : "",
"data": evt.target.result});
IPython.notebook.ws_dragdrop.send(msg);
event.preventDefault();
} );
reader.readAsDataURL(blob);
send_to_server = function(name,path,msg) {
if (name == '') {
name = uniqueid() + '.' + msg.match(/data:image\/(\S+);/)[1];
}
var url = 'http://' + location.host + '/api/contents/' + path + '/' + name;
var img = msg.replace(/(^\S+,)/, ''); // strip header
// console.log("send_to_server:", url, msg);
data = {'name': name, 'format':'base64', 'content': img, 'type': 'file'}
var settings = {
processData : false,
cache : false,
type : "PUT",
dataType : "json",
data : JSON.stringify(data),
headers : {'Content-Type': 'text/plain'},
async : false,
success : function (data, status, xhr) {
var new_cell = IPython.notebook.insert_cell_below('markdown');
var str = '<img src="' + name + '"/>';
new_cell.set_text(str);
new_cell.execute();
//new_cell.select();
},
error : function() {console.log('fail'); },
};
$.ajax(url, settings);
}
/*
* override clipboard 'paste' and insert new cell from json data in clipboard
*/
window.addEventListener('paste', function(event){
var cell = IPython.notebook.get_selected_cell();
if (cell.mode == "command" ) {
event.preventDefault();
var items = event.clipboardData.items;
for (var i = 0; i < items.length; i++) {
console.log("items:", items[i].type);
if (items[i].type == 'notebook-cell/json') {
/* json data adds a new notebook cell */
var data = event.clipboardData.getData('notebook-cell/json');
var new_cell_data = JSON.parse(data);
var new_cell = IPython.notebook.insert_cell_below(new_cell_data.cell_type);
new_cell.fromJSON(new_cell_data);
} else if (items[i].type.indexOf('image/') !== -1) {
/* images are transferred to the server as file and linked to */
var blob = items[i].getAsFile();
var reader = new FileReader();
reader.onload = ( function(evt) {
var filename = '';
send_to_server(filename, IPython.notebook.notebook_path, evt.target.result);
event.preventDefault();
} );
reader.readAsDataURL(blob);
}
}
}
}
});
});
/*
* override clipboard 'copy' and copy current cell as json and text to clipboard
*/
window.addEventListener('copy', function(event){
var cell = IPython.notebook.get_selected_cell();
if (cell.mode == "command") {
var sel = window.getSelection();
if (sel.type == "Range") return; /* default: copy marked text */
event.preventDefault();
var j = cell.toJSON();
var json = JSON.stringify(j);
var text = cell.code_mirror.getValue();
/* copy cell as json and cell contents as text */
event.clipboardData.setData('notebook-cell/json',json);
event.clipboardData.setData("Text", text);
}
});
/*
* override clipboard 'copy' and copy current cell as json and text to clipboard
*/
window.addEventListener('copy', function(event){
var cell = IPython.notebook.get_selected_cell();
if (cell.mode == "command") {
var sel = window.getSelection();
if (sel.type == "Range") return; /* default: copy marked text */
event.preventDefault();
var j = cell.toJSON();
var json = JSON.stringify(j);
var text = cell.code_mirror.getValue();
/* copy cell as json and cell contents as text */
event.clipboardData.setData('notebook-cell/json',json);
event.clipboardData.setData("Text", text);
}
});
/*
* override clipboard 'cut' and copy current cell as json and text to clipboard
*/
window.addEventListener('cut', function(event){
var cell = IPython.notebook.get_selected_cell();
if (cell.mode == "command" ) {
var sel = window.getSelection();
if (sel.type == "Range") return; /* default: cut marked text */
event.preventDefault();
var j = cell.toJSON();
var json = JSON.stringify(j);
var text = cell.code_mirror.getValue();
/* copy cell as json and cell contents as text */
event.clipboardData.setData('notebook-cell/json',json);
event.clipboardData.setData("Text", text);
IPython.notebook.delete_cell(IPython.notebook.find_cell_index(cell));
}
});
/*
* override clipboard 'cut' and copy current cell as json and text to clipboard
*/
window.addEventListener('cut', function(event){
var cell = IPython.notebook.get_selected_cell();
if (cell.mode == "command" ) {
var sel = window.getSelection();
if (sel.type == "Range") return; /* default: cut marked text */
event.preventDefault();
var j = cell.toJSON();
var json = JSON.stringify(j);
var text = cell.code_mirror.getValue();
/* copy cell as json and cell contents as text */
event.clipboardData.setData('notebook-cell/json',json);
event.clipboardData.setData("Text", text);
IPython.notebook.delete_cell(IPython.notebook.find_cell_index(cell));
}
});
};
function callback(out_data)
{
var ul = out_data.content.data;
var webport = eval(ul['text/plain'])
console.log("webport:",webport);
var wsUri = "ws://" + document.domain + ":" + webport + "/"+ "websocket";
var ws_dragdrop = new WebSocket(wsUri);
IPython.notebook.ws_dragdrop = ws_dragdrop;
ws_dragdrop.onmessage = dragdrop_event;
}
return {
load_ipython_extension : load_ipython_extension,
};
});
function getport()
{
var code = 'drag_and_drop_webport';
var callbacks = { iopub : { output: callback } };
IPython.notebook.kernel.execute(code, callbacks, {silent: false});
}
$([IPython.events]).on('create.Cell',create_cell);
$([IPython.events]).on('status_started.Kernel',function() { getport();});
}();
@@ -1,14 +0,0 @@
# start websocket server for drag-and-drop extension
drag_and_drop_webport = get_ipython().config['DragDrop']['port']
def start_drag_and_drop():
c = get_ipython()
nb_dir = get_ipython().config['FileNotebookManager']['notebook_dir']
newpath = os.path.normpath(c.config['NotebookApp']['extra_static_paths'][0]+'/custom/dragdrop/')
sys.path.insert(0, newpath)
import drag_and_drop
drag_and_drop.start_server(drag_and_drop_webport, nb_dir)
start_drag_and_drop()
+153 -175
View File
@@ -1,80 +1,108 @@
// add drag&drop functionality
// Allow drag&drop of images into a notebook
// Tested with Firefox and Chrome
"using strict";
define( function () {
var load_ipython_extension = function () {
drag_and_drop = function() {
/* http://stackoverflow.com/questions/3231459/create-unique-id-with-javascript */
function uniqueid(){
// always start with a letter (for DOM friendlyness)
var idstr=String.fromCharCode(Math.floor((Math.random()*25)+65));
do {
// between numbers and characters (48 is 0 and 90 is Z (42-48 = 90)
var ascicode=Math.floor((Math.random()*42)+48);
if (ascicode<58 || ascicode>64){
// exclude all chars between : (58) and @ (64)
idstr+=String.fromCharCode(ascicode);
}
} while (idstr.length<32);
/* http://stackoverflow.com/questions/3231459/create-unique-id-with-javascript */
function uniqueid(){
// always start with a letter (for DOM friendlyness)
var idstr=String.fromCharCode(Math.floor((Math.random()*25)+65));
do {
// between numbers and characters (48 is 0 and 90 is Z (42-48 = 90)
var ascicode=Math.floor((Math.random()*42)+48);
if (ascicode<58 || ascicode>64){
// exclude all chars between : (58) and @ (64)
idstr+=String.fromCharCode(ascicode);
}
} while (idstr.length<32);
return (idstr);
}
/* receive url of graphics from websocket */
dragdrop_event = function(evt){
console.log("Websock-Event:", evt);
var obj = $.parseJSON(evt.data);
if (obj.status == "OK") {
var new_cell = IPython.notebook.insert_cell_below('markdown');
var filename = obj.name;
var str = '<img src="' + filename + '"/>';
new_cell.set_text(str);
new_cell.rendered = false;
new_cell.render();
return (idstr);
}
}
/* the dragover event needs to be canceled to allow firing the drop event */
window.addEventListener('dragover', function(event){
if (event.preventDefault) { event.preventDefault(); };
});
/* allow dropping an image in notebook */
window.addEventListener('drop', function(event){
if (IPython.notebook.mode === "edit") return;
// console.log("drop event x:",event);
var cell = IPython.notebook.get_selected_cell();
event.preventDefault();
if(event.stopPropagation) {event.stopPropagation();}
if (event.dataTransfer.items != undefined) {
/* Chrome here */
var items = event.dataTransfer.items;
for (var i = 0; i < items.length; i++) {
/* data coming from local file system, must be an image to allow dropping*/
if (items[i].kind == 'file' && items[i].type.indexOf('image/') !== -1) {
var blob = items[i].getAsFile();
var filename = blob.name;
var reader = new FileReader();
reader.onload = ( function(evt) {
console.log("name:",filename)
var msg = JSON.stringify({"type":"file",
"name":filename,
"path":IPython.notebook.notebook_path,
"url" : "",
"data": evt.target.result});
IPython.notebook.ws_dragdrop.send(msg);
event.preventDefault();
send_to_server = function(name,path,msg) {
if (name == '') {
name = uniqueid() + '.' + msg.match(/data:image\/(\S+);/)[1];
}
var url = 'http://' + location.host + '/api/contents/' + path + '/' + name;
var img = msg.replace(/(^\S+,)/, ''); // strip header
//console.log("send_to_server:", url, img);
data = {'name': name, 'format':'base64', 'content': img, 'type': 'file'}
var settings = {
processData : false,
cache : false,
type : "PUT",
dataType : "json",
data : JSON.stringify(data),
headers : {'Content-Type': 'text/plain'},
async : false,
success : function (data, status, xhr) {
var new_cell = IPython.notebook.insert_cell_below('markdown');
var str = '<img src="' + name + '"/>';
new_cell.set_text(str);
new_cell.execute();
//new_cell.select();
},
error : function() {console.log('fail'); },
};
$.ajax(url, settings);
}
/* the dragover event needs to be canceled to allow firing the drop event */
window.addEventListener('dragover', function(event){
if (event.preventDefault) { event.preventDefault(); };
});
/* allow dropping an image in notebook */
window.addEventListener('drop', function(event){
// console.log("drop event x:",event);
var cell = IPython.notebook.get_selected_cell();
event.preventDefault();
if(event.stopPropagation) {event.stopPropagation();}
if (event.dataTransfer.items != undefined) {
/* Chrome here */
var items = event.dataTransfer.items;
for (var i = 0; i < items.length; i++) {
/* data coming from local file system, must be an image to allow dropping*/
if (items[i].kind == 'file' && items[i].type.indexOf('image/') !== -1) {
var blob = items[i].getAsFile();
var filename = blob.name;
var reader = new FileReader();
reader.onload = ( function(evt) {
send_to_server(filename, IPython.notebook.notebook_path, evt.target.result);
event.preventDefault();
} );
reader.readAsDataURL(blob);
} else if (items[i].kind == 'string') {
/* data coming from browser */
reader.readAsDataURL(blob);
} else if (items[i].kind == 'string') {
/* data coming from browser */
var data = event.dataTransfer.getData('text/plain');
if (data[0] == 'd') {
url = "";
filename = '';
} else {
url = data;
data = "";
}
/* data coming from browser:
* url - image is given as an url
* data - image is a base64 blob
*/
//console.log("file"," name:", filename," path:", IPython.notebook.notebook_path," url:", url);
send_to_server(filename, IPython.notebook.notebook_path, data);
event.preventDefault();
return;
}
}
} else {
/* Firefox here */
var files = event.dataTransfer.files;
if (files.length == 0) {
var filename = event.dataTransfer.getData('application/x-moz-file-promise-dest-filename');
var data = event.dataTransfer.getData('text/plain');
if (data[0] == 'd') {
if (filename.length == 0) {
url = "";
filename = uniqueid();
filename = '';
} else {
url = data;
data = "";
@@ -83,116 +111,66 @@ drag_and_drop = function() {
* url - image is given as an url
* data - image is a base64 blob
*/
var msg = JSON.stringify({"type":"url",
"name":filename,
"path":IPython.notebook.notebook_path,
"url" : url,
"data": data});
IPython.notebook.ws_dragdrop.send(msg);
//console.log("type:",url," name:", filename," path:", IPython.notebook.notebook_path," url:", url);
send_to_server(filename, IPython.notebook.notebook_path, data);
event.preventDefault();
return;
}
}
} else {
/* Firefox here */
var files = event.dataTransfer.files;
if (files.length == 0) {
var filename = event.dataTransfer.getData('application/x-moz-file-promise-dest-filename');
var data = event.dataTransfer.getData('text/plain');
if (filename.length == 0) {
url = "";
filename = uniqueid();
} else {
url = data;
data = "";
}
/* data coming from local file system, must be an image to allow dropping*/
for (var i=0; i < files.length; i++) {
var blob = event.dataTransfer.files[0];
if (blob.type.indexOf('image/') !== -1) {
var filename = blob.name;
var url = event.view.location.origin;
var reader = new FileReader();
reader.onload = ( function(evt) {
//console.log("file"," name:", filename," path:", IPython.notebook.notebook_path," url:", url);
send_to_server(filename, IPython.notebook.notebook_path, evt.target.result);
event.preventDefault();
} );
reader.readAsDataURL(blob);
}
}
/* data coming from browser:
* url - image is given as an url
* data - image is a base64 blob
*/
console.log("type:",url," name:", filename," path:", IPython.notebook.notebook_path," url:", url);
var msg = JSON.stringify({"type":"url",
"name":filename,
"path":IPython.notebook.notebook_path,
"url" : url,
"data": data});
IPython.notebook.ws_dragdrop.send(msg);
event.preventDefault();
return;
}
/* data coming from local file system, must be an image to allow dropping*/
for (var i=0; i < files.length; i++) {
var blob = event.dataTransfer.files[0];
if (blob.type.indexOf('image/') !== -1) {
var filename = blob.name;
var url = event.view.location.origin;
var reader = new FileReader();
reader.onload = ( function(evt) {
console.log("file"," name:", filename," path:", IPython.notebook.notebook_path," url:", url);
var msg = JSON.stringify({"type":"file",
"name":filename,
"path":IPython.notebook.notebook_path,
"url" : url,
"data": evt.target.result});
IPython.notebook.ws_dragdrop.send(msg);
event.preventDefault();
} );
reader.readAsDataURL(blob);
}
}
}
});
/*
* make sure we do not drop images into a codemirror text field
*/
checktype = function(cm,event) {
if (event.dataTransfer.items != undefined)
{
evt.codemirrorIgnore = true;
}
var blob = evt.dataTransfer.files[0];
if (blob.type.indexOf('image/') !== -1) {
evt.codemirrorIgnore = true;
});
/*
* make sure we do not drop images into a codemirror text field
*/
checktype = function(cm,event) {
if (event.dataTransfer.items != undefined)
{
evt.codemirrorIgnore = true;
}
var blob = evt.dataTransfer.files[0];
if (blob.type.indexOf('image/') !== -1) {
evt.codemirrorIgnore = true;
}
}
create_cell = function (event,nbcell,nbindex) {
var cell = nbcell.cell;
if ((cell instanceof IPython.CodeCell)) {
cell.code_mirror.on('drop', checktype);
}
}
create_cell = function (event,nbcell,nbindex) {
var cell = nbcell.cell;
if ((cell instanceof IPython.CodeCell)) {
cell.code_mirror.on('drop', checktype);
}
};
var cells = IPython.notebook.get_cells();
for(var i in cells){
var cell = cells[i];
if ((cell instanceof IPython.CodeCell)) {
cell.code_mirror.on('drop', checktype);
}
};
function callback(out_data)
{
var ul = out_data.content.data;
var webport = eval(ul['text/plain'])
console.log("Graphics webport:",webport);
var wsUri = "ws://" + document.domain + ":" + webport + "/"+ "websocket";
var ws_dragdrop = new WebSocket(wsUri);
IPython.notebook.ws_dragdrop = ws_dragdrop;
ws_dragdrop.onmessage = dragdrop_event;
}
function getport()
{
var code = 'drag_and_drop_webport';
var callbacks = { iopub : { output: callback } };
IPython.notebook.kernel.execute(code, callbacks, {silent: false});
}
};
$([IPython.events]).on('create.Cell',create_cell);
$([IPython.events]).on('status_started.Kernel',function() { getport();});
}();
var cells = IPython.notebook.get_cells();
for(var i in cells){
var cell = cells[i];
if ((cell instanceof IPython.CodeCell)) {
cell.code_mirror.on('drop', checktype);
}
};
$([IPython.events]).on('create.Cell',create_cell);
};
return {
load_ipython_extension : load_ipython_extension,
};
});
-164
View File
@@ -1,164 +0,0 @@
# -*- coding: utf-8 -*-
"""
# Copyright (C) 2013
# Distributed under the terms of the BSD License. The full license is in
# the file COPYING, distributed as part of this software.
@author: juhasch
"""
"""
Tornado web server to
push value received from Pyzmq pull messages
to web browser using a webscocket connection
Configuration in ipython_notebook_config.py:
c.DragDrop.port = 8901
"""
import time
import os.path
import sys, getopt
import numpy as np
import tornado.web
import tornado.websocket
import tornado.ioloop
import random
import json
import base64
import hashlib
from zmq.eventloop import ioloop, zmqstream
webport = 0
nb_dir = ''
GLOBALS={
'sockets': []
}
# http://stackoverflow.com/questions/273192/check-if-a-directory-exists-and-create-it-if-necessary
def ensure_dir(f):
d = os.path.dirname(f)
if not os.path.exists(d):
os.makedirs(d)
def md5sum(fname, block_size=2**20):
f = open(fname, 'rb')
md5 = hashlib.md5()
while True:
data = f.read(block_size)
if not data:
break
md5.update(data)
f.close()
return md5.hexdigest()
class WebSocketHandler(tornado.websocket.WebSocketHandler):
def open(self):
print "open socket"
GLOBALS['sockets'].append(self)
def on_close(self):
print "on_close"
GLOBALS['sockets'].remove(self)
def on_message(self, message):
x=json.loads(message)
print "Data received"
url = x['url']
if len(url) == 0:
print "Base64"
filename = x['name']
print "Filename: %s" % filename
path = nb_dir + u'\\' + x['path'] + u'\\images\\'
print "Path: %s" %path
ensure_dir(path)
png_b64 = x['data']
data = png_b64.split(',') # [0] is header, [1] b64 data
png = base64.b64decode(data[1])
print "Filename: %s" % filename
# check if file exists
if os.path.exists(path+filename):
print('File %s already exists')
# compare md5sum
md5_file = md5sum(path+filename)
# print('md5sum of file is %s' % md5_file)
d = hashlib.md5()
d.update(png)
md5_websocket = d.hexdigest()
# print('md5sum of dropped image is is %s' % md5_websocket)
if md5_file != md5_websocket:
i = 0
while True:
if not os.path.exists('%s%0d_%s' % (path, i, filename)):
break
filename = '%0d_%s' % (i, filename)
f = open(path+filename, 'wb')
f.write(png)
f.close()
else:
f = open(path+filename, 'wb')
f.write(png)
f.close()
status = "OK"
reply = {"status": status, "name": 'images/' + filename }
self.write_message(reply)
else:
status = "OK"
reply = {"status": status, "name": url }
self.write_message(reply)
application = tornado.web.Application([
(r"/websocket", WebSocketHandler),
])
def main(argv):
global webport, nb_dir
#try:
opts, args = getopt.getopt(argv,"hp:d:",["port=","directory="])
if opts == []:
print 'drag-and-drop.py -p <port> -d <directory>'
sys.exit(2)
for opt, arg in opts:
if opt == '-h':
print 'drag-and-drop.py -p <port> -d <directory>'
sys.exit()
elif opt in ("-p", "--port"):
webport = int(arg)
elif opt in ("-d", "--directory"):
nb_dir = arg
print 'webport is "', webport
print 'notebook directory is "', nb_dir
if webport < 1000 or webport > 65535:
print('Illegal webport adress %d' % webport)
sys.exit(2)
if not os.path.exists(nb_dir):
print('Directory %s does not exist' % nb_dir)
sys.exit(2)
ioloop.install()
try:
application.listen(webport)
except:
print('Port %d already in use!' % webport)
exit()
main_loop = tornado.ioloop.IOLoop.instance()
main_loop.start()
if __name__ == "__main__":
main(sys.argv[1:])
-147
View File
@@ -1,147 +0,0 @@
# -*- coding: utf-8 -*-
"""
# Copyright (C) 2014
# Distributed under the terms of the BSD License.
"""
"""
Tornado websocket server to save images received from web browser and reply
with URL of stored image.
This is required for drag&drop of images in the IPython notebook
The websocket port can be configured in ipython_notebook_config.py:
c.DragDrop.port = 8901
"""
import time
import os.path
import sys, getopt
import numpy as np
import tornado.web
import tornado.websocket
import tornado.ioloop
import random
import json
import base64
import hashlib
from multiprocessing import Process
from zmq.eventloop import ioloop, zmqstream
webport = 0
nb_dir = ''
GLOBALS={
'sockets': []
}
# http://stackoverflow.com/questions/273192/check-if-a-directory-exists-and-create-it-if-necessary
def ensure_dir(f):
d = os.path.dirname(f)
if not os.path.exists(d):
os.makedirs(d)
def md5sum(fname, block_size=2**20):
f = open(fname, 'rb')
md5 = hashlib.md5()
while True:
data = f.read(block_size)
if not data:
break
md5.update(data)
f.close()
return md5.hexdigest()
class WebSocketHandler(tornado.websocket.WebSocketHandler):
""" Handle websocket connections from web browser
"""
def open(self):
GLOBALS['sockets'].append(self)
def on_close(self):
GLOBALS['sockets'].remove(self)
def on_message(self, message):
""" Receive image from web browser
Save it to the local 'images' directory under it's name.
If filename already exists, md5-check if identical, otherwise rename.
If no filename is given, create unique ID.
"""
x=json.loads(message)
url = x['url']
eventtype = x['type']
if eventtype == 'file':
filename = x['name']
path = nb_dir + u'\\' + x['path'] + u'\\images\\'
ensure_dir(path)
data = x['data'].split(',') # [0] is header, [1] b64 data
png = base64.b64decode(data[1])
# check if file exists: skip if identical, rename if new
if os.path.exists(path+filename):
# print('File %s already exists' % filename)
# compare md5sum
md5_file = md5sum(path+filename)
d = hashlib.md5()
d.update(png)
md5_websocket = d.hexdigest()
if md5_file != md5_websocket:
i = 0
while True:
if not os.path.exists('%s%0d_%s' % (path, i, filename)):
break
filename = '%0d_%s' % (i, filename)
f = open(path+filename, 'wb')
f.write(png)
f.close()
else:
f = open(path+filename, 'wb')
f.write(png)
f.close()
status = "OK"
#reply = {"status": status, "name": 'images/' + filename }
# send url instead of file path, otherwise it won't work for nbconvert
url_path = url + '/notebooks' + x['path'] + '/images/' + filename
reply = {"status": status, "name": url_path}
self.write_message(reply)
else:
# just reply already existing url
status = "OK"
reply = {"status": status, "name": url }
self.write_message(reply)
application = tornado.web.Application([
(r"/websocket", WebSocketHandler),
])
def websocket_server(webport, nbdir):
global nb_dir
nb_dir = nbdir
ioloop.install()
try:
application.listen(webport)
except:
# print('Port %d already in use!' % webport)
sys.exit(2)
main_loop = tornado.ioloop.IOLoop.instance()
main_loop.start()
def start_server(webport,nb_dir):
print('webport is %s' % webport)
print('notebook directory is %s' % nb_dir)
if webport < 1000 or webport > 65535:
print('Illegal webport adress %d' % webport)
sys.exit(2)
if not os.path.exists(nb_dir):
print('Directory %s does not exist' % nb_dir)
sys.exit(2)
p = Process(target=websocket_server, args=(webport,nb_dir))
p.start()