lib/daemon/ProjectBroker.rb in taskjuggler-0.0.5 vs lib/daemon/ProjectBroker.rb in taskjuggler-0.0.6
- old
+ new
@@ -14,10 +14,11 @@
require 'thread'
require 'drb'
require 'drb/acl'
require 'daemon/Daemon'
require 'daemon/ProjectServer'
+require 'daemon/WebServer'
require 'TjTime'
class TaskJuggler
# The ProjectBroker is the central object of the TaskJuggler daemon. It can
@@ -33,34 +34,47 @@
#
# Currently only tj3client can be used to communicate with the TaskJuggler
# daemon.
class ProjectBroker < Daemon
- attr_accessor :port
+ attr_accessor :port, :enableWebServer, :webServerPort, :projectFiles
+ attr_reader :authKey
def initialize
super
# We don't have a default key. The user must provice a key in the config
# file. Otherwise the daemon will not start.
@authKey = nil
- # The default TCP/IP port. ASCII decimal codes for 'T' and 'J'.
+ # The default TCP/IP port. ASCII code decimals for 'T' and 'J'.
@port = 8474
# A list of loaded projects as Array of ProjectRecord objects.
@projects = []
# We operate with multiple threads so we need a Monitor to synchronize
# the access to the list.
@projects.extend(MonitorMixin)
+ # A list of the initial projects. Array with Array of files names.
+ @projectFiles = []
+
# This Queue is used to load new projects. The DRb thread pushes load
# requests that the housekeeping thread will then perform.
@projectsToLoad = Queue.new
+ # Referece to WEBrick object.
+ @webServer = nil
+
+ # Port used by the web server
+ @webServerPort = 8080
+
+ # True if web server should be activated
+ @enableWebServer = false
+
# This flag will be set to true to terminate the daemon.
@terminate = false
end
- def start(projects)
+ def start
# To ensure a certain level of security, the user must provide an
# authentication key to authenticate the client to this server.
unless @authKey
@log.fatal(<<'EOT'
You must set an authentication key in the configuration file. Create a file
@@ -71,13 +85,23 @@
authKey: your_secret_key
EOT
)
end
+ # In daemon mode, we fork twice and only the 2nd child continues here.
super()
@log.debug("Starting project broker")
+ begin
+ # The web server must be started before we turn SAFE mode on.
+ @webServer = WebServer.new(self, @webServerPort) if @enableWebServer
+ @log.info("TaskJuggler web server is listening on port " +
+ "#{@webServerPort}")
+ rescue
+ @log.fatal("Cannot start web server: #{$!}")
+ end
+
# Setup a DRb server to handle the incomming requests from the clients.
brokerIface = ProjectBrokerIface.new(self)
begin
$SAFE = 1
DRb.install_acl(ACL.new(%w[ deny all
@@ -88,12 +112,12 @@
@log.fatal("Cannot listen on port #{@port}: #{$!}")
end
# If project files were specified on the command line, we add them here.
i = 0
- projects.each do |project|
- @projectsToLoad.push([ i += 1, project ])
+ @projectFiles.each do |project|
+ @projectsToLoad.push(project)
end
# Start a Thread that waits for the @terminate flag to be set and does
# some other work asynchronously.
startHousekeeping
@@ -119,10 +143,15 @@
# This command will initiate the termination of the daemon.
def stop
@log.debug('Terminating on client request')
+ # Shut down the web server if we've started one.
+ if @webServer
+ @webServer.stop
+ end
+
# Send termination signal to all ProjectServer instances
@projects.synchronize do
@projects.each { |p| p.terminateServer }
end
@@ -221,10 +250,25 @@
return [ nil, nil ]
end
[ project.uri, project.authKey ]
end
+ # Return a list of IDs of projects that are in state :ready.
+ def getProjectList
+ list = []
+ @projects.synchronize do
+ @projects.each do |project|
+ list << project.id if project.state == :ready
+ end
+ end
+ list
+ end
+
+ def report(projectId, reportId)
+ uri, key = getProject(projectId)
+ end
+
# This is a callback from the ProjectServer process. It's used to update
# the current state of the ProjectServer in the ProjectRecord list.
def updateState(authKey, id, state)
result = false
@projects.synchronize do
@@ -294,13 +338,13 @@
end
end
# And then send them a termination command.
termList.each { |p| p.terminateServer }
- # Check every 60 seconds that the ProjectServer processes are
+ # Check every 30 seconds that the ProjectServer processes are
# still alive. If not, remove them from the list.
- if (cntr += 1) > 60
+ if (cntr += 1) > 30
@projects.synchronize do
@projects.each do |p|
unless p.ping
termList << p unless termList.include?(p)
end
@@ -320,13 +364,22 @@
end
end
end
end
- def loadProject(tag)
- @log.debug("Loading project for tag #{tag}")
+ def loadProject(tagOrProject)
+ if tagOrProject.is_a?(Array)
+ tag = rand(9999999999999)
+ project = tagOrProject
+ # The 2nd element of the Array is the *.tjp file name.
+ @log.debug("Loading project #{tagOrProject[1]} with tag #{tag}")
+ else
+ tag = tagOrProject
+ project = nil
+ @log.debug("Loading project for tag #{tag}")
+ end
pr = ProjectRecord.new(tag)
- ps = ProjectServer.new
+ ps = ProjectServer.new(project)
# The ProjectServer can be reached via this DRb URI
pr.uri = ps.uri
# Method calls must be authenticated with this key
pr.authKey = ps.authKey