mongrel_service 0.1 → 0.4.beta1

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