rbsrt 0.1.0
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.
- checksums.yaml +7 -0
- data/README.md +752 -0
- data/Rakefile +29 -0
- data/bin/rbsrt-client +113 -0
- data/bin/rbsrt-server +68 -0
- data/bin/rbsrt-sockets +82 -0
- data/ext/rbsrt/extconf.rb +37 -0
- data/ext/rbsrt/rbsrt.c +2270 -0
- data/ext/rbsrt/rbsrt.h +265 -0
- data/ext/rbsrt/rbstats.c +960 -0
- data/ext/rbsrt/rbstats.h +24 -0
- data/lib/rbsrt/rbsrt.bundle +0 -0
- data/lib/rbsrt/streamid_components.rb +113 -0
- data/lib/rbsrt/version.rb +3 -0
- data/lib/rbsrt.rb +5 -0
- data/rbsrt.gemspec +22 -0
- data/test/rbsrt/poll_test.rb +153 -0
- data/test/rbsrt/stats_test.rb +546 -0
- data/test/rbsrt/streamid_components_test.rb +281 -0
- metadata +83 -0
data/ext/rbsrt/rbstats.h
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
/*
|
2
|
+
* Ruby SRT - Ruby binding for Secure, Reliable, Transport
|
3
|
+
* Copyright (c) 2019 Klaas Speller, Recce.
|
4
|
+
*
|
5
|
+
* This Source Code Form is subject to the terms of the Mozilla Public
|
6
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
7
|
+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
8
|
+
*
|
9
|
+
*/
|
10
|
+
|
11
|
+
/**
|
12
|
+
* A Ruby wrapper for SRT (Secure Reliable Transport)
|
13
|
+
*
|
14
|
+
* @author: Klaas Speller <klaas@recce.nl>
|
15
|
+
*/
|
16
|
+
|
17
|
+
#ifndef RBSRT_STATS_H
|
18
|
+
#define RBSRT_STATS_H
|
19
|
+
|
20
|
+
#include <ruby/ruby.h>
|
21
|
+
|
22
|
+
void RBSRT_stat_init(VALUE srt_module);
|
23
|
+
|
24
|
+
#endif /* RBSRT_STATS_H */
|
Binary file
|
@@ -0,0 +1,113 @@
|
|
1
|
+
# srt streamid parser based on https://github.com/Haivision/srt/blob/master/docs/AccessControl.md
|
2
|
+
|
3
|
+
require "uri"
|
4
|
+
|
5
|
+
module SRT
|
6
|
+
class StreamIDComponents
|
7
|
+
Types = ["stream", "file", "auth"]
|
8
|
+
|
9
|
+
Modes = ["request", "publish", "bidirectional"]
|
10
|
+
|
11
|
+
Header = "#!::"
|
12
|
+
|
13
|
+
attr_accessor :resource_name
|
14
|
+
attr_accessor :user_name
|
15
|
+
attr_accessor :mode
|
16
|
+
attr_accessor :host_name
|
17
|
+
attr_accessor :type
|
18
|
+
attr_accessor :sessionid
|
19
|
+
attr_reader :extra
|
20
|
+
|
21
|
+
def initialize(*args)
|
22
|
+
|
23
|
+
@mode = :request
|
24
|
+
@type = :stream
|
25
|
+
@extra = {}
|
26
|
+
|
27
|
+
# no args
|
28
|
+
return unless args.first
|
29
|
+
|
30
|
+
# hash args
|
31
|
+
if args.first.class == ::Hash
|
32
|
+
merge_hash!(args.first)
|
33
|
+
elsif streamid = args.first.to_s
|
34
|
+
if streamid.index(Header) == 0
|
35
|
+
merge_str!(streamid)
|
36
|
+
elsif streamid =~ URI::regexp
|
37
|
+
merge_uri!(URI(streamid))
|
38
|
+
else
|
39
|
+
@resource_name = streamid
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def to_s
|
45
|
+
streamid = Header.dup
|
46
|
+
|
47
|
+
vars = []
|
48
|
+
|
49
|
+
vars << "r=#{resource_name}" if resource_name
|
50
|
+
vars << "u=#{user_name}" if user_name
|
51
|
+
vars << "m=#{mode}" if mode
|
52
|
+
vars << "h=#{host_name}" if host_name
|
53
|
+
vars << "t=#{type}" if type
|
54
|
+
vars << "s=#{sessionid}" if sessionid
|
55
|
+
|
56
|
+
extra.each { |key,val| vars << "#{key}=#{val}" }
|
57
|
+
|
58
|
+
streamid + vars.join(",")
|
59
|
+
end
|
60
|
+
|
61
|
+
def method_missing(name, *args)
|
62
|
+
return extra[name.to_s] if extra.key? name.to_s
|
63
|
+
match = name.to_s.match(/^(.*?)(=?)$/)
|
64
|
+
case match[2]
|
65
|
+
when "="
|
66
|
+
@extra[match[1]] = args.first
|
67
|
+
else
|
68
|
+
return nil
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def set(key, val)
|
73
|
+
case key.to_s
|
74
|
+
when 'resource_name', 'r' then @resource_name = val
|
75
|
+
when 'user_name', 'u' then @user_name = val
|
76
|
+
when 'mode', 'm' then @mode = val.to_sym if Modes.include?(val.to_s)
|
77
|
+
when 'host_name', 'h'
|
78
|
+
if sep = val.index("/")
|
79
|
+
@host_name = val[0..(sep - 1)]
|
80
|
+
(@resource_name = val[(sep + 1)..-1] unless @resource_name)
|
81
|
+
else
|
82
|
+
@host_name = val
|
83
|
+
end
|
84
|
+
when 'type', 't' then (@type = val.to_sym if Types.include?(val.to_s))
|
85
|
+
when 'sessionid', 's' then @sessionid = val
|
86
|
+
else @extra[key] = val
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def merge_uri!(streamid)
|
91
|
+
uri = URI(streamid)
|
92
|
+
|
93
|
+
@host_name = uri.hostname
|
94
|
+
@resource_name = uri.path[1..-1] if uri.path
|
95
|
+
|
96
|
+
if uri.query && form = URI.decode_www_form(uri.query)
|
97
|
+
merge_hash!(Hash[form])
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def merge_str!(streamid)
|
102
|
+
streamid.scan(/([a-z0-9_-]+?)=(.+?)(,|$)/i).each do |key,val,_|
|
103
|
+
set(key, val)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def merge_hash!(hash)
|
108
|
+
hash.each do |key, val|
|
109
|
+
set(key, val)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
data/lib/rbsrt.rb
ADDED
data/rbsrt.gemspec
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
$:.push File.expand_path("../lib", __FILE__)
|
2
|
+
|
3
|
+
require "rbsrt/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = 'rbsrt'
|
7
|
+
s.version = SRT::VERSION
|
8
|
+
s.licenses = ['MPLv2.0', 'MIT']
|
9
|
+
s.summary = "Ruby API for SRT (Secure Reliable Transport)"
|
10
|
+
s.description = "Build SRT (Secure Reliable Transport) servers and clients with Ruby"
|
11
|
+
s.authors = ["Klaas Speller"]
|
12
|
+
s.email = ["klaas@recce.nl"]
|
13
|
+
s.files = Dir['README*.md', 'lib/**/*', 'ext/**/*', 'bin/**/*'] + ['Rakefile', 'rbsrt.gemspec']
|
14
|
+
s.test_files = Dir['test/**/*_test.rb']
|
15
|
+
s.bindir = "bin"
|
16
|
+
s.executables = ["rbsrt-server", "rbsrt-client"]
|
17
|
+
s.homepage = 'https://github.com/spllr/rbsrt'
|
18
|
+
s.metadata = { "source_code_uri" => "https://github.com/spllr/rbsrt" }
|
19
|
+
s.extensions = %w[ext/rbsrt/extconf.rb]
|
20
|
+
s.required_ruby_version = ">= 2.2.0"
|
21
|
+
s.add_development_dependency "rake-compiler", "~> 1.0"
|
22
|
+
end
|
@@ -0,0 +1,153 @@
|
|
1
|
+
require 'minitest/spec'
|
2
|
+
|
3
|
+
require "rbsrt"
|
4
|
+
require "thread"
|
5
|
+
|
6
|
+
describe SRT::Poll do
|
7
|
+
it "can be created" do
|
8
|
+
assert_instance_of(SRT::Poll, SRT::Poll.new)
|
9
|
+
end
|
10
|
+
|
11
|
+
|
12
|
+
|
13
|
+
describe "monitor server sockets" do
|
14
|
+
before do
|
15
|
+
# puts "server start"
|
16
|
+
@server = SRT::Socket.new
|
17
|
+
@server.bind "127.0.0.1", "6789"
|
18
|
+
@server.listen 2
|
19
|
+
end
|
20
|
+
|
21
|
+
after do
|
22
|
+
# puts "server stop"
|
23
|
+
@client.close if @client
|
24
|
+
@server.close if @server
|
25
|
+
end
|
26
|
+
|
27
|
+
it "will trigger when an new connection is available" do
|
28
|
+
poll = SRT::Poll.new
|
29
|
+
|
30
|
+
poll.add @server, :in
|
31
|
+
|
32
|
+
Thread.new do
|
33
|
+
# puts "connect to server"
|
34
|
+
@client = SRT::Socket.new
|
35
|
+
@client.connect "127.0.0.1", "6789"
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
# block/ yield style
|
40
|
+
|
41
|
+
did_call = false
|
42
|
+
|
43
|
+
poll.wait do |readable, writable, errors|
|
44
|
+
did_call = true
|
45
|
+
refute_empty readable
|
46
|
+
assert_empty writable
|
47
|
+
assert_empty errors
|
48
|
+
|
49
|
+
assert_equal @server, readable.first
|
50
|
+
|
51
|
+
@accepted_sock = readable.first.accept
|
52
|
+
|
53
|
+
poll.add @accepted_sock, :in, :err
|
54
|
+
end
|
55
|
+
|
56
|
+
assert_equal true, did_call, "wait block must yield"
|
57
|
+
|
58
|
+
# return style
|
59
|
+
|
60
|
+
Thread.new do
|
61
|
+
# puts "write data to server"
|
62
|
+
@client.sendmsg "data from client"
|
63
|
+
end
|
64
|
+
|
65
|
+
readable, writable, errors = poll.wait 1000
|
66
|
+
|
67
|
+
refute_empty readable
|
68
|
+
assert_empty writable
|
69
|
+
assert_empty errors
|
70
|
+
|
71
|
+
assert_equal @accepted_sock, readable.first
|
72
|
+
|
73
|
+
assert_equal "data from client", readable.first.recvmsg
|
74
|
+
|
75
|
+
# removing sockets
|
76
|
+
|
77
|
+
poll.remove @client
|
78
|
+
|
79
|
+
Thread.new do
|
80
|
+
# puts "write data to server"
|
81
|
+
@client.sendmsg "data from client"
|
82
|
+
end
|
83
|
+
|
84
|
+
readable, writable, errors = poll.wait 100
|
85
|
+
|
86
|
+
assert_empty readable
|
87
|
+
assert_empty writable
|
88
|
+
assert_empty errors
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
|
93
|
+
describe "adding and updating sockets" do
|
94
|
+
before do
|
95
|
+
# puts "server start"
|
96
|
+
@server = SRT::Socket.new
|
97
|
+
@server.bind "127.0.0.1", "6789"
|
98
|
+
@server.listen 2
|
99
|
+
end
|
100
|
+
|
101
|
+
after do
|
102
|
+
# puts "server stop"
|
103
|
+
@client.close if @client
|
104
|
+
@server.close if @server
|
105
|
+
end
|
106
|
+
|
107
|
+
it "can update a socket" do
|
108
|
+
poll = SRT::Poll.new
|
109
|
+
|
110
|
+
poll.add @server, :in
|
111
|
+
|
112
|
+
Thread.new do
|
113
|
+
@client = SRT::Socket.new
|
114
|
+
@client.connect "127.0.0.1", "6789"
|
115
|
+
end
|
116
|
+
|
117
|
+
readable, _, _ = poll.wait 100
|
118
|
+
|
119
|
+
remote_client = readable.first.accept
|
120
|
+
|
121
|
+
# puts "++ IN OUT"
|
122
|
+
poll.add remote_client, :err
|
123
|
+
# puts "-- IN OUT"
|
124
|
+
|
125
|
+
Thread.new do
|
126
|
+
@client.write "foobar 1"
|
127
|
+
end
|
128
|
+
|
129
|
+
readable, writable, errors = poll.wait 100
|
130
|
+
|
131
|
+
assert_empty readable
|
132
|
+
assert_empty writable
|
133
|
+
assert_empty errors
|
134
|
+
|
135
|
+
_ = remote_client.read
|
136
|
+
|
137
|
+
# upddate
|
138
|
+
|
139
|
+
poll.update remote_client, :in
|
140
|
+
|
141
|
+
Thread.new do
|
142
|
+
@client.write "foobar 2"
|
143
|
+
end
|
144
|
+
|
145
|
+
readable, writable, errors = poll.wait 100
|
146
|
+
|
147
|
+
# pending
|
148
|
+
# refute_empty readable
|
149
|
+
# assert_empty writable
|
150
|
+
# assert_empty errors
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|