/// import { UpdateCheckResponse, UpdateCheckRequest, DeploymentStatusReport, DownloadReport } from "rest-definitions"; export module Http { export const enum Verb { GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, CONNECT, PATCH } export interface Response { statusCode: number; body?: string; } export interface Requester { request(verb: Verb, url: string, callback: Callback): void; request(verb: Verb, url: string, requestBody: string, callback: Callback): void; } } // All fields are non-nullable, except when retrieving the currently running package on the first run of the app, // in which case only the appVersion is compulsory export interface Package { deploymentKey: string; description: string; label: string; appVersion: string; isMandatory: boolean; packageHash: string; packageSize: number; } export interface RemotePackage extends Package { downloadUrl: string; } export interface NativeUpdateNotification { updateAppVersion: boolean; // Always true appVersion: string; } export interface LocalPackage extends Package { localPath: string; } export interface Callback { (error: Error, parameter: T): void; } export interface Configuration { appVersion: string; clientUniqueId: string; deploymentKey: string; serverUrl: string; ignoreAppVersion?: boolean } export class AcquisitionStatus { public static DeploymentSucceeded = "DeploymentSucceeded"; public static DeploymentFailed = "DeploymentFailed"; } export class AcquisitionManager { private _appVersion: string; private _clientUniqueId: string; private _deploymentKey: string; private _httpRequester: Http.Requester; private _ignoreAppVersion: boolean; private _serverUrl: string; constructor(httpRequester: Http.Requester, configuration: Configuration) { this._httpRequester = httpRequester; this._serverUrl = configuration.serverUrl; if (this._serverUrl.slice(-1) !== "/") { this._serverUrl += "/"; } this._appVersion = configuration.appVersion; this._clientUniqueId = configuration.clientUniqueId; this._deploymentKey = configuration.deploymentKey; this._ignoreAppVersion = configuration.ignoreAppVersion; } public queryUpdateWithCurrentPackage(currentPackage: Package, callback?: Callback): void { if (!currentPackage || !currentPackage.appVersion) { throw new Error("Calling common acquisition SDK with incorrect package"); // Unexpected; indicates error in our implementation } var updateRequest: UpdateCheckRequest = { deploymentKey: this._deploymentKey, appVersion: currentPackage.appVersion, packageHash: currentPackage.packageHash, isCompanion: this._ignoreAppVersion, label: currentPackage.label, clientUniqueId: this._clientUniqueId }; var requestUrl: string = this._serverUrl + "updateCheck?" + queryStringify(updateRequest); this._httpRequester.request(Http.Verb.GET, requestUrl, (error: Error, response: Http.Response) => { if (error) { callback(error, /*remotePackage=*/ null); return; } if (response.statusCode !== 200) { callback(new Error(response.statusCode + ": " + response.body), /*remotePackage=*/ null); return; } try { var responseObject = JSON.parse(response.body); var updateInfo: UpdateCheckResponse = responseObject.updateInfo; } catch (error) { callback(error, /*remotePackage=*/ null); return; } if (!updateInfo) { callback(error, /*remotePackage=*/ null); return; } else if (updateInfo.updateAppVersion || updateInfo.shouldRunBinaryVersion) { var returnUpdateInfo: any = {}; if (updateInfo.shouldRunBinaryVersion) { returnUpdateInfo.shouldRunBinaryVersion = true; } if (updateInfo.updateAppVersion) { returnUpdateInfo.updateAppVersion = true; returnUpdateInfo.appVersion = updateInfo.appVersion; } callback(/*error=*/ null, returnUpdateInfo); return; } else if (!updateInfo.isAvailable) { callback(/*error=*/ null, /*remotePackage=*/ null); return; } var remotePackage: RemotePackage = { deploymentKey: this._deploymentKey, description: updateInfo.description, label: updateInfo.label, appVersion: updateInfo.appVersion, isMandatory: updateInfo.isMandatory, packageHash: updateInfo.packageHash, packageSize: updateInfo.packageSize, downloadUrl: updateInfo.downloadURL }; callback(/*error=*/ null, remotePackage); }); } public reportStatusDeploy(deployedPackage?: Package, status?: string, previousLabelOrAppVersion?: string, previousDeploymentKey?: string, callback?: Callback): void { var url: string = this._serverUrl + "reportStatus/deploy"; var body: DeploymentStatusReport = { appVersion: this._appVersion, deploymentKey: this._deploymentKey }; if (this._clientUniqueId) { body.clientUniqueId = this._clientUniqueId; } if (deployedPackage) { body.label = deployedPackage.label; body.appVersion = deployedPackage.appVersion; switch (status) { case AcquisitionStatus.DeploymentSucceeded: case AcquisitionStatus.DeploymentFailed: body.status = status; break; default: if (callback) { if (!status) { callback(new Error("Missing status argument."), /*not used*/ null); } else { callback(new Error("Unrecognized status \"" + status + "\"."), /*not used*/ null); } } return; } } if (previousLabelOrAppVersion) { body.previousLabelOrAppVersion = previousLabelOrAppVersion; } if (previousDeploymentKey) { body.previousDeploymentKey = previousDeploymentKey; } callback = typeof arguments[arguments.length - 1] === "function" && arguments[arguments.length - 1]; this._httpRequester.request(Http.Verb.POST, url, JSON.stringify(body), (error: Error, response: Http.Response): void => { if (callback) { if (error) { callback(error, /*not used*/ null); return; } if (response.statusCode !== 200) { callback(new Error(response.statusCode + ": " + response.body), /*not used*/ null); return; } callback(/*error*/ null, /*not used*/ null); } }); } public reportStatusDownload(downloadedPackage: Package, callback?: Callback): void { var url: string = this._serverUrl + "reportStatus/download"; var body: DownloadReport = { clientUniqueId: this._clientUniqueId, deploymentKey: this._deploymentKey, label: downloadedPackage.label }; this._httpRequester.request(Http.Verb.POST, url, JSON.stringify(body), (error: Error, response: Http.Response): void => { if (callback) { if (error) { callback(error, /*not used*/ null); return; } if (response.statusCode !== 200) { callback(new Error(response.statusCode + ": " + response.body), /*not used*/ null); return; } callback(/*error*/ null, /*not used*/ null); } }); } } function queryStringify(object: Object): string { var queryString = ""; var isFirst: boolean = true; for (var property in object) { if (object.hasOwnProperty(property)) { var value: string = (object)[property]; if (!isFirst) { queryString += "&"; } queryString += encodeURIComponent(property) + "="; if (value !== null && typeof value !== "undefined") { queryString += encodeURIComponent(value); } isFirst = false; } } return queryString; }