feat: multiple machines support#4
Conversation
- Replace env vars with YAML configuration (config.yaml or WOL_CONFIG env var) - Update /wake endpoint to support ?device=name or direct ?mac=&ip= parameters - Remove godotenv dependency, add gopkg.in/yaml.v3 - Update README with new configuration examples BREAKING CHANGE: Environment variables (WOL_MAC, WOL_IP, etc.) no longer supported. Use YAML config or new API parameters.
There was a problem hiding this comment.
Pull request overview
This PR refactors the WOL server from environment variable-based configuration to YAML-based configuration, adding support for managing multiple devices. The refactor introduces a cleaner API that allows both named device lookups and direct parameter-based wake requests.
Key Changes
- Replaced environment variable configuration with YAML-based config supporting multiple named devices
- Added dual API modes: device lookup by name or direct parameters (MAC, IP, port, broadcast)
- Extracted
buildMagicPacketfunction for better testability and code organization
Reviewed changes
Copilot reviewed 12 out of 13 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| go.mod | Updated dependencies from godotenv to yaml.v3 for YAML parsing |
| config.go | Complete rewrite implementing YAML-based configuration with device lookup and default handling |
| config_test.go | New comprehensive test suite for configuration loading from env and file sources |
| main.go | Refactored handler to support both device-based and direct parameter-based wake requests |
| wol.go | Extracted buildMagicPacket function for improved testability |
| wol_test.go | New test suite for magic packet construction and validation |
| handlers_test.go | New HTTP handler tests covering various parameter combinations and error cases |
| config.example.yaml | New example configuration file demonstrating multi-device setup |
| README.md | Updated documentation with new API examples and configuration instructions |
| docs/DEVELOPMENT.md | New development guide with build, test, and deployment instructions |
| dockerfile | Removed hardcoded environment variables now handled via config |
| .gitignore | Added wol-server binary to ignored files |
| .cspell.json | Removed obsolete godotenv-related words from spell check dictionary |
Comments suppressed due to low confidence (2)
main.go:83
- The handler does not validate the HTTP method. While the documentation shows GET requests, the handler will accept POST, PUT, DELETE, etc. without any validation. Consider adding an HTTP method check at the beginning of the handler to only allow GET requests and return 405 Method Not Allowed for other methods, following REST best practices.
func handler(w http.ResponseWriter, r *http.Request) {
query := r.URL.Query()
var config WOLConfig
var err error
// Check if device parameter is provided (lookup in config)
if deviceName := query.Get("device"); deviceName != "" {
config, err = getDeviceConfig(deviceName)
if err != nil {
log.Printf("Error getting device config: %v", err)
http.Error(w, fmt.Sprintf("Device not found: %s", deviceName), http.StatusNotFound)
return
}
} else if mac := query.Get("mac"); mac != "" {
// Direct parameters provided
ip := query.Get("ip")
if ip == "" {
http.Error(w, "Missing required parameter: ip", http.StatusBadRequest)
return
}
port := 9 // default
if portStr := query.Get("port"); portStr != "" {
if p, err := strconv.Atoi(portStr); err == nil {
port = p
}
}
broadcast := true // default
if broadcastStr := query.Get("broadcast"); broadcastStr != "" {
broadcast = broadcastStr == "true"
}
// Validate MAC address format
if _, err := net.ParseMAC(mac); err != nil {
http.Error(w, fmt.Sprintf("Invalid MAC address: %s", mac), http.StatusBadRequest)
return
}
config = WOLConfig{
MACAddress: mac,
IPAddress: ip,
Port: port,
Broadcast: broadcast,
}
} else {
http.Error(w, "Missing required parameter: either 'device' or 'mac' and 'ip' must be provided", http.StatusBadRequest)
return
}
err = sendMagicPacket(config)
if err != nil {
log.Printf("Error sending magic packet: %v", err)
http.Error(w, "Failed to send magic packet", http.StatusInternalServerError)
return
}
fmt.Fprintf(w, "Magic packet sent to %s", config.MACAddress)
}
wol.go:60
- The Broadcast field from the WOLConfig is not being used when sending the magic packet. The field is accepted in the configuration and API parameters, but the actual UDP socket doesn't have broadcast mode enabled based on this field. This means the broadcast parameter has no effect. Consider using syscall.SetsockoptInt to enable SO_BROADCAST on the connection when config.Broadcast is true, or remove the unused field from the configuration.
func sendMagicPacket(config WOLConfig) error {
packet, err := buildMagicPacket(config.MACAddress)
if err != nil {
return err
}
// Set destination
addr := net.UDPAddr{
IP: net.ParseIP(config.IPAddress),
Port: config.Port,
}
log.Printf("Sending magic packet to %s via %s:%d",
config.MACAddress, config.IPAddress, config.Port)
conn, err := net.DialUDP("udp", nil, &addr)
if err != nil {
return fmt.Errorf("could not dial UDP: %w", err)
}
defer conn.Close()
// Enable broadcast (important!)
if err := conn.SetWriteBuffer(len(packet)); err != nil {
return fmt.Errorf("set write buffer failed: %w", err)
}
if _, err := conn.Write(packet); err != nil {
return fmt.Errorf("write to UDP failed: %w", err)
}
return nil
}
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 12 out of 13 changed files in this pull request and generated 3 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Welcome to Codecov 🎉Once you merge this PR into your default branch, you're all set! Codecov will compare coverage reports and display results in all future pull requests. Thanks for integrating Codecov - We've got you covered ☂️ |
Multi-device support with YAML configuration
Closes #1
Breaking Changes:
/wakeendpoint now requires eitherdeviceormac+ipparameters (no default device)Features:
WOL_CONFIGenv var (Docker) or~/.config/wol-server/config.yaml(bare metal)?device=name) or direct parameters (?mac=...&ip=...)broadcastparameter (determined by IP address)Implementation:
buildMagicPacket()as testable pure functionDependencies:
gopkg.in/yaml.v3github.com/joho/godotenvDocumentation:
README.md+ separateDEVELOPMENT.md