Repository navigation
Expand file tree
/
Copy pathserver.js
More file actions
95 lines (82 loc) · 2.8 KB
/
Copy pathserver.js
File metadata and controls
95 lines (82 loc) · 2.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
import cors from 'cors';
import express from 'express';
import { createServer } from 'node:http';
import {
existsSync,
mkdirSync,
readFileSync,
renameSync,
writeFileSync
} from 'node:fs';
import { dirname, resolve } from 'node:path';
import { fileURLToPath } from 'node:url';
import { Server } from 'socket.io';
const projectRoot = dirname(fileURLToPath(import.meta.url));
function readBoard(dataFile) {
try {
const saved = JSON.parse(readFileSync(dataFile, 'utf8'));
if (typeof saved.content === 'string' && saved.initialized === true) {
return { content: saved.content, initialized: true };
}
} catch {
// Start with an empty board if the data file does not exist or is invalid.
}
return { content: '', initialized: false };
}
export function createPlannerServer({
dataFile = resolve(projectRoot, '.data/whiteboard.json'),
staticRoot = projectRoot
} = {}) {
const app = express();
const httpServer = createServer(app);
const io = new Server(httpServer, { cors: { origin: '*' } });
let board = readBoard(dataFile);
app.use(cors());
app.use(express.json({ limit: '1mb' }));
function saveBoard(content, initializeOnly = false, sourceSocket = null) {
if (initializeOnly && board.initialized) return board;
board = { content, initialized: true };
mkdirSync(dirname(dataFile), { recursive: true });
const temporaryFile = `${dataFile}.tmp`;
writeFileSync(temporaryFile, JSON.stringify(board), 'utf8');
renameSync(temporaryFile, dataFile);
if (sourceSocket) {
sourceSocket.broadcast.emit('whiteboardUpdate', board.content);
} else {
io.emit('whiteboardUpdate', board.content);
}
return board;
}
app.get('/whiteboard', (_request, response) => {
response.json(board);
});
app.put('/whiteboard', (request, response) => {
const { content, initializeOnly = false } = request.body || {};
if (typeof content !== 'string') {
response.status(400).json({ error: 'content must be a string' });
return;
}
const current = saveBoard(content, initializeOnly === true);
response.json({ success: true, ...current });
});
io.on('connection', socket => {
socket.emit('whiteboardUpdate', board.content);
socket.on('whiteboardUpdate', content => {
if (typeof content === 'string') saveBoard(content, false, socket);
});
});
if (staticRoot && existsSync(staticRoot)) {
app.use(express.static(staticRoot));
}
return { app, httpServer, io };
}
export function startServer(port = Number(process.env.PORT) || 8080) {
const server = createPlannerServer();
server.httpServer.listen(port, () => {
console.log(`Fall Cloud is available at http://localhost:${port}`);
});
return server;
}
if (process.argv[1] && resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
startServer();
}