Skip to content

Commit 293c87d

Browse files
authored
Event timing issue (#1198)
* test to see changes * got rid of logs * changed logs * cleaned up the code
1 parent c287cdb commit 293c87d

File tree

1 file changed

+97
-72
lines changed

1 file changed

+97
-72
lines changed

plugins/apple-calendar/src/sync.rs

Lines changed: 97 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,23 @@ pub async fn sync_events(
3131
let db_events_with_session = list_db_events_with_session(&db, &user_id).await?;
3232
let db_selected_calendars = list_db_calendars_selected(&db, &user_id).await?;
3333

34+
// Batch API call instead of individual calls
35+
let calendar_tracking_ids: Vec<String> = db_selected_calendars
36+
.iter()
37+
.map(|cal| cal.tracking_id.clone())
38+
.collect();
39+
40+
let system_events_per_tracking_id =
41+
list_system_events_for_calendars(calendar_tracking_ids).await;
42+
43+
// Convert from tracking_id -> database_id mapping
3444
let mut system_events_per_selected_calendar = std::collections::HashMap::new();
3545
for db_calendar in &db_selected_calendars {
36-
system_events_per_selected_calendar.insert(
37-
db_calendar.id.clone(),
38-
list_system_events(db_calendar.tracking_id.clone()).await,
39-
);
46+
let events = system_events_per_tracking_id
47+
.get(&db_calendar.tracking_id)
48+
.unwrap_or(&vec![])
49+
.clone();
50+
system_events_per_selected_calendar.insert(db_calendar.id.clone(), events);
4051
}
4152

4253
_sync_events(
@@ -81,7 +92,7 @@ async fn _sync_calendars(
8192
.find(|db_c| db_c.tracking_id == sys_c.id);
8293

8394
hypr_db_user::Calendar {
84-
id: uuid::Uuid::new_v4().to_string(),
95+
id: existing.map_or(uuid::Uuid::new_v4().to_string(), |c| c.id.clone()),
8596
tracking_id: sys_c.id.clone(),
8697
user_id: user_id.clone(),
8798
name: sys_c.name.clone(),
@@ -121,13 +132,10 @@ async fn _sync_events(
121132
.collect();
122133

123134
// Process existing events:
124-
// 1. Delete events from unselected calendars that have no sessions
125-
// 2. Handle rescheduled events (update instead of delete + create)
126-
// 3. Delete events that no longer exist in the system calendar
127135
for (db_event, session) in &db_events_with_session {
128136
let is_selected_cal = db_selected_calendars
129137
.iter()
130-
.any(|c| c.tracking_id == db_event.calendar_id.clone().unwrap_or_default());
138+
.any(|c| c.id == db_event.calendar_id.clone().unwrap_or_default());
131139

132140
if !is_selected_cal && session.as_ref().map_or(true, |s| s.is_empty()) {
133141
state.to_delete.push(db_event.clone());
@@ -138,38 +146,29 @@ async fn _sync_events(
138146
if let Some(events) = system_events_per_selected_calendar.get(calendar_id) {
139147
// Check if event exists with same tracking_id
140148
if let Some(matching_event) = events.iter().find(|e| e.id == db_event.tracking_id) {
141-
// Event exists with same tracking_id - it may have been updated
142149
let updated_event = hypr_db_user::Event {
143-
id: db_event.id.clone(), // Preserve the original database ID
150+
id: db_event.id.clone(),
144151
tracking_id: matching_event.id.clone(),
145152
user_id: user_id.clone(),
146153
calendar_id: Some(calendar_id.clone()),
147154
name: matching_event.name.clone(),
148155
note: matching_event.note.clone(),
149156
start_date: matching_event.start_date,
150157
end_date: matching_event.end_date,
151-
google_event_url: db_event.google_event_url.clone(), // Preserve any existing URL
158+
google_event_url: db_event.google_event_url.clone(),
152159
};
153160
state.to_update.push(updated_event);
154161
continue;
155162
}
156163

157-
// Check if this might be a rescheduled event (same name, calendar, but different tracking_id)
164+
// Check for rescheduled events
158165
if let Some(rescheduled_event) = find_potentially_rescheduled_event(
159166
&db_event,
160167
&all_system_events,
161168
&db_selected_calendars,
162169
) {
163-
tracing::info!(
164-
"Detected rescheduled event: {} -> {}, event: '{}'",
165-
db_event.tracking_id,
166-
rescheduled_event.id,
167-
db_event.name
168-
);
169-
170-
// Update the existing database event with new tracking_id and details
171170
let updated_event = hypr_db_user::Event {
172-
id: db_event.id.clone(), // Preserve the original database ID to keep user notes/sessions
171+
id: db_event.id.clone(),
173172
tracking_id: rescheduled_event.id.clone(),
174173
user_id: user_id.clone(),
175174
calendar_id: db_event.calendar_id.clone(),
@@ -183,54 +182,50 @@ async fn _sync_events(
183182
continue;
184183
}
185184

186-
// Event not found - mark for deletion
187-
tracing::info!(
188-
"Event not found in system calendar, marking for deletion: {} '{}'",
189-
db_event.tracking_id,
190-
db_event.name
191-
);
185+
state.to_delete.push(db_event.clone());
186+
} else {
192187
state.to_delete.push(db_event.clone());
193188
}
189+
} else {
190+
state.to_delete.push(db_event.clone());
194191
}
195192
}
196193

197194
// Add new events (that haven't been handled as updates)
198195
for db_calendar in db_selected_calendars {
199-
let fresh_events = system_events_per_selected_calendar
200-
.get(&db_calendar.id)
201-
.unwrap();
196+
if let Some(fresh_events) = system_events_per_selected_calendar.get(&db_calendar.id) {
197+
for system_event in fresh_events {
198+
// Skip if this event was already handled as an update
199+
let already_handled = state
200+
.to_update
201+
.iter()
202+
.any(|e| e.tracking_id == system_event.id);
203+
if already_handled {
204+
continue;
205+
}
202206

203-
for system_event in fresh_events {
204-
// Skip if this event was already handled as an update
205-
let already_handled = state
206-
.to_update
207-
.iter()
208-
.any(|e| e.tracking_id == system_event.id);
209-
if already_handled {
210-
continue;
211-
}
207+
// Skip if this event already exists in the database with the same tracking_id
208+
let already_exists = db_events_with_session
209+
.iter()
210+
.any(|(db_event, _)| db_event.tracking_id == system_event.id);
211+
if already_exists {
212+
continue;
213+
}
212214

213-
// Skip if this event already exists in the database with the same tracking_id
214-
let already_exists = db_events_with_session
215-
.iter()
216-
.any(|(db_event, _)| db_event.tracking_id == system_event.id);
217-
if already_exists {
218-
continue;
215+
// This is a genuinely new event
216+
let new_event = hypr_db_user::Event {
217+
id: uuid::Uuid::new_v4().to_string(),
218+
tracking_id: system_event.id.clone(),
219+
user_id: user_id.clone(),
220+
calendar_id: Some(db_calendar.id.clone()),
221+
name: system_event.name.clone(),
222+
note: system_event.note.clone(),
223+
start_date: system_event.start_date,
224+
end_date: system_event.end_date,
225+
google_event_url: None,
226+
};
227+
state.to_upsert.push(new_event);
219228
}
220-
221-
// This is a genuinely new event
222-
let new_event = hypr_db_user::Event {
223-
id: uuid::Uuid::new_v4().to_string(),
224-
tracking_id: system_event.id.clone(),
225-
user_id: user_id.clone(),
226-
calendar_id: Some(db_calendar.id.clone()),
227-
name: system_event.name.clone(),
228-
note: system_event.note.clone(),
229-
start_date: system_event.start_date,
230-
end_date: system_event.end_date,
231-
google_event_url: None,
232-
};
233-
state.to_upsert.push(new_event);
234229
}
235230
}
236231

@@ -279,25 +274,55 @@ async fn list_system_calendars() -> Vec<hypr_calendar_interface::Calendar> {
279274
.unwrap_or_default()
280275
}
281276

282-
async fn list_system_events(calendar_tracking_id: String) -> Vec<hypr_calendar_interface::Event> {
277+
async fn list_system_events_for_calendars(
278+
calendar_tracking_ids: Vec<String>,
279+
) -> std::collections::HashMap<String, Vec<hypr_calendar_interface::Event>> {
280+
let now = Utc::now();
281+
282+
for (i, id) in calendar_tracking_ids.iter().enumerate() {
283+
tracing::info!(" Calendar {}: tracking_id={}", i + 1, id);
284+
}
285+
283286
tauri::async_runtime::spawn_blocking(move || {
284287
let handle = hypr_calendar_apple::Handle::new();
285288

286-
let filter = EventFilter {
287-
calendar_tracking_id,
288-
from: Utc::now(),
289-
to: Utc::now() + chrono::Duration::days(28),
290-
};
289+
let mut results = std::collections::HashMap::new();
291290

292-
let rt = tokio::runtime::Builder::new_current_thread()
293-
.enable_all()
294-
.build()
295-
.unwrap();
291+
for (i, calendar_tracking_id) in calendar_tracking_ids.iter().enumerate() {
292+
let filter = EventFilter {
293+
calendar_tracking_id: calendar_tracking_id.clone(),
294+
from: now,
295+
to: now + chrono::Duration::days(28),
296+
};
296297

297-
rt.block_on(async { handle.list_events(filter).await.unwrap_or_default() })
298+
// Add small delay between API calls to avoid overwhelming EventKit
299+
if i > 0 {
300+
std::thread::sleep(std::time::Duration::from_millis(50));
301+
tracing::info!(" Applied 50ms delay after calendar {}", i);
302+
}
303+
304+
let events = match tokio::runtime::Handle::try_current() {
305+
Ok(rt) => {
306+
tracing::info!(" Using existing tokio runtime");
307+
rt.block_on(handle.list_events(filter)).unwrap_or_default()
308+
}
309+
Err(_) => {
310+
tracing::info!(" Creating new tokio runtime");
311+
let rt = tokio::runtime::Builder::new_current_thread()
312+
.enable_all()
313+
.build()
314+
.unwrap();
315+
rt.block_on(handle.list_events(filter)).unwrap_or_default()
316+
}
317+
};
318+
319+
results.insert(calendar_tracking_id.clone(), events);
320+
}
321+
322+
results
298323
})
299324
.await
300-
.unwrap_or_default()
325+
.unwrap_or_else(|e| std::collections::HashMap::new())
301326
}
302327

303328
async fn list_db_calendars(

0 commit comments

Comments
 (0)