jls-lumberjack 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (2) hide show
  1. data/ruby/lib/lumberjack/server.rb +150 -0
  2. metadata +47 -0
@@ -0,0 +1,150 @@
1
+ require "socket"
2
+ require "thread"
3
+ require "openssl"
4
+ require "zlib"
5
+
6
+ module Lumberjack
7
+ class Server
8
+ attr_reader :port
9
+
10
+ # Create a new Lumberjack server.
11
+ #
12
+ # - options is a hash. Valid options are:
13
+ #
14
+ # * :port - the port to listen on
15
+ # * :address - the host/address to bind to
16
+ # * :ssl_certificate - the path to the ssl cert to use
17
+ # * :ssl_key - the path to the ssl key to use
18
+ # * :ssl_key_passphrase - the key passphrase (optional)
19
+ def initialize(options={})
20
+ @options = {
21
+ :port => 0,
22
+ :address => "0.0.0.0",
23
+ :ssl_certificate => nil,
24
+ :ssl_key => nil,
25
+ :ssl_key_passphrase => nil,
26
+ }.merge(options)
27
+
28
+ [:ssl_certificate, :ssl_key].each do |k|
29
+ if @options[k].nil?
30
+ raise "You must specify #{k} in Lumberjack::Server.new(...)"
31
+ end
32
+ end
33
+
34
+ @tcp_server = TCPServer.new(@options[:port])
35
+ # Query the port in case the port number is '0'
36
+ # TCPServer#addr == [ address_family, port, address, address ]
37
+ @port = @tcp_server.addr[1]
38
+ @ssl = OpenSSL::SSL::SSLContext.new
39
+ @ssl.cert = OpenSSL::X509::Certificate.new(File.read(@options[:ssl_certificate]))
40
+ @ssl.key = OpenSSL::PKey::RSA.new(File.read(@options[:ssl_key]),
41
+ @options[:ssl_key_passphrase])
42
+ @ssl_server = OpenSSL::SSL::SSLServer.new(@tcp_server, @ssl)
43
+ end # def initialize
44
+
45
+ def run(&block)
46
+ while true
47
+ begin
48
+ Thread.new(@ssl_server.accept) do |fd|
49
+ Connection.new(fd).run(&block)
50
+ end
51
+ rescue => e
52
+ p :accept_error => e
53
+ end
54
+ end
55
+ end # def run
56
+ end # class Server
57
+
58
+ class Connection
59
+ def initialize(fd)
60
+ @fd = fd
61
+ end # def initialize
62
+
63
+ def run(&block)
64
+ each_event(&block)
65
+ end # def run
66
+
67
+ def each_event(&block)
68
+ last_ack = 0
69
+ window_size = 0
70
+ io = IOWrap.new(@fd)
71
+ while true
72
+ version = io.read(1)
73
+ frame = io.read(1)
74
+
75
+ if frame == "W" # window size
76
+ window_size = io.read(4).unpack("N").first / 2
77
+ #puts "Window size: #{window_size}"
78
+ next
79
+ elsif frame == "C" # compressed data
80
+ length = io.read(4).unpack("N").first
81
+ #puts "Compressed frame length #{length}"
82
+ compressed = io.read(length)
83
+ original = Zlib::Inflate.inflate(compressed)
84
+ #original = LZ4::uncompress(compressed, length)
85
+ io.pushback(original)
86
+ next
87
+ elsif frame != "D"
88
+ #puts "Unexpected frame type: #{version.inspect} / #{frame.inspect}"
89
+ io.close
90
+ return
91
+ end
92
+ #
93
+ # data frame
94
+ sequence = io.read(4).unpack("N").first
95
+ count = io.read(4).unpack("N").first
96
+
97
+ map = {}
98
+ count.times do
99
+ key_len = io.read(4).unpack("N").first
100
+ key = io.read(key_len);
101
+ value_len = io.read(4).unpack("N").first
102
+ value = io.read(value_len);
103
+ map[key] = value
104
+ end
105
+
106
+ block.call(map)
107
+
108
+ if sequence - last_ack >= window_size
109
+ # ack this.
110
+ io.syswrite(["1", "A", sequence].pack("AAN"))
111
+ last_ack = sequence
112
+ end
113
+ end
114
+ end # def each_event
115
+ end # class Connection
116
+
117
+ # Wrap an io-like object but support pushback.
118
+ class IOWrap
119
+ def initialize(io)
120
+ @io = io
121
+ @buffer = ""
122
+ end
123
+
124
+ def read(bytes)
125
+ if @buffer.empty?
126
+ #puts "reading direct from @io"
127
+ return @io.read(bytes)
128
+ elsif @buffer.length > bytes
129
+ #puts "reading buffered"
130
+ data = @buffer[0...bytes]
131
+ @buffer[0...bytes] = ""
132
+ return data
133
+ else
134
+ data = @buffer.clone
135
+ @buffer.clear
136
+ return data + @io.read(bytes - data.length)
137
+ end
138
+ end
139
+
140
+ def pushback(data)
141
+ #puts "Pushback: #{data[0..30].inspect}..."
142
+ @buffer += data
143
+ end
144
+
145
+ def method_missing(method, *args)
146
+ @io.send(method, *args)
147
+ end
148
+ end # class IOWrap
149
+ end # module Lumberjack
150
+
metadata ADDED
@@ -0,0 +1,47 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: jls-lumberjack
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Jordan Sissel
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-09-18 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: lumberjack log transport library
15
+ email:
16
+ - jls@semicomplete.com
17
+ executables: []
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - ruby/lib/lumberjack/server.rb
22
+ homepage: https://github.com/jordansissel/lumberjack
23
+ licenses: []
24
+ post_install_message:
25
+ rdoc_options: []
26
+ require_paths:
27
+ - ruby/lib
28
+ required_ruby_version: !ruby/object:Gem::Requirement
29
+ none: false
30
+ requirements:
31
+ - - ! '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ required_rubygems_version: !ruby/object:Gem::Requirement
35
+ none: false
36
+ requirements:
37
+ - - ! '>='
38
+ - !ruby/object:Gem::Version
39
+ version: '0'
40
+ requirements: []
41
+ rubyforge_project:
42
+ rubygems_version: 1.8.24
43
+ signing_key:
44
+ specification_version: 3
45
+ summary: lumberjack log transport library
46
+ test_files: []
47
+ has_rdoc: