44import json
55import socket
66import sys
7+ import typing
8+ import types
9+ import asyncio
710import tornado .concurrent
811import tornado .gen
912import tornado .httpserver
@@ -56,6 +59,39 @@ def options(self, *args, **kwargs):
5659 """Handle an OPTIONS request."""
5760 self .set_status (204 )
5861
62+ async def represent_response (
63+ self , data , content_type : str = "application/json" , headers : dict = None
64+ ):
65+ headers = headers or {}
66+ for k , v in headers :
67+ self .set_header (k , v )
68+
69+ self .set_header ("Content-Type" , content_type )
70+
71+ if isinstance (data , (typing .AsyncGenerator , types .GeneratorType )):
72+ self .set_header (
73+ "Cache-Control" ,
74+ "no-store, no-cache, must-revalidate, pre-check=0, post-check=0, max-age=0" ,
75+ )
76+ self .set_header ("Pragma" , "no-cache" )
77+
78+ if isinstance (data , typing .AsyncGenerator ):
79+ async for frame in data :
80+ # Write data to memory
81+ self .write (frame )
82+ # Write data to network
83+ await self .flush ()
84+ elif isinstance (data , types .GeneratorType ):
85+ for frame in data :
86+ # Write data to memory
87+ self .write (frame )
88+ # Write data to network
89+ await self .flush ()
90+ else :
91+ if content_type == "application/json" :
92+ data = json .dumps (data )
93+ self .write (data )
94+
5995
6096class ThingHandler (tornado .websocket .WebSocketHandler , Subscriber ):
6197 """Handle a request to /."""
@@ -299,7 +335,7 @@ def update_event(self, event):
299335class PropertiesHandler (BaseHandler ):
300336 """Handle a request to /properties."""
301337
302- def get (self ):
338+ async def get (self ):
303339 """
304340 Handle a GET request.
305341 """
@@ -308,13 +344,13 @@ def get(self):
308344 return
309345
310346 self .set_header ("Content-Type" , "application/json" )
311- self .write (json .dumps (self .thing .get_properties ()))
347+ self .write (json .dumps (await self .thing .get_properties ()))
312348
313349
314350class PropertyHandler (BaseHandler ):
315351 """Handle a request to /properties/<property>."""
316352
317- def get (self , property_name = None ):
353+ async def get (self , property_name = None ):
318354 """
319355 Handle a GET request.
320356
@@ -324,13 +360,14 @@ def get(self, property_name=None):
324360 self .set_status (404 )
325361 return
326362
327- if self .thing .has_property (property_name ):
328- self .set_header ("Content-Type" , "application/json" )
329- self .write (json .dumps (self .thing .get_property (property_name )))
363+ prop = self .thing .find_property (property_name )
364+ if prop :
365+ data = await self .thing .get_property (property_name )
366+ await self .represent_response (data , prop .get_content_type ())
330367 else :
331368 self .set_status (404 )
332369
333- def put (self , property_name = None ):
370+ async def put (self , property_name = None ):
334371 """
335372 Handle a PUT request.
336373
@@ -346,20 +383,15 @@ def put(self, property_name=None):
346383 self .set_status (400 )
347384 return
348385
349- if self .thing .has_property (property_name ):
386+ prop = self .thing .find_property (property_name )
387+ if prop :
350388 try :
351- self .thing .set_property (property_name , args )
389+ await self .thing .set_property (property_name , args )
352390 except PropertyError :
353391 self .set_status (400 )
354392 return
355-
356- self .set_header ("Content-Type" , "application/json" )
357- self .write (
358- json .dumps (
359- {
360- property_name : self .thing .get_property (property_name ),
361- }
362- )
393+ await self .represent_response (
394+ await self .thing .get_property (property_name ), prop .get_content_type ()
363395 )
364396 else :
365397 self .set_status (404 )
@@ -368,18 +400,17 @@ def put(self, property_name=None):
368400class ActionsHandler (BaseHandler ):
369401 """Handle a request to /actions."""
370402
371- def get (self ):
403+ async def get (self ):
372404 """
373405 Handle a GET request.
374406 """
375407 if self .thing is None :
376408 self .set_status (404 )
377409 return
378410
379- self .set_header ("Content-Type" , "application/json" )
380- self .write (json .dumps (self .thing .get_action_descriptions ()))
411+ await self .represent_response (self .thing .get_action_descriptions ())
381412
382- def post (self ):
413+ async def post (self ):
383414 """
384415 Handle a POST request.
385416 """
@@ -412,15 +443,15 @@ def post(self):
412443 tornado .ioloop .IOLoop .current ().spawn_callback (action .start )
413444
414445 self .set_status (201 )
415- self .write ( json . dumps ( response ) )
446+ await self .represent_response ( response )
416447 else :
417448 self .set_status (400 )
418449
419450
420451class ActionHandler (BaseHandler ):
421452 """Handle a request to /actions/<action_name>."""
422453
423- def get (self , action_name = None ):
454+ async def get (self , action_name = None ):
424455 """
425456 Handle a GET request.
426457
@@ -430,10 +461,11 @@ def get(self, action_name=None):
430461 self .set_status (404 )
431462 return
432463
433- self .set_header ("Content-Type" , "application/json" )
434- self .write (json .dumps (self .thing .get_action_descriptions (action_name = action_name )))
464+ await self .represent_response (
465+ self .thing .get_action_descriptions (action_name = action_name )
466+ )
435467
436- def post (self , action_name = None ):
468+ async def post (self , action_name = None ):
437469 """
438470 Handle a POST request.
439471 """
@@ -455,15 +487,15 @@ def post(self, action_name=None):
455487 tornado .ioloop .IOLoop .current ().spawn_callback (action .start )
456488
457489 self .set_status (201 )
458- self .write ( json . dumps ( response ) )
490+ await self .represent_response ( response )
459491 else :
460492 self .set_status (400 )
461493
462494
463495class ActionIDHandler (BaseHandler ):
464496 """Handle a request to /actions/<action_name>/<action_id>."""
465497
466- def get (self , action_name = None , action_id = None ):
498+ async def get (self , action_name = None , action_id = None ):
467499 """
468500 Handle a GET request.
469501
@@ -479,10 +511,9 @@ def get(self, action_name=None, action_id=None):
479511 self .set_status (404 )
480512 return
481513
482- self .set_header ("Content-Type" , "application/json" )
483- self .write (json .dumps (action .as_action_description ()))
514+ await self .represent_response (action .as_action_description ())
484515
485- def put (self , action_name = None , action_id = None ):
516+ def put (self , action_name = None , action_id = None ):
486517 """
487518 Handle a PUT request.
488519
@@ -517,22 +548,21 @@ def delete(self, action_name=None, action_id=None):
517548class EventsHandler (BaseHandler ):
518549 """Handle a request to /events."""
519550
520- def get (self ):
551+ async def get (self ):
521552 """
522553 Handle a GET request.
523554 """
524555 if self .thing is None :
525556 self .set_status (404 )
526557 return
527558
528- self .set_header ("Content-Type" , "application/json" )
529- self .write (json .dumps (self .thing .get_event_descriptions ()))
559+ await self .represent_response (self .thing .get_event_descriptions ())
530560
531561
532562class EventHandler (BaseHandler ):
533563 """Handle a request to /events/<event_name>."""
534564
535- def get (self , event_name = None ):
565+ async def get (self , event_name = None ):
536566 """
537567 Handle a GET request.
538568
@@ -542,8 +572,9 @@ def get(self, event_name=None):
542572 self .set_status (404 )
543573 return
544574
545- self .set_header ("Content-Type" , "application/json" )
546- self .write (json .dumps (self .thing .get_event_descriptions (event_name = event_name )))
575+ await self .represent_response (
576+ self .thing .get_event_descriptions (event_name = event_name )
577+ )
547578
548579
549580class WebThingServer :
0 commit comments