Salut 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE.txt +20 -0
- data/README.markdown +84 -0
- data/lib/Salut/Browser.rb +169 -0
- data/lib/Salut/Service.rb +188 -0
- data/lib/Salut.rb +21 -0
- data/spec/Browser_spec.rb +2 -0
- data/spec/Service_spec.rb +307 -0
- data/spec/spec_helper.rb +6 -0
- metadata +146 -0
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2010 Mark Rada
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.markdown
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
Salut
|
2
|
+
=====
|
3
|
+
|
4
|
+
Salut is just a little bit of example code of using Bonjour with MacRuby.
|
5
|
+
|
6
|
+
Of course, this is not a substitute for reading the [Bonjour Overview](http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/NetServices/Introduction.html%23//apple_ref/doc/uid/TP40002445-SW1) and related documentation (not even close).
|
7
|
+
|
8
|
+
Reference Documentation
|
9
|
+
=======================
|
10
|
+
|
11
|
+
Apple's superb documentation of Bonjour and the Bonjour Objective-C interface:
|
12
|
+
|
13
|
+
- [Bonjour Overview](http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/NetServices/Introduction.html%23//apple_ref/doc/uid/TP40002445-SW1)
|
14
|
+
- [NSNetServices Programming Guide](http://developer.apple.com/library/ios/#documentation/Networking/Conceptual/NSNetServiceProgGuide/Introduction.html)
|
15
|
+
- [NSNetService](http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSNetService_Class/Reference/Reference.html)
|
16
|
+
- [NSNetServiceDelegate Protocol](http://developer.apple.com/library/ios/#documentation/cocoa/reference/NSNetServiceDelegate_Protocol/Reference/Reference.html)
|
17
|
+
- [NSNetServiceBrowser](http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSNetServiceBrowser_Class/Reference/Reference.html)
|
18
|
+
- [NSNetServiceBrowserDelegate Protocol](http://developer.apple.com/library/ios/#documentation/cocoa/reference/NSNetServiceBrowserDelegate_Protocol/Reference/Reference.html)
|
19
|
+
|
20
|
+
Example Usage
|
21
|
+
=============
|
22
|
+
|
23
|
+
Advertising a hypothetical service:
|
24
|
+
|
25
|
+
service = Salut::Service.new({
|
26
|
+
service_type:'_http._tcp.',
|
27
|
+
instance_name:`hostname s`.chomp,
|
28
|
+
port:3000
|
29
|
+
})
|
30
|
+
service.start_advertising
|
31
|
+
|
32
|
+
Finding the service using the browser:
|
33
|
+
|
34
|
+
browser = Salut::Browser.new
|
35
|
+
# look at the delegate methods to find out what variables are given to the proc
|
36
|
+
browser.delegates[:'netServiceBrowser:didFindService:moreComing:'] = Proc.new {
|
37
|
+
|sender, service, more|
|
38
|
+
service.resolve # because we want to resolve them all!
|
39
|
+
if more
|
40
|
+
NSLog('Not up to date yet')
|
41
|
+
else
|
42
|
+
NSLog('All caught up')
|
43
|
+
end
|
44
|
+
}
|
45
|
+
browser.find_services '_http._tcp.', in_domain:''
|
46
|
+
|
47
|
+
If you want to stop advertising:
|
48
|
+
|
49
|
+
service.stop_advertising
|
50
|
+
|
51
|
+
You might notice that you aren't seeing the results of the callbacks, this is because
|
52
|
+
they are waiting for the current run loop to cycle. This would happen automatically with
|
53
|
+
a GUI app, but a command line app will have to force the loop to run.
|
54
|
+
|
55
|
+
NSRunLoop.currentRunLoop.run # => runs indefinitely
|
56
|
+
NSRunLoop.currentRunLoop.runUntiDate (Time.now + 5) # => runs for 5 seconds
|
57
|
+
|
58
|
+
You can only use a Service or Browser for one thing at a time, and the API is designed
|
59
|
+
with that assumption in mind.
|
60
|
+
|
61
|
+
TODO
|
62
|
+
====
|
63
|
+
|
64
|
+
- Monitoring and TXT record stuff
|
65
|
+
- publishWithOptions default argument
|
66
|
+
- Do not pass NSNetService or NSNetServiceBrowser to callbacks
|
67
|
+
|
68
|
+
Contributing to Salut
|
69
|
+
=====================
|
70
|
+
|
71
|
+
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
|
72
|
+
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
|
73
|
+
* Fork the project
|
74
|
+
* Start a feature/bugfix branch
|
75
|
+
* Commit and push until you are happy with your contribution
|
76
|
+
* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
|
77
|
+
* Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
|
78
|
+
|
79
|
+
Copyright
|
80
|
+
=========
|
81
|
+
|
82
|
+
Copyright (c) 2010 Mark Rada. See LICENSE.txt for
|
83
|
+
further details.
|
84
|
+
|
@@ -0,0 +1,169 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
module Salut
|
4
|
+
|
5
|
+
# Browsers are used for searching for services or domains. A single instance
|
6
|
+
# should only be used for a single search.
|
7
|
+
#
|
8
|
+
# You should be careful not to reuse the same instance for multiple
|
9
|
+
# searches without calling {#stop_searching}, otherwise you are likely to get
|
10
|
+
# an error logged. The reason for this is that a browser never really
|
11
|
+
# stops searching (unless you call {#stop_searching}), even if moreComing
|
12
|
+
# is false. moreComing is a signal that the browser up to date on the network
|
13
|
+
# state for the moment but any new network state changes will trigger the
|
14
|
+
# callbacks again.
|
15
|
+
class Browser
|
16
|
+
|
17
|
+
# @return [Boolean]
|
18
|
+
attr_reader :searching
|
19
|
+
alias_method :searching?, :searching
|
20
|
+
|
21
|
+
# @return [Array<String>]
|
22
|
+
attr_reader :domains
|
23
|
+
|
24
|
+
# @return [Array<NSNetService>]
|
25
|
+
attr_reader :services
|
26
|
+
|
27
|
+
# Ensure that some instance variables are initialized
|
28
|
+
def initialize
|
29
|
+
@browser = NSNetServiceBrowser.alloc.init
|
30
|
+
@browser.delegate = self
|
31
|
+
@domains = []
|
32
|
+
@services = []
|
33
|
+
@delegates = {}
|
34
|
+
@searching = false
|
35
|
+
end
|
36
|
+
|
37
|
+
# Stop searching for things, whether they be domains or services
|
38
|
+
def stop_finding
|
39
|
+
@browser.stop
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
# @group Adding callback extensions
|
44
|
+
|
45
|
+
# @return [Hash{Symbol=>Proc}]
|
46
|
+
attr_accessor :delegates
|
47
|
+
|
48
|
+
# A shortcut for reading from the delegate methods
|
49
|
+
# @param [Symbol] key
|
50
|
+
# @return [Proc]
|
51
|
+
def [] key
|
52
|
+
@delegates[key]
|
53
|
+
end
|
54
|
+
|
55
|
+
# A shortcut for writing to the delegate methods hash
|
56
|
+
# @param [Symbol] key
|
57
|
+
# @param [Proc] value
|
58
|
+
# @return [Proc]
|
59
|
+
def []= key, value
|
60
|
+
@delegates[key] = value
|
61
|
+
end
|
62
|
+
|
63
|
+
# @endgroup
|
64
|
+
|
65
|
+
|
66
|
+
# @group Finding domains
|
67
|
+
|
68
|
+
# @return [nil]
|
69
|
+
def find_browsable_domains
|
70
|
+
@browser.searchForBrowsableDomains
|
71
|
+
end
|
72
|
+
|
73
|
+
alias_method :stop_finding_domains, :stop_finding
|
74
|
+
|
75
|
+
# @endgroup
|
76
|
+
|
77
|
+
|
78
|
+
# @group Finding services
|
79
|
+
|
80
|
+
# @param [String] service_name
|
81
|
+
# @param [String] domain_name
|
82
|
+
def find_services service_type, in_domain:domain_name
|
83
|
+
@browser.searchForServicesOfType service_type, inDomain:domain_name
|
84
|
+
end
|
85
|
+
|
86
|
+
alias_method :stop_finding_services, :stop_finding
|
87
|
+
|
88
|
+
# @endgroup
|
89
|
+
|
90
|
+
|
91
|
+
# @group Delegate methods
|
92
|
+
|
93
|
+
# @yieldparam [NSNetServiceBrowser] sender
|
94
|
+
# @yieldparam [String] domain_name
|
95
|
+
# @yieldparam [Boolean] more
|
96
|
+
# @return [nil]
|
97
|
+
def netServiceBrowser sender, didFindDomain:domain_name, moreComing:more
|
98
|
+
@domains << domain_name
|
99
|
+
@delegates[__method__].call sender, domain_name, more if @delegates[__method__]
|
100
|
+
Salut.log.info "Found domain: #{domain_name}"
|
101
|
+
end
|
102
|
+
|
103
|
+
# @yieldparam [NSNetServiceBrowser] sender
|
104
|
+
# @yieldparam [String] domain_name
|
105
|
+
# @yieldparam [Boolean] more
|
106
|
+
# @return [nil]
|
107
|
+
def netServiceBrowser sender, didRemoveDomain:domain_name, moreComing:more
|
108
|
+
@domains.delete domain_name
|
109
|
+
@delegates[__method__].call sender, domain_name, more if @delegates[__method__]
|
110
|
+
Salut.log.info "Removing domain: #{domain_name}"
|
111
|
+
end
|
112
|
+
|
113
|
+
# @yieldparam [NSNetServiceBrowser] sender
|
114
|
+
# @yieldparam [Salut::Service] service
|
115
|
+
# @yieldparam [Boolean] more
|
116
|
+
# @return [nil]
|
117
|
+
def netServiceBrowser sender, didFindService:service, moreComing:more
|
118
|
+
salut_service = Service.new({ service:service })
|
119
|
+
@services << salut_service
|
120
|
+
@delegates[__method__].call sender, salut_service, more if @delegates[__method__]
|
121
|
+
Salut.log.info "Found service (#{service.description})"
|
122
|
+
end
|
123
|
+
|
124
|
+
# @yieldparam [NSNetServiceBrowser] sender
|
125
|
+
# @yieldparam [Salut::Service] removed_service
|
126
|
+
# @yieldparam [Boolean] more
|
127
|
+
# @return [nil]
|
128
|
+
def netServiceBrowser sender, didRemoveService:service, moreComing:more
|
129
|
+
removed_service
|
130
|
+
@services.delete_if { |salut_service|
|
131
|
+
if salut_service.service == service
|
132
|
+
removed_service = salut_service
|
133
|
+
true
|
134
|
+
end
|
135
|
+
}
|
136
|
+
@delegates[__method__].call sender, removed_service, more if @delegates[__method__]
|
137
|
+
Salut.log.info "Removing service (#{service.description})"
|
138
|
+
end
|
139
|
+
|
140
|
+
# @yieldparam [NSNetServiceBrowser] sender
|
141
|
+
# @return [nil]
|
142
|
+
def netServiceBrowserWillSearch sender
|
143
|
+
@searching = true
|
144
|
+
@delegates[__method__].call sender if @delegates[__method__]
|
145
|
+
Salut.log.info "Starting search (#{sender.description})"
|
146
|
+
end
|
147
|
+
|
148
|
+
# @yieldparam [NSNetServiceBrowser] sender
|
149
|
+
# @yieldparam [Hash] error_dict
|
150
|
+
# @return [nil]
|
151
|
+
def netServiceBrowser sender, didNotSearch:error_dict
|
152
|
+
@searching = false
|
153
|
+
@delegates[__method__].call sender, error_dict if @delegates[__method__]
|
154
|
+
Salut.log.info "Failed to search (#{sender.description})\n\t problem was\n#{error_dict.description}"
|
155
|
+
end
|
156
|
+
|
157
|
+
# @yieldparam [NSNetServiceBrowser] sender
|
158
|
+
# @return [nil]
|
159
|
+
def netServiceBrowserDidStopSearch sender
|
160
|
+
@searching = false
|
161
|
+
@delegates[__method__].call sender if @delegates[__method__]
|
162
|
+
Salut.log.info "Done searching (#{sender.description})"
|
163
|
+
end
|
164
|
+
|
165
|
+
# @endgroup
|
166
|
+
|
167
|
+
end
|
168
|
+
|
169
|
+
end
|
@@ -0,0 +1,188 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
module Salut
|
4
|
+
|
5
|
+
# Advertises its service on the local network using Bonjour or is
|
6
|
+
# a service that was found using Sault::Browser.
|
7
|
+
#
|
8
|
+
# Note that an instance of the service should be used for one or the
|
9
|
+
# other, but not both. Some methods are meant for when you are using
|
10
|
+
# Service to advertise a service and other methods are meant for when
|
11
|
+
# you are working with services that have been discovered.
|
12
|
+
class Service
|
13
|
+
|
14
|
+
# @return [Boolean]
|
15
|
+
attr_reader :advertising
|
16
|
+
alias_method :advertising?, :advertising
|
17
|
+
|
18
|
+
# @return [NSNetService]
|
19
|
+
attr_reader :service
|
20
|
+
|
21
|
+
# @return [String]
|
22
|
+
attr_accessor :service_type
|
23
|
+
|
24
|
+
# @return [String]
|
25
|
+
attr_accessor :instance_name
|
26
|
+
|
27
|
+
# @return [Fixnum]
|
28
|
+
attr_accessor :port
|
29
|
+
|
30
|
+
# @example Initializing with properties
|
31
|
+
# service = Advertiser.new({
|
32
|
+
# service_type:'_http._tcp.',
|
33
|
+
# instance_name:'Test',
|
34
|
+
# port:3000
|
35
|
+
# })
|
36
|
+
# @example Initializing with an existing service
|
37
|
+
# service = Advertiser.new({
|
38
|
+
# service:NSNetService.alloc.initWithDomain('',
|
39
|
+
# type:'_http._tcp.',
|
40
|
+
# name:`hostname -s`.chomp,
|
41
|
+
# port:3000)
|
42
|
+
# })
|
43
|
+
# @param [Hash{Symbol=>(String,Fixnum,NSNetService)}] params
|
44
|
+
def initialize params = {}
|
45
|
+
@service_type = params[:service_type]
|
46
|
+
@instance_name = params[:instance_name]
|
47
|
+
@port = params[:port]
|
48
|
+
@service = params[:service]
|
49
|
+
@delegates = {}
|
50
|
+
@advertising = false
|
51
|
+
end
|
52
|
+
|
53
|
+
|
54
|
+
# @group Adding callback extensions
|
55
|
+
|
56
|
+
# @return [Hash{Symbol=>Proc}]
|
57
|
+
attr_accessor :delegates
|
58
|
+
|
59
|
+
# A shortcut for reading from the delegate methods
|
60
|
+
# @param [Symbol] key
|
61
|
+
# @return [Proc]
|
62
|
+
def [] key
|
63
|
+
@delegates[key]
|
64
|
+
end
|
65
|
+
|
66
|
+
# A shortcut for writing to the delegate methods hash
|
67
|
+
# @param [Symbol] key
|
68
|
+
# @param [Proc] value
|
69
|
+
# @return [Proc]
|
70
|
+
def []= key, value
|
71
|
+
@delegates[key] = value
|
72
|
+
end
|
73
|
+
|
74
|
+
# @endgroup
|
75
|
+
|
76
|
+
|
77
|
+
# @group Advertising a service
|
78
|
+
|
79
|
+
# Start advertising the service. If you want to change the service
|
80
|
+
# type, instance name, or port, you will have to {#stop_advertising}
|
81
|
+
# first.
|
82
|
+
#
|
83
|
+
# If there is an error creating the underlying NSNetService object
|
84
|
+
# (usually because one of @service_type, @instance_name, and @port
|
85
|
+
# are not specified) then you will get a NilClass NoMethodError when
|
86
|
+
# the method tries to set the delegate.
|
87
|
+
# @param [String] domain defaults to all domains
|
88
|
+
def start_advertising domain = ''
|
89
|
+
@service = NSNetService.alloc.initWithDomain domain,
|
90
|
+
type:@service_type,
|
91
|
+
name:@instance_name,
|
92
|
+
port:@port
|
93
|
+
@service.delegate = self
|
94
|
+
@service.publish
|
95
|
+
end
|
96
|
+
|
97
|
+
# Stop advertising the service, which is a nice thing to do when you
|
98
|
+
# are cleaning up before exiting your code, but the script/program
|
99
|
+
# exiting will also cause the service to stop being published.
|
100
|
+
def stop_advertising
|
101
|
+
@service.stop
|
102
|
+
@service = nil
|
103
|
+
end
|
104
|
+
|
105
|
+
# @endgroup
|
106
|
+
|
107
|
+
|
108
|
+
# @group Working with discovered services
|
109
|
+
|
110
|
+
# A more Ruby-like #resolveWithTimeout by supporting a default argument
|
111
|
+
# @param [Float] timeout number of seconds to wait before timing out
|
112
|
+
def resolve timeout = 60.0
|
113
|
+
@service.resolveWithTimeout timeout
|
114
|
+
end
|
115
|
+
|
116
|
+
# @endgroup
|
117
|
+
|
118
|
+
|
119
|
+
# @group Delegate methods
|
120
|
+
|
121
|
+
# @yieldparam [NSNetService] sender
|
122
|
+
# @return [nil]
|
123
|
+
def netServiceWillPublish sender
|
124
|
+
@delegates[__method__].call sender if @delegates[__method__]
|
125
|
+
Salut.log.info "Starting to advertise service (#{sender.description})"
|
126
|
+
end
|
127
|
+
|
128
|
+
# @yieldparam [NSNetService] sender
|
129
|
+
# @yieldparam [Hash] error_dict
|
130
|
+
# @return [nil]
|
131
|
+
def netService sender, didNotPublish:error_dict
|
132
|
+
@advertising = false
|
133
|
+
@delegates[__method__].call sender, error_dict if @delegates[__method__]
|
134
|
+
Salut.log.info "ERROR: could not advertise service (#{sender.description})\n\t the problem was\n#{error_dict.description}"
|
135
|
+
end
|
136
|
+
|
137
|
+
# @yieldparam [NSNetService] sender
|
138
|
+
# @return [nil]
|
139
|
+
def netServiceDidPublish sender
|
140
|
+
@advertising = true
|
141
|
+
@delegates[__method__].call sender if @delegates[__method__]
|
142
|
+
Salut.log.info "Successfully advertising service (#{sender.description})"
|
143
|
+
end
|
144
|
+
|
145
|
+
# @yieldparam [NSNetService] sender
|
146
|
+
# @return [nil]
|
147
|
+
def netServiceWillResolve sender
|
148
|
+
@delegates[__method__].call sender if @delegates[__method__]
|
149
|
+
Salut.log.info "Resolving service (#{sender.description})"
|
150
|
+
end
|
151
|
+
|
152
|
+
# @yieldparam [NSNetService] sender
|
153
|
+
# @yieldparam [Hash] error_dict
|
154
|
+
# @return [nil]
|
155
|
+
def netService sender, didNotResolve:error_dict
|
156
|
+
@delegates[__method__].call sender if @delegates[__method__]
|
157
|
+
Salut.log.info "ERROR: could not resolve service (#{sender.description})\n\t the problem was\n#{error_dict.description}"
|
158
|
+
end
|
159
|
+
|
160
|
+
# @yieldparam [NSNetService] sender
|
161
|
+
# @return [nil]
|
162
|
+
def netServiceDidResolveAddress sender
|
163
|
+
@delegates[__method__].call sender if @delegates[__method__]
|
164
|
+
Salut.log.info "Resolved address for service (#{sender.description})"
|
165
|
+
end
|
166
|
+
|
167
|
+
# @todo should I process the TXT record before giving it to the proc?
|
168
|
+
# @yieldparam [NSNetService] sender
|
169
|
+
# @yieldparam [NSData] data the new TXT record
|
170
|
+
# @return [nil]
|
171
|
+
def netService sender, didUpdateTXTRecordData:data
|
172
|
+
@delegates[__method__].call sender, data if @delegates[__method__]
|
173
|
+
Salut.log.info "Updated TXT record for service (#{sender.description})"
|
174
|
+
end
|
175
|
+
|
176
|
+
# @yieldparam [NSNetService] sender
|
177
|
+
# @return [nil]
|
178
|
+
def netServiceDidStop sender
|
179
|
+
@advertising = false
|
180
|
+
@delegates[__method__].call sender if @delegates[__method__]
|
181
|
+
Salut.log.info "Stopped advertising service (#{sender.description})"
|
182
|
+
end
|
183
|
+
|
184
|
+
# @endgroup
|
185
|
+
|
186
|
+
end
|
187
|
+
|
188
|
+
end
|
data/lib/Salut.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
framework 'Foundation'
|
3
|
+
require 'logger'
|
4
|
+
|
5
|
+
require 'Salut/Service'
|
6
|
+
require 'Salut/Browser'
|
7
|
+
|
8
|
+
# A class to help with advertising services using Bonjour and finding
|
9
|
+
# other services that are being advertised using Bonjour.
|
10
|
+
module Salut
|
11
|
+
|
12
|
+
class << self
|
13
|
+
|
14
|
+
# @return [Logger]
|
15
|
+
attr_accessor :log
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
@log = Logger.new STDERR
|
20
|
+
|
21
|
+
end
|
@@ -0,0 +1,307 @@
|
|
1
|
+
require './spec_helper'
|
2
|
+
|
3
|
+
describe Salut::Service do
|
4
|
+
before do
|
5
|
+
Salut.log.level = Logger::WARN
|
6
|
+
end
|
7
|
+
|
8
|
+
describe '#advertising?' do
|
9
|
+
before do
|
10
|
+
@service = Salut::Service.new({
|
11
|
+
port:3000,
|
12
|
+
instance_name:'Test',
|
13
|
+
service_type:'_http._tcp.'
|
14
|
+
})
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'should be initialized to false' do
|
18
|
+
@service.advertising?.should.be.equal false
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'should be false when I start advertising (until #netServiceDidPublish is called)' do
|
22
|
+
@service.start_advertising
|
23
|
+
@service.advertising?.should.be.equal false
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'should be false after I stop advertising' do
|
27
|
+
@service.start_advertising
|
28
|
+
NSRunLoop.currentRunLoop.runUntilDate Time.now + 2
|
29
|
+
@service.stop_advertising
|
30
|
+
NSRunLoop.currentRunLoop.runUntilDate Time.now + 2
|
31
|
+
@service.advertising?.should.be.equal false
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'should be false if advertising fails' do
|
35
|
+
@other_service = @service.dup
|
36
|
+
@service.start_advertising
|
37
|
+
NSRunLoop.currentRunLoop.runUntilDate Time.now + 2
|
38
|
+
@other_service.start_advertising
|
39
|
+
NSRunLoop.currentRunLoop.runUntilDate Time.now + 2
|
40
|
+
@other_service.advertising?.should.be.equal false
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'should be true when advertising is successful' do
|
44
|
+
@service.start_advertising
|
45
|
+
NSRunLoop.currentRunLoop.runUntilDate Time.now + 2
|
46
|
+
@service.advertising?.should.be.equal true
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
describe '#service' do
|
52
|
+
it 'is an NSNetService instance' do
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'can be set at initialization' do
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'will be created when advertising starts' do
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'will be set to nil when advertising stops' do
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
|
66
|
+
describe '#initialize' do
|
67
|
+
it 'will let you initialize the port number' do
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'will let you initialize the instance name' do
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'will let you initialize the service type' do
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'will let you initialize with a service' do
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'will initialize delegates to an empty hash' do
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'will initialize @advertising to false' do
|
83
|
+
end
|
84
|
+
|
85
|
+
it 'will let you initialize with nothing being set' do
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
|
90
|
+
describe '#delegates' do
|
91
|
+
it 'should be initialized to an empty hash' do
|
92
|
+
end
|
93
|
+
|
94
|
+
it 'should be writable' do
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
|
99
|
+
describe '#[]' do
|
100
|
+
it 'should be equivalent to #delegates' do
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
|
105
|
+
describe '#[]=' do
|
106
|
+
it 'should be equivalent to #delegates=' do
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
|
111
|
+
describe '#start_advertising' do
|
112
|
+
it 'should create a new @service object' do
|
113
|
+
end
|
114
|
+
|
115
|
+
it 'should set the delegate for @service to self' do
|
116
|
+
end
|
117
|
+
|
118
|
+
# a fragile test since it depends on one of the callbacks
|
119
|
+
# being called
|
120
|
+
it 'should call #publish on @service' do
|
121
|
+
end
|
122
|
+
|
123
|
+
it 'should set domain to an empty string by default' do
|
124
|
+
end
|
125
|
+
|
126
|
+
it 'should allow me to specify a domain' do
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
|
131
|
+
describe '#stop_advertising' do
|
132
|
+
# a fragile test since it depends on one of the callbacks
|
133
|
+
# being called
|
134
|
+
it 'should call #stop on @service' do
|
135
|
+
end
|
136
|
+
|
137
|
+
it 'should set @service to nil' do
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
|
142
|
+
describe '#resolve' do
|
143
|
+
before do
|
144
|
+
# need a browser to find stuff to resolve
|
145
|
+
end
|
146
|
+
|
147
|
+
# a fragile test since it depends on one of the callbacks
|
148
|
+
# being called
|
149
|
+
it 'should cause the resolve callback to be called' do
|
150
|
+
end
|
151
|
+
|
152
|
+
it 'should timeout after 60 seconds' do
|
153
|
+
end
|
154
|
+
|
155
|
+
it 'should allow me to override the timeout' do
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
|
160
|
+
describe 'callback skeletons' do
|
161
|
+
|
162
|
+
before do
|
163
|
+
# set the logger to log INFO and log to a stringIO object
|
164
|
+
end
|
165
|
+
|
166
|
+
|
167
|
+
describe '#netServiceWillPublish' do
|
168
|
+
it 'should call its proc if exists' do
|
169
|
+
end
|
170
|
+
|
171
|
+
it 'should not explode if the proc does not exist' do
|
172
|
+
end
|
173
|
+
|
174
|
+
it 'should log a message at the INFO level' do
|
175
|
+
end
|
176
|
+
|
177
|
+
it 'should pass self to the proc' do
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
|
182
|
+
describe '#netService:didNotPublish:' do
|
183
|
+
it 'should call its proc if exists' do
|
184
|
+
end
|
185
|
+
|
186
|
+
it 'should not explode if the proc does not exist' do
|
187
|
+
end
|
188
|
+
|
189
|
+
it 'should log a message at the INFO level' do
|
190
|
+
end
|
191
|
+
|
192
|
+
it 'should set @advertising to false' do
|
193
|
+
end
|
194
|
+
|
195
|
+
it 'should pass self to the proc' do
|
196
|
+
end
|
197
|
+
|
198
|
+
it 'should pass the error dict to the proc' do
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
|
203
|
+
describe '#netServiceDidPublish' do
|
204
|
+
it 'should call its proc if exists' do
|
205
|
+
end
|
206
|
+
|
207
|
+
it 'should not explode if the proc does not exist' do
|
208
|
+
end
|
209
|
+
|
210
|
+
it 'should log a message at the INFO level' do
|
211
|
+
end
|
212
|
+
|
213
|
+
it 'should set @advertising to true' do
|
214
|
+
end
|
215
|
+
|
216
|
+
it 'should pass self to the proc' do
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
|
221
|
+
describe '#netServiceWillResolve' do
|
222
|
+
it 'should call its proc if exists' do
|
223
|
+
end
|
224
|
+
|
225
|
+
it 'should not explode if the proc does not exist' do
|
226
|
+
end
|
227
|
+
|
228
|
+
it 'should log a message at the INFO level' do
|
229
|
+
end
|
230
|
+
|
231
|
+
it 'should pass self to the proc' do
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
|
236
|
+
describe '#netService:didNotResolve:' do
|
237
|
+
it 'should call its proc if exists' do
|
238
|
+
end
|
239
|
+
|
240
|
+
it 'should not explode if the proc does not exist' do
|
241
|
+
end
|
242
|
+
|
243
|
+
it 'should log a message at the INFO level' do
|
244
|
+
end
|
245
|
+
|
246
|
+
it 'should pass self to the proc' do
|
247
|
+
end
|
248
|
+
|
249
|
+
it 'should pass the error dict to the proc' do
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
|
254
|
+
describe '#netServiceDidResolveAddress' do
|
255
|
+
it 'should call its proc if exists' do
|
256
|
+
end
|
257
|
+
|
258
|
+
it 'should not explode if the proc does not exist' do
|
259
|
+
end
|
260
|
+
|
261
|
+
it 'should log a message at the INFO level' do
|
262
|
+
end
|
263
|
+
|
264
|
+
it 'should pass self to the proc' do
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
|
269
|
+
describe '#netService:didUpdateTXTRecordData:' do
|
270
|
+
it 'should call its proc if exists' do
|
271
|
+
end
|
272
|
+
|
273
|
+
it 'should not explode if the proc does not exist' do
|
274
|
+
end
|
275
|
+
|
276
|
+
it 'should log a message at the INFO level' do
|
277
|
+
end
|
278
|
+
|
279
|
+
it 'should pass self to the proc' do
|
280
|
+
end
|
281
|
+
|
282
|
+
it 'should pass the TXT record data to the proc' do
|
283
|
+
end
|
284
|
+
end
|
285
|
+
|
286
|
+
|
287
|
+
describe '#netServiceDidStop' do
|
288
|
+
it 'should call its proc if exists' do
|
289
|
+
end
|
290
|
+
|
291
|
+
it 'should not explode if the proc does not exist' do
|
292
|
+
end
|
293
|
+
|
294
|
+
it 'should log a message at the INFO level' do
|
295
|
+
end
|
296
|
+
|
297
|
+
it 'should set @advertising to false' do
|
298
|
+
end
|
299
|
+
|
300
|
+
it 'should pass self to the proc' do
|
301
|
+
end
|
302
|
+
end
|
303
|
+
|
304
|
+
end
|
305
|
+
|
306
|
+
|
307
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,146 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: Salut
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 3
|
8
|
+
- 0
|
9
|
+
version: 0.3.0
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Mark Rada
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2011-01-17 00:00:00 -05:00
|
18
|
+
default_executable:
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: yard
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
none: false
|
25
|
+
requirements:
|
26
|
+
- - ~>
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
segments:
|
29
|
+
- 0
|
30
|
+
- 6
|
31
|
+
- 0
|
32
|
+
version: 0.6.0
|
33
|
+
type: :development
|
34
|
+
version_requirements: *id001
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: bluecloth
|
37
|
+
prerelease: false
|
38
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ~>
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
segments:
|
44
|
+
- 2
|
45
|
+
- 0
|
46
|
+
- 0
|
47
|
+
version: 2.0.0
|
48
|
+
type: :development
|
49
|
+
version_requirements: *id002
|
50
|
+
- !ruby/object:Gem::Dependency
|
51
|
+
name: jeweler
|
52
|
+
prerelease: false
|
53
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
54
|
+
none: false
|
55
|
+
requirements:
|
56
|
+
- - ~>
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
segments:
|
59
|
+
- 1
|
60
|
+
- 5
|
61
|
+
- 1
|
62
|
+
version: 1.5.1
|
63
|
+
type: :development
|
64
|
+
version_requirements: *id003
|
65
|
+
- !ruby/object:Gem::Dependency
|
66
|
+
name: mac_bacon
|
67
|
+
prerelease: false
|
68
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
69
|
+
none: false
|
70
|
+
requirements:
|
71
|
+
- - ~>
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
segments:
|
74
|
+
- 1
|
75
|
+
- 1
|
76
|
+
- 21
|
77
|
+
version: 1.1.21
|
78
|
+
type: :development
|
79
|
+
version_requirements: *id004
|
80
|
+
- !ruby/object:Gem::Dependency
|
81
|
+
name: rcov
|
82
|
+
prerelease: false
|
83
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
84
|
+
none: false
|
85
|
+
requirements:
|
86
|
+
- - ">="
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
segments:
|
89
|
+
- 0
|
90
|
+
version: "0"
|
91
|
+
type: :development
|
92
|
+
version_requirements: *id005
|
93
|
+
description: Uses the Objective-C NetService classes to advertise and discover services on the local network
|
94
|
+
email: marada@uwaterloo.ca
|
95
|
+
executables: []
|
96
|
+
|
97
|
+
extensions: []
|
98
|
+
|
99
|
+
extra_rdoc_files:
|
100
|
+
- LICENSE.txt
|
101
|
+
- README.markdown
|
102
|
+
files:
|
103
|
+
- lib/Salut.rb
|
104
|
+
- lib/Salut/Browser.rb
|
105
|
+
- lib/Salut/Service.rb
|
106
|
+
- LICENSE.txt
|
107
|
+
- README.markdown
|
108
|
+
- spec/Browser_spec.rb
|
109
|
+
- spec/Service_spec.rb
|
110
|
+
- spec/spec_helper.rb
|
111
|
+
has_rdoc: true
|
112
|
+
homepage: http://github.com/ferrous26/Salut
|
113
|
+
licenses:
|
114
|
+
- MIT
|
115
|
+
post_install_message:
|
116
|
+
rdoc_options: []
|
117
|
+
|
118
|
+
require_paths:
|
119
|
+
- lib
|
120
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
121
|
+
none: false
|
122
|
+
requirements:
|
123
|
+
- - ">="
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
segments:
|
126
|
+
- 0
|
127
|
+
version: "0"
|
128
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
129
|
+
none: false
|
130
|
+
requirements:
|
131
|
+
- - ">="
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
segments:
|
134
|
+
- 0
|
135
|
+
version: "0"
|
136
|
+
requirements: []
|
137
|
+
|
138
|
+
rubyforge_project:
|
139
|
+
rubygems_version: 1.3.7
|
140
|
+
signing_key:
|
141
|
+
specification_version: 3
|
142
|
+
summary: A simple example of using Bonjour with MacRuby
|
143
|
+
test_files:
|
144
|
+
- spec/Browser_spec.rb
|
145
|
+
- spec/Service_spec.rb
|
146
|
+
- spec/spec_helper.rb
|