Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: remove proxy code (moved to runtimes) #774

Merged
merged 11 commits into from
Feb 5, 2025
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
import { CodeWhispererStreaming, CodeWhispererStreamingClientConfig } from '@amzn/codewhisperer-streaming'
import { ConfiguredRetryStrategy } from '@aws-sdk/util-retry'
import { readFileSync } from 'fs'
import { NodeHttpHandler } from '@smithy/node-http-handler'
import { HttpsProxyAgent } from 'hpagent'
import { SDKInitializator } from '@aws/language-server-runtimes/server-interface'

export class StreamingClient {
Expand Down Expand Up @@ -31,36 +28,11 @@ export async function createStreamingClient(
): Promise<CodeWhispererStreaming> {
const creds = credentialsProvider.getCredentials('bearer')

let clientOptions
// short term solution to fix webworker bundling, broken due to this node.js specific logic in here
const isNodeJS: boolean = typeof process !== 'undefined' && process.release && process.release.name === 'node'
const proxyUrl = isNodeJS ? (process.env.HTTPS_PROXY ?? process.env.https_proxy) : undefined
const certs = isNodeJS
? process.env.AWS_CA_BUNDLE
? [readFileSync(process.env.AWS_CA_BUNDLE)]
: undefined
: undefined

if (proxyUrl) {
const agent = new HttpsProxyAgent({
proxy: proxyUrl,
ca: certs,
})

clientOptions = {
requestHandler: new NodeHttpHandler({
httpAgent: agent,
httpsAgent: agent,
}),
}
}

const streamingClient = sdkInitializator(CodeWhispererStreaming, {
region: codeWhispererRegion,
endpoint: codeWhispererEndpoint,
token: { token: creds.token },
retryStrategy: new ConfiguredRetryStrategy(0, (attempt: number) => 500 + attempt ** 10),
requestHandler: clientOptions?.requestHandler,
...config,
})
return streamingClient
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,12 @@ export interface GenerateSuggestionsResponse {

import CodeWhispererSigv4Client = require('../client/sigv4/codewhisperersigv4client')
import CodeWhispererTokenClient = require('../client/token/codewhispererbearertokenclient')
import { makeProxyConfig } from './utils'

// Right now the only difference between the token client and the IAM client for codewhsiperer is the difference in function name
// This abstract class can grow in the future to account for any additional changes across the clients
export abstract class CodeWhispererServiceBase {
protected readonly codeWhispererRegion
protected readonly codeWhispererEndpoint
protected proxyConfig: ConfigurationOptions = {}
public shareCodeWhispererContentWithAWS = false
public customizationArn?: string
abstract client: CodeWhispererSigv4Client | CodeWhispererTokenClient
Expand All @@ -60,7 +58,6 @@ export abstract class CodeWhispererServiceBase {
abstract generateSuggestions(request: GenerateSuggestionsRequest): Promise<GenerateSuggestionsResponse>

constructor(workspace: Workspace, codeWhispererRegion: string, codeWhispererEndpoint: string) {
this.proxyConfig = makeProxyConfig(workspace)
this.codeWhispererRegion = codeWhispererRegion
this.codeWhispererEndpoint = codeWhispererEndpoint
}
Expand Down Expand Up @@ -93,7 +90,6 @@ export class CodeWhispererServiceIAM extends CodeWhispererServiceBase {
]),
}
this.client = createCodeWhispererSigv4Client(options, sdkInitializator)
this.updateClientConfig(this.proxyConfig)
this.client.setupRequestListeners = ({ httpRequest }) => {
httpRequest.headers['x-amzn-codewhisperer-optout'] = `${!this.shareCodeWhispererContentWithAWS}`
}
Expand Down Expand Up @@ -154,7 +150,6 @@ export class CodeWhispererServiceToken extends CodeWhispererServiceBase {
],
}
this.client = createCodeWhispererTokenClient(options, sdkInitializator)
this.updateClientConfig(this.proxyConfig)
}

getCredentialsType(): CredentialsType {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,6 @@ import { CodeWhispererServiceIAM, CodeWhispererServiceToken } from './codeWhispe
import { QNetTransformServerToken } from './netTransformServer'
import { QChatServer } from './qChatServer'
import { QConfigurationServerToken } from './configuration/qConfigurationServer'
import { readFileSync } from 'fs'
import { HttpsProxyAgent } from 'hpagent'
import { NodeHttpHandler } from '@smithy/node-http-handler'

export const CodeWhispererServerTokenProxy = CodewhispererServerFactory(
(credentialsProvider, workspace, awsQRegion, awsQEndpointUrl, sdkInitializator) => {
Expand Down Expand Up @@ -59,39 +56,11 @@ export const QNetTransformServerTokenProxy = QNetTransformServerToken(
)

export const QChatServerProxy = QChatServer((credentialsProvider, awsQRegion, awsQEndpointUrl, sdkInitializator) => {
let clientOptions: ChatSessionServiceConfig | undefined
// short term solution to fix webworker bundling, broken due to this node.js specific logic in here
const isNodeJS: boolean = typeof process !== 'undefined' && process.release && process.release.name === 'node'
const proxyUrl = isNodeJS ? (process.env.HTTPS_PROXY ?? process.env.https_proxy) : undefined
const certs = isNodeJS
? process.env.AWS_CA_BUNDLE
? [readFileSync(process.env.AWS_CA_BUNDLE)]
: undefined
: undefined

if (proxyUrl) {
clientOptions = () => {
// this mimics aws-sdk-v3-js-proxy
const agent = new HttpsProxyAgent({
proxy: proxyUrl,
ca: certs,
})

return {
requestHandler: new NodeHttpHandler({
httpAgent: agent,
httpsAgent: agent,
}),
}
}
}

return ChatSessionManagementService.getInstance()
.withCredentialsProvider(credentialsProvider)
.withCodeWhispererEndpoint(awsQEndpointUrl)
.withCodeWhispererRegion(awsQRegion)
.withSdkRuntimeConfigurator(sdkInitializator)
.withConfig(clientOptions)
})

export const QConfigurationServerTokenProxy = QConfigurationServerToken(
Expand Down
29 changes: 1 addition & 28 deletions server/aws-lsp-codewhisperer/src/language-server/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,12 @@ import {
Position,
Workspace,
} from '@aws/language-server-runtimes/server-interface'
import { AWSError, ConfigurationOptions } from 'aws-sdk'
import { AWSError } from 'aws-sdk'
import { distance } from 'fastest-levenshtein'
import { Suggestion } from './codeWhispererService'
import { CodewhispererCompletionType } from './telemetry/types'
import { BUILDER_ID_START_URL, MISSING_BEARER_TOKEN_ERROR } from './constants'
import { ServerInfo } from '@aws/language-server-runtimes/server-interface/runtime'
import { HttpsProxyAgent } from 'hpagent'
export type SsoConnectionType = 'builderId' | 'identityCenter' | 'none'

export function isAwsError(error: unknown): error is AWSError {
Expand Down Expand Up @@ -130,29 +129,3 @@ export function getEndPositionForAcceptedSuggestion(content: string, startPositi
}
return endPosition
}

export const makeProxyConfig = (workspace: Workspace) => {
let additionalAwsConfig: ConfigurationOptions = {}
// short term solution to fix webworker bundling, broken due to this node.js specific logic in here
const isNodeJS: boolean = typeof process !== 'undefined' && process.release && process.release.name === 'node'
const proxyUrl = isNodeJS ? (process.env.HTTPS_PROXY ?? process.env.https_proxy) : undefined

if (proxyUrl) {
const certs = isNodeJS
? process.env.AWS_CA_BUNDLE
? [workspace.fs.readFileSync(process.env.AWS_CA_BUNDLE)]
: undefined
: undefined
const agent = new HttpsProxyAgent({
proxy: proxyUrl,
ca: certs,
})
additionalAwsConfig = {
httpOptions: {
agent: agent,
},
}
}

return additionalAwsConfig
}
Loading