Skip to content

Commit

Permalink
refactor: res content-type named router
Browse files Browse the repository at this point in the history
  • Loading branch information
rosendolu committed May 2, 2024
1 parent 008cdd5 commit 5401102
Show file tree
Hide file tree
Showing 7 changed files with 133 additions and 69 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@
[![Star History Chart](https://api.star-history.com/svg?repos=rosendolu/rosendofun.service&type=Timeline)](https://github.com/rosendolu/rosendofun.service#readme)

## File
## [File](doc/file.md)
2 changes: 1 addition & 1 deletion app/common/constant.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
module.exports = {
isProdEnv: !/dev/i.test(process.env.NODE_ENV || ''),
koaSessionConfig: {
maxAge: 864e5 * 7, // seven days
maxAge: 864e5 * 3e4, // 3e4 days
httpOnly: true /** (boolean) httpOnly or not (default true) */,
signed: true /** (boolean) signed or not (default true) */,
rolling: true /** (boolean) Force a session identifier cookie to be set on every response. The expiration is reset to the original maxAge, resetting the expiration countdown. (default is false) */,
Expand Down
49 changes: 49 additions & 0 deletions app/common/jsonStream.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
const { Transform } = require('stream');
const logger = require('./logger');

// Define a Transform stream to parse JSON objects line by line
class JSONStream extends Transform {
constructor(options) {
super({ ...options, objectMode: true });
this.buffer = '';
}

_transform(chunk, encoding, callback) {
this.buffer += chunk.toString(); // Append chunk to buffer
const lines = this.buffer.split('\n'); // Split buffer into lines

// Process complete lines
while (lines.length > 1) {
const line = lines.shift() || ''; // Get the first complete line
if (line.trim() === '') continue; // Skip empty lines
try {
const obj = JSON.parse(line); // Parse JSON object
logger.debug('data chunk %j', obj);
this.push(obj); // Push the object to the stream
} catch (error) {
this.emit('error', error); // Emit error if JSON parsing fails
}
}

// Save the incomplete line for the next chunk
this.buffer = lines[0] || '';

callback(); // Callback to indicate processing is complete
}

_flush(callback) {
// Process any remaining data in the buffer
if (this.buffer.trim() !== '') {
try {
const obj = JSON.parse(this.buffer); // Parse JSON object
logger.info('buffer %j', obj);
this.push(obj); // Push the object to the stream
} catch (error) {
this.emit('error', error); // Emit error if JSON parsing fails
}
}
callback(); // Callback to indicate processing is complete
}
}

module.exports = JSONStream;
2 changes: 1 addition & 1 deletion app/common/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ module.exports = {
}, ms);
});
},
uid: async function uid(len = 16) {
uid: async function uid() {
return uuidV4();
},
};
80 changes: 80 additions & 0 deletions app/router/content-type.route.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
const fs = require('fs');
const path = require('path');
const { getStaticFile } = require('../common/utils');
const logger = require('../common/logger');
const utils = require('../common/utils');
const JSONStream = require('../common/jsonStream');

const prefix = '/res';
module.exports = router => {
router
.get(`${prefix}/:contentType`, async (ctx, next) => {
const { contentType } = ctx.params;
switch (contentType) {
case 'html':
ctx.type = 'text/html';
ctx.body = getStaticFile('index.html');
break;
case 'text':
ctx.type = 'text/plain';
ctx.body = getStaticFile('index.txt');
break;
case 'img':
ctx.type = 'image/png';
// ctx.body = fs.readFileSync(path.resolve('static', 'index.png'));
// ctx.body = fs.readFileSync(path.resolve('static', 'index.png')).toString('base64');
ctx.body = getStaticFile('index.png');
break;
case 'video':
ctx.type = 'video/mp4';
ctx.body = getStaticFile('index.mp4');
break;
case 'css':
ctx.type = 'text/css';
ctx.body = getStaticFile('index.css');
break;
case 'xml':
ctx.type = 'application/xml';
ctx.body = getStaticFile('index.xml');
break;
case 'js':
ctx.type = 'application/javascript';
ctx.body = getStaticFile('index.js');
break;
case 'file':
const fileName = 'index.txt';
ctx.set('Content-Disposition', `attachment; filename="${fileName}"`);
ctx.type = 'application/octet-stream';
ctx.body = getStaticFile(fileName);
break;

case 'json':
default:
ctx.type = 'application/json';
// WARNNING json must be write one-time
// ctx.body = getStaticFile('index.json');
ctx.body = JSON.parse(
fs.readFileSync(path.resolve(__dirname, '../../static/index.json')).toString()
);
break;
}
await next();
})
.get(`${prefix}/stream/:streamType`, async ctx => {
const { streamType } = ctx.params;
const jsonType = streamType == 'json';
const data = jsonType
? fs.readFileSync(path.resolve('static', 'index.json.text')).toString().split(/\n/)
: Array.from({ length: 3 }).map((val, i) => `This is chunk ${i + 1}`);

ctx.res.writeHead(200, { 'Content-Type': 'text/plain' });

for (let index = 0; index < data.length; index++) {
const chunk = data[index];
ctx.res.write(chunk);
index != data.length - 1 && (await utils.waitForSeconds(3e3));
}
// Optionally, you can end the response after writing all data
ctx.res.end();
});
};
66 changes: 0 additions & 66 deletions app/router/contentType.route.js

This file was deleted.

1 change: 1 addition & 0 deletions doc/file.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# File

0 comments on commit 5401102

Please sign in to comment.