use std::sync::atomic::{AtomicU64, AtomicU32,Ordering};
use chrono::Utc;
use std::net::UdpSocket;
pub struct SonyFlakeEntity{
time_stamp:AtomicU64,
counter:AtomicU32,
node_id:u16,
}
impl SonyFlakeEntity{
pub fn new(nodeid:u16)->Self{
SonyFlakeEntity{
time_stamp:AtomicU64::new(0),
counter:AtomicU32::new(0),
node_id:nodeid,
}
}
pub fn new_default()->Self{
let mut nodeid = 1;
if let Some(s)=get_ip(){
let ips:Vec<_> = s.split('.').collect();
let a = ips[2].parse::<u8>().unwrap();
let b = ips[3].parse::<u8>().unwrap();
nodeid = u16::from_be_bytes([a,b]);
}
SonyFlakeEntity{
time_stamp:AtomicU64::new(0),
counter:AtomicU32::new(0),
node_id:nodeid,
}
}
pub fn get_id(&self)->i64{
let (ts,sid) = self.get_ts_sid();
return Self::generate_id(ts,sid,self.node_id);
}
#[allow(unused_assignments)]
fn get_ts_sid(&self)->(u64,u32){
let mut timestamp = 0;
let mut sequence:u32 = 0;
let ntime = Utc::now().timestamp_millis() as u64;
let otime = self.time_stamp.load(Ordering::Acquire);
if ntime <= otime{
sequence = self.counter.fetch_add(1,Ordering::Relaxed);
timestamp = otime; }else{
self.counter.store(1,Ordering::Relaxed);
timestamp = ntime;
self.time_stamp.store(ntime,Ordering::Release);
}
return (timestamp,sequence);
}
fn generate_id(ts:u64,sid:u32,nid:u16)->i64{
let mut res:Vec<u8> = vec![0, 0, 0, 0, 0, 0, 0, 0];
let ts = ts << 22;
let vts = Vec::from(ts.to_be_bytes());
for i in 0..6{
res[i] = res[i] | vts[i];
}
res[0] = res[0]&0x7F;
let mut vnid = Vec::from(nid.to_be_bytes());
vnid[0] = vnid[0] & 0x03;
res[5] = res[5]|vnid[0];
res[6] = res[6]|vnid[1];
let mut vsid = Vec::from(sid.to_be_bytes());
vsid[2] = vsid[2]&0x0F;
res[6] = res[6]|vsid[2];
res[7] = res[7]|vsid[3];
i64::from_be_bytes([res[0],res[1],res[2],res[3],res[4],res[5],res[6],res[7]])
}
}
pub 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,
};
match socket.local_addr() {
Ok(addr) => return Some(addr.ip().to_string()),
Err(_) => return None,
};
}