Start RPC library
This commit is contained in:
parent
716ae24600
commit
33d8277dc3
@ -1,6 +1,7 @@
|
|||||||
cmake_minimum_required(VERSION 3.0)
|
cmake_minimum_required(VERSION 3.20)
|
||||||
project(CppConsoleGame VERSION 1.0.0)
|
project(CppConsoleGame VERSION 1.0.0)
|
||||||
|
|
||||||
add_subdirectory(conio)
|
add_subdirectory(conio)
|
||||||
add_subdirectory(random-utils)
|
add_subdirectory(random-utils)
|
||||||
|
add_subdirectory(eRPC)
|
||||||
add_subdirectory(cpp-console-game)
|
add_subdirectory(cpp-console-game)
|
@ -16,7 +16,6 @@ namespace ConsoleGame
|
|||||||
void Board::draw()
|
void Board::draw()
|
||||||
{
|
{
|
||||||
std::cout << "\033[H"; // Move cursor to the top left corner
|
std::cout << "\033[H"; // Move cursor to the top left corner
|
||||||
std::cout << "\033[2J"; // Clear the screen
|
|
||||||
|
|
||||||
for (auto row : cells)
|
for (auto row : cells)
|
||||||
{
|
{
|
||||||
|
@ -25,6 +25,7 @@ target_link_libraries(
|
|||||||
cpp-console-game PRIVATE
|
cpp-console-game PRIVATE
|
||||||
GameState
|
GameState
|
||||||
conio
|
conio
|
||||||
|
eRPC
|
||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(
|
target_link_libraries(
|
||||||
|
@ -3,6 +3,9 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <conio.hpp>
|
#include <conio.hpp>
|
||||||
|
#include <Server.hpp>
|
||||||
|
#include <Client.hpp>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
ConsoleGame::GameState gameState(20, 10);
|
ConsoleGame::GameState gameState(20, 10);
|
||||||
|
|
||||||
@ -39,6 +42,8 @@ void inputLoop(int playerId)
|
|||||||
|
|
||||||
void renderLoop()
|
void renderLoop()
|
||||||
{
|
{
|
||||||
|
std::cout << "\033[2J"; // Clear the screen
|
||||||
|
|
||||||
while (gameState.isRunning())
|
while (gameState.isRunning())
|
||||||
{
|
{
|
||||||
gameState.draw();
|
gameState.draw();
|
||||||
@ -46,15 +51,43 @@ void renderLoop()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int main()
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
int playerId = gameState.addPlayer();
|
if (argc < 4)
|
||||||
|
{
|
||||||
|
std::cerr << "Usage: " << argv[0] << "<client/server> <port> <host>" << std::endl;
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
std::thread inputThread(inputLoop, playerId);
|
std::string mode = argv[1];
|
||||||
std::thread renderThread(renderLoop);
|
int port = std::stoi(argv[2]);
|
||||||
|
std::string host = argv[3];
|
||||||
|
|
||||||
inputThread.join();
|
if (mode == "server")
|
||||||
renderThread.join();
|
{
|
||||||
|
eRPC::Server server(port);
|
||||||
|
server.start();
|
||||||
|
}
|
||||||
|
else if (mode == "client")
|
||||||
|
{
|
||||||
|
eRPC::Client client(host, port);
|
||||||
|
client.openConnection();
|
||||||
|
client.call("Hello from client");
|
||||||
|
client.closeConnection();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::cerr << "Invalid mode" << std::endl;
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
// int playerId = gameState.addPlayer();
|
||||||
|
|
||||||
|
// std::thread inputThread(inputLoop, playerId);
|
||||||
|
// std::thread renderThread(renderLoop);
|
||||||
|
|
||||||
|
// inputThread.join();
|
||||||
|
// renderThread.join();
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
26
eRPC/CMakeLists.txt
Normal file
26
eRPC/CMakeLists.txt
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
add_library(
|
||||||
|
eRPC
|
||||||
|
Client.hpp
|
||||||
|
Client.cpp
|
||||||
|
Server.hpp
|
||||||
|
Server.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
add_library(
|
||||||
|
eRPC_helpers
|
||||||
|
Request.hpp
|
||||||
|
Request.cpp
|
||||||
|
Response.hpp
|
||||||
|
Response.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(
|
||||||
|
eRPC PRIVATE
|
||||||
|
eRPC_helpers
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories(
|
||||||
|
eRPC
|
||||||
|
PUBLIC
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
|
)
|
74
eRPC/Client.cpp
Normal file
74
eRPC/Client.cpp
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
#include "Client.hpp"
|
||||||
|
#include "Request.hpp"
|
||||||
|
#include "Response.hpp"
|
||||||
|
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
namespace eRPC
|
||||||
|
{
|
||||||
|
Client::Client(std::string host, int port) : sockfd(-1), serv_addr()
|
||||||
|
{
|
||||||
|
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Failed to create socket");
|
||||||
|
}
|
||||||
|
|
||||||
|
sockaddr_in serv_addr;
|
||||||
|
serv_addr.sin_family = AF_INET;
|
||||||
|
serv_addr.sin_port = htons(port);
|
||||||
|
|
||||||
|
if (inet_pton(AF_INET, host.c_str(), &serv_addr.sin_addr) <= 0)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Invalid address");
|
||||||
|
}
|
||||||
|
|
||||||
|
this->serv_addr = serv_addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Client::~Client()
|
||||||
|
{
|
||||||
|
closeConnection();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Client::openConnection()
|
||||||
|
{
|
||||||
|
if (sockfd < 0)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Socket not created");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (connect(sockfd, (sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Failed to connect to server");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "Connected to server" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Client::closeConnection()
|
||||||
|
{
|
||||||
|
close(sockfd);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Client::call(std::string method)
|
||||||
|
{
|
||||||
|
if (sockfd < 0)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Socket not created");
|
||||||
|
}
|
||||||
|
|
||||||
|
Request request(0, method, {"First argument", "Another argument"});
|
||||||
|
auto serialized = request.serialize();
|
||||||
|
write(sockfd, serialized.c_str(), serialized.size() + 1);
|
||||||
|
|
||||||
|
char buffer[1024] = {0};
|
||||||
|
read(sockfd, buffer, 1024);
|
||||||
|
|
||||||
|
Response response(buffer);
|
||||||
|
std::cout << "Received response:\n" << response.serialize() << std::endl;
|
||||||
|
}
|
||||||
|
}
|
24
eRPC/Client.hpp
Normal file
24
eRPC/Client.hpp
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
#ifndef ERPC_CLIENT_HPP
|
||||||
|
#define ERPC_CLIENT_HPP
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
|
||||||
|
namespace eRPC
|
||||||
|
{
|
||||||
|
class Client
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Client(std::string host, int port);
|
||||||
|
~Client();
|
||||||
|
void openConnection();
|
||||||
|
void closeConnection();
|
||||||
|
void call(std::string method);
|
||||||
|
|
||||||
|
private:
|
||||||
|
int sockfd;
|
||||||
|
sockaddr_in serv_addr;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // ERPC_CLIENT_HPP
|
65
eRPC/Request.cpp
Normal file
65
eRPC/Request.cpp
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
#include "Request.hpp"
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
namespace eRPC
|
||||||
|
{
|
||||||
|
Request::Request(int msgid, std::string method, std::vector<std::string> params)
|
||||||
|
: msgid(msgid), method(method), params(params)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Request::Request(std::string msg) : msgid(-1), method(), params()
|
||||||
|
{
|
||||||
|
std::string line;
|
||||||
|
std::istringstream iss(msg);
|
||||||
|
|
||||||
|
std::getline(iss, line);
|
||||||
|
if (line != "eRPC 1.0")
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Invalid message");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::getline(iss, line);
|
||||||
|
msgid = std::stoi(line);
|
||||||
|
|
||||||
|
std::getline(iss, method);
|
||||||
|
|
||||||
|
while (std::getline(iss, line))
|
||||||
|
{
|
||||||
|
params.push_back(line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Request::serialize()
|
||||||
|
{
|
||||||
|
std::string msg = "eRPC 1.0\n";
|
||||||
|
|
||||||
|
msg += std::to_string(msgid) + "\n";
|
||||||
|
msg += method + "\n";
|
||||||
|
|
||||||
|
for (std::string param : params)
|
||||||
|
{
|
||||||
|
msg += param + "\n";
|
||||||
|
}
|
||||||
|
msg.pop_back();
|
||||||
|
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Request::getMsgid()
|
||||||
|
{
|
||||||
|
return msgid;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Request::getMethod()
|
||||||
|
{
|
||||||
|
return method;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> Request::getParams()
|
||||||
|
{
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
}
|
38
eRPC/Request.hpp
Normal file
38
eRPC/Request.hpp
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
#ifndef ERPC_REQUEST_HPP
|
||||||
|
#define ERPC_REQUEST_HPP
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace eRPC
|
||||||
|
{
|
||||||
|
class Request
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Construct a request with the given message ID, method, and parameters.
|
||||||
|
*/
|
||||||
|
Request(int msgid, std::string method, std::vector<std::string> params);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a request by parsing the given message.
|
||||||
|
*/
|
||||||
|
Request(std::string msg);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serialize the request to a string.
|
||||||
|
*/
|
||||||
|
std::string serialize();
|
||||||
|
|
||||||
|
int getMsgid();
|
||||||
|
std::string getMethod();
|
||||||
|
std::vector<std::string> getParams();
|
||||||
|
|
||||||
|
private:
|
||||||
|
int msgid;
|
||||||
|
std::string method;
|
||||||
|
std::vector<std::string> params;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // ERPC_REQUEST_HPP
|
61
eRPC/Response.cpp
Normal file
61
eRPC/Response.cpp
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
#include "Response.hpp"
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
namespace eRPC
|
||||||
|
{
|
||||||
|
Response::Response() : msgid(-1), ok(false), result()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Response::Response(int msgid, bool ok, std::string result)
|
||||||
|
: msgid(msgid), ok(ok), result(result)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Response::Response(std::string msg) : msgid(-1), ok(false), result()
|
||||||
|
{
|
||||||
|
std::string line;
|
||||||
|
std::istringstream iss(msg);
|
||||||
|
|
||||||
|
std::getline(iss, line);
|
||||||
|
if (line != "eRPC 1.0")
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Invalid message");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::getline(iss, line);
|
||||||
|
msgid = std::stoi(line);
|
||||||
|
|
||||||
|
std::getline(iss, line);
|
||||||
|
ok = (line == "OK");
|
||||||
|
|
||||||
|
std::getline(iss, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Response::serialize()
|
||||||
|
{
|
||||||
|
std::string msg = "eRPC 1.0\n";
|
||||||
|
|
||||||
|
msg += std::to_string(msgid) + "\n";
|
||||||
|
msg += ok ? "OK\n" : "ERROR\n";
|
||||||
|
msg += result;
|
||||||
|
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Response::getMsgid()
|
||||||
|
{
|
||||||
|
return msgid;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Response::isOk()
|
||||||
|
{
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Response::getResult()
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
39
eRPC/Response.hpp
Normal file
39
eRPC/Response.hpp
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
#ifndef ERPC_RESPONSE_HPP
|
||||||
|
#define ERPC_RESPONSE_HPP
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace eRPC
|
||||||
|
{
|
||||||
|
class Response
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Response();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a response with the given message ID, status, and result.
|
||||||
|
*/
|
||||||
|
Response(int msgid, bool ok, std::string result);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a response by parsing the given message.
|
||||||
|
*/
|
||||||
|
Response(std::string msg);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serialize the response to a string.
|
||||||
|
*/
|
||||||
|
std::string serialize();
|
||||||
|
|
||||||
|
int getMsgid();
|
||||||
|
bool isOk();
|
||||||
|
std::string getResult();
|
||||||
|
|
||||||
|
private:
|
||||||
|
int msgid;
|
||||||
|
bool ok;
|
||||||
|
std::string result;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // ERPC_RESPONSE_HPP
|
101
eRPC/Server.cpp
Normal file
101
eRPC/Server.cpp
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
#include "Server.hpp"
|
||||||
|
#include "Request.hpp"
|
||||||
|
#include "Response.hpp"
|
||||||
|
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
namespace eRPC
|
||||||
|
{
|
||||||
|
Server::Server(int port) : sockfd(-1), running(false)
|
||||||
|
{
|
||||||
|
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Failed to create socket");
|
||||||
|
}
|
||||||
|
|
||||||
|
sockaddr_in serv_addr;
|
||||||
|
serv_addr.sin_family = AF_INET;
|
||||||
|
serv_addr.sin_addr.s_addr = INADDR_ANY;
|
||||||
|
serv_addr.sin_port = htons(port);
|
||||||
|
|
||||||
|
if (bind(sockfd, (sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Failed to bind socket");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (listen(sockfd, 5) < 0)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Failed to listen on socket");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "Server listening on port " << port << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
Server::~Server()
|
||||||
|
{
|
||||||
|
stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Server::start()
|
||||||
|
{
|
||||||
|
if (running)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
running = true;
|
||||||
|
|
||||||
|
while (running)
|
||||||
|
{
|
||||||
|
std::cout << "Waiting for connection" << std::endl;
|
||||||
|
|
||||||
|
int connfd = accept(sockfd, (sockaddr *)NULL, NULL);
|
||||||
|
|
||||||
|
char buffer[1024] = {0};
|
||||||
|
read(connfd, buffer, 1024);
|
||||||
|
Request request(buffer);
|
||||||
|
std::cout << "Received request:\n"
|
||||||
|
<< request.serialize() << std::endl;
|
||||||
|
|
||||||
|
Response response;
|
||||||
|
if (methods.find(request.getMethod()) != methods.end())
|
||||||
|
{
|
||||||
|
std::function<void *()> method = methods[request.getMethod()];
|
||||||
|
method();
|
||||||
|
|
||||||
|
response = Response(
|
||||||
|
request.getMsgid(),
|
||||||
|
true,
|
||||||
|
"RESULTS HERE");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
response = Response(
|
||||||
|
request.getMsgid(),
|
||||||
|
false,
|
||||||
|
"Method \"" + request.getMethod() + "\" not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string serialized = response.serialize();
|
||||||
|
write(connfd, serialized.c_str(), serialized.size() + 1);
|
||||||
|
|
||||||
|
close(connfd);
|
||||||
|
}
|
||||||
|
|
||||||
|
close(sockfd);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Server::stop()
|
||||||
|
{
|
||||||
|
running = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Server::bindMethod(std::string method, std::function<void *()> callback)
|
||||||
|
{
|
||||||
|
methods[method] = callback;
|
||||||
|
}
|
||||||
|
}
|
45
eRPC/Server.hpp
Normal file
45
eRPC/Server.hpp
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
#ifndef ERPC_SERVER_HPP
|
||||||
|
#define ERPC_SERVER_HPP
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <functional>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
namespace eRPC
|
||||||
|
{
|
||||||
|
class Server
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Construct a server on the given port.
|
||||||
|
*/
|
||||||
|
Server(int port);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destroy the server.
|
||||||
|
*/
|
||||||
|
~Server();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start the server loop.
|
||||||
|
*/
|
||||||
|
void start();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stop the server loop.
|
||||||
|
*/
|
||||||
|
void stop();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bind a method to a callback.
|
||||||
|
*/
|
||||||
|
void bindMethod(std::string method, std::function<void *()> callback);
|
||||||
|
|
||||||
|
private:
|
||||||
|
int sockfd;
|
||||||
|
bool running;
|
||||||
|
std::unordered_map<std::string, std::function<void *()>> methods;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // ERPC_SERVER_HPP
|
Loading…
Reference in New Issue
Block a user