Skip to content

Commit 1f2c152

Browse files
Merge branch 'master' into heroku
2 parents 681eb72 + 796602d commit 1f2c152

File tree

3 files changed

+109
-62
lines changed

3 files changed

+109
-62
lines changed

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -284,4 +284,4 @@ RUN printf '#!/bin/bash\n\
284284

285285
EXPOSE 4000
286286

287-
CMD python3 -m server --host 0.0.0.0 --port $PORT
287+
ENTRYPOINT ["python3","-m","server","--host","0.0.0.0","--port","4000"]

README.md

Lines changed: 60 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ author: André Dietrich
33
44
email: LiaScript@web.de
55
6-
version: 0.0.3
6+
version: 0.0.4
77
88
language: en
99
@@ -17,6 +17,7 @@ window.CodeRunner = {
1717
error: "",
1818
url: "",
1919
firstConnection: true,
20+
pingTimer: null,
2021
2122
init(url, step = 0) {
2223
this.url = url
@@ -39,11 +40,10 @@ window.CodeRunner = {
3940
this.ws.onopen = function () {
4041
clearTimeout(connectionTimeout);
4142
self.log("connections established");
42-
4343
self.connected = true
44-
45-
setInterval(function() {
46-
self.ws.send("ping")
44+
if (self.pingTimer) clearInterval(self.pingTimer)
45+
self.pingTimer = setInterval(function() {
46+
try { self.ws.send("ping") } catch (_) {}
4747
}, 15000);
4848
}
4949
this.ws.onmessage = function (e) {
@@ -61,16 +61,17 @@ window.CodeRunner = {
6161
}
6262
this.ws.onclose = function () {
6363
clearTimeout(connectionTimeout);
64+
if (self.pingTimer) { clearInterval(self.pingTimer); self.pingTimer = null }
6465
self.connected = false
6566
self.warn("connection closed ... reconnecting")
66-
6767
setTimeout(function(){
6868
console.warn("....", step+1)
6969
self.init(url, step+1)
7070
}, 1000)
7171
}
7272
this.ws.onerror = function (e) {
7373
clearTimeout(connectionTimeout);
74+
if (self.pingTimer) { clearInterval(self.pingTimer); self.pingTimer = null }
7475
self.warn("an error has occurred")
7576
}
7677
},
@@ -2215,29 +2216,54 @@ window.CodeRunner = {
22152216
}
22162217
22172218
//window.CodeRunner.init("wss://coderunner.informatik.tu-freiberg.de/")
2218-
//window.CodeRunner.init("ws://127.0.0.1:8000/")
2219+
//window.CodeRunner.init("ws://localhost:4000/")
22192220
window.CodeRunner.init("wss://ancient-hollows-41316.herokuapp.com/")
22202221
@end
22212222
22222223
22232224
@LIA.ada: @LIA.eval(`["main.ada"]`, `gnatmake main.ada`, `./main`)
2225+
@LIA.algol: @LIA.eval(`["main.alg"]`, `none`, `a68g main.alg`)
2226+
@LIA.apl: @LIA.eval(`["main.apl"]`, `none`, `dyalog -script main.apl`)
2227+
@LIA.awk: @LIA.eval(`["main.awk"]`, `none`, `awk -f main.awk`)
2228+
@LIA.basic: @LIA.eval(`["main.bas"]`, `none`, `bwbasic main.bas`)
22242229
@LIA.c: @LIA.eval(`["main.c"]`, `gcc -Wall main.c -o a.out`, `./a.out`)
22252230
@LIA.clojure: @LIA.eval(`["main.clj"]`, `none`, `clojure -M main.clj`)
22262231
@LIA.clojure_withShell: @LIA.eval(`["main.clj"]`, `none`, `clojure -M -i main.clj -r`)
22272232
@LIA.cpp: @LIA.eval(`["main.cpp"]`, `g++ main.cpp -o a.out`, `./a.out`)
2233+
@LIA.cobol: @LIA.eval(`["main.cob"]`, `cobc -x --free main.cob`, `./main`)
2234+
@LIA.coq: @LIA.eval(`["file.v"]`, `coqc file.v`, `coqtop -lv file.v`)
2235+
@LIA.d: @LIA.eval(`["main.d"]`, `gdc main.d`, `./a.out`)
22282236
@LIA.elixir: @LIA.eval(`["main.exs"]`, `none`, `elixir main.exs`)
22292237
@LIA.elixir_withShell: @LIA.eval(`["main.exs"]`, `none`, `iex main.exs`)
2238+
@LIA.erlang: @LIA.eval(`["hello.erl"]`, `erlc hello.erl`, `erl -noshell -s hello hello -s init stop`)
2239+
@LIA.erlang_withShell: @LIA.eval(`["hello.erl"]`, `erlc hello.erl`, `erl -noshell -s hello hello`)
2240+
@LIA.forth: @LIA.eval(`["main.fs"]`, `none`, `gforth main.fs -e BYE`)
2241+
@LIA.forth_withShell: @LIA.eval(`["main.fs"]`, `none`, `gforth main.fs`)
2242+
@LIA.fortran: @LIA.eval(`["main.f90"]`, `gfortran main.f90 -o a.out`, `./a.out`)
22302243
@LIA.go: @LIA.eval(`["main.go"]`, `go build main.go`, `./main`)
2244+
@LIA.groovy: @LIA.eval(`["main.groovy"]`, `none`, `groovy main.groovy`)
22312245
@LIA.haskell: @LIA.eval(`["main.hs"]`, `ghc main.hs -o main`, `./main`)
22322246
@LIA.haskell_withShell: @LIA.eval(`["main.hs"]`, `none`, `ghci main.hs`)
2247+
@LIA.haxe: @LIA.eval(`["Main.hx"]`, `none`, `haxe -main Main --interp`)
2248+
@LIA.inform: @LIA.eval(`["main.inf"]`, `inform -o main.inf > compile.log && [ -f "main.z5" ] || { cat compile.log >&2; exit 1; }`, `/usr/games/dfrotz main.z5`)
2249+
@LIA.io: @LIA.eval(`["main.io"]`, `none`, `io main.io`)
2250+
@LIA.io_withShell: @LIA.eval(`["main.io"]`, `none`, `io -i main.io`)
22332251
@LIA.java: @LIA.eval(`["@0.java"]`, `javac @0.java`, `java @0`)
22342252
@LIA.julia: @LIA.eval(`["main.jl"]`, `none`, `julia main.jl`)
22352253
@LIA.julia_withShell: @LIA.eval(`["main.jl"]`, `none`, `julia -i main.jl`)
2254+
@LIA.kotlin: @LIA.eval(`["main.kt"]`, `kotlinc main.kt -include-runtime -d main.jar`, `java -jar main.jar`)
2255+
@LIA.lua: @LIA.eval(`["main.lua"]`, `none`, `lua main.lua`)
22362256
@LIA.mono: @LIA.eval(`["main.cs"]`, `mcs main.cs`, `mono main.exe`)
22372257
@LIA.nasm: @LIA.eval(`["main.asm"]`, `nasm -felf64 main.asm && ld main.o`, `./a.out`)
22382258
@LIA.nim: @LIA.eval(`["main.nim"]`, `nim c main.nim`, `./main`)
2259+
@LIA.nodejs: @LIA.eval(`["main.js"]`, `none`, `node main.js`)
2260+
@LIA.ocaml: @LIA.eval(`["main.ml"]`, `none`, `ocaml main.ml`)
22392261
@LIA.perl: @LIA.eval(`["main.pl"]`, `perl -c main.pl`, `perl main.pl`)
22402262
@LIA.perl_withShell: @LIA.eval(`["main.pl"]`, `perl -c main.pl`, `perl -d main.pl`)
2263+
@LIA.php: @LIA.eval(`["main.php"]`, `none`, `php main.php`)
2264+
@LIA.postscript: @LIA.eval(`["input.ps"]`, `none`, `gs -sDEVICE=png16m -r300 -o output.png input.ps`)
2265+
@LIA.prolog: @LIA.eval(`["main.pl"]`, `none`, `swipl -s main.pl -g @0 -t halt`)
2266+
@LIA.prolog_withShell: @LIA.eval(`["main.pl"]`, `none`, `swipl -s main.pl`)
22412267
@LIA.python: @LIA.python3
22422268
@LIA.python_withShell: @LIA.python3_withShell
22432269
@LIA.python2: @LIA.eval(`["main.py"]`, `python2.7 -m compileall .`, `python2.7 main.pyc`)
@@ -2246,11 +2272,19 @@ window.CodeRunner.init("wss://ancient-hollows-41316.herokuapp.com/")
22462272
@LIA.python3_withShell: @LIA.eval(`["main.py"]`, `none`, `python3 -i main.py`)
22472273
@LIA.r: @LIA.eval(`["main.R"]`, `none`, `Rscript main.R`)
22482274
@LIA.r_withShell: @LIA.eval(`["main.R"]`, `none`, `sh -c "cat main.R - | R --interactive"`)
2275+
@LIA.racket: @LIA.eval(`["main.rkt"]`, `none`, `racket main.rkt`)
22492276
@LIA.ruby: @LIA.eval(`["main.rb"]`, `none`, `ruby main.rb`)
22502277
@LIA.ruby_withShell: @LIA.eval(`["main.rb"]`, `none`, `irb --nomultiline -r ./main.rb`)
22512278
@LIA.rust: @LIA.eval(`["main.rs"]`, `rustc main.rs`, `./main`)
2279+
@LIA.scala: @LIA.eval(`["@0.scala"]`, `scalac @0.scala`, `scala @0`)
2280+
@LIA.scheme: @LIA.eval(`["main.scm"]`, `none`, `guile --no-auto-compile main.scm`)
2281+
@LIA.selectscript: @LIA.eval(`["main.s2"]`, `none`, `S2c -x main.s2`)
2282+
@LIA.smalltalk: @LIA.eval(`["main.st"]`, `none`, `gst main.st`)
2283+
@LIA.tcl: @LIA.eval(`["main.tcl"]`, `none`, `tclsh main.tcl`)
22522284
@LIA.v: @LIA.eval(`["main.v"]`, `v main.v`, `./main`)
22532285
@LIA.v_withShell: @LIA.eval(`["main.v"]`, `none`, `sh -c "cat main.v - | v repl"`)
2286+
@LIA.verilog: @LIA.eval(`["main.v"]`, `iverilog -o main.vvp main.v`, `vvp main.vvp`)
2287+
@LIA.vhdl: @LIA.eval(`["@0.vhdl"]`, `ghdl -a @0.vhdl && ghdl -e @0`, `ghdl -r @0`)
22542288
@LIA.zig: @LIA.eval(`["main.zig"]`, `zig build-exe ./main.zig -O ReleaseSmall`, `./main`)
22552289
22562290
@LIA.dotnet
@@ -2282,6 +2316,18 @@ window.CodeRunner.init("wss://ancient-hollows-41316.herokuapp.com/")
22822316
@LIA.eval(`["Program.fs", "project.fsproj"]`, `dotnet build -nologo`, `dotnet run`)
22832317
@end
22842318

2319+
@LIA.qsharp
2320+
```xml -project.csproj
2321+
<Project Sdk="Microsoft.Quantum.Sdk/0.28.302812">
2322+
<PropertyGroup>
2323+
<OutputType>Exe</OutputType>
2324+
<TargetFramework>net8.0</TargetFramework>
2325+
</PropertyGroup>
2326+
</Project>
2327+
```
2328+
@LIA.eval(`["Program.qs", "project.csproj"]`, `dotnet build -nologo`, `dotnet run`)
2329+
@end
2330+
22852331
@LIA.eval: @LIA.eval_(false,`@0`,@1,@2,@3)
22862332

22872333
@LIA.evalWithDebug: @LIA.eval_(true,`@0`,@1,@2,@3)
@@ -2393,6 +2439,13 @@ CodeRunner.handle(uid, function (msg) {
23932439
}
23942440
}
23952441

2442+
if (msg.videos) {
2443+
for(let i = 0; i < msg.videos.length; i++) {
2444+
console.html("<hr/>", msg.videos[i].file)
2445+
console.html("<video controls style='width:100%' title='" + msg.videos[i].file + "' src='" + msg.videos[i].data + "'></video>")
2446+
}
2447+
}
2448+
23962449
if (msg.files) {
23972450
let str = "<hr/>"
23982451
for(let i = 0; i < msg.files.length; i++) {

server.py

Lines changed: 48 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -20,30 +20,35 @@
2020

2121
coloredlogs.install()
2222

23-
2423
class NewWebSocketHandler (WebSocketHandler):
2524
def read_http_headers(self):
2625
headers = {}
27-
# first line should be HTTP GET
2826
http_get = self.rfile.readline().decode().strip()
29-
27+
3028
if not http_get.upper().startswith('GET'):
31-
logging.warning("Unsupported HTTP method")
32-
response = 'HTTP/1.1 400 Bad Request\r\n\r\n'
33-
with self._send_lock:
34-
self.request.sendall(response.encode())
35-
self.keep_alive = False
36-
return headers
37-
38-
39-
#assert http_get.upper().startswith('GET')
40-
# remaining should be headers
29+
logging.info("Unsupported HTTP method")
30+
response = 'HTTP/1.1 405 Method Not Allowed\r\nConnection: close\r\nContent-Length: 0\r\n\r\n'
31+
try:
32+
with self._send_lock:
33+
self.request.sendall(response.encode())
34+
except BrokenPipeError:
35+
logging.debug("Client closed before error response could be sent.")
36+
except Exception as e:
37+
logging.debug("Failed to send error response: %s", e)
38+
finally:
39+
self.keep_alive = False
40+
return headers
41+
42+
# headers lesen
4143
while True:
4244
header = self.rfile.readline().decode().strip()
4345
if not header:
4446
break
45-
head, value = header.split(':', 1)
46-
headers[head.lower().strip()] = value.strip()
47+
try:
48+
head, value = header.split(':', 1)
49+
headers[head.lower().strip()] = value.strip()
50+
except ValueError:
51+
logging.debug("Malformed header line ignored: %r", header)
4752
return headers
4853

4954
def handshake(self):
@@ -64,36 +69,51 @@ def handshake(self):
6469
return
6570

6671
response = self.make_handshake_response(key)
67-
with self._send_lock:
68-
self.handshake_done = self.request.send(response.encode())
72+
try:
73+
with self._send_lock:
74+
self.handshake_done = self.request.send(response.encode())
75+
except BrokenPipeError:
76+
logging.debug("Client closed during handshake response.")
77+
self.keep_alive = False
78+
return
6979
self.valid_client = True
7080
self.server._new_client_(self)
7181
else:
72-
# timeStr = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
73-
# print(f"请升级到ws协议{timeStr}")
74-
response = 'HTTP/1.1 400 Bad Request\r\n\r\n'
75-
76-
with self._send_lock:
77-
self.request.sendall(response.encode())
78-
self.keep_alive = False
82+
# Health-Check: freundlich 200 OK und schließen
83+
body = b"OK\n"
84+
response = (
85+
'HTTP/1.1 200 OK\r\n'
86+
'Content-Type: text/plain; charset=utf-8\r\n'
87+
f'Content-Length: {len(body)}\r\n'
88+
'Connection: close\r\n\r\n'
89+
).encode() + body
90+
try:
91+
with self._send_lock:
92+
self.request.sendall(response)
93+
except BrokenPipeError:
94+
logging.debug("Client closed before health-check response.")
95+
except Exception as e:
96+
logging.debug("Failed to send health-check response: %s", e)
97+
finally:
98+
self.keep_alive = False
99+
79100

80101
class Server (WebsocketServer):
81102
def __init__(self, host='127.0.0.1', port=0, loglevel=logging.WARNING, key=None, cert=None):
82103
#logging.setLevel(loglevel)
83104
TCPServer.__init__(self, (host, port), NewWebSocketHandler)
84105
self.host = host
85106
self.port = self.socket.getsockname()[1]
86-
87107
self.key = key
88108
self.cert = cert
89-
90109
self.clients = []
91110
self.id_counter = 0
92111
self.thread = None
93-
94112
self._deny_clients = False
95113

96-
114+
def handle_error(self, request, client_address):
115+
# Unterdrücke laute Tracebacks von erwartbaren Client-Abbrüchen
116+
logging.debug("Suppressed client error from %s", client_address)
97117

98118

99119
class Process:
@@ -511,31 +531,6 @@ def stop(error_message: str | None = None, images=[], videos=[], files=[]):
511531
server.send_message(client, json.dumps({"ok": True, "service": "stop", "uid": message["uid"]}))
512532

513533

514-
def handshake(self):
515-
headers = self.read_http_headers()
516-
if 'upgrade' in headers:
517-
518-
try:
519-
assert headers['upgrade'].lower() == 'websocket'
520-
except AssertionError:
521-
self.keep_alive = False
522-
return
523-
524-
try:
525-
key = headers['sec-websocket-key']
526-
except KeyError:
527-
logger.warning("Client tried to connect but was missing a key")
528-
self.keep_alive = False
529-
return
530-
531-
response = self.make_handshake_response(key)
532-
with self._send_lock:
533-
self.handshake_done = self.request.send(response.encode())
534-
self.valid_client = True
535-
self.server._new_client_(self)
536-
else:
537-
print("upgrade to ws")
538-
539534
if __name__ == "__main__":
540535
argv = sys.argv[1:]
541536

@@ -569,7 +564,6 @@ def handshake(self):
569564
server.set_fn_new_client(new_client)
570565
server.set_fn_client_left(client_left)
571566
server.set_fn_message_received(message_received)
572-
server.handshake = (handshake)
573567

574568
logging.basicConfig(level=logging.DEBUG)
575569

0 commit comments

Comments
 (0)