comparison src/server/server.py @ 995:f88325b56a6a

server: dynamic pages first draft: /!\ new dependency: autobahn This patch introduce server part of dynamic pages. Dynamic pages use websockets to establish constant connection with a Libervia page, allowing to receive real time data or update it. The feature is activated by specifying "dynamic = true" in the page. Once activated, page can implement "on_data" method which will be called when data are sent by the page. To send data the other way, the page can use request.sendData. The new "registerSignal" method allows to use an "on_signal" method to be called each time given signal is received, with automatic (and optional) filtering on profile. New renderPartial and renderAndUpdate method allow to append new HTML elements to the dynamic page.
author Goffi <goffi@goffi.org>
date Wed, 03 Jan 2018 01:10:12 +0100
parents 6daa59d44ee2
children 05cc33d8e328
comparison
equal deleted inserted replaced
994:b92b06f023cb 995:f88325b56a6a
49 import uuid 49 import uuid
50 import urlparse 50 import urlparse
51 import urllib 51 import urllib
52 from httplib import HTTPS_PORT 52 from httplib import HTTPS_PORT
53 import libervia 53 import libervia
54 from libervia.server import websockets
54 from libervia.server.pages import LiberviaPage 55 from libervia.server.pages import LiberviaPage
55 from libervia.server.utils import quote 56 from libervia.server.utils import quote
56 from functools import partial 57 from functools import partial
57 58
58 try: 59 try:
828 avatar = yield self.asyncBridgeCall("avatarGet", entity, cache_only, hash_only, profile) 829 avatar = yield self.asyncBridgeCall("avatarGet", entity, cache_only, hash_only, profile)
829 if hash_only: 830 if hash_only:
830 defer.returnValue(avatar) 831 defer.returnValue(avatar)
831 else: 832 else:
832 filename = os.path.basename(avatar) 833 filename = os.path.basename(avatar)
833 avatar_url = os.path.join(C.CACHE_DIR, session_data.uuid, filename) 834 avatar_url = os.path.join(session_data.cache_dir, filename)
834 defer.returnValue(avatar_url) 835 defer.returnValue(avatar_url)
835 836
836 def jsonrpc_getAccountDialogUI(self): 837 def jsonrpc_getAccountDialogUI(self):
837 """Get the dialog for managing user account 838 """Get the dialog for managing user account
838 @return: XML string of the XMLUI""" 839 @return: XML string of the XMLUI"""
1362 profile = session_iface.ISATSession(request.getSession()).profile 1363 profile = session_iface.ISATSession(request.getSession()).profile
1363 return ("setAvatar", filepath, profile) 1364 return ("setAvatar", filepath, profile)
1364 1365
1365 1366
1366 class Libervia(service.Service): 1367 class Libervia(service.Service):
1368 debug = defer.Deferred.debug # True if twistd/Libervia is launched in debug mode
1367 1369
1368 def __init__(self, options): 1370 def __init__(self, options):
1369 self.options = options 1371 self.options = options
1370 self.initialised = defer.Deferred() 1372 self.initialised = defer.Deferred()
1371 self.waiting_profiles = WaitingRequests() # FIXME: should be removed 1373 self.waiting_profiles = WaitingRequests() # FIXME: should be removed
1450 1452
1451 # static pages 1453 # static pages
1452 self.putChild('blog', MicroBlog(self)) 1454 self.putChild('blog', MicroBlog(self))
1453 self.putChild(C.THEMES_URL, ProtectedFile(self.themes_dir)) 1455 self.putChild(C.THEMES_URL, ProtectedFile(self.themes_dir))
1454 1456
1457 # websocket
1458 if self.options['connection_type'] in ('https', 'both'):
1459 wss = websockets.LiberviaPageWSProtocol.getResource(self, secure=True)
1460 self.putChild('wss', wss)
1461 if self.options['connection_type'] in ('http', 'both'):
1462 ws = websockets.LiberviaPageWSProtocol.getResource(self, secure=False)
1463 self.putChild('ws', ws)
1464
1465 # Libervia pages
1455 LiberviaPage.importPages(self) 1466 LiberviaPage.importPages(self)
1456 LiberviaPage.setMenu(self.options['menu_json']) 1467 LiberviaPage.setMenu(self.options['menu_json'])
1468 ## following signal is needed for cache handling in Libervia pages
1457 self.bridge.register_signal("psEventRaw", partial(LiberviaPage.onNodeEvent, self), "plugin") 1469 self.bridge.register_signal("psEventRaw", partial(LiberviaPage.onNodeEvent, self), "plugin")
1470 self.bridge.register_signal("messageNew", partial(LiberviaPage.onSignal, self, "messageNew"))
1458 1471
1459 # media dirs 1472 # media dirs
1460 # FIXME: get rid of dirname and "/" in C.XXX_DIR 1473 # FIXME: get rid of dirname and "/" in C.XXX_DIR
1461 self.putChild(os.path.dirname(C.MEDIA_DIR), ProtectedFile(self.media_dir)) 1474 self.putChild(os.path.dirname(C.MEDIA_DIR), ProtectedFile(self.media_dir))
1462 self.cache_resource = web_resource.NoResource() 1475 self.cache_resource = web_resource.NoResource()
1792 if len(args) == 1: 1805 if len(args) == 1:
1793 return args[0](session) 1806 return args[0](session)
1794 else: 1807 else:
1795 return (iface(session) for iface in args) 1808 return (iface(session) for iface in args)
1796 1809
1810 ## Websocket (dynamic pages) ##
1811
1812 def getWebsocketURL(self, request):
1813 if request.isSecure():
1814 ws = 'wss'
1815 else:
1816 ws = 'ws'
1817
1818 if self.base_url_ext:
1819 base_url = self.base_url_ext
1820 else:
1821 o = self.options
1822 if request.isSecure():
1823 port = o['port_https_ext'] or o['port_https']
1824 else:
1825 port = o['port']
1826 base_url = request.getRequestHostname().decode('utf-8') + u':' + unicode(port)+ u'/'
1827
1828 return u'{ws}://{base_url}{ws}'.format(
1829 ws = ws,
1830 base_url = base_url)
1831
1832 def registerWSToken(self, token, page, request):
1833 websockets.LiberviaPageWSProtocol.registerToken(token, page, request)
1834
1797 ## TLS related methods ## 1835 ## TLS related methods ##
1798 1836
1799 def _TLSOptionsCheck(self): 1837 def _TLSOptionsCheck(self):
1800 """Check options coherence if TLS is activated, and update missing values 1838 """Check options coherence if TLS is activated, and update missing values
1801 1839