Skip to content

Commit 72c01a7

Browse files
Merge pull request #3 from GravityDarkLab/add-monitoring
Add `javamelody` and extend endpoints to control multiple clients
2 parents d54d5ef + dbaff21 commit 72c01a7

8 files changed

Lines changed: 354 additions & 43 deletions

File tree

Dockerfile

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
FROM eclipse-temurin:17-jdk-focal
2+
3+
WORKDIR /app
4+
5+
COPY .mvn/ .mvn
6+
COPY mvnw pom.xml ./
7+
RUN chmod +x mvnw
8+
RUN ./mvnw dependency:go-offline
9+
10+
COPY src ./src
11+
12+
CMD ["./mvnw", "spring-boot:run"]

compose.yaml

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,31 @@
1+
version: '3.8'
2+
13
services:
4+
app:
5+
build:
6+
context: .
7+
dockerfile: Dockerfile
8+
ports:
9+
- "8080:8080"
10+
volumes:
11+
- .:/app
12+
- maven_cache:/root/.m2
13+
environment:
14+
SPRING_PROFILES_ACTIVE: dev
15+
JAVA_OPTS: "-Xmx512m -Xms256m"
16+
networks:
17+
- app-network
18+
healthcheck:
19+
test: [ "CMD", "curl", "-f", "http://localhost:8080/health/health" ]
20+
interval: 1m30s
21+
timeout: 10s
22+
retries: 3
23+
start_period: 40s
24+
25+
networks:
26+
app-network:
27+
driver: bridge
28+
29+
volumes:
30+
maven_cache:
31+
driver: local

pom.xml

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,24 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3-
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
3+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
44
<modelVersion>4.0.0</modelVersion>
55
<parent>
66
<groupId>org.springframework.boot</groupId>
77
<artifactId>spring-boot-starter-parent</artifactId>
88
<version>3.2.1</version>
99
<relativePath/> <!-- lookup parent from repository -->
1010
</parent>
11+
1112
<groupId>com.gravitylab</groupId>
1213
<artifactId>obs-controller-api</artifactId>
1314
<version>0.0.1-SNAPSHOT</version>
1415
<name>obs-controller-api</name>
1516
<description>API Controller for OBS</description>
1617
<properties>
1718
<java.version>17</java.version>
19+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
1820
</properties>
21+
1922
<dependencies>
2023
<dependency>
2124
<groupId>org.springframework.boot</groupId>
@@ -46,7 +49,15 @@
4649
<artifactId>json</artifactId>
4750
<version>20231013</version>
4851
</dependency>
49-
52+
<dependency>
53+
<groupId>org.springframework.boot</groupId>
54+
<artifactId>spring-boot-starter-actuator</artifactId>
55+
</dependency>
56+
<dependency>
57+
<groupId>net.bull.javamelody</groupId>
58+
<artifactId>javamelody-spring-boot-starter</artifactId>
59+
<version>2.0.1</version>
60+
</dependency>
5061
</dependencies>
5162

5263
<build>
Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,25 @@
11
package com.gravitylab.obscontrollerapi.config;
22

3+
import org.springdoc.core.models.GroupedOpenApi;
34
import org.springframework.context.annotation.Bean;
45
import org.springframework.context.annotation.Configuration;
56

67
import io.swagger.v3.oas.models.OpenAPI;
78
import io.swagger.v3.oas.models.info.Info;
9+
import io.swagger.v3.oas.models.info.License;
810

911
@Configuration
1012
public class OpenApiConfig {
1113
@Bean
1214
public OpenAPI customOpenAPI() {
1315
return new OpenAPI().info(new Info().title("OBS WebSocket API").version("v1.0")
14-
.description("API for controlling OBS through WebSocket"));
16+
.description("API for controlling OBS through WebSocket").license(new License().name("MIT License")
17+
.identifier("GravityLab").url("https://github.com/GravityDarkLab")));
1518
}
19+
20+
@Bean
21+
public GroupedOpenApi publicApi() {
22+
return GroupedOpenApi.builder().group("OBS").pathsToMatch("/obs/**").build();
23+
}
24+
1625
}
Lines changed: 124 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
package com.gravitylab.obscontrollerapi.controller;
22

3+
import java.util.List;
4+
35
import org.springframework.beans.factory.annotation.Autowired;
46
import org.springframework.http.ResponseEntity;
5-
import org.springframework.web.bind.annotation.PostMapping;
6-
import org.springframework.web.bind.annotation.RequestMapping;
7-
import org.springframework.web.bind.annotation.RequestParam;
8-
import org.springframework.web.bind.annotation.RestController;
7+
import org.springframework.web.bind.annotation.*;
98

109
import com.gravitylab.obscontrollerapi.service.OBSWebSocketService;
1110

11+
import io.swagger.v3.oas.annotations.Operation;
1212
import io.swagger.v3.oas.annotations.tags.Tag;
13+
import jakarta.servlet.http.HttpServletRequest;
1314
import lombok.extern.slf4j.Slf4j;
1415

1516
@RestController
@@ -25,10 +26,15 @@ public OBSController(OBSWebSocketService obsWebSocketService) {
2526
}
2627

2728
@Tag(name = "Connection Management")
29+
@Operation(summary = "Connects to an OBS instance", description = "Connects to an OBS instance, must be called before any other operation")
2830
@PostMapping("/connect")
29-
public ResponseEntity<?> connect(@RequestParam String ipAddress, @RequestParam int port,
30-
@RequestParam String password) {
31+
public ResponseEntity<?> connect(@RequestParam(required = false, defaultValue = "self") String ipAddress,
32+
@RequestParam(required = false, defaultValue = "4455") int port, @RequestParam String password,
33+
HttpServletRequest request) {
3134
try {
35+
if (ipAddress.equals("self")) {
36+
ipAddress = request.getRemoteAddr();
37+
}
3238
obsWebSocketService.connectClient(ipAddress, port, password);
3339
return ResponseEntity.ok("Connected to OBS at " + ipAddress + ":" + port);
3440
} catch (Exception e) {
@@ -38,37 +44,144 @@ public ResponseEntity<?> connect(@RequestParam String ipAddress, @RequestParam i
3844
}
3945

4046
@Tag(name = "Connection Management")
47+
@Operation(summary = "Connects to an OBS instance", description = "Connects to an OBS instance, must be called before any other operation. Requires no authentication")
48+
@PostMapping("/connectNoAuth")
49+
public ResponseEntity<?> connect(@RequestParam(required = false, defaultValue = "self") String ipAddress,
50+
@RequestParam(required = false, defaultValue = "4455") int port, HttpServletRequest request) {
51+
try {
52+
if (ipAddress.equals("self")) {
53+
ipAddress = request.getRemoteAddr();
54+
}
55+
obsWebSocketService.connectClient(ipAddress, port);
56+
return ResponseEntity.ok("Connected to OBS at " + ipAddress + ":" + port);
57+
} catch (Exception e) {
58+
log.error("Error connecting to OBS: ", e);
59+
return ResponseEntity.badRequest().body("Failed to connect: " + e.getMessage());
60+
}
61+
}
62+
63+
@Tag(name = "Connection Management")
64+
@Operation(summary = "Authenticates an OBS instance", description = "Authenticates an OBS instance, must be called after connecting, but not needed when no password is set")
4165
@PostMapping("/authenticate")
42-
public ResponseEntity<?> authenticate(@RequestParam String ipAddress, @RequestParam int port) {
66+
public ResponseEntity<?> authenticate(@RequestParam(required = false, defaultValue = "self") String ipAddress,
67+
@RequestParam(required = false, defaultValue = "4455") int port, HttpServletRequest request) {
68+
if (ipAddress.equals("self")) {
69+
ipAddress = request.getRemoteAddr();
70+
}
4371
obsWebSocketService.authenticate(ipAddress, port);
4472
return ResponseEntity.ok("Authenticated OBS at " + ipAddress + ":" + port);
4573
}
4674

4775
@Tag(name = "Connection Management")
76+
@Operation(summary = "Reconnects to an OBS instance", description = "Reconnects to an OBS instance, must be called if connection is lost")
4877
@PostMapping("/reconnect")
49-
public ResponseEntity<?> reconnect(@RequestParam String ipAddress, @RequestParam int port) {
78+
public ResponseEntity<?> reconnect(@RequestParam(required = false, defaultValue = "self") String ipAddress,
79+
@RequestParam(required = false, defaultValue = "4455") int port, HttpServletRequest request) {
80+
if (ipAddress.equals("self")) {
81+
ipAddress = request.getRemoteAddr();
82+
}
5083
obsWebSocketService.reconnect(ipAddress, port);
5184
return ResponseEntity.ok("Reconnected to OBS at " + ipAddress + ":" + port);
5285
}
86+
@Tag(name = "Connection Management")
87+
@Operation(summary = "Reconnects to all OBS instances", description = "Reconnects to all OBS instances, must be called if connection is lost")
88+
@PostMapping("/reconnectAll")
89+
public ResponseEntity<?> reconnectAll() {
90+
obsWebSocketService.reconnectAll();
91+
return ResponseEntity.ok("Reconnected to all OBS instances");
92+
}
5393

5494
@Tag(name = "Connection Management")
95+
@Operation(summary = "Disconnects from an OBS instance", description = "Disconnects from an OBS instance, called only at the end")
5596
@PostMapping("/disconnect")
56-
public ResponseEntity<?> disconnect(@RequestParam String ipAddress, @RequestParam int port) {
97+
public ResponseEntity<?> disconnect(@RequestParam(required = false, defaultValue = "self") String ipAddress,
98+
@RequestParam(required = false, defaultValue = "4455") int port, HttpServletRequest request) {
99+
if (ipAddress.equals("self")) {
100+
ipAddress = request.getRemoteAddr();
101+
}
57102
obsWebSocketService.disconnect(ipAddress, port);
58103
return ResponseEntity.ok("Disconnected from OBS at " + ipAddress + ":" + port);
59104
}
60105

106+
@Tag(name = "Connection Management")
107+
@Operation(summary = "Disconnects from all OBS instances", description = "Disconnects from all OBS instances, called only at the end")
108+
@PostMapping("/disconnectAll")
109+
public ResponseEntity<?> disconnectAll() {
110+
obsWebSocketService.disconnectAll();
111+
return ResponseEntity.ok("Disconnected from all OBS instances");
112+
}
113+
61114
@Tag(name = "Recording Control")
115+
@Operation(summary = "Starts recording on an OBS instance", description = "Starts recording on an OBS instance")
62116
@PostMapping("/startRecording")
63-
public ResponseEntity<?> startRecording(@RequestParam String ipAddress, @RequestParam int port) {
117+
public ResponseEntity<?> startRecording(@RequestParam(required = false, defaultValue = "self") String ipAddress,
118+
@RequestParam(required = false, defaultValue = "4455") int port, HttpServletRequest request) {
119+
if (ipAddress.equals("self")) {
120+
ipAddress = request.getRemoteAddr();
121+
}
64122
obsWebSocketService.startRecording(ipAddress, port);
65123
return ResponseEntity.ok("Started recording on OBS at " + ipAddress + ":" + port);
66124
}
67125

68126
@Tag(name = "Recording Control")
127+
@Operation(summary = "Starts recording on all OBS instances", description = "Starts recording on all OBS instances")
128+
@PostMapping("/startRecordingAll")
129+
public ResponseEntity<?> startRecordingAll() {
130+
obsWebSocketService.startRecordingAll();
131+
return ResponseEntity.ok("Started recording on all OBS instances");
132+
}
133+
134+
@Tag(name = "Recording Control")
135+
@Operation(summary = "Stops recording on an OBS instance", description = "Stops recording on an OBS instance")
69136
@PostMapping("/stopRecording")
70-
public ResponseEntity<?> stopRecording(@RequestParam String ipAddress, @RequestParam int port) {
137+
public ResponseEntity<?> stopRecording(@RequestParam(required = false, defaultValue = "self") String ipAddress,
138+
@RequestParam(required = false, defaultValue = "4455") int port, HttpServletRequest request) {
139+
if (ipAddress.equals("self")) {
140+
ipAddress = request.getRemoteAddr();
141+
}
71142
obsWebSocketService.stopRecording(ipAddress, port);
72143
return ResponseEntity.ok("Stopped recording on OBS at " + ipAddress + ":" + port);
73144
}
145+
146+
@Tag(name = "Recording Control")
147+
@Operation(summary = "Stops recording on all OBS instances", description = "Stops recording on all OBS instances")
148+
@PostMapping("/stopRecordingAll")
149+
public ResponseEntity<?> stopRecordingAll() {
150+
obsWebSocketService.stopRecordingAll();
151+
return ResponseEntity.ok("Stopped recording on all OBS instances");
152+
}
153+
154+
@Tag(name = "Health Check")
155+
@Operation(summary = "Checks for the connected instances", description = "Checks for the connected instances")
156+
@GetMapping("/ipAddresses")
157+
public ResponseEntity<?> getIpAddresses() {
158+
List<String> ipAddresses = obsWebSocketService.getAllIpAddresses();
159+
ipAddresses.sort(String::compareTo);
160+
return ResponseEntity.ok(ipAddresses);
161+
}
162+
163+
@Tag(name = "Health Check")
164+
@Operation(summary = "Checks for the number of connected instances", description = "Checks for the number of connected instances")
165+
@GetMapping("/count")
166+
public ResponseEntity<?> getCount() {
167+
int count = obsWebSocketService.getNumberOfClients();
168+
return ResponseEntity.ok(count);
169+
}
170+
171+
@Tag(name = "Health Check")
172+
@Operation(summary = "Test connection to an OBS instance", description = "Test connection to an OBS instance")
173+
@PostMapping("/testConnection")
174+
public ResponseEntity<?> testConnection(@RequestParam(required = false, defaultValue = "self") String ipAddress,
175+
@RequestParam(required = false, defaultValue = "4455") int port, HttpServletRequest request) {
176+
try {
177+
if (ipAddress.equals("self")) {
178+
ipAddress = request.getRemoteAddr();
179+
}
180+
String str = obsWebSocketService.testConnection(ipAddress, port);
181+
return ResponseEntity.ok(str);
182+
} catch (Exception e) {
183+
log.error("Error connecting to OBS: ", e);
184+
return ResponseEntity.badRequest().body("Failed to connect: " + e.getMessage());
185+
}
186+
}
74187
}

0 commit comments

Comments
 (0)