"use strict";
/*---------------------------------------------------------------------------------------------
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/
/** @packageDocumentation
 * @module RpcInterface
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.RpcOperation = exports.RpcOperationPolicy = void 0;
const core_bentley_1 = require("@itwin/core-bentley");
const IModelError_1 = require("../../IModelError");
const RpcConstants_1 = require("./RpcConstants");
const RpcRegistry_1 = require("./RpcRegistry");
/** The policy for an RPC operation.
 * @internal
 */
class RpcOperationPolicy {
    constructor() {
        /** Supplies the IModelRpcProps for an operation request. */
        this.token = (request) => request.findTokenPropsParameter();
        /** Supplies the initial retry interval for an operation request. */
        this.retryInterval = (configuration) => configuration.pendingOperationRetryInterval;
        /** Called before every operation request on the frontend is sent. */
        this.requestCallback = (_request) => { };
        /** Called after every operation request on the frontend is sent. */
        this.sentCallback = (_request) => { };
        /**
         * Determines if caching is permitted for an operation response.
         * @note Not all RPC protocols support caching.
         */
        this.allowResponseCaching = (_request) => RpcConstants_1.RpcResponseCacheControl.None;
        /** Forces RpcConfiguration.strictMode for this operation. */
        this.forceStrictMode = false;
        /** Whether the IModelRpcProps in the operation parameter list is allowed to differ from the token in the request URL. */
        this.allowTokenMismatch = false;
        /** Whether to compress the operation response with one of the client's supported encodings. */
        this.allowResponseCompression = true;
    }
}
exports.RpcOperationPolicy = RpcOperationPolicy;
/** An RPC operation descriptor.
 * @internal
 */
class RpcOperation {
    /** Looks up an RPC operation by name. */
    static lookup(target, operationName) {
        const definition = typeof (target) === "string" ? RpcRegistry_1.RpcRegistry.instance.lookupInterfaceDefinition(target) : target;
        const propertyName = RpcOperation.computeOperationName(operationName);
        const proto = definition.prototype;
        if (!proto.hasOwnProperty(propertyName))
            throw new IModelError_1.IModelError(core_bentley_1.BentleyStatus.ERROR, `RPC interface class "${definition.interfaceName}" does not does not declare operation "${operationName}"`);
        return proto[propertyName][RpcRegistry_1.OPERATION];
    }
    /** Iterates the operations of an RPC interface definition. */
    static forEach(definition, callback) {
        Object.getOwnPropertyNames(definition.prototype).forEach((operationName) => {
            if (operationName === "constructor" || operationName === "configurationSupplier")
                return;
            const propertyName = RpcOperation.computeOperationName(operationName);
            callback(definition.prototype[propertyName][RpcRegistry_1.OPERATION]);
        });
    }
    /** The version of this operation. */
    get interfaceVersion() { return this.interfaceDefinition.interfaceVersion; }
    /** @internal */
    constructor(definition, operation, policy) {
        this.interfaceDefinition = definition;
        this.operationName = operation;
        this.policy = policy;
    }
    /** @internal */
    static computeOperationName(identifier) {
        const c = identifier.indexOf(":");
        if (c === -1)
            return identifier;
        return identifier.substring(0, c + 1);
    }
}
exports.RpcOperation = RpcOperation;
/** A fallback token to use for RPC requests that do not semantically depend on an iModel. */
RpcOperation.fallbackToken = undefined;
/** @internal */
(function (RpcOperation) {
    function obtainInstance(obj) {
        if (obj instanceof RpcOperationPolicy) {
            return obj;
        }
        else {
            const instance = new RpcOperationPolicy();
            Object.assign(instance, obj);
            return instance;
        }
    }
    /** Decorator for setting the policy for an RPC operation function. */
    function setPolicy(policy) {
        return (target, propertyKey, descriptor) => {
            descriptor.value[RpcRegistry_1.OPERATION] = new RpcOperation(target.constructor, propertyKey, obtainInstance(policy));
        };
    }
    RpcOperation.setPolicy = setPolicy;
    /** Convenience decorator for setting an RPC operation policy that allows response caching. */
    function allowResponseCaching(control = RpcConstants_1.RpcResponseCacheControl.Immutable) {
        return (target, propertyKey, descriptor) => {
            descriptor.value[RpcRegistry_1.OPERATION] = new RpcOperation(target.constructor, propertyKey, new class extends RpcOperationPolicy {
                constructor() {
                    super(...arguments);
                    this.allowResponseCaching = () => control;
                }
            }());
        };
    }
    RpcOperation.allowResponseCaching = allowResponseCaching;
    /** Convenience decorator for setting an RPC operation policy that supplies the IModelRpcProps for an operation. */
    function setRoutingProps(handler) {
        return (target, propertyKey, descriptor) => {
            descriptor.value[RpcRegistry_1.OPERATION] = new RpcOperation(target.constructor, propertyKey, new class extends RpcOperationPolicy {
                constructor() {
                    super(...arguments);
                    this.token = handler;
                }
            }());
        };
    }
    RpcOperation.setRoutingProps = setRoutingProps;
    /** Decorator for setting the default policy for an RPC interface definition class. */
    function setDefaultPolicy(policy) {
        return (definition) => {
            definition[RpcRegistry_1.POLICY] = obtainInstance(policy);
        };
    }
    RpcOperation.setDefaultPolicy = setDefaultPolicy;
})(RpcOperation || (exports.RpcOperation = RpcOperation = {}));
//# sourceMappingURL=RpcOperation.js.map