mirror of
https://github.com/skidoodle/iphistory.git
synced 2025-02-15 08:29:16 +01:00
160 lines
3.2 KiB
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()
|
|
}
|