mongrel_service 0.1 → 0.4.beta1

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,75 @@
1
+ '#--
2
+ '# Copyright (c) 2006-2007 Luis Lavena, Multimedia systems
3
+ '#
4
+ '# This source code is released under the MIT License.
5
+ '# See MIT-LICENSE file for details
6
+ '#++
7
+
8
+ #ifndef __CONSOLE_PROCESS_BI__
9
+ #define __CONSOLE_PROCESS_BI__
10
+
11
+ #include once "windows.bi"
12
+ #include once "boolean.bi"
13
+
14
+ enum ProcessStdEnum
15
+ ProcessStdOut = 1
16
+ ProcessStdErr = 2
17
+ ProcessStdBoth = 3
18
+ end enum
19
+
20
+ type ConsoleProcess
21
+ '# this class provide basic functionality
22
+ '# to control child processes
23
+
24
+ '# new ConsoleProcess(Filename, Parameters)
25
+ declare constructor(byref as string = "", byref as string = "")
26
+
27
+ '# delete
28
+ declare destructor()
29
+
30
+ '# properties (only getters)
31
+ declare property filename as string
32
+ declare property filename(byref as string)
33
+
34
+ declare property arguments as string
35
+ declare property arguments(byref as string)
36
+
37
+ '# stdout and stderr allow you redirect
38
+ '# console output and errors to files
39
+ declare property redirected_stdout as string
40
+ declare property redirected_stderr as string
41
+
42
+ '# evaluate if the process is running
43
+ declare property running as boolean
44
+
45
+ '# pid will return the current Process ID, or 0 if no process is running
46
+ declare property pid as uinteger
47
+
48
+ '# exit_code is the value set by the process prior exiting.
49
+ declare property exit_code as uinteger
50
+
51
+ '# methods
52
+ declare function redirect(byval as ProcessStdEnum, byref as string) as boolean
53
+ declare function start() as boolean
54
+ declare function terminate(byval as boolean = false) as boolean
55
+
56
+ private:
57
+ _filename as string
58
+ _arguments as string
59
+ _pid as uinteger
60
+ _process_info as PROCESS_INFORMATION
61
+ _show_console as boolean = false
62
+
63
+ _redirect_stdout as boolean
64
+ _stdout_filename as string
65
+
66
+ _redirect_stderr as boolean
67
+ _stderr_filename as string
68
+
69
+ '# this fake console handler
70
+ '# is used to trap ctrl-c
71
+ declare static function _console_handler(byval as DWORD) as BOOL
72
+
73
+ end type 'ConsoleProcess
74
+
75
+ #endif '__CONSOLE_PROCESS_BI__
@@ -0,0 +1,198 @@
1
+ '##################################################################
2
+ '#
3
+ '# mongrel_service: Win32 native implementation for mongrel
4
+ '# (using ServiceFB and FreeBASIC)
5
+ '#
6
+ '# Copyright (c) 2006 Multimedia systems
7
+ '# (c) and code by Luis Lavena
8
+ '#
9
+ '# mongrel_service (native) and mongrel_service gem_pluing are licensed
10
+ '# in the same terms as mongrel, please review the mongrel license at
11
+ '# http://mongrel.rubyforge.org/license.html
12
+ '#
13
+ '##################################################################
14
+
15
+ '##################################################################
16
+ '# Requirements:
17
+ '# - FreeBASIC 0.18
18
+ '#
19
+ '##################################################################
20
+
21
+ #include once "mongrel_service.bi"
22
+ #define DEBUG_LOG_FILE EXEPATH + "\mongrel_service.log"
23
+ #include once "_debug.bi"
24
+
25
+ namespace mongrel_service
26
+ constructor SingleMongrel()
27
+ dim redirect_path as string = EXEPATH
28
+ dim redirect_file as string = "mongrel.default.log"
29
+ dim flag as string
30
+ dim idx as integer = 1
31
+
32
+ '# determine supplied logfile
33
+ flag = command(idx)
34
+ do while (len(flag) > 0)
35
+ '# application directory
36
+ if (flag = "-c") or (flag = "--chdir") then
37
+ redirect_path = command(idx + 1)
38
+ end if
39
+
40
+ '# log file
41
+ if (flag = "-l") or (flag = "--log") then
42
+ redirect_file = command(idx + 1)
43
+ end if
44
+ idx += 1
45
+
46
+ flag = command(idx)
47
+ loop
48
+
49
+ with this.__service
50
+ .name = "single"
51
+ .description = "Mongrel Single Process service"
52
+
53
+ '# disabling shared process
54
+ .shared_process = FALSE
55
+
56
+ '# TODO: fix inheritance here
57
+ .onInit = @single_onInit
58
+ .onStart = @single_onStart
59
+ .onStop = @single_onStop
60
+ end with
61
+
62
+ with this.__console
63
+ debug("redirecting to: " + redirect_path + "/" + redirect_file)
64
+ .redirect(ProcessStdBoth, (redirect_path + "/" + redirect_file))
65
+ end with
66
+
67
+ '# TODO: fix inheritance here
68
+ single_mongrel_ref = @this
69
+ end constructor
70
+
71
+ destructor SingleMongrel()
72
+ '# TODO: fin inheritance here
73
+ end destructor
74
+
75
+ function single_onInit(byref self as ServiceProcess) as integer
76
+ dim result as integer
77
+ dim mongrel_cmd as string
78
+
79
+ debug("single_onInit()")
80
+
81
+ '# ruby.exe must be in the path, which we guess is already there.
82
+ '# because mongrel_service executable (.exe) is located in the same
83
+ '# folder than mongrel_rails ruby script, we complete the path with
84
+ '# EXEPATH + "\mongrel_rails" to make it work.
85
+ '# FIXED ruby installation outside PATH and inside folders with spaces
86
+ mongrel_cmd = !"\"" + EXEPATH + !"\\ruby.exe" + !"\" " + !"\"" + EXEPATH + !"\\mongrel_rails" + !"\"" + " start"
87
+
88
+ '# due lack of inheritance, we use single_mongrel_ref as pointer to
89
+ '# SingleMongrel instance. now we should call StillAlive
90
+ self.StillAlive()
91
+ if (len(self.commandline) > 0) then
92
+ '# assign the program
93
+ single_mongrel_ref->__console.filename = mongrel_cmd
94
+ single_mongrel_ref->__console.arguments = self.commandline
95
+
96
+ '# fix commandline, it currently contains params to be passed to
97
+ '# mongrel_rails, and not ruby.exe nor the script to be run.
98
+ self.commandline = mongrel_cmd + " " + self.commandline
99
+
100
+ '# now launch the child process
101
+ debug("starting child process with cmdline: " + self.commandline)
102
+ single_mongrel_ref->__child_pid = 0
103
+ if (single_mongrel_ref->__console.start() = true) then
104
+ single_mongrel_ref->__child_pid = single_mongrel_ref->__console.pid
105
+ end if
106
+ self.StillAlive()
107
+
108
+ '# check if pid is valid
109
+ if (single_mongrel_ref->__child_pid > 0) then
110
+ '# it worked
111
+ debug("child process pid: " + str(single_mongrel_ref->__child_pid))
112
+ result = not FALSE
113
+ end if
114
+ else
115
+ '# if no param, no service!
116
+ debug("no parameters was passed to this service!")
117
+ result = FALSE
118
+ end if
119
+
120
+ debug("single_onInit() done")
121
+ return result
122
+ end function
123
+
124
+ sub single_onStart(byref self as ServiceProcess)
125
+ debug("single_onStart()")
126
+
127
+ do while (self.state = Running) or (self.state = Paused)
128
+ '# instead of sitting idle here, we must monitor the pid
129
+ '# and re-spawn a new process if needed
130
+ if not (single_mongrel_ref->__console.running = true) then
131
+ '# check if we aren't terminating
132
+ if (self.state = Running) or (self.state = Paused) then
133
+ debug("child process terminated!, re-spawning a new one")
134
+
135
+ single_mongrel_ref->__child_pid = 0
136
+ if (single_mongrel_ref->__console.start() = true) then
137
+ single_mongrel_ref->__child_pid = single_mongrel_ref->__console.pid
138
+ end if
139
+
140
+ if (single_mongrel_ref->__child_pid > 0) then
141
+ debug("new child process pid: " + str(single_mongrel_ref->__child_pid))
142
+ end if
143
+ end if
144
+ end if
145
+
146
+ '# wait for 5 seconds
147
+ sleep 5000
148
+ loop
149
+
150
+ debug("single_onStart() done")
151
+ end sub
152
+
153
+ sub single_onStop(byref self as ServiceProcess)
154
+ debug("single_onStop()")
155
+
156
+ '# now terminates the child process
157
+ if not (single_mongrel_ref->__child_pid = 0) then
158
+ debug("trying to kill pid: " + str(single_mongrel_ref->__child_pid))
159
+ if not (single_mongrel_ref->__console.terminate() = true) then
160
+ debug("Terminate() reported a problem when terminating process " + str(single_mongrel_ref->__child_pid))
161
+ else
162
+ debug("child process terminated with success.")
163
+ single_mongrel_ref->__child_pid = 0
164
+ end if
165
+ end if
166
+
167
+ debug("single_onStop() done")
168
+ end sub
169
+
170
+ sub application()
171
+ dim simple as SingleMongrel
172
+ dim host as ServiceHost
173
+ dim ctrl as ServiceController = ServiceController("Mongrel Windows Service", "version " + VERSION, _
174
+ "(c) 2006-2010 The Mongrel development team.")
175
+
176
+ '# add SingleMongrel (service)
177
+ host.Add(simple.__service)
178
+ select case ctrl.RunMode()
179
+ '# call from Service Control Manager (SCM)
180
+ case RunAsService:
181
+ debug("ServiceHost RunAsService")
182
+ host.Run()
183
+
184
+ '# call from console, useful for debug purposes.
185
+ case RunAsConsole:
186
+ debug("ServiceController Console")
187
+ ctrl.Console()
188
+
189
+ case else:
190
+ ctrl.Banner()
191
+ print "mongrel_service is not designed to run form commandline,"
192
+ print "please use mongrel_rails service:: commands to create a win32 service."
193
+ end select
194
+ end sub
195
+ end namespace
196
+
197
+ '# MAIN: start native mongrel_service here
198
+ mongrel_service.application()
@@ -0,0 +1,61 @@
1
+ '##################################################################
2
+ '#
3
+ '# mongrel_service: Win32 native implementation for mongrel
4
+ '# (using ServiceFB and FreeBASIC)
5
+ '#
6
+ '# Copyright (c) 2006 Multimedia systems
7
+ '# (c) and code by Luis Lavena
8
+ '#
9
+ '# mongrel_service (native) and mongrel_service gem_pluing are licensed
10
+ '# in the same terms as mongrel, please review the mongrel license at
11
+ '# http://mongrel.rubyforge.org/license.html
12
+ '#
13
+ '##################################################################
14
+
15
+ '##################################################################
16
+ '# Requirements:
17
+ '# - FreeBASIC 0.18.
18
+ '#
19
+ '##################################################################
20
+
21
+ #define SERVICEFB_INCLUDE_UTILS
22
+ #include once "ServiceFB.bi"
23
+ #include once "console_process.bi"
24
+
25
+ '# use for debug versions
26
+ #if not defined(GEM_VERSION)
27
+ #define GEM_VERSION (debug mode)
28
+ #endif
29
+
30
+ '# preprocessor stringize
31
+ #define PPSTR(x) #x
32
+
33
+ namespace mongrel_service
34
+ const VERSION as string = PPSTR(GEM_VERSION)
35
+
36
+ '# namespace include
37
+ using fb.svc
38
+ using fb.svc.utils
39
+
40
+ declare function single_onInit(byref as ServiceProcess) as integer
41
+ declare sub single_onStart(byref as ServiceProcess)
42
+ declare sub single_onStop(byref as ServiceProcess)
43
+
44
+ '# SingleMongrel
45
+ type SingleMongrel
46
+ declare constructor()
47
+ declare destructor()
48
+
49
+ '# TODO: replace for inheritance here
50
+ 'declare function onInit() as integer
51
+ 'declare sub onStart()
52
+ 'declare sub onStop()
53
+
54
+ __service as ServiceProcess
55
+ __console as ConsoleProcess
56
+ __child_pid as uinteger
57
+ end type
58
+
59
+ '# TODO: replace with inheritance here
60
+ dim shared single_mongrel_ref as SingleMongrel ptr
61
+ end namespace
data/tasks/gem.rake ADDED
@@ -0,0 +1,17 @@
1
+ require 'hoe'
2
+
3
+ # compile takes higher importance in packaging
4
+ task :package => [:compile]
5
+ task :gem => [:compile]
6
+
7
+ HOE = Hoe.spec 'mongrel_service' do
8
+ self.rubyforge_name = "mongrel"
9
+ self.version = '0.4.beta1'
10
+
11
+ developer 'Luis Lavena', 'luislavena@gmail.com'
12
+
13
+ extra_deps << ['gem_plugin', '~> 0.2.3']
14
+ extra_deps << ['mongrel', '~> 1.1.5']
15
+
16
+ self.need_tar = false
17
+ end
@@ -0,0 +1,40 @@
1
+ require 'tools/freebasic'
2
+
3
+ # ServiceFB namespace (lib)
4
+ namespace :lib do
5
+ lib_options = {
6
+ :debug => false,
7
+ :profile => false,
8
+ :errorchecking => :ex,
9
+ :mt => true,
10
+ :pedantic => true
11
+ }
12
+
13
+ lib_options[:debug] = true if ENV['DEBUG']
14
+ lib_options[:profile] = true if ENV['PROFILE']
15
+ lib_options[:errorchecking] = :exx if ENV['EXX']
16
+ lib_options[:pedantic] = false if ENV['NOPEDANTIC']
17
+
18
+ project_task 'servicefb' do
19
+ lib 'ServiceFB'
20
+ build_to 'builds'
21
+
22
+ define 'SERVICEFB_DEBUG_LOG' if ENV['LOG']
23
+ source 'src/ServiceFB/ServiceFB.bas'
24
+
25
+ option lib_options
26
+ end
27
+
28
+ project_task 'servicefb_utils' do
29
+ lib 'ServiceFB_Utils'
30
+ build_to 'builds'
31
+
32
+ define 'SERVICEFB_DEBUG_LOG' if ENV['LOG']
33
+ source 'src/ServiceFB/ServiceFB_Utils.bas'
34
+
35
+ option lib_options
36
+ end
37
+ end
38
+
39
+ task :native_lib => ["lib:build"]
40
+ task :clean => ["lib:clobber"]
@@ -0,0 +1,42 @@
1
+ require 'tools/freebasic'
2
+
3
+ # mongrel_service (native)
4
+ namespace :native do
5
+ exe_options = {
6
+ :debug => false,
7
+ :profile => false,
8
+ :errorchecking => :ex,
9
+ :mt => true,
10
+ :pedantic => true
11
+ }
12
+
13
+ exe_options[:debug] = true if ENV['DEBUG']
14
+ exe_options[:profile] = true if ENV['PROFILE']
15
+ exe_options[:errorchecking] = :exx if ENV['EXX']
16
+ exe_options[:pedantic] = false if ENV['NOPEDANTIC']
17
+
18
+ project_task 'mongrel_service' do
19
+ executable 'mongrel_service'
20
+ build_to 'resources'
21
+
22
+ define 'DEBUG_LOG' if ENV['LOG']
23
+ define "GEM_VERSION=\"#{HOE.spec.version}\""
24
+
25
+ main 'src/mongrel_service/mongrel_service.bas'
26
+ source 'src/mongrel_service/console_process.bas'
27
+
28
+ search_path 'src/ServiceFB'
29
+
30
+ lib_path 'builds'
31
+ library 'ServiceFB', 'ServiceFB_Utils'
32
+ library 'user32', 'advapi32', 'psapi'
33
+
34
+ option exe_options
35
+ end
36
+ end
37
+
38
+ task :clean => ['native:clobber']
39
+ task :native_service => [:native_lib, 'native:build']
40
+
41
+ desc "Compile native code"
42
+ task :compile => [:native_service]
data/tasks/tests.rake ADDED
@@ -0,0 +1,55 @@
1
+ require 'tools/freebasic'
2
+
3
+ # global options shared by all the project in this Rakefile
4
+ options = {
5
+ :debug => false,
6
+ :profile => false,
7
+ :errorchecking => :ex,
8
+ :mt => true,
9
+ :pedantic => true
10
+ }
11
+
12
+ options[:debug] = true if ENV['DEBUG']
13
+ options[:profile] = true if ENV['PROFILE']
14
+ options[:errorchecking] = :exx if ENV['EXX']
15
+ options[:pedantic] = false if ENV['NOPEDANTIC']
16
+
17
+ project_task :mock_process do
18
+ executable :mock_process
19
+ build_to 'tests'
20
+
21
+ main 'tests/fixtures/mock_process.bas'
22
+
23
+ option options
24
+ end
25
+
26
+ task "all_tests:build" => ["lib:build"]
27
+
28
+ project_task :all_tests do
29
+ executable :all_tests
30
+ build_to 'tests'
31
+
32
+ search_path 'src/mongrel_service'
33
+ lib_path 'builds'
34
+
35
+ main 'tests/all_tests.bas'
36
+
37
+ # this temporally fix the inverse namespace ctors of FB
38
+ source Dir.glob("tests/test_*.bas").reverse
39
+
40
+ library 'testly'
41
+
42
+ source 'native/console_process.bas'
43
+
44
+ option options
45
+ end
46
+
47
+ desc "Run all the internal tests for the library"
48
+ task "all_tests:run" => ["mock_process:build", "all_tests:build"] do
49
+ Dir.chdir('tests') do
50
+ sh %{all_tests}
51
+ end
52
+ end
53
+
54
+ desc "Run all the test for this project"
55
+ task :test => "all_tests:run"