rest-ftp-daemon 0.9.0 → 0.20.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 +15 -0
- data/.gitignore +8 -0
- data/Gemfile +3 -2
- data/Gemfile.lock +0 -61
- data/Rakefile +1 -49
- data/lib/config.ru +1 -0
- data/lib/rest-ftp-daemon.rb +257 -253
- data/lib/version.rb +3 -0
- data/rest-ftp-daemon.gemspec +46 -61
- metadata +18 -74
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
ODc0NWU3ZTFkMDMxNzJkYzNmZmZhNzRlODZlYzdiNDI4Y2NlMWE2Ng==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
NmM2NTA1MDViYzU1MDc0MDViNTI0MWY2NDQ1NjAzY2FkNDcxMTA1Yw==
|
7
|
+
SHA512:
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
MDBhM2E0YmQyNjMzM2Y2MGE5OTBiOTA4YmI2Y2NiYTI1MjYxZmMwOWEyMjlk
|
10
|
+
MzQ4NTk0N2FiMDA3NWQ1N2Y0YzJkZGRkZWUyZDRhZDEzODAwOWRiNDRmMDI3
|
11
|
+
ZTVhMTY2ZDkwMDg3YTAxODQ5NWY5MzcwZGM2N2QyZjQ0MDJlYWM=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
MTA1ZmRkMGYzM2VkMWExMDIwMDVjZDhkZWFhOGI1YzYxMGNjNzViNzQxNzdk
|
14
|
+
YjIzYWU0ZmIyYzZjNTRlYTkwMTY0YTAxMDUwMWU1N2Q5MWFhNDgwNTM3OGNl
|
15
|
+
ODJmODA4MDZiMjhlOWRmOTY2M2IxMDFhYzdiYzgxMTNhOGRlYzU=
|
data/.gitignore
ADDED
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,81 +1,20 @@
|
|
1
1
|
GEM
|
2
2
|
remote: http://rubygems.org/
|
3
3
|
specs:
|
4
|
-
activesupport (4.1.4)
|
5
|
-
i18n (~> 0.6, >= 0.6.9)
|
6
|
-
json (~> 1.7, >= 1.7.7)
|
7
|
-
minitest (~> 5.1)
|
8
|
-
thread_safe (~> 0.1)
|
9
|
-
tzinfo (~> 1.1)
|
10
|
-
addressable (2.3.6)
|
11
|
-
builder (3.2.2)
|
12
|
-
descendants_tracker (0.0.4)
|
13
|
-
thread_safe (~> 0.3, >= 0.3.1)
|
14
|
-
faraday (0.9.0)
|
15
|
-
multipart-post (>= 1.2, < 3)
|
16
|
-
git (1.2.8)
|
17
|
-
github_api (0.12.0)
|
18
|
-
addressable (~> 2.3)
|
19
|
-
descendants_tracker (~> 0.0.4)
|
20
|
-
faraday (~> 0.8, < 0.10)
|
21
|
-
hashie (>= 3.2)
|
22
|
-
multi_json (>= 1.7.5, < 2.0)
|
23
|
-
nokogiri (~> 1.6.3)
|
24
|
-
oauth2
|
25
|
-
hashie (3.2.0)
|
26
|
-
highline (1.6.21)
|
27
|
-
i18n (0.6.11)
|
28
|
-
jeweler (2.0.1)
|
29
|
-
builder
|
30
|
-
bundler (>= 1.0)
|
31
|
-
git (>= 1.2.5)
|
32
|
-
github_api
|
33
|
-
highline (>= 1.6.15)
|
34
|
-
nokogiri (>= 1.5.10)
|
35
|
-
rake
|
36
|
-
rdoc
|
37
4
|
json (1.8.1)
|
38
|
-
jwt (1.0.0)
|
39
|
-
mini_portile (0.6.0)
|
40
|
-
minitest (5.4.0)
|
41
|
-
multi_json (1.10.1)
|
42
|
-
multi_xml (0.5.5)
|
43
|
-
multipart-post (2.0.0)
|
44
|
-
nokogiri (1.6.3.1)
|
45
|
-
mini_portile (= 0.6.0)
|
46
|
-
oauth2 (1.0.0)
|
47
|
-
faraday (>= 0.8, < 0.10)
|
48
|
-
jwt (~> 1.0)
|
49
|
-
multi_json (~> 1.3)
|
50
|
-
multi_xml (~> 0.5)
|
51
|
-
rack (~> 1.2)
|
52
5
|
rack (1.5.2)
|
53
6
|
rack-protection (1.5.3)
|
54
7
|
rack
|
55
|
-
rake (10.3.2)
|
56
|
-
rdoc (4.1.1)
|
57
|
-
json (~> 1.4)
|
58
|
-
shoulda (3.5.0)
|
59
|
-
shoulda-context (~> 1.0, >= 1.0.1)
|
60
|
-
shoulda-matchers (>= 1.4.1, < 3.0)
|
61
|
-
shoulda-context (1.2.1)
|
62
|
-
shoulda-matchers (2.6.2)
|
63
|
-
activesupport (>= 3.0.0)
|
64
8
|
sinatra (1.4.5)
|
65
9
|
rack (~> 1.4)
|
66
10
|
rack-protection (~> 1.4)
|
67
11
|
tilt (~> 1.3, >= 1.3.4)
|
68
|
-
thread_safe (0.3.4)
|
69
12
|
tilt (1.4.1)
|
70
|
-
tzinfo (1.2.1)
|
71
|
-
thread_safe (~> 0.1)
|
72
13
|
|
73
14
|
PLATFORMS
|
74
15
|
ruby
|
75
16
|
|
76
17
|
DEPENDENCIES
|
77
18
|
bundler (~> 1.0)
|
78
|
-
jeweler (~> 2.0.1)
|
79
19
|
json
|
80
|
-
shoulda
|
81
20
|
sinatra
|
data/Rakefile
CHANGED
@@ -1,51 +1,3 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
-
|
2
|
+
require "bundler/gem_tasks"
|
3
3
|
require 'rubygems'
|
4
|
-
require 'bundler'
|
5
|
-
begin
|
6
|
-
Bundler.setup(:default, :development)
|
7
|
-
rescue Bundler::BundlerError => e
|
8
|
-
$stderr.puts e.message
|
9
|
-
$stderr.puts "Run `bundle install` to install missing gems"
|
10
|
-
exit e.status_code
|
11
|
-
end
|
12
|
-
require 'rake'
|
13
|
-
|
14
|
-
require 'jeweler'
|
15
|
-
Jeweler::Tasks.new do |gem|
|
16
|
-
# gem is a Gem::Specification... see http://guides.rubygems.org/specification-reference/ for more options
|
17
|
-
gem.name = "rest-ftp-daemon"
|
18
|
-
gem.homepage = "http://github.com/bmedici/rest-ftp-daemon"
|
19
|
-
gem.license = "MIT"
|
20
|
-
gem.summary = "RESTful FTP client daemon"
|
21
|
-
gem.description = "This is a pretty simple FTP client daemon, controlled through a RESTfull API"
|
22
|
-
gem.email = "rest-ftp-daemon@bmconseil.com"
|
23
|
-
gem.authors = ["Bruno"]
|
24
|
-
# dependencies defined in Gemfile
|
25
|
-
end
|
26
|
-
Jeweler::RubygemsDotOrgTasks.new
|
27
|
-
|
28
|
-
require 'rake/testtask'
|
29
|
-
Rake::TestTask.new(:test) do |test|
|
30
|
-
test.libs << 'lib' << 'test'
|
31
|
-
test.pattern = 'test/**/test_*.rb'
|
32
|
-
test.verbose = true
|
33
|
-
end
|
34
|
-
|
35
|
-
desc "Code coverage detail"
|
36
|
-
task :simplecov do
|
37
|
-
ENV['COVERAGE'] = "true"
|
38
|
-
Rake::Task['test'].execute
|
39
|
-
end
|
40
|
-
|
41
|
-
task :default => :test
|
42
|
-
|
43
|
-
require 'rdoc/task'
|
44
|
-
Rake::RDocTask.new do |rdoc|
|
45
|
-
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
46
|
-
|
47
|
-
rdoc.rdoc_dir = 'rdoc'
|
48
|
-
rdoc.title = "rest-ftp-daemon #{version}"
|
49
|
-
rdoc.rdoc_files.include('README*')
|
50
|
-
rdoc.rdoc_files.include('lib/**/*.rb')
|
51
|
-
end
|
data/lib/config.ru
CHANGED
data/lib/rest-ftp-daemon.rb
CHANGED
@@ -1,305 +1,309 @@
|
|
1
|
-
|
1
|
+
# module RestFtpDaemon
|
2
2
|
|
3
|
-
|
4
|
-
configure :development, :production do
|
3
|
+
class RestFtpDaemon < Sinatra::Base
|
5
4
|
|
6
|
-
#
|
7
|
-
|
5
|
+
# General config
|
6
|
+
configure :development, :production do
|
8
7
|
|
9
|
-
|
10
|
-
|
8
|
+
# Create new thread group
|
9
|
+
@@workers = ThreadGroup.new
|
11
10
|
|
12
|
-
|
13
|
-
|
14
|
-
disable :logging
|
15
|
-
end
|
16
|
-
|
17
|
-
# Server initialization
|
18
|
-
def initialize
|
19
|
-
# Setup logger
|
20
|
-
@logger = Logger.new(APP_LOGTO, 'daily')
|
21
|
-
#@logger = Logger.new
|
22
|
-
#@logger.level = Logger::INFO
|
23
|
-
|
24
|
-
# Other stuff
|
25
|
-
@@last_worker_id = 0
|
26
|
-
@@hostname = `hostname`.chomp
|
11
|
+
# Logging configuration
|
12
|
+
#use Rack::CommonLogger, logger
|
27
13
|
|
28
|
-
|
29
|
-
|
14
|
+
# Some other configuration
|
15
|
+
disable :sessions
|
16
|
+
disable :logging
|
17
|
+
end
|
30
18
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
19
|
+
# Server initialization
|
20
|
+
def initialize
|
21
|
+
# Setup logger
|
22
|
+
@logger = Logger.new(APP_LOGTO, 'daily')
|
23
|
+
#@logger = Logger.new
|
24
|
+
#@logger.level = Logger::INFO
|
35
25
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
end
|
26
|
+
# Other stuff
|
27
|
+
@@last_worker_id = 0
|
28
|
+
@@hostname = `hostname`.chomp
|
40
29
|
|
41
|
-
|
42
|
-
|
43
|
-
# Debug query
|
44
|
-
info "GET /jobs"
|
30
|
+
super
|
31
|
+
end
|
45
32
|
|
46
|
-
#
|
47
|
-
|
48
|
-
|
49
|
-
|
33
|
+
# Server global status
|
34
|
+
get "/" do
|
35
|
+
# Debug query
|
36
|
+
info "GET /"
|
50
37
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
38
|
+
# Build response
|
39
|
+
content_type :json
|
40
|
+
JSON.pretty_generate get_status
|
41
|
+
end
|
55
42
|
|
56
|
-
#
|
57
|
-
|
43
|
+
# List jobs
|
44
|
+
get "/jobs" do
|
45
|
+
# Debug query
|
46
|
+
info "GET /jobs"
|
58
47
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
end
|
48
|
+
# Build response
|
49
|
+
content_type :json
|
50
|
+
JSON.pretty_generate get_jobs
|
51
|
+
end
|
64
52
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
53
|
+
# Get job info
|
54
|
+
get "/jobs/:id" do
|
55
|
+
# Debug query
|
56
|
+
info "GET /jobs/#{params[:id]}"
|
69
57
|
|
70
|
-
|
71
|
-
|
58
|
+
# Find this process by name
|
59
|
+
found = find_job params[:id]
|
72
60
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
61
|
+
# Build response
|
62
|
+
error 404 and return if found.nil?
|
63
|
+
content_type :json
|
64
|
+
JSON.pretty_generate found
|
65
|
+
end
|
78
66
|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
payload = JSON.parse request.body.read
|
67
|
+
# Delete jobs
|
68
|
+
delete "/jobs/:id" do
|
69
|
+
# Debug query
|
70
|
+
info "DELETE /jobs/#{params[:name]}"
|
84
71
|
|
85
|
-
|
86
|
-
|
72
|
+
# Find and kill this job
|
73
|
+
found = delete_job params[:id]
|
87
74
|
|
88
|
-
|
89
|
-
|
75
|
+
# Build response
|
76
|
+
error 404 and return if found.nil?
|
77
|
+
content_type :json
|
78
|
+
JSON.pretty_generate found
|
79
|
+
end
|
90
80
|
|
91
|
-
#
|
92
|
-
|
93
|
-
|
94
|
-
|
81
|
+
# Spawn a new thread for this new job
|
82
|
+
post '/jobs' do
|
83
|
+
# Extract payload
|
84
|
+
request.body.rewind
|
85
|
+
payload = JSON.parse request.body.read
|
95
86
|
|
96
|
-
|
87
|
+
# Debug query
|
88
|
+
info "POST /jobs: #{payload.to_json}"
|
97
89
|
|
98
|
-
|
99
|
-
|
100
|
-
info "process_job: starting"
|
101
|
-
job = Thread.current.job
|
102
|
-
job_status :started
|
103
|
-
transferred = 0
|
90
|
+
# Spawn a thread for this job
|
91
|
+
result = new_job payload
|
104
92
|
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
job_error ERR_JOB_SOURCE_NOTFOUND, :ERR_JOB_SOURCE_NOTFOUND
|
109
|
-
return
|
110
|
-
end
|
111
|
-
info "process_job: job_source: #{job_source}"
|
112
|
-
source_size = File.size job_source
|
113
|
-
job_set :source_size, source_size
|
114
|
-
|
115
|
-
# Check target
|
116
|
-
job_target = job["target"]
|
117
|
-
target = URI(job_target) rescue nil
|
118
|
-
if job_target.nil? || target.nil?
|
119
|
-
job_error ERR_JOB_TARGET_UNPARSEABLE, :ERR_JOB_TARGET_UNPARSEABLE
|
120
|
-
return
|
121
|
-
end
|
122
|
-
info "process_job: job_target: #{job_target}"
|
123
|
-
|
124
|
-
# Split URI
|
125
|
-
target_path = File.dirname target.path
|
126
|
-
target_name = File.basename target.path
|
127
|
-
info "ftp_transfer: job_target.host [#{target.host}]"
|
128
|
-
info "ftp_transfer: target_path [#{target_path}]"
|
129
|
-
info "ftp_transfer: target_name [#{target_name}]"
|
130
|
-
|
131
|
-
# Prepare FTP transfer
|
132
|
-
ftp = Net::FTP.new(target.host)
|
133
|
-
ftp.passive = true
|
134
|
-
ftp.login
|
135
|
-
ftp.chdir(target_path)
|
136
|
-
|
137
|
-
|
138
|
-
# Check if target file is found
|
139
|
-
info "source: checking target file"
|
140
|
-
job_status :checking_target
|
141
|
-
job_error ERR_BUSY, :checking_target
|
142
|
-
|
143
|
-
results = ftp.list(target_name)
|
144
|
-
info "ftp.list: #{results}"
|
145
|
-
unless results.count.zero?
|
146
|
-
job_error ERR_JOB_TARGET_PRESENT, :ERR_JOB_TARGET_PRESENT
|
147
|
-
info "target: existing: ERR_JOB_TARGET_PRESENT"
|
148
|
-
ftp.close
|
149
|
-
return
|
93
|
+
# Build response
|
94
|
+
content_type :json
|
95
|
+
JSON.pretty_generate result
|
150
96
|
end
|
151
97
|
|
98
|
+
protected
|
99
|
+
|
100
|
+
def process_job
|
101
|
+
# Init
|
102
|
+
info "process_job: starting"
|
103
|
+
job = Thread.current.job
|
104
|
+
job_status :started
|
105
|
+
transferred = 0
|
152
106
|
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
107
|
+
# Check source
|
108
|
+
job_source = File.expand_path(job["source"])
|
109
|
+
if !(File.exists? job_source)
|
110
|
+
job_error ERR_JOB_SOURCE_NOTFOUND, :ERR_JOB_SOURCE_NOTFOUND
|
111
|
+
return
|
112
|
+
end
|
113
|
+
info "process_job: job_source: #{job_source}"
|
114
|
+
source_size = File.size job_source
|
115
|
+
job_set :source_size, source_size
|
116
|
+
|
117
|
+
# Check target
|
118
|
+
job_target = job["target"]
|
119
|
+
target = URI(job_target) rescue nil
|
120
|
+
if job_target.nil? || target.nil?
|
121
|
+
job_error ERR_JOB_TARGET_UNPARSEABLE, :ERR_JOB_TARGET_UNPARSEABLE
|
122
|
+
return
|
123
|
+
end
|
124
|
+
info "process_job: job_target: #{job_target}"
|
125
|
+
|
126
|
+
# Split URI
|
127
|
+
target_path = File.dirname target.path
|
128
|
+
target_name = File.basename target.path
|
129
|
+
info "ftp_transfer: job_target.host [#{target.host}]"
|
130
|
+
info "ftp_transfer: target_path [#{target_path}]"
|
131
|
+
info "ftp_transfer: target_name [#{target_name}]"
|
132
|
+
|
133
|
+
# Prepare FTP transfer
|
134
|
+
ftp = Net::FTP.new(target.host)
|
135
|
+
ftp.passive = true
|
136
|
+
ftp.login
|
137
|
+
ftp.chdir(target_path)
|
138
|
+
|
139
|
+
|
140
|
+
# Check if target file is found
|
141
|
+
info "source: checking target file"
|
142
|
+
job_status :checking_target
|
143
|
+
job_error ERR_BUSY, :checking_target
|
144
|
+
|
145
|
+
results = ftp.list(target_name)
|
146
|
+
info "ftp.list: #{results}"
|
147
|
+
unless results.count.zero?
|
148
|
+
job_error ERR_JOB_TARGET_PRESENT, :ERR_JOB_TARGET_PRESENT
|
149
|
+
info "target: existing: ERR_JOB_TARGET_PRESENT"
|
150
|
+
ftp.close
|
151
|
+
return
|
152
|
+
end
|
158
153
|
|
159
|
-
begin
|
160
|
-
ftp.putbinaryfile(job_source, target_name, TRANSFER_CHUNK_SIZE) do |block|
|
161
|
-
# Update thread info
|
162
|
-
percent = (100.0 * transferred / source_size).round(1)
|
163
|
-
job_set :progress, percent
|
164
|
-
job_set :transferred, transferred
|
165
|
-
info "transferring [#{percent} %] of [#{target_name}]"
|
166
154
|
|
167
|
-
|
168
|
-
|
155
|
+
# Do transfer
|
156
|
+
info "source: starting stransfer"
|
157
|
+
#Thread.current[:status] = :transferring
|
158
|
+
job_status :uploading
|
159
|
+
job_error ERR_BUSY, :uploading
|
160
|
+
|
161
|
+
begin
|
162
|
+
ftp.putbinaryfile(job_source, target_name, TRANSFER_CHUNK_SIZE) do |block|
|
163
|
+
# Update thread info
|
164
|
+
percent = (100.0 * transferred / source_size).round(1)
|
165
|
+
job_set :progress, percent
|
166
|
+
job_set :transferred, transferred
|
167
|
+
info "transferring [#{percent} %] of [#{target_name}]"
|
168
|
+
|
169
|
+
# Update counters
|
170
|
+
transferred += TRANSFER_CHUNK_SIZE
|
171
|
+
end
|
172
|
+
|
173
|
+
rescue Net::FTPPermError
|
174
|
+
#job_status :failed
|
175
|
+
job_error ERR_JOB_PERMISSION, :ERR_JOB_PERMISSION
|
176
|
+
info "source: FAILED: PERMISSIONS ERROR"
|
177
|
+
|
178
|
+
else
|
179
|
+
#job_status :finished
|
180
|
+
job_error ERR_OK, :finished
|
181
|
+
info "source: finished stransfer"
|
169
182
|
end
|
170
183
|
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
info "source: FAILED: PERMISSIONS ERROR"
|
184
|
+
# Close FTP connexion
|
185
|
+
ftp.close
|
186
|
+
end
|
175
187
|
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
188
|
+
def get_status
|
189
|
+
info "> get_status"
|
190
|
+
{
|
191
|
+
app_name: APP_NAME,
|
192
|
+
hostname: @@hostname,
|
193
|
+
version: APP_VER,
|
194
|
+
started: APP_STARTED,
|
195
|
+
uptime: (Time.now - APP_STARTED).round(1),
|
196
|
+
jobs_count: @@workers.list.count,
|
197
|
+
}
|
180
198
|
end
|
181
199
|
|
182
|
-
|
183
|
-
|
184
|
-
end
|
200
|
+
def get_jobs
|
201
|
+
info "> get_jobs"
|
185
202
|
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
app_name: APP_NAME,
|
190
|
-
hostname: @@hostname,
|
191
|
-
version: APP_VER,
|
192
|
-
started: APP_STARTED,
|
193
|
-
uptime: (Time.now - APP_STARTED).round(1),
|
194
|
-
jobs_count: @@workers.list.count,
|
195
|
-
}
|
196
|
-
end
|
203
|
+
# Collect info's
|
204
|
+
@@workers.list.map { |thread| thread.job }
|
205
|
+
end
|
197
206
|
|
198
|
-
|
199
|
-
|
207
|
+
def delete_job id
|
208
|
+
info "> delete_job(#{id})"
|
200
209
|
|
201
|
-
|
202
|
-
|
203
|
-
end
|
210
|
+
# Find jobs with this id
|
211
|
+
jobs = jobs_with_id id
|
204
212
|
|
205
|
-
|
206
|
-
|
213
|
+
# Kill them
|
214
|
+
jobs.each{ |thread| Thread.kill(thread) }
|
207
215
|
|
208
|
-
|
209
|
-
|
216
|
+
# Return the first one
|
217
|
+
return nil if jobs.empty?
|
218
|
+
jobs.first.job
|
219
|
+
end
|
210
220
|
|
211
|
-
|
212
|
-
|
221
|
+
def find_job id
|
222
|
+
info "> find_job(#{id})"
|
213
223
|
|
214
|
-
|
215
|
-
|
216
|
-
jobs.first.job
|
217
|
-
end
|
224
|
+
# Find jobs with this id
|
225
|
+
jobs = jobs_with_id id
|
218
226
|
|
219
|
-
|
220
|
-
|
227
|
+
# Return the first one
|
228
|
+
return nil if jobs.empty?
|
229
|
+
jobs.first.job
|
230
|
+
end
|
221
231
|
|
222
|
-
|
223
|
-
|
232
|
+
def jobs_with_id id
|
233
|
+
info "> find_jobs_by_id(#{id})"
|
234
|
+
@@workers.list.select{ |thread| thread[:id].to_s == id.to_s }
|
235
|
+
end
|
224
236
|
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
237
|
+
def new_job context = {}
|
238
|
+
info "new_job"
|
239
|
+
|
240
|
+
# Generate name
|
241
|
+
@@last_worker_id +=1
|
242
|
+
host = @@hostname.split('.')[0]
|
243
|
+
worker_id = @@last_worker_id
|
244
|
+
worker_name = "#{host}-#{Process.pid.to_s}-#{worker_id}"
|
245
|
+
info "new_job: creating thread [#{worker_name}]"
|
246
|
+
|
247
|
+
# Parse parameters
|
248
|
+
job_source = context["source"]
|
249
|
+
job_target = context["target"]
|
250
|
+
return { code: ERR_REQ_SOURCE_MISSING, errmsg: :ERR_REQ_SOURCE_MISSING} if job_source.nil?
|
251
|
+
return { code: ERR_REQ_TARGET_MISSING, errmsg: :ERR_REQ_TARGET_MISSING} if job_target.nil?
|
252
|
+
|
253
|
+
# Parse dest URI
|
254
|
+
target = URI(job_target)
|
255
|
+
info target.scheme
|
256
|
+
return { code: ERR_REQ_TARGET_SCHEME, errmsg: :ERR_REQ_TARGET_SCHEME} unless target.scheme == "ftp"
|
257
|
+
|
258
|
+
# Create thread
|
259
|
+
job = Thread.new(worker_id, worker_name, job) do
|
260
|
+
# Tnitialize thread
|
261
|
+
Thread.abort_on_exception = true
|
262
|
+
job_status :initializing
|
263
|
+
job_error ERR_OK
|
264
|
+
|
265
|
+
# Initialize job info
|
266
|
+
Thread.current[:job] = {}
|
267
|
+
Thread.current[:job].merge! context if context.is_a? Enumerable
|
268
|
+
Thread.current[:id] = worker_id
|
269
|
+
job_set :worker_name, worker_name
|
270
|
+
job_set :created, Time.now
|
271
|
+
|
272
|
+
# Do the job
|
273
|
+
info "new_job: thread running"
|
274
|
+
process_job
|
275
|
+
|
276
|
+
# Sleep a few seconds before dying
|
277
|
+
job_status :graceful_ending
|
278
|
+
sleep THREAD_SLEEP_BEFORE_DIE
|
279
|
+
job_status :ended
|
280
|
+
info "new_job: thread finished"
|
281
|
+
end
|
229
282
|
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
end
|
283
|
+
# Keep thread in thread group
|
284
|
+
info "new_job: attaching thread [#{worker_name}] to group"
|
285
|
+
@@workers.add job
|
234
286
|
|
235
|
-
|
236
|
-
info "new_job"
|
237
|
-
|
238
|
-
# Generate name
|
239
|
-
@@last_worker_id +=1
|
240
|
-
host = @@hostname.split('.')[0]
|
241
|
-
worker_id = @@last_worker_id
|
242
|
-
worker_name = "#{host}-#{Process.pid.to_s}-#{worker_id}"
|
243
|
-
info "new_job: creating thread [#{worker_name}]"
|
244
|
-
|
245
|
-
# Parse parameters
|
246
|
-
job_source = context["source"]
|
247
|
-
job_target = context["target"]
|
248
|
-
return { code: ERR_REQ_SOURCE_MISSING, errmsg: :ERR_REQ_SOURCE_MISSING} if job_source.nil?
|
249
|
-
return { code: ERR_REQ_TARGET_MISSING, errmsg: :ERR_REQ_TARGET_MISSING} if job_target.nil?
|
250
|
-
|
251
|
-
# Parse dest URI
|
252
|
-
target = URI(job_target)
|
253
|
-
info target.scheme
|
254
|
-
return { code: ERR_REQ_TARGET_SCHEME, errmsg: :ERR_REQ_TARGET_SCHEME} unless target.scheme == "ftp"
|
255
|
-
|
256
|
-
# Create thread
|
257
|
-
job = Thread.new(worker_id, worker_name, job) do
|
258
|
-
# Tnitialize thread
|
259
|
-
Thread.abort_on_exception = true
|
260
|
-
job_status :initializing
|
261
|
-
job_error ERR_OK
|
262
|
-
|
263
|
-
# Initialize job info
|
264
|
-
Thread.current[:job] = {}
|
265
|
-
Thread.current[:job].merge! context if context.is_a? Enumerable
|
266
|
-
Thread.current[:id] = worker_id
|
267
|
-
job_set :worker_name, worker_name
|
268
|
-
job_set :created, Time.now
|
269
|
-
|
270
|
-
# Do the job
|
271
|
-
info "new_job: thread running"
|
272
|
-
process_job
|
273
|
-
|
274
|
-
# Sleep a few seconds before dying
|
275
|
-
job_status :graceful_ending
|
276
|
-
sleep THREAD_SLEEP_BEFORE_DIE
|
277
|
-
job_status :ended
|
278
|
-
info "new_job: thread finished"
|
287
|
+
return { code: 0, errmsg: 'success', worker_id: worker_id, context: context }
|
279
288
|
end
|
280
289
|
|
281
|
-
|
282
|
-
|
283
|
-
|
290
|
+
def info msg=""
|
291
|
+
@logger.info msg
|
292
|
+
end
|
284
293
|
|
285
|
-
|
286
|
-
|
294
|
+
def job_error error, errmsg = nil
|
295
|
+
job_set :error, error
|
296
|
+
job_set :errmsg, errmsg
|
297
|
+
end
|
298
|
+
def job_status status
|
299
|
+
job_set :status, status
|
300
|
+
end
|
287
301
|
|
288
|
-
|
289
|
-
|
290
|
-
|
302
|
+
def job_set attribute, value, thread = Thread.current
|
303
|
+
thread[:job][attribute] = value if thread[:job].is_a? Enumerable
|
304
|
+
end
|
291
305
|
|
292
|
-
def job_error error, errmsg = nil
|
293
|
-
job_set :error, error
|
294
|
-
job_set :errmsg, errmsg
|
295
|
-
end
|
296
|
-
def job_status status
|
297
|
-
job_set :status, status
|
298
|
-
end
|
299
306
|
|
300
|
-
def job_set attribute, value, thread = Thread.current
|
301
|
-
thread[:job][attribute] = value if thread[:job].is_a? Enumerable
|
302
307
|
end
|
303
308
|
|
304
|
-
|
305
|
-
end
|
309
|
+
# end
|
data/lib/version.rb
ADDED
data/rest-ftp-daemon.gemspec
CHANGED
@@ -1,67 +1,52 @@
|
|
1
|
-
#
|
2
|
-
|
3
|
-
|
4
|
-
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'version.rb'
|
5
5
|
|
6
|
-
Gem::Specification.new do |
|
7
|
-
|
8
|
-
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "rest-ftp-daemon"
|
8
|
+
spec.version = "0.20.0"
|
9
|
+
spec.date = "2014-08-14"
|
10
|
+
spec.authors = ["Bruno MEDICI"]
|
11
|
+
spec.email = "rest-ftp-daemon@bmconseil.com"
|
12
|
+
spec.description = "This is a pretty simple FTP client daemon, controlled through a RESTfull API"
|
13
|
+
spec.summary = "RESTful FTP client daemon"
|
14
|
+
spec.homepage = "http://github.com/bmedici/rest-ftp-daemon"
|
15
|
+
spec.licenses = ["MIT"]
|
9
16
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
s.executables = ["rest-ftp-daemon"]
|
16
|
-
s.extra_rdoc_files = [
|
17
|
-
"LICENSE.txt",
|
18
|
-
"README.md"
|
19
|
-
]
|
20
|
-
s.files = [
|
21
|
-
"Gemfile",
|
22
|
-
"Gemfile.lock",
|
23
|
-
"LICENSE.txt",
|
24
|
-
"README.md",
|
25
|
-
"Rakefile",
|
26
|
-
"VERSION",
|
27
|
-
"bin/rest-ftp-daemon",
|
28
|
-
"lib/config.rb",
|
29
|
-
"lib/config.ru",
|
30
|
-
"lib/errors.rb",
|
31
|
-
"lib/extend_threads.rb",
|
32
|
-
"lib/rest-ftp-daemon.rb",
|
33
|
-
"rest-ftp-daemon.gemspec",
|
34
|
-
"test/helper.rb",
|
35
|
-
"test/test_rest-ftp-daemon.rb"
|
36
|
-
]
|
37
|
-
s.homepage = "http://github.com/bmedici/rest-ftp-daemon"
|
38
|
-
s.licenses = ["MIT"]
|
39
|
-
s.require_paths = ["lib"]
|
40
|
-
s.rubygems_version = "1.8.23"
|
41
|
-
s.summary = "RESTful FTP client daemon"
|
17
|
+
spec.files = `git ls-files -z`.split("\x0")
|
18
|
+
#spec.executables = ["rest-ftp-daemon"]
|
19
|
+
#spec.executables = `git ls-files -- bin/*`.split('\n').map{ |f| File.basename(f) }
|
20
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
21
|
+
spec.require_paths = ["lib"]
|
42
22
|
|
43
|
-
if s.respond_to? :specification_version then
|
44
|
-
s.specification_version = 3
|
45
23
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
24
|
+
spec.required_ruby_version = '>= 1.9'
|
25
|
+
|
26
|
+
spec.add_development_dependency "bundler", "~> 1.6"
|
27
|
+
spec.add_development_dependency "rake"
|
28
|
+
|
29
|
+
|
30
|
+
# spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
31
|
+
# spec.files = [
|
32
|
+
# "Gemfile",
|
33
|
+
# "Gemfile.lock",
|
34
|
+
# "LICENSE.txt",
|
35
|
+
# "README.md",
|
36
|
+
# "Rakefile",
|
37
|
+
# "VERSION",
|
38
|
+
# "bin/rest-ftp-daemon",
|
39
|
+
# "lib/config.rb",
|
40
|
+
# "lib/config.ru",
|
41
|
+
# "lib/errors.rb",
|
42
|
+
# "lib/extend_threads.rb",
|
43
|
+
# "lib/rest-ftp-daemon.rb",
|
44
|
+
# "rest-ftp-daemon.gemspec",
|
45
|
+
# "test/helper.rb",
|
46
|
+
# "test/test_rest-ftp-daemon.rb"
|
47
|
+
# ]
|
48
|
+
# spec.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
49
|
+
# spec.rubygems_version = "2.4.1"
|
50
|
+
|
66
51
|
end
|
67
52
|
|
metadata
CHANGED
@@ -1,106 +1,52 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rest-ftp-daemon
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
5
|
-
prerelease:
|
4
|
+
version: 0.20.0
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
|
-
- Bruno
|
7
|
+
- Bruno MEDICI
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date: 2014-08-
|
11
|
+
date: 2014-08-14 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
|
-
- !ruby/object:Gem::Dependency
|
15
|
-
name: sinatra
|
16
|
-
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
|
-
requirements:
|
19
|
-
- - ! '>='
|
20
|
-
- !ruby/object:Gem::Version
|
21
|
-
version: '0'
|
22
|
-
type: :runtime
|
23
|
-
prerelease: false
|
24
|
-
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
|
-
requirements:
|
27
|
-
- - ! '>='
|
28
|
-
- !ruby/object:Gem::Version
|
29
|
-
version: '0'
|
30
|
-
- !ruby/object:Gem::Dependency
|
31
|
-
name: json
|
32
|
-
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
|
-
requirements:
|
35
|
-
- - ! '>='
|
36
|
-
- !ruby/object:Gem::Version
|
37
|
-
version: '0'
|
38
|
-
type: :runtime
|
39
|
-
prerelease: false
|
40
|
-
version_requirements: !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
|
-
requirements:
|
43
|
-
- - ! '>='
|
44
|
-
- !ruby/object:Gem::Version
|
45
|
-
version: '0'
|
46
|
-
- !ruby/object:Gem::Dependency
|
47
|
-
name: shoulda
|
48
|
-
requirement: !ruby/object:Gem::Requirement
|
49
|
-
none: false
|
50
|
-
requirements:
|
51
|
-
- - ! '>='
|
52
|
-
- !ruby/object:Gem::Version
|
53
|
-
version: '0'
|
54
|
-
type: :development
|
55
|
-
prerelease: false
|
56
|
-
version_requirements: !ruby/object:Gem::Requirement
|
57
|
-
none: false
|
58
|
-
requirements:
|
59
|
-
- - ! '>='
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
version: '0'
|
62
13
|
- !ruby/object:Gem::Dependency
|
63
14
|
name: bundler
|
64
15
|
requirement: !ruby/object:Gem::Requirement
|
65
|
-
none: false
|
66
16
|
requirements:
|
67
17
|
- - ~>
|
68
18
|
- !ruby/object:Gem::Version
|
69
|
-
version: '1.
|
19
|
+
version: '1.6'
|
70
20
|
type: :development
|
71
21
|
prerelease: false
|
72
22
|
version_requirements: !ruby/object:Gem::Requirement
|
73
|
-
none: false
|
74
23
|
requirements:
|
75
24
|
- - ~>
|
76
25
|
- !ruby/object:Gem::Version
|
77
|
-
version: '1.
|
26
|
+
version: '1.6'
|
78
27
|
- !ruby/object:Gem::Dependency
|
79
|
-
name:
|
28
|
+
name: rake
|
80
29
|
requirement: !ruby/object:Gem::Requirement
|
81
|
-
none: false
|
82
30
|
requirements:
|
83
|
-
- -
|
31
|
+
- - ! '>='
|
84
32
|
- !ruby/object:Gem::Version
|
85
|
-
version:
|
33
|
+
version: '0'
|
86
34
|
type: :development
|
87
35
|
prerelease: false
|
88
36
|
version_requirements: !ruby/object:Gem::Requirement
|
89
|
-
none: false
|
90
37
|
requirements:
|
91
|
-
- -
|
38
|
+
- - ! '>='
|
92
39
|
- !ruby/object:Gem::Version
|
93
|
-
version:
|
40
|
+
version: '0'
|
94
41
|
description: This is a pretty simple FTP client daemon, controlled through a RESTfull
|
95
42
|
API
|
96
43
|
email: rest-ftp-daemon@bmconseil.com
|
97
44
|
executables:
|
98
45
|
- rest-ftp-daemon
|
99
46
|
extensions: []
|
100
|
-
extra_rdoc_files:
|
101
|
-
- LICENSE.txt
|
102
|
-
- README.md
|
47
|
+
extra_rdoc_files: []
|
103
48
|
files:
|
49
|
+
- .gitignore
|
104
50
|
- Gemfile
|
105
51
|
- Gemfile.lock
|
106
52
|
- LICENSE.txt
|
@@ -113,35 +59,33 @@ files:
|
|
113
59
|
- lib/errors.rb
|
114
60
|
- lib/extend_threads.rb
|
115
61
|
- lib/rest-ftp-daemon.rb
|
62
|
+
- lib/version.rb
|
116
63
|
- rest-ftp-daemon.gemspec
|
117
64
|
- test/helper.rb
|
118
65
|
- test/test_rest-ftp-daemon.rb
|
119
66
|
homepage: http://github.com/bmedici/rest-ftp-daemon
|
120
67
|
licenses:
|
121
68
|
- MIT
|
69
|
+
metadata: {}
|
122
70
|
post_install_message:
|
123
71
|
rdoc_options: []
|
124
72
|
require_paths:
|
125
73
|
- lib
|
126
74
|
required_ruby_version: !ruby/object:Gem::Requirement
|
127
|
-
none: false
|
128
75
|
requirements:
|
129
76
|
- - ! '>='
|
130
77
|
- !ruby/object:Gem::Version
|
131
|
-
version: '
|
132
|
-
segments:
|
133
|
-
- 0
|
134
|
-
hash: 3650939871823663291
|
78
|
+
version: '1.9'
|
135
79
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
136
|
-
none: false
|
137
80
|
requirements:
|
138
81
|
- - ! '>='
|
139
82
|
- !ruby/object:Gem::Version
|
140
83
|
version: '0'
|
141
84
|
requirements: []
|
142
85
|
rubyforge_project:
|
143
|
-
rubygems_version:
|
86
|
+
rubygems_version: 2.4.1
|
144
87
|
signing_key:
|
145
|
-
specification_version:
|
88
|
+
specification_version: 4
|
146
89
|
summary: RESTful FTP client daemon
|
147
90
|
test_files: []
|
91
|
+
has_rdoc:
|