@@ -3310,26 +3310,65 @@ function bulkAssignItemsToFolder(string $type, string $folderId, array $items):
33103310 ];
33113311 }
33123312
3313- function syncContainerOrder ( string $ type ): void {
3313+ function dockerSyncOrderLockPath ( ): string {
33143314 global $ configDir ;
3315- fv3_debug_log ("syncContainerOrder called for type: $ type " );
3315+ if (!is_dir ($ configDir )) {
3316+ @mkdir ($ configDir , 0770 , true );
3317+ }
3318+ return $ configDir . '/docker-sync-order.lock ' ;
3319+ }
33163320
3317- if ($ type !== 'docker ' ) { return ; }
3321+ function dockerSyncOrderPendingPath (): string {
3322+ global $ configDir ;
3323+ if (!is_dir ($ configDir )) {
3324+ @mkdir ($ configDir , 0770 , true );
3325+ }
3326+ return $ configDir . '/docker-sync-order.pending ' ;
3327+ }
3328+
3329+ function markDockerSyncOrderPending (): void {
3330+ @file_put_contents (dockerSyncOrderPendingPath (), (string )microtime (true ));
3331+ }
3332+
3333+ function clearDockerSyncOrderPending (): void {
3334+ $ pendingPath = dockerSyncOrderPendingPath ();
3335+ if (file_exists ($ pendingPath )) {
3336+ @unlink ($ pendingPath );
3337+ }
3338+ }
3339+
3340+ function hasDockerSyncOrderPending (): bool {
3341+ return file_exists (dockerSyncOrderPendingPath ());
3342+ }
3343+
3344+ function syncContainerOrderUnlocked (): void {
3345+ global $ configDir ;
33183346
33193347 $ prefsFile = "/boot/config/plugins/dockerMan/userprefs.cfg " ;
33203348 if (!file_exists ($ prefsFile )) { return ; }
33213349
3350+ $ currentPrefsRaw = @file_get_contents ($ prefsFile );
33223351 $ currentPrefs = @parse_ini_file ($ prefsFile );
33233352 $ currentOrder = $ currentPrefs ? array_values ($ currentPrefs ) : [];
33243353
33253354 $ foldersFile = "$ configDir/docker.json " ;
33263355 $ folders = file_exists ($ foldersFile ) ? (json_decode (file_get_contents ($ foldersFile ), true ) ?: []) : [];
33273356
33283357 $ dockerClient = new DockerClient ();
3329- $ allContainerNames = array_column ($ dockerClient ->getDockerContainers (), 'Name ' );
3358+ $ allContainerNames = [];
3359+ foreach ((array )$ dockerClient ->getDockerContainers () as $ containerMeta ) {
3360+ $ name = trim ((string )($ containerMeta ['Name ' ] ?? '' ));
3361+ if ($ name === '' || in_array ($ name , $ allContainerNames , true )) {
3362+ continue ;
3363+ }
3364+ $ allContainerNames [] = $ name ;
3365+ }
33303366 $ prefs = readTypePrefs ('docker ' );
33313367 $ rules = is_array ($ prefs ['autoRules ' ] ?? null ) ? $ prefs ['autoRules ' ] : [];
3332- $ infoByName = readInfo ('docker ' );
3368+ $ infoByName = readInfoState ('docker ' );
3369+ if (count ($ allContainerNames ) <= 0 ) {
3370+ $ allContainerNames = array_keys ($ infoByName );
3371+ }
33333372 $ ruleTargetByName = [];
33343373 $ labelTargetByName = [];
33353374 foreach ($ allContainerNames as $ name ) {
@@ -3343,11 +3382,11 @@ function syncContainerOrder(string $type): void {
33433382 $ folderContainers = [];
33443383 $ assignedContainers = [];
33453384 foreach ($ folders as $ folderId => $ folder ) {
3346- $ members = $ folder ['containers ' ] ?? [];
3385+ $ members = normalizeFolderMembers ( $ folder ['containers ' ] ?? []) ;
33473386 if (!empty ($ folder ['regex ' ])) {
33483387 $ regex = '/ ' . str_replace ('/ ' , '\/ ' , $ folder ['regex ' ]) . '/ ' ;
33493388 foreach ($ allContainerNames as $ name ) {
3350- if (@preg_match ($ regex , $ name ) && !in_array ($ name , $ members )) {
3389+ if (@preg_match ($ regex , $ name ) && !in_array ($ name , $ members, true )) {
33513390 $ members [] = $ name ;
33523391 }
33533392 }
@@ -3425,8 +3464,12 @@ function syncContainerOrder(string $type): void {
34253464 foreach ($ newOrder as $ i => $ name ) {
34263465 $ ini .= ($ i + 1 ) . '=" ' . $ name . '" ' . "\n" ;
34273466 }
3428- file_put_contents ($ prefsFile , $ ini );
3429- fv3_debug_log ("syncContainerOrder: wrote userprefs.cfg with " . count ($ newOrder ) . " entries " );
3467+ if ((string )$ currentPrefsRaw !== $ ini ) {
3468+ file_put_contents ($ prefsFile , $ ini );
3469+ fv3_debug_log ("syncContainerOrder: wrote userprefs.cfg with " . count ($ newOrder ) . " entries " );
3470+ } else {
3471+ fv3_debug_log ("syncContainerOrder: userprefs.cfg already up to date " );
3472+ }
34303473
34313474 // Reorder autostart file to match new container order
34323475 $ dockerManPaths = @parse_ini_file ('/boot/config/plugins/dockerMan/dockerMan.cfg ' ) ?: [];
@@ -3459,8 +3502,52 @@ function syncContainerOrder(string $type): void {
34593502 foreach ($ autoStartMap as $ line ) {
34603503 $ newAutoStart [] = $ line ;
34613504 }
3462- file_put_contents ($ autoStartFile , implode ("\n" , $ newAutoStart ) . "\n" );
3463- fv3_debug_log ("syncContainerOrder: wrote autostart file with " . count ($ newAutoStart ) . " entries " );
3505+ $ nextAutoStartContent = count ($ newAutoStart ) > 0
3506+ ? implode ("\n" , $ newAutoStart ) . "\n"
3507+ : '' ;
3508+ $ currentAutoStartContent = @file_get_contents ($ autoStartFile );
3509+ if ((string )$ currentAutoStartContent !== $ nextAutoStartContent ) {
3510+ file_put_contents ($ autoStartFile , $ nextAutoStartContent );
3511+ fv3_debug_log ("syncContainerOrder: wrote autostart file with " . count ($ newAutoStart ) . " entries " );
3512+ } else {
3513+ fv3_debug_log ("syncContainerOrder: autostart file already up to date " );
3514+ }
3515+ }
3516+ }
3517+
3518+ function syncContainerOrder (string $ type ): void {
3519+ fv3_debug_log ("syncContainerOrder called for type: $ type " );
3520+
3521+ if ($ type !== 'docker ' ) { return ; }
3522+
3523+ $ lockHandle = @fopen (dockerSyncOrderLockPath (), 'c+ ' );
3524+ if (!is_resource ($ lockHandle )) {
3525+ fv3_debug_log ('syncContainerOrder: unable to open lock file, falling back to unlocked run ' );
3526+ syncContainerOrderUnlocked ();
3527+ return ;
3528+ }
3529+
3530+ if (!@flock ($ lockHandle , LOCK_EX | LOCK_NB )) {
3531+ markDockerSyncOrderPending ();
3532+ fv3_debug_log ('syncContainerOrder: coalesced while another sync is already running ' );
3533+ @fclose ($ lockHandle );
3534+ return ;
3535+ }
3536+
3537+ try {
3538+ $ attempt = 0 ;
3539+ do {
3540+ $ attempt ++;
3541+ clearDockerSyncOrderPending ();
3542+ $ startedAt = microtime (true );
3543+ syncContainerOrderUnlocked ();
3544+ $ durationMs = (int )round ((microtime (true ) - $ startedAt ) * 1000 );
3545+ $ shouldRerun = hasDockerSyncOrderPending ();
3546+ fv3_debug_log ("syncContainerOrder: pass $ attempt completed in {$ durationMs }ms " . ($ shouldRerun ? ' (pending rerun requested) ' : '' ));
3547+ } while ($ shouldRerun && $ attempt < 3 );
3548+ } finally {
3549+ @flock ($ lockHandle , LOCK_UN );
3550+ @fclose ($ lockHandle );
34643551 }
34653552 }
34663553
0 commit comments