Skip to content

Commit 5a97c89

Browse files
authored
Merge pull request #6390 from jpinkney-aws/fetcher
refactor(core): Improve httpResourceFetcher API
2 parents 16c0228 + f727e0e commit 5a97c89

File tree

14 files changed

+49
-155
lines changed

14 files changed

+49
-155
lines changed

packages/core/src/lambda/utils.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,6 @@ import { CloudFormationClient } from '../shared/clients/cloudFormationClient'
1313
import { LambdaClient } from '../shared/clients/lambdaClient'
1414
import { getFamily, getNodeMajorVersion, RuntimeFamily } from './models/samLambdaRuntime'
1515
import { getLogger } from '../shared/logger'
16-
import { ResourceFetcher } from '../shared/resourcefetcher/resourcefetcher'
17-
import { CompositeResourceFetcher } from '../shared/resourcefetcher/compositeResourceFetcher'
1816
import { HttpResourceFetcher } from '../shared/resourcefetcher/httpResourceFetcher'
1917
import { FileResourceFetcher } from '../shared/resourcefetcher/fileResourceFetcher'
2018
import { sampleRequestManifestPath } from './constants'
@@ -99,7 +97,7 @@ interface SampleRequestManifest {
9997

10098
export async function getSampleLambdaPayloads(): Promise<SampleRequest[]> {
10199
const logger = getLogger()
102-
const sampleInput = await makeSampleRequestManifestResourceFetcher().get()
100+
const sampleInput = await getSampleRequestManifest()
103101

104102
if (!sampleInput) {
105103
throw new Error('Unable to retrieve Sample Request manifest')
@@ -120,9 +118,11 @@ export async function getSampleLambdaPayloads(): Promise<SampleRequest[]> {
120118
return inputs
121119
}
122120

123-
function makeSampleRequestManifestResourceFetcher(): ResourceFetcher {
124-
return new CompositeResourceFetcher(
125-
new HttpResourceFetcher(sampleRequestManifestPath, { showUrl: true }),
126-
new FileResourceFetcher(globals.manifestPaths.lambdaSampleRequests)
127-
)
121+
async function getSampleRequestManifest(): Promise<string | undefined> {
122+
const httpResp = await new HttpResourceFetcher(sampleRequestManifestPath, { showUrl: true }).get()
123+
if (!httpResp) {
124+
const fileResp = new FileResourceFetcher(globals.manifestPaths.lambdaSampleRequests)
125+
return fileResp.get()
126+
}
127+
return httpResp.text()
128128
}

packages/core/src/lambda/vue/configEditor/samInvokeBackend.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,8 @@ export class SamInvokeWebview extends VueWebview {
170170
return
171171
}
172172
const sampleUrl = `${sampleRequestPath}${pickerResponse.filename}`
173-
const sample = (await new HttpResourceFetcher(sampleUrl, { showUrl: true }).get()) ?? ''
173+
const resp = await new HttpResourceFetcher(sampleUrl, { showUrl: true }).get()
174+
const sample = (await resp?.text()) ?? ''
174175

175176
return sample
176177
} catch (err) {

packages/core/src/lambda/vue/remoteInvoke/invokeLambda.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,8 @@ export class RemoteInvokeWebview extends VueWebview {
219219
return
220220
}
221221
const sampleUrl = `${sampleRequestPath}${pickerResponse.filename}`
222-
const sample = (await new HttpResourceFetcher(sampleUrl, { showUrl: true }).get()) ?? ''
222+
const resp = await new HttpResourceFetcher(sampleUrl, { showUrl: true }).get()
223+
const sample = (await resp?.text()) ?? ''
223224

224225
return sample
225226
} catch (err) {

packages/core/src/shared/resourcefetcher/compositeResourceFetcher.ts

Lines changed: 0 additions & 34 deletions
This file was deleted.

packages/core/src/shared/resourcefetcher/httpResourceFetcher.ts

Lines changed: 13 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,11 @@ import { getLogger, Logger } from '../logger'
88
import { ResourceFetcher } from './resourcefetcher'
99
import { Timeout, CancelEvent } from '../utilities/timeoutUtils'
1010
import request, { RequestError } from '../request'
11+
import { withRetries } from '../utilities/functionUtils'
1112

1213
type RequestHeaders = { eTag?: string; gZip?: boolean }
1314

14-
export class HttpResourceFetcher implements ResourceFetcher {
15+
export class HttpResourceFetcher implements ResourceFetcher<Response> {
1516
private readonly logger: Logger = getLogger()
1617

1718
/**
@@ -20,27 +21,27 @@ export class HttpResourceFetcher implements ResourceFetcher {
2021
* @param params Additional params for the fetcher
2122
* @param {boolean} params.showUrl Whether or not to the URL in log statements.
2223
* @param {string} params.friendlyName If URL is not shown, replaces the URL with this text.
23-
* @param {function} params.onSuccess Function to execute on successful request. No effect if piping to a location.
2424
* @param {Timeout} params.timeout Timeout token to abort/cancel the request. Similar to `AbortSignal`.
25+
* @param {number} params.retries The number of retries a get request should make if one fails
2526
*/
2627
public constructor(
2728
private readonly url: string,
2829
private readonly params: {
2930
showUrl: boolean
3031
friendlyName?: string
31-
onSuccess?(contents: string): void
3232
timeout?: Timeout
33+
retries?: number
3334
}
3435
) {}
3536

3637
/**
37-
* Returns the contents of the resource, or undefined if the resource could not be retrieved.
38-
*
39-
* @param pipeLocation Optionally pipe the download to a file system location
38+
* Returns the response of the resource, or undefined if the response failed could not be retrieved.
4039
*/
41-
public get(): Promise<string | undefined> {
40+
public get(): Promise<Response | undefined> {
4241
this.logger.verbose(`downloading: ${this.logText()}`)
43-
return this.downloadRequest()
42+
return withRetries(() => this.downloadRequest(), {
43+
maxRetries: this.params.retries ?? 1,
44+
})
4445
}
4546

4647
/**
@@ -69,26 +70,16 @@ export class HttpResourceFetcher implements ResourceFetcher {
6970
this.logger.verbose(`E-Tag, ${eTagResponse}, matched. No content downloaded from: ${this.url}`)
7071
} else {
7172
this.logger.verbose(`No E-Tag match. Downloaded content from: ${this.logText()}`)
72-
if (this.params.onSuccess) {
73-
this.params.onSuccess(contents)
74-
}
7573
}
7674

7775
return { content: contents, eTag: eTagResponse }
7876
}
7977

80-
private async downloadRequest(): Promise<string | undefined> {
78+
private async downloadRequest(): Promise<Response | undefined> {
8179
try {
82-
// HACK(?): receiving JSON as a string without `toString` makes it so we can't deserialize later
8380
const resp = await this.getResponseFromGetRequest(this.params.timeout)
84-
const contents = (await resp.text()).toString()
85-
if (this.params.onSuccess) {
86-
this.params.onSuccess(contents)
87-
}
88-
8981
this.logger.verbose(`downloaded: ${this.logText()}`)
90-
91-
return contents
82+
return resp
9283
} catch (err) {
9384
const error = err as RequestError
9485
this.logger.verbose(
@@ -150,7 +141,8 @@ export async function getPropertyFromJsonUrl(
150141
fetcher?: HttpResourceFetcher
151142
): Promise<any | undefined> {
152143
const resourceFetcher = fetcher ?? new HttpResourceFetcher(url, { showUrl: true })
153-
const result = await resourceFetcher.get()
144+
const resp = await resourceFetcher.get()
145+
const result = await resp?.text()
154146
if (result) {
155147
try {
156148
const json = JSON.parse(result)

packages/core/src/shared/resourcefetcher/resourcefetcher.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@
44
*/
55

66
// TODO: this is just a "thunk". Replace it with something more generic.
7-
export interface ResourceFetcher {
7+
export interface ResourceFetcher<T = string> {
88
/**
99
* Returns the contents of the resource, or undefined if the resource could not be retrieved.
1010
* Implementations are expected to handle Errors.
1111
*/
12-
get(): Promise<string | undefined>
12+
get(): Promise<T | undefined>
1313
}

packages/core/src/shared/sam/debugger/csharpSamDebug.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -196,8 +196,8 @@ async function downloadInstallScript(debuggerPath: string): Promise<string> {
196196
installScriptPath = path.join(debuggerPath, 'installVsdbgScript.sh')
197197
}
198198

199-
const installScriptFetcher = new HttpResourceFetcher(installScriptUrl, { showUrl: true })
200-
const installScript = await installScriptFetcher.get()
199+
const installScriptFetcher = await new HttpResourceFetcher(installScriptUrl, { showUrl: true }).get()
200+
const installScript = await installScriptFetcher?.text()
201201
if (!installScript) {
202202
throw Error(`Failed to download ${installScriptUrl}`)
203203
}

packages/core/src/shared/schemas.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,8 @@ export async function updateSchemaFromRemote(params: {
225225

226226
try {
227227
const httpFetcher = new HttpResourceFetcher(params.url, { showUrl: true })
228-
const content = await httpFetcher.get()
228+
const resp = await httpFetcher.get()
229+
const content = await resp?.text()
229230

230231
if (!content) {
231232
throw new Error(`failed to resolve schema: ${params.destination}`)

packages/core/src/stepFunctions/utils.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -179,8 +179,8 @@ async function httpsGetRequestWrapper(url: string): Promise<string> {
179179
const logger = getLogger()
180180
logger.verbose('Step Functions is getting content...')
181181

182-
const fetcher = new HttpResourceFetcher(url, { showUrl: true })
183-
const val = await fetcher.get()
182+
const fetcher = await new HttpResourceFetcher(url, { showUrl: true }).get()
183+
const val = await fetcher?.text()
184184

185185
if (!val) {
186186
const message = 'Step Functions was unable to get content.'

packages/core/src/test/lambda/vue/remoteInvoke/invokeLambda.test.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import { FakeExtensionContext } from '../../../fakeExtensionContext'
2121
import * as samCliRemoteTestEvent from '../../../../shared/sam/cli/samCliRemoteTestEvent'
2222
import { TestEventsOperation, SamCliRemoteTestEventsParameters } from '../../../../shared/sam/cli/samCliRemoteTestEvent'
2323
import { assertLogsContain } from '../../../globalSetup.test'
24+
import { createResponse } from '../../../testUtil'
2425

2526
describe('RemoteInvokeWebview', () => {
2627
let outputChannel: vscode.OutputChannel
@@ -394,7 +395,7 @@ describe('RemoteInvokeWebview', () => {
394395
createQuickPickStub.returns({})
395396
promptUserStub.resolves([{ label: 'testEvent', filename: 'testEvent.json' }])
396397
verifySinglePickerOutputStub.returns({ label: 'testEvent', filename: 'testEvent.json' })
397-
httpFetcherStub.resolves(mockSampleContent)
398+
httpFetcherStub.resolves(createResponse(mockSampleContent))
398399

399400
const result = await remoteInvokeWebview.getSamplePayload()
400401

0 commit comments

Comments
 (0)