- Added a new contacts database (`ContactsDB`) to store contact information. This improves data organization and allows for more efficient querying and manipulation of contact data. - Implemented a virtual file system (VFS) for contacts (`vfs_contacts`). This provides a file-like interface to access and manage contact data, improving integration with existing file-system-based tools and workflows. The VFS supports listing by group, by name, and by email. - Added model structs for contacts, improving data organization and serialization. This lays the foundation for more robust data handling and future expansion.
411 lines
10 KiB
V
411 lines
10 KiB
V
module vfs_contacts
|
|
|
|
import json
|
|
import time
|
|
import freeflowuniverse.herolib.vfs
|
|
import freeflowuniverse.herolib.circles.mcc.models as contacts
|
|
import freeflowuniverse.herolib.core.texttools
|
|
|
|
// Basic operations
|
|
pub fn (mut myvfs ContactsVFS) 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 ContactsFSEntry{
|
|
path: ''
|
|
metadata: metadata
|
|
}
|
|
}
|
|
|
|
// File operations
|
|
pub fn (mut myvfs ContactsVFS) file_create(path string) !vfs.FSEntry {
|
|
return error('Contacts VFS is read-only')
|
|
}
|
|
|
|
pub fn (mut myvfs ContactsVFS) 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}')
|
|
}
|
|
|
|
contacts_entry := entry as ContactsFSEntry
|
|
if contact := contacts_entry.contact {
|
|
return json.encode(contact).bytes()
|
|
}
|
|
|
|
return error('Failed to read file: ${path}')
|
|
}
|
|
|
|
pub fn (mut myvfs ContactsVFS) file_write(path string, data []u8) ! {
|
|
return error('Contacts VFS is read-only')
|
|
}
|
|
|
|
pub fn (mut myvfs ContactsVFS) file_concatenate(path string, data []u8) ! {
|
|
return error('Contacts VFS is read-only')
|
|
}
|
|
|
|
pub fn (mut myvfs ContactsVFS) file_delete(path string) ! {
|
|
return error('Contacts VFS is read-only')
|
|
}
|
|
|
|
// Directory operations
|
|
pub fn (mut myvfs ContactsVFS) dir_create(path string) !vfs.FSEntry {
|
|
return error('Contacts VFS is read-only')
|
|
}
|
|
|
|
pub fn (mut myvfs ContactsVFS) dir_list(path string) ![]vfs.FSEntry {
|
|
if !myvfs.exists(path) {
|
|
return error('Directory does not exist: ${path}')
|
|
}
|
|
|
|
// Get all contacts
|
|
contacts_ := myvfs.contacts_db.getall() or { return error('Failed to get contacts: ${err}') }
|
|
|
|
// If we're at the root, return all groups
|
|
if path == '' {
|
|
return myvfs.list_groups(contacts_)!
|
|
}
|
|
|
|
// Check if we're in a group path
|
|
path_parts := path.split('/')
|
|
if path_parts.len == 1 {
|
|
// We're in a group, show the by_name and by_email directories
|
|
return myvfs.list_group_subdirs(path)!
|
|
} else if path_parts.len == 2 && path_parts[1] in ['by_name', 'by_email'] {
|
|
// We're in a by_name or by_email directory, list the contacts
|
|
return myvfs.list_contacts_by_type(path_parts[0], path_parts[1], contacts_)!
|
|
}
|
|
|
|
return []vfs.FSEntry{}
|
|
}
|
|
|
|
pub fn (mut myvfs ContactsVFS) dir_delete(path string) ! {
|
|
return error('Contacts VFS is read-only')
|
|
}
|
|
|
|
// Symlink operations
|
|
pub fn (mut myvfs ContactsVFS) link_create(target_path string, link_path string) !vfs.FSEntry {
|
|
return error('Contacts VFS does not support symlinks')
|
|
}
|
|
|
|
pub fn (mut myvfs ContactsVFS) link_read(path string) !string {
|
|
return error('Contacts VFS does not support symlinks')
|
|
}
|
|
|
|
pub fn (mut myvfs ContactsVFS) link_delete(path string) ! {
|
|
return error('Contacts VFS does not support symlinks')
|
|
}
|
|
|
|
// Common operations
|
|
pub fn (mut myvfs ContactsVFS) exists(path string) bool {
|
|
// Root always exists
|
|
if path == '' {
|
|
return true
|
|
}
|
|
|
|
// Get all contacts
|
|
contacts_ := myvfs.contacts_db.getall() or { return false }
|
|
|
|
path_parts := path.split('/')
|
|
|
|
// Check if the path is a group
|
|
if path_parts.len == 1 {
|
|
for contact in contacts_ {
|
|
if contact.group == path_parts[0] {
|
|
return true
|
|
}
|
|
}
|
|
}
|
|
|
|
// Check if the path is a group subdir (by_name or by_email)
|
|
if path_parts.len == 2 && path_parts[1] in ['by_name', 'by_email'] {
|
|
for contact in contacts_ {
|
|
if contact.group == path_parts[0] {
|
|
return true
|
|
}
|
|
}
|
|
}
|
|
|
|
// Check if the path is a contact file
|
|
if path_parts.len == 3 && path_parts[1] in ['by_name', 'by_email'] {
|
|
for contact in contacts_ {
|
|
if contact.group != path_parts[0] {
|
|
continue
|
|
}
|
|
|
|
if path_parts[1] == 'by_name' {
|
|
filename := texttools.name_fix('${contact.first_name}_${contact.last_name}') +
|
|
'.json'
|
|
if filename == path_parts[2] {
|
|
return true
|
|
}
|
|
} else if path_parts[1] == 'by_email' {
|
|
filename := texttools.name_fix(contact.email) + '.json'
|
|
if filename == path_parts[2] {
|
|
return true
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
pub fn (mut myvfs ContactsVFS) get(path string) !vfs.FSEntry {
|
|
// Root always exists
|
|
if path == '' {
|
|
return myvfs.root_get()!
|
|
}
|
|
|
|
// Get all contacts
|
|
contacts_ := myvfs.contacts_db.getall() or { return error('Failed to get contacts: ${err}') }
|
|
|
|
path_parts := path.split('/')
|
|
|
|
// Check if the path is a group
|
|
if path_parts.len == 1 {
|
|
for contact in contacts_ {
|
|
if contact.group == 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 ContactsFSEntry{
|
|
path: path
|
|
metadata: metadata
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Check if the path is a group subdir (by_name or by_email)
|
|
if path_parts.len == 2 && path_parts[1] in ['by_name', 'by_email'] {
|
|
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 ContactsFSEntry{
|
|
path: path
|
|
metadata: metadata
|
|
}
|
|
}
|
|
|
|
// Check if the path is a contact file
|
|
if path_parts.len == 3 && path_parts[1] in ['by_name', 'by_email'] {
|
|
for contact in contacts_ {
|
|
if contact.group != path_parts[0] {
|
|
continue
|
|
}
|
|
|
|
if path_parts[1] == 'by_name' {
|
|
filename := texttools.name_fix('${contact.first_name}_${contact.last_name}') +
|
|
'.json'
|
|
if filename == path_parts[2] {
|
|
metadata := vfs.Metadata{
|
|
id: u32(contact.id)
|
|
name: filename
|
|
file_type: .file
|
|
size: u64(json.encode(contact).len)
|
|
created_at: contact.created_at
|
|
modified_at: contact.modified_at
|
|
accessed_at: time.now().unix()
|
|
}
|
|
|
|
return ContactsFSEntry{
|
|
path: path
|
|
metadata: metadata
|
|
contact: contact
|
|
}
|
|
}
|
|
} else if path_parts[1] == 'by_email' {
|
|
filename := texttools.name_fix(contact.email) + '.json'
|
|
if filename == path_parts[2] {
|
|
metadata := vfs.Metadata{
|
|
id: u32(contact.id)
|
|
name: filename
|
|
file_type: .file
|
|
size: u64(json.encode(contact).len)
|
|
created_at: contact.created_at
|
|
modified_at: contact.modified_at
|
|
accessed_at: time.now().unix()
|
|
}
|
|
|
|
return ContactsFSEntry{
|
|
path: path
|
|
metadata: metadata
|
|
contact: contact
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return error('Path not found: ${path}')
|
|
}
|
|
|
|
pub fn (mut myvfs ContactsVFS) rename(old_path string, new_path string) !vfs.FSEntry {
|
|
return error('Contacts VFS is read-only')
|
|
}
|
|
|
|
pub fn (mut myvfs ContactsVFS) copy(src_path string, dst_path string) !vfs.FSEntry {
|
|
return error('Contacts VFS is read-only')
|
|
}
|
|
|
|
pub fn (mut myvfs ContactsVFS) move(src_path string, dst_path string) !vfs.FSEntry {
|
|
return error('Contacts VFS is read-only')
|
|
}
|
|
|
|
pub fn (mut myvfs ContactsVFS) delete(path string) ! {
|
|
return error('Contacts VFS is read-only')
|
|
}
|
|
|
|
// FSEntry Operations
|
|
pub fn (mut myvfs ContactsVFS) get_path(entry &vfs.FSEntry) !string {
|
|
contacts_entry := entry as ContactsFSEntry
|
|
return contacts_entry.path
|
|
}
|
|
|
|
pub fn (mut myvfs ContactsVFS) print() ! {
|
|
println('Contacts VFS')
|
|
}
|
|
|
|
// Cleanup operation
|
|
pub fn (mut myvfs ContactsVFS) destroy() ! {
|
|
// Nothing to clean up
|
|
}
|
|
|
|
// Helper functions
|
|
fn (mut myvfs ContactsVFS) list_groups(contacts_ []contacts.Contact) ![]vfs.FSEntry {
|
|
mut groups := map[string]bool{}
|
|
|
|
// Collect unique group names
|
|
for contact in contacts_ {
|
|
groups[contact.group] = true
|
|
}
|
|
|
|
// Create FSEntry for each group
|
|
mut result := []vfs.FSEntry{cap: groups.len}
|
|
for group, _ in groups {
|
|
metadata := vfs.Metadata{
|
|
id: u32(group.bytes().bytestr().hash())
|
|
name: group
|
|
file_type: .directory
|
|
created_at: time.now().unix()
|
|
modified_at: time.now().unix()
|
|
accessed_at: time.now().unix()
|
|
}
|
|
|
|
result << ContactsFSEntry{
|
|
path: group
|
|
metadata: metadata
|
|
}
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
fn (mut myvfs ContactsVFS) list_group_subdirs(group string) ![]vfs.FSEntry {
|
|
mut result := []vfs.FSEntry{cap: 2}
|
|
|
|
// Create by_name directory
|
|
by_name_metadata := vfs.Metadata{
|
|
id: u32('${group}/by_name'.bytes().bytestr().hash())
|
|
name: 'by_name'
|
|
file_type: .directory
|
|
created_at: time.now().unix()
|
|
modified_at: time.now().unix()
|
|
accessed_at: time.now().unix()
|
|
}
|
|
|
|
result << ContactsFSEntry{
|
|
path: '${group}/by_name'
|
|
metadata: by_name_metadata
|
|
}
|
|
|
|
// Create by_email directory
|
|
by_email_metadata := vfs.Metadata{
|
|
id: u32('${group}/by_email'.bytes().bytestr().hash())
|
|
name: 'by_email'
|
|
file_type: .directory
|
|
created_at: time.now().unix()
|
|
modified_at: time.now().unix()
|
|
accessed_at: time.now().unix()
|
|
}
|
|
|
|
result << ContactsFSEntry{
|
|
path: '${group}/by_email'
|
|
metadata: by_email_metadata
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
fn (mut myvfs ContactsVFS) list_contacts_by_type(group string, list_type string, contacts_ []contacts.Contact) ![]vfs.FSEntry {
|
|
mut result := []vfs.FSEntry{}
|
|
|
|
for contact in contacts_ {
|
|
if contact.group != group {
|
|
continue
|
|
}
|
|
|
|
if list_type == 'by_name' {
|
|
filename := texttools.name_fix('${contact.first_name}_${contact.last_name}') + '.json'
|
|
metadata := vfs.Metadata{
|
|
id: u32(contact.id)
|
|
name: filename
|
|
file_type: .file
|
|
size: u64(json.encode(contact).len)
|
|
created_at: contact.created_at
|
|
modified_at: contact.modified_at
|
|
accessed_at: time.now().unix()
|
|
}
|
|
|
|
result << ContactsFSEntry{
|
|
path: '${group}/by_name/${filename}'
|
|
metadata: metadata
|
|
contact: contact
|
|
}
|
|
} else if list_type == 'by_email' {
|
|
filename := texttools.name_fix(contact.email) + '.json'
|
|
metadata := vfs.Metadata{
|
|
id: u32(contact.id)
|
|
name: filename
|
|
file_type: .file
|
|
size: u64(json.encode(contact).len)
|
|
created_at: contact.created_at
|
|
modified_at: contact.modified_at
|
|
accessed_at: time.now().unix()
|
|
}
|
|
|
|
result << ContactsFSEntry{
|
|
path: '${group}/by_email/${filename}'
|
|
metadata: metadata
|
|
contact: contact
|
|
}
|
|
}
|
|
}
|
|
|
|
return result
|
|
}
|