Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

now depending on autobahn and twisted.

  • Loading branch information...
commit 5d0b82f460d938ddb77b3f26059be02e2c71e5b4 1 parent 24fb751
Boris Smus authored
View
43 server/app.py
@@ -1,9 +1,23 @@
-# objc-related imports
+# PyObjC-related imports
import objc
from Foundation import *
from AppKit import *
from PyObjCTools import AppHelper
+# Twisted and autobahn imports
+try:
+ from twisted.internet import _threadedselect as threadedselectreactor
+except:
+ from twisted.internet import threadedselectreactor
+try:
+ threadedselectreactor.install()
+except:
+ pass
+from twisted.internet import reactor
+from broadcast import BroadcastServerFactory
+
+KEY_UP = 11
+
class KeySocketApp(NSApplication):
def finishLaunching(self):
@@ -27,6 +41,11 @@ def finishLaunching(self):
menu.addItem_(menuitem)
self.statusitem.setMenu_(menu)
+ # Also start twisted
+ reactor.interleave(AppHelper.callAfter)
+ reactor.addSystemEventTrigger(
+ 'after', 'shutdown', AppHelper.stopEventLoop)
+
def sendEvent_(self, event):
if event.type() is NSSystemDefined and event.subtype() is 8:
@@ -40,7 +59,27 @@ def sendEvent_(self, event):
NSApplication.sendEvent_(self, event)
-def initialize(callback):
+
+ def applicationShouldTerminate_(self, sender):
+ if reactor.running:
+ reactor.stop()
+ return False
+ return True
+
+ def applicationDidFinishLaunching_(self, aNotification):
+ """Create and display a new connection window
+ """
+
+
+if __name__ == '__main__':
+ factory = BroadcastServerFactory()
+ reactor.listenTCP(1337, factory)
+
+ def callback(code, state):
+ if state is KEY_UP:
+ factory.broadcast(str(code))
+
app = KeySocketApp.sharedApplication()
app.callback = callback
AppHelper.runEventLoop()
+
View
81 server/hello.py
@@ -1,81 +0,0 @@
-# generic Python imports
-import datetime
-import os
-import sched
-import sys
-import tempfile
-import threading
-import time
-
-# need PyObjC on sys.path...:
-for d in sys.path:
- if 'Extras' in d:
- sys.path.append(d + '/PyObjC')
- break
-
-# objc-related imports
-import objc
-from Foundation import *
-from AppKit import *
-from PyObjCTools import AppHelper
-
-# all stuff related to the repeating-action
-thesched = sched.scheduler(time.time, time.sleep)
-
-def tick(n, writer):
- writer(n)
- thesched.enter(20.0, 10, tick, (n+1, writer))
- fd, name = tempfile.mkstemp('.txt', 'hello', '/tmp');
- print 'writing %r' % name
- f = os.fdopen(fd, 'w')
- f.write(datetime.datetime.now().isoformat())
- f.write('\n')
- f.close()
-
-def schedule(writer):
- pool = NSAutoreleasePool.alloc().init()
- thesched.enter(0.0, 10, tick, (1, writer))
- thesched.run()
- # normally you'd want pool.drain() here, but since this function never
- # ends until end of program (thesched.run never returns since each tick
- # schedules a new one) that pool.drain would never execute here;-).
-
-# objc-related stuff
-class TheDelegate(NSObject):
-
- statusbar = None
- state = 'idle'
-
- def applicationDidFinishLaunching_(self, notification):
- statusbar = NSStatusBar.systemStatusBar()
- self.statusitem = statusbar.statusItemWithLength_(
- NSVariableStatusItemLength)
- self.statusitem.setHighlightMode_(1)
- self.statusitem.setToolTip_('Example')
- self.statusitem.setTitle_('Example')
-
- self.menu = NSMenu.alloc().init()
- menuitem = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(
- 'Quit', 'terminate:', '')
- self.menu.addItem_(menuitem)
- self.statusitem.setMenu_(self.menu)
-
- def writer(self, s):
- self.badge.setBadgeLabel_(str(s))
-
-
-if __name__ == "__main__":
- # prepare and set our delegate
- app = NSApplication.sharedApplication()
- delegate = TheDelegate.alloc().init()
- app.setDelegate_(delegate)
- delegate.badge = app.dockTile()
- delegate.writer(0)
-
- # on a separate thread, run the scheduler
- t = threading.Thread(target=schedule, args=(delegate.writer,))
- t.setDaemon(1)
- t.start()
-
- # let her rip!-)
- AppHelper.runEventLoop()
View
BIN  server/icon-hi.png
Deleted file not rendered
View
BIN  server/icon.icns
Binary file not shown
View
BIN  server/icon.png
Deleted file not rendered
View
39 server/keysocket.py
@@ -1,39 +0,0 @@
-from threading import Thread
-import logging
-
-import app
-import websocket
-
-KEY_UP = 11
-
-class KeySocket(websocket.WebSocket):
- pass
-
-
-class KeySocketServer(Thread):
- def __init__(self):
- self.server = websocket.WebSocketServer('localhost', 1337, KeySocket)
- Thread.__init__(self)
-
- def run(self):
- self.server.listen()
-
- def sendKey(self, keyCode):
- for socket in self.server.connections.values():
- socket.send(keyCode)
-
-if __name__ == "__main__":
- # Start the websocket server in a separate thread
- server = KeySocketServer()
- server.start()
-
- def sendKeyCommand(code, state):
- # When there's a keyup
- if state is KEY_UP:
- # Send the code to the websocket
- server.sendKey(code)
- logging.info('Sent code %s to clients.' % code)
-
-
- # Launch the cocoa app
- app.initialize(sendKeyCommand);
View
6 server/setup.py
@@ -1,8 +1,8 @@
from setuptools import setup
OPTIONS = {
- 'iconfile': 'icon.icns',
- 'resources': ['icon.png', 'icon-hi.png'],
+ 'iconfile': 'res/icon.icns',
+ 'resources': ['res/icon.png', 'res/icon-hi.png'],
'plist': {
'CFBundleVersion': "0.1",
'LSUIElement': True
@@ -11,7 +11,7 @@
setup(
name="Key Socket",
- app=["keysocket.py"],
+ app=["app.py"],
options={'py2app': OPTIONS},
setup_requires=["py2app"],
)
View
161 server/websocket.py
@@ -1,161 +0,0 @@
-import time
-import struct
-import socket
-import hashlib
-import sys
-from select import select
-import re
-import logging
-from threading import Thread
-import signal
-
-logging.basicConfig(level=logging.DEBUG)
-
-class WebSocket(object):
- handshake = (
- "HTTP/1.1 101 Web Socket Protocol Handshake\r\n"
- "Upgrade: WebSocket\r\n"
- "Connection: Upgrade\r\n"
- "WebSocket-Origin: %(origin)s\r\n"
- "WebSocket-Location: ws://%(bind)s:%(port)s/\r\n"
- "Sec-Websocket-Origin: %(origin)s\r\n"
- "Sec-Websocket-Location: ws://%(bind)s:%(port)s/\r\n"
- "\r\n"
- )
- def __init__(self, client, server):
- self.client = client
- self.server = server
- self.handshaken = False
- self.header = ""
- self.data = ""
-
- def feed(self, data):
- if not self.handshaken:
- self.header += data
- if self.header.find('\r\n\r\n') != -1:
- parts = self.header.split('\r\n\r\n', 1)
- self.header = parts[0]
- if self.dohandshake(self.header, parts[1]):
- logging.info("Handshake successful")
- self.handshaken = True
- else:
- self.data += data
- msgs = self.data.split('\xff')
- self.data = msgs.pop()
- for msg in msgs:
- if msg[0] == '\x00':
- self.onmessage(msg[1:])
-
- def dohandshake(self, header, key=None):
- logging.debug("Begin handshake: %s" % header)
- digitRe = re.compile(r'[^0-9]')
- spacesRe = re.compile(r'\s')
- part_1 = part_2 = origin = None
- for line in header.split('\r\n')[1:]:
- name, value = line.split(': ', 1)
- if name.lower() == "sec-websocket-key1":
- key_number_1 = int(digitRe.sub('', value))
- spaces_1 = len(spacesRe.findall(value))
- if spaces_1 == 0:
- return False
- if key_number_1 % spaces_1 != 0:
- return False
- part_1 = key_number_1 / spaces_1
- elif name.lower() == "sec-websocket-key2":
- key_number_2 = int(digitRe.sub('', value))
- spaces_2 = len(spacesRe.findall(value))
- if spaces_2 == 0:
- return False
- if key_number_2 % spaces_2 != 0:
- return False
- part_2 = key_number_2 / spaces_2
- elif name.lower() == "origin":
- origin = value
- if part_1 and part_2:
- logging.debug("Using challenge + response")
- challenge = struct.pack('!I', part_1) + struct.pack('!I', part_2) + key
- response = hashlib.md5(challenge).digest()
- handshake = WebSocket.handshake % {
- 'origin': origin,
- 'port': self.server.port,
- 'bind': self.server.bind
- }
- handshake += response
- else:
- logging.warning("Not using challenge + response")
- handshake = WebSocket.handshake % {
- 'origin': origin,
- 'port': self.server.port,
- 'bind': self.server.bind
- }
- logging.debug("Sending handshake %s" % handshake)
- self.client.send(handshake)
- return True
-
- def onmessage(self, data):
- logging.info("Got message: %s" % data)
-
- def send(self, data):
- logging.info("Sent message: %s" % data)
- self.client.send("\x00%s\xff" % data)
-
- def close(self):
- self.client.close()
-
-class WebSocketServer(object):
- def __init__(self, bind, port, cls):
- self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
- self.socket.bind((bind, port))
- self.bind = bind
- self.port = port
- self.cls = cls
- self.connections = {}
- self.listeners = [self.socket]
-
- def listen(self, backlog=5):
- self.socket.listen(backlog)
- logging.info("Listening on %s" % self.port)
- self.running = True
- while self.running:
- rList, wList, xList = select(self.listeners, [], self.listeners, 1)
- for ready in rList:
- if ready == self.socket:
- logging.debug("New client connection")
- client, address = self.socket.accept()
- fileno = client.fileno()
- self.listeners.append(fileno)
- self.connections[fileno] = self.cls(client, self)
- else:
- logging.debug("Client ready for reading %s" % ready)
- logging.debug("Connections %s" % `self.connections`)
- client = self.connections[ready].client
- data = client.recv(1024)
- fileno = client.fileno()
- if data:
- self.connections[fileno].feed(data)
- else:
- logging.debug("Closing client %s" % ready)
- self.connections[fileno].close()
- del self.connections[fileno]
- self.listeners.remove(ready)
- for failed in xList:
- if failed == self.socket:
- logging.error("Socket broke")
- for fileno, conn in self.connections:
- conn.close()
- self.running = False
-
-if __name__ == "__main__":
- logging.basicConfig(level=logging.DEBUG, format="%(asctime)s - %(levelname)s - %(message)s")
- server = WebSocketServer("localhost", 9999, WebSocket)
- server_thread = Thread(target=server.listen, args=[5])
- server_thread.start()
- # Add SIGINT handler for killing the threads
- def signal_handler(signal, frame):
- logging.info("Caught Ctrl+C, shutting down...")
- server.running = False
- sys.exit()
- signal.signal(signal.SIGINT, signal_handler)
- while True:
- time.sleep(100)
Please sign in to comment.
Something went wrong with that request. Please try again.