server/aws-lsp-codewhisperer/src/language-server/configuration/qConfigurationServer.ts (152 lines of code) (raw):
import {
CancellationToken,
CredentialsProvider,
GetConfigurationFromServerParams,
InitializeParams,
Logging,
LSPErrorCodes,
ResponseError,
Server,
} from '@aws/language-server-runtimes/server-interface'
import {
AmazonQDeveloperProfile,
getListAllAvailableProfilesHandler,
ListAllAvailableProfilesHandler,
} from '../../shared/amazonQServiceManager/qDeveloperProfiles'
import { Customizations } from '../../client/token/codewhispererbearertokenclient'
import { AmazonQTokenServiceManager } from '../../shared/amazonQServiceManager/AmazonQTokenServiceManager'
import { Q_CONFIGURATION_SECTION } from '../../shared/constants'
import { AmazonQError } from '../../shared/amazonQServiceManager/errors'
const Q_CUSTOMIZATIONS = 'customizations'
const Q_DEVELOPER_PROFILES = 'developerProfiles'
export const Q_CUSTOMIZATIONS_CONFIGURATION_SECTION = `${Q_CONFIGURATION_SECTION}.${Q_CUSTOMIZATIONS}`
export const Q_DEVELOPER_PROFILES_CONFIGURATION_SECTION = `${Q_CONFIGURATION_SECTION}.${Q_DEVELOPER_PROFILES}`
export const QConfigurationServerToken =
(): Server =>
({ credentialsProvider, lsp, logging }) => {
let amazonQServiceManager: AmazonQTokenServiceManager
let serverConfigurationProvider: ServerConfigurationProvider
lsp.addInitializer((params: InitializeParams) => {
return {
capabilities: {},
awsServerCapabilities: {
configurationProvider: {
sections: [
Q_CONFIGURATION_SECTION,
Q_CUSTOMIZATIONS_CONFIGURATION_SECTION,
Q_DEVELOPER_PROFILES_CONFIGURATION_SECTION,
],
},
},
}
})
lsp.onInitialized(async () => {
amazonQServiceManager = AmazonQTokenServiceManager.getInstance()
serverConfigurationProvider = new ServerConfigurationProvider(
amazonQServiceManager,
credentialsProvider,
logging
)
})
lsp.extensions.onGetConfigurationFromServer(
async (params: GetConfigurationFromServerParams, token: CancellationToken) => {
const section = params.section
let customizations: Customizations
let developerProfiles: AmazonQDeveloperProfile[]
try {
switch (section) {
case Q_CONFIGURATION_SECTION:
;[customizations, developerProfiles] = await Promise.all([
serverConfigurationProvider.listAvailableCustomizations(),
serverConfigurationProvider.listAvailableProfiles(token),
])
throwIfCancelled(token)
return amazonQServiceManager.getEnableDeveloperProfileSupport()
? { customizations, developerProfiles }
: { customizations }
case Q_CUSTOMIZATIONS_CONFIGURATION_SECTION:
customizations = await serverConfigurationProvider.listAvailableCustomizations()
return customizations
case Q_DEVELOPER_PROFILES_CONFIGURATION_SECTION:
developerProfiles = await serverConfigurationProvider.listAvailableProfiles(token)
throwIfCancelled(token)
return developerProfiles
default:
break
}
} catch (error) {
if (error instanceof ResponseError) {
throw error
}
logging.error(`Failed to fetch resources for section ${section}: ${error}`)
throw new ResponseError(
LSPErrorCodes.RequestFailed,
`An unexpected error occured while fetching resource(s) for section: ${section}`
)
}
}
)
logging.log('Amazon Q Configuration server has been initialised')
return () => {}
}
function throwIfCancelled(token: CancellationToken) {
if (token.isCancellationRequested) {
throw new ResponseError(LSPErrorCodes.RequestCancelled, 'Request cancelled')
}
}
const ON_GET_CONFIGURATION_FROM_SERVER_ERROR_PREFIX = 'Failed to fetch: '
export class ServerConfigurationProvider {
private listAllAvailableProfilesHandler: ListAllAvailableProfilesHandler
constructor(
private serviceManager: AmazonQTokenServiceManager,
private credentialsProvider: CredentialsProvider,
private logging: Logging
) {
this.listAllAvailableProfilesHandler = getListAllAvailableProfilesHandler(
this.serviceManager.getServiceFactory()
)
}
async listAvailableProfiles(token: CancellationToken): Promise<AmazonQDeveloperProfile[]> {
if (!this.serviceManager.getEnableDeveloperProfileSupport()) {
this.logging.debug('Q developer profiles disabled - returning empty list')
return []
}
try {
const profiles = await this.listAllAvailableProfilesHandler({
connectionType: this.credentialsProvider.getConnectionType(),
logging: this.logging,
token: token,
})
return profiles
} catch (error) {
if (error instanceof AmazonQError) {
this.logging.error(error.message)
throw new ResponseError(
LSPErrorCodes.RequestFailed,
`${ON_GET_CONFIGURATION_FROM_SERVER_ERROR_PREFIX}${Q_DEVELOPER_PROFILES}`,
{
awsErrorCode: error.code,
}
)
}
throw this.getResponseError(
`${ON_GET_CONFIGURATION_FROM_SERVER_ERROR_PREFIX}${Q_DEVELOPER_PROFILES}`,
error
)
}
}
async listAvailableCustomizations(): Promise<Customizations> {
try {
const customizations = (
await this.serviceManager.getCodewhispererService().listAvailableCustomizations({ maxResults: 100 })
).customizations
return customizations
} catch (error) {
throw this.getResponseError(`${ON_GET_CONFIGURATION_FROM_SERVER_ERROR_PREFIX}${Q_CUSTOMIZATIONS}`, error)
}
}
private getResponseError(message: string, error: any): ResponseError {
this.logging.error(`${message}: ${error}`)
return new ResponseError(LSPErrorCodes.RequestFailed, message)
}
}