sup 0.12.1 → 0.13.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of sup might be problematic. Click here for more details.
- data.tar.gz.sig +1 -0
- data/CONTRIBUTORS +25 -12
- data/History.txt +6 -1
- data/README.md +70 -0
- data/ReleaseNotes +5 -0
- data/bin/sup +22 -15
- data/bin/sup-add +3 -3
- data/bin/sup-config +3 -4
- data/bin/sup-import-dump +1 -1
- data/bin/sup-sync +1 -1
- data/bin/sup-sync-back +2 -2
- data/bin/sup-tweak-labels +1 -1
- data/lib/sup.rb +39 -23
- data/lib/sup/account.rb +4 -0
- data/lib/sup/buffer.rb +4 -7
- data/lib/sup/colormap.rb +10 -2
- data/lib/sup/contact.rb +11 -5
- data/lib/sup/crypto.rb +278 -101
- data/lib/sup/draft.rb +3 -2
- data/lib/sup/horizontal-selector.rb +5 -2
- data/lib/sup/index.rb +47 -42
- data/lib/sup/label.rb +1 -1
- data/lib/sup/message-chunks.rb +4 -2
- data/lib/sup/message.rb +14 -3
- data/lib/sup/modes/buffer-list-mode.rb +1 -1
- data/lib/sup/modes/compose-mode.rb +1 -1
- data/lib/sup/modes/contact-list-mode.rb +2 -2
- data/lib/sup/modes/edit-message-async-mode.rb +109 -0
- data/lib/sup/modes/edit-message-mode.rb +148 -16
- data/lib/sup/modes/file-browser-mode.rb +2 -2
- data/lib/sup/modes/forward-mode.rb +4 -4
- data/lib/sup/modes/line-cursor-mode.rb +2 -2
- data/lib/sup/modes/reply-mode.rb +34 -30
- data/lib/sup/modes/resume-mode.rb +4 -1
- data/lib/sup/modes/scroll-mode.rb +8 -6
- data/lib/sup/modes/text-mode.rb +1 -1
- data/lib/sup/modes/thread-index-mode.rb +44 -25
- data/lib/sup/modes/thread-view-mode.rb +26 -24
- data/lib/sup/person.rb +18 -7
- data/lib/sup/poll.rb +1 -1
- data/lib/sup/rfc2047.rb +1 -1
- data/lib/sup/sent.rb +2 -2
- data/lib/sup/source.rb +1 -1
- data/lib/sup/textfield.rb +38 -1
- data/lib/sup/thread.rb +1 -1
- data/lib/sup/time.rb +83 -0
- data/lib/sup/util.rb +38 -74
- data/lib/sup/version.rb +3 -0
- metadata +333 -168
- metadata.gz.sig +0 -0
- data/README.txt +0 -128
- data/bin/sup-cmd +0 -138
- data/bin/sup-server +0 -44
- data/lib/sup/client.rb +0 -92
- data/lib/sup/protocol.rb +0 -161
- data/lib/sup/server.rb +0 -116
metadata.gz.sig
ADDED
Binary file
|
data/README.txt
DELETED
@@ -1,128 +0,0 @@
|
|
1
|
-
sup
|
2
|
-
by William Morgan <wmorgan-sup@masanjin.net>
|
3
|
-
http://sup.rubyforge.org
|
4
|
-
|
5
|
-
== DESCRIPTION:
|
6
|
-
|
7
|
-
Sup is a console-based email client for people with a lot of email.
|
8
|
-
It supports tagging, very fast full-text search, automatic contact-
|
9
|
-
list management, and more. If you're the type of person who treats
|
10
|
-
email as an extension of your long-term memory, Sup is for you.
|
11
|
-
|
12
|
-
Sup makes it easy to:
|
13
|
-
- Handle massive amounts of email.
|
14
|
-
|
15
|
-
- Mix email from different sources: mbox files and Maildirs.
|
16
|
-
|
17
|
-
- Instantaneously search over your entire email collection. Search over
|
18
|
-
body text, or use a query language to combine search predicates in any
|
19
|
-
way.
|
20
|
-
|
21
|
-
- Handle multiple accounts. Replying to email sent to a particular
|
22
|
-
account will use the correct SMTP server, signature, and from address.
|
23
|
-
|
24
|
-
- Add custom code to customize Sup to whatever particular and bizarre
|
25
|
-
needs you may have.
|
26
|
-
|
27
|
-
- Organize email with user-defined labels, automatically track recent
|
28
|
-
contacts, and much more!
|
29
|
-
|
30
|
-
The goal of Sup is to become the email client of choice for nerds
|
31
|
-
everywhere.
|
32
|
-
|
33
|
-
== FEATURES/PROBLEMS:
|
34
|
-
|
35
|
-
Features:
|
36
|
-
|
37
|
-
- Scalability to massive amounts of email. Immediate startup and
|
38
|
-
operability, regardless of how much amount of email you have.
|
39
|
-
|
40
|
-
- Immediate full-text search of your entire email archive, using the
|
41
|
-
Xapian query language. Search over message bodies, labels, from: and
|
42
|
-
to: fields, or any combination thereof.
|
43
|
-
|
44
|
-
- Thread-centrism. Operations are performed at the thread, not the
|
45
|
-
message level. Entire threads are manipulated and viewed (with
|
46
|
-
redundancies removed) at a time.
|
47
|
-
|
48
|
-
- Labels instead of folders. Drop that tired old metaphor and you'll see
|
49
|
-
how much easier it is to organize email.
|
50
|
-
|
51
|
-
- GMail-style thread management. Archive a thread, and it will disappear
|
52
|
-
from your inbox until someone replies. Kill a thread, and it will
|
53
|
-
never come back to your inbox (but will still show up in searches.)
|
54
|
-
Mark a thread as spam and you'll never again see it unless explicitly
|
55
|
-
searching for spam.
|
56
|
-
|
57
|
-
- Console based interface. No mouse clicking required!
|
58
|
-
|
59
|
-
- Programmability. It's in Ruby. The code is good. It has an extensive
|
60
|
-
hook system that makes it easy to extend and customize.
|
61
|
-
|
62
|
-
- Multiple buffer support. Why be limited to viewing one thing at a
|
63
|
-
time?
|
64
|
-
|
65
|
-
- Tons of other little features, like automatic context-sensitive help,
|
66
|
-
multi-message operations, MIME attachment viewing, recent contact list
|
67
|
-
generation, etc.
|
68
|
-
|
69
|
-
Current limitations which will be fixed:
|
70
|
-
|
71
|
-
- Sup doesn't play nicely with other mail clients. If you alter a mail
|
72
|
-
source (read, move, delete, etc) with another client Sup will punish
|
73
|
-
you with a lengthy reindexing process.
|
74
|
-
|
75
|
-
- Unix-centrism in MIME attachment handling and in sendmail invocation.
|
76
|
-
|
77
|
-
== SYNOPSYS:
|
78
|
-
|
79
|
-
0. sup-config
|
80
|
-
1. sup
|
81
|
-
|
82
|
-
Note that Sup never changes the contents of any mailboxes; it only
|
83
|
-
indexes in to them. So it shouldn't ever corrupt your mail. The flip
|
84
|
-
side is that if you change a mailbox (e.g. delete messages, or, in the
|
85
|
-
case of mbox files, read an unread message) then Sup will be unable to
|
86
|
-
load messages from that source and will ask you to run sup-sync
|
87
|
-
--changed.
|
88
|
-
|
89
|
-
== REQUIREMENTS:
|
90
|
-
|
91
|
-
- xapian-full >= 1.1.3.2
|
92
|
-
- ncurses >= 0.9.1
|
93
|
-
- rmail >= 0.17
|
94
|
-
- highline
|
95
|
-
- net-ssh
|
96
|
-
- trollop >= 1.12
|
97
|
-
- lockfile
|
98
|
-
- mime-types
|
99
|
-
- gettext
|
100
|
-
- fastthread
|
101
|
-
|
102
|
-
== INSTALL:
|
103
|
-
|
104
|
-
* gem install sup
|
105
|
-
|
106
|
-
== PROBLEMS:
|
107
|
-
|
108
|
-
See FAQ.txt for some common problems and their solutions.
|
109
|
-
|
110
|
-
== LICENSE:
|
111
|
-
|
112
|
-
Copyright (c) 2006--2009 William Morgan.
|
113
|
-
|
114
|
-
This program is free software; you can redistribute it and/or
|
115
|
-
modify it under the terms of the GNU General Public License
|
116
|
-
as published by the Free Software Foundation; either version 2
|
117
|
-
of the License, or (at your option) any later version.
|
118
|
-
|
119
|
-
This program is distributed in the hope that it will be useful,
|
120
|
-
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
121
|
-
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
122
|
-
GNU General Public License for more details.
|
123
|
-
|
124
|
-
You should have received a copy of the GNU General Public License
|
125
|
-
along with this program; if not, write to the Free Software
|
126
|
-
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
127
|
-
02110-1301, USA.
|
128
|
-
|
data/bin/sup-cmd
DELETED
@@ -1,138 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
require 'rubygems'
|
3
|
-
require 'trollop'
|
4
|
-
require 'sup'
|
5
|
-
require 'sup/client'
|
6
|
-
require 'pp'
|
7
|
-
require 'yaml'
|
8
|
-
include Redwood
|
9
|
-
|
10
|
-
SUB_COMMANDS = %w(query count label add)
|
11
|
-
global_opts = Trollop::options do
|
12
|
-
#version = "sup-cmd (sup #{Redwood::VERSION})"
|
13
|
-
banner <<EOS
|
14
|
-
Connect to a running sup-server.
|
15
|
-
|
16
|
-
Usage:
|
17
|
-
sup-cmd [global options] command [options]
|
18
|
-
|
19
|
-
Valid commands: #{SUB_COMMANDS * ', '}
|
20
|
-
|
21
|
-
Global options:
|
22
|
-
EOS
|
23
|
-
|
24
|
-
opt :host, "server address", :type => :string, :default => 'localhost', :short => 'o'
|
25
|
-
opt :port, "server port", :type => :int, :default => 4300
|
26
|
-
opt :socket, "unix domain socket path", :type => :string, :default => nil
|
27
|
-
opt :verbose
|
28
|
-
|
29
|
-
conflicts :host, :socket
|
30
|
-
conflicts :port, :socket
|
31
|
-
|
32
|
-
stop_on SUB_COMMANDS
|
33
|
-
end
|
34
|
-
|
35
|
-
cmd = ARGV.shift
|
36
|
-
cmd_opts = case cmd
|
37
|
-
when "query"
|
38
|
-
Trollop.options do
|
39
|
-
opt :offset, "Offset", :default => 0, :type => :int
|
40
|
-
opt :limit, "Limit", :type => :int
|
41
|
-
opt :raw, "Retrieve raw message text", :default => false
|
42
|
-
end
|
43
|
-
when "count"
|
44
|
-
Trollop.options do
|
45
|
-
end
|
46
|
-
when "label"
|
47
|
-
Trollop.options do
|
48
|
-
opt :add_labels, "Labels to add", :default => ""
|
49
|
-
opt :remove_labels, "Labels to remove", :default => ""
|
50
|
-
end
|
51
|
-
when "add"
|
52
|
-
Trollop.options do
|
53
|
-
opt :labels, "Labels separated by commas", :default => ""
|
54
|
-
opt :mbox, "Treat input files as mboxes", :default => false
|
55
|
-
end
|
56
|
-
else
|
57
|
-
Trollop::die "unrecognized command #{cmd.inspect}"
|
58
|
-
end
|
59
|
-
|
60
|
-
class SupCmd < Redwood::Client
|
61
|
-
def initialize cmd, args, opts
|
62
|
-
@cmd = cmd
|
63
|
-
@opts = opts
|
64
|
-
@args = args
|
65
|
-
super()
|
66
|
-
end
|
67
|
-
|
68
|
-
def get_query
|
69
|
-
@args.first or fail "query argument required"
|
70
|
-
end
|
71
|
-
|
72
|
-
def connection_established
|
73
|
-
case @cmd
|
74
|
-
when "query"
|
75
|
-
query get_query, @opts[:offset], @opts[:limit], @opts[:raw] do |result|
|
76
|
-
if result
|
77
|
-
puts YAML.dump(result['summary'])
|
78
|
-
puts YAML.dump(result['raw']) if @opts[:raw]
|
79
|
-
else
|
80
|
-
close_connection
|
81
|
-
end
|
82
|
-
end
|
83
|
-
when "count"
|
84
|
-
count(get_query) do |x|
|
85
|
-
puts x
|
86
|
-
close_connection
|
87
|
-
end
|
88
|
-
when "label"
|
89
|
-
label get_query, @opts[:remove_labels].split(','), @opts[:add_labels].split(',') do
|
90
|
-
close_connection
|
91
|
-
end
|
92
|
-
when "add"
|
93
|
-
ARGF.binmode
|
94
|
-
labels = @opts[:labels].split(',')
|
95
|
-
get_message = lambda do
|
96
|
-
return ARGF.gets(nil) unless @opts[:mbox]
|
97
|
-
str = ""
|
98
|
-
l = ARGF.gets
|
99
|
-
str << l until ARGF.closed? || ARGF.eof? || MBox::is_break_line?(l = ARGF.gets)
|
100
|
-
str.empty? ? nil : str
|
101
|
-
end
|
102
|
-
i_s = i = 0
|
103
|
-
t = Time.now
|
104
|
-
while raw = get_message[]
|
105
|
-
i += 1
|
106
|
-
t_d = Time.now - t
|
107
|
-
if t_d >= 5
|
108
|
-
i_d = i - i_s
|
109
|
-
puts "indexed #{i} messages (#{i_d/t_d} m/s)" if global_opts[:verbose]
|
110
|
-
t = Time.now
|
111
|
-
i_s = i
|
112
|
-
end
|
113
|
-
add raw, labels do
|
114
|
-
close_connection
|
115
|
-
end
|
116
|
-
end
|
117
|
-
else
|
118
|
-
fail "#{@cmd} command unimplemented"
|
119
|
-
close_connection
|
120
|
-
end
|
121
|
-
end
|
122
|
-
|
123
|
-
def unbind
|
124
|
-
EM.stop
|
125
|
-
end
|
126
|
-
end
|
127
|
-
|
128
|
-
|
129
|
-
EM.run do
|
130
|
-
if global_opts[:socket]
|
131
|
-
EM.connect global_opts[:socket], SupCmd, cmd, ARGV, cmd_opts.merge(global_opts)
|
132
|
-
else
|
133
|
-
EM.connect global_opts[:host], global_opts[:port], SupCmd, cmd, ARGV, cmd_opts.merge(global_opts)
|
134
|
-
end
|
135
|
-
end
|
136
|
-
|
137
|
-
exit 0
|
138
|
-
|
data/bin/sup-server
DELETED
@@ -1,44 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
require 'rubygems'
|
3
|
-
require 'trollop'
|
4
|
-
require 'sup'
|
5
|
-
require 'sup/server'
|
6
|
-
require 'pp'
|
7
|
-
require 'yaml'
|
8
|
-
include Redwood
|
9
|
-
|
10
|
-
global_opts = Trollop::options do
|
11
|
-
#version = "sup-cmd (sup #{Redwood::VERSION})"
|
12
|
-
banner <<EOS
|
13
|
-
Interact with a Sup index.
|
14
|
-
|
15
|
-
Usage:
|
16
|
-
sup-server [options]
|
17
|
-
EOS
|
18
|
-
|
19
|
-
opt :host, "address to listen on", :type => :string, :default => 'localhost', :short => 'o'
|
20
|
-
opt :port, "port to listen on", :type => :int, :default => 4300
|
21
|
-
opt :verbose
|
22
|
-
end
|
23
|
-
|
24
|
-
Redwood.start
|
25
|
-
Index.init
|
26
|
-
Index.lock_interactively or exit
|
27
|
-
begin
|
28
|
-
if(s = Redwood::SourceManager.source_for SentManager.source_uri)
|
29
|
-
SentManager.source = s
|
30
|
-
else
|
31
|
-
Redwood::SourceManager.add_source SentManager.default_source
|
32
|
-
end
|
33
|
-
|
34
|
-
Index.load
|
35
|
-
|
36
|
-
EM.run do
|
37
|
-
EM.start_server global_opts[:host], global_opts[:port],
|
38
|
-
Redwood::Server, Index.instance
|
39
|
-
EM.next_tick { puts "ready" }
|
40
|
-
end
|
41
|
-
|
42
|
-
ensure
|
43
|
-
Index.unlock
|
44
|
-
end
|
data/lib/sup/client.rb
DELETED
@@ -1,92 +0,0 @@
|
|
1
|
-
require 'sup/protocol'
|
2
|
-
|
3
|
-
module Redwood
|
4
|
-
|
5
|
-
class Client < EM::P::RedwoodClient
|
6
|
-
def initialize *a
|
7
|
-
@next_tag = 1
|
8
|
-
@cbs = {}
|
9
|
-
super *a
|
10
|
-
end
|
11
|
-
|
12
|
-
def mktag &b
|
13
|
-
@next_tag.tap do |x|
|
14
|
-
@cbs[x] = b
|
15
|
-
@next_tag += 1
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
def rmtag tag
|
20
|
-
@cbs.delete tag
|
21
|
-
end
|
22
|
-
|
23
|
-
def query qstr, offset, limit, raw, &b
|
24
|
-
tag = mktag do |type,tag,args|
|
25
|
-
if type == 'message'
|
26
|
-
b.call args
|
27
|
-
else
|
28
|
-
fail unless type == 'done'
|
29
|
-
b.call nil
|
30
|
-
rmtag tag
|
31
|
-
end
|
32
|
-
end
|
33
|
-
send_message 'query', tag,
|
34
|
-
'query' => qstr,
|
35
|
-
'offset' => offset,
|
36
|
-
'limit' => limit,
|
37
|
-
'raw' => raw
|
38
|
-
end
|
39
|
-
|
40
|
-
def count qstr, &b
|
41
|
-
tag = mktag do |type,tag,args|
|
42
|
-
b.call args['count']
|
43
|
-
rmtag tag
|
44
|
-
end
|
45
|
-
send_message 'count', tag,
|
46
|
-
'query' => qstr
|
47
|
-
end
|
48
|
-
|
49
|
-
def label qstr, add, remove, &b
|
50
|
-
tag = mktag do |type,tag,args|
|
51
|
-
b.call
|
52
|
-
rmtag tag
|
53
|
-
end
|
54
|
-
send_message 'label', tag,
|
55
|
-
'query' => qstr,
|
56
|
-
'add' => add,
|
57
|
-
'remove' => remove
|
58
|
-
end
|
59
|
-
|
60
|
-
def add raw, labels, &b
|
61
|
-
tag = mktag do |type,tag,args|
|
62
|
-
b.call
|
63
|
-
rmtag tag
|
64
|
-
end
|
65
|
-
send_message 'add', tag,
|
66
|
-
'raw' => raw,
|
67
|
-
'labels' => labels
|
68
|
-
end
|
69
|
-
|
70
|
-
def thread msg_id, raw, &b
|
71
|
-
tag = mktag do |type,tag,args|
|
72
|
-
if type == 'message'
|
73
|
-
b.call args
|
74
|
-
else
|
75
|
-
fail unless type == 'done'
|
76
|
-
b.call nil
|
77
|
-
rmtag tag
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
send_message 'thread', tag,
|
82
|
-
'message_id' => msg_id,
|
83
|
-
'raw' => raw
|
84
|
-
end
|
85
|
-
|
86
|
-
def receive_message type, tag, args
|
87
|
-
cb = @cbs[tag] or fail "invalid tag #{tag.inspect}"
|
88
|
-
cb[type, tag, args]
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
|
-
end
|
data/lib/sup/protocol.rb
DELETED
@@ -1,161 +0,0 @@
|
|
1
|
-
require 'eventmachine'
|
2
|
-
require 'socket'
|
3
|
-
require 'stringio'
|
4
|
-
require 'yajl'
|
5
|
-
|
6
|
-
class EM::P::Redwood < EM::Connection
|
7
|
-
VERSION = 1
|
8
|
-
ENCODINGS = %w(marshal json)
|
9
|
-
|
10
|
-
attr_reader :debug
|
11
|
-
|
12
|
-
def initialize *args
|
13
|
-
@state = :negotiating
|
14
|
-
@version_buf = ""
|
15
|
-
@debug = false
|
16
|
-
super
|
17
|
-
end
|
18
|
-
|
19
|
-
def receive_data data
|
20
|
-
if @state == :negotiating
|
21
|
-
@version_buf << data
|
22
|
-
if i = @version_buf.index("\n")
|
23
|
-
l = @version_buf.slice!(0..i)
|
24
|
-
receive_version *parse_version(l.strip)
|
25
|
-
x = @version_buf
|
26
|
-
@version_buf = nil
|
27
|
-
@state = :established
|
28
|
-
connection_established
|
29
|
-
receive_data x
|
30
|
-
end
|
31
|
-
else
|
32
|
-
@filter.decode(data).each do |msg|
|
33
|
-
puts "#{self.class.name} received: #{msg.inspect}" if @debug
|
34
|
-
validate_message *msg
|
35
|
-
receive_message *msg
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
def connection_established
|
41
|
-
end
|
42
|
-
|
43
|
-
def send_version encodings, extensions
|
44
|
-
fail if encodings.empty?
|
45
|
-
send_data "Redwood #{VERSION} #{encodings * ','} #{extensions.empty? ? :none : (extensions * ',')}\n"
|
46
|
-
end
|
47
|
-
|
48
|
-
def send_message type, tag, params={}
|
49
|
-
fail "attempted to send message during negotiation" unless @state == :established
|
50
|
-
puts "#{self.class.name} sent: #{[type, tag, params].inspect}" if @debug
|
51
|
-
validate_message type, tag, params
|
52
|
-
send_data @filter.encode([type,tag,params])
|
53
|
-
end
|
54
|
-
|
55
|
-
def receive_version l
|
56
|
-
fail "unimplemented"
|
57
|
-
end
|
58
|
-
|
59
|
-
def receive_message type, tag, params
|
60
|
-
fail "unimplemented"
|
61
|
-
end
|
62
|
-
|
63
|
-
private
|
64
|
-
|
65
|
-
def validate_message type, tag, params
|
66
|
-
fail unless type.is_a? String or type.is_a? Symbol
|
67
|
-
fail unless tag.is_a? String or tag.is_a? Integer
|
68
|
-
fail unless params.is_a? Hash
|
69
|
-
end
|
70
|
-
|
71
|
-
def parse_version l
|
72
|
-
l =~ /^Redwood\s+(\d+)\s+([\w,]+)\s+([\w,]+)$/ or fail "unexpected banner #{l.inspect}"
|
73
|
-
version, encodings, extensions = $1.to_i, $2, $3
|
74
|
-
encodings = encodings.split ','
|
75
|
-
extensions = extensions.split ','
|
76
|
-
extensions = [] if extensions == ['none']
|
77
|
-
fail unless version == VERSION
|
78
|
-
fail if encodings.empty?
|
79
|
-
[encodings, extensions]
|
80
|
-
end
|
81
|
-
|
82
|
-
def create_filter encoding
|
83
|
-
case encoding
|
84
|
-
when 'json' then JSONFilter.new
|
85
|
-
when 'marshal' then MarshalFilter.new
|
86
|
-
else fail "unknown encoding #{encoding.inspect}"
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
class JSONFilter
|
91
|
-
def initialize
|
92
|
-
@parser = Yajl::Parser.new :check_utf8 => false
|
93
|
-
end
|
94
|
-
|
95
|
-
def decode chunk
|
96
|
-
parsed = []
|
97
|
-
@parser.on_parse_complete = lambda { |o| parsed << o }
|
98
|
-
@parser << chunk
|
99
|
-
parsed
|
100
|
-
end
|
101
|
-
|
102
|
-
def encode *os
|
103
|
-
os.inject('') { |s, o| s << Yajl::Encoder.encode(o) }
|
104
|
-
end
|
105
|
-
end
|
106
|
-
|
107
|
-
class MarshalFilter
|
108
|
-
def initialize
|
109
|
-
@buf = ''
|
110
|
-
@state = :prefix
|
111
|
-
@size = 0
|
112
|
-
end
|
113
|
-
|
114
|
-
def decode chunk
|
115
|
-
received = []
|
116
|
-
@buf << chunk
|
117
|
-
|
118
|
-
begin
|
119
|
-
if @state == :prefix
|
120
|
-
break unless @buf.size >= 4
|
121
|
-
prefix = @buf.slice!(0...4)
|
122
|
-
@size = prefix.unpack('N')[0]
|
123
|
-
@state = :data
|
124
|
-
end
|
125
|
-
|
126
|
-
fail unless @state == :data
|
127
|
-
break if @buf.size < @size
|
128
|
-
received << Marshal.load(@buf.slice!(0...@size))
|
129
|
-
@state = :prefix
|
130
|
-
end until @buf.empty?
|
131
|
-
|
132
|
-
received
|
133
|
-
end
|
134
|
-
|
135
|
-
def encode o
|
136
|
-
data = Marshal.dump o
|
137
|
-
[data.size].pack('N') + data
|
138
|
-
end
|
139
|
-
end
|
140
|
-
end
|
141
|
-
|
142
|
-
class EM::P::RedwoodServer < EM::P::Redwood
|
143
|
-
def post_init
|
144
|
-
send_version ENCODINGS, []
|
145
|
-
end
|
146
|
-
|
147
|
-
def receive_version encodings, extensions
|
148
|
-
fail unless encodings.size == 1
|
149
|
-
fail unless ENCODINGS.member? encodings.first
|
150
|
-
@filter = create_filter encodings.first
|
151
|
-
end
|
152
|
-
end
|
153
|
-
|
154
|
-
class EM::P::RedwoodClient < EM::P::Redwood
|
155
|
-
def receive_version encodings, extensions
|
156
|
-
encoding = (ENCODINGS & encodings).first
|
157
|
-
fail unless encoding
|
158
|
-
@filter = create_filter encoding
|
159
|
-
send_version [encoding], []
|
160
|
-
end
|
161
|
-
end
|