dtas-all
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH 2/2] player: add "state dump" command to serialize state


From: Eric Wong
Subject: [PATCH 2/2] player: add "state dump" command to serialize state
Date: Sun, 1 Sep 2013 02:13:14 +0000

This helps in case dtas-player is hit with SIGKILL or the system
crashes.  This does not fsync(2) as that could introduce delays on
slow filesystems.  Users should open the file manually and fsync
themselves if they need to.
---
 Documentation/dtas-player_protocol.txt |  8 ++++++++
 lib/dtas/player.rb                     |  2 ++
 lib/dtas/player/client_handler.rb      | 21 +++++++++++++++++++++
 lib/dtas/state_file.rb                 |  2 ++
 test/test_player_integration.rb        | 18 ++++++++++++++++++
 5 files changed, 51 insertions(+)

diff --git a/Documentation/dtas-player_protocol.txt 
b/Documentation/dtas-player_protocol.txt
index efbd065..b431180 100644
--- a/Documentation/dtas-player_protocol.txt
+++ b/Documentation/dtas-player_protocol.txt
@@ -203,6 +203,14 @@ Commands here should be alphabetized according to 
`LC_ALL=C sort'
         1. input type (flac/opus/mp3/etc)
         2. transport protocol (local FS/http/ftp/sftp/etc)
 
+* state dump [FILENAME]
+  Immediately dump the state of the player.  If a FILENAME is specified,
+  the state is written to that file.  Otherwise, the default state file
+  (configured via DTAS_PLAYER_STATE environment variable, defaulting
+  to ~/.dtas/player_state.yml) is written to.  This does not use fsync(2),
+  users requiring fsync should open(2) that file and fsync(2) it
+  themselves if necessary.
+
 * watch - adds the client to the passive watch list for notifications.
   It is recommended clients issue no further commands and open
   another client socket to issue non-watch commands.
diff --git a/lib/dtas/player.rb b/lib/dtas/player.rb
index ba42490..3571a7f 100644
--- a/lib/dtas/player.rb
+++ b/lib/dtas/player.rb
@@ -212,6 +212,8 @@ class DTAS::Player # :nodoc:
       io.emit("OK")
     when "source"
       source_handler(io, msg)
+    when "state"
+      state_file_handler(io, msg)
     when "cd"
       chdir_handler(io, msg)
     when "pwd"
diff --git a/lib/dtas/player/client_handler.rb 
b/lib/dtas/player/client_handler.rb
index f601d46..bbdc1c5 100644
--- a/lib/dtas/player/client_handler.rb
+++ b/lib/dtas/player/client_handler.rb
@@ -479,5 +479,26 @@ module DTAS::Player::ClientHandler # :nodoc:
     # echo(%W(cd msg[0])) # should we broadcast this?
     io.emit("OK")
   end
+
+  def state_file_handler(io, msg)
+    case msg.shift
+    when "dump"
+      dest = msg.shift
+      if dest
+        sf = DTAS::StateFile.new(dest, false)
+      elsif @state_file
+        sf = @state_file
+        dest = sf.path
+      else
+        return io.emit("ERR no state file configured")
+      end
+      begin
+        sf.dump(self)
+      rescue => e
+        return io.emit("ERR dumping to #{xs(Array(dest))} #{e.message}")
+      end
+    end
+    io.emit("OK")
+  end
 end
 # :startdoc:
diff --git a/lib/dtas/state_file.rb b/lib/dtas/state_file.rb
index c009797..0ba876f 100644
--- a/lib/dtas/state_file.rb
+++ b/lib/dtas/state_file.rb
@@ -3,6 +3,8 @@
 require 'yaml'
 require 'tempfile'
 class DTAS::StateFile # :nodoc:
+  attr_reader :path
+
   def initialize(path, do_fsync = false)
     @path = path
     @do_fsync = do_fsync
diff --git a/test/test_player_integration.rb b/test/test_player_integration.rb
index b60ed36..e7f7306 100644
--- a/test/test_player_integration.rb
+++ b/test/test_player_integration.rb
@@ -188,6 +188,24 @@ class TestPlayerIntegration < Minitest::Unit::TestCase
     assert_equal "/", s.req("pwd")
   end
 
+  def test_state_file
+    state = Tempfile.new(%w(state .yml))
+    state_path = state.path
+    state.close!
+    s = client_socket
+    s.req_ok(%W(state dump #{state_path}))
+    hash = YAML.load(IO.binread(state_path))
+    assert_equal @sock_path, hash["socket"]
+    assert_equal "default", hash["sinks"][0]["name"]
+
+    assert_equal "", IO.binread(@state_tmp.path)
+    s.req_ok(%W(state dump))
+    orig = YAML.load(IO.binread(@state_tmp.path))
+    assert_equal orig, hash
+  ensure
+    File.unlink(state_path)
+  end
+
   def test_source_ed
     s = client_socket
     assert_equal "sox av ff", s.req("source ls")
-- 
1.8.4




reply via email to

[Prev in Thread] Current Thread [Next in Thread]