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(): ...@@ -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.web.wsgi import WSGIResource
from twisted.internet import protocol, reactor, endpoints from twisted.internet import protocol, reactor, endpoints
from twisted.web import server as twisted_server from twisted.web import server as twisted_server
import urllib import urllib
import asyncua
from Products.ERP5Type.Log import log from Products.ERP5Type.Log import log
# I modified runwsgi() without thinking carefully. # I modified runwsgi() without thinking carefully.
...@@ -393,6 +405,37 @@ def runwsgitw(): ...@@ -393,6 +405,37 @@ def runwsgitw():
class EchoFactory(protocol.Factory): class EchoFactory(protocol.Factory):
def buildProtocol(self, addr): def buildProtocol(self, addr):
return Echo() 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. # Add a wsgi server, this is normal.
endpoints.serverFromString(reactor, "tcp:%s:interface=%s" % (port, ip)).listen(twisted_server.Site(resource)) endpoints.serverFromString(reactor, "tcp:%s:interface=%s" % (port, ip)).listen(twisted_server.Site(resource))
...@@ -402,5 +445,40 @@ def runwsgitw(): ...@@ -402,5 +445,40 @@ def runwsgitw():
# to a different port. # to a different port.
endpoints.serverFromString(reactor, "tcp:2261:interface=%s" % ip).listen(EchoFactory()) 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. # Start main loop.
reactor.run() 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