diff -r ddb2c4668a6b -r f5da343b9b63 svghmi/svghmi_server.py --- a/svghmi/svghmi_server.py Tue Oct 15 17:14:48 2019 +0200 +++ b/svghmi/svghmi_server.py Thu Oct 17 15:48:09 2019 +0200 @@ -6,6 +6,7 @@ # See COPYING file for copyrights details. from __future__ import absolute_import +import errno from twisted.web.server import Site from twisted.web.resource import Resource @@ -13,6 +14,7 @@ from twisted.web.static import File from autobahn.twisted.websocket import WebSocketServerFactory, WebSocketServerProtocol +from autobahn.websocket.protocol import WebSocketProtocol from autobahn.twisted.resource import WebSocketResource # TODO multiclient : @@ -25,7 +27,7 @@ svghmi_send_collect.restype = ctypes.c_int # error or 0 svghmi_send_collect.argtypes = [ ctypes.POINTER(ctypes.c_uint32), # size - ctypes.POINTER(ctypes.c_char_p)] # data ptr + ctypes.POINTER(ctypes.c_void_p)] # data ptr # TODO multiclient : switch to arrays svghmi_recv_dispatch = PLCBinary.svghmi_recv_dispatch @@ -38,10 +40,11 @@ class HMISession(object): def __init__(self, protocol_instance): global svghmi_session - - # TODO: kill existing session for robustness - assert(svghmi_session is None) - + + # Single client : + # Creating a new HMISession closes pre-existing HMISession + if svghmi_session is not None: + svghmi_session.close() svghmi_session = self self.protocol_instance = protocol_instance @@ -50,13 +53,11 @@ # get a unique bit index amont other svghmi_sessions, # so that we can match flags passed by C->python callback - def __del__(self): + def close(self): global svghmi_session - assert(svghmi_session) - svghmi_session = None - - # TODO multiclient : - # svghmi_sessions.remove(self) + if svghmi_session == self: + svghmi_session = None + self.protocol_instance.sendClose(WebSocketProtocol.CLOSE_STATUS_CODE_NORMAL) def onMessage(self, msg): # pass message to the C side recieve_message() @@ -66,7 +67,8 @@ def sendMessage(self, msg): - self.sendMessage(msg, True) + self.protocol_instance.sendMessage(msg, True) + return 0 class HMIProtocol(WebSocketServerProtocol): @@ -75,18 +77,15 @@ WebSocketServerProtocol.__init__(self, *args, **kwargs) def onOpen(self): + assert(self._hmi_session is None) self._hmi_session = HMISession(self) - print "open" def onClose(self, wasClean, code, reason): - del self._hmi_session self._hmi_session = None - print "close" def onMessage(self, msg, isBinary): + assert(self._hmi_session is not None) self._hmi_session.onMessage(msg) - # print msg - #self.sendMessage(msg, binary) class HMIWebSocketServerFactory(WebSocketServerFactory): protocol = HMIProtocol @@ -98,14 +97,17 @@ def SendThreadProc(): global svghmi_session size = ctypes.c_uint32() - ptr = ctypes.c_char_p() + ptr = ctypes.c_void_p() res = 0 - while svghmi_send_collect(ctypes.byref(size), ctypes.byref(ptr)) == 0 and \ - svghmi_session is not None and \ - svghmi_session.sendMessage(ctypes.string_at(ptr,size)) == 0: - pass + while True: + res=svghmi_send_collect(ctypes.byref(size), ctypes.byref(ptr)) + if res == 0: + # TODO multiclient : dispatch to sessions + if svghmi_session is not None: + svghmi_session.sendMessage(ctypes.string_at(ptr.value,size.value)) + elif res not in [errno.EAGAIN, errno.ENODATA]: + break - # TODO multiclient : dispatch to sessions @@ -125,7 +127,9 @@ # Called by PLCObject at stop def _runtime_svghmi0_stop(): - global svghmi_listener, svghmi_root, svghmi_send_thread + global svghmi_listener, svghmi_root, svghmi_send_thread, svghmi_session + if svghmi_session is not None: + svghmi_session.close() svghmi_root.delEntity("ws") svghmi_root = None svghmi_listener.stopListening()