SinatraおよびDataMapperに基づくホームファイルホスティング。 パート3-非常に高度な機能

前の2つの記事( 12 )は、予想以上に人気がありました。 そして今、SinatraとDataMapperに基づいたファイル共有に関する3番目の最終記事の時が来ました。



今回は以下を検討します。









同じファイル名



前回、 Kaneはアプリケーションの重要なエラーに気付きました。ファイルをダウンロードするための鍵は、そのためのダイジェストです-しかし、同じ名前の2つのファイルをアップロードするとどうなりますか? 残念ながら、それらのダイジェストは一致するため、現在のバージョンでは、どのファイルがユーザーに提供されるか(1つ目または2つ目)を判断することすらできません。 しかし、幸いなことに、このエラーは簡単に修正できます。ダウンロードするファイルのIDをダウンロードリンクに追加するだけです。 したがって、2つの同一ファイルには、次の形式の異なるリンクがあります。

 /ダイジェスト/ ID1
 /ダイジェスト/ ID2


ただし、ユーザーは他のファイルをダウンロードするためのリンクを決定することはできません(同じファイルをダウンロードするために同じダイジェストのIDを反復処理することしかできません)。 この修正では、init.rbのコードとlist.hamlテンプレートをかなり変更する必要があります。

init.rb

  get '/:sha /:id' do
   @file = StoredFile.first:sha => params [:sha] ,: id => params [:id]
   #さらに変更なし

 get '/:sha /:id / delete' do
   @file = StoredFile.first:sha => params [:sha] ,: id => params [:id]
 #さらに変更なし




list.haml

  %a {:href => "/#{file.shaasket/#{file.id}" ,: title => file.filename} = file.filename 


現在、同名のファイルは私たちを恐れていません!



ロード前の待機ページ



状況を想像してください。あなたの友人が、あなたが撮った写真を彼に送るように頼みます。 ファイルホスティングにドロップして、ファイルホスティングへのリンクを送信すると、ダウンロードを開始します。 次に、タスクを複雑にします。ファイルサイズは20メガバイトで、友人がGPRSに座っています。 当然、ファイルサイズを事前に知っていた場合、高価なトラフィックを節約するためにダウンロードすることはありませんでした。 解決策:ロードする前に表示されるページを作成し、名前とファイルサイズに関する情報を配置します。



init.rbから始めましょう。

 get '/:sha /:id' do
   @file = StoredFile.first:sha => params [:sha] ,: id => params [:id]
   params [:nowait] == 'true'でない限り
     haml:ダウンロード
  他に
     @ file.downloads + = 1
     @ file.save
     send_file "./files/#{@file.idasket.upload" ,: filename => @ file.filename ,: type => 'Application / octet-stream'
  終わり
終わり




そのため、リンクパラメータで「nowait = true」が渡された場合、ダウンロードが即座に開始されます。そうでない場合は、download.hamlテンプレートのみが表示されます。



そして実際、ここで彼は:

download.haml

 %script {:type => "text / javascript"}
   nowait = '?nowait = true';
   var timeout = true;
   setTimeout( 'if(timeout){window.location = window.location + nowait;}'、10000);
 %h1ファイルのダウンロード
 .info
  ファイルをダウンロードしようとしています
   %span.filename> = "#{@file.filename}"
  サイズ 
   %span.filesize
     = @ file.filesize / 1024
    キロバイト。 
  内でダウンロードが開始されます
   %スパン#秒10
  秒。 クリックしてください
   %a {:href => "/#{params [:sha]}?nowait = true" ,: onclick => 'timeout = false;'  }このリンク
  待ちたくない場合


最初に、10秒待機して同じリンクにリダイレクトする単純なJavaScriptがありますが、パラメーター「nowait = true」を使用し、ファイル名とサイズを示すテキスト自体を使用します。



ファイルリストテンプレートを展開して、2つのリンクが含まれるようにします-即時ダウンロード(私たちはそれを自分で使用します)と遅延ダウンロード(ICQを介してこのリンクを送信します)。 次のようになります。

list.haml

 %td.filename
   %a {:href => "/#{file.shaasket/#{file.idasket?nowait=true" ,: title => file.filename} = file.filename
   = "(#{file.filesize / 1024} Kb)"
   %a {:href => "/#{file.shaasket/#{file.id}"}転送用 




チェックを入れて、次の項目に進みます。



サス



SASSは、CSSファイルの作成を担当するHamlパッケージの一部です。 構文の観点から見ると、SASSはCSSとHamlの間にあります。セレクタと属性(CSS)を含むスキームを使用しますが、リミッターとして中括弧ではなくインデント(Haml)を使用します。



SASSファイルは、一連のルールで構成されています。

セレクター(S)
   :PROPERTY1 VALUE1
   :PROPERTY2 VALUE2
   ...
   :PROPERTY_N VALUE_N


SELECTOR(S)は1つ以上の通常のCSSセレクター(クラス、ID、タグ名)であり、PROPRETY_X / VALUE_XはCSSプロパティの名前と値です。 CSSに非常に似ていますが、いくつかの違いがあります。

一般的に、多くの利点があります-おそらく、多くのコーダーやWeb開発者は、深刻なプロジェクトを作成するときにSASSの知識から本当に恩恵を受けるでしょう。



しかし、ラムに戻ります。SASSファイルは2つの方法で使用できます。CSSファイルを取得してアプリケーションに接続するか、Sinatraに組み込まれたSASSテンプレートエンジンを使用してCSSを「オンザフライ」で生成できます。 無意味にもかかわらず、2番目の方法を使用します:)



init.rb

  '/style.css'を取得します
   response ['Content-Type'] = 'text / css;  charset = utf-8 '#応答ヘッダーを設定します
   sass:スタイル
終わり





layout.haml

  %link {:href => "/style.css" ,: media => "screen" ,: rel => "stylesheet" ,: type => "text / css"} 


さて、あなたはこのリンクで私のstyle.sassファイルを見ることができます。



これで、アプリケーションにある種のデザインができました。



認証



それでは、通常の認証メカニズムをアプリケーションに添付します。 誰もが直接リンクを介してファイルをダウンロードできるようにしたいのですが、アップロードとファイルの削除、および一般リストの表示は、パスワードを入力した後にのみ使用可能にする必要があります(簡単にするため、ハードコードされたパスワードを1つ設定します)。



この問題を次のように解決しました。HTTP認証モジュール( 参照によるコード)を取得し、libフォルダーに配置して、init.rbに次の変更を加えました。

 「lib /承認」が必要

ヘルパーは
   Sinatraを含める::認証
終わり

 「/」を取得
   require_administrative_privileges
 #次に変更なし
終わり

 「/」を投稿
   require_administrative_privileges
 #投稿は変更なし
終わり

 get '/:sha /:id / delete' do
   require_administrative_privileges
 #変更せずにさらに削除
終わり




要するに、「helpers do ... end」ブロックはすべてのブロックのコンテキストで実行されます-URLハンドラー、つまり、アプリケーション内でSinatra:Authorizationモジュールを使用可能にします。 同じブロック内で、テンプレートとメインアプリケーションで使用できるメソッドを定義できます(いわゆるヘルパーは、テンプレート内で同じコードを繰り返さないようにするヘルパーメソッドです)。



薄い下から走る



そのため、私たちのアプリケーションは産業の高みに達し、本番サーバーに展開する準備ができています。 ruby init.rbコマンドで実行し、rubyを備えたコンソールが開いているときに動作することを思い出させてください-もちろん、これは深刻ではありません-WebアプリケーションはWebサーバーによって起動されるべきです。 Webサーバーとしては、 Thinを選択します。これは、Rubyアプリケーション用のコンパクトで非常に高速なサーバーです。 インストールは簡単です:

  sudo gem install thin 




ここで、アプリケーションのディレクトリにいくつかのフォルダーを作成します。

  mkdir config
 mkdir tmp
 mkdirログ 


configフォルダーで、config.rbファイルをlibフォルダーから移動します(同時に、init.rbでファイルへのパスを修正します)。 thinを設定するには、thin.ymlを呼び出すファイルが必要です-configフォルダーに作成し、以下を記述します:

 --- 
    環境:生産
     chdir:アプリケーションカタログ
     pid:アプリケーションカタログ/ tmp / thin.pid 
     rackup:アプリケーションカタログ/ config / config.ru 
     log:アプリケーションカタログ/ log / thin.log 
     max_conns:1024 
    タイムアウト:30 
     max_persistent_conns:512 
     daemonize:true


アプリケーションのルートディレクトリにchdirを作成し、tmpフォルダーにPIDファイルを配置し、configフォルダーにRackupファイル(以下について)を作成し、log / log 30秒のタイムアウトで最大1024の同時接続、最大512の永続的な接続を維持し、デーモンとして動作します(つまり、システムにログインしているユーザーの存在に関係なく)。



ラックアップファイルについて:実際、これはRubyとWebサーバー間のラックインターフェースの構成ファイルです(この例では薄い)。 このファイルには2行のみが含まれています。

 「init」が必要
ラック::ハンドラー:: Thin.run Sinatra :: Application ,: Port => 3000 ,: Host => "0.0.0.0"


最初の行はinit.rb(つまり、アプリケーション)を接続し、2行目は3000番目のポートでシンを実行してSinatraアプリケーションを渡す必要があることをRackに伝えます。



仕事は完了です! このコマンドでアプリケーションが起動します

 シンスタート-C config / thin.yml 


設定ファイルをシンに渡すだけです。

コマンドによる停止

 シンストップ-C config / thin.yml 




RSpecを使用したテスト



Sinatraのアプリケーションをテストする人はほとんどいないことを理解しているため、最後に特別にこのセクションを終了しました。 詳細には触れず、 RSpecがどのようなものであるかを説明せず、仕様がどのように見えるかを示します。

 「シナトラ」が必要
 「シナトラ/テスト/ rspec」が必要
 「init」が必要

 「TrashFilesアプリ」の説明  
   「遅延してテンプレートをレンダリングする」必要があります
     @file = StoredFile.first 
     get "/#{@file.shaasket/#{@file.id}"
     @response ['Content-Type']。should == "text / html"
  終わり
  
   「ファイルを提供する必要がありますか?nowait = trueが指定されている場合」
     @file = StoredFile.first 
     get "/#{@file.shaasket/#{@file.idasket?nowait=true"
     @response ['Content-Type']。should == "Application / octet-stream"
     @response ['Content-Disposition']。should == "attachment; filename = \"#{@ file.filename} \ ""
  終わり
終わり


トリックはありません-たとえば、Railsの場合と同じ/ it / shouldを記述します。 主なことは、シナトラ/テスト/ rspecを接続することを忘れないことです。



ベンチマーク

コメントの1つで、結果のアプリケーションのパフォーマンスを測定するように依頼されました-問題ありません。

最初-メインページ(ファイルのリスト)のベンチマーク。

ab -n 1000 -c 1 -A admin:secret http://127.0.0.1 {000 /

 同時実行レベル:1
テストにかかった時間:24.109秒
転送された合計:3,739,000バイト
転送されるHTML:3604000バイト
 1秒あたりのリクエスト:41.48 [#/秒](平均)
リクエストあたりの時間:24.109 [ms](平均)
リクエストあたりの時間:24.109 [ms](平均、すべての同時リクエスト全体)
転送速度:151.45 [Kバイト/秒]受信





ab -n 1000 -c 10 -A admin:secret http://127.0.0.1∗000/

 同時実行レベル:10
テストにかかった時間:24.381秒
転送された合計:3,739,000バイト
転送されるHTML:3604000バイト
 1秒あたりのリクエスト:41.02 [#/秒](平均)
リクエストあたりの時間:243.811 [ms](平均)
リクエストあたりの時間:24.381 [ms](平均、すべての同時リクエスト全体)
転送速度:149.76 [Kバイト/秒]受信





ab -n 1000 -c 100 -A admin:secret http://127.0.0.1 {000 /

 同時実行レベル:100
テストにかかった時間:23.798秒
転送された合計:3,739,000バイト
転送されるHTML:3604000バイト
 1秒あたりのリクエスト:42.02 [#/秒](平均)
リクエストあたりの時間:2379.816 [ms](平均)
リクエストあたりの時間:23.798 [ms](平均、すべての同時リクエスト全体)
転送速度:153.43 [Kバイト/秒]受信


サーバーへのファイルのアップロード(ファイルサイズ1.5 Kb)

ab -n 1000 -c 1 -A admin:secret -T 'application / x-www-form-urlencoded' -p post.data http://127.0.0.1 {000 /

 同時実行レベル:1
テストにかかった時間:16.305秒
転送された合計:160000バイト
投稿された合計:242000
 1秒あたりのリクエスト:61.33 [#/秒](平均)
リクエストあたりの時間:16.305 [ms](平均)
リクエストあたりの時間:16.305 [ms](平均、すべての同時リクエスト全体)
転送速度:9.58 [キロバイト/秒]受信
                         14.49 kb / s送信
                        合計24.08 kb / s





ab -n 1000 -c 10 -A admin:secret -T 'application / x-www-form-urlencoded' -p post.data http://127.0.0.1 {000 /

 同時実行レベル:10
テストにかかった時間:18.463秒
転送された合計:161280バイト
投稿された合計:243936
転送されたHTML:0バイト
 1秒あたりのリクエスト:54.16 [#/ sec](平均)
リクエストあたりの時間:184.631 [ms](平均)
リクエストあたりの時間:18.463 [ms](平均、すべての同時リクエスト全体)
転送速度:8.53 [キロバイト/秒]受信
                         12.90 kb / s送信
                        合計21.43 kb / s




ab -n 1000 -c 100 -A admin:secret -T 'application / x-www-form-urlencoded' -p post.data http://127.0.0.1 {000 /

 同時実行レベル:100
テストにかかった時間:16.029秒
転送された合計:160160バイト
投稿された合計:242242
転送されたHTML:0バイト
 1秒あたりのリクエスト:62.39 [#/秒](平均)
リクエストあたりの時間:1602.899 [ms](平均)
リクエストあたりの時間:16.029 [ms](平均、すべての同時リクエスト全体)
転送速度:9.76 [キロバイト/秒]受信
                         14.76 kb / s送信
                        合計24.52 kb / s 




同時要求の数が100(100!)回増加しても、パフォーマンスはあまり変化しないことに注意してください。 テストは、Mac Book Core 2 Duo 2.4 Ghz、2 GB RAMで実行され、いくつかのアプリケーションがバックグラウンドで実行されました。



終わり



私の偶然に始まった物語を完了する時が来ました。 興味を持っていただければ幸いであり、少なくとも一部の人が非主流の技術(Sinatra、DataMapper、thin、haml、sass)の研究を奨励できたと思います。 最新バージョンのアプリケーションはgithubに投稿されています。 これらのかなり大きな記事を読んでくれたすべての人に感謝します。



All Articles