1 Commits

Author SHA1 Message Date
xiaochao
03f8f3fa21 Update coordinator.py 2025-07-04 17:44:56 +08:00
2 changed files with 91 additions and 78 deletions

View File

@@ -69,39 +69,46 @@ class FlynasCoordinator(DataUpdateCoordinator):
async def get_ssh_connection(self): async def get_ssh_connection(self):
"""从连接池获取或创建SSH连接""" """从连接池获取或创建SSH连接"""
# 如果连接池中有可用连接且没有超过最大活动命令数 # 避免递归调用,改为循环等待
while len(self.ssh_pool) > 0 and self.active_commands < self.max_connections: start_time = time.time()
conn = self.ssh_pool.pop() while True:
if await self.is_connection_alive(conn): # 如果连接池中有可用连接且没有超过最大活动命令数
self.active_commands += 1 while len(self.ssh_pool) > 0 and self.active_commands < self.max_connections:
return conn conn = self.ssh_pool.pop()
else: if await self.is_connection_alive(conn):
await self.close_connection(conn) self.active_commands += 1
return conn
else:
await self.close_connection(conn)
# 如果没有可用连接,创建新连接 # 如果没有可用连接,创建新连接
if self.active_commands < self.max_connections: if self.active_commands < self.max_connections:
try: try:
conn = await asyncssh.connect( conn = await asyncssh.connect(
self.host, self.host,
port=self.port, port=self.port,
username=self.username, username=self.username,
password=self.password, password=self.password,
known_hosts=None, known_hosts=None,
connect_timeout=10 connect_timeout=10
) )
self.active_commands += 1 self.active_commands += 1
self.ssh_closed = False self.ssh_closed = False
# 确定是否需要sudo权限 # 确定是否需要sudo权限
await self.determine_sudo_setting(conn) await self.determine_sudo_setting(conn)
return conn return conn
except Exception as e: except Exception as e:
_LOGGER.error("创建SSH连接失败: %s", str(e), exc_info=True) _LOGGER.error("创建SSH连接失败: %s", str(e), exc_info=True)
raise UpdateFailed(f"SSH连接失败: {str(e)}") raise UpdateFailed(f"SSH连接失败: {str(e)}")
else:
# 等待0.1秒后重试,避免递归
await asyncio.sleep(0.1) await asyncio.sleep(0.1)
return await self.get_ssh_connection()
# 设置超时30秒
if time.time() - start_time > 30:
raise UpdateFailed("获取SSH连接超时")
async def determine_sudo_setting(self, conn): async def determine_sudo_setting(self, conn):
"""确定是否需要使用sudo权限""" """确定是否需要使用sudo权限"""
@@ -179,52 +186,58 @@ class FlynasCoordinator(DataUpdateCoordinator):
async def run_command(self, command: str, retries=2) -> str: async def run_command(self, command: str, retries=2) -> str:
"""使用连接池执行命令""" """使用连接池执行命令"""
conn = None conn = None
try: current_retries = retries
conn = await self.get_ssh_connection()
# 根据sudo设置执行命令 while current_retries >= 0:
if self.use_sudo: try:
password = self.root_password if self.root_password else self.password conn = await self.get_ssh_connection()
if password:
full_command = f"sudo -S {command}" # 根据sudo设置执行命令
result = await conn.run(full_command, input=password + "\n", check=True) if self.use_sudo:
password = self.root_password if self.root_password else self.password
if password:
full_command = f"sudo -S {command}"
result = await conn.run(full_command, input=password + "\n", check=True)
else:
full_command = f"sudo {command}"
result = await conn.run(full_command, check=True)
else: else:
full_command = f"sudo {command}" result = await conn.run(command, check=True)
result = await conn.run(full_command, check=True)
else:
result = await conn.run(command, check=True)
return result.stdout.strip() return result.stdout.strip()
except asyncssh.process.ProcessError as e: except asyncssh.process.ProcessError as e:
if e.exit_status in [4, 32]: if e.exit_status in [4, 32]:
return "" return ""
_LOGGER.error("Command failed: %s (exit %d)", command, e.exit_status) _LOGGER.error("Command failed: %s (exit %d)", command, e.exit_status)
# 连接可能已损坏,关闭它 # 连接可能已损坏,关闭它
await self.close_connection(conn) await self.close_connection(conn)
conn = None conn = None
if retries > 0: if current_retries > 0:
return await self.run_command(command, retries-1) current_retries -= 1
else: continue
raise UpdateFailed(f"Command failed: {command}") from e else:
except asyncssh.Error as e: raise UpdateFailed(f"Command failed: {command}") from e
_LOGGER.error("SSH连接错误: %s", str(e)) except asyncssh.Error as e:
await self.close_connection(conn) _LOGGER.error("SSH连接错误: %s", str(e))
conn = None await self.close_connection(conn)
if retries > 0: conn = None
return await self.run_command(command, retries-1) if current_retries > 0:
else: current_retries -= 1
raise UpdateFailed(f"SSH错误: {str(e)}") from e continue
except Exception as e: else:
_LOGGER.error("意外错误: %s", str(e), exc_info=True) raise UpdateFailed(f"SSH错误: {str(e)}") from e
await self.close_connection(conn) except Exception as e:
conn = None _LOGGER.error("意外错误: %s", str(e), exc_info=True)
if retries > 0: await self.close_connection(conn)
return await self.run_command(command, retries-1) conn = None
else: if current_retries > 0:
raise UpdateFailed(f"意外错误: {str(e)}") from e current_retries -= 1
finally: continue
if conn: else:
await self.release_ssh_connection(conn) raise UpdateFailed(f"意外错误: {str(e)}") from e
finally:
if conn:
await self.release_ssh_connection(conn)
async def async_connect(self): async def async_connect(self):
"""建立SSH连接使用连接池""" """建立SSH连接使用连接池"""

View File

@@ -1,7 +1,7 @@
{ {
"domain": "fn_nas", "domain": "fn_nas",
"name": "飞牛NAS", "name": "飞牛NAS",
"version": "1.3.1", "version": "1.3.3",
"documentation": "https://github.com/anxms/fn_nas", "documentation": "https://github.com/anxms/fn_nas",
"dependencies": [], "dependencies": [],
"codeowners": ["@anxms"], "codeowners": ["@anxms"],