@@ -23,7 +23,7 @@ class CachedAssetSchemeHandler: NSObject, WKURLSchemeHandler {
2323        return  nil 
2424    } 
2525
26-     let  worker :  Worker 
26+     private   let  worker :  Worker 
2727
2828    init ( library:  EditorAssetsLibrary )  { 
2929        self . worker =  . init( library:  library) 
@@ -40,69 +40,102 @@ class CachedAssetSchemeHandler: NSObject, WKURLSchemeHandler {
4040            await  worker. stop ( urlSchemeTask) 
4141        } 
4242    } 
43+ } 
4344
44-      actor  Worker  { 
45-           struct  TaskInfo  { 
46-               var  webViewTask :  WKURLSchemeTask 
47-               var  fetchAssetTask :  Task < Void ,  Never > 
45+ private  actor  Worker  { 
46+      struct  TaskInfo  { 
47+          var  webViewTask :  WKURLSchemeTask 
48+          var  fetchAssetTask :  Task < Void ,  Never > 
4849
49-              func  cancel( )  { 
50-                  fetchAssetTask. cancel ( ) 
51-              } 
52-         } 
50+          func  cancel( )  { 
51+              fetchAssetTask. cancel ( ) 
52+          } 
53+     } 
54+ 
55+     let  library :  EditorAssetsLibrary 
56+     var  tasks :  [ ObjectIdentifier :  TaskInfo ]  =  [ : ] 
57+ 
58+     init ( library:  EditorAssetsLibrary )  { 
59+         self . library =  library
60+     } 
5361
54-         let  library :  EditorAssetsLibrary 
55-         var  tasks :  [ ObjectIdentifier :  TaskInfo ]  =  [ : ] 
62+     deinit  { 
63+         for  (_,  task)    in  tasks { 
64+             task. cancel ( ) 
65+         } 
66+     } 
5667
57-         init ( library:  EditorAssetsLibrary )  { 
58-             self . library =  library
68+     func  start( _ task:  WKURLSchemeTask )  { 
69+         guard  let  url =  task. request. url,  let  httpURL =  CachedAssetSchemeHandler . originalHTTPURL ( from:  url)  else  { 
70+             task. didFailWithError ( URLError ( . badURL) ) 
71+             return 
5972        } 
6073
61-         deinit  { 
62-             for  (_,  task)    in  tasks { 
63-                 task. cancel ( ) 
74+         let  taskKey  =  ObjectIdentifier ( task) 
75+ 
76+         let  fetchAssetTask  =  Task  {  [ library,  weak self]  in 
77+             do  { 
78+                 let  ( response,  content)  =  try   await  library. cacheAsset ( from:  httpURL,  webViewURL:  url) 
79+ 
80+                 await  self ? . tasks [ taskKey] ? . webViewTask. didReceive ( response) 
81+                 await  self ? . tasks [ taskKey] ? . webViewTask. didReceive ( content) 
82+ 
83+                 await  self ? . finish ( with:  nil ,  taskKey:  taskKey) 
84+             }  catch  { 
85+                 await  self ? . finish ( with:  error,  taskKey:  taskKey) 
6486            } 
6587        } 
88+         tasks [ taskKey]  =  . init( webViewTask:  task,  fetchAssetTask:  fetchAssetTask) 
89+     } 
6690
67-         func  start( _ task:  WKURLSchemeTask )  { 
68-             guard  let  url =  task. request. url,  let  httpURL =  CachedAssetSchemeHandler . originalHTTPURL ( from:  url)  else  { 
69-                 task. didFailWithError ( URLError ( . badURL) ) 
70-                 return 
71-             } 
91+     func  stop( _ task:  WKURLSchemeTask )  { 
92+         let  taskKey  =  ObjectIdentifier ( task) 
93+         tasks [ taskKey] ? . cancel ( ) 
94+         tasks [ taskKey]  =  nil 
95+     } 
96+ 
97+     private  func  finish( with error:  Error ? ,  taskKey:  ObjectIdentifier )  { 
98+         guard  let  task =  tasks [ taskKey]  else  {  return  } 
7299
73-             let  taskKey  =  ObjectIdentifier ( task) 
100+         if  let  error { 
101+             task. webViewTask. didFailWithError ( error) 
102+         }  else  { 
103+             task. webViewTask. didFinish ( ) 
104+         } 
105+         tasks [ taskKey]  =  nil 
106+     } 
107+ } 
108+ 
109+ @available ( iOS 26 . 0 ,  * )  
110+ extension  CachedAssetSchemeHandler :  URLSchemeHandler  { 
111+     func  reply( for request:  URLRequest )  ->  AsyncThrowingStream < URLSchemeTaskResult ,  Error >  { 
112+         AsyncThrowingStream  {  [ library =  worker. library]  continuation in 
113+             let  task  =  Task  { 
114+                 guard  let  url =  request. url, 
115+                       let  httpURL =  CachedAssetSchemeHandler . originalHTTPURL ( from:  url)  else  { 
116+                     continuation. yield ( with:  . failure( URLError ( . badURL) ) ) 
117+                     continuation. finish ( ) 
118+                     return 
119+                 } 
74120
75-             let  fetchAssetTask  =  Task  {  [ library,  weak self]  in 
76121                do  { 
77122                    let  ( response,  content)  =  try   await  library. cacheAsset ( from:  httpURL,  webViewURL:  url) 
123+                     try   Task . checkCancellation ( ) 
78124
79-                     await  self ? . tasks [ taskKey] ? . webViewTask. didReceive ( response) 
80-                     await  self ? . tasks [ taskKey] ? . webViewTask. didReceive ( content) 
81- 
82-                     await  self ? . finish ( with:  nil ,  taskKey:  taskKey) 
125+                     continuation. yield ( with:  . success( . response( response) ) ) 
126+                     continuation. yield ( with:  . success( . data( content) ) ) 
83127                }  catch  { 
84-                     await  self ? . finish ( with:  error,  taskKey:  taskKey) 
128+                     try   Task . checkCancellation ( ) 
129+                     continuation. yield ( with:  . failure( error) ) 
85130                } 
131+                 continuation. finish ( ) 
86132            } 
87-             tasks [ taskKey]  =  . init( webViewTask:  task,  fetchAssetTask:  fetchAssetTask) 
88-         } 
89- 
90-         func  stop( _ task:  WKURLSchemeTask )  { 
91-             let  taskKey  =  ObjectIdentifier ( task) 
92-             tasks [ taskKey] ? . cancel ( ) 
93-             tasks [ taskKey]  =  nil 
94-         } 
95133
96-         private  func  finish( with error:  Error ? ,  taskKey:  ObjectIdentifier )  { 
97-             guard  let  task =  tasks [ taskKey]  else  {  return  } 
98- 
99-             if  let  error { 
100-                 task. webViewTask. didFailWithError ( error) 
101-             }  else  { 
102-                 task. webViewTask. didFinish ( ) 
134+             continuation. onTermination =  { 
135+                 if  case . cancelled =  $0 { 
136+                     task. cancel ( ) 
137+                 } 
103138            } 
104-             tasks [ taskKey]  =  nil 
105139        } 
106140    } 
107141} 
108- 
0 commit comments