snarl-snp 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/GUIDE.rdoc.ja +126 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +144 -0
- data/README.rdoc.ja +166 -0
- data/Rakefile +47 -0
- data/VERSION +1 -0
- data/exsample/ping.rb +8 -0
- data/exsample/winamp_nowplaying.rb +227 -0
- data/exsample/yahoo_weather.rb +35 -0
- data/lib/snarl/autotest.rb +112 -0
- data/lib/snarl/snp.rb +11 -0
- data/lib/snarl/snp/action.rb +138 -0
- data/lib/snarl/snp/config.rb +32 -0
- data/lib/snarl/snp/error.rb +76 -0
- data/lib/snarl/snp/request.rb +83 -0
- data/lib/snarl/snp/response.rb +36 -0
- data/lib/snarl/snp/snp.rb +142 -0
- data/snarl-snp.gemspec +78 -0
- data/spec/exsample/data/weather_yahoo_co_jp.html +608 -0
- data/spec/exsample/yahoo_weather_spec.rb +22 -0
- data/spec/snp/action_spec.rb +198 -0
- data/spec/snp/config_spec.rb +53 -0
- data/spec/snp/request_spec.rb +72 -0
- data/spec/snp/response_sprc.rb +96 -0
- data/spec/snp/snp_spec.rb +265 -0
- data/spec/spec_helper.rb +20 -0
- metadata +119 -0
@@ -0,0 +1,138 @@
|
|
1
|
+
class Snarl
|
2
|
+
class SNP
|
3
|
+
module Action
|
4
|
+
|
5
|
+
NOTIFICATION_PARAM_ORDER = [:title, :text, :icon, :timeout, :class, :action, :app]
|
6
|
+
|
7
|
+
# Sends a SNP command "register" to Snarl. For registering +app+ to Snarl setting window.
|
8
|
+
# snp.register('Ruby-Snarl')
|
9
|
+
# +app+ :: an application name. Snarl uses it as an application ID.
|
10
|
+
# Snarl::SNP keeps +app+ for add_class method and notification method.
|
11
|
+
# +app+ default is SNP::DEFAULT_APP, 'Ruby-Snarl'.
|
12
|
+
# Returns SNP::Response object.
|
13
|
+
#
|
14
|
+
# Snarl sends back a casual error when +app+ is already registered.
|
15
|
+
# It is treated as SNP::SNPError::Casual::SNP_ERROR_ALREADY_REGISTERED.
|
16
|
+
def register(app=nil)
|
17
|
+
@app = app
|
18
|
+
cmds = {:action => 'register', :app => app}
|
19
|
+
request(Request.new(cmds))
|
20
|
+
end
|
21
|
+
alias :app= :register
|
22
|
+
|
23
|
+
# Sends a SNP command "add_class" to Snarl. For adding +classid+ class and its +classtitle+ nickname.
|
24
|
+
# snp.add_class('green')
|
25
|
+
# snp.add_class('red', 'failure popup')
|
26
|
+
# +classid+ :: classname ID on the registered application
|
27
|
+
# +classtitle+ :: display alias for +classname+, optional
|
28
|
+
# Returns SNP::Response object.
|
29
|
+
# Before adding a class, you should register the application.
|
30
|
+
#
|
31
|
+
# Snarl sends back a casual error when +classid+ is already added.
|
32
|
+
# It is treated as SNP::SNPError::Casual::SNP_ERROR_CLASS_ALREADY_EXISTS.
|
33
|
+
def add_class(classid, classtitle=nil)
|
34
|
+
# TODO: add_class(app=nil, classid, classtitle=nil)
|
35
|
+
# type=SNP#?version=1.0#?action=add_class#?class=t returns (107) Bad Packet
|
36
|
+
raise "#{self}#register(appname) required before add_class" unless @app
|
37
|
+
cmds = {:action => 'add_class', :app => @app, :class => classid.to_s, :title => classtitle}
|
38
|
+
request(Request.new(cmds))
|
39
|
+
end
|
40
|
+
|
41
|
+
# Sends SNP command "notification" to Snarl. For making a popup message itself.
|
42
|
+
# snp.notification('title', 'text', 'icon.jpg', 10, 'classA') # 10 is timeout Integer
|
43
|
+
# snp.notification(:title => 't', :text => 't', :icon => 'i.jpg', :timeout => 10, :class => 'claA')
|
44
|
+
# +title+ :: title of popup. String.
|
45
|
+
# +text+ :: text body of popup. String. linebreaks should be only "\n". "\r" confuses Snarl.
|
46
|
+
# +icon+ :: icon image path of popup. String/#to_s. path on Snarl machine or http URL. bmp/jpg/png/gif.
|
47
|
+
# +timeout+ :: display seconds of popup. Integer. if nil, DEFAULT_TIMEOUT 10. if 0, popup never closes automatically.
|
48
|
+
# +class+ :: classid of popup. String. It should have been added by "add_class" method when you use.
|
49
|
+
# notification(title, text, icon=nil, timeout=nil, classid=nil) or notification(keyword-hash).
|
50
|
+
# snp.notification('title', 'text', 10)
|
51
|
+
# snp.notification('title', 'text')
|
52
|
+
# snp.notification('text') # title == DEFAULT_APP == 'Ruby-Snarl'
|
53
|
+
def notification(*keyhash)
|
54
|
+
# TODO: priority
|
55
|
+
cmds = normalize_notification_params(keyhash)
|
56
|
+
request(Request.new(cmds))
|
57
|
+
end
|
58
|
+
alias :notify :notification
|
59
|
+
|
60
|
+
# Sends SNP command "unregister" to Snarl. For removing +app+ from Snarl setting window.
|
61
|
+
# snp.unregister('Ruby-Snarl')
|
62
|
+
# After this, Snarl users can not edit the settings for +app+ 's popup.
|
63
|
+
# If you allow users to edit settings, do not send unregister.
|
64
|
+
# Without sending unregister, the applications are always reseted when Snarl restarts.
|
65
|
+
#
|
66
|
+
# Snarl sends back a casual error when +app+ is not registered.
|
67
|
+
# It is treated as SNP::SNPError::Casual::SNP_ERROR_NOT_REGISTERED.
|
68
|
+
def unregister(app=nil)
|
69
|
+
app = app || @app
|
70
|
+
raise "#{self}#unregister requires appname." unless app
|
71
|
+
cmds = {:action => 'unregister', :app => app}
|
72
|
+
request(Request.new(cmds))
|
73
|
+
end
|
74
|
+
|
75
|
+
# Sends SNP command "hello".
|
76
|
+
# irb> Snarl::SNP.new('127.0.0.1').hello
|
77
|
+
# SNP/1.1/0/OK/Snarl R2.21
|
78
|
+
def hello
|
79
|
+
request(Request.new({:action => 'hello'}))
|
80
|
+
end
|
81
|
+
|
82
|
+
# Sends SNP command "version".
|
83
|
+
# irb> Snarl::SNP.new('127.0.0.1').version
|
84
|
+
# SNP/1.1/0/OK/40.15
|
85
|
+
def version
|
86
|
+
request(Request.new({:action => 'version'}))
|
87
|
+
end
|
88
|
+
|
89
|
+
# UTILS -----------------------------
|
90
|
+
|
91
|
+
private
|
92
|
+
|
93
|
+
def paramarray_to_hash(param_array)
|
94
|
+
title, text, icon, timeout, classid, action, app = param_array
|
95
|
+
pattern = {
|
96
|
+
:only_text => (param_array.size == 1),
|
97
|
+
:text_timeout => (param_array.size == 2) && title && text.kind_of?(Integer),
|
98
|
+
:title_text_timeout => (param_array.size == 3) && title && text && icon.kind_of?(Integer)
|
99
|
+
}
|
100
|
+
case
|
101
|
+
when pattern[:only_text] then # notify("msg")
|
102
|
+
{:title => nil, :text => title}
|
103
|
+
when pattern[:text_timeout] then # notify("msg", 10)
|
104
|
+
{:title => nil, :text => title, :timeout => text}
|
105
|
+
when pattern[:title_text_timeout] then # notify("tit", "msg", 10)
|
106
|
+
{:title => title, :text => text, :timeout => icon}
|
107
|
+
else
|
108
|
+
Hash[*NOTIFICATION_PARAM_ORDER.zip(param_array).flatten].delete_if{|k, v| v.nil?}
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
# we support for:
|
113
|
+
# notify( 'text')
|
114
|
+
# notify('title', 'text')
|
115
|
+
# notify( 'text', 10)
|
116
|
+
# notify('title', 'text', 10)
|
117
|
+
def normalize_notification_params(param)
|
118
|
+
res = Hash.new
|
119
|
+
if param[0].kind_of?(Hash) then
|
120
|
+
keyhash = param[0]
|
121
|
+
else
|
122
|
+
keyhash = paramarray_to_hash(param)
|
123
|
+
end
|
124
|
+
NOTIFICATION_PARAM_ORDER.each do |command|
|
125
|
+
keyhash_value = (keyhash[command.to_s] || keyhash[command])
|
126
|
+
res[command] = keyhash_value if keyhash_value
|
127
|
+
end
|
128
|
+
res[:action] = 'notification'
|
129
|
+
res[:app] = @app if (res[:app].nil? && @app) # default notification
|
130
|
+
res[:app] = nil if res[:app] == :anonymous # from snp.show_message
|
131
|
+
res[:title] = (@title || DEFAULT_TITLE) unless res[:title]
|
132
|
+
res[:timeout] = (@timeout || DEFAULT_TIMEOUT) unless res[:timeout]
|
133
|
+
res[:icon] = icon(res[:icon]) if res[:icon]
|
134
|
+
return res
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
|
2
|
+
# when config file exists, require this config
|
3
|
+
class Snarl
|
4
|
+
class SNP
|
5
|
+
class Config
|
6
|
+
|
7
|
+
DEFAULT_HOST = '127.0.0.1'
|
8
|
+
DEFAULT_PORT = 9887
|
9
|
+
@host = nil
|
10
|
+
@port = nil
|
11
|
+
|
12
|
+
def self.host
|
13
|
+
@host || ENV['SNARL_HOST'] || DEFAULT_HOST
|
14
|
+
end
|
15
|
+
def self.host=(v)
|
16
|
+
@host = if v then v.to_s else nil end
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.port
|
20
|
+
@port || ENV['SNARL_PORT'] || DEFAULT_PORT
|
21
|
+
end
|
22
|
+
def self.port=(v)
|
23
|
+
@port = if v then v.to_i else nil end
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.reset
|
27
|
+
self.host = nil
|
28
|
+
self.port = nil
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
class Snarl
|
2
|
+
class SNP
|
3
|
+
module Error
|
4
|
+
class SNPError < StandardError
|
5
|
+
def initialize(response, request=nil) # request is String or Request
|
6
|
+
@response, @request = response, request
|
7
|
+
end
|
8
|
+
attr_accessor :request, :response
|
9
|
+
def code ; @response.code ; end
|
10
|
+
def message ; "(#{code}) #{@response.message}" ; end
|
11
|
+
def ok? ; @response.ok? ; end
|
12
|
+
end
|
13
|
+
|
14
|
+
class Casual < SNPError ; end
|
15
|
+
|
16
|
+
class SNP_OK < Casual ; end
|
17
|
+
# (0) OK
|
18
|
+
|
19
|
+
class SNP_ERROR_NOT_REGISTERED < Casual ; end
|
20
|
+
# (202) The application hasn't been registered.
|
21
|
+
|
22
|
+
class SNP_ERROR_ALREADY_REGISTERED < Casual ; end
|
23
|
+
# (203) The application is already registered.
|
24
|
+
|
25
|
+
class SNP_ERROR_CLASS_ALREADY_EXISTS < Casual ; end
|
26
|
+
# (204) Class is already registered.
|
27
|
+
|
28
|
+
class Fatal < SNPError ; end
|
29
|
+
|
30
|
+
class SNP_ERROR_FAILED < Fatal ; end
|
31
|
+
# (101) An internal error occurred - usually this represents a fault within Snarl itself.
|
32
|
+
|
33
|
+
class SNP_ERROR_UNKNOWN_COMMAND < Fatal ; end
|
34
|
+
# (102) An unknown action was specified.
|
35
|
+
|
36
|
+
class SNP_ERROR_TIMED_OUT < Fatal ; end
|
37
|
+
# (103) The command sending (or subsequent reply) timed out.
|
38
|
+
|
39
|
+
class SNP_ERROR_BAD_PACKET < Fatal ; end
|
40
|
+
# (107) The command packet is wrongly formed.
|
41
|
+
|
42
|
+
class SNP_ERROR_NOT_RUNNING < Fatal ; end
|
43
|
+
# (201) Incoming network notification handling has been disabled by the user.
|
44
|
+
|
45
|
+
class RUBYSNARL_UNKNOWN_RESPONSE < Fatal ; end
|
46
|
+
# (???) Snarl returns unknown return code.
|
47
|
+
|
48
|
+
CODE_TO_OBJ = {
|
49
|
+
'0' => SNP_OK,
|
50
|
+
'101' => SNP_ERROR_FAILED,
|
51
|
+
'102' => SNP_ERROR_UNKNOWN_COMMAND,
|
52
|
+
'103' => SNP_ERROR_TIMED_OUT,
|
53
|
+
'107' => SNP_ERROR_BAD_PACKET,
|
54
|
+
'201' => SNP_ERROR_NOT_RUNNING,
|
55
|
+
'202' => SNP_ERROR_NOT_REGISTERED,
|
56
|
+
'203' => SNP_ERROR_ALREADY_REGISTERED,
|
57
|
+
'204' => SNP_ERROR_CLASS_ALREADY_EXISTS
|
58
|
+
}
|
59
|
+
|
60
|
+
def self.klass(response, request=nil)
|
61
|
+
if klass = Error::CODE_TO_OBJ[response.to_s] then
|
62
|
+
klass
|
63
|
+
elsif response.kind_of?(Error::SNPError)
|
64
|
+
response
|
65
|
+
else
|
66
|
+
Error::RUBYSNARL_UNKNOWN_RESPONSE
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def self.raise(response, request)
|
71
|
+
Error.klass.new(response, request)
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
class Snarl
|
2
|
+
class SNP
|
3
|
+
class Request
|
4
|
+
PROTOCOL_NAME = "SNP"
|
5
|
+
PROTOCOL_VERSION ="1.0"
|
6
|
+
|
7
|
+
SNP_ACTIONS = {
|
8
|
+
'register' => %w(type version action app),
|
9
|
+
'add_class' => %w(type version action app class title),
|
10
|
+
'notification' => %w(type version action app class title text timeout icon priority),
|
11
|
+
'unregister' => %w(type version action app),
|
12
|
+
'hello' => %w(type version action),
|
13
|
+
'version' => %w(type version action),
|
14
|
+
}
|
15
|
+
|
16
|
+
# You have to send non-ascii messages by "Windows" encoding.
|
17
|
+
ENCODING = 'cp932'
|
18
|
+
|
19
|
+
SNP_SEPARATOR = '#?'
|
20
|
+
SNP_TERMINAL_STRING = "\r\n"
|
21
|
+
SNP_HEADER = {'type' => PROTOCOL_NAME, 'version' => PROTOCOL_VERSION}
|
22
|
+
|
23
|
+
# make SNP request string from command hash and is Request object.
|
24
|
+
def initialize(cmd_hash={})
|
25
|
+
@commands = {}.update(cmd_hash)
|
26
|
+
end
|
27
|
+
|
28
|
+
attr_reader :commands
|
29
|
+
|
30
|
+
# Adds command key and value to Request
|
31
|
+
def []=(cmdkey, value) ; @commands[cmdkey] = value ; end # TODO: normalize
|
32
|
+
# Returns command value for command key
|
33
|
+
def [](cmdkey) ; @commands[cmdkey] ; end
|
34
|
+
|
35
|
+
# Returns Request query string with SNP_TERMINAL_STRING "\r\n"
|
36
|
+
def to_str ; query + SNP_TERMINAL_STRING ; end # FIXME: include "\r\n"?
|
37
|
+
alias :to_s :to_str
|
38
|
+
# Returns Request query string. has no SNP_TERMINAL_STRING "\r\n".
|
39
|
+
def inspect ; query ; end
|
40
|
+
def action ; @commands['action'] ; end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def order_command_pair
|
45
|
+
action = @commands['action']
|
46
|
+
@commands.to_a.sort_by{|pair| SNP_ACTIONS[action].index(pair[0])}
|
47
|
+
end
|
48
|
+
|
49
|
+
def query
|
50
|
+
normalize
|
51
|
+
order_command_pair.map{|pair| pair.join('=')}.join(SNP_SEPARATOR)
|
52
|
+
end
|
53
|
+
|
54
|
+
# normalize item pairs
|
55
|
+
# - symbol keys and upcase KEYS are normalized into downcased string keys.
|
56
|
+
# - query should not have any "\r". use "\n"
|
57
|
+
# - when value is nil, delete the item pair.
|
58
|
+
def normalize
|
59
|
+
norm_commands = Hash[*@commands.map{|k, v| [crlf2lf(k).downcase, crlf2lf(v)]}.flatten]
|
60
|
+
action = normalize_action(norm_commands['action'])
|
61
|
+
norm_commands['action'] = action
|
62
|
+
@commands = SNP_HEADER.dup
|
63
|
+
available_commands_in(action).each do |cmd|
|
64
|
+
@commands[cmd] = norm_commands[cmd] if norm_commands[cmd]
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def normalize_action(action_type)
|
69
|
+
action_type.downcase.gsub(/-/){'_'}.sub(/\Aaddclass\Z/){'add_class'}
|
70
|
+
end
|
71
|
+
|
72
|
+
def available_commands_in(action)
|
73
|
+
SNP_ACTIONS[action] || {}
|
74
|
+
end
|
75
|
+
|
76
|
+
def crlf2lf(s)
|
77
|
+
s ? s.to_s.gsub(/\r\n/){"\n"}.gsub(/\r/){"\n"} : s
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
@@ -0,0 +1,36 @@
|
|
1
|
+
class Snarl
|
2
|
+
class SNP
|
3
|
+
class Response
|
4
|
+
ResponseParseRegexp = /\ASNP\/[\d\.]+\/(\d+)\/(.+?)\Z/
|
5
|
+
def initialize(s)
|
6
|
+
if s.respond_to?(:get) then
|
7
|
+
@response = s.get
|
8
|
+
else
|
9
|
+
@response = s
|
10
|
+
end
|
11
|
+
parse_response
|
12
|
+
end
|
13
|
+
|
14
|
+
attr_reader :code, :message, :infomation, :response
|
15
|
+
attr_accessor :request
|
16
|
+
alias :status :code
|
17
|
+
|
18
|
+
def parse_response
|
19
|
+
if ResponseParseRegexp =~ @response.chomp then
|
20
|
+
@code = $1
|
21
|
+
@message, @infomation= $2.split(/\//)
|
22
|
+
else
|
23
|
+
raise Snarl::SNP::Error::RUBYSNARL_UNKNOWN_RESPONSE.new(self, nil)
|
24
|
+
end
|
25
|
+
raise error.new(self, nil) unless ok?
|
26
|
+
end
|
27
|
+
|
28
|
+
def error ; Error.klass(self.code) ; end
|
29
|
+
|
30
|
+
def to_s ; code ; end # puts response #=> "0"
|
31
|
+
def inspect ; @response.chomp ; end # p response #=> "SNP/1.1/0/OK/456"
|
32
|
+
|
33
|
+
def ok? ; code.to_i.zero? ; end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,142 @@
|
|
1
|
+
class Snarl # conpat for ruby-snarl
|
2
|
+
|
3
|
+
class SNP
|
4
|
+
|
5
|
+
include Action
|
6
|
+
|
7
|
+
# default "timeout command" value. popup disappers in 10 seconds.
|
8
|
+
DEFAULT_TIMEOUT = 10
|
9
|
+
|
10
|
+
# default title for "non-title" notification
|
11
|
+
DEFAULT_TITLE = 'Ruby-Snarl'
|
12
|
+
|
13
|
+
# Snarl::SNP.new('127.0.0.1', 9887)
|
14
|
+
def initialize(host=nil, port=nil, verbose=false)
|
15
|
+
@host = host
|
16
|
+
@port = port
|
17
|
+
@verbose = verbose
|
18
|
+
@logger = nil
|
19
|
+
@app = nil
|
20
|
+
@timeout = nil
|
21
|
+
@iconset = {}
|
22
|
+
@title = nil
|
23
|
+
end
|
24
|
+
|
25
|
+
# When you set it true, all unimportant SNP errors raise.
|
26
|
+
# Default is false, Snarl::SNP::Error::Casual are disabled.
|
27
|
+
attr_accessor :verbose
|
28
|
+
|
29
|
+
# a value of SNP command "app".
|
30
|
+
attr_reader :app
|
31
|
+
|
32
|
+
attr_accessor :title
|
33
|
+
|
34
|
+
# a value of SNP command "timeout".
|
35
|
+
attr_accessor :timeout
|
36
|
+
|
37
|
+
# set Logger object. It is used when sending request and getting response.
|
38
|
+
def logger=(logger)
|
39
|
+
@logger = (logger.kind_of?(Class) ? logger.new($stdout) : logger)
|
40
|
+
end
|
41
|
+
|
42
|
+
# send Snarl::SNP::Request/Hash/String and get Snarl::SNP::Response fron Snarl.
|
43
|
+
# When the response "fatal" response, raise errors.
|
44
|
+
# When method +verbose+ returns true, "casual" errors also raises.
|
45
|
+
def request(req)
|
46
|
+
req = Request.new(req) if req.kind_of?(Hash)
|
47
|
+
debug(req)
|
48
|
+
begin
|
49
|
+
action = req.kind_of?(Request) ? req.action : '(string)'
|
50
|
+
res = get_response(req)
|
51
|
+
info("#{action}: #{res.inspect}")
|
52
|
+
rescue Error::Casual => ex
|
53
|
+
info("#{action}: (ignored) #{ex.message}")
|
54
|
+
raise if verbose
|
55
|
+
rescue Error::Fatal => ex
|
56
|
+
info("#{action}: #{ex.message}")
|
57
|
+
raise
|
58
|
+
end
|
59
|
+
return res
|
60
|
+
end
|
61
|
+
|
62
|
+
# SHORTCUT METHODS ----------------
|
63
|
+
|
64
|
+
# add_classes('type1', 'type2', 'type3')
|
65
|
+
# add_classes(['type1', desc1], ['type2', desc2], ['type3', desc3])
|
66
|
+
def add_classes(*classes)
|
67
|
+
classes.each do |classpair|
|
68
|
+
classpair = [classpair, nil] if classpair.kind_of?(String)
|
69
|
+
add_class(*classpair)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# returns icon path if SNP knows. optional.
|
74
|
+
def icon(s)
|
75
|
+
if @iconset.has_key?(s) then @iconset[s] else s end
|
76
|
+
end
|
77
|
+
|
78
|
+
# set icons pair. quite optional.
|
79
|
+
# snp.iconset(:red => 'red.jpg')
|
80
|
+
# snp.notification('title', 'text', :red) #=> sends "icon=red.jpg"
|
81
|
+
# snp.notification('title', 'text', 'blue') #=> sends "icon=blue"
|
82
|
+
def iconset(icons)
|
83
|
+
@iconset = icons
|
84
|
+
end
|
85
|
+
alias :icons :iconset
|
86
|
+
|
87
|
+
def ping
|
88
|
+
notification(DEFAULT_TITLE, 'Ruby Snarl-SNP Ping Message', 3, nil)
|
89
|
+
end
|
90
|
+
|
91
|
+
alias :message :notification
|
92
|
+
|
93
|
+
def snarl_hello
|
94
|
+
hello.infomation
|
95
|
+
end
|
96
|
+
|
97
|
+
def snarl_version
|
98
|
+
version.infomation
|
99
|
+
end
|
100
|
+
|
101
|
+
# Snarl::SNP.open(host, port){|snp| snp.register ... }
|
102
|
+
# "ensure block" is empty. TCPSocket is closed per access.
|
103
|
+
def self.open(host=nil, port=nil, verbose=false, &block)
|
104
|
+
client = new(host, port, verbose)
|
105
|
+
yield(client) # socket always closed in TCPSocket#open{...}
|
106
|
+
client
|
107
|
+
end
|
108
|
+
|
109
|
+
# send message only. app is "anonymous".
|
110
|
+
# Snarl::SNP.show_message(host, 9887, title, text, tomeout, icon)
|
111
|
+
# Snarl::SNP.show_message(host, title, text, tomeout, icon)
|
112
|
+
def self.show_message(host, port, title=nil, text=nil, timeout=nil, icon=nil)
|
113
|
+
# TODO: (host, title, text, 10)
|
114
|
+
if port.kind_of?(String) && icon.nil? then
|
115
|
+
port, title, text, timeout, icon = nil, port, title, text, timeout
|
116
|
+
end
|
117
|
+
new(host, port).notification(:title => title, :text => text, :timeout => timeout, :icon => icon)
|
118
|
+
end
|
119
|
+
|
120
|
+
def self.ping(host=nil, port=nil)
|
121
|
+
new(host, port).ping
|
122
|
+
end
|
123
|
+
# ----------------- SHORTCUT METHODS
|
124
|
+
|
125
|
+
private
|
126
|
+
|
127
|
+
def get_response(req)
|
128
|
+
host = @host || Config.host
|
129
|
+
port = @port || Config.port
|
130
|
+
TCPSocket.open(host, port) do |s|
|
131
|
+
s.write(req)
|
132
|
+
res = Response.new(s.gets)
|
133
|
+
res.request = req
|
134
|
+
res
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
def info(m); @logger.info(m) if @logger; end
|
139
|
+
def debug(m); @logger.debug(m) if @logger; end
|
140
|
+
|
141
|
+
end
|
142
|
+
end
|