diff --git a/app/db/crud.py b/app/db/crud.py index cd9a9b5..c321c62 100644 --- a/app/db/crud.py +++ b/app/db/crud.py @@ -33,8 +33,8 @@ def add_default_hosts(db: Session, inbounds: List[Inbound]): def assure_node_inbounds(db: Session, inbounds: List[Inbound], node_id: int): - existing_inbounds = set((i.protocol, i.tag) for i in db.query(Inbound).filter(Inbound.node_id == node_id).all()) - inbounds_set = set((json.loads(i.config)["protocol"], i.tag) for i in list(inbounds)) + existing_inbounds = set((i.protocol, i.tag, i.config) for i in db.query(Inbound).filter(Inbound.node_id == node_id).all()) + inbounds_set = set((json.loads(i.config)["protocol"], i.tag, i.config) for i in list(inbounds)) new_inbounds = inbounds_set - existing_inbounds deleted_inbounds = existing_inbounds - inbounds_set # difference = [ i for i in existing_inbounds if (i.protocol, i.tag) not in existing_inbounds ] @@ -46,7 +46,7 @@ def assure_node_inbounds(db: Session, inbounds: List[Inbound], node_id: int): .execution_options(synchronize_session="fetch") ) db.execute(stmt)""" - new_inbounds = [Inbound(tag=i[1], protocol=i[0], node_id=node_id) for i in new_inbounds] + new_inbounds = [Inbound(tag=i[1], protocol=i[0], config=i[2], node_id=node_id) for i in new_inbounds] db.add_all(new_inbounds) db.flush() for i in new_inbounds: diff --git a/app/db/migrations/versions/20faa9f18c0a_init.py b/app/db/migrations/versions/20faa9f18c0a_init.py index 7988dd2..0e2a38c 100644 --- a/app/db/migrations/versions/20faa9f18c0a_init.py +++ b/app/db/migrations/versions/20faa9f18c0a_init.py @@ -41,10 +41,10 @@ def upgrade() -> None: op.create_table('nodes', sa.Column('id', sa.Integer(), nullable=False), sa.Column('name', sa.String(length=256, collation='NOCASE'), nullable=True), - sa.Column('address', sa.String(length=256), nullable=False), - sa.Column('port', sa.Integer(), nullable=False), + sa.Column('address', sa.String(length=256), nullable=True), + sa.Column('port', sa.Integer(), nullable=True), sa.Column('xray_version', sa.String(length=32), nullable=True), - sa.Column('status', sa.Enum('connected', 'connecting', 'error', 'disabled', name='nodestatus'), nullable=False), + sa.Column('status', sa.Enum('healthy', 'unhealthy', 'disabled', name='nodestatus'), nullable=False), sa.Column('last_status_change', sa.DateTime(), nullable=True), sa.Column('message', sa.String(length=1024), nullable=True), sa.Column('created_at', sa.DateTime(), nullable=True), @@ -85,6 +85,7 @@ def upgrade() -> None: sa.Column('id', sa.Integer(), nullable=False), sa.Column('protocol', sa.String(), nullable=True), sa.Column('tag', sa.String(length=256), nullable=False), + sa.Column('config', sa.String(), nullable=False), sa.Column('node_id', sa.Integer(), nullable=True), sa.ForeignKeyConstraint(['node_id'], ['nodes.id'], ), sa.PrimaryKeyConstraint('id') diff --git a/app/db/models.py b/app/db/models.py index 27939b3..02fcd1e 100644 --- a/app/db/models.py +++ b/app/db/models.py @@ -121,6 +121,7 @@ class Inbound(Base): id = Column(Integer, primary_key=True) protocol = Column(Enum(ProxyTypes)) tag = Column(String(256), nullable=False, index=True) + config = Column(String(), nullable=False) node_id = Column(Integer, ForeignKey("nodes.id"), index=True) node = relationship("Node", back_populates="inbounds") services = relationship("Service", secondary=inbounds_services, back_populates="inbounds") diff --git a/app/marznode/grpc.py b/app/marznode/grpc.py index 0ebcbb0..393de69 100644 --- a/app/marznode/grpc.py +++ b/app/marznode/grpc.py @@ -4,6 +4,7 @@ import tempfile from grpclib import GRPCError from grpclib.client import Channel +from grpclib.exceptions import StreamTerminatedError from grpclib.health.v1.health_grpc import HealthStub from grpclib.health.v1.health_pb2 import HealthCheckResponse, HealthCheckRequest @@ -99,7 +100,7 @@ class MarzNodeGRPC(MarzNodeBase): async def is_alive(self) -> bool: try: response = await self._health.Check(HealthCheckRequest()) - except (OSError, ConnectionError, GRPCError): + except (OSError, ConnectionError, GRPCError, StreamTerminatedError): pass else: if response.status is HealthCheckResponse.SERVING: diff --git a/app/models/proxy.py b/app/models/proxy.py index 4358139..ff33de7 100644 --- a/app/models/proxy.py +++ b/app/models/proxy.py @@ -160,6 +160,7 @@ class InboundBase(BaseModel): id: Optional[int] = Field(None) tag: str = Field() protocol: ProxyTypes = Field() + config: str node_id: Optional[int] = Field(None) model_config = ConfigDict(from_attributes=True) diff --git a/app/models/user.py b/app/models/user.py index 95ece94..fb67664 100644 --- a/app/models/user.py +++ b/app/models/user.py @@ -94,8 +94,10 @@ class UserBase(BaseModel): return v model_config = ConfigDict(from_attributes=True) + from app.models.service import ServiceBase + class User(UserBase): pass @@ -131,7 +133,7 @@ class UserCreate(User): on_hold_expire = info.data.get("on_hold_expire_duration") expire = info.data.get("expire") if status == UserStatusCreate.on_hold: - if (on_hold_expire == 0 or on_hold_expire is None): + if on_hold_expire == 0 or on_hold_expire is None: raise ValueError("User cannot be on hold without a valid on_hold_expire_duration.") if expire: raise ValueError("User cannot be on hold with specified expire.") @@ -192,9 +194,9 @@ class UserResponse(User): @computed_field @property def links(self) -> List[str]: - return [""]# generate_v2ray_links( - # inbounds=self.inbounds, key=self.key, extra_data=self.dict(exclude={'subscription_url', 'links'}) - # ) + return generate_v2ray_links( + inbounds=self.inbounds, key=self.key, extra_data=self.dict(exclude={'subscription_url', 'links'}) + ) @computed_field @property diff --git a/app/utils/share.py b/app/utils/share.py index d8fb31a..798eaec 100644 --- a/app/utils/share.py +++ b/app/utils/share.py @@ -922,11 +922,10 @@ def process_inbounds_and_tags( results = [] for inb in inbounds: - inb_id, protocol, tag = inb.id, inb.protocol, inb.tag + inb_id, inbound, protocol, tag = inb.id, json.loads(inb.config), inb.protocol, inb.tag settings = generate_settings(ukey, protocol) format_variables.update({"PROTOCOL": protocol.name}) - inbound = xray.configs[inb.node_id].inbounds_by_tag.get(tag) if not inbound: continue