thin_service 0.0.1

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,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"