codegen/smithy-aws-go-codegen/src/main/java/software/amazon/smithy/aws/go/codegen/EndpointDiscoveryGenerator.java
private static void generateFetchDiscoveredEndpointFunction(
            Model model, SymbolProvider symbolProvider, GoWriter writer, ServiceShape service, OperationShape operation
    ) {
        if (!operationUsesEndpointDiscovery(model, service, operation)) {
            return;
        }

        // Generate operation specific fetch discovered endpoint function
        String fetchDiscoveredEndpointFuncName = generateFetchDiscoverEndpointFuncName(service, operation);
        String operationName = operation.getId().getName(service);
        String sdkId = service.expectTrait(ServiceTrait.class).getSdkId();

        Shape inputShape = model.expectShape(operation.getInput().get());
        OperationShape discoveryOperation = model.expectShape(getEndpointDiscoveryOperationId(model, service),
                OperationShape.class);
        Shape discoveryOperationInput = model.expectShape(discoveryOperation.getInput().get());
        Symbol discoveryOperationInputSymbol = symbolProvider.toSymbol(discoveryOperationInput);
        String DISCOVERY_OPERATION_INPUT_NAME = "discoveryOperationInput";

        writer.addUseImports(SmithyGoDependency.CONTEXT);
        writer.openBlock(
                "func (c *Client) $L(ctx context.Context, input interface{}, optFns ...func($P)) ($T, error) {", "}",
                fetchDiscoveredEndpointFuncName, DISCOVERY_ENDPOINT_OPTIONS, DISCOVERY_ENDPOINT_WEIGHTED_ADDRESS,
                () -> {
                    writer.write("in, ok := input.($P)", symbolProvider.toSymbol(inputShape));
                    writer.openBlock("if !ok {", "}", () -> {
                        writer.addUseImports(SmithyGoDependency.FMT);
                        writer.write("return $T{}, fmt.Errorf(\"unknown input type %T\", input)",
                                DISCOVERY_ENDPOINT_WEIGHTED_ADDRESS);
                    });
                    writer.write("_ = in");
                    writer.write("");

                    // build identifier map
                    String IDENTIFIER_MAP = "identifierMap";
                    writer.write("$L := make(map[string]string, 0)", IDENTIFIER_MAP);

                    for (MemberShape member : getMembersUsedAsIdForDiscovery(model, service, operation)) {
                        String memberName = member.getMemberName();
                        Shape targetShape = model.expectShape(member.getTarget());
                        String assignFormat = String.format("$L[$S] = %s",
                                targetShape.hasTrait(EnumTrait.class) ? "string(in.$L)" : "in.$L");
                        writer.write(assignFormat, IDENTIFIER_MAP, memberName, memberName);
                    }

                    writer.write("");
                    writer.write("key := fmt.Sprintf(\"$L.%v\", $L)", sdkId, IDENTIFIER_MAP);

                    writer.write("");
                    writer.openBlock("if v, ok := c.$L.Get(key); ok {", "}", CLIENT_MEMBER_ENDPOINT_CACHE, () -> {
                        writer.write("return v, nil");
                    }).write("");

                    // build input for endpoint discovery call
                    writer.openBlock("$L := &$T{", "}", DISCOVERY_OPERATION_INPUT_NAME,
                            discoveryOperationInputSymbol, () -> {
                                for (MemberShape member : discoveryOperationInput.members()) {
                                    String memberName = member.getMemberName();
                                    if (memberName.equalsIgnoreCase("Operation")) {
                                        writer.write("$T : $S", member, operationName);
                                    }

                                    if (memberName.equalsIgnoreCase("Identifiers")) {
                                        writer.write("$T : $L", member, IDENTIFIER_MAP);
                                    }
                                }
                            }).write("");

                    // resolve options
                    writer.write("opt := $T{}", DISCOVERY_ENDPOINT_OPTIONS);
                    writer.openBlock("for _, fn := range optFns {", "}", () -> {
                        writer.write("fn(&opt)");
                    }).write("");

                    // if discovery not required, then spin up a unblocking go routine
                    if (!operationRequiresEndpointDiscovery(model, service, operation)) {
                        writer.write("go c.$L(ctx, $L, key, opt)", DISCOVERY_ENDPOINT_HANDLER_NAME,
                                DISCOVERY_OPERATION_INPUT_NAME);
                        writer.write("return $T{}, nil", DISCOVERY_ENDPOINT_WEIGHTED_ADDRESS);
                        return;
                    }

                    writer.write("endpoint, err := c.$L(ctx, $L, key, opt)", DISCOVERY_ENDPOINT_HANDLER_NAME,
                            DISCOVERY_OPERATION_INPUT_NAME);
                    writer.write("if err != nil { return $T{}, err }", DISCOVERY_ENDPOINT_WEIGHTED_ADDRESS);
                    writer.write("");

                    writer.write("weighted, ok := endpoint.GetValidAddress()");
                    writer.write(
                            "if !ok { return $T{}, fmt.Errorf(\"no valid endpoint address returned by the endpoint discovery api\")}",
                            DISCOVERY_ENDPOINT_WEIGHTED_ADDRESS);
                    writer.write("return weighted, nil");
                });
    }
/**
     * Generates a function to fetch a discovered endpoint.
     *
     * @param model          is the generation model
     * @param symbolProvider is the symbol provider used in generation context
     * @param writer         is the GoWriter
     * @param service        is the service for which endpoint discovery is performed.
     * @param operation      is the operation for which discover endpoint middleware is added.
     */
Generates a function to fetch a discovered endpoint.
@param model          is the generation model
@param symbolProvider is the symbol provider used in generation context
@param writer         is the GoWriter
@param service        is the service for which endpoint discovery is performed.
@param operation      is the operation for which discover endpoint middleware is added.
Generates a function to fetch a discovered endpoint . @param model is the generation model @param symbolProvider is the symbol provider used in generation context @param writer is the GoWriter @param service is the service for which endpoint discovery is performed . @param operation is the operation for which discover endpoint middleware is added .
private static void generateFetchDiscoveredEndpointFunction(
            Model model, SymbolProvider symbolProvider, GoWriter writer, ServiceShape service, OperationShape operation
    ) {
        if (!operationUsesEndpointDiscovery(model, service, operation)) {
            return;
        }
        String fetchDiscoveredEndpointFuncName = generateFetchDiscoverEndpointFuncName(service, operation);
        String operationName = operation.getId().getName(service);
        String sdkId = service.expectTrait(ServiceTrait.class).getSdkId();
        Shape inputShape = model.expectShape(operation.getInput().get());
        OperationShape discoveryOperation = model.expectShape(getEndpointDiscoveryOperationId(model, service),
                OperationShape.class);
        Shape discoveryOperationInput = model.expectShape(discoveryOperation.getInput().get());
        Symbol discoveryOperationInputSymbol = symbolProvider.toSymbol(discoveryOperationInput);
        String DISCOVERY_OPERATION_INPUT_NAME = "discoveryOperationInput";
        writer.addUseImports(SmithyGoDependency.CONTEXT);
        writer.openBlock(
                "func (c *Client) $L(ctx context.Context, input interface{}, optFns ...func($P)) ($T, error) {", "}",
                fetchDiscoveredEndpointFuncName, DISCOVERY_ENDPOINT_OPTIONS, DISCOVERY_ENDPOINT_WEIGHTED_ADDRESS,
                () -> {
                    writer.write("in, ok := input.($P)", symbolProvider.toSymbol(inputShape));
                    writer.openBlock("if !ok {", "}", () -> {
                        writer.addUseImports(SmithyGoDependency.FMT);
                        writer.write("return $T{}, fmt.Errorf(\"unknown input type %T\", input)",
                                DISCOVERY_ENDPOINT_WEIGHTED_ADDRESS);
                    });
                    writer.write("_ = in");
                    writer.write("");
                    String IDENTIFIER_MAP = "identifierMap";
                    writer.write("$L := make(map[string]string, 0)", IDENTIFIER_MAP);
                    for (MemberShape member : getMembersUsedAsIdForDiscovery(model, service, operation)) {
                        String memberName = member.getMemberName();
                        Shape targetShape = model.expectShape(member.getTarget());
                        String assignFormat = String.format("$L[$S] = %s",
                                targetShape.hasTrait(EnumTrait.class) ? "string(in.$L)" : "in.$L");
                        writer.write(assignFormat, IDENTIFIER_MAP, memberName, memberName);
                    }
                    writer.write("");
                    writer.write("key := fmt.Sprintf(\"$L.%v\", $L)", sdkId, IDENTIFIER_MAP);
                    writer.write("");
                    writer.openBlock("if v, ok := c.$L.Get(key); ok {", "}", CLIENT_MEMBER_ENDPOINT_CACHE, () -> {
                        writer.write("return v, nil");
                    }).write("");
                    writer.openBlock("$L := &$T{", "}", DISCOVERY_OPERATION_INPUT_NAME,
                            discoveryOperationInputSymbol, () -> {
                                for (MemberShape member : discoveryOperationInput.members()) {
                                    String memberName = member.getMemberName();
                                    if (memberName.equalsIgnoreCase("Operation")) {
                                        writer.write("$T : $S", member, operationName);
                                    }
                                    if (memberName.equalsIgnoreCase("Identifiers")) {
                                        writer.write("$T : $L", member, IDENTIFIER_MAP);
                                    }
                                }
                            }).write("");
                    writer.write("opt := $T{}", DISCOVERY_ENDPOINT_OPTIONS);
                    writer.openBlock("for _, fn := range optFns {", "}", () -> {
                        writer.write("fn(&opt)");
                    }).write("");
                    if (!operationRequiresEndpointDiscovery(model, service, operation)) {
                        writer.write("go c.$L(ctx, $L, key, opt)", DISCOVERY_ENDPOINT_HANDLER_NAME,
                                DISCOVERY_OPERATION_INPUT_NAME);
                        writer.write("return $T{}, nil", DISCOVERY_ENDPOINT_WEIGHTED_ADDRESS);
                        return;
                    }
                    writer.write("endpoint, err := c.$L(ctx, $L, key, opt)", DISCOVERY_ENDPOINT_HANDLER_NAME,
                            DISCOVERY_OPERATION_INPUT_NAME);
                    writer.write("if err != nil { return $T{}, err }", DISCOVERY_ENDPOINT_WEIGHTED_ADDRESS);
                    writer.write("");
                    writer.write("weighted, ok := endpoint.GetValidAddress()");
                    writer.write(
                            "if !ok { return $T{}, fmt.Errorf(\"no valid endpoint address returned by the endpoint discovery api\")}",
                            DISCOVERY_ENDPOINT_WEIGHTED_ADDRESS);
                    writer.write("return weighted, nil");
                });
    }
private static void generateFetchDiscoveredEndpointFunction ( Model model , SymbolProvider symbolProvider , GoWriter writer , ServiceShape service , OperationShape operation ) { if ( ! operationUsesEndpointDiscovery ( model , service , operation ) ) { return ; } String fetchDiscoveredEndpointFuncName = generateFetchDiscoverEndpointFuncName ( service , operation ) ; String operationName = operation . getId ( ) . getName ( service ) ; String sdkId = service . expectTrait ( ServiceTrait . class ) . getSdkId ( ) ; Shape inputShape = model . expectShape ( operation . getInput ( ) . get ( ) ) ; OperationShape discoveryOperation = model . expectShape ( getEndpointDiscoveryOperationId ( model , service ) , OperationShape . class ) ; Shape discoveryOperationInput = model . expectShape ( discoveryOperation . getInput ( ) . get ( ) ) ; Symbol discoveryOperationInputSymbol = symbolProvider . toSymbol ( discoveryOperationInput ) ; String DISCOVERY_OPERATION_INPUT_NAME = "discoveryOperationInput" ; writer . addUseImports ( SmithyGoDependency . CONTEXT ) ; writer . openBlock ( "func (c *Client) $L(ctx context.Context, input interface{}, optFns ...func($P)) ($T, error) {" , "}" , fetchDiscoveredEndpointFuncName , DISCOVERY_ENDPOINT_OPTIONS , DISCOVERY_ENDPOINT_WEIGHTED_ADDRESS , ( ) -> { writer . write ( "in, ok := input.($P)" , symbolProvider . toSymbol ( inputShape ) ) ; writer . openBlock ( "if !ok {" , "}" , ( ) -> { writer . addUseImports ( SmithyGoDependency . FMT ) ; writer . write ( "return $T{}, fmt.Errorf(\"unknown input type %T\", input)" , DISCOVERY_ENDPOINT_WEIGHTED_ADDRESS ) ; } ) ; writer . write ( "_ = in" ) ; writer . write ( "" ) ; String IDENTIFIER_MAP = "identifierMap" ; writer . write ( "$L := make(map[string]string, 0)" , IDENTIFIER_MAP ) ; for ( MemberShape member : getMembersUsedAsIdForDiscovery ( model , service , operation ) ) { String memberName = member . getMemberName ( ) ; Shape targetShape = model . expectShape ( member . getTarget ( ) ) ; String assignFormat = String . format ( "$L[$S] = %s" , targetShape . hasTrait ( EnumTrait . class ) ? "string(in.$L)" : "in.$L" ) ; writer . write ( assignFormat , IDENTIFIER_MAP , memberName , memberName ) ; } writer . write ( "" ) ; writer . write ( "key := fmt.Sprintf(\"$L.%v\", $L)" , sdkId , IDENTIFIER_MAP ) ; writer . write ( "" ) ; writer . openBlock ( "if v, ok := c.$L.Get(key); ok {" , "}" , CLIENT_MEMBER_ENDPOINT_CACHE , ( ) -> { writer . write ( "return v, nil" ) ; } ) . write ( "" ) ; writer . openBlock ( "$L := &$T{" , "}" , DISCOVERY_OPERATION_INPUT_NAME , discoveryOperationInputSymbol , ( ) -> { for ( MemberShape member : discoveryOperationInput . members ( ) ) { String memberName = member . getMemberName ( ) ; if ( memberName . equalsIgnoreCase ( "Operation" ) ) { writer . write ( "$T : $S" , member , operationName ) ; } if ( memberName . equalsIgnoreCase ( "Identifiers" ) ) { writer . write ( "$T : $L" , member , IDENTIFIER_MAP ) ; } } } ) . write ( "" ) ; writer . write ( "opt := $T{}" , DISCOVERY_ENDPOINT_OPTIONS ) ; writer . openBlock ( "for _, fn := range optFns {" , "}" , ( ) -> { writer . write ( "fn(&opt)" ) ; } ) . write ( "" ) ; if ( ! operationRequiresEndpointDiscovery ( model , service , operation ) ) { writer . write ( "go c.$L(ctx, $L, key, opt)" , DISCOVERY_ENDPOINT_HANDLER_NAME , DISCOVERY_OPERATION_INPUT_NAME ) ; writer . write ( "return $T{}, nil" , DISCOVERY_ENDPOINT_WEIGHTED_ADDRESS ) ; return ; } writer . write ( "endpoint, err := c.$L(ctx, $L, key, opt)" , DISCOVERY_ENDPOINT_HANDLER_NAME , DISCOVERY_OPERATION_INPUT_NAME ) ; writer . write ( "if err != nil { return $T{}, err }" , DISCOVERY_ENDPOINT_WEIGHTED_ADDRESS ) ; writer . write ( "" ) ; writer . write ( "weighted, ok := endpoint.GetValidAddress()" ) ; writer . write ( "if !ok { return $T{}, fmt.Errorf(\"no valid endpoint address returned by the endpoint discovery api\")}" , DISCOVERY_ENDPOINT_WEIGHTED_ADDRESS ) ; writer . write ( "return weighted, nil" ) ; } ) ; }
Generates a function to fetch a discovered endpoint.
Generates a function to fetch a discovered endpoint .
// Generate operation specific fetch discovered endpoint function // build identifier map // build input for endpoint discovery call // resolve options // if discovery not required, then spin up a unblocking go routine