iphistory/main.go

160 lines
3.2 KiB
Go

package main
import (
"bufio"
"encoding/json"
"fmt"
"io"
"net/http"
"os"
"strings"
"time"
)
const (
traceURL = "https://one.one.one.one/cdn-cgi/trace"
ipHistoryPath = "ip_history.txt"
checkInterval = 30 * time.Second
maxRetries = 3
retryDelay = 10 * time.Second
)
func getPublicIP() (string, error) {
var ip string
var err error
for attempt := 1; attempt <= maxRetries; attempt++ {
ip, err = fetchIP()
if err == nil {
return ip, nil
}
fmt.Printf("Attempt %d: Error fetching IP: %v\n", attempt, err)
time.Sleep(retryDelay)
}
return "", err
}
func fetchIP() (string, error) {
resp, err := http.Get(traceURL)
if err != nil {
return "", err
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return "", err
}
for _, line := range strings.Split(string(body), "\n") {
if strings.HasPrefix(line, "ip=") {
return strings.TrimPrefix(line, "ip="), nil
}
}
return "", fmt.Errorf("IP address not found")
}
func readHistory() ([]string, error) {
file, err := os.Open(ipHistoryPath)
if os.IsNotExist(err) {
return []string{}, nil
} else if err != nil {
return nil, err
}
defer file.Close()
var history []string
scanner := bufio.NewScanner(file)
for scanner.Scan() {
history = append(history, scanner.Text())
}
return history, scanner.Err()
}
func writeHistory(history []string) error {
file, err := os.Create(ipHistoryPath)
if err != nil {
return err
}
defer file.Close()
writer := bufio.NewWriter(file)
for _, entry := range history {
_, err := writer.WriteString(entry + "\n")
if err != nil {
return err
}
}
return writer.Flush()
}
func trackIP(ipChan <-chan string) {
var lastLoggedIP string
for ip := range ipChan {
history, err := readHistory()
if err != nil {
fmt.Println("Error reading IP history:", err)
continue
}
entry := fmt.Sprintf("%s - %s", time.Now().Format("2006-01-02 15:04:05 MST"), ip)
if len(history) == 0 || !strings.Contains(history[0], ip) {
history = append([]string{entry}, history...)
if err := writeHistory(history); err != nil {
fmt.Println("Error writing IP history:", err)
}
fmt.Printf("📄 New IP logged: %s\n", entry)
lastLoggedIP = ip
} else {
if lastLoggedIP != ip {
fmt.Println("🤷 IP is already up to date")
lastLoggedIP = ip
}
}
}
}
func serveWeb() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w, r, "index.html")
})
http.HandleFunc("/history", func(w http.ResponseWriter, r *http.Request) {
history, err := readHistory()
if err != nil {
http.Error(w, "Error reading IP history", http.StatusInternalServerError)
return
}
jsonData, err := json.Marshal(history)
if err != nil {
http.Error(w, "Error converting history to JSON", http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
w.Write(jsonData)
})
fmt.Println("Starting server on :8080")
http.ListenAndServe(":8080", nil)
}
func main() {
ipChan := make(chan string)
go func() {
for {
ip, err := getPublicIP()
if err != nil {
fmt.Println("Error fetching public IP:", err)
} else {
ipChan <- ip
}
time.Sleep(checkInterval)
}
}()
go trackIP(ipChan)
serveWeb()
}