filestore 0.0.19 → 0.0.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/filestore.rb +6 -2
- data/lib/filestore/factory.rb +43 -0
- data/lib/filestore/observer.rb +4 -0
- data/lib/filestore/simple_store.rb +1 -1
- data/lib/filestore/webdav/webdav.rb +211 -0
- data/lib/filestore/webdav_store.rb +153 -0
- data/test/tc_webdav.rb +130 -0
- data/test/tc_webdav_store.rb +109 -0
- metadata +9 -3
    
        data/lib/filestore.rb
    CHANGED
    
    | @@ -19,7 +19,9 @@ LIBS = [ | |
| 19 19 | 
             
              'uuidtools',
         | 
| 20 20 | 
             
              'fileutils',
         | 
| 21 21 | 
             
              'yaml',
         | 
| 22 | 
            -
              'etc'
         | 
| 22 | 
            +
              'etc',
         | 
| 23 | 
            +
              'socket',
         | 
| 24 | 
            +
              'base64'
         | 
| 23 25 | 
             
            ]
         | 
| 24 26 | 
             
            FILESTORE_FILES = [
         | 
| 25 27 | 
             
              #
         | 
| @@ -31,7 +33,9 @@ FILESTORE_FILES = [ | |
| 31 33 | 
             
              'memory_meta',
         | 
| 32 34 | 
             
              'simple_store',
         | 
| 33 35 | 
             
              'multitenant_store',
         | 
| 34 | 
            -
              'factory'
         | 
| 36 | 
            +
              'factory',
         | 
| 37 | 
            +
              'webdav/webdav',
         | 
| 38 | 
            +
              'webdav_store'
         | 
| 35 39 | 
             
            ]
         | 
| 36 40 | 
             
            #
         | 
| 37 41 | 
             
            # Loads required 3rd party libs as defined in FileStore::LIBS
         | 
    
        data/lib/filestore/factory.rb
    CHANGED
    
    | @@ -208,4 +208,47 @@ module FileStore | |
| 208 208 | 
             
                  end
         | 
| 209 209 | 
             
                end
         | 
| 210 210 | 
             
              end
         | 
| 211 | 
            +
              
         | 
| 212 | 
            +
              module WebDAV
         | 
| 213 | 
            +
                #
         | 
| 214 | 
            +
                # WebDAVStore factory class
         | 
| 215 | 
            +
                #
         | 
| 216 | 
            +
                class WebDAVStoreFactory
         | 
| 217 | 
            +
                  #
         | 
| 218 | 
            +
                  # Creates a WebDAV file-store instance
         | 
| 219 | 
            +
                  #
         | 
| 220 | 
            +
                  # Arguments:
         | 
| 221 | 
            +
                  #   root_path: The base path directory
         | 
| 222 | 
            +
                  #   host: The WebDAV host
         | 
| 223 | 
            +
                  #   prefix: The path prefix for any URL
         | 
| 224 | 
            +
                  #   port (optional): The WebDAV port
         | 
| 225 | 
            +
                  #   user (optional): HTTP user
         | 
| 226 | 
            +
                  #   password (optional): HTTP password 
         | 
| 227 | 
            +
                  #   observable (optional): Determines wether this instance should support observation
         | 
| 228 | 
            +
                  #   logger (optional): The logging facility
         | 
| 229 | 
            +
                  #
         | 
| 230 | 
            +
                  # Returns:
         | 
| 231 | 
            +
                  #   A new instance of WebDAVStore
         | 
| 232 | 
            +
                  #
         | 
| 233 | 
            +
                  def self.create(root_path, host, prefix, port = 80, user = '', password = '', observable = false, logger = StdoutLogger)
         | 
| 234 | 
            +
                    store = nil
         | 
| 235 | 
            +
                    
         | 
| 236 | 
            +
                    begin
         | 
| 237 | 
            +
                      store = WebDAVStore.new host, port, user, password, root_path, logger
         | 
| 238 | 
            +
                      store.connection.path_prefix = prefix
         | 
| 239 | 
            +
                      
         | 
| 240 | 
            +
                      if observable then
         | 
| 241 | 
            +
                        logger.debug "Extending instance with module 'ObservedSubject'"
         | 
| 242 | 
            +
                        
         | 
| 243 | 
            +
                        store.extend ObservedSubject
         | 
| 244 | 
            +
                        store.initialize_obs 
         | 
| 245 | 
            +
                      end
         | 
| 246 | 
            +
                    rescue FileStoreException => e
         | 
| 247 | 
            +
                      logger.debug "Couldn't create webdav store.\nReason: #{e.message}"
         | 
| 248 | 
            +
                    end
         | 
| 249 | 
            +
                    
         | 
| 250 | 
            +
                    return store
         | 
| 251 | 
            +
                  end
         | 
| 252 | 
            +
                end
         | 
| 253 | 
            +
              end
         | 
| 211 254 | 
             
            end
         | 
    
        data/lib/filestore/observer.rb
    CHANGED
    
    | @@ -11,9 +11,12 @@ module FileStore | |
| 11 11 | 
             
              #
         | 
| 12 12 | 
             
              class ObserverAction
         | 
| 13 13 | 
             
                TYPE_DEFAULT        = "DEFAULT"
         | 
| 14 | 
            +
                TYPE_DAV_ADD        = "WEBDAV_ADD_FILE"
         | 
| 15 | 
            +
                TYPE_DAV_REMOVE     = "WEBDAV_REMOVE_FILE"
         | 
| 14 16 | 
             
                TYPE_STORE_ADD      = "STORE_ADD_FILE"
         | 
| 15 17 | 
             
                TYPE_STORE_REMOVE   = "STORE_REMOVE_FILE"
         | 
| 16 18 | 
             
                TYPE_STORE_GET      = "STORE_GET_FILE"
         | 
| 19 | 
            +
                TYPE_DAV_GET        = "WEBDAV_GET_FILE"
         | 
| 17 20 | 
             
                TYPE_STORE_RESTORE  = "STORE_RESTORE_FILE"
         | 
| 18 21 | 
             
                TYPE_STORE_SHUTDOWN = "STORE_SHUTDOWN"
         | 
| 19 22 | 
             
                TYPE_MSTORE_CREATE  = "MSTORE_CREATE_TENANT"
         | 
| @@ -23,6 +26,7 @@ module FileStore | |
| 23 26 | 
             
                TYPE_META_REMOVE    = "META_REMOVE_FILE"
         | 
| 24 27 | 
             
                TYPE_META_RESTORE   = "META_RESTORE_FILE"
         | 
| 25 28 | 
             
                TYPE_META_SHUTDOWN  = "META_SHUTDOWN"
         | 
| 29 | 
            +
                TYPE_DAV_SHUTDOWN   = "DAV_SHUTDOWN"
         | 
| 26 30 | 
             
                #
         | 
| 27 31 | 
             
                # Attribute accessors for instance variable defining the type of
         | 
| 28 32 | 
             
                # action
         | 
| @@ -78,7 +78,7 @@ module FileStore | |
| 78 78 | 
             
            					(@logger.info("Copying file"); FileUtils.copy_file(file, dstPath))
         | 
| 79 79 |  | 
| 80 80 | 
             
            				inform ObserverAction.new(:type => ObserverAction::TYPE_STORE_ADD, 
         | 
| 81 | 
            -
                      :objects =>  | 
| 81 | 
            +
                      :objects => { :file => file, :meta => meta }, :msg => "Added file to file store") if self.is_a?(ObservedSubject)
         | 
| 82 82 | 
             
            			rescue Exception => e
         | 
| 83 83 | 
             
            				raise FileStoreException, "Couldn't add file #{file} to store.", e.backtrace
         | 
| 84 84 | 
             
            			end
         | 
| @@ -0,0 +1,211 @@ | |
| 1 | 
            +
            #
         | 
| 2 | 
            +
            # webdav.rb
         | 
| 3 | 
            +
            #
         | 
| 4 | 
            +
            # author: Thomas Stätter
         | 
| 5 | 
            +
            # date: 2014/02/01
         | 
| 6 | 
            +
            #
         | 
| 7 | 
            +
            module FileStore::WebDAV
         | 
| 8 | 
            +
              #
         | 
| 9 | 
            +
              # Class WebDAVException is used to identify errors occuring
         | 
| 10 | 
            +
              # in WebDAV connections
         | 
| 11 | 
            +
              #
         | 
| 12 | 
            +
              class WebDAVException < Exception
         | 
| 13 | 
            +
              end
         | 
| 14 | 
            +
              #
         | 
| 15 | 
            +
              # Class implementing easy accessor to HTTP response headers
         | 
| 16 | 
            +
              #
         | 
| 17 | 
            +
              class ResponseHeaders
         | 
| 18 | 
            +
                attr_reader :headers, :http_version, :status, :response_text
         | 
| 19 | 
            +
                #
         | 
| 20 | 
            +
                # Initialize new ResponseHeaders instance
         | 
| 21 | 
            +
                #
         | 
| 22 | 
            +
                # Arguments:
         | 
| 23 | 
            +
                #   text: The raw response text
         | 
| 24 | 
            +
                #
         | 
| 25 | 
            +
                def initialize(text)
         | 
| 26 | 
            +
                  @headers = {}
         | 
| 27 | 
            +
                  @http_version = ''
         | 
| 28 | 
            +
                  @status = -1
         | 
| 29 | 
            +
                  @response_text = ''
         | 
| 30 | 
            +
                  
         | 
| 31 | 
            +
                  parse text
         | 
| 32 | 
            +
                end
         | 
| 33 | 
            +
                #
         | 
| 34 | 
            +
                # Determines wether the reponse body is XML
         | 
| 35 | 
            +
                #
         | 
| 36 | 
            +
                # Returns:
         | 
| 37 | 
            +
                #   true if content type is appilcation/xml, false otherwise
         | 
| 38 | 
            +
                #
         | 
| 39 | 
            +
                def is_xml?
         | 
| 40 | 
            +
                  not (@headers['Content-Type'] =~ /^application\/xml.*/).nil?
         | 
| 41 | 
            +
                end
         | 
| 42 | 
            +
                #
         | 
| 43 | 
            +
                # Determines wether the reponse body is HTML
         | 
| 44 | 
            +
                #
         | 
| 45 | 
            +
                # Returns:
         | 
| 46 | 
            +
                #   true if content type is appilcation/html, false otherwise
         | 
| 47 | 
            +
                #
         | 
| 48 | 
            +
                def is_html?
         | 
| 49 | 
            +
                  not (@headers['Content-Type'] =~ /^application\/html.*/).nil?
         | 
| 50 | 
            +
                end
         | 
| 51 | 
            +
                
         | 
| 52 | 
            +
                private
         | 
| 53 | 
            +
                #
         | 
| 54 | 
            +
                # Parse the reponse text
         | 
| 55 | 
            +
                #
         | 
| 56 | 
            +
                def parse(text)
         | 
| 57 | 
            +
                  text.split("\n").each do |line|
         | 
| 58 | 
            +
                    if line =~ /^.*\:.*$/
         | 
| 59 | 
            +
                      s = line.split(":")
         | 
| 60 | 
            +
                  
         | 
| 61 | 
            +
                      key = s[0].strip
         | 
| 62 | 
            +
                      value = s[1].strip
         | 
| 63 | 
            +
                  
         | 
| 64 | 
            +
                      @headers[key] = value
         | 
| 65 | 
            +
                    else
         | 
| 66 | 
            +
                      s = line.split
         | 
| 67 | 
            +
                      
         | 
| 68 | 
            +
                      @http_version = s[0]
         | 
| 69 | 
            +
                      @status = s[1].to_i
         | 
| 70 | 
            +
                      @response_text = s[2]
         | 
| 71 | 
            +
                    end
         | 
| 72 | 
            +
                  end
         | 
| 73 | 
            +
                end
         | 
| 74 | 
            +
              end
         | 
| 75 | 
            +
              #
         | 
| 76 | 
            +
              # Class implementing a connector to a HTTP resource via WebDAV
         | 
| 77 | 
            +
              #
         | 
| 78 | 
            +
              class WebDAV
         | 
| 79 | 
            +
                include FileStore::Logger
         | 
| 80 | 
            +
                
         | 
| 81 | 
            +
                attr_reader :host, :port, :protocol, :chunk_size
         | 
| 82 | 
            +
                attr_accessor :credentials, :path_prefix
         | 
| 83 | 
            +
                
         | 
| 84 | 
            +
                @socket = nil
         | 
| 85 | 
            +
               
         | 
| 86 | 
            +
                def initialize(host,port=80,protocol='HTTP/1.1',chunk=8096)
         | 
| 87 | 
            +
                  @host = host.to_s
         | 
| 88 | 
            +
                  @port = port.to_i
         | 
| 89 | 
            +
                  @protocol = protocol
         | 
| 90 | 
            +
                  @chunk_size = chunk.to_i
         | 
| 91 | 
            +
                  @credentials = {}
         | 
| 92 | 
            +
                end
         | 
| 93 | 
            +
                
         | 
| 94 | 
            +
                def encode_credentials
         | 
| 95 | 
            +
                  Base64.encode64("#{credentials[:user]}:#{credentials[:password]}").strip
         | 
| 96 | 
            +
                end
         | 
| 97 | 
            +
               
         | 
| 98 | 
            +
                def build_header(method, path, content_length = nil)
         | 
| 99 | 
            +
                  header = "#{method} #{File.join(@path_prefix, path)} #{@protocol} \r\n"
         | 
| 100 | 
            +
                  header += "Content-Length: #{content_length}\r\n" unless content_length.nil?
         | 
| 101 | 
            +
                  header += "Host: #{@host}\r\n"
         | 
| 102 | 
            +
                  header += "Authorization: Basic #{encode_credentials}\r\n" unless @credentials.empty?
         | 
| 103 | 
            +
                  header += "User-Agent: WebDAV-Client/0.1\r\n"
         | 
| 104 | 
            +
                  header += "Connection: close\r\n\r\n"
         | 
| 105 | 
            +
                  
         | 
| 106 | 
            +
                  return header
         | 
| 107 | 
            +
                end
         | 
| 108 | 
            +
               
         | 
| 109 | 
            +
                def request(method, path)
         | 
| 110 | 
            +
                  data = {}
         | 
| 111 | 
            +
                  buf = ''      
         | 
| 112 | 
            +
                  begin
         | 
| 113 | 
            +
                    open
         | 
| 114 | 
            +
                    header = build_header(method, path)
         | 
| 115 | 
            +
                    
         | 
| 116 | 
            +
                    if @socket.write(header) == header.length then
         | 
| 117 | 
            +
                      while line = @socket.gets # Read lines from socket
         | 
| 118 | 
            +
                        buf += line
         | 
| 119 | 
            +
                      end
         | 
| 120 | 
            +
                      
         | 
| 121 | 
            +
                      data = { 
         | 
| 122 | 
            +
                        header: ResponseHeaders.new(buf.split("\r\n\r\n")[0]), 
         | 
| 123 | 
            +
                        body: buf.split("\r\n\r\n")[1] 
         | 
| 124 | 
            +
                      }
         | 
| 125 | 
            +
                    else
         | 
| 126 | 
            +
                      raise WebDAVException.new "Couldn't send request headers"
         | 
| 127 | 
            +
                    end
         | 
| 128 | 
            +
                  rescue Exception => e
         | 
| 129 | 
            +
                    raise WebDAVException.new "Caught exception while sending request. #{e.message}"
         | 
| 130 | 
            +
                  ensure
         | 
| 131 | 
            +
                    close
         | 
| 132 | 
            +
                  end
         | 
| 133 | 
            +
                  
         | 
| 134 | 
            +
                  return data
         | 
| 135 | 
            +
                end
         | 
| 136 | 
            +
                
         | 
| 137 | 
            +
                def delete(path)
         | 
| 138 | 
            +
                  request('DELETE', path)
         | 
| 139 | 
            +
                end
         | 
| 140 | 
            +
                
         | 
| 141 | 
            +
                def propfind(path)
         | 
| 142 | 
            +
                  request('PROPFIND', path)
         | 
| 143 | 
            +
                end
         | 
| 144 | 
            +
               
         | 
| 145 | 
            +
                def head(path)
         | 
| 146 | 
            +
                  request('HEAD', path)
         | 
| 147 | 
            +
                end
         | 
| 148 | 
            +
               
         | 
| 149 | 
            +
                def mkcol(path)
         | 
| 150 | 
            +
                  request('MKCOL', path)
         | 
| 151 | 
            +
                end
         | 
| 152 | 
            +
               
         | 
| 153 | 
            +
                def put(path, local_file, auto_head = true)
         | 
| 154 | 
            +
                  if !File.exists?(local_file) || !File.readable?(local_file)
         | 
| 155 | 
            +
                    raise WebDAVException.new "File not exists or not accessible for reading!"
         | 
| 156 | 
            +
                  end
         | 
| 157 | 
            +
               
         | 
| 158 | 
            +
                  open
         | 
| 159 | 
            +
               
         | 
| 160 | 
            +
                  datalen = File.size(local_file)
         | 
| 161 | 
            +
                  header = build_header('PUT', path, datalen)
         | 
| 162 | 
            +
               
         | 
| 163 | 
            +
                  begin
         | 
| 164 | 
            +
                    if @socket.write(header) == header.length then
         | 
| 165 | 
            +
                      written = 0
         | 
| 166 | 
            +
                      File.open(local_file,'r') do |f| 
         | 
| 167 | 
            +
                        until f.eof? do
         | 
| 168 | 
            +
                          written += @socket.write f.read(@chunk_size)
         | 
| 169 | 
            +
                        end
         | 
| 170 | 
            +
                      end
         | 
| 171 | 
            +
               
         | 
| 172 | 
            +
                      if written == datalen
         | 
| 173 | 
            +
                        close
         | 
| 174 | 
            +
                        if !auto_head
         | 
| 175 | 
            +
                          return true
         | 
| 176 | 
            +
                        else
         | 
| 177 | 
            +
                          return head(path)
         | 
| 178 | 
            +
                        end
         | 
| 179 | 
            +
                      end
         | 
| 180 | 
            +
                    end
         | 
| 181 | 
            +
                  rescue Exception => e
         | 
| 182 | 
            +
                    raise WebDAVException.new "Caught exception in PUT request. #{e.message}"
         | 
| 183 | 
            +
                  ensure
         | 
| 184 | 
            +
                    close
         | 
| 185 | 
            +
                  end
         | 
| 186 | 
            +
                end
         | 
| 187 | 
            +
                
         | 
| 188 | 
            +
                def get(path)
         | 
| 189 | 
            +
                  request('GET', path)
         | 
| 190 | 
            +
                end
         | 
| 191 | 
            +
               
         | 
| 192 | 
            +
                def open
         | 
| 193 | 
            +
                  begin 
         | 
| 194 | 
            +
                    @socket = TCPSocket.open(@host, @port)
         | 
| 195 | 
            +
                    return true
         | 
| 196 | 
            +
                  rescue Exception => e
         | 
| 197 | 
            +
                    raise WebDAVException.new "Caught exception while opening connection. #{e.message}"
         | 
| 198 | 
            +
                  end
         | 
| 199 | 
            +
                end
         | 
| 200 | 
            +
               
         | 
| 201 | 
            +
                def close
         | 
| 202 | 
            +
                  begin
         | 
| 203 | 
            +
                    return @socket.close
         | 
| 204 | 
            +
                  rescue 
         | 
| 205 | 
            +
                    return false
         | 
| 206 | 
            +
                  end
         | 
| 207 | 
            +
                end
         | 
| 208 | 
            +
                
         | 
| 209 | 
            +
              end
         | 
| 210 | 
            +
              
         | 
| 211 | 
            +
            end
         | 
| @@ -0,0 +1,153 @@ | |
| 1 | 
            +
            #
         | 
| 2 | 
            +
            # webdav_store.rb
         | 
| 3 | 
            +
            #
         | 
| 4 | 
            +
            # author: Thomas Stätter
         | 
| 5 | 
            +
            # date: 2014/02/01
         | 
| 6 | 
            +
            #
         | 
| 7 | 
            +
            module FileStore::WebDAV
         | 
| 8 | 
            +
            	#
         | 
| 9 | 
            +
            	# Main library class implementing a WebDAV file store used for storing and managing 
         | 
| 10 | 
            +
            	# arbitrary files
         | 
| 11 | 
            +
            	#
         | 
| 12 | 
            +
            	class WebDAVStore
         | 
| 13 | 
            +
            	  include FileStore::Logger
         | 
| 14 | 
            +
            		#
         | 
| 15 | 
            +
            		# Accessors for important properties
         | 
| 16 | 
            +
            		#
         | 
| 17 | 
            +
            		attr_reader :host, :port, :root_path, :connection, :user, :password
         | 
| 18 | 
            +
            		#
         | 
| 19 | 
            +
            		# Initializes a new instance of SimpleFileStore
         | 
| 20 | 
            +
            		#
         | 
| 21 | 
            +
            		# Arguments:
         | 
| 22 | 
            +
            		# 	root_path: The path where the file store resides
         | 
| 23 | 
            +
            		#   logger: The logging facility
         | 
| 24 | 
            +
            		#
         | 
| 25 | 
            +
            		def initialize(host, port, user, password, root_path = '/', logger = StdoutLogger)
         | 
| 26 | 
            +
            			@host = host
         | 
| 27 | 
            +
            			@port = port
         | 
| 28 | 
            +
            			@user = user
         | 
| 29 | 
            +
            			@password = password
         | 
| 30 | 
            +
            			@root_path = root_path
         | 
| 31 | 
            +
            			
         | 
| 32 | 
            +
            			initialize_connection
         | 
| 33 | 
            +
            		end
         | 
| 34 | 
            +
            		#
         | 
| 35 | 
            +
            		# Adds a file to the store
         | 
| 36 | 
            +
            		#
         | 
| 37 | 
            +
            		# Arguments:
         | 
| 38 | 
            +
            		# 	file: The file to be stored
         | 
| 39 | 
            +
            		#
         | 
| 40 | 
            +
            		# Returns:
         | 
| 41 | 
            +
            		#	  The file path or nil
         | 
| 42 | 
            +
            		#
         | 
| 43 | 
            +
            		def add(file)
         | 
| 44 | 
            +
            			raise FileStoreException, "File #{file} not found" if not File.exists?(file)
         | 
| 45 | 
            +
            			raise FileStoreException, "File #{file} isn't readable" if not File.readable?(file)
         | 
| 46 | 
            +
            			
         | 
| 47 | 
            +
            			f_path = File.basename file
         | 
| 48 | 
            +
            			remote_path = File.join @root_path, f_path
         | 
| 49 | 
            +
            			
         | 
| 50 | 
            +
            			begin
         | 
| 51 | 
            +
            				result = @connection.put remote_path, file
         | 
| 52 | 
            +
             | 
| 53 | 
            +
            				raise "Couldn't upload file, response code isn't of type 2xx" unless (result[:header].status.to_s =~ /2\d{2}/)
         | 
| 54 | 
            +
            				
         | 
| 55 | 
            +
            				inform ObserverAction.new(:type => ObserverAction::TYPE_DAV_ADD, 
         | 
| 56 | 
            +
                      :objects => { :file => remote_path, :meta => meta }, :msg => "Added file to remote file store") if self.is_a?(ObservedSubject)
         | 
| 57 | 
            +
            			rescue Exception => e
         | 
| 58 | 
            +
            				raise FileStoreException, "Couldn't put file '#{file}' to remote store URL '#{remote_path}'.\n#{e.backtrace.join("\n")}"
         | 
| 59 | 
            +
            			end
         | 
| 60 | 
            +
            			
         | 
| 61 | 
            +
            			return remote_path
         | 
| 62 | 
            +
            		end
         | 
| 63 | 
            +
            		#
         | 
| 64 | 
            +
            		# Retrieves a file identified by it's path
         | 
| 65 | 
            +
            		#
         | 
| 66 | 
            +
            		# Arguments:
         | 
| 67 | 
            +
            		# 	file: The file path to get from the remote store
         | 
| 68 | 
            +
            		#
         | 
| 69 | 
            +
            		# Returns: 
         | 
| 70 | 
            +
            		#	A hash of file object (:path) and corresponding meta data (:data)
         | 
| 71 | 
            +
            		#			representing the file in the store
         | 
| 72 | 
            +
            		#
         | 
| 73 | 
            +
            		def get(file)
         | 
| 74 | 
            +
            			raise FileStoreException, "No file given" if file.nil? or file == ''
         | 
| 75 | 
            +
            			
         | 
| 76 | 
            +
            			# Retrieve data from the store
         | 
| 77 | 
            +
            			result = @connection.get file
         | 
| 78 | 
            +
            			
         | 
| 79 | 
            +
            			unless result[:body].nil?
         | 
| 80 | 
            +
              			inform ObserverAction.new(:type => ObserverAction::TYPE_DAV_GET, 
         | 
| 81 | 
            +
                      :objects => [file], :msg => "Returning file from the remote store")  if self.is_a?(ObservedSubject)
         | 
| 82 | 
            +
                      
         | 
| 83 | 
            +
                    return { :path => file, :data => result[:body] }
         | 
| 84 | 
            +
            			else
         | 
| 85 | 
            +
            			  return {}
         | 
| 86 | 
            +
            			end
         | 
| 87 | 
            +
            			
         | 
| 88 | 
            +
            		end
         | 
| 89 | 
            +
            		#
         | 
| 90 | 
            +
            		# Deletes a file from the remote store
         | 
| 91 | 
            +
            		#
         | 
| 92 | 
            +
            		# Arguments:
         | 
| 93 | 
            +
            		# 	file: The remote file path
         | 
| 94 | 
            +
            		#
         | 
| 95 | 
            +
            		def remove(file)
         | 
| 96 | 
            +
            			raise FileStoreException, "No file given for removal" if (file == '' or file.nil?)
         | 
| 97 | 
            +
            			
         | 
| 98 | 
            +
            			begin
         | 
| 99 | 
            +
            				result = @connection.delete file
         | 
| 100 | 
            +
            				
         | 
| 101 | 
            +
            				if result[:header].status.to_s =~ /2\d{2}/
         | 
| 102 | 
            +
              				inform ObserverAction.new(:type => ObserverAction::TYPE_DAV_REMOVE, 
         | 
| 103 | 
            +
                        :objects => [id], :msg => "Deleted file from remote store") if self.is_a?(ObservedSubject)
         | 
| 104 | 
            +
                    else
         | 
| 105 | 
            +
                      raise "Response code isn't of class 2xx"
         | 
| 106 | 
            +
                    end
         | 
| 107 | 
            +
            			rescue Exception => e
         | 
| 108 | 
            +
            				raise FileStoreException, "Couldn't remove file '#{file}' from remote store.\n#{e.message}"
         | 
| 109 | 
            +
            			end
         | 
| 110 | 
            +
            		end
         | 
| 111 | 
            +
            		#
         | 
| 112 | 
            +
            		# Shuts down the file store
         | 
| 113 | 
            +
            		#
         | 
| 114 | 
            +
            		def shutdown
         | 
| 115 | 
            +
            			@connection.close
         | 
| 116 | 
            +
            			
         | 
| 117 | 
            +
            			inform ObserverAction.new(:type => ObserverAction::TYPE_DAV_SHUTDOWN, 
         | 
| 118 | 
            +
                    :msg => "WebDAV store shutdown")  if self.is_a?(ObservedSubject)
         | 
| 119 | 
            +
            		end
         | 
| 120 | 
            +
            		
         | 
| 121 | 
            +
            		private
         | 
| 122 | 
            +
            		#
         | 
| 123 | 
            +
            		# Initialize the HTTP connection
         | 
| 124 | 
            +
            		#
         | 
| 125 | 
            +
            		def initialize_connection
         | 
| 126 | 
            +
            		  @connection = WebDAV.new @host, @port
         | 
| 127 | 
            +
            		  @connection.credentials = { :user => @user, :password => @password }
         | 
| 128 | 
            +
            		end
         | 
| 129 | 
            +
            		#
         | 
| 130 | 
            +
            		# Creates the directory if it doesn't exist
         | 
| 131 | 
            +
            		#
         | 
| 132 | 
            +
            		# Arguments:
         | 
| 133 | 
            +
            		#   path: The path to be tested or created
         | 
| 134 | 
            +
            		#
         | 
| 135 | 
            +
            		def ensure_path(path)
         | 
| 136 | 
            +
            		  ret = false
         | 
| 137 | 
            +
            		  remote_path = File.join(@root_path, path)
         | 
| 138 | 
            +
            		  result = @connection.propfind(remote_path)
         | 
| 139 | 
            +
            		  
         | 
| 140 | 
            +
            		  if result[:header].status.to_s =~ /2\d{2}/
         | 
| 141 | 
            +
            		    # Directory exists
         | 
| 142 | 
            +
            		    ret = true
         | 
| 143 | 
            +
            		  else
         | 
| 144 | 
            +
            		    # Directory must be created
         | 
| 145 | 
            +
            		    result = @connection.mkcol remote_path
         | 
| 146 | 
            +
            		    ret = true if (result[:header].status.to_s =~ /2\d{2}/)
         | 
| 147 | 
            +
            		  end
         | 
| 148 | 
            +
            		  
         | 
| 149 | 
            +
            		  ret
         | 
| 150 | 
            +
            		end
         | 
| 151 | 
            +
            	end
         | 
| 152 | 
            +
             | 
| 153 | 
            +
            end
         | 
    
        data/test/tc_webdav.rb
    ADDED
    
    | @@ -0,0 +1,130 @@ | |
| 1 | 
            +
            #
         | 
| 2 | 
            +
            # tc_webdav.rb
         | 
| 3 | 
            +
            #
         | 
| 4 | 
            +
            # @author Thomas Stätter
         | 
| 5 | 
            +
            # @date 2014/02/01
         | 
| 6 | 
            +
            # @description Test script
         | 
| 7 | 
            +
            #
         | 
| 8 | 
            +
            require './classes.rb'
         | 
| 9 | 
            +
            require 'test/unit'
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            include FileStore::WebDAV
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            class TestWebDAV < Test::Unit::TestCase
         | 
| 14 | 
            +
              
         | 
| 15 | 
            +
              def setup
         | 
| 16 | 
            +
                @host = 'owncloud.strawanzen.at'
         | 
| 17 | 
            +
                @credentials = { :user => 'demo', :password => 'demo' }
         | 
| 18 | 
            +
                @path = '/files'
         | 
| 19 | 
            +
                @test_file = 'testfile.txt'
         | 
| 20 | 
            +
                @webdav = WebDAV.new @host
         | 
| 21 | 
            +
                @remote_dir = File.join(@path, 'new@dir')
         | 
| 22 | 
            +
                
         | 
| 23 | 
            +
                @webdav.logger = StdoutLogger
         | 
| 24 | 
            +
                @webdav.credentials = @credentials
         | 
| 25 | 
            +
                @webdav.path_prefix = '/remote.php/webdav/'
         | 
| 26 | 
            +
                
         | 
| 27 | 
            +
                File.open(@test_file, "w+") do |f|
         | 
| 28 | 
            +
                  f.write("lorem ipsum")
         | 
| 29 | 
            +
                end
         | 
| 30 | 
            +
              end
         | 
| 31 | 
            +
              
         | 
| 32 | 
            +
              def teardown
         | 
| 33 | 
            +
                FileUtils.rm(@test_file) if File.exists?(@test_file)
         | 
| 34 | 
            +
              end
         | 
| 35 | 
            +
              
         | 
| 36 | 
            +
              def test_01_connect
         | 
| 37 | 
            +
                   puts "=" * 80
         | 
| 38 | 
            +
                   puts "TestWebDAV::test_connect"
         | 
| 39 | 
            +
                   puts "=" * 80
         | 
| 40 | 
            +
                   result = {}
         | 
| 41 | 
            +
                   
         | 
| 42 | 
            +
                   assert_nothing_raised(Exception) { result = @webdav.propfind(@path) }
         | 
| 43 | 
            +
                   assert_not_nil(result[:header])
         | 
| 44 | 
            +
                   assert_not_nil(result[:body])
         | 
| 45 | 
            +
                   assert_match(/2\d{2}/, result[:header].status.to_s, "[TestWebDAV::test_connect] Response code isn't of class 2xx")
         | 
| 46 | 
            +
                   assert(result[:header].is_xml?, "[TestWebDAV::test_connect] Response is not XML")
         | 
| 47 | 
            +
              end
         | 
| 48 | 
            +
                
         | 
| 49 | 
            +
              def test_02_put
         | 
| 50 | 
            +
                   puts "=" * 80
         | 
| 51 | 
            +
                   puts "TestWebDAV::test_put"
         | 
| 52 | 
            +
                   puts "=" * 80
         | 
| 53 | 
            +
                   
         | 
| 54 | 
            +
                   # result = {}
         | 
| 55 | 
            +
                   upload = File.join(@path, @test_file)
         | 
| 56 | 
            +
                   
         | 
| 57 | 
            +
                   assert_nothing_raised(WebDAVException) {
         | 
| 58 | 
            +
                     puts "[TestWebDAV::test_put] Uploading file '#{@test_file}' to '#{upload}'" 
         | 
| 59 | 
            +
                     result = @webdav.put upload, @test_file
         | 
| 60 | 
            +
                   }
         | 
| 61 | 
            +
                   # assert_match(/2\d{2}/, result[:header].status.to_s, "Response code isn't of class 2xx")
         | 
| 62 | 
            +
              end
         | 
| 63 | 
            +
                 
         | 
| 64 | 
            +
              def test_03_propfind
         | 
| 65 | 
            +
                   puts "=" * 80
         | 
| 66 | 
            +
                   puts "TestWebDAV::test_propfind"
         | 
| 67 | 
            +
                   puts "=" * 80
         | 
| 68 | 
            +
                   
         | 
| 69 | 
            +
                   upload = File.join(@path, @test_file)
         | 
| 70 | 
            +
                   result = {}
         | 
| 71 | 
            +
                   
         | 
| 72 | 
            +
                   assert_nothing_raised(WebDAVException) {
         | 
| 73 | 
            +
                     puts "[TestWebDAV::test_propfind] Reading info for '#{upload}'" 
         | 
| 74 | 
            +
                     result = @webdav.propfind upload
         | 
| 75 | 
            +
                   }
         | 
| 76 | 
            +
                   assert_match(/2\d{2}/, result[:header].status.to_s, "[TestWebDAV::test_propfind] Response code isn't of class 2xx")
         | 
| 77 | 
            +
              end
         | 
| 78 | 
            +
                 
         | 
| 79 | 
            +
              def test_04_mkcol
         | 
| 80 | 
            +
                   puts "=" * 80
         | 
| 81 | 
            +
                   puts "TestWebDAV::test_mkcol"
         | 
| 82 | 
            +
                   puts "=" * 80
         | 
| 83 | 
            +
                   
         | 
| 84 | 
            +
                   result = {}
         | 
| 85 | 
            +
                   
         | 
| 86 | 
            +
                   assert_nothing_raised(WebDAVException) {
         | 
| 87 | 
            +
                     puts "[TestWebDAV::test_mkcol] Creating directory file '#{@remote_dir}'" 
         | 
| 88 | 
            +
                     result = @webdav.mkcol @remote_dir
         | 
| 89 | 
            +
                   }
         | 
| 90 | 
            +
                   assert_match(/2\d{2}/, result[:header].status.to_s, "[TestWebDAV::test_mkcol] Response code isn't of class 2xx")
         | 
| 91 | 
            +
              end
         | 
| 92 | 
            +
              
         | 
| 93 | 
            +
              def test_05_get
         | 
| 94 | 
            +
                puts "=" * 80
         | 
| 95 | 
            +
                puts "TestWebDAV::test_get"
         | 
| 96 | 
            +
                puts "=" * 80
         | 
| 97 | 
            +
                
         | 
| 98 | 
            +
                result = {}
         | 
| 99 | 
            +
                remote_file = File.join(@path, @test_file)
         | 
| 100 | 
            +
                
         | 
| 101 | 
            +
                assert_nothing_raised(WebDAVException) {
         | 
| 102 | 
            +
                  puts "[TestWebDAV::test_get] Trying to get remote file '#{remote_file}'" 
         | 
| 103 | 
            +
                  result = @webdav.get remote_file
         | 
| 104 | 
            +
                  puts "[TestWebDAV::test_get] Got file contents: #{result[:body]}"
         | 
| 105 | 
            +
                }
         | 
| 106 | 
            +
                assert_match(/2\d{2}/, result[:header].status.to_s, "[TestWebDAV::test_get] Response code isn't of class 2xx")
         | 
| 107 | 
            +
                assert_not_nil(result[:body], "[TestWebDAV::test_get] No data given")
         | 
| 108 | 
            +
              end
         | 
| 109 | 
            +
              
         | 
| 110 | 
            +
              def test_06_delete
         | 
| 111 | 
            +
                puts "=" * 80
         | 
| 112 | 
            +
                puts "TestWebDAV::test_delete"
         | 
| 113 | 
            +
                puts "=" * 80
         | 
| 114 | 
            +
                
         | 
| 115 | 
            +
                upload = File.join(@path, @test_file)
         | 
| 116 | 
            +
                result = {}
         | 
| 117 | 
            +
                
         | 
| 118 | 
            +
                assert_nothing_raised(WebDAVException) {
         | 
| 119 | 
            +
                  puts "[TestWebDAV::test_delete] Deleting file '#{upload}'" 
         | 
| 120 | 
            +
                  result = @webdav.delete upload
         | 
| 121 | 
            +
                }
         | 
| 122 | 
            +
                assert_match(/2\d{2}/, result[:header].status.to_s, "[TestWebDAV::test_delete] Response code isn't of class 2xx")
         | 
| 123 | 
            +
                assert_nothing_raised(WebDAVException) {
         | 
| 124 | 
            +
                  puts "[TestWebDAV::test_delete] Deleting directory '#{@remote_dir}'" 
         | 
| 125 | 
            +
                  result = @webdav.delete @remote_dir
         | 
| 126 | 
            +
                }
         | 
| 127 | 
            +
                assert_match(/2\d{2}/, result[:header].status.to_s, "[TestWebDAV::test_delete] Response code isn't of class 2xx")
         | 
| 128 | 
            +
              end
         | 
| 129 | 
            +
              
         | 
| 130 | 
            +
            end
         | 
| @@ -0,0 +1,109 @@ | |
| 1 | 
            +
            #
         | 
| 2 | 
            +
            # tc_webdav_store.rb
         | 
| 3 | 
            +
            #
         | 
| 4 | 
            +
            # @author Thomas Stätter
         | 
| 5 | 
            +
            # @date 2014/02/01
         | 
| 6 | 
            +
            # @description Test script
         | 
| 7 | 
            +
            #
         | 
| 8 | 
            +
            require './classes.rb'
         | 
| 9 | 
            +
            require 'test/unit'
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            include FileStore::WebDAV
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            class TestWebDAVStore < FileStoreTest
         | 
| 14 | 
            +
              
         | 
| 15 | 
            +
              def test_01_init_shutdown
         | 
| 16 | 
            +
                puts "=" * 80
         | 
| 17 | 
            +
                puts "TestWebDAVStore::test_init_shutdown"
         | 
| 18 | 
            +
                puts "=" * 80
         | 
| 19 | 
            +
                
         | 
| 20 | 
            +
                store = nil
         | 
| 21 | 
            +
                
         | 
| 22 | 
            +
                assert_nothing_raised(FileStoreException) {
         | 
| 23 | 
            +
                  store = WebDAVStoreFactory::create 'files', 'owncloud.strawanzen.at', '/remote.php/webdav/', 80, 'demo', 'demo'
         | 
| 24 | 
            +
                }
         | 
| 25 | 
            +
                assert_nothing_raised(FileStoreException) {
         | 
| 26 | 
            +
                  store.shutdown
         | 
| 27 | 
            +
                }
         | 
| 28 | 
            +
              end
         | 
| 29 | 
            +
              
         | 
| 30 | 
            +
              def test_02_observer_registration
         | 
| 31 | 
            +
                puts "=" * 80
         | 
| 32 | 
            +
                puts "TestWebDAVStore::test_observer_registration"
         | 
| 33 | 
            +
                puts "=" * 80
         | 
| 34 | 
            +
                
         | 
| 35 | 
            +
                store = nil
         | 
| 36 | 
            +
                
         | 
| 37 | 
            +
                assert_nothing_raised(FileStoreException) {
         | 
| 38 | 
            +
                  o1 = ObserverClass.new
         | 
| 39 | 
            +
                  o1.logger = StdoutLogger
         | 
| 40 | 
            +
                  
         | 
| 41 | 
            +
                  store = WebDAVStoreFactory::create 'files/', 'owncloud.strawanzen.at', '/remote.php/webdav/', 80, 'demo', 'demo', true
         | 
| 42 | 
            +
                  
         | 
| 43 | 
            +
                  store.register o1
         | 
| 44 | 
            +
                  store.inform "Some test message"
         | 
| 45 | 
            +
                  store.shutdown
         | 
| 46 | 
            +
                }
         | 
| 47 | 
            +
              end
         | 
| 48 | 
            +
             | 
| 49 | 
            +
              def test_03_actions_with_observer
         | 
| 50 | 
            +
                # puts "=" * 80
         | 
| 51 | 
            +
                # puts "TestWebDAVStore::test_actions_with_observer"
         | 
| 52 | 
            +
                # puts "=" * 80
         | 
| 53 | 
            +
              end
         | 
| 54 | 
            +
              
         | 
| 55 | 
            +
              def test_04_upload
         | 
| 56 | 
            +
                puts "=" * 80
         | 
| 57 | 
            +
                puts "TestWebDAVStore::test_upload"
         | 
| 58 | 
            +
                puts "=" * 80
         | 
| 59 | 
            +
                
         | 
| 60 | 
            +
                assert_nothing_raised(FileStoreException) {
         | 
| 61 | 
            +
                  open(@testFileSimple, 'w') do |f|
         | 
| 62 | 
            +
                    f.write "lorem ipsum"
         | 
| 63 | 
            +
                  end
         | 
| 64 | 
            +
                  
         | 
| 65 | 
            +
                  store = WebDAVStoreFactory::create 'files', 'owncloud.strawanzen.at', '/remote.php/webdav/', 80, 'demo', 'demo'
         | 
| 66 | 
            +
                  puts "[TestWebDAVStore::test_upload] Trying to upload '#{@testFileSimple}' to remote store"
         | 
| 67 | 
            +
                  file = store.add @testFileSimple
         | 
| 68 | 
            +
                  
         | 
| 69 | 
            +
                  store.shutdown
         | 
| 70 | 
            +
                  
         | 
| 71 | 
            +
                  puts "[TestWebDAVStore::test_upload] Added file '#{file}'"
         | 
| 72 | 
            +
                }
         | 
| 73 | 
            +
              end
         | 
| 74 | 
            +
              
         | 
| 75 | 
            +
              def test_05_get
         | 
| 76 | 
            +
                puts "=" * 80
         | 
| 77 | 
            +
                puts "TestWebDAVStore::test_get"
         | 
| 78 | 
            +
                puts "=" * 80
         | 
| 79 | 
            +
                
         | 
| 80 | 
            +
                remote_file = 'files/testfile.txt'
         | 
| 81 | 
            +
                
         | 
| 82 | 
            +
                assert_nothing_raised(FileStoreException) {
         | 
| 83 | 
            +
                  store = WebDAVStoreFactory::create 'files', 'owncloud.strawanzen.at', '/remote.php/webdav/', 80, 'demo', 'demo'
         | 
| 84 | 
            +
                  puts "[TestWebDAVStore::test_get] Trying to upload '#{remote_file}' to remote store"
         | 
| 85 | 
            +
                  file = store.get remote_file
         | 
| 86 | 
            +
                  
         | 
| 87 | 
            +
                  store.shutdown
         | 
| 88 | 
            +
                  
         | 
| 89 | 
            +
                  puts "[TestWebDAVStore::test_upload] Got file '#{file}'"
         | 
| 90 | 
            +
                }
         | 
| 91 | 
            +
              end
         | 
| 92 | 
            +
              
         | 
| 93 | 
            +
              def test_06_remove
         | 
| 94 | 
            +
                puts "=" * 80
         | 
| 95 | 
            +
                puts "TestWebDAVStore::test_remove"
         | 
| 96 | 
            +
                puts "=" * 80
         | 
| 97 | 
            +
                
         | 
| 98 | 
            +
                remote_file = 'files/testfile.txt'
         | 
| 99 | 
            +
                
         | 
| 100 | 
            +
                assert_nothing_raised(FileStoreException) {
         | 
| 101 | 
            +
                  store = WebDAVStoreFactory::create 'files', 'owncloud.strawanzen.at', '/remote.php/webdav/', 80, 'demo', 'demo'
         | 
| 102 | 
            +
                  puts "[TestWebDAVStore::test_remove] Trying to delete '#{remote_file}' from remote store"
         | 
| 103 | 
            +
                  store.remove remote_file
         | 
| 104 | 
            +
                  
         | 
| 105 | 
            +
                  store.shutdown
         | 
| 106 | 
            +
                }
         | 
| 107 | 
            +
              end
         | 
| 108 | 
            +
              
         | 
| 109 | 
            +
            end
         | 
    
        metadata
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: filestore
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0.0. | 
| 4 | 
            +
              version: 0.0.20
         | 
| 5 5 | 
             
              prerelease: 
         | 
| 6 6 | 
             
            platform: ruby
         | 
| 7 7 | 
             
            authors:
         | 
| @@ -9,7 +9,7 @@ authors: | |
| 9 9 | 
             
            autorequire: 
         | 
| 10 10 | 
             
            bindir: bin
         | 
| 11 11 | 
             
            cert_chain: []
         | 
| 12 | 
            -
            date: 2014- | 
| 12 | 
            +
            date: 2014-02-02 00:00:00.000000000 Z
         | 
| 13 13 | 
             
            dependencies:
         | 
| 14 14 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 15 15 | 
             
              name: uuidtools
         | 
| @@ -46,12 +46,16 @@ files: | |
| 46 46 | 
             
            - lib/filestore/multitenant_store.rb
         | 
| 47 47 | 
             
            - lib/filestore/observer.rb
         | 
| 48 48 | 
             
            - lib/filestore/simple_store.rb
         | 
| 49 | 
            +
            - lib/filestore/webdav/webdav.rb
         | 
| 50 | 
            +
            - lib/filestore/webdav_store.rb
         | 
| 49 51 | 
             
            - lib/filestore.rb
         | 
| 50 52 | 
             
            - test/classes.rb
         | 
| 51 53 | 
             
            - test/tc_filestore.rb
         | 
| 52 54 | 
             
            - test/tc_meta.rb
         | 
| 53 55 | 
             
            - test/tc_module.rb
         | 
| 54 56 | 
             
            - test/tc_multitenant.rb
         | 
| 57 | 
            +
            - test/tc_webdav.rb
         | 
| 58 | 
            +
            - test/tc_webdav_store.rb
         | 
| 55 59 | 
             
            - test/ts_all.rb
         | 
| 56 60 | 
             
            homepage: https://github.com/tstaetter/filestore-gem
         | 
| 57 61 | 
             
            licenses: []
         | 
| @@ -72,7 +76,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement | |
| 72 76 | 
             
                - !ruby/object:Gem::Version
         | 
| 73 77 | 
             
                  version: '0'
         | 
| 74 78 | 
             
            requirements:
         | 
| 75 | 
            -
            - gem uuidtools | 
| 79 | 
            +
            - gem uuidtools
         | 
| 76 80 | 
             
            rubyforge_project: 
         | 
| 77 81 | 
             
            rubygems_version: 1.8.24
         | 
| 78 82 | 
             
            signing_key: 
         | 
| @@ -84,4 +88,6 @@ test_files: | |
| 84 88 | 
             
            - test/tc_meta.rb
         | 
| 85 89 | 
             
            - test/tc_module.rb
         | 
| 86 90 | 
             
            - test/tc_multitenant.rb
         | 
| 91 | 
            +
            - test/tc_webdav.rb
         | 
| 92 | 
            +
            - test/tc_webdav_store.rb
         | 
| 87 93 | 
             
            - test/ts_all.rb
         |