Permalink
Browse files

Merge branch 'v2' into integration

  • Loading branch information...
progrium committed Apr 27, 2012
2 parents 1ff9d85 + 6e67964 commit ad57044dc3ec66e3196bb3be4d6f2f26b16d73ce
Showing with 455 additions and 0 deletions.
  1. +7 −0 .gitignore
  2. +1 −0 Procfile
  3. +45 −0 README
  4. +12 −0 deploy/builder
  5. +6 −0 deploy/dotcloud.conf.py
  6. +6 −0 deploy/heroku.conf.py
  7. +3 −0 dotcloud.yml
  8. +5 −0 localtunnel/__init__.py
  9. +103 −0 localtunnel/client.py
  10. +244 −0 localtunnel/server.py
  11. +6 −0 requirements.txt
  12. +17 −0 setup.py
View
@@ -1,3 +1,10 @@
+bin
+*.pyc
+**/*.pyc
+build
+dist
+*.egg-info
+serviced.log
.idea
.idea/*
.idea/**/*
View
@@ -0,0 +1 @@
+app: python -c "__requires__ = 'ginkgo'; import sys; from pkg_resources import load_entry_point; sys.exit(load_entry_point('ginkgo', 'console_scripts', 'ginkgo')())" ./config/heroku.conf.py
View
45 README
@@ -0,0 +1,45 @@
+How to use v2:
+
+First:
+
+python setup.py develop
+
+(Alternatively you can do install instead of develop)
+
+Now run some web app locally on, say, port 8000. If you have nothing,
+run this in some directory:
+
+python -m SimpleHTTPServer 8000
+
+Localtunnel does some stuff with the hostname, so you want to set up two
+hostnames. One for localtunnel registration, one for your localtunnel.
+Normally it expects a wildcard, but we'll just hardcode a hostname for
+this example tunnel.
+
+example.localtunnel.local -> 127.0.0.1
+localtunnel.local -> 127.0.0.1
+
+You can do this in /etc/hosts or use that fancy ghost utility.
+
+Now you can start the server. It's based on a configuration file in the
+config directory. You can make your own, but this one is configured to
+run the server on port 9999 and expects the hostname localtunnel.local
+
+ginkgo config/default.conf.py
+
+Like your web app or SimpleHTTPServer, you'll want to leave this
+running. The client is installed as a command called "lt". You use this
+to make the tunnel. We have to specify the broker address, and the name
+of the tunnel:
+
+lt --broker 127.0.0.1:9999 --name example 8000
+
+Leave this running. Now you should be able to browse to:
+
+http://example.localtunnel.local:9999
+
+And you should see the same thing as you would at:
+
+http://localhost:8000
+
+THE END
View
@@ -0,0 +1,12 @@
+#!/bin/bash
+cp -a . ~
+cd
+(cat <<-EOF
+ virtualenv --python=python2.7 env
+ . env/bin/activate
+ pip install -r requirements.txt
+ python setup.py develop
+ python -c "__requires__ = 'ginkgo'; import sys; from pkg_resources import load_entry_point; sys.exit(load_entry_point('ginkgo','console_scripts', 'ginkgo')())" ./config/dotcloud.conf.py
+EOF
+) > run
+chmod a+x run
View
@@ -0,0 +1,6 @@
+import os
+
+port = int(os.environ.get("PORT_WWW", 5000))
+hostname = 'v2.localtunnel.com'
+
+service = 'localtunnel.server.TunnelBroker'
View
@@ -0,0 +1,6 @@
+import os
+
+port = int(os.environ.get("PORT", 5000))
+hostname = 'localtunnel.heroku'
+
+service = 'localtunnel.server.TunnelBroker'
View
@@ -0,0 +1,3 @@
+www:
+ type: custom
+ buildscript: deploy/builder
View
@@ -0,0 +1,5 @@
+def encode_data_packet(conn_id, data):
+ return ''.join([chr(conn_id), data])
+
+def decode_data_packet(data):
+ return data[0], data[1:]
View
@@ -0,0 +1,103 @@
+import json
+import uuid
+
+import gevent
+from gevent.socket import create_connection
+from gevent.coros import Semaphore
+
+from ginkgo import Service
+
+from ws4py.client.geventclient import WebSocketClient
+
+from localtunnel import encode_data_packet
+from localtunnel import decode_data_packet
+
+#WebSocketClient.upgrade_header = 'X-Upgrade'
+
+def main():
+ import argparse
+ parser = argparse.ArgumentParser(description='Open a public HTTP tunnel to a local server')
+ parser.add_argument('port', metavar='port', type=int,
+ help='local port of server to tunnel to')
+ parser.add_argument('--name', dest='name', metavar='name',
+ default=str(uuid.uuid4()).split('-')[-1],
+ help='name of the tunnel (default: randomly generate)')
+ parser.add_argument('--broker', dest='broker', metavar='address',
+ default='localtunnel.com',
+ help='tunnel broker hostname (default: localtunnel.com)')
+ args = parser.parse_args()
+
+ client = TunnelClient(args.port, args.name, args.broker)
+ client.serve_forever()
+
+class TunnelClient(Service):
+
+ def __init__(self, local_port, name, broker_address):
+ self.local_port = local_port
+ self.ws = WebSocketClient('http://%s/t/%s' % (broker_address, name))
+ self.connections = {}
+ self._send_lock = Semaphore()
+
+ def do_start(self):
+ self.ws.connect()
+ self.spawn(self.listen)
+ #gevent.spawn(self.visual_heartbeat)
+
+ def visual_heartbeat(self):
+ while True:
+ print "."
+ gevent.sleep(1)
+
+ def listen(self):
+ while True:
+ msg = self.ws.receive(msg_obj=True)
+ if msg is None:
+ print "Trying to stop"
+ self.stop()
+ if msg.is_text:
+ parsed = json.loads(str(msg))
+ print str(msg)
+ conn_id, event = parsed[0:2]
+ if event == 'open':
+ self.local_open(conn_id)
+ elif event == 'closed':
+ self.local_close(conn_id)
+ elif msg.is_binary:
+ conn_id, data = decode_data_packet(msg.data)
+ self.local_send(conn_id, data)
+
+ def local_open(self, conn_id):
+ socket = create_connection(('0.0.0.0', self.local_port))
+ self.connections[conn_id] = socket
+ self.spawn(self.local_recv, conn_id)
+
+ def local_close(self, conn_id):
+ socket = self.connections.pop(conn_id)
+ try:
+ socket.shutdown(0)
+ socket.close()
+ except:
+ pass
+
+ def local_send(self, conn_id, data):
+ self.connections[conn_id].send(data)
+
+ def local_recv(self, conn_id):
+ while True:
+ data = self.connections[conn_id].recv(1024)
+ if not data:
+ break
+ self.tunnel_send(conn_id, data)
+ self.tunnel_send(conn_id, open=False)
+
+ def tunnel_send(self, conn_id, data=None, open=None):
+ if open is False:
+ msg = [conn_id, 'closed']
+ with self._send_lock:
+ self.ws.send(json.dumps(msg))
+ elif data:
+ msg = encode_data_packet(conn_id, data)
+ with self._send_lock:
+ self.ws.send(msg, binary=True)
+ else:
+ return
Oops, something went wrong.

0 comments on commit ad57044

Please sign in to comment.