diff --git a/.gitignore b/.gitignore index 894a44cc..57a8c6a4 100644 --- a/.gitignore +++ b/.gitignore @@ -102,3 +102,24 @@ venv.bak/ # mypy .mypy_cache/ + +# Visual Studio +.vs/ +.vscode/ + +# CSharp +[Oo]bj/ +[Dd]ebug/ +[Rr]elease/ +[Pp]roperties/ +*.dll +*.exe +appsettings.json +appsettings.*.json + +# Certificate files +*.cer +*.pfx + + + diff --git a/.vscode/settings.json b/.vscode/settings.json index 56422821..663d2eb0 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,4 @@ { - "workbench.colorCustomizations": {} + "workbench.colorCustomizations": {}, + "python.pythonPath": "C:\\Users\\shbanerj\\.conda\\envs\\py-azurefunctions\\python.exe" } \ No newline at end of file diff --git a/investigations/DotNetGrpcClient/DotNetGrpcClient.csproj b/investigations/DotNetGrpcClient/DotNetGrpcClient.csproj new file mode 100644 index 00000000..b9261141 --- /dev/null +++ b/investigations/DotNetGrpcClient/DotNetGrpcClient.csproj @@ -0,0 +1,19 @@ + + + + Exe + netcoreapp3.0 + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + diff --git a/investigations/DotNetGrpcClient/Program.cs b/investigations/DotNetGrpcClient/Program.cs new file mode 100644 index 00000000..a8d9e08c --- /dev/null +++ b/investigations/DotNetGrpcClient/Program.cs @@ -0,0 +1,42 @@ +using System; +using System.Net.Http; +using System.Threading.Tasks; +using DotNetGrpcService; +using Grpc.Net.Client; + +namespace GrpcGreeterClient +{ + class Program + { + static async Task Main(string[] args) + { + // The port number(5001) must match the port of the gRPC server. + + Console.WriteLine("Calling C# Endpoint..."); + await CallEndpoint("http://localhost:5000", true); + + Console.WriteLine("Calling Python Endpoint..."); + await CallEndpoint("http://localhost:50051", true); + + + Console.WriteLine("Press any key to exit..."); + Console.ReadKey(); + } + + static GrpcChannel GetChannel(string grpcEndpointAddress, bool isInsecure = false) + { + AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", isInsecure); + return GrpcChannel.ForAddress(grpcEndpointAddress); + } + + static async Task CallEndpoint(string grpcEndpointAddress, bool isInsecure = false) + { + var channel = GetChannel(grpcEndpointAddress, isInsecure); + var client = new Greeter.GreeterClient(channel); + + var reply = await client.SayHelloAsync( + new HelloRequest { Name = "GreeterClient" }); + Console.WriteLine("Greeting: " + reply.Message); + } + } +} \ No newline at end of file diff --git a/investigations/DotNetGrpcClient/Protos/greet.proto b/investigations/DotNetGrpcClient/Protos/greet.proto new file mode 100644 index 00000000..62060ee9 --- /dev/null +++ b/investigations/DotNetGrpcClient/Protos/greet.proto @@ -0,0 +1,21 @@ +syntax = "proto3"; + +option csharp_namespace = "DotNetGrpcService"; + +package Greet; + +// The greeting service definition. +service Greeter { + // Sends a greeting + rpc SayHello (HelloRequest) returns (HelloReply); +} + +// The request message containing the user's name. +message HelloRequest { + string name = 1; +} + +// The response message containing the greetings. +message HelloReply { + string message = 1; +} diff --git a/investigations/DotNetGrpcService/DotNetGrpcService.csproj b/investigations/DotNetGrpcService/DotNetGrpcService.csproj new file mode 100644 index 00000000..6dbc3bbd --- /dev/null +++ b/investigations/DotNetGrpcService/DotNetGrpcService.csproj @@ -0,0 +1,21 @@ + + + + netcoreapp3.0 + + + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + diff --git a/investigations/DotNetGrpcService/DotNetGrpcService.sln b/investigations/DotNetGrpcService/DotNetGrpcService.sln new file mode 100644 index 00000000..e2331799 --- /dev/null +++ b/investigations/DotNetGrpcService/DotNetGrpcService.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.29316.153 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DotNetGrpcService", "DotNetGrpcService.csproj", "{6D265B48-69E0-4511-9E77-A8B6501AAB48}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotNetGrpcClient", "..\DotNetGrpcClient\DotNetGrpcClient.csproj", "{3E1D7598-32EE-43DC-B9E6-22C3568742FF}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {6D265B48-69E0-4511-9E77-A8B6501AAB48}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6D265B48-69E0-4511-9E77-A8B6501AAB48}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6D265B48-69E0-4511-9E77-A8B6501AAB48}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6D265B48-69E0-4511-9E77-A8B6501AAB48}.Release|Any CPU.Build.0 = Release|Any CPU + {3E1D7598-32EE-43DC-B9E6-22C3568742FF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3E1D7598-32EE-43DC-B9E6-22C3568742FF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3E1D7598-32EE-43DC-B9E6-22C3568742FF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3E1D7598-32EE-43DC-B9E6-22C3568742FF}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {75B6A36C-EF88-4E3A-83FD-5BD41A270F0C} + EndGlobalSection +EndGlobal diff --git a/investigations/DotNetGrpcService/Program.cs b/investigations/DotNetGrpcService/Program.cs new file mode 100644 index 00000000..6f6597c1 --- /dev/null +++ b/investigations/DotNetGrpcService/Program.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Hosting; + +namespace DotNetGrpcService +{ + public class Program + { + public static void Main(string[] args) + { + CreateHostBuilder(args).Build().Run(); + } + + // Additional configuration is required to successfully run gRPC on macOS. + // For instructions on how to configure Kestrel and gRPC clients on macOS, visit https://go.microsoft.com/fwlink/?linkid=2099682 + public static IHostBuilder CreateHostBuilder(string[] args) => + Host.CreateDefaultBuilder(args) + .ConfigureWebHostDefaults(webBuilder => + { + webBuilder.UseStartup(); + }); + } +} diff --git a/investigations/DotNetGrpcService/Protos/greet.proto b/investigations/DotNetGrpcService/Protos/greet.proto new file mode 100644 index 00000000..62060ee9 --- /dev/null +++ b/investigations/DotNetGrpcService/Protos/greet.proto @@ -0,0 +1,21 @@ +syntax = "proto3"; + +option csharp_namespace = "DotNetGrpcService"; + +package Greet; + +// The greeting service definition. +service Greeter { + // Sends a greeting + rpc SayHello (HelloRequest) returns (HelloReply); +} + +// The request message containing the user's name. +message HelloRequest { + string name = 1; +} + +// The response message containing the greetings. +message HelloReply { + string message = 1; +} diff --git a/investigations/DotNetGrpcService/Services/GreeterService.cs b/investigations/DotNetGrpcService/Services/GreeterService.cs new file mode 100644 index 00000000..7d7fc516 --- /dev/null +++ b/investigations/DotNetGrpcService/Services/GreeterService.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Grpc.Core; +using Microsoft.Extensions.Logging; + +namespace DotNetGrpcService +{ + public class GreeterService : Greeter.GreeterBase + { + private readonly ILogger _logger; + public GreeterService(ILogger logger) + { + _logger = logger; + } + + public override Task SayHello(HelloRequest request, ServerCallContext context) + { + return Task.FromResult(new HelloReply + { + Message = "Hello " + request.Name + }); + } + } +} diff --git a/investigations/DotNetGrpcService/Startup.cs b/investigations/DotNetGrpcService/Startup.cs new file mode 100644 index 00000000..d8bf433a --- /dev/null +++ b/investigations/DotNetGrpcService/Startup.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; + +namespace DotNetGrpcService +{ + public class Startup + { + // This method gets called by the runtime. Use this method to add services to the container. + // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 + public void ConfigureServices(IServiceCollection services) + { + services.AddGrpc(); + } + + // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. + public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + { + if (env.IsDevelopment()) + { + app.UseDeveloperExceptionPage(); + } + + app.UseRouting(); + + app.UseEndpoints(endpoints => + { + + endpoints.MapGrpcService(); + + endpoints.MapGet("/", async context => + { + await context.Response.WriteAsync("Communication with gRPC endpoints must be made through a gRPC client. To learn how to create a client, visit: https://go.microsoft.com/fwlink/?linkid=2086909"); + }); + }); + } + } +} diff --git a/investigations/PythonGrpc/greet_client.py b/investigations/PythonGrpc/greet_client.py new file mode 100644 index 00000000..bc4780dd --- /dev/null +++ b/investigations/PythonGrpc/greet_client.py @@ -0,0 +1,26 @@ +import grpc + +import greet_pb2_grpc +import greet_pb2 + + + +def getChannel(grpcEndpointAddress): + return grpc.insecure_channel(grpcEndpointAddress) + +def sendGreetings(grpcChannel): + stub = greet_pb2_grpc.GreeterStub(grpcChannel) + reply = stub.SayHello(greet_pb2.HelloRequest(name='Shashank')) + return reply + +def main(): + print ("Send greetings to C# Server...") + channel = getChannel("localhost:5000") + print(sendGreetings(channel)) + + print ("Send greetings to Python Server...") + channel = getChannel("localhost:50051") + print(sendGreetings(channel)) + +if __name__ == '__main__': + main() diff --git a/investigations/PythonGrpc/greet_pb2.py b/investigations/PythonGrpc/greet_pb2.py new file mode 100644 index 00000000..2bb81b75 --- /dev/null +++ b/investigations/PythonGrpc/greet_pb2.py @@ -0,0 +1,134 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: greet.proto + +import sys +_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1')) +from google.protobuf import descriptor as _descriptor +from google.protobuf import message as _message +from google.protobuf import reflection as _reflection +from google.protobuf import symbol_database as _symbol_database +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor.FileDescriptor( + name='greet.proto', + package='Greet', + syntax='proto3', + serialized_options=_b('\252\002\021DotNetGrpcService'), + serialized_pb=_b('\n\x0bgreet.proto\x12\x05Greet\"\x1c\n\x0cHelloRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\"\x1d\n\nHelloReply\x12\x0f\n\x07message\x18\x01 \x01(\t2=\n\x07Greeter\x12\x32\n\x08SayHello\x12\x13.Greet.HelloRequest\x1a\x11.Greet.HelloReplyB\x14\xaa\x02\x11\x44otNetGrpcServiceb\x06proto3') +) + + + + +_HELLOREQUEST = _descriptor.Descriptor( + name='HelloRequest', + full_name='Greet.HelloRequest', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='name', full_name='Greet.HelloRequest.name', index=0, + number=1, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=22, + serialized_end=50, +) + + +_HELLOREPLY = _descriptor.Descriptor( + name='HelloReply', + full_name='Greet.HelloReply', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='message', full_name='Greet.HelloReply.message', index=0, + number=1, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=52, + serialized_end=81, +) + +DESCRIPTOR.message_types_by_name['HelloRequest'] = _HELLOREQUEST +DESCRIPTOR.message_types_by_name['HelloReply'] = _HELLOREPLY +_sym_db.RegisterFileDescriptor(DESCRIPTOR) + +HelloRequest = _reflection.GeneratedProtocolMessageType('HelloRequest', (_message.Message,), { + 'DESCRIPTOR' : _HELLOREQUEST, + '__module__' : 'greet_pb2' + # @@protoc_insertion_point(class_scope:Greet.HelloRequest) + }) +_sym_db.RegisterMessage(HelloRequest) + +HelloReply = _reflection.GeneratedProtocolMessageType('HelloReply', (_message.Message,), { + 'DESCRIPTOR' : _HELLOREPLY, + '__module__' : 'greet_pb2' + # @@protoc_insertion_point(class_scope:Greet.HelloReply) + }) +_sym_db.RegisterMessage(HelloReply) + + +DESCRIPTOR._options = None + +_GREETER = _descriptor.ServiceDescriptor( + name='Greeter', + full_name='Greet.Greeter', + file=DESCRIPTOR, + index=0, + serialized_options=None, + serialized_start=83, + serialized_end=144, + methods=[ + _descriptor.MethodDescriptor( + name='SayHello', + full_name='Greet.Greeter.SayHello', + index=0, + containing_service=None, + input_type=_HELLOREQUEST, + output_type=_HELLOREPLY, + serialized_options=None, + ), +]) +_sym_db.RegisterServiceDescriptor(_GREETER) + +DESCRIPTOR.services_by_name['Greeter'] = _GREETER + +# @@protoc_insertion_point(module_scope) diff --git a/investigations/PythonGrpc/greet_pb2_grpc.py b/investigations/PythonGrpc/greet_pb2_grpc.py new file mode 100644 index 00000000..cf5f056d --- /dev/null +++ b/investigations/PythonGrpc/greet_pb2_grpc.py @@ -0,0 +1,46 @@ +# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! +import grpc + +import greet_pb2 as greet__pb2 + + +class GreeterStub(object): + """The greeting service definition. + """ + + def __init__(self, channel): + """Constructor. + + Args: + channel: A grpc.Channel. + """ + self.SayHello = channel.unary_unary( + '/Greet.Greeter/SayHello', + request_serializer=greet__pb2.HelloRequest.SerializeToString, + response_deserializer=greet__pb2.HelloReply.FromString, + ) + + +class GreeterServicer(object): + """The greeting service definition. + """ + + def SayHello(self, request, context): + """Sends a greeting + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + +def add_GreeterServicer_to_server(servicer, server): + rpc_method_handlers = { + 'SayHello': grpc.unary_unary_rpc_method_handler( + servicer.SayHello, + request_deserializer=greet__pb2.HelloRequest.FromString, + response_serializer=greet__pb2.HelloReply.SerializeToString, + ), + } + generic_handler = grpc.method_handlers_generic_handler( + 'Greet.Greeter', rpc_method_handlers) + server.add_generic_rpc_handlers((generic_handler,)) diff --git a/investigations/PythonGrpc/greet_server.py b/investigations/PythonGrpc/greet_server.py new file mode 100644 index 00000000..825ea02f --- /dev/null +++ b/investigations/PythonGrpc/greet_server.py @@ -0,0 +1,24 @@ +from concurrent import futures +import grpc + +import greet_pb2_grpc +import greet_pb2 + +class GreetServer (greet_pb2_grpc.GreeterServicer): + + def SayHello(self, request, context): + print(f'Received client request from {request.name}') + return greet_pb2.HelloReply(message='Hello ' + request.name) + +def serve(): + server = grpc.server(futures.ThreadPoolExecutor(max_workers=10)) + greet_pb2_grpc.add_GreeterServicer_to_server(GreetServer(), server) + print('Starting gRPC Server on port 50051') + server.add_insecure_port('[::]:50051') + server.start() + print('Started. Waiting for client connections...') + server.wait_for_termination() + + +if __name__ == '__main__': + serve() \ No newline at end of file