Passed
Push — master ( 4d0af3...1ea234 )
by Stanislav
01:15
created

main.Notify   A

Complexity

Conditions 1

Size

Total Lines 3
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 3
dl 0
loc 3
rs 10
c 0
b 0
f 0
nop 1
1
package main
2
3
import (
4
	"fmt"
5
	"io"
6
	"log"
7
	"os"
8
	"time"
9
10
	"flag"
11
	"github.com/getlantern/systray"
12
	"github.com/popstas/go-toggl"
13
	"github.com/viasite/planfix-toggl-server/app/client"
14
	"github.com/viasite/planfix-toggl-server/app/config"
15
	"github.com/viasite/planfix-toggl-server/app/icon"
16
	"github.com/viasite/planfix-toggl-server/app/rest"
17
	"github.com/viasite/planfix-toggl-server/app/util"
18
	"runtime"
19
)
20
21
var version string
22
var trayMenu map[string] *systray.MenuItem
23
24
func getLogger(cfg config.Config) *log.Logger {
25
	// logging
26
	logger := log.New(os.Stderr, "[planfix-toggl] ", log.LstdFlags)
27
	if cfg.Debug {
28
		logger.SetFlags(log.Ldate | log.Ltime | log.Lmicroseconds | log.Lshortfile)
29
	} else {
30
		toggl.DisableLog()
31
	}
32
	if cfg.LogFile != "" {
33
		f, err := os.OpenFile(cfg.LogFile, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0644)
34
		if err != nil {
35
			logger.Fatalf("[ERROR] Failed to open log file: %s", cfg.LogFile)
36
		}
37
		//defer f.Close()
38
		// file should be first, when -ldflags -H=windowsgui build, Stdout absent and block log output
39
		mw := io.MultiWriter(f, os.Stdout)
40
		logger.SetOutput(mw)
41
	}
42
	return logger
43
}
44
45
func parseFlags(cfg *config.Config) {
46
	dryRun := flag.Bool("dry-run", false, "Don't actually change data")
47
	if runtime.GOOS == "windows" {
48
		// Allow user to hide the console window
49
		flag.BoolVar(&cfg.NoConsole, "no-console", false, "Hide console window")
50
	}
51
	flag.Parse()
52
53
	if *dryRun {
54
		cfg.DryRun = true
55
	}
56
}
57
58
func connectServices(cfg *config.Config, logger *log.Logger, togglClient *client.TogglClient) (err error) {
59
	// toggl
60
	logger.Println("[INFO] подключение к Toggl...")
61
	account, err := togglClient.GetTogglUser()
62
	cfg.TogglUserID = account.Data.ID
63
	if err != nil {
64
		return err
65
	}
66
67
	ok, err := togglClient.IsWorkspaceExists(cfg.TogglWorkspaceID)
68
	if err != nil {
69
		return err
70
	}
71
	if !ok {
72
		return fmt.Errorf("Toggl workspace ID %d не найден", cfg.TogglWorkspaceID)
73
	}
74
75
	// planfix
76
	if cfg.PlanfixUserName != "" && cfg.PlanfixUserPassword != "" {
77
		logger.Println("[INFO] подключение к Планфиксу...")
78
		user, err := togglClient.GetPlanfixUser()
79
		cfg.PlanfixUserID = user.ID
80
		if err != nil {
81
			return err
82
		}
83
84
		logger.Println("[INFO] получение данных аналитики Планфикса...")
85
		_, err = togglClient.GetAnaliticDataCached(
86
			cfg.PlanfixAnaliticName,
87
			cfg.PlanfixAnaliticTypeName,
88
			cfg.PlanfixAnaliticTypeValue,
89
			cfg.PlanfixAnaliticCountName,
90
			cfg.PlanfixAnaliticCommentName,
91
			cfg.PlanfixAnaliticDateName,
92
			cfg.PlanfixAnaliticUsersName,
93
		)
94
		if err != nil {
95
			return fmt.Errorf("Поля аналитики указаны неправильно: %s", err.Error())
96
		}
97
	}
98
	return nil
99
}
100
101
func initApp() {
102
	fmt.Printf("planfix-toggl %s\n", version)
103
	cfg := config.GetConfig()
104
105
	parseFlags(&cfg)
106
107
	logger := getLogger(cfg)
108
109
	errors, isValid := cfg.Validate()
110
	if !isValid {
111
		for _, e := range errors {
112
			log.Println(e)
113
		}
114
	}
115
116
	if cfg.NoConsole {
117
		util.HideConsole()
118
	}
119
120
	togglClient := client.TogglClient{
121
		Config:  &cfg,
122
		Logger:  logger,
123
		SentLog: make(map[string]int),
124
		Opts:    map[string]string{"LastSent": ""},
125
	}
126
	togglClient.ReloadConfig()
127
128
	// get planfix and toggl user IDs, for early API check
129
	err := connectServices(&cfg, logger, &togglClient)
130
	if err != nil {
131
		isValid = false
132
		logger.Printf("[ERROR] %s", err.Error())
133
		util.Notify(err.Error())
134
	}
135
136
	trayMenu["web"].Enable()
137
	trayMenu["log"].Enable()
138
139
	if isValid {
140
		trayMenu["send"].Enable()
141
		togglClient.Run()
142
	} else {
143
		util.OpenBrowser(fmt.Sprintf("https://localhost:%d", cfg.PortSSL))
144
	}
145
146
	// update last sent on menuitem
147
	go func() {
148
		for {
149
			if togglClient.Opts["LastSent"] != "" {
150
				t := togglClient.Opts["LastSent"]
151
				trayMenu["send"].SetTitle(fmt.Sprintf("Sync (last at %s)", t))
152
			}
153
			time.Sleep(time.Duration(60 * time.Second))
154
		}
155
	}()
156
157
	go func() {
158
		// tray menu actions
159
		for {
160
			select {
161
			case <-trayMenu["send"].ClickedCh:
162
				err := togglClient.SendToPlanfix()
163
				t := togglClient.Opts["LastSent"]
164
				trayMenu["send"].SetTitle(fmt.Sprintf("Sync (last at %s)", t))
165
				if err != nil {
166
					logger.Println(err)
167
				}
168
169
			case <-trayMenu["web"].ClickedCh:
170
				cfg := config.GetConfig()
171
				util.OpenBrowser(fmt.Sprintf("https://localhost:%d", cfg.PortSSL))
172
173
			case <-trayMenu["log"].ClickedCh:
174
				cfg := config.GetConfig()
175
				systray.ShowAppWindow(fmt.Sprintf("https://localhost:%d/log", cfg.PortSSL))
176
177
			case <-trayMenu["quit"].ClickedCh:
178
				onExit()
179
			}
180
		}
181
	}()
182
183
	// start API server
184
	server := rest.Server{
185
		Version:     version,
186
		TogglClient: &togglClient,
187
		Config:      &cfg,
188
		Logger:      logger,
189
	}
190
	server.Run(cfg.PortSSL)
191
}
192
193
func onReady() {
194
	go initApp()
195
196
	// systray.EnableAppWindow("Lantern", 1024, 768) // in next systray versions
197
	systray.SetIcon(icon.Data)
198
	systray.SetTitle("planfix-toggl")
199
	systray.SetTooltip(fmt.Sprintf("planfix-toggl %s", version))
200
201
	trayMenu = make(map[string]*systray.MenuItem)
202
	trayMenu["send"] = systray.AddMenuItem("Sync", "")
203
	trayMenu["web"] = systray.AddMenuItem("Open web interface", "")
204
	trayMenu["log"] = systray.AddMenuItem("Open log", "")
205
	trayMenu["quit"] = systray.AddMenuItem("Quit", "Quit the whole app")
206
207
	trayMenu["send"].Disable()
208
	trayMenu["web"].Disable()
209
	trayMenu["log"].Disable()
210
}
211
212
func onExit() {
213
	systray.Quit()
214
	//os.Exit(0)
215
}
216
217
func main() {
218
	//systray.Run(onReady, onExit)
219
	systray.RunWithAppWindow("planfix-toggl", 1024, 768, onReady, onExit)
220
}
221