I've inherited code that was done by 2 other developers. It appears that a proof of concept website turned into production code so most all of the code is in main. It's a simple program in theory. The setup is a raspberry pi that controls sprinklers written in go that can set a schedule of turning on different zones. I've successfully encapsulated the relay controller into a package, now I want to encapsulate the schedule api. The part is a fairly straight forward CRUD operations.for simplicity I'll just post where I call it from main and the bare basics in the schedule_handler. so first:
main.go
func main() {
log.SetFlags(log.LstdFlags | log.LUTC)
log.SetOutput(&lumberjack.Logger{
Filename: "application.log",
MaxSize: 10, // megabytes
MaxBackups: 3,
MaxAge: 365, //days
LocalTime: false,
})
log.Printf("System Startup
")
parseTemplates()
loadConfig()
config.Eth0Addr = getIPv4ForInterfaceName("eth0")
saveConfig()
log.Printf("local ethernet address: %s
", config.Eth0Addr)
// gin.SetMode(gin.ReleaseMode)
gin.SetMode(gin.DebugMode)
r := gin.Default()
r.GET("/", mainGetHandler) // homepage
r.GET("/login", loginGetHandler)
r.POST("/login", loginPostHandler)
r.GET("/logout", authRequired(), logoutGetHandler)
scheduleRepository = nsScheduleRepository.Default("schedule.json")
parameters := nsScheduleApi.ScheduleHandlerParameters{
Engine: r,
Repository: scheduleRepository,
}
nsScheduleApi.Init(¶meters)
r.GET("/schedule", authRequired(), scheduleGetHandler)
http.Handle("/", r)
r.Static("/static/", "./static/")
config.URL = ""
// hack - wait 10 seconds for network to come up...
time.Sleep(10 * time.Second)
log.Println("Starting up on port 80")
log.Fatal(http.ListenAndServe(":80", r))
}
schedule/api/schedule_handler.go
package api
import (
"mysprinkler/schedule"
"github.com/gin-gonic/gin"
"log"
"strconv"
)
type ScheduleHandlerParameters struct {
Repository schedule.ScheduleRepository
Engine *gin.Engine
}
var parameters *ScheduleHandlerParameters
func getSchedules(c *gin.Context) {
repository := parameters.Repository
circuitnum, _ := strconv.ParseInt(c.Query("circuitnum"), 10, 64)
log.Printf("[ScheduleHandler] getting schedules %d", circuitnum)
var scheds = make([]*schedule.Schedule2, 0)
if circuitnum > 0 {
schedule := repository.Get(string(circuitnum))
if schedule == nil {
// c.AbortWithStatus(404)
log.Printf("[ScheduleHandler] Could not find schedule '%d' in db", circuitnum)
} else {
scheds = append(scheds, schedule)
}
} else {
scheds = repository.GetAll()
}
c.JSON(200, scheds)
}
func getSchedule(c *gin.Context) {
repository := parameters.Repository
id := c.Params.ByName("id")
log.Printf("[ScheduleHandler] getting schedule %s", id)
sched := repository.Get(id)
c.JSON(200, sched)
}
func createSchedule(c *gin.Context) {
repository := parameters.Repository
var sched schedule.Schedule2
err := c.BindJSON(&sched)
if err != nil {
log.Printf("[ScheduleHandler] Error creating schedule %s", err)
} else {
log.Printf("[ScheduleHandler] insert schedule for circuit %d", sched.CircuitNum)
}
err = repository.InsertOrUpdate(&sched)
if err != nil {
c.AbortWithError(500, err)
return
}
logSchedule(&sched, "created")
c.JSON(200, sched)
}
func updateSchedule(c *gin.Context) {
repository := parameters.Repository
id := c.Params.ByName("id")
log.Printf("[ScheduleHandler] updating schedule %s", id)
sched := repository.Get(id)
c.BindJSON(&sched)
err := repository.InsertOrUpdate(sched)
if err != nil {
c.AbortWithError(500, err)
return
}
logSchedule(sched, "updated")
c.JSON(200, sched)
}
func deleteSchedule(c *gin.Context) {
repository := parameters.Repository
id := c.Params.ByName("id")
log.Printf("[ScheduleHandler] deleting schedule %s", id)
err := repository.Delete(id)
if err != nil {
c.Error(err)
return
}
c.JSON(200, gin.H{"id #" + id: "deleted"})
}
func logSchedule(sched *schedule.Schedule2, action string) {
log.Printf("schedule: %s
", action)
log.Printf("*** id: %d
", sched.ID)
log.Printf("*** load: %d
", sched.CircuitNum+1)
log.Printf("*** on time: %s
", sched.OnTime)
log.Printf("*** off time: %s
", sched.OffTime)
log.Printf("*** enabled: %v", sched.Enabled)
log.Printf("*** sun: %v", sched.Sun)
log.Printf("*** mon: %v", sched.Mon)
log.Printf("*** tue: %v", sched.Tue)
log.Printf("*** wed: %v", sched.Wed)
log.Printf("*** thu: %v", sched.Thu)
log.Printf("*** fri: %v", sched.Fri)
log.Printf("*** sat: %v", sched.Sat)
}
// Init creates a handler for the schedule api
func Init(parameters *ScheduleHandlerParameters) {
parameters = parameters
r := parameters.Engine
r.GET("/schedule2", getSchedules)
r.GET("/schedule2/:id", getSchedule)
r.POST("/schedule2", createSchedule)
r.PUT("/schedule2/:id", updateSchedule)
r.DELETE("/schedule2/:id", deleteSchedule)
}
In the log I'm seeing
2018/05/20 12:14:36 System Startup
2018/05/20 12:14:36 local ethernet address: 10.0.0.7
2018/05/20 12:14:36 [GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
- using env: export GIN_MODE=release
- using code: gin.SetMode(gin.ReleaseMode)
2018/05/20 12:14:36 [GIN-debug] GET / --> main.mainGetHandler (3 handlers)
2018/05/20 12:14:36 [GIN-debug] GET /login --> main.loginGetHandler (3 handlers)
2018/05/20 12:14:36 [GIN-debug] POST /login --> main.loginPostHandler (3 handlers)
2018/05/20 12:14:36 [GIN-debug] GET /logout --> main.logoutGetHandler (4 handlers)
2018/05/20 12:14:36 [GIN-debug] GET /schedule2 --> sprinkler/schedule/api.getSchedules (3 handlers)
2018/05/20 12:14:36 [GIN-debug] GET /schedule2/:id --> sprinkler/schedule/api.getSchedule (3 handlers)
2018/05/20 12:14:36 [GIN-debug] POST /schedule2 --> sprinkler/schedule/api.createSchedule (3 handlers)
2018/05/20 12:14:36 [GIN-debug] PUT /schedule2/:id --> sprinkler/schedule/api.updateSchedule (3 handlers)
2018/05/20 12:14:36 [GIN-debug] DELETE /schedule2/:id --> sprinkler/schedule/api.deleteSchedule (3 handlers)
2018/05/20 12:14:36 [GIN-debug] GET /static/*filepath --> github.com/gin-gonic/gin.(*RouterGroup).createStaticHandler.func1 (3 handlers)
2018/05/20 12:14:36 [GIN-debug] HEAD /static/*filepath --> github.com/gin-gonic/gin.(*RouterGroup).createStaticHandler.func1 (3 handlers)
2018/05/20 12:14:46 Starting up on port 80
2018/05/20 12:15:15 admin logged in
but when I navigate to /schedule the template is loaded then immediatly i get two internal 500 errors (one for each call to /schedule2?circuitnum=1). Now this code worked before when it was all in main i just moved the methods into the schedule_api file then made an Init
and put that setup code into it. Having a C# background I'm lost as to why this broke. My first guess is that I'm losing a reference to my schedule handler when it drops out of scope of Main
but I don't understand why. Any ideas where I went wrong?