Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

server and client websocket closing #43

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions client/dfclient/include/game_data.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@ struct GameData {
std::vector<Player> players;
std::string levelData;
bool gameInProgress = false;

WebSocket* socket = nullptr;
};

extern GameData gameData;
13 changes: 5 additions & 8 deletions client/dfclient/include/websocket.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@

struct WebSocket {
virtual int Connect(std::string& address) = 0;
virtual bool Send(std::string& data) = 0;
virtual bool Send(const std::string& data) = 0;
virtual void Close() = 0;
virtual ~WebSocket() {}

// TODO use lock-free queue instead?
Expand All @@ -19,12 +20,8 @@ struct WebSocket {
std::vector<std::string> messageQueue;
};

struct WebSocketManager {
Messages GetMessages();
Messages GetMessages();

std::unique_ptr<WebSocket> _ws;
};

WebSocket* CreateWebSocket();
void CreateWebSocket();

extern WebSocketManager webSocketManager;
extern std::unique_ptr<WebSocket> GlobalWebsocket;
7 changes: 4 additions & 3 deletions client/dfclient/src/menu_state.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ void MenuState::ShowMessage(std::string message)
[text] (tweeny::tween<int>& t, int v) -> bool {
auto textColor = text->color();
text->setColor(textColor.r(), textColor.g(), textColor.b(), v);
std::cout << "v " << v << "\n";
if (v == 0)
delete text;
return false;
Expand All @@ -61,6 +60,8 @@ MenuState::MenuState(Resources& r) : _resources(r) {
TextCreator textCreator(r);
std::cout << "menu game in progress\n";
ShowMessage("game already in progress");
GlobalWebsocket->Close();
GlobalWebsocket = nullptr;
gameData.gameInProgress = false;
}
boost::property_tree::ptree pt;
Expand Down Expand Up @@ -91,8 +92,8 @@ MenuState::MenuState(Resources& r) : _resources(r) {
void MenuState::TryConnect() {
gameData.serverAddress = "ws://" + gameData.serverAddress;
std::cout << "server " << gameData.serverAddress << ", my nickname " << gameData.myNickname << "\n";
gameData.socket = CreateWebSocket();
int ret = gameData.socket->Connect(gameData.serverAddress);
CreateWebSocket();
int ret = GlobalWebsocket->Connect(gameData.serverAddress);
if (ret < 0) {
std::cout << "socket->Connect failed " << ret << "\n";
this->ShowMessage("connecting to server failed");
Expand Down
2 changes: 1 addition & 1 deletion client/dfclient/src/state_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ TextCreator StateManager::CreateTextCreator() {
void StateManager::OnFrameStart() {
_resources.UpdateTweens();

auto nextStateType = _currentState->Update(webSocketManager.GetMessages());
auto nextStateType = _currentState->Update(GetMessages());
if (nextStateType == _currentStateType) {
return;
}
Expand Down
2 changes: 1 addition & 1 deletion client/dfclient/src/util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ void SendData(flatbuffers::FlatBufferBuilder& builder) {
auto size = builder.GetSize();
auto str = std::string(data, data + size);

gameData.socket->Send(str);
GlobalWebsocket->Send(str);
}

std::vector<nc::Vector2f> createArcTexels(float outerRadius, float innerRadius, int degrees)
Expand Down
113 changes: 73 additions & 40 deletions client/dfclient/src/websocket.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,21 @@

#include <iostream>

WebSocketManager webSocketManager;
std::unique_ptr<WebSocket> GlobalWebsocket;

// Runs in game loop thread
Messages WebSocketManager::GetMessages() {
Messages GetMessages() {
Messages m;
if (!_ws) {
if (!GlobalWebsocket) {
return m;
}

std::lock_guard<std::mutex> guard(_ws->mq_mutex);
m.opened = _ws->toBeOpened;
m.data_msgs.swap(_ws->messageQueue);
std::lock_guard<std::mutex> guard(GlobalWebsocket->mq_mutex);
m.opened = GlobalWebsocket->toBeOpened;
m.data_msgs.swap(GlobalWebsocket->messageQueue);

if (m.opened) {
_ws->toBeOpened = false;
GlobalWebsocket->toBeOpened = false;
}

return m;
Expand All @@ -30,7 +30,8 @@ class WebSocketEmscripten
{
public:
int Connect(std::string& address) override;
bool Send(std::string& data) override;
bool Send(const std::string& data) override;
void Close() override;
virtual ~WebSocketEmscripten() {}

EMSCRIPTEN_WEBSOCKET_T _socket;
Expand Down Expand Up @@ -84,28 +85,26 @@ int WebSocketEmscripten::Connect(std::string& address) {
return 0;
}

bool WebSocketEmscripten::Send(std::string& data) {
return emscripten_websocket_send_binary(this->_socket, data.data(), data.size()) == EMSCRIPTEN_RESULT_SUCCESS;
bool WebSocketEmscripten::Send(const std::string& data) {
return emscripten_websocket_send_binary(this->_socket, (void*) data.data(), data.size()) == EMSCRIPTEN_RESULT_SUCCESS;
}

#else // __EMSCRIPTEN__
void WebSocketEmscripten::Close() {
std::cout << "TODO implement\n";
exit(1);
}

class WebSocketBeast
: public WebSocket
{
public:
int Connect(std::string& address) override;
bool Send(std::string& data) override;
virtual ~WebSocketBeast() {}
#else // __EMSCRIPTEN__

};
class WebSocketBeast;

typedef WebSocketBeast WebSocketType;

#include <boost/beast/core.hpp>
#include <boost/beast/websocket.hpp>
#include <boost/asio/connect.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/beast/core.hpp>
#include <boost/beast/websocket.hpp>
#include <boost/exception/diagnostic_information.hpp>
#include <cstdlib>
#include <iostream>
#include <string>
Expand All @@ -117,9 +116,22 @@ namespace websocket = beast::websocket; // from <boost/beast/websocket.hpp>
namespace net = boost::asio; // from <boost/asio.hpp>
using tcp = boost::asio::ip::tcp; // from <boost/asio/ip/tcp.hpp>

net::io_context ioc;
websocket::stream<tcp::socket> ws{ioc};
beast::flat_buffer buffer;
struct beastContext {
net::io_context ioc;
websocket::stream<tcp::socket> ws{ioc};
beast::flat_buffer buffer;
};

class WebSocketBeast
: public WebSocket
{
public:
int Connect(std::string& address) override;
bool Send(const std::string& data) override;
void Close() override;
virtual ~WebSocketBeast() {}
beastContext ctx;
};

void DoRead();

Expand All @@ -131,27 +143,32 @@ void OnRead(beast::error_code ec, std::size_t bytes_transferred) {
if (ec.value() == boost::system::errc::operation_canceled) {
// this websocket has disconnected
// todo: cleanup whatever is happening and return to main menu
std::cout << "operation canceled\n";
return;
}
std::cout << "read failed " << ec << "\n";
}

auto str = beast::buffers_to_string(buffer.data());
WebSocketBeast* wsb = (WebSocketBeast*) webSocketManager._ws.get();
WebSocketBeast* wsb = (WebSocketBeast*) GlobalWebsocket.get();
auto str = beast::buffers_to_string(wsb->ctx.buffer.data());
std::lock_guard<std::mutex> guard(wsb->mq_mutex);
wsb->messageQueue.push_back(str);
buffer.consume(buffer.size());
wsb->ctx.buffer.consume(wsb->ctx.buffer.size());
DoRead();
}

void DoRead() {
ws.async_read(buffer, &OnRead);
WebSocketBeast* wsb = (WebSocketBeast*) GlobalWebsocket.get();
wsb->ctx.ws.async_read(wsb->ctx.buffer, &OnRead);
}

int WebSocketBeast::Connect(std::string& fullAddress) {
tcp::resolver resolver{ioc};

ws.binary(true);
WebSocketBeast* wsb = (WebSocketBeast*) GlobalWebsocket.get();

tcp::resolver resolver{wsb->ctx.ioc};

wsb->ctx.ws.binary(true);

auto address = fullAddress.substr(std::string("ws://").size(), fullAddress.size());

Expand All @@ -164,38 +181,54 @@ int WebSocketBeast::Connect(std::string& fullAddress) {
auto port = address.substr(colon + 1, address.size());
auto const results = resolver.resolve(host, port);
try {
auto ep = net::connect(ws.next_layer(), results);
auto ep = net::connect(wsb->ctx.ws.next_layer(), results);
host += ':' + std::to_string(ep.port());
ws.set_option(websocket::stream_base::decorator(
wsb->ctx.ws.set_option(websocket::stream_base::decorator(
[](websocket::request_type& req)
{
req.set(http::field::user_agent,
std::string(BOOST_BEAST_VERSION_STRING) +
" websocket-client-coro");
}));
ws.handshake(host, "/");
wsb->ctx.ws.handshake(host, "/");
} catch (std::exception e) {
return -1;
}

webSocketManager._ws->toBeOpened = true;
GlobalWebsocket->toBeOpened = true;

DoRead();

new std::thread([&](){
ioc.run();
try {
wsb->ctx.ioc.run();
} catch (const boost::exception& e) {
std::cout << "wsb->ctx.ioc.run() failed: " << boost::diagnostic_information(e) << "\n";
}
std::cout << "ioc quitting\n";
});

return 0;
}

bool WebSocketBeast::Send(std::string& data) {
ws.write(net::buffer(std::string(data)));
bool WebSocketBeast::Send(const std::string& data) {
WebSocketBeast* wsb = (WebSocketBeast*) GlobalWebsocket.get();
wsb->ctx.ws.write(net::buffer(std::string(data)));
}

void WebSocketBeast::Close() {
WebSocketBeast* wsb = (WebSocketBeast*) GlobalWebsocket.get();
try {
wsb->ctx.ws.close(websocket::close_code::normal);
} catch (const std::exception& ex) {
std::cout << "exception occured while closing websocket: " << ex.what() << std::endl;
} catch (...) {
std::cout << "an unknown exception occured while closing websocket" << std::endl;
}
}

#endif

WebSocket* CreateWebSocket() {
webSocketManager._ws = std::make_unique<WebSocketType>();
return webSocketManager._ws.get();
void CreateWebSocket() {
GlobalWebsocket = std::make_unique<WebSocketType>(); // this deletes the old one
}
3 changes: 2 additions & 1 deletion server/game_thread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@ std::string makeServerMessage(flatbuffers::FlatBufferBuilder &builder,

void sendGameAlreadyInProgress(dfws::Handle hdl)
{
std::cout << "sending game already in progress";
flatbuffers::FlatBufferBuilder builder;
auto offset = FlatBuffGenerated::CreateSimpleServerEvent(builder,
FlatBuffGenerated::SimpleServerEventType_GameAlreadyInProgress);
Expand Down Expand Up @@ -510,7 +509,9 @@ void gameOnMessage(dfws::Handle hdl, const std::string& payload)

auto p = getPlayerByConnHdl(hdl);
if (!p) {
std::cout << "gameOnMessage: game already in progress\n";
sendGameAlreadyInProgress(hdl);
dfws::Close(hdl);
return;
}
if (p->state == MobState::ATTACKING)
Expand Down
39 changes: 30 additions & 9 deletions server/websocket.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -141,26 +141,46 @@ class DfWebsocket : public std::enable_shared_from_this<DfWebsocket> {
// sync write
ws_.write(net::buffer(data));
}

void Close() {
ws_.close(websocket::close_code::normal);
}
};

void dfws::SendData(Handle hdl, const std::string& data)
std::shared_ptr<DfWebsocket> getSocketForHandle(dfws::Handle hdl)
{
for (auto& s : sockets) {
if (s->socketID_ == hdl) {
s->Send(data);
return;
}
auto it = std::find_if(sockets.begin(), sockets.end(), [&] (const auto& s) {
return s->socketID_ == hdl;
});
if (it == sockets.end()) {
std::cout << "could not find socket with id " << hdl << "\n";
exit(1);
}
std::cout << "could not find socket with id " << hdl << "\n";
exit(1);
return *it;
}

void dfws::SendData(Handle hdl, const std::string& data)
{
auto s = getSocketForHandle(hdl);
s->Send(data);
}

void dfws::Close(Handle hdl)
{
std::cout << "closing handle " << hdl << "\n";
auto it = std::find_if(sockets.begin(), sockets.end(), [&] (const auto& s) {
return s->socketID_ == hdl;
});
(*it)->Close();
sockets.erase(it);
}

void dfwsOnAccept(beast::error_code ec, tcp::socket socket)
{
std::cout << "on accept\n";
if (ec)
return fail(ec, "accept");
// websocket::stream<beast::tcp_stream> ws_(std::move(socket));

auto socketPtr = std::make_shared<DfWebsocket>(std::move(socket), lastSocketID++);
sockets.push_back(socketPtr);
sockets.back()->start();
Expand Down Expand Up @@ -210,4 +230,5 @@ void dfws::Run(unsigned short port)

acceptor.async_accept(&dfwsOnAccept);
ioc.run();
std::cout << "ioc quitting\n";
}
1 change: 1 addition & 0 deletions server/websocket.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,6 @@ void SetOnMessage(OnMessageHandler msgHandler);
void SetOnOpen(OnOpenHandler handler);
void SetOnClose(OnCloseHandler handler);
void Run(unsigned short port);
void Close(Handle hdl);

};