Skip to content

Instantly share code, notes, and snippets.

@guitarrapc
Created November 9, 2020 07:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save guitarrapc/bb4aaf22dea43d9a82613dfa1d520f59 to your computer and use it in GitHub Desktop.
Save guitarrapc/bb4aaf22dea43d9a82613dfa1d520f59 to your computer and use it in GitHub Desktop.
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="ConsoleAppFramework" Version="2.4.0" />
<PackageReference Include="MagicOnion" Version="4.0.0-preview.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\EchoGrpcMagicOnion.Shared\EchoGrpcMagicOnion.Shared.csproj" />
</ItemGroup>
</Project>
using ConsoleAppFramework;
using EchoGrpcMagicOnion.Shared;
using Grpc.Core;
using Grpc.Net.Client;
using MagicOnion.Client;
using Microsoft.Extensions.Hosting;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace EchoGrpcMagicOnion.Client
{
class Program : ConsoleAppBase, IMyHubReceiver
{
static async Task Main(string[] args)
{
// -- Echo
// local
//args = new[] {
// "Echo",
// "-hostPort",
// "http://127.0.0.1:5000",
// "-message",
// "echo",
// "-H",
// "x-pod-name: echo-grpc-0",
// "-verbose",
// "true"
//};
// -- Stream
// local
//args = new[] {
// "Stream",
// "-hostPort",
// "http://127.0.0.1:5000",
// "-roomName",
// "A",
// "-userName",
// "hoge",
// "-H",
// "x-pod-name: echo-grpc-0"
//};
// --readiness
//args = "Readiness -hostPort http://127.0.0.1:5000".Split(" ");
await Host.CreateDefaultBuilder()
.RunConsoleAppFrameworkAsync<Program>(args);
}
[Command("Echo")]
public async Task Echo(string hostPort, string message, [Option("H")]string headers, [Option("v")]bool verbose = false)
{
// under .NET Core 3.x: https://docs.microsoft.com/ja-jp/aspnet/core/grpc/troubleshoot?view=aspnetcore-3.1#call-insecure-grpc-services-with-net-core-client
AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);
await Task.Delay(TimeSpan.FromSeconds(3));
var channel = GrpcChannel.ForAddress(hostPort);
var client = MagicOnionClient.Create<IEchoService>(channel, new IClientFilter[]
{
new AppendHeaderFilter(headers),
new ResponseHandlingFilter(verbose),
});
try
{
var res = await client.EchoAsync(message);
Console.WriteLine(res);
}
catch (Exception ex)
{
Console.WriteLine($"{ex.Message} {ex.StackTrace}");
}
}
[Command("Stream")]
public async Task Stream(string hostPort, string roomName, string userName, [Option("H")]string headers)
{
// under .NET Core 3.x: https://docs.microsoft.com/ja-jp/aspnet/core/grpc/troubleshoot?view=aspnetcore-3.1#call-insecure-grpc-services-with-net-core-client
AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);
await Task.Delay(TimeSpan.FromSeconds(3));
var channel = GrpcChannel.ForAddress(hostPort);
var options = new CallOptions();
if (!string.IsNullOrEmpty(headers))
{
var metadata = new Metadata();
foreach (var headerItem in headers.Split(','))
{
var splitHeader = headerItem.Split(':');
var headerKey = splitHeader[0].Trim();
var headerValue = splitHeader[1].Trim();
metadata.Add(headerKey, headerValue);
}
options = options.WithHeaders(metadata);
}
await ConnectAndLeave(channel, roomName, userName, TimeSpan.FromSeconds(2), options);
}
[Command("Readiness")]
public async Task Readiness(string hostPort)
{
// under .NET Core 3.x: https://docs.microsoft.com/ja-jp/aspnet/core/grpc/troubleshoot?view=aspnetcore-3.1#call-insecure-grpc-services-with-net-core-client
AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);
var channel = GrpcChannel.ForAddress(hostPort);
var client = MagicOnionClient.Create<IHealthzService>(channel);
await client.Readiness();
}
// StreamingHub
IMyHub _hubClient;
public async Task ConnectAndLeave(GrpcChannel channel, string roomName, string userName, TimeSpan delay, CallOptions option)
{
try
{
await ConnectAsync(channel, roomName, userName, option);
await EchoAsync("echo1");
await EchoAsync("echo2");
await EchoAsync("echo3");
await Task.Delay(delay);
await LeaveAsync();
}
finally
{
await _hubClient.DisposeAsync();
await _hubClient.WaitForDisconnect();
await channel.ShutdownAsync();
}
}
public async Task ConnectAsync(GrpcChannel channel, string roomName, string userName, CallOptions option)
{
_hubClient = StreamingHubClient.Connect<IMyHub, IMyHubReceiver>(channel, this, option: option);
var roomPlayers = await _hubClient.JoinAsync(roomName, userName);
foreach (var player in roomPlayers)
{
(this as IMyHubReceiver).OnJoin(player);
}
}
public Task LeaveAsync()
{
return _hubClient.LeaveAsync();
}
public Task<string> EchoAsync(string message)
{
return _hubClient.EchoAsync(message);
}
public void OnJoin(Player player)
{
}
public void OnLeave(Player player)
{
}
public void OnEcho(string message)
{
Console.WriteLine(message);
}
// filters
public class AppendHeaderFilter : IClientFilter
{
private readonly string _headers;
public AppendHeaderFilter(string headers)
{
_headers = headers;
}
public async ValueTask<ResponseContext> SendAsync(RequestContext context, Func<RequestContext, ValueTask<ResponseContext>> next)
{
if (!string.IsNullOrEmpty(_headers))
{
var header = context.CallOptions.Headers;
foreach (var headerItem in _headers.Split(','))
{
var splitHeader = headerItem.Split(':');
var headerKey = splitHeader[0].Trim();
var headerValue = splitHeader[1].Trim();
header.Add(headerKey, headerValue);
}
}
return await next(context);
}
}
public class ResponseHandlingFilter : IClientFilter
{
private readonly bool _verbose;
public ResponseHandlingFilter(bool verbose)
{
_verbose = verbose;
}
public async ValueTask<ResponseContext> SendAsync(RequestContext context, Func<RequestContext, ValueTask<ResponseContext>> next)
{
// capture request metadata
var requestHeaders = context.CallOptions.Headers;
var response = await next(context);
var content = await response.GetResponseAs<string>();
// request metadata
if (_verbose)
{
Console.WriteLine("Request headers to send:");
foreach (var requestHeader in requestHeaders)
{
Console.WriteLine($"{requestHeader.Key}: {requestHeader.Value}");
}
Console.WriteLine();
}
// response headers
if (_verbose)
{
Console.WriteLine("Response headers received:");
var responseHeaders = await response.ResponseHeadersAsync;
if (!responseHeaders.Any())
{
Console.WriteLine("(empty)");
}
else
{
foreach (var responseHeader in responseHeaders)
{
Console.WriteLine($"{responseHeader.Key}: {responseHeader.Value}");
}
}
Console.WriteLine();
}
// contents
if (_verbose)
{
Console.WriteLine("Response contents:");
Console.WriteLine("{");
Console.WriteLine($" content: {content}");
Console.WriteLine("}");
Console.WriteLine();
}
// response trailers
if (_verbose)
{
Console.WriteLine("Response trailers received:");
var responseTrailers = response.GetTrailers();
if (!responseTrailers.Any())
{
Console.WriteLine("(empty)");
}
else
{
foreach (var responseTrailer in responseTrailers)
{
Console.WriteLine($"{responseTrailer.Key}: {responseTrailer.Value}");
}
}
Console.WriteLine();
}
return response;
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment