diff --git a/backends/twitter/TwitterPlugin.cpp b/backends/twitter/TwitterPlugin.cpp index 02bb3e3a..504f9731 100644 --- a/backends/twitter/TwitterPlugin.cpp +++ b/backends/twitter/TwitterPlugin.cpp @@ -85,6 +85,11 @@ TwitterPlugin::TwitterPlugin(Config *config, Swift::SimpleEventLoop *loop, Stora tweet_timer->start(); message_timer->start(); + +#if HAVE_SWIFTEN_3 + cryptoProvider = boost::shared_ptr(Swift::PlatformCryptoProvider::create()); +#endif + LOG4CXX_INFO(logger, "Starting the plugin."); } @@ -438,7 +443,7 @@ bool TwitterPlugin::setTwitterMode(const std::string user, int m) //int type; std::string s_m = std::string(1,m+'0'); - LOG4CXX_ERROR(logger, "Storing mode " << m <<" for user " << user) + LOG4CXX_INFO(logger, "Storing mode " << m <<" for user " << user) storagebackend->updateUserSetting((long)info.id, MODE, s_m); return true; } diff --git a/spectrum_manager/src/CMakeLists.txt b/spectrum_manager/src/CMakeLists.txt index 22be5837..9256eeb8 100644 --- a/spectrum_manager/src/CMakeLists.txt +++ b/spectrum_manager/src/CMakeLists.txt @@ -1,15 +1,15 @@ cmake_minimum_required(VERSION 2.6) FILE(GLOB SRC *.cpp *.c) -ADD_EXECUTABLE(spectrum2_manager ${SRC} ../../libtransport/Config.cpp ../../libtransport/Util.cpp ${CMAKE_CURRENT_SOURCE_DIR}/../../include/transport/protocol.pb.cc) +ADD_EXECUTABLE(spectrum2_manager ${SRC}) ADD_DEPENDENCIES(spectrum2_manager pb) SET_SOURCE_FILES_PROPERTIES(${CMAKE_CURRENT_SOURCE_DIR}/../../include/transport/protocol.pb.cc PROPERTIES GENERATED 1) -target_link_libraries(spectrum2_manager ${SWIFTEN_LIBRARY} ${PROTOBUF_LIBRARIES}) +target_link_libraries(spectrum2_manager transport ${SWIFTEN_LIBRARY} ${PROTOBUF_LIBRARIES}) if(APPLE) -target_link_libraries(spectrum2_manager ${APPLE_FRAMEWORKS}) +target_link_libraries(spectrum2_manager transport ${APPLE_FRAMEWORKS}) endif() INSTALL(TARGETS spectrum2_manager RUNTIME DESTINATION bin) diff --git a/spectrum_manager/src/main.cpp b/spectrum_manager/src/main.cpp index f950450b..f97a853e 100644 --- a/spectrum_manager/src/main.cpp +++ b/spectrum_manager/src/main.cpp @@ -142,7 +142,7 @@ int main(int argc, char **argv) return restart_instances(&config); } else if (command[0] == "server") { - Server server(&config); + Server server(&config, config_file); if (server.start() == false) { std::cerr << "Can't set up server handler.\n"; return 1; diff --git a/spectrum_manager/src/managerconfig.cpp b/spectrum_manager/src/managerconfig.cpp index 0087df9c..c25b1a04 100644 --- a/spectrum_manager/src/managerconfig.cpp +++ b/spectrum_manager/src/managerconfig.cpp @@ -33,8 +33,15 @@ bool ManagerConfig::load(const std::string &configfile, boost::program_options:: ("service.admin_password", value()->default_value(""), "Administrator password.") ("service.port", value()->default_value(8081), "Web interface port.") ("service.config_directory", value()->default_value("/etc/spectrum2/transports/"), "Directory with spectrum2 configuration files. One .cfg file per one instance") - ("service.data_dir", value()->default_value("/var/lib/spectrum2_manager"), "Directory to store Spectrum 2 manager data") + ("service.data_dir", value()->default_value("/var/lib/spectrum2_manager/html"), "Directory to store Spectrum 2 manager data") ("servers.server", value >()->multitoken(), "Server.") + ("database.type", value()->default_value("none"), "Database type.") + ("database.database", value()->default_value("/var/lib/spectrum2/$jid/database.sql"), "Database used to store data") + ("database.server", value()->default_value("localhost"), "Database server.") + ("database.user", value()->default_value(""), "Database user.") + ("database.password", value()->default_value(""), "Database Password.") + ("database.port", value()->default_value(0), "Database port.") + ("database.prefix", value()->default_value(""), "Prefix of tables in database") ; store(parse_config_file(ifs, opts), m_variables); diff --git a/spectrum_manager/src/server.cpp b/spectrum_manager/src/server.cpp index 65152e6d..b255f505 100644 --- a/spectrum_manager/src/server.cpp +++ b/spectrum_manager/src/server.cpp @@ -51,7 +51,7 @@ static void _event_handler(struct mg_connection *nc, int ev, void *p) { static_cast(nc->mgr->user_data)->event_handler(nc, ev, p); } -Server::Server(ManagerConfig *config) { +Server::Server(ManagerConfig *config, const std::string &config_file) { srand((unsigned) time(0)); m_config = config; m_user = CONFIG_STRING(m_config, "service.admin_username"); @@ -80,10 +80,29 @@ Server::Server(ManagerConfig *config) { footer.read(&m_footer[0], m_footer.size()); footer.close(); } + + m_storageCfg = new Config(); + m_storageCfg->load(config_file); + + std::string error; + m_storage = StorageBackend::createBackend(m_storageCfg, error); + if (m_storage == NULL) { + std::cerr << "Error creating StorageBackend! " << error << "\n"; + std::cerr << "Registering new Spectrum 2 manager users won't work" << "\n"; + } + else if (!m_storage->connect()) { + delete m_storage; + m_storage = NULL; + std::cerr << "Can't connect to database!\n"; + } } Server::~Server() { mg_mgr_free(&m_mgr); + if (m_storage) { + delete m_storage; + } + delete m_storageCfg; } bool Server::start() { @@ -95,7 +114,16 @@ bool Server::start() { } bool Server::check_password(const std::string &user, const std::string &password) { - return (m_user == user && m_password == password); + if (m_user == user && m_password == password) { + return true; + } + + UserInfo info; + if (m_storage && m_storage->getUser(user, info) == true && info.password == password) { + return true; + } + + return false; } // Allocate new session object @@ -192,6 +220,25 @@ void Server::print_html(struct mg_connection *conn, struct http_message *hm, con (int) html.size() + m_header.size() + m_footer.size(), m_header.c_str(), html.c_str(), m_footer.c_str()); } +std::string Server::send_command(const std::string &jid, const std::string &cmd) { + Swift::SimpleEventLoop eventLoop; + Swift::BoostNetworkFactories networkFactories(&eventLoop); + + ask_local_server(m_config, networkFactories, jid, cmd); + eventLoop.runUntilEvents(); + struct timeval td_start,td_end; + float elapsed = 0; + gettimeofday(&td_start, NULL); + + time_t started = time(NULL); + while(get_response().empty() && td_end.tv_sec - td_start.tv_sec < 1) { + gettimeofday(&td_end, NULL); + eventLoop.runOnce(); + } + + return get_response(); +} + void Server::serve_onlineusers(struct mg_connection *conn, struct http_message *hm) { std::string html; std::string jid = get_http_var(hm, "jid"); @@ -244,18 +291,80 @@ void Server::serve_cmd(struct mg_connection *conn, struct http_message *hm) { print_html(conn, hm, html); } +void Server::serve_users_add(struct mg_connection *conn, struct http_message *hm) { + std::string user = get_http_var(hm, "user"); + std::string password = get_http_var(hm, "password"); -void Server::serve_start(struct mg_connection *conn, struct http_message *hm) { - std::string html; - std::string jid = get_http_var(hm, "jid"); + if (!user.empty() && !password.empty()) { + UserInfo info; + info.jid = user; + info.password = password; + if (m_storage) { + m_storage->setUser(info); + } + } + redirect_to(conn, hm, "/users"); +} + +void Server::serve_users(struct mg_connection *conn, struct http_message *hm) { + std::string html = "

Spectrum 2 manager users

"; + + html += "

Here, you can add new users who will have access to this web interface. " + "These users will be able to register new accounts on all Spectrum 2 instances " + "running on these server. They won't be able to change any Spectrum 2 instance " + "configuration influencing other users.

"; + + if (!m_storage) { + print_html(conn, hm, html); + return; + } + + html += "
\ +

Add user \ + Add new user to Spectrum 2 manager web interface. \ +

\ + \ + \ + \ +

"; + std::vector users; + m_storage->getUsers(users); + + html += ""; + BOOST_FOREACH(std::string &jid, users) { + html += ""; + html += ""; + html += ""; + html += ""; + } + html += "
UserAction
" + jid + "
"; - start_instances(m_config, jid); - html += "" + get_response() + "
Back to main page"; - html += ""; print_html(conn, hm, html); } -void Server::serve_stop(struct mg_connection *conn, struct http_message *hm) { +void Server::serve_instances_start(struct mg_connection *conn, struct http_message *hm) { + std::string html; + std::string jid = get_http_var(hm, "jid"); + if (jid.empty()) { + redirect_to(conn, hm, "/"); + return; + } + + start_instances(m_config, jid); + html += "

Starting Spectrum 2 instance

"; + html += "" + get_response() + "
Back to main page"; + print_html(conn, hm, html); +} + +void Server::serve_instances_stop(struct mg_connection *conn, struct http_message *hm) { std::string html; std::string jid = get_http_var(hm, "jid"); @@ -264,44 +373,154 @@ void Server::serve_stop(struct mg_connection *conn, struct http_message *hm) { html += ""; print_html(conn, hm, html); } -void Server::serve_root(struct mg_connection *conn, struct http_message *hm) { - std::vector list = show_list(m_config, false); - std::string html = "

List of instances

"; - if (list.empty()) { - html += "

There are no Spectrum 2 instances yet. You can create new instance by adding configuration files into

/etc/spectrum2/transports
directory. You can then maintain the Spectrum 2 instance here.

"; +void Server::serve_instance(struct mg_connection *conn, struct http_message *hm, const std::string &jid) { + std::string html = "

Spectrum 2 instance: " + jid + "

"; + + print_html(conn, hm, html); +} + +void Server::serve_instances_unregister(struct mg_connection *conn, struct http_message *hm) { + +} + +void Server::serve_instances_register(struct mg_connection *conn, struct http_message *hm) { + std::string instance = get_http_var(hm, "instance"); + if (!instance.empty()) { + serve_instance(conn, hm, instance); + return; + } + + std::string jid = get_http_var(hm, "jid"); + std::string uin = get_http_var(hm, "uin"); + std::string password = get_http_var(hm, "password"); + Server:session *session = get_session(hm); + UserInfo info; + m_storage->getUser(session->user, info); + + if (uin.empty() || password.empty()) { + std::string html = "

Register Spectrum 2 instance

"; + html += "
\ +

Register Spectrum 2 instance \ + Write the Slack team name, 3rd-party network username and password. \ +

\ + \ + \ + \ + \ +

"; + print_html(conn, hm, html); } else { - html += ""; - BOOST_FOREACH(std::string &instance, list) { - html += ""; - html += ""; - Swift::SimpleEventLoop eventLoop; - Swift::BoostNetworkFactories networkFactories(&eventLoop); - - ask_local_server(m_config, networkFactories, instance, "status"); - eventLoop.runUntilEvents(); - while(get_response().empty()) { - eventLoop.runUntilEvents(); - } - html += ""; - if (get_response().find("Running") == 0) { - html += ""; - html += ""; - } - else { - html += ""; - html += ""; - } - - html += ""; + std::string response = send_command(jid, "register " + jid + " " + uin + " " + password); + if (!response.empty()) { + std::string value = jid; + int type = (int) TYPE_STRING; + m_storage->updateUserSetting(info.id, jid, value); } + redirect_to(conn, hm, "/instances"); + } - html += "
JIDStatusCommandRun command
" + instance + "" + get_response() + "Stop
"; - html += ""; - html += ""; - html += ""; - html += "
Start
"; +} + +void Server::serve_instances(struct mg_connection *conn, struct http_message *hm) { + std::string jid = get_http_var(hm, "jid"); + if (!jid.empty()) { + serve_instance(conn, hm, jid); + return; + } + + std::vector list = show_list(m_config, false); + std::string html = "

List of Spectrum 2 instances

"; + + Server:session *session = get_session(hm); + + if (session->admin) { + if (list.empty()) { + html += "

There are no Spectrum 2 instances yet. You can create new instance by adding configuration files into

/etc/spectrum2/transports
directory. You can then maintain the Spectrum 2 instance here.

"; + } + else { + html += ""; + BOOST_FOREACH(std::string &instance, list) { + html += ""; + html += ""; + + std::string response = send_command(instance, "status"); + if (response.empty()) { + response = "Cannot get the server status"; + } + + html += ""; + if (response.find("Running") == 0) { + html += ""; + html += ""; + } + else { + html += ""; + html += ""; + } + + html += ""; + } + + html += "
HostnameStatusCommandRun command
" + instance + "" + response + "Stop
"; + html += ""; + html += ""; + html += ""; + html += "
Start
"; + } + } + else { + UserInfo info; + m_storage->getUser(session->user, info); + + if (list.empty()) { + html += "

There are no Spectrum 2 instances yet.

"; + } + else { + html += ""; + BOOST_FOREACH(std::string &instance, list) { + html += ""; + html += ""; + + std::string response = send_command(instance, "status"); + if (response.empty()) { + response = "Cannot get the server status"; + } + + html += ""; + if (response.find("Running") == 0) { + std::string value = ""; + int type = (int) TYPE_STRING; + m_storage->getUserSetting(info.id, instance, type, value); + + if (!value.empty()) { + html += ""; + } + else { + html += ""; + } + } + else { + html += ""; + } + + html += ""; + } + + html += "
HostnameStatusAction
" + instance + "" + response + "UnregisterRegisterNo available action
"; + } } print_html(conn, hm, html); } @@ -318,15 +537,25 @@ void Server::event_handler(struct mg_connection *conn, int ev, void *p) { } else if (mg_vcmp(&hm->uri, "/authorize") == 0) { authorize(conn, hm); } else if (mg_vcmp(&hm->uri, "/") == 0) { - serve_root(conn, hm); + serve_instances(conn, hm); + } else if (mg_vcmp(&hm->uri, "/instances") == 0) { + serve_instances(conn, hm); } else if (mg_vcmp(&hm->uri, "/onlineusers") == 0) { serve_onlineusers(conn, hm); } else if (mg_vcmp(&hm->uri, "/cmd") == 0) { serve_cmd(conn, hm); - } else if (mg_vcmp(&hm->uri, "/start") == 0) { - serve_start(conn, hm); - } else if (mg_vcmp(&hm->uri, "/stop") == 0) { - serve_stop(conn, hm); + } else if (mg_vcmp(&hm->uri, "/instances/start") == 0) { + serve_instances_start(conn, hm); + } else if (mg_vcmp(&hm->uri, "/instances/stop") == 0) { + serve_instances_stop(conn, hm); + } else if (mg_vcmp(&hm->uri, "/instances/register") == 0) { + serve_instances_register(conn, hm); + } else if (mg_vcmp(&hm->uri, "/instances/unregister") == 0) { + serve_instances_unregister(conn, hm); + } else if (mg_vcmp(&hm->uri, "/users") == 0) { + serve_users(conn, hm); + } else if (mg_vcmp(&hm->uri, "/users/add") == 0) { + serve_users_add(conn, hm); } else { mg_serve_http(conn, hm, s_http_server_opts); } diff --git a/spectrum_manager/src/server.h b/spectrum_manager/src/server.h index f20cae66..95973110 100644 --- a/spectrum_manager/src/server.h +++ b/spectrum_manager/src/server.h @@ -31,6 +31,14 @@ #include "mongoose.h" #include "managerconfig.h" +#include "transport/Config.h" +#include "transport/SQLite3Backend.h" +#include "transport/MySQLBackend.h" +#include "transport/PQXXBackend.h" +#include "transport/StorageBackend.h" + +using namespace Transport; + class Server { public: struct session { @@ -42,7 +50,7 @@ class Server { }; /// Constructor. - Server(ManagerConfig *config); + Server(ManagerConfig *config, const std::string &config_file); /// Destructor virtual ~Server(); @@ -52,12 +60,18 @@ class Server { void event_handler(struct mg_connection *nc, int ev, void *p); private: - void serve_root(struct mg_connection *conn, struct http_message *hm); - void serve_start(struct mg_connection *conn, struct http_message *hm); - void serve_stop(struct mg_connection *conn, struct http_message *hm); + void serve_instance(struct mg_connection *conn, struct http_message *hm, const std::string &jid); + void serve_instances(struct mg_connection *conn, struct http_message *hm); + void serve_instances_start(struct mg_connection *conn, struct http_message *hm); + void serve_instances_stop(struct mg_connection *conn, struct http_message *hm); + void serve_instances_register(struct mg_connection *conn, struct http_message *hm); + void serve_instances_unregister(struct mg_connection *conn, struct http_message *hm); + void serve_users(struct mg_connection *conn, struct http_message *hm); + void serve_users_add(struct mg_connection *conn, struct http_message *hm); void serve_onlineusers(struct mg_connection *conn, struct http_message *hm); void serve_cmd(struct mg_connection *conn, struct http_message *hm); void print_html(struct mg_connection *conn, struct http_message *hm, const std::string &html); + std::string send_command(const std::string &jid, const std::string &cmd); private: bool check_password(const std::string &user, const std::string &password); @@ -80,4 +94,6 @@ class Server { ManagerConfig *m_config; std::string m_header; std::string m_footer; + Config *m_storageCfg; + StorageBackend *m_storage; }; diff --git a/spectrum_manager/src/spectrum_manager.cfg b/spectrum_manager/src/spectrum_manager.cfg index d520a467..8ebf8541 100644 --- a/spectrum_manager/src/spectrum_manager.cfg +++ b/spectrum_manager/src/spectrum_manager.cfg @@ -3,6 +3,10 @@ admin_username=admin admin_password=test config_directory=/etc/spectrum2/transports/ +[database] +type=sqlite3 +database=/var/lib/spectrum2_manager/database.sql + [servers] server=localhost #server=icq.spectrum.im diff --git a/tests/twitter/twitter_test.py b/tests/twitter/twitter_test.py index da6b6218..62ce4d8a 100644 --- a/tests/twitter/twitter_test.py +++ b/tests/twitter/twitter_test.py @@ -36,6 +36,7 @@ class Client(sleekxmpp.ClientXMPP): self.tests["friends"] = ["#friends command", False] self.tests["unfollow"] = ["#unfollow command", False] self.tests["friends2"] = ["#friends after unfollow command", False] + self.tests["mode1"] = ["#mode 1", False] self.status = "timeline" self.timestamp = int(time.time()) @@ -60,16 +61,16 @@ class Client(sleekxmpp.ClientXMPP): self.tests["follow"][1] = True self.send_message(mto=msg['from'], mbody="#friends") elif self.status == "friends" and msg['body'].find("USER LIST") != -1 and msg['body'].find("colinpwheeler") != -1: - self.status = "unfollow" - self.tests["friends"][1] = True - self.send_message(mto=msg['from'], mbody="#unfollow colinpwheeler") - elif self.status == "unfollow" and msg['body'] == "You are not following colinpwheeler anymore": - self.status = "friends2" - self.tests["unfollow"][1] = True - self.send_message(mto=msg['from'], mbody="#friends") - elif self.status == "friends2" and msg['body'].find("USER LIST") != -1 and msg['body'].find("colinpwheeler") == -1: - self.tests["friends2"][1] = True - self.finished = True + #self.status = "unfollow" + #self.tests["friends"][1] = True + #self.send_message(mto=msg['from'], mbody="#unfollow colinpwheeler") + #elif self.status == "unfollow" and msg['body'] == "You are not following colinpwheeler anymore": + #self.status = "friends2" + #self.tests["unfollow"][1] = True + #self.send_message(mto=msg['from'], mbody="#friends") + #elif self.status == "friends2" and msg['body'].find("USER LIST") != -1 and msg['body'].find("colinpwheeler") == -1: + #self.tests["friends2"][1] = True + self.send_message(mto=msg['from'], mbody="#mode 1") def start(self, event): self.getRoster()