2019-09-15 15:03:44 -04:00
package com.chameleonvision.web ;
2019-09-10 23:47:06 +03:00
2019-09-19 14:07:42 -04:00
import com.chameleonvision.CameraException ;
2019-09-15 15:03:44 -04:00
import com.chameleonvision.settings.SettingsManager ;
2019-09-19 14:07:42 -04:00
import com.chameleonvision.vision.camera.CameraManager ;
2019-09-18 03:04:48 +03:00
import edu.wpi.cscore.VideoException ;
2019-09-10 23:47:06 +03:00
import io.javalin.Javalin ;
2019-09-11 20:28:56 +03:00
import io.javalin.websocket.WsContext ;
2019-09-15 01:55:29 +03:00
import java.lang.reflect.Field ;
2019-09-16 04:10:26 +03:00
import java.util.* ;
2019-09-15 01:55:29 +03:00
import org.json.JSONArray ;
2019-09-11 20:28:56 +03:00
import org.json.JSONObject ;
2019-09-15 01:55:29 +03:00
import org.springframework.beans.BeanUtils ;
2019-09-11 20:28:56 +03:00
2019-09-10 23:47:06 +03:00
public class Server {
2019-09-19 14:07:42 -04:00
private static List < WsContext > users = new ArrayList < > ( ) ;
2019-09-16 04:10:26 +03:00
2019-09-10 23:47:06 +03:00
public static void main ( int port ) {
2019-09-11 20:28:56 +03:00
Javalin app = Javalin . create ( ) ;
app . config . addStaticFiles ( " web " ) ;
2019-09-16 04:10:26 +03:00
app . ws ( " /websocket " , ws - > {
2019-09-11 20:28:56 +03:00
ws . onConnect ( ctx - > {
users . add ( ctx ) ;
System . out . println ( " Socket Connected " ) ;
2019-09-16 04:10:26 +03:00
sendFullSettings ( ) ;
2019-09-11 20:28:56 +03:00
} ) ;
ws . onClose ( ctx - > {
users . remove ( ctx ) ;
System . out . println ( " Socket Disconnected " ) ;
2019-09-20 19:54:59 -04:00
SettingsManager . saveSettings ( ) ;
2019-09-11 20:28:56 +03:00
} ) ;
ws . onMessage ( ctx - > {
2019-09-18 03:04:48 +03:00
broadcastMessage ( ctx . message ( ) , ctx ) ;
2019-09-19 14:07:42 -04:00
2019-09-15 01:55:29 +03:00
JSONObject jsonObject = new JSONObject ( ctx . message ( ) ) ;
2019-09-16 11:45:56 -04:00
String key = null ;
2019-09-17 02:12:53 -04:00
var jsonKeySetArray = jsonObject . keySet ( ) . toArray ( ) ;
2019-09-16 11:45:56 -04:00
try {
2019-09-17 02:12:53 -04:00
key = jsonKeySetArray [ 0 ] . toString ( ) ;
2019-09-16 11:45:56 -04:00
} catch ( Exception ex ) {
2019-09-17 02:12:53 -04:00
System . err . println ( " WebSocket JSON data was empty! " ) ;
2019-09-16 11:45:56 -04:00
}
if ( key = = null ) return ;
2019-09-15 01:55:29 +03:00
Object value = jsonObject . get ( key ) ;
2019-09-17 02:12:53 -04:00
// System.out.printf("Got websocket json data: [%s, %s]\n", key, value);
2019-09-19 14:07:42 -04:00
if ( ! allFieldsToMap ( CameraManager . getCurrentPipeline ( ) ) . containsKey ( key ) ) {
2019-09-16 04:10:26 +03:00
//If field not in pipeline
switch ( key ) {
case " change_general_settings_values " :
JSONObject newSettings = ( JSONObject ) value ;
2019-09-17 02:12:53 -04:00
setFields ( SettingsManager . GeneralSettings , newSettings ) ;
2019-09-16 04:10:26 +03:00
break ;
case " curr_camera " :
2019-09-17 02:12:53 -04:00
String newCamera = ( String ) value ;
System . out . printf ( " Changing camera to %s \ n " , newCamera ) ;
2019-09-19 14:07:42 -04:00
CameraManager . setCurrentCamera ( newCamera ) ;
2019-09-16 04:10:26 +03:00
//broadcastMessage((Map<String, Object>) new HashMap<String, Object>(){}.put("port",SettingsManager.CameraPorts.get(SettingsManager.GeneralSettings.curr_camera)));
2019-09-19 14:07:42 -04:00
broadcastMessage ( CameraManager . getCurrentCamera ( ) ) ; //TODO CHECK JSON FOR CAMERA CHANGE
2019-09-16 04:10:26 +03:00
break ;
case " curr_pipeline " :
2019-09-17 02:12:53 -04:00
String newPipeline = ( String ) value ;
2019-09-19 14:07:42 -04:00
var pipelineNumber = Integer . parseInt ( newPipeline . replace ( " pipeline " , " " ) ) ;
2019-09-17 02:12:53 -04:00
System . out . printf ( " Changing pipeline to %s \ n " , newPipeline ) ;
2019-09-19 14:07:42 -04:00
CameraManager . setCurrentPipeline ( pipelineNumber ) ;
broadcastMessage ( allFieldsToMap ( CameraManager . getCurrentPipeline ( ) ) ) ;
2019-09-16 04:10:26 +03:00
break ;
case " resolution " :
2019-09-19 14:07:42 -04:00
int newVideoMode = ( int ) value ;
System . out . printf ( " Changing video mode to %d \ n " , newVideoMode ) ;
CameraManager . getCurrentCamera ( ) . setCamVideoMode ( newVideoMode ) ;
2019-09-16 04:10:26 +03:00
break ;
2019-09-19 14:07:42 -04:00
case " FOV " :
2019-09-17 02:12:53 -04:00
double newFov = ( double ) value ;
2019-09-18 03:04:48 +03:00
System . out . printf ( " Changing FOV to %f \ n " , newFov ) ;
2019-09-19 14:07:42 -04:00
CameraManager . getCurrentCamera ( ) . setFOV ( newFov ) ;
2019-09-16 04:10:26 +03:00
break ;
default :
2019-09-17 02:12:53 -04:00
System . out . printf ( " Unexpected value from websocket: [%s, %s] \ n " , key , value ) ;
break ;
}
2019-09-18 03:04:48 +03:00
} else {
2019-09-19 14:07:42 -04:00
setField ( CameraManager . getCurrentPipeline ( ) , key , value ) ;
2019-09-18 03:04:48 +03:00
//Special cases for exposure and brightness
//TODO maybe add listener for value changes instead of this special case
2019-09-17 02:12:53 -04:00
switch ( key ) {
case " exposure " :
int newExposure = ( int ) value ;
System . out . printf ( " Changing exposure to %d \ n " , newExposure ) ;
2019-09-18 03:04:48 +03:00
try {
2019-09-19 14:07:42 -04:00
CameraManager . getCurrentCamera ( ) . setExposure ( newExposure ) ;
2019-09-18 03:04:48 +03:00
}
catch ( VideoException e )
{
System . out . println ( " Exposure changes is not supported on your webcam/webcam's driver " ) ;
}
//TODO check if this crash occurs on linux
2019-09-17 02:12:53 -04:00
break ;
case " brightness " :
int newBrightness = ( int ) value ;
System . out . printf ( " Changing brightness to %d \ n " , newBrightness ) ;
2019-09-19 14:07:42 -04:00
CameraManager . getCurrentCamera ( ) . setBrightness ( newBrightness ) ;
2019-09-16 04:10:26 +03:00
break ;
2019-09-15 01:55:29 +03:00
}
}
2019-09-11 20:28:56 +03:00
} ) ;
} ) ;
app . start ( port ) ;
}
2019-09-16 04:10:26 +03:00
2019-09-18 03:04:48 +03:00
private static void setField ( Object obj , String fieldName , Object value ) {
2019-09-16 04:10:26 +03:00
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 ) {
2019-09-18 03:04:48 +03:00
System . out . println ( " IllegalAccessException " ) ;
e . printStackTrace ( ) ;
2019-09-16 04:10:26 +03:00
}
}
2019-09-18 03:04:48 +03:00
private static void setFields ( Object obj , JSONObject data ) {
Map < String , Object > map = data . toMap ( ) ;
map . forEach ( ( s , o ) - > setField ( obj , s , o ) ) ;
2019-09-16 04:10:26 +03:00
}
2019-09-18 03:04:48 +03:00
private static void broadcastMessage ( Object obj , WsContext userToSkip ) { //TODO chekc if session id is a good way to differentiate users
2019-09-16 04:10:26 +03:00
for ( var user : users ) {
2019-09-18 03:04:48 +03:00
if ( userToSkip ! = null & & user . getSessionId ( ) . equals ( userToSkip . getSessionId ( ) ) ) {
2019-09-16 18:50:00 +03:00
continue ;
2019-09-11 20:28:56 +03:00
}
2019-09-16 18:50:00 +03:00
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 ( ) ) ;
2019-09-11 20:28:56 +03:00
}
2019-09-10 23:47:06 +03:00
}
2019-09-11 20:28:56 +03:00
2019-09-18 13:48:34 +03:00
public static void broadcastMessage ( Object obj ) {
2019-09-18 03:04:48 +03:00
broadcastMessage ( obj , null ) ; //Broadcasts the message to ever user
}
private static Map < String , Object > allFieldsToMap ( Object obj ) {
2019-09-19 14:07:42 -04:00
Map map = new HashMap < String , Object > ( ) ;
2019-09-16 04:10:26 +03:00
try {
Field [ ] fields = obj . getClass ( ) . getFields ( ) ;
2019-09-19 14:07:42 -04:00
for ( Field field : fields ) {
2019-09-16 04:10:26 +03:00
map . put ( field . getName ( ) , field . get ( obj ) ) ;
2019-09-19 14:07:42 -04:00
}
2019-09-16 04:10:26 +03:00
} catch ( IllegalAccessException e ) {
2019-09-19 14:07:42 -04:00
System . err . println ( " Illegal Access error: " + e . getStackTrace ( ) ) ;
2019-09-16 04:10:26 +03:00
}
2019-09-18 03:04:48 +03:00
return map ;
2019-09-16 04:10:26 +03:00
}
private static void sendFullSettings ( ) {
//General settings
2019-09-19 14:07:42 -04:00
Map < String , Object > fullSettings = new HashMap < > ( allFieldsToMap ( SettingsManager . GeneralSettings ) ) ;
fullSettings . put ( " cameraList " , CameraManager . getAllCamerasByName ( ) . keySet ( ) ) ;
2019-09-16 04:10:26 +03:00
try {
2019-09-19 14:07:42 -04:00
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-16 04:10:26 +03:00
// fullSettings.put("port", SettingsManager.CameraPorts.get(SettingsManager.GeneralSettings.curr_camera));
2019-09-19 14:07:42 -04:00
} catch ( CameraException e ) {
2019-09-16 04:10:26 +03:00
System . err . println ( " No camera found! " ) ;
//TODO: add message to ui to inform that there are no cameras
}
2019-09-18 03:04:48 +03:00
broadcastMessage ( fullSettings ) ;
2019-09-16 04:10:26 +03:00
}
2019-09-15 01:55:29 +03:00
2019-09-10 23:47:06 +03:00
}