| 579 | } |
| 580 | |
| 581 | static bool host_state_prepare(host_state_t *host, const cbm_daemon_ipc_endpoint_t *endpoint) { |
| 582 | host->http_ops = &g_host_http_default_ops; |
| 583 | host->http_assets_available = CBM_EMBEDDED_FILE_COUNT > 0; |
| 584 | if (!cbm_secure_random(host->ui_readiness_secret, sizeof(host->ui_readiness_secret))) { |
| 585 | cbm_log_error("daemon.readiness_secret_failed", "reason", "system_rng_unavailable"); |
| 586 | return false; |
| 587 | } |
| 588 | size_t aggregate_memory_budget_bytes = cbm_mem_budget(); |
| 589 | const char *cache = cbm_resolve_cache_dir(); |
| 590 | if (!cache || !cache[0]) { |
| 591 | cbm_log_error("daemon.runtime_config_open_failed", "reason", "cache_dir_unavailable"); |
| 592 | return false; |
| 593 | } |
| 594 | host->runtime_config = cbm_config_open(cache); |
| 595 | if (!host->runtime_config) { |
| 596 | cbm_log_error("daemon.runtime_config_open_failed", "reason", "config_db_unavailable"); |
| 597 | return false; |
| 598 | } |
| 599 | host->project_locks = cbm_project_lock_manager_new(endpoint); |
| 600 | /* #335: watcher_enabled (default true) is the master switch for the |
| 601 | * background watcher. When false the daemon never builds the watcher or the |
| 602 | * in-memory store backing it, so the poll thread never starts |
| 603 | * (host_background_start has nothing to run) and no project ever registers |
| 604 | * (register_watcher_if_enabled early-returns on a NULL watcher). The daemon |
| 605 | * still starts and still owns everything else: IPC, HTTP/UI, project locks, |
| 606 | * and manual index_repository. Read once here at daemon startup, so a change |
| 607 | * takes effect when the daemon next starts — see docs/CONFIGURATION.md. */ |
| 608 | bool watcher_enabled = cbm_config_watcher_enabled(host->runtime_config); |
| 609 | if (watcher_enabled) { |
| 610 | host->watch_store = cbm_store_open_memory(); |
| 611 | host->watcher = cbm_watcher_new(host->watch_store, host_watcher_index, host); |
| 612 | } else { |
| 613 | cbm_log_info("watcher.disabled", "reason", "config"); |
| 614 | } |
| 615 | cbm_daemon_application_config_t application_config = { |
| 616 | .watcher = host->watcher, |
| 617 | .config = host->runtime_config, |
| 618 | .aggregate_memory_budget_bytes = aggregate_memory_budget_bytes, |
| 619 | .project_locks = host->project_locks, |
| 620 | .ui_readiness_secret = host->ui_readiness_secret, |
| 621 | .ui_readiness_secret_length = sizeof(host->ui_readiness_secret), |
| 622 | }; |
| 623 | host->application = cbm_daemon_application_new(&application_config); |
| 624 | if (host->application && host->permanent) { |
| 625 | cbm_daemon_application_set_permanent(host->application, true); |
| 626 | } |
| 627 | if (!host->project_locks || !host->application) { |
| 628 | return false; |
| 629 | } |
| 630 | /* A watcher deliberately left unbuilt by watcher_enabled=false is not a |
| 631 | * startup failure; an allocation failure while it is enabled still is. */ |
| 632 | if (watcher_enabled && (!host->watch_store || !host->watcher)) { |
| 633 | return false; |
| 634 | } |
| 635 | return true; |
| 636 | } |
| 637 | |
| 638 | bool cbm_daemon_host_state_prepare_for_test(const cbm_daemon_ipc_endpoint_t *endpoint) { |
no test coverage detected