| 1945 | } |
| 1946 | |
| 1947 | cbm_http_server_t *cbm_http_server_new(int port) { |
| 1948 | cbm_http_server_t *srv = calloc(1, sizeof(*srv)); |
| 1949 | if (!srv) |
| 1950 | return NULL; |
| 1951 | |
| 1952 | srv->port = port; |
| 1953 | atomic_init(&srv->stop_flag, 0); |
| 1954 | atomic_init(&srv->run_state, HTTP_RUN_IDLE); |
| 1955 | |
| 1956 | /* Create a dedicated MCP server for HTTP (own SQLite connection) */ |
| 1957 | srv->mcp = cbm_mcp_server_new(NULL); |
| 1958 | if (!srv->mcp) { |
| 1959 | cbm_log_error("ui.http.mcp_fail", "reason", "cannot create MCP instance"); |
| 1960 | free(srv); |
| 1961 | return NULL; |
| 1962 | } |
| 1963 | cbm_mcp_server_set_background_tasks(srv->mcp, false); |
| 1964 | cbm_mcp_server_set_index_executor(srv->mcp, http_read_only_index_rejected, srv); |
| 1965 | |
| 1966 | /* Bind to localhost only (httpd refuses anything else by construction) */ |
| 1967 | srv->listener = cbm_httpd_listen(port); |
| 1968 | if (!srv->listener) { |
| 1969 | char port_str[16]; |
| 1970 | snprintf(port_str, sizeof(port_str), "%d", port); |
| 1971 | cbm_log_warn("ui.unavailable", "port", port_str, "reason", "in_use", "hint", |
| 1972 | "use --port=N to override"); |
| 1973 | cbm_mcp_server_free(srv->mcp); |
| 1974 | free(srv); |
| 1975 | return NULL; |
| 1976 | } |
| 1977 | |
| 1978 | srv->port = cbm_httpd_port(srv->listener); |
| 1979 | srv->listener_ok = true; |
| 1980 | |
| 1981 | char port_str[16]; |
| 1982 | snprintf(port_str, sizeof(port_str), "%d", srv->port); |
| 1983 | char url[64]; |
| 1984 | snprintf(url, sizeof(url), "http://127.0.0.1:%d", srv->port); |
| 1985 | cbm_log_info("ui.serving", "url", url, "port", port_str); |
| 1986 | |
| 1987 | return srv; |
| 1988 | } |
| 1989 | |
| 1990 | bool cbm_http_server_free(cbm_http_server_t *srv) { |
| 1991 | if (!srv) |