Skip to content

Commit 1c15132

Browse files
authored
[core-http-compat] Policy factory compat (Azure#22798)
* Create a policy wrapper for pipeline interop
1 parent b8afd33 commit 1c15132

11 files changed

+446
-33
lines changed

dataplane.code-workspace

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,9 @@
274274
},
275275
{
276276
"path": "sdk/instrumentation/opentelemetry-instrumentation-azure-sdk"
277+
},
278+
{
279+
"path": "sdk/core/core-http-compat"
277280
}
278281
],
279282
"settings": {

sdk/core/core-http-compat/review/core-http-compat.api.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { FullOperationResponse } from '@azure/core-client';
1010
import { HttpMethods } from '@azure/core-rest-pipeline';
1111
import { OperationArguments } from '@azure/core-client';
1212
import { OperationSpec } from '@azure/core-client';
13+
import { PipelinePolicy } from '@azure/core-rest-pipeline';
1314
import { ProxySettings } from '@azure/core-rest-pipeline';
1415
import { ServiceClient } from '@azure/core-client';
1516
import { ServiceClientOptions } from '@azure/core-client';
@@ -20,6 +21,9 @@ export interface CompatResponse extends Omit<FullOperationResponse, "request" |
2021
request: WebResourceLike;
2122
}
2223

24+
// @public
25+
export function createRequestPolicyFactoryPolicy(factories: RequestPolicyFactory[]): PipelinePolicy;
26+
2327
// @public (undocumented)
2428
export const disbaleKeepAlivePolicyName = "DisableKeepAlivePolicy";
2529

@@ -63,6 +67,18 @@ export interface HttpHeadersLike {
6367
}): RawHttpHeaders;
6468
}
6569

70+
// @public
71+
export enum HttpPipelineLogLevel {
72+
// (undocumented)
73+
ERROR = 1,
74+
// (undocumented)
75+
INFO = 3,
76+
// (undocumented)
77+
OFF = 0,
78+
// (undocumented)
79+
WARNING = 2
80+
}
81+
6682
// @public
6783
export interface KeepAliveOptions {
6884
enable?: boolean;
@@ -79,6 +95,29 @@ export interface RedirectOptions {
7995
maxRetries?: number;
8096
}
8197

98+
// @public
99+
export interface RequestPolicy {
100+
// (undocumented)
101+
sendRequest(httpRequest: WebResourceLike): Promise<CompatResponse>;
102+
}
103+
104+
// @public
105+
export interface RequestPolicyFactory {
106+
// (undocumented)
107+
create(nextPolicy: RequestPolicy, options: RequestPolicyOptionsLike): RequestPolicy;
108+
}
109+
110+
// @public
111+
export const requestPolicyFactoryPolicyName = "RequestPolicyFactoryPolicy";
112+
113+
// @public
114+
export interface RequestPolicyOptionsLike {
115+
// (undocumented)
116+
log(logLevel: HttpPipelineLogLevel, message: string): void;
117+
// (undocumented)
118+
shouldLog(logLevel: HttpPipelineLogLevel): boolean;
119+
}
120+
82121
// @public
83122
export type TransferProgressEvent = {
84123
loadedBytes: number;

sdk/core/core-http-compat/src/extendedClient.ts

Lines changed: 5 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,15 @@ import { createDisableKeepAlivePolicy } from "./policies/disableKeepAlivePolicy"
66
import { RedirectOptions } from "./policies/redirectOptions";
77
import { redirectPolicyName } from "@azure/core-rest-pipeline";
88
import {
9-
ServiceClient,
10-
ServiceClientOptions,
119
CommonClientOptions,
10+
FullOperationResponse,
1211
OperationArguments,
1312
OperationSpec,
14-
FullOperationResponse,
1513
RawResponseCallback,
14+
ServiceClient,
15+
ServiceClientOptions,
1616
} from "@azure/core-client";
17-
import { toWebResourceLike, toHttpHeaderLike, WebResourceLike, HttpHeadersLike } from "./util";
17+
import { toCompatResponse } from "./response";
1818

1919
/**
2020
* Options specific to Shim Clients.
@@ -94,28 +94,10 @@ export class ExtendedServiceClient extends ServiceClient {
9494

9595
if (lastResponse) {
9696
Object.defineProperty(result, "_response", {
97-
value: {
98-
...lastResponse,
99-
request: toWebResourceLike(lastResponse.request),
100-
headers: toHttpHeaderLike(lastResponse.headers),
101-
},
97+
value: toCompatResponse(lastResponse),
10298
});
10399
}
104100

105101
return result;
106102
}
107103
}
108-
109-
/**
110-
* Http Response that is compatible with the core-v1(core-http).
111-
*/
112-
export interface CompatResponse extends Omit<FullOperationResponse, "request" | "headers"> {
113-
/**
114-
* A description of a HTTP request to be made to a remote server.
115-
*/
116-
request: WebResourceLike;
117-
/**
118-
* A collection of HTTP header key/value pairs.
119-
*/
120-
headers: HttpHeadersLike;
121-
}

sdk/core/core-http-compat/src/index.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,16 @@ export {
1111
ExtendedServiceClientOptions,
1212
ExtendedCommonClientOptions,
1313
ExtendedClientOptions,
14-
CompatResponse,
1514
} from "./extendedClient";
15+
export { CompatResponse } from "./response";
16+
export {
17+
requestPolicyFactoryPolicyName,
18+
createRequestPolicyFactoryPolicy,
19+
RequestPolicyFactory,
20+
RequestPolicy,
21+
RequestPolicyOptionsLike,
22+
HttpPipelineLogLevel,
23+
} from "./policies/requestPolicyFactoryPolicy";
1624
export { KeepAliveOptions } from "./policies/keepAliveOptions";
1725
export { RedirectOptions } from "./policies/redirectOptions";
1826
export { disbaleKeepAlivePolicyName } from "./policies/disableKeepAlivePolicy";

sdk/core/core-http-compat/src/policies/disableKeepAlivePolicy.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
import {
55
PipelinePolicy,
66
PipelineRequest,
7-
SendRequest,
87
PipelineResponse,
8+
SendRequest,
99
} from "@azure/core-rest-pipeline";
1010

1111
export const disbaleKeepAlivePolicyName = "DisableKeepAlivePolicy";
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT license.
3+
4+
import {
5+
PipelinePolicy,
6+
PipelineRequest,
7+
PipelineResponse,
8+
SendRequest,
9+
} from "@azure/core-rest-pipeline";
10+
import { WebResourceLike, toPipelineRequest, toWebResourceLike } from "../util";
11+
import { CompatResponse, toCompatResponse, toPipelineResponse } from "../response";
12+
13+
/**
14+
* A compatible interface for core-http request policies
15+
*/
16+
export interface RequestPolicy {
17+
sendRequest(httpRequest: WebResourceLike): Promise<CompatResponse>;
18+
}
19+
20+
/**
21+
* An enum for compatibility with RequestPolicy
22+
*/
23+
export enum HttpPipelineLogLevel {
24+
ERROR = 1,
25+
INFO = 3,
26+
OFF = 0,
27+
WARNING = 2,
28+
}
29+
30+
/**
31+
* An interface for compatibility with RequestPolicy
32+
*/
33+
export interface RequestPolicyOptionsLike {
34+
log(logLevel: HttpPipelineLogLevel, message: string): void;
35+
shouldLog(logLevel: HttpPipelineLogLevel): boolean;
36+
}
37+
38+
const mockRequestPolicyOptions: RequestPolicyOptionsLike = {
39+
log(_logLevel: HttpPipelineLogLevel, _message: string): void {
40+
/* do nothing */
41+
},
42+
shouldLog(_logLevel: HttpPipelineLogLevel): boolean {
43+
return false;
44+
},
45+
};
46+
47+
/**
48+
* An interface for compatibility with core-http's RequestPolicyFactory
49+
*/
50+
export interface RequestPolicyFactory {
51+
create(nextPolicy: RequestPolicy, options: RequestPolicyOptionsLike): RequestPolicy;
52+
}
53+
54+
/**
55+
* The name of the RequestPolicyFactoryPolicy
56+
*/
57+
export const requestPolicyFactoryPolicyName = "RequestPolicyFactoryPolicy";
58+
59+
/**
60+
* A policy that wraps policies written for core-http.
61+
* @param factories - An array of `RequestPolicyFactory` objects from a core-http pipeline
62+
*/
63+
export function createRequestPolicyFactoryPolicy(
64+
factories: RequestPolicyFactory[]
65+
): PipelinePolicy {
66+
const orderedFactories = factories.slice().reverse();
67+
68+
return {
69+
name: requestPolicyFactoryPolicyName,
70+
async sendRequest(request: PipelineRequest, next: SendRequest): Promise<PipelineResponse> {
71+
let httpPipeline: RequestPolicy = {
72+
async sendRequest(httpRequest) {
73+
const response = await next(toPipelineRequest(httpRequest));
74+
return toCompatResponse(response, { createProxy: true });
75+
},
76+
};
77+
for (const factory of orderedFactories) {
78+
httpPipeline = factory.create(httpPipeline, mockRequestPolicyOptions);
79+
}
80+
81+
const webResourceLike = toWebResourceLike(request, { createProxy: true });
82+
const response = await httpPipeline.sendRequest(webResourceLike);
83+
return toPipelineResponse(response);
84+
},
85+
};
86+
}
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT license.
3+
4+
import { FullOperationResponse } from "@azure/core-client";
5+
import { PipelineResponse, createHttpHeaders } from "@azure/core-rest-pipeline";
6+
import {
7+
HttpHeadersLike,
8+
WebResourceLike,
9+
toHttpHeaderLike,
10+
toPipelineRequest,
11+
toWebResourceLike,
12+
} from "./util";
13+
/**
14+
* Http Response that is compatible with the core-v1(core-http).
15+
*/
16+
export interface CompatResponse extends Omit<FullOperationResponse, "request" | "headers"> {
17+
/**
18+
* A description of a HTTP request to be made to a remote server.
19+
*/
20+
request: WebResourceLike;
21+
/**
22+
* A collection of HTTP header key/value pairs.
23+
*/
24+
headers: HttpHeadersLike;
25+
}
26+
27+
const originalResponse = Symbol("Original FullOperationResponse");
28+
type ExtendedCompatResponse = CompatResponse & { [originalResponse]?: FullOperationResponse };
29+
30+
/**
31+
* A helper to convert response objects from the new pipeline back to the old one.
32+
* @param response - A response object from core-client.
33+
* @returns A response compatible with `HttpOperationResponse` from core-http.
34+
*/
35+
export function toCompatResponse(
36+
response: FullOperationResponse,
37+
options?: { createProxy?: boolean }
38+
): CompatResponse {
39+
let request = toWebResourceLike(response.request);
40+
let headers = toHttpHeaderLike(response.headers);
41+
if (options?.createProxy) {
42+
return new Proxy(response, {
43+
get(target, prop, receiver) {
44+
if (prop === "headers") {
45+
return headers;
46+
} else if (prop === "request") {
47+
return request;
48+
}
49+
return Reflect.get(target, prop, receiver);
50+
},
51+
set(target, prop, value, receiver) {
52+
if (prop === "headers") {
53+
headers = value;
54+
} else if (prop === "request") {
55+
request = value;
56+
}
57+
return Reflect.set(target, prop, value, receiver);
58+
},
59+
}) as unknown as CompatResponse;
60+
} else {
61+
return {
62+
...response,
63+
request,
64+
headers,
65+
};
66+
}
67+
}
68+
69+
/**
70+
* A helper to convert back to a PipelineResponse
71+
* @param compatResponse - A response compatible with `HttpOperationResponse` from core-http.
72+
*/
73+
export function toPipelineResponse(compatResponse: CompatResponse): PipelineResponse {
74+
const extendedCompatResponse = compatResponse as ExtendedCompatResponse;
75+
const response = extendedCompatResponse[originalResponse];
76+
const headers = createHttpHeaders(compatResponse.headers.toJson({ preserveCase: true }));
77+
if (response) {
78+
response.headers = headers;
79+
return response;
80+
} else {
81+
return {
82+
...compatResponse,
83+
headers,
84+
request: toPipelineRequest(compatResponse.request),
85+
};
86+
}
87+
}

0 commit comments

Comments
 (0)