Skip to content

Commit 46c8ae2

Browse files
committed
Update for newer Red5 Pro and loss of SharedObject support there
1 parent ec7bf87 commit 46c8ae2

File tree

10 files changed

+407
-123
lines changed

10 files changed

+407
-123
lines changed

.vscode/settings.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"java.compile.nullAnalysis.mode": "disabled",
3+
"java.configuration.updateBuildConfiguration": "automatic"
4+
}

CLAUDE.md

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
# CLAUDE.md
2+
3+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4+
5+
## Project Overview
6+
7+
This is a Red5 WebSocket chat application demo that demonstrates real-time chat functionality using WebSockets with a Red5 server. The application provides both WebSocket and Flash/Shared Object communication channels.
8+
9+
## Build Commands
10+
11+
- **Build**: `mvn package` - Builds the application and creates a WAR file
12+
- **Default goal**: `package` - Maven's default goal is set to package
13+
14+
## Architecture
15+
16+
### Core Components
17+
18+
1. **Application.java** (`src/main/java/org/red5/demos/chat/Application.java`):
19+
- Main Red5 application entry point extending `MultiThreadedApplicationAdapter`
20+
- Handles application lifecycle (start/stop)
21+
- Spring-aware component
22+
23+
2. **WebSocketChatDataListener.java** (`src/main/java/org/red5/demos/chat/WebSocketChatDataListener.java`):
24+
- Primary WebSocket message handler extending `WebSocketDataListener`
25+
- Manages WebSocket connections in a HashSet
26+
- Routes messages between WebSocket clients and shared objects
27+
- Handles both JSON and plain text messages
28+
- Uses "chat" protocol identifier
29+
30+
3. **Router.java** (`src/main/java/org/red5/demos/chat/Router.java`):
31+
- Bridges WebSocket messages to Red5 shared objects
32+
- Enables cross-platform communication (WebSocket ↔ Flash clients)
33+
34+
### Configuration
35+
36+
- **Spring Configuration**: `src/main/webapp/WEB-INF/red5-web.xml`
37+
- Defines WebSocket scope and listeners
38+
- Wires components together (Application, Router, WebSocketChatDataListener)
39+
- **Properties**: `src/main/webapp/WEB-INF/red5-web.properties`
40+
- **Web Configuration**: Requires WebSocketFilter servlet configuration for WebSocket support
41+
42+
### Message Flow
43+
44+
1. WebSocket clients connect and are added to connections set
45+
2. Messages received via `onWSMessage()` are:
46+
- Parsed (JSON detection and parsing)
47+
- Broadcast to all WebSocket connections on same path via `sendToAll()`
48+
- Routed to shared objects via Router for Flash client compatibility
49+
3. Path-based routing enables multiple chat rooms
50+
51+
## Deployment
52+
53+
The application packages as a WAR file that should be deployed to the Red5 server's webapps directory. Default port is 5080.
54+
55+
## Dependencies
56+
57+
- Red5 Server 2.0.19
58+
- Spring Framework 6.2.8 (beans, context, context-support)
59+
- Apache MINA 2.0.23
60+
- Gson 2.13.1 for JSON parsing
61+
- Java 17 (updated from Java 11)
62+
63+
## Key Design Patterns
64+
65+
- Uses Spring dependency injection for component wiring
66+
- Dual communication channels (WebSocket + Shared Objects) for cross-platform support
67+
- Path-based message routing for multi-room functionality
68+
- Protocol-based message filtering

README.md

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
1-
Chat application
2-
================
1+
# Chat application
32

43
Red5 WebSocket chat application example.
54

6-
The example <i>index.html</i> defaults to using a WebSocket connection to localhost on port 5080.
5+
The example `index.html` defaults to using a WebSocket connection to localhost on port 5080.
6+
7+
## Add the WebSocket filter servlet to webapps that require WebSocket support
78

8-
# Add the WebSocket filter servlet to webapps that require WebSocket support
9-
109
```xml
1110
<filter>
1211
<filter-name>WebSocketFilter</filter-name>
@@ -31,8 +30,8 @@ Deploy your application by copying the war file into your <i>red5/webapps</i> di
3130

3231
After deploy is complete, go to http://localhost:5080/chat/ in your browser (open two tabs if you want to chat back and forth on the same computer).
3332

34-
Pre-compiled WAR
35-
----------------
33+
## Pre-compiled WAR
34+
3635
You can find [compiled artifacts via Maven](http://mvnrepository.com/artifact/org.red5.demos/chat)
3736

38-
[Direct Download](https://oss.sonatype.org/content/repositories/releases/org/red5/demos/chat/2.0.0/chat-2.0.0.war)
37+
[Direct Download](https://oss.sonatype.org/content/repositories/releases/org/red5/demos/chat/2.0.19/chat-2.0.19.war)

pom.xml

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<parent>
44
<groupId>org.red5</groupId>
55
<artifactId>red5-parent</artifactId>
6-
<version>1.3.33</version>
6+
<version>2.0.19</version>
77
</parent>
88
<modelVersion>4.0.0</modelVersion>
99
<groupId>org.red5.demos</groupId>
@@ -48,11 +48,11 @@
4848
<skipTests>true</skipTests>
4949
<!-- to be or not to be verbose -->
5050
<verbose>false</verbose>
51-
<maven.compiler.source>1.11</maven.compiler.source>
52-
<maven.compiler.target>1.11</maven.compiler.target>
53-
<java.release.level>11</java.release.level>
54-
<red5.version>1.3.33</red5.version>
55-
<gson.version>2.9.0</gson.version>
51+
<maven.compiler.source>17</maven.compiler.source>
52+
<maven.compiler.target>17</maven.compiler.target>
53+
<java.release.level>17</java.release.level>
54+
<red5.version>2.0.19</red5.version>
55+
<gson.version>2.13.1</gson.version>
5656
</properties>
5757
<build>
5858
<defaultGoal>package</defaultGoal>
@@ -68,7 +68,7 @@
6868
</plugin>
6969
<plugin>
7070
<artifactId>maven-war-plugin</artifactId>
71-
<version>3.3.1</version>
71+
<version>3.4.0</version>
7272
<configuration>
7373
<packagingIncludes>*.html,*.swf,*.js,*.swz,WEB-INF/*.properties,WEB-INF/*.xml,WEB-INF/classes/**</packagingIncludes>
7474
<packagingExcludes>WEB-INF/lib/*.jar</packagingExcludes>

red5-websocket-chat.code-workspace

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"folders": [
3+
{
4+
"path": "."
5+
}
6+
],
7+
"settings": {
8+
"java.compile.nullAnalysis.mode": "disabled",
9+
"java.configuration.updateBuildConfiguration": "automatic"
10+
}
11+
}

src/main/java/org/red5/demos/chat/Application.java

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
package org.red5.demos.chat;
22

3+
import org.red5.net.websocket.WebSocketPlugin;
4+
import org.red5.net.websocket.WebSocketScopeManager;
35
import org.red5.server.adapter.MultiThreadedApplicationAdapter;
6+
import org.red5.server.api.Red5;
47
import org.red5.server.api.scope.IScope;
8+
import org.red5.server.plugin.PluginRegistry;
59
import org.slf4j.Logger;
610
import org.slf4j.LoggerFactory;
711
import org.springframework.beans.BeansException;
@@ -22,14 +26,64 @@ public class Application extends MultiThreadedApplicationAdapter implements Appl
2226
@SuppressWarnings("unused")
2327
private ApplicationContext applicationContext;
2428

29+
private Thread startupThread;
30+
2531
@Override
2632
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
2733
this.applicationContext = applicationContext;
2834
}
2935

3036
@Override
3137
public boolean appStart(IScope scope) {
32-
log.info("Chat starting");
38+
log.info("Chat starting on scope: {} path: {}", scope.getName(), scope.getContextPath());
39+
if (startupThread != null && startupThread.isAlive()) {
40+
log.warn("Startup thread is already running, skipping appStart");
41+
return false;
42+
}
43+
final Application app = this;
44+
startupThread = Thread.ofVirtual().start(new Runnable() {
45+
@Override
46+
public void run() {
47+
String path = scope.getContextPath();
48+
try {
49+
while (!Red5.isPluginsReady()) {
50+
log.info("Waiting for plugins to be ready...");
51+
Thread.sleep(1000L);
52+
}
53+
log.info("Plugins are ready, proceeding with chat application startup");
54+
do {
55+
WebSocketPlugin webSocketPlugin = (WebSocketPlugin) PluginRegistry.getPlugin(WebSocketPlugin.NAME);
56+
if (webSocketPlugin == null) {
57+
log.warn("WebSocketPlugin is null, cannot start chat application");
58+
Thread.sleep(100L);
59+
continue;
60+
}
61+
WebSocketScopeManager webSocketScopeManager = webSocketPlugin.getManager(path);
62+
if (webSocketScopeManager == null) {
63+
log.warn("WebSocketScopeManager is null, cannot start chat application");
64+
Thread.sleep(100L);
65+
continue;
66+
}
67+
// Initialize the router
68+
Router router = new Router();
69+
router.setApp(app);
70+
scope.setAttribute("router", router);
71+
log.info("Router set in scope: {}", scope.getName());
72+
// Register the WebSocketChatDataListener
73+
WebSocketChatDataListener chatListener = new WebSocketChatDataListener();
74+
chatListener.setRouter(router);
75+
scope.setAttribute("chatListener", chatListener);
76+
log.info("Chat listener set in scope: {}", scope.getName());
77+
// Start the WebSocketChatDataListener
78+
webSocketScopeManager.addListener(chatListener, path);
79+
log.info("WebSocketChatDataListener added to WebSocket scope: {}", path);
80+
break; // exit the loop if everything is set up correctly
81+
} while(true);
82+
} catch (Exception e) {
83+
log.error("Error occurred while starting chat application", e);
84+
}
85+
}
86+
});
3387
return super.appStart(scope);
3488
}
3589

@@ -39,4 +93,8 @@ public void appStop(IScope scope) {
3993
super.appStop(scope);
4094
}
4195

96+
public void messageTransmit(String message) {
97+
log.info("Message transmitted: {}", message);
98+
}
99+
42100
}

0 commit comments

Comments
 (0)