Last active
December 4, 2017 11:07
-
-
Save shun115/6ed0f4d9ccfee00f806167c30224056f to your computer and use it in GitHub Desktop.
nginx + nginx-upload-module + jQuery-File-Upload + railsでchunk upload
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 参考: http://bclennox.com/extremely-large-file-uploads-with-nginx-passenger-rails-and-jquery | |
cd lib | |
git clone https://github.com/vkholodkov/nginx-upload-module.git | |
cd nginx-upload-module | |
# 新し目のnginxに対応したブランチに変更 | |
git checkout 2.255 | |
# nginx-upload-moduleでstateファイルにアクセスできないバグに対応するパッチを当てる | |
# https://github.com/vkholodkov/nginx-upload-module/issues/41#issuecomment-59182124 | |
--- ngx_http_upload_module.c.bak 2017-11-30 20:57:38.586963921 +0900 | |
+++ ngx_http_upload_module.c 2017-11-30 21:02:49.299370085 +0900 | |
@@ -1195,7 +1195,7 @@ | |
ngx_file_t *file = &u->output_file; | |
ngx_path_t *path = u->store_path; | |
- ngx_path_t *state_path = u->state_store_path; | |
+// ngx_path_t *state_path = u->state_store_path; | |
uint32_t n; | |
ngx_uint_t i; | |
ngx_int_t rc; | |
@@ -1243,17 +1243,20 @@ | |
return NGX_UPLOAD_NOMEM; | |
} | |
- state_file->name.len = state_path->name.len + 1 + state_path->len + u->session_id.len + sizeof(".state")-1; | |
+// state_file->name.len = state_path->name.len + 1 + state_path->len + u->session_id.len + sizeof(".state")-1; | |
+ state_file->name.len = file->name.len + 1 + sizeof(".state"); | |
state_file->name.data = ngx_palloc(u->request->pool, state_file->name.len + 1); | |
if(state_file->name.data == NULL) | |
return NGX_UPLOAD_NOMEM; | |
- ngx_memcpy(state_file->name.data, state_path->name.data, state_path->name.len); | |
- (void) ngx_sprintf(state_file->name.data + state_path->name.len + 1 + state_path->len, | |
- "%V.state%Z", &u->session_id); | |
- | |
- ngx_create_hashed_filename(state_path, state_file->name.data, state_file->name.len); | |
+// ngx_memcpy(state_file->name.data, state_path->name.data, state_path->name.len); | |
+// (void) ngx_sprintf(state_file->name.data + state_path->name.len + 1 + state_path->len, | |
+// "%V.state%Z", &u->session_id); | |
+// | |
+// ngx_create_hashed_filename(state_path, state_file->name.data, state_file->name.len); | |
+ ngx_memcpy(state_file->name.data, file->name.data, file->name.len); | |
+ ngx_memcpy(state_file->name.data + file->name.len, ".state", sizeof(".state") + 1); | |
ngx_log_debug1(NGX_LOG_DEBUG_CORE, file->log, 0, | |
"hashed path of state file: %s", state_file->name.data); | |
# 適用 | |
patch -u ngx_http_upload_module.c < patch | |
# nginxコンパイル | |
sudo /usr/local/rvm/bin/rvm all do passenger-install-nginx-module --auto --auto-download --prefix=/opt/nginx --extra-configure-flags=" \ | |
--conf-path=/etc/nginx/nginx.conf \ | |
--pid-path=/var/run/nginx.pid \ | |
--sbin-path=/usr/sbin \ | |
--error-log-path=/var/log/nginx/error.log \ | |
--http-log-path=/var/log/nginx/access.log \ | |
--with-http_gunzip_module \ | |
--with-http_ssl_module \ | |
--add-module='/root/lib/nginx-upload-module'" | |
# nginx.conf設定の導入 | |
if ($args ~ chunk_movie_upload=on ) { | |
set $upload_field_name "user_post[movie]"; | |
upload_pass @rails; | |
upload_pass_form_field ".*"; | |
upload_store /tmp; | |
upload_store_access user:rw group:rw all:rw; | |
upload_resumable on; | |
upload_set_form_field "$upload_field_name[original_filename]" "$upload_file_name"; | |
upload_set_form_field "$upload_field_name[content_type]" "$upload_content_type"; | |
upload_set_form_field "$upload_field_name[file_path]" "$upload_tmp_path"; | |
# upload_aggregate_form_field "$upload_field_name[md5]" "$upload_file_md5"; | |
upload_aggregate_form_field "$upload_field_name[size]" "$upload_file_size"; | |
# upload_cleanup 200-599; | |
} | |
# JS | |
var hash, sessionId; | |
hash = function(s, tableSize) { | |
var a, b, h, i, j, ref; | |
b = 27183; | |
h = 0; | |
a = 31415; | |
for (i = j = 0, ref = s.length; 0 <= ref ? j < ref : j > ref; i = 0 <= ref ? ++j : --j) { | |
h = (a * h + s[i].charCodeAt()) % tableSize; | |
a = ((a % tableSize) * (b % tableSize)) % tableSize; | |
} | |
return h; | |
}; | |
sessionId = function(filename) { | |
return hash(filename, 16384); | |
}; | |
var url = "<%= hoge_path(chunk_movie_upload: 'on') %>"; | |
$('#file-addmovie').fileupload({ | |
url: url, | |
dataType: 'text', | |
type: 'POST', | |
<% if Rails.env == 'staging' || Rails.env == 'production' -%> | |
maxChunkSize: 1*1024*1024, | |
multipart: false, | |
<% else -%> | |
multipart: true, | |
<% end -%> | |
paramName: 'user_post[movie]', | |
add: function(e, data) { | |
data.headers || (data.headers = {}); | |
data.headers['Session-Id'] = sessionId(data.files[0].name); | |
return data.submit(); | |
}, | |
send: function(e, data){ | |
$('#progress').text(''); | |
$('#movies > .wrap-movie').remove(); | |
loading.show(); | |
}, | |
done: function (e, data) { | |
loading.hide(); | |
$('#movies').append('<li class="wrap-movie"><div class="img"><video src="' + JSON.parse(data.result)[0].url + '" width="200" controls></video></div></li>'); | |
}, | |
progressall: function (e, data) { | |
var progress = parseInt(data.loaded / data.total * 100, 10); | |
$('#progress').text(progress + '%'); | |
} | |
}); | |
# rails | |
movie_param = params[:user_post][:movie] | |
if movie_param.class.name == 'ActionController::Parameters' && movie_param[:file_path].present? | |
required_params[:movie] = ActionDispatch::Http::UploadedFile.new( | |
filename: movie_param[:original_filename], | |
type: movie_param[:content_type], | |
tempfile: File.new(movie_param[:file_path]), | |
head: nil | |
) | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment