Make things actually work (#10)

- Added build.cmd
- Renamed the solution to match our conventions
- Fixed bad doc comment references
- Used strong name version of StackExchange.Redis
This commit is contained in:
David Fowler 2016-11-07 20:58:41 -08:00 committed by GitHub
parent dfa9c927b7
commit 239999e4c9
11 changed files with 191 additions and 21 deletions

32
.travis.yml Normal file
View File

@ -0,0 +1,32 @@
language: csharp
sudo: required
dist: trusty
addons:
apt:
packages:
- gettext
- libcurl4-openssl-dev
- libicu-dev
- libssl-dev
- libunwind8
- zlib1g
env:
global:
- DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true
- DOTNET_CLI_TELEMETRY_OPTOUT: 1
mono:
- 4.0.5
os:
- linux
- osx
osx_image: xcode7.1
branches:
only:
- master
- release
- dev
- /^(.*\/)?ci-.*$/
before_install:
- if test "$TRAVIS_OS_NAME" == "osx"; then brew update; brew install openssl; ln -s /usr/local/opt/openssl/lib/libcrypto.1.0.0.dylib /usr/local/lib/; ln -s /usr/local/opt/openssl/lib/libssl.1.0.0.dylib /usr/local/lib/; fi
script:
- ./build.sh --quiet verify

13
appveyor.yml Normal file
View File

@ -0,0 +1,13 @@
init:
- git config --global core.autocrlf true
branches:
only:
- master
- release
- dev
- /^(.*\/)?ci-.*$/
build_script:
- build.cmd --quiet verify
clone_depth: 1
test: off
deploy: off

2
build.cmd Normal file
View File

@ -0,0 +1,2 @@
@ECHO OFF
PowerShell -NoProfile -NoLogo -ExecutionPolicy unrestricted -Command "[System.Threading.Thread]::CurrentThread.CurrentCulture = ''; [System.Threading.Thread]::CurrentThread.CurrentUICulture = '';& '%~dp0build.ps1' %*; exit $LASTEXITCODE"

67
build.ps1 Normal file
View File

@ -0,0 +1,67 @@
$ErrorActionPreference = "Stop"
function DownloadWithRetry([string] $url, [string] $downloadLocation, [int] $retries)
{
while($true)
{
try
{
Invoke-WebRequest $url -OutFile $downloadLocation
break
}
catch
{
$exceptionMessage = $_.Exception.Message
Write-Host "Failed to download '$url': $exceptionMessage"
if ($retries -gt 0) {
$retries--
Write-Host "Waiting 10 seconds before retrying. Retries left: $retries"
Start-Sleep -Seconds 10
}
else
{
$exception = $_.Exception
throw $exception
}
}
}
}
cd $PSScriptRoot
$repoFolder = $PSScriptRoot
$env:REPO_FOLDER = $repoFolder
$koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip"
if ($env:KOREBUILD_ZIP)
{
$koreBuildZip=$env:KOREBUILD_ZIP
}
$buildFolder = ".build"
$buildFile="$buildFolder\KoreBuild.ps1"
if (!(Test-Path $buildFolder)) {
Write-Host "Downloading KoreBuild from $koreBuildZip"
$tempFolder=$env:TEMP + "\KoreBuild-" + [guid]::NewGuid()
New-Item -Path "$tempFolder" -Type directory | Out-Null
$localZipFile="$tempFolder\korebuild.zip"
DownloadWithRetry -url $koreBuildZip -downloadLocation $localZipFile -retries 6
Add-Type -AssemblyName System.IO.Compression.FileSystem
[System.IO.Compression.ZipFile]::ExtractToDirectory($localZipFile, $tempFolder)
New-Item -Path "$buildFolder" -Type directory | Out-Null
copy-item "$tempFolder\**\build\*" $buildFolder -Recurse
# Cleanup
if (Test-Path $tempFolder) {
Remove-Item -Recurse -Force $tempFolder
}
}
&"$buildFile" $args

46
build.sh Normal file
View File

@ -0,0 +1,46 @@
#!/usr/bin/env bash
repoFolder="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
cd $repoFolder
koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip"
if [ ! -z $KOREBUILD_ZIP ]; then
koreBuildZip=$KOREBUILD_ZIP
fi
buildFolder=".build"
buildFile="$buildFolder/KoreBuild.sh"
if test ! -d $buildFolder; then
echo "Downloading KoreBuild from $koreBuildZip"
tempFolder="/tmp/KoreBuild-$(uuidgen)"
mkdir $tempFolder
localZipFile="$tempFolder/korebuild.zip"
retries=6
until (wget -O $localZipFile $koreBuildZip 2>/dev/null || curl -o $localZipFile --location $koreBuildZip 2>/dev/null)
do
echo "Failed to download '$koreBuildZip'"
if [ "$retries" -le 0 ]; then
exit 1
fi
retries=$((retries - 1))
echo "Waiting 10 seconds before retrying. Retries left: $retries"
sleep 10s
done
unzip -q -d $tempFolder $localZipFile
mkdir $buildFolder
cp -r $tempFolder/**/build/** $buildFolder
chmod +x $buildFile
# Cleanup
if test ! -d $tempFolder; then
rm -rf $tempFolder
fi
fi
$buildFile -r $repoFolder "$@"

View File

@ -26,7 +26,7 @@
"target": "project"
},
"NETStandard.Library": "1.6.1-*",
"StackExchange.Redis": "1.1.*"
"StackExchange.Redis.StrongName": "1.1.605"
},
"frameworks": {

View File

@ -13,13 +13,13 @@ namespace Microsoft.Extensions.WebSockets.Internal
/// <remarks>
/// <para>
/// Implementors of this type are generally considered thread-safe under the following condition: No two threads attempt to call either
/// <see cref="ReceiveAsync"/> or <see cref="SendAsync"/> simultaneously. Different threads may call each method, but the same method
/// <see cref="ExecuteAsync"/> or <see cref="SendAsync"/> simultaneously. Different threads may call each method, but the same method
/// cannot be re-entered while it is being run in a different thread. However, ensure you verify that the specific implementor is
/// thread-safe in this way. For example, <see cref="WebSocketConnection"/> (including the implementations returned by the
/// static factory methods on that type) is thread-safe in this way.
/// </para>
/// <para>
/// The general pattern of having a single thread running <see cref="ReceiveAsync"/> and a separate thread running <see cref="SendAsync"/> will
/// The general pattern of having a single thread running <see cref="ExecuteAsync"/> and a separate thread running <see cref="SendAsync"/> will
/// be thread-safe, as each method interacts with completely separate state.
/// </para>
/// </remarks>
@ -70,56 +70,63 @@ namespace Microsoft.Extensions.WebSockets.Internal
/// <summary>
/// Sends the specified frame.
/// </summary>
/// <param name="connection">The <see cref="IWebSocketConnection"/></param>
/// <param name="message">The message to send.</param>
/// <returns>A <see cref="Task"/> that completes when the message has been written to the outbound stream.</returns>
public static Task SendAsync(this IWebSocketConnection self, WebSocketFrame message) => self.SendAsync(message, CancellationToken.None);
public static Task SendAsync(this IWebSocketConnection connection, WebSocketFrame message) => connection.SendAsync(message, CancellationToken.None);
/// <summary>
/// Sends a Close frame to the other party. This does not guarantee that the client will send a responding close frame.
/// </summary>
/// <param name="connection">The <see cref="IWebSocketConnection"/></param>
/// <param name="status">A <see cref="WebSocketCloseStatus"/> value to be sent to the client in the close frame</param>.
/// <returns>A <see cref="Task"/> that completes when the close frame has been sent</returns>
public static Task CloseAsync(this IWebSocketConnection self, WebSocketCloseStatus status) => self.CloseAsync(new WebSocketCloseResult(status), CancellationToken.None);
public static Task CloseAsync(this IWebSocketConnection connection, WebSocketCloseStatus status) => connection.CloseAsync(new WebSocketCloseResult(status), CancellationToken.None);
/// <summary>
/// Sends a Close frame to the other party. This does not guarantee that the client will send a responding close frame.
/// </summary>
/// <param name="connection">The <see cref="IWebSocketConnection"/></param>
/// <param name="status">A <see cref="WebSocketCloseStatus"/> value to be sent to the client in the close frame</param>.
/// <param name="description">A textual description of the reason for closing the connection.</param>
/// <returns>A <see cref="Task"/> that completes when the close frame has been sent</returns>
public static Task CloseAsync(this IWebSocketConnection self, WebSocketCloseStatus status, string description) => self.CloseAsync(new WebSocketCloseResult(status, description), CancellationToken.None);
public static Task CloseAsync(this IWebSocketConnection connection, WebSocketCloseStatus status, string description) => connection.CloseAsync(new WebSocketCloseResult(status, description), CancellationToken.None);
/// <summary>
/// Sends a Close frame to the other party. This does not guarantee that the client will send a responding close frame.
/// </summary>
/// <param name="connection">The <see cref="IWebSocketConnection"/></param>
/// <param name="status">A <see cref="WebSocketCloseStatus"/> value to be sent to the client in the close frame</param>.
/// <param name="cancellationToken">A <see cref="CancellationToken"/> that indicates when/if the send is cancelled.</param>
/// <returns>A <see cref="Task"/> that completes when the close frame has been sent</returns>
public static Task CloseAsync(this IWebSocketConnection self, WebSocketCloseStatus status, CancellationToken cancellationToken) => self.CloseAsync(new WebSocketCloseResult(status), cancellationToken);
public static Task CloseAsync(this IWebSocketConnection connection, WebSocketCloseStatus status, CancellationToken cancellationToken) => connection.CloseAsync(new WebSocketCloseResult(status), cancellationToken);
/// <summary>
/// Sends a Close frame to the other party. This does not guarantee that the client will send a responding close frame.
/// </summary>
/// <param name="connection">The <see cref="IWebSocketConnection"/></param>
/// <param name="status">A <see cref="WebSocketCloseStatus"/> value to be sent to the client in the close frame</param>.
/// <param name="description">A textual description of the reason for closing the connection.</param>
/// <param name="cancellationToken">A <see cref="CancellationToken"/> that indicates when/if the send is cancelled.</param>
/// <returns>A <see cref="Task"/> that completes when the close frame has been sent</returns>
public static Task CloseAsync(this IWebSocketConnection self, WebSocketCloseStatus status, string description, CancellationToken cancellationToken) => self.CloseAsync(new WebSocketCloseResult(status, description), cancellationToken);
public static Task CloseAsync(this IWebSocketConnection connection, WebSocketCloseStatus status, string description, CancellationToken cancellationToken) => connection.CloseAsync(new WebSocketCloseResult(status, description), cancellationToken);
/// <summary>
/// Sends a Close frame to the other party. This does not guarantee that the client will send a responding close frame.
/// </summary>
/// <param name="connection">The <see cref="IWebSocketConnection"/></param>
/// <param name="result">A <see cref="WebSocketCloseResult"/> with the payload for the close frame.</param>
/// <returns>A <see cref="Task"/> that completes when the close frame has been sent</returns>
public static Task CloseAsync(this IWebSocketConnection self, WebSocketCloseResult result) => self.CloseAsync(result, CancellationToken.None);
public static Task CloseAsync(this IWebSocketConnection connection, WebSocketCloseResult result) => connection.CloseAsync(result, CancellationToken.None);
/// <summary>
/// Runs the WebSocket receive loop, using the provided message handler.
/// </summary>
/// <param name="connection">The <see cref="IWebSocketConnection"/></param>
/// <param name="messageHandler">The callback that will be invoked for each new frame</param>
/// <returns>A <see cref="Task{WebSocketCloseResult}"/> that will complete when the client has sent a close frame, or the connection has been terminated</returns>
public static Task<WebSocketCloseResult> ExecuteAsync(this IWebSocketConnection self, Action<WebSocketFrame> messageHandler) =>
self.ExecuteAsync((frame, _) =>
public static Task<WebSocketCloseResult> ExecuteAsync(this IWebSocketConnection connection, Action<WebSocketFrame> messageHandler) =>
connection.ExecuteAsync((frame, _) =>
{
messageHandler(frame);
return Task.CompletedTask;
@ -128,10 +135,12 @@ namespace Microsoft.Extensions.WebSockets.Internal
/// <summary>
/// Runs the WebSocket receive loop, using the provided message handler.
/// </summary>
/// <param name="connection">The <see cref="IWebSocketConnection"/></param>
/// <param name="messageHandler">The callback that will be invoked for each new frame</param>
/// <param name="state">The state to pass to the callback when the delegate is invoked. This may be null.</param>
/// <returns>A <see cref="Task{WebSocketCloseResult}"/> that will complete when the client has sent a close frame, or the connection has been terminated</returns>
public static Task<WebSocketCloseResult> ExecuteAsync(this IWebSocketConnection self, Action<WebSocketFrame, object> messageHandler, object state) =>
self.ExecuteAsync((frame, s) =>
public static Task<WebSocketCloseResult> ExecuteAsync(this IWebSocketConnection connection, Action<WebSocketFrame, object> messageHandler, object state) =>
connection.ExecuteAsync((frame, s) =>
{
messageHandler(frame, s);
return Task.CompletedTask;
@ -140,9 +149,10 @@ namespace Microsoft.Extensions.WebSockets.Internal
/// <summary>
/// Runs the WebSocket receive loop, using the provided message handler.
/// </summary>
/// <param name="connection">The <see cref="IWebSocketConnection"/></param>
/// <param name="messageHandler">The callback that will be invoked for each new frame</param>
/// <returns>A <see cref="Task{WebSocketCloseResult}"/> that will complete when the client has sent a close frame, or the connection has been terminated</returns>
public static Task<WebSocketCloseResult> ExecuteAsync(this IWebSocketConnection self, Func<WebSocketFrame, Task> messageHandler) =>
self.ExecuteAsync((frame, _) => messageHandler(frame), null);
public static Task<WebSocketCloseResult> ExecuteAsync(this IWebSocketConnection connection, Func<WebSocketFrame, Task> messageHandler) =>
connection.ExecuteAsync((frame, _) => messageHandler(frame), null);
}
}

View File

@ -12,4 +12,4 @@ using System.Runtime.CompilerServices;
[assembly: AssemblyProduct("Microsoft.Extensions.WebSockets")]
[assembly: AssemblyTrademark("")]
[assembly: InternalsVisibleTo("Microsoft.Extensions.WebSockets.Tests")]
[assembly: InternalsVisibleTo("Microsoft.Extensions.WebSockets.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]

View File

@ -18,11 +18,11 @@ namespace Microsoft.Extensions.WebSockets.Internal
/// <remarks>
/// <para>
/// This type is thread-safe under the following condition: No two threads attempt to call either
/// <see cref="ReceiveAsync"/> or <see cref="SendAsync"/> simultaneously. Different threads may call each method, but the same method
/// <see cref="ExecuteAsync"/> or <see cref="SendAsync"/> simultaneously. Different threads may call each method, but the same method
/// cannot be re-entered while it is being run in a different thread.
/// </para>
/// <para>
/// The general pattern of having a single thread running <see cref="ReceiveAsync"/> and a separate thread running <see cref="SendAsync"/> will
/// The general pattern of having a single thread running <see cref="ExecuteAsync"/> and a separate thread running <see cref="SendAsync"/> will
/// be thread-safe, as each method interacts with completely separate state.
/// </para>
/// </remarks>

View File

@ -1,6 +1,6 @@
{
"version": "0.1.0-*",
"description": "WebSockets client and server components.",
"description": "Low-allocation Push-oriented WebSockets based on Channels",
"packOptions": {
"repository": {
@ -18,10 +18,10 @@
"nowarn": [
"CS1591"
],
"xmlDoc": true
"xmlDoc": true,
"allowUnsafe": true
},
"description": "Low-allocation Push-oriented WebSockets based on Channels",
"dependencies": {
"Channels": "0.2.0-beta-*",
"Channels.Text.Primitives": "0.2.0-beta-*",