Files
herolib/lib/vfs/vfs_calendar/vfs_implementation.v
2025-10-12 12:30:19 +03:00

600 lines
16 KiB
V

module vfs_calendar
import json
import time
import incubaid.herolib.vfs
import incubaid.herolib.circles.mcc.models as calendar
import incubaid.herolib.core.texttools
// Basic operations
pub fn (mut myvfs CalendarVFS) root_get() !vfs.FSEntry {
metadata := vfs.Metadata{
id: 1
name: ''
file_type: .directory
created_at: time.now().unix()
modified_at: time.now().unix()
accessed_at: time.now().unix()
}
return CalendarFSEntry{
path: ''
metadata: metadata
}
}
// File operations
pub fn (mut myvfs CalendarVFS) file_create(path string) !vfs.FSEntry {
return error('Calendar VFS is read-only')
}
pub fn (mut myvfs CalendarVFS) file_read(path string) ![]u8 {
if !myvfs.exists(path) {
return error('File does not exist: ${path}')
}
entry := myvfs.get(path)!
if !entry.is_file() {
return error('Path is not a file: ${path}')
}
calendar_entry := entry as CalendarFSEntry
if event := calendar_entry.calendar {
return json.encode(event).bytes()
}
return error('Failed to read file: ${path}')
}
pub fn (mut myvfs CalendarVFS) file_write(path string, data []u8) ! {
return error('Calendar VFS is read-only')
}
pub fn (mut myvfs CalendarVFS) file_concatenate(path string, data []u8) ! {
return error('Calendar VFS is read-only')
}
pub fn (mut myvfs CalendarVFS) file_delete(path string) ! {
return error('Calendar VFS is read-only')
}
// Directory operations
pub fn (mut myvfs CalendarVFS) dir_create(path string) !vfs.FSEntry {
return error('Calendar VFS is read-only')
}
pub fn (mut myvfs CalendarVFS) dir_list(path string) ![]vfs.FSEntry {
if !myvfs.exists(path) {
return error('Directory does not exist: ${path}')
}
// Get all events
events := myvfs.calendar_db.getall() or { return error('Failed to get events: ${err}') }
// If we're at the root, return all calendars
if path == '' {
return myvfs.list_calendars(events)!
}
// Split the path to determine the level
path_parts := path.split('/')
// Level 1: We're in a calendar, show the browsing methods (by_date, by_title, by_organizer)
if path_parts.len == 1 {
return myvfs.list_calendar_subdirs(path)!
}
// Level 2: We're in a browsing method directory
if path_parts.len == 2 {
match path_parts[1] {
'by_date' {
return myvfs.list_date_subdirs(path_parts[0], events)!
}
'by_title', 'by_organizer' {
return myvfs.list_events_by_type(path_parts[0], path_parts[1], events)!
}
else {
return error('Invalid browsing method: ${path_parts[1]}. Supported methods are by_date, by_title, by_organizer')
}
}
}
// Level 3: We're in a year_month directory under by_date
if path_parts.len == 3 && path_parts[1] == 'by_date' {
return myvfs.list_events_by_date(path_parts[0], path_parts[2], events)!
}
return error('Path depth not supported: ${path}')
}
pub fn (mut myvfs CalendarVFS) dir_delete(path string) ! {
return error('Calendar VFS is read-only')
}
// Symlink operations
pub fn (mut myvfs CalendarVFS) link_create(target_path string, link_path string) !vfs.FSEntry {
return error('Calendar VFS does not support symlinks')
}
pub fn (mut myvfs CalendarVFS) link_read(path string) !string {
return error('Calendar VFS does not support symlinks')
}
pub fn (mut myvfs CalendarVFS) link_delete(path string) ! {
return error('Calendar VFS does not support symlinks')
}
// Common operations
pub fn (mut myvfs CalendarVFS) exists(path string) bool {
// Root always exists
if path == '' {
return true
}
// Get all events
events := myvfs.calendar_db.getall() or { return false }
path_parts := path.split('/')
// Level 1: Check if the path is a calendar
if path_parts.len == 1 {
for event in events {
if event.id.str() == path_parts[0] {
return true
}
}
return false
}
// Level 2: Check if the path is a valid browsing method
if path_parts.len == 2 {
if path_parts[1] !in ['by_date', 'by_title', 'by_organizer'] {
return false
}
for event in events {
if event.id.str() == path_parts[0] {
return true
}
}
return false
}
// Level 3: Check if the path is a valid year_month directory under by_date
if path_parts.len == 3 && path_parts[1] == 'by_date' {
for event in events {
if event.id.str() != path_parts[0] {
continue
}
event_time := event.start_time.time()
year_month := '${event_time.year:04d}_${event_time.month:02d}'
if year_month == path_parts[2] {
return true
}
}
return false
}
// Level 3 or 4: Check if the path is an event file
if (path_parts.len == 4 && path_parts[1] == 'by_date')
|| (path_parts.len == 3 && path_parts[1] in ['by_title', 'by_organizer']) {
for event in events {
if event.id.str() != path_parts[0] {
continue
}
if path_parts[1] == 'by_date' {
event_time := event.start_time.time()
year_month := '${event_time.year:04d}_${event_time.month:02d}'
day := '${event_time.day:02d}'
filename := texttools.name_fix('${day}_${event.title}') + '.json'
if year_month == path_parts[2] && filename == path_parts[3] {
return true
}
} else if path_parts[1] == 'by_title' {
filename := texttools.name_fix(event.title) + '.json'
if filename == path_parts[2] {
return true
}
} else if path_parts[1] == 'by_organizer' {
if event.organizer.len > 0 {
filename := texttools.name_fix(event.organizer) + '.json'
if filename == path_parts[2] {
return true
}
}
}
}
}
return false
}
pub fn (mut myvfs CalendarVFS) get(path string) !vfs.FSEntry {
// Root always exists
if path == '' {
return myvfs.root_get()!
}
// Get all events
events := myvfs.calendar_db.getall() or { return error('Failed to get events: ${err}') }
path_parts := path.split('/')
// Level 1: Check if the path is a calendar
if path_parts.len == 1 {
for event in events {
if event.id.str() == path_parts[0] {
metadata := vfs.Metadata{
id: u32(path_parts[0].bytes().bytestr().hash())
name: path_parts[0]
file_type: .directory
created_at: time.now().unix()
modified_at: time.now().unix()
accessed_at: time.now().unix()
}
return CalendarFSEntry{
path: path
metadata: metadata
}
}
}
return error('Calendar not found: ${path_parts[0]}')
}
// Level 2: Check if the path is a browsing method directory
if path_parts.len == 2 {
if path_parts[1] !in ['by_date', 'by_title', 'by_organizer'] {
return error('Invalid browsing method: ${path_parts[1]}. Supported methods are by_date, by_title, by_organizer')
}
for event in events {
if event.id.str() == path_parts[0] {
metadata := vfs.Metadata{
id: u32(path.bytes().bytestr().hash())
name: path_parts[1]
file_type: .directory
created_at: time.now().unix()
modified_at: time.now().unix()
accessed_at: time.now().unix()
}
return CalendarFSEntry{
path: path
metadata: metadata
}
}
}
return error('Calendar not found: ${path_parts[0]}')
}
// Level 3: Check if the path is a year_month directory under by_date
if path_parts.len == 3 && path_parts[1] == 'by_date' {
for event in events {
if event.id.str() != path_parts[0] {
continue
}
event_time := event.start_time.time()
year_month := '${event_time.year:04d}_${event_time.month:02d}'
if year_month == path_parts[2] {
metadata := vfs.Metadata{
id: u32(path.bytes().bytestr().hash())
name: path_parts[2]
file_type: .directory
created_at: time.now().unix()
modified_at: time.now().unix()
accessed_at: time.now().unix()
}
return CalendarFSEntry{
path: path
metadata: metadata
}
}
}
return error('Date directory not found: ${path}')
}
// Level 3 or 4: Check if the path is an event file
if (path_parts.len == 4 && path_parts[1] == 'by_date')
|| (path_parts.len == 3 && path_parts[1] in ['by_title', 'by_organizer']) {
for event in events {
if event.id.str() != path_parts[0] {
continue
}
if path_parts[1] == 'by_date' {
event_time := event.start_time.time()
year_month := '${event_time.year:04d}_${event_time.month:02d}'
day := '${event_time.day:02d}'
filename := texttools.name_fix('${day}_${event.title}') + '.json'
if year_month == path_parts[2] && filename == path_parts[3] {
metadata := vfs.Metadata{
id: u32(event.id)
name: filename
file_type: .file
size: u64(json.encode(event).len)
created_at: event.start_time.time().unix()
modified_at: event.start_time.time().unix()
accessed_at: time.now().unix()
}
return CalendarFSEntry{
path: path
metadata: metadata
calendar: event
}
}
} else if path_parts[1] == 'by_title' {
filename := texttools.name_fix(event.title) + '.json'
if filename == path_parts[2] {
metadata := vfs.Metadata{
id: u32(event.id)
name: filename
file_type: .file
size: u64(json.encode(event).len)
created_at: event.start_time.time().unix()
modified_at: event.start_time.time().unix()
accessed_at: time.now().unix()
}
return CalendarFSEntry{
path: path
metadata: metadata
calendar: event
}
}
} else if path_parts[1] == 'by_organizer' {
if event.organizer.len > 0 {
filename := texttools.name_fix(event.organizer) + '.json'
if filename == path_parts[2] {
metadata := vfs.Metadata{
id: u32(event.id)
name: filename
file_type: .file
size: u64(json.encode(event).len)
created_at: event.start_time.time().unix()
modified_at: event.start_time.time().unix()
accessed_at: time.now().unix()
}
return CalendarFSEntry{
path: path
metadata: metadata
calendar: event
}
}
}
}
}
return error('Event file not found: ${path}')
}
return error('Path not found: ${path}')
}
pub fn (mut myvfs CalendarVFS) rename(old_path string, new_path string) !vfs.FSEntry {
return error('Calendar VFS is read-only')
}
pub fn (mut myvfs CalendarVFS) copy(src_path string, dst_path string) !vfs.FSEntry {
return error('Calendar VFS is read-only')
}
pub fn (mut myvfs CalendarVFS) move(src_path string, dst_path string) !vfs.FSEntry {
return error('Calendar VFS is read-only')
}
pub fn (mut myvfs CalendarVFS) delete(path string) ! {
return error('Calendar VFS is read-only')
}
// FSEntry Operations
pub fn (mut myvfs CalendarVFS) get_path(entry &vfs.FSEntry) !string {
calendar_entry := entry as CalendarFSEntry
return calendar_entry.path
}
pub fn (mut myvfs CalendarVFS) print() ! {
println('Calendar VFS')
}
// Cleanup operation
pub fn (mut myvfs CalendarVFS) destroy() ! {
// Nothing to clean up
}
// Helper functions
// list_calendars lists all unique calendars as directories
fn (mut myvfs CalendarVFS) list_calendars(events []calendar.CalendarEvent) ![]vfs.FSEntry {
mut calendars := map[string]bool{}
// Collect unique calendar names
for event in events {
calendars[event.id.str()] = true
}
// Create FSEntry for each calendar
mut result := []vfs.FSEntry{cap: calendars.len}
for calendar, _ in calendars {
metadata := vfs.Metadata{
id: u32(calendar.bytes().bytestr().hash())
name: calendar
file_type: .directory
created_at: time.now().unix()
modified_at: time.now().unix()
accessed_at: time.now().unix()
}
result << CalendarFSEntry{
path: calendar
metadata: metadata
}
}
return result
}
// list_calendar_subdirs lists the browsing methods (by_date, by_title, by_organizer) for a calendar
fn (mut myvfs CalendarVFS) list_calendar_subdirs(calendar_ string) ![]vfs.FSEntry {
mut result := []vfs.FSEntry{cap: 3}
// Create by_date directory
by_date_metadata := vfs.Metadata{
id: u32('${calendar_}/by_date'.bytes().bytestr().hash())
name: 'by_date'
file_type: .directory
created_at: time.now().unix()
modified_at: time.now().unix()
accessed_at: time.now().unix()
}
result << CalendarFSEntry{
path: '${calendar_}/by_date'
metadata: by_date_metadata
}
// Create by_title directory
by_title_metadata := vfs.Metadata{
id: u32('${calendar_}/by_title'.bytes().bytestr().hash())
name: 'by_title'
file_type: .directory
created_at: time.now().unix()
modified_at: time.now().unix()
accessed_at: time.now().unix()
}
result << CalendarFSEntry{
path: '${calendar_}/by_title'
metadata: by_title_metadata
}
// Create by_organizer directory
by_organizer_metadata := vfs.Metadata{
id: u32('${calendar_}/by_organizer'.bytes().bytestr().hash())
name: 'by_organizer'
file_type: .directory
created_at: time.now().unix()
modified_at: time.now().unix()
accessed_at: time.now().unix()
}
result << CalendarFSEntry{
path: '${calendar_}/by_organizer'
metadata: by_organizer_metadata
}
return result
}
// list_date_subdirs lists year_month directories under by_date for a calendar
fn (mut myvfs CalendarVFS) list_date_subdirs(calendar_ string, events []calendar.CalendarEvent) ![]vfs.FSEntry {
mut date_dirs := map[string]bool{}
// Collect unique year_month directories
for event in events {
if event.id.str() != calendar_ {
continue
}
event_time := event.start_time.time()
year_month := '${event_time.year:04d}_${event_time.month:02d}'
date_dirs[year_month] = true
}
// Create FSEntry for each year_month directory
mut result := []vfs.FSEntry{cap: date_dirs.len}
for year_month, _ in date_dirs {
metadata := vfs.Metadata{
id: u32('${calendar_}/by_date/${year_month}'.bytes().bytestr().hash())
name: year_month
file_type: .directory
created_at: time.now().unix()
modified_at: time.now().unix()
accessed_at: time.now().unix()
}
result << CalendarFSEntry{
path: '${calendar_}/by_date/${year_month}'
metadata: metadata
}
}
return result
}
// list_events_by_date lists events in a specific year_month directory
fn (mut myvfs CalendarVFS) list_events_by_date(calendar_ string, year_month string, events []calendar.CalendarEvent) ![]vfs.FSEntry {
mut result := []vfs.FSEntry{}
for event in events {
if event.id.str() != calendar_ {
continue
}
event_time := event.start_time.time()
event_year_month := '${event_time.year:04d}_${event_time.month:02d}'
if event_year_month != year_month {
continue
}
day := '${event_time.day:02d}'
filename := texttools.name_fix('${day}_${event.title}') + '.json'
metadata := vfs.Metadata{
id: u32(event.id)
name: filename
file_type: .file
size: u64(json.encode(event).len)
created_at: event.start_time.time().unix()
modified_at: event.start_time.time().unix()
accessed_at: time.now().unix()
}
result << CalendarFSEntry{
path: '${calendar_}/by_date/${year_month}/${filename}'
metadata: metadata
calendar: event
}
}
return result
}
// list_events_by_type lists events by a specific browsing method (by_title or by_organizer)
fn (mut myvfs CalendarVFS) list_events_by_type(calendar_ string, list_type string, events []calendar.CalendarEvent) ![]vfs.FSEntry {
mut result := []vfs.FSEntry{}
for event in events {
if event.id.str() != calendar_ {
continue
}
if list_type == 'by_title' {
filename := texttools.name_fix(event.title) + '.json'
metadata := vfs.Metadata{
id: u32(event.id)
name: filename
file_type: .file
size: u64(json.encode(event).len)
created_at: event.start_time.time().unix()
modified_at: event.start_time.time().unix()
accessed_at: time.now().unix()
}
result << CalendarFSEntry{
path: '${calendar_}/by_title/${filename}'
metadata: metadata
calendar: event
}
} else if list_type == 'by_organizer' {
if event.organizer.len > 0 {
filename := texttools.name_fix(event.organizer) + '.json'
metadata := vfs.Metadata{
id: u32(event.id)
name: filename
file_type: .file
size: u64(json.encode(event).len)
created_at: event.start_time.time().unix()
modified_at: event.start_time.time().unix()
accessed_at: time.now().unix()
}
result << CalendarFSEntry{
path: '${calendar_}/by_organizer/${filename}'
metadata: metadata
calendar: event
}
}
}
}
return result
}