# $Id: sharedance.rb 867 2007-01-22 18:29:18Z j $ class Sharedance require 'socket' require 'timeout' SHAREDANCE_DEFAULT_PORT = 1042 SHAREDANCE_DEFAULT_TIMEOUT = 10 attr_accessor :host, :port, :timeout def initialize(params) @host = params[:host] @port = params[:port] || SHAREDANCE_DEFAULT_PORT @timeout = params[:timeout] || SHAREDANCE_DEFAULT_TIMEOUT end def self.open(params) yield(self.new(params)) end def fetch(params) result = sharedance_command( "F" + params[:key].encode_size_for_sharedance + params[:key]) result.empty? ? nil : result end def store(params) raise "Storage failed" unless sharedance_command( "S" + params[:key].encode_size_for_sharedance + params[:data].encode_size_for_sharedance + params[:key] + params[:data]) === "OK\n" end def delete(params) raise "Deletion failed" unless sharedance_command( "D" + params[:key].encode_size_for_sharedance + params[:key]) === "OK\n" end def [](key) fetch(:key => key) end def []=(key, data) data.nil? ? delete(:key => key) : store(:key => key, :data => data) end protected @sock = nil def connect_to_server @sock = TCPSocket.new(@host, @port) unless @sock end def close_from_server @sock.close if @sock @sock = nil end def sharedance_command(command) result = nil begin Timeout.timeout(@timeout) do connect_to_server @sock << command result = @sock.read end ensure close_from_server end result end end class String def encode_size_for_sharedance raise "Overflow" if (size = self.size) > 0xffffffff [(size >> 24) & 0xff, (size >> 16) & 0xff, (size >> 8) & 0xff, size & 0xff].pack("cccc") end end