Skip to content

Commit 7a0f32d

Browse files
committed
Promisify utils.
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.
1 parent 7a49998 commit 7a0f32d

31 files changed

+231
-338
lines changed

Diff for: README.md

+2
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@ cordova-res android --skip-config --copy
7070
- The committed codes should pass all GitHub checks.
7171
- Use [Visual Studio Code](https://code.visualstudio.com/) with workspace settings for consistent coding style.
7272
- Use [Prettier extension](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode) to auto format on save.
73+
- Prefer `Promise` than `Observable` when only emitting one value. See [issue #233](https://github.com/numbersprotocol/capture-lite/issues/233).
74+
- Avoid using `toPromise()` to convert `Observable` to `Promise` as [it is an anti-pattern](https://stackoverflow.com/a/49596716/8789738).
7375

7476
### Platform
7577

Diff for: src/app/app.component.ts

+11-21
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,7 @@ import { DomSanitizer } from '@angular/platform-browser';
44
import { Plugins } from '@capacitor/core';
55
import { Platform } from '@ionic/angular';
66
import { TranslocoService } from '@ngneat/transloco';
7-
import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';
8-
import { concatMap } from 'rxjs/operators';
7+
import { UntilDestroy } from '@ngneat/until-destroy';
98
import { CollectorService } from './services/collector/collector.service';
109
import { CapacitorFactsProvider } from './services/collector/facts/capacitor-provider/capacitor-facts-provider.service';
1110
import { WebCryptoApiSignatureProvider } from './services/collector/signature/web-crypto-api-provider/web-crypto-api-signature-provider.service';
@@ -15,8 +14,7 @@ import { NumbersStorageApi } from './services/publisher/numbers-storage/numbers-
1514
import { NumbersStoragePublisher } from './services/publisher/numbers-storage/numbers-storage-publisher';
1615
import { AssetRepository } from './services/publisher/numbers-storage/repositories/asset/asset-repository.service';
1716
import { PublishersAlert } from './services/publisher/publishers-alert/publishers-alert.service';
18-
import { restoreKilledAppResult$ } from './utils/camera';
19-
import { fromExtension } from './utils/mime-type';
17+
import { restoreKilledCapture } from './utils/camera';
2018

2119
const { SplashScreen } = Plugins;
2220

@@ -50,25 +48,17 @@ export class AppComponent {
5048
this.registerIcon();
5149
}
5250

53-
restoreAppStatus() {
54-
restoreKilledAppResult$()
55-
.pipe(
56-
concatMap(cameraPhoto =>
57-
this.collectorService.runAndStore({
58-
[cameraPhoto.base64String]: {
59-
mimeType: fromExtension(cameraPhoto.format),
60-
},
61-
})
62-
),
63-
untilDestroyed(this)
64-
)
65-
.subscribe();
51+
async restoreAppStatus() {
52+
const photo = await restoreKilledCapture();
53+
const proof = await this.collectorService.runAndStore({
54+
[photo.base64]: { mimeType: photo.mimeType },
55+
});
56+
return this.publishersAlert.presentOrPublish(proof);
6657
}
6758

68-
initializeApp() {
69-
this.platform.ready().then(() => {
70-
SplashScreen.hide();
71-
});
59+
async initializeApp() {
60+
await this.platform.ready();
61+
await SplashScreen.hide();
7262
}
7363

7464
initializeCollector() {

Diff for: src/app/pages/about/about.page.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import { Component } from '@angular/core';
22
import { Plugins } from '@capacitor/core';
3-
import { UntilDestroy } from '@ngneat/until-destroy';
3+
import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';
44
import { defer } from 'rxjs';
5-
import { first, pluck } from 'rxjs/operators';
5+
import { pluck } from 'rxjs/operators';
66

77
const { Device } = Plugins;
88

@@ -14,7 +14,7 @@ const { Device } = Plugins;
1414
})
1515
export class AboutPage {
1616
readonly version$ = defer(() => Device.getInfo()).pipe(
17-
first(),
18-
pluck('appVersion')
17+
pluck('appVersion'),
18+
untilDestroyed(this)
1919
);
2020
}

Diff for: src/app/pages/home/home.page.ts

+8-17
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { formatDate } from '@angular/common';
22
import { Component, OnInit } from '@angular/core';
33
import { MatTabChangeEvent } from '@angular/material/tabs';
4-
import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';
4+
import { UntilDestroy } from '@ngneat/until-destroy';
55
import { groupBy } from 'lodash';
66
import { combineLatest, interval, of, zip } from 'rxjs';
77
import { concatMap, concatMapTo, map, pluck } from 'rxjs/operators';
@@ -13,8 +13,7 @@ import { PublishersAlert } from '../../services/publisher/publishers-alert/publi
1313
import { PushNotificationService } from '../../services/push-notification/push-notification.service';
1414
import { getOldProof } from '../../services/repositories/proof/old-proof-adapter';
1515
import { ProofRepository } from '../../services/repositories/proof/proof-repository.service';
16-
import { capture$ } from '../../utils/camera';
17-
import { fromExtension } from '../../utils/mime-type';
16+
import { capture } from '../../utils/camera';
1817
import { forkJoinWithDefault } from '../../utils/rx-operators';
1918

2019
@UntilDestroy({ checkProperties: true })
@@ -116,20 +115,12 @@ export class HomePage implements OnInit {
116115
);
117116
}
118117

119-
capture() {
120-
capture$()
121-
.pipe(
122-
concatMap(cameraPhoto =>
123-
this.collectorService.runAndStore({
124-
[cameraPhoto.base64String]: {
125-
mimeType: fromExtension(cameraPhoto.format),
126-
},
127-
})
128-
),
129-
concatMap(proof => this.publishersAlert.presentOrPublish(proof)),
130-
untilDestroyed(this)
131-
)
132-
.subscribe();
118+
async capture() {
119+
const photo = await capture();
120+
const proof = await this.collectorService.runAndStore({
121+
[photo.base64]: { mimeType: photo.mimeType },
122+
});
123+
return this.publishersAlert.presentOrPublish(proof);
133124
}
134125

135126
onTapChanged(event: MatTabChangeEvent) {

Diff for: src/app/pages/profile/profile.page.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,8 @@ export class ProfilePage {
3939
private readonly webCryptoApiSignatureProvider: WebCryptoApiSignatureProvider
4040
) {}
4141

42-
copyToClipboard(value: string) {
43-
Clipboard.write({ string: value });
42+
async copyToClipboard(value: string) {
43+
await Clipboard.write({ string: value });
4444
this.snackBar.open(
4545
this.translocoService.translate('message.copiedToClipboard')
4646
);

Diff for: src/app/services/collector/signature/web-crypto-api-provider/web-crypto-api-signature-provider.service.ts

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import { Injectable } from '@angular/core';
22
import { Signature } from '../../../../services/repositories/proof/proof';
33
import {
4-
createEcKeyPair$,
5-
signWithSha256AndEcdsa$,
4+
createEcKeyPair,
5+
signWithSha256AndEcdsa,
66
} from '../../../../utils/crypto/crypto';
77
import { PreferenceManager } from '../../../preference-manager/preference-manager.service';
88
import { SignatureProvider } from '../signature-provider';
@@ -18,10 +18,10 @@ export class WebCryptoApiSignatureProvider implements SignatureProvider {
1818

1919
async provide(serializedSortedSignTargets: string): Promise<Signature> {
2020
const privateKey = await this.getPrivateKey();
21-
const signature = await signWithSha256AndEcdsa$(
21+
const signature = await signWithSha256AndEcdsa(
2222
serializedSortedSignTargets,
2323
privateKey
24-
).toPromise();
24+
);
2525
const publicKey = await this.getPublicKey();
2626
return { signature, publicKey };
2727
}
@@ -30,7 +30,7 @@ export class WebCryptoApiSignatureProvider implements SignatureProvider {
3030
const originalPublicKey = await this.getPublicKey();
3131
const originalPrivateKey = await this.getPrivateKey();
3232
if (originalPublicKey.length === 0 || originalPrivateKey.length === 0) {
33-
const { publicKey, privateKey } = await createEcKeyPair$().toPromise();
33+
const { publicKey, privateKey } = await createEcKeyPair();
3434
await this.preferences.setString(PrefKeys.PUBLIC_KEY, publicKey);
3535
await this.preferences.setString(PrefKeys.PRIVATE_KEY, privateKey);
3636
}

Diff for: src/app/services/database/table/capacitor-filesystem-table-impl/capacitor-filesystem-table-impl.spec.ts renamed to src/app/services/database/table/capacitor-filesystem-table/capacitor-filesystem-table.spec.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { Table, Tuple } from '../table';
2-
import { CapacitorFilesystemTableImpl } from './capacitor-filesystem-table-impl';
2+
import { CapacitorFilesystemTable } from './capacitor-filesystem-table';
33

4-
describe('MemoryTableImpl', () => {
4+
describe('CapacitorFilesystemTable', () => {
55
let table: Table<TestTuple>;
66
const tableId = 'tableId';
77
const testTuple1: TestTuple = {
@@ -43,7 +43,7 @@ describe('MemoryTableImpl', () => {
4343
},
4444
};
4545

46-
beforeEach(() => (table = new CapacitorFilesystemTableImpl(tableId)));
46+
beforeEach(() => (table = new CapacitorFilesystemTable(tableId)));
4747

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

Diff for: src/app/services/database/table/capacitor-filesystem-table-impl/capacitor-filesystem-table-impl.ts renamed to src/app/services/database/table/capacitor-filesystem-table/capacitor-filesystem-table.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ import { Table, Tuple } from '../table';
1111

1212
const { Filesystem } = Plugins;
1313

14-
export class CapacitorFilesystemTableImpl<T extends Tuple> implements Table<T> {
14+
export class CapacitorFilesystemTable<T extends Tuple> implements Table<T> {
1515
private readonly directory = FilesystemDirectory.Data;
16-
private readonly rootDir = CapacitorFilesystemTableImpl.name;
16+
private readonly rootDir = CapacitorFilesystemTable.name;
1717
private readonly tuples$ = new BehaviorSubject<T[]>([]);
1818
private hasInitialized = false;
1919
private readonly mutex = new Mutex();

Diff for: src/app/services/database/table/memory-table-impl/memory-table-impl.spec.ts renamed to src/app/services/database/table/memory-table/memory-table.spec.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { Table, Tuple } from '../table';
2-
import { MemoryTableImpl } from './memory-table-impl';
2+
import { MemoryTable } from './memory-table';
33

4-
describe('MemoryTableImpl', () => {
4+
describe('MemoryTable', () => {
55
let table: Table<TestTuple>;
66
const tableId = 'tableId';
77
const tuple1: TestTuple = {
@@ -43,7 +43,7 @@ describe('MemoryTableImpl', () => {
4343
},
4444
};
4545

46-
beforeEach(() => (table = new MemoryTableImpl(tableId)));
46+
beforeEach(() => (table = new MemoryTable(tableId)));
4747

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

Diff for: src/app/services/database/table/memory-table-impl/memory-table-impl.ts renamed to src/app/services/database/table/memory-table/memory-table.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { equals } from 'lodash/fp';
22
import { BehaviorSubject } from 'rxjs';
33
import { Table, Tuple } from '../table';
44

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

88
constructor(readonly id: string) {}
+3-3
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import { zip } from 'rxjs';
22
import { first } from 'rxjs/operators';
33
import { Preferences } from '../preferences';
4-
import { CapacitorStoragePreferencesImpl } from './capacitor-storage-preferences-impl';
4+
import { CapacitorStoragePreferences } from './capacitor-storage-preferences';
55

6-
describe('MemoryPreferencesImpl', () => {
6+
describe('CapacitorStoragePreferences', () => {
77
let preferences: Preferences;
88
const id = 'id';
99

10-
beforeEach(() => (preferences = new CapacitorStoragePreferencesImpl(id)));
10+
beforeEach(() => (preferences = new CapacitorStoragePreferences(id)));
1111

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { Preferences } from '../preferences';
66

77
const { Storage } = Plugins;
88

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

Diff for: src/app/services/preference-manager/preferences/memory-preferences-impl/memory-preferences-impl.spec.ts renamed to src/app/services/preference-manager/preferences/memory-preferences/memory-preferences.spec.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import { zip } from 'rxjs';
22
import { first } from 'rxjs/operators';
33
import { Preferences } from '../preferences';
4-
import { MemoryPreferencesImpl } from './memory-preferences-impl';
4+
import { MemoryPreferences } from './memory-preferences';
55

6-
describe('MemoryPreferencesImpl', () => {
6+
describe('MemoryPreferences', () => {
77
let preferences: Preferences;
88
const id = 'id';
99

10-
beforeEach(() => (preferences = new MemoryPreferencesImpl(id)));
10+
beforeEach(() => (preferences = new MemoryPreferences(id)));
1111

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

Diff for: src/app/services/preference-manager/preferences/memory-preferences-impl/memory-preferences-impl.ts renamed to src/app/services/preference-manager/preferences/memory-preferences/memory-preferences.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { BehaviorSubject, Observable } from 'rxjs';
22
import { Preferences } from '../preferences';
33

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

77
constructor(readonly id: string) {}

Diff for: src/app/services/publisher/numbers-storage/numbers-storage-api.service.ts

+4-6
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { Injectable } from '@angular/core';
33
import { defer, of, zip } from 'rxjs';
44
import { concatMap, concatMapTo, pluck } from 'rxjs/operators';
55
import { secret } from '../../../../environments/secret';
6-
import { dataUrlWithBase64ToBlob$ } from '../../../utils/encoding/encoding';
6+
import { base64ToBlob } from '../../../utils/encoding/encoding';
77
import { PreferenceManager } from '../../preference-manager/preference-manager.service';
88
import {
99
getSortedProofInformation,
@@ -119,10 +119,11 @@ export class NumbersStorageApi {
119119
signatures: OldSignature[],
120120
tag: string
121121
) {
122+
const proofMimeType = Object.values(proof.assets)[0].mimeType;
122123
return defer(() => this.getHttpHeadersWithAuthToken()).pipe(
123124
concatMap(headers =>
124125
zip(
125-
dataUrlWithBase64ToBlob$(rawFileBase64),
126+
defer(() => base64ToBlob(rawFileBase64, proofMimeType)),
126127
getSortedProofInformation(proof),
127128
of(headers)
128129
)
@@ -133,10 +134,7 @@ export class NumbersStorageApi {
133134
);
134135
const formData = new FormData();
135136
formData.append('asset_file', rawFile);
136-
formData.append(
137-
'asset_file_mime_type',
138-
Object.values(proof.assets)[0].mimeType
139-
);
137+
formData.append('asset_file_mime_type', proofMimeType);
140138
formData.append('meta', JSON.stringify(oldSortedProofInformation));
141139
formData.append('target_provider', targetProvider);
142140
formData.append('caption', caption);

Diff for: src/app/services/publisher/numbers-storage/numbers-storage-publisher.ts

+1-3
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,7 @@ export class NumbersStoragePublisher extends Publisher {
2929
const oldSignatures = await getOldSignatures(proof);
3030
const assetResponse = await this.numbersStorageApi
3131
.createAsset$(
32-
`data:${Object.values(proof.assets)[0].mimeType};base64,${
33-
Object.keys(proof.assets)[0]
34-
}`,
32+
Object.keys(proof.assets)[0],
3533
proof,
3634
TargetProvider.Numbers,
3735
'',

Diff for: src/app/services/repositories/proof/old-proof-adapter.spec.ts

+2-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { dataUrlWithBase64ToBlob$ } from '../../../utils/encoding/encoding';
1+
import { base64ToBlob } from '../../../utils/encoding/encoding';
22
import { MimeType } from '../../../utils/mime-type';
33
import {
44
AssetMeta,
@@ -57,9 +57,7 @@ describe('old-proof-adapter', () => {
5757
});
5858

5959
it('should convert SortedProofInformation with raw Blob to Proof', async () => {
60-
const blob = await dataUrlWithBase64ToBlob$(
61-
`data:${ASSET1_MIMETYPE};base64,${ASSET1_BASE64}`
62-
).toPromise();
60+
const blob = await base64ToBlob(ASSET1_BASE64, ASSET1_MIMETYPE);
6361
const convertedProof = await getProof(
6462
blob,
6563
SORTED_PROOF_INFORMATION,

Diff for: src/app/services/repositories/proof/old-proof-adapter.ts

+5-9
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { flow, groupBy, mapValues } from 'lodash/fp';
2-
import { sha256WithBase64$ } from '../../../utils/crypto/crypto';
3-
import { blobToDataUrlWithBase64$ } from '../../../utils/encoding/encoding';
2+
import { sha256WithBase64 } from '../../../utils/crypto/crypto';
3+
import { blobToBase64 } from '../../../utils/encoding/encoding';
44
import { MimeType } from '../../../utils/mime-type';
55
import { Tuple } from '../../database/table/table';
66
import { Proof, Signature } from './proof';
@@ -21,7 +21,7 @@ export async function getOldProof(proof: Proof): Promise<OldProof> {
2121
return {
2222
mimeType: oldProofData[1].mimeType,
2323
timestamp: proof.timestamp,
24-
hash: await sha256WithBase64$(oldProofData[0]).toPromise(),
24+
hash: await sha256WithBase64(oldProofData[0]),
2525
};
2626
}
2727

@@ -61,9 +61,7 @@ function createSortedEssentialInformation(
6161
}
6262

6363
export async function getOldSignatures(proof: Proof): Promise<OldSignature[]> {
64-
const assetHash = await sha256WithBase64$(
65-
Object.entries(proof.assets)[0][0]
66-
).toPromise();
64+
const assetHash = await sha256WithBase64(Object.entries(proof.assets)[0][0]);
6765
return Object.entries(proof.signatures).map(
6866
([provider, { signature, publicKey }]) => ({
6967
provider,
@@ -79,9 +77,7 @@ export async function getProof(
7977
sortedProofInformation: SortedProofInformation,
8078
oldSignatures: OldSignature[]
8179
): Promise<Proof> {
82-
const base64 = (await blobToDataUrlWithBase64$(raw).toPromise()).split(
83-
','
84-
)[1];
80+
const base64 = await blobToBase64(raw);
8581
const groupedByProvider = groupObjectsBy(
8682
sortedProofInformation.information,
8783
'provider'

0 commit comments

Comments
 (0)