Class: Lich::Common::Script

Inherits:
Object
  • Object
show all
Defined in:
documented/common/script.rb

Overview

Class for managing scripts This class provides methods to start, manage, and interact with scripts.

Examples:

Starting a script

Script.start("my_script", args)

Direct Known Subclasses

ExecScript, WizardScript

Defined Under Namespace

Classes: JumpError

Constant Summary collapse

JUMP =
JumpError.exception('JUMP')
JUMP_ERROR =
JumpError.exception('JUMP_ERROR')
@@elevated_script_start =
proc { |args|
  if args.empty?
    # fixme: error
    next nil
  elsif args[0].is_a?(String)
    script_name = args[0]
    if args[1]
      if args[1].is_a?(String)
        script_args = args[1]
        if args[2]
          if args[2].is_a?(Hash)
            options = args[2]
          else
            # fixme: error
            next nil
          end
        end
      elsif args[1].is_a?(Hash)
        options = args[1]
        script_args = (options[:args] || String.new)
      else
        # fixme: error
        next nil
      end
    else
      options = Hash.new
    end
  elsif args[0].is_a?(Hash)
    options = args[0]
    if options[:name]
      script_name = options[:name]
    else
      # fixme: error
      next nil
    end
    script_args = (options[:args] || String.new)
  end
   # fixme: look in wizard script directory
  # fixme: allow subdirectories?
  file_list = Dir.children(File.join(SCRIPT_DIR, "custom")).sort_by { |fn| fn.sub(/[.](lic|rb|cmd|wiz)$/, '') }.map { |s| s.prepend("/custom/") } + Dir.children(SCRIPT_DIR).sort_by { |fn| fn.sub(/[.](lic|rb|cmd|wiz)$/, '') }
  if (file_name = (file_list.find { |val| val =~ /^(?:\/custom\/)?#{Regexp.escape(script_name)}\.(?:lic|rb|cmd|wiz)(?:\.gz|\.Z)?$/ || val =~ /^(?:\/custom\/)?#{Regexp.escape(script_name)}\.(?:lic|rb|cmd|wiz)(?:\.gz|\.Z)?$/i } || file_list.find { |val| val =~ /^(?:\/custom\/)?#{Regexp.escape(script_name)}[^.]+\.(?i:lic|rb|cmd|wiz)(?:\.gz|\.Z)?$/ } || file_list.find { |val| val =~ /^(?:\/custom\/)?#{Regexp.escape(script_name)}[^.]+\.(?:lic|rb|cmd|wiz)(?:\.gz|\.Z)?$/i }))
    script_name = file_name.sub(/\..{1,3}$/, '')
  end
  if file_name.nil?
    respond "--- Lich: could not find script '#{script_name}' in directory #{SCRIPT_DIR} or #{SCRIPT_DIR}/custom"
    next nil
  end
  if (options[:force] != true) and (Script.running + Script.hidden).find { |s| s.name =~ /^#{Regexp.escape(script_name.sub('/custom/', ''))}$/i }
    respond "--- Lich: #{script_name} is already running (use #{$clean_lich_char}force [scriptname] if desired)."
    next nil
  end
  begin
    if file_name =~ /\.(?:cmd|wiz)(?:\.gz)?$/i
      trusted = false
      script_obj = WizardScript.new("#{SCRIPT_DIR}/#{file_name}", script_args)
    else
      if script_obj.labels.length > 1
        trusted = false
      else
        trusted = true
      end
      script_obj = Script.new(:file => "#{SCRIPT_DIR}/#{file_name}", :args => script_args, :quiet => options[:quiet])
    end
    if trusted
      script_binding = TRUSTED_SCRIPT_BINDING.call
    else
      script_binding = Scripting.new.script
    end
  rescue
    respond "--- Lich: error: #{$!}\n\t#{$!.backtrace.join("\n\t")}"
    next nil
  end
  unless script_obj
    respond "--- Lich: error: failed to start script (#{script_name})"
    next nil
  end
  script_obj.quiet = true if options[:quiet]
  new_thread = Thread.new {
    100.times { break if Script.current == script_obj; sleep 0.01 }
     if (script = Script.current)
      eval('script = Script.current', script_binding, script.name)
      Thread.current.priority = 1
      respond("--- Lich: #{script.custom? ? 'custom/' : ''}#{script.name} active.") unless script.quiet
      if trusted
        begin
          eval(script.labels[script.current_label].to_s, script_binding, script.name)
        rescue SystemExit
          nil
        rescue SyntaxError
          respond "--- Lich: error: #{$!}\n\t#{$!.backtrace[0..1].join("\n\t")}"
          Lich.log "error: #{$!}\n\t#{$!.backtrace.join("\n\t")}"
        rescue ScriptError
          respond "--- Lich: error: #{$!}\n\t#{$!.backtrace[0..1].join("\n\t")}"
          Lich.log "error: #{$!}\n\t#{$!.backtrace.join("\n\t")}"
        rescue NoMemoryError
          respond "--- Lich: error: #{$!}\n\t#{$!.backtrace[0..1].join("\n\t")}"
          Lich.log "error: #{$!}\n\t#{$!.backtrace.join("\n\t")}"
        rescue LoadError
          respond "--- Lich: error: #{$!}\n\t#{$!.backtrace[0..1].join("\n\t")}"
          Lich.log "error: #{$!}\n\t#{$!.backtrace.join("\n\t")}"
        rescue SecurityError
          respond "--- Lich: error: #{$!}\n\t#{$!.backtrace[0..1].join("\n\t")}"
          Lich.log "error: #{$!}\n\t#{$!.backtrace.join("\n\t")}"
        rescue ThreadError
          respond "--- Lich: error: #{$!}\n\t#{$!.backtrace[0..1].join("\n\t")}"
          Lich.log "error: #{$!}\n\t#{$!.backtrace.join("\n\t")}"
        rescue SystemStackError
          respond "--- Lich: error: #{$!}\n\t#{$!.backtrace[0..1].join("\n\t")}"
          Lich.log "error: #{$!}\n\t#{$!.backtrace.join("\n\t")}"
        rescue JumpError
          if $! == JUMP
            retry if Script.current.get_next_label != JUMP_ERROR
            respond "--- label error: `#{Script.current.jump_label}' was not found, and no `LabelError' label was found!"
            respond $!.backtrace.first
            Lich.log "label error: `#{Script.current.jump_label}' was not found, and no `LabelError' label was found!\n\t#{$!.backtrace.join("\n\t")}"
            Script.current.kill
          else
            respond "--- Lich: error: #{$!}\n\t#{$!.backtrace[0..1].join("\n\t")}"
            Lich.log "error: #{$!}\n\t#{$!.backtrace.join("\n\t")}"
          end
        rescue StandardError
          respond "--- Lich: error: #{$!}\n\t#{$!.backtrace[0..1].join("\n\t")}"
          Lich.log "error: #{$!}\n\t#{$!.backtrace.join("\n\t")}"
        ensure
          Script.current.kill
        end
      else
        begin
          while (script = Script.current) and script.current_label
            proc { foo = script.labels[script.current_label]; eval(foo, script_binding, script.name, 1) }.call
            Script.current.get_next_label
          end
        rescue SystemExit
          nil
        rescue SyntaxError
          respond "--- Lich: error: #{$!}\n\t#{$!.backtrace[0..1].join("\n\t")}"
          Lich.log "error: #{$!}\n\t#{$!.backtrace.join("\n\t")}"
        rescue ScriptError
          respond "--- Lich: error: #{$!}\n\t#{$!.backtrace[0..1].join("\n\t")}"
          Lich.log "error: #{$!}\n\t#{$!.backtrace.join("\n\t")}"
        rescue NoMemoryError
          respond "--- Lich: error: #{$!}\n\t#{$!.backtrace[0..1].join("\n\t")}"
          Lich.log "error: #{$!}\n\t#{$!.backtrace.join("\n\t")}"
        rescue LoadError
          respond "--- Lich: error: #{$!}\n\t#{$!.backtrace[0..1].join("\n\t")}"
          Lich.log "error: #{$!}\n\t#{$!.backtrace.join("\n\t")}"
        rescue SecurityError
          respond "--- Lich: error: #{$!}\n\t#{$!.backtrace[0..1].join("\n\t")}"
          if (name = Script.current.name)
            respond "--- Lich: review this script (#{name}) to make sure it isn't malicious, and type #{$clean_lich_char}trust #{name}"
          end
          Lich.log "error: #{$!}\n\t#{$!.backtrace.join("\n\t")}"
        rescue ThreadError
          respond "--- Lich: error: #{$!}\n\t#{$!.backtrace[0..1].join("\n\t")}"
          Lich.log "error: #{$!}\n\t#{$!.backtrace.join("\n\t")}"
        rescue SystemStackError
          respond "--- Lich: error: #{$!}\n\t#{$!.backtrace[0..1].join("\n\t")}"
          Lich.log "error: #{$!}\n\t#{$!.backtrace.join("\n\t")}"
        rescue JumpError
          if $! == JUMP
            retry if Script.current.get_next_label != JUMP_ERROR
            respond "--- label error: `#{Script.current.jump_label}' was not found, and no `LabelError' label was found!"
            respond $!.backtrace.first
            Lich.log "label error: `#{Script.current.jump_label}' was not found, and no `LabelError' label was found!\n\t#{$!.backtrace.join("\n\t")}"
            Script.current.kill
          else
            respond "--- Lich: error: #{$!}\n\t#{$!.backtrace[0..1].join("\n\t")}"
            Lich.log "error: #{$!}\n\t#{$!.backtrace.join("\n\t")}"
          end
        rescue StandardError
          respond "--- Lich: error: #{$!}\n\t#{$!.backtrace[0..1].join("\n\t")}"
          Lich.log "error: #{$!}\n\t#{$!.backtrace.join("\n\t")}"
        ensure
          Script.current.kill
        end
      end
    else
      respond '--- error: out of cheese'
    end
  }
  script_obj.thread_group.add(new_thread)
  script_obj
}
@@elevated_exists =
proc { |script_name|
  if script_name =~ /\\|\//
    nil
  elsif script_name =~ /\.(?:lic|lich|rb|cmd|wiz)(?:\.gz)?$/i
    File.exist?("#{SCRIPT_DIR}/#{script_name}") || File.exist?("#{SCRIPT_DIR}/custom/#{script_name}")
  else
    File.exist?("#{SCRIPT_DIR}/#{script_name}.lic") || File.exist?("#{SCRIPT_DIR}/custom/#{script_name}.lic") ||
      File.exist?("#{SCRIPT_DIR}/#{script_name}.lich") || File.exist?("#{SCRIPT_DIR}/custom/#{script_name}.lich") ||
      File.exist?("#{SCRIPT_DIR}/#{script_name}.rb") || File.exist?("#{SCRIPT_DIR}/custom/#{script_name}.rb") ||
      File.exist?("#{SCRIPT_DIR}/#{script_name}.cmd") || File.exist?("#{SCRIPT_DIR}/custom/#{script_name}.cmd") ||
      File.exist?("#{SCRIPT_DIR}/#{script_name}.wiz") || File.exist?("#{SCRIPT_DIR}/custom/#{script_name}.wiz") ||
      File.exist?("#{SCRIPT_DIR}/#{script_name}.lic.gz") || File.exist?("#{SCRIPT_DIR}/custom/#{script_name}.lic.gz") ||
      File.exist?("#{SCRIPT_DIR}/#{script_name}.rb.gz") || File.exist?("#{SCRIPT_DIR}/custom/#{script_name}.rb.gz") ||
      File.exist?("#{SCRIPT_DIR}/#{script_name}.cmd.gz") || File.exist?("#{SCRIPT_DIR}/custom/#{script_name}.cmd.gz") ||
      File.exist?("#{SCRIPT_DIR}/#{script_name}.wiz.gz") || File.exist?("#{SCRIPT_DIR}/custom/#{script_name}.wiz.gz")
  end
}
@@elevated_log =
proc { |data|
  if (script = Script.current)
    if script.name =~ /\\|\//
      nil
    else
      begin
        Dir.mkdir("#{LICH_DIR}/logs") unless File.exist?("#{LICH_DIR}/logs")
        File.open("#{LICH_DIR}/logs/#{script.name}.log", 'a') { |f| f.puts data }
        true
      rescue
        respond "--- Lich: error: Script.log: #{$!}"
        false
      end
    end
  else
    respond '--- error: Script.log: unable to identify calling script'
    false
  end
}
@@elevated_db =
proc {
  if (script = Script.current)
    if script.name =~ /^lich$/i
      respond '--- error: Script.db cannot be used by a script named lich'
      nil
    elsif script.is_a?(ExecScript)
      respond '--- error: Script.db cannot be used by exec scripts'
      nil
    else
      SQLite3::Database.new("#{DATA_DIR}/#{script.name.gsub(/\/|\\/, '_')}.db3")
    end
  else
    respond '--- error: Script.db called by an unknown script'
    nil
  end
}
@@elevated_open_file =
proc { |ext, mode, _block|
  if (script = Script.current)
    if script.name =~ /^lich$/i
      respond '--- error: Script.open_file cannot be used by a script named lich'
      nil
    elsif script.name =~ /^entry$/i
      respond '--- error: Script.open_file cannot be used by a script named entry'
      nil
    elsif script.is_a?(ExecScript)
      respond '--- error: Script.open_file cannot be used by exec scripts'
      nil
    elsif ext.downcase == 'db3'
      SQLite3::Database.new("#{DATA_DIR}/#{script.name.gsub(/\/|\\/, '_')}.db3")
      # fixme: block gets elevated... why?
      #         elsif block
      #            File.open("#{DATA_DIR}/#{script.name.gsub(/\/|\\/, '_')}.#{ext.gsub(/\/|\\/, '_')}", mode, &block)
    else
      File.open("#{DATA_DIR}/#{script.name.gsub(/\/|\\/, '_')}.#{ext.gsub(/\/|\\/, '_')}", mode)
    end
  else
    respond '--- error: Script.open_file called by an unknown script'
    nil
  end
}
@@running =
Array.new

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(args) ⇒ Script

Returns a new instance of Script.



600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
# File 'documented/common/script.rb', line 600

def initialize(args)
  @file_name = args[:file]
  @name = /.*[\/\\]+([^\.]+)\./.match(@file_name).captures.first
  @custom = (/.*[\/\\]+(custom)[\/\\]+[^\.]+\./.match(@file_name).captures.nil? ? false : true)
  if args[:args].is_a?(String)
    if args[:args].empty?
      @vars = Array.new
    else
      @vars = [args[:args]]
      @vars.concat(args[:args].scan(/[^\s"]*(?<!\\)"(?:\\"|[^"])+(?<!\\)"[^\s]*|(?:\\"|[^"\s])+/).collect { |s| s.gsub(/(?<!\\)"/, '').gsub('\\"', '"') })
    end
  elsif args[:args].is_a?(Array)
    unless (args[:args].nil? || args[:args].empty?)
      @vars = [args[:args].join(" ")]
      @vars.concat args[:args]
    else
      @vars = Array.new
    end
  else
    @vars = Array.new
  end
  @quiet = (args[:quiet] ? true : false)
  @downstream_buffer = LimitedArray.new
  @downstream_buffer.max_size = 400
  @want_downstream = true
  @want_downstream_xml = false
  @want_script_output = false
  @upstream_buffer = LimitedArray.new
  @want_upstream = false
  @unique_buffer = LimitedArray.new
  @watchfor = Hash.new
  @at_exit_procs = Array.new
  @die_with = Array.new
  @paused = false
  @hidden = false
  @no_pause_all = false
  @no_kill_all = false
  @silent = false
  @safe = false
  @no_echo = false
  @match_stack_labels = Array.new
  @match_stack_strings = Array.new
  @label_order = Array.new
  @labels = Hash.new
  @killer_mutex = Mutex.new
  @ignore_pause = false
  data = nil
  if @file_name =~ /\.gz$/i
    begin
      Zlib::GzipReader.open(@file_name) { |f| data = f.readlines.collect { |line| line.chomp } }
    rescue
      respond "--- Lich: error reading script file (#{@file_name}): #{$!}"
      # return nil
    end
  else
    begin
      File.open(@file_name) { |f| data = f.readlines.collect { |line| line.chomp } }
    rescue
      respond "--- Lich: error reading script file (#{@file_name}): #{$!}"
      # return nil
    end
  end
  @quiet = true if data[0] =~ /^[\t\s]*#?[\t\s]*(?:quiet|hush)$/i
  @current_label = '~start'
  @labels[@current_label] = String.new
  @label_order.push(@current_label)
  for line in data
    if line =~ /^([\d_\w]+):$/
      @current_label = $1
      @label_order.push(@current_label)
      @labels[@current_label] = String.new
    else
      @labels[@current_label].concat "#{line}\n"
    end
  end
  data = nil
  @current_label = @label_order[0]
  @thread_group = ThreadGroup.new
  @@running.push(self)
  # return self
end

Instance Attribute Details

#at_exit_procsObject (readonly)

Returns the value of attribute at_exit_procs.



304
305
306
# File 'documented/common/script.rb', line 304

def at_exit_procs
  @at_exit_procs
end

#command_lineObject

Returns the value of attribute command_line.



305
306
307
# File 'documented/common/script.rb', line 305

def command_line
  @command_line
end

#current_labelObject

Returns the value of attribute current_label.



305
306
307
# File 'documented/common/script.rb', line 305

def current_label
  @current_label
end

#die_withObject

Returns the value of attribute die_with.



305
306
307
# File 'documented/common/script.rb', line 305

def die_with
  @die_with
end

#downstream_bufferObject

Returns the value of attribute downstream_buffer.



305
306
307
# File 'documented/common/script.rb', line 305

def downstream_buffer
  @downstream_buffer
end

#file_nameObject (readonly)

Returns the value of attribute file_name.



304
305
306
# File 'documented/common/script.rb', line 304

def file_name
  @file_name
end

#hiddenObject

Returns the value of attribute hidden.



305
306
307
# File 'documented/common/script.rb', line 305

def hidden
  @hidden
end

#ignore_pauseObject

Returns the value of attribute ignore_pause.



305
306
307
# File 'documented/common/script.rb', line 305

def ignore_pause
  @ignore_pause
end

#jump_labelObject

Returns the value of attribute jump_label.



305
306
307
# File 'documented/common/script.rb', line 305

def jump_label
  @jump_label
end

#label_orderObject (readonly)

Returns the value of attribute label_order.



304
305
306
# File 'documented/common/script.rb', line 304

def label_order
  @label_order
end

#match_stack_labelsObject

Returns the value of attribute match_stack_labels.



305
306
307
# File 'documented/common/script.rb', line 305

def match_stack_labels
  @match_stack_labels
end

#match_stack_stringsObject

Returns the value of attribute match_stack_strings.



305
306
307
# File 'documented/common/script.rb', line 305

def match_stack_strings
  @match_stack_strings
end

#nameObject (readonly)

Returns the value of attribute name.



304
305
306
# File 'documented/common/script.rb', line 304

def name
  @name
end

#no_echoObject

Returns the value of attribute no_echo.



305
306
307
# File 'documented/common/script.rb', line 305

def no_echo
  @no_echo
end

#no_kill_allObject

Returns the value of attribute no_kill_all.



305
306
307
# File 'documented/common/script.rb', line 305

def no_kill_all
  @no_kill_all
end

#no_pause_allObject

Returns the value of attribute no_pause_all.



305
306
307
# File 'documented/common/script.rb', line 305

def no_pause_all
  @no_pause_all
end

#pausedObject

Returns the value of attribute paused.



305
306
307
# File 'documented/common/script.rb', line 305

def paused
  @paused
end

#quietObject

Returns the value of attribute quiet.



305
306
307
# File 'documented/common/script.rb', line 305

def quiet
  @quiet
end

#safeObject (readonly)

Returns the value of attribute safe.



304
305
306
# File 'documented/common/script.rb', line 304

def safe
  @safe
end

#silentObject

Returns the value of attribute silent.



305
306
307
# File 'documented/common/script.rb', line 305

def silent
  @silent
end

#unique_bufferObject

Returns the value of attribute unique_buffer.



305
306
307
# File 'documented/common/script.rb', line 305

def unique_buffer
  @unique_buffer
end

#upstream_bufferObject

Returns the value of attribute upstream_buffer.



305
306
307
# File 'documented/common/script.rb', line 305

def upstream_buffer
  @upstream_buffer
end

#varsObject (readonly)

Returns the value of attribute vars.



304
305
306
# File 'documented/common/script.rb', line 304

def vars
  @vars
end

#want_downstreamObject

Returns the value of attribute want_downstream.



305
306
307
# File 'documented/common/script.rb', line 305

def want_downstream
  @want_downstream
end

#want_downstream_xmlObject

Returns the value of attribute want_downstream_xml.



305
306
307
# File 'documented/common/script.rb', line 305

def want_downstream_xml
  @want_downstream_xml
end

#want_script_outputObject

Returns the value of attribute want_script_output.



305
306
307
# File 'documented/common/script.rb', line 305

def want_script_output
  @want_script_output
end

#want_upstreamObject

Returns the value of attribute want_upstream.



305
306
307
# File 'documented/common/script.rb', line 305

def want_upstream
  @want_upstream
end

#watchforObject

Returns the value of attribute watchfor.



305
306
307
# File 'documented/common/script.rb', line 305

def watchfor
  @watchfor
end

Class Method Details

.at_exit(&block) ⇒ Object



483
484
485
486
487
488
489
490
# File 'documented/common/script.rb', line 483

def Script.at_exit(&block)
  if (script = Script.current)
    script.at_exit(&block)
  else
    respond "--- Lich: error: Script.at_exit: can't identify calling script"
    return false
  end
end

.clear_exit_procsObject



492
493
494
495
496
497
498
499
# File 'documented/common/script.rb', line 492

def Script.clear_exit_procs
  if (script = Script.current)
    script.clear_exit_procs
  else
    respond "--- Lich: error: Script.clear_exit_procs: can't identify calling script"
    return false
  end
end

.currentScript?

Retrieves the currently running script

Returns:

  • (Script, nil)

    The current script or nil if none is running



362
363
364
365
366
367
368
369
# File 'documented/common/script.rb', line 362

def Script.current
  if (script = @@running.find { |s| s.has_thread?(Thread.current) })
    sleep 0.2 while script.paused? and not script.ignore_pause
    script
  else
    nil
  end
end

.dbObject



475
476
477
# File 'documented/common/script.rb', line 475

def Script.db
  @@elevated_db.call
end

.distrust(_script_name) ⇒ Object



556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
# File 'documented/common/script.rb', line 556

def Script.distrust(script_name)
  begin
    there = Lich.db.get_first_value('SELECT name FROM trusted_scripts WHERE name=?;', [script_name.encode('UTF-8')])
  rescue SQLite3::BusyException
    sleep 0.1
    retry
  end
  if there
    begin
      Lich.db.execute('DELETE FROM trusted_scripts WHERE name=?;', [script_name.encode('UTF-8')])
    rescue SQLite3::BusyException
      sleep 0.1
      retry
    end
    true
  else
    false
  end
end

.exists?(script_name) ⇒ Boolean

Checks if a script exists

Parameters:

  • script_name (String)

    The name of the script to check

Returns:

  • (Boolean)

    True if the script exists, false otherwise



428
429
430
# File 'documented/common/script.rb', line 428

def Script.exists?(script_name)
  @@elevated_exists.call(script_name)
end

.exit!Object



501
502
503
504
505
506
507
508
# File 'documented/common/script.rb', line 501

def Script.exit!
  if (script = Script.current)
    script.exit!
  else
    respond "--- Lich: error: Script.exit!: can't identify calling script"
    return false
  end
end

.hiddenObject



527
528
529
530
531
532
533
# File 'documented/common/script.rb', line 527

def Script.hidden
  list = Array.new
  for script in @@running
    list.push(script) if script.hidden
  end
  return list
end

.indexObject



523
524
525
# File 'documented/common/script.rb', line 523

def Script.index
  Script.running
end

.kill(name) ⇒ Object



408
409
410
411
412
413
414
415
# File 'documented/common/script.rb', line 408

def Script.kill(name)
  if (s = (@@running.find { |i| i.name == name }) || (@@running.find { |i| i.name =~ /^#{name}$/i }))
    s.kill
    true
  else
    false
  end
end

.listArray<Script>

Lists all currently running scripts

Returns:

  • (Array<Script>)

    An array of currently running scripts



356
357
358
# File 'documented/common/script.rb', line 356

def Script.list
  @@running.dup
end

.list_trustedObject



576
577
578
579
580
581
582
583
584
585
# File 'documented/common/script.rb', line 576

def Script.list_trusted
  list = Array.new
  begin
    Lich.db.execute('SELECT name FROM trusted_scripts;').each { |name| list.push(name[0]) }
  rescue SQLite3::BusyException
    sleep 0.1
    retry
  end
  list
end

.log(data) ⇒ Object



471
472
473
# File 'documented/common/script.rb', line 471

def Script.log(data)
  @@elevated_log.call(data)
end

.namescript_incoming(line) ⇒ Object



535
536
537
# File 'documented/common/script.rb', line 535

def Script.namescript_incoming(line)
  Script.new_downstream(line)
end

.new_downstream(line) ⇒ Object



444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
# File 'documented/common/script.rb', line 444

def Script.new_downstream(line)
  @@running.each { |script|
    script.downstream_buffer.push(line.chomp) if script.want_downstream
    unless script.watchfor.empty?
      script.watchfor.each_pair { |trigger, action|
        if line =~ trigger
          new_thread = Thread.new {
            sleep 0.011 until Script.current
            begin
              action.call
            rescue
              echo "watchfor error: #{$!}"
            end
          }
          script.thread_group.add(new_thread)
        end
      }
    end
  }
end

.new_downstream_xml(line) ⇒ Object



432
433
434
435
436
# File 'documented/common/script.rb', line 432

def Script.new_downstream_xml(line)
  for script in @@running
    script.downstream_buffer.push(line.chomp) if script.want_downstream_xml
  end
end

.new_script_output(line) ⇒ Object



465
466
467
468
469
# File 'documented/common/script.rb', line 465

def Script.new_script_output(line)
  for script in @@running
    script.downstream_buffer.push(line.chomp) if script.want_script_output
  end
end

.new_upstream(line) ⇒ Object



438
439
440
441
442
# File 'documented/common/script.rb', line 438

def Script.new_upstream(line)
  for script in @@running
    script.upstream_buffer.push(line.chomp) if script.want_upstream
  end
end

.open_file(ext, mode = 'r', &block) ⇒ Object



479
480
481
# File 'documented/common/script.rb', line 479

def Script.open_file(ext, mode = 'r', &block)
  @@elevated_open_file.call(ext, mode, block)
end

.pause(name = nil) ⇒ Object



385
386
387
388
389
390
391
392
393
394
395
396
397
# File 'documented/common/script.rb', line 385

def Script.pause(name = nil)
  if name.nil?
    Script.current.pause
    Script.current
  else
    if (s = (@@running.find { |i| (i.name == name) and not i.paused? }) || (@@running.find { |i| (i.name =~ /^#{name}$/i) and not i.paused? }))
      s.pause
      true
    else
      false
    end
  end
end

.paused?(name) ⇒ Boolean

Returns:

  • (Boolean)


417
418
419
420
421
422
423
# File 'documented/common/script.rb', line 417

def Script.paused?(name)
  if (s = (@@running.find { |i| i.name == name }) || (@@running.find { |i| i.name =~ /^#{name}$/i }))
    s.paused?
  else
    nil
  end
end

.run(*args) ⇒ Object



375
376
377
378
379
# File 'documented/common/script.rb', line 375

def Script.run(*args)
  if (s = @@elevated_script_start.call(args))
    sleep 0.1 while @@running.include?(s)
  end
end

.runningObject



515
516
517
518
519
520
521
# File 'documented/common/script.rb', line 515

def Script.running
  list = Array.new
  for script in @@running
    list.push(script) unless script.hidden
  end
  return list
end

.running?(name) ⇒ Boolean

Returns:

  • (Boolean)


381
382
383
# File 'documented/common/script.rb', line 381

def Script.running?(name)
  @@running.any? { |i| (i.name =~ /^#{name}$/i) }
end

.selfObject

moved from lich.rbw 2024



511
512
513
# File 'documented/common/script.rb', line 511

def Script.self
  Script.current
end

.start(*args) ⇒ Object



371
372
373
# File 'documented/common/script.rb', line 371

def Script.start(*args)
  @@elevated_script_start.call(args)
end

.trust(_script_name) ⇒ Object



540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
# File 'documented/common/script.rb', line 540

def Script.trust(script_name)
  # fixme: case sensitive blah blah
  if not caller.any? { |c| c =~ /eval|run/ }
    begin
      Lich.db.execute('INSERT OR REPLACE INTO trusted_scripts(name) values(?);', [script_name.encode('UTF-8')])
    rescue SQLite3::BusyException
      sleep 0.1
      retry
    end
    true
  else
    respond '--- error: scripts may not trust scripts'
    false
  end
end

.unpause(name) ⇒ Object



399
400
401
402
403
404
405
406
# File 'documented/common/script.rb', line 399

def Script.unpause(name)
  if (s = (@@running.find { |i| (i.name == name) and i.paused? }) || (@@running.find { |i| (i.name =~ /^#{name}$/i) and i.paused? }))
    s.unpause
    true
  else
    false
  end
end

.version(script_name, script_version_required = nil) ⇒ Gem::Version?

Retrieves the version of a script

Parameters:

  • script_name (String)

    The name of the script

  • script_version_required (String, nil) (defaults to: nil)

    The required version of the script

Returns:

  • (Gem::Version, nil)

    The version of the script or nil if not found

Raises:

  • (StandardError)

    If the script cannot be found



317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
# File 'documented/common/script.rb', line 317

def Script.version(script_name, script_version_required = nil)
  script_name = script_name.sub(/[.](lic|rb|cmd|wiz)$/, '')
  file_list = Dir.children(File.join(SCRIPT_DIR, "custom")).sort_by { |fn| fn.sub(/[.](lic|rb|cmd|wiz)$/, '') }.map { |s| s.prepend("/custom/") } + Dir.children(SCRIPT_DIR).sort_by { |fn| fn.sub(/[.](lic|rb|cmd|wiz)$/, '') }
  if (file_name = (file_list.find { |val| val =~ /^(?:\/custom\/)?#{Regexp.escape(script_name)}\.(?:lic|rb|cmd|wiz)(?:\.gz|\.Z)?$/ || val =~ /^(?:\/custom\/)?#{Regexp.escape(script_name)}\.(?:lic|rb|cmd|wiz)(?:\.gz|\.Z)?$/i } || file_list.find { |val| val =~ /^(?:\/custom\/)?#{Regexp.escape(script_name)}[^.]+\.(?i:lic|rb|cmd|wiz)(?:\.gz|\.Z)?$/ } || file_list.find { |val| val =~ /^(?:\/custom\/)?#{Regexp.escape(script_name)}[^.]+\.(?:lic|rb|cmd|wiz)(?:\.gz|\.Z)?$/i }))
    script_name = file_name.sub(/\..{1,3}$/, '')
  end
  if file_name.nil?
    respond "--- Lich: could not find script '#{script_name}' in directory #{SCRIPT_DIR}"
    return nil
  end

  script_version = '0.0.0'
  script_data = File.open("#{SCRIPT_DIR}/#{file_name}", 'r').read
  if script_data =~ /^=begin\r?\n?(.+?)^=end/m
    comments = $1.split("\n")
  else
    comments = []
    script_data.split("\n").each { |line|
      if line =~ /^[\t\s]*#/
        comments.push(line)
      elsif line !~ /^[\t\s]*$/
        break
      end
    }
  end
  for line in comments
    if line =~ /^[\s\t#]*version:[\s\t]*([\w,\s\.\d]+)/i
      script_version = $1.sub(/\s\(.*?\)/, '').strip
    end
  end
  if script_version_required
    Gem::Version.new(script_version) < Gem::Version.new(script_version_required)
  else
    Gem::Version.new(script_version)
  end
end

Instance Method Details

#at_exit(&block) ⇒ Object



710
711
712
713
714
715
716
717
718
# File 'documented/common/script.rb', line 710

def at_exit(&block)
  if block
    @at_exit_procs.push(block)
    return true
  else
    respond '--- warning: Script.at_exit called with no code block'
    return false
  end
end

#clearObject



791
792
793
794
795
# File 'documented/common/script.rb', line 791

def clear
  to_return = @downstream_buffer.dup
  @downstream_buffer.clear
  to_return
end

#clear_exit_procsObject



720
721
722
723
# File 'documented/common/script.rb', line 720

def clear_exit_procs
  @at_exit_procs.clear
  true
end

#custom?Boolean

Returns:

  • (Boolean)


871
872
873
# File 'documented/common/script.rb', line 871

def custom?
  @custom
end

#exitObject



725
726
727
# File 'documented/common/script.rb', line 725

def exit
  kill
end

#exit!Object



729
730
731
732
# File 'documented/common/script.rb', line 729

def exit!
  @at_exit_procs.clear
  kill
end

#feedme_upstreamObject



857
858
859
# File 'documented/common/script.rb', line 857

def feedme_upstream
  @want_upstream = !@want_upstream
end

#get_next_labelObject



772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
# File 'documented/common/script.rb', line 772

def get_next_label
  if !@jump_label
    @current_label = @label_order[@label_order.index(@current_label) + 1]
  else
    if (label = @labels.keys.find { |val| val =~ /^#{@jump_label}$/ })
      @current_label = label
    elsif (label = @labels.keys.find { |val| val =~ /^#{@jump_label}$/i })
      @current_label = label
    elsif (label = @labels.keys.find { |val| val =~ /^labelerror$/i })
      @current_label = label
    else
      @current_label = nil
      return JUMP_ERROR
    end
    @jump_label = nil
    @current_label
  end
end

#getsObject



801
802
803
804
805
806
807
808
809
810
811
# File 'documented/common/script.rb', line 801

def gets
  # fixme: no xml gets
  if @want_downstream or @want_downstream_xml or @want_script_output
    sleep 0.05 while @downstream_buffer.empty?
    @downstream_buffer.shift
  else
    echo 'this script is set as unique but is waiting for game data...'
    sleep 2
    false
  end
end

#gets?Boolean

Returns:

  • (Boolean)


813
814
815
816
817
818
819
820
821
822
823
824
825
# File 'documented/common/script.rb', line 813

def gets?
  if @want_downstream or @want_downstream_xml or @want_script_output
    if @downstream_buffer.empty?
      nil
    else
      @downstream_buffer.shift
    end
  else
    echo 'this script is set as unique but is waiting for game data...'
    sleep 2
    false
  end
end

#has_thread?(t) ⇒ Boolean

Returns:

  • (Boolean)


746
747
748
# File 'documented/common/script.rb', line 746

def has_thread?(t)
  @thread_group.list.include?(t)
end

#instance_eval(*_a) ⇒ Object



736
# File 'documented/common/script.rb', line 736

def instance_eval(*_a);         nil; end

#instance_variable_get(*_a) ⇒ Object



734
# File 'documented/common/script.rb', line 734

def instance_variable_get(*_a); nil; end

#killObject



682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
# File 'documented/common/script.rb', line 682

def kill
  Thread.new {
    @killer_mutex.synchronize {
      if @@running.include?(self)
        begin
          @thread_group.list.dup.each { |t|
            unless t == Thread.current
              t.kill rescue nil
            end
          }
          @thread_group.add(Thread.current)
          @die_with.each { |script_name| Script.kill(script_name) }
          @paused = false
          @at_exit_procs.each { |p| report_errors { p.call } }
          @die_with = @at_exit_procs = @downstream_buffer = @upstream_buffer = @match_stack_labels = @match_stack_strings = nil
          @@running.delete(self)
          respond("--- Lich: #{@custom ? 'custom/' : ''}#{@name} has exited.") unless @quiet
          GC.start
        rescue
          respond "--- Lich: error: #{$!}"
          Lich.log "error: #{$!}\n\t#{$!.backtrace.join("\n\t")}"
        end
      end
    }
  }
  @name
end

#labelsObject



738
739
740
# File 'documented/common/script.rb', line 738

def labels
  @labels
end

#match_stack_add(label, string) ⇒ Object



861
862
863
864
# File 'documented/common/script.rb', line 861

def match_stack_add(label, string)
  @match_stack_labels.push(label)
  @match_stack_strings.push(string)
end

#match_stack_clearObject



866
867
868
869
# File 'documented/common/script.rb', line 866

def match_stack_clear
  @match_stack_labels.clear
  @match_stack_strings.clear
end

#pauseObject



750
751
752
753
754
755
756
757
# File 'documented/common/script.rb', line 750

def pause
  if @paused == true
    respond "--- Lich: #{@name} is already paused."
  else
    respond "--- Lich: #{@name} paused."
    @paused = true
  end
end

#paused?Boolean

Returns:

  • (Boolean)


768
769
770
# File 'documented/common/script.rb', line 768

def paused?
  @paused
end

#safe?Boolean

Returns:

  • (Boolean)


853
854
855
# File 'documented/common/script.rb', line 853

def safe?
  @safe
end

#thread_groupObject



742
743
744
# File 'documented/common/script.rb', line 742

def thread_group
  @thread_group
end

#to_sObject



797
798
799
# File 'documented/common/script.rb', line 797

def to_s
  @name
end

#unique_getsObject



840
841
842
843
# File 'documented/common/script.rb', line 840

def unique_gets
  sleep 0.05 while @unique_buffer.empty?
  @unique_buffer.shift
end

#unique_gets?Boolean

Returns:

  • (Boolean)


845
846
847
848
849
850
851
# File 'documented/common/script.rb', line 845

def unique_gets?
  if @unique_buffer.empty?
    nil
  else
    @unique_buffer.shift
  end
end

#unpauseObject



759
760
761
762
763
764
765
766
# File 'documented/common/script.rb', line 759

def unpause
  if @paused == true
    respond "--- Lich: #{@name} unpaused."
    @paused = false
  else
    respond "--- Lich: #{@name} is not paused."
  end
end

#upstream_getsObject



827
828
829
830
# File 'documented/common/script.rb', line 827

def upstream_gets
  sleep 0.05 while @upstream_buffer.empty?
  @upstream_buffer.shift
end

#upstream_gets?Boolean

Returns:

  • (Boolean)


832
833
834
835
836
837
838
# File 'documented/common/script.rb', line 832

def upstream_gets?
  if @upstream_buffer.empty?
    nil
  else
    @upstream_buffer.shift
  end
end