import { TopicValidatorResult } from '@libp2p/interface';
import { MessageStatus, type PeerIdStr, RejectReason, type RejectReasonObj, type TopicStr, type ValidateError } from './types.js';
import type { RPC } from './message/rpc.js';
import type { PeerScoreThresholds } from './score/peer-score-thresholds.js';
/** Topic label as provided in `topicStrToLabel` */
export type TopicLabel = string;
export type TopicStrToLabel = Map<TopicStr, TopicLabel>;
export declare enum MessageSource {
    forward = "forward",
    publish = "publish"
}
type NoLabels = Record<string, never>;
type LabelsGeneric = Record<string, string | number>;
type LabelKeys<Labels extends LabelsGeneric> = Extract<keyof Labels, string>;
interface CollectFn<Labels extends LabelsGeneric> {
    (metric: Gauge<Labels>): void;
}
export interface Gauge<Labels extends LabelsGeneric = NoLabels> {
    inc: NoLabels extends Labels ? (value?: number) => void : (labels: Labels, value?: number) => void;
    set: NoLabels extends Labels ? (value: number) => void : (labels: Labels, value: number) => void;
    addCollect(collectFn: CollectFn<Labels>): void;
}
export interface Histogram<Labels extends LabelsGeneric = NoLabels> {
    startTimer(): () => void;
    observe: NoLabels extends Labels ? (value: number) => void : (labels: Labels, value: number) => void;
    reset(): void;
}
export interface AvgMinMax<Labels extends LabelsGeneric = NoLabels> {
    set: NoLabels extends Labels ? (values: number[]) => void : (labels: Labels, values: number[]) => void;
}
export type GaugeConfig<Labels extends LabelsGeneric> = {
    name: string;
    help: string;
} & (NoLabels extends Labels ? {
    labelNames?: never;
} : {
    labelNames: [LabelKeys<Labels>, ...Array<LabelKeys<Labels>>];
});
export type HistogramConfig<Labels extends LabelsGeneric> = GaugeConfig<Labels> & {
    buckets?: number[];
};
export type AvgMinMaxConfig<Labels extends LabelsGeneric> = GaugeConfig<Labels>;
export interface MetricsRegister {
    gauge<Labels extends LabelsGeneric = NoLabels>(config: GaugeConfig<Labels>): Gauge<Labels>;
    histogram<Labels extends LabelsGeneric = NoLabels>(config: HistogramConfig<Labels>): Histogram<Labels>;
    avgMinMax<Labels extends LabelsGeneric = NoLabels>(config: AvgMinMaxConfig<Labels>): AvgMinMax<Labels>;
}
export declare enum InclusionReason {
    /** Peer was a fanaout peer. */
    Fanout = "fanout",
    /** Included from random selection. */
    Random = "random",
    /** Peer subscribed. */
    Subscribed = "subscribed",
    /** On heartbeat, peer was included to fill the outbound quota. */
    Outbound = "outbound",
    /** On heartbeat, not enough peers in mesh */
    NotEnough = "not_enough",
    /** On heartbeat opportunistic grafting due to low mesh score */
    Opportunistic = "opportunistic"
}
export declare enum ChurnReason {
    Dc = "disconnected",
    BadScore = "bad_score",
    Prune = "prune",
    Excess = "excess"
}
export declare enum ScorePenalty {
    GraftBackoff = "graft_backoff",
    BrokenPromise = "broken_promise",
    MessageDeficit = "message_deficit",
    IPColocation = "IP_colocation"
}
export declare enum IHaveIgnoreReason {
    LowScore = "low_score",
    MaxIhave = "max_ihave",
    MaxIasked = "max_iasked"
}
export declare enum ScoreThreshold {
    graylist = "graylist",
    publish = "publish",
    gossip = "gossip",
    mesh = "mesh"
}
export type PeersByScoreThreshold = Record<ScoreThreshold, number>;
export interface ToSendGroupCount {
    direct: number;
    floodsub: number;
    mesh: number;
    fanout: number;
}
export interface ToAddGroupCount {
    fanout: number;
    random: number;
}
export type PromiseDeliveredStats = {
    expired: false;
    requestedCount: number;
    maxDeliverMs: number;
} | {
    expired: true;
    maxDeliverMs: number;
};
export interface TopicScoreWeights<T> {
    p1w: T;
    p2w: T;
    p3w: T;
    p3bw: T;
    p4w: T;
}
export interface ScoreWeights<T> {
    byTopic: Map<TopicLabel, TopicScoreWeights<T>>;
    p5w: T;
    p6w: T;
    p7w: T;
    score: T;
}
export type Metrics = ReturnType<typeof getMetrics>;
/**
 * A collection of metrics used throughout the Gossipsub behaviour.
 * NOTE: except for special reasons, do not add more than 1 label for frequent metrics,
 * there's a performance penalty as of June 2023.
 */
export declare function getMetrics(register: MetricsRegister, topicStrToLabel: TopicStrToLabel, opts: {
    gossipPromiseExpireSec: number;
    behaviourPenaltyThreshold: number;
    maxMeshMessageDeliveriesWindowSec: number;
}): {
    protocolsEnabled: Gauge<{
        protocol: string;
    }>;
    /**
     * Status of our subscription to this topic. This metric allows analyzing other topic metrics
     * filtered by our current subscription status.
     * = rust-libp2p `topic_subscription_status` */
    topicSubscriptionStatus: Gauge<{
        topicStr: TopicStr;
    }>;
    /** Number of peers subscribed to each topic. This allows us to analyze a topic's behaviour
     * regardless of our subscription status. */
    topicPeersCount: Gauge<{
        topicStr: TopicStr;
    }>;
    /**
     * Number of peers in our mesh. This metric should be updated with the count of peers for a
     * topic in the mesh regardless of inclusion and churn events.
     * = rust-libp2p `mesh_peer_counts` */
    meshPeerCounts: Gauge<{
        topicStr: TopicStr;
    }>;
    /**
     * Number of times we include peers in a topic mesh for different reasons.
     * = rust-libp2p `mesh_peer_inclusion_events` */
    meshPeerInclusionEventsFanout: Gauge<{
        topic: TopicLabel;
    }>;
    meshPeerInclusionEventsRandom: Gauge<{
        topic: TopicLabel;
    }>;
    meshPeerInclusionEventsSubscribed: Gauge<{
        topic: TopicLabel;
    }>;
    meshPeerInclusionEventsOutbound: Gauge<{
        topic: TopicLabel;
    }>;
    meshPeerInclusionEventsNotEnough: Gauge<{
        topic: TopicLabel;
    }>;
    meshPeerInclusionEventsOpportunistic: Gauge<{
        topic: TopicLabel;
    }>;
    meshPeerInclusionEventsUnknown: Gauge<{
        topic: TopicLabel;
    }>;
    /**
     * Number of times we remove peers in a topic mesh for different reasons.
     * = rust-libp2p `mesh_peer_churn_events` */
    meshPeerChurnEventsDisconnected: Gauge<{
        topic: TopicLabel;
    }>;
    meshPeerChurnEventsBadScore: Gauge<{
        topic: TopicLabel;
    }>;
    meshPeerChurnEventsPrune: Gauge<{
        topic: TopicLabel;
    }>;
    meshPeerChurnEventsExcess: Gauge<{
        topic: TopicLabel;
    }>;
    meshPeerChurnEventsUnknown: Gauge<{
        topic: TopicLabel;
    }>;
    /**
     * Gossipsub supports floodsub, gossipsub v1.0, v1.1, and v1.2. Peers are classified based
     * on which protocol they support. This metric keeps track of the number of peers that are
     * connected of each type. */
    peersPerProtocol: Gauge<{
        protocol: string;
    }>;
    /** The time it takes to complete one iteration of the heartbeat. */
    heartbeatDuration: Histogram<NoLabels>;
    /** Heartbeat run took longer than heartbeat interval so next is skipped */
    heartbeatSkipped: Gauge<NoLabels>;
    /**
     * Message validation results for each topic.
     * Invalid == Reject?
     * = rust-libp2p `invalid_messages`, `accepted_messages`, `ignored_messages`, `rejected_messages` */
    acceptedMessagesTotal: Gauge<{
        topic: TopicLabel;
    }>;
    ignoredMessagesTotal: Gauge<{
        topic: TopicLabel;
    }>;
    rejectedMessagesTotal: Gauge<{
        topic: TopicLabel;
    }>;
    unknownValidationResultsTotal: Gauge<{
        topic: TopicLabel;
    }>;
    /**
     * When the user validates a message, it tries to re propagate it to its mesh peers. If the
     * message expires from the memcache before it can be validated, we count this a cache miss
     * and it is an indicator that the memcache size should be increased.
     * = rust-libp2p `mcache_misses` */
    asyncValidationMcacheHit: Gauge<{
        hit: 'hit' | 'miss';
    }>;
    asyncValidationDelayFromFirstSeenSec: Histogram<NoLabels>;
    asyncValidationUnknownFirstSeen: Gauge<NoLabels>;
    peerReadStreamError: Gauge<NoLabels>;
    rpcRecvBytes: Gauge<NoLabels>;
    rpcRecvCount: Gauge<NoLabels>;
    rpcRecvSubscription: Gauge<NoLabels>;
    rpcRecvMessage: Gauge<NoLabels>;
    rpcRecvControl: Gauge<NoLabels>;
    rpcRecvIHave: Gauge<NoLabels>;
    rpcRecvIWant: Gauge<NoLabels>;
    rpcRecvGraft: Gauge<NoLabels>;
    rpcRecvPrune: Gauge<NoLabels>;
    rpcDataError: Gauge<NoLabels>;
    rpcRecvError: Gauge<NoLabels>;
    /** Total count of RPC dropped because acceptFrom() == false */
    rpcRecvNotAccepted: Gauge<NoLabels>;
    rpcSentBytes: Gauge<NoLabels>;
    rpcSentCount: Gauge<NoLabels>;
    rpcSentSubscription: Gauge<NoLabels>;
    rpcSentMessage: Gauge<NoLabels>;
    rpcSentControl: Gauge<NoLabels>;
    rpcSentIHave: Gauge<NoLabels>;
    rpcSentIWant: Gauge<NoLabels>;
    rpcSentGraft: Gauge<NoLabels>;
    rpcSentPrune: Gauge<NoLabels>;
    rpcSentIDontWant: Gauge<NoLabels>;
    /** Total count of msg published by topic */
    msgPublishCount: Gauge<{
        topic: TopicLabel;
    }>;
    /** Total count of peers that we publish a msg to */
    msgPublishPeersByTopic: Gauge<{
        topic: TopicLabel;
    }>;
    /** Total count of peers (by group) that we publish a msg to */
    directPeersPublishedTotal: Gauge<{
        topic: TopicLabel;
    }>;
    floodsubPeersPublishedTotal: Gauge<{
        topic: TopicLabel;
    }>;
    meshPeersPublishedTotal: Gauge<{
        topic: TopicLabel;
    }>;
    fanoutPeersPublishedTotal: Gauge<{
        topic: TopicLabel;
    }>;
    /** Total count of msg publish data.length bytes */
    msgPublishBytes: Gauge<{
        topic: TopicLabel;
    }>;
    /** Total time in seconds to publish a message */
    msgPublishTime: Histogram<{
        topic: TopicLabel;
    }>;
    /** Total count of msg forwarded by topic */
    msgForwardCount: Gauge<{
        topic: TopicLabel;
    }>;
    /** Total count of peers that we forward a msg to */
    msgForwardPeers: Gauge<{
        topic: TopicLabel;
    }>;
    /** Total count of recv msgs before any validation */
    msgReceivedPreValidation: Gauge<{
        topic: TopicLabel;
    }>;
    /** Total count of recv msgs error */
    msgReceivedError: Gauge<{
        topic: TopicLabel;
    }>;
    /** Tracks distribution of recv msgs by duplicate, invalid, valid */
    prevalidationInvalidTotal: Gauge<{
        topic: TopicLabel;
    }>;
    prevalidationValidTotal: Gauge<{
        topic: TopicLabel;
    }>;
    prevalidationDuplicateTotal: Gauge<{
        topic: TopicLabel;
    }>;
    prevalidationUnknownTotal: Gauge<{
        topic: TopicLabel;
    }>;
    /** Tracks specific reason of invalid */
    msgReceivedInvalid: Gauge<{
        error: RejectReason | ValidateError;
    }>;
    msgReceivedInvalidByTopic: Gauge<{
        topic: TopicLabel;
    }>;
    /** Track duplicate message delivery time */
    duplicateMsgDeliveryDelay: Histogram<{
        topic: TopicLabel;
    }>;
    /** Total count of late msg delivery total by topic */
    duplicateMsgLateDelivery: Gauge<{
        topic: TopicLabel;
    }>;
    duplicateMsgIgnored: Gauge<{
        topic: TopicLabel;
    }>;
    /** Total times score() is called */
    scoreFnCalls: Gauge<NoLabels>;
    /** Total times score() call actually computed computeScore(), no cache */
    scoreFnRuns: Gauge<NoLabels>;
    scoreCachedDelta: Histogram<NoLabels>;
    /** Current count of peers by score threshold */
    peersByScoreThreshold: Gauge<{
        threshold: ScoreThreshold;
    }>;
    score: AvgMinMax<NoLabels>;
    /**
     * Separate score weights
     * Need to use 2-label metrics in this case to debug the score weights
     **/
    scoreWeights: AvgMinMax<{
        topic?: string | undefined;
        p: string;
    }>;
    /** Histogram of the scores for each mesh topic. */
    scorePerMesh: AvgMinMax<{
        topic: TopicLabel;
    }>;
    /** A counter of the kind of penalties being applied to peers. */
    scoringPenalties: Gauge<{
        penalty: ScorePenalty;
    }>;
    behaviourPenalty: Histogram<NoLabels>;
    /** Total received IHAVE messages that we ignore for some reason */
    ihaveRcvIgnored: Gauge<{
        reason: IHaveIgnoreReason;
    }>;
    /** Total received IHAVE messages by topic */
    ihaveRcvMsgids: Gauge<{
        topic: TopicLabel;
    }>;
    /**
     * Total messages per topic we don't have. Not actual requests.
     * The number of times we have decided that an IWANT control message is required for this
     * topic. A very high metric might indicate an underperforming network.
     * = rust-libp2p `topic_iwant_msgs` */
    ihaveRcvNotSeenMsgids: Gauge<{
        topic: TopicLabel;
    }>;
    /** Total received IWANT messages by topic */
    iwantRcvMsgids: Gauge<{
        topic: TopicLabel;
    }>;
    /** Total requested messageIDs that we don't have */
    iwantRcvDonthaveMsgids: Gauge<NoLabels>;
    /** Total received IDONTWANT messages */
    idontwantRcvMsgids: Gauge<NoLabels>;
    /** Total received IDONTWANT messageIDs that we don't have */
    idontwantRcvDonthaveMsgids: Gauge<NoLabels>;
    iwantPromiseStarted: Gauge<NoLabels>;
    /** Total count of resolved IWANT promises */
    iwantPromiseResolved: Gauge<NoLabels>;
    /** Total count of resolved IWANT promises from duplicate messages */
    iwantPromiseResolvedFromDuplicate: Gauge<NoLabels>;
    /** Total count of peers we have asked IWANT promises that are resolved */
    iwantPromiseResolvedPeers: Gauge<NoLabels>;
    iwantPromiseBroken: Gauge<NoLabels>;
    iwantMessagePruned: Gauge<NoLabels>;
    /** Histogram of delivery time of resolved IWANT promises */
    iwantPromiseDeliveryTime: Histogram<NoLabels>;
    iwantPromiseUntracked: Gauge<NoLabels>;
    /** Backoff time */
    connectedPeersBackoffSec: Histogram<NoLabels>;
    /** Unbounded cache sizes */
    cacheSize: Gauge<{
        cache: string;
    }>;
    /** Current mcache msg count */
    mcacheSize: Gauge<NoLabels>;
    mcacheNotValidatedCount: Gauge<NoLabels>;
    fastMsgIdCacheCollision: Gauge<NoLabels>;
    newConnectionCount: Gauge<{
        status: string;
    }>;
    topicStrToLabel: TopicStrToLabel;
    toTopic(topicStr: TopicStr): TopicLabel;
    /** We joined a topic */
    onJoin(topicStr: TopicStr): void;
    /** We left a topic */
    onLeave(topicStr: TopicStr): void;
    /** Register the inclusion of peers in our mesh due to some reason. */
    onAddToMesh(topicStr: TopicStr, reason: InclusionReason, count: number): void;
    /** Register the removal of peers in our mesh due to some reason */
    onRemoveFromMesh(topicStr: TopicStr, reason: ChurnReason, count: number): void;
    /**
     * Update validation result to metrics
     *
     * @param messageRecord - null means the message's mcache record was not known at the time of acceptance report
     */
    onReportValidation(messageRecord: {
        message: {
            topic: TopicStr;
        };
    } | null, acceptance: TopicValidatorResult, firstSeenTimestampMs: number | null): void;
    /**
     * - in handle_graft() Penalty::GraftBackoff
     * - in apply_iwant_penalties() Penalty::BrokenPromise
     * - in metric_score() P3 Penalty::MessageDeficit
     * - in metric_score() P6 Penalty::IPColocation
     */
    onScorePenalty(penalty: ScorePenalty): void;
    onIhaveRcv(topicStr: TopicStr, ihave: number, idonthave: number): void;
    onIwantRcv(iwantByTopic: Map<TopicStr, number>, iwantDonthave: number): void;
    onIdontwantRcv(idontwant: number, idontwantDonthave: number): void;
    onForwardMsg(topicStr: TopicStr, tosendCount: number): void;
    onPublishMsg(topicStr: TopicStr, tosendGroupCount: ToSendGroupCount, tosendCount: number, dataLen: number, ms: number): void;
    onMsgRecvPreValidation(topicStr: TopicStr): void;
    onMsgRecvError(topicStr: TopicStr): void;
    onPrevalidationResult(topicStr: TopicStr, status: MessageStatus): void;
    onMsgRecvInvalid(topicStr: TopicStr, reason: RejectReasonObj): void;
    onDuplicateMsgDelivery(topicStr: TopicStr, deliveryDelayMs: number, isLateDelivery: boolean): void;
    onPublishDuplicateMsg(topicStr: TopicStr): void;
    onPeerReadStreamError(): void;
    onRpcRecvError(): void;
    onRpcDataError(): void;
    onRpcRecv(rpc: RPC, rpcBytes: number): void;
    onRpcSent(rpc: RPC, rpcBytes: number): void;
    registerScores(scores: number[], scoreThresholds: PeerScoreThresholds): void;
    registerScoreWeights(sw: ScoreWeights<number[]>): void;
    registerScorePerMesh(mesh: Map<TopicStr, Set<PeerIdStr>>, scoreByPeer: Map<PeerIdStr, number>): void;
};
export {};
//# sourceMappingURL=metrics.d.ts.map