Skip to content

Commit f8095bc

Browse files
committed
Added matomo configuration to global template
1 parent a88f655 commit f8095bc

19 files changed

+2676
-14
lines changed

config/features_test.go

Lines changed: 31 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -161,10 +161,24 @@ featureoptions:
161161
require.Nil(t, mat.Config["k1"])
162162
}
163163

164+
func TestMatomoConfigured(t *testing.T) {
165+
opts := getAnalyticsOptions(t)
166+
matomo := opts.GetProvider(MATOMO)
167+
require.NotNil(t, matomo)
168+
require.NotZero(t, matomo.SampleRate)
169+
require.Equal(t, 1, matomo.Config["idsite"])
170+
}
171+
172+
func getAnalyticsOptions(t *testing.T) (opts AnalyticsOptions) {
173+
var g Global
174+
require.NoError(t, yaml.Unmarshal(getGlobalTemplate(t), &g))
175+
require.NoError(t, g.UnmarshalFeatureOptions(FeatureAnalytics, &opts))
176+
return
177+
}
178+
164179
func TestReplicaByCountry(t *testing.T) {
165-
require := require.New(t)
166180
assert := assert.New(t)
167-
fos := getReplicaOptionsRoot(require)
181+
fos := getReplicaOptionsRoot(t)
168182
assert.Contains(fos.ByCountry, "RU")
169183
assert.NotContains(fos.ByCountry, "AU")
170184
assert.NotEmpty(fos.ByCountry)
@@ -177,20 +191,9 @@ func TestReplicaByCountry(t *testing.T) {
177191
assert.Equal(fos.ByCountry["IR"].Trackers, globalTrackers)
178192
}
179193

180-
func getReplicaOptionsRoot(require *require.Assertions) (fos ReplicaOptionsRoot) {
181-
var w bytes.Buffer
182-
// We could write into a pipe, but that requires concurrency and we're old-school in tests.
183-
require.NoError(template.Must(template.New("").Parse(embeddedconfig.GlobalTemplate)).Execute(&w, nil))
184-
var g Global
185-
require.NoError(yaml.Unmarshal(w.Bytes(), &g))
186-
require.NoError(g.UnmarshalFeatureOptions(FeatureReplica, &fos))
187-
return
188-
}
189-
190194
func TestReplicaProxying(t *testing.T) {
191-
require := require.New(t)
192195
assert := assert.New(t)
193-
fos := getReplicaOptionsRoot(require)
196+
fos := getReplicaOptionsRoot(t)
194197
numInfohashes := len(fos.ProxyAnnounceTargets)
195198
// The default is to announce as a proxy.
196199
assert.True(numInfohashes > 0)
@@ -199,3 +202,17 @@ func TestReplicaProxying(t *testing.T) {
199202
// Iran looks for peers from the default countries.
200203
assert.Len(fos.ByCountry["IR"].ProxyPeerInfoHashes, numInfohashes)
201204
}
205+
206+
func getReplicaOptionsRoot(t *testing.T) (fos ReplicaOptionsRoot) {
207+
var g Global
208+
require.NoError(t, yaml.Unmarshal(getGlobalTemplate(t), &g))
209+
require.NoError(t, g.UnmarshalFeatureOptions(FeatureReplica, &fos))
210+
return
211+
}
212+
213+
func getGlobalTemplate(t *testing.T) []byte {
214+
var w bytes.Buffer
215+
// We could write into a pipe, but that requires concurrency and we're old-school in tests.
216+
require.NoError(t, template.Must(template.New("").Parse(embeddedconfig.GlobalTemplate)).Execute(&w, nil))
217+
return w.Bytes()
218+
}

config_v2/ads.go

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
package config
2+
3+
import (
4+
"math/rand"
5+
"strings"
6+
)
7+
8+
const (
9+
none = "none"
10+
free = "free"
11+
pro = "pro"
12+
)
13+
14+
// AdSettings are settings to use when showing ads to Android clients
15+
type AdSettings struct {
16+
NativeBannerZoneID string `yaml:"nativebannerzoneid,omitempty"`
17+
StandardBannerZoneID string `yaml:"standardbannerzoneid,omitempty"`
18+
InterstitialZoneID string `yaml:"interstitialzoneid,omitempty"`
19+
DaysToSuppress int `yaml:"daystosuppress,omitempty"`
20+
Percentage float64
21+
Countries map[string]string
22+
}
23+
24+
type AdProvider struct {
25+
AdSettings
26+
}
27+
28+
func (s *AdSettings) GetAdProvider(isPro bool, countryCode string, daysSinceInstalled int) *AdProvider {
29+
if !s.adsEnabled(isPro, countryCode, daysSinceInstalled) {
30+
return nil
31+
}
32+
33+
return &AdProvider{*s}
34+
}
35+
36+
func (s *AdSettings) adsEnabled(isPro bool, countryCode string, daysSinceInstalled int) bool {
37+
if s == nil {
38+
return false
39+
}
40+
41+
if daysSinceInstalled < s.DaysToSuppress {
42+
return false
43+
}
44+
45+
level := s.Countries[strings.ToLower(countryCode)]
46+
switch level {
47+
case free:
48+
return !isPro
49+
case pro:
50+
return true
51+
default:
52+
return false
53+
}
54+
}
55+
56+
func (p *AdProvider) GetNativeBannerZoneID() string {
57+
if p == nil {
58+
return ""
59+
}
60+
return p.NativeBannerZoneID
61+
}
62+
63+
func (p *AdProvider) GetStandardBannerZoneID() string {
64+
if p == nil {
65+
return ""
66+
}
67+
return p.StandardBannerZoneID
68+
}
69+
70+
func (p *AdProvider) GetInterstitialZoneID() string {
71+
if p == nil {
72+
return ""
73+
}
74+
return p.InterstitialZoneID
75+
}
76+
77+
func (p *AdProvider) ShouldShowAd() bool {
78+
return rand.Float64() <= p.Percentage/100
79+
}

config_v2/ads_test.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package config
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/assert"
7+
)
8+
9+
func TestAdSettings(t *testing.T) {
10+
s := &AdSettings{
11+
NativeBannerZoneID: "a",
12+
StandardBannerZoneID: "b",
13+
InterstitialZoneID: "c",
14+
DaysToSuppress: 1,
15+
Percentage: 100,
16+
Countries: map[string]string{
17+
"ir": "pro",
18+
"ae": "free",
19+
"us": "none",
20+
"uk": "wrong",
21+
},
22+
}
23+
24+
assert.True(t, s.adsEnabled(true, "IR", 1))
25+
assert.True(t, s.adsEnabled(false, "IR", 1))
26+
assert.False(t, s.adsEnabled(true, "AE", 1))
27+
assert.True(t, s.adsEnabled(false, "AE", 1))
28+
assert.False(t, s.adsEnabled(false, "AE", 0))
29+
assert.False(t, s.adsEnabled(false, "US", 1))
30+
assert.False(t, s.adsEnabled(false, "UK", 1))
31+
assert.False(t, s.adsEnabled(false, "Ru", 1))
32+
33+
p := s.GetAdProvider(false, "IR", 1)
34+
if assert.NotNil(t, p) {
35+
if assert.True(t, p.ShouldShowAd()) {
36+
assert.Equal(t, s.NativeBannerZoneID, p.GetNativeBannerZoneID())
37+
assert.Equal(t, s.StandardBannerZoneID, p.GetStandardBannerZoneID())
38+
assert.Equal(t, s.InterstitialZoneID, p.GetInterstitialZoneID())
39+
}
40+
}
41+
}

config_v2/bootstrap.go

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
package config
2+
3+
import (
4+
"errors"
5+
"io/ioutil"
6+
"os"
7+
"path/filepath"
8+
"strings"
9+
10+
"github.com/getlantern/yaml"
11+
12+
"github.com/getlantern/flashlight/common"
13+
)
14+
15+
var (
16+
name = ".packaged-lantern.yaml"
17+
lanternYamlName = "lantern.yaml"
18+
)
19+
20+
// BootstrapSettings provides access to configuration embedded directly in Lantern installation
21+
// packages. On OSX, that means data embedded in the Lantern.app app bundle in
22+
// Lantern.app/Contents/Resources/.lantern.yaml, while on Windows that means data embedded
23+
// in AppData/Roaming/Lantern/.lantern.yaml. This allows customization embedded in the
24+
// installer outside of the auto-updated binary that should only be used under special
25+
// circumstances.
26+
type BootstrapSettings struct {
27+
StartupUrl string
28+
}
29+
30+
// ReadBootstrapSettings reads packaged settings from pre-determined paths
31+
// on the various OSes.
32+
func ReadBootstrapSettings(configDir string) (*BootstrapSettings, error) {
33+
_, yamlPath, err := bootstrapPath(name)
34+
if err != nil {
35+
return &BootstrapSettings{}, err
36+
}
37+
38+
ps, er := readSettingsFromFile(yamlPath)
39+
if er != nil {
40+
// This is the local copy of our embedded ration file. This is necessary
41+
// to ensure we remember the embedded ration across auto-updated
42+
// binaries. We write to the local file system instead of to the package
43+
// itself (app bundle on OSX, install directory on Windows) because
44+
// we're not always sure we can write to that directory.
45+
return readSettingsFromFile(filepath.Join(configDir, name))
46+
}
47+
return ps, nil
48+
}
49+
50+
// ReadSettingsFromFile reads BootstrapSettings from the yaml file at the specified
51+
// path.
52+
func readSettingsFromFile(yamlPath string) (*BootstrapSettings, error) {
53+
log.Debugf("Opening file at: %v", yamlPath)
54+
data, err := ioutil.ReadFile(yamlPath)
55+
if err != nil {
56+
// This will happen whenever there's no packaged settings, which is often
57+
log.Debugf("Error reading file %v", err)
58+
return &BootstrapSettings{}, err
59+
}
60+
61+
trimmed := strings.TrimSpace(string(data))
62+
63+
log.Debugf("Read bytes: %v", trimmed)
64+
65+
if trimmed == "" {
66+
log.Debugf("Ignoring empty string")
67+
return &BootstrapSettings{}, errors.New("Empty string")
68+
}
69+
var s BootstrapSettings
70+
err = yaml.Unmarshal([]byte(trimmed), &s)
71+
72+
if err != nil {
73+
log.Errorf("Could not read yaml: %v", err)
74+
return &BootstrapSettings{}, err
75+
}
76+
return &s, nil
77+
}
78+
79+
func bootstrapPath(fileName string) (string, string, error) {
80+
dir, err := filepath.Abs(filepath.Dir(os.Args[0]))
81+
if err != nil {
82+
log.Errorf("Could not get current directory %v", err)
83+
return "", "", err
84+
}
85+
var yamldir string
86+
if common.Platform == "windows" {
87+
yamldir = dir
88+
} else if common.Platform == "darwin" {
89+
// Code signing doesn't like this file in the current directory
90+
// for whatever reason, so we grab it from the Resources/en.lproj
91+
// directory in the app bundle. See:
92+
// https://developer.apple.com/library/mac/technotes/tn2206/_index.html#//apple_ref/doc/uid/DTS40007919-CH1-TNTAG402
93+
yamldir = dir + "/../Resources/en.lproj"
94+
if _, err := ioutil.ReadDir(yamldir); err != nil {
95+
// This likely means the user originally installed with an older version that didn't include en.lproj
96+
// in the app bundle, so just look in the old location in Resources.
97+
yamldir = dir + "/../Resources"
98+
}
99+
} else if common.Platform == "linux" {
100+
yamldir = dir + "/../"
101+
}
102+
fullPath := filepath.Join(yamldir, fileName)
103+
log.Debugf("Opening bootstrap file from: %v", fullPath)
104+
return yamldir, fullPath, nil
105+
}

config_v2/bootstrap_test.go

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package config
2+
3+
import (
4+
"io/ioutil"
5+
"os"
6+
"path/filepath"
7+
"testing"
8+
9+
"github.com/getlantern/yaml"
10+
"github.com/stretchr/testify/assert"
11+
12+
"github.com/getlantern/flashlight/common"
13+
)
14+
15+
func TestBootstrapSettings(t *testing.T) {
16+
file, err := ioutil.TempFile("", ".packaged-lantern.yaml")
17+
defer func() {
18+
err := os.Remove(file.Name())
19+
if err != nil {
20+
log.Errorf("Could not remove file? %v", err)
21+
}
22+
}()
23+
assert.True(t, err == nil, "Should not be an error")
24+
file.Close()
25+
26+
log.Debugf("File at: %v", file.Name())
27+
settings := BootstrapSettings{StartupUrl: "test"}
28+
log.Debugf("Settings: %v", settings)
29+
30+
data, er := yaml.Marshal(&settings)
31+
assert.True(t, er == nil, "Should not be an error")
32+
33+
e := ioutil.WriteFile(file.Name(), data, 0644)
34+
assert.True(t, e == nil, "Should not be an error")
35+
36+
ps, errr := readSettingsFromFile(file.Name())
37+
assert.Equal(t, "test", ps.StartupUrl, "Unexpected startup URL")
38+
assert.NoError(t, errr, "Unable to read settings")
39+
40+
_, path, err := bootstrapPath(name)
41+
assert.True(t, err == nil, "Should not be an error")
42+
43+
var dir string
44+
45+
if common.Platform == "darwin" {
46+
dir, err = filepath.Abs(filepath.Dir(os.Args[0]) + "/../Resources")
47+
} else if common.Platform == "linux" {
48+
dir, err = filepath.Abs(filepath.Dir(os.Args[0]) + "/../")
49+
}
50+
assert.True(t, err == nil, "Should not be an error")
51+
52+
log.Debugf("Running in %v", dir)
53+
if common.Platform == "darwin" {
54+
assert.Equal(t, dir+"/"+name, path, "Unexpected settings dir")
55+
} else if common.Platform == "linux" {
56+
assert.Equal(t, dir+"/"+name, path, "Unexpected settings dir")
57+
}
58+
}

0 commit comments

Comments
 (0)