From c17b5f6f7b6b28c890764688ff5e966ecebece63 Mon Sep 17 00:00:00 2001 From: "kali kaneko (leap communications)" Date: Tue, 16 Jun 2020 21:28:48 +0200 Subject: [feat] re-implement donation reminders first pass on giving functionality to the donation reminder --- pkg/backend/api.go | 29 +++++++++----- pkg/backend/bitmask.go | 19 +++++++-- pkg/backend/donate.go | 35 +++++++++++++++++ pkg/backend/status.go | 103 ++++++++++++++++++++++++------------------------- pkg/config/gui.go | 14 +++---- 5 files changed, 126 insertions(+), 74 deletions(-) create mode 100644 pkg/backend/donate.go (limited to 'pkg') diff --git a/pkg/backend/api.go b/pkg/backend/api.go index f924cbd..5cb0304 100644 --- a/pkg/backend/api.go +++ b/pkg/backend/api.go @@ -6,6 +6,7 @@ import ( "C" "fmt" "log" + "time" "unsafe" "0xacab.org/leap/bitmask-vpn/pkg/bitmask" @@ -23,18 +24,24 @@ func SwitchOff() { } func Unblock() { + //TODO fmt.Println("unblock... [not implemented]") } func Quit() { if ctx.Status != off { go setStatus(stopping) + ctx.cfg.SetUserStoppedVPN(true) stopVPN() } } -func ToggleDonate() { - toggleDonate() +func DonateAccepted() { + donateAccepted() +} + +func DonateRejected() { + donateRejected() } func SubscribeToEvent(event string, f unsafe.Pointer) { @@ -42,21 +49,23 @@ func SubscribeToEvent(event string, f unsafe.Pointer) { } func InitializeBitmaskContext() { - pi := bitmask.GetConfiguredProvider() + p := bitmask.GetConfiguredProvider() initOnce.Do(func() { - initializeContext(pi.Provider, pi.AppName) + initializeContext( + p.Provider, p.AppName) }) go ctx.updateStatus() - /* DEBUG - timer := time.NewTimer(time.Second * 3) go func() { - <-timer.C - fmt.Println("donate timer fired") - toggleDonate() + if needsDonationReminder() { + // wait a bit before launching reminder + timer := time.NewTimer(time.Minute * 5) + <-timer.C + showDonate() + } + }() - */ } func RefreshContext() *C.char { diff --git a/pkg/backend/bitmask.go b/pkg/backend/bitmask.go index 07d27ea..8fd2367 100644 --- a/pkg/backend/bitmask.go +++ b/pkg/backend/bitmask.go @@ -5,6 +5,7 @@ import ( "os" "0xacab.org/leap/bitmask-vpn/pkg/bitmask" + "0xacab.org/leap/bitmask-vpn/pkg/config" ) func initializeBitmask() { @@ -19,6 +20,7 @@ func initializeBitmask() { log.Println("error: cannot initialize bitmask") } ctx.bm = b + ctx.cfg = config.ParseConfig() } func startVPN() { @@ -36,16 +38,25 @@ func stopVPN() { } } +func wantDonations() bool { + if config.AskForDonations == "true" { + return true + } + return false +} + // initializeContext initializes an empty connStatus and assigns it to the // global ctx holder. This is expected to be called only once, so the public // api uses the sync.Once primitive to call this. func initializeContext(provider, appName string) { var st status = off ctx = &connectionCtx{ - AppName: appName, - Provider: provider, - Donate: false, - Status: st, + AppName: appName, + Provider: provider, + DonateURL: config.DonateURL, + AskForDonations: wantDonations(), + DonateDialog: false, + Status: st, } go trigger(OnStatusChanged) initializeBitmask() diff --git a/pkg/backend/donate.go b/pkg/backend/donate.go new file mode 100644 index 0000000..d216687 --- /dev/null +++ b/pkg/backend/donate.go @@ -0,0 +1,35 @@ +package backend + +import ( + "log" + "time" +) + +func needsDonationReminder() bool { + return ctx.cfg.NeedsDonationReminder() +} + +func donateAccepted() { + stmut.Lock() + defer stmut.Unlock() + ctx.DonateDialog = false + log.Println("marking as donated") + ctx.cfg.SetDonated() + go trigger(OnStatusChanged) +} + +func donateRejected() { + timer := time.NewTimer(time.Hour) + go func() { + <-timer.C + showDonate() + }() +} + +func showDonate() { + stmut.Lock() + defer stmut.Unlock() + ctx.DonateDialog = true + ctx.cfg.SetLastReminded() + go trigger(OnStatusChanged) +} diff --git a/pkg/backend/status.go b/pkg/backend/status.go index e2d31db..7e9f211 100644 --- a/pkg/backend/status.go +++ b/pkg/backend/status.go @@ -6,6 +6,7 @@ import ( "log" "0xacab.org/leap/bitmask-vpn/pkg/bitmask" + "0xacab.org/leap/bitmask-vpn/pkg/config" ) const ( @@ -20,60 +21,20 @@ const ( // if we ever switch again to a provider-agnostic app, we should keep a map here. var ctx *connectionCtx -// the status type reflects the current VPN status. Go code is responsible for updating -// it; the C gui just watches its changes and pulls its updates via the serialized -// context object. - -type status int - -const ( - off status = iota - starting - on - stopping - failed - unknown -) - -func (s status) String() string { - return [...]string{offStr, startingStr, onStr, stoppingStr, failedStr}[s] -} - -func (s status) MarshalJSON() ([]byte, error) { - b := bytes.NewBufferString(`"`) - b.WriteString(s.String()) - b.WriteString(`"`) - return b.Bytes(), nil -} - -func (s status) fromString(st string) status { - switch st { - case offStr: - return off - case startingStr: - return starting - case onStr: - return on - case stoppingStr: - return stopping - case failedStr: - return failed - default: - return unknown - } -} - // The connectionCtx keeps the global state that is passed around to C-land. It // also serves as the primary way of passing requests from the frontend to the // Go-core, by letting the UI write some of these variables and processing // them. type connectionCtx struct { - AppName string `json:"appName"` - Provider string `json:"provider"` - Donate bool `json:"donate"` - Status status `json:"status"` - bm bitmask.Bitmask + AppName string `json:"appName"` + Provider string `json:"provider"` + AskForDonations bool `json:"askForDonations"` + DonateDialog bool `json:"donateDialog"` + DonateURL string `json:"donateURL"` + Status status `json:"status"` + bm bitmask.Bitmask + cfg *config.Config } func (c connectionCtx) toJson() ([]byte, error) { @@ -110,11 +71,47 @@ func setStatus(st status) { go trigger(OnStatusChanged) } -func toggleDonate() { - stmut.Lock() - defer stmut.Unlock() - ctx.Donate = !ctx.Donate - go trigger(OnStatusChanged) +// the status type reflects the current VPN status. Go code is responsible for updating +// it; the C gui just watches its changes and pulls its updates via the serialized +// context object. + +type status int + +const ( + off status = iota + starting + on + stopping + failed + unknown +) + +func (s status) String() string { + return [...]string{offStr, startingStr, onStr, stoppingStr, failedStr}[s] +} + +func (s status) MarshalJSON() ([]byte, error) { + b := bytes.NewBufferString(`"`) + b.WriteString(s.String()) + b.WriteString(`"`) + return b.Bytes(), nil +} + +func (s status) fromString(st string) status { + switch st { + case offStr: + return off + case startingStr: + return starting + case onStr: + return on + case stoppingStr: + return stopping + case failedStr: + return failed + default: + return unknown + } } func setStatusFromStr(stStr string) { diff --git a/pkg/config/gui.go b/pkg/config/gui.go index ce3f14d..5fa4886 100644 --- a/pkg/config/gui.go +++ b/pkg/config/gui.go @@ -37,7 +37,7 @@ var ( // Config holds the configuration of the systray type Config struct { file struct { - LastNotification time.Time + LastReminded time.Time Donated time.Time SelectGateway bool Obfs4 bool @@ -77,16 +77,16 @@ func (c *Config) SetUserStoppedVPN(vpnStopped bool) error { return c.save() } -func (c *Config) HasDonated() bool { - return c.file.Donated.Add(oneMonth).After(time.Now()) +func (c *Config) NeedsDonationReminder() bool { + return !c.hasDonated() && c.file.LastReminded.Add(oneDay).Before(time.Now()) } -func (c *Config) NeedsNotification() bool { - return !c.HasDonated() && c.file.LastNotification.Add(oneDay).Before(time.Now()) +func (c *Config) hasDonated() bool { + return c.file.Donated.Add(oneMonth).After(time.Now()) } -func (c *Config) SetNotification() error { - c.file.LastNotification = time.Now() +func (c *Config) SetLastReminded() error { + c.file.LastReminded = time.Now() return c.save() } -- cgit v1.2.3