microsoft/vscode-react-native
Publicmirrored from https://github.com/microsoft/vscode-react-nativeAvailable
src/extension/appcenter/codepush/release-strategy/legacyCodePushServiceClient.ts
111lines · modecode
| 1 | // Copyright (c) Microsoft Corporation. All rights reserved. |
| 2 | // Licensed under the MIT license. See LICENSE file in the project root for details. |
| 3 | |
| 4 | import * as request from "request"; |
| 5 | import { DefaultApp } from "../../command/commandParams"; |
| 6 | import * as fs from "fs"; |
| 7 | import * as Q from "q"; |
| 8 | import { models } from "../../api/index"; |
| 9 | |
| 10 | export interface PackageInfo { |
| 11 | appVersion?: string; |
| 12 | description?: string; |
| 13 | isDisabled?: boolean; |
| 14 | isMandatory?: boolean; |
| 15 | label?: string; |
| 16 | packageHash?: string; |
| 17 | rollout?: number; |
| 18 | } |
| 19 | |
| 20 | export interface Package extends PackageInfo { |
| 21 | /*generated*/ blobUrl: string; |
| 22 | /*generated*/ diffPackageMap?: PackageHashToBlobInfoMap; |
| 23 | /*generated*/ originalLabel?: string; // Set on "Promote" and "Rollback" |
| 24 | /*generated*/ originalDeployment?: string; // Set on "Promote" |
| 25 | /*generated*/ releasedBy?: string; // Set by commitPackage |
| 26 | /*generated*/ releaseMethod?: string; // "Upload", "Promote" or "Rollback". Unknown if unspecified |
| 27 | /*generated*/ size: number; |
| 28 | /*generated*/ uploadTime: number; |
| 29 | } |
| 30 | |
| 31 | export interface PackageHashToBlobInfoMap { |
| 32 | [packageHash: string]: BlobInfo; |
| 33 | } |
| 34 | |
| 35 | export interface BlobInfo { |
| 36 | size: number; |
| 37 | url: string; |
| 38 | } |
| 39 | |
| 40 | export type Headers = { [headerName: string]: string }; |
| 41 | |
| 42 | export default class LegacyCodePushServiceClient { |
| 43 | private static API_VERSION: number = 2; |
| 44 | |
| 45 | constructor(private accessKey: string, private app: DefaultApp, private serverUrl: string) { |
| 46 | if (!accessKey) throw new Error("A token must be specified to execute server calls."); |
| 47 | if (!serverUrl) throw new Error("A server url must be specified to execute server calls."); |
| 48 | } |
| 49 | |
| 50 | public release(deploymentName: string, filePath: string, updateMetadata: PackageInfo): Q.Promise<models.CodePushRelease> { |
| 51 | const appName = this.app.identifier; |
| 52 | return Q.Promise<models.CodePushRelease>((resolve, reject) => { |
| 53 | const options = { |
| 54 | url: this.serverUrl + this.urlEncode(`/apps/${this.appNameParam(appName)}/deployments/${deploymentName}/release`), |
| 55 | headers: { |
| 56 | "Accept": `application/vnd.code-push.v${LegacyCodePushServiceClient.API_VERSION}+json`, |
| 57 | "Authorization": `Bearer ${this.accessKey}`, |
| 58 | }, |
| 59 | formData: { |
| 60 | "packageInfo": JSON.stringify(updateMetadata), |
| 61 | "package": fs.createReadStream(filePath), |
| 62 | }, |
| 63 | }; |
| 64 | |
| 65 | request.post(options, (err: any, httpResponse: any) => { |
| 66 | if (err) { |
| 67 | reject(this.getErrorMessage(err, httpResponse)); |
| 68 | return; |
| 69 | } |
| 70 | if (httpResponse.statusCode === 201) { |
| 71 | resolve(<models.CodePushRelease>JSON.parse(httpResponse.body).package); |
| 72 | } else { |
| 73 | reject(this.getErrorMessage(null, httpResponse)); |
| 74 | return; |
| 75 | } |
| 76 | }); |
| 77 | }); |
| 78 | } |
| 79 | |
| 80 | // A template string tag function that URL encodes the substituted values |
| 81 | private urlEncode(strings: any, ...values: string[]): string { |
| 82 | let result = ""; |
| 83 | for (let i = 0; i < strings.length; i++) { |
| 84 | result += strings[i]; |
| 85 | if (i < values.length) { |
| 86 | result += encodeURIComponent(values[i]); |
| 87 | } |
| 88 | } |
| 89 | |
| 90 | return result; |
| 91 | } |
| 92 | |
| 93 | // IIS and Azure web apps have this annoying behavior where %2F (URL encoded slashes) in the URL are URL decoded |
| 94 | // BEFORE the requests reach node. That essentially means there's no good way to encode a "/" in the app name-- |
| 95 | // URL encodeing will work when running locally but when running on Azure it gets decoded before express sees it, |
| 96 | // so app names with slashes don't get routed properly. See https://github.com/tjanczuk/iisnode/issues/343 (or other sites |
| 97 | // that complain about the same) for some more info. I explored some IIS config based workarounds, but the previous |
| 98 | // link seems to say they won't work, so I eventually gave up on that. |
| 99 | // Anyway, to workaround this issue, we now allow the client to encode / characters as ~~ (two tildes, URL encoded). |
| 100 | // The CLI now converts / to ~~ if / appears in an app name, before passing that as part of the URL. This code below |
| 101 | // does the encoding. It's hack, but seems like the least bad option here. |
| 102 | // Eventually, this service will go away & we'll all be on Max's new service. That's hosted in docker, no more IIS, |
| 103 | // so this issue should go away then. |
| 104 | private appNameParam(appName: string) { |
| 105 | return appName.replace("/", "~~"); |
| 106 | } |
| 107 | |
| 108 | private getErrorMessage(error: Error | null, response: request.RequestResponse): string { |
| 109 | return response && response.body ? response.body : (error ? error.message : ""); |
| 110 | } |
| 111 | } |
| 112 | |