Quellcode durchsuchen

continue refactor, now multithreaded

Missingmew vor 4 Jahren
Ursprung
Commit
3d986ff498

+ 10 - 14
cli/include/cmdman.h

@@ -15,7 +15,7 @@ using std::map;
 
 class CmdMan {
 public:
-	enum rettype { json, error, text };
+	enum rettype { notsend, send, error, startlist, stoplist, close, seton };
 	struct CmdRet {
 		rettype type;
 		string msg;
@@ -28,18 +28,6 @@ public:
 	// if cmd unknown, returns error string
 	CmdRet execute(string cmd, vector<string> args);
 	CmdRet handle(Json::Value root);
-
-	//~ bool sendJson(Json::Value root);
-	//~ bool receiveJson(boost::asio::streambuf &recvbuf);
-	//~ bool parseJson(Json::Value *root, boost::asio::streambuf &recvbuf);
-	
-	
-	/* internal commands */
-	CmdRet cmdVersion(string);
-	CmdRet cmdLogin(string, string);
-	CmdRet cmdPutdata();
-	CmdRet cmdGetdata();
-	
 	
 	Json::CharReader* reader;
 	
@@ -70,10 +58,18 @@ private:
 	const string descList = "list files available on server";
 	CmdRet cmdList(vector<string> args);
 	
+	/* internal execute commands */
+	CmdRet cmdVersion(vector<string> args);
+	CmdRet cmdLogin(vector<string> args);
+	
 	/* handle commands go here */
-	CmdRet handleDefault(Json::Value);
+	CmdRet handleStatus(Json::Value);
+	CmdRet handleClose(Json::Value);
 	CmdRet handlePut(Json::Value);
 	CmdRet handleGet(Json::Value);
+	CmdRet handleList(Json::Value);
+	CmdRet handleVersion(Json::Value);
+	CmdRet handleLogin(Json::Value);
 };
 
 #endif

+ 3 - 1
cli/include/global.h

@@ -1,6 +1,8 @@
 #ifndef GLOBAL_H
 #define GLOBAL_H
 
-#define VERSION "0.1"
+#include <string>
+
+const std::string protocolVersion = "0.2";
 
 #endif

+ 34 - 11
cli/include/ioman.h

@@ -6,15 +6,16 @@
 
 #include <boost/asio.hpp>
 #include <string>
+#include <thread>
+#include <mutex>
+#include <vector>
 
 using boost::asio::ip::tcp;
 
 #define BLOCKSIZE 8
 
-
 class IoMan {
 private:
-	const std::string protoVersion = "0.2";
 	boost::asio::io_service ios;
 	boost::asio::streambuf sendbuf;
 	boost::asio::streambuf recvbuf;
@@ -23,15 +24,41 @@ private:
 	std::string ipstring;
 	int port;
 	bool connected;
-
-protected:
 	CmdMan cmdman;
 	FileMan fileman;
-	bool loggedin;
+
+	/*
+	3 threads: handleinput, handlenetwork, handleresponse
+	*/
+	std::thread tinput, tnetwork, tresponse;
+	bool runmain, runinput, runnetwork, runresponse;
+
+	std::vector<Json::Value> netinput;
+	std::vector<std::string> localinput;
+	std::mutex netmutex, localmutex;
+	
+	/*
+	to be put elsewhere
+	*/
+	Json::CharReader* reader;
+	Json::StreamWriterBuilder wbuilder;
+	string jsonerror;
 	
-	bool parseJson(Json::Value *root, string jsonstring);
-	virtual bool handleJson(Json::Value root) = 0;
+	void networkMain();
+	void inputMain();
+	void responseMain();
+	
+	enum Status { off, on, err };
+	
+	Status versionstatus;
+	Status loginstatus;
+	
+	bool startlist;
+
+protected:
+	virtual void printNormalMessage(std::string msg) = 0;
 	virtual void printErrorMessage(std::string msg) = 0;
+	virtual void printDebugMessage(std::string msg) = 0;
 	virtual void printWelcomeMessage() = 0;
 	virtual std::string getCmdPrompt() = 0;
 	virtual std::string getUserPrompt() = 0;
@@ -49,10 +76,6 @@ public:
 
 	// tries to establish connection, returns error string if applicable
 	bool connect();
-	// sends a string
-	bool sendJsonString(std::string msg);
-	// returns a single json object as string
-	std::string receiveJsonString();
 	// disconnect from server
 	void disconnect();
 	

+ 2 - 0
cli/include/machineioman.h

@@ -9,7 +9,9 @@ public:
 
 	bool parseJson(Json::Value *root, string jsonstring);
 	bool handleJson(Json::Value root);
+	void printNormalMessage(std::string msg);
 	void printErrorMessage(std::string msg);
+	void printDebugMessage(std::string msg);
 	void printWelcomeMessage();
 
 	std::string getCmdPrompt();

+ 2 - 0
cli/include/userioman.h

@@ -9,7 +9,9 @@ public:
 
 	bool parseJson(Json::Value *root, string jsonstring);
 	bool handleJson(Json::Value root);
+	void printNormalMessage(std::string msg);
 	void printErrorMessage(std::string msg);
+	void printDebugMessage(std::string msg);
 	void printWelcomeMessage();
 
 	std::string getCmdPrompt();

+ 95 - 24
cli/src/cmdman.cpp

@@ -1,3 +1,4 @@
+#include "../include/global.h"
 #include "../include/cmdman.h"
 
 CmdMan::CmdMan(FileMan &fm) : fileman(fileman) {
@@ -14,6 +15,8 @@ CmdMan::CmdMan(FileMan &fm) : fileman(fileman) {
 	execmap["put"] = &CmdMan::cmdPut;
 	execmap["get"] = &CmdMan::cmdGet;
 	execmap["list"] = &CmdMan::cmdList;
+	execmap["version"] = &CmdMan::cmdVersion;
+	execmap["login"] = &CmdMan::cmdLogin;
 	
 	/* initialize description map */
 	helpmap["help"] = descHelp;
@@ -24,11 +27,13 @@ CmdMan::CmdMan(FileMan &fm) : fileman(fileman) {
 	helpmap["list"] = descList;
 	
 	/* initialize handle command map */
-	handlemap["status"] = &CmdMan::handleDefault;
-	handlemap["disconnect"] = &CmdMan::handleDefault;
-	handlemap["put"] = &CmdMan::handleDefault;
-	handlemap["get"] = &CmdMan::handleDefault;
-	handlemap["list"] = NULL;
+	handlemap["status"] = &CmdMan::handleStatus;
+	handlemap["disconnect"] = &CmdMan::handleClose;
+	handlemap["put"] = &CmdMan::handlePut;
+	handlemap["get"] = &CmdMan::handleGet;
+	handlemap["list"] = &CmdMan::handleList;
+	handlemap["version"] = &CmdMan::handleVersion;
+	handlemap["login"] = &CmdMan::handleLogin;
 }
 
 CmdMan::~CmdMan() {
@@ -44,7 +49,7 @@ CmdMan::CmdRet CmdMan::cmdHelp(vector<string> args) {
 		retval.msg.append(it->second);
 		retval.msg.append("\n");
 	}
-	retval.type = text;
+	retval.type = notsend;
 	return retval;
 }
 
@@ -52,7 +57,7 @@ CmdMan::CmdRet CmdMan::cmdStatus(vector<string> args) {
 	CmdRet retval;
 	Json::Value root;
 	root["command"] = "status";
-	retval.type = json;
+	retval.type = send;
 	retval.msg = Json::writeString(wbuilder, root);
 	
 	return retval;
@@ -62,7 +67,7 @@ CmdMan::CmdRet CmdMan::cmdDisconnect(vector<string> args) {
 	CmdRet retval;
 	Json::Value root;
 	root["command"] = "close";
-	retval.type = json;
+	retval.type = send;
 	retval.msg = Json::writeString(wbuilder, root);
 	
 	return retval;
@@ -77,7 +82,7 @@ CmdMan::CmdRet CmdMan::cmdPut(vector<string> args) {
 		root["command"] = "put";
 		root["file"] = fileman.getPutName();
 		root["size"] = fileman.getPutChunks();
-		retval.type = json;
+		retval.type = send;
 		retval.msg = Json::writeString(wbuilder, root);
 	}
 	else {
@@ -96,7 +101,7 @@ CmdMan::CmdRet CmdMan::cmdGet(vector<string> args) {
 	if(opened) {
 		root["command"] = "get";
 		root["file"] = fileman.getGetName();
-		retval.type = json;
+		retval.type = send;
 		retval.msg = Json::writeString(wbuilder, root);
 	}
 	else {
@@ -111,7 +116,7 @@ CmdMan::CmdRet CmdMan::cmdList(vector<string> args) {
 	CmdRet retval;
 	Json::Value root;
 	root["command"] = "list";
-	retval.type = json;
+	retval.type = send;
 	retval.msg = Json::writeString(wbuilder, root);
 	
 	return retval;
@@ -128,42 +133,69 @@ CmdMan::CmdRet CmdMan::execute(string cmd, vector<string> args) {
 }
 
 /* internal commands */
-CmdMan::CmdRet CmdMan::cmdVersion(string version) {
+CmdMan::CmdRet CmdMan::cmdVersion(vector<string> args) {
 	CmdRet retval;
 	Json::Value root;
-	root["version"] = version;
-	retval.type = json;
+	root["version"] = protocolVersion;
+	retval.type = send;
 	retval.msg = Json::writeString(wbuilder, root);
 	
 	return retval;
 }
 
-CmdMan::CmdRet CmdMan::cmdLogin(string user, string pass) {
+CmdMan::CmdRet CmdMan::cmdLogin(vector<string> args) {
 	CmdRet retval;
 	Json::Value root;
-	root["user"] = user;
-	root["pass"] = pass;
+	root["user"] = args[0];
+	root["pass"] = args[1];
 	root["login"] = true;
 	root["cancel"] = false;
-	retval.type = json;
+	retval.type = send;
 	retval.msg = Json::writeString(wbuilder, root);
 	
 	return retval;
 }
 
-CmdMan::CmdRet CmdMan::handleDefault(Json::Value root) {
+/*
+	handlemap["status"] = &CmdMan::handleDefault;
+	handlemap["disconnect"] = &CmdMan::handleDefault;
+	handlemap["put"] = &CmdMan::handleDefault;
+	handlemap["get"] = &CmdMan::handleDefault;
+	handlemap["list"] = NULL;
+	handlemap["version"] = NULL;
+	handlemap["login"] = NULL;
+*/
+
+CmdMan::CmdRet CmdMan::handle(Json::Value root) {
+	map<string,CmdRet(CmdMan::*)(Json::Value)>::iterator it = handlemap.find(root["command"].asString());
+	string retmsg;
+	if(it == handlemap.end()) {
+		return { error, "unknown command \"" + root["command"].asString() + "\".\nensure code is implemented." };
+	}
+	return (this->*(handlemap[root["command"].asString()]))(root);
+}
+
+CmdMan::CmdRet CmdMan::handleStatus(Json::Value root) {
 	CmdRet retval;
+	retval.type = notsend;
+	retval.msg = root["response"].asString();
 	
-	retval.type = json;
-	retval.msg = Json::writeString(wbuilder, root);
+	return retval;
+}
+
+CmdMan::CmdRet CmdMan::handleClose(Json::Value root) {
+	CmdRet retval;
+	retval.type = close;
+	retval.msg = root["response"].asString();
 	
 	return retval;
 }
+	
 
 CmdMan::CmdRet CmdMan::handlePut(Json::Value root) {
 	CmdRet retval;
 	
-	retval.type = json;
+	retval.type = send;
 	retval.msg = Json::writeString(wbuilder, root);
 	
 	return retval;
@@ -172,8 +204,47 @@ CmdMan::CmdRet CmdMan::handlePut(Json::Value root) {
 CmdMan::CmdRet CmdMan::handleGet(Json::Value root) {
 	CmdRet retval;
 	
-	retval.type = json;
+	retval.type = send;
 	retval.msg = Json::writeString(wbuilder, root);
 	
 	return retval;
-}
+}
+
+CmdMan::CmdRet CmdMan::handleList(Json::Value root) {
+	CmdRet retval;
+	
+	retval.type = send;
+	retval.msg = Json::writeString(wbuilder, root);
+	
+	return retval;
+}
+
+CmdMan::CmdRet CmdMan::handleVersion(Json::Value root) {
+	CmdRet retval;
+	
+	if(!root["accept"].asBool()) {
+		retval.type = error;
+		retval.msg = "Version check failed: Server reports " + root["version"].asString() + " but client is version " + protocolVersion;
+	}
+	else {
+		retval.type = seton;
+		retval.msg = "Version check ok.";
+	}
+	
+	return retval;
+}
+
+CmdMan::CmdRet CmdMan::handleLogin(Json::Value root) {
+	CmdRet retval;
+	
+	if(!root["accept"].asBool()) {
+		retval.type = error;
+		retval.msg = "Login failed: " + root["error"].asString();
+	}
+	else {
+		retval.type = seton;
+		retval.msg = "Login ok.";
+	}
+	
+	return retval;
+}

+ 308 - 122
cli/src/ioman.cpp

@@ -1,3 +1,4 @@
+#include "../include/global.h"
 #include "../include/ioman.h"
 
 #include <boost/asio.hpp>
@@ -21,12 +22,32 @@ IoMan::IoMan(char *ipcstring) : cmdman(fileman) {
   port = 1234;
   tcpsock = new tcp::socket(ios);
   connected = false;
+	
+	/* to be put elsewhere */
+
+	/* setup json stuff */
+  Json::CharReaderBuilder rbuilder;
+  wbuilder.settings_["indentation"] = "";
+  reader = rbuilder.newCharReader();
+	runnetwork = false;
+	runinput = false;
+	runresponse = false;
+	startlist = false;
 }
 
 IoMan::~IoMan() {
+	runnetwork = false;
+	runinput = false;
+	runresponse = false;
+	
+	tnetwork.join();
+	tinput.join();
+	tresponse.join();
+	
 	if(connected) {
 		disconnect();
 	}
+	
 	delete tcpsock;
 }
 
@@ -36,11 +57,11 @@ bool IoMan::connect() {
   ep = new tcp::endpoint(boost::asio::ip::address::from_string(ipstring), 1234);
 
   // establish connection
-  std::cerr << "IoMan::connect() connecting to " << ipstring << std::endl;
+  printDebugMessage("IoMan::connect() connecting to " + ipstring);
   tcpsock->connect(*ep, errcode);
   if (errcode) {
 	  delete ep;
-	  printErrorMessage("IoMan::connect() couldnt connect to " + ipstring + "\n" + errcode.message() + "\n");
+	  printErrorMessage("IoMan::connect() couldnt connect to " + ipstring + "\n" + errcode.message());
 	return false;
   }
   connected = true;
@@ -50,68 +71,42 @@ bool IoMan::connect() {
 
 
 void IoMan::disconnect() {
-  std::cerr << "IoMan::disconnect()" << std::endl;
+  printDebugMessage("IoMan::disconnect()");
 	tcpsock->close();
 	connected = false;
 }
 
-bool IoMan::sendJsonString(std::string msg) {
-  std::cerr << "IoMan::sendJsonString() " << msg << std::endl;
-  boost::asio::write(*tcpsock, buffer(msg + "\n"), errcode);
-  if (errcode) {
-	  printErrorMessage("IoMan::sendJsonString() couldnt send json data\n" + errcode.message() + "\n");
-	  return false;
-  }
-  return true;
-}
-
-std::string IoMan::receiveJsonString() {
-	std::string retstring;
-  std::cerr << "IoMan::receiveJsonString()" << std::endl;
-	// use transfer_at_least(1) to avoid deadlock with transfer_all()
-  boost::asio::read_until(*tcpsock, recvbuf, '\n', errcode);
-  if (errcode && errcode != boost::asio::error::eof) {
-	  printErrorMessage("IoMan::receiveJsonString() couldnt read json data\n" + errcode.message() + "\n");
-  }
-  retstring = boost::asio::buffer_cast<const char *>(recvbuf.data());
-  recvbuf.consume(recvbuf.size());
-  std::cerr << "IoMan::receiveJsonString(): returning string \"" << retstring << "\"" << std::endl;
-  return retstring;
-}
-
-bool IoMan::parseJson(Json::Value *root, string jsonstring) {
-  const char *recvjson;
-  std::string jsonerror;
-  recvjson = jsonstring.c_str();
-  if (!cmdman.reader->parse(recvjson, recvjson + jsonstring.size(), root, &jsonerror)) {
-	printErrorMessage("couldnt parse json data: " + jsonerror + "\n");
-    return false;
-  }
-  return true;
-}
 
 bool IoMan::init() {
 	CmdMan::CmdRet ret;
 	string work;
 	Json::Value root;
 	
+	printDebugMessage("IoMan::Init() begin");
+	
 	if(!connect()) return false;
 	
-	ret = cmdman.cmdVersion(protoVersion);
+	printDebugMessage("IoMan::Init() versioncheck");
+	
+	localmutex.lock();
+	localinput.push_back("version " + protocolVersion);
+	localmutex.unlock();
 	
-	if(!sendJsonString(ret.msg)) return false;
+	printDebugMessage("IoMan::Init() begin");
 	
-	work = receiveJsonString();
-	if(work.empty()) return false;
+	runnetwork = true;
+	runinput = true;
+	runresponse = true;
 	
-	if(!parseJson(&root, work)) return false;
+	tnetwork = std::thread(&IoMan::networkMain, this);
+	tinput = std::thread(&IoMan::inputMain, this);
+	tresponse = std::thread(&IoMan::responseMain, this);
 	
-	if(!root["accept"].asBool()) {
-		work = "IoMan::init() Version check failed. Server reports ";
-		work.append(root["version"].asString());
-		work.append(" but client is ");
-		work.append(protoVersion);
-		printErrorMessage(work);
+	while(versionstatus == off);
+	if(versionstatus == err) {
+		runnetwork = false;
+		runinput = false;
+		runresponse = false;
 		return false;
 	}
 	
@@ -119,15 +114,245 @@ bool IoMan::init() {
 	return true;
 }
 
+void IoMan::networkMain() {
+	vector<Json::Value> toput;
+	const char *recvjson;
+	Json::Value root;
+	unsigned int jsonsize;
+	
+	printDebugMessage("IoMan::networkMain() begin");
+	while(runnetwork) {
+		/*
+		read from network until \n
+		try to parse json
+		- output error if not ok
+		store all ok json in local vector
+		
+		get networkmutex
+		put all local jsons into network vector
+		release networkmutex
+		*/
+		
+		// read from network
+		boost::asio::read_until(*tcpsock, recvbuf, '\n', errcode);
+		if (errcode && errcode != boost::asio::error::eof) {
+			printErrorMessage("IoMan::networkMain() couldnt read json data\n" + errcode.message());
+			continue;
+		}
+		
+		recvjson = boost::asio::buffer_cast<const char *>(recvbuf.data());
+		while(strchr(recvjson, '\n')) {
+			// parse
+			jsonsize = strchr(recvjson, '\n') - recvjson;
+			
+			if (!reader->parse(recvjson, recvjson + jsonsize, &root, &jsonerror)) {
+				printErrorMessage("IoMan::networkMain() couldnt parse json data: " + jsonerror);
+				recvbuf.consume(jsonsize);
+				continue;
+			}
+			recvbuf.consume(jsonsize);
+			
+			// store locally
+			toput.push_back(root);
+		}
+		
+		// put into global vector
+		netmutex.lock();
+		netinput.insert(netinput.end(), toput.begin(), toput.end());
+		netmutex.unlock();
+	}
+}
+
+void IoMan::inputMain() {
+	vector<string> toprocess;
+	string command;
+	vector<string> args;
+	CmdMan::CmdRet cmdret;
+	
+	size_t prev, index, quot;
+	
+	printDebugMessage("IoMan::inputMain() begin");
+	while(runinput) {
+		/*
+		get inputmutex
+		read all input vector into local vector
+		release inputmutex
+		
+		process inputs
+		send to server if required
+		*/
+		
+		// read into local vector
+		if(localinput.size()) {
+			localmutex.lock();
+			toprocess = vector<string>(localinput);
+			localinput = vector<string>();
+			localmutex.unlock();
+		}
+		
+		printDebugMessage(string("have ") + std::to_string(toprocess.size()) + string(" commands"));
+		
+		// process
+		for(string cmd : toprocess) {
+			args = vector<string>();
+			
+			if((index = cmd.find(" ")) == string::npos) {
+				// only command no args
+				command = cmd;
+			}
+			else {
+				command = cmd.substr(0, index);
+				index++;
+				while(true) {
+					// find first char thats not a space
+					while(cmd[index] == ' ') {
+						index++;
+						
+						// bounds check
+						if(index == cmd.size()) goto end_tokenizing;
+					}
+					
+					cmd = cmd.substr(index);
+					
+					if(cmd[0] == '\"') {
+						// quoted string
+						index = cmd.find("\"");
+						args.push_back(cmd.substr(1, index-1));
+						index++;
+						
+						/*
+						tokens.push_back(cmd.substr(0, ++index));
+						*/
+						
+						// char after closing quote should be space while within bounds
+						if(index == cmd.size()) goto end_tokenizing;
+					}
+					else {
+						// non-quoted string
+						index = cmd.find(" ");
+						if(index == string::npos) { // no spaces, last arg
+							args.push_back(cmd);
+							goto end_tokenizing;
+						}
+						else {
+							args.push_back(cmd.substr(1, index));
+						}
+					}
+				}
+				end_tokenizing: ;
+			}
+			
+			cmdret = cmdman.execute(command, args);
+			
+			// determine wether to send something and do so if required
+			switch(cmdret.type) {
+				case CmdMan::rettype::send: {
+					printDebugMessage("IoMan::inputMain() sending json \"" + cmdret.msg + "\"");
+					boost::asio::write(*tcpsock, buffer(cmdret.msg + "\n"), errcode);
+					if (errcode) {
+						printErrorMessage("IoMan::inputMain() couldnt send json data\n" + errcode.message() + "\n");
+						continue;
+					}
+					break;
+				}
+				case CmdMan::rettype::notsend: {
+					printNormalMessage(cmdret.msg);
+					break;
+				}
+				case CmdMan::rettype::error: {
+					printErrorMessage(cmdret.msg);
+					break;
+				}
+			}
+		}
+	}
+}
+
+void IoMan::responseMain() {
+	vector<Json::Value> toprocess;
+	vector<string> toput;
+	CmdMan::CmdRet cmdret;
+	
+	printDebugMessage("IoMan::responseMain() begin");
+	while(runresponse) {
+		/*
+		get networkmutex
+		read all network vector into local vector
+		release networkmutex
+		
+		process all jsons
+		process putdata
+		process getdata
+		process listdata
+		
+		get inputmutex
+		place new commands into input vector
+		release inputmutex
+		*/
+		
+		// read into local vector
+		if(netinput.size()) {
+			netmutex.lock();
+			toprocess = vector<Json::Value>(netinput);
+			netinput = vector<Json::Value>();
+			netmutex.unlock();
+		}
+		
+		// process jsons
+		for(Json::Value root : toprocess) {
+			cmdret = cmdman.handle(root);
+			switch(cmdret.type) {
+				case CmdMan::rettype::startlist: {
+					startlist = true;
+					break;
+				}
+				case CmdMan::rettype::stoplist: {
+					startlist = false;
+					break;
+				}
+				case CmdMan::rettype::close: {
+					/* TODO i dunno */
+					runmain = false;
+					break;
+				}
+				case CmdMan::rettype::error: {
+					if(versionstatus == off) versionstatus = err;
+					else if(loginstatus == off) loginstatus = err;
+					printErrorMessage(cmdret.msg);
+					break;
+				}
+				case CmdMan::rettype::seton: {
+					if(versionstatus == off) versionstatus = on;
+					else loginstatus = on;
+				}
+				case CmdMan::rettype::notsend: {
+					printNormalMessage(cmdret.msg);
+					break;
+				}
+				case CmdMan::rettype::send: {
+					toput.push_back(cmdret.msg);
+					break;
+				}
+			}
+		}
+		
+		// put new commands into global vector
+		localmutex.lock();
+		localinput.insert(localinput.end(), toput.begin(), toput.end());
+		localmutex.unlock();
+	}
+}
+
 void IoMan::run() {
-	std::cerr << "IoMan::run() begin" << std::endl;
-	bool running = true;
+	printDebugMessage("IoMan::run() begin");
 	char *line = NULL, *user = NULL, *pass = NULL;
 	vector<string> tokens;
 	string work, command;
 	CmdMan::CmdRet cmdret;
 	Json::Value root;
 	
+	runmain = true;
+	
 	while(!user) {
 		user = readline(getUserPrompt().c_str());
 		printErrorMessage("Using user: " + string(user));
@@ -137,88 +362,49 @@ void IoMan::run() {
 		printErrorMessage("Using pass: " + string(pass));
 	}
 	
-	std::cerr << "IoMan::run() begin" << std::endl;
+	printDebugMessage("IoMan::run() login");
 	
-	/* move login elsewhere? */
-	cmdret = cmdman.cmdLogin(string(user), string(pass));
+	localmutex.lock();
+	localinput.push_back("login " + string(user) + " " + string(pass));
+	localmutex.unlock();
 	free(user);
 	free(pass);
 	
-	if(!sendJsonString(cmdret.msg)) return;
+	while(loginstatus == off);
+	if(loginstatus == err) return;
 	
-	work = receiveJsonString();
-	if(work.empty()) return;
-	
-	if(!parseJson(&root, work)) return;
-	if(!root["accept"].asBool()) {
-		work = "IoMan::run() Login refused. ";
-		work.append(root["error"].asString());
-		printErrorMessage(work);
-		return;
-	}
-	
-	
-	while(running) {
+	while(runmain) {
 		free(line);
 		
 		line = readline(getCmdPrompt().c_str());
+		
+		if(!runmain) break;
 
-	    // if no input, do not add to history, and go to reading next line
-	    if (strlen(line) == 0) {
-	      continue;
-	    }
-
-	    // split input line into tokens
-	    boost::algorithm::split(tokens, std::string(line),
-				    boost::algorithm::is_any_of(" "),
-				    boost::algorithm::token_compress_on);
-
-	    // if input contains only spaces, do not add to history, and go to reading
-	    // next line
-	    if (tokens.size() < 1) {
-	      continue;
-	    }
-
-	    // add the line to history
-	    add_history(line);
-	    command = tokens[0];
-	    tokens.erase(tokens.begin());
-	    
-	    cmdret = cmdman.execute(command, tokens);
-	    switch(cmdret.type) {
-		    case CmdMan::rettype::error: {
-			printErrorMessage(cmdret.msg);
-			break;
-		    }
-		    case CmdMan::rettype::text: {
-			    // only for userioman
-			    std::cout << cmdret.msg << std::endl;
-			    break;
-		    }
-		    case CmdMan::rettype::json: {
-			    if(!sendJsonString(cmdret.msg)) continue;
-			
-			while(1) {
-				work = receiveJsonString();
-				if(work.empty()) break;
-				
-				if(!work.size()) break;
-				
-				if(!parseJson(&root, work)) break;
-				else if(!handleJson(root)) {
-					running = false;
-					break;
-				}
-			}				
-			break;
-		    }
-	    }
-	    
-	    if(!connected) break;
+		// if no input, do not add to history, and go to reading next line
+		if (strlen(line) == 0) {
+		  continue;
+		}
+
+		// split input line into tokens
+		boost::algorithm::split(tokens, std::string(line),
+					boost::algorithm::is_any_of(" "),
+					boost::algorithm::token_compress_on);
+
+		// if input contains only spaces, do not add to history, and go to reading
+		// next line
+		if (tokens.size() < 1) {
+		  continue;
+		}
+
+		// add the line to history
+		add_history(line);
+		
+		localmutex.lock();
+		localinput.push_back(line);
+		localmutex.unlock();
+		
+		if(!connected) break;
 	}
 	
 	free(line);
 }
-
-
-

+ 8 - 0
cli/src/machineioman.cpp

@@ -20,10 +20,18 @@ bool MachineIoMan::handleJson(Json::Value root) {
 	return false;
 }
 
+void MachineIoMan::printNormalMessage(std::string msg) {
+	std::cout << msg << std::endl;
+}
+
 void MachineIoMan::printErrorMessage(std::string msg) {
 	std::cout << msg << std::endl;
 }
 
+void MachineIoMan::printDebugMessage(std::string msg) {
+	std::cerr << msg << std::endl;
+}
+
 void MachineIoMan::printWelcomeMessage() {
 	std::cout << "please enter user and password" << std::endl;
 }

+ 8 - 0
cli/src/userioman.cpp

@@ -22,10 +22,18 @@ bool UserIoMan::handleJson(Json::Value root) {
 	return false;
 }
 
+void UserIoMan::printNormalMessage(std::string msg) {
+	std::cout << msg << std::endl;
+}
+
 void UserIoMan::printErrorMessage(std::string msg) {
 	std::cout << msg << std::endl;
 }
 
+void UserIoMan::printDebugMessage(std::string msg) {
+	std::cerr << msg << std::endl;
+}
+
 void UserIoMan::printWelcomeMessage() {
 	std::cout << "please enter user and password" << std::endl;
 }