Skip to content

Commit 7d47ca3

Browse files
committed
Add websocket transport implementation
1 parent 1d0ae04 commit 7d47ca3

File tree

11 files changed

+301
-0
lines changed

11 files changed

+301
-0
lines changed

JavaScript/2-WS/api/move.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
'use strict';
2+
3+
const move = (point, x, y) => {
4+
point.x += x;
5+
point.y += y;
6+
};
7+
8+
module.exports = async (name, x, y) => {
9+
const shape = memory.get(name);
10+
if (!shape) return 'Shape is not found';
11+
for (const key in shape) {
12+
const point = shape[key];
13+
move(point, x, y);
14+
}
15+
return 'Shape moved';
16+
};

JavaScript/2-WS/api/read.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
'use strict';
2+
3+
module.exports = async name => {
4+
const shape = memory.get(name);
5+
if (!shape) return 'Shape is not found';
6+
return shape;
7+
};

JavaScript/2-WS/api/rect.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
'use strict';
2+
3+
class Point {
4+
constructor(x, y) {
5+
this.x = x;
6+
this.y = y;
7+
}
8+
}
9+
10+
class Rect {
11+
constructor(x1, y1, x2, y2) {
12+
this.a = new Point(x1, y1);
13+
this.b = new Point(x2, y1);
14+
this.c = new Point(x2, y2);
15+
this.d = new Point(x1, y2);
16+
}
17+
}
18+
19+
module.exports = async (name, x1, y1, x2, y2) => {
20+
const rect = new Rect(x1, y1, x2, y2);
21+
memory.set(name, rect);
22+
return 'ok';
23+
};

JavaScript/2-WS/api/render.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
'use strict';
2+
3+
module.exports = async name => {
4+
const shape = memory.get(name);
5+
if (!shape) return 'Shape is not found';
6+
const points = [];
7+
for (const key in shape) {
8+
const point = shape[key];
9+
points.push(point);
10+
}
11+
const svg = [];
12+
svg.push('<svg viewBox="-20 -20 40 40" xmlns="http://www.w3.org/2000/svg">');
13+
svg.push('<polygon points="');
14+
svg.push(points.map(({ x, y }) => `${x},${y}`).join(' '));
15+
svg.push('" /></svg>');
16+
return svg.join('');
17+
};

JavaScript/2-WS/api/resize.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
'use strict';
2+
3+
const resize = (point, k) => {
4+
let { x, y } = point;
5+
x *= k;
6+
y *= k;
7+
point.x = x;
8+
point.y = y;
9+
};
10+
11+
module.exports = async (name, k) => {
12+
const shape = memory.get(name);
13+
if (!shape) return 'Shape is not found';
14+
for (const key in shape) {
15+
const point = shape[key];
16+
resize(point, k);
17+
}
18+
return 'Shape rotated';
19+
};

JavaScript/2-WS/api/rotate.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
'use strict';
2+
3+
const rotate = (point, angle) => {
4+
const sin = Math.sin(angle);
5+
const cos = Math.cos(angle);
6+
const { x, y } = point;
7+
point.x = x * cos - y * sin;
8+
point.y = x * sin + y * cos;
9+
};
10+
11+
module.exports = async (name, angle) => {
12+
const shape = memory.get(name);
13+
if (!shape) return 'Shape is not found';
14+
for (const key in shape) {
15+
const point = shape[key];
16+
rotate(point, angle);
17+
}
18+
return 'Shape rotated';
19+
};

JavaScript/2-WS/package-lock.json

Lines changed: 55 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

JavaScript/2-WS/package.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"name": "ws-api",
3+
"version": "1.0.0",
4+
"author": "Timur Shemsedinov <timur.shemsedinov@gmail.com>",
5+
"description": "WS API Example",
6+
"license": "MIT",
7+
"dependencies": {
8+
"websocket": "^1.0.28"
9+
}
10+
}

JavaScript/2-WS/server.js

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
'use strict';
2+
3+
const http = require('http');
4+
const path = require('path');
5+
const fs = require('fs');
6+
const Websocket = require('websocket').server;
7+
8+
global.memory = new Map();
9+
const api = new Map();
10+
11+
const apiPath = './api/';
12+
13+
const cacheFile = name => {
14+
const filePath = apiPath + name;
15+
const key = path.basename(filePath, '.js');
16+
try {
17+
const libPath = require.resolve(filePath);
18+
delete require.cache[libPath];
19+
} catch (e) {
20+
return;
21+
}
22+
try {
23+
const method = require(filePath);
24+
api.set(key, method);
25+
} catch (e) {
26+
api.delete(name);
27+
}
28+
};
29+
30+
const cacheFolder = path => {
31+
fs.readdir(path, (err, files) => {
32+
if (err) return;
33+
files.forEach(cacheFile);
34+
});
35+
};
36+
37+
const watch = path => {
38+
fs.watch(path, (event, file) => {
39+
cacheFile(file);
40+
});
41+
};
42+
43+
cacheFolder(apiPath);
44+
watch(apiPath);
45+
46+
setTimeout(() => {
47+
console.dir({ api });
48+
}, 1000);
49+
50+
const server = http.createServer(async (req, res) => {
51+
const url = req.url === '/' ? '/index.html' : req.url;
52+
const [file] = url.substring(1).split('/');
53+
const path = `./static/${file}`;
54+
try {
55+
const data = await fs.promises.readFile(path);
56+
res.end(data);
57+
} catch (err) {
58+
res.statusCode = 404;
59+
res.end('"File is not found"');
60+
}
61+
}).listen(8000);
62+
63+
const ws = new Websocket({
64+
httpServer: server,
65+
autoAcceptConnections: false
66+
});
67+
68+
ws.on('request', req => {
69+
const connection = req.accept('', req.origin);
70+
console.log('Connected ' + connection.remoteAddress);
71+
connection.on('message', async message => {
72+
const dataName = message.type + 'Data';
73+
const data = message[dataName];
74+
console.log('Received: ' + data);
75+
const obj = JSON.parse(data);
76+
const { method, args } = obj;
77+
const fn = api.get(method);
78+
try {
79+
const result = await fn(...args);
80+
if (!result) {
81+
connection.send('"No result"');
82+
return;
83+
}
84+
connection.send(JSON.stringify(result));
85+
} catch (err) {
86+
console.dir({ err });
87+
connection.send('"Server error"');
88+
}
89+
});
90+
});

JavaScript/2-WS/static/client.js

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
'use strict';
2+
3+
const socket = new WebSocket('ws://127.0.0.1:8000/');
4+
5+
const buildAPI = methods => {
6+
const api = {};
7+
for (const method of methods) {
8+
api[method] = (...args) => new Promise(resolve => {
9+
socket.send(JSON.stringify({ method, args }));
10+
socket.onmessage = event => {
11+
const data = JSON.parse(event.data);
12+
resolve(data);
13+
};
14+
});
15+
}
16+
return api;
17+
};
18+
19+
const api = buildAPI(['rect', 'move', 'rotate', 'read', 'render', 'resize']);
20+
21+
const show = async () => {
22+
const svg = await api.render('Rect1');
23+
const output = document.getElementById('output');
24+
output.innerHTML = svg;
25+
};
26+
27+
const scenario = async () => {
28+
await api.rect('Rect1', -10, 10, 10, -10);
29+
await api.move('Rect1', 5, 5);
30+
await api.rotate('Rect1', 5);
31+
const data = await api.read('Rect1');
32+
console.dir({ data });
33+
await show();
34+
};
35+
36+
setTimeout(scenario, 1000);

0 commit comments

Comments
 (0)