sme_storage 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,9 @@
1
+ Copyright (c) 2010, Vehera LTD
All rights reserved.
2
+
3
+ Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
4
+
5
+ * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
6
+ * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
7
+ * Neither the name of Vehera nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
8
+
9
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
data/README ADDED
@@ -0,0 +1,12 @@
1
+ A small ruby library for uploading files to SMEStorage (http://www.smestorage.com/). It does not implement all of SMEStorage's API, just the file upload part.
2
+
3
+ Basic usage:
4
+
5
+ require "rubygems"
6
+ require "sme_storage"
7
+
8
+ storage = SmeStorage.new("user", "password")
9
+ storage.authenticate
10
+ storage.upload("/Users/augustl/Desktop/testfile.txt")
11
+
12
+ Author: August Lilleaas, august.lilleaas@gmail.com
data/Rakefile ADDED
@@ -0,0 +1,13 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+
4
+ desc 'Default: run unit tests.'
5
+ task :default => :test
6
+
7
+ desc 'Test it!'
8
+ Rake::TestTask.new(:test) do |t|
9
+ t.libs << 'lib'
10
+ t.libs << 'test'
11
+ t.pattern = 'test/*_test.rb'
12
+ t.verbose = true
13
+ end
@@ -0,0 +1,67 @@
1
+ require "net/http"
2
+ require "uri"
3
+ require "base64"
4
+ require "rexml/document"
5
+
6
+ class SmeStorage
7
+ # The interface to the REST api. You need a token to interact with it.
8
+ #
9
+ # @token = SmeStorage::Api.get_token(username, password)
10
+ #
11
+ # When you have the token, you can call any action you want in the API.
12
+ #
13
+ # SmeStorage::Api.get(@token, "doInitUpload", "arbitary", "parameters", "here")
14
+ class Api
15
+ HTTP = Net::HTTP.new("www.smestorage.com", 80)
16
+ API_URI = "/api"
17
+ USER_AGENT = "SMEStorage Automator Upload Workflow"
18
+
19
+ attr_reader :root
20
+
21
+ # Similar to +new+, but also fetches and parses XML in one pass.
22
+ def self.get(*args)
23
+ instance = new(*args)
24
+ instance.fetch
25
+ instance.parse
26
+ return instance
27
+ end
28
+
29
+ # Returns the token if successful, false if not.
30
+ def self.get_token(username, password)
31
+ response = get(nil, "gettoken", username, password)
32
+ response.ok? && response.root.elements["token"].text
33
+ end
34
+
35
+ # The token can be nil, for authentication operations. The action matches
36
+ # the action names in the SMEStorage API. The arguments are the base64
37
+ # encoded comma separated arguments, also matching the SMEStorage API.
38
+ def initialize(token, action, *arguments)
39
+ @token = token || "*"
40
+ @action = action
41
+ @arguments = encode_arguments(arguments)
42
+ @uri = [API_URI, @token, @action, @arguments].join("/")
43
+ end
44
+
45
+ def fetch
46
+ request = Net::HTTP::Get.new(@uri)
47
+ request["User-Agent"] = USER_AGENT
48
+ @xml = HTTP.request(request).body
49
+ end
50
+
51
+ def parse
52
+ @doc = REXML::Document.new(@xml)
53
+ @root = @doc.root
54
+ @status = @root.elements["status"].text
55
+ end
56
+
57
+ def ok?
58
+ @status == "ok"
59
+ end
60
+
61
+ private
62
+
63
+ def encode_arguments(arguments)
64
+ arguments.map {|arg| Base64.encode64(arg).chomp }.join(",")
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,15 @@
1
+ class SmeStorage
2
+ # Inspired by TMail.new_boundary. Generates a unique boundary for the
3
+ # multipart file uploads in +Uploader+.
4
+ class MimeBoundary
5
+ def initialize
6
+ t = Time.now
7
+ random_tag = sprintf("%x%x_%x%x", t.to_i, t.tv_usec, Thread.current.object_id, rand(255))
8
+ @boundary = "mimepart_" + random_tag
9
+ end
10
+
11
+ def to_s
12
+ @boundary
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,38 @@
1
+ require "net/http"
2
+ require "uri"
3
+
4
+ class SmeStorage
5
+ # The actual uploading of a file is not done with the regular API. It
6
+ # emulates a HTML form type multipart upload.
7
+ class Uploader
8
+ UPLOADER_SCRIPT = "http://www.smetube.com/cgi-bin/uploader/uploader1.cgi"
9
+
10
+ def initialize(upload_code, path_to_file)
11
+ @upload_code = upload_code
12
+ @path_to_file = path_to_file
13
+ @boundary = MimeBoundary.new.to_s
14
+ @uri = URI.parse("#{UPLOADER_SCRIPT}?#{@upload_code}")
15
+ end
16
+
17
+ # Mimics a HTML form type multipart upload.
18
+ def upload
19
+ http = Net::HTTP.new(@uri.host, @uri.port)
20
+ request = Net::HTTP::Post.new(@uri.request_uri)
21
+ request.body = request_body(File.basename(@path_to_file), File.read(@path_to_file))
22
+ request["Content-Type"] = "multipart/form-data, boundary=#{@boundary}"
23
+ http.request(request)
24
+ end
25
+
26
+ def request_body(filename, file)
27
+ post_body = []
28
+ post_body << "--#{@boundary}\r\n"
29
+ post_body << "Content-Disposition: form-data; name=\"datafile\"; filename=\"#{filename}\"\r\n"
30
+ post_body << "Content-Type: text/plain\r\n"
31
+ post_body << "\r\n"
32
+ post_body << file
33
+ post_body << "\r\n--#{@boundary}--\r\n"
34
+
35
+ post_body.join
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,79 @@
1
+ require "sme_storage/api"
2
+ require "sme_storage/mime_boundary"
3
+ require "sme_storage/uploader"
4
+
5
+ # The wrapper class for the uploading operation.
6
+ #
7
+ # storage = SmeStorage.new("username", "password")
8
+ # storage.authenticate
9
+ # storage.upload("/path/to/file")
10
+ class SmeStorage
11
+ class NotAuthenticated < RuntimeError; end
12
+ def initialize(username, password)
13
+ @username, @password = username, password
14
+ end
15
+
16
+ # Performs the authentication. Has to be called before upload.
17
+ def authenticate
18
+ @token = Api.get_token(@username, @password)
19
+ @authenticated = (@token != nil)
20
+ end
21
+
22
+ # The actual upload. Takes a File instance, or a Pathname, or a
23
+ # String (path to the file, not file contents).
24
+ def upload(file_thing)
25
+ raise NotAuthenticated unless authenticated?
26
+
27
+ case file_thing.class.name.to_sym # so that we don't have to require pathname
28
+ when :File
29
+ perform_upload(file_thing.path)
30
+ when :Pathname
31
+ perform_upload(file_thing.to_s)
32
+ when :String
33
+ perform_upload(file_thing)
34
+ else
35
+ raise ArgumentError, "Needs a File, String or Pathname"
36
+ end
37
+ end
38
+
39
+ def authenticated?
40
+ @authenticated == true
41
+ end
42
+
43
+ private
44
+
45
+ def perform_upload(path)
46
+ if !File.file?(path)
47
+ raise ArgumentError, "The file `#{path}' does not exist."
48
+ end
49
+
50
+ # Tell the API we're going to upload
51
+ init_call = Api.get(@token, "doInitUpload",
52
+ File.basename(path), # File label
53
+ "", # Description
54
+ "", # Tags
55
+ "", # ID of parent folder
56
+ File.basename(path), # Filename
57
+ "xml", # Response type
58
+ "", # Response data, when response type is javascript
59
+ "", # Encryption phrase. Blank means unencrypted
60
+ "", # File ID, for overwrites
61
+ "n" # Chuck the file (y or n)
62
+ )
63
+
64
+ # Perform the upload
65
+ upload_code = init_call.root.elements["uploadcode"].text
66
+ Uploader.new(upload_code, path).upload
67
+
68
+ # Tell the API that we have uploaded
69
+ response = Api.get(@token, "doCompleteUpload", upload_code)
70
+
71
+ if response.ok?
72
+ file_id = response.root.elements["file"].elements["fi_id"].text
73
+ tiny_url = Api.get(@token, "getFileTinyURL", file_id)
74
+ tiny_url.root.elements["tinyurl"].text
75
+ else
76
+ false
77
+ end
78
+ end
79
+ end
metadata ADDED
@@ -0,0 +1,61 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sme_storage
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - August Lilleaas
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2010-01-29 00:00:00 +01:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: " Uploads files to SMEStorage with theri API.\n"
17
+ email: august.lilleaas@gmail.com
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files: []
23
+
24
+ files:
25
+ - README
26
+ - LICENSE
27
+ - Rakefile
28
+ - lib/sme_storage/api.rb
29
+ - lib/sme_storage/mime_boundary.rb
30
+ - lib/sme_storage/uploader.rb
31
+ - lib/sme_storage.rb
32
+ has_rdoc: true
33
+ homepage: http://gitorious.org/smestorage
34
+ licenses: []
35
+
36
+ post_install_message:
37
+ rdoc_options: []
38
+
39
+ require_paths:
40
+ - lib
41
+ required_ruby_version: !ruby/object:Gem::Requirement
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ version: "0"
46
+ version:
47
+ required_rubygems_version: !ruby/object:Gem::Requirement
48
+ requirements:
49
+ - - ">="
50
+ - !ruby/object:Gem::Version
51
+ version: "0"
52
+ version:
53
+ requirements: []
54
+
55
+ rubyforge_project:
56
+ rubygems_version: 1.3.5
57
+ signing_key:
58
+ specification_version: 3
59
+ summary: SMEStorage file upload library.
60
+ test_files: []
61
+