torchat 0.0.1.rc.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 +43 -0
- data/bin/torchatd +537 -0
- data/doc/protocol/broadcast.md +26 -0
- data/doc/protocol/groupchat.md +140 -0
- data/doc/protocol/latency.md +30 -0
- data/doc/protocol/standard.md +279 -0
- data/doc/protocol/typing.md +41 -0
- data/etc/torchat.yml +12 -0
- data/lib/torchat.rb +239 -0
- data/lib/torchat/protocol.rb +256 -0
- data/lib/torchat/protocol/broadcast.rb +40 -0
- data/lib/torchat/protocol/groupchat.rb +197 -0
- data/lib/torchat/protocol/latency.rb +44 -0
- data/lib/torchat/protocol/standard.rb +367 -0
- data/lib/torchat/protocol/typing.rb +36 -0
- data/lib/torchat/session.rb +603 -0
- data/lib/torchat/session/broadcast/message.rb +50 -0
- data/lib/torchat/session/broadcasts.rb +72 -0
- data/lib/torchat/session/buddies.rb +152 -0
- data/lib/torchat/session/buddy.rb +343 -0
- data/lib/torchat/session/buddy/joined_group_chat.rb +42 -0
- data/lib/torchat/session/buddy/joined_group_chats.rb +46 -0
- data/lib/torchat/session/buddy/latency.rb +54 -0
- data/lib/torchat/session/event.rb +79 -0
- data/lib/torchat/session/file_transfer.rb +173 -0
- data/lib/torchat/session/file_transfer/block.rb +51 -0
- data/lib/torchat/session/file_transfers.rb +89 -0
- data/lib/torchat/session/group_chat.rb +123 -0
- data/lib/torchat/session/group_chat/participant.rb +38 -0
- data/lib/torchat/session/group_chat/participants.rb +52 -0
- data/lib/torchat/session/group_chats.rb +74 -0
- data/lib/torchat/session/incoming.rb +187 -0
- data/lib/torchat/session/outgoing.rb +102 -0
- data/lib/torchat/tor.rb +107 -0
- data/lib/torchat/utils.rb +87 -0
- data/lib/torchat/version.rb +24 -0
- data/test/file_transfer/receiver.rb +41 -0
- data/test/file_transfer/sender.rb +45 -0
- data/test/group_chat/a.rb +37 -0
- data/test/group_chat/b.rb +37 -0
- data/test/group_chat/c.rb +57 -0
- data/torchat.gemspec +21 -0
- metadata +140 -0
@@ -0,0 +1,42 @@
|
|
1
|
+
#--
|
2
|
+
# Copyleft meh. [http://meh.paranoid.pk | meh@paranoici.org]
|
3
|
+
#
|
4
|
+
# This file is part of torchat for ruby.
|
5
|
+
#
|
6
|
+
# torchat for ruby is free software: you can redistribute it and/or modify
|
7
|
+
# it under the terms of the GNU Affero General Public License as published
|
8
|
+
# by the Free Software Foundation, either version 3 of the License, or
|
9
|
+
# (at your option) any later version.
|
10
|
+
#
|
11
|
+
# torchat for ruby is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
+
# GNU Affero General Public License for more details.
|
15
|
+
#
|
16
|
+
# You should have received a copy of the GNU Affero General Public License
|
17
|
+
# along with torchat for ruby. If not, see <http://www.gnu.org/licenses/>.
|
18
|
+
#++
|
19
|
+
|
20
|
+
require 'delegate'
|
21
|
+
|
22
|
+
require 'torchat/session/group_chat'
|
23
|
+
|
24
|
+
class Torchat; class Session; class Buddy
|
25
|
+
|
26
|
+
class JoinedGroupChat < DelegateClass(GroupChat)
|
27
|
+
def initialize (group_chat, buddy)
|
28
|
+
super(group_chat)
|
29
|
+
|
30
|
+
@buddy = buddy
|
31
|
+
end
|
32
|
+
|
33
|
+
def leave (reason = nil)
|
34
|
+
delete(@buddy)
|
35
|
+
|
36
|
+
session.fire :group_chat_leave, group_chat: group_chat, buddy: @buddy, reason: reason
|
37
|
+
end
|
38
|
+
|
39
|
+
alias ~ __getobj__
|
40
|
+
end
|
41
|
+
|
42
|
+
end; end; end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
#--
|
2
|
+
# Copyleft meh. [http://meh.paranoid.pk | meh@paranoici.org]
|
3
|
+
#
|
4
|
+
# This file is part of torchat for ruby.
|
5
|
+
#
|
6
|
+
# torchat for ruby is free software: you can redistribute it and/or modify
|
7
|
+
# it under the terms of the GNU Affero General Public License as published
|
8
|
+
# by the Free Software Foundation, either version 3 of the License, or
|
9
|
+
# (at your option) any later version.
|
10
|
+
#
|
11
|
+
# torchat for ruby is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
+
# GNU Affero General Public License for more details.
|
15
|
+
#
|
16
|
+
# You should have received a copy of the GNU Affero General Public License
|
17
|
+
# along with torchat for ruby. If not, see <http://www.gnu.org/licenses/>.
|
18
|
+
#++
|
19
|
+
|
20
|
+
require 'torchat/session/buddy/joined_group_chat'
|
21
|
+
|
22
|
+
class Torchat; class Session; class Buddy
|
23
|
+
|
24
|
+
class JoinedGroupChats < Hash
|
25
|
+
attr_reader :buddy
|
26
|
+
|
27
|
+
def initialize (buddy)
|
28
|
+
@buddy = buddy
|
29
|
+
end
|
30
|
+
|
31
|
+
def add (id)
|
32
|
+
group_chat = id.is_a?(GroupChat) ? id : buddy.session.group_chats[id]
|
33
|
+
|
34
|
+
if group_chat
|
35
|
+
self[group_chat.id] = JoinedGroupChat.new(group_chat, buddy)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def delete (id)
|
40
|
+
super(id.respond_to?(:id) ? id.id : id)
|
41
|
+
end
|
42
|
+
|
43
|
+
private :[]=
|
44
|
+
end
|
45
|
+
|
46
|
+
end; end; end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
#--
|
2
|
+
# Copyleft meh. [http://meh.paranoid.pk | meh@paranoici.org]
|
3
|
+
#
|
4
|
+
# This file is part of torchat for ruby.
|
5
|
+
#
|
6
|
+
# torchat for ruby is free software: you can redistribute it and/or modify
|
7
|
+
# it under the terms of the GNU Affero General Public License as published
|
8
|
+
# by the Free Software Foundation, either version 3 of the License, or
|
9
|
+
# (at your option) any later version.
|
10
|
+
#
|
11
|
+
# torchat for ruby is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
+
# GNU Affero General Public License for more details.
|
15
|
+
#
|
16
|
+
# You should have received a copy of the GNU Affero General Public License
|
17
|
+
# along with torchat for ruby. If not, see <http://www.gnu.org/licenses/>.
|
18
|
+
#++
|
19
|
+
|
20
|
+
class Torchat; class Session; class Buddy
|
21
|
+
|
22
|
+
class Latency
|
23
|
+
attr_reader :buddy
|
24
|
+
|
25
|
+
def initialize (buddy)
|
26
|
+
@buddy = buddy
|
27
|
+
end
|
28
|
+
|
29
|
+
def ping!
|
30
|
+
@last_check = buddy.send_packet [:latency, :ping]
|
31
|
+
end
|
32
|
+
|
33
|
+
def pong (id)
|
34
|
+
return unless id == @last_check.id
|
35
|
+
|
36
|
+
@internal = Time.now - @last_check.at
|
37
|
+
end
|
38
|
+
|
39
|
+
def to_f
|
40
|
+
unless @internal
|
41
|
+
ping! unless @last_check
|
42
|
+
|
43
|
+
return 0
|
44
|
+
end
|
45
|
+
|
46
|
+
@internal
|
47
|
+
end
|
48
|
+
|
49
|
+
def to_i
|
50
|
+
to_f.to_i
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
end; end; end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
#--
|
2
|
+
# Copyleft meh. [http://meh.paranoid.pk | meh@paranoici.org]
|
3
|
+
#
|
4
|
+
# This file is part of torchat for ruby.
|
5
|
+
#
|
6
|
+
# torchat for ruby is free software: you can redistribute it and/or modify
|
7
|
+
# it under the terms of the GNU Affero General Public License as published
|
8
|
+
# by the Free Software Foundation, either version 3 of the License, or
|
9
|
+
# (at your option) any later version.
|
10
|
+
#
|
11
|
+
# torchat for ruby is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
+
# GNU Affero General Public License for more details.
|
15
|
+
#
|
16
|
+
# You should have received a copy of the GNU Affero General Public License
|
17
|
+
# along with torchat for ruby. If not, see <http://www.gnu.org/licenses/>.
|
18
|
+
#++
|
19
|
+
|
20
|
+
require 'ostruct'
|
21
|
+
|
22
|
+
class Torchat; class Session
|
23
|
+
|
24
|
+
class Event
|
25
|
+
class Removable
|
26
|
+
attr_reader :session, :name, :chain, :block
|
27
|
+
|
28
|
+
def initialize (session, name, chain = nil, &block)
|
29
|
+
@session = session
|
30
|
+
@name = name
|
31
|
+
@chain = chain
|
32
|
+
@block = block
|
33
|
+
end
|
34
|
+
|
35
|
+
def removed?; @removed; end
|
36
|
+
|
37
|
+
def remove!
|
38
|
+
return if removed?
|
39
|
+
|
40
|
+
@removed = true
|
41
|
+
|
42
|
+
session.remove_callback(chain, name, block)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
attr_reader :session, :name
|
47
|
+
|
48
|
+
def initialize (session, name, data = nil, &block)
|
49
|
+
@session = session
|
50
|
+
@name = name
|
51
|
+
|
52
|
+
@data = OpenStruct.new(data).tap(&block || proc {}).marshal_dump
|
53
|
+
end
|
54
|
+
|
55
|
+
def method_missing (id, *args)
|
56
|
+
unless args.empty?
|
57
|
+
raise ArgumentError, 'tried to pass parameters to an Event attribute'
|
58
|
+
end
|
59
|
+
|
60
|
+
@data[id] if @data.has_key? id
|
61
|
+
end
|
62
|
+
|
63
|
+
def respond_to_missing? (*)
|
64
|
+
true
|
65
|
+
end
|
66
|
+
|
67
|
+
def remove!; @remove = true; end
|
68
|
+
def removed!; @remove = false; end
|
69
|
+
def remove?; @remove; end
|
70
|
+
|
71
|
+
def stop!; @stop = true; end
|
72
|
+
def stopped?; @stop; end
|
73
|
+
|
74
|
+
def inspect
|
75
|
+
"#<Torchat::Event(#{name}): #{@data.inspect}>"
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
end; end
|
@@ -0,0 +1,173 @@
|
|
1
|
+
#--
|
2
|
+
# Copyleft meh. [http://meh.paranoid.pk | meh@paranoici.org]
|
3
|
+
#
|
4
|
+
# This file is part of torchat for ruby.
|
5
|
+
#
|
6
|
+
# torchat for ruby is free software: you can redistribute it and/or modify
|
7
|
+
# it under the terms of the GNU Affero General Public License as published
|
8
|
+
# by the Free Software Foundation, either version 3 of the License, or
|
9
|
+
# (at your option) any later version.
|
10
|
+
#
|
11
|
+
# torchat for ruby is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
+
# GNU Affero General Public License for more details.
|
15
|
+
#
|
16
|
+
# You should have received a copy of the GNU Affero General Public License
|
17
|
+
# along with torchat for ruby. If not, see <http://www.gnu.org/licenses/>.
|
18
|
+
#++
|
19
|
+
|
20
|
+
require 'digest/md5'
|
21
|
+
require 'forwardable'
|
22
|
+
|
23
|
+
require 'torchat/session/file_transfer/block'
|
24
|
+
|
25
|
+
class Torchat
|
26
|
+
|
27
|
+
class FileTransfer
|
28
|
+
extend Forwardable
|
29
|
+
|
30
|
+
attr_reader :file_transfers, :id, :name, :size, :output, :input
|
31
|
+
attr_accessor :from, :to, :block_size
|
32
|
+
|
33
|
+
alias length size
|
34
|
+
|
35
|
+
def initialize (file_transfers = nil, name, size)
|
36
|
+
@file_transfers = file_transfers
|
37
|
+
@id = id || Torchat.new_cookie
|
38
|
+
@name = name
|
39
|
+
@size = size
|
40
|
+
@block_size = 4096
|
41
|
+
end
|
42
|
+
|
43
|
+
def outgoing?
|
44
|
+
!!to
|
45
|
+
end
|
46
|
+
|
47
|
+
def incoming?
|
48
|
+
!!from
|
49
|
+
end
|
50
|
+
|
51
|
+
def input= (io)
|
52
|
+
raise ArgumentError, 'you cannot change input' if @input && @input != io
|
53
|
+
|
54
|
+
@input = io
|
55
|
+
end
|
56
|
+
|
57
|
+
def output= (io)
|
58
|
+
raise ArgumentError, 'you cannot change output' if @output && @output != io
|
59
|
+
|
60
|
+
@output = io
|
61
|
+
|
62
|
+
@cache.each {|block|
|
63
|
+
output.seek(block.offset)
|
64
|
+
output.write(block.data)
|
65
|
+
}
|
66
|
+
|
67
|
+
@cache = nil
|
68
|
+
end
|
69
|
+
|
70
|
+
def tell
|
71
|
+
if @input
|
72
|
+
@input.tell
|
73
|
+
elsif @output
|
74
|
+
@output.size
|
75
|
+
elsif @cache
|
76
|
+
block = @cache.max { |a, b| a.offset <=> b.offset }
|
77
|
+
|
78
|
+
block.offset + block.size
|
79
|
+
else
|
80
|
+
0
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def completion
|
85
|
+
tell.to_f / size * 100
|
86
|
+
end
|
87
|
+
|
88
|
+
def finished?
|
89
|
+
io.size >= size
|
90
|
+
end
|
91
|
+
|
92
|
+
def add_block (offset, data, md5 = nil)
|
93
|
+
Block.new(self, offset, data, md5).tap {|block|
|
94
|
+
unless block.valid?
|
95
|
+
from.send_packet :filedata_error, id, offset
|
96
|
+
|
97
|
+
return false
|
98
|
+
end
|
99
|
+
|
100
|
+
if output
|
101
|
+
output.seek(offset)
|
102
|
+
output.write(data)
|
103
|
+
else
|
104
|
+
(@cache ||= []) << block
|
105
|
+
end
|
106
|
+
|
107
|
+
fire :file_transfer_activity, file_transfer: self
|
108
|
+
|
109
|
+
if completion == 100
|
110
|
+
fire :file_transfer_complete, file_transfer: self
|
111
|
+
end
|
112
|
+
}
|
113
|
+
end
|
114
|
+
|
115
|
+
def next_block
|
116
|
+
raise 'there is no input' unless input
|
117
|
+
|
118
|
+
return if input.tell >= input.size
|
119
|
+
|
120
|
+
@last = Block.new(self, input.tell, input.read(block_size))
|
121
|
+
end
|
122
|
+
|
123
|
+
def last_block
|
124
|
+
raise 'there is no input' unless input
|
125
|
+
|
126
|
+
@last = Block.new(self, input.tell, input.read(block_size))
|
127
|
+
end
|
128
|
+
|
129
|
+
def send_next_block
|
130
|
+
if block = next_block
|
131
|
+
to.send_packet :filedata, file_transfer.id, block.offset, block.data, block.md5
|
132
|
+
|
133
|
+
fire :file_transfer_activity, file_transfer: self
|
134
|
+
else
|
135
|
+
fire :file_transfer_complete, file_transfer: self
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
def send_last_block
|
140
|
+
if block = file_transfer.last_block
|
141
|
+
to.send_packet :filedata, file_transfer.id, block.offset, block.data, block.md5
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
def stopped?; @stopped; end
|
146
|
+
|
147
|
+
def stop (interrupted_by_other = false)
|
148
|
+
unless interrupted_by_other
|
149
|
+
if incoming?
|
150
|
+
from.send_packet :file_stop_sending, id
|
151
|
+
elsif outgoing?
|
152
|
+
to.send_packet :file_stop_receiving, id
|
153
|
+
else
|
154
|
+
raise ArgumentError, 'the file transfer is unstoppable, call Denzel Washington'
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
@stopped = true
|
159
|
+
|
160
|
+
if file_transfers
|
161
|
+
file_transfers.delete(id)
|
162
|
+
file_transfers.session.fire :file_transfer_stop, file_transfer: self
|
163
|
+
end
|
164
|
+
|
165
|
+
self
|
166
|
+
end
|
167
|
+
|
168
|
+
def inspect
|
169
|
+
"#<Torchat::FileTransfer(#{id}): #{name} #{tell}/#{size} (#{'%.2f' % completion}%)>"
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
#--
|
2
|
+
# Copyleft meh. [http://meh.paranoid.pk | meh@paranoici.org]
|
3
|
+
#
|
4
|
+
# This file is part of torchat for ruby.
|
5
|
+
#
|
6
|
+
# torchat for ruby is free software: you can redistribute it and/or modify
|
7
|
+
# it under the terms of the GNU Affero General Public License as published
|
8
|
+
# by the Free Software Foundation, either version 3 of the License, or
|
9
|
+
# (at your option) any later version.
|
10
|
+
#
|
11
|
+
# torchat for ruby is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
+
# GNU Affero General Public License for more details.
|
15
|
+
#
|
16
|
+
# You should have received a copy of the GNU Affero General Public License
|
17
|
+
# along with torchat for ruby. If not, see <http://www.gnu.org/licenses/>.
|
18
|
+
#++
|
19
|
+
|
20
|
+
require 'digest/md5'
|
21
|
+
|
22
|
+
class Torchat; class FileTransfer
|
23
|
+
|
24
|
+
class Block
|
25
|
+
attr_reader :owner, :offset, :data, :md5
|
26
|
+
|
27
|
+
def initialize (owner, offset, data, md5 = nil)
|
28
|
+
@owner = owner
|
29
|
+
@offset = offset
|
30
|
+
@data = data.force_encoding('BINARY')
|
31
|
+
@md5 = md5 || Digest::MD5.hexdigest(data)
|
32
|
+
end
|
33
|
+
|
34
|
+
def size
|
35
|
+
@size || @data.bytesize
|
36
|
+
end
|
37
|
+
|
38
|
+
alias length size
|
39
|
+
|
40
|
+
def valid?
|
41
|
+
Digest::MD5.hexdigest(data) == md5
|
42
|
+
end
|
43
|
+
|
44
|
+
def to_s
|
45
|
+
@data
|
46
|
+
end
|
47
|
+
|
48
|
+
alias to_str to_s
|
49
|
+
end
|
50
|
+
|
51
|
+
end; end
|