From 7729bbcf3909b8404a34369f8be435d58242ca67 Mon Sep 17 00:00:00 2001
From: ale <ale@incal.net>
Date: Sat, 18 Oct 2014 09:07:41 +0100
Subject: [PATCH] kill sources on local icecast upon reload

This is an attempt to fix a problem where sources would become stuck
on master -> slave state transitions.
---
 node/icecast.go | 39 ++++++++++++++++++++++++++++++++++++---
 1 file changed, 36 insertions(+), 3 deletions(-)

diff --git a/node/icecast.go b/node/icecast.go
index 403a9219..ac490f8e 100644
--- a/node/icecast.go
+++ b/node/icecast.go
@@ -73,24 +73,57 @@ func (ic *IcecastController) reload() error {
 	return cmd.Run()
 }
 
+// Kill sources connected to local streams.
+func (ic *IcecastController) killSources(conf *ClusterConfig) error {
+	var anyErr error
+	client := &http.Client{}
+	for _, m := range conf.ListMounts() {
+		req, err := http.NewRequest("GET", fmt.Sprintf("http://localhost:%d/admin/killsource?mount=%s", autoradio.IcecastPort, autoradio.MountNameToIcecastPath(m.Name)), nil)
+		if err != nil {
+			anyErr = err
+			continue
+		}
+		req.SetBasicAuth("admin", getIcecastAdminPassword())
+		resp, err := client.Do(req)
+		if err != nil {
+			anyErr = err
+			continue
+		}
+		resp.Body.Close()
+		if resp.StatusCode != 200 {
+			anyErr = fmt.Errorf("HTTP status %s", resp.Status)
+		}
+	}
+	return anyErr
+}
+
 // Update reloads the Icecast daemon with a new configuration.
 func (ic *IcecastController) Update(conf *ClusterConfig, isMaster bool, masterAddr string) error {
 	if !isMaster && masterAddr == "" {
 		return errors.New("unknown system state")
 	}
 
-	tmpf := icecastConfigFile + ".tmp"
-	defer os.Remove(tmpf)
+	// Try to kill sources connected to the local icecast daemon
+	// before reloading, otherwise we'll have problems on master
+	// -> slave transitions (for example, on a restart of radiod)
+	// as sources will be "stuck" preventing the new configuration
+	// from taking effect.
+	if err := ic.killSources(conf); err != nil {
+		log.Printf("error killing sources: %v", err)
+	}
 
+	// Write a new configuration (atomically).
 	ic.config.Update(conf, isMaster, masterAddr)
+	tmpf := icecastConfigFile + ".tmp"
+	defer os.Remove(tmpf)
 	if err := ic.config.EncodeToFile(tmpf); err != nil {
 		return err
 	}
-
 	if err := os.Rename(tmpf, icecastConfigFile); err != nil {
 		return err
 	}
 
+	// Tell the Icecast daemon to reload its configuration.
 	return ic.reload()
 }
 
-- 
GitLab