#include "../include/Window.hpp" #include "../include/Cache.hpp" #include "../include/ChannelDataType.hpp" #include "../include/WindowNotification.hpp" #include #include #include namespace dchat { const int nodesPerColumn = 5; const int nodesPerRow = 5; Window::Window() { set_border_width(0); WindowNotification *windowNotification = Gtk::manage(new WindowNotification()); overlay.add_overlay(*windowNotification); overlay.set_overlay_pass_through(*windowNotification); overlay.add(stack); add(overlay); stack.set_transition_type(Gtk::StackTransitionType::STACK_TRANSITION_TYPE_SLIDE_LEFT_RIGHT); stack.set_transition_duration(250); stack.add(loginWindow, "login"); stack.add(chatWindow, "chat"); overlay.show(); windowNotification->show_all(); stack.show(); chatWindow.show_all(); loginWindow.show(); loginWindow.setLoginHandler([this, windowNotification](const Glib::ustring &username, const Glib::ustring &password) { if(!database) { windowNotification->show("You are not connected to the bootstrap node yet! please wait..."); return; } try { fprintf(stderr, "Trying to login with username %s\n", username.raw().c_str()); auto storedNodes = database->getStoredNodeUserInfoDecrypted(username.raw(), password.raw()); windowNotification->show(Glib::ustring("Successfully logged in as ") + username); drawBackgroundConnection.disconnect(); stack.set_visible_child(chatWindow); for(auto &nodeInfo : storedNodes) { database->loadNode(nodeInfo.first); } } catch(std::exception &e) { Glib::ustring errMsg = "Failed to login, reason: "; errMsg += e.what(); windowNotification->show(errMsg); } }); loginWindow.setRegisterHandler([this, windowNotification](const Glib::ustring &username, const Glib::ustring &password) { if(!database) { windowNotification->show("You are not connected to the bootstrap node yet! please wait..."); return; } try { fprintf(stderr, "Trying to register username %s\n", username.raw().c_str()); database->storeUserWithoutNodes(username.raw(), password.raw()); windowNotification->show(Glib::ustring("Successfully registered user ") + username); drawBackgroundConnection.disconnect(); stack.set_visible_child(chatWindow); } catch(std::exception &e) { Glib::ustring errMsg = "Failed to register username "; errMsg += username.raw(); errMsg += ", reason: "; errMsg += e.what(); windowNotification->show(errMsg); } }); loginWindow.setRegisterPasswordMismatch([windowNotification] { windowNotification->show("Passwords do not match"); }); odhtdb::DatabaseCallbackFuncs callbackFuncs; callbackFuncs.createNodeCallbackFunc = [this](const odhtdb::DatabaseCreateNodeRequest &request) { std::lock_guard lock(databaseCallbackMutex); chatWindow.addChannel(*request.nodeHash); chatWindow.addUser(*request.creatorPublicKey); }; callbackFuncs.addNodeCallbackFunc = [this](const odhtdb::DatabaseAddNodeRequest &request) { std::lock_guard lock(databaseCallbackMutex); if(request.decryptedData.size == 0) return; ChannelDataType channelDataType = (ChannelDataType)static_cast(request.decryptedData.data)[0]; try { switch(channelDataType) { case ChannelDataType::ADD_MESSAGE: { Glib::ustring msg((const char*)request.decryptedData.data + 1, request.decryptedData.size - 1); uint32_t timestampSeconds = ntp::NtpTimestamp::fromCombined(request.timestamp).seconds; chatWindow.addLocalMessage(*request.nodeHash, *request.creatorPublicKey, timestampSeconds, std::move(msg)); break; } case ChannelDataType::NICKNAME_CHANGE: { sibs::SafeDeserializer deserializer((const u8*)request.decryptedData.data + 1, request.decryptedData.size - 1); u8 nameLength = deserializer.extract(); if(nameLength > 0) { std::string nickname; nickname.resize(nameLength); deserializer.extract((u8*)&nickname[0], nameLength); chatWindow.setUserNickname(*request.creatorPublicKey, nickname); } break; } default: break; } } catch(std::exception &e) { fprintf(stderr, "Failed to process add node request, reason: %s\n", e.what()); } }; callbackFuncs.addUserCallbackFunc = [this](const odhtdb::DatabaseAddUserRequest &request) { std::lock_guard lock(databaseCallbackMutex); chatWindow.addUser(*request.userToAddPublicKey); }; fprintf(stderr, "Connecting...\n"); database = odhtdb::Database::connect("83.252.53.188", 27130, Cache::getDchatDir(), callbackFuncs).get(); stack.set_visible_child(loginWindow); windowNotification->show("Connected to 83.252.53.188:27130"); backgroundRng.seed(std::random_device()()); std::uniform_int_distribution sizeDeviationRand(0, 5); std::uniform_int_distribution posDeviationRand(0, 100); const double spaceBetweenNodesColumn = 1.0 / (double)(nodesPerColumn - 1); const double spaceBetweenNodesRow = 1.0 / (double)(nodesPerRow - 1); for(int y = 0; y < nodesPerRow; ++y) { for(int x = 0; x < nodesPerColumn; ++x) { int sizeDeviation = sizeDeviationRand(backgroundRng); //int xDeviation = posDeviationRand(backgroundRng) - 50; //int yDeviation = posDeviationRand(backgroundRng) - 50; int xDeviation = 0; int yDeviation = 0; Node node; node.radius = 5.0 + sizeDeviation; node.originalPosX = /*spaceBetweenNodesColumn * 0.5 + */x * spaceBetweenNodesColumn + xDeviation * 0.001; node.originalPosY = /*spaceBetweenNodesRow * 0.5 + */y * spaceBetweenNodesRow + yDeviation * 0.001; node.currentPosX = node.originalPosX; node.currentPosY = node.originalPosY; node.targetPosX = node.currentPosX; node.targetPosY = node.currentPosY; backgroundNodes.push_back(node); } } prevTimeMillis = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count() - 5000; drawBackgroundConnection = signal_draw().connect(sigc::mem_fun(*this, &Window::drawBackground)); set_size_request(640, 480); } Window::~Window() { } static void drawNode(const Cairo::RefPtr &cairo, double x, double y, double radius) { cairo->arc(x, y, radius, 0.0, 2.0 * M_PI); cairo->fill(); cairo->arc(x, y, radius + (radius * 0.8), 0.0, 2.0 * M_PI); cairo->set_line_width(radius * 0.1); cairo->stroke(); } bool Window::drawBackground(const Cairo::RefPtr &cairo) { int windowWidth, windowHeight; get_size(windowWidth, windowHeight); cairo->set_source_rgb(0.5, 0.5, 0.5); int currentTimeMillis = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); int deltaTimeMillis = currentTimeMillis - prevTimeMillis; bool updateTarget = false; if(deltaTimeMillis > 3000) { prevTimeMillis = currentTimeMillis; updateTarget = true; } std::uniform_int_distribution posDeviationRand(0, 100); const double moveSpeed = 0.0001; for(Node &node : backgroundNodes) { if(updateTarget) { int xDeviation = posDeviationRand(backgroundRng) - 50; int yDeviation = posDeviationRand(backgroundRng) - 50; node.targetPosX = node.originalPosX + xDeviation * 0.001; node.targetPosY = node.originalPosY + yDeviation * 0.001; } double diffX = node.targetPosX - node.currentPosX; double diffY = node.targetPosY - node.currentPosY; double diffDist = std::max(0.01, std::sqrt(diffX*diffX + diffY*diffY)); diffX /= diffDist; diffY /= diffDist; node.currentPosX += (diffX * moveSpeed); node.currentPosY += (diffY * moveSpeed); drawNode(cairo, node.currentPosX * windowWidth, node.currentPosY * windowHeight, node.radius); } cairo->set_line_width(2.0); for(int y = 0; y < nodesPerRow; ++y) { for(int x = 0; x < nodesPerColumn; ++x) { Node *currentNode = &backgroundNodes[x + y * nodesPerRow]; if(x > 0) { Node *prevNode = &backgroundNodes[x - 1 + y * nodesPerRow]; int currentNodeRadius = currentNode->radius + (currentNode->radius * 0.8); int prevNodeRadius = prevNode->radius + (prevNode->radius * 0.8); cairo->move_to(prevNode->currentPosX * windowWidth + prevNodeRadius, prevNode->currentPosY * windowHeight); cairo->line_to(currentNode->currentPosX * windowWidth - currentNodeRadius, currentNode->currentPosY * windowHeight); } if(y > 0) { Node *prevNode = &backgroundNodes[x + (y - 1) * nodesPerRow]; int currentNodeRadius = currentNode->radius + (currentNode->radius * 0.8); int prevNodeRadius = prevNode->radius + (prevNode->radius * 0.8); cairo->move_to(prevNode->currentPosX * windowWidth, prevNode->currentPosY * windowHeight + prevNodeRadius); cairo->line_to(currentNode->currentPosX * windowWidth, currentNode->currentPosY * windowHeight - currentNodeRadius); } } } cairo->stroke(); overlay.draw(cairo); queue_draw(); return true; } }