001/*
002 * Copyright (c) 2023. The BifroMQ Authors. All Rights Reserved.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *    http://www.apache.org/licenses/LICENSE-2.0
008 * Unless required by applicable law or agreed to in writing,
009 * software distributed under the License is distributed on an "AS IS" BASIS,
010 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
011 * See the License for the specific language governing permissions and limitations under the License.
012 */
013
014package com.baidu.bifromq.plugin.settingprovider;
015
016import java.util.function.Predicate;
017import lombok.extern.slf4j.Slf4j;
018
019@Slf4j
020public enum Setting {
021    MQTT3Enabled(Boolean.class, val -> true, true),
022    MQTT4Enabled(Boolean.class, val -> true, true),
023    MQTT5Enabled(Boolean.class, val -> true, true),
024    DebugModeEnabled(Boolean.class, val -> true, false),
025    ForceTransient(Boolean.class, val -> true, false),
026    ByPassPermCheckError(Boolean.class, val -> true, true),
027    PayloadFormatValidationEnabled(Boolean.class, val -> true, true),
028    RetainEnabled(Boolean.class, val -> true, true),
029    WildcardSubscriptionEnabled(Boolean.class, val -> true, true),
030    SubscriptionIdentifierEnabled(Boolean.class, val -> true, true),
031    SharedSubscriptionEnabled(Boolean.class, val -> true, true),
032    MaximumQoS(Integer.class, val -> (int) val == 0 || (int) val == 1 || (int) val == 2, 2),
033    MaxTopicLevelLength(Integer.class, val -> (int) val > 0, 40),
034    MaxTopicLevels(Integer.class, val -> (int) val > 0, 16),
035    MaxTopicLength(Integer.class, val -> (int) val > 0 && (int) val < 65536, 255),
036    MaxTopicAlias(Integer.class, val -> (int) val >= 0 && (int) val < 65536, 10),
037    MaxSharedGroupMembers(Integer.class, val -> (int) val > 0, 200),
038    MaxTopicFiltersPerInbox(Integer.class, val -> (int) val > 0, 100),
039    MsgPubPerSec(Integer.class, val -> (int) val > 0 && (int) val <= 1000, 200),
040    ReceivingMaximum(Integer.class, val -> (int) val > 0 && (int) val <= 65535, 200),
041    InBoundBandWidth(Long.class, val -> (long) val >= 0, 512 * 1024L),
042    OutBoundBandWidth(Long.class, val -> (long) val >= 0, 512 * 1024L),
043    MaxUserPayloadBytes(Integer.class, val -> (int) val > 0 && (int) val <= 256 * 1024 * 1024, 256 * 1024),
044    MaxResendTimes(Integer.class, val -> (int) val >= 0, 3),
045    ResendTimeoutSeconds(Integer.class, val -> (int) val > 0, 10),
046    MaxTopicFiltersPerSub(Integer.class, val -> (int) val > 0 && (int) val <= 100, 10),
047    MaxSessionExpirySeconds(Integer.class, val -> (int) val > 0, 24 * 60 * 60),
048    SessionInboxSize(Integer.class, val -> (int) val > 0 && (int) val <= 65535, 1000),
049    QoS0DropOldest(Boolean.class, val -> true, false),
050    RetainMessageMatchLimit(Integer.class, val -> (int) val >= 0, 10);
051
052    public final Class<?> valueType;
053    private final Predicate<Object> validator;
054    private final Object defVal;
055    private volatile ISettingProvider settingProvider;
056
057    Setting(Class<?> valueType, Predicate<Object> validator, Object defValue) {
058        this.valueType = valueType;
059        this.validator = validator;
060        this.defVal = resolve(defValue);
061        assert isValid(defVal);
062    }
063
064    /**
065     * The current effective setting's value for given tenant
066     *
067     * @param tenantId the id of the calling tenant
068     * @return The effective value of the setting for the client
069     */
070    public <R> R current(String tenantId) {
071        return settingProvider == null ? initialValue() : settingProvider.provide(this, tenantId);
072    }
073
074
075    /**
076     * Validate if provided value is a valid for the setting
077     *
078     * @param val the setting value to be verified
079     * @return true if the value is valid
080     */
081    public <R> boolean isValid(R val) {
082        if (!valueType.isInstance(val)) {
083            return false;
084        }
085        return this.validator.test(val);
086    }
087
088    @SuppressWarnings("unchecked")
089    <R> R initialValue() {
090        return (R) defVal;
091    }
092
093    void setProvider(ISettingProvider provider) {
094        this.settingProvider = provider;
095    }
096
097
098    Object resolve(Object initial) {
099        String override = System.getProperty(name());
100        if (override != null) {
101            try {
102                if (valueType == Integer.class) {
103                    return Integer.parseInt(override);
104                }
105                if (valueType == Long.class) {
106                    return Long.parseLong(override);
107                }
108                if (valueType == Boolean.class) {
109                    return Boolean.parseBoolean(override);
110                }
111            } catch (Throwable e) {
112                log.error("Unable to parse setting value from system property: setting={}, value={}",
113                    name(), override);
114                return initial;
115            }
116        }
117        return initial;
118    }
119}