Reputation: 2409
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\n")
parseTemplates()
loadConfig()
config.Eth0Addr = getIPv4ForInterfaceName("eth0")
saveConfig()
log.Printf("local ethernet address: %s\n", 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\n", action)
log.Printf("*** id: %d\n", sched.ID)
log.Printf("*** load: %d\n", sched.CircuitNum+1)
log.Printf("*** on time: %s\n", sched.OnTime)
log.Printf("*** off time: %s\n", 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?
Upvotes: 0
Views: 389
Reputation: 1740
Exactly! When you are doing this:
func Init(parameters *ScheduleHandlerParameters) {
parameters = parameters
// ....
}
parameters
becomes a local variable to this function and next line is just assigning it to itself. And global variable parameters
still holds nil
value, was never changed. Which caused error!
Changing function param to something like this should work fine:
func Init(shPrms *ScheduleHandlerParameters) {
parameters = shPrms
// ....
}
Upvotes: 1