/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
import { TypedEventEmitter } from "@fluid-internal/client-utils";
import { ICriticalContainerError } from "@fluidframework/container-definitions";
import { IContainerRuntime, IContainerRuntimeEvents } from "@fluidframework/container-runtime-definitions/internal";
import { IFluidHandleContext, type IFluidHandleInternal } from "@fluidframework/core-interfaces/internal";
import { IDocumentStorageService, ISnapshotTree, ISequencedDocumentMessage } from "@fluidframework/driver-definitions/internal";
import { IGarbageCollectionData, ISummaryTreeWithStats, ITelemetryContext } from "@fluidframework/runtime-definitions/internal";
import { FluidHandleBase } from "@fluidframework/runtime-utils/internal";
/**
 * This class represents blob (long string)
 * This object is used only when creating (writing) new blob and serialization purposes.
 * De-serialization process goes through FluidObjectHandle and request flow:
 * DataObject.request() recognizes requests in the form of `/blobs/<id>`
 * and loads blob.
 */
export declare class BlobHandle extends FluidHandleBase<ArrayBufferLike> {
    readonly path: string;
    readonly routeContext: IFluidHandleContext;
    get: () => Promise<ArrayBufferLike>;
    private readonly onAttachGraph?;
    private attached;
    get isAttached(): boolean;
    readonly absolutePath: string;
    constructor(path: string, routeContext: IFluidHandleContext, get: () => Promise<ArrayBufferLike>, onAttachGraph?: (() => void) | undefined);
    attachGraph(): void;
    bind(handle: IFluidHandleInternal): void;
}
/**
 * Information from a snapshot needed to load BlobManager
 * @alpha
 */
export interface IBlobManagerLoadInfo {
    ids?: string[];
    redirectTable?: [string, string][];
}
export type IBlobManagerRuntime = Pick<IContainerRuntime, "attachState" | "connected" | "baseLogger" | "clientDetails"> & TypedEventEmitter<IContainerRuntimeEvents>;
export interface IPendingBlobs {
    [id: string]: {
        blob: string;
        storageId?: string;
        uploadTime?: number;
        minTTLInSeconds?: number;
        acked?: boolean;
    };
}
export interface IBlobManagerEvents {
    (event: "noPendingBlobs", listener: () => void): any;
}
export declare class BlobManager extends TypedEventEmitter<IBlobManagerEvents> {
    static readonly basePath = "_blobs";
    private static readonly redirectTableBlobName;
    private readonly mc;
    /**
     * Map of local IDs to storage IDs. Contains identity entries (id → id) for storage IDs. All requested IDs should
     * be a key in this map. Blobs created while the container is detached are stored in IDetachedBlobStorage which
     * gives local IDs; the storage IDs are filled in at attach time.
     * Note: It contains mappings from all clients, i.e., from remote clients as well. local ID comes from the client
     * that uploaded the blob but its mapping to storage ID is needed in all clients in order to retrieve the blob.
     */
    private readonly redirectTable;
    /**
     * Blobs which we have not yet seen a BlobAttach op round-trip and not yet attached to a DDS.
     */
    private readonly pendingBlobs;
    /**
     * Track ops in flight for online flow. This is used for optimizations where if we receive an ack for a storage ID,
     * we can resolve all pending blobs with the same storage ID even though they may have different local IDs. That's
     * because we know that the server will not delete the blob corresponding to that storage ID.
     */
    private readonly opsInFlight;
    private readonly sendBlobAttachOp;
    private stopAttaching;
    private readonly routeContext;
    private readonly getStorage;
    private readonly blobRequested;
    private readonly isBlobDeleted;
    private readonly runtime;
    private readonly closeContainer;
    constructor(props: {
        readonly routeContext: IFluidHandleContext;
        snapshot: IBlobManagerLoadInfo;
        readonly getStorage: () => IDocumentStorageService;
        /**
         * Submit a BlobAttach op. When a blob is uploaded, there is a short grace period before which the blob is
         * deleted. The BlobAttach op notifies the server that blob is in use. The server will then not delete the
         * the blob as long as it is listed as referenced in future summaries. The summarizing client will know to
         * include the storage ID in the summary when it sees the op.
         *
         * The op will also include a local ID to inform all clients of the relation to the storage ID, without
         * knowledge of which they cannot request the blob from storage. It's important that this op is sequenced
         * before any ops that reference the local ID, otherwise, an invalid handle could be added to the document.
         */
        sendBlobAttachOp: (localId: string, storageId?: string) => void;
        readonly blobRequested: (blobPath: string) => void;
        readonly isBlobDeleted: (blobPath: string) => boolean;
        readonly runtime: IBlobManagerRuntime;
        stashedBlobs: IPendingBlobs | undefined;
        readonly closeContainer: (error?: ICriticalContainerError) => void;
    });
    get allBlobsAttached(): boolean;
    get hasPendingBlobs(): boolean;
    private createAbortError;
    hasPendingStashedUploads(): boolean;
    /**
     * Upload blobs added while offline. This must be completed before connecting and resubmitting ops.
     */
    trackPendingStashedUploads(): Promise<void>;
    /**
     * Set of actual storage IDs (i.e., IDs that can be requested from storage). This will be empty if the container is
     * detached or there are no (non-pending) attachment blobs in the document
     */
    private get storageIds();
    getBlob(blobId: string): Promise<ArrayBufferLike>;
    private getBlobHandle;
    private createBlobDetached;
    createBlob(blob: ArrayBufferLike, signal?: AbortSignal): Promise<IFluidHandleInternal<ArrayBufferLike>>;
    private uploadBlob;
    /**
     * Set up a mapping in the redirect table from fromId to toId. Also, notify the runtime that a reference is added
     * which is required for GC.
     */
    private setRedirection;
    private deletePendingBlobMaybe;
    private deletePendingBlob;
    private onUploadResolve;
    /**
     * Resubmit a BlobAttach op. Used to add storage IDs to ops that were
     * submitted to runtime while disconnected.
     * @param metadata - op metadata containing storage and/or local IDs
     */
    reSubmit(metadata: Record<string, unknown> | undefined): void;
    processBlobAttachOp(message: ISequencedDocumentMessage, local: boolean): void;
    /**
     * Reads blobs needed to load BlobManager from storage.
     * @param blobsTree - Tree containing IDs of previously attached blobs. We
     * look for the IDs in the blob entries of the tree since the both the r11s
     * and SPO drivers replace the attachment types returned in snapshot() with blobs.
     */
    static load(blobsTree: ISnapshotTree | undefined, tryFetchBlob: (id: string) => Promise<[string, string][]>): Promise<IBlobManagerLoadInfo>;
    /**
     * Load a set of previously attached blob IDs and redirect table from a previous snapshot.
     */
    private load;
    summarize(telemetryContext?: ITelemetryContext): ISummaryTreeWithStats;
    /**
     * Generates data used for garbage collection. Each blob uploaded represents a node in the GC graph as it can be
     * individually referenced by storing its handle in a referenced DDS. Returns the list of blob ids as GC nodes.
     * @param fullGC - true to bypass optimizations and force full generation of GC data. BlobManager doesn't care
     * about this for now because the data is a simple list of blob ids.
     */
    getGCData(fullGC?: boolean): IGarbageCollectionData;
    /**
     * Delete attachment blobs that are sweep ready.
     * @param sweepReadyBlobRoutes - The routes of blobs that are sweep ready and should be deleted. These routes will
     * be based off of local ids.
     * @returns The routes of blobs that were deleted.
     */
    deleteSweepReadyNodes(sweepReadyBlobRoutes: readonly string[]): readonly string[];
    /**
     * Delete blobs with the given routes from the redirect table.
     * The routes are GC nodes paths of format -`/<BlobManager.basePath>/<blobId>`. The blob ids are all local ids.
     * Deleting the blobs involves 2 steps:
     * 1. The redirect table entry for the local ids are deleted.
     * 2. If the storage ids corresponding to the deleted local ids are not in-use anymore, the redirect table entries
     * for the storage ids are deleted as well.
     *
     * Note that this does not delete the blobs from storage service immediately. Deleting the blobs from redirect table
     * will remove them the next summary. The service would them delete them some time in the future.
     */
    private deleteBlobsFromRedirectTable;
    /**
     * Verifies that the blob with given id is not deleted, i.e., it has not been garbage collected. If the blob is GC'd,
     * log an error and throw if necessary.
     */
    private verifyBlobNotDeleted;
    setRedirectTable(table: Map<string, string>): void;
    attachAndGetPendingBlobs(stopBlobAttachingSignal?: AbortSignal): Promise<IPendingBlobs | undefined>;
}
//# sourceMappingURL=blobManager.d.ts.map