diff --git a/common/template_init.go b/common/template_init.go index 252772cf..2e9389dc 100644 --- a/common/template_init.go +++ b/common/template_init.go @@ -402,6 +402,7 @@ func compileTemplates(wg *sync.WaitGroup, c *tmpl.CTemplateSet, themeName string } wg.Add(1) go func() { + defer EatPanics() tname := themeName if tname != "" { tname = "_" + tname @@ -591,6 +592,7 @@ func compileJSTemplates(wg *sync.WaitGroup, c *tmpl.CTemplateSet, themeName stri } wg.Add(1) go func() { + defer EatPanics() tname := themeName if tname != "" { tname = "_" + tname @@ -737,6 +739,7 @@ func writeTemplateList(c *tmpl.CTemplateSet, wg *sync.WaitGroup, prefix string) log.Print("Writing template list") wg.Add(1) go func() { + defer EatPanics() e := writeFile(prefix+"tmpl_list.go", getTemplateList(c, wg, prefix)) if e != nil { log.Fatal(e) diff --git a/main.go b/main.go index c59560ec..2efebab0 100644 --- a/main.go +++ b/main.go @@ -19,6 +19,7 @@ import ( "os" "os/signal" "runtime" + "runtime/debug" "runtime/pprof" "strconv" "strings" @@ -356,13 +357,13 @@ func storeInit() (e error) { // TODO: Split this function up func main() { // TODO: Recover from panics - /*defer func() { + defer func() { if r := recover(); r != nil { log.Print(r) debug.PrintStack() - return + log.Fatal("Fatal error.") } - }()*/ + }() c.StartTime = time.Now() // TODO: Have a file for each run with the time/date the server started as the file name? @@ -465,6 +466,7 @@ func main() { defer watcher.Close() go func() { + defer c.EatPanics() var ErrFileSkip = errors.New("skip mod file") modifiedFileEvent := func(path string) error { pathBits := strings.Split(path, "\\") @@ -551,9 +553,11 @@ func main() { if err = tickLoop(thumbChan); err != nil { c.LogError(err) } + go TickLoop.Loop() // Resource Management Goroutine go func() { + defer c.EatPanics() uc, tc := c.Users.GetCache(), c.Topics.GetCache() if uc == nil && tc == nil { return @@ -594,6 +598,7 @@ func main() { sigs := make(chan os.Signal, 1) signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM) go func() { + defer c.EatPanics() sig := <-sigs log.Print("Received a signal to shutdown: ", sig) // TODO: Gracefully shutdown the HTTP server @@ -690,6 +695,7 @@ func startServer() { sQuicPort := strconv.Itoa(c.Dev.QuicPort) log.Print("Listening on quic port " + sQuicPort) go func() { + defer c.EatPanics() c.StoppedServer(http3.ListenAndServeQUIC(":"+sQuicPort, c.Config.SslFullchain, c.Config.SslPrivkey, router)) }() }*/ @@ -700,6 +706,7 @@ func startServer() { } log.Print("Listening on port " + c.Site.Port) go func() { + defer c.EatPanics() c.StoppedServer(newServer(":"+c.Site.Port, router).ListenAndServe()) }() return @@ -712,12 +719,14 @@ func startServer() { // We should also run the server on port 80 // TODO: Redirect to port 443 go func() { + defer c.EatPanics() log.Print("Listening on port 80") c.StoppedServer(newServer(":80", &HTTPSRedirect{}).ListenAndServe()) }() } log.Printf("Listening on port %s", c.Site.Port) go func() { + defer c.EatPanics() c.StoppedServer(newServer(":"+c.Site.Port, router).ListenAndServeTLS(c.Config.SslFullchain, c.Config.SslPrivkey)) }() } diff --git a/misc_test.go b/misc_test.go index e0f32930..cf475cfd 100644 --- a/misc_test.go +++ b/misc_test.go @@ -3186,4 +3186,18 @@ func TestWordCount(t *testing.T) { func TestTick(t *testing.T) { expectNilErr(t, c.StartupTasks()) expectNilErr(t, c.Dailies()) + + expectNilErr(t, c.Tasks.HalfSec.Run()) + expectNilErr(t, c.Tasks.Sec.Run()) + expectNilErr(t, c.Tasks.FifteenMin.Run()) + expectNilErr(t, c.Tasks.Hour.Run()) + expectNilErr(t, c.Tasks.Day.Run()) + + thumbChan := make(chan bool) + expectNilErr(t, tickLoop(thumbChan)) + expectNilErr(t, c.CTickLoop.HalfSecf()) + expectNilErr(t, c.CTickLoop.Secf()) + expectNilErr(t, c.CTickLoop.FifteenMinf()) + expectNilErr(t, c.CTickLoop.Hourf()) + expectNilErr(t, c.CTickLoop.Dayf()) } diff --git a/routes/panel/dashboard.go b/routes/panel/dashboard.go index d500bd66..69910ad5 100644 --- a/routes/panel/dashboard.go +++ b/routes/panel/dashboard.go @@ -265,6 +265,7 @@ func startDirSizeTask() { dstMuGuess = 0 dstMu.Unlock() }() + defer c.EatPanics() dDirSize, e := c.DirSize(".") if e != nil { c.LogWarning(e) diff --git a/tickloop.go b/tickloop.go index d496f917..2e70a84a 100644 --- a/tickloop.go +++ b/tickloop.go @@ -1,12 +1,15 @@ package main import ( + "bytes" "database/sql" "log" + "net/http/httptest" "strconv" "time" c "github.com/Azareal/Gosora/common" + "github.com/Azareal/Gosora/routes" "github.com/Azareal/Gosora/uutils" "github.com/pkg/errors" ) @@ -101,7 +104,10 @@ func tickLoop(thumbChan chan bool) error { return e } cn := uutils.Nanotime() - go func() { thumbChan <- true }() + go func() { + defer c.EatPanics() + thumbChan <- true + }() if e = c.Tasks.Sec.Run(); e != nil { return e @@ -152,12 +158,14 @@ func tickLoop(thumbChan chan bool) error { if e = c.Tasks.Hour.Run(); e != nil { return e } + if e = PingLastTopicTick(); e != nil { + return e + } handleLogLongTick("hour", cn, 5) return runHook("after_hour_tick") } - go tl.Loop() - + c.CTickLoop = tl return nil } @@ -211,3 +219,45 @@ func sched() error { return nil } + +// TODO: Move somewhere else +func PingLastTopicTick() error { + g, e := c.Groups.Get(c.GuestUser.Group) + if e != nil { + return e + } + tList, _, _, e := c.TopicList.GetListByGroup(g, 1, 0, nil) + if e != nil { + return e + } + if len(tList) == 0 { + return nil + } + w := httptest.NewRecorder() + sid := strconv.Itoa(tList[0].ID) + req := httptest.NewRequest("get", "/topic/"+sid, bytes.NewReader(nil)) + cn := uutils.Nanotime() + + // Deal with the session stuff, etc. + ucpy, ok := c.PreRoute(w, req) + if !ok { + return errors.New("preroute failed") + } + head, rerr := c.UserCheck(w, req, &ucpy) + if rerr != nil { + return errors.New(rerr.Error()) + } + rerr = routes.ViewTopic(w, req, &ucpy, head, sid) + if rerr != nil { + return errors.New(rerr.Error()) + } + /*if w.Code != 200 { + return errors.New("topic code not 200") + }*/ + + dur := time.Duration(uutils.Nanotime() - cn) + if dur.Seconds() > 5 { + c.Log("topic " + sid + " completed in " + dur.String()) + } + return nil +}