@@ -479,18 +479,26 @@ public function subdomainRelease(Request $request, array $params): Response
479479 public function relayStatus (Request $ request , array $ params ): Response
480480 {
481481 try {
482- $ relayApp = $ this ->getRelayApplication ();
483- $ relayConsumer = $ this ->getRelayConsumer ();
484-
485- $ running = $ relayApp !== null && $ relayApp ->isRunning ();
486- $ connected = $ relayConsumer !== null && $ relayConsumer ->isConnected ();
487- $ active = $ relayConsumer !== null && $ relayConsumer ->isActive ();
482+ // The relay tunnel runs as a separate Workerman worker process (phlix-relay-tunnel)
483+ // which creates its own RelayConsumer directly. The RelayConsumer from our container
484+ // is a different instance that was never started. So we check the actual tunnel
485+ // worker process state instead of the container instance.
486+ $ tunnelRunning = $ this ->isTunnelWorkerRunning ();
487+ $ tunnelActive = false ;
488+ $ lastActivity = null ;
489+
490+ if ($ tunnelRunning ) {
491+ // Check recent logs for tunnel active status
492+ $ logState = $ this ->getTunnelLogState ();
493+ $ tunnelActive = $ logState ['active ' ];
494+ $ lastActivity = $ logState ['lastActivity ' ];
495+ }
488496
489497 return (new Response ())->json ([
490- 'connected ' => $ running && $ connected ,
491- 'active ' => $ running && $ active ,
492- 'endpoint ' => null , // Not exposed by RelayConsumer
493- 'establishedAt ' => null , // Not tracked
498+ 'connected ' => $ tunnelRunning && $ tunnelActive ,
499+ 'active ' => $ tunnelActive ,
500+ 'endpoint ' => null ,
501+ 'establishedAt ' => $ lastActivity ,
494502 ]);
495503 } catch (Throwable $ e ) {
496504 return (new Response ())->status (500 )->json ([
@@ -904,4 +912,66 @@ private function getRelayConsumer(): ?RelayConsumer
904912 return null ;
905913 }
906914 }
915+
916+ /**
917+ * Check if the relay tunnel worker process is running.
918+ */
919+ private function isTunnelWorkerRunning (): bool
920+ {
921+ // Check for the tunnel worker process
922+ $ output = [];
923+ exec ('pgrep -f "phlix-relay-tunnel" 2>/dev/null ' , $ output );
924+ return count ($ output ) > 0 ;
925+ }
926+
927+ /**
928+ * Get tunnel connection state from recent log entries.
929+ *
930+ * @return array{active: bool, lastActivity: ?string}
931+ */
932+ private function getTunnelLogState (): array
933+ {
934+ $ logFile = defined ('PHLIX_LOG_DIR ' ) ? PHLIX_LOG_DIR : __DIR__ . '/../../../../.logs ' ;
935+ $ logFile = $ logFile . '/events- ' . date ('Y-m-d ' ) . '.log ' ;
936+
937+ if (!file_exists ($ logFile )) {
938+ return ['active ' => false , 'lastActivity ' => null ];
939+ }
940+
941+ // Read last 50 lines and look for tunnel active status
942+ $ fp = fopen ($ logFile , 'r ' );
943+ if ($ fp === false ) {
944+ return ['active ' => false , 'lastActivity ' => null ];
945+ }
946+
947+ $ lines = [];
948+ while (($ line = fgets ($ fp )) !== false ) {
949+ $ lines [] = $ line ;
950+ if (count ($ lines ) > 50 ) {
951+ array_shift ($ lines );
952+ }
953+ }
954+ fclose ($ fp );
955+
956+ $ active = false ;
957+ $ lastActivity = null ;
958+
959+ foreach (array_reverse ($ lines ) as $ line ) {
960+ if (strpos ($ line , 'RelayConsumer: tunnel active ' ) !== false ) {
961+ $ active = true ;
962+ // Extract timestamp from log line
963+ if (preg_match ('/^\[([^\]]+)\]/ ' , $ line , $ matches )) {
964+ $ lastActivity = $ matches [1 ];
965+ }
966+ break ;
967+ }
968+ if (strpos ($ line , 'RelayConsumer connected; sending HELLO ' ) !== false && $ lastActivity === null ) {
969+ if (preg_match ('/^\[([^\]]+)\]/ ' , $ line , $ matches )) {
970+ $ lastActivity = $ matches [1 ];
971+ }
972+ }
973+ }
974+
975+ return ['active ' => $ active , 'lastActivity ' => $ lastActivity ];
976+ }
907977}
0 commit comments