diff --git a/.circleci/config.yml b/.circleci/config.yml index 341ba55a0..2e8297d7e 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -54,20 +54,10 @@ workflows: version: 2 release: jobs: - - build_ui: - filters: - branches: - only: - - master - - dev + - build_ui - build_jar: requires: - build_ui - filters: - branches: - only: - - master - - dev - deploy: requires: - build_jar diff --git a/chameleon-client/src/views/Settings.vue b/chameleon-client/src/views/Settings.vue index c67e9db41..4f8a47796 100644 --- a/chameleon-client/src/views/Settings.vue +++ b/chameleon-client/src/views/Settings.vue @@ -11,7 +11,7 @@ - +
Camera Stream
@@ -34,18 +34,13 @@ data() { return { selectedTab: 0, + tabList:[General, Cameras] } }, computed: { selectedComponent: { get() { - switch (this.selectedTab) { - case 0: - return "General"; - case 1: - return "Cameras"; - } - return ""; + return this.tabList[this.selectedTab]; } }, streamAddress: { diff --git a/chameleon-client/src/views/SettingsViewes/General.vue b/chameleon-client/src/views/SettingsViewes/General.vue index fe655c19e..46e97426b 100644 --- a/chameleon-client/src/views/SettingsViewes/General.vue +++ b/chameleon-client/src/views/SettingsViewes/General.vue @@ -1,5 +1,9 @@ @@ -25,26 +53,64 @@ CVinput }, data() { - return {} + return { + file: undefined, + snackbar: { + color: "success", + text: "" + }, + snack: false, + isLoading: false + } }, methods: { sendGeneralSettings() { const self = this; this.axios.post("http://" + this.$address + "/api/settings/general", this.settings).then( function (response) { - if (response.status === 200){ + if (response.status === 200) { self.$store.state.saveBar = true; } } ) + }, + installOrUpdate() { + let formData = new FormData(); + formData.append('file', this.file); + if (this.file !== undefined) { + this.isLoading = true; + } + this.axios.post("http://" + this.$address + "/api/install", formData, { + headers: { + 'Content-Type': 'multipart/form-data' + } + }).then(() => { + this.snackbar = { + color: "success", + text: "Installation successful" + }; + this.isLoading = false; + this.snack = true; + }).catch(error => { + this.snackbar = { + color: "error", + text: error.response.data + }; + this.isLoading = false; + this.snack = true; + }) } }, computed: { - isDisabled() { - if (this.settings.connectionType === 0) { - return true; + fileUploadText() { + if (this.file !== undefined) { + return "Install and update" + } else { + return "Install current version" } - return false; + }, + isDisabled() { + return this.settings.connectionType === 0; }, settings: { get() { diff --git a/chameleon-server/chameleon-vision.iml b/chameleon-server/chameleon-vision.iml index 9cae10245..e863282a1 100644 --- a/chameleon-server/chameleon-vision.iml +++ b/chameleon-server/chameleon-vision.iml @@ -7,47 +7,32 @@ - - - - - - - - - - - - - - - - - - - + + + + - - - + + + - - - - - - - - - - - - - + + + + + + + + + + + + + diff --git a/chameleon-server/pom.xml b/chameleon-server/pom.xml index 44cf14d3d..f2b3295e6 100644 --- a/chameleon-server/pom.xml +++ b/chameleon-server/pom.xml @@ -63,7 +63,7 @@ io.javalin javalin - 3.4.1 + RELEASE diff --git a/chameleon-server/src/main/java/com/chameleonvision/util/Helpers.java b/chameleon-server/src/main/java/com/chameleonvision/util/Helpers.java index f63f5d1e7..afc6fdde1 100644 --- a/chameleon-server/src/main/java/com/chameleonvision/util/Helpers.java +++ b/chameleon-server/src/main/java/com/chameleonvision/util/Helpers.java @@ -1,13 +1,34 @@ package com.chameleonvision.util; import edu.wpi.cscore.VideoMode; +import io.javalin.http.UploadedFile; import org.opencv.core.Scalar; import java.awt.*; +import java.io.FileWriter; +import java.io.IOException; +import java.io.Writer; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.HashMap; import java.util.Map; public class Helpers { + private static final String kServicePath = "/etc/systemd/system/chameleonVision.service"; + private static final String kServiceString = "[Unit]\n" + + "Description=chameleon vision\n" + + "\n" + + "[Service]\n" + + "ExecStart=/usr/bin/java -jar %s \n" + + "StandardOutput=file:/var/log/something.out.txt\n" + + "StandardError=file:/var/log/something.err.txt\n" + + "Type=simple\n" + + "WorkingDirectory=/usr/local/bin\n" + + "\n" + + "[Install]\n" + + "WantedBy=multi-user.target\n" + + "\n"; + private Helpers() { } @@ -17,9 +38,19 @@ public class Helpers { public static HashMap VideoModeToHashMap(VideoMode videoMode) { return new HashMap() {{ - put("width", videoMode.width); - put("height", videoMode.height); - put("fps", videoMode.fps); - put("pixelFormat", videoMode.pixelFormat.toString());}}; + put("width", videoMode.width); + put("height", videoMode.height); + put("fps", videoMode.fps); + put("pixelFormat", videoMode.pixelFormat.toString()); + }}; + } + + public static void setService(Path filePath) throws IOException, InterruptedException { + String newService = String.format(kServiceString, filePath.toString()); + Writer writer = new FileWriter(kServicePath, false); + writer.write(newService); + writer.close(); + Process p = Runtime.getRuntime().exec("systemctl enable chameleonVision.service"); + p.waitFor(); } } diff --git a/chameleon-server/src/main/java/com/chameleonvision/web/RequestHandler.java b/chameleon-server/src/main/java/com/chameleonvision/web/RequestHandler.java index 584cb48c7..c68b14835 100644 --- a/chameleon-server/src/main/java/com/chameleonvision/web/RequestHandler.java +++ b/chameleon-server/src/main/java/com/chameleonvision/web/RequestHandler.java @@ -1,9 +1,13 @@ package com.chameleonvision.web; import com.chameleonvision.Exceptions.DuplicatedKeyException; +import com.chameleonvision.Main; import com.chameleonvision.config.ConfigManager; import com.chameleonvision.network.NetworkIPMode; import com.chameleonvision.networktables.NetworkTablesManager; +import com.chameleonvision.util.Helpers; +import com.chameleonvision.util.Platform; +import com.chameleonvision.util.ProgramDirectoryUtilities; import com.chameleonvision.vision.VisionManager; import com.chameleonvision.vision.VisionProcess; import com.chameleonvision.vision.camera.USBCameraCapture; @@ -17,13 +21,19 @@ import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.ObjectMapper; import edu.wpi.cscore.VideoMode; import edu.wpi.first.wpilibj.geometry.Rotation2d; +import io.javalin.core.util.FileUtil; import io.javalin.http.Context; import io.javalin.http.Handler; +import io.javalin.http.UploadedFile; +import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.math3.ml.neuralnet.Network; import org.opencv.core.Point; import org.opencv.core.Point3; -import java.io.IOException; +import java.io.*; +import java.net.URISyntaxException; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -209,4 +219,31 @@ public class RequestHandler { ctx.status(500); } } + + public static void onInstallOrUpdate(Context ctx) { + Platform p = Platform.getCurrentPlatform(); + try { + if (p == Platform.LINUX_RASPBIAN || p == Platform.LINUX_64) { + UploadedFile file = ctx.uploadedFile("file"); + Path filePath; + if (file != null) { + filePath = Paths.get(ProgramDirectoryUtilities.getProgramDirectory(), file.getFilename()); + File target = new File(filePath.toString()); + OutputStream stream = new FileOutputStream(target); + file.getContent().transferTo(stream); + stream.close(); + } else { + filePath = Paths.get(new File(Main.class.getProtectionDomain().getCodeSource().getLocation().toURI()).getPath()); // quirk to get the current file directory + } + Helpers.setService(filePath); + ctx.status(200); + } else { + ctx.result("Only Linux Platforms Support this feature"); + ctx.status(500); + } + } catch (Exception e) { + ctx.result(e.toString()); + ctx.status(500); + } + } } diff --git a/chameleon-server/src/main/java/com/chameleonvision/web/Server.java b/chameleon-server/src/main/java/com/chameleonvision/web/Server.java index a9617edbb..1561302bf 100644 --- a/chameleon-server/src/main/java/com/chameleonvision/web/Server.java +++ b/chameleon-server/src/main/java/com/chameleonvision/web/Server.java @@ -35,6 +35,7 @@ public class Server { app.post("/api/settings/snapshot", RequestHandler::onSnapshot); app.post("/api/settings/endCalibration", RequestHandler::onCalibrationEnding); app.post("/api/vision/pnpModel", RequestHandler::onPnpModel); + app.post("/api/install", RequestHandler::onInstallOrUpdate); app.start(port); } } diff --git a/chameleon-server/src/main/java/com/chameleonvision/web/SocketHandler.java b/chameleon-server/src/main/java/com/chameleonvision/web/SocketHandler.java index d8b7b5302..da52719f1 100644 --- a/chameleon-server/src/main/java/com/chameleonvision/web/SocketHandler.java +++ b/chameleon-server/src/main/java/com/chameleonvision/web/SocketHandler.java @@ -53,8 +53,8 @@ public class SocketHandler { @SuppressWarnings("unchecked") void onBinaryMessage(WsBinaryMessageContext context) throws Exception { - Map deserialized = objectMapper.readValue(ArrayUtils.toPrimitive(context.data()), new TypeReference<>() { - }); + Map deserialized = objectMapper.readValue((byte[]) ArrayUtils.toPrimitive(context.data()), + new TypeReference<>(){}); for (Map.Entry entry : deserialized.entrySet()) { try { VisionProcess currentProcess = VisionManager.getCurrentUIVisionProcess(); @@ -266,11 +266,11 @@ public class SocketHandler { tmp.put("streamDivisor", currentVisionProcess.cameraStreamer.getDivisor().ordinal()); tmp.put("resolution", currentVisionProcess.getCamera().getProperties().getCurrentVideoModeIndex()); tmp.put("tilt", currentVisionProcess.getCamera().getProperties().getTilt().getDegrees()); - + List calibrations = currentCamera.getAllCalibrationData().stream() .map(CameraCalibrationConfig.UICameraCalibrationConfig::new).collect(Collectors.toList()); tmp.put("calibration", calibrations); - + return tmp; }