feat(serial):基本完成冰雹ID生成器设计,基本完成全部计划中功能设计。

This commit is contained in:
徐涛 2023-07-03 22:33:15 +08:00
parent 3f3191fcea
commit e6447fdd43
4 changed files with 125 additions and 1 deletions

View File

@ -21,6 +21,7 @@ hmac-sha256 = "1.1.7"
hmac-sha512 = "1.1.5"
image = "0.24.6"
md-5 = "0.10.5"
once_cell = "1.18.0"
rand = "0.8.5"
rsa = { version = "0.9.2", features = ["sha2"] }
sha1 = "0.10.5"

View File

@ -26,7 +26,7 @@ Rust 中可以使用的常用辅助功能工具箱。主要配备以下功能:
- [x] MD5 散列算法
- [x] 图像感知散列算法
- 唯一序列号生成器
- [ ] 冰雹 ID 生成器(短主机精简日期版雪花 ID)
- [x] 冰雹 ID 生成器(短主机精简日期版雪花 ID)
- [x] UUID 生成器
- [x] short UUID 生成器
- 签名算法

121
src/serial_code/hail.rs Normal file
View File

@ -0,0 +1,121 @@
use core::time;
use std::sync::{Arc, Mutex};
use chrono::NaiveDateTime;
use once_cell::sync::{Lazy, OnceCell};
use thiserror::Error;
const HAIL_PERIOD_START: Lazy<i64> = Lazy::new(|| {
crate::time::date(2022, 2, 22)
.map(|d| d.and_hms_opt(22, 22, 22))
.flatten()
.map(|dt| crate::time::attach_asia_shanghai(dt))
.map(|dt| dt.timestamp())
.unwrap_or_else(|| NaiveDateTime::MIN.timestamp())
});
type TimestampValidator = fn(i64) -> bool;
type TimestampGenerator = fn() -> i64;
static INSTANCE: OnceCell<HailSerialCodeAlgorithm> = OnceCell::new();
#[derive(Debug, Error)]
pub enum HailSerialCodeAlgorithmError {
#[error("Algorithm is already initialized")]
AlgorithmAlreadyInitialized,
}
/// 冰雹序列ID算法。
/// 缩减了时间戳的位数相比雪花算法可以额外支持近40年。
pub struct HailSerialCodeAlgorithm {
validator: Option<TimestampValidator>,
generator: Option<TimestampGenerator>,
host_id: i64,
last_timestamp: Arc<Mutex<i64>>,
counter: Arc<Mutex<i64>>,
}
impl HailSerialCodeAlgorithm {
/// 获取一个算法实例用于获取序列ID。
pub fn get() -> &'static Self {
INSTANCE.get().unwrap()
}
/// 初始化整个序列ID算法。
/// ! 注意如果选择使用内置的主机独立时间戳生成器和验证器那么将不能保证多主机状态下的序列ID一致性。可能会存在个别主机时间回拨现象。
///
/// - `host_id`主机ID取值范围为0~65535。
/// - `timestamp_generator`:时间戳生成器,用于生成时间戳。如果不提供,则使用算法内置的主机独立时间戳生成器。
/// - `timestamp_validatoe`:时间戳验证器,用于验证时间戳是否有效。如果不提供,则使用算法内置的主机独立时间戳验证器。
pub fn initialize_algorithm(
host_id: i64,
timestamp_generator: Option<TimestampGenerator>,
timestamp_validatoe: Option<TimestampValidator>,
) -> Result<(), HailSerialCodeAlgorithmError> {
let algorithm = HailSerialCodeAlgorithm {
validator: timestamp_validatoe,
generator: timestamp_generator,
host_id,
last_timestamp: Arc::new(Mutex::new(0)),
counter: Arc::new(Mutex::new(0)),
};
INSTANCE
.set(algorithm)
.map_err(|_| HailSerialCodeAlgorithmError::AlgorithmAlreadyInitialized)
}
/// 生成一个自计时起点以来的时间戳。
fn generate_timestamp(&self) -> i64 {
let current_time = crate::time::now_asia_shanghai().timestamp();
current_time - *HAIL_PERIOD_START
}
/// 判断指定时间戳是否比已经存储的最后一次使用的时间戳要大。否则时间发生了回拨。
fn validate_timestamp(&self, timestamp: i64) -> bool {
let last_timestamp = self.last_timestamp.clone();
let last_timestamp = last_timestamp.lock().unwrap();
timestamp >= *last_timestamp
}
/// 生成一个64位长整型序列ID。
pub fn generate_serial(&self) -> i64 {
let last_timestamp = self.last_timestamp.clone();
let mut last_timestamp = last_timestamp.lock().unwrap();
let counter = self.counter.clone();
let mut counter = counter.lock().unwrap();
loop {
let timestamp = if let Some(generator) = self.generator {
generator()
} else {
self.generate_timestamp()
};
if let Some(validator) = self.validator {
if !validator(timestamp) {
std::thread::sleep(time::Duration::from_secs(1));
continue;
}
} else if !self.validate_timestamp(timestamp) {
std::thread::sleep(time::Duration::from_secs(1));
continue;
}
if *last_timestamp < timestamp {
// 对齐时间戳并重置序列计数器
*last_timestamp = timestamp;
*counter = 0;
}
*counter += 1;
return (timestamp << 20) | ((self.host_id & 0xFFFF) << 16) | (*counter & 0xFFFF_FFFF);
}
}
/// 生成一个17位长前补零的序列ID字符串。
pub fn generate_string_serial(&self) -> String {
let serial = self.generate_serial();
format!("{:017}", serial)
}
/// 生成一个带字符串前缀17位长前补零的序列ID字符串。
pub fn generate_prefixed_string_serial(&self, prefix: &str) -> String {
let serial = self.generate_serial();
format!("{}{:017}", prefix, serial)
}
}

View File

@ -1,3 +1,5 @@
pub mod hail;
pub mod uuid {
pub fn new() -> Box<String> {
Box::from(uuid::Uuid::new_v4().to_string())