123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179 |
- #include "server/application.hpp"
- #include <ctime>
- using namespace binom;
- namespace {
- std::string getHostStr(TcpServer::Client& client) {
- uint32_t ip = client.getHost ();
- return std::to_string(int(reinterpret_cast<char*>(&ip)[0])) + '.' +
- std::to_string(int(reinterpret_cast<char*>(&ip)[1])) + '.' +
- std::to_string(int(reinterpret_cast<char*>(&ip)[2])) + '.' +
- std::to_string(int(reinterpret_cast<char*>(&ip)[3])) + ':' +
- std::to_string(client.getPort());
- }
- }
- bool strIsNumber(const std::string& s) {
- return !s.empty() && std::find_if(s.begin(),
- s.end(), [](unsigned char c) { return !std::isdigit(c); }) == s.end();
- }
- int main(int argc, char* argv[]) {Application(argc, argv); return EXIT_SUCCESS;}
- Application::AppIniter Application::processArgs(int argc, char* argv[]) {
- #define ifeq(str_1, str_2) if(isstreq(str_1, str_2))
- #define elifeq(str_1, str_2) else if(isstreq(str_1, str_2))
- if(argc <= 1) return AppIniter{};
- enum class Token {
- flag,
- port,
- db_path,
- name
- }token = Token::flag;
- AppIniter app_init;
- for((--argc, ++argv); argc ;(--argc, ++argv)) {
- switch (token) {
- case Token::flag:
- ifeq(*argv, "--port") {
- token = Token::port;
- } elifeq(*argv, "-p") {
- token = Token::port;
- } elifeq(*argv, "--db-path") {
- token = Token::db_path;
- } elifeq(*argv, "-d") {
- token = Token::db_path;
- } elifeq(*argv, "--name") {
- token = Token::name;
- } elifeq(*argv, "-n") {
- token = Token::name;
- } elifeq(*argv, "--init-db") {
- std::string input;
- std::clog << "Do you rally want to initialize the database?\n"
- "Print \"yes\" if you want initialize the database\n"
- "Other answers will be perceived as no\n"
- "> ";
- std::getline(std::cin, input, '\n');
- app_init.init_db = !strcmp(input.c_str(), "yes");
- }
- continue;
- case Token::port: {
- if(strIsNumber(*argv))
- app_init.server_port = atol(*argv);
- token = Token::flag;
- }continue;
- case Token::db_path:
- app_init.db_path = *argv;
- token = Token::flag;
- continue;
- case Token::name:
- app_init.server_name = *argv;
- token = Token::flag;
- continue;
- }
- }
- return app_init;
- #undef ifeq
- #undef elifeq
- }
- void Application::dataHandler(DataBuffer& data, TcpServer::Client& client) {
- try {
- std::clog << getHostStr(client) << " (sent data of "<< data.size << " bytes)\n";
- char connection_uuid[6];
- *reinterpret_cast<uint32_t*>(connection_uuid) = client.getHost();
- *reinterpret_cast<uint16_t*>(connection_uuid + 4) = client.getPort();
- RequestHandler(db,
- server,
- server_key,
- client,
- Variable::deserialize(ByteArray(data.data_ptr, data.size)),
- db.getRoot()({"session", BufferArray(ValType::byte, connection_uuid, sizeof(connection_uuid))})
- );
- } catch(Exception& e) {
- std::cerr << getHostStr(client) << " (err): " << e.what() << '\n';
- ByteArray result = Variable(vobj{{"act", ui8(ServerAction::err)}}).serialize();
- client.sendData(result.begin(), result.length());
- }
- }
- void Application::connectHandler(TcpServer::Client& client) {
- std::clog << getHostStr(client) << " (connected)\n";
- FileNodeVisitor conn_data = db.getRoot()("session");
- char uid[6];
- *reinterpret_cast<uint32_t*>(uid) = client.getHost();
- *reinterpret_cast<uint16_t*>(uid + 4) = client.getPort();
- conn_data.insert(BufferArray(ValType::byte, uid, sizeof (uid)), vobj{{"state",ui8(RequestHandler::ClientState::connected)}});
- }
- void Application::disconnectHandler(TcpServer::Client& client) {
- std::clog << getHostStr(client) << " (disconnected)\n";
- char uid[6];
- *reinterpret_cast<uint32_t*>(uid) = client.getHost();
- *reinterpret_cast<uint16_t*>(uid + 4) = client.getPort();
- db.getRoot()("session").remove(BufferArray(ValType::byte, uid, sizeof (uid)));
- }
- Application::Application(int argc, char* argv[]) try : Application(processArgs(argc, argv)) {}
- catch(const Exception& e) {
- std::cerr << e.full() << '\n';
- std::exit(EXIT_FAILURE);
- } catch(const std::exception& e) {
- std::cerr << e.what() << '\n';
- std::exit(EXIT_FAILURE);
- } catch(...) {
- std::cerr << "Unexpected exception!\n";
- std::exit(EXIT_FAILURE);
- }
- Application::Application(Application::AppIniter app_initer)
- : db(app_initer.db_path,
- #include "server_db.hpp"
- , app_initer.init_db),
- server(app_initer.server_port,
- [this](DataBuffer data, TcpServer::Client& client){dataHandler(data, client);},
- [this](TcpServer::Client& client){connectHandler(client);},
- [this](TcpServer::Client& client){disconnectHandler(client);}),
- server_key(Security::genKey()) {
- // Server name init (will be used in the server federation system)
- if(FileNodeVisitor name = db.getRoot()({"server_data","name"}); app_initer.server_name) {
- if(name.getVariable().toBufferArray() != BufferArray(app_initer.server_name)) {
- name.setVariable(app_initer.server_name);
- std::clog << "Server human-readable name assigned\n"
- "current server name = " << name.getVariable().toBufferArray().toString() << '\n';
- }
- } else if(!name.getElementCount()) {
- name.setVariable(
- BufferArray(
- Security::encodeBase64(
- Security::getHashOf(
- Security::extractPublicKey(server_key),
- Security::HashMethod::shake128
- )
- )
- )
- );
- std::clog << "Server base64 name assigned\n"
- "current server name = " << name.getVariable().toBufferArray().toString() << "\n"
- "Use `librehubd -n <your-server-name>` to assign human-readable name\n";
- } else std::clog << "current server name = " << name.getVariable().toBufferArray().toString() << '\n';
- // Server start
- if(server.start() == TcpServer::status::up) {
- std::clog<<"Server up on port: "<< app_initer.server_port <<std::endl;
- server.joinLoop(); // Joing to the client handling loop
- } else {
- std::cerr<<"Server start error! Error code:"<< int(server.getStatus()) << std::endl;
- std::exit(-1);
- }
- }
|