124 lines
5.4 KiB
Python
124 lines
5.4 KiB
Python
from __future__ import annotations
|
|
|
|
from datetime import datetime
|
|
from sqlalchemy import Column, BigInteger, Integer, String, DateTime, JSON, Boolean, ForeignKey
|
|
from sqlalchemy.orm import relationship
|
|
|
|
from .base import AlchemyBase
|
|
|
|
|
|
class EncryptedContent(AlchemyBase):
|
|
__tablename__ = 'encrypted_contents'
|
|
|
|
id = Column(Integer, autoincrement=True, primary_key=True)
|
|
# CID of encrypted source stored in IPFS (CIDv1 base32)
|
|
encrypted_cid = Column(String(128), nullable=False, unique=True)
|
|
|
|
# Public metadata
|
|
title = Column(String(512), nullable=False)
|
|
description = Column(String(4096), nullable=True)
|
|
content_type = Column(String(64), nullable=False) # e.g. audio/flac, video/mp4, application/octet-stream
|
|
|
|
# Sizes
|
|
enc_size_bytes = Column(BigInteger, nullable=True)
|
|
plain_size_bytes = Column(BigInteger, nullable=True)
|
|
|
|
# Preview flags and config (all preview params live here, not in derivatives)
|
|
preview_enabled = Column(Boolean, nullable=False, default=False)
|
|
preview_conf = Column(JSON, nullable=False, default=dict)
|
|
|
|
# Crypto parameters (fixed per network)
|
|
aead_scheme = Column(String(32), nullable=False, default='AES_GCM')
|
|
chunk_bytes = Column(Integer, nullable=False, default=1048576)
|
|
salt_b64 = Column(String(64), nullable=True) # per-content salt used for nonce derivation
|
|
|
|
created_at = Column(DateTime, nullable=False, default=datetime.utcnow)
|
|
updated_at = Column(DateTime, nullable=False, default=datetime.utcnow, onupdate=datetime.utcnow)
|
|
|
|
|
|
class ContentKey(AlchemyBase):
|
|
__tablename__ = 'content_keys'
|
|
|
|
content_id = Column(Integer, ForeignKey('encrypted_contents.id'), primary_key=True)
|
|
key_ciphertext_b64 = Column(String(512), nullable=False)
|
|
key_fingerprint = Column(String(128), nullable=False)
|
|
issuer_node_id = Column(String(128), nullable=False)
|
|
allow_auto_grant = Column(Boolean, nullable=False, default=True)
|
|
lease_expires_at = Column(DateTime, nullable=True)
|
|
created_at = Column(DateTime, nullable=False, default=datetime.utcnow)
|
|
|
|
content = relationship('EncryptedContent', uselist=False, foreign_keys=[content_id])
|
|
|
|
|
|
class IpfsSync(AlchemyBase):
|
|
__tablename__ = 'ipfs_sync'
|
|
|
|
content_id = Column(Integer, ForeignKey('encrypted_contents.id'), primary_key=True)
|
|
pin_state = Column(String(32), nullable=False, default='pinned') # not_pinned|queued|pinning|pinned|failed
|
|
pin_error = Column(String(1024), nullable=True)
|
|
bytes_total = Column(BigInteger, nullable=True)
|
|
bytes_fetched = Column(BigInteger, nullable=True)
|
|
providers_cache = Column(JSON, nullable=False, default=list)
|
|
first_seen_at = Column(DateTime, nullable=True)
|
|
pinned_at = Column(DateTime, nullable=True)
|
|
updated_at = Column(DateTime, nullable=False, default=datetime.utcnow, onupdate=datetime.utcnow)
|
|
|
|
content = relationship('EncryptedContent', uselist=False, foreign_keys=[content_id])
|
|
|
|
|
|
class ContentDerivative(AlchemyBase):
|
|
__tablename__ = 'content_derivatives'
|
|
|
|
id = Column(Integer, autoincrement=True, primary_key=True)
|
|
content_id = Column(Integer, ForeignKey('encrypted_contents.id'), nullable=False)
|
|
kind = Column(String(64), nullable=False) # decrypted_high|decrypted_low|decrypted_thumbnail|decrypted_preview
|
|
interval_start_ms = Column(Integer, nullable=True)
|
|
interval_end_ms = Column(Integer, nullable=True)
|
|
local_path = Column(String(1024), nullable=False)
|
|
content_type = Column(String(64), nullable=True)
|
|
size_bytes = Column(BigInteger, nullable=True)
|
|
status = Column(String(32), nullable=False, default='pending') # pending|processing|ready|failed
|
|
error = Column(String(1024), nullable=True)
|
|
created_at = Column(DateTime, nullable=False, default=datetime.utcnow)
|
|
last_access_at = Column(DateTime, nullable=True)
|
|
|
|
content = relationship('EncryptedContent', uselist=False, foreign_keys=[content_id])
|
|
|
|
|
|
class ContentIndexItem(AlchemyBase):
|
|
__tablename__ = 'content_index_items'
|
|
|
|
encrypted_cid = Column(String(128), primary_key=True)
|
|
payload = Column(JSON, nullable=False, default=dict)
|
|
sig = Column(String(512), nullable=False)
|
|
updated_at = Column(DateTime, nullable=False, default=datetime.utcnow, onupdate=datetime.utcnow)
|
|
|
|
|
|
class KeyGrant(AlchemyBase):
|
|
__tablename__ = 'key_grants'
|
|
|
|
id = Column(Integer, autoincrement=True, primary_key=True)
|
|
encrypted_cid = Column(String(128), nullable=False)
|
|
issuer_node_id = Column(String(128), nullable=False)
|
|
to_node_id = Column(String(128), nullable=False)
|
|
sealed_key_b64 = Column(String(1024), nullable=False)
|
|
aead_scheme = Column(String(32), nullable=False)
|
|
chunk_bytes = Column(Integer, nullable=False)
|
|
constraints = Column(JSON, nullable=False, default=dict)
|
|
issued_at = Column(DateTime, nullable=False, default=datetime.utcnow)
|
|
sig = Column(String(512), nullable=False)
|
|
|
|
|
|
class UploadSession(AlchemyBase):
|
|
__tablename__ = 'upload_sessions'
|
|
|
|
id = Column(String(128), primary_key=True) # tus Upload.ID
|
|
filename = Column(String(512), nullable=True)
|
|
size_bytes = Column(BigInteger, nullable=True)
|
|
state = Column(String(32), nullable=False, default='uploading') # uploading|processing|pinned|failed
|
|
encrypted_cid = Column(String(128), nullable=True)
|
|
storage_path = Column(String(1024), nullable=True)
|
|
error = Column(String(1024), nullable=True)
|
|
created_at = Column(DateTime, nullable=False, default=datetime.utcnow)
|
|
updated_at = Column(DateTime, nullable=False, default=datetime.utcnow, onupdate=datetime.utcnow)
|