1 module hunt.service.util.UrlHelper;
2 
3 import hunt.service.util.UrlInfo;
4 import hunt.collection.ArrayList;
5 import hunt.collection.HashMap;
6 import hunt.collection.List;
7 import hunt.collection.Map;
8 import hunt.Exceptions;
9 import hunt.text.StringBuilder;
10 import std.string;
11 import std.conv;
12 import hunt.text.Common;
13 import hunt.text.StringUtils;
14 import hunt.service.util.CommonUtils;
15 
16 
17 enum UrlInfoAttrs
18 {
19     ATTR_RPC_VERSION = "rpcVer",
20     ATTR_SERIALIZATION = "serialization",
21     ATTR_WEIGHT = "weight",
22 }
23 
24 public class UrlHelper {
25     
26 
27     /**
28      * Compare two provider list, return add list and remove list
29      *
30      * @param oldList old Provider list
31      * @param newList new provider list
32      * @param add     provider list need add
33      * @param remove  provider list need remove
34      */
35     // public static void compareProviders(List!(UrlInfo) oldList, List!(UrlInfo) newList,
36     //                                     List!(UrlInfo) add, List!(UrlInfo) remove) {
37     //     // 比较老列表和当前列表
38     //     if (oldList is null || oldList.size == 0) {
39     //         // 空变成非空
40     //         if (newList !is null) {
41     //             add.addAll(newList);
42     //         }
43     //         // 空到空,忽略
44     //     } else {
45     //         // 非空变成空
46     //         if (newList is null || newList.size == 0) {
47     //             remove.addAll(oldList);
48     //         } else {
49     //             // 非空变成非空,比较
50     //             if (oldList !is null) {
51     //                 List!(UrlInfo) tmpList = new ArrayList!(UrlInfo)();
52     //                 foreach(value; newList) {
53     //                     tmpList.add(value);
54     //                 }
55     //                 // 遍历老的
56     //                 foreach (UrlInfo oldProvider ; oldList) {
57     //                     if (tmpList.contains(oldProvider)) {
58     //                         tmpList.remove(oldProvider);
59     //                     } else {
60     //                         // 新的没有,老的有,删掉
61     //                         remove.add(oldProvider);
62     //                     }
63     //                 }
64     //                 add.addAll(tmpList);
65     //             }
66     //         }
67     //     }
68     // }
69     
70     /**
71      * Write provider info to url string
72      * 
73      * @param providerInfo Provide info
74      * @return the string
75      */
76     public static string toUrl(UrlInfo providerInfo) {
77         string uri = providerInfo.getProtocolType() ~ "://" ~ providerInfo.getHost().to!string ~ ":" ~ providerInfo.getPort().to!string;
78         uri ~= strip(providerInfo.getPath());
79         StringBuilder sb = new StringBuilder();
80         if (providerInfo.getRpcVersion() > 0) {
81             sb.append("&").append(UrlInfoAttrs.ATTR_RPC_VERSION).append("=").append(providerInfo.getRpcVersion());
82         }
83         if (providerInfo.getSerializationType() != null) {
84             sb.append("&").append(UrlInfoAttrs.ATTR_SERIALIZATION).append("=")
85                 .append(providerInfo.getSerializationType());
86         }
87         foreach(string k , string v ; providerInfo.getStaticAttrs()) {
88             sb.append("&").append(k).append("=").append(v);
89         }
90         if (sb.length() > 0) {
91             uri ~= sb.replace(0, 1, "?").toString();
92         }
93         return uri;
94     }
95 
96     /**
97      * Parse url string to UrlInfo.
98      *
99      * @param url the url
100      * @return UrlInfo 
101      */
102     public static UrlInfo toProviderInfo(string url) {
103         UrlInfo providerInfo = new UrlInfo();
104         providerInfo.setOriginUrl(url);
105         try {
106             int protocolIndex = cast(int)(url.indexOf("://"));
107             string remainUrl;
108             if (protocolIndex > -1) {
109                 string protocol = url.substring(0, protocolIndex).toLower();
110                 providerInfo.setProtocolType(protocol);
111                 remainUrl = url.substring(protocolIndex + 3);
112             } else { // 默认
113                 remainUrl = url;
114             }
115 
116             int addressIndex = cast(int)(remainUrl.indexOf("/"));
117             string address;
118             if (addressIndex > -1) {
119                 address = remainUrl.substring(0, addressIndex);
120                 remainUrl = remainUrl.substring(addressIndex);
121             } else {
122                 int itfIndex = cast(int)(remainUrl.indexOf('?'));
123                 if (itfIndex > -1) {
124                     address = remainUrl.substring(0, itfIndex);
125                     remainUrl = remainUrl.substring(itfIndex);
126                 } else {
127                     address = remainUrl;
128                     remainUrl = "";
129                 }
130             }
131             string[] ipAndPort = StringUtils.split(address,":", -1); // TODO 不支持ipv6
132             providerInfo.setHost(ipAndPort[0]);
133             if (ipAndPort.length > 1) {
134                 providerInfo.setPort(CommonUtils.parseInt(ipAndPort[1], providerInfo.getPort()));
135             }
136 
137             // 后面可以解析remainUrl得到interface等 /xxx?a=1&b=2
138             if (remainUrl.length > 0) {
139                 int itfIndex = cast(int)(remainUrl.indexOf('?'));
140                 if (itfIndex > -1) {
141                     string itf = remainUrl.substring(0, itfIndex);
142                     providerInfo.setPath(itf);
143                     // 剩下是params,例如a=1&b=2
144                     remainUrl = remainUrl.substring(itfIndex + 1);
145                     string[] params = StringUtils.split(remainUrl,"&", -1);
146                     foreach (string parm ; params) {
147                         string[] kvpair = StringUtils.split(parm,"=", -1);
148                         if (UrlInfoAttrs.ATTR_WEIGHT.equals(kvpair[0]) && CommonUtils.isNotEmpty(kvpair[1])) {
149                             int weight = CommonUtils.parseInt(kvpair[1], providerInfo.getWeight());
150                             providerInfo.setWeight(weight);
151                             providerInfo.setStaticAttr(UrlInfoAttrs.ATTR_WEIGHT, to!string(weight));
152                         } else if (UrlInfoAttrs.ATTR_RPC_VERSION == kvpair[0] && CommonUtils.isNotEmpty(kvpair[1])) {
153                             providerInfo.setRpcVersion(CommonUtils.parseInt(kvpair[1], providerInfo.getRpcVersion()));
154                         } else if (UrlInfoAttrs.ATTR_SERIALIZATION == kvpair[0] &&
155                             CommonUtils.isNotEmpty(kvpair[1])) {
156                             providerInfo.setSerializationType(kvpair[1]);
157                         } else {
158                             providerInfo.getStaticAttrs().put(kvpair[0], kvpair[1]);
159                         }
160 
161                     }
162                 } else {
163                     providerInfo.setPath(remainUrl);
164                 }
165             } else {
166                 providerInfo.setPath("");
167             }
168         } catch (Exception e) {
169             throw new IllegalArgumentException("Failed to convert url to provider, the wrong url is:" ~ url, e);
170         }
171         return providerInfo;
172     }
173 }