feat: externalize cluster integration and API
This commit is contained in:
204
README.md
204
README.md
@@ -1,182 +1,114 @@
|
||||
# SPORE UI
|
||||
# SPORE UI Frontend
|
||||
|
||||
Zero-configuration web interface for monitoring and managing SPORE embedded systems.
|
||||
Frontend web interface for monitoring and managing SPORE embedded systems. Now works in conjunction with the SPORE Gateway backend service.
|
||||
|
||||
## Architecture
|
||||
|
||||
This frontend server works together with the **SPORE Gateway** (spore-gateway) backend service:
|
||||
|
||||
- **spore-ui**: Serves the static frontend files and provides the user interface
|
||||
- **spore-gateway**: Handles UDP node discovery, API endpoints, and WebSocket connections
|
||||
|
||||
## Features
|
||||
|
||||
- **🌐 Cluster Monitoring**: Real-time view of all cluster members with auto-discovery
|
||||
- **🌐 Cluster Monitoring**: Real-time view of all cluster members via spore-gateway
|
||||
- **📊 Node Details**: Detailed system information including running tasks and available endpoints
|
||||
- **🚀 OTA**: Clusterwide over-the-air firmware updates
|
||||
- **📱 Responsive**: Works on all devices and screen sizes
|
||||
- **🖥️ Terminal**: Terminal for interacting with a node's WebSocket
|
||||
- **🔗 Gateway Integration**: Seamlessly connects to spore-gateway for all backend functionality
|
||||
|
||||
## Screenshots
|
||||
### Cluster
|
||||

|
||||

|
||||
### Topology
|
||||

|
||||

|
||||
### Monitoring
|
||||

|
||||

|
||||
### Firmware
|
||||

|
||||
|
||||
## Getting Started
|
||||
|
||||
### Prerequisites
|
||||
1. **Install dependencies**: `npm install`
|
||||
2. **Start the server**: `npm start`
|
||||
3. **Open in browser**: `http://localhost:3001`
|
||||
2. **Start spore-gateway**: `./spore-gateway` (in the spore-gateway directory)
|
||||
3. **Start frontend server**: `npm start`
|
||||
|
||||
## API Endpoints
|
||||
### Access
|
||||
- **Frontend UI**: `http://localhost:3000`
|
||||
- **API Backend**: spore-gateway runs on port 3001
|
||||
- **WebSocket**: Connects to spore-gateway on port 3001
|
||||
|
||||
- **`/`** - Main UI page
|
||||
- **`/api/cluster/members`** - Get cluster member information
|
||||
- **`/api/tasks/status`** - Get task status
|
||||
- **`/api/node/status`** - Get system status
|
||||
- **`/api/node/status/:ip`** - Get status from specific node
|
||||
## API Integration
|
||||
|
||||
The frontend automatically connects to the spore-gateway for:
|
||||
|
||||
- **Cluster Discovery**: `/api/discovery/*` endpoints
|
||||
- **Node Management**: `/api/node/*` endpoints
|
||||
- **Task Monitoring**: `/api/tasks/*` endpoints
|
||||
- **Real-time Updates**: WebSocket connections via `/ws`
|
||||
|
||||
## Technologies Used
|
||||
|
||||
- **Backend**: Express.js, Node.js
|
||||
- **Backend Integration**: Express.js server connecting to spore-gateway
|
||||
- **Frontend**: Vanilla JavaScript, CSS3, HTML5
|
||||
- **Framework**: Custom component-based architecture
|
||||
- **API**: SPORE Embedded System API
|
||||
- **API**: SPORE Embedded System API via spore-gateway
|
||||
- **Design**: Glassmorphism, CSS Grid, Flexbox
|
||||
|
||||
## UDP Heartbeat Discovery
|
||||
## Development
|
||||
|
||||
The backend now includes automatic UDP heartbeat-based discovery for SPORE nodes on the network. This eliminates the need for hardcoded IP addresses and provides a self-healing, scalable solution for managing SPORE clusters.
|
||||
|
||||
### 🚀 How It Works
|
||||
|
||||
1. **UDP Server**: The backend listens on port 4210 for UDP messages
|
||||
2. **Heartbeat Message**: Nodes send `CLUSTER_HEARTBEAT` messages to broadcast address `255.255.255.255:4210`
|
||||
3. **Auto Configuration**: When a heartbeat message is received, the source IP is automatically used to configure the SporeApiClient
|
||||
4. **Dynamic Updates**: The system automatically switches to the most recently seen node as the primary connection
|
||||
5. **Health Monitoring**: Continuous monitoring of node availability with automatic failover
|
||||
|
||||
### 📡 Heartbeat Protocol
|
||||
|
||||
- **Port**: 4210 (configurable via `UDP_PORT` constant)
|
||||
- **Message**: `CLUSTER_HEARTBEAT` (configurable via `HEARTBEAT_MESSAGE` constant)
|
||||
- **Broadcast**: `255.255.255.255:4210`
|
||||
- **Protocol**: UDP broadcast listening
|
||||
- **Auto-binding**: Automatically binds to the specified port on startup
|
||||
|
||||
### 🔧 Setup Instructions
|
||||
|
||||
#### Backend Setup
|
||||
```bash
|
||||
# Start the backend server
|
||||
npm start
|
||||
|
||||
# The server will automatically:
|
||||
# - Start HTTP server on port 3001
|
||||
# - Start UDP heartbeat server on port 4210
|
||||
# - Wait for CLUSTER_HEARTBEAT messages
|
||||
### File Structure
|
||||
```
|
||||
spore-ui/
|
||||
├── public/ # Static frontend files
|
||||
│ ├── index.html # Main HTML page
|
||||
│ ├── scripts/ # JavaScript components
|
||||
│ └── styles/ # CSS stylesheets
|
||||
├── index.js # Simple static file server
|
||||
└── package.json # Node.js dependencies
|
||||
```
|
||||
|
||||
#### Node Configuration
|
||||
SPORE nodes should send heartbeat messages periodically:
|
||||
### Key Changes
|
||||
- **Simplified Backend**: Now only serves static files
|
||||
- **Gateway Integration**: All API calls go through spore-gateway
|
||||
- **WebSocket Proxy**: Real-time updates via spore-gateway
|
||||
- **UDP Discovery**: Handled by spore-gateway service
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
|
||||
**Frontend not connecting to gateway**
|
||||
```bash
|
||||
# Recommended: Send every 30-60 seconds
|
||||
# Message format: "CLUSTER_HEARTBEAT:hostname"
|
||||
# Target: 255.255.255.255:4210
|
||||
```
|
||||
|
||||
### 🌐 Cluster Endpoints
|
||||
|
||||
#### Cluster Management
|
||||
- `GET /api/discovery/nodes` - View all cluster nodes and current status
|
||||
- `POST /api/discovery/refresh` - Manually trigger cluster refresh
|
||||
- `POST /api/discovery/primary/:ip` - Manually set a specific node as primary
|
||||
- `POST /api/discovery/random-primary` - Randomly select a new primary node
|
||||
|
||||
#### Health Monitoring
|
||||
- `GET /api/health` - Comprehensive health check including cluster status
|
||||
|
||||
### 🧪 Testing & Development
|
||||
|
||||
#### Test Scripts
|
||||
```bash
|
||||
# Send discovery messages to test the system
|
||||
npm run test-discovery broadcast
|
||||
|
||||
# Send to specific IP
|
||||
npm run test-discovery 192.168.1.100
|
||||
|
||||
# Send multiple messages
|
||||
npm run test-discovery broadcast 5
|
||||
|
||||
# Test random primary node selection
|
||||
npm run test-random-selection
|
||||
|
||||
# Monitor discovery in real-time
|
||||
npm run demo-discovery
|
||||
```
|
||||
|
||||
#### Manual Testing
|
||||
```bash
|
||||
# Check discovery status
|
||||
curl http://localhost:3001/api/discovery/nodes
|
||||
|
||||
# Check health
|
||||
# Check if spore-gateway is running
|
||||
curl http://localhost:3001/api/health
|
||||
|
||||
# Manual refresh
|
||||
curl -X POST http://localhost:3001/api/discovery/refresh
|
||||
|
||||
# Random primary selection
|
||||
curl -X POST http://localhost:3001/api/discovery/random-primary
|
||||
|
||||
# Set specific primary
|
||||
curl -X POST http://localhost:3001/api/discovery/primary/192.168.1.100
|
||||
# Verify gateway health
|
||||
# Should return gateway health status
|
||||
```
|
||||
|
||||
### 🔍 Troubleshooting
|
||||
|
||||
#### Common Issues
|
||||
|
||||
**No Nodes Discovered**
|
||||
**WebSocket connection issues**
|
||||
```bash
|
||||
# Check if backend is running
|
||||
curl http://localhost:3001/api/health
|
||||
# Check WebSocket endpoint
|
||||
curl http://localhost:3001/api/test/websocket
|
||||
|
||||
# Verify UDP port is open
|
||||
netstat -tulpn | grep 4210
|
||||
|
||||
# Send test discovery message
|
||||
npm run test-discovery broadcast
|
||||
# Verify gateway WebSocket server is running
|
||||
```
|
||||
|
||||
**UDP Port Already in Use**
|
||||
**No cluster data**
|
||||
```bash
|
||||
# Check for conflicting processes
|
||||
netstat -tulpn | grep 4210
|
||||
|
||||
# Kill conflicting processes or change port in code
|
||||
# Restart backend server
|
||||
```
|
||||
|
||||
**Client Not Initialized**
|
||||
```bash
|
||||
# Check discovery status
|
||||
# Check gateway discovery status
|
||||
curl http://localhost:3001/api/discovery/nodes
|
||||
|
||||
# Verify nodes are sending discovery messages
|
||||
# Check network connectivity
|
||||
# Verify SPORE nodes are sending heartbeat messages
|
||||
```
|
||||
|
||||
#### Debug Commands
|
||||
```bash
|
||||
# Check discovery status
|
||||
curl http://localhost:3001/api/discovery/nodes
|
||||
## Architecture Benefits
|
||||
|
||||
# Check health
|
||||
curl http://localhost:3001/api/health
|
||||
|
||||
# Manual refresh
|
||||
curl -X POST http://localhost:3001/api/discovery/refresh
|
||||
|
||||
# Set primary node
|
||||
curl -X POST http://localhost:3001/api/discovery/primary/192.168.1.100
|
||||
```
|
||||
1. **Separation of Concerns**: Frontend handles UI, gateway handles backend logic
|
||||
2. **Scalability**: Gateway can handle multiple frontend instances
|
||||
3. **Maintainability**: Clear separation between presentation and business logic
|
||||
4. **Performance**: Gateway can optimize API calls and caching
|
||||
5. **Reliability**: Gateway provides failover and health monitoring
|
||||
|
||||
1164
index-standalone.js
Normal file
1164
index-standalone.js
Normal file
File diff suppressed because it is too large
Load Diff
@@ -159,9 +159,9 @@ class WebSocketClient {
|
||||
const wsProtocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
|
||||
|
||||
if (currentHost === 'localhost' || currentHost === '127.0.0.1') {
|
||||
this.wsUrl = `${wsProtocol}//localhost:3001`;
|
||||
this.wsUrl = `${wsProtocol}//localhost:3001/ws`;
|
||||
} else {
|
||||
this.wsUrl = `${wsProtocol}//${currentHost}:3001`;
|
||||
this.wsUrl = `${wsProtocol}//${currentHost}:3001/ws`;
|
||||
}
|
||||
|
||||
logger.debug('WebSocket Client initialized with URL:', this.wsUrl);
|
||||
|
||||
Reference in New Issue
Block a user