public ServerStreaming(ServiceDetails svc, MethodDescriptor desc) : base(svc, desc)
 {
     ApiCallTyp         = Typ.Generic(typeof(ApiServerStreamingCall <,>), RequestTyp, ResponseTyp);
     AbstractStreamTyp  = Typ.Nested(svc.ClientAbstractTyp, $"{SyncMethodName}Stream");
     ImplStreamTyp      = Typ.Nested(svc.ClientImplTyp, $"{SyncMethodName}StreamImpl");
     AsyncEnumeratorTyp = Typ.Generic(typeof(AsyncResponseStream <>), ResponseTyp);
 }
        public ServiceDetails(ProtoCatalog catalog, string ns, ServiceDescriptor desc, ServiceConfig grpcServiceConfig)
        {
            Catalog            = catalog;
            Namespace          = ns;
            ProtoPackage       = desc.File.Package;
            DocLines           = desc.Declaration.DocLines().ToList();
            SnippetsNamespace  = $"{ns}.Snippets";
            UnitTestsNamespace = $"{ns}.Tests";
            // Must come early; used by `MethodDetails.Create()`
            MethodGrpcConfigsByName = grpcServiceConfig?.MethodConfig
                                      .SelectMany(conf => conf.Name.Select(name => (name, conf)))
                                      .Where(x => x.name.Service == desc.FullName)
                                      .ToImmutableDictionary(x => $"{x.name.Service}/{x.name.Method}", x => x.conf) ??
                                      ImmutableDictionary <string, MethodConfig> .Empty;
            ServiceFullName   = desc.FullName;
            ServiceName       = desc.Name;
            DocumentationName = desc.Name; // TODO: There may be a more suitable name than this.
            ProtoTyp          = Typ.Manual(ns, desc.Name);
            GrpcClientTyp     = Typ.Nested(ProtoTyp, $"{desc.Name}Client");
            SettingsTyp       = Typ.Manual(ns, $"{desc.Name}Settings");
            BuilderTyp        = Typ.Manual(ns, $"{desc.Name}ClientBuilder");
            ClientAbstractTyp = Typ.Manual(ns, $"{desc.Name}Client");
            ClientImplTyp     = Typ.Manual(ns, $"{desc.Name}ClientImpl");
            DefaultHost       = desc.GetExtension(ClientExtensions.DefaultHost) ?? "";
            DefaultPort       = 443; // Hardcoded; this is not specifiable by proto annotation.
            var oauthScopes = desc.GetExtension(ClientExtensions.OauthScopes);

            DefaultScopes         = string.IsNullOrEmpty(oauthScopes) ? Enumerable.Empty <string>() : oauthScopes.Split(',', ' ');
            Methods               = desc.Methods.Select(x => MethodDetails.Create(this, x)).ToList();
            SnippetsTyp           = Typ.Manual(SnippetsNamespace, $"Generated{desc.Name}ClientSnippets");
            StandaloneSnippetsTyp = Typ.Manual(SnippetsNamespace, $"Generated{desc.Name}ClientStandaloneSnippets");
            SnippetsClientName    = $"{desc.Name.ToLowerCamelCase()}Client";
            UnitTestsTyp          = Typ.Manual(UnitTestsNamespace, $"Generated{desc.Name}ClientTest");
            NonStandardLro        = NonStandardLroDetails.ForService(desc);
        }
 public ResourceClassBuilder(SourceFileContext ctx, ResourceDetails.Definition def)
 {
     _ctx = ctx;
     _def = def;
     ResourceNameTypeTyp = Typ.Nested(def.ResourceNameTyp, "ResourceNameType", isEnum: true);
     PatternDetails      = _def.Patterns.Where(x => !x.IsWildcard).Select(x => new PatternDetails(ctx, def, x)).ToList();
 }
 public ClientStreaming(ServiceDetails svc, MethodDescriptor desc) : base(svc, desc)
 {
     ApiCallTyp            = Typ.Generic(typeof(ApiClientStreamingCall <,>), RequestTyp, ResponseTyp);
     AbstractStreamTyp     = Typ.Nested(svc.ClientAbstractTyp, $"{SyncMethodName}Stream");
     ImplStreamTyp         = Typ.Nested(svc.ClientImplTyp, $"{SyncMethodName}StreamImpl");
     StreamingSettingsName = $"{desc.Name}StreamingSettings";
     ModifyStreamingCallSettingsMethodName = $"Modify_{RequestTyp.Name}CallSettings";
     ModifyStreamingRequestMethodName      = $"Modify_{RequestTyp.Name}Request";
 }
Beispiel #5
0
        public EnumDeclarationSyntax GenerateDeclaration(SourceFileContext ctx)
        {
            var declaration = Enum(Modifier.Public, Typ.Nested(ctx.CurrentTyp, TypeName, isEnum: true))
                                  (Members.Select(m => m.GenerateDeclaration(ctx)).ToArray());

            if (Description is string description)
            {
                declaration = declaration.WithXmlDoc(XmlDoc.Summary(description));
            }
            return(declaration);
        }
        public ResourceModel(PackageModel package, ResourceModel parent, string name, RestResource discoveryResource)
        {
            Name         = name;
            PropertyName = name.ToMemberName();
            string className = name.ToClassName(package, parent?.Typ.Name) + "Resource";

            Typ = parent is null?Typ.Manual(package.PackageName, className) : Typ.Nested(parent.Typ, className);

            Subresources = discoveryResource.Resources.ToReadOnlyList(pair => new ResourceModel(package, this, pair.Key, pair.Value));
            Methods      = discoveryResource.Methods.ToReadOnlyList(pair => new MethodModel(package, this, pair.Key, pair.Value));
        }
Beispiel #7
0
        public MethodModel(PackageModel package, ResourceModel resource, string name, RestMethod restMethod)
        {
            Package         = package;
            Resource        = resource;
            Name            = name;
            PascalCasedName = name.ToClassName(package, resource.ClassName);
            ParentTyp       = resource?.Typ ?? package.ServiceTyp;
            RequestTyp      = Typ.Nested(ParentTyp, $"{PascalCasedName}Request");
            BodyTyp         = restMethod.Request is object?package.GetDataModelByReference(restMethod.Request.Ref__).GetTypForReference() : null;

            ResponseTyp = restMethod.Response is object?package.GetDataModelByReference(restMethod.Response.Ref__).GetTypForReference() : Typ.Of <string>();

            _restMethod = restMethod;
        }
        public ServiceDetails(ProtoCatalog catalog, string ns, ServiceDescriptor desc, ServiceConfig grpcServiceConfig, Service serviceConfig, ApiTransports transports)
        {
            Catalog            = catalog;
            Namespace          = ns;
            ProtoPackage       = desc.File.Package;
            PackageVersion     = ProtoPackage.Split('.').FirstOrDefault(part => ApiVersionPattern.IsMatch(part));
            DocLines           = desc.Declaration.DocLines().ToList();
            SnippetsNamespace  = $"{ns}.Snippets";
            UnitTestsNamespace = $"{ns}.Tests";
            // Must come early; used by `MethodDetails.Create()`
            MethodGrpcConfigsByName = grpcServiceConfig?.MethodConfig
                                      .SelectMany(conf => conf.Name.Select(name => (name, conf)))
                                      .Where(x => x.name.Service == desc.FullName)
                                      .ToImmutableDictionary(x => $"{x.name.Service}/{x.name.Method}", x => x.conf) ??
                                      ImmutableDictionary <string, MethodConfig> .Empty;
            ServiceFullName   = desc.FullName;
            ServiceName       = desc.Name;
            DocumentationName = desc.Name; // TODO: There may be a more suitable name than this.
            ProtoTyp          = Typ.Manual(ns, desc.Name);
            GrpcClientTyp     = Typ.Nested(ProtoTyp, $"{desc.Name}Client");
            SettingsTyp       = Typ.Manual(ns, $"{desc.Name}Settings");
            BuilderTyp        = Typ.Manual(ns, $"{desc.Name}ClientBuilder");
            ClientAbstractTyp = Typ.Manual(ns, $"{desc.Name}Client");
            ClientImplTyp     = Typ.Manual(ns, $"{desc.Name}ClientImpl");
            DefaultHost       = desc.GetExtension(ClientExtensions.DefaultHost) ?? "";
            // We need to account for regional default endpoints like "us-east1-pubsub.googleapis.com"
            DefaultHostServiceName = DefaultHost
                                     .Split('.', StringSplitOptions.RemoveEmptyEntries).FirstOrDefault()
                                     ?.Split('-', StringSplitOptions.RemoveEmptyEntries).LastOrDefault();
            DefaultPort = 443; // Hardcoded; this is not specifiable by proto annotation.
            var oauthScopes = desc.GetExtension(ClientExtensions.OauthScopes);

            DefaultScopes      = string.IsNullOrEmpty(oauthScopes) ? Enumerable.Empty <string>() : oauthScopes.Split(',', ' ');
            Methods            = desc.Methods.Select(x => MethodDetails.Create(this, x)).ToList();
            ServiceSnippetsTyp = Typ.Manual(SnippetsNamespace, $"AllGenerated{desc.Name}ClientSnippets");
            SnippetsTyp        = Typ.Manual(SnippetsNamespace, $"Generated{desc.Name}ClientSnippets");
            SnippetsClientName = $"{desc.Name.ToLowerCamelCase()}Client";
            UnitTestsTyp       = Typ.Manual(UnitTestsNamespace, $"Generated{desc.Name}ClientTest");
            NonStandardLro     = NonStandardLroDetails.ForService(desc);
            Mixins             = serviceConfig?.Apis
                                 .Select(api => AvailableMixins.GetValueOrDefault(api.Name))
                                 .Where(mixin => mixin is object)
                                 // Don't use mixins within the package that contains that mixin.
                                 .Where(mixin => mixin.GapicClientType.Namespace != ns)
                                 .ToList() ?? Enumerable.Empty <MixinDetails>();
            Transports = transports;
        }
Beispiel #9
0
        private static IEnumerable <MemberDeclarationSyntax> LroPartialClasses(SourceFileContext ctx, ServiceDetails svc)
        {
            if (svc.Methods.Any(m => m is MethodDetails.StandardLro))
            {
                // Emit partial class to give access to an LRO operations client.
                var grpcOuterCls = Class(Public | Static | Partial, svc.GrpcClientTyp.DeclaringTyp);
                using (ctx.InClass(grpcOuterCls))
                {
                    var grpcInnerClass = Class(Public | Partial, svc.GrpcClientTyp);
                    using (ctx.InClass(grpcInnerClass))
                    {
                        var callInvoker = Property(Private, ctx.TypeDontCare, "CallInvoker");
                        var opTyp       = ctx.Type <Operations.OperationsClient>();
                        var createOperationsClientMethod = Method(Public | Virtual, opTyp, "CreateOperationsClient")()
                                                           .WithBody(New(opTyp)(callInvoker))
                                                           .WithXmlDoc(
                            XmlDoc.Summary("Creates a new instance of ", opTyp, " using the same call invoker as this client."),
                            XmlDoc.Returns("A new Operations client for the same target as this client.")
                            );
                        grpcInnerClass = grpcInnerClass.AddMembers(createOperationsClientMethod);
                    }
                    grpcOuterCls = grpcOuterCls.AddMembers(grpcInnerClass);
                }
                yield return(grpcOuterCls);
            }

            // Generate partial classes to delegate to other services handling operations
            if (svc.Methods.Any(m => m is MethodDetails.NonStandardLro))
            {
                var operationServices = svc.Methods.OfType <MethodDetails.NonStandardLro>().Select(lro => lro.OperationService).Distinct().ToList();

                // Emit partial class to give access to an LRO operations client.
                var grpcOuterCls = Class(Public | Static | Partial, svc.GrpcClientTyp.DeclaringTyp);
                using (ctx.InClass(grpcOuterCls))
                {
                    var grpcInnerClass = Class(Public | Partial, svc.GrpcClientTyp);
                    using (ctx.InClass(grpcInnerClass))
                    {
                        var callInvoker = Property(Private, ctx.TypeDontCare, "CallInvoker");
                        var opTyp       = ctx.Type <Operations.OperationsClient>();

                        foreach (var operationService in operationServices)
                        {
                            var grpcClient = ctx.Type(Typ.Nested(Typ.Manual(ctx.Namespace, operationService), $"{operationService}Client"));
                            var createOperationsClientMethod = Method(Public | Virtual, opTyp, $"CreateOperationsClientFor{operationService}")()
                                                               .WithBody(grpcClient.Call("CreateOperationsClient")(callInvoker))
                                                               .WithXmlDoc(
                                XmlDoc.Summary("Creates a new instance of ", opTyp, $" using the same call invoker as this client, delegating to {operationService}."),
                                XmlDoc.Returns("A new Operations client for the same target as this client.")
                                );
                            grpcInnerClass = grpcInnerClass.AddMembers(createOperationsClientMethod);
                        }
                    }
                    grpcOuterCls = grpcOuterCls.AddMembers(grpcInnerClass);
                }
                yield return(grpcOuterCls);
            }

            // Generate partial classes for the operation-handling services
            if (svc.NonStandardLro is ServiceDetails.NonStandardLroDetails lroDetails)
            {
                // Emit partial class to give access to an LRO operations client.
                var grpcOuterCls = Class(Public | Static | Partial, svc.GrpcClientTyp.DeclaringTyp);
                using (ctx.InClass(grpcOuterCls))
                {
                    var grpcInnerClass = Class(Public | Partial, svc.GrpcClientTyp);
                    using (ctx.InClass(grpcInnerClass))
                    {
                        var callInvoker                  = Parameter(ctx.Type <CallInvoker>(), "callInvoker");
                        var request                      = Parameter(ctx.TypeDontCare, "request");
                        var response                     = Parameter(ctx.TypeDontCare, "response");
                        var opTyp                        = ctx.Type <Operations.OperationsClient>();
                        var forwardingCallInvoker        = Local(ctx.Type <CallInvoker>(), "forwardingCallInvoker");
                        var createOperationsClientMethod = Method(Internal | Static, opTyp, "CreateOperationsClient")(callInvoker)
                                                           .WithBody(
                            forwardingCallInvoker.WithInitializer(
                                // Note: can't use Typ.Of<ForwardingCallInvoker<GetOperationRequest>> as it's a static class.
                                ctx.Type(Typ.Generic(Typ.Of(typeof(ForwardingCallInvoker <>)), Typ.Of <GetOperationRequest>())).Call("Create")(
                                    callInvoker,
                                    "/google.longrunning.Operations/GetOperation",
                                    Property(Private, ctx.TypeDontCare, $"__Method_{lroDetails.PollingMethod.Name}"),
                                    ctx.Type(lroDetails.PollingRequestTyp).Access("ParseLroRequest"),     // Method group conversion
                                    Lambda(request, response)(response.Call("ToLroResponse")(request.Access("Name")))
                                    )),
                            Return(New(opTyp)(forwardingCallInvoker)))
                                                           .WithXmlDoc(
                            XmlDoc.Summary(
                                "Creates a new instance of ", opTyp, "using the specified call invoker, but ",
                                $"redirecting Google.LongRunning RPCs to {lroDetails.Service.Name} RPCs."),
                            XmlDoc.Returns("A new Operations client for the same target as this client.")
                            );
                        grpcInnerClass = grpcInnerClass.AddMembers(createOperationsClientMethod);
                    }
                    grpcOuterCls = grpcOuterCls.AddMembers(grpcInnerClass);
                }
                yield return(grpcOuterCls);
            }
        }
Beispiel #10
0
        public DataModel(PackageModel package, DataModel parent, string name, JsonSchema schema)
        {
            _schema = schema;
            Name    = name;
            Id      = schema.Id;
            Package = package;
            Parent  = parent;
            // TODO: Move this logic into Naming somehow, but noting that we *don't* escape keywords here. <sigh>
            string className = schema.Id is object && IsArray ? name + "Items" : name;

            className = className.ToUpperCamelCase(upperAfterDigit: null);
            if (className == parent?.Typ.Name)
            {
                className += "Schema";
            }
            Typ = parent is null?Typ.Manual(Package.PackageName + ".Data", className) : Typ.Nested(parent.Typ, className);

            // We may get a JsonSchema for an array as a nested model. Just use the properties from schema.Items for simplicity.
            Properties = GetProperties(schema).ToReadOnlyList(pair => new DataPropertyModel(this, pair.Key, pair.Value));
        }
Beispiel #11
0
        private IEnumerable <MemberDeclarationSyntax> GenerateUploadMembers(SourceFileContext ctx)
        {
            var uploadTyp = Typ.Nested(ctx.CurrentTyp, PascalCasedName + "MediaUpload");

            var baseTypArgument1 = BodyTyp ?? Typ.Of <string>();
            var baseTyp          = _restMethod.Response is object
                                   ?Typ.Generic(Typ.Of(typeof(ResumableUpload <,>)), baseTypArgument1, ResponseTyp)
                                       : Typ.Generic(Typ.Of(typeof(ResumableUpload <>)), baseTypArgument1);

            var uploadCls = Class(Modifier.Public, uploadTyp, ctx.Type(baseTyp))
                            .WithXmlDoc(XmlDoc.Summary($"{PascalCasedName} media upload which supports resumable upload."));

            var parameters         = CreateParameterList(uploadTyp);
            var requiredParameters = parameters
                                     .TakeWhile(p => p.IsRequired)
                                     .Select(p => (param: p, decl: Parameter(ctx.Type(p.Typ), p.CodeParameterName)))
                                     .ToList();

            var insertMethodParameters = new List <ParameterSyntax>();

            if (BodyTyp is object)
            {
                insertMethodParameters.Add(Parameter(ctx.Type(BodyTyp), "body"));
            }
            insertMethodParameters.AddRange(requiredParameters.Select(pair => pair.decl));
            var streamParam = Parameter(ctx.Type <Stream>(), "stream");

            var contentTypeParam = Parameter(ctx.Type <string>(), "contentType");

            insertMethodParameters.Add(streamParam);
            insertMethodParameters.Add(contentTypeParam);

            // This doc comment is common between the method and the constructor.
            var remarks = XmlDoc.Remarks("Considerations regarding ", streamParam, ":",
                                         XmlDoc.BulletListOfItemNodes(
                                             XmlDoc.Item("If ", streamParam, " is seekable, then the stream position will be reset to ", 0, " before reading commences. If ", streamParam, " is not seekable, then it will be read from its current position"),
                                             XmlDoc.Item("Caller is responsible for maintaining the ", streamParam, " open until the upload is completed"),
                                             XmlDoc.Item("Caller is responsible for closing the ", streamParam)));

            var methodDocComments = new List <DocumentationCommentTriviaSyntax>
            {
                XmlDoc.Summary(_restMethod.Description),
                remarks
            };

            if (BodyTyp is object)
            {
                methodDocComments.Add(XmlDoc.Param(Parameter(ctx.Type(BodyTyp), "body"), "The body of the request."));
            }

            methodDocComments.AddRange(requiredParameters.Select(pair => XmlDoc.Param(pair.decl, pair.param.Description)));
            methodDocComments.Add(XmlDoc.Param(streamParam, "The stream to upload. See remarks for further information."));
            methodDocComments.Add(XmlDoc.Param(contentTypeParam, "The content type of the stream to upload."));

            // We're taking it from the field in the parent type, but it becomes a parameter for the constructor...
            // So long as it appears as "service" we don't really mind.
            var serviceParam   = Parameter(ctx.Type <IClientService>(), "service");
            var ctorParameters = new List <ParameterSyntax> {
                serviceParam
            };

            ctorParameters.AddRange(insertMethodParameters);

            var insertMethod = Method(Modifier.Public | Modifier.Virtual, ctx.Type(uploadTyp), PascalCasedName)(insertMethodParameters.ToArray())
                               .WithBlockBody(Return(New(ctx.Type(uploadTyp))(ctorParameters)))
                               .WithXmlDoc(methodDocComments.ToArray());

            using (ctx.InClass(uploadTyp))
            {
                var baseInitializerArgs = new List <object>
                {
                    serviceParam,
                    ctx.Type <string>().Call(nameof(string.Format))("/{0}/{1}{2}", "upload", serviceParam.Access("BasePath"), _restMethod.Path),
                    _restMethod.HttpMethod,
                    streamParam,
                    contentTypeParam
                };
                var baseInitializer = BaseInitializer(baseInitializerArgs).WithAdditionalAnnotations(Annotations.LineBreakAnnotation);
                var assignments     = requiredParameters.Select(p => Field(0, ctx.Type(p.param.Typ), p.param.PropertyName).Assign(p.decl)).ToList();

                if (BodyTyp is object)
                {
                    // The Body property is in the base class.
                    var bodyProperty = Property(Modifier.Public, ctx.Type(BodyTyp), "Body");
                    assignments.Add(bodyProperty.Assign(Parameter(ctx.Type(BodyTyp), "body")));
                }

                // The parameters to the constructor are the same as for the method.
                var uploadCtor = Ctor(Modifier.Public, uploadCls, baseInitializer)(ctorParameters.ToArray())
                                 .WithBlockBody(assignments)
                                 .WithXmlDoc(XmlDoc.Summary($"Constructs a new {PascalCasedName} media upload instance."), remarks);

                uploadCls = uploadCls.AddMembers(Package.CreateParameterList(uploadTyp).SelectMany(p => p.GenerateDeclarations(ctx)).ToArray());
                uploadCls = uploadCls.AddMembers(parameters.SelectMany(p => p.GenerateDeclarations(ctx)).ToArray());
                uploadCls = uploadCls.AddMembers(uploadCtor);
            }

            yield return(insertMethod);

            yield return(uploadCls);
        }