mirror of
https://github.com/tomaae/homeassistant-mikrotik_router.git
synced 2025-07-10 09:24:31 +02:00
reverted back to customized fork of librouteros
This commit is contained in:
parent
1010a8aa3a
commit
0a58db40cd
8 changed files with 621 additions and 29 deletions
|
@ -0,0 +1,60 @@
|
|||
# -*- coding: UTF-8 -*-
|
||||
|
||||
from socket import create_connection
|
||||
from collections import ChainMap
|
||||
|
||||
from .exceptions import (
|
||||
ConnectionClosed,
|
||||
FatalError,
|
||||
)
|
||||
from .connections import SocketTransport
|
||||
from .protocol import ApiProtocol
|
||||
from .login import (
|
||||
plain,
|
||||
token,
|
||||
)
|
||||
from .api import Api
|
||||
|
||||
DEFAULTS = {
|
||||
'timeout': 10,
|
||||
'port': 8728,
|
||||
'saddr': '',
|
||||
'subclass': Api,
|
||||
'encoding': 'ASCII',
|
||||
'ssl_wrapper': lambda sock: sock,
|
||||
'login_method': plain,
|
||||
}
|
||||
|
||||
|
||||
def connect(host, username, password, **kwargs):
|
||||
"""
|
||||
Connect and login to routeros device.
|
||||
Upon success return a Api class.
|
||||
|
||||
:param host: Hostname to connecto to. May be ipv4,ipv6,FQDN.
|
||||
:param username: Username to login with.
|
||||
:param password: Password to login with. Only ASCII characters allowed.
|
||||
:param timeout: Socket timeout. Defaults to 10.
|
||||
:param port: Destination port to be used. Defaults to 8728.
|
||||
:param saddr: Source address to bind to.
|
||||
:param subclass: Subclass of Api class. Defaults to Api class from library.
|
||||
:param ssl_wrapper: Callable (e.g. ssl.SSLContext instance) to wrap socket with.
|
||||
:param login_method: Callable with login method.
|
||||
"""
|
||||
arguments = ChainMap(kwargs, DEFAULTS)
|
||||
transport = create_transport(host, **arguments)
|
||||
protocol = ApiProtocol(transport=transport, encoding=arguments['encoding'])
|
||||
api = arguments['subclass'](protocol=protocol)
|
||||
|
||||
try:
|
||||
arguments['login_method'](api=api, username=username, password=password)
|
||||
return api
|
||||
except (ConnectionClosed, FatalError):
|
||||
transport.close()
|
||||
raise
|
||||
|
||||
|
||||
def create_transport(host, **kwargs):
|
||||
sock = create_connection((host, kwargs['port']), kwargs['timeout'], (kwargs['saddr'], 0))
|
||||
sock = kwargs['ssl_wrapper'](sock)
|
||||
return SocketTransport(sock=sock)
|
136
custom_components/mikrotik_router/librouteros_custom/api.py
Normal file
136
custom_components/mikrotik_router/librouteros_custom/api.py
Normal file
|
@ -0,0 +1,136 @@
|
|||
# -*- coding: UTF-8 -*-
|
||||
|
||||
from posixpath import join as pjoin
|
||||
|
||||
from .exceptions import TrapError, MultiTrapError
|
||||
from .protocol import (
|
||||
compose_word,
|
||||
parse_word,
|
||||
)
|
||||
from .query import Query
|
||||
|
||||
|
||||
class Api:
|
||||
|
||||
def __init__(self, protocol):
|
||||
self.protocol = protocol
|
||||
|
||||
def __call__(self, cmd, **kwargs):
|
||||
"""
|
||||
Call Api with given command.
|
||||
Yield each row.
|
||||
|
||||
:param cmd: Command word. eg. /ip/address/print
|
||||
:param kwargs: Dictionary with optional arguments.
|
||||
"""
|
||||
words = (compose_word(key, value) for key, value in kwargs.items())
|
||||
self.protocol.writeSentence(cmd, *words)
|
||||
yield from self.readResponse()
|
||||
|
||||
def rawCmd(self, cmd, *words):
|
||||
"""
|
||||
Call Api with given command and raw words.
|
||||
End user is responsible to properly format each api word argument.
|
||||
:param cmd: Command word. eg. /ip/address/print
|
||||
:param args: Iterable with optional plain api arguments.
|
||||
"""
|
||||
self.protocol.writeSentence(cmd, *words)
|
||||
yield from self.readResponse()
|
||||
|
||||
def readSentence(self):
|
||||
"""
|
||||
Read one sentence and parse words.
|
||||
|
||||
:returns: Reply word, dict with attribute words.
|
||||
"""
|
||||
reply_word, words = self.protocol.readSentence()
|
||||
words = dict(parse_word(word) for word in words)
|
||||
return reply_word, words
|
||||
|
||||
def readResponse(self):
|
||||
"""
|
||||
Yield each sentence untill !done is received.
|
||||
|
||||
:throws TrapError: If one !trap is received.
|
||||
:throws MultiTrapError: If > 1 !trap is received.
|
||||
"""
|
||||
traps = []
|
||||
reply_word = None
|
||||
while reply_word != '!done':
|
||||
reply_word, words = self.readSentence()
|
||||
if reply_word == '!trap':
|
||||
traps.append(TrapError(**words))
|
||||
elif reply_word in ('!re', '!done') and words:
|
||||
yield words
|
||||
|
||||
if len(traps) > 1:
|
||||
raise MultiTrapError(*traps)
|
||||
if len(traps) == 1:
|
||||
raise traps[0]
|
||||
|
||||
def close(self):
|
||||
self.protocol.close()
|
||||
|
||||
def path(self, *path):
|
||||
return Path(
|
||||
path='',
|
||||
api=self,
|
||||
).join(*path)
|
||||
|
||||
|
||||
class Path:
|
||||
"""Represents absolute command path."""
|
||||
|
||||
def __init__(self, path, api):
|
||||
self.path = path
|
||||
self.api = api
|
||||
|
||||
def select(self, key, *other):
|
||||
keys = (key, ) + other
|
||||
return Query(path=self, keys=keys, api=self.api)
|
||||
|
||||
def __str__(self):
|
||||
return self.path
|
||||
|
||||
def __repr__(self):
|
||||
return "<{module}.{cls} {path!r}>".format(
|
||||
module=self.__class__.__module__,
|
||||
cls=self.__class__.__name__,
|
||||
path=self.path,
|
||||
)
|
||||
|
||||
def __iter__(self):
|
||||
yield from self('print')
|
||||
|
||||
def __call__(self, cmd, **kwargs):
|
||||
yield from self.api(
|
||||
self.join(cmd).path,
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
def join(self, *path):
|
||||
"""Join current path with one or more path strings."""
|
||||
return Path(
|
||||
api=self.api,
|
||||
path=pjoin('/', self.path, *path).rstrip('/'),
|
||||
)
|
||||
|
||||
def remove(self, *ids):
|
||||
ids = ','.join(ids)
|
||||
tuple(self(
|
||||
'remove',
|
||||
**{'.id': ids},
|
||||
))
|
||||
|
||||
def add(self, **kwargs):
|
||||
ret = self(
|
||||
'add',
|
||||
**kwargs,
|
||||
)
|
||||
return tuple(ret)[0]['ret']
|
||||
|
||||
def update(self, **kwargs):
|
||||
tuple(self(
|
||||
'set',
|
||||
**kwargs,
|
||||
))
|
|
@ -0,0 +1,37 @@
|
|||
# -*- coding: UTF-8 -*-
|
||||
|
||||
from .exceptions import ConnectionClosed
|
||||
|
||||
|
||||
class SocketTransport:
|
||||
|
||||
def __init__(self, sock):
|
||||
self.sock = sock
|
||||
|
||||
def write(self, data):
|
||||
"""
|
||||
Write given bytes to socket. Loop as long as every byte in
|
||||
string is written unless exception is raised.
|
||||
"""
|
||||
self.sock.sendall(data)
|
||||
|
||||
def read(self, length):
|
||||
"""
|
||||
Read as many bytes from socket as specified in length.
|
||||
Loop as long as every byte is read unless exception is raised.
|
||||
"""
|
||||
data = bytearray()
|
||||
while len(data) != length:
|
||||
tmp = None
|
||||
try:
|
||||
tmp = self.sock.recv((length - len(data)))
|
||||
except:
|
||||
raise ConnectionClosed('Socket recv failed.')
|
||||
|
||||
data += tmp
|
||||
if not data:
|
||||
raise ConnectionClosed('Connection unexpectedly closed.')
|
||||
return data
|
||||
|
||||
def close(self):
|
||||
self.sock.close()
|
|
@ -0,0 +1,52 @@
|
|||
# -*- coding: UTF-8 -*-
|
||||
|
||||
|
||||
class LibRouterosError(Exception):
|
||||
"""Base exception for all other."""
|
||||
|
||||
|
||||
class ConnectionClosed(LibRouterosError):
|
||||
"""Raised when connection have been closed."""
|
||||
|
||||
|
||||
class ProtocolError(LibRouterosError):
|
||||
"""Raised when e.g. encoding/decoding fails."""
|
||||
|
||||
|
||||
class FatalError(ProtocolError):
|
||||
"""Exception raised when !fatal is received."""
|
||||
|
||||
|
||||
class TrapError(ProtocolError):
|
||||
"""
|
||||
Exception raised when !trap is received.
|
||||
|
||||
:param int category: Optional integer representing category.
|
||||
:param str message: Error message.
|
||||
"""
|
||||
|
||||
def __init__(self, message, category=None):
|
||||
self.category = category
|
||||
self.message = message
|
||||
super().__init__()
|
||||
|
||||
def __str__(self):
|
||||
return str(self.message.replace('\r\n', ','))
|
||||
|
||||
def __repr__(self):
|
||||
return '{}({!r})'.format(self.__class__.__name__, str(self))
|
||||
|
||||
|
||||
class MultiTrapError(ProtocolError):
|
||||
"""
|
||||
Exception raised when multiple !trap words have been received in one response.
|
||||
|
||||
:param traps: TrapError instances.
|
||||
"""
|
||||
|
||||
def __init__(self, *traps):
|
||||
self.traps = traps
|
||||
super().__init__()
|
||||
|
||||
def __str__(self):
|
||||
return ', '.join(str(trap) for trap in self.traps)
|
|
@ -0,0 +1,26 @@
|
|||
from binascii import unhexlify, hexlify
|
||||
from hashlib import md5
|
||||
|
||||
|
||||
def encode_password(token, password):
|
||||
#pylint: disable=redefined-outer-name
|
||||
token = token.encode('ascii', 'strict')
|
||||
token = unhexlify(token)
|
||||
password = password.encode('ascii', 'strict')
|
||||
hasher = md5()
|
||||
hasher.update(b'\x00' + password + token)
|
||||
password = hexlify(hasher.digest())
|
||||
return '00' + password.decode('ascii', 'strict')
|
||||
|
||||
|
||||
def token(api, username, password):
|
||||
"""Login using pre routeros 6.43 authorization method."""
|
||||
sentence = api('/login')
|
||||
tok = tuple(sentence)[0]['ret']
|
||||
encoded = encode_password(tok, password)
|
||||
tuple(api('/login', **{'name': username, 'response': encoded}))
|
||||
|
||||
|
||||
def plain(api, username, password):
|
||||
"""Login using post routeros 6.43 authorization method."""
|
||||
tuple(api('/login', **{'name': username, 'password': password}))
|
209
custom_components/mikrotik_router/librouteros_custom/protocol.py
Normal file
209
custom_components/mikrotik_router/librouteros_custom/protocol.py
Normal file
|
@ -0,0 +1,209 @@
|
|||
# -*- coding: UTF-8 -*-
|
||||
|
||||
from struct import pack, unpack
|
||||
from logging import getLogger, NullHandler
|
||||
|
||||
from .exceptions import (
|
||||
ProtocolError,
|
||||
FatalError,
|
||||
)
|
||||
|
||||
LOGGER = getLogger('librouteros')
|
||||
LOGGER.addHandler(NullHandler())
|
||||
|
||||
|
||||
def parse_word(word):
|
||||
"""
|
||||
Split given attribute word to key, value pair.
|
||||
|
||||
Values are casted to python equivalents.
|
||||
|
||||
:param word: API word.
|
||||
:returns: Key, value pair.
|
||||
"""
|
||||
mapping = {'yes': True, 'true': True, 'no': False, 'false': False}
|
||||
_, key, value = word.split('=', 2)
|
||||
try:
|
||||
value = int(value)
|
||||
except ValueError:
|
||||
value = mapping.get(value, value)
|
||||
return (key, value)
|
||||
|
||||
|
||||
def cast_to_api(value):
|
||||
"""Cast python equivalent to API."""
|
||||
mapping = {True: 'yes', False: 'no'}
|
||||
# this is necesary because 1 == True, 0 == False
|
||||
if type(value) == int:
|
||||
value = str(value)
|
||||
else:
|
||||
value = mapping.get(value, str(value))
|
||||
return value
|
||||
|
||||
|
||||
def compose_word(key, value):
|
||||
"""
|
||||
Create a attribute word from key, value pair.
|
||||
Values are casted to api equivalents.
|
||||
"""
|
||||
return '={}={}'.format(key, cast_to_api(value))
|
||||
|
||||
|
||||
class Encoder:
|
||||
|
||||
def encodeSentence(self, *words):
|
||||
"""
|
||||
Encode given sentence in API format.
|
||||
|
||||
:param words: Words to endoce.
|
||||
:returns: Encoded sentence.
|
||||
"""
|
||||
encoded = map(self.encodeWord, words)
|
||||
encoded = b''.join(encoded)
|
||||
# append EOS (end of sentence) byte
|
||||
encoded += b'\x00'
|
||||
return encoded
|
||||
|
||||
def encodeWord(self, word):
|
||||
"""
|
||||
Encode word in API format.
|
||||
|
||||
:param word: Word to encode.
|
||||
:returns: Encoded word.
|
||||
"""
|
||||
#pylint: disable=no-member
|
||||
encoded_word = word.encode(encoding=self.encoding, errors='strict')
|
||||
return Encoder.encodeLength(len(word)) + encoded_word
|
||||
|
||||
@staticmethod
|
||||
def encodeLength(length):
|
||||
"""
|
||||
Encode given length in mikrotik format.
|
||||
|
||||
:param length: Integer < 268435456.
|
||||
:returns: Encoded length.
|
||||
"""
|
||||
if length < 128:
|
||||
ored_length = length
|
||||
offset = -1
|
||||
elif length < 16384:
|
||||
ored_length = length | 0x8000
|
||||
offset = -2
|
||||
elif length < 2097152:
|
||||
ored_length = length | 0xC00000
|
||||
offset = -3
|
||||
elif length < 268435456:
|
||||
ored_length = length | 0xE0000000
|
||||
offset = -4
|
||||
else:
|
||||
raise ProtocolError('Unable to encode length of {}'.format(length))
|
||||
|
||||
return pack('!I', ored_length)[offset:]
|
||||
|
||||
|
||||
class Decoder:
|
||||
|
||||
@staticmethod
|
||||
def determineLength(length):
|
||||
"""
|
||||
Given first read byte, determine how many more bytes
|
||||
needs to be known in order to get fully encoded length.
|
||||
|
||||
:param length: First read byte.
|
||||
:return: How many bytes to read.
|
||||
"""
|
||||
integer = ord(length)
|
||||
|
||||
#pylint: disable=no-else-return
|
||||
if integer < 128:
|
||||
return 0
|
||||
elif integer < 192:
|
||||
return 1
|
||||
elif integer < 224:
|
||||
return 2
|
||||
elif integer < 240:
|
||||
return 3
|
||||
|
||||
raise ProtocolError('Unknown controll byte {}'.format(length))
|
||||
|
||||
@staticmethod
|
||||
def decodeLength(length):
|
||||
"""
|
||||
Decode length based on given bytes.
|
||||
|
||||
:param length: Bytes string to decode.
|
||||
:return: Decoded length.
|
||||
"""
|
||||
bytes_length = len(length)
|
||||
|
||||
if bytes_length < 2:
|
||||
offset = b'\x00\x00\x00'
|
||||
xor = 0
|
||||
elif bytes_length < 3:
|
||||
offset = b'\x00\x00'
|
||||
xor = 0x8000
|
||||
elif bytes_length < 4:
|
||||
offset = b'\x00'
|
||||
xor = 0xC00000
|
||||
elif bytes_length < 5:
|
||||
offset = b''
|
||||
xor = 0xE0000000
|
||||
else:
|
||||
raise ProtocolError('Unable to decode length of {}'.format(length))
|
||||
|
||||
decoded = unpack('!I', (offset + length))[0]
|
||||
decoded ^= xor
|
||||
return decoded
|
||||
|
||||
|
||||
class ApiProtocol(Encoder, Decoder):
|
||||
|
||||
def __init__(self, transport, encoding):
|
||||
self.transport = transport
|
||||
self.encoding = encoding
|
||||
|
||||
@staticmethod
|
||||
def log(direction_string, *sentence):
|
||||
for word in sentence:
|
||||
LOGGER.debug('{0} {1!r}'.format(direction_string, word))
|
||||
|
||||
LOGGER.debug('{0} EOS'.format(direction_string))
|
||||
|
||||
def writeSentence(self, cmd, *words):
|
||||
"""
|
||||
Write encoded sentence.
|
||||
|
||||
:param cmd: Command word.
|
||||
:param words: Aditional words.
|
||||
"""
|
||||
encoded = self.encodeSentence(cmd, *words)
|
||||
self.log('<---', cmd, *words)
|
||||
self.transport.write(encoded)
|
||||
|
||||
def readSentence(self):
|
||||
"""
|
||||
Read every word untill empty word (NULL byte) is received.
|
||||
|
||||
:return: Reply word, tuple with read words.
|
||||
"""
|
||||
sentence = tuple(word for word in iter(self.readWord, ''))
|
||||
self.log('--->', *sentence)
|
||||
reply_word, words = sentence[0], sentence[1:]
|
||||
if reply_word == '!fatal':
|
||||
self.transport.close()
|
||||
raise FatalError(words[0])
|
||||
return reply_word, words
|
||||
|
||||
def readWord(self):
|
||||
byte = self.transport.read(1)
|
||||
# Early return check for null byte
|
||||
if byte == b'\x00':
|
||||
return ''
|
||||
to_read = self.determineLength(byte)
|
||||
byte += self.transport.read(to_read)
|
||||
length = self.decodeLength(byte)
|
||||
word = self.transport.read(length)
|
||||
return word.decode(encoding=self.encoding, errors='strict')
|
||||
|
||||
def close(self):
|
||||
self.transport.close()
|
|
@ -0,0 +1,64 @@
|
|||
# -*- coding: UTF-8 -*-
|
||||
from itertools import chain
|
||||
from .protocol import (
|
||||
cast_to_api,
|
||||
)
|
||||
|
||||
|
||||
class Key:
|
||||
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
|
||||
def __eq__(self, other):
|
||||
yield '?={}={}'.format(self, cast_to_api(other))
|
||||
|
||||
def __ne__(self, other):
|
||||
yield from self == other
|
||||
yield '?#!'
|
||||
|
||||
def __lt__(self, other):
|
||||
yield '?<{}={}'.format(self, cast_to_api(other))
|
||||
|
||||
def __gt__(self, other):
|
||||
yield '?>{}={}'.format(self, cast_to_api(other))
|
||||
|
||||
def __str__(self):
|
||||
return str(self.name)
|
||||
|
||||
|
||||
class Query:
|
||||
|
||||
def __init__(self, path, keys, api):
|
||||
self.path = path
|
||||
self.keys = keys
|
||||
self.api = api
|
||||
self.query = tuple()
|
||||
|
||||
def where(self, *args):
|
||||
self.query = tuple(chain.from_iterable(args))
|
||||
return self
|
||||
|
||||
def __iter__(self):
|
||||
keys = ','.join(str(key) for key in self.keys)
|
||||
keys = '=.proplist={}'.format(keys)
|
||||
cmd = str(self.path.join('print'))
|
||||
return iter(self.api.rawCmd(cmd, keys, *self.query))
|
||||
|
||||
|
||||
def And(left, right, *rest):
|
||||
#pylint: disable=invalid-name
|
||||
yield from left
|
||||
yield from right
|
||||
yield from chain.from_iterable(rest)
|
||||
yield '?#&'
|
||||
yield from ('?#&', ) * len(rest)
|
||||
|
||||
|
||||
def Or(left, right, *rest):
|
||||
#pylint: disable=invalid-name
|
||||
yield from left
|
||||
yield from right
|
||||
yield from chain.from_iterable(rest)
|
||||
yield '?#|'
|
||||
yield from ('?#|', ) * len(rest)
|
|
@ -10,7 +10,15 @@ from .const import (
|
|||
DEFAULT_ENCODING,
|
||||
)
|
||||
|
||||
import librouteros
|
||||
import os
|
||||
import sys
|
||||
import importlib
|
||||
MODULE_PATH = os.path.join(os.path.dirname(__file__), "librouteros_custom", "__init__.py")
|
||||
MODULE_NAME = "librouteros_custom"
|
||||
spec = importlib.util.spec_from_file_location(MODULE_NAME, MODULE_PATH)
|
||||
librouteros_custom = importlib.util.module_from_spec(spec)
|
||||
sys.modules[spec.name] = librouteros_custom
|
||||
spec.loader.exec_module(librouteros_custom)
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
@ -86,15 +94,15 @@ class MikrotikAPI:
|
|||
kwargs["ssl_wrapper"] = self._ssl_wrapper
|
||||
self.lock.acquire()
|
||||
try:
|
||||
self._connection = librouteros.connect(
|
||||
self._connection = librouteros_custom.connect(
|
||||
self._host, self._username, self._password, **kwargs
|
||||
)
|
||||
except (
|
||||
librouteros.exceptions.TrapError,
|
||||
librouteros.exceptions.MultiTrapError,
|
||||
librouteros.exceptions.ConnectionClosed,
|
||||
librouteros.exceptions.ProtocolError,
|
||||
librouteros.exceptions.FatalError,
|
||||
librouteros_custom.exceptions.TrapError,
|
||||
librouteros_custom.exceptions.MultiTrapError,
|
||||
librouteros_custom.exceptions.ConnectionClosed,
|
||||
librouteros_custom.exceptions.ProtocolError,
|
||||
librouteros_custom.exceptions.FatalError,
|
||||
ssl.SSLError,
|
||||
BrokenPipeError,
|
||||
OSError,
|
||||
|
@ -166,7 +174,7 @@ class MikrotikAPI:
|
|||
try:
|
||||
response = self._connection.path(path)
|
||||
_LOGGER.debug("API response (%s): %s", path, response)
|
||||
except librouteros.exceptions.ConnectionClosed:
|
||||
except librouteros_custom.exceptions.ConnectionClosed:
|
||||
if not self.connection_error_reported:
|
||||
_LOGGER.error("Mikrotik %s connection closed", self._host)
|
||||
self.connection_error_reported = True
|
||||
|
@ -175,10 +183,10 @@ class MikrotikAPI:
|
|||
self.lock.release()
|
||||
return None
|
||||
except (
|
||||
librouteros.exceptions.TrapError,
|
||||
librouteros.exceptions.MultiTrapError,
|
||||
librouteros.exceptions.ProtocolError,
|
||||
librouteros.exceptions.FatalError,
|
||||
librouteros_custom.exceptions.TrapError,
|
||||
librouteros_custom.exceptions.MultiTrapError,
|
||||
librouteros_custom.exceptions.ProtocolError,
|
||||
librouteros_custom.exceptions.FatalError,
|
||||
ssl.SSLError,
|
||||
BrokenPipeError,
|
||||
OSError,
|
||||
|
@ -202,7 +210,7 @@ class MikrotikAPI:
|
|||
|
||||
try:
|
||||
tuple(response)
|
||||
except librouteros.exceptions.ConnectionClosed as api_error:
|
||||
except librouteros_custom.exceptions.ConnectionClosed as api_error:
|
||||
if not self.connection_error_reported:
|
||||
_LOGGER.error("Mikrotik %s error while path %s", self._host, api_error)
|
||||
self.connection_error_reported = True
|
||||
|
@ -252,7 +260,7 @@ class MikrotikAPI:
|
|||
self.lock.acquire()
|
||||
try:
|
||||
response.update(**params)
|
||||
except librouteros.exceptions.ConnectionClosed:
|
||||
except librouteros_custom.exceptions.ConnectionClosed:
|
||||
if not self.connection_error_reported:
|
||||
_LOGGER.error("Mikrotik %s connection closed", self._host)
|
||||
self.connection_error_reported = True
|
||||
|
@ -261,10 +269,10 @@ class MikrotikAPI:
|
|||
self.lock.release()
|
||||
return False
|
||||
except (
|
||||
librouteros.exceptions.TrapError,
|
||||
librouteros.exceptions.MultiTrapError,
|
||||
librouteros.exceptions.ProtocolError,
|
||||
librouteros.exceptions.FatalError,
|
||||
librouteros_custom.exceptions.TrapError,
|
||||
librouteros_custom.exceptions.MultiTrapError,
|
||||
librouteros_custom.exceptions.ProtocolError,
|
||||
librouteros_custom.exceptions.FatalError,
|
||||
ssl.SSLError,
|
||||
BrokenPipeError,
|
||||
OSError,
|
||||
|
@ -326,7 +334,7 @@ class MikrotikAPI:
|
|||
try:
|
||||
run = response("run", **{".id": tmp[".id"]})
|
||||
tuple(run)
|
||||
except librouteros.exceptions.ConnectionClosed:
|
||||
except librouteros_custom.exceptions.ConnectionClosed:
|
||||
if not self.connection_error_reported:
|
||||
_LOGGER.error("Mikrotik %s connection closed", self._host)
|
||||
self.connection_error_reported = True
|
||||
|
@ -335,10 +343,10 @@ class MikrotikAPI:
|
|||
self.lock.release()
|
||||
return False
|
||||
except (
|
||||
librouteros.exceptions.TrapError,
|
||||
librouteros.exceptions.MultiTrapError,
|
||||
librouteros.exceptions.ProtocolError,
|
||||
librouteros.exceptions.FatalError,
|
||||
librouteros_custom.exceptions.TrapError,
|
||||
librouteros_custom.exceptions.MultiTrapError,
|
||||
librouteros_custom.exceptions.ProtocolError,
|
||||
librouteros_custom.exceptions.FatalError,
|
||||
ssl.SSLError,
|
||||
BrokenPipeError,
|
||||
OSError,
|
||||
|
@ -395,7 +403,7 @@ class MikrotikAPI:
|
|||
_LOGGER.debug(
|
||||
"API response (%s): %s", "/interface/monitor-traffic", traffic
|
||||
)
|
||||
except librouteros.exceptions.ConnectionClosed:
|
||||
except librouteros_custom.exceptions.ConnectionClosed:
|
||||
if not self.connection_error_reported:
|
||||
_LOGGER.error("Mikrotik %s connection closed", self._host)
|
||||
self.connection_error_reported = True
|
||||
|
@ -404,10 +412,10 @@ class MikrotikAPI:
|
|||
self.lock.release()
|
||||
return None
|
||||
except (
|
||||
librouteros.exceptions.TrapError,
|
||||
librouteros.exceptions.MultiTrapError,
|
||||
librouteros.exceptions.ProtocolError,
|
||||
librouteros.exceptions.FatalError,
|
||||
librouteros_custom.exceptions.TrapError,
|
||||
librouteros_custom.exceptions.MultiTrapError,
|
||||
librouteros_custom.exceptions.ProtocolError,
|
||||
librouteros_custom.exceptions.FatalError,
|
||||
ssl.SSLError,
|
||||
BrokenPipeError,
|
||||
OSError,
|
||||
|
@ -435,7 +443,7 @@ class MikrotikAPI:
|
|||
|
||||
try:
|
||||
tuple(response)
|
||||
except librouteros.exceptions.ConnectionClosed as api_error:
|
||||
except librouteros_custom.exceptions.ConnectionClosed as api_error:
|
||||
if not self.connection_error_reported:
|
||||
_LOGGER.error(
|
||||
"Mikrotik %s error while get_traffic %s", self._host, api_error
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue