From 8a8450319162965e013e78c90b2a71b8850e1721 Mon Sep 17 00:00:00 2001 From: Artem Date: Thu, 21 Aug 2025 23:58:28 +0200 Subject: [PATCH 1/6] =?UTF-8?q?feat:=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D1=82=D1=8C=20=D1=8D=D0=BD=D0=B4=D0=BF=D0=BE=D0=B8=D0=BD?= =?UTF-8?q?=D1=82=20=D0=B4=D0=BB=D1=8F=20=D0=BF=D0=BE=D0=BB=D1=83=D1=87?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D1=8F=20=D1=81=D1=8B=D1=80=D0=BE=D0=B9=20?= =?UTF-8?q?=D0=BF=D0=BE=D0=B4=D0=BF=D0=B8=D1=81=D0=BA=D0=B8=20=D0=BF=D0=BE?= =?UTF-8?q?=20=D0=BA=D0=BE=D1=80=D0=BE=D1=82=D0=BA=D0=BE=D0=BC=D1=83=20UUI?= =?UTF-8?q?D=20=D0=B8=20=D0=BE=D0=B1=D0=BD=D0=BE=D0=B2=D0=B8=D1=82=D1=8C?= =?UTF-8?q?=20=D0=BC=D0=BE=D0=B4=D0=B5=D0=BB=D0=B8=20=D0=BF=D0=BE=D0=B4?= =?UTF-8?q?=D0=BF=D0=B8=D1=81=D0=BA=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- remnawave/controllers/subscription.py | 12 ++++- remnawave/controllers/users.py | 8 ---- remnawave/models/subscription.py | 67 +++++++++++++++++++++++++++ remnawave/models/users.py | 3 -- tests/test_users.py | 1 - 5 files changed, 78 insertions(+), 13 deletions(-) diff --git a/remnawave/controllers/subscription.py b/remnawave/controllers/subscription.py index 860cad8..32ac88f 100644 --- a/remnawave/controllers/subscription.py +++ b/remnawave/controllers/subscription.py @@ -3,7 +3,7 @@ from typing import Annotated from rapid_api_client import Path from remnawave.enums import ClientType -from remnawave.models import GetSubscriptionInfoResponseDto +from remnawave.models import GetSubscriptionInfoResponseDto, GetRawSubscriptionByShortUuidResponseDto from remnawave.rapid import BaseController, get @@ -52,3 +52,13 @@ class SubscriptionController(BaseController): ) -> str: """None""" ... + + # get raw sub by short uuid + @get("/sub/{short_uuid}/raw", response_class=GetRawSubscriptionByShortUuidResponseDto) + async def get_raw_subscription( + self, + short_uuid: Annotated[str, Path(description="Short UUID of the user")], + withDisabledHosts: Annotated[Annotated[bool, Path(description="Include disabled hosts")], bool] = False, + ) -> GetRawSubscriptionByShortUuidResponseDto: + """None""" + ... \ No newline at end of file diff --git a/remnawave/controllers/users.py b/remnawave/controllers/users.py index b8b92ce..d0bd942 100644 --- a/remnawave/controllers/users.py +++ b/remnawave/controllers/users.py @@ -93,14 +93,6 @@ class UsersController(BaseController): ) -> UserResponseDto: """Reset User Traffic""" ... - - @post("/users/{uuid}/actions/activate-all-inbounds", response_class=UserResponseDto) - async def activate_all_inbounds( - self, - uuid: Annotated[str, Path(description="UUID of the user")], - ) -> UserResponseDto: - """Activate All Inbounds""" - ... @get("/users/by-short-uuid/{short_uuid}", response_class=UserResponseDto) async def get_user_by_short_uuid( diff --git a/remnawave/models/subscription.py b/remnawave/models/subscription.py index 3d587ce..18969cd 100644 --- a/remnawave/models/subscription.py +++ b/remnawave/models/subscription.py @@ -16,6 +16,10 @@ class UserSubscription(BaseModel): days_left: int = Field(alias="daysLeft") traffic_used: str = Field(alias="trafficUsed") traffic_limit: str = Field(alias="trafficLimit") + lifetime_traffic_used: str = Field(alias="lifetimeTrafficUsed") + traffic_used_bytes: str = Field(alias="trafficUsedBytes") + traffic_limit_bytes: str = Field(alias="trafficLimitBytes") + lifetime_traffic_used_bytes: int = Field(alias="lifetimeTrafficUsedBytes") traffic_limit_strategy: TrafficLimitStrategy = Field(alias="trafficLimitStrategy") expires_at: datetime = Field(alias="expiresAt") user_status: UserStatus = Field(alias="userStatus") @@ -40,6 +44,69 @@ class GetSubscriptionInfoResponseDto(BaseModel): happ: HappCrypto +class RawHostAdditionalParams(BaseModel): + mode: Optional[str] = None + heartbeat_period: Optional[int] = Field(None, alias="heartbeatPeriod") + + +class RawHostProtocolOptions(BaseModel): + class SSOptions(BaseModel): + method: Optional[str] = None + + ss: Optional[SSOptions] = None + + +class RawHostDbData(BaseModel): + raw_inbound: Optional[Dict[str, Any]] = Field(alias="rawInbound") + inbound_tag: str = Field(alias="inboundTag") + uuid: str + config_profile_uuid: Optional[str] = Field(alias="configProfileUuid") + config_profile_inbound_uuid: Optional[str] = Field(alias="configProfileInboundUuid") + is_disabled: bool = Field(alias="isDisabled") + view_position: int = Field(alias="viewPosition") + remark: str + is_hidden: bool = Field(alias="isHidden") + tag: Optional[str] = None + + +class RawHost(BaseModel): + address: Optional[str] = None + alpn: Optional[str] = None + fingerprint: Optional[str] = None + host: Optional[str] = None + network: Optional[str] = None + password: Optional[str] = None + path: Optional[str] = None + public_key: Optional[str] = Field(None, alias="publicKey") + port: Optional[int] = None + protocol: Optional[str] = None + remark: Optional[str] = None + short_id: Optional[str] = Field(None, alias="shortId") + sni: Optional[str] = None + spider_x: Optional[str] = Field(None, alias="spiderX") + tls: Optional[str] = None + header_type: Optional[str] = Field(None, alias="headerType") + additional_params: Optional[RawHostAdditionalParams] = Field(None, alias="additionalParams") + x_http_extra_params: Optional[Dict[str, Any]] = Field(None, alias="xHttpExtraParams") + mux_params: Optional[Dict[str, Any]] = Field(None, alias="muxParams") + sockopt_params: Optional[Dict[str, Any]] = Field(None, alias="sockoptParams") + server_description: Optional[str] = Field(None, alias="serverDescription") + flow: Optional[str] = None + protocol_options: Optional[RawHostProtocolOptions] = Field(None, alias="protocolOptions") + db_data: RawHostDbData = Field(alias="dbData") + + +class RawSubscriptionResponse(BaseModel): + user: UserSubscription + subscription_url: str = Field(alias="subscriptionUrl") + raw_hosts: List[RawHost] = Field(alias="rawHosts") + headers: Dict[str, str] + is_hwid_limited: bool = Field(alias="isHwidLimited") + + +class GetRawSubscriptionByShortUuidResponseDto(RawSubscriptionResponse): + pass + class SubscriptionWithoutHapp(BaseModel): is_found: bool = Field(alias="isFound") user: UserSubscription diff --git a/remnawave/models/users.py b/remnawave/models/users.py index 18120d2..b56ee30 100644 --- a/remnawave/models/users.py +++ b/remnawave/models/users.py @@ -71,9 +71,6 @@ class CreateUserRequestDto(BaseModel): hwidDeviceLimit: Optional[int] = Field( None, serialization_alias="hwidDeviceLimit", strict=True, ge=0 ) - activate_all_inbounds: Optional[bool] = Field( - None, serialization_alias="activateAllInbounds" - ) active_internal_squads: Optional[List[str]] = Field( None, serialization_alias="activeInternalSquads" ) diff --git a/tests/test_users.py b/tests/test_users.py index 500093b..8972b68 100644 --- a/tests/test_users.py +++ b/tests/test_users.py @@ -34,7 +34,6 @@ async def test_users(remnawave) -> None: email=email, telegram_id=telegram_id, expire_at=expire_at, - activate_all_inbounds=True, ) ) From 8e34b50c6c8cd23083e324ad35f71121f2dc3261 Mon Sep 17 00:00:00 2001 From: Artem Date: Mon, 25 Aug 2025 15:38:14 +0200 Subject: [PATCH 2/6] =?UTF-8?q?feat:=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D1=82=D1=8C=20=D0=BC=D0=BE=D0=B4=D0=B5=D0=BB=D1=8C=20Tag?= =?UTF-8?q?UserResponseDto=20=D0=B8=20=D0=BE=D0=B1=D0=BD=D0=BE=D0=B2=D0=B8?= =?UTF-8?q?=D1=82=D1=8C=20=D0=BA=D0=BE=D0=BD=D1=82=D1=80=D0=BE=D0=BB=D0=BB?= =?UTF-8?q?=D0=B5=D1=80=20=D0=BF=D0=BE=D0=BB=D1=8C=D0=B7=D0=BE=D0=B2=D0=B0?= =?UTF-8?q?=D1=82=D0=B5=D0=BB=D0=B5=D0=B9=20=D0=B4=D0=BB=D1=8F=20=D0=B8?= =?UTF-8?q?=D1=81=D0=BF=D0=BE=D0=BB=D1=8C=D0=B7=D0=BE=D0=B2=D0=B0=D0=BD?= =?UTF-8?q?=D0=B8=D1=8F=20=D0=BD=D0=BE=D0=B2=D0=BE=D0=B9=20=D0=BC=D0=BE?= =?UTF-8?q?=D0=B4=D0=B5=D0=BB=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- remnawave/controllers/users.py | 31 +++++++++++++++++++++---------- remnawave/models/__init__.py | 2 ++ remnawave/models/users.py | 8 ++++++++ 3 files changed, 31 insertions(+), 10 deletions(-) diff --git a/remnawave/controllers/users.py b/remnawave/controllers/users.py index d0bd942..3809c07 100644 --- a/remnawave/controllers/users.py +++ b/remnawave/controllers/users.py @@ -13,7 +13,8 @@ from remnawave.models import ( UserResponseDto, UsersResponseDto, TagsResponseDto, - RevokeUserRequestDto + TagUserResponseDto, + RevokeUserRequestDto, ) from remnawave.rapid import BaseController, delete, get, patch, post @@ -38,8 +39,12 @@ class UsersController(BaseController): @get("/users", response_class=UsersResponseDto) async def get_all_users_v2( self, - start: Annotated[int, Query(default=0, ge=0, description="Index to start pagination from")], - size: Annotated[int, Query(default=25, ge=1, description="Number of users per page")], + start: Annotated[ + int, Query(default=0, ge=0, description="Index to start pagination from") + ], + size: Annotated[ + int, Query(default=25, ge=1, description="Number of users per page") + ], ) -> UsersResponseDto: """ Get users page from the end. @@ -52,7 +57,7 @@ class UsersController(BaseController): UsersResponseDto """ ... - + @delete("/users/{uuid}", response_class=DeleteUserResponseDto) async def delete_user( self, @@ -102,7 +107,10 @@ class UsersController(BaseController): """Get User By Short UUID""" ... - @get("/users/by-subscription-uuid/{subscription_uuid}", response_class=UserResponseDto) + @get( + "/users/by-subscription-uuid/{subscription_uuid}", + response_class=UserResponseDto, + ) async def get_user_by_subscription_uuid( self, subscription_uuid: Annotated[str, Path(description="UUID of the subscription")], @@ -145,14 +153,14 @@ class UsersController(BaseController): """Get Users By Email""" ... - @get("/users/by-tag/{tag}", response_class=UsersResponseDto) + @get("/users/by-tag/{tag}", response_class=TagUserResponseDto) async def get_users_by_tag( self, tag: Annotated[str, Path(description="Tag of the user")], - ) -> UsersResponseDto: + ) -> TagUserResponseDto: """Get Users By Tag""" ... - + @get("/users/tags", response_class=TagsResponseDto) async def get_all_tags( self, @@ -160,10 +168,13 @@ class UsersController(BaseController): """Get All Tags""" ... - @get("/users/{uuid}/accessible-nodes", response_class=GetUserAccessibleNodesResponseDto) + @get( + "/users/{uuid}/accessible-nodes", + response_class=GetUserAccessibleNodesResponseDto, + ) async def get_user_accessible_nodes( self, uuid: Annotated[str, Path(description="UUID of the user")], ) -> GetUserAccessibleNodesResponseDto: """Get User Accessible Nodes""" - ... \ No newline at end of file + ... diff --git a/remnawave/models/__init__.py b/remnawave/models/__init__.py index 896bc21..b40533f 100644 --- a/remnawave/models/__init__.py +++ b/remnawave/models/__init__.py @@ -208,6 +208,7 @@ from .users import ( UserResponseDto, UsersResponseDto, TagsResponseDto, + TagUserResponseDto, RevokeUserRequestDto, ) from .users_bulk_actions import ( @@ -379,6 +380,7 @@ __all__ = [ "UserLastConnectedNodeDto", "UserResponseDto", "UsersResponseDto", + "TagUserResponseDto", # Users bulk actions models "BulkAllResetTrafficUsersResponseDto", "BulkAllUpdateUsersRequestDto", diff --git a/remnawave/models/users.py b/remnawave/models/users.py index b56ee30..bc6b4a7 100644 --- a/remnawave/models/users.py +++ b/remnawave/models/users.py @@ -154,6 +154,14 @@ class EmailUserResponseDto(RootModel[List[UserResponseDto]]): return self.root[item] +class TagUserResponseDto(RootModel[List[UserResponseDto]]): + def __iter__(self): + return iter(self.root) + + def __getitem__(self, item): + return self.root[item] + + class TelegramUserResponseDto(RootModel[List[UserResponseDto]]): def __iter__(self): return iter(self.root) From d3ad6ea3304fcbf45f3d9e159d6e82fbd3b86c55 Mon Sep 17 00:00:00 2001 From: Artem Date: Mon, 25 Aug 2025 15:40:44 +0200 Subject: [PATCH 3/6] =?UTF-8?q?feat:=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D1=82=D1=8C=20=D0=BC=D0=BE=D0=B4=D0=B5=D0=BB=D1=8C=20Get?= =?UTF-8?q?RawSubscriptionByShortUuidResponseDto=20=D0=B2=20=D0=BC=D0=BE?= =?UTF-8?q?=D0=B4=D1=83=D0=BB=D1=8C=20=D0=BF=D0=BE=D0=B4=D0=BF=D0=B8=D1=81?= =?UTF-8?q?=D0=BE=D0=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- remnawave/models/__init__.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/remnawave/models/__init__.py b/remnawave/models/__init__.py index b40533f..a365f74 100644 --- a/remnawave/models/__init__.py +++ b/remnawave/models/__init__.py @@ -166,6 +166,7 @@ from .subscription import ( GetSubscriptionInfoResponseDto, SubscriptionInfoResponseDto, # Legacy alias UserSubscription, + GetRawSubscriptionByShortUuidResponseDto, ) from .subscriptions_settings import ( GetSubscriptionSettingsResponseDto, @@ -286,6 +287,7 @@ __all__ = [ "GetSubscriptionInfoResponseDto", "SubscriptionInfoResponseDto", # Legacy alias "UserSubscription", + "GetRawSubscriptionByShortUuidResponseDto", # Subscription settings models "GetSubscriptionSettingsResponseDto", "SubscriptionSettingsResponseDto", From b8db6a9241454907d19f42b13a2c933ff3b97d08 Mon Sep 17 00:00:00 2001 From: Artem Date: Mon, 25 Aug 2025 15:46:37 +0200 Subject: [PATCH 4/6] =?UTF-8?q?feat:=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D1=82=D1=8C=20=D0=BF=D0=B0=D1=80=D0=B0=D0=BC=D0=B5=D1=82?= =?UTF-8?q?=D1=80=20ssl=5Fignore=20=D0=B2=20=D0=B8=D0=BD=D0=B8=D1=86=D0=B8?= =?UTF-8?q?=D0=B0=D0=BB=D0=B8=D0=B7=D0=B0=D1=86=D0=B8=D1=8E=20RemnawaveSDK?= =?UTF-8?q?=20=D0=B4=D0=BB=D1=8F=20=D1=83=D0=BF=D1=80=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=BF=D1=80=D0=BE=D0=B2=D0=B5=D1=80?= =?UTF-8?q?=D0=BA=D0=BE=D0=B9=20SSL?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- remnawave/__init__.py | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/remnawave/__init__.py b/remnawave/__init__.py index 4d4eb92..e79f252 100644 --- a/remnawave/__init__.py +++ b/remnawave/__init__.py @@ -39,20 +39,23 @@ class RemnawaveSDK: base_url: Optional[str] = None, token: Optional[str] = None, caddy_token: Optional[str] = None, + ssl_ignore: Optional[bool] = False, ): """ Remnawave SDK init Args: - client (Optional[httpx.AsyncClient]): - Default client. + client (Optional[httpx.AsyncClient]): - Default client. base_url (Optional[str]): - Base url of the Remnawave panel. Defaults to None. - token (Optional[str]): - Token for authorization. + token (Optional[str]): - Token for authorization. caddy_token (Optional[str]): - Token for Caddy Auth (Headers). Defaults to None. + ssl_ignore (Optional[bool]): - Whether to ignore SSL certificate errors. Defaults to False. """ self._client = client self._token = token self.base_url = base_url self.caddy_token = caddy_token + self.ssl_ignore = ssl_ignore self._validate_params() @@ -98,20 +101,24 @@ class RemnawaveSDK: def _prepare_client(self) -> httpx.AsyncClient: return httpx.AsyncClient( - base_url=self._prepare_url(), headers=self._prepare_headers() + base_url=self._prepare_url(), + headers=self._prepare_headers(), + verify=not self.ssl_ignore, ) def _prepare_headers(self) -> dict: headers = {} if self._token: headers["Authorization"] = ( - self._token if self._token.startswith("Bearer ") else f"Bearer {self._token}" + self._token + if self._token.startswith("Bearer ") + else f"Bearer {self._token}" ) - + # X-Api-Key for Caddy (https://remna.st/security/caddy-with-custom-path#issuing-api-keys) if self.caddy_token is not None: headers["X-Api-Key"] = self.caddy_token - + return headers def _prepare_url(self) -> str: From 9d7f1ab0d9ab3e78fe43990016faa2053e8d4252 Mon Sep 17 00:00:00 2001 From: Artem Date: Mon, 25 Aug 2025 15:55:17 +0200 Subject: [PATCH 5/6] =?UTF-8?q?feat:=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D1=82=D1=8C=20=D0=BF=D0=BE=D0=B4=D0=B4=D0=B5=D1=80=D0=B6?= =?UTF-8?q?=D0=BA=D1=83=20=D0=BF=D0=BE=D0=BB=D1=8C=D0=B7=D0=BE=D0=B2=D0=B0?= =?UTF-8?q?=D1=82=D0=B5=D0=BB=D1=8C=D1=81=D0=BA=D0=B8=D1=85=20=D0=B7=D0=B0?= =?UTF-8?q?=D0=B3=D0=BE=D0=BB=D0=BE=D0=B2=D0=BA=D0=BE=D0=B2=20=D0=B2=20?= =?UTF-8?q?=D0=B8=D0=BD=D0=B8=D1=86=D0=B8=D0=B0=D0=BB=D0=B8=D0=B7=D0=B0?= =?UTF-8?q?=D1=86=D0=B8=D1=8E=20RemnawaveSDK?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- remnawave/__init__.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/remnawave/__init__.py b/remnawave/__init__.py index e79f252..679fb46 100644 --- a/remnawave/__init__.py +++ b/remnawave/__init__.py @@ -40,6 +40,7 @@ class RemnawaveSDK: token: Optional[str] = None, caddy_token: Optional[str] = None, ssl_ignore: Optional[bool] = False, + custom_headers: Optional[dict] = None, ): """ Remnawave SDK init @@ -50,12 +51,14 @@ class RemnawaveSDK: token (Optional[str]): - Token for authorization. caddy_token (Optional[str]): - Token for Caddy Auth (Headers). Defaults to None. ssl_ignore (Optional[bool]): - Whether to ignore SSL certificate errors. Defaults to False. + custom_headers (Optional[dict]): - Custom headers to include in the requests. Defaults to None. """ self._client = client self._token = token self.base_url = base_url self.caddy_token = caddy_token self.ssl_ignore = ssl_ignore + self.custom_headers = custom_headers self._validate_params() @@ -119,6 +122,9 @@ class RemnawaveSDK: if self.caddy_token is not None: headers["X-Api-Key"] = self.caddy_token + if self.custom_headers: + headers.update(self.custom_headers) + return headers def _prepare_url(self) -> str: From f9d9af7f2761d980afe5ae2bc6c9ad83fbf0909a Mon Sep 17 00:00:00 2001 From: Artem Date: Wed, 27 Aug 2025 00:27:29 +0200 Subject: [PATCH 6/6] =?UTF-8?q?feat:=20=D0=BE=D0=B1=D0=BD=D0=BE=D0=B2?= =?UTF-8?q?=D0=B8=D1=82=D1=8C=20=D0=B2=D0=B5=D1=80=D1=81=D0=B8=D1=8E=20SDK?= =?UTF-8?q?=20=D0=B4=D0=BE=202.1.4=20=D0=B8=20=D0=B4=D0=BE=D0=B1=D0=B0?= =?UTF-8?q?=D0=B2=D0=B8=D1=82=D1=8C=20=D0=BF=D0=BE=D0=B4=D0=B4=D0=B5=D1=80?= =?UTF-8?q?=D0=B6=D0=BA=D1=83=20=D0=B7=D0=B0=D0=BF=D1=80=D0=BE=D1=81=D0=B0?= =?UTF-8?q?=20=D0=BF=D0=B5=D1=80=D0=B5=D0=B7=D0=B0=D0=BF=D1=83=D1=81=D0=BA?= =?UTF-8?q?=D0=B0=20=D0=B2=D1=81=D0=B5=D1=85=20=D1=83=D0=B7=D0=BB=D0=BE?= =?UTF-8?q?=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 3 ++- pyproject.toml | 4 ++-- remnawave/controllers/nodes.py | 6 ++++-- remnawave/models/__init__.py | 10 ++++++++++ remnawave/models/inbounds.py | 1 + remnawave/models/nodes.py | 4 ++++ 6 files changed, 23 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index b59e08e..41e2e34 100644 --- a/README.md +++ b/README.md @@ -63,7 +63,8 @@ pip install git+https://github.com/remnawave/python-sdk.git@development | Contract Version | Remnawave Panel Version | | ---------------- | ----------------------- | -| 2.1.1. | >=2.1.1 | +| 2.1.4 | >=2.1.4 | +| 2.1.1 | >=2.1.1, <2.1.4 | | 2.0.0 | >=2.0.0,<2.1.0 | | 1.1.3 | >=1.6.12,<2.0.0 | | 1.1.2 | >=1.6.3,<=1.6.11 | diff --git a/pyproject.toml b/pyproject.toml index 8f0c971..a386ebb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,7 @@ [project] name = "remnawave" -version = "2.1.1" -description = "A Python SDK for interacting with the Remnawave API v2.1.1." +version = "2.1.4" +description = "A Python SDK for interacting with the Remnawave API v2.1.4." authors = [ {name = "Artem",email = "dev@forestsnet.com"} ] diff --git a/remnawave/controllers/nodes.py b/remnawave/controllers/nodes.py index 7815d97..53de2d4 100644 --- a/remnawave/controllers/nodes.py +++ b/remnawave/controllers/nodes.py @@ -17,6 +17,7 @@ from remnawave.models import ( RestartNodeResponseDto, UpdateNodeRequestDto, UpdateNodeResponseDto, + RestartAllNodesRequestDto, ) from remnawave.rapid import BaseController, delete, get, patch, post @@ -44,7 +45,7 @@ class NodesController(BaseController): ) -> GetOneNodeResponseDto: """Get One Node""" ... - + @delete("/nodes/{uuid}", response_class=DeleteNodeResponseDto) async def delete_node( self, @@ -52,7 +53,7 @@ class NodesController(BaseController): ) -> DeleteNodeResponseDto: """Delete Node""" ... - + @patch("/nodes", response_class=UpdateNodeResponseDto) async def update_node( self, @@ -88,6 +89,7 @@ class NodesController(BaseController): @post("/nodes/actions/restart-all", response_class=RestartAllNodesResponseDto) async def restart_all_nodes( self, + body: Annotated[RestartAllNodesRequestDto, PydanticBody()], ) -> RestartAllNodesResponseDto: """Restart All Nodes""" ... diff --git a/remnawave/models/__init__.py b/remnawave/models/__init__.py index a365f74..885ea4d 100644 --- a/remnawave/models/__init__.py +++ b/remnawave/models/__init__.py @@ -151,6 +151,7 @@ from .nodes import ( RestartNodeResponseDto, UpdateNodeRequestDto, UpdateNodeResponseDto, + RestartAllNodesRequestDto, ) from .nodes_usage_history import ( GetNodeUserUsageByRangeResponseDto, @@ -256,6 +257,9 @@ __all__ = [ "RestartNodeResponseDto", "UpdateNodeRequestDto", "UpdateNodeResponseDto", + "NodeConfigProfileDto", + "NodeConfigProfileRequestDto", + "RestartAllNodesRequestDto", # Hosts models "CreateHostRequestDto", "CreateHostResponseDto", @@ -269,7 +273,11 @@ __all__ = [ "UpdateHostRequestDto", "UpdateHostResponseDto", "GetAllHostTagsResponseDto", + "CreateHostInboundData", + "HostInboundData", + "ReorderHostItem", # Inbounds models + "AllInboundsData", "FullInboundResponseDto", "FullInboundStatistic", "FullInboundsResponseDto", @@ -278,6 +286,7 @@ __all__ = [ "InboundResponseDto", "InboundsResponseDto", # Legacy alias "GetInternalSquadAccessibleNodesResponseDto", + "InboundsByProfileData", # Keygen models "GetPubKeyResponseDto", "PubKeyResponseDto", # Legacy alias @@ -405,6 +414,7 @@ __all__ = [ "InboundDto", "UpdateConfigProfileRequestDto", "UpdateConfigProfileResponseDto", + "GetAllConfigProfilesResponsePaginated", # Infra billing models "CreateInfraBillingNodeRequestDto", "CreateInfraBillingNodeResponseDto", diff --git a/remnawave/models/inbounds.py b/remnawave/models/inbounds.py index 7b3810b..53d3540 100644 --- a/remnawave/models/inbounds.py +++ b/remnawave/models/inbounds.py @@ -13,6 +13,7 @@ class InboundResponseDto(BaseModel): security: Optional[str] = None port: Optional[float] = None raw_inbound: Optional[Any] = Field(None, alias="rawInbound") + active_squads: Optional[list[UUID]] = Field(None, alias="activeSquads") class AllInboundsData(BaseModel): diff --git a/remnawave/models/nodes.py b/remnawave/models/nodes.py index f13e27e..96e6209 100644 --- a/remnawave/models/nodes.py +++ b/remnawave/models/nodes.py @@ -192,3 +192,7 @@ class DeleteNodeResponseDto(BaseModel): def __bool__(self): return self.is_deleted + + +class RestartAllNodesRequestDto(BaseModel): + force_restart: bool = Field(default=False, alias="forceRestart")