sx-http: remove server-side fragment extraction — client handles sx-select
Server always returns full page. Client sx-select handles extraction. No application logic in OCaml server. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -2085,7 +2085,7 @@ let http_mode port =
|
|||||||
let n_workers = max 2 (Domain.recommended_domain_count ()) in
|
let n_workers = max 2 (Domain.recommended_domain_count ()) in
|
||||||
|
|
||||||
(* Render queue: for cache misses that need full page render *)
|
(* Render queue: for cache misses that need full page render *)
|
||||||
let render_queue : (Unix.file_descr * string * bool) list ref = ref [] in
|
let render_queue : (Unix.file_descr * string) list ref = ref [] in
|
||||||
let render_mutex = Mutex.create () in
|
let render_mutex = Mutex.create () in
|
||||||
let render_cond = Condition.create () in
|
let render_cond = Condition.create () in
|
||||||
let shutdown = ref false in
|
let shutdown = ref false in
|
||||||
@@ -2106,64 +2106,14 @@ let http_mode port =
|
|||||||
w
|
w
|
||||||
in
|
in
|
||||||
match work with
|
match work with
|
||||||
| Some (fd, path, is_ajax) ->
|
| Some (fd, path) ->
|
||||||
let response =
|
let response =
|
||||||
try
|
try
|
||||||
match http_render_page env path with
|
match http_render_page env path with
|
||||||
| Some html ->
|
| Some html ->
|
||||||
if is_ajax then begin
|
let resp = http_response html in
|
||||||
(* Extract #main-panel fragment for AJAX *)
|
Hashtbl.replace response_cache path resp;
|
||||||
let panel_start = try
|
resp
|
||||||
let idx = ref 0 in
|
|
||||||
let found = ref false in
|
|
||||||
while not !found && !idx < String.length html - 20 do
|
|
||||||
if String.sub html !idx 18 = "id=\"main-panel\"" then found := true
|
|
||||||
else idx := !idx + 1
|
|
||||||
done;
|
|
||||||
if !found then begin
|
|
||||||
let start = ref !idx in
|
|
||||||
while !start > 0 && html.[!start] <> '<' do start := !start - 1 done;
|
|
||||||
Some !start
|
|
||||||
end else None
|
|
||||||
with _ -> None in
|
|
||||||
match panel_start with
|
|
||||||
| Some start ->
|
|
||||||
(* Find the tag name (section, div, etc.) *)
|
|
||||||
let tag_end = ref (start + 1) in
|
|
||||||
while !tag_end < String.length html && html.[!tag_end] <> ' ' && html.[!tag_end] <> '>' do
|
|
||||||
tag_end := !tag_end + 1
|
|
||||||
done;
|
|
||||||
let tag = String.sub html (start + 1) (!tag_end - start - 1) in
|
|
||||||
(* Find matching close tag by counting depth *)
|
|
||||||
let open_tag = "<" ^ tag in
|
|
||||||
let close_tag = "</" ^ tag ^ ">" in
|
|
||||||
let depth = ref 1 in
|
|
||||||
let pos = ref (!tag_end) in
|
|
||||||
let found_end = ref (String.length html) in
|
|
||||||
while !depth > 0 && !pos < String.length html - String.length close_tag do
|
|
||||||
if String.sub html !pos (String.length close_tag) = close_tag then begin
|
|
||||||
depth := !depth - 1;
|
|
||||||
if !depth = 0 then
|
|
||||||
found_end := !pos + String.length close_tag
|
|
||||||
else
|
|
||||||
pos := !pos + 1
|
|
||||||
end else if !pos + String.length open_tag < String.length html
|
|
||||||
&& String.sub html !pos (String.length open_tag) = open_tag
|
|
||||||
&& (html.[!pos + String.length open_tag] = ' '
|
|
||||||
|| html.[!pos + String.length open_tag] = '>') then begin
|
|
||||||
depth := !depth + 1;
|
|
||||||
pos := !pos + 1
|
|
||||||
end else
|
|
||||||
pos := !pos + 1
|
|
||||||
done;
|
|
||||||
let fragment = String.sub html start (!found_end - start) in
|
|
||||||
http_response ~content_type:"text/html; charset=utf-8" fragment
|
|
||||||
| None -> http_response html
|
|
||||||
end else begin
|
|
||||||
let resp = http_response html in
|
|
||||||
Hashtbl.replace response_cache path resp;
|
|
||||||
resp
|
|
||||||
end
|
|
||||||
| None -> http_response ~status:404 "<h1>Not Found</h1>"
|
| None -> http_response ~status:404 "<h1>Not Found</h1>"
|
||||||
with e ->
|
with e ->
|
||||||
Printf.eprintf "[render] Error for %s: %s\n%!" path (Printexc.to_string e);
|
Printf.eprintf "[render] Error for %s: %s\n%!" path (Printexc.to_string e);
|
||||||
@@ -2176,7 +2126,7 @@ let http_mode port =
|
|||||||
|
|
||||||
(* Fast path: handle a request from the main loop.
|
(* Fast path: handle a request from the main loop.
|
||||||
Returns true if handled immediately (cached), false if queued. *)
|
Returns true if handled immediately (cached), false if queued. *)
|
||||||
let fast_handle fd data is_ajax =
|
let fast_handle fd data _is_ajax =
|
||||||
match parse_http_request data with
|
match parse_http_request data with
|
||||||
| None -> write_response fd (http_response ~status:400 "Bad Request"); true
|
| None -> write_response fd (http_response ~status:400 "Bad Request"); true
|
||||||
| Some (method_, raw_path) ->
|
| Some (method_, raw_path) ->
|
||||||
@@ -2190,25 +2140,15 @@ let http_mode port =
|
|||||||
let is_sx = path = "/sx/" || path = "/sx"
|
let is_sx = path = "/sx/" || path = "/sx"
|
||||||
|| (String.length path > 4 && String.sub path 0 4 = "/sx/") in
|
|| (String.length path > 4 && String.sub path 0 4 = "/sx/") in
|
||||||
if is_sx then begin
|
if is_sx then begin
|
||||||
if not is_ajax then
|
(* Serve from cache (full page) — client handles sx-select extraction *)
|
||||||
(* Check cache — instant response *)
|
match Hashtbl.find_opt response_cache path with
|
||||||
match Hashtbl.find_opt response_cache path with
|
| Some cached -> write_response fd cached; true
|
||||||
| Some cached -> write_response fd cached; true
|
| None ->
|
||||||
| None ->
|
|
||||||
(* Queue for render worker *)
|
|
||||||
Mutex.lock render_mutex;
|
|
||||||
render_queue := !render_queue @ [(fd, path, false)];
|
|
||||||
Condition.signal render_cond;
|
|
||||||
Mutex.unlock render_mutex;
|
|
||||||
false
|
|
||||||
else begin
|
|
||||||
(* AJAX always renders fresh (no cache for fragments) *)
|
|
||||||
Mutex.lock render_mutex;
|
Mutex.lock render_mutex;
|
||||||
render_queue := !render_queue @ [(fd, path, true)];
|
render_queue := !render_queue @ [(fd, path)];
|
||||||
Condition.signal render_cond;
|
Condition.signal render_cond;
|
||||||
Mutex.unlock render_mutex;
|
Mutex.unlock render_mutex;
|
||||||
false
|
false
|
||||||
end
|
|
||||||
end else if String.length path > 8 && String.sub path 0 8 = "/static/" then begin
|
end else if String.length path > 8 && String.sub path 0 8 = "/static/" then begin
|
||||||
write_response fd (serve_static_file static_dir path); true
|
write_response fd (serve_static_file static_dir path); true
|
||||||
end else begin
|
end else begin
|
||||||
|
|||||||
Reference in New Issue
Block a user