A bit of cleanup and documentation
continuous-integration/drone/push Build is passing Details

This commit is contained in:
Tyler 2022-01-09 23:53:23 -05:00
parent c98b04f9c1
commit e6d3782450
4 changed files with 257 additions and 251 deletions

View File

@ -22,11 +22,12 @@ func redirectRequest(w http.ResponseWriter, r *http.Request) {
ip := net.ParseIP(ipStr) ip := net.ParseIP(ipStr)
// TODO: This is temporary to allow testing on private addresses.
if ip.IsPrivate() { if ip.IsPrivate() {
ip = net.ParseIP("1.1.1.1") ip = net.ParseIP("1.1.1.1")
} }
server, distance, err := settings.Servers.Closest(ip) server, distance, err := servers.Closest(ip)
if err != nil { if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusInternalServerError)

17
main.go
View File

@ -12,9 +12,10 @@ import (
var ( var (
db *maxminddb.Reader db *maxminddb.Reader
settings = &Settings{} servers ServerList
) )
// City represents a MaxmindDB city
type City struct { type City struct {
Location struct { Location struct {
Latitude float64 `maxminddb:"latitude"` Latitude float64 `maxminddb:"latitude"`
@ -22,10 +23,6 @@ type City struct {
} `maxminddb:"location"` } `maxminddb:"location"`
} }
type Settings struct {
Servers ServerList
}
func main() { func main() {
viper.SetConfigName("dlrouter") // name of config file (without extension) viper.SetConfigName("dlrouter") // name of config file (without extension)
viper.SetConfigType("yaml") // REQUIRED if the config file does not have the extension in the name viper.SetConfigType("yaml") // REQUIRED if the config file does not have the extension in the name
@ -44,9 +41,9 @@ func main() {
log.WithError(err).Fatalln("Unable to open database") log.WithError(err).Fatalln("Unable to open database")
} }
servers := viper.GetStringSlice("servers") serverList := viper.GetStringSlice("servers")
for _, server := range servers { for _, server := range serverList {
var prefix string var prefix string
if !strings.HasPrefix(server, "http") { if !strings.HasPrefix(server, "http") {
@ -84,7 +81,7 @@ func main() {
continue continue
} }
settings.Servers = append(settings.Servers, &Server{ servers = append(servers, &Server{
Host: u.Host, Host: u.Host,
Path: u.Path, Path: u.Path,
Latitude: city.Location.Latitude, Latitude: city.Location.Latitude,
@ -101,10 +98,10 @@ func main() {
log.Info("Servers added, checking statuses") log.Info("Servers added, checking statuses")
// Force initial check before running // Force initial check before running
settings.Servers.Check() servers.Check()
// Start check loop // Start check loop
go settings.Servers.checkLoop() go servers.checkLoop()
log.Info("Starting") log.Info("Starting")

View File

@ -13,6 +13,8 @@ var (
forwardLimit = 5 forwardLimit = 5
) )
// RealIPMiddleware is an implementation of reverse proxy checks.
// It uses the remote address to find the originating IP, as well as protocol
func RealIPMiddleware(f http.HandlerFunc) http.HandlerFunc { func RealIPMiddleware(f http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
// Treat unix socket as 127.0.0.1 // Treat unix socket as 127.0.0.1
@ -83,4 +85,3 @@ func realProto(r *http.Request) string {
return proto return proto
} }

View File

@ -31,12 +31,15 @@ func (s ServerList) checkLoop() {
t := time.NewTicker(60 * time.Second) t := time.NewTicker(60 * time.Second)
for { for {
<- t.C <-t.C
s.Check() s.Check()
} }
} }
// Check will request the index from all servers
// If a server does not respond in 10 seconds, it is considered offline.
// This will wait until all checks are complete.
func (s ServerList) Check() { func (s ServerList) Check() {
var wg sync.WaitGroup var wg sync.WaitGroup
@ -44,11 +47,13 @@ func (s ServerList) Check() {
wg.Add(1) wg.Add(1)
go func(server *Server) { go func(server *Server) {
req, err := http.NewRequest(http.MethodGet, "https://" + server.Host + "/" + strings.TrimLeft(server.Path, "/"), nil) req, err := http.NewRequest(http.MethodGet, "https://"+server.Host+"/"+strings.TrimLeft(server.Path, "/"), nil)
req.Header.Set("User-Agent", "ArmbianRouter/1.0 (Go " + runtime.Version() + ")") req.Header.Set("User-Agent", "ArmbianRouter/1.0 (Go "+runtime.Version()+")")
if err != nil { if err != nil {
// This should never happen.
log.WithError(err).Warning("Invalid request! This should not happen, please check config.")
return return
} }
@ -72,6 +77,8 @@ func (s ServerList) Check() {
wg.Wait() wg.Wait()
} }
// Closest will use GeoIP on the IP provided and find the closest server.
// Return values are the closest server, the distance, and if an error occurred.
func (s ServerList) Closest(ip net.IP) (*Server, float64, error) { func (s ServerList) Closest(ip net.IP) (*Server, float64, error) {
var city City var city City
err := db.Lookup(ip, &city) err := db.Lookup(ip, &city)