thin_service 0.0.1

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,199 @@
1
+ '##################################################################
2
+ '#
3
+ '# mongrel_service: Win32 native implementation for thin
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://thin.rubyforge.org/license.html
12
+
13
+ '#
14
+ '##################################################################
15
+
16
+ '##################################################################
17
+ '# Requirements:
18
+ '# - FreeBASIC 0.18
19
+ '#
20
+ '##################################################################
21
+
22
+ #include once "thin_service.bi"
23
+ #define DEBUG_LOG_FILE EXEPATH + "\thin_service.log"
24
+ #include once "_debug.bi"
25
+
26
+ namespace thin_service
27
+ constructor SingleThin()
28
+ dim redirect_path as string = EXEPATH
29
+ dim redirect_file as string = "thin.default.log"
30
+ dim flag as string
31
+ dim idx as integer = 1
32
+
33
+ '# determine supplied logfile
34
+ flag = command(idx)
35
+ do while (len(flag) > 0)
36
+ '# application directory
37
+ if (flag = "-c") or (flag = "--chdir") then
38
+ redirect_path = command(idx + 1)
39
+ end if
40
+
41
+ '# log file
42
+ if (flag = "-l") or (flag = "--log") then
43
+ redirect_file = command(idx + 1)
44
+ end if
45
+ idx += 1
46
+
47
+ flag = command(idx)
48
+ loop
49
+
50
+ with this.__service
51
+ .name = "single"
52
+ .description = "Thin Single Process service"
53
+
54
+ '# disabling shared process
55
+ .shared_process = FALSE
56
+
57
+ '# TODO: fix inheritance here
58
+ .onInit = @single_onInit
59
+ .onStart = @single_onStart
60
+ .onStop = @single_onStop
61
+ end with
62
+
63
+ with this.__console
64
+ debug("redirecting to: " + redirect_path + "/" + redirect_file)
65
+ .redirect(ProcessStdBoth, (redirect_path + "/" + redirect_file))
66
+ end with
67
+
68
+ '# TODO: fix inheritance here
69
+ single_thin_ref = @this
70
+ end constructor
71
+
72
+ destructor SingleThin()
73
+ '# TODO: fin inheritance here
74
+ end destructor
75
+
76
+ function single_onInit(byref self as ServiceProcess) as integer
77
+ dim result as integer
78
+ dim thin_cmd as string
79
+
80
+ debug("single_onInit()")
81
+
82
+ '# ruby.exe must be in the path, which we guess is already there.
83
+ '# because thin_service executable (.exe) is located in the same
84
+ '# folder than thin_rails ruby script, we complete the path with
85
+ '# EXEPATH + "\thin_rails" to make it work.
86
+ '# FIXED ruby installation outside PATH and inside folders with spaces
87
+ thin_cmd = !"\"" + EXEPATH + !"\\ruby.exe" + !"\" " + !"\"" + EXEPATH + !"\\thin_service" + !"\""
88
+
89
+ '# due lack of inheritance, we use single_thin_ref as pointer to
90
+ '# SingleThin instance. now we should call StillAlive
91
+ self.StillAlive()
92
+ if (len(self.commandline) > 0) then
93
+ '# assign the program
94
+ single_thin_ref->__console.filename = thin_cmd
95
+ single_thin_ref->__console.arguments = self.commandline
96
+
97
+ '# fix commandline, it currently contains params to be passed to
98
+ '# thin_rails, and not ruby.exe nor the script to be run.
99
+ self.commandline = thin_cmd + " " + self.commandline
100
+
101
+ '# now launch the child process
102
+ debug("starting child process with cmdline: " + self.commandline)
103
+ single_thin_ref->__child_pid = 0
104
+ if (single_thin_ref->__console.start() = true) then
105
+ single_thin_ref->__child_pid = single_thin_ref->__console.pid
106
+ end if
107
+ self.StillAlive()
108
+
109
+ '# check if pid is valid
110
+ if (single_thin_ref->__child_pid > 0) then
111
+ '# it worked
112
+ debug("child process pid: " + str(single_thin_ref->__child_pid))
113
+ result = not FALSE
114
+ end if
115
+ else
116
+ '# if no param, no service!
117
+ debug("no parameters was passed to this service!")
118
+ result = FALSE
119
+ end if
120
+
121
+ debug("single_onInit() done")
122
+ return result
123
+ end function
124
+
125
+ sub single_onStart(byref self as ServiceProcess)
126
+ debug("single_onStart()")
127
+
128
+ do while (self.state = Running) or (self.state = Paused)
129
+ '# instead of sitting idle here, we must monitor the pid
130
+ '# and re-spawn a new process if needed
131
+ if not (single_thin_ref->__console.running = true) then
132
+ '# check if we aren't terminating
133
+ if (self.state = Running) or (self.state = Paused) then
134
+ debug("child process terminated!, re-spawning a new one")
135
+
136
+ single_thin_ref->__child_pid = 0
137
+ if (single_thin_ref->__console.start() = true) then
138
+ single_thin_ref->__child_pid = single_thin_ref->__console.pid
139
+ end if
140
+
141
+ if (single_thin_ref->__child_pid > 0) then
142
+ debug("new child process pid: " + str(single_thin_ref->__child_pid))
143
+ end if
144
+ end if
145
+ end if
146
+
147
+ '# wait for 5 seconds
148
+ sleep 5000
149
+ loop
150
+
151
+ debug("single_onStart() done")
152
+ end sub
153
+
154
+ sub single_onStop(byref self as ServiceProcess)
155
+ debug("single_onStop()")
156
+
157
+ '# now terminates the child process
158
+ if not (single_thin_ref->__child_pid = 0) then
159
+ debug("trying to kill pid: " + str(single_thin_ref->__child_pid))
160
+ if not (single_thin_ref->__console.terminate() = true) then
161
+ debug("Terminate() reported a problem when terminating process " + str(single_thin_ref->__child_pid))
162
+ else
163
+ debug("child process terminated with success.")
164
+ single_thin_ref->__child_pid = 0
165
+ end if
166
+ end if
167
+
168
+ debug("single_onStop() done")
169
+ end sub
170
+
171
+ sub application()
172
+ dim simple as SingleThin
173
+ dim host as ServiceHost
174
+ dim ctrl as ServiceController = ServiceController("Thin Windows Service", "version " + VERSION, _
175
+ "(c) 2006-2010 The Mongrel development team.")
176
+
177
+ '# add SingleThin (service)
178
+ host.Add(simple.__service)
179
+ select case ctrl.RunMode()
180
+ '# call from Service Control Manager (SCM)
181
+ case RunAsService:
182
+ debug("ServiceHost RunAsService")
183
+ host.Run()
184
+
185
+ '# call from console, useful for debug purposes.
186
+ case RunAsConsole:
187
+ debug("ServiceController Console")
188
+ ctrl.Console()
189
+
190
+ case else:
191
+ ctrl.Banner()
192
+ print "thin_service is not designed to run form commandline,"
193
+ print "please use thin_rails service:: commands to create a win32 service."
194
+ end select
195
+ end sub
196
+ end namespace
197
+
198
+ '# MAIN: start native thin_service here
199
+ thin_service.application()
@@ -0,0 +1,61 @@
1
+ '##################################################################
2
+ '#
3
+ '# thin_service: Win32 native implementation for thin
4
+ '# (using ServiceFB and FreeBASIC)
5
+ '#
6
+ '# Copyright (c) 2006 Multimedia systems
7
+ '# (c) and code by Luis Lavena
8
+ '#
9
+ '# thin_service (native) and thin_service gem_pluing are licensed
10
+ '# in the same terms as thin, please review the thin license at
11
+ '# http://thin.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 thin_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
+ '# SingleThin
45
+ type SingleThin
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_thin_ref as SingleThin ptr
61
+ end namespace
@@ -0,0 +1,40 @@
1
+ require_relative '../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,43 @@
1
+ require_relative '../tools/freebasic'
2
+ require_relative '../lib/thin_service/version'
3
+
4
+ # thin_service (native)
5
+ namespace :native do
6
+ exe_options = {
7
+ :debug => false,
8
+ :profile => false,
9
+ :errorchecking => :ex,
10
+ :mt => true,
11
+ :pedantic => true
12
+ }
13
+
14
+ exe_options[:debug] = true if ENV['DEBUG']
15
+ exe_options[:profile] = true if ENV['PROFILE']
16
+ exe_options[:errorchecking] = :exx if ENV['EXX']
17
+ exe_options[:pedantic] = false if ENV['NOPEDANTIC']
18
+
19
+ project_task 'thin_service' do
20
+ executable 'thin_service_wrapper'
21
+ build_to 'resource'
22
+
23
+ define 'DEBUG_LOG' if ENV['LOG']
24
+ define "GEM_VERSION=\"#{ThinService::VERSION}\""
25
+
26
+ main 'src/thin_service/thin_service.bas'
27
+ source 'src/thin_service/console_process.bas'
28
+
29
+ search_path 'src/ServiceFB'
30
+
31
+ lib_path 'builds'
32
+ library 'ServiceFB', 'ServiceFB_Utils'
33
+ library 'user32', 'advapi32', 'psapi'
34
+
35
+ option exe_options
36
+ end
37
+ end
38
+
39
+ task :clean => ['native:clobber']
40
+ task :native_service => [:native_lib, 'native:build']
41
+
42
+ desc "Compile native code"
43
+ task :compile => [:native_service]
data/tasks/tests.rake ADDED
@@ -0,0 +1,55 @@
1
+ require_relative '../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 'src/mongrel_service/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"