This commit is contained in:
Quentin McGaw
2020-08-30 14:48:57 +00:00
parent aac5274eab
commit 7c102c0028
11 changed files with 262 additions and 18 deletions

View File

@@ -108,6 +108,8 @@ type Reader interface {
// Public IP getters
GetPublicIPPeriod() (period time.Duration, err error)
GetVersionInformation() (enabled bool, err error)
}
type reader struct {
@@ -138,3 +140,7 @@ func (r *reader) GetVPNSP() (vpnServiceProvider models.VPNProvider, err error) {
}
return models.VPNProvider(s), err
}
func (r *reader) GetVersionInformation() (enabled bool, err error) {
return r.envParams.GetOnOff("VERSION_INFORMATION", libparams.Default("on"))
}

View File

@@ -31,10 +31,6 @@ type DNS struct {
}
func (d *DNS) String() string {
const (
enabled = "enabled"
disabled = "disabled"
)
if !d.Enabled {
return fmt.Sprintf("DNS over TLS disabled, using plaintext DNS %s", d.PlaintextAddress)
}

View File

@@ -8,19 +8,29 @@ import (
"github.com/qdm12/gluetun/internal/params"
)
const (
enabled = "enabled"
disabled = "disabled"
)
// Settings contains all settings for the program to run
type Settings struct {
VPNSP models.VPNProvider
OpenVPN OpenVPN
System System
DNS DNS
Firewall Firewall
TinyProxy TinyProxy
ShadowSocks ShadowSocks
PublicIPPeriod time.Duration
VPNSP models.VPNProvider
OpenVPN OpenVPN
System System
DNS DNS
Firewall Firewall
TinyProxy TinyProxy
ShadowSocks ShadowSocks
PublicIPPeriod time.Duration
VersionInformation bool
}
func (s *Settings) String() string {
versionInformation := disabled
if s.VersionInformation {
versionInformation = enabled
}
return strings.Join([]string{
"Settings summary below:",
s.OpenVPN.String(),
@@ -30,6 +40,7 @@ func (s *Settings) String() string {
s.TinyProxy.String(),
s.ShadowSocks.String(),
"Public IP check period: " + s.PublicIPPeriod.String(),
"Version information: " + versionInformation,
"", // new line at the end
}, "\n")
}
@@ -69,5 +80,9 @@ func GetAllSettings(paramsReader params.Reader) (settings Settings, err error) {
if err != nil {
return settings, err
}
settings.VersionInformation, err = paramsReader.GetVersionInformation()
if err != nil {
return settings, err
}
return settings, nil
}

View File

@@ -20,9 +20,9 @@ func (s *ShadowSocks) String() string {
if !s.Enabled {
return "ShadowSocks settings: disabled"
}
log := "disabled"
log := disabled
if s.Log {
log = "enabled"
log = enabled
}
settingsList := []string{
"ShadowSocks settings:",

View File

@@ -21,9 +21,9 @@ func (t *TinyProxy) String() string {
if !t.Enabled {
return "TinyProxy settings: disabled"
}
auth := "disabled"
auth := disabled
if t.User != "" {
auth = "enabled"
auth = enabled
}
settingsList := []string{
fmt.Sprintf("Port: %d", t.Port),

View File

@@ -0,0 +1,58 @@
package version
import (
"encoding/json"
"io/ioutil"
"net/http"
"time"
)
type githubRelease struct {
TagName string `json:"tag_name"`
Name string `json:"name"`
Prerelease bool `json:"prerelease"`
PublishedAt time.Time `json:"published_at"`
}
type githubCommit struct {
Sha string `json:"sha"`
Commit struct {
Committer struct {
Date time.Time `json:"date"`
} `json:"committer"`
}
}
func getGithubReleases(client *http.Client) (releases []githubRelease, err error) {
const url = "https://api.github.com/repos/qdm12/gluetun/releases"
response, err := client.Get(url)
if err != nil {
return nil, err
}
defer response.Body.Close()
b, err := ioutil.ReadAll(response.Body)
if err != nil {
return nil, err
}
if err := json.Unmarshal(b, &releases); err != nil {
return nil, err
}
return releases, nil
}
func getGithubCommits(client *http.Client) (commits []githubCommit, err error) {
const url = "https://api.github.com/repos/qdm12/gluetun/commits"
response, err := client.Get(url)
if err != nil {
return nil, err
}
defer response.Body.Close()
b, err := ioutil.ReadAll(response.Body)
if err != nil {
return nil, err
}
if err := json.Unmarshal(b, &commits); err != nil {
return nil, err
}
return commits, nil
}

View File

@@ -0,0 +1,88 @@
package version
import (
"fmt"
"net/http"
"time"
)
// GetMessage returns a message for the user describing if there is a newer version
// available. It should only be called once the tunnel is established.
func GetMessage(version, commitShort string, client *http.Client) (message string, err error) {
if version == "latest" {
// Find # of commits between current commit and latest commit
commitsSince, err := getCommitsSince(client, commitShort)
if err != nil {
return "", fmt.Errorf("cannot get version information: %w", err)
} else if commitsSince == 0 {
return fmt.Sprintf("You are running on the bleeding edge of %s!", version), nil
}
commits := "commits"
if commitsSince == 1 {
commits = "commit"
}
return fmt.Sprintf("You are running %d %s behind the most recent %s", commitsSince, commits, version), nil
}
tagName, name, releaseTime, err := getLatestRelease(client)
if err != nil {
return "", fmt.Errorf("cannot get version information: %w", err)
}
if tagName == version {
return fmt.Sprintf("You are running the latest release %s", version), nil
}
timeSinceRelease := formatDuration(time.Since(releaseTime))
return fmt.Sprintf("There is a new release %s (%s) created %s ago",
tagName, name, timeSinceRelease),
nil
}
func formatDuration(duration time.Duration) string {
switch {
case duration < time.Minute:
seconds := int(duration.Round(time.Second).Seconds())
if seconds < 2 {
return fmt.Sprintf("%d second", seconds)
}
return fmt.Sprintf("%d seconds", seconds)
case duration <= time.Hour:
minutes := int(duration.Round(time.Minute).Minutes())
if minutes == 1 {
return "1 minute"
}
return fmt.Sprintf("%d minutes", minutes)
case duration < 48*time.Hour:
hours := int(duration.Truncate(time.Hour).Hours())
return fmt.Sprintf("%d hours", hours)
default:
days := int(duration.Truncate(time.Hour).Hours() / 24)
return fmt.Sprintf("%d days", days)
}
}
func getLatestRelease(client *http.Client) (tagName, name string, time time.Time, err error) {
releases, err := getGithubReleases(client)
if err != nil {
return "", "", time, err
}
for _, release := range releases {
if release.Prerelease {
continue
}
return release.TagName, release.Name, release.PublishedAt, nil
}
return "", "", time, fmt.Errorf("no releases found")
}
func getCommitsSince(client *http.Client, commitShort string) (n int, err error) {
commits, err := getGithubCommits(client)
if err != nil {
return 0, err
}
for i := range commits {
if commits[i].Sha[:7] == commitShort {
return n, nil
}
n++
}
return 0, fmt.Errorf("no commit matching %q was found", commitShort)
}

View File

@@ -0,0 +1,64 @@
package version
import (
"testing"
"time"
"github.com/stretchr/testify/assert"
)
func Test_formatDuration(t *testing.T) {
t.Parallel()
testCases := map[string]struct {
duration time.Duration
s string
}{
"zero": {
s: "0 second",
},
"one second": {
duration: time.Second,
s: "1 second",
},
"59 seconds": {
duration: 59 * time.Second,
s: "59 seconds",
},
"1 minute": {
duration: time.Minute,
s: "1 minute",
},
"2 minutes": {
duration: 2 * time.Minute,
s: "2 minutes",
},
"1 hour": {
duration: time.Hour,
s: "60 minutes",
},
"2 hours": {
duration: 2 * time.Hour,
s: "2 hours",
},
"26 hours": {
duration: 26 * time.Hour,
s: "26 hours",
},
"28 hours": {
duration: 28 * time.Hour,
s: "28 hours",
},
"55 hours": {
duration: 55 * time.Hour,
s: "2 days",
},
}
for name, testCase := range testCases {
testCase := testCase
t.Run(name, func(t *testing.T) {
t.Parallel()
s := formatDuration(testCase.duration)
assert.Equal(t, testCase.s, s)
})
}
}