react-native-update 10.37.4 → 10.37.6
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.
|
@@ -18,7 +18,6 @@ interface ZipFile {
|
|
|
18
18
|
export class DownloadTask {
|
|
19
19
|
private context: common.Context;
|
|
20
20
|
private hash: string;
|
|
21
|
-
private readonly DOWNLOAD_CHUNK_SIZE = 4096;
|
|
22
21
|
private eventHub: EventHub;
|
|
23
22
|
|
|
24
23
|
constructor(context: common.Context) {
|
|
@@ -53,27 +52,104 @@ export class DownloadTask {
|
|
|
53
52
|
private async downloadFile(params: DownloadTaskParams): Promise<void> {
|
|
54
53
|
const httpRequest = http.createHttp();
|
|
55
54
|
this.hash = params.hash;
|
|
55
|
+
let writer: fileIo.File | null = null;
|
|
56
|
+
let contentLength = 0;
|
|
57
|
+
let received = 0;
|
|
58
|
+
let writeError: Error | null = null;
|
|
59
|
+
let writeQueue = Promise.resolve();
|
|
60
|
+
|
|
61
|
+
const closeWriter = async () => {
|
|
62
|
+
if (writer) {
|
|
63
|
+
await fileIo.close(writer);
|
|
64
|
+
writer = null;
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
const dataEndPromise = new Promise<void>((resolve, reject) => {
|
|
69
|
+
httpRequest.on('dataEnd', () => {
|
|
70
|
+
writeQueue
|
|
71
|
+
.then(async () => {
|
|
72
|
+
if (writeError) {
|
|
73
|
+
throw writeError;
|
|
74
|
+
}
|
|
75
|
+
await closeWriter();
|
|
76
|
+
resolve();
|
|
77
|
+
})
|
|
78
|
+
.catch(async error => {
|
|
79
|
+
await closeWriter();
|
|
80
|
+
reject(error);
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
});
|
|
56
84
|
|
|
57
85
|
try {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
await fileIo.mkdir(targetDir);
|
|
70
|
-
}
|
|
86
|
+
let exists = fileIo.accessSync(params.targetFile);
|
|
87
|
+
if (exists) {
|
|
88
|
+
await fileIo.unlink(params.targetFile);
|
|
89
|
+
} else {
|
|
90
|
+
const targetDir = params.targetFile.substring(
|
|
91
|
+
0,
|
|
92
|
+
params.targetFile.lastIndexOf('/'),
|
|
93
|
+
);
|
|
94
|
+
exists = fileIo.accessSync(targetDir);
|
|
95
|
+
if (!exists) {
|
|
96
|
+
await fileIo.mkdir(targetDir);
|
|
71
97
|
}
|
|
72
|
-
} catch (error) {
|
|
73
|
-
throw error;
|
|
74
98
|
}
|
|
75
99
|
|
|
76
|
-
|
|
100
|
+
writer = await fileIo.open(
|
|
101
|
+
params.targetFile,
|
|
102
|
+
fileIo.OpenMode.CREATE | fileIo.OpenMode.READ_WRITE,
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
httpRequest.on('headersReceive', (header: Record<string, string>) => {
|
|
106
|
+
if (!header) {
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
const lengthKey = Object.keys(header).find(
|
|
110
|
+
key => key.toLowerCase() === 'content-length',
|
|
111
|
+
);
|
|
112
|
+
if (!lengthKey) {
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
const length = parseInt(header[lengthKey], 10);
|
|
116
|
+
if (!Number.isNaN(length)) {
|
|
117
|
+
contentLength = length;
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
httpRequest.on('dataReceive', (data: ArrayBuffer) => {
|
|
122
|
+
if (writeError) {
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
received += data.byteLength;
|
|
126
|
+
writeQueue = writeQueue.then(async () => {
|
|
127
|
+
if (!writer || writeError) {
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
try {
|
|
131
|
+
await fileIo.write(writer.fd, data);
|
|
132
|
+
} catch (error) {
|
|
133
|
+
writeError = error as Error;
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
this.onProgressUpdate(received, contentLength);
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
httpRequest.on(
|
|
140
|
+
'dataReceiveProgress',
|
|
141
|
+
(data: http.DataReceiveProgressInfo) => {
|
|
142
|
+
if (data.totalSize > 0) {
|
|
143
|
+
contentLength = data.totalSize;
|
|
144
|
+
}
|
|
145
|
+
if (data.receiveSize > received) {
|
|
146
|
+
received = data.receiveSize;
|
|
147
|
+
}
|
|
148
|
+
this.onProgressUpdate(received, contentLength);
|
|
149
|
+
},
|
|
150
|
+
);
|
|
151
|
+
|
|
152
|
+
const responseCode = await httpRequest.requestInStream(params.url, {
|
|
77
153
|
method: http.RequestMethod.GET,
|
|
78
154
|
readTimeout: 60000,
|
|
79
155
|
connectTimeout: 60000,
|
|
@@ -81,32 +157,14 @@ export class DownloadTask {
|
|
|
81
157
|
'Content-Type': 'application/octet-stream',
|
|
82
158
|
},
|
|
83
159
|
});
|
|
84
|
-
if (
|
|
85
|
-
throw Error(`Server error: ${
|
|
160
|
+
if (responseCode > 299) {
|
|
161
|
+
throw Error(`Server error: ${responseCode}`);
|
|
86
162
|
}
|
|
87
163
|
|
|
88
|
-
|
|
89
|
-
const writer = await fileIo.open(
|
|
90
|
-
params.targetFile,
|
|
91
|
-
fileIo.OpenMode.CREATE | fileIo.OpenMode.READ_WRITE,
|
|
92
|
-
);
|
|
93
|
-
let received = 0;
|
|
94
|
-
const data = response.result as ArrayBuffer;
|
|
95
|
-
const chunks = Math.ceil(data.byteLength / this.DOWNLOAD_CHUNK_SIZE);
|
|
96
|
-
for (let i = 0; i < chunks; i++) {
|
|
97
|
-
const start = i * this.DOWNLOAD_CHUNK_SIZE;
|
|
98
|
-
const end = Math.min(start + this.DOWNLOAD_CHUNK_SIZE, data.byteLength);
|
|
99
|
-
const chunk = data.slice(start, end);
|
|
100
|
-
|
|
101
|
-
await fileIo.write(writer.fd, chunk);
|
|
102
|
-
received += chunk.byteLength;
|
|
103
|
-
|
|
104
|
-
this.onProgressUpdate(received, contentLength);
|
|
105
|
-
}
|
|
106
|
-
await fileIo.close(writer);
|
|
164
|
+
await dataEndPromise;
|
|
107
165
|
const stats = await fileIo.stat(params.targetFile);
|
|
108
166
|
const fileSize = stats.size;
|
|
109
|
-
if (fileSize !== contentLength) {
|
|
167
|
+
if (contentLength > 0 && fileSize !== contentLength) {
|
|
110
168
|
throw Error(
|
|
111
169
|
`Download incomplete: expected ${contentLength} bytes but got ${stats.size} bytes`,
|
|
112
170
|
);
|
|
@@ -115,6 +173,15 @@ export class DownloadTask {
|
|
|
115
173
|
console.error('Download failed:', error);
|
|
116
174
|
throw error;
|
|
117
175
|
} finally {
|
|
176
|
+
try {
|
|
177
|
+
await closeWriter();
|
|
178
|
+
} catch (closeError) {
|
|
179
|
+
console.error('Failed to close file:', closeError);
|
|
180
|
+
}
|
|
181
|
+
httpRequest.off('headersReceive');
|
|
182
|
+
httpRequest.off('dataReceive');
|
|
183
|
+
httpRequest.off('dataReceiveProgress');
|
|
184
|
+
httpRequest.off('dataEnd');
|
|
118
185
|
httpRequest.destroy();
|
|
119
186
|
}
|
|
120
187
|
}
|
|
@@ -432,7 +499,6 @@ export class DownloadTask {
|
|
|
432
499
|
default:
|
|
433
500
|
throw Error(`Unknown task type: ${params.type}`);
|
|
434
501
|
}
|
|
435
|
-
|
|
436
502
|
} catch (error) {
|
|
437
503
|
console.error('Task execution failed:', error.message);
|
|
438
504
|
if (params.type !== DownloadTaskParams.TASK_TYPE_CLEANUP) {
|
|
@@ -86,7 +86,7 @@ export class PushyTurboModule extends TurboModule {
|
|
|
86
86
|
return UpdateModuleImpl.getLocalHashInfo(this.context, hash);
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
-
async setUuid(uuid: string): Promise<
|
|
89
|
+
async setUuid(uuid: string): Promise<void> {
|
|
90
90
|
logger.debug(TAG, ',call setUuid');
|
|
91
91
|
return UpdateModuleImpl.setUuid(this.context, uuid);
|
|
92
92
|
}
|
|
@@ -131,15 +131,6 @@ export class PushyTurboModule extends TurboModule {
|
|
|
131
131
|
return UpdateModuleImpl.downloadFullUpdate(this.context, options);
|
|
132
132
|
}
|
|
133
133
|
|
|
134
|
-
async downloadAndInstallApk(options: {
|
|
135
|
-
url: string;
|
|
136
|
-
target: string;
|
|
137
|
-
hash: string;
|
|
138
|
-
}): Promise<void> {
|
|
139
|
-
logger.debug(TAG, ',call downloadAndInstallApk');
|
|
140
|
-
return UpdateModuleImpl.downloadAndInstallApk(this.mUiCtx, options);
|
|
141
|
-
}
|
|
142
|
-
|
|
143
134
|
addListener(_eventName: string): void {
|
|
144
135
|
logger.debug(TAG, ',call addListener');
|
|
145
136
|
}
|
package/package.json
CHANGED
package/src/client.ts
CHANGED
|
@@ -282,19 +282,23 @@ export class Pushy {
|
|
|
282
282
|
type: 'errorChecking',
|
|
283
283
|
message: this.t('error_cannot_connect_backup', { message: e.message }),
|
|
284
284
|
});
|
|
285
|
-
const backupEndpoints = await this.getBackupEndpoints();
|
|
285
|
+
const backupEndpoints = await this.getBackupEndpoints().catch();
|
|
286
286
|
if (backupEndpoints) {
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
287
|
+
resp = await promiseAny(
|
|
288
|
+
backupEndpoints.map(endpoint =>
|
|
289
|
+
enhancedFetch(this.getCheckUrl(endpoint), fetchPayload),
|
|
290
|
+
),
|
|
291
|
+
).catch(() => {
|
|
292
|
+
this.report({
|
|
293
|
+
type: 'errorChecking',
|
|
294
|
+
message: this.t('errorCheckingUseBackup'),
|
|
295
|
+
});
|
|
296
|
+
});
|
|
296
297
|
} else {
|
|
297
|
-
this.
|
|
298
|
+
this.report({
|
|
299
|
+
type: 'errorChecking',
|
|
300
|
+
message: this.t('errorCheckingGetBackup'),
|
|
301
|
+
});
|
|
298
302
|
}
|
|
299
303
|
}
|
|
300
304
|
if (!resp) {
|
|
@@ -316,7 +320,7 @@ export class Pushy {
|
|
|
316
320
|
type: 'errorChecking',
|
|
317
321
|
message: errorMessage,
|
|
318
322
|
});
|
|
319
|
-
this.throwIfEnabled(Error(errorMessage));
|
|
323
|
+
this.throwIfEnabled(Error('errorChecking: ' + errorMessage));
|
|
320
324
|
return this.lastRespJson ? await this.lastRespJson : emptyObj;
|
|
321
325
|
}
|
|
322
326
|
this.lastRespJson = resp.json();
|