feat: working on the client-server connection
This commit is contained in:
parent
dc1aed487e
commit
13f9e8479c
11 changed files with 114 additions and 101 deletions
9
.clangd
9
.clangd
|
|
@ -6,6 +6,8 @@ Diagnostics:
|
|||
Includes:
|
||||
IgnoreHeader:
|
||||
- \.compat\.inc
|
||||
CompileFlags:
|
||||
CompilationDatabase: engine/
|
||||
---
|
||||
# Header-specific conditions.
|
||||
|
||||
|
|
@ -20,11 +22,4 @@ CompileFlags:
|
|||
- -Wno-unused-const-variable
|
||||
- -Wno-unused-function
|
||||
- -Wno-unused-variable
|
||||
---
|
||||
# Suppress all third-party warnings.
|
||||
|
||||
If:
|
||||
PathMatch: thirdparty/.*
|
||||
|
||||
Diagnostics:
|
||||
Suppress: "*"
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@
|
|||
config_version=5
|
||||
|
||||
[application]
|
||||
|
||||
config/name="you_done_it"
|
||||
run/main_scene="uid://dosb4sb7pvss4"
|
||||
config/features=PackedStringArray("4.5", "Forward Plus")
|
||||
config/icon="res://icon.svg"
|
||||
|
|
|
|||
9
justfile
9
justfile
|
|
@ -6,7 +6,7 @@ compiledb := if tree_hash == `cat .tree.hash` { "no" } else { "yes" }
|
|||
|
||||
build: format
|
||||
# Compiling Editor
|
||||
cd engine/ && scons target=editor symbols=yes optimization=debug dev_build=yes linker=mold use_llvm=yes compiledb={{compiledb}} custom_modules="../modules"
|
||||
cd engine/ && scons disable_exceptions=false target=editor symbols=yes optimization=debug dev_build=yes linker=mold use_llvm=yes compiledb={{compiledb}} custom_modules="../modules"
|
||||
echo {{tree_hash}} > .tree.hash
|
||||
|
||||
run: build
|
||||
|
|
@ -15,7 +15,7 @@ run: build
|
|||
|
||||
release-linux: build
|
||||
# Compiling Linux Release
|
||||
cd engine/ && scons platform=linuxbsd target=template_release arch=x86_64 linker=mold use_llvm=yes custom_modules="../modules"
|
||||
cd engine/ && scons disable_exceptions=false platform=linuxbsd target=template_release arch=x86_64 linker=mold use_llvm=yes custom_modules="../modules"
|
||||
# Preparing Build Environment
|
||||
sed -i "s!templatepath!{{`realpath engine/bin/godot.linuxbsd.template_release.x86_64.llvm`}}!" project/export_presets.cfg
|
||||
rm -rf build && mkdir build
|
||||
|
|
@ -27,7 +27,7 @@ release-linux: build
|
|||
|
||||
release-windows: build
|
||||
# Compiling Windows Release
|
||||
cd engine/ && scons platform=windows target=template_release arch=x86_64 linker=mold custom_modules="../modules"
|
||||
cd engine/ && scons disable_exceptions=false platform=windows target=template_release arch=x86_64 linker=mold custom_modules="../modules"
|
||||
# Preparing Build Environment
|
||||
sed -i "s!templatepath!{{`realpath engine/bin/godot.windows.template_release.x86_64`}}!" project/export_presets.cfg
|
||||
rm -rf build && mkdir build
|
||||
|
|
@ -46,4 +46,5 @@ initialize-template projectname:
|
|||
|
||||
format:
|
||||
# Formatting Custom Modules
|
||||
clang-format -i $(find modules/ -iname '*.h' -o -iname '*.c' -o -iname '*.hpp' -o -iname '*.cpp' -o -iname '*.hxx' -o -iname '*.cxx')
|
||||
clang-format -i modules/you_done_it/*.h modules/you_done_it/*.cpp
|
||||
# $(find modules/ -iname '*.h' -o -iname '*.c' -o -iname '*.hpp' -o -iname '*.cpp' -o -iname '*.hxx' -o -iname '*.cxx')
|
||||
|
|
|
|||
|
|
@ -7,9 +7,9 @@ ydi_env = env.Clone()
|
|||
ydi_env.Append(CPPPATH=["libzmq/include", "cppzmq/"])
|
||||
ydi_env.add_source_files(env.modules_sources, "*.cpp")
|
||||
|
||||
if not os.path.isdir(Dir('libzmq/build/lib').abspath):
|
||||
call(["cmake", "-Slibzmq", "-B" + Dir('libzmq/build').abspath, "-DZMQ_BUILD_TESTS=OFF"])
|
||||
call(["cmake", "-Slibzmq", "-B" + Dir('libzmq/build').abspath, "-DZMQ_BUILD_TESTS=OFF", "-DZMQ_BUILD_STATIC=ON", "-DZMQ_BUILD_SHARED=OFF"])
|
||||
call(["cmake", "--build", Dir('libzmq/build').abspath])
|
||||
|
||||
env.Append(LIBPATH=[Dir('libzmq/build/lib/').abspath])
|
||||
ydi_env.Append(LIBS=['libzmq'])
|
||||
ydi_env.Append(LIBPATH=[Dir('libzmq/build/lib/').abspath])
|
||||
env.Append(LIBS=['libzmq'])
|
||||
|
|
|
|||
|
|
@ -1,11 +0,0 @@
|
|||
#include "flatscreen_root.h"
|
||||
|
||||
void FlatscreenRoot::_bind_methods() {}
|
||||
|
||||
void FlatscreenRoot::enter_tree() {
|
||||
ydi::server::open();
|
||||
}
|
||||
|
||||
void FlatscreenRoot::exit_tree() {
|
||||
ydi::server::close();
|
||||
}
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "ydi_server.h"
|
||||
#include <scene/gui/container.h>
|
||||
|
||||
class FlatscreenRoot : public Container {
|
||||
GDCLASS(FlatscreenRoot, Container);
|
||||
static void _bind_methods();
|
||||
void enter_tree();
|
||||
void exit_tree();
|
||||
protected:
|
||||
void _notification(int what);
|
||||
};
|
||||
|
|
@ -1,12 +1,13 @@
|
|||
#include "register_types.h"
|
||||
|
||||
#include "core/object/class_db.h"
|
||||
#include "zmq.hpp"
|
||||
#include "server_node.h"
|
||||
#include <core/object/class_db.h>
|
||||
|
||||
void initialize_you_done_it_module(ModuleInitializationLevel p_level) {
|
||||
if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
|
||||
return;
|
||||
}
|
||||
ClassDB::register_class<ServerNode>();
|
||||
}
|
||||
|
||||
void uninitialize_you_done_it_module(ModuleInitializationLevel p_level) {
|
||||
|
|
|
|||
|
|
@ -1,39 +1,30 @@
|
|||
#include "ydi_networking.h"
|
||||
#include <zmq.hpp>
|
||||
#include <zmq_addon.hpp>
|
||||
|
||||
namespace ydi {
|
||||
MessageType to_message_type(std::string const &msg) {
|
||||
int as_int{ std::stoi(msg) };
|
||||
if (as_int >= 0 && as_int < MESSAGE_TYPE_MAX) {
|
||||
MessageType to_message_type(zmq::message_t const &msg) {
|
||||
int as_int{ std::stoi(msg.str()) };
|
||||
if (as_int >= 0 && as_int < MESSAGE_TYPE_INVALID) {
|
||||
return (MessageType)as_int;
|
||||
} else {
|
||||
return NONE;
|
||||
return MESSAGE_TYPE_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
MessageType message_type(zmq::multipart_t const &msg, size_t *type_idx) {
|
||||
MessageType type{ to_message_type(msg[0].to_string()) };
|
||||
size_t idx{ 0 };
|
||||
if (!type) {
|
||||
++idx;
|
||||
type = to_message_type(msg[0].to_string());
|
||||
NOKReason to_nok_reason(zmq::message_t const &msg) {
|
||||
int as_int{ std::stoi(msg.str()) };
|
||||
if (as_int >= 0 && as_int < NOK_REASON_INVALID) {
|
||||
return (NOKReason)as_int;
|
||||
} else {
|
||||
return NOK_REASON_INVALID;
|
||||
}
|
||||
if (!type) {
|
||||
idx = std::numeric_limits<size_t>::max();
|
||||
}
|
||||
if (type_idx) {
|
||||
*type_idx = idx;
|
||||
}
|
||||
return type;
|
||||
|
||||
}
|
||||
|
||||
bool decompose_connect(zmq::multipart_t &msg, int *code) {
|
||||
size_t start{};
|
||||
MessageType actual_type{ message_type(msg, &start) };
|
||||
if (actual_type) {
|
||||
|
||||
ClueID to_clue_id(zmq::message_t const &msg) {
|
||||
int as_int{ std::stoi(msg.str()) };
|
||||
if (as_int >= 0 && as_int < CLUE_MAX) {
|
||||
return (ClueID)as_int;
|
||||
} else {
|
||||
return CLUE_MAX;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -67,4 +58,4 @@ void extend_multipart(zmq::multipart_t &mpart, zmq::multipart_t const &right) {
|
|||
}
|
||||
|
||||
void extend_multipart(zmq::multipart_t &mpart) {}
|
||||
}
|
||||
} //namespace ydi
|
||||
|
|
|
|||
|
|
@ -1,30 +1,44 @@
|
|||
#pragma once
|
||||
|
||||
#include <zmq.h>
|
||||
#include <zmq.hpp>
|
||||
#include <zmq_addon.hpp>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <zmq.hpp>
|
||||
#include <zmq_addon.hpp>
|
||||
|
||||
namespace ydi {
|
||||
enum MessageType {
|
||||
NONE = 0u,
|
||||
// connection management messages
|
||||
CONNECT = 1u,
|
||||
OK,
|
||||
NOK,
|
||||
MESSAGE_TYPE_MAX
|
||||
HEART,
|
||||
BEAT,
|
||||
// gameplay messages
|
||||
REVEAL,
|
||||
// end of messages
|
||||
MESSAGE_TYPE_INVALID
|
||||
};
|
||||
|
||||
enum ClueID {
|
||||
FIRST_CLUE,
|
||||
CLUE_MAX
|
||||
};
|
||||
|
||||
MessageType to_message_type(std::string const &msg);
|
||||
MessageType message_type(zmq::multipart_t const &msg, size_t *type_idx = nullptr);
|
||||
enum ConnectionStatus {
|
||||
DISCONNECTED,
|
||||
CONNECTED,
|
||||
AUTHENTICATED
|
||||
};
|
||||
|
||||
bool decompose_connect(zmq::multipart_t &msg, int *code);
|
||||
bool decompose_nok(zmq::multipart_t &msg, MessageType &failed);
|
||||
bool decompose_reveal_clue(zmq::multipart_t &msg, ClueID &id);
|
||||
enum NOKReason {
|
||||
CLIENT_UNAUTHENTICATED,
|
||||
NOK_REASON_INVALID //!< this means the value could not be parsed as a NOK reason, not that the reason is an invalid message.INVALID
|
||||
};
|
||||
|
||||
MessageType to_message_type(zmq::message_t const &msg);
|
||||
NOKReason to_nok_reason(zmq::message_t const &msg);
|
||||
ClueID to_clue_id(zmq::message_t const &msg);
|
||||
|
||||
void extend_multipart(zmq::multipart_t &mpart, MessageType type);
|
||||
void extend_multipart(zmq::multipart_t &mpart, ClueID type);
|
||||
|
|
@ -37,7 +51,7 @@ void extend_multipart(zmq::multipart_t &mpart, zmq::multipart_t const &right);
|
|||
void extend_multipart(zmq::multipart_t &mpart);
|
||||
|
||||
template <typename TArg, typename... TArgs>
|
||||
void extend_multipart(zmq::multipart_t &mpart, TArg const &arg, TArgs const &... args) {
|
||||
void extend_multipart(zmq::multipart_t &mpart, TArg const &arg, TArgs const &...args) {
|
||||
extend_multipart(mpart, arg);
|
||||
extend_multipart(mpart, args...);
|
||||
}
|
||||
|
|
@ -50,9 +64,9 @@ zmq::multipart_t multipart(TArg const &arg) {
|
|||
}
|
||||
|
||||
template <typename TArg, typename... TArgs>
|
||||
zmq::multipart_t multipart(TArg const &arg, TArgs const &... args) {
|
||||
zmq::multipart_t multipart(TArg const &arg, TArgs const &...args) {
|
||||
zmq::multipart_t mpart{ multipart(arg) };
|
||||
extend_multipart(mpart, args...);
|
||||
return mpart;
|
||||
}
|
||||
}
|
||||
} //namespace ydi
|
||||
|
|
|
|||
|
|
@ -2,39 +2,48 @@
|
|||
#include "ydi_networking.h"
|
||||
#include <core/os/time.h>
|
||||
#include <core/templates/vector.h>
|
||||
#include <atomic>
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
#include <stop_token>
|
||||
#include <chrono>
|
||||
#include <queue>
|
||||
#include <thread>
|
||||
#include <unordered_set>
|
||||
#include <zmq.hpp>
|
||||
#include <zmq_addon.hpp>
|
||||
|
||||
namespace ydi::server {
|
||||
struct Event {
|
||||
MessageType type;
|
||||
union {
|
||||
ClueID clue;
|
||||
};
|
||||
};
|
||||
struct Service {
|
||||
std::optional<zmq::context_t> context{ std::nullopt };
|
||||
std::optional<zmq::socket_t> socket{ std::nullopt };
|
||||
std::unordered_set<ClueID> revealedClues{};
|
||||
std::unordered_set<ClueID> revealed_clues{};
|
||||
std::recursive_mutex mtx{};
|
||||
std::optional<std::string> client{ std::nullopt };
|
||||
std::queue<Event> unhandled_events{};
|
||||
double lastHeart{ 0.0 };
|
||||
double lastBeat{ 0.0 };
|
||||
|
||||
std::atomic<bool> stop_threads{ false };
|
||||
};
|
||||
|
||||
std::optional<std::thread> receive_thread{ std::nullopt };
|
||||
std::optional<std::thread> ping_thread{ std::nullopt };
|
||||
std::optional<Service> service{ std::nullopt };
|
||||
std::optional<std::thread> receiveThread{ std::nullopt };
|
||||
std::optional<std::thread> pingThread{ std::nullopt };
|
||||
|
||||
void handle_reveal_clue(zmq::multipart_t const &message) {
|
||||
Event evt{ .type = REVEAL, .clue = to_clue_id(message.at(2)) };
|
||||
service->unhandled_events.push(evt);
|
||||
}
|
||||
|
||||
void handle_authorised_message(std::string_view const &sender, std::string_view const &type, zmq::multipart_t &message) {
|
||||
if (type == "BEAT") {
|
||||
void handle_authorised_message(std::string_view const &sender, MessageType type, zmq::multipart_t &message) {
|
||||
if (type == BEAT) {
|
||||
service->lastBeat = Time::get_singleton()->get_unix_time_from_system();
|
||||
} else if(type == "REVEAL") {
|
||||
} else if (type == REVEAL) {
|
||||
handle_reveal_clue(message);
|
||||
} else {
|
||||
multipart(sender, "NOK", "UNKOWN_COMMAND", message).send(*service->socket);
|
||||
|
|
@ -43,18 +52,19 @@ void handle_authorised_message(std::string_view const &sender, std::string_view
|
|||
|
||||
void handle_message(zmq::multipart_t &message) {
|
||||
std::string_view const sender{ message.at(0).to_string_view() };
|
||||
std::string_view const type{ message.at(1).to_string_view() };
|
||||
MessageType type{ to_message_type(message.at(1)) };
|
||||
std::scoped_lock lock{ service->mtx };
|
||||
if (service->client) {
|
||||
if (sender != service->client) {
|
||||
multipart(sender,"NOK", "UNAUTHORIZED_REQUEST").send(*service->socket);
|
||||
if (sender == service->client) {
|
||||
handle_authorised_message(sender, type, message);
|
||||
} else {
|
||||
multipart(sender, "NOK", "UNAUTHORIZED_REQUEST").send(*service->socket);
|
||||
}
|
||||
handle_authorised_message(sender, type, message);
|
||||
} else if (type == "CONNECT") {
|
||||
} else if (type == CONNECT) {
|
||||
service->client.emplace(sender);
|
||||
multipart(sender, "OK", message).send(*service->socket);
|
||||
multipart(sender, OK, message).send(*service->socket);
|
||||
} else {
|
||||
multipart(sender,"NOK", "UNAUTHORIZED_REQUEST", message).send(*service->socket);
|
||||
multipart(sender, NOK, "UNAUTHORIZED_REQUEST", message).send(*service->socket);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -72,7 +82,8 @@ void receive_thread_entry() {
|
|||
|
||||
void ping_thread_entry() {
|
||||
using namespace std::chrono_literals;
|
||||
{ std::scoped_lock lock{ service->mtx };
|
||||
{
|
||||
std::scoped_lock lock{ service->mtx };
|
||||
if (!service->client) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -87,45 +98,67 @@ void ping_thread_entry() {
|
|||
}
|
||||
|
||||
void open() {
|
||||
print_line("Server: Starting");
|
||||
service.emplace();
|
||||
try {
|
||||
service->context.emplace(1);
|
||||
} catch (...) {
|
||||
service.reset();
|
||||
print_line("Server: Failed to create context");
|
||||
return;
|
||||
}
|
||||
print_line("Server: Created zmq context");
|
||||
try {
|
||||
service->socket.emplace(*service->context, zmq::socket_type::router);
|
||||
} catch (...) {
|
||||
service->context->close();
|
||||
service->context.reset();
|
||||
service.reset();
|
||||
print_line("Server: Failed to create socket");
|
||||
return;
|
||||
}
|
||||
print_line("Server: Created socket");
|
||||
try {
|
||||
service->socket->connect("tcp://*:6667");
|
||||
service->socket->bind("tcp://*:6667");
|
||||
} catch (...) {
|
||||
service->socket->close();
|
||||
service->socket.reset();
|
||||
service->context->close();
|
||||
service->context.reset();
|
||||
service.reset();
|
||||
print_line("Server: Failed to bind socket");
|
||||
return;
|
||||
}
|
||||
receiveThread.emplace(receive_thread_entry);
|
||||
print_line("Server: Bound socket");
|
||||
receive_thread.emplace(receive_thread_entry);
|
||||
}
|
||||
|
||||
void close() {
|
||||
if (service) {
|
||||
print_line("Server: Shutting down...");
|
||||
std::scoped_lock lock{ service->mtx };
|
||||
service->stop_threads = true;
|
||||
print_line("Server: Stopping Threads...");
|
||||
if (receive_thread && receive_thread->joinable()) {
|
||||
receive_thread->join();
|
||||
}
|
||||
print_line("Server: Receive thread stopped");
|
||||
if (ping_thread && ping_thread->joinable()) {
|
||||
ping_thread->join();
|
||||
}
|
||||
print_line("Server: Ping thread stopped");
|
||||
if (service->socket) {
|
||||
service->socket->close();
|
||||
service->socket.reset();
|
||||
}
|
||||
print_line("Server: Socket closed");
|
||||
if (service->context) {
|
||||
service->context->close();
|
||||
service->context.reset();
|
||||
}
|
||||
print_line("Server: Context closed");
|
||||
service.reset();
|
||||
print_line("Server: Shutdown complete!");
|
||||
}
|
||||
}
|
||||
}
|
||||
} //namespace ydi::server
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
#pragma once
|
||||
|
||||
#include <cassert>
|
||||
#include "ydi_networking.h"
|
||||
#include <core/io/image.h>
|
||||
#include <core/string/ustring.h>
|
||||
#include <core/templates/vector.h>
|
||||
#include "ydi_networking.h"
|
||||
#include <cassert>
|
||||
|
||||
namespace ydi::server {
|
||||
void open();
|
||||
|
|
@ -12,8 +12,8 @@ void close();
|
|||
namespace receive {
|
||||
bool isRevealed(ClueID id);
|
||||
Ref<Image> clueImage(ClueID id);
|
||||
}
|
||||
} //namespace receive
|
||||
namespace send {
|
||||
void announceConclusion(ClueID method, ClueID motive, ClueID murderer);
|
||||
}
|
||||
}
|
||||
} //namespace ydi::server
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue