torchat 0.0.1.rc.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. data/README.md +43 -0
  2. data/bin/torchatd +537 -0
  3. data/doc/protocol/broadcast.md +26 -0
  4. data/doc/protocol/groupchat.md +140 -0
  5. data/doc/protocol/latency.md +30 -0
  6. data/doc/protocol/standard.md +279 -0
  7. data/doc/protocol/typing.md +41 -0
  8. data/etc/torchat.yml +12 -0
  9. data/lib/torchat.rb +239 -0
  10. data/lib/torchat/protocol.rb +256 -0
  11. data/lib/torchat/protocol/broadcast.rb +40 -0
  12. data/lib/torchat/protocol/groupchat.rb +197 -0
  13. data/lib/torchat/protocol/latency.rb +44 -0
  14. data/lib/torchat/protocol/standard.rb +367 -0
  15. data/lib/torchat/protocol/typing.rb +36 -0
  16. data/lib/torchat/session.rb +603 -0
  17. data/lib/torchat/session/broadcast/message.rb +50 -0
  18. data/lib/torchat/session/broadcasts.rb +72 -0
  19. data/lib/torchat/session/buddies.rb +152 -0
  20. data/lib/torchat/session/buddy.rb +343 -0
  21. data/lib/torchat/session/buddy/joined_group_chat.rb +42 -0
  22. data/lib/torchat/session/buddy/joined_group_chats.rb +46 -0
  23. data/lib/torchat/session/buddy/latency.rb +54 -0
  24. data/lib/torchat/session/event.rb +79 -0
  25. data/lib/torchat/session/file_transfer.rb +173 -0
  26. data/lib/torchat/session/file_transfer/block.rb +51 -0
  27. data/lib/torchat/session/file_transfers.rb +89 -0
  28. data/lib/torchat/session/group_chat.rb +123 -0
  29. data/lib/torchat/session/group_chat/participant.rb +38 -0
  30. data/lib/torchat/session/group_chat/participants.rb +52 -0
  31. data/lib/torchat/session/group_chats.rb +74 -0
  32. data/lib/torchat/session/incoming.rb +187 -0
  33. data/lib/torchat/session/outgoing.rb +102 -0
  34. data/lib/torchat/tor.rb +107 -0
  35. data/lib/torchat/utils.rb +87 -0
  36. data/lib/torchat/version.rb +24 -0
  37. data/test/file_transfer/receiver.rb +41 -0
  38. data/test/file_transfer/sender.rb +45 -0
  39. data/test/group_chat/a.rb +37 -0
  40. data/test/group_chat/b.rb +37 -0
  41. data/test/group_chat/c.rb +57 -0
  42. data/torchat.gemspec +21 -0
  43. 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