lib/vagrant-notify/server.rb
require 'socket'
require 'json'
require 'tmpdir'
module Vagrant
module Notify
class Server
HTTP_RESPONSE = "Hi! You just reached the vagrant notification server"
def self.run(id, port, bind_ip, sender_app, sender_params_str, sender_params_escape, machine_name='default', provider='virtualbox')
#id = env[:machine].id
#machine_name = env[:machine].name
#provider = env[:machine].provider_name
#sender_app = env[:machine].config.sender_app
#sender_params_str = env[:machine].config.sender_params_str
#sender_params_escape = env[:machine].config.sender_params_escape
if __FILE__ == $0
begin
tcp_server = TCPServer.open(bind_ip, port)
rescue
exit 1
end
server = self.new(id, sender_app, sender_params_str, sender_params_escape, machine_name, provider)
# Have to wrap this in a begin/rescue block so we can be certain the server is running at all times.
begin
loop {
Thread.start(tcp_server.accept) { |client|
Thread.handle_interrupt(Interrupt => :never) {
server.receive_data(client)
}
}
}
rescue Interrupt
retry
end
end
end
def initialize(id, sender_app, sender_params_str, sender_params_escape, machine_name = :default, provider = :virtualbox)
@id = id
@machine_name = machine_name
@provider = provider
@sender_app = sender_app
@sender_params_str = sender_params_str
@sender_params_escape = sender_params_escape
end
def receive_data(client)
args = read_args(client)
if http_request?(args)
client.puts HTTP_RESPONSE
else
json_data=JSON.parse(args)
parsed_args=map_params_str(json_data)
fix_icon_path! parsed_args
system "#{@sender_app} #{parsed_args}"
end
client.close
rescue => ex
log ex.message
end
private
# Maps params str with values
#
#@param data [Map] Array values map
#
#@return [String]
def map_params_str(data)
cmd=@sender_params_str + ''
cmd.gsub! '%', '%%'
replace=[]
cmd.scan(/\[[^\]]+\]/).each do |part|
variable=part[/\{[^\}]+\}/][1..-2]
if data.key? variable
replace << part[1..-2].sub('{' + variable + '}', escape_param(data[variable]))
cmd.sub! part, '%'+replace.length.to_s+'$s'
else
cmd.sub! part, ''
end
end
cmd.scan(/\{[^\}]+\}/).each do |part|
variable=part[1..-2]
if data.key? variable
replace << escape_param(data[variable])
cmd.sub! part, '%'+replace.length.to_s+'$s'
end
end
cmd % replace
end
def log(message)
File.open(@log_path, 'a+') do |log|
log.puts "#{message}"
end
end
# Escapes param
#
#@param param [String] Param
#
#@return [String]
def escape_param(param)
return param unless @sender_params_escape
'"' + param.gsub('"', "\\\"").gsub("'", "\\'").gsub("\\", "\\\\") + '"'
end
# Gets log path
#
#@return [String]
def log_path
File.join Dir.tmpdir(), "vagrant-notify-error-#{@id}.log"
end
def read_args(client)
''.tap do |args|
while tmp = client.gets and tmp !~ /^\s*$/
args << tmp
end
end
end
def http_request?(args)
args =~ /^GET/
end
def fix_icon_path!(args)
return unless args =~ /-i '([^']+)'/
icon = $1
# TODO: Handle system icons
host_file = "/tmp/vagrant-notify/#{@id}/#{icon.gsub('/', '-')}"
args.gsub!(icon, host_file)
end
end
end
end
# Ghetto
id = ARGV[0]
port = ARGV[1]
bind_ip = ARGV[2]
sender_app = ARGV[3]
sender_params_str = ARGV[4]
sender_params_escape = ARGV[5]
Vagrant::Notify::Server.run id, port, bind_ip, sender_app, sender_params_str, sender_params_escape