int main() { ::SetConsoleTitle("ClientHandler"); Show::attach(&std::cout); Show::start(); Show::title("\n ClientHandler Server started"); BlockingQueue<HttpMessage> msgQ; SocketSystem ss; SocketListener sl(8080, Socket::IP6); ClientHandler cp(msgQ); sl.start(cp); try { while (true) { HttpMessage msg = msgQ.deQ(); std::cout << "\n\n clienthandler " + msg.findValue("toAddr") + " recvd message contents:\n " + msg.bodyString() + "\n from client " + msg.findValue("fromAddr") + "\n"; if (msg.bodyString() == "closeServer") { ::Sleep(100); } } } catch (std::exception& exc) { Show::write("\n Exeception caught: "); std::string exMsg = "\n " + std::string(exc.what()) + "\n\n"; Show::write(exMsg); } std::cout << "\n\n"; return 0; }
// ------------------------------------ Starts Receiver for the this component --------------------------- void Server::startReceiverThread() { BlockingQueue<HttpMessage> msgQ; try { SocketSystem ss; SocketListener sl(getServerPort(), Socket::IP6); Receiver cp(msgQ,"Server"); sl.start(cp); /* * Since this is a server the loop below never terminates. * We could easily change that by sending a distinguished * message for shutdown. */ while (true) { HttpMessage msg = msgQ.deQ(); std::string cPort = msg.findValue("From-Port"); if (msg.attributes()[0].first == "GET") { // Checks if its an file extraction request std::string filename = msg.findValue("file"); Show::write("\n\n Client @: "+cPort+ " => requested file :: " + filename); sendServerFiles(msg); } else Show::write("\n\n Message from client @:"+cPort +" => " + msg.bodyString()); } } catch (std::exception& exc) { Show::write("\n Exeception caught: "); std::string exMsg = "\n " + std::string(exc.what()) + "\n\n"; Show::write(exMsg); } }
//receriveFile void MsgClient::receiveFile(Socket& socket) { HttpMessage msg; while (true) { std::string attribString = socket.recvString('\n'); if (attribString.size() > 1) { HttpMessage::Attribute attrib = HttpMessage::parseAttribute(attribString); msg.addAttribute(attrib); } else { break; } } std::string filename = msg.findValue("file"); if (filename != "") { size_t contentSize; std::string sizeString = msg.findValue("content-length"); if (sizeString != "") contentSize = Converter<size_t>::toValue(sizeString); downloadFile(filename, contentSize, socket); Show::write("Client download file "+filename + "\n"); } }
// -----------------< prepare error message >-------------------- HttpMessage ClientHandler::errorMessage(HttpMessage msg, std::string body) { HttpMessage message; message.addAttribute(HttpMessage::attribute("type", "error")); message.addAttribute(HttpMessage::attribute("fromAddr", msg.findValue("toAddr"))); message.addAttribute(HttpMessage::attribute("toAddr", msg.findValue("fromAddr"))); message.addBody(body); return message; }
// ------------------< prepare and send message to recepient >------------- void ClientHandler::sendMessage(HttpMessage msg) { HttpMessage message; Sender sndr(msg.findValue("fromAddr")); sndr.start(); message = sndr.makeMessage(0, msg.bodyString(), msg.findValue("toAddr")); sndr.postMessage(message); sndr.postMessage(sndr.makeMessage(0, "closeServer", msg.findValue("toAddr"))); sndr.postMessage(sndr.makeMessage(0, "quit", msg.findValue("toAddr"))); sndr.wait(); }
// --------------< save the file to the clients machine >------------------ void ClientHandler::saveFileClient(HttpMessage msg, Socket& socket) { std::string filename = msg.findValue("file").substr(msg.findValue("file").find_last_of("/") + 1); std::string path = "../TestFileClient/"; FileSystem::Directory::create(path); size_t contentSize; std::string sizeString = msg.findValue("content-length"); if (sizeString != "") contentSize = Converter<size_t>::toValue(sizeString); else return; readFile(filename, contentSize, socket, path); }
// ----------------< get the list of files in a specified package >------------- HttpMessage ClientHandler::getFileNameList(HttpMessage msg) { std::vector<std::string> fileList = FileSystem::Directory::getFiles("../TestFileServer/" + msg.findValue("dir")); std::string body = ""; for (size_t i = 0; i < fileList.size(); ++i) if (fileList[i] != "." && fileList[i] != "..") body += "\n " + fileList[i]; body += "\n"; HttpMessage message; message.addAttribute(HttpMessage::attribute("fromAddr", msg.findValue("toAddr"))); message.addAttribute(HttpMessage::attribute("toAddr", msg.findValue("fromAddr"))); message.addAttribute(HttpMessage::attribute("type", "returnList")); message.addBody(body); return message; }
// -------------< establish client handler and start receiving messages >-------------- void Receiver::start() { ClientHandler ch(rcvrQ); size_t port = stoi(localUrl.substr(localUrl.find(":") + 1, 4)); SocketSystem ss; SocketListener sl(port, Socket::IP6); sl.start(ch); while (true) { HttpMessage msg = rcvrQ.deQ(); std::cout << "\n\n " + msg.findValue("toAddr") + " recvd message contents:\n " + msg.bodyString() + "\n from " + msg.findValue("fromAddr"); if (msg.bodyString() == "closeServer") break; } }
// ---------------< construct a general message to be sent as acknowledgement >--------- HttpMessage ClientHandler::constructMessage(HttpMessage msg) { msg.removeAttribute("content-length"); std::string bodyString = "<file>" + msg.findValue("file") + "</file>"; std::string sizeString = Converter<size_t>::toString(bodyString.size()); msg.addAttribute(HttpMessage::Attribute("content-length", sizeString)); msg.addBody(bodyString); return msg; }
// -----------------< get the requested files, with or without dependencies >------------ HttpMessage ClientHandler::getFiles(HttpMessage msg, std::string type) { HttpMessage message; if (!FileSystem::Directory::exists("../TestFileServer/" + msg.bodyString())) return errorMessage(msg, "\n no package " + msg.bodyString()); std::string path = "../TestFileServer/" + msg.bodyString() + "/"; std::vector<std::string> files = FileSystem::Directory::getFiles(path, "*.ver*"); if (files.size() == 0) return errorMessage(msg, "\n so files in package " + msg.bodyString()); std::vector<std::string> sendFiles; for (int i = files.size() - 1; i >= 0; --i) { // figure out the latest version of the files std::string ext = files[i].substr(files[i].find_last_of(".") + 1); if (ext == "xml") continue; std::string name = files[i].substr(0, files[i].find_last_of(".")); if (find(sendFiles, name) == sendFiles.size()) sendFiles.push_back(files[i]); // add only unique file names to be sent } std::vector<std::shared_ptr<AbstractXmlElement>> deps; if (type == "FileWithDeps") { // figure out dependencies of files to be sent for (int i = 0; i < sendFiles.size(); ++i) { std::string file = sendFiles[i]; if (!FileSystem::File::exists("../TestFileServer/" + msg.bodyString() + "/" + file)) continue; std::string xmlname = "../TestFileServer/" + msg.bodyString() + "/" + file + ".xml"; XmlDocument doc(xmlname, XmlDocument::file); deps = doc.element("deps").descendents().select(); for (auto dep : deps) if (dep->tag() == "") { // prevent circular dependencies to be stuck in a loop std::string depName = dep->value().substr(0, dep->value().find("\n")); if (find(sendFiles, depName.substr(0, depName.find_last_of("."))) == sendFiles.size()) sendFiles.push_back(depName); } } } std::string body; for (size_t i = 0; i < sendFiles.size() - 1; ++i) body += sendFiles[i] + ","; body += sendFiles[sendFiles.size() - 1]; message.addAttribute(HttpMessage::attribute("fromAddr", msg.findValue("toAddr"))); message.addAttribute(HttpMessage::attribute("toAddr", msg.findValue("fromAddr"))); message.addAttribute(HttpMessage::attribute("type", "returnFiles")); message.addBody(body); return message; }
// -------------------- This Function sends the requested file to the client and checks if the dependencies need to be sent-------------------- void Server::sendServerFiles(HttpMessage msg) { SocketSystem ss; SocketConnecter si; std::string cPort = msg.findValue("From-Port"); int ClientPort = Converter<int>::toValue(cPort); while (!si.connect("localhost", ClientPort)) { ::Sleep(100); } // Searches for the revlevant folder and then sends the file Sender send; std::string DepsFlag = msg.findValue("ExtractWithDepsFlag"); std::string fileToSend = msg.findValue("file"); std::string path; std::vector<std::string> dirs = FileSystem::Directory::getDirectories("./ServerDrive", fileToSend+"*"); if (dirs.size() == 0) Show::write("No such file present in the repository => " + fileToSend + "\n"); if (dirs.size() == 1) { std::vector<std::string> files = FileSystem::Directory::getFiles("./ServerDrive/" + dirs[0], fileToSend + "*"); Show::write("\n Sending File :: " + files[0] + " to Client @: " + cPort); send.sendFile("./ServerDrive/" + dirs[0] + "/" + files[0], si, getServerPort(), ClientPort); path = "./ServerDrive/" + dirs[0] + "/"; if (DepsFlag == "Yes") sendFileDependencies(msg, path,si); } if (dirs.size() > 1) { std::string latest_dir = getLatestDir(dirs,fileToSend); std::vector<std::string> files = FileSystem::Directory::getFiles("./ServerDrive/" + latest_dir, fileToSend + "*"); Show::write("\n Sending File :: " + files[0] + " to Client @: " + cPort); send.sendFile("./ServerDrive/" + latest_dir + "/" + files[0], si , getServerPort(), ClientPort); path = "./ServerDrive/" + latest_dir + "/"; if (DepsFlag == "Yes") sendFileDependencies(msg, path,si); } msg = makeMessage(1, "quit", "toAddr:localhost:"+cPort); send.sendMessage(msg, si); }
// -------------------- This Function sends the Dependent files to the client-------------------- void Server::sendFileDependencies(HttpMessage msg, std::string path, Socket & socket) { std::string cPort = msg.findValue("From-Port"); int ClientPort = Converter<int>::toValue(cPort); std::string requestedFile = msg.findValue("file"); Sender send; std::vector<std::string> depFile = FileSystem::Directory::getFiles(path, "*.xml"); std::string src = path + depFile[0]; XmlParser parser(src); XmlDocument* pDoc = parser.buildDocument(); std::vector<std::string> depFileNames; std::vector<sPtr> found = pDoc->element("Dependencies").descendents().select(); // Read the dependencies xml if (found.size() > 0) { for (auto pElem : found) { if (pElem->value() != "dep") depFileNames.push_back(pElem->value()); } } for (std::string f : depFileNames) { // Sending each of the dependency file if exists std::string fileToSend = Utilities::StringHelper::trim(f); std::vector<std::string> dirs = FileSystem::Directory::getDirectories("./ServerDrive/", fileToSend +"*"); if (dirs.size() == 0) Show::write("No such file present in the repository => " + fileToSend + "\n"); if (dirs.size() > 0) { std::string latest_dir = getLatestDir(dirs, fileToSend); std::vector<std::string> files = FileSystem::Directory::getFiles("./ServerDrive/" + latest_dir, fileToSend + "*"); Show::write("\nSending Dependency File of "+ requestedFile+ " => " + files[0] + " to client @: "+cPort); send.sendFile("./ServerDrive/" + latest_dir + "/" + files[0], socket , getServerPort(), ClientPort); path = "./ServerDrive/" + latest_dir + "/"; } } msg = makeMessage(1, "quit", "toAddr:localhost:"+cPort); send.sendMessage(msg, socket); }
HttpMessage MsgClient::readMessage(Socket& socket) { Show::write("Client readMessage \n"); //connectionClosed_ = false; HttpMessage msg; //read attribute while (true) { std::string attribString = socket.recvString('\n'); if (attribString.size() > 1) { HttpMessage::Attribute attrib = HttpMessage::parseAttribute(attribString); msg.addAttribute(attrib); } else { break; } } if (msg.attributes().size() == 0) { return msg; } if (msg.attributes()[0].first == "POST") { std::string filePath = msg.findValue("filePath"); if (filePath != "") { Show::write("Test for get FolderList"); size_t numBytes = 0; size_t pos = msg.findAttribute("content-length"); if (pos < msg.attributes().size()) { numBytes = Converter<size_t>::toValue(msg.attributes()[pos].second); Socket::byte* buffer = new Socket::byte[numBytes + 1]; socket.recv(numBytes, buffer); buffer[numBytes] = '\0'; std::string msgBody(buffer); msg.addBody(msgBody); Show::write("getFolderList:" + msgBody + "\n"); } } } return msg; }
//----< receiver functionality is defined by this function >--------- void ClientHandler::operator()(Socket socket) { std::function<void()> threadProc = [&]() { while (true) { HttpMessage msg = readMessage(socket); // read a message from socket if (msg.attributes().size() == 0 || msg.bodyString() == "quit") break; if (msg.findValue("type") == "returnList") { sendMessage(msg); continue; } else if (msg.findValue("type") == "returnFiles") { Sender sndr(msg.findValue("fromAddr")); sndr.start(); std::vector<std::string> files = splitString(msg.bodyString()); for (std::string file : files) { std::string fileSpec = searchFile(file); FileSystem::FileInfo fi(fileSpec); FileSystem::File fileIn(fileSpec); fileIn.open(FileSystem::File::in, FileSystem::File::binary); if (!fileIn.isGood()) { std::cout << "\n could not open file " << file; continue; } size_t fileSize = fi.size(); std::string sizeString = Converter<size_t>::toString(fileSize); HttpMessage message = sndr.makeMessage(4, "", msg.findValue("toAddr")); message.addAttribute(HttpMessage::Attribute("file", fileSpec)); message.addAttribute(HttpMessage::Attribute("content-length", sizeString)); sndr.postMessage(message); } sndr.postMessage(sndr.makeMessage(0, "closeServer", msg.findValue("toAddr"))); sndr.postMessage(sndr.makeMessage(0, "quit", msg.findValue("toAddr"))); sndr.wait(); continue; } else if (msg.attributes()[0].second == "error") { sendMessage(msg); continue; } msgQ_.enQ(msg); } }; std::thread receiveThread(threadProc); receiveThread.join(); }
// -----------< save a file to the server >--------------- void ClientHandler::saveFileServer(HttpMessage msg, Socket& socket) { FileSystem::Directory::create("../TestFileServer/"); std::string filename = msg.findValue("file") + ".ver1"; std::string packageName = msg.findValue("dir") + "." + getCurrentDate(); std::string path = "../TestFileServer/" + packageName + "/"; FileSystem::Directory::create(path); std::string dependencies = msg.findValue("deps"); std::vector<std::string> deps; if(dependencies != "") deps = findDeps(dependencies); std::vector<std::string> files; for (auto fileSpec : FileSystem::Directory::getFiles(path, msg.findValue("file") + ".ver*")) if (fileSpec.substr(fileSpec.find_last_of(".")) != ".xml") files.push_back(fileSpec); if (files.size() > 0) { std::string name = files[files.size() - 1]; int ver = std::stoi(name.substr(name.find_last_of(".") + 4)); filename = msg.findValue("file") + ".ver" + std::to_string(ver + 1); } std::string xmlpath = path + filename + ".xml"; XmlDocument doc = builDocument(filename, deps); FileSystem::File file(xmlpath); file.open(FileSystem::File::out, FileSystem::File::text); if (file.isGood()) file.putLine(doc.toString()); file.close(); size_t contentSize; std::string sizeString = msg.findValue("content-length"); if (sizeString != "") contentSize = Converter<size_t>::toValue(sizeString); else return; readFile(filename, contentSize, socket, path); updateXML(packageName, msg.findValue("file"), deps); }
// ----------------< close a package to prevent addditional updating >------------- HttpMessage ClientHandler::closePackage(HttpMessage msg) { HttpMessage message; if (!FileSystem::Directory::exists("../TestFileServer/" + msg.findValue("dir"))) { message.addAttribute(HttpMessage::attribute("type", "error")); message.addAttribute(HttpMessage::attribute("fromAddr", msg.findValue("toAddr"))); message.addAttribute(HttpMessage::attribute("toAddr", msg.findValue("fromAddr"))); std::string str = "\n no package with the name " + msg.findValue("dir"); message.addBody(str); return message; } std::string name = "../TestFileServer/" + msg.findValue("dir") + "/" + msg.findValue("dir") + "." + getCurrentDate() + ".xml"; XmlDocument doc(name, XmlDocument::file); sPtr close = makeTaggedElement("close"); close->addChild(makeTextElement("true")); doc.xmlRoot()->addChild(close); FileSystem::File::remove(name); FileSystem::File xml(name); xml.open(FileSystem::File::out, FileSystem::File::text); if (xml.isGood()) xml.putLine(doc.toString()); xml.close(); return message; }
// --------------< construct a message based on custom body string >---------------- HttpMessage ClientHandler::constructMessage(HttpMessage msg, std::string body) { Sender sndr(msg.findValue("toAddr")); HttpMessage message = sndr.makeMessage(0, body, msg.findValue("fromAddr")); return message; }