runtime/NevowServer.py
changeset 2279 70143c20d2c0
parent 2260 74205edac761
child 2262 4195545e2d17
equal deleted inserted replaced
2278:a3ac46366b86 2279:70143c20d2c0
    24 
    24 
    25 
    25 
    26 from __future__ import absolute_import
    26 from __future__ import absolute_import
    27 from __future__ import print_function
    27 from __future__ import print_function
    28 import os
    28 import os
    29 from nevow import appserver, inevow, tags, loaders, athena
    29 import platform as platform_module
       
    30 from zope.interface import implements
       
    31 from nevow import appserver, inevow, tags, loaders, athena, url, rend
    30 from nevow.page import renderer
    32 from nevow.page import renderer
       
    33 from formless import annotate
       
    34 from formless import webform
       
    35 from formless import configurable
    31 from twisted.internet import reactor
    36 from twisted.internet import reactor
       
    37 
    32 import util.paths as paths
    38 import util.paths as paths
       
    39 from runtime.loglevels import LogLevels, LogLevelsDict
       
    40 
       
    41 PAGE_TITLE = 'Beremiz Runtime Web Interface'
    33 
    42 
    34 xhtml_header = '''<?xml version="1.0" encoding="utf-8"?>
    43 xhtml_header = '''<?xml version="1.0" encoding="utf-8"?>
    35 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
    44 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
    36 "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
    45 "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
    37 '''
    46 '''
    38 
    47 
    39 WorkingDir = None
    48 WorkingDir = None
       
    49 _PySrv = None
    40 
    50 
    41 
    51 
    42 class PLCHMI(athena.LiveElement):
    52 class PLCHMI(athena.LiveElement):
    43 
    53 
    44     initialised = False
    54     initialised = False
   118     def detachFragmentChildren(self):
   128     def detachFragmentChildren(self):
   119         for child in self.liveFragmentChildren[:]:
   129         for child in self.liveFragmentChildren[:]:
   120             child.detach()
   130             child.detach()
   121 
   131 
   122 
   132 
       
   133 class ConfigurableBindings(configurable.Configurable):
       
   134 
       
   135     def __init__(self):
       
   136         configurable.Configurable.__init__(self, None)
       
   137         self.bindingsNames = []
       
   138 
       
   139     def getBindingNames(self, ctx):
       
   140         return self.bindingsNames
       
   141 
       
   142     def addExtension(self, name, desc, fields, btnlabel, callback):
       
   143         def _bind(ctx):
       
   144             return annotate.MethodBinding(
       
   145                 'action_' + name,
       
   146                 annotate.Method(
       
   147                     arguments=[
       
   148                         annotate.Argument(*field)
       
   149                         for field in fields],
       
   150                     label=desc),
       
   151                 action=btnlabel)
       
   152         setattr(self, 'bind_' + name, _bind)
       
   153 
       
   154         setattr(self, 'action_' + name, callback)
       
   155 
       
   156         self.bindingsNames.append(name)
       
   157 
       
   158 
       
   159 ConfigurableSettings = ConfigurableBindings()
       
   160 
       
   161 
       
   162 class ISettings(annotate.TypedInterface):
       
   163     platform = annotate.String(label=_("Platform"),
       
   164                                default=platform_module.system() +
       
   165                                " " + platform_module.release(),
       
   166                                immutable=True)
       
   167 
       
   168     # TODO version ?
       
   169 
       
   170     # pylint: disable=no-self-argument
       
   171     def sendLogMessage(
       
   172             ctx=annotate.Context(),
       
   173             level=annotate.Choice(LogLevels,
       
   174                                   required=True,
       
   175                                   label=_("Log message level")),
       
   176             message=annotate.String(label=_("Message text"))):
       
   177         pass
       
   178 
       
   179     sendLogMessage = annotate.autocallable(sendLogMessage,
       
   180                                            label=_(
       
   181                                                "Send a message to the log"),
       
   182                                            action=_("Send"))
       
   183 
       
   184 
       
   185 customSettingsURLs = {
       
   186 }
       
   187 
       
   188 
       
   189 class SettingsPage(rend.Page):
       
   190     # We deserve a slash
       
   191     addSlash = True
       
   192 
       
   193     # This makes webform_css url answer some default CSS
       
   194     child_webform_css = webform.defaultCSS
       
   195 
       
   196     implements(ISettings)
       
   197 
       
   198     docFactory = loaders.stan([
       
   199         tags.html[
       
   200             tags.head[
       
   201                 tags.title[_("Beremiz Runtime Settings")],
       
   202                 tags.link(rel='stylesheet',
       
   203                           type='text/css',
       
   204                           href=url.here.child("webform_css"))
       
   205             ],
       
   206             tags.body[
       
   207                 tags.h1["Runtime settings:"],
       
   208                 webform.renderForms('staticSettings'),
       
   209                 tags.h2["Extensions settings:"],
       
   210                 webform.renderForms('dynamicSettings'),
       
   211             ]
       
   212         ]
       
   213     ])
       
   214 
       
   215     def configurable_staticSettings(self, ctx):
       
   216         return configurable.TypedInterfaceConfigurable(self)
       
   217 
       
   218     def configurable_dynamicSettings(self, ctx):
       
   219         return ConfigurableSettings
       
   220 
       
   221     def sendLogMessage(self, level, message, **kwargs):
       
   222         level = LogLevelsDict[level]
       
   223         if _PySrv.plcobj is not None:
       
   224             _PySrv.plcobj.LogMessage(
       
   225                 level, "Web form log message: " + message)
       
   226 
       
   227     def locateChild(self, ctx, segments):
       
   228         if segments[0] in customSettingsURLs:
       
   229             return customSettingsURLs[segments[0]](ctx, segments)
       
   230         return super(SettingsPage, self).locateChild(ctx, segments)
       
   231 
       
   232 
   123 class WebInterface(athena.LivePage):
   233 class WebInterface(athena.LivePage):
   124 
   234 
   125     docFactory = loaders.stan([tags.raw(xhtml_header),
   235     docFactory = loaders.stan([tags.raw(xhtml_header),
   126                                tags.html(xmlns="http://www.w3.org/1999/xhtml")[
   236                                tags.html(xmlns="http://www.w3.org/1999/xhtml")[
   127                                    tags.head(render=tags.directive('liveglue')),
   237                                    tags.head(render=tags.directive('liveglue'))[
       
   238                                        tags.title[PAGE_TITLE],
       
   239                                        tags.link(rel='stylesheet',
       
   240                                                  type='text/css',
       
   241                                                  href=url.here.child("webform_css"))
       
   242                                    ],
   128                                    tags.body[
   243                                    tags.body[
   129                                        tags.div[
   244                                        tags.div[
   130                                            tags.div(render=tags.directive("MainPage"))
   245                                            tags.div(
       
   246                                                render=tags.directive(
       
   247                                                    "MainPage")),
   131                                        ]]]])
   248                                        ]]]])
   132     MainPage = MainPage()
   249     MainPage = MainPage()
   133     PLCHMI = PLCHMI
   250     PLCHMI = PLCHMI
   134 
   251 
       
   252     def child_settings(self, context):
       
   253         return SettingsPage()
       
   254 
   135     def __init__(self, plcState=False, *a, **kw):
   255     def __init__(self, plcState=False, *a, **kw):
   136         super(WebInterface, self).__init__(*a, **kw)
   256         super(WebInterface, self).__init__(*a, **kw)
   137         self.jsModules.mapping[u'WebInterface'] = paths.AbsNeighbourFile(__file__, 'webinterface.js')
   257         self.jsModules.mapping[u'WebInterface'] = paths.AbsNeighbourFile(
       
   258             __file__, 'webinterface.js')
   138         self.plcState = plcState
   259         self.plcState = plcState
   139         self.MainPage.setPLCState(plcState)
   260         self.MainPage.setPLCState(plcState)
   140 
   261 
   141     def getHMI(self):
   262     def getHMI(self):
   142         return self.MainPage.getHMI()
   263         return self.MainPage.getHMI()
   192     print(_('HTTP interface port :'), port)
   313     print(_('HTTP interface port :'), port)
   193     return website
   314     return website
   194 
   315 
   195 
   316 
   196 class statuslistener(object):
   317 class statuslistener(object):
       
   318 
   197     def __init__(self, site):
   319     def __init__(self, site):
   198         self.oldstate = None
   320         self.oldstate = None
   199         self.site = site
   321         self.site = site
   200 
   322 
   201     def listen(self, state):
   323     def listen(self, state):
   207             self.oldstate = state
   329             self.oldstate = state
   208 
   330 
   209 
   331 
   210 def website_statuslistener_factory(site):
   332 def website_statuslistener_factory(site):
   211     return statuslistener(site).listen
   333     return statuslistener(site).listen
       
   334 
       
   335 
       
   336 def SetServer(pysrv):
       
   337     global _PySrv
       
   338     _PySrv = pysrv