This repository has been archived by the owner on Apr 6, 2021. It is now read-only.
/
geo.go
101 lines (90 loc) · 2.38 KB
/
geo.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
package geo
import (
"fmt"
"net"
"net/http"
"strings"
"time"
log "github.com/sirupsen/logrus"
"github.com/gravitational/teleconsole/conf"
)
type Endpoint struct {
Hostname string `json:"dns_name"`
SessionPrefix string `json:"session_prefix"`
}
var (
// US West is the default:
DefaultEndpoint = Endpoint{Hostname: conf.DefaultServerHost, SessionPrefix: ""}
// List of Teleconsole proxy servers.
Endpoints = []Endpoint{
DefaultEndpoint,
{"eu.teleconsole.com", "eu"},
{"as.teleconsole.com", "as"},
}
)
// FindFastestEndpoint returns the Teleconsole server endpoint which was
// the fastest to respond to HTTP ping/pong
func FindFastestEndpoint() Endpoint {
responded := make(chan Endpoint)
start := time.Now()
// performs HTTP GET against a given endpoint
ping := func(ep Endpoint) {
url := fmt.Sprintf("http://%s/ping", ep.Hostname)
log.Infof("Ping %s", url)
resp, err := http.Get(url)
if err != nil {
log.Error(err)
return
}
defer resp.Body.Close()
if resp.StatusCode == http.StatusOK {
responded <- ep
}
}
for _, ep := range Endpoints {
go ping(ep)
}
timeout := time.NewTimer(time.Second * 5)
defer timeout.Stop()
select {
case e := <-responded:
log.Infof("%s responded in %v", e.Hostname, time.Now().Sub(start))
return e
case <-timeout.C:
log.Error("Timeout: none of the severs have played pong.")
}
return DefaultEndpoint
}
// SessionPrefixFor finds a session prefix for a given endpoint
func SesionPrefixFor(endpoint string) string {
host, _, _ := net.SplitHostPort(endpoint)
if host != "" {
endpoint = host
}
for _, ep := range Endpoints {
if endpoint == ep.Hostname {
return ep.SessionPrefix
}
}
return ""
}
// EndpointForSession deterines which Teleconsole server generated a given session ID
// It looks at the prefix (first few bytes) of it.
//
// Returns the endpoint (or "" for legacy sessions from teleconsole.com) and also
// returns the session ID without the prefix
func EndpointForSession(sid string) (string, string) {
for _, ep := range Endpoints {
if len(ep.SessionPrefix) > 0 {
if strings.HasPrefix(sid, ep.SessionPrefix) {
return ep.Hostname, sid[len(ep.SessionPrefix):]
}
}
}
return DefaultEndpoint.Hostname, sid
}
// IsGeobalancedSession returns 'true' if the given session ID starts with a geo prefix
func IsGeobalancedSession(sid string) bool {
_, rs := EndpointForSession(sid)
return rs != sid
}