replaced http.server with python version and used sockets instead of psutil

This commit is contained in:
Abubakar Abid 2019-02-24 22:15:12 -08:00
parent 6c1c9bbc31
commit eb2f141326
3 changed files with 225 additions and 29 deletions

View File

@ -2,18 +2,9 @@
"cells": [
{
"cell_type": "code",
"execution_count": 15,
"execution_count": 1,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"The autoreload extension is already loaded. To reload it, use:\n",
" %reload_ext autoreload\n"
]
}
],
"outputs": [],
"source": [
"%load_ext autoreload\n",
"%autoreload 2\n",
@ -23,7 +14,7 @@
},
{
"cell_type": "code",
"execution_count": 16,
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
@ -33,7 +24,7 @@
},
{
"cell_type": "code",
"execution_count": 17,
"execution_count": 3,
"metadata": {
"scrolled": true
},
@ -52,7 +43,7 @@
},
{
"cell_type": "code",
"execution_count": 20,
"execution_count": 4,
"metadata": {},
"outputs": [
{
@ -60,14 +51,167 @@
"output_type": "stream",
"text": [
"NOTE: Gradio is in beta stage, please report all bugs to: a12d@stanford.edu\n",
"Model available locally at: http://localhost:7871/interface.html\n",
"Model available locally at: http://localhost:7861/interface.html\n",
"To create a public link, set `share_link=True` in the argument to `launch()`\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"127.0.0.1 - - [24/Feb/2019 22:06:01] \"GET /interface.html HTTP/1.1\" 200 -\n",
"127.0.0.1 - - [24/Feb/2019 22:06:01] \"GET /js/all-io.js HTTP/1.1\" 200 -\n",
"127.0.0.1 - - [24/Feb/2019 22:06:01] \"GET /css/bootstrap.min.css HTTP/1.1\" 200 -\n",
"127.0.0.1 - - [24/Feb/2019 22:06:01] \"GET /css/draw-a-digit.css HTTP/1.1\" 200 -\n",
"127.0.0.1 - - [24/Feb/2019 22:06:01] \"GET /js/bootstrap.min.js HTTP/1.1\" 200 -\n",
"127.0.0.1 - - [24/Feb/2019 22:06:01] \"GET /js/bootstrap-notify.min.js HTTP/1.1\" 200 -\n",
"127.0.0.1 - - [24/Feb/2019 22:06:01] \"GET /js/textbox-input.js HTTP/1.1\" 200 -\n",
"127.0.0.1 - - [24/Feb/2019 22:06:01] \"GET /js/textbox-output.js HTTP/1.1\" 200 -\n",
"127.0.0.1 - - [24/Feb/2019 22:06:35] \"GET /interface.html HTTP/1.1\" 304 -\n",
"127.0.0.1 - - [24/Feb/2019 22:06:35] \"GET /js/all-io.js HTTP/1.1\" 304 -\n",
"127.0.0.1 - - [24/Feb/2019 22:06:35] \"GET /css/bootstrap.min.css HTTP/1.1\" 304 -\n",
"127.0.0.1 - - [24/Feb/2019 22:06:35] \"GET /css/draw-a-digit.css HTTP/1.1\" 304 -\n",
"127.0.0.1 - - [24/Feb/2019 22:06:35] \"GET /js/bootstrap.min.js HTTP/1.1\" 304 -\n",
"127.0.0.1 - - [24/Feb/2019 22:06:35] \"GET /js/bootstrap-notify.min.js HTTP/1.1\" 304 -\n",
"127.0.0.1 - - [24/Feb/2019 22:06:35] \"GET /js/textbox-input.js HTTP/1.1\" 304 -\n",
"127.0.0.1 - - [24/Feb/2019 22:06:35] \"GET /js/textbox-output.js HTTP/1.1\" 304 -\n"
]
}
],
"source": [
"iface.launch()"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Model type not explicitly identified, inferred to be: python function\n"
]
}
],
"source": [
"iface2 = gradio.Interface(input=\"textbox\", output=\"textbox\", model=test)"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Model type not explicitly identified, inferred to be: python function\n"
]
}
],
"source": [
"iface = gradio.Interface(input=\"textbox\", output=\"textbox\", model=test)"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"127.0.0.1 - - [24/Feb/2019 21:50:49] code 404, message File not found\n",
"127.0.0.1 - - [24/Feb/2019 21:50:49] \"GET /css/bootstrap.min.css HTTP/1.1\" 404 -\n",
"127.0.0.1 - - [24/Feb/2019 21:50:49] code 404, message File not found\n",
"127.0.0.1 - - [24/Feb/2019 21:50:49] \"GET /css/index.css HTTP/1.1\" 404 -\n",
"127.0.0.1 - - [24/Feb/2019 21:50:49] code 404, message File not found\n",
"127.0.0.1 - - [24/Feb/2019 21:50:49] \"GET /js/bootstrap.min.js HTTP/1.1\" 404 -\n",
"127.0.0.1 - - [24/Feb/2019 21:50:49] code 404, message File not found\n",
"127.0.0.1 - - [24/Feb/2019 21:50:49] \"GET /img/draw-a-digit.png HTTP/1.1\" 404 -\n",
"127.0.0.1 - - [24/Feb/2019 21:50:49] code 404, message File not found\n",
"127.0.0.1 - - [24/Feb/2019 21:50:49] \"GET /js/bootstrap.min.js HTTP/1.1\" 404 -\n",
"127.0.0.1 - - [24/Feb/2019 21:50:49] code 404, message File not found\n",
"127.0.0.1 - - [24/Feb/2019 21:50:49] \"GET /img/placeholder.png HTTP/1.1\" 404 -\n"
]
}
],
"source": [
"#!/bin/env python\n",
"import sys, signal\n",
"import http.server\n",
"import socketserver\n",
"import threading\n",
"\n",
"port = 7865\n",
"\n",
"# Note ForkingTCPServer does not work on Windows as the os.fork() \n",
"# function is not available on that OS. Instead we must use the \n",
"# subprocess server to handle multiple requests\n",
"server = socketserver.ThreadingTCPServer(('localhost',port), http.server.SimpleHTTPRequestHandler )\n",
"\n",
"#Ensures that Ctrl-C cleanly kills all spawned threads\n",
"server.daemon_threads = True \n",
"#Quicker rebinding\n",
"server.allow_reuse_address = True \n",
"\n",
"# A custom signal handle to allow us to Ctrl-C out of the process\n",
"def signal_handler(signal, frame):\n",
" print( 'Exiting http server (Ctrl+C pressed)')\n",
" try:\n",
" if(server):\n",
" server.server_close()\n",
" finally:\n",
" sys.exit(0)\n",
"\n",
"# Install the keyboard interrupt handler\n",
"signal.signal(signal.SIGINT, signal_handler)\n",
"\n",
"# Now loop forever\n",
"def serve_forever():\n",
" try:\n",
" while True:\n",
" sys.stdout.flush()\n",
" server.serve_forever()\n",
" except KeyboardInterrupt:\n",
" pass\n",
"\n",
"thread = threading.Thread(target=serve_forever)\n",
"thread.start()"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [],
"source": [
"import socket\n",
"\n",
"s = socket.socket() \n",
"s.bind(('localhost', 7866))\n",
"s.close()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"1+1"
]
}
],
"metadata": {

View File

@ -167,7 +167,7 @@ class Interface():
path_to_server = 'http://localhost:{}/'.format(server_port)
self._build_template(output_directory)
ports_in_use = networking.get_ports_in_use()
ports_in_use = networking.get_ports_in_use(INITIAL_WEBSOCKET_PORT, INITIAL_WEBSOCKET_PORT + TRY_NUM_PORTS)
for i in range(TRY_NUM_PORTS):
if not ((INITIAL_WEBSOCKET_PORT + i) in ports_in_use):
break
@ -191,6 +191,7 @@ class Interface():
else:
if verbose:
print("To create a public link, set `share_link=True` in the argument to `launch()`")
asyncio.get_event_loop().run_until_complete(start_server)
try:
asyncio.get_event_loop().run_forever()

View File

@ -4,11 +4,17 @@ import zipfile
import io
import sys
import os
import socket
from psutil import process_iter, AccessDenied
from signal import SIGTERM # or SIGKILL
import signal
import http.server
import socketserver
import threading
INITIAL_PORT_VALUE = 7860
TRY_NUM_PORTS = 100
LOCALHOST_NAME = 'localhost'
LOCALHOST_PREFIX = 'localhost:'
NGROK_TUNNELS_API_URL = "http://localhost:4040/api/tunnels" # TODO(this should be captured from output)
NGROK_TUNNELS_API_URL2 = "http://localhost:4041/api/tunnels" # TODO(this should be captured from output)
@ -20,31 +26,76 @@ NGROK_ZIP_URLS = {
}
def get_ports_in_use():
def get_ports_in_use(start, stop):
ports_in_use = []
try:
for proc in process_iter():
for conns in proc.connections(kind='inet'):
ports_in_use.append(conns.laddr.port)
except AccessDenied:
pass # TODO(abidlabs): somehow find a way to handle this issue?
for port in range(start, stop):
try:
s = socket.socket() # create a socket object
s.bind((LOCALHOST_NAME, port)) # Bind to the port
s.close()
except OSError:
ports_in_use.append(port)
return ports_in_use
# ports_in_use = []
# try:
# for proc in process_iter():
# for conns in proc.connections(kind='inet'):
# ports_in_use.append(conns.laddr.port)
# except AccessDenied:
# pass # TODO(abidlabs): somehow find a way to handle this issue?
# return ports_in_use
def serve_files_in_background(port, directory_to_serve=None):
def handler(*args):
return http.server.SimpleHTTPRequestHandler(*args, directory=directory_to_serve)
server = socketserver.ThreadingTCPServer(('localhost', port), handler)
# Ensures that Ctrl-C cleanly kills all spawned threads
server.daemon_threads = True
# Quicker rebinding
server.allow_reuse_address = True
# A custom signal handle to allow us to Ctrl-C out of the process
def signal_handler(signal, frame):
print('Exiting http server (Ctrl+C pressed)')
try:
if (server):
server.server_close()
finally:
sys.exit(0)
# Install the keyboard interrupt handler
signal.signal(signal.SIGINT, signal_handler)
# Now loop forever
def serve_forever():
try:
while True:
sys.stdout.flush()
server.serve_forever()
except KeyboardInterrupt:
pass
thread = threading.Thread(target=serve_forever)
thread.start()
def start_simple_server(directory_to_serve=None):
# TODO(abidlabs): increment port number until free port is found
ports_in_use = get_ports_in_use()
ports_in_use = get_ports_in_use(start=INITIAL_PORT_VALUE, stop=INITIAL_PORT_VALUE + TRY_NUM_PORTS)
for i in range(TRY_NUM_PORTS):
if not((INITIAL_PORT_VALUE + i) in ports_in_use):
break
else:
raise OSError("All ports from {} to {} are in use. Please close a port.".format(
INITIAL_PORT_VALUE, INITIAL_PORT_VALUE + TRY_NUM_PORTS))
if directory_to_serve is None:
subprocess.Popen(['python', '-m', 'http.server', str(INITIAL_PORT_VALUE + i)])
else:
cmd = ' '.join(['python', '-m', 'http.server', '-d', directory_to_serve, str(INITIAL_PORT_VALUE + i)])
subprocess.Popen(cmd, shell=True) # Doesn't seem to work if list is passed for some reason.
serve_files_in_background(INITIAL_PORT_VALUE + i, directory_to_serve)
# if directory_to_serve is None:
# subprocess.Popen(['python', '-m', 'http.server', str(INITIAL_PORT_VALUE + i)])
# else:
# cmd = ' '.join(['python', '-m', 'http.server', '-d', directory_to_serve, str(INITIAL_PORT_VALUE + i)])
# subprocess.Popen(cmd, shell=True) # Doesn't seem to work if list is passed for some reason.
return INITIAL_PORT_VALUE + i