react-native-update 10.38.3 → 10.38.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/harmony/pushy/src/main/cpp/CMakeLists.txt +70 -0
- package/harmony/pushy/src/main/cpp/PushyPackage.h +55 -0
- package/harmony/pushy/src/main/cpp/PushyTurboModule.cpp +142 -0
- package/harmony/pushy/src/main/cpp/PushyTurboModule.h +38 -0
- package/harmony/pushy/src/main/cpp/pushy.c +117 -0
- package/harmony/pushy/src/main/cpp/pushy.cpp +856 -0
- package/harmony/pushy/src/main/cpp/pushy.h +8 -0
- package/harmony/pushy/src/main/ets/DownloadTask.ts +610 -0
- package/harmony/pushy/src/main/ets/DownloadTaskParams.ts +19 -0
- package/harmony/pushy/src/main/ets/EventHub.ts +39 -0
- package/harmony/pushy/src/main/ets/Logger.ts +52 -0
- package/harmony/pushy/src/main/ets/NativePatchCore.ts +87 -0
- package/harmony/pushy/src/main/ets/PushyFileJSBundleProvider.ets +50 -0
- package/harmony/pushy/src/main/ets/PushyPackage.ts +22 -0
- package/harmony/pushy/src/main/ets/PushyTurboModule.ts +139 -0
- package/harmony/pushy/src/main/ets/SaveFile.ts +34 -0
- package/harmony/pushy/src/main/ets/UpdateContext.ts +346 -0
- package/harmony/pushy/src/main/ets/UpdateModuleImpl.ts +123 -0
- package/harmony/pushy/src/main/module.json5 +7 -0
- package/harmony/pushy/src/main/resources/base/element/string.json +8 -0
- package/harmony/pushy/src/main/resources/en_US/element/string.json +8 -0
- package/harmony/pushy/src/main/resources/zh_CN/element/string.json +8 -0
- package/harmony/pushy.har +0 -0
- package/package.json +1 -1
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
import preferences from '@ohos.data.preferences';
|
|
2
|
+
import fileIo from '@ohos.file.fs';
|
|
3
|
+
import { DownloadTask } from './DownloadTask';
|
|
4
|
+
import common from '@ohos.app.ability.common';
|
|
5
|
+
import { DownloadTaskParams } from './DownloadTaskParams';
|
|
6
|
+
import NativePatchCore, {
|
|
7
|
+
STATE_OP_CLEAR_FIRST_TIME,
|
|
8
|
+
STATE_OP_CLEAR_ROLLBACK_MARK,
|
|
9
|
+
STATE_OP_MARK_SUCCESS,
|
|
10
|
+
STATE_OP_RESOLVE_LAUNCH,
|
|
11
|
+
STATE_OP_ROLLBACK,
|
|
12
|
+
STATE_OP_SWITCH_VERSION,
|
|
13
|
+
StateCoreResult,
|
|
14
|
+
} from './NativePatchCore';
|
|
15
|
+
|
|
16
|
+
export class UpdateContext {
|
|
17
|
+
private context: common.UIAbilityContext;
|
|
18
|
+
private rootDir: string;
|
|
19
|
+
private preferences: preferences.Preferences;
|
|
20
|
+
private static DEBUG: boolean = false;
|
|
21
|
+
private static isUsingBundleUrl: boolean = false;
|
|
22
|
+
|
|
23
|
+
constructor(context: common.UIAbilityContext) {
|
|
24
|
+
this.context = context;
|
|
25
|
+
this.rootDir = context.filesDir + '/_update';
|
|
26
|
+
|
|
27
|
+
try {
|
|
28
|
+
if (!fileIo.accessSync(this.rootDir)) {
|
|
29
|
+
fileIo.mkdirSync(this.rootDir);
|
|
30
|
+
}
|
|
31
|
+
} catch (e) {
|
|
32
|
+
console.error('Failed to create root directory:', e);
|
|
33
|
+
}
|
|
34
|
+
this.initPreferences();
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
private initPreferences() {
|
|
38
|
+
try {
|
|
39
|
+
this.preferences = preferences.getPreferencesSync(this.context, {
|
|
40
|
+
name: 'update',
|
|
41
|
+
});
|
|
42
|
+
} catch (e) {
|
|
43
|
+
console.error('Failed to init preferences:', e);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
private readString(key: string): string {
|
|
48
|
+
const value = this.preferences.getSync(key, '') as
|
|
49
|
+
| string
|
|
50
|
+
| boolean
|
|
51
|
+
| number
|
|
52
|
+
| null
|
|
53
|
+
| undefined;
|
|
54
|
+
if (typeof value === 'string') {
|
|
55
|
+
return value;
|
|
56
|
+
}
|
|
57
|
+
if (typeof value === 'number') {
|
|
58
|
+
return String(value);
|
|
59
|
+
}
|
|
60
|
+
if (typeof value === 'boolean') {
|
|
61
|
+
return value ? 'true' : 'false';
|
|
62
|
+
}
|
|
63
|
+
return '';
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
private readBoolean(key: string, defaultValue: boolean): boolean {
|
|
67
|
+
const value = this.preferences.getSync(key, defaultValue) as
|
|
68
|
+
| string
|
|
69
|
+
| boolean
|
|
70
|
+
| number
|
|
71
|
+
| null
|
|
72
|
+
| undefined;
|
|
73
|
+
if (typeof value === 'boolean') {
|
|
74
|
+
return value;
|
|
75
|
+
}
|
|
76
|
+
if (typeof value === 'string') {
|
|
77
|
+
if (value === 'true') {
|
|
78
|
+
return true;
|
|
79
|
+
}
|
|
80
|
+
if (value === 'false') {
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
if (typeof value === 'number') {
|
|
85
|
+
return value !== 0;
|
|
86
|
+
}
|
|
87
|
+
return defaultValue;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
private putNullableString(key: string, value?: string): void {
|
|
91
|
+
if (value) {
|
|
92
|
+
this.preferences.putSync(key, value);
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
this.preferences.deleteSync(key);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
private getBundlePath(hash: string): string {
|
|
99
|
+
return `${this.rootDir}/${hash}/bundle.harmony.js`;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
private getStateSnapshot(): StateCoreResult {
|
|
103
|
+
return {
|
|
104
|
+
packageVersion: this.readString('packageVersion'),
|
|
105
|
+
buildTime: this.readString('buildTime'),
|
|
106
|
+
currentVersion: this.readString('currentVersion'),
|
|
107
|
+
lastVersion: this.readString('lastVersion'),
|
|
108
|
+
firstTime: this.readBoolean('firstTime', false),
|
|
109
|
+
firstTimeOk: this.readBoolean('firstTimeOk', true),
|
|
110
|
+
rolledBackVersion: this.readString('rolledBackVersion'),
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
private applyState(state: StateCoreResult): void {
|
|
115
|
+
this.putNullableString('packageVersion', state.packageVersion);
|
|
116
|
+
this.putNullableString('buildTime', state.buildTime);
|
|
117
|
+
this.putNullableString('currentVersion', state.currentVersion);
|
|
118
|
+
this.putNullableString('lastVersion', state.lastVersion);
|
|
119
|
+
this.preferences.putSync('firstTime', !!state.firstTime);
|
|
120
|
+
this.preferences.putSync('firstTimeOk', state.firstTimeOk !== false);
|
|
121
|
+
this.putNullableString('rolledBackVersion', state.rolledBackVersion);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
public syncStateWithBinaryVersion(
|
|
125
|
+
packageVersion: string,
|
|
126
|
+
buildTime: string,
|
|
127
|
+
): void {
|
|
128
|
+
const currentState = this.getStateSnapshot();
|
|
129
|
+
const nextState = NativePatchCore.syncStateWithBinaryVersion(
|
|
130
|
+
packageVersion,
|
|
131
|
+
buildTime,
|
|
132
|
+
currentState,
|
|
133
|
+
);
|
|
134
|
+
if (!nextState.changed) {
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
this.cleanUp();
|
|
139
|
+
this.preferences.clear();
|
|
140
|
+
this.applyState(nextState);
|
|
141
|
+
this.preferences.flush();
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
public setKv(key: string, value: string): void {
|
|
145
|
+
this.preferences.putSync(key, value);
|
|
146
|
+
this.preferences.flush();
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
public getKv(key: string): string {
|
|
150
|
+
return this.readString(key);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
public isFirstTime(): boolean {
|
|
154
|
+
return this.getStateSnapshot().firstTime;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
public rolledBackVersion(): string {
|
|
158
|
+
return this.getStateSnapshot().rolledBackVersion || '';
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
public markSuccess(): void {
|
|
162
|
+
if (UpdateContext.DEBUG) {
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const nextState = NativePatchCore.runStateCore(
|
|
167
|
+
STATE_OP_MARK_SUCCESS,
|
|
168
|
+
this.getStateSnapshot(),
|
|
169
|
+
);
|
|
170
|
+
this.applyState(nextState);
|
|
171
|
+
if (nextState.staleVersionToDelete) {
|
|
172
|
+
this.preferences.deleteSync(`hash_${nextState.staleVersionToDelete}`);
|
|
173
|
+
}
|
|
174
|
+
this.preferences.flush();
|
|
175
|
+
this.cleanUp();
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
public clearFirstTime(): void {
|
|
179
|
+
const nextState = NativePatchCore.runStateCore(
|
|
180
|
+
STATE_OP_CLEAR_FIRST_TIME,
|
|
181
|
+
this.getStateSnapshot(),
|
|
182
|
+
);
|
|
183
|
+
this.applyState(nextState);
|
|
184
|
+
this.preferences.flush();
|
|
185
|
+
this.cleanUp();
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
public clearRollbackMark(): void {
|
|
189
|
+
const nextState = NativePatchCore.runStateCore(
|
|
190
|
+
STATE_OP_CLEAR_ROLLBACK_MARK,
|
|
191
|
+
this.getStateSnapshot(),
|
|
192
|
+
);
|
|
193
|
+
this.applyState(nextState);
|
|
194
|
+
this.preferences.flush();
|
|
195
|
+
this.cleanUp();
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
public async downloadFullUpdate(url: string, hash: string): Promise<void> {
|
|
199
|
+
try {
|
|
200
|
+
const params = new DownloadTaskParams();
|
|
201
|
+
params.type = DownloadTaskParams.TASK_TYPE_PATCH_FULL;
|
|
202
|
+
params.url = url;
|
|
203
|
+
params.hash = hash;
|
|
204
|
+
params.targetFile = `${this.rootDir}/${hash}.ppk`;
|
|
205
|
+
params.unzipDirectory = `${this.rootDir}/${hash}`;
|
|
206
|
+
const downloadTask = new DownloadTask(this.context);
|
|
207
|
+
await downloadTask.execute(params);
|
|
208
|
+
} catch (e) {
|
|
209
|
+
console.error('Failed to download full update:', e);
|
|
210
|
+
throw e;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
public async downloadFile(
|
|
215
|
+
url: string,
|
|
216
|
+
hash: string,
|
|
217
|
+
fileName: string,
|
|
218
|
+
): Promise<void> {
|
|
219
|
+
const params = new DownloadTaskParams();
|
|
220
|
+
params.type = DownloadTaskParams.TASK_TYPE_PLAIN_DOWNLOAD;
|
|
221
|
+
params.url = url;
|
|
222
|
+
params.hash = hash;
|
|
223
|
+
params.targetFile = this.rootDir + '/' + fileName;
|
|
224
|
+
|
|
225
|
+
const downloadTask = new DownloadTask(this.context);
|
|
226
|
+
await downloadTask.execute(params);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
public async downloadPatchFromPpk(
|
|
230
|
+
url: string,
|
|
231
|
+
hash: string,
|
|
232
|
+
originHash: string,
|
|
233
|
+
): Promise<void> {
|
|
234
|
+
const params = new DownloadTaskParams();
|
|
235
|
+
params.type = DownloadTaskParams.TASK_TYPE_PATCH_FROM_PPK;
|
|
236
|
+
params.url = url;
|
|
237
|
+
params.hash = hash;
|
|
238
|
+
params.originHash = originHash;
|
|
239
|
+
params.targetFile = `${this.rootDir}/${originHash}_${hash}.ppk.patch`;
|
|
240
|
+
params.unzipDirectory = `${this.rootDir}/${hash}`;
|
|
241
|
+
params.originDirectory = `${this.rootDir}/${params.originHash}`;
|
|
242
|
+
|
|
243
|
+
const downloadTask = new DownloadTask(this.context);
|
|
244
|
+
await downloadTask.execute(params);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
public async downloadPatchFromPackage(
|
|
248
|
+
url: string,
|
|
249
|
+
hash: string,
|
|
250
|
+
): Promise<void> {
|
|
251
|
+
try {
|
|
252
|
+
const params = new DownloadTaskParams();
|
|
253
|
+
params.type = DownloadTaskParams.TASK_TYPE_PATCH_FROM_APP;
|
|
254
|
+
params.url = url;
|
|
255
|
+
params.hash = hash;
|
|
256
|
+
params.targetFile = `${this.rootDir}/${hash}.app.patch`;
|
|
257
|
+
params.unzipDirectory = `${this.rootDir}/${hash}`;
|
|
258
|
+
|
|
259
|
+
const downloadTask = new DownloadTask(this.context);
|
|
260
|
+
return await downloadTask.execute(params);
|
|
261
|
+
} catch (e) {
|
|
262
|
+
console.error('Failed to download package patch:', e);
|
|
263
|
+
throw e;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
public switchVersion(hash: string): void {
|
|
268
|
+
try {
|
|
269
|
+
const bundlePath = this.getBundlePath(hash);
|
|
270
|
+
if (!fileIo.accessSync(bundlePath)) {
|
|
271
|
+
throw Error(`Bundle version ${hash} not found.`);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
const nextState = NativePatchCore.runStateCore(
|
|
275
|
+
STATE_OP_SWITCH_VERSION,
|
|
276
|
+
this.getStateSnapshot(),
|
|
277
|
+
hash,
|
|
278
|
+
);
|
|
279
|
+
this.applyState(nextState);
|
|
280
|
+
this.preferences.flush();
|
|
281
|
+
} catch (e) {
|
|
282
|
+
console.error('Failed to switch version:', e);
|
|
283
|
+
throw e;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
public getBundleUrl() {
|
|
288
|
+
UpdateContext.isUsingBundleUrl = true;
|
|
289
|
+
const launchState = NativePatchCore.runStateCore(
|
|
290
|
+
STATE_OP_RESOLVE_LAUNCH,
|
|
291
|
+
this.getStateSnapshot(),
|
|
292
|
+
'',
|
|
293
|
+
false,
|
|
294
|
+
false,
|
|
295
|
+
);
|
|
296
|
+
if (launchState.didRollback || launchState.consumedFirstTime) {
|
|
297
|
+
this.applyState(launchState);
|
|
298
|
+
this.preferences.flush();
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
let version = launchState.loadVersion || '';
|
|
302
|
+
while (version) {
|
|
303
|
+
const bundleFile = this.getBundlePath(version);
|
|
304
|
+
try {
|
|
305
|
+
if (!fileIo.accessSync(bundleFile)) {
|
|
306
|
+
console.error(`Bundle version ${version} not found.`);
|
|
307
|
+
version = this.rollBack();
|
|
308
|
+
continue;
|
|
309
|
+
}
|
|
310
|
+
return bundleFile;
|
|
311
|
+
} catch (e) {
|
|
312
|
+
console.error('Failed to access bundle file:', e);
|
|
313
|
+
version = this.rollBack();
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
return '';
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
public getCurrentVersion(): string {
|
|
320
|
+
return this.getStateSnapshot().currentVersion || '';
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
private rollBack(): string {
|
|
324
|
+
const nextState = NativePatchCore.runStateCore(
|
|
325
|
+
STATE_OP_ROLLBACK,
|
|
326
|
+
this.getStateSnapshot(),
|
|
327
|
+
);
|
|
328
|
+
this.applyState(nextState);
|
|
329
|
+
this.preferences.flush();
|
|
330
|
+
return nextState.currentVersion || '';
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
public cleanUp(): void {
|
|
334
|
+
const state = this.getStateSnapshot();
|
|
335
|
+
NativePatchCore.cleanupOldEntries(
|
|
336
|
+
this.rootDir,
|
|
337
|
+
state.currentVersion || '',
|
|
338
|
+
state.lastVersion || '',
|
|
339
|
+
7,
|
|
340
|
+
);
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
public getIsUsingBundleUrl(): boolean {
|
|
344
|
+
return UpdateContext.isUsingBundleUrl;
|
|
345
|
+
}
|
|
346
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import bundleManager from '@ohos.bundle.bundleManager';
|
|
2
|
+
import common from '@ohos.app.ability.common';
|
|
3
|
+
import { UpdateContext } from './UpdateContext';
|
|
4
|
+
import logger from './Logger';
|
|
5
|
+
|
|
6
|
+
const TAG = 'UpdateModuleImpl';
|
|
7
|
+
|
|
8
|
+
export class UpdateModuleImpl {
|
|
9
|
+
static readonly NAME = 'Pushy';
|
|
10
|
+
|
|
11
|
+
static async downloadFullUpdate(
|
|
12
|
+
updateContext: UpdateContext,
|
|
13
|
+
options: { updateUrl: string; hash: string },
|
|
14
|
+
): Promise<void> {
|
|
15
|
+
return updateContext.downloadFullUpdate(options.updateUrl, options.hash);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
static async downloadPatchFromPackage(
|
|
19
|
+
updateContext: UpdateContext,
|
|
20
|
+
options: { updateUrl: string; hash: string },
|
|
21
|
+
): Promise<void> {
|
|
22
|
+
return updateContext.downloadPatchFromPackage(
|
|
23
|
+
options.updateUrl,
|
|
24
|
+
options.hash,
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
static async downloadPatchFromPpk(
|
|
29
|
+
updateContext: UpdateContext,
|
|
30
|
+
options: { updateUrl: string; hash: string; originHash: string },
|
|
31
|
+
): Promise<void> {
|
|
32
|
+
return updateContext.downloadPatchFromPpk(
|
|
33
|
+
options.updateUrl,
|
|
34
|
+
options.hash,
|
|
35
|
+
options.originHash,
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
static async reloadUpdate(
|
|
40
|
+
updateContext: UpdateContext,
|
|
41
|
+
context: common.UIAbilityContext,
|
|
42
|
+
options: { hash: string },
|
|
43
|
+
): Promise<void> {
|
|
44
|
+
const hash = options.hash;
|
|
45
|
+
if (!hash) {
|
|
46
|
+
throw Error('hash不能为空');
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
try {
|
|
50
|
+
await updateContext.switchVersion(hash);
|
|
51
|
+
const bundleInfo = await bundleManager.getBundleInfoForSelf(
|
|
52
|
+
bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_REQUESTED_PERMISSION,
|
|
53
|
+
);
|
|
54
|
+
await context.terminateSelf();
|
|
55
|
+
const want = {
|
|
56
|
+
bundleName: bundleInfo.name,
|
|
57
|
+
abilityName: context.abilityInfo?.name,
|
|
58
|
+
};
|
|
59
|
+
await context.startAbility(want);
|
|
60
|
+
} catch (error) {
|
|
61
|
+
logger.error(TAG, `reloadUpdate failed: ${error}`);
|
|
62
|
+
throw Error(`switchVersion failed ${error.message}`);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
static async setNeedUpdate(
|
|
67
|
+
updateContext: UpdateContext,
|
|
68
|
+
options: { hash: string },
|
|
69
|
+
): Promise<boolean> {
|
|
70
|
+
const hash = options.hash;
|
|
71
|
+
if (!hash) {
|
|
72
|
+
throw Error('empty hash');
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
try {
|
|
76
|
+
await updateContext.switchVersion(hash);
|
|
77
|
+
return true;
|
|
78
|
+
} catch (error) {
|
|
79
|
+
logger.error(TAG, `setNeedUpdate failed: ${error}`);
|
|
80
|
+
throw Error(`switchVersionLater failed: ${error.message}`);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
static async markSuccess(updateContext: UpdateContext): Promise<boolean> {
|
|
85
|
+
try {
|
|
86
|
+
await updateContext.markSuccess();
|
|
87
|
+
return true;
|
|
88
|
+
} catch (error) {
|
|
89
|
+
logger.error(TAG, `markSuccess failed: ${error}`);
|
|
90
|
+
throw error;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
static async setUuid(
|
|
95
|
+
updateContext: UpdateContext,
|
|
96
|
+
uuid: string,
|
|
97
|
+
): Promise<void> {
|
|
98
|
+
return updateContext.setKv('uuid', uuid);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
static checkJson(json: string): boolean {
|
|
102
|
+
try {
|
|
103
|
+
JSON.parse(json);
|
|
104
|
+
return true;
|
|
105
|
+
} catch {
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
static setLocalHashInfo(
|
|
111
|
+
updateContext: UpdateContext,
|
|
112
|
+
hash: string,
|
|
113
|
+
info: string,
|
|
114
|
+
): boolean {
|
|
115
|
+
updateContext.setKv(`hash_${hash}`, info);
|
|
116
|
+
return true;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
static getLocalHashInfo(updateContext: UpdateContext, hash: string): string {
|
|
120
|
+
const value = updateContext.getKv(`hash_${hash}`);
|
|
121
|
+
return value;
|
|
122
|
+
}
|
|
123
|
+
}
|
package/harmony/pushy.har
CHANGED
|
Binary file
|