start working on friends system
This commit is contained in:
@@ -10,8 +10,11 @@ sources = [
|
||||
'src/generated/footer.cpp',
|
||||
'src/generated/login.cpp',
|
||||
'src/generated/settings.cpp',
|
||||
'src/generated/friends.cpp',
|
||||
'src/generated/script_friends.cpp',
|
||||
'src/generated/style.cpp',
|
||||
'src/generated/script.cpp',
|
||||
'src/generated/notify.cpp',
|
||||
|
||||
# bcrypt
|
||||
'src/bcrypt/bcrypt.cpp',
|
||||
|
||||
25526
server/src/json/json.hpp
Normal file
25526
server/src/json/json.hpp
Normal file
File diff suppressed because it is too large
Load Diff
@@ -3,11 +3,17 @@
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "httplib/httplib.h"
|
||||
#include "bcrypt/bcrypt.h"
|
||||
|
||||
#define JSON_USE_IMPLICIT_CONVERSIONS 0
|
||||
#include "json/json.hpp"
|
||||
|
||||
using Json = nlohmann::json;
|
||||
|
||||
#include "db.h"
|
||||
#include "post.h"
|
||||
|
||||
@@ -17,8 +23,11 @@
|
||||
#include "generated/footer.h"
|
||||
#include "generated/login.h"
|
||||
#include "generated/settings.h"
|
||||
#include "generated/friends.h"
|
||||
#include "generated/script_friends.h"
|
||||
#include "generated/style.h"
|
||||
#include "generated/script.h"
|
||||
#include "generated/notify.h"
|
||||
|
||||
std::optional<User> getLoggedInUser(const httplib::Request& request, Database& database) {
|
||||
if (!request.has_header("Cookie")) {
|
||||
@@ -46,23 +55,31 @@ int main() {
|
||||
const bin2cpp::File& footerfile = bin2cpp::getFooterHtmlFile();
|
||||
const bin2cpp::File& loginfile = bin2cpp::getLoginHtmlFile();
|
||||
const bin2cpp::File& settingsfile = bin2cpp::getSettingsHtmlFile();
|
||||
const bin2cpp::File& friendsfile = bin2cpp::getFriendsHtmlFile();
|
||||
const bin2cpp::File& friendsjsfile = bin2cpp::getScript_friendsJsFile();
|
||||
const bin2cpp::File& e404file = bin2cpp::getE404HtmlFile();
|
||||
const bin2cpp::File& stylefile = bin2cpp::getStyleCssFile();
|
||||
const bin2cpp::File& scriptfile = bin2cpp::getScriptJsFile();
|
||||
const bin2cpp::File& notifyfile = bin2cpp::getNotifyOpusFile();
|
||||
|
||||
std::string headerTop{headerTopFile.getBuffer(), headerTopFile.getSize()};
|
||||
std::string headerBottom{headerBottomFile.getBuffer(), headerBottomFile.getSize()};
|
||||
std::string footer{footerfile.getBuffer(), footerfile.getSize()};
|
||||
std::string login{loginfile.getBuffer(), loginfile.getSize()};
|
||||
std::string settings{settingsfile.getBuffer(), settingsfile.getSize()};
|
||||
std::string friends{friendsfile.getBuffer(), friendsfile.getSize()};
|
||||
std::string friendsjs{friendsjsfile.getBuffer(), friendsjsfile.getSize()};
|
||||
std::string e404{e404file.getBuffer(), e404file.getSize()};
|
||||
std::string style{stylefile.getBuffer(), stylefile.getSize()};
|
||||
std::string script{scriptfile.getBuffer(), scriptfile.getSize()};
|
||||
std::string notify{notifyfile.getBuffer(), notifyfile.getSize()};
|
||||
|
||||
Database database{"chookchat.db"};
|
||||
|
||||
std::mutex data_mutex;
|
||||
|
||||
std::unordered_map<uint64_t, httplib::ws::WebSocket*> connectedFriends;
|
||||
|
||||
httplib::Server svr;
|
||||
|
||||
svr.Get("/style.css", [&style](const httplib::Request& request, httplib::Response& response) {
|
||||
@@ -73,11 +90,15 @@ int main() {
|
||||
response.set_content(script, "text/javascript");
|
||||
});
|
||||
|
||||
svr.Get("/login", [&login](const httplib::Request& request, httplib::Response& response) {
|
||||
response.set_content(login, "text/html");
|
||||
svr.Get("/script_friends.js", [&friendsjs](const httplib::Request& request, httplib::Response& response) {
|
||||
response.set_content(friendsjs, "text/javascript");
|
||||
});
|
||||
|
||||
svr.Get("/login.html", [&login](const httplib::Request& request, httplib::Response& response) {
|
||||
svr.Get("/notify.opus", [¬ify](const httplib::Request& request, httplib::Response& response) {
|
||||
response.set_content(notify, "audio/ogg; codecs=opus");
|
||||
});
|
||||
|
||||
svr.Get("/login", [&login](const httplib::Request& request, httplib::Response& response) {
|
||||
response.set_content(login, "text/html");
|
||||
});
|
||||
|
||||
@@ -85,8 +106,8 @@ int main() {
|
||||
response.set_content(settings, "text/html");
|
||||
});
|
||||
|
||||
svr.Get("/settings.html", [&settings](const httplib::Request& request, httplib::Response& response) {
|
||||
response.set_content(settings, "text/html");
|
||||
svr.Get("/friends", [&friends](const httplib::Request& request, httplib::Response& response) {
|
||||
response.set_content(friends, "text/html");
|
||||
});
|
||||
|
||||
svr.Post("/login", [&database, &data_mutex](const httplib::Request& request, httplib::Response& response) {
|
||||
@@ -363,6 +384,7 @@ int main() {
|
||||
response.set_header("X-Logged-In", "true");
|
||||
response.set_header("X-Username", user->name);
|
||||
response.set_header("X-Bio", user->bio);
|
||||
response.set_header("X-User-ID", std::to_string(user->id));
|
||||
} catch (const std::runtime_error& e) {
|
||||
response.status = 500;
|
||||
response.set_content("<p>there was an error :( it is: " + std::string(e.what()) + "</p>", "text/html");
|
||||
@@ -373,6 +395,156 @@ int main() {
|
||||
|
||||
});
|
||||
|
||||
svr.Get("/userinfo/:userid", [&database, &data_mutex](const httplib::Request& request, httplib::Response& response) {
|
||||
std::lock_guard<std::mutex> lock(data_mutex);
|
||||
try {
|
||||
uint64_t userId = std::stoull(request.path_params.at("userid"));
|
||||
std::optional<User> user = database.getUser(userId);
|
||||
response.set_header("Cache-Control", "no-store");
|
||||
|
||||
if (!user.has_value()) {
|
||||
response.status = 404;
|
||||
return;
|
||||
}
|
||||
|
||||
response.set_header("X-Logged-In", "true");
|
||||
response.set_header("X-Username", user->name);
|
||||
response.set_header("X-Bio", user->bio);
|
||||
response.set_header("X-User-ID", std::to_string(user->id));
|
||||
} catch (const std::runtime_error& e) {
|
||||
response.status = 500;
|
||||
response.set_content("<p>there was an error :( it is: " + std::string(e.what()) + "</p>", "text/html");
|
||||
} catch (const std::exception& e) {
|
||||
response.status = 500;
|
||||
response.set_content("<p>there was an error :( it is: " + std::string(e.what()) + "</p>", "text/html");
|
||||
}
|
||||
});
|
||||
|
||||
// friends endpoints
|
||||
svr.WebSocket("/friends/ws", [&database, &data_mutex, &connectedFriends](const httplib::Request& request, httplib::ws::WebSocket& ws) {
|
||||
|
||||
std::optional<User> user = getLoggedInUser(request, database);
|
||||
if (!user.has_value()) {
|
||||
ws.close();
|
||||
return;
|
||||
}
|
||||
|
||||
// add us to the logged in users
|
||||
connectedFriends[user->id] = &ws;
|
||||
|
||||
{
|
||||
// send out an update to everyone with the new user list
|
||||
Json data;
|
||||
data["type"] = "users";
|
||||
Json list;
|
||||
for (const auto& [user, value] : connectedFriends) {
|
||||
list.push_back(user);
|
||||
}
|
||||
data["content"] = list;
|
||||
std::string datadump = data.dump();
|
||||
for (const auto& [userid, conn] : connectedFriends) {
|
||||
conn->send(datadump);
|
||||
}
|
||||
}
|
||||
|
||||
std::string msg;
|
||||
while (ws.read(msg)) {
|
||||
try {
|
||||
/*
|
||||
* type:
|
||||
* 0 (message), 1 (friend request), 2 (change status), 3 (ping),
|
||||
* 4 (get online friends)
|
||||
* userId: <int>
|
||||
* content:
|
||||
* <string> (message),
|
||||
* (0 (offline), 1 (online) (change status)),
|
||||
* nil, (friend request)
|
||||
*/
|
||||
Json data = Json::parse(msg);
|
||||
double type = data["type"].get<double>();
|
||||
uint64_t userId = static_cast<uint64_t>(data["userId"].get<double>());
|
||||
if (type == 0) { // message
|
||||
std::string content = data["content"].get<std::string>();
|
||||
if (connectedFriends.find(userId) == connectedFriends.end()) {
|
||||
Json data;
|
||||
data["type"] = "error";
|
||||
data["content"] = "friend not online";
|
||||
ws.send(data.dump());
|
||||
continue;
|
||||
}
|
||||
httplib::ws::WebSocket* friendWs = connectedFriends[userId];
|
||||
if (friendWs->is_open()) {
|
||||
Json data;
|
||||
data["type"] = "message";
|
||||
data["userId"] = user->id;
|
||||
data["content"] = content;
|
||||
friendWs->send(data.dump());
|
||||
|
||||
Json returnData;
|
||||
returnData["type"] = "ok";
|
||||
ws.send(returnData.dump());
|
||||
} else {
|
||||
Json data;
|
||||
data["type"] = "error";
|
||||
data["content"] = "friend not online";
|
||||
ws.send(data.dump());
|
||||
connectedFriends.erase(userId);
|
||||
}
|
||||
// TODO:
|
||||
// - Store in databse
|
||||
// - Verify users are friends
|
||||
|
||||
} else if (type == 1) { // friend request
|
||||
Json data;
|
||||
data["type"] = "error";
|
||||
data["content"] = "not implemented yet";
|
||||
ws.send(data.dump());
|
||||
continue;
|
||||
} else if (type == 2) {
|
||||
// blank for now
|
||||
// no need for a ping anymore
|
||||
} else if (type == 3) {
|
||||
Json data;
|
||||
data["type"] = "ok";
|
||||
ws.send(data.dump());
|
||||
} else if (type == 4) {
|
||||
Json data;
|
||||
data["type"] = "users";
|
||||
Json list;
|
||||
for (const auto& [user, value] : connectedFriends) {
|
||||
list.push_back(user);
|
||||
}
|
||||
data["content"] = list;
|
||||
ws.send(data.dump());
|
||||
}
|
||||
} catch (const std::runtime_error& e) {
|
||||
Json data;
|
||||
data["type"] = "error";
|
||||
data["content"] = e.what();
|
||||
ws.send(data.dump());
|
||||
}
|
||||
}
|
||||
|
||||
// clean up the connection
|
||||
connectedFriends.erase(user->id);
|
||||
ws.close();
|
||||
|
||||
// send out an update to everyone with the new user list
|
||||
{
|
||||
Json data;
|
||||
data["type"] = "users";
|
||||
Json list;
|
||||
for (const auto& [user, value] : connectedFriends) {
|
||||
list.push_back(user);
|
||||
}
|
||||
data["content"] = list;
|
||||
std::string datadump = data.dump();
|
||||
for (const auto& [userid, conn] : connectedFriends) {
|
||||
conn->send(datadump);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// settings endpoints
|
||||
svr.Post("/settings/changePassword", [&database, &data_mutex](const httplib::Request& request, httplib::Response& response) {
|
||||
|
||||
Reference in New Issue
Block a user