I am trying to build an windows service ( WIN XP SP-2) using the
Win32-service package for ruby.
This service is supposed to pull some stock data from yahoo site
every minute and print to screen.
For this objective to be accomplished i have the following three files
1> yahootickerpull.rb
This has a class Yahooticker and a method called refresh.
2> datasrc_ctl.rb
This has code for controlling the service like
install,start,stop,delete etc… Here i utilize the win32/service
3>yahootickerservice.rb
Here i require the yahootickerpull and win32/service … and override
the “Daemon” class onto “YDaemon” class .
In the “service_init” method i create a Yahooticker object … and in
the service_main method i call the refresh method of this object.
This is the blue print.
problem is i get an error:
C:\mooney.com\historicalqoute\yahooticker>ruby datasrc_ctl.rb start
VERSION: 0.5.2
datasrc_ctl.rb:61:in `start’: The service did not respond to the start
or control
request in a timely fashion. (Win32::ServiceError)
from datasrc_ctl.rb:61
==================================
I suspected the win32/service … but the example code that comes
with the package tdaemon.rb and tdaemon_ctl.rb… works perfectly
…
So i suppose i am doing some fundamental mistakes…
1>1>1>1>1>=======yahootickerpull.rb
require ‘open-uri’
require ‘ostruct’
require ‘csv’
require ‘yaml’
require ‘mysql’
include Enumerable
class Yahooticker
SOURCE_URL = “http://finance.yahoo.com/d/quotes.csv”
#These are the symbols I understand, which are limited
OPTIONS = {
:symbol=>“s”,
:name=>“n”,
:last_trade=>“l1”,
:last_trade_date=>“d1”,
:last_trade_time=>“t1”,
:open=>“o”,
:high=>“h”,
:low=>“g”,
:high_52_week=>“k”,
:low_52_week=>“j”
}
def initialize(symbols, options = [:symbol, :name,
:last_trade, :last_trade_date,
:last_trade_time])
@symbols = symbols
@options = options
@data = nil
end
def each
data.each do |row|
struct = OpenStruct.new(Hash[*(@options.zip(row).flatten)])
yield struct
end
end
def each_hash
data.each do |row|
hash = Hash[*(@options.zip(row).flatten)]
yield hash
end
end
def refresh
#p @symbols.to_s
symbol_fragment = @symbols.to_s.gsub(/\n/,‘+’)
#p “THE symbol: #{symbol_fragment}”
puts “============================”
option_fragment = @options.map{|s| OPTIONS[s] }.join “”
url = SOURCE_URL + “?s=#{symbol_fragment}&f=#{option_fragment}”
#puts “THE URL: #{url}”
@data = []
CSV.parse open(url,:proxy=>“http://127.0.0.1:8080”).read do |row|
this is where we will modify and put it in mysql database
p row
end
end
#def data
#refresh unless @data
#@data
#end
end
1>1>1>1>1>1>==================================
2>2>2>2>2>2>======datasrc_ctl.rb==================
#require ‘yahootickerpull’
require ‘win32/service’
include Win32
puts 'VERSION: ’ + Service::VERSION
I start the service name with an ‘A’ so that it appears at the top
SERVICE_NAME = ‘AbbaSvc’
SERVICE_DISPLAYNAME = ‘Abba’
cmd = ‘c:\ruby\bin\ruby ’
cmd += ‘"’ + File.dirname(File.expand_path($0)).tr(’/', ‘\’) +
‘\yahootickerservice.rb’ + ‘"’
raise ArgumentError, ‘No argument provided’ unless ARGV[0]
case ARGV[0].downcase
when ‘install’
svc = Service.new
svc.create_service{ |s|
s.service_name = SERVICE_NAME
s.display_name = SERVICE_DISPLAYNAME
s.binary_path_name = cmd
}
svc.close
puts ‘Service ’ + SERVICE_NAME + ’ installed’
when ‘start’
if Service.status(SERVICE_NAME).current_state != ‘running’
#@portfolio=[]
#@portfolio=IO.readlines(‘c:\mooney.com\teststock.txt’)
#options=[:symbol, :name, :open, :high , :low]
#@tick = Yahooticker.new(@portfolio,options)
#@tick.refresh
Service.start(SERVICE_NAME)
while Service.status(SERVICE_NAME).current_state != ‘running’
puts ‘One moment…’ +
Service.status(SERVICE_NAME).current_state
sleep 1
end
puts ‘Service ’ + SERVICE_NAME + ’ started’
else
puts ‘Already running’
end
when ‘stop’
if Service.status(SERVICE_NAME).current_state != ‘stopped’
Service.stop(SERVICE_NAME)
while Service.status(SERVICE_NAME).current_state != ‘stopped’
puts ‘One moment…’ +
Service.status(SERVICE_NAME).current_state
sleep 1
end
puts ‘Service ’ + SERVICE_NAME + ’ stopped’
else
puts ‘Already stopped’
end
when ‘uninstall’, ‘delete’
if Service.status(SERVICE_NAME).current_state != ‘stopped’
Service.stop(SERVICE_NAME)
end
while Service.status(SERVICE_NAME).current_state != ‘stopped’
puts ‘One moment…’ +
Service.status(SERVICE_NAME).current_state
sleep 1
end
Service.delete(SERVICE_NAME)
puts ‘Service ’ + SERVICE_NAME + ’ deleted’
when ‘pause’
if Service.status(SERVICE_NAME).current_state != ‘paused’
Service.pause(SERVICE_NAME)
while Service.status(SERVICE_NAME).current_state != ‘paused’
puts ‘One moment…’ +
Service.status(SERVICE_NAME).current_state
sleep 1
end
puts ‘Service ’ + SERVICE_NAME + ’ paused’
else
puts ‘Already paused’
end
when ‘resume’
if Service.status(SERVICE_NAME).current_state != ‘running’
Service.resume(SERVICE_NAME)
while Service.status(SERVICE_NAME).current_state != ‘running’
puts ‘One moment…’ +
Service.status(SERVICE_NAME).current_state
sleep 1
end
puts ‘Service ’ + SERVICE_NAME + ’ resumed’
else
puts ‘Already running’
end
else
raise ArgumentError, 'unknown option: ’ + ARGV[0]
end
2>2>2>2>2>2>=========================================================
3>3>3>3>3>3>===========yahootickerservice.rb====================================
require ‘yahootickerpull’
require ‘win32/service’
include Win32
LOG_FILE = “C:\test.log”
begin
class YDaemon < Daemon
def service_init
@portfolio=[]
@portfolio=IO.readlines(‘c:\mooney.com\teststock.txt’)
options=[:symbol, :name, :open, :high , :low]
@tick=Yahooticker.new(@portfolio,options)
sleep 2
end
def service_main
msg = 'service_main entered at: ' + Time.now.to_s
File.open(LOG_FILE, "a+"){ |f| f.puts msg }
while running?
if state == RUNNING
@tick.refresh
sleep 60
else
sleep 0.5
end
end
File.open(LOG_FILE, "a+"){ |f| f.puts "STATE: #{state}" }
msg = 'service_main left at: ' + Time.now.to_s
File.open(LOG_FILE, "a+"){ |f| f.puts msg }
end
def service_stop
msg = "Received stop signal at: " + Time.now.to_s
File.open(LOG_FILE, "a+"){ |f| f.puts msg }
end
def service_pause
msg = "Received pause signal at: " + Time.now.to_s
File.open(LOG_FILE, "a+"){ |f| f.puts msg }
end
def service_resume
msg = "Received resume signal at: " + Time.now.to_s
File.open(LOG_FILE, "a+"){ |f| f.puts msg }
end
end
YDaemon.new.mainloop
rescue Exception => err
File.open(LOG_FILE, “a+”){ |fh| fh.puts 'Daemon failure: ’ + err }
raise
end
3>3>3>3>3>3>=============================================
sorry for a long post.
Thanks
rajib