use std::{thread, time};
use std::net::UdpSocket;
use chrono::Utc;
#[derive(Clone)]
pub struct Snowflake {
epoch: i64,
worker_id: i64,
sequence: i64,
time: i64,
sequence_mask: i64
}
impl Snowflake {
pub fn kubernetes() -> Snowflake {
let ip = get_ip().unwrap();
let ip_split: Vec<&str> = ip.split(".").collect();
let ip_low = ip_split[2].to_string().parse::<i64>().unwrap() << 8 | ip_split[3].to_string().parse::<i64>().unwrap();
Snowflake {
epoch: 1575129600000,
worker_id: ip_low,
sequence: 0,
time: 0,
sequence_mask: -1 ^ -1 << 12,
}
}
pub fn new(worker_id: i64) -> Snowflake {
Snowflake {
epoch: 1575129600000,
worker_id,
sequence: 0,
time: 0,
sequence_mask: -1 ^ (-1 << 12),
}
}
pub fn generate(&mut self) -> Option<i64> {
let mut timestamp = self.get_time();
if timestamp < self.time {
if self.time - timestamp > 150 {
return None
} else {
thread::sleep(time::Duration::from_millis((self.time - timestamp + 1) as u64));
timestamp = self.get_time();
}
} else if timestamp == self.get_time() {
self.sequence = (self.sequence + 1) & self.sequence_mask
} else {
self.sequence = 0
}
self.time = timestamp;
Option::from((timestamp << 28) | (self.worker_id << 12) | self.sequence)
}
fn get_time(&self) -> i64 {
Utc::now().timestamp_millis() - self.epoch
}
}
fn get_ip() -> Option<String> {
let socket = match UdpSocket::bind("0.0.0.0:0") {
Ok(s) => s,
Err(_) => return None,
};
match socket.connect("8.8.8.8:80") {
Ok(()) => (),
Err(_) => return None,
};
return match socket.local_addr() {
Ok(addr) => Some(addr.ip().to_string()),
Err(_) => None,
};
}