mirror of
https://github.com/PhotonVision/photonvision
synced 2026-06-24 01:31:44 +00:00
Initial 3.0 Commit
This commit is contained in:
@@ -0,0 +1,12 @@
|
||||
package com.chameleonvision.common.configuration;
|
||||
|
||||
public class ConfigFile {
|
||||
|
||||
/**
|
||||
* Represents a config file at a fixed path
|
||||
* @param path Path to config file
|
||||
*/
|
||||
public ConfigFile(String path) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.chameleonvision.common.configuration;
|
||||
|
||||
public class ConfigFolder {
|
||||
|
||||
/**
|
||||
* Represents a folder of config files
|
||||
* @param path path to config file
|
||||
*/
|
||||
public ConfigFolder(String path) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.chameleonvision.common.configuration;
|
||||
|
||||
import com.chameleonvision.common.server.configuration.MainConfig;
|
||||
|
||||
public class ConfigManager {
|
||||
|
||||
private final ConfigFolder rootFolder;
|
||||
final MainConfig mainConfig;
|
||||
|
||||
protected ConfigManager() {
|
||||
|
||||
rootFolder = new ConfigFolder("");
|
||||
|
||||
mainConfig = MainConfig.getInstance();
|
||||
}
|
||||
|
||||
private static class SingletonHolder {
|
||||
private static final ConfigManager INSTANCE = new ConfigManager();
|
||||
}
|
||||
|
||||
public static ConfigManager getInstance() {
|
||||
return SingletonHolder.INSTANCE;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
package com.chameleonvision.common.network;
|
||||
|
||||
import org.apache.commons.io.FileUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.SocketException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class LinuxNetworking extends SysNetworking {
|
||||
private static final String PATH = "/etc/dhcpcd.conf";
|
||||
|
||||
@Override
|
||||
public boolean setDHCP() {
|
||||
File dhcpConf = new File(PATH);
|
||||
if (dhcpConf.exists()) {
|
||||
try {
|
||||
List<String> lines = FileUtils.readLines(dhcpConf, StandardCharsets.UTF_8);
|
||||
for (int i = 0; i < lines.size(); i++) {
|
||||
String line = lines.get(i);
|
||||
if (line.startsWith("interface " + networkInterface.name)) {
|
||||
lines.remove(i);
|
||||
for (int j = i; j < lines.size(); j++) {
|
||||
String subInterface = lines.get(j);
|
||||
if (subInterface.contains("static ip_address") || subInterface.contains("static routers")) {
|
||||
lines.remove(j);
|
||||
j--;
|
||||
}
|
||||
if (subInterface.contains("interface")) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
FileUtils.writeLines(dhcpConf, lines);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
|
||||
} else {
|
||||
System.err.println("dhcpcd5 is not installed, unable to set IP.");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setHostname(String newHostname) {
|
||||
try {
|
||||
var setHostnameRetCode = shell.execute("hostnamectl", "set-hostname", newHostname);
|
||||
return setHostnameRetCode == 0;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setStatic(String ipAddress, String netmask, String gateway) {
|
||||
setDHCP(); // clean up old static interface
|
||||
File dhcpConf = new File(PATH);
|
||||
try {
|
||||
List<String> lines = FileUtils.readLines(dhcpConf, StandardCharsets.UTF_8);
|
||||
lines.add("interface " + networkInterface.name);
|
||||
InetAddress iNetMask = InetAddress.getByName(netmask);
|
||||
int prefix = convertNetmaskToCIDR(iNetMask);
|
||||
lines.add("static ip_address=" + ipAddress + "/" + prefix);
|
||||
lines.add("static routers=" + gateway);
|
||||
FileUtils.writeLines(dhcpConf, lines);
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<java.net.NetworkInterface> getNetworkInterfaces() throws SocketException {
|
||||
List<java.net.NetworkInterface> netInterfaces;
|
||||
try {
|
||||
netInterfaces = Collections.list(java.net.NetworkInterface.getNetworkInterfaces());
|
||||
} catch (SocketException e) {
|
||||
return null;
|
||||
}
|
||||
List<java.net.NetworkInterface> goodInterfaces = new ArrayList<>();
|
||||
|
||||
for (var netInterface : netInterfaces) {
|
||||
if (netInterface.getDisplayName().contains("lo")) continue;
|
||||
if (!netInterface.isUp()) continue;
|
||||
goodInterfaces.add(netInterface);
|
||||
}
|
||||
return goodInterfaces;
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package com.chameleonvision.common.network;
|
||||
|
||||
import java.net.InterfaceAddress;
|
||||
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
public class NetworkInterface {
|
||||
public final String name;
|
||||
public final String displayName;
|
||||
public final String IPAddress;
|
||||
public final String Netmask;
|
||||
public final String Gateway;
|
||||
public final String Broadcast;
|
||||
|
||||
public NetworkInterface(java.net.NetworkInterface inetface, InterfaceAddress ifaceAddress) {
|
||||
name = inetface.getName();
|
||||
displayName = inetface.getDisplayName();
|
||||
|
||||
var inetAddress = ifaceAddress.getAddress();
|
||||
IPAddress = inetAddress.getHostAddress();
|
||||
Netmask = getIPv4LocalNetMask(ifaceAddress);
|
||||
|
||||
// TODO: (low) hack to "get" gateway, this is gross and bad, pls fix
|
||||
var splitIPAddr = IPAddress.split("\\.");
|
||||
splitIPAddr[3] = "1";
|
||||
Gateway = String.join(".", splitIPAddr);
|
||||
splitIPAddr[3] = "255";
|
||||
Broadcast = String.join(".", splitIPAddr);
|
||||
}
|
||||
|
||||
private static String getIPv4LocalNetMask(InterfaceAddress interfaceAddress) {
|
||||
var netPrefix = interfaceAddress.getNetworkPrefixLength();
|
||||
try {
|
||||
// Since this is for IPv4, it's 32 bits, so set the sign value of
|
||||
// the int to "negative"...
|
||||
int shiftby = (1<<31);
|
||||
// For the number of bits of the prefix -1 (we already set the sign bit)
|
||||
for (int i = netPrefix - 1; i > 0; i--) {
|
||||
// Shift the sign right... Java makes the sign bit sticky on a shift...
|
||||
// So no need to "set it back up"...
|
||||
shiftby = (shiftby >> 1);
|
||||
}
|
||||
// Transform the resulting value in xxx.xxx.xxx.xxx format, like if
|
||||
/// it was a standard address...
|
||||
// Return the address thus created...
|
||||
return ((shiftby >> 24) & 255) + "." + ((shiftby >> 16) & 255) + "." + ((shiftby >> 8) & 255) + "." + (shiftby & 255);
|
||||
// return InetAddress.getByName(maskString);
|
||||
}
|
||||
catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
// Something went wrong here...
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.chameleonvision.common.network;
|
||||
|
||||
public class NetworkManager {
|
||||
private NetworkManager() {}
|
||||
|
||||
private static class SingletonHolder {
|
||||
private static final NetworkManager INSTANCE = new NetworkManager();
|
||||
}
|
||||
|
||||
public static NetworkManager getInstance() {
|
||||
return SingletonHolder.INSTANCE;
|
||||
}
|
||||
|
||||
private boolean isManaged = false;
|
||||
|
||||
public void initialize(boolean shouldManage) {
|
||||
isManaged = shouldManage;
|
||||
if (!isManaged) {
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package com.chameleonvision.common.network;
|
||||
|
||||
public enum NetworkMode {
|
||||
DHCP,
|
||||
STATIC
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package com.chameleonvision.common.network;
|
||||
|
||||
import com.chameleonvision.common.server.util.ShellExec;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.SocketException;
|
||||
import java.util.List;
|
||||
|
||||
public abstract class SysNetworking {
|
||||
NetworkInterface networkInterface;
|
||||
ShellExec shell = new ShellExec(true, true);
|
||||
|
||||
private String hostname = getHostname();
|
||||
|
||||
public String getHostname() {
|
||||
if (hostname == null) {
|
||||
try {
|
||||
var retCode = shell.execute("hostname", null, true);
|
||||
if (retCode == 0) {
|
||||
while(!shell.isOutputCompleted()) {}
|
||||
return shell.getOutput();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
return null;
|
||||
}
|
||||
} else return hostname;
|
||||
}
|
||||
|
||||
//code belongs to https://stackoverflow.com/questions/19531411/calculate-cidr-from-a-given-netmask-java
|
||||
public static int convertNetmaskToCIDR(InetAddress netmask) {
|
||||
|
||||
byte[] netmaskBytes = netmask.getAddress();
|
||||
int cidr = 0;
|
||||
boolean zero = false;
|
||||
for (byte b : netmaskBytes) {
|
||||
int mask = 0x80;
|
||||
|
||||
for (int i = 0; i < 8; i++) {
|
||||
int result = b & mask;
|
||||
if (result == 0) {
|
||||
zero = true;
|
||||
} else if (zero) {
|
||||
throw new IllegalArgumentException("Invalid netmask.");
|
||||
} else {
|
||||
cidr++;
|
||||
}
|
||||
mask >>>= 1;
|
||||
}
|
||||
}
|
||||
return cidr;
|
||||
}
|
||||
|
||||
public void setNetworkInterface(NetworkInterface networkInterface) {
|
||||
this.networkInterface = networkInterface;
|
||||
}
|
||||
public abstract boolean setDHCP();
|
||||
public abstract boolean setHostname(String hostname);
|
||||
public abstract boolean setStatic(String ipAddress, String netmask, String gateway);
|
||||
public abstract List<java.net.NetworkInterface> getNetworkInterfaces() throws SocketException;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.chameleonvision.common.server.configuration;
|
||||
|
||||
import com.chameleonvision.common.configuration.ConfigFile;
|
||||
|
||||
public class MainConfig extends ConfigFile {
|
||||
|
||||
public int teamNumber = 0;
|
||||
public boolean ntServer = false;
|
||||
|
||||
private MainConfig() {
|
||||
super("general");
|
||||
}
|
||||
|
||||
private static class SingletonHolder {
|
||||
private static final MainConfig INSTANCE = new MainConfig();
|
||||
}
|
||||
|
||||
public static MainConfig getInstance() {
|
||||
return SingletonHolder.INSTANCE;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.chameleonvision.common.server.configuration;
|
||||
|
||||
import com.chameleonvision.common.configuration.ConfigFile;
|
||||
import com.chameleonvision.common.network.NetworkMode;
|
||||
|
||||
public class NetworkConfig extends ConfigFile {
|
||||
|
||||
public NetworkMode networkMode = NetworkMode.DHCP;
|
||||
public String ip = "";
|
||||
public String hostname = "chameleon-vision";
|
||||
|
||||
private NetworkConfig() {
|
||||
super("network");
|
||||
}
|
||||
|
||||
private static class SingletonHolder {
|
||||
private static final NetworkConfig INSTANCE = new NetworkConfig();
|
||||
}
|
||||
|
||||
public static NetworkConfig getInstance() {
|
||||
return SingletonHolder.INSTANCE;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
package com.chameleonvision.common.server.util;
|
||||
|
||||
import edu.wpi.first.wpiutil.RuntimeDetector;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public enum Platform {
|
||||
// WPILib Supported (JNI)
|
||||
WINDOWS_32("Windows x32"),
|
||||
WINDOWS_64("Windows x64"),
|
||||
LINUX_64("Linux x64"),
|
||||
LINUX_RASPBIAN("Linux Raspbian"), // Raspberry Pi 3/4
|
||||
LINUX_AARCH64BIONIC("Linux AARCH64 Bionic"), // Jetson Nano, Jetson TX2
|
||||
MACOS_64("Mac OS x64"),
|
||||
|
||||
// ChameleonVision Supported (Manual install)
|
||||
LINUX_ARM32("Linux ARM32"), // ODROID XU4, C1+
|
||||
LINUX_ARM64("Linux ARM64"), // ODROID C2, N2
|
||||
|
||||
// Completely unsupported
|
||||
UNSUPPORTED("Unsupported Platform");
|
||||
|
||||
public final String value;
|
||||
public final boolean isRoot = checkForRoot();
|
||||
|
||||
Platform(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
private static final String OS_NAME = System.getProperty("os.name");
|
||||
private static final String OS_ARCH = System.getProperty("os.arch");
|
||||
public static final Platform CurrentPlatform = getCurrentPlatform();
|
||||
|
||||
private static String UnknownPlatformString = String.format("Unknown Platform. OS: %s, Architecture: %s", OS_NAME, OS_ARCH);
|
||||
|
||||
public boolean isWindows() {
|
||||
return this == WINDOWS_64 || this == WINDOWS_32;
|
||||
}
|
||||
|
||||
public boolean isLinux() {
|
||||
return this == LINUX_64 || this == LINUX_RASPBIAN || this == LINUX_ARM64;
|
||||
}
|
||||
|
||||
public boolean isMac() {
|
||||
return this == MACOS_64;
|
||||
}
|
||||
|
||||
public static boolean isRaspberryPi() {
|
||||
return CurrentPlatform.equals(LINUX_RASPBIAN);
|
||||
}
|
||||
|
||||
private static ShellExec shell = new ShellExec(true, false);
|
||||
|
||||
@SuppressWarnings("StatementWithEmptyBody")
|
||||
private boolean checkForRoot() {
|
||||
if (isLinux() || isMac()) {
|
||||
try {
|
||||
shell.execute("id", null, true, "-u");
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
// TODO: better way to do this?
|
||||
while (!shell.isOutputCompleted()) {
|
||||
// ignored
|
||||
}
|
||||
|
||||
if (shell.getExitCode() == 0) {
|
||||
return shell.getOutput().split("\n")[0].equals("0");
|
||||
}
|
||||
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static Platform getCurrentPlatform() {
|
||||
if (RuntimeDetector.isWindows()) {
|
||||
if (RuntimeDetector.is32BitIntel()) return WINDOWS_32;
|
||||
if (RuntimeDetector.is64BitIntel()) return WINDOWS_64;
|
||||
}
|
||||
|
||||
if (RuntimeDetector.isMac()) {
|
||||
if (RuntimeDetector.is32BitIntel()) return UNSUPPORTED;
|
||||
if (RuntimeDetector.is64BitIntel()) return MACOS_64;
|
||||
}
|
||||
|
||||
if (RuntimeDetector.isLinux()) {
|
||||
if (RuntimeDetector.is32BitIntel()) return UNSUPPORTED;
|
||||
if (RuntimeDetector.is64BitIntel()) return LINUX_64;
|
||||
if (RuntimeDetector.isRaspbian()) return LINUX_RASPBIAN;
|
||||
|
||||
}
|
||||
|
||||
System.out.println(UnknownPlatformString);
|
||||
return Platform.UNSUPPORTED;
|
||||
}
|
||||
|
||||
|
||||
public String toString() {
|
||||
if (this.equals(UNSUPPORTED)) {
|
||||
return UnknownPlatformString;
|
||||
} else {
|
||||
return this.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,181 @@
|
||||
package com.chameleonvision.common.server.util;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
/**
|
||||
* Execute external process and optionally read output buffer.
|
||||
*/
|
||||
@SuppressWarnings({"unused", "ConstantConditions"})
|
||||
public class ShellExec {
|
||||
private int exitCode;
|
||||
private boolean readOutput, readError;
|
||||
private StreamGobbler errorGobbler, outputGobbler;
|
||||
|
||||
public ShellExec() {
|
||||
this(false, false);
|
||||
}
|
||||
|
||||
public ShellExec(boolean readOutput, boolean readError) {
|
||||
this.readOutput = readOutput;
|
||||
this.readError = readError;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a bash command. We can handle complex bash commands including
|
||||
* multiple executions (; | && ||), quotes, expansions ($), escapes (\), e.g.:
|
||||
* "cd /abc/def; mv ghi 'older ghi '$(whoami)"
|
||||
* @param command Bash command to execute
|
||||
* @return true if bash got started, but your command may have failed.
|
||||
*/
|
||||
public int executeBashCommand(String command) throws IOException {
|
||||
boolean wait = true;
|
||||
boolean success = false;
|
||||
Runtime r = Runtime.getRuntime();
|
||||
// Use bash -c so we can handle things like multi commands separated by ; and
|
||||
// things like quotes, $, |, and \. My tests show that command comes as
|
||||
// one argument to bash, so we do not need to quote it to make it one thing.
|
||||
// Also, exec may object if it does not have an executable file as the first thing,
|
||||
// so having bash here makes it happy provided bash is installed and in path.
|
||||
String[] commands = {"bash", "-c", command};
|
||||
|
||||
Process process = r.exec(commands);
|
||||
|
||||
// Consume streams, older jvm's had a memory leak if streams were not read,
|
||||
// some other jvm+OS combinations may block unless streams are consumed.
|
||||
return doProcess(wait, process);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a command in current folder, and wait for process to end
|
||||
* @param command command ("c:/some/folder/script.bat" or "some/folder/script.sh")
|
||||
* @param args 0..n command line arguments
|
||||
* @return process exit code
|
||||
*/
|
||||
public int execute(String command, String... args) throws IOException {
|
||||
return execute(command, null, true, args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a command.
|
||||
* @param command command ("c:/some/folder/script.bat" or "some/folder/script.sh")
|
||||
* @param workdir working directory or NULL to use command folder
|
||||
* @param wait wait for process to end
|
||||
* @param args 0..n command line arguments
|
||||
* @return process exit code
|
||||
*/
|
||||
public int execute(String command, String workdir, boolean wait, String...args) throws IOException {
|
||||
String[] cmdArr;
|
||||
if (args != null && args.length > 0) {
|
||||
cmdArr = new String[1+args.length];
|
||||
cmdArr[0] = command;
|
||||
System.arraycopy(args, 0, cmdArr, 1, args.length);
|
||||
} else {
|
||||
cmdArr = new String[] { command };
|
||||
}
|
||||
|
||||
ProcessBuilder pb = new ProcessBuilder(cmdArr);
|
||||
File workingDir = (workdir==null ? new File(command).getParentFile() : new File(workdir) );
|
||||
pb.directory(workingDir);
|
||||
|
||||
Process process = pb.start();
|
||||
|
||||
// Consume streams, older jvm's had a memory leak if streams were not read,
|
||||
// some other jvm+OS combinations may block unless streams are consumed.
|
||||
return doProcess(wait, process);
|
||||
}
|
||||
|
||||
private int doProcess(boolean wait, Process process) {
|
||||
errorGobbler = new StreamGobbler(process.getErrorStream(), readError);
|
||||
outputGobbler = new StreamGobbler(process.getInputStream(), readOutput);
|
||||
errorGobbler.start();
|
||||
outputGobbler.start();
|
||||
|
||||
exitCode = 0;
|
||||
if (wait) {
|
||||
try {
|
||||
process.waitFor();
|
||||
exitCode = process.exitValue();
|
||||
} catch (InterruptedException ignored) { }
|
||||
}
|
||||
return exitCode;
|
||||
}
|
||||
|
||||
public int getExitCode() {
|
||||
return exitCode;
|
||||
}
|
||||
|
||||
public boolean isOutputCompleted() {
|
||||
return (outputGobbler != null && outputGobbler.isCompleted());
|
||||
}
|
||||
|
||||
public boolean isErrorCompleted() {
|
||||
return (errorGobbler != null && errorGobbler.isCompleted());
|
||||
}
|
||||
|
||||
public String getOutput() {
|
||||
return (outputGobbler != null ? outputGobbler.getOutput() : null);
|
||||
}
|
||||
|
||||
public String getError() {
|
||||
return (errorGobbler != null ? errorGobbler.getOutput() : null);
|
||||
}
|
||||
|
||||
//********************************************
|
||||
//********************************************
|
||||
|
||||
/**
|
||||
* StreamGobbler reads inputstream to "gobble" it.
|
||||
* This is used by Executor class when running
|
||||
* a commandline applications. Gobblers must read/purge
|
||||
* INSTR and ERRSTR process streams.
|
||||
* http://www.javaworld.com/javaworld/jw-12-2000/jw-1229-traps.html?page=4
|
||||
*/
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
private static class StreamGobbler extends Thread {
|
||||
private InputStream is;
|
||||
private StringBuilder output;
|
||||
private volatile boolean completed; // mark volatile to guarantee a thread safety
|
||||
|
||||
public StreamGobbler(InputStream is, boolean readStream) {
|
||||
this.is = is;
|
||||
this.output = (readStream ? new StringBuilder(256) : null);
|
||||
}
|
||||
|
||||
public void run() {
|
||||
completed = false;
|
||||
try {
|
||||
String NL = System.getProperty("line.separator", "\r\n");
|
||||
|
||||
InputStreamReader isr = new InputStreamReader(is);
|
||||
BufferedReader br = new BufferedReader(isr);
|
||||
String line;
|
||||
while ( (line = br.readLine()) != null) {
|
||||
if (output != null)
|
||||
output.append(line).append(NL);
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
// ex.printStackTrace();
|
||||
}
|
||||
completed = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get inputstream buffer or null if stream
|
||||
* was not consumed.
|
||||
* @return Output stream
|
||||
*/
|
||||
public String getOutput() {
|
||||
return (output != null ? output.toString() : null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is input stream completed.
|
||||
* @return if input stream is completed
|
||||
*/
|
||||
public boolean isCompleted() {
|
||||
return completed;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package com.chameleonvision.common.server.util;
|
||||
|
||||
import org.apache.commons.exec.*;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
// TODO: Finish me!
|
||||
@SuppressWarnings({"FieldCanBeLocal", "unused"})
|
||||
public class ShellExecutor {
|
||||
|
||||
private final Executor executor;
|
||||
private final ExecuteWatchdog watchdog;
|
||||
private final DefaultExecuteResultHandler resultHandler = new DefaultExecuteResultHandler();
|
||||
private final OutputStream stdOutStream = new ByteArrayOutputStream();
|
||||
private final OutputStream stdErrStream = new ByteArrayOutputStream();
|
||||
private final boolean block;
|
||||
|
||||
public ShellExecutor(String command, boolean block, int timeoutMillis, String... args) {
|
||||
this.block = block;
|
||||
|
||||
CommandLine cmdLine = new CommandLine(command);
|
||||
cmdLine.addArguments(args);
|
||||
|
||||
watchdog = new ExecuteWatchdog(timeoutMillis);
|
||||
executor = new DefaultExecutor();
|
||||
executor.setWatchdog(watchdog);
|
||||
executor.setStreamHandler(new PumpStreamHandler(stdOutStream, stdErrStream));
|
||||
}
|
||||
|
||||
// public int execute() {
|
||||
// if ()
|
||||
// }
|
||||
|
||||
public String getStdOut() {
|
||||
if (!watchdog.isWatching()) {
|
||||
return executor.toString();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
public String getStdErr() {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package com.chameleonvision.common.vision.base.camera;
|
||||
|
||||
import com.chameleonvision.common.vision.base.capture.USBFrameProvider;
|
||||
|
||||
public class USBCamera extends USBFrameProvider {
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.chameleonvision.common.vision.base.capture;
|
||||
|
||||
import com.chameleonvision.common.vision.base.frame.Frame;
|
||||
import com.chameleonvision.common.vision.base.frame.FrameProvider;
|
||||
import org.apache.commons.lang3.NotImplementedException;
|
||||
|
||||
public class FileFrameProvider implements FrameProvider {
|
||||
@Override
|
||||
public Frame getFrame() {
|
||||
throw new NotImplementedException("");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.chameleonvision.common.vision.base.capture;
|
||||
|
||||
import com.chameleonvision.common.vision.base.frame.Frame;
|
||||
import com.chameleonvision.common.vision.base.frame.FrameProvider;
|
||||
import org.apache.commons.lang3.NotImplementedException;
|
||||
|
||||
public class NetworkFrameProvider implements FrameProvider {
|
||||
@Override
|
||||
public Frame getFrame() {
|
||||
throw new NotImplementedException("");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.chameleonvision.common.vision.base.capture;
|
||||
|
||||
import com.chameleonvision.common.vision.base.frame.Frame;
|
||||
import com.chameleonvision.common.vision.base.frame.FrameProvider;
|
||||
import org.apache.commons.lang3.NotImplementedException;
|
||||
|
||||
public class USBFrameProvider implements FrameProvider {
|
||||
@Override
|
||||
public Frame getFrame() {
|
||||
throw new NotImplementedException("");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.chameleonvision.common.vision.base.frame;
|
||||
|
||||
import org.opencv.core.Mat;
|
||||
import org.opencv.core.Size;
|
||||
|
||||
public class Frame {
|
||||
public long timestamp;
|
||||
public Mat image;
|
||||
public Size imageSize;
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package com.chameleonvision.common.vision.base.frame;
|
||||
|
||||
public interface FrameConsumer {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package com.chameleonvision.common.vision.base.frame;
|
||||
|
||||
public interface FrameProvider {
|
||||
Frame getFrame();
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.chameleonvision.common.vision.base.pipeline;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* Defines a pipe. A pipe is a single step in a pipeline.
|
||||
* This class is to be extended, never used on its own.
|
||||
*
|
||||
* @param <I> Input type for the pipe
|
||||
* @param <O> Output type for the pipe
|
||||
*/
|
||||
public abstract class Pipe<I, O> implements Function<I, PipeResult<O>> {
|
||||
|
||||
private PipeResult<O> result = new PipeResult<>();
|
||||
|
||||
/**
|
||||
* Runs the process for the pipe.
|
||||
*
|
||||
* @param in Input for pipe processing
|
||||
* @return Result of processing
|
||||
*/
|
||||
protected abstract O process(I in);
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param in Input for pipe processing
|
||||
* @return Result of processing
|
||||
*/
|
||||
@Override
|
||||
public PipeResult<O> apply(I in) {
|
||||
long pipeStartNanos = System.nanoTime();
|
||||
result.result = process(in);
|
||||
result.nanosElapsed = System.nanoTime() - pipeStartNanos;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package com.chameleonvision.common.vision.base.pipeline;
|
||||
|
||||
public class PipeResult<O> {
|
||||
O result;
|
||||
long nanosElapsed;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.chameleonvision.common.vision.base.pipeline.pipe;
|
||||
|
||||
import com.chameleonvision.common.vision.base.pipeline.Pipe;
|
||||
import org.opencv.core.Mat;
|
||||
|
||||
public class ResizeImagePipe extends Pipe<Mat, Mat> {
|
||||
|
||||
public ResizeImagePipe() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Mat process(Mat in) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.chameleonvision.common.vision.base.pipeline.pipe.javacv;
|
||||
|
||||
import com.chameleonvision.common.vision.base.pipeline.Pipe;
|
||||
import org.bytedeco.opencv.opencv_core.GpuMat;
|
||||
|
||||
public class GPUResizeImagePipe extends Pipe<GpuMat, GpuMat> {
|
||||
|
||||
public GPUResizeImagePipe() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected GpuMat process(GpuMat in) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
package com.chameleonvision.common.vision.base.stream;
|
||||
|
||||
public class AsyncMjpgStreamer extends MjpgStreamer {
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
package com.chameleonvision.common.vision.base.stream;
|
||||
|
||||
public class MjpgStreamer {
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
package com.chameleonvision.common.vision.base.stream;
|
||||
|
||||
public interface Streamer {
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
package com.chameleonvision.common.vision.opencv;
|
||||
|
||||
public class OpenCVWrapper {
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
package com.chameleonvision.common.vision.target;
|
||||
|
||||
public class KnownTarget {
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
package com.chameleonvision.common.vision.target;
|
||||
|
||||
public class TrackedTarget {
|
||||
}
|
||||
Reference in New Issue
Block a user