fix: desktop interop

This commit is contained in:
Baptiste Grob
2020-09-03 23:33:11 +02:00
parent 568fb14f3a
commit 35fe78e49e
4 changed files with 47 additions and 58 deletions

View File

@@ -1,13 +1,24 @@
import { PurePayload, Environment } from "snjs";
/** Platform-specific (i-e Electron/browser) behavior is handled by a Bridge object. */ /** Platform-specific (i-e Electron/browser) behavior is handled by a Bridge object. */
export interface Bridge { export interface Bridge {
environment: Environment,
getKeychainValue(): Promise<unknown>; getKeychainValue(): Promise<unknown>;
setKeychainValue(value: any): Promise<void>; setKeychainValue(value: any): Promise<void>;
clearKeychainValue(): Promise<void>; clearKeychainValue(): Promise<void>;
extensionsServerHost?: string;
syncComponents(payloads: PurePayload[]): void;
onMajorDataChange(): void;
onInitialDataLoad(): void;
onSearch(text?: string): void;
} }
const KEYCHAIN_STORAGE_KEY = 'keychain'; const KEYCHAIN_STORAGE_KEY = 'keychain';
export class BrowserBridge implements Bridge { export class BrowserBridge implements Bridge {
environment = Environment.Web;
async getKeychainValue(): Promise<unknown> { async getKeychainValue(): Promise<unknown> {
const value = localStorage.getItem(KEYCHAIN_STORAGE_KEY); const value = localStorage.getItem(KEYCHAIN_STORAGE_KEY);
@@ -23,4 +34,15 @@ export class BrowserBridge implements Bridge {
async clearKeychainValue(): Promise<void> { async clearKeychainValue(): Promise<void> {
localStorage.removeItem(KEYCHAIN_STORAGE_KEY); localStorage.removeItem(KEYCHAIN_STORAGE_KEY);
} }
/** No-ops */
syncComponents() {
}
onMajorDataChange() {
}
onInitialDataLoad() {
}
onSearch() {
}
} }

View File

@@ -1,9 +1,10 @@
import { SNComponent, PurePayload, ComponentMutator, AppDataField } from 'snjs'; import { SNComponent, PurePayload, ComponentMutator, AppDataField, ContentType } from 'snjs';
/* eslint-disable camelcase */ /* eslint-disable camelcase */
import { WebApplication } from '@/ui_models/application'; import { WebApplication } from '@/ui_models/application';
// An interface used by the Desktop app to interact with SN // An interface used by the Desktop app to interact with SN
import { isDesktopApplication } from '@/utils'; import { isDesktopApplication } from '@/utils';
import { EncryptionIntent, ApplicationService, ApplicationEvent, removeFromArray } from 'snjs'; import { EncryptionIntent, ApplicationService, ApplicationEvent, removeFromArray } from 'snjs';
import { Bridge } from './bridge';
type UpdateObserverCallback = (component: SNComponent) => void type UpdateObserverCallback = (component: SNComponent) => void
type ComponentActivationCallback = (payload: PurePayload) => void type ComponentActivationCallback = (payload: PurePayload) => void
@@ -23,18 +24,14 @@ export class DesktopManager extends ApplicationService {
isDesktop = isDesktopApplication(); isDesktop = isDesktopApplication();
dataLoaded = false dataLoaded = false
dataLoadHandler?: () => void
majorDataChangeHandler?: () => void
extServerHost?: string
installationSyncHandler?: (payloads: PurePayload[]) => void
installComponentHandler?: (payload: PurePayload) => void
lastSearchedText?: string lastSearchedText?: string
searchHandler?: (text?: string) => void private removeComponentObserver?: () => void;
constructor( constructor(
$rootScope: ng.IRootScopeService, $rootScope: ng.IRootScopeService,
$timeout: ng.ITimeoutService, $timeout: ng.ITimeoutService,
application: WebApplication application: WebApplication,
private bridge: Bridge,
) { ) {
super(application); super(application);
this.$rootScope = $rootScope; this.$rootScope = $rootScope;
@@ -48,6 +45,8 @@ export class DesktopManager extends ApplicationService {
deinit() { deinit() {
this.componentActivationObservers.length = 0; this.componentActivationObservers.length = 0;
this.updateObservers.length = 0; this.updateObservers.length = 0;
this.removeComponentObserver?.();
this.removeComponentObserver = undefined;
super.deinit(); super.deinit();
} }
@@ -55,33 +54,29 @@ export class DesktopManager extends ApplicationService {
super.onAppEvent(eventName); super.onAppEvent(eventName);
if (eventName === ApplicationEvent.LocalDataLoaded) { if (eventName === ApplicationEvent.LocalDataLoaded) {
this.dataLoaded = true; this.dataLoaded = true;
if (this.dataLoadHandler) { this.bridge.onInitialDataLoad();
this.dataLoadHandler();
}
} else if (eventName === ApplicationEvent.MajorDataChange) { } else if (eventName === ApplicationEvent.MajorDataChange) {
if (this.majorDataChangeHandler) { this.bridge.onMajorDataChange();
this.majorDataChangeHandler();
}
} }
} }
saveBackup() { saveBackup() {
this.majorDataChangeHandler && this.majorDataChangeHandler(); this.bridge.onMajorDataChange();
} }
getExtServerHost() { getExtServerHost() {
console.assert( console.assert(
this.extServerHost, this.bridge.extensionsServerHost,
'extServerHost is null' 'extServerHost is null'
); );
return this.extServerHost; return this.bridge.extensionsServerHost;
} }
/** /**
* Sending a component in its raw state is really slow for the desktop app * Sending a component in its raw state is really slow for the desktop app
* Keys are not passed into ItemParams, so the result is not encrypted * Keys are not passed into ItemParams, so the result is not encrypted
*/ */
async convertComponentForTransmission(component: SNComponent) { convertComponentForTransmission(component: SNComponent) {
return this.application!.protocolService!.payloadByEncryptingPayload( return this.application!.protocolService!.payloadByEncryptingPayload(
component.payloadRepresentation(), component.payloadRepresentation(),
EncryptionIntent.FileDecrypted EncryptionIntent.FileDecrypted
@@ -96,16 +91,14 @@ export class DesktopManager extends ApplicationService {
Promise.all(components.map((component) => { Promise.all(components.map((component) => {
return this.convertComponentForTransmission(component); return this.convertComponentForTransmission(component);
})).then((payloads) => { })).then((payloads) => {
this.installationSyncHandler!(payloads); this.bridge.syncComponents(
payloads.filter(payload =>
!payload.errorDecrypting && !payload.waitingForKey
)
);
}); });
} }
async installComponent(component: SNComponent) {
this.installComponentHandler!(
await this.convertComponentForTransmission(component)
);
}
registerUpdateObserver(callback: UpdateObserverCallback) { registerUpdateObserver(callback: UpdateObserverCallback) {
const observer = { const observer = {
callback: callback callback: callback
@@ -121,7 +114,7 @@ export class DesktopManager extends ApplicationService {
return; return;
} }
this.lastSearchedText = text; this.lastSearchedText = text;
this.searchHandler && this.searchHandler(text); this.bridge.onSearch(text);
} }
redoSearch() { redoSearch() {
@@ -130,11 +123,6 @@ export class DesktopManager extends ApplicationService {
} }
} }
// Pass null to cancel search
desktop_setSearchHandler(handler: (text?: string) => void) {
this.searchHandler = handler;
}
desktop_windowGainedFocus() { desktop_windowGainedFocus() {
this.$rootScope.$broadcast('window-gained-focus'); this.$rootScope.$broadcast('window-gained-focus');
} }
@@ -199,38 +187,16 @@ export class DesktopManager extends ApplicationService {
}); });
} }
/* Used to resolve 'sn://' */ onExtensionsReady() {
desktop_setExtServerHost(host: string) {
this.extServerHost = host;
this.webApplication.getAppState().desktopExtensionsReady(); this.webApplication.getAppState().desktopExtensionsReady();
} }
desktop_setComponentInstallationSyncHandler(handler: (payloads: PurePayload[]) => void) { desktop_requestBackupFile() {
this.installationSyncHandler = handler; return this.application!.createBackupFile(
}
desktop_setInstallComponentHandler(handler: (payload: PurePayload) => void) {
this.installComponentHandler = handler;
}
desktop_setInitialDataLoadHandler(handler: () => void) {
this.dataLoadHandler = handler;
if (this.dataLoaded) {
this.dataLoadHandler();
}
}
async desktop_requestBackupFile(callback: (data: any) => void) {
const data = await this.application!.createBackupFile(
undefined, undefined,
undefined, undefined,
true true
); );
callback(data);
}
desktop_setMajorDataChangeHandler(handler: () => void) {
this.majorDataChangeHandler = handler;
} }
desktop_didBeginBackup() { desktop_didBeginBackup() {

View File

@@ -64,7 +64,7 @@ export class WebApplication extends SNApplication {
bridge bridge
); );
super( super(
Environment.Web, bridge.environment,
platformFromString(getPlatformString()), platformFromString(getPlatformString()),
deviceInterface, deviceInterface,
new SNWebCrypto(), new SNWebCrypto(),

View File

@@ -86,7 +86,8 @@ export class ApplicationGroup {
const desktopService = new DesktopManager( const desktopService = new DesktopManager(
this.$rootScope, this.$rootScope,
this.$timeout, this.$timeout,
application application,
this.bridge,
); );
const keyboardService = new KeyboardManager(); const keyboardService = new KeyboardManager();
const lockService = new LockManager( const lockService = new LockManager(