Skip to content

Commit c94382f

Browse files
committed
refactoring to events
1 parent 1b98dba commit c94382f

File tree

3 files changed

+718
-378
lines changed

3 files changed

+718
-378
lines changed

tools/REFACTORING_SUMMARY.md

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
# Refactoring Summary: Event-Based HyperfyAppServer with Separated Handlers
2+
3+
## 🎯 **What Was Accomplished**
4+
5+
### 1. **Core Architecture Transformation**
6+
- **Before**: Monolithic `HyperfyAppServer` with all functionality mixed together
7+
- **After**: Clean separation into two classes:
8+
- `HyperfyAppServer` - Event-driven infrastructure (EventEmitter, WebSocket management, HTTP)
9+
- `HyperfyAppServerHandler` - Business logic and message handling
10+
11+
### 2. **Event System Implementation**
12+
- Made `HyperfyAppServer` extend `EventEmitter`
13+
- All WebSocket messages now emit events: `auth`, `world_snapshot`, `ping`, `blueprint_modified`, `asset_response`, `request_model_content`
14+
- Added infrastructure events: `connection`, `disconnect`, `error`, `websocket_error`
15+
- Replaced switch-case message handling with event emission
16+
17+
### 3. **Handler Extraction**
18+
Successfully moved these methods from `HyperfyAppServer` to `HyperfyAppServerHandler`:
19+
- `handleAuth()` - User authentication logic
20+
- `handleWorldSnapshot()` - World state processing
21+
- `handleBlueprintModified()` - Blueprint change handling
22+
- `handleScriptChange()` - Script update processing
23+
- `handleConfigUpdate()` - Configuration file updates
24+
- `handleAssetChanges()` - Asset management and downloading
25+
- `handleAssetResponse()` - Asset response processing
26+
- `handleModelContentRequest()` - Model content serving
27+
28+
### 4. **Updated Integration**
29+
- Modified `setupDefaultEventHandlers()` to create and use `HyperfyAppServerHandler`
30+
- All handlers properly reference server through `this.server`
31+
- Maintained full backward compatibility
32+
33+
### 5. **Developer Experience**
34+
- Added convenience methods: `addMessageHandler()`, `removeMessageHandler()`, `broadcast()`, etc.
35+
- Enhanced documentation and examples showing handler extension patterns
36+
- Created comprehensive usage examples in `example-usage.js`
37+
38+
## 🚧 **Current State**
39+
40+
### What's Working
41+
- ✅ Server starts successfully
42+
- ✅ Event emission system functional
43+
- ✅ Handler separation complete for message processing
44+
- ✅ No linting errors
45+
- ✅ Backward compatibility maintained
46+
47+
### What Still Needs Migration
48+
These components are still in `HyperfyAppServer` but should move to `HyperfyAppServerHandler`:
49+
50+
#### File System Operations
51+
- `appsDir` property - Should be in handler, not server
52+
- `setupFileWatching()` - File watching logic
53+
- `watchExistingApps()` - App directory monitoring
54+
- `watchAppScript()` - Individual script file watching
55+
- `handleScriptFileChange()` - Script change response
56+
- `deployScriptToLinkedWorlds()` - Hot reload deployment
57+
58+
#### Hot Reload System
59+
- `hotReload` configuration - Should be handler responsibility
60+
- `fileWatchers` Map - File watcher management
61+
- `pendingDeployments` Map - Deployment debouncing
62+
63+
#### App Management
64+
- Any methods that currently access file watchers or apps directory
65+
66+
## 🎯 **Next Phase: File Operations Migration**
67+
68+
### Goals
69+
1. **Move file system responsibilities to handler class**
70+
- `appsDir`, `fileWatchers`, `pendingDeployments``HyperfyAppServerHandler`
71+
- All file watching logic → Handler
72+
- Hot reload configuration → Handler
73+
74+
2. **Maintain clean separation**
75+
- Server focuses on: connections, HTTP endpoints, event emission
76+
- Handler focuses on: file operations, business logic, app management
77+
78+
3. **Critical Constraint**:
79+
- **NO `defaultHandler` property on `HyperfyAppServer`**
80+
- If any server method needs handler access, move that method to handler instead
81+
82+
### Migration Strategy
83+
1. Move file system properties (`appsDir`, `fileWatchers`, `pendingDeployments`) to handler
84+
2. Move file watching methods to handler
85+
3. Update constructor and initialization flow
86+
4. Move any server methods that reference these properties to handler
87+
5. Update all cross-references and method calls
88+
89+
### Expected Outcome
90+
- `HyperfyAppServer`: Pure event infrastructure + HTTP + WebSocket management
91+
- `HyperfyAppServerHandler`: Complete business logic including file operations and hot reload
92+
93+
## 📋 **Files Modified So Far**
94+
- `tools/server.js` - Main refactoring
95+
- `tools/example-usage.js` - Usage examples with handler patterns
96+
- `tools/EVENT_BASED_SERVER.md` - Updated documentation
97+
98+
## 🔄 **Ready for Next Phase**
99+
The foundation is solid. Ready to continue with file operations migration while maintaining the clean architecture and avoiding any `defaultHandler` dependencies.

tools/example-usage.js

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
// Example of how to use the event-based HyperfyAppServer
2+
3+
const { HyperfyAppServer, HyperfyAppServerHandler } = require('./server.js')
4+
5+
// Create a new server instance
6+
const server = new HyperfyAppServer(8080, { hotReload: true })
7+
8+
// Example 1: Add custom auth validation
9+
server.addMessageHandler('auth', (ws, message) => {
10+
console.log('🔐 Custom auth validation for user:', message.userId)
11+
12+
// Example: Add custom validation logic
13+
if (message.authToken && message.authToken.includes('admin')) {
14+
console.log('🔑 Admin user detected')
15+
// You could add special privileges here
16+
}
17+
})
18+
19+
// Example 2: Log all world snapshots
20+
server.addMessageHandler('world_snapshot', (ws, message) => {
21+
console.log('📸 World snapshot received:', {
22+
worldUrl: message.worldUrl,
23+
blueprintCount: message.blueprints.length,
24+
entityCount: message.entities.length
25+
})
26+
})
27+
28+
// Example 3: Handle custom message types
29+
server.addMessageHandler('custom_game_event', (ws, message) => {
30+
console.log('🎮 Custom game event:', message.eventType)
31+
32+
// Broadcast the event to all other worlds
33+
const worldUrl = server.getWorldUrlForSocket(ws)
34+
server.broadcast({
35+
type: 'game_event_notification',
36+
fromWorld: worldUrl,
37+
eventData: message
38+
})
39+
})
40+
41+
// Example 4: Monitor connections and disconnections
42+
server.addConnectionHandler((ws, req) => {
43+
console.log('👋 New client connected from:', req.socket.remoteAddress)
44+
})
45+
46+
server.addDisconnectHandler((ws, userId) => {
47+
if (userId) {
48+
console.log('🚪 User left:', userId)
49+
50+
// Notify other users
51+
server.broadcast({
52+
type: 'user_left',
53+
userId: userId
54+
})
55+
}
56+
})
57+
58+
// Example 5: Handle unknown message types
59+
server.addMessageHandler('message', (ws, message) => {
60+
console.log('❓ Unknown message type received:', message.type)
61+
62+
// You could log to analytics, handle special cases, etc.
63+
})
64+
65+
// Example 6: Error handling
66+
server.on('error', (error, ws, data) => {
67+
console.error('💥 Message parsing error:', error.message)
68+
// Could log to error tracking service
69+
})
70+
71+
server.on('websocket_error', (error, ws) => {
72+
console.error('🔌 WebSocket error:', error.message)
73+
// Could handle connection recovery
74+
})
75+
76+
// Example 7: Periodic tasks using server state
77+
setInterval(() => {
78+
const connectedWorlds = server.getConnectedWorlds()
79+
console.log(`📊 Server stats: ${connectedWorlds.size} connected worlds`)
80+
81+
// Example: Send periodic updates to all worlds
82+
if (connectedWorlds.size > 0) {
83+
server.broadcast({
84+
type: 'server_stats',
85+
timestamp: new Date().toISOString(),
86+
connectedUsers: connectedClients.size
87+
})
88+
}
89+
}, 30000) // Every 30 seconds
90+
91+
// Example 8: Creating a custom handler class
92+
class CustomHyperfyHandler extends HyperfyAppServerHandler {
93+
constructor(server) {
94+
super(server)
95+
}
96+
97+
// Override or extend default handlers
98+
handleAuth(ws, message) {
99+
console.log('🔐 Custom handler: Enhanced auth validation')
100+
101+
// Call the parent handler for default behavior
102+
super.handleAuth(ws, message)
103+
104+
// Add custom logic
105+
const { userId, authToken } = message
106+
if (authToken && authToken.includes('premium')) {
107+
console.log('💎 Premium user detected:', userId)
108+
// Add premium-specific logic
109+
}
110+
}
111+
112+
handleWorldSnapshot(ws, message) {
113+
console.log('📸 Custom handler: Enhanced world snapshot processing')
114+
115+
// Call the parent handler
116+
super.handleWorldSnapshot(ws, message)
117+
118+
// Add custom analytics or processing
119+
console.log('📊 Analytics: Recording world snapshot data')
120+
}
121+
}
122+
123+
// Example 9: Using a custom handler instead of the default one
124+
function createServerWithCustomHandler() {
125+
const customServer = new HyperfyAppServer(8081, { hotReload: true })
126+
127+
// Replace the default handler with our custom one
128+
const customHandler = new CustomHyperfyHandler(customServer)
129+
customServer.defaultHandler = customHandler
130+
customHandler.attachHandlers()
131+
132+
return customServer
133+
}
134+
135+
// Start the server
136+
server.start()
137+
138+
console.log('🚀 Event-based Hyperfy server started with custom handlers!')
139+
console.log('📖 See the code above for examples of:')
140+
console.log(' - Adding custom message handlers')
141+
console.log(' - Monitoring connections and disconnections')
142+
console.log(' - Handling custom message types')
143+
console.log(' - Error handling')
144+
console.log(' - Creating custom handler classes')
145+
console.log(' - Extending default behavior')

0 commit comments

Comments
 (0)