diff --git a/api.go b/api.go index 68b8596ac47c39ec5f154b99ba71f616a1299517..57372bdc3ee8cd58cd806549e2fcf39724a67068 100644 --- a/api.go +++ b/api.go @@ -7,6 +7,7 @@ import ( "encoding/json" "errors" "fmt" + "hash/crc32" "net" "strings" "time" @@ -403,3 +404,9 @@ func GeneratePassword() string { rand.Read(b) return base64.StdEncoding.EncodeToString(b) } + +// GenerateUsername returns a username somehow related to the name of +// the mount, possibly unique (but not actually guaranteed to be so). +func GenerateUsername(path string) string { + return fmt.Sprintf("source%d", crc32.ChecksumIEEE([]byte(path))) +} diff --git a/cmd/radioctl/radioctl.go b/cmd/radioctl/radioctl.go index a30a16d3e01b60080becc980c2f6a1f5c041389b..2ec35a829554ae2bf33d0a406273f97ed15f33df 100644 --- a/cmd/radioctl/radioctl.go +++ b/cmd/radioctl/radioctl.go @@ -4,7 +4,6 @@ import ( "encoding/json" "flag" "fmt" - "hash/crc32" "log" "net/url" "os" @@ -140,14 +139,10 @@ func getClient() *autoradio.Client { return autoradio.NewClient(autoradio.NewEtcdClient(false)) } -func generateUsername(path string) string { - return fmt.Sprintf("source%d", crc32.ChecksumIEEE([]byte(path))) -} - func setRelay(m *autoradio.Mount, relayUrl string) { if relayUrl == "" { // Randomly generate source credentials. - m.Username = generateUsername(m.Name) + m.Username = autoradio.GenerateUsername(m.Name) m.Password = autoradio.GeneratePassword() } else { // Validate the given relay URL. diff --git a/debug.go b/debug.go new file mode 100644 index 0000000000000000000000000000000000000000..13fe66df5f2077e022846e83446ef35388222c86 --- /dev/null +++ b/debug.go @@ -0,0 +1,73 @@ +package autoradio + +import "sort" + +// MountStatus reports the configuration and status of a mount, +// including eventual transcoded mounts that source it. +type MountStatus struct { + Mount *Mount + Listeners int + TransMounts []*MountStatus +} + +func newMountStatus(m *Mount, nodes []*NodeStatus) *MountStatus { + var listeners int + for _, n := range nodes { + for _, ims := range n.Mounts { + if ims.Name == m.Name { + listeners += ims.Listeners + break + } + } + } + return &MountStatus{ + Mount: m, + Listeners: listeners, + } +} + +type mountStatusList []*MountStatus + +func (l mountStatusList) Len() int { return len(l) } +func (l mountStatusList) Swap(i, j int) { l[i], l[j] = l[j], l[i] } +func (l mountStatusList) Less(i, j int) bool { + return l[i].Mount.Name < l[j].Mount.Name +} + +// MountsToStatus converts a list of mounts (and eventually the +// current list of nodes) to a nicely sorted and tree-aggregated list +// of MountStatus objects. The list of nodes can be nil, in which case +// listener statistics will be omitted. +func MountsToStatus(mounts []*Mount, nodes []*NodeStatus) []*MountStatus { + // Aggregate stats, and create a tree of transcoding mounts. + ms := make(map[string]*MountStatus) + for _, m := range mounts { + if m.HasTranscoder() { + continue + } + ms[m.Name] = newMountStatus(m, nodes) + } + for _, m := range mounts { + if !m.HasTranscoder() { + continue + } + src := ms[m.Transcoding.SourceName] + if src == nil { + continue + } + src.TransMounts = append(src.TransMounts, newMountStatus(m, nodes)) + } + msl := make([]*MountStatus, 0, len(ms)) + for _, m := range ms { + msl = append(msl, m) + } + + // Sort everything (including transcoded mounts). + sort.Sort(mountStatusList(msl)) + for _, s := range msl { + if s.TransMounts != nil { + sort.Sort(mountStatusList(s.TransMounts)) + } + } + return msl +} diff --git a/fe/http.go b/fe/http.go index 596f1482e09a95de54a2a96694d5be226c662773..a37a4fe9bad6475b0ac623fadc643d536e430e93 100644 --- a/fe/http.go +++ b/fe/http.go @@ -11,7 +11,6 @@ import ( "net/http" "net/url" "path/filepath" - "sort" "strconv" "strings" "time" @@ -266,76 +265,16 @@ func (h *HTTPRedirector) serveSource(mount *autoradio.Mount, w http.ResponseWrit proxy.ServeHTTP(w, r) } -type mountStatus struct { - Mount *autoradio.Mount - Listeners int - TransMounts []*mountStatus -} - -func newMountStatus(m *autoradio.Mount, nodes []*autoradio.NodeStatus) *mountStatus { - var listeners int - for _, n := range nodes { - for _, ims := range n.Mounts { - if ims.Name == m.Name { - listeners += ims.Listeners - break - } - } - } - return &mountStatus{ - Mount: m, - Listeners: listeners, - } -} - -type mountStatusList []*mountStatus - -func (l mountStatusList) Len() int { return len(l) } -func (l mountStatusList) Swap(i, j int) { l[i], l[j] = l[j], l[i] } -func (l mountStatusList) Less(i, j int) bool { - return l[i].Mount.Name < l[j].Mount.Name -} - // Serve our cluster status page. func (h *HTTPRedirector) serveStatusPage(w http.ResponseWriter, r *http.Request) { nodes, _ := h.client.GetNodes() mounts, _ := h.client.ListMounts() - // Aggregate stats, and create a tree of transcoding mounts. - ms := make(map[string]*mountStatus) - for _, m := range mounts { - if m.HasTranscoder() { - continue - } - ms[m.Name] = newMountStatus(m, nodes) - } - for _, m := range mounts { - if !m.HasTranscoder() { - continue - } - src := ms[m.Transcoding.SourceName] - if src == nil { - continue - } - src.TransMounts = append(src.TransMounts, newMountStatus(m, nodes)) - } - msl := make([]*mountStatus, 0, len(ms)) - for _, m := range ms { - msl = append(msl, m) - } - - // Sort everything. - sort.Sort(mountStatusList(msl)) - for _, s := range msl { - if s.TransMounts != nil { - sort.Sort(mountStatusList(s.TransMounts)) - } - } - + msl := autoradio.MountsToStatus(mounts, nodes) ctx := struct { Domain string Nodes []*autoradio.NodeStatus - Mounts []*mountStatus + Mounts []*autoradio.MountStatus }{h.domain, nodes, msl} var buf bytes.Buffer diff --git a/node/bwmonitor/bwmonitor.go b/node/bwmonitor/bwmonitor.go index baeeaff980522b685be131ba0db9632283e582cc..25f915be549ca7eb0e812e862a773fc024623ba9 100644 --- a/node/bwmonitor/bwmonitor.go +++ b/node/bwmonitor/bwmonitor.go @@ -68,9 +68,8 @@ func (bw *BandwidthMonitor) Run(stop chan bool) { t := time.NewTicker(bw.period) for { select { - case <-t.C: + case now := <-t.C: if c, err := getBytesSentForDevice(bw.device); err == nil { - now := time.Now() bw.lock.Lock() bw.rate = float64(c-bw.counter) / now.Sub(bw.stamp).Seconds() bw.counter = c