-
Notifications
You must be signed in to change notification settings - Fork 14
/
Copy pathserver.js
162 lines (132 loc) · 3.91 KB
/
server.js
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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
'use strict'
const express = require('express')
const expressStaticGzip = require('express-static-gzip')
const bodyParser = require('body-parser')
const http = require('http')
const socketIo = require('socket.io')
const Repl = require('./repl/Repl.js')
const Ansi = require('ansi-escapes')
const port = process.env.PORT || 3000
const app = express()
const server = http.Server(app)
const io = socketIo(server) // our websocket server
let histOutputs = ''
let currOutputLength = 0
let lastOutput = ''
let currentPrompt = null
let sessionURL = 'localhost:' + port
let isConfirmDelete = false
app.use(bodyParser.text())
app.use(bodyParser.json())
app.use('/', expressStaticGzip('public'))
const WELCOME_MSG = 'WELCOME TO SPACECRAFT!\n\r'
const TOO_MUCH_OUTPUT = (() => {
const text = '--------MAXIMUM OUTPUT EXCEEDED--------'
const formatted = `\u001b[31m\u001b[7m\u001b[1m${text}\u001b[0m`
return Ansi.cursorUp(1) + formatted + Ansi.cursorDown(1) + Ansi.cursorBackward(text.length)
})()
const MAX_OUTPUT_LENGTH = 10000
const MAX_HIST_LENGTH = 100000
const DEFAULT_LANG = 'ruby'
const intervalId = setInterval(() => {
io.of('/').clients((_, clients) => {
if (isConfirmDelete) {
console.log(sessionURL)
const fetch = require('node-fetch')
console.log(sessionURL)
fetch('http://' + sessionURL, { method: 'DELETE' })
clearInterval(intervalId)
}
if (clients.length === 0) isConfirmDelete = true
})
}, 10000)
app.post('/session', (req, res) => {
console.log('POST received', sessionURL)
sessionURL = req.body.sessionURL
res.send('sessionURL received')
})
io.on('connection', (socket) => {
isConfirmDelete = false
const resetOutputCache = () => {
histOutputs = ''
lastOutput = ''
currOutputLength = 0
}
const cacheOutputs = (output) => {
histOutputs += output
currOutputLength += output.length
lastOutput = output
if (histOutputs.length > MAX_HIST_LENGTH) histOutputs = histOutputs.slice(-1000)
}
const handleTooMuchOutput = () => {
currOutputLength = 0
Repl.write('\x03')
setTimeout(() => io.emit('output', { output: TOO_MUCH_OUTPUT }), 50)
}
const emitOutput = (output) => {
io.emit('output', { output })
cacheOutputs(output)
if (currOutputLength > MAX_OUTPUT_LENGTH) return handleTooMuchOutput()
}
const initRepl = (language, welcome_msg = '') => {
Repl.kill()
Repl.init(language)
resetOutputCache()
io.emit('langChange', {
language: Repl.language,
data: welcome_msg
})
Repl.process.on('data', emitOutput)
}
const getCurrentPrompt = () => {
return lastOutput.split('\n').pop()
}
// @todo: Check if this is necessary.
socket.emit('langChange', {
language: Repl.language || DEFAULT_LANG,
data: WELCOME_MSG
})
socket.emit('output', { output: histOutputs })
io.of('/').clients((_, clients) => {
if (clients.length === 1) {
initRepl(DEFAULT_LANG, WELCOME_MSG)
}
})
socket.on('registerSession', ({ url }) => {
sessionURL = url
console.log(sessionURL)
})
socket.on('initRepl', ({ language }) => {
currentPrompt = null
if (language === Repl.language) return
initRepl(language)
})
socket.on('evaluate', ({ code }) => {
currentPrompt = null
lastOutput = ''
currOutputLength = 0
Repl.write(code)
})
socket.on('lineChanged', ({ line, syncSelf }) => {
currentPrompt = currentPrompt || getCurrentPrompt()
const data = { line, prompt: currentPrompt }
if (syncSelf) return io.emit('syncLine', data)
socket.broadcast.emit('syncLine', data)
})
socket.on('clear', () => {
io.emit('clear')
histOutputs = ''
})
socket.on('disconnect', () => {
io.of('/').clients((_, clients) => {
if (clients.length === 0) {
Repl.kill()
}
})
})
// Yjs Websockets Server Events
require('./yjs-ws-server.js')(io, socket)
})
server.listen(port, () => {
console.log('Listening on 3000...')
})