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