Skip to content

Commit

Permalink
Promisify utils.
Browse files Browse the repository at this point in the history
Use Promise to Replace Observable Only Emitting Once. See #233.

- Remove impl suffix from table preferences classes.
- Remove unused utils.
- Suppress tslint:await-promise rule for crypto.ts.
  • Loading branch information
seanwu1105 committed Dec 1, 2020
1 parent 7a49998 commit 7a0f32d
Show file tree
Hide file tree
Showing 31 changed files with 231 additions and 338 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ cordova-res android --skip-config --copy
- The committed codes should pass all GitHub checks.
- Use [Visual Studio Code](https://code.visualstudio.com/) with workspace settings for consistent coding style.
- Use [Prettier extension](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode) to auto format on save.
- Prefer `Promise` than `Observable` when only emitting one value. See [issue #233](https://github.com/numbersprotocol/capture-lite/issues/233).
- Avoid using `toPromise()` to convert `Observable` to `Promise` as [it is an anti-pattern](https://stackoverflow.com/a/49596716/8789738).

### Platform

Expand Down
32 changes: 11 additions & 21 deletions src/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@ import { DomSanitizer } from '@angular/platform-browser';
import { Plugins } from '@capacitor/core';
import { Platform } from '@ionic/angular';
import { TranslocoService } from '@ngneat/transloco';
import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';
import { concatMap } from 'rxjs/operators';
import { UntilDestroy } from '@ngneat/until-destroy';
import { CollectorService } from './services/collector/collector.service';
import { CapacitorFactsProvider } from './services/collector/facts/capacitor-provider/capacitor-facts-provider.service';
import { WebCryptoApiSignatureProvider } from './services/collector/signature/web-crypto-api-provider/web-crypto-api-signature-provider.service';
Expand All @@ -15,8 +14,7 @@ import { NumbersStorageApi } from './services/publisher/numbers-storage/numbers-
import { NumbersStoragePublisher } from './services/publisher/numbers-storage/numbers-storage-publisher';
import { AssetRepository } from './services/publisher/numbers-storage/repositories/asset/asset-repository.service';
import { PublishersAlert } from './services/publisher/publishers-alert/publishers-alert.service';
import { restoreKilledAppResult$ } from './utils/camera';
import { fromExtension } from './utils/mime-type';
import { restoreKilledCapture } from './utils/camera';

const { SplashScreen } = Plugins;

Expand Down Expand Up @@ -50,25 +48,17 @@ export class AppComponent {
this.registerIcon();
}

restoreAppStatus() {
restoreKilledAppResult$()
.pipe(
concatMap(cameraPhoto =>
this.collectorService.runAndStore({
[cameraPhoto.base64String]: {
mimeType: fromExtension(cameraPhoto.format),
},
})
),
untilDestroyed(this)
)
.subscribe();
async restoreAppStatus() {
const photo = await restoreKilledCapture();
const proof = await this.collectorService.runAndStore({
[photo.base64]: { mimeType: photo.mimeType },
});
return this.publishersAlert.presentOrPublish(proof);
}

initializeApp() {
this.platform.ready().then(() => {
SplashScreen.hide();
});
async initializeApp() {
await this.platform.ready();
await SplashScreen.hide();
}

initializeCollector() {
Expand Down
8 changes: 4 additions & 4 deletions src/app/pages/about/about.page.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Component } from '@angular/core';
import { Plugins } from '@capacitor/core';
import { UntilDestroy } from '@ngneat/until-destroy';
import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';
import { defer } from 'rxjs';
import { first, pluck } from 'rxjs/operators';
import { pluck } from 'rxjs/operators';

const { Device } = Plugins;

Expand All @@ -14,7 +14,7 @@ const { Device } = Plugins;
})
export class AboutPage {
readonly version$ = defer(() => Device.getInfo()).pipe(
first(),
pluck('appVersion')
pluck('appVersion'),
untilDestroyed(this)
);
}
25 changes: 8 additions & 17 deletions src/app/pages/home/home.page.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { formatDate } from '@angular/common';
import { Component, OnInit } from '@angular/core';
import { MatTabChangeEvent } from '@angular/material/tabs';
import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';
import { UntilDestroy } from '@ngneat/until-destroy';
import { groupBy } from 'lodash';
import { combineLatest, interval, of, zip } from 'rxjs';
import { concatMap, concatMapTo, map, pluck } from 'rxjs/operators';
Expand All @@ -13,8 +13,7 @@ import { PublishersAlert } from '../../services/publisher/publishers-alert/publi
import { PushNotificationService } from '../../services/push-notification/push-notification.service';
import { getOldProof } from '../../services/repositories/proof/old-proof-adapter';
import { ProofRepository } from '../../services/repositories/proof/proof-repository.service';
import { capture$ } from '../../utils/camera';
import { fromExtension } from '../../utils/mime-type';
import { capture } from '../../utils/camera';
import { forkJoinWithDefault } from '../../utils/rx-operators';

@UntilDestroy({ checkProperties: true })
Expand Down Expand Up @@ -116,20 +115,12 @@ export class HomePage implements OnInit {
);
}

capture() {
capture$()
.pipe(
concatMap(cameraPhoto =>
this.collectorService.runAndStore({
[cameraPhoto.base64String]: {
mimeType: fromExtension(cameraPhoto.format),
},
})
),
concatMap(proof => this.publishersAlert.presentOrPublish(proof)),
untilDestroyed(this)
)
.subscribe();
async capture() {
const photo = await capture();
const proof = await this.collectorService.runAndStore({
[photo.base64]: { mimeType: photo.mimeType },
});
return this.publishersAlert.presentOrPublish(proof);
}

onTapChanged(event: MatTabChangeEvent) {
Expand Down
4 changes: 2 additions & 2 deletions src/app/pages/profile/profile.page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ export class ProfilePage {
private readonly webCryptoApiSignatureProvider: WebCryptoApiSignatureProvider
) {}

copyToClipboard(value: string) {
Clipboard.write({ string: value });
async copyToClipboard(value: string) {
await Clipboard.write({ string: value });
this.snackBar.open(
this.translocoService.translate('message.copiedToClipboard')
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Injectable } from '@angular/core';
import { Signature } from '../../../../services/repositories/proof/proof';
import {
createEcKeyPair$,
signWithSha256AndEcdsa$,
createEcKeyPair,
signWithSha256AndEcdsa,
} from '../../../../utils/crypto/crypto';
import { PreferenceManager } from '../../../preference-manager/preference-manager.service';
import { SignatureProvider } from '../signature-provider';
Expand All @@ -18,10 +18,10 @@ export class WebCryptoApiSignatureProvider implements SignatureProvider {

async provide(serializedSortedSignTargets: string): Promise<Signature> {
const privateKey = await this.getPrivateKey();
const signature = await signWithSha256AndEcdsa$(
const signature = await signWithSha256AndEcdsa(
serializedSortedSignTargets,
privateKey
).toPromise();
);
const publicKey = await this.getPublicKey();
return { signature, publicKey };
}
Expand All @@ -30,7 +30,7 @@ export class WebCryptoApiSignatureProvider implements SignatureProvider {
const originalPublicKey = await this.getPublicKey();
const originalPrivateKey = await this.getPrivateKey();
if (originalPublicKey.length === 0 || originalPrivateKey.length === 0) {
const { publicKey, privateKey } = await createEcKeyPair$().toPromise();
const { publicKey, privateKey } = await createEcKeyPair();
await this.preferences.setString(PrefKeys.PUBLIC_KEY, publicKey);
await this.preferences.setString(PrefKeys.PRIVATE_KEY, privateKey);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Table, Tuple } from '../table';
import { CapacitorFilesystemTableImpl } from './capacitor-filesystem-table-impl';
import { CapacitorFilesystemTable } from './capacitor-filesystem-table';

describe('MemoryTableImpl', () => {
describe('CapacitorFilesystemTable', () => {
let table: Table<TestTuple>;
const tableId = 'tableId';
const testTuple1: TestTuple = {
Expand Down Expand Up @@ -43,7 +43,7 @@ describe('MemoryTableImpl', () => {
},
};

beforeEach(() => (table = new CapacitorFilesystemTableImpl(tableId)));
beforeEach(() => (table = new CapacitorFilesystemTable(tableId)));

afterEach(async () => table.drop());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ import { Table, Tuple } from '../table';

const { Filesystem } = Plugins;

export class CapacitorFilesystemTableImpl<T extends Tuple> implements Table<T> {
export class CapacitorFilesystemTable<T extends Tuple> implements Table<T> {
private readonly directory = FilesystemDirectory.Data;
private readonly rootDir = CapacitorFilesystemTableImpl.name;
private readonly rootDir = CapacitorFilesystemTable.name;
private readonly tuples$ = new BehaviorSubject<T[]>([]);
private hasInitialized = false;
private readonly mutex = new Mutex();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Table, Tuple } from '../table';
import { MemoryTableImpl } from './memory-table-impl';
import { MemoryTable } from './memory-table';

describe('MemoryTableImpl', () => {
describe('MemoryTable', () => {
let table: Table<TestTuple>;
const tableId = 'tableId';
const tuple1: TestTuple = {
Expand Down Expand Up @@ -43,7 +43,7 @@ describe('MemoryTableImpl', () => {
},
};

beforeEach(() => (table = new MemoryTableImpl(tableId)));
beforeEach(() => (table = new MemoryTable(tableId)));

afterEach(async () => table.drop());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { equals } from 'lodash/fp';
import { BehaviorSubject } from 'rxjs';
import { Table, Tuple } from '../table';

export class MemoryTableImpl<T extends Tuple> implements Table<T> {
export class MemoryTable<T extends Tuple> implements Table<T> {
private readonly tuples$ = new BehaviorSubject<T[]>([]);

constructor(readonly id: string) {}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { zip } from 'rxjs';
import { first } from 'rxjs/operators';
import { Preferences } from '../preferences';
import { CapacitorStoragePreferencesImpl } from './capacitor-storage-preferences-impl';
import { CapacitorStoragePreferences } from './capacitor-storage-preferences';

describe('MemoryPreferencesImpl', () => {
describe('CapacitorStoragePreferences', () => {
let preferences: Preferences;
const id = 'id';

beforeEach(() => (preferences = new CapacitorStoragePreferencesImpl(id)));
beforeEach(() => (preferences = new CapacitorStoragePreferences(id)));

it('should be created', () => expect(preferences).toBeTruthy());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { Preferences } from '../preferences';

const { Storage } = Plugins;

export class CapacitorStoragePreferencesImpl implements Preferences {
export class CapacitorStoragePreferences implements Preferences {
private readonly subjects = new Map<string, BehaviorSubject<any>>();
private readonly mutex = new Mutex();

Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { zip } from 'rxjs';
import { first } from 'rxjs/operators';
import { Preferences } from '../preferences';
import { MemoryPreferencesImpl } from './memory-preferences-impl';
import { MemoryPreferences } from './memory-preferences';

describe('MemoryPreferencesImpl', () => {
describe('MemoryPreferences', () => {
let preferences: Preferences;
const id = 'id';

beforeEach(() => (preferences = new MemoryPreferencesImpl(id)));
beforeEach(() => (preferences = new MemoryPreferences(id)));

it('should be created', () => expect(preferences).toBeTruthy());

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { BehaviorSubject, Observable } from 'rxjs';
import { Preferences } from '../preferences';

export class MemoryPreferencesImpl implements Preferences {
export class MemoryPreferences implements Preferences {
private readonly subjects = new Map<string, BehaviorSubject<any>>();

constructor(readonly id: string) {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Injectable } from '@angular/core';
import { defer, of, zip } from 'rxjs';
import { concatMap, concatMapTo, pluck } from 'rxjs/operators';
import { secret } from '../../../../environments/secret';
import { dataUrlWithBase64ToBlob$ } from '../../../utils/encoding/encoding';
import { base64ToBlob } from '../../../utils/encoding/encoding';
import { PreferenceManager } from '../../preference-manager/preference-manager.service';
import {
getSortedProofInformation,
Expand Down Expand Up @@ -119,10 +119,11 @@ export class NumbersStorageApi {
signatures: OldSignature[],
tag: string
) {
const proofMimeType = Object.values(proof.assets)[0].mimeType;
return defer(() => this.getHttpHeadersWithAuthToken()).pipe(
concatMap(headers =>
zip(
dataUrlWithBase64ToBlob$(rawFileBase64),
defer(() => base64ToBlob(rawFileBase64, proofMimeType)),
getSortedProofInformation(proof),
of(headers)
)
Expand All @@ -133,10 +134,7 @@ export class NumbersStorageApi {
);
const formData = new FormData();
formData.append('asset_file', rawFile);
formData.append(
'asset_file_mime_type',
Object.values(proof.assets)[0].mimeType
);
formData.append('asset_file_mime_type', proofMimeType);
formData.append('meta', JSON.stringify(oldSortedProofInformation));
formData.append('target_provider', targetProvider);
formData.append('caption', caption);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,7 @@ export class NumbersStoragePublisher extends Publisher {
const oldSignatures = await getOldSignatures(proof);
const assetResponse = await this.numbersStorageApi
.createAsset$(
`data:${Object.values(proof.assets)[0].mimeType};base64,${
Object.keys(proof.assets)[0]
}`,
Object.keys(proof.assets)[0],
proof,
TargetProvider.Numbers,
'',
Expand Down
6 changes: 2 additions & 4 deletions src/app/services/repositories/proof/old-proof-adapter.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { dataUrlWithBase64ToBlob$ } from '../../../utils/encoding/encoding';
import { base64ToBlob } from '../../../utils/encoding/encoding';
import { MimeType } from '../../../utils/mime-type';
import {
AssetMeta,
Expand Down Expand Up @@ -57,9 +57,7 @@ describe('old-proof-adapter', () => {
});

it('should convert SortedProofInformation with raw Blob to Proof', async () => {
const blob = await dataUrlWithBase64ToBlob$(
`data:${ASSET1_MIMETYPE};base64,${ASSET1_BASE64}`
).toPromise();
const blob = await base64ToBlob(ASSET1_BASE64, ASSET1_MIMETYPE);
const convertedProof = await getProof(
blob,
SORTED_PROOF_INFORMATION,
Expand Down
14 changes: 5 additions & 9 deletions src/app/services/repositories/proof/old-proof-adapter.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { flow, groupBy, mapValues } from 'lodash/fp';
import { sha256WithBase64$ } from '../../../utils/crypto/crypto';
import { blobToDataUrlWithBase64$ } from '../../../utils/encoding/encoding';
import { sha256WithBase64 } from '../../../utils/crypto/crypto';
import { blobToBase64 } from '../../../utils/encoding/encoding';
import { MimeType } from '../../../utils/mime-type';
import { Tuple } from '../../database/table/table';
import { Proof, Signature } from './proof';
Expand All @@ -21,7 +21,7 @@ export async function getOldProof(proof: Proof): Promise<OldProof> {
return {
mimeType: oldProofData[1].mimeType,
timestamp: proof.timestamp,
hash: await sha256WithBase64$(oldProofData[0]).toPromise(),
hash: await sha256WithBase64(oldProofData[0]),
};
}

Expand Down Expand Up @@ -61,9 +61,7 @@ function createSortedEssentialInformation(
}

export async function getOldSignatures(proof: Proof): Promise<OldSignature[]> {
const assetHash = await sha256WithBase64$(
Object.entries(proof.assets)[0][0]
).toPromise();
const assetHash = await sha256WithBase64(Object.entries(proof.assets)[0][0]);
return Object.entries(proof.signatures).map(
([provider, { signature, publicKey }]) => ({
provider,
Expand All @@ -79,9 +77,7 @@ export async function getProof(
sortedProofInformation: SortedProofInformation,
oldSignatures: OldSignature[]
): Promise<Proof> {
const base64 = (await blobToDataUrlWithBase64$(raw).toPromise()).split(
','
)[1];
const base64 = await blobToBase64(raw);
const groupedByProvider = groupObjectsBy(
sortedProofInformation.information,
'provider'
Expand Down
Loading

0 comments on commit 7a0f32d

Please sign in to comment.