apache_dubbo/common/
url.rs

1/*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements.  See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License.  You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18use std::collections::HashMap;
19
20#[derive(Debug, Clone, Default, PartialEq)]
21pub struct Url {
22    pub uri: String,
23    pub protocol: String,
24    pub location: String,
25    pub ip: String,
26    pub port: String,
27    pub service_key: Vec<String>,
28    pub params: HashMap<String, String>,
29}
30
31impl Url {
32    pub fn new() -> Self {
33        Default::default()
34    }
35
36    pub fn from_url(url: &str) -> Option<Self> {
37        // url: triple://127.0.0.1:8888/helloworld.Greeter
38        let uri = url
39            .parse::<http::Uri>()
40            .map_err(|err| {
41                tracing::error!("fail to parse url({}), err: {:?}", url, err);
42            })
43            .unwrap();
44        Some(Self {
45            uri: uri.to_string(),
46            protocol: uri.scheme_str()?.to_string(),
47            ip: uri.authority()?.host().to_string(),
48            port: uri.authority()?.port()?.to_string(),
49            location: uri.authority()?.to_string(),
50            service_key: uri
51                .path()
52                .trim_start_matches('/')
53                .split(',')
54                .map(|x| x.to_string())
55                .collect::<Vec<_>>(),
56            params: HashMap::new(),
57        })
58    }
59
60    pub fn get_service_name(&self) -> Vec<String> {
61        self.service_key.clone()
62    }
63
64    pub fn get_param(&self, key: String) -> Option<String> {
65        self.params.get(&key).cloned()
66    }
67
68    pub fn encode_param(&self) -> String {
69        let mut params_vec: Vec<String> = Vec::new();
70        for (k, v) in self.params.iter() {
71            // let tmp = format!("{}={}", k, v);
72            params_vec.push(format!("{}={}", k, v));
73        }
74        params_vec.join("&")
75    }
76
77    pub fn decode(&mut self, params: String) {
78        let p: Vec<String> = params.split('&').map(|v| v.trim().to_string()).collect();
79        for v in p.iter() {
80            let values: Vec<String> = v.split('=').map(|v| v.trim().to_string()).collect();
81            if values.len() != 2 {
82                continue;
83            }
84            self.params.insert(values[0].clone(), values[1].clone());
85        }
86    }
87
88    pub fn to_url(&self) -> String {
89        format!("{}://{}:{}", self.protocol, self.ip, self.port)
90    }
91}
92
93#[cfg(test)]
94mod tests {
95    use super::*;
96
97    #[test]
98    fn test_from_url() {
99        let u1 = Url::from_url("");
100    }
101
102    #[test]
103    fn test_encode_params() {
104        let mut u = Url::default();
105        u.params.insert("method".to_string(), "GET".to_string());
106        u.params.insert("args".to_string(), "GET".to_string());
107
108        let en = u.encode_param();
109        println!("encode_params: {:?}", en);
110
111        let mut u1 = Url::default();
112        u1.decode(en);
113        println!("decode_params: {:?}", u1);
114        assert_eq!(u1, u);
115    }
116}