Skip to content

Commit

Permalink
fix: geo auto update #1261
Browse files Browse the repository at this point in the history
  • Loading branch information
Larvan2 committed May 17, 2024
1 parent fe88f0e commit 5c3a9b1
Show file tree
Hide file tree
Showing 9 changed files with 144 additions and 114 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ func (e *updateError) Error() string {

// Update performs the auto-updater. It returns an error if the updater failed.
// If firstRun is true, it assumes the configuration file doesn't exist.
func Update(execPath string) (err error) {
func UpdateCore(execPath string) (err error) {
mu.Lock()
defer mu.Unlock()

Expand Down
94 changes: 92 additions & 2 deletions config/update_geo.go → component/updater/update_geo.go
Original file line number Diff line number Diff line change
@@ -1,18 +1,29 @@
package config
package updater

import (
"errors"
"fmt"
"os"
"runtime"
"sync"
"time"

"github.com/metacubex/mihomo/common/atomic"
"github.com/metacubex/mihomo/component/geodata"
_ "github.com/metacubex/mihomo/component/geodata/standard"
"github.com/metacubex/mihomo/component/mmdb"
C "github.com/metacubex/mihomo/constant"
"github.com/metacubex/mihomo/log"

"github.com/oschwald/maxminddb-golang"
)

func UpdateGeoDatabases() error {
var (
updateGeoMux sync.Mutex
UpdatingGeo atomic.Bool
)

func updateGeoDatabases() error {
defer runtime.GC()
geoLoader, err := geodata.GetGeoDataLoader("standard")
if err != nil {
Expand Down Expand Up @@ -88,3 +99,82 @@ func UpdateGeoDatabases() error {

return nil
}

func UpdateGeoDatabases() error {
log.Infoln("[GEO] Start updating GEO database")

updateGeoMux.Lock()

if UpdatingGeo.Load() {
updateGeoMux.Unlock()
return errors.New("GEO database is updating, skip")
}

UpdatingGeo.Store(true)
updateGeoMux.Unlock()

defer func() {
UpdatingGeo.Store(false)
}()

log.Infoln("[GEO] Updating GEO database")

if err := updateGeoDatabases(); err != nil {
log.Errorln("[GEO] update GEO database error: %s", err.Error())
return err
}

return nil
}

func getUpdateTime() (err error, time time.Time) {
var fileInfo os.FileInfo
if C.GeodataMode {
fileInfo, err = os.Stat(C.Path.GeoIP())
if err != nil {
return err, time
}
} else {
fileInfo, err = os.Stat(C.Path.MMDB())
if err != nil {
return err, time
}
}

return nil, fileInfo.ModTime()
}

func RegisterGeoUpdater() {
if C.GeoUpdateInterval <= 0 {
log.Errorln("[GEO] Invalid update interval: %d", C.GeoUpdateInterval)
return
}

ticker := time.NewTicker(time.Duration(C.GeoUpdateInterval) * time.Hour)
defer ticker.Stop()

log.Infoln("[GEO] update GEO database every %d hours", C.GeoUpdateInterval)
go func() {
err, lastUpdate := getUpdateTime()
if err != nil {
log.Errorln("[GEO] Get GEO database update time error: %s", err.Error())
return
}

log.Infoln("[GEO] last update time %s", lastUpdate)
if lastUpdate.Add(time.Duration(C.GeoUpdateInterval) * time.Hour).Before(time.Now()) {
log.Infoln("[GEO] Database has not been updated for %v, update now", time.Duration(C.GeoUpdateInterval)*time.Hour)
if err := UpdateGeoDatabases(); err != nil {
log.Errorln("[GEO] Failed to update GEO database: %s", err.Error())
return
}
}

for range ticker.C {
if err := UpdateGeoDatabases(); err != nil {
log.Errorln("[GEO] Failed to update GEO database: %s", err.Error())
return
}
}
}()
}
6 changes: 3 additions & 3 deletions config/update_ui.go → component/updater/update_ui.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package config
package updater

import (
"archive/zip"
Expand Down Expand Up @@ -29,7 +29,7 @@ func UpdateUI() error {
xdMutex.Lock()
defer xdMutex.Unlock()

err := prepare()
err := prepare_ui()
if err != nil {
return err
}
Expand Down Expand Up @@ -64,7 +64,7 @@ func UpdateUI() error {
return nil
}

func prepare() error {
func prepare_ui() error {
if ExternalUIPath == "" || ExternalUIURL == "" {
return ErrIncompleteConf
}
Expand Down
23 changes: 23 additions & 0 deletions hub/updater/limitedreader.go → component/updater/utils.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,35 @@
package updater

import (
"context"
"fmt"
"io"
"net/http"
"os"
"time"

mihomoHttp "github.com/metacubex/mihomo/component/http"
C "github.com/metacubex/mihomo/constant"

"golang.org/x/exp/constraints"
)

func downloadForBytes(url string) ([]byte, error) {
ctx, cancel := context.WithTimeout(context.Background(), time.Second*90)
defer cancel()
resp, err := mihomoHttp.HttpRequest(ctx, url, http.MethodGet, http.Header{"User-Agent": {C.UA}}, nil)
if err != nil {
return nil, err
}
defer resp.Body.Close()

return io.ReadAll(resp.Body)
}

func saveFile(bytes []byte, path string) error {
return os.WriteFile(path, bytes, 0o644)
}

// LimitReachedError records the limit and the operation that caused it.
type LimitReachedError struct {
Limit int64
Expand Down
19 changes: 10 additions & 9 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
SNIFF "github.com/metacubex/mihomo/component/sniffer"
tlsC "github.com/metacubex/mihomo/component/tls"
"github.com/metacubex/mihomo/component/trie"
"github.com/metacubex/mihomo/component/updater"
C "github.com/metacubex/mihomo/constant"
"github.com/metacubex/mihomo/constant/features"
providerTypes "github.com/metacubex/mihomo/constant/provider"
Expand Down Expand Up @@ -640,28 +641,28 @@ func parseGeneral(cfg *RawConfig) (*General, error) {
N.KeepAliveInterval = time.Duration(cfg.KeepAliveInterval) * time.Second
}

ExternalUIPath = cfg.ExternalUI
updater.ExternalUIPath = cfg.ExternalUI
// checkout externalUI exist
if ExternalUIPath != "" {
ExternalUIPath = C.Path.Resolve(ExternalUIPath)
if _, err := os.Stat(ExternalUIPath); os.IsNotExist(err) {
if updater.ExternalUIPath != "" {
updater.ExternalUIPath = C.Path.Resolve(updater.ExternalUIPath)
if _, err := os.Stat(updater.ExternalUIPath); os.IsNotExist(err) {
defaultUIpath := path.Join(C.Path.HomeDir(), "ui")
log.Warnln("external-ui: %s does not exist, creating folder in %s", ExternalUIPath, defaultUIpath)
log.Warnln("external-ui: %s does not exist, creating folder in %s", updater.ExternalUIPath, defaultUIpath)
if err := os.MkdirAll(defaultUIpath, os.ModePerm); err != nil {
return nil, err
}
ExternalUIPath = defaultUIpath
updater.ExternalUIPath = defaultUIpath
cfg.ExternalUI = defaultUIpath
}
}
// checkout UIpath/name exist
if cfg.ExternalUIName != "" {
ExternalUIName = cfg.ExternalUIName
updater.ExternalUIName = cfg.ExternalUIName
} else {
ExternalUIFolder = ExternalUIPath
updater.ExternalUIFolder = updater.ExternalUIPath
}
if cfg.ExternalUIURL != "" {
ExternalUIURL = cfg.ExternalUIURL
updater.ExternalUIURL = cfg.ExternalUIURL
}

cfg.Tun.RedirectToTun = cfg.EBpf.RedirectToTun
Expand Down
23 changes: 0 additions & 23 deletions config/utils.go
Original file line number Diff line number Diff line change
@@ -1,38 +1,15 @@
package config

import (
"context"
"fmt"
"io"
"net"
"net/http"
"net/netip"
"os"
"strings"
"time"

"github.com/metacubex/mihomo/adapter/outboundgroup"
"github.com/metacubex/mihomo/common/structure"
mihomoHttp "github.com/metacubex/mihomo/component/http"
C "github.com/metacubex/mihomo/constant"
)

func downloadForBytes(url string) ([]byte, error) {
ctx, cancel := context.WithTimeout(context.Background(), time.Second*90)
defer cancel()
resp, err := mihomoHttp.HttpRequest(ctx, url, http.MethodGet, http.Header{"User-Agent": {C.UA}}, nil)
if err != nil {
return nil, err
}
defer resp.Body.Close()

return io.ReadAll(resp.Body)
}

func saveFile(bytes []byte, path string) error {
return os.WriteFile(path, bytes, 0o644)
}

func trimArr(arr []string) (r []string) {
for _, e := range arr {
r = append(r, strings.Trim(e, " "))
Expand Down
31 changes: 8 additions & 23 deletions hub/route/configs.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ import (
"net/http"
"net/netip"
"path/filepath"
"sync"

"github.com/metacubex/mihomo/adapter/inbound"
"github.com/metacubex/mihomo/component/dialer"
"github.com/metacubex/mihomo/component/resolver"
"github.com/metacubex/mihomo/component/updater"
"github.com/metacubex/mihomo/config"
C "github.com/metacubex/mihomo/constant"
"github.com/metacubex/mihomo/hub/executor"
Expand All @@ -21,11 +21,6 @@ import (
"github.com/go-chi/render"
)

var (
updateGeoMux sync.Mutex
updatingGeo = false
)

func configRouter() http.Handler {
r := chi.NewRouter()
r.Get("/", getConfigs)
Expand Down Expand Up @@ -369,30 +364,20 @@ func updateConfigs(w http.ResponseWriter, r *http.Request) {
}

func updateGeoDatabases(w http.ResponseWriter, r *http.Request) {
updateGeoMux.Lock()

if updatingGeo {
updateGeoMux.Unlock()
if updater.UpdatingGeo.Load() {
render.Status(r, http.StatusBadRequest)
render.JSON(w, r, newError("updating..."))
return
}

updatingGeo = true
updateGeoMux.Unlock()
err := updater.UpdateGeoDatabases()
if err != nil {
render.Status(r, http.StatusBadRequest)
render.JSON(w, r, newError(err.Error()))
return
}

go func() {
defer func() {
updatingGeo = false
}()

log.Warnln("[REST-API] updating GEO databases...")

if err := config.UpdateGeoDatabases(); err != nil {
log.Errorln("[REST-API] update GEO databases failed: %v", err)
return
}

cfg, err := executor.ParseWithPath(C.Path.Config())
if err != nil {
log.Errorln("[REST-API] update GEO databases failed: %v", err)
Expand Down
10 changes: 5 additions & 5 deletions hub/route/upgrade.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@ import (
"net/http"
"os"

"github.com/metacubex/mihomo/config"
"github.com/metacubex/mihomo/hub/updater"
"github.com/metacubex/mihomo/component/updater"
"github.com/metacubex/mihomo/log"

"github.com/go-chi/chi/v5"
Expand All @@ -18,6 +17,7 @@ func upgradeRouter() http.Handler {
r := chi.NewRouter()
r.Post("/", upgradeCore)
r.Post("/ui", updateUI)
r.Post("/geo", updateGeoDatabases)
return r
}

Expand All @@ -31,7 +31,7 @@ func upgradeCore(w http.ResponseWriter, r *http.Request) {
return
}

err = updater.Update(execPath)
err = updater.UpdateCore(execPath)
if err != nil {
log.Warnln("%s", err)
render.Status(r, http.StatusInternalServerError)
Expand All @@ -48,9 +48,9 @@ func upgradeCore(w http.ResponseWriter, r *http.Request) {
}

func updateUI(w http.ResponseWriter, r *http.Request) {
err := config.UpdateUI()
err := updater.UpdateUI()
if err != nil {
if errors.Is(err, config.ErrIncompleteConf) {
if errors.Is(err, updater.ErrIncompleteConf) {
log.Warnln("%s", err)
render.Status(r, http.StatusNotImplemented)
render.JSON(w, r, newError(fmt.Sprintf("%s", err)))
Expand Down

0 comments on commit 5c3a9b1

Please sign in to comment.