talker 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/README.md +97 -0
- data/Rakefile +8 -0
- data/bin/talker-cat +32 -0
- data/bin/talker-shell +71 -0
- data/lib/talker/cli.rb +16 -0
- data/lib/talker.rb +136 -0
- data/spec/spec_helper.rb +22 -0
- data/spec/talker.example.yml +7 -0
- data/spec/talker.yml +3 -0
- data/spec/talker_spec.rb +68 -0
- data/talker.gemspec +17 -0
- metadata +89 -0
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
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
|
data/spec/spec_helper.rb
ADDED
@@ -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
data/spec/talker_spec.rb
ADDED
@@ -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
|