From 84cba4d3403c2eb6fb74b9c7961257b472518572 Mon Sep 17 00:00:00 2001 From: Brian Buller Date: Tue, 23 Jan 2018 14:55:52 -0600 Subject: [PATCH] Running out of memory now Save to DB happens on timed interval and on shutdown --- admin_games.go | 63 +++++++++++++++++++++++++++++++-------------- main.go | 23 +++++++++++++++++ model.go | 32 +++++++++++++---------- model_games.go | 3 ++- model_votes.go | 18 ++++++++----- public_endpoints.go | 20 ++++++++++++-- 6 files changed, 116 insertions(+), 43 deletions(-) diff --git a/admin_games.go b/admin_games.go index c9729ef..2485333 100644 --- a/admin_games.go +++ b/admin_games.go @@ -20,13 +20,7 @@ func handleAdminGames(w http.ResponseWriter, req *http.Request, page *pageData) teamId := vars["id"] if teamId == "" { // Games List - // TODO: We should be able to just pass m.jam to the template instead of a custom struct - type gamesPageData struct { - Teams []Team - } - gpd := new(gamesPageData) - gpd.Teams = m.jam.Teams - page.TemplateData = gpd + page.TemplateData = m.jam page.SubTitle = "Games" page.show("admin-games.html", w) } else { @@ -48,22 +42,50 @@ func handleAdminGames(w http.ResponseWriter, req *http.Request, page *pageData) page.session.setFlashMessage("Team game updated", "success") } redirect("/admin/teams/"+tm.UUID+"#game", w, req) + case "screenshotupload": - if err := saveScreenshots(tm, req); err != nil { + var ss *Screenshot + tm, err := m.jam.GetTeamById(tm.UUID) + if err != nil { page.session.setFlashMessage("Error updating game: "+err.Error(), "error") + redirect("/admin/teams/"+tm.UUID+"#game", w, req) + } + ss, err = ssFromRequest(tm, req) + if err != nil { + page.session.setFlashMessage("Error updating game: "+err.Error(), "error") + redirect("/admin/teams/"+tm.UUID+"#game", w, req) + } + gm := tm.Game + gm.Screenshots = append(gm.Screenshots, *ss) + if err = m.jam.UpdateGame(tm.UUID, gm); err != nil { + page.session.setFlashMessage("Error updating game: "+err.Error(), "error") + } else { + page.session.setFlashMessage("Screenshot Uploaded", "success") } redirect("/admin/teams/"+tm.UUID+"#game", w, req) + case "screenshotdelete": - var ss *Screenshot var err error ssid := vars["subid"] - if ss, err = NewScreenshot(tm.UUID, ssid); err != nil { - page.session.setFlashMessage("Error deleting screenshot: "+err.Error(), "error") + tm, err := m.jam.GetTeamById(tm.UUID) + if err != nil { + page.session.setFlashMessage("Error updating game: "+err.Error(), "error") + redirect("/admin/teams/"+tm.UUID+"#game", w, req) + break } - if err = m.jam.DeleteScreenshot(ss); err != nil { - page.session.setFlashMessage("Error deleting screenshot: "+err.Error(), "error") + gm := tm.Game + if err = gm.RemoveScreenshot(ssid); err != nil { + page.session.setFlashMessage("Error updating game: "+err.Error(), "error") + redirect("/admin/teams/"+tm.UUID+"#game", w, req) + break + } + if err = m.jam.UpdateGame(tm.UUID, gm); err != nil { + page.session.setFlashMessage("Error updating game: "+err.Error(), "error") + } else { + page.session.setFlashMessage("Screenshot Removed", "success") } redirect("/admin/teams/"+tm.UUID+"#game", w, req) + } } else { page.session.setFlashMessage("Not a valid team id", "error") @@ -72,13 +94,13 @@ func handleAdminGames(w http.ResponseWriter, req *http.Request, page *pageData) } } -func saveScreenshots(tm *Team, req *http.Request) error { +func ssFromRequest(tm *Team, req *http.Request) (*Screenshot, error) { var err error var ss *Screenshot file, hdr, err := req.FormFile("newssfile") if err != nil { - return err + return nil, err } extIdx := strings.LastIndex(hdr.Filename, ".") fltp := "png" @@ -89,29 +111,30 @@ func saveScreenshots(tm *Team, req *http.Request) error { buf := new(bytes.Buffer) // We convert everything to jpg if err = jpeg.Encode(buf, mI, nil); err != nil { - return errors.New("Unable to encode image") + return nil, errors.New("Unable to encode image") } thm := resize.Resize(200, 0, mI, resize.Lanczos3) thmBuf := new(bytes.Buffer) var thmString string if fltp == "gif" { if err = gif.Encode(thmBuf, thm, nil); err != nil { - return errors.New("Unable to encode image") + return nil, errors.New("Unable to encode image") } } else { if err = jpeg.Encode(thmBuf, thm, nil); err != nil { - return errors.New("Unable to encode image") + return nil, errors.New("Unable to encode image") } } thmString = base64.StdEncoding.EncodeToString(thmBuf.Bytes()) if ss, err = NewScreenshot(tm.UUID, ""); err != nil { - return err + return nil, err } ss.Image = base64.StdEncoding.EncodeToString(buf.Bytes()) ss.Thumbnail = thmString ss.Filetype = fltp - return m.jam.SaveScreenshot(ss) + return ss, nil + //return m.jam.SaveScreenshot(ss) } diff --git a/main.go b/main.go index 584da71..3cc889d 100644 --- a/main.go +++ b/main.go @@ -9,8 +9,11 @@ import ( "log" "net/http" "os" + "os/signal" "strconv" "strings" + "syscall" + "time" "golang.org/x/crypto/ssh/terminal" @@ -71,6 +74,15 @@ func main() { if err = m.site.SaveToDB(); err != nil { errorExit("Unable to save site config to DB: " + err.Error()) } + + // Save changes to the DB every 5 minutes + go func() { + for { + m.saveChanges() + time.Sleep(5 * time.Minute) + } + }() + initialize() r = mux.NewRouter() @@ -108,6 +120,17 @@ func main() { chain := alice.New(loggingHandler).Then(r) + // Set up a channel to intercept Ctrl+C for graceful shutdowns + c := make(chan os.Signal, 1) + signal.Notify(c, os.Interrupt, syscall.SIGTERM) + go func() { + <-c + // Save the changes when the app quits + fmt.Println("\nFinishing up...") + m.saveChanges() + os.Exit(0) + }() + fmt.Printf("Listening on port %d\n", m.site.Port) log.Fatal(http.ListenAndServe("127.0.0.1:"+strconv.Itoa(m.site.Port), chain)) } diff --git a/model.go b/model.go index 8f02588..88606d8 100644 --- a/model.go +++ b/model.go @@ -2,6 +2,7 @@ package main import ( "errors" + "fmt" "github.com/br0xen/boltease" ) @@ -114,22 +115,25 @@ func (m *model) saveChanges() error { } defer m.closeDB() - if m.site.NeedsSave() { - if err = m.site.SaveToDB(); err != nil { - return err - } + //if m.site.NeedsSave() { + fmt.Println("Saving Site data to DB") + if err = m.site.SaveToDB(); err != nil { + return err } - if m.jam.IsChanged { - if err = m.jam.SaveToDB(); err != nil { - return err - } - m.jam.IsChanged = false + //} + //if m.jam.IsChanged { + fmt.Println("Saving Jam data to DB") + if err = m.jam.SaveToDB(); err != nil { + return err } - if m.clientsUpdated { - if err = m.SaveAllClients(); err != nil { - return err - } - m.clientsUpdated = false + m.jam.IsChanged = false + //} + //if m.clientsUpdated { + fmt.Println("Saving Client data to DB") + if err = m.SaveAllClients(); err != nil { + return err } + m.clientsUpdated = false + //} return nil } diff --git a/model_games.go b/model_games.go index 788b3b3..888b5de 100644 --- a/model_games.go +++ b/model_games.go @@ -2,6 +2,7 @@ package main import ( "errors" + "fmt" "github.com/pborman/uuid" ) @@ -45,12 +46,12 @@ func (gm *Game) RemoveScreenshot(ssId string) error { for i, ss := range gm.Screenshots { if ss.UUID == ssId { idx = i - return nil } } if idx < 0 { return errors.New("Invalid Id") } + fmt.Print("Removing Screenshot (", ssId, ") (IDX:", idx, ")\n") gm.Screenshots = append(gm.Screenshots[:idx], gm.Screenshots[idx+1:]...) return nil } diff --git a/model_votes.go b/model_votes.go index 644040a..677036c 100644 --- a/model_votes.go +++ b/model_votes.go @@ -2,6 +2,7 @@ package main import ( "errors" + "fmt" "strconv" "time" ) @@ -30,7 +31,10 @@ func NewVote(clId string, tm time.Time) (*Vote, error) { } vt := new(Vote) + + vt.Timestamp = tm vt.mPath = []string{"jam", "votes", clId, tm.Format(time.RFC3339)} + return vt, nil } @@ -52,9 +56,9 @@ func (gj *Gamejam) GetVoteWithTimeString(clId, ts string) (*Vote, error) { } func (gj *Gamejam) GetVote(clId string, ts time.Time) (*Vote, error) { - for _, v := range gj.Votes { - if v.ClientId == clId && v.Timestamp == ts { - return &v, nil + for i := range gj.Votes { + if gj.Votes[i].ClientId == clId && gj.Votes[i].Timestamp == ts { + return &gj.Votes[i], nil } } return nil, errors.New("Couldn't find requested vote") @@ -96,6 +100,7 @@ func (gj *Gamejam) LoadAllVotes() []Vote { continue } for _, t := range times { + fmt.Println("Loading Vote", cId, t) if vt, err := gj.LoadVote(cId, t); err == nil { ret = append(ret, *vt) } @@ -116,7 +121,7 @@ func (gj *Gamejam) LoadVote(clientId, t string) (*Vote, error) { return nil, errors.New("Error creating vote: " + err.Error()) } var choices []string - if choices, err = m.bolt.GetKeyList(vt.mPath); err != nil { + if choices, err = gj.m.bolt.GetKeyList(vt.mPath); err != nil { return nil, errors.New("Error creating vote: " + err.Error()) } for _, v := range choices { @@ -124,8 +129,9 @@ func (gj *Gamejam) LoadVote(clientId, t string) (*Vote, error) { var rank int if rank, err = strconv.Atoi(v); err == nil { ch.Rank = rank - ch.Team, _ = m.bolt.GetValue(vt.mPath, v) - vt.Choices = append(vt.Choices, *ch) + if ch.Team, err = gj.m.bolt.GetValue(vt.mPath, v); err == nil { + vt.Choices = append(vt.Choices, *ch) + } } } return vt, nil diff --git a/public_endpoints.go b/public_endpoints.go index e4a8131..52f98e1 100644 --- a/public_endpoints.go +++ b/public_endpoints.go @@ -38,7 +38,8 @@ func loadVotingPage(w http.ResponseWriter, req *http.Request) { Timestamp string } vpd := new(votingPageData) - tms := m.jam.Teams + tms := make([]Team, len(m.jam.Teams)) + copy(tms, m.jam.Teams) // Randomize the team list rand.Seed(time.Now().Unix()) @@ -173,6 +174,7 @@ func handleTeamMgmtRequest(w http.ResponseWriter, req *http.Request) { page.SubTitle = "Team Management" page.TemplateData = tm page.show("public-teammgmt.html", w) + case "savemember": m, err := NewTeamMember(tm.UUID, "") if err != nil { @@ -189,6 +191,7 @@ func handleTeamMgmtRequest(w http.ResponseWriter, req *http.Request) { page.session.setFlashMessage(m.Name+" added to team!", "success") } redirect("/team/"+tm.UUID+"#members", w, req) + case "deletemember": mbrId := req.FormValue("memberid") err := tm.RemoveTeamMemberById(mbrId) @@ -198,23 +201,36 @@ func handleTeamMgmtRequest(w http.ResponseWriter, req *http.Request) { page.session.setFlashMessage("Team member removed", "success") } redirect("/team/"+tm.UUID, w, req) + case "savegame": tm.Game.Name = req.FormValue("gamename") tm.Game.Link = req.FormValue("gamelink") tm.Game.Description = req.FormValue("gamedesc") page.session.setFlashMessage("Team game updated", "success") redirect("/team/"+tm.UUID, w, req) + case "screenshotupload": - if err := saveScreenshots(tm, req); err != nil { + ss, err := ssFromRequest(tm, req) + if err != nil { page.session.setFlashMessage("Error updating game: "+err.Error(), "error") + redirect("/team/"+tm.UUID, w, req) + } + gm := tm.Game + gm.Screenshots = append(gm.Screenshots, *ss) + if err = m.jam.UpdateGame(tm.UUID, gm); err != nil { + page.session.setFlashMessage("Error updating game: "+err.Error(), "error") + } else { + page.session.setFlashMessage("Screenshot Uploaded", "success") } redirect("/team/"+tm.UUID, w, req) + case "screenshotdelete": ssid := vars["subid"] if err := tm.Game.RemoveScreenshot(ssid); err != nil { page.session.setFlashMessage("Error deleting screenshot: "+err.Error(), "error") } redirect("/team/"+tm.UUID, w, req) + } } else { http.Error(w, "Page Not Found", 404)