Skip to content
Snippets Groups Projects
Commit 74f79956 authored by Ondřej Trojan's avatar Ondřej Trojan
Browse files

adder connection maintain, shutdown buttons

parent bbd2bd59
No related branches found
No related tags found
No related merge requests found
......@@ -25,13 +25,13 @@ public class MainController {
@GetMapping()
public String Index(@RequestParam(name="name", required=false, defaultValue="World") String name, Model model) {
public String Index(@RequestParam(name = "name", required = false, defaultValue = "World") String name, Model model) {
model.addAttribute("name", responseService.changeName(name));
return "index";
}
@GetMapping("/main")
public String main(@RequestParam(name="name", required=false, defaultValue="World") String name, Model model) {
public String main(@RequestParam(name = "name", required = false, defaultValue = "World") String name, Model model) {
model.addAttribute("name", responseService.changeName(name));
return "main";
}
......@@ -45,12 +45,12 @@ public class MainController {
}
@PostMapping(value = "/add", consumes = "application/json", produces = "application/json")
@PostMapping(value = "/add", consumes = "application/json", produces = "application/json")
public ResponseEntity add(@RequestBody ControlEntity model) {
System.out.println(model.videoName);
controlService.add(model.videoName);
return new ResponseEntity<>(
"Video "+model.videoName+" set to play", HttpStatus.OK);
"Video " + model.videoName + " set to play", HttpStatus.OK);
}
......@@ -61,13 +61,16 @@ public class MainController {
"Video set to pause", HttpStatus.OK);
}
@PostMapping(value = "/shutdown", produces = "application/json")
public ResponseEntity shutdown(@RequestParam String clientId) {
controlService.shutdownById(clientId);
return new ResponseEntity<>(
"Client "+clientId+ " set to shutdown", HttpStatus.OK);
}
@GetMapping("/")
public List<String> get(){
public List<String> get() {
return List.of("Hello", "edited", "s");
}
}
......
......@@ -4,7 +4,6 @@ package com.museum.projection.service;
import com.museum.projection.config.CustomConfig;
import com.museum.projection.util.VlcClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
......@@ -12,6 +11,8 @@ import javax.annotation.Resource;
@Service
public class ControlService {
private static volatile boolean outOfSync = false;
private final CustomConfig config;
@Resource(name = "client1")
......@@ -27,43 +28,92 @@ public class ControlService {
}
public void play() {
client1.sendMessage("play");
client2.sendMessage("play");
sendCommand(client1, "play");
sendCommand(client2, "play");
}
public void add(String videoName) {
client1.sendMessage("add " + config.getVideoFolderPath() + videoName);
client2.sendMessage("add " + config.getVideoFolderPath() + videoName);
sendCommand(client1, "add", config.getVideoFolderPath() + videoName);
sendCommand(client2, "add", config.getVideoFolderPath() + videoName);
}
public void pause() {
client1.sendMessage("pause");
client2.sendMessage("pause");
sendCommand(client1, "pause");
sendCommand(client2, "pause");
}
public void stop() {
client1.sendMessage("stop");
client2.sendMessage("stop");
sendCommand(client1, "stop");
sendCommand(client2, "stop");
}
public void clear() {
client1.sendMessage("clear");
client2.sendMessage("clear");
sendCommand(client1, "clear");
sendCommand(client2, "clear");
}
public void logout1() {
client1.sendMessage("logout");
client1.close();
sendCommand(client1, "logout");
}
public void logout2() {
client2.sendMessage("logout");
client2.close();
sendCommand(client2, "logout");
}
public void logoutAll() {
logout1();
logout2();
}
private void shutdown1() {
sendCommand(client1, "shutdown");
}
private void shutdown2() {
sendCommand(client2, "shutdown");
}
public void shutdownById(String id) {
System.out.println(id);
if (id.equals("1")) {
shutdown1();
} else if (id.equals("2")) {
shutdown2();
} else {
throw new IllegalArgumentException("No shutdown client with id " + id);
}
}
public void shutdownAll() {
shutdown1();
shutdown2();
}
public void sendCommand(VlcClient client, String cmd) {
sendCommand(client, cmd, "");
}
public void sendCommand(VlcClient client, String cmd, String parameter) {
client.send(cmd + " " + parameter, getLinesFor(cmd));
}
private int getLinesFor(String command) {
switch (command) {
case "add":
case "play":
case "clear":
case "pause":
return 0;
case "is_playing":
case "logout":
case "shutdown":
return 1;
default:
return Integer.MAX_VALUE;
}
}
}
......@@ -2,23 +2,23 @@ package com.museum.projection.util;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.io.*;
import java.net.*;
import java.util.*;
public class VlcClient {
private static final int INTERVAL_MAINTAIN = 1000;
private static final int INTERVAL_STARTUP = 500;
private static final int SOCKET_TIMEOUT = 200;
private static final String[] correctResponse = {"VLC media player 3.0.8 Vetinari", "Command Line Interface initialized. Type `help' for help.", "> 1"};
private static final int INTERVAL_MAINTAIN = 4000;
private static final int INTERVAL_STARTUP = 1000;
private static final int SOCKET_TIMEOUT = 900;
private static final int SOCKET_SINGLE_TIMEOUT = 200;
private static final int SOCKET_TIMEOUT_LIMIT = 1;
private static final String[] STARTUP_RESPONSE = {"VLC media player 3.0.8 Vetinari", "Command Line Interface initialized. Type `help' for help."};
private static final String WAITING_COMMAND = "> ";
private static final String IS_PLAYING_TRUE = "> 1";
private static final String IS_PLAYING_FALSE = "> 0";
private static final Logger log = LoggerFactory.getLogger(VlcClient.class);
......@@ -26,9 +26,13 @@ public class VlcClient {
private volatile PrintWriter out;
private volatile BufferedReader in;
private volatile int timeoutsCounter = 0;
private volatile int lostConnectionTimeoutCounter = 0;
private volatile boolean connectionReady = false;
private String ip;
private int port;
private final String ip;
private final int port;
@Scheduled(fixedRate = INTERVAL_STARTUP)
......@@ -42,7 +46,8 @@ public class VlcClient {
@Scheduled(fixedRate = INTERVAL_MAINTAIN)
private void maintainCheck() throws InterruptedException {
if (isConnectionReady()) {
maintainConnection();
log.info("Maintaining connection to " + ip + ":" + port);
verifyConnection();
}
}
......@@ -54,6 +59,8 @@ public class VlcClient {
private void startConnection() throws InterruptedException {
log.info("Starting connection to " + ip + ":" + port);
lostConnectionTimeoutCounter = 0;
timeoutsCounter = 0;
try {
socket = new Socket(ip, port);
out = new PrintWriter(socket.getOutputStream(), true);
......@@ -70,47 +77,79 @@ public class VlcClient {
} catch (IOException e) {
log.error("Error during connection to" + ip + ":" + port, e);
setConnectionReady(false);
closeCurrentConnectAttempt();
return;
}
out.println("is_playing" + '\n');
String resp = null;
for (int i = 0; i < 2; i++) {
try {
resp = in.readLine();
if (resp == null) {
closeCurrentConnectAttempt();
return;
}
setConnectionReady(isConnectionReady() && resp.equals(correctResponse[i]));
} catch (SocketTimeoutException | SocketException e) {
log.error("Socket " + ip + ":" + port + " buffer read exited on timeout of "+SOCKET_TIMEOUT,e.getCause());
setConnectionReady(false);
return;
} catch (IOException e) {
e.printStackTrace();
return;
List<String> received = new ArrayList<>();
String line;
boolean responseOk = true;
try {
for (int i = 0; i < 2; i++) {
line = in.readLine();
log.info("start_" + line);
received.add(line);
responseOk &= received.get(i).equals(STARTUP_RESPONSE[i]);
}
setConnectionReady(false);
String next = Character.toString((char) in.read()) + Character.toString((char) in.read());
received.add(next);
responseOk &= received.get(2).equals(WAITING_COMMAND);
} catch (SocketTimeoutException e) {
log.error("Socket " + ip + ":" + port + " buffer read exited on timeout of " + SOCKET_TIMEOUT, e.getCause());
closeCurrentConnectAttempt();
return;
} catch (IOException e) {
log.error("Error during connection to" + ip + ":" + port, e);
closeCurrentConnectAttempt();
return;
}
setConnectionReady(true);
log.info("Connection to " + ip + ":" + port + " has been established");
setConnectionReady(responseOk);
log.info("Connection to " + ip + ":" + port + " has been established " + isConnectionReady());
}
private void maintainConnection() {
log.info("Maintaining connection to " + ip + ":" + port);
private void verifyConnection() {
List<String> received = null;
try {
received = sendMessage("is_playing", 1, 1);
} catch (SocketTimeoutException | SocketException e) {
log.error("Socket " + ip + ":" + port + " buffer read exited on timeout of " + SOCKET_TIMEOUT, e.getCause());
timeoutsCounter++;
//TODO out of sync
if (timeoutsCounter > SOCKET_TIMEOUT_LIMIT) {
log.error("Socket " + ip + ":" + port + " timeout limit of " + SOCKET_TIMEOUT_LIMIT + " exceeded, shutting the connection");
timeoutsCounter = 0;
closeCurrentConnectAttempt();
}
return;
} catch (IOException e) {
log.error("Connection " + ip + ":" + port + " verified as not active, shutting down", e.getCause());
closeCurrentConnectAttempt();
return;
}
if (received.size() != 1 || received.get(0) == null) {
log.error("Connection " + ip + ":" + port + " unexpected response. Expected " + IS_PLAYING_FALSE + " or " + IS_PLAYING_TRUE + ", received " + Arrays.toString(received.toArray()));
lostConnectionTimeoutCounter++;
//TODO out of sync
if (lostConnectionTimeoutCounter > SOCKET_TIMEOUT_LIMIT) {
log.error("Connection " + ip + ":" + port + " timeout limit of " + SOCKET_TIMEOUT_LIMIT + " exceeded, shutting the connection");
closeCurrentConnectAttempt();
}
return;
}
boolean status = received.get(0).equals("0") || received.get(0).equals("1");
setConnectionReady(status);
if (status) {
lostConnectionTimeoutCounter = 0;
timeoutsCounter = 0;
}
}
private void closeCurrentConnectAttempt() {
setConnectionReady(false);
try {
socket.close();
} catch (IOException e) {
//LOG socket cannot by closed
e.printStackTrace();
}
close();
}
public synchronized boolean isConnectionReady() {
......@@ -122,19 +161,43 @@ public class VlcClient {
}
public String sendMessage(String msg) {
public List<String> send(String msg, int expectedLines) {
if (!isConnectionReady()) {
log.warn("Attempt to send to non established connection");
return "";
return Collections.EMPTY_LIST;
}
out.println(msg + '\n');
String resp = null;
try {
resp = in.readLine();
System.out.println(resp);
return sendMessage(msg, expectedLines, 1);
} catch (SocketTimeoutException | SocketException e) {
log.error("Socket " + ip + ":" + port + " buffer read exited on timeout of " + SOCKET_TIMEOUT, e.getCause());
timeoutsCounter++;
if (timeoutsCounter > SOCKET_TIMEOUT_LIMIT) {
log.error("Socket " + ip + ":" + port + " timeout limit of " + SOCKET_TIMEOUT_LIMIT + " exceeded, shutting the connection");
closeCurrentConnectAttempt();
}
} catch (IOException e) {
e.printStackTrace();
closeCurrentConnectAttempt();
}
return null;
}
private synchronized List<String> sendMessage(String msg, int expectedLines, int wait) throws IOException {
out.println(msg);
ArrayList<String> resp = new ArrayList<>();
String line = null;
for (int i = 0; i < expectedLines; i++) {
line = in.readLine();
resp.add(line);
}
String next = (Character.toString((char) in.read()) + Character.toString((char) in.read()));
if (!next.equals(WAITING_COMMAND)) {
log.error("Not received next command character");
}
log.info("Send " + msg + " received " + Arrays.toString(resp.toArray()));
return resp;
}
......@@ -145,9 +208,10 @@ public class VlcClient {
out.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
log.error("Socket " + ip + ":" + port + "cannot be closed", e);
}
}
}
......@@ -15,4 +15,7 @@ spring.task.scheduling.shutdown.await-termination=true
5d.client1ip=127.0.0.1
5d.client2ip=127.0.0.1
5d.client1port=5041
5d.client2port=5031
\ No newline at end of file
5d.client2port=5031
#5d.connection-maintain-interval=1000
#5d.init-interval=400
#5d.socket-timeout=200
\ No newline at end of file
......@@ -8,4 +8,6 @@
background-color: #f5f5f5;
}
.alert-box {
margin: 20px 30px 20px 30px;
}
......@@ -3,6 +3,9 @@
var playBtn = document.getElementById('play');
var pauseBtn = document.getElementById('pause');
var addBtn = document.getElementById('add');
var shutdown1Btn = document.getElementById('shutdown1');
var shutdown2Btn = document.getElementById('shutdown2');
const sendHttpRequest = (method, url, data) => {
const promise = new Promise((resolve, reject) => {
......@@ -63,11 +66,22 @@ const controlPause = () => {
})
}
const controlShutdown= () => {
console.log("shutdown",this)
sendHttpRequest('POST', 'http://localhost:8080/control/shutdown?clientId=1').then(responseData =>{
console.log(responseData);
}).catch(err => {
console.log(err);
})
}
playBtn.addEventListener('click', controlPlay)
pauseBtn.addEventListener('click', controlPause)
addBtn.addEventListener('click', controlAdd)
shutdown1Btn.addEventListener('click', controlShutdown)
shutdown2Btn.addEventListener('click', controlShutdown)
......@@ -9,33 +9,39 @@
</head>
<body class="d-flex flex-column h-100" data-gr-c-s-loaded="true">
<div class="container flex-shrink-0">
<h1 class="mt-5">5D projection monitor</h1>
<p class="lead">Here you can perform basics testing and monitoring</p>
<button id="play" type="button" class="btn btn-primary">Play</button>
<button id="pause" type="button" class="btn btn-primary">Pause</button>
<button id="add" type="button" class="btn btn-primary">Add 1.mp4</button>
</div>
<footer class="footer mt-auto py-3">
<div class="container">
<span class="text-muted">This system was created by Ondrej Trojan</span>
</div>
</footer>
<script src="/js/jquery-3.4.1.slim.min.js"></script>
<script src="/js/popper.min.js"></script>
<script src="/js/bootstrap.min.js"></script>
<script src="/js/javascript.js"></script>
<div class="alert-box">
<div class="alert alert-primary" role="alert">
Please, if you make changes using this page, make sure you know what you are doing.
</div>
</div>
<div class="container">
<h1 class="display-4">5D projection monitor</h1>
<h2>Basic operations</h2>
<p class="lead">Here you can perform basics testing and monitoring, it serves as a secondary tool for control.</p>
<button id="play" type="button" class="btn btn-primary">Play</button>
<button id="pause" type="button" class="btn btn-primary">Pause</button>
<button id="add" type="button" class="btn btn-primary">Add 1.mp4</button>
</div>
<br>
<div class="container">
<h2>Restarting</h2>
<p class="lead">By restarting the application running on client will shutdown and restart automaticaly</p>
<button id="shutdown1" type="button" class="btn btn-danger">Restart 1</button>
<button id="shutdown2" type="button" class="btn btn-danger">Restart 2</button>
</div>
<footer class="footer mt-auto py-3">
<div class="container">
<span class="text-muted">This system was created by Ondrej Trojan</span>
</div>
</footer>
<script src="/js/jquery-3.4.1.slim.min.js"></script>
<script src="/js/popper.min.js"></script>
<script src="/js/bootstrap.min.js"></script>
<script src="/js/javascript.js"></script>
</body>
</html>
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment