boxlet 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 6d5950f183d1274de5cd16237709c40ad58c65cf
4
+ data.tar.gz: 7ebc60f5a772512343f7d6778eb25ca227b2998f
5
+ SHA512:
6
+ metadata.gz: 94c93357b399e5855256009dc8bd9edcd3c18d4537cca5fdb2927d773021570148292b2d081b4b0db34d02a261093fab7f43827d6b9387ec0d353dfdf9171b72
7
+ data.tar.gz: 0667cdd101c8ebaf9c0a34d2975d3ec573a3b0eff0a08fb24ebdff0714f765108927efbd233eeb3da861bb6093831161e94ada72394f63ae5f47c39758753857
data/bin/boxlet CHANGED
@@ -1,12 +1,15 @@
1
- #! /usr/bin/env ruby
1
+ #!/usr/bin/env ruby
2
2
 
3
- require "boxlet"
3
+ require 'boxlet'
4
4
 
5
- # Check to make sure we aren't running in Windows
6
- if RUBY_PLATFORM =~ /(win|w)32$/ then
7
- puts "Sorry, Boxlet is currently only available for Unix/Linux."
8
- exit!
5
+ argv = *ARGV
6
+ command = argv.count % 2 != 0 ? argv.shift : 'run'
7
+ argv_hash = Hash[*argv]
8
+
9
+ config = argv_hash["-c"] || argv_hash["--config"]
10
+ if !config
11
+ puts "WARNING: config file not specified, looking in current directory..."
12
+ config = 'config.yml'
9
13
  end
10
14
 
11
- server = Boxlet::Server.new
12
- server.run
15
+ Boxlet.run! argv_hash, command, config
data/boxlet.gemspec CHANGED
@@ -6,22 +6,30 @@ require "boxlet/version"
6
6
  Gem::Specification.new do |spec|
7
7
  spec.name = "boxlet"
8
8
  spec.version = Boxlet::VERSION
9
- spec.authors = ["Clayton Liggitt", "arktisklada"]
9
+ spec.authors = ["arktisklada"]
10
10
  spec.email = ["mail@enorganik.com"]
11
- spec.description = %q{A server for Boxlet, a DIY, self-hosted file storage system}
12
- spec.summary = spec.description
13
- spec.homepage = "http://github.com/arktisklada/boxlet"
11
+ spec.summary = %q{Upload pics from your phone}
12
+ spec.description = spec.summary
13
+ spec.homepage = "https://github.com/arktisklada/boxlet"
14
14
  spec.license = "MIT"
15
15
 
16
- # spec.files = `git ls-files`.split($/)
17
16
  spec.files = %w[config.yml LICENSE.txt README.md Rakefile boxlet.gemspec]
18
17
  spec.files += Dir.glob('lib/**/*.rb')
18
+ spec.files += Dir.glob('lib/boxlet/app/*.rb')
19
19
 
20
- # spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
21
20
  spec.executables = 'boxlet'
22
21
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
23
- spec.require_paths = %w[lib]
22
+ spec.require_paths = ["lib"]
23
+
24
+ spec.add_dependency "rack", "~> 1.5"
25
+ spec.add_dependency "rack-contrib", "~> 1.1"
26
+ spec.add_dependency "thin", "~> 1.6"
27
+
28
+ spec.add_runtime_dependency 'multi_json', '~> 1.10', '>= 1.10.1'
29
+ spec.add_runtime_dependency 'mongo', '~> 1.10', '>= 1.10.2'
30
+ spec.add_runtime_dependency 'bson_ext', '~> 1.10', '>= 1.10.2'
31
+ spec.add_runtime_dependency 'sys-filesystem', '~> 1.1', '>= 1.1.2'
24
32
 
25
33
  spec.add_development_dependency "bundler", "~> 1.3"
26
- spec.add_development_dependency "rake"
27
- end
34
+ spec.add_development_dependency "rake", "~> 10.3"
35
+ end
data/config.yml CHANGED
@@ -1,8 +1,32 @@
1
1
  # Boxlet configuration file
2
2
 
3
- # TCP Debug mode changes logging level between WARN (false) and DEBUG (true)
4
- tcp_debug: true
3
+ # Environment
4
+ environment: development
5
+ debug: true
5
6
 
6
- # Server configuration
7
- tcp_listen_ip: 127.0.0.1
8
- tcp_listen_port: 8077
7
+ # File system parameters
8
+ # path: ./
9
+ # upload_dir: ./uploads
10
+ # tmp_dir: /tmp
11
+ # file_system_root: /
12
+
13
+ # Capacity is either a percentage of available space on the drive or number in MB
14
+ capacity: 90%
15
+
16
+ # Server type and listen parameters
17
+ port: 8077
18
+ host: localhost
19
+ server_type: thin
20
+ daemonize: false
21
+
22
+ # Database config
23
+ db:
24
+ development:
25
+ host: localhost
26
+ db: boxlet_dev
27
+ production:
28
+ host: localhost
29
+ # port:
30
+ # user:
31
+ # pass:
32
+ db: boxlet
data/lib/boxlet.rb CHANGED
@@ -1,33 +1,73 @@
1
- require "fileutils"
2
1
  require "yaml"
3
-
2
+ require "rack/contrib"
4
3
  require "boxlet/version"
5
- require "boxlet/log"
6
- require "boxlet/tcp_server"
4
+ require "boxlet/app"
5
+ require "boxlet/config"
6
+ require "boxlet/runner"
7
+ require "pp" #unless ENV['RACK_ENV'] == 'production'
8
+
9
+
10
+ APP_ROOT = Dir.pwd
7
11
 
8
12
 
9
13
  module Boxlet
10
-
11
- class Server
12
- def initialize()
13
- # Load the config
14
- @@config = YAML.load_file("config.yml")
15
-
16
- if @@config['git_debug'] then
17
- Grit.debug = true
18
- end
19
-
20
- @server = TcpServer.new
21
- end
22
-
23
- public
24
-
25
- def self.config
26
- return @@config
27
- end
14
+
15
+ extend self
16
+ extend Boxlet::Config
17
+
18
+ attr_accessor :runner, :config, :raw_params, :raw_config
19
+
20
+ def run!(argv, command='run', config_file='config.yml', &blk)
21
+ populate_params!(argv, config_file)
28
22
 
29
- def run
30
- @server.start
23
+ app = Boxlet::App.new
24
+
25
+ case command
26
+ when 'run'
27
+ @runner = Boxlet::Runner.new
28
+ @runner.start(app.bind, &blk)
29
+ else
30
+ app.send(command, Boxlet.config)
31
31
  end
32
+
33
+ app
34
+ end
35
+
36
+ def stop!
37
+ @runner.stop
38
+ app
39
+ end
40
+
41
+
42
+ def debug?
43
+ @config[:debug] == true ? true : false
44
+ end
45
+
46
+ def config
47
+ @config
48
+ end
49
+
50
+ def params
51
+ @params
32
52
  end
53
+
33
54
  end
55
+
56
+
57
+ # Configure our temporary folder
58
+ class Dir
59
+ def Dir::tmpdir
60
+ tmp = './tmp'
61
+ if $SAFE > 0
62
+ tmp = @@systmpdir
63
+ else
64
+ for dir in [ENV['TMPDIR'], ENV['TMP'], ENV['TEMP'], @@systmpdir, '/tmp']
65
+ if dir and stat = File.stat(dir) and stat.directory? and stat.writable?
66
+ tmp = dir
67
+ break
68
+ end rescue nil
69
+ end
70
+ File.expand_path(tmp)
71
+ end
72
+ end
73
+ end
data/lib/boxlet/app.rb ADDED
@@ -0,0 +1,133 @@
1
+ require "sys/filesystem"
2
+ #require "rack/boxlet_url_builder"
3
+ require "rack/request"
4
+ require "rack/response"
5
+ require "rack/file_upload"
6
+ require "boxlet/db"
7
+ require "boxlet/app/router"
8
+
9
+
10
+ module Boxlet
11
+ class App
12
+
13
+ include Sys
14
+
15
+ def self.routes
16
+ routes = {
17
+ ["/", :get] => :index,
18
+ # ["/auth"] => :auth,
19
+ # ["/register_device", :post] => :register_device,
20
+ # ["/notifications", :*] => :notifications,
21
+ ["/stats", :post] => :stats,
22
+ ["/push_files", :post] => :push_files,
23
+ ["/file_list"] => :file_list,
24
+ ["/file_info"] => :file_info
25
+ }
26
+ end
27
+
28
+ def initialize
29
+ usage = Boxlet::App.app_space_usage
30
+ capacity = Boxlet::App.app_space_capacity
31
+ puts "Space Utilization: #{usage}MB / #{capacity}MB (#{(usage.to_f / capacity).round(3)}%)"
32
+ end
33
+
34
+ def bind
35
+ Rack::Builder.new do
36
+ use Rack::Reloader
37
+ # use Rack::Static, :urls => ["/public"]
38
+ use Rack::FileUpload, :upload_dir => [Boxlet.config[:upload_dir] || APP_ROOT + '/uploads']
39
+
40
+ Boxlet::App.routes.each do |route, action|
41
+ map route[0] do
42
+ run Boxlet::Router.new(route[1] || :*, action)
43
+ end
44
+ end
45
+
46
+ end.to_app
47
+ end
48
+
49
+
50
+ def setup(config)
51
+ begin
52
+ # Check for free space
53
+ if Boxlet::App.free_space <= 50
54
+ raise "Not enough free space"
55
+ end
56
+ if Boxlet::App.app_space_usage / Boxlet::App.app_space_capacity >= 0.9
57
+ puts "App is over 90% full"
58
+ end
59
+
60
+ # Create upload and tmp directories
61
+ upload_dir = Boxlet.config[:upload_dir]
62
+ tmp_dir = Boxlet.config[:tmp_dir]
63
+ if !File.exists?(upload_dir) || !File.exists?(tmp_dir)
64
+ if !File.exists?(upload_dir)
65
+ puts "Upload directory (#{upload_dir}) does not exist. Create? [y/n]"
66
+ create = gets.chomp
67
+ if create =~ /y/i
68
+ Dir.mkdir(upload_dir)
69
+ puts "Upload directory created!"
70
+ end
71
+ end
72
+ if !File.exists?(tmp_dir)
73
+ puts "Temp directory (#{tmp_dir}) does not exist. Create? [y/n]"
74
+ create = gets.chomp
75
+ if create =~ /y/i
76
+ Dir.mkdir(tmp_dir)
77
+ puts "Temp directory created!"
78
+ end
79
+ end
80
+ if File.exists?(upload_dir) && File.exists?(tmp_dir)
81
+ puts "Done creating directories."
82
+ else
83
+ raise "Error creating directories. Please check your config and file permissions, and retry."
84
+ end
85
+ end
86
+
87
+ puts "\nBoxlet setup is done!"
88
+ rescue => e
89
+ puts "\nERROR: #{e}"
90
+ end
91
+ end
92
+
93
+
94
+ # App disk space functions
95
+
96
+ def self.free_space
97
+ Boxlet::App.app_space_capacity - Boxlet::App.app_space_usage
98
+ end
99
+
100
+ def self.app_space_capacity
101
+ drive_free_space = Boxlet::App.drive_free_space
102
+ if Boxlet.config[:capacity].is_a? String
103
+ Boxlet::App.drive_free_space * Boxlet.config[:capacity].to_i / 100
104
+ else
105
+ Boxlet.config[:capacity]
106
+ end
107
+ end
108
+
109
+ def self.app_space_usage
110
+ raise RuntimeError, "#{Boxlet.config[:upload_dir]} is not a directory" unless File.directory?(Boxlet.config[:upload_dir])
111
+
112
+ total_size = 0
113
+ Dir["#{Boxlet.config[:upload_dir]}/**/*"].each do |f|
114
+ total_size += File.size(f) if File.file?(f) && File.size?(f)
115
+ end
116
+ total_size / 1000000 # / 1048576 # to megabytes
117
+ end
118
+
119
+ # Drive disk space functions
120
+
121
+ def self.drive_free_space
122
+ stat = Filesystem.stat(Boxlet.config[:file_system_root])
123
+ (stat.block_size * stat.blocks_available).to_mb
124
+ end
125
+
126
+ def self.drive_capacity
127
+ stat = Filesystem.stat(Boxlet.config[:file_system_root])
128
+ (stat.block_size * stat.blocks).to_mb
129
+ end
130
+
131
+
132
+ end
133
+ end
@@ -0,0 +1,168 @@
1
+ require 'date'
2
+
3
+ # routes = {
4
+ # ["/", :get] => :index,
5
+ # ["/auth"] => :auth,
6
+ # ["/register_device", :post] => :register_device,
7
+ # ["/notifications", :post] => :notifications,
8
+ # ["/push_files", :post] => :push_files,
9
+ # ["/file_list"] => :file_list,
10
+ # ["/file_info"] => :file_info
11
+ # }
12
+
13
+
14
+ module Boxlet
15
+ class Controller
16
+ attr_accessor :request, :format, :params
17
+
18
+ def initialize(request)
19
+ @request = request
20
+ @params = Boxlet.symbolize_keys request.params
21
+ pp request.params
22
+
23
+ @format = :html
24
+ end
25
+
26
+ def action(action)
27
+ action_response = self.send(action)
28
+ set_user if action =~ /push_files|file_list|file_info/
29
+
30
+ {format: @format, content: action_response}
31
+ end
32
+
33
+
34
+ # actions
35
+
36
+ def index
37
+ '<html><body><form action="/push_files" method="post" enctype="multipart/form-data">UUID:<input type="text" name="uuid"><br><input type="file" name="file"><input type="submit"></form>'
38
+ end
39
+
40
+ # def auth
41
+ # @format = :json
42
+ # "auth"
43
+ # end
44
+
45
+ # def register_device
46
+ # @format = :json
47
+
48
+ # pp @params if Boxlet.config[:debug]
49
+
50
+ # uuid = @params[:uuid]
51
+ # # user = user_model.merge { uuid: uuid }
52
+ # if db.collection('users').insert(user)
53
+ # {response: true}
54
+ # else
55
+ # {response: false}
56
+ # end
57
+ # end
58
+
59
+ # def notifications
60
+ # @format = :json
61
+
62
+ # uuid = @params[:uuid]
63
+ # notifications = @params[:notifications]
64
+ # pp uuid
65
+ # # @user
66
+ # "notifications"
67
+ # end
68
+
69
+ def stats
70
+ @format = :json
71
+
72
+ {
73
+ capacity: Boxlet::App.app_space_capacity,
74
+ usage: Boxlet::App.app_space_usage,
75
+ free_space: free_space?
76
+ }
77
+ end
78
+
79
+ def push_files
80
+ @format = :json
81
+
82
+ upload_path = user_upload_dir || './uploads'
83
+ upload_file = @params[:file]
84
+ asset_path = @params[:asset_path]
85
+ asset_path_params = Rack::Utils.parse_nested_query(asset_path[asset_path.index('?') + 1..-1])
86
+
87
+ new_filename = "#{asset_path_params["id"]}.#{asset_path_params["ext"]}"
88
+ new_path = File.join(upload_path, new_filename)
89
+ FileUtils.mv(upload_file[:tempfile].path, new_path)
90
+
91
+ if File.exists? new_path
92
+ file = File.open(new_path, 'r')
93
+ # asset_date = Date.parse(@params[:asset_date])
94
+ asset = {
95
+ filename: upload_file[:filename],
96
+ size: file.size,
97
+ local_date: file.mtime.to_i,
98
+ asset_path: @params[:asset_path],
99
+ asset_date: @params[:asset_date],
100
+ uuid: @params[:uuid]
101
+ }
102
+ db.collection('assets').insert(asset)
103
+ {response: true}
104
+ else
105
+ {response: false}
106
+ end
107
+ end
108
+
109
+ def file_list
110
+ @format = :json
111
+
112
+ uuid = @params[:uuid]
113
+ db.collection('assets').find({uuid: uuid}).to_a
114
+ end
115
+
116
+ def file_info
117
+ @format = :json
118
+
119
+ uuid = @params[:uuid]
120
+ asset_path = @params[:asset_path]
121
+ file_model.merge db.collection('assets').find({asset_path: asset_path, uuid: uuid}).to_a.first || {}
122
+ end
123
+
124
+
125
+ private
126
+
127
+ def db
128
+ Boxlet::Db.connection
129
+ end
130
+
131
+ def set_user
132
+ user_model.merge db.collection('users').find({uuid: @params[:uuid]}).to_a.first || {}
133
+ end
134
+
135
+ def user_upload_dir
136
+ user_upload_dir_name = Boxlet.config[:upload_dir] + "/" + (@params[:uuid] || '')
137
+ Dir.mkdir(user_upload_dir_name) unless File.exists?(user_upload_dir_name)
138
+ user_upload_dir_name
139
+ end
140
+
141
+ def free_space?
142
+ Boxlet::App.free_space > 50
143
+ end
144
+
145
+
146
+ # Models
147
+
148
+ def file_model
149
+ {
150
+ filename: '',
151
+ size: 0,
152
+ local_date: 0,
153
+ asset_path: '',
154
+ asset_date: '',
155
+ uuid: []
156
+ }
157
+ end
158
+
159
+ def user_model
160
+ {
161
+ uuid: '',
162
+ notifications: 1,
163
+ last_activity: Time.now
164
+ }
165
+ end
166
+
167
+ end
168
+ end
@@ -0,0 +1,45 @@
1
+ require "rack/request"
2
+ require "rack/response"
3
+ require "boxlet/app/controller"
4
+ require "json"
5
+
6
+
7
+ module Boxlet
8
+ class Router
9
+
10
+ attr_accessor :method, :action
11
+
12
+ def initialize(method, action)
13
+ @method = method
14
+ @action = action
15
+ end
16
+
17
+ def call(env)
18
+ request = Rack::Request.new(env)
19
+
20
+ if Boxlet.debug?
21
+ puts "\n#{env["REMOTE_ADDR"]} - [#{Time.now.to_s}] #{@method.upcase} #{env["SERVER_PROTOCOL"]} => #{env["REQUEST_PATH"]}"
22
+ end
23
+
24
+ response = Rack::Response.new
25
+ controller = Boxlet::Controller.new(request)
26
+ if (@method == :* || request.get? && @method == :get) || (request.post? && @method == :post)
27
+ puts "Responding: #{@method.upcase} => #{@action}" if Boxlet.debug?
28
+ action_response = controller.action(@action)
29
+ response.status = 200
30
+ else
31
+ response.status = 404
32
+ raise "404"
33
+ end
34
+
35
+ if action_response[:format] == :json
36
+ response.write action_response[:content].to_json
37
+ else
38
+ response.write action_response[:content]
39
+ end
40
+
41
+ response.finish
42
+ end
43
+
44
+ end
45
+ end
@@ -0,0 +1,119 @@
1
+ module Boxlet
2
+ module Config
3
+
4
+ ARGS = {
5
+ :path => {
6
+ :short => 'f',
7
+ :default => Proc.new { Dir.pwd }
8
+ },
9
+ :port => {
10
+ :short => 'p',
11
+ :default => 8077,
12
+ :sanitizer => Proc.new { |p| p.to_i }
13
+ },
14
+ :host => {
15
+ :short => 'o',
16
+ :default => 'localhost'
17
+ },
18
+ :server_type => {
19
+ :short => 's',
20
+ :default => 'rack',
21
+ :sanitizer => Proc.new { |p| p.to_sym }
22
+ },
23
+ :environment => {
24
+ :short => 'E',
25
+ :default => 'development'
26
+ },
27
+ :daemonize => {
28
+ :short => 'D',
29
+ :default => 'false',
30
+ :sanitizer => Proc.new { |p| p == 'true' }
31
+ },
32
+ :debug => {
33
+ :short => 'd',
34
+ :default => 'true',
35
+ :sanitizer => Proc.new { |p| p == 'true' }
36
+ },
37
+ :upload_dir => {
38
+ :short => 'U',
39
+ :default => './uploads'
40
+ },
41
+ :tmp_dir => {
42
+ :short => 'T',
43
+ :default => './tmp'
44
+ },
45
+ :file_system_root => {
46
+ :short => 'r',
47
+ :default => '/'
48
+ },
49
+ :capacity => {
50
+ :short => 'C',
51
+ :default => '90%',
52
+ :sanitizer => Proc.new { |p| (p.to_i.to_s == p) ? p.to_i : p }
53
+ }
54
+ }
55
+
56
+
57
+ def populate_params!(argv, path_to_config)
58
+ @raw_config = load_config_file(path_to_config)
59
+ @raw_params = parse_arguments(argv)
60
+ # @config = @raw_params.merge(@raw_config)
61
+ @config = @raw_config.merge(@raw_params)
62
+
63
+ @config[:debug] = @raw_config[:debug] || @raw_params[:debug]
64
+ if @config[:debug]
65
+ pp @config
66
+ end
67
+ end
68
+
69
+
70
+ def symbolize_keys(hash)
71
+ hash.inject({}){|result, (key, value)|
72
+ new_key = key.instance_of?(String) ? key.to_sym : key
73
+ new_value = value.instance_of?(Hash) ? symbolize_keys(value) : value
74
+
75
+ result[new_key] = new_value
76
+ result
77
+ }
78
+ end
79
+
80
+ private
81
+
82
+ def parse_arguments(argv)
83
+ params = Hash.new
84
+
85
+ ARGS.each_pair do |param_name, param_attrs|
86
+ param_short_name = param_attrs[:short]
87
+ config_value = @raw_config[param_name.to_sym]
88
+ default = param_attrs[:default]
89
+ sanitizer = param_attrs[:sanitizer]
90
+
91
+ param_value = argv["--#{param_name}"] ||
92
+ (param_short_name.nil? ? nil : argv["-#{param_short_name}"]) ||
93
+ (config_value.nil? ? nil : config_value) ||
94
+ (default.is_a?(Proc) ? default.call : default)
95
+
96
+ param_value = sanitizer.call(param_value) if sanitizer.is_a?(Proc)
97
+
98
+ if !param_value.nil?
99
+ params[param_name] = param_value
100
+ end
101
+ end
102
+
103
+ params
104
+ end
105
+
106
+ def load_config_file(path_to_config)
107
+ begin
108
+ loaded_config = YAML.load_file(path_to_config)
109
+ symbolize_keys(loaded_config)
110
+ rescue
111
+ puts "Error loading config file! Using defaults..."
112
+ {}
113
+ end
114
+ end
115
+
116
+ end
117
+
118
+
119
+ end
data/lib/boxlet/db.rb ADDED
@@ -0,0 +1,29 @@
1
+ require 'mongo'
2
+
3
+
4
+ module Boxlet
5
+ module Db
6
+
7
+ extend self
8
+ include Mongo
9
+
10
+ attr_accessor :db
11
+
12
+ def connection
13
+ @db ||= self.connect
14
+ end
15
+
16
+ def connect
17
+ config = Boxlet.config
18
+ db_config = config[:db][config[:environment].to_sym || :development]
19
+
20
+ host = db_config[:host] || 'localhost'
21
+ port = db_config[:port] || MongoClient::DEFAULT_PORT
22
+ puts "Connecting to #{host}:#{port}" if Boxlet.debug?
23
+ client = MongoClient.new(host, port)
24
+ db = client.db(db_config[:db] || 'boxlet_development')
25
+ return db
26
+ end
27
+
28
+ end
29
+ end
data/lib/boxlet/log.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  require "logger"
2
2
  require "fileutils"
3
3
 
4
+
4
5
  module Log
5
6
  def get_logger(name, shift_age, shift_size, level)
6
7
  # create the directory for the log if it doesn't exist
@@ -0,0 +1,37 @@
1
+ require "handlers/thin"
2
+
3
+
4
+ module Boxlet
5
+ class Runner
6
+ attr_accessor :server, :server_instance
7
+
8
+ def start(app, &block)
9
+ params = Boxlet.config
10
+ environment = ENV['RACK_ENV'] || params[:environment] rescue 'development'
11
+ default_host = environment == 'development' ? 'localhost' : '0.0.0.0'
12
+
13
+ params[:Host] = params.delete(:host) || default_host
14
+ params[:Port] = params.delete(:port) || 8077
15
+
16
+ server_type = params.delete(:server_type) || :thin
17
+ @server_instance = self.send server_type.to_sym, app, params
18
+ @server_instance.start do |server|
19
+ self.server = server
20
+ block.call(server) if block_given?
21
+ end
22
+ end
23
+
24
+ def stop
25
+ @server.stop!
26
+ end
27
+
28
+ def rack(app, params)
29
+ Rack::Server.new(params.merge({app: app}))
30
+ end
31
+
32
+ def thin(app, params)
33
+ Boxlet::Handlers::Thin.new(app, params)
34
+ end
35
+
36
+ end
37
+ end
@@ -1,3 +1,3 @@
1
1
  module Boxlet
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
@@ -0,0 +1,34 @@
1
+ require "thin"
2
+ require "rack/content_length"
3
+ require "rack/chunked"
4
+
5
+
6
+ module Boxlet
7
+ module Handlers
8
+ class Thin
9
+ attr_accessor :app, :params
10
+
11
+ def initialize(app, params={})
12
+ @app = app
13
+ @params = params
14
+ # super
15
+ end
16
+
17
+ # ported from https://github.com/rack/rack/tree/master/lib/rack/handler/thin.rb
18
+ def start
19
+ # environment = ENV['RACK_ENV'] || 'development'
20
+ # default_host = environment == 'development' ? : '0.0.0.0'
21
+ host = @params.delete(:Host) || 'localhost'
22
+ port = @params.delete(:Port) || 8077
23
+
24
+ args = [host, port, @app, @params]
25
+
26
+ # Thin versions below 0.8.0 do not support additional options
27
+ args.pop if ::Thin::VERSION::MAJOR < 1 && ::Thin::VERSION::MINOR < 8
28
+ server = ::Thin::Server.new(*args)
29
+ yield server if block_given?
30
+ server.start
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,16 @@
1
+ require "rack"
2
+ require "rack/boxlet_url_map"
3
+
4
+
5
+ module Rack
6
+ class BoxletUrlBuilder < Builder
7
+
8
+ private
9
+
10
+ def generate_map(default_app, mapping)
11
+ mapped = default_app ? {'/' => default_app} : {}
12
+ mapping.each { |r,b| mapped[r] = self.class.new(default_app, &b) }
13
+ BoxletUrlMap.new(mapped)
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,66 @@
1
+ require "rack"
2
+
3
+
4
+ module Rack
5
+ class BoxletUrlMap < URLMap
6
+
7
+ def remap(map)
8
+ @mapping = map.map { |location, app|
9
+ if location.is_a? String
10
+ if location =~ %r{\Ahttps?://(.*?)(/.*)}
11
+ host, location = $1, $2
12
+ else
13
+ host = nil
14
+ end
15
+
16
+ unless location[0] == ?/
17
+ raise ArgumentError, "paths need to start with /"
18
+ end
19
+
20
+ location = location.chomp('/')
21
+ match = Regexp.new("^#{Regexp.quote(location).gsub('/', '/+')}(.*)", nil, 'n')
22
+ elsif location.is_a? Regexp
23
+ match = location
24
+ else
25
+ raise ArgumentError, "location should be an instance of String or Regexp"
26
+ end
27
+
28
+ [host, location, match, app]
29
+ }.sort_by do |(host, location, _, _)|
30
+ [host ? -host.size : INFINITY, (location.is_a?(String) ? -location.size : INFINITY)]
31
+ end
32
+
33
+ @mapping
34
+ end
35
+
36
+ def call(env)
37
+ path = env["PATH_INFO"]
38
+ script_name = env['SCRIPT_NAME']
39
+ hHost = env['HTTP_HOST']
40
+ sName = env['SERVER_NAME']
41
+ sPort = env['SERVER_PORT']
42
+
43
+ @mapping.each do |host, location, match, app|
44
+ unless hHost == host \
45
+ || sName == host \
46
+ || (!host && (hHost == sName || hHost == sName+':'+sPort))
47
+ next
48
+ end
49
+
50
+ next unless m = match.match(path.to_s)
51
+
52
+ rest = m[1]
53
+ next unless !rest || rest.empty? || rest[0] == ?/
54
+
55
+ return app.call(env)
56
+ end
57
+
58
+ [404, {"Content-Type" => "text/plain", "X-Cascade" => "pass"}, ["Not Found: #{path}"]]
59
+
60
+ ensure
61
+ env['PATH_INFO'] = path
62
+ env['SCRIPT_NAME'] = script_name
63
+ end
64
+
65
+ end
66
+ end
@@ -0,0 +1,121 @@
1
+ # ported from https://github.com/New-Bamboo/rack-raw-upload
2
+ require 'multi_json'
3
+
4
+
5
+ module Rack
6
+ class FileUpload
7
+
8
+ def initialize(app, options={})
9
+ @app = app
10
+ @paths = [options[:upload_dir]]
11
+ @explicit = options[:explicit]
12
+ @tmpdir = options[:tmp_dir] || Dir::tmpdir
13
+ @paths = [@paths] if @paths.kind_of?(String)
14
+ end
15
+
16
+ def call(env)
17
+ kick_in?(env) ? convert_and_pass_on(env) : @app.call(env)
18
+ end
19
+
20
+ def upload_path?(request_path)
21
+ return true if @paths.nil?
22
+
23
+ @paths.any? do |candidate|
24
+ literal_path_match?(request_path, candidate) || wildcard_path_match?(request_path, candidate)
25
+ end
26
+ end
27
+
28
+
29
+ private
30
+
31
+ def convert_and_pass_on(env)
32
+ if env['rack.input'].kind_of?(Tempfile)
33
+ env['rack.input'].extend(EqlFix)
34
+ tempfile = env['rack.input']
35
+ else
36
+ tempfile = Tempfile.new('raw-upload.', @tmpdir)
37
+
38
+ env['rack.input'].each do |chunk|
39
+ if chunk.respond_to?(:force_encoding)
40
+ tempfile << chunk.force_encoding('UTF-8')
41
+ else
42
+ tempfile << chunk
43
+ end
44
+ end
45
+ env['rack.input'].rewind
46
+
47
+ tempfile.flush
48
+ tempfile.rewind
49
+ end
50
+ fake_file = {
51
+ :filename => env['HTTP_X_FILE_NAME'],
52
+ :type => env['CONTENT_TYPE'],
53
+ :tempfile => tempfile,
54
+ }
55
+ env['rack.request.form_input'] = env['rack.input']
56
+ env['rack.request.form_hash'] ||= {}
57
+ env['rack.request.query_hash'] ||= {}
58
+ env['rack.request.form_hash']['file'] = fake_file
59
+ env['rack.request.query_hash']['file'] = fake_file
60
+ if env['HTTP_X_QUERY_PARAMS']
61
+ env['rack.errors'].puts("Warning! The header X-Query-Params is deprecated. Please use X-JSON-Params instead.")
62
+ inject_json_params!(env, env['HTTP_X_QUERY_PARAMS'])
63
+ end
64
+ if env['HTTP_X_JSON_PARAMS']
65
+ inject_json_params!(env, env['HTTP_X_JSON_PARAMS'])
66
+ end
67
+ if env['HTTP_X_PARAMS']
68
+ inject_query_params!(env, env['HTTP_X_PARAMS'])
69
+ end
70
+ @app.call(env)
71
+ end
72
+
73
+ def kick_in?(env)
74
+ env['HTTP_X_FILE_UPLOAD'] == 'true' ||
75
+ ! @explicit && env['HTTP_X_FILE_UPLOAD'] != 'false' && raw_file_upload?(env) ||
76
+ env.has_key?('HTTP_X_FILE_UPLOAD') && env['HTTP_X_FILE_UPLOAD'] != 'false' && raw_file_upload?(env)
77
+ end
78
+
79
+ def raw_file_upload?(env)
80
+ upload_path?(env['PATH_INFO']) &&
81
+ %{POST PUT}.include?(env['REQUEST_METHOD']) &&
82
+ content_type_of_raw_file?(env['CONTENT_TYPE']) &&
83
+ env['CONTENT_LENGTH'].to_i > 0
84
+ end
85
+
86
+ def literal_path_match?(request_path, candidate)
87
+ candidate == request_path
88
+ end
89
+
90
+ def wildcard_path_match?(request_path, candidate)
91
+ return false unless candidate.include?('*')
92
+ regexp = '^' + candidate.gsub('.', '\.').gsub('*', '[^/]*') + '$'
93
+ !! (Regexp.new(regexp) =~ request_path)
94
+ end
95
+
96
+ def content_type_of_raw_file?(content_type)
97
+ case content_type
98
+ when %r{^application/x-www-form-urlencoded}, %r{^multipart/form-data}
99
+ false
100
+ else
101
+ true
102
+ end
103
+ end
104
+
105
+ def random_string
106
+ (0...8).map{65.+(rand(25)).chr}.join
107
+ end
108
+
109
+ def inject_json_params!(env, params)
110
+ json = MultiJson.load(params)
111
+ env['rack.request.form_hash'].merge!(json)
112
+ env['rack.request.query_hash'].merge!(json)
113
+ end
114
+
115
+ def inject_query_params!(env, params)
116
+ json = Rack::Utils.parse_query(params)
117
+ env['rack.request.form_hash'].merge!(json)
118
+ env['rack.request.query_hash'].merge!(json)
119
+ end
120
+ end
121
+ end
metadata CHANGED
@@ -1,50 +1,166 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: boxlet
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
5
- prerelease:
4
+ version: 0.0.2
6
5
  platform: ruby
7
6
  authors:
8
- - Clayton Liggitt
9
7
  - arktisklada
10
8
  autorequire:
11
9
  bindir: bin
12
10
  cert_chain: []
13
- date: 2014-06-02 00:00:00.000000000 Z
11
+ date: 2014-07-10 00:00:00.000000000 Z
14
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rack
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.5'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.5'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rack-contrib
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.1'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.1'
41
+ - !ruby/object:Gem::Dependency
42
+ name: thin
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.6'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.6'
55
+ - !ruby/object:Gem::Dependency
56
+ name: multi_json
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.10'
62
+ - - ">="
63
+ - !ruby/object:Gem::Version
64
+ version: 1.10.1
65
+ type: :runtime
66
+ prerelease: false
67
+ version_requirements: !ruby/object:Gem::Requirement
68
+ requirements:
69
+ - - "~>"
70
+ - !ruby/object:Gem::Version
71
+ version: '1.10'
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: 1.10.1
75
+ - !ruby/object:Gem::Dependency
76
+ name: mongo
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: '1.10'
82
+ - - ">="
83
+ - !ruby/object:Gem::Version
84
+ version: 1.10.2
85
+ type: :runtime
86
+ prerelease: false
87
+ version_requirements: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - "~>"
90
+ - !ruby/object:Gem::Version
91
+ version: '1.10'
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ version: 1.10.2
95
+ - !ruby/object:Gem::Dependency
96
+ name: bson_ext
97
+ requirement: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - "~>"
100
+ - !ruby/object:Gem::Version
101
+ version: '1.10'
102
+ - - ">="
103
+ - !ruby/object:Gem::Version
104
+ version: 1.10.2
105
+ type: :runtime
106
+ prerelease: false
107
+ version_requirements: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - "~>"
110
+ - !ruby/object:Gem::Version
111
+ version: '1.10'
112
+ - - ">="
113
+ - !ruby/object:Gem::Version
114
+ version: 1.10.2
115
+ - !ruby/object:Gem::Dependency
116
+ name: sys-filesystem
117
+ requirement: !ruby/object:Gem::Requirement
118
+ requirements:
119
+ - - "~>"
120
+ - !ruby/object:Gem::Version
121
+ version: '1.1'
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: 1.1.2
125
+ type: :runtime
126
+ prerelease: false
127
+ version_requirements: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '1.1'
132
+ - - ">="
133
+ - !ruby/object:Gem::Version
134
+ version: 1.1.2
15
135
  - !ruby/object:Gem::Dependency
16
136
  name: bundler
17
137
  requirement: !ruby/object:Gem::Requirement
18
- none: false
19
138
  requirements:
20
- - - ~>
139
+ - - "~>"
21
140
  - !ruby/object:Gem::Version
22
141
  version: '1.3'
23
142
  type: :development
24
143
  prerelease: false
25
144
  version_requirements: !ruby/object:Gem::Requirement
26
- none: false
27
145
  requirements:
28
- - - ~>
146
+ - - "~>"
29
147
  - !ruby/object:Gem::Version
30
148
  version: '1.3'
31
149
  - !ruby/object:Gem::Dependency
32
150
  name: rake
33
151
  requirement: !ruby/object:Gem::Requirement
34
- none: false
35
152
  requirements:
36
- - - ! '>='
153
+ - - "~>"
37
154
  - !ruby/object:Gem::Version
38
- version: '0'
155
+ version: '10.3'
39
156
  type: :development
40
157
  prerelease: false
41
158
  version_requirements: !ruby/object:Gem::Requirement
42
- none: false
43
159
  requirements:
44
- - - ! '>='
160
+ - - "~>"
45
161
  - !ruby/object:Gem::Version
46
- version: '0'
47
- description: A server for Boxlet, a DIY, self-hosted file storage system
162
+ version: '10.3'
163
+ description: Upload pics from your phone
48
164
  email:
49
165
  - mail@enorganik.com
50
166
  executables:
@@ -52,39 +168,47 @@ executables:
52
168
  extensions: []
53
169
  extra_rdoc_files: []
54
170
  files:
55
- - config.yml
56
171
  - LICENSE.txt
57
172
  - README.md
58
173
  - Rakefile
174
+ - bin/boxlet
59
175
  - boxlet.gemspec
176
+ - config.yml
177
+ - lib/boxlet.rb
178
+ - lib/boxlet/app.rb
179
+ - lib/boxlet/app/controller.rb
180
+ - lib/boxlet/app/router.rb
181
+ - lib/boxlet/config.rb
182
+ - lib/boxlet/db.rb
60
183
  - lib/boxlet/log.rb
61
- - lib/boxlet/tcp_server.rb
184
+ - lib/boxlet/runner.rb
62
185
  - lib/boxlet/version.rb
63
- - lib/boxlet.rb
64
- - bin/boxlet
65
- homepage: http://github.com/arktisklada/boxlet
186
+ - lib/handlers/thin.rb
187
+ - lib/rack/boxlet_url_builder.rb
188
+ - lib/rack/boxlet_url_map.rb
189
+ - lib/rack/file_upload.rb
190
+ homepage: https://github.com/arktisklada/boxlet
66
191
  licenses:
67
192
  - MIT
193
+ metadata: {}
68
194
  post_install_message:
69
195
  rdoc_options: []
70
196
  require_paths:
71
197
  - lib
72
198
  required_ruby_version: !ruby/object:Gem::Requirement
73
- none: false
74
199
  requirements:
75
- - - ! '>='
200
+ - - ">="
76
201
  - !ruby/object:Gem::Version
77
202
  version: '0'
78
203
  required_rubygems_version: !ruby/object:Gem::Requirement
79
- none: false
80
204
  requirements:
81
- - - ! '>='
205
+ - - ">="
82
206
  - !ruby/object:Gem::Version
83
207
  version: '0'
84
208
  requirements: []
85
209
  rubyforge_project:
86
- rubygems_version: 1.8.23
210
+ rubygems_version: 2.2.2
87
211
  signing_key:
88
- specification_version: 3
89
- summary: A server for Boxlet, a DIY, self-hosted file storage system
212
+ specification_version: 4
213
+ summary: Upload pics from your phone
90
214
  test_files: []
@@ -1,62 +0,0 @@
1
- require "socket"
2
-
3
- class TcpServer
4
-
5
- include Log
6
-
7
- def initialize()
8
- @listen_ip = Boxlet::Server.config['tcp_listen_ip'] || '127.0.0.1'
9
- @listen_port = Boxlet::Server.config['tcp_listen_port'] || 11311
10
-
11
- @log = get_logger('log/tcp.log', 10, 1024000, Boxlet::Server.config['tcp_debug'] ? Logger::DEBUG : Logger::WARN);
12
- @log.info("Initializing TCP server on #{@listen_ip}:#{@listen_port}")
13
- @server = TCPServer.open(@listen_ip, @listen_port)
14
-
15
- @connections = Hash.new
16
- end
17
-
18
- def start
19
- @log.info("Starting TCP server")
20
-
21
- # Start a new thread for the TCP server so that it does not block and
22
- # hold up the rest of the program execution
23
- # Thread.start() do
24
- loop {
25
- # When a new connection comes in, create a new thread and begin handling
26
- # requests
27
- Thread.start(@server.accept) do |client|
28
- @log.info("Client connected!")
29
-
30
- # Output welcome messages
31
- client.puts Time.now.ctime
32
- client.puts "Welcome to Boxlet!"
33
-
34
- # Read input from TCP client
35
- while line = client.gets
36
- entry = line.split
37
- cmd = entry.shift
38
-
39
- case cmd
40
- # Retrieve config value
41
- when "config_get" then client.puts(Boxlet::Server.config[entry[0]] || "ERROR")
42
-
43
- # Halt the server
44
- when "stop" then
45
- client.puts "Daemon halting!"
46
- @log.info("Daemon halting!")
47
- exit(0)
48
-
49
- # Disconnect the client
50
- when "quit" then
51
- client.puts "Goodbye!"
52
- client.close
53
- else
54
- client.puts "INVALID"
55
- end
56
- end
57
- end
58
- }
59
- # end
60
- end
61
-
62
- end