sinatra-weixin-robot 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.
- data/lib/sinatra-weixin-robot.rb +10 -0
- data/lib/sinatra/weixin-robot.rb +195 -0
- metadata +47 -0
@@ -0,0 +1,195 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'sinatra/base'
|
4
|
+
require 'digest/sha1'
|
5
|
+
|
6
|
+
module Sinatra
|
7
|
+
module WeiXinRobot
|
8
|
+
module RobotHelpers
|
9
|
+
def generate_signature(token=nil)
|
10
|
+
weixin_token = settings.wexin_token || token
|
11
|
+
signature, timestamp, nonce = params[:signature], params[:timestamp], params[:nonce]
|
12
|
+
weixin_sha1 = [token, timestamp.to_s, nonce.to_s].sort!.join
|
13
|
+
Digest::SHA1.hexdigest(weixin_sha1)
|
14
|
+
end
|
15
|
+
|
16
|
+
def message_receiver(msg)
|
17
|
+
Sinatra::WeiXinRobot::Receiver.message(msg)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
module MessageHelpers
|
21
|
+
def text?
|
22
|
+
@msg_type == "text"
|
23
|
+
end
|
24
|
+
|
25
|
+
def music?
|
26
|
+
@msg_type == "music"
|
27
|
+
end
|
28
|
+
|
29
|
+
def news?
|
30
|
+
@msg_type == "news"
|
31
|
+
end
|
32
|
+
|
33
|
+
def image?
|
34
|
+
@msg_type == "image"
|
35
|
+
end
|
36
|
+
def location?
|
37
|
+
@msg_type == "location"
|
38
|
+
end
|
39
|
+
def link?
|
40
|
+
@msg_type == "link"
|
41
|
+
end
|
42
|
+
|
43
|
+
def event?
|
44
|
+
@msg_type == "event"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
class Receiver
|
48
|
+
include MessageHelpers
|
49
|
+
attr_reader :robot, :user,
|
50
|
+
:create_time,
|
51
|
+
:raw_meesage,
|
52
|
+
:content,
|
53
|
+
:pic_url,
|
54
|
+
:title, :description, :url,
|
55
|
+
:location_y, :location_x, :scale, :label,
|
56
|
+
:event, :latitude, :precision, :foobar
|
57
|
+
def initialize(raw_message)
|
58
|
+
if raw_message.instance_of?(StringIO)
|
59
|
+
@raw_message = raw_message.string
|
60
|
+
elsif raw_message.instance_of?(Tempfile)
|
61
|
+
@raw_message = raw_message.read
|
62
|
+
else
|
63
|
+
@raw_message = raw_message.to_str
|
64
|
+
end
|
65
|
+
@robot = @raw_message.scan(/<ToUserName><!\[CDATA\[(.*)\]\]><\/ToUserName>/).flatten.join
|
66
|
+
@user = @raw_message.scan(/<FromUserName><!\[CDATA\[(.*)\]\]><\/FromUserName>/).flatten.join
|
67
|
+
@create_time = @raw_message.scan(/<CreateTime>(\d+)<\/CreateTime>/).flatten.join
|
68
|
+
@msg_type = @raw_message.scan(/<MsgType><!\[CDATA\[(.*)\]\]><\/MsgType>/).flatten.join
|
69
|
+
@msg_id = @raw_message.scan(/<MsgId>(\d+)<\/MsgId>/).flatten.join
|
70
|
+
end
|
71
|
+
def self.message(raw_message)
|
72
|
+
msg = new(raw_message)
|
73
|
+
msg.handler
|
74
|
+
msg
|
75
|
+
end
|
76
|
+
def handler
|
77
|
+
if text?
|
78
|
+
@content = @raw_message.scan(/<Content><!\[CDATA\[(.*)\]\]><\/Content>/).flatten.join
|
79
|
+
elsif image?
|
80
|
+
@pic_url = @raw_message.scan(/<PicUrl><!\[CDATA\[(.*)\]><\/PicUrl>/).flatten.join
|
81
|
+
elsif location?
|
82
|
+
@location_x = @raw_message.scan(/<Location_X>(.*)<\/Location_X>/).flatten.join
|
83
|
+
@location_y = @raw_message.scan(/<Location_Y>(.*)<\/Location_Y>/).flatten.join
|
84
|
+
@scale = @raw_message.scan(/<Scale>(\d+)<\/Scale>/).flatten.join
|
85
|
+
@label = @raw_message.scan(/<Label><!\[CDATA\[(.*)\]\]><\/Label>/).flatten.join
|
86
|
+
elsif link?
|
87
|
+
@title = @raw_message.scan(/<Title><!\[CDATA\[(.*)\]\]><\/Title>/).flatten.join
|
88
|
+
@description = @raw_message.scan(/<Description><!\[CDATA\[(.*)\]\]><\/Description>/).flatten.join
|
89
|
+
@url = @raw_message.scan(/<Url><!\[CDATA\[(.*)\]\]><\/Url>/).flatten.join
|
90
|
+
elsif event?
|
91
|
+
@event = @raw_message.scan(/<Event><!\[CDATA\[(.*)\]\]><\/Event>/).flatten.join
|
92
|
+
@latitude = @raw_message.scan(/<Latitude>(.*)<\/Latitude>/).flatten.join
|
93
|
+
@precision = @raw_message.scan(/<Precision>(.*)<\/Precision>/).flatten.join
|
94
|
+
else
|
95
|
+
raise TypeError
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def sender(params={}, &block)
|
100
|
+
options = {:robot => @robot, :user => @user, :msg_type => "text"}.merge!(params)
|
101
|
+
if block_given?
|
102
|
+
block.call(Reply.new(options))
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end # Receiver
|
106
|
+
class Reply
|
107
|
+
include MessageHelpers
|
108
|
+
attr_accessor :content,
|
109
|
+
:create_time,
|
110
|
+
:msg_type,
|
111
|
+
:func_flag,
|
112
|
+
:music,
|
113
|
+
:articles
|
114
|
+
|
115
|
+
attr_reader :user, :robot
|
116
|
+
def initialize(options={})
|
117
|
+
@user = options.delete(:user)
|
118
|
+
@robot = options.delete(:robot)
|
119
|
+
@create_time = options.delete(:create_time) || Time.now.to_i
|
120
|
+
@msg_type = options.delete(:msg_type)
|
121
|
+
@func_flag = options.delete(:func_flag) || 0
|
122
|
+
@content = options.delete(:content)
|
123
|
+
@articles = options.delete(:articles) || []
|
124
|
+
@music = options.delete(:music)
|
125
|
+
end
|
126
|
+
|
127
|
+
def articles=(hash)
|
128
|
+
@articles.push(hash)
|
129
|
+
end
|
130
|
+
|
131
|
+
def text_message
|
132
|
+
raise RuntimeError, "#{__LINE__} `@content` not defined" if @content.nil?
|
133
|
+
"<Content><![CDATA[#{@content}]]></Content>"
|
134
|
+
end
|
135
|
+
|
136
|
+
def music_message
|
137
|
+
raise RuntimeError, "#{__LINE__} `@music` not defined" if @music.nil?
|
138
|
+
xml = "<Music>"
|
139
|
+
xml += "<Title><![CDATA[#{@music[:title]}]]></Title>"
|
140
|
+
xml += "<Description><![CDATA[#{@music[:description]}]]></Description>"
|
141
|
+
xml += "<MusicUrl><![CDATA[#{@music[:url]}]]></MusicUrl>\n"
|
142
|
+
xml += "<HQMusicUrl><![CDATA[#{@music[:hq_url]}]]></HQMusicUrl>"
|
143
|
+
xml += "</Music>"
|
144
|
+
end
|
145
|
+
|
146
|
+
def news_message
|
147
|
+
raise RuntimeError, "#{__LINE__} `@news` not defined" if @articles.nil?
|
148
|
+
xml = "<ArticleCount>#{@articles.length}</ArticleCount>"
|
149
|
+
xml += "<Articles>"
|
150
|
+
@articles.each do |artcile|
|
151
|
+
xml += "<item>"
|
152
|
+
xml += "<Title><![CDATA[#{artcile[:title]}]]></Title>"
|
153
|
+
xml += "<Description><![CDATA[#{artcile[:description]}]]></Description>"
|
154
|
+
xml += "<PicUrl><![CDATA[#{artcile[:pic_url]}]]></PicUrl>"
|
155
|
+
xml += "<Url><![CDATA[#{artcile[:url]}]]></Url>"
|
156
|
+
xml += "</item>"
|
157
|
+
end
|
158
|
+
xml += "</Articles>"
|
159
|
+
end
|
160
|
+
|
161
|
+
def to_xml
|
162
|
+
xml = "<xml>"
|
163
|
+
xml += "<ToUserName><![CDATA[#{@user}]]></ToUserName>"
|
164
|
+
xml += "<FromUserName><![CDATA[#{@robot}]]></FromUserName>"
|
165
|
+
xml += "<CreateTime>#{@create_time}</CreateTime>"
|
166
|
+
xml += "<MsgType><![CDATA[#{@msg_type}]]></MsgType>"
|
167
|
+
xml += text_message if text?
|
168
|
+
xml += music_message if music?
|
169
|
+
xml += news_message if news?
|
170
|
+
xml += "<FuncFlag>#{@func_flag}</FuncFlag>"
|
171
|
+
xml += "</xml>"
|
172
|
+
end
|
173
|
+
|
174
|
+
def complete!
|
175
|
+
to_xml
|
176
|
+
self
|
177
|
+
end
|
178
|
+
end
|
179
|
+
def self.registered(robot)
|
180
|
+
robot.set :weixin_token, "your-token"
|
181
|
+
robot.set :weixin_uri, "http://wwww.your-weixin-bot-url.com/"
|
182
|
+
robot.set :weixin_path, URI(robot.settings.weixin_uri).path.to_s
|
183
|
+
robot.helpers RobotHelpers
|
184
|
+
robot.before "#{robot.settings.weixin_path}" do
|
185
|
+
if request.request_method == "POST"
|
186
|
+
content_type 'application/xml'
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end # WeiXinRobot
|
191
|
+
register WeiXinRobot
|
192
|
+
end # Sinatra
|
193
|
+
|
194
|
+
|
195
|
+
|
metadata
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: sinatra-weixin-robot
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- KennX
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-03-18 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description: WeiXin Robot for sinatra
|
15
|
+
email:
|
16
|
+
- kennx9@gmail.com
|
17
|
+
executables: []
|
18
|
+
extensions: []
|
19
|
+
extra_rdoc_files: []
|
20
|
+
files:
|
21
|
+
- lib/sinatra/weixin-robot.rb
|
22
|
+
- lib/sinatra-weixin-robot.rb
|
23
|
+
homepage: https://github.com/kennx/weixin_robot
|
24
|
+
licenses: []
|
25
|
+
post_install_message:
|
26
|
+
rdoc_options: []
|
27
|
+
require_paths:
|
28
|
+
- lib
|
29
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
30
|
+
none: false
|
31
|
+
requirements:
|
32
|
+
- - ! '>='
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: 1.9.2
|
35
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
36
|
+
none: false
|
37
|
+
requirements:
|
38
|
+
- - ! '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
requirements: []
|
42
|
+
rubyforge_project:
|
43
|
+
rubygems_version: 1.8.25
|
44
|
+
signing_key:
|
45
|
+
specification_version: 3
|
46
|
+
summary: WeiXin Robot for sinatra
|
47
|
+
test_files: []
|