talker 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.md ADDED
@@ -0,0 +1,97 @@
1
+ # Talker Ruby Client
2
+ A real-time Talker Ruby client.
3
+
4
+ # Usage
5
+ 1) Get a Talker account at https://talkerapp.com/signup
6
+
7
+ 2) Get your Talker Token on https://myaccount.talkerapp.com/settings
8
+
9
+ 3) Find the Room ID you want to connect to. This is the last part of the URL:
10
+
11
+ https://myaccount.talkerapp.com/rooms/<room_id>
12
+
13
+ 4) Serve hot and enjoy
14
+
15
+ Talker.connect(:room => ROOM_ID, :token => YOUR_TALKER_TOKEN) do |client|
16
+ client.on_connected do
17
+ client.send_message "hello!"
18
+ end
19
+
20
+ client.on_message do |user, message|
21
+ puts user["name"] + ": " + message
22
+ end
23
+
24
+ trap("INT") { client.close }
25
+ end
26
+
27
+ # Callbacks
28
+ All arguments are optional.
29
+
30
+ ## <code>on_connected</code>
31
+ Called when the user is authenticated and ready to receive events.
32
+
33
+ ## <code>on_presence(users)</code>
34
+ Called after <code>on_connected</code> with the list of connected users.
35
+ With <code>users</code> being something like this:
36
+
37
+ [{"id"=>1, "name"=>"macournoyer", "email"=>"macournoyer@talkerapp.com"},
38
+ {"id"=>2, "name"=>"gary", "email"=>"gary@talkerapp.com"}]
39
+
40
+ ## <code>on_message(user, message, event)</code>
41
+ Called when a new message is received.
42
+ <code>user</code> is the sender. <code>event</code> contains the full event sent by the server.
43
+
44
+ ## <code>on_join(user)</code>
45
+ Called when a user joins the room.
46
+
47
+ ## <code>on_idle(user)</code>
48
+ Called when a user becomes idle (closed connection without leaving).
49
+
50
+ ## <code>on_back(user)</code>
51
+ Called when a user is back from idle.
52
+
53
+ ## <code>on_leave(user)</code>
54
+ Called when a user leaves.
55
+
56
+ ## <code>on_close</code>
57
+ Called when the connection is closed.
58
+
59
+ ## <code>on_error(error_message)</code>
60
+ Called an error is received from the Talker server.
61
+
62
+ # Methods
63
+ Methods of an instance of Talker class.
64
+
65
+ ## <code>users</code>
66
+ Array of users currently in the room. In the form:
67
+
68
+ [{"id"=>1, "name"=>"macournoyer", "email"=>"macournoyer@talkerapp.com"},
69
+ {"id"=>2, "name"=>"gary", "email"=>"gary@talkerapp.com"}]
70
+
71
+ ## <code>leave</code>
72
+ Leave the room and close the connection.
73
+
74
+ ## <code>close</code>
75
+ Close the connection without leaving the room.
76
+
77
+ ## <code>send_message(message)</code>
78
+ Send a message.
79
+
80
+ ## <code>send_private_message(user_name, message)</code>
81
+ Send a private message to <code>user_name</code>.
82
+
83
+ # Running the specs
84
+ Howdy brave lil' one! To run the specs you'll need courage, hard work and some luck:
85
+
86
+ 1) Install from source my "special" fork of em-spec at http://github.com/macournoyer/em-spec.
87
+
88
+ 2) Edit the file spec/talker.example.yml with your info and rename it to spec/talker.yml.
89
+
90
+ 3) Run <code>rake</code> and everything should be green, birds should start signing and someone will make you a chocolate cake
91
+
92
+ (results may vary).
93
+
94
+ # Credits & License
95
+ Released under the Ruby License, (c) Talker
96
+
97
+ Thanks to http://github.com/raggi for kicking this off.
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ require "spec/rake/spectask"
2
+
3
+ task :default => :spec
4
+
5
+ Spec::Rake::SpecTask.new do |t|
6
+ t.spec_opts = %w(-fs -c)
7
+ t.spec_files = FileList["spec/**_spec.rb"]
8
+ end
data/bin/talker-cat ADDED
@@ -0,0 +1,32 @@
1
+ #!/usr/bin/env ruby
2
+ require "talker"
3
+ require "talker/cli"
4
+
5
+ token = Talker::CLI.load_token
6
+ room = ARGV.first
7
+
8
+ abort <<-EOS unless room
9
+ usage: echo 'something' | talker-cat <room_id>
10
+
11
+ Send a message to a room:
12
+
13
+ echo 'something' | talker-cat 1
14
+
15
+ Send a file to a room:
16
+
17
+ talker-cat 1 < site_fixer.rb
18
+
19
+ Room ID is the last part of the URL:
20
+ https://myaccount.talkerapp.com/rooms/<room_id>
21
+
22
+ EOS
23
+
24
+ Talker.connect(:room => room, :token => token) do |client|
25
+ client.on_connected do
26
+ client.send_message STDIN.read
27
+ client.close
28
+ end
29
+ client.on_error do |error|
30
+ puts error
31
+ end
32
+ end
data/bin/talker-shell ADDED
@@ -0,0 +1,71 @@
1
+ #!/usr/bin/env ruby
2
+ require "talker"
3
+ require "talker/cli"
4
+
5
+ token = Talker::CLI.load_token
6
+ room, cmd, process_name = *ARGV
7
+ process_name ||= cmd
8
+
9
+ abort <<-EOS unless room && cmd
10
+ usage: talker-shell <room_id> <command> [name]
11
+ Launch an irb session connected to a room:
12
+
13
+ talker-shell 1 irb
14
+
15
+ Room ID is the last part of the URL:
16
+ https://myaccount.talkerapp.com/rooms/<room_id>
17
+
18
+ EOS
19
+
20
+
21
+ module Process
22
+ attr_accessor :name, :client
23
+
24
+ def receive_data(data)
25
+ log data
26
+ end
27
+
28
+ def unbind
29
+ log "exited"
30
+ @client.close
31
+ end
32
+
33
+ def log(msg)
34
+ puts "> #{msg}"
35
+ @client.send_message("#{name}> #{msg}")
36
+ end
37
+ end
38
+
39
+
40
+ EM.run do
41
+ Talker.connect(:room => room, :token => token) do |client|
42
+ @process = nil
43
+
44
+ client.on_connected do
45
+ EM.popen(cmd, Process) do |process|
46
+ client.send_message "Connected to process: #{cmd}, prefix commands w/ '#{process_name}: '"
47
+
48
+ process.name = process_name
49
+ process.client = client
50
+ trap("INT") { process.close_connection_after_writing }
51
+
52
+ @process = process
53
+ end
54
+ end
55
+
56
+ client.on_message do |user, message|
57
+ if command = message[/^#{process_name}: (.*)$/, 1]
58
+ puts "> #{cmd}"
59
+ @process.send_data command + "\n"
60
+ end
61
+ end
62
+
63
+ client.on_error do |error|
64
+ puts error
65
+ end
66
+
67
+ client.on_close do
68
+ EM.stop
69
+ end
70
+ end
71
+ end
data/lib/talker/cli.rb ADDED
@@ -0,0 +1,16 @@
1
+ class Talker
2
+ class CLI
3
+ def self.load_token
4
+ token_path = File.join(ENV['HOME'], '.talker')
5
+
6
+ unless File.file?(token_path)
7
+ abort <<-EOS
8
+ Place your Talker Token in #{token_path}. You can find your
9
+ token in https://myaccount.talkerapp.com/settings
10
+ EOS
11
+ end
12
+
13
+ File.read(token_path).strip
14
+ end
15
+ end
16
+ end
data/lib/talker.rb ADDED
@@ -0,0 +1,136 @@
1
+ require "eventmachine"
2
+ require "yajl"
3
+
4
+ class Talker < EM::Connection
5
+ class Error < RuntimeError; end
6
+
7
+ attr_accessor :room, :token, :thread
8
+
9
+ def self.connect(options={})
10
+ host = options[:host] || "talkerapp.com"
11
+ port = (options[:port] || 8500).to_i
12
+ room = options[:room].to_i
13
+ token = options[:token]
14
+
15
+ thread = Thread.new { EM.run } unless EM.reactor_running?
16
+
17
+ EM.connect host, port, self do |c|
18
+ c.thread = thread
19
+ c.room = room
20
+ c.token = token
21
+ yield c if block_given?
22
+ end
23
+
24
+ thread.join unless thread.nil?
25
+ end
26
+
27
+ def initialize
28
+ @users = {}
29
+ end
30
+
31
+ # Callbacks
32
+ %w( connected message join idle back leave presence error close ).each do |method|
33
+ class_eval <<-EOS
34
+ def on_#{method}(&block)
35
+ @on_#{method} = block
36
+ end
37
+ EOS
38
+ end
39
+
40
+ def users
41
+ @users.values
42
+ end
43
+
44
+ def send_message(message, attributes={})
45
+ send({ :type => "message", :content => message }.merge(attributes))
46
+ end
47
+
48
+ def send_private_message(to, message)
49
+ if to.is_a?(String)
50
+ user = @users.values.detect { |user| user["name"] == to }
51
+ raise Error, "User #{to} not found" unless user
52
+ user_id = user["id"]
53
+ else
54
+ user_id = to
55
+ end
56
+ send_message message, :to => user_id
57
+ end
58
+
59
+
60
+ ## EventMachine callbacks
61
+
62
+ def connection_completed
63
+ send :type => "connect", :room => @room, :token => @token
64
+ EM.add_periodic_timer(20) { send :type => "ping" }
65
+ end
66
+
67
+ def leave
68
+ send :type => "close"
69
+ close
70
+ end
71
+
72
+ def close
73
+ close_connection_after_writing
74
+ end
75
+
76
+ def post_init
77
+ @parser = Yajl::Parser.new
78
+ @parser.on_parse_complete = method(:event_parsed)
79
+ end
80
+
81
+ def receive_data(data)
82
+ @parser << data
83
+ end
84
+
85
+ def unbind
86
+ trigger :close
87
+ @thread.kill if @thread
88
+ end
89
+
90
+
91
+ private
92
+ def event_parsed(event)
93
+ case event["type"]
94
+ when "connected"
95
+ trigger :connected
96
+ when "error"
97
+ if @on_error
98
+ @on_error.call(event["message"])
99
+ else
100
+ raise Error, event["message"]
101
+ end
102
+ when "users"
103
+ event["users"].each do |user|
104
+ @users[user["id"]] = user
105
+ end
106
+ trigger :presence, @users.values
107
+ when "join"
108
+ @users[event["user"]["id"]] = event["user"]
109
+ trigger :join, event["user"]
110
+ when "leave"
111
+ @users.delete(event["user"]["id"])
112
+ trigger :leave, event["user"]
113
+ when "idle"
114
+ trigger :idle, event["user"]
115
+ when "back"
116
+ trigger :back, event["user"]
117
+ when "message"
118
+ @users[event["user"]["id"]] ||= event["user"]
119
+ trigger :message, event["user"], event["content"], event
120
+ else
121
+ raise Error, "unknown event type received from server: " + event["type"]
122
+ end
123
+ rescue
124
+ close
125
+ raise
126
+ end
127
+
128
+ def trigger(callback, *args)
129
+ callback = instance_variable_get(:"@on_#{callback}")
130
+ callback.call(*args[0,callback.arity]) if callback
131
+ end
132
+
133
+ def send(data)
134
+ send_data Yajl::Encoder.encode(data) + "\n"
135
+ end
136
+ end
@@ -0,0 +1,22 @@
1
+ require "rubygems"
2
+ require "yaml"
3
+ require 'spec'
4
+ $:.unshift File.dirname(__FILE__) + "/../lib"
5
+ require "talker"
6
+
7
+ # Installing em-spec from http://github.com/macournoyer/em-spec
8
+ require 'em/spec'
9
+ require 'em/spec/rspec'
10
+ EM.spec_backend = EM::Spec::Rspec
11
+
12
+ TALKER_CONFIG = YAML.load_file(File.dirname(__FILE__) + "/talker.yml")
13
+
14
+ module Helpers
15
+ def connect(&callback)
16
+ Talker.connect :room => TALKER_CONFIG["room"].to_i, :token => TALKER_CONFIG["token"], &callback
17
+ end
18
+ end
19
+
20
+ Spec::Runner.configure do |config|
21
+ config.include Helpers
22
+ end
@@ -0,0 +1,7 @@
1
+ # Get your Talker Token on https://myaccount.talkerapp.com/settings
2
+ token: YOUR_TALKER_TOKEN
3
+ # Room ID is the last part of the URL:
4
+ # https://myaccount.talkerapp.com/rooms/<room_id>
5
+ room: ROOM_ID
6
+ # Make sure it matches or some specs will fail
7
+ user_name: YOUR_USER_NAME
data/spec/talker.yml ADDED
@@ -0,0 +1,3 @@
1
+ token: 845a877053137c0bc76acfc027b92ca0e1d3699f
2
+ room: 62
3
+ user_name: ma
@@ -0,0 +1,68 @@
1
+ require File.dirname(__FILE__) + "/spec_helper"
2
+
3
+ EM.describe Talker do
4
+ it "should connect" do
5
+ connect do |client|
6
+ client.on_connected do
7
+ done
8
+ end
9
+ end
10
+ end
11
+
12
+ it "should close" do
13
+ connect do |client|
14
+ client.on_connected do
15
+ client.close
16
+ end
17
+ client.on_close do
18
+ done
19
+ end
20
+ end
21
+ end
22
+
23
+ it "should receive presence" do
24
+ connect do |client|
25
+ client.on_presence do |users|
26
+ users.size.should >= 1
27
+ users.map { |user| user["name"] }.should include(TALKER_CONFIG["user_name"])
28
+ done
29
+ end
30
+ end
31
+ end
32
+
33
+ it "should send and receive message" do
34
+ connect do |client|
35
+ client.on_connected do
36
+ client.send_message "it works, magic!"
37
+ end
38
+ client.on_message do |user, message|
39
+ message.should == "it works, magic!"
40
+ done
41
+ end
42
+ end
43
+ end
44
+
45
+ it "should send and receive private message" do
46
+ connect do |client|
47
+ client.on_presence do
48
+ client.send_private_message TALKER_CONFIG["user_name"], "private magic"
49
+ end
50
+ client.on_message do |user, message|
51
+ message.should == "private magic"
52
+ done
53
+ end
54
+ end
55
+ end
56
+
57
+ # Keep at the end, mmmkay?
58
+ it "should leave" do
59
+ connect do |client|
60
+ client.on_connected do
61
+ client.leave
62
+ end
63
+ client.on_close do
64
+ done
65
+ end
66
+ end
67
+ end
68
+ end
data/talker.gemspec ADDED
@@ -0,0 +1,17 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = %q{talker}
3
+ s.version = "0.0.1"
4
+
5
+ s.authors = ["Marc-Andre Cournoyer"]
6
+ s.email = "macournoyer@talkerapp.com"
7
+ s.files = Dir["**/*"]
8
+ s.homepage = "http://github.com/macournoyer/talker.rb"
9
+ s.require_paths = ["lib"]
10
+ s.bindir = "bin"
11
+ s.executables = ["talker-cat", "talker-shell"]
12
+ s.summary = "A real-time Talker Ruby client."
13
+ s.test_files = Dir["spec/**"]
14
+
15
+ s.add_dependency "eventmachine"
16
+ s.add_dependency "yajl-ruby"
17
+ end
metadata ADDED
@@ -0,0 +1,89 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: talker
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Marc-Andre Cournoyer
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-11-12 00:00:00 -05:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: eventmachine
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: yajl-ruby
27
+ type: :runtime
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: "0"
34
+ version:
35
+ description:
36
+ email: macournoyer@talkerapp.com
37
+ executables:
38
+ - talker-cat
39
+ - talker-shell
40
+ extensions: []
41
+
42
+ extra_rdoc_files: []
43
+
44
+ files:
45
+ - bin/talker-cat
46
+ - bin/talker-shell
47
+ - lib/talker/cli.rb
48
+ - lib/talker.rb
49
+ - Rakefile
50
+ - README.md
51
+ - spec/spec_helper.rb
52
+ - spec/talker.example.yml
53
+ - spec/talker.yml
54
+ - spec/talker_spec.rb
55
+ - talker-0.0.1.gem
56
+ - talker.gemspec
57
+ has_rdoc: true
58
+ homepage: http://github.com/macournoyer/talker.rb
59
+ licenses: []
60
+
61
+ post_install_message:
62
+ rdoc_options: []
63
+
64
+ require_paths:
65
+ - lib
66
+ required_ruby_version: !ruby/object:Gem::Requirement
67
+ requirements:
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ version: "0"
71
+ version:
72
+ required_rubygems_version: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ version: "0"
77
+ version:
78
+ requirements: []
79
+
80
+ rubyforge_project:
81
+ rubygems_version: 1.3.5
82
+ signing_key:
83
+ specification_version: 3
84
+ summary: A real-time Talker Ruby client.
85
+ test_files:
86
+ - spec/spec_helper.rb
87
+ - spec/talker.example.yml
88
+ - spec/talker.yml
89
+ - spec/talker_spec.rb