feat: send firmware update through ws
This commit is contained in:
56
.cursor/rules/cleancode.mdc
Normal file
56
.cursor/rules/cleancode.mdc
Normal 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
111
.cursor/rules/gitflow.mdc
Normal 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
35
.cursor/rules/golang.mdc
Normal 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.
|
||||||
|
|
||||||
@@ -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))
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
Reference in New Issue
Block a user