Fix failing constraint
This commit is contained in:
@@ -55,9 +55,10 @@ impl Database {
|
||||
);
|
||||
|
||||
-- Main table with normalized foreign keys and integer timestamp
|
||||
-- timestamp_ms stores milliseconds since epoch for uniqueness
|
||||
CREATE TABLE IF NOT EXISTS signature_entries (
|
||||
session_id TEXT NOT NULL,
|
||||
timestamp INTEGER NOT NULL,
|
||||
timestamp_ms INTEGER NOT NULL,
|
||||
app_id INTEGER NOT NULL REFERENCES apps(id),
|
||||
version_id INTEGER NOT NULL REFERENCES versions(id),
|
||||
offline_login_usage INTEGER,
|
||||
@@ -70,7 +71,7 @@ impl Database {
|
||||
model_id INTEGER REFERENCES models(id),
|
||||
device_id INTEGER REFERENCES devices(id),
|
||||
password_autofill_usage INTEGER,
|
||||
PRIMARY KEY (session_id, timestamp)
|
||||
PRIMARY KEY (session_id, timestamp_ms)
|
||||
) WITHOUT ROWID;
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_session_id ON signature_entries(session_id);
|
||||
@@ -96,7 +97,7 @@ impl Database {
|
||||
let mut insert_stmt = tx.prepare_cached(
|
||||
r#"
|
||||
INSERT INTO signature_entries (
|
||||
session_id, timestamp, app_id, version_id,
|
||||
session_id, timestamp_ms, app_id, version_id,
|
||||
offline_login_usage, is_password_autofill_enabled, camera_roll_usage,
|
||||
os_id, app_name_id, touch_id, is_offline_login_enabled,
|
||||
model_id, device_id, password_autofill_usage
|
||||
@@ -114,7 +115,7 @@ impl Database {
|
||||
|
||||
insert_stmt.execute(params![
|
||||
entry.session_id,
|
||||
entry.timestamp.and_utc().timestamp(),
|
||||
entry.timestamp_ms,
|
||||
app_id,
|
||||
version_id,
|
||||
entry.offline_login_usage,
|
||||
|
||||
@@ -7,7 +7,8 @@ use std::sync::LazyLock;
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct SignatureEntry {
|
||||
pub session_id: String,
|
||||
pub timestamp: NaiveDateTime,
|
||||
/// Timestamp as milliseconds since Unix epoch (UTC)
|
||||
pub timestamp_ms: i64,
|
||||
pub app: String,
|
||||
pub version: String,
|
||||
pub offline_login_usage: Option<i64>,
|
||||
@@ -39,7 +40,7 @@ pub enum ParsedMessage {
|
||||
static SESSION_ID_RE: LazyLock<Regex> =
|
||||
LazyLock::new(|| Regex::new(r"sessionId=([^,\s]+)").unwrap());
|
||||
static DATETIME_RE: LazyLock<Regex> =
|
||||
LazyLock::new(|| Regex::new(r#"dt="(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})"#).unwrap());
|
||||
LazyLock::new(|| Regex::new(r#"dt="(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})(?:,(\d{3}))?"#).unwrap());
|
||||
static CORRELATION_ID_RE: LazyLock<Regex> =
|
||||
LazyLock::new(|| Regex::new(r"correlationId=([^,\s]+)").unwrap());
|
||||
static SIGNATURE_RE: LazyLock<Regex> =
|
||||
@@ -84,15 +85,8 @@ impl SignatureParser {
|
||||
.map(|m| m.as_str().to_string())
|
||||
.ok_or_else(|| anyhow!("Missing sessionId"))?;
|
||||
|
||||
// Extract timestamp
|
||||
let datetime_str = DATETIME_RE
|
||||
.captures(line)
|
||||
.and_then(|c| c.get(1))
|
||||
.map(|m| m.as_str())
|
||||
.ok_or_else(|| anyhow!("Missing datetime"))?;
|
||||
|
||||
let timestamp = NaiveDateTime::parse_from_str(datetime_str, "%Y-%m-%d %H:%M:%S")
|
||||
.map_err(|e| anyhow!("Invalid datetime format: {}", e))?;
|
||||
// Extract timestamp as milliseconds
|
||||
let timestamp_ms = extract_timestamp_ms(line)?;
|
||||
|
||||
// Extract signature details
|
||||
let caps = SIGNATURE_RE
|
||||
@@ -109,7 +103,7 @@ impl SignatureParser {
|
||||
|
||||
let entry = SignatureEntry {
|
||||
session_id,
|
||||
timestamp,
|
||||
timestamp_ms,
|
||||
app,
|
||||
version,
|
||||
offline_login_usage: parse_number(&details, "offlineLoginUsage"),
|
||||
@@ -143,7 +137,7 @@ impl MessageParser for MobileClientIosParser {
|
||||
|
||||
impl MobileClientIosParser {
|
||||
fn parse_mobile_ios_line(&self, line: &str) -> Result<ParsedMessage> {
|
||||
let timestamp = extract_timestamp(line)?;
|
||||
let timestamp_ms = extract_timestamp_ms(line)?;
|
||||
let session_id = extract_correlation_id(line)?;
|
||||
|
||||
let caps = MOBILE_IOS_RE
|
||||
@@ -158,7 +152,7 @@ impl MobileClientIosParser {
|
||||
|
||||
let entry = SignatureEntry {
|
||||
session_id,
|
||||
timestamp,
|
||||
timestamp_ms,
|
||||
app,
|
||||
version,
|
||||
offline_login_usage: None,
|
||||
@@ -192,7 +186,7 @@ impl MessageParser for MobileClientAndroidParser {
|
||||
|
||||
impl MobileClientAndroidParser {
|
||||
fn parse_mobile_android_line(&self, line: &str) -> Result<ParsedMessage> {
|
||||
let timestamp = extract_timestamp(line)?;
|
||||
let timestamp_ms = extract_timestamp_ms(line)?;
|
||||
let session_id = extract_correlation_id(line)?;
|
||||
|
||||
let caps = MOBILE_ANDROID_RE
|
||||
@@ -207,7 +201,7 @@ impl MobileClientAndroidParser {
|
||||
|
||||
let entry = SignatureEntry {
|
||||
session_id,
|
||||
timestamp,
|
||||
timestamp_ms,
|
||||
app,
|
||||
version,
|
||||
offline_login_usage: None,
|
||||
@@ -226,16 +220,22 @@ impl MobileClientAndroidParser {
|
||||
}
|
||||
}
|
||||
|
||||
/// Extract timestamp from log line
|
||||
fn extract_timestamp(line: &str) -> Result<NaiveDateTime> {
|
||||
let datetime_str = DATETIME_RE
|
||||
/// Extract timestamp from log line as milliseconds since Unix epoch
|
||||
fn extract_timestamp_ms(line: &str) -> Result<i64> {
|
||||
let caps = DATETIME_RE
|
||||
.captures(line)
|
||||
.and_then(|c| c.get(1))
|
||||
.map(|m| m.as_str())
|
||||
.ok_or_else(|| anyhow!("Missing datetime"))?;
|
||||
|
||||
NaiveDateTime::parse_from_str(datetime_str, "%Y-%m-%d %H:%M:%S")
|
||||
.map_err(|e| anyhow!("Invalid datetime format: {}", e))
|
||||
let datetime_str = caps.get(1).map(|m| m.as_str()).unwrap();
|
||||
let millis: i64 = caps
|
||||
.get(2)
|
||||
.map(|m| m.as_str().parse().unwrap_or(0))
|
||||
.unwrap_or(0);
|
||||
|
||||
let dt = NaiveDateTime::parse_from_str(datetime_str, "%Y-%m-%d %H:%M:%S")
|
||||
.map_err(|e| anyhow!("Invalid datetime format: {}", e))?;
|
||||
|
||||
Ok(dt.and_utc().timestamp_millis() + millis)
|
||||
}
|
||||
|
||||
/// Extract correlation ID as session ID for mobile client logs
|
||||
|
||||
Reference in New Issue
Block a user