@@ -46,12 +46,6 @@ public synchronized void ensureRunning() {
4646 if (plugin .usesProxy ) {
4747 return ;
4848 }
49- if (isEndpointReachable ()) {
50- return ;
51- }
52- if (process != null && process .isAlive ()) {
53- return ;
54- }
5549
5650 LaunchTarget launchTarget = null ;
5751 try {
@@ -61,20 +55,27 @@ public synchronized void ensureRunning() {
6155 return ;
6256 }
6357
64- List <String > command = new ArrayList <>();
65- command .add (launchTarget .command ());
66- command .addAll (launchTarget .arguments ());
67- appendRuntimeArguments (command );
58+ ManagedConfigSyncResult initialSync = syncManagedServerProperties (launchTarget .installDirectory ());
59+
60+ if (process != null && process .isAlive ()) {
61+ if (initialSync .changed ()) {
62+ restartManagedProcess (launchTarget , "Managed VoiceCraft config changed, restarting process..." );
63+ }
64+ return ;
65+ }
66+ if (isEndpointReachable ()) {
67+ return ;
68+ }
6869
69- ProcessBuilder builder = new ProcessBuilder (command );
70- builder .directory (launchTarget .workingDirectory ().toFile ());
71- configureRuntimeEnvironment (builder );
70+ startManagedProcess (launchTarget );
7271
73- plugin .Logger .info ("Starting managed VoiceCraft process: " + launchTarget .command ());
74- process = builder .start ();
75- startLogPump (process .getInputStream (), false );
76- startLogPump (process .getErrorStream (), true );
77- waitUntilReachable ();
72+ if (initialSync .missing ()) {
73+ ManagedConfigSyncResult postStartSync = syncManagedServerProperties (launchTarget .installDirectory ());
74+ if (postStartSync .changed ()) {
75+ restartManagedProcess (launchTarget ,
76+ "Managed VoiceCraft config was generated and updated, restarting process..." );
77+ }
78+ }
7879 } catch (InterruptedException ex ) {
7980 Thread .currentThread ().interrupt ();
8081 plugin .Logger .error ("VoiceCraft startup was interrupted: " + ex .getMessage ());
@@ -93,20 +94,52 @@ public synchronized void shutdown() {
9394
9495 if (plugin .getConfig ().getBoolean ("config.voicecraft.shutdown-on-disable" , true )) {
9596 plugin .Logger .info ("Stopping managed VoiceCraft process..." );
96- process .destroy ();
97- try {
98- if (!process .waitFor (5 , java .util .concurrent .TimeUnit .SECONDS )) {
99- process .destroyForcibly ();
100- }
101- } catch (InterruptedException ex ) {
102- Thread .currentThread ().interrupt ();
103- process .destroyForcibly ();
104- }
97+ stopProcess ();
10598 }
10699
107100 process = null ;
108101 }
109102
103+ private void startManagedProcess (LaunchTarget launchTarget ) throws IOException {
104+ List <String > command = new ArrayList <>();
105+ command .add (launchTarget .command ());
106+ command .addAll (launchTarget .arguments ());
107+ appendRuntimeArguments (command );
108+
109+ ProcessBuilder builder = new ProcessBuilder (command );
110+ builder .directory (launchTarget .workingDirectory ().toFile ());
111+ configureRuntimeEnvironment (builder );
112+
113+ plugin .Logger .info ("Starting managed VoiceCraft process: " + launchTarget .command ());
114+ process = builder .start ();
115+ startLogPump (process .getInputStream (), false );
116+ startLogPump (process .getErrorStream (), true );
117+ waitUntilReachable ();
118+ }
119+
120+ private void restartManagedProcess (LaunchTarget launchTarget , String reason ) throws IOException {
121+ plugin .Logger .info (reason );
122+ stopProcess ();
123+ process = null ;
124+ startManagedProcess (launchTarget );
125+ }
126+
127+ private void stopProcess () {
128+ if (process == null ) {
129+ return ;
130+ }
131+
132+ process .destroy ();
133+ try {
134+ if (!process .waitFor (5 , java .util .concurrent .TimeUnit .SECONDS )) {
135+ process .destroyForcibly ();
136+ }
137+ } catch (InterruptedException ex ) {
138+ Thread .currentThread ().interrupt ();
139+ process .destroyForcibly ();
140+ }
141+ }
142+
110143 private Thread startLogPump (InputStream stream , boolean errorStream ) {
111144 Thread thread = Thread .ofVirtual ().name (errorStream ? "voicecraft-stderr" : "voicecraft-stdout" ).start (() -> {
112145 try (BufferedReader reader = new BufferedReader (new InputStreamReader (stream , StandardCharsets .UTF_8 ))) {
@@ -200,16 +233,15 @@ private LaunchTarget resolveReleaseLaunchTarget() throws IOException, Interrupte
200233 writeReleaseMarker (releaseMarker , releaseId );
201234 }
202235
203- updateManagedServerProperties (installDirectory );
204-
205236 if (!Files .exists (executablePath )) {
206237 plugin .Logger .error ("Managed VoiceCraft executable was not found after extraction: " + executablePath );
207238 return null ;
208239 }
209240
210241 executablePath .toFile ().setExecutable (true );
211242 Path absoluteExecutablePath = executablePath .toAbsolutePath ().normalize ();
212- return new LaunchTarget (absoluteExecutablePath .getParent (), absoluteExecutablePath .toString (), List .of ());
243+ return new LaunchTarget (installDirectory , absoluteExecutablePath .getParent (), absoluteExecutablePath .toString (),
244+ List .of ());
213245 }
214246
215247 private Path resolveInstallDirectory () {
@@ -237,20 +269,25 @@ private Path resolveManagedExecutable(Path installDirectory, String platform) {
237269 return installDirectory .resolve (fileName ).normalize ();
238270 }
239271
240- private void updateManagedServerProperties (Path installDirectory ) throws IOException {
272+ private ManagedConfigSyncResult syncManagedServerProperties (Path installDirectory ) throws IOException {
241273 Path serverPropertiesPath = installDirectory .resolve ("config" ).resolve ("ServerProperties.json" ).normalize ();
242274 if (!Files .exists (serverPropertiesPath )) {
243- plugin .Logger .warn ("Managed VoiceCraft config file was not found : " + serverPropertiesPath );
244- return ;
275+ plugin .Logger .info ("Managed VoiceCraft config file is not present yet : " + serverPropertiesPath );
276+ return new ManagedConfigSyncResult ( serverPropertiesPath , false , true ) ;
245277 }
246278
247279 String content = Files .readString (serverPropertiesPath , StandardCharsets .UTF_8 );
248- String updated = content .replaceFirst ("\" Port\" \\ s*:\\ s*\\ d+" ,
249- "\" Port\" : " + plugin .getManagedVoicePort ());
280+ String updated = content .replaceFirst ("\" Port\" \\ s*:\\ s*\\ d+" , "\" Port\" : " + plugin .getManagedVoicePort ());
250281 if (!updated .equals (content )) {
251282 Files .writeString (serverPropertiesPath , updated , StandardCharsets .UTF_8 ,
252283 StandardOpenOption .TRUNCATE_EXISTING , StandardOpenOption .WRITE );
284+ return new ManagedConfigSyncResult (serverPropertiesPath , true , false );
253285 }
286+ return new ManagedConfigSyncResult (serverPropertiesPath , false , false );
287+ }
288+
289+ Path getManagedServerPropertiesPath () {
290+ return resolveInstallDirectory ().resolve ("config" ).resolve ("ServerProperties.json" ).normalize ();
254291 }
255292
256293 private void downloadAndExtractRelease (Path installDirectory , String assetName ) throws IOException , InterruptedException {
@@ -361,6 +398,9 @@ private static String capitalize(String value) {
361398 return Character .toUpperCase (value .charAt (0 )) + value .substring (1 ).toLowerCase (Locale .ROOT );
362399 }
363400
364- private record LaunchTarget (Path workingDirectory , String command , List <String > arguments ) {
401+ private record LaunchTarget (Path installDirectory , Path workingDirectory , String command , List <String > arguments ) {
402+ }
403+
404+ private record ManagedConfigSyncResult (Path path , boolean changed , boolean missing ) {
365405 }
366406}
0 commit comments