package main import ( "encoding/json" "fmt" "io/ioutil" "net/http" "os" "strings" "time" ) type Config struct { UpdateURL string `json:"update_url"` CheckIntervalSecs int `json:"check_interval_seconds"` IPCheckURL string `json:"ip_check_url"` } func loadConfig(path string) (*Config, error) { data, err := ioutil.ReadFile(path) if err != nil { return nil, err } var cfg Config err = json.Unmarshal(data, &cfg) if err != nil { return nil, err } return &cfg, nil } func getPublicIP(ipURL string) (string, error) { resp, err := http.Get(ipURL) if err != nil { return "", err } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { return "", err } return strings.TrimSpace(string(body)), nil } func updateDDNS(url string) error { resp, err := http.Get(url) if err != nil { return err } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { return fmt.Errorf("failed, status code %d", resp.StatusCode) } return nil } func main() { cfg, err := loadConfig("config.json") if err != nil { fmt.Println("Failed to load config:", err) os.Exit(1) } //var lastIP string lastIP, err := getPublicIP(cfg.IPCheckURL) if err != nil { fmt.Println("Error getting intial public IP:", err) lastIP = "" } else { fmt.Println(time.Now(), "Starting with current IP:", lastIP) } ticker := time.NewTicker(time.Duration(cfg.CheckIntervalSecs) * time.Second) defer ticker.Stop() for { ip, err := getPublicIP(cfg.IPCheckURL) if err != nil { fmt.Println("Error getting public IP:", err) } else if ip != lastIP { fmt.Println(time.Now(), "IP changed to", ip) if err := updateDDNS(cfg.UpdateURL); err != nil { fmt.Println("Failed to update DDNS:", err) } else { fmt.Println(time.Now(), "DDNS updated successfully") lastIP = ip } } else { fmt.Println(time.Now(), "IP unchanged:", ip) } <-ticker.C } }