WCF (Websocket Communication Foundation) - a skeleton for websocket transport
This commit is contained in:
Родитель
05101d3f68
Коммит
6f089a3934
|
@ -101,6 +101,7 @@
|
|||
<ClInclude Include="..\..\stdafx.h" />
|
||||
<ClInclude Include="..\..\targetver.h" />
|
||||
<ClInclude Include="..\..\url_builder.h" />
|
||||
<ClInclude Include="..\..\websocket_transport.h" />
|
||||
<ClInclude Include="..\..\web_request_factory.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
|
|
@ -60,6 +60,9 @@
|
|||
<ClInclude Include="..\..\request_sender.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\websocket_transport.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\stdafx.cpp">
|
||||
|
|
|
@ -17,7 +17,7 @@ namespace signalr
|
|||
m_user_agent_string = user_agent_string;
|
||||
}
|
||||
|
||||
pplx::task<web_response> web_request::get_response() const
|
||||
pplx::task<web_response> web_request::get_response()
|
||||
{
|
||||
web::http::client::http_client client(m_url);
|
||||
web::http::http_request request(m_method);
|
||||
|
|
|
@ -0,0 +1,95 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
#include <cpprest/ws_client.h>
|
||||
#include "url_builder.h"
|
||||
|
||||
using namespace web::experimental;
|
||||
|
||||
namespace signalr
|
||||
{
|
||||
template<typename T = web_sockets::client::websocket_client> // testing
|
||||
class websocket_transport
|
||||
{
|
||||
public:
|
||||
websocket_transport() : websocket_transport(T())
|
||||
{ }
|
||||
|
||||
websocket_transport(T&& websocket_client)
|
||||
: m_websocket_client(std::move(websocket_client))
|
||||
{ }
|
||||
|
||||
websocket_transport(T websocket_client)
|
||||
: m_websocket_client(websocket_client)
|
||||
{ }
|
||||
|
||||
websocket_transport(const websocket_transport&) = delete;
|
||||
|
||||
websocket_transport<T>& operator=(const websocket_transport&) = delete;
|
||||
|
||||
pplx::task<void> connect(const web::uri &url)
|
||||
{
|
||||
// TODO: prepare request (websocket_client_config)
|
||||
|
||||
m_websocket_client.connect(url)
|
||||
.then([this](pplx::task<void> connect_task){
|
||||
try
|
||||
{
|
||||
connect_task.wait();
|
||||
receive_loop();
|
||||
this->m_connect_tce.set();
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
this->m_connect_tce.set_exception(e);
|
||||
}
|
||||
});
|
||||
|
||||
return pplx::create_task(m_connect_tce);
|
||||
}
|
||||
|
||||
pplx::task<void> send(const utility::string_t &data)
|
||||
{
|
||||
web_sockets::client::websocket_outgoing_message msg;
|
||||
msg.set_utf8_message(utility::conversions::to_utf8string(data));
|
||||
|
||||
// send will throw if client not connected
|
||||
return m_websocket_client.send(msg);
|
||||
}
|
||||
|
||||
pplx::task<void> disconnect()
|
||||
{
|
||||
return m_websocket_client.close();
|
||||
}
|
||||
|
||||
private:
|
||||
T m_websocket_client;
|
||||
|
||||
pplx::task_completion_event<void> m_connect_tce;
|
||||
|
||||
void receive_loop()
|
||||
{
|
||||
m_websocket_client.receive().then([this](pplx::task<web_sockets::client::websocket_incoming_message> msg_task)
|
||||
{
|
||||
try
|
||||
{
|
||||
auto msg = msg_task.get();
|
||||
msg.extract_string().then([this](std::string msg_body)
|
||||
{
|
||||
receive_loop();
|
||||
});
|
||||
}
|
||||
catch (web_sockets::client::websocket_exception &)
|
||||
{
|
||||
// TODO: should close the websocket?
|
||||
// TODO: report error
|
||||
}
|
||||
catch (std::exception &)
|
||||
{
|
||||
// TODO: should close the websocket?
|
||||
// TODO: report error
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
|
@ -98,6 +98,7 @@
|
|||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\url_builder_tests.cpp" />
|
||||
<ClCompile Include="..\..\websocket_transport_tests.cpp" />
|
||||
<ClCompile Include="..\..\web_request_tests.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
|
|
@ -47,6 +47,9 @@
|
|||
<ClCompile Include="..\..\web_request_tests.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\websocket_transport_tests.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
|
|
|
@ -0,0 +1,148 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "websocket_transport.h"
|
||||
|
||||
using namespace signalr;
|
||||
using namespace web::experimental;
|
||||
|
||||
class test_websocket_client
|
||||
{
|
||||
public:
|
||||
|
||||
pplx::task<void> connect(const web::uri &url)
|
||||
{
|
||||
return m_connect_function(url);
|
||||
}
|
||||
|
||||
pplx::task<void> send(web_sockets::client::websocket_outgoing_message msg)
|
||||
{
|
||||
return m_send_function(msg);
|
||||
}
|
||||
|
||||
pplx::task<web_sockets::client::websocket_incoming_message> receive()
|
||||
{
|
||||
return m_receive_function();
|
||||
}
|
||||
|
||||
pplx::task<void> close()
|
||||
{
|
||||
return m_close_function();
|
||||
}
|
||||
|
||||
void set_connect_function(std::function<pplx::task<void>(const web::uri &url)> connect_function)
|
||||
{
|
||||
m_connect_function = connect_function;
|
||||
}
|
||||
|
||||
void set_send_function(std::function<pplx::task<void>(web_sockets::client::websocket_outgoing_message)> send_function)
|
||||
{
|
||||
m_send_function = send_function;
|
||||
}
|
||||
|
||||
void set_receive_function(std::function<pplx::task<web_sockets::client::websocket_incoming_message>()> receive_function)
|
||||
{
|
||||
m_receive_function = receive_function;
|
||||
}
|
||||
|
||||
void set_close_function(std::function<pplx::task<void>()> close_function)
|
||||
{
|
||||
m_close_function = close_function;
|
||||
}
|
||||
|
||||
private:
|
||||
std::function<pplx::task<void>(const web::uri &url)> m_connect_function
|
||||
= [](const web::uri &){ return pplx::task_from_result(); };
|
||||
|
||||
std::function<pplx::task<void>(web_sockets::client::websocket_outgoing_message)> m_send_function
|
||||
= [](web_sockets::client::websocket_outgoing_message msg){ return pplx::task_from_result(); };
|
||||
|
||||
std::function<pplx::task<web_sockets::client::websocket_incoming_message>()> m_receive_function
|
||||
= [](){ return pplx::task_from_result(web_sockets::client::websocket_incoming_message()); };
|
||||
|
||||
std::function<pplx::task<void>()> m_close_function
|
||||
= [](){ return pplx::task_from_result(); };
|
||||
};
|
||||
|
||||
TEST(websocket_transport_connect, connect_connects_and_starts_receive_loop)
|
||||
{
|
||||
bool connect_called = false, receive_called = false;
|
||||
|
||||
test_websocket_client client;
|
||||
client.set_connect_function([&connect_called](const web::uri &) -> pplx::task<void>
|
||||
{
|
||||
connect_called = true;
|
||||
return pplx::task_from_result();
|
||||
});
|
||||
|
||||
client.set_receive_function([&receive_called]() -> pplx::task<web_sockets::client::websocket_incoming_message>
|
||||
{
|
||||
receive_called = true;
|
||||
return pplx::task_from_result(web_sockets::client::websocket_incoming_message());
|
||||
});
|
||||
|
||||
websocket_transport<test_websocket_client> ws_transport(client);
|
||||
|
||||
ws_transport.connect(_XPLATSTR("http://fakeuri.org")).wait();
|
||||
|
||||
ASSERT_TRUE(connect_called);
|
||||
ASSERT_TRUE(receive_called);
|
||||
}
|
||||
|
||||
TEST(websocket_transport_connect, connect_propagates_exceptions)
|
||||
{
|
||||
test_websocket_client client;
|
||||
client.set_connect_function([](const web::uri &) -> pplx::task<void>
|
||||
{
|
||||
throw web_sockets::client::websocket_exception(_XPLATSTR("connecting failed"));
|
||||
});
|
||||
|
||||
websocket_transport<test_websocket_client> ws_transport(client);
|
||||
|
||||
try
|
||||
{
|
||||
ws_transport.connect(_XPLATSTR("http://fakeuri.org")).wait();
|
||||
ASSERT_TRUE(false); // exception not thrown
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
ASSERT_STREQ("connecting failed", e.what());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(websocket_transport_send, send_creates_and_sends_websocket_messages)
|
||||
{
|
||||
bool send_called = false;
|
||||
|
||||
test_websocket_client client;
|
||||
client.set_send_function([&send_called](web_sockets::client::websocket_outgoing_message msg) -> pplx::task<void>
|
||||
{
|
||||
send_called = true;
|
||||
return pplx::task_from_result();
|
||||
});
|
||||
|
||||
websocket_transport<test_websocket_client> ws_transport(client);
|
||||
|
||||
ws_transport.send(_XPLATSTR("ABC")).wait();
|
||||
|
||||
ASSERT_TRUE(send_called);
|
||||
}
|
||||
|
||||
TEST(websocket_transport_disconnect, disconnect_closes_websocket)
|
||||
{
|
||||
bool close_called = false;
|
||||
|
||||
test_websocket_client client;
|
||||
client.set_close_function([&close_called]() -> pplx::task<void>
|
||||
{
|
||||
close_called = true;
|
||||
return pplx::task_from_result();
|
||||
});
|
||||
|
||||
websocket_transport<test_websocket_client> ws_transport(client);
|
||||
|
||||
ws_transport.disconnect().wait();
|
||||
|
||||
ASSERT_TRUE(close_called);
|
||||
}
|
Загрузка…
Ссылка в новой задаче