gloo 3.0.1 → 3.1.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.
@@ -0,0 +1,299 @@
1
+ # Author:: Eric Crane (mailto:eric.crane@mac.com)
2
+ # Copyright:: Copyright (c) 2024 Eric Crane. All rights reserved.
3
+ #
4
+ # A web web server running inside gloo.
5
+ #
6
+
7
+ module Gloo
8
+ module Objs
9
+ class Svr < Gloo::Core::Obj
10
+
11
+ KEYWORD = 'server'.freeze
12
+ KEYWORD_SHORT = 'svr'.freeze
13
+
14
+ # Configuration
15
+ SCHEME = 'scheme'.freeze
16
+ HOST = 'host'.freeze
17
+ PORT = 'port'.freeze
18
+
19
+ # Events
20
+ ON_START = 'on_start'.freeze
21
+ ON_STOP = 'on_stop'.freeze
22
+
23
+ # Container with pages in the web app.
24
+ PAGES = 'pages'.freeze
25
+
26
+ # Default layout for pages.
27
+ LAYOUT = 'layout'.freeze
28
+
29
+ # Alias to the home and error pages
30
+ HOME = 'home'.freeze
31
+ ERR_PAGE = 'error'.freeze
32
+
33
+
34
+ # Messages
35
+ SERVER_NOT_RUNNING = 'The web server is not running and cannot be stopped'.freeze
36
+
37
+ #
38
+ # Should the current request be redirected?
39
+ # If the redirect is set, then use that page instead
40
+ # of the one requested.
41
+ #
42
+ attr_accessor :redirect, :router, :asset, :embedded_renderer
43
+
44
+ #
45
+ # The name of the object type.
46
+ #
47
+ def self.typename
48
+ return KEYWORD
49
+ end
50
+
51
+ #
52
+ # The short name of the object type.
53
+ #
54
+ def self.short_typename
55
+ return KEYWORD_SHORT
56
+ end
57
+
58
+ #
59
+ # Set the value with any necessary type conversions.
60
+ #
61
+ def set_value( new_value )
62
+ self.value = new_value.to_s
63
+ end
64
+
65
+ #
66
+ # Does this object support multi-line values?
67
+ # Initially only true for scripts.
68
+ #
69
+ def multiline_value?
70
+ return false
71
+ end
72
+
73
+ #
74
+ # Get the Scheme (http or https) from the child object.
75
+ # Returns nil if there is none.
76
+ #
77
+ def scheme_value
78
+ scheme = find_child SCHEME
79
+ return nil unless scheme
80
+
81
+ return scheme.value
82
+ end
83
+
84
+ #
85
+ # Get the host from the child object.
86
+ # Returns nil if there is none.
87
+ #
88
+ def host_value
89
+ host = find_child HOST
90
+ return nil unless host
91
+
92
+ return host.value
93
+ end
94
+
95
+ #
96
+ # Get the port from the child object.
97
+ # Returns nil if there is none.
98
+ #
99
+ def port_value
100
+ port = find_child PORT
101
+ return nil unless port
102
+
103
+ return port.value
104
+ end
105
+
106
+
107
+ #
108
+ # Get the default layout for the app.
109
+ #
110
+ def default_page_layout
111
+ o = find_child LAYOUT
112
+ return nil unless o
113
+
114
+ o = Gloo::Objs::Alias.resolve_alias( @engine, o )
115
+ return o
116
+ end
117
+
118
+ # ---------------------------------------------------------------------
119
+ # Children
120
+ # ---------------------------------------------------------------------
121
+
122
+ #
123
+ # Does this object have children to add when an object
124
+ # is created in interactive mode?
125
+ # This does not apply during obj load, etc.
126
+ #
127
+ def add_children_on_create?
128
+ return true
129
+ end
130
+
131
+ #
132
+ # Add children to this object.
133
+ # This is used by containers to add children needed
134
+ # for default configurations.
135
+ #
136
+ def add_default_children
137
+ fac = @engine.factory
138
+
139
+ fac.create_string SCHEME, 'http', self
140
+ fac.create_string HOST, 'localhost', self
141
+ fac.create_string PORT, '8080', self
142
+
143
+ fac.create_script ON_START, '', self
144
+ fac.create_script ON_STOP, '', self
145
+
146
+ fac.create_can PAGES, self
147
+ fac.create_can HOME, self
148
+ end
149
+
150
+
151
+ # ---------------------------------------------------------------------
152
+ # Messages
153
+ # ---------------------------------------------------------------------
154
+
155
+ #
156
+ # Get a list of message names that this object receives.
157
+ #
158
+ def self.messages
159
+ return super + [ 'start', 'stop' ]
160
+ end
161
+
162
+ #
163
+ # Start the gloo web server.
164
+ #
165
+ def msg_start
166
+ @engine.log.debug "Starting web server…"
167
+ # @engine.log.quiet = true
168
+
169
+ # Set running app to this object.
170
+ @engine.start_running_app( self )
171
+ # The running app will call the start function (below)
172
+ end
173
+
174
+ #
175
+ # Stop the running web server.
176
+ #
177
+ def msg_stop
178
+ if @web_server
179
+ @engine.stop_running_app
180
+ # The running app will call the stop function (below)
181
+ else
182
+ @engine.log.error SERVER_NOT_RUNNING
183
+ end
184
+ end
185
+
186
+ # ---------------------------------------------------------------------
187
+ # Start and Stop Events
188
+ # Might come from messages or from other application events.
189
+ # RunningApp fires these events.
190
+ # ---------------------------------------------------------------------
191
+
192
+ #
193
+ # Start running the web server.
194
+ #
195
+ def start
196
+ config = Gloo::WebSvr::Config.new( scheme_value, host_value, port_value )
197
+ @engine.log.info "Web Server URL: #{config.base_url}"
198
+
199
+ handler = Gloo::WebSvr::Handler.new( @engine, self )
200
+ @web_server = Gloo::WebSvr::Server.new( @engine, handler, config )
201
+ @web_server.start
202
+
203
+ @router = Gloo::WebSvr::Router.new( @engine, self )
204
+ @router.add_page_routes
205
+
206
+ @asset = Gloo::WebSvr::Asset.new( @engine, self )
207
+ @asset.add_asset_routes
208
+
209
+ @embedded_renderer = Gloo::WebSvr::EmbeddedRenderer.new( @engine, self )
210
+
211
+ run_on_start
212
+ @engine.log.info "Web server started and listening…"
213
+ end
214
+
215
+ #
216
+ # Stop the running web server.
217
+ #
218
+ def stop
219
+ @engine.log.info "Stopping web server…"
220
+ @web_server.stop
221
+ @web_server = nil
222
+
223
+ run_on_stop
224
+ @engine.log.info "Web server stopped…"
225
+ end
226
+
227
+
228
+ # ---------------------------------------------------------------------
229
+ # On Events - Scripts
230
+ # ---------------------------------------------------------------------
231
+
232
+ #
233
+ # Run the on render script if there is one.
234
+ #
235
+ def run_on_start
236
+ o = find_child ON_START
237
+ return unless o
238
+
239
+ Gloo::Exec::Dispatch.message( @engine, 'run', o )
240
+ end
241
+
242
+ #
243
+ # Run the on rendered script if there is one.
244
+ #
245
+ def run_on_stop
246
+ o = find_child ON_STOP
247
+ return unless o
248
+
249
+ Gloo::Exec::Dispatch.message( @engine, 'run', o )
250
+ end
251
+
252
+
253
+ # ---------------------------------------------------------------------
254
+ # Pages and standard elements.
255
+ # ---------------------------------------------------------------------
256
+
257
+ #
258
+ # Get the pages container.
259
+ #
260
+ def pages_container
261
+ return find_child PAGES
262
+ end
263
+
264
+ #
265
+ # Get the home page, the root/default route.
266
+ #
267
+ def home_page
268
+ o = find_child HOME
269
+ return nil unless o
270
+
271
+ o = Gloo::Objs::Alias.resolve_alias( @engine, o )
272
+ return o
273
+ end
274
+
275
+ #
276
+ # Get the application error page.
277
+ #
278
+ def err_page
279
+ o = find_child ERR_PAGE
280
+ return nil unless o
281
+
282
+ o = Gloo::Objs::Alias.resolve_alias( @engine, o )
283
+ return o
284
+ end
285
+
286
+ #
287
+ # Get the default layout for pages.
288
+ #
289
+ def default_layout
290
+ o = find_child LAYOUT
291
+ return nil unless o
292
+
293
+ o = Gloo::Objs::Alias.resolve_alias( @engine, o )
294
+ return o
295
+ end
296
+
297
+ end
298
+ end
299
+ end
@@ -8,7 +8,7 @@ module Gloo
8
8
  module Verbs
9
9
  class Cls < Gloo::Core::Verb
10
10
 
11
- KEYWORD = 'cls'.freeze
11
+ KEYWORD = 'clear'.freeze
12
12
  KEYWORD_SHORT = 'cls'.freeze
13
13
 
14
14
  #
@@ -0,0 +1,56 @@
1
+ # Author:: Eric Crane (mailto:eric.crane@mac.com)
2
+ # Copyright:: Copyright (c) 2024 Eric Crane. All rights reserved.
3
+ #
4
+ # Redirect the web svr request to a different page.
5
+ # This verb only works in context of a running web server.
6
+ #
7
+
8
+ module Gloo
9
+ module Verbs
10
+ class Redirect < Gloo::Core::Verb
11
+
12
+ KEYWORD = 'redirect'.freeze
13
+ KEYWORD_SHORT = 'go'.freeze
14
+
15
+ MISSING_EXPR_ERR = 'Missing Expression!'.freeze
16
+
17
+ #
18
+ # Run the verb.
19
+ #
20
+ def run
21
+ if @tokens.token_count < 2
22
+ @engine.err MISSING_EXPR_ERR
23
+ return
24
+ end
25
+
26
+ # Send the redirect page to the running app.
27
+ if @engine.app_running?
28
+ obj_name = @tokens.second
29
+ pn = Gloo::Core::Pn.new( @engine, obj_name )
30
+ @engine.running_app.obj.redirect = pn.resolve
31
+ end
32
+ end
33
+
34
+ #
35
+ # Get the Verb's keyword.
36
+ #
37
+ def self.keyword
38
+ return KEYWORD
39
+ end
40
+
41
+ #
42
+ # Get the Verb's keyword shortcut.
43
+ #
44
+ def self.keyword_shortcut
45
+ return KEYWORD_SHORT
46
+ end
47
+
48
+ # ---------------------------------------------------------------------
49
+ # Private functions
50
+ # ---------------------------------------------------------------------
51
+
52
+ private
53
+
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,194 @@
1
+ # Author:: Eric Crane (mailto:eric.crane@mac.com)
2
+ # Copyright:: Copyright (c) 20124 Eric Crane. All rights reserved.
3
+ #
4
+ # A helper class for static assets.
5
+ #
6
+
7
+ module Gloo
8
+ module WebSvr
9
+ class Asset
10
+
11
+ ASSETS_FOLDER = 'assets'.freeze
12
+ IMAGES_FOLDER = 'images'.freeze
13
+ STYLESHEETS_FOLDER = 'stylesheets'.freeze
14
+
15
+ CSS_TYPE = 'text/css'.freeze
16
+ JS_TYPE = 'text/javascript'.freeze
17
+
18
+ IMAGE_TYPE = 'image/'.freeze
19
+ FAVICON_TYPE = 'image/x-icon'.freeze
20
+
21
+
22
+ # ---------------------------------------------------------------------
23
+ # Initialization
24
+ # ---------------------------------------------------------------------
25
+
26
+ #
27
+ # Set up the web server.
28
+ #
29
+ def initialize( engine, web_svr_obj )
30
+ @engine = engine
31
+ @log = @engine.log
32
+
33
+ @web_svr_obj = web_svr_obj
34
+ end
35
+
36
+
37
+ # ---------------------------------------------------------------------
38
+ # Asset Helpers
39
+ # ---------------------------------------------------------------------
40
+
41
+ #
42
+ # Get the asset folder in the project.
43
+ #
44
+ def assets_folder
45
+ return File.join( @engine.settings.project_path, ASSETS_FOLDER )
46
+ end
47
+
48
+ #
49
+ # Get the images folder in the project.
50
+ #
51
+ def images_folder
52
+ return File.join( assets_folder, IMAGES_FOLDER )
53
+ end
54
+
55
+ #
56
+ # Get the stylesheets folder in the project.
57
+ #
58
+ def stylesheets_folder
59
+ return File.join( assets_folder, STYLESHEETS_FOLDER )
60
+ end
61
+
62
+ #
63
+ # Find and return the page for the given route.
64
+ #
65
+ def path_for_file file
66
+ pn = file.value
67
+
68
+ # Is the file's value a recognizable file?
69
+ return pn if File.exist? pn
70
+
71
+ # Look in the web server's asset folder.
72
+ pn = File.join( assets_folder, pn )
73
+
74
+ return pn
75
+ end
76
+
77
+ #
78
+ # Get the return type for the given file.
79
+ #
80
+ def type_for_file file
81
+ ext = File.extname( file ).downcase
82
+ ext = ext[1..-1] if ext[0] == '.'
83
+
84
+ if ext == 'css'
85
+ return CSS_TYPE
86
+ elsif ext == 'js'
87
+ return JS_TYPE
88
+ elsif ext == 'ico'
89
+ return FAVICON_TYPE
90
+ else
91
+ return "#{IMAGE_TYPE}#{ext}"
92
+ end
93
+ end
94
+
95
+
96
+ # ---------------------------------------------------------------------
97
+ # Render Asset
98
+ # ---------------------------------------------------------------------
99
+
100
+ #
101
+ # Helper to create a successful image response with the given data.
102
+ #
103
+ def render_file( file )
104
+ type = type_for_file file
105
+ data = File.binread file
106
+ code = Gloo::WebSvr::ResponseCode::SUCCESS
107
+
108
+ return Gloo::WebSvr::Response.new( @engine, code, type, data )
109
+ end
110
+
111
+
112
+ # ---------------------------------------------------------------------
113
+ # Dynamic Add Assets
114
+ # ---------------------------------------------------------------------
115
+
116
+ #
117
+ # Add all asssets to the web server pages (routes).
118
+ #
119
+ def add_asset_routes
120
+ return unless File.exist? assets_folder
121
+
122
+ @log.debug 'Adding asset routes to web server…'
123
+ @factory = @engine.factory
124
+
125
+ add_containers
126
+ add_images
127
+ add_stylesheets
128
+ end
129
+
130
+ #
131
+ # Create the containers for the assets if they do not exist.
132
+ #
133
+ def add_containers
134
+ pages = @web_svr_obj.pages_container
135
+
136
+ @assets = pages.find_child( ASSETS_FOLDER ) ||
137
+ @factory.create_can( ASSETS_FOLDER, pages )
138
+
139
+ @images = @assets.find_child( IMAGES_FOLDER ) ||
140
+ @factory.create_can( IMAGES_FOLDER, @assets )
141
+
142
+ @stylesheets = @assets.find_child( STYLESHEETS_FOLDER ) ||
143
+ @factory.create_can( STYLESHEETS_FOLDER, @assets )
144
+ end
145
+
146
+ #
147
+ # Add the images to the web server pages.
148
+ #
149
+ def add_images
150
+ @log.debug 'Adding image asset routes to web server…'
151
+
152
+ return unless File.exist? images_folder
153
+
154
+ # for each file in the images folder
155
+ # create a file object and add it to the images container
156
+ Dir.each_child( images_folder ) do |name|
157
+ pn = File.join( IMAGES_FOLDER, name )
158
+ add_file_obj( @images, name, pn )
159
+ end
160
+ end
161
+
162
+ #
163
+ # Add the stylesheets to the web server pages.
164
+ #
165
+ def add_stylesheets
166
+ @log.debug 'Adding stylesheet asset routes to web server…'
167
+
168
+ return unless File.exist? stylesheets_folder
169
+
170
+ # for each file in the stylesheets folder
171
+ # create a file object and add it to the stylesheets container
172
+ Dir.each_child( stylesheets_folder ) do |name|
173
+ pn = File.join( STYLESHEETS_FOLDER, name )
174
+ add_file_obj( @stylesheets, name, pn )
175
+ end
176
+ end
177
+
178
+ #
179
+ # Add a file object (page route) to the given container.
180
+ #
181
+ def add_file_obj( can, name, pn )
182
+ name = name.gsub( '.', '_' )
183
+ @log.debug "Adding route for file: #{name}"
184
+
185
+ # First make sure the child doesn't already exist.
186
+ child = can.find_child( name )
187
+ return if child
188
+
189
+ @factory.create_file( name, pn, can )
190
+ end
191
+
192
+ end
193
+ end
194
+ end
@@ -0,0 +1,56 @@
1
+ # Author:: Eric Crane (mailto:eric.crane@mac.com)
2
+ # Copyright:: Copyright (c) 20124 Eric Crane. All rights reserved.
3
+ #
4
+ # Configuration for a gloo web server.
5
+ #
6
+
7
+ module Gloo
8
+ module WebSvr
9
+ class Config
10
+
11
+ SCHEME_SEPARATOR = '://'
12
+ HTTP = 'http'
13
+ HTTPS = 'https'
14
+ LOCALHOST = 'localhost'
15
+ PORT_DEFAULT = '8080'
16
+
17
+ attr_reader :scheme, :host, :port
18
+
19
+
20
+ # ---------------------------------------------------------------------
21
+ # Initialization
22
+ # ---------------------------------------------------------------------
23
+
24
+ #
25
+ # Set up the web server.
26
+ #
27
+ def initialize( scheme = HTTP, host = LOCALHOST, port = PORT_DEFAULT )
28
+ @scheme = scheme
29
+ @host = host
30
+ @port = port
31
+ end
32
+
33
+
34
+ # ---------------------------------------------------------------------
35
+ # Static Helper Functions
36
+ # ---------------------------------------------------------------------
37
+
38
+
39
+ # ---------------------------------------------------------------------
40
+ # Helper Functions
41
+ # ---------------------------------------------------------------------
42
+
43
+ #
44
+ # The base url, including scheme, host and port.
45
+ #
46
+ def base_url
47
+ url = "#{self.scheme}#{SCHEME_SEPARATOR}#{self.host}"
48
+ unless self.port.blank?
49
+ url << ":#{self.port}"
50
+ end
51
+ return url
52
+ end
53
+
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,91 @@
1
+ # Author:: Eric Crane (mailto:eric.crane@mac.com)
2
+ # Copyright:: Copyright (c) 20124 Eric Crane. All rights reserved.
3
+ #
4
+ # A helper class used to render parameters (ERB) in text.
5
+ # Also uses helper functions to render.
6
+ #
7
+
8
+ module Gloo
9
+ module WebSvr
10
+ class EmbeddedRenderer
11
+
12
+ HELPER = 'helper'.freeze
13
+
14
+ attr_reader :engine, :log, :web_svr_obj
15
+
16
+
17
+ # ---------------------------------------------------------------------
18
+ # Initialization
19
+ # ---------------------------------------------------------------------
20
+
21
+ #
22
+ # Set up the web server.
23
+ #
24
+ def initialize( engine, web_svr_obj )
25
+ @engine = engine
26
+ @log = @engine.log
27
+
28
+ @web_svr_obj = web_svr_obj
29
+ end
30
+
31
+
32
+ # ---------------------------------------------------------------------
33
+ # Obj Helper Functions
34
+ # ---------------------------------------------------------------------
35
+
36
+ #
37
+ # Handle a missing method by looking for a helper function.
38
+ # If there is one, then call it and return the result.
39
+ # If not, log an error and return nil.
40
+ #
41
+ def method_missing( method_name, *args )
42
+ @log.debug "missing method '#{method_name}' with args #{args}"
43
+
44
+ helper_pn = "#{HELPER}.#{method_name}"
45
+ @log.debug "looking for function: #{helper_pn}"
46
+
47
+ pn = Gloo::Core::Pn.new( @engine, helper_pn )
48
+ obj = pn.resolve
49
+ if obj
50
+ @log.debug "found obj: #{obj.pn}"
51
+ return obj.invoke args
52
+ else
53
+ @log.error "Function not found: #{helper_pn}"
54
+ end
55
+
56
+ return nil
57
+ end
58
+
59
+
60
+ # ---------------------------------------------------------------------
61
+ # Renderer
62
+ # ---------------------------------------------------------------------
63
+
64
+ #
65
+ # Render content with the given params.
66
+ # Params might be nil, in which case the content
67
+ # is returned with no changes.
68
+ #
69
+ def render content, params
70
+ # If the params is nil, let's make it an empty hash.
71
+ params = {} unless params
72
+
73
+ # Get the binding context for this render.
74
+ b = binding
75
+
76
+ # Add the params to the binding context.
77
+ params.each_pair do |key, value|
78
+ b.local_variable_set key.to_sym, value
79
+ end
80
+
81
+ # Render in the current binding content.
82
+ renderer = ERB.new( content )
83
+ content = renderer.result( b )
84
+
85
+ return content
86
+ end
87
+
88
+ end
89
+
90
+ end
91
+ end