cyberarm_engine 0.24.4 → 0.24.5

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 (93) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +8 -8
  3. data/.rubocop.yml +7 -7
  4. data/.travis.yml +5 -5
  5. data/Gemfile +6 -6
  6. data/Gemfile.lock +24 -0
  7. data/LICENSE.txt +21 -21
  8. data/README.md +74 -74
  9. data/Rakefile +10 -10
  10. data/assets/shaders/fragment/g_buffer.glsl +30 -30
  11. data/assets/shaders/fragment/lighting.glsl +115 -69
  12. data/assets/shaders/include/light_struct.glsl +11 -11
  13. data/assets/shaders/include/material_struct.glsl +16 -16
  14. data/assets/shaders/vertex/g_buffer.glsl +28 -28
  15. data/assets/shaders/vertex/lighting.glsl +24 -24
  16. data/bin/console +14 -14
  17. data/bin/setup +8 -8
  18. data/cyberarm_engine.gemspec +36 -36
  19. data/lib/cyberarm_engine/animator.rb +219 -219
  20. data/lib/cyberarm_engine/background.rb +180 -179
  21. data/lib/cyberarm_engine/background_image.rb +93 -93
  22. data/lib/cyberarm_engine/background_nine_slice.rb +142 -142
  23. data/lib/cyberarm_engine/bounding_box.rb +150 -150
  24. data/lib/cyberarm_engine/builtin/intro_state.rb +130 -130
  25. data/lib/cyberarm_engine/cache/download_manager.rb +123 -123
  26. data/lib/cyberarm_engine/cache.rb +4 -4
  27. data/lib/cyberarm_engine/common.rb +128 -128
  28. data/lib/cyberarm_engine/config_file.rb +46 -46
  29. data/lib/cyberarm_engine/console/command.rb +157 -157
  30. data/lib/cyberarm_engine/console/commands/help_command.rb +43 -43
  31. data/lib/cyberarm_engine/console/subcommand.rb +99 -99
  32. data/lib/cyberarm_engine/console.rb +248 -248
  33. data/lib/cyberarm_engine/game_object.rb +244 -244
  34. data/lib/cyberarm_engine/game_state.rb +124 -124
  35. data/lib/cyberarm_engine/gosu_ext/draw_arc.rb +97 -97
  36. data/lib/cyberarm_engine/gosu_ext/draw_circle.rb +30 -30
  37. data/lib/cyberarm_engine/gosu_ext/draw_path.rb +17 -17
  38. data/lib/cyberarm_engine/model/material.rb +21 -21
  39. data/lib/cyberarm_engine/model/{model_object.rb → mesh.rb} +131 -131
  40. data/lib/cyberarm_engine/model/parser.rb +74 -74
  41. data/lib/cyberarm_engine/model/parsers/collada_parser.rb +138 -138
  42. data/lib/cyberarm_engine/model/parsers/wavefront_parser.rb +154 -154
  43. data/lib/cyberarm_engine/model.rb +216 -213
  44. data/lib/cyberarm_engine/model_cache.rb +31 -31
  45. data/lib/cyberarm_engine/notification.rb +82 -82
  46. data/lib/cyberarm_engine/notification_manager.rb +241 -241
  47. data/lib/cyberarm_engine/opengl/light.rb +52 -50
  48. data/lib/cyberarm_engine/opengl/orthographic_camera.rb +46 -46
  49. data/lib/cyberarm_engine/opengl/perspective_camera.rb +41 -38
  50. data/lib/cyberarm_engine/opengl/renderer/bounding_box_renderer.rb +249 -249
  51. data/lib/cyberarm_engine/opengl/renderer/g_buffer.rb +167 -165
  52. data/lib/cyberarm_engine/opengl/renderer/opengl_renderer.rb +307 -304
  53. data/lib/cyberarm_engine/opengl/renderer/renderer.rb +33 -33
  54. data/lib/cyberarm_engine/opengl/shader.rb +408 -406
  55. data/lib/cyberarm_engine/opengl/texture.rb +69 -69
  56. data/lib/cyberarm_engine/opengl.rb +53 -40
  57. data/lib/cyberarm_engine/ray.rb +56 -56
  58. data/lib/cyberarm_engine/stats.rb +200 -200
  59. data/lib/cyberarm_engine/text.rb +260 -260
  60. data/lib/cyberarm_engine/timer.rb +23 -23
  61. data/lib/cyberarm_engine/transform.rb +296 -296
  62. data/lib/cyberarm_engine/trees/aabb_node.rb +126 -0
  63. data/lib/cyberarm_engine/trees/aabb_tree.rb +55 -0
  64. data/lib/cyberarm_engine/trees/aabb_tree_debug.rb +29 -0
  65. data/lib/cyberarm_engine/ui/border_canvas.rb +102 -102
  66. data/lib/cyberarm_engine/ui/dsl.rb +142 -142
  67. data/lib/cyberarm_engine/ui/element.rb +662 -662
  68. data/lib/cyberarm_engine/ui/elements/button.rb +100 -100
  69. data/lib/cyberarm_engine/ui/elements/check_box.rb +54 -54
  70. data/lib/cyberarm_engine/ui/elements/container.rb +404 -404
  71. data/lib/cyberarm_engine/ui/elements/edit_box.rb +179 -179
  72. data/lib/cyberarm_engine/ui/elements/edit_line.rb +297 -297
  73. data/lib/cyberarm_engine/ui/elements/flow.rb +15 -15
  74. data/lib/cyberarm_engine/ui/elements/image.rb +72 -72
  75. data/lib/cyberarm_engine/ui/elements/list_box.rb +79 -79
  76. data/lib/cyberarm_engine/ui/elements/menu.rb +27 -27
  77. data/lib/cyberarm_engine/ui/elements/menu_item.rb +6 -6
  78. data/lib/cyberarm_engine/ui/elements/progress.rb +93 -93
  79. data/lib/cyberarm_engine/ui/elements/radio.rb +6 -6
  80. data/lib/cyberarm_engine/ui/elements/slider.rb +107 -107
  81. data/lib/cyberarm_engine/ui/elements/stack.rb +11 -11
  82. data/lib/cyberarm_engine/ui/elements/text_block.rb +216 -216
  83. data/lib/cyberarm_engine/ui/elements/toggle_button.rb +67 -67
  84. data/lib/cyberarm_engine/ui/event.rb +54 -54
  85. data/lib/cyberarm_engine/ui/gui_state.rb +321 -321
  86. data/lib/cyberarm_engine/ui/style.rb +50 -50
  87. data/lib/cyberarm_engine/ui/theme.rb +225 -225
  88. data/lib/cyberarm_engine/vector.rb +312 -312
  89. data/lib/cyberarm_engine/version.rb +4 -4
  90. data/lib/cyberarm_engine/window.rb +195 -195
  91. data/lib/cyberarm_engine.rb +70 -78
  92. data/mrbgem.rake +29 -29
  93. metadata +8 -7
@@ -1,131 +1,131 @@
1
- module CyberarmEngine
2
- class IntroState < CyberarmEngine::GameState
3
- def setup
4
- @display_width = 800
5
- @display_height = 600
6
-
7
- @title_size = 56
8
- @caption_size = 24
9
-
10
- @title = CyberarmEngine::Text.new("", size: @title_size, shadow_color: 0xaa_222222, static: true)
11
- @caption = CyberarmEngine::Text.new("", size: @caption_size, shadow_color: 0xaa_222222, static: true)
12
-
13
- @spacer_width = 256
14
- @spacer_height = 6
15
- @padding = 6
16
-
17
- @cyberarm_engine_logo = get_image "#{CYBERARM_ENGINE_ROOT_PATH}/assets/textures/logo.png"
18
-
19
- @gosu_logo = generate_proxy("Gosu", "Game Library", 0xff_111111)
20
- @ruby_logo = generate_proxy("Ruby", "Programming Language", 0xff_880000)
21
- @opengl_logo = generate_proxy("OpenGL", "Graphics API", 0xff_5586a4) if RUBY_ENGINE != "mruby" && defined?(OpenGL)
22
-
23
- base_time = Gosu.milliseconds
24
-
25
- @born_time = Gosu.milliseconds
26
- @continue_after = 5_000
27
-
28
- @animators = [
29
- Animator.new(start_time: base_time += 1000, duration: 100, from: 0.0, to: 1.0, tween: :ease_in_out),
30
- Animator.new(start_time: base_time += -500, duration: 1_000, from: 0.0, to: 1.0, tween: :ease_in_out),
31
- Animator.new(start_time: base_time += 500, duration: 1_000, from: 0.0, to: 1.0, tween: :ease_in_out),
32
- Animator.new(start_time: base_time += 500, duration: 1_000, from: 0.0, to: 1.0, tween: :ease_in_out),
33
- Animator.new(start_time: base_time + 500, duration: 1_000, from: 0.0, to: 1.0, tween: :ease_in_out),
34
- Animator.new(start_time: Gosu.milliseconds + @continue_after - 1_000, duration: 1_000, from: 0.0, to: 1.0, tween: :ease_in_out),
35
-
36
- Animator.new(start_time: Gosu.milliseconds + 250, duration: 500, from: 0.0, to: 1.0, tween: :swing_to) # CyberarmEngine LOGO
37
- ]
38
- end
39
-
40
- def draw
41
- Gosu.draw_rect(0, 0, window.width, window.height, 0xff_222222)
42
-
43
- scale = (@display_width - @padding * 2).to_f / @cyberarm_engine_logo.width * @animators.last.transition
44
-
45
- @cyberarm_engine_logo.draw_rot(
46
- window.width / 2,
47
- (window.height) / 2 - @cyberarm_engine_logo.height / 2 - @padding * 2,
48
- 2,
49
- 0,
50
- 0.5,
51
- 0.5,
52
- scale,
53
- scale
54
- )
55
-
56
- Gosu.draw_rect(
57
- window.width / 2 - (@display_width / 2 + @padding),
58
- window.height / 2 - @spacer_height / 2,
59
- @display_width + @padding,
60
- @spacer_height * @animators[0].transition,
61
- Gosu::Color::WHITE
62
- )
63
-
64
- @title.x = window.width / 2 - @title.text_width / 2
65
- @title.y = (window.height / 2 + (@spacer_height / 2) + @padding) * @animators[1].transition
66
- @title.text = "Powered By"
67
-
68
- Gosu.clip_to(0, window.height / 2 + (@spacer_height / 2), window.width, @title.height) do
69
- @title.draw
70
- end
71
-
72
- y = @title.y + @title.height * 2
73
-
74
- Gosu.clip_to(0, y, window.width, @gosu_logo.height) do
75
- Gosu.translate(@opengl_logo.nil? ? @ruby_logo.width / 2 : 0, 0) do
76
- @gosu_logo.draw(
77
- window.width.to_f / 2 - @ruby_logo.width / 2 - (@ruby_logo.width - @padding),
78
- y * @animators[2].transition,
79
- 2
80
- )
81
- @ruby_logo.draw(
82
- window.width.to_f / 2 - @ruby_logo.width / 2,
83
- y * @animators[3].transition,
84
- 2
85
- )
86
- @opengl_logo&.draw(
87
- window.width.to_f / 2 - @ruby_logo.width / 2 + (@ruby_logo.width - @padding),
88
- y * @animators[4].transition,
89
- 2
90
- )
91
- end
92
- end
93
-
94
- Gosu.draw_rect(0, 0, window.width, window.height, Gosu::Color.rgba(0, 0, 0, 255 * @animators[5].transition), 10_000)
95
- end
96
-
97
- def update
98
- @animators.each(&:update)
99
-
100
- return unless Gosu.milliseconds - @born_time >= @continue_after
101
-
102
- pop_state
103
- push_state(@options[:forward], @options[:forward_options] || {}) if @options[:forward]
104
- end
105
-
106
- def button_down(_id)
107
- @continue_after = 0
108
- end
109
-
110
- def generate_proxy(title, caption, color_hint)
111
- @title.text = title
112
- @caption.text = caption
113
-
114
- width = @spacer_width + 2 * @padding
115
- height = @title_size + @caption_size + @spacer_height + 2 * @padding + @spacer_height
116
-
117
- Gosu.record(width.ceil, height.ceil) do
118
- @title.x = (width - @padding * 2) / 2 - @title.text_width / 2
119
- @title.y = @padding
120
- @title.draw
121
-
122
- Gosu.draw_rect(0, @padding + @title_size + @padding, @spacer_width, @spacer_height, Gosu::Color::WHITE)
123
- Gosu.draw_rect(1, @padding + @title_size + @padding + 1, @spacer_width - 2, @spacer_height - 2, color_hint)
124
-
125
- @caption.x = (width - @padding * 2) / 2 - @caption.text_width / 2
126
- @caption.y = @padding + @title_size + @padding + @spacer_height + @padding
127
- @caption.draw
128
- end
129
- end
130
- end
1
+ module CyberarmEngine
2
+ class IntroState < CyberarmEngine::GameState
3
+ def setup
4
+ @display_width = 800
5
+ @display_height = 600
6
+
7
+ @title_size = 56
8
+ @caption_size = 24
9
+
10
+ @title = CyberarmEngine::Text.new("", size: @title_size, shadow_color: 0xaa_222222, static: true)
11
+ @caption = CyberarmEngine::Text.new("", size: @caption_size, shadow_color: 0xaa_222222, static: true)
12
+
13
+ @spacer_width = 256
14
+ @spacer_height = 6
15
+ @padding = 6
16
+
17
+ @cyberarm_engine_logo = get_image "#{CYBERARM_ENGINE_ROOT_PATH}/assets/textures/logo.png"
18
+
19
+ @gosu_logo = generate_proxy("Gosu", "Game Library", 0xff_111111)
20
+ @ruby_logo = generate_proxy("Ruby", "Programming Language", 0xff_880000)
21
+ @opengl_logo = generate_proxy("OpenGL", "Graphics API", 0xff_5586a4) if RUBY_ENGINE != "mruby" && defined?(OpenGL)
22
+
23
+ base_time = Gosu.milliseconds
24
+
25
+ @born_time = Gosu.milliseconds
26
+ @continue_after = 5_000
27
+
28
+ @animators = [
29
+ Animator.new(start_time: base_time += 1000, duration: 100, from: 0.0, to: 1.0, tween: :ease_in_out),
30
+ Animator.new(start_time: base_time += -500, duration: 1_000, from: 0.0, to: 1.0, tween: :ease_in_out),
31
+ Animator.new(start_time: base_time += 500, duration: 1_000, from: 0.0, to: 1.0, tween: :ease_in_out),
32
+ Animator.new(start_time: base_time += 500, duration: 1_000, from: 0.0, to: 1.0, tween: :ease_in_out),
33
+ Animator.new(start_time: base_time + 500, duration: 1_000, from: 0.0, to: 1.0, tween: :ease_in_out),
34
+ Animator.new(start_time: Gosu.milliseconds + @continue_after - 1_000, duration: 1_000, from: 0.0, to: 1.0, tween: :ease_in_out),
35
+
36
+ Animator.new(start_time: Gosu.milliseconds + 250, duration: 500, from: 0.0, to: 1.0, tween: :swing_to) # CyberarmEngine LOGO
37
+ ]
38
+ end
39
+
40
+ def draw
41
+ Gosu.draw_rect(0, 0, window.width, window.height, 0xff_222222)
42
+
43
+ scale = (@display_width - @padding * 2).to_f / @cyberarm_engine_logo.width * @animators.last.transition
44
+
45
+ @cyberarm_engine_logo.draw_rot(
46
+ window.width / 2,
47
+ (window.height) / 2 - @cyberarm_engine_logo.height / 2 - @padding * 2,
48
+ 2,
49
+ 0,
50
+ 0.5,
51
+ 0.5,
52
+ scale,
53
+ scale
54
+ )
55
+
56
+ Gosu.draw_rect(
57
+ window.width / 2 - (@display_width / 2 + @padding),
58
+ window.height / 2 - @spacer_height / 2,
59
+ @display_width + @padding,
60
+ @spacer_height * @animators[0].transition,
61
+ Gosu::Color::WHITE
62
+ )
63
+
64
+ @title.x = window.width / 2 - @title.text_width / 2
65
+ @title.y = (window.height / 2 + (@spacer_height / 2) + @padding) * @animators[1].transition
66
+ @title.text = "Powered By"
67
+
68
+ Gosu.clip_to(0, window.height / 2 + (@spacer_height / 2), window.width, @title.height) do
69
+ @title.draw
70
+ end
71
+
72
+ y = @title.y + @title.height * 2
73
+
74
+ Gosu.clip_to(0, y, window.width, @gosu_logo.height) do
75
+ Gosu.translate(@opengl_logo.nil? ? @ruby_logo.width / 2 : 0, 0) do
76
+ @gosu_logo.draw(
77
+ window.width.to_f / 2 - @ruby_logo.width / 2 - (@ruby_logo.width - @padding),
78
+ y * @animators[2].transition,
79
+ 2
80
+ )
81
+ @ruby_logo.draw(
82
+ window.width.to_f / 2 - @ruby_logo.width / 2,
83
+ y * @animators[3].transition,
84
+ 2
85
+ )
86
+ @opengl_logo&.draw(
87
+ window.width.to_f / 2 - @ruby_logo.width / 2 + (@ruby_logo.width - @padding),
88
+ y * @animators[4].transition,
89
+ 2
90
+ )
91
+ end
92
+ end
93
+
94
+ Gosu.draw_rect(0, 0, window.width, window.height, Gosu::Color.rgba(0, 0, 0, 255 * @animators[5].transition), 10_000)
95
+ end
96
+
97
+ def update
98
+ @animators.each(&:update)
99
+
100
+ return unless Gosu.milliseconds - @born_time >= @continue_after
101
+
102
+ pop_state
103
+ push_state(@options[:forward], @options[:forward_options] || {}) if @options[:forward]
104
+ end
105
+
106
+ def button_down(_id)
107
+ @continue_after = 0
108
+ end
109
+
110
+ def generate_proxy(title, caption, color_hint)
111
+ @title.text = title
112
+ @caption.text = caption
113
+
114
+ width = @spacer_width + 2 * @padding
115
+ height = @title_size + @caption_size + @spacer_height + 2 * @padding + @spacer_height
116
+
117
+ Gosu.record(width.ceil, height.ceil) do
118
+ @title.x = (width - @padding * 2) / 2 - @title.text_width / 2
119
+ @title.y = @padding
120
+ @title.draw
121
+
122
+ Gosu.draw_rect(0, @padding + @title_size + @padding, @spacer_width, @spacer_height, Gosu::Color::WHITE)
123
+ Gosu.draw_rect(1, @padding + @title_size + @padding + 1, @spacer_width - 2, @spacer_height - 2, color_hint)
124
+
125
+ @caption.x = (width - @padding * 2) / 2 - @caption.text_width / 2
126
+ @caption.y = @padding + @title_size + @padding + @spacer_height + @padding
127
+ @caption.draw
128
+ end
129
+ end
130
+ end
131
131
  end
@@ -1,123 +1,123 @@
1
- require "excon"
2
-
3
- module CyberarmEngine
4
- module Cache
5
- class DownloadManager
6
- attr_reader :downloads
7
-
8
- def initialize(max_parallel_downloads: 4)
9
- @max_parallel_downloads = max_parallel_downloads
10
- @downloads = []
11
- end
12
-
13
- def download(url:, save_as: nil, &callback)
14
- uri = URI(url)
15
- save_as ||= "filename_path" # TODO: if no save_as path is provided, then get one from the Cache controller
16
-
17
- @downloads << Download.new(uri: uri, save_as: save_as, callback: callback)
18
- end
19
-
20
- def status
21
- if active_downloads > 0
22
- :busy
23
- else
24
- :idle
25
- end
26
- end
27
-
28
- def progress
29
- remaining_bytes = @downloads.map { |d| d.remaining_bytes }.sum
30
- total_bytes = @downloads.map { |d| d.total_bytes }.sum
31
-
32
- v = 1.0 - (remaining_bytes.to_f / total_bytes)
33
- return 0.0 if v.nan?
34
-
35
- v
36
- end
37
-
38
- def active_downloads
39
- @downloads.select { |d| %i[pending downloading].include?(d.status) }
40
- end
41
-
42
- def update
43
- @downloads.each do |download|
44
- if download.status == :pending && active_downloads.size <= @max_parallel_downloads
45
- download.status = :downloading
46
- Thread.start { download.download }
47
- end
48
- end
49
- end
50
-
51
- def prune
52
- @downloads.delete_if { |d| d.status == :finished || d.status == :failed }
53
- end
54
-
55
- class Download
56
- attr_accessor :status
57
- attr_reader :uri, :save_as, :callback, :remaining_bytes, :total_downloaded_bytes, :total_bytes,
58
- :error_message, :started_at, :finished_at
59
-
60
- def initialize(uri:, save_as:, callback: nil)
61
- @uri = uri
62
- @save_as = save_as
63
- @callback = callback
64
-
65
- @status = :pending
66
-
67
- @remaining_bytes = 0.0
68
- @total_downloaded_bytes = 0.0
69
- @total_bytes = 0.0
70
-
71
- @error_message = ""
72
- end
73
-
74
- def progress
75
- v = 1.0 - (@remaining_bytes.to_f / total_bytes)
76
- return 0.0 if v.nan?
77
-
78
- v
79
- end
80
-
81
- def download
82
- @status = :downloading
83
- @started_at = Time.now # TODO: monotonic time
84
-
85
- io = File.open(@save_as, "w")
86
- streamer = lambda do |chunk, remaining_bytes, total_bytes|
87
- io.write(chunk)
88
-
89
- @remaining_bytes = remaining_bytes.to_f
90
- @total_downloaded_bytes += chunk.size
91
- @total_bytes = total_bytes.to_f
92
- end
93
-
94
- begin
95
- response = Excon.get(
96
- @uri.to_s,
97
- middlewares: Excon.defaults[:middlewares] + [Excon::Middleware::RedirectFollower],
98
- response_block: streamer
99
- )
100
-
101
- if response.status == 200
102
- @status = :finished
103
- @finished_at = Time.now # TODO: monotonic time
104
- @callback.call(self) if @callback
105
- else
106
- @error_message = "Got a non 200 HTTP status of #{response.status}"
107
- @status = :failed
108
- @finished_at = Time.now # TODO: monotonic time
109
- @callback.call(self) if @callback
110
- end
111
- rescue StandardError => e # TODO: cherrypick errors to cature
112
- @status = :failed
113
- @finished_at = Time.now # TODO: monotonic time
114
- @error_message = e.message
115
- @callback.call(self) if @callback
116
- end
117
- ensure
118
- io.close if io
119
- end
120
- end
121
- end
122
- end
123
- end
1
+ require "excon"
2
+
3
+ module CyberarmEngine
4
+ module Cache
5
+ class DownloadManager
6
+ attr_reader :downloads
7
+
8
+ def initialize(max_parallel_downloads: 4)
9
+ @max_parallel_downloads = max_parallel_downloads
10
+ @downloads = []
11
+ end
12
+
13
+ def download(url:, save_as: nil, &callback)
14
+ uri = URI(url)
15
+ save_as ||= "filename_path" # TODO: if no save_as path is provided, then get one from the Cache controller
16
+
17
+ @downloads << Download.new(uri: uri, save_as: save_as, callback: callback)
18
+ end
19
+
20
+ def status
21
+ if active_downloads > 0
22
+ :busy
23
+ else
24
+ :idle
25
+ end
26
+ end
27
+
28
+ def progress
29
+ remaining_bytes = @downloads.map { |d| d.remaining_bytes }.sum
30
+ total_bytes = @downloads.map { |d| d.total_bytes }.sum
31
+
32
+ v = 1.0 - (remaining_bytes.to_f / total_bytes)
33
+ return 0.0 if v.nan?
34
+
35
+ v
36
+ end
37
+
38
+ def active_downloads
39
+ @downloads.select { |d| %i[pending downloading].include?(d.status) }
40
+ end
41
+
42
+ def update
43
+ @downloads.each do |download|
44
+ if download.status == :pending && active_downloads.size <= @max_parallel_downloads
45
+ download.status = :downloading
46
+ Thread.start { download.download }
47
+ end
48
+ end
49
+ end
50
+
51
+ def prune
52
+ @downloads.delete_if { |d| d.status == :finished || d.status == :failed }
53
+ end
54
+
55
+ class Download
56
+ attr_accessor :status
57
+ attr_reader :uri, :save_as, :callback, :remaining_bytes, :total_downloaded_bytes, :total_bytes,
58
+ :error_message, :started_at, :finished_at
59
+
60
+ def initialize(uri:, save_as:, callback: nil)
61
+ @uri = uri
62
+ @save_as = save_as
63
+ @callback = callback
64
+
65
+ @status = :pending
66
+
67
+ @remaining_bytes = 0.0
68
+ @total_downloaded_bytes = 0.0
69
+ @total_bytes = 0.0
70
+
71
+ @error_message = ""
72
+ end
73
+
74
+ def progress
75
+ v = 1.0 - (@remaining_bytes.to_f / total_bytes)
76
+ return 0.0 if v.nan?
77
+
78
+ v
79
+ end
80
+
81
+ def download
82
+ @status = :downloading
83
+ @started_at = Time.now # TODO: monotonic time
84
+
85
+ io = File.open(@save_as, "w")
86
+ streamer = lambda do |chunk, remaining_bytes, total_bytes|
87
+ io.write(chunk)
88
+
89
+ @remaining_bytes = remaining_bytes.to_f
90
+ @total_downloaded_bytes += chunk.size
91
+ @total_bytes = total_bytes.to_f
92
+ end
93
+
94
+ begin
95
+ response = Excon.get(
96
+ @uri.to_s,
97
+ middlewares: Excon.defaults[:middlewares] + [Excon::Middleware::RedirectFollower],
98
+ response_block: streamer
99
+ )
100
+
101
+ if response.status == 200
102
+ @status = :finished
103
+ @finished_at = Time.now # TODO: monotonic time
104
+ @callback.call(self) if @callback
105
+ else
106
+ @error_message = "Got a non 200 HTTP status of #{response.status}"
107
+ @status = :failed
108
+ @finished_at = Time.now # TODO: monotonic time
109
+ @callback.call(self) if @callback
110
+ end
111
+ rescue StandardError => e # TODO: cherrypick errors to cature
112
+ @status = :failed
113
+ @finished_at = Time.now # TODO: monotonic time
114
+ @error_message = e.message
115
+ @callback.call(self) if @callback
116
+ end
117
+ ensure
118
+ io.close if io
119
+ end
120
+ end
121
+ end
122
+ end
123
+ end
@@ -1,4 +1,4 @@
1
- module CyberarmEngine
2
- module Cache
3
- end
4
- end
1
+ module CyberarmEngine
2
+ module Cache
3
+ end
4
+ end