netz 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +3 -0
- data/README.rdoc +8 -0
- data/Rakefile +22 -0
- data/VERSION +1 -0
- data/lib/netz.rb +7 -0
- data/lib/netz/broadcaster.rb +31 -0
- data/lib/netz/catcher.rb +26 -0
- data/lib/netz/client.rb +137 -0
- data/lib/netz/command.rb +8 -0
- data/lib/netz/command_serializer.rb +13 -0
- data/lib/netz/safe_array.rb +43 -0
- data/netz.gemspec +63 -0
- data/script/run_client.rb +7 -0
- data/script/run_lobby.rb +9 -0
- metadata +135 -0
data/.gitignore
ADDED
data/README.rdoc
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
begin
|
2
|
+
require 'jeweler'
|
3
|
+
Jeweler::Tasks.new do |gem|
|
4
|
+
gem.name = "netz"
|
5
|
+
gem.rubyforge_project = "netz"
|
6
|
+
gem.summary = %Q{Networking library for use in games.}
|
7
|
+
gem.description = %Q{P2P Networking library for us in games. }
|
8
|
+
gem.email = "shawn42@gmail.com"
|
9
|
+
gem.homepage = "http://shawn42.github.com/netz"
|
10
|
+
gem.authors = ["Shawn Anderson"]
|
11
|
+
gem.add_development_dependency "rspec"
|
12
|
+
gem.add_development_dependency "jeweler"
|
13
|
+
gem.add_dependency 'gosu'
|
14
|
+
gem.add_dependency 'bundler'
|
15
|
+
gem.test_files = FileList['{spec,test}/**/*.rb']
|
16
|
+
end
|
17
|
+
Jeweler::GemcutterTasks.new
|
18
|
+
rescue LoadError
|
19
|
+
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
20
|
+
end
|
21
|
+
|
22
|
+
# vim: syntax=Ruby
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.1
|
data/lib/netz.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
module Netz
|
2
|
+
class Broadcaster
|
3
|
+
attr_accessor :remote_clients, :command_channel
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@remote_clients = []
|
7
|
+
end
|
8
|
+
|
9
|
+
def run
|
10
|
+
Thread.new do
|
11
|
+
loop do
|
12
|
+
command = @command_channel.pop
|
13
|
+
push_to_peers command if command.local?
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def push_to_peers(command)
|
19
|
+
# TODO add command buffering?
|
20
|
+
command.extend(CommandSerializer)
|
21
|
+
|
22
|
+
# write to clients
|
23
|
+
msg = command.serialize
|
24
|
+
puts msg
|
25
|
+
@remote_clients.each do |rc|
|
26
|
+
rc.write [msg.length].pack("S")
|
27
|
+
rc.write msg
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/lib/netz/catcher.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
module Netz
|
2
|
+
class Catcher
|
3
|
+
attr_accessor :remote_clients, :command_channel
|
4
|
+
|
5
|
+
def initialize()
|
6
|
+
@remote_clients = []
|
7
|
+
end
|
8
|
+
|
9
|
+
def run
|
10
|
+
#thread per client?
|
11
|
+
@remote_clients.each do |rc|
|
12
|
+
Thread.new do
|
13
|
+
loop do
|
14
|
+
read_command(rc)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def read_command(remote_client)
|
21
|
+
length = remote_client.recvfrom(2)[0].unpack("S")[0]
|
22
|
+
cmd = CommandSerializer.deserialize(remote_client.recvfrom(length))
|
23
|
+
@command_channel << cmd
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/lib/netz/client.rb
ADDED
@@ -0,0 +1,137 @@
|
|
1
|
+
|
2
|
+
module Netz
|
3
|
+
module ManagementCommands
|
4
|
+
PEER_CONNECT = 1
|
5
|
+
START = 2
|
6
|
+
end
|
7
|
+
|
8
|
+
class Client
|
9
|
+
include ManagementCommands
|
10
|
+
MANAGEMENT_PORT = 7370
|
11
|
+
INITIAL_PEER_PORT = 7374
|
12
|
+
def initialize
|
13
|
+
@port = INITIAL_PEER_PORT
|
14
|
+
@peers = SafeArray.new
|
15
|
+
Thread.new do
|
16
|
+
setup_management_port
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def start_all
|
21
|
+
setup_with_siblings
|
22
|
+
|
23
|
+
@peers.each do |peer_socket|
|
24
|
+
to_send_address = peer_socket.peeraddr[3].split(":").last
|
25
|
+
puts "STARTING... #{to_send_address}"
|
26
|
+
peer_mng_socket = TCPSocket.new to_send_address, MANAGEMENT_PORT
|
27
|
+
|
28
|
+
peer_mng_socket << [START].pack("C")
|
29
|
+
peer_mng_socket.close
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def add_peer(peer_socket)
|
34
|
+
@port += 1
|
35
|
+
Thread.new do
|
36
|
+
peer_server = TCPServer.open @port
|
37
|
+
puts "waiting for peer on per-peer port #{@port}"
|
38
|
+
peer = peer_server.accept
|
39
|
+
puts "accepted peer."
|
40
|
+
@peers.push(peer)
|
41
|
+
end
|
42
|
+
#push port, then ip strings
|
43
|
+
peer_socket << [@port].pack("I")
|
44
|
+
peer_socket << [@peers.size].pack("I")
|
45
|
+
@peers.each do |peer_socket|
|
46
|
+
# TODO will this always be peeraddr? or sometime addr depending on Server vs Socket?
|
47
|
+
to_send_address = peer_socket.peeraddr[3].split(":").last
|
48
|
+
peer_socket << [to_send_address.length].pack("I")
|
49
|
+
peer_socket << to_send_address
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def setup_with_siblings
|
54
|
+
puts "setting up siblings"
|
55
|
+
@channel = Queue.new
|
56
|
+
broadcaster = Broadcaster.new
|
57
|
+
broadcaster.command_channel = @channel
|
58
|
+
broadcaster.remote_clients = @peers
|
59
|
+
|
60
|
+
catcher = Catcher.new
|
61
|
+
catcher.command_channel = @channel
|
62
|
+
catcher.remote_clients = @peers
|
63
|
+
|
64
|
+
catcher.run
|
65
|
+
broadcaster.run
|
66
|
+
|
67
|
+
@channel.push Command.new
|
68
|
+
end
|
69
|
+
|
70
|
+
def setup_management_port
|
71
|
+
puts "creating management port on #{MANAGEMENT_PORT}"
|
72
|
+
begin
|
73
|
+
server = TCPServer.open MANAGEMENT_PORT
|
74
|
+
@management_accept_thread = Thread.new do
|
75
|
+
begin
|
76
|
+
loop do
|
77
|
+
puts "management thread trying to accept..."
|
78
|
+
peer = server.accept
|
79
|
+
puts "YAY! peer connected!"
|
80
|
+
|
81
|
+
cmd = peer.recvfrom(1)[0].unpack("C")[0].to_i
|
82
|
+
case cmd
|
83
|
+
when PEER_CONNECT
|
84
|
+
puts "connection from peer #{peer.inspect}"
|
85
|
+
add_peer peer
|
86
|
+
when START
|
87
|
+
puts "got start"
|
88
|
+
setup_with_siblings
|
89
|
+
else
|
90
|
+
puts "unknown cmd"
|
91
|
+
p cmd
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
rescue Exception => ex
|
98
|
+
puts "client failed to open management port: #{ex}"
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|
102
|
+
|
103
|
+
def connect_to_peer(ip, port)
|
104
|
+
puts "connecting to peer #{ip}:#{port}"
|
105
|
+
@peers << TCPSocket.new(ip, port)
|
106
|
+
end
|
107
|
+
|
108
|
+
def join(ip)
|
109
|
+
puts "trying to join #{ip}"
|
110
|
+
@joined_peer_ips ||= []
|
111
|
+
@joined_peer_ips << ip
|
112
|
+
peer_accept = TCPSocket.new ip, MANAGEMENT_PORT
|
113
|
+
peer_accept << [PEER_CONNECT].pack("C")
|
114
|
+
|
115
|
+
peer_ips = []
|
116
|
+
join_port = peer_accept.recvfrom(4)[0].unpack("I")[0]
|
117
|
+
puts "got join_port #{join_port}"
|
118
|
+
num_additional_peers = peer_accept.recvfrom(4)[0].unpack("I")[0]
|
119
|
+
puts "got num_additional_peers #{num_additional_peers}"
|
120
|
+
num_additional_peers.times do
|
121
|
+
puts "getting peer ip from stream"
|
122
|
+
ip_length = peer_accept.recvfrom(4)[0].unpack("I")
|
123
|
+
peer_ip = peer_accept.recvfrom(ip_length)[0].unpack("a")
|
124
|
+
peer_ips << peer_ip unless @joined_peer_ips.include? peer_ip
|
125
|
+
end
|
126
|
+
|
127
|
+
connect_to_peer ip, join_port
|
128
|
+
|
129
|
+
peer_accept.close
|
130
|
+
|
131
|
+
peer_ips.each do |pip|
|
132
|
+
join pip
|
133
|
+
end
|
134
|
+
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
data/lib/netz/command.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'thread'
|
2
|
+
module Netz
|
3
|
+
# a thread safe array class
|
4
|
+
class SafeArray
|
5
|
+
def initialize(items=[])
|
6
|
+
@items = items
|
7
|
+
@mutex = Mutex.new
|
8
|
+
end
|
9
|
+
|
10
|
+
def push(item)
|
11
|
+
@mutex.synchronize {
|
12
|
+
@items.push item
|
13
|
+
}
|
14
|
+
self
|
15
|
+
end
|
16
|
+
alias :<< :push
|
17
|
+
|
18
|
+
def delete(item)
|
19
|
+
@mutex.synchronize {
|
20
|
+
@items.delete item
|
21
|
+
}
|
22
|
+
end
|
23
|
+
|
24
|
+
def each(&block)
|
25
|
+
@mutex.synchronize {
|
26
|
+
@items.each(&block)
|
27
|
+
}
|
28
|
+
self
|
29
|
+
end
|
30
|
+
|
31
|
+
def empty?
|
32
|
+
@mutex.synchronize {
|
33
|
+
@items.empty?
|
34
|
+
}
|
35
|
+
end
|
36
|
+
|
37
|
+
def size
|
38
|
+
@mutex.synchronize {
|
39
|
+
@items.size
|
40
|
+
}
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
data/netz.gemspec
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{netz}
|
8
|
+
s.version = "0.0.1"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Shawn Anderson"]
|
12
|
+
s.date = %q{2010-10-27}
|
13
|
+
s.description = %q{P2P Networking library for us in games. }
|
14
|
+
s.email = %q{shawn42@gmail.com}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"README.rdoc"
|
17
|
+
]
|
18
|
+
s.files = [
|
19
|
+
".gitignore",
|
20
|
+
"README.rdoc",
|
21
|
+
"Rakefile",
|
22
|
+
"VERSION",
|
23
|
+
"lib/netz.rb",
|
24
|
+
"lib/netz/broadcaster.rb",
|
25
|
+
"lib/netz/catcher.rb",
|
26
|
+
"lib/netz/client.rb",
|
27
|
+
"lib/netz/command.rb",
|
28
|
+
"lib/netz/command_serializer.rb",
|
29
|
+
"lib/netz/safe_array.rb",
|
30
|
+
"netz.gemspec",
|
31
|
+
"script/run_client.rb",
|
32
|
+
"script/run_lobby.rb"
|
33
|
+
]
|
34
|
+
s.homepage = %q{http://shawn42.github.com/netz}
|
35
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
36
|
+
s.require_paths = ["lib"]
|
37
|
+
s.rubyforge_project = %q{netz}
|
38
|
+
s.rubygems_version = %q{1.3.7}
|
39
|
+
s.summary = %q{Networking library for use in games.}
|
40
|
+
|
41
|
+
if s.respond_to? :specification_version then
|
42
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
43
|
+
s.specification_version = 3
|
44
|
+
|
45
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
46
|
+
s.add_development_dependency(%q<rspec>, [">= 0"])
|
47
|
+
s.add_development_dependency(%q<jeweler>, [">= 0"])
|
48
|
+
s.add_runtime_dependency(%q<gosu>, [">= 0"])
|
49
|
+
s.add_runtime_dependency(%q<bundler>, [">= 0"])
|
50
|
+
else
|
51
|
+
s.add_dependency(%q<rspec>, [">= 0"])
|
52
|
+
s.add_dependency(%q<jeweler>, [">= 0"])
|
53
|
+
s.add_dependency(%q<gosu>, [">= 0"])
|
54
|
+
s.add_dependency(%q<bundler>, [">= 0"])
|
55
|
+
end
|
56
|
+
else
|
57
|
+
s.add_dependency(%q<rspec>, [">= 0"])
|
58
|
+
s.add_dependency(%q<jeweler>, [">= 0"])
|
59
|
+
s.add_dependency(%q<gosu>, [">= 0"])
|
60
|
+
s.add_dependency(%q<bundler>, [">= 0"])
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
data/script/run_lobby.rb
ADDED
metadata
ADDED
@@ -0,0 +1,135 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: netz
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 29
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- 1
|
10
|
+
version: 0.0.1
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Shawn Anderson
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2010-10-27 00:00:00 -04:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: rspec
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 3
|
30
|
+
segments:
|
31
|
+
- 0
|
32
|
+
version: "0"
|
33
|
+
type: :development
|
34
|
+
version_requirements: *id001
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: jeweler
|
37
|
+
prerelease: false
|
38
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
hash: 3
|
44
|
+
segments:
|
45
|
+
- 0
|
46
|
+
version: "0"
|
47
|
+
type: :development
|
48
|
+
version_requirements: *id002
|
49
|
+
- !ruby/object:Gem::Dependency
|
50
|
+
name: gosu
|
51
|
+
prerelease: false
|
52
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
53
|
+
none: false
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
hash: 3
|
58
|
+
segments:
|
59
|
+
- 0
|
60
|
+
version: "0"
|
61
|
+
type: :runtime
|
62
|
+
version_requirements: *id003
|
63
|
+
- !ruby/object:Gem::Dependency
|
64
|
+
name: bundler
|
65
|
+
prerelease: false
|
66
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
67
|
+
none: false
|
68
|
+
requirements:
|
69
|
+
- - ">="
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
hash: 3
|
72
|
+
segments:
|
73
|
+
- 0
|
74
|
+
version: "0"
|
75
|
+
type: :runtime
|
76
|
+
version_requirements: *id004
|
77
|
+
description: "P2P Networking library for us in games. "
|
78
|
+
email: shawn42@gmail.com
|
79
|
+
executables: []
|
80
|
+
|
81
|
+
extensions: []
|
82
|
+
|
83
|
+
extra_rdoc_files:
|
84
|
+
- README.rdoc
|
85
|
+
files:
|
86
|
+
- .gitignore
|
87
|
+
- README.rdoc
|
88
|
+
- Rakefile
|
89
|
+
- VERSION
|
90
|
+
- lib/netz.rb
|
91
|
+
- lib/netz/broadcaster.rb
|
92
|
+
- lib/netz/catcher.rb
|
93
|
+
- lib/netz/client.rb
|
94
|
+
- lib/netz/command.rb
|
95
|
+
- lib/netz/command_serializer.rb
|
96
|
+
- lib/netz/safe_array.rb
|
97
|
+
- netz.gemspec
|
98
|
+
- script/run_client.rb
|
99
|
+
- script/run_lobby.rb
|
100
|
+
has_rdoc: true
|
101
|
+
homepage: http://shawn42.github.com/netz
|
102
|
+
licenses: []
|
103
|
+
|
104
|
+
post_install_message:
|
105
|
+
rdoc_options:
|
106
|
+
- --charset=UTF-8
|
107
|
+
require_paths:
|
108
|
+
- lib
|
109
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
110
|
+
none: false
|
111
|
+
requirements:
|
112
|
+
- - ">="
|
113
|
+
- !ruby/object:Gem::Version
|
114
|
+
hash: 3
|
115
|
+
segments:
|
116
|
+
- 0
|
117
|
+
version: "0"
|
118
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
119
|
+
none: false
|
120
|
+
requirements:
|
121
|
+
- - ">="
|
122
|
+
- !ruby/object:Gem::Version
|
123
|
+
hash: 3
|
124
|
+
segments:
|
125
|
+
- 0
|
126
|
+
version: "0"
|
127
|
+
requirements: []
|
128
|
+
|
129
|
+
rubyforge_project: netz
|
130
|
+
rubygems_version: 1.3.7
|
131
|
+
signing_key:
|
132
|
+
specification_version: 3
|
133
|
+
summary: Networking library for use in games.
|
134
|
+
test_files: []
|
135
|
+
|