From 62785771502f431bc10ad28a47a7e855c9cfbafb Mon Sep 17 00:00:00 2001 From: DimitarTachev Date: Fri, 14 Sep 2018 14:05:15 +0300 Subject: [PATCH] refactor: start using getInitialFiles instead of applyChanges during the first Preview sync --- lib/definitions/preview-app-livesync.d.ts | 11 ++-- lib/services/livesync/livesync-service.ts | 26 +++----- .../playground/preview-app-constants.ts | 1 - .../preview-app-livesync-service.ts | 52 +++++++++------- .../playground/preview-sdk-service.ts | 25 +++----- npm-shrinkwrap.json | 19 +++++- package.json | 2 +- .../preview-app-livesync-service.ts | 59 ++++++++++++------- 8 files changed, 109 insertions(+), 86 deletions(-) diff --git a/lib/definitions/preview-app-livesync.d.ts b/lib/definitions/preview-app-livesync.d.ts index a725e8d160..181b7e0008 100644 --- a/lib/definitions/preview-app-livesync.d.ts +++ b/lib/definitions/preview-app-livesync.d.ts @@ -1,20 +1,19 @@ -import { FilePayload, Device } from "nativescript-preview-sdk"; +import { FilePayload, Device, FilesPayload } from "nativescript-preview-sdk"; declare global { interface IPreviewAppLiveSyncService { - initialize(): void; - initialSync(data: IPreviewAppLiveSyncData): Promise; + initialize(data: IPreviewAppLiveSyncData): void; syncFiles(data: IPreviewAppLiveSyncData, filesToSync: string[]): Promise; stopLiveSync(): Promise; } interface IPreviewAppLiveSyncData extends IProjectDir, IAppFilesUpdaterOptionsComposition, IEnvOptions { } - interface IPreviewSdkService extends NodeJS.EventEmitter { + interface IPreviewSdkService { qrCodeUrl: string; connectedDevices: Device[]; - initialize(): void; - applyChanges(files: FilePayload[], platform: string): Promise; + initialize(getInitialFiles: (device: Device) => Promise): void; + applyChanges(filesPayload: FilesPayload): Promise; stop(): void; } diff --git a/lib/services/livesync/livesync-service.ts b/lib/services/livesync/livesync-service.ts index a7328c8c9d..29a86a97fc 100644 --- a/lib/services/livesync/livesync-service.ts +++ b/lib/services/livesync/livesync-service.ts @@ -321,7 +321,14 @@ export class LiveSyncService extends EventEmitter implements IDebugLiveSyncServi let deviceDescriptorsForInitialSync: ILiveSyncDeviceInfo[] = []; if (liveSyncData.syncToPreviewApp) { - this.$previewAppLiveSyncService.initialize(); + this.$previewAppLiveSyncService.initialize({ + appFilesUpdaterOptions: { + bundle: liveSyncData.bundle, + release: liveSyncData.release + }, + env: liveSyncData.env, + projectDir: projectData.projectDir + }); } else { await this.$pluginsService.ensureAllDependenciesAreInstalled(projectData); // In case liveSync is called for a second time for the same projectDir. @@ -457,26 +464,11 @@ export class LiveSyncService extends EventEmitter implements IDebugLiveSyncServi } private async initialSync(projectData: IProjectData, liveSyncData: ILiveSyncInfo, deviceDescriptors: ILiveSyncDeviceInfo[]): Promise { - if (liveSyncData.syncToPreviewApp) { - await this.initialSyncToPreviewApp(projectData, liveSyncData); - } else { + if (!liveSyncData.syncToPreviewApp) { await this.initialCableSync(projectData, liveSyncData, deviceDescriptors); } } - private async initialSyncToPreviewApp(projectData: IProjectData, liveSyncData: ILiveSyncInfo) { - await this.addActionToChain(projectData.projectDir, async () => { - await this.$previewAppLiveSyncService.initialSync({ - appFilesUpdaterOptions: { - bundle: liveSyncData.bundle, - release: liveSyncData.release - }, - env: liveSyncData.env, - projectDir: projectData.projectDir - }); - }); - } - private async initialCableSync(projectData: IProjectData, liveSyncData: ILiveSyncInfo, deviceDescriptors: ILiveSyncDeviceInfo[]): Promise { const preparedPlatforms: string[] = []; const rebuiltInformation: ILiveSyncBuildInfo[] = []; diff --git a/lib/services/livesync/playground/preview-app-constants.ts b/lib/services/livesync/playground/preview-app-constants.ts index fd3d38d469..32b3f91d9b 100644 --- a/lib/services/livesync/playground/preview-app-constants.ts +++ b/lib/services/livesync/playground/preview-app-constants.ts @@ -1,5 +1,4 @@ export class PreviewSdkEventNames { - public static DEVICE_CONNECTED = "onDeviceConnected"; public static CHANGE_EVENT_NAME = "change"; } diff --git a/lib/services/livesync/playground/preview-app-livesync-service.ts b/lib/services/livesync/playground/preview-app-livesync-service.ts index 0d47b8089c..2733b66edf 100644 --- a/lib/services/livesync/playground/preview-app-livesync-service.ts +++ b/lib/services/livesync/playground/preview-app-livesync-service.ts @@ -1,5 +1,5 @@ import * as path from "path"; -import { FilePayload, Device } from "nativescript-preview-sdk"; +import { FilePayload, Device, FilesPayload } from "nativescript-preview-sdk"; import { PreviewSdkEventNames } from "./preview-app-constants"; import { APP_FOLDER_NAME, APP_RESOURCES_FOLDER_NAME, TNS_MODULES_FOLDER_NAME } from "../../../constants"; const isTextOrBinary = require('istextorbinary'); @@ -9,6 +9,7 @@ export class PreviewAppLiveSyncService implements IPreviewAppLiveSyncService { private excludedFiles = [".DS_Store"]; constructor(private $fs: IFileSystem, + private $errors: IErrors, private $hooksService: IHooksService, private $logger: ILogger, private $platformService: IPlatformService, @@ -19,15 +20,14 @@ export class PreviewAppLiveSyncService implements IPreviewAppLiveSyncService { private $projectFilesManager: IProjectFilesManager, private $projectFilesProvider: IProjectFilesProvider) { } - public initialize() { - this.$previewSdkService.initialize(); - } + public initialize(data: IPreviewAppLiveSyncData) { + this.$previewSdkService.initialize(async (device: Device) => { + if (!device) { + this.$errors.failWithoutHelp("Sending initial preview files without a specified device is not supported."); + } - public async initialSync(data: IPreviewAppLiveSyncData): Promise { - this.$previewSdkService.on(PreviewSdkEventNames.DEVICE_CONNECTED, async (device: Device) => { - this.$logger.trace("Found connected device", device); const filesToSyncMap: IDictionary = {}; - let promise = Promise.resolve(); + let promise = Promise.resolve(null); const startSyncFilesTimeout = async (platform: string) => { await promise .then(async () => { @@ -45,11 +45,13 @@ export class PreviewAppLiveSyncService implements IPreviewAppLiveSyncService { appFilesUpdaterOptions: data.appFilesUpdaterOptions, }, filesToSyncMap, -   startSyncFilesTimeout: startSyncFilesTimeout.bind(this) + startSyncFilesTimeout: startSyncFilesTimeout.bind(this) } -            }); + }); await this.$previewAppPluginsService.comparePluginsOnDevice(device); - await this.syncFilesForPlatformSafe(data, device.platform); + const payloads = await this.syncFilesForPlatformSafe(data, device.platform); + + return payloads; }); } @@ -71,33 +73,41 @@ export class PreviewAppLiveSyncService implements IPreviewAppLiveSyncService { } public async stopLiveSync(): Promise { - this.$previewSdkService.removeAllListeners(); this.$previewSdkService.stop(); } - private async syncFilesForPlatformSafe(data: IPreviewAppLiveSyncData, platform: string, files?: string[]): Promise { + private async syncFilesForPlatformSafe(data: IPreviewAppLiveSyncData, platform: string, files?: string[]): Promise { this.$logger.info(`Start syncing changes for platform ${platform}.`); try { const { appFilesUpdaterOptions, env, projectDir } = data; const projectData = this.$projectDataService.getProjectData(projectDir); + const platformData = this.$platformsData.getPlatformData(platform, projectData); await this.preparePlatform(platform, appFilesUpdaterOptions, env, projectData); - await this.applyChanges(projectData, platform, files); + let result: FilesPayload = null; + if (files && files.length) { + result = await this.applyChanges(platformData, projectData, files); + } else { + result = await this.getFilesPayload(platformData, projectData); + } this.$logger.info(`Successfully synced changes for platform ${platform}.`); + + return result; } catch (err) { this.$logger.warn(`Unable to apply changes for platform ${platform}. Error is: ${err}, ${JSON.stringify(err, null, 2)}.`); } } - private async applyChanges(projectData: IProjectData, platform: string, files: string[]) { - const platformData = this.$platformsData.getPlatformData(platform, projectData); - const payloads = this.getFilePayloads(platformData, projectData, _(files).uniq().value()); - await this.$previewSdkService.applyChanges(payloads, platform); + private async applyChanges(platformData: IPlatformData, projectData: IProjectData, files: string[]): Promise { + const payloads = this.getFilesPayload(platformData, projectData, _(files).uniq().value()); + await this.$previewSdkService.applyChanges(payloads); + + return payloads; } - private getFilePayloads(platformData: IPlatformData, projectData: IProjectData, files?: string[]): FilePayload[] { + private getFilesPayload(platformData: IPlatformData, projectData: IProjectData, files?: string[]): FilesPayload { const appFolderPath = path.join(projectData.projectDir, APP_FOLDER_NAME); const platformsAppFolderPath = path.join(platformData.appDestinationDirectoryPath, APP_FOLDER_NAME); @@ -127,7 +137,7 @@ export class PreviewAppLiveSyncService implements IPreviewAppLiveSyncService { }; if (filePayload.binary) { - const bitmap = this.$fs.readFile(file); + const bitmap = this.$fs.readFile(file); const base64 = Buffer.from(bitmap).toString('base64'); filePayload.fileContents = base64; } else { @@ -137,7 +147,7 @@ export class PreviewAppLiveSyncService implements IPreviewAppLiveSyncService { return filePayload; }); - return payloads; + return { files: payloads, platform: platformData.normalizedPlatformName.toLowerCase() }; } private async preparePlatform(platform: string, appFilesUpdaterOptions: IAppFilesUpdaterOptions, env: Object, projectData: IProjectData): Promise { diff --git a/lib/services/livesync/playground/preview-sdk-service.ts b/lib/services/livesync/playground/preview-sdk-service.ts index ee6ee3d310..46e273677e 100644 --- a/lib/services/livesync/playground/preview-sdk-service.ts +++ b/lib/services/livesync/playground/preview-sdk-service.ts @@ -1,9 +1,8 @@ -import { FilePayload, MessagingService, Config, Device, DeviceConnectedMessage, SdkCallbacks, ConnectedDevices } from "nativescript-preview-sdk"; -import { EventEmitter } from "events"; -import { PreviewSdkEventNames, PubnubKeys } from "./preview-app-constants"; +import { MessagingService, Config, Device, DeviceConnectedMessage, SdkCallbacks, ConnectedDevices, FilesPayload } from "nativescript-preview-sdk"; +import { PubnubKeys } from "./preview-app-constants"; const pako = require("pako"); -export class PreviewSdkService extends EventEmitter implements IPreviewSdkService { +export class PreviewSdkService implements IPreviewSdkService { private messagingService: MessagingService = null; private instanceId: string = null; public connectedDevices: Device[] = []; @@ -12,22 +11,21 @@ export class PreviewSdkService extends EventEmitter implements IPreviewSdkServic private $logger: ILogger, private $httpClient: Server.IHttpClient, private $config: IConfiguration) { - super(); } public get qrCodeUrl(): string { return `nsplay://boot?instanceId=${this.instanceId}&pKey=${PubnubKeys.PUBLISH_KEY}&sKey=${PubnubKeys.SUBSCRIBE_KEY}&template=play-ng`; } - public initialize(): void { - const initConfig = this.getInitConfig(); + public initialize(getInitialFiles: (device: Device) => Promise): void { + const initConfig = this.getInitConfig(getInitialFiles); this.messagingService = new MessagingService(); this.instanceId = this.messagingService.initialize(initConfig); } - public applyChanges(files: FilePayload[], platform: string): Promise { + public applyChanges(filesPayload: FilesPayload): Promise { return new Promise((resolve, reject) => { - this.messagingService.applyChanges(this.instanceId, { files, platform }, err => { + this.messagingService.applyChanges(this.instanceId, filesPayload, err => { if (err) { reject(err); } else { @@ -41,16 +39,12 @@ export class PreviewSdkService extends EventEmitter implements IPreviewSdkServic this.messagingService.stop(); } - private getInitConfig(): Config { + private getInitConfig(getInitialFiles: (device: Device) => Promise): Config { return { pubnubPublishKey: PubnubKeys.PUBLISH_KEY, pubnubSubscribeKey: PubnubKeys.SUBSCRIBE_KEY, callbacks: this.getCallbacks(), - getInitialFiles: async () => { - return { - files: [] - }; - } + getInitialFiles }; } @@ -71,7 +65,6 @@ export class PreviewSdkService extends EventEmitter implements IPreviewSdkServic }, onDeviceConnectedMessage: (deviceConnectedMessage: DeviceConnectedMessage) => ({ }), onDeviceConnected: (device: Device) => { - this.emit(PreviewSdkEventNames.DEVICE_CONNECTED, device); if (!_.includes(this.connectedDevices, device)) { this.connectedDevices.push(device); } diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index a19dbeb19e..117d96cf09 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -4124,6 +4124,19 @@ "strip-ansi": "^3.0.0", "supports-color": "^2.0.0" } + }, + "cli-table": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/cli-table/-/cli-table-0.3.1.tgz", + "integrity": "sha1-9TsFJmqLGguTSz0IIebi3FkUriM=", + "requires": { + "colors": "1.0.3" + } + }, + "colors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", + "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=" } } }, @@ -4453,9 +4466,9 @@ } }, "nativescript-preview-sdk": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/nativescript-preview-sdk/-/nativescript-preview-sdk-0.2.2.tgz", - "integrity": "sha512-+UXRbP8l7dQ53lNJbn5XfexApRabR8NUlpNAnLbKu8PGdkRXvTEK2RSCgZpkixYnOerFDCEAaE2EKgh+INFekA==", + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/nativescript-preview-sdk/-/nativescript-preview-sdk-0.2.4.tgz", + "integrity": "sha512-Osmj370clhWCyMajq52ez7TPB47PtcghVzU6jFI4MzO69k4RpXrxq2DsHN3kN4L6o09TLYu/xYzvFoL65QDfNg==", "requires": { "@types/pubnub": "4.0.2", "@types/shortid": "0.0.29", diff --git a/package.json b/package.json index 50a791148f..9dfb6bce31 100644 --- a/package.json +++ b/package.json @@ -56,7 +56,7 @@ "mkdirp": "0.5.1", "mute-stream": "0.0.5", "nativescript-doctor": "1.2.0", - "nativescript-preview-sdk": "0.2.2", + "nativescript-preview-sdk": "0.2.4", "open": "0.0.5", "ora": "2.0.0", "osenv": "0.1.3", diff --git a/test/services/playground/preview-app-livesync-service.ts b/test/services/playground/preview-app-livesync-service.ts index 9301d71a36..9b78fab4df 100644 --- a/test/services/playground/preview-app-livesync-service.ts +++ b/test/services/playground/preview-app-livesync-service.ts @@ -1,7 +1,6 @@ import { Yok } from "../../../lib/common/yok"; -import { LoggerStub } from "../../stubs"; -import { FilePayload, Device } from "nativescript-preview-sdk"; -import { EventEmitter } from "events"; +import { LoggerStub, ErrorsStub } from "../../stubs"; +import { FilePayload, Device, FilesPayload } from "nativescript-preview-sdk"; import { PreviewAppLiveSyncService } from "../../../lib/services/livesync/playground/preview-app-livesync-service"; import * as chai from "chai"; import * as path from "path"; @@ -16,23 +15,25 @@ interface ITestCase { } interface IActOptions { - emitDeviceConnected: boolean; + callGetInitialFiles: boolean; } interface IAssertOptions { checkWarnings?: boolean; isComparePluginsOnDeviceCalled?: boolean; + checkInitialFiles?: boolean; } interface IActInput { previewAppLiveSyncService?: IPreviewAppLiveSyncService; - previewSdkService?: IPreviewSdkService; + previewSdkService?: PreviewSdkServiceMock; projectFiles?: string[]; actOptions?: IActOptions; } let isComparePluginsOnDeviceCalled = false; let applyChangesParams: FilePayload[] = []; +let initialFiles: FilePayload[] = []; let readTextParams: string[] = []; let warnParams: string[] = []; const nativeFilesWarning = "Unable to apply changes from App_Resources folder. You need to build your application in order to make changes in App_Resources folder."; @@ -58,19 +59,28 @@ const syncFilesMockData = { release: false, bundle: false }, - env: { } + env: {} }; -class PreviewSdkServiceMock extends EventEmitter implements IPreviewSdkService { +class PreviewSdkServiceMock implements IPreviewSdkService { + public getInitialFiles: (device: Device) => Promise; + public get qrCodeUrl() { return "my_cool_qr_code_url"; } public connectedDevices: Device[] = [deviceMockData]; - public initialize() { /* empty block */ } + public initialize(getInitialFiles: (device: Device) => Promise) { + this.getInitialFiles = async (device) => { + const filesPayload = await getInitialFiles(device); + initialFiles.push(...filesPayload.files); - public async applyChanges(files: FilePayload[]) { - applyChangesParams.push(...files); + return filesPayload; + }; + } + + public async applyChanges(files: FilesPayload) { + applyChangesParams.push(...files.files); } public stop() { /* empty block */ } @@ -92,6 +102,7 @@ function createTestInjector(options?: { injector.register("platformService", { preparePlatform: async () => ({}) }); + injector.register("errors", ErrorsStub); injector.register("platformsData", { getPlatformData: () => ({ appDestinationDirectoryPath: platformsDirPath, @@ -140,7 +151,7 @@ function createTestInjector(options?: { return injector; } -function arrange(options?: { projectFiles ?: string[] }) { +function arrange(options?: { projectFiles?: string[] }) { options = options || {}; const injector = createTestInjector({ projectFiles: options.projectFiles }); @@ -158,19 +169,20 @@ async function initialSync(input?: IActInput) { const { previewAppLiveSyncService, previewSdkService, actOptions } = input; - await previewAppLiveSyncService.initialSync(syncFilesMockData); - if (actOptions.emitDeviceConnected) { - previewSdkService.emit("onDeviceConnected", deviceMockData); + await previewAppLiveSyncService.initialize(syncFilesMockData); + if (actOptions.callGetInitialFiles) { + await previewSdkService.getInitialFiles(deviceMockData); } } async function syncFiles(input?: IActInput) { - input = input || { }; + input = input || {}; const { previewAppLiveSyncService, previewSdkService, projectFiles, actOptions } = input; - if (actOptions.emitDeviceConnected) { - previewSdkService.emit("onDeviceConnected", deviceMockData); + await previewAppLiveSyncService.initialize(syncFilesMockData); + if (actOptions.callGetInitialFiles) { + await previewSdkService.getInitialFiles(deviceMockData); } await previewAppLiveSyncService.syncFiles(syncFilesMockData, projectFiles); @@ -178,8 +190,9 @@ async function syncFiles(input?: IActInput) { async function assert(expectedFiles: string[], options?: IAssertOptions) { options = options || {}; + const actualFiles = options.checkInitialFiles ? initialFiles : applyChangesParams; - chai.assert.deepEqual(applyChangesParams, mapFiles(expectedFiles)); + chai.assert.deepEqual(actualFiles, mapFiles(expectedFiles)); if (options.checkWarnings) { chai.assert.deepEqual(warnParams, [nativeFilesWarning]); @@ -193,6 +206,7 @@ async function assert(expectedFiles: string[], options?: IAssertOptions) { function reset() { isComparePluginsOnDeviceCalled = false; applyChangesParams = []; + initialFiles = []; readTextParams = []; warnParams = []; } @@ -215,7 +229,7 @@ function mapFiles(files: string[]): FilePayload[] { function setDefaults(testCase: ITestCase): ITestCase { if (!testCase.actOptions) { testCase.actOptions = { - emitDeviceConnected: true + callGetInitialFiles: true }; } @@ -315,7 +329,10 @@ describe("previewAppLiveSyncService", () => { const noAppFilesTestCases: ITestCase[] = [ { name: "should transfer correctly default project files", - expectedFiles: defaultProjectFiles + expectedFiles: defaultProjectFiles, + assertOptions: { + checkInitialFiles: true + } } ]; @@ -327,7 +344,7 @@ describe("previewAppLiveSyncService", () => { { name: "should show warning and not transfer native files when", testCases: nativeFilesTestCases.map(testCase => { - testCase.assertOptions = { checkWarnings: true }; + testCase.assertOptions = { checkWarnings: true }; return testCase; }) },