diff options
Diffstat (limited to 'projects/mongrel_service/lib')
7 files changed, 0 insertions, 1634 deletions
diff --git a/projects/mongrel_service/lib/ServiceFB/ServiceFB.bas b/projects/mongrel_service/lib/ServiceFB/ServiceFB.bas deleted file mode 100644 index 8364867..0000000 --- a/projects/mongrel_service/lib/ServiceFB/ServiceFB.bas +++ /dev/null @@ -1,650 +0,0 @@ -'#--
-'# Copyright (c) 2006-2007 Luis Lavena, Multimedia systems
-'#
-'# This source code is released under the MIT License.
-'# See MIT-LICENSE file for details
-'#++
-
-#include once "ServiceFB.bi"
-#include once "_internals.bi"
-
-namespace fb
-namespace svc
- '# I started this as simple, unique service served from one process
- '# but the idea of share the same process space (and reduce resources use) was good.
- '# to do that, I needed a references table (similar to service_table, but we will
- '# hold the ServiceProcess registered by ServiceHost (the multi services host).
- '# also, I needed a locking mechanism to avoid problems of two calls changing the table
- '# at the same time.
- dim shared _svc_references as ServiceProcess ptr ptr
- dim shared _svc_references_count as integer
- dim shared _svc_references_lock as any ptr
-
-
- '#####################
- '# ServiceProcess
- '# ctor()
- constructor ServiceProcess()
- constructor("NewServiceProcess")
- end constructor
-
-
- '# ctor(name)
- constructor ServiceProcess(byref new_name as string)
- _dprint("ServiceProcess(new_name)")
- '# assign the service name
- this.name = new_name
-
- '# initialize the status structure
- with this._svcStatus
- .dwServiceType = SERVICE_WIN32_OWN_PROCESS
- .dwCurrentState = SERVICE_STOPPED
- .dwControlsAccepted = (SERVICE_ACCEPT_STOP or SERVICE_ACCEPT_SHUTDOWN)
- .dwWin32ExitCode = NO_ERROR
- .dwServiceSpecificExitCode = NO_ERROR
- .dwCheckPoint = 0
- .dwWaitHint = 0
- end with
-
- '# use a state placeholder
- this.state = this._svcStatus.dwCurrentState
-
- '# disable shared process by default
- this.shared_process = FALSE
-
- '# create the stop event
- this._svcStopEvent = CreateEvent( 0, FALSE, FALSE, 0 )
- _dprint("ServiceProcess(new_name) done")
- end constructor
-
-
- '# dtor()
- destructor ServiceProcess()
- _dprint("ServiceProcess() destructor")
- '# safe to destroy it. anyway, just checking
- with this
- .onInit = 0
- .onStart = 0
- .onStop = 0
- .onPause = 0
- .onContinue = 0
- ._threadHandle = 0
- CloseHandle(._svcStopEvent)
- end with
- _dprint("ServiceProcess() destructor done")
- end destructor
-
-
- '# for single process, here I create the references table and then
- '# delegate control to _run() which will call the service control dispatcher
- sub ServiceProcess.Run()
- _dprint("ServiceProcess.Run()")
-
- '# add the unique reference
- _add_to_references(this)
-
- '# delegate control to _run()
- _run()
-
- _dprint("ServiceProcess.Run() done")
- end sub
-
-
- '# I use this method to simplify changing the service state
- '# notification to the service manager.
- '# is needed to set dwControlsAccepted = 0 if state is SERVICE_*_PENDING
- '# also, StillAlive() call it to set the checkpoint and waithint
- '# to avoid SCM shut us down.
- '# is not for the the end-user (*you*) to access it, but implemented in this
- '# way to reduce needed to pass the right service reference each time
- sub ServiceProcess.UpdateState(byval state as DWORD, byval checkpoint as integer = 0, byval waithint as integer = 0)
- _dprint("ServiceProcess.UpdateState()")
- '# set the state
- select case state
- '# if the service is starting or stopping, I must disable the option to accept
- '# other controls form SCM.
- case SERVICE_START_PENDING, SERVICE_STOP_PENDING:
- this._svcStatus.dwControlsAccepted = 0
-
- '# in this case, running or paused, stop and shutdown must be available
- '# also, we must check here if our service is capable of pause/continue ç
- '# functionality and allow them (or not).
- case SERVICE_RUNNING, SERVICE_PAUSED:
- this._svcStatus.dwControlsAccepted = (SERVICE_ACCEPT_STOP or SERVICE_ACCEPT_SHUTDOWN)
-
- '# from start, the service accept stop and shutdown (see ctor(name)).
- '# configure the accepted controls.
- '# Pause and Continue only will be enabled if you setup onPause and onContinue
- if not (this.onPause = 0) and _
- not (this.onContinue = 0) then
- this._svcStatus.dwControlsAccepted or= SERVICE_ACCEPT_PAUSE_CONTINUE
- end if
-
- end select
-
- '# set the structure status
- '# also the property
- this._svcStatus.dwCurrentState = state
- this.state = state
-
- '# set checkpoint and waithint
- this._svcStatus.dwCheckPoint = checkpoint
- this._svcStatus.dwWaitHint = waithint
-
- '# call the API
- '# only we will call is _svcHandle is valid
- '# this will allow use of UpdateState (and StillAlive) from console
- if not (this._svcHandle = 0) then
- _dprint("SetServiceStatus() API")
- SetServiceStatus(this._svcHandle, @this._svcStatus)
- end if
- _dprint("ServiceProcess.UpdateState() done")
- end sub
-
-
- '# use StillAlive() method when performing lengthly tasks during onInit or onStop
- '# (if they take too much time).
- '# by default we set a wait hint gap of 10 seconds, but you could specify how many
- '# you could specify how many seconds more will require your *work*
- sub ServiceProcess.StillAlive(byval waithint as integer = 10)
- dim as integer checkpoint
-
- _dprint("ServiceProcess.StillAlive()")
- '# start or stop pending?
- if (this._svcStatus.dwCurrentState = SERVICE_START_PENDING) or _
- (this._svcStatus.dwCurrentState = SERVICE_STOP_PENDING) then
- with this
- checkpoint = this._svcStatus.dwCheckPoint
- checkpoint += 1
- .UpdateState(._svcStatus.dwCurrentState, checkpoint, (waithint * 1000))
- end with
- end if
- _dprint("ServiceProcess.StillAlive() done")
- end sub
-
-
- '# call_onStart() is a wrapper around the new limitation of threadcreate
- '# sub used as pointers in threadcreate must conform the signature
- sub ServiceProcess.call_onStart(byval any_service as any ptr)
- var service = cast(ServiceProcess ptr, any_service)
- service->onStart(*service)
- end sub
-
- '#####################
- '# ServiceHost
- '# ctor()
- '# currently isn't needed, why I defined it?
- constructor ServiceHost()
- _dprint("ServiceHost()")
- _dprint("ServiceHost() done")
- end constructor
-
-
- '# dtor()
- '# currently isn't needed, why I defined it?
- destructor ServiceHost()
- _dprint("ServiceHost() destructor")
- _dprint("ServiceHost() destructor done")
- end destructor
-
-
- '# using Add() will register an already initialized service into the references
- '# table, which will be used later to launch and control the different services
- '# we should be careful when handling references, so for that reference_lock is
- '# provided ;-)
- sub ServiceHost.Add(byref service as ServiceProcess)
- _dprint("ServiceHost.Add()")
-
- '# add the service reference to the references table
- '# get the new count as result, so
- '# increment the local counter
- this.count = _add_to_references(service)
-
- _dprint("ServiceHost.Add() done")
- end sub
-
-
- '# ServiceHost.Run() is just a placeholder, it delegates control to _run()
- '# pretty simple, but still must be present to simplify user interaction.
- sub ServiceHost.Run()
- _dprint("ServiceHost.Run()")
-
- '# the longest, hard coded function in the world!
- '# just kidding
- _run()
-
- _dprint("ServiceHost.Run() done")
- end sub
-
-
- '# the purpose of this sub is provide a generic service creation and running
- '# this is be called from exisitng ServiceProcess and ServiceHost.
- '# this construct the SERVICE_TABLE_ENTRY based on the the references table,
- '# which will be sent to StartServiceCtrlDispatcher()
- private sub _run()
- dim ServiceTable(_svc_references_count) as SERVICE_TABLE_ENTRY
- dim idx as integer
-
- _dprint("_run()")
-
- _dprint("creating service table for " + str(_svc_references_count) + " services")
- for idx = 0 to (_svc_references_count - 1)
- '# we take the service name from the references and set as ServiceMain the same
- '# _main() routine for all the services
- ServiceTable(idx) = type<SERVICE_TABLE_ENTRY>(strptr(_svc_references[idx]->name), @_main)
- _dprint(str(idx) + ": " + _svc_references[idx]->name)
- next idx
- '# last member of the table must be null
- ServiceTable(_svc_references_count) = type<SERVICE_TABLE_ENTRY>(0, 0)
- _dprint("service table created")
-
- '# start the dispatcher
- _dprint("start service dispatcher")
- StartServiceCtrlDispatcher( @ServiceTable(0) )
-
- _dprint("_run() done")
- end sub
-
-
- '# this sub is fired by StartServiceCtrlDispatcher in another thread.
- '# because it is a global _main for all the services in the table, looking up
- '# in the references for the right service is needed prior registering its
- '# control handler.
- private sub _main(byval argc as DWORD, byval argv as LPSTR ptr)
- dim success as integer
- dim service as ServiceProcess ptr
- dim run_mode as string
- dim service_name as string
- dim commandline as string
- dim param_line as string
- dim temp as string
-
- _dprint("_main()")
-
- '# debug dump of argc and argv
- dim idx as integer = 0
- for idx = 0 to (argc - 1)
- _dprint(str(idx) + ": " + *argv[idx])
- next idx
-
- '# retrieve all the information (mode, service name and command line
- _build_commandline(run_mode, service_name, commandline)
- service = _find_in_references(service_name)
-
- '# build parameter line (passed from SCM)
- if (argc > 1) then
- param_line = ""
- for idx = 1 to (argc - 1)
- temp = *argv[idx]
- if (instr(temp, chr(32)) > 0) then
- param_line += """" + temp + """"
- else
- param_line += temp
- end if
- param_line += " "
- next idx
- end if
-
- '# parameters passed using SCM have priority over ImagePath ones
- if not (len(param_line) = 0) then
- commandline = param_line
- end if
-
- '# a philosofical question: to run or not to run?
- if not (service = 0) then
- _dprint("got a valid service reference")
- _dprint("real service name: " + service->name)
-
- '# pass to the service the commandline
- _dprint("passing service commandline: " + commandline)
- service->commandline = commandline
-
- '# ok, its a service!, its alive!
- '# register his ControlHandlerEx
- _dprint("register control handler ex")
- service->_svcHandle = RegisterServiceCtrlHandlerEx(strptr(service_name), @_control_ex, cast(LPVOID, service))
-
- '# check if evething is done right
- if not (service->_svcHandle = 0) then
- '# now, we are a single service or a bunch, like the bradys?
- if (_svc_references_count > 1) then
- '# determine if we share or not the process
- if (service->shared_process = FALSE) then
- service->_svcStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS
- else
- '# this mean we will be sharing... hope neighbors don't crash the house!
- service->_svcStatus.dwServiceType = SERVICE_WIN32_SHARE_PROCESS
- end if
- else
- '# ok, we have a full house (ehem, process) for us only!
- service->_svcStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS
- end if
-
- '# START_PENDING
- _dprint("service start pending")
- service->UpdateState(SERVICE_START_PENDING)
-
- '# now delegate to the long running initialization if it exist.
- if not (service->onInit = 0) then
- _dprint("pass control to lengthly initialization")
- success = service->onInit(*service)
- else
- '# if no onInit was defined (maybe you don't need it?)
- '# we should simulate it was successful to proceed
- success = (-1)
- end if
- _dprint("onInit result: " + str(success))
-
- '# check if everything is ok
- '# if onInit showed problems, 0 was returned and service must not continue
- if not (success = 0) then
- '# SERVICE_RUNNING
- '# we must launch the onStart as thread, but first setting state as running
- service->UpdateState(SERVICE_RUNNING)
- if not (service->onStart = 0) then
- _dprint("dispatch onStart() as new thread")
- service->_threadHandle = threadcreate(@ServiceProcess.call_onStart, service)
- '# my guess? was a hit!
- end if
-
- '# now that we are out of onStart thread, check if actually hit the stop sign
- _dprint("waiting for stop signal")
- do
- '# do nothing ...
- '# but not too often!
- loop while (WaitForSingleObject(service->_svcStopEvent, 100) = WAIT_TIMEOUT)
-
- '# now, wait for the thread (anyway, I hope it will be checking this.state, right?)
- '# we should do this, or actualy jump and wait for StopEvent?
- _dprint("waiting for onStart() thread to finish")
- threadwait(service->_threadHandle)
- end if
-
- '# if we reach here, that means the service is not running, and the onStop was performed
- '# so no more chat, stop it one and for all!
- '# set SERVICE_STOPPED (just checking)
- _dprint("service stopped")
- service->UpdateState(SERVICE_STOPPED)
- end if
-
- '# ok, we are done!
- end if
-
- _dprint("_main() done")
- end sub
-
-
- '# this sub is used by _main when registering the ControlHandler for this service
- '# (as callback from service manager).
- '# we process each control codes and perform the actions using the pseudo-events (callbacks)
- '# also we use lpContext to get the right reference when _main registered the control handler.
- private function _control_ex(byval dwControl as DWORD, byval dwEventType as DWORD, byval lpEventData as LPVOID, byval lpContext as LPVOID) as DWORD
- dim result as DWORD
- dim service as ServiceProcess ptr
-
- _dprint("_control_ex()")
-
- '# we get a reference form the context
- service = cast(ServiceProcess ptr, lpContext)
-
- '# show if the service reference is valid?
- _dprint("service name: " + service->name)
-
- select case dwControl
- case SERVICE_CONTROL_INTERROGATE:
- '# we are running, so what we should do here?
- _dprint("interrogation signal received")
- '# in case we get a interrogation, we always should answer this way.
- result = NO_ERROR
-
- case SERVICE_CONTROL_SHUTDOWN, SERVICE_CONTROL_STOP:
- _dprint("stop signal received")
- '# ok, service manager requested us to stop.
- '# we must call onStop if was defined.
- service->UpdateState(SERVICE_STOP_PENDING)
- if not (service->onStop = 0) then
- _dprint("pass control to onStop()")
- service->onStop(*service)
- end if
- '# now signal the stop event so _main could take care of the rest.
- _dprint("signal stop event")
- SetEvent(service->_svcStopEvent)
-
- case SERVICE_CONTROL_PAUSE:
- _dprint("pause signal received")
- '# we must check if we could answer to the request.
- if not (service->onPause = 0) and _
- not (service->onContinue = 0) then
-
- '# just to be sure
- if not (service->onPause = 0) then
- service->UpdateState(SERVICE_PAUSE_PENDING)
-
- _dprint("pass control to onPause()")
- service->onPause(*service)
-
- service->UpdateState(SERVICE_PAUSED)
- _dprint("service paused")
- end if
- result = NO_ERROR
-
- else
- '# ok, our service didn't support pause or continue
- '# tell the service manager about that!
- result = ERROR_CALL_NOT_IMPLEMENTED
- end if
-
- case SERVICE_CONTROL_CONTINUE:
- _dprint("continue signal received")
- '# we should resume from a paused state
- '# we must check if we could answer to the request.
- if not (service->onPause = 0) and _
- not (service->onContinue = 0) then
-
- '# just to be sure
- if not (service->onPause = 0) then
- service->UpdateState(SERVICE_CONTINUE_PENDING)
-
- _dprint("pass control to onContinue()")
- service->onContinue(*service)
-
- service->UpdateState(SERVICE_RUNNING)
- _dprint("service running")
- end if
- result = NO_ERROR
-
- else
- '# ok, our service didn't support pause or continue
- '# tell the service manager about that!
- result = ERROR_CALL_NOT_IMPLEMENTED
- end if
-
- case else:
- result = NO_ERROR
- end select
-
- _dprint("_control_ex() done")
- return result
- end function
-
-
- '# add_to_references is a helper used to reduce code duplication (DRY).
- '# here is used a lock around _svc_references to avoid two threads try change the
- '# reference count (just in case).
- function _add_to_references(byref service as ServiceProcess) as integer
- _dprint("_add_to_references()")
-
- '# get a lock before even think touch references!
- mutexlock(_svc_references_lock)
-
- '# now, reallocate space
- _svc_references_count += 1
- _svc_references = reallocate(_svc_references, sizeof(ServiceProcess ptr) * _svc_references_count)
-
- '# put the reference of this service into the table
- _svc_references[(_svc_references_count - 1)] = @service
-
- '# ok, done, unlock our weapons! ;-)
- mutexunlock(_svc_references_lock)
-
- _dprint("_add_to_references() done")
- '# return the new references count
- return _svc_references_count
- end function
-
-
- '# find_in_references is used by _main to lookup for the specified service in
- '# references table.
- function _find_in_references(byref service_name as string) as ServiceProcess ptr
- dim result as ServiceProcess ptr
- dim item as ServiceProcess ptr
- dim idx as integer
-
- _dprint("_find_in_references()")
-
- '# we start with a pesimistic idea ;-)
- result = 0
-
- for idx = 0 to (_svc_references_count - 1)
- '# hold a reference to the item
- item = _svc_references[idx]
-
- '# compare if we have a match
- if (service_name = item->name) then
- result = item
- exit for
- end if
- next idx
-
- _dprint("_find_in_references() done")
- '# return the found (or not) reference
- return result
- end function
-
-
- '# namespace constructor
- '# first we must create the mutex to be used with references
- private sub _initialize() constructor
- _dprint("_initialize() constructor")
- '# we do this in case was already defined... don't know the situation,
- '# just to be sure
- if (_svc_references_lock = 0) then
- _svc_references_lock = mutexcreate()
-
- '# also initialize our count :-)
- _svc_references_count = 0
- end if
-
- _dprint("_initialize() constructor done")
- end sub
-
-
- '# namespace destructor
- private sub _terminate() destructor
- _dprint("_terminate() destructor")
- '# to avoid removing everything, we must lock to the references
- mutexlock(_svc_references_lock)
-
- '# destroy our refernces allocated memory!
- deallocate(_svc_references)
-
- '# unlock the mutex and destroy it too.
- mutexunlock(_svc_references_lock)
- mutexdestroy(_svc_references_lock)
-
- _dprint("_terminate() destructor done")
- end sub
-
-
- '# command line builder (helper)
- '# this is used to gather information about:
- '# mode (if present)
- '# valid service name (after lookup in the table)
- '# command line to be passed to service
- sub _build_commandline(byref mode as string, byref service_name as string, byref commandline as string)
- dim result_mode as string
- dim result_name as string
- dim result_cmdline as string
- dim service as ServiceProcess ptr
- dim idx as integer
- dim temp as string
-
- idx = 1
- '# first, determine if mode is pressent in commandline, must me command(1)
- temp = lcase(command(idx))
-
- if (temp = "console") or _
- (temp = "manage") then
- result_mode = temp
- idx += 1
- end if
-
- '# now, check if service name is present
- temp = command(idx)
-
- '# its present?
- if (len(temp) > 0) then
- '# lookup in references table
- service = _find_in_references(temp)
- if not (service = 0) then
- '# was found, so must be valid
- result_name = temp
- '# adjust start index for cmdline
- idx += 1
- end if
- end if
-
- '# is service valid?
- '# its really needed?
- if (service = 0) then
- if (_svc_references_count = 1) then
- '# no, get the first one
- service = _svc_references[0]
- result_name = service->name
- '# adjust start index for cmdline
- else
- '# this is needed!
- result_name = ""
- end if
- end if
-
- result_cmdline = ""
-
- temp = command(idx)
- do while (len(temp) > 0)
- if (instr(temp, chr(32)) > 0) then
- '# properly quote parameters with spaces
- result_cmdline += """" + temp + """"
- else
- result_cmdline += temp
- end if
- result_cmdline += " "
- idx += 1
-
- temp = command(idx)
- loop
-
- '# now, return the results
- mode = result_mode
- service_name = result_name
- commandline = result_cmdline
- end sub
-
-
- '# ### DEBUG ###
- '# just for debuging purposes
- '# (will be removed in the future when Loggers get implemented)
-#ifdef SERVICEFB_DEBUG_LOG
- sub _dprint(byref message as string)
- dim handle as integer
-
- handle = freefile
- open EXEPATH + "\servicefb.log" for append as #handle
-
- print #handle, message
-
- close #handle
- end sub
-#endif
-end namespace '# fb.svc
-end namespace '# fb
diff --git a/projects/mongrel_service/lib/ServiceFB/ServiceFB.bi b/projects/mongrel_service/lib/ServiceFB/ServiceFB.bi deleted file mode 100644 index dc0acec..0000000 --- a/projects/mongrel_service/lib/ServiceFB/ServiceFB.bi +++ /dev/null @@ -1,109 +0,0 @@ -'#--
-'# Copyright (c) 2006-2007 Luis Lavena, Multimedia systems
-'#
-'# This source code is released under the MIT License.
-'# See MIT-LICENSE file for details
-'#++
-
-#if __FB_VERSION__ < "0.17"
-#error ServiceFB is designed to compile with FreeBASIC version "0.17"
-#else
-
-#ifndef __FB_WIN32__
-#error Platform unsupported. Compiling ServiceFB requires Windows platform.
-#else
-
-#ifndef __ServiceFB_bi__
-#define __ServiceFB_bi__
-
-#include once "windows.bi"
-#inclib "advapi32"
-
-namespace fb
-namespace svc '# fb.svc
-#ifdef SERVICEFB_DEBUG_LOG
- '# debug print
- declare sub _dprint(byref as string)
-#else
- #define _dprint(message)
-#endif
-
- '# service states used by end user with 'state' property
- enum ServiceStateEnum
- Running = SERVICE_RUNNING
- Paused = SERVICE_PAUSED
- Stopped = SERVICE_STOPPED
- end enum
-
-
- '# ServiceProcess type (object)
- '# use this to create new services and reference the on*() methods to perform the related
- '# tasks.
- type ServiceProcess
- '# ctor/dtor
- declare constructor()
- declare constructor(byref as string)
- declare destructor()
-
- '# methods (public)
- declare sub Run()
- declare sub StillAlive(byval as integer = 10)
-
- '# helper methods (private)
- declare sub UpdateState(byval as DWORD, byval as integer = 0, byval as integer = 0)
-
- '# pseudo-events
- '# for onInit you should return FALSE (0) in case you want to abort
- '# service initialization.
- '# If everything was ok, then return TRUE (-1)
- onInit as function(byref as ServiceProcess) as integer
- onStart as sub(byref as ServiceProcess)
- onStop as sub(byref as ServiceProcess)
- onPause as sub(byref as ServiceProcess)
- onContinue as sub(byref as ServiceProcess)
-
- '# call_* are used to avoid the warning arround ThreadCreate
- declare static sub call_onStart(byval as any ptr)
-
- '# properties (public)
- name as string
- description as string
- state as ServiceStateEnum
- commandline as string '# TODO
- shared_process as integer
-
- '# properties (private)
- _svcStatus as SERVICE_STATUS
- _svcHandle as SERVICE_STATUS_HANDLE
- _svcStopEvent as HANDLE
- _threadHandle as any ptr
- end type
-
-
- '# ServiceHost type (object)
- '# use this, beside ServiceProcess, to manage the registration and running of
- '# several services sharing the same process.
- '# NOTE: ServiceHost.Run() and ServiceProcess.Run() are mutually exclusive, that
- '# means don't mix single service with multiple service in the same program!
- type ServiceHost
- '# ctor/dtor()
- declare constructor()
- declare destructor()
-
- '# methods (public)
- declare sub Add(byref as ServiceProcess)
- declare sub Run()
-
- '# properties (public)
- count as integer
- end type
-end namespace '# fb.svc
-end namespace '# fb
-
-#ifdef SERVICEFB_INCLUDE_UTILS
-#include once "ServiceFB_Utils.bi"
-#endif
-
-#endif '# __ServiceFB_bi__
-#endif '# __FB_WIN32__
-#endif '# __FB_VERSION__
\ No newline at end of file diff --git a/projects/mongrel_service/lib/ServiceFB/ServiceFB_Utils.bas b/projects/mongrel_service/lib/ServiceFB/ServiceFB_Utils.bas deleted file mode 100644 index c8a77a3..0000000 --- a/projects/mongrel_service/lib/ServiceFB/ServiceFB_Utils.bas +++ /dev/null @@ -1,493 +0,0 @@ -'#--
-'# Copyright (c) 2006-2007 Luis Lavena, Multimedia systems
-'#
-'# This source code is released under the MIT License.
-'# See MIT-LICENSE file for details
-'#++
-
-#include once "ServiceFB.bi"
-#include once "_internals.bi"
-#include once "ServiceFB_Utils.bi"
-#include once "_utils_internals.bi"
-
-namespace fb
-namespace svc
-namespace utils '# fb.svc.utils
- '# private (internals) for ServiceProcess.Console()
- dim shared _svc_stop_signal as any ptr
- dim shared _svc_stop_mutex as any ptr
- dim shared _svc_stopped as BOOL
- dim shared _svc_in_console as ServiceProcess ptr
- dim shared _svc_in_console_stop_flag as BOOL
-
- '#####################
- '# ServiceController
- '# ctor()
- constructor ServiceController()
- with this
- .product = "My Product"
- .version = "v0.1"
- .copyright = "my copyright goes here."
- end with
- end constructor
-
-
- '# ctor(product)
- constructor ServiceController(byref new_product as string)
- this.product = new_product
- end constructor
-
-
- '# ctor(product, version)
- constructor ServiceController(byref new_product as string, byref new_version as string)
- constructor(new_product)
- this.version = new_version
- end constructor
-
-
- '# ctor(product, version, copyright)
- constructor ServiceController(byref new_product as string, byref new_version as string, byref new_copyright as string)
- constructor(new_product, new_version)
- this.copyright = new_copyright
- end constructor
-
-
- '# dtor()
- destructor ServiceController()
- end destructor
-
-
- '# Banner() will display in the console, information regarding your program
- '# using this formatting:
- '# 'Product', 'Version'
- '# 'Copyright'
- sub ServiceController.Banner()
- '# display Product and Version
- print this.product; ", "; this.version
- print this.copyright
- print ""
- '# leave a empty line between banner (header) and other info
- end sub
-
-
- '# RunMode() provide a simple way to get (*you*) from where this process was started
- '# and do the corresponding action.
- function ServiceController.RunMode() as ServiceRunMode
- dim result as ServiceRunMode
- dim currPID as DWORD
- dim parent_pid as uinteger
- dim parent_name as string
- dim start_mode as string
-
- _dprint("ServiceController.RunMode()")
-
- '# get this process PID
- currPID = GetCurrentProcessId()
- _dprint("CurrentPID: " + str(currPID))
-
- '# get the parent PID
- parent_pid = _parent_pid(currPID)
- _dprint("ParentPID: " + str(parent_pid))
-
- '# now the the name
- parent_name = _process_name(parent_pid)
- if (parent_name = "<unknown>") then
- parent_name = _process_name_dyn_psapi(parent_pid)
- end if
- _dprint("Parent Name: " + parent_name)
-
- '# this process started as service?
- '# that means his parent is services.exe
- if (parent_name = "services.exe") then
- result = RunAsService
- else
- '# ok, it didn't start as service, analyze command line then
- start_mode = lcase(trim(command(1)))
- if (start_mode = "manage") then
- '# start ServiceController.Manage()
- result = RunAsManager
- elseif (start_mode = "console") then
- '# start ServiceController.Console()
- result = RunAsConsole
- else
- '# ok, the first paramenter in the commandline didn't work,
- '# report back so we could send the banner!
- result = RunAsUnknown
- end if
- end if
-
- _dprint("ServiceController.RunMode() done")
- return result
- end function
-
-
- '# Manage will offer the user (end-user) option in the commandline to
- '# install, remove, start, stop and query the status of the installed service
- '# use Manage() when you code a multi-services (ServiceHost) based programs
- '# for single services, use Manage(service)
- sub ServiceController.Manage()
- end sub
-
-
- '# this is used when you want management capabilities for your service
- '# use this for single services, or call Manage() for multi services
- sub ServiceController.Manage(byref service as ServiceProcess)
- end sub
-
-
- '# this offer the user a way to test/debug your service or run it like a normal
- '# program, from the command line
- '# will let you SHUTDOWN the service using CTRL+C
- '# use this for multi-services (ServiceHost) based programs
- sub ServiceController.Console()
- dim working_thread as any ptr
- dim run_mode as string
- dim service_name as string
- dim service as ServiceProcess ptr
- dim commandline as string
- dim success as integer
-
- _dprint("ServiceController.Console()")
-
- '# show the controller banner
- this.Banner()
-
- '# determine how many service exist in references
- if (_svc_references_count > 0) then
- _build_commandline(run_mode, service_name, commandline)
- service = _find_in_references(service_name)
-
- if (service = 0) then
- '# no valid service reference, list available services
- _list_references()
- else
- '# build the command line, excluding 'console' and service_name
- service->commandline = commandline
-
- '# got a service reference
- '# also, set the global handler that will be used by _control_handler
- _svc_in_console = service
-
- '# create the signal used to stop the service thread.
- _svc_stop_signal = condcreate()
- _svc_stop_mutex = mutexcreate()
-
- '# register the Console Handler
- SetConsoleCtrlHandler(@_console_handler, TRUE)
-
- print "Starting service '"; service_name; "' in console mode, please wait..."
-
- '# onInit should be started inline,
- '# and its result validated!
- if not (service->onInit = 0) then
- success = service->onInit(*service)
- end if
-
- '# only continue if success
- if not (success = 0) then
- '# now set service.state to running
- service->state = Running
-
- '# now, fire the main loop (onStart)
- if not (service->onStart = 0) then
- '# create the thread
- working_thread = threadcreate(@ServiceProcess.call_onStart, service)
- if (working_thread = 0) then
- print "Failed to create working thread."
- end if
- end if
-
- print "Service is in running state."
- print "Press Ctrl-C to stop it."
-
- '# now that onStart is running, must monitor the stop_signal
- '# in case it arrives, the service state must change to exit the
- '# working thread.
- mutexlock(_svc_stop_mutex)
- do while (_svc_stopped = FALSE)
- condwait(_svc_stop_signal, _svc_stop_mutex)
- loop
- mutexunlock(_svc_stop_mutex)
-
- print "Stop signal received, stopping..."
-
- '# received the signal, so set state = Stopped
- service->state = Stopped
-
- print "Waiting for onStart() to exit..."
-
- '# now wait for the thread to terminate
- if not (working_thread = 0) then
- threadwait(working_thread)
- end if
-
- else
- print "Error starting the service, onInit() failed."
- end if
-
- print "Service stopped, doing cleanup."
-
- '# remove the console handler
- SetConsoleCtrlHandler(@_console_handler, FALSE)
-
- '# now that service was stopped, destroy the references.
- conddestroy(_svc_stop_signal)
- mutexdestroy(_svc_stop_mutex)
- print "Done."
- end if
- else
- print "ERROR: No services could be served by this program. Exiting."
- end if
-
- _dprint("ServiceController.Console() done")
- end sub
-
-
- '# this offer the user a way to test/debug your service or run it like a normal
- '# program, from the command line
- '# will let you SHUTDOWN the service using CTRL+C
- '# use this for single-services
- sub ServiceController.Console(byref service as ServiceProcess)
-
- _dprint("ServiceController.RunMode(service)")
-
- '# register the service in the references table
- _add_to_references(service)
-
- _dprint("delegate to Console()")
- '# now delegate control to Console()
- this.Console()
-
- _dprint("ServiceController.Console(service) done")
- end sub
-
-
- '# console_handler is used to get feedback form keyboard and allow
- '# shutdown of service using Ctrl+C / Ctrl+Break from keyboard
- function _console_handler(byval dwCtrlType as DWORD) as BOOL
- dim result as BOOL
- dim service as ServiceProcess ptr
-
- _dprint("_console_handler()")
-
- '# get the reference from svc_in_console
- service = _svc_in_console
-
- '# we default processing of the message to false
- result = FALSE
-
- '# avoid recursion problems
- if (_svc_in_console_stop_flag = FALSE) then
- _dprint("no previous signaled, process event")
- '# all the CtrlType events listed will raise the onStop
- '# of the service
- '# here also will be raised the _svc_stop_signal
- select case dwCtrlType
- case CTRL_C_EVENT, CTRL_CLOSE_EVENT, CTRL_BREAK_EVENT, CTRL_LOGOFF_EVENT, CTRL_SHUTDOWN_EVENT:
- _dprint("got supported CTRL_*_EVENT")
- '# avoid recursion problems
- _svc_in_console_stop_flag = TRUE
- _dprint("set signaled to TRUE")
-
- '# the service defined onStop?
- if not (service->onStop = 0) then
- _dprint("pass control to onStop()")
- service->onStop(*service)
- end if
-
- '# now fire the signal
- _dprint("fire stop signal")
- mutexlock(_svc_stop_mutex)
- condsignal(_svc_stop_signal)
- result = TRUE
- _svc_in_console_stop_flag = FALSE
- _svc_stopped = TRUE
- mutexunlock(_svc_stop_mutex)
-
- case else:
- _dprint("unsupported CTRL EVENT")
- result = FALSE
- end select
- else
- _dprint("already running onStop(), do not pass the message to other message handlers!")
- result = TRUE
- end if
-
- _dprint("_console_handler() done")
- return result
- end function
-
-
- '# helper private subs used to list the services and their descriptions
- '# in _svc_references
- private sub _list_references()
- dim item as ServiceProcess ptr
- dim idx as integer
-
- print "Available services in this program:"
-
- for idx = 0 to (_svc_references_count - 1)
- item = _svc_references[idx]
-
- print space(2);
- print trim(item->name), , trim(item->description)
- next idx
-
- end sub
-
-
- '# TODO: SimpleLogger
- '# TODO: EventLogger
-
-
- '#####################
- '# private (internals)
- '# _parent_pid is used to retrieve, based on the PID you passed by, the one of the parent
- '# that launched that process.
- '# on fail, it will return 0
- '# Thanks to MichaelW (FreeBASIC forums) for his help about this.
- private function _parent_pid(byval PID as uinteger) as uinteger
- dim as uinteger result
- dim as HANDLE hProcessSnap
- dim as PROCESSENTRY32 pe32
-
- '# initialize result, 0 = fail, other number, ParentPID
- result = 0
-
- hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)
- if not (hProcessSnap = INVALID_HANDLE_VALUE) then
- pe32.dwSize = sizeof(PROCESSENTRY32)
- if (Process32First(hProcessSnap, @pe32) = TRUE) then
- do
- if (pe32.th32ProcessID = PID) then
- result = pe32.th32ParentProcessID
- exit do
- end if
- loop while not (Process32Next(hProcessSnap, @pe32) = 0)
- end if
- end if
-
- CloseHandle(hProcessSnap)
- return result
- end function
-
-
- '# _process_name is used to retrieve the name (ImageName, BaseModule, whatever) of the PID you
- '# pass to it. if no module name was found, it should return <unknown>
- private function _process_name(byval PID as uinteger) as string
- dim result as string
- dim hProcess as HANDLE
- dim hMod as HMODULE
- dim cbNeeded as DWORD
-
- '# assign "<unknown>" to process name, allocate MAX_PATH (260 bytes)
- result = "<unknown>"
- result += space(MAX_PATH - len(result))
-
- '# get a handle to the Process
- hProcess = OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ, FALSE, PID)
-
- '# if valid, get the process name
- if not (hProcess = NULL) then
- '# success getting Process modules
- if not (EnumProcessModules(hProcess, @hMod, sizeof(hMod), @cbNeeded) = 0) then
- result = space(cbNeeded)
- GetModuleBaseName(hProcess, hMod, strptr(result), len(result))
- end if
- end if
-
- CloseHandle(hProcess)
-
- '# return a trimmed result
- result = trim(result)
- return result
- end function
-
- '# _process_name_dyn_psapi is a workaround for some issues with x64 versions of Windows.
- '# by default, 32bits process can't query information from 64bits modules.
- private function _process_name_dyn_psapi(byval PID as uinteger) as string
- dim result as string
- dim chop as uinteger
- dim zresult as zstring * MAX_PATH
- dim hLib as any ptr
- dim hProcess as HANDLE
- dim cbNeeded as DWORD
- dim GetProcessImageFileName as function (byval as HANDLE, byval as LPTSTR, byval as DWORD) as DWORD
-
- '# assign "<unknown>" to process name, allocate MAX_PATH (260 bytes)
- zresult = "<unknown>" + chr(0)
-
- '# get dynlib
- hLib = dylibload("psapi.dll")
- if not (hlib = 0) then
- GetProcessImageFileName = dylibsymbol(hlib, "GetProcessImageFileNameA")
- if not (GetProcessImageFileName = 0) then
- '# get a handle to the Process
- hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, PID)
-
- '# if valid, get the process name
- if not (hProcess = NULL) then
- cbNeeded = sizeof(zresult)
- if (GetProcessImageFileName(hProcess, @zresult, cbNeeded) = 0) then
- _dprint("Error with GetProcessImageFileName")
- _dprint("GetLastError: " + str(GetLastError()) + _show_error())
- else
- result = zresult
- chop = InStrRev(0, result, "\")
- if (chop > 0) then
- result = mid(result, chop + 1, (len(result) - chop))
- end if
- end if
- else
- _dprint("Error with OpenProcess")
- _dprint("GetLastError: " + str(GetLastError()) + _show_error())
- end if
-
- CloseHandle(hProcess)
- else
- _dprint("Unable to get a reference to dynamic symbol GetProcessImageFileNameA.")
- end if
- else
- _dprint("Unable to dynamic load psapi.dll")
- end if
-
- '# return a trimmed result
- 'result = trim(result)
- return result
- end function
-
- private function _show_error() as string
- dim buffer as string * 1024
- dim p as integer
-
- FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM,_
- 0,_
- GetLastError(),_
- 0,_
- strptr(buffer),_
- 1024,_
- 0 )
- buffer = rtrim(buffer)
- p = instr(buffer, chr(13))
- if p then buffer = left(buffer, p - 1)
-
- return buffer
- end function
-
- private function InStrRev(byval start as uinteger = 0, byref src as string, byref search as string) as uinteger
- dim lensearch as uinteger = len(search)
- dim as uinteger b, a = 0, exit_loop = 0
-
- do
- b = a
- a += 1
- a = instr(a, src, search)
- if start >= lensearch then if a + lensearch > start then exit_loop = 1
- loop while (a > 0) and (exit_loop = 0)
-
- return b
- end function
-
-end namespace '# fb.svc.utils
-end namespace '# fb.svc
-end namespace '# fb
diff --git a/projects/mongrel_service/lib/ServiceFB/ServiceFB_Utils.bi b/projects/mongrel_service/lib/ServiceFB/ServiceFB_Utils.bi deleted file mode 100644 index 8ae1f28..0000000 --- a/projects/mongrel_service/lib/ServiceFB/ServiceFB_Utils.bi +++ /dev/null @@ -1,70 +0,0 @@ -'#--
-'# Copyright (c) 2006-2007 Luis Lavena, Multimedia systems
-'#
-'# This source code is released under the MIT License.
-'# See MIT-LICENSE file for details
-'#++
-
-#if __FB_VERSION__ < "0.17"
-#error ServiceFB is designed to compile with FreeBASIC version "0.17"
-#else
-
-#ifndef __FB_WIN32__
-#error Platform unsupported. Compiling ServiceFB requires Windows platform.
-#else
-
-#ifndef __ServiceFB_Utils_bi__
-#define __ServiceFB_Utils_bi__
-
-#include once "win/psapi.bi"
-#include once "win/tlhelp32.bi"
-
-namespace fb
-namespace svc
-namespace utils '# fb.svc.utils
- '# use this to determine (using select case maybe?) the
- '# mode which the service was invoked.
- enum ServiceRunMode
- RunAsUnknown = 0
- RunAsService
- RunAsManager
- RunAsConsole
- end enum
-
-
- '# ServiceController type (object)
- '# this is a helper object in case you want to implement
- '# console mode (command line testing/debugging) and management (install/remove/control)
- '# to your services, all from the same executable
- type ServiceController
- '# ctor/dtor()
- declare constructor()
- declare constructor(byref as string)
- declare constructor(byref as string, byref as string)
- declare constructor(byref as string, byref as string, byref as string)
- declare destructor()
-
- '# methods (public)
- declare sub Banner()
- declare function RunMode() as ServiceRunMode
- declare sub Manage()
- declare sub Manage(byref as ServiceProcess)
- declare sub Console()
- declare sub Console(byref as ServiceProcess)
-
- '# properties (public)
- '# use these properties for shwoing information on console/manager mode
- '# as banner.
- '# Product, version
- '# copyright
- product as string
- version as string
- copyright as string
- end type
-end namespace '# fb.svc.utils
-end namespace '# fb.svc
-end namespace '# fb
-
-#endif '# __ServiceFB_bi__
-#endif '# __FB_WIN32__
-#endif '# __FB_VERSION__
\ No newline at end of file diff --git a/projects/mongrel_service/lib/ServiceFB/_internals.bi b/projects/mongrel_service/lib/ServiceFB/_internals.bi deleted file mode 100644 index 55ea882..0000000 --- a/projects/mongrel_service/lib/ServiceFB/_internals.bi +++ /dev/null @@ -1,50 +0,0 @@ -'#--
-'# Copyright (c) 2006-2007 Luis Lavena, Multimedia systems
-'#
-'# This source code is released under the MIT License.
-'# See MIT-LICENSE file for details
-'#++
-
-'##################################################################
-'#
-'# DO NOT INCLUDE THIS FILE DIRECTLY!
-'# it is used internaly by ServiceFB
-'# use ServiceFB.bi instead
-'#
-'##################################################################
-
-namespace fb
-namespace svc
- '# now due references locking, I needed a constructor and destructor for
- '# the namespace to garantee everything is cleaned up on termination of the process
- declare sub _initialize() constructor
- declare sub _terminate() destructor
-
- '# global service procedures (private)
- declare sub _main(byval as DWORD, byval as LPSTR ptr)
- declare function _control_ex(byval as DWORD, byval as DWORD, byval as LPVOID, byval as LPVOID) as DWORD
- declare sub _run()
-
- '# global references helper
- declare function _add_to_references(byref as ServiceProcess) as integer
- declare function _find_in_references(byref as string) as ServiceProcess ptr
-
- '# command line builder (helper)
- '# this is used to gather information about:
- '# mode (if present)
- '# valid service name (after lookup in the table)
- '# command line to be passed to service
- declare sub _build_commandline(byref as string, byref as string, byref as string)
-
- '# I started this as simple, unique service served from one process
- '# but the idea of share the same process space (and reduce resources use) was good.
- '# to do that, I needed a references table (similar to service_table, but we will
- '# hold the ServiceProcess registered by ServiceHost (the multi services host).
- '# also, I needed a locking mechanism to avoid problems of two calls changing the table
- '# at the same time.
- extern _svc_references as ServiceProcess ptr ptr
- extern _svc_references_count as integer
- extern _svc_references_lock as any ptr
-end namespace '# fb.svc
-end namespace '# fb
-
diff --git a/projects/mongrel_service/lib/ServiceFB/_utils_internals.bi b/projects/mongrel_service/lib/ServiceFB/_utils_internals.bi deleted file mode 100644 index fab00f0..0000000 --- a/projects/mongrel_service/lib/ServiceFB/_utils_internals.bi +++ /dev/null @@ -1,51 +0,0 @@ -'#--
-'# Copyright (c) 2006-2007 Luis Lavena, Multimedia systems
-'#
-'# This source code is released under the MIT License.
-'# See MIT-LICENSE file for details
-'#++
-
-'##################################################################
-'#
-'# DO NOT INCLUDE THIS FILE DIRECTLY!
-'# it is used internaly by ServiceFB
-'# use ServiceFB_Utils.bi instead
-'#
-'##################################################################
-
-namespace fb
-namespace svc
-namespace utils '# fb.svc.utils
- '# console_handler is used to get feedback form keyboard and allow
- '# shutdown of service using Ctrl+C / Ctrl+Break from keyboard
- declare function _console_handler(byval as DWORD) as BOOL
-
- '# helper private subs used to list the services and their descriptions
- '# in _svc_references
- declare sub _list_references()
-
- '# internals functions used to get Parent PID and Process Name
- '# using this we automatically determine if the service was started by SCM
- '# or by the user, from commandline or from explorer
- declare function _parent_pid(byval as uinteger) as uinteger
- declare function _process_name(byval as uinteger) as string
- declare function _process_name_dyn_psapi(byval as uinteger) as string
- declare function _show_error() as string
-
- '# InStrRev (authored by ikkejw @ freebasic forums)
- '# http://www.freebasic.net/forum/viewtopic.php?p=49315#49315
- declare function InStrRev(byval as uinteger = 0, byref as string, byref as string) as uinteger
-
- '# use a signal (condition) in the console mode to know
- '# when the service should be stopped.
- '# the Console() main loop will wait for it, and the console_handler
- '# will raise in case Ctrl+C / Ctrl+Break or other events are
- '# received.
- extern _svc_stop_signal as any ptr
- extern _svc_stop_mutex as any ptr
- extern _svc_stopped as BOOL
- extern _svc_in_console as ServiceProcess ptr
- extern _svc_in_console_stop_flag as BOOL
-end namespace '# fb.svc.utils
-end namespace '# fb.svc
-end namespace '# fb
diff --git a/projects/mongrel_service/lib/mongrel_service/init.rb b/projects/mongrel_service/lib/mongrel_service/init.rb deleted file mode 100644 index f1475f0..0000000 --- a/projects/mongrel_service/lib/mongrel_service/init.rb +++ /dev/null @@ -1,211 +0,0 @@ -require 'gem_plugin'
-require 'mongrel'
-require 'mongrel/rails'
-require 'rbconfig'
-require 'fileutils'
-
-module Service
- class Install < GemPlugin::Plugin "/commands"
- include Mongrel::Command::Base
-
- def configure
- options [
- ['-N', '--name SVC_NAME', "Required name for the service to be registered/installed.", :@svc_name, nil],
- ['-D', '--display SVC_DISPLAY', "Adjust the display name of the service.", :@svc_display, nil],
- ["-e", "--environment ENV", "Rails environment to run as", :@environment, ENV['RAILS_ENV'] || "development"],
- ['-p', '--port PORT', "Which port to bind to", :@port, 3000],
- ['-a', '--address ADDR', "Address to bind to", :@address, "0.0.0.0"],
- ['-l', '--log FILE', "Where to write log messages", :@log_file, "log/mongrel.log"],
- ['-P', '--pid FILE', "Where to write the PID", :@pid_file, "log/mongrel.pid"],
- ['-n', '--num-procs INT', "Number of processors active before clients denied", :@num_procs, 1024],
- ['-t', '--timeout TIME', "Timeout all requests after 100th seconds time", :@timeout, 0],
- ['-m', '--mime PATH', "A YAML file that lists additional MIME types", :@mime_map, nil],
- ['-c', '--chdir PATH', "Change to dir before starting (will be expanded)", :@cwd, Dir.pwd],
- ['-r', '--root PATH', "Set the document root (default 'public')", :@docroot, "public"],
- ['-B', '--debug', "Enable debugging mode", :@debug, false],
- ['-C', '--config PATH', "Use a config file", :@config_file, nil],
- ['-S', '--script PATH', "Load the given file as an extra config script.", :@config_script, nil],
- ['', '--prefix PATH', "URL prefix for Rails app", :@prefix, nil]
- ]
- end
-
- # When we validate the options, we need to make sure the --root is actually RAILS_ROOT
- # of the rails application we wanted to serve, because later "as service" no error
- # show to trace this.
- def validate
- # TODO: investigate why Win32::Service interfere with gem_plugin
- gem 'win32-service', '>= 0.5.2', '< 0.6.0'
- require 'win32/service'
-
- @cwd = File.expand_path(@cwd)
- valid_dir? @cwd, "Invalid path to change to: #@cwd"
-
- # change there to start, then we'll have to come back after daemonize
- Dir.chdir(@cwd)
-
- # start with the premise of app really exist.
- app_exist = true
- %w{app config log}.each do |path|
- if !File.directory?(File.join(@cwd, path))
- app_exist = false
- break
- end
- end
-
- valid?(@prefix[0].chr == "/" && @prefix[-1].chr != "/", "Prefix must begin with / and not end in /") if @prefix
-
- valid? app_exist == true, "The path you specified isn't a valid Rails application."
-
- valid_dir? File.dirname(@log_file), "Path to log file not valid: #@log_file"
- valid_dir? File.dirname(@pid_file), "Path to pid file not valid: #@pid_file"
- valid_dir? @docroot, "Path to docroot not valid: #@docroot"
- valid_exists? @mime_map, "MIME mapping file does not exist: #@mime_map" if @mime_map
- valid_exists? @config_file, "Config file not there: #@config_file" if @config_file
-
- # We should validate service existance here, right Zed?
- begin
- valid? !Win32::Service.exists?(@svc_name), "The service already exist, please remove it first."
- rescue
- end
-
- valid? @svc_name != nil, "A service name is mandatory."
-
- # default service display to service name
- @svc_display = @svc_name if !@svc_display
-
- return @valid
- end
-
- def run
- gem 'win32-service', '>= 0.5.2', '< 0.6.0'
- require 'win32/service'
-
- # check if mongrel_service.exe is in ruby bindir.
- gem_root = File.join(File.dirname(__FILE__), "..", "..")
- gem_executable = File.join(gem_root, "bin/mongrel_service.exe")
- bindir_executable = File.join(Config::CONFIG['bindir'], '/mongrel_service.exe')
-
- unless File.exist?(bindir_executable)
- STDERR.puts "** Copying native mongrel_service executable..."
- FileUtils.cp gem_executable, bindir_executable rescue nil
- end
-
- unless FileUtils.compare_file(bindir_executable, gem_executable)
- STDERR.puts "** Updating native mongrel_service executable..."
- FileUtils.rm_f bindir_executable rescue nil
- FileUtils.cp gem_executable, bindir_executable rescue nil
- end
-
- # build the command line
- argv = []
-
- # start using the native executable
- argv << '"' + bindir_executable + '"'
-
- # use the 'single' service for now
- argv << "single"
-
- # command line setting override config file settings
- @options = { :host => @address, :port => @port, :cwd => @cwd,
- :log_file => @log_file, :pid_file => @pid_file, :environment => @environment,
- :docroot => @docroot, :mime_map => @mime_map,
- :debug => @debug, :includes => ["mongrel"], :config_script => @config_script,
- :num_procs => @num_procs, :timeout => @timeout, :cpu => @cpu, :prefix => @prefix
- }
-
- # if we are using a config file, pass -c and -C to the service instead of each start parameter.
- if @config_file
- STDERR.puts "** Using #{@config_file} instead of command line parameters."
- conf = YAML.load_file(@config_file)
-
- # add the root folder (-c)
- argv << "-c \"#{conf[:cwd]}\""
-
- # use the config file
- argv << "-C \"#{@config_file}\""
-
- else
- # use the command line instead
- # now the options
- argv << "-e #{@options[:environment]}" if @options[:environment]
- argv << "-p #{@options[:port]}"
- argv << "-a #{@options[:host]}" if @options[:host]
- argv << "-l \"#{@options[:log_file]}\"" if @options[:log_file]
- argv << "-P \"#{@options[:pid_file]}\""
- argv << "-c \"#{@options[:cwd]}\"" if @options[:cwd]
- argv << "-t #{@options[:timeout]}" if @options[:timeout]
- argv << "-m \"#{@options[:mime_map]}\"" if @options[:mime_map]
- argv << "-r \"#{@options[:docroot]}\"" if @options[:docroot]
- argv << "-n #{@options[:num_procs]}" if @options[:num_procs]
- argv << "-B" if @options[:debug]
- argv << "-S \"#{@options[:config_script]}\"" if @options[:config_script]
- argv << "-u #{@options[:cpu.to_i]}" if @options[:cpu]
- argv << "--prefix \"#{@options[:prefix]}\"" if @options[:prefix]
- end
-
- svc = Win32::Service.new
- begin
- svc.create_service{ |s|
- s.service_name = @svc_name
- s.display_name = @svc_display
- s.binary_path_name = argv.join ' '
- s.dependencies = []
- s.service_type = Win32::Service::WIN32_OWN_PROCESS
- }
- puts "Mongrel service '#{@svc_display}' installed as '#{@svc_name}'."
- rescue Win32::ServiceError => err
- puts "There was a problem installing the service:"
- puts err
- end
- svc.close
- end
- end
-
- module ServiceValidation
- def configure
- options [
- ['-N', '--name SVC_NAME', "Required name for the service to be registered/installed.", :@svc_name, nil],
- ]
- end
-
- def validate
- valid? @svc_name != nil, "A service name is mandatory."
-
- gem 'win32-service', '>= 0.5.2', '< 0.6.0'
- require 'win32/service'
-
- # Validate that the service exists
- begin
- valid? Win32::Service.exists?(@svc_name), "There is no service with that name, cannot proceed."
- Win32::Service.open(@svc_name) do |svc|
- valid? svc.binary_path_name.include?("mongrel_service"), "The service specified isn't a Mongrel service."
- end
- rescue
- end
-
- return @valid
- end
- end
-
- class Remove < GemPlugin::Plugin "/commands"
- include Mongrel::Command::Base
- include ServiceValidation
-
- def run
- gem 'win32-service', '>= 0.5.2', '< 0.6.0'
- require 'win32/service'
-
- display_name = Win32::Service.getdisplayname(@svc_name)
-
- begin
- Win32::Service.stop(@svc_name)
- rescue
- end
- begin
- Win32::Service.delete(@svc_name)
- rescue
- end
- puts "#{display_name} service removed."
- end
- end
-end
|