subscription.py 3.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. from datetime import datetime
  2. from typing import List, Optional
  3. from sqlmodel import SQLModel, Field,Session,select,Relationship
  4. from sqlalchemy.engine import Engine
  5. from sqlalchemy.dialects.postgresql import JSON
  6. from pydantic import BaseModel
  7. import yaml
  8. from database.engine import get_session,create_engine,engine
  9. class SubscriptFile(SQLModel, table=True):
  10. id: Optional[int] = Field(default=None, primary_key=True)
  11. url: str = Field(index=True)
  12. file_path: str = Field()
  13. updated_at: datetime = Field(default_factory=datetime.now)
  14. error: int = Field(default=0)
  15. detail: dict = Field(default={}, sa_type=JSON)
  16. mihomo_meta: List["MihomoMeta"] = Relationship(back_populates="subscript_file")
  17. class MihomoMeta(SQLModel, table=True):
  18. id: Optional[int] = Field(default=None, primary_key=True)
  19. provider_name: str
  20. proxy_name: str
  21. mixed_port: Optional[int]
  22. external_controller: Optional[str]
  23. temp_file_path: Optional[str]
  24. pid: Optional[int]
  25. running: Optional[bool] = False
  26. updated_at: datetime = Field(default_factory=datetime.now)
  27. subscript_file_id: Optional[int] = Field(default=None, foreign_key="subscriptfile.id")
  28. subscript_file: SubscriptFile | None = Relationship(back_populates="mihomo_meta")
  29. class SubscriptionManager:
  30. def __init__(self, db:Engine=None):
  31. self.engine:Engine = db or engine
  32. def add_subscription_meta(self, sub_model: SubscriptFile, overwrite:bool=False):
  33. with Session(self.engine) as session:
  34. exist_sub = session.exec(select(SubscriptFile).where(SubscriptFile.url == sub_model.url)).first()
  35. if exist_sub and not overwrite:
  36. return exist_sub
  37. name, groups = self._check_valid(sub_model)
  38. # 如果存在且需要覆盖,则删除旧的 MihomoMeta 记录
  39. if exist_sub and overwrite:
  40. session.exec(select(MihomoMeta).where(MihomoMeta.subscript_file_id == exist_sub.id)).delete()
  41. session.delete(exist_sub)
  42. session.commit()
  43. # 添加新的 SubscriptFile
  44. session.add(sub_model)
  45. session.commit()
  46. session.refresh(sub_model)
  47. # 添加 MihomoMeta 记录
  48. for group in groups:
  49. miho = MihomoMeta(
  50. provider_name=name,
  51. proxy_name=group["name"],
  52. subscript_file_id=sub_model.id # 使用 sub_model.id
  53. )
  54. session.add(miho)
  55. session.commit()
  56. session.refresh(sub_model)
  57. return sub_model
  58. def get_subscription_meta(self) -> List[SubscriptFile]:
  59. with Session(self.engine) as session:
  60. return session.exec(select(SubscriptFile)).all()
  61. def _check_valid(self, sub_model:SubscriptFile):
  62. with open(sub_model.file_path, "r",encoding='utf-8') as f:
  63. sub_yaml = yaml.safe_load(f)
  64. groups = sub_yaml.get("proxy-groups", [])
  65. if not groups:
  66. raise ValueError("subscription file is not valid")
  67. name = groups[0].get("name", "")
  68. if not name:
  69. raise ValueError("subscription file is not valid")
  70. return name, groups
  71. # ret.append(
  72. # SubscriptionResponse(
  73. # file_name=Path(sub.file_path).name,
  74. # provider_name=name,
  75. # updated_at=sub.updated_at,
  76. # proxies=sub_yaml.get("proxies", []),
  77. # )
  78. # )
  79. # return ret