gloo 3.0.0 → 3.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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