feat: send firmware update through ws

This commit is contained in:
2025-10-21 13:15:15 +02:00
parent 3098e2166b
commit 9435af0137
5 changed files with 269 additions and 0 deletions

View File

@@ -0,0 +1,56 @@
---
description: Guidelines for writing clean, maintainable, and human-readable code. Apply these rules when writing or reviewing code to ensure consistency and quality.
globs:
alwaysApply: true
---
# Clean Code Guidelines
## Constants Over Magic Numbers
- Replace hard-coded values with named constants
- Use descriptive constant names that explain the value's purpose
- Keep constants at the top of the file or in a dedicated constants file
## Meaningful Names
- Variables, functions, and classes should reveal their purpose
- Names should explain why something exists and how it's used
- Avoid abbreviations unless they're universally understood
## Smart Comments
- Don't comment on what the code does - make the code self-documenting
- Use comments to explain why something is done a certain way
- Document APIs, complex algorithms, and non-obvious side effects
## Single Responsibility
- Each function should do exactly one thing
- Functions should be small and focused
- If a function needs a comment to explain what it does, it should be split
## DRY (Don't Repeat Yourself)
- Extract repeated code into reusable functions
- Share common logic through proper abstraction
- Maintain single sources of truth
## Clean Structure
- Keep related code together
- Organize code in a logical hierarchy
- Use consistent file and folder naming conventions
## Encapsulation
- Hide implementation details
- Expose clear interfaces
- Move nested conditionals into well-named functions
## Code Quality Maintenance
- Refactor continuously
- Fix technical debt early
- Leave code cleaner than you found it
## Testing
- Write tests before fixing bugs
- Keep tests readable and maintainable
- Test edge cases and error conditions
## Version Control
- Write clear commit messages
- Make small, focused commits
- Use meaningful branch names

111
.cursor/rules/gitflow.mdc Normal file
View File

@@ -0,0 +1,111 @@
---
description: Gitflow Workflow Rules. These rules should be applied when performing git operations.
---
# Gitflow Workflow Rules
## Main Branches
### main (or master)
- Contains production-ready code
- Never commit directly to main
- Only accepts merges from:
- hotfix/* branches
- release/* branches
- Must be tagged with version number after each merge
### develop
- Main development branch
- Contains latest delivered development changes
- Source branch for feature branches
- Never commit directly to develop
## Supporting Branches
### feature/*
- Branch from: develop
- Merge back into: develop
- Naming convention: feature/[issue-id]-descriptive-name
- Example: feature/123-user-authentication
- Must be up-to-date with develop before creating PR
- Delete after merge
### release/*
- Branch from: develop
- Merge back into:
- main
- develop
- Naming convention: release/vX.Y.Z
- Example: release/v1.2.0
- Only bug fixes, documentation, and release-oriented tasks
- No new features
- Delete after merge
### hotfix/*
- Branch from: main
- Merge back into:
- main
- develop
- Naming convention: hotfix/vX.Y.Z
- Example: hotfix/v1.2.1
- Only for urgent production fixes
- Delete after merge
## Commit Messages
- Format: `type(scope): description`
- Types:
- feat: New feature
- fix: Bug fix
- docs: Documentation changes
- style: Formatting, missing semicolons, etc.
- refactor: Code refactoring
- test: Adding tests
- chore: Maintenance tasks
## Version Control
### Semantic Versioning
- MAJOR version for incompatible API changes
- MINOR version for backwards-compatible functionality
- PATCH version for backwards-compatible bug fixes
## Pull Request Rules
1. All changes must go through Pull Requests
2. Required approvals: minimum 1
3. CI checks must pass
4. No direct commits to protected branches (main, develop)
5. Branch must be up to date before merging
6. Delete branch after merge
## Branch Protection Rules
### main & develop
- Require pull request reviews
- Require status checks to pass
- Require branches to be up to date
- Include administrators in restrictions
- No force pushes
- No deletions
## Release Process
1. Create release branch from develop
2. Bump version numbers
3. Fix any release-specific issues
4. Create PR to main
5. After merge to main:
- Tag release
- Merge back to develop
- Delete release branch
## Hotfix Process
1. Create hotfix branch from main
2. Fix the issue
3. Bump patch version
4. Create PR to main
5. After merge to main:
- Tag release
- Merge back to develop
- Delete hotfix branch

35
.cursor/rules/golang.mdc Normal file
View File

@@ -0,0 +1,35 @@
---
description:
globs: *.go
alwaysApply: true
---
You are an expert AI programming assistant specializing in building APIs with Go, using the standard library's net/http package and the new ServeMux introduced in Go 1.22.
Always use the latest stable version of Go (1.22 or newer) and be familiar with RESTful API design principles, best practices, and Go idioms.
- Follow the user's requirements carefully & to the letter.
- First think step-by-step - describe your plan for the API structure, endpoints, and data flow in pseudocode, written out in great detail.
- Confirm the plan, then write code!
- Write correct, up-to-date, bug-free, fully functional, secure, and efficient Go code for APIs.
- Use the standard library's net/http package for API development:
- Utilize the new ServeMux introduced in Go 1.22 for routing
- Implement proper handling of different HTTP methods (GET, POST, PUT, DELETE, etc.)
- Use method handlers with appropriate signatures (e.g., func(w http.ResponseWriter, r *http.Request))
- Leverage new features like wildcard matching and regex support in routes
- Implement proper error handling, including custom error types when beneficial.
- Use appropriate status codes and format JSON responses correctly.
- Implement input validation for API endpoints.
- Utilize Go's built-in concurrency features when beneficial for API performance.
- Follow RESTful API design principles and best practices.
- Include necessary imports, package declarations, and any required setup code.
- Implement proper logging using the standard library's log package or a simple custom logger.
- Consider implementing middleware for cross-cutting concerns (e.g., logging, authentication).
- Implement rate limiting and authentication/authorization when appropriate, using standard library features or simple custom implementations.
- Leave NO todos, placeholders, or missing pieces in the API implementation.
- Be concise in explanations, but provide brief comments for complex logic or Go-specific idioms.
- If unsure about a best practice or implementation detail, say so instead of guessing.
- Offer suggestions for testing the API endpoints using Go's testing package.
Always prioritize security, scalability, and maintainability in your API designs and implementations. Leverage the power and simplicity of Go's standard library to create efficient and idiomatic APIs.

View File

@@ -538,6 +538,9 @@ func (hs *HTTPServer) updateNodeFirmware(w http.ResponseWriter, r *http.Request)
"file_size": len(fileData), "file_size": len(fileData),
}).Info("Firmware upload received") }).Info("Firmware upload received")
// Broadcast firmware upload status to WebSocket clients
hs.webSocketServer.BroadcastFirmwareUploadStatus(nodeIP, "uploading", filename, len(fileData))
// Send immediate acknowledgment to client // Send immediate acknowledgment to client
response := struct { response := struct {
Success bool `json:"success"` Success bool `json:"success"`
@@ -591,6 +594,9 @@ func (hs *HTTPServer) updateNodeFirmware(w http.ResponseWriter, r *http.Request)
"node_ip": nodeIP, "node_ip": nodeIP,
"error": err.Error(), "error": err.Error(),
}).Error("Error uploading firmware to device") }).Error("Error uploading firmware to device")
// Broadcast failure status to WebSocket clients
hs.webSocketServer.BroadcastFirmwareUploadStatus(nodeIP, "failed", filename, len(fileData))
return return
} }
@@ -600,6 +606,9 @@ func (hs *HTTPServer) updateNodeFirmware(w http.ResponseWriter, r *http.Request)
"node_ip": nodeIP, "node_ip": nodeIP,
"message": result.Message, "message": result.Message,
}).Error("Device reported firmware update failure") }).Error("Device reported firmware update failure")
// Broadcast failure status to WebSocket clients
hs.webSocketServer.BroadcastFirmwareUploadStatus(nodeIP, "failed", filename, len(fileData))
return return
} }
@@ -609,6 +618,9 @@ func (hs *HTTPServer) updateNodeFirmware(w http.ResponseWriter, r *http.Request)
"filename": filename, "filename": filename,
"result": result.Status, "result": result.Status,
}).Info("Firmware upload completed successfully") }).Info("Firmware upload completed successfully")
// Broadcast success status to WebSocket clients
hs.webSocketServer.BroadcastFirmwareUploadStatus(nodeIP, "completed", filename, len(fileData))
}() }()
} }

View File

@@ -279,6 +279,61 @@ func (wss *WebSocketServer) broadcastNodeDiscovery(nodeIP, action string) {
} }
} }
// BroadcastFirmwareUploadStatus sends firmware upload status updates to all clients
func (wss *WebSocketServer) BroadcastFirmwareUploadStatus(nodeIP, status, filename string, fileSize int) {
wss.mutex.RLock()
clients := make([]*websocket.Conn, 0, len(wss.clients))
for client := range wss.clients {
clients = append(clients, client)
}
wss.mutex.RUnlock()
if len(clients) == 0 {
return
}
message := struct {
Type string `json:"type"`
NodeIP string `json:"nodeIp"`
Status string `json:"status"`
Filename string `json:"filename"`
FileSize int `json:"fileSize"`
Timestamp string `json:"timestamp"`
}{
Type: "firmware_upload_status",
NodeIP: nodeIP,
Status: status,
Filename: filename,
FileSize: fileSize,
Timestamp: time.Now().Format(time.RFC3339),
}
data, err := json.Marshal(message)
if err != nil {
wss.logger.WithError(err).Error("Failed to marshal firmware upload status")
return
}
wss.logger.WithFields(log.Fields{
"node_ip": nodeIP,
"status": status,
"filename": filename,
"file_size": fileSize,
"clients": len(clients),
}).Debug("Broadcasting firmware upload status to WebSocket clients")
// Send to all clients with write synchronization
wss.writeMutex.Lock()
defer wss.writeMutex.Unlock()
for _, client := range clients {
client.SetWriteDeadline(time.Now().Add(5 * time.Second))
if err := client.WriteMessage(websocket.TextMessage, data); err != nil {
wss.logger.WithError(err).Error("Failed to send firmware upload status to client")
}
}
}
// getCurrentClusterMembers fetches real cluster data from SPORE nodes // getCurrentClusterMembers fetches real cluster data from SPORE nodes
func (wss *WebSocketServer) getCurrentClusterMembers() ([]client.ClusterMember, error) { func (wss *WebSocketServer) getCurrentClusterMembers() ([]client.ClusterMember, error) {
nodes := wss.nodeDiscovery.GetNodes() nodes := wss.nodeDiscovery.GetNodes()