Skip to content

Commit d7a629a

Browse files
Add MessagePack support (#53)
1 parent 62ad9a8 commit d7a629a

33 files changed

+1395
-163
lines changed

.azure/default-build.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ jobs:
4545

4646
- task: CMake@1
4747
inputs:
48-
cmakeArgs: .. ${{ parameters.cMakeRunArgs }} -DCMAKE_TOOLCHAIN_FILE=../submodules/vcpkg/scripts/buildsystems/vcpkg.cmake -DCMAKE_BUILD_TYPE=${{ parameters.configuration }} -DUSE_CPPRESTSDK=${{ parameters.useCppRestSDK }}
48+
cmakeArgs: .. ${{ parameters.cMakeRunArgs }} -DCMAKE_TOOLCHAIN_FILE=../submodules/vcpkg/scripts/buildsystems/vcpkg.cmake -DCMAKE_BUILD_TYPE=${{ parameters.configuration }} -DUSE_CPPRESTSDK=${{ parameters.useCppRestSDK }} -DUSE_MSGPACK=true
4949
workingDirectory: 'build.${{ parameters.configuration }}'
5050
displayName: Create build files
5151
- task: CMake@1

CMakeLists.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ else()
1919
set(EXTRA_FLAGS "-DSIGNALRCLIENT_EXPORTS")
2020
endif()
2121

22+
if(USE_MSGPACK)
23+
string(APPEND EXTRA_FLAGS " -DUSE_MSGPACK")
24+
endif()
25+
2226
if(INJECT_HEADER_AFTER_STDAFX)
2327
string(APPEND EXTRA_FLAGS " -DINJECT_HEADER_AFTER_STDAFX=${INJECT_HEADER_AFTER_STDAFX}")
2428
endif()
@@ -39,6 +43,11 @@ if(NOT INCLUDE_JSONCPP)
3943
set(JSONCPP_LIB "jsoncpp_lib" CACHE STRING "jsoncpp target name")
4044
endif()
4145

46+
if(USE_MSGPACK)
47+
find_package(msgpack CONFIG REQUIRED)
48+
set(MSGPACK_LIB "msgpackc-cxx")
49+
endif()
50+
4251
include_directories (include)
4352

4453
if(USE_CPPRESTSDK)

CMakeSettings.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
"inheritEnvironments": [ "msvc_x64_x64" ],
88
"buildRoot": "${projectDir}\\out\\build\\${name}",
99
"installRoot": "${projectDir}\\out\\install\\${name}",
10-
"cmakeCommandArgs": "-DBUILD_SAMPLES=true -DUSE_CPPRESTSDK=true",
10+
"cmakeCommandArgs": "-DBUILD_SAMPLES=true -DUSE_CPPRESTSDK=true -DUSE_MSGPACK=true",
1111
"buildCommandArgs": "-v",
1212
"ctestCommandArgs": "",
1313
"cmakeToolchain": "${projectDir}\\submodules\\vcpkg\\scripts\\buildsystems\\vcpkg.cmake",
@@ -19,7 +19,7 @@
1919
"configurationType": "Release",
2020
"buildRoot": "${projectDir}\\out\\build\\${name}",
2121
"installRoot": "${projectDir}\\out\\install\\${name}",
22-
"cmakeCommandArgs": "-DBUILD_SAMPLES=true -DUSE_CPPRESTSDK=true",
22+
"cmakeCommandArgs": "-DBUILD_SAMPLES=true -DUSE_CPPRESTSDK=true -DUSE_MSGPACK=true",
2323
"buildCommandArgs": "-v",
2424
"ctestCommandArgs": "",
2525
"cmakeToolchain": "${projectDir}\\submodules\\vcpkg\\scripts\\buildsystems\\vcpkg.cmake",

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ Below are instructions to build on different OS's. You can also use the followin
2020
| --- | --- | --- |
2121
| -DBUILD_SAMPLES | Build the included sample project | false |
2222
| -DBUILD_TESTING | Builds the test project | true |
23-
| -DUSE_CPPRESTSDK | Includes the CppRestSDK (default http stack) | false |
23+
| -DUSE_CPPRESTSDK | Includes the CppRestSDK (default http stack) (requires cpprestsdk to be installed) | false |
24+
| -DUSE_MSGPACK | Adds an option to use the MessagePack Hub Protocol (requires msgpack-c to be installed) | false |
2425
| -DINCLUDE_JSONCPP | Builds jsoncpp source code as part of the output binary | true |
2526
| -DWERROR | Enables warnings as errors | true |
2627
| -DWALL | Enables all warnings | true |

azure-pipelines.yml

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ stages:
3737
- powershell: "& ./submodules/vcpkg/bootstrap-vcpkg.bat"
3838
condition: ne(variables.CACHE_RESTORED, 'true')
3939
displayName: Bootstrap vcpkg
40-
- powershell: "& ./submodules/vcpkg/vcpkg.exe install cpprestsdk:x64-windows --vcpkg-root ./submodules/vcpkg"
40+
- powershell: "& ./submodules/vcpkg/vcpkg.exe install cpprestsdk:x64-windows msgpack:x64-windows --vcpkg-root ./submodules/vcpkg"
4141
condition: ne(variables.CACHE_RESTORED, 'true')
4242
displayName: vcpkg install dependencies
4343

@@ -50,7 +50,7 @@ stages:
5050
- bash: "./submodules/vcpkg/bootstrap-vcpkg.sh --allowAppleClang"
5151
condition: ne(variables.CACHE_RESTORED, 'true')
5252
displayName: Bootstrap vcpkg
53-
- bash: "./submodules/vcpkg/vcpkg install cpprestsdk"
53+
- bash: "./submodules/vcpkg/vcpkg install cpprestsdk msgpack"
5454
condition: ne(variables.CACHE_RESTORED, 'true')
5555
displayName: vcpkg install dependencies
5656

@@ -63,7 +63,7 @@ stages:
6363
- bash: "./submodules/vcpkg/bootstrap-vcpkg.sh"
6464
condition: ne(variables.CACHE_RESTORED, 'true')
6565
displayName: Bootstrap vcpkg
66-
- bash: "./submodules/vcpkg/vcpkg install cpprestsdk boost-system boost-chrono boost-thread --vcpkg-root ./submodules/vcpkg"
66+
- bash: "./submodules/vcpkg/vcpkg install cpprestsdk boost-system boost-chrono boost-thread msgpack --vcpkg-root ./submodules/vcpkg"
6767
condition: ne(variables.CACHE_RESTORED, 'true')
6868
displayName: vcpkg install dependencies
6969
- bash: "sudo apt-get update && sudo apt install valgrind"
@@ -75,6 +75,12 @@ stages:
7575
jobName: Linux_Build_Test
7676
useCppRestSDK: false
7777
beforeBuild:
78+
- bash: "./submodules/vcpkg/bootstrap-vcpkg.sh"
79+
condition: ne(variables.CACHE_RESTORED, 'true')
80+
displayName: Bootstrap vcpkg
81+
- bash: "./submodules/vcpkg/vcpkg install msgpack --vcpkg-root ./submodules/vcpkg"
82+
condition: ne(variables.CACHE_RESTORED, 'true')
83+
displayName: vcpkg install dependencies
7884
- bash: "sudo apt-get update && sudo apt install valgrind"
7985
displayName: install valgrind
8086

@@ -84,6 +90,13 @@ stages:
8490
jobName: Windows_Build_Test
8591
useCppRestSDK: false
8692
cMakeRunArgs: '-A x64'
93+
beforeBuild:
94+
- powershell: "& ./submodules/vcpkg/bootstrap-vcpkg.bat"
95+
condition: ne(variables.CACHE_RESTORED, 'true')
96+
displayName: Bootstrap vcpkg
97+
- powershell: "& ./submodules/vcpkg/vcpkg.exe install msgpack:x64-windows --vcpkg-root ./submodules/vcpkg"
98+
condition: ne(variables.CACHE_RESTORED, 'true')
99+
displayName: vcpkg install dependencies
87100

88101
- template: .azure/default-build.yml
89102
parameters:
@@ -93,6 +106,12 @@ stages:
93106
beforeBuild:
94107
- script: brew install gcc
95108
displayName: Install gcc
109+
- bash: "./submodules/vcpkg/bootstrap-vcpkg.sh"
110+
condition: ne(variables.CACHE_RESTORED, 'true')
111+
displayName: Bootstrap vcpkg
112+
- bash: "./submodules/vcpkg/vcpkg install msgpack"
113+
condition: ne(variables.CACHE_RESTORED, 'true')
114+
displayName: vcpkg install dependencies
96115

97116
- ${{ if and(ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:
98117
- stage: post_build

include/signalrclient/hub_connection.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ namespace signalr
1919
class websocket_client;
2020
class hub_connection_impl;
2121
class hub_connection_builder;
22+
class hub_protocol;
2223

2324
class hub_connection
2425
{
@@ -54,9 +55,11 @@ namespace signalr
5455
private:
5556
friend class hub_connection_builder;
5657

57-
explicit hub_connection(const std::string& url, trace_level trace_level = trace_level::info,
58-
std::shared_ptr<log_writer> log_writer = nullptr, std::function<std::shared_ptr<http_client>(const signalr_client_config&)> http_client_factory = nullptr,
59-
std::function<std::shared_ptr<websocket_client>(const signalr_client_config&)> websocket_factory = nullptr, bool skip_negotiation = false);
58+
explicit hub_connection(const std::string& url, std::unique_ptr<hub_protocol>&& hub_protocol,
59+
trace_level trace_level = trace_level::info, std::shared_ptr<log_writer> log_writer = nullptr,
60+
std::function<std::shared_ptr<http_client>(const signalr_client_config&)> http_client_factory = nullptr,
61+
std::function<std::shared_ptr<websocket_client>(const signalr_client_config&)> websocket_factory = nullptr,
62+
bool skip_negotiation = false);
6063

6164
std::shared_ptr<hub_connection_impl> m_pImpl;
6265
};

include/signalrclient/hub_connection_builder.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@ namespace signalr
3535

3636
SIGNALRCLIENT_API hub_connection_builder& skip_negotiation(bool skip = true);
3737

38+
#ifdef USE_MSGPACK
39+
SIGNALRCLIENT_API hub_connection_builder& with_messagepack_hub_protocol();
40+
#endif
41+
3842
SIGNALRCLIENT_API hub_connection build();
3943
private:
4044
hub_connection_builder(const std::string& url);
@@ -45,5 +49,6 @@ namespace signalr
4549
std::function<std::shared_ptr<websocket_client>(const signalr_client_config&)> m_websocket_factory;
4650
std::function<std::shared_ptr<http_client>(const signalr_client_config&)> m_http_client_factory;
4751
bool m_skip_negotiation = false;
52+
bool m_use_messagepack = false;
4853
};
4954
}

include/signalrclient/signalr_exception.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,9 @@ namespace signalr
1414
explicit signalr_exception(const std::string &what)
1515
: runtime_error(what)
1616
{}
17+
18+
explicit signalr_exception(const char* what)
19+
: runtime_error(what)
20+
{}
1721
};
1822
}

src/signalrclient/CMakeLists.txt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,14 @@ set (SOURCES
2525
../../third_party_code/cpprestsdk/uri_builder.cpp
2626
)
2727

28+
if(USE_MSGPACK)
29+
list (APPEND SOURCES
30+
binary_message_formatter.cpp
31+
binary_message_parser.cpp
32+
messagepack_hub_protocol.cpp
33+
)
34+
endif()
35+
2836
include_directories(
2937
../../third_party_code/cpprestsdk
3038
)
@@ -90,6 +98,12 @@ else()
9098
endif()
9199
endif() # USE_CPPRESTSDK
92100

101+
if(USE_MSGPACK)
102+
target_link_libraries(microsoft-signalr
103+
PRIVATE ${MSGPACK_LIB}
104+
)
105+
endif() # USE_MSGPACK
106+
93107
include(GNUInstallDirs)
94108

95109
install(TARGETS microsoft-signalr
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
#include "stdafx.h"
6+
7+
#ifdef USE_MSGPACK
8+
#include "binary_message_formatter.h"
9+
#include <cassert>
10+
#include <signalrclient/signalr_exception.h>
11+
12+
namespace signalr
13+
{
14+
namespace binary_message_formatter
15+
{
16+
void write_length_prefix(std::string& payload)
17+
{
18+
// We support payloads up to 2GB so the biggest number we support is 7fffffff which when encoded as
19+
// VarInt is 0xFF 0xFF 0xFF 0xFF 0x07 - hence the maximum length prefix is 5 bytes.
20+
char buffer[5];
21+
22+
size_t length = payload.length();
23+
size_t length_num_bytes = 0;
24+
do
25+
{
26+
buffer[length_num_bytes] = (char)(length & 0x7f);
27+
length >>= 7;
28+
if (length > 0)
29+
{
30+
buffer[length_num_bytes] |= 0x80;
31+
}
32+
length_num_bytes++;
33+
} while (length > 0 && length_num_bytes < 5);
34+
35+
if (length_num_bytes == 5 && buffer[4] != 0x07)
36+
{
37+
throw signalr_exception("messages over 2GB are not supported.");
38+
}
39+
40+
payload.insert(0, buffer, length_num_bytes);
41+
}
42+
}
43+
}
44+
45+
#endif

0 commit comments

Comments
 (0)