diff --git a/api.go b/api.go index 090a032088c9dc708a489a5b48f04f16797f8651..7b49833b3fd5651d38e62234d2333b98b139e0b2 100644 --- a/api.go +++ b/api.go @@ -45,13 +45,13 @@ func mountPath(mountName string) string { // Status of a mount on an individual Icecast server. type IcecastMountStatus struct { - Name string `xml:"name,attr"` - Listeners int `xml:"listeners"` - BitRate int `xml:"bitrate"` - Quality float32 `xml:"quality"` - VideoQuality float32 `xml:"video-quality"` - FrameSize string `xml:"frame-size"` - FrameRate float32 `xml:"frame-rate"` + Name string + Listeners int + BitRate int + Quality float64 + VideoQuality float64 + FrameSize string + FrameRate float64 } // Status of a node. This is used to report load and stream status. diff --git a/node/icecast.go b/node/icecast.go index 86a757af15d342bdcc5b7b0f8900a6aa28f23e3f..88aa0c85594fc324be51efbf70ef895f9ddee2f2 100644 --- a/node/icecast.go +++ b/node/icecast.go @@ -8,6 +8,7 @@ import ( "net/http" "os" "os/exec" + "strconv" "time" "git.autistici.org/ale/radioai" @@ -17,10 +18,30 @@ var ( statusPageUrl = "http://localhost:8000/status-radioai.xsl" ) +// Icecast returns empty fields in our status handler, which we'll +// need to turn into integers (the xml unmarshaler will return an +// error in this specific case), so we use a separate type for +// decoding the status page output. This would be much simpler if I +// knew how to get the XSLT to put a default value in the output +// instead of an empty field... +type icecastMountStatusUnparsed struct { + Name string `xml:"name,attr"` + Listeners string `xml:"listeners"` + BitRate string `xml:"bitrate"` + Quality string `xml:"quality"` + VideoQuality string `xml:"video-quality"` + FrameSize string `xml:"frame-size"` + FrameRate string `xml:"frame-rate"` +} + +type icecastStatusUnparsed struct { + XMLName xml.Name `xml:"status"` + Mounts []icecastMountStatusUnparsed `xml:"mount"` +} + type IcecastStatus struct { - XMLName xml.Name `xml:"status",json:"-"` - Mounts []radioai.IcecastMountStatus `xml:"mount"` - Up bool + Mounts []radioai.IcecastMountStatus + Up bool } type IcecastController struct { @@ -104,11 +125,42 @@ func (ic *IcecastController) fetchStatus() (*IcecastStatus, error) { } func (ic *IcecastController) parseStatusPage(input io.Reader) (*IcecastStatus, error) { - var status IcecastStatus - if err := xml.NewDecoder(input).Decode(&status); err != nil { + var ustatus icecastStatusUnparsed + if err := xml.NewDecoder(input).Decode(&ustatus); err != nil { return nil, err } - status.Up = true + + // Quick converters from string that default to 0. + toi := func(s string) int { + if i, err := strconv.Atoi(s); err == nil { + return i + } + return 0 + } + tof := func(s string) float64 { + if f, err := strconv.ParseFloat(s, 64); err == nil { + return f + } + return 0 + } + + status := IcecastStatus{ + Up: true, + Mounts: make([]radioai.IcecastMountStatus, 0, len(ustatus.Mounts)), + } + for _, um := range ustatus.Mounts { + m := radioai.IcecastMountStatus{ + Name: um.Name, + Listeners: toi(um.Listeners), + BitRate: toi(um.BitRate), + Quality: tof(um.Quality), + VideoQuality: tof(um.VideoQuality), + FrameSize: um.FrameSize, + FrameRate: tof(um.FrameRate), + } + status.Mounts = append(status.Mounts, m) + } + return &status, nil }