use ms timestamps everywhere

This commit is contained in:
Nikita Galaiko 2023-02-20 12:41:01 +01:00
parent bd2c5b5809
commit 2e0f757cd9
No known key found for this signature in database
GPG Key ID: EBAB54E845BA519D
16 changed files with 72 additions and 64 deletions

View File

@ -20,7 +20,7 @@ tauri-plugin-window-state = { git = "https://github.com/tauri-apps/plugins-works
tauri-plugin-log = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "dev", features = ["colored"] } tauri-plugin-log = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "dev", features = ["colored"] }
log = "0.4.17" log = "0.4.17"
notify = "5.1.0" notify = "5.1.0"
serde_json = "1.0.92" serde_json = {version = "1.0.92", features = [ "std", "arbitrary_precision" ] }
uuid = "1.3.0" uuid = "1.3.0"
yrs = "0.16.1" yrs = "0.16.1"
difference = "2.0.0" difference = "2.0.0"

View File

@ -8,7 +8,7 @@ use std::{collections::HashMap, path::Path};
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct Delta { pub struct Delta {
pub operations: Vec<operations::Operation>, pub operations: Vec<operations::Operation>,
pub timestamp_ms: u64, pub timestamp_ms: u128,
} }
pub fn read(project: &projects::Project, file_path: &Path) -> Result<Option<Vec<Delta>>> { pub fn read(project: &projects::Project, file_path: &Path) -> Result<Option<Vec<Delta>>> {

View File

@ -68,7 +68,7 @@ impl TextDocument {
timestamp_ms: SystemTime::now() timestamp_ms: SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH) .duration_since(SystemTime::UNIX_EPOCH)
.unwrap() .unwrap()
.as_millis() as u64, .as_millis(),
}; };
if event.operations.len() == 0 { if event.operations.len() == 0 {
return false; return false;

View File

@ -6,7 +6,7 @@ use serde::Serialize;
pub struct Activity { pub struct Activity {
#[serde(rename = "type")] #[serde(rename = "type")]
pub activity_type: String, pub activity_type: String,
pub timestamp: u64, pub timestamp_ms: u128,
pub message: String, pub message: String,
} }
@ -14,13 +14,13 @@ pub fn parse_reflog_line(line: &str) -> Result<Activity> {
match line.split("\t").collect::<Vec<&str>>()[..] { match line.split("\t").collect::<Vec<&str>>()[..] {
[meta, message] => { [meta, message] => {
let meta_parts = meta.split_whitespace().collect::<Vec<&str>>(); let meta_parts = meta.split_whitespace().collect::<Vec<&str>>();
let timestamp = meta_parts[meta_parts.len() - 2].parse::<u64>()?; let timestamp_ms = meta_parts[meta_parts.len() - 2].parse::<u128>()?;
match message.split(": ").collect::<Vec<&str>>()[..] { match message.split(": ").collect::<Vec<&str>>()[..] {
[entry_type, msg] => Ok(Activity { [entry_type, msg] => Ok(Activity {
activity_type: entry_type.to_string(), activity_type: entry_type.to_string(),
message: msg.to_string(), message: msg.to_string(),
timestamp, timestamp_ms,
}), }),
_ => Err(anyhow!("failed to parse reflog line: {}", line)), _ => Err(anyhow!("failed to parse reflog line: {}", line)),
} }

View File

@ -5,39 +5,39 @@ fn test_parse_reflog_line() {
let test_cases = vec![ let test_cases = vec![
( (
"9ea641990993cb60c7d89c41606f6b457adb9681 3f2657e0d1eae57f58d7734aae10310a861de8e8 Nikita Galaiko <nikita@galaiko.rocks> 1676275740 +0100 commit: try sturdy mac dev certificate", "9ea641990993cb60c7d89c41606f6b457adb9681 3f2657e0d1eae57f58d7734aae10310a861de8e8 Nikita Galaiko <nikita@galaiko.rocks> 1676275740 +0100 commit: try sturdy mac dev certificate",
Activity{ activity_type: "commit".to_string(), timestamp: 1676275740, message: "try sturdy mac dev certificate".to_string() } Activity{ activity_type: "commit".to_string(), timestamp_ms: 1676275740000, message: "try sturdy mac dev certificate".to_string() }
), ),
( (
"999bc2f0194ea001f71ba65b5422a742b5e66d9f bb98b5411d597fdede63053c190260a38d459ecb Nikita Galaiko <nikita@galaiko.rocks> 1675428111 +0100 checkout: moving from production-build to master", "999bc2f0194ea001f71ba65b5422a742b5e66d9f bb98b5411d597fdede63053c190260a38d459ecb Nikita Galaiko <nikita@galaiko.rocks> 1675428111 +0100 checkout: moving from production-build to master",
Activity{ activity_type: "checkout".to_string(), timestamp: 1675428111, message: "moving from production-build to master".to_string() }, Activity{ activity_type: "checkout".to_string(), timestamp_ms: 1675428111000, message: "moving from production-build to master".to_string() },
), ),
( (
"0000000000000000000000000000000000000000 9aa96f488fbdb8f7b15151d9d2e47690d3b21b46 Nikita Galaiko <nikita@galaiko.rocks> 1675176957 +0100 commit (initial): simple tauri example", "0000000000000000000000000000000000000000 9aa96f488fbdb8f7b15151d9d2e47690d3b21b46 Nikita Galaiko <nikita@galaiko.rocks> 1675176957 +0100 commit (initial): simple tauri example",
Activity{ activity_type: "commit (initial)".to_string(), timestamp: 1675176957, message: "simple tauri example".to_string() }, Activity{ activity_type: "commit (initial)".to_string(), timestamp_ms: 1675176957000, message: "simple tauri example".to_string() },
), ),
( (
"d083bb9213fc5e0bb6d07c2c6c1eae5be483be25 dc870a80fddb843583baa36cb637c5c820b1e863 Nikita Galaiko <nikita@galaiko.rocks> 1675425613 +0100 commit (amend): build app with github actions", "d083bb9213fc5e0bb6d07c2c6c1eae5be483be25 dc870a80fddb843583baa36cb637c5c820b1e863 Nikita Galaiko <nikita@galaiko.rocks> 1675425613 +0100 commit (amend): build app with github actions",
Activity{ activity_type: "commit (amend)".to_string(), timestamp: 1675425613, message: "build app with github actions".to_string() }, Activity{ activity_type: "commit (amend)".to_string(), timestamp_ms: 1675425613000, message: "build app with github actions".to_string() },
), ),
( (
"2843be38a72ac8418c7e5c5630cba3c4803916d1 fbb7a9356484b948bde4c7ee9fdeb6439edff8c0 Nikita Galaiko <nikita@galaiko.rocks> 1676274883 +0100 pull: Fast-forward", "2843be38a72ac8418c7e5c5630cba3c4803916d1 fbb7a9356484b948bde4c7ee9fdeb6439edff8c0 Nikita Galaiko <nikita@galaiko.rocks> 1676274883 +0100 pull: Fast-forward",
Activity{ activity_type: "pull".to_string(), timestamp: 1676274883, message: "Fast-forward".to_string() }, Activity{ activity_type: "pull".to_string(), timestamp_ms: 1676274883000, message: "Fast-forward".to_string() },
), ),
( (
"3f2657e0d1eae57f58d7734aae10310a861de8e8 3f2657e0d1eae57f58d7734aae10310a861de8e8 Nikita Galaiko <nikita@galaiko.rocks> 1676277401 +0100 reset: moving to HEAD", "3f2657e0d1eae57f58d7734aae10310a861de8e8 3f2657e0d1eae57f58d7734aae10310a861de8e8 Nikita Galaiko <nikita@galaiko.rocks> 1676277401 +0100 reset: moving to HEAD",
Activity{ activity_type: "reset".to_string() , timestamp: 1676277401, message: "moving to HEAD".to_string() }, Activity{ activity_type: "reset".to_string() , timestamp_ms: 1676277401000, message: "moving to HEAD".to_string() },
), ),
( (
"9a831ba2fa07aa6a399bbb498e8effd913cec2e0 add94e65594e4c240b0f6b03973a3be3ff594306 Nikita Galaiko <nikita@galaiko.rocks> 1676039997 +0100 pull --rebase (start): checkout add94e65594e4c240b0f6b03973a3be3ff594306", "9a831ba2fa07aa6a399bbb498e8effd913cec2e0 add94e65594e4c240b0f6b03973a3be3ff594306 Nikita Galaiko <nikita@galaiko.rocks> 1676039997 +0100 pull --rebase (start): checkout add94e65594e4c240b0f6b03973a3be3ff594306",
Activity{ activity_type: "pull --rebase (start)".to_string(), timestamp: 1676039997, message: "checkout add94e65594e4c240b0f6b03973a3be3ff594306".to_string() }, Activity{ activity_type: "pull --rebase (start)".to_string(), timestamp_ms: 1676039997000, message: "checkout add94e65594e4c240b0f6b03973a3be3ff594306".to_string() },
), ),
( (
"add94e65594e4c240b0f6b03973a3be3ff594306 bcc93167c068649868aa3df4999ba154468a62b5 Nikita Galaiko <nikita@galaiko.rocks> 1676039997 +0100 pull --rebase (pick): make app run in background", "add94e65594e4c240b0f6b03973a3be3ff594306 bcc93167c068649868aa3df4999ba154468a62b5 Nikita Galaiko <nikita@galaiko.rocks> 1676039997 +0100 pull --rebase (pick): make app run in background",
Activity{ activity_type: "pull --rebase (pick)".to_string(), timestamp: 1676039997, message: "make app run in background".to_string() }, Activity{ activity_type: "pull --rebase (pick)".to_string(), timestamp_ms: 1676039997000, message: "make app run in background".to_string() },
), ),
( (
"bcc93167c068649868aa3df4999ba154468a62b5 bcc93167c068649868aa3df4999ba154468a62b5 Nikita Galaiko <nikita@galaiko.rocks> 1676039997 +0100 pull --rebase (finish): returning to refs/heads/master", "bcc93167c068649868aa3df4999ba154468a62b5 bcc93167c068649868aa3df4999ba154468a62b5 Nikita Galaiko <nikita@galaiko.rocks> 1676039997 +0100 pull --rebase (finish): returning to refs/heads/master",
Activity{ activity_type: "pull --rebase (finish)".to_string(), timestamp: 1676039997, message: "returning to refs/heads/master".to_string() }, Activity{ activity_type: "pull --rebase (finish)".to_string(), timestamp_ms: 1676039997000, message: "returning to refs/heads/master".to_string() },
) )
]; ];

View File

@ -18,9 +18,9 @@ use uuid::Uuid;
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct Meta { pub struct Meta {
// timestamp of when the session was created // timestamp of when the session was created
pub start_ts: u64, pub start_timestamp_ms: u128,
// timestamp of when the session was last active // timestamp of when the session was last active
pub last_ts: u64, pub last_timestamp_ms: u128,
// session branch name // session branch name
pub branch: String, pub branch: String,
// session commit hash // session commit hash
@ -47,7 +47,7 @@ impl Session {
let start_path = meta_path.join("start"); let start_path = meta_path.join("start");
let start_ts = std::fs::read_to_string(start_path.clone())? let start_ts = std::fs::read_to_string(start_path.clone())?
.parse::<u64>() .parse::<u128>()
.with_context(|| { .with_context(|| {
format!( format!(
"failed to parse start timestamp from {}", "failed to parse start timestamp from {}",
@ -57,7 +57,7 @@ impl Session {
let last_path = meta_path.join("last"); let last_path = meta_path.join("last");
let last_ts = std::fs::read_to_string(last_path.clone())? let last_ts = std::fs::read_to_string(last_path.clone())?
.parse::<u64>() .parse::<u128>()
.with_context(|| { .with_context(|| {
format!( format!(
"failed to parse last timestamp from {}", "failed to parse last timestamp from {}",
@ -84,7 +84,7 @@ impl Session {
let activity = reflog let activity = reflog
.lines() .lines()
.filter_map(|line| activity::parse_reflog_line(line).ok()) .filter_map(|line| activity::parse_reflog_line(line).ok())
.filter(|activity| activity.timestamp >= start_ts) .filter(|activity| activity.timestamp_ms >= start_ts)
.collect::<Vec<activity::Activity>>(); .collect::<Vec<activity::Activity>>();
let id_path = meta_path.join("id"); let id_path = meta_path.join("id");
@ -96,8 +96,8 @@ impl Session {
hash: None, hash: None,
activity, activity,
meta: Meta { meta: Meta {
start_ts, start_timestamp_ms: start_ts,
last_ts, last_timestamp_ms: last_ts,
branch, branch,
commit, commit,
}, },
@ -108,15 +108,15 @@ impl Session {
let now_ts = SystemTime::now() let now_ts = SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH) .duration_since(SystemTime::UNIX_EPOCH)
.unwrap() .unwrap()
.as_secs(); .as_millis();
let head = repo.head()?; let head = repo.head()?;
let session = Session { let session = Session {
id: Uuid::new_v4().to_string(), id: Uuid::new_v4().to_string(),
hash: None, hash: None,
meta: Meta { meta: Meta {
start_ts: now_ts, start_timestamp_ms: now_ts,
last_ts: now_ts, last_timestamp_ms: now_ts,
branch: head.name().unwrap().to_string(), branch: head.name().unwrap().to_string(),
commit: head.peel_to_commit().unwrap().id().to_string(), commit: head.peel_to_commit().unwrap().id().to_string(),
}, },
@ -131,8 +131,8 @@ impl Session {
format!("failed to get tree from commit {}", commit.id().to_string()) format!("failed to get tree from commit {}", commit.id().to_string())
})?; })?;
let start_ts = read_as_string(repo, &tree, Path::new("session/meta/start"))? let start_timestamp_ms = read_as_string(repo, &tree, Path::new("session/meta/start"))?
.parse::<u64>() .parse::<u128>()
.with_context(|| { .with_context(|| {
format!( format!(
"failed to parse start timestamp from commit {}", "failed to parse start timestamp from commit {}",
@ -149,7 +149,7 @@ impl Session {
let activity = reflog let activity = reflog
.lines() .lines()
.filter_map(|line| activity::parse_reflog_line(line).ok()) .filter_map(|line| activity::parse_reflog_line(line).ok())
.filter(|activity| activity.timestamp >= start_ts) .filter(|activity| activity.timestamp_ms >= start_timestamp_ms)
.collect::<Vec<activity::Activity>>(); .collect::<Vec<activity::Activity>>();
Ok(Session { Ok(Session {
@ -161,9 +161,9 @@ impl Session {
})?, })?,
hash: Some(commit.id().to_string()), hash: Some(commit.id().to_string()),
meta: Meta { meta: Meta {
start_ts, start_timestamp_ms,
last_ts: read_as_string(repo, &tree, Path::new("session/meta/last"))? last_timestamp_ms: read_as_string(repo, &tree, Path::new("session/meta/last"))?
.parse::<u64>() .parse::<u128>()
.with_context(|| { .with_context(|| {
format!( format!(
"failed to parse last timestamp from commit {}", "failed to parse last timestamp from commit {}",
@ -222,7 +222,11 @@ fn write(session_path: &Path, session: &Session) -> Result<()> {
.with_context(|| format!("failed to write session id to {}", id_path.display()))?; .with_context(|| format!("failed to write session id to {}", id_path.display()))?;
let start_path = meta_path.join("start"); let start_path = meta_path.join("start");
std::fs::write(start_path.clone(), session.meta.start_ts.to_string()).with_context(|| { std::fs::write(
start_path.clone(),
session.meta.start_timestamp_ms.to_string(),
)
.with_context(|| {
format!( format!(
"failed to write session start timestamp to {}", "failed to write session start timestamp to {}",
start_path.display() start_path.display()
@ -230,7 +234,11 @@ fn write(session_path: &Path, session: &Session) -> Result<()> {
})?; })?;
let last_path = meta_path.join("last"); let last_path = meta_path.join("last");
std::fs::write(last_path.clone(), session.meta.last_ts.to_string()).with_context(|| { std::fs::write(
last_path.clone(),
session.meta.last_timestamp_ms.to_string(),
)
.with_context(|| {
format!( format!(
"failed to write session last timestamp to {}", "failed to write session last timestamp to {}",
last_path.display() last_path.display()

View File

@ -237,8 +237,8 @@ fn write_beginning_meta_files<R: tauri::Runtime>(
let now_ts = SystemTime::now() let now_ts = SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH) .duration_since(SystemTime::UNIX_EPOCH)
.unwrap() .unwrap()
.as_secs(); .as_millis();
session.meta.last_ts = now_ts; session.meta.last_timestamp_ms = now_ts;
session session
.update(project) .update(project)
.with_context(|| "failed to update session")?; .with_context(|| "failed to update session")?;

View File

@ -6,8 +6,8 @@ use std::{
time::{Duration, SystemTime}, time::{Duration, SystemTime},
}; };
const FIVE_MINUTES: u64 = Duration::new(5 * 60, 0).as_secs(); const FIVE_MINUTES: u128 = Duration::new(5 * 60, 0).as_millis();
const ONE_HOUR: u64 = Duration::new(60 * 60, 0).as_secs(); const ONE_HOUR: u128 = Duration::new(60 * 60, 0).as_millis();
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct GitWatcher { pub struct GitWatcher {
@ -124,10 +124,10 @@ fn session_to_commit(
let now = SystemTime::now() let now = SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH) .duration_since(SystemTime::UNIX_EPOCH)
.unwrap() .unwrap()
.as_secs() as u64; .as_millis();
let elapsed_last = now - current_session.meta.last_ts; let elapsed_last = now - current_session.meta.last_timestamp_ms;
let elapsed_start = now - current_session.meta.start_ts; let elapsed_start = now - current_session.meta.start_timestamp_ms;
// TODO: uncomment // TODO: uncomment
if (elapsed_last > FIVE_MINUTES) || (elapsed_start > ONE_HOUR) { if (elapsed_last > FIVE_MINUTES) || (elapsed_start > ONE_HOUR) {

View File

@ -35,8 +35,8 @@
class="hover:text-zinc-200" class="hover:text-zinc-200"
href="/projects/{$project.id}/sessions/{$session.id}" href="/projects/{$project.id}/sessions/{$session.id}"
> >
{toHumanReadableTime($session.meta.startTs)} {toHumanReadableTime($session.meta.startTimestampMs)}
{toHumanReadableTime($session.meta.lastTs)} {toHumanReadableTime($session.meta.lastTimestampMs)}
</a> </a>
{/if} {/if}
</div> </div>

View File

@ -19,14 +19,14 @@
</div> </div>
<div class="mt-1 text-xs"> <div class="mt-1 text-xs">
<span> <span>
{#if session.meta.startTs} {#if session.meta.startTimestampMs}
{toHumanReadableTime(session.meta.startTs)} {toHumanReadableTime(session.meta.startTimestampMs)}
{/if} {/if}
</span> </span>
<span></span> <span></span>
<span> <span>
{#if session.meta.lastTs} {#if session.meta.lastTimestampMs}
{toHumanReadableTime(session.meta.lastTs)} {toHumanReadableTime(session.meta.lastTimestampMs)}
{/if} {/if}
</span> </span>
</div> </div>

View File

@ -63,16 +63,16 @@
<div class="my-2 mx-1"> <div class="my-2 mx-1">
<TimelineDaySessionActivities <TimelineDaySessionActivities
activities={session.activity} activities={session.activity}
sessionStart={session.meta.startTs} sessionStart={session.meta.startTimestampMs}
sessionEnd={session.meta.lastTs} sessionEnd={session.meta.lastTimestampMs}
/> />
</div> </div>
</div> </div>
<div id="time-range" class="text-xs"> <div id="time-range" class="text-xs">
{toHumanReadableDate(session.meta.startTs)}, {toHumanReadableDate(session.meta.startTimestampMs)},
{toHumanReadableTime(session.meta.startTs)} {toHumanReadableTime(session.meta.startTimestampMs)}
<div class="text-xs text-zinc-600"> <div class="text-xs text-zinc-600">
{Math.round((session.meta.lastTs - session.meta.startTs) / 60)} min {Math.round((session.meta.lastTimestampMs - session.meta.startTimestampMs) / 60)} min
</div> </div>
</div> </div>
<div id="files"> <div id="files">

View File

@ -29,14 +29,14 @@
<div <div
class="flex -mx-1.5" class="flex -mx-1.5"
style="position:relative; left: {proportionOfTime( style="position:relative; left: {proportionOfTime(
activity.timestamp activity.timestampMs
)}%;" )}%;"
> >
<div <div
class="w-3 h-3 text-slate-700 z-50 absolute inset-0" class="w-3 h-3 text-slate-700 z-50 absolute inset-0"
style="" style=""
title="{activity.type}: {activity.message} at {toHumanReadableTime( title="{activity.type}: {activity.message} at {toHumanReadableTime(
activity.timestamp activity.timestampMs
)}" )}"
> >
{#if activity.type === "commit"} {#if activity.type === "commit"}

View File

@ -4,7 +4,7 @@ import { writable } from "svelte/store";
export type Activity = { export type Activity = {
type: string; type: string;
timestamp: number; timestampMs: number;
message: string; message: string;
}; };
@ -12,8 +12,8 @@ export type Session = {
id: string; id: string;
hash?: string; hash?: string;
meta: { meta: {
startTs: number; startTimestampMs: number;
lastTs: number; lastTimestampMs: number;
branch: string; branch: string;
commit: string; commit: string;
}; };

View File

@ -8,7 +8,7 @@
const sessionDisplayWidth = (session: Session) => { const sessionDisplayWidth = (session: Session) => {
let sessionDurationMinutes = let sessionDurationMinutes =
(session.meta.lastTs - session.meta.startTs) / 60; (session.meta.lastTimestampMs - session.meta.startTimestampMs) / 60;
if (sessionDurationMinutes <= 10) { if (sessionDurationMinutes <= 10) {
return "w-40 min-w-40"; return "w-40 min-w-40";
} else { } else {

View File

@ -22,7 +22,7 @@
const sessionDisplayWidth = (session: Session) => { const sessionDisplayWidth = (session: Session) => {
let sessionDurationMinutes = let sessionDurationMinutes =
(session.meta.lastTs - session.meta.startTs) / 60; (session.meta.lastTimestampMs - session.meta.startTimestampMs) / 60;
if (sessionDurationMinutes <= 10) { if (sessionDurationMinutes <= 10) {
return "w-40 min-w-40"; return "w-40 min-w-40";
} else { } else {
@ -39,8 +39,8 @@
const end = new Date(start.getTime() + 24 * 60 * 60 * 1000); const end = new Date(start.getTime() + 24 * 60 * 60 * 1000);
return sessions.filter((session) => { return sessions.filter((session) => {
return ( return (
start <= new Date(session.meta.startTs * 1000) && start <= new Date(session.meta.startTimestampMs * 1000) &&
new Date(session.meta.startTs * 1000) <= end new Date(session.meta.startTimestampMs * 1000) <= end
); );
}); });
}); });

View File

@ -23,8 +23,8 @@
$: sessionsInWeek = derived([sessions], ([sessions]) => { $: sessionsInWeek = derived([sessions], ([sessions]) => {
return sessions.filter((session) => { return sessions.filter((session) => {
return ( return (
week.start <= new Date(session.meta.startTs * 1000) && week.start <= new Date(session.meta.startTimestampMs * 1000) &&
new Date(session.meta.startTs * 1000) <= week.end new Date(session.meta.startTimestampMs * 1000) <= week.end
); );
}); });
}); });
@ -256,8 +256,8 @@
> >
{#each $sessionsInWeek as session} {#each $sessionsInWeek as session}
<WeekBlockEntry <WeekBlockEntry
startTime={new Date(session.meta.startTs * 1000)} startTime={new Date(session.meta.startTimestampMs * 1000)}
endTime={new Date(session.meta.startTs * 1000)} endTime={new Date(session.meta.startTimestampMs * 1000)}
label={session.meta.branch} label={session.meta.branch}
href="/projects/{$project?.id}/sessions/{session.id}/" href="/projects/{$project?.id}/sessions/{session.id}/"
/> />