Skip to content

Commit 16eec29

Browse files
authoredJan 30, 2021
Merge pull request #45 from Moumouls/moumouls/fix-huge-data
fix: content length mismatch
2 parents 7cd79d7 + 697d0f6 commit 16eec29

File tree

2 files changed

+74
-46
lines changed

2 files changed

+74
-46
lines changed
 

‎src/server.ts

+29-18
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ export class Server {
1010
private instance: HttpServer;
1111
private plotsContainer: IPlotsContainer = {};
1212
private port: number;
13-
private sockets: {[id: number]: Socket} = {};
13+
private sockets: { [id: number]: Socket } = {};
1414
private nextSocketID = 0;
1515

1616
constructor(port: number) {
@@ -74,18 +74,24 @@ export class Server {
7474

7575
private openWindow(location: string) {
7676
switch (type()) {
77-
case 'Linux': exec(`xdg-open ${location}`); break;
78-
case 'Darwin': exec(`open ${location}`); break;
79-
case 'Windows_NT': exec(`start ${location}`); break;
77+
case 'Linux':
78+
exec(`xdg-open ${location}`);
79+
break;
80+
case 'Darwin':
81+
exec(`open ${location}`);
82+
break;
83+
case 'Windows_NT':
84+
exec(`start ${location}`);
85+
break;
8086
}
8187
}
8288

8389
/**
8490
* Creates the Webserver instance
8591
*/
8692
private createServer(): HttpServer {
87-
return createServer((req, res) => {
88-
if (!this.serveData(req, res)) {
93+
return createServer(async (req, res) => {
94+
if (!(await this.serveData(req, res))) {
8995
this.serveWebsite(req, res); // only serve website if request was not served from serveData
9096
}
9197
});
@@ -94,32 +100,39 @@ export class Server {
94100
/**
95101
* Serves the plot data at /data/:id of the container[id].
96102
* It markes the container as opened and not pending anymore.
97-
* @param req
103+
* @param req
98104
* @param res
99105
* @returns {boolean} - Whether the request was served or not
100106
*/
101-
private serveData(req: IncomingMessage, res: ServerResponse) {
107+
private async serveData(req: IncomingMessage, res: ServerResponse) {
102108
if (req && req.url && req.url.match(/data\/[0-9]+/)) {
103109
const segments = req.url.split('/');
104110
const id = +segments[segments.length - 1];
105-
111+
106112
const container = this.plotsContainer[id];
107113
const temporaryPlots = container && container.plots;
108114

109115
this.plotsContainer[id].opened = true;
110116
this.plotsContainer[id].pending = false;
111117

112118
res.end(JSON.stringify(temporaryPlots));
113-
this.close();
119+
// Wait before closing the server
120+
// to avoid https://github.com/ngfelixl/nodeplotlib/issues/20
121+
await new Promise<void>(resolve =>
122+
res.on('finish', () => {
123+
this.close();
124+
resolve();
125+
}),
126+
);
114127
return true; // request successfully server
115128
}
116129
return false; // request not served
117130
}
118131

119132
/**
120133
* Serves the website at http://localhost:PORT/plots/:id/index.html
121-
* @param req
122-
* @param res
134+
* @param req
135+
* @param res
123136
*/
124137
private serveWebsite(req: IncomingMessage, res: ServerResponse) {
125138
if (req && req.url && req.url.match(/plots\/[0-9]+\/index.html/)) {
@@ -136,7 +149,7 @@ export class Server {
136149
res.writeHead(200);
137150
res.end(file);
138151
});
139-
} else if (req && req.url && (req.url.match(/nodeplotlib.min.js/) || req.url && req.url.match(/plotly.min.js/))) {
152+
} else if (req && req.url && (req.url.match(/nodeplotlib.min.js/) || (req.url && req.url.match(/plotly.min.js/)))) {
140153
const segments = req.url.split('/');
141154
const script = segments[segments.length - 1];
142155

@@ -166,13 +179,11 @@ export class Server {
166179
* and all plots were opened
167180
*/
168181
private close() {
169-
const pending = Object.values(this.plotsContainer)
170-
.reduce((a, b) => a || b.pending, false);
171-
const opened = Object.values(this.plotsContainer)
172-
.reduce((a, b) => a && b.opened, true);
182+
const pending = Object.values(this.plotsContainer).reduce((a, b) => a || b.pending, false);
183+
const opened = Object.values(this.plotsContainer).reduce((a, b) => a && b.opened, true);
173184

174185
if (this.instance && !pending && opened) {
175186
this.clean();
176187
}
177188
}
178-
}
189+
}

‎test/server.spec.ts

+45-28
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,15 @@ const port = Number(process.env.PORT) || 8080;
66
const validData = {
77
opened: false,
88
pending: false,
9-
plots: [{data: [{ x: [1], y: [2]}]}]
9+
plots: [{ data: [{ x: [1], y: [2] }] }],
1010
};
1111

1212
jest.mock('child_process');
13-
jest.mock('fs', () => ({readFile: (path: any, options: any, callback: (err: any, data: any) => void) => {
14-
callback('Error', null);
15-
}}));
13+
jest.mock('fs', () => ({
14+
readFile: (path: any, options: any, callback: (err: any, data: any) => void) => {
15+
callback('Error', null);
16+
},
17+
}));
1618

1719
describe('Server', () => {
1820
let server: any;
@@ -26,81 +28,96 @@ describe('Server', () => {
2628
});
2729

2830
it('should call opn once when spawning a plot', () => {
29-
server.spawn({0: {
30-
opened: false,
31-
pending: false,
32-
plots: []
33-
}});
31+
server.spawn({
32+
0: {
33+
opened: false,
34+
pending: false,
35+
plots: [],
36+
},
37+
});
3438

3539
expect(exec).toHaveBeenCalledTimes(1);
3640
});
3741

38-
it('should serve the data', (done) => {
39-
server.spawn({0: validData});
42+
it('should serve the data', done => {
43+
server.spawn({ 0: validData });
4044

4145
request(`http://localhost:${port}/data/0`, (err, response, body) => {
42-
expect(JSON.parse(body)).toEqual([{data: [{ x: [1], y: [2]}]}]);
46+
expect(JSON.parse(body)).toEqual([{ data: [{ x: [1], y: [2] }] }]);
4347
done();
4448
});
4549
});
4650

47-
it('should spawn two times but listen just once', (done) => {
48-
const data = {0: validData};
51+
it('should spawn two times but listen just once', done => {
52+
const data = { 0: validData };
4953

5054
server.spawn(data);
5155
server.spawn(data);
5256

5357
request(`http://localhost:${port}/data/0`, (err, response, body) => {
54-
expect(JSON.parse(body)).toEqual([{data: [{ x: [1], y: [2]}]}]);
58+
expect(JSON.parse(body)).toEqual([{ data: [{ x: [1], y: [2] }] }]);
5559
done();
5660
});
5761
});
5862

59-
it('should serve the website and return 404 if html file not found', (done) => {
60-
server.spawn({0: validData});
63+
it('should serve the website and return 404 if html file not found', done => {
64+
server.spawn({ 0: validData });
6165

6266
request(`http://localhost:${port}/plots/0/index.html`, (err, response, body) => {
6367
expect(response.statusCode).toBe(404);
6468
done();
6569
});
6670
});
6771

68-
it('should serve the nodeplotlib script and return 404 if file not found', (done) => {
69-
server.spawn({0: validData});
72+
it('should serve the nodeplotlib script and return 404 if file not found', done => {
73+
server.spawn({ 0: validData });
7074

7175
request(`http://localhost:${port}/plots/0/nodeplotlib.min.js`, (err, response, body) => {
7276
expect(response.statusCode).toBe(404);
7377
done();
7478
});
7579
});
7680

77-
it('should serve the plotly.min.js script and return 404 if file not found', (done) => {
78-
server.spawn({0: validData});
81+
it('should serve the plotly.min.js script and return 404 if file not found', done => {
82+
server.spawn({ 0: validData });
7983

8084
request(`http://localhost:${port}/plots/0/plotly.min.js`, (err, response, body) => {
8185
expect(response.statusCode).toBe(404);
8286
done();
8387
});
8488
});
8589

86-
it('should not close the webserver, if one plot hasn\'t got its data', (done) => {
90+
it("should not close the webserver, if one plot hasn't got its data", done => {
8791
server.spawn({
88-
0: { pending: false, opened: false, plots: [{ data: [{x: [1], y: [2]}] }]},
89-
1: { pending: false, opened: false, plots: [{ data: [{x: [1], y: [3]}] }]}
92+
0: { pending: false, opened: false, plots: [{ data: [{ x: [1], y: [2] }] }] },
93+
1: { pending: false, opened: false, plots: [{ data: [{ x: [1], y: [3] }] }] },
9094
});
9195

9296
request(`http://localhost:${port}/data/0`, (err, response, body) => {
93-
expect(JSON.parse(body)).toEqual([{data: [{ x: [1], y: [2]}]}]);
97+
expect(JSON.parse(body)).toEqual([{ data: [{ x: [1], y: [2] }] }]);
9498

9599
request(`http://localhost:${port}/data/1`, (err1, response1, body1) => {
96-
expect(JSON.parse(body1)).toEqual([{data: [{ x: [1], y: [3]}]}]);
100+
expect(JSON.parse(body1)).toEqual([{ data: [{ x: [1], y: [3] }] }]);
97101
done();
98102
});
99103
});
100104
});
101105

102-
it('should return 404 if routes not matching', (done) => {
103-
const data = {0: validData};
106+
it('should not close webserver until plot data is entirely transferred', done => {
107+
const elements = 100000;
108+
const plot = [{ data: [{ x: new Array(elements).fill(1), y: new Array(elements).fill(1) }] }];
109+
server.spawn({
110+
0: { pending: false, opened: false, plots: plot },
111+
});
112+
113+
request(`http://localhost:${port}/data/0`, (err, response, body) => {
114+
expect(JSON.parse(body)).toEqual(plot);
115+
done();
116+
});
117+
});
118+
119+
it('should return 404 if routes not matching', done => {
120+
const data = { 0: validData };
104121

105122
server.spawn(data);
106123

0 commit comments

Comments
 (0)