ts3bot/service_template.iced

154 lines
3.8 KiB
Plaintext
Raw Normal View History

Sync = require "sync"
getLogger = require "./logger"
EventEmitter = require("events").EventEmitter
merge = require "merge"
services = require "./services"
module.exports = class Service extends EventEmitter
constructor: (@name, funcs) ->
@log = getLogger @name
@_funcs = funcs
@_funcs.log = @log # for bind lovers and coffeescript fat arrow (=>) lovers
@on "started", => @emit "_ready"
@on "stopped", => @emit "_ready"
if not @dependencies
@dependencies = []
state: "stopped"
start: () => @_start.apply @, [ false ].concat Array.prototype.slice.call(arguments)
startSync: () => Sync () => @start.sync @
_start: (quiet, args...) =>
if typeof quiet != "boolean"
throw new "quiet parameter must be a boolean"
serviceArgs = args.slice 0
cb = serviceArgs.pop()
if typeof cb != "function"
throw new Error "Callback needs to be given and needs to be a function"
# wait until state is definite
if @state != "started" and @state != "stopped"
await @on "_ready", defer()
if @state != "stopped"
@log.warn "Requested startup of #{@name} but it needs to be stopped, current state is #{@state}."
if @state == "started"
@_funcs.start.apply @, serviceArgs.concat [ cb ] # start should return service object and null-error to callback
else
cb? new Error "Invalid state"
return
# make sure dependencies are running
dependencyServices = []
for serviceName in @dependencies
service = services.find serviceName
if not service
@log.error "Could not find dependency #{serviceName}!"
cb? new Error "Dependency #{serviceName} not found"
return
dependencyServices.push service
dependencyServices.sort require("./service_depcomparer") # sort services by dependency
for service in dependencyServices
if service.state != "started"
await service.start defer err
if err
@log.error "Dependency #{service.name} failed, can't start #{@name}"
cb? new Error "Dependency #{service.name} failed"
return
if not quiet
@log.info "Starting #{@name}"
@state = "starting"
@emit "starting"
await @_funcs.start.apply @, serviceArgs.concat [ defer(err, service) ]
if err
cb? err
@emit "startfail", err
@state = "stopped"
return
if not quiet
@log.info "Started #{@name}"
@_lastArgs = args
@state = "started"
@emit "started", service
cb? null, service
stop: () => @_stop.apply @, [ false ].concat Array.prototype.slice.call(arguments)
stopSync: () => Sync () => @stop.sync @
_stop: (quiet, args...) =>
if typeof quiet != "boolean"
throw new "quiet parameter must be a boolean"
serviceArgs = args.slice 0
cb = serviceArgs.pop()
if typeof cb != "function"
throw new Error "Callback needs to be given and needs to be a function"
# wait until state is definite
if @state != "started" and @state != "stopped"
await @on "_ready", defer()
if @state != "started"
@log.warn "Requested shutdown of #{@name} but it needs to be started, current state is #{@state}."
cb? new Error "Invalid state"
return
if not quiet
@log.info "Stopping #{@name}"
@state = "stopping"
@emit "stopping"
await @_funcs.stop.apply @, serviceArgs.concat [ defer(err, service) ]
if err
cb? err
@state = "started"
@emit "stopfail", err
return
if not quiet
@log.info "Stopped #{@name}"
@state = "stopped"
@emit "stopped"
cb?()
restart: (cb) =>
# wait until state is definite
if @state != "started" and @state != "stopped"
await @on "_ready", defer()
@log.info "Restarting #{@name}"
@emit "restarting"
if @state == "started"
await @_stop true, defer(err)
if err
cb? err
if @state == "stopped"
await @_start true, @_lastArgs..., defer(err)
if err
cb? err
@log.info "Restarted #{@name}"
@emit "restarted"
cb? err
restartSync: () => Sync () => @restart.sync @