ZIP extraction error handling (#4002) * Improve error handling in extractFileFromZipBuffer function * Add warning logging to NovelAI image upscaling

c218c1baeaa58025ce38f1abc0dec742b0156097

Cohee <18619528+Cohee1207@users.noreply.github.com>

Signed
2 files changed, +51 -27Ignore whitespace
src/endpoints/novelai.js+3 -2
@@ -394,7 +394,8 @@ router.post('/generate-image', async (request, response) => {
394 });394 });
395395
396 if (!upscaleResult.ok) {396 if (!upscaleResult.ok) {
397 throw new Error('NovelAI returned an error.');397 const text = await upscaleResult.text();
398 throw new Error('NovelAI returned an error.', { cause: text });
398 }399 }
399400
400 const upscaledArchiveBuffer = await upscaleResult.arrayBuffer();401 const upscaledArchiveBuffer = await upscaleResult.arrayBuffer();
@@ -408,7 +409,7 @@ router.post('/generate-image', async (request, response) => {
408409
409 return response.send(upscaledBase64);410 return response.send(upscaledBase64);
410 } catch (error) {411 } catch (error) {
411 console.warn('NovelAI generated an image, but upscaling failed. Returning original image.');412 console.warn('NovelAI generated an image, but upscaling failed. Returning original image.', error);
412 return response.send(originalBase64);413 return response.send(originalBase64);
413 }414 }
414 } catch (error) {415 } catch (error) {
src/util.js+48 -25
@@ -207,35 +207,58 @@ export function formatBytes(bytes) {
207 * @returns {Promise<Buffer|null>} Buffer containing the extracted file. Null if the file was not found.207 * @returns {Promise<Buffer|null>} Buffer containing the extracted file. Null if the file was not found.
208 */208 */
209export async function extractFileFromZipBuffer(archiveBuffer, fileExtension) {209export async function extractFileFromZipBuffer(archiveBuffer, fileExtension) {
210 return await new Promise((resolve, reject) => yauzl.fromBuffer(Buffer.from(archiveBuffer), { lazyEntries: true }, (err, zipfile) => {210 return await new Promise((resolve) => {
211 if (err) reject(err);211 try {
212212 yauzl.fromBuffer(Buffer.from(archiveBuffer), { lazyEntries: true }, (err, zipfile) => {
213 zipfile.readEntry();213 if (err) {
214 zipfile.on('entry', (entry) => {214 console.warn(`Error opening ZIP file: ${err.message}`);
215 if (entry.fileName.endsWith(fileExtension) && !entry.fileName.startsWith('__MACOSX')) {215 return resolve(null);
216 console.info(`Extracting ${entry.fileName}`);216 }
217 zipfile.openReadStream(entry, (err, readStream) => {217
218 if (err) {218 zipfile.readEntry();
219 reject(err);219
220 } else {220 zipfile.on('entry', (entry) => {
221 const chunks = [];221 if (entry.fileName.endsWith(fileExtension) && !entry.fileName.startsWith('__MACOSX')) {
222 readStream.on('data', (chunk) => {222 console.info(`Extracting ${entry.fileName}`);
223 chunks.push(chunk);223 zipfile.openReadStream(entry, (err, readStream) => {
224 });224 if (err) {
225 console.warn(`Error opening read stream: ${err.message}`);
226 return zipfile.readEntry();
227 } else {
228 const chunks = [];
229 readStream.on('data', (chunk) => {
230 chunks.push(chunk);
231 });
232
233 readStream.on('end', () => {
234 const buffer = Buffer.concat(chunks);
235 resolve(buffer);
236 zipfile.readEntry(); // Continue to the next entry
237 });
225238
226 readStream.on('end', () => {239 readStream.on('error', (err) => {
227 const buffer = Buffer.concat(chunks);240 console.warn(`Error reading stream: ${err.message}`);
228 resolve(buffer);241 zipfile.readEntry();
229 zipfile.readEntry(); // Continue to the next entry242 });
243 }
230 });244 });
245 } else {
246 zipfile.readEntry();
231 }247 }
232 });248 });
233 } else {249
234 zipfile.readEntry();250 zipfile.on('error', (err) => {
235 }251 console.warn('ZIP processing error', err);
236 });252 resolve(null);
237 zipfile.on('end', () => resolve(null));253 });
238 }));254
255 zipfile.on('end', () => resolve(null));
256 });
257 } catch (error) {
258 console.warn('Failed to process ZIP buffer', error);
259 resolve(null);
260 }
261 });
239}262}
240263
241/**264/**