about summary refs log tree commit homepage
path: root/lib/dtas/server_loop.rb
diff options
context:
space:
mode:
authorEric Wong <e@80x24.org>2015-12-02 11:11:06 +0000
committerEric Wong <e@80x24.org>2016-01-22 06:12:58 +0000
commit19e69366177799f7ccff75b6f4a1850ff0ca8d09 (patch)
treee2de2969aad85337ed0d8d5c3b01ca46e9e006f7 /lib/dtas/server_loop.rb
parenta9fcfdb4ac43ccd625df1667611fa143f155dedc (diff)
downloaddtas-19e69366177799f7ccff75b6f4a1850ff0ca8d09.tar.gz
Get basic commands and output buffering (in-memory) working.
The original mpd buffers large responses into memory, too,
so there probably isn't much concern for DoS-ing with slow
clients like a typical web server has.
Diffstat (limited to 'lib/dtas/server_loop.rb')
-rw-r--r--lib/dtas/server_loop.rb55
1 files changed, 55 insertions, 0 deletions
diff --git a/lib/dtas/server_loop.rb b/lib/dtas/server_loop.rb
new file mode 100644
index 0000000..f0936aa
--- /dev/null
+++ b/lib/dtas/server_loop.rb
@@ -0,0 +1,55 @@
+# Copyright (C) 2015 all contributors <dtas-all@nongnu.org>
+# License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
+
+require_relative '../dtas'
+
+# Used for mpd emulation currently, but dtas-player might use this eventually
+class DTAS::ServerLoop
+  def initialize(listeners, client_class)
+    @rd = {}
+    @wr = {}
+    @rbuf = ''
+    @client_class = client_class
+    listeners.each { |l| @rd[l] = true }
+  end
+
+  def run_forever
+    begin
+      r = IO.select(@rd.keys, @wr.keys) or next
+      r[0].each { |rd| do_read(rd) }
+      r[1].each { |wr| do_write(wr) }
+    end while true
+  end
+
+  def do_write(wr)
+    case wr.dispatch_wr
+    when :wait_readable
+      @wr.delete(wr)
+      @rd[wr] = true
+    when nil
+      @wr.delete(wr)
+      wr.to_io.close
+    # when :wait_writable # do nothing
+    end
+  end
+
+  def do_read(rd)
+    case rd
+    when @client_class
+      case rd.dispatch_rd(@rbuf)
+      when :wait_writable
+        @rd.delete(rd)
+        @wr[rd] = true
+      when nil
+        @rd.delete(rd)
+        rd.to_io.close
+      # when :wait_readable : do nothing
+      end
+    else
+      case io = rd.accept_nonblock(exception: false)
+      when :wait_readable then break
+      when IO then @rd[@client_class.new(io)] = true
+      end while true
+    end
+  end
+end