Established a connection between the Interface and the browser.

All we're doing right now is pinging, but it should be fairly simple to get an API working now that the browser and interface can talk.
This commit is contained in:
Markil3
2021-07-29 11:37:07 -07:00
parent 1321549ef3
commit 105c89b615
25 changed files with 1236 additions and 118 deletions

View File

@@ -4,11 +4,20 @@
package edu.regis.universeplayer.browser;
import edu.regis.universeplayer.Player;
import edu.regis.universeplayer.browserCommands.*;
import edu.regis.universeplayer.data.Song;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.IOException;
import java.io.*;
import java.net.ConnectException;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.LinkedList;
import java.util.Scanner;
import java.util.concurrent.*;
/**
* This serves as a central point for controlling the browser process.
@@ -16,23 +25,88 @@ import java.io.IOException;
* @author William Hubbard
* @since 0.1
*/
public class Browser
public class Browser extends MessageRunner implements Player<InternetSong>
{
private static Logger logger = LoggerFactory.getLogger(Browser.class);
private static final Logger logger = LoggerFactory.getLogger(Browser.class);
private final Socket socket;
private final Process process;
private static Process process;
public static Browser createBrowser() throws IOException, InterruptedException
{
/*
* The maximum number of attempts that will be made to establish a
* connection.
*/
final int MAX_ATTEMPTS = 20;
/*
* How long the thread will sleep between connection attempts, in
* milliseconds.
*/
final long SLEEP_TIME = 500;
int startExit;
Socket socket = null;
Browser browser;
Process browserProcess = launchBrowser();
/*
* Wait for the browser to fully start.
*/
startExit = browserProcess.waitFor();
if (startExit != 0)
{
logger.error("Error in browser launch (exit code {})", startExit);
try (Scanner scanner = new Scanner(browserProcess.getErrorStream()))
{
while (scanner.hasNextLine())
{
logger.error(scanner.nextLine());
}
}
throw new IOException("Error in browser launch (exit code " + startExit + ")");
}
logger.debug("Browser started.");
ConnectException connErr = null;
logger.debug("Attempting connection");
for (int attempts = 0; socket == null && attempts < MAX_ATTEMPTS; attempts++)
{
try
{
socket = new Socket(BrowserConstants.IP, BrowserConstants.PORT);
}
catch (ConnectException e)
{
connErr = e;
logger.debug("Connection attempt {} failed, trying again", attempts);
Thread.sleep(SLEEP_TIME);
}
}
if (socket == null)
{
throw connErr;
}
logger.debug("Browser connection established.");
browser = new Browser(socket, browserProcess);
return browser;
}
private Browser(Socket socket, Process process) throws IOException
{
super("BrowserRunner", socket.getInputStream(), socket.getOutputStream());
this.socket = socket;
this.process = process;
}
/**
* Utility method for launching a browser instance
*
* @throws IOException - Thrown if there is a problem launching the browser.
*/
public static void launchBrowser() throws IOException
private static Process launchBrowser() throws IOException
{
Process process = null;
String os = System.getProperty("os.name").toLowerCase();
String arch = System.getProperty("os.arch").toLowerCase();
String args;
int startExit;
File browserDir = new File(System.getProperty("user.dir"), "browser");
if (!browserDir.exists())
@@ -46,12 +120,12 @@ public class Browser
{
if (arch.contains("64"))
{
logger.info("Starting Windows x86_64 browser");
logger.debug("Starting Windows x86_64 browser");
process = Runtime.getRuntime().exec(new File(browserDir, "windows64/firefox.exe").getAbsolutePath() + args);
}
else
{
logger.info("Starting Windows x86 browser");
logger.debug("Starting Windows x86 browser");
process = Runtime.getRuntime().exec(new File(browserDir, "windows32/firefox.exe").getAbsolutePath() + args);
}
}
@@ -59,12 +133,12 @@ public class Browser
{
if (arch.contains("64"))
{
logger.info("Starting Linux x86_64 browser");
logger.debug("Starting Linux x86_64 browser");
process = Runtime.getRuntime().exec(new File(browserDir, "linux64/firefox").getAbsolutePath() + args);
}
else
{
logger.info("Starting Linux 86 browser");
logger.debug("Starting Linux 86 browser");
process = Runtime.getRuntime().exec(new File(browserDir, "linux32/firefox").getAbsolutePath() + args);
}
}
@@ -72,12 +146,35 @@ public class Browser
{
throw new IOException("Could not find Firefox installation for OS " + os + " " + arch);
}
return process;
}
@Override
public Song getCurrentSong()
{
return null;
}
@Override
public QueryFuture<Void> loadSong(InternetSong song)
{
try
{
return new ForwardedFuture<Void>(this.sendObject(new CommandLoadSong(song.location)));
}
catch (IOException e)
{
logger.error("Could not send message", e);
return null;
}
}
/**
* Tells the browser process to shut down.
*/
public static void closeBrowser()
@Override
public QueryFuture<Void> close()
{
if (process != null)
{
@@ -89,5 +186,118 @@ public class Browser
{
logger.info("Process already destroyed.");
}
try
{
this.socket.close();
}
catch (IOException e)
{
logger.error("Could not close browser socket", e);
}
return null;
}
@Override
public QueryFuture<Void> play()
{
return null;
}
@Override
public QueryFuture<Void> pause()
{
return null;
}
@Override
public QueryFuture<Void> togglePlayback()
{
return null;
}
@Override
public QueryFuture<Void> seek(float time)
{
return null;
}
@Override
public QueryFuture<Boolean> isPaused()
{
return null;
}
@Override
public QueryFuture<Float> getCurrentTime()
{
return null;
}
@Override
public QueryFuture<Float> getLength()
{
return null;
}
private class ForwardedFuture<T> implements QueryFuture<T>
{
private final Future future;
ForwardedFuture(Future future)
{
this.future = future;
}
private CommandReturn<T> getVal() throws ExecutionException, InterruptedException
{
return ((CommandReturn<T>) this.future.get());
}
private CommandReturn<T> getVal(long timeout, TimeUnit unit) throws ExecutionException, InterruptedException, TimeoutException
{
return ((CommandReturn<T>) this.future.get(timeout, unit));
}
@Override
public CommandConfirmation getConfirmation() throws CancellationException, ExecutionException, InterruptedException
{
return this.getVal().getConfirmation();
}
@Override
public CommandConfirmation getConfirmation(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException
{
return this.getVal(timeout, unit).getConfirmation();
}
@Override
public boolean cancel(boolean mayInterruptIfRunning)
{
return this.future.cancel(mayInterruptIfRunning);
}
@Override
public boolean isCancelled()
{
return this.future.isCancelled();
}
@Override
public boolean isDone()
{
return this.future.isDone();
}
@Override
public T get() throws InterruptedException, ExecutionException
{
return this.getVal().getReturnValue();
}
@Override
public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException
{
return this.getVal(timeout, unit).getReturnValue();
}
}
}