Skip to content

Commit

Permalink
Refactoring AutoNetTransport concept
Browse files Browse the repository at this point in the history
Better to have the transport in a separate file if it's a separate class.  Also flipped a link that was making use of std::function in preference of an explicit interface, which seems to be more appropriate in this case.
  • Loading branch information
codemercenary committed Feb 5, 2015
1 parent 697e390 commit 30936da
Show file tree
Hide file tree
Showing 6 changed files with 187 additions and 129 deletions.
38 changes: 31 additions & 7 deletions autowiring/AutoNetServer.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,42 @@
#include STL_UNORDERED_MAP
#include FUNCTIONAL_HEADER

class AutoNetTransport {
class AutoNetTransportHandler {
public:
typedef std::weak_ptr<void> connection_hdl;


virtual void OnOpen(connection_hdl handle) = 0;
virtual void OnClose(connection_hdl handle) = 0;
virtual void OnMessage(connection_hdl handle, const std::string& message) = 0;
};

/// <summary>
/// Represents a transport implementation that carries AutoNet data to a visualizer client
/// </summary>
class AutoNetTransport {
public:
/// <summary>
/// Causes the transport to begin servicing user requests
/// </summary>
virtual void Start(void) = 0;

/// <summary>
/// Causes the transport to stop servicing user requests, also shuts down any active connections
/// </summary>
virtual void Stop(void) = 0;

/// <summary>
/// Transmits the specified string message to the remote host
/// </summary>
virtual void Send(AutoNetTransportHandler::connection_hdl hdl, const std::string& msg) = 0;

virtual void Send(connection_hdl hdl, const std::string& msg) = 0;

virtual void OnOpen(std::function<void(connection_hdl)> fn) = 0;
virtual void OnClose(std::function<void(connection_hdl)> fn) = 0;
virtual void OnMessage(std::function<void(connection_hdl, std::string)> fn) = 0;
/// <summary>
/// Assigns the handler for operations occuring on this transport
/// </summary>
/// <remarks>
/// This routine accepts a nullptr argument, the effect will be to clear the current handler
/// </remarks>
virtual void SetTransportHandler(std::shared_ptr<AutoNetTransportHandler> handler) = 0;
};

class AutoNetServer;
Expand Down
94 changes: 14 additions & 80 deletions src/autonet/AutoNetServerImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "AutoNetServerImpl.hpp"
#include "at_exit.h"
#include "autowiring.h"
#include "AutoNetTransportHttp.hpp"
#include "demangle.h"
#include "ObjectTraits.h"
#include "EventRegistry.h"
Expand All @@ -12,88 +13,18 @@

using json11::Json;

////
//// Default AutoNet transport layer implementation
////
#ifdef _MSC_VER
// Because Windows is dumb
#undef SendMessage
#endif

DefaultAutoNetTransport::DefaultAutoNetTransport(void):
m_port(8000)
{
m_server.init_asio();
m_server.set_access_channels(websocketpp::log::alevel::none);
m_server.set_error_channels(websocketpp::log::elevel::none);
}

DefaultAutoNetTransport::~DefaultAutoNetTransport(void){}

void DefaultAutoNetTransport::Start(void) {
m_server.listen(m_port);
m_server.start_accept();
m_server.run();
}

void DefaultAutoNetTransport::Stop(void) {
if (m_server.is_listening())
m_server.stop_listening();

for (auto& conn : m_connections)
m_server.close(conn, websocketpp::close::status::normal, "closed");
}

void DefaultAutoNetTransport::Send(connection_hdl hdl, const std::string& msg){
m_server.send(hdl, msg, websocketpp::frame::opcode::text);
}

void DefaultAutoNetTransport::OnOpen(std::function<void(connection_hdl)> fn) {
m_server.set_open_handler([this, fn] (connection_hdl hdl) {
(std::lock_guard<std::mutex>)m_lock,
m_connections.insert(hdl);

fn(hdl);
});
}

void DefaultAutoNetTransport::OnClose(std::function<void(connection_hdl)> fn) {
m_server.set_close_handler([this, fn] (connection_hdl hdl) {
(std::lock_guard<std::mutex>)m_lock,
m_connections.erase(hdl);

fn(hdl);
});
}
AutoNetServerImpl::AutoNetServerImpl(void):
AutoNetServerImpl(std::unique_ptr<AutoNetTransportHttp>(new AutoNetTransportHttp))
{}

void DefaultAutoNetTransport::OnMessage(std::function<void(connection_hdl, std::string)> fn) {
m_server.set_message_handler([fn](websocketpp::connection_hdl hdl, message_ptr message){
std::string msg = message->get_payload();
fn(hdl, msg);
});
}

////
//// AutoNetServer implementation
////

AutoNetServerImpl::AutoNetServerImpl(std::unique_ptr<AutoNetTransport> transport) :
AutoNetServerImpl::AutoNetServerImpl(std::unique_ptr<AutoNetTransport>&& transport) :
m_transport(std::move(transport))
{

// Register handlers
m_transport->OnOpen([this] (AutoNetTransport::connection_hdl hdl) {
*this += [this, hdl] {
SendMessage(hdl, "opened");
};
});

m_transport->OnClose([this] (AutoNetTransport::connection_hdl hdl) {
*this += [this, hdl] {
this->m_Subscribers.erase(hdl);
};
});

m_transport->OnMessage([this](AutoNetTransport::connection_hdl hdl, std::string payload) {
OnMessage(hdl, payload);
});

{
// Register internal event handlers
AddEventHandler("terminateContext", [this] (int contextID) {
ResolveContextID(contextID)->SignalShutdown();
Expand Down Expand Up @@ -143,6 +74,9 @@ AutoNetServer* NewAutoNetServerImpl(void) {
void AutoNetServerImpl::Run(void){
std::cout << "Starting Autonet server..." << std::endl;

// Register ourselves as a handler
m_transport->SetTransportHandler(std::static_pointer_cast<AutoNetServerImpl>(shared_from_this()));

// blocks until the server finishes
auto websocket = std::async(std::launch::async, [this]{
m_transport->Start();
Expand All @@ -156,7 +90,7 @@ void AutoNetServerImpl::OnStop(void) {
m_transport->Stop();
}

void AutoNetServerImpl::OnMessage(AutoNetTransport::connection_hdl hdl, std::string payload) {
void AutoNetServerImpl::OnMessage(AutoNetTransportHandler::connection_hdl hdl, const std::string& payload) {
// Parse string from client
std::string err;
Json msg = Json::parse(payload, err);
Expand Down
66 changes: 24 additions & 42 deletions src/autonet/AutoNetServerImpl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,54 +14,36 @@
#define BOOST_NO_CXX11_HDR_INITIALIZER_LIST
#endif

// Need to redefine this namespace so we don't create linker problems. Such problems may be
// created if our static library is imported by another project that uses an incompatible
// version of websocketpp.
#define websocketpp websocketpp_autonet
#include <websocketpp/server.hpp>
#include <websocketpp/config/asio_no_tls.hpp>

struct ObjectTraits;
struct TypeIdentifierBase;

//// Default transport layer for AutoNet
class DefaultAutoNetTransport:
public AutoNetTransport
{
public:
DefaultAutoNetTransport();
virtual ~DefaultAutoNetTransport();

void Start(void);
void Stop(void);

void Send(connection_hdl hdl, const std::string& msg);

void OnOpen(std::function<void(connection_hdl)> fn);
void OnClose(std::function<void(connection_hdl)> fn);
void OnMessage(std::function<void(connection_hdl, std::string)> fn);

private:
typedef websocketpp::server<websocketpp::config::asio> t_server;
typedef t_server::message_ptr message_ptr;

std::mutex m_lock;
std::set<connection_hdl, std::owner_less<AutoNetTransport::connection_hdl>> m_connections;
int m_port;
t_server m_server;
};

// Protocol layer for AutoNet
class AutoNetServerImpl:
public AutoNetServer,
public virtual AutowiringEvents
public AutowiringEvents,
public AutoNetTransportHandler
{
public:
AutoNetServerImpl(std::unique_ptr<AutoNetTransport> = std::make_unique<DefaultAutoNetTransport>());
/// <summary>
/// Constructs an AutoNet server with the default HTTP transport mechanism
/// </summary>
AutoNetServerImpl(void);

/// <summary>
/// Constructs an AutoNet server with the specified transport
/// </summary>
AutoNetServerImpl(std::unique_ptr<AutoNetTransport>&& transport);
~AutoNetServerImpl();

// Handle websocket messages
void OnMessage(AutoNetTransport::connection_hdl hdl, std::string payload);
void OnOpen(connection_hdl handle) override {
}
void OnClose(connection_hdl handle) override {
*this += [this, handle] {
this->m_Subscribers.erase(handle);
};
}
void OnMessage(AutoNetTransportHandler::connection_hdl hdl, const std::string& payload) override;

// Functions from BasicThread
virtual void Run(void) override;
Expand Down Expand Up @@ -101,7 +83,7 @@ class AutoNetServerImpl:
/// Client callback with same number of arguments passed here will be called
/// </remarks>
template<typename... Args>
void SendMessage(AutoNetTransport::connection_hdl hdl, const char* p_type, Args&&... args){
void SendMessage(AutoNetTransportHandler::connection_hdl hdl, const char* p_type, Args&&... args) {
using json11::Json;

Json msg = Json::object{
Expand All @@ -119,7 +101,7 @@ class AutoNetServerImpl:
/// <param name="args...">An arg to be passed to client side event handler</param>
template<typename ...Args>
void BroadcastMessage(const char* p_type, Args&&... args) {
for(AutoNetTransport::connection_hdl ptr : m_Subscribers)
for(auto ptr : m_Subscribers)
SendMessage(ptr, p_type, std::forward<Args>(args)...);
}

Expand All @@ -130,13 +112,13 @@ class AutoNetServerImpl:
/// Called when a "Subscribe" event is sent from a client
/// </summary>
/// <param name="client">Client that sent event</param>
void HandleSubscribe(AutoNetTransport::connection_hdl hdl);
void HandleSubscribe(AutoNetTransportHandler::connection_hdl hdl);

/// <summary>
/// Called when a "Unsubscribe" event is sent from a client
/// </summary>
/// <param name="client">Client that sent event</param>
void HandleUnsubscribe(AutoNetTransport::connection_hdl hdl);
void HandleUnsubscribe(AutoNetTransportHandler::connection_hdl hdl);

/// <summary>
/// Assigns each context a unique ID number
Expand All @@ -156,7 +138,7 @@ class AutoNetServerImpl:
*******************************************/

// Set of all subscribers
std::set<AutoNetTransport::connection_hdl, std::owner_less<AutoNetTransport::connection_hdl>> m_Subscribers;
std::set<AutoNetTransportHandler::connection_hdl, std::owner_less<AutoNetTransportHandler::connection_hdl>> m_Subscribers;

// one-to-one map of contexts to integers
std::map<CoreContext*, int> m_ContextIDs;
Expand Down
68 changes: 68 additions & 0 deletions src/autonet/AutoNetTransportHttp.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// Copyright (C) 2012-2015 Leap Motion, Inc. All rights reserved.
#include "stdafx.h"
#include "AutoNetTransportHttp.hpp"

AutoNetTransportHttp::AutoNetTransportHttp(void) :
m_port(8000)
{
m_server.init_asio();
m_server.set_access_channels(websocketpp::log::alevel::none);
m_server.set_error_channels(websocketpp::log::elevel::none);


m_server.set_open_handler([this](connection_hdl hdl) {
auto handler =
(
(std::lock_guard<std::mutex>)m_lock,
m_connections.insert(hdl),
m_handler
);
if (m_handler)
m_handler->OnOpen(hdl);
});

m_server.set_close_handler([this](connection_hdl hdl) {
auto handler =
(
(std::lock_guard<std::mutex>)m_lock,
m_connections.erase(hdl),
m_handler
);

m_handler->OnClose(hdl);
});

m_server.set_message_handler([this](websocketpp::connection_hdl hdl, message_ptr message){
auto handler = ((std::lock_guard<std::mutex>)m_lock, m_handler);

std::string msg = message->get_payload();
handler->OnMessage(hdl, msg);
});
}

AutoNetTransportHttp::~AutoNetTransportHttp(void)
{
}

void AutoNetTransportHttp::Start(void) {
m_server.listen(m_port);
m_server.start_accept();
m_server.run();
}

void AutoNetTransportHttp::Stop(void) {
if (m_server.is_listening())
m_server.stop_listening();

for (auto& conn : m_connections)
m_server.close(conn, websocketpp::close::status::normal, "closed");
}

void AutoNetTransportHttp::Send(connection_hdl hdl, const std::string& msg){
m_server.send(hdl, msg, websocketpp::frame::opcode::text);
}

void AutoNetTransportHttp::SetTransportHandler(std::shared_ptr<AutoNetTransportHandler> handler) {
std::lock_guard<std::mutex> lk(m_lock);
m_handler = handler;
}
Loading

0 comments on commit 30936da

Please sign in to comment.