more solid task updating, no need to stop the main loop to avoid race conditions
This commit is contained in:
@@ -4,11 +4,11 @@ import os
|
||||
import subprocess
|
||||
import time
|
||||
from pprint import pprint
|
||||
from zoneinfo import ZoneInfo
|
||||
|
||||
import state
|
||||
import task
|
||||
from config import logger, switches
|
||||
from zoneinfo import ZoneInfo
|
||||
|
||||
desktops = ("Plan", "Think", "Work", "Other", "Away", "Work", "Work", "Work")
|
||||
unlabeled = "Away"
|
||||
@@ -39,22 +39,18 @@ def now():
|
||||
return datetime.datetime.now(ZoneInfo(cfg["timezone"]))
|
||||
|
||||
|
||||
def handle_task_file_changes(current_task):
|
||||
"""Check if task file changed and update task if needed. Returns (new_task, file_changed)"""
|
||||
def handle_task_file_changes():
|
||||
"""Check if task file changed and sync definitions to DB. Does not change current task."""
|
||||
current_mtime = state.retrieve("current").get("filetime")
|
||||
file_mtime = task.get_file_mtime(None)
|
||||
|
||||
if current_mtime != file_mtime:
|
||||
task_id = task.read_and_extract(None)
|
||||
logger.debug(f"task_id:{task_id}")
|
||||
task.file_to_db(None)
|
||||
if task_id != current_task:
|
||||
state.save("current", task=task_id)
|
||||
current_task = task_id
|
||||
state.save("current", filetime=file_mtime)
|
||||
logger.info("Task file changed, definitions synced to DB")
|
||||
return True # File changed
|
||||
|
||||
return current_task, True # File changed
|
||||
|
||||
return current_task, False # No change
|
||||
return False # No change
|
||||
|
||||
|
||||
def update_workspace_state():
|
||||
@@ -65,14 +61,19 @@ def update_workspace_state():
|
||||
|
||||
|
||||
def enforce_desktop_task(current_workspace, work_desktop_tasks, current_task):
|
||||
"""Enforce assigned task for work desktops"""
|
||||
if current_workspace in work_desktop_tasks and work_desktop_tasks[current_workspace]:
|
||||
"""Enforce assigned task for work desktops. Updates MongoDB state only, never writes to file."""
|
||||
if (
|
||||
current_workspace in work_desktop_tasks
|
||||
and work_desktop_tasks[current_workspace]
|
||||
):
|
||||
assigned_task = work_desktop_tasks[current_workspace]
|
||||
|
||||
if current_task != assigned_task:
|
||||
current_task = assigned_task
|
||||
state.save("current", task=current_task)
|
||||
task.db_to_file_as_is(None)
|
||||
logger.debug(
|
||||
f"Enforced task {assigned_task} for workspace {current_workspace}"
|
||||
)
|
||||
|
||||
return current_task
|
||||
|
||||
@@ -121,8 +122,9 @@ def desktop(workspace_index):
|
||||
return unlabeled
|
||||
|
||||
|
||||
task.read_and_extract(None)
|
||||
# Sync task definitions from file to DB on startup
|
||||
task.file_to_db(None)
|
||||
state.save("current", filetime=task.get_file_mtime(None))
|
||||
|
||||
current_workspace = active_workspace()
|
||||
current_task = state.retrieve("current").get("task")
|
||||
@@ -144,18 +146,21 @@ while True:
|
||||
# Load work_desktop_tasks from state
|
||||
work_desktop_tasks = state.retrieve_desktop_state()
|
||||
|
||||
# Handle task file changes
|
||||
current_task, file_changed = handle_task_file_changes(current_task)
|
||||
# Sync task definitions if file changed (does not change current task)
|
||||
handle_task_file_changes()
|
||||
|
||||
# Update current task and workspace
|
||||
# Get current state
|
||||
current_task = state.retrieve("current").get("task")
|
||||
current_workspace = update_workspace_state()
|
||||
|
||||
# Enforce desktop task assignments (but skip if file just changed - user's manual change takes priority)
|
||||
if not file_changed:
|
||||
current_task = enforce_desktop_task(current_workspace, work_desktop_tasks, current_task)
|
||||
# Enforce work desktop task assignments
|
||||
current_task = enforce_desktop_task(
|
||||
current_workspace, work_desktop_tasks, current_task
|
||||
)
|
||||
|
||||
# Track workspace switches
|
||||
last_switch_time = track_workspace_switch(current_workspace, current_task, last_switch_time)
|
||||
last_switch_time = track_workspace_switch(
|
||||
current_workspace, current_task, last_switch_time
|
||||
)
|
||||
|
||||
time.sleep(2)
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
import datetime
|
||||
import re
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
|
||||
import state
|
||||
from bson import ObjectId
|
||||
from config import logger, tasks
|
||||
|
||||
@@ -59,7 +57,13 @@ def file_to_db(filepath: str):
|
||||
if task_id:
|
||||
tasks.update_one(
|
||||
{"task_id": task_id},
|
||||
{"$set": {"path": full_path, "task_id": task_id, "historic": False}},
|
||||
{
|
||||
"$set": {
|
||||
"path": full_path,
|
||||
"task_id": task_id,
|
||||
"historic": False,
|
||||
}
|
||||
},
|
||||
upsert=True,
|
||||
)
|
||||
elif full_path not in seen_paths:
|
||||
@@ -68,96 +72,10 @@ def file_to_db(filepath: str):
|
||||
seen_paths.add(full_path)
|
||||
|
||||
|
||||
def format_task_line(
|
||||
path_parts: list, indent_level: int, task_id: str, current_task: str
|
||||
) -> str:
|
||||
line = " " * (4 * indent_level) + path_parts[-1]
|
||||
if task_id:
|
||||
padding = max(1, 64 - len(line))
|
||||
line = f"{line}{' ' * padding}|{task_id}"
|
||||
if task_id == current_task:
|
||||
line += " *"
|
||||
return line
|
||||
|
||||
|
||||
def db_to_file_as_is(filepath: str):
|
||||
"""Write tasks from MongoDB to file exactly as they were read."""
|
||||
if filepath is None:
|
||||
filepath = task_file
|
||||
|
||||
current_task = state.retrieve("current").get("task")
|
||||
all_tasks = list(tasks.find())
|
||||
|
||||
with open(filepath, "w") as f:
|
||||
for task in all_tasks:
|
||||
if not task["path"]:
|
||||
f.write("\n")
|
||||
continue
|
||||
|
||||
path_parts = task["path"].split("/")
|
||||
line = format_task_line(
|
||||
path_parts, len(path_parts) - 1, task.get("task_id", ""), current_task
|
||||
)
|
||||
f.write(f"{line}\n")
|
||||
|
||||
|
||||
def get_all_tasks(prefix):
|
||||
return list(tasks.find({"path": {"$ne": ""}}).sort("path", 1))
|
||||
|
||||
|
||||
def db_to_file_consolidated(filepath: str):
|
||||
"""Write tasks from MongoDB to file as a consolidated tree."""
|
||||
current_task = state.retrieve("current").get("task")
|
||||
all_tasks = list(tasks.find({"path": {"$ne": ""}}).sort("path", 1))
|
||||
|
||||
with open(filepath, "w") as f:
|
||||
prev_parts = []
|
||||
for task in all_tasks:
|
||||
path_parts = task["path"].split("/")
|
||||
common = 0
|
||||
for i, (prev, curr) in enumerate(zip(prev_parts, path_parts)):
|
||||
if prev != curr:
|
||||
break
|
||||
common = i + 1
|
||||
|
||||
for i, part in enumerate(path_parts[common:], common):
|
||||
path_segment = path_parts[: i + 1]
|
||||
task_id = task.get("task_id", "") if path_segment == path_parts else ""
|
||||
line = format_task_line([part], i, task_id, current_task)
|
||||
f.write(f"{line}\n")
|
||||
|
||||
prev_parts = path_parts
|
||||
|
||||
|
||||
def extract(line: str) -> Optional[str]:
|
||||
"""Extract task ID if line ends with * and has a valid ID."""
|
||||
line = line.rstrip()
|
||||
if line.endswith("*"):
|
||||
pipe_index = line.find("|")
|
||||
if pipe_index != -1:
|
||||
# Extract everything between | and * and strip spaces
|
||||
id_part = line[pipe_index + 1 : -1].strip()
|
||||
if len(id_part) == 8:
|
||||
return id_part
|
||||
return None
|
||||
|
||||
|
||||
def read_and_extract(filepath: str) -> Optional[str]:
|
||||
"""Read file and update state if current task is found."""
|
||||
if filepath is None:
|
||||
filepath = task_file
|
||||
|
||||
mtime = get_file_mtime(filepath)
|
||||
state.save("current", filetime=mtime)
|
||||
|
||||
with open(filepath, "r") as file:
|
||||
for line in file:
|
||||
task_id = extract(line)
|
||||
if task_id:
|
||||
return task_id
|
||||
return None
|
||||
|
||||
|
||||
def get_file_mtime(filepath: str) -> str:
|
||||
"""Get file modification time as ISO format string."""
|
||||
if filepath is None:
|
||||
|
||||
Reference in New Issue
Block a user