2020import functools
2121import yaml
2222
23- # Fix UTF-8 decode error
24- # See: https://github.com/akpw/mktxp/issues/47
25- # The RouterOS-api implicitly assumes that the API response is UTF-8 encoded.
26- # But Mikrotik uses latin-1.
27- # Because the upstream dependency is currently abandoned, this is a quick hack to solve the issue
23+ # Fix UTF-8 decode error and memory leak from upstream RouterOS-api
24+ (# Ref: https://github.com/akpw/mktxp/issues/47)
2825
26+ # 1. The RouterOS-api implicitly assumes that the API response is UTF-8 encoded,
27+ # but Mikrotik often uses latin-1, so monkey-patching StringField to fallback to latin-1
28+
29+ # 2. The upstream library uses `collections.defaultdict(StringField)` which caches every unique
30+ # key returned by the router, causing an unbounded memory leak. Monkey-patching it with LeaklessDefaultDict
2931MIKROTIK_ENCODING = 'latin-1'
3032import routeros_api .api_structure
3133
@@ -36,7 +38,13 @@ def _decode_bytes(bytes_to_decode):
3638 return bytes_to_decode .decode (MIKROTIK_ENCODING )
3739
3840routeros_api .api_structure .StringField .get_python_value = lambda _ , bytes : _decode_bytes (bytes )
39- routeros_api .api_structure .default_structure = collections .defaultdict (routeros_api .api_structure .StringField )
41+
42+ class LeaklessDefaultDict (dict ):
43+ def __missing__ (self , key ):
44+ return routeros_api .api_structure .StringField ()
45+
46+ routeros_api .api_structure .default_structure = LeaklessDefaultDict ()
47+
4048
4149from routeros_api import RouterOsApiPool
4250
0 commit comments