diff --git a/core/Errors.py b/core/Errors.py index a0e6f1b..d4ee750 100644 --- a/core/Errors.py +++ b/core/Errors.py @@ -51,4 +51,6 @@ class FileIntegrityError(Exception): class EndpointVerificationError(Exception): pass class SingboxNotInstalledException(Exception): + pass +class PaymentRequiredError(Exception): pass \ No newline at end of file diff --git a/core/controllers/ConnectionController.py b/core/controllers/ConnectionController.py index 35ef893..623dbdf 100644 --- a/core/controllers/ConnectionController.py +++ b/core/controllers/ConnectionController.py @@ -1,6 +1,5 @@ from collections.abc import Callable from core.Constants import Constants -from core.Errors import InvalidSubscriptionError, MissingSubscriptionError, ConnectionUnprotectedError, ConnectionTerminationError, CommandNotFoundError from core.controllers.ConfigurationController import ConfigurationController from core.controllers.ProfileController import ProfileController from core.controllers.SessionStateController import SessionStateController @@ -13,6 +12,7 @@ from core.services.WebServiceApiService import WebServiceApiService from essentials.modules.TorModule import TorModule from essentials.services.ConnectionService import ConnectionService from pathlib import Path +from core.Errors import InvalidSubscriptionError, MissingSubscriptionError, ConnectionUnprotectedError, ConnectionTerminationError, CommandNotFoundError, PaymentRequiredError from subprocess import CalledProcessError from typing import Union, Optional, Any import os @@ -105,7 +105,7 @@ class ConnectionController: ) if operator_proxy_session is None: - raise InvalidSubscriptionError() + raise PaymentRequiredError() profile.attach_operator_proxy_session(operator_proxy_session) diff --git a/core/controllers/ProfileController.py b/core/controllers/ProfileController.py index 688837c..cade914 100644 --- a/core/controllers/ProfileController.py +++ b/core/controllers/ProfileController.py @@ -1,4 +1,4 @@ -from core.Errors import InvalidSubscriptionError, MissingSubscriptionError, ConnectionTerminationError, ProfileActivationError, ProfileDeactivationError, MissingLocationError, ConnectionUnprotectedError, EndpointVerificationError, ProfileStateConflictError +from core.Errors import InvalidSubscriptionError, MissingSubscriptionError, ConnectionTerminationError, ProfileActivationError, ProfileDeactivationError, MissingLocationError, ConnectionUnprotectedError, EndpointVerificationError, ProfileStateConflictError, PaymentRequiredError from core.controllers.ApplicationController import ApplicationController from core.controllers.ApplicationVersionController import ApplicationVersionController from core.controllers.SessionStateController import SessionStateController @@ -140,15 +140,27 @@ class ProfileController: from core.controllers.ConnectionController import ConnectionController if profile.has_subscription(): - - print(f"DEBUG activate_subscription:") - print(f" billing_code: {profile.subscription.billing_code}") - print(f" operator_id: {profile.subscription.operator_id}") - + + # Operator profiles (vless/hysteria2): check if already activated locally first. + # If not, poll the server — the payment may have been processed since last attempt. + if profile.subscription.operator_id is not None: + if profile.subscription.has_been_activated(): + profile.save() + return + subscription = ConnectionController.with_preferred_connection( + profile.subscription.billing_code, + task=WebServiceApiService.get_subscription, + connection_observer=connection_observer + ) + if subscription is not None: + profile.subscription = subscription + profile.save() + return + else: + raise PaymentRequiredError() + subscription = ConnectionController.with_preferred_connection(profile.subscription.billing_code, task=WebServiceApiService.get_subscription, connection_observer=connection_observer) - print(f" get_subscription returned: {subscription}") - if subscription is not None: profile.subscription = subscription profile.save() @@ -157,7 +169,7 @@ class ProfileController: else: raise MissingSubscriptionError() - + @staticmethod def is_enabled(profile: Union[SessionProfile, SystemProfile]): @@ -299,4 +311,4 @@ class ProfileController: return dict( private=base64.b64encode(private_key).decode(), public=base64.b64encode(public_key).decode() - ) + ) \ No newline at end of file