<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>rockuw (rockuw)</title>
    <link>https://ruby-china.org/rockuw</link>
    <description>Ruby</description>
    <language>en-us</language>
    <item>
      <title>阿里云 OSS 发布 Ruby SDK 啦，支持 STS/Callback~~~</title>
      <description>&lt;p&gt;喜欢 Ruby 的同学终于可以优雅地使用 OSS 了。先看看 Rubyist 如何上传和下载文件吧：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'aliyun/oss'&lt;/span&gt;
&lt;span class="n"&gt;bucket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Aliyun&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;OSS&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="ss"&gt;endpoint: &lt;/span&gt;&lt;span class="s1"&gt;'http://oss-cn-hangzhou.aliyuncs.com'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;access_key_id: &lt;/span&gt;&lt;span class="s1"&gt;'xxx'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;access_key_secret: &lt;/span&gt;&lt;span class="s1"&gt;'yyy'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;get_bucket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'bucket'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;put_object&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'ruby'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s1"&gt;'hello world'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_object&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'ruby'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;put_object&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'rails'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:file&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'/tmp/x'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_object&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'rails'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:file&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'/tmp/y'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;是不是 so easy？OSS SDK for Ruby 支持 OSS 99.9% 的功能，主要的 highlights 包括：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;简洁的接口 put_object/get_object/list_buckets/list_objects&lt;/li&gt;
&lt;li&gt;block 风格的代码&lt;/li&gt;
&lt;li&gt;iterator 形式的列表&lt;/li&gt;
&lt;li&gt;流式上传/下载&lt;/li&gt;
&lt;li&gt;断点续传上传/下载&lt;/li&gt;
&lt;li&gt;支持 STS&lt;/li&gt;
&lt;li&gt;支持 OSS Callback（上传回调）&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;下面我们介绍其中几个：&lt;/p&gt;
&lt;h3 id="iterator形式的列表"&gt;iterator 形式的列表&lt;/h3&gt;
&lt;p&gt;OSS 用户在一个 bucket 下可能有成千上万的 objects，所以 OSS 不会将 object 列表一次性全部返回，每次最多返回 1000 条。如果我要列出前 1001 个 object 怎么办？一般来说用户可能要调用两次接口。但是在 ruby 中你只需要一行：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;list_objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;take&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1001&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;再比如用户要找 files/下文件名包含'ruby'的文件：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;list_objects&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;prefix: &lt;/span&gt;&lt;span class="s1"&gt;'files/'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;key&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;include?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'ruby'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;是不是非常方便？&lt;/p&gt;
&lt;h3 id="流式上传"&gt;流式上传&lt;/h3&gt;
&lt;p&gt;流式上传允许用户动态地一边生成内容，一边上传到 OSS，上传的数据可以 generate on the fly。如下面的例子：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;put_object&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'numbers'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="mi"&gt;1_000_000&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;stream&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;注意：这里并不是要 100 万个数字都生成完后再发送，而是一边生成一边发送的。&lt;/strong&gt;多线程？No。是协程（Fiber）。&lt;/p&gt;

&lt;p&gt;上面的代码看似简单，但是实现起来却并不简单。试想一下，&lt;code&gt;put_object&lt;/code&gt;如何调用接受的 block？如果调用那么 100 万个数字都一口气生成完了。&lt;strong&gt;如何能做到对一个函数调用一半？&lt;/strong&gt;这就需要用到 Fiber：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;hello&lt;/span&gt;
  &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s1"&gt;'hello'&lt;/span&gt;
  &lt;span class="no"&gt;Fiber&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;yield&lt;/span&gt;
  &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s1"&gt;'world'&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;world&lt;/span&gt;
  &lt;span class="n"&gt;fiber&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Fiber&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;hello&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s1"&gt;'first'&lt;/span&gt;
  &lt;span class="n"&gt;fiber&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resume&lt;/span&gt; &lt;span class="c1"&gt;# puts 'hello'&lt;/span&gt;
  &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s1"&gt;'second'&lt;/span&gt;
  &lt;span class="n"&gt;fiber&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resume&lt;/span&gt; &lt;span class="c1"&gt;# puts 'world'&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;world&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;类似上面的代码，&lt;code&gt;stream#&amp;lt;&amp;lt;&lt;/code&gt;内每接受一部分内容，会将自己 yield 出去，这样已经接受的内容就可以立即发送出去。有兴趣可以查看 SDK 代码（见文章末尾链接）。&lt;/p&gt;
&lt;h3 id="断点上传"&gt;断点上传&lt;/h3&gt;
&lt;p&gt;在上传大文件时如果中途失败了，要重新上传是不是很沮丧？有了断点上传，中途失败后可以接着上次的进度继续上传。在 ruby 中只需要：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resumable_upload&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'object_key'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'local_file'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;断点上传依赖于 OSS 提供的 multipart 功能，类似于一个事务：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;开启一个 multipart 上传 (begin transaction)&lt;/li&gt;
&lt;li&gt;将文件分成多个 part 分别上传 (do modify)&lt;/li&gt;
&lt;li&gt;完成此次 multipart 上传 (commit transaction)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;只有最后一步成功后文件才算上传成功，在此之前文件对用户是不可见的。&lt;/p&gt;

&lt;p&gt;文件被中断后如何恢复上传？如何知道哪些 parts 已经上传成功？这需要记录事务的状态信息。SDK 的做法是将这些信息（称为 checkpoint）保存在一个本地的 json 文件中。每上传完一个 part 就更新一次 checkpoint。恢复上传时从 checkpoint 文件中恢复上传的进度。&lt;/p&gt;

&lt;p&gt;另外断点上传/下载中也利用多线程实现加速，先看结果：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="vg"&gt;$ruby&lt;/span&gt; &lt;span class="n"&gt;tests&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;test_large_file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;rb&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="n"&gt;test_large_file_1gb&lt;/span&gt;                                                                                                                                                     
&lt;span class="no"&gt;Run&lt;/span&gt; &lt;span class="ss"&gt;options: &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="n"&gt;test_large_file_1gb&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;seed&lt;/span&gt; &lt;span class="mi"&gt;7587&lt;/span&gt;

&lt;span class="c1"&gt;# Running:&lt;/span&gt;

&lt;span class="n"&gt;user&lt;/span&gt;     &lt;span class="nb"&gt;system&lt;/span&gt;      &lt;span class="n"&gt;total&lt;/span&gt;        &lt;span class="n"&gt;real&lt;/span&gt;
&lt;span class="no"&gt;Upload&lt;/span&gt; &lt;span class="n"&gt;with&lt;/span&gt; &lt;span class="ss"&gt;put_object:           &lt;/span&gt;&lt;span class="mf"&gt;20.810000&lt;/span&gt;   &lt;span class="mf"&gt;1.880000&lt;/span&gt;  &lt;span class="mf"&gt;22.690000&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="mf"&gt;62.843336&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="no"&gt;Upload&lt;/span&gt; &lt;span class="n"&gt;with&lt;/span&gt; &lt;span class="ss"&gt;resumable_upload:     &lt;/span&gt;&lt;span class="mf"&gt;28.720000&lt;/span&gt;   &lt;span class="mf"&gt;9.740000&lt;/span&gt;  &lt;span class="mf"&gt;38.460000&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="mf"&gt;33.963555&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="no"&gt;Download&lt;/span&gt; &lt;span class="n"&gt;with&lt;/span&gt; &lt;span class="ss"&gt;get_object:         &lt;/span&gt;&lt;span class="mf"&gt;17.300000&lt;/span&gt;   &lt;span class="mf"&gt;4.550000&lt;/span&gt;  &lt;span class="mf"&gt;21.850000&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="mf"&gt;47.132476&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="no"&gt;Download&lt;/span&gt; &lt;span class="n"&gt;with&lt;/span&gt; &lt;span class="ss"&gt;resumable_download:  &lt;/span&gt;&lt;span class="mf"&gt;23.260000&lt;/span&gt;   &lt;span class="mf"&gt;9.530000&lt;/span&gt;  &lt;span class="mf"&gt;32.790000&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="mf"&gt;31.883211&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ruby 或者 Python 的多线程一直是个“迷”，但是对于这种重 IO 场景，用多线程效果还是很明显的。因为进行 IO 的标准库函数在需要等待 IO 时会将当前线程切出去。参考：&lt;a href="http://yehudakatz.com/2010/08/14/threads-in-ruby-enough-already/" rel="nofollow" target="_blank"&gt;http://yehudakatz.com/2010/08/14/threads-in-ruby-enough-already/&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="使用STS授权"&gt;使用 STS 授权&lt;/h3&gt;
&lt;p&gt;[STS][aliyun-sts] 是阿里云提供的临时授权服务，一般应用于在移动端场景中：应用服务器持有阿里云 OSS 的账号，移动端需要访问 OSS 时，向应用服务器申请一个临时 TOKEN。应用服务器向 STS 申请一个临时 Token，这样做的好处是：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;可以为不同的移动端设置不同的权限&lt;/li&gt;
&lt;li&gt;可以隔离不同的移动端的存储目录，例如社交应用只具有&lt;code&gt;sns/*&lt;/code&gt;目录的权限，而支付应用具有&lt;code&gt;pay/*&lt;/code&gt;目录的权限&lt;/li&gt;
&lt;li&gt;返回给移动端的临时 TOKEN 有失效期限（默认 1 小时），减小泄露的风险&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;更多使用 STS 的例子请参考：&lt;a href="https://help.aliyun.com/document_detail/oss/sdk/ruby-sdk/using-sts.html" rel="nofollow" target="_blank"&gt;https://help.aliyun.com/document_detail/oss/sdk/ruby-sdk/using-sts.html&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="使用Callback"&gt;使用 Callback&lt;/h3&gt;
&lt;p&gt;OSS 支持 [上传回调][oss-callback]：文件上传成功后，OSS 会向用户指定的服务器地址发起一个 HTTP POST 请求，以通知应用服务器相应的事件发生了。通知的内容可以携带上传成功的文件名，Bucket 名等信息。应用服务器在收到通知后可以做相应的动作，例如更新数据库、增加统计信息等。&lt;/p&gt;

&lt;p&gt;更多使用 Callback 的例子请参考：&lt;a href="https://help.aliyun.com/document_detail/oss/sdk/ruby-sdk/put-object.html" rel="nofollow" target="_blank"&gt;https://help.aliyun.com/document_detail/oss/sdk/ruby-sdk/put-object.html&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="一个简单的rails demo"&gt;一个简单的 rails demo&lt;/h3&gt;
&lt;p&gt;使用 OSS Ruby SDK 和 rails 可以在&lt;strong&gt;半小时&lt;/strong&gt;内搭建一个 oss 文件管理器，可以查看/上传/下载文件。效果图如下：&lt;/p&gt;

&lt;p&gt;&lt;img src="http://img3.tbcdn.cn/L1/461/1/320b7e22b5de82f44aa39a9720000e2827e1f738.png" title="" alt="QQ20151202_0"&gt;&lt;/p&gt;

&lt;p&gt;手把手教程：&lt;a href="https://help.aliyun.com/document_detail/oss/sdk/ruby-sdk/rails-application.html" rel="nofollow" target="_blank"&gt;https://help.aliyun.com/document_detail/oss/sdk/ruby-sdk/rails-application.html&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="更多"&gt;更多&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;github 地址：&lt;a href="https://github.com/aliyun/aliyun-oss-ruby-sdk" rel="nofollow" target="_blank"&gt;https://github.com/aliyun/aliyun-oss-ruby-sdk&lt;/a&gt;  （欢迎大家 fork, 提 issue, pr）&lt;/li&gt;
&lt;li&gt;SDK 文档：&lt;a href="http://help.aliyun.com/document_detail/oss/sdk/ruby-sdk/install.html" rel="nofollow" target="_blank"&gt;http://help.aliyun.com/document_detail/oss/sdk/ruby-sdk/install.html&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;API 文档地址：&lt;a href="http://www.rubydoc.info/gems/aliyun-sdk/" rel="nofollow" target="_blank"&gt;http://www.rubydoc.info/gems/aliyun-sdk/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;ChangeLog：&lt;a href="https://github.com/aliyun/aliyun-oss-ruby-sdk/blob/master/CHANGELOG.md" rel="nofollow" target="_blank"&gt;https://github.com/aliyun/aliyun-oss-ruby-sdk/blob/master/CHANGELOG.md&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;oss-manager: &lt;a href="https://github.com/rockuw/oss-manager" rel="nofollow" target="_blank"&gt;https://github.com/rockuw/oss-manager&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;[aliyun-sts]: &lt;a href="https://help.aliyun.com/document_detail/ram/intro/concepts.html" rel="nofollow" target="_blank"&gt;https://help.aliyun.com/document_detail/ram/intro/concepts.html&lt;/a&gt;
[oss-callback]: &lt;a href="https://help.aliyun.com/document_detail/oss/user_guide/upload_object/upload_callback.html" rel="nofollow" target="_blank"&gt;https://help.aliyun.com/document_detail/oss/user_guide/upload_object/upload_callback.html&lt;/a&gt;&lt;/p&gt;</description>
      <author>rockuw</author>
      <pubDate>Thu, 10 Dec 2015 10:56:18 +0800</pubDate>
      <link>https://ruby-china.org/topics/28334</link>
      <guid>https://ruby-china.org/topics/28334</guid>
    </item>
  </channel>
</rss>
