Commit ae1ca233201c55a7c7fd6007964a9699192e7c42

Authored by Miguel Barão
1 parent 7f9b7abd
Exists in dev

update running tornado to use asyncio event loop

Showing 2 changed files with 55 additions and 23 deletions   Show diff stats
aprendizations/main.py
... ... @@ -7,6 +7,7 @@ Setup configurations and then runs the application.
7 7  
8 8 # python standard library
9 9 import argparse
  10 +import asyncio
10 11 import logging
11 12 import logging.config
12 13 from os import environ, path
... ... @@ -16,7 +17,7 @@ from typing import Any, Dict
16 17  
17 18 # this project
18 19 from .learnapp import LearnApp, LearnException
19   -from .serve import run_webserver
  20 +from .serve import webserver
20 21 from .tools import load_yaml
21 22 from . import APP_NAME, APP_VERSION
22 23  
... ... @@ -179,17 +180,19 @@ def main():
179 180  
180 181 # --- start application --------------------------------------------------
181 182 try:
182   - learnapp = LearnApp(courses=arg.courses,
183   - prefix=arg.prefix,
184   - dbase=arg.db,
185   - check=arg.check)
  183 + app = LearnApp(courses=arg.courses,
  184 + prefix=arg.prefix,
  185 + dbase=arg.db,
  186 + check=arg.check)
186 187 except LearnException:
187 188 logging.critical('Failed to start application')
188 189 sys.exit(1)
189 190 logging.info('LearnApp started')
190 191  
191 192 # --- run webserver forever ----------------------------------------------
192   - run_webserver(app=learnapp, ssl=ssl_ctx, port=arg.port, debug=arg.debug)
  193 + asyncio.run(webserver(app=app, ssl=ssl_ctx, port=arg.port, debug=arg.debug))
  194 +
  195 + logging.critical('Webserver stopped.')
193 196  
194 197  
195 198 # ----------------------------------------------------------------------------
... ...
aprendizations/serve.py
... ... @@ -4,6 +4,7 @@ Webserver
4 4  
5 5  
6 6 # python standard library
  7 +import asyncio
7 8 import base64
8 9 import functools
9 10 from logging import getLogger
... ... @@ -58,8 +59,9 @@ class WebApplication(tornado.web.Application):
58 59 (r'/rankings', RankingsHandler), # rankings table
59 60 (r'/topic/(.+)', TopicHandler), # start topic
60 61 (r'/file/(.+)', FileHandler), # serve file
61   - (r'/courses', CoursesHandler), # show list of courses
62   - (r'/course/(.*)', CourseHandler), # show course topics
  62 + (r'/courses', CoursesHandler), # show available courses
  63 + (r'/course/(.*)', CourseHandler), # show topics from course
  64 + (r'/course2/(.*)', CourseHandler2), # show topics from course FIXME
63 65 (r'/', RootHandler), # redirects
64 66 ]
65 67 settings = {
... ... @@ -241,9 +243,38 @@ class CoursesHandler(BaseHandler):
241 243  
242 244  
243 245 # ============================================================================
  246 +class CourseHandler2(BaseHandler):
  247 + @tornado.web.authenticated
  248 + def get(self, course_id) -> None:
  249 + '''
  250 + Handles get /course/...
  251 + Starts a given course and show list of topics
  252 + '''
  253 + uid = self.current_user
  254 + logger.debug('[CourseHandler2] uid="%s", course_id="%s"', uid, course_id)
  255 +
  256 + if course_id == '':
  257 + course_id = self.learn.get_current_course_id(uid)
  258 +
  259 + try:
  260 + self.learn.start_course(uid, course_id)
  261 + except LearnException:
  262 + self.redirect('/courses')
  263 +
  264 + # print(self.learn.get_course(course_id))
  265 + self.render('maintopics-table2.html',
  266 + appname=APP_NAME,
  267 + uid=uid,
  268 + name=self.learn.get_student_name(uid),
  269 + state=self.learn.get_student_state(uid),
  270 + course_id=course_id,
  271 + course=self.learn.get_course(course_id)
  272 + )
  273 +
  274 +# ============================================================================
244 275 class CourseHandler(BaseHandler):
245 276 '''
246   - Handles a particular course to show the topics table
  277 + Show topics for a particular course
247 278 '''
248 279  
249 280 @tornado.web.authenticated
... ... @@ -253,6 +284,8 @@ class CourseHandler(BaseHandler):
253 284 Starts a given course and show list of topics
254 285 '''
255 286 uid = self.current_user
  287 + logger.debug('[CourseHandler] uid="%s", course_id="%s"', uid, course_id)
  288 +
256 289 if course_id == '':
257 290 course_id = self.learn.get_current_course_id(uid)
258 291  
... ... @@ -286,7 +319,7 @@ class TopicHandler(BaseHandler):
286 319 Starts a given topic
287 320 '''
288 321 uid = self.current_user
289   - logger.debug('[TopicHandler.get] %s', topic)
  322 + logger.debug('[TopicHandler] %s', topic)
290 323 try:
291 324 await self.learn.start_topic(uid, topic) # FIXME GET should not modify state...
292 325 except KeyError:
... ... @@ -315,8 +348,8 @@ class FileHandler(BaseHandler):
315 348 public_dir = self.learn.get_current_public_dir(uid)
316 349 filepath = expanduser(join(public_dir, filename))
317 350  
318   - logger.debug('uid=%s, public_dir=%s, filepath=%s', uid, public_dir,
319   - filepath)
  351 + logger.debug('[FileHandler] uid=%s, public_dir=%s, filepath=%s',
  352 + uid, public_dir, filepath)
320 353 try:
321 354 with open(filepath, 'rb') as file:
322 355 data = file.read()
... ... @@ -356,7 +389,7 @@ class QuestionHandler(BaseHandler):
356 389 '''
357 390 Get question to render or an animated trophy if no more questions.
358 391 '''
359   - logger.debug('[QuestionHandler.get]')
  392 + logger.debug('[QuestionHandler]')
360 393 user = self.current_user
361 394 question = await self.learn.get_question(user)
362 395  
... ... @@ -396,7 +429,7 @@ class QuestionHandler(BaseHandler):
396 429 user = self.current_user
397 430 answer = self.get_body_arguments('answer') # list
398 431 qid = self.get_body_arguments('qid')[0]
399   - # logger.debug('[QuestionHandler] answer=%s', answer)
  432 + logger.debug('[QuestionHandler] answer=%s', answer)
400 433  
401 434 # --- check if browser opened different questions simultaneously
402 435 if qid != self.learn.get_current_question_id(user):
... ... @@ -486,9 +519,9 @@ def signal_handler(*_) -> None:
486 519  
487 520  
488 521 # ----------------------------------------------------------------------------
489   -def run_webserver(app, ssl, port: int = 8443, debug: bool = False) -> None:
  522 +async def webserver(app, ssl, port: int = 8443, debug: bool = False) -> None:
490 523 '''
491   - Starts and runs webserver until a SIGINT signal (Ctrl-C) is received.
  524 + Runs webserver until a SIGINT signal (Ctrl-C) is received.
492 525 '''
493 526  
494 527 # --- create web application
... ... @@ -517,10 +550,6 @@ def run_webserver(app, ssl, port: int = 8443, debug: bool = False) -> None:
517 550 # --- set signal handler for Control-C
518 551 signal.signal(signal.SIGINT, signal_handler)
519 552  
520   - # --- run tornado webserver
521   - try:
522   - tornado.ioloop.IOLoop.current().start() # running...
523   - except Exception:
524   - logger.critical('Webserver stopped.')
525   - tornado.ioloop.IOLoop.current().stop()
526   - raise
  553 + # --- run event loop (and tornado webserver)
  554 + await asyncio.Event().wait()
  555 +
... ...