minitcp 0.10.0 → 0.15.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 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