001/**
002 * Copyright (c) 2015-2022, Michael Yang 杨福海 (fuhai999@gmail.com).
003 * <p>
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 * <p>
008 * http://www.apache.org/licenses/LICENSE-2.0
009 * <p>
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package io.jboot.components.gateway;
017
018import io.jboot.utils.ConfigUtil;
019import io.jboot.components.gateway.discovery.GatewayDiscovery;
020import io.jboot.components.gateway.discovery.GatewayDiscoveryManager;
021import io.jboot.components.gateway.discovery.GatewayInstance;
022import io.jboot.utils.StrUtil;
023
024import javax.servlet.http.HttpServletRequest;
025import java.util.HashSet;
026import java.util.List;
027import java.util.Map;
028import java.util.Set;
029import java.util.concurrent.ConcurrentHashMap;
030
031/**
032 * @author michael yang (fuhai999@gmail.com)
033 * @Date: 2020/3/21
034 */
035public class JbootGatewayManager {
036
037    private static JbootGatewayManager me = new JbootGatewayManager();
038
039    public static JbootGatewayManager me() {
040        return me;
041    }
042
043    private Map<String, JbootGatewayConfig> configMap;
044    private GatewayErrorRender gatewayErrorRender;
045    private GatewayDiscovery discovery;
046
047
048    private JbootGatewayManager() {
049
050        initDiscovery();
051
052        initConfigs();
053    }
054
055    private void initConfigs() {
056        Map<String, JbootGatewayConfig> configMap = ConfigUtil.getConfigModels(JbootGatewayConfig.class, "jboot.gateway");
057        for (Map.Entry<String, JbootGatewayConfig> entry : configMap.entrySet()) {
058            if ("discovery".equals(entry.getKey()) || "instance".equals(entry.getKey())) {
059                continue;
060            }
061            JbootGatewayConfig config = entry.getValue();
062            if (StrUtil.isBlank(config.getName())) {
063                config.setName(entry.getKey());
064            }
065            registerConfig(config);
066        }
067    }
068
069    /**
070     * 初始化服务发现
071     */
072    private void initDiscovery() {
073        this.discovery = GatewayDiscoveryManager.me().getGatewayDiscovery();
074    }
075
076    public boolean isConfigOk() {
077        return configMap != null && !configMap.isEmpty();
078    }
079
080
081    /**
082     * 动态注册新的路由配置
083     *
084     * @param config 配置信息
085     */
086    public void registerConfig(JbootGatewayConfig config) {
087        if (configMap == null) {
088            configMap = new ConcurrentHashMap<>();
089        }
090        configMap.put(config.getName(), config);
091
092        if (discovery != null) {
093            List<GatewayInstance> healthyInstances = discovery.selectInstances(config.getName(), true);
094            syncDiscoveryUris(healthyInstances, config);
095
096            discovery.subscribe(config.getName(), eventInfo -> {
097                List<GatewayInstance> changedInstances = eventInfo.getInstances();
098                syncDiscoveryUris(changedInstances, config);
099            });
100        }
101
102        if (config.isEnable()) {
103            JbootGatewayHealthChecker.me().start();
104        }
105    }
106
107    private void syncDiscoveryUris(List<GatewayInstance> instances, JbootGatewayConfig config) {
108        if (instances == null) {
109            config.syncDiscoveryUris(null);
110        } else {
111            Set<String> uris = new HashSet<>();
112            instances.forEach(instance -> {
113                if (instance.isHealthy()) {
114                    uris.add(instance.getUri());
115                }
116            });
117            config.syncDiscoveryUris(uris);
118        }
119    }
120
121
122    /**
123     * 动态移除路由配置
124     *
125     * @param name 配置名称
126     * @return 被移除的配置信息
127     */
128    public JbootGatewayConfig removeConfig(String name) {
129        return configMap == null ? null : configMap.remove(name);
130    }
131
132
133    /**
134     * 获取某个配置信息
135     *
136     * @param name 配置名称
137     * @return 配置信息
138     */
139    public JbootGatewayConfig getConfig(String name) {
140        return configMap == null ? null : configMap.get(name);
141    }
142
143
144    /**
145     * 获取所有的配置信息
146     *
147     * @return
148     */
149    public Map<String, JbootGatewayConfig> getConfigMap() {
150        return configMap;
151    }
152
153    /**
154     * 匹配可用的网关
155     *
156     * @param req 请求
157     * @return 返回匹配到的网关配置
158     */
159    public JbootGatewayConfig matchingConfig(HttpServletRequest req) {
160        if (configMap != null && !configMap.isEmpty()) {
161            for (JbootGatewayConfig config : configMap.values()) {
162                if (config.isEnable() && config.matches(req)) {
163                    return config;
164                }
165            }
166        }
167        return null;
168    }
169
170    public GatewayErrorRender getGatewayErrorRender() {
171        return gatewayErrorRender;
172    }
173
174    public void setGatewayErrorRender(GatewayErrorRender gatewayErrorRender) {
175        this.gatewayErrorRender = gatewayErrorRender;
176    }
177
178
179}