Adds a system for transferring console input between the main instance and remote consoles.

This will allow the main interface to dynamically prompt the user for further information.
This commit is contained in:
Markil3
2021-11-13 10:48:11 -07:00
parent 6ef844c8b8
commit d2473d3873
2 changed files with 261 additions and 11 deletions

View File

@@ -13,6 +13,7 @@ import java.util.*;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
/** /**
* This runner is used to handle other instances of the program wanting to * This runner is used to handle other instances of the program wanting to
@@ -46,7 +47,48 @@ public class InstanceConnector implements Runnable
{ {
ObjectInputStream scanner = new ObjectInputStream(socket.getInputStream()); ObjectInputStream scanner = new ObjectInputStream(socket.getInputStream());
PrintStream stream = new PrintStream(socket.getOutputStream()); PrintStream stream = new PrintStream(socket.getOutputStream());
PipedOutputStream consoleInProxy = new PipedOutputStream();
PipedInputStream consoleInput = new PipedInputStream(consoleInProxy);
AtomicBoolean consoleRunning = new AtomicBoolean(true);
AtomicInteger consoleCode = new AtomicInteger(0);
Thread consoleRunner = new Thread(() ->
{
try (PrintStream consoleStream = new PrintStream(consoleInProxy))
{
synchronized (consoleCode)
{
while (consoleRunning.get())
{
consoleCode.set(scanner.readInt());
consoleCode.notifyAll();
if (consoleCode.get() == 5)
{
consoleStream.println((String) scanner.readObject());
}
else if (consoleCode.get() == -1)
{
break;
}
}
}
}
catch (IOException | ClassNotFoundException e)
{
if (!(e instanceof EOFException))
{
logger.error("Error reading remote console input", e);
}
synchronized (consoleCode)
{
consoleCode.set(-1);
consoleCode.notifyAll();
}
}
}, "ConsoleRunner");
CommandLine cmd = (CommandLine) scanner.readObject(); CommandLine cmd = (CommandLine) scanner.readObject();
consoleRunner.start();
logger.debug("Receiving commands: " + Arrays.toString(cmd.getArgs())); logger.debug("Receiving commands: " + Arrays.toString(cmd.getArgs()));
if (cmd.hasOption("help")) if (cmd.hasOption("help"))
{ {
@@ -55,7 +97,7 @@ public class InstanceConnector implements Runnable
else else
{ {
PlayerEnvironment.runArguments(cmd, PlayerEnvironment.runArguments(cmd,
stream); stream, consoleInput);
} }
/* /*
* Wait for the client to acknowledge the print * Wait for the client to acknowledge the print
@@ -63,7 +105,20 @@ public class InstanceConnector implements Runnable
*/ */
stream.println(); stream.println();
stream.println("END"); stream.println("END");
scanner.readInt(); synchronized (consoleCode)
{
while (consoleCode.get() != -1)
{
try
{
consoleCode.wait();
}
catch (InterruptedException e)
{
logger.error("Interrupted while waiting for remote to confirm exit", e);
}
}
}
logger.debug("Finished request"); logger.debug("Finished request");
} }
catch (EOFException e) catch (EOFException e)

View File

@@ -9,14 +9,12 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import javax.swing.*; import javax.swing.*;
import java.io.IOException; import java.io.*;
import java.io.ObjectOutputStream;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.net.Socket; import java.net.Socket;
import java.util.*; import java.util.*;
import java.util.concurrent.ForkJoinPool; import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask; import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors; import java.util.stream.Collectors;
/** /**
@@ -95,23 +93,62 @@ public class PlayerEnvironment
String data; String data;
Socket socket; Socket socket;
boolean success = false; boolean success = false;
AtomicBoolean streamRunning = new AtomicBoolean(true);
Thread inputRunner;
try try
{ {
socket = new Socket("localhost", ConfigManager.PORT); socket = new Socket("localhost", ConfigManager.PORT);
ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream()); ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream());
Scanner in = new Scanner(socket.getInputStream()); Scanner remoteOut = new Scanner(socket.getInputStream());
logger.debug("Connecting to remote"); logger.debug("Connecting to remote");
out.writeObject(args); out.writeObject(args);
logger.debug("Waiting for output"); /*
while (in.hasNextLine()) * Start a stream for
*/
inputRunner = new Thread(() -> {
Scanner sysIn = new Scanner(System.in);
String line;
while (streamRunning.get())
{ {
data = in.nextLine(); if (sysIn.hasNextLine())
{
line = sysIn.nextLine();
try
{
out.writeInt(5);
out.writeObject(line);
}
catch (IOException e)
{
logger.error("Could not write console input to remote instance", e);
}
}
else
{
try
{
Thread.sleep(100);
}
catch (InterruptedException e)
{
logger.error("Error in input runner while sleeping", e);
}
}
}
sysIn.close();
}, "InputRunner");
inputRunner.start();
logger.debug("Waiting for output");
while (remoteOut.hasNextLine())
{
data = remoteOut.nextLine();
if (data.equals("END")) if (data.equals("END"))
{ {
break; break;
} }
System.out.println(data); System.out.println(data);
} }
streamRunning.set(false);
success = true; success = true;
logger.debug("Finished reading return output."); logger.debug("Finished reading return output.");
out.writeInt(-1); out.writeInt(-1);
@@ -223,7 +260,7 @@ public class PlayerEnvironment
/* /*
* Open up the relevant songs * Open up the relevant songs
*/ */
runArguments(cmd, System.out); runArguments(cmd, System.out, System.in);
/* /*
* Stops the interface connector and shut down players as needed when we * Stops the interface connector and shut down players as needed when we
@@ -304,6 +341,52 @@ public class PlayerEnvironment
.desc("Searches the library for songs matching the arguments, instead of enqueuing them.") .desc("Searches the library for songs matching the arguments, instead of enqueuing them.")
.build(); .build();
OPTIONS.addOption(search); OPTIONS.addOption(search);
Option addAlbum = Option.builder().longOpt("addAlbum")
.hasArg().optionalArg(true).argName("name")
.desc("Adds an album to the library")
.build();
OPTIONS.addOption(addAlbum);
Option addRemote = Option.builder().longOpt("add")
.numberOfArgs(6).argName("url title artist1;artist2 track disc albumName")
.desc("Adds an internet song to the library.")
.build();
OPTIONS.addOption(addRemote);
Option name = Option.builder().longOpt("name")
.hasArg().argName("title")
.desc("Used for searching and adding elements to specify the name of what song you want to find/add.")
.build();
OPTIONS.addOption(name);
Option artists = Option.builder("a").longOpt("artist")
.hasArg().argName("artist1;artist2")
.desc("A semicolon-separated list used for searching and adding elements to specify artists to find/add to your element.")
.build();
OPTIONS.addOption(artists);
Option year = Option.builder("y").longOpt("year")
.hasArg().argName("year")
.desc("Used for searching and adding elements to specify the year of the album to find/add.")
.build();
OPTIONS.addOption(year);
Option genres = Option.builder("g").longOpt("genre")
.hasArg().argName("genre1;genre2")
.desc("A semicolon-separated list used for searching and adding elements to specify genres to find/add to your album.")
.build();
OPTIONS.addOption(genres);
Option albumName = Option.builder("b").longOpt("album")
.hasArg().argName("name")
.desc("Used for searching and adding songs to specify the name of the album to find/add to.")
.build();
OPTIONS.addOption(albumName);
Option track = Option.builder().longOpt("track")
.hasArg().argName("trackNum")
.desc("Used for searching and adding elements to specify the track number of the song or the number of tracks in the album, depending on the context.")
.build();
OPTIONS.addOption(track);
Option disc = Option.builder("d").longOpt("disc")
.hasArg().argName("discNum")
.desc("Used for searching and adding elements to specify the disc the song is on or the number of discs in the album, depending on the context.")
.build();
OPTIONS.addOption(disc);
} }
return OPTIONS; return OPTIONS;
} }
@@ -316,7 +399,7 @@ public class PlayerEnvironment
* is just as likely going to be outputting to another program * is just as likely going to be outputting to another program
* instance. * instance.
*/ */
public static void runArguments(CommandLine cmd, PrintStream out) public static void runArguments(CommandLine cmd, PrintStream out, InputStream in)
{ {
try try
{ {
@@ -408,6 +491,118 @@ public class PlayerEnvironment
out.print(" "); out.print(" ");
out.println(song.toString()); out.println(song.toString());
} }
}
case "addAlbum" -> {
String albumName = op.getValue();
String[] artists = null;
String[] genres = null;
int year = -1;
int tracks = -1;
int discs = -1;
if (albumName == null)
{
if (cmd.hasOption("name"))
{
albumName = cmd.getOptionValue("name");
}
if (albumName == null)
{
if (cmd.hasOption("album"))
{
albumName = cmd.getOptionValue("album");
}
}
}
if (cmd.hasOption("artist") && cmd.getOptionValue("artist") != null)
{
artists = cmd.getOptionValue("artist").split("\\s*;\\s*");
}
if (cmd.hasOption("genre") && cmd.getOptionValue("genre") != null)
{
genres = cmd.getOptionValue("genre").split("\\s*;\\s*");
}
if (cmd.hasOption("year") && cmd.getOptionValue("year") != null)
{
year = Integer.parseInt(cmd.getOptionValue("year"));
}
if (cmd.hasOption("track") && cmd.getOptionValue("track") != null)
{
tracks = Integer.parseInt(cmd.getOptionValue("track"));
}
if (cmd.hasOption("disc") && cmd.getOptionValue("disc") != null)
{
discs = Integer.parseInt(cmd.getOptionValue("disc"));
}
/*
* Prompt the user for missing information
*/
try (Scanner scanner = new Scanner(in))
{
if (albumName == null)
{
out.println("What is the name of the album: ");
albumName = scanner.nextLine();
}
if (artists == null)
{
out.println("Please enter the album artists as a semicolon-separated list: ");
artists = scanner.nextLine().split("\\s*;\\s*");
}
if (genres == null)
{
out.println("Please enter the genres as a semicolon-separated list: ");
genres = scanner.nextLine().split("\\s*;\\s*");
}
while (year == -1)
{
out.println("Please enter the album year: ");
try
{
year = Integer.parseInt(scanner.nextLine());
}
catch (NumberFormatException e)
{
out.println("Invalid number entered.");
}
}
while (tracks == -1)
{
out.println("Please enter the number of tracks on the album: ");
try
{
tracks = Integer.parseInt(scanner.nextLine());
}
catch (NumberFormatException e)
{
out.println("Invalid number entered.");
}
}
while (discs == -1)
{
out.println("Please enter the number of discs on the album: ");
try
{
discs = Integer.parseInt(scanner.nextLine());
}
catch (NumberFormatException e)
{
out.println("Invalid number entered.");
}
}
}
Album album = new Album();
album.name = albumName;
album.artists = artists;
album.genres = genres;
album.year = year;
album.totalTracks = tracks;
album.totalDiscs = discs;
out.println(album.toString());
}
case "add" -> {
} }
} }
} }