11package com .shimmerresearch .grpc ;
22
33import java .io .BufferedReader ;
4+ import java .io .File ;
45import java .io .IOException ;
56import java .io .InputStreamReader ;
67import java .net .ServerSocket ;
8+ import java .net .URISyntaxException ;
9+ import java .net .URL ;
10+ import java .nio .file .Path ;
11+ import java .nio .file .Paths ;
712import java .util .ArrayList ;
813import java .util .List ;
14+ import java .util .concurrent .TimeUnit ;
915
1016import javax .swing .JFrame ;
17+
18+ import com .shimmerresearch .driverUtilities .UtilShimmer ;
19+
1120import javax .swing .JButton ;
1221import java .awt .event .ActionListener ;
1322import java .awt .event .ActionEvent ;
1423
1524public class GrpcBLERadioByteTools {
1625
1726 private Process runningProcess ;
18- String mExeName = "ShimmerBLEGrpc.exe" ;
19- String mExePath = "C:\\ Github\\ Shimmer-C-API\\ ShimmerAPI\\ ShimmerBLEGrpc\\ bin\\ Debug\\ " + mExeName ; // Replace with the path to your .exe file
27+ String mExeNameWindows = "ShimmerBLEGrpc.exe" ;
28+ String mExePathWindows = "C:\\ Github\\ Shimmer-C-API\\ ShimmerAPI\\ ShimmerBLEGrpc\\ bin\\ Debug\\ " + mExeNameWindows ; // Replace with the path to your .exe file
2029 //String exePath = "C:\\Users\\JC\\Desktop\\testgrpc\\ShimmerBLEGrpc.exe"; // Replace with the path to your .exe file
2130
22- public GrpcBLERadioByteTools () {
31+ //Below used by Consensys MacOS
32+ String userDir = System .getProperty ("user.dir" ).equals ("/" ) ? (getApplicationPath ().toString () + "/libs/" ) : (System .getProperty ("user.dir" ) + "/libs/" );
33+ String mExeNameMac = "ShimmerBLEGrpc" ;
34+ String mExePathMac = userDir + "ShimmerBLEGrpc/Products/usr/local/bin/" + mExeNameMac ;
35+
36+ public GrpcBLERadioByteTools () {
2337
2438 }
2539
2640 public GrpcBLERadioByteTools (String exeName , String exePath ) {
27- mExeName = exeName ;
28- mExePath = exePath ;
41+ mExeNameWindows = exeName ;
42+ mExeNameMac = exeName ;
43+ mExePathWindows = exePath ;
44+ mExePathMac = exePath ;
2945 }
3046
3147
@@ -67,37 +83,105 @@ public boolean isExeRunning(String exeName) {
6783 return false ;
6884 }
6985 }
70- public int startServer () throws Exception {
86+
87+ public boolean isExeRunningMacOS (String exeName ) {
88+ try {
89+ Process process = Runtime .getRuntime ().exec (new String []{"pgrep" , "-x" , exeName });
90+ BufferedReader reader = new BufferedReader (new InputStreamReader (process .getInputStream ()));
91+ boolean found = reader .readLine () != null ;
92+
93+ if (!process .waitFor (5 , TimeUnit .SECONDS )) { // Wait up to 5 seconds
94+ process .destroy (); // Terminate the process if it doesn't exit
95+ System .err .println ("pgrep process timed out." );
96+ return false ; // Consider it not found or an error
97+ }
7198
99+ return found ;
100+ } catch (IOException e ) {
101+ System .err .println ("Error executing pgrep command: " + e .getMessage ());
102+ e .printStackTrace ();
103+ return false ;
104+ } catch (InterruptedException e ) {
105+ System .err .println ("Thread interrupted while waiting for pgrep process: " + e .getMessage ());
106+ Thread .currentThread ().interrupt (); // Restore the interrupted status
107+ return false ;
108+ }
109+ }
72110
111+ public boolean isServerRunning () {
112+ if (UtilShimmer .isOsMac ()) {
113+ return isExeRunningMacOS (mExeNameMac );
114+ } else {
115+ return isExeRunning (mExeNameWindows );
116+ }
117+ }
118+
119+ public int startServer () throws Exception {
73120 int port = getFreePort ();
74121
75122 System .out .println (port + " is free" );
76123 List <String > command = new ArrayList <>();
77124
78125 // Add the command itself
79- command .add (mExePath );
126+ if (UtilShimmer .isOsMac ()) {
127+ command .add (mExePathMac );
128+ command .add ("--port" );
129+ } else {
130+ command .add (mExePathWindows );
131+ }
80132 command .add (Integer .toString (port ));
133+
81134 ProcessBuilder processBuilder = new ProcessBuilder (command );
82135 processBuilder .redirectErrorStream (true ); // Redirect standard error to the input stream
83136 runningProcess = processBuilder .start ();
137+
138+ // Add shutdown hook to ensure server is closed when Java app exits
139+ try {
140+ Runtime .getRuntime ().addShutdownHook (shutdownHook );
141+ } catch (IllegalStateException ignored ) {
142+ // JVM is already shutting down
143+ }
144+
84145 Thread processThread = new Thread (() -> {
85146 try (BufferedReader reader = new BufferedReader (new InputStreamReader (runningProcess .getInputStream ()))) {
86147 String line ;
87148 while ((line = reader .readLine ()) != null ) {
88- System .out .println (line );
149+ System .out .println ("[BLEGrpcServer] " + line );
89150 }
90151 } catch (IOException e ) {
91152 // TODO Auto-generated catch block
92153 e .printStackTrace ();
93154 }
94155 });
156+ runningProcess .onExit ().thenAccept (p -> {
157+ int code = p .exitValue ();
158+ System .err .println ("[BLEGrpcServer] exited: code=" + code +
159+ (code >= 128 ? " (likely signal " + (code - 128 ) + ")" : "" ));
160+ });
95161
96162 processThread .start ();
97163 return port ;
98164 // You can continue with other tasks here
99-
100165 }
166+
167+ private final Thread shutdownHook = new Thread (() -> {
168+ Process p = runningProcess ;
169+ if (p == null ) return ;
170+
171+ try {
172+ // Try graceful termination first
173+ p .destroy (); // sends SIGTERM on Unix, WM_CLOSE/CTRL_BREAK semantics vary on Windows
174+ if (!p .waitFor (3 , java .util .concurrent .TimeUnit .SECONDS )) {
175+ // Fall back to force kill
176+ p .destroyForcibly ();
177+ p .waitFor (2 , java .util .concurrent .TimeUnit .SECONDS );
178+ }
179+ } catch (InterruptedException ie ) {
180+ Thread .currentThread ().interrupt ();
181+ } catch (Exception e ) {
182+ e .printStackTrace ();
183+ }
184+ });
101185
102186 public void stopServer () {
103187 if (runningProcess != null ) {
@@ -107,6 +191,18 @@ public void stopServer() {
107191 System .err .println ("No external process is currently running." );
108192 }
109193 }
194+
195+ public static Path getApplicationPath () {
196+ try {
197+ URL codeSourceUrl = GrpcBLERadioByteTools .class .getProtectionDomain ().getCodeSource ().getLocation ();
198+ Path codeSourcePath = Paths .get (codeSourceUrl .toURI ());
199+ if (codeSourcePath .toFile ().isFile ())
200+ return codeSourcePath .getParent ();
201+ return codeSourcePath ;
202+ } catch (URISyntaxException e ) {
203+ throw new IllegalStateException ("Failed to determine application path due to a URI syntax error." , e );
204+ }
205+ }
110206
111207 public static void main (String [] args ) {
112208
@@ -142,7 +238,7 @@ public void actionPerformed(ActionEvent e) {
142238 JButton btnCheck = new JButton ("checkServerApp" );
143239 btnCheck .addActionListener (new ActionListener () {
144240 public void actionPerformed (ActionEvent e ) {
145- if (grpcTools .isExeRunning (grpcTools .mExeName )) {
241+ if (grpcTools .isExeRunning (grpcTools .mExeNameWindows )) {
146242 System .out .println ("EXE RUNNING" );
147243 } else {
148244 System .out .println ("EXE NOT RUNNING" );
0 commit comments