from core.services.networking.httpx import connect from core.services.networking.api_requests.ApiResponseModel import ApiResponse, ErrorType from core.models.invoice.Invoice import Invoice from core.models.invoice.PaymentMethod import PaymentMethod from core.models.session.SessionProfile import SessionProfile from core.models.system.SystemProfile import SystemProfile from core.Errors import MissingSubscriptionError, InvalidSubscriptionError # from core.services.WebServiceApiService import WebServiceApiService from core.controllers.ConnectionController import ConnectionController from core.observers.ConnectionObserver import ConnectionObserver from core.Constants import Constants from core.models.Subscription import Subscription from core.models.SubscriptionPlan import SubscriptionPlan from core.errors.logger import logger from typing import Union, Optional import re def activate_subscription( profile: Union[SessionProfile, SystemProfile], connection_observer: Optional[ConnectionObserver] = None ) -> bool: """ Purpose: Ensure subscription is ready. Features: Idempotent. Checks local first Confusion: This returns True both if was already active or just activated. Returns: Returns True if subscription was already active. Returns True if subscription was just activated. Errors: True. Raises if subscription is missing or invalid. (not false) """ if not profile.has_subscription(): raise MissingSubscriptionError() # Already activated—nothing to do if profile.subscription.has_been_activated(): return True # ================================================== # ENCRYPTED PROXY # ================================================== if profile.connection.code in ("vless", "hysteria2"): logger.info("Getting an Encrypted proxy subscription code") subscription = get_encrypted_proxy_billing_code( location_id=profile.location.id, subscription_plan_id=profile.subscription.id, connection_observer=connection_observer ) # ================================================== # WIREGUARD AND GENERIC SOCKS5 PROXY # ================================================== else: logger.info("Getting a Wireguard or regular proxy subscription DATED EXPIRED") # Fetch and activate subscription = get_subscription( billing_code=profile.subscription.billing_code, connection_observer=connection_observer ) # legacy # subscription = ConnectionController.with_preferred_connection( # profile.subscription.billing_code, # task=WebServiceApiService.get_subscription, # connection_observer=connection_observer # ) if subscription is None: raise InvalidSubscriptionError() profile.subscription = subscription profile.save() return True def is_subscription_ready(profile: Union[SessionProfile, SystemProfile]) -> bool: """Check if subscription exists and is activated (no side effects).""" return ( profile.has_subscription() and profile.subscription.has_been_activated() ) def get_subscription(billing_code: str, connection_observer: ConnectionObserver) -> Subscription: billing_code = billing_code.replace('-', '').upper() billing_code_fragments = re.findall('....?', billing_code) billing_code = '-'.join(billing_code_fragments) url = f'{Constants.SP_API_BASE_URL}/subscriptions/current' api_response = connect.single_endpoint( method="get", url=url, observer=connection_observer, payload=None, billing_code=billing_code ) if api_response.valid: raw_json = api_response.data subscription = raw_json['data'] return Subscription(billing_code, Subscription.from_iso_format(subscription['expires_at'])) else: logger.error(f"API Reply of {api_response.error_type}") return None def get_invoice(billing_code: str, connection_observer: ConnectionObserver) -> Invoice: url = f'{Constants.SP_API_BASE_URL}/invoices/current' api_response = connect.single_endpoint( method="get", url=url, observer=connection_observer, payload=None, billing_code=billing_code ) if api_response.valid: raw_json = api_response.data response_data = raw_json['data'] invoice = { 'status': response_data['status'], 'expires_at': response_data['expires_at'] } payment_methods = [] for payment_method in response_data['payment_methods']: payment_methods.append(PaymentMethod(payment_method['code'], payment_method['name'], payment_method['address'], payment_method['payment_link'], payment_method['rate'], payment_method['amount'], payment_method['due'])) return Invoice(billing_code, invoice['status'], invoice['expires_at'], tuple[PaymentMethod](payment_methods)) else: return None def get_encrypted_proxy_billing_code( location_id: int, subscription_plan_id: int, connection_observer: ConnectionObserver ) -> str: url = f'{Constants.SP_API_BASE_URL}/api/v1/subscriptions' payload = { "subscription_plan_id": subscription_plan_id, "location_id": location_id } api_response = connect.single_endpoint( method="post", url=url, observer=connection_observer, payload=payload, billing_code=None ) if api_response.valid: raw_reply = api_response.data data = raw_reply['data'] billing_code = data.get('billing_code', None) return billing_code else: logger.error(f"API Error: {api_response.error_type}") return None