You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

153 lines
3.0 KiB

package assets
import (
"XProxy/logger"
"github.com/robfig/cron"
urlpkg "net/url"
"os"
"os/signal"
"strings"
"sync"
"syscall"
)
var buildinAssets = map[string]string{
"geoip.dat": "/geoip.dat.xz",
"geosite.dat": "/geosite.dat.xz",
}
func LoadBuildin() {
updateLocalAssets(buildinAssets, true)
}
type updateConfig struct {
spec string
cron *cron.Cron
renew sync.Mutex
running sync.Mutex
proxy *urlpkg.URL
assets map[string]string
}
var update updateConfig
func init() {
updateChan := make(chan os.Signal, 1)
go func() {
for {
<-updateChan
logger.Debugf("Trigger assets update due to receiving SIGALRM")
Update()
}
}()
signal.Notify(updateChan, syscall.SIGALRM)
}
func mapClone(raw map[string]string) map[string]string {
assets := make(map[string]string, len(raw))
for file, url := range raw {
assets[file] = strings.Clone(url)
}
return assets
}
func Update() {
update.renew.Lock()
proxy := update.proxy
assets := mapClone(update.assets)
update.renew.Unlock()
if !update.running.TryLock() {
logger.Infof("Another assets update is in progress, skip it")
return
}
logger.Infof("Start remote assets update process")
updateRemoteAssets(assets, proxy, false)
update.running.Unlock()
}
func GetAssets() map[string]string {
update.renew.Lock()
assets := mapClone(update.assets)
update.renew.Unlock()
return assets
}
func SetAssets(assets map[string]string) {
update.renew.Lock()
update.assets = mapClone(assets)
update.renew.Unlock()
}
func GetProxy() string {
update.renew.Lock()
proxy := update.proxy.String()
update.renew.Unlock()
return proxy
}
func SetProxy(proxy string) error {
var proxyUrl *urlpkg.URL
if proxy != "" {
url, err := urlpkg.Parse(proxy)
if err != nil {
logger.Errorf("Invalid proxy url `%s` -> %v", proxy, err)
return err
}
proxyUrl = url
}
update.renew.Lock()
update.proxy = proxyUrl
update.renew.Unlock()
return nil
}
// GetCron is used to obtain cron service specification.
func GetCron() string {
update.renew.Lock()
spec := strings.Clone(update.spec)
update.renew.Unlock()
return spec
}
// SetCron is used to update cron service specification.
func SetCron(spec string) error {
if spec == update.spec {
return nil // cron spec without renew
}
var cs *cron.Cron
if spec != "" { // update cron service
cs = cron.New()
err := cs.AddFunc(spec, func() {
var entry *cron.Entry
if entries := update.cron.Entries(); len(entries) != 0 && entries[0] != nil {
entry = entries[0]
}
logger.Debugf("hello from cron")
if entry != nil {
logger.Debugf("Assets cron service next trigger -> `%s`", entry.Next)
}
})
if err != nil {
logger.Errorf("Invalid cron spec `%s` -> %v", spec, err)
return err
}
cs.Start()
}
update.renew.Lock()
if update.cron != nil {
update.cron.Stop() // stop old cron service
}
update.cron = cs
update.spec = spec
if cs == nil {
logger.Infof("Assets cron service has been terminated")
} else {
logger.Infof("Assets cron service has been updated -> `%s`", spec)
}
update.renew.Unlock()
return nil
}