datacomshell 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
datacomshell/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import re
|
|
3
|
+
from typing import Optional
|
|
4
|
+
import telnetlib3
|
|
5
|
+
from telnetlib3 import TelnetWriter, TelnetReader, TelnetWriterUnicode, TelnetReaderUnicode
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class ConnectError(RuntimeError):
|
|
9
|
+
def __init__(self, message: str) -> None:
|
|
10
|
+
super().__init__(message)
|
|
11
|
+
pass
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class LoginError(RuntimeError):
|
|
15
|
+
def __init__(self, message: str) -> None:
|
|
16
|
+
super().__init__(message)
|
|
17
|
+
pass
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
__const_command_runned_pattern = re.compile(
|
|
21
|
+
r'<.*>|\[.*\]|<~.*>|\[~.*\]|<\*.*>|\[\*.*\]')
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class DatacomShell(object):
|
|
25
|
+
def __init__(self,
|
|
26
|
+
host: str,
|
|
27
|
+
username: str,
|
|
28
|
+
password: str,
|
|
29
|
+
port: int = 23,
|
|
30
|
+
connect_timeout: Optional[float] = None
|
|
31
|
+
) -> None:
|
|
32
|
+
self.__host = host
|
|
33
|
+
self.__port = port
|
|
34
|
+
self.__connect_timeout = connect_timeout
|
|
35
|
+
|
|
36
|
+
self.__username = username
|
|
37
|
+
self.__password = password
|
|
38
|
+
|
|
39
|
+
self.__login_status = False
|
|
40
|
+
self.__reader: TelnetReader | TelnetReaderUnicode | None = None
|
|
41
|
+
self.__writer: TelnetWriter | TelnetWriterUnicode | None = None
|
|
42
|
+
|
|
43
|
+
self.__const_command_runned_pattern = __const_command_runned_pattern
|
|
44
|
+
|
|
45
|
+
async def __read(self,
|
|
46
|
+
pattern: Optional[re.Pattern] = __const_command_runned_pattern,
|
|
47
|
+
error_pattern: Optional[re.Pattern] = None,
|
|
48
|
+
timeout: Optional[float] = 10.0,
|
|
49
|
+
size: int = 1024
|
|
50
|
+
) -> str | None:
|
|
51
|
+
buffer = ''
|
|
52
|
+
runStatus = True
|
|
53
|
+
|
|
54
|
+
if self.__reader is None or self.__writer is None:
|
|
55
|
+
raise ConnectError("Not connected to device")
|
|
56
|
+
|
|
57
|
+
while True:
|
|
58
|
+
try:
|
|
59
|
+
res = await asyncio.wait_for(self.__reader.read(size), timeout)
|
|
60
|
+
except asyncio.TimeoutError:
|
|
61
|
+
break
|
|
62
|
+
|
|
63
|
+
if not res:
|
|
64
|
+
break
|
|
65
|
+
|
|
66
|
+
if res is bytes:
|
|
67
|
+
buffer += res.decode('utf-8')
|
|
68
|
+
elif res is str:
|
|
69
|
+
buffer += res
|
|
70
|
+
|
|
71
|
+
if pattern is not None and re.search(pattern=pattern, string=buffer, flags=0) is not None:
|
|
72
|
+
break
|
|
73
|
+
|
|
74
|
+
if error_pattern is not None and re.search(pattern=error_pattern, string=buffer, flags=0) is not None:
|
|
75
|
+
runStatus = False
|
|
76
|
+
break
|
|
77
|
+
|
|
78
|
+
return buffer if runStatus else None
|
|
79
|
+
|
|
80
|
+
def __write(self, command: str) -> None:
|
|
81
|
+
if self.__writer is None:
|
|
82
|
+
raise ConnectError("Not connected to device")
|
|
83
|
+
|
|
84
|
+
in_command = command + "\r\n"
|
|
85
|
+
|
|
86
|
+
# 根据 writer 类型决定使用字符串还是字节
|
|
87
|
+
if isinstance(self.__writer, TelnetWriterUnicode):
|
|
88
|
+
self.__writer.write(in_command)
|
|
89
|
+
else:
|
|
90
|
+
self.__writer.write(in_command.encode('utf-8'))
|
|
91
|
+
|
|
92
|
+
async def connect(self) -> None:
|
|
93
|
+
try:
|
|
94
|
+
self.__reader, self.__writer = await telnetlib3.open_connection(
|
|
95
|
+
host=self.__host, port=self.__port, connect_timeout=self.__connect_timeout)
|
|
96
|
+
except asyncio.TimeoutError:
|
|
97
|
+
raise TimeoutError(
|
|
98
|
+
f"Connection to {self.__host}:{self.__port} timed out after {self.__connect_timeout} seconds")
|
|
99
|
+
|
|
100
|
+
if self.__reader is None or self.__writer is None:
|
|
101
|
+
raise ConnectionError("Failed to connect to device")
|
|
102
|
+
|
|
103
|
+
return
|
|
104
|
+
|
|
105
|
+
async def login(self) -> None:
|
|
106
|
+
if self.__login_status:
|
|
107
|
+
return
|
|
108
|
+
|
|
109
|
+
if self.__read(pattern=re.compile(r"Username:")) is not None:
|
|
110
|
+
self.__write(self.__username)
|
|
111
|
+
else:
|
|
112
|
+
raise LoginError("Failed to connect to device")
|
|
113
|
+
|
|
114
|
+
if self.__read(pattern=re.compile(r"Password:")) is not None:
|
|
115
|
+
self.__write(self.__password)
|
|
116
|
+
else:
|
|
117
|
+
raise LoginError("Failed to connect to device")
|
|
118
|
+
|
|
119
|
+
if self.__read(pattern=self.__const_command_runned_pattern) is not None:
|
|
120
|
+
self.__login_status = True
|
|
121
|
+
return
|
|
122
|
+
|
|
123
|
+
async def send_command(self, command: str):
|
|
124
|
+
self.__write(command)
|
|
125
|
+
return await self.__read()
|
|
126
|
+
|
|
127
|
+
async def build(self) -> None:
|
|
128
|
+
await self.connect()
|
|
129
|
+
await self.login()
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
datacomshell/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
|
2
|
+
datacomshell/datacom_shell.py,sha256=KzmCB90uaa1e5zursk0hO0kxy47BOx5MzMwzqUMGxJs,4278
|
|
3
|
+
datacomshell-0.1.0.dist-info/WHEEL,sha256=fWriCkzqm-pffF5af4gJC9iI5FMFaJTuN9UxxxzOmdY,81
|
|
4
|
+
datacomshell-0.1.0.dist-info/entry_points.txt,sha256=tmvJuga4uEQhLh2zXYCp_guv7DKvb6bWflwyQC2vyPo,52
|
|
5
|
+
datacomshell-0.1.0.dist-info/METADATA,sha256=NEd6zaV5N88V3VNQ9PjbgJ8SZXDvjvGF4u7ENj_GLsQ,243
|
|
6
|
+
datacomshell-0.1.0.dist-info/RECORD,,
|