Example #1
0
// 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
			}
		}
	}
}
Example #2
0
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
		}
	}
}
Example #3
0
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
}