@@ -67,6 +67,7 @@ client: *Http.Client,
6767allocator : Allocator ,
6868buffer_pool : BufferPool ,
6969script_pool : std .heap .MemoryPool (PendingScript ),
70+ async_module_pool : std .heap .MemoryPool (AsyncModule ),
7071
7172const OrderList = std .DoublyLinkedList ;
7273
@@ -85,13 +86,15 @@ pub fn init(browser: *Browser, page: *Page) ScriptManager {
8586 .static_scripts_done = false ,
8687 .buffer_pool = BufferPool .init (allocator , 5 ),
8788 .script_pool = std .heap .MemoryPool (PendingScript ).init (allocator ),
89+ .async_module_pool = std .heap .MemoryPool (AsyncModule ).init (allocator ),
8890 };
8991}
9092
9193pub fn deinit (self : * ScriptManager ) void {
9294 self .reset ();
9395 self .buffer_pool .deinit ();
9496 self .script_pool .deinit ();
97+ self .async_module_pool .deinit ();
9598}
9699
97100pub fn reset (self : * ScriptManager ) void {
@@ -256,7 +259,7 @@ pub fn addFromElement(self: *ScriptManager, element: *parser.Element) !void {
256259// Unlike external modules which can only ever be executed after releasing an
257260// http handle, these are executed without there necessarily being a free handle.
258261// Thus, Http/Client.zig maintains a dedicated handle for these calls.
259- pub fn blockingGet (self : * ScriptManager , url : [:0 ]const u8 ) ! BlockingResult {
262+ pub fn blockingGet (self : * ScriptManager , url : [:0 ]const u8 ) ! GetResult {
260263 std .debug .assert (self .is_blocking == false );
261264
262265 self .is_blocking = true ;
@@ -302,6 +305,34 @@ pub fn blockingGet(self: *ScriptManager, url: [:0]const u8) !BlockingResult {
302305 }
303306}
304307
308+ pub fn getAsyncModule (self : * ScriptManager , url : [:0 ]const u8 , cb : AsyncModule.Callback , cb_data : * anyopaque ) ! void {
309+ const async = try self .async_module_pool .create ();
310+ errdefer self .async_module_pool .destroy (async );
311+
312+ async .* = .{
313+ .cb = cb ,
314+ .manager = self ,
315+ .cb_data = cb_data ,
316+ };
317+
318+ var headers = try self .client .newHeaders ();
319+ try self .page .requestCookie (.{}).headersForRequest (self .page .arena , url , & headers );
320+
321+ try self .client .request (.{
322+ .url = url ,
323+ .method = .GET ,
324+ .headers = headers ,
325+ .cookie_jar = self .page .cookie_jar ,
326+ .ctx = async ,
327+ .resource_type = .script ,
328+ .start_callback = if (log .enabled (.http , .debug )) AsyncModule .startCallback else null ,
329+ .header_callback = AsyncModule .headerCallback ,
330+ .data_callback = AsyncModule .dataCallback ,
331+ .done_callback = AsyncModule .doneCallback ,
332+ .error_callback = AsyncModule .errorCallback ,
333+ });
334+ }
335+
305336pub fn staticScriptsDone (self : * ScriptManager ) void {
306337 std .debug .assert (self .static_scripts_done == false );
307338 self .static_scripts_done = true ;
@@ -594,7 +625,7 @@ const Script = struct {
594625 .javascript = > _ = js_context .eval (content , url ) catch break :blk false ,
595626 .module = > {
596627 // We don't care about waiting for the evaluation here.
597- _ = js_context .module (content , url , cacheable ) catch break :blk false ;
628+ js_context .module (false , content , url , cacheable ) catch break :blk false ;
598629 },
599630 }
600631 break :blk true ;
@@ -760,7 +791,7 @@ const Blocking = struct {
760791 const State = union (enum ) {
761792 running : void ,
762793 err : anyerror ,
763- done : BlockingResult ,
794+ done : GetResult ,
764795 };
765796
766797 fn startCallback (transfer : * Http.Transfer ) ! void {
@@ -814,19 +845,93 @@ const Blocking = struct {
814845 fn errorCallback (ctx : * anyopaque , err : anyerror ) void {
815846 var self : * Blocking = @ptrCast (@alignCast (ctx ));
816847 self .state = .{ .err = err };
817- self .buffer_pool .release (self .buffer );
848+ if (self .buffer .items .len > 0 ) {
849+ self .buffer_pool .release (self .buffer );
850+ }
851+ }
852+ };
853+
854+ pub const AsyncModule = struct {
855+ cb : Callback ,
856+ cb_data : * anyopaque ,
857+ manager : * ScriptManager ,
858+ buffer : std .ArrayListUnmanaged (u8 ) = .{},
859+
860+ pub const Callback = * const fn (ptr : * anyopaque , result : anyerror ! GetResult ) void ;
861+
862+ fn startCallback (transfer : * Http.Transfer ) ! void {
863+ log .debug (.http , "script fetch start" , .{ .req = transfer , .async = true });
864+ }
865+
866+ fn headerCallback (transfer : * Http.Transfer ) ! void {
867+ const header = & transfer .response_header .? ;
868+ log .debug (.http , "script header" , .{
869+ .req = transfer ,
870+ .async = true ,
871+ .status = header .status ,
872+ .content_type = header .contentType (),
873+ });
874+
875+ if (header .status != 200 ) {
876+ return error .InvalidStatusCode ;
877+ }
878+
879+ var self : * AsyncModule = @ptrCast (@alignCast (transfer .ctx ));
880+ self .buffer = self .manager .buffer_pool .get ();
881+ }
882+
883+ fn dataCallback (transfer : * Http.Transfer , data : []const u8 ) ! void {
884+ // too verbose
885+ // log.debug(.http, "script data chunk", .{
886+ // .req = transfer,
887+ // .blocking = true,
888+ // });
889+
890+ var self : * AsyncModule = @ptrCast (@alignCast (transfer .ctx ));
891+ self .buffer .appendSlice (self .manager .allocator , data ) catch | err | {
892+ log .err (.http , "SM.dataCallback" , .{
893+ .err = err ,
894+ .len = data .len ,
895+ .ascyn = true ,
896+ .transfer = transfer ,
897+ });
898+ return err ;
899+ };
900+ }
901+
902+ fn doneCallback (ctx : * anyopaque ) ! void {
903+ var self : * AsyncModule = @ptrCast (@alignCast (ctx ));
904+ defer self .manager .async_module_pool .destroy (self );
905+ self .cb (self .cb_data , .{
906+ .buffer = self .buffer ,
907+ .buffer_pool = & self .manager .buffer_pool ,
908+ });
909+ }
910+
911+ fn errorCallback (ctx : * anyopaque , err : anyerror ) void {
912+ var self : * AsyncModule = @ptrCast (@alignCast (ctx ));
913+
914+ if (err != error .Abort ) {
915+ self .cb (self .cb_data , err );
916+ }
917+
918+ if (self .buffer .items .len > 0 ) {
919+ self .manager .buffer_pool .release (self .buffer );
920+ }
921+
922+ self .manager .async_module_pool .destroy (self );
818923 }
819924};
820925
821- pub const BlockingResult = struct {
926+ pub const GetResult = struct {
822927 buffer : std .ArrayListUnmanaged (u8 ),
823928 buffer_pool : * BufferPool ,
824929
825- pub fn deinit (self : * BlockingResult ) void {
930+ pub fn deinit (self : * GetResult ) void {
826931 self .buffer_pool .release (self .buffer );
827932 }
828933
829- pub fn src (self : * const BlockingResult ) []const u8 {
934+ pub fn src (self : * const GetResult ) []const u8 {
830935 return self .buffer .items ;
831936 }
832937};
0 commit comments