Skip to content

Commit bfa5893

Browse files
author
cage
committed
apply patch to fix emu-app-config
pebble/pebble-tool#46
1 parent 36ee2e0 commit bfa5893

File tree

2 files changed

+148
-0
lines changed

2 files changed

+148
-0
lines changed

docker-compose.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ services:
44
environment:
55
- DISPLAY
66
volumes:
7+
- ./docker/browser.py:/opt/pebble-sdk-4.5-linux64/pebble-tool/pebble_tool/util/browser.py
78
- /tmp/.X11-unit:/tmp.X11-unit
89
- ~/.Xauthority:/home/pebble/.Xauthority
910
- .:/pebble

docker/browser.py

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
from __future__ import absolute_import
2+
3+
from six.moves import BaseHTTPServer
4+
import logging
5+
import os
6+
import pyqrcode
7+
import socket
8+
import time
9+
from six.moves.urllib import parse as urlparse
10+
import webbrowser
11+
12+
from .phone_sensor import SENSOR_PAGE_HTML
13+
14+
15+
logger = logging.getLogger("pebble_tool.util.browser")
16+
17+
class BrowserController(object):
18+
def __init__(self):
19+
self.port = None
20+
21+
def open_config_page(self, url, callback):
22+
self.port = port = self._choose_port()
23+
url = self.url_append_params(url, {'return_to': 'http://localhost:{}/close?'.format(port)})
24+
if not url.startswith('file'):
25+
filename = '/tmp/config.%s.html' % os.getpid()
26+
temp = open(filename, 'w+b')
27+
temp.write('<head><meta http-equiv="refresh" content="0;URL={}"></head>'.format(url))
28+
temp.close()
29+
url = "file://{}".format(filename)
30+
webbrowser.open_new(url)
31+
self.serve_page(port, callback)
32+
33+
def serve_page(self, port, callback):
34+
# This is an array so AppConfigHandler doesn't create an instance variable when trying to set the state to False
35+
running = [True]
36+
37+
class AppConfigHandler(BaseHTTPServer.BaseHTTPRequestHandler):
38+
def do_GET(self):
39+
path, query = self.path.split('?', 1)
40+
if path == '/close':
41+
self.send_response(200)
42+
self.end_headers()
43+
self.wfile.write("OK")
44+
running[0] = False
45+
callback(query)
46+
else:
47+
self.send_response(404)
48+
self.end_headers()
49+
self.wfile.write("Not Found")
50+
51+
server = BaseHTTPServer.HTTPServer(('', port), AppConfigHandler)
52+
while running[0]:
53+
server.handle_request()
54+
55+
def url_append_params(self, url, params):
56+
parsed = urlparse.urlparse(url, "http")
57+
query = parsed.query
58+
if parsed.query != '':
59+
query += '&'
60+
61+
encoded_params = urlparse.urlencode(params)
62+
query += encoded_params
63+
return urlparse.urlunparse((parsed.scheme, parsed.netloc, parsed.path, parsed.params, query, parsed.fragment))
64+
65+
def serve_sensor_page(self, pypkjs_port, port=None):
66+
controller = self
67+
self.port = port or self._choose_port()
68+
69+
class SensorPageHandler(BaseHTTPServer.BaseHTTPRequestHandler):
70+
PERMITTED_PATHS = {'static/js/backbone-min.js',
71+
'static/js/backbone-min.map',
72+
'static/js/propeller.min.js',
73+
'static/js/sensors.js',
74+
'static/js/underscore-min.js',
75+
'static/js/underscore-min.map',
76+
'static/js/websocket.js',
77+
'static/compass-arrow.png',
78+
'static/compass-rose.png',
79+
'static/stylesheets/normalize.min.css',
80+
'static/stylesheets/sensors.css'}
81+
82+
def do_HEAD(self):
83+
self.send_response(200)
84+
self.end_headers()
85+
86+
def do_GET(self):
87+
requested_file = self.path.rsplit('/', 1)[1]
88+
file_path = self.path.lstrip('/')
89+
if requested_file == '':
90+
self.send_response(200)
91+
self.send_header('Content-type', 'text/html')
92+
self.end_headers()
93+
self.wfile.write(SENSOR_PAGE_HTML.format(websocket_host="'{}'".format(controller._get_ip()),
94+
websocket_port="'{}'".format(pypkjs_port)))
95+
elif file_path in self.PERMITTED_PATHS:
96+
try:
97+
file_contents = open(os.path.join(os.path.dirname(os.path.realpath(__file__)), file_path))
98+
self.send_response(200)
99+
self.end_headers()
100+
self.wfile.write(file_contents.read())
101+
except IOError:
102+
self.send_response(404)
103+
self.end_headers()
104+
self.wfile.write("Not Found")
105+
else:
106+
self.send_response(403)
107+
self.end_headers()
108+
self.wfile.write("Forbidden")
109+
110+
def log_request(self, code='-', size='-'):
111+
logger.debug("{} - - [{}] '{}' {} {}".format(self.client_address[0], self.log_date_time_string(),
112+
self.requestline, code, size))
113+
114+
server = BaseHTTPServer.HTTPServer(('', self.port), SensorPageHandler)
115+
try:
116+
url = "http://{}:{}".format(self._get_ip(), server.server_port)
117+
url_code = pyqrcode.create(url)
118+
print(url_code.terminal(quiet_zone=1))
119+
print("===================================================================================================")
120+
print("Please scan the QR code or enter the following URL in your mobile browser:\n{}".format(url))
121+
print("===================================================================================================")
122+
except socket.error:
123+
print("Unable to determine local IP address. Please browse to port {} on this machine from your mobile "
124+
"browser.".format(server.server_port))
125+
126+
print("\nUse Ctrl-C to stop sending sensor data to the emulator.\n")
127+
try:
128+
server.serve_forever()
129+
except KeyboardInterrupt:
130+
print("Stopping...")
131+
server.server_close()
132+
time.sleep(2) # Wait for WS connection to die between phone/QEMU
133+
134+
def _choose_port(self):
135+
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
136+
s.bind(('localhost', 0))
137+
addr, port = s.getsockname()
138+
s.close()
139+
return port
140+
141+
@classmethod
142+
def _get_ip(cls):
143+
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
144+
s.connect(('10.255.255.255', 1))
145+
addr, port = s.getsockname()
146+
s.close()
147+
return addr

0 commit comments

Comments
 (0)