| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310 |
- """
- API客户端
- """
- import requests
- from typing import Dict, Any, Optional
- from src.utils.logger import get_logger
- from src.config.constants import API_BASE_URL, API_TIMEOUT, SOFTWARE_CODE, ENCRYPT_ENABLED
- from src.api.encrypt import encryptor
- logger = get_logger(__name__)
- class APIClient:
- """API客户端"""
-
- def __init__(self, base_url: str = API_BASE_URL):
- self.base_url = base_url.rstrip('/')
- self.session = requests.Session()
- self.session.timeout = API_TIMEOUT
-
- def _request(self, method: str, endpoint: str, data: Optional[Dict[str, Any]] = None,
- headers: Optional[Dict[str, str]] = None) -> Dict[str, Any]:
- """发送请求"""
- url = f"{self.base_url}{endpoint}"
-
- # 准备请求数据
- request_data = data or {}
- request_data['software_code'] = SOFTWARE_CODE
-
- # 确保公钥已加载
- self.ensure_public_key_loaded()
- # 加密数据
- encrypted_data = encryptor.encrypt(request_data)
-
- # 请求头
- request_headers = {
- 'Content-Type': 'application/json',
- **(headers or {})
- }
-
- try:
- response = self.session.request(
- method=method,
- url=url,
- json={'encrypted': encrypted_data},
- headers=request_headers
- )
- response.raise_for_status()
- return response.json()
- except requests.exceptions.Timeout:
- logger.error(f"API请求超时: {url}")
- raise Exception("请求超时,请检查网络连接")
- except requests.exceptions.ConnectionError:
- logger.error(f"API连接失败: {url}")
- raise Exception("无法连接到服务器,请检查网络连接")
- except requests.exceptions.HTTPError as e:
- logger.error(f"API HTTP错误: {e.response.status_code} - {url}")
- try:
- error_data = e.response.json()
- error_msg = error_data.get("msg", f"请求失败: {e.response.status_code}")
- except:
- error_msg = f"请求失败: {e.response.status_code}"
- raise Exception(error_msg)
- except requests.exceptions.RequestException as e:
- logger.error(f"API请求失败: {e} - {url}")
- raise Exception(f"请求失败: {str(e)}")
-
- def register(self, username: str, password: str, email: str,
- card_code: str, machine_code: str) -> Dict[str, Any]:
- """用户注册"""
- return self._request('POST', '/api/user/register', {
- 'username': username,
- 'password': password,
- 'email': email,
- 'card_code': card_code,
- 'machine_code': machine_code
- })
-
- def login(self, username: str, password: str, machine_code: str) -> Dict[str, Any]:
- """用户登录"""
- return self._request('POST', '/api/user/login', {
- 'username': username,
- 'password': password,
- 'machine_code': machine_code
- })
-
- def unbind(self, username: str, password: str) -> Dict[str, Any]:
- """机器解绑"""
- return self._request('POST', '/api/user/unbind', {
- 'username': username,
- 'password': password
- })
-
- def heartbeat(self, user_id: int) -> Dict[str, Any]:
- """心跳检测"""
- return self._request('POST', '/api/user/heartbeat', {
- 'user_id': user_id
- })
-
- def activate_card(self, user_id: int, card_code: str) -> Dict[str, Any]:
- """激活卡密(充值)"""
- return self._request('POST', '/api/user/activate-card', {
- 'user_id': user_id,
- 'card_code': card_code
- })
-
- def get_recharge_records(self, user_id: int) -> Dict[str, Any]:
- """获取充值记录"""
- # GET请求需要特殊处理,因为需要传递加密数据
- url = f"{self.base_url}/api/user/recharge-records"
-
- # 准备请求数据
- request_data = {
- 'user_id': user_id,
- 'software_code': SOFTWARE_CODE
- }
-
- # 加密数据
- encrypted_data = encryptor.encrypt(request_data)
-
- try:
- response = self.session.get(
- url,
- params={'encrypted': encrypted_data},
- timeout=API_TIMEOUT
- )
- response.raise_for_status()
- return response.json()
- except requests.exceptions.Timeout:
- logger.error(f"API请求超时: {url}")
- raise Exception("请求超时,请检查网络连接")
- except requests.exceptions.ConnectionError:
- logger.error(f"API连接失败: {url}")
- raise Exception("无法连接到服务器,请检查网络连接")
- except requests.exceptions.HTTPError as e:
- logger.error(f"API HTTP错误: {e.response.status_code} - {url}")
- try:
- error_data = e.response.json()
- error_msg = error_data.get("msg", f"请求失败: {e.response.status_code}")
- except:
- error_msg = f"请求失败: {e.response.status_code}"
- raise Exception(error_msg)
- except requests.exceptions.RequestException as e:
- logger.error(f"API请求失败: {e} - {url}")
- raise Exception(f"请求失败: {str(e)}")
-
- def get_public_key(self) -> Dict[str, Any]:
- """获取公钥"""
- # 心跳接口不需要加密
- url = f"{self.base_url}/api/keys/public"
- response = self.session.get(url, timeout=API_TIMEOUT)
- response.raise_for_status()
- return response.json()
- def refresh_public_key(self) -> bool:
- """主动刷新公钥"""
- if not ENCRYPT_ENABLED:
- return True
- try:
- result = self.get_public_key()
- if result.get("code") == 200:
- data = result.get("data", {})
- public_key = data.get("public_key")
- if public_key:
- encryptor.load_public_key(public_key)
- logger.info("公钥刷新成功")
- return True
- raise ValueError("公钥数据为空")
- raise ValueError(result.get("msg", "获取公钥失败"))
- except Exception as e:
- logger.error(f"刷新公钥失败: {e}")
- raise Exception("获取公钥失败,请稍后重试")
- def ensure_public_key_loaded(self):
- """确保公钥已加载(必要时自动刷新)"""
- if not ENCRYPT_ENABLED:
- return
- if encryptor.public_key:
- return
- self.refresh_public_key()
-
- def get_announcement(self, page: int = 1, page_size: int = 10, keyword: Optional[str] = None) -> Dict[str, Any]:
- """获取公告(支持分页与检索)"""
- # 公告接口不需要加密,使用查询参数
- url = f"{self.base_url}/api/announcement"
- params: Dict[str, Any] = {
- "page": page,
- "page_size": page_size,
- }
- if keyword:
- params["keyword"] = keyword
- response = self.session.get(url, params=params, timeout=API_TIMEOUT)
- response.raise_for_status()
- return response.json()
-
- def get_steam_accounts(self, user_id: int) -> Dict[str, Any]:
- """获取Steam账号列表"""
- url = f"{self.base_url}/api/user/steam-accounts"
-
- # 准备请求数据
- request_data = {
- 'user_id': user_id,
- 'software_code': SOFTWARE_CODE
- }
-
- # 加密数据
- encrypted_data = encryptor.encrypt(request_data)
-
- try:
- response = self.session.get(
- url,
- params={'encrypted': encrypted_data},
- timeout=API_TIMEOUT
- )
- response.raise_for_status()
- return response.json()
- except requests.exceptions.Timeout:
- logger.error(f"API请求超时: {url}")
- raise Exception("请求超时,请检查网络连接")
- except requests.exceptions.ConnectionError:
- logger.error(f"API连接失败: {url}")
- raise Exception("无法连接到服务器,请检查网络连接")
- except requests.exceptions.HTTPError as e:
- logger.error(f"API HTTP错误: {e.response.status_code} - {url}")
- try:
- error_data = e.response.json()
- error_msg = error_data.get("msg", f"请求失败: {e.response.status_code}")
- except:
- error_msg = f"请求失败: {e.response.status_code}"
- raise Exception(error_msg)
- except requests.exceptions.RequestException as e:
- logger.error(f"API请求失败: {e} - {url}")
- raise Exception(f"请求失败: {str(e)}")
-
- def create_steam_account(self, user_id: int, steam_username: str,
- shared_secret: str, identity_secret: str,
- steam_id: Optional[str] = None) -> Dict[str, Any]:
- """添加Steam账号"""
- return self._request('POST', '/api/user/steam-accounts', {
- 'user_id': user_id,
- 'steam_username': steam_username,
- 'steam_id': steam_id,
- 'shared_secret': shared_secret,
- 'identity_secret': identity_secret
- })
-
- def update_steam_account(self, user_id: int, account_id: int,
- steam_username: Optional[str] = None,
- shared_secret: Optional[str] = None,
- identity_secret: Optional[str] = None,
- steam_id: Optional[str] = None,
- is_active: Optional[int] = None) -> Dict[str, Any]:
- """更新Steam账号"""
- data = {'user_id': user_id}
- if steam_username is not None:
- data['steam_username'] = steam_username
- if shared_secret is not None:
- data['shared_secret'] = shared_secret
- if identity_secret is not None:
- data['identity_secret'] = identity_secret
- if steam_id is not None:
- data['steam_id'] = steam_id
- if is_active is not None:
- data['is_active'] = is_active
-
- return self._request('PUT', f'/api/user/steam-accounts/{account_id}', data)
-
- def delete_steam_account(self, user_id: int, account_id: int) -> Dict[str, Any]:
- """删除Steam账号"""
- # DELETE请求需要特殊处理
- url = f"{self.base_url}/api/user/steam-accounts/{account_id}"
-
- # 准备请求数据
- request_data = {
- 'user_id': user_id,
- 'software_code': SOFTWARE_CODE
- }
-
- # 加密数据
- encrypted_data = encryptor.encrypt(request_data)
-
- try:
- response = self.session.delete(
- url,
- json={'encrypted': encrypted_data},
- timeout=API_TIMEOUT
- )
- response.raise_for_status()
- return response.json()
- except requests.exceptions.Timeout:
- logger.error(f"API请求超时: {url}")
- raise Exception("请求超时,请检查网络连接")
- except requests.exceptions.ConnectionError:
- logger.error(f"API连接失败: {url}")
- raise Exception("无法连接到服务器,请检查网络连接")
- except requests.exceptions.HTTPError as e:
- logger.error(f"API HTTP错误: {e.response.status_code} - {url}")
- try:
- error_data = e.response.json()
- error_msg = error_data.get("msg", f"请求失败: {e.response.status_code}")
- except:
- error_msg = f"请求失败: {e.response.status_code}"
- raise Exception(error_msg)
- except requests.exceptions.RequestException as e:
- logger.error(f"API请求失败: {e} - {url}")
- raise Exception(f"请求失败: {str(e)}")
- # 全局API客户端实例
- api_client = APIClient()
|