diff options
-rw-r--r-- | commands.cpp | 45 | ||||
-rw-r--r-- | commands.h | 24 | ||||
-rw-r--r-- | main.cpp | 2 | ||||
-rw-r--r-- | music.cpp | 8 | ||||
-rw-r--r-- | music.h | 1 | ||||
-rw-r--r-- | telnet_connection.cpp | 66 | ||||
-rw-r--r-- | telnet_connection.h | 4 |
7 files changed, 149 insertions, 1 deletions
diff --git a/commands.cpp b/commands.cpp new file mode 100644 index 0000000..dfeeebb --- /dev/null +++ b/commands.cpp @@ -0,0 +1,45 @@ +#include "commands.h" +#include "music.h" + +#include <boost/cast.hpp> + +#include <iostream> + +static std::vector<std::string> ls(const std::vector<std::string>& args) { + if(args.size() != 2) { + throw commands::CommandException("usage: ls DIR"); + } + + MusicListing::p ml = music::get(args[1]); + if(!ml || !fs::is_directory(ml->path)) { + throw commands::CommandException("no such directory"); + } + std::vector<std::string> result; + MusicDirectory *dir = boost::polymorphic_downcast<MusicDirectory*>(&(*ml)); + for(MusicDirectory::PathListings::iterator it = dir->directories.begin(); it != dir->directories.end(); it++) { + std::string rel_path = it->string().substr(music::root_directory.string().size()); + result.push_back(rel_path); + } + for(MusicDirectory::PathListings::iterator it = dir->tracks.begin(); it != dir->tracks.end(); it++) { + std::string rel_path = it->string().substr(music::root_directory.string().size()); + result.push_back(rel_path); + } + + return result; +} + +std::map<std::string, commands::Handler> commands::handlers; + +void commands::init() { + handlers["ls"] = ls; +} + +std::vector<std::string> commands::execute(const std::vector<std::string>& args) { + assert(args.size()); + Handler h = commands::handlers[args[0]]; + if(!h) { + throw CommandException("unknown command"); + } + + return h(args); +} diff --git a/commands.h b/commands.h new file mode 100644 index 0000000..bc4092f --- /dev/null +++ b/commands.h @@ -0,0 +1,24 @@ +#ifndef COMMANDS_H +#define COMMANDS_H + +#include <boost/function.hpp> + +#include <string> +#include <vector> +#include <map> +#include <stdexcept> + +namespace commands { + typedef boost::function<std::vector<std::string> (const std::vector<std::string>&)> Handler; + extern std::map<std::string, commands::Handler> handlers; + + class CommandException : public std::runtime_error { + public: + CommandException(const char *s) : std::runtime_error(s) {}; + }; + + void init(); + std::vector<std::string> execute(const std::vector<std::string>& args); +}; + +#endif @@ -4,6 +4,7 @@ #include "encoder.h" #include "httpd.h" #include "telnetd.h" +#include "commands.h" #include <iostream> #include <vector> @@ -16,6 +17,7 @@ int main(int argc, char **argv) { music::init(config::vm["audist.music_root"].as<std::string>()); decoder::init(); encoder::init(); + commands::init(); boost::asio::io_service io_service; @@ -7,6 +7,8 @@ #include <boost/format.hpp> #include <boost/algorithm/string/predicate.hpp> +#include <boost/algorithm/string/classification.hpp> +#include <boost/algorithm/string/split.hpp> #include <boost/filesystem/fstream.hpp> #include <soci/soci.h> @@ -49,6 +51,12 @@ MusicListing::p music::get(const std::vector<std::string>& path) { return MusicListing::p(); } +MusicListing::p music::get(const std::string& path) { + std::vector<std::string> path_vector; + boost::algorithm::split(path_vector, path, boost::algorithm::is_any_of("/\\")); + return get(path_vector); +} + std::vector<MusicListing::p> music::find_artist(const std::string artist) { soci::session sql(config::vm["audist.database"].as<std::string>()); @@ -37,6 +37,7 @@ namespace music { extern fs::path root_directory; void init(std::string root); MusicListing::p get(const std::vector<std::string>& path); + MusicListing::p get(const std::string& path); std::vector<MusicListing::p> find_artist(const std::string artist); }; diff --git a/telnet_connection.cpp b/telnet_connection.cpp index e2ea96f..457d1ba 100644 --- a/telnet_connection.cpp +++ b/telnet_connection.cpp @@ -1,12 +1,76 @@ #include "telnet_connection.h" +#include "commands.h" #include <boost/bind.hpp> +#include <boost/algorithm/string.hpp> +#include <boost/algorithm/string/regex.hpp> +#include <boost/format.hpp> + +#include <iostream> telnet::Connection::Connection(boost::asio::io_service& io_service) : socket(io_service) { } void telnet::Connection::handle_read(const boost::system::error_code& error, size_t bytes_transferred) { - boost::asio::write(socket, buf); + if(error) { + return; + } + + std::string line; + std::istream is(&buf); + std::getline(is, line); + boost::trim(line); + + if(line == "exit") { + return; + } + + std::vector<std::string> args = parse_args(line); + // no arguments, i.e. empty line + if(!args.size()) { + start(); + return; + } + + std::vector<std::string> r; + try { + r = commands::execute(args); + } catch(commands::CommandException& ce) { + std::string s(ce.what()); + s += '\n'; + boost::asio::write(socket, boost::asio::buffer(s)); + start(); + return; + } + + for(std::vector<std::string>::iterator it = r.begin(); it != r.end(); it++) { + boost::asio::write(socket, boost::asio::buffer(*it + "\n")); + } + + start(); +} + +std::vector<std::string> telnet::Connection::parse_args(std::string& line) { + std::string::const_iterator begin = line.begin(); + std::string::const_iterator end = line.end(); + + boost::regex re("(\")?((?(1)[^\"]|[^ ])+)(?(1)\")"); + boost::match_results<std::string::const_iterator> what; + boost::match_flag_type flags = boost::match_default; + + std::vector<std::string> args; + + while(boost::regex_search(begin, end, what, re, flags)) { + std::string s = std::string(what[2].first, what[2].second); + boost::algorithm::trim(s); + // avoid empty strings when parsing multi-word arguments (a "b c") + if(s.size()) { + args.push_back(s); + } + begin = what[0].second; + } + + return args; } void telnet::Connection::start() { diff --git a/telnet_connection.h b/telnet_connection.h index 8ea3cad..68d652e 100644 --- a/telnet_connection.h +++ b/telnet_connection.h @@ -4,6 +4,9 @@ #include <boost/asio.hpp> #include <boost/enable_shared_from_this.hpp> +#include <vector> +#include <string> + using boost::asio::ip::tcp; namespace telnet { @@ -13,6 +16,7 @@ namespace telnet { private: Connection(boost::asio::io_service& io_service); void handle_read(const boost::system::error_code& error, size_t bytes_transferred); + std::vector<std::string> parse_args(std::string& line); tcp::socket socket; boost::asio::streambuf buf; |