POST /api/index — body: {"root_path": "/abs/path", "project_name": "..."} */
| 1146 | |
| 1147 | /* POST /api/index — body: {"root_path": "/abs/path", "project_name": "..."} */ |
| 1148 | static void handle_index_start(cbm_http_conn_t *c, const cbm_http_req_t *req) { |
| 1149 | if (req->body_len == 0 || req->body_len > 4096) { |
| 1150 | cbm_http_replyf(c, 400, g_cors_json, "{\"error\":\"invalid body\"}"); |
| 1151 | return; |
| 1152 | } |
| 1153 | |
| 1154 | yyjson_doc *doc = yyjson_read(req->body, req->body_len, 0); |
| 1155 | if (!doc) { |
| 1156 | cbm_http_replyf(c, 400, g_cors_json, "{\"error\":\"invalid json\"}"); |
| 1157 | return; |
| 1158 | } |
| 1159 | yyjson_val *root = yyjson_doc_get_root(doc); |
| 1160 | yyjson_val *v_path = yyjson_obj_get(root, "root_path"); |
| 1161 | if (!v_path || !yyjson_is_str(v_path)) { |
| 1162 | yyjson_doc_free(doc); |
| 1163 | cbm_http_replyf(c, 400, g_cors_json, "{\"error\":\"missing root_path\"}"); |
| 1164 | return; |
| 1165 | } |
| 1166 | const char *rpath = yyjson_get_str(v_path); |
| 1167 | yyjson_val *v_project_name = yyjson_obj_get(root, "project_name"); |
| 1168 | const char *project_name = yyjson_is_str(v_project_name) ? yyjson_get_str(v_project_name) : ""; |
| 1169 | |
| 1170 | /* Check path exists */ |
| 1171 | if (!cbm_is_dir(rpath)) { |
| 1172 | yyjson_doc_free(doc); |
| 1173 | cbm_http_replyf(c, 400, g_cors_json, "{\"error\":\"directory not found\"}"); |
| 1174 | return; |
| 1175 | } |
| 1176 | |
| 1177 | /* Find free job slot */ |
| 1178 | int slot = -1; |
| 1179 | for (int i = 0; i < MAX_INDEX_JOBS; i++) { |
| 1180 | int st = atomic_load(&g_index_jobs[i].status); |
| 1181 | if (st == 0 || st == 2 || st == 3) { |
| 1182 | slot = i; |
| 1183 | break; |
| 1184 | } |
| 1185 | } |
| 1186 | if (slot < 0) { |
| 1187 | yyjson_doc_free(doc); |
| 1188 | cbm_http_replyf(c, 429, g_cors_json, "{\"error\":\"all index slots busy\"}"); |
| 1189 | return; |
| 1190 | } |
| 1191 | |
| 1192 | index_job_t *job = &g_index_jobs[slot]; |
| 1193 | snprintf(job->root_path, sizeof(job->root_path), "%s", rpath); |
| 1194 | snprintf(job->project_name, sizeof(job->project_name), "%s", project_name); |
| 1195 | job->error_msg[0] = '\0'; |
| 1196 | atomic_store(&job->status, 1); |
| 1197 | yyjson_doc_free(doc); |
| 1198 | |
| 1199 | /* Spawn background thread */ |
| 1200 | cbm_thread_t tid; |
| 1201 | if (cbm_thread_create(&tid, 0, index_thread_fn, job) != 0) { |
| 1202 | atomic_store(&job->status, 3); |
| 1203 | snprintf(job->error_msg, sizeof(job->error_msg), "thread creation failed"); |
| 1204 | cbm_http_replyf(c, 500, g_cors_json, "{\"error\":\"thread creation failed\"}"); |
| 1205 | return; |
no test coverage detected