char/avril
(wip) why'd you have to go and make things so complicaaaaated?
git clone https://git.t4t.associates/char/avril
6534c3e
main
1use std:: cell:: RefCell ; 2use std:: future:: Future ; 3use std:: rc:: Rc ; 4use std:: sync:: Arc ; 5use std:: sync:: atomic:: Ordering ; 6use std:: task:: Poll ; 7use std:: time:: Duration ; 8 9use avril_caps:: Capabilities ; 10use avril_core::{ Extension , ModuleLoader , Runtime , RuntimeOptions , Snapshot }; 11use avril_ext_workers::{ Control , WorkerScope }; 12use avril_host:: environment:: Environment ; 13use avril_host:: messaging::{ Broker , Endpoint }; 14use futures:: future::{ Either , select}; 15use tokio_util:: sync:: CancellationToken ; 16 17use crate :: modules:: ModuleGraph ; 18use crate :: registry:: PackageStore ; 19 20mod snapshots; 21pub use snapshots:: createas create_snapshot; 22 23# [ cfg ( test )] 24mod tests; 25 26# [ derive ( Clone )] 27pub struct Settings { 28pub snapshot : Option < Arc < Snapshot >>, 29pub storage : avril_webstorage:: Persistent , 30pub caps : Arc < Capabilities >, 31pub environment : Environment , 32pub args : Vec < String >, 33pub store : Arc < PackageStore >, 34pub runtime : tokio:: runtime:: Handle , 35pub broker : Arc < Broker >, 36pub process_signal : avril_ext_process:: SignalMode , 37} 38 39pub fn runtime ( 40graph : Rc < ModuleGraph >, 41settings : Settings , 42stdio : Rc < avril_ext_stdio:: Stdio >, 43listener : Option < avril_http:: Address >, 44test : Option < avril_ext_test:: Shared >, 45) ->Result < Runtime , Box < dyn std:: error:: Error >> { 46create_runtime ( graph, settings, stdio, None , listener, test) 47} 48 49fn create_runtime ( 50graph : Rc < ModuleGraph >, 51settings : Settings , 52stdio : Rc < avril_ext_stdio:: Stdio >, 53worker : Option < WorkerScope >, 54listener : Option < avril_http:: Address >, 55test : Option < avril_ext_test:: Shared >, 56) ->Result < Runtime , Box < dyn std:: error:: Error >> { 57let snapshot = settings. snapshot . clone (); 58let extensions =extensions ( graph. clone (), settings, stdio, worker, listener, test) ?; 59let options =RuntimeOptions { 60 extensions, 61module_loader : Some ( graph), 62}; 63let mut runtime =match snapshot. as_deref () { 64Some ( snapshot) =>Runtime :: from_snapshot ( options, snapshot) ?, 65None =>Runtime :: new ( options) ?, 66}; 67crate :: stdlib:: register ( & mut runtime) ?; 68Ok ( runtime) 69} 70 71fn extensions ( 72graph : Rc < ModuleGraph >, 73settings : Settings , 74stdio : Rc < avril_ext_stdio:: Stdio >, 75worker : Option < WorkerScope >, 76listener : Option < avril_http:: Address >, 77test : Option < avril_ext_test:: Shared >, 78) ->Result < Vec < Extension >, Box < dyn std:: error:: Error >> { 79let environment =Rc :: new ( RefCell :: new ( settings. environment . clone ())); 80// Outside `avril test`, `test()` registers harmlessly and never runs. 81let test = test. unwrap_or_else ( || avril_ext_test:: idle ( & stdio)); 82let ( websocket, sockets) = 83 avril_ext_websocket:: init ( settings. runtime . clone (), settings. caps . clone ()) ?; 84let ( file, files) = avril_ext_file:: init ( 85 settings. runtime . clone (), 86 settings. caps . clone (), 87 stdio. interrupt_flag (), 88); 89let top_level = worker. is_none (); 90let mut extensions =vec! [ 91 avril_ext_web:: with_broker ( settings. broker . clone ()), 92 avril_ext_timers:: init () ?, 93 avril_ext_url:: init (), 94 avril_ext_urlpattern:: init (), 95 avril_ext_webstreams:: init (), 96 avril_compression:: init (), 97 avril_webcrypto:: init (), 98 avril_ext_fjson:: init (), 99 avril_ext_kv:: init ( settings. runtime . clone (), settings. caps . clone ()), 100 avril_ext_task:: init (), 101 avril_ffi:: init ( settings. caps . clone ()), 102 avril_ext_encoding:: init (), 103 avril_ext_blob:: init (), 104 avril_ext_form_data:: init (), 105 avril_ext_http_types:: init (), 106 avril_ext_fetch:: init ( 107 settings. runtime . clone (), 108 settings. caps . clone (), 109 graph. entry_url (), 110), 111 avril_ext_net:: init ( settings. runtime . clone (), settings. caps . clone ()), 112 avril_ext_http:: init ( 113 settings. runtime . clone (), 114 settings. caps . clone (), 115 sockets, 116 files. clone (), 117 listener, 118), 119 websocket, 120 avril_ext_wasmstreaming:: init (), 121 avril_ext_structured_clone:: init (), 122 file, 123 avril_ext_process:: init ( 124 settings. runtime . clone (), 125 settings. caps . clone (), 126 environment. clone (), 127 files, 128 worker 129. as_ref () 130. map_or_else ( CancellationToken :: new, |worker|{ 131 worker. control . process_cancellation () 132}), 133 worker. is_some (), 134 settings. process_signal , 135), 136 stdio. extension (), 137 avril_ext_test:: init ( test), 138 avril_ext_base:: init ( 139 settings. caps . clone (), 140 environment. clone (), 141 settings. args . clone (), 142), 143 avril_ext_console:: init ( stdio), 144 avril_ext_path:: init (), 145 avril_ext_workers:: init ( 146move || graph. entry_url (), 147 settings. caps . clone (), 148 settings. broker . clone (), 149Arc :: new ( settings. clone ()), 150 environment, 151 worker, 152), 153]; 154// Web Storage is a top-level-only API; worker runtimes omit it entirely. 155if top_level{ 156 extensions. push ( avril_webstorage:: init ( settings. storage . clone ())); 157} 158Ok ( extensions) 159} 160 161impl avril_ext_workers:: Launch for Settings { 162fn run ( 163& self , 164request : avril_ext_workers:: Request , 165control : Arc < Control >, 166inbox : Arc < Endpoint >, 167) ->Result <(), Box < dyn std:: error:: Error >> { 168let mut settings =self . clone (); 169 settings. caps = request. caps ; 170 settings. environment = request. environment ; 171let specifier = request. specifier ; 172let referrer = request. referrer ; 173let name = request. name ; 174let authority = avril_runtime:: authority:: SourceAuthority :: execute ( settings. caps . clone ()); 175let graph =Rc :: new ( ModuleGraph :: open_shared ( authority, settings. store . clone ())); 176let host = settings. runtime . clone (); 177let entry = host. block_on ( async { 178match select ( 179Box :: pin ( graph. prepare ( specifier, referrer)), 180Box :: pin ( control. cancelled ()), 181) 182. await 183{ 184Either :: Left (( entry, _)) => entry. map ( Some ), 185Either :: Right ( _) =>Ok ( None ), 186} 187}) ?; 188let Some ( entry) = entryelse { 189return Ok (()); 190}; 191 graph. set_entry ( & entry); 192let url = 193 avril_core:: ModuleLoader :: module_url ( &* graph, & entry). unwrap_or_else ( || entry. clone ()); 194let terminated = control. termination_flag (); 195let stdio = avril_ext_stdio:: Stdio :: new_for_worker ( terminated. clone ()) ?; 196let mut runtime =create_runtime ( 197 graph, 198 settings, 199 stdio. clone (), 200Some ( WorkerScope { 201control : control. clone (), 202 inbox, 203 url, 204 name, 205}), 206None , 207None , 208) ?; 209 control. set_isolate ( Some ( runtime. isolate_handle ())); 210let result = runtime. start_module ( & entry). and_then ( |() |{ 211let mut background_delay =None ; 212 host. block_on ( futures:: future:: poll_fn ( |cx|{ 213 control. register_waker ( cx. waker ()); 214if control. is_stopped () { 215return Poll :: Ready ( Ok (())); 216} 217let background_pending = runtime. has_pending_background_tasks (); 218if let Err ( error) = runtime. poll_event_loop ( cx) { 219return Poll :: Ready ( Err ( error)); 220} 221// The default V8 platform does not notify the host about foreground tasks. 222if background_pending || runtime. has_pending_background_tasks () { 223let delay = background_delay. get_or_insert_with ( ||{ 224Box :: pin ( tokio:: time:: sleep ( Duration :: from_millis ( 20 ))) 225}); 226if delay. as_mut (). poll ( cx). is_ready () { 227 background_delay =None ; 228 cx. waker (). wake_by_ref (); 229} 230} else { 231 background_delay =None ; 232} 233Poll :: Pending 234})) 235}); 236let flushed = stdio. flush_interruptible ( || terminated. load ( Ordering :: SeqCst )); 237 control. set_isolate ( None ); 238 result?; 239 flushed?; 240Ok (()) 241} 242}