<commit_before>#Set $LISTEN_GEM_DEBUGGING to 1 or 2 for debugging
#More information on https://github.com/guard/listen
#
$LISTEN_GEM_DEBUGGING = 1

require 'fileutils'
require 'pathname'
require 'listen'
require_relative 'ExtendedString'

class RhoWatcherSubscriber
  def uri=(anUri)
    @uri = anUri
  end

  def uri
    @uri
  end

  def platform=(aString)
    @platform = aString
  end

  def platform
    @platform
  end

  def name=(aString)
    @name = aString
  end

  def name
    @name
  end

  def application=(aString)
    @application = aString
  end

  def application
    @application
  end

  def normalizedPlatformName
    if ['apple', 'iphone' ].include?(@platform.downcase)
      return 'iphone'
    end
    @platform
  end

  def buildTask
    "build:#{self.normalizedPlatformName}:upgrade_package_partial"
  end

  def to_s
    "RhoWatcherSubscriber(uri=#{@uri}, name=#{@name}, platform=#{@platform}, app=#{@application})"
  end

  def to_hash
    hash = {}
    instance_variables.each {|var| hash[var.to_s.delete("@")] = instance_variable_get(var) }
    hash
  end

end

class RhoWatcher
  def initialize
    @attempt = 0
    @subscribers = Array.new
    @listeners = Array.new
    @serverRoot = Dir.mktmpdir
  end

  def addSubscriber(aSubscriber)
    @subscribers << aSubscriber
  end

  def addDirectory(aString)
    listener = Listen.to(aString) do |modified, added, removed|
      self.onFileChanged(added, modified, removed)
    end
    @listeners << listener
  end

  def serverUri=(anUri)
    @serverUri = anUri
  end

  def serverUri
    @serverUri
  end

  def serverRoot
    @serverRoot
  end

  def applicationRoot=(aString)
    @applicationRoot = aString
  end

  def applicationRoot
    @applicationRoot
  end

  def downloadedBundleName
    "bundle_#{@attempt}.zip"
  end

  def hasSubscriberWithUri(aString)
    (@subscribers.index { |each| each.uri == aString }) != nil
  end

  def removeSubsriberWithUri(aString)
    @subscribers.delete_if { |each| each.uri == aString }
  end

  def writeUpdatedListFile(addedFiles, changedFiles)
    self.writeArrayToFile('upgrade_package_add_files.txt', addedFiles + changedFiles)
  end

  def writeRemovedListFile(removedFiles)
    self.writeArrayToFile('upgrade_package_remove_files.txt', removedFiles)
  end

  def writeArrayToFile(filename, anArray)
    File.open(File.join(@applicationRoot, filename), 'w') { |file|
      anArray.each { |each| file.puts(self.relativePath(each)) }
    }
  end


  def onFileChanged(addedFiles, changedFiles, removedFiles)
    puts 'Files changed...'
    self.createDiffFiles(addedFiles, changedFiles, removedFiles)
    self.createBundles
    self.notifySubscribers
    puts 'Subscribers have been notified'
  end

  def relativePath(aString)
    first = Pathname @applicationRoot
    second = Pathname aString
    second.relative_path_from first
  end


  def createDiffFiles(addedFiles, changedFiles, removedFiles)
    puts 'Create diff files'.primary
    self.writeUpdatedListFile(addedFiles, changedFiles)
    self.writeRemovedListFile(removedFiles)
  end


  def createBundles
    puts "Building".primary

    @attempt = @attempt + 1
    buildedPlatforms = []

    @subscribers.each { |each|
      if !buildedPlatforms.include?(each.platform)
        puts "#{each.platform} will build"
        buildedPlatforms << each.platform
        Rake::Task[each.buildTask].invoke
        from = File.join($targetdir, "upgrade_bundle_partial.zip")
        to = File.join(@serverRoot, 'download', each.platform, self.downloadedBundleName)
        FileUtils.mkpath(File.dirname(to))
        FileUtils.cp(from, to)
        puts "Bundle was builded and put into #{to}"
      else
        puts "#{each.platform} already built"
      end
    }
  end

  def notifySubscribers
    @subscribers.each { |each|
      #TODO Create method urlForUpdate in Subscriber with "http://#{each.uri}/development/update_bundle" ?
      query = "/development/update_bundle?http://#{@serverUri.host}:#{@serverUri.port}/download/#{each.platform}/#{self.downloadedBundleName}"
      url = URI("http://#{each.uri}"+query)
      puts "Send to #{each}  request #{url}".primary
      begin
        http = Net::HTTP.new(url.host, url.port)
        http.open_timeout = 5
        http.start() { |http|
          http.get(query)
        }
      rescue Errno::ECONNREFUSED,
          Net::OpenTimeout => e
        #TODO may be it is necessary remove subscriber from list?
        puts "#{each} is not accessible".warning
      end
    }
  end

  def run
    webServer = WEBrick::HTTPServer.new :BindAddress => @serverUri.host, :Port => @serverUri.port, :DocumentRoot => @serverRoot
    self.configureWebServer(webServer)

    webServerThread = Thread.new do
      webServer.start
    end
    puts 'WebServer started'.primary
    puts "Server root: #{@serverRoot}"
    @listeners.each { |each| each.start }
    puts 'FileSystem listeners started'.primary

    trap 'INT' do
      webServer.shutdown<commit_msg>[server side] Paramers ip & port were added in notify request to subscribers<commit_after>#Set $LISTEN_GEM_DEBUGGING to 1 or 2 for debugging
#More information on https://github.com/guard/listen
#
$LISTEN_GEM_DEBUGGING = 1

require 'fileutils'
require 'pathname'
require 'listen'
require_relative 'ExtendedString'

class RhoWatcherSubscriber
  def uri=(anUri)
    @uri = anUri
  end

  def uri
    @uri
  end

  def platform=(aString)
    @platform = aString
  end

  def platform
    @platform
  end

  def name=(aString)
    @name = aString
  end

  def name
    @name
  end

  def application=(aString)
    @application = aString
  end

  def application
    @application
  end

  def normalizedPlatformName
    if ['apple', 'iphone' ].include?(@platform.downcase)
      return 'iphone'
    end
    @platform
  end

  def buildTask
    "build:#{self.normalizedPlatformName}:upgrade_package_partial"
  end

  def to_s
    "RhoWatcherSubscriber(uri=#{@uri}, name=#{@name}, platform=#{@platform}, app=#{@application})"
  end

  def to_hash
    hash = {}
    instance_variables.each {|var| hash[var.to_s.delete("@")] = instance_variable_get(var) }
    hash
  end

end

class RhoWatcher
  def initialize
    @attempt = 0
    @subscribers = Array.new
    @listeners = Array.new
    @serverRoot = Dir.mktmpdir
  end

  def addSubscriber(aSubscriber)
    @subscribers << aSubscriber
  end

  def addDirectory(aString)
    listener = Listen.to(aString) do |modified, added, removed|
      self.onFileChanged(added, modified, removed)
    end
    @listeners << listener
  end

  def serverUri=(anUri)
    @serverUri = anUri
  end

  def serverUri
    @serverUri
  end

  def serverRoot
    @serverRoot
  end

  def applicationRoot=(aString)
    @applicationRoot = aString
  end

  def applicationRoot
    @applicationRoot
  end

  def downloadedBundleName
    "bundle_#{@attempt}.zip"
  end

  def hasSubscriberWithUri(aString)
    (@subscribers.index { |each| each.uri == aString }) != nil
  end

  def removeSubsriberWithUri(aString)
    @subscribers.delete_if { |each| each.uri == aString }
  end

  def writeUpdatedListFile(addedFiles, changedFiles)
    self.writeArrayToFile('upgrade_package_add_files.txt', addedFiles + changedFiles)
  end

  def writeRemovedListFile(removedFiles)
    self.writeArrayToFile('upgrade_package_remove_files.txt', removedFiles)
  end

  def writeArrayToFile(filename, anArray)
    File.open(File.join(@applicationRoot, filename), 'w') { |file|
      anArray.each { |each| file.puts(self.relativePath(each)) }
    }
  end


  def onFileChanged(addedFiles, changedFiles, removedFiles)
    puts 'Files changed...'
    puts "File added: #{addedFiles}"
    puts "File changed: #{changedFiles}"
    puts "File removed: #{removedFiles}"

    self.createDiffFiles(addedFiles, changedFiles, removedFiles)
    self.createBundles
    self.notifySubscribers
    puts 'Subscribers have been notified'
  end

  def relativePath(aString)
    first = Pathname @applicationRoot
    second = Pathname aString
    second.relative_path_from first
  end


  def createDiffFiles(addedFiles, changedFiles, removedFiles)
    puts 'Create diff files'.primary
    self.writeUpdatedListFile(addedFiles, changedFiles)
    self.writeRemovedListFile(removedFiles)
  end


  def createBundles
    puts "Building".primary

    @attempt = @attempt + 1
    puts "Attempt: #{@attempt}"
    builtPlatforms = []
   begin
    @subscribers.each { |each|
      if !builtPlatforms.include?(each.platform)
        puts "#{each.platform} will built".primary
        builtPlatforms << each.platform
        Rake::Task[each.buildTask].invoke
        from = File.join($targetdir, "upgrade_bundle_partial.zip")
        to = File.join(@serverRoot, 'download', each.platform, self.downloadedBundleName)
        FileUtils.mkpath(File.dirname(to))
        FileUtils.cp(from, to)
        puts "Bundle #{each.platform} was built and put into #{to}".primary
      else
        puts "#{each.platform} already built".primary
      end
    }
   rescue => e
     puts e.inspect
   end
  end

  def notifySubscribers
    @subscribers.each { |each|
      #TODO Create method urlForUpdate in Subscriber with "http://#{each.uri}/development/update_bundle" or extract below code to RhoWatcher method?
      ip = each.uri.split(':')[0]
      port = each.uri.split(':')[1]
      query = "/development/update_bundle?http://#{@serverUri.host}:#{@serverUri.port}/download/#{each.platform}/#{self.downloadedBundleName}&ip=#{ip}&port=#{port}"
      url = URI("http://#{each.uri}"+query)
      puts "Send to #{each}  request #{url}".primary
      begin
        http = Net::HTTP.new(url.host, url.port)
        http.open_timeout = 5
        http.start() { |http|
          http.get(url.path + '?' + url.query)
        }
      rescue Errno::ECONNREFUSED,
          Net::OpenTimeout => e
        #TODO may be it is necessary remove subscriber from list?
        puts "#{each} is not accessible".warning
      end
    }
  end

  def run
    webServer = WEBrick::HTTPServer.new :BindAddress => @serverUri.host, :Port => @serverUri.port, :DocumentRoot => @serverRoot
    self.configureWebServer(webServer)

    webServerThread = Thread.new do
      webServer.start
    end
    puts 'WebServer started'.primary
    puts "Server root: #{@serverRoot}"
    @listeners.each { |each| each.start }
    puts 'FileSystem listeners started'.primary

    trap 'INT' do
      webServer.shutdown
{'fraction_non_alphanumeric': 0.10726975895515221, 'fraction_numerical': 0.0013444732545856142, 'mean_word_length': 3.2767967145790555, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 12, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 10, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5735655', 'n_tokens_mistral': 3357, 'n_tokens_neox': 3285, 'n_words': 766}