mojodna-switchboard 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.
Files changed (37) hide show
  1. data/README.markdown +31 -0
  2. data/bin/switchboard +35 -0
  3. data/examples/election_results.rb +61 -0
  4. data/lib/switchboard/colors.rb +10 -0
  5. data/lib/switchboard/commands/command.rb +85 -0
  6. data/lib/switchboard/commands/config/config.rb +20 -0
  7. data/lib/switchboard/commands/config.rb +1 -0
  8. data/lib/switchboard/commands/default.rb +47 -0
  9. data/lib/switchboard/commands/help/help.rb +15 -0
  10. data/lib/switchboard/commands/help.rb +1 -0
  11. data/lib/switchboard/commands/pubsub/pubsub.rb +16 -0
  12. data/lib/switchboard/commands/pubsub/subscribe.rb +35 -0
  13. data/lib/switchboard/commands/pubsub/subscriptions.rb +32 -0
  14. data/lib/switchboard/commands/pubsub/unsubscribe.rb +31 -0
  15. data/lib/switchboard/commands/pubsub.rb +4 -0
  16. data/lib/switchboard/commands/roster/add.rb +26 -0
  17. data/lib/switchboard/commands/roster/list.rb +24 -0
  18. data/lib/switchboard/commands/roster/remove.rb +29 -0
  19. data/lib/switchboard/commands/roster/roster.rb +7 -0
  20. data/lib/switchboard/commands/roster.rb +4 -0
  21. data/lib/switchboard/commands.rb +6 -0
  22. data/lib/switchboard/core.rb +324 -0
  23. data/lib/switchboard/instance_exec.rb +16 -0
  24. data/lib/switchboard/jacks/auto_accept.rb +16 -0
  25. data/lib/switchboard/jacks/debug.rb +17 -0
  26. data/lib/switchboard/jacks/notify.rb +15 -0
  27. data/lib/switchboard/jacks/oauth_pubsub.rb +50 -0
  28. data/lib/switchboard/jacks/roster_debug.rb +23 -0
  29. data/lib/switchboard/jacks.rb +5 -0
  30. data/lib/switchboard/oauth/request_proxy/mock_request.rb +21 -0
  31. data/lib/switchboard/settings.rb +32 -0
  32. data/lib/switchboard/switchboard.rb +5 -0
  33. data/lib/switchboard/version.rb +3 -0
  34. data/lib/switchboard/xmpp4r/pubsub/helper/oauth_service_helper.rb +107 -0
  35. data/lib/switchboard.rb +1 -0
  36. data/switchboard.gemspec +14 -0
  37. metadata +113 -0
data/README.markdown ADDED
@@ -0,0 +1,31 @@
1
+ # Switchboard
2
+
3
+ Switchboard is both a toolkit for assembling XMPP clients as well as a set of
4
+ command-line tools for interacting with XMPP servers.
5
+
6
+ ## Getting Started
7
+
8
+ Install it:
9
+
10
+ $ gem install mojodna-switchboard -s http://gems.github.com
11
+
12
+ Configure it:
13
+
14
+ $ switchboard config jid jid@example.com
15
+ $ switchboard config password pa55word
16
+ $ switchboard config oauth.consumer_key asdf
17
+ $ switchboard config oauth.consumer_secret qwerty
18
+ $ switchboard config oauth.token asdf
19
+ $ switchboard config oauth.token_secret qwerty
20
+ $ switchboard config oauth.general_token asdf
21
+ $ switchboard config oauth.general_token_secret qwerty
22
+ $ switchboard config pubsub.server fireeagle.com
23
+
24
+ _Settings will be stored in `$HOME/.switchboardrc`_
25
+
26
+ Run it:
27
+
28
+ $ switchboard <command> <args>
29
+ $ switchboard roster list
30
+ $ switchboard roster add fireeagle.com
31
+ $ ...
data/bin/switchboard ADDED
@@ -0,0 +1,35 @@
1
+ #!/usr/bin/env ruby
2
+ require 'switchboard'
3
+ require 'optparse'
4
+
5
+ command = ARGV.clone.options do |opts|
6
+ # opts.banner = "Usage: example.rb [options]"
7
+
8
+ command = Switchboard::Commands::Default
9
+ command.options(opts)
10
+
11
+ cmd = []
12
+ argv = []
13
+
14
+ # force optparse into being a command parser
15
+ opts.order! do |arg|
16
+ cmd << arg
17
+
18
+ if c = Switchboard::COMMANDS[cmd * "_"]
19
+ command = c
20
+ command.options(opts)
21
+ elsif c = Switchboard::COMMANDS["_" + cmd * "_"]
22
+ command = c
23
+ else
24
+ # unrecognized, unclaimed argument; keep as ARGV
25
+ argv << arg
26
+ end
27
+ end
28
+
29
+ # correct ARGV to match unrecognized, unclaimed arguments
30
+ ARGV.reject! { |v| !argv.include?(v) }
31
+
32
+ command
33
+ end
34
+
35
+ command.run!
@@ -0,0 +1,61 @@
1
+ #!/usr/bin/env ruby
2
+ require 'fire_hydrant'
3
+ require 'rexml/document'
4
+ require 'open-uri'
5
+
6
+ hydrant = FireHydrant.new(YAML.load(File.read("fire_hydrant.yml"))) do
7
+ old_votes = load_results
8
+
9
+ while(!shutdown?) do
10
+ # load the results feed
11
+ votes = load_results
12
+ diff = nil
13
+
14
+ # loop through and compare it to the old results
15
+ votes.each do |state, cand|
16
+ cand.each do |c, val|
17
+ unless old_votes[state][c] == val
18
+ diff ||= "Electoral results changed"
19
+ diff << "\n#{state} - #{c}: #{old_votes[state][c].inspect} => #{val.inspect}"
20
+ end
21
+ end
22
+ end
23
+
24
+ if diff
25
+ puts diff
26
+ broadcast(diff)
27
+ end
28
+
29
+ # set this as old_votes
30
+ old_votes = votes
31
+
32
+ # wait 5 minutes
33
+ puts "-----"
34
+ sleep 300
35
+ end
36
+ end
37
+
38
+ hydrant.jack!(AutoAcceptJack, NotifyJack)
39
+
40
+ def hydrant.load_results(url = "http://d.yimg.com/b/data/us/news/xml/elections/2008a/pres.xml")
41
+ doc = REXML::Document.new(open(url))
42
+ nodes = doc.elements.collect("//state") { |node| [node.attributes["name"].downcase, node.elements.collect("cand") { |cand| [cand.attributes["name"].downcase, cand.attributes["PopPct"].to_f, cand.attributes["PopVote"].to_i] }] }
43
+
44
+ votes = {}
45
+ nodes.each do |state, results|
46
+ votes[state] = {}
47
+ results.each do |cand, pct, vote|
48
+ votes[state][cand] = [pct, vote]
49
+ end
50
+ end
51
+
52
+ votes
53
+ end
54
+
55
+ def hydrant.broadcast(msg)
56
+ roster.items.each do |jid, item|
57
+ client.send(Jabber::Message.new(jid, msg))
58
+ end
59
+ end
60
+
61
+ hydrant.run!
@@ -0,0 +1,10 @@
1
+ class String
2
+ def red; colorize(self, "\e[1m\e[31m"); end
3
+ def green; colorize(self, "\e[1m\e[32m"); end
4
+ def dark_green; colorize(self, "\e[32m"); end
5
+ def yellow; colorize(self, "\e[1m\e[33m"); end
6
+ def blue; colorize(self, "\e[1m\e[34m"); end
7
+ def dark_blue; colorize(self, "\e[34m"); end
8
+ def purple; colorize(self, "\e[1m\e[35m"); end
9
+ def colorize(text, color_code) "#{color_code}#{text}\e[0m" end
10
+ end
@@ -0,0 +1,85 @@
1
+ module Switchboard
2
+ COMMANDS = {}
3
+
4
+ def self.commands(command = nil)
5
+ if command
6
+ COMMANDS.select { |k,v| k =~ /^#{command.to_command_name("_")}_/ }
7
+ else
8
+ COMMANDS.reject { |k,v| k =~ /_/ }
9
+ end
10
+ end
11
+
12
+ def self.hide_command(command)
13
+ COMMANDS["_#{command.to_command_name("_")}"] = unregister_command(command)
14
+ end
15
+
16
+ def self.register_command(command)
17
+ COMMANDS[command.to_command_name("_")] = command
18
+ end
19
+
20
+ def self.unregister_command(command)
21
+ COMMANDS.delete(command.to_command_name("_"))
22
+ end
23
+
24
+
25
+ module Commands
26
+ end
27
+
28
+ class Command
29
+ def self.description(description = nil)
30
+ @description = description if description
31
+ @description
32
+ end
33
+
34
+ def self.help
35
+ "No help is available for this command (#{self.to_command_name})."
36
+ end
37
+
38
+ # TODO consider accepting a block in subclasses
39
+ def self.options(opts)
40
+ @options = opts
41
+ @options.banner = "Usage: #{opts.program_name} [options] #{self.to_command_name} [options] [args]"
42
+ @options
43
+ end
44
+
45
+ def self.run!
46
+ puts self.options(OptionParser.new).help
47
+ commands = Switchboard.commands(self)
48
+
49
+ if commands.any?
50
+ puts
51
+ puts "Available commands:"
52
+ commands.each do |name, command|
53
+ puts " #{command.to_command.ljust(15)}#{command.description}"
54
+ command.options(OptionParser.new).summarize do |line|
55
+ puts " " * 16 + line
56
+ end
57
+ end
58
+ puts
59
+ puts "See '#{@options.program_name} help COMMAND' for more information on a specific command."
60
+ end
61
+ end
62
+
63
+ def self.to_command
64
+ self.name.gsub("Switchboard::Commands::", "").split("::").last.downcase
65
+ end
66
+
67
+ def self.to_command_name(delimiter = " ")
68
+ self.name.gsub("Switchboard::Commands::", "").split("::").map { |c| c.downcase } * delimiter
69
+ end
70
+
71
+ private
72
+
73
+ def self.hide!
74
+ Switchboard.hide_command(self)
75
+ end
76
+
77
+ def self.inherited(klass)
78
+ Switchboard.register_command(klass) if klass.name =~ /^Switchboard::Commands/
79
+ end
80
+
81
+ def self.unregister!
82
+ Switchboard.unregister_command(self)
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,20 @@
1
+ module Switchboard
2
+ module Commands
3
+ class Config < Switchboard::Command
4
+ description "Get and set global options"
5
+
6
+ def self.run!
7
+ settings = Switchboard::Settings.new
8
+ if ARGV.empty?
9
+ super
10
+ elsif ARGV.length == 1
11
+ puts settings.get(ARGV.shift)
12
+ elsif ARGV.length == 2
13
+ settings.set!(ARGV.shift, ARGV.shift)
14
+ else
15
+ puts "error: More than one value for the key #{ARGV.shift}: #{ARGV * " "}"
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1 @@
1
+ require 'switchboard/commands/config/config'
@@ -0,0 +1,47 @@
1
+ module Switchboard
2
+ class Command
3
+ OPTIONS = {}
4
+ DEFAULT_OPTIONS = {
5
+ # :detach => false,
6
+ "debug" => false,
7
+ "oauth" => false,
8
+ "resource" => "switchboard"
9
+ }
10
+ end
11
+ module Commands
12
+ class Default < Switchboard::Command
13
+ unregister!
14
+
15
+ def self.options(opts)
16
+ super(opts)
17
+
18
+ opts.banner = "Usage: #{opts.program_name} [options] COMMAND [options] [args]"
19
+
20
+ # opts.on("-d", "--daemon", "Make server run as a daemon.") { OPTIONS[:detach] = true }
21
+ # opts.on("-l", "--log=path", String, "Specifies a path to log script output.") { |v| OPTIONS[:log] = v }
22
+ # opts.on("-p", "--pidfile=path", String,
23
+ # "Specifies a pidfile to use.") { |v| OPTIONS[:pidfile] = v }
24
+ # opts.on("-v", "--[no-]verbose", "Run verbosely") { |v| OPTIONS[:verbose] = v }
25
+
26
+ opts.separator ""
27
+
28
+ opts.on_tail("-h", "--help", "Show this help message.") { puts opts; exit }
29
+ opts.on_tail("--version", "Show version") { puts "switchboard version #{Switchboard::VERSION * "."}"; exit }
30
+ end
31
+
32
+ def self.run!
33
+ puts self.options(OptionParser.new).help
34
+ puts
35
+ puts "Available commands:"
36
+ Switchboard.commands.each do |name, command|
37
+ puts " #{command.to_command.ljust(15)}#{command.description}"
38
+ command.options(OptionParser.new).summarize do |line|
39
+ puts " " * 16 + line
40
+ end
41
+ end
42
+ puts
43
+ puts "See '#{@options.program_name} help COMMAND' for more information on a specific command."
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,15 @@
1
+ module Switchboard
2
+ module Commands
3
+ class Help < Switchboard::Command
4
+ hide!
5
+
6
+ def self.run!
7
+ if ARGV.any?
8
+ puts Switchboard::COMMANDS[ARGV * "_"].help
9
+ else
10
+ Switchboard::Commands::Default.run!
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1 @@
1
+ require 'switchboard/commands/help/help'
@@ -0,0 +1,16 @@
1
+ module Switchboard
2
+ module Commands
3
+ class PubSub < Switchboard::Command
4
+ description "Pubsub node manipulation"
5
+
6
+ def self.help
7
+ "These are the more extensive instructions for using the pubsub command."
8
+ end
9
+
10
+ def self.options(opts)
11
+ super(opts)
12
+ # opts.on("--oauth", "Sign requests using OAuth.") { OPTIONS[:oauth] = true }
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,35 @@
1
+ module Switchboard
2
+ module Commands
3
+ class PubSub
4
+ class Subscribe < Switchboard::Command
5
+ description "Subscribe to a pubsub node"
6
+
7
+ def self.run!
8
+ # TODO override settings with values from the command line
9
+ switchboard = Switchboard::Core.new do
10
+ # this executes in the main loop, so it doesn't really matter that this runs in a different thread
11
+ defer :subscribed do
12
+ begin
13
+ pubsub.subscribe_to("/api/0.1/user/#{settings["oauth.token"]}", oauth_consumer, oauth_token)
14
+ rescue Jabber::ServerError => e
15
+ puts e
16
+ end
17
+ end
18
+
19
+ # define here or as hydrant.subscriptions_received
20
+ def subscribed(subscription)
21
+ if subscription.subscription == :subscribed
22
+ puts "Subscribe successful."
23
+ else
24
+ puts "Subscribe failed!".red
25
+ end
26
+ end
27
+ end
28
+
29
+ switchboard.plug!(OAuthPubSubJack)
30
+ switchboard.run!
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,32 @@
1
+ module Switchboard
2
+ module Commands
3
+ class PubSub
4
+ class Subscriptions < Switchboard::Command
5
+ description "List pubsub subscriptions"
6
+
7
+ def self.run!
8
+ # TODO override settings with values from the command line
9
+ switchboard = Switchboard::Core.new do
10
+ # this executes in the main loop, so it doesn't really matter that this runs in a different thread
11
+ defer :subscriptions_received do
12
+ begin
13
+ pubsub.get_subscriptions_from_all_nodes(oauth_consumer, general_token)
14
+ rescue Jabber::ServerError => e
15
+ puts e
16
+ end
17
+ end
18
+
19
+ # define here or as hydrant.subscriptions_received
20
+ def subscriptions_received(subscriptions)
21
+ puts "Subscriptions:"
22
+ puts subscriptions.collect { |subscription| "#{subscription.jid} => #{subscription.node}" } * "\n"
23
+ end
24
+ end
25
+
26
+ switchboard.plug!(OAuthPubSubJack)
27
+ switchboard.run!
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,31 @@
1
+ module Switchboard
2
+ module Commands
3
+ class PubSub
4
+ class Unsubscribe < Switchboard::Command
5
+ description "Unsubscribe from a pubsub node"
6
+
7
+ def self.run!
8
+ # TODO override settings with values from the command line
9
+ switchboard = Switchboard::Core.new do
10
+ # this executes in the main loop, so it doesn't really matter that this runs in a different thread
11
+ defer :unsubscribed do
12
+ begin
13
+ pubsub.unsubscribe_from("/api/0.1/user/#{settings["oauth.token"]}", oauth_consumer, oauth_token)
14
+ rescue Jabber::ServerError => e
15
+ puts e
16
+ end
17
+ end
18
+
19
+ # define here or as hydrant.subscriptions_received
20
+ def unsubscribed(successful)
21
+ puts "Unsubscribe was successful." if successful
22
+ end
23
+ end
24
+
25
+ switchboard.plug!(OAuthPubSubJack)
26
+ switchboard.run!
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,4 @@
1
+ require 'switchboard/commands/pubsub/pubsub'
2
+ require 'switchboard/commands/pubsub/subscribe'
3
+ require 'switchboard/commands/pubsub/subscriptions'
4
+ require 'switchboard/commands/pubsub/unsubscribe'
@@ -0,0 +1,26 @@
1
+ module Switchboard
2
+ module Commands
3
+ class Roster
4
+ class Add < Switchboard::Command
5
+ description "Add a JID to your roster"
6
+
7
+ def self.run!
8
+ # TODO override settings with values from the command line
9
+ switchboard = Switchboard::Core.new do
10
+ # add the server as a contact if it wasn't already added
11
+ ARGV.each do |jid|
12
+ if roster.find(jid).empty?
13
+ puts "Adding #{jid} to my roster..."
14
+ roster.add(jid, nil, true)
15
+ end
16
+ end
17
+ end
18
+
19
+ switchboard.plug!(AutoAcceptJack)
20
+
21
+ switchboard.run!
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,24 @@
1
+ module Switchboard
2
+ module Commands
3
+ class Roster
4
+ class List < Switchboard::Command
5
+ description "List all roster items"
6
+
7
+ def self.run!
8
+ # TODO override settings with values from the command line
9
+ switchboard = Switchboard::Core.new do
10
+ if roster.items.any?
11
+ puts "#{settings["jid"]}'s roster:"
12
+ puts roster.items.keys.map { |jid| jid.to_s } * "\n"
13
+ else
14
+ puts "#{settings["jid"]}'s roster is empty."
15
+ end
16
+ end
17
+
18
+ switchboard.plug!(AutoAcceptJack)
19
+ switchboard.run!
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,29 @@
1
+ module Switchboard
2
+ module Commands
3
+ class Roster
4
+ class Remove < Switchboard::Command
5
+ description "Remove a JID from your roster"
6
+
7
+ def self.options(opts)
8
+ super(opts)
9
+ # opts.on("-l", "--log=path", String, "Specifies a path to log script output.") { |v| OPTIONS[:log] = v }
10
+ end
11
+
12
+ def self.run!
13
+ # TODO override settings with values from the command line
14
+ switchboard = Switchboard::Core.new do
15
+ ARGV.each do |jid|
16
+ if (items = roster.find(jid)).any?
17
+ item = items.values.first
18
+ puts "Removing #{item.jid.to_s} from my roster..."
19
+ item.remove
20
+ end
21
+ end
22
+ end
23
+
24
+ switchboard.run!
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,7 @@
1
+ module Switchboard
2
+ module Commands
3
+ class Roster < Switchboard::Command
4
+ description "Roster manipulation"
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,4 @@
1
+ require 'switchboard/commands/roster/roster'
2
+ require 'switchboard/commands/roster/add'
3
+ require 'switchboard/commands/roster/list'
4
+ require 'switchboard/commands/roster/remove'
@@ -0,0 +1,6 @@
1
+ require 'switchboard/commands/command'
2
+ require 'switchboard/commands/config'
3
+ require 'switchboard/commands/default'
4
+ require 'switchboard/commands/help'
5
+ require 'switchboard/commands/pubsub'
6
+ require 'switchboard/commands/roster'