Commit acb150c7 authored by Levin Zimmermann's avatar Levin Zimmermann

add basic opcua server

this is a very dirty adhoc approach: we basically build our own asyncua.Server.
parent d630a237
......@@ -250,11 +250,23 @@ def runwsgi():
#
################################################################
import math
# We need asyncio support in twisted because our opcua lib is written with
# asyncio syntax. See https://meejah.ca/blog/python3-twisted-and-asyncio
import asyncio
from twisted.internet import asyncioreactor
asyncioreactor.install(asyncio.get_event_loop())
from twisted.internet.task import react
from twisted.internet.defer import ensureDeferred
from twisted.web.wsgi import WSGIResource
from twisted.internet import protocol, reactor, endpoints
from twisted.web import server as twisted_server
import urllib
import asyncua
from Products.ERP5Type.Log import log
# I modified runwsgi() without thinking carefully.
......@@ -394,6 +406,37 @@ def runwsgitw():
def buildProtocol(self, addr):
return Echo()
class OPCUA(protocol.Protocol, asyncua.server.binary_server_asyncio.OPCUAProtocol):
def __init__(self, *args, **kwargs):
asyncua.server.binary_server_asyncio.OPCUAProtocol.__init__(self, *args, **kwargs)
protocol.Protocol.__init__(self)
def dataReceived(self, data):
log("data received")
log(data)
self.data_received(data)
log("PASSED data received")
def connectionMade(self):
log("connection made")
# opcua transport has 'get_extra_info':
# https://github.com/FreeOpcUa/opcua-asyncio/blob/ff6969d/asyncua/server/uaprocessor.py#LL32-L32C61
self.transport.get_extra_info = lambda *args, **kwags: "test"
# this also has 'close'
# https://github.com/FreeOpcUa/opcua-asyncio/blob/master/asyncua/server/binary_server_asyncio.py#L108
self.transport.close = lambda *args, **kwags: None
self.connection_made(self.transport)
log("PASSED conn made")
def connectionLost(self, ex):
log("connection lost")
self.connection_lost(ex)
log("PASSED conn lost")
class OPCUAFactory(protocol.Factory):
def buildProtocol(self, addr):
return OPCUA(self.iserver, [], [], [], self.limits)
# Add a wsgi server, this is normal.
endpoints.serverFromString(reactor, "tcp:%s:interface=%s" % (port, ip)).listen(twisted_server.Site(resource))
......@@ -402,5 +445,40 @@ def runwsgitw():
# to a different port.
endpoints.serverFromString(reactor, "tcp:2261:interface=%s" % ip).listen(EchoFactory())
# Add OPCUA server
opcua_ip, opcua_port = ip, '2262'
opcua_factory = OPCUAFactory()
add_iserver(opcua_factory)
add_limits(opcua_factory)
endpoints.serverFromString(
reactor, f"tcp:{opcua_port}:interface={opcua_ip}").listen(opcua_factory)
# Start main loop.
reactor.run()
def add_iserver(opcua_factory, opcua_ip, opcua_port):
opcua_factory.iserver = asyncua.server.internal_server.InternalServer()
# see https://github.com/FreeOpcUa/opcua-asyncio/blob/ff6969d2/asyncua/server/server.py#LL411C13-L411C70
opcua_factory.iserver.supported_tokens = (asyncua.ua.AnonymousIdentityToken,)
# adhoc creation of endpoint, only most essential parts
# https://github.com/FreeOpcUa/opcua-asyncio/blob/ff6969d2b7d93cc22c517cbb2f43ef98dc643a8c/asyncua/server/server.py#L434
edp = asyncua.ua.EndpointDescription()
edp.EndpointUrl = urllib.parse.urlparse(f"opc.tcp://{opcua_ip}:{opcua_port}/freeopcua/server/").geturl()
edp.SecurityMode = asyncua.ua.MessageSecurityMode.None_
edp.SecurityPolicyUri = asyncua.ua.SecurityPolicy.URI
opcua_factory.iserver.add_endpoint(edp)
def add_limits(opcua_factory):
# Use acceptable limits
buffer_sz = 65535
max_msg_sz = 100 * 1024 * 1024 # 100mb
opcua_factory.limits = asyncua.common.connection.TransportLimits(
max_recv_buffer=buffer_sz,
max_send_buffer=buffer_sz,
max_chunk_count=math.ceil(max_msg_sz / buffer_sz), # Round up to allow max msg size
max_message_size=max_msg_sz
)
\ No newline at end of file
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment