void Connection::write(uint8* buffer, uint16 size)
{
    if(!m_connected)
        return;

    // send old buffer if we can't add more data
    if(m_sendBufferSize + size >= SEND_BUFFER_SIZE && m_sendEvent)
        m_sendEvent->execute();

    // we can't send the data right away, otherwise we could create tcp congestion
    memcpy(m_sendBuffer + m_sendBufferSize, buffer, size);
    m_sendBufferSize += size;

    if(!m_sendEvent || m_sendEvent->isExecuted() || m_sendEvent->isCanceled()) {
        auto weakSelf = ConnectionWeakPtr(shared_from_this());

        // wait 1 ms to do the real send
        m_sendEvent = g_dispatcher.scheduleEvent([=] {
            if(!weakSelf.lock())
                return;
            //m_writeTimer.cancel();

            asio::async_write(m_socket,
                              asio::buffer(m_sendBuffer, m_sendBufferSize),
                              std::bind(&Connection::onWrite, shared_from_this(), std::placeholders::_1, std::placeholders::_2));

            m_writeTimer.expires_from_now(boost::posix_time::seconds(WRITE_TIMEOUT));
            m_writeTimer.async_wait(std::bind(&Connection::onTimeout, shared_from_this(), std::placeholders::_1));

            m_sendBufferSize = 0;
        }, SEND_INTERVAL);
    }
}
void Connection::connect(const std::string& host, uint16 port, const std::function<void()>& connectCallback)
{
    m_connected = false;
    m_connecting = true;
    m_error.clear();
    m_connectCallback = connectCallback;

    asio::ip::tcp::resolver::query query(host, stdext::unsafe_cast<std::string>(port));

    auto weakSelf = ConnectionWeakPtr(shared_from_this());
    m_resolver.async_resolve(query, [=](const boost::system::error_code& error, asio::ip::tcp::resolver::iterator endpointIterator) {
        if(!weakSelf.lock())
            return;
        m_readTimer.cancel();

        if(!error) {
            m_socket.async_connect(*endpointIterator, std::bind(&Connection::onConnect, shared_from_this(), std::placeholders::_1));

            m_readTimer.expires_from_now(boost::posix_time::seconds(READ_TIMEOUT));
            m_readTimer.async_wait(std::bind(&Connection::onTimeout, shared_from_this(), std::placeholders::_1));
        } else
            handleError(error);
    });

    m_readTimer.expires_from_now(boost::posix_time::seconds(READ_TIMEOUT));
    m_readTimer.async_wait(std::bind(&Connection::onTimeout, shared_from_this(), std::placeholders::_1));
}
UserConnection::UserConnection(Urho3D::Context* context, ConnectionPtr connection_) :
    Tundra::UserConnection(context),
    webSocketConnection(ConnectionWeakPtr(connection_))
{
}