Move Cpp Client to main repo (#1703)
This commit is contained in:
parent
a4d0bf2e3a
commit
476d337989
|
|
@ -43,4 +43,15 @@ dist/
|
|||
global.json
|
||||
BenchmarkDotNet.Artifacts/
|
||||
.rpt2_cache/
|
||||
*.orig
|
||||
*.orig
|
||||
*.vspscc
|
||||
*.vssscc
|
||||
*.opensdf
|
||||
Debug/
|
||||
Release/
|
||||
ipch/
|
||||
*.vcxproj.user
|
||||
*.exe
|
||||
*.aps
|
||||
*.opendb
|
||||
*.db
|
||||
|
|
@ -0,0 +1,432 @@
|
|||
.NET Core uses third-party libraries or other resources that may be
|
||||
distributed under licenses different than the .NET Core software.
|
||||
|
||||
In the event that we accidentally failed to list a required notice, please
|
||||
bring it to our attention. Post an issue or email us:
|
||||
|
||||
dotnet@microsoft.com
|
||||
|
||||
The attached notices are provided for information only.
|
||||
|
||||
|
||||
License notice for googletest
|
||||
------------------------------------
|
||||
|
||||
"Copyright 2008, Google Inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
|
||||
|
||||
|
||||
License notice for es6-promise
|
||||
------------------------------------------------------------------------------
|
||||
"Copyright (c) 2014 Yehuda Katz, Tom Dale, Stefan Penner and contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE."
|
||||
|
||||
|
||||
License notice for buffer
|
||||
------------------------------------------------------------------------------
|
||||
"The MIT License (MIT)
|
||||
|
||||
Copyright (c) Feross Aboukhadijeh, and other contributors.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE."
|
||||
|
||||
|
||||
License notice for base64-js
|
||||
------------------------------------------------------------------------------
|
||||
"The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE."
|
||||
|
||||
|
||||
License notice for ieee754
|
||||
------------------------------------------------------------------------------
|
||||
"Copyright (c) 2008, Fair Oaks Labs, Inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of Fair Oaks Labs, Inc. nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE."
|
||||
|
||||
|
||||
License notice for msgpack5
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
"The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 Matteo Collina
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE."
|
||||
|
||||
|
||||
License notice for bl
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
"The MIT License (MIT)
|
||||
=====================
|
||||
|
||||
Copyright (c) 2013-2016 bl contributors
|
||||
----------------------------------
|
||||
|
||||
*bl contributors listed at <https://github.com/rvagg/bl#contributors>*
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE."
|
||||
|
||||
|
||||
License notice for inherits
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
"The ISC License
|
||||
|
||||
Copyright (c) Isaac Z. Schlueter
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
PERFORMANCE OF THIS SOFTWARE."
|
||||
|
||||
|
||||
License notice for readable-stream
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
"Node.js is licensed for use as follows:
|
||||
|
||||
"""
|
||||
Copyright Node.js contributors. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to
|
||||
deal in the Software without restriction, including without limitation the
|
||||
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
sell copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
IN THE SOFTWARE.
|
||||
"""
|
||||
|
||||
This license applies to parts of Node.js originating from the
|
||||
https://github.com/joyent/node repository:
|
||||
|
||||
"""
|
||||
Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to
|
||||
deal in the Software without restriction, including without limitation the
|
||||
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
sell copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
IN THE SOFTWARE.
|
||||
""""
|
||||
|
||||
|
||||
License notice for core-util-is
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
"Copyright Node.js contributors. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to
|
||||
deal in the Software without restriction, including without limitation the
|
||||
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
sell copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
IN THE SOFTWARE."
|
||||
|
||||
|
||||
License notice for isarray
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
"(MIT)
|
||||
|
||||
Copyright (c) 2013 Julian Gruber <julian@juliangruber.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE."
|
||||
|
||||
|
||||
License notice for process-nextick-args
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
"# Copyright (c) 2015 Calvin Metcalf
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
**THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.**"
|
||||
|
||||
|
||||
License notice for string_decoder
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
"Node.js is licensed for use as follows:
|
||||
|
||||
"""
|
||||
Copyright Node.js contributors. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to
|
||||
deal in the Software without restriction, including without limitation the
|
||||
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
sell copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
IN THE SOFTWARE.
|
||||
"""
|
||||
|
||||
This license applies to parts of Node.js originating from the
|
||||
https://github.com/joyent/node repository:
|
||||
|
||||
"""
|
||||
Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to
|
||||
deal in the Software without restriction, including without limitation the
|
||||
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
sell copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
IN THE SOFTWARE.
|
||||
""""
|
||||
|
||||
|
||||
License notice for util-deprecate
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
"(The MIT License)
|
||||
|
||||
Copyright (c) 2014 Nathan Rajlich <nathan@tootallnate.net>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE."
|
||||
|
||||
|
||||
License notice for safe-buffer
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
"The MIT License (MIT)
|
||||
|
||||
Copyright (c) Feross Aboukhadijeh
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE."
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<solution>
|
||||
<add key="disableSourceControlIntegration" value="true" />
|
||||
</solution>
|
||||
</configuration>
|
||||
Binary file not shown.
|
|
@ -0,0 +1,144 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">$(MSBuildProjectDirectory)\..\</SolutionDir>
|
||||
|
||||
<!-- Enable the restore command to run before builds -->
|
||||
<RestorePackages Condition=" '$(RestorePackages)' == '' ">false</RestorePackages>
|
||||
|
||||
<!-- Property that enables building a package from a project -->
|
||||
<BuildPackage Condition=" '$(BuildPackage)' == '' ">false</BuildPackage>
|
||||
|
||||
<!-- Determines if package restore consent is required to restore packages -->
|
||||
<RequireRestoreConsent Condition=" '$(RequireRestoreConsent)' != 'false' ">true</RequireRestoreConsent>
|
||||
|
||||
<!-- Download NuGet.exe if it does not already exist -->
|
||||
<DownloadNuGetExe Condition=" '$(DownloadNuGetExe)' == '' ">false</DownloadNuGetExe>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup Condition=" '$(PackageSources)' == '' ">
|
||||
<!-- Package sources used to restore packages. By default, registered sources under %APPDATA%\NuGet\NuGet.Config will be used -->
|
||||
<!-- The official NuGet package source (https://www.nuget.org/api/v2/) will be excluded if package sources are specified and it does not appear in the list -->
|
||||
<!--
|
||||
<PackageSource Include="https://www.nuget.org/api/v2/" />
|
||||
<PackageSource Include="https://my-nuget-source/nuget/" />
|
||||
-->
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup Condition=" '$(OS)' == 'Windows_NT'">
|
||||
<!-- Windows specific commands -->
|
||||
<NuGetToolsPath>$([System.IO.Path]::Combine($(SolutionDir), ".nuget"))</NuGetToolsPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition=" '$(OS)' != 'Windows_NT'">
|
||||
<!-- We need to launch nuget.exe with the mono command if we're not on windows -->
|
||||
<NuGetToolsPath>$(SolutionDir).nuget</NuGetToolsPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<PackagesProjectConfig Condition=" '$(OS)' == 'Windows_NT'">$(MSBuildProjectDirectory)\packages.$(MSBuildProjectName.Replace(' ', '_')).config</PackagesProjectConfig>
|
||||
<PackagesProjectConfig Condition=" '$(OS)' != 'Windows_NT'">$(MSBuildProjectDirectory)\packages.$(MSBuildProjectName).config</PackagesProjectConfig>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<PackagesConfig Condition="Exists('$(MSBuildProjectDirectory)\packages.config')">$(MSBuildProjectDirectory)\packages.config</PackagesConfig>
|
||||
<PackagesConfig Condition="Exists('$(PackagesProjectConfig)')">$(PackagesProjectConfig)</PackagesConfig>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<!-- NuGet command -->
|
||||
<NuGetExePath Condition=" '$(NuGetExePath)' == '' ">$(NuGetToolsPath)\NuGet.exe</NuGetExePath>
|
||||
<PackageSources Condition=" $(PackageSources) == '' ">@(PackageSource)</PackageSources>
|
||||
|
||||
<NuGetCommand Condition=" '$(OS)' == 'Windows_NT'">"$(NuGetExePath)"</NuGetCommand>
|
||||
<NuGetCommand Condition=" '$(OS)' != 'Windows_NT' ">mono --runtime=v4.0.30319 "$(NuGetExePath)"</NuGetCommand>
|
||||
|
||||
<PackageOutputDir Condition="$(PackageOutputDir) == ''">$(TargetDir.Trim('\\'))</PackageOutputDir>
|
||||
|
||||
<RequireConsentSwitch Condition=" $(RequireRestoreConsent) == 'true' ">-RequireConsent</RequireConsentSwitch>
|
||||
<NonInteractiveSwitch Condition=" '$(VisualStudioVersion)' != '' AND '$(OS)' == 'Windows_NT' ">-NonInteractive</NonInteractiveSwitch>
|
||||
|
||||
<PaddedSolutionDir Condition=" '$(OS)' == 'Windows_NT'">"$(SolutionDir) "</PaddedSolutionDir>
|
||||
<PaddedSolutionDir Condition=" '$(OS)' != 'Windows_NT' ">"$(SolutionDir)"</PaddedSolutionDir>
|
||||
|
||||
<!-- Commands -->
|
||||
<RestoreCommand>$(NuGetCommand) install "$(PackagesConfig)" -source "$(PackageSources)" $(NonInteractiveSwitch) $(RequireConsentSwitch) -solutionDir $(PaddedSolutionDir)</RestoreCommand>
|
||||
<BuildCommand>$(NuGetCommand) pack "$(ProjectPath)" -Properties "Configuration=$(Configuration);Platform=$(Platform)" $(NonInteractiveSwitch) -OutputDirectory "$(PackageOutputDir)" -symbols</BuildCommand>
|
||||
|
||||
<!-- We need to ensure packages are restored prior to assembly resolve -->
|
||||
<BuildDependsOn Condition="$(RestorePackages) == 'true'">
|
||||
RestorePackages;
|
||||
$(BuildDependsOn);
|
||||
</BuildDependsOn>
|
||||
|
||||
<!-- Make the build depend on restore packages -->
|
||||
<BuildDependsOn Condition="$(BuildPackage) == 'true'">
|
||||
$(BuildDependsOn);
|
||||
BuildPackage;
|
||||
</BuildDependsOn>
|
||||
</PropertyGroup>
|
||||
|
||||
<Target Name="CheckPrerequisites">
|
||||
<!-- Raise an error if we're unable to locate nuget.exe -->
|
||||
<Error Condition="'$(DownloadNuGetExe)' != 'true' AND !Exists('$(NuGetExePath)')" Text="Unable to locate '$(NuGetExePath)'" />
|
||||
<!--
|
||||
Take advantage of MsBuild's build dependency tracking to make sure that we only ever download nuget.exe once.
|
||||
This effectively acts as a lock that makes sure that the download operation will only happen once and all
|
||||
parallel builds will have to wait for it to complete.
|
||||
-->
|
||||
<MsBuild Targets="_DownloadNuGet" Projects="$(MSBuildThisFileFullPath)" Properties="Configuration=NOT_IMPORTANT;DownloadNuGetExe=$(DownloadNuGetExe)" />
|
||||
</Target>
|
||||
|
||||
<Target Name="_DownloadNuGet">
|
||||
<DownloadNuGet OutputFilename="$(NuGetExePath)" Condition=" '$(DownloadNuGetExe)' == 'true' AND !Exists('$(NuGetExePath)')" />
|
||||
</Target>
|
||||
|
||||
<Target Name="RestorePackages" DependsOnTargets="CheckPrerequisites">
|
||||
<Exec Command="$(RestoreCommand)"
|
||||
Condition="'$(OS)' != 'Windows_NT' And Exists('$(PackagesConfig)')" />
|
||||
|
||||
<Exec Command="$(RestoreCommand)"
|
||||
LogStandardErrorAsError="true"
|
||||
Condition="'$(OS)' == 'Windows_NT' And Exists('$(PackagesConfig)')" />
|
||||
</Target>
|
||||
|
||||
<Target Name="BuildPackage" DependsOnTargets="CheckPrerequisites">
|
||||
<Exec Command="$(BuildCommand)"
|
||||
Condition=" '$(OS)' != 'Windows_NT' " />
|
||||
|
||||
<Exec Command="$(BuildCommand)"
|
||||
LogStandardErrorAsError="true"
|
||||
Condition=" '$(OS)' == 'Windows_NT' " />
|
||||
</Target>
|
||||
|
||||
<UsingTask TaskName="DownloadNuGet" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll">
|
||||
<ParameterGroup>
|
||||
<OutputFilename ParameterType="System.String" Required="true" />
|
||||
</ParameterGroup>
|
||||
<Task>
|
||||
<Reference Include="System.Core" />
|
||||
<Using Namespace="System" />
|
||||
<Using Namespace="System.IO" />
|
||||
<Using Namespace="System.Net" />
|
||||
<Using Namespace="Microsoft.Build.Framework" />
|
||||
<Using Namespace="Microsoft.Build.Utilities" />
|
||||
<Code Type="Fragment" Language="cs">
|
||||
<![CDATA[
|
||||
try {
|
||||
OutputFilename = Path.GetFullPath(OutputFilename);
|
||||
|
||||
Log.LogMessage("Downloading latest version of NuGet.exe...");
|
||||
WebClient webClient = new WebClient();
|
||||
webClient.DownloadFile("https://dist.nuget.org/win-x86-commandline/latest/nuget.exe", OutputFilename);
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex) {
|
||||
Log.LogErrorFromException(ex);
|
||||
return false;
|
||||
}
|
||||
]]>
|
||||
</Code>
|
||||
</Task>
|
||||
</UsingTask>
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildThisFileDirectory)Version.props" />
|
||||
<PropertyGroup>
|
||||
<SolutionDir Condition="$(SolutionDir) == '' Or '$(SolutionDir)' == '*Undefined*'">$(MSBuildThisFileDirectory)..\</SolutionDir>
|
||||
<Configuration Condition="'$(Configuration)'==''">Debug</Configuration>
|
||||
<Platform Condition="'$(Platform)'==''">Win32</Platform>
|
||||
<PlatformToolset Condition=" '$(PlatformToolset)' == '' And '$(VisualStudioVersion)' == '12.0'">v120</PlatformToolset>
|
||||
<PlatformToolset Condition=" '$(PlatformToolset)' == '' And '$(VisualStudioVersion)' == '14.0'">v140</PlatformToolset>
|
||||
<PlatformToolset Condition=" '$(PlatformToolset)' == ''">v140</PlatformToolset>
|
||||
<SubSystem Condition="'$(SubSystem)' != 'UWP'">Desktop</SubSystem>
|
||||
<OutDir Condition="'$(OutDir)' == ''">$(SolutionDir)bin\$(SubSystem)\$(Platform)\$(Configuration)\</OutDir>
|
||||
<SignalrClientTargetName>signalrclient</SignalrClientTargetName>
|
||||
<DefaultLanguage>en-US</DefaultLanguage>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="12.0" DefaultTargets="Test" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
|
||||
<UsingTask TaskName="ExecAsync" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v12.0.dll">
|
||||
<ParameterGroup>
|
||||
<Executable ParameterType="System.String" Required="true" />
|
||||
<Arguments ParameterType="System.String" Required="false" />
|
||||
</ParameterGroup>
|
||||
<Task>
|
||||
<Using Namespace="System.IO" />
|
||||
<Using Namespace="System.Diagnostics" />
|
||||
<Code Type="Fragment" Language="cs">
|
||||
<![CDATA[
|
||||
Log.LogMessage("Executable {0}...", Executable);
|
||||
var name = System.IO.Path.GetFileNameWithoutExtension(Executable);
|
||||
Log.LogMessage("Starting {0}...", name);
|
||||
var processStartInfo = new ProcessStartInfo(Executable, Arguments) { UseShellExecute = true };
|
||||
Process.Start(processStartInfo);
|
||||
Log.LogMessage("Finished starting process {0}.", name);
|
||||
]]>
|
||||
</Code>
|
||||
</Task>
|
||||
</UsingTask>
|
||||
|
||||
<UsingTask TaskName="Sleep" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v12.0.dll">
|
||||
<ParameterGroup>
|
||||
<TimeoutMs ParameterType="System.Int32" Required="true" />
|
||||
</ParameterGroup>
|
||||
<Task>
|
||||
<Code Type="Fragment" Language="cs">
|
||||
<![CDATA[System.Threading.Thread.Sleep(TimeoutMs);]]>
|
||||
</Code>
|
||||
</Task>
|
||||
</UsingTask>
|
||||
|
||||
<UsingTask TaskName="ZipDir" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v12.0.dll">
|
||||
<ParameterGroup>
|
||||
<InputDir ParameterType="System.String" Required="true" />
|
||||
<OutputFileName ParameterType="System.String" Required="true" />
|
||||
<IncludeBaseDir ParameterType="System.Boolean" Required="false" />
|
||||
</ParameterGroup>
|
||||
<Task>
|
||||
<Reference Include="System.IO.Compression.FileSystem" />
|
||||
<Using Namespace="System.IO.Compression" />
|
||||
<Code Type="Fragment" Language="cs">
|
||||
<![CDATA[ ZipFile.CreateFromDirectory(InputDir, OutputFileName, CompressionLevel.Optimal, IncludeBaseDir); ]]>
|
||||
</Code>
|
||||
</Task>
|
||||
</UsingTask>
|
||||
|
||||
<UsingTask TaskName="RegexReplaceInFile" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v12.0.dll">
|
||||
<ParameterGroup>
|
||||
<InputFilename ParameterType="System.String" Required="true" />
|
||||
<OutputFilename ParameterType="System.String" Required="true" />
|
||||
<Pattern ParameterType="System.String" Required="true" />
|
||||
<Replacement ParameterType="System.String" Required="true" />
|
||||
</ParameterGroup>
|
||||
<Task>
|
||||
<Using Namespace="System.IO" />
|
||||
<Using Namespace="System.Linq" />
|
||||
<Using Namespace="System.Text.RegularExpressions" />
|
||||
<Code Type="Fragment" Language="cs">
|
||||
<![CDATA[
|
||||
string contents;
|
||||
using (var input = new StreamReader(InputFilename))
|
||||
{
|
||||
contents = input.ReadToEnd();
|
||||
}
|
||||
|
||||
contents = new Regex(Pattern, RegexOptions.Compiled | RegexOptions.Multiline)
|
||||
.Replace(contents, Replacement);
|
||||
|
||||
using (var output = new StreamWriter(OutputFilename))
|
||||
{
|
||||
output.Write(contents);
|
||||
}
|
||||
]]>
|
||||
</Code>
|
||||
</Task>
|
||||
</UsingTask>
|
||||
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,91 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildThisFileDirectory)\Common.Build.Settings" />
|
||||
<PropertyGroup>
|
||||
<DownloadNuGetExe Condition=" '$(DownloadNuGetExe)' == '' ">true</DownloadNuGetExe>
|
||||
<RestorePackages>true</RestorePackages>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)' == 'Debug'">
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<WholeProgramOptimization>false</WholeProgramOptimization>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(SubSystem)' == 'UWP'">
|
||||
<MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion>
|
||||
<AppContainerApplication>true</AppContainerApplication>
|
||||
<ApplicationType>Windows Store</ApplicationType>
|
||||
<WindowsTargetPlatformVersion>10.0.10586.0</WindowsTargetPlatformVersion>
|
||||
<WindowsTargetPlatformMinVersion>10.0.10240.0</WindowsTargetPlatformMinVersion>
|
||||
<ApplicationTypeRevision>10.0</ApplicationTypeRevision>
|
||||
<GenerateProjectSpecificOutputFolder>False</GenerateProjectSpecificOutputFolder>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<TreatWarningAsError Condition="'$(TreatWarningsAsErrors)' != ''">true</TreatWarningAsError>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<StringPooling>true</StringPooling>
|
||||
<CompileAsWinRT Condition="'$(SubSystem)' == 'UWP'">true</CompileAsWinRT>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem Condition="'$(SubSystem)' != 'UWP'">Windows</SubSystem>
|
||||
<SubSystem Condition="'$(SubSystem)' == 'UWP'">Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<ProgramDatabaseFile>$(OutDir)$(TargetName).pdb</ProgramDatabaseFile>
|
||||
<StripPrivateSymbols>$(OutDir)$(TargetName).pub.pdb</StripPrivateSymbols>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<Profile>true</Profile>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)'=='Debug'">
|
||||
<ClCompile>
|
||||
<Optimization>Disabled</Optimization>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)'=='Release'">
|
||||
<ClCompile>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions>_WIN64;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions>_WIN64;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<!-- When changing version remember to update version in $src\signalrclient\constants.h -->
|
||||
<SignalRClientCppVersionMajor>1</SignalRClientCppVersionMajor>
|
||||
<SignalRClientCppVersionMinor>0</SignalRClientCppVersionMinor>
|
||||
<SignalRClientCppVersionPatch>0</SignalRClientCppVersionPatch>
|
||||
<SignalRClientCppVersionSuffix>-alpha0</SignalRClientCppVersionSuffix>
|
||||
<!-- $(build_number) generated by Team City -->
|
||||
<SignalRClientCppVersionSuffix Condition="'$(build_number)' != '' And '$(build_branch)' != 'release'">$(SignalRClientCppVersionSuffix)-$(build_number)</SignalRClientCppVersionSuffix>
|
||||
<SignalRClientCppVersionString>$(SignalRClientCppVersionMajor).$(SignalRClientCppVersionMinor).$(SignalRClientCppVersionPatch)$(SignalRClientCppVersionSuffix)</SignalRClientCppVersionString>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,147 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="12.0" DefaultTargets="Test" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildThisFileDirectory)\Common.tasks" />
|
||||
<Import Project="$(MSBuildThisFileDirectory)\Common.Build.Settings" />
|
||||
|
||||
<ItemGroup>
|
||||
<Projects Include="$(SolutionDir)src\signalrclientdll\Build\VS\signalrclientdll.vcxproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<TestProjects Include="$(SolutionDir)src\signalrclient\Build\VS\signalrclient.vcxproj" />
|
||||
<TestProjects Include="$(SolutionDir)test\signalrclienttests\Build\VS\signalrclienttests.vcxproj" />
|
||||
<TestProjects Include="$(SolutionDir)test\signalrclient-e2e-tests\Build\VS\signalrclient-e2e-tests.vcxproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ManagedProjects Include="$(SolutionDir)test\signalrclient-testhost\signalrclient-testhost.csproj" />
|
||||
<!--
|
||||
<ManagedProjects Include="$(SolutionDir)\samples\SignalRServer\SignalRServer.csproj" />
|
||||
-->
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<!--
|
||||
<SampleProjects Include="$(SolutionDir)\samples\PersistentConnectionSample\PersistentConnectionSample.vcxproj" />
|
||||
<SampleProjects Include="$(SolutionDir)\samples\HubConnectionSample\HubConnectionSample.vcxproj" />
|
||||
-->
|
||||
</ItemGroup>
|
||||
|
||||
<Import Project="$(SolutionDir)\.nuget\nuget.targets" />
|
||||
|
||||
<Target Name="Build">
|
||||
<MSBuild Targets="RestorePackages" Projects="@(Projects)" />
|
||||
<MSBuild Targets="RestorePackages" Projects="@(SampleProjects)" />
|
||||
<MSBuild Targets="RestorePackages" Projects="@(ManagedProjects)" />
|
||||
|
||||
<MSBuild Targets="$(BuildTargets)"
|
||||
Projects="@(Projects)"
|
||||
Properties="Configuration=$(Configuration);Platform=$(Platform);PlatformToolset=$(PlatformToolset);SubSystem=$(SubSystem)" />
|
||||
|
||||
<MSBuild Targets="$(BuildTargets)"
|
||||
Projects="@(TestProjects)"
|
||||
Properties="Configuration=$(Configuration);Platform=$(Platform);PlatformToolset=$(PlatformToolset)" Condition="'$(SubSystem)' == 'Desktop'"/>
|
||||
|
||||
<MSBuild Targets="$(BuildTargets)"
|
||||
Projects="@(SampleProjects)"
|
||||
Properties="Configuration=$(Configuration);Platform=$(Platform);PlatformToolset=$(PlatformToolset)" Condition="'$(SubSystem)' == 'Desktop'"/>
|
||||
|
||||
<MSBuild Targets="$(BuildTargets)"
|
||||
Projects="@(ManagedProjects)"
|
||||
Properties="Configuration=$(Configuration)" Condition="'$(SubSystem)' == 'Desktop'"/>
|
||||
</Target>
|
||||
|
||||
<Target Name="Clean">
|
||||
<MSBuild Targets="Clean"
|
||||
Projects="@(Projects)" />
|
||||
<MSBuild Targets="Clean"
|
||||
Projects="@(TestProjects)" />
|
||||
<MSBuild Targets="Clean"
|
||||
Projects="@(SampleProjects)" />
|
||||
<MSBuild Targets="Clean"
|
||||
Projects="@(ManagedProjects)" />
|
||||
</Target>
|
||||
|
||||
<Target Name="Rebuild">
|
||||
<MSBuild Targets="Clean;Build"
|
||||
Projects="$(MSBuildProjectFile)"
|
||||
Properties="BuildTargets=Rebuild;Configuration=$(Configuration);Platform=$(Platform);PlatformToolset=$(PlatformToolset);SubSystem=$(SubSystem)"/>
|
||||
</Target>
|
||||
|
||||
<Target Name="Test" DependsOnTargets="Build" Condition="'$(SubSystem)' == 'Desktop'">
|
||||
<Exec Command="$(OutDir)\signalrclienttests.exe --gtest_output=xml:$(OutDir)test_results.xml" />
|
||||
<ExecAsync Executable="$(SolutionDir)test\signalrclient-testhost\bin\$(Configuration)\signalrclient-testhost.exe" Arguments="60000" />
|
||||
<!-- give the host some time to open the port otherwise the first tests may fail on slow machines-->
|
||||
<Sleep TimeoutMs="3000" />
|
||||
<Exec Command="$(OutDir)\signalrclient-e2e-tests.exe --gtest_output=xml:$(OutDir)e2e_test_results.xml" />
|
||||
<Exec Command="taskkill /IM signalrclient-testhost.exe /F" ContinueOnError="true" />
|
||||
</Target>
|
||||
|
||||
<Import Project="Config.Definitions.Props" />
|
||||
|
||||
<Target Name="CreatePackage">
|
||||
<PropertyGroup>
|
||||
<PlatformToolset Condition="'$(PlatformToolset)' == ''">v140</PlatformToolset>
|
||||
<SubSystem Condition="'$(SubSystem)' != 'UWP'">Desktop</SubSystem>
|
||||
<PackageSource>$(SolutionDir)bin\Package\$(SubSystem)\$(PlatformToolset)\</PackageSource>
|
||||
<PackageSourceNative>$(PackageSource)build\native\</PackageSourceNative>
|
||||
<NuGetArtifactsPath>$(MSBuildThisFileDirectory)..\NuGet\</NuGetArtifactsPath>
|
||||
<NuSpecTemplatePath>$(NuGetArtifactsPath)signalrclientcpp.nuspec.template</NuSpecTemplatePath>
|
||||
<PackageOutputDir>$(SolutionDir)artifacts\build</PackageOutputDir>
|
||||
<PrivateSymbols>$(SolutionDir)bin\Symbols\$(SubSystem)\$(PlatformToolset)\</PrivateSymbols>
|
||||
</PropertyGroup>
|
||||
|
||||
<Error Text="UWP not supported with v120 toolset" Condition="'$(SubSystem)' == 'UWP' And '$(PlatformToolset)' != 'v140'" />
|
||||
|
||||
<ItemGroup>
|
||||
<Include Include="$(SolutionDir)include\**\*.*" />
|
||||
</ItemGroup>
|
||||
<Copy SourceFiles="@(Include)" DestinationFolder="$(PackageSourceNative)include\%(RecursiveDir)" />
|
||||
<MakeDir Directories="$(PackageSource)" />
|
||||
|
||||
<RegexReplaceInFile InputFileName="$(NuSpecTemplatePath)" OutputFileName="$(PackageSource)signalrclientcpp.nuspec" Pattern="#Toolset#" Replacement="$(PlatformToolset)" />
|
||||
<RegexReplaceInFile InputFileName="$(PackageSource)signalrclientcpp.nuspec" OutputFileName="$(PackageSource)signalrclientcpp.nuspec" Pattern="#casablanca-subsystem#" Replacement="windesktop" Condition="'$(SubSystem)' == 'Desktop'" />
|
||||
<RegexReplaceInFile InputFileName="$(PackageSource)signalrclientcpp.nuspec" OutputFileName="$(PackageSource)signalrclientcpp.nuspec" Pattern="#SubSystem#" Replacement="WinDesktop" Condition="'$(SubSystem)' == 'Desktop'" />
|
||||
<RegexReplaceInFile InputFileName="$(PackageSource)signalrclientcpp.nuspec" OutputFileName="$(PackageSource)signalrclientcpp.nuspec" Pattern="#casablanca-subsystem#" Replacement="winapp" Condition="'$(SubSystem)' == 'UWP'" />
|
||||
<RegexReplaceInFile InputFileName="$(PackageSource)signalrclientcpp.nuspec" OutputFileName="$(PackageSource)signalrclientcpp.nuspec" Pattern="#SubSystem#" Replacement="UWP" Condition="'$(SubSystem)' == 'UWP'" />
|
||||
|
||||
<RegexReplaceInFile InputFileName="$(NuGetArtifactsPath)\Microsoft.AspNet.SignalR.Client.Cpp.WinDesktop.targets.template"
|
||||
OutputFileName="$(PackageSourceNative)Microsoft.AspNet.SignalR.Client.Cpp.$(PlatformToolset).WinDesktop.targets" Pattern="#Toolset#" Replacement="$(PlatformToolset)" Condition="'$(SubSystem)' == 'Desktop'" />
|
||||
<RegexReplaceInFile InputFileName="$(NuGetArtifactsPath)\Microsoft.AspNet.SignalR.Client.Cpp.UWP.targets.template"
|
||||
OutputFileName="$(PackageSourceNative)Microsoft.AspNet.SignalR.Client.Cpp.$(PlatformToolset).UWP.targets" Pattern="#Toolset#" Replacement="$(PlatformToolset)" Condition="'$(SubSystem)' == 'UWP'" />
|
||||
|
||||
<MSBuild Targets="RestorePackages" Projects="@(Projects)" />
|
||||
|
||||
<MSBuild Targets="BuildForNuget"
|
||||
Projects="$(MSBuildThisFile)" Properties="PackageSourceNative=$(PackageSourceNative);PrivateSymbols=$(PrivateSymbols);Configuration=%(ProjectConfiguration.Configuration);Platform=%(ProjectConfiguration.Platform);PlatformToolset=$(PlatformToolset);SubSystem=$(SubSystem);SignalrClientTargetName=$(SignalrClientTargetName)" />
|
||||
|
||||
<MakeDir Directories="$(PackageOutputDir)" />
|
||||
<Exec Command="$(NuGetCommand) pack $(PackageSource)signalrclientcpp.nuspec -BasePath $(PackageSource) -OutputDirectory $(PackageOutputDir) -Version $(SignalRClientCppVersionString)" LogStandardErrorAsError="true" />
|
||||
|
||||
<ZipDir InputDir="$(PrivateSymbols)" OutputFileName="$(PackageOutputDir)\Symbols_$(PlatformToolset)_$(SubSystem).zip" IncludeBaseDir="false"/>
|
||||
</Target>
|
||||
|
||||
<Target Name="BuildForNuget">
|
||||
<MSBuild Targets="$(BuildTargets)"
|
||||
Projects="@(Projects)"
|
||||
Properties="Configuration=$(Configuration);Platform=$(Platform);PlatformToolset=$(PlatformToolset);SubSystem=$(SubSystem)" />
|
||||
|
||||
<Copy SourceFiles="$(OutDir)dll\$(SignalrClientTargetName).lib" DestinationFolder="$(PackageSourceNative)lib\$(Platform)\$(PlatformToolset)\$(Configuration)" />
|
||||
|
||||
<Copy SourceFiles="$(OutDir)dll\$(SignalrClientTargetName).dll" DestinationFolder="$(PackageSourceNative)dll\$(Platform)\$(PlatformToolset)\$(Configuration)" />
|
||||
<Copy SourceFiles="$(OutDir)dll\$(SignalrClientTargetName).pub.pdb" DestinationFiles="$(PackageSourceNative)dll\$(Platform)\$(PlatformToolset)\$(Configuration)\$(SignalrClientTargetName).pdb" />
|
||||
<Copy SourceFiles="$(OutDir)dll\$(SignalrClientTargetName).pdb" DestinationFiles="$(PrivateSymbols)$(Platform)\$(PlatformToolset)\$(Configuration)\$(SignalrClientTargetName).pdb" />
|
||||
</Target>
|
||||
|
||||
<Target Name="NuGetPush">
|
||||
<PropertyGroup>
|
||||
<NuGetExePath Condition="'$(NuGetExePath)' == ''">$(PUSH_NUGET_EXE)</NuGetExePath>
|
||||
<NuGetExePath Condition="'$(NuGetExePath)' == ''">$(MSBuildThisFileDirectory)..\.nuget\NuGet.exe</NuGetExePath>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Package Include="$(SolutionDir)artifacts\build\*.nupkg" />
|
||||
<Package Include="$(SolutionDir)artifacts\build\*.symbols.nupkg" />
|
||||
</ItemGroup>
|
||||
<Exec Command="$(NuGetExePath) push -nosymbols %(Package.Identity) -Source $(NUGET_PUBLISH_FEED) -ApiKey $(APIKEY)" />
|
||||
</Target>
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
cmake_minimum_required (VERSION 2.8.11)
|
||||
project (signalrclient)
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -fPIC -L -lcpprest")
|
||||
|
||||
set(CPPREST_INCLUDE_DIR "" CACHE FILEPATH "Path to casablanca include dir")
|
||||
|
||||
include_directories (
|
||||
include
|
||||
"${CPPREST_INCLUDE_DIR}")
|
||||
|
||||
find_library(CPPREST_SO NAMES "cpprest" PATHS ${CPPREST_LIB_DIR} REQUIRED)
|
||||
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin)
|
||||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin)
|
||||
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin)
|
||||
|
||||
add_subdirectory(src/signalrclient)
|
||||
add_subdirectory(test)
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
Contributing
|
||||
======
|
||||
|
||||
Information on contributing to this repo is in the [Contributing Guide](https://github.com/aspnet/Home/blob/dev/CONTRIBUTING.md) in the Home repo.
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<packageSources>
|
||||
<clear />
|
||||
<add key="nuget" value="https://api.nuget.org/v3/index.json" />
|
||||
</packageSources>
|
||||
</configuration>
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" InitialTargets="signalrclient_uwp_inittarget">
|
||||
|
||||
<PropertyGroup Condition="'$(PlatformToolset)' != 'v140' Or '$(ApplicationType)' != 'Windows Store'">
|
||||
<DisableUwp>True</DisableUwp>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemDefinitionGroup Condition="'$(DisableUwp)' == ''">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>$(MSBuildThisFileDirectory)include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<ResourceCompile>
|
||||
<AdditionalIncludeDirectories>$(MSBuildThisFileDirectory)include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ResourceCompile>
|
||||
</ItemDefinitionGroup>
|
||||
|
||||
<ItemDefinitionGroup Label="x64 and #Toolset# and Release" Condition="'$(DisableUwp)' == '' And '$(Platform)' == 'x64' And '$(PlatformToolset)' == '#Toolset#' And $(Configuration.ToLower().IndexOf('debug')) == -1">
|
||||
<Link>
|
||||
<AdditionalDependencies>$(MSBuildThisFileDirectory)lib\x64\#Toolset#\Release\signalrclient.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Label="x64 and #Toolset# and Debug" Condition="'$(DisableUwp)' == '' And '$(Platform)' == 'x64' And '$(PlatformToolset)' == '#Toolset#' And $(Configuration.ToLower().IndexOf('debug')) > -1">
|
||||
<Link>
|
||||
<AdditionalDependencies>$(MSBuildThisFileDirectory)lib\x64\#Toolset#\Debug\signalrclient.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Label="Win32 and #Toolset# and Release" Condition="'$(DisableUwp)' == '' And '$(Platform)' == 'Win32' And '$(PlatformToolset)' == '#Toolset#' And $(Configuration.ToLower().IndexOf('debug')) == -1">
|
||||
<Link>
|
||||
<AdditionalDependencies>$(MSBuildThisFileDirectory)lib\Win32\#Toolset#\Release\signalrclient.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Label="Win32 and #Toolset# and Debug" Condition="'$(DisableUwp)' == '' And '$(Platform)' == 'Win32' And '$(PlatformToolset)' == '#Toolset#' And $(Configuration.ToLower().IndexOf('debug')) > -1">
|
||||
<Link>
|
||||
<AdditionalDependencies>$(MSBuildThisFileDirectory)lib\Win32\#Toolset#\Debug\signalrclient.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
|
||||
<Target Name="signalrclient_uwp_AfterBuild" AfterTargets="AfterBuild" Condition="'$(DisableUwp)' == ''">
|
||||
<PropertyGroup>
|
||||
<UseHardlinksIfPossible Condition="'$(UseHardlinksIfPossible)' == ''">true</UseHardlinksIfPossible>
|
||||
</PropertyGroup>
|
||||
|
||||
<Copy DestinationFolder="$(TargetDir)" SourceFiles="@(CopyToOutput)" SkipUnchangedFiles="true" UseHardlinksIfPossible="$(UseHardlinksIfPossible)">
|
||||
<Output TaskParameter="DestinationFiles" PropertyName="DestinationFiles" />
|
||||
<Output TaskParameter="DestinationFiles" ItemName="DestinationFiles" />
|
||||
<Output TaskParameter="CopiedFiles" PropertyName="CopiedFiles" />
|
||||
<Output TaskParameter="CopiedFiles" ItemName="CopiedFiles" />
|
||||
</Copy>
|
||||
</Target>
|
||||
|
||||
<Target Name="signalrclient_uwp_inittarget" Condition="'$(DisableUwp)' == ''">
|
||||
<ItemGroup Label="x64 and #Toolset# and Debug" Condition="'$(Platform)' == 'x64' And '$(PlatformToolset)' == '#Toolset#' And $(Configuration.ToLower().IndexOf('debug')) > -1">
|
||||
<ReferenceCopyLocalPaths Include="$(MSBuildThisFileDirectory)dll\x64\#Toolset#\Debug\signalrclient.dll" />
|
||||
<ReferenceCopyLocalPaths Include="$(MSBuildThisFileDirectory)dll\x64\#Toolset#\Debug\signalrclient.pdb" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Label="x64 and #Toolset# and Release" Condition="'$(Platform)' == 'x64' And '$(PlatformToolset)' == '#Toolset#' And $(Configuration.ToLower().IndexOf('debug')) == -1">
|
||||
<ReferenceCopyLocalPaths Include="$(MSBuildThisFileDirectory)dll\x64\#Toolset#\Release\signalrclient.dll" />
|
||||
<ReferenceCopyLocalPaths Include="$(MSBuildThisFileDirectory)dll\x64\#Toolset#\Release\signalrclient.pdb" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Label="Win32 and #Toolset# and Debug" Condition="'$(Platform)' == 'Win32' And '$(PlatformToolset)' == '#Toolset#' And $(Configuration.ToLower().IndexOf('debug')) > -1">
|
||||
<ReferenceCopyLocalPaths Include="$(MSBuildThisFileDirectory)dll\Win32\#Toolset#\Debug\signalrclient.dll" />
|
||||
<ReferenceCopyLocalPaths Include="$(MSBuildThisFileDirectory)dll\Win32\#Toolset#\Debug\signalrclient.pdb" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Label="Win32 and #Toolset# and Release" Condition="'$(Platform)' == 'Win32' And '$(PlatformToolset)' == '#Toolset#' And $(Configuration.ToLower().IndexOf('debug')) == -1">
|
||||
<ReferenceCopyLocalPaths Include="$(MSBuildThisFileDirectory)dll\Win32\#Toolset#\Release\signalrclient.dll" />
|
||||
<ReferenceCopyLocalPaths Include="$(MSBuildThisFileDirectory)dll\Win32\#Toolset#\Release\signalrclient.pdb" />
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" InitialTargets="signalrclient_inittarget">
|
||||
|
||||
<PropertyGroup Condition="'$(ApplicationType)' != ''">
|
||||
<DisableDesktop>True</DisableDesktop>
|
||||
</PropertyGroup>
|
||||
|
||||
|
||||
<ItemDefinitionGroup Condition="'$(DisableDesktop)' == ''">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>$(MSBuildThisFileDirectory)include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<ResourceCompile>
|
||||
<AdditionalIncludeDirectories>$(MSBuildThisFileDirectory)include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ResourceCompile>
|
||||
</ItemDefinitionGroup>
|
||||
|
||||
<ItemDefinitionGroup Label="x64 and #Toolset# and Release" Condition="'$(DisableDesktop)' == '' And '$(Platform)' == 'x64' And '$(PlatformToolset)' == '#Toolset#' And $(Configuration.ToLower().IndexOf('debug')) == -1">
|
||||
<Link>
|
||||
<AdditionalDependencies>$(MSBuildThisFileDirectory)lib\x64\#Toolset#\Release\signalrclient.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Label="x64 and #Toolset# and Debug" Condition="'$(DisableDesktop)' == '' And '$(Platform)' == 'x64' And '$(PlatformToolset)' == '#Toolset#' And $(Configuration.ToLower().IndexOf('debug')) > -1">
|
||||
<Link>
|
||||
<AdditionalDependencies>$(MSBuildThisFileDirectory)lib\x64\#Toolset#\Debug\signalrclient.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Label="Win32 and #Toolset# and Release" Condition="'$(DisableDesktop)' == '' And '$(Platform)' == 'Win32' And '$(PlatformToolset)' == '#Toolset#' And $(Configuration.ToLower().IndexOf('debug')) == -1">
|
||||
<Link>
|
||||
<AdditionalDependencies>$(MSBuildThisFileDirectory)lib\Win32\#Toolset#\Release\signalrclient.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Label="Win32 and #Toolset# and Debug" Condition="'$(DisableDesktop)' == '' And '$(Platform)' == 'Win32' And '$(PlatformToolset)' == '#Toolset#' And $(Configuration.ToLower().IndexOf('debug')) > -1">
|
||||
<Link>
|
||||
<AdditionalDependencies>$(MSBuildThisFileDirectory)lib\Win32\#Toolset#\Debug\signalrclient.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
|
||||
<Target Name="signalrclient_AfterBuild" AfterTargets="AfterBuild" Condition="'$(DisableDesktop)' == ''">
|
||||
<PropertyGroup>
|
||||
<UseHardlinksIfPossible Condition="'$(UseHardlinksIfPossible)' == ''">true</UseHardlinksIfPossible>
|
||||
</PropertyGroup>
|
||||
|
||||
<Copy DestinationFolder="$(TargetDir)" SourceFiles="@(CopyToOutput)" SkipUnchangedFiles="true" UseHardlinksIfPossible="$(UseHardlinksIfPossible)">
|
||||
<Output TaskParameter="DestinationFiles" PropertyName="DestinationFiles" />
|
||||
<Output TaskParameter="DestinationFiles" ItemName="DestinationFiles" />
|
||||
<Output TaskParameter="CopiedFiles" PropertyName="CopiedFiles" />
|
||||
<Output TaskParameter="CopiedFiles" ItemName="CopiedFiles" />
|
||||
</Copy>
|
||||
</Target>
|
||||
|
||||
<Target Name="signalrclient_inittarget" Condition="'$(DisableDesktop)' == ''">
|
||||
<ItemGroup Label="x64 and #Toolset# and Debug" Condition="'$(Platform)' == 'x64' And '$(PlatformToolset)' == '#Toolset#' And $(Configuration.ToLower().IndexOf('debug')) > -1">
|
||||
<CopyToOutput Include="$(MSBuildThisFileDirectory)dll\x64\#Toolset#\Debug\signalrclient.dll" />
|
||||
<CopyToOutput Include="$(MSBuildThisFileDirectory)dll\x64\#Toolset#\Debug\signalrclient.pdb" />
|
||||
<None Include="$(MSBuildThisFileDirectory)dll\x64\#Toolset#\Debug\signalrclient.dll">
|
||||
<DeploymentContent>true</DeploymentContent>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup Label="x64 and #Toolset# and Release" Condition="'$(Platform)' == 'x64' And '$(PlatformToolset)' == '#Toolset#' And $(Configuration.ToLower().IndexOf('debug')) == -1">
|
||||
<CopyToOutput Include="$(MSBuildThisFileDirectory)dll\x64\#Toolset#\Release\signalrclient.dll" />
|
||||
<CopyToOutput Include="$(MSBuildThisFileDirectory)dll\x64\#Toolset#\Release\signalrclient.pdb" />
|
||||
<None Include="$(MSBuildThisFileDirectory)dll\x64\#Toolset#\Release\signalrclient.dll">
|
||||
<DeploymentContent>true</DeploymentContent>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup Label="Win32 and #Toolset# and Debug" Condition="'$(Platform)' == 'Win32' And '$(PlatformToolset)' == '#Toolset#' And $(Configuration.ToLower().IndexOf('debug')) > -1">
|
||||
<CopyToOutput Include="$(MSBuildThisFileDirectory)dll\Win32\#Toolset#\Debug\signalrclient.dll" />
|
||||
<CopyToOutput Include="$(MSBuildThisFileDirectory)dll\Win32\#Toolset#\Debug\signalrclient.pdb" />
|
||||
<None Include="$(MSBuildThisFileDirectory)dll\Win32\#Toolset#\Debug\signalrclient.dll">
|
||||
<DeploymentContent>true</DeploymentContent>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup Label="Win32 and #Toolset# and Release" Condition="'$(Platform)' == 'Win32' And '$(PlatformToolset)' == '#Toolset#' And $(Configuration.ToLower().IndexOf('debug')) == -1">
|
||||
<CopyToOutput Include="$(MSBuildThisFileDirectory)dll\Win32\#Toolset#\Release\signalrclient.dll" />
|
||||
<CopyToOutput Include="$(MSBuildThisFileDirectory)dll\Win32\#Toolset#\Release\signalrclient.pdb" />
|
||||
<None Include="$(MSBuildThisFileDirectory)dll\Win32\#Toolset#\Release\signalrclient.dll">
|
||||
<DeploymentContent>true</DeploymentContent>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
<?xml version="1.0"?>
|
||||
<package>
|
||||
<metadata>
|
||||
<id>Microsoft.AspNet.SignalR.Client.Cpp.#Toolset#.#SubSystem#</id>
|
||||
<title>Microsoft ASP.NET SignalR C++ Client</title>
|
||||
<version>0.0.0</version>
|
||||
<authors>Microsoft</authors>
|
||||
<owners>Microsoft</owners>
|
||||
<licenseUrl>http://www.microsoft.com/web/webpi/eula/net_library_eula_ENU.htm</licenseUrl>
|
||||
<copyright>© Microsoft Corporation. All rights reserved.</copyright>
|
||||
<projectUrl>http://www.asp.net/signalr</projectUrl>
|
||||
<requireLicenseAcceptance>true</requireLicenseAcceptance>
|
||||
<description>C++ client for ASP.NET SignalR.</description>
|
||||
<language>en-US</language>
|
||||
<tags>Microsoft AspNet SignalR AspNetSignalR Client C++ native</tags>
|
||||
<releaseNotes>https://github.com/aspnet/SignalR-Client-Cpp/releases</releaseNotes>
|
||||
<dependencies>
|
||||
<dependency id="cpprestsdk.#Toolset#.#casablanca-subsystem#.msvcstl.dyn.rt-dyn" version="2.9.1" />
|
||||
</dependencies>
|
||||
</metadata>
|
||||
</package>
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
ASP.NET Core SignalR C++ Client
|
||||
========
|
||||
|
||||
This folder contains a C++ client for ASP.NET Core SignalR.
|
||||
|
||||
**There are no plans to ship this client at this time.**
|
||||
|
|
@ -0,0 +1 @@
|
|||
msbuild "%~dp0\Build\build.msbuild" /v:minimal /maxcpucount /nodeReuse:false %*
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef NO_SIGNALRCLIENT_EXPORTS
|
||||
#define SIGNALRCLIENT_API
|
||||
#else
|
||||
#ifdef SIGNALRCLIENT_EXPORTS
|
||||
#define SIGNALRCLIENT_API __declspec(dllexport)
|
||||
#else
|
||||
#define SIGNALRCLIENT_API __declspec(dllimport)
|
||||
#endif // SIGNALRCLIENT_EXPORTS
|
||||
#endif // NO_SIGNALRCLIENT_EXPORTS
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "_exports.h"
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
#include "pplx/pplxtasks.h"
|
||||
#include "connection_state.h"
|
||||
#include "trace_level.h"
|
||||
#include "log_writer.h"
|
||||
#include "signalr_client_config.h"
|
||||
|
||||
namespace signalr
|
||||
{
|
||||
class connection_impl;
|
||||
|
||||
class connection
|
||||
{
|
||||
public:
|
||||
typedef std::function<void __cdecl(const utility::string_t&)> message_received_handler;
|
||||
|
||||
SIGNALRCLIENT_API explicit connection(const utility::string_t& url, const utility::string_t& query_string = _XPLATSTR(""),
|
||||
trace_level trace_level = trace_level::all, std::shared_ptr<log_writer> log_writer = nullptr);
|
||||
|
||||
SIGNALRCLIENT_API ~connection();
|
||||
|
||||
connection(const connection&) = delete;
|
||||
|
||||
connection& operator=(const connection&) = delete;
|
||||
|
||||
SIGNALRCLIENT_API pplx::task<void> __cdecl start();
|
||||
|
||||
SIGNALRCLIENT_API pplx::task<void> __cdecl send(const utility::string_t& data);
|
||||
|
||||
SIGNALRCLIENT_API void __cdecl set_message_received(const message_received_handler& message_received_callback);
|
||||
SIGNALRCLIENT_API void __cdecl set_reconnecting(const std::function<void __cdecl()>& reconnecting_callback);
|
||||
SIGNALRCLIENT_API void __cdecl set_reconnected(const std::function<void __cdecl()>& reconnected_callback);
|
||||
SIGNALRCLIENT_API void __cdecl set_disconnected(const std::function<void __cdecl()>& disconnected_callback);
|
||||
|
||||
SIGNALRCLIENT_API void __cdecl set_client_config(const signalr_client_config& config);
|
||||
|
||||
SIGNALRCLIENT_API pplx::task<void> __cdecl stop();
|
||||
|
||||
SIGNALRCLIENT_API connection_state __cdecl get_connection_state() const;
|
||||
SIGNALRCLIENT_API utility::string_t __cdecl get_connection_id() const;
|
||||
|
||||
private:
|
||||
// The recommended smart pointer to use when doing pImpl is the `std::unique_ptr`. However
|
||||
// we are capturing the m_pImpl instance in the lambdas used by tasks which can outlive
|
||||
// the connection instance. Using `std::shared_ptr` guarantees that we won't be using
|
||||
// a deleted object if the task is run after the `connection` instance goes away.
|
||||
std::shared_ptr<connection_impl> m_pImpl;
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace signalr
|
||||
{
|
||||
enum class connection_state
|
||||
{
|
||||
connecting,
|
||||
connected,
|
||||
reconnecting,
|
||||
disconnecting,
|
||||
disconnected
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "_exports.h"
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
#include "pplx/pplxtasks.h"
|
||||
#include "cpprest/json.h"
|
||||
#include "connection_state.h"
|
||||
#include "trace_level.h"
|
||||
#include "log_writer.h"
|
||||
#include "signalr_client_config.h"
|
||||
|
||||
namespace signalr
|
||||
{
|
||||
class hub_connection_impl;
|
||||
|
||||
class hub_connection
|
||||
{
|
||||
public:
|
||||
typedef std::function<void __cdecl (const web::json::value&)> method_invoked_handler;
|
||||
|
||||
SIGNALRCLIENT_API explicit hub_connection(const utility::string_t& url, const utility::string_t& query_string = _XPLATSTR(""),
|
||||
trace_level trace_level = trace_level::all, std::shared_ptr<log_writer> log_writer = nullptr, bool use_default_url = true);
|
||||
|
||||
SIGNALRCLIENT_API ~hub_connection();
|
||||
|
||||
hub_connection(const hub_connection&) = delete;
|
||||
|
||||
hub_connection& operator=(const hub_connection&) = delete;
|
||||
|
||||
SIGNALRCLIENT_API pplx::task<void> __cdecl start();
|
||||
SIGNALRCLIENT_API pplx::task<void> __cdecl stop();
|
||||
|
||||
SIGNALRCLIENT_API connection_state __cdecl get_connection_state() const;
|
||||
SIGNALRCLIENT_API utility::string_t __cdecl get_connection_id() const;
|
||||
|
||||
SIGNALRCLIENT_API void __cdecl set_reconnecting(const std::function<void __cdecl()>& reconnecting_callback);
|
||||
SIGNALRCLIENT_API void __cdecl set_reconnected(const std::function<void __cdecl()>& reconnected_callback);
|
||||
SIGNALRCLIENT_API void __cdecl set_disconnected(const std::function<void __cdecl()>& disconnected_callback);
|
||||
|
||||
SIGNALRCLIENT_API void __cdecl set_client_config(const signalr_client_config& config);
|
||||
|
||||
SIGNALRCLIENT_API void __cdecl on(const utility::string_t& event_name, const method_invoked_handler& handler);
|
||||
|
||||
pplx::task<web::json::value> invoke(const utility::string_t& method_name, const web::json::value& arguments = web::json::value::array())
|
||||
{
|
||||
return invoke_json(method_name, arguments);
|
||||
}
|
||||
|
||||
pplx::task<void> send(const utility::string_t& method_name, const web::json::value& arguments = web::json::value::array())
|
||||
{
|
||||
return invoke_void(method_name, arguments);
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<hub_connection_impl> m_pImpl;
|
||||
|
||||
SIGNALRCLIENT_API pplx::task<web::json::value> __cdecl invoke_json(const utility::string_t& method_name, const web::json::value& arguments);
|
||||
SIGNALRCLIENT_API pplx::task<void> __cdecl invoke_void(const utility::string_t& method_name, const web::json::value& arguments);
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdexcept>
|
||||
#include "cpprest/details/basic_types.h"
|
||||
#include "cpprest/json.h"
|
||||
#include "cpprest/asyncrt_utils.h"
|
||||
#include "signalr_exception.h"
|
||||
|
||||
namespace signalr
|
||||
{
|
||||
class hub_exception : public signalr_exception
|
||||
{
|
||||
public:
|
||||
hub_exception(const utility::string_t &what, const web::json::value& error_data)
|
||||
: signalr_exception(what), m_error_data(error_data)
|
||||
{}
|
||||
|
||||
web::json::value error_data() const
|
||||
{
|
||||
return m_error_data;
|
||||
}
|
||||
|
||||
private:
|
||||
web::json::value m_error_data;
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cpprest/details/basic_types.h"
|
||||
|
||||
namespace signalr
|
||||
{
|
||||
class log_writer
|
||||
{
|
||||
public:
|
||||
// NOTE: the caller does not enforce thread safety of this call
|
||||
virtual void __cdecl write(const utility::string_t &entry) = 0;
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cpprest/http_client.h"
|
||||
#include "cpprest/ws_client.h"
|
||||
#include "_exports.h"
|
||||
|
||||
namespace signalr
|
||||
{
|
||||
class signalr_client_config
|
||||
{
|
||||
public:
|
||||
SIGNALRCLIENT_API void __cdecl set_proxy(const web::web_proxy &proxy);
|
||||
// Please note that setting credentials does not work in all cases.
|
||||
// For example, Basic Authentication fails under Win32.
|
||||
// As a workaround, you can set the required authorization headers directly
|
||||
// using signalr_client_config::set_http_headers
|
||||
SIGNALRCLIENT_API void __cdecl set_credentials(const web::credentials &credentials);
|
||||
|
||||
SIGNALRCLIENT_API web::http::client::http_client_config __cdecl get_http_client_config() const;
|
||||
SIGNALRCLIENT_API void __cdecl set_http_client_config(const web::http::client::http_client_config& http_client_config);
|
||||
|
||||
SIGNALRCLIENT_API web::websockets::client::websocket_client_config __cdecl get_websocket_client_config() const;
|
||||
SIGNALRCLIENT_API void __cdecl set_websocket_client_config(const web::websockets::client::websocket_client_config& websocket_client_config);
|
||||
|
||||
SIGNALRCLIENT_API web::http::http_headers __cdecl get_http_headers() const;
|
||||
SIGNALRCLIENT_API void __cdecl set_http_headers(const web::http::http_headers& http_headers);
|
||||
|
||||
private:
|
||||
web::http::client::http_client_config m_http_client_config;
|
||||
web::websockets::client::websocket_client_config m_websocket_client_config;
|
||||
web::http::http_headers m_http_headers;
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdexcept>
|
||||
#include "cpprest/details/basic_types.h"
|
||||
#include "cpprest/asyncrt_utils.h"
|
||||
|
||||
namespace signalr
|
||||
{
|
||||
class signalr_exception : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
explicit signalr_exception(const utility::string_t &what)
|
||||
: runtime_error(utility::conversions::to_utf8string(what))
|
||||
{}
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace signalr
|
||||
{
|
||||
enum class trace_level : int
|
||||
{
|
||||
none = 0,
|
||||
messages = 1,
|
||||
events = 2,
|
||||
state_changes = 4,
|
||||
errors = 8,
|
||||
info = 16,
|
||||
all = messages | events | state_changes | errors | info
|
||||
};
|
||||
|
||||
inline trace_level operator|(trace_level lhs, trace_level rhs)
|
||||
{
|
||||
return static_cast<trace_level>(static_cast<int>(lhs) | static_cast<int>(rhs));
|
||||
}
|
||||
|
||||
inline trace_level operator&(trace_level lhs, trace_level rhs)
|
||||
{
|
||||
return static_cast<trace_level>(static_cast<int>(lhs) & static_cast<int>(rhs));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace signalr
|
||||
{
|
||||
enum class transport_type
|
||||
{
|
||||
long_polling,
|
||||
websockets
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdexcept>
|
||||
#include "cpprest/details/basic_types.h"
|
||||
#include "cpprest/asyncrt_utils.h"
|
||||
|
||||
namespace signalr
|
||||
{
|
||||
class web_exception : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
web_exception(const utility::string_t &what, unsigned short status_code)
|
||||
: runtime_error(utility::conversions::to_utf8string(what)), m_status_code(status_code)
|
||||
{}
|
||||
|
||||
unsigned short status_code() const
|
||||
{
|
||||
return m_status_code;
|
||||
}
|
||||
|
||||
private:
|
||||
unsigned short m_status_code;
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 2013
|
||||
VisualStudioVersion = 12.0.31101.0
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PersistentConnectionSample", "samples\PersistentConnectionSample\PersistentConnectionSample.vcxproj", "{BD075706-11E9-403B-A2E3-A5E1397E53EF}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HubConnectionSample", "samples\HubConnectionSample\HubConnectionSample.vcxproj", "{3C9BD092-18E6-4C6E-A887-CDFC80ACB206}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SignalRServer", "samples\SignalRServer\SignalRServer.csproj", "{A6782DC4-7435-4DB2-9E34-3F0390BC3FDE}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{4AA7C02A-A2E9-4E22-A026-B43D623C272F}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
.nuget\NuGet.Config = .nuget\NuGet.Config
|
||||
.nuget\NuGet.exe = .nuget\NuGet.exe
|
||||
.nuget\NuGet.targets = .nuget\NuGet.targets
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Debug|Mixed Platforms = Debug|Mixed Platforms
|
||||
Debug|Win32 = Debug|Win32
|
||||
Release|Any CPU = Release|Any CPU
|
||||
Release|Mixed Platforms = Release|Mixed Platforms
|
||||
Release|Win32 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{BD075706-11E9-403B-A2E3-A5E1397E53EF}.Debug|Any CPU.ActiveCfg = Debug|Win32
|
||||
{BD075706-11E9-403B-A2E3-A5E1397E53EF}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32
|
||||
{BD075706-11E9-403B-A2E3-A5E1397E53EF}.Debug|Mixed Platforms.Build.0 = Debug|Win32
|
||||
{BD075706-11E9-403B-A2E3-A5E1397E53EF}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{BD075706-11E9-403B-A2E3-A5E1397E53EF}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{BD075706-11E9-403B-A2E3-A5E1397E53EF}.Release|Any CPU.ActiveCfg = Release|Win32
|
||||
{BD075706-11E9-403B-A2E3-A5E1397E53EF}.Release|Mixed Platforms.ActiveCfg = Release|Win32
|
||||
{BD075706-11E9-403B-A2E3-A5E1397E53EF}.Release|Mixed Platforms.Build.0 = Release|Win32
|
||||
{BD075706-11E9-403B-A2E3-A5E1397E53EF}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{BD075706-11E9-403B-A2E3-A5E1397E53EF}.Release|Win32.Build.0 = Release|Win32
|
||||
{3C9BD092-18E6-4C6E-A887-CDFC80ACB206}.Debug|Any CPU.ActiveCfg = Debug|Win32
|
||||
{3C9BD092-18E6-4C6E-A887-CDFC80ACB206}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32
|
||||
{3C9BD092-18E6-4C6E-A887-CDFC80ACB206}.Debug|Mixed Platforms.Build.0 = Debug|Win32
|
||||
{3C9BD092-18E6-4C6E-A887-CDFC80ACB206}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{3C9BD092-18E6-4C6E-A887-CDFC80ACB206}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{3C9BD092-18E6-4C6E-A887-CDFC80ACB206}.Release|Any CPU.ActiveCfg = Release|Win32
|
||||
{3C9BD092-18E6-4C6E-A887-CDFC80ACB206}.Release|Mixed Platforms.ActiveCfg = Release|Win32
|
||||
{3C9BD092-18E6-4C6E-A887-CDFC80ACB206}.Release|Mixed Platforms.Build.0 = Release|Win32
|
||||
{3C9BD092-18E6-4C6E-A887-CDFC80ACB206}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{3C9BD092-18E6-4C6E-A887-CDFC80ACB206}.Release|Win32.Build.0 = Release|Win32
|
||||
{A6782DC4-7435-4DB2-9E34-3F0390BC3FDE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{A6782DC4-7435-4DB2-9E34-3F0390BC3FDE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{A6782DC4-7435-4DB2-9E34-3F0390BC3FDE}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
{A6782DC4-7435-4DB2-9E34-3F0390BC3FDE}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||
{A6782DC4-7435-4DB2-9E34-3F0390BC3FDE}.Debug|Win32.ActiveCfg = Debug|Any CPU
|
||||
{A6782DC4-7435-4DB2-9E34-3F0390BC3FDE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{A6782DC4-7435-4DB2-9E34-3F0390BC3FDE}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{A6782DC4-7435-4DB2-9E34-3F0390BC3FDE}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{A6782DC4-7435-4DB2-9E34-3F0390BC3FDE}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{A6782DC4-7435-4DB2-9E34-3F0390BC3FDE}.Release|Win32.ActiveCfg = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
// Copyright (c) .NET Foundation. 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 <iostream>
|
||||
#include <sstream>
|
||||
#include "hub_connection.h"
|
||||
#include "log_writer.h"
|
||||
|
||||
class logger : public signalr::log_writer
|
||||
{
|
||||
// Inherited via log_writer
|
||||
virtual void __cdecl write(const utility::string_t & entry) override
|
||||
{
|
||||
//std::cout << utility::conversions::to_utf8string(entry) << std::endl;
|
||||
}
|
||||
};
|
||||
|
||||
void send_message(signalr::hub_connection& connection, const utility::string_t& name, const utility::string_t& message)
|
||||
{
|
||||
web::json::value args{};
|
||||
args[0] = web::json::value::string(name);
|
||||
args[1] = web::json::value(message);
|
||||
|
||||
// if you get an internal compiler error uncomment the lambda below or install VS Update 4
|
||||
connection.invoke(U("Invoke"), args/*, [](const web::json::value&){}*/)
|
||||
.then([](pplx::task<web::json::value> invoke_task) // fire and forget but we need to observe exceptions
|
||||
{
|
||||
try
|
||||
{
|
||||
auto val = invoke_task.get();
|
||||
ucout << U("Received: ") << val.serialize() << std::endl;
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
ucout << U("Error while sending data: ") << e.what() << std::endl;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void chat(const utility::string_t& name)
|
||||
{
|
||||
signalr::hub_connection connection(U("http://localhost:5000/default"), U(""), signalr::trace_level::all, std::make_shared<logger>());
|
||||
connection.on(U("Send"), [](const web::json::value& m)
|
||||
{
|
||||
ucout << std::endl << m.at(0).as_string() << /*U(" wrote:") << m.at(1).as_string() <<*/ std::endl << U("Enter your message: ");
|
||||
});
|
||||
|
||||
connection.start()
|
||||
.then([&connection, name]()
|
||||
{
|
||||
ucout << U("Enter your message:");
|
||||
for (;;)
|
||||
{
|
||||
utility::string_t message;
|
||||
std::getline(ucin, message);
|
||||
|
||||
if (message == U(":q"))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
send_message(connection, name, message);
|
||||
}
|
||||
})
|
||||
.then([&connection]() // fine to capture by reference - we are blocking so it is guaranteed to be valid
|
||||
{
|
||||
return connection.stop();
|
||||
})
|
||||
.then([](pplx::task<void> stop_task)
|
||||
{
|
||||
try
|
||||
{
|
||||
stop_task.get();
|
||||
ucout << U("connection stopped successfully") << std::endl;
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
ucout << U("exception when starting or stopping connection: ") << e.what() << std::endl;
|
||||
}
|
||||
}).get();
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
ucout << U("Enter your name: ");
|
||||
utility::string_t name;
|
||||
std::getline(ucin, name);
|
||||
|
||||
chat(name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,114 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{3C9BD092-18E6-4C6E-A887-CDFC80ACB206}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>HubConnectionSample</RootNamespace>
|
||||
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir>
|
||||
<DownloadNuGetExe Condition=" '$(DownloadNuGetExe)' == '' ">true</DownloadNuGetExe>
|
||||
<RestorePackages>true</RestorePackages>
|
||||
<WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition="Exists('$(SolutionDir)\.nuget\NuGet.targets')" />
|
||||
<Import Project="..\..\packages\cpprestsdk.v140.windesktop.msvcstl.dyn.rt-dyn.2.9.1\build\native\cpprestsdk.v140.windesktop.msvcstl.dyn.rt-dyn.targets" Condition="Exists('..\..\packages\cpprestsdk.v140.windesktop.msvcstl.dyn.rt-dyn.2.9.1\build\native\cpprestsdk.v140.windesktop.msvcstl.dyn.rt-dyn.targets')" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>..\..\include\signalrclient;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalLibraryDirectories>
|
||||
</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>$(MSBuildThisFileDirectory)..\..\packages\cpprestsdk.v140.windesktop.msvcstl.dyn.rt-dyn.2.9.1\lib\native\v140\windesktop\msvcstl\dyn\rt-dyn\x86\Debug\cpprest140d_2_9.lib;$(MSBuildThisFileDirectory)..\..\bin\Desktop\Win32\Debug\dll\signalrclient.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="stdafx.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="HubConnectionSample.cpp" />
|
||||
<ClCompile Include="stdafx.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\signalrclient\Build\VS\signalrclient.vcxproj">
|
||||
<Project>{87ed3ad4-d820-48cd-8382-a12564213a12}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('$(SolutionDir)\.nuget\NuGet.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\.nuget\NuGet.targets'))" />
|
||||
<Error Condition="!Exists('..\..\packages\cpprestsdk.v140.windesktop.msvcstl.dyn.rt-dyn.2.9.1\build\native\cpprestsdk.v140.windesktop.msvcstl.dyn.rt-dyn.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\cpprestsdk.v140.windesktop.msvcstl.dyn.rt-dyn.2.9.1\build\native\cpprestsdk.v140.windesktop.msvcstl.dyn.rt-dyn.targets'))" />
|
||||
</Target>
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="stdafx.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="stdafx.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="HubConnectionSample.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="cpprestsdk.v140.windesktop.msvcstl.dyn.rt-dyn" version="2.9.1" targetFramework="native" />
|
||||
</packages>
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
#include "stdafx.h"
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
#pragma once
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
// Copyright (c) .NET Foundation. 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 "signalrclient\connection.h"
|
||||
#include <iostream>
|
||||
|
||||
void send_message(signalr::connection &connection, const utility::string_t& message)
|
||||
{
|
||||
connection.send(message)
|
||||
.then([](pplx::task<void> send_task) // fire and forget but we need to observe exceptions
|
||||
{
|
||||
try
|
||||
{
|
||||
send_task.get();
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
ucout << U("Error while sending data: ") << e.what();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
signalr::connection connection{ U("http://localhost:34281/echo") };
|
||||
connection.set_message_received([](const utility::string_t& m)
|
||||
{
|
||||
ucout << U("Message received:") << m << std::endl << U("Enter message: ");
|
||||
});
|
||||
|
||||
connection.start()
|
||||
.then([&connection]() // fine to capture by reference - we are blocking so it is guaranteed to be valid
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
utility::string_t message;
|
||||
std::getline(ucin, message);
|
||||
|
||||
if (message == U(":q"))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
send_message(connection, message);
|
||||
}
|
||||
|
||||
return connection.stop();
|
||||
})
|
||||
.then([](pplx::task<void> stop_task)
|
||||
{
|
||||
try
|
||||
{
|
||||
stop_task.get();
|
||||
ucout << U("connection stopped successfully") << std::endl;
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
ucout << U("exception when starting or closing connection: ") << e.what() << std::endl;
|
||||
}
|
||||
}).get();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,109 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{BD075706-11E9-403B-A2E3-A5E1397E53EF}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>PersistentConnectionSample</RootNamespace>
|
||||
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir>
|
||||
<DownloadNuGetExe Condition=" '$(DownloadNuGetExe)' == '' ">true</DownloadNuGetExe>
|
||||
<RestorePackages>true</RestorePackages>
|
||||
<WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="stdafx.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="PersistentConnectionSample.cpp" />
|
||||
<ClCompile Include="stdafx.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition="Exists('$(SolutionDir)\.nuget\NuGet.targets')" />
|
||||
<Import Project="..\..\packages\cpprestsdk.v140.windesktop.msvcstl.dyn.rt-dyn.2.7.0\build\native\cpprestsdk.v140.windesktop.msvcstl.dyn.rt-dyn.targets" Condition="Exists('..\..\packages\cpprestsdk.v140.windesktop.msvcstl.dyn.rt-dyn.2.7.0\build\native\cpprestsdk.v140.windesktop.msvcstl.dyn.rt-dyn.targets')" />
|
||||
<Import Project="..\..\packages\Microsoft.AspNet.SignalR.Client.Cpp.v140.WinDesktop.1.0.0-beta1\build\native\Microsoft.AspNet.SignalR.Client.Cpp.v140.WinDesktop.targets" Condition="Exists('..\..\packages\Microsoft.AspNet.SignalR.Client.Cpp.v140.WinDesktop.1.0.0-beta1\build\native\Microsoft.AspNet.SignalR.Client.Cpp.v140.WinDesktop.targets')" />
|
||||
</ImportGroup>
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('$(SolutionDir)\.nuget\NuGet.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\.nuget\NuGet.targets'))" />
|
||||
<Error Condition="!Exists('..\..\packages\cpprestsdk.v140.windesktop.msvcstl.dyn.rt-dyn.2.7.0\build\native\cpprestsdk.v140.windesktop.msvcstl.dyn.rt-dyn.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\cpprestsdk.v140.windesktop.msvcstl.dyn.rt-dyn.2.7.0\build\native\cpprestsdk.v140.windesktop.msvcstl.dyn.rt-dyn.targets'))" />
|
||||
<Error Condition="!Exists('..\..\packages\Microsoft.AspNet.SignalR.Client.Cpp.v140.WinDesktop.1.0.0-beta1\build\native\Microsoft.AspNet.SignalR.Client.Cpp.v140.WinDesktop.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Microsoft.AspNet.SignalR.Client.Cpp.v140.WinDesktop.1.0.0-beta1\build\native\Microsoft.AspNet.SignalR.Client.Cpp.v140.WinDesktop.targets'))" />
|
||||
</Target>
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="stdafx.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="stdafx.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="PersistentConnectionSample.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="cpprestsdk.v140.windesktop.msvcstl.dyn.rt-dyn" version="2.7.0" targetFramework="native" />
|
||||
<package id="Microsoft.AspNet.SignalR.Client.Cpp.v140.WinDesktop" version="1.0.0-beta1" targetFramework="native" />
|
||||
</packages>
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
#include "stdafx.h"
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
#pragma once
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using Microsoft.AspNet.SignalR;
|
||||
|
||||
namespace SignalRServer
|
||||
{
|
||||
public class ChatHub : Hub
|
||||
{
|
||||
public void Send(string name, string message)
|
||||
{
|
||||
// Call the broadcastMessage method to update clients.
|
||||
Clients.All.broadcastMessage(name, message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.SignalR;
|
||||
|
||||
namespace SignalRServer
|
||||
{
|
||||
public class EchoConnection : PersistentConnection
|
||||
{
|
||||
protected override Task OnConnected(IRequest request, string connectionId)
|
||||
{
|
||||
return Connection.Send(connectionId, "Welcome!");
|
||||
}
|
||||
|
||||
protected override Task OnReceived(IRequest request, string connectionId, string data)
|
||||
{
|
||||
return Connection.Broadcast(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("SignalRServer")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("SignalRServer")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2015")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("64b40dbb-f6c1-45b4-8fc4-764526e9f16c")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Revision and Build Numbers
|
||||
// by using the '*' as shown below:
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,153 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProductVersion>
|
||||
</ProductVersion>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectGuid>{A6782DC4-7435-4DB2-9E34-3F0390BC3FDE}</ProjectGuid>
|
||||
<ProjectTypeGuids>{349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>SignalRServer</RootNamespace>
|
||||
<AssemblyName>SignalRServer</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
||||
<UseIISExpress>true</UseIISExpress>
|
||||
<IISExpressSSLPort />
|
||||
<IISExpressAnonymousAuthentication />
|
||||
<IISExpressWindowsAuthentication />
|
||||
<IISExpressUseClassicPipelineMode />
|
||||
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir>
|
||||
<DownloadNuGetExe Condition=" '$(DownloadNuGetExe)' == '' ">true</DownloadNuGetExe>
|
||||
<RestorePackages>true</RestorePackages>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Microsoft.AspNet.SignalR.Core">
|
||||
<HintPath>..\..\packages\Microsoft.AspNet.SignalR.Core.2.2.0\lib\net45\Microsoft.AspNet.SignalR.Core.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.AspNet.SignalR.SystemWeb">
|
||||
<HintPath>..\..\packages\Microsoft.AspNet.SignalR.SystemWeb.2.2.0\lib\net45\Microsoft.AspNet.SignalR.SystemWeb.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="Microsoft.Owin, Version=3.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\..\packages\Microsoft.Owin.3.0.1\lib\net45\Microsoft.Owin.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Owin.Host.SystemWeb">
|
||||
<HintPath>..\..\packages\Microsoft.Owin.Host.SystemWeb.3.0.0\lib\net45\Microsoft.Owin.Host.SystemWeb.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Owin.Security">
|
||||
<HintPath>..\..\packages\Microsoft.Owin.Security.3.0.1\lib\net45\Microsoft.Owin.Security.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Web.Infrastructure, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<Private>True</Private>
|
||||
<HintPath>..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Newtonsoft.Json, Version=6.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\..\packages\Newtonsoft.Json.6.0.4\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Owin">
|
||||
<HintPath>..\..\packages\Owin.1.0\lib\net40\Owin.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Web.DynamicData" />
|
||||
<Reference Include="System.Web.Entity" />
|
||||
<Reference Include="System.Web.ApplicationServices" />
|
||||
<Reference Include="System.ComponentModel.DataAnnotations" />
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="System.Web.Extensions" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.Web" />
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="System.Configuration" />
|
||||
<Reference Include="System.Web.Services" />
|
||||
<Reference Include="System.EnterpriseServices" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="packages.config" />
|
||||
<Content Include="Scripts\jquery-1.10.2.min.map" />
|
||||
<None Include="Web.Debug.config">
|
||||
<DependentUpon>Web.config</DependentUpon>
|
||||
</None>
|
||||
<None Include="Web.Release.config">
|
||||
<DependentUpon>Web.config</DependentUpon>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="Scripts\jquery-1.10.2.intellisense.js" />
|
||||
<Content Include="index.html" />
|
||||
<Content Include="Scripts\jquery-1.10.2.js" />
|
||||
<Content Include="Scripts\jquery-1.10.2.min.js" />
|
||||
<Content Include="Scripts\jquery.signalR-2.2.0.js" />
|
||||
<Content Include="Scripts\jquery.signalR-2.2.0.min.js" />
|
||||
<Content Include="Web.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="ChatHub.cs" />
|
||||
<Compile Include="EchoConnection.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Startup.cs" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup>
|
||||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
|
||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||
<Import Project="$(VSToolsPath)\WebApplications\Microsoft.WebApplication.targets" Condition="'$(VSToolsPath)' != ''" />
|
||||
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" Condition="false" />
|
||||
<ProjectExtensions>
|
||||
<VisualStudio>
|
||||
<FlavorProperties GUID="{349c5851-65df-11da-9384-00065b846f21}">
|
||||
<WebProjectProperties>
|
||||
<UseIIS>True</UseIIS>
|
||||
<AutoAssignPort>True</AutoAssignPort>
|
||||
<DevelopmentServerPort>34281</DevelopmentServerPort>
|
||||
<DevelopmentServerVPath>/</DevelopmentServerVPath>
|
||||
<IISUrl>http://localhost:34281/</IISUrl>
|
||||
<NTLMAuthentication>False</NTLMAuthentication>
|
||||
<UseCustomServer>False</UseCustomServer>
|
||||
<CustomServerUrl>
|
||||
</CustomServerUrl>
|
||||
<SaveServerSettingsInUserFile>False</SaveServerSettingsInUserFile>
|
||||
</WebProjectProperties>
|
||||
</FlavorProperties>
|
||||
</VisualStudio>
|
||||
</ProjectExtensions>
|
||||
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition="Exists('$(SolutionDir)\.nuget\NuGet.targets')" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('$(SolutionDir)\.nuget\NuGet.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\.nuget\NuGet.targets'))" />
|
||||
</Target>
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Owin;
|
||||
using Owin;
|
||||
|
||||
[assembly: OwinStartup(typeof(SignalRServer.Startup))]
|
||||
|
||||
namespace SignalRServer
|
||||
{
|
||||
public class Startup
|
||||
{
|
||||
public void Configuration(IAppBuilder app)
|
||||
{
|
||||
app.MapSignalR();
|
||||
app.MapSignalR<EchoConnection>("/echo");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<!-- For more information on using web.config transformation visit http://go.microsoft.com/fwlink/?LinkId=125889 -->
|
||||
|
||||
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
|
||||
<!--
|
||||
In the example below, the "SetAttributes" transform will change the value of
|
||||
"connectionString" to use "ReleaseSQLServer" only when the "Match" locator
|
||||
finds an attribute "name" that has a value of "MyDB".
|
||||
|
||||
<connectionStrings>
|
||||
<add name="MyDB"
|
||||
connectionString="Data Source=ReleaseSQLServer;Initial Catalog=MyReleaseDB;Integrated Security=True"
|
||||
xdt:Transform="SetAttributes" xdt:Locator="Match(name)"/>
|
||||
</connectionStrings>
|
||||
-->
|
||||
<system.web>
|
||||
<!--
|
||||
In the example below, the "Replace" transform will replace the entire
|
||||
<customErrors> section of your web.config file.
|
||||
Note that because there is only one customErrors section under the
|
||||
<system.web> node, there is no need to use the "xdt:Locator" attribute.
|
||||
|
||||
<customErrors defaultRedirect="GenericError.htm"
|
||||
mode="RemoteOnly" xdt:Transform="Replace">
|
||||
<error statusCode="500" redirect="InternalError.htm"/>
|
||||
</customErrors>
|
||||
-->
|
||||
</system.web>
|
||||
</configuration>
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<!-- For more information on using web.config transformation visit http://go.microsoft.com/fwlink/?LinkId=125889 -->
|
||||
|
||||
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
|
||||
<!--
|
||||
In the example below, the "SetAttributes" transform will change the value of
|
||||
"connectionString" to use "ReleaseSQLServer" only when the "Match" locator
|
||||
finds an attribute "name" that has a value of "MyDB".
|
||||
|
||||
<connectionStrings>
|
||||
<add name="MyDB"
|
||||
connectionString="Data Source=ReleaseSQLServer;Initial Catalog=MyReleaseDB;Integrated Security=True"
|
||||
xdt:Transform="SetAttributes" xdt:Locator="Match(name)"/>
|
||||
</connectionStrings>
|
||||
-->
|
||||
<system.web>
|
||||
<compilation xdt:Transform="RemoveAttributes(debug)" />
|
||||
<!--
|
||||
In the example below, the "Replace" transform will replace the entire
|
||||
<customErrors> section of your web.config file.
|
||||
Note that because there is only one customErrors section under the
|
||||
<system.web> node, there is no need to use the "xdt:Locator" attribute.
|
||||
|
||||
<customErrors defaultRedirect="GenericError.htm"
|
||||
mode="RemoteOnly" xdt:Transform="Replace">
|
||||
<error statusCode="500" redirect="InternalError.htm"/>
|
||||
</customErrors>
|
||||
-->
|
||||
</system.web>
|
||||
</configuration>
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
For more information on how to configure your ASP.NET application, please visit
|
||||
http://go.microsoft.com/fwlink/?LinkId=169433
|
||||
-->
|
||||
<configuration>
|
||||
<system.web>
|
||||
<compilation debug="true" targetFramework="4.5" />
|
||||
<httpRuntime targetFramework="4.5" />
|
||||
</system.web>
|
||||
<runtime>
|
||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Microsoft.Owin" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Microsoft.Owin.Security" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0" />
|
||||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
</runtime>
|
||||
</configuration>
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>SignalR Simple Chat</title>
|
||||
<style type="text/css">
|
||||
.container {
|
||||
background-color: #99CCFF;
|
||||
border: thick solid #808080;
|
||||
padding: 20px;
|
||||
margin: 20px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<input type="text" id="message" />
|
||||
<input type="button" id="sendmessage" value="Send" />
|
||||
<input type="hidden" id="displayname" />
|
||||
<ul id="discussion"></ul>
|
||||
</div>
|
||||
<!--Script references. -->
|
||||
<!--Reference the jQuery library. -->
|
||||
<script src="Scripts/jquery-1.10.2.min.js"></script>
|
||||
<!--Reference the SignalR library. -->
|
||||
<script src="Scripts/jquery.signalR-2.2.0.min.js"></script>
|
||||
<!--Reference the autogenerated SignalR hub script. -->
|
||||
<script src="signalr/hubs"></script>
|
||||
<!--Add script to update the page and send messages.-->
|
||||
<script type="text/javascript">
|
||||
$(function () {
|
||||
// Declare a proxy to reference the hub.
|
||||
var chat = $.connection.chatHub;
|
||||
// Create a function that the hub can call to broadcast messages.
|
||||
chat.client.broadcastMessage = function (name, message) {
|
||||
// Html encode display name and message.
|
||||
var encodedName = $('<div />').text(name).html();
|
||||
var encodedMsg = $('<div />').text(message).html();
|
||||
// Add the message to the page.
|
||||
$('#discussion').append('<li><strong>' + encodedName
|
||||
+ '</strong>: ' + encodedMsg + '</li>');
|
||||
};
|
||||
// Get the user name and store it to prepend to messages.
|
||||
$('#displayname').val(prompt('Enter your name:', ''));
|
||||
// Set initial focus to message input box.
|
||||
$('#message').focus();
|
||||
// Start the connection.
|
||||
$.connection.hub.start().done(function () {
|
||||
$('#sendmessage').click(function () {
|
||||
// Call the Send method on the hub.
|
||||
chat.server.send($('#displayname').val(), $('#message').val());
|
||||
// Clear text box and reset focus for next comment.
|
||||
$('#message').val('').focus();
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="jQuery" version="1.10.2" targetFramework="net45" />
|
||||
<package id="Microsoft.AspNet.SignalR" version="2.2.0" targetFramework="net45" />
|
||||
<package id="Microsoft.AspNet.SignalR.Core" version="2.2.0" targetFramework="net45" />
|
||||
<package id="Microsoft.AspNet.SignalR.JS" version="2.2.0" targetFramework="net45" />
|
||||
<package id="Microsoft.AspNet.SignalR.SystemWeb" version="2.2.0" targetFramework="net45" />
|
||||
<package id="Microsoft.Owin" version="3.0.1" targetFramework="net45" />
|
||||
<package id="Microsoft.Owin.Host.SystemWeb" version="3.0.0" targetFramework="net45" />
|
||||
<package id="Microsoft.Owin.Security" version="3.0.1" targetFramework="net45" />
|
||||
<package id="Microsoft.Web.Infrastructure" version="1.0.0.0" targetFramework="net45" />
|
||||
<package id="Newtonsoft.Json" version="6.0.4" targetFramework="net45" />
|
||||
<package id="Owin" version="1.0" targetFramework="net45" />
|
||||
</packages>
|
||||
|
|
@ -0,0 +1,146 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.27428.1
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "signalrclient", "src\signalrclient\Build\VS\signalrclient.vcxproj", "{87ED3AD4-D820-48CD-8382-A12564213A12}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "signalrclienttests", "test\signalrclienttests\Build\VS\signalrclienttests.vcxproj", "{10376148-BCF4-4B55-98A5-3C98C87FD898}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gtest", "test\gtest-1.8.0\msvc\gtest.vcxproj", "{2AF210A9-5BDC-45E8-95DD-07B5A2616493}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "signalrclientdll", "src\signalrclientdll\Build\VS\signalrclientdll.vcxproj", "{18377AE8-E372-40CE-94FD-7F65008D39A3}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{063421D3-4E32-4BE5-874A-2E784B450858}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
.nuget\NuGet.Config = .nuget\NuGet.Config
|
||||
.nuget\NuGet.exe = .nuget\NuGet.exe
|
||||
.nuget\NuGet.targets = .nuget\NuGet.targets
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{AABF08B1-12A4-4D06-A188-F01FBF8A9658}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "signalrclient-e2e-tests", "test\signalrclient-e2e-tests\Build\VS\signalrclient-e2e-tests.vcxproj", "{6006C96A-29F0-4B18-8DDD-764DC3419E2F}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "signalrclient-testhost", "test\signalrclient-testhost\signalrclient-testhost.csproj", "{11848039-1F13-4047-9539-8F9F45930788}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HubConnectionSample", "samples\HubConnectionSample\HubConnectionSample.vcxproj", "{3C9BD092-18E6-4C6E-A887-CDFC80ACB206}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Debug|Mixed Platforms = Debug|Mixed Platforms
|
||||
Debug|Win32 = Debug|Win32
|
||||
Debug|x64 = Debug|x64
|
||||
Release|Any CPU = Release|Any CPU
|
||||
Release|Mixed Platforms = Release|Mixed Platforms
|
||||
Release|Win32 = Release|Win32
|
||||
Release|x64 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{87ED3AD4-D820-48CD-8382-A12564213A12}.Debug|Any CPU.ActiveCfg = Debug|Win32
|
||||
{87ED3AD4-D820-48CD-8382-A12564213A12}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32
|
||||
{87ED3AD4-D820-48CD-8382-A12564213A12}.Debug|Mixed Platforms.Build.0 = Debug|Win32
|
||||
{87ED3AD4-D820-48CD-8382-A12564213A12}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{87ED3AD4-D820-48CD-8382-A12564213A12}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{87ED3AD4-D820-48CD-8382-A12564213A12}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{87ED3AD4-D820-48CD-8382-A12564213A12}.Debug|x64.Build.0 = Debug|x64
|
||||
{87ED3AD4-D820-48CD-8382-A12564213A12}.Release|Any CPU.ActiveCfg = Release|Win32
|
||||
{87ED3AD4-D820-48CD-8382-A12564213A12}.Release|Mixed Platforms.ActiveCfg = Release|Win32
|
||||
{87ED3AD4-D820-48CD-8382-A12564213A12}.Release|Mixed Platforms.Build.0 = Release|Win32
|
||||
{87ED3AD4-D820-48CD-8382-A12564213A12}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{87ED3AD4-D820-48CD-8382-A12564213A12}.Release|Win32.Build.0 = Release|Win32
|
||||
{87ED3AD4-D820-48CD-8382-A12564213A12}.Release|x64.ActiveCfg = Release|x64
|
||||
{87ED3AD4-D820-48CD-8382-A12564213A12}.Release|x64.Build.0 = Release|x64
|
||||
{10376148-BCF4-4B55-98A5-3C98C87FD898}.Debug|Any CPU.ActiveCfg = Debug|Win32
|
||||
{10376148-BCF4-4B55-98A5-3C98C87FD898}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32
|
||||
{10376148-BCF4-4B55-98A5-3C98C87FD898}.Debug|Mixed Platforms.Build.0 = Debug|Win32
|
||||
{10376148-BCF4-4B55-98A5-3C98C87FD898}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{10376148-BCF4-4B55-98A5-3C98C87FD898}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{10376148-BCF4-4B55-98A5-3C98C87FD898}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{10376148-BCF4-4B55-98A5-3C98C87FD898}.Debug|x64.Build.0 = Debug|x64
|
||||
{10376148-BCF4-4B55-98A5-3C98C87FD898}.Release|Any CPU.ActiveCfg = Release|Win32
|
||||
{10376148-BCF4-4B55-98A5-3C98C87FD898}.Release|Mixed Platforms.ActiveCfg = Release|Win32
|
||||
{10376148-BCF4-4B55-98A5-3C98C87FD898}.Release|Mixed Platforms.Build.0 = Release|Win32
|
||||
{10376148-BCF4-4B55-98A5-3C98C87FD898}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{10376148-BCF4-4B55-98A5-3C98C87FD898}.Release|Win32.Build.0 = Release|Win32
|
||||
{10376148-BCF4-4B55-98A5-3C98C87FD898}.Release|x64.ActiveCfg = Release|x64
|
||||
{10376148-BCF4-4B55-98A5-3C98C87FD898}.Release|x64.Build.0 = Release|x64
|
||||
{2AF210A9-5BDC-45E8-95DD-07B5A2616493}.Debug|Any CPU.ActiveCfg = Debug|Win32
|
||||
{2AF210A9-5BDC-45E8-95DD-07B5A2616493}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32
|
||||
{2AF210A9-5BDC-45E8-95DD-07B5A2616493}.Debug|Mixed Platforms.Build.0 = Debug|Win32
|
||||
{2AF210A9-5BDC-45E8-95DD-07B5A2616493}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{2AF210A9-5BDC-45E8-95DD-07B5A2616493}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{2AF210A9-5BDC-45E8-95DD-07B5A2616493}.Debug|x64.ActiveCfg = Debug|Win32
|
||||
{2AF210A9-5BDC-45E8-95DD-07B5A2616493}.Release|Any CPU.ActiveCfg = Release|Win32
|
||||
{2AF210A9-5BDC-45E8-95DD-07B5A2616493}.Release|Mixed Platforms.ActiveCfg = Release|Win32
|
||||
{2AF210A9-5BDC-45E8-95DD-07B5A2616493}.Release|Mixed Platforms.Build.0 = Release|Win32
|
||||
{2AF210A9-5BDC-45E8-95DD-07B5A2616493}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{2AF210A9-5BDC-45E8-95DD-07B5A2616493}.Release|Win32.Build.0 = Release|Win32
|
||||
{2AF210A9-5BDC-45E8-95DD-07B5A2616493}.Release|x64.ActiveCfg = Release|Win32
|
||||
{18377AE8-E372-40CE-94FD-7F65008D39A3}.Debug|Any CPU.ActiveCfg = Debug|Win32
|
||||
{18377AE8-E372-40CE-94FD-7F65008D39A3}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32
|
||||
{18377AE8-E372-40CE-94FD-7F65008D39A3}.Debug|Mixed Platforms.Build.0 = Debug|Win32
|
||||
{18377AE8-E372-40CE-94FD-7F65008D39A3}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{18377AE8-E372-40CE-94FD-7F65008D39A3}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{18377AE8-E372-40CE-94FD-7F65008D39A3}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{18377AE8-E372-40CE-94FD-7F65008D39A3}.Debug|x64.Build.0 = Debug|x64
|
||||
{18377AE8-E372-40CE-94FD-7F65008D39A3}.Release|Any CPU.ActiveCfg = Release|Win32
|
||||
{18377AE8-E372-40CE-94FD-7F65008D39A3}.Release|Mixed Platforms.ActiveCfg = Release|Win32
|
||||
{18377AE8-E372-40CE-94FD-7F65008D39A3}.Release|Mixed Platforms.Build.0 = Release|Win32
|
||||
{18377AE8-E372-40CE-94FD-7F65008D39A3}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{18377AE8-E372-40CE-94FD-7F65008D39A3}.Release|Win32.Build.0 = Release|Win32
|
||||
{18377AE8-E372-40CE-94FD-7F65008D39A3}.Release|x64.ActiveCfg = Release|x64
|
||||
{18377AE8-E372-40CE-94FD-7F65008D39A3}.Release|x64.Build.0 = Release|x64
|
||||
{6006C96A-29F0-4B18-8DDD-764DC3419E2F}.Debug|Any CPU.ActiveCfg = Debug|Win32
|
||||
{6006C96A-29F0-4B18-8DDD-764DC3419E2F}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32
|
||||
{6006C96A-29F0-4B18-8DDD-764DC3419E2F}.Debug|Mixed Platforms.Build.0 = Debug|Win32
|
||||
{6006C96A-29F0-4B18-8DDD-764DC3419E2F}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{6006C96A-29F0-4B18-8DDD-764DC3419E2F}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{6006C96A-29F0-4B18-8DDD-764DC3419E2F}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{6006C96A-29F0-4B18-8DDD-764DC3419E2F}.Debug|x64.Build.0 = Debug|x64
|
||||
{6006C96A-29F0-4B18-8DDD-764DC3419E2F}.Release|Any CPU.ActiveCfg = Release|Win32
|
||||
{6006C96A-29F0-4B18-8DDD-764DC3419E2F}.Release|Mixed Platforms.ActiveCfg = Release|Win32
|
||||
{6006C96A-29F0-4B18-8DDD-764DC3419E2F}.Release|Mixed Platforms.Build.0 = Release|Win32
|
||||
{6006C96A-29F0-4B18-8DDD-764DC3419E2F}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{6006C96A-29F0-4B18-8DDD-764DC3419E2F}.Release|Win32.Build.0 = Release|Win32
|
||||
{6006C96A-29F0-4B18-8DDD-764DC3419E2F}.Release|x64.ActiveCfg = Release|x64
|
||||
{6006C96A-29F0-4B18-8DDD-764DC3419E2F}.Release|x64.Build.0 = Release|x64
|
||||
{11848039-1F13-4047-9539-8F9F45930788}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{11848039-1F13-4047-9539-8F9F45930788}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{11848039-1F13-4047-9539-8F9F45930788}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
{11848039-1F13-4047-9539-8F9F45930788}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||
{11848039-1F13-4047-9539-8F9F45930788}.Debug|Win32.ActiveCfg = Debug|Any CPU
|
||||
{11848039-1F13-4047-9539-8F9F45930788}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{11848039-1F13-4047-9539-8F9F45930788}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{11848039-1F13-4047-9539-8F9F45930788}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{11848039-1F13-4047-9539-8F9F45930788}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{11848039-1F13-4047-9539-8F9F45930788}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{11848039-1F13-4047-9539-8F9F45930788}.Release|Win32.ActiveCfg = Release|Any CPU
|
||||
{11848039-1F13-4047-9539-8F9F45930788}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{3C9BD092-18E6-4C6E-A887-CDFC80ACB206}.Debug|Any CPU.ActiveCfg = Debug|Win32
|
||||
{3C9BD092-18E6-4C6E-A887-CDFC80ACB206}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32
|
||||
{3C9BD092-18E6-4C6E-A887-CDFC80ACB206}.Debug|Mixed Platforms.Build.0 = Debug|Win32
|
||||
{3C9BD092-18E6-4C6E-A887-CDFC80ACB206}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{3C9BD092-18E6-4C6E-A887-CDFC80ACB206}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{3C9BD092-18E6-4C6E-A887-CDFC80ACB206}.Debug|x64.ActiveCfg = Debug|Win32
|
||||
{3C9BD092-18E6-4C6E-A887-CDFC80ACB206}.Release|Any CPU.ActiveCfg = Release|Win32
|
||||
{3C9BD092-18E6-4C6E-A887-CDFC80ACB206}.Release|Mixed Platforms.ActiveCfg = Release|Win32
|
||||
{3C9BD092-18E6-4C6E-A887-CDFC80ACB206}.Release|Mixed Platforms.Build.0 = Release|Win32
|
||||
{3C9BD092-18E6-4C6E-A887-CDFC80ACB206}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{3C9BD092-18E6-4C6E-A887-CDFC80ACB206}.Release|Win32.Build.0 = Release|Win32
|
||||
{3C9BD092-18E6-4C6E-A887-CDFC80ACB206}.Release|x64.ActiveCfg = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{10376148-BCF4-4B55-98A5-3C98C87FD898} = {AABF08B1-12A4-4D06-A188-F01FBF8A9658}
|
||||
{2AF210A9-5BDC-45E8-95DD-07B5A2616493} = {AABF08B1-12A4-4D06-A188-F01FBF8A9658}
|
||||
{6006C96A-29F0-4B18-8DDD-764DC3419E2F} = {AABF08B1-12A4-4D06-A188-F01FBF8A9658}
|
||||
{11848039-1F13-4047-9539-8F9F45930788} = {AABF08B1-12A4-4D06-A188-F01FBF8A9658}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {0286287F-3519-42E6-9165-FB342028F9FF}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="cpprestsdk" version="2.9.1.1" targetFramework="native" />
|
||||
<package id="cpprestsdk.v120.winapp.msvcstl.dyn.rt-dyn" version="2.9.1" targetFramework="native" />
|
||||
<package id="cpprestsdk.v120.windesktop.msvcstl.dyn.rt-dyn" version="2.9.1" targetFramework="native" />
|
||||
<package id="cpprestsdk.v120.winphone.msvcstl.dyn.rt-dyn" version="2.9.1" targetFramework="native" />
|
||||
<package id="cpprestsdk.v120.winphonesl.msvcstl.dyn.rt-dyn" version="2.9.1" targetFramework="native" />
|
||||
<package id="cpprestsdk.v120.winxp.msvcstl.dyn.rt-dyn" version="2.9.1" targetFramework="native" />
|
||||
<package id="cpprestsdk.v140.winapp.msvcstl.dyn.rt-dyn" version="2.9.1" targetFramework="native" />
|
||||
<package id="cpprestsdk.v140.windesktop.msvcstl.dyn.rt-dyn" version="2.9.1" targetFramework="native" />
|
||||
</packages>
|
||||
|
|
@ -0,0 +1,129 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="..\..\..\..\Build\SignalRClient.Build.Settings" />
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{87ED3AD4-D820-48CD-8382-A12564213A12}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>signalr</RootNamespace>
|
||||
<ProjectName>signalrclient</ProjectName>
|
||||
<TargetName>$(SignalrClientTargetName)</TargetName>
|
||||
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\..\..\</SolutionDir>
|
||||
<OutDir Condition="'$(OutDir)' == ''">$(SolutionDir)$(Configuration)\</OutDir>
|
||||
<OutDir>$(OutDir)lib\</OutDir>
|
||||
<IntDir>$(Configuration)\lib\</IntDir>
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="..\..\..\..\Build\Config.Definitions.props" />
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions>_WINDOWS;_USRDLL;NO_SIGNALRCLIENT_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>..\..\..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\..\..\include\signalrclient\connection.h" />
|
||||
<ClInclude Include="..\..\..\..\include\signalrclient\connection_state.h" />
|
||||
<ClInclude Include="..\..\..\..\include\signalrclient\hub_connection.h" />
|
||||
<ClInclude Include="..\..\..\..\include\signalrclient\hub_exception.h" />
|
||||
<ClInclude Include="..\..\..\..\include\signalrclient\log_writer.h" />
|
||||
<ClInclude Include="..\..\..\..\include\signalrclient\signalr_client_config.h" />
|
||||
<ClInclude Include="..\..\..\..\include\signalrclient\signalr_exception.h" />
|
||||
<ClInclude Include="..\..\..\..\include\signalrclient\trace_level.h" />
|
||||
<ClInclude Include="..\..\..\..\include\signalrclient\transport_type.h" />
|
||||
<ClInclude Include="..\..\..\..\include\signalrclient\web_exception.h" />
|
||||
<ClInclude Include="..\..\..\..\include\signalrclient\_exports.h" />
|
||||
<ClInclude Include="..\..\case_insensitive_comparison_utils.h" />
|
||||
<ClInclude Include="..\..\connection_impl.h" />
|
||||
<ClInclude Include="..\..\constants.h" />
|
||||
<ClInclude Include="..\..\default_websocket_client.h" />
|
||||
<ClInclude Include="..\..\event.h" />
|
||||
<ClInclude Include="..\..\http_sender.h" />
|
||||
<ClInclude Include="..\..\hub_connection_impl.h" />
|
||||
<ClInclude Include="..\..\callback_manager.h" />
|
||||
<ClInclude Include="..\..\logger.h" />
|
||||
<ClInclude Include="..\..\negotiation_response.h" />
|
||||
<ClInclude Include="..\..\request_sender.h" />
|
||||
<ClInclude Include="..\..\stdafx.h" />
|
||||
<ClInclude Include="..\..\trace_log_writer.h" />
|
||||
<ClInclude Include="..\..\transport.h" />
|
||||
<ClInclude Include="..\..\transport_factory.h" />
|
||||
<ClInclude Include="..\..\url_builder.h" />
|
||||
<ClInclude Include="..\..\websocket_client.h" />
|
||||
<ClInclude Include="..\..\websocket_transport.h" />
|
||||
<ClInclude Include="..\..\web_request.h" />
|
||||
<ClInclude Include="..\..\web_request_factory.h" />
|
||||
<ClInclude Include="..\..\web_response.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\connection.cpp" />
|
||||
<ClCompile Include="..\..\connection_impl.cpp" />
|
||||
<ClCompile Include="..\..\http_sender.cpp" />
|
||||
<ClCompile Include="..\..\hub_connection.cpp" />
|
||||
<ClCompile Include="..\..\hub_connection_impl.cpp" />
|
||||
<ClCompile Include="..\..\callback_manager.cpp" />
|
||||
<ClCompile Include="..\..\logger.cpp" />
|
||||
<ClCompile Include="..\..\request_sender.cpp" />
|
||||
<ClCompile Include="..\..\signalr_client_config.cpp" />
|
||||
<ClCompile Include="..\..\stdafx.cpp">
|
||||
<PrecompiledHeader>Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\trace_log_writer.cpp" />
|
||||
<ClCompile Include="..\..\transport.cpp" />
|
||||
<ClCompile Include="..\..\transport_factory.cpp" />
|
||||
<ClCompile Include="..\..\url_builder.cpp" />
|
||||
<ClCompile Include="..\..\default_websocket_client.cpp" />
|
||||
<ClCompile Include="..\..\websocket_transport.cpp" />
|
||||
<ClCompile Include="..\..\web_request.cpp" />
|
||||
<ClCompile Include="..\..\web_request_factory.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\signalrclientdll\Build\VS\signalrclientdll.vcxproj">
|
||||
<Project>{18377ae8-e372-40ce-94fd-7f65008d39a3}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition="Exists('$(SolutionDir)\.nuget\NuGet.targets')" />
|
||||
<Import Project="..\..\..\..\packages\cpprestsdk.v120.winapp.msvcstl.dyn.rt-dyn.2.9.1\build\native\cpprestsdk.v120.winapp.msvcstl.dyn.rt-dyn.targets" Condition="Exists('..\..\..\..\packages\cpprestsdk.v120.winapp.msvcstl.dyn.rt-dyn.2.9.1\build\native\cpprestsdk.v120.winapp.msvcstl.dyn.rt-dyn.targets')" />
|
||||
<Import Project="..\..\..\..\packages\cpprestsdk.v120.windesktop.msvcstl.dyn.rt-dyn.2.9.1\build\native\cpprestsdk.v120.windesktop.msvcstl.dyn.rt-dyn.targets" Condition="Exists('..\..\..\..\packages\cpprestsdk.v120.windesktop.msvcstl.dyn.rt-dyn.2.9.1\build\native\cpprestsdk.v120.windesktop.msvcstl.dyn.rt-dyn.targets')" />
|
||||
<Import Project="..\..\..\..\packages\cpprestsdk.v120.winphone.msvcstl.dyn.rt-dyn.2.9.1\build\native\cpprestsdk.v120.winphone.msvcstl.dyn.rt-dyn.targets" Condition="Exists('..\..\..\..\packages\cpprestsdk.v120.winphone.msvcstl.dyn.rt-dyn.2.9.1\build\native\cpprestsdk.v120.winphone.msvcstl.dyn.rt-dyn.targets')" />
|
||||
<Import Project="..\..\..\..\packages\cpprestsdk.v120.winphonesl.msvcstl.dyn.rt-dyn.2.9.1\build\native\cpprestsdk.v120.winphonesl.msvcstl.dyn.rt-dyn.targets" Condition="Exists('..\..\..\..\packages\cpprestsdk.v120.winphonesl.msvcstl.dyn.rt-dyn.2.9.1\build\native\cpprestsdk.v120.winphonesl.msvcstl.dyn.rt-dyn.targets')" />
|
||||
<Import Project="..\..\..\..\packages\cpprestsdk.v120.winxp.msvcstl.dyn.rt-dyn.2.9.1\build\native\cpprestsdk.v120.winxp.msvcstl.dyn.rt-dyn.targets" Condition="Exists('..\..\..\..\packages\cpprestsdk.v120.winxp.msvcstl.dyn.rt-dyn.2.9.1\build\native\cpprestsdk.v120.winxp.msvcstl.dyn.rt-dyn.targets')" />
|
||||
<Import Project="..\..\..\..\packages\cpprestsdk.v140.winapp.msvcstl.dyn.rt-dyn.2.9.1\build\native\cpprestsdk.v140.winapp.msvcstl.dyn.rt-dyn.targets" Condition="Exists('..\..\..\..\packages\cpprestsdk.v140.winapp.msvcstl.dyn.rt-dyn.2.9.1\build\native\cpprestsdk.v140.winapp.msvcstl.dyn.rt-dyn.targets')" />
|
||||
<Import Project="..\..\..\..\packages\cpprestsdk.v140.windesktop.msvcstl.dyn.rt-dyn.2.9.1\build\native\cpprestsdk.v140.windesktop.msvcstl.dyn.rt-dyn.targets" Condition="Exists('..\..\..\..\packages\cpprestsdk.v140.windesktop.msvcstl.dyn.rt-dyn.2.9.1\build\native\cpprestsdk.v140.windesktop.msvcstl.dyn.rt-dyn.targets')" />
|
||||
</ImportGroup>
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('$(SolutionDir)\.nuget\NuGet.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\.nuget\NuGet.targets'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\cpprestsdk.v120.winapp.msvcstl.dyn.rt-dyn.2.9.1\build\native\cpprestsdk.v120.winapp.msvcstl.dyn.rt-dyn.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\cpprestsdk.v120.winapp.msvcstl.dyn.rt-dyn.2.9.1\build\native\cpprestsdk.v120.winapp.msvcstl.dyn.rt-dyn.targets'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\cpprestsdk.v120.windesktop.msvcstl.dyn.rt-dyn.2.9.1\build\native\cpprestsdk.v120.windesktop.msvcstl.dyn.rt-dyn.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\cpprestsdk.v120.windesktop.msvcstl.dyn.rt-dyn.2.9.1\build\native\cpprestsdk.v120.windesktop.msvcstl.dyn.rt-dyn.targets'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\cpprestsdk.v120.winphone.msvcstl.dyn.rt-dyn.2.9.1\build\native\cpprestsdk.v120.winphone.msvcstl.dyn.rt-dyn.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\cpprestsdk.v120.winphone.msvcstl.dyn.rt-dyn.2.9.1\build\native\cpprestsdk.v120.winphone.msvcstl.dyn.rt-dyn.targets'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\cpprestsdk.v120.winphonesl.msvcstl.dyn.rt-dyn.2.9.1\build\native\cpprestsdk.v120.winphonesl.msvcstl.dyn.rt-dyn.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\cpprestsdk.v120.winphonesl.msvcstl.dyn.rt-dyn.2.9.1\build\native\cpprestsdk.v120.winphonesl.msvcstl.dyn.rt-dyn.targets'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\cpprestsdk.v120.winxp.msvcstl.dyn.rt-dyn.2.9.1\build\native\cpprestsdk.v120.winxp.msvcstl.dyn.rt-dyn.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\cpprestsdk.v120.winxp.msvcstl.dyn.rt-dyn.2.9.1\build\native\cpprestsdk.v120.winxp.msvcstl.dyn.rt-dyn.targets'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\cpprestsdk.v140.winapp.msvcstl.dyn.rt-dyn.2.9.1\build\native\cpprestsdk.v140.winapp.msvcstl.dyn.rt-dyn.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\cpprestsdk.v140.winapp.msvcstl.dyn.rt-dyn.2.9.1\build\native\cpprestsdk.v140.winapp.msvcstl.dyn.rt-dyn.targets'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\cpprestsdk.v140.windesktop.msvcstl.dyn.rt-dyn.2.9.1\build\native\cpprestsdk.v140.windesktop.msvcstl.dyn.rt-dyn.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\cpprestsdk.v140.windesktop.msvcstl.dyn.rt-dyn.2.9.1\build\native\cpprestsdk.v140.windesktop.msvcstl.dyn.rt-dyn.targets'))" />
|
||||
</Target>
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,174 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\stdafx.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\..\include\signalrclient\connection.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\..\include\signalrclient\_exports.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\..\include\signalrclient\transport_type.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\..\include\signalrclient\trace_level.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\url_builder.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\constants.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\http_sender.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\..\include\signalrclient\web_exception.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\negotiation_response.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\request_sender.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\websocket_transport.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\connection_impl.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\..\include\signalrclient\connection_state.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\websocket_client.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\default_websocket_client.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\..\include\signalrclient\log_writer.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\logger.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\trace_log_writer.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\transport_factory.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\web_request_factory.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\transport.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\web_response.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\web_request.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\hub_connection_impl.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\callback_manager.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\..\include\signalrclient\hub_exception.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\..\include\signalrclient\hub_connection.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\case_insensitive_comparison_utils.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\event.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\..\include\signalrclient\signalr_exception.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\..\include\signalrclient\signalr_client_config.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\stdafx.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\url_builder.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\web_request.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\connection_impl.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\http_sender.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\connection.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\transport_factory.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\web_request_factory.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\default_websocket_client.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\websocket_transport.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\logger.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\transport.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\hub_connection_impl.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\callback_manager.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\hub_connection.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\trace_log_writer.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\signalr_client_config.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\request_sender.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
|
||||
|
||||
set (SOURCES
|
||||
callback_manager.cpp
|
||||
connection.cpp
|
||||
connection_impl.cpp
|
||||
default_websocket_client.cpp
|
||||
http_sender.cpp
|
||||
hub_connection.cpp
|
||||
hub_connection_impl.cpp
|
||||
hub_proxy.cpp
|
||||
internal_hub_proxy.cpp
|
||||
logger.cpp
|
||||
request_sender.cpp
|
||||
signalr_client_config.cpp
|
||||
stdafx.cpp
|
||||
trace_log_writer.cpp
|
||||
transport.cpp
|
||||
transport_factory.cpp
|
||||
url_builder.cpp
|
||||
web_request.cpp
|
||||
web_request_factory.cpp
|
||||
websocket_transport.cpp
|
||||
)
|
||||
|
||||
add_library (signalrclient SHARED ${SOURCES})
|
||||
|
||||
target_link_libraries(signalrclient ${CPPREST_SO})
|
||||
|
|
@ -0,0 +1,91 @@
|
|||
// Copyright (c) .NET Foundation. 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 "callback_manager.h"
|
||||
|
||||
namespace signalr
|
||||
{
|
||||
// dtor_clear_arguments will be passed when closing any pending callbacks when the `callback_manager` is
|
||||
// destroyed (i.e. in the dtor)
|
||||
callback_manager::callback_manager(const web::json::value& dtor_clear_arguments)
|
||||
: m_dtor_clear_arguments(dtor_clear_arguments)
|
||||
{ }
|
||||
|
||||
callback_manager::~callback_manager()
|
||||
{
|
||||
clear(m_dtor_clear_arguments);
|
||||
}
|
||||
|
||||
// note: callback must not throw except for the `on_progress` callback which will never be invoked from the dtor
|
||||
utility::string_t callback_manager::register_callback(const std::function<void(const web::json::value&)>& callback)
|
||||
{
|
||||
auto callback_id = get_callback_id();
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_map_lock);
|
||||
|
||||
m_callbacks.insert(std::make_pair(callback_id, callback));
|
||||
}
|
||||
|
||||
return callback_id;
|
||||
}
|
||||
|
||||
|
||||
// invokes a callback and stops tracking it if remove callback set to true
|
||||
bool callback_manager::invoke_callback(const utility::string_t& callback_id, const web::json::value& arguments, bool remove_callback)
|
||||
{
|
||||
std::function<void(const web::json::value& arguments)> callback;
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_map_lock);
|
||||
|
||||
auto iter = m_callbacks.find(callback_id);
|
||||
if (iter == m_callbacks.end())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
callback = iter->second;
|
||||
|
||||
if (remove_callback)
|
||||
{
|
||||
m_callbacks.erase(callback_id);
|
||||
}
|
||||
}
|
||||
|
||||
callback(arguments);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool callback_manager::remove_callback(const utility::string_t& callback_id)
|
||||
{
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_map_lock);
|
||||
|
||||
return m_callbacks.erase(callback_id) != 0;
|
||||
}
|
||||
}
|
||||
|
||||
void callback_manager::clear(const web::json::value& arguments)
|
||||
{
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_map_lock);
|
||||
|
||||
for (auto& kvp : m_callbacks)
|
||||
{
|
||||
kvp.second(arguments);
|
||||
}
|
||||
|
||||
m_callbacks.clear();
|
||||
}
|
||||
}
|
||||
|
||||
utility::string_t callback_manager::get_callback_id()
|
||||
{
|
||||
auto callback_id = m_id++;
|
||||
utility::stringstream_t ss;
|
||||
ss << callback_id;
|
||||
return ss.str();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <unordered_map>
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
#include "cpprest/json.h"
|
||||
|
||||
namespace signalr
|
||||
{
|
||||
class callback_manager
|
||||
{
|
||||
public:
|
||||
explicit callback_manager(const web::json::value& dtor_error);
|
||||
~callback_manager();
|
||||
|
||||
callback_manager(const callback_manager&) = delete;
|
||||
callback_manager& operator=(const callback_manager&) = delete;
|
||||
|
||||
utility::string_t register_callback(const std::function<void(const web::json::value&)>& callback);
|
||||
bool invoke_callback(const utility::string_t& callback_id, const web::json::value& arguments, bool remove_callback);
|
||||
bool remove_callback(const utility::string_t& callback_id);
|
||||
void clear(const web::json::value& arguments);
|
||||
|
||||
private:
|
||||
std::atomic<int> m_id { 0 };
|
||||
std::unordered_map<utility::string_t, std::function<void(const web::json::value&)>> m_callbacks;
|
||||
std::mutex m_map_lock;
|
||||
const web::json::value m_dtor_clear_arguments;
|
||||
|
||||
utility::string_t get_callback_id();
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <cctype>
|
||||
#include "cpprest/details/basic_types.h"
|
||||
|
||||
namespace signalr
|
||||
{
|
||||
// Note: These functions are not pretending to be all-purpose helpers for case insensitive string comparison. Rather
|
||||
// we use them to compare hub and hub method names which are expected to be almost exclusively ASCII and this is the
|
||||
// simplest thing that would work without having to take dependencies on third party libraries.
|
||||
struct case_insensitive_equals : std::binary_function<utility::string_t, utility::string_t, bool>
|
||||
{
|
||||
bool operator()(const utility::string_t& s1, const utility::string_t& s2) const
|
||||
{
|
||||
if (s1.length() != s2.length())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (auto s1_iterator = s1.begin(), s2_iterator = s2.begin(); s1_iterator != s1.end(); ++s1_iterator, ++s2_iterator)
|
||||
{
|
||||
if (std::toupper(*s1_iterator) != std::toupper(*s2_iterator))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
struct case_insensitive_hash : std::unary_function<utility::string_t, std::size_t>
|
||||
{
|
||||
std::size_t operator()(const utility::string_t& s) const
|
||||
{
|
||||
size_t hash = 0;
|
||||
std::hash<size_t> hasher;
|
||||
for (const utility::char_t& c : s)
|
||||
{
|
||||
hash ^= hasher(std::toupper(c)) + (hash << 5) + (hash >> 2);
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
// Copyright (c) .NET Foundation. 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 "signalrclient/connection.h"
|
||||
#include "signalrclient/transport_type.h"
|
||||
#include "connection_impl.h"
|
||||
|
||||
namespace signalr
|
||||
{
|
||||
connection::connection(const utility::string_t& url, const utility::string_t& query_string, trace_level trace_level, std::shared_ptr<log_writer> log_writer)
|
||||
: m_pImpl(connection_impl::create(url, query_string, trace_level, std::move(log_writer)))
|
||||
{}
|
||||
|
||||
// Do NOT remove this destructor. Letting the compiler generate and inline the default dtor may lead to
|
||||
// undefinded behavior since we are using an incomplete type. More details here: http://herbsutter.com/gotw/_100/
|
||||
connection::~connection() = default;
|
||||
|
||||
pplx::task<void> connection::start()
|
||||
{
|
||||
return m_pImpl->start();
|
||||
}
|
||||
|
||||
pplx::task<void> connection::send(const utility::string_t& data)
|
||||
{
|
||||
return m_pImpl->send(data);
|
||||
}
|
||||
|
||||
void connection::set_message_received(const message_received_handler& message_received_callback)
|
||||
{
|
||||
m_pImpl->set_message_received_string(message_received_callback);
|
||||
}
|
||||
|
||||
void connection::set_reconnecting(const std::function<void()>& reconnecting_callback)
|
||||
{
|
||||
m_pImpl->set_reconnecting(reconnecting_callback);
|
||||
}
|
||||
|
||||
void connection::set_reconnected(const std::function<void()>& reconnected_callback)
|
||||
{
|
||||
m_pImpl->set_reconnected(reconnected_callback);
|
||||
}
|
||||
|
||||
void connection::set_disconnected(const std::function<void()>& disconnected_callback)
|
||||
{
|
||||
m_pImpl->set_disconnected(disconnected_callback);
|
||||
}
|
||||
|
||||
void connection::set_client_config(const signalr_client_config& config)
|
||||
{
|
||||
m_pImpl->set_client_config(config);
|
||||
}
|
||||
|
||||
pplx::task<void> connection::stop()
|
||||
{
|
||||
return m_pImpl->stop();
|
||||
}
|
||||
|
||||
connection_state connection::get_connection_state() const
|
||||
{
|
||||
return m_pImpl->get_connection_state();
|
||||
}
|
||||
|
||||
utility::string_t connection::get_connection_id() const
|
||||
{
|
||||
return m_pImpl->get_connection_id();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,874 @@
|
|||
// Copyright (c) .NET Foundation. 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 <thread>
|
||||
#include <algorithm>
|
||||
#include "cpprest/asyncrt_utils.h"
|
||||
#include "constants.h"
|
||||
#include "connection_impl.h"
|
||||
#include "request_sender.h"
|
||||
#include "url_builder.h"
|
||||
#include "trace_log_writer.h"
|
||||
#include "make_unique.h"
|
||||
#include "signalrclient/signalr_exception.h"
|
||||
|
||||
namespace signalr
|
||||
{
|
||||
// unnamed namespace makes it invisble outside this translation unit
|
||||
namespace
|
||||
{
|
||||
// this is a workaround for a compiler bug where mutable lambdas won't sometimes compile
|
||||
static void log(const logger& logger, trace_level level, const utility::string_t& entry);
|
||||
}
|
||||
|
||||
std::shared_ptr<connection_impl> connection_impl::create(const utility::string_t& url, const utility::string_t& query_string,
|
||||
trace_level trace_level, const std::shared_ptr<log_writer>& log_writer)
|
||||
{
|
||||
return connection_impl::create(url, query_string, trace_level, log_writer, std::make_unique<web_request_factory>(), std::make_unique<transport_factory>());
|
||||
}
|
||||
|
||||
std::shared_ptr<connection_impl> connection_impl::create(const utility::string_t& url, const utility::string_t& query_string, trace_level trace_level,
|
||||
const std::shared_ptr<log_writer>& log_writer, std::unique_ptr<web_request_factory> web_request_factory, std::unique_ptr<transport_factory> transport_factory)
|
||||
{
|
||||
return std::shared_ptr<connection_impl>(new connection_impl(url, query_string, trace_level,
|
||||
log_writer ? log_writer : std::make_shared<trace_log_writer>(), std::move(web_request_factory), std::move(transport_factory)));
|
||||
}
|
||||
|
||||
connection_impl::connection_impl(const utility::string_t& url, const utility::string_t& query_string, trace_level trace_level, const std::shared_ptr<log_writer>& log_writer,
|
||||
std::unique_ptr<web_request_factory> web_request_factory, std::unique_ptr<transport_factory> transport_factory)
|
||||
: m_base_url(url), m_query_string(query_string), m_connection_state(connection_state::disconnected), m_reconnect_delay(2000),
|
||||
m_logger(log_writer, trace_level), m_transport(nullptr), m_web_request_factory(std::move(web_request_factory)),
|
||||
m_transport_factory(std::move(transport_factory)), m_message_received([](const web::json::value&){}),
|
||||
m_reconnecting([](){}), m_reconnected([](){}), m_disconnected([](){}), m_handshakeReceived(false)
|
||||
{ }
|
||||
|
||||
connection_impl::~connection_impl()
|
||||
{
|
||||
try
|
||||
{
|
||||
// Signaling the event is safe here. We are in the dtor so noone is using this instance. There might be some
|
||||
// outstanding threads that hold on to the connection via a weak pointer but they won't be able to acquire
|
||||
// the instance since it is being destroyed. Note that the event may actually be in non-signaled state here.
|
||||
// This for instance happens when the connection goes out of scope while a reconnect is in progress. In this
|
||||
// case the reconnect logic will not be able to acquire the connection instance from the weak_pointer to
|
||||
// signal the event so this dtor would hang indefinitely. Using a shared_ptr to the connection in reconnect
|
||||
// is not a good idea since it would prevent from invoking this dtor until the connection is reconnected or
|
||||
// reconnection fails even if the instance actually went out of scope.
|
||||
m_start_completed_event.set();
|
||||
shutdown().get();
|
||||
}
|
||||
catch (const pplx::task_canceled&)
|
||||
{
|
||||
// because we are in the dtor and the `connection_imp` is ref counted we should not get the `task_canceled`
|
||||
// exception because it would indicate that some other thread/task still holds reference to this instance
|
||||
// so how come we are in the dtor?
|
||||
_ASSERTE(false);
|
||||
return;
|
||||
}
|
||||
catch (...) // must not throw from destructors
|
||||
{ }
|
||||
|
||||
m_transport = nullptr;
|
||||
change_state(connection_state::disconnected);
|
||||
}
|
||||
|
||||
pplx::task<void> connection_impl::start()
|
||||
{
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_stop_lock);
|
||||
if (!change_state(connection_state::disconnected, connection_state::connecting))
|
||||
{
|
||||
return pplx::task_from_exception<void>(
|
||||
signalr_exception(_XPLATSTR("cannot start a connection that is not in the disconnected state")));
|
||||
}
|
||||
|
||||
// there should not be any active transport at this point
|
||||
_ASSERTE(!m_transport);
|
||||
|
||||
m_disconnect_cts = pplx::cancellation_token_source();
|
||||
m_start_completed_event.reset();
|
||||
m_message_id = m_groups_token = m_connection_id = _XPLATSTR("");
|
||||
}
|
||||
|
||||
pplx::task_completion_event<void> start_tce;
|
||||
|
||||
auto connection = shared_from_this();
|
||||
|
||||
pplx::task_from_result()
|
||||
.then([connection]()
|
||||
{
|
||||
return request_sender::negotiate(*connection->m_web_request_factory, connection->m_base_url,
|
||||
connection->m_query_string, connection->m_signalr_client_config);
|
||||
}, m_disconnect_cts.get_token())
|
||||
.then([connection](negotiation_response negotiation_response)
|
||||
{
|
||||
connection->m_connection_id = negotiation_response.connection_id;
|
||||
|
||||
// TODO: check available transports
|
||||
|
||||
return connection->start_transport(negotiation_response)
|
||||
.then([connection, negotiation_response](std::shared_ptr<transport> transport)
|
||||
{
|
||||
connection->m_transport = transport;
|
||||
});
|
||||
}, m_disconnect_cts.get_token())
|
||||
.then([start_tce, connection](pplx::task<void> previous_task)
|
||||
{
|
||||
try
|
||||
{
|
||||
previous_task.get();
|
||||
if (!connection->change_state(connection_state::connecting, connection_state::connected))
|
||||
{
|
||||
connection->m_logger.log(trace_level::errors,
|
||||
utility::string_t(_XPLATSTR("internal error - transition from an unexpected state. expected state: connecting, actual state: "))
|
||||
.append(translate_connection_state(connection->get_connection_state())));
|
||||
|
||||
_ASSERTE(false);
|
||||
}
|
||||
|
||||
connection->m_start_completed_event.set();
|
||||
start_tce.set();
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
auto task_canceled_exception = dynamic_cast<const pplx::task_canceled *>(&e);
|
||||
if (task_canceled_exception)
|
||||
{
|
||||
connection->m_logger.log(trace_level::info,
|
||||
_XPLATSTR("starting the connection has been cancelled."));
|
||||
}
|
||||
else
|
||||
{
|
||||
connection->m_logger.log(trace_level::errors,
|
||||
utility::string_t(_XPLATSTR("connection could not be started due to: "))
|
||||
.append(utility::conversions::to_string_t(e.what())));
|
||||
}
|
||||
|
||||
connection->m_transport = nullptr;
|
||||
connection->change_state(connection_state::disconnected);
|
||||
connection->m_start_completed_event.set();
|
||||
start_tce.set_exception(std::current_exception());
|
||||
}
|
||||
});
|
||||
|
||||
return pplx::create_task(start_tce);
|
||||
}
|
||||
|
||||
pplx::task<std::shared_ptr<transport>> connection_impl::start_transport(negotiation_response negotiation_response)
|
||||
{
|
||||
auto connection = shared_from_this();
|
||||
|
||||
pplx::task_completion_event<void> connect_request_tce;
|
||||
|
||||
auto weak_connection = std::weak_ptr<connection_impl>(connection);
|
||||
auto& disconnect_cts = m_disconnect_cts;
|
||||
auto& logger = m_logger;
|
||||
|
||||
auto process_response_callback =
|
||||
[weak_connection, connect_request_tce, disconnect_cts, logger](const utility::string_t& response) mutable
|
||||
{
|
||||
// When a connection is stopped we don't wait for its transport to stop. As a result if the same connection
|
||||
// is immediately re-started the old transport can still invoke this callback. To prevent this we capture
|
||||
// the disconnect_cts by value which allows distinguishing if the message is for the running connection
|
||||
// or for the one that was already stopped. If this is the latter we just ignore it.
|
||||
if (disconnect_cts.get_token().is_canceled())
|
||||
{
|
||||
logger.log(trace_level::info,
|
||||
utility::string_t(_XPLATSTR("ignoring stray message received after connection was restarted. message: "))
|
||||
.append(response));
|
||||
return;
|
||||
}
|
||||
|
||||
auto connection = weak_connection.lock();
|
||||
if (connection)
|
||||
{
|
||||
connection->process_response(response, connect_request_tce);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
auto error_callback =
|
||||
[weak_connection, connect_request_tce, disconnect_cts, logger](const std::exception &e) mutable
|
||||
{
|
||||
// When a connection is stopped we don't wait for its transport to stop. As a result if the same connection
|
||||
// is immediately re-started the old transport can still invoke this callback. To prevent this we capture
|
||||
// the disconnect_cts by value which allows distinguishing if the error is for the running connection
|
||||
// or for the one that was already stopped. If this is the latter we just ignore it.
|
||||
if (disconnect_cts.get_token().is_canceled())
|
||||
{
|
||||
logger.log(trace_level::info,
|
||||
utility::string_t(_XPLATSTR("ignoring stray error received after connection was restarted. error: "))
|
||||
.append(utility::conversions::to_string_t(e.what())));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// no op after connection started successfully
|
||||
connect_request_tce.set_exception(e);
|
||||
|
||||
auto connection = weak_connection.lock();
|
||||
if (connection)
|
||||
{
|
||||
connection->reconnect();
|
||||
}
|
||||
};
|
||||
|
||||
auto transport = connection->m_transport_factory->create_transport(
|
||||
transport_type::websockets, connection->m_logger, connection->m_signalr_client_config,
|
||||
process_response_callback, error_callback);
|
||||
|
||||
pplx::create_task([negotiation_response, connect_request_tce, disconnect_cts, weak_connection]()
|
||||
{
|
||||
//std::this_thread::sleep_for(std::chrono::milliseconds(negotiation_response.transport_connect_timeout));
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(5000));
|
||||
|
||||
// if the disconnect_cts is canceled it means that the connection has been stopped or went out of scope in
|
||||
// which case we should not throw due to timeout. Instead we need to set the tce prevent the task that is
|
||||
// using this tce from hanging indifinitely. (This will eventually result in throwing the pplx::task_canceled
|
||||
// exception to the user since this is what we do in the start() function if disconnect_cts is tripped).
|
||||
if (disconnect_cts.get_token().is_canceled())
|
||||
{
|
||||
connect_request_tce.set();
|
||||
}
|
||||
else
|
||||
{
|
||||
connect_request_tce.set_exception(signalr_exception(_XPLATSTR("transport timed out when trying to connect")));
|
||||
}
|
||||
});
|
||||
|
||||
return connection->send_connect_request(transport, connect_request_tce)
|
||||
.then([transport](){ return pplx::task_from_result(transport); });
|
||||
}
|
||||
|
||||
pplx::task<void> connection_impl::send_connect_request(const std::shared_ptr<transport>& transport, const pplx::task_completion_event<void>& connect_request_tce)
|
||||
{
|
||||
auto logger = m_logger;
|
||||
auto connect_url = url_builder::build_connect(m_base_url, transport->get_transport_type(), m_query_string);
|
||||
|
||||
transport->connect(connect_url)
|
||||
.then([transport, connect_request_tce, logger](pplx::task<void> connect_task)
|
||||
mutable {
|
||||
try
|
||||
{
|
||||
connect_task.get();
|
||||
transport->send(_XPLATSTR("{\"protocol\":\"json\",\"version\":1}\x1e")).get();
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
logger.log(
|
||||
trace_level::errors,
|
||||
utility::string_t(_XPLATSTR("transport could not connect due to: "))
|
||||
.append(utility::conversions::to_string_t(e.what())));
|
||||
|
||||
connect_request_tce.set_exception(std::current_exception());
|
||||
}
|
||||
});
|
||||
|
||||
return pplx::create_task(connect_request_tce);
|
||||
}
|
||||
|
||||
enum MessageType
|
||||
{
|
||||
Invocation = 1,
|
||||
StreamItem,
|
||||
Completion,
|
||||
StreamInvocation,
|
||||
CancelInvocation,
|
||||
Ping,
|
||||
Close,
|
||||
};
|
||||
|
||||
void connection_impl::process_response(const utility::string_t& response, const pplx::task_completion_event<void>& connect_request_tce)
|
||||
{
|
||||
m_logger.log(trace_level::messages,
|
||||
utility::string_t(_XPLATSTR("processing message: ")).append(response));
|
||||
|
||||
try
|
||||
{
|
||||
auto pos = response.find('\x1e');
|
||||
std::size_t lastPos = 0;
|
||||
while (pos != utility::string_t::npos)
|
||||
{
|
||||
auto message = response.substr(lastPos, pos - lastPos);
|
||||
const auto result = web::json::value::parse(message);
|
||||
|
||||
if (!result.is_object())
|
||||
{
|
||||
m_logger.log(trace_level::info, utility::string_t(_XPLATSTR("unexpected response received from the server: "))
|
||||
.append(message));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_handshakeReceived)
|
||||
{
|
||||
if (result.has_field(_XPLATSTR("error")))
|
||||
{
|
||||
auto error = result.at(_XPLATSTR("error")).as_string();
|
||||
m_logger.log(trace_level::errors, utility::string_t(_XPLATSTR("handshake error: "))
|
||||
.append(error));
|
||||
connect_request_tce.set_exception(signalr_exception(utility::string_t(_XPLATSTR("Received an error during handshake: ")).append(error)));
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (result.size() != 0)
|
||||
{
|
||||
connect_request_tce.set_exception(signalr_exception(utility::string_t(_XPLATSTR("Received unexpected message while waiting for the handshake response."))));
|
||||
}
|
||||
m_handshakeReceived = true;
|
||||
connect_request_tce.set();
|
||||
}
|
||||
}
|
||||
|
||||
auto messageType = result.at(_XPLATSTR("type"));
|
||||
switch (messageType.as_integer())
|
||||
{
|
||||
case MessageType::Invocation:
|
||||
{
|
||||
invoke_message_received(result);
|
||||
break;
|
||||
}
|
||||
case MessageType::StreamInvocation:
|
||||
// Sent to server only, should not be received by client
|
||||
throw std::runtime_error("Received unexpected message type 'StreamInvocation'.");
|
||||
case MessageType::StreamItem:
|
||||
// TODO
|
||||
break;
|
||||
case MessageType::Completion:
|
||||
{
|
||||
if (result.has_field(_XPLATSTR("error")) && result.has_field(_XPLATSTR("result")))
|
||||
{
|
||||
//error
|
||||
}
|
||||
invoke_message_received(result);
|
||||
break;
|
||||
}
|
||||
case MessageType::CancelInvocation:
|
||||
// Sent to server only, should not be received by client
|
||||
throw std::runtime_error("Received unexpected message type 'CancelInvocation'.");
|
||||
case MessageType::Ping:
|
||||
// TODO
|
||||
break;
|
||||
case MessageType::Close:
|
||||
// TODO
|
||||
break;
|
||||
}
|
||||
|
||||
lastPos = pos + 1;
|
||||
pos = response.find('\x1e', lastPos);
|
||||
}
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
m_logger.log(trace_level::errors, utility::string_t(_XPLATSTR("error occured when parsing response: "))
|
||||
.append(utility::conversions::to_string_t(e.what()))
|
||||
.append(_XPLATSTR(". response: "))
|
||||
.append(response));
|
||||
}
|
||||
}
|
||||
|
||||
void connection_impl::invoke_message_received(const web::json::value& message)
|
||||
{
|
||||
try
|
||||
{
|
||||
m_message_received(message);
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
m_logger.log(
|
||||
trace_level::errors,
|
||||
utility::string_t(_XPLATSTR("message_received callback threw an exception: "))
|
||||
.append(utility::conversions::to_string_t(e.what())));
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
m_logger.log(trace_level::errors, _XPLATSTR("message_received callback threw an unknown exception"));
|
||||
}
|
||||
}
|
||||
|
||||
pplx::task<void> connection_impl::send(const utility::string_t& data)
|
||||
{
|
||||
// To prevent an (unlikely) condition where the transport is nulled out after we checked the connection_state
|
||||
// and before sending data we store the pointer in the local variable. In this case `send()` will throw but
|
||||
// we won't crash.
|
||||
auto transport = m_transport;
|
||||
|
||||
auto connection_state = get_connection_state();
|
||||
if (connection_state != signalr::connection_state::connected || !transport)
|
||||
{
|
||||
return pplx::task_from_exception<void>(signalr_exception(
|
||||
utility::string_t{_XPLATSTR("cannot send data when the connection is not in the connected state. current connection state: " })
|
||||
.append(translate_connection_state(connection_state))));
|
||||
}
|
||||
|
||||
auto logger = m_logger;
|
||||
|
||||
logger.log(trace_level::info, utility::string_t(_XPLATSTR("sending data: ")).append(data));
|
||||
|
||||
return transport->send(data)
|
||||
.then([logger](pplx::task<void> send_task)
|
||||
mutable {
|
||||
try
|
||||
{
|
||||
send_task.get();
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
logger.log(
|
||||
trace_level::errors,
|
||||
utility::string_t(_XPLATSTR("error sending data: "))
|
||||
.append(utility::conversions::to_string_t(e.what())));
|
||||
|
||||
throw;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
pplx::task<void> connection_impl::stop()
|
||||
{
|
||||
m_logger.log(trace_level::info, _XPLATSTR("stopping connection"));
|
||||
|
||||
auto connection = shared_from_this();
|
||||
return shutdown()
|
||||
.then([connection]()
|
||||
{
|
||||
{
|
||||
// the lock prevents a race where the user calls `stop` on a disconnected connection and calls `start`
|
||||
// on a different thread at the same time. In this case we must not null out the transport if we are
|
||||
// not in the `disconnecting` state to not affect the 'start' invocation.
|
||||
std::lock_guard<std::mutex> lock(connection->m_stop_lock);
|
||||
if (connection->change_state(connection_state::disconnecting, connection_state::disconnected))
|
||||
{
|
||||
// we do let the exception through (especially the task_canceled exception)
|
||||
connection->m_transport = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
connection->m_disconnected();
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
connection->m_logger.log(
|
||||
trace_level::errors,
|
||||
utility::string_t(_XPLATSTR("disconnected callback threw an exception: "))
|
||||
.append(utility::conversions::to_string_t(e.what())));
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
connection->m_logger.log(
|
||||
trace_level::errors,
|
||||
utility::string_t(_XPLATSTR("disconnected callback threw an unknown exception")));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// This function is called from the dtor so you must not use `shared_from_this` here (it will throw).
|
||||
pplx::task<void> connection_impl::shutdown()
|
||||
{
|
||||
m_handshakeReceived = false;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_stop_lock);
|
||||
m_logger.log(trace_level::info, _XPLATSTR("acquired lock in shutdown()"));
|
||||
|
||||
auto current_state = get_connection_state();
|
||||
if (current_state == connection_state::disconnected)
|
||||
{
|
||||
return pplx::task_from_result();
|
||||
}
|
||||
|
||||
if (current_state == connection_state::disconnecting)
|
||||
{
|
||||
// canceled task will be returned if `stop` was called while another `stop` was already in progress.
|
||||
// This is to prevent from resetting the `m_transport` in the upstream callers because doing so might
|
||||
// affect the other invocation which is using it.
|
||||
auto cts = pplx::cancellation_token_source();
|
||||
cts.cancel();
|
||||
return pplx::create_task([](){}, cts.get_token());
|
||||
}
|
||||
|
||||
// we request a cancellation of the ongoing start or reconnect request (if any) and wait until it is cancelled
|
||||
m_disconnect_cts.cancel();
|
||||
|
||||
while (m_start_completed_event.wait(60000) != 0)
|
||||
{
|
||||
m_logger.log(trace_level::errors,
|
||||
_XPLATSTR("internal error - stopping the connection is still waiting for the start operation to finish which should have already finished or timed out"));
|
||||
}
|
||||
|
||||
// at this point we are either in the connected, reconnecting or disconnected state. If we are in the disconnected state
|
||||
// we must break because the transport has already been nulled out.
|
||||
if (m_connection_state == connection_state::disconnected)
|
||||
{
|
||||
return pplx::task_from_result();
|
||||
}
|
||||
|
||||
_ASSERTE(m_connection_state == connection_state::connected || m_connection_state == connection_state::reconnecting);
|
||||
|
||||
change_state(connection_state::disconnecting);
|
||||
}
|
||||
|
||||
return m_transport->disconnect();
|
||||
}
|
||||
|
||||
void connection_impl::reconnect()
|
||||
{
|
||||
m_logger.log(trace_level::info, _XPLATSTR("connection lost - trying to re-establish connection"));
|
||||
|
||||
pplx::cancellation_token_source disconnect_cts;
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_stop_lock);
|
||||
m_logger.log(trace_level::info, _XPLATSTR("acquired lock before invoking reconnecting callback"));
|
||||
|
||||
// reconnect might be called when starting the connection has not finished yet so wait until it is done
|
||||
// before actually trying to reconnect
|
||||
while (m_start_completed_event.wait(60000) != 0)
|
||||
{
|
||||
m_logger.log(trace_level::errors,
|
||||
_XPLATSTR("internal error - reconnect is still waiting for the start operation to finish which should have already finished or timed out"));
|
||||
}
|
||||
|
||||
// exit if starting the connection has not completed successfully or there is an ongoing stop request
|
||||
if (!change_state(connection_state::connected, connection_state::reconnecting))
|
||||
{
|
||||
m_logger.log(trace_level::info,
|
||||
_XPLATSTR("reconnecting cancelled - connection is not in the connected state"));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
disconnect_cts = m_disconnect_cts;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
m_logger.log(trace_level::info, _XPLATSTR("invoking reconnecting callback"));
|
||||
m_reconnecting();
|
||||
m_logger.log(trace_level::info, _XPLATSTR("reconnecting callback returned without error"));
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
m_logger.log(
|
||||
trace_level::errors,
|
||||
utility::string_t(_XPLATSTR("reconnecting callback threw an exception: "))
|
||||
.append(utility::conversions::to_string_t(e.what())));
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
m_logger.log(
|
||||
trace_level::errors,
|
||||
utility::string_t(_XPLATSTR("reconnecting callback threw an unknown exception")));
|
||||
}
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_stop_lock);
|
||||
|
||||
m_logger.log(trace_level::info, _XPLATSTR("acquired lock before starting reconnect logic"));
|
||||
|
||||
// This is to prevent a case where a connection was stopped (and possibly restarted and got into a reconnecting
|
||||
// state) after we changed the state to reconnecting in the original reconnecting request. In this case we have
|
||||
// the original cts which would have been cancelled by the stop request and we can use it to stop the original
|
||||
// reconnecting request
|
||||
if (disconnect_cts.get_token().is_canceled())
|
||||
{
|
||||
m_logger.log(trace_level::info,
|
||||
_XPLATSTR("reconnecting canceled - connection was stopped and restarted after reconnecting started"));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// we set the connection to the reconnecting before we invoked the reconnecting callback. If the connection
|
||||
// state changed from the reconnecting state the user might have stopped/restarted the connection in the
|
||||
// reconnecting callback or there might have started stopping the connection on the main thread and we should
|
||||
// not try to continue the reconnect
|
||||
if (m_connection_state != connection_state::reconnecting)
|
||||
{
|
||||
m_logger.log(trace_level::info,
|
||||
_XPLATSTR("reconnecting canceled - connection is no longer in the reconnecting state"));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// re-using the start completed event is safe because you cannot start the connection if it is not in the
|
||||
// disconnected state. It also make it easier to handle stopping the connection when it is reconnecting.
|
||||
m_start_completed_event.reset();
|
||||
}
|
||||
|
||||
auto reconnect_url = url_builder::build_reconnect(m_base_url, m_transport->get_transport_type(),
|
||||
m_message_id, m_groups_token, m_query_string);
|
||||
|
||||
auto weak_connection = std::weak_ptr<connection_impl>(shared_from_this());
|
||||
|
||||
// this is non-blocking
|
||||
try_reconnect(reconnect_url, utility::datetime::utc_now().to_interval(), m_reconnect_window, m_reconnect_delay, disconnect_cts)
|
||||
.then([weak_connection](pplx::task<bool> reconnect_task)
|
||||
{
|
||||
// try reconnect does not throw
|
||||
auto reconnected = reconnect_task.get();
|
||||
|
||||
auto connection = weak_connection.lock();
|
||||
if (!connection)
|
||||
{
|
||||
// connection instance went away - nothing to be done
|
||||
return pplx::task_from_result();
|
||||
}
|
||||
|
||||
if (reconnected)
|
||||
{
|
||||
if (!connection->change_state(connection_state::reconnecting, connection_state::connected))
|
||||
{
|
||||
connection->m_logger.log(trace_level::errors,
|
||||
utility::string_t(_XPLATSTR("internal error - transition from an unexpected state. expected state: reconnecting, actual state: "))
|
||||
.append(translate_connection_state(connection->get_connection_state())));
|
||||
|
||||
_ASSERTE(false);
|
||||
}
|
||||
|
||||
// we must set the event before calling into the user code to prevent a deadlock that would happen
|
||||
// if the user called stop() from the handler
|
||||
connection->m_start_completed_event.set();
|
||||
|
||||
try
|
||||
{
|
||||
connection->m_logger.log(trace_level::info, _XPLATSTR("invoking reconnected callback"));
|
||||
connection->m_reconnected();
|
||||
connection->m_logger.log(trace_level::info, _XPLATSTR("reconnected callback returned without error"));
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
connection->m_logger.log(
|
||||
trace_level::errors,
|
||||
utility::string_t(_XPLATSTR("reconnected callback threw an exception: "))
|
||||
.append(utility::conversions::to_string_t(e.what())));
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
connection->m_logger.log(
|
||||
trace_level::errors, _XPLATSTR("reconnected callback threw an unknown exception"));
|
||||
}
|
||||
|
||||
return pplx::task_from_result();
|
||||
}
|
||||
|
||||
connection->m_start_completed_event.set();
|
||||
|
||||
return connection->stop();
|
||||
});
|
||||
}
|
||||
|
||||
// the assumption is that this function won't throw
|
||||
pplx::task<bool> connection_impl::try_reconnect(const web::uri& reconnect_url, const utility::datetime::interval_type reconnect_start_time,
|
||||
int reconnect_window /*milliseconds*/, int reconnect_delay /*milliseconds*/, pplx::cancellation_token_source disconnect_cts)
|
||||
{
|
||||
if (disconnect_cts.get_token().is_canceled())
|
||||
{
|
||||
log(m_logger, trace_level::info, utility::string_t(_XPLATSTR("reconnecting cancelled - connection is being stopped. line: "))
|
||||
.append(utility::conversions::to_string_t(std::to_string(__LINE__))));
|
||||
return pplx::task_from_result<bool>(false);
|
||||
}
|
||||
|
||||
auto weak_connection = std::weak_ptr<connection_impl>(shared_from_this());
|
||||
auto& logger = m_logger;
|
||||
|
||||
return m_transport->connect(reconnect_url)
|
||||
.then([weak_connection, reconnect_url, reconnect_start_time, reconnect_window, reconnect_delay, logger, disconnect_cts]
|
||||
(pplx::task<void> reconnect_task)
|
||||
{
|
||||
try
|
||||
{
|
||||
log(logger, trace_level::info, _XPLATSTR("reconnect attempt starting"));
|
||||
reconnect_task.get();
|
||||
log(logger, trace_level::info, _XPLATSTR("reconnect attempt completed successfully"));
|
||||
|
||||
return pplx::task_from_result<bool>(true);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
log(logger, trace_level::info, utility::string_t(_XPLATSTR("reconnect attempt failed due to: "))
|
||||
.append(utility::conversions::to_string_t(e.what())));
|
||||
}
|
||||
|
||||
if (disconnect_cts.get_token().is_canceled())
|
||||
{
|
||||
log(logger, trace_level::info, utility::string_t(_XPLATSTR("reconnecting cancelled - connection is being stopped. line: "))
|
||||
.append(utility::conversions::to_string_t(std::to_string(__LINE__))));
|
||||
return pplx::task_from_result<bool>(false);
|
||||
}
|
||||
|
||||
auto reconnect_window_end = reconnect_start_time + utility::datetime::from_milliseconds(reconnect_window);
|
||||
if (utility::datetime::utc_now().to_interval() + utility::datetime::from_milliseconds(reconnect_delay) > reconnect_window_end)
|
||||
{
|
||||
utility::ostringstream_t oss;
|
||||
oss << _XPLATSTR("connection could not be re-established within the configured timeout of ")
|
||||
<< reconnect_window << _XPLATSTR(" milliseconds");
|
||||
log(logger, trace_level::info, oss.str());
|
||||
|
||||
return pplx::task_from_result<bool>(false);
|
||||
}
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(reconnect_delay));
|
||||
|
||||
if (disconnect_cts.get_token().is_canceled())
|
||||
{
|
||||
log(logger, trace_level::info, utility::string_t(_XPLATSTR("reconnecting cancelled - connection is being stopped. line: "))
|
||||
.append(utility::conversions::to_string_t(std::to_string(__LINE__))));
|
||||
|
||||
return pplx::task_from_result<bool>(false);
|
||||
}
|
||||
|
||||
auto connection = weak_connection.lock();
|
||||
if (connection)
|
||||
{
|
||||
return connection->try_reconnect(reconnect_url, reconnect_start_time, reconnect_window, reconnect_delay, disconnect_cts);
|
||||
}
|
||||
|
||||
log(logger, trace_level::info, _XPLATSTR("reconnecting cancelled - connection no longer valid."));
|
||||
return pplx::task_from_result<bool>(false);
|
||||
});
|
||||
}
|
||||
|
||||
connection_state connection_impl::get_connection_state() const
|
||||
{
|
||||
return m_connection_state.load();
|
||||
}
|
||||
|
||||
utility::string_t connection_impl::get_connection_id() const
|
||||
{
|
||||
if (m_connection_state.load() == connection_state::connecting)
|
||||
{
|
||||
return _XPLATSTR("");
|
||||
}
|
||||
|
||||
return m_connection_id;
|
||||
}
|
||||
|
||||
void connection_impl::set_message_received_string(const std::function<void(const utility::string_t&)>& message_received)
|
||||
{
|
||||
set_message_received_json([message_received](const web::json::value& payload)
|
||||
{
|
||||
message_received(payload.is_string() ? payload.as_string() : payload.serialize());
|
||||
});
|
||||
}
|
||||
|
||||
void connection_impl::set_message_received_json(const std::function<void(const web::json::value&)>& message_received)
|
||||
{
|
||||
ensure_disconnected(_XPLATSTR("cannot set the callback when the connection is not in the disconnected state. "));
|
||||
m_message_received = message_received;
|
||||
}
|
||||
|
||||
void connection_impl::set_connection_data(const utility::string_t& connection_data)
|
||||
{
|
||||
_ASSERTE(get_connection_state() == connection_state::disconnected);
|
||||
|
||||
m_connection_data = connection_data;
|
||||
}
|
||||
|
||||
void connection_impl::set_client_config(const signalr_client_config& config)
|
||||
{
|
||||
ensure_disconnected(_XPLATSTR("cannot set client config when the connection is not in the disconnected state. "));
|
||||
m_signalr_client_config = config;
|
||||
}
|
||||
|
||||
void connection_impl::set_reconnecting(const std::function<void()>& reconnecting)
|
||||
{
|
||||
ensure_disconnected(_XPLATSTR("cannot set the reconnecting callback when the connection is not in the disconnected state. "));
|
||||
m_reconnecting = reconnecting;
|
||||
}
|
||||
|
||||
void connection_impl::set_reconnected(const std::function<void()>& reconnected)
|
||||
{
|
||||
ensure_disconnected(_XPLATSTR("cannot set the reconnected callback when the connection is not in the disconnected state. "));
|
||||
m_reconnected = reconnected;
|
||||
}
|
||||
|
||||
void connection_impl::set_disconnected(const std::function<void()>& disconnected)
|
||||
{
|
||||
ensure_disconnected(_XPLATSTR("cannot set the disconnected callback when the connection is not in the disconnected state. "));
|
||||
m_disconnected = disconnected;
|
||||
}
|
||||
|
||||
void connection_impl::set_reconnect_delay(const int reconnect_delay)
|
||||
{
|
||||
ensure_disconnected(_XPLATSTR("cannot set reconnect delay when the connection is not in the disconnected state. "));
|
||||
m_reconnect_delay = reconnect_delay;
|
||||
}
|
||||
|
||||
void connection_impl::ensure_disconnected(const utility::string_t& error_message)
|
||||
{
|
||||
auto state = get_connection_state();
|
||||
if (state != connection_state::disconnected)
|
||||
{
|
||||
throw signalr_exception(
|
||||
error_message + _XPLATSTR("current connection state: ") + translate_connection_state(state));
|
||||
}
|
||||
}
|
||||
|
||||
bool connection_impl::change_state(connection_state old_state, connection_state new_state)
|
||||
{
|
||||
if (m_connection_state.compare_exchange_strong(old_state, new_state, std::memory_order_seq_cst))
|
||||
{
|
||||
handle_connection_state_change(old_state, new_state);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
connection_state connection_impl::change_state(connection_state new_state)
|
||||
{
|
||||
auto old_state = m_connection_state.exchange(new_state);
|
||||
if (old_state != new_state)
|
||||
{
|
||||
handle_connection_state_change(old_state, new_state);
|
||||
}
|
||||
|
||||
return old_state;
|
||||
}
|
||||
|
||||
void connection_impl::handle_connection_state_change(connection_state old_state, connection_state new_state)
|
||||
{
|
||||
m_logger.log(
|
||||
trace_level::state_changes,
|
||||
translate_connection_state(old_state)
|
||||
.append(_XPLATSTR(" -> "))
|
||||
.append(translate_connection_state(new_state)));
|
||||
|
||||
// Words of wisdom (if we decide to add a state_changed callback and invoke it from here):
|
||||
// "Be extra careful when you add this callback, because this is sometimes being called with the m_stop_lock.
|
||||
// This could lead to interesting problems.For example, you could run into a segfault if the connection is
|
||||
// stopped while / after transitioning into the connecting state."
|
||||
}
|
||||
|
||||
utility::string_t connection_impl::translate_connection_state(connection_state state)
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case connection_state::connecting:
|
||||
return _XPLATSTR("connecting");
|
||||
case connection_state::connected:
|
||||
return _XPLATSTR("connected");
|
||||
case connection_state::reconnecting:
|
||||
return _XPLATSTR("reconnecting");
|
||||
case connection_state::disconnecting:
|
||||
return _XPLATSTR("disconnecting");
|
||||
case connection_state::disconnected:
|
||||
return _XPLATSTR("disconnected");
|
||||
default:
|
||||
_ASSERTE(false);
|
||||
return _XPLATSTR("(unknown)");
|
||||
}
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
// this is a workaround for the VS2013 compiler bug where mutable lambdas won't compile sometimes
|
||||
static void log(const logger& logger, trace_level level, const utility::string_t& entry)
|
||||
{
|
||||
const_cast<signalr::logger &>(logger).log(level, entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,105 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <mutex>
|
||||
#include "cpprest/http_client.h"
|
||||
#include "signalrclient/trace_level.h"
|
||||
#include "signalrclient/connection_state.h"
|
||||
#include "signalrclient/signalr_client_config.h"
|
||||
#include "web_request_factory.h"
|
||||
#include "transport_factory.h"
|
||||
#include "logger.h"
|
||||
#include "negotiation_response.h"
|
||||
#include "event.h"
|
||||
|
||||
namespace signalr
|
||||
{
|
||||
// Note:
|
||||
// Factory methods and private constructors prevent from using this class incorrectly. Because this class
|
||||
// derives from `std::enable_shared_from_this` the instance has to be owned by a `std::shared_ptr` whenever
|
||||
// a member method calls `std::shared_from_this()` otherwise the behavior is undefined. Therefore constructors
|
||||
// are private to disallow creating instances directly and factory methods return `std::shared_ptr<connection_impl>`.
|
||||
class connection_impl : public std::enable_shared_from_this<connection_impl>
|
||||
{
|
||||
public:
|
||||
static std::shared_ptr<connection_impl> create(const utility::string_t& url, const utility::string_t& query_string,
|
||||
trace_level trace_level, const std::shared_ptr<log_writer>& log_writer);
|
||||
|
||||
static std::shared_ptr<connection_impl> create(const utility::string_t& url, const utility::string_t& query_string, trace_level trace_level,
|
||||
const std::shared_ptr<log_writer>& log_writer, std::unique_ptr<web_request_factory> web_request_factory, std::unique_ptr<transport_factory> transport_factory);
|
||||
|
||||
connection_impl(const connection_impl&) = delete;
|
||||
|
||||
connection_impl& operator=(const connection_impl&) = delete;
|
||||
|
||||
~connection_impl();
|
||||
|
||||
pplx::task<void> start();
|
||||
pplx::task<void> send(const utility::string_t &data);
|
||||
pplx::task<void> stop();
|
||||
|
||||
connection_state get_connection_state() const;
|
||||
utility::string_t get_connection_id() const;
|
||||
|
||||
void set_message_received_string(const std::function<void(const utility::string_t&)>& message_received);
|
||||
void set_message_received_json(const std::function<void(const web::json::value&)>& message_received);
|
||||
void set_reconnecting(const std::function<void()>& reconnecting);
|
||||
void set_reconnected(const std::function<void()>& reconnected);
|
||||
void set_disconnected(const std::function<void()>& disconnected);
|
||||
void set_client_config(const signalr_client_config& config);
|
||||
void set_reconnect_delay(const int reconnect_delay /*milliseconds*/);
|
||||
|
||||
void set_connection_data(const utility::string_t& connection_data);
|
||||
|
||||
private:
|
||||
web::uri m_base_url;
|
||||
utility::string_t m_query_string;
|
||||
std::atomic<connection_state> m_connection_state;
|
||||
logger m_logger;
|
||||
std::shared_ptr<transport> m_transport;
|
||||
std::unique_ptr<web_request_factory> m_web_request_factory;
|
||||
std::unique_ptr<transport_factory> m_transport_factory;
|
||||
|
||||
std::function<void(const web::json::value&)> m_message_received;
|
||||
std::function<void()> m_reconnecting;
|
||||
std::function<void()> m_reconnected;
|
||||
std::function<void()> m_disconnected;
|
||||
signalr_client_config m_signalr_client_config;
|
||||
|
||||
pplx::cancellation_token_source m_disconnect_cts;
|
||||
std::mutex m_stop_lock;
|
||||
event m_start_completed_event;
|
||||
utility::string_t m_connection_id;
|
||||
utility::string_t m_connection_data;
|
||||
int m_reconnect_window; // in milliseconds
|
||||
int m_reconnect_delay; // in milliseconds
|
||||
utility::string_t m_message_id;
|
||||
utility::string_t m_groups_token;
|
||||
bool m_handshakeReceived;
|
||||
|
||||
connection_impl(const utility::string_t& url, const utility::string_t& query_string, trace_level trace_level, const std::shared_ptr<log_writer>& log_writer,
|
||||
std::unique_ptr<web_request_factory> web_request_factory, std::unique_ptr<transport_factory> transport_factory);
|
||||
|
||||
pplx::task<std::shared_ptr<transport>> start_transport(negotiation_response negotiation_response);
|
||||
pplx::task<void> send_connect_request(const std::shared_ptr<transport>& transport,
|
||||
const pplx::task_completion_event<void>& connect_request_tce);
|
||||
|
||||
void process_response(const utility::string_t& response, const pplx::task_completion_event<void>& connect_request_tce);
|
||||
|
||||
pplx::task<void> shutdown();
|
||||
void reconnect();
|
||||
pplx::task<bool> try_reconnect(const web::uri& reconnect_url, const utility::datetime::interval_type reconnect_start_time,
|
||||
int reconnect_window, int reconnect_delay, pplx::cancellation_token_source disconnect_cts);
|
||||
|
||||
bool change_state(connection_state old_state, connection_state new_state);
|
||||
connection_state change_state(connection_state new_state);
|
||||
void handle_connection_state_change(connection_state old_state, connection_state new_state);
|
||||
void invoke_message_received(const web::json::value& message);
|
||||
|
||||
static utility::string_t translate_connection_state(connection_state state);
|
||||
void ensure_disconnected(const utility::string_t& error_message);
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cpprest/details/basic_types.h"
|
||||
|
||||
#define SIGNALR_VERSION _XPLATSTR("0.1.0-alpha0")
|
||||
#define PROTOCOL _XPLATSTR("1.4")
|
||||
#define USER_AGENT _XPLATSTR("SignalR.Client.Cpp/") SIGNALR_VERSION
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
// Copyright (c) .NET Foundation. 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 "default_websocket_client.h"
|
||||
|
||||
namespace signalr
|
||||
{
|
||||
namespace
|
||||
{
|
||||
static web::websockets::client::websocket_client_config create_client_config(const signalr_client_config& signalr_client_config)
|
||||
{
|
||||
auto websocket_client_config = signalr_client_config.get_websocket_client_config();
|
||||
websocket_client_config.headers() = signalr_client_config.get_http_headers();
|
||||
|
||||
return websocket_client_config;
|
||||
}
|
||||
}
|
||||
|
||||
default_websocket_client::default_websocket_client(const signalr_client_config& signalr_client_config)
|
||||
: m_underlying_client(create_client_config(signalr_client_config))
|
||||
{ }
|
||||
|
||||
pplx::task<void> default_websocket_client::connect(const web::uri &url)
|
||||
{
|
||||
return m_underlying_client.connect(url);
|
||||
}
|
||||
|
||||
pplx::task<void> default_websocket_client::send(const utility::string_t &message)
|
||||
{
|
||||
web::websockets::client::websocket_outgoing_message msg;
|
||||
msg.set_utf8_message(utility::conversions::to_utf8string(message));
|
||||
return m_underlying_client.send(msg);
|
||||
}
|
||||
|
||||
pplx::task<std::string> default_websocket_client::receive()
|
||||
{
|
||||
// the caller is responsible for observing exceptions
|
||||
return m_underlying_client.receive()
|
||||
.then([](web::websockets::client::websocket_incoming_message msg)
|
||||
{
|
||||
return msg.extract_string();
|
||||
});
|
||||
}
|
||||
|
||||
pplx::task<void> default_websocket_client::close()
|
||||
{
|
||||
return m_underlying_client.close();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cpprest/ws_client.h"
|
||||
#include "signalrclient/signalr_client_config.h"
|
||||
#include "websocket_client.h"
|
||||
|
||||
namespace signalr
|
||||
{
|
||||
class default_websocket_client : public websocket_client
|
||||
{
|
||||
public:
|
||||
explicit default_websocket_client(const signalr_client_config& signalr_client_config = signalr_client_config{});
|
||||
|
||||
pplx::task<void> connect(const web::uri &url) override;
|
||||
|
||||
pplx::task<void> send(const utility::string_t &message) override;
|
||||
|
||||
pplx::task<std::string> receive() override;
|
||||
|
||||
pplx::task<void> close() override;
|
||||
|
||||
private:
|
||||
web::websockets::client::websocket_client m_underlying_client;
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <assert.h>
|
||||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
|
||||
namespace signalr
|
||||
{
|
||||
class event
|
||||
{
|
||||
private:
|
||||
std::mutex m_lock;
|
||||
std::condition_variable m_condition;
|
||||
bool m_signaled;
|
||||
public:
|
||||
|
||||
static const unsigned int timeout_infinite = 0xFFFFFFFF;
|
||||
|
||||
event()
|
||||
: m_signaled(false)
|
||||
{
|
||||
}
|
||||
|
||||
void set()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_lock);
|
||||
m_signaled = true;
|
||||
m_condition.notify_all();
|
||||
}
|
||||
|
||||
void reset()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_lock);
|
||||
m_signaled = false;
|
||||
}
|
||||
|
||||
unsigned int wait(unsigned int timeout)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_lock);
|
||||
if (timeout == event::timeout_infinite)
|
||||
{
|
||||
m_condition.wait(lock, [this]() { return m_signaled; });
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::chrono::milliseconds period(timeout);
|
||||
auto status = m_condition.wait_for(lock, period, [this]() { return m_signaled; });
|
||||
assert(status == m_signaled);
|
||||
// Return 0 if the wait completed as a result of signaling the event. Otherwise, return timeout_infinite
|
||||
return status ? 0 : event::timeout_infinite;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int wait()
|
||||
{
|
||||
return wait(event::timeout_infinite);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
// Copyright (c) .NET Foundation. 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 "signalrclient/web_exception.h"
|
||||
#include "web_request_factory.h"
|
||||
#include "constants.h"
|
||||
|
||||
namespace signalr
|
||||
{
|
||||
namespace http_sender
|
||||
{
|
||||
pplx::task<utility::string_t> get(web_request_factory& request_factory, const web::uri& url,
|
||||
const signalr_client_config& signalr_client_config)
|
||||
{
|
||||
auto request = request_factory.create_web_request(url);
|
||||
request->set_method(web::http::methods::GET);
|
||||
|
||||
request->set_user_agent(USER_AGENT);
|
||||
request->set_client_config(signalr_client_config);
|
||||
|
||||
return request->get_response().then([](web_response response)
|
||||
{
|
||||
if (response.status_code != 200)
|
||||
{
|
||||
utility::ostringstream_t oss;
|
||||
oss << _XPLATSTR("web exception - ") << response.status_code << _XPLATSTR(" ") << response.reason_phrase;
|
||||
throw web_exception(oss.str(), response.status_code);
|
||||
}
|
||||
|
||||
return response.body;
|
||||
});
|
||||
}
|
||||
|
||||
pplx::task<utility::string_t> post(web_request_factory& request_factory, const web::uri& url,
|
||||
const signalr_client_config& signalr_client_config)
|
||||
{
|
||||
auto request = request_factory.create_web_request(url);
|
||||
request->set_method(web::http::methods::POST);
|
||||
|
||||
request->set_user_agent(USER_AGENT);
|
||||
request->set_client_config(signalr_client_config);
|
||||
|
||||
return request->get_response().then([](web_response response)
|
||||
{
|
||||
if (response.status_code != 200)
|
||||
{
|
||||
utility::ostringstream_t oss;
|
||||
oss << _XPLATSTR("web exception - ") << response.status_code << _XPLATSTR(" ") << response.reason_phrase;
|
||||
throw web_exception(oss.str(), response.status_code);
|
||||
}
|
||||
|
||||
return response.body;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "pplx/pplxtasks.h"
|
||||
#include "cpprest/details/basic_types.h"
|
||||
#include "signalrclient/signalr_client_config.h"
|
||||
#include "web_request_factory.h"
|
||||
|
||||
namespace signalr
|
||||
{
|
||||
namespace http_sender
|
||||
{
|
||||
pplx::task<utility::string_t> get(web_request_factory& request_factory, const web::uri& url,
|
||||
const signalr_client_config& client_config = signalr_client_config{});
|
||||
|
||||
pplx::task<utility::string_t> post(web_request_factory& request_factory, const web::uri& url,
|
||||
const signalr_client_config& client_config = signalr_client_config{});
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
// Copyright (c) .NET Foundation. 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 "signalrclient/hub_connection.h"
|
||||
#include "hub_connection_impl.h"
|
||||
#include "signalrclient/signalr_exception.h"
|
||||
|
||||
namespace signalr
|
||||
{
|
||||
hub_connection::hub_connection(const utility::string_t& url, const utility::string_t& query_string,
|
||||
trace_level trace_level, std::shared_ptr<log_writer> log_writer, bool use_default_url)
|
||||
: m_pImpl(hub_connection_impl::create(url, query_string, trace_level, std::move(log_writer), use_default_url))
|
||||
{}
|
||||
|
||||
// Do NOT remove this destructor. Letting the compiler generate and inline the default dtor may lead to
|
||||
// undefinded behavior since we are using an incomplete type. More details here: http://herbsutter.com/gotw/_100/
|
||||
hub_connection::~hub_connection() = default;
|
||||
|
||||
pplx::task<void> hub_connection::start()
|
||||
{
|
||||
return m_pImpl->start();
|
||||
}
|
||||
|
||||
pplx::task<void> hub_connection::stop()
|
||||
{
|
||||
return m_pImpl->stop();
|
||||
}
|
||||
|
||||
void hub_connection::on(const utility::string_t& event_name, const method_invoked_handler& handler)
|
||||
{
|
||||
if (!m_pImpl)
|
||||
{
|
||||
throw signalr_exception(_XPLATSTR("on() cannot be called on uninitialized hub_connection instance"));
|
||||
}
|
||||
|
||||
return m_pImpl->on(event_name, handler);
|
||||
}
|
||||
|
||||
pplx::task<web::json::value> hub_connection::invoke_json(const utility::string_t& method_name, const web::json::value& arguments)
|
||||
{
|
||||
if (!m_pImpl)
|
||||
{
|
||||
throw signalr_exception(_XPLATSTR("invoke() cannot be called on uninitialized hub_proxy instance"));
|
||||
}
|
||||
|
||||
return m_pImpl->invoke_json(method_name, arguments);
|
||||
}
|
||||
|
||||
pplx::task<void> hub_connection::invoke_void(const utility::string_t& method_name, const web::json::value& arguments)
|
||||
{
|
||||
if (!m_pImpl)
|
||||
{
|
||||
throw signalr_exception(_XPLATSTR("invoke() cannot be called on uninitialized hub_proxy instance"));
|
||||
}
|
||||
|
||||
return m_pImpl->invoke_void(method_name, arguments);
|
||||
}
|
||||
|
||||
connection_state hub_connection::get_connection_state() const
|
||||
{
|
||||
return m_pImpl->get_connection_state();
|
||||
}
|
||||
|
||||
utility::string_t hub_connection::get_connection_id() const
|
||||
{
|
||||
return m_pImpl->get_connection_id();
|
||||
}
|
||||
|
||||
void hub_connection::set_reconnecting(const std::function<void()>& reconnecting_callback)
|
||||
{
|
||||
m_pImpl->set_reconnecting(reconnecting_callback);
|
||||
}
|
||||
|
||||
void hub_connection::set_reconnected(const std::function<void()>& reconnected_callback)
|
||||
{
|
||||
m_pImpl->set_reconnected(reconnected_callback);
|
||||
}
|
||||
|
||||
void hub_connection::set_disconnected(const std::function<void()>& disconnected_callback)
|
||||
{
|
||||
m_pImpl->set_disconnected(disconnected_callback);
|
||||
}
|
||||
|
||||
void hub_connection::set_client_config(const signalr_client_config& config)
|
||||
{
|
||||
m_pImpl->set_client_config(config);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,296 @@
|
|||
// Copyright (c) .NET Foundation. 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 "hub_connection_impl.h"
|
||||
#include "signalrclient/hub_exception.h"
|
||||
#include "trace_log_writer.h"
|
||||
#include "make_unique.h"
|
||||
#include "signalrclient/signalr_exception.h"
|
||||
|
||||
using namespace web;
|
||||
|
||||
namespace signalr
|
||||
{
|
||||
// unnamed namespace makes it invisble outside this translation unit
|
||||
namespace
|
||||
{
|
||||
static std::function<void(const json::value&)> create_hub_invocation_callback(const logger& logger,
|
||||
const std::function<void(const json::value&)>& set_result,
|
||||
const std::function<void(const std::exception_ptr e)>& set_exception);
|
||||
|
||||
static utility::string_t adapt_url(const utility::string_t& url, bool use_default_url);
|
||||
}
|
||||
|
||||
std::shared_ptr<hub_connection_impl> hub_connection_impl::create(const utility::string_t& url, const utility::string_t& query_string,
|
||||
trace_level trace_level, const std::shared_ptr<log_writer>& log_writer, bool use_default_url)
|
||||
{
|
||||
return hub_connection_impl::create(url, query_string, trace_level, log_writer, use_default_url,
|
||||
std::make_unique<web_request_factory>(), std::make_unique<transport_factory>());
|
||||
}
|
||||
|
||||
std::shared_ptr<hub_connection_impl> hub_connection_impl::create(const utility::string_t& url, const utility::string_t& query_string,
|
||||
trace_level trace_level, const std::shared_ptr<log_writer>& log_writer, bool use_default_url,
|
||||
std::unique_ptr<web_request_factory> web_request_factory, std::unique_ptr<transport_factory> transport_factory)
|
||||
{
|
||||
auto connection = std::shared_ptr<hub_connection_impl>(new hub_connection_impl(url, query_string, trace_level,
|
||||
log_writer ? log_writer : std::make_shared<trace_log_writer>(), use_default_url,
|
||||
std::move(web_request_factory), std::move(transport_factory)));
|
||||
|
||||
connection->initialize();
|
||||
|
||||
return connection;
|
||||
}
|
||||
|
||||
hub_connection_impl::hub_connection_impl(const utility::string_t& url, const utility::string_t& query_string, trace_level trace_level,
|
||||
const std::shared_ptr<log_writer>& log_writer, bool use_default_url, std::unique_ptr<web_request_factory> web_request_factory,
|
||||
std::unique_ptr<transport_factory> transport_factory)
|
||||
: m_connection(connection_impl::create(adapt_url(url, use_default_url), query_string, trace_level, log_writer,
|
||||
std::move(web_request_factory), std::move(transport_factory))),m_logger(log_writer, trace_level),
|
||||
m_callback_manager(json::value::parse(_XPLATSTR("{ \"E\" : \"connection went out of scope before invocation result was received\"}")))
|
||||
{ }
|
||||
|
||||
void hub_connection_impl::initialize()
|
||||
{
|
||||
auto this_hub_connection = shared_from_this();
|
||||
|
||||
// weak_ptr prevents a circular dependency leading to memory leak and other problems
|
||||
auto weak_hub_connection = std::weak_ptr<hub_connection_impl>(this_hub_connection);
|
||||
|
||||
m_connection->set_message_received_json([weak_hub_connection](const web::json::value& message)
|
||||
{
|
||||
auto connection = weak_hub_connection.lock();
|
||||
if (connection)
|
||||
{
|
||||
connection->process_message(message);
|
||||
}
|
||||
});
|
||||
|
||||
set_reconnecting([](){});
|
||||
}
|
||||
|
||||
void hub_connection_impl::on(const utility::string_t& event_name, const std::function<void(const json::value &)>& handler)
|
||||
{
|
||||
if (event_name.length() == 0)
|
||||
{
|
||||
throw std::invalid_argument("event_name cannot be empty");
|
||||
}
|
||||
|
||||
auto weak_connection = std::weak_ptr<hub_connection_impl>(shared_from_this());
|
||||
auto connection = weak_connection.lock();
|
||||
if (connection && connection->get_connection_state() != connection_state::disconnected)
|
||||
{
|
||||
throw signalr_exception(_XPLATSTR("can't register a handler if the connection is in a disconnected state"));
|
||||
}
|
||||
|
||||
if (m_subscriptions.find(event_name) != m_subscriptions.end())
|
||||
{
|
||||
throw signalr_exception(
|
||||
_XPLATSTR("an action for this event has already been registered. event name: ") + event_name);
|
||||
}
|
||||
|
||||
m_subscriptions.insert(std::pair<utility::string_t, std::function<void(const json::value &)>> {event_name, handler});
|
||||
}
|
||||
|
||||
pplx::task<void> hub_connection_impl::start()
|
||||
{
|
||||
return m_connection->start();
|
||||
}
|
||||
|
||||
pplx::task<void> hub_connection_impl::stop()
|
||||
{
|
||||
m_callback_manager.clear(json::value::parse(_XPLATSTR("{ \"E\" : \"connection was stopped before invocation result was received\"}")));
|
||||
return m_connection->stop();
|
||||
}
|
||||
|
||||
void hub_connection_impl::process_message(const web::json::value& message)
|
||||
{
|
||||
auto type = message.at(_XPLATSTR("type")).as_integer();
|
||||
if (type == 3)
|
||||
{
|
||||
if (invoke_callback(message))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (type == 1)
|
||||
{
|
||||
auto method = message.at(_XPLATSTR("target")).as_string();
|
||||
auto event = m_subscriptions.find(method);
|
||||
if (event != m_subscriptions.end())
|
||||
{
|
||||
event->second(message.at(_XPLATSTR("arguments")));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
m_logger.log(trace_level::info, utility::string_t(_XPLATSTR("non-hub message received and will be discarded. message: "))
|
||||
.append(message.serialize()));
|
||||
}
|
||||
|
||||
bool hub_connection_impl::invoke_callback(const web::json::value& message)
|
||||
{
|
||||
auto id = message.at(_XPLATSTR("invocationId")).as_string();
|
||||
if (!m_callback_manager.invoke_callback(id, message, true))
|
||||
{
|
||||
m_logger.log(trace_level::info, utility::string_t(_XPLATSTR("no callback found for id: ")).append(id));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
pplx::task<json::value> hub_connection_impl::invoke_json(const utility::string_t& method_name, const json::value& arguments)
|
||||
{
|
||||
_ASSERTE(arguments.is_array());
|
||||
|
||||
pplx::task_completion_event<json::value> tce;
|
||||
|
||||
const auto callback_id = m_callback_manager.register_callback(
|
||||
create_hub_invocation_callback(m_logger, [tce](const json::value& result) { tce.set(result); },
|
||||
[tce](const std::exception_ptr e) { tce.set_exception(e); }));
|
||||
|
||||
invoke_hub_method(method_name, arguments, callback_id, nullptr,
|
||||
[tce](const std::exception_ptr e){tce.set_exception(e); });
|
||||
|
||||
return pplx::create_task(tce);
|
||||
}
|
||||
|
||||
pplx::task<void> hub_connection_impl::invoke_void(const utility::string_t& method_name, const json::value& arguments)
|
||||
{
|
||||
_ASSERTE(arguments.is_array());
|
||||
|
||||
pplx::task_completion_event<void> tce;
|
||||
|
||||
invoke_hub_method(method_name, arguments, _XPLATSTR(""),
|
||||
[tce]() { tce.set(); },
|
||||
[tce](const std::exception_ptr e){ tce.set_exception(e); });
|
||||
|
||||
return pplx::create_task(tce);
|
||||
}
|
||||
|
||||
void hub_connection_impl::invoke_hub_method(const utility::string_t& method_name, const json::value& arguments,
|
||||
const utility::string_t& callback_id, std::function<void()> set_completion, std::function<void(const std::exception_ptr)> set_exception)
|
||||
{
|
||||
json::value request;
|
||||
request[_XPLATSTR("type")] = json::value::value(1);
|
||||
if (!callback_id.empty())
|
||||
{
|
||||
request[_XPLATSTR("invocationId")] = json::value::string(callback_id);
|
||||
}
|
||||
request[_XPLATSTR("target")] = json::value::string(method_name);
|
||||
request[_XPLATSTR("arguments")] = arguments;
|
||||
|
||||
auto this_hub_connection = shared_from_this();
|
||||
|
||||
// weak_ptr prevents a circular dependency leading to memory leak and other problems
|
||||
auto weak_hub_connection = std::weak_ptr<hub_connection_impl>(this_hub_connection);
|
||||
|
||||
m_connection->send(request.serialize() + _XPLATSTR('\x1e'))
|
||||
.then([set_completion, set_exception, weak_hub_connection, callback_id](pplx::task<void> send_task)
|
||||
{
|
||||
try
|
||||
{
|
||||
send_task.get();
|
||||
if (callback_id.empty())
|
||||
{
|
||||
// complete nonBlocking call
|
||||
set_completion();
|
||||
}
|
||||
}
|
||||
catch (const std::exception&)
|
||||
{
|
||||
set_exception(std::current_exception());
|
||||
auto hub_connection = weak_hub_connection.lock();
|
||||
if (hub_connection)
|
||||
{
|
||||
hub_connection->m_callback_manager.remove_callback(callback_id);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
connection_state hub_connection_impl::get_connection_state() const
|
||||
{
|
||||
return m_connection->get_connection_state();
|
||||
}
|
||||
|
||||
utility::string_t hub_connection_impl::get_connection_id() const
|
||||
{
|
||||
return m_connection->get_connection_id();
|
||||
}
|
||||
|
||||
void hub_connection_impl::set_client_config(const signalr_client_config& config)
|
||||
{
|
||||
m_connection->set_client_config(config);
|
||||
}
|
||||
|
||||
void hub_connection_impl::set_reconnecting(const std::function<void()>& reconnecting)
|
||||
{
|
||||
// weak_ptr prevents a circular dependency leading to memory leak and other problems
|
||||
auto weak_hub_connection = std::weak_ptr<hub_connection_impl>(shared_from_this());
|
||||
|
||||
m_connection->set_reconnecting([weak_hub_connection, reconnecting]()
|
||||
{
|
||||
auto hub_connection = weak_hub_connection.lock();
|
||||
if (hub_connection)
|
||||
{
|
||||
hub_connection->m_callback_manager.clear(
|
||||
json::value::parse(_XPLATSTR("{ \"E\" : \"connection has been lost\"}")));
|
||||
}
|
||||
|
||||
reconnecting();
|
||||
});
|
||||
}
|
||||
|
||||
void hub_connection_impl::set_reconnected(const std::function<void()>& reconnected)
|
||||
{
|
||||
m_connection->set_reconnected(reconnected);
|
||||
}
|
||||
|
||||
void hub_connection_impl::set_disconnected(const std::function<void()>& disconnected)
|
||||
{
|
||||
m_connection->set_disconnected(disconnected);
|
||||
}
|
||||
|
||||
// unnamed namespace makes it invisble outside this translation unit
|
||||
namespace
|
||||
{
|
||||
static std::function<void(const json::value&)> create_hub_invocation_callback(const logger& logger,
|
||||
const std::function<void(const json::value&)>& set_result,
|
||||
const std::function<void(const std::exception_ptr)>& set_exception)
|
||||
{
|
||||
return [logger, set_result, set_exception](const json::value& message)
|
||||
{
|
||||
if (message.has_field(_XPLATSTR("result")))
|
||||
{
|
||||
set_result(message.at(_XPLATSTR("result")));
|
||||
}
|
||||
else if (message.has_field(_XPLATSTR("error")))
|
||||
{
|
||||
set_exception(
|
||||
std::make_exception_ptr(
|
||||
signalr_exception(message.at(_XPLATSTR("error")).serialize())));
|
||||
}
|
||||
|
||||
set_result(json::value::null());
|
||||
};
|
||||
}
|
||||
|
||||
static utility::string_t adapt_url(const utility::string_t& url, bool use_default_url)
|
||||
{
|
||||
if (use_default_url)
|
||||
{
|
||||
auto new_url = url;
|
||||
if (new_url.back() != _XPLATSTR('/'))
|
||||
{
|
||||
new_url.append(_XPLATSTR("/"));
|
||||
}
|
||||
|
||||
return new_url;
|
||||
}
|
||||
|
||||
return url;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <unordered_map>
|
||||
#include "cpprest/details/basic_types.h"
|
||||
#include "connection_impl.h"
|
||||
#include "callback_manager.h"
|
||||
#include "case_insensitive_comparison_utils.h"
|
||||
|
||||
using namespace web;
|
||||
|
||||
namespace signalr
|
||||
{
|
||||
// Note:
|
||||
// Factory methods and private constructors prevent from using this class incorrectly. Because this class
|
||||
// derives from `std::enable_shared_from_this` the instance has to be owned by a `std::shared_ptr` whenever
|
||||
// a member method calls `std::shared_from_this()` otherwise the behavior is undefined. Therefore constructors
|
||||
// are private to disallow creating instances directly and factory methods return `std::shared_ptr<connection_impl>`.
|
||||
class hub_connection_impl : public std::enable_shared_from_this<hub_connection_impl>
|
||||
{
|
||||
public:
|
||||
static std::shared_ptr<hub_connection_impl> create(const utility::string_t& url, const utility::string_t& query_string,
|
||||
trace_level trace_level, const std::shared_ptr<log_writer>& log_writer, bool use_default_url);
|
||||
|
||||
static std::shared_ptr<hub_connection_impl> create(const utility::string_t& url, const utility::string_t& query_string,
|
||||
trace_level trace_level, const std::shared_ptr<log_writer>& log_writer, bool use_default_url,
|
||||
std::unique_ptr<web_request_factory> web_request_factory, std::unique_ptr<transport_factory> transport_factory);
|
||||
|
||||
hub_connection_impl(const hub_connection_impl&) = delete;
|
||||
hub_connection_impl& operator=(const hub_connection_impl&) = delete;
|
||||
|
||||
void on(const utility::string_t& event_name, const std::function<void(const json::value &)>& handler);
|
||||
|
||||
pplx::task<json::value> invoke_json(const utility::string_t& method_name, const json::value& arguments);
|
||||
pplx::task<void> invoke_void(const utility::string_t& method_name, const json::value& arguments);
|
||||
|
||||
pplx::task<void> start();
|
||||
pplx::task<void> stop();
|
||||
|
||||
connection_state get_connection_state() const;
|
||||
utility::string_t get_connection_id() const;
|
||||
|
||||
void set_client_config(const signalr_client_config& config);
|
||||
void set_reconnecting(const std::function<void()>& reconnecting);
|
||||
void set_reconnected(const std::function<void()>& reconnected);
|
||||
void set_disconnected(const std::function<void()>& disconnected);
|
||||
|
||||
private:
|
||||
hub_connection_impl(const utility::string_t& url, const utility::string_t& query_string, trace_level trace_level,
|
||||
const std::shared_ptr<log_writer>& log_writer, bool use_default_url,
|
||||
std::unique_ptr<web_request_factory> web_request_factory, std::unique_ptr<transport_factory> transport_factory);
|
||||
|
||||
std::shared_ptr<connection_impl> m_connection;
|
||||
logger m_logger;
|
||||
callback_manager m_callback_manager;
|
||||
std::unordered_map<utility::string_t, std::function<void(const json::value &)>, case_insensitive_hash, case_insensitive_equals> m_subscriptions;
|
||||
|
||||
void initialize();
|
||||
|
||||
void process_message(const web::json::value& message);
|
||||
|
||||
void invoke_hub_method(const utility::string_t& method_name, const json::value& arguments, const utility::string_t& callback_id,
|
||||
std::function<void()> set_completion, std::function<void(const std::exception_ptr)> set_exception);
|
||||
bool invoke_callback(const web::json::value& message);
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
// Copyright (c) .NET Foundation. 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 "logger.h"
|
||||
#include "cpprest/asyncrt_utils.h"
|
||||
#include <iomanip>
|
||||
|
||||
namespace signalr
|
||||
{
|
||||
logger::logger(const std::shared_ptr<log_writer>& log_writer, trace_level trace_level)
|
||||
: m_log_writer(log_writer), m_trace_level(trace_level)
|
||||
{ }
|
||||
|
||||
void logger::log(trace_level level, const utility::string_t& entry)
|
||||
{
|
||||
if ((level & m_trace_level) != trace_level::none)
|
||||
{
|
||||
try
|
||||
{
|
||||
utility::ostringstream_t os;
|
||||
os << utility::datetime::utc_now().to_string(utility::datetime::date_format::ISO_8601) << _XPLATSTR(" [")
|
||||
<< std::left << std::setw(12) << translate_trace_level(level) << "] "<< entry << std::endl;
|
||||
m_log_writer->write(os.str());
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
ucerr << _XPLATSTR("error occurred when logging: ") << utility::conversions::to_string_t(e.what())
|
||||
<< std::endl << _XPLATSTR(" entry: ") << entry << std::endl;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
ucerr << _XPLATSTR("unknown error occurred when logging") << std::endl << _XPLATSTR(" entry: ") << entry << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
utility::string_t logger::translate_trace_level(trace_level trace_level)
|
||||
{
|
||||
switch (trace_level)
|
||||
{
|
||||
case signalr::trace_level::messages:
|
||||
return _XPLATSTR("message");
|
||||
case signalr::trace_level::state_changes:
|
||||
return _XPLATSTR("state change");
|
||||
case signalr::trace_level::events:
|
||||
return _XPLATSTR("event");
|
||||
case signalr::trace_level::errors:
|
||||
return _XPLATSTR("error");
|
||||
case signalr::trace_level::info:
|
||||
return _XPLATSTR("info");
|
||||
default:
|
||||
_ASSERTE(false);
|
||||
return _XPLATSTR("(unknown)");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include "signalrclient/trace_level.h"
|
||||
#include "signalrclient/log_writer.h"
|
||||
|
||||
namespace signalr
|
||||
{
|
||||
class logger
|
||||
{
|
||||
public:
|
||||
logger(const std::shared_ptr<log_writer>& log_writer, trace_level trace_level);
|
||||
|
||||
void log(trace_level level, const utility::string_t& entry);
|
||||
|
||||
private:
|
||||
std::shared_ptr<log_writer> m_log_writer;
|
||||
trace_level m_trace_level;
|
||||
|
||||
static utility::string_t translate_trace_level(trace_level trace_level);
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#if defined (__GNUC__)
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace std
|
||||
{
|
||||
template<typename T, typename... Args>
|
||||
std::unique_ptr<T> make_unique(Args&&... args)
|
||||
{
|
||||
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cpprest/details/basic_types.h"
|
||||
|
||||
namespace signalr
|
||||
{
|
||||
struct negotiation_response
|
||||
{
|
||||
utility::string_t connection_id;
|
||||
web::json::value availableTransports;
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
// Copyright (c) .NET Foundation. 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 "request_sender.h"
|
||||
#include "http_sender.h"
|
||||
#include "url_builder.h"
|
||||
#include "signalrclient/signalr_exception.h"
|
||||
|
||||
namespace signalr
|
||||
{
|
||||
namespace request_sender
|
||||
{
|
||||
pplx::task<negotiation_response> negotiate(web_request_factory& request_factory, const web::uri& base_url,
|
||||
const utility::string_t& query_string, const signalr_client_config& signalr_client_config)
|
||||
{
|
||||
auto negotiate_url = url_builder::build_negotiate(base_url, query_string);
|
||||
|
||||
return http_sender::post(request_factory, negotiate_url, signalr_client_config)
|
||||
.then([](utility::string_t body)
|
||||
{
|
||||
auto negotiation_response_json = web::json::value::parse(body);
|
||||
negotiation_response response
|
||||
{
|
||||
negotiation_response_json[_XPLATSTR("connectionId")].as_string(),
|
||||
negotiation_response_json[_XPLATSTR("availableTransports")],
|
||||
};
|
||||
|
||||
return response;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cpprest/base_uri.h"
|
||||
#include "signalrclient/signalr_client_config.h"
|
||||
#include "signalrclient/transport_type.h"
|
||||
#include "web_request_factory.h"
|
||||
#include "negotiation_response.h"
|
||||
|
||||
|
||||
namespace signalr
|
||||
{
|
||||
namespace request_sender
|
||||
{
|
||||
pplx::task<negotiation_response> negotiate(web_request_factory& request_factory, const web::uri &base_url,
|
||||
const utility::string_t& query_string, const signalr_client_config& signalr_client_config = signalr::signalr_client_config{});
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
// Copyright (c) .NET Foundation. 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 "signalrclient/signalr_client_config.h"
|
||||
#include "cpprest/http_client.h"
|
||||
#include "cpprest/ws_client.h"
|
||||
|
||||
namespace signalr
|
||||
{
|
||||
void signalr_client_config::set_proxy(const web::web_proxy &proxy)
|
||||
{
|
||||
m_http_client_config.set_proxy(proxy);
|
||||
m_websocket_client_config.set_proxy(proxy);
|
||||
}
|
||||
|
||||
void signalr_client_config::set_credentials(const web::credentials &credentials)
|
||||
{
|
||||
m_http_client_config.set_credentials(credentials);
|
||||
m_websocket_client_config.set_credentials(credentials);
|
||||
}
|
||||
|
||||
web::http::client::http_client_config signalr_client_config::get_http_client_config() const
|
||||
{
|
||||
return m_http_client_config;
|
||||
}
|
||||
|
||||
void signalr_client_config::set_http_client_config(const web::http::client::http_client_config& http_client_config)
|
||||
{
|
||||
m_http_client_config = http_client_config;
|
||||
}
|
||||
|
||||
web::websockets::client::websocket_client_config signalr_client_config::get_websocket_client_config() const
|
||||
{
|
||||
return m_websocket_client_config;
|
||||
}
|
||||
|
||||
void signalr_client_config::set_websocket_client_config(const web::websockets::client::websocket_client_config& websocket_client_config)
|
||||
{
|
||||
m_websocket_client_config = websocket_client_config;
|
||||
}
|
||||
|
||||
web::http::http_headers signalr_client_config::get_http_headers() const
|
||||
{
|
||||
return m_http_headers;
|
||||
}
|
||||
|
||||
void signalr_client_config::set_http_headers(const web::http::http_headers& http_headers)
|
||||
{
|
||||
m_http_headers = http_headers;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
#include "stdafx.h"
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef _WIN32 // used in the default log writer and to build the dll
|
||||
|
||||
// prevents from defining min/max macros that conflict with std::min()/std::max() functions
|
||||
#define NOMINMAX
|
||||
|
||||
#include <SDKDDKVer.h>
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#endif
|
||||
|
||||
#include <functional>
|
||||
#include <unordered_map>
|
||||
#include "cpprest/details/basic_types.h"
|
||||
#include "cpprest/json.h"
|
||||
#include "pplx/pplxtasks.h"
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
// Copyright (c) .NET Foundation. 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 "trace_log_writer.h"
|
||||
|
||||
namespace signalr
|
||||
{
|
||||
void trace_log_writer::write(const utility::string_t &entry)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
// OutputDebugString is thread safe
|
||||
OutputDebugString(entry.c_str());
|
||||
#else
|
||||
// Note: there is no data race for standard output streams in C++ 11 but the results
|
||||
// might be garbled when the method is called concurrently from multiple threads
|
||||
#ifdef _UTF16_STRINGS
|
||||
std::wclog << entry;
|
||||
#else
|
||||
std::clog << entry;
|
||||
#endif // _UTF16_STRINGS
|
||||
|
||||
#endif // _MS_WINDOWS
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "signalrclient/log_writer.h"
|
||||
|
||||
namespace signalr
|
||||
{
|
||||
class trace_log_writer : public log_writer
|
||||
{
|
||||
public:
|
||||
void __cdecl write(const utility::string_t &entry) override;
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
// Copyright (c) .NET Foundation. 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 "transport.h"
|
||||
#include "connection_impl.h"
|
||||
|
||||
namespace signalr
|
||||
{
|
||||
transport::transport(const logger& logger, const std::function<void(const utility::string_t&)>& process_response_callback,
|
||||
std::function<void(const std::exception&)> error_callback)
|
||||
: m_logger(logger), m_process_response_callback(process_response_callback), m_error_callback(error_callback)
|
||||
{}
|
||||
|
||||
// Do NOT remove this destructor. Letting the compiler generate and inline the default dtor may lead to
|
||||
// undefinded behavior since we are using an incomplete type. More details here: http://herbsutter.com/gotw/_100/
|
||||
transport::~transport()
|
||||
{ }
|
||||
|
||||
void transport::process_response(const utility::string_t &message)
|
||||
{
|
||||
m_process_response_callback(message);
|
||||
}
|
||||
|
||||
void transport::error(const std::exception& e)
|
||||
{
|
||||
m_error_callback(e);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "pplx/pplxtasks.h"
|
||||
#include "cpprest/base_uri.h"
|
||||
#include "signalrclient/transport_type.h"
|
||||
#include "logger.h"
|
||||
|
||||
namespace signalr
|
||||
{
|
||||
class transport
|
||||
{
|
||||
public:
|
||||
virtual pplx::task<void> connect(const web::uri &url) = 0;
|
||||
|
||||
virtual pplx::task<void> send(const utility::string_t &data) = 0;
|
||||
|
||||
virtual pplx::task<void> disconnect() = 0;
|
||||
|
||||
virtual transport_type get_transport_type() const = 0;
|
||||
|
||||
virtual ~transport();
|
||||
|
||||
protected:
|
||||
transport(const logger& logger, const std::function<void(const utility::string_t &)>& process_response_callback,
|
||||
std::function<void(const std::exception&)> error_callback);
|
||||
|
||||
void process_response(const utility::string_t &message);
|
||||
void error(const std::exception &e);
|
||||
|
||||
logger m_logger;
|
||||
|
||||
private:
|
||||
std::function<void(const utility::string_t &)> m_process_response_callback;
|
||||
|
||||
std::function<void(const std::exception&)> m_error_callback;
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
// Copyright (c) .NET Foundation. 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 "transport_factory.h"
|
||||
#include "websocket_transport.h"
|
||||
|
||||
namespace signalr
|
||||
{
|
||||
std::shared_ptr<transport> transport_factory::create_transport(transport_type transport_type, const logger& logger,
|
||||
const signalr_client_config& signalr_client_config,
|
||||
std::function<void(const utility::string_t&)> process_response_callback,
|
||||
std::function<void(const std::exception&)> error_callback)
|
||||
{
|
||||
if (transport_type == signalr::transport_type::websockets)
|
||||
{
|
||||
return websocket_transport::create(
|
||||
[signalr_client_config](){ return std::make_shared<default_websocket_client>(signalr_client_config); },
|
||||
logger, process_response_callback, error_callback);
|
||||
}
|
||||
|
||||
throw std::runtime_error("not implemented");
|
||||
}
|
||||
|
||||
transport_factory::~transport_factory()
|
||||
{ }
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include "signalrclient/signalr_client_config.h"
|
||||
#include "signalrclient/transport_type.h"
|
||||
#include "transport.h"
|
||||
|
||||
namespace signalr
|
||||
{
|
||||
class transport_factory
|
||||
{
|
||||
public:
|
||||
virtual std::shared_ptr<transport> create_transport(transport_type transport_type, const logger& logger,
|
||||
const signalr_client_config& signalr_client_config,
|
||||
std::function<void(const utility::string_t&)> process_response_callback,
|
||||
std::function<void(const std::exception&)> error_callback);
|
||||
|
||||
virtual ~transport_factory();
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,134 @@
|
|||
// Copyright (c) .NET Foundation. 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 "constants.h"
|
||||
#include "cpprest/http_client.h"
|
||||
#include "signalrclient/transport_type.h"
|
||||
|
||||
namespace signalr
|
||||
{
|
||||
namespace url_builder
|
||||
{
|
||||
utility::string_t get_transport_name(transport_type transport)
|
||||
{
|
||||
_ASSERTE(transport == transport_type::websockets || transport == transport_type::long_polling);
|
||||
|
||||
return transport == transport_type::websockets
|
||||
? _XPLATSTR("webSockets")
|
||||
: _XPLATSTR("longPolling");
|
||||
}
|
||||
|
||||
void append_transport(web::uri_builder &builder, transport_type transport)
|
||||
{
|
||||
if (transport > static_cast<transport_type>(-1))
|
||||
{
|
||||
builder.append_query(_XPLATSTR("transport"), get_transport_name(transport));
|
||||
}
|
||||
}
|
||||
|
||||
void append_connection_token(web::uri_builder &builder, const utility::string_t &connection_token)
|
||||
{
|
||||
if (connection_token.length() > 0)
|
||||
{
|
||||
builder.append_query(_XPLATSTR("connectionToken"), connection_token, /* do_encoding */ true);
|
||||
}
|
||||
}
|
||||
|
||||
void append_connection_data(web::uri_builder& builder, const utility::string_t& connection_data)
|
||||
{
|
||||
if (connection_data.length() > 0)
|
||||
{
|
||||
builder.append_query(_XPLATSTR("connectionData"), connection_data, /* do_encoding */ true);
|
||||
}
|
||||
}
|
||||
|
||||
void append_message_id(web::uri_builder& builder, const utility::string_t& message_id)
|
||||
{
|
||||
if (message_id.length() > 0)
|
||||
{
|
||||
builder.append_query(_XPLATSTR("messageId"), message_id, /* do_encoding */ true);
|
||||
}
|
||||
}
|
||||
|
||||
void append_groups_token(web::uri_builder& builder, const utility::string_t& groups_token)
|
||||
{
|
||||
if (groups_token.length() > 0)
|
||||
{
|
||||
builder.append_query(_XPLATSTR("groupsToken"), groups_token, /* do_encoding */ true);
|
||||
}
|
||||
}
|
||||
|
||||
web::uri_builder &convert_to_websocket_url(web::uri_builder &builder, transport_type transport)
|
||||
{
|
||||
if (transport == transport_type::websockets)
|
||||
{
|
||||
if (builder.scheme() == _XPLATSTR("https"))
|
||||
{
|
||||
builder.set_scheme(utility::string_t(_XPLATSTR("wss")));
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.set_scheme(utility::string_t(_XPLATSTR("ws")));
|
||||
}
|
||||
}
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
web::uri_builder build_uri(const web::uri& base_url, const utility::string_t& command, transport_type transport,
|
||||
const utility::string_t& connection_data, const utility::string_t& query_string,
|
||||
const utility::string_t& last_message_id = _XPLATSTR(""), const utility::string_t& groups_token = _XPLATSTR(""))
|
||||
{
|
||||
_ASSERTE(command == _XPLATSTR("reconnect") || (last_message_id.length() == 0 && groups_token.length() == 0));
|
||||
|
||||
web::uri_builder builder(base_url);
|
||||
builder.append_path(command);
|
||||
append_transport(builder, transport);
|
||||
builder.append_query(_XPLATSTR("clientProtocol"), PROTOCOL);
|
||||
//append_connection_token(builder, connection_token);
|
||||
append_connection_data(builder, connection_data);
|
||||
append_message_id(builder, last_message_id);
|
||||
append_groups_token(builder, groups_token);
|
||||
return builder.append_query(query_string);
|
||||
}
|
||||
|
||||
web::uri_builder build_uri(const web::uri& base_url, const utility::string_t& command, const utility::string_t& query_string)
|
||||
{
|
||||
web::uri_builder builder(base_url);
|
||||
builder.append_path(command);
|
||||
return builder.append_query(query_string);
|
||||
}
|
||||
|
||||
web::uri build_negotiate(const web::uri& base_url, const utility::string_t& query_string)
|
||||
{
|
||||
return build_uri(base_url, _XPLATSTR("negotiate"), query_string).to_uri();
|
||||
}
|
||||
|
||||
web::uri build_connect(const web::uri& base_url, transport_type transport, const utility::string_t& query_string)
|
||||
{
|
||||
auto builder = build_uri(base_url, _XPLATSTR(""), query_string);
|
||||
return convert_to_websocket_url(builder, transport).to_uri();
|
||||
//auto builder = build_uri(base_url, _XPLATSTR("connect"), transport, connection_data, query_string);
|
||||
//return convert_to_websocket_url(builder, transport).to_uri();
|
||||
}
|
||||
|
||||
web::uri build_reconnect(const web::uri& base_url, transport_type transport, const utility::string_t& last_message_id, const utility::string_t& groups_token,
|
||||
const utility::string_t& query_string)
|
||||
{
|
||||
auto builder = build_uri(base_url, _XPLATSTR("reconnect"), transport, query_string, last_message_id, groups_token);
|
||||
return convert_to_websocket_url(builder, transport).to_uri();
|
||||
}
|
||||
|
||||
web::uri build_start(const web::uri &base_url, const utility::string_t &query_string)
|
||||
{
|
||||
return build_uri(base_url, _XPLATSTR(""), query_string).to_uri();
|
||||
}
|
||||
|
||||
web::uri build_abort(const web::uri &base_url, transport_type transport,
|
||||
const utility::string_t& connection_data, const utility::string_t &query_string)
|
||||
{
|
||||
return build_uri(base_url, _XPLATSTR("abort"), transport, connection_data, query_string).to_uri();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cpprest/http_client.h"
|
||||
#include "signalrclient/transport_type.h"
|
||||
|
||||
namespace signalr
|
||||
{
|
||||
namespace url_builder
|
||||
{
|
||||
web::uri build_negotiate(const web::uri& base_url, const utility::string_t& query_string);
|
||||
web::uri build_connect(const web::uri& base_url, transport_type transport, const utility::string_t& query_string);
|
||||
web::uri build_reconnect(const web::uri& base_url, transport_type transport, const utility::string_t& last_message_id,
|
||||
const utility::string_t& groups_token, const utility::string_t& query_string);
|
||||
web::uri build_start(const web::uri& base_url, const utility::string_t& query_string);
|
||||
web::uri build_abort(const web::uri &base_url, transport_type transport,
|
||||
const utility::string_t& connection_data, const utility::string_t& query_string);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
// Copyright (c) .NET Foundation. 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 "cpprest/http_client.h"
|
||||
#include "web_request.h"
|
||||
|
||||
namespace signalr
|
||||
{
|
||||
web_request::web_request(const web::uri &url)
|
||||
: m_url(url)
|
||||
{ }
|
||||
|
||||
void web_request::set_method(const utility::string_t &method)
|
||||
{
|
||||
m_request.set_method(method);
|
||||
}
|
||||
|
||||
void web_request::set_user_agent(const utility::string_t &user_agent_string)
|
||||
{
|
||||
m_user_agent_string = user_agent_string;
|
||||
}
|
||||
|
||||
void web_request::set_client_config(const signalr_client_config& signalr_client_config)
|
||||
{
|
||||
m_signalr_client_config = signalr_client_config;
|
||||
}
|
||||
|
||||
pplx::task<web_response> web_request::get_response()
|
||||
{
|
||||
web::http::client::http_client client(m_url, m_signalr_client_config.get_http_client_config());
|
||||
|
||||
m_request.headers() = m_signalr_client_config.get_http_headers();
|
||||
if (!m_user_agent_string.empty())
|
||||
{
|
||||
m_request.headers()[_XPLATSTR("User-Agent")] = m_user_agent_string;
|
||||
}
|
||||
|
||||
return client.request(m_request)
|
||||
.then([](web::http::http_response response)
|
||||
{
|
||||
return web_response
|
||||
{
|
||||
response.status_code(),
|
||||
response.reason_phrase(),
|
||||
response.extract_string()
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
web_request::~web_request() = default;
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "web_response.h"
|
||||
#include "signalrclient/signalr_client_config.h"
|
||||
|
||||
namespace signalr
|
||||
{
|
||||
class web_request
|
||||
{
|
||||
public:
|
||||
explicit web_request(const web::uri &url);
|
||||
|
||||
virtual void set_method(const utility::string_t &method);
|
||||
virtual void set_user_agent(const utility::string_t &user_agent_string);
|
||||
virtual void set_client_config(const signalr_client_config& signalr_client_config);
|
||||
|
||||
virtual pplx::task<web_response> get_response();
|
||||
|
||||
web_request& operator=(const web_request&) = delete;
|
||||
|
||||
virtual ~web_request();
|
||||
|
||||
private:
|
||||
const web::uri m_url;
|
||||
web::http::http_request m_request;
|
||||
utility::string_t m_user_agent_string;
|
||||
signalr_client_config m_signalr_client_config;
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
// Copyright (c) .NET Foundation. 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 "web_request_factory.h"
|
||||
#include "make_unique.h"
|
||||
|
||||
namespace signalr
|
||||
{
|
||||
std::unique_ptr<web_request> web_request_factory::create_web_request(const web::uri &url)
|
||||
{
|
||||
return std::make_unique<web_request>(url);
|
||||
}
|
||||
|
||||
web_request_factory::~web_request_factory()
|
||||
{}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue