@@ -103,7 +103,7 @@ class LuaRunner {
103103 _registerConfigTable (lua, configValues);
104104 _registerConfigGet (lua, configValues);
105105 _registerStorage (lua, pluginId);
106- _registerWeb (lua);
106+ _registerWeb (lua, pluginId );
107107 _registerSyncNoArgFunc (lua, 'platform' , () => _bridge.platform);
108108 _registerSyncNoArgFunc (lua, 'homeDir' , () => _bridge.homeDir);
109109 _registerSyncNoArgBool (lua, 'isMobile' , () => _bridge.isMobile);
@@ -336,7 +336,7 @@ class LuaRunner {
336336 lua.setField (- 2 , 'execResult' );
337337 }
338338
339- void _registerWeb (LuaState lua) {
339+ void _registerWeb (LuaState lua, String pluginId ) {
340340 lua.pushDartFunction ((ls) {
341341 final url = ls.getTop () >= 1 ? ls.toStr (1 ) : null ;
342342 if (url == null || url.isEmpty) {
@@ -361,18 +361,26 @@ class LuaRunner {
361361 }
362362
363363 if (_bridge.isMobile) {
364- final cacheKey = _buildWebCacheKey (
364+ final cacheKey = '$ pluginId |${ _buildWebCacheKey (
365365 url ,
366366 method : method ,
367367 headers : headers ,
368368 body : body ,
369369 timeout : timeout ,
370370 raw : raw ,
371- );
371+ )}' ;
372+
373+ var cached = _webCache[cacheKey];
374+ if (cached == null ) {
375+ cached = _readWebCache (pluginId, cacheKey);
376+ if (cached != null ) {
377+ _webCache[cacheKey] = cached;
378+ }
379+ }
372380
373- final cached = _webCache[cacheKey];
374381 if (! _webInFlight.contains (cacheKey)) {
375382 _webInFlight.add (cacheKey);
383+ final cachedSnapshot = cached;
376384 _bridge
377385 .web (
378386 url,
@@ -382,8 +390,14 @@ class LuaRunner {
382390 timeout: timeout ?? 30 ,
383391 )
384392 .then ((response) {
385- _webCache[cacheKey] = response;
393+ if (_isSuccessfulWebResponse (response)) {
394+ _webCache[cacheKey] = response;
395+ _writeWebCache (pluginId, cacheKey, response);
396+ } else if (cachedSnapshot == null ) {
397+ _webCache[cacheKey] = response;
398+ }
386399 }).catchError ((e) {
400+ if (cachedSnapshot != null ) return ;
387401 _webCache[cacheKey] = {
388402 'error' : true ,
389403 'message' : e.toString (),
@@ -500,6 +514,57 @@ class LuaRunner {
500514 }
501515 }
502516
517+ String _resolveWebCacheBaseDir () {
518+ final appDir = _bridge.appDataDir;
519+ if (appDir != null && appDir.isNotEmpty && appDir != '~' ) {
520+ return appDir;
521+ }
522+ if (_bridge.isMobile) {
523+ return Directory .systemTemp.path;
524+ }
525+ return _bridge.homeDir;
526+ }
527+
528+ File _webCacheFile (String pluginId, String cacheKey) {
529+ final safeId = _sanitizePluginId (pluginId.isEmpty ? 'unknown' : pluginId);
530+ final baseDir = _resolveWebCacheBaseDir ();
531+ final dir = Directory (path.join (baseDir, 'crossbar_web_cache' , safeId));
532+ final fileName = _bridge.hash (cacheKey);
533+ return File (path.join (dir.path, '$fileName .json' ));
534+ }
535+
536+ dynamic _readWebCache (String pluginId, String cacheKey) {
537+ final file = _webCacheFile (pluginId, cacheKey);
538+ if (! file.existsSync ()) return null ;
539+ try {
540+ return jsonDecode (file.readAsStringSync ());
541+ } catch (_) {
542+ return null ;
543+ }
544+ }
545+
546+ void _writeWebCache (String pluginId, String cacheKey, dynamic value) {
547+ try {
548+ final file = _webCacheFile (pluginId, cacheKey);
549+ final dir = file.parent;
550+ if (! dir.existsSync ()) {
551+ dir.createSync (recursive: true );
552+ }
553+ file.writeAsStringSync (jsonEncode (value));
554+ } catch (_) {
555+ // Ignore cache write errors
556+ }
557+ }
558+
559+ bool _isSuccessfulWebResponse (dynamic response) {
560+ if (response is Map ) {
561+ if (response['error' ] == true ) return false ;
562+ final status = response['status' ];
563+ if (status is int && status >= 400 ) return false ;
564+ }
565+ return true ;
566+ }
567+
503568 void _registerStorage (LuaState lua, String pluginId) {
504569 lua.pushDartFunction ((ls) {
505570 final key = ls.getTop () >= 1 ? ls.toStr (1 ) : null ;
0 commit comments