Skip to content

Commit

Permalink
Add support for port ranges. Split proxy.port into client.proxyPort, …
Browse files Browse the repository at this point in the history
…browser.proxyPort and browser.proxyPortRange.
  • Loading branch information
tvst committed Nov 30, 2018
1 parent d8d69d2 commit ae264c2
Show file tree
Hide file tree
Showing 10 changed files with 108 additions and 55 deletions.
4 changes: 2 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,8 +143,8 @@ make install
make pytest
python admin/test_streamlit.py
```
Check that all elements and figures work properly
and everything should run over port `8501`.
Check that all elements and figures work properly and the browser connection
should run over port `8501`.

**Note:** It's fine to `ctrl-C` kill `mnist-cnn.py` becuase it runs for so long.

Expand Down
6 changes: 3 additions & 3 deletions frontend/src/StreamlitApp.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ import StaticConnection from './StaticConnection';
import StreamlitDialog from './StreamlitDialog';

import { ForwardMsg, Text as TextProto } from './protobuf';
import { PROXY_PORT_PROD, FETCH_PARAMS } from './baseconsts';
import { FETCH_PARAMS } from './baseconsts';
import { addRows } from './dataFrameProto';
import { initRemoteTracker, trackEventRemotely } from './remotetracking';
import { toImmutableProto, dispatchOneOf } from './immutableProto';
Expand Down Expand Up @@ -115,8 +115,8 @@ class StreamlitApp extends PureComponent {
const reportName = query.name;
this.setReportName(reportName);

const uri =
getWsUrl(window.location.hostname, PROXY_PORT_PROD, reportName);
const uri = getWsUrl(
window.location.hostname, window.location.port, reportName);

this.connection = new WebsocketConnection({
uriList: [uri],
Expand Down
7 changes: 0 additions & 7 deletions frontend/src/baseconsts.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,6 @@
* Copyright 2018 Streamlit Inc. All rights reserved.
*/

/**
* Port used to connect to the proxy server.
* TODO: Allow user to change this via config options. Today, the config option
* exists, but it looks like it's never sent to the web client.
*/
export const PROXY_PORT_PROD = 8501;

/**
* This is the port used to connect to the web server.
*/
Expand Down
9 changes: 5 additions & 4 deletions lib/streamlit/ConfigOption.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,19 @@
class ConfigOption(object):
'''Stores a Streamlit configuration option.
A configuration option, like 'proxy.port', which indicates which port to use
when connecting to the proxy. There are two ways to create a ConfigOption:
A configuration option, like 'client.proxyPort', which indicates which port
to use when connecting to the proxy. There are two ways to create a
ConfigOption:
Simple ConfigOptions are created as follows:
ConfigOption('proxy.port',
ConfigOption('client.proxyPort',
description = 'Connect to the proxy at this port.',
default_val = 8501)
More complex config options resolve thier values at runtime as follows:
@ConfigOption('proxy.port')
@ConfigOption('client.proxyPort')
def _proxy_port():
"""Connect to the proxy at this port.
Expand Down
2 changes: 1 addition & 1 deletion lib/streamlit/Connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ def _cleanup_on_exit(self, main_thread, on_cleanup):

def _wait_for_proxy_to_close(self):
host = config.get_option('client.proxyAddress')
port = config.get_option('proxy.port')
port = config.get_option('client.proxyPort')
url = f'http://{host}:{port}/healthz'

LOGGER.debug('Waiting for proxy to close...')
Expand Down
2 changes: 1 addition & 1 deletion lib/streamlit/DeltaConnection.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ def _build_uri(report_id):
LOGGER.debug(f'Report name: "{name}"')

server = config.get_option('client.proxyAddress')
port = config.get_option('proxy.port')
port = config.get_option('client.proxyPort')
report_name = urllib.parse.quote_plus(name)
uri = f'ws://{server}:{port}/new/{report_name}'

Expand Down
47 changes: 38 additions & 9 deletions lib/streamlit/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,20 +159,21 @@ def _global_log_level():
'client.proxyAddress',
description='''
Internet address of the proxy server that the client should connect
to. Can be IP address or DNS name. Only set if different from
proxy.port.''',
to. Can be IP address or DNS name.''',
default_val='localhost')

_create_option(
'client.proxyPort',
description='''
The port that the client should use to connect to the proxy.
''',
default_val=8500)


# Config Section: Proxy #

_create_section('proxy', 'Configuration of the proxy server.')

_create_option(
'proxy.port',
description='Port that the proxy server should listed on.',
default_val=8501)

_create_option(
'proxy.autoCloseDelaySecs',
description=(
Expand Down Expand Up @@ -255,8 +256,36 @@ def _proxy_is_remote():
'browser.proxyAddress',
description='''
Internet address of the proxy server that the browser should connect
to. Can be IP address or DNS name. Only set if different from
proxy.port.''',
to. Can be IP address or DNS name.''',
default_val=None)


@_create_option('browser.proxyPort')
@util.memoize
def _browser_proxy_port():
"""Port that the browser should use to connect to the proxy.
Default: 8501
"""
port_range = get_option('browser.proxyPortRange')

if port_range is None:
return 8501

assert len(port_range) == 2, (
'browser.proxyPortRange must be a 2-element list')

import random
return random.randint(port_range[0], port_range[1])


_create_option(
'browser.proxyPortRange',
description='''
Use this if you want the proxy to pick a random port for communication
with the browser. Accepts ranges in the form (min, max), such as
(49152, 65535).
''',
default_val=None)


Expand Down
56 changes: 38 additions & 18 deletions lib/streamlit/proxy/Proxy.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,20 +76,46 @@ def __init__(self):
LOGGER.debug(
f'Creating proxy with self._connections: {id(self._connections)}')

# We have to import these in here to break a circular import reference
self._set_up_client_server()
self._set_up_browser_server()

# Remember whether we've seen any browser connections so that we can
# display a helpful warming message if the proxy closed without having
# received any connections.
self._received_browser_connection = False

# Avoids an exception by guarding against twice stopping the event loop.
self._stopped = False

def _set_up_client_server(self):
# We have to import this in here to break a circular import reference
# issue in Python 2.7.
from streamlit.proxy import ClientWebSocket, BrowserWebSocket
from streamlit.proxy import ClientWebSocket

# Set up HTTP routes
routes = [
# Endpoint for WebSocket used by clients to send data to the Proxy.
('/new/(.*)', ClientWebSocket, dict(proxy=self)),
('/healthz', _HealthHandler),
]

# Endpoint for WebSocket used by the Proxy to send data to browsers.
('/stream/(.*)', BrowserWebSocket, dict(proxy=self)),
app = web.Application(routes)
port = config.get_option('client.proxyPort')

http_server = HTTPServer(app)
http_server.listen(port)

LOGGER.info('Proxy HTTP server for client connections started on '
'port {}'.format(port))

def _set_up_browser_server(self):
# We have to import this in here to break a circular import reference
# issue in Python 2.7.
from streamlit.proxy import BrowserWebSocket

routes = [
('/stream/(.*)', BrowserWebSocket, dict(proxy=self)),
('/healthz', _HealthHandler),
]

if not config.get_option('proxy.useNode'):
# If we're not using the node development server, then the proxy
# will serve up the development pages.
Expand All @@ -102,21 +128,15 @@ def __init__(self):
])
else:
LOGGER.info('useNode == True, not serving static content from python.')
self._app = web.Application(routes)

# Attach an http server
port = config.get_option('proxy.port')
http_server = HTTPServer(self._app)
http_server.listen(port)
LOGGER.info('Proxy http server started on port {}'.format(port))
app = web.Application(routes)
port = config.get_option('browser.proxyPort')

# Remember whether we've seen any browser connections so that we can
# display a helpful warming message if the proxy closed without having
# received any connections.
self._received_browser_connection = False
http_server = HTTPServer(app)
http_server.listen(port)

# Avoids an exception by guarding against twice stopping the event loop.
self._stopped = False
LOGGER.info('Proxy HTTP server for browser connection started on '
'port {}'.format(port))

def run_app(self):
"""Run web app."""
Expand Down
8 changes: 4 additions & 4 deletions lib/streamlit/proxy/ProxyConnection.py
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,7 @@ def _build_manifest(
configuredProxyAddress=configured_proxy_address,
externalProxyIP=external_proxy_ip,
internalProxyIP=internal_proxy_ip,
proxyPort=config.get_option('proxy.port'),
proxyPort=config.get_option('browser.proxyPort'),
)


Expand All @@ -310,13 +310,13 @@ def _get_report_url(host, name):
The report's URL.
"""
port = _get_http_port()
port = _get_proxy_browser_port()

quoted_name = urllib.parse.quote_plus(name)
return 'http://{}:{}/?name={}'.format(host, port, quoted_name)


def _get_http_port():
def _get_proxy_browser_port():
if config.get_option('proxy.useNode'):
return 3000
return config.get_option('proxy.port')
return config.get_option('browser.proxyPort')
22 changes: 16 additions & 6 deletions site/content/docs/help.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,25 @@ weight: 103
Sometimes people hit roadblocks when using Streamlit. Here are a few problems we have seen, and ways we have solved them in the past. Hopefully, you find a fix that works for you. If not, please let us know (<hello@streamlit.io>).

### Opening the Streamlit report in my browser doesn't work
You ran `streamlit help` or `python my_script.py` and it printed out the URL where you should find your report -
but it doesn't seem to work when you open that link!

**if you are running Streamlit remotely**, this can happen if you haven't opened up port 8501 on your instance.
You ran `streamlit help` or `python my_script.py` and it printed out the URL
where you should find your report - but it doesn't seem to work when you open
that link!

How do you fix this? First, click on your instance in the [AWS Console](https://us-west-2.console.aws.amazon.com/ec2/v2/home?region=us-west-2#Instances:sort=instanceId). Then scroll down until you see the "Security Groups" & click on that. Click on "Inbound" & "Edit". Next, add a "Custom TCP" rule that allows the Port Range "8501" with Source "0.0.0.0/0".
**If you are running Streamlit remotely**, this can happen if you haven't
opened up port 8501 on your instance.

How do you fix this? First, click on your instance in the [AWS
Console](https://us-west-2.console.aws.amazon.com/ec2/v2/home?region=us-west-2#Instances:sort=instanceId).
Then scroll down until you see the "Security Groups" & click on that. Click on
"Inbound" & "Edit". Next, add a "Custom TCP" rule that allows the Port Range
"8501" with Source "0.0.0.0/0".

### Streamlit just hangs when I run my script
Sometimes there is a hanging proxy from your previous run. A quick way to fix that is by running this command:

Sometimes there is a hanging proxy from your previous run. A quick way to fix
that is by running this command:

```bash
$ streamlit kill_proxy
```
```

0 comments on commit ae264c2

Please sign in to comment.