
大容量ファイルのアップロードのため、[Flow.js](
https://github.com/flowjs/flow.js/tree/master)を使って分割を実装しました。その時のメモ。
## 前提
インスタンスを作ったり消したりするし、
複数インスタンスの場合もあるので、ローカル
ファイルシステム内に`chunk`を置きたくない。
## 参考
### [
Ruby backend in
Sinatra](
https://github.com/flowjs/flow.js/blob/master/samples/Ruby%20backend%20in%20Sinatra.md)
タイトルまま。
これをベースにFileの代わりに`
AWS::S3`を使うようにしました。
### [Efficient
Amazon S3 Object Concatenation Using the
AWS SDK for
Ruby](
http://ruby.awsblog.com/post/Tx2JE2CXGQGQ6A4/Efficient-Amazon-S3-Object-Concatenation-Using-the-AWS-SDK-for-Ruby)
S3に置いた
複数のファイルをS3上で結合する方法についての解説記事。
## コードサンプル(
Rails)
簡略化するとこんな感じでとりあえずダサいですが動きます。
実際は結合処理はここでは行わず、キューやSWFを使った方がよいと思います。たぶん。
```
ruby
class UploadController < ApplicationController
def get
obj = bucket.objects[chunk_file_path]
head obj.exists? ? 200 : 404
end
def post
save_file!
combine_file! if last_chunk?
head 200
end
private
def save_file!
obj = bucket.objects[chunk_file_path]
obj.write Pathname(File.open(params['file'].tempfile.to_path))
end
def last_chunk?
params[:flowChunkNumber].to_i == params[:flowTotalChunks].to_i
end
def chunk_file_path
File.join chunk_file_directory, "#{params[:flowFilename]}.part#{params[:flowChunkNumber]}"
end
def chunk_file_directory
File.join 'tmp', 'flow', 'chunks', params[:flowIdentifier]
end
def combine_file!
obj = bucket.objects[final_file_path]
upload = obj.multipart_upload
file_chunks.each do |file_chunk_path|
upload.copy_part File.join(bucket.name, file_chunk_path)
end
upload.complete()
bucket.objects.with_prefix(chunk_file_directory).delete_all
end
def final_file_path
File.join final_file_directory, params[:flowFilename]
end
def final_file_directory
'src'
end
def file_chunks
bucket.objects.with_prefix(chunk_file_directory).
collect(&:key).
sort_by do |f|
f.split('.part')[1].to_i
end
end
def bucket
return @bucket if defined?(@bucket)
s3 =
AWS::S3.new
@bucket = s3.buckets['sample']
end
end
```