File: file.rb

package info (click to toggle)
ruby-fog-openstack 1.1.5-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 11,784 kB
  • sloc: ruby: 47,937; makefile: 5; sh: 4
file content (195 lines) | stat: -rw-r--r-- 7,235 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
require 'fog/openstack/models/model'

module Fog
  module OpenStack
    class Storage
      class File < Fog::OpenStack::Model
        identity  :key,             :aliases => 'name'

        attribute :access_control_allow_origin, :aliases => ['Access-Control-Allow-Origin']
        attribute :cache_control,   :aliases => ['Cache-Control']
        attribute :content_length,  :aliases => ['bytes', 'Content-Length'], :type => :integer
        attribute :content_type,    :aliases => ['content_type', 'Content-Type']
        attribute :content_disposition, :aliases => ['content_disposition', 'Content-Disposition']
        attribute :etag,            :aliases => ['hash', 'Etag']
        attribute :last_modified,   :aliases => ['last_modified', 'Last-Modified'], :type => :time
        attribute :metadata
        attribute :origin,          :aliases => ['Origin']
        # @!attribute [rw] delete_at
        # A Unix Epoch Timestamp, in integer form, representing the time when this object will be automatically deleted.
        # @return [Integer] the unix epoch timestamp of when this object will be automatically deleted
        # @see http://docs.openstack.org/developer/swift/overview_expiring_objects.html
        attribute :delete_at, :aliases => ['X-Delete-At']

        # @!attribute [rw] delete_after
        # A number of seconds representing how long from now this object will be automatically deleted.
        # @return [Integer] the number of seconds until this object will be automatically deleted
        # @see http://docs.openstack.org/developer/swift/overview_expiring_objects.html
        attribute :delete_after, :aliases => ['X-Delete-After']

        # @!attribute [rw] content_encoding
        # When you create an object or update its metadata, you can optionally set the Content-Encoding metadata.
        # This metadata enables you to indicate that the object content is compressed without losing the identity of the
        # underlying media type (Content-Type) of the file, such as a video.
        # @see http://docs.openstack.org/developer/swift/api/use_content-encoding_metadata.html#use-content-encoding-metadata
        attribute :content_encoding, :aliases => 'Content-Encoding'

        def initialize(new_attributes = {})
          super
          @dirty = if last_modified then false else true end
        end

        def body
          attributes[:body] ||= if last_modified
                                  collection.get(identity).try(:body) || ''
                                else
                                  ''
                                end
        end

        def body=(new_body)
          attributes[:body] = new_body
          @dirty = true
        end

        attr_reader :directory

        def copy(target_directory_key, target_file_key, options = {})
          requires :directory, :key
          options['Content-Type'] ||= content_type if content_type
          options['Access-Control-Allow-Origin'] ||= access_control_allow_origin if access_control_allow_origin
          options['Origin'] ||= origin if origin
          options['Content-Encoding'] ||= content_encoding if content_encoding
          service.copy_object(directory.key, key, target_directory_key, target_file_key, options)
          target_directory = service.directories.new(:key => target_directory_key)
          target_directory.files.get(target_file_key)
        end

        def destroy
          requires :directory, :key
          service.delete_object(directory.key, key)
          @dirty = true
          true
        end

        def metadata
          attributes[:metadata] ||= headers_to_metadata
        end

        def owner=(new_owner)
          if new_owner
            attributes[:owner] = {
              :display_name => new_owner['DisplayName'],
              :id           => new_owner['ID']
            }
          end
        end

        def public=(new_public)
          new_public
        end

        # Get a url for file.
        #
        #     required attributes: key
        #
        # @param expires [String] number of seconds (since 1970-01-01 00:00) before url expires
        # @param options [Hash]
        # @return [String] url
        #
        def url(expires, options = {})
          requires :directory, :key
          service.create_temp_url(directory.key, key, expires, "GET", options)
        end

        def public_url
          requires :key
          collection.get_url(key)
        end

        def save(options = {})
          requires :directory, :key
          options['Cache-Control'] = cache_control if cache_control
          options['Content-Type'] = content_type if content_type
          options['Content-Disposition'] = content_disposition if content_disposition
          options['Access-Control-Allow-Origin'] = access_control_allow_origin if access_control_allow_origin
          options['Origin'] = origin if origin
          options['X-Delete-At'] = delete_at if delete_at
          options['X-Delete-After'] = delete_after if delete_after
          options['Content-Encoding'] = content_encoding if content_encoding
          options.merge!(metadata_to_headers)

          if not @dirty
            data = service.post_object(directory.key, key, options)
          else
            requires :body
            data = service.put_object(directory.key, key, body, options)
            self.content_length = Fog::Storage.get_body_size(body)
            self.content_type ||= Fog::Storage.get_content_type(body)
          end
          update_attributes_from(data)
          refresh_metadata

          true
        end

        private

        attr_writer :directory

        def refresh_metadata
          metadata.reject! { |_k, v| v.nil? }
        end

        def headers_to_metadata
          key_map = key_mapping
          Hash[metadata_attributes.map { |k, v| [key_map[k], v] }]
        end

        def key_mapping
          key_map = metadata_attributes
          key_map.each_pair { |k, _v| key_map[k] = header_to_key(k) }
        end

        def header_to_key(opt)
          opt.gsub(metadata_prefix, '').split('-').map { |k| k[0, 1].downcase + k[1..-1] }.join('_').to_sym
        end

        def metadata_to_headers
          header_map = header_mapping
          Hash[metadata.map { |k, v| [header_map[k], v] }]
        end

        def header_mapping
          header_map = metadata.dup
          header_map.each_pair { |k, _v| header_map[k] = key_to_header(k) }
        end

        def key_to_header(key)
          metadata_prefix + key.to_s.split(/[-_]/).map(&:capitalize).join('-')
        end

        def metadata_attributes
          if last_modified
            headers = service.head_object(directory.key, key).headers
            headers.reject! { |k, _v| !metadata_attribute?(k) }
          else
            {}
          end
        end

        def metadata_attribute?(key)
          key.to_s =~ /^#{metadata_prefix}/
        end

        def metadata_prefix
          "X-Object-Meta-"
        end

        def update_attributes_from(data)
          merge_attributes(data.headers.reject { |key, _value| ['Content-Length', 'Content-Type'].include?(key) })
        end
      end
    end
  end
end