minitcp 0.10.0 → 0.15.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5a5ea8ac3aaaa06e3051b9d4e696713132b1e721
4
- data.tar.gz: 98eb5966f3ff14ca68c1522110b6fdd3d941b3d3
3
+ metadata.gz: 40c86e0923a11e1d1399840594700ed14d087f5b
4
+ data.tar.gz: 25fc9a740519e40ed6ccf029cb986bb85e0e0a13
5
5
  SHA512:
6
- metadata.gz: 87f235759fc78198cbeeb0446b788c685f4c82ca79947fe551f0822da7c29e5fb7961e756eec422b524d92d2821688871caeaee01ac502d831d093aa598288f5
7
- data.tar.gz: d217d33d86b4181190730605dfe88ccbfc3405eeb022521ae8fab0b32041a4ed57d7a199c73fc34fa7bf0836c9e3a3cbb36e99aad413e1d65bf1a89b665e95bf
6
+ metadata.gz: 1e59ae815447e1bd2639a3a49a8c536f9af7856c88a6c0861e643e671f78f68973eeec0ecb1cc1c067c6730e88d1bd3ee61b9633d7844550f4c09fcdee72d445
7
+ data.tar.gz: b204d6cb22237371a6bb93e449ee977564d7e8d9931ed86b0d1c76b15c1b310f726611f8f7168a6627f7a834fde673f6366361cdd933358ed6c3f433a0f962c5
data/CHANGELOG.txt CHANGED
@@ -1,3 +1,23 @@
1
+ 0.15.0 : 2015-04-02 15:51:14 +0200
2
+ minitcp.rb : force data received to encding BINARY
3
+ 0.14.0 : 2015-01-13 20:56:17 +0100
4
+ minitcp.rb : no audit, no log for tcp server
5
+ relaiproxy.rb : notraces
6
+ relai_config.data : test1 aded
7
+ minitcp.rb : no traces
8
+ 0.13.0 : 2014-11-28 13:35:33 +0100
9
+ plot.rb : window resize enable
10
+ pingpongplot.rb : multiple url test
11
+ README.md : message agent expample
12
+ README.md : massage agent expalple
13
+ README.md : example message
14
+ README.md : example for agent message
15
+ 0.12.0 : 2014-10-30 21:31:33 +0100
16
+ 0.11.0 : 2014-10-30 21:30:28 +0100
17
+ README.md : ocpp
18
+ README.md : plugin doc
19
+ Rakefile.rb : version management
20
+ README.md : plugin ocpp description
1
21
  0.10.0 : 2014-09-24 20:18:54 +0200
2
22
  minitcp.rb : reveive_n_byte correction
3
23
  0.9.0 : 2014-09-18 22:38:31 +0200
data/README.md CHANGED
@@ -61,6 +61,28 @@ A UDP sender :
61
61
  )
62
62
  ```
63
63
 
64
+ A Message agent :
65
+ Message Client:
66
+ ```ruby
67
+ MClientAgent.run("localhost",2222) do |chan|
68
+ chan.send_message({date: Time.now.to_f})
69
+ chan.on_message do |mess|
70
+ puts "cli: receive: #{mess.inspect}"
71
+ chan.close
72
+ nil
73
+ end
74
+ chan.on_timeout(10_000) { p "timeout" ; chan.close rescue nil }
75
+ chan.wait_end
76
+ end
77
+ ```
78
+
79
+ Message Server:
80
+ ```ruby
81
+ MServerAgent.run(2222,"localhost",22) do |chan|
82
+ chan.on_message { |mess| p mess ; "ok" }
83
+ chan.wait_end
84
+ end
85
+ ```
64
86
 
65
87
  Docs: http://rubydoc.info/gems/minitcp
66
88
 
@@ -126,13 +148,27 @@ UDP
126
148
  * **send_datagram(host,port,message)** : create a socket, send mesage and close socket (ca'nt receive a reply)
127
149
  * **send_datagram_on_socket(socket,host,port,message)** : use existant socket for send a message to ip:port
128
150
 
151
+ Messages
152
+ ===
153
+ Serveur and client ```MServerAgent``` and ```MClientAgent``` define a 'agent ' which
154
+ can communicate by messages.
155
+
156
+ Messages are ```ruby-data.inspect```, max size is 1 MByte.
157
+ * MClientAgent.run(host,port) : connect to a MServerAgent, for communicate by message
158
+ * MServerAgent.run(port,host,max-connections) : message server
159
+
160
+ in Agent, socket are extended with this capability :
161
+ * socket.send_message(data)
162
+ * socket.on_message { |data| .... ; ret_data} will send ret_data to sender if not nil
163
+
164
+ See test.rb for an example
129
165
 
130
166
  TODO
131
167
  ==
132
168
 
133
169
  * Serial line
134
170
  * more socket primitive
135
-
171
+ * messages Agent : use Marchal instead of inspect/eval ....
136
172
 
137
173
  Tests case
138
174
  ==
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.10.0
1
+ 0.15.0
data/lib/minitcp.rb CHANGED
@@ -11,9 +11,9 @@ require 'gserver'
11
11
 
12
12
 
13
13
  module SocketReactive
14
-
14
+ def strempty() ''.force_encoding Encoding::BINARY end
15
15
  def data_readed=(v) @data_readed=v end
16
- def data_readed() @data_readed||="" end
16
+ def data_readed() @data_readed||=strempty end
17
17
 
18
18
  # read n byte, block the caller, return nil if socket if close
19
19
  # if block is defined, it is yield with data, method return whith the value of yield
@@ -29,7 +29,7 @@ module SocketReactive
29
29
  loop do
30
30
  #p ["waiting ",s,data_readed]
31
31
  sd=s>1024 ? 1024 : s
32
- data=(self.recv(sd) rescue nil)
32
+ data=(self.recv(sd) rescue (p $!;nil))
33
33
  #p "nrec: w#{sizemax}/ rec:#{(data||'').size} / #{sd} old=#{data_readed.size} /// #{(data||'').size<70 ? data : "."}"
34
34
  if data && data.size>0
35
35
  self.data_readed=self.data_readed+data
@@ -75,7 +75,7 @@ module SocketReactive
75
75
  Thread.new() do
76
76
  begin
77
77
  if self.data_readed.size>0
78
- buff,self.data_readed=self.data_readed,""
78
+ buff,self.data_readed=self.data_readed,strempty
79
79
  yield(buff)
80
80
  end
81
81
  loop do
@@ -317,16 +317,16 @@ end
317
317
  # Run a TCP serveur, with a max connection simultaneous,
318
318
  # When connection succes, call the bloc given with socket (extended by SocketReactive).
319
319
  #
320
- # MServer( "8080" , "0.0.0.0" ,1) { |socket| loop { p socket.gets} }
320
+ # MServer.new( "8080" , "0.0.0.0" ,1) { |socket| loop { p socket.gets} }
321
321
  class MServer < GServer
322
322
  def self.service(port,host,max,&b)
323
323
  srv=new(port,host,max,&b)
324
- srv.audit = true
324
+ srv.audit = false
325
325
  srv.start
326
326
  srv
327
327
  end
328
328
  def initialize(port,host,max=1,&b)
329
- super(port,host,max)
329
+ super(port,host,max,nil)
330
330
  @bloc=b
331
331
  end
332
332
  def serve( io )
@@ -339,3 +339,43 @@ class MServer < GServer
339
339
  end
340
340
  end
341
341
 
342
+ ##########################################################
343
+ # messages stream
344
+ ##########################################################
345
+
346
+ module SocketMessage
347
+ def on_message(timeout=nil,&b)
348
+ on_n_receive(6) do |head|
349
+ len=head.to_i
350
+ received_n_timeout(len,10_000) do |data|
351
+ response=b.call(eval(data))
352
+ send(response) if response
353
+ end
354
+ end
355
+ end
356
+ def send_message(message)
357
+ data=message.inspect
358
+ send(("%6d" % data.size)+data,0)
359
+ end
360
+ end
361
+
362
+ class MClientAgent
363
+ def self.run(host,port,&b)
364
+ me=MClientAgent.new
365
+ MClient.run_continious(host,port,10_000) do |so|
366
+ so.extend(SocketMessage)
367
+ me.instance_eval { b.call(so) }
368
+ end
369
+ end
370
+ end
371
+
372
+ class MServerAgent
373
+ def self.run(port,host,n,&b)
374
+ me=MClientAgent.new
375
+ MServer.service( port , host ,n) do |so|
376
+ so.extend(SocketMessage)
377
+ me.instance_eval { b.call(so) }
378
+ end
379
+ end
380
+ end
381
+
data/samples/pxy.rb ADDED
@@ -0,0 +1,429 @@
1
+ #!/usr/bin/ruby
2
+ # LGPL
3
+ ####################################################
4
+ # proxy.rb : pure tcp proxy, for dev/admin/fun :)
5
+ #
6
+ # Usage :
7
+ # > ruby proxy.rb target-hostname target-port [mode]
8
+ # mode= ascii/bin/none : style of printing
9
+ ####################################################
10
+ # LGPL, Author: Regis d'Aubarede <regis.aubarede@gmail.com>
11
+ #
12
+ ##################################################### start minitcp
13
+
14
+ ##############################################################
15
+ # minitcp.rb
16
+ ##############################################################
17
+
18
+ require 'thread'
19
+ require 'timeout'
20
+ require 'socket'
21
+ require 'gserver'
22
+
23
+
24
+ module SocketReactive
25
+
26
+ def data_readed=(v) @data_readed=v end
27
+ def data_readed() @data_readed||="" end
28
+
29
+ # read n byte, block the caller, return nil if socket if close
30
+ # if block is defined, it is yield with data, method return whith the value of yield
31
+ # if looping is true, the method loop until socket close, (or current thread is killed)
32
+ def receive_n_bytes(sizemax,looping=false,&b)
33
+ s=sizemax
34
+ if self.data_readed.size>=sizemax
35
+ buff,self.data_readed=self.data_readed[0..sizemax-1],self.data_readed[sizemax..-1]
36
+ buff=b.call(buff) if block_given?
37
+ return buff unless looping
38
+ end
39
+ s=sizemax-self.data_readed.size
40
+ loop do
41
+ #p ["waiting ",s,data_readed]
42
+ sd=s>1024 ? 1024 : s
43
+ data=(self.recv(sd) rescue (p $!;nil))
44
+ #p "nrec: w#{sizemax}/ rec:#{(data||'').size} / #{sd} old=#{data_readed.size} /// #{(data||'').size<70 ? data : "."}"
45
+ if data && data.size>0
46
+ self.data_readed=self.data_readed+data
47
+ s=sizemax-self.data_readed.size
48
+ if s<=0
49
+ buff,self.data_readed=self.data_readed,""
50
+ s=sizemax
51
+ buff=b.call(buff) if block_given?
52
+ return buff unless looping
53
+ end
54
+ else
55
+ close rescue nil
56
+ break # socket close
57
+ end
58
+ end #loop
59
+ end
60
+ # wait n byte or timeout. if block is defined, it is yielded with data
61
+ # return nil if timeout/socket closed, or data if no bloc, or yield value
62
+ def received_n_timeout(sizemax,timeout_ms,&b)
63
+ timeout(timeout_ms/1000.0) {
64
+ ret=receive_n_bytes(sizemax,false,&b)
65
+ return ret
66
+ }
67
+ rescue Timeout::Error
68
+ return nil
69
+ rescue Exception => e
70
+ $stdout.puts "#{e} :\n #{e.backtrace.join("\n ")}"
71
+ end
72
+
73
+ def received_any_timeout(sizemax,timeout_ms)
74
+ timeout(timeout_ms/1000.0) {
75
+ return recv(sizemax)
76
+ }
77
+ rescue Timeout::Error
78
+ return nil
79
+ rescue Exception => e
80
+ $stdout.puts "#{e} :\n #{e.backtrace.join("\n ")}"
81
+ end
82
+
83
+ # async wait and read data on socket, yield values readed,
84
+ # return thread spawned, which can be kill
85
+ def on_any_receive()
86
+ Thread.new() do
87
+ begin
88
+ if self.data_readed.size>0
89
+ buff,self.data_readed=self.data_readed,""
90
+ yield(buff)
91
+ end
92
+ loop do
93
+ data=(self.recv(64*1024) rescue nil)
94
+ data && data.size>0 ? yield(data) : break
95
+ end
96
+ rescue Exception => e
97
+ $stdout.puts "#{e} :\n #{e.backtrace.join("\n ")}"
98
+ end
99
+ close rescue nil
100
+ end
101
+ end
102
+
103
+
104
+ # async yield on received n bytes
105
+ # return thread spawned, which can be kill
106
+ def on_n_receive(sizemax=1,&b)
107
+ Thread.new() do
108
+ begin
109
+ receive_n_bytes(sizemax,true,&b)
110
+ rescue Exception => e
111
+ $stdout.puts "#{e} :\n #{e.backtrace.join("\n ")}"
112
+ end
113
+ end
114
+ end
115
+
116
+ # read until separator reached, block the caller, return nil if socket is close
117
+ # if block is defined, it is yield with data, method return whith the value of yield
118
+ # if looping is true, the method loop until socket close, (or current thread is killed)
119
+ # this read some extra data. they can be retrieve with in socket.data_readed.
120
+ # data_readed is use for next calls to receives_n_byte/receive_sep
121
+ def receive_sep(separator,sizemax=1024,looping=false,&b)
122
+ if self.data_readed.size>0
123
+ a=self.data_readed.split(separator,2)
124
+ while a.size>1
125
+ buff= a.size>2 ? a[0..-2] : a.first
126
+ self.data_readed=a.last
127
+ buff=b.call(buff) if block_given?
128
+ return buff unless looping
129
+ a=self.data_readed.split(separator,2)
130
+ end
131
+ end
132
+ loop do
133
+ data=(self.recv(sizemax-self.data_readed.size) rescue nil)
134
+ if data && data.size>0
135
+ self.data_readed=self.data_readed+data
136
+ a=(self.data_readed).split(separator,2)
137
+ while a.size>1
138
+ buff= a.size>2 ? a[0..-2] : a.first
139
+ self.data_readed=a.last
140
+ buff=b.call(buff) if block_given?
141
+ return buff unless looping
142
+ a=(self.data_readed).split(separator,2)
143
+ end
144
+ else
145
+ close rescue nil
146
+ break
147
+ end
148
+ end
149
+ end
150
+
151
+ # async yield on received data until end-buffer string
152
+ # end-buffer can be string or regexp (args of data.split(,2))
153
+ # return thread spawned, which can be kill
154
+ # this read some extra data. they can be retrieve with in socket.data_readed.
155
+ # data_readed is use for next calls to receives_n_byte/receive_sep
156
+ def on_receive_sep(separator,sizemax=1024,&b)
157
+ Thread.new() do
158
+ begin
159
+ receive_sep(separator,sizemax,looping=true,&b)
160
+ rescue Exception => e
161
+ $stdout.puts "#{e} :\n #{e.backtrace.join("\n ")}"
162
+ end
163
+ end
164
+ end
165
+
166
+ # async yield after a duration, if socket is open
167
+ # return thread spawned, which can be kill
168
+ def after(duration_ms)
169
+ Thread.new() do
170
+ begin
171
+ sleep(duration_ms/1000.0)
172
+ yield unless self.connected?()
173
+ rescue Exception => e
174
+ $stdout.puts "#{e} :\n #{e.backtrace.join("\n ")}"
175
+ end
176
+ end
177
+ end
178
+
179
+ # async yield periodicaly, if socket is open
180
+ # return thread spawned, which can be kill
181
+ def on_timer(value=1000)
182
+ Thread.new() {
183
+ begin
184
+ nbtick=(value/TICK)+1
185
+ loop do
186
+ i=0
187
+ sleep(TICK/1000.0) while self.connected?() && (i+=1)<nbtick
188
+ self.connected?() ? yield() : break
189
+ end
190
+ rescue Exception => e
191
+ $stdout.puts "#{e} :\n #{e.backtrace.join("\n ")}"
192
+ end
193
+ }
194
+ end
195
+
196
+ # wait until curent socket is close.
197
+ def wait_end()
198
+ begin
199
+ loop do
200
+ sleep(TICK/1000.0) while (self.connected?() rescue nil)
201
+ break
202
+ end
203
+ rescue Exception => e
204
+ end
205
+ end
206
+
207
+ # Test if a socket is open. (use socket.remote_address() !)
208
+ def connected?()
209
+ (self.remote_address rescue nil) ? true : false
210
+ end
211
+ # duration of sleep when active wait (wait_end,on_timer...)
212
+ TICK=600
213
+
214
+ def self.make_socket_reactive(socket)
215
+ socket.extend(SocketReactive)
216
+ socket.data_readed=""
217
+ end
218
+ end
219
+
220
+ # Assure connection to server, extend socket connection by SocketReactive module.
221
+ #
222
+ # MClient.run_one_shot("localhost",2200) do |socket| .. end.join
223
+ #
224
+ # MClient.run_continous("localhost",2200,6000) do |socket| .. end.join
225
+ #
226
+ class MClient
227
+ # maintain a conntection to a TCP serveur, sleep timer_interconnection_ms millisecondes
228
+ # beetwen each reconnections
229
+ def self.run_continious(host,port,timer_interconnection_ms,&b)
230
+ Thread.new do
231
+ loop { run_one_shot(host,port,&b).join ; sleep timer_interconnection_ms/1000.0 }
232
+ end
233
+ end
234
+
235
+ def self.run_continous(host,port,timer_interconnection,&b)
236
+ self.run_continious(host,port,timer_interconnection,&b)
237
+ end
238
+
239
+ # Connecte to a TCP server, call block with client socket if connection sucess.
240
+ # enssure close connection after end of block
241
+ def self.run_one_shot(host="localhost",port=80)
242
+ begin
243
+ sleep(0.03) # give some time for server ready (for test...)
244
+ socket = TCPSocket.new(host,port)
245
+ rescue
246
+ puts "not connected to #{host}:#{port}: " + $!.to_s
247
+ return (Thread.new {})
248
+ end
249
+ SocketReactive::make_socket_reactive(socket)
250
+ Thread.new do
251
+ begin
252
+ yield(socket)
253
+ rescue Exception => e
254
+ puts "#{e}\n #{e.backtrace.join("\n ")}"
255
+ ensure
256
+ socket.close() rescue nil
257
+ end
258
+ end
259
+ end
260
+ end
261
+
262
+
263
+ # Assure connection to server, extend socket connection by SocketReactive module.
264
+ #
265
+ # MClient.run_one_shot("localhost",2200) do |socket| .. end.join
266
+ #
267
+ # MClient.run_continous("localhost",2200,6000) do |socket| .. end.join
268
+ #
269
+ class UDPAgent
270
+ # maintain a conntection to a TCP serveur, sleep timer_interconnection_ms millisecondes
271
+ # beetwen each reconnections
272
+ def self.send_datagram(host,port,mess)
273
+ sock = UDPSocket.new
274
+ #p ["sock.send",mess, 0, host, port]
275
+ sock.send(mess, 0, host, port)
276
+ sock.close
277
+ end
278
+ def self.send_datagram_on_socket(socket,host,port,mess)
279
+ socket.send(mess, 0, host, port)
280
+ end
281
+
282
+ Thread.abort_on_exception=true
283
+
284
+ # send datagram on timer
285
+ def self.on_timer(periode,options)
286
+ Thread.new do
287
+ sleep periode/1000.0
288
+ sock = UDPSocket.new
289
+ if options[:port]
290
+ sock.bind("0.0.0.0", options[:port])
291
+ end
292
+ loop do
293
+ rep=IO.select([sock],nil,nil,periode/1000.0)
294
+ #puts "IO.SELECT => #{rep}"
295
+ if rep
296
+ Thread.new {
297
+ data,peer=sock.recvfrom(1024)
298
+ options[:on_receive].call(data,peer,sock)
299
+ } if options[:on_receive]
300
+ elsif options[:on_timer]
301
+ h=options[:on_timer].call()
302
+ self.send_datagram_on_socket(sock,h[:host], h[:port],h[:mess]) if h && h[:mess] && h[:host] && h[:port]
303
+ end
304
+ end
305
+ end
306
+ end
307
+ # recieved UDP datagramme, bloc can ellaborate a reply, which will be sending to client
308
+ def self.on_datagramme(host,port)
309
+ serv = UDPSocket.new
310
+ serv.bind(host, port)
311
+ Thread.new do
312
+ loop do
313
+ begin
314
+ Thread.new(*serv.recvfrom(1024)) do |data,peer| # peer=["AF_INET", 59340, "127.0.0.1", "127.0.0.1"]
315
+ proto,cli_port,srv_addr,cli_addr=*peer
316
+ response=yield(data,cli_addr,cli_port)
317
+ self.send_datagram_on_socket(serv,cli_addr,cli_port,response) if response
318
+ end
319
+ rescue Exception => e
320
+ puts "#{e}\n #{e.backtrace.join("\n ")}"
321
+ ensure
322
+ end
323
+ end
324
+ end
325
+ end
326
+ end
327
+
328
+ # Run a TCP serveur, with a max connection simultaneous,
329
+ # When connection succes, call the bloc given with socket (extended by SocketReactive).
330
+ #
331
+ # MServer.new( "8080" , "0.0.0.0" ,1) { |socket| loop { p socket.gets} }
332
+ class MServer < GServer
333
+ def self.service(port,host,max,&b)
334
+ srv=new(port,host,max,&b)
335
+ srv.audit = true
336
+ srv.start
337
+ srv
338
+ end
339
+ def initialize(port,host,max=1,&b)
340
+ super(port,host,max)
341
+ @bloc=b
342
+ end
343
+ def serve( io )
344
+ SocketReactive::make_socket_reactive(io)
345
+ begin
346
+ @bloc.call(io)
347
+ rescue Exception => e
348
+ puts "Error in Mserver block: #{e} :\n #{e.backtrace.join("\n ")}"
349
+ end
350
+ end
351
+ end
352
+
353
+ ##########################################################
354
+ # messages stream
355
+ ##########################################################
356
+
357
+ module SocketMessage
358
+ def on_message(timeout=nil,&b)
359
+ on_n_receive(6) do |head|
360
+ len=head.to_i
361
+ received_n_timeout(len,10_000) do |data|
362
+ response=b.call(eval(data))
363
+ send(response) if response
364
+ end
365
+ end
366
+ end
367
+ def send_message(message)
368
+ data=message.inspect
369
+ send(("%6d" % data.size)+data,0)
370
+ end
371
+ end
372
+
373
+ class MClientAgent
374
+ def self.run(host,port,&b)
375
+ me=MClientAgent.new
376
+ MClient.run_continious(host,port,10_000) do |so|
377
+ so.extend(SocketMessage)
378
+ me.instance_eval { b.call(so) }
379
+ end
380
+ end
381
+ end
382
+
383
+ class MServerAgent
384
+ def self.run(port,host,n,&b)
385
+ me=MClientAgent.new
386
+ MServer.service( port , host ,n) do |so|
387
+ so.extend(SocketMessage)
388
+ me.instance_eval { b.call(so) }
389
+ end
390
+ end
391
+ end
392
+
393
+ ##################################################### end minitcp
394
+
395
+ $host,$port,$opt=ARGV[0]||"localhost",ARGV[1]||80,ARGV[2]||"ascii"
396
+ puts "Server on port 2200, proxy to #{$host}:#{$port}..."
397
+
398
+
399
+ MServer.service(2200,"0.0.0.0",22) do |s_cli|
400
+ puts "> ======== client Connected ========"
401
+ srv=MClient.run_one_shot($host,$port) do |s_srv|
402
+ puts "< ======== server Concected ========"
403
+ s_srv.on_any_receive { |data| spy 1,data; s_cli.print data }
404
+ s_cli.on_any_receive { |data| spy 2,data; s_srv.print data}
405
+ s_srv.wait_end
406
+ s_cli.close rescue nil
407
+ end
408
+ s_cli.wait_end
409
+ p "end cli, stop proxy"
410
+ srv.kill
411
+ end
412
+
413
+ def spy(sens,data)
414
+ return if $opt=="none"
415
+ prefix=(sens==1 ? "< " : "> ")
416
+ if $opt=="ascii"
417
+ data.each_line {|line| puts "#{prefix}#{line.chomp}" }
418
+ else
419
+ data.chars.each_slice(16) do |aline|
420
+ a=(aline.map { |char| "%02X " % char.ord }).join.ljust(16*3)+prefix+
421
+ aline.map { |char| (char.ord>30 ? char : "~") }.join()
422
+ puts "#{prefix}#{a}"
423
+ end
424
+ end
425
+ end
426
+
427
+ sleep
428
+
429
+
@@ -26,16 +26,39 @@ Server ---------------> | proxy-relai | <------//--------| relai | -----------
26
26
  internet server server-in-intranet intranet hosts
27
27
  ```
28
28
 
29
+ Plugin
30
+ ======
31
+
32
+ Relai receive http request for an intranet server.
33
+ Plugin must be writing for find ip:port/path for the host target.
34
+ this can varying with http-subprotocole used.
35
+
36
+ occp plugin is the first plugin used :
37
+ * requests servied by this plugin are SOAP, header contain a field ```<ChargeBoxId>name-equipment</ChargeBoxId>```
38
+ * a local config file give url for each id
39
+ * the plugin will :
40
+ 1) parse the request for finding the value of ChargeBoxId (regexp)
41
+ 2) find ip:port/path for the itranet-server adressed
42
+ 3) modify the path in the GET http command
29
43
 
30
44
  Usage
31
45
  =====
32
46
  Extranet:
47
+
48
+ ```
33
49
  > ruby relaiproxy.rb proxyhttp proxy-hostname proxy-port
50
+ ```
34
51
 
35
52
  Intranet:
53
+
54
+ ```
36
55
  > vi relai_config.rb
56
+ ```
57
+
58
+ ```
37
59
  > ruby relaiproxy.rb relai proxy-ip proxy-port plugin-name
60
+ ```
38
61
 
39
- (actualy ocpp is the plugin)
62
+ (actualy 'ocpp' is only plugin disponible)
40
63
 
41
64
 
@@ -1,4 +1,5 @@
1
1
  {
2
+ "TEST1" => ["localhost",7780,""],
2
3
  "TOTO" => ["localhost",7708,""],
3
4
  "TITI" => ["localhost",80,"/"]
4
- }
5
+ }
@@ -27,67 +27,106 @@ Server ---------------> | proxy-relai | <------//--------| relai | -----------
27
27
  internet server server-in-intranet intranet hosts
28
28
  =end
29
29
 
30
- #require 'minitcp'
31
- require_relative 'minitcp/lib/minitcp.rb'
30
+ require 'minitcp'
31
+ #require_relative 'minitcp/lib/minitcp.rb'
32
32
 
33
33
  if ARGV.size<1
34
34
  puts"Usage>"
35
- puts" #{$0} type hostname port"
35
+ puts" #{$0} type hostname port"
36
36
  puts" #{$0} proxyhttp proxy-hostname proxy-port"
37
- puts" #{$0} relai proxy-saia-ip proxy-saia-port plugin"
37
+ puts" #{$0} relai proxy-saia-ip proxy-port plugin"
38
38
  exit(1)
39
39
  end
40
40
 
41
41
  $opt,$host,$port=ARGV[0]||"proxyhttp",ARGV[1]||"localhost",ARGV[2]||80
42
42
 
43
43
  NBDIGITHEAD=8
44
- QUEUE_SIZE=100
44
+ QUEUE_SIZE=10
45
45
 
46
46
  def sformat(socket,mess)
47
- socket.send("%-#{NBDIGITHEAD}d%s" % [mess.size,mess],0)
47
+ puts "sformat message len=#{mess.size} #{mess.inspect[0..30]}..."
48
+ data=("%-#{NBDIGITHEAD}d%s" % [mess.size,mess])
49
+ socket.send(data,0)
50
+ end
51
+
52
+ def sformat0(socket,mess)
53
+ data=("%-#{NBDIGITHEAD}d%s" % [mess.size,mess])
54
+ l=socket.send(data,0)
48
55
  end
49
56
  def receive(socket)
50
- resp_length= socket.receive_n_bytes(NBDIGITHEAD)
51
- len =resp_length.strip.to_i
52
- #log "header: #{resp_length} => #{len}"
53
- (len>0) ? socket.receive_n_bytes(len) : ""
57
+ log "r1 len=#{NBDIGITHEAD} #{socket}"
58
+ resp_length= socket.receive_n_bytes(NBDIGITHEAD)
59
+ return nil unless resp_length
60
+ len =resp_length.strip.to_i
61
+ log "header: #{resp_length} => #{len}"
62
+ (len>0) ? socket.receive_n_bytes(len) : ""
63
+ end
64
+ def receive_to(socket,to=1000)
65
+ begin
66
+ timeout(to/1000.0) {
67
+ #log "r1 len=#{NBDIGITHEAD} #{socket}"
68
+ resp_length= socket.receive_n_bytes(NBDIGITHEAD)
69
+ return nil unless resp_length
70
+ len =resp_length.strip.to_i
71
+ #log "header: #{resp_length} => #{len}"
72
+ (len>0) ? socket.receive_n_bytes(len) : ""
73
+ }
74
+ rescue Exception => e
75
+ return(nil)
76
+ end
54
77
  end
55
78
  def log(t) puts "%10s | %s" % [Time.now.to_s,t] end
56
79
 
57
80
  if $opt=="proxyhttp"
58
81
  ##################################################################################
59
- ## P R O X Y
82
+ ## P R O X Y : extranet side
60
83
  ##################################################################################
61
84
 
62
85
  $client_sockets ={}
63
86
  $queue=Queue.new
64
87
  ############# Proxy serveur http saia >>> machine distante #######################
65
-
66
- MServer.service($port.to_i,"0.0.0.0",22) do |s_cli|
67
-
68
- begin relai=$queue.pop end until $client_sockets[relai]
88
+ def relai_command(mess)
89
+ relai=nil
69
90
  begin
70
- header=s_cli.receive_sep("\r\n\r\n")
71
- log("request...#{header.inspect}")
72
- if header.match(/^Content-length: (\d+)/i) || "0"=~/(.)/
73
- length=$1.strip.to_i
74
- log("length body==#{length}")
75
- body= length>0 ? s_cli.receive_n_bytes(length) : ""
76
- mess="#{header}\r\n\r\n#{body}"
77
- log("transmit request...")
78
- sformat(relai,mess)
79
- log("wait response...")
80
- response= (timeout(5) { receive(relai) } rescue nil)
81
- log(response!=nil ? "response ok" : "timeout") unless response
82
- s_cli.write(response ? response : "HTTP/1.0 500 NOK\r\n\r\n")
83
- else
84
- s_cli.write( "HTTP/1.0 501 NOK\r\n\r\n")
85
- end
91
+ loop {
92
+ begin relai=$queue.pop end until $client_sockets[relai]
93
+ sformat(relai,"SDV")
94
+ break if receive_to(relai,1000)!=nil
95
+ }
96
+ log("getted relai #{relai}")
97
+ sformat(relai,mess)
98
+ log("wait response...")
99
+ receive_to(relai,9000)
86
100
  ensure
87
- $queue.push(relai)
101
+ $queue.push(relai) if relai
88
102
  end
89
103
  end
90
104
 
105
+ MServer.service($port.to_i,"0.0.0.0",22) do |s_cli|
106
+ log("telecommande")
107
+ timeout(10) {
108
+ begin
109
+ header=s_cli.receive_sep("\r\n\r\n")
110
+ #log("request header=#{header.inspect}")
111
+ if header.match(/^Content-Length: (\d+)/i) || "0"=~/(.)/
112
+ length=$1.strip.to_i
113
+ #log("length body==#{length}")
114
+ body= length>0 ? s_cli.receive_n_bytes(length) : ""
115
+ #log("request body=#{body.inspect}")
116
+ mess="#{header}\r\n\r\n#{body}"
117
+ log("transmit request...")
118
+ response=relai_command(mess)
119
+ log(response!=nil ? "response ok" : "timeout") unless response
120
+ s_cli.write(response ? response : "HTTP/1.0 500 NOK\r\n\r\n")
121
+ else
122
+ s_cli.write( "HTTP/1.0 501 NOK\r\n\r\n")
123
+ end
124
+ rescue Exception => e
125
+ puts "global error: #{e} #{}"
126
+ end
127
+ }
128
+ end
129
+
91
130
  ############# serveur http machine distante #######################
92
131
 
93
132
  MServer.service($port.to_i+1,"0.0.0.0",22) do |s_cli|
@@ -99,17 +138,48 @@ MServer.service($port.to_i+1,"0.0.0.0",22) do |s_cli|
99
138
  $client_sockets.delete(s_cli)
100
139
  end
101
140
 
141
+ #-- signe de vie sur chaque socket du pool
142
+
143
+ Thread.new { loop {
144
+ begin relai=$queue.pop end until $client_sockets[relai]
145
+ #puts "testing #{relai}..."
146
+ sformat0(relai,"SDV")
147
+ receive_to(relai,1000)
148
+ sleep(0.1)
149
+ if $client_sockets[relai]
150
+ $queue.push(relai)
151
+ sleep 5
152
+ else
153
+ puts "testing socket pool: nok"
154
+ end
155
+ } }
102
156
  else
103
157
 
104
158
  ##################################################################################
105
- ## R E L A Y
159
+ ## R E L A Y : intranet side
106
160
  ##################################################################################
107
161
  CONF="relai_config.data"
108
- plugin=ARGV.last||"ocpp"
109
- p plugin
162
+ $plugin=ARGV.last||"ocpp"
110
163
  $config=nil
111
164
  $configtime=nil
112
-
165
+ =begin
166
+ <soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
167
+ <soap:Header>
168
+ <chargeBoxIdentity xmlns="urn://Ocpp/Cp/2012/06/">TEST1</chargeBoxIdentity>
169
+ <Action xmlns="http://www.w3.org/2005/08/addressing">/ChangeAvailability</Action>
170
+ <MessageID xmlns="http://www.w3.org/2005/08/addressing">urn:uuid:4efc4b17-6fc0-4a91-bf0b-153ecbc03cd0</MessageID>
171
+ <To xmlns="http://www.w3.org/2005/08/addressing">http://localhost:7700/</To>
172
+ <ReplyTo xmlns="http://www.w3.org/2005/08/addressing">
173
+ <Address>http://www.w3.org/2005/08/addressing/anonymous</Address>
174
+ </ReplyTo>
175
+ </soap:Header>
176
+ <soap:Body><changeAvailabilityRequest xmlns="urn://Ocpp/Cp/2012/06/">
177
+ <connectorId>1</connectorId>
178
+ <type>Operative</type>
179
+ </changeAvailabilityRequest>
180
+ </soap:Body>
181
+ </soap:Envelope>
182
+ =end
113
183
  def load_config()
114
184
  return if $configtime!=nil && $configtime.to_f == File.mtime(CONF).to_f
115
185
  begin
@@ -121,58 +191,87 @@ def load_config()
121
191
  log("Error loading configration : #{$!}")
122
192
  end
123
193
  end
124
-
194
+ def verify_request_ocpp(request)
195
+ (log("request does not contain ChargeBoxId0");return false) unless request =~/chargeBoxIdentity/i
196
+ return(true)
197
+ end
125
198
  def transform_ocpp(request)
126
199
  load_config
127
- pos=0
128
- puts "recieved request #{request}"
129
- (log("request does not contain ChargeBoxId");return nil) unless pos=(request =~/ChargeBoxId/i)
130
- (log("request does not contain ChargeBoxId");return nil) unless request[pos,pos+50] =~ /%3E(.*?)%3C/m
131
- id=$1.strip
132
- ip=$config[id]
133
- (log("unknown CS #{id} in config"); return nil) unless ip
134
- request.sub!(/\?[^\s]*/,"")
135
- request.sub!(/GET [^\s]*/,"GET #{ip.last}") if ip.last!=""
136
- [*ip,request]
200
+ (log("request does not contain valid ChargeBoxId");return nil) unless request =~ /chargeBoxIdentity.*?>(.*?)<\/.*?chargeBoxIdentity/
201
+ chargeboxIdentity=$1.strip
202
+ ip=$config[chargeboxIdentity] # [ip,port,path]
203
+ unless ip
204
+ p request
205
+ log("unknown CS #{chargeboxIdentity} in config")
206
+ nil
207
+ else
208
+ #request.gsub!(
209
+ # %r{(<To[^>]*>http://)([^<]*)(</To>)},
210
+ # "\\1#{ip[0]}:#{ip[1]}#{ip[2]}\\3"
211
+ #)
212
+ #puts request
213
+ ip+[request] # return [ip, port, path, request]
214
+ end
137
215
  end
138
216
 
139
217
  def transmit(ip,port=nil,path=nil,request=nil)
140
- return "HTTP/1.0 404 NOK\r\n\r\n" unless request
141
- log("send data <#{request.inspect[0..70]}...\n > to #{ip}:#{port}#{path} len=#{request.size}")
218
+ return "HTTP/1.0 404 NOK\r\n\r\n" unless request
219
+
220
+ #log("send data <#{request.inspect[0..70]}...\n > to #{ip}:#{port}#{path} len=#{request.size}")
142
221
  response=nil
143
- MClient.run_one_shot(ip,port) { |socket|
144
- socket.send(request,0)
145
- header=socket.receive_sep("\r\n\r\n")
146
- puts header
147
- response=header+"\r\n\r\n"+if header=~/Content-length: (\d+)/i && $1 && $1.to_i>0
148
- puts "with content-length #{$1}"
149
- socket.received_n_timeout($1.to_i,10) rescue "ERROR"
150
- else
151
- puts "until close"
152
- rep=""
153
- rep+=(a=socket.receive_any(1000_000)) until a==nil
154
- rep
222
+ begin
223
+ timeout(5) do
224
+ MClient.run_one_shot(ip,port) { |client|
225
+ client.send(request,0)
226
+ header=client.receive_sep("\r\n\r\n")
227
+ if header=~/Content-Length: (\d+)/i && $1.to_i>0
228
+ log( "receive data with content-length #{$1}")
229
+ begin
230
+ data_response=client.received_timeout($1.to_i,3000)
231
+ rescue
232
+ log($!.to_s)
233
+ data_response="ERROR_TIMEOUT"
234
+ end
235
+ else
236
+ puts "until close"
237
+ rep=""
238
+ rep+=(a=client.receive_any(1000_000)) until a==nil
239
+ data_response=rep
240
+ end
241
+ #log( "data_response="+data_response)
242
+ response=header+"\r\n\r\n" + data_response
243
+ }.join
244
+ response
155
245
  end
156
- }.join
157
- response
246
+ rescue Exception => e
247
+ p e
248
+ nil
249
+ end
158
250
  end
159
251
 
160
252
  QUEUE_SIZE.times do
161
253
  MClient.run_continious($host,$port.to_i+1,1000) do |socket|
162
254
  nbr=0
255
+ puts "connected..."
163
256
  socket.on_n_receive(NBDIGITHEAD) do |header|
164
- p header
257
+ #p header
165
258
  nbr+=1
166
259
  len=header.strip.to_i
167
260
  #p len
168
261
  request=socket.receive_n_bytes(len)
169
262
  #p request
170
- response= transmit(*send("transform_#{plugin}",request))
171
- puts "replay with len=#{(response||"").size} <<<\n#{(response.inspect||"")[0..40]}..#{(response.inspect||"")[-40..-1]}\n>>"
172
- sformat( socket, response ? response : "NOK #{Time.now}")
173
- (socket.close rescue nil) if nbr>100
263
+ if request!="SDV" && send("verify_request_#{$plugin}",request)
264
+ ip,port,path,request=send("transform_#{$plugin}",request)
265
+ response= transmit(ip,port,path,request)
266
+ puts "\n\nreplay with len=#{(response||"").size} <<<\n#{(response.inspect||"")[0..150]}..#{(response.inspect||"")[-40..-1]}\n>>"
267
+ sformat( socket, response ? response : "NOK #{Time.now}\r\n")
268
+ else
269
+ sformat(socket,"OK")
270
+ print "."
271
+ end
174
272
  end
175
273
  socket.wait_end
274
+ puts "deconnected."
176
275
  end
177
276
  end
178
277
 
data/test.rb CHANGED
@@ -42,7 +42,7 @@ if ARGV.size==0 || ARGV[0]=="2"
42
42
  (socket.close; next) if s!="e"
43
43
  size=data.to_i
44
44
  puts " Server waiting for #{size} Bytes of data"
45
- socket.received_timeout(size,100_000) do |data|
45
+ socket.received_n_timeout(size,100_000) do |data|
46
46
  puts " Server recieved buffer : #{data.size} Bytes"
47
47
  puts " emit ack..."
48
48
  socket.send("o",0)
@@ -61,7 +61,7 @@ if ARGV.size==0 || ARGV[0]=="2"
61
61
  s,data=data[0..(1024-1)],data[1024..-1]
62
62
  socket.send s,0
63
63
  end
64
- p socket.received_timeout(1,[size/1000,1000].max) ? "ack ok" : "!!! timeout ack"
64
+ p socket.received_n_timeout(1,[size/1000,1000].max) ? "ack ok" : "!!! timeout ack"
65
65
  #puts "\n"*7
66
66
  }
67
67
  p "end client"
@@ -189,4 +189,40 @@ if ARGV.size==0 || ARGV[0]=="5"
189
189
  sleep 10
190
190
  end
191
191
 
192
+ if ARGV.size==0 || ARGV[0]=="6"
193
+ th=MServerAgent.run(2222,"localhost",22) do |chan|
194
+ puts "sv: connect"
195
+ @lchan||={}
196
+ @lchan[chan]=chan
197
+ chan.on_message do |mess|
198
+ puts "sv: broadcast #{mess.inspect}..."
199
+ @lchan.keys.each {|chan1| chan1.send_message(mess) if chan1!=chan }
200
+ nil
201
+ end
202
+ chan.wait_end
203
+ @lchan.delete(chan)
204
+ end
205
+ lth=[]
206
+ 5.times {
207
+ puts "####################### Run Client ########################"
208
+ lth << MClientAgent.run("localhost",2222) do |chan|
209
+ nb=0
210
+ chan.on_timer(100*rand(5..15)) {
211
+ chan.send_message(["C",1,2,1.2,Time.now.to_f,true])
212
+ nb+=1
213
+ (chan.close rescue nil)if nb>50
214
+ }
215
+ chan.on_message { |mess| p "cli: receive: #{mess.inspect}" ; nil}
216
+ chan.wait_end
217
+ puts "client closed"
218
+ end
219
+ sleep rand(1..2)
220
+ }
221
+ sleep 10
222
+ puts "\n\n############# Kill all agents...\n\n"
223
+ lth.each { |th| th.kill}
224
+ th.shutdown
225
+ sleep 2
226
+ end
227
+
192
228
  puts "Test End !"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: minitcp
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.10.0
4
+ version: 0.15.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Regis d'Aubarede
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-09-24 00:00:00.000000000 Z
11
+ date: 2015-04-02 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: |
14
14
  A DSL for programming little Tcp client and server
@@ -18,25 +18,24 @@ extensions: []
18
18
  extra_rdoc_files: []
19
19
  files:
20
20
  - CHANGELOG.txt
21
- - lib/minitcp.rb
22
21
  - LICENSE
23
- - minitcp.gemspec
24
- - Rakefile.rb
25
22
  - README.md
23
+ - Rakefile.rb
24
+ - VERSION
25
+ - lib/minitcp.rb
26
+ - minitcp.gemspec
27
+ - samples/README.md
26
28
  - samples/name_server.rb
27
- - samples/pingpongplot.rb
28
- - samples/plot.rb
29
29
  - samples/proxy.rb
30
- - samples/README.md
31
- - samples/relay/c.rb
30
+ - samples/pxy.rb
31
+ - samples/relay.rb
32
32
  - samples/relay/README.md
33
- - samples/relay/relaiproxy.rb
33
+ - samples/relay/c.rb
34
34
  - samples/relay/relai_config.data
35
- - samples/relay.rb
35
+ - samples/relay/relaiproxy.rb
36
36
  - samples/spdy.rb
37
37
  - samples/statcpu.rb
38
38
  - test.rb
39
- - VERSION
40
39
  homepage: https://github.com/glurp/minitcp
41
40
  licenses:
42
41
  - LGPL
@@ -57,15 +56,14 @@ required_rubygems_version: !ruby/object:Gem::Requirement
57
56
  version: '0'
58
57
  requirements: []
59
58
  rubyforge_project:
60
- rubygems_version: 2.1.7
59
+ rubygems_version: 2.4.6
61
60
  signing_key:
62
61
  specification_version: 3
63
62
  summary: A DSL for programming little Tcp client and server
64
63
  test_files:
65
64
  - samples/name_server.rb
66
- - samples/pingpongplot.rb
67
- - samples/plot.rb
68
65
  - samples/proxy.rb
66
+ - samples/pxy.rb
69
67
  - samples/README.md
70
68
  - samples/relay.rb
71
69
  - samples/spdy.rb
@@ -1,26 +0,0 @@
1
- # LGPL, Author: Regis d'Aubarede <regis.aubarede@gmail.com>
2
- #################################################################
3
- # pingpongplot.rb : measure pingpong time on google, plot it
4
- #
5
- # Usage :
6
- # > ruby pingpongplot.rb | ruby plot.rb 0 0 300 pingpong auto
7
- #################################################################
8
- require_relative '../lib/minitcp.rb'
9
-
10
-
11
- $stdout.sync=true
12
-
13
- MClient.run_continious("google.com",80,100) do |socket|
14
- s=Time.now.to_f
15
- socket.on_receive_sep("\r\n") do |data|
16
- $stdout.puts("#{(Time.now.to_f-s)*1000}")
17
- socket.close rescue nil
18
- Thread.current.kill
19
- end
20
- s=Time.now.to_f
21
- socket.print "GET /blabla HTTP/1.0\r\n\r\n"
22
- socket.wait_end
23
- end
24
-
25
-
26
- sleep
data/samples/plot.rb DELETED
@@ -1,190 +0,0 @@
1
- # LGPL
2
- ###############################################################
3
- # plot.rb plot data(s) of stdin to Gui display
4
- # Usage:
5
- # > vmstat 1 | ruby plot.rb -2 0-value 100%-value cpu -- 10 0 5000 io auto
6
- # ^input-column ^label ^in-column .. ^auto-scale
7
- #
8
- ###############################################################
9
-
10
- require 'Ruiby'
11
- $bgcolor=::Gdk::Color.parse("#023")
12
- $fgcolor=[
13
- ::Gdk::Color.parse("#FFAA00"),
14
- ::Gdk::Color.parse("#99DDFF"),
15
- ::Gdk::Color.parse("#00FF00"),
16
- ::Gdk::Color.parse("#0000FF"),
17
- ::Gdk::Color.parse("#FFFF00"),
18
- ::Gdk::Color.parse("#00FFFF"),
19
- ::Gdk::Color.parse("#FF00FF"),
20
- ::Gdk::Color.parse("#999"),
21
- ]
22
- class Measure
23
- class << self
24
- def create(argv)
25
- noc=argv.shift.to_i
26
- y0=(argv.shift||"0.0").to_f
27
- y1=(argv.shift||"100.0").to_f
28
- label=argv.shift||"?"
29
- autoscale=argv.size>0
30
- @lcurve||=[]
31
- @lcurve << Measure.new(noc,y0,y1,label,autoscale)
32
- @lcurve.size-1
33
- end
34
- def add(noc,y0,y1,label,autoscale)
35
- @lcurve << Measure.new(noc,y0,y1,label,autoscale)
36
- @lcurve.size-1
37
- end
38
- def scan_line(line)
39
- nums=line.scan(/[\d+.]+/)
40
- @lcurve.each { |m| m.register_value(nums) }
41
- end
42
- def add_value(index,value)
43
- @lcurve[index].register_value(value)
44
- end
45
- def draw_measures(ctx)
46
- @lcurve.each_with_index { |m,index| m.plot_curve(index,ctx) }
47
- @lcurve.each_with_index { |m,index| m.plot_label(index,ctx) }
48
- end
49
- end
50
- def initialize(noc,min,max,label,auto_scale)
51
- @noc=noc
52
- @div,@offset=calc_coef(min,0.0,max,1.0)
53
- @name=label
54
- @value= 0
55
- @curve=[]
56
- @label=@name
57
- @autoscale=auto_scale
58
- end
59
- def register_value(data)
60
- if data.is_a? Array
61
- svalue=data[@noc]
62
- return if !svalue || svalue !~ /[\d.]+/
63
- @value=svalue.to_f
64
- else
65
- @value=data
66
- end
67
- @label = "%s %5.2f" % [@name,@value]
68
- v= @value * @div + @offset
69
- py=[0.0,(H-HHEAD)*1.0,(H-HHEAD)*(1.0-v)].sort[1]+HHEAD
70
- @curve << [W+PAS,py,v,@value]
71
- @curve.select! {|pt| pt[0]-=PAS; pt[0]>=0}
72
- p [i,@value,v,py] if $DEBUG
73
- auto_scale if @autoscale && @curve.size>5
74
- end
75
- def auto_scale()
76
- min,max=@curve.minmax_by {|pt| pt[2]}
77
- if min!=max && (min[2]<-0.01 || max[2]>1.01)
78
- p "correction1 #{@name} #{min} // #{max}"
79
- @div,@offset=calc_coef(min[3],0.0,max[3],1.0)
80
- @curve.each {|a| a[2]=a[3]*@div+@offset ; a[1] = (H-HHEAD)*(1-a[2])}
81
- elsif (d=(max[2]-min[2]))< 0.1 && (@curve.size-1) >= W/PAS && d>0.0001
82
- p "correction2 #{@name} #{min} // #{max}"
83
- @div,@offset=calc_coef(min[3],min[2]-3*d,max[3],max[2]+3*d)
84
- @curve.each {|a| a[2]=a[3]*@div+@offset ; a[1] = (H-HHEAD)*(1.0-a[2])}
85
- end
86
- end
87
- def calc_coef(x0,y0,x1,y1)
88
- y0=[0.0,1.0,y0].sort[1]
89
- y1=[0.0,1.0,y1].sort[1]
90
- a=1.0*(y0-y1)/(x0-x1)
91
- b= (y0+y1-(x0+x1)*a)/2
92
- [a,b]
93
- end
94
- def plot_curve(index,ctx)
95
- return if @curve.size<2
96
- a,*l=@curve
97
- style(ctx,3,$fgcolor.last) ; draw(ctx,a,l)
98
- style(ctx,1,$fgcolor[index]) ; draw(ctx,a,l)
99
- end
100
- def style(ctx,width,color)
101
- ctx.set_line_width(width)
102
- ctx.set_source_rgba(color.red/65000.0,color.green/65000.0,color.blue/65000.0, 1.0)
103
- end
104
- def draw(ctx,h,t)
105
- ctx.move_to(h.first,h[1])
106
- t.each {|x,y,*q| ctx.line_to(x,y) }
107
- ctx.stroke
108
- end
109
- def plot_label(index,ctx)
110
- style(ctx,3,$fgcolor[index])
111
- ctx.move_to(5+60*index,HHEAD-5)
112
- ctx.show_text(@label)
113
- end
114
- end
115
-
116
-
117
- def run(app)
118
- $str=$stdin.gets
119
- if $str
120
- p $str if $DEBUG
121
- Measure.scan_line($str)
122
- gui_invoke { @cv.redraw }
123
- else
124
- exit!(0)
125
- end
126
- end
127
-
128
- def run_window()
129
- Ruiby.app width: W, height: H, title: "Curve" do
130
- stack do
131
- @cv=canvas(W,H) do
132
- on_canvas_draw { |w,ctx| expose(w,ctx) }
133
- end
134
- popup(@cv) do
135
- pp_item(" Plot ") { }
136
- pp_separator
137
- pp_item("htop") { system("lxterminal", "-e", "htop") }
138
- pp_item("Gnome Monitor") { Process.spawn("gnome-system-monitor") }
139
- pp_item("Terminal") { system("lxterminal") }
140
- pp_separator
141
- pp_item("Exit") { ask("Exit ?") && exit(0) }
142
- end
143
- end
144
- chrome(false)
145
- move($posxy[0],$posxy[1])
146
- @ow,@oh=size
147
- def expose(cv,ctx)
148
- ctx.set_source_rgba($bgcolor.red/65000.0, $bgcolor.green/65000.0, $bgcolor.blue/65000.0, 1)
149
- ctx.rectangle(0,0,W,H)
150
- ctx.fill()
151
- ctx.set_source_rgba($bgcolor.red/65000.0, $bgcolor.green/65000.0, 05+$bgcolor.blue/65000.0, 0.3)
152
- ctx.rectangle(0,0,W,HHEAD)
153
- ctx.fill()
154
- Measure.draw_measures(ctx)
155
- (puts "source modified!!!";exit!(0)) if File.mtime(__FILE__)!=$mtime
156
- end
157
- $mtime=File.mtime(__FILE__)
158
-
159
- Thread.new(self) { |app| loop { run(app) } }
160
- end
161
- end
162
-
163
- ############################### Main #################################
164
-
165
- if $0==__FILE__
166
- trap("TERM") { exit!(0) }
167
-
168
- PAS=2
169
- HHEAD=20
170
- $posxy=[0,0]
171
-
172
- if ARGV.size>=2 && ARGV[0]=="--pos"
173
- _,posxy=ARGV.shift,ARGV.shift
174
- $posxy=posxy.split(/[x,:]/).map(&:to_i)
175
- end
176
- if ARGV.size>=2 && ARGV[0]=="--dim"
177
- _,geom=ARGV.shift,ARGV.shift
178
- W,H=geom.split(/[x,:]/).map(&:to_i)
179
- else
180
- W,H=200,100
181
- end
182
-
183
- while ARGV.size>0
184
- argv=[]
185
- argv << ARGV.shift while ARGV.size>0 && ARGV.first!="--"
186
- Measure.create(argv)
187
- ARGV.shift if ARGV.size>0 && ARGV.first=="--"
188
- end
189
- run_window
190
- end