|
14 | 14 | * limitations under the License. |
15 | 15 | */ |
16 | 16 |
|
| 17 | +import fetch from 'node-fetch'; |
17 | 18 | import IClientContext from '../contracts/IClientContext'; |
18 | 19 | import { LogLevel } from '../contracts/IDBSQLLogger'; |
19 | 20 |
|
@@ -104,17 +105,75 @@ export default class FeatureFlagCache { |
104 | 105 | } |
105 | 106 |
|
106 | 107 | /** |
107 | | - * Fetches feature flag from server. |
108 | | - * This is a placeholder implementation that returns false. |
109 | | - * Real implementation would fetch from server using connection provider. |
110 | | - * @param _host The host to fetch feature flag for (unused in placeholder implementation) |
| 108 | + * Gets the driver version from package.json. |
| 109 | + * Used for version-specific feature flag requests. |
111 | 110 | */ |
112 | | - // eslint-disable-next-line @typescript-eslint/no-unused-vars |
113 | | - private async fetchFeatureFlag(_host: string): Promise<boolean> { |
114 | | - // Placeholder implementation |
115 | | - // Real implementation would use: |
116 | | - // const connectionProvider = await this.context.getConnectionProvider(); |
117 | | - // and make an API call to fetch the feature flag |
118 | | - return false; |
| 111 | + private getDriverVersion(): string { |
| 112 | + try { |
| 113 | + // eslint-disable-next-line @typescript-eslint/no-var-requires |
| 114 | + const packageJson = require('../../package.json'); |
| 115 | + return packageJson.version || 'unknown'; |
| 116 | + } catch { |
| 117 | + return 'unknown'; |
| 118 | + } |
| 119 | + } |
| 120 | + |
| 121 | + /** |
| 122 | + * Fetches feature flag from server REST API. |
| 123 | + * Makes authenticated call to connector-service endpoint. |
| 124 | + * @param host The host to fetch feature flag for |
| 125 | + */ |
| 126 | + private async fetchFeatureFlag(host: string): Promise<boolean> { |
| 127 | + const logger = this.context.getLogger(); |
| 128 | + try { |
| 129 | + const driverVersion = this.getDriverVersion(); |
| 130 | + const endpoint = `https://${host}/api/2.0/connector-service/feature-flags/OSS_NODEJS/${driverVersion}`; |
| 131 | + |
| 132 | + // Get authentication headers |
| 133 | + const authHeaders = await this.context.getAuthHeaders(); |
| 134 | + |
| 135 | + logger.log(LogLevel.debug, `Fetching feature flag from ${endpoint}`); |
| 136 | + |
| 137 | + const response = await fetch(endpoint, { |
| 138 | + method: 'GET', |
| 139 | + headers: { |
| 140 | + ...authHeaders, |
| 141 | + 'Content-Type': 'application/json', |
| 142 | + 'User-Agent': `databricks-sql-nodejs/${driverVersion}`, |
| 143 | + }, |
| 144 | + }); |
| 145 | + |
| 146 | + if (!response.ok) { |
| 147 | + logger.log(LogLevel.debug, `Feature flag fetch returned status ${response.status}`); |
| 148 | + return false; |
| 149 | + } |
| 150 | + |
| 151 | + const data: any = await response.json(); |
| 152 | + |
| 153 | + // Update cache duration from ttl_seconds if provided |
| 154 | + if (data && data.ttl_seconds) { |
| 155 | + const ctx = this.contexts.get(host); |
| 156 | + if (ctx) { |
| 157 | + ctx.cacheDuration = data.ttl_seconds * 1000; |
| 158 | + logger.log(LogLevel.debug, `Updated cache duration to ${data.ttl_seconds} seconds`); |
| 159 | + } |
| 160 | + } |
| 161 | + |
| 162 | + // Find the telemetry flag |
| 163 | + if (data && data.flags && Array.isArray(data.flags)) { |
| 164 | + const flag = data.flags.find((f: any) => f.name === this.FEATURE_FLAG_NAME); |
| 165 | + if (flag) { |
| 166 | + const enabled = String(flag.value).toLowerCase() === 'true'; |
| 167 | + logger.log(LogLevel.debug, `Feature flag ${this.FEATURE_FLAG_NAME} = ${enabled}`); |
| 168 | + return enabled; |
| 169 | + } |
| 170 | + } |
| 171 | + |
| 172 | + logger.log(LogLevel.debug, `Feature flag ${this.FEATURE_FLAG_NAME} not found in response`); |
| 173 | + return false; |
| 174 | + } catch (error: any) { |
| 175 | + logger.log(LogLevel.debug, `Error fetching feature flag from ${host}: ${error.message}`); |
| 176 | + return false; |
| 177 | + } |
119 | 178 | } |
120 | 179 | } |
0 commit comments