* Inline manifest.json Improve performance by eliminating this separate request and just inline this small JSON in HTML directly as a data uri. Also update previously static app name scripts to use AppName. I've confirmed this as working via "Add to Homescreen" feature which offered to save the shortcut under the new app name. * prerender manifest data on startup * move to settings * restore setting.AppStartTime and use it on admin page * use double quotes because template.URL escapes everything * fix lint * move variable to global context variable * delete template file Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com> Co-authored-by: zeripath <art27@cantab.net>
		
			
				
	
	
		
			483 lines
		
	
	
	
		
			15 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			483 lines
		
	
	
	
		
			15 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // Copyright 2014 The Gogs Authors. All rights reserved.
 | |
| // Copyright 2019 The Gitea Authors. All rights reserved.
 | |
| // Use of this source code is governed by a MIT-style
 | |
| // license that can be found in the LICENSE file.
 | |
| 
 | |
| package admin
 | |
| 
 | |
| import (
 | |
| 	"encoding/json"
 | |
| 	"fmt"
 | |
| 	"net/url"
 | |
| 	"os"
 | |
| 	"runtime"
 | |
| 	"strconv"
 | |
| 	"strings"
 | |
| 	"time"
 | |
| 
 | |
| 	"code.gitea.io/gitea/models"
 | |
| 	"code.gitea.io/gitea/modules/auth"
 | |
| 	"code.gitea.io/gitea/modules/base"
 | |
| 	"code.gitea.io/gitea/modules/context"
 | |
| 	"code.gitea.io/gitea/modules/cron"
 | |
| 	"code.gitea.io/gitea/modules/git"
 | |
| 	"code.gitea.io/gitea/modules/log"
 | |
| 	"code.gitea.io/gitea/modules/process"
 | |
| 	"code.gitea.io/gitea/modules/queue"
 | |
| 	"code.gitea.io/gitea/modules/setting"
 | |
| 	"code.gitea.io/gitea/modules/timeutil"
 | |
| 	"code.gitea.io/gitea/services/mailer"
 | |
| 
 | |
| 	"gitea.com/macaron/macaron"
 | |
| 	"gitea.com/macaron/session"
 | |
| )
 | |
| 
 | |
| const (
 | |
| 	tplDashboard base.TplName = "admin/dashboard"
 | |
| 	tplConfig    base.TplName = "admin/config"
 | |
| 	tplMonitor   base.TplName = "admin/monitor"
 | |
| 	tplQueue     base.TplName = "admin/queue"
 | |
| )
 | |
| 
 | |
| var sysStatus struct {
 | |
| 	Uptime       string
 | |
| 	NumGoroutine int
 | |
| 
 | |
| 	// General statistics.
 | |
| 	MemAllocated string // bytes allocated and still in use
 | |
| 	MemTotal     string // bytes allocated (even if freed)
 | |
| 	MemSys       string // bytes obtained from system (sum of XxxSys below)
 | |
| 	Lookups      uint64 // number of pointer lookups
 | |
| 	MemMallocs   uint64 // number of mallocs
 | |
| 	MemFrees     uint64 // number of frees
 | |
| 
 | |
| 	// Main allocation heap statistics.
 | |
| 	HeapAlloc    string // bytes allocated and still in use
 | |
| 	HeapSys      string // bytes obtained from system
 | |
| 	HeapIdle     string // bytes in idle spans
 | |
| 	HeapInuse    string // bytes in non-idle span
 | |
| 	HeapReleased string // bytes released to the OS
 | |
| 	HeapObjects  uint64 // total number of allocated objects
 | |
| 
 | |
| 	// Low-level fixed-size structure allocator statistics.
 | |
| 	//	Inuse is bytes used now.
 | |
| 	//	Sys is bytes obtained from system.
 | |
| 	StackInuse  string // bootstrap stacks
 | |
| 	StackSys    string
 | |
| 	MSpanInuse  string // mspan structures
 | |
| 	MSpanSys    string
 | |
| 	MCacheInuse string // mcache structures
 | |
| 	MCacheSys   string
 | |
| 	BuckHashSys string // profiling bucket hash table
 | |
| 	GCSys       string // GC metadata
 | |
| 	OtherSys    string // other system allocations
 | |
| 
 | |
| 	// Garbage collector statistics.
 | |
| 	NextGC       string // next run in HeapAlloc time (bytes)
 | |
| 	LastGC       string // last run in absolute time (ns)
 | |
| 	PauseTotalNs string
 | |
| 	PauseNs      string // circular buffer of recent GC pause times, most recent at [(NumGC+255)%256]
 | |
| 	NumGC        uint32
 | |
| }
 | |
| 
 | |
| func updateSystemStatus() {
 | |
| 	sysStatus.Uptime = timeutil.TimeSincePro(setting.AppStartTime, "en")
 | |
| 
 | |
| 	m := new(runtime.MemStats)
 | |
| 	runtime.ReadMemStats(m)
 | |
| 	sysStatus.NumGoroutine = runtime.NumGoroutine()
 | |
| 
 | |
| 	sysStatus.MemAllocated = base.FileSize(int64(m.Alloc))
 | |
| 	sysStatus.MemTotal = base.FileSize(int64(m.TotalAlloc))
 | |
| 	sysStatus.MemSys = base.FileSize(int64(m.Sys))
 | |
| 	sysStatus.Lookups = m.Lookups
 | |
| 	sysStatus.MemMallocs = m.Mallocs
 | |
| 	sysStatus.MemFrees = m.Frees
 | |
| 
 | |
| 	sysStatus.HeapAlloc = base.FileSize(int64(m.HeapAlloc))
 | |
| 	sysStatus.HeapSys = base.FileSize(int64(m.HeapSys))
 | |
| 	sysStatus.HeapIdle = base.FileSize(int64(m.HeapIdle))
 | |
| 	sysStatus.HeapInuse = base.FileSize(int64(m.HeapInuse))
 | |
| 	sysStatus.HeapReleased = base.FileSize(int64(m.HeapReleased))
 | |
| 	sysStatus.HeapObjects = m.HeapObjects
 | |
| 
 | |
| 	sysStatus.StackInuse = base.FileSize(int64(m.StackInuse))
 | |
| 	sysStatus.StackSys = base.FileSize(int64(m.StackSys))
 | |
| 	sysStatus.MSpanInuse = base.FileSize(int64(m.MSpanInuse))
 | |
| 	sysStatus.MSpanSys = base.FileSize(int64(m.MSpanSys))
 | |
| 	sysStatus.MCacheInuse = base.FileSize(int64(m.MCacheInuse))
 | |
| 	sysStatus.MCacheSys = base.FileSize(int64(m.MCacheSys))
 | |
| 	sysStatus.BuckHashSys = base.FileSize(int64(m.BuckHashSys))
 | |
| 	sysStatus.GCSys = base.FileSize(int64(m.GCSys))
 | |
| 	sysStatus.OtherSys = base.FileSize(int64(m.OtherSys))
 | |
| 
 | |
| 	sysStatus.NextGC = base.FileSize(int64(m.NextGC))
 | |
| 	sysStatus.LastGC = fmt.Sprintf("%.1fs", float64(time.Now().UnixNano()-int64(m.LastGC))/1000/1000/1000)
 | |
| 	sysStatus.PauseTotalNs = fmt.Sprintf("%.1fs", float64(m.PauseTotalNs)/1000/1000/1000)
 | |
| 	sysStatus.PauseNs = fmt.Sprintf("%.3fs", float64(m.PauseNs[(m.NumGC+255)%256])/1000/1000/1000)
 | |
| 	sysStatus.NumGC = m.NumGC
 | |
| }
 | |
| 
 | |
| // Dashboard show admin panel dashboard
 | |
| func Dashboard(ctx *context.Context) {
 | |
| 	ctx.Data["Title"] = ctx.Tr("admin.dashboard")
 | |
| 	ctx.Data["PageIsAdmin"] = true
 | |
| 	ctx.Data["PageIsAdminDashboard"] = true
 | |
| 	ctx.Data["Stats"] = models.GetStatistic()
 | |
| 	// FIXME: update periodically
 | |
| 	updateSystemStatus()
 | |
| 	ctx.Data["SysStatus"] = sysStatus
 | |
| 	ctx.Data["SSH"] = setting.SSH
 | |
| 	ctx.HTML(200, tplDashboard)
 | |
| }
 | |
| 
 | |
| // DashboardPost run an admin operation
 | |
| func DashboardPost(ctx *context.Context, form auth.AdminDashboardForm) {
 | |
| 	ctx.Data["Title"] = ctx.Tr("admin.dashboard")
 | |
| 	ctx.Data["PageIsAdmin"] = true
 | |
| 	ctx.Data["PageIsAdminDashboard"] = true
 | |
| 	ctx.Data["Stats"] = models.GetStatistic()
 | |
| 	updateSystemStatus()
 | |
| 	ctx.Data["SysStatus"] = sysStatus
 | |
| 
 | |
| 	// Run operation.
 | |
| 	if form.Op != "" {
 | |
| 		task := cron.GetTask(form.Op)
 | |
| 		if task != nil {
 | |
| 			go task.RunWithUser(ctx.User, nil)
 | |
| 			ctx.Flash.Success(ctx.Tr("admin.dashboard.task.started", ctx.Tr("admin.dashboard."+form.Op)))
 | |
| 		} else {
 | |
| 			ctx.Flash.Error(ctx.Tr("admin.dashboard.task.unknown", form.Op))
 | |
| 		}
 | |
| 	}
 | |
| 	if form.From == "monitor" {
 | |
| 		ctx.Redirect(setting.AppSubURL + "/admin/monitor")
 | |
| 	} else {
 | |
| 		ctx.Redirect(setting.AppSubURL + "/admin")
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // SendTestMail send test mail to confirm mail service is OK
 | |
| func SendTestMail(ctx *context.Context) {
 | |
| 	email := ctx.Query("email")
 | |
| 	// Send a test email to the user's email address and redirect back to Config
 | |
| 	if err := mailer.SendTestMail(email); err != nil {
 | |
| 		ctx.Flash.Error(ctx.Tr("admin.config.test_mail_failed", email, err))
 | |
| 	} else {
 | |
| 		ctx.Flash.Info(ctx.Tr("admin.config.test_mail_sent", email))
 | |
| 	}
 | |
| 
 | |
| 	ctx.Redirect(setting.AppSubURL + "/admin/config")
 | |
| }
 | |
| 
 | |
| func shadowPasswordKV(cfgItem, splitter string) string {
 | |
| 	fields := strings.Split(cfgItem, splitter)
 | |
| 	for i := 0; i < len(fields); i++ {
 | |
| 		if strings.HasPrefix(fields[i], "password=") {
 | |
| 			fields[i] = "password=******"
 | |
| 			break
 | |
| 		}
 | |
| 	}
 | |
| 	return strings.Join(fields, splitter)
 | |
| }
 | |
| 
 | |
| func shadowURL(provider, cfgItem string) string {
 | |
| 	u, err := url.Parse(cfgItem)
 | |
| 	if err != nil {
 | |
| 		log.Error("Shadowing Password for %v failed: %v", provider, err)
 | |
| 		return cfgItem
 | |
| 	}
 | |
| 	if u.User != nil {
 | |
| 		atIdx := strings.Index(cfgItem, "@")
 | |
| 		if atIdx > 0 {
 | |
| 			colonIdx := strings.LastIndex(cfgItem[:atIdx], ":")
 | |
| 			if colonIdx > 0 {
 | |
| 				return cfgItem[:colonIdx+1] + "******" + cfgItem[atIdx:]
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	return cfgItem
 | |
| }
 | |
| 
 | |
| func shadowPassword(provider, cfgItem string) string {
 | |
| 	switch provider {
 | |
| 	case "redis":
 | |
| 		return shadowPasswordKV(cfgItem, ",")
 | |
| 	case "mysql":
 | |
| 		//root:@tcp(localhost:3306)/macaron?charset=utf8
 | |
| 		atIdx := strings.Index(cfgItem, "@")
 | |
| 		if atIdx > 0 {
 | |
| 			colonIdx := strings.Index(cfgItem[:atIdx], ":")
 | |
| 			if colonIdx > 0 {
 | |
| 				return cfgItem[:colonIdx+1] + "******" + cfgItem[atIdx:]
 | |
| 			}
 | |
| 		}
 | |
| 		return cfgItem
 | |
| 	case "postgres":
 | |
| 		// user=jiahuachen dbname=macaron port=5432 sslmode=disable
 | |
| 		if !strings.HasPrefix(cfgItem, "postgres://") {
 | |
| 			return shadowPasswordKV(cfgItem, " ")
 | |
| 		}
 | |
| 		fallthrough
 | |
| 	case "couchbase":
 | |
| 		return shadowURL(provider, cfgItem)
 | |
| 		// postgres://pqgotest:password@localhost/pqgotest?sslmode=verify-full
 | |
| 		// Notice: use shadowURL
 | |
| 	}
 | |
| 	return cfgItem
 | |
| }
 | |
| 
 | |
| // Config show admin config page
 | |
| func Config(ctx *context.Context) {
 | |
| 	ctx.Data["Title"] = ctx.Tr("admin.config")
 | |
| 	ctx.Data["PageIsAdmin"] = true
 | |
| 	ctx.Data["PageIsAdminConfig"] = true
 | |
| 
 | |
| 	ctx.Data["CustomConf"] = setting.CustomConf
 | |
| 	ctx.Data["AppUrl"] = setting.AppURL
 | |
| 	ctx.Data["Domain"] = setting.Domain
 | |
| 	ctx.Data["OfflineMode"] = setting.OfflineMode
 | |
| 	ctx.Data["DisableRouterLog"] = setting.DisableRouterLog
 | |
| 	ctx.Data["RunUser"] = setting.RunUser
 | |
| 	ctx.Data["RunMode"] = strings.Title(macaron.Env)
 | |
| 	if version, err := git.LocalVersion(); err == nil {
 | |
| 		ctx.Data["GitVersion"] = version.Original()
 | |
| 	}
 | |
| 	ctx.Data["RepoRootPath"] = setting.RepoRootPath
 | |
| 	ctx.Data["CustomRootPath"] = setting.CustomPath
 | |
| 	ctx.Data["StaticRootPath"] = setting.StaticRootPath
 | |
| 	ctx.Data["LogRootPath"] = setting.LogRootPath
 | |
| 	ctx.Data["ScriptType"] = setting.ScriptType
 | |
| 	ctx.Data["ReverseProxyAuthUser"] = setting.ReverseProxyAuthUser
 | |
| 	ctx.Data["ReverseProxyAuthEmail"] = setting.ReverseProxyAuthEmail
 | |
| 
 | |
| 	ctx.Data["SSH"] = setting.SSH
 | |
| 	ctx.Data["LFS"] = setting.LFS
 | |
| 
 | |
| 	ctx.Data["Service"] = setting.Service
 | |
| 	ctx.Data["DbCfg"] = setting.Database
 | |
| 	ctx.Data["Webhook"] = setting.Webhook
 | |
| 
 | |
| 	ctx.Data["MailerEnabled"] = false
 | |
| 	if setting.MailService != nil {
 | |
| 		ctx.Data["MailerEnabled"] = true
 | |
| 		ctx.Data["Mailer"] = setting.MailService
 | |
| 	}
 | |
| 
 | |
| 	ctx.Data["CacheAdapter"] = setting.CacheService.Adapter
 | |
| 	ctx.Data["CacheInterval"] = setting.CacheService.Interval
 | |
| 
 | |
| 	ctx.Data["CacheConn"] = shadowPassword(setting.CacheService.Adapter, setting.CacheService.Conn)
 | |
| 	ctx.Data["CacheItemTTL"] = setting.CacheService.TTL
 | |
| 
 | |
| 	sessionCfg := setting.SessionConfig
 | |
| 	if sessionCfg.Provider == "VirtualSession" {
 | |
| 		var realSession session.Options
 | |
| 		if err := json.Unmarshal([]byte(sessionCfg.ProviderConfig), &realSession); err != nil {
 | |
| 			log.Error("Unable to unmarshall session config for virtualed provider config: %s\nError: %v", sessionCfg.ProviderConfig, err)
 | |
| 		}
 | |
| 		sessionCfg.Provider = realSession.Provider
 | |
| 		sessionCfg.ProviderConfig = realSession.ProviderConfig
 | |
| 		sessionCfg.CookieName = realSession.CookieName
 | |
| 		sessionCfg.CookiePath = realSession.CookiePath
 | |
| 		sessionCfg.Gclifetime = realSession.Gclifetime
 | |
| 		sessionCfg.Maxlifetime = realSession.Maxlifetime
 | |
| 		sessionCfg.Secure = realSession.Secure
 | |
| 		sessionCfg.Domain = realSession.Domain
 | |
| 	}
 | |
| 	sessionCfg.ProviderConfig = shadowPassword(sessionCfg.Provider, sessionCfg.ProviderConfig)
 | |
| 	ctx.Data["SessionConfig"] = sessionCfg
 | |
| 
 | |
| 	ctx.Data["DisableGravatar"] = setting.DisableGravatar
 | |
| 	ctx.Data["EnableFederatedAvatar"] = setting.EnableFederatedAvatar
 | |
| 
 | |
| 	ctx.Data["Git"] = setting.Git
 | |
| 
 | |
| 	type envVar struct {
 | |
| 		Name, Value string
 | |
| 	}
 | |
| 
 | |
| 	envVars := map[string]*envVar{}
 | |
| 	if len(os.Getenv("GITEA_WORK_DIR")) > 0 {
 | |
| 		envVars["GITEA_WORK_DIR"] = &envVar{"GITEA_WORK_DIR", os.Getenv("GITEA_WORK_DIR")}
 | |
| 	}
 | |
| 	if len(os.Getenv("GITEA_CUSTOM")) > 0 {
 | |
| 		envVars["GITEA_CUSTOM"] = &envVar{"GITEA_CUSTOM", os.Getenv("GITEA_CUSTOM")}
 | |
| 	}
 | |
| 
 | |
| 	ctx.Data["EnvVars"] = envVars
 | |
| 	ctx.Data["Loggers"] = setting.GetLogDescriptions()
 | |
| 	ctx.Data["RedirectMacaronLog"] = setting.RedirectMacaronLog
 | |
| 	ctx.Data["EnableAccessLog"] = setting.EnableAccessLog
 | |
| 	ctx.Data["AccessLogTemplate"] = setting.AccessLogTemplate
 | |
| 	ctx.Data["DisableRouterLog"] = setting.DisableRouterLog
 | |
| 	ctx.Data["EnableXORMLog"] = setting.EnableXORMLog
 | |
| 	ctx.Data["LogSQL"] = setting.Database.LogSQL
 | |
| 
 | |
| 	ctx.HTML(200, tplConfig)
 | |
| }
 | |
| 
 | |
| // Monitor show admin monitor page
 | |
| func Monitor(ctx *context.Context) {
 | |
| 	ctx.Data["Title"] = ctx.Tr("admin.monitor")
 | |
| 	ctx.Data["PageIsAdmin"] = true
 | |
| 	ctx.Data["PageIsAdminMonitor"] = true
 | |
| 	ctx.Data["Processes"] = process.GetManager().Processes()
 | |
| 	ctx.Data["Entries"] = cron.ListTasks()
 | |
| 	ctx.Data["Queues"] = queue.GetManager().ManagedQueues()
 | |
| 	ctx.HTML(200, tplMonitor)
 | |
| }
 | |
| 
 | |
| // MonitorCancel cancels a process
 | |
| func MonitorCancel(ctx *context.Context) {
 | |
| 	pid := ctx.ParamsInt64("pid")
 | |
| 	process.GetManager().Cancel(pid)
 | |
| 	ctx.JSON(200, map[string]interface{}{
 | |
| 		"redirect": setting.AppSubURL + "/admin/monitor",
 | |
| 	})
 | |
| }
 | |
| 
 | |
| // Queue shows details for a specific queue
 | |
| func Queue(ctx *context.Context) {
 | |
| 	qid := ctx.ParamsInt64("qid")
 | |
| 	mq := queue.GetManager().GetManagedQueue(qid)
 | |
| 	if mq == nil {
 | |
| 		ctx.Status(404)
 | |
| 		return
 | |
| 	}
 | |
| 	ctx.Data["Title"] = ctx.Tr("admin.monitor.queue", mq.Name)
 | |
| 	ctx.Data["PageIsAdmin"] = true
 | |
| 	ctx.Data["PageIsAdminMonitor"] = true
 | |
| 	ctx.Data["Queue"] = mq
 | |
| 	ctx.HTML(200, tplQueue)
 | |
| }
 | |
| 
 | |
| // WorkerCancel cancels a worker group
 | |
| func WorkerCancel(ctx *context.Context) {
 | |
| 	qid := ctx.ParamsInt64("qid")
 | |
| 	mq := queue.GetManager().GetManagedQueue(qid)
 | |
| 	if mq == nil {
 | |
| 		ctx.Status(404)
 | |
| 		return
 | |
| 	}
 | |
| 	pid := ctx.ParamsInt64("pid")
 | |
| 	mq.CancelWorkers(pid)
 | |
| 	ctx.Flash.Info(ctx.Tr("admin.monitor.queue.pool.cancelling"))
 | |
| 	ctx.JSON(200, map[string]interface{}{
 | |
| 		"redirect": setting.AppSubURL + fmt.Sprintf("/admin/monitor/queue/%d", qid),
 | |
| 	})
 | |
| }
 | |
| 
 | |
| // Flush flushes a queue
 | |
| func Flush(ctx *context.Context) {
 | |
| 	qid := ctx.ParamsInt64("qid")
 | |
| 	mq := queue.GetManager().GetManagedQueue(qid)
 | |
| 	if mq == nil {
 | |
| 		ctx.Status(404)
 | |
| 		return
 | |
| 	}
 | |
| 	timeout, err := time.ParseDuration(ctx.Query("timeout"))
 | |
| 	if err != nil {
 | |
| 		timeout = -1
 | |
| 	}
 | |
| 	ctx.Flash.Info(ctx.Tr("admin.monitor.queue.pool.flush.added", mq.Name))
 | |
| 	go func() {
 | |
| 		err := mq.Flush(timeout)
 | |
| 		if err != nil {
 | |
| 			log.Error("Flushing failure for %s: Error %v", mq.Name, err)
 | |
| 		}
 | |
| 	}()
 | |
| 	ctx.Redirect(setting.AppSubURL + fmt.Sprintf("/admin/monitor/queue/%d", qid))
 | |
| }
 | |
| 
 | |
| // AddWorkers adds workers to a worker group
 | |
| func AddWorkers(ctx *context.Context) {
 | |
| 	qid := ctx.ParamsInt64("qid")
 | |
| 	mq := queue.GetManager().GetManagedQueue(qid)
 | |
| 	if mq == nil {
 | |
| 		ctx.Status(404)
 | |
| 		return
 | |
| 	}
 | |
| 	number := ctx.QueryInt("number")
 | |
| 	if number < 1 {
 | |
| 		ctx.Flash.Error(ctx.Tr("admin.monitor.queue.pool.addworkers.mustnumbergreaterzero"))
 | |
| 		ctx.Redirect(setting.AppSubURL + fmt.Sprintf("/admin/monitor/queue/%d", qid))
 | |
| 		return
 | |
| 	}
 | |
| 	timeout, err := time.ParseDuration(ctx.Query("timeout"))
 | |
| 	if err != nil {
 | |
| 		ctx.Flash.Error(ctx.Tr("admin.monitor.queue.pool.addworkers.musttimeoutduration"))
 | |
| 		ctx.Redirect(setting.AppSubURL + fmt.Sprintf("/admin/monitor/queue/%d", qid))
 | |
| 		return
 | |
| 	}
 | |
| 	if _, ok := mq.Managed.(queue.ManagedPool); !ok {
 | |
| 		ctx.Flash.Error(ctx.Tr("admin.monitor.queue.pool.none"))
 | |
| 		ctx.Redirect(setting.AppSubURL + fmt.Sprintf("/admin/monitor/queue/%d", qid))
 | |
| 		return
 | |
| 	}
 | |
| 	mq.AddWorkers(number, timeout)
 | |
| 	ctx.Flash.Success(ctx.Tr("admin.monitor.queue.pool.added"))
 | |
| 	ctx.Redirect(setting.AppSubURL + fmt.Sprintf("/admin/monitor/queue/%d", qid))
 | |
| }
 | |
| 
 | |
| // SetQueueSettings sets the maximum number of workers and other settings for this queue
 | |
| func SetQueueSettings(ctx *context.Context) {
 | |
| 	qid := ctx.ParamsInt64("qid")
 | |
| 	mq := queue.GetManager().GetManagedQueue(qid)
 | |
| 	if mq == nil {
 | |
| 		ctx.Status(404)
 | |
| 		return
 | |
| 	}
 | |
| 	if _, ok := mq.Managed.(queue.ManagedPool); !ok {
 | |
| 		ctx.Flash.Error(ctx.Tr("admin.monitor.queue.pool.none"))
 | |
| 		ctx.Redirect(setting.AppSubURL + fmt.Sprintf("/admin/monitor/queue/%d", qid))
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	maxNumberStr := ctx.Query("max-number")
 | |
| 	numberStr := ctx.Query("number")
 | |
| 	timeoutStr := ctx.Query("timeout")
 | |
| 
 | |
| 	var err error
 | |
| 	var maxNumber, number int
 | |
| 	var timeout time.Duration
 | |
| 	if len(maxNumberStr) > 0 {
 | |
| 		maxNumber, err = strconv.Atoi(maxNumberStr)
 | |
| 		if err != nil {
 | |
| 			ctx.Flash.Error(ctx.Tr("admin.monitor.queue.settings.maxnumberworkers.error"))
 | |
| 			ctx.Redirect(setting.AppSubURL + fmt.Sprintf("/admin/monitor/queue/%d", qid))
 | |
| 			return
 | |
| 		}
 | |
| 		if maxNumber < -1 {
 | |
| 			maxNumber = -1
 | |
| 		}
 | |
| 	} else {
 | |
| 		maxNumber = mq.MaxNumberOfWorkers()
 | |
| 	}
 | |
| 
 | |
| 	if len(numberStr) > 0 {
 | |
| 		number, err = strconv.Atoi(numberStr)
 | |
| 		if err != nil || number < 0 {
 | |
| 			ctx.Flash.Error(ctx.Tr("admin.monitor.queue.settings.numberworkers.error"))
 | |
| 			ctx.Redirect(setting.AppSubURL + fmt.Sprintf("/admin/monitor/queue/%d", qid))
 | |
| 			return
 | |
| 		}
 | |
| 	} else {
 | |
| 		number = mq.BoostWorkers()
 | |
| 	}
 | |
| 
 | |
| 	if len(timeoutStr) > 0 {
 | |
| 		timeout, err = time.ParseDuration(timeoutStr)
 | |
| 		if err != nil {
 | |
| 			ctx.Flash.Error(ctx.Tr("admin.monitor.queue.settings.timeout.error"))
 | |
| 			ctx.Redirect(setting.AppSubURL + fmt.Sprintf("/admin/monitor/queue/%d", qid))
 | |
| 			return
 | |
| 		}
 | |
| 	} else {
 | |
| 		timeout = mq.BoostTimeout()
 | |
| 	}
 | |
| 
 | |
| 	mq.SetPoolSettings(maxNumber, number, timeout)
 | |
| 	ctx.Flash.Success(ctx.Tr("admin.monitor.queue.settings.changed"))
 | |
| 	ctx.Redirect(setting.AppSubURL + fmt.Sprintf("/admin/monitor/queue/%d", qid))
 | |
| }
 |