--- a/runtime/NevowServer.py Fri Aug 10 17:45:33 2018 +0300
+++ b/runtime/NevowServer.py Fri Aug 10 18:07:38 2018 +0300
@@ -26,10 +26,19 @@
from __future__ import absolute_import
from __future__ import print_function
import os
-from nevow import appserver, inevow, tags, loaders, athena
+import platform as platform_module
+from zope.interface import implements
+from nevow import appserver, inevow, tags, loaders, athena, url, rend
from nevow.page import renderer
+from formless import annotate
+from formless import webform
+from formless import configurable
from twisted.internet import reactor
+
import util.paths as paths
+from runtime.loglevels import LogLevels, LogLevelsDict
+
+PAGE_TITLE = 'Beremiz Runtime Web Interface'
xhtml_header = '''<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
@@ -37,6 +46,7 @@
'''
WorkingDir = None
+_PySrv = None
class PLCHMI(athena.LiveElement):
@@ -120,21 +130,132 @@
child.detach()
+class ConfigurableBindings(configurable.Configurable):
+
+ def __init__(self):
+ configurable.Configurable.__init__(self, None)
+ self.bindingsNames = []
+
+ def getBindingNames(self, ctx):
+ return self.bindingsNames
+
+ def addExtension(self, name, desc, fields, btnlabel, callback):
+ def _bind(ctx):
+ return annotate.MethodBinding(
+ 'action_' + name,
+ annotate.Method(
+ arguments=[
+ annotate.Argument(*field)
+ for field in fields],
+ label=desc),
+ action=btnlabel)
+ setattr(self, 'bind_' + name, _bind)
+
+ setattr(self, 'action_' + name, callback)
+
+ self.bindingsNames.append(name)
+
+
+ConfigurableSettings = ConfigurableBindings()
+
+
+class ISettings(annotate.TypedInterface):
+ platform = annotate.String(label=_("Platform"),
+ default=platform_module.system() +
+ " " + platform_module.release(),
+ immutable=True)
+
+ # TODO version ?
+
+ # pylint: disable=no-self-argument
+ def sendLogMessage(
+ ctx=annotate.Context(),
+ level=annotate.Choice(LogLevels,
+ required=True,
+ label=_("Log message level")),
+ message=annotate.String(label=_("Message text"))):
+ pass
+
+ sendLogMessage = annotate.autocallable(sendLogMessage,
+ label=_(
+ "Send a message to the log"),
+ action=_("Send"))
+
+
+customSettingsURLs = {
+}
+
+
+class SettingsPage(rend.Page):
+ # We deserve a slash
+ addSlash = True
+
+ # This makes webform_css url answer some default CSS
+ child_webform_css = webform.defaultCSS
+
+ implements(ISettings)
+
+ docFactory = loaders.stan([
+ tags.html[
+ tags.head[
+ tags.title[_("Beremiz Runtime Settings")],
+ tags.link(rel='stylesheet',
+ type='text/css',
+ href=url.here.child("webform_css"))
+ ],
+ tags.body[
+ tags.h1["Runtime settings:"],
+ webform.renderForms('staticSettings'),
+ tags.h2["Extensions settings:"],
+ webform.renderForms('dynamicSettings'),
+ ]
+ ]
+ ])
+
+ def configurable_staticSettings(self, ctx):
+ return configurable.TypedInterfaceConfigurable(self)
+
+ def configurable_dynamicSettings(self, ctx):
+ return ConfigurableSettings
+
+ def sendLogMessage(self, level, message, **kwargs):
+ level = LogLevelsDict[level]
+ if _PySrv.plcobj is not None:
+ _PySrv.plcobj.LogMessage(
+ level, "Web form log message: " + message)
+
+ def locateChild(self, ctx, segments):
+ if segments[0] in customSettingsURLs:
+ return customSettingsURLs[segments[0]](ctx, segments)
+ return super(SettingsPage, self).locateChild(ctx, segments)
+
+
class WebInterface(athena.LivePage):
docFactory = loaders.stan([tags.raw(xhtml_header),
tags.html(xmlns="http://www.w3.org/1999/xhtml")[
- tags.head(render=tags.directive('liveglue')),
+ tags.head(render=tags.directive('liveglue'))[
+ tags.title[PAGE_TITLE],
+ tags.link(rel='stylesheet',
+ type='text/css',
+ href=url.here.child("webform_css"))
+ ],
tags.body[
tags.div[
- tags.div(render=tags.directive("MainPage"))
+ tags.div(
+ render=tags.directive(
+ "MainPage")),
]]]])
MainPage = MainPage()
PLCHMI = PLCHMI
+ def child_settings(self, context):
+ return SettingsPage()
+
def __init__(self, plcState=False, *a, **kw):
super(WebInterface, self).__init__(*a, **kw)
- self.jsModules.mapping[u'WebInterface'] = paths.AbsNeighbourFile(__file__, 'webinterface.js')
+ self.jsModules.mapping[u'WebInterface'] = paths.AbsNeighbourFile(
+ __file__, 'webinterface.js')
self.plcState = plcState
self.MainPage.setPLCState(plcState)
@@ -194,6 +315,7 @@
class statuslistener(object):
+
def __init__(self, site):
self.oldstate = None
self.site = site
@@ -209,3 +331,8 @@
def website_statuslistener_factory(site):
return statuslistener(site).listen
+
+
+def SetServer(pysrv):
+ global _PySrv
+ _PySrv = pysrv