refactor: improve device interface types (#996)
This commit is contained in:
11
app/assets/javascripts/Device/DesktopDeviceInterface.ts
Normal file
11
app/assets/javascripts/Device/DesktopDeviceInterface.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { DeviceInterface, Environment } from '@standardnotes/snjs'
|
||||
import { WebOrDesktopDevice } from '@/Device/WebOrDesktopDevice'
|
||||
import { WebCommunicationReceiver } from './DesktopWebCommunication'
|
||||
|
||||
export function isDesktopDevice(x: DeviceInterface): x is DesktopDeviceInterface {
|
||||
return x.environment === Environment.Desktop
|
||||
}
|
||||
|
||||
export interface DesktopDeviceInterface extends WebOrDesktopDevice, WebCommunicationReceiver {
|
||||
environment: Environment.Desktop
|
||||
}
|
||||
1
app/assets/javascripts/Device/DesktopSnjsExports.ts
Normal file
1
app/assets/javascripts/Device/DesktopSnjsExports.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { Environment, RawKeychainValue } from '@standardnotes/snjs'
|
||||
44
app/assets/javascripts/Device/DesktopWebCommunication.ts
Normal file
44
app/assets/javascripts/Device/DesktopWebCommunication.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
import { DecryptedTransferPayload } from '@standardnotes/snjs'
|
||||
|
||||
/** Receives communications emitted by Web Core. This would be the Desktop client. */
|
||||
export interface WebCommunicationReceiver {
|
||||
localBackupsCount(): Promise<number>
|
||||
|
||||
viewlocalBackups(): void
|
||||
|
||||
deleteLocalBackups(): Promise<void>
|
||||
|
||||
syncComponents(payloads: unknown[]): void
|
||||
|
||||
onMajorDataChange(): void
|
||||
|
||||
onInitialDataLoad(): void
|
||||
|
||||
onSignOut(): void
|
||||
|
||||
onSearch(text?: string): void
|
||||
|
||||
downloadBackup(): void | Promise<void>
|
||||
|
||||
get extensionsServerHost(): string
|
||||
}
|
||||
|
||||
/** Receives communications emitted by the desktop client. This would be Web Core. */
|
||||
export interface DesktopCommunicationReceiver {
|
||||
updateAvailable(): void
|
||||
|
||||
windowGainedFocus(): void
|
||||
|
||||
windowLostFocus(): void
|
||||
|
||||
onComponentInstallationComplete(
|
||||
componentData: DecryptedTransferPayload,
|
||||
error: unknown,
|
||||
): Promise<void>
|
||||
|
||||
requestBackupFile(): Promise<string | undefined>
|
||||
|
||||
didBeginBackup(): void
|
||||
|
||||
didFinishBackup(success: boolean): void
|
||||
}
|
||||
8
app/assets/javascripts/Device/StartApplication.ts
Normal file
8
app/assets/javascripts/Device/StartApplication.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import { WebOrDesktopDevice } from './WebOrDesktopDevice'
|
||||
|
||||
export type StartApplication = (
|
||||
defaultSyncServerHost: string,
|
||||
device: WebOrDesktopDevice,
|
||||
enableUnfinishedFeatures: boolean,
|
||||
webSocketUrl: string,
|
||||
) => Promise<void>
|
||||
26
app/assets/javascripts/Device/WebDevice.ts
Normal file
26
app/assets/javascripts/Device/WebDevice.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import { Environment, RawKeychainValue } from '@standardnotes/snjs'
|
||||
import { WebOrDesktopDevice } from '@/Device/WebOrDesktopDevice'
|
||||
|
||||
const KEYCHAIN_STORAGE_KEY = 'keychain'
|
||||
|
||||
export class WebDevice extends WebOrDesktopDevice {
|
||||
environment = Environment.Web
|
||||
|
||||
async getKeychainValue(): Promise<RawKeychainValue> {
|
||||
const value = localStorage.getItem(KEYCHAIN_STORAGE_KEY)
|
||||
|
||||
if (value) {
|
||||
return JSON.parse(value)
|
||||
}
|
||||
|
||||
return {}
|
||||
}
|
||||
|
||||
async setKeychainValue(value: RawKeychainValue): Promise<void> {
|
||||
localStorage.setItem(KEYCHAIN_STORAGE_KEY, JSON.stringify(value))
|
||||
}
|
||||
|
||||
async clearRawKeychainValue(): Promise<void> {
|
||||
localStorage.removeItem(KEYCHAIN_STORAGE_KEY)
|
||||
}
|
||||
}
|
||||
176
app/assets/javascripts/Device/WebOrDesktopDevice.ts
Normal file
176
app/assets/javascripts/Device/WebOrDesktopDevice.ts
Normal file
@@ -0,0 +1,176 @@
|
||||
import {
|
||||
SNApplication,
|
||||
ApplicationIdentifier,
|
||||
Environment,
|
||||
LegacyRawKeychainValue,
|
||||
RawKeychainValue,
|
||||
TransferPayload,
|
||||
NamespacedRootKeyInKeychain,
|
||||
} from '@standardnotes/snjs'
|
||||
import { Database } from '../Database'
|
||||
import { WebOrDesktopDeviceInterface } from './WebOrDesktopDeviceInterface'
|
||||
|
||||
export abstract class WebOrDesktopDevice implements WebOrDesktopDeviceInterface {
|
||||
constructor(public appVersion: string) {}
|
||||
|
||||
private databases: Database[] = []
|
||||
|
||||
abstract environment: Environment
|
||||
|
||||
setApplication(application: SNApplication) {
|
||||
const database = new Database(application.identifier, application.alertService)
|
||||
|
||||
this.databases.push(database)
|
||||
}
|
||||
|
||||
public async getJsonParsedRawStorageValue(key: string): Promise<unknown | undefined> {
|
||||
const value = await this.getRawStorageValue(key)
|
||||
if (value == undefined) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
try {
|
||||
return JSON.parse(value)
|
||||
} catch (e) {
|
||||
return value
|
||||
}
|
||||
}
|
||||
|
||||
private databaseForIdentifier(identifier: ApplicationIdentifier) {
|
||||
return this.databases.find((database) => database.databaseName === identifier) as Database
|
||||
}
|
||||
|
||||
deinit() {
|
||||
for (const database of this.databases) {
|
||||
database.deinit()
|
||||
}
|
||||
this.databases = []
|
||||
}
|
||||
|
||||
async getRawStorageValue(key: string): Promise<string | undefined> {
|
||||
const result = localStorage.getItem(key)
|
||||
|
||||
if (result == undefined) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
async getAllRawStorageKeyValues() {
|
||||
const results = []
|
||||
for (const key of Object.keys(localStorage)) {
|
||||
results.push({
|
||||
key: key,
|
||||
value: localStorage[key],
|
||||
})
|
||||
}
|
||||
return results
|
||||
}
|
||||
|
||||
async setRawStorageValue(key: string, value: string) {
|
||||
localStorage.setItem(key, value)
|
||||
}
|
||||
|
||||
async removeRawStorageValue(key: string) {
|
||||
localStorage.removeItem(key)
|
||||
}
|
||||
|
||||
async removeAllRawStorageValues() {
|
||||
localStorage.clear()
|
||||
}
|
||||
|
||||
async openDatabase(identifier: ApplicationIdentifier) {
|
||||
this.databaseForIdentifier(identifier).unlock()
|
||||
return new Promise((resolve, reject) => {
|
||||
this.databaseForIdentifier(identifier)
|
||||
.openDatabase(() => {
|
||||
resolve({ isNewDatabase: true })
|
||||
})
|
||||
.then(() => {
|
||||
resolve({ isNewDatabase: false })
|
||||
})
|
||||
.catch((error) => {
|
||||
reject(error)
|
||||
})
|
||||
}) as Promise<{ isNewDatabase?: boolean } | undefined>
|
||||
}
|
||||
|
||||
async getAllRawDatabasePayloads(identifier: ApplicationIdentifier) {
|
||||
return this.databaseForIdentifier(identifier).getAllPayloads()
|
||||
}
|
||||
|
||||
async saveRawDatabasePayload(payload: TransferPayload, identifier: ApplicationIdentifier) {
|
||||
return this.databaseForIdentifier(identifier).savePayload(payload)
|
||||
}
|
||||
|
||||
async saveRawDatabasePayloads(payloads: TransferPayload[], identifier: ApplicationIdentifier) {
|
||||
return this.databaseForIdentifier(identifier).savePayloads(payloads)
|
||||
}
|
||||
|
||||
async removeRawDatabasePayloadWithId(id: string, identifier: ApplicationIdentifier) {
|
||||
return this.databaseForIdentifier(identifier).deletePayload(id)
|
||||
}
|
||||
|
||||
async removeAllRawDatabasePayloads(identifier: ApplicationIdentifier) {
|
||||
return this.databaseForIdentifier(identifier).clearAllPayloads()
|
||||
}
|
||||
|
||||
async getNamespacedKeychainValue(identifier: ApplicationIdentifier) {
|
||||
const keychain = await this.getKeychainValue()
|
||||
|
||||
if (!keychain) {
|
||||
return
|
||||
}
|
||||
|
||||
return keychain[identifier]
|
||||
}
|
||||
|
||||
async setNamespacedKeychainValue(
|
||||
value: NamespacedRootKeyInKeychain,
|
||||
identifier: ApplicationIdentifier,
|
||||
) {
|
||||
let keychain = await this.getKeychainValue()
|
||||
|
||||
if (!keychain) {
|
||||
keychain = {}
|
||||
}
|
||||
|
||||
return this.setKeychainValue({
|
||||
...keychain,
|
||||
[identifier]: value,
|
||||
})
|
||||
}
|
||||
|
||||
async clearNamespacedKeychainValue(identifier: ApplicationIdentifier) {
|
||||
const keychain = await this.getKeychainValue()
|
||||
if (!keychain) {
|
||||
return
|
||||
}
|
||||
|
||||
delete keychain[identifier]
|
||||
|
||||
return this.setKeychainValue(keychain)
|
||||
}
|
||||
|
||||
setRawKeychainValue(value: unknown): Promise<void> {
|
||||
return this.setKeychainValue(value)
|
||||
}
|
||||
|
||||
openUrl(url: string) {
|
||||
const win = window.open(url, '_blank')
|
||||
if (win) {
|
||||
win.focus()
|
||||
}
|
||||
}
|
||||
|
||||
setLegacyRawKeychainValue(value: LegacyRawKeychainValue): Promise<void> {
|
||||
return this.setKeychainValue(value)
|
||||
}
|
||||
|
||||
abstract getKeychainValue(): Promise<RawKeychainValue>
|
||||
|
||||
abstract setKeychainValue(value: unknown): Promise<void>
|
||||
|
||||
abstract clearRawKeychainValue(): Promise<void>
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import { DeviceInterface, RawKeychainValue } from '@standardnotes/snjs'
|
||||
|
||||
export interface WebOrDesktopDeviceInterface extends DeviceInterface {
|
||||
readonly appVersion: string
|
||||
|
||||
getKeychainValue(): Promise<RawKeychainValue>
|
||||
|
||||
setKeychainValue(value: RawKeychainValue): Promise<void>
|
||||
}
|
||||
Reference in New Issue
Block a user