slicer_plugin_upload.py 2.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253
  1. """Uploads sent by the slicer plugin, and where each one came from."""
  2. from datetime import datetime
  3. from sqlalchemy import DateTime, ForeignKey, String, Text, func
  4. from sqlalchemy.orm import Mapped, mapped_column
  5. from backend.app.core.database import Base
  6. class SlicerPluginUpload(Base):
  7. """One upload from the slicer plugin, keyed by the id the plugin chose for it.
  8. Two jobs. It makes the upload idempotent: the plugin retries a send whose
  9. response it never saw, and a retry that queued the file a second time would
  10. print it twice. And it keeps what the file cannot say about itself -- which
  11. slicer and presets produced it, and a fingerprint of the model -- which is
  12. what lets a later slice of the same model find this one.
  13. """
  14. __tablename__ = "slicer_plugin_uploads"
  15. id: Mapped[int] = mapped_column(primary_key=True)
  16. # Chosen by the plugin, one per send. Unique, so two requests carrying the
  17. # same id cannot both get past the claim in slicer_plugin.py.
  18. upload_id: Mapped[str] = mapped_column(String(64), unique=True, index=True)
  19. # Who sent it: "user:<id>", "apikey:<id>", or "anonymous" with auth off. A
  20. # replay from anyone else is refused rather than answered with this
  21. # caller's result.
  22. caller: Mapped[str] = mapped_column(String(40))
  23. # "processing" while the request that claimed the id is still working,
  24. # "done" once `response` holds what it returned.
  25. status: Mapped[str] = mapped_column(String(20), default="processing")
  26. library_file_id: Mapped[int | None] = mapped_column(
  27. ForeignKey("library_files.id", ondelete="SET NULL"), nullable=True, index=True
  28. )
  29. # Provenance, as the plugin reported it.
  30. slicer: Mapped[str | None] = mapped_column(String(50), nullable=True)
  31. slicer_version: Mapped[str | None] = mapped_column(String(50), nullable=True)
  32. plugin_version: Mapped[str | None] = mapped_column(String(50), nullable=True)
  33. project_name: Mapped[str | None] = mapped_column(String(255), nullable=True)
  34. model_fingerprint: Mapped[str | None] = mapped_column(String(128), nullable=True, index=True)
  35. presets: Mapped[str | None] = mapped_column(Text, nullable=True) # JSON
  36. # The JSON body the first request returned, sent back verbatim on a replay.
  37. response: Mapped[str | None] = mapped_column(Text, nullable=True)
  38. created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())