mirror of
https://github.com/PhotonVision/photonvision
synced 2026-06-20 00:51:41 +00:00
Bootup sprint (#18)
* Did some stuff * Fix gradle, start implementing mjpeg frame consumer * Did some stuff * bade changes * rename camera config to USBCameraConfiguration, add name * unrename cameraconfiguration * Add pub/sub framework * Add setResolution to mjpeg frame consumer * add NTDataConsumer * Add some totally broken hsv hacks * Start refactoring UI data * Update index.js * Commit and push, he says * Fix up some errors * Fix input tab * Fix fps * Update index.js * Add pipeline field setting, update PipelineManager, fix nullpointers and USBCameraSettables * Change v-model to point to data() * update hsv to use mutations * Work on saving, fix hsv * Rename shouldErode/shouldDilate to erode and dilate * Hook all the tabs up to the Store * Change handleData to handlePipelineData * camera quirk redo, add ICCSub to SocketHandler * Fix some property names * Fixed tons of naming in UI, fix backend for multi-val PSCs, fix PSC enums * change pipeline type to an int in store * Fix mutation naming * Attempt threshold fix * Update SocketHandler.java * Add truthy data sending * Start adding logging support * [UI] Add delay to slider input boxes (#1) * [UI] [Backend] potentially fix camera settings, various logging tweaks * Don't release raw input mat * add setVideoModeIndex to vision settables * Implement pipeline index in socket handler, add framework for renaming/changing pipes * (ish) get pipeline change working * Create index.html * Cleanups, fix pipeline index bug, fix stream res for MJPG, add dashboard stream (unused) * Refactor UI to use mutatePipeline, send pipeline results * Update NetworkConfig.java * Change double to number * Run spotless * Fix reversal of large/small comparators * Fix left/right * Fix pitch/yaw calculation bug, fix area bug * Use Vue.set instead of assignment This fixes {{ }} * Update App.vue * run spotless * Actually add pipelines and reassign indecies * Delete old pipeline configs Fixes duplication on renaming pipeline * Start working on deleting pipes * Fix camera nickname change * run spotless * Fix some test stuff * Update VisionModuleManagerTest.java * vision source manager test is still broken * Fix VisionSourceManager test * Apply spotless 2 electric boogaloo Co-authored-by: Banks Troutman <btrout.dhrs@gmail.com> Co-authored-by: Declan Freeman-Gleason <declanfreemangleason@gmail.com> Co-authored-by: Aaryan Agrawal <54345060+13Ducks@users.noreply.github.com>
This commit is contained in:
@@ -18,24 +18,54 @@
|
||||
package org.photonvision.server;
|
||||
|
||||
import io.javalin.Javalin;
|
||||
import org.photonvision.common.logging.LogGroup;
|
||||
import org.photonvision.common.logging.Logger;
|
||||
|
||||
public class Server {
|
||||
private static final Logger logger = new Logger(Server.class, LogGroup.Server);
|
||||
|
||||
public static void main(int port) {
|
||||
|
||||
Javalin app =
|
||||
Javalin.create(
|
||||
javalinConfig -> {
|
||||
javalinConfig.showJavalinBanner = false;
|
||||
javalinConfig.addStaticFiles("web");
|
||||
javalinConfig.enableCorsForAllOrigins();
|
||||
config -> {
|
||||
config.showJavalinBanner = false;
|
||||
config.addStaticFiles("web");
|
||||
config.enableCorsForAllOrigins();
|
||||
|
||||
config.requestLogger(
|
||||
(ctx, ms) ->
|
||||
logger.debug(
|
||||
"Handled HTTP "
|
||||
+ ctx.req.getMethod()
|
||||
+ " request from "
|
||||
+ ctx.req.getRemoteHost()
|
||||
+ " in "
|
||||
+ ms.toString()
|
||||
+ "ms"));
|
||||
|
||||
config.wsLogger(
|
||||
ws ->
|
||||
ws.onMessage(
|
||||
ctx -> logger.debug("Got WebSockets message: " + ctx.message())));
|
||||
|
||||
config.wsLogger(
|
||||
ws ->
|
||||
ws.onBinaryMessage(
|
||||
ctx ->
|
||||
logger.debug(
|
||||
"Got WebSockets binary message from host " + ctx.host())));
|
||||
});
|
||||
|
||||
var socketHandler = SocketHandler.getInstance();
|
||||
|
||||
/*Web Socket Events */
|
||||
app.ws(
|
||||
"/websocket",
|
||||
ws -> {
|
||||
ws.onConnect(SocketHandler::onConnect);
|
||||
ws.onClose(SocketHandler::onClose);
|
||||
ws.onBinaryMessage(SocketHandler::onBinaryMessage);
|
||||
ws.onConnect(socketHandler::onConnect);
|
||||
ws.onClose(socketHandler::onClose);
|
||||
ws.onBinaryMessage(socketHandler::onBinaryMessage);
|
||||
});
|
||||
/*API Events*/
|
||||
app.post("/api/settings/general", RequestHandler::onGeneralSettings);
|
||||
|
||||
@@ -23,49 +23,273 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import io.javalin.websocket.*;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.msgpack.jackson.dataformat.MessagePackFactory;
|
||||
import org.photonvision.common.dataflow.DataChangeDestination;
|
||||
import org.photonvision.common.dataflow.DataChangeService;
|
||||
import org.photonvision.common.dataflow.camera.IncomingCameraCommandSubscriber;
|
||||
import org.photonvision.common.dataflow.events.IncomingWebSocketEvent;
|
||||
import org.photonvision.common.logging.LogGroup;
|
||||
import org.photonvision.common.logging.Logger;
|
||||
import org.photonvision.vision.pipeline.PipelineType;
|
||||
import org.photonvision.vision.processes.PipelineManager;
|
||||
import org.photonvision.vision.processes.VisionModuleManager;
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public class SocketHandler {
|
||||
static List<WsContext> users = new ArrayList<>();
|
||||
static ObjectMapper objectMapper = new ObjectMapper(new MessagePackFactory());
|
||||
|
||||
public static void onConnect(WsConnectContext context) {
|
||||
users.add(context);
|
||||
private final Logger logger = new Logger(SocketHandler.class, LogGroup.Server);
|
||||
private final List<WsContext> users = new ArrayList<>();
|
||||
private final ObjectMapper objectMapper = new ObjectMapper(new MessagePackFactory());
|
||||
private final DataChangeService dcService = DataChangeService.getInstance();
|
||||
|
||||
@SuppressWarnings("FieldCanBeLocal")
|
||||
private final UIOutboundSubscriber uiOutboundSubscriber = new UIOutboundSubscriber(this);
|
||||
|
||||
private final IncomingCameraCommandSubscriber cameraChangeSubscriber =
|
||||
new IncomingCameraCommandSubscriber(VisionModuleManager.getInstance());
|
||||
|
||||
public static class UIMap extends HashMap<String, Object> {}
|
||||
|
||||
abstract static class SelectiveBroadcastPair extends Pair<UIMap, WsContext> {}
|
||||
|
||||
private static class ThreadSafeSingleton {
|
||||
private static final SocketHandler INSTANCE = new SocketHandler();
|
||||
}
|
||||
|
||||
static void onClose(WsCloseContext context) {
|
||||
public static SocketHandler getInstance() {
|
||||
return SocketHandler.ThreadSafeSingleton.INSTANCE;
|
||||
}
|
||||
|
||||
private SocketHandler() {
|
||||
dcService.addSubscribers(
|
||||
uiOutboundSubscriber,
|
||||
cameraChangeSubscriber,
|
||||
new UIInboundSubscriber()); // Subscribe outgoing messages to the data change service
|
||||
}
|
||||
|
||||
public void onConnect(WsConnectContext context) {
|
||||
context.session.setIdleTimeout(Long.MAX_VALUE); // TODO: determine better value
|
||||
var host = context.session.getRemote().getInetSocketAddress().getHostName();
|
||||
logger.info("New websocket connection from " + host);
|
||||
users.add(context);
|
||||
dcService.publishEvent(
|
||||
new IncomingWebSocketEvent<>(
|
||||
DataChangeDestination.DCD_GENSETTINGS, "userConnected", context));
|
||||
}
|
||||
|
||||
protected void onClose(WsCloseContext context) {
|
||||
var host = context.session.getRemote().getInetSocketAddress().getHostName();
|
||||
var reason = context.reason() != null ? context.reason() : "Connection closed by client";
|
||||
logger.info("Closing websocket connection from " + host + " for reason: " + reason);
|
||||
users.remove(context);
|
||||
}
|
||||
|
||||
public static void onBinaryMessage(WsBinaryMessageContext context) {
|
||||
@SuppressWarnings({"unchecked"})
|
||||
public void onBinaryMessage(WsBinaryMessageContext context) {
|
||||
try {
|
||||
Map<String, Object> data =
|
||||
objectMapper.readValue(context.data(), new TypeReference<Map<String, Object>>() {});
|
||||
// TODO pass data to ui data provider
|
||||
Map<String, Object> deserializedData =
|
||||
objectMapper.readValue(context.data(), new TypeReference<>() {});
|
||||
|
||||
// Special case the current camera index
|
||||
var camIndexValue = deserializedData.get("cameraIndex");
|
||||
Integer cameraIndex = null;
|
||||
if (camIndexValue instanceof Integer) {
|
||||
cameraIndex = (Integer) camIndexValue;
|
||||
deserializedData.remove("cameraIndex");
|
||||
}
|
||||
|
||||
for (Map.Entry<String, Object> entry : deserializedData.entrySet()) {
|
||||
try {
|
||||
var entryKey = entry.getKey();
|
||||
var entryValue = entry.getValue();
|
||||
var socketMessageType = SocketMessageType.fromEntryKey(entryKey);
|
||||
|
||||
logger.debug(
|
||||
"Got WS message: ["
|
||||
+ socketMessageType
|
||||
+ "] ==> ["
|
||||
+ entryKey
|
||||
+ "], ["
|
||||
+ entryValue
|
||||
+ "]");
|
||||
|
||||
if (socketMessageType == null) {
|
||||
logger.warn("Got unknown socket message type: " + entryKey);
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (socketMessageType) {
|
||||
case SMT_DRIVERMODE:
|
||||
{
|
||||
// TODO: what is this event?
|
||||
var data = (HashMap<String, Object>) entryValue;
|
||||
var dmExpEvent =
|
||||
new IncomingWebSocketEvent<Integer>(
|
||||
DataChangeDestination.DCD_ACTIVEMODULE, "driverExposure", data);
|
||||
var dmBrightEvent =
|
||||
new IncomingWebSocketEvent<Integer>(
|
||||
DataChangeDestination.DCD_ACTIVEMODULE, "driverBrightness", data);
|
||||
var dmIsDriverEvent =
|
||||
new IncomingWebSocketEvent<Boolean>(
|
||||
DataChangeDestination.DCD_ACTIVEMODULE, "isDriver", data);
|
||||
|
||||
dcService.publishEvents(dmExpEvent, dmBrightEvent, dmIsDriverEvent);
|
||||
break;
|
||||
}
|
||||
case SMT_CHANGECAMERANAME:
|
||||
{
|
||||
var ccnEvent =
|
||||
new IncomingWebSocketEvent<>(
|
||||
DataChangeDestination.DCD_ACTIVEMODULE,
|
||||
"cameraNickname",
|
||||
(String) entryValue,
|
||||
cameraIndex);
|
||||
dcService.publishEvent(ccnEvent);
|
||||
break;
|
||||
}
|
||||
case SMT_CHANGEPIPELINENAME:
|
||||
{
|
||||
var cpnEvent =
|
||||
new IncomingWebSocketEvent<>(
|
||||
DataChangeDestination.DCD_ACTIVEMODULE,
|
||||
"pipelineName",
|
||||
(String) entryValue,
|
||||
cameraIndex);
|
||||
dcService.publishEvent(cpnEvent);
|
||||
break;
|
||||
}
|
||||
case SMT_ADDNEWPIPELINE:
|
||||
{
|
||||
// HashMap<String, Object> data = (HashMap<String,
|
||||
// Object>) entryValue;
|
||||
// var type = (PipelineType)
|
||||
// data.get("pipelineType");
|
||||
// var name = (String) data.get("pipelineName");
|
||||
var type = PipelineType.Reflective;
|
||||
var name = (String) entryValue;
|
||||
|
||||
var newPipelineEvent =
|
||||
new IncomingWebSocketEvent<>(
|
||||
DataChangeDestination.DCD_ACTIVEMODULE,
|
||||
"newPipelineInfo",
|
||||
Pair.of(name, type),
|
||||
cameraIndex);
|
||||
dcService.publishEvent(newPipelineEvent);
|
||||
break;
|
||||
}
|
||||
case SMT_COMMAND:
|
||||
{
|
||||
var cmd = SocketMessageCommandType.fromEntryKey((String) entryValue);
|
||||
switch (cmd) {
|
||||
case SMCT_DELETECURRENTPIPELINE:
|
||||
{
|
||||
var deleteCurrentPipelineEvent =
|
||||
new IncomingWebSocketEvent<>(
|
||||
DataChangeDestination.DCD_ACTIVEMODULE,
|
||||
"deleteCurrPipeline",
|
||||
0,
|
||||
cameraIndex);
|
||||
dcService.publishEvent(deleteCurrentPipelineEvent);
|
||||
break;
|
||||
}
|
||||
case SMCT_SAVE:
|
||||
{
|
||||
var saveEvent =
|
||||
new IncomingWebSocketEvent<>(DataChangeDestination.DCD_OTHER, "save", 0);
|
||||
dcService.publishEvent(saveEvent);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SMT_CURRENTCAMERA:
|
||||
{
|
||||
var changeCurrentCameraEvent =
|
||||
new IncomingWebSocketEvent<>(
|
||||
DataChangeDestination.DCD_OTHER, "changeUICamera", (Integer) entryValue);
|
||||
dcService.publishEvent(changeCurrentCameraEvent);
|
||||
break;
|
||||
}
|
||||
case SMT_CURRENTPIPELINE:
|
||||
{
|
||||
var changePipelineEvent =
|
||||
new IncomingWebSocketEvent<>(
|
||||
DataChangeDestination.DCD_ACTIVEMODULE,
|
||||
"changePipeline",
|
||||
(Integer) entryValue,
|
||||
cameraIndex);
|
||||
dcService.publishEvent(changePipelineEvent);
|
||||
break;
|
||||
}
|
||||
case SMT_ISPNPCALIBRATION:
|
||||
{
|
||||
var changePipelineEvent =
|
||||
new IncomingWebSocketEvent<>(
|
||||
DataChangeDestination.DCD_ACTIVEMODULE,
|
||||
"changePipeline",
|
||||
PipelineManager.CAL_3D_INDEX,
|
||||
cameraIndex);
|
||||
dcService.publishEvent(changePipelineEvent);
|
||||
break;
|
||||
}
|
||||
case SMT_TAKECALIBRATIONSNAPSHOT:
|
||||
{
|
||||
var takeCalSnapshotEvent =
|
||||
new IncomingWebSocketEvent<>(
|
||||
DataChangeDestination.DCD_ACTIVEMODULE, "takeCalSnapshot", 0, cameraIndex);
|
||||
dcService.publishEvent(takeCalSnapshotEvent);
|
||||
break;
|
||||
}
|
||||
case SMT_PIPELINESETTINGCHANGE:
|
||||
{
|
||||
HashMap<String, Object> data = (HashMap<String, Object>) entryValue;
|
||||
|
||||
if (data.size() >= 2) {
|
||||
var cameraIndex2 = (int) data.get("cameraIndex");
|
||||
for (var dataEntry : data.entrySet()) {
|
||||
if (dataEntry.getKey().equals("cameraIndex")) {
|
||||
continue;
|
||||
}
|
||||
var pipelineSettingChangeEvent =
|
||||
new IncomingWebSocketEvent(
|
||||
DataChangeDestination.DCD_ACTIVEPIPELINESETTINGS,
|
||||
dataEntry.getKey(),
|
||||
dataEntry.getValue(),
|
||||
cameraIndex2);
|
||||
dcService.publishEvent(pipelineSettingChangeEvent);
|
||||
}
|
||||
} else {
|
||||
logger.warn("Unknown message for PSC: " + data.keySet().iterator().next());
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
logger.error("unknown booboo");
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
// TODO: log
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static void sendMessage(Object message, WsContext user) throws JsonProcessingException {
|
||||
// TODO: change to use the DataFlow system
|
||||
private void sendMessage(Object message, WsContext user) throws JsonProcessingException {
|
||||
ByteBuffer b = ByteBuffer.wrap(objectMapper.writeValueAsBytes(message));
|
||||
user.send(b);
|
||||
}
|
||||
|
||||
public static void broadcastMessage(Object message, WsContext userToSkip)
|
||||
// TODO: change to use the DataFlow system
|
||||
public void broadcastMessage(Object message, WsContext userToSkip)
|
||||
throws JsonProcessingException {
|
||||
for (WsContext user : users) {
|
||||
if (user != userToSkip) {
|
||||
sendMessage(message, user);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
public static void broadcastMessage(Object message) throws JsonProcessingException {
|
||||
broadcastMessage(message, null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Photon Vision.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.server;
|
||||
|
||||
public enum SocketMessageCommandType {
|
||||
SMCT_DELETECURRENTPIPELINE("deleteCurrentPipeline"),
|
||||
SMCT_SAVE("save");
|
||||
|
||||
public final String entryValue;
|
||||
|
||||
SocketMessageCommandType(String entryValue) {
|
||||
this.entryValue = entryValue;
|
||||
}
|
||||
|
||||
public static SocketMessageCommandType fromEntryKey(String entryValue) {
|
||||
if (entryValue.equalsIgnoreCase(SMCT_SAVE.entryValue)) return SMCT_SAVE;
|
||||
else return SMCT_DELETECURRENTPIPELINE;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Photon Vision.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.server;
|
||||
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public enum SocketMessageType {
|
||||
SMT_DRIVERMODE("driverMode"),
|
||||
SMT_CHANGECAMERANAME("changeCameraName"),
|
||||
SMT_CHANGEPIPELINENAME("changePipelineName"),
|
||||
SMT_ADDNEWPIPELINE("addNewPipeline"),
|
||||
SMT_COMMAND("command"),
|
||||
SMT_CURRENTCAMERA("currentCamera"),
|
||||
SMT_PIPELINESETTINGCHANGE("changePipelineSetting"),
|
||||
SMT_CURRENTPIPELINE("currentPipeline"),
|
||||
SMT_ISPNPCALIBRATION("isPNPCalibration"),
|
||||
SMT_TAKECALIBRATIONSNAPSHOT("takeCalibrationSnapshot");
|
||||
|
||||
public final String entryKey;
|
||||
|
||||
SocketMessageType(String entryKey) {
|
||||
this.entryKey = entryKey;
|
||||
}
|
||||
|
||||
private static final Map<String, SocketMessageType> entryKeyToValueMap = new HashMap<>();
|
||||
|
||||
static {
|
||||
for (var value : EnumSet.allOf(SocketMessageType.class)) {
|
||||
entryKeyToValueMap.put(value.entryKey, value);
|
||||
}
|
||||
}
|
||||
|
||||
public static SocketMessageType fromEntryKey(String entryKey) {
|
||||
return entryKeyToValueMap.get(entryKey);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Photon Vision.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.server;
|
||||
|
||||
import java.util.Collections;
|
||||
import org.photonvision.common.configuration.ConfigManager;
|
||||
import org.photonvision.common.dataflow.DataChangeDestination;
|
||||
import org.photonvision.common.dataflow.DataChangeService;
|
||||
import org.photonvision.common.dataflow.DataChangeSource;
|
||||
import org.photonvision.common.dataflow.DataChangeSubscriber;
|
||||
import org.photonvision.common.dataflow.events.DataChangeEvent;
|
||||
import org.photonvision.common.dataflow.events.IncomingWebSocketEvent;
|
||||
import org.photonvision.common.dataflow.events.OutgoingUIEvent;
|
||||
|
||||
public class UIInboundSubscriber extends DataChangeSubscriber {
|
||||
|
||||
public UIInboundSubscriber() {
|
||||
super(
|
||||
Collections.singletonList(DataChangeSource.DCS_WEBSOCKET),
|
||||
Collections.singletonList(DataChangeDestination.DCD_GENSETTINGS));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDataChangeEvent(DataChangeEvent event) {
|
||||
if (event instanceof IncomingWebSocketEvent) {
|
||||
var incomingWSEvent = (IncomingWebSocketEvent) event;
|
||||
if (incomingWSEvent.propertyName.equals("userConnected")
|
||||
|| incomingWSEvent.propertyName.equals("sendFullSettings")) {
|
||||
// Send full settings
|
||||
var settings = ConfigManager.getInstance().getConfig().toHashMap();
|
||||
var message = new OutgoingUIEvent<>(UIUpdateType.BROADCAST, "fullsettings", settings);
|
||||
DataChangeService.getInstance().publishEvent(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Photon Vision.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.server;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.photonvision.common.dataflow.DataChangeDestination;
|
||||
import org.photonvision.common.dataflow.DataChangeSource;
|
||||
import org.photonvision.common.dataflow.DataChangeSubscriber;
|
||||
import org.photonvision.common.dataflow.events.DataChangeEvent;
|
||||
import org.photonvision.common.dataflow.events.OutgoingUIEvent;
|
||||
import org.photonvision.common.logging.LogGroup;
|
||||
import org.photonvision.common.logging.Logger;
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
/*
|
||||
* DO NOT use logging in this class. If you do, the logs will recuse forever!
|
||||
*/
|
||||
class UIOutboundSubscriber extends DataChangeSubscriber {
|
||||
Logger logger = new Logger(UIOutboundSubscriber.class, LogGroup.Server);
|
||||
|
||||
private final SocketHandler socketHandler;
|
||||
|
||||
public UIOutboundSubscriber(SocketHandler socketHandler) {
|
||||
super(DataChangeSource.AllSources, Collections.singletonList(DataChangeDestination.DCD_UI));
|
||||
this.socketHandler = socketHandler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDataChangeEvent(DataChangeEvent event) {
|
||||
if (event instanceof OutgoingUIEvent) {
|
||||
var thisEvent = (OutgoingUIEvent) event;
|
||||
try {
|
||||
switch (thisEvent.updateType) {
|
||||
case BROADCAST:
|
||||
{
|
||||
// logger.debug("Broadcasting message");
|
||||
if (event.data instanceof HashMap) {
|
||||
var data = (HashMap) event.data;
|
||||
socketHandler.broadcastMessage(data, null);
|
||||
} else {
|
||||
socketHandler.broadcastMessage(event.data, null);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SINGLEUSER:
|
||||
{
|
||||
// logger.debug("Sending single user message");
|
||||
if (event.data instanceof Pair) {
|
||||
var pair = (SocketHandler.SelectiveBroadcastPair) event.data;
|
||||
socketHandler.broadcastMessage(pair.getLeft(), pair.getRight());
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (JsonProcessingException e) {
|
||||
// TODO: Log
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Photon Vision.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.server;
|
||||
|
||||
import org.photonvision.common.configuration.CameraConfiguration;
|
||||
import org.photonvision.common.configuration.NetworkConfig;
|
||||
|
||||
public class UISettings {
|
||||
public NetworkConfig networkConfig;
|
||||
public CameraConfiguration currentCameraConfiguration;
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Photon Vision.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.server;
|
||||
|
||||
public enum UIUpdateType {
|
||||
BROADCAST,
|
||||
SINGLEUSER
|
||||
}
|
||||
Reference in New Issue
Block a user