thingfish 0.5.0.pre20161103181816 → 0.5.0
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.
- checksums.yaml +4 -4
 - checksums.yaml.gz.sig +0 -0
 - data.tar.gz.sig +0 -0
 - data/ChangeLog +8739 -0
 - data/Gemfile +2 -0
 - data/History.rdoc +4 -2
 - data/Manifest.txt +0 -2
 - data/README.rdoc +12 -8
 - data/Rakefile +4 -5
 - data/etc/mongrel2-config.rb +57 -0
 - data/lib/thingfish.rb +1 -12
 - data/lib/thingfish/handler.rb +47 -20
 - data/lib/thingfish/processor/sha256.rb +51 -0
 - data/spec/thingfish/handler_spec.rb +30 -13
 - data/spec/thingfish/processor/{mp3_spec.rb → sha256_spec.rb} +10 -11
 - metadata +11 -22
 - metadata.gz.sig +0 -0
 - data/lib/thingfish/processor/mp3.rb +0 -167
 
    
        data/Gemfile
    ADDED
    
    
    
        data/History.rdoc
    CHANGED
    
    
    
        data/Manifest.txt
    CHANGED
    
    | 
         @@ -22,7 +22,6 @@ lib/thingfish/metastore.rb 
     | 
|
| 
       22 
22 
     | 
    
         
             
            lib/thingfish/metastore/memory.rb
         
     | 
| 
       23 
23 
     | 
    
         
             
            lib/thingfish/mixins.rb
         
     | 
| 
       24 
24 
     | 
    
         
             
            lib/thingfish/processor.rb
         
     | 
| 
       25 
     | 
    
         
            -
            lib/thingfish/processor/mp3.rb
         
     | 
| 
       26 
25 
     | 
    
         
             
            lib/thingfish/processor/sha256.rb
         
     | 
| 
       27 
26 
     | 
    
         
             
            lib/thingfish/processordaemon.rb
         
     | 
| 
       28 
27 
     | 
    
         
             
            lib/thingfish/spechelpers.rb
         
     | 
| 
         @@ -38,7 +37,6 @@ spec/thingfish/handler_spec.rb 
     | 
|
| 
       38 
37 
     | 
    
         
             
            spec/thingfish/metastore/memory_spec.rb
         
     | 
| 
       39 
38 
     | 
    
         
             
            spec/thingfish/metastore_spec.rb
         
     | 
| 
       40 
39 
     | 
    
         
             
            spec/thingfish/mixins_spec.rb
         
     | 
| 
       41 
     | 
    
         
            -
            spec/thingfish/processor/mp3_spec.rb
         
     | 
| 
       42 
40 
     | 
    
         
             
            spec/thingfish/processor/sha256_spec.rb
         
     | 
| 
       43 
41 
     | 
    
         
             
            spec/thingfish/processor_spec.rb
         
     | 
| 
       44 
42 
     | 
    
         
             
            spec/thingfish_spec.rb
         
     | 
    
        data/README.rdoc
    CHANGED
    
    | 
         @@ -26,19 +26,23 @@ fetch it, all through a REST API. 
     | 
|
| 
       26 
26 
     | 
    
         | 
| 
       27 
27 
     | 
    
         
             
            === Requirements
         
     | 
| 
       28 
28 
     | 
    
         | 
| 
       29 
     | 
    
         
            -
            Thingfish is written in ruby, and is tested using version 2. 
     | 
| 
       30 
     | 
    
         
            -
             
     | 
| 
       31 
     | 
    
         
            -
              * Ruby (>= 2.0.0): http://www.ruby-lang.org/en/downloads/
         
     | 
| 
       32 
     | 
    
         
            -
             
     | 
| 
       33 
     | 
    
         
            -
            Other versions may work, but are not tested.
         
     | 
| 
      
 29 
     | 
    
         
            +
            Thingfish is written in ruby, and is tested using {version 2.3}[http://www.ruby-lang.org/en/downloads/]. Other versions may work,
         
     | 
| 
      
 30 
     | 
    
         
            +
            but are not tested.
         
     | 
| 
       34 
31 
     | 
    
         | 
| 
       35 
32 
     | 
    
         
             
            === Ruby Modules
         
     | 
| 
       36 
33 
     | 
    
         | 
| 
       37 
34 
     | 
    
         
             
            You can install Thingfish via the Rubygems package manager:
         
     | 
| 
       38 
35 
     | 
    
         | 
| 
       39 
     | 
    
         
            -
              $  
     | 
| 
      
 36 
     | 
    
         
            +
              $ gem install thingfish
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
            This will install the basic server and its dependencies. Additional functionality is available via separate gems in the following namespaces:
         
     | 
| 
       40 
39 
     | 
    
         | 
| 
       41 
     | 
    
         
            -
             
     | 
| 
      
 40 
     | 
    
         
            +
            [thingfish-metastore-*]
         
     | 
| 
      
 41 
     | 
    
         
            +
              Storage backends for resource metadata
         
     | 
| 
      
 42 
     | 
    
         
            +
            [thingfish-filestore-*]
         
     | 
| 
      
 43 
     | 
    
         
            +
              Storage backends for resources themselves
         
     | 
| 
      
 44 
     | 
    
         
            +
            [thingfish-processor-*]
         
     | 
| 
      
 45 
     | 
    
         
            +
              Filters and extractors for resources
         
     | 
| 
       42 
46 
     | 
    
         | 
| 
       43 
47 
     | 
    
         | 
| 
       44 
48 
     | 
    
         
             
            == Contributing
         
     | 
| 
         @@ -61,7 +65,7 @@ You can submit bug reports, suggestions, and read more about future plans at 
     | 
|
| 
       61 
65 
     | 
    
         | 
| 
       62 
66 
     | 
    
         
             
            == License
         
     | 
| 
       63 
67 
     | 
    
         | 
| 
       64 
     | 
    
         
            -
            Copyright (c) 2007- 
     | 
| 
      
 68 
     | 
    
         
            +
            Copyright (c) 2007-2016, Michael Granger and Mahlon E. Smith
         
     | 
| 
       65 
69 
     | 
    
         
             
            All rights reserved.
         
     | 
| 
       66 
70 
     | 
    
         | 
| 
       67 
71 
     | 
    
         
             
            Redistribution and use in source and binary forms, with or without
         
     | 
    
        data/Rakefile
    CHANGED
    
    | 
         @@ -26,12 +26,11 @@ hoespec = Hoe.spec 'thingfish' do 
     | 
|
| 
       26 
26 
     | 
    
         
             
            	self.developer 'Mahlon E. Smith', 'mahlon@martini.nu'
         
     | 
| 
       27 
27 
     | 
    
         
             
            	self.license "BSD"
         
     | 
| 
       28 
28 
     | 
    
         | 
| 
       29 
     | 
    
         
            -
            	self.dependency 'strelka', 
     | 
| 
       30 
     | 
    
         
            -
            	self.dependency 'mongrel2', 
     | 
| 
      
 29 
     | 
    
         
            +
            	self.dependency 'strelka',      '~> 0.9'
         
     | 
| 
      
 30 
     | 
    
         
            +
            	self.dependency 'mongrel2',     '~> 0.46'
         
     | 
| 
       31 
31 
     | 
    
         | 
| 
       32 
     | 
    
         
            -
            	self.dependency 'hoe-deveiate', 
     | 
| 
       33 
     | 
    
         
            -
            	self.dependency 'simplecov', 
     | 
| 
       34 
     | 
    
         
            -
            	self.dependency 'ruby-mp3info',    '~> 0.8',  :development
         
     | 
| 
      
 32 
     | 
    
         
            +
            	self.dependency 'hoe-deveiate', '~> 0.3',  :development
         
     | 
| 
      
 33 
     | 
    
         
            +
            	self.dependency 'simplecov',    '~> 0.7',  :development
         
     | 
| 
       35 
34 
     | 
    
         | 
| 
       36 
35 
     | 
    
         
             
            	self.require_ruby_version( '>=2.0.0' )
         
     | 
| 
       37 
36 
     | 
    
         | 
| 
         @@ -0,0 +1,57 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # -*- ruby -*-
         
     | 
| 
      
 2 
     | 
    
         
            +
            # vim: set nosta noet ts=4 sw=4:
         
     | 
| 
      
 3 
     | 
    
         
            +
            #encoding: utf-8
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            #
         
     | 
| 
      
 6 
     | 
    
         
            +
            # This script generates a Mongrel2 configuration database suitable for
         
     | 
| 
      
 7 
     | 
    
         
            +
            # getting a Thingfish handler running.
         
     | 
| 
      
 8 
     | 
    
         
            +
            #
         
     | 
| 
      
 9 
     | 
    
         
            +
            # Load it with:
         
     | 
| 
      
 10 
     | 
    
         
            +
            #
         
     | 
| 
      
 11 
     | 
    
         
            +
            #     $ m2sh.rb -c mongrel2.sqlite load examples/mongrel2-config.rb
         
     | 
| 
      
 12 
     | 
    
         
            +
            #
         
     | 
| 
      
 13 
     | 
    
         
            +
            # Afterwards, ensure the path to the mongrel2.sqlite file is in your
         
     | 
| 
      
 14 
     | 
    
         
            +
            # thingfish.conf:
         
     | 
| 
      
 15 
     | 
    
         
            +
            #
         
     | 
| 
      
 16 
     | 
    
         
            +
            #     mongrel2:
         
     | 
| 
      
 17 
     | 
    
         
            +
            #       configdb: /path/to/mongrel2.sqlite
         
     | 
| 
      
 18 
     | 
    
         
            +
            #
         
     | 
| 
      
 19 
     | 
    
         
            +
            # ... and start the mongrel2 daemon:
         
     | 
| 
      
 20 
     | 
    
         
            +
            #
         
     | 
| 
      
 21 
     | 
    
         
            +
            #     $ mongrel2 /path/to/mongrel2.sqlite thingfish
         
     | 
| 
      
 22 
     | 
    
         
            +
            #
         
     | 
| 
      
 23 
     | 
    
         
            +
            # In production use, you'll likely want to mount the Thingfish handler
         
     | 
| 
      
 24 
     | 
    
         
            +
            # within the URI space of an existing Mongrel2 environment.
         
     | 
| 
      
 25 
     | 
    
         
            +
            #
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
            require 'mongrel2'
         
     | 
| 
      
 28 
     | 
    
         
            +
            require 'mongrel2/config/dsl'
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
            server 'thingfish' do
         
     | 
| 
      
 31 
     | 
    
         
            +
            	name         'Thingfish'
         
     | 
| 
      
 32 
     | 
    
         
            +
            	default_host 'localhost'
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
            	access_log   'logs/access.log'
         
     | 
| 
      
 35 
     | 
    
         
            +
            	error_log    'logs/error.log'
         
     | 
| 
      
 36 
     | 
    
         
            +
            	chroot       ''
         
     | 
| 
      
 37 
     | 
    
         
            +
            	pid_file     'run/mongrel2.pid'
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
            	bind_addr    '0.0.0.0'
         
     | 
| 
      
 40 
     | 
    
         
            +
            	port         3474
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
            	xrequest     '/usr/local/lib/mongrel2/filters/sendfile.so'
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
            	host 'localhost' do
         
     | 
| 
      
 45 
     | 
    
         
            +
            		route '/', handler( 'tcp://127.0.0.1:9900', 'thingfish' )
         
     | 
| 
      
 46 
     | 
    
         
            +
            	end
         
     | 
| 
      
 47 
     | 
    
         
            +
            end
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
            setting 'zeromq.threads', 1
         
     | 
| 
      
 50 
     | 
    
         
            +
            setting 'limits.content_length', 250_000
         
     | 
| 
      
 51 
     | 
    
         
            +
            setting 'server.daemonize', false
         
     | 
| 
      
 52 
     | 
    
         
            +
            setting 'upload.temp_store', 'var/uploads/mongrel2.upload.XXXXXX'
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
            mkdir_p 'var/uploads'
         
     | 
| 
      
 55 
     | 
    
         
            +
            mkdir_p 'run'
         
     | 
| 
      
 56 
     | 
    
         
            +
            mkdir_p 'logs'
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
    
        data/lib/thingfish.rb
    CHANGED
    
    | 
         @@ -2,18 +2,7 @@ 
     | 
|
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
            require 'loggability'
         
     | 
| 
       4 
4 
     | 
    
         | 
| 
       5 
     | 
    
         
            -
            #
         
     | 
| 
       6 
5 
     | 
    
         
             
            # Network-accessable datastore service
         
     | 
| 
       7 
     | 
    
         
            -
            #
         
     | 
| 
       8 
     | 
    
         
            -
            # == Version
         
     | 
| 
       9 
     | 
    
         
            -
            #
         
     | 
| 
       10 
     | 
    
         
            -
            #  $Id: thingfish.rb,v ce172208b523 2013/11/20 02:21:12 ged $
         
     | 
| 
       11 
     | 
    
         
            -
            #
         
     | 
| 
       12 
     | 
    
         
            -
            # == Authors
         
     | 
| 
       13 
     | 
    
         
            -
            #
         
     | 
| 
       14 
     | 
    
         
            -
            # * Michael Granger <ged@FaerieMUD.org>
         
     | 
| 
       15 
     | 
    
         
            -
            # * Mahlon E. Smith <mahlon@martini.nu>
         
     | 
| 
       16 
     | 
    
         
            -
            #
         
     | 
| 
       17 
6 
     | 
    
         
             
            module Thingfish
         
     | 
| 
       18 
7 
     | 
    
         
             
            	extend Loggability
         
     | 
| 
       19 
8 
     | 
    
         | 
| 
         @@ -26,7 +15,7 @@ module Thingfish 
     | 
|
| 
       26 
15 
     | 
    
         
             
            	VERSION = '0.5.0'
         
     | 
| 
       27 
16 
     | 
    
         | 
| 
       28 
17 
     | 
    
         
             
            	# Version control revision
         
     | 
| 
       29 
     | 
    
         
            -
            	REVISION = %q$Revision:  
     | 
| 
      
 18 
     | 
    
         
            +
            	REVISION = %q$Revision: 3607a807e2bf $
         
     | 
| 
       30 
19 
     | 
    
         | 
| 
       31 
20 
     | 
    
         | 
| 
       32 
21 
     | 
    
         
             
            	### Get the library version. If +include_buildnum+ is true, the version string will
         
     | 
    
        data/lib/thingfish/handler.rb
    CHANGED
    
    | 
         @@ -193,7 +193,7 @@ class Thingfish::Handler < Strelka::App 
     | 
|
| 
       193 
193 
     | 
    
         
             
            		"The name(s) of the fields to order results by."
         
     | 
| 
       194 
194 
     | 
    
         
             
            	param :direction, /^(asc|desc)$/i, "The order direction (ascending or descending)"
         
     | 
| 
       195 
195 
     | 
    
         
             
            	param :casefold, :boolean, "Whether or not to convert to lowercase before matching"
         
     | 
| 
       196 
     | 
    
         
            -
            	param :relationship,  
     | 
| 
      
 196 
     | 
    
         
            +
            	param :relationship, /^[\w\-]+$/, "The name of the relationship between two resources"
         
     | 
| 
       197 
197 
     | 
    
         | 
| 
       198 
198 
     | 
    
         | 
| 
       199 
199 
     | 
    
         
             
            	#
         
     | 
| 
         @@ -316,6 +316,9 @@ class Thingfish::Handler < Strelka::App 
     | 
|
| 
       316 
316 
     | 
    
         | 
| 
       317 
317 
     | 
    
         
             
            		finish_with( HTTP::NOT_FOUND, "No such object." ) unless self.metastore.include?( uuid )
         
     | 
| 
       318 
318 
     | 
    
         | 
| 
      
 319 
     | 
    
         
            +
            		primary_metadata = self.metastore.fetch( uuid )
         
     | 
| 
      
 320 
     | 
    
         
            +
            		self.check_resource_permissions( req, uuid, primary_metadata )
         
     | 
| 
      
 321 
     | 
    
         
            +
             
     | 
| 
       319 
322 
     | 
    
         
             
            		criteria = {
         
     | 
| 
       320 
323 
     | 
    
         
             
            			'relation' => uuid,
         
     | 
| 
       321 
324 
     | 
    
         
             
            			'relationship' => rel,
         
     | 
| 
         @@ -328,6 +331,9 @@ class Thingfish::Handler < Strelka::App 
     | 
|
| 
       328 
331 
     | 
    
         
             
            		metadata = self.metastore.fetch( uuid )
         
     | 
| 
       329 
332 
     | 
    
         | 
| 
       330 
333 
     | 
    
         
             
            		res = req.response
         
     | 
| 
      
 334 
     | 
    
         
            +
            		self.add_etag_headers( req, metadata )
         
     | 
| 
      
 335 
     | 
    
         
            +
            		self.add_content_disposition( res, metadata )
         
     | 
| 
      
 336 
     | 
    
         
            +
             
     | 
| 
       331 
337 
     | 
    
         
             
            		res.body = object
         
     | 
| 
       332 
338 
     | 
    
         
             
            		res.content_type = metadata['format']
         
     | 
| 
       333 
339 
     | 
    
         | 
| 
         @@ -349,6 +355,7 @@ class Thingfish::Handler < Strelka::App 
     | 
|
| 
       349 
355 
     | 
    
         
             
            		res.content_type = metadata['format']
         
     | 
| 
       350 
356 
     | 
    
         | 
| 
       351 
357 
     | 
    
         
             
            		self.add_etag_headers( req, metadata )
         
     | 
| 
      
 358 
     | 
    
         
            +
            		self.add_content_disposition( res, metadata )
         
     | 
| 
       352 
359 
     | 
    
         | 
| 
       353 
360 
     | 
    
         
             
            		if object.respond_to?( :path )
         
     | 
| 
       354 
361 
     | 
    
         
             
            			path = Pathname( object.path )
         
     | 
| 
         @@ -411,9 +418,9 @@ class Thingfish::Handler < Strelka::App 
     | 
|
| 
       411 
418 
     | 
    
         | 
| 
       412 
419 
     | 
    
         
             
            		self.check_resource_permissions( req, uuid )
         
     | 
| 
       413 
420 
     | 
    
         | 
| 
       414 
     | 
    
         
            -
            		self.datastore.remove( uuid ) or finish_with( HTTP::NOT_FOUND, "No such object." )
         
     | 
| 
       415 
     | 
    
         
            -
            		metadata = self.metastore.remove( uuid )
         
     | 
| 
       416 
421 
     | 
    
         
             
            		self.remove_related_resources( uuid )
         
     | 
| 
      
 422 
     | 
    
         
            +
            		metadata = self.metastore.remove( uuid )
         
     | 
| 
      
 423 
     | 
    
         
            +
            		self.datastore.remove( uuid ) or finish_with( HTTP::NOT_FOUND, "No such object." )
         
     | 
| 
       417 
424 
     | 
    
         
             
            		self.send_event( :deleted, :uuid => uuid )
         
     | 
| 
       418 
425 
     | 
    
         | 
| 
       419 
426 
     | 
    
         
             
            		res = req.response
         
     | 
| 
         @@ -441,8 +448,7 @@ class Thingfish::Handler < Strelka::App 
     | 
|
| 
       441 
448 
     | 
    
         | 
| 
       442 
449 
     | 
    
         
             
            		finish_with( HTTP::NOT_FOUND, "No such object." ) unless self.metastore.include?( uuid )
         
     | 
| 
       443 
450 
     | 
    
         | 
| 
       444 
     | 
    
         
            -
            		metadata = self. 
     | 
| 
       445 
     | 
    
         
            -
            		metadata[ 'oid' ] = uuid
         
     | 
| 
      
 451 
     | 
    
         
            +
            		metadata = self.normalized_metadata_for( uuid )
         
     | 
| 
       446 
452 
     | 
    
         
             
            		self.check_resource_permissions( req, uuid, metadata )
         
     | 
| 
       447 
453 
     | 
    
         | 
| 
       448 
454 
     | 
    
         
             
            		res = req.response
         
     | 
| 
         @@ -538,13 +544,17 @@ class Thingfish::Handler < Strelka::App 
     | 
|
| 
       538 
544 
     | 
    
         
             
            		metadata = self.metastore.fetch( uuid )
         
     | 
| 
       539 
545 
     | 
    
         
             
            		self.check_resource_permissions( req, uuid, metadata )
         
     | 
| 
       540 
546 
     | 
    
         | 
| 
       541 
     | 
    
         
            -
            		op_metadata 
     | 
| 
      
 547 
     | 
    
         
            +
            		op_metadata  = self.metastore.fetch( uuid, *OPERATIONAL_METADATA_KEYS )
         
     | 
| 
       542 
548 
     | 
    
         
             
            		new_metadata = self.extract_metadata( req )
         
     | 
| 
       543 
     | 
    
         
            -
            		self.metastore. 
     | 
| 
      
 549 
     | 
    
         
            +
            		self.metastore.transaction do
         
     | 
| 
      
 550 
     | 
    
         
            +
            			self.metastore.remove_except( uuid, *OPERATIONAL_METADATA_KEYS )
         
     | 
| 
      
 551 
     | 
    
         
            +
            			self.metastore.merge( uuid, new_metadata.merge(op_metadata) )
         
     | 
| 
      
 552 
     | 
    
         
            +
            		end
         
     | 
| 
       544 
553 
     | 
    
         
             
            		self.send_event( :metadata_replaced, :uuid => uuid )
         
     | 
| 
       545 
554 
     | 
    
         | 
| 
       546 
555 
     | 
    
         
             
            		res = req.response
         
     | 
| 
       547 
     | 
    
         
            -
            		res.status = HTTP:: 
     | 
| 
      
 556 
     | 
    
         
            +
            		res.status = HTTP::OK
         
     | 
| 
      
 557 
     | 
    
         
            +
            		res.for( :json, :yaml ) { self.normalized_metadata_for(uuid) }
         
     | 
| 
       548 
558 
     | 
    
         | 
| 
       549 
559 
     | 
    
         
             
            		return res
         
     | 
| 
       550 
560 
     | 
    
         
             
            	end
         
     | 
| 
         @@ -565,7 +575,8 @@ class Thingfish::Handler < Strelka::App 
     | 
|
| 
       565 
575 
     | 
    
         
             
            		self.send_event( :metadata_updated, :uuid => uuid )
         
     | 
| 
       566 
576 
     | 
    
         | 
| 
       567 
577 
     | 
    
         
             
            		res = req.response
         
     | 
| 
       568 
     | 
    
         
            -
            		res.status = HTTP:: 
     | 
| 
      
 578 
     | 
    
         
            +
            		res.status = HTTP::OK
         
     | 
| 
      
 579 
     | 
    
         
            +
            		res.for( :json, :yaml ) { self.normalized_metadata_for(uuid) }
         
     | 
| 
       569 
580 
     | 
    
         | 
| 
       570 
581 
     | 
    
         
             
            		return res
         
     | 
| 
       571 
582 
     | 
    
         
             
            	end
         
     | 
| 
         @@ -585,7 +596,8 @@ class Thingfish::Handler < Strelka::App 
     | 
|
| 
       585 
596 
     | 
    
         
             
            		self.send_event( :metadata_deleted, :uuid => uuid )
         
     | 
| 
       586 
597 
     | 
    
         | 
| 
       587 
598 
     | 
    
         
             
            		res = req.response
         
     | 
| 
       588 
     | 
    
         
            -
            		res.status = HTTP:: 
     | 
| 
      
 599 
     | 
    
         
            +
            		res.status = HTTP::OK
         
     | 
| 
      
 600 
     | 
    
         
            +
            		res.for( :json, :yaml ) { self.normalized_metadata_for(uuid) }
         
     | 
| 
       589 
601 
     | 
    
         | 
| 
       590 
602 
     | 
    
         
             
            		return res
         
     | 
| 
       591 
603 
     | 
    
         
             
            	end
         
     | 
| 
         @@ -626,8 +638,8 @@ class Thingfish::Handler < Strelka::App 
     | 
|
| 
       626 
638 
     | 
    
         
             
            		metadata.merge!( self.extract_header_metadata(request) )
         
     | 
| 
       627 
639 
     | 
    
         
             
            		metadata.merge!( self.extract_default_metadata(request) )
         
     | 
| 
       628 
640 
     | 
    
         | 
| 
       629 
     | 
    
         
            -
            		self.verify_operational_metadata( metadata )
         
     | 
| 
       630 
641 
     | 
    
         
             
            		self.check_resource_permissions( request, uuid, metadata )
         
     | 
| 
      
 642 
     | 
    
         
            +
            		self.verify_operational_metadata( metadata )
         
     | 
| 
       631 
643 
     | 
    
         | 
| 
       632 
644 
     | 
    
         
             
            		if uuid
         
     | 
| 
       633 
645 
     | 
    
         
             
            			self.log.info "Replacing resource %s (encoding: %p)" %
         
     | 
| 
         @@ -722,15 +734,7 @@ class Thingfish::Handler < Strelka::App 
     | 
|
| 
       722 
734 
     | 
    
         
             
            	### Extract and validate supplied metadata from the +request+.
         
     | 
| 
       723 
735 
     | 
    
         
             
            	def extract_metadata( req )
         
     | 
| 
       724 
736 
     | 
    
         
             
            		new_metadata = req.params.fields.dup
         
     | 
| 
       725 
     | 
    
         
            -
            		new_metadata. 
     | 
| 
       726 
     | 
    
         
            -
             
     | 
| 
       727 
     | 
    
         
            -
            		protected_keys = OPERATIONAL_METADATA_KEYS & new_metadata.keys
         
     | 
| 
       728 
     | 
    
         
            -
             
     | 
| 
       729 
     | 
    
         
            -
            		unless protected_keys.empty?
         
     | 
| 
       730 
     | 
    
         
            -
            			finish_with HTTP::FORBIDDEN,
         
     | 
| 
       731 
     | 
    
         
            -
            				"Unable to alter protected metadata. (%s)" % [ protected_keys.join(', ') ]
         
     | 
| 
       732 
     | 
    
         
            -
            		end
         
     | 
| 
       733 
     | 
    
         
            -
             
     | 
| 
      
 737 
     | 
    
         
            +
            		new_metadata = self.remove_operational_metadata( new_metadata )
         
     | 
| 
       734 
738 
     | 
    
         
             
            		return new_metadata
         
     | 
| 
       735 
739 
     | 
    
         
             
            	end
         
     | 
| 
       736 
740 
     | 
    
         | 
| 
         @@ -750,6 +754,13 @@ class Thingfish::Handler < Strelka::App 
     | 
|
| 
       750 
754 
     | 
    
         
             
            	end
         
     | 
| 
       751 
755 
     | 
    
         | 
| 
       752 
756 
     | 
    
         | 
| 
      
 757 
     | 
    
         
            +
            	### Fetch the current metadata for +uuid+, altering it for easier
         
     | 
| 
      
 758 
     | 
    
         
            +
            	### round trips with REST.
         
     | 
| 
      
 759 
     | 
    
         
            +
            	def normalized_metadata_for( uuid )
         
     | 
| 
      
 760 
     | 
    
         
            +
            		return self.metastore.fetch(uuid).merge( 'uuid' => uuid )
         
     | 
| 
      
 761 
     | 
    
         
            +
            	end
         
     | 
| 
      
 762 
     | 
    
         
            +
             
     | 
| 
      
 763 
     | 
    
         
            +
             
     | 
| 
       753 
764 
     | 
    
         
             
            	### Check that the metadata provided contains valid values for
         
     | 
| 
       754 
765 
     | 
    
         
             
            	### the operational keys, before saving a resource to disk.
         
     | 
| 
       755 
766 
     | 
    
         
             
            	def verify_operational_metadata( metadata )
         
     | 
| 
         @@ -759,6 +770,13 @@ class Thingfish::Handler < Strelka::App 
     | 
|
| 
       759 
770 
     | 
    
         
             
            	end
         
     | 
| 
       760 
771 
     | 
    
         | 
| 
       761 
772 
     | 
    
         | 
| 
      
 773 
     | 
    
         
            +
            	### Prune operational +metadata+ from the provided hash.
         
     | 
| 
      
 774 
     | 
    
         
            +
            	def remove_operational_metadata( metadata )
         
     | 
| 
      
 775 
     | 
    
         
            +
            		operationals = OPERATIONAL_METADATA_KEYS + [ 'uuid' ]
         
     | 
| 
      
 776 
     | 
    
         
            +
            		return metadata.reject{|key, _| operationals.include?(key) }
         
     | 
| 
      
 777 
     | 
    
         
            +
            	end
         
     | 
| 
      
 778 
     | 
    
         
            +
             
     | 
| 
      
 779 
     | 
    
         
            +
             
     | 
| 
       762 
780 
     | 
    
         
             
            	### Send an event of +type+ with the given +msg+ over the zmq event socket.
         
     | 
| 
       763 
781 
     | 
    
         
             
            	def send_event( type, msg )
         
     | 
| 
       764 
782 
     | 
    
         
             
            		esock = self.event_socket or return
         
     | 
| 
         @@ -785,6 +803,15 @@ class Thingfish::Handler < Strelka::App 
     | 
|
| 
       785 
803 
     | 
    
         
             
            	end
         
     | 
| 
       786 
804 
     | 
    
         | 
| 
       787 
805 
     | 
    
         | 
| 
      
 806 
     | 
    
         
            +
            	### Add a filename "hint" for browsers, if the resource being fetched
         
     | 
| 
      
 807 
     | 
    
         
            +
            	### has a 'title' attribute.
         
     | 
| 
      
 808 
     | 
    
         
            +
            	def add_content_disposition( res, metadata )
         
     | 
| 
      
 809 
     | 
    
         
            +
            		return unless metadata[ 'title' ]
         
     | 
| 
      
 810 
     | 
    
         
            +
            		title = metadata[ 'title' ].encode( 'us-ascii', :undef => :replace )
         
     | 
| 
      
 811 
     | 
    
         
            +
            		res.headers[ :content_disposition ] = "filename=%p" % [ title ]
         
     | 
| 
      
 812 
     | 
    
         
            +
            	end
         
     | 
| 
      
 813 
     | 
    
         
            +
             
     | 
| 
      
 814 
     | 
    
         
            +
             
     | 
| 
       788 
815 
     | 
    
         
             
            	### Supply a method that child handlers can override.  The regular auth
         
     | 
| 
       789 
816 
     | 
    
         
             
            	### plugin runs too early (but can also be used), this hook allows
         
     | 
| 
       790 
817 
     | 
    
         
             
            	### child handlers to make access decisions based on the +request+
         
     | 
| 
         @@ -0,0 +1,51 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # -*- ruby -*-
         
     | 
| 
      
 2 
     | 
    
         
            +
            #encoding: utf-8
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            require 'digest/sha2'
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            require 'thingfish' unless defined?( Thingfish )
         
     | 
| 
      
 7 
     | 
    
         
            +
            require 'thingfish/processor' unless defined?( Thingfish::Processor )
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
            # Calculate and store a sha256 checksum for a resource.
         
     | 
| 
      
 11 
     | 
    
         
            +
            class Thingfish::Processor::SHA256 < Thingfish::Processor
         
     | 
| 
      
 12 
     | 
    
         
            +
            	extend Loggability
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
            	# The chunk size to read
         
     | 
| 
      
 15 
     | 
    
         
            +
            	CHUNK_SIZE = 32 * 1024
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
            	# Loggability API -- log to the :thingfish logger
         
     | 
| 
      
 18 
     | 
    
         
            +
            	log_to :thingfish
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
            	# The list of handled types
         
     | 
| 
      
 21 
     | 
    
         
            +
            	handled_types '*/*'
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
            	### Synchronous processor API -- generate a checksum during upload.
         
     | 
| 
      
 25 
     | 
    
         
            +
            	def on_request( request )
         
     | 
| 
      
 26 
     | 
    
         
            +
            		request.add_metadata( :checksum => self.checksum(request.body) )
         
     | 
| 
      
 27 
     | 
    
         
            +
            		request.related_resources.each_pair do |io, metadata|
         
     | 
| 
      
 28 
     | 
    
         
            +
            			metadata[ :checksum ] = self.checksum( io )
         
     | 
| 
      
 29 
     | 
    
         
            +
            		end
         
     | 
| 
      
 30 
     | 
    
         
            +
            	end
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
            	#########
         
     | 
| 
      
 34 
     | 
    
         
            +
            	protected
         
     | 
| 
      
 35 
     | 
    
         
            +
            	#########
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
            	### Given an +io+, return a sha256 checksum of it's contents.
         
     | 
| 
      
 38 
     | 
    
         
            +
            	def checksum( io )
         
     | 
| 
      
 39 
     | 
    
         
            +
            		digest = Digest::SHA256.new
         
     | 
| 
      
 40 
     | 
    
         
            +
            		buf = ''
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
            		while io.read( CHUNK_SIZE, buf )
         
     | 
| 
      
 43 
     | 
    
         
            +
            			digest.update( buf )
         
     | 
| 
      
 44 
     | 
    
         
            +
            		end
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
            		io.rewind
         
     | 
| 
      
 47 
     | 
    
         
            +
            		return digest.hexdigest
         
     | 
| 
      
 48 
     | 
    
         
            +
            	end
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
            end # class Thingfish::Processor::SHA256
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
         @@ -277,7 +277,9 @@ describe Thingfish::Handler do 
     | 
|
| 
       277 
277 
     | 
    
         
             
            				'format'       => 'image/png',
         
     | 
| 
       278 
278 
     | 
    
         
             
            				'extent'       => @png_io.string.bytesize,
         
     | 
| 
       279 
279 
     | 
    
         
             
            				'relation'     => main_uuid,
         
     | 
| 
       280 
     | 
    
         
            -
            				'relationship' => "twinsies"
         
     | 
| 
      
 280 
     | 
    
         
            +
            				'relationship' => "twinsies",
         
     | 
| 
      
 281 
     | 
    
         
            +
            				'title'        => 'Make America Smart Again.png',
         
     | 
| 
      
 282 
     | 
    
         
            +
            				'checksum'     => '123456'
         
     | 
| 
       281 
283 
     | 
    
         
             
            			})
         
     | 
| 
       282 
284 
     | 
    
         | 
| 
       283 
285 
     | 
    
         
             
            			req = factory.get( "/#{main_uuid}/related/twinsies" )
         
     | 
| 
         @@ -285,6 +287,8 @@ describe Thingfish::Handler do 
     | 
|
| 
       285 
287 
     | 
    
         | 
| 
       286 
288 
     | 
    
         
             
            			expect( res.status_line ).to match( /200 ok/i )
         
     | 
| 
       287 
289 
     | 
    
         
             
            			expect( res.headers.content_type ).to eq( 'image/png' )
         
     | 
| 
      
 290 
     | 
    
         
            +
            			expect( res.headers.etag ).to eq( '123456' )
         
     | 
| 
      
 291 
     | 
    
         
            +
            			expect( res.headers.content_disposition ).to eq( 'filename="Make America Smart Again.png"' )
         
     | 
| 
       288 
292 
     | 
    
         
             
            			expect( res.body.read ).to eq( TEST_PNG_DATA )
         
     | 
| 
       289 
293 
     | 
    
         
             
            		end
         
     | 
| 
       290 
294 
     | 
    
         | 
| 
         @@ -367,6 +371,20 @@ describe Thingfish::Handler do 
     | 
|
| 
       367 
371 
     | 
    
         
             
            		end
         
     | 
| 
       368 
372 
     | 
    
         | 
| 
       369 
373 
     | 
    
         | 
| 
      
 374 
     | 
    
         
            +
            		it "adds content disposition filename, if the resource has a title" do
         
     | 
| 
      
 375 
     | 
    
         
            +
            			uuid = @handler.datastore.save( @png_io )
         
     | 
| 
      
 376 
     | 
    
         
            +
            			@handler.metastore.save( uuid, {'format' => 'image/png', 'title' => 'spょler"py.txt'} )
         
     | 
| 
      
 377 
     | 
    
         
            +
             
     | 
| 
      
 378 
     | 
    
         
            +
            			req = factory.get( "/#{uuid}" )
         
     | 
| 
      
 379 
     | 
    
         
            +
            			result = @handler.handle( req )
         
     | 
| 
      
 380 
     | 
    
         
            +
             
     | 
| 
      
 381 
     | 
    
         
            +
            			expect( result.status_line ).to match( /200 ok/i )
         
     | 
| 
      
 382 
     | 
    
         
            +
            			expect( result.body.read ).to eq( @png_io.string )
         
     | 
| 
      
 383 
     | 
    
         
            +
            			expect( result.headers.content_type ).to eq( 'image/png' )
         
     | 
| 
      
 384 
     | 
    
         
            +
            			expect( result.headers.content_disposition ).to eq( 'filename="sp?ler\"py.txt"' )
         
     | 
| 
      
 385 
     | 
    
         
            +
            		end
         
     | 
| 
      
 386 
     | 
    
         
            +
             
     | 
| 
      
 387 
     | 
    
         
            +
             
     | 
| 
       370 
388 
     | 
    
         
             
            		it "returns a 304 not modified for unchanged client cache requests" do
         
     | 
| 
       371 
389 
     | 
    
         
             
            			uuid = @handler.datastore.save( @png_io )
         
     | 
| 
       372 
390 
     | 
    
         
             
            			@handler.metastore.save( uuid, 'format' => 'image/png', 'checksum' => '123456' )
         
     | 
| 
         @@ -433,7 +451,7 @@ describe Thingfish::Handler do 
     | 
|
| 
       433 
451 
     | 
    
         
             
            			expect( result.status ).to eq( 200 )
         
     | 
| 
       434 
452 
     | 
    
         
             
            			expect( result.headers.content_type ).to eq( 'application/json' )
         
     | 
| 
       435 
453 
     | 
    
         
             
            			expect( content_hash ).to be_a( Hash )
         
     | 
| 
       436 
     | 
    
         
            -
            			expect( content_hash[' 
     | 
| 
      
 454 
     | 
    
         
            +
            			expect( content_hash['uuid'] ).to eq( uuid )
         
     | 
| 
       437 
455 
     | 
    
         
             
            			expect( content_hash['extent'] ).to eq( 288 )
         
     | 
| 
       438 
456 
     | 
    
         
             
            			expect( content_hash['created'] ).to eq( Time.at(1378313840).to_s )
         
     | 
| 
       439 
457 
     | 
    
         
             
            		end
         
     | 
| 
         @@ -496,19 +514,20 @@ describe Thingfish::Handler do 
     | 
|
| 
       496 
514 
     | 
    
         
             
            			uuid = @handler.datastore.save( @png_io )
         
     | 
| 
       497 
515 
     | 
    
         
             
            			@handler.metastore.save( uuid, {
         
     | 
| 
       498 
516 
     | 
    
         
             
            				'format' => 'image/png',
         
     | 
| 
       499 
     | 
    
         
            -
            				'extent' => 288 
     | 
| 
      
 517 
     | 
    
         
            +
            				'extent' => 288
         
     | 
| 
       500 
518 
     | 
    
         
             
            			})
         
     | 
| 
       501 
519 
     | 
    
         | 
| 
       502 
     | 
    
         
            -
            			body_json = Yajl.dump({ 'comment' => 'Ignore me!' })
         
     | 
| 
      
 520 
     | 
    
         
            +
            			body_json = Yajl.dump({ 'comment' => 'Ignore me!', 'uuid' => 123 })
         
     | 
| 
       503 
521 
     | 
    
         
             
            			req = factory.post( "/#{uuid}/metadata", body_json, 'Content-type' => 'application/json' )
         
     | 
| 
       504 
522 
     | 
    
         
             
            			result = @handler.handle( req )
         
     | 
| 
       505 
523 
     | 
    
         | 
| 
       506 
     | 
    
         
            -
            			expect( result.status ).to eq( HTTP:: 
     | 
| 
      
 524 
     | 
    
         
            +
            			expect( result.status ).to eq( HTTP::OK )
         
     | 
| 
       507 
525 
     | 
    
         
             
            			expect( @handler.metastore.fetch_value(uuid, 'comment') ).to eq( 'Ignore me!' )
         
     | 
| 
      
 526 
     | 
    
         
            +
            			expect( @handler.metastore.fetch_value(uuid, 'uuid') ).to be_nil
         
     | 
| 
       508 
527 
     | 
    
         
             
            		end
         
     | 
| 
       509 
528 
     | 
    
         | 
| 
       510 
529 
     | 
    
         | 
| 
       511 
     | 
    
         
            -
            		it " 
     | 
| 
      
 530 
     | 
    
         
            +
            		it "ignores attempts to alter operational metadata when merging" do
         
     | 
| 
       512 
531 
     | 
    
         
             
            			uuid = @handler.datastore.save( @png_io )
         
     | 
| 
       513 
532 
     | 
    
         
             
            			@handler.metastore.save( uuid, {
         
     | 
| 
       514 
533 
     | 
    
         
             
            				'format' => 'image/png',
         
     | 
| 
         @@ -519,10 +538,8 @@ describe Thingfish::Handler do 
     | 
|
| 
       519 
538 
     | 
    
         
             
            			req = factory.post( "/#{uuid}/metadata", body_json, 'Content-type' => 'application/json' )
         
     | 
| 
       520 
539 
     | 
    
         
             
            			result = @handler.handle( req )
         
     | 
| 
       521 
540 
     | 
    
         | 
| 
       522 
     | 
    
         
            -
            			expect( result.status ).to eq( HTTP:: 
     | 
| 
       523 
     | 
    
         
            -
            			expect(  
     | 
| 
       524 
     | 
    
         
            -
            			expect( result.body.string ).to match( /format/i )
         
     | 
| 
       525 
     | 
    
         
            -
            			expect( @handler.metastore.fetch_value(uuid, 'comment') ).to be_nil
         
     | 
| 
      
 541 
     | 
    
         
            +
            			expect( result.status ).to eq( HTTP::OK )
         
     | 
| 
      
 542 
     | 
    
         
            +
            			expect( @handler.metastore.fetch_value(uuid, 'comment') ).to eq( 'Ignore me!' )
         
     | 
| 
       526 
543 
     | 
    
         
             
            			expect( @handler.metastore.fetch_value(uuid, 'format') ).to eq( 'image/png' )
         
     | 
| 
       527 
544 
     | 
    
         
             
            		end
         
     | 
| 
       528 
545 
     | 
    
         | 
| 
         @@ -630,7 +647,7 @@ describe Thingfish::Handler do 
     | 
|
| 
       630 
647 
     | 
    
         
             
            			                   'Content-type' => 'application/json' )
         
     | 
| 
       631 
648 
     | 
    
         
             
            			result = @handler.handle( req )
         
     | 
| 
       632 
649 
     | 
    
         | 
| 
       633 
     | 
    
         
            -
            			expect( result.status ).to eq( HTTP:: 
     | 
| 
      
 650 
     | 
    
         
            +
            			expect( result.status ).to eq( HTTP::OK )
         
     | 
| 
       634 
651 
     | 
    
         
             
            			expect( @handler.metastore.fetch_value(uuid, 'comment') ).to eq( 'Yeah.' )
         
     | 
| 
       635 
652 
     | 
    
         
             
            			expect( @handler.metastore.fetch_value(uuid, 'format') ).to eq( 'image/png' )
         
     | 
| 
       636 
653 
     | 
    
         
             
            			expect( @handler.metastore ).to_not include( 'ephemeral' )
         
     | 
| 
         @@ -652,8 +669,8 @@ describe Thingfish::Handler do 
     | 
|
| 
       652 
669 
     | 
    
         
             
            			req = factory.delete( "/#{uuid}/metadata" )
         
     | 
| 
       653 
670 
     | 
    
         
             
            			result = @handler.handle( req )
         
     | 
| 
       654 
671 
     | 
    
         | 
| 
       655 
     | 
    
         
            -
            			expect( result.status ).to eq( HTTP:: 
     | 
| 
       656 
     | 
    
         
            -
            			expect( result.body.string ). 
     | 
| 
      
 672 
     | 
    
         
            +
            			expect( result.status ).to eq( HTTP::OK )
         
     | 
| 
      
 673 
     | 
    
         
            +
            			expect( result.body.string ).to_not be_empty
         
     | 
| 
       657 
674 
     | 
    
         
             
            			expect( @handler.metastore.fetch_value(uuid, 'format') ).to eq( 'image/png' )
         
     | 
| 
       658 
675 
     | 
    
         
             
            			expect( @handler.metastore.fetch_value(uuid, 'extent') ).to eq( 288 )
         
     | 
| 
       659 
676 
     | 
    
         
             
            			expect( @handler.metastore.fetch_value(uuid, 'uploadaddress') ).to eq( '127.0.0.1' )
         
     |