Ruby Server #eliminate garbage build up - ruby

I have a working TCP/IP socket server that loads 3-flash files in succession. How can I unload previous files and eliminate the garbage build up?
2-Flash clients are active, 1-the loader, 2-the next Flash file being loaded, however "the Flash files don't unload." Maybe there's a "put - kill" method or something similar to addChild removeChild in as3. Any resource would help, since I'm not very familiar with Ruby.
Files involved
POLICY SERVER "server lets Flash files play"
policyserver_little.rb
RUBY TCP/IP SOCKET SERVER "server plays loader, that loads 3-Flash files"
server_little#.rb
FLASH LOADER "client"
loader_little.swf
FLASH MOVIES "numbers_odom.swf, numbers_fruits.swf, $mil.swf"
"msg1, msg2, msg3"
WHAT I SEE
def worker==>end
There's no method to unload.
RUBY SERVER server_little#.rb
require 'socket'
require 'rexml/document'
include Socket::Constants
def create_xml_msg(msg, parent)
el = nil
msg.each do |key, value|
if parent
el = parent.add_element(key)
else
el = REXML::Element.new(key)
end
if value.instance_of?(Hash)
create_xml_msg(value, el)
else
el.text = value.to_s
end
end
return el
end
def worker(client, client_sockaddr, worker_number)
$tid << Thread.new([client, client_sockaddr, worker_number]) do |cl|
Thread.current[:number] = cl[2]
puts("\nThread #{cl[2]} servicing #{Socket.unpack_sockaddr_in(cl[1]).join(':')}")
#2
seq_no = cl[2] * 10000000
loop do
begin
msg1 = {"msg" => {"head" => {"type" => "frctl", "seq_no" => seq_no, "version" => 1.0},
"body" => {"file" => "numbers_odom.swf", "start" => 5,
"end" => 3000, "rate" => 40, "duration" => 60}}}
msg2 = {"msg" => {"head" => {"type" => "frctl", "seq_no" => seq_no, "version" => 1.0},
"body" => {"file" => "numbers_fruits.swf", "start" => 5, "end" => 3000, "rate" => 40, "duration" => 60}}}
msg3 = {"msg" => {"head" => {"type" => "frctl", "seq_no" => seq_no, "version" => 1.0},
"body" => {"file" => "$mil.swf", "start" => 5,
"end" => 3000, "rate" => 40, "duration" => 60}}}
[ msg1, msg2, msg3 ].each do |m|
seq_no += 1
m["msg"]["head"]["seq_no"] = seq_no
xml_msg = create_xml_msg(m, nil)
xml_msg.write(cl[0], 0)
cl[0].putc 0
sleep 10
end
rescue
cl[0].close
puts "\nThread #{Thread.current[:number]} exiting..."
Thread.exit
end
end
end
end
$tid = [] # array of active worker thread ids
$wno = [] # array of active worker numbers
$worker_count = 0
$max_workers = 3
$wlist = Array(1..$max_workers) #array of all possible worker numbers
socket = Socket.new( AF_INET, SOCK_STREAM, 0 )
sockaddr = Socket.pack_sockaddr_in( 1999, '0.0.0.0' )
begin
socket.bind( sockaddr )
socket.listen( 5 )
rescue
print $!.class, " ", $!
sleep 3
retry
end
loop do
begin
$tid.each do |t|
if (t.status == false || t.status == "aborting" )
t.join
$wno.delete(t[:number])
$tid.delete(t)
$worker_count -= 1
puts("\nWorker count #{$worker_count}")
end
end
client, client_sockaddr = socket.accept_nonblock
if (client)
if ($worker_count >= $max_workers)
puts "\n too many clients...\n"
client.puts("<msg>error: too many clients; closing connection...</msg>")
client.close
else
$worker_count += 1
$wlist.each do |w| #find a hole in worker number list
if (!$wno.include?(w))
$wno << w #add new worker number to the active worker num array
worker(client, client_sockaddr, w)
break
end
end
puts("\nWorker count #{$worker_count}")
end
end
rescue Errno::EAGAIN, Errno::ECONNABORTED, Errno::EINTR, Errno::EWOULDBLOCK
IO.select([socket], nil, nil, 1)
retry
end
end
REFERENCE
Ruby version 186-25
http://rubylearning.com/satishtalim/ruby_threads.html

A very good resource for socket programming in ruby:
Ruby Sockets: IBM
It was tough for me to get a feel for your code by reading through it, so I can't give you a direct answer. However I can tell you that if you want a good resource for sockets in ruby that pdf is it.

In general i think the only way to eliminate garbage is to fork off a process, let it do the garbage-y stuff then die. If that's your question. NB that jruby, macruby, and rubinius have more advanced GC's.
-r

Related

How to return to the calling method?

I have a program that uses a method for verification, if that verification failed I would like to return to the method it was called from, for example:
def obtain_pokemon_name
print 'Enter Pokemon: '
pokemon = gets.chomp.capitalize
obtain_basic_attack(pokemon)
end
def obtain_basic_attack(poke)
print 'Enter basic attack: '
basic_attack = gets.chomp.downcase
check_attacks(poke, basic_attack)
obtain_spec_attack(poke)
end
def obtain_spec_attack(poke)
print 'Enter special attack: '
spec_attack = gets.chomp.downcase
check_attacks(poke, spec_attack)
end
def check_attacks(pokemon, attack)
if POKEMON_ATTACKS[pokemon][attack] == nil
puts "#{attack} is not one of #{pokemon}'s attacks, try again.."
return # to where this function was called
else
attack
end
end
begin
obtain_pokemon_name
rescue => e
puts "Failed with error code: #{e}"
end
When this is run:
Enter Pokemon: arbok
Enter basic attack: eat
eat is not one of Arbok's attacks, try again..
Enter special attack: test
test is not one of Arbok's attacks, try again..
Attack list:
POKEMON_ATTACKS = {
'Bulbasaur' => {'tackle' => 10.9, 'vine whip' => 15.4, 'power whip' => 21.4, 'seed bomb' => 12.5, 'sludge bomb' => 19.2},
'Ivysaur' => {'razor leaf' => 10.3, 'vine whip' => 15.4, 'power whip' => 21.4, 'sludge bomb' => 19.2, 'solar beam' => 13.3},
'Kakuna' => {'bug bite' => 13.3, 'poison sting' => 10.3, 'struggle' => 8.8},
'Beedrill' => {'bug bite' => 13.3, 'poison jab' => 14.3, 'aerial ace' => 8.6, 'sludge bomb' => 19.2, 'x-scissor' => 14.3},
'Pidgey' => {'quick attack' => 7.5, 'tackle' => 10.9, 'aerial ace' => 8.6, 'air cutter' => 7.6, 'twister' => 5.6},
'Ekans' => {'acid' => 9.5, 'poison sting' => 10.3, 'gunk shot' => 20.0, 'sludge bomb' => 19.2, 'wrap' => 3.8},
'Arbok' => {'acid' => 9.5, 'bite' => 12.0, 'dark pulse' => 12.9, 'gunk shot' => 20.0, 'sludge wave' => 17.6},
}
So my question is, if the attack is not present in the data, how can I return back to the calling method? So for instance if I call arbok and his attack is tackle if it doesn't exist in the hash, how would I return to the obtain_basic_attack(poke) method?
RIght here:
puts "#{attack} is not one of #{pokemon}'s attacks, try again.."
return # to where this function was called
you should call the original method again. i.e.
if POKEMON_ATTACKS[pokemon][attack] == nil
puts "#{attack} is not one of #{pokemon}'s attacks, try again.."
return obtain_spec_attack(poke)
You could alternatively add this logic to obtain_spec_attack:
def obtain_spec_attack(poke)
loop do
print 'Enter special attack: '
spec_attack = gets.chomp.downcase
attack_found = check_attacks(poke, spec_attack)
if attack_found
break attack_found # this will return attack_found from the loop
else
puts "attack not found"
end
end
end
edit
looking at your question again, I realize you want to return to a method multiple levels up. You could use the approaches I've already outlined, or alternatively use rescue:
def obtain_basic_attack(poke)
begin
print 'Enter basic attack: '
basic_attack = gets.chomp.downcase
check_attacks(poke, basic_attack)
obtain_spec_attack(poke)
rescue AttackNotFoundError
retry # runs the 'begin' block again
end
end
def obtain_spec_attack(poke)
print 'Enter special attack: '
spec_attack = gets.chomp.downcase
check_attacks(poke, spec_attack)
end
def check_attacks(pokemon, attack)
if POKEMON_ATTACKS[pokemon][attack] == nil
puts "#{attack} is not one of #{pokemon}'s attacks, try again.."
raise AttackNotFoundError
else
attack
end
end
In order to use a custom error like AttackNotFoundError, you need to define the error class somewhere:
class AttackNotFoundError < StandardError; end
You could use any error really, such as raise StandardError, but it's better to restrict what errors you're rescuing so that you don't accidentally rescue an unrelated error.

Better way to gurantte initializing without error

My initialization failed randomly.
What the better way to implement the init ?
#client = Mongo::Client.new([ cfg["HOST"] ], :database => cfg["NAME"])
At least retry 10 times.
I found some solution like that
begin
coll.insert( { "counter" => i, "named" => "name#{i}" })
rescue Mongo::ConnectionFailure => ex
sleep(0.5)
coll.insert( { "counter" => i, "named" => "name#{i}" })
end
Is there any elegant way to do so ? because I need to do similar init in my project many places
You could extract your connection logic to another method and do
connections = 0
while connections < 10 # or however many
begin
try_connecting
break # only called when no error raised
rescue Mongo::ConnectionFailure => ex
connections += 1
sleep(0.5)
end
end
or maybe this:
def connect
try_connecting
rescue Mongo::ConnectionFailure => ex
fail = true
sleep(0.5)
ensure
return defined?(fail)
end
10.times { break unless connect }

Errors locating elements with Ruby Watir and PhantomJS

I have a script that runs perfectly in the ChromeWebDriver but fails on PhantomJS. When I check if an element exists i get the following error:
[ERROR - 2014-01-07T19:31:55.878Z] WebElementLocator - _handleLocateCommand - El
ement(s) NOT Found: GAVE UP. Search Stop Time: 1389123115867
This doesn't really seem like an issue as the script continues. However, later on the script will fail unable to locate the following element:
question.div(:class => "choices")
This particular script visits a page that has test questions on it. They are in random order. The script decided what kind of question it is and chooses a random answer.
Thanks for any help. Here is the relevant code:
def QuestionType(question)
if question.div(:class => "questionPrompt").text_field.exists?
puts "FITB"
FITB(question)
#elsif question.div(:class => "choices").ul(:class =>"choices-list").li(:index => 1).checkbox.exists?
elsif question.checkbox.exists?
puts "Checkbox"
Checkbox(question)
else
puts "Radio"
Radio(question)
end
end
def FITB(question)
arn = Random.new.rand(0..10)
if arn == 0
answers.li(:index => arn).radio.set
else
idx = 0
begin
question.div(:class => "questionPrompt").text_field(:index => idx).set("Test #{idx}")
idx = idx + 1;
end while question.div(:class => "questionPrompt").text_field(:index => idx).exists?
end
puts "FITB Complete"
end
def Checkbox(question)
allAnswers = question.div(:class => "choices")
answers = allAnswers.ul
max = answers.lis.length - 1
arn = Random.new.rand(0..max)
if arn == 0
answers.li(:index => arn).radio.set
else
for i in 1..arn
answers.li(:index => i).checkbox.set
end
end
puts "Checkbox Complete"
end
def Radio(question)
allAnswers = question.div(:class => "choices")
answers = allAnswers.ul
max = answers.lis.length - 1
arn = Random.new.rand(0..max)
answers.li(:index => arn).radio.set
puts "Radio Complete"
end

syntax error, unexpected keyword_end, expecting '}' [closed]

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 10 years ago.
I have gotten this syntax error message:
/usr/src/check_in/lib/check_in.rb:105: syntax error, unexpected keyword_end, expecting '}'
class CheckIn < Adhearsion::CallController
def run
answer
#play 'welcome.wav' # "Welcome to the PSG check in application."
logger.info "#{call.from.to_s} called at #{time.now.to_s}"
if verify_phone(call.from) == false # If it's not a site phone
logger.info "Number not recognised, routing to Ops"
#play 'not_site_phone.wav' # "Number not recognized."
#dial(sip:number) # Dial operations
hangup
else
user = verify_uid # Checks the User Id
end
if to_check_out?(user.uid)
check_out(user.uid)
else
update_shift(user.uid)
#play 'thank_you.wav'
end
end
def verify_uid
count = 1 # Generic count variable
input = ask 'enter_uid.wav', :limit => 5, :timeout => 5.seconds #takes user ID as DTMF
while (count <= 3 ) # Tracks the number of attempts
if User.find_by_uid(input.response) == nil # If user.find doesn't return anything
logger.info "Invalid user ID. ID entered = #{input.response} Attepmt = #{count}"
input = ask "please_try_again.wav", :limit => 5, :timeout => 10.seconds
count += 1 # Get user to try again
elsif count == 3
play "try_again_later.wav" #"Please try you again later"
logger.info "Tries exceeded, played try again later."
hangup
else
#user = User.find_by_uid(input) # Assigns the user variable to return.
logger.info "User ID: #{#user.uid} is valid"
return #user
end
end
end
def verify_phone(caller_id)
if Sites.find_by_site_phone(caller_id) != nil
return true
else
return false
end
end
def update_shift (user_id)
#user = User.find_by_uid(user_id) # Grabs the user object
if (#user.checked_in?) # If the user is already checked in assign the relevant attributes
#user.time_olc = time.now
#user.num_ci += 1
#user.check_in.create_check_in(:site_id => #user.site_id, uid => #user.uid, :time => time.now)
logger.info "#{#user.uid} checked in at #{#user.time_olc}"
else # Otherwise set all the attributes for the shift
#user.update_attributes(:checked_in? => true, :time_in => time.now, :time_olc => time.now, :num_ci => 1, :site_id => #user.site.find_by_site_phone(call.from))
#user.check_in.create_check_in(:site_id => #user.site_id, uid => #user.uid, :time => time.now)
logger.info "#{#user.uid} punched in at #{#user.time_in}"
end
end
def to_check_out?(user_id) # Method to see if the user has reached check out
#user = User.find_by_uid(user_id)
num_of_ci = #user.num_ci + #user.num_notifications
if (num_of_ci >= #user.site.shift_len)
return true
else
return false
end
end
def check_out!(user_id)
#user = User.find_by_uid(user_id)
input = ask 'check_out?.wav', :limit => 1, :timeout => 5.seconds
if (input == 1)
update(#user.uid)
else
#user.time_out = time.now
#user.time_olc = time.now
#user.update_attributes(:checked_in => false)
end
report_for_user(uid)
end
def secure
count = 1
play 'secure.wav'
sec = 5.times.map {Random.rand(0..9)
result = ask %w"#{sec[0]}, #{sec[1]}, #{sec[2]}, #{sec[3]}, #{sec[4]}", :limit => 5, :timeout => 5.seconds
while (count <= 3)
if (sec.join == result.response)
logger.info "Check in valid"
return true
elsif (count < 3)
result = ask 'please_try_again.wav', :limit => 5, :timeout => 5.seconds
else
play 'try_again_later.wav'
hangup
end
end
end
def report_for_user(user_id)
#user = Users.find_by_uid(user_id)
report = file.open("/report/#{user_id}-#{#user.site_id}-#{date.current}",w)
user_check_ins = #user.check_in.all
report.write("Time, Site ID, User ID")
user_check_ins.each do |check_in|
report.write("#{user.check_in.time}, #{user.check_in.site_id}, #{user.checkin.uid}")
check_in.destroy
end
end
def notify
foo = Users.all
foo.each do |user|
if user.checked_in?
t1 = Time.now #sets a time place holder
t2 = user.time_olc
convert_time = (t1.hour * 60 * 60) + (t1.min * 60) + t1.sec
convert_tolc = (t2.hour * 60 * 60) + (t2.min * 60) + t1.sec
if ((convert_time - convert_tolc)/60 > 75)
user.num_notification += 1
a = user.uid.to_s
logger.info "#{user.uid} hasn't checked in this hour"
# Adhearsion::OutboundCall.originate '+tel: Mobile' :from => ' ' do
# answer
# play a[0], a[1], a[2], a[3], a[4], 'has_not_checked_in.wav'
# hangup
# end
end
end
end
end
end
In this method you have opened one curly bracket '{' but not closed it.
def secure
count = 1
play 'secure.wav'
sec = 5.times.map {Random.rand(0..9)
result = ask %w"#{sec[0]}, #{sec[1]}, #{sec[2]}, #{sec[3]}, #{sec[4]}", :limit => 5, :timeout => 5.seconds
while (count <= 3)
if (sec.join == result.response)
logger.info "Check in valid"
return true
elsif (count < 3)
result = ask 'please_try_again.wav', :limit => 5, :timeout => 5.seconds
else
play 'try_again_later.wav'
hangup
end
end
end
you are missing a closing brace in secure method at the following line
sec = 5.times.map {Random.rand(0..9)

Strange behavior with instance variables in Shoes

Hey, all. I'm working on making a GUI for a Ruby project using Shoes.
I've got a class called Manager (as in memory manager) that loads a 'process list' from a file, splits it up and assigns things to different 'pages' in memory when a certain execution call is made. I really don't think this part matters too much, though. It all works as a terminal application just fine.
However, Shoes is just baffling me. Here's what I've got so far:
Shoes.app(:title => "Paging Simulator", :width => 800, :height => 450) do
#manager = Manager.new
stack(:width => 200) do
#exec_list = stack {
title "Execution Queue", :size => 14
#exec_lines = para "click button to load", :size => 9
#file_button = button "Load Process List"
#file_button.click {
filename = ask_open_file
# #manager.set_exec_list filename
# alert "this makes no sense"
#exec_lines.text = #manager.exec_list.join "\n"
# exec_lines.text = File.read filename
}
}
end
end
What happens when I run this:
The program view loads as expected. I get a header, a paragraph that says "click button....", and a button. I click the button and I select the file. But this is where things get weird.
If I run the last commented line exec_lines.text = File.read filename it does as I would like, but my manager doesn't get any of the information it needs.
If I run the #manager.set_exec_list filename line, nothing from that line on in the block gets run, including the alert, or any other code I try to put in there.
if I run as shown above, however, I get the output I expect, but I don't get to set my data from the file that I select.
I've tried to figure this out from the Shoes Rules page, but this doesn't seem to be an issue that they address, and their "it changes/doesn't change self" I think I grasp, but it's confusing and I don't think it's exactly related to this problem.
Does anyone have any idea how to get this to work? I'm kind of down to crunch time on this project and I can't seem to get any other Ruby GUI toolkit to even run, so I think I'm pretty stuck with Shoes.
Thanks.
Update
I've tried running ruby-debug on the code when I make the call to #manager.set_exec_list filename, and stepping through it shows that this call is made, but the code never actually (from what I can tell) jumps into that method, and acts like it's the last line of code in the block. Do I need to include these classes inside the Shoes.app block?
Update Nope. That does nothing different.
update fullsource code follows:
#!/usr/bin/env shoes
require 'rubygems'
require 'ruby-debug'
class MemSegment
attr_accessor :filled, :pid, :seg, :seg_id
def initialize(filled=false, pid=nil, seg=nil, seg_id=0)
#filled = filled
#pid = pid.to_i
#seg = seg.to_s
#seg_id = seg_id.to_i
self
end
def fill(pid, seg, seg_id)
#filled = true; #pid = pid; #seg = seg; #seg_id = seg_id;
self
end
def clear
self.filled = false; self.pid = nil; self.seg = nil;
self
end
def filled?
#filled
end
def to_s
filled? ? "#{seg} #{seg_id} for pid #{pid}" : "Free"
end
end
class SimProc
include Enumerable
attr_accessor :pid, :code, :data
def initialize(pid, code, data)
#pid = pid.to_i
#code = code.to_i
#data = data.to_i
end
def each
yield :code, code
yield :data, data
end
def to_s
"[SimProc :pid => #{pid}, :code => #{code}, :data => #{data}]"
end
def to_a
[#pid, #code, #data]
end
end
class Manager
attr_reader :segments, :processes, :exec_list, :exec_object
def initialize
#exec_list = [[1, 2], [3, 4], [5, 6]]
#processes = {}
#segments = Array.new(8) { MemSegment.new }
end
def print_activity
#segments.each_with_index {|s, index| puts "Seg #{index} => #{s}" }
#processes.each_value {|s| puts s }
end
def load_process(pcb, exec_index)
if pcb.size == 3
p = SimProc.new(*pcb)
bad_load = false
#processes.store p.pid, p
#processes[p.pid].each do |proc_seg, bsize|
(bsize / 512.0).ceil.times do |seg_id|
#segments.each_with_index do |s, index|
if !s.filled
#find the first empty memory segment
s.fill p.pid, proc_seg, seg_id
break
# if all slots are filled and we couldn't place a proc block
elsif index == #segments.size - 1
bad_load = true
puts "Cannot find a place for #{proc_seg} segment of size #{bsize}. Requeueing..."
break;
end
end
break if bad_load
end
end
# recover pages and queue the process for later
if bad_load
#segments.each_with_index do |seg, seg_index|
# clear any segments that didn't get loaded properly
if seg.pid == p.pid
seg.clear
puts "Seg #{seg_index} => segment cleared: #{seg}"
end
end
# reinsert this process after the next in the execution list
# it will attempt to load and run after the next process is performed
#exec_list.insert(exec_index + 2, p.to_a)
end
print_activity
elsif pcb.size == 2 and pcb[1] == -1
# a process is exiting
puts "removing pid #{pcb[0]}"
#segments.each { |s| s.clear if s.pid == pcb[0] }
#processes.delete pcb[0]
print_activity
end
end
def set_exec_list(filename)
file = File.open filename
file.each { |pcb| #exec_list << pcb.split.map(&:to_i) } unless file.nil?
filename
end
def main
exseq = File.open('exseq2.txt')
set_exec_list exseq
# this is the object that will be used to run each process with .next
#exec_object = #exec_list.each_with_index
# #exec_list.each_with_index { |pcb, exec_index| load_process(pcb, exec_index) }
(#exec_list.size + 1).times do
load_process(*#exec_object.next)
end
end
end
=begin
manager = Manager.new
manager.main
=end
#=begin
Shoes.app(:title => "Paging Simulator", :width => 800, :height => 450) do
#manager = Manager.new
stack(:width => 200) do
#exec_list = stack {
title "Execution Queue", :size => 14
#exec_lines = para "click button to load", :size => 9
#file_button = button "Load Process List"
debugger
#file_button.click {
filename = ask_open_file
#manager.set_exec_list filename
# alert "this makes no sense"
# #exec_lines.text = #manager.exec_list
# #exec_lines.text = File.read filename
#exec_lines.text = #manager.exec_list.join "\n"
}
}
end
end
#=end
So, a few things:
#1, I don't have the implementation of Manager, so I can't tell you why it breaks. Did you try checking the Shoes console for any errors? Hit control-/ to bring that up. If 'nothing runs after it hits that line,' that's probably the issue.
#2, this does work for me, as long as you change exec_lines to #exec_lines on the last line. Here's what I tried:
class Manager;end
Shoes.app(:title => "Paging Simulator", :width => 800, :height => 450) do
#manager = Manager.new
stack(:width => 200) do
#exec_list = stack {
title "Execution Queue", :size => 14
#exec_lines = para "click button to load", :size => 9
#file_button = button "Load Process List"
#file_button.click {
filename = ask_open_file
#alert "this makes no sense"
#exec_lines.text = File.read filename
}
}
end
end
Hope that helps!

Resources