initial commit

This commit is contained in:
zhangjingqiang 2023-03-09 17:55:45 +08:00
commit 13716f4923
1425 changed files with 163227 additions and 0 deletions

32
lib/g3-msgpack/src/key.rs Normal file
View file

@ -0,0 +1,32 @@
/*
* Copyright 2023 ByteDance and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
pub fn normalize(raw: &str) -> String {
raw.to_lowercase().replace('-', "_")
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn t() {
assert_eq!(normalize("Abc"), "abc");
assert_eq!(normalize("ABC"), "abc");
assert_eq!(normalize("A-B-C"), "a_b_c");
assert_eq!(normalize("A-B_C"), "a_b_c");
}
}

18
lib/g3-msgpack/src/lib.rs Normal file
View file

@ -0,0 +1,18 @@
/*
* Copyright 2023 ByteDance and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
pub mod key;
pub mod value;

View file

@ -0,0 +1,57 @@
/*
* Copyright 2023 ByteDance and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
use anyhow::anyhow;
use chrono::{DateTime, Utc};
use rmpv::ValueRef;
pub fn as_rfc3339_datetime(value: &ValueRef) -> anyhow::Result<DateTime<Utc>> {
match value {
ValueRef::String(s) => match s.as_str() {
Some(s) => {
let datetime = DateTime::parse_from_rfc3339(s)
.map_err(|e| anyhow!("invalid rfc3339 datetime string: {e}"))?;
Ok(datetime.with_timezone(&Utc))
}
None => Err(anyhow!("invalid utf-8 string")),
},
_ => Err(anyhow!(
"yaml value type for 'rfc3339 datetime' should be string"
)),
}
}
#[cfg(test)]
mod tests {
use super::*;
use rmpv::Utf8StringRef;
#[test]
fn utc_tz() {
let value = ValueRef::String(Utf8StringRef::from("2019-05-23T17:38:00Z"));
let dt = as_rfc3339_datetime(&value).unwrap();
assert_eq!(dt.to_rfc3339(), "2019-05-23T17:38:00+00:00");
}
#[test]
fn t_error() {
let value = ValueRef::String(Utf8StringRef::from("2019-05-23 17:38:00"));
assert!(as_rfc3339_datetime(&value).is_err());
let value = ValueRef::F32(1.0);
assert!(as_rfc3339_datetime(&value).is_err());
}
}

View file

@ -0,0 +1,29 @@
/*
* Copyright 2023 ByteDance and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
mod datetime;
mod primary;
mod uuid;
#[cfg(feature = "rustls")]
mod rustls;
pub use self::uuid::as_uuid;
pub use datetime::as_rfc3339_datetime;
pub use primary::{as_f64, as_string, as_u32, as_weighted_name_string};
#[cfg(feature = "rustls")]
pub use self::rustls::{as_certificates, as_private_key};

View file

@ -0,0 +1,227 @@
/*
* Copyright 2023 ByteDance and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
use std::str::FromStr;
use anyhow::{anyhow, Context};
use atoi::FromRadix10;
use rmpv::ValueRef;
use g3_types::collection::WeightedValue;
pub fn as_string(v: &ValueRef) -> anyhow::Result<String> {
match v {
ValueRef::String(s) => s
.as_str()
.map(|s| s.to_owned())
.ok_or_else(|| anyhow!("invalid utf-8 string")),
ValueRef::Binary(b) => {
let s = std::str::from_utf8(b).map_err(|e| anyhow!("invalid utf-8 string: {e}"))?;
Ok(s.to_string())
}
ValueRef::Integer(i) => Ok(i.to_string()),
_ => Err(anyhow!(
"msgpack value type for string should be 'string' / 'binary' / 'integer'"
)),
}
}
pub fn as_u32(v: &ValueRef) -> anyhow::Result<u32> {
match v {
ValueRef::String(s) => match s.as_str() {
Some(s) => u32::from_str(s).map_err(|e| anyhow!("invalid u32 string: {e}")),
None => Err(anyhow!("invalid utf-8 string")),
},
ValueRef::Binary(b) => {
let (v, len) = u32::from_radix_10(b);
if len != b.len() {
Err(anyhow!("invalid u32 binary string"))
} else {
Ok(v)
}
}
ValueRef::Integer(i) => match i.as_u64() {
Some(i) => u32::try_from(i).map_err(|e| anyhow!("out of range u32 integer: {e}")),
None => Err(anyhow!("invalid unsigned integer value")),
},
_ => Err(anyhow!(
"msgpack value type for 'u32' should be 'integer' / 'string' / 'binary'"
)),
}
}
pub fn as_f64(v: &ValueRef) -> anyhow::Result<f64> {
match v {
ValueRef::Integer(i) => i
.as_f64()
.ok_or_else(|| anyhow!("out of range integer value")),
ValueRef::F64(f) => Ok(*f),
ValueRef::F32(f) => Ok(*f as f64),
ValueRef::String(s) => match s.as_str() {
Some(s) => f64::from_str(s).map_err(|e| anyhow!("invalid f64 string: {e}")),
None => Err(anyhow!("invalid utf-8 string")),
},
_ => Err(anyhow!(
"msgpack value type for 'f64' should be 'integer' or 'f64' or 'f32' or 'string'"
)),
}
}
pub fn as_weighted_name_string(v: &ValueRef) -> anyhow::Result<WeightedValue<String>> {
const KEY_NAME: &str = "name";
const KEY_WEIGHT: &str = "weight";
match v {
ValueRef::Map(map) => {
let mut name: Option<String> = None;
let mut weight = WeightedValue::<String>::DEFAULT_WEIGHT;
for (k, v) in map {
let key = as_string(k).context("all keys should be string")?;
match crate::key::normalize(key.as_str()).as_str() {
KEY_NAME => {
let v =
as_string(v).context(format!("invalid string value for key {key}"))?;
name = Some(v);
}
KEY_WEIGHT => {
weight = crate::value::as_f64(v)
.context(format!("invalid f64 value for key {key}"))?;
}
_ => {} // ignore all other keys
}
}
match name {
Some(s) => Ok(WeightedValue::with_weight(s, weight)),
None => Err(anyhow!("no required key {KEY_NAME} found")),
}
}
_ => {
let s = as_string(v).context("invalid string value")?;
Ok(WeightedValue::new(s))
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use rmpv::{Integer, Utf8StringRef, ValueRef};
#[test]
fn t_string() {
let v = ValueRef::String(Utf8StringRef::from("123.0"));
let pv = as_string(&v).unwrap();
assert_eq!(pv, "123.0");
let v = ValueRef::Integer(Integer::from(123u32));
let pv = as_string(&v).unwrap();
assert_eq!(pv, "123");
let v = ValueRef::Integer(Integer::from(-123i32));
let pv = as_string(&v).unwrap();
assert_eq!(pv, "-123");
let v = ValueRef::F32(123.0);
assert!(as_string(&v).is_err());
let v = ValueRef::Boolean(false);
assert!(as_string(&v).is_err());
}
#[test]
fn t_u32() {
let v = ValueRef::String(Utf8StringRef::from("123"));
let pv = as_u32(&v).unwrap();
assert_eq!(pv, 123u32);
let v = ValueRef::Integer(Integer::from(123u64));
let pv = as_u32(&v).unwrap();
assert_eq!(pv, 123u32);
let v = ValueRef::Integer(Integer::from(4_294_967_296u64));
assert!(as_u32(&v).is_err());
let v = ValueRef::Integer(Integer::from(-123i32));
assert!(as_u32(&v).is_err());
let v = ValueRef::F32(123.0);
assert!(as_u32(&v).is_err());
let v = ValueRef::Boolean(false);
assert!(as_string(&v).is_err());
}
#[test]
fn t_f64() {
let v = ValueRef::String(Utf8StringRef::from("123"));
let pv = as_f64(&v).unwrap();
assert_eq!(pv, 123.0f64);
let v = ValueRef::String(Utf8StringRef::from("123.0"));
let pv = as_f64(&v).unwrap();
assert_eq!(pv, 123.0f64);
let v = ValueRef::String(Utf8StringRef::from("-123"));
let pv = as_f64(&v).unwrap();
assert_eq!(pv, -123.0f64);
let v = ValueRef::Integer(Integer::from(123u64));
let pv = as_f64(&v).unwrap();
assert_eq!(pv, 123.0f64);
let v = ValueRef::F32(123.0);
let pv = as_f64(&v).unwrap();
assert_eq!(pv, 123.0f64);
let v = ValueRef::F64(123.0);
let pv = as_f64(&v).unwrap();
assert_eq!(pv, 123.0f64);
let v = ValueRef::Boolean(false);
assert!(as_string(&v).is_err());
}
#[test]
fn t_weighted_name_string() {
let v = ValueRef::String(Utf8StringRef::from("anc"));
let pv = as_weighted_name_string(&v).unwrap();
assert_eq!(pv, WeightedValue::<String>::new("anc".to_string()));
let v = vec![(
ValueRef::String(Utf8StringRef::from("name")),
ValueRef::String(Utf8StringRef::from("anc")),
)];
let v = ValueRef::Map(v);
let pv = as_weighted_name_string(&v).unwrap();
assert_eq!(pv, WeightedValue::<String>::new("anc".to_string()));
let v = vec![
(
ValueRef::String(Utf8StringRef::from("name")),
ValueRef::String(Utf8StringRef::from("anc")),
),
(
ValueRef::String(Utf8StringRef::from("weight")),
ValueRef::Integer(Integer::from(1)),
),
];
let v = ValueRef::Map(v);
let pv = as_weighted_name_string(&v).unwrap();
assert_eq!(pv, WeightedValue::<String>::new("anc".to_string()));
}
}

View file

@ -0,0 +1,85 @@
/*
* Copyright 2023 ByteDance and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
use std::io::{BufRead, BufReader};
use anyhow::{anyhow, Context};
use rmpv::ValueRef;
use rustls::{Certificate, PrivateKey};
use rustls_pemfile::Item;
fn as_certificates_from_single_element(value: &ValueRef) -> anyhow::Result<Vec<Certificate>> {
let bytes = match value {
ValueRef::String(s) => s.as_bytes(),
ValueRef::Binary(b) => *b,
_ => {
return Err(anyhow!(
"msgpack value type 'certificates' should be 'string' or 'binary'"
));
}
};
let certs = rustls_pemfile::certs(&mut BufReader::new(bytes))
.map_err(|e| anyhow!("invalid certificate string: {e:?}"))?;
if certs.is_empty() {
Err(anyhow!("no valid certificate found"))
} else {
Ok(certs.into_iter().map(Certificate).collect())
}
}
pub fn as_certificates(value: &ValueRef) -> anyhow::Result<Vec<Certificate>> {
if let ValueRef::Array(seq) = value {
let mut certs = Vec::with_capacity(seq.len());
for (i, v) in seq.iter().enumerate() {
let this_certs = as_certificates_from_single_element(v)
.context(format!("invalid certificates value for element #{i}"))?;
certs.extend(this_certs);
}
Ok(certs)
} else {
as_certificates_from_single_element(value)
}
}
fn read_first_private_key<R>(reader: &mut R) -> anyhow::Result<PrivateKey>
where
R: BufRead,
{
loop {
match rustls_pemfile::read_one(reader)
.map_err(|e| anyhow!("read private key failed: {e:?}"))?
{
Some(Item::PKCS8Key(d)) => return Ok(PrivateKey(d)),
Some(Item::RSAKey(d)) => return Ok(PrivateKey(d)),
Some(Item::ECKey(d)) => return Ok(PrivateKey(d)),
Some(_) => continue,
None => return Err(anyhow!("no valid private key found")),
}
}
}
pub fn as_private_key(value: &ValueRef) -> anyhow::Result<PrivateKey> {
let bytes = match value {
ValueRef::String(s) => s.as_bytes(),
ValueRef::Binary(b) => *b,
_ => {
return Err(anyhow!(
"msgpack value type for 'private key' should be 'string' or 'binary'"
));
}
};
read_first_private_key(&mut BufReader::new(bytes))
}

View file

@ -0,0 +1,68 @@
/*
* Copyright 2023 ByteDance and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
use anyhow::anyhow;
use rmpv::ValueRef;
use uuid::Uuid;
pub fn as_uuid(v: &ValueRef) -> anyhow::Result<Uuid> {
match v {
ValueRef::String(s) => {
if let Some(s) = s.as_str() {
Uuid::parse_str(s).map_err(|e| anyhow!("invalid encoded uuid string: {e}"))
} else {
Err(anyhow!("invalid utf-8 string"))
}
}
ValueRef::Binary(b) => Uuid::from_slice(b).map_err(|e| anyhow!("invalid uuid bytes: {e}")),
_ => Err(anyhow!(
"msgpack value type for 'uuid' should be 'binary' or 'string'"
)),
}
}
#[cfg(test)]
mod tests {
use super::*;
use rmpv::Utf8StringRef;
#[test]
fn t_uuid() {
let slice_v: [u8; 16] = [
0x70, 0xa7, 0xc2, 0xbb, 0x47, 0x6f, 0x4d, 0x79, 0x8a, 0x38, 0xc7, 0xc6, 0xaf, 0xfb,
0xfa, 0xf7,
];
let tv = Uuid::from_slice(&slice_v).unwrap();
let v = ValueRef::String(Utf8StringRef::from("70a7c2bb-476f-4d79-8a38-c7c6affbfaf7"));
let pv = as_uuid(&v).unwrap();
assert_eq!(pv, tv);
let v = ValueRef::String(Utf8StringRef::from("70a7c2bb476f4d798a38c7c6affbfaf7"));
let pv = as_uuid(&v).unwrap();
assert_eq!(pv, tv);
let v = ValueRef::String(Utf8StringRef::from("70a7c2bb476f4d798a38c7c6affbfaf"));
assert!(as_uuid(&v).is_err());
let v = ValueRef::Binary(&slice_v);
let pv = as_uuid(&v).unwrap();
assert_eq!(pv, tv);
let v = ValueRef::F32(0.0);
assert!(as_uuid(&v).is_err());
}
}