Skip to content

Commit d79b970

Browse files
Improve ProcessHelper ergonomics
at the moment the timeout is removed, but it probably isn't needed anymore
1 parent f7a5516 commit d79b970

File tree

4 files changed

+36
-63
lines changed

4 files changed

+36
-63
lines changed

src/main/java/com/github/stickerifier/stickerify/bot/Stickerify.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,8 @@ private void answerFile(TelegramRequest request, String fileId) {
136136
}
137137
} catch (TelegramApiException | MediaException e) {
138138
processFailure(request, e);
139+
} catch (InterruptedException e) {
140+
Thread.currentThread().interrupt();
139141
} finally {
140142
deleteTempFiles(pathsToDelete);
141143
}

src/main/java/com/github/stickerifier/stickerify/media/MediaHelper.java

Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,9 @@ public final class MediaHelper {
6464
* @param inputFile the file to convert
6565
* @return a resized and converted file
6666
* @throws MediaException if the file is not supported or if the conversion failed
67+
* @throws InterruptedException if the current thread is interrupted while converting a video file
6768
*/
68-
public static File convert(File inputFile) throws MediaException {
69+
public static File convert(File inputFile) throws MediaException, InterruptedException {
6970
var mimeType = detectMimeType(inputFile);
7071

7172
try {
@@ -334,8 +335,9 @@ private static void deleteFile(File file) throws FileOperationException {
334335
* @param file the file to convert
335336
* @return converted video, {@code null} if no conversion was needed
336337
* @throws MediaException if file conversion is not successful
338+
* @throws InterruptedException if the current thread is interrupted while converting the video file
337339
*/
338-
private static File convertToWebm(File file) throws MediaException {
340+
private static File convertToWebm(File file) throws MediaException, InterruptedException {
339341
if (isVideoCompliant(file)) {
340342
LOGGER.atInfo().log("The video doesn't need conversion");
341343

@@ -389,8 +391,9 @@ private static MultimediaInfo retrieveMultimediaInfo(File file) throws Corrupted
389391
* @param file the file to convert
390392
* @return converted video
391393
* @throws MediaException if file conversion is not successful
394+
* @throws InterruptedException if the current thread is interrupted while converting the file
392395
*/
393-
private static File convertWithFfmpeg(File file) throws MediaException {
396+
private static File convertWithFfmpeg(File file) throws MediaException, InterruptedException {
394397
var webmVideo = createTempFile("webm");
395398
var logPrefix = webmVideo.getAbsolutePath() + "-passlog";
396399
var baseCommand = new String[] {
@@ -416,9 +419,13 @@ private static File convertWithFfmpeg(File file) throws MediaException {
416419
} catch (FileOperationException ex) {
417420
e.addSuppressed(ex);
418421
}
419-
throw new MediaException(e.getMessage());
422+
throw new MediaException(e);
420423
} finally {
421-
deleteLogFile(logPrefix);
424+
try {
425+
deleteFile(new File(logPrefix + "-0.log"));
426+
} catch (FileOperationException _) {
427+
// ignore the exception
428+
}
422429
}
423430

424431
return webmVideo;
@@ -438,18 +445,6 @@ private static String[] buildFfmpegCommand(String[] baseCommand, String... addit
438445
return commands;
439446
}
440447

441-
/**
442-
* Delete the passlog file based on the prefix
443-
*
444-
* @param prefix the prefix of the passlog file
445-
*/
446-
private static void deleteLogFile(String prefix) {
447-
try {
448-
deleteFile(new File(prefix + "-0.log"));
449-
} catch (FileOperationException _) {
450-
}
451-
}
452-
453448
private MediaHelper() {
454449
throw new UnsupportedOperationException();
455450
}

src/main/java/com/github/stickerifier/stickerify/process/PathLocator.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package com.github.stickerifier.stickerify.process;
22

33
import static com.github.stickerifier.stickerify.process.ProcessHelper.IS_WINDOWS;
4-
import static java.lang.System.lineSeparator;
54

65
import com.github.stickerifier.stickerify.exception.ProcessException;
76
import org.slf4j.Logger;
@@ -24,12 +23,14 @@ public class PathLocator implements ProcessLocator {
2423
public PathLocator() {
2524
try {
2625
if (ffmpegLocation == null || ffmpegLocation.isBlank()) {
27-
ffmpegLocation = ProcessHelper.executeCommand(FIND_FFMPEG).split(lineSeparator())[0];
26+
ffmpegLocation = ProcessHelper.executeCommand(FIND_FFMPEG).getFirst();
2827
}
2928

3029
LOGGER.atInfo().log("FFmpeg is installed at {}", ffmpegLocation);
3130
} catch (ProcessException e) {
3231
LOGGER.atError().setCause(e).log("Unable to detect FFmpeg's installation path");
32+
} catch (InterruptedException _) {
33+
Thread.currentThread().interrupt();
3334
}
3435
}
3536

src/main/java/com/github/stickerifier/stickerify/process/ProcessHelper.java

Lines changed: 19 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
package com.github.stickerifier.stickerify.process;
22

33
import static java.nio.charset.StandardCharsets.UTF_8;
4-
import static java.util.concurrent.TimeUnit.MINUTES;
54

65
import com.github.stickerifier.stickerify.exception.ProcessException;
76

87
import java.io.IOException;
9-
import java.io.InputStream;
8+
import java.util.LinkedList;
9+
import java.util.List;
1010
import java.util.concurrent.Semaphore;
1111

1212
public final class ProcessHelper {
@@ -21,65 +21,40 @@ public final class ProcessHelper {
2121
* on Windows they will be at most 4, on every other system they will be at most 5.
2222
*
2323
* @param command the command to be executed
24-
* @return the output of the command
24+
* @return the output of the command, split by lines
2525
* @throws ProcessException either if:
2626
* <ul>
2727
* <li>the command was unsuccessful
28-
* <li>the waiting time elapsed
2928
* <li>an unexpected failure happened running the command
29+
* <li>an unexpected failure happened reading the output
3030
* </ul>
31+
* @throws InterruptedException if the current thread is interrupted while waiting for the command to finish execution
3132
*/
32-
public static String executeCommand(final String[] command) throws ProcessException {
33-
Process process = null;
34-
33+
public static List<String> executeCommand(final String[] command) throws ProcessException, InterruptedException {
3534
try {
3635
SEMAPHORE.acquire();
37-
process = new ProcessBuilder(command).start();
38-
var processExited = process.waitFor(1, MINUTES);
36+
var process = new ProcessBuilder(command).redirectErrorStream(true).start();
3937

40-
if (!processExited || process.exitValue() != 0) {
41-
var reason = processExited ? "successfully" : "in time";
42-
var output = readStream(process.getErrorStream());
43-
throw new ProcessException("The command {} couldn't complete {}\n{}", command[0], reason, output);
38+
var output = new LinkedList<String>();
39+
try (var reader = process.inputReader(UTF_8)) {
40+
reader.lines().forEach(output::add);
4441
}
4542

46-
return readProcessOutput(process);
47-
} catch (IOException | InterruptedException e) {
43+
var exitCode = process.waitFor();
44+
if (exitCode != 0) {
45+
process.destroy();
46+
var lines = String.join("\n", output);
47+
throw new ProcessException("The command {} exited with code {}\n{}", command[0], exitCode, lines);
48+
}
49+
50+
return output;
51+
} catch (IOException e) {
4852
throw new ProcessException(e);
4953
} finally {
5054
SEMAPHORE.release();
51-
if (process != null) {
52-
process.destroy();
53-
}
5455
}
5556
}
5657

57-
/**
58-
* Processes the content of the stream and retrieves its UTF-8 string representation.
59-
*
60-
* @param stream the stream to be decoded
61-
* @return the UTF-8 representation of passed-in stream
62-
* @throws IOException if an error occurs reading stream's bytes
63-
*/
64-
private static String readStream(InputStream stream) throws IOException {
65-
return new String(stream.readAllBytes(), UTF_8);
66-
}
67-
68-
/**
69-
* Reads the content of the input stream.
70-
* If the input stream is empty, the content of the error stream is returned.
71-
*
72-
* @param process the process
73-
* @return the output of the process
74-
* @throws IOException if an error occurs reading stream's bytes
75-
*/
76-
private static String readProcessOutput(Process process) throws IOException {
77-
var inputStream = readStream(process.getInputStream());
78-
var output = inputStream.isEmpty() ? readStream(process.getErrorStream()) : inputStream;
79-
80-
return output.trim();
81-
}
82-
8358
private ProcessHelper() {
8459
throw new UnsupportedOperationException();
8560
}

0 commit comments

Comments
 (0)