161 lines
4.8 KiB
Python
161 lines
4.8 KiB
Python
import http.server
|
|
import urllib.parse
|
|
import socket
|
|
import threading
|
|
from logbook import Logger
|
|
|
|
from service.settings import CRESTSettings
|
|
pyfalog = Logger(__name__)
|
|
|
|
# noinspection PyPep8
|
|
HTML = '''
|
|
<!DOCTYPE html>
|
|
<html>
|
|
|
|
<head>
|
|
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
|
|
<title>pyfa Local Server</title>
|
|
<style type="text/css">
|
|
body {{ text-align: center; padding: 150px; }}
|
|
h1 {{ font-size: 40px; }}
|
|
h2 {{ font-size: 32px; }}
|
|
body {{ font: 20px Helvetica, sans-serif; color: #333; }}
|
|
#article {{ display: block; text-align: left; width: 650px; margin: 0 auto; }}
|
|
a {{ color: #dc8100; text-decoration: none; }}
|
|
a:hover {{ color: #333; text-decoration: none; }}
|
|
</style>
|
|
</head>
|
|
|
|
<body>
|
|
|
|
<!-- Layout from Short Circuit's CREST login. Shout out! https://github.com/farshield/shortcircuit -->
|
|
<div id="article">
|
|
<h1>pyfa</h1>
|
|
{0}
|
|
</div>
|
|
|
|
<script type="text/javascript">
|
|
function extractFromHash(name, hash) {{
|
|
var match = hash.match(new RegExp(name + "=([^&]+)"));
|
|
return !!match && match[1];
|
|
}}
|
|
|
|
var hash = window.location.hash;
|
|
var token = extractFromHash("access_token", hash);
|
|
var step2 = extractFromHash("step2", hash);
|
|
|
|
function doRedirect() {{
|
|
if (token){{
|
|
// implicit authentication
|
|
var redirect = window.location.origin.concat('/?', window.location.hash.substr(1), '&step=2');
|
|
window.location = redirect;
|
|
}}
|
|
else {{
|
|
// user-defined
|
|
var redirect = window.location.href + '&step=2';
|
|
window.location = redirect;
|
|
}}
|
|
}}
|
|
|
|
// do redirect if we are not already on step 2
|
|
if (window.location.href.indexOf('step=2') == -1) {{
|
|
setTimeout(doRedirect(), 1000);
|
|
}}
|
|
</script>
|
|
</body>
|
|
</html>
|
|
'''
|
|
|
|
|
|
# https://github.com/fuzzysteve/CREST-Market-Downloader/
|
|
class AuthHandler(http.server.BaseHTTPRequestHandler):
|
|
def do_GET(self):
|
|
if self.path == "/favicon.ico":
|
|
return
|
|
|
|
parsed_path = urllib.parse.urlparse(self.path)
|
|
parts = urllib.parse.parse_qs(parsed_path.query)
|
|
msg = ""
|
|
|
|
step2 = 'step' in parts
|
|
|
|
try:
|
|
if step2:
|
|
self.server.callback(parts)
|
|
pyfalog.info("Successfully logged into CREST.")
|
|
msg = "If you see this message then it means you should be logged into CREST. You may close this window and return to the application."
|
|
else:
|
|
# For implicit mode, we have to serve up the page which will take the hash and redirect useing a querystring
|
|
pyfalog.info("Processing response from EVE Online.")
|
|
msg = "Processing response from EVE Online"
|
|
except Exception as ex:
|
|
pyfalog.error("Error in CREST AuthHandler")
|
|
pyfalog.error(ex)
|
|
msg = "<h2>Error</h2>\n<p>{}</p>".format(ex.message)
|
|
finally:
|
|
self.send_response(200)
|
|
self.end_headers()
|
|
self.wfile.write(HTML.format(msg))
|
|
|
|
if step2:
|
|
# Only stop once if we've received something in the querystring
|
|
self.server.stop()
|
|
|
|
def log_message(self, format, *args):
|
|
return
|
|
|
|
|
|
# http://code.activestate.com/recipes/425210-simple-stoppable-server-using-socket-timeout/
|
|
class StoppableHTTPServer(http.server.HTTPServer):
|
|
def server_bind(self):
|
|
http.server.HTTPServer.server_bind(self)
|
|
self.settings = CRESTSettings.getInstance()
|
|
|
|
# Allow listening for x seconds
|
|
sec = self.settings.get('timeout')
|
|
pyfalog.debug("Running server for {0} seconds", sec)
|
|
|
|
self.socket.settimeout(1)
|
|
self.max_tries = sec / self.socket.gettimeout()
|
|
self.tries = 0
|
|
self.run = True
|
|
|
|
def get_request(self):
|
|
while self.run:
|
|
try:
|
|
sock, addr = self.socket.accept()
|
|
sock.settimeout(None)
|
|
return sock, addr
|
|
except socket.timeout:
|
|
pyfalog.warning("Server timed out waiting for connection")
|
|
pass
|
|
|
|
def stop(self):
|
|
pyfalog.warning("Setting CREST server to stop.")
|
|
self.run = False
|
|
|
|
def handle_timeout(self):
|
|
pyfalog.debug("Number of tries: {0}", self.tries)
|
|
self.tries += 1
|
|
if self.tries == self.max_tries:
|
|
pyfalog.debug("Server timed out waiting for connection")
|
|
self.stop()
|
|
|
|
def serve(self, callback=None):
|
|
self.callback = callback
|
|
while self.run:
|
|
try:
|
|
self.handle_request()
|
|
except TypeError:
|
|
pyfalog.debug("Caught exception in serve")
|
|
pass
|
|
|
|
self.server_close()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
httpd = StoppableHTTPServer(('', 6461), AuthHandler)
|
|
t = threading.Thread(target=httpd.serve)
|
|
input("Press <RETURN> to stop server\n")
|
|
httpd.stop()
|