Skip to content

Commit

Permalink
feat(perf): Add WebSocket to enable full-duplex communication, see #46
Browse files Browse the repository at this point in the history
  • Loading branch information
annelhote committed Dec 28, 2023
1 parent 08124ab commit f5fd8de
Show file tree
Hide file tree
Showing 8 changed files with 80 additions and 5 deletions.
3 changes: 2 additions & 1 deletion client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.11.1",
"react-tooltip": "^5.18.1"
"react-tooltip": "^5.18.1",
"react-use-websocket": "^4.5.0"
},
"devDependencies": {
"@types/react": "^18.0.28",
Expand Down
2 changes: 1 addition & 1 deletion client/src/pages/filters.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ export default function Filters({ sendQuery }) {
>
<Checkbox
label="Search for datasets only"
checked={currentSearchParams.datasets}
checked={currentSearchParams?.datasets ?? false}
onChange={(e) => setSearchParams({ ...currentSearchParams, datasets: e.target.checked })}
/>
</CheckboxGroup>
Expand Down
6 changes: 6 additions & 0 deletions client/src/pages/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
} from '@dataesr/react-dsfr';
import { useQuery } from '@tanstack/react-query';
import { useEffect, useState } from 'react';
import useWebSocket from 'react-use-websocket';

import Actions from './actions';
import AffiliationsTab from './affiliationsTab';
Expand Down Expand Up @@ -43,6 +44,11 @@ export default function Home() {
cacheTime: Infinity,
});

useWebSocket('ws://127.0.0.1:8080', {
onMessage: (message) => console.log(message.data),
share: true,
});

const sendQuery = async (_options) => {
setAllAffiliations([]);
setAllDatasets([]);
Expand Down
42 changes: 39 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"express-async-errors": "^3.1.1",
"express-openapi-validator": "^5.0.4",
"winston": "^3.8.2",
"ws": "^8.16.0",
"yamljs": "^0.3.0"
},
"devDependencies": {
Expand Down
8 changes: 8 additions & 0 deletions server/src/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,19 @@ import * as OAV from 'express-openapi-validator';

import { handleErrors } from './commons/middlewares/handle-errors';
import router from './router';
import webSocketServer from './webSocketServer';

const apiSpec = 'src/openapi/api.yml';
const apiDocument = YAML.load(apiSpec);
const app = express();

const expressServer = app.listen(process.env.WS_PORT, () => { console.log(`WebSocket server is running on port ${process.env.WS_PORT}`); });
expressServer.on('upgrade', (request, socket, head) => {
webSocketServer.handleUpgrade(request, socket, head, (websocket) => {
webSocketServer.emit('connection', websocket, request);
});
});

app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.disable('x-powered-by');
Expand Down
9 changes: 9 additions & 0 deletions server/src/routes/works.routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import express from 'express';

import { range } from '../utils/utils';
import { deduplicateWorks, getFosmWorks, getOpenAlexPublications, groupByAffiliations } from '../utils/works';
import webSocketServer from '../webSocketServer';

const router = new express.Router();

Expand All @@ -12,6 +13,7 @@ router.route('/works')
if (!options?.affiliations) {
res.status(400).json({ message: 'You must provide at least one affiliation.' });
} else {
webSocketServer.broadcast('start');
console.time(`0. Requests ${options.affiliations}`);
options.affiliations = options.affiliations.split(',');
options.datasets = options.datasets === 'true';
Expand All @@ -21,20 +23,24 @@ router.route('/works')
getOpenAlexPublications({ options }),
]);
console.timeEnd(`0. Requests ${options.affiliations}`);
webSocketServer.broadcast('step_0');
console.time(`1. Concat ${options.affiliations}`);
const works = [
...responses[0],
...responses[1],
];
console.timeEnd(`1. Concat ${options.affiliations}`);
webSocketServer.broadcast('step_1');
console.time(`2. Dedup ${options.affiliations}`);
// Deduplicate publications by ids
const deduplicatedWorks = deduplicateWorks(works);
console.timeEnd(`2. Dedup ${options.affiliations}`);
webSocketServer.broadcast('step_2');
// Compute distinct affiliations of works
console.time(`3. GroupBy ${options.affiliations}`);
const uniqueAffiliations = groupByAffiliations({ options, works: deduplicatedWorks });
console.timeEnd(`3. GroupBy ${options.affiliations}`);
webSocketServer.broadcast('step_3');
// Sort between publications and datasets
console.time(`4. Sort works ${options.affiliations}`);
const publications = [];
Expand All @@ -53,6 +59,7 @@ router.route('/works')
}
}
console.timeEnd(`4. Sort works ${options.affiliations}`);
webSocketServer.broadcast('step_4');
// Compute distinct types & years for facet
console.time(`5. Facet ${options.affiliations}`);
// TODO chek if Set is optim
Expand All @@ -65,6 +72,7 @@ router.route('/works')
const publicationsTypes = [...new Set(publications.map((publication) => publication?.type))];
const datasetsTypes = [...new Set(datasets.map((dataset) => dataset?.type))];
console.timeEnd(`5. Facet ${options.affiliations}`);
webSocketServer.broadcast('step_5');
// Build and serialize response
console.time(`6. Serialization ${options.affiliations}`);
res.status(200).json({
Expand All @@ -73,6 +81,7 @@ router.route('/works')
publications: { results: publications, types: publicationsTypes, years: publicationsYears },
});
console.timeEnd(`6. Serialization ${options.affiliations}`);
webSocketServer.broadcast('step_6');
}
} catch (err) {
console.error(err);
Expand Down
14 changes: 14 additions & 0 deletions server/src/webSocketServer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import WebSocket, { WebSocketServer } from 'ws';

const wsServer = new WebSocketServer({ noServer: true });

// eslint-disable-next-line arrow-body-style, func-names
wsServer.broadcast = function (message) {
return this.clients.forEach((client) => {
if (client.readyState === WebSocket.OPEN) {
client.send(message);
}
});
};

export default wsServer;

0 comments on commit f5fd8de

Please sign in to comment.