Junjie
17 小时以前 42ce1f4b6f9df984d14e29f9d9ff188de7f3c6d7
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
package com.zy.asrs.service.impl;
 
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.core.exception.CoolException;
import com.zy.asrs.service.RuntimeConfigService;
import com.zy.system.entity.Config;
import com.zy.system.service.ConfigService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
 
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
 
@Service("runtimeConfigService")
public class RuntimeConfigServiceImpl implements RuntimeConfigService {
 
    private static final LinkedHashMap<String, RuntimeConfigRule> RUNTIME_CONFIG_RULE_MAP = buildRuntimeConfigRuleMap();
 
    @Autowired
    private ConfigService configService;
 
    @Override
    @Transactional
    public Map<String, Object> updateRuntimeConfig(Map<String, Object> configMap) {
        if (configMap == null || configMap.isEmpty()) {
            throw new CoolException("参数不能为空");
        }
 
        LinkedHashMap<String, String> normalizedMap = new LinkedHashMap<>();
        for (Map.Entry<String, Object> entry : configMap.entrySet()) {
            String code = entry.getKey();
            RuntimeConfigRule rule = RUNTIME_CONFIG_RULE_MAP.get(code);
            if (rule == null) {
                throw new CoolException("不支持的运行参数: " + code);
            }
 
            Config config = getConfig(code);
            if (config == null) {
                throw new CoolException("运行参数不存在: " + code);
            }
            if (!Short.valueOf((short) 1).equals(config.getStatus())) {
                throw new CoolException("运行参数已禁用: " + code);
            }
 
            normalizedMap.put(code, rule.normalize(code, entry.getValue()));
        }
 
        LinkedHashMap<String, String> changedMap = saveChangedConfig(normalizedMap);
        if (!changedMap.isEmpty()) {
            configService.refreshSystemConfigCache();
        }
 
        LinkedHashMap<String, Object> result = new LinkedHashMap<>();
        result.put("changed", changedMap);
        result.put("current", buildRuntimeConfigSnapshot(normalizedMap.keySet()));
        return result;
    }
 
    private LinkedHashMap<String, String> saveChangedConfig(LinkedHashMap<String, String> normalizedMap) {
        LinkedHashMap<String, String> changedMap = new LinkedHashMap<>();
        for (Map.Entry<String, String> entry : normalizedMap.entrySet()) {
            Config config = getConfig(entry.getKey());
            if (config == null) {
                throw new CoolException("运行参数不存在: " + entry.getKey());
            }
            if (Objects.equals(config.getValue(), entry.getValue())) {
                continue;
            }
            config.setValue(entry.getValue());
            if (!configService.updateById(config)) {
                throw new CoolException("保存失败: " + entry.getKey());
            }
            changedMap.put(entry.getKey(), entry.getValue());
        }
        return changedMap;
    }
 
    private LinkedHashMap<String, String> buildRuntimeConfigSnapshot(Set<String> codeSet) {
        LinkedHashMap<String, String> result = new LinkedHashMap<>();
        for (String code : codeSet) {
            Config config = getConfig(code);
            if (config != null) {
                result.put(code, config.getValue());
            }
        }
        return result;
    }
 
    private Config getConfig(String code) {
        return configService.getOne(new QueryWrapper<Config>().eq("code", code).last("limit 1"));
    }
 
    private static LinkedHashMap<String, RuntimeConfigRule> buildRuntimeConfigRuleMap() {
        LinkedHashMap<String, RuntimeConfigRule> ruleMap = new LinkedHashMap<>();
        putIntRule(ruleMap, "conveyorStationTaskLimit", 1, 1000);
        putIntRule(ruleMap, "aiAutoTuneIntervalMinutes", 5, 60);
        putIntRule(ruleMap, "stationCommandSendLength", 1, 200);
        putRatioRule(ruleMap, "stationCommandSegmentAdvanceRatio");
        putIntRule(ruleMap, "stationCommandConfigRefreshSeconds", 5, 300);
        putIntRule(ruleMap, "stationV5SegmentExecutorPoolSize", 16, 512);
        putIntRule(ruleMap, "stationV5SegmentExecutorQueueCapacity", 64, 4096);
        putIntRule(ruleMap, "crnOutBatchRunningLimit", 0, 1000);
        putBooleanRule(ruleMap, "crnOutRequireStationOutEnable");
        putIntRule(ruleMap, "deviceCommandAutoRollbackLimit", 1, 100);
        putBooleanRule(ruleMap, "checkDeepLocOutTaskBlockReport");
        return ruleMap;
    }
 
    private static void putIntRule(LinkedHashMap<String, RuntimeConfigRule> ruleMap,
                                   String code,
                                   int min,
                                   int max) {
        ruleMap.put(code, new RuntimeConfigRule(RuntimeConfigValueType.INT, min, max));
    }
 
    private static void putRatioRule(LinkedHashMap<String, RuntimeConfigRule> ruleMap, String code) {
        ruleMap.put(code, new RuntimeConfigRule(RuntimeConfigValueType.RATIO, 0, 100));
    }
 
    private static void putBooleanRule(LinkedHashMap<String, RuntimeConfigRule> ruleMap, String code) {
        ruleMap.put(code, new RuntimeConfigRule(RuntimeConfigValueType.BOOLEAN, 0, 0));
    }
 
    private enum RuntimeConfigValueType {
        INT,
        RATIO,
        BOOLEAN
    }
 
    private static class RuntimeConfigRule {
 
        private final RuntimeConfigValueType valueType;
        private final int min;
        private final int max;
 
        private RuntimeConfigRule(RuntimeConfigValueType valueType, int min, int max) {
            this.valueType = valueType;
            this.min = min;
            this.max = max;
        }
 
        private String normalize(String code, Object rawValue) {
            if (rawValue == null) {
                throw new CoolException(code + " 参数不能为空");
            }
            String value = String.valueOf(rawValue).trim();
            if (value.isEmpty()) {
                throw new CoolException(code + " 参数不能为空");
            }
            if (RuntimeConfigValueType.BOOLEAN.equals(valueType)) {
                return normalizeBoolean(code, value);
            }
            if (RuntimeConfigValueType.RATIO.equals(valueType)) {
                return normalizeRatio(code, value);
            }
            return normalizeInt(code, value);
        }
 
        private String normalizeBoolean(String code, String value) {
            if ("Y".equalsIgnoreCase(value) || "true".equalsIgnoreCase(value) || "1".equals(value)) {
                return "Y";
            }
            if ("N".equalsIgnoreCase(value) || "false".equalsIgnoreCase(value) || "0".equals(value)) {
                return "N";
            }
            throw new CoolException(code + " 仅支持 Y/N、true/false 或 1/0");
        }
 
        private String normalizeRatio(String code, String value) {
            String text = value;
            boolean percentText = text.endsWith("%");
            if (percentText) {
                text = text.substring(0, text.length() - 1).trim();
            }
            double parsed;
            try {
                parsed = Double.parseDouble(text);
            } catch (Exception e) {
                throw new CoolException(code + " 必须为 0~1 比例或 0~100 百分比");
            }
            if (parsed < 0d || parsed > 100d) {
                throw new CoolException(code + " 必须为 0~1 比例或 0~100 百分比");
            }
            if (percentText || parsed > 1d) {
                parsed = parsed / 100d;
            }
            return stripTrailingZero(parsed);
        }
 
        private String normalizeInt(String code, String value) {
            int parsed;
            try {
                parsed = Integer.parseInt(value);
            } catch (Exception e) {
                throw new CoolException(code + " 必须为整数");
            }
            if (parsed < min || parsed > max) {
                throw new CoolException(code + " 必须在 " + min + "~" + max + " 范围内");
            }
            return String.valueOf(parsed);
        }
 
        private String stripTrailingZero(double value) {
            String text = java.math.BigDecimal.valueOf(value).stripTrailingZeros().toPlainString();
            return "-0".equals(text) ? "0" : text;
        }
    }
}