2019-09-21 16:04:58 +03:00
|
|
|
package com.chameleonvision.web;
|
|
|
|
|
|
|
|
|
|
import com.chameleonvision.CameraException;
|
|
|
|
|
import com.chameleonvision.settings.SettingsManager;
|
|
|
|
|
import com.chameleonvision.vision.Pipeline;
|
2019-09-22 02:49:30 -04:00
|
|
|
import com.chameleonvision.vision.camera.Camera;
|
2019-09-21 16:04:58 +03:00
|
|
|
import com.chameleonvision.vision.camera.CameraManager;
|
2019-09-24 02:44:02 +03:00
|
|
|
import com.google.gson.JsonArray;
|
2019-09-21 16:04:58 +03:00
|
|
|
import edu.wpi.cscore.VideoException;
|
|
|
|
|
import io.javalin.websocket.WsCloseContext;
|
|
|
|
|
import io.javalin.websocket.WsConnectContext;
|
|
|
|
|
import io.javalin.websocket.WsContext;
|
|
|
|
|
import io.javalin.websocket.WsMessageContext;
|
|
|
|
|
import org.json.JSONArray;
|
|
|
|
|
import org.json.JSONObject;
|
|
|
|
|
import org.springframework.beans.BeanUtils;
|
|
|
|
|
|
|
|
|
|
import java.lang.reflect.Field;
|
|
|
|
|
import java.util.ArrayList;
|
|
|
|
|
import java.util.HashMap;
|
|
|
|
|
import java.util.List;
|
|
|
|
|
import java.util.Map;
|
|
|
|
|
|
|
|
|
|
public class ServerHandler {
|
|
|
|
|
|
|
|
|
|
private static List<WsContext> users;
|
|
|
|
|
|
2019-09-21 13:05:00 -04:00
|
|
|
ServerHandler() {
|
|
|
|
|
users = new ArrayList<>();
|
2019-09-21 16:04:58 +03:00
|
|
|
}
|
|
|
|
|
|
2019-09-21 13:05:00 -04:00
|
|
|
void onConnect(WsConnectContext context) {
|
2019-09-21 16:04:58 +03:00
|
|
|
users.add(context);
|
|
|
|
|
sendFullSettings();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void onClose(WsCloseContext context) {
|
|
|
|
|
users.remove(context);
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-21 13:05:00 -04:00
|
|
|
void onMessage(WsMessageContext data) throws CameraException {
|
2019-09-21 16:04:58 +03:00
|
|
|
broadcastMessage(data.message(), data);
|
|
|
|
|
|
|
|
|
|
JSONObject jsonObject = new JSONObject(data.message());
|
|
|
|
|
String key = null;
|
|
|
|
|
var jsonKeySetArray = jsonObject.keySet().toArray();
|
|
|
|
|
try {
|
|
|
|
|
key = jsonKeySetArray[0].toString();
|
|
|
|
|
} catch (Exception ex) {
|
|
|
|
|
System.err.println("WebSocket JSON data was empty!");
|
|
|
|
|
}
|
|
|
|
|
if (key == null) return;
|
|
|
|
|
Object value = jsonObject.get(key);
|
|
|
|
|
System.out.printf("Got websocket json data: [%s, %s]\n", key, value);
|
|
|
|
|
if (hasField(CameraManager.getCurrentPipeline(), key)) {
|
2019-09-24 02:44:02 +03:00
|
|
|
//Special cases for exposure and brightness and aspect ratio
|
2019-09-21 16:04:58 +03:00
|
|
|
switch (key) {
|
|
|
|
|
case "exposure":
|
|
|
|
|
int newExposure = (int) value;
|
|
|
|
|
System.out.printf("Changing exposure to %d\n", newExposure);
|
|
|
|
|
try {
|
|
|
|
|
CameraManager.getCurrentCamera().setExposure(newExposure);
|
|
|
|
|
} catch (VideoException e) {
|
|
|
|
|
System.out.println("Exposure changes is not supported on your webcam/webcam's driver");
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case "brightness":
|
|
|
|
|
int newBrightness = (int) value;
|
|
|
|
|
System.out.printf("Changing brightness to %d\n", newBrightness);
|
|
|
|
|
CameraManager.getCurrentCamera().setBrightness(newBrightness);
|
|
|
|
|
break;
|
2019-09-24 02:44:02 +03:00
|
|
|
case "ratio":
|
|
|
|
|
//If there is any better to convert Integer to Double you're welcome to change it
|
|
|
|
|
List<Double> doubleRatio = CameraManager.getCurrentPipeline().ratio;
|
|
|
|
|
List<Object> newRatio = ((JSONArray) value).toList();
|
|
|
|
|
for (int i = 0; i < newRatio.size(); i++) {
|
|
|
|
|
doubleRatio.set(i, Double.parseDouble(newRatio.get(i).toString()));
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
//Any other field in CameraManager that doesn't need anything special
|
|
|
|
|
setField(CameraManager.getCurrentPipeline(), key, value);
|
|
|
|
|
break;
|
2019-09-21 16:04:58 +03:00
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
switch (key) {
|
|
|
|
|
case "change_general_settings_values":
|
|
|
|
|
JSONObject newSettings = (JSONObject) value;
|
|
|
|
|
Map<String, Object> map = newSettings.toMap();
|
|
|
|
|
map.forEach((s, o) -> setField(SettingsManager.GeneralSettings, s, o));
|
2019-09-24 03:31:56 +03:00
|
|
|
SettingsManager.saveSettings();
|
2019-09-21 16:04:58 +03:00
|
|
|
break;
|
|
|
|
|
case "curr_camera":
|
|
|
|
|
String newCamera = (String) value;
|
|
|
|
|
System.out.printf("Changing camera to %s\n", newCamera);
|
|
|
|
|
CameraManager.setCurrentCamera(newCamera);
|
2019-09-24 03:06:04 +03:00
|
|
|
HashMap<String, Integer> portMap = new HashMap<>();
|
2019-09-24 02:44:02 +03:00
|
|
|
portMap.put("port", CameraManager.getCurrentCamera().getStreamPort());
|
2019-09-24 03:06:04 +03:00
|
|
|
sendFullSettings();
|
2019-09-21 16:04:58 +03:00
|
|
|
break;
|
|
|
|
|
case "curr_pipeline":
|
2019-10-01 02:18:55 -04:00
|
|
|
int newPipeline = (int) value;
|
2019-09-21 16:04:58 +03:00
|
|
|
System.out.printf("Changing pipeline to %s\n", newPipeline);
|
2019-10-01 02:18:55 -04:00
|
|
|
CameraManager.setCurrentPipeline(newPipeline);
|
|
|
|
|
CameraManager.getCurrentCameraProcess().ntPipelineEntry.setNumber(newPipeline);
|
2019-09-21 16:04:58 +03:00
|
|
|
broadcastMessage(allFieldsToMap(CameraManager.getCurrentPipeline()));
|
2019-09-25 10:32:22 -07:00
|
|
|
|
2019-09-21 16:04:58 +03:00
|
|
|
break;
|
|
|
|
|
case "resolution":
|
|
|
|
|
int newVideoMode = (int) value;
|
|
|
|
|
System.out.printf("Changing video mode to %d\n", newVideoMode);
|
2019-09-22 13:35:19 -04:00
|
|
|
CameraManager.getCurrentCamera().setCamVideoMode(newVideoMode, true);
|
2019-09-21 16:04:58 +03:00
|
|
|
break;
|
|
|
|
|
case "FOV":
|
2019-09-24 03:06:04 +03:00
|
|
|
double newFov = Double.parseDouble(value.toString());
|
2019-09-21 16:04:58 +03:00
|
|
|
System.out.printf("Changing FOV to %f\n", newFov);
|
|
|
|
|
CameraManager.getCurrentCamera().setFOV(newFov);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
System.out.printf("Unexpected value from websocket: [%s, %s]\n", key, value);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void setField(Object obj, String fieldName, Object value) {
|
|
|
|
|
try {
|
|
|
|
|
Field[] fields = obj.getClass().getFields();
|
|
|
|
|
for (Field f : fields) {
|
|
|
|
|
if (f.getName().equals(fieldName)) {
|
|
|
|
|
if (BeanUtils.isSimpleValueType(value.getClass())) {
|
|
|
|
|
f.set(obj, value);
|
|
|
|
|
} else if (value.getClass() == JSONArray.class) {
|
|
|
|
|
f.set(obj, ((JSONArray) value).toList());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} catch (IllegalAccessException e) {
|
|
|
|
|
System.out.println("IllegalAccessException ");
|
|
|
|
|
e.printStackTrace();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static void broadcastMessage(Object obj, WsContext userToSkip) {//TODO check if session id is a good way to differentiate users
|
|
|
|
|
for (var user : users) {
|
|
|
|
|
if (userToSkip != null && user.getSessionId().equals(userToSkip.getSessionId())) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (obj.getClass() == String.class)
|
|
|
|
|
user.send((String) obj);
|
|
|
|
|
else if (obj.getClass() == HashMap.class)
|
|
|
|
|
user.send(new JSONObject((HashMap<String, Object>) obj).toString());
|
|
|
|
|
else
|
|
|
|
|
user.send(new JSONObject(obj).toString());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void broadcastMessage(Object obj) {
|
|
|
|
|
broadcastMessage(obj, null);//Broadcasts the message to ever user
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private boolean hasField(Object obj, String fieldName) {
|
|
|
|
|
Field[] fields = obj.getClass().getFields();
|
|
|
|
|
for (Field field : fields) {
|
|
|
|
|
if (fieldName.equals(field.getName()))
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static Map<String, Object> allFieldsToMap(Object obj) {
|
|
|
|
|
Map map = new HashMap<String, Object>();
|
|
|
|
|
try {
|
|
|
|
|
Field[] fields = obj.getClass().getFields();
|
|
|
|
|
for (Field field : fields) {
|
|
|
|
|
map.put(field.getName(), field.get(obj));
|
|
|
|
|
}
|
|
|
|
|
} catch (IllegalAccessException e) {
|
|
|
|
|
System.err.println("Illegal Access error:" + e.getStackTrace());
|
|
|
|
|
}
|
|
|
|
|
return map;
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-22 02:49:30 -04:00
|
|
|
public static void sendFullSettings() {
|
2019-09-21 16:04:58 +03:00
|
|
|
//General settings
|
|
|
|
|
Map<String, Object> fullSettings = new HashMap<>(allFieldsToMap(SettingsManager.GeneralSettings));
|
|
|
|
|
fullSettings.put("cameraList", CameraManager.getAllCamerasByName().keySet());
|
|
|
|
|
try {
|
|
|
|
|
var currentCamera = CameraManager.getCurrentCamera();
|
|
|
|
|
fullSettings.putAll(allFieldsToMap(currentCamera.getCurrentPipeline()));
|
|
|
|
|
fullSettings.put("pipelineList", currentCamera.getPipelines().keySet());
|
|
|
|
|
fullSettings.put("resolutionList", CameraManager.getResolutionList());
|
|
|
|
|
fullSettings.put("resolution", currentCamera.getVideoModeIndex());
|
|
|
|
|
fullSettings.put("FOV", currentCamera.getFOV());
|
2019-09-22 02:49:30 -04:00
|
|
|
fullSettings.put("port", currentCamera.getStreamPort());
|
2019-09-21 16:04:58 +03:00
|
|
|
} catch (CameraException e) {
|
|
|
|
|
System.err.println("No camera found!");
|
|
|
|
|
//TODO: add message to ui to inform that there are no cameras
|
|
|
|
|
}
|
|
|
|
|
broadcastMessage(fullSettings);
|
|
|
|
|
}
|
|
|
|
|
}
|