summaryrefslogtreecommitdiffstats
path: root/src/uscxml/debug/DebuggerServlet.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/uscxml/debug/DebuggerServlet.cpp')
-rw-r--r--src/uscxml/debug/DebuggerServlet.cpp330
1 files changed, 134 insertions, 196 deletions
diff --git a/src/uscxml/debug/DebuggerServlet.cpp b/src/uscxml/debug/DebuggerServlet.cpp
index e179b8c..55ced75 100644
--- a/src/uscxml/debug/DebuggerServlet.cpp
+++ b/src/uscxml/debug/DebuggerServlet.cpp
@@ -23,25 +23,30 @@
namespace uscxml {
-void DebuggerServlet::pushData(Data pushData) {
+void DebuggerServlet::pushData(boost::shared_ptr<DebugSession> session, Data pushData) {
std::cout << "trying to push " << pushData["replyType"].atom << std::endl;
- _sendQueue.push(pushData);
- serverPushData();
+
+ if (!session) {
+ if (_sendQueues.size() > 0) // logging is not aware of its interpreter
+ _sendQueues.begin()->second.push(pushData);
+ } else {
+ _sendQueues[session].push(pushData);
+ }
+
+ serverPushData(session);
}
-void DebuggerServlet::serverPushData() {
- tthread::lock_guard<tthread::recursive_mutex> lock(_mutex);
-
- if (_sendQueue.isEmpty())
+void DebuggerServlet::serverPushData(boost::shared_ptr<DebugSession> session) {
+ if (_sendQueues[session].isEmpty())
return;
- if (!_clientConn)
+ if (!_clientConns[session])
return;
- Data reply = _sendQueue.pop();
+ Data reply = _sendQueues[session].pop();
std::cout << "pushing " << reply["replyType"].atom << std::endl;
- returnData(_clientConn, reply);
- _clientConn = HTTPServer::Request();
+ returnData(_clientConns[session], reply);
+ _clientConns[session] = HTTPServer::Request();
}
void DebuggerServlet::returnData(const HTTPServer::Request& request, Data replyData) {
@@ -56,17 +61,6 @@ void DebuggerServlet::returnData(const HTTPServer::Request& request, Data replyD
reply.headers["Content-Type"] = "application/json";
HTTPServer::reply(reply);
}
-
-void DebuggerServlet::hitBreakpoint(const Interpreter& interpreter,
- Data data) {
- tthread::lock_guard<tthread::recursive_mutex> lock(_mutex);
-
- data.compound["replyType"] = Data("breakpoint", Data::VERBATIM);
- pushData(data);
-
- _resumeCond.wait(_mutex);
- tthread::this_thread::sleep_for(tthread::chrono::milliseconds(200));
-}
bool DebuggerServlet::isCORS(const HTTPServer::Request& request) {
return (request.data["type"].atom == "options" &&
@@ -101,220 +95,164 @@ bool DebuggerServlet::httpRecvRequest(const HTTPServer::Request& request) {
std::cout << request.data["path"] << ": " << request.data["content"] << std::endl;
+ Data replyData;
+ // process request that don't need a session
if (false) {
- } else if (boost::starts_with(request.data["path"].atom, "/poll")) {
- processPoll(request);
- } else if (boost::starts_with(request.data["path"].atom, "/connect")) {
+ } else if (boost::starts_with(request.data["path"].atom, "/debug/connect")) {
processConnect(request);
- } else if (boost::starts_with(request.data["path"].atom, "/disconnect")) {
- processDisconnect(request);
- } else if (boost::starts_with(request.data["path"].atom, "/sessions")) {
+ return true;
+ } else if (boost::starts_with(request.data["path"].atom, "/debug/sessions")) {
processListSessions(request);
- } else if (boost::starts_with(request.data["path"].atom, "/breakpoint/add")) {
- processAddBreakPoint(request);
- } else if (boost::starts_with(request.data["path"].atom, "/breakpoint/remove")) {
- processRemoveBreakPoint(request);
+ return true;
+ }
+
+ // get session or return error
+ if (false) {
+ } else if (!request.data["content"].hasKey("session")) {
+ replyData.compound["status"] = Data("failure", Data::VERBATIM);
+ replyData.compound["reason"] = Data("No session given", Data::VERBATIM);
+ } else if (_sessionForId.find(request.data["content"]["session"].atom) == _sessionForId.end()) {
+ replyData.compound["status"] = Data("failure", Data::VERBATIM);
+ replyData.compound["reason"] = Data("No such session", Data::VERBATIM);
+ }
+ if (replyData) {
+ returnData(request, replyData);
+ return true;
+ }
+
+ boost::shared_ptr<DebugSession> session = _sessionForId[request.data["content"]["session"].atom];
+
+ if (false) {
+ } else if (boost::starts_with(request.data["path"].atom, "/debug/poll")) {
+ // save long-standing client poll
+ _clientConns[session] = request;
+ serverPushData(session);
+
+ } else if (boost::starts_with(request.data["path"].atom, "/debug/disconnect")) {
+ processDisconnect(request);
+
+ } else if (boost::starts_with(request.data["path"].atom, "/debug/breakpoint/enable/all")) {
+ replyData = session->enableAllBreakPoints();
+ } else if (boost::starts_with(request.data["path"].atom, "/debug/breakpoint/disable/all")) {
+ replyData = session->disableAllBreakPoints();
+ } else if (boost::starts_with(request.data["path"].atom, "/debug/breakpoint/skipto")) {
+ replyData = session->skipToBreakPoint(request.data["content"]);
+ } else if (boost::starts_with(request.data["path"].atom, "/debug/breakpoint/add")) {
+ replyData = session->addBreakPoint(request.data["content"]);
+ } else if (boost::starts_with(request.data["path"].atom, "/debug/breakpoint/remove")) {
+ replyData = session->removeBreakPoint(request.data["content"]);
+ } else if (boost::starts_with(request.data["path"].atom, "/debug/breakpoint/enable")) {
+ replyData = session->enableBreakPoint(request.data["content"]);
+ } else if (boost::starts_with(request.data["path"].atom, "/debug/breakpoint/disable")) {
+ replyData = session->disableBreakPoint(request.data["content"]);
+ } else if (boost::starts_with(request.data["path"].atom, "/debug/stop")) {
+ replyData = session->debugStop(request.data["content"]);
} else if (boost::starts_with(request.data["path"].atom, "/debug/prepare")) {
- processDebugPrepare(request);
+ replyData = session->debugPrepare(request.data["content"]);
+ } else if (boost::starts_with(request.data["path"].atom, "/debug/attach")) {
+ replyData = session->debugAttach(request.data["content"]);
} else if (boost::starts_with(request.data["path"].atom, "/debug/start")) {
- processDebugStart(request);
- } else if (boost::starts_with(request.data["path"].atom, "/debug/stop")) {
- processDebugStop(request);
+ replyData = session->debugStart(request.data["content"]);
} else if (boost::starts_with(request.data["path"].atom, "/debug/step")) {
- processDebugStep(request);
+ replyData = session->debugStep(request.data["content"]);
} else if (boost::starts_with(request.data["path"].atom, "/debug/pause")) {
- processDebugPause(request);
+ replyData = session->debugPause(request.data["content"]);
} else if (boost::starts_with(request.data["path"].atom, "/debug/resume")) {
- processDebugResume(request);
+ replyData = session->debugResume(request.data["content"]);
} else if (boost::starts_with(request.data["path"].atom, "/debug/eval")) {
- processDebugEval(request);
+ replyData = session->debugEval(request.data["content"]);
}
- return true;
-}
-
-void DebuggerServlet::processPoll(const HTTPServer::Request& request) {
- tthread::lock_guard<tthread::recursive_mutex> lock(_mutex);
- _clientConn = request;
- serverPushData();
-}
-
-void DebuggerServlet::processDebugPrepare(const HTTPServer::Request& request) {
- tthread::lock_guard<tthread::recursive_mutex> lock(_mutex);
-
-// std::cout << "clearing all pushes" << std::endl;
-// _sendQueue.clear();
-
- // this will call the destructor if _interpreter already is set
- _resumeCond.notify_all();
- _interpreter = Interpreter::fromXML(request.data["content"].atom);
-
- Data replyData;
- if (_interpreter) {
- // register ourself as a monitor
- _interpreter.addMonitor(this);
- replyData.compound["status"] = Data("success", Data::VERBATIM);
- } else {
- replyData.compound["status"] = Data("failure", Data::VERBATIM);
+ if (replyData) {
+ returnData(request, replyData);
+ return true;
}
- returnData(request, replyData);
+
+ return true;
}
-void DebuggerServlet::processDebugStart(const HTTPServer::Request& request) {
+// someone connected, create a new session
+void DebuggerServlet::processConnect(const HTTPServer::Request& request) {
tthread::lock_guard<tthread::recursive_mutex> lock(_mutex);
+ std::string sessionId = UUID::getUUID();
+
+ _sessionForId[sessionId] = boost::shared_ptr<DebugSession>(new DebugSession());
+ _sessionForId[sessionId]->setDebugger(this);
Data replyData;
- if (_interpreter) {
- // register ourself as a monitor
- _interpreter.start();
- replyData.compound["status"] = Data("success", Data::VERBATIM);
- } else {
- replyData.compound["status"] = Data("failure", Data::VERBATIM);
- }
+ replyData.compound["session"] = Data(sessionId, Data::VERBATIM);
+ replyData.compound["status"] = Data("success", Data::VERBATIM);
returnData(request, replyData);
}
-void DebuggerServlet::processDebugStop(const HTTPServer::Request& request) {
-// tthread::lock_guard<tthread::recursive_mutex> lock(_mutex);
-
- stepping(false);
+void DebuggerServlet::processDisconnect(const HTTPServer::Request& request) {
+ tthread::lock_guard<tthread::recursive_mutex> lock(_mutex);
Data replyData;
- if (_interpreter) {
- _interpreter.stop();
- _resumeCond.notify_all(); // unblock breakpoints
- _interpreter.join();
- _interpreter = Interpreter(); // empty interpreter, calls destructor
- replyData.compound["status"] = Data("success", Data::VERBATIM);
- } else {
- replyData.compound["status"] = Data("failure", Data::VERBATIM);
- replyData.compound["reason"] = Data("Interpreter already stopped", Data::VERBATIM);
- }
- returnData(request, replyData);
-}
-void DebuggerServlet::processDebugEval(const HTTPServer::Request& request) {
- Data replyData;
- if (!_interpreter) {
- replyData.compound["status"] = Data("failure", Data::VERBATIM);
- replyData.compound["reason"] = Data("No interpreter running", Data::VERBATIM);
- } else if (!_interpreter.getDataModel()) {
+ if (!request.data["content"].hasKey("session")) {
replyData.compound["status"] = Data("failure", Data::VERBATIM);
- replyData.compound["reason"] = Data("No datamodel available", Data::VERBATIM);
- } else if (!request.data["content"].hasKey("expression")) {
- replyData.compound["status"] = Data("failure", Data::VERBATIM);
- replyData.compound["reason"] = Data("No expression given", Data::VERBATIM);
- } else {
- std::string expr = request.data["content"]["expression"].atom;
- try {
- replyData.compound["eval"] = _interpreter.getDataModel().getStringAsData(expr);
- } catch (Event e) {
- replyData.compound["eval"] = e.data;
- replyData.compound["eval"].compound["error"] = Data(e.name, Data::VERBATIM);
- }
- replyData.compound["status"] = Data("success", Data::VERBATIM);
+ replyData.compound["reason"] = Data("No session given", Data::VERBATIM);
+ returnData(request, replyData);
}
- returnData(request, replyData);
-}
-void DebuggerServlet::processDebugStep(const HTTPServer::Request& request) {
- tthread::lock_guard<tthread::recursive_mutex> lock(_mutex);
+ std::string sessionId = request.data["content"]["session"].atom;
- stepping(true);
- _resumeCond.notify_one();
-
- Data replyData;
- if (_interpreter && !_interpreter.isRunning()) {
- // register ourself as a monitor
- _interpreter.start();
- replyData.compound["status"] = Data("success", Data::VERBATIM);
- } else {
+ if (_sessionForId.find(sessionId) == _sessionForId.end()) {
replyData.compound["status"] = Data("failure", Data::VERBATIM);
+ replyData.compound["reason"] = Data("No such session", Data::VERBATIM);
+ } else {
+ replyData.compound["status"] = Data("success", Data::VERBATIM);
+ detachSession(_sessionForId[sessionId]->getInterpreter());
+ _sessionForId[sessionId]->debugStop(request.data["content"]);
+ _clientConns.erase(_sessionForId[sessionId]);
+ _sendQueues.erase(_sessionForId[sessionId]);
+ _sessionForId.erase(sessionId);
}
- returnData(request, replyData);
-
-}
-
-void DebuggerServlet::processDebugResume(const HTTPServer::Request& request) {
- tthread::lock_guard<tthread::recursive_mutex> lock(_mutex);
-
- stepping(false);
-
- Data replyData;
- replyData.compound["status"] = Data("success", Data::VERBATIM);
- returnData(request, replyData);
-
- _resumeCond.notify_one();
-}
-
-void DebuggerServlet::processDebugPause(const HTTPServer::Request& request) {
- tthread::lock_guard<tthread::recursive_mutex> lock(_mutex);
-
- Data replyData;
- replyData.compound["status"] = Data("success", Data::VERBATIM);
- returnData(request, replyData);
-}
-
-void DebuggerServlet::processConnect(const HTTPServer::Request& request) {
- tthread::lock_guard<tthread::recursive_mutex> lock(_mutex);
- _sessionId = UUID::getUUID();
- _breakPoints.clear();
-// _sendQueue.clear();
- Data replyData;
- replyData.compound["session"] = Data(_sessionId, Data::VERBATIM);
- replyData.compound["status"] = Data("success", Data::VERBATIM);
returnData(request, replyData);
}
void DebuggerServlet::processListSessions(const HTTPServer::Request& request) {
Data replyData;
-
- // TODO: return actual data
- Data sessionData;
- sessionData.compound["name"] = Data("Not actually a Session", Data::VERBATIM);
- sessionData.compound["id"] = Data("23452523-wg23g2g2-234t2g-23g2g", Data::VERBATIM);
- replyData.compound["sessions"].array.push_back(sessionData);
-
- sessionData.compound["name"] = Data("But returned from the server!", Data::VERBATIM);
- sessionData.compound["id"] = Data("swfgsgfw-g232vqvq-234t2g-23g2g", Data::VERBATIM);
- replyData.compound["sessions"].array.push_back(sessionData);
-
- replyData.compound["status"] = Data("success", Data::VERBATIM);
- returnData(request, replyData);
-}
-
-void DebuggerServlet::processDisconnect(const HTTPServer::Request& request) {
- Data replyData;
- replyData.compound["status"] = Data("success", Data::VERBATIM);
- returnData(request, replyData);
-}
-
-void DebuggerServlet::processAddBreakPoint(const HTTPServer::Request& request) {
- Breakpoint breakPoint(request.data["content"]);
- Data replyData;
- if (breakPoint.isValid()) {
- replyData.compound["status"] = Data("success", Data::VERBATIM);
-
- if (_breakPoints.find(breakPoint) == _breakPoints.end()) {
- _breakPoints.insert(breakPoint);
+
+ std::map<std::string, boost::weak_ptr<InterpreterImpl> > instances = Interpreter::getInstances();
+ for (std::map<std::string, boost::weak_ptr<InterpreterImpl> >::iterator instIter = instances.begin();
+ instIter != instances.end();
+ instIter++) {
+
+ boost::shared_ptr<InterpreterImpl> instance = instIter->second.lock();
+ if (instance) {
+ Data sessionData;
+ sessionData.compound["name"] = Data(instance->getName(), Data::VERBATIM);
+ sessionData.compound["id"] = Data(instance->getSessionId(), Data::VERBATIM);
+ sessionData.compound["source"] = Data(instance->getSourceURI().asString(), Data::VERBATIM);
+ sessionData.compound["xml"].node = instance->getDocument();
+
+ replyData.compound["sessions"].array.push_back(sessionData);
}
- } else {
- replyData.compound["status"] = Data("failure", Data::VERBATIM);
}
+
+ replyData.compound["status"] = Data("success", Data::VERBATIM);
returnData(request, replyData);
}
-void DebuggerServlet::processRemoveBreakPoint(const HTTPServer::Request& request) {
- Breakpoint breakPoint(request.data["content"]);
- Data replyData;
- if (_breakPoints.erase(breakPoint) > 0) {
- replyData.compound["status"] = Data("success", Data::VERBATIM);
- } else {
- replyData.compound["message"] = Data("No such breakpoint", Data::VERBATIM);
- replyData.compound["status"] = Data("failure", Data::VERBATIM);
- }
- returnData(request, replyData);
+void DebuggerServlet::send(google::LogSeverity severity, const char* full_filename,
+ const char* base_filename, int line,
+ const struct ::tm* tm_time,
+ const char* message, size_t message_len) {
+
+ // _sendQueue is thread-safe, not sure about ToString though
+
+ LogMessage msg(severity,
+ full_filename,
+ base_filename,
+ line,
+ tm_time,
+ std::string(message, message_len),
+ ToString(severity, base_filename, line, tm_time, message, message_len));
+ msg.compound["replyType"] = Data("log", Data::VERBATIM);
+ pushData(boost::shared_ptr<DebugSession>(), msg);
}