├── .gitignore ├── .rspec ├── .travis.yml ├── CODE_OF_CONDUCT.md ├── Gemfile ├── Gemfile.lock ├── LICENSE.txt ├── README.md ├── Rakefile ├── bin ├── console └── setup ├── lib ├── xinge.rb └── xinge │ ├── android.rb │ ├── base.rb │ ├── ios.rb │ ├── notification.rb │ └── version.rb ├── spec ├── spec_helper.rb └── xinge_spec.rb └── xinge.gemspec /.gitignore: -------------------------------------------------------------------------------- 1 | .bundle 2 | tmp/ 3 | coverage/ 4 | db/*.sqlite3 5 | tmp/ 6 | log/*.log 7 | log/*.log* 8 | tmp/**/* 9 | .sass-cache/ 10 | public/assets/ 11 | public/uploads/**/* 12 | public/hot_music 13 | public/hot_music/**/* 14 | .redcar 15 | .DS_Store 16 | *.swp 17 | *.swo 18 | .rvmrc 19 | vendor/ruby 20 | doc/wiki_repo 21 | solr/data/ 22 | solr/pids/ 23 | pkg 24 | .gitignore 25 | -------------------------------------------------------------------------------- /.rspec: -------------------------------------------------------------------------------- 1 | --format documentation 2 | --color 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: ruby 2 | rvm: 3 | - 2.1.3 4 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Code of Conduct 2 | 3 | As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities. 4 | 5 | We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, age, or religion. 6 | 7 | Examples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct. 8 | 9 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team. 10 | 11 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers. 12 | 13 | This Code of Conduct is adapted from the [Contributor Covenant](http:contributor-covenant.org), version 1.0.0, available at [http://contributor-covenant.org/version/1/0/0/](http://contributor-covenant.org/version/1/0/0/) 14 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | # Specify your gem's dependencies in xinge.gemspec 4 | gemspec 5 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | PATH 2 | remote: . 3 | specs: 4 | ruby-for-xinge (0.1.4) 5 | 6 | GEM 7 | remote: https://rubygems.org/ 8 | specs: 9 | diff-lcs (1.2.5) 10 | httparty (0.13.3) 11 | json (~> 1.8) 12 | multi_xml (>= 0.5.2) 13 | json (1.8.2) 14 | multi_xml (0.5.5) 15 | rake (10.4.2) 16 | rspec (3.2.0) 17 | rspec-core (~> 3.2.0) 18 | rspec-expectations (~> 3.2.0) 19 | rspec-mocks (~> 3.2.0) 20 | rspec-core (3.2.2) 21 | rspec-support (~> 3.2.0) 22 | rspec-expectations (3.2.0) 23 | diff-lcs (>= 1.2.0, < 2.0) 24 | rspec-support (~> 3.2.0) 25 | rspec-mocks (3.2.1) 26 | diff-lcs (>= 1.2.0, < 2.0) 27 | rspec-support (~> 3.2.0) 28 | rspec-support (3.2.2) 29 | 30 | PLATFORMS 31 | ruby 32 | 33 | DEPENDENCIES 34 | bundler (~> 1.8) 35 | httparty (~> 0.13.3) 36 | rake (~> 10.0) 37 | rspec 38 | ruby-for-xinge! 39 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Robot Jiang 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Ruby for Tencent Xinge 2 | 3 | Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/xinge`. To experiment with that code, run `bin/console` for an interactive prompt. 4 | 5 | TODO: Delete this and the text above, and describe your gem 6 | 7 | ## Installation 8 | 9 | Add this line to your application's Gemfile: 10 | 11 | ```ruby 12 | gem 'ruby-for-xinge' 13 | ``` 14 | 15 | And then execute: 16 | 17 | $ bundle 18 | 19 | Or install it yourself as: 20 | 21 | $ gem install ruby-for-xinge 22 | 23 | ## Usage 24 | 25 | Add below codes to your application.rb or a init file in config/initializers 26 | 27 | require 'xinge' 28 | Xinge.configure do |config| 29 | config[:android_accessId] = Your android access id 30 | config[:android_secretKey] = 'Your secret key xxx' 31 | config[:ios_accessId] = Your ios access id 32 | config[:ios_secretKey] = 'Your secret key xxx' 33 | config[:env] = Rails.env # if you are not in a rails app, you can set it config[:env]='development' or config[:env]='production', it is 'development' default. 34 | end 35 | 36 | 37 | ## Development 38 | 39 | After checking out the repo, run `bin/setup` to install dependencies. Then, run `bin/console` for an interactive prompt that will allow you to experiment. 40 | 41 | To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release` to create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org). 42 | 43 | ## Contributing 44 | 45 | 1. Fork it ( https://github.com/[my-github-username]/xinge/fork ) 46 | 2. Create your feature branch (`git checkout -b my-new-feature`) 47 | 3. Commit your changes (`git commit -am 'Add some feature'`) 48 | 4. Push to the branch (`git push origin my-new-feature`) 49 | 5. Create a new Pull Request 50 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require "bundler/gem_tasks" 2 | 3 | -------------------------------------------------------------------------------- /bin/console: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require "bundler/setup" 4 | require "xinge" 5 | 6 | # You can add fixtures and/or initialization code here to make experimenting 7 | # with your gem easier. You can also use a different console, if you like. 8 | 9 | # (If you use this, don't forget to add pry to your Gemfile!) 10 | # require "pry" 11 | # Pry.start 12 | 13 | require "irb" 14 | IRB.start 15 | -------------------------------------------------------------------------------- /bin/setup: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -euo pipefail 3 | IFS=$'\n\t' 4 | 5 | bundle install 6 | 7 | # Do any other automated setup that you need to do here 8 | -------------------------------------------------------------------------------- /lib/xinge.rb: -------------------------------------------------------------------------------- 1 | require "xinge/version" 2 | require "xinge/base" 3 | require "xinge/ios" 4 | require "xinge/android" 5 | require "xinge/notification" 6 | 7 | module Xinge 8 | 9 | end 10 | -------------------------------------------------------------------------------- /lib/xinge/android.rb: -------------------------------------------------------------------------------- 1 | require 'xinge/base' 2 | module Xinge 3 | class Android < Base 4 | def initialize(accessId = nil, secretKey = nil, options = {}) 5 | super 6 | end 7 | def pushToSingleDevice(token, title, content, params={}, custom_content={}) 8 | self.push_single_device(token, 1, build_simple_message(title, content, custom_content), params) 9 | end 10 | def pushToAllDevice(title, content, params={}, custom_content={}) 11 | self.push_all_device(1, build_simple_message(title, content, custom_content), params) 12 | end 13 | 14 | protected 15 | 16 | def build_simple_message(title, content, custom_content) 17 | { 18 | title: title, content: content, vibrate: 1 19 | }.merge(custom_content).to_json 20 | end 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /lib/xinge/base.rb: -------------------------------------------------------------------------------- 1 | require 'httparty' 2 | require 'digest' 3 | 4 | module Xinge 5 | 6 | @xinge_config = {env: 'development'} 7 | 8 | class << self 9 | def configure 10 | yield @xinge_config if block_given? 11 | end 12 | def config 13 | @xinge_config 14 | end 15 | end 16 | 17 | class Base 18 | include HTTParty 19 | base_uri 'http://openapi.xg.qq.com' 20 | 21 | DEFAULT_OPTIONS = { 22 | api_version: 'v2' 23 | } 24 | HOST = "openapi.xg.qq.com" 25 | HTTP_METHOD = :post 26 | 27 | def initialize(accessId = nil, secretKey = nil, options = {}) 28 | raise 'accessId is invalid' unless accessId.is_a? Integer 29 | raise 'secretKey is invalid' if !secretKey.is_a?(String) or secretKey.strip.size == 0 30 | @accessId = accessId 31 | @secretKey = secretKey.strip 32 | @options = DEFAULT_OPTIONS.merge options 33 | end 34 | 35 | 36 | #push消息(包括通知和透传消息)给单个设备 37 | def push_single_device(device_token, message_type, message, params = {}) 38 | params.merge!({ 39 | device_token: device_token, 40 | message: message, 41 | message_type: message_type 42 | }) 43 | self.send_request('push','single_device',params) 44 | end 45 | 46 | #push消息(包括通知和透传消息)给单个账户或别名 47 | def push_single_account(account, message_type, message, params = {}) 48 | params.merge!({ 49 | account: account, 50 | message_type: message_type, 51 | message: message 52 | }) 53 | self.send_request('push','single_account',params) 54 | end 55 | 56 | #push消息(包括通知和透传消息)给app的所有设备 57 | def push_all_device(message_type, message, params = {}) 58 | params.merge!({ 59 | message_type: message_type, 60 | message: message 61 | }) 62 | self.send_request('push','all_device',params) 63 | end 64 | 65 | #push消息(包括通知和透传消息)给tags指定的设备 66 | def push_tags_device(message_type, message, tags_list, tags_op, params = {}) 67 | params.merge!({ 68 | message_type: message_type, 69 | message: message, 70 | tags_list: tags_list.to_json, 71 | tags_op: tags_op 72 | }) 73 | self.send_request('push','tags_device',params) 74 | end 75 | 76 | #查询群发消息发送状态 77 | def push_get_msg_status(push_ids, params = {}) 78 | params.merge!({ 79 | push_ids: push_ids.to_json 80 | }) 81 | self.send_request('push','get_msg_status',params) 82 | end 83 | 84 | #查询应用覆盖的设备数 85 | def application_get_app_device_num(params = {}) 86 | self.send_request('application','get_app_device_num',params) 87 | end 88 | 89 | #查询应用的Tags 90 | def tags_query_app_tags(params = {}) 91 | self.send_request('tags','query_app_tags',params) 92 | end 93 | 94 | #取消尚未触发的定时群发任务 95 | def push_cancel_timing_task(push_id, params = {}) 96 | params.merge!({ 97 | push_id: push_id 98 | }) 99 | @request.fetch(params) 100 | self.send_request('push','cancel_timing_task',params) 101 | end 102 | 103 | #批量设置标签 104 | def tags_batch_set(tag_token_list, params = {}) 105 | params.merge!({ 106 | tag_token_list: tag_token_list 107 | }) 108 | self.send_request('tags','batch_set',params) 109 | end 110 | 111 | #批量删除标签 112 | def tags_batch_del(tag_token_list, params = {}) 113 | params.merge!({ 114 | tag_token_list: tag_token_list 115 | }) 116 | self.send_request('tags','batch_del',params) 117 | end 118 | 119 | #查询应用某token设置的标签 120 | def tags_query_token_tags(device_token, params = {}) 121 | params.merge!({ 122 | device_token: device_token 123 | }) 124 | self.send_request('tags','query_token_tags',params) 125 | end 126 | 127 | #查询应用某标签关联的设备数量 128 | def tags_query_tag_token_num(tag, params = {}) 129 | params.merge!({ 130 | tag: tag 131 | }) 132 | self.send_request('tags','query_tag_token_num',params) 133 | end 134 | 135 | protected 136 | 137 | def send_request(type,method,params = {}) 138 | params.merge!({access_id: @accessId, 139 | timestamp: Time.now.to_i}) 140 | #sign params 141 | params_string = params.sort.map{ |h| h.join('=') }.join 142 | sign = Digest::MD5.hexdigest("#{HTTP_METHOD.to_s.upcase}#{HOST}#{self.get_request_url(type,method)}#{params_string}#{@secretKey}") 143 | 144 | params.merge!({ sign: sign }) 145 | options = { body: params } 146 | 147 | result = JSON.parse(self.class.send(HTTP_METHOD,self.get_request_url(type,method), options)) 148 | 149 | [result["ret_code"], result["err_msg"]] 150 | end 151 | 152 | def get_request_url(type,method) 153 | "/#{@options[:api_version]}/#{type}/#{method}" 154 | end 155 | 156 | def build_simple_message(title, content) 157 | raise 'let child class to implement it.' 158 | end 159 | 160 | end 161 | 162 | end 163 | 164 | -------------------------------------------------------------------------------- /lib/xinge/ios.rb: -------------------------------------------------------------------------------- 1 | require 'xinge/base' 2 | module Xinge 3 | class Ios < Base 4 | 5 | ENV_MAP = {'production' => 1, 'development' => 2} 6 | 7 | def initialize(accessId = nil, secretKey = nil, options = {}) 8 | super 9 | end 10 | def pushToSingleDevice(token, title, content, params={}, custom_content={}) 11 | self.push_single_device(token, 1, build_simple_message(title, content, custom_content), params.merge({environment: ENV_MAP[Xinge.config[:env]]})) 12 | end 13 | def pushToAllDevice(title, content, params={}, custom_content={}) 14 | self.push_all_device(1, build_simple_message(title, content, custom_content), params.merge({environment: ENV_MAP[Xinge.config[:env]]})) 15 | end 16 | 17 | protected 18 | 19 | def build_simple_message(title, content, custom_content) 20 | { 21 | aps: { 22 | alert: { 23 | title: title, 24 | body: content 25 | }, 26 | sound: 'default', 27 | badge: 1 28 | } 29 | }.merge(custom_content).to_json 30 | end 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /lib/xinge/notification.rb: -------------------------------------------------------------------------------- 1 | require 'singleton' 2 | require 'xinge/base' 3 | require 'xinge/ios' 4 | require 'xinge/android' 5 | 6 | module Xinge 7 | 8 | class Notification 9 | include Singleton 10 | attr_reader :android, :ios 11 | def initialize 12 | @android = Xinge::Android.new(Xinge.config[:android_accessId].to_i, Xinge.config[:android_secretKey]) 13 | @ios = Xinge::Ios.new(Xinge.config[:ios_accessId].to_i, Xinge.config[:ios_secretKey]) 14 | end 15 | #发送简单消息到所有 android , ios 设备 16 | def send_simple_to_all(title, content) 17 | result = [] 18 | [@android, @ios].each do |sender| 19 | result << sender.pushToAllDevice(title,content) 20 | end 21 | result 22 | end 23 | 24 | end 25 | 26 | end 27 | 28 | -------------------------------------------------------------------------------- /lib/xinge/version.rb: -------------------------------------------------------------------------------- 1 | module Xinge 2 | VERSION = "0.1.4" 3 | end 4 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__) 2 | require 'xinge' 3 | 4 | #将测试时用到的 accessid , secretkey 环境变量预先配置到你的 .bashrc 或者 .zshrc 文件当中 5 | #example: export XINGE_ANDROID_ACCESSID=xxxx 6 | Xinge.configure do |config| 7 | config[:android_accessId] = ENV['XINGE_ANDROID_ACCESSID'] 8 | config[:android_secretKey] = ENV['XINGE_ANDROID_SECRETKEY'] 9 | config[:ios_accessId] = ENV['IOS_ACCESSID'] 10 | config[:ios_secretKey] = ENV['IOS_SECRETKEY'] 11 | end 12 | 13 | -------------------------------------------------------------------------------- /spec/xinge_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | #run bundle exec rspec spec 4 | # 5 | describe Xinge do 6 | before(:all) do 7 | #将token环境变量预先配置到你的 .bashrc 或者 .zshrc 文件当中 8 | #如果要设置多个,请用逗号分隔 9 | #example: export XINGE_TEST_TOKENS='xxxx,xxxx' 10 | @target_device_tokens = ENV['XINGE_TEST_TOKENS'].split(',') 11 | 12 | end 13 | it 'has a version number' do 14 | expect(Xinge::VERSION).not_to be nil 15 | end 16 | 17 | it 'can push to a android device' do 18 | #puts Xinge.config 19 | @target_device_tokens.each do |token| 20 | expect(Xinge::Notification.instance.android.pushToSingleDevice(token, 'Xinge_Title', 'Xinge_测试内容')).to eq([0, nil]) 21 | end 22 | end 23 | 24 | #it 'can send message to all ios device' do 25 | #expect(Xinge::Notification.instance.ios.pushToAllDevice('','hello,ios device')).to eq([0,nil]) 26 | #end 27 | #it 'can send message to all ios and android' do 28 | #expect(Xinge::Notification.instance.send_simple_to_all('','all device, 你们好吗?')).to eq([[0,nil],[0,nil]]) 29 | #end 30 | 31 | end 32 | -------------------------------------------------------------------------------- /xinge.gemspec: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | lib = File.expand_path('../lib', __FILE__) 3 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) 4 | require 'xinge/version' 5 | 6 | Gem::Specification.new do |spec| 7 | spec.name = "ruby-for-xinge" 8 | spec.version = Xinge::VERSION 9 | spec.authors = ["Robot Jiang"] 10 | spec.email = ["robot.z.jiang@gmail.com"] 11 | 12 | if spec.respond_to?(:metadata) 13 | spec.metadata['allowed_push_host'] = "https://rubygems.org" 14 | end 15 | 16 | spec.summary = %q{A Ruby portal for Tencent Xinge} 17 | spec.description = %q{腾讯 信鸽 Rest API for Ruby} 18 | spec.homepage = "https://github.com/RobotJiang/ruby-for-xinge" 19 | spec.license = "MIT" 20 | 21 | spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) } 22 | spec.bindir = "exe" 23 | spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) } 24 | spec.require_paths = ["lib"] 25 | 26 | spec.add_development_dependency "httparty", "~> 0.13.3" 27 | spec.add_development_dependency "bundler", "~> 1.8" 28 | spec.add_development_dependency "rake", "~> 10.0" 29 | spec.add_development_dependency "rspec" 30 | end 31 | --------------------------------------------------------------------------------