Skip to content

feat: use long living socket connection for sync #3841

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 28, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions lib/definitions/livesync.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,11 @@ interface IAndroidNativeScriptDeviceLiveSyncService extends INativeScriptDeviceL
}

interface IAndroidLivesyncTool {
/**
* The protocol version the current app(adnroid runtime) is using.
*/
protocolVersion: string;

/**
* Creates new socket connection.
* @param configuration - The configuration to the socket connection.
Expand Down Expand Up @@ -457,6 +462,11 @@ interface IAndroidLivesyncTool {
* @param error - Optional error for rejecting pending sync operations
*/
end(error?: Error): void;

/**
* Returns true if a connection has been already established
*/
hasConnection(): boolean;
}

interface IAndroidLivesyncToolConfiguration {
Expand Down
37 changes: 26 additions & 11 deletions lib/services/livesync/android-device-livesync-sockets-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@ import { LiveSyncPaths } from "../../common/constants";
import { AndroidLivesyncTool } from "./android-livesync-tool";
import * as path from "path";
import * as temp from "temp";
import * as semver from "semver";

export class AndroidDeviceSocketsLiveSyncService extends DeviceLiveSyncServiceBase implements IAndroidNativeScriptDeviceLiveSyncService, INativeScriptDeviceLiveSyncService {
private livesyncTool: IAndroidLivesyncTool;
private static STATUS_UPDATE_INTERVAL = 10000;
private static MINIMAL_VERSION_LONG_LIVING_CONNECTION = "0.2.0";

constructor(
private data: IProjectData,
Expand All @@ -20,19 +22,18 @@ export class AndroidDeviceSocketsLiveSyncService extends DeviceLiveSyncServiceBa
protected device: Mobile.IAndroidDevice,
private $options: ICommonOptions,
private $processService: IProcessService,
private $fs: IFileSystem) {
private $fs: IFileSystem,
private $devicePlatformsConstants: Mobile.IDevicePlatformsConstants) {
super($platformsData, device);
this.livesyncTool = this.$injector.resolve(AndroidLivesyncTool);
}

public async beforeLiveSyncAction(deviceAppData: Mobile.IDeviceAppData): Promise<void> {
const platformData = this.$platformsData.getPlatformData(deviceAppData.platform, this.data);
const projectFilesPath = path.join(platformData.appDestinationDirectoryPath, APP_FOLDER_NAME);
const pathToLiveSyncFile = temp.path({ prefix: "livesync" });
this.$fs.writeFile(pathToLiveSyncFile, "");
await this.device.fileSystem.putFile(pathToLiveSyncFile, this.getPathToLiveSyncFileOnDevice(deviceAppData.appIdentifier), deviceAppData.appIdentifier);
await this.device.applicationManager.startApplication({ appId: deviceAppData.appIdentifier, projectName: this.data.projectName, justLaunch: true });
await this.connectLivesyncTool(projectFilesPath, this.data.projectId);
await this.connectLivesyncTool(this.data.projectId);
}

private getPathToLiveSyncFileOnDevice(appIdentifier: string): string {
Expand All @@ -42,8 +43,11 @@ export class AndroidDeviceSocketsLiveSyncService extends DeviceLiveSyncServiceBa
public async finalizeSync(liveSyncInfo: ILiveSyncResultInfo, projectData: IProjectData): Promise<IAndroidLivesyncSyncOperationResult> {
try {
const result = await this.doSync(liveSyncInfo, projectData);
if (!semver.gte(this.livesyncTool.protocolVersion, AndroidDeviceSocketsLiveSyncService.MINIMAL_VERSION_LONG_LIVING_CONNECTION)) {
this.livesyncTool.end();
}
return result;
} finally {
} catch (e) {
this.livesyncTool.end();
}
}
Expand Down Expand Up @@ -85,6 +89,13 @@ export class AndroidDeviceSocketsLiveSyncService extends DeviceLiveSyncServiceBa
const canExecuteFastSync = !liveSyncInfo.isFullSync && this.canExecuteFastSyncForPaths(liveSyncInfo.modifiedFilesData, projectData, this.device.deviceInfo.platform);
if (!canExecuteFastSync || !liveSyncInfo.didRefresh) {
await this.device.applicationManager.restartApplication({ appId: liveSyncInfo.deviceAppData.appIdentifier, projectName: projectData.projectName });
if (this.livesyncTool.protocolVersion && semver.gte(this.livesyncTool.protocolVersion, AndroidDeviceSocketsLiveSyncService.MINIMAL_VERSION_LONG_LIVING_CONNECTION)) {
try {
await this.connectLivesyncTool(liveSyncInfo.deviceAppData.appIdentifier);
} catch (e) {
this.$logger.trace("Failed to connect after app restart.");
}
}
}
}

Expand Down Expand Up @@ -143,12 +154,16 @@ export class AndroidDeviceSocketsLiveSyncService extends DeviceLiveSyncServiceBa
return transferredLocalToDevicePaths;
}

private async connectLivesyncTool(projectFilesPath: string, appIdentifier: string) {
await this.livesyncTool.connect({
appIdentifier,
deviceIdentifier: this.device.deviceInfo.identifier,
appPlatformsPath: projectFilesPath
});
private async connectLivesyncTool(appIdentifier: string) {
const platformData = this.$platformsData.getPlatformData(this.$devicePlatformsConstants.Android, this.data);
const projectFilesPath = path.join(platformData.appDestinationDirectoryPath, APP_FOLDER_NAME);
if (!this.livesyncTool.hasConnection()) {
await this.livesyncTool.connect({
appIdentifier,
deviceIdentifier: this.device.deviceInfo.identifier,
appPlatformsPath: projectFilesPath
});
}
}

public getDeviceHashService(appIdentifier: string): Mobile.IAndroidDeviceHashService {
Expand Down
6 changes: 6 additions & 0 deletions lib/services/livesync/android-livesync-tool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ const TRY_CONNECT_TIMEOUT = 30000;
const DEFAULT_LOCAL_HOST_ADDRESS = "127.0.0.1";

export class AndroidLivesyncTool implements IAndroidLivesyncTool {
public protocolVersion: string;
private operationPromises: IDictionary<any>;
private socketError: string | Error;
private socketConnection: INetSocket;
Expand Down Expand Up @@ -179,6 +180,10 @@ export class AndroidLivesyncTool implements IAndroidLivesyncTool {
}
}

public hasConnection(): boolean {
return !!this.socketConnection;
}

private sendFileHeader(filePath: string): Promise<void> {
return new Promise((resolve, reject) => {
let error;
Expand Down Expand Up @@ -292,6 +297,7 @@ export class AndroidLivesyncTool implements IAndroidLivesyncTool {
const protocolVersion = versionBuffer.toString();
const appIdentifier = appIdentifierBuffer.toString();
this.$logger.trace(`Handle socket connection for app identifier: ${appIdentifier} with protocol version: ${protocolVersion}.`);
this.protocolVersion = protocolVersion;

this.socketConnection.on("data", (connectionData: NodeBuffer) => this.handleData(socket.uid, connectionData));
this.socketConnection.on("close", (hasError: boolean) => this.handleSocketClose(socket.uid, hasError));
Expand Down