@@ -40,11 +40,13 @@ import { ClientWrapper } from "./client_wrapper";
4040import { logger } from "../logutils" ;
4141import { Messages } from "./utils/messages" ;
4242import { DatabaseDialectCodes } from "./database_dialect/database_dialect_codes" ;
43- import { getWriter } from "./utils/utils" ;
43+ import { getWriter , logTopology } from "./utils/utils" ;
4444import { TelemetryFactory } from "./utils/telemetry/telemetry_factory" ;
4545import { DriverDialect } from "./driver_dialect/driver_dialect" ;
46+ import { AllowedAndBlockedHosts } from "./AllowedAndBlockedHosts" ;
4647
4748export class PluginService implements ErrorHandler , HostListProviderService {
49+ private static readonly DEFAULT_HOST_AVAILABILITY_CACHE_EXPIRE_NANO = 5 * 60_000_000_000 ; // 5 minutes
4850 private readonly _currentClient : AwsClient ;
4951 private _currentHostInfo ?: HostInfo ;
5052 private _hostListProvider ?: HostListProvider ;
@@ -59,6 +61,7 @@ export class PluginService implements ErrorHandler, HostListProviderService {
5961 protected readonly sessionStateService : SessionStateService ;
6062 protected static readonly hostAvailabilityExpiringCache : CacheMap < string , HostAvailability > = new CacheMap < string , HostAvailability > ( ) ;
6163 readonly props : Map < string , any > ;
64+ private allowedAndBlockedHosts : AllowedAndBlockedHosts | null = null ;
6265
6366 constructor (
6467 container : PluginServiceManagerContainer ,
@@ -114,17 +117,34 @@ export class PluginService implements ErrorHandler, HostListProviderService {
114117 this . _currentHostInfo = this . _initialConnectionHostInfo ;
115118
116119 if ( ! this . _currentHostInfo ) {
117- if ( this . getHosts ( ) . length === 0 ) {
120+ if ( this . getAllHosts ( ) . length === 0 ) {
118121 throw new AwsWrapperError ( Messages . get ( "PluginService.hostListEmpty" ) ) ;
119122 }
120123
121- const writerHost = getWriter ( this . getHosts ( ) ) ;
124+ const writerHost = getWriter ( this . getAllHosts ( ) ) ;
122125 if ( writerHost ) {
123126 this . _currentHostInfo = writerHost ;
124- } else {
127+ if ( ! this . getHosts ( ) . some ( ( hostInfo : HostInfo ) => hostInfo . host === writerHost ?. host ) ) {
128+ throw new AwsWrapperError (
129+ Messages . get (
130+ "PluginService.currentHostNotAllowed" ,
131+ this . _currentHostInfo ? this . _currentHostInfo . host : "<null>" ,
132+ logTopology ( this . hosts , "[PluginService.currentHostNotAllowed] " )
133+ )
134+ ) ;
135+ }
136+ }
137+
138+ if ( ! this . _currentHostInfo ) {
125139 this . _currentHostInfo = this . getHosts ( ) [ 0 ] ;
126140 }
127141 }
142+
143+ if ( ! this . _currentHostInfo ) {
144+ throw new AwsWrapperError ( Messages . get ( "PluginService.currentHostNotDefined" ) ) ;
145+ }
146+
147+ logger . debug ( `Set current host to: ${ this . _currentHostInfo . host } ` ) ;
128148 }
129149
130150 return this . _currentHostInfo ;
@@ -286,11 +306,64 @@ export class PluginService implements ErrorHandler, HostListProviderService {
286306 }
287307 }
288308
289- getHosts ( ) : HostInfo [ ] {
309+ getAllHosts ( ) : HostInfo [ ] {
290310 return this . hosts ;
291311 }
292312
293- setAvailability ( hostAliases : Set < string > , availability : HostAvailability ) { }
313+ getHosts ( ) : HostInfo [ ] {
314+ const hostPermissions = this . allowedAndBlockedHosts ;
315+ if ( ! hostPermissions ) {
316+ return this . hosts ;
317+ }
318+
319+ let hosts = this . hosts ;
320+ const allowedHostIds = hostPermissions . getAllowedHostIds ( ) ;
321+ const blockedHostIds = hostPermissions . getBlockedHostIds ( ) ;
322+
323+ if ( allowedHostIds && allowedHostIds . size > 0 ) {
324+ hosts = hosts . filter ( ( host : HostInfo ) => allowedHostIds . has ( host . hostId ) ) ;
325+ }
326+
327+ if ( blockedHostIds && blockedHostIds . size > 0 ) {
328+ hosts = hosts . filter ( ( host : HostInfo ) => ! blockedHostIds . has ( host . hostId ) ) ;
329+ }
330+
331+ return hosts ;
332+ }
333+
334+ setAvailability ( hostAliases : Set < string > , availability : HostAvailability ) {
335+ if ( hostAliases . size === 0 ) {
336+ return ;
337+ }
338+
339+ const hostsToChange = [
340+ ...new Set (
341+ this . getAllHosts ( ) . filter (
342+ ( host : HostInfo ) => hostAliases . has ( host . asAlias ) || [ ...host . aliases ] . some ( ( hostAlias : string ) => hostAliases . has ( hostAlias ) )
343+ )
344+ )
345+ ] ;
346+
347+ if ( hostsToChange . length === 0 ) {
348+ logger . debug ( Messages . get ( "PluginService.hostsChangeListEmpty" ) ) ;
349+ return ;
350+ }
351+
352+ const changes = new Map < string , Set < HostChangeOptions > > ( ) ;
353+ for ( const host of hostsToChange ) {
354+ const currentAvailability = host . getAvailability ( ) ;
355+ PluginService . hostAvailabilityExpiringCache . put ( host . url , availability , PluginService . DEFAULT_HOST_AVAILABILITY_CACHE_EXPIRE_NANO ) ;
356+ if ( currentAvailability !== availability ) {
357+ let hostChanges = new Set < HostChangeOptions > ( ) ;
358+ if ( availability === HostAvailability . AVAILABLE ) {
359+ hostChanges = new Set ( [ HostChangeOptions . WENT_UP , HostChangeOptions . HOST_CHANGED ] ) ;
360+ } else {
361+ hostChanges = new Set ( [ HostChangeOptions . WENT_DOWN , HostChangeOptions . HOST_CHANGED ] ) ;
362+ }
363+ changes . set ( host . url , hostChanges ) ;
364+ }
365+ }
366+ }
294367
295368 updateConfigWithProperties ( props : Map < string , any > ) {
296369 this . _currentClient . config = Object . fromEntries ( props . entries ( ) ) ;
@@ -527,4 +600,12 @@ export class PluginService implements ErrorHandler, HostListProviderService {
527600 attachNoOpErrorListener ( clientWrapper : ClientWrapper | undefined ) : void {
528601 this . getDialect ( ) . getErrorHandler ( ) . attachNoOpErrorListener ( clientWrapper ) ;
529602 }
603+
604+ setAllowedAndBlockedHosts ( allowedAndBlockedHosts : AllowedAndBlockedHosts ) {
605+ this . allowedAndBlockedHosts = allowedAndBlockedHosts ;
606+ }
607+
608+ static clearHostAvailabilityCache ( ) : void {
609+ PluginService . hostAvailabilityExpiringCache . clear ( ) ;
610+ }
530611}
0 commit comments