Skip to content
This repository has been archived by the owner on Oct 21, 2022. It is now read-only.

Commit

Permalink
Fixed block highlighting crashing in edge cases. Completely separate …
Browse files Browse the repository at this point in the history
…code execution process from webserver process
  • Loading branch information
maxos committed Feb 21, 2017
1 parent 499ca93 commit 5a6c12d
Show file tree
Hide file tree
Showing 6 changed files with 165 additions and 109 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,11 @@ Some other features:
- can be rendered in a mobile browser and supports touch interaction (tested in iOS 10.2)
- view camera in the same browser tab (just another blockly tab) - can be potentially overlaid
- blocks are highlighted when being executed
- view your program transled into Python or XML AST
- view your program translated into Python or XML AST
- view Cozmo's camera (only when program is running)

## How to run
1. Check out this repository with "git" or download it as zip archive.
1. Check out this repository with "git", or download it as a zip archive and unpack
2. Install prerequisites:
* `pip3 install --user cozmo[camera]`
* `pip3 install --user tornado ws4py`
Expand Down Expand Up @@ -69,7 +69,7 @@ Compressed version is compiled with google's closure library, is minified and ob
Uncompressed version is debuggable.

To run uncompressed version: `python3 server.py -d` which enables debug mode.
You may encounter some caching issues. If so, restart the server.
You may encounter some caching issues. If so, restart `server.py`

## Issues
Any issues? Report an issue above.
175 changes: 96 additions & 79 deletions blockly/demos/cozmo/js/code.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ Code.LANGUAGE_RTL = ['ar', 'fa', 'he', 'lki'];
Code.workspace = null;

Code.camera = null;
Code.highlighter = null;

/**
* Angle increases clockwise (true) or counterclockwise (false).
Expand All @@ -65,8 +66,8 @@ Blockly.FieldAngle.OFFSET = 0;
*/
Blockly.FieldAngle.WRAP = 360;

Blockly.Python.STATEMENT_PREFIX = 'app.highlightBlock(%1)\n';
Blockly.Python.addReservedWords('app', 'highlightBlock', 'cozmo, robot, bot, tapped_cube');
Blockly.Python.STATEMENT_PREFIX = 'highlighter.send(%1)\n';
Blockly.Python.addReservedWords('highlighter', 'cozmo, robot, bot, tapped_cube');

/**
* Extracts a parameter from the URL.
Expand Down Expand Up @@ -256,11 +257,10 @@ Code.tabClick = function(clickedName) {
}
}

// Disconnect camera WS.
if (Code.camera) {
Code.camera.doDisconnect()
}
Code.stopCamera();
Code.stopHighlighter();

// If blocks tab was open, hide workspace.
if (document.getElementById('tab_blocks').className == 'tabon') {
Code.workspace.setVisible(false);
}
Expand All @@ -278,9 +278,6 @@ Code.tabClick = function(clickedName) {
document.getElementById('content_' + clickedName).style.visibility =
'visible';
Code.renderContent();
if (clickedName == 'blocks') {
Code.workspace.setVisible(true);
}
Blockly.svgResize(Code.workspace);
};

Expand All @@ -303,67 +300,40 @@ Code.drawImageBinary = function(data, canvas, context) {
*/
Code.renderContent = function() {
var content = document.getElementById('content_' + Code.selected);
// Initialize the pane.
if (content.id == 'content_xml') {
var xmlTextarea = document.getElementById('content_xml');
var xmlDom = Blockly.Xml.workspaceToDom(Code.workspace);
var xmlText = Blockly.Xml.domToPrettyText(xmlDom);
xmlTextarea.value = xmlText;
xmlTextarea.focus();
} else if (content.id == 'content_camera') {
var canvas = document.getElementById('canvas_cam');
var context = canvas.getContext("2d");

Code.camera = new cozmoWs();

Code.camera.onMessage = function(msg) {
Code.drawImageBinary(msg.data, canvas, context);
};

var loc = window.location;
var wsurl = 'ws://' + loc.host + '/camSub';
Code.camera.doConnect(wsurl, true);

} else if (content.id == 'content_javascript') {
var code = Blockly.JavaScript.workspaceToCode(Code.workspace);
content.textContent = code;
if (typeof prettyPrintOne == 'function') {
code = content.textContent;
code = prettyPrintOne(code, 'js');
content.innerHTML = code;
}
} else if (content.id == 'content_python') {
code = Blockly.Python.workspaceToCode(Code.workspace);
content.textContent = code;
if (typeof prettyPrintOne == 'function') {
code = content.textContent;
code = prettyPrintOne(code, 'py');
content.innerHTML = code;
}
} else if (content.id == 'content_php') {
code = Blockly.PHP.workspaceToCode(Code.workspace);
content.textContent = code;
if (typeof prettyPrintOne == 'function') {
code = content.textContent;
code = prettyPrintOne(code, 'php');
content.innerHTML = code;
}
} else if (content.id == 'content_dart') {
code = Blockly.Dart.workspaceToCode(Code.workspace);
content.textContent = code;
if (typeof prettyPrintOne == 'function') {
code = content.textContent;
code = prettyPrintOne(code, 'dart');
content.innerHTML = code;
}
} else if (content.id == 'content_lua') {
code = Blockly.Lua.workspaceToCode(Code.workspace);
var renderInnerContent = function(code, type) {
content.textContent = code;
if (typeof prettyPrintOne == 'function') {
code = content.textContent;
code = prettyPrintOne(code, 'lua');
code = prettyPrintOne(code, type);
content.innerHTML = code;
}
};
// Initialize the pane.
if (Code.selected == 'xml') {
var xmlDom = Blockly.Xml.workspaceToDom(Code.workspace);
var xmlText = Blockly.Xml.domToPrettyText(xmlDom);
content.value = xmlText;
content.focus();
} else if (Code.selected == 'blocks') {
Code.workspace.setVisible(true);
Code.startHighlighter();
} else if (Code.selected == 'camera') {
Code.startCamera();
} else if (Code.selected == 'javascript') {
var code = Blockly.JavaScript.workspaceToCode(Code.workspace);
renderInnerContent(code, 'js');
} else if (Code.selected == 'python') {
var code = Blockly.Python.workspaceToCode(Code.workspace);
renderInnerContent(code, 'py');
} else if (Code.selected == 'php') {
var code = Blockly.PHP.workspaceToCode(Code.workspace);
renderInnerContent(code, 'php');
} else if (Code.selected == 'dart') {
var code = Blockly.Dart.workspaceToCode(Code.workspace);
renderInnerContent(code, 'dart');
} else if (Code.selected == 'lua') {
var code = Blockly.Lua.workspaceToCode(Code.workspace);
renderInnerContent(code, 'lua');
}
};

Expand Down Expand Up @@ -583,8 +553,11 @@ Code.init = function() {

for (var i = 0; i < Code.TABS_.length; i++) {
var name = Code.TABS_[i];
Code.bindClick('tab_' + name,
function(name_) {return function() {Code.tabClick(name_);};}(name));
Code.bindClick('tab_' + name, function(name_) {
return function() {
Code.tabClick(name_);
};
}(name));
}
onresize();
Blockly.svgResize(Code.workspace);
Expand Down Expand Up @@ -669,12 +642,7 @@ Code.sendCodeToUrl = function(urlToSendTo) {
code = Blockly.Xml.domToText(xml);
}

var highlighter = new cozmoWs();

highlighter.onMessage = function(evt) {
Code.workspace.highlightBlock(evt.data);
};
highlighter.onOpen = function(evt) {
var onHighlighterConnected = function() {
// Send code after highlighter websocket is connected.
$.ajax({
url: urlToSendTo,
Expand All @@ -686,18 +654,66 @@ Code.sendCodeToUrl = function(urlToSendTo) {
console.log('success');
})
.fail(function(jqXHR, textStatus, errorThrown) {
alert(errorThrown);
console.log(errorThrown);
});
};
highlighter.onClose = function(evt) {

Code.startHighlighter(onHighlighterConnected);
};

Code.startHighlighter = function(onConnectFunc) {
Code.stopHighlighter();

Code.highlighter = new cozmoWs();

Code.highlighter.onMessage = function(evt) {
if (document.getElementById('tab_blocks').className == 'tabon') {
Code.workspace.highlightBlock(evt.data);
}
};
Code.highlighter.onOpen = function(evt) {
if (onConnectFunc) {
onConnectFunc();
}
};
Code.highlighter.onClose = function(evt) {
Code.workspace.highlightBlock(null);
};

var loc = window.location;
var wsurl = 'ws://' + loc.host + '/highlight';
highlighter.doConnect(wsurl);
};
var wsurl = 'ws://' + loc.host + '/highlightSub';
Code.highlighter.doConnect(wsurl);
}

Code.stopHighlighter = function() {
if (Code.highlighter) {
Code.highlighter.doDisconnect();
Code.highlighter = null;
}
}

Code.startCamera = function() {
var canvas = document.getElementById('canvas_cam');
var context = canvas.getContext("2d");

Code.camera = new cozmoWs();

Code.camera.onMessage = function(msg) {
Code.drawImageBinary(msg.data, canvas, context);
};

var loc = window.location;
var wsurl = 'ws://' + loc.host + '/camSub';
Code.camera.doConnect(wsurl, true);
}

Code.stopCamera = function() {
// Disconnect camera WS.
if (Code.camera) {
Code.camera.doDisconnect()
Code.camera = null;
}
}

Code.sendXmlToUrl = function(urlToSendTo) {
var xml = Blockly.Xml.workspaceToDom(Code.workspace);
Expand Down Expand Up @@ -786,7 +802,8 @@ Code.stopRemoteExecution = function() {
method: 'POST'
})
.done(function(data, textStatus, jqXHR) {
Code.workspace.highlightBlock(null);
// Disconnect highlighter WS.
Code.stopHighlighter();
console.log('terminated');
})
.fail(function(jqXHR, textStatus, errorThrown) {
Expand Down
2 changes: 1 addition & 1 deletion nodejs/headless.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ require('../blockly/generators/python/procedures.js');

require('../blockly/msg/messages.js');

Blockly.Python.STATEMENT_PREFIX = 'app.highlightBlock(%1)\n';
Blockly.Python.STATEMENT_PREFIX = 'highlighter.send(%1)\n';

var express = require('express');
var bodyParser = require('body-parser')
Expand Down
8 changes: 4 additions & 4 deletions server/CodeExecutor.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ def __init__(self, nonsecure = False):
if nonsecure:
print("WARNING: Code will be executed in non-secure manner - Python code is accepted from the network for execution!")

def start(self, code, app):
def start(self, code):
self.stop()

if self._nonsecure:
Expand Down Expand Up @@ -52,7 +52,7 @@ def start(self, code, app):
on_start()
"""

self._starter = Process(target=self._exec_code, args=(starter_code, app))
self._starter = Process(target=self._exec_code, args=(starter_code, ))
self._starter.start()

def stop(self):
Expand All @@ -61,7 +61,7 @@ def stop(self):
self._starter.join()
self._starter = None

def _exec_code(self, code, app):
def _exec_code(self, code):

def signal_handler(signal, frame):
print('CodeExecutor process got ' + str(signal) + ' signal. Exitting...')
Expand All @@ -70,5 +70,5 @@ def signal_handler(signal, frame):
signal.signal(signal.SIGINT, signal_handler)
signal.signal(signal.SIGTERM, signal_handler)

bot = CozmoBot(app)
bot = CozmoBot()
bot.start(code)
21 changes: 18 additions & 3 deletions server/cozmobot.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,23 @@
"STARTLED": cozmo.anim.Triggers.ReactToUnexpectedMovement
}

class Highlighter:
def __init__(self):
self._client = None

def start(self):
from ws4py.client.threadedclient import WebSocketClient

self._client = WebSocketClient('ws://localhost:9090/highlightPub')
self._client.connect()

def send(self, block):
self._client.send(block)

class CozmoBot:
def __init__(self, app):
def __init__(self):
self._robot = None
self._origin = None
self._app = app
self._camPubThread = None

def start(self, code):
Expand All @@ -49,7 +61,10 @@ def run(sdk_conn):
self._robot.camera.image_stream_enabled = True

bot = self
app = self._app

highlighter = Highlighter()
highlighter.start()

import cozmo
exec(code, locals(), locals())

Expand Down
Loading

0 comments on commit 5a6c12d

Please sign in to comment.