]>
Commit | Line | Data |
---|---|---|
1 | #!/usr/bin/env node | |
2 | ||
3 | 'use strict'; | |
4 | ||
5 | /* eslint no-console: 0 */ | |
6 | ||
7 | const Net = require('net'); | |
8 | ||
9 | const kPort = 9999; | |
10 | const kEscape = new Buffer([0xFF, 0xF4, 0XFF, 0xFD, 0x06]); // IAC IP IAC DO TIMING_MARK | |
11 | const kNAWSRequest = new Buffer([0xFF, 0xFD, 0X1F]); // IAC DO NAWS | |
12 | const kNAWSResponse = new Buffer([0xFF, 0xFB, 0X1F, 0xFF, 0xFA, 0X1F]); // IAC WILL NAWS IAC SB NAWS | |
13 | const kFrequency = 333; | |
14 | const kModulationSpeed = 5; | |
15 | ||
16 | const run = function run () { | |
17 | const server = startServer(); | |
18 | bindEvents(server); | |
19 | }; | |
20 | ||
21 | const startServer = function startServer () { | |
22 | const server = Net.createServer(); | |
23 | server.listen(kPort, function () { | |
24 | const address = server.address(); | |
25 | console.log(`The server is now listening on ${address.address}:${address.port}`); | |
26 | }); | |
27 | ||
28 | return server; | |
29 | }; | |
30 | ||
31 | const bindEvents = function bindEvents (server) { | |
32 | server.on('error', function (err) { | |
33 | console.error(err.stack || err.message || err); | |
34 | process.exit(1); | |
35 | }); | |
36 | ||
37 | server.on('connection', function (socket) { | |
38 | let connectionData = { | |
39 | width: null, | |
40 | height: null, | |
41 | modulation: 0, | |
42 | screen: screens[Math.floor(Math.random() * screens.length)], | |
43 | mode: modes[Math.floor(Math.random() * modes.length)] | |
44 | }; | |
45 | let interval = null; | |
46 | ||
47 | socket.write(kNAWSRequest); | |
48 | ||
49 | // Currently this is naive, we should parse the buffer properly. | |
50 | socket.on('data', function (data) { | |
51 | ||
52 | // Only send message if NAWS is supported. | |
53 | if (data.slice(0, 6).compare(kNAWSResponse) === 0) { | |
54 | connectionData.width = parse16BitBuffer(data.slice(6, 8)); | |
55 | connectionData.height = parse16BitBuffer(data.slice(8, 10)); | |
56 | ||
57 | socket.write('\x1B[2J'); // Clear the Screen (CSI 2 J) | |
58 | interval = setInterval(writeMessage.bind(null, socket, connectionData), kFrequency); | |
59 | } | |
60 | ||
61 | if (data.compare(kEscape) === 0) { | |
62 | socket.write('\n'); | |
63 | clearInterval(interval); | |
64 | socket.end(); | |
65 | } | |
66 | }); | |
67 | }); | |
68 | }; | |
69 | ||
70 | const writeMessage = function writeMessage (socket, connectionData) { | |
71 | let message = ''; | |
72 | message += '\x1B[1;1H'; // Move cursor to top left (CSI 1;1 H) | |
73 | message += connectionData.screen(connectionData.modulation, connectionData.width, connectionData.height, getANSIColor.bind(null, connectionData.mode)); | |
74 | ||
75 | connectionData.modulation = connectionData.modulation + kModulationSpeed; | |
76 | if (connectionData.modulation === 255) { | |
77 | connectionData.modulation = 0; | |
78 | } | |
79 | ||
80 | socket.write(message); | |
81 | // return '\x1B[2J*** SUCCESSS ***'; | |
82 | }; | |
83 | ||
84 | const parse16BitBuffer = function parse16BitBuffer (buffer) { | |
85 | return buffer[0] * 256 + buffer[1]; | |
86 | }; | |
87 | ||
88 | // SCREENS | |
89 | ||
90 | const fillScreen = function fillScreen (modulation, width, height, getANSIColor) { | |
91 | let response = ''; | |
92 | ||
93 | for (let i = 0; i < height; i++) { | |
94 | for (let j = 0; j < width; j++) { | |
95 | let red = ((modulation + i) * 255 / height) % 255; | |
96 | let blue = ((modulation + j) * 255 / width) % 255; | |
97 | let green = ((modulation + i * j) * 255 / (width * height)) % 255; | |
98 | ||
99 | response = response + getANSIColor(red, blue, green); | |
100 | response = response + ' '; | |
101 | } | |
102 | ||
103 | if (i < height - 1) { | |
104 | response = response + '\n'; | |
105 | } | |
106 | } | |
107 | ||
108 | return response; | |
109 | }; | |
110 | ||
111 | const randomScreen = function randomScreen (modulation, width, height, getANSIColor) { | |
112 | let response = ''; | |
113 | ||
114 | for (let i = 0; i < height; i++) { | |
115 | for (let j = 0; j < width; j++) { | |
116 | let red = Math.floor(Math.random() * 255); | |
117 | let blue = Math.floor(Math.random() * 255); | |
118 | let green = Math.floor(Math.random() * 255); | |
119 | ||
120 | response = response + getANSIColor(red, blue, green); | |
121 | response = response + ' '; | |
122 | } | |
123 | ||
124 | if (i < height - 1) { | |
125 | response = response + '\n'; | |
126 | } | |
127 | } | |
128 | ||
129 | return response; | |
130 | }; | |
131 | ||
132 | const mirrorScreen = function mirrorScreen (modulation, width, height, getANSIColor) { | |
133 | let response = []; | |
134 | ||
135 | let scale = 2 + Math.round(Math.random() * 4); | |
136 | let scaledHeight = Math.floor(height / scale); | |
137 | let scaledWidth = Math.floor(width / scale); | |
138 | ||
139 | for (let i = 0; i < scaledHeight; i++) { | |
140 | let row = []; | |
141 | for (let j = 0; j < scaledWidth; j++) { | |
142 | let red = ((modulation + i) * 255 / height) % 255; | |
143 | let blue = ((modulation + j) * 255 / width) % 255; | |
144 | let green = ((modulation + i * j) * 255 / (width * height)) % 255; | |
145 | ||
146 | let cell = [getANSIColor(red, blue, green), ' ']; | |
147 | row.push(cell.join('')); | |
148 | } | |
149 | ||
150 | let rowText = ''; | |
151 | for (let j = 0; j < scale; j++) { | |
152 | rowText += row.reverse().join(''); | |
153 | } | |
154 | ||
155 | for (let j = 1; j < scale; j++) { | |
156 | response[j * i] = rowText; | |
157 | response[(height - 1 - (j * i))] = rowText; | |
158 | } | |
159 | } | |
160 | ||
161 | return response.join('\n'); | |
162 | }; | |
163 | ||
164 | const randomSprinkles = function mirrorRandomScreen (modulation, width, height, getANSIColor) { | |
165 | let response = ''; | |
166 | ||
167 | let maxSprinkleCount = (width * height) / 2; | |
168 | let minSprinkleCount = (width * height) / 8; | |
169 | let sprinkleCount = Math.round(Math.random() * (maxSprinkleCount - minSprinkleCount)) + minSprinkleCount; | |
170 | ||
171 | let red = Math.floor(Math.random() * 255); | |
172 | let blue = Math.floor(Math.random() * 255); | |
173 | let green = Math.floor(Math.random() * 255); | |
174 | ||
175 | for (let i = 0; i < sprinkleCount; i++) { | |
176 | let x = Math.round(Math.random() * (width - 1)) + 1; | |
177 | let y = Math.round(Math.random() * (height - 1)) + 1; | |
178 | ||
179 | let position = `\x1B[${y};${x}H`; // Move cursor to y,x (CSI y;x H) | |
180 | ||
181 | response += `${position}${getANSIColor(red, blue, green)} `; | |
182 | } | |
183 | ||
184 | return response; | |
185 | }; | |
186 | ||
187 | const circlesScreen = function circlesScreen (modulation, width, height, getANSIColor) { | |
188 | let response = []; | |
189 | ||
190 | let circles = width > height ? height : width; | |
191 | ||
192 | for (let i = 0; i < circles; i++) { | |
193 | let centerX = Math.round(width / 2) + 1; | |
194 | let centerY = Math.round(height / 2) + 1; | |
195 | ||
196 | let red = Math.floor(Math.random() * 255); | |
197 | let blue = Math.floor(Math.random() * 255); | |
198 | let green = Math.floor(Math.random() * 255); | |
199 | ||
200 | for (let j = 0; j < 180; j++) { | |
201 | let angle = 2 * j * (Math.PI / 180); | |
202 | let x = Math.round(centerX + Math.sin(angle) * i); | |
203 | let y = Math.round(centerY + Math.cos(angle) * i); | |
204 | ||
205 | if (x <= width && x > 0 && y <= height && y > 0) { | |
206 | let position = `\x1B[${y};${x}H`; // Move cursor to y,x (CSI y;x H) | |
207 | response += `${position}${getANSIColor(red, blue, green)} `; | |
208 | } | |
209 | } | |
210 | } | |
211 | ||
212 | return response; | |
213 | }; | |
214 | ||
215 | // instead of binding themode, return the one funciton... | |
216 | const getANSIColor = function getANSIColor (mode, red, blue, green) { | |
217 | let colorCode; | |
218 | ||
219 | if (mode === '256') { | |
220 | let redValue = Math.round(red * 5 / 255); | |
221 | let blueValue = Math.round(blue * 5 / 255); | |
222 | let greenValue = Math.round(green * 5 / 255); | |
223 | ||
224 | let colorNumber = 16 + 36 * redValue + 6 * greenValue + blueValue; | |
225 | ||
226 | colorCode = `\x1B[48;5;${colorNumber}m`; | |
227 | } else if (mode === 'ansi') { | |
228 | let colorOffset = Math.round((red + blue + green) * 7 / (255 * 3)); | |
229 | ||
230 | let colorNumber = 40 + colorOffset; | |
231 | ||
232 | colorCode = `\x1B[${colorNumber}m`; | |
233 | } else{ | |
234 | colorCode = `\x1B[48;2;${Math.round(red)};${Math.round(green)};${Math.round(blue)}m`; | |
235 | } | |
236 | ||
237 | return colorCode; | |
238 | }; | |
239 | ||
240 | const screens = [fillScreen, randomScreen, mirrorScreen, randomSprinkles, circlesScreen]; | |
241 | const modes = ['full', '256', 'ansi']; | |
242 | ||
243 | run(); |