{"id":28528645,"url":"https://github.com/returnfi/hysteria2-api","last_synced_at":"2026-02-21T14:31:55.647Z","repository":{"id":287193332,"uuid":"963932322","full_name":"ReturnFI/Hysteria2-API","owner":"ReturnFI","description":"A Python package for interacting with the Hysteria2 proxy server API.","archived":false,"fork":false,"pushed_at":"2025-06-10T09:55:48.000Z","size":29,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-09-18T04:56:38.699Z","etag":null,"topics":["api","hysteria2","hysteria2-api","pypi","pypi-package"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ReturnFI.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2025-04-10T12:39:01.000Z","updated_at":"2025-08-22T04:02:30.000Z","dependencies_parsed_at":"2025-04-10T13:37:07.102Z","dependency_job_id":"eeeae138-edd8-47b2-9b2a-c9ecf966a861","html_url":"https://github.com/ReturnFI/Hysteria2-API","commit_stats":null,"previous_names":["returnfi/hysteria2-api"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/ReturnFI/Hysteria2-API","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ReturnFI%2FHysteria2-API","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ReturnFI%2FHysteria2-API/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ReturnFI%2FHysteria2-API/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ReturnFI%2FHysteria2-API/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ReturnFI","download_url":"https://codeload.github.com/ReturnFI/Hysteria2-API/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ReturnFI%2FHysteria2-API/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29683935,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-21T14:31:22.911Z","status":"ssl_error","status_checked_at":"2026-02-21T14:31:22.570Z","response_time":107,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["api","hysteria2","hysteria2-api","pypi","pypi-package"],"created_at":"2025-06-09T13:10:21.807Z","updated_at":"2026-02-21T14:31:55.634Z","avatar_url":"https://github.com/ReturnFI.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Hysteria2-API\n\n[![PyPI version](https://badge.fury.io/py/hysteria2-api.svg)](https://badge.fury.io/py/hysteria2-api)\n[![Python Versions](https://img.shields.io/pypi/pyversions/hysteria2-api.svg)](https://pypi.org/project/hysteria2-api/)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nA Python client library for interacting with the Hysteria2 proxy server API.\n\n## Installation\n\n```bash\npip install hysteria2-api\n```\n\n## Quick Start\n\n```python\nfrom hysteria2_api import Hysteria2Client\n\n# Initialize the client\nclient = Hysteria2Client(\n    base_url=\"http://127.0.0.1:25413\",  # Replace with your Hysteria2 API URL\n    secret=\"your_secret_here\"           # Replace with your API secret\n)\n\n# Get traffic statistics with automatic clearing\ntraffic_stats = client.get_traffic_stats(clear=True)\nfor user_id, stats in traffic_stats.items():\n    print(f\"User: {user_id}\")\n    print(f\"Upload: {stats.upload_bytes} bytes\")\n    print(f\"Download: {stats.download_bytes} bytes\")\n\n# Check which users are online\nonline_users = client.get_online_clients()\nfor user_id, status in online_users.items():\n    if status.is_online:\n        print(f\"User {user_id} is online with {status.connections} connection(s)\")\n\n# Kick specific users\nclient.kick_clients([\"user1\", \"user2\"])\n```\n\n## Features\n\n- **Traffic Statistics**: Get traffic data for all clients with option to clear after retrieval\n- **Online Status**: Check which clients are currently connected and how many connections they have\n- **User Management**: Kick clients by their IDs\n- **Type Support**: Full type hinting support for better IDE integration\n- **Error Handling**: Specialized exception classes for different error scenarios\n\n## API Reference\n\n### Hysteria2Client\n\nThe main client class for interacting with the Hysteria2 API.\n\n```python\nclient = Hysteria2Client(\n    base_url=\"http://127.0.0.1:25413\",  # Base URL of the Hysteria2 API\n    secret=\"your_secret_here\",          # API secret for authentication\n    timeout=10                          # Request timeout in seconds\n)\n```\n\n#### Methods\n\n- **get_traffic_stats(clear=False)**\n  - Gets traffic statistics for all clients\n  - Parameters:\n    - `clear` (bool): Whether to clear statistics after retrieval\n  - Returns: Dictionary mapping client IDs to `TrafficStats` objects\n\n- **get_online_clients()**\n  - Gets online status for all clients\n  - Returns: Dictionary mapping client IDs to `OnlineStatus` objects\n\n- **kick_clients(client_ids)**\n  - Kicks clients by their IDs\n  - Parameters:\n    - `client_ids` (List[str]): List of client IDs to kick\n  - Returns: True if successful, raises exception otherwise\n\n### Data Models\n\n#### TrafficStats\n\nRepresents traffic statistics for a client.\n\n```python\nstats = TrafficStats(tx=1024, rx=2048)\n```\n\n- **Properties**:\n  - `tx` (int): Transmitted bytes (upload)\n  - `rx` (int): Received bytes (download)\n  - `upload_bytes` (int): Alias for tx\n  - `download_bytes` (int): Alias for rx\n\n#### OnlineStatus\n\nRepresents online status information for clients.\n\n```python\nstatus = OnlineStatus(connections=2)\n```\n\n- **Properties**:\n  - `connections` (int): Number of active connections\n  - `is_online` (bool): Whether the client is online (has at least one connection)\n\n### Exceptions\n\n- **Hysteria2Error**: Base exception for all Hysteria2 API errors\n- **Hysteria2AuthError**: Raised when authentication with the API fails\n- **Hysteria2ConnectionError**: Raised when there's an error connecting to the API\n\n## Example: Traffic Monitoring Script\n\nHere's an example of a script that monitors traffic and updates a local JSON file:\n\n```python\n#!/usr/bin/env python3\nimport json\nimport os\nfrom hysteria2_api import Hysteria2Client\n\n# Define static variables\nCONFIG_FILE = '/etc/hysteria/config.json'\nUSERS_FILE = '/etc/hysteria/users.json'\nAPI_BASE_URL = 'http://127.0.0.1:25413'\n\ndef traffic_status():\n    # ANSI color codes\n    green = '\\033[0;32m'\n    cyan = '\\033[0;36m'\n    NC = '\\033[0m'  # No Color\n\n    # Load config to get API secret\n    with open(CONFIG_FILE, 'r') as config_file:\n        config = json.load(config_file)\n        secret = config.get('trafficStats', {}).get('secret')\n\n    if not secret:\n        print(\"Error: Secret not found in config.json\")\n        return\n\n    # Initialize API client\n    client = Hysteria2Client(base_url=API_BASE_URL, secret=secret)\n\n    # Get data from API\n    traffic_stats = client.get_traffic_stats(clear=True)\n    online_status = client.get_online_clients()\n\n    # Load existing user data\n    users_data = {}\n    if os.path.exists(USERS_FILE):\n        with open(USERS_FILE, 'r') as users_file:\n            users_data = json.load(users_file)\n\n    # Update user data with new information\n    for user_id in list(users_data.keys()):\n        users_data[user_id][\"status\"] = \"Offline\"\n\n    for user_id, status in online_status.items():\n        if user_id in users_data:\n            users_data[user_id][\"status\"] = \"Online\" if status.is_online else \"Offline\"\n        else:\n            users_data[user_id] = {\n                \"upload_bytes\": 0,\n                \"download_bytes\": 0,\n                \"status\": \"Online\" if status.is_online else \"Offline\"\n            }\n\n    for user_id, stats in traffic_stats.items():\n        if user_id in users_data:\n            users_data[user_id][\"upload_bytes\"] += stats.upload_bytes\n            users_data[user_id][\"download_bytes\"] += stats.download_bytes\n        else:\n            online = user_id in online_status and online_status[user_id].is_online\n            users_data[user_id] = {\n                \"upload_bytes\": stats.upload_bytes,\n                \"download_bytes\": stats.download_bytes,\n                \"status\": \"Online\" if online else \"Offline\"\n            }\n\n    # Save updated data\n    with open(USERS_FILE, 'w') as users_file:\n        json.dump(users_data, users_file, indent=4)\n\n    # Display traffic data\n    print(\"Traffic Data:\")\n    print(\"-------------------------------------------------\")\n    print(f\"{'User':\u003c15} {'Upload':\u003c15} {'Download':\u003c15} {'Status':\u003c10}\")\n    print(\"-------------------------------------------------\")\n\n    for user, entry in users_data.items():\n        upload = format_bytes(entry.get(\"upload_bytes\", 0))\n        download = format_bytes(entry.get(\"download_bytes\", 0))\n        status = entry.get(\"status\", \"Offline\")\n\n        print(f\"{user:\u003c15} {green}{upload:\u003c15}{NC} {cyan}{download:\u003c15}{NC} {status:\u003c10}\")\n\ndef format_bytes(bytes):\n    for unit in ['B', 'KB', 'MB', 'GB', 'TB']:\n        if bytes \u003c 1024:\n            return f\"{bytes:.2f}{unit}\"\n        bytes /= 1024\n    return f\"{bytes:.2f}PB\"\n\nif __name__ == \"__main__\":\n    traffic_status()\n```\n\n## Contributing\n\nContributions are welcome! Please feel free to submit a Pull Request.\n\n1. Fork the repository\n2. Create your feature branch (`git checkout -b feature/amazing-feature`)\n3. Commit your changes (`git commit -m 'Add some amazing feature'`)\n4. Push to the branch (`git push origin feature/amazing-feature`)\n5. Open a Pull Request\n\n## License\n\nThis project is licensed under the MIT License - see the LICENSE file for details.\n\n## Acknowledgments\n\n- [Hysteria2](https://github.com/apernet/hysteria) - The high-performance proxy protocol this library interacts with","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Freturnfi%2Fhysteria2-api","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Freturnfi%2Fhysteria2-api","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Freturnfi%2Fhysteria2-api/lists"}