datacomshell 0.1.0__tar.gz

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.
@@ -0,0 +1,10 @@
1
+ Metadata-Version: 2.3
2
+ Name: datacomshell
3
+ Version: 0.1.0
4
+ Summary: Add your description here
5
+ Author: Saven
6
+ Author-email: Saven <2416844857@qq.com>
7
+ Requires-Dist: telnetlib3>=4.0.2
8
+ Requires-Python: >=3.14
9
+ Description-Content-Type: text/markdown
10
+
File without changes
@@ -0,0 +1,19 @@
1
+ [project]
2
+ name = "datacomshell"
3
+ version = "0.1.0"
4
+ description = "Add your description here"
5
+ authors = [
6
+ { name = "Saven", email = "2416844857@qq.com" },
7
+ ]
8
+ readme = "README.md"
9
+ requires-python = ">=3.14"
10
+ dependencies = [
11
+ "telnetlib3>=4.0.2",
12
+ ]
13
+
14
+ [project.scripts]
15
+ datacomshell = "datacomshell:main"
16
+
17
+ [build-system]
18
+ requires = ["uv_build>=0.11.14,<0.12.0"]
19
+ build-backend = "uv_build"
@@ -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()