<commit_before>/**
 * @module node-opcua-server
 */
// tslint:disable:no-console

import { EventEmitter } from "events";
import * as chalk from "chalk";

import { SessionContext, AddressSpace, BaseNode, Duration, UAObjectType } from "node-opcua-address-space";
import { assert } from "node-opcua-assert";
import { Byte, UInt32 } from "node-opcua-basic-types";
import { SubscriptionDiagnosticsDataType } from "node-opcua-common";
import { NodeClass, AttributeIds, isValidDataEncoding } from "node-opcua-data-model";
import { TimestampsToReturn } from "node-opcua-data-value";
import { checkDebugFlag, make_debugLog, make_warningLog } from "node-opcua-debug";
import { NodeId } from "node-opcua-nodeid";
import { ObjectRegistry } from "node-opcua-object-registry";
import { SequenceNumberGenerator } from "node-opcua-secure-channel";
import { EventFilter, checkSelectClauses } from "node-opcua-service-filter";
import { AggregateFilter } from "node-opcua-service-subscription";
import {
    DataChangeNotification,
    EventNotificationList,
    MonitoringMode,
    MonitoredItemCreateResult,
    MonitoredItemNotification,
    PublishResponse,
    NotificationMessage,
    StatusChangeNotification,
    DataChangeFilter,
    MonitoredItemCreateRequest
} from "node-opcua-service-subscription";
import { StatusCode, StatusCodes } from "node-opcua-status-code";
import { AggregateFilterResult, ContentFilterResult, EventFieldList, EventFilterResult, NotificationData } from "node-opcua-types";
import { Queue } from "./queue";

import { MonitoredItem, MonitoredItemOptions, QueueItem } from "./monitored_item";
import { ServerSession } from "./server_session";
import { validateFilter } from "./validate_filter";
import { IServerSidePublishEngine, TransferredSubscription } from "./i_server_side_publish_engine";

const debugLog = make_debugLog(__filename);
const doDebug = checkDebugFlag(__filename);
const warningLog = make_warningLog(__filename);
const maxNotificationMessagesInQueue = 100;

export interface SubscriptionDiagnosticsDataTypePriv extends SubscriptionDiagnosticsDataType {
    $subscription: Subscription;
}

export enum SubscriptionState {
    CLOSED = 1, // The Subscription has not yet been created or has terminated.
    CREATING = 2, // The Subscription is being created
    NORMAL = 3, // The Subscription is cyclically checking for Notifications from its MonitoredItems.
    // The keep-alive counter is not used in this state.
    LATE = 4, // The publishing timer has expired and there are Notifications available or a keep-alive Message is
    // ready to be sent, but there are no Publish requests queued. When in this state, the next Publish
    // request is processed when it is received. The keep-alive counter is not used in this state.
    KEEPALIVE = 5, // The Subscription is cyclically checking for Notification
    // alive counter to count down to 0 from its maximum.
    TERMINATED = 6
}

function _adjust_publishing_interval(publishingInterval?: number): number {
    publishingInterval =
        publishingInterval === undefined || Number.isNaN(publishingInterval)
            ? Subscription.defaultPublishingInterval
            : publishingInterval;
    publishingInterval = Math.max(publishingInterval, Subscription.minimumPublishingInterval);
    publishingInterval = Math.min(publishingInterval, Subscription.maximumPublishingInterval);
    return publishingInterval;
}

const minimumMaxKeepAliveCount = 2;
const maximumMaxKeepAliveCount = 12000;

function _adjust_maxKeepAliveCount(maxKeepAliveCount?: number /*,publishingInterval*/): number {
    maxKeepAliveCount = maxKeepAliveCount || minimumMaxKeepAliveCount;
    maxKeepAliveCount = Math.max(maxKeepAliveCount, minimumMaxKeepAliveCount);
    maxKeepAliveCount = Math.min(maxKeepAliveCount, maximumMaxKeepAliveCount);
    return maxKeepAliveCount;
}

function _adjust_lifeTimeCount(lifeTimeCount: number, maxKeepAliveCount: number, publishingInterval: number): number {
    lifeTimeCount = lifeTimeCount || 1;

    // let's make sure that lifeTimeCount is at least three time maxKeepAliveCount
    // Note : the specs say ( part 3  - CreateSubscriptionParameter )
    //        "The lifetime count shall be a minimum of three times the keep keep-alive count."
    lifeTimeCount = Math.max(lifeTimeCount, maxKeepAliveCount * 3);

    const minTicks = Math.ceil(Subscription.minimumLifetimeDuration / publishingInterval);
    const maxTicks = Math.floor(Subscription.maximumLifetimeDuration / publishingInterval);

    lifeTimeCount = Math.max(minTicks, lifeTimeCount);
    lifeTimeCount = Math.min(maxTicks, lifeTimeCount);
    return lifeTimeCount;
}

function _adjust_publishingEnable(publishingEnabled?: boolean | null): boolean {
    return publishingEnabled === null || publishingEnabled === undefined ? true : !!publishingEnabled;
}

function _adjust_maxNotificationsPerPublish(maxNotificationsPerPublish?: number): number {
    assert(Subscription.maxNotificationPerPublishHighLimit > 0, "Subscription.maxNotificationPerPublishHighLimit must be positive");

    maxNotificationsPerPublish = maxNotificationsPerPublish || 0;
    assert(typeof maxNotificationsPerPublish === "number");

    // must be strictly positive<commit_msg>fix: lifetimeCount adjustment<commit_after>/**
 * @module node-opcua-server
 */
// tslint:disable:no-console

import { EventEmitter } from "events";
import * as chalk from "chalk";

import { SessionContext, AddressSpace, BaseNode, Duration, UAObjectType } from "node-opcua-address-space";
import { assert } from "node-opcua-assert";
import { Byte, UInt32 } from "node-opcua-basic-types";
import { SubscriptionDiagnosticsDataType } from "node-opcua-common";
import { NodeClass, AttributeIds, isValidDataEncoding } from "node-opcua-data-model";
import { TimestampsToReturn } from "node-opcua-data-value";
import { checkDebugFlag, make_debugLog, make_warningLog } from "node-opcua-debug";
import { NodeId } from "node-opcua-nodeid";
import { ObjectRegistry } from "node-opcua-object-registry";
import { SequenceNumberGenerator } from "node-opcua-secure-channel";
import { EventFilter, checkSelectClauses } from "node-opcua-service-filter";
import { AggregateFilter } from "node-opcua-service-subscription";
import {
    DataChangeNotification,
    EventNotificationList,
    MonitoringMode,
    MonitoredItemCreateResult,
    MonitoredItemNotification,
    PublishResponse,
    NotificationMessage,
    StatusChangeNotification,
    DataChangeFilter,
    MonitoredItemCreateRequest
} from "node-opcua-service-subscription";
import { StatusCode, StatusCodes } from "node-opcua-status-code";
import { AggregateFilterResult, ContentFilterResult, EventFieldList, EventFilterResult, NotificationData } from "node-opcua-types";
import { Queue } from "./queue";

import { MonitoredItem, MonitoredItemOptions, QueueItem } from "./monitored_item";
import { ServerSession } from "./server_session";
import { validateFilter } from "./validate_filter";
import { IServerSidePublishEngine, TransferredSubscription } from "./i_server_side_publish_engine";

const debugLog = make_debugLog(__filename);
const doDebug = checkDebugFlag(__filename);
const warningLog = make_warningLog(__filename);
const maxNotificationMessagesInQueue = 100;

export interface SubscriptionDiagnosticsDataTypePriv extends SubscriptionDiagnosticsDataType {
    $subscription: Subscription;
}

export enum SubscriptionState {
    CLOSED = 1, // The Subscription has not yet been created or has terminated.
    CREATING = 2, // The Subscription is being created
    NORMAL = 3, // The Subscription is cyclically checking for Notifications from its MonitoredItems.
    // The keep-alive counter is not used in this state.
    LATE = 4, // The publishing timer has expired and there are Notifications available or a keep-alive Message is
    // ready to be sent, but there are no Publish requests queued. When in this state, the next Publish
    // request is processed when it is received. The keep-alive counter is not used in this state.
    KEEPALIVE = 5, // The Subscription is cyclically checking for Notification
    // alive counter to count down to 0 from its maximum.
    TERMINATED = 6
}

function _adjust_publishing_interval(publishingInterval?: number): number {
    publishingInterval =
        publishingInterval === undefined || Number.isNaN(publishingInterval)
            ? Subscription.defaultPublishingInterval
            : publishingInterval;
    publishingInterval = Math.max(publishingInterval, Subscription.minimumPublishingInterval);
    publishingInterval = Math.min(publishingInterval, Subscription.maximumPublishingInterval);
    return publishingInterval;
}

const minimumMaxKeepAliveCount = 2;
const maximumMaxKeepAliveCount = 12000;

function _adjust_maxKeepAliveCount(maxKeepAliveCount?: number /*,publishingInterval*/): number {
    maxKeepAliveCount = maxKeepAliveCount || minimumMaxKeepAliveCount;
    maxKeepAliveCount = Math.max(maxKeepAliveCount, minimumMaxKeepAliveCount);
    maxKeepAliveCount = Math.min(maxKeepAliveCount, maximumMaxKeepAliveCount);
    return maxKeepAliveCount;
}

const MaxUint32 = 0xFFFFFFFF;

function _adjust_lifeTimeCount(lifeTimeCount: number, maxKeepAliveCount: number, publishingInterval: number): number {
    lifeTimeCount = lifeTimeCount || 1;

    const minTicks = Math.ceil(Subscription.minimumLifetimeDuration / publishingInterval);
    const maxTicks = Math.floor(Subscription.maximumLifetimeDuration / publishingInterval);

    lifeTimeCount = Math.max(minTicks, lifeTimeCount);
    lifeTimeCount = Math.min(maxTicks, lifeTimeCount);

    // let's make sure that lifeTimeCount is at least three time maxKeepAliveCount
    // Note : the specs say ( part 3  - CreateSubscriptionParameter )
    //        "The lifetime count shall be a minimum of three times the keep keep-alive count."
    lifeTimeCount = Math.max(lifeTimeCount, Math.min(maxKeepAliveCount * 3, MaxUint32));

    return lifeTimeCount;
}

function _adjust_publishingEnable(publishingEnabled?: boolean | null): boolean {
    return publishingEnabled === null || publishingEnabled === undefined ? true : !!publishingEnabled;
}

function _adjust_maxNotificationsPerPublish(maxNotificationsPerPublish?: number): number {
    assert(Subscription.maxNotificationPerPublishHighLimit > 0, "Subscription.maxNotificationPerPublishHighLimit must be positive");

    maxNotificationsPerPublish = maxNotificationsPerPublish || 0;
    assert(typeof maxNotificationsPerPublish === "number");

    // must be strictly positive
{'fraction_non_alphanumeric': 0.0853022108359427, 'fraction_numerical': 0.004839168801594079, 'mean_word_length': 5.096009253903991, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 1, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '253118', 'n_tokens_mistral': 2918, 'n_tokens_neox': 2851, 'n_words': 783}