Skip to main content

Service

Struct Service 

Source
pub struct Service {
    store: Store,
    broker: Arc<Broker>,
    config: Arc<ConfigState>,
    permits: Arc<Semaphore>,
    memory: Arc<Semaphore>,
    batches: Mutex<HashMap<String, Arc<AtomicBool>>>,
    inflight: Arc<Mutex<HashMap<String, usize>>>,
    session_budget: Mutex<()>,
}

Fields§

§store: Store§broker: Arc<Broker>§config: Arc<ConfigState>§permits: Arc<Semaphore>

Bounds concurrent jobs (CPU).

§memory: Arc<Semaphore>

Bounds the decode memory of concurrent jobs, in MiB.

§batches: Mutex<HashMap<String, Arc<AtomicBool>>>

Cancellation flags of batches still running.

§inflight: Arc<Mutex<HashMap<String, usize>>>

Jobs currently processing each id. Identical images processed at once share one stored original, so a failing job may only discard it when no other job is still using it. Placing an original and the discard check both happen under this lock.

§session_budget: Mutex<()>

Serializes the per-session inline-budget read, spend and write, so two overlapping turns of one Claude session can’t both spend the same remaining budget or overwrite each other’s count.

Implementations§

Source§

impl Service

Source

pub fn new(store: Store, broker: Arc<Broker>, config: Arc<ConfigState>) -> Self

Source

pub fn store(&self) -> &Store

Source

pub fn limits(&self) -> Limits

Source

fn start_sweeper(self: &Arc<Self>)

Source

pub fn ingest( self: &Arc<Self>, req: CommandAttachmentsIngestData, ) -> AttachmentsIngestResult

Classify paths, apply the limits, and (unless dry_run) start processing the accepted images in the background. Returns at once.

Source

pub fn cancel(&self, batch_id: &str) -> bool

Source

pub async fn info(self: &Arc<Self>, ids: &[String]) -> Vec<AttachmentInfo>

Info for each id still in the store, in request order. May decode (after a send-edge change), so call it off the async workers.

Source

pub async fn ensure_derived(self: &Arc<Self>, id: &str) -> Option<StoredMeta>

Metadata under the current fingerprint. When the send edge or the pipeline changed since the attachment was processed, re-derive it from the stored original under the same CPU and memory limits as ingest, so a transcript full of old thumbnails can’t start an unbounded number of decodes at once.

Source

async fn derive_kind( self: &Arc<Self>, id: &str, blob: PathBuf, kind: FileKind, name: &str, edge: u32, ) -> Result<StoredMeta, ProcessError>

Derive a placed original. Images reserve decode memory from their header first; other files are bounded by the extraction limits (extract.rs) and PDFs run out of process. The caller holds a CPU slot.

Source

pub fn with_session_inline_budget<T>( &self, key: &str, carry_from: Option<&str>, max: u64, f: impl FnOnce(u64) -> (T, u64), ) -> T

Run f with the inline budget left in Claude session key (out of max), and record what it reports spending, as one step under a lock. carry_from is a per-block key counted before the session had an id; its count moves into key first. Blocking.

Source

pub fn send_target(&self, id: &str, name: &str) -> Option<SendTarget>

What the agent gets for attachment id sent under the user’s name, marking it used: an image’s send-copy, or for any other file a freshly made copy named name, with a note for the agent’s list. Doesn’t decode: call Self::ensure_derived first so a stale fingerprint is re-derived under the limits.

Source

async fn reserve_memory(&self, w: u32, h: u32) -> Option<OwnedSemaphorePermit>

Reserve decode memory for a w×h image. Held until dropped.

Source

pub async fn commit_upload( self: &Arc<Self>, tmp: PathBuf, id: String, name: String, ) -> Result<AttachmentInfo, ProcessError>

Store a file already sitting in incoming/ (an upload): place it, reserve decode memory, derive. Returns its info.

Source

fn place_tracked( &self, tmp: &Path, id: &str, name: &str, ) -> Result<(PathBuf, FileKind, InflightGuard), ProcessError>

Store::place, registering this job as a user of the id first, under the same lock the discard check takes. Blocking.

Source

async fn discard_unprocessed(&self, guard: InflightGuard)

After a failed job: discard the original unless another job for the same bytes is still processing it (Store::discard_if_unprocessed also keeps it when any fingerprint has metadata). Consumes the guard.

Source

async fn run_batch( self: Arc<Self>, block_id: String, batch_id: String, items: Vec<AttachmentPending>, limits: Limits, cancel: Arc<AtomicBool>, )

Source

async fn run_item( self: &Arc<Self>, block_id: &str, batch_id: &str, item: AttachmentPending, limits: Limits, cancel: &Arc<AtomicBool>, ) -> Result<AttachmentInfo, ProcessError>

One item: wait for a CPU slot, copy + hash + place, reserve decode memory from the header, derive. The cancel flag is checked before each step and between copy chunks; a decode already running finishes but is reported as cancelled.

Source

async fn derive_placed( self: &Arc<Self>, block_id: &str, batch_id: &str, item: &AttachmentPending, id: &str, blob: PathBuf, kind: FileKind, limits: Limits, cancel: &Arc<AtomicBool>, ) -> Result<AttachmentInfo, ProcessError>

The part of Self::run_item after the original is in blobs/: reserve decode memory from the header and derive.

Source

fn copy_and_place( &self, block_id: &str, batch_id: &str, item: &AttachmentPending, limits: Limits, cancel: &AtomicBool, ) -> Result<(String, PathBuf, FileKind, InflightGuard), ProcessError>

Copy the source into incoming/ with progress and cancellation, then move it into blobs/. Runs on a blocking thread.

Source

fn publish<E: Event>(&self, block_id: &str, data: &E::Payload)

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
§

impl<T> Downcast for T
where T: Any,

§

fn into_any(self: Box<T>) -> Box<dyn Any>

Convert Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.
§

fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>

Convert Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be further downcast into Rc<ConcreteType> where ConcreteType implements Trait.
§

fn as_any(&self) -> &(dyn Any + 'static)

Convert &Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &Any’s vtable from &Trait’s.
§

fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)

Convert &mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &mut Any’s vtable from &mut Trait’s.
§

impl<T> DowncastSync for T
where T: Any + Send + Sync,

§

fn into_any_arc(self: Arc<T>) -> Arc<dyn Any + Send + Sync> ⓘ

Convert Arc<Trait> (where Trait: Downcast) to Arc<Any>. Arc<Any> can then be further downcast into Arc<ConcreteType> where ConcreteType implements Trait.
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<A, B, T> HttpServerConnExec<A, B> for T
where B: Body,

§

impl<T> Instrument for T

§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided [Span], returning an Instrumented wrapper. Read more
§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
§

impl<T> PolicyExt for T
where T: ?Sized,

§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns [Action::Follow] only if self and other return Action::Follow. Read more
§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns [Action::Follow] if either self or other returns Action::Follow. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

§

fn vzip(self) -> V

§

impl<T> WithSubscriber for T

§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> ⓘ
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ

Attaches the current default Subscriber to this type, returning a [WithDispatch] wrapper. Read more