rong_cloud_server 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: c0a792a26e83b1a5420aa834459d44f62be0ec8c
4
+ data.tar.gz: 50b3157736cff25fa9937cd99a002d7fa5a62134
5
+ SHA512:
6
+ metadata.gz: 9a77797344c9ad396fc0f8b8586d68c061944abac3932cac51445470c2f21d28d4e9544a4ec8524bf21899d2c50a24703b51005ac3b8257b7edf4bf61fdd1ad1
7
+ data.tar.gz: 72ae4a709051e62499d409c103feb9c106e6f4d1f49b4cbd30cde0f506c3f8ee4d10c4cde46b9495e9f9fe89386ecd99be40e1372b15d1d29c7c45e678cf88fa
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ /config.yml
2
+ .byebug_history
3
+ rong_cloud.log
4
+ /doc
5
+ .yardoc/
data/README.md ADDED
@@ -0,0 +1,41 @@
1
+ 融云 Server SDK
2
+ ===
3
+
4
+ 此 gem 实现了[融云 Server API](http://www.rongcloud.cn/docs/server.html)的大部分接口的 Ruby 实现。
5
+
6
+ ### Getting Started
7
+ 1. 安装此 gem;
8
+ 2. 在项目中添加配置:
9
+
10
+ ```ruby
11
+ RongCloud.configure do |config|
12
+ config.app_key = "APP_KEY"
13
+ config.secret_key = "SECRET_KEY"
14
+ config.host = "http://api.cn.ronghub.com" # default: https://api.cn.ronghub.com, use http is convenient for debugging
15
+ end
16
+ ```
17
+ 3. 通过 service 对象使用:
18
+
19
+ ```ruby
20
+ service = RongCloud::Service.new
21
+
22
+ # 更多方法,请查看测试用例 https://github.com/Martin91/rong_cloud/tree/master/test/rong_cloud/services
23
+ service.get_token(..., ..., ...)
24
+ ```
25
+
26
+ ### 特点
27
+ 1. **轻量**:无其他依赖;
28
+ 2. **简洁**:不过分封装,仅做必要的请求实现,使用方自行处理响应的 JSON 解析后的 Hash 对象,各字段释义请自行查阅融云文档;
29
+ 3. **丰富的异常类型**:针对不同的 HTTP 状态码,抛出相对应的异常类型,同时可以通过异常对象的 `business_code` 方法获取错误业务码,可以参考[request test 的代码](https://github.com/Martin91/rong_cloud/blob/master/test/rong_cloud/request_test.rb)。
30
+
31
+ ### TODOs
32
+ 1. 私聊与系统模板消息;
33
+ 2. 聊天室其他服务以及高级接口实现;
34
+ 3. 实时消息路由;
35
+ 4. 消息历史记录;
36
+ 5. 在线状态订阅。
37
+
38
+ ### How to contribute
39
+ 1. Fork this repo;
40
+ 2. Write your code and test;
41
+ 3. Open a new Pull Request.
@@ -0,0 +1,3 @@
1
+ app_key: APP_KEY
2
+ app_secret: APP_SECRET
3
+ host: https://api.cn.ronghub.com
@@ -0,0 +1,30 @@
1
+ require "logger"
2
+
3
+ module RongCloud
4
+ # 管理融云 SDK 连接配置信息
5
+ #
6
+ module Configuration
7
+ # 默认 API 服务器,使用 https
8
+ DEFAULT_HOST = "https://api.cn.ronghub.com".freeze
9
+
10
+ module ModuleMethods
11
+ attr_accessor :app_key, :app_secret, :host, :logger
12
+
13
+ # 获取目标主机,默认为 https://api.cn.ronghub.com
14
+ #
15
+ def host
16
+ @host || DEFAULT_HOST
17
+ end
18
+
19
+ # 获取日志文件对象,默认日志文件为标准输出
20
+ def logger
21
+ @logger || default_logger
22
+ end
23
+
24
+ def default_logger
25
+ @default_logger ||= ::Logger.new(STDOUT)
26
+ end
27
+ end
28
+ extend ModuleMethods
29
+ end
30
+ end
@@ -0,0 +1,39 @@
1
+ module RongCloud
2
+ # 不支持的消息类型错误
3
+ class UnsupportedMessageChannelName < ::StandardError;end
4
+ # 与融云接口请求相关的基本错误类型,其他错误类型继承此类型
5
+ class RequestError < ::StandardError
6
+ # @!attribute [rw] business_code
7
+ # 接口错误时的业务返回码,详见:http://www.rongcloud.cn/docs/server.html#API_方法返回值说明
8
+ attr_accessor :business_code
9
+ end
10
+
11
+ # 错误请求
12
+ class BadRequest < RequestError;end
13
+ # 验证错误
14
+ class AuthenticationFailed < RequestError;end
15
+ # 被拒绝
16
+ class RequestForbidden < RequestError;end
17
+ # 资源不存在
18
+ class ResourceNotFound < RequestError;end
19
+ # 群上限
20
+ class ExceedLimit < RequestError;end
21
+ # 过多的请求
22
+ class TooManyRequests < RequestError;end
23
+ # 内部服务器错误
24
+ class InternalServerError < RequestError;end
25
+ # 内部服务器响应超时
26
+ class Timeout < RequestError;end
27
+
28
+ # 融云服务器响应状态码到 Ruby 错误类型的映射
29
+ HTTP_CODE_TO_ERRORS_MAP = {
30
+ "400" => BadRequest,
31
+ "401" => AuthenticationFailed,
32
+ "403" => RequestForbidden,
33
+ "404" => ResourceNotFound,
34
+ "405" => ExceedLimit,
35
+ "429" => TooManyRequests,
36
+ "500" => InternalServerError,
37
+ "504" => Timeout
38
+ }.freeze
39
+ end
@@ -0,0 +1,69 @@
1
+ require 'net/http'
2
+ require 'json'
3
+ require 'rong_cloud/signature'
4
+
5
+ module RongCloud
6
+ # 请求封装类,所有请求基于 Net::HTTP,自动支持 http 或者 https
7
+ #
8
+ module Request
9
+ include Signature
10
+
11
+ # 拼接请求的接口的路径
12
+ #
13
+ # @param path [String] 接口的相对路径,e.g. "/user/getToken" 或者 "user/getToken",代码中自动处理开头的斜杠
14
+ # @return [URI] 请求全路径生成的 URI 对象,自动追加 .json 格式扩展名
15
+ #
16
+ def get_uri(path)
17
+ url = "#{RongCloud::Configuration.host}/#{path.gsub(/^\//, "")}"
18
+ URI(url.end_with?(".json") ? url : "#{url}.json")
19
+ end
20
+
21
+ # 实例化请求对象
22
+ #
23
+ # @param uri [URI] 请求路径对象
24
+ # @param params [Hash] 请求的参数,所有参数通过 form encoded data 方式发送
25
+ # @return [Net::HTTP::Post] 请求的实例
26
+ #
27
+ def initialize_request(uri, params)
28
+ req = Net::HTTP::Post.new(uri)
29
+ req.set_form_data(params) if params.respond_to?(:map)
30
+ signed_headers.each { |header, value| req[header] = value }
31
+
32
+ req
33
+ end
34
+
35
+ # 解析响应数据,包含错误检测
36
+ #
37
+ # @param res [HTTPResponse] 响应结果的实例
38
+ # @return [Hash] JSON 解析后的响应正文
39
+ # @raise [RongCloud::BadRequest] 请求参数有误,缺失或者不正确等,详见官方文档
40
+ #
41
+ def handle_response(res)
42
+ json = JSON.parse(res.body)
43
+ case res
44
+ when Net::HTTPOK
45
+ json
46
+ else
47
+ error = (HTTP_CODE_TO_ERRORS_MAP[res.code] || RequestError).new(json["errorMessage"])
48
+ error.business_code = json["code"]
49
+ raise error
50
+ end
51
+ end
52
+
53
+ # 执行请求
54
+ # @param path [String] 请求 API 的相对路径
55
+ # @param params [Hash] 请求的参数
56
+ # @return [Hash] JSON 解析后的响应数据
57
+ # @raise [RongCloud::BadRequest] 请求参数有误,缺失或者不正确等,详见官方文档
58
+ def request(path, params = nil)
59
+ uri = get_uri(path)
60
+ req = initialize_request(uri, params)
61
+ use_ssl = uri.scheme == 'https'
62
+ res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: use_ssl) do |http|
63
+ http.request(req)
64
+ end
65
+
66
+ handle_response(res)
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,17 @@
1
+ require 'rong_cloud/request'
2
+ require 'rong_cloud/services/user'
3
+ require 'rong_cloud/services/message'
4
+ require 'rong_cloud/services/wordfilter'
5
+ require 'rong_cloud/services/group'
6
+
7
+ module RongCloud
8
+ # 封装所有接口的 Service 类,所有业务接口通过 Service 的实例完成调用
9
+ #
10
+ class Service
11
+ include RongCloud::Request
12
+ include RongCloud::Services::User
13
+ include RongCloud::Services::Message
14
+ include RongCloud::Services::Wordfilter
15
+ include RongCloud::Services::Group
16
+ end
17
+ end
@@ -0,0 +1,73 @@
1
+ module RongCloud
2
+ module Services
3
+ # 群组服务相关接口 http://www.rongcloud.cn/docs/server.html#群组服务
4
+ module Group
5
+ # 同步用户所属群组
6
+ #
7
+ # @param user_id [String] 用户在融云的 id
8
+ # @param groups [Hash] 用户需要同步的群组信息,以群组 id 为键,以群组名称为值
9
+ #
10
+ def sync_group(user_id, groups)
11
+ params = {userId: user_id}
12
+ groups.each do |id, name|
13
+ params["group[#{id}]"] = name
14
+ end
15
+
16
+ request("/group/sync", params)
17
+ end
18
+
19
+ # 创建群组
20
+ #
21
+ def create_group(user_id, group_id, group_name)
22
+ request("/group/create", userId: user_id, groupId: group_id, groupName: group_name)
23
+ end
24
+
25
+ # 加入群组
26
+ #
27
+ def join_group(user_id, group_id, group_name)
28
+ request("/group/join", userId: user_id, groupId: group_id, groupName: group_name)
29
+ end
30
+
31
+ # 退出群组
32
+ #
33
+ def quit_group(user_id, group_id)
34
+ request("/group/quit", userId: user_id, groupId: group_id)
35
+ end
36
+
37
+ # 解散群组
38
+ #
39
+ def dismiss_group(user_id, group_id)
40
+ request("/group/dismiss", userId: user_id, groupId: group_id)
41
+ end
42
+
43
+ # 刷新群组信息
44
+ def refresh_group(group_id, group_name)
45
+ request("/group/refresh", groupId: group_id, groupName: group_name)
46
+ end
47
+
48
+ # 查询群成员
49
+ #
50
+ def group_members(group_id)
51
+ request("/group/user/query", groupId: group_id)
52
+ end
53
+
54
+ # 添加禁言群成员
55
+ #
56
+ def block_group_member(user_id, group_id, minute)
57
+ request("/group/user/gag/add", userId: user_id, groupId: group_id, minute: minute)
58
+ end
59
+
60
+ # 移除禁言群成员
61
+ #
62
+ def unblock_group_member(user_id, group_id)
63
+ request("/group/user/gag/rollback", userId: user_id, groupId: group_id)
64
+ end
65
+
66
+ # 查询被禁言群成员
67
+ #
68
+ def blocked_group_members(group_id)
69
+ request("/group/user/gag/list", groupId: group_id)
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,45 @@
1
+ module RongCloud
2
+ module Services
3
+ module Message
4
+ # 消息发送渠道,区分私信、系统消息、群组消息、讨论组消息、聊天室消息以及广播消息
5
+ class MessageChannel
6
+ # 各消息渠道各自对应请求路径以及特殊参数名
7
+ #
8
+ CHANNEL_TO_REQUEST_DETAILS_MAP = {
9
+ 'private': { target_param_name: "toUserId", api_path: "/message/private/publish" },
10
+ system: { target_param_name: "toUserId", api_path: "/message/system/publish" },
11
+ group: { target_param_name: 'toGroupId', api_path: "/message/group/publish" },
12
+ discussion: { target_param_name: "toDiscussionId", api_path: "/message/discussion/publish" },
13
+ chatroom: { target_param_name: "toChatroomId", api_path: "/message/chatroom/publish" },
14
+ broadcast: { api_path: "/message/broadcast" }
15
+ }.freeze
16
+ # 支持的消息渠道的列表
17
+ #
18
+ VALID_CHANNEL_NAMES = CHANNEL_TO_REQUEST_DETAILS_MAP.keys.map(&:to_s).freeze
19
+
20
+ # 实例化消息渠道对象
21
+ #
22
+ # @param channel_name [String] 渠道名称
23
+ # @return [RongCloud::Services::Message::MessageChannel] 消息渠道实例
24
+ # @raise [RongCloud::UnsupportedMessageChannelName] 消息渠道不支持
25
+ #
26
+ def initialize(channel_name)
27
+ if VALID_CHANNEL_NAMES.include?(channel_name.to_s)
28
+ @channel_name = channel_name.to_s.to_sym
29
+ else
30
+ raise UnsupportedMessageChannelName,
31
+ "support only channels: #{VALID_CHANNEL_NAMES}"
32
+ end
33
+ end
34
+
35
+ def target_param_name
36
+ CHANNEL_TO_REQUEST_DETAILS_MAP[@channel_name][:target_param_name]
37
+ end
38
+
39
+ def api_path
40
+ CHANNEL_TO_REQUEST_DETAILS_MAP[@channel_name][:api_path]
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,58 @@
1
+ require 'rong_cloud/services/message/message_channel'
2
+
3
+ module RongCloud
4
+ module Services
5
+ # 消息发送相关接口 http://www.rongcloud.cn/docs/server.html#消息发送服务
6
+ module Message
7
+ # 通用的发送消息方法
8
+ # @param from_user_id [String] 消息发起人 id
9
+ # @param target_id [String, Integer] 消息接收方,用户 id、群组 id、讨论组 id、聊天室 id 等
10
+ # @param channel_name [String] 消息通道,表示单聊、系统、群组、讨论组、聊天室或者广播消息
11
+ # @param object_name [String] 消息类型名称,内置消息类型或者自定义消息类型名称
12
+ # @param [Hash] content 消息体,更多消息请看 http://www.rongcloud.cn/docs/server.html#内置消息类型表
13
+ # @option content [Object] :content 消息体中的正文,如果为自定义消息,由消息消费方自行解析
14
+ # @option content [Object] :extra 消息体中的附加信息,传递时为字符串,由消息消费方自行解析
15
+ #
16
+ # @param [Hash] options 额外选项,包含 pushContent 以及 pushData 等配置,所有支持选项根据各消息类型确定
17
+ # @option options [String] :pushContent 推送通知显示的 Push 内容
18
+ # @option options [Hash] :pushData 推送 payload
19
+ #
20
+ def send_message(from_user_id, target_id, channel_name, object_name, content, options = {})
21
+ message_channel = MessageChannel.new(channel_name)
22
+ params = { fromUserId: from_user_id, objectName: object_name, content: content.to_json }
23
+ if message_channel.target_param_name
24
+ params.merge!(message_channel.target_param_name => target_id)
25
+ end
26
+
27
+ params.merge!(options)
28
+ request(message_channel.api_path, params)
29
+ end
30
+
31
+ # 发送单聊消息 http://www.rongcloud.cn/docs/server.html#发送单聊消息_方法
32
+ #
33
+ def send_private_message(from_user_id, to_user_id, object_name, content, options = {})
34
+ send_message(from_user_id, to_user_id, :private, object_name, content, options)
35
+ end
36
+
37
+ # 发送系统消息 http://www.rongcloud.cn/docs/server.html#发送系统消息_方法
38
+ def send_system_message(from_user_id, to_user_id, object_name, content, options = {})
39
+ send_message(from_user_id, to_user_id, :system, object_name, content, options)
40
+ end
41
+
42
+ # 发送群组消息 http://www.rongcloud.cn/docs/server.html#发送群组消息_方法
43
+ def send_group_message(from_user_id, to_group_id, object_name, content, options = {})
44
+ send_message(from_user_id, to_group_id, :group, object_name, content, options)
45
+ end
46
+
47
+ # 发送讨论组消息 http://www.rongcloud.cn/docs/server.html#发送讨论组消息_方法
48
+ def send_discussion_message(from_user_id, to_discussion_id, object_name, content, options = {})
49
+ send_message(from_user_id, to_discussion_id, :discussion, object_name, content, options)
50
+ end
51
+
52
+ # 发送广播消息 http://www.rongcloud.cn/docs/server.html#发送广播消息_方法
53
+ def send_broadcast_message(from_user_id, object_name, content, options = {})
54
+ send_message(from_user_id, nil, :broadcast, object_name, content, options)
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,70 @@
1
+ module RongCloud
2
+ module Services
3
+ # 用户相关接口 http://www.rongcloud.cn/docs/server.html#用户服务
4
+ module User
5
+ # 获取 Token,即创建融云用户
6
+ #
7
+ # @param user_id [String] 用户 Id,最大长度 64 字节。是用户在 App 中的唯一标识码,必须保证在同一个 App 内不重复,重复的用户 Id 将被当作是同一用户
8
+ # @param name [String] 用户名称,最大长度 128 字节。用来在 Push 推送时显示用户的名称。
9
+ # @param portrait_uri [String] 用户头像 URI,最大长度 1024 字节。用来在 Push 推送时显示用户的头像。
10
+ # @return [Hash] 请求响应结果数据
11
+ #
12
+ def get_token(user_id, name, portrait_uri)
13
+ request("/user/getToken", {userId: user_id, name: name, portraitUri: portrait_uri})
14
+ end
15
+
16
+ # 刷新用户信息
17
+ #
18
+ def refresh_user(user_id, name = nil, portrait_uri = nil)
19
+ params = { userId: user_id, name: name, portraitUri: portrait_uri }
20
+ params.reject!{|key, value| value.nil?}
21
+
22
+ request("/user/refresh", params)
23
+ end
24
+
25
+ # 检查用户在线状态
26
+ #
27
+ def check_online(user_id)
28
+ request("/user/checkOnline", { userId: user_id })
29
+ end
30
+
31
+ # 封禁用户
32
+ # @param user_id [String] 用户在融云的用户 id
33
+ # @param minute [Integer] 封禁时长
34
+ #
35
+ def block_user(user_id, minute)
36
+ request("/user/block", { userId: user_id, minute: minute })
37
+ end
38
+
39
+ # 解除用户封禁
40
+ #
41
+ def unblock_user(user_id)
42
+ request("/user/unblock", userId: user_id)
43
+ end
44
+
45
+ # 查询被封禁用户列表
46
+ #
47
+ def blocked_users
48
+ request("/user/block/query")
49
+ end
50
+
51
+ # 添加用户到黑名单
52
+ #
53
+ def blacklist_add(user_id, black_user_id)
54
+ request("/user/blacklist/add", userId: user_id, blackUserId: black_user_id)
55
+ end
56
+
57
+ # 从黑名单中移除用户
58
+ #
59
+ def blacklist_remove(user_id, black_user_id)
60
+ request("/user/blacklist/remove", userId: user_id, blackUserId: black_user_id)
61
+ end
62
+
63
+ # 获取某用户的黑名单列表
64
+ #
65
+ def blacklisted_users(user_id)
66
+ request("/user/blacklist/query", userId: user_id)
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,26 @@
1
+ module RongCloud
2
+ module Services
3
+ # 敏感词相关接口 http://www.rongcloud.cn/docs/server.html#敏感词服务
4
+ module Wordfilter
5
+ # 添加敏感词
6
+ #
7
+ # @param word [String] 敏感词
8
+ #
9
+ def add_wordfilter(word)
10
+ request("/wordfilter/add", { word: word })
11
+ end
12
+
13
+ # 移除敏感词
14
+ #
15
+ def delete_wordfilter(word)
16
+ request("/wordfilter/delete", { word: word })
17
+ end
18
+
19
+ # 查询已有敏感词的列表
20
+ #
21
+ def wordfilter_list
22
+ request("/wordfilter/list")
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,39 @@
1
+ require 'digest/sha1'
2
+
3
+ module RongCloud
4
+ # 签名算法相关模块
5
+ # http://www.rongcloud.cn/docs/server.html#通用_API_接口签名规则
6
+ #
7
+ module Signature
8
+ # 生成签名串
9
+ #
10
+ # @param nonce [String] 参与签名的随机字串,无长度限制
11
+ # @param timestamp [String] 时间戳,从 1970 年 1 月 1 日 0 点 0 分 0 秒开始到现在的秒数
12
+ # @return [String] 签名完成之后的结果字串
13
+ #
14
+ def signature(nonce, timestamp)
15
+ str = "#{RongCloud::Configuration.app_secret}#{nonce}#{timestamp}"
16
+ Digest::SHA1.hexdigest(str)
17
+ end
18
+
19
+ # API 调用签名所需的请求头,包含签名等
20
+ # @note 包含以下请求头:
21
+ # App-Key
22
+ # Nonce
23
+ # Timestamp
24
+ # Signature
25
+ # @return [Hash] 签名所需请求头
26
+ def signed_headers
27
+ nonce = rand(10**6)
28
+ timestamp = Time.now.to_i
29
+ signature = signature(nonce, timestamp)
30
+
31
+ {
32
+ 'App-Key' => RongCloud::Configuration.app_key,
33
+ 'Nonce' => nonce,
34
+ 'Timestamp' => timestamp,
35
+ 'Signature' => signature
36
+ }
37
+ end
38
+ end
39
+ end
data/lib/rong_cloud.rb ADDED
@@ -0,0 +1,12 @@
1
+ require 'rong_cloud/configuration'
2
+ require 'rong_cloud/errors'
3
+ require 'rong_cloud/service'
4
+
5
+ # 融云 Ruby SDK 的全局命名空间
6
+ module RongCloud
7
+ # 配置融云 Server 连接信息
8
+ #
9
+ def self.configure(&block)
10
+ yield RongCloud::Configuration
11
+ end
12
+ end
@@ -0,0 +1,13 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = 'rong_cloud_server'
3
+ s.platform = Gem::Platform::RUBY
4
+ s.require_path = 'lib'
5
+ s.summary = '融云 Server API SDK'
6
+ s.description = '融云服务器端接口 API,http://www.rongcloud.cn/docs/server.html'
7
+ s.version = '0.0.1'
8
+ s.files = `git ls-files`.split("\n")
9
+ s.authors = ['Martin Hong']
10
+ s.email = 'hongzeqin@gmail.com'
11
+ s.homepage = 'http://blog.hackerpie.com/rong_cloud/'
12
+ s.license = 'MIT'
13
+ end
data/run_tests.sh ADDED
@@ -0,0 +1 @@
1
+ echo "Dir.glob('./test/**/*_test.rb').each { |file| require file}" | ruby -Itest -Ilib
@@ -0,0 +1,33 @@
1
+ require 'test_helper'
2
+
3
+ module RongCloud
4
+ class ConfigurationTest < Minitest::Test
5
+ def setup
6
+ RongCloud.configure do |config|
7
+ config.host = nil
8
+ end
9
+ end
10
+
11
+ def test_app_key_settings_and_reading
12
+ RongCloud::Configuration.app_key = "test_key"
13
+ assert_equal "test_key", RongCloud::Configuration.app_key
14
+ end
15
+
16
+ def test_app_secret_settings_and_reading
17
+ RongCloud::Configuration.app_secret = "test_secret"
18
+ assert_equal "test_secret", RongCloud::Configuration.app_secret
19
+ end
20
+
21
+ def test_logger_setting_and_reading
22
+ logger = ::Logger.new("rong_cloud.log")
23
+ RongCloud::Configuration.logger = logger
24
+ assert_equal logger, RongCloud::Configuration.logger
25
+ end
26
+
27
+ def test_default_host_and_setting_and_reading
28
+ assert_equal "https://api.cn.ronghub.com", RongCloud::Configuration.host
29
+ RongCloud::Configuration.host = "http://other.host.com"
30
+ assert_equal "http://other.host.com", RongCloud::Configuration.host
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,56 @@
1
+ require 'test_helper'
2
+
3
+ module RongCloud
4
+ class RequestTest < Minitest::Test
5
+ include RongCloud::Request
6
+
7
+ def setup
8
+ rong_cloud_configure_with_settings
9
+ end
10
+
11
+ def test_get_uri_path_end_with_json_format
12
+ uri = get_uri("users.json")
13
+ assert_equal "/users.json", uri.path
14
+ assert_equal "api.cn.ronghub.com", uri.host
15
+ end
16
+
17
+ def test_get_uri_path_not_end_with_json_format
18
+ uri = get_uri("users")
19
+ assert_equal "/users.json", uri.path
20
+ assert_equal "api.cn.ronghub.com", uri.host
21
+ end
22
+
23
+ def test_request_with_invalid_app_key
24
+ RongCloud::Configuration.app_key = "xxx"
25
+ error = assert_raises RongCloud::BadRequest do
26
+ request("/user/getToken", {userId: 'user', name: "User"})
27
+ end
28
+ assert_equal "invalid App-Key.", error.message
29
+ assert_equal 1002, error.business_code
30
+ end
31
+
32
+ def test_request_with_invalid_app_secret
33
+ RongCloud::Configuration.app_secret = "xxx"
34
+ error = assert_raises RongCloud::AuthenticationFailed do
35
+ request("/user/getToken", {userId: 'user', name: "User"})
36
+ end
37
+ assert_equal "签名错误,请检查。", error.message
38
+ assert_equal 1004, error.business_code
39
+ end
40
+
41
+ def test_request_with_missing_required_field
42
+ error = assert_raises RongCloud::BadRequest do
43
+ request("/user/getToken")
44
+ end
45
+ assert_equal "userId is required.", error.message
46
+ assert_equal 1002, error.business_code
47
+ end
48
+
49
+ def test_request_with_valid_params
50
+ response = request("/user/getToken", { userId: 'user', name: "User", portraitUri: "uri" })
51
+ assert_equal 200, response["code"]
52
+ assert_equal "user", response["userId"]
53
+ assert response["token"]
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,19 @@
1
+ require 'test_helper'
2
+ require 'rong_cloud/services/user_test'
3
+ require 'rong_cloud/services/message_test'
4
+ require 'rong_cloud/services/wordfilter_test'
5
+ require 'rong_cloud/services/group_test'
6
+
7
+ module RongCloud
8
+ class ServiceTest < Minitest::Test
9
+ include RongCloud::Services::UserTest
10
+ include RongCloud::Services::MessageTest
11
+ include RongCloud::Services::WordfilterTest
12
+ include RongCloud::Services::GroupTest
13
+
14
+ def setup
15
+ rong_cloud_configure_with_settings
16
+ @service = RongCloud::Service.new
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,102 @@
1
+ module RongCloud
2
+ module Services
3
+ module GroupTest
4
+ def test_sync_group
5
+ response = @service.sync_group('user1', '1' => 'group1', '2' => 'group2')
6
+ assert_equal 200, response['code']
7
+ end
8
+
9
+ def test_create_group_with_single_user_id
10
+ response = @service.create_group('user1', '3', 'group3')
11
+ assert_equal 200, response['code']
12
+ end
13
+
14
+ def test_create_group_with_multiple_user_id
15
+ response = @service.create_group(%w(user1 user2 user3), '4', 'group4')
16
+ assert_equal 200, response['code']
17
+ end
18
+
19
+ def test_create_group_without_group_id
20
+ error = assert_raises RongCloud::BadRequest do
21
+ @service.create_group('user1', nil, 'group3')
22
+ end
23
+ assert_equal 'groupId is required.', error.message
24
+ end
25
+
26
+ def test_create_group_without_group_name
27
+ response = @service.create_group('user1', '5', nil)
28
+ assert_equal 200, response['code']
29
+ end
30
+
31
+ def test_join_group_with_single_user_id
32
+ response = @service.join_group('user1', '3', 'group3')
33
+ assert_equal 200, response['code']
34
+ end
35
+
36
+ def test_join_group_with_multiple_user_id
37
+ response = @service.join_group(%w(user1 user2 user3), '4', 'group4')
38
+ assert_equal 200, response['code']
39
+ end
40
+
41
+ def test_join_group_without_group_id
42
+ error = assert_raises RongCloud::BadRequest do
43
+ @service.join_group('user1', nil, 'group3')
44
+ end
45
+ assert_equal 'groupId is required.', error.message
46
+ end
47
+
48
+ def test_join_group_without_group_name
49
+ response = @service.join_group('user1', '5', nil)
50
+ assert_equal 200, response['code']
51
+ end
52
+
53
+ def test_quit_group
54
+ response = @service.quit_group('user', 'group1')
55
+ assert_equal 200, response['code']
56
+ end
57
+
58
+ def test_dismiss_group
59
+ response = @service.dismiss_group('user', 'group1')
60
+ assert_equal 200, response['code']
61
+ end
62
+
63
+ def test_refresh_group
64
+ response = @service.refresh_group('group1', "测试群组1")
65
+ assert_equal 200, response['code']
66
+ end
67
+
68
+ def test_group_members
69
+ @service.create_group("user1", "group6", "测试群组成员")
70
+ @service.join_group("user2", "group6", "测试群组成员")
71
+ response = @service.group_members("group6")
72
+ user_ids = response['users'].map{|user| user['id'] }
73
+
74
+ assert_equal 2, user_ids.count
75
+ assert_includes user_ids, 'user1'
76
+ assert_includes user_ids, 'user2'
77
+ end
78
+
79
+ def test_block_group_member
80
+ response = @service.block_group_member("user1", "group1", 600)
81
+ assert_equal 200, response['code']
82
+ end
83
+
84
+ def test_unblock_group_member
85
+ response = @service.unblock_group_member("user1", "group1")
86
+ assert_equal 200, response['code']
87
+ end
88
+
89
+ def test_blocked_group_members
90
+ @service.create_group("user1", "group1", "测试群组禁言服务")
91
+ @service.join_group("user2", "group1", "测试群组禁言服务")
92
+ @service.block_group_member("user2", "group1", 60000)
93
+
94
+ response = @service.blocked_group_members('group1')
95
+ user_ids = response['users'].map{|user| user['userId']}
96
+
97
+ assert_equal 1, user_ids.count
98
+ assert_includes user_ids, "user2"
99
+ end
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,82 @@
1
+ require 'rong_cloud/services/message/message_channel'
2
+
3
+ module RongCloud
4
+ module Services
5
+ module Message
6
+ class MessageChannelTest < Minitest::Test
7
+ def test_initialize_with_supported_channel_name
8
+ channel = RongCloud::Services::Message::MessageChannel.new(:private)
9
+ assert channel
10
+ end
11
+
12
+ def test_initialize_with_unsupported_channel_name
13
+ error = assert_raises RongCloud::UnsupportedMessageChannelName do
14
+ RongCloud::Services::Message::MessageChannel.new(:nothing)
15
+ end
16
+ expected_error = "support only channels: [\"private\", \"system\", \"group\", \"discussion\", \"chatroom\", \"broadcast\"]"
17
+ assert_equal expected_error, error.message
18
+ end
19
+
20
+ def test_target_param_name_for_private
21
+ channel = RongCloud::Services::Message::MessageChannel.new(:private)
22
+ assert_equal "toUserId", channel.target_param_name
23
+ end
24
+
25
+ def test_target_param_name_for_system
26
+ channel = RongCloud::Services::Message::MessageChannel.new(:system)
27
+ assert_equal "toUserId", channel.target_param_name
28
+ end
29
+
30
+ def test_target_param_name_for_group
31
+ channel = RongCloud::Services::Message::MessageChannel.new(:group)
32
+ assert_equal "toGroupId", channel.target_param_name
33
+ end
34
+
35
+ def test_target_param_name_for_discussion
36
+ channel = RongCloud::Services::Message::MessageChannel.new(:discussion)
37
+ assert_equal "toDiscussionId", channel.target_param_name
38
+ end
39
+
40
+ def test_target_param_name_for_chatroom
41
+ channel = RongCloud::Services::Message::MessageChannel.new(:chatroom)
42
+ assert_equal "toChatroomId", channel.target_param_name
43
+ end
44
+
45
+ def test_target_param_name_for_broadcast
46
+ channel = RongCloud::Services::Message::MessageChannel.new(:broadcast)
47
+ assert_nil channel.target_param_name
48
+ end
49
+
50
+ def test_api_path_for_private
51
+ channel = RongCloud::Services::Message::MessageChannel.new(:private)
52
+ assert_equal "/message/private/publish", channel.api_path
53
+ end
54
+
55
+ def test_api_path_for_system
56
+ channel = RongCloud::Services::Message::MessageChannel.new(:system)
57
+ assert_equal "/message/system/publish", channel.api_path
58
+ end
59
+
60
+ def test_api_path_for_group
61
+ channel = RongCloud::Services::Message::MessageChannel.new(:group)
62
+ assert_equal "/message/group/publish", channel.api_path
63
+ end
64
+
65
+ def test_api_path_for_discussion
66
+ channel = RongCloud::Services::Message::MessageChannel.new(:discussion)
67
+ assert_equal "/message/discussion/publish", channel.api_path
68
+ end
69
+
70
+ def test_api_path_for_chatroom
71
+ channel = RongCloud::Services::Message::MessageChannel.new(:chatroom)
72
+ assert_equal "/message/chatroom/publish", channel.api_path
73
+ end
74
+
75
+ def test_api_path_for_broadcast
76
+ channel = RongCloud::Services::Message::MessageChannel.new(:broadcast)
77
+ assert_equal "/message/broadcast", channel.api_path
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,83 @@
1
+ module RongCloud
2
+ module Services
3
+ module MessageTest
4
+ def test_send_private_message_with_single_to_user_id
5
+ response = @service.send_private_message(1, 2, "RC:TxtMsg", { content: "hello world", extra: "nothing" })
6
+ assert_equal 200, response["code"]
7
+ end
8
+
9
+ def test_send_private_message_with_multiple_to_user_ids
10
+ response = @service.send_private_message(1, [2, 3, 4], "RC:TxtMsg", { content: "hello world", extra: "nothing" })
11
+ assert_equal 200, response["code"]
12
+ end
13
+
14
+ def test_send_private_message_with_options
15
+ options = { pushContent: "hello", pushData: { shouldBeTrue: "true" } }
16
+ response = @service.send_private_message(1, [2, 3, 4], "RC:TxtMsg", { content: "hello world", extra: "nothing" }, options)
17
+ assert_equal 200, response["code"]
18
+ end
19
+
20
+ def test_send_system_message_with_single_to_user_id
21
+ response = @service.send_system_message(1, 2, "RC:TxtMsg", { content: "hello world", extra: "nothing" })
22
+ assert_equal 200, response["code"]
23
+ end
24
+
25
+ def test_send_system_message_with_multiple_to_user_ids
26
+ response = @service.send_system_message(1, [2, 3, 4], "RC:TxtMsg", { content: "hello world", extra: "nothing" })
27
+ assert_equal 200, response["code"]
28
+ end
29
+
30
+ def test_send_system_message_with_options
31
+ options = { pushContent: "hello", pushData: { shouldBeTrue: "true" } }
32
+ response = @service.send_system_message(1, [2, 3, 4], "RC:TxtMsg", { content: "hello world", extra: "nothing" }, options)
33
+ assert_equal 200, response["code"]
34
+ end
35
+
36
+ def test_send_group_message_with_single_to_group_id
37
+ response = @service.send_group_message(1, 2, "RC:TxtMsg", { content: "hello world", extra: "nothing" })
38
+ assert_equal 200, response["code"]
39
+ end
40
+
41
+ def test_send_group_message_with_multiple_to_group_ids
42
+ response = @service.send_group_message(1, [2, 3, 4], "RC:TxtMsg", { content: "hello world", extra: "nothing" })
43
+ assert_equal 200, response["code"]
44
+ end
45
+
46
+ def test_send_group_message_with_multiple_to_too_many_group_ids
47
+ error = assert_raises RongCloud::BadRequest do
48
+ @service.send_group_message(1, [2, 3, 4, 5], "RC:TxtMsg", { content: "hello world", extra: "nothing" })
49
+ end
50
+
51
+ assert_equal "the number of toUserId should less than 3.", error.message
52
+ assert_equal 1002, error.business_code
53
+ end
54
+
55
+ def test_send_group_message_with_options
56
+ options = { pushContent: "hello", pushData: { shouldBeTrue: "true" } }
57
+ response = @service.send_group_message(1, [2, 3, 4], "RC:TxtMsg", { content: "hello world", extra: "nothing" }, options)
58
+ assert_equal 200, response["code"]
59
+ end
60
+
61
+ def test_send_discussion_message_with_single_to_discussion_id
62
+ response = @service.send_discussion_message(1, 2, "RC:TxtMsg", { content: "hello world", extra: "nothing" })
63
+ assert_equal 200, response["code"]
64
+ end
65
+
66
+ def test_send_discussion_message_with_multiple_to_discussion_ids
67
+ response = @service.send_discussion_message(1, [2, 3, 4], "RC:TxtMsg", { content: "hello world", extra: "nothing" })
68
+ assert_equal 200, response["code"]
69
+ end
70
+
71
+ def test_send_discussion_message_with_options
72
+ options = { pushContent: "hello", pushData: { shouldBeTrue: "true" } }
73
+ response = @service.send_discussion_message(1, [2, 3, 4], "RC:TxtMsg", { content: "hello world", extra: "nothing" }, options)
74
+ assert_equal 200, response["code"]
75
+ end
76
+
77
+ def test_send_broadcast_message
78
+ response = @service.send_broadcast_message(1, "RC:TxtMsg", { content: "hello world", extra: "nothing" })
79
+ assert_equal 200, response["code"]
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,144 @@
1
+ module RongCloud
2
+ module Services
3
+ module UserTest
4
+ def test_get_token_without_user_id
5
+ error = assert_raises RongCloud::BadRequest do
6
+ @service.get_token(nil, nil, nil)
7
+ end
8
+ assert_equal 1002, error.business_code
9
+ assert_equal "userId is required.", error.message
10
+ end
11
+
12
+ def test_get_token_without_name
13
+ response = @service.get_token("user", nil, nil)
14
+ assert response["token"]
15
+ end
16
+
17
+ def test_get_token_without_portrait_url
18
+ response = @service.get_token("user", "User", nil)
19
+ assert response["token"]
20
+ end
21
+
22
+ def test_get_token_with_all_params
23
+ response = @service.get_token("user", "User", "fake_url")
24
+ assert response["token"]
25
+ end
26
+
27
+ def test_get_token_with_chinese_name
28
+ response = @service.get_token("user", "王二狗", "fake_url")
29
+ assert response["token"]
30
+ end
31
+
32
+ def test_refresh_user_without_user_id
33
+ error = assert_raises RongCloud::BadRequest do
34
+ @service.refresh_user(nil, nil, nil)
35
+ end
36
+ assert_equal 1002, error.business_code
37
+ assert_equal "userId is required.", error.message
38
+ end
39
+
40
+ def test_refresh_user_with_unexisted_user_id
41
+ error = assert_raises RongCloud::BadRequest do
42
+ @service.refresh_user("unexistedUserId", nil, nil)
43
+ end
44
+ assert_equal "userIdunexistedUserId is not exist.", error.message
45
+ assert_equal 1002, error.business_code
46
+ end
47
+
48
+ def test_refresh_user_without_portrait_url
49
+ response = @service.refresh_user("user", "User", nil)
50
+ assert_equal 200, response["code"]
51
+ end
52
+
53
+ def test_refresh_user_with_all_params
54
+ response = @service.refresh_user("user", "User", "fake_url")
55
+ assert_equal 200, response["code"]
56
+ end
57
+
58
+ def test_refresh_user_with_chinese_name
59
+ response = @service.refresh_user("user", "小李子", nil)
60
+ assert_equal 200, response["code"]
61
+ end
62
+
63
+ def test_check_online_without_user_id
64
+ error = assert_raises RongCloud::BadRequest do
65
+ @service.check_online(nil)
66
+ end
67
+ assert_equal "userId is required.", error.message
68
+ assert_equal 1002, error.business_code
69
+ end
70
+
71
+ def test_check_online_with_unexisted_user_id
72
+ response = @service.check_online("unexistedUserId")
73
+ assert_equal "0", response["status"]
74
+ end
75
+
76
+ def test_check_online_with_existed_user_id
77
+ response = @service.check_online("user")
78
+ assert_equal "0", response["status"]
79
+ end
80
+
81
+ def test_block_user_without_user_id
82
+ error = assert_raises RongCloud::BadRequest do
83
+ @service.block_user(nil, nil)
84
+ end
85
+ assert_equal "userId is required.", error.message
86
+ assert_equal 1002, error.business_code
87
+ end
88
+
89
+ def test_block_user_without_minute
90
+ @service.get_token("blocked_user", "Blocked", "fake_url")
91
+ error = assert_raises RongCloud::BadRequest do
92
+ @service.block_user("blocked_user", nil)
93
+ end
94
+
95
+ assert_equal "minute is required.", error.message
96
+ assert_equal 1002, error.business_code
97
+ end
98
+
99
+ def test_block_user_without_unexisted_user_id
100
+ response = @service.block_user("unexistedUserId", 3)
101
+ assert_equal 200, response["code"]
102
+ end
103
+
104
+ def test_block_user_and_blocked_users_and_unblock_user
105
+ @service.get_token("blocked_user2", "Blocked", "fake_url")
106
+ response = @service.block_user("blocked_user2", 10)
107
+ assert_equal 200, response["code"]
108
+
109
+ users = @service.blocked_users["users"]
110
+ user = users.detect{|object| object["userId"] == "blocked_user2"}
111
+ assert user["blockEndTime"]
112
+
113
+ response = @service.unblock_user("blocked_user2")
114
+ assert 200, response["code"]
115
+ end
116
+
117
+ def test_blacklist_add_for_unexisted_user_id
118
+ response = @service.blacklist_add("unexisted", "blacklisted_user")
119
+ assert_equal 200, response["code"]
120
+ end
121
+
122
+ def test_blacklist_add_for_existed_user_with_multiple_black_user_id
123
+ response = @service.blacklist_add("user", %w(blu blu2 blu3))
124
+ assert_equal 200, response["code"]
125
+ end
126
+
127
+ def test_blacklist_remove_for_unexisted_user_id
128
+ response = @service.blacklist_remove("unexisted_user", "blacklisted_user")
129
+ assert_equal 200, response["code"]
130
+ end
131
+
132
+ def test_blacklist_remove_for_unblacklisted_user_id
133
+ response = @service.blacklist_remove("user", "unexisted_user")
134
+ assert_equal 200, response["code"]
135
+ end
136
+
137
+ def test_blacklisted_users
138
+ @service.blacklist_add("user", %w(user2 user3))
139
+ response = @service.blacklisted_users("user")
140
+ assert %w(user2 user3) & response["users"] == %w(user2 user3)
141
+ end
142
+ end
143
+ end
144
+ end
@@ -0,0 +1,30 @@
1
+ module RongCloud
2
+ module Services
3
+ module WordfilterTest
4
+ def test_add_wordfilter_with_single_word
5
+ response = @service.add_wordfilter("敏感词")
6
+ assert_equal 200, response["code"]
7
+ end
8
+
9
+ def test_delete_exist_wordfilter
10
+ @service.add_wordfilter("hello")
11
+ response = @service.delete_wordfilter("hello")
12
+ assert_equal 200, response["code"]
13
+ end
14
+
15
+ def test_delete_unexist_wordfilter
16
+ response = @service.delete_wordfilter("unexistedWord")
17
+ assert_equal 500, response["code"] # TODO: 500 非期待,后边修复
18
+ end
19
+
20
+ def test_wordfilter_list
21
+ @service.add_wordfilter("乱")
22
+ response = @service.wordfilter_list
23
+ words = response["words"].map{|word| word["word"]}
24
+ assert_includes words, "乱"
25
+
26
+ @service.delete_wordfilter("乱")
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,39 @@
1
+ require 'test_helper'
2
+
3
+ module RongCloud
4
+ class SignatureTest < Minitest::Test
5
+ include RongCloud::Signature
6
+
7
+ def setup
8
+ RongCloud.configure do |config|
9
+ config.app_key = "uwd1c0sxdlx2"
10
+ config.app_secret = "Y1W2MeFwwwRxa0"
11
+
12
+ @nonce = 14314
13
+ @timestamp = 1408706337
14
+ @expected_sign = "e107e3819638b81a00383951d1d871197910ffe6"
15
+ end
16
+ end
17
+
18
+ def test_signature
19
+ signature = signature(@nonce, @timestamp)
20
+ assert_equal @expected_sign, signature
21
+ end
22
+
23
+ def test_signed_headers
24
+ Time.stub :now, Time.at(@timestamp) do
25
+ def rand(args)
26
+ @nonce
27
+ end
28
+
29
+ expected_headers = {
30
+ 'App-Key' => RongCloud::Configuration.app_key,
31
+ 'Nonce' => @nonce,
32
+ 'Timestamp' => @timestamp,
33
+ 'Signature' => @expected_sign
34
+ }
35
+ assert_equal expected_headers, signed_headers
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,15 @@
1
+ require 'test_helper'
2
+
3
+ class RondCloudTest < Minitest::Test
4
+ def test_configure
5
+ RongCloud.configure do |app|
6
+ app.app_key = "KEY"
7
+ app.app_secret = "SECRET"
8
+ app.host = "HOST"
9
+ end
10
+
11
+ assert_equal "KEY", RongCloud::Configuration.app_key
12
+ assert_equal "SECRET", RongCloud::Configuration.app_secret
13
+ assert_equal "HOST", RongCloud::Configuration.host
14
+ end
15
+ end
@@ -0,0 +1,14 @@
1
+ require 'minitest/autorun'
2
+ require 'byebug'
3
+ require 'rong_cloud'
4
+ require 'yaml'
5
+
6
+ $settings = YAML.load_file("./config.yml")
7
+
8
+ def rong_cloud_configure_with_settings
9
+ RongCloud.configure do |config|
10
+ $settings.each do |setting, value|
11
+ config.send("#{setting}=", value)
12
+ end
13
+ end
14
+ end
metadata ADDED
@@ -0,0 +1,70 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rong_cloud_server
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Martin Hong
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-10-09 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: 融云服务器端接口 API,http://www.rongcloud.cn/docs/server.html
14
+ email: hongzeqin@gmail.com
15
+ executables: []
16
+ extensions: []
17
+ extra_rdoc_files: []
18
+ files:
19
+ - ".gitignore"
20
+ - README.md
21
+ - config.example.yml
22
+ - lib/rong_cloud.rb
23
+ - lib/rong_cloud/configuration.rb
24
+ - lib/rong_cloud/errors.rb
25
+ - lib/rong_cloud/request.rb
26
+ - lib/rong_cloud/service.rb
27
+ - lib/rong_cloud/services/group.rb
28
+ - lib/rong_cloud/services/message.rb
29
+ - lib/rong_cloud/services/message/message_channel.rb
30
+ - lib/rong_cloud/services/user.rb
31
+ - lib/rong_cloud/services/wordfilter.rb
32
+ - lib/rong_cloud/signature.rb
33
+ - rong_cloud.gemspec
34
+ - run_tests.sh
35
+ - test/rong_cloud/configuration_test.rb
36
+ - test/rong_cloud/request_test.rb
37
+ - test/rong_cloud/service_test.rb
38
+ - test/rong_cloud/services/group_test.rb
39
+ - test/rong_cloud/services/message/message_channel_test.rb
40
+ - test/rong_cloud/services/message_test.rb
41
+ - test/rong_cloud/services/user_test.rb
42
+ - test/rong_cloud/services/wordfilter_test.rb
43
+ - test/rong_cloud/signature_test.rb
44
+ - test/rong_cloud_test.rb
45
+ - test/test_helper.rb
46
+ homepage: http://blog.hackerpie.com/rong_cloud/
47
+ licenses:
48
+ - MIT
49
+ metadata: {}
50
+ post_install_message:
51
+ rdoc_options: []
52
+ require_paths:
53
+ - lib
54
+ required_ruby_version: !ruby/object:Gem::Requirement
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ version: '0'
59
+ required_rubygems_version: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: '0'
64
+ requirements: []
65
+ rubyforge_project:
66
+ rubygems_version: 2.6.6
67
+ signing_key:
68
+ specification_version: 4
69
+ summary: 融云 Server API SDK
70
+ test_files: []