Beispiel #1
0
 public GrpcServer(GrpcServerBuilder builder)
 {
     _builder = builder;
     _options = builder.Options ?? throw new ArgumentNullException("GrpcServerOption cannot be null");
     _server  = new Server();
     _server.Ports.Add(new ServerPort(_options.Host, _options.Port, ServerCredentials.Insecure));
 }
Beispiel #2
0
        public List <ClassDescripter> GenerateGrpcProxy(GrpcServerOptions options, CodeBuilder codeBuilder = null)
        {
            if (codeBuilder == null)
            {
                codeBuilder = CodeBuilder.Default;
            }
            var implInterfaceTypes  = options.GetKServicers();
            var classDescripterList = new List <ClassDescripter>();
            var protoMessageCode    = new StringBuilder();
            var protoServiceCode    = new StringBuilder();

            foreach (Type service in implInterfaceTypes)
            {
                var bindServicesCode = new StringBuilder("return ServerServiceDefinition.CreateBuilder()\n");
                protoServiceCode.AppendLine($"service {service.Name} {{");
                var @class     = this.GenerateGrpcService(service);
                var interfaces = service.GetInterfaces();
                foreach (var method in service.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly))
                {
                    if (method.CustomAttributes.FirstOrDefault(p => p.AttributeType == typeof(NotGrpcMethodAttribute)) != null)
                    {
                        continue;
                    }
                    var parameters = RpcParameterInfo.Convert(method.GetParameters());
                    if (parameters.Count == 0)
                    {
                        var emptyMessageType = typeof(EmptyMessage);
                        parameters.Add(new RpcParameterInfo()
                        {
                            Name          = emptyMessageType.Name,
                            ParameterType = emptyMessageType,
                            IsEmpty       = true
                        });
                    }

                    @class = GenerateGrpcMethod(@class, method, parameters[0], interfaces);
                    GenerateGrpcCallCode(method, parameters[0], options.NamespaceName, codeBuilder, ref bindServicesCode);
                    GenerateGrpcCallCodeForOldVersion(method, parameters[0], options.NamespaceName, options.ServiceName, codeBuilder, ref bindServicesCode);
                    if (options.IsGeneralProtoFile)
                    {
                        GenerateProtoCode(method, parameters[0], ref protoServiceCode, ref protoMessageCode);
                    }
                }
                bindServicesCode.AppendLine(".Build();");
                protoServiceCode.AppendLine();
                protoServiceCode.AppendLine("}");
                @class.CreateMember(new MethodDescripter("BindServices", false).SetCode(bindServicesCode.ToString()).SetReturn("ServerServiceDefinition").SetAccess(AccessType.Public));
                codeBuilder.AddAssemblyRefence(Assembly.GetExecutingAssembly())
                .AddAssemblyRefence(typeof(ServerServiceDefinition).Assembly)
                .AddAssemblyRefence(typeof(ServerServiceDefinition).Assembly)
                .AddAssemblyRefence(typeof(ServiceProviderServiceExtensions).Assembly)
                .AddAssemblyRefence(typeof(Console).Assembly)
                .AddAssemblyRefence(service.Assembly);
                codeBuilder.CreateClass(@class);
                classDescripterList.Add(@class);
            }
            if (options.IsGeneralProtoFile)
            {
                if (string.IsNullOrWhiteSpace(options.PackageName))
                {
                    options.PackageName = options.NamespaceName;
                }

                var stringBuilder = new StringBuilder();
                stringBuilder.AppendLine("syntax = \"proto3\";");
                stringBuilder.AppendLine($@"option csharp_namespace = ""{options.NamespaceName}"";");
                stringBuilder.AppendLine($"package {options.PackageName};\n");
                stringBuilder.Append(protoServiceCode);
                stringBuilder.AppendLine();
                var messageCode = protoMessageCode.ToString();
                if (messageCode.Contains(".bcl."))
                {
                    protoMessageCode.Replace(".bcl.", "");
                    protoMessageCode.AppendLine(Bcl.Proto);
                }
                stringBuilder.Append(protoMessageCode);
                var path = $"{Environment.CurrentDirectory}/{options.NamespaceName}.proto";
                if (File.Exists(path))
                {
                    File.Delete(path);
                }

                File.WriteAllText(path, stringBuilder.ToString());
                _messages = null;
            }
            return(classDescripterList);
        }
Beispiel #3
0
        public ClassDescripter GenerateGrpcProxy(
            GrpcServerOptions options, CodeBuilder codeBuilder = null)
        {
            if (codeBuilder == null)
            {
                codeBuilder = CodeBuilder.Default;
            }

            var types = RefelectionHelper.GetImplInterfaceTypes(
                typeof(IMessagingServicer), true, options.GetScanAssemblies());

            var codeClass = new ClassDescripter("GrpcService", "Kadder")
                            .SetAccess(AccessType.Public)
                            .SetBaseType("IGrpcServices")
                            .AddUsing("using Grpc.Core;")
                            .AddUsing("using System.Threading.Tasks;")
                            .AddUsing("using Kadder;")
                            .AddUsing("using Kadder.Utilies;")
                            .AddUsing("using Microsoft.Extensions.DependencyInjection;")
                            .CreateFiled(
                new FieldDescripter("_binarySerializer")
                .SetAccess(AccessType.PrivateReadonly)
                .SetType(typeof(IBinarySerializer)),
                new FieldDescripter("_messageServicer")
                .SetAccess(AccessType.PrivateReadonly)
                .SetType(typeof(GrpcMessageServicer)))
                            .CreateConstructor(
                new ConstructorDescripter("GrpcService")
                .SetCode("_binarySerializer=GrpcServerBuilder.ServiceProvider.GetService<IBinarySerializer>();\n_messageServicer=GrpcServerBuilder.ServiceProvider.GetService<GrpcMessageServicer>();")
                .SetAccess(AccessType.Public));

            var bindServicesCode = new StringBuilder("return ServerServiceDefinition.CreateBuilder()\n");
            var protoServiceCode = new StringBuilder($"service {options.ServiceName} {{");
            var protoMessageCode = new StringBuilder();

            protoServiceCode.AppendLine();
            foreach (var item in types)
            {
                var baseInterfaces = item.GetInterfaces();
                foreach (var method in item.GetMethods())
                {
                    if (method.CustomAttributes.FirstOrDefault(p => p.AttributeType == typeof(NotGrpcMethodAttribute)) != null)
                    {
                        continue;
                    }
                    var parameters = method.GetParameters();
                    if (parameters.Length != 1)
                    {
                        continue;
                    }
                    CreateCallCode(method, parameters[0], baseInterfaces);
                    CreateGrpcCallCode(method, parameters[0]);

                    if (options.IsGeneralProtoFile)
                    {
                        CreateProtoCode(method, parameters[0]);
                    }
                }
            }
            bindServicesCode.AppendLine(".Build();");
            codeClass.CreateMember(
                new MethodDescripter("BindServices")
                .SetCode(bindServicesCode.ToString())
                .SetReturn("ServerServiceDefinition")
                .SetAccess(AccessType.Public));
            codeBuilder.AddAssemblyRefence(Assembly.GetExecutingAssembly().Location)
            .AddAssemblyRefence(typeof(ServerServiceDefinition).Assembly.Location)
            .AddAssemblyRefence(typeof(ServerServiceDefinition).Assembly.Location)
            .AddAssemblyRefence(typeof(ServiceProviderServiceExtensions).Assembly.Location);

            if (options.IsGeneralProtoFile)
            {
                protoServiceCode.Append("\n}\n");
                var protoStr = new StringBuilder();
                protoStr.AppendLine(@"syntax = ""proto3"";");
                protoStr.AppendLine($@"option csharp_namespace = ""{options.NamespaceName}"";");
                protoStr.AppendLine($"package {options.PackageName};\n");
                protoStr.Append(protoServiceCode);
                protoStr.AppendLine();
                protoStr.Append(protoMessageCode);
                var fileName = $"{Environment.CurrentDirectory}/{options.NamespaceName}.proto";
                if (File.Exists(fileName))
                {
                    File.Delete(fileName);
                }
                File.WriteAllText(fileName, protoStr.ToString());
                _messages = null;
            }

            codeBuilder.CreateClass(codeClass);

            return(codeClass);

            void CreateCallCode(MethodInfo method, ParameterInfo parameter, Type[] baseInterfaces)
            {
                var requestName = GetRequestName(method);

                codeClass
                .CreateMember(
                    new MethodDescripter($"{method.Name.Replace("Async", "")}", true)
                    .AppendCode(
                        $@"request.SetTypeFullName(""{requestName}"");
                            return await _messageServicer.ProcessAsync<{parameter.ParameterType.Name},{GetMethodReturn(method.ReturnType).Name}>(request,context);")
                    .SetReturn($"Task<{GetMethodReturn(method.ReturnType).Name}>")
                    .SetParams(
                        new ParameterDescripter(parameter.ParameterType.Name, "request"),
                        new ParameterDescripter("ServerCallContext", "context"))
                    .SetAccess(AccessType.Public))
                .AddUsing($"using {parameter.ParameterType.Namespace};")
                .AddUsing($"using {GetMethodReturn(method.ReturnType).Namespace};");
            }

            void CreateGrpcCallCode(MethodInfo method, ParameterInfo parameter)
            {
                bindServicesCode.AppendLine($@".AddMethod(new Method<{parameter.ParameterType.Name},{GetMethodReturn(method.ReturnType).Name}>(
                                            MethodType.Unary,
                                            ""{options.NamespaceName}.{options.ServiceName}"",
                                            ""{method.Name.Replace("Async", "")}"",
                                            new Marshaller<{parameter.ParameterType.Name}>(
                                                _binarySerializer.Serialize,
                                                _binarySerializer.Deserialize<{parameter.ParameterType.Name}>
                                            ),
                                            new Marshaller<{GetMethodReturn(method.ReturnType).Name}>(
                                                _binarySerializer.Serialize,
                                                _binarySerializer.Deserialize<{GetMethodReturn(method.ReturnType).Name}>)
                                            ),
                                        {method.Name.Replace("Async", "")})");
                codeBuilder.AddAssemblyRefence(parameter.ParameterType.Assembly.Location)
                .AddAssemblyRefence(GetMethodReturn(method.ReturnType).Assembly.Location);
            }

            void CreateProtoCode(MethodInfo method, ParameterInfo parameter)
            {
                protoServiceCode.AppendLine();
                protoServiceCode.AppendLine($"\trpc {method.Name.Replace("Async", "")}({parameter.ParameterType.Name}) returns({GetMethodReturn(method.ReturnType).Name});");
                if (!_messages.Contains(parameter.ParameterType.Name))
                {
                    protoMessageCode.AppendLine(CreateProtoMessageCode(parameter.ParameterType));
                    _messages.Add(parameter.ParameterType.Name);
                }
                if (!_messages.Contains(GetMethodReturn(method.ReturnType).Name))
                {
                    protoMessageCode.AppendLine(CreateProtoMessageCode(GetMethodReturn(method.ReturnType)));
                    _messages.Add(GetMethodReturn(method.ReturnType).Name);
                }
            }

            string CreateProtoMessageCode(Type messageType)
            {
                //    Serializer.GetProto(messageType);

                if (_messages.Contains(messageType.Name))
                {
                    return("");
                }

                var messageCode = new StringBuilder($"message {messageType.Name} {{");
                var enumCode    = new StringBuilder();
                var refenceCode = new StringBuilder();

                messageCode.AppendLine();
                var properties      = messageType.GetProperties().Where(p => p.DeclaringType == messageType);
                var isNeedAutoIndex = !(properties.FirstOrDefault(p => p.GetCustomAttribute(typeof(ProtoMemberAttribute)) != null) != null);
                int index           = 1;

                foreach (var item in properties.OrderBy(p => p.Name, new ProtoPropertyCompare()))
                {
                    if (item.GetCustomAttribute(typeof(ProtoIgnoreAttribute)) != null)
                    {
                        continue;
                    }
                    if (!isNeedAutoIndex)
                    {
                        var memberAttribute = item.GetCustomAttribute <ProtoMemberAttribute>();
                        if (memberAttribute == null)
                        {
                            continue;
                        }
                        messageCode.Append($"\t{GetFiledType(item.PropertyType)} {item.Name} = {memberAttribute.Tag};\n");
                    }
                    else
                    {
                        if (item.GetCustomAttribute(typeof(ProtoIgnoreAttribute)) != null)
                        {
                            continue;
                        }
                        messageCode.Append($"\t{GetFiledType(item.PropertyType)} {item.Name} = {index};\n");
                        index++;
                    }

                    if (!item.PropertyType.IsGenericType && string.Equals(item.PropertyType.BaseType.Name.ToLower(), "enum") && !_messages.Contains(item.PropertyType.Name))
                    {
                        GeneralEnumCode(item.PropertyType);
                        _messages.Add(item.PropertyType.Name);
                    }

                    if (item.PropertyType.IsClass && item.PropertyType.GetCustomAttribute <ProtoContractAttribute>() != null)
                    {
                        refenceCode.AppendLine(CreateProtoMessageCode(item.PropertyType));
                    }
                    if (item.PropertyType.IsArray && item.PropertyType.GetElementType().GetCustomAttribute <ProtoContractAttribute>() != null)
                    {
                        refenceCode.AppendLine(CreateProtoMessageCode(item.PropertyType.GetElementType()));
                    }
                }
                _messages.Add(messageType.Name);
                return(messageCode.Append("}\n\n").Append(enumCode).Append(refenceCode).ToString());

                string GetFiledType(Type type)
                {
                    switch (type.Name.ToLower())
                    {
                    case "int": return("int32");

                    case "int32": return("int32");

                    case "int64": return("int64");

                    case "long": return("int64");

                    case "string": return("string");

                    case "datetime": return("bcl.DateTime");

                    case "bool": return("bool");

                    case "boolean": return("bool");

                    case "double": return("double");

                    case "float": return("float");

                    default:
                        if (type.Name.Contains("[]"))
                        {
                            return($"repeated {GetFiledType(type.GetElementType())}");
                        }
                        return(type.Name);
                    }
                }

                void GeneralEnumCode(Type type)
                {
                    var zeroCode      = "\tZERO = 0;";
                    var enumFiledCode = new StringBuilder();
                    var hasDefault    = false;

                    foreach (var item in type.GetFields())
                    {
                        if (item.Name.Equals("value__"))
                        {
                            continue;
                        }
                        var values = (int)item.GetValue(null);
                        if (values <= 0)
                        {
                            hasDefault = true;
                        }
                        enumFiledCode.AppendLine($"\t{item.Name} = {values};");
                    }
                    if (hasDefault)
                    {
                        enumCode.Append($"enum {type.Name}{{\n{enumFiledCode}}}\n");
                    }
                    else
                    {
                        enumCode.Append($"enum {type.Name}{{\n{zeroCode}\n{enumFiledCode}}}\n");
                    }
                }
            }
        }