Small status changes

This commit is contained in:
Ruben van de Ven 2019-11-01 17:02:38 +01:00
parent b3a73d6ea9
commit 9aee12decd
4 changed files with 75 additions and 22 deletions

View file

@ -5,7 +5,7 @@ Webserver is published to the web trough ssh remote forward. In /etc/ssh/sshd_co
Then start `autossh` to maintain the connection: Then start `autossh` to maintain the connection:
```bash ```bash
autossh -M 0 -o "ServerAliveInterval 30" -o "ServerAliveCountMax 3" -R 8888:localhost:8888 here.rubenvandeven.com autossh -M 0 -o "ServerAliveInterval 30" -o "ServerAliveCountMax 3" -R 8127:localhost:8888 here.rubenvandeven.com
``` ```
@ -59,3 +59,32 @@ sudo udevadm control --reload-rules && sudo udevadm trigger
``` ```
## Apache on here.rubenvandeven.com
Unfortunately an SSH remote port-forward does change the ip of the requester into ::1/127.0.0.1. One solution would be to run a proxy on the server itself, which forwards a port to our server port, while adding a X-Forwarded-For header.
Example of apache host setup to forward remote port 8888 to local port 8127, to which we connect our (auto)ssh remote tunnel (see above).
```
Listen 8888
<VirtualHost *:8888>
Servername here.rubenvandeven.com
RewriteEngine On
RewriteCond %{HTTP:Upgrade} =websocket [NC]
RewriteRule /(.*) ws://localhost:8127/$1 [P,L]
RewriteCond %{HTTP:Upgrade} !=websocket [NC]
RewriteRule /(.*) http://localhost:8127/$1 [P,L]
ProxyPass / http://localhost:8127/
ProxyPassReverse / http://localhost:8127/
ProxyPreserveHost On
</VirtualHost>
```
requires `a2enmod rewrite proxy proxy_http proxy_wstunnel`

View file

@ -90,6 +90,8 @@ class Store:
self.Session = sessionmaker(bind=self.engine) self.Session = sessionmaker(bind=self.engine)
self.session = self.Session() self.session = self.Session()
self.currentHit = None # mirrors Centralmanagmenet, stored here so we can quickly access it from webserver classes
@contextmanager @contextmanager
def getSession(self): def getSession(self):
"""Provide a transactional scope around a series of operations.""" """Provide a transactional scope around a series of operations."""

View file

@ -151,12 +151,12 @@ class CentralManagement():
self.currentHit.open_page_at = datetime.datetime.utcnow() self.currentHit.open_page_at = datetime.datetime.utcnow()
self.store.saveHIT(self.currentHit) self.store.saveHIT(self.currentHit)
self.setLight(True) self.setLight(True)
self.server.statusPage.set('state', self.currentHit.getStatus())
elif signal.name == 'server.submit': elif signal.name == 'server.submit':
self.currentHit.submit_page_at = datetime.datetime.utcnow() self.currentHit.submit_page_at = datetime.datetime.utcnow()
self.store.saveHIT(self.currentHit) self.store.saveHIT(self.currentHit)
self.plotter.park() self.plotter.park()
self.setLight(False) self.server.statusPage.set('state', self.currentHit.getStatus())
# park always triggers a plotter.finished after being processed # park always triggers a plotter.finished after being processed
elif signal.name[:4] == 'sqs.': elif signal.name[:4] == 'sqs.':
@ -210,6 +210,7 @@ class CentralManagement():
self.server.statusPage.set('state', sqsHit.getStatus()) self.server.statusPage.set('state', sqsHit.getStatus())
elif signal.name == 'plotter.finished': elif signal.name == 'plotter.finished':
if self.currentHit.submit_page_at: if self.currentHit.submit_page_at:
self.setLight(False)
scan = threading.Thread(target=self.scanImage, name='scan') scan = threading.Thread(target=self.scanImage, name='scan')
scan.start() scan.start()
else: else:
@ -219,6 +220,7 @@ class CentralManagement():
def makeHit(self): def makeHit(self):
self.server.statusPage.reset() self.server.statusPage.reset()
self.currentHit = self.store.createHIT() self.currentHit = self.store.createHIT()
self.store.currentHit = self.currentHit
self.logger.info(f"Make HIT {self.currentHit.id}") self.logger.info(f"Make HIT {self.currentHit.id}")

View file

@ -39,12 +39,11 @@ class WebSocketHandler(tornado.websocket.WebSocketHandler):
CORS_ORIGINS = ['localhost', '.mturk.com', 'here.rubenvandeven.com'] CORS_ORIGINS = ['localhost', '.mturk.com', 'here.rubenvandeven.com']
connections = set() connections = set()
def initialize(self, config, plotterQ: Queue, eventQ: Queue, store: HITStore, geoip_reader: geoip2.database.Reader): def initialize(self, config, plotterQ: Queue, eventQ: Queue, store: HITStore):
self.config = config self.config = config
self.plotterQ = plotterQ self.plotterQ = plotterQ
self.eventQ = eventQ self.eventQ = eventQ
self.store = store self.store = store
self.geoip_reader = geoip_reader
def check_origin(self, origin): def check_origin(self, origin):
parsed_origin = urlparse(origin) parsed_origin = urlparse(origin)
@ -55,14 +54,17 @@ class WebSocketHandler(tornado.websocket.WebSocketHandler):
# the client connected # the client connected
def open(self, p = None): def open(self, p = None):
self.__class__.connections.add(self) self.__class__.connections.add(self)
hit_id = self.get_query_argument('id') hit_id = int(self.get_query_argument('id'))
self.hit = self.store.getHitById(hit_id) if hit_id != self.store.currentHit.id:
self.close()
return
self.hit = self.store.currentHit
if self.hit.submit_hit_at: if self.hit.submit_hit_at:
raise Exception("Opening websocket for already submitted hit") raise Exception("Opening websocket for already submitted hit")
logger.info(f"New client connected: {self.request.remote_ip} for {self.hit.id}/{self.hit.hit_id}") #logger.info(f"New client connected: {self.request.remote_ip} for {self.hit.id}/{self.hit.hit_id}")
self.eventQ.put(Signal('hit.info', dict(hit_id=self.hit.id, ip=self.request.remote_ip)))
self.eventQ.put(Signal('server.open', dict(hit_id=self.hit.id))) self.eventQ.put(Signal('server.open', dict(hit_id=self.hit.id)))
self.strokes = [] self.strokes = []
@ -71,14 +73,7 @@ class WebSocketHandler(tornado.websocket.WebSocketHandler):
if ua: if ua:
ua_info = httpagentparser.detect(ua) ua_info = httpagentparser.detect(ua)
self.eventQ.put(Signal('hit.info', dict(hit_id=self.hit.id, os=ua_info['os']['name'], browser=ua_info['browser']['name']))) self.eventQ.put(Signal('hit.info', dict(hit_id=self.hit.id, os=ua_info['os']['name'], browser=ua_info['browser']['name'])))
try:
geoip = self.geoip_reader.country(self.request.remote_ip)
logger.info(f"Geo {geoip}")
self.eventQ.put(Signal('hit.info', dict(hit_id=self.hit.id, location=geoip.country.name)))
except Exception as e:
logger.exception(e)
logger.info("No geo IP possible")
self.eventQ.put(Signal('hit.info', dict(hit_id=self.hit.id, location='Unknown')))
# self.write_message("hello!") # self.write_message("hello!")
# the client sent the message # the client sent the message
@ -109,6 +104,7 @@ class WebSocketHandler(tornado.websocket.WebSocketHandler):
'action': 'submitted', 'action': 'submitted',
'msg': f"Submission ok, please refer to your submission as: {self.hit.uuid}" 'msg': f"Submission ok, please refer to your submission as: {self.hit.uuid}"
})) }))
self.close()
elif msg['action'] == 'down': elif msg['action'] == 'down':
# not used, implicit in move? # not used, implicit in move?
@ -233,7 +229,7 @@ def strokes2D(strokes):
return d; return d;
class DrawPageHandler(tornado.web.RequestHandler): class DrawPageHandler(tornado.web.RequestHandler):
def initialize(self, store: HITStore, path: str, width: int, height: int, draw_width: int, draw_height: int, top_padding: int, left_padding: int): def initialize(self, store: HITStore, eventQ: Queue, path: str, width: int, height: int, draw_width: int, draw_height: int, top_padding: int, left_padding: int, geoip_reader: geoip2.database.Reader):
self.store = store self.store = store
self.path = path self.path = path
self.width = width self.width = width
@ -242,11 +238,16 @@ class DrawPageHandler(tornado.web.RequestHandler):
self.draw_height = draw_height self.draw_height = draw_height
self.top_padding = top_padding self.top_padding = top_padding
self.left_padding = left_padding self.left_padding = left_padding
self.eventQ = eventQ
self.geoip_reader = geoip_reader
def get(self): def get(self):
try: try:
hit_id = self.get_query_argument('id') hit_id = int(self.get_query_argument('id'))
hit = self.store.getHitById(hit_id) if hit_id != self.store.currentHit.id:
self.write("Invalid HIT")
return
hit = self.store.currentHit
except Exception: except Exception:
self.write("HIT not found") self.write("HIT not found")
else: else:
@ -274,6 +275,24 @@ class DrawPageHandler(tornado.web.RequestHandler):
.replace("{LEFT_PADDING}", str(self.left_padding)) .replace("{LEFT_PADDING}", str(self.left_padding))
self.write(contents) self.write(contents)
if 'X-Forwarded-For' in self.request.headers:
ip = self.request.headers['X-Forwarded-For']
else:
ip = self.request.remote_ip
logger.info(f"Request from {ip}")
self.eventQ.put(Signal('hit.info', dict(hit_id=hit.id, ip=ip)))
try:
geoip = self.geoip_reader.country(ip)
logger.info(f"Geo {geoip}")
self.eventQ.put(Signal('hit.info', dict(hit_id=hit.id, location=geoip.country.name)))
except Exception as e:
logger.exception(e)
logger.info("No geo IP possible")
self.eventQ.put(Signal('hit.info', dict(hit_id=hit.id, location='Unknown')))
class BackendHandler(tornado.web.RequestHandler): class BackendHandler(tornado.web.RequestHandler):
def initialize(self, store: HITStore, path: str): def initialize(self, store: HITStore, path: str):
self.store = store self.store = store
@ -385,19 +404,20 @@ class Server:
'plotterQ': self.plotterQ, 'plotterQ': self.plotterQ,
'eventQ': self.eventQ, 'eventQ': self.eventQ,
'store': self.store, 'store': self.store,
'geoip_reader': self.geoip_reader
}), }),
(r"/status/ws", StatusWebSocketHandler), (r"/status/ws", StatusWebSocketHandler),
(r"/draw", DrawPageHandler, (r"/draw", DrawPageHandler,
dict( dict(
store = self.store, store = self.store,
eventQ = self.eventQ,
path=self.web_root, path=self.web_root,
width=self.config['scanner']['width'], width=self.config['scanner']['width'],
height=self.config['scanner']['height'], height=self.config['scanner']['height'],
draw_width=self.config['scanner']['draw_width'], draw_width=self.config['scanner']['draw_width'],
draw_height=self.config['scanner']['draw_height'], draw_height=self.config['scanner']['draw_height'],
top_padding=self.config['scanner']['top_padding'], top_padding=self.config['scanner']['top_padding'],
left_padding=self.config['scanner']['left_padding'] left_padding=self.config['scanner']['left_padding'],
geoip_reader= self.geoip_reader
)), )),
(r"/backend", BackendHandler, (r"/backend", BackendHandler,
dict( dict(