// StartBlocklistUpgrader react to certain conitions for when the list of // blocked urls should be updated. // // This function runs in it's own goroutine. func StartBlocklistUpgrader() { connectionEventListener := make(chan service.ConnectionHistory) uChecker, _ := NewUpdateChecker("blocklist") service.AddListener(connectionEventListener) currentCountry := clientconfig.Get().Settings.Local.CountryCode checkCountrySettingC := time.NewTicker(2 * time.Second) defer checkCountrySettingC.Stop() loop: for { select { // Update when the transport connection comes up case event := <-connectionEventListener: if event.IsUp() { uChecker.Activate() uChecker.UpdateNow() } // Tell updatechecker to request update when user changes country settings case <-checkCountrySettingC.C: conf := clientconfig.Get() if currentCountry != conf.Settings.Local.CountryCode { currentCountry = conf.Settings.Local.CountryCode uChecker.UpdateNow() } // Update by request of the update checker case request := <-uChecker.RequestC: conf := clientconfig.Get() if conf.Settings.Local.CountryCode == "__" { lg.V(9).Infoln("Country is __, skipping blocklist updates") continue loop } currentCountry = conf.Settings.Local.CountryCode n, err := upgradeBlockList() if err != nil { lg.Errorf("blocklist update cc:%s err:%v", currentCountry, err) ui.Notify("blocklist_update_error_message") request.ResponseC <- UpdateError } else { lg.V(5).Infof("blocklist update success cc:%s, got %d entries", currentCountry, n) ui.Notify("blocklist_update_success_message") request.ResponseC <- UpdateSuccess } } } }
func StartConnectionManager(authKey string) { go updateTransportOkLoop() listeners := make([]chan ConnectionHistory, 0) // TODO: Test on irregular intervals reverifyTicker := time.NewTicker(connectionManagerTimings.TestTransportTicker) // the key is Connection.UUID histories := make(map[string][]ConnectionEvent) currents := make(map[string]*ConnectionEvent) currentConnectionID := "" currentConnectionsMu.Lock() currentConnIdx := 0 if len(currents) < 1 { go connect(currentConnections[currentConnIdx], authKey) currentConnectionID = currentConnections[currentConnIdx].ID } currentConnectionsMu.Unlock() firstUpNoProblems := true // no need to spam the user with popups var reconnectTimer *time.Timer var connectionTestRunning bool loop: for { s: select { case <-stopCh: lg.Infoln("connection manager shut down") break loop case <-reconnectCh: currentConnectionsMu.Lock() if len(currentConnections) < 1 { currentConnectionsMu.Unlock() lg.Warningln("No connections enabled") reconnectTimer = time.AfterFunc(connectionManagerTimings.ReconnectTransportDelay, func() { reconnectCh <- true }) break s } currentConnIdx = (currentConnIdx + 1) % (len(currentConnections)) c := currentConnections[currentConnIdx] lg.V(10).Infof("reconnecting to transport %v", c) go connect(currentConnections[currentConnIdx], authKey) currentConnectionID = c.ID currentConnectionsMu.Unlock() case listener := <-addNetworkStateListener: listeners = append(listeners, listener) case event := <-connectionEvents: if _, v := histories[event.Connection.ID]; !v { histories[event.Connection.ID] = make([]ConnectionEvent, 0) } else if len(histories[event.Connection.ID]) > 20 { lg.V(5).Infoln("trimming connection history") histories[event.Connection.ID] = histories[event.Connection.ID][:20] } histories[event.Connection.ID] = append(histories[event.Connection.ID], event) currents[event.Connection.ID] = &event emitEvent := ConnectionHistory{ History: histories[event.Connection.ID], } if lg.V(3) { switch event.State { case Failed, TestFailed: lg.Warningln("event ", event.Connection.ID, ": ", event.State) default: lg.Infoln("event ", event.Connection.ID, ": ", event.State) } } switch event.State { case Up: if firstUpNoProblems { firstUpNoProblems = false } else { ui.Notify("transport_connected_message") } case Failed: firstUpNoProblems = false ui.Notify("transport_error_message") case TestFailed: firstUpNoProblems = false ui.Notify("transport_retry") case Ended: delete(currents, event.Connection.ID) lg.V(15).Infoln("waiting before sending reconnect") if reconnectTimer != nil { reconnectTimer.Stop() } reconnectTimer = time.AfterFunc(connectionManagerTimings.ReconnectTransportDelay, func() { reconnectCh <- true }) } lg.V(7).Infoln("Forwarding connection event to listeners", emitEvent.Current()) for _, l := range listeners { l <- emitEvent } case <-reverifyTicker.C: if !connectionTestRunning { conn, ok := currents[currentConnectionID] if ok && conn.State == Up { connectionTestRunning = true go func() { err := testConn(conn) if err != nil { lg.Warningln(err) connectionTestedCh <- false } connectionTestedCh <- true }() } } case <-connectionTestedCh: connectionTestRunning = false } } }
func startInternalHTTPServer(authKey string) error { lg.V(15).Infoln("starting internal api server") mux, err := createServeMux() if err != nil { lg.Error("failed to create router") return err } auth := Auth{Key: authKey, wrapped: mux} conf := clientconfig.Get() listener, err := net.Listen("tcp", conf.Settings.Local.ClientBindAddr) if err != nil { lg.Warning(err) listener, err = net.Listen("tcp", "127.0.0.1:") } if err != nil { lg.Warning(err) ui.Notify("Could not bind any local port (bootstrap)") lg.Errorln("Could not bind any local port (bootstrap)") return err } go func(listenaddr string) { // baseURL := fmt.Sprintf() baseURL := fmt.Sprintf("http://%s?suk=", listenaddr) for { select { case <-ui.Actions.CopyBrowserCodeToClipboard: bc := browsercode.BrowserCode{Key: authKey} err := bc.SetHostport(listener.Addr().String()) if err != nil { lg.Errorln(err) continue } err = bc.CopyToClipboard() if err != nil { lg.Errorln(err) } case <-ui.Actions.OpenInBrowser: browser.OpenURL(baseURL + singleUseKeys.New() + "#/") case <-ui.Actions.Help: browser.OpenURL(baseURL + singleUseKeys.New() + "#/docs/__/index") } singleUseKeys.Cleanup() } }(listener.Addr().String()) doneC := make(chan bool, 1) go func() { defer listener.Close() err = http.Serve(listener, auth) if err != nil { doneC <- false } }() select { case ok := <-doneC: if !ok { return errors.New("Could not start internal http server") } case <-time.After(time.Millisecond * 200): return nil } return nil }