Used by Client to keep the session open. OPCUA defines timeout both for sessions and secure channel
| 30 | |
| 31 | |
| 32 | class KeepAlive(Thread): |
| 33 | |
| 34 | """ |
| 35 | Used by Client to keep the session open. |
| 36 | OPCUA defines timeout both for sessions and secure channel |
| 37 | """ |
| 38 | |
| 39 | def __init__(self, client, timeout): |
| 40 | """ |
| 41 | :param session_timeout: Timeout to re-new the session |
| 42 | in milliseconds. |
| 43 | """ |
| 44 | Thread.__init__(self) |
| 45 | _logger = logging.getLogger(__name__) |
| 46 | |
| 47 | self.client = client |
| 48 | self._dostop = False |
| 49 | self._cond = Condition() |
| 50 | self.timeout = timeout |
| 51 | |
| 52 | # some server support no timeout, but we do not trust them |
| 53 | if self.timeout == 0: |
| 54 | self.timeout = 3600000 # 1 hour |
| 55 | |
| 56 | def run(self): |
| 57 | _logger.debug("starting keepalive thread with period of %s milliseconds", self.timeout) |
| 58 | server_state = self.client.get_node(ua.FourByteNodeId(ua.ObjectIds.Server_ServerStatus_State)) |
| 59 | while not self._dostop: |
| 60 | with self._cond: |
| 61 | self._cond.wait(self.timeout / 1000) |
| 62 | if self._dostop: |
| 63 | break |
| 64 | _logger.debug("renewing channel") |
| 65 | try: |
| 66 | self.client.open_secure_channel(renew=True) |
| 67 | except concurrent.futures.TimeoutError: |
| 68 | _logger.debug("keepalive failed: timeout on open_secure_channel()") |
| 69 | break |
| 70 | val = server_state.get_value() |
| 71 | _logger.debug("server state is: %s ", val) |
| 72 | _logger.debug("keepalive thread has stopped") |
| 73 | |
| 74 | def stop(self): |
| 75 | _logger.debug("stoping keepalive thread") |
| 76 | self._dostop = True |
| 77 | with self._cond: |
| 78 | self._cond.notify_all() |
| 79 | |
| 80 | |
| 81 | class Client(object): |