andrej@1731: #!/usr/bin/env python andrej@1731: # -*- coding: utf-8 -*- andrej@1731: andrej@1731: # This file is part of Beremiz, a Integrated Development Environment for andrej@1731: # programming IEC 61131-3 automates supporting plcopen standard and CanFestival. andrej@1731: # andrej@1731: # Copyright (C) 2007: Edouard TISSERANT and Laurent BESSARD andrej@1731: # Copyright (C) 2017: Andrey Skvortsov andrej@1731: # andrej@1731: # See COPYING file for copyrights details. andrej@1731: # andrej@1731: # This program is free software; you can redistribute it and/or andrej@1731: # modify it under the terms of the GNU General Public License andrej@1731: # as published by the Free Software Foundation; either version 2 andrej@1731: # of the License, or (at your option) any later version. andrej@1731: # andrej@1731: # This program is distributed in the hope that it will be useful, andrej@1731: # but WITHOUT ANY WARRANTY; without even the implied warranty of andrej@1731: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the andrej@1731: # GNU General Public License for more details. andrej@1731: # andrej@1731: # You should have received a copy of the GNU General Public License andrej@1731: # along with this program; if not, write to the Free Software andrej@1731: # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. andrej@1731: andrej@1731: # Package initialisation andrej@1731: andrej@1881: andrej@1881: from __future__ import absolute_import andrej@1731: from os import listdir, path andrej@1731: import util.paths as paths Edouard@2463: from connectors.ConnectorBase import ConnectorBase Edouard@2463: from types import ClassType andrej@1731: Edouard@2329: connectors_packages = ["PYRO","WAMP"] Edouard@2329: andrej@1731: andrej@1731: def _GetLocalConnectorClassFactory(name): andrej@1731: return lambda: getattr(__import__(name, globals(), locals()), name + "_connector_factory") andrej@1731: andrej@2182: Edouard@2329: connectors = {name: _GetLocalConnectorClassFactory(name) Edouard@2329: for name in connectors_packages} denis@2007: Edouard@2329: _dialogs_imported = False Edouard@2329: per_URI_connectors = None Edouard@2329: schemes = None andrej@2182: Edouard@2329: # lazy import of connectors dialogs, only if used Edouard@2329: def _Import_Dialogs(): Edouard@2329: global per_URI_connectors, schemes, _dialogs_imported Edouard@2329: if not _dialogs_imported: Edouard@2329: _dialogs_imported = True Edouard@2329: per_URI_connectors = {} Edouard@2329: schemes = [] Edouard@2329: for con_name in connectors_packages: Edouard@2329: module = __import__(con_name + '_dialog', globals(), locals()) denis@2007: Edouard@2329: for scheme in module.Schemes: Edouard@2329: per_URI_connectors[scheme] = getattr(module, con_name + '_dialog') Edouard@2329: schemes += [scheme] denis@2007: andrej@1731: andrej@1731: def ConnectorFactory(uri, confnodesroot): andrej@1731: """ andrej@1731: Return a connector corresponding to the URI andrej@1731: or None if cannot connect to URI andrej@1731: """ Edouard@2463: _scheme = uri.split("://")[0].upper() Edouard@2478: Edouard@2478: # commented code to enable for MDNS:// support Edouard@2478: # _scheme, location = uri.split("://") Edouard@2478: # _scheme = _scheme.upper() Edouard@2478: Edouard@2463: if _scheme == "LOCAL": andrej@1731: # Local is special case andrej@1731: # pyro connection to local runtime andrej@1731: # started on demand, listening on random port Edouard@2338: scheme = "PYRO" andrej@1731: runtime_port = confnodesroot.AppFrame.StartLocalRuntime( andrej@1731: taskbaricon=True) andrej@1731: uri = "PYROLOC://127.0.0.1:" + str(runtime_port) Edouard@2478: Edouard@2478: # commented code to enable for MDNS:// support Edouard@2478: # elif _scheme == "MDNS": Edouard@2478: # try: Edouard@2478: # from zeroconf import Zeroconf Edouard@2478: # r = Zeroconf() Edouard@2478: # i = r.get_service_info(zeroconf_service_type, location) Edouard@2478: # if i is None: Edouard@2478: # raise Exception("'%s' not found" % location) Edouard@2478: # ip = str(socket.inet_ntoa(i.address)) Edouard@2478: # port = str(i.port) Edouard@2478: # newlocation = ip + ':' + port Edouard@2478: # confnodesroot.logger.write(_("'{a1}' is located at {a2}\n").format(a1=location, a2=newlocation)) Edouard@2478: # location = newlocation Edouard@2478: # # not a bug, but a workaround against obvious downgrade attack Edouard@2478: # scheme = "PYROS" Edouard@2478: # r.close() Edouard@2478: # except Exception: Edouard@2478: # confnodesroot.logger.write_error(_("MDNS resolution failure for '%s'\n") % location) Edouard@2478: # confnodesroot.logger.write_error(traceback.format_exc()) Edouard@2478: # return None Edouard@2478: Edouard@2463: elif _scheme in connectors: Edouard@2463: scheme = _scheme Edouard@2463: elif _scheme[-1] == 'S' and _scheme[:-1] in connectors: Edouard@2463: scheme = _scheme[:-1] andrej@1731: else: andrej@1731: return None andrej@1731: Edouard@2463: # import module according to uri type and get connector specific baseclass Edouard@2463: # first call to import the module, Edouard@2463: # then call with parameters to create the class Edouard@2463: connector_specific_class = connectors[scheme]()(uri, confnodesroot) Edouard@2469: Edouard@2469: if connector_specific_class is None: Edouard@2469: return None denis@2007: Edouard@2463: # new class inheriting from generic and specific connector base classes Edouard@2463: return ClassType(_scheme + "_connector", Edouard@2463: (ConnectorBase, connector_specific_class), {})() andrej@2182: Edouard@2329: def EditorClassFromScheme(scheme): Edouard@2329: _Import_Dialogs() Edouard@2329: return per_URI_connectors.get(scheme, None) denis@2007: Edouard@2329: def ConnectorSchemes(): Edouard@2329: _Import_Dialogs() Edouard@2329: return schemes