mirror of
				https://github.com/zulip/zulip.git
				synced 2025-11-03 21:43:21 +00:00 
			
		
		
		
	- All necessary strings was converted to bytestring - Added twisted as py3 dependency - Change type annotation for method getchild of class Resource - Remove activating python2 env section from run-dev.py script Fixes #1256
		
			
				
	
	
		
			169 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			169 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
#!/usr/bin/env python
 | 
						|
from __future__ import print_function
 | 
						|
 | 
						|
import optparse
 | 
						|
import pwd
 | 
						|
import subprocess
 | 
						|
import signal
 | 
						|
import traceback
 | 
						|
import sys
 | 
						|
import os
 | 
						|
 | 
						|
if False: from typing import Any
 | 
						|
 | 
						|
from twisted.internet import reactor
 | 
						|
from twisted.web      import proxy, server, resource
 | 
						|
 | 
						|
# Monkey-patch twisted.web.http to avoid request.finish exceptions
 | 
						|
# https://trac.zulip.net/ticket/1728
 | 
						|
from twisted.web.http import Request
 | 
						|
orig_finish = Request.finish
 | 
						|
def patched_finish(self):
 | 
						|
    # type: (Any) -> None
 | 
						|
    if not self._disconnected:
 | 
						|
        orig_finish(self)
 | 
						|
Request.finish = patched_finish
 | 
						|
 | 
						|
if 'posix' in os.name and os.geteuid() == 0:
 | 
						|
    raise RuntimeError("run-dev.py should not be run as root.")
 | 
						|
 | 
						|
parser = optparse.OptionParser(r"""
 | 
						|
 | 
						|
Starts the app listening on localhost, for local development.
 | 
						|
 | 
						|
This script launches the Django and Tornado servers, then runs a reverse proxy
 | 
						|
which serves to both of them.  After it's all up and running, browse to
 | 
						|
 | 
						|
    http://localhost:9991/
 | 
						|
 | 
						|
Note that, while runserver and runtornado have the usual auto-restarting
 | 
						|
behavior, the reverse proxy itself does *not* automatically restart on changes
 | 
						|
to this file.
 | 
						|
""")
 | 
						|
 | 
						|
parser.add_option('--test',
 | 
						|
    action='store_true', dest='test',
 | 
						|
    help='Use the testing database and ports')
 | 
						|
 | 
						|
parser.add_option('--interface',
 | 
						|
    action='store', dest='interface',
 | 
						|
    default=None, help='Set the IP or hostname for the proxy to listen on')
 | 
						|
 | 
						|
parser.add_option('--no-clear-memcached',
 | 
						|
    action='store_false', dest='clear_memcached',
 | 
						|
    default=True, help='Do not clear memcached')
 | 
						|
 | 
						|
(options, args) = parser.parse_args()
 | 
						|
 | 
						|
if options.interface is None:
 | 
						|
    user_id = os.getuid()
 | 
						|
    user_name = pwd.getpwuid(user_id).pw_name
 | 
						|
    if user_name == "vagrant":
 | 
						|
        # In the Vagrant development environment, we need to listen on
 | 
						|
        # all ports, and it's safe to do so, because Vagrant is only
 | 
						|
        # exposing certain guest ports (by default just 9991) to the host.
 | 
						|
        options.interface = ""
 | 
						|
    else:
 | 
						|
        # Otherwise, only listen to requests on localhost for security.
 | 
						|
        options.interface = "127.0.0.1"
 | 
						|
 | 
						|
base_port   = 9991
 | 
						|
if options.test:
 | 
						|
    base_port   = 9981
 | 
						|
    settings_module = "zproject.test_settings"
 | 
						|
else:
 | 
						|
    settings_module = "zproject.settings"
 | 
						|
 | 
						|
manage_args = ['--settings=%s' % (settings_module,)]
 | 
						|
os.environ['DJANGO_SETTINGS_MODULE'] = settings_module
 | 
						|
 | 
						|
sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
 | 
						|
 | 
						|
from scripts.lib.zulip_tools import WARNING, ENDC
 | 
						|
 | 
						|
proxy_port   = base_port
 | 
						|
django_port  = base_port+1
 | 
						|
tornado_port = base_port+2
 | 
						|
webpack_port = base_port+3
 | 
						|
 | 
						|
os.chdir(os.path.join(os.path.dirname(__file__), '..'))
 | 
						|
 | 
						|
# Clean up stale .pyc files etc.
 | 
						|
subprocess.check_call('./tools/clean-repo')
 | 
						|
 | 
						|
# HACK to fix up node_modules/.bin/handlebars deletion issue
 | 
						|
if not os.path.exists("node_modules/.bin/handlebars") and os.path.exists("node_modules/handlebars"):
 | 
						|
    print("Handlebars binary missing due to rebase past .gitignore fixup; fixing...")
 | 
						|
    subprocess.check_call(["rm", "-rf", "node_modules/handlebars"])
 | 
						|
    subprocess.check_call(["npm", "install"])
 | 
						|
 | 
						|
if options.clear_memcached:
 | 
						|
    print("Clearing memcached ...")
 | 
						|
    subprocess.check_call('./scripts/setup/flush-memcached')
 | 
						|
 | 
						|
# Set up a new process group, so that we can later kill run{server,tornado}
 | 
						|
# and all of the processes they spawn.
 | 
						|
os.setpgrp()
 | 
						|
 | 
						|
# Pass --nostatic because we configure static serving ourselves in
 | 
						|
# zulip/urls.py.
 | 
						|
cmds = [['./tools/compile-handlebars-templates', 'forever'],
 | 
						|
        ['python', 'manage.py', 'rundjango'] +
 | 
						|
          manage_args + ['127.0.0.1:%d' % (django_port,)],
 | 
						|
        ['python', '-u', 'manage.py', 'runtornado'] +
 | 
						|
          manage_args + ['127.0.0.1:%d' % (tornado_port,)],
 | 
						|
        ['./tools/run-dev-queue-processors'] + manage_args,
 | 
						|
        ['env', 'PGHOST=127.0.0.1', # Force password authentication using .pgpass
 | 
						|
         './puppet/zulip/files/postgresql/process_fts_updates']]
 | 
						|
if options.test:
 | 
						|
    # Webpack doesn't support 2 copies running on the same system, so
 | 
						|
    # in order to support running the Casper tests while a Zulip
 | 
						|
    # development server is running, we use webpack in production mode
 | 
						|
    # for the Casper tests.
 | 
						|
    subprocess.check_call('./tools/webpack')
 | 
						|
else:
 | 
						|
    cmds += [['./tools/webpack', '--watch', '--port', str(webpack_port)]]
 | 
						|
for cmd in cmds:
 | 
						|
    subprocess.Popen(cmd)
 | 
						|
 | 
						|
class Resource(resource.Resource):
 | 
						|
    def getChild(self, name, request):
 | 
						|
        # type: (bytes, server.Request) -> resource.Resource
 | 
						|
 | 
						|
        # Assume an HTTP 1.1 request
 | 
						|
        proxy_host = request.requestHeaders.getRawHeaders('Host')
 | 
						|
        request.requestHeaders.setRawHeaders('X-Forwarded-Host', proxy_host)
 | 
						|
        if (request.uri in [b'/json/get_events'] or
 | 
						|
            request.uri.startswith(b'/json/events') or
 | 
						|
            request.uri.startswith(b'/api/v1/events') or
 | 
						|
            request.uri.startswith(b'/sockjs')):
 | 
						|
            return proxy.ReverseProxyResource('127.0.0.1', tornado_port, b'/' + name)
 | 
						|
 | 
						|
        elif (request.uri.startswith(b'/webpack') or
 | 
						|
              request.uri.startswith(b'/socket.io')):
 | 
						|
            return proxy.ReverseProxyResource('127.0.0.1', webpack_port, b'/' + name)
 | 
						|
 | 
						|
        return proxy.ReverseProxyResource('127.0.0.1', django_port, b'/'+name)
 | 
						|
 | 
						|
 | 
						|
    # log which services/ports will be started
 | 
						|
    print("Starting Zulip services on ports: web proxy: {},".format(proxy_port),
 | 
						|
          "Django: {}, Tornado: {}".format(django_port, tornado_port), end='')
 | 
						|
    if options.test:
 | 
						|
        print("")  # no webpack for --test
 | 
						|
    else:
 | 
						|
        print(", webpack: {}".format(webpack_port))
 | 
						|
 | 
						|
    print(WARNING + "Note: only port {} is exposed to the host in a Vagrant environment.".format(proxy_port) + ENDC)
 | 
						|
 | 
						|
try:
 | 
						|
    reactor.listenTCP(proxy_port, server.Site(Resource()), interface=options.interface)
 | 
						|
    reactor.run()
 | 
						|
except:
 | 
						|
    # Print the traceback before we get SIGTERM and die.
 | 
						|
    traceback.print_exc()
 | 
						|
    raise
 | 
						|
finally:
 | 
						|
    # Kill everything in our process group.
 | 
						|
    os.killpg(0, signal.SIGTERM)
 |