読者です 読者をやめる 読者になる 読者になる

元フリーエンジニアライフ

Ruby on Rails とか MovableType とかAWSやってるフリーランスウェブエンジニアの記録でした。現在は法人成りしてIT社長。

Flow.js + S3 + Ruby で分割アップロード バックエンド実装メモ

flowjs.png 大容量ファイルのアップロードのため、[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 ```