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

Make easywsclient injectable #31

Open
dhbaird opened this issue Sep 2, 2014 · 1 comment
Open

Make easywsclient injectable #31

dhbaird opened this issue Sep 2, 2014 · 1 comment

Comments

@dhbaird
Copy link
Owner

dhbaird commented Sep 2, 2014

Rather than have easywsclient depend directly on a specific socket implementation, instead inject the socket implementation. Reasons why this is needed:

  1. Platform support (currently resolved by using macros). Dependency injection enables more platform support without needing to resorting to macro flags. Right now, Winsock vs UNIX sockets, is determined with some macro craziness. Further, adding another layer to support SSL gets even more macro crazy. Let's just throw the macros out (mostly) and do dependency injection instead. (I don't mean to diss on macros! But this case here is not a good use of macros.)
  2. SSL (would resolve feature: Implement secure WebSocket (wss) #9 and added ssl support, fixed a bug in receiving continuation frames. #29). Dependency injection makes it possible to inject (or not) an SSL implementation. This means that the user will have the flexibility to choose OpenSSL or Mozilla NSS or anything else they want.
  3. Unit testing. Dependency injection would make it possible to formally unit test the easywsclient code itself.

Here's some pseudocode along these lines...

class Socket // just a normal TCP socket, not a websocket. This is what gets injected.
{
    // return codes follow the BSD/POSIX convention:
    enum { EWOULDBLOCK = ..., ... };
    virtual void close() = 0;
    virtual ssize_t recv(void *buf, size_t len) = 0;
    virtual ssize_t send(const void *buf, size_t len) = 0;
    virtual void select(int millisecondsTimeout) = 0;
};

class RealWebSocket : public easywsclient::WebSocket
{
    // Now inject a Socket object instead of a socket file descriptor:
    RealWebSocket(auto_ptr<Socket> socket, ...);
};

// This is the factory: the function responsible for creating and injecting all dependencies:
WebSocket::pointer WebSocket::from_url(const std::string& url, const std::string& origin)
{
    if ("wss:" == url.substr(0, 4)) {
        auto_ptr<OpenSslSocket> socket(new OpenSslSocket(...));
        return new RealWebSocket(socket, ...);
    }
    else { // assume ws:
        #ifdef _WIN32
        auto_ptr<WinsockSocket> socket(new WinsockSocket(...));
        #else
        auto_ptr<PosixSocket> socket(new PosixSocket(...));
        #endif
        return new RealWebSocket(socket, ...);
    }
}

New to dependency injection? Miško Hevery explains it best: The Clean Code Talks - Don't Look For Things!. It is also described on the Wikipedia SOLID page.

@NozzerFX
Copy link

Hi @dhbaird, many thanks for this. I've been trying to use a different C++ lib for this using ASIO but its been a ball ache to implement. It has optional boost support I I dont want to use boost in my VS2017 project. I've got over the issues because boost support can be removed and standalone ASIO can be used. The issue I've had is linking to OpenSSL. I just cannot get it working in ASIO. I've tried multiple different versions et-al. This library looks awesome, but I need to inject OpenSSL. The sample is cool, but did you get this working? How did you get OpenSSL linked in? I would really appreciate some advice because I've never hooked in OpenSSL before. What version did you get working, what libs and headers, and what headers do I need for the above code snippet? Any advice would be extremely appreciated.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants