Skip to content

feat: multiple machines support#4

Merged
daltonbr merged 15 commits into
mainfrom
feat/multiple-machines
Dec 21, 2025
Merged

feat: multiple machines support#4
daltonbr merged 15 commits into
mainfrom
feat/multiple-machines

Conversation

@daltonbr

@daltonbr daltonbr commented Dec 20, 2025

Copy link
Copy Markdown
Owner

Multi-device support with YAML configuration

Closes #1

Breaking Changes:

  • Replaced environment variable configuration with YAML-based config
  • /wake endpoint now requires either device or mac+ip parameters (no default device)

Features:

  • Support multiple devices via YAML configuration (env var or file)
  • Two configuration methods: WOL_CONFIG env var (Docker) or ~/.config/wol-server/config.yaml (bare metal)
  • Two wake modes: configured device lookup (?device=name) or direct parameters (?mac=...&ip=...)
  • Removed unnecessary broadcast parameter (determined by IP address)

Implementation:

  • Extracted buildMagicPacket() as testable pure function
  • Added several validation around inputs
  • Added comprehensive test suite (tests covering config, handlers, and WOL logic)
  • Multi-arch Docker support (linux/amd64, linux/arm64)

Dependencies:

  • Added: gopkg.in/yaml.v3
  • Removed: github.com/joho/godotenv

Documentation:

  • Refactored documentation: user-focused README.md + separate DEVELOPMENT.md
  • Streamlined README for end users
  • Added macOS Docker networking notes

- 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.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 buildMagicPacket function 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.

Comment thread config.example.yaml Outdated
Comment thread handlers_test.go
Comment thread main.go Outdated
Comment thread config.go
Comment thread config.go
Comment thread main.go
Comment thread README.md Outdated

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread main.go
Comment thread config.go
Comment thread README.md
@codecov-commenter

Copy link
Copy Markdown

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 ☂️

@daltonbr daltonbr merged commit a524509 into main Dec 21, 2025
1 check passed
@daltonbr daltonbr deleted the feat/multiple-machines branch December 21, 2025 01:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add Query Support for Multiple Devices (optional)

3 participants