mongrel_service 0.3.4-i386-mswin32
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.
- data/CHANGELOG +33 -0
- data/COPYING +20 -0
- data/LICENSE +55 -0
- data/Manifest +21 -0
- data/README +11 -0
- data/TODO +19 -0
- data/bin/mongrel_service.exe +0 -0
- data/lib/ServiceFB/ServiceFB.bas +650 -0
- data/lib/ServiceFB/ServiceFB.bi +109 -0
- data/lib/ServiceFB/ServiceFB_Utils.bas +480 -0
- data/lib/ServiceFB/ServiceFB_Utils.bi +70 -0
- data/lib/ServiceFB/_internals.bi +50 -0
- data/lib/ServiceFB/_utils_internals.bi +49 -0
- data/lib/mongrel_service/init.rb +211 -0
- data/mongrel_service.gemspec +117 -0
- data/native/_debug.bi +59 -0
- data/native/console_process.bas +389 -0
- data/native/console_process.bi +75 -0
- data/native/mongrel_service.bas +179 -0
- data/native/mongrel_service.bi +61 -0
- data/resources/defaults.yaml +2 -0
- data/tools/freebasic.rb +355 -0
- metadata +114 -0
data/native/_debug.bi
ADDED
@@ -0,0 +1,59 @@
|
|
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.17, Win32 CVS Build (as for November 09, 2006).
|
18
|
+
'#
|
19
|
+
'##################################################################
|
20
|
+
|
21
|
+
#ifndef __Debug_bi__
|
22
|
+
#define __Debug_bi__
|
23
|
+
|
24
|
+
#ifdef DEBUG_LOG
|
25
|
+
#include once "vbcompat.bi"
|
26
|
+
#ifndef DEBUG_LOG_FILE
|
27
|
+
#define DEBUG_LOG_FILE EXEPATH + "\debug.log"
|
28
|
+
#endif
|
29
|
+
|
30
|
+
'# this procedure is only used for debugging purposed, will be removed from
|
31
|
+
'# final compilation
|
32
|
+
private sub debug_to_file(byref message as string, byref file as string, byval linenumber as uinteger, byref func as string)
|
33
|
+
dim handle as integer
|
34
|
+
static first_time as integer
|
35
|
+
|
36
|
+
handle = freefile
|
37
|
+
open DEBUG_LOG_FILE for append as #handle
|
38
|
+
|
39
|
+
if (first_time = 0) then
|
40
|
+
print #handle, "# Logfile created on "; format(now(), "dd/mm/yyyy HH:mm:ss")
|
41
|
+
print #handle, ""
|
42
|
+
first_time = 1
|
43
|
+
end if
|
44
|
+
|
45
|
+
'# src/module.bas:123, namespace.function:
|
46
|
+
'# message
|
47
|
+
'#
|
48
|
+
print #handle, file; ":"; str(linenumber); ", "; lcase(func); ":"
|
49
|
+
print #handle, space(2); message
|
50
|
+
print #handle, ""
|
51
|
+
|
52
|
+
close #handle
|
53
|
+
end sub
|
54
|
+
#define debug(message) debug_to_file(message, __FILE__, __LINE__, __FUNCTION__)
|
55
|
+
#else
|
56
|
+
#define debug(message)
|
57
|
+
#endif '# DEBUG_LOG
|
58
|
+
|
59
|
+
#endif '# __Debug_bi__
|
@@ -0,0 +1,389 @@
|
|
1
|
+
'#--
|
2
|
+
'# Copyright (c) 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
|
+
#include once "console_process.bi"
|
9
|
+
|
10
|
+
constructor ConsoleProcess(byref new_filename as string = "", byref new_arguments as string = "")
|
11
|
+
'# assign filename and arguments
|
12
|
+
|
13
|
+
'# if filename contains spaces, automatically quote it!
|
14
|
+
if (instr(new_filename, " ") > 0) then
|
15
|
+
_filename = !"\"" + new_filename + !"\""
|
16
|
+
else
|
17
|
+
_filename = new_filename
|
18
|
+
endif
|
19
|
+
|
20
|
+
_arguments = new_arguments
|
21
|
+
end constructor
|
22
|
+
|
23
|
+
destructor ConsoleProcess()
|
24
|
+
'# in case process still running
|
25
|
+
if (running = true) then
|
26
|
+
terminate(true)
|
27
|
+
|
28
|
+
'# close opened handles
|
29
|
+
'# ...
|
30
|
+
CloseHandle(_process_info.hProcess)
|
31
|
+
CloseHandle(_process_info.hThread)
|
32
|
+
end if
|
33
|
+
end destructor
|
34
|
+
|
35
|
+
property ConsoleProcess.filename() as string
|
36
|
+
return _filename
|
37
|
+
end property
|
38
|
+
|
39
|
+
property ConsoleProcess.filename(byref rhs as string)
|
40
|
+
if not (running = true) then
|
41
|
+
_filename = rhs
|
42
|
+
end if
|
43
|
+
end property
|
44
|
+
|
45
|
+
property ConsoleProcess.arguments() as string
|
46
|
+
return _arguments
|
47
|
+
end property
|
48
|
+
|
49
|
+
property ConsoleProcess.arguments(byref rhs as string)
|
50
|
+
if not (running = true) then
|
51
|
+
_arguments = rhs
|
52
|
+
end if
|
53
|
+
end property
|
54
|
+
|
55
|
+
property ConsoleProcess.redirected_stdout() as string
|
56
|
+
return _stdout_filename
|
57
|
+
end property
|
58
|
+
|
59
|
+
property ConsoleProcess.redirected_stderr() as string
|
60
|
+
return _stderr_filename
|
61
|
+
end property
|
62
|
+
|
63
|
+
'# running is a helper which evaluates _pid and exit_code
|
64
|
+
property ConsoleProcess.running() as boolean
|
65
|
+
dim result as boolean
|
66
|
+
|
67
|
+
'# presume not running
|
68
|
+
result = false
|
69
|
+
|
70
|
+
if not (_pid = 0) then
|
71
|
+
'# that means the process is/was running.
|
72
|
+
'# now evaluate if exit_code = STILL_ACTIVE
|
73
|
+
result = (exit_code = STILL_ACTIVE)
|
74
|
+
end if
|
75
|
+
|
76
|
+
return result
|
77
|
+
end property
|
78
|
+
|
79
|
+
property ConsoleProcess.pid() as uinteger
|
80
|
+
return _pid
|
81
|
+
end property
|
82
|
+
|
83
|
+
property ConsoleProcess.exit_code() as uinteger
|
84
|
+
dim result as uinteger
|
85
|
+
|
86
|
+
result = 0
|
87
|
+
|
88
|
+
'# is _pid valid?
|
89
|
+
if not (_pid = 0) then
|
90
|
+
if not (_process_info.hProcess = NULL) then
|
91
|
+
'# the process reference is valid, get the exit_code
|
92
|
+
if not (GetExitCodeProcess(_process_info.hProcess, @result) = 0) then
|
93
|
+
'# OK
|
94
|
+
'# no error in the query, get result
|
95
|
+
end if '# not (GetExitCodeProcess() = 0)
|
96
|
+
end if '# not (proc = NULL)
|
97
|
+
end if '# not (_pid = 0)
|
98
|
+
|
99
|
+
return result
|
100
|
+
end property
|
101
|
+
|
102
|
+
function ConsoleProcess.redirect(byval target as ProcessStdEnum, byref new_std_filename as string) as boolean
|
103
|
+
dim result as boolean
|
104
|
+
|
105
|
+
if not (running = true) then
|
106
|
+
select case target
|
107
|
+
case ProcessStdOut:
|
108
|
+
_stdout_filename = new_std_filename
|
109
|
+
result = true
|
110
|
+
|
111
|
+
case ProcessStdErr:
|
112
|
+
_stderr_filename = new_std_filename
|
113
|
+
result = true
|
114
|
+
|
115
|
+
case ProcessStdBoth:
|
116
|
+
_stdout_filename = new_std_filename
|
117
|
+
_stderr_filename = new_std_filename
|
118
|
+
result = true
|
119
|
+
|
120
|
+
end select
|
121
|
+
end if
|
122
|
+
|
123
|
+
return result
|
124
|
+
end function
|
125
|
+
|
126
|
+
function ConsoleProcess.start() as boolean
|
127
|
+
dim result as boolean
|
128
|
+
dim success as boolean
|
129
|
+
|
130
|
+
'# API
|
131
|
+
'# New Process resources
|
132
|
+
dim context as STARTUPINFO
|
133
|
+
dim proc_sa as SECURITY_ATTRIBUTES = type(sizeof(SECURITY_ATTRIBUTES), NULL, TRUE)
|
134
|
+
|
135
|
+
'# StdIn, StdOut, StdErr Read and Write Pipes.
|
136
|
+
dim as HANDLE StdInRd, StdOutRd, StdErrRd
|
137
|
+
dim as HANDLE StdInWr, StdOutWr, StdErrWr
|
138
|
+
dim merged as boolean
|
139
|
+
|
140
|
+
'# cmdline
|
141
|
+
dim cmdline as string
|
142
|
+
|
143
|
+
'# assume start will fail
|
144
|
+
result = false
|
145
|
+
|
146
|
+
if (running = false) then
|
147
|
+
'# we should create the std* for the new proc!
|
148
|
+
'# (like good parents, prepare everything!)
|
149
|
+
|
150
|
+
'# to ensure everything will work, we must allocate a console
|
151
|
+
'# using AllocConsole, even if it fails.
|
152
|
+
'# This solve the problems when running as service.
|
153
|
+
'# we discard result of AllocConsole since we ALWAYS will allocate it.
|
154
|
+
AllocConsole()
|
155
|
+
|
156
|
+
'# assume all the following steps succeed
|
157
|
+
success = true
|
158
|
+
|
159
|
+
'# StdIn is the only std that will be created using pipes always
|
160
|
+
'# StdIn
|
161
|
+
if (CreatePipe(@StdInRd, @StdInWr, @proc_sa, 0) = 0) then
|
162
|
+
success = false
|
163
|
+
end if
|
164
|
+
|
165
|
+
'# Ensure the handles to the pipe are not inherited.
|
166
|
+
if (SetHandleInformation(StdInWr, HANDLE_FLAG_INHERIT, 0) = 0) then
|
167
|
+
success = false
|
168
|
+
end if
|
169
|
+
|
170
|
+
'# StdOut and StdErr should be redirected?
|
171
|
+
if (not _stdout_filename = "") or _
|
172
|
+
(not _stderr_filename = "") then
|
173
|
+
|
174
|
+
'# out and err are the same? (merged)
|
175
|
+
if (_stdout_filename = _stderr_filename) then
|
176
|
+
merged = true
|
177
|
+
end if
|
178
|
+
end if
|
179
|
+
|
180
|
+
'# StdOut if stdout_filename
|
181
|
+
if not (_stdout_filename = "") then
|
182
|
+
StdOutWr = CreateFile(strptr(_stdout_filename), _
|
183
|
+
GENERIC_WRITE, _
|
184
|
+
FILE_SHARE_READ or FILE_SHARE_WRITE, _
|
185
|
+
@proc_sa, _
|
186
|
+
OPEN_ALWAYS, _
|
187
|
+
FILE_ATTRIBUTE_NORMAL, _
|
188
|
+
NULL)
|
189
|
+
|
190
|
+
if (StdOutWr = INVALID_HANDLE_VALUE) then
|
191
|
+
'# failed to open file
|
192
|
+
success = false
|
193
|
+
else
|
194
|
+
SetFilePointer(StdOutWr, 0, NULL, FILE_END)
|
195
|
+
end if
|
196
|
+
else
|
197
|
+
'# use pipes instead
|
198
|
+
'# StdOut
|
199
|
+
if (CreatePipe(@StdOutRd, @StdOutWr, @proc_sa, 0) = 0) then
|
200
|
+
success = false
|
201
|
+
end if
|
202
|
+
|
203
|
+
if (SetHandleInformation(StdOutRd, HANDLE_FLAG_INHERIT, 0) = 0) then
|
204
|
+
success = false
|
205
|
+
end if
|
206
|
+
end if 'not (_stdout_filename = "")
|
207
|
+
|
208
|
+
'# only create stderr if no merged.
|
209
|
+
if (merged = true) then
|
210
|
+
StdErrWr = StdOutWr
|
211
|
+
else
|
212
|
+
'# do the same for StdErr...
|
213
|
+
if not (_stderr_filename = "") then
|
214
|
+
StdErrWr = CreateFile(strptr(_stderr_filename), _
|
215
|
+
GENERIC_WRITE, _
|
216
|
+
FILE_SHARE_READ or FILE_SHARE_WRITE, _
|
217
|
+
@proc_sa, _
|
218
|
+
OPEN_ALWAYS, _
|
219
|
+
FILE_ATTRIBUTE_NORMAL, _
|
220
|
+
NULL)
|
221
|
+
|
222
|
+
if (StdErrWr = INVALID_HANDLE_VALUE) then
|
223
|
+
'# failed to open file
|
224
|
+
success = false
|
225
|
+
else
|
226
|
+
SetFilePointer(StdErrWr, 0, NULL, FILE_END)
|
227
|
+
end if
|
228
|
+
else
|
229
|
+
'# use pipes instead
|
230
|
+
'# StdOut
|
231
|
+
if (CreatePipe(@StdErrRd, @StdErrWr, @proc_sa, 0) = 0) then
|
232
|
+
success = false
|
233
|
+
end if
|
234
|
+
|
235
|
+
if (SetHandleInformation(StdErrRd, HANDLE_FLAG_INHERIT, 0) = 0) then
|
236
|
+
success = false
|
237
|
+
end if
|
238
|
+
|
239
|
+
end if 'not (_stderr_filename = "")
|
240
|
+
end if '(merged = true)
|
241
|
+
|
242
|
+
'# now we must proceed to create the process
|
243
|
+
'# without the pipes, we shouldn't continue!
|
244
|
+
if (success = true) then
|
245
|
+
'# Set the Std* handles ;-)
|
246
|
+
with context
|
247
|
+
.cb = sizeof( context )
|
248
|
+
.hStdError = StdErrWr
|
249
|
+
.hStdOutput = StdOutWr
|
250
|
+
.hStdInput = StdInRd
|
251
|
+
.dwFlags = STARTF_USESTDHANDLES or STARTF_USESHOWWINDOW
|
252
|
+
'# FIXME: .wShowWindow = iif((_show_console = true), SW_SHOW, SW_HIDE)
|
253
|
+
.wShowWindow = SW_HIDE
|
254
|
+
end with
|
255
|
+
|
256
|
+
'# build the command line
|
257
|
+
cmdline = _filename + " " + _arguments
|
258
|
+
|
259
|
+
'# now creates the process
|
260
|
+
if (CreateProcess(NULL, _
|
261
|
+
strptr(cmdline), _
|
262
|
+
NULL, _
|
263
|
+
NULL, _
|
264
|
+
1, _ '# win32 TRUE (1)
|
265
|
+
0, _
|
266
|
+
NULL, _
|
267
|
+
NULL, _
|
268
|
+
@context, _
|
269
|
+
@_process_info) = 0) then
|
270
|
+
result = false
|
271
|
+
else
|
272
|
+
'# set the _pid
|
273
|
+
_pid = _process_info.dwProcessId
|
274
|
+
|
275
|
+
'# OK? yeah, I think so.
|
276
|
+
result = true
|
277
|
+
|
278
|
+
'# close the Std* handles
|
279
|
+
CloseHandle(StdInRd)
|
280
|
+
CloseHandle(StdInWr)
|
281
|
+
CloseHandle(StdOutRd)
|
282
|
+
CloseHandle(StdOutWr)
|
283
|
+
CloseHandle(StdErrRd)
|
284
|
+
CloseHandle(StdErrWr)
|
285
|
+
|
286
|
+
'# close children main Thread handle
|
287
|
+
'CloseHandle(proc.hThread)
|
288
|
+
'CloseHandle(proc.hProcess)
|
289
|
+
|
290
|
+
end if '# (CreateProcess() = 0)
|
291
|
+
else
|
292
|
+
result = false
|
293
|
+
end if '# (success = TRUE)
|
294
|
+
end if
|
295
|
+
|
296
|
+
return result
|
297
|
+
end function
|
298
|
+
|
299
|
+
function ConsoleProcess.terminate(byval force as boolean = false) as boolean
|
300
|
+
dim result as boolean
|
301
|
+
dim success as boolean
|
302
|
+
|
303
|
+
dim proc as HANDLE
|
304
|
+
dim code as uinteger
|
305
|
+
dim wait_code as uinteger
|
306
|
+
|
307
|
+
'# is pid valid?
|
308
|
+
if (running = true) then
|
309
|
+
'# hook our custom console handler
|
310
|
+
if not (SetConsoleCtrlHandler(@_console_handler, 1) = 0) then
|
311
|
+
success = true
|
312
|
+
end if
|
313
|
+
|
314
|
+
if (success = true) then
|
315
|
+
'# get a handle to Process
|
316
|
+
proc = _process_info.hProcess
|
317
|
+
if not (proc = NULL) then
|
318
|
+
'# process is valid, perform actions
|
319
|
+
success = false
|
320
|
+
|
321
|
+
if not (force = true) then
|
322
|
+
'# send CTRL_C_EVENT and wait for result
|
323
|
+
if not (GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0) = 0) then
|
324
|
+
'# it worked, wait 5 seconds terminates.
|
325
|
+
wait_code = WaitForSingleObject(proc, 5000)
|
326
|
+
if not (wait_code = WAIT_TIMEOUT) then
|
327
|
+
success = true
|
328
|
+
end if
|
329
|
+
else
|
330
|
+
success = false
|
331
|
+
end if
|
332
|
+
|
333
|
+
'# Ctrl-C didn't work, try Ctrl-Break
|
334
|
+
if (success = false) then
|
335
|
+
'# send CTRL_BREAK_EVENT and wait for result
|
336
|
+
if not (GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, 0) = 0) then
|
337
|
+
'# it worked, wait 5 seconds terminates.
|
338
|
+
wait_code = WaitForSingleObject(proc, 5000)
|
339
|
+
if not (wait_code = WAIT_TIMEOUT) then
|
340
|
+
success = true
|
341
|
+
end if
|
342
|
+
else
|
343
|
+
success = false
|
344
|
+
end if
|
345
|
+
end if
|
346
|
+
|
347
|
+
'# only do termination if force was set.
|
348
|
+
elseif (force = true) and (success = false) then
|
349
|
+
'# still no luck? we should do a hard kill then
|
350
|
+
if (TerminateProcess(proc, 0) = 0) then
|
351
|
+
success = false
|
352
|
+
else
|
353
|
+
success = true
|
354
|
+
end if
|
355
|
+
end if
|
356
|
+
|
357
|
+
'# now get process exit code
|
358
|
+
if (success = true) then
|
359
|
+
result = true
|
360
|
+
else
|
361
|
+
result = false
|
362
|
+
end if
|
363
|
+
else
|
364
|
+
'# invalid process handler
|
365
|
+
result = false
|
366
|
+
end if
|
367
|
+
|
368
|
+
end if '# (success = true)
|
369
|
+
|
370
|
+
'# remove hooks
|
371
|
+
if not (SetConsoleCtrlHandler(@_console_handler, 0) = 0) then
|
372
|
+
success = true
|
373
|
+
end if
|
374
|
+
end if '# not (pid = 0)
|
375
|
+
|
376
|
+
return result
|
377
|
+
end function
|
378
|
+
|
379
|
+
function ConsoleProcess._console_handler(byval dwCtrlType as DWORD) as BOOL
|
380
|
+
dim result as BOOL
|
381
|
+
|
382
|
+
if (dwCtrlType = CTRL_C_EVENT) then
|
383
|
+
result = 1
|
384
|
+
elseif (dwCtrlType = CTRL_BREAK_EVENT) then
|
385
|
+
result = 1
|
386
|
+
end if
|
387
|
+
|
388
|
+
return result
|
389
|
+
end function
|
@@ -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__
|