Guest User

g2d per farlo funzionare (tipo pygame)

a guest
Nov 13th, 2019
88
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 33.22 KB | None | 0 0
  1.  
  2.  
  3. import os, signal, subprocess, sys, threading, time
  4. import http.server, socketserver, webbrowser
  5.  
  6. _ws, _httpd, _wv = None, None, None
  7. _usr_tick = None
  8. _mouse_pos = (0, 0)
  9. _keys, _prev_keys = set(), set()
  10. _jss, _answers, _events = [], [], []
  11. _cond = threading.Condition()
  12.  
  13. def produce_msg(msg: str, msgs: list) -> None:
  14.     with _cond:
  15.         msgs.append(msg)
  16.         _cond.notify_all()
  17.  
  18. def consume_msg(msgs: list) -> str:
  19.     with _cond:
  20.         while len(msgs) == 0:
  21.             _cond.wait()
  22.         return msgs.pop(0)
  23.  
  24. def init_canvas(size: (int, int)) -> None:
  25.     if not _ws:
  26.         threading.Thread(target=serve_files).start()
  27.         threading.Thread(target=start_websocket).start()
  28.         threading.Thread(target=start_webview, args=size).start()
  29.         consume_msg(_events)
  30.     _jss.append(f"initCanvas({size[0]}, {size[1]})")
  31.     update_canvas()
  32.  
  33. def set_color(c: (int, int, int)) -> None:
  34.     _jss.append(f"setColor({c[0]}, {c[1]}, {c[2]})")
  35.  
  36. def clear_canvas() -> None:
  37.     _jss.append(f"clearCanvas()")
  38.  
  39. def draw_line(pt1: (int, int), pt2: (int, int)) -> None:
  40.     _jss.append(f"drawLine({pt1[0]}, {pt1[1]}, {pt2[0]}, {pt2[1]})")
  41.  
  42. def fill_circle(pt: (int, int), r: int) -> None:
  43.     _jss.append(f"fillCircle({pt[0]}, {pt[1]}, {r})")
  44.  
  45. def fill_rect(r: (int, int, int, int)) -> None:
  46.     _jss.append(f"fillRect({r[0]}, {r[1]}, {r[2]}, {r[3]})")
  47.  
  48. def load_image(src: str) -> str:
  49.     key = hash(src)
  50.     _jss.append(f"loadImage('{key}', '{src}')")
  51.     return key
  52.  
  53. def draw_image(img: str, pt: (int, int)) -> None:
  54.     _jss.append(f"drawImage('{img}', {pt[0]}, {pt[1]})")
  55.  
  56. def draw_image_clip(img: str, clip: (int, int, int, int), r: (int, int, int, int)) -> None:
  57.     _jss.append(f"drawImageClip('{img}', {clip[0]}, {clip[1]}, {clip[2]}, {clip[3]}, {r[0]}, {r[1]}, {r[2]}, {r[3]})")
  58.  
  59. def draw_text(txt: str, pt: (int, int), size: int) -> None:
  60.     _jss.append(f"drawText('{txt}', {pt[0]}, {pt[1]}, {size})")
  61.  
  62. def draw_text_centered(txt: str, pt: (int, int), size: int) -> None:
  63.     _jss.append(f"drawTextCentered('{txt}', {pt[0]}, {pt[1]}, {size})")
  64.  
  65. def load_audio(src: str) -> str:
  66.     key = hash(src)
  67.     _jss.append(f"loadAudio('{key}', '{src}')")
  68.     return key
  69.  
  70. def play_audio(audio: str, loop=False) -> None:
  71.     l = str(loop).lower()
  72.     _jss.append(f"playAudio('{audio}', {l})")
  73.  
  74. def pause_audio(audio: str) -> None:
  75.     _jss.append(f"pauseAudio('{audio}')")
  76.  
  77. def _dialog(js: str) -> str:
  78.     _jss.append(js)
  79.     update_canvas()
  80.     return consume_msg(_answers)
  81.  
  82. def alert(message: str) -> None:
  83.     _dialog(f"doAlert('{message}')")
  84.  
  85. def confirm(message: str) -> bool:
  86.     return _dialog(f"doConfirm('{message}')") == "true"
  87.  
  88. def prompt(message: str) -> str:
  89.     return _dialog(f"doPrompt('{message}')")
  90.  
  91. def mouse_position() -> (int, int):
  92.     return _mouse_pos
  93.  
  94. def key_pressed(key: str) -> bool:
  95.     return key in _keys and key not in _prev_keys
  96.  
  97. def key_released(key: str) -> bool:
  98.     return key not in _keys and key in _prev_keys
  99.  
  100. def update_canvas() -> None:
  101.     if _ws:
  102.         _ws.sendMessage(";\n".join(_jss + [""]))
  103.         _jss.clear()
  104.  
  105. def main_loop(tick=None, fps=30) -> None:
  106.     global _mouse_pos, _usr_tick, _prev_keys
  107.     _usr_tick = tick
  108.     _jss.append(f"mainLoop({fps})")
  109.     update_canvas()
  110.     looping = True
  111.     while looping:
  112.         msg = consume_msg(_events)
  113.         args = msg.split(" ")
  114.         if args[0] == "mousemove":
  115.             _mouse_pos = int(args[1]), int(args[2])
  116.         elif args[0] == "keydown":
  117.             _keys.add(args[1])
  118.         elif args[0] == "keyup":
  119.             _keys.discard(args[1])
  120.         elif args[0] == "update" and _usr_tick != None:
  121.             _usr_tick()
  122.             update_canvas()
  123.             _prev_keys = _keys.copy()
  124.         elif args[0] == "disconnect":
  125.             looping = False
  126.     _httpd.shutdown()
  127.     if _wv:
  128.         _wv.terminate()
  129.  
  130. def close_canvas():
  131.     global _usr_tick
  132.     _usr_tick = None
  133.     _jss.append(f"closeCanvas()")
  134.     update_canvas()
  135.  
  136.  
  137. #### index.html
  138.  
  139. html = """<!DOCTYPE html>
  140. <html>
  141. <head>
  142. <meta charset="utf-8" />
  143.  
  144. <title>WebSocket Test</title>
  145. <style>
  146.    body { margin: 0; padding: 0; }
  147.    canvas { position: fixed; left: 50%; top: 50%; transform: translate(-50%, -50%);
  148.             margin: 0; padding: 0; border: 1px solid silver; }
  149. </style>
  150. <script language="javascript" type="text/javascript">
  151.  
  152. function doConnect() {
  153.    websocket = new WebSocket("ws://localhost:7574/");
  154.    websocket.onopen = function(evt) {
  155.        console.log("open");
  156.    };
  157.    websocket.onclose = function(evt) {
  158.        console.log("close");
  159.        closeCanvas();
  160.    };
  161.    websocket.onmessage = function(evt) {
  162.        console.log("message: " + evt.data);
  163.        eval(evt.data);
  164.    };
  165.    websocket.onerror = function(evt) {
  166.        console.log("error");
  167.        websocket.close();
  168.    };
  169. }
  170. function doSend(message) {
  171.    console.log("sending: " + message);
  172.    websocket.send(message);
  173. }
  174. function doDisconnect() {
  175.    console.log("disconnecting");
  176.    websocket.close();
  177. }
  178. window.addEventListener("load", doConnect, false);
  179.  
  180. invokeExternal = doSend
  181. loaded = {};
  182. keyPressed = {};
  183. mouseCodes = ["LeftButton", "MiddleButton", "RightButton"];
  184.  
  185. function initCanvas(w, h) {
  186.    canvas = document.getElementById("g2d-canvas");
  187.    if (canvas == null) {
  188.        canvas = document.createElement("CANVAS");
  189.        canvas.id = "g2d-canvas";
  190.        document.getElementsByTagName("body")[0].appendChild(canvas);
  191.    }
  192.    canvas.width = w;
  193.    canvas.height = h;
  194.    ctx = canvas.getContext("2d");
  195.    setColor(127, 127, 127);
  196.    clearCanvas();
  197. }
  198. function clearCanvas() {
  199.    ctx.clearRect(0, 0, canvas.width, canvas.height);
  200. }
  201. function setColor(r, g, b) {
  202.    ctx.strokeStyle = "rgb("+r+", "+g+", "+b+")";
  203.    ctx.fillStyle = "rgb("+r+", "+g+", "+b+")";
  204. }
  205. function drawLine(x1, y1, x2, y2) {
  206.    ctx.beginPath();
  207.    ctx.moveTo(x1, y1);
  208.    ctx.lineTo(x2, y2);
  209.    ctx.stroke();
  210. }
  211. function fillCircle(x, y, r) {
  212.    ctx.beginPath();
  213.    ctx.arc(x, y, r, 0, 2*Math.PI);
  214.    ctx.closePath();
  215.    ctx.fill();
  216. }
  217. function fillRect(x, y, w, h) {
  218.    ctx.fillRect(x, y, w, h);
  219. }
  220. function loadImage(key, src) {
  221.    img = document.createElement("IMG");
  222.    img.src = src;
  223.    img.onerror = function() {
  224.        if (img.src.indexOf("githubusercontent") == -1) {
  225.            img.src = "https://raw.githubusercontent.com/tomamic/fondinfo/master/examples/" + src;
  226.        }
  227.    }
  228.    loaded[key] = img;
  229. }
  230. function drawImage(key, x, y) {
  231.    img = loaded[key];
  232.    ctx.drawImage(img, x, y);
  233. }
  234. function drawImageClip(key, x0, y0, w0, h0, x1, y1, w1, h1) {
  235.    img = loaded[key];
  236.    ctx.drawImage(img, x0, y0, w0, h0, x1, y1, w1, h1);
  237. }
  238. function drawText(txt, x, y, size) {
  239.    ctx.font = "" + size + "px sans-serif";
  240.    ctx.textBaseline = "top";
  241.    ctx.textAlign = "left";
  242.    ctx.fillText(txt, x, y);
  243. }
  244. function drawTextCentered(txt, x, y, size) {
  245.    ctx.font = "" + size + "px sans-serif";
  246.    ctx.textBaseline = "middle";
  247.    ctx.textAlign = "center";
  248.    ctx.fillText(txt, x, y);
  249. }
  250. function loadAudio(key, src) {
  251.    audio = document.createElement("AUDIO");
  252.    audio.src = src;
  253.    audio.onerror = function() {
  254.        if (audio.src.indexOf("githubusercontent") == -1) {
  255.            audio.src = "https://raw.githubusercontent.com/tomamic/fondinfo/master/examples/" + src;
  256.        }
  257.    }
  258.    loaded[key] = audio;
  259. }
  260. function playAudio(key, loop) {
  261.    audio = loaded[key];
  262.    audio.loop = loop;
  263.    audio.play();
  264. }
  265. function pauseAudio(key) {
  266.    audio = loaded[key];
  267.    audio.pause();
  268. }
  269. function doAlert(message) {
  270.    alert(message);
  271.    invokeExternal("answer true");
  272. }
  273. function doConfirm(message) {
  274.    ans = confirm(message);
  275.    invokeExternal("answer " + ans);
  276. }
  277. function doPrompt(message) {
  278.    ans = prompt(message);
  279.    invokeExternal("answer " + ans);
  280. }
  281. function fixKey(k) {
  282.    if (k=="Left" || k=="Up" || k=="Right" || k=="Down") k = "Arrow"+k;
  283.    else if (k==" " || k=="Space") k = "Spacebar";
  284.    else if (k=="Esc") k = "Escape";
  285.    else if (k=="Del") k = "Delete";
  286.    return k;
  287. }
  288. function mainLoop(fps) {
  289.    document.onkeydown = function(e) {
  290.        var k = fixKey(e.key);
  291.        if (keyPressed[k]) return;
  292.        keyPressed[k] = true;
  293.        invokeExternal("keydown " + k);
  294.    };
  295.    document.onkeyup = function(e) {
  296.        var k = fixKey(e.key);
  297.        if (keyPressed[k]) keyPressed[k] = false;
  298.        invokeExternal("keyup " + k);
  299.    };
  300.    document.onmousedown = function(e) {
  301.        if (0 <= e.button && e.button < 3) {
  302.            invokeExternal("keydown " + mouseCodes[e.button]);
  303.        }
  304.    };
  305.    document.onmouseup = function(e) {
  306.        if (0 <= e.button && e.button < 3) {
  307.            invokeExternal("keyup " + mouseCodes[e.button]);
  308.        }
  309.    };
  310.    document.onmousemove = function(e) {
  311.        var rect = canvas.getBoundingClientRect()
  312.        var x = Math.round(e.clientX - rect.left)
  313.        var y = Math.round(e.clientY - rect.top)
  314.        invokeExternal("mousemove " + x + " " + y);
  315.    };
  316.    document.onfocus = function(e) {
  317.        keyPressed = {};
  318.    };
  319.  
  320.    if (typeof timerId !== "undefined") {
  321.        clearInterval(timerId);
  322.        delete timerId;
  323.    }
  324.    if (fps >= 0) {
  325.        timerId = setInterval(function(e) {
  326.            invokeExternal("update");
  327.        }, 1000/fps);
  328.    }
  329. }
  330. function closeCanvas() {
  331.    if (typeof timerId !== "undefined") {
  332.        clearInterval(timerId);
  333.        delete timerId;
  334.    }
  335.    if (typeof canvas !== "undefined") {
  336.        canvas.parentNode.removeChild(canvas);
  337.        delete canvas;
  338.    }
  339.    doDisconnect();
  340.    /*alert("You can close this window, now.");*/
  341.    open("about:blank", "_self").close();
  342. }
  343. </script>
  344. </head>
  345. <body>
  346. </body>
  347. </html>"""
  348.  
  349. class FileHandler(http.server.SimpleHTTPRequestHandler):
  350.     def do_GET(self):
  351.         if self.path == "/":
  352.             self.send_response(200)
  353.             self.send_header("Content-type", "text/html")
  354.             self.end_headers()
  355.             self.wfile.write(html.encode("utf-8"))
  356.         else:
  357.             super().do_GET()
  358.  
  359. def serve_files() -> None:
  360.     global _httpd
  361.     # minimal web server, for files in current dir
  362.     socketserver.TCPServer.allow_reuse_address = True
  363.     _httpd = socketserver.TCPServer(("", 8008), FileHandler)
  364.     _httpd.serve_forever()
  365.  
  366.  
  367. #### webview
  368.  
  369. if __name__ == "__main__":
  370.     import sys, webview
  371.     webview.create_window(url="http://localhost:8008/",
  372.         width=max(480, int(sys.argv[1])), height=max(360, int(sys.argv[2])),
  373.         title="G2D Canvas", resizable=False, debug=False)
  374.     sys.exit()
  375.  
  376.  
  377. def start_webview(w, h):
  378.     global _wv
  379.     try:
  380.         import webview
  381.         _wv = subprocess.Popen([sys.executable, __file__, str(w), str(h)])
  382.     except:
  383.         webbrowser.open("http://localhost:8008/", new=0)
  384.  
  385.  
  386. #### websockets
  387.  
  388. '''
  389. The MIT License (MIT)
  390. Copyright (c) 2013 Dave P.
  391. '''
  392. import sys
  393. VER = sys.version_info[0]
  394. if VER >= 3:
  395.     import socketserver
  396.     from http.server import BaseHTTPRequestHandler
  397.     from io import StringIO, BytesIO
  398. else:
  399.     import SocketServer
  400.     from BaseHTTPServer import BaseHTTPRequestHandler
  401.     from StringIO import StringIO
  402.  
  403. import hashlib
  404. import base64
  405. import socket
  406. import struct
  407. import ssl
  408. import errno
  409. import codecs
  410. from collections import deque
  411. from select import select
  412.  
  413. def _check_unicode(val):
  414.     if VER >= 3:
  415.         return isinstance(val, str)
  416.     else:
  417.         return isinstance(val, basestring)
  418.  
  419. class HTTPRequest(BaseHTTPRequestHandler):
  420.    def __init__(self, request_text):
  421.       if VER >= 3:
  422.           self.rfile = BytesIO(request_text)
  423.       else:
  424.           self.rfile = StringIO(request_text)
  425.       self.raw_requestline = self.rfile.readline()
  426.       self.error_code = self.error_message = None
  427.       self.parse_request()
  428.  
  429. _VALID_STATUS_CODES = [1000, 1001, 1002, 1003, 1007, 1008,
  430.                         1009, 1010, 1011, 3000, 3999, 4000, 4999]
  431.  
  432. HANDSHAKE_STR = (
  433.    "HTTP/1.1 101 Switching Protocols\r\n"
  434.    "Upgrade: WebSocket\r\n"
  435.    "Connection: Upgrade\r\n"
  436.    "Sec-WebSocket-Accept: %(acceptstr)s\r\n\r\n"
  437. )
  438.  
  439. FAILED_HANDSHAKE_STR = (
  440.    "HTTP/1.1 426 Upgrade Required\r\n"
  441.    "Upgrade: WebSocket\r\n"
  442.    "Connection: Upgrade\r\n"
  443.    "Sec-WebSocket-Version: 13\r\n"
  444.    "Content-Type: text/plain\r\n\r\n"
  445.    "This service requires use of the WebSocket protocol\r\n"
  446. )
  447.  
  448. GUID_STR = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'
  449.  
  450. STREAM = 0x0
  451. TEXT = 0x1
  452. BINARY = 0x2
  453. CLOSE = 0x8
  454. PING = 0x9
  455. PONG = 0xA
  456.  
  457. HEADERB1 = 1
  458. HEADERB2 = 3
  459. LENGTHSHORT = 4
  460. LENGTHLONG = 5
  461. MASK = 6
  462. PAYLOAD = 7
  463.  
  464. MAXHEADER = 65536
  465. MAXPAYLOAD = 33554432
  466.  
  467. class WebSocket(object):
  468.  
  469.    def __init__(self, server, sock, address):
  470.       self.server = server
  471.       self.client = sock
  472.       self.address = address
  473.  
  474.       self.handshaked = False
  475.       self.headerbuffer = bytearray()
  476.       self.headertoread = 2048
  477.  
  478.       self.fin = 0
  479.       self.data = bytearray()
  480.       self.opcode = 0
  481.       self.hasmask = 0
  482.       self.maskarray = None
  483.       self.length = 0
  484.       self.lengtharray = None
  485.       self.index = 0
  486.       self.request = None
  487.       self.usingssl = False
  488.  
  489.       self.frag_start = False
  490.       self.frag_type = BINARY
  491.       self.frag_buffer = None
  492.       self.frag_decoder = codecs.getincrementaldecoder('utf-8')(errors='strict')
  493.       self.closed = False
  494.       self.sendq = deque()
  495.  
  496.       self.state = HEADERB1
  497.  
  498.       # restrict the size of header and payload for security reasons
  499.       self.maxheader = MAXHEADER
  500.       self.maxpayload = MAXPAYLOAD
  501.  
  502.    def handleMessage(self):
  503.       """
  504.          Called when websocket frame is received.
  505.          To access the frame data call self.data.
  506.  
  507.          If the frame is Text then self.data is a unicode object.
  508.          If the frame is Binary then self.data is a bytearray object.
  509.      """
  510.       pass
  511.  
  512.    def handleConnected(self):
  513.       """
  514.          Called when a websocket client connects to the server.
  515.      """
  516.       pass
  517.  
  518.    def handleClose(self):
  519.       """
  520.          Called when a websocket server gets a Close frame from a client.
  521.      """
  522.       pass
  523.  
  524.    def _handlePacket(self):
  525.       if self.opcode == CLOSE:
  526.          pass
  527.       elif self.opcode == STREAM:
  528.          pass
  529.       elif self.opcode == TEXT:
  530.          pass
  531.       elif self.opcode == BINARY:
  532.          pass
  533.       elif self.opcode == PONG or self.opcode == PING:
  534.          if len(self.data) > 125:
  535.             raise Exception('control frame length can not be > 125')
  536.       else:
  537.           # unknown or reserved opcode so just close
  538.          raise Exception('unknown opcode')
  539.  
  540.       if self.opcode == CLOSE:
  541.          status = 1000
  542.          reason = u''
  543.          length = len(self.data)
  544.  
  545.          if length == 0:
  546.             pass
  547.          elif length >= 2:
  548.             status = struct.unpack_from('!H', self.data[:2])[0]
  549.             reason = self.data[2:]
  550.  
  551.             if status not in _VALID_STATUS_CODES:
  552.                 status = 1002
  553.  
  554.             if len(reason) > 0:
  555.                 try:
  556.                     reason = reason.decode('utf8', errors='strict')
  557.                 except:
  558.                     status = 1002
  559.          else:
  560.             status = 1002
  561.  
  562.          self.close(status, reason)
  563.          return
  564.  
  565.       elif self.fin == 0:
  566.           if self.opcode != STREAM:
  567.               if self.opcode == PING or self.opcode == PONG:
  568.                   raise Exception('control messages can not be fragmented')
  569.  
  570.               self.frag_type = self.opcode
  571.               self.frag_start = True
  572.               self.frag_decoder.reset()
  573.  
  574.               if self.frag_type == TEXT:
  575.                   self.frag_buffer = []
  576.                   utf_str = self.frag_decoder.decode(self.data, final = False)
  577.                   if utf_str:
  578.                       self.frag_buffer.append(utf_str)
  579.               else:
  580.                   self.frag_buffer = bytearray()
  581.                   self.frag_buffer.extend(self.data)
  582.  
  583.           else:
  584.               if self.frag_start is False:
  585.                   raise Exception('fragmentation protocol error')
  586.  
  587.               if self.frag_type == TEXT:
  588.                   utf_str = self.frag_decoder.decode(self.data, final = False)
  589.                   if utf_str:
  590.                       self.frag_buffer.append(utf_str)
  591.               else:
  592.                   self.frag_buffer.extend(self.data)
  593.  
  594.       else:
  595.           if self.opcode == STREAM:
  596.               if self.frag_start is False:
  597.                   raise Exception('fragmentation protocol error')
  598.  
  599.               if self.frag_type == TEXT:
  600.                   utf_str = self.frag_decoder.decode(self.data, final = True)
  601.                   self.frag_buffer.append(utf_str)
  602.                   self.data = u''.join(self.frag_buffer)
  603.               else:
  604.                   self.frag_buffer.extend(self.data)
  605.                   self.data = self.frag_buffer
  606.  
  607.               self.handleMessage()
  608.  
  609.               self.frag_decoder.reset()
  610.               self.frag_type = BINARY
  611.               self.frag_start = False
  612.               self.frag_buffer = None
  613.  
  614.           elif self.opcode == PING:
  615.               self._sendMessage(False, PONG, self.data)
  616.  
  617.           elif self.opcode == PONG:
  618.               pass
  619.  
  620.           else:
  621.               if self.frag_start is True:
  622.                   raise Exception('fragmentation protocol error')
  623.  
  624.               if self.opcode == TEXT:
  625.                   try:
  626.                       self.data = self.data.decode('utf8', errors='strict')
  627.                   except Exception as exp:
  628.                       raise Exception('invalid utf-8 payload')
  629.  
  630.               self.handleMessage()
  631.  
  632.  
  633.    def _handleData(self):
  634.       # do the HTTP header and handshake
  635.       if self.handshaked is False:
  636.  
  637.          data = self.client.recv(self.headertoread)
  638.          if not data:
  639.             raise Exception('remote socket closed')
  640.  
  641.          else:
  642.             # accumulate
  643.             self.headerbuffer.extend(data)
  644.  
  645.             if len(self.headerbuffer) >= self.maxheader:
  646.                raise Exception('header exceeded allowable size')
  647.  
  648.             # indicates end of HTTP header
  649.             if b'\r\n\r\n' in self.headerbuffer:
  650.                self.request = HTTPRequest(self.headerbuffer)
  651.  
  652.                # handshake rfc 6455
  653.                try:
  654.                   key = self.request.headers['Sec-WebSocket-Key']
  655.                   k = key.encode('ascii') + GUID_STR.encode('ascii')
  656.                   k_s = base64.b64encode(hashlib.sha1(k).digest()).decode('ascii')
  657.                   hStr = HANDSHAKE_STR % {'acceptstr': k_s}
  658.                   self.sendq.append((BINARY, hStr.encode('ascii')))
  659.                   self.handshaked = True
  660.                   self.handleConnected()
  661.                except Exception as e:
  662.                   hStr = FAILED_HANDSHAKE_STR
  663.                   self._sendBuffer(hStr.encode('ascii'), True)
  664.                   self.client.close()
  665.                   raise Exception('handshake failed: %s', str(e))
  666.  
  667.       # else do normal data
  668.       else:
  669.          data = self.client.recv(16384)
  670.          if not data:
  671.             raise Exception("remote socket closed")
  672.  
  673.          if VER >= 3:
  674.              for d in data:
  675.                  self._parseMessage(d)
  676.          else:
  677.              for d in data:
  678.                  self._parseMessage(ord(d))
  679.  
  680.    def close(self, status = 1000, reason = u''):
  681.        """
  682.          Send Close frame to the client. The underlying socket is only closed
  683.          when the client acknowledges the Close frame.
  684.  
  685.          status is the closing identifier.
  686.          reason is the reason for the close.
  687.        """
  688.        try:
  689.           if self.closed is False:
  690.             close_msg = bytearray()
  691.             close_msg.extend(struct.pack("!H", status))
  692.             if _check_unicode(reason):
  693.                 close_msg.extend(reason.encode('utf-8'))
  694.             else:
  695.                 close_msg.extend(reason)
  696.  
  697.             self._sendMessage(False, CLOSE, close_msg)
  698.  
  699.        finally:
  700.             self.closed = True
  701.  
  702.  
  703.    def _sendBuffer(self, buff, send_all = False):
  704.       size = len(buff)
  705.       tosend = size
  706.       already_sent = 0
  707.  
  708.       while tosend > 0:
  709.          try:
  710.             # i should be able to send a bytearray
  711.             sent = self.client.send(buff[already_sent:])
  712.             if sent == 0:
  713.                raise RuntimeError('socket connection broken')
  714.  
  715.             already_sent += sent
  716.             tosend -= sent
  717.  
  718.          except socket.error as e:
  719.             # if we have full buffers then wait for them to drain and try again
  720.             if e.errno in [errno.EAGAIN, errno.EWOULDBLOCK]:
  721.                if send_all:
  722.                    continue
  723.                return buff[already_sent:]
  724.             else:
  725.                raise e
  726.  
  727.       return None
  728.  
  729.    def sendFragmentStart(self, data):
  730.       """
  731.          Send the start of a data fragment stream to a websocket client.
  732.          Subsequent data should be sent using sendFragment().
  733.          A fragment stream is completed when sendFragmentEnd() is called.
  734.  
  735.          If data is a unicode object then the frame is sent as Text.
  736.          If the data is a bytearray object then the frame is sent as Binary.
  737.      """
  738.       opcode = BINARY
  739.       if _check_unicode(data):
  740.          opcode = TEXT
  741.       self._sendMessage(True, opcode, data)
  742.  
  743.    def sendFragment(self, data):
  744.       """
  745.          see sendFragmentStart()
  746.  
  747.          If data is a unicode object then the frame is sent as Text.
  748.          If the data is a bytearray object then the frame is sent as Binary.
  749.      """
  750.       self._sendMessage(True, STREAM, data)
  751.  
  752.    def sendFragmentEnd(self, data):
  753.       """
  754.          see sendFragmentEnd()
  755.  
  756.          If data is a unicode object then the frame is sent as Text.
  757.          If the data is a bytearray object then the frame is sent as Binary.
  758.      """
  759.       self._sendMessage(False, STREAM, data)
  760.  
  761.    def sendMessage(self, data):
  762.       """
  763.          Send websocket data frame to the client.
  764.  
  765.          If data is a unicode object then the frame is sent as Text.
  766.          If the data is a bytearray object then the frame is sent as Binary.
  767.      """
  768.       opcode = BINARY
  769.       if _check_unicode(data):
  770.          opcode = TEXT
  771.       self._sendMessage(False, opcode, data)
  772.  
  773.  
  774.    def _sendMessage(self, fin, opcode, data):
  775.  
  776.         payload = bytearray()
  777.  
  778.         b1 = 0
  779.         b2 = 0
  780.         if fin is False:
  781.            b1 |= 0x80
  782.         b1 |= opcode
  783.  
  784.         if _check_unicode(data):
  785.            data = data.encode('utf-8')
  786.  
  787.         length = len(data)
  788.         payload.append(b1)
  789.  
  790.         if length <= 125:
  791.            b2 |= length
  792.            payload.append(b2)
  793.  
  794.         elif length >= 126 and length <= 65535:
  795.            b2 |= 126
  796.            payload.append(b2)
  797.            payload.extend(struct.pack("!H", length))
  798.  
  799.         else:
  800.            b2 |= 127
  801.            payload.append(b2)
  802.            payload.extend(struct.pack("!Q", length))
  803.  
  804.         if length > 0:
  805.            payload.extend(data)
  806.  
  807.         self.sendq.append((opcode, payload))
  808.  
  809.  
  810.    def _parseMessage(self, byte):
  811.       # read in the header
  812.       if self.state == HEADERB1:
  813.  
  814.          self.fin = byte & 0x80
  815.          self.opcode = byte & 0x0F
  816.          self.state = HEADERB2
  817.  
  818.          self.index = 0
  819.          self.length = 0
  820.          self.lengtharray = bytearray()
  821.          self.data = bytearray()
  822.  
  823.          rsv = byte & 0x70
  824.          if rsv != 0:
  825.             raise Exception('RSV bit must be 0')
  826.  
  827.       elif self.state == HEADERB2:
  828.          mask = byte & 0x80
  829.          length = byte & 0x7F
  830.  
  831.          if self.opcode == PING and length > 125:
  832.              raise Exception('ping packet is too large')
  833.  
  834.          if mask == 128:
  835.             self.hasmask = True
  836.          else:
  837.             self.hasmask = False
  838.  
  839.          if length <= 125:
  840.             self.length = length
  841.  
  842.             # if we have a mask we must read it
  843.             if self.hasmask is True:
  844.                self.maskarray = bytearray()
  845.                self.state = MASK
  846.             else:
  847.                # if there is no mask and no payload we are done
  848.                if self.length <= 0:
  849.                   try:
  850.                      self._handlePacket()
  851.                   finally:
  852.                      self.state = HEADERB1
  853.                      self.data = bytearray()
  854.  
  855.                # we have no mask and some payload
  856.                else:
  857.                   #self.index = 0
  858.                   self.data = bytearray()
  859.                   self.state = PAYLOAD
  860.  
  861.          elif length == 126:
  862.             self.lengtharray = bytearray()
  863.             self.state = LENGTHSHORT
  864.  
  865.          elif length == 127:
  866.             self.lengtharray = bytearray()
  867.             self.state = LENGTHLONG
  868.  
  869.  
  870.       elif self.state == LENGTHSHORT:
  871.          self.lengtharray.append(byte)
  872.  
  873.          if len(self.lengtharray) > 2:
  874.             raise Exception('short length exceeded allowable size')
  875.  
  876.          if len(self.lengtharray) == 2:
  877.             self.length = struct.unpack_from('!H', self.lengtharray)[0]
  878.  
  879.             if self.hasmask is True:
  880.                self.maskarray = bytearray()
  881.                self.state = MASK
  882.             else:
  883.                # if there is no mask and no payload we are done
  884.                if self.length <= 0:
  885.                   try:
  886.                      self._handlePacket()
  887.                   finally:
  888.                      self.state = HEADERB1
  889.                      self.data = bytearray()
  890.  
  891.                # we have no mask and some payload
  892.                else:
  893.                   #self.index = 0
  894.                   self.data = bytearray()
  895.                   self.state = PAYLOAD
  896.  
  897.       elif self.state == LENGTHLONG:
  898.  
  899.          self.lengtharray.append(byte)
  900.  
  901.          if len(self.lengtharray) > 8:
  902.             raise Exception('long length exceeded allowable size')
  903.  
  904.          if len(self.lengtharray) == 8:
  905.             self.length = struct.unpack_from('!Q', self.lengtharray)[0]
  906.  
  907.             if self.hasmask is True:
  908.                self.maskarray = bytearray()
  909.                self.state = MASK
  910.             else:
  911.                # if there is no mask and no payload we are done
  912.                if self.length <= 0:
  913.                   try:
  914.                      self._handlePacket()
  915.                   finally:
  916.                      self.state = HEADERB1
  917.                      self.data = bytearray()
  918.  
  919.                # we have no mask and some payload
  920.                else:
  921.                   #self.index = 0
  922.                   self.data = bytearray()
  923.                   self.state = PAYLOAD
  924.  
  925.       # MASK STATE
  926.       elif self.state == MASK:
  927.          self.maskarray.append(byte)
  928.  
  929.          if len(self.maskarray) > 4:
  930.             raise Exception('mask exceeded allowable size')
  931.  
  932.          if len(self.maskarray) == 4:
  933.             # if there is no mask and no payload we are done
  934.             if self.length <= 0:
  935.                try:
  936.                   self._handlePacket()
  937.                finally:
  938.                   self.state = HEADERB1
  939.                   self.data = bytearray()
  940.  
  941.             # we have no mask and some payload
  942.             else:
  943.                #self.index = 0
  944.                self.data = bytearray()
  945.                self.state = PAYLOAD
  946.  
  947.       # PAYLOAD STATE
  948.       elif self.state == PAYLOAD:
  949.          if self.hasmask is True:
  950.             self.data.append( byte ^ self.maskarray[self.index % 4] )
  951.          else:
  952.             self.data.append( byte )
  953.  
  954.          # if length exceeds allowable size then we except and remove the connection
  955.          if len(self.data) >= self.maxpayload:
  956.             raise Exception('payload exceeded allowable size')
  957.  
  958.          # check if we have processed length bytes; if so we are done
  959.          if (self.index+1) == self.length:
  960.             try:
  961.                self._handlePacket()
  962.             finally:
  963.                #self.index = 0
  964.                self.state = HEADERB1
  965.                self.data = bytearray()
  966.          else:
  967.             self.index += 1
  968.  
  969.  
  970. class SimpleWebSocketServer(object):
  971.    def __init__(self, host, port, websocketclass, selectInterval = 0.1):
  972.       self.websocketclass = websocketclass
  973.  
  974.       if (host == ''):
  975.          host = None
  976.  
  977.       if host is None:
  978.          fam = socket.AF_INET6
  979.       else:
  980.          fam = 0
  981.  
  982.       hostInfo = socket.getaddrinfo(host, port, fam, socket.SOCK_STREAM, socket.IPPROTO_TCP, socket.AI_PASSIVE)
  983.       self.serversocket = socket.socket(hostInfo[0][0], hostInfo[0][1], hostInfo[0][2])
  984.       self.serversocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
  985.       self.serversocket.bind(hostInfo[0][4])
  986.       self.serversocket.listen(5)
  987.       self.selectInterval = selectInterval
  988.       self.connections = {}
  989.       self.listeners = [self.serversocket]
  990.  
  991.    def _decorateSocket(self, sock):
  992.       return sock
  993.  
  994.    def _constructWebSocket(self, sock, address):
  995.       return self.websocketclass(self, sock, address)
  996.  
  997.    def close(self):
  998.       self.serversocket.close()
  999.  
  1000.       for desc, conn in self.connections.items():
  1001.          conn.close()
  1002.          self._handleClose(conn)
  1003.  
  1004.    def _handleClose(self, client):
  1005.       client.client.close()
  1006.       # only call handleClose when we have a successful websocket connection
  1007.       if client.handshaked:
  1008.          try:
  1009.             client.handleClose()
  1010.          except:
  1011.             pass
  1012.  
  1013.    def serveonce(self):
  1014.       writers = []
  1015.       for fileno in self.listeners:
  1016.          if fileno == self.serversocket:
  1017.             continue
  1018.          client = self.connections[fileno]
  1019.          if client.sendq:
  1020.             writers.append(fileno)
  1021.  
  1022.       rList, wList, xList = select(self.listeners, writers, self.listeners, self.selectInterval)
  1023.  
  1024.       for ready in wList:
  1025.          client = self.connections[ready]
  1026.          try:
  1027.             while client.sendq:
  1028.                opcode, payload = client.sendq.popleft()
  1029.                remaining = client._sendBuffer(payload)
  1030.                if remaining is not None:
  1031.                    client.sendq.appendleft((opcode, remaining))
  1032.                    break
  1033.                else:
  1034.                    if opcode == CLOSE:
  1035.                       raise Exception('received client close')
  1036.  
  1037.          except Exception as n:
  1038.             self._handleClose(client)
  1039.             del self.connections[ready]
  1040.             self.listeners.remove(ready)
  1041.  
  1042.       for ready in rList:
  1043.          if ready == self.serversocket:
  1044.             sock = None
  1045.             try:
  1046.                sock, address = self.serversocket.accept()
  1047.                newsock = self._decorateSocket(sock)
  1048.                newsock.setblocking(0)
  1049.                fileno = newsock.fileno()
  1050.                self.connections[fileno] = self._constructWebSocket(newsock, address)
  1051.                self.listeners.append(fileno)
  1052.             except Exception as n:
  1053.                if sock is not None:
  1054.                   sock.close()
  1055.          else:
  1056.             if ready not in self.connections:
  1057.                 continue
  1058.             client = self.connections[ready]
  1059.             try:
  1060.                client._handleData()
  1061.             except Exception as n:
  1062.                self._handleClose(client)
  1063.                del self.connections[ready]
  1064.                self.listeners.remove(ready)
  1065.  
  1066.       for failed in xList:
  1067.          if failed == self.serversocket:
  1068.             self.close()
  1069.             raise Exception('server socket failed')
  1070.          else:
  1071.             if failed not in self.connections:
  1072.                continue
  1073.             client = self.connections[failed]
  1074.             self._handleClose(client)
  1075.             del self.connections[failed]
  1076.             self.listeners.remove(failed)
  1077.  
  1078.    def serveforever(self):
  1079.       while True:
  1080.          self.serveonce()
  1081.  
  1082. class SimpleSSLWebSocketServer(SimpleWebSocketServer):
  1083.  
  1084.    def __init__(self, host, port, websocketclass, certfile = None,
  1085.                 keyfile = None, version = ssl.PROTOCOL_TLSv1, selectInterval = 0.1, ssl_context = None):
  1086.  
  1087.       SimpleWebSocketServer.__init__(self, host, port,
  1088.                                         websocketclass, selectInterval)
  1089.  
  1090.       if ssl_context is None:
  1091.          self.context = ssl.SSLContext(version)
  1092.          self.context.load_cert_chain(certfile, keyfile)
  1093.       else:
  1094.          self.context = ssl_context
  1095.  
  1096.    def close(self):
  1097.       super(SimpleSSLWebSocketServer, self).close()
  1098.  
  1099.    def _decorateSocket(self, sock):
  1100.       sslsock = self.context.wrap_socket(sock, server_side=True)
  1101.       return sslsock
  1102.  
  1103.    def _constructWebSocket(self, sock, address):
  1104.       ws = self.websocketclass(self, sock, address)
  1105.       ws.usingssl = True
  1106.       return ws
  1107.  
  1108.    def serveforever(self):
  1109.       super(SimpleSSLWebSocketServer, self).serveforever()
  1110.  
  1111.  
  1112. #### g2d-ws
  1113.  
  1114. class SocketHandler(WebSocket):
  1115.     def handleMessage(self):
  1116.         #print(self.data)
  1117.         args = self.data.split(" ", 1)
  1118.         if args[0] == "answer":
  1119.             produce_msg(args[1], _answers)
  1120.         produce_msg(self.data, _events)
  1121.  
  1122.     def handleConnected(self):
  1123.         global _ws
  1124.         _ws = self
  1125.         produce_msg("connect", _events)
  1126.  
  1127.     def handleClose(self):
  1128.         produce_msg("disconnect", _events)
  1129.         self.server.closing = True
  1130.         self.server.close()
  1131.  
  1132. def start_websocket():
  1133.     server = SimpleWebSocketServer("localhost", 7574, SocketHandler)
  1134.     server.closing = False
  1135.     while not server.closing:
  1136.         server.serveonce()
Add Comment
Please, Sign In to add comment