mongrel_service 0.3.4-i386-mswin32
Sign up to get free protection for your applications and to get access to all the features.
- 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__
|