Quellcode durchsuchen

implement useriomanager get/put

Denys vor 5 Jahren
Ursprung
Commit
9a44deebc0
1 geänderte Dateien mit 293 neuen und 77 gelöschten Zeilen
  1. 293 77
      cli/src/useriomanager.cpp

+ 293 - 77
cli/src/useriomanager.cpp

@@ -1,11 +1,17 @@
 #include "../include/useriomanager.hpp"
 #include "../include/commands.hpp"
+#include "../include/base64.hpp"
 
 #include <iostream>
+#include <fstream>
+#include <vector>
+#include <boost/algorithm/string.hpp>
 
 #include <readline/history.h>
 #include <readline/readline.h>
 
+#define BLOCKSIZE 8
+
 using boost::asio::buffer;
 
 void UserIoManager::run() {
@@ -13,7 +19,10 @@ void UserIoManager::run() {
 
   bool keep_reading = true;
   COMMANDID cmd;
+  
   char *line = NULL;
+  std::vector<std::string> tokens;
+  
   while (keep_reading) {
     free(line);
 
@@ -24,88 +33,295 @@ void UserIoManager::run() {
     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);
-
-    cmd = getCmdIdFromString(line);
+    
+    
+    // check for passed command
+    cmd = getCmdIdFromString(tokens[0].c_str());
 
     switch (cmd) {
-    case CMD_STATUS: {
-
-      boost::asio::streambuf recvbuf;
-      Json::Value root, checkok;
-      const char *recvjson;
-
-      // ask for status
-      root["command"] = "status";
-      boost::asio::write(*tcpsock, buffer(Json::writeString(wbuilder, root)),
-                         errcode);
-      if (errcode) {
-        std::cerr << "couldnt send status query to server " << ipstring
-                  << std::endl
-                  << errcode.message() << std::endl;
-        keep_reading = false;
-        continue;
-      }
-
-      // recieve answer to status query
-      boost::asio::read(*tcpsock, recvbuf, boost::asio::transfer_at_least(1),
-                        errcode);
-      if (errcode && errcode != boost::asio::error::eof) {
-        std::cerr << "couldnt recieve status from " << ipstring << std::endl
-                  << errcode.message() << std::endl;
-        keep_reading = false;
-        continue;
-      }
-
-      // parse json
-      recvjson = boost::asio::buffer_cast<const char *>(recvbuf.data());
-      if (!reader->parse(recvjson, recvjson + recvbuf.size(), &root,
-                         &jsonerror)) {
-        std::cerr << "couldnt parse recieved json" << std::endl
-                  << jsonerror << std::endl;
-        keep_reading = false;
-        continue;
-      }
-
-      // remove processed data from recvbuf
-      recvbuf.consume(recvbuf.size());
-
-      // check if received answer to right query
-      checkok = root["command"];
-
-      if (checkok.asString().compare("status") != 0) {
-        std::cerr << "command check failed. client sent command \"status\""
-                  << std::endl
-                  << "server replied to command \"" << checkok << "\""
-                  << std::endl;
-        keep_reading = false;
-        continue;
-      } else {
-        std::cout << "server replied with status: " << root["response"]
-                  << std::endl;
-      }
-
-      break;
-    }
-    case CMD_DISCONNECT: {
-      std::printf("disconnecting\n");
-      keep_reading = false;
-      break;
-    }
-    default: {
-      std::printf("unknown command %s\n", line);
-    }
-    case CMD_HELP: {
-      std::printf("\n");
-      std::printf("AVAILABLE COMMANDS are:\n");
-      // printCmds();
-      std::printf("help        - shows this help\n");
-      std::printf("status      - asks the server for status\n");
-      std::printf("disconnect  - closes the connection to the server\n");
-      break;
-    }
+	    case CMD_STATUS: {
+
+	      boost::asio::streambuf recvbuf;
+	      Json::Value root, checkok;
+	      const char *recvjson;
+
+	      // ask for status
+	      root["command"] = "status";
+	      boost::asio::write(*tcpsock, buffer(Json::writeString(wbuilder, root)),
+		                 errcode);
+	      if (errcode) {
+		std::cerr << "couldnt send status query to server " << ipstring
+		          << std::endl
+		          << errcode.message() << std::endl;
+		keep_reading = false;
+		continue;
+	      }
+
+	      // recieve answer to status query
+	      boost::asio::read(*tcpsock, recvbuf, boost::asio::transfer_at_least(1),
+		                errcode);
+	      if (errcode && errcode != boost::asio::error::eof) {
+		std::cerr << "couldnt recieve status from " << ipstring << std::endl
+		          << errcode.message() << std::endl;
+		keep_reading = false;
+		continue;
+	      }
+
+	      // parse json
+	      recvjson = boost::asio::buffer_cast<const char *>(recvbuf.data());
+	      if (!reader->parse(recvjson, recvjson + recvbuf.size(), &root,
+		                 &jsonerror)) {
+		std::cerr << "couldnt parse recieved json" << std::endl
+		          << jsonerror << std::endl;
+		keep_reading = false;
+		continue;
+	      }
+
+	      // remove processed data from recvbuf
+	      recvbuf.consume(recvbuf.size());
+
+	      // check if received answer to right query
+	      checkok = root["command"];
+
+	      if (checkok.asString().compare("status") != 0) {
+		std::cerr << "command check failed. client sent command \"status\""
+		          << std::endl
+		          << "server replied to command \"" << checkok << "\""
+		          << std::endl;
+		keep_reading = false;
+		continue;
+	      } else {
+		std::cout << "server replied with status: " << root["response"]
+		          << std::endl;
+	      }
+
+	      break;
+	    }
+	    case CMD_PUT: {
+	    	
+	    	boost::asio::streambuf recvbuf;
+	    	Json::Value root, ackRecv;
+	    	
+	    	std::fstream fs;
+	    	fs.open(tokens[1].c_str(), std::fstream::in | std::fstream::binary);
+	    	
+	    	// determine file size
+	    	fs.seekg(0, fs.end);
+	    	int filelen = fs.tellg();
+	    	fs.seekg(0, fs.beg);
+	    	
+	    	// determine file name
+	    	std::vector<std::string> path;
+	    	boost::algorithm::split(path, tokens[1], boost::algorithm::is_any_of("/"), boost::algorithm::token_compress_on);
+	    	std::string filename = path.back();
+	    	
+	    	
+	    	// send first query to server
+	    	root["command"] = "put";
+		root["file"] = filename;
+		root["size"] = filelen;
+	    	
+	    	std::cout << root << std::endl;
+	    	
+	    	if(!sendJson(root)){
+	    		keep_reading = false;
+			continue;
+	    	}
+	    	std::cout << "sent request to server " << ipstring << std::endl;
+	    	
+	    	if(!receiveJson(recvbuf)){
+	    		keep_reading = false;
+			continue;
+	    	}
+	    	if(!parseJson(&root, recvbuf)){
+	    		std::cerr << "received invalid JSON from server" << std::endl;
+	    		keep_reading = false;
+			continue;
+	    	}
+	    	
+	    	std::cout << root << std::endl;
+	    	
+	    	if(!root["accept"].asBool()){
+	    		std::cerr << "server did not accept request" << std::endl;
+	    		keep_reading = false;
+			continue;
+	    	}
+	    	
+	    	std::cout << "request successful, beginning to send file to " << ipstring << std::endl;
+	    	
+	    	
+	    	// determine number of chunks
+	    	int size_remainder = filelen % BLOCKSIZE;
+	    	int chunks = filelen / BLOCKSIZE + ((size_remainder > 0)?1:0);
+	    	
+	    	char readbuf[BLOCKSIZE];
+	    	
+	    	// send file
+	    	root = Json::Value();
+	    	root["command"] = "put";
+		root["cancel"] = false;
+	    	
+	    	
+	    	while(chunks > 0){
+	    		chunks--;
+	    		if(!chunks & (size_remainder != 0)) { // size_remainder is the size of the last chunk if it's not 0
+	    			fs.read(readbuf, size_remainder);
+	    			root["data"] = base64::encodeVector(std::vector<char>(readbuf, readbuf+size_remainder*sizeof(char)));
+	    		} else { // not last chunk or last chunk has full length
+	    			fs.read(readbuf, BLOCKSIZE);
+	    			root["data"] = base64::encodeVector(std::vector<char>(readbuf, readbuf+BLOCKSIZE*sizeof(char)));
+	    		}
+	    		root["remaining"] = chunks;
+	    		
+	    		std::cout << root << std::endl;
+	    		
+	    		if(!sendJson(root)){
+	    			std::cerr << "couldn't send file, " << chunks+1 << " chunks not sent" << std::endl;
+	    			keep_reading = false;
+				continue;
+	    		}
+	    		
+	    		if(!receiveJson(recvbuf)){
+	    			continue;
+	    		}
+	    		if(!parseJson(&ackRecv, recvbuf)){
+		    		std::cerr << "received invalid JSON from server" << std::endl;
+				continue;
+		    	}
+		    	// TODO: check for cancel answer
+		    	
+	    	}
+	    	
+	    	fs.close();
+	    	std::cout << "successfully sent file to " << ipstring << std::endl;
+	    	
+	    	break;
+	    	
+	    }
+	    case CMD_GET: {
+	    	
+	    	
+	    	boost::asio::streambuf recvbuf;
+	    	Json::Value root, recvAck;
+	    		    	
+	    	// send first query to server
+	    	root["command"] = "get";
+		root["file"] = tokens[1];
+	    	
+	    	std::cout << root << std::endl;
+	    	
+	    	if(!sendJson(root)){
+	    		keep_reading = false;
+			continue;
+	    	}
+	    	std::cout << "sent request to server " << ipstring << std::endl;
+	    	
+	    	if(!receiveJson(recvbuf)){
+	    		keep_reading = false;
+			continue;
+	    	}
+	    	if(!parseJson(&root, recvbuf)){
+	    		std::cerr << "received invalid JSON from server" << std::endl;
+	    		keep_reading = false;
+			continue;
+	    	}
+	    	
+	    	std::cout << root << std::endl;
+	    	
+	    	if(!root["accept"].asBool()){
+	    		std::cerr << "server did not accept request" << std::endl;
+	    		keep_reading = false;
+			continue;
+	    	}
+	    	
+	    	std::cout << "request successful, beginning to receive file from " << ipstring << std::endl;
+	    	
+	    	// open file stream
+	    	std::fstream fs;
+	    	fs.open(tokens[1].c_str(), std::fstream::out | std::fstream::trunc | std::fstream::binary);
+	    	std::vector<char> writebuf;
+	    	
+	    	// number of remaining chunks, dummy value to entry loop
+	    	int remaining = std::numeric_limits<int>::max();
+	    	int recvCount = 0;
+	    	
+	    	std::cout << "foobar" << std::endl;
+	    	
+	    	while(remaining > 0){
+	    	
+	    		std::cout << "foobar0" << std::endl;
+	    		
+	    		if(!receiveJson(recvbuf)){
+		    		keep_reading = false;
+		    		
+		    		std::cout << "fail1" << std::endl;
+		    		
+				continue;
+		    	}
+		    	
+		    	std::cout << "foobar1" << std::endl;
+		    	
+		    	if(!parseJson(&root, recvbuf)){
+		    		std::cerr << "received invalid JSON from server" << std::endl;
+		    		keep_reading = false;
+				continue;
+		    	}
+		    	std::cout << "foobar2" << std::endl;
+		    	std::cout << root << std::endl;
+		    	
+		    	if(root["cancel"].asBool()){
+		    		std::cerr << "server cancelled recieving file" << std::endl;
+		    		keep_reading = false;
+				continue;
+		    	}
+		    	
+		    	writebuf = base64::decodeVector(root["data"].asString());
+		    	fs.write(writebuf.data(), writebuf.size());
+			remaining = root["remaining"].asInt();
+			
+			std::cout << "remaining == " << remaining << std::endl;
+		    	
+		    	recvAck["received"] = recvCount++;
+		    	
+		    	if(!sendJson(recvAck)){
+		    		continue;
+		    	}
+			
+	    	
+	    	}
+	    	
+	    	fs.close();
+	    	break;
+	    	
+	    }
+	    case CMD_DISCONNECT: {
+	      std::printf("disconnecting\n");
+	      keep_reading = false;
+	      break;
+	    }
+	    default: {
+	      std::printf("unknown command %s\n", line);
+	    }
+	    case CMD_HELP: {
+	      std::printf("\n");
+	      std::printf("AVAILABLE COMMANDS are:\n");
+	      printCmds(); // TODO: implement to have put and get in here
+	      std::printf("help        - shows this help\n");
+	      std::printf("status      - asks the server for status\n");
+	      std::printf("disconnect  - closes the connection to the server\n");
+	      break;
+	    }
     }
     std::printf("\n");
   }