This commit is contained in:
2025-03-11 08:27:46 +01:00
parent 4358ba6471
commit ac583741a4
15 changed files with 374 additions and 181 deletions

View File

@@ -1,10 +1,9 @@
module actionprocessor module actionprocessor
import freeflowuniverse.herolib.circles.models.core import freeflowuniverse.herolib.circles.dbs.core
import freeflowuniverse.herolib.circles.models import freeflowuniverse.herolib.circles.models
import freeflowuniverse.herolib.core.texttools import freeflowuniverse.herolib.core.texttools
import os
__global ( __global (
circle_global map[string]&CircleCoordinator circle_global map[string]&CircleCoordinator
@@ -17,10 +16,10 @@ __global (
pub struct CircleCoordinator { pub struct CircleCoordinator {
pub mut: pub mut:
name string //is a unique name on planetary scale is a dns name name string //is a unique name on planetary scale is a dns name
agents &core.AgentManager agents &core.AgentDB
circles &core.CircleManager // circles &core.CircleDB
names &core.NameManager // names &core.NameDB
session_state model.SessionState session_state models.SessionState
} }
@@ -30,6 +29,7 @@ pub mut:
name string = "local" name string = "local"
pubkey string // pubkey of user who called this pubkey string // pubkey of user who called this
addr string //mycelium address addr string //mycelium address
path string
} }
// new creates a new CircleCoordinator instance // new creates a new CircleCoordinator instance
@@ -38,12 +38,11 @@ pub fn new(args_ CircleCoordinatorArgs) !&CircleCoordinator {
args.name = texttools.name_fix(args.name) args.name = texttools.name_fix(args.name)
if args.name in circle_global { if args.name in circle_global {
mut c:=circle_global[args.name] mut c:=circle_global[args.name] or {panic("bug")}
c.args = args
return c return c
} }
mut session_state:=models.new(name: args.name, pubkey: args.pubkey, addr: args.addr, path: args.path)! mut session_state:=models.new_session(name: args.name, pubkey: args.pubkey, addr: args.addr, path: args.path)!
// os.mkdir_all(mypath)! // os.mkdir_all(mypath)!
// Create the directories if they don't exist// SHOULD BE AUTOMATIC // Create the directories if they don't exist// SHOULD BE AUTOMATIC
@@ -53,15 +52,15 @@ pub fn new(args_ CircleCoordinatorArgs) !&CircleCoordinator {
// os.mkdir_all(os.join_path(mypath, 'meta_mcc'))! //message, contacts, calendar // os.mkdir_all(os.join_path(mypath, 'meta_mcc'))! //message, contacts, calendar
// Initialize the managers with proper ourdb instances // Initialize the db handlers with proper ourdb instances
mut agent_manager := core.new_agentmanager(session_state)! mut agent_db := core.new_agentdb(session_state)!
mut circle_manager := core.new_circlemanager(session_state)! // mut circle_db := core.new_circledb(session_state)!
mut name_manager := core.new_namemanager(session_state)! // mut name_db := core.new_namedb(session_state)!
mut cm := &CircleCoordinator{ mut cm := &CircleCoordinator{
agents: &agent_manager agents: &agent_db
circles: &circle_manager // circles: &circle_db
names: &name_manager // names: &name_db
session_state: session_state session_state: session_state
} }

View File

@@ -0,0 +1,121 @@
module core
import freeflowuniverse.herolib.data.ourtime
import freeflowuniverse.herolib.circles.models { DBHandler, SessionState }
import freeflowuniverse.herolib.circles.models.core { Agent, AgentService, AgentServiceAction, AgentState }
@[heap]
pub struct AgentDB {
pub mut:
db DBHandler[Agent]
}
pub fn new_agentdb(session_state SessionState) !AgentDB {
return AgentDB{
db:models.new_dbhandler[Agent]('agent', session_state)
}
}
pub fn (mut m AgentDB) new() Agent {
return Agent{}
}
// set adds or updates an agent
pub fn (mut m AgentDB) set(agent Agent) !Agent {
return m.db.set(agent)!
}
// get retrieves an agent by its ID
pub fn (mut m AgentDB) get(id u32) !Agent {
return m.db.get(id)!
}
// list returns all agent IDs
pub fn (mut m AgentDB) list() ![]u32 {
return m.db.list()!
}
pub fn (mut m AgentDB) getall() ![]Agent {
return m.db.getall()!
}
// delete removes an agent by its ID
pub fn (mut m AgentDB) delete(id u32) ! {
m.db.delete(id)!
}
//////////////////CUSTOM METHODS//////////////////////////////////
// get_by_pubkey retrieves an agent by its public key
pub fn (mut m AgentDB) get_by_pubkey(pubkey string) !Agent {
return m.db.get_by_key('pubkey', pubkey)!
}
// delete_by_pubkey removes an agent by its public key
pub fn (mut m AgentDB) delete_by_pubkey(pubkey string) ! {
// Get the agent by pubkey
agent := m.get_by_pubkey(pubkey) or {
// Agent not found, nothing to delete
return
}
// Delete the agent by ID
m.delete(agent.id)!
}
// update_status updates just the status of an agent
pub fn (mut m AgentDB) update_status(pubkey string, status AgentState) !Agent {
// Get the agent by pubkey
mut agent := m.get_by_pubkey(pubkey)!
// Update the status
agent.status.status = status
agent.status.timestamp_last = ourtime.now()
// Save the updated agent
return m.set(agent)!
}
// get_all_agent_pubkeys returns all agent pubkeys
pub fn (mut m AgentDB) get_all_agent_pubkeys() ![]string {
// Get all agent IDs
agent_ids := m.list()!
// Get pubkeys for all agents
mut pubkeys := []string{}
for id in agent_ids {
agent := m.get(id) or { continue }
pubkeys << agent.pubkey
}
return pubkeys
}
// get_by_service returns all agents that provide a specific service
pub fn (mut m AgentDB) get_by_service(actor string, action string) ![]Agent {
mut matching_agents := []Agent{}
// Get all agent IDs
agent_ids := m.list()!
// Filter agents that provide the specified service
for id in agent_ids {
// Get the agent by ID
agent := m.get(id) or { continue }
// Check if agent provides the specified service
for service in agent.services {
if service.actor == actor {
for service_action in service.actions {
if service_action.action == action {
matching_agents << agent
break
}
}
break
}
}
}
return matching_agents
}

View File

@@ -2,14 +2,15 @@ module core
import os import os
import rand import rand
import freeflowuniverse.herolib.circles.actionprocessor
fn test_agents_model() { import freeflowuniverse.herolib.circles.models.core
fn test_agent_db() {
// Create a temporary directory for testing // Create a temporary directory for testing
test_dir := os.join_path(os.temp_dir(), 'hero_agent_test_${rand.intn(9000) or { 0 } + 1000}') test_dir := os.join_path(os.temp_dir(), 'hero_agent_test_${rand.intn(9000) or { 0 } + 1000}')
os.mkdir_all(test_dir) or { panic(err) } os.mkdir_all(test_dir) or { panic(err) }
defer { os.rmdir_all(test_dir) or {} } defer { os.rmdir_all(test_dir) or {} }
mut runner := new(path: test_dir)! mut runner := actionprocessor.new(path: test_dir)!
// Create multiple agents for testing // Create multiple agents for testing
mut agent1 := runner.agents.new() mut agent1 := runner.agents.new()
@@ -27,29 +28,19 @@ fn test_agents_model() {
agent3.address = '127.0.0.3' agent3.address = '127.0.0.3'
agent3.description = 'Test Agent 3' agent3.description = 'Test Agent 3'
// Create a service action // Create a service using the factory method
mut action := AgentServiceAction{ mut service := agent1.new_service(actor: 'vm_manager', description: 'VM Management Service')
action: 'start'
description: 'Start a VM'
params: {
'name': 'string'
}
params_example: {
'name': 'myvm'
}
status: .ok
public: true
}
// Create a service // Create a service action using the factory method
mut service := AgentService{ mut action := service.new_action(action:'start', description: 'Start a VM')
actor: 'vm_manager'
actions: [action]
description: 'VM Management Service'
status: .ok
}
agent1.services = [service] // Set additional properties for the action
action.params = {
'name': 'string'
}
action.params_example = {
'name': 'myvm'
}
// Add the agents // Add the agents
println('Adding agent 1') println('Adding agent 1')
@@ -72,11 +63,14 @@ fn test_agents_model() {
println('Agent IDs in list: ${agent_ids}') println('Agent IDs in list: ${agent_ids}')
// Debug: Print the 'all' key from the radix tree // Debug: Print the 'all' key from the radix tree
if all_bytes := runner.agents.manager.db_meta.search('agent:all') { all_bytes := runner.agents.db.session_state.dbs.db_meta_core.get('agent:id') or {
println('No agent:id key found in radix tree')
[]u8{}
}
if all_bytes.len > 0 {
all_str := all_bytes.bytestr() all_str := all_bytes.bytestr()
println('Raw agent:all key content: "${all_str}"') println('Raw agent:id key content: "${all_str}"')
} else {
println('No agent:all key found in radix tree')
} }
// Get all agents // Get all agents
@@ -174,7 +168,7 @@ fn test_agents_model() {
agents_after_all_deleted := runner.agents.getall() or { agents_after_all_deleted := runner.agents.getall() or {
// This is expected to fail with 'No agents found' error // This is expected to fail with 'No agents found' error
assert err.msg() == 'No agents found' assert err.msg() == 'No agents found'
[]Agent{} []core.Agent{cap: 0}
} }
assert agents_after_all_deleted.len == 0, 'Expected 0 agents after all deletions, got ${agents_after_all_deleted.len}' assert agents_after_all_deleted.len == 0, 'Expected 0 agents after all deletions, got ${agents_after_all_deleted.len}'

View File

@@ -3,19 +3,58 @@ module core
import freeflowuniverse.herolib.data.ourtime import freeflowuniverse.herolib.data.ourtime
import freeflowuniverse.herolib.data.encoder import freeflowuniverse.herolib.data.encoder
// Agent represents a service provider that can execute jobs // Agent represents self service provider that can execute jobs
pub struct Agent { pub struct Agent {
pub mut: pub mut:
id u32 id u32
pubkey string // pubkey using ed25519 pubkey string // pubkey using ed25519
address string // where we can find the agent address string // where we can find the agent
port int // default 9999 port u16 // default 9999
description string // optional description string // optional
status AgentStatus status AgentStatus
services []AgentService // these are the public services services []AgentService // these are the public services
signature string // signature as done by private key of $address+$port+$description+$status signature string // signature as done by private key of $address+$port+$description+$status
} }
@[params]
pub struct ServiceParams {
pub mut:
actor string
description string
}
// new_service creates self new AgentService for this agent
pub fn (mut self Agent) new_service(args ServiceParams) &AgentService {
mut service := AgentService{
actor: args.actor
description: args.description
status: .ok
public: true
}
self.services << service
return &self.services[self.services.len - 1]
}
@[params]
pub struct ActionParams {
pub mut:
action string
description string
}
// new_service_action creates self new AgentServiceAction for the specified service
pub fn (mut service AgentService) new_action(args ActionParams) &AgentServiceAction {
mut service_action := AgentServiceAction{
action: args.action
description: args.description
status: .ok
public: true
}
service.actions << service_action
return &service.actions[service.actions.len - 1]
}
// AgentStatus represents the current state of an agent // AgentStatus represents the current state of an agent
pub struct AgentStatus { pub struct AgentStatus {
pub mut: pub mut:
@@ -25,7 +64,7 @@ pub mut:
status AgentState // current state of the agent status AgentState // current state of the agent
} }
// AgentService represents a service provided by an agent // AgentService represents self service provided by an agent
pub struct AgentService { pub struct AgentService {
pub mut: pub mut:
actor string // name of the actor providing the service actor string // name of the actor providing the service
@@ -35,7 +74,7 @@ pub mut:
public bool // if everyone can use then true, if restricted means only certain people can use public bool // if everyone can use then true, if restricted means only certain people can use
} }
// AgentServiceAction represents an action that can be performed by a service // AgentServiceAction represents an action that can be performed by self service
pub struct AgentServiceAction { pub struct AgentServiceAction {
pub mut: pub mut:
action string // which action action string // which action
@@ -62,34 +101,34 @@ pub enum AgentServiceState {
halted // service/action has been manually stopped halted // service/action has been manually stopped
} }
pub fn (c Agent) index_keys() map[string]string { pub fn (self Agent) index_keys() map[string]string {
return {"pubkey": c.pubkey} return {"pubkey": self.pubkey}
} }
// dumps serializes the Agent struct to binary format using the encoder // dumps serializes the Agent struct to binary format using the encoder
pub fn (a Agent) dumps() ![]u8 { pub fn (self Agent) dumps() ![]u8 {
mut e := encoder.new() mut e := encoder.new()
// Add unique encoding ID to identify this type of data // Add unique encoding ID to identify this type of data
e.add_u16(100) e.add_u16(100)
// Encode Agent fields // Encode Agent fields
e.add_string(a.pubkey) e.add_string(self.pubkey)
e.add_string(a.address) e.add_string(self.address)
e.add_int(a.port) e.add_u16(self.port)
e.add_string(a.description) e.add_string(self.description)
// Encode AgentStatus // Encode AgentStatus
e.add_string(a.status.guid) e.add_string(self.status.guid)
e.add_ourtime(a.status.timestamp_first) e.add_ourtime(self.status.timestamp_first)
e.add_ourtime(a.status.timestamp_last) e.add_ourtime(self.status.timestamp_last)
e.add_u8(u8(a.status.status)) e.add_u8(u8(self.status.status))
// Encode services array // Encode services array
e.add_u16(u16(a.services.len)) e.add_u16(u16(self.services.len))
for service in a.services { for service in self.services {
// Encode AgentService fields // Encode AgentService fields
e.add_string(service.actor) e.add_string(service.actor)
e.add_string(service.description) e.add_string(service.description)
@@ -114,15 +153,14 @@ pub fn (a Agent) dumps() ![]u8 {
} }
// Encode signature // Encode signature
e.add_string(a.signature) e.add_string(self.signature)
return e.data return e.data
} }
// loads deserializes binary data into an Agent struct // loads deserializes binary data into an Agent struct
pub fn Agent.loads(data []u8) !Agent { pub fn agent_loads(data []u8) !Agent {
mut d := encoder.decoder_new(data) mut d := encoder.decoder_new(data)
mut agent := Agent{}
// Check encoding ID to verify this is the correct type of data // Check encoding ID to verify this is the correct type of data
encoding_id := d.get_u16()! encoding_id := d.get_u16()!
@@ -130,18 +168,20 @@ pub fn Agent.loads(data []u8) !Agent {
return error('Wrong file type: expected encoding ID 100, got ${encoding_id}, for agent') return error('Wrong file type: expected encoding ID 100, got ${encoding_id}, for agent')
} }
mut self:=Agent{}
// Decode Agent fields // Decode Agent fields
agent.pubkey = d.get_string()! self.pubkey = d.get_string()!
agent.address = d.get_string()! self.address = d.get_string()!
agent.port = d.get_int()! self.port = d.get_u16()!
agent.description = d.get_string()! self.description = d.get_string()!
// Decode AgentStatus // Decode AgentStatus
agent.status.guid = d.get_string()! self.status.guid = d.get_string()!
agent.status.timestamp_first = d.get_ourtime()! self.status.timestamp_first = d.get_ourtime()!
agent.status.timestamp_last = d.get_ourtime()! self.status.timestamp_last = d.get_ourtime()!
status_val := d.get_u8()! status_val := d.get_u8()!
agent.status.status = match status_val { self.status.status = match status_val {
0 { AgentState.ok } 0 { AgentState.ok }
1 { AgentState.down } 1 { AgentState.down }
2 { AgentState.error } 2 { AgentState.error }
@@ -151,7 +191,7 @@ pub fn Agent.loads(data []u8) !Agent {
// Decode services array // Decode services array
services_len := d.get_u16()! services_len := d.get_u16()!
agent.services = []AgentService{len: int(services_len)} self.services = []AgentService{len: int(services_len)}
for i in 0 .. services_len { for i in 0 .. services_len {
mut service := AgentService{} mut service := AgentService{}
@@ -196,11 +236,12 @@ pub fn Agent.loads(data []u8) !Agent {
service.actions[j] = action service.actions[j] = action
} }
agent.services[i] = service self.services[i] = service
} }
// Decode signature // Decode signature
agent.signature = d.get_string()! self.signature = d.get_string()!
return self
return agent
} }

View File

@@ -1,9 +1,6 @@
module models module models
import freeflowuniverse.herolib.data.radixtree import freeflowuniverse.herolib.circles.models.core { agent_loads, Agent }
import freeflowuniverse.herolib.data.ourdb
import json
pub struct DBHandler[T] { pub struct DBHandler[T] {
pub mut: pub mut:
@@ -25,7 +22,7 @@ pub fn (mut m DBHandler[T]) set(item_ T) !T {
mut item := item_ mut item := item_
// Store the item data in the database and get the assigned ID // Store the item data in the database and get the assigned ID
item.id = m.session_state.dbs.db_data_core.set(id: item.id, data: item.dumps()!)! item.id = m.session_state.dbs.db_data_core.set(data: item.dumps()!)!
// Update index keys // Update index keys
for key, value in m.index_keys(item)! { for key, value in m.index_keys(item)! {
@@ -42,13 +39,23 @@ pub fn (mut m DBHandler[T]) get(id u32) !T {
item_data := m.session_state.dbs.db_data_core.get(id) or { item_data := m.session_state.dbs.db_data_core.get(id) or {
return error('Item data not found for ID ${id}') return error('Item data not found for ID ${id}')
} }
mut o:=T.loads(item_data)! mut o:= T{}
match o {
Agent {
o=agent_loads(item_data)!
}else{
return panic('Not implemented object')
}
}
// o.loads(item_data)!
o.id = id o.id = id
return o return o
} }
pub fn (mut m DBHandler[T]) exists(id u32) !bool { pub fn (mut m DBHandler[T]) exists(id u32) !bool {
return m.db_data.get(id) or { return false } != []u8{} item_data := m.session_state.dbs.db_data_core.get(id) or { return false }
return item_data != []u8{}
} }
@@ -99,12 +106,33 @@ fn (mut m DBHandler[T]) index_keys(item T) !map[string]string {
return keymap return keymap
} }
// list returns all ids from the manager // list returns all ids from the db handler
pub fn (mut m DBHandler[T]) list() ![]u32 { pub fn (mut m DBHandler[T]) list() ![]u32 {
// Use the RadixTree's prefix capabilities to list all items // Use the RadixTree's prefix capabilities to list all items
defaultkey:=m.index_keys(T{})[0] or {panic('no index keys')} mut empty_item := T{}
keys := m.session_state.dbs.db_meta_core.getall('${m.prefix}:${defaultkey}')! mut keys_map := m.index_keys(empty_item)!
return keys if keys_map.len == 0 {
return error('No index keys defined for this type')
}
// Get the first key from the map
mut default_key := ''
for k, _ in keys_map {
default_key = k
break
}
// Get all IDs from the meta database
id_bytes := m.session_state.dbs.db_meta_core.getall('${m.prefix}:${default_key}')!
// Convert bytes to u32 IDs
mut result := []u32{}
for id_byte in id_bytes {
id_str := id_byte.bytestr()
result << id_str.u32()
}
return result
} }

View File

@@ -11,6 +11,7 @@ pub mut:
name string name string
pubkey string // pubkey of user who called this pubkey string // pubkey of user who called this
addr string //mycelium address addr string //mycelium address
dbs Databases
} }
pub struct Databases{ pub struct Databases{
@@ -42,22 +43,27 @@ pub fn new_session(args_ StateArgs) !SessionState {
mypath:=os.join_path(args.path, args.name) mypath:=os.join_path(args.path, args.name)
mut dbs:=Databases{ mut db_data_core := ourdb.new(
db_data_core : ourdb.new(
path: os.join_path(mypath, 'data_core') path: os.join_path(mypath, 'data_core')
incremental_mode: true incremental_mode: true
)! )!
db_meta_core : radixtree.new( mut db_meta_core := radixtree.new(
path: os.join_path(mypath, 'meta_core') path: os.join_path(mypath, 'meta_core')
)! )!
db_data_mcc : ourdb.new( mut db_data_mcc := ourdb.new(
path: os.join_path(mypath, 'data_mcc') path: os.join_path(mypath, 'data_mcc')
incremental_mode: false incremental_mode: false
)! )!
db_meta_mcc : radixtree.new( mut db_meta_mcc := radixtree.new(
path: os.join_path(mypath, 'meta_mcc') path: os.join_path(mypath, 'meta_mcc')
)! )!
}
mut dbs := Databases{
db_data_core: &db_data_core
db_meta_core: &db_meta_core
db_data_mcc: &db_data_mcc
db_meta_mcc: &db_meta_mcc
}
mut s := SessionState{ mut s := SessionState{
name: args.name name: args.name

View File

@@ -1,59 +1,58 @@
module core module core
import freeflowuniverse.herolib.data.ourtime import freeflowuniverse.herolib.data.ourtime
import freeflowuniverse.herolib.data.ourdb import freeflowuniverse.herolib.circles.models { DBHandler, SessionState }
import freeflowuniverse.herolib.data.radixtree import freeflowuniverse.herolib.circles.models.core { Agent, AgentService, AgentServiceAction, AgentState }
import freeflowuniverse.herolib.circles.models
@[heap] @[heap]
pub struct AgentManager { pub struct AgentDB {
pub mut: pub mut:
db models.DBHandler[Agent] db models.DBHandler[Agent]
} }
pub fn new_agentdb(session_state SessionState) AgentManager { pub fn new_agentdb(session_state SessionState) !AgentDB {
return AgentManager{ return AgentDB{
db:models.new_dbhandler[Agent]('agent', session_state) db:models.new_dbhandler[Agent]('agent', session_state)
} }
} }
pub fn (mut m AgentManager) new() Agent { pub fn (mut m AgentDB) new() Agent {
return Agent{} return Agent{}
} }
// set adds or updates an agent // set adds or updates an agent
pub fn (mut m AgentManager) set(agent Agent) !Agent { pub fn (mut m AgentDB) set(agent Agent) !Agent {
return m.db.set(agent)! return m.db.set(agent)!
} }
// get retrieves an agent by its ID // get retrieves an agent by its ID
pub fn (mut m AgentManager) get(id u32) !Agent { pub fn (mut m AgentDB) get(id u32) !Agent {
return m.db.get(id)! return m.db.get(id)!
} }
// list returns all agent IDs // list returns all agent IDs
pub fn (mut m AgentManager) list() ![]u32 { pub fn (mut m AgentDB) list() ![]u32 {
return m.db.list()! return m.db.list()!
} }
pub fn (mut m AgentManager) getall() ![]Agent { pub fn (mut m AgentDB) getall() ![]Agent {
return m.db.getall()! return m.db.getall()!
} }
// delete removes an agent by its ID // delete removes an agent by its ID
pub fn (mut m AgentManager) delete(id u32) ! { pub fn (mut m AgentDB) delete(id u32) ! {
m.db.delete(id)! m.db.delete(id)!
} }
//////////////////CUSTOM METHODS////////////////////////////////// //////////////////CUSTOM METHODS//////////////////////////////////
// get_by_pubkey retrieves an agent by its public key // get_by_pubkey retrieves an agent by its public key
pub fn (mut m AgentManager) get_by_pubkey(pubkey string) !Agent { pub fn (mut m AgentDB) get_by_pubkey(pubkey string) !Agent {
return m.db.get_by_key('pubkey', pubkey)! return m.db.get_by_key('pubkey', pubkey)!
} }
// delete_by_pubkey removes an agent by its public key // delete_by_pubkey removes an agent by its public key
pub fn (mut m AgentManager) delete_by_pubkey(pubkey string) ! { pub fn (mut m AgentDB) delete_by_pubkey(pubkey string) ! {
// Get the agent by pubkey // Get the agent by pubkey
agent := m.get_by_pubkey(pubkey) or { agent := m.get_by_pubkey(pubkey) or {
// Agent not found, nothing to delete // Agent not found, nothing to delete
@@ -65,7 +64,7 @@ pub fn (mut m AgentManager) delete_by_pubkey(pubkey string) ! {
} }
// update_status updates just the status of an agent // update_status updates just the status of an agent
pub fn (mut m AgentManager) update_status(pubkey string, status AgentState) !Agent { pub fn (mut m AgentDB) update_status(pubkey string, status AgentState) !Agent {
// Get the agent by pubkey // Get the agent by pubkey
mut agent := m.get_by_pubkey(pubkey)! mut agent := m.get_by_pubkey(pubkey)!
@@ -78,7 +77,7 @@ pub fn (mut m AgentManager) update_status(pubkey string, status AgentState) !Age
} }
// get_all_agent_pubkeys returns all agent pubkeys // get_all_agent_pubkeys returns all agent pubkeys
fn (mut m AgentManager) get_all_agent_pubkeys() ![]string { pub fn (mut m AgentDB) get_all_agent_pubkeys() ![]string {
// Get all agent IDs // Get all agent IDs
agent_ids := m.list()! agent_ids := m.list()!
@@ -93,7 +92,7 @@ fn (mut m AgentManager) get_all_agent_pubkeys() ![]string {
} }
// get_by_service returns all agents that provide a specific service // get_by_service returns all agents that provide a specific service
pub fn (mut m AgentManager) get_by_service(actor string, action string) ![]Agent { pub fn (mut m AgentDB) get_by_service(actor string, action string) ![]Agent {
mut matching_agents := []Agent{} mut matching_agents := []Agent{}
// Get all agent IDs // Get all agent IDs

View File

@@ -70,7 +70,8 @@ fn test_agent_dumps_loads() {
} }
// Test binary decoding // Test binary decoding
decoded_agent := agent_loads(binary_data) or { mut decoded_agent := Agent{}
decoded_agent.loads(binary_data) or {
assert false, 'Failed to decode agent: ${err}' assert false, 'Failed to decode agent: ${err}'
return return
} }
@@ -232,7 +233,8 @@ fn test_agent_complex_structure() {
} }
// Test binary decoding // Test binary decoding
decoded_agent := agent_loads(binary_data) or { mut decoded_agent := Agent{}
decoded_agent.loads(binary_data) or {
assert false, 'Failed to decode complex agent: ${err}' assert false, 'Failed to decode complex agent: ${err}'
return return
} }
@@ -303,7 +305,8 @@ fn test_agent_empty_structures() {
} }
// Test binary decoding // Test binary decoding
decoded_agent := agent_loads(binary_data) or { mut decoded_agent := Agent{}
decoded_agent.loads(binary_data) or {
assert false, 'Failed to decode empty agent: ${err}' assert false, 'Failed to decode empty agent: ${err}'
return return
} }

View File

@@ -3,56 +3,57 @@ module core
import freeflowuniverse.herolib.data.ourdb import freeflowuniverse.herolib.data.ourdb
import freeflowuniverse.herolib.data.radixtree import freeflowuniverse.herolib.data.radixtree
import freeflowuniverse.herolib.core.playbook import freeflowuniverse.herolib.core.playbook
import freeflowuniverse.herolib.circles.models
@[heap] @[heap]
pub struct CircleManager { pub struct CircleDB {
pub mut: pub mut:
manager DBSession[Circle] db models.DBHandler[Circle]
} }
pub fn new_circlemanager(db_data &ourdb.OurDB, db_meta &radixtree.RadixTree) CircleManager { pub fn new_circledb(session_state models.SessionState) !CircleDB {
return CircleManager{ return CircleDB{
manager: session.new_dbsession[Circle](db_data, db_meta, 'circle') db: models.new_dbhandler[Circle]('circle', session_state)
} }
} }
pub fn (mut m CircleManager) new() Circle { pub fn (mut m CircleDB) new() Circle {
return Circle{} return Circle{}
} }
// set adds or updates a circle // set adds or updates a circle
pub fn (mut m CircleManager) set(circle Circle) !Circle { pub fn (mut m CircleDB) set(circle Circle) !Circle {
return m.manager.set(circle)! return m.db.set(circle)!
} }
// get retrieves a circle by its ID // get retrieves a circle by its ID
pub fn (mut m CircleManager) get(id u32) !Circle { pub fn (mut m CircleDB) get(id u32) !Circle {
return m.manager.get(id)! return m.db.get(id)!
} }
// list returns all circle IDs // list returns all circle IDs
pub fn (mut m CircleManager) list() ![]u32 { pub fn (mut m CircleDB) list() ![]u32 {
return m.manager.list()! return m.db.list()!
} }
pub fn (mut m CircleManager) getall() ![]Circle { pub fn (mut m CircleDB) getall() ![]Circle {
return m.manager.getall()! return m.db.getall()!
} }
// delete removes a circle by its ID // delete removes a circle by its ID
pub fn (mut m CircleManager) delete(id u32) ! { pub fn (mut m CircleDB) delete(id u32) ! {
m.manager.delete(id)! m.db.delete(id)!
} }
//////////////////CUSTOM METHODS////////////////////////////////// //////////////////CUSTOM METHODS//////////////////////////////////
// get_by_name retrieves a circle by its name // get_by_name retrieves a circle by its name
pub fn (mut m CircleManager) get_by_name(name string) !Circle { pub fn (mut m CircleDB) get_by_name(name string) !Circle {
return m.manager.get_by_key('name', name)! return m.db.get_by_key('name', name)!
} }
// delete_by_name removes a circle by its name // delete_by_name removes a circle by its name
pub fn (mut m CircleManager) delete_by_name(name string) ! { pub fn (mut m CircleDB) delete_by_name(name string) ! {
// Get the circle by name // Get the circle by name
circle := m.get_by_name(name) or { circle := m.get_by_name(name) or {
// Circle not found, nothing to delete // Circle not found, nothing to delete
@@ -64,7 +65,7 @@ pub fn (mut m CircleManager) delete_by_name(name string) ! {
} }
// add_member adds a member to a circle // add_member adds a member to a circle
pub fn (mut m CircleManager) add_member(circle_id u32, member Member) !Circle { pub fn (mut m CircleDB) add_member(circle_id u32, member Member) !Circle {
// Get the circle by ID // Get the circle by ID
mut circle := m.get(circle_id)! mut circle := m.get(circle_id)!
@@ -91,7 +92,7 @@ pub fn (mut m CircleManager) add_member(circle_id u32, member Member) !Circle {
} }
// remove_member removes a member from a circle by pubkey // remove_member removes a member from a circle by pubkey
pub fn (mut m CircleManager) remove_member(circle_id u32, pubkey string) !Circle { pub fn (mut m CircleDB) remove_member(circle_id u32, pubkey string) !Circle {
// Get the circle by ID // Get the circle by ID
mut circle := m.get(circle_id)! mut circle := m.get(circle_id)!
@@ -127,7 +128,7 @@ pub fn (mut m CircleManager) remove_member(circle_id u32, pubkey string) !Circle
} }
// update_member_role updates the role of a member in a circle // update_member_role updates the role of a member in a circle
pub fn (mut m CircleManager) update_member_role(circle_id u32, pubkey string, role Role) !Circle { pub fn (mut m CircleDB) update_member_role(circle_id u32, pubkey string, role Role) !Circle {
// Get the circle by ID // Get the circle by ID
mut circle := m.get(circle_id)! mut circle := m.get(circle_id)!
@@ -156,7 +157,7 @@ pub fn (mut m CircleManager) update_member_role(circle_id u32, pubkey string, ro
} }
// get_members returns all members of a circle // get_members returns all members of a circle
pub fn (mut m CircleManager) get_members(circle_id u32) ![]Member { pub fn (mut m CircleDB) get_members(circle_id u32) ![]Member {
// Get the circle by ID // Get the circle by ID
circle := m.get(circle_id)! circle := m.get(circle_id)!
@@ -164,7 +165,7 @@ pub fn (mut m CircleManager) get_members(circle_id u32) ![]Member {
} }
// get_members_by_role returns all members of a circle with a specific role // get_members_by_role returns all members of a circle with a specific role
pub fn (mut m CircleManager) get_members_by_role(circle_id u32, role Role) ![]Member { pub fn (mut m CircleDB) get_members_by_role(circle_id u32, role Role) ![]Member {
// Get the circle by ID // Get the circle by ID
circle := m.get(circle_id)! circle := m.get(circle_id)!
@@ -181,7 +182,7 @@ pub fn (mut m CircleManager) get_members_by_role(circle_id u32, role Role) ![]Me
} }
// play processes heroscript commands for circles // play processes heroscript commands for circles
pub fn play_circle(mut cm CircleManager, mut plbook playbook.PlayBook) ! { pub fn play_circle(mut cm CircleDB, mut plbook playbook.PlayBook) ! {
// Find all actions that start with 'circle.' // Find all actions that start with 'circle.'
circle_actions := plbook.actions_find(actor: 'circle')! circle_actions := plbook.actions_find(actor: 'circle')!
if circle_actions.len == 0 { if circle_actions.len == 0 {

View File

@@ -3,7 +3,7 @@ module core
import os import os
import rand import rand
fn test_circle_manager() { fn test_circle_db() {
// Create a temporary directory for testing // Create a temporary directory for testing
test_dir := os.join_path(os.temp_dir(), 'hero_circle_test_${rand.intn(9000) or { 0 } + 1000}') test_dir := os.join_path(os.temp_dir(), 'hero_circle_test_${rand.intn(9000) or { 0 } + 1000}')
os.mkdir_all(test_dir) or { panic(err) } os.mkdir_all(test_dir) or { panic(err) }

View File

@@ -3,56 +3,57 @@ module core
import freeflowuniverse.herolib.data.ourdb import freeflowuniverse.herolib.data.ourdb
import freeflowuniverse.herolib.data.radixtree import freeflowuniverse.herolib.data.radixtree
import freeflowuniverse.herolib.core.playbook import freeflowuniverse.herolib.core.playbook
import freeflowuniverse.herolib.circles.models
@[heap] @[heap]
pub struct NameManager { pub struct NameDB {
pub mut: pub mut:
manager DBSession[Name] db models.DBHandler[Name]
} }
pub fn new_namemanager(db_data &ourdb.OurDB, db_meta &radixtree.RadixTree) NameManager { pub fn new_namedb(session_state models.SessionState) !NameDB {
return NameManager{ return NameDB{
manager: session.new_dbsession[Name](db_data, db_meta, 'name') db: models.new_dbhandler[Name]('name', session_state)
} }
} }
pub fn (mut m NameManager) new() Name { pub fn (mut m NameDB) new() Name {
return Name{} return Name{}
} }
// set adds or updates a name // set adds or updates a name
pub fn (mut m NameManager) set(name Name) !Name { pub fn (mut m NameDB) set(name Name) !Name {
return m.manager.set(name)! return m.db.set(name)!
} }
// get retrieves a name by its ID // get retrieves a name by its ID
pub fn (mut m NameManager) get(id u32) !Name { pub fn (mut m NameDB) get(id u32) !Name {
return m.manager.get(id)! return m.db.get(id)!
} }
// list returns all name IDs // list returns all name IDs
pub fn (mut m NameManager) list() ![]u32 { pub fn (mut m NameDB) list() ![]u32 {
return m.manager.list()! return m.db.list()!
} }
pub fn (mut m NameManager) getall() ![]Name { pub fn (mut m NameDB) getall() ![]Name {
return m.manager.getall()! return m.db.getall()!
} }
// delete removes a name by its ID // delete removes a name by its ID
pub fn (mut m NameManager) delete(id u32) ! { pub fn (mut m NameDB) delete(id u32) ! {
m.manager.delete(id)! m.db.delete(id)!
} }
//////////////////CUSTOM METHODS////////////////////////////////// //////////////////CUSTOM METHODS//////////////////////////////////
// get_by_domain retrieves a name by its domain // get_by_domain retrieves a name by its domain
pub fn (mut m NameManager) get_by_domain(domain string) !Name { pub fn (mut m NameDB) get_by_domain(domain string) !Name {
return m.manager.get_by_key('domain', domain)! return m.db.get_by_key('domain', domain)!
} }
// delete_by_domain removes a name by its domain // delete_by_domain removes a name by its domain
pub fn (mut m NameManager) delete_by_domain(domain string) ! { pub fn (mut m NameDB) delete_by_domain(domain string) ! {
// Get the name by domain // Get the name by domain
name := m.get_by_domain(domain) or { name := m.get_by_domain(domain) or {
// Name not found, nothing to delete // Name not found, nothing to delete
@@ -64,7 +65,7 @@ pub fn (mut m NameManager) delete_by_domain(domain string) ! {
} }
// add_record adds a record to a name // add_record adds a record to a name
pub fn (mut m NameManager) add_record(name_id u32, record Record) !Name { pub fn (mut m NameDB) add_record(name_id u32, record Record) !Name {
// Get the name by ID // Get the name by ID
mut name := m.get(name_id)! mut name := m.get(name_id)!
@@ -83,7 +84,7 @@ pub fn (mut m NameManager) add_record(name_id u32, record Record) !Name {
} }
// remove_record removes a record from a name by name and category // remove_record removes a record from a name by name and category
pub fn (mut m NameManager) remove_record(name_id u32, record_name string, category RecordType) !Name { pub fn (mut m NameDB) remove_record(name_id u32, record_name string, category RecordType) !Name {
// Get the name by ID // Get the name by ID
mut name := m.get(name_id)! mut name := m.get(name_id)!
@@ -111,7 +112,7 @@ pub fn (mut m NameManager) remove_record(name_id u32, record_name string, catego
} }
// update_record updates a record in a name // update_record updates a record in a name
pub fn (mut m NameManager) update_record(name_id u32, record_name string, category RecordType, new_record Record) !Name { pub fn (mut m NameDB) update_record(name_id u32, record_name string, category RecordType, new_record Record) !Name {
// Get the name by ID // Get the name by ID
mut name := m.get(name_id)! mut name := m.get(name_id)!
@@ -145,7 +146,7 @@ pub fn (mut m NameManager) update_record(name_id u32, record_name string, catego
} }
// get_records returns all records of a name // get_records returns all records of a name
pub fn (mut m NameManager) get_records(name_id u32) ![]Record { pub fn (mut m NameDB) get_records(name_id u32) ![]Record {
// Get the name by ID // Get the name by ID
name := m.get(name_id)! name := m.get(name_id)!
@@ -153,7 +154,7 @@ pub fn (mut m NameManager) get_records(name_id u32) ![]Record {
} }
// get_records_by_category returns all records of a name with a specific category // get_records_by_category returns all records of a name with a specific category
pub fn (mut m NameManager) get_records_by_category(name_id u32, category RecordType) ![]Record { pub fn (mut m NameDB) get_records_by_category(name_id u32, category RecordType) ![]Record {
// Get the name by ID // Get the name by ID
name := m.get(name_id)! name := m.get(name_id)!
@@ -170,7 +171,7 @@ pub fn (mut m NameManager) get_records_by_category(name_id u32, category RecordT
} }
// add_admin adds an admin to a name // add_admin adds an admin to a name
pub fn (mut m NameManager) add_admin(name_id u32, pubkey string) !Name { pub fn (mut m NameDB) add_admin(name_id u32, pubkey string) !Name {
// Get the name by ID // Get the name by ID
mut name := m.get(name_id)! mut name := m.get(name_id)!
@@ -189,7 +190,7 @@ pub fn (mut m NameManager) add_admin(name_id u32, pubkey string) !Name {
} }
// remove_admin removes an admin from a name // remove_admin removes an admin from a name
pub fn (mut m NameManager) remove_admin(name_id u32, pubkey string) !Name { pub fn (mut m NameDB) remove_admin(name_id u32, pubkey string) !Name {
// Get the name by ID // Get the name by ID
mut name := m.get(name_id)! mut name := m.get(name_id)!
@@ -222,7 +223,7 @@ pub fn (mut m NameManager) remove_admin(name_id u32, pubkey string) !Name {
} }
// play processes heroscript commands for names // play processes heroscript commands for names
pub fn (mut m NameManager) play(mut plbook playbook.PlayBook) ! { pub fn (mut m NameDB) play(mut plbook playbook.PlayBook) ! {
// Find all actions that start with 'name.' // Find all actions that start with 'name.'
name_actions := plbook.actions_find(actor: 'name')! name_actions := plbook.actions_find(actor: 'name')!
if name_actions.len == 0 { if name_actions.len == 0 {

View File

@@ -3,7 +3,7 @@ module core
import os import os
import rand import rand
fn test_name_manager() { fn test_name_db() {
// Create a temporary directory for testing // Create a temporary directory for testing
test_dir := os.join_path(os.temp_dir(), 'hero_name_test_${rand.intn(9000) or { 0 } + 1000}') test_dir := os.join_path(os.temp_dir(), 'hero_name_test_${rand.intn(9000) or { 0 } + 1000}')
os.mkdir_all(test_dir) or { panic(err) } os.mkdir_all(test_dir) or { panic(err) }

View File

@@ -122,15 +122,14 @@ pub fn (mut d Decoder) get_i64() !i64 {
} }
pub fn (mut d Decoder) get_time() !time.Time { pub fn (mut d Decoder) get_time() !time.Time {
nano_time := d.get_i64()! secs_:=d.get_u32()!
seconds := nano_time / int(1e9) secs := i64(secs_)
nano_seconds := int(nano_time % int(1e9)) return time.unix(secs)
return time.unix_nanosecond(seconds, nano_seconds)
} }
pub fn (mut d Decoder) get_ourtime() !ourtime.OurTime { pub fn (mut d Decoder) get_ourtime() !ourtime.OurTime {
return ourtime.OurTime{ return ourtime.OurTime{
unixt: d.get_i64()! unixt: d.get_u32()!
} }
} }

View File

@@ -86,11 +86,11 @@ pub fn (mut b Encoder) add_i64(data i64) {
} }
pub fn (mut b Encoder) add_time(data time.Time) { pub fn (mut b Encoder) add_time(data time.Time) {
b.add_u64(u64(data.unix_nano())) // add as epoch time b.add_u32(u32(data.unix())) // add as epoch time
} }
pub fn (mut b Encoder) add_ourtime(data ourtime.OurTime) { pub fn (mut b Encoder) add_ourtime(data ourtime.OurTime) {
b.add_i64(data.unixt) b.add_u32(u32(data.unixt))
} }
pub fn (mut b Encoder) add_list_string(data []string) { pub fn (mut b Encoder) add_list_string(data []string) {

View File

@@ -1,7 +1,7 @@
module radixtree module radixtree
import freeflowuniverse.herolib.data.ourdb import freeflowuniverse.herolib.data.ourdb
import freeflowuniverse.herolib.ui.console // import freeflowuniverse.herolib.ui.console
// Represents a node in the radix tree // Represents a node in the radix tree
struct Node { struct Node {
@@ -34,7 +34,7 @@ pub mut:
} }
// Creates a new radix tree with the specified database path // Creates a new radix tree with the specified database path
pub fn new(args NewArgs) !&RadixTree { pub fn new(args NewArgs) !RadixTree {
mut db := ourdb.new( mut db := ourdb.new(
path: args.path path: args.path
record_size_max: 1024 * 4 // 4KB max record size record_size_max: 1024 * 4 // 4KB max record size
@@ -58,11 +58,12 @@ pub fn new(args NewArgs) !&RadixTree {
} else { } else {
//console.print_debug('Debug: Using existing root node') //console.print_debug('Debug: Using existing root node')
root_data := db.get(1)! // Get root node with ID 1 root_data := db.get(1)! // Get root node with ID 1
root_node := deserialize_node(root_data)! // root_node :=
deserialize_node(root_data)!
//console.print_debug('Debug: Root node has ${root_node.children.len} children') //console.print_debug('Debug: Root node has ${root_node.children.len} children')
} }
return &RadixTree{ return RadixTree{
db: &db db: &db
root_id: root_id root_id: root_id
} }
@@ -128,7 +129,7 @@ pub fn (mut rt RadixTree) set(key string, value []u8) ! {
// First verify we can deserialize the data correctly // First verify we can deserialize the data correctly
//console.print_debug('Debug: Verifying serialization...') //console.print_debug('Debug: Verifying serialization...')
if test_node := deserialize_node(parent_data) { if _ := deserialize_node(parent_data) {
//console.print_debug('Debug: Serialization test successful - node has ${test_node.children.len} children') //console.print_debug('Debug: Serialization test successful - node has ${test_node.children.len} children')
} else { } else {
//console.print_debug('Debug: ERROR - Failed to deserialize test data') //console.print_debug('Debug: ERROR - Failed to deserialize test data')