mirror of
https://github.com/bytedance/g3.git
synced 2026-05-05 07:10:51 +00:00
initial commit
This commit is contained in:
commit
13716f4923
1425 changed files with 163227 additions and 0 deletions
32
lib/g3-msgpack/src/key.rs
Normal file
32
lib/g3-msgpack/src/key.rs
Normal 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
18
lib/g3-msgpack/src/lib.rs
Normal 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;
|
||||
57
lib/g3-msgpack/src/value/datetime.rs
Normal file
57
lib/g3-msgpack/src/value/datetime.rs
Normal 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());
|
||||
}
|
||||
}
|
||||
29
lib/g3-msgpack/src/value/mod.rs
Normal file
29
lib/g3-msgpack/src/value/mod.rs
Normal 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};
|
||||
227
lib/g3-msgpack/src/value/primary.rs
Normal file
227
lib/g3-msgpack/src/value/primary.rs
Normal 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()));
|
||||
}
|
||||
}
|
||||
85
lib/g3-msgpack/src/value/rustls.rs
Normal file
85
lib/g3-msgpack/src/value/rustls.rs
Normal 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))
|
||||
}
|
||||
68
lib/g3-msgpack/src/value/uuid.rs
Normal file
68
lib/g3-msgpack/src/value/uuid.rs
Normal 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());
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue