ease_engine 0.0.19

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.
Files changed (60) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +25 -0
  3. data/.travis.yml +3 -0
  4. data/Gemfile +4 -0
  5. data/README.md +33 -0
  6. data/Rakefile +1 -0
  7. data/benchmark/echo/echo_client.rb +90 -0
  8. data/benchmark/echo/echo_packet.rb +9 -0
  9. data/benchmark/echo/echo_server.rb +48 -0
  10. data/benchmark/fps.rb +23 -0
  11. data/benchmark/http.rb +9 -0
  12. data/benchmark/loop/Makefile +39 -0
  13. data/benchmark/loop/Makefile.rb +11 -0
  14. data/benchmark/loop/Rakefile +42 -0
  15. data/benchmark/loop/loop.c +38 -0
  16. data/benchmark/loop/loop.cs +33 -0
  17. data/benchmark/loop/loop.go +33 -0
  18. data/benchmark/loop/loop.js +23 -0
  19. data/benchmark/loop/loop.php +22 -0
  20. data/benchmark/loop/loop.rb +19 -0
  21. data/benchmark/loop/loop.scala +30 -0
  22. data/benchmark/loop/loop_c +0 -0
  23. data/benchmark/loop/loop_cs +0 -0
  24. data/benchmark/loop/loop_go +0 -0
  25. data/benchmark/measure/measure_client.rb +76 -0
  26. data/benchmark/measure/measure_server.rb +47 -0
  27. data/benchmark/process.rb +3 -0
  28. data/benchmark/tcp/tcp_client.rb +45 -0
  29. data/benchmark/tcp/tcp_server.rb +40 -0
  30. data/benchmark/udp/udp_client.rb +84 -0
  31. data/benchmark/udp/udp_packet.rb +40 -0
  32. data/benchmark/udp/udp_server.rb +33 -0
  33. data/bin/console +14 -0
  34. data/bin/setup +7 -0
  35. data/ease_engine.gemspec +27 -0
  36. data/lib/ease_engine.rb +35 -0
  37. data/lib/ease_engine/application.rb +269 -0
  38. data/lib/ease_engine/buffer.rb +25 -0
  39. data/lib/ease_engine/data.rb +158 -0
  40. data/lib/ease_engine/frame.rb +38 -0
  41. data/lib/ease_engine/http.rb +42 -0
  42. data/lib/ease_engine/log.rb +109 -0
  43. data/lib/ease_engine/measure.rb +25 -0
  44. data/lib/ease_engine/packet.rb +150 -0
  45. data/lib/ease_engine/platform.rb +19 -0
  46. data/lib/ease_engine/process.rb +31 -0
  47. data/lib/ease_engine/socket.rb +174 -0
  48. data/lib/ease_engine/time.rb +22 -0
  49. data/lib/ease_engine/timer.rb +72 -0
  50. data/lib/ease_engine/version.rb +3 -0
  51. data/lib/ease_engine/watcher.rb +95 -0
  52. data/types/Rakefile +83 -0
  53. data/types/csharp/EaseEngine.cs +39 -0
  54. data/types/csharp/EaseEngine/Buffer.cs +49 -0
  55. data/types/csharp/EaseEngine/Measure.cs +47 -0
  56. data/types/csharp/EaseEngine/Time.cs +41 -0
  57. data/types/csharp/EaseEngine/Version.cs +7 -0
  58. data/types/csharp/Unity/Assets/Menu.cs +56 -0
  59. data/types/csharp/Unity/Assets/Menu.unity +0 -0
  60. metadata +158 -0
@@ -0,0 +1,33 @@
1
+ require "ease_engine"
2
+ require "./udp_packet"
3
+
4
+ class BenchmarkApplication < EaseEngine::Application
5
+ def on_start
6
+ super
7
+
8
+ @is_update = true
9
+ EaseEngine::Frame.fps = 60
10
+
11
+ host = ARGV[ 0 ]
12
+ port = ARGV[ 1 ].to_i
13
+
14
+ udp_socket = EaseEngine::UDPSocket.new
15
+ udp_socket.bind( host, port )
16
+ add_socket( udp_socket )
17
+
18
+ EE_LOG_DBG.call "host=#{host} port=#{port}"
19
+ end
20
+
21
+ def on_update
22
+ if 1000000 <= @measure.check
23
+ EE_LOG_DBG.call "watcher.size=#{@watcher.size} update_usec=#{@measure.update_usec} count=#{@measure.count}"
24
+
25
+ @measure.start
26
+ end
27
+ end
28
+
29
+ def on_read_socket( socket, packet )
30
+ write_packet( socket, packet, 0 )
31
+ end
32
+ end
33
+ BenchmarkApplication::run
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "ease_engine"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,27 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'ease_engine/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "ease_engine"
8
+ spec.version = EaseEngine::VERSION
9
+ spec.authors = ["liveralmask"]
10
+ spec.email = ["liveralmask.lisk@gmail.com"]
11
+ spec.license = "MIT"
12
+
13
+ spec.summary = %q{Easy application programming scripts.}
14
+ spec.description = %q{Easy application programming scripts.}
15
+ spec.homepage = "https://github.com/liveralmask/ease_engine"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
+ spec.bindir = "exe"
19
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
+ spec.require_paths = ["lib"]
21
+
22
+ spec.add_development_dependency "bundler", "~> 1.9"
23
+ spec.add_development_dependency "rake", "~> 10.0"
24
+
25
+ spec.add_dependency "cool.io"
26
+ spec.add_dependency "msgpack"
27
+ end
@@ -0,0 +1,35 @@
1
+ require "ease_engine/version"
2
+ require "ease_engine/application"
3
+
4
+ module EaseEngine
5
+ def self.assert( result, *args )
6
+ if ! result
7
+ args = [ "Assert" ] if 0 == args.length
8
+ raise sprintf( *args )
9
+ end
10
+ end
11
+
12
+ def self.rotate( min, max, value, add )
13
+ return min if value < min || max < value
14
+
15
+ value += add
16
+ ( value < min || max < value ) ? min : value
17
+ end
18
+
19
+ def self.trace_info( trace = 0 )
20
+ trace = caller[ trace ] if ! trace.instance_of?( String )
21
+
22
+ info = {
23
+ :file => "",
24
+ :line => 0,
25
+ :method => "",
26
+ }
27
+ if /^(.+?):(\d+)(?::in `(.*)')?/ =~ trace
28
+ info[ :file ] = $1
29
+ info[ :line ] = $2.to_i
30
+ info[ :method ] = $3
31
+ end
32
+ info[ :str ] = "#{info[ :file ]}:#{info[ :line ]} #{info[ :method ]}"
33
+ info
34
+ end
35
+ end
@@ -0,0 +1,269 @@
1
+ require "ease_engine/measure"
2
+ require "ease_engine/frame"
3
+ require "ease_engine/watcher"
4
+ require "ease_engine/packet"
5
+ require "ease_engine/log"
6
+ require "ease_engine/http"
7
+ require "ease_engine/process"
8
+ require "ease_engine/platform"
9
+ require "ease_engine/timer"
10
+
11
+ module EaseEngine
12
+ class Application
13
+ def self.run( options = {} )
14
+ EaseEngine::Log.inf( "EaseEngine #{EaseEngine::VERSION} options=#{options}" )
15
+ application = new( options )
16
+ begin
17
+ application.on_start
18
+ rescue => err
19
+ application.on_error( err )
20
+
21
+ application.is_update = false
22
+ end
23
+
24
+ while application.is_update
25
+ begin
26
+ EaseEngine::Frame.update{|sleep_time_usec, sleep_time_f|
27
+ application.watcher.watch( sleep_time_f )
28
+ }
29
+ application.timer.update
30
+ application.socket_timer.update
31
+ application.on_update
32
+ rescue => err
33
+ application.on_error( err )
34
+ end
35
+ end
36
+
37
+ begin
38
+ application.on_end
39
+ rescue => err
40
+ application.on_error( err )
41
+ end
42
+
43
+ application.exit_status
44
+ end
45
+
46
+ attr_accessor :options
47
+ attr_accessor :exit_status, :is_update
48
+ attr_accessor :watcher, :measure
49
+ attr_accessor :timer, :socket_timer
50
+ attr_accessor :is_daemon
51
+
52
+ def initialize( options )
53
+ @options = options
54
+ if ! @options.key?( :watcher )
55
+ @options[ :watcher ] = {}
56
+ end
57
+ if ! @options.key?( :timer )
58
+ @options[ :timer ] = {}
59
+ end
60
+ if ! @options.key?( :socket_timer )
61
+ @options[ :socket_timer ] = {
62
+ :connect_timeout_usec => 10000000,
63
+ :connected_timeout_usec => 10000000,
64
+ }
65
+ end
66
+ @options[ :is_daemon ] = false if ! @options.key?( :is_daemon )
67
+
68
+ @exit_status = 0
69
+ @is_update = false
70
+
71
+ @watcher = EaseEngine::Watcher.new( @options[ :watcher ] )
72
+ @measure = EaseEngine::Measure.new
73
+ @timer = EaseEngine::Timer.new( @options[ :timer ] )
74
+ @socket_timer = EaseEngine::Timer.new( @options[ :socket_timer ] )
75
+
76
+ @is_daemon = @options[ :is_daemon ]
77
+ end
78
+
79
+ def on_start
80
+ trap( :INT ){
81
+ @is_update = false
82
+ @exit_status = :INT
83
+ }
84
+
85
+ trap( :TERM ){
86
+ @is_update = false
87
+ @exit_status = :TERM
88
+ }
89
+
90
+ trap( :PIPE ){}
91
+ end
92
+
93
+ def on_update
94
+ end
95
+
96
+ def on_end
97
+ @watcher.each{|info|
98
+ @watcher.remove( info.io )
99
+ }
100
+ end
101
+
102
+ def on_accept_socket( socket )
103
+ accepted_socket = socket.accept
104
+ if ! socket.err.nil?
105
+ on_error_socket( socket )
106
+ return
107
+ end
108
+
109
+ add_socket( accepted_socket )
110
+ on_accepted_socket( accepted_socket, socket )
111
+ end
112
+
113
+ def on_accepted_socket( accepted_socket, server_socket )
114
+ end
115
+
116
+ def on_connected_socket( socket )
117
+ end
118
+
119
+ def on_read_socket( socket, packet )
120
+ end
121
+
122
+ def on_close_socket( socket )
123
+ end
124
+
125
+ def on_timeout_socket( socket )
126
+ EaseEngine::Log.wrn( "on_timeout_socket #{socket}" )
127
+ end
128
+
129
+ def on_error_socket( socket )
130
+ EaseEngine::Log.err( "on_error_socket #{socket} #{socket.err.class.name}: #{socket.err}\n#{socket.err.backtrace}" )
131
+ end
132
+
133
+ def on_error( err )
134
+ EaseEngine::Log.err( "on_error #{err.class.name}: #{err}\n#{err.backtrace}" )
135
+ end
136
+
137
+ def add_server_socket( socket )
138
+ application = self
139
+ @watcher.add( socket, {
140
+ :on_read => Proc.new{|socket|
141
+ application.on_accept_socket( socket )
142
+ },
143
+ :on_remove => Proc.new{|socket|
144
+ application.close_socket( socket )
145
+ }
146
+ })
147
+ end
148
+
149
+ def add_socket( socket )
150
+ application = self
151
+ @watcher.add( socket, {
152
+ :on_read => Proc.new{|socket|
153
+ application.read_socket( socket )
154
+ },
155
+ :on_remove => Proc.new{|socket|
156
+ application.close_socket( socket )
157
+ }
158
+ })
159
+ end
160
+
161
+ def add_connect_socket( socket )
162
+ application = self
163
+ @watcher.add( socket, {
164
+ :on_read => Proc.new{|socket|
165
+ socket.err = SystemCallError.new( socket.errno )
166
+ application.on_error_socket( socket )
167
+ application.remove_socket( socket )
168
+ },
169
+ :on_write => Proc.new{|socket|
170
+ application.remove_socket_timer( socket.to_i )
171
+
172
+ socket.err = nil
173
+ application.add_socket( socket )
174
+ application.on_connected_socket( socket )
175
+
176
+ if socket.is_heartbeat
177
+ # connected timeout
178
+ hash = {
179
+ :socket => socket,
180
+ :timeout_usec => @options[ :socket_timer ][ :connected_timeout_usec ],
181
+ }
182
+ hash[ :callback ] = Proc.new{|hash|
183
+ if hash[ :socket ].is_timeout
184
+ application.timeout_socket( hash[ :socket ] )
185
+ next
186
+ end
187
+
188
+ hash[ :socket ].is_timeout = true
189
+ application.write_packet( socket, EaseEngine::HeartbeatBeginPacket.new )
190
+ application.add_socket_timer( hash[ :socket ].to_i, hash[ :timeout_usec ], hash, hash[ :callback ] )
191
+ }
192
+ hash[ :callback ].call( hash )
193
+ end
194
+ },
195
+ :on_remove => Proc.new{|socket|
196
+ application.close_socket( socket )
197
+ }
198
+ })
199
+
200
+ # connect timeout
201
+ add_socket_timer( socket.to_i, @options[ :socket_timer ][ :connect_timeout_usec ], socket, Proc.new{|socket|
202
+ application.timeout_socket( socket )
203
+ })
204
+ end
205
+
206
+ def remove_socket( socket )
207
+ @watcher.remove( socket )
208
+ end
209
+
210
+ def read_socket( socket )
211
+ Packet.creates( socket ).each{|packet|
212
+ case packet.packet_name
213
+ when "EaseEngine.HeartbeatBeginPacket"
214
+ write_packet( socket, EaseEngine::HeartbeatEndPacket.new )
215
+ when "EaseEngine.HeartbeatEndPacket"
216
+ else
217
+ on_read_socket( socket, packet )
218
+ end
219
+ }
220
+ check_socket( socket )
221
+ end
222
+
223
+ def write_packet( socket, packet, flags = 0, *args )
224
+ packet.write( socket, flags, *args )
225
+ end
226
+
227
+ def reflect_socket( socket, recv_flags = 0, send_flags = 0 )
228
+ buf = socket.recv( socket.read_max_size, recv_flags )
229
+ if ! buf.empty?
230
+ result = socket.send( buf, send_flags )
231
+ return if result == buf.length
232
+ EaseEngine::Log.err( "reflect_socket #{result} != #{buf.length}" ) if 0 < result && result != buf.length
233
+ end
234
+ check_socket( socket )
235
+ end
236
+
237
+ def check_socket( socket )
238
+ on_error_socket( socket ) if ! socket.err.nil?
239
+ remove_socket( socket ) if socket.is_disable
240
+ end
241
+
242
+ def timeout_socket( socket )
243
+ on_timeout_socket( socket )
244
+ remove_socket( socket )
245
+ end
246
+
247
+ def close_socket( socket )
248
+ remove_socket_timer( socket.to_i )
249
+ on_close_socket( socket )
250
+ socket.close
251
+ end
252
+
253
+ def add_timer( group_id, timeout_usec, arg, callback )
254
+ @timer.add( group_id, timeout_usec, arg, callback )
255
+ end
256
+
257
+ def remove_timer( group_id, timer_id = 0 )
258
+ @timer.remove( group_id, timer_id )
259
+ end
260
+
261
+ def add_socket_timer( socket_id, timeout_usec, arg, callback )
262
+ @socket_timer.add( socket_id, timeout_usec, arg, callback )
263
+ end
264
+
265
+ def remove_socket_timer( socket_id, timer_id = 0 )
266
+ @socket_timer.remove( socket_id, timer_id )
267
+ end
268
+ end
269
+ end
@@ -0,0 +1,25 @@
1
+ module EaseEngine
2
+ class Buffer
3
+ attr_accessor :value, :size
4
+
5
+ def initialize( value = "" )
6
+ @value = value
7
+ @size = value.length
8
+ end
9
+
10
+ def <<( value )
11
+ if ! value.empty?
12
+ @value << value
13
+ @size += value.length
14
+ end
15
+ @value
16
+ end
17
+
18
+ def >>( size )
19
+ return "" if size <= 0
20
+
21
+ @size -= size
22
+ @value.slice!( 0, size )
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,158 @@
1
+ module EaseEngine
2
+ module Data
3
+ class Hary
4
+ class Info
5
+ attr_accessor :id, :index, :data
6
+
7
+ def initialize( id, index, data )
8
+ @id = id
9
+ @index = index
10
+ @data = data
11
+ end
12
+ end
13
+
14
+ def initialize
15
+ @ary = []
16
+ @indexes = {}
17
+ end
18
+
19
+ def add( id, data )
20
+ if ! @indexes.key?( id )
21
+ info = Info.new( id, @ary.size, data )
22
+ @ary.push info
23
+ @indexes[ id ] = info.index
24
+ else
25
+ info = @ary[ @indexes[ id ] ]
26
+ info.id = id
27
+ info.data = data
28
+ end
29
+
30
+ sort!
31
+ id
32
+ end
33
+
34
+ def remove( id )
35
+ remove_at( @indexes[ id ] ) if @indexes.key?( id )
36
+ end
37
+
38
+ def remove_at( index )
39
+ return nil if @ary.size <= index
40
+
41
+ info = @ary[ index ]
42
+ @ary.delete_at( index )
43
+ @indexes.delete( info.id )
44
+ update if index != @ary.size # 末尾データの削除なら、更新しない
45
+ info.data
46
+ end
47
+
48
+ def get( id )
49
+ @indexes[ id ]
50
+ end
51
+
52
+ def get_at( index )
53
+ ( @ary.size <= index ) ? nil : @ary[ index ]
54
+ end
55
+
56
+ def key?( id )
57
+ @indexes.key?( id )
58
+ end
59
+
60
+ def size
61
+ @ary.size
62
+ end
63
+
64
+ def each
65
+ @ary.each{|info|
66
+ yield info.id, info.index, info.data
67
+ }
68
+ end
69
+
70
+ def update
71
+ @ary.each_with_index{|info, index|
72
+ info.index = index
73
+ @indexes[ info.id ] = index
74
+ }
75
+ end
76
+
77
+ def sort!
78
+ update
79
+ end
80
+ end
81
+
82
+ class Record < Hary
83
+ def initialize( min, max )
84
+ @min = min
85
+ @max = max
86
+ @id = min
87
+
88
+ super()
89
+ end
90
+
91
+ def add( data )
92
+ @id = generate_id( @id )
93
+ return 0 if 0 == @id
94
+
95
+ super( @id, data )
96
+ end
97
+
98
+ protected
99
+ def generate_id( id )
100
+ generated_id = 0
101
+ start_id = id
102
+ begin
103
+ generated_id = id if ! key?( id )
104
+
105
+ id = EaseEngine::rotate( @min, @max, id, 1 )
106
+ end while 0 == generated_id && start_id != id
107
+ generated_id
108
+ end
109
+ end
110
+
111
+ class Group
112
+ def initialize
113
+ @group = {}
114
+ @data = {}
115
+ end
116
+
117
+ def add( group_id, data_id )
118
+ if @group.key?( group_id )
119
+ @group[ group_id ][ data_id ] = group_id
120
+ else
121
+ @group[ group_id ] = {
122
+ data_id => group_id
123
+ }
124
+ end
125
+
126
+ if @data.key?( data_id )
127
+ @data[ data_id ][ group_id ] = data_id
128
+ else
129
+ @data[ data_id ] = {
130
+ group_id => data_id
131
+ }
132
+ end
133
+ end
134
+
135
+ def remove( group_id, data_id )
136
+ if @group.key?( group_id )
137
+ @group[ group_id ].each{|data_id, group_id|
138
+ @data.delete( data_id )
139
+ }
140
+ @group.delete( group_id )
141
+ elsif @data.key?( data_id )
142
+ @data[ data_id ].each{|group_id, data_id|
143
+ @group[ group_id ].delete( data_id )
144
+ }
145
+ @data.delete( data_id )
146
+ end
147
+ end
148
+
149
+ def group( group_id )
150
+ @group.key?( group_id ) ? @group[ group_id ] : {}
151
+ end
152
+
153
+ def data( data_id )
154
+ @data.key?( data_id ) ? @data[ data_id ] : {}
155
+ end
156
+ end
157
+ end
158
+ end