izapple2/fujinet/json.go

117 lines
2.3 KiB
Go

package fujinet
import (
"encoding/json"
"strconv"
"strings"
)
/*
See:
https://github.com/FujiNetWIFI/fujinet-platformio/tree/master/lib/fnjson
https://github.com/FujiNetWIFI/fujinet-platformio/wiki/JSON-Query-Format
*/
type FnJson struct {
data any
Result []uint8
}
func NewFnJson() *FnJson {
var js FnJson
return &js
}
func (js *FnJson) Parse(data []uint8) ErrorCode {
// See FNJSON::parse()
err := json.Unmarshal(data, &js.data)
if err != nil {
return NetworkErrorJsonParseError
}
return NoError
}
func (js *FnJson) Query(query []uint8) {
// See FNJSON::setReadQuery
// See https://github.com/kbranigan/cJSON/blob/master/cJSON_Utils.c
if query[len(query)-1] == 0 {
query = query[0 : len(query)-1]
}
queryString := string(query)
queryString = strings.TrimSuffix(queryString, "/0")
queryString = strings.TrimPrefix(queryString, "/")
queryString = strings.TrimSuffix(queryString, "/")
path := strings.Split(queryString, "/")
js.Result = getJsonValue(nil)
current := js.data
for i := 0; i < len(path); i++ {
switch v := current.(type) {
case map[string]any:
var found bool
current, found = v[path[i]]
if !found {
// Not found
return
}
case []any:
index, err := strconv.Atoi(path[i])
if err != nil {
// Path for arrays should be an int
return
}
if index < 0 || index >= len(v) {
// Index out of bounds
return
}
current = v[index]
default:
// It's a leaf. We can't go down
return
}
}
js.Result = getJsonValue(current)
}
func getJsonValue(data any) []uint8 {
// See FNJson::getValue
if data == nil {
return []uint8("NULL")
}
switch v := data.(type) {
case bool:
if v {
return []uint8("TRUE")
} else {
return []uint8("FALSE")
}
case float64:
//if math.Floor(v) == v { // As done in FNJSON__getValue()
// It's an integer
return []uint8(strconv.Itoa(int(v)))
//} else {
// return []uint8(fmt.Sprintf("%.10f", v))
//}
case string:
return []uint8(v)
case []any:
s := make([]uint8, 0)
for i := 0; i < len(v); i++ {
s = append(s, getJsonValue(v[i])...)
}
return s
case map[string]any:
s := make([]uint8, 0)
for k, e := range v {
s = append(s, []uint8(k)...)
s = append(s, getJsonValue(e)...)
}
return s
default:
// Should not be possible for an object unmarshalled from a JSON
return []uint8("UNKNOWN")
}
}