/* * Copyright 2019 gRPC authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ import { ServiceConfig } from './service-config'; import * as resolver_dns from './resolver-dns'; import * as resolver_uds from './resolver-uds'; import { StatusObject } from './call-stream'; import { SubchannelAddress } from './subchannel'; import { GrpcUri, uriToString } from './uri-parser'; /** * A listener object passed to the resolver's constructor that provides name * resolution updates back to the resolver's owner. */ export interface ResolverListener { /** * Called whenever the resolver has new name resolution results to report * @param addressList The new list of backend addresses * @param serviceConfig The new service configuration corresponding to the * `addressList`. Will be `null` if no service configuration was * retrieved or if the service configuration was invalid * @param serviceConfigError If non-`null`, indicates that the retrieved * service configuration was invalid */ onSuccessfulResolution( addressList: SubchannelAddress[], serviceConfig: ServiceConfig | null, serviceConfigError: StatusObject | null ): void; /** * Called whenever a name resolution attempt fails. * @param error Describes how resolution failed */ onError(error: StatusObject): void; } /** * A resolver class that handles one or more of the name syntax schemes defined * in the [gRPC Name Resolution document](https://github.com/grpc/grpc/blob/master/doc/naming.md) */ export interface Resolver { /** * Indicates that the caller wants new name resolution data. Calling this * function may eventually result in calling one of the `ResolverListener` * functions, but that is not guaranteed. Those functions will never be * called synchronously with the constructor or updateResolution. */ updateResolution(): void; } export interface ResolverConstructor { new (target: GrpcUri, listener: ResolverListener): Resolver; /** * Get the default authority for a target. This loosely corresponds to that * target's hostname. Throws an error if this resolver class cannot parse the * `target`. * @param target */ getDefaultAuthority(target: GrpcUri): string; } const registeredResolvers: { [scheme: string]: ResolverConstructor } = {}; let defaultScheme: string | null = null; /** * Register a resolver class to handle target names prefixed with the `prefix` * string. This prefix should correspond to a URI scheme name listed in the * [gRPC Name Resolution document](https://github.com/grpc/grpc/blob/master/doc/naming.md) * @param prefix * @param resolverClass */ export function registerResolver( scheme: string, resolverClass: ResolverConstructor ) { registeredResolvers[scheme] = resolverClass; } /** * Register a default resolver to handle target names that do not start with * any registered prefix. * @param resolverClass */ export function registerDefaultScheme(scheme: string) { defaultScheme = scheme; } /** * Create a name resolver for the specified target, if possible. Throws an * error if no such name resolver can be created. * @param target * @param listener */ export function createResolver( target: GrpcUri, listener: ResolverListener ): Resolver { if (target.scheme !== undefined && target.scheme in registeredResolvers) { return new registeredResolvers[target.scheme](target, listener); } else { throw new Error( `No resolver could be created for target ${uriToString(target)}` ); } } /** * Get the default authority for the specified target, if possible. Throws an * error if no registered name resolver can parse that target string. * @param target */ export function getDefaultAuthority(target: GrpcUri): string { if (target.scheme !== undefined && target.scheme in registeredResolvers) { return registeredResolvers[target.scheme].getDefaultAuthority(target); } else { throw new Error(`Invalid target ${uriToString(target)}`); } } export function mapUriDefaultScheme(target: GrpcUri): GrpcUri | null { if (target.scheme === undefined || !(target.scheme in registeredResolvers)) { if (defaultScheme !== null) { return { scheme: defaultScheme, authority: undefined, path: uriToString(target) }; } else { return null; } } return target; } export function registerAll() { resolver_dns.setup(); resolver_uds.setup(); }