package http import ( "errors" "net/http" "strconv" "strings" ccc "th7/config" "th7/data/config" "github.com/gin-gonic/gin" ) var ( ErrConfigChannelNotFound = errors.New("a configured channel with this ID was not found") ErrConfigRestrictedDB = errors.New("access to the DB map is restricted") ) func (g *GinAdapter) getConfigByID(id int) (config.Channel, error) { for channel := range g.cfg.Channels { if g.cfg.Channels[channel].Id == id { return g.cfg.Channels[channel], nil } } return config.Channel{}, ErrConfigChannelNotFound } // check if a supplied key string is in the device struct (TH7) func configDeviceIsValidKey(key string) bool { deviceKeys := []string{ "debug", "nolog", "noweb", "led", } key = strings.ToLower(key) for k := range deviceKeys { if key == deviceKeys[k] { return true } } return false } func configDeviceIsValidValue(key string, value string) bool { // all the values are bools for now value = strings.ToLower(value) return (value == "true" || value == "false") } // this doesn't actually do anything to program state... yet func (g *GinAdapter) updateConfigDevice(key string, value string) error { bValue, err := strconv.ParseBool(value) if err != nil { return err } key = strings.ToLower(key) // might have to sync these writes ? // go doesn't have switch case fall-thru switch key { case "led": g.cfg.Board.Led = bValue case "nolog": g.cfg.Board.NoLog = bValue case "noweb": g.cfg.Board.NoWeb = bValue case "debug": g.cfg.Board.Debug = bValue } return nil } func (g *GinAdapter) validConfigChannel(id int) bool { for c := range g.cfg.Channels { if g.cfg.Channels[c].Id == id { return true } } return false } func configChannelIsValidKey(key string) bool { // will add more later channelKeys := []string{ "thermocouple", "gain", "offset", } key = strings.ToLower(key) for k := range channelKeys { if key == channelKeys[k] { return true } } return false } func (g *GinAdapter) configChannelUpdateValue(id int, key string, value string) error { key = strings.ToLower(key) value = strings.ToLower(value) var cfgChannelPtr *config.Channel foundChannel := false // find the channel, given and checked by id for k := range g.cfg.Channels { if g.cfg.Channels[k].Id == id { cfgChannelPtr = &(g.cfg.Channels[k]) foundChannel = true } } if !foundChannel { return ErrConfigChannelNotFound } switch key { case "thermocouple": tc, err := ccc.GetThermocoupleType(value) if err != nil { return err } cfgChannelPtr.Thermo = tc case "gain": fValue, err := strconv.ParseFloat(value, 64) if err != nil { return err } cfgChannelPtr.Gain = fValue case "offset": fValue, err := strconv.ParseFloat(value, 64) if err != nil { return err } cfgChannelPtr.Offset = fValue } return nil } /*************************************************************************/ /*************************************************************************/ /*************************************************************************/ func (g *GinAdapter) GetConfigChannelByIdHandler(c *gin.Context) { var timestamp string id, err := strconv.Atoi(c.Param("id")) if err != nil { c.JSON(http.StatusBadRequest, gin.H{ "error": err, }) return } channel, err := g.getConfigByID(id) if err != nil { c.JSON(http.StatusBadRequest, gin.H{ "error": err, }) return } timestamp = g.getTimestamp() c.JSON(http.StatusOK, gin.H{ "channel": channel, "time": timestamp, }) } func (g *GinAdapter) GetConfigChannelsHandler(c *gin.Context) { timestamp := g.getTimestamp() c.JSON(http.StatusOK, gin.H{ "channels": g.cfg.Channels, "time": timestamp, }) } func (g *GinAdapter) GetConfigDeviceHandler(c *gin.Context) { timestamp := g.getTimestamp() c.JSON(http.StatusOK, gin.H{ "channels": g.cfg.Board, "time": timestamp, }) } func (g *GinAdapter) GetConfigDBHandler(c *gin.Context) { var timestamp string if g.cfg.API[0].Restricted { c.JSON(http.StatusForbidden, gin.H{ "error": ErrConfigRestrictedDB, }) return } timestamp = g.getTimestamp() c.JSON(http.StatusOK, gin.H{ // "db": g.getConfigDB(), "db": g.cfg.DB, "time": timestamp, }) } func (g *GinAdapter) SetConfigDeviceHandler(c *gin.Context) { var req PostRequest if err := c.ShouldBind(&req); err != nil { c.String(http.StatusBadRequest, err.Error()) return } validKey := configDeviceIsValidKey(req.Key) if !validKey { c.String(http.StatusBadRequest, "invalid device config key") return } validValue := configDeviceIsValidValue(req.Key, req.Value) if !validValue { c.String(http.StatusBadRequest, "invalid device config value") return } err := g.updateConfigDevice(req.Key, req.Value) if err != nil { c.String(http.StatusBadRequest, err.Error()) return } c.String(http.StatusOK, "OK") } // this function can only modify already set up channels, for now. func (g *GinAdapter) SetConfigChannelByIdHandler(c *gin.Context) { var req PostRequest id, err := strconv.Atoi(c.Param("id")) if err != nil { c.String(http.StatusBadRequest, err.Error()) return } validChannel := g.validConfigChannel(id) if !validChannel { c.String(http.StatusBadRequest, "channel not initially configured. TODO fix") return } if err := c.ShouldBind(&req); err != nil { c.String(http.StatusBadRequest, err.Error()) return } validKey := configChannelIsValidKey(req.Key) if !validKey { c.String(http.StatusBadRequest, "invalid channel config key") return } err = g.configChannelUpdateValue(id, req.Key, req.Value) if err != nil { c.String(http.StatusBadRequest, err.Error()) return } c.String(http.StatusOK, "OK") } func (g *GinAdapter) SetConfigDBHandler(c *gin.Context) { var req PostRequest if g.cfg.API[0].Restricted { c.String(http.StatusForbidden, ErrConfigRestrictedDB.Error()) return } if err := c.ShouldBind(&req); err != nil { c.String(http.StatusBadRequest, err.Error()) return } // what could go wrong? g.cfg.DB[req.Key] = req.Value c.String(http.StatusOK, "OK") }