Created
September 15, 2011 15:53
-
-
Save jiangmiao/1219633 to your computer and use it in GitHub Desktop.
File Monitor and auto F5
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env ruby | |
require 'rubygems' | |
require 'rb-inotify' | |
require 'getoptlong' | |
class Monitor | |
def initialize(project_dir) | |
@notifier = INotify::Notifier.new | |
@project_dir = project_dir | |
@events = [] | |
end | |
def ignore?(path) | |
file = File.basename path | |
if ['.git', '.svn'].include? file | |
return true | |
end | |
return false | |
end | |
def watch(dir) | |
if ignore?(dir) | |
puts "ignore #{dir}" | |
return false | |
else | |
puts "watching #{dir}" | |
end | |
@notifier.watch dir, :modify, :create, :move, :delete, :onlydir do|event| | |
flags = event.flags | |
if flags.include? :isdir | |
if flags.include? :ignore? | |
@notifier.watchers.delete watcher.id | |
elsif not flags.include? :delete | |
watch path | |
else | |
@events << event | |
end | |
else | |
@events << event | |
end | |
end | |
return true | |
end | |
# use our recursive instead :recursive to filt | |
def watch_recursive(dir) | |
Dir.glob(File.join(dir, "*/"), File::FNM_DOTMATCH).each do|dir| | |
name = File.basename(dir) | |
next if name == ".." or name == "." | |
if watch dir | |
watch_recursive dir | |
end | |
end | |
end | |
def run | |
# watch all sub-directories | |
watch @project_dir | |
watch_recursive @project_dir | |
while true | |
if IO.select([@notifier.to_io], [], [], 0.2) | |
@notifier.process | |
elsif @events.size > 0 | |
check @events | |
@events = [] | |
end | |
end | |
end | |
end | |
class KeyF5 < Monitor | |
def initialize(dir) | |
super(dir) | |
end | |
def get_browser_id | |
puts "Select browser" | |
if `xwininfo -wm`.match /Window id: (\w*)/ | |
@browser_id = $1 | |
puts "browser id #{@browser_id}" | |
else | |
raise 'get browser id failed' | |
end | |
end | |
def refresh_browser | |
info = `xwininfo -id #{@browser_id} -wm` | |
if info.include? 'Firefox' | |
# firefox不聚焦时发送F5不工作 | |
puts "refresh Firefox #{@browser_id}" | |
system "xdotool windowactivate --sync #{@browser_id} key F5 windowactivate --sync `xdotool getactivewindow`" | |
elsif info.include? 'Chromium' | |
puts "refresh Chromium #{@browser_id}" | |
system "xdotool key --window #{@browser_id} F5" | |
else | |
puts "only support firefox and chromium, please repick the window" | |
get_browser_id | |
end | |
end | |
def check(events) | |
for event in events | |
path = File.expand_path(event.absolute_name) | |
puts "#{path} [ #{event.flags.join(", ")} ]" | |
end | |
refresh_browser | |
end | |
def run | |
get_browser_id | |
super | |
end | |
end | |
class AjaxF5 < Monitor | |
attr_reader :updated_at, :js | |
def initialize(dir) | |
super dir | |
@updated_at = Time.now.to_f | |
@js = <<EOT | |
(function() { | |
var ajax; | |
function $(e){if(typeof e=='string')e=document.getElementById(e);return e}; | |
function collect(a,f){var n=[];for(var i=0;i<a.length;i++){var v=f(a[i]);if(v!=null)n.push(v)}return n}; | |
ajax={}; | |
ajax.x=function(){try{return new ActiveXObject('Msxml2.XMLHTTP')}catch(e){try{return new ActiveXObject('Microsoft.XMLHTTP')}catch(e){return new XMLHttpRequest()}}}; | |
ajax.serialize=function(f){var g=function(n){return f.getElementsByTagName(n)};var nv=function(e){if(e.name)return encodeURIComponent(e.name)+'='+encodeURIComponent(e.value);else return ''};var i=collect(g('input'),function(i){if((i.type!='radio'&&i.type!='checkbox')||i.checked)return nv(i)});var s=collect(g('select'),nv);var t=collect(g('textarea'),nv);return i.concat(s).concat(t).join('&');}; | |
ajax.send=function(u,f,m,a){var x=ajax.x();x.open(m,u,true);x.onreadystatechange=function(){if(x.readyState==4)f(x.responseText)};if(m=='POST')x.setRequestHeader('Content-type','application/x-www-form-urlencoded');x.send(a)}; | |
ajax.get=function(url,func){ajax.send(url,func,'GET')}; | |
var now = Date.now(); | |
function check() { | |
ajax.get("/f5_status", function(rt) { | |
if (now < parseFloat(rt)) { | |
location.reload(true); | |
} | |
}); | |
setTimeout(check, 500); | |
} | |
check(); | |
})(); | |
EOT | |
end | |
def check(events) | |
@updated_at = Time.now.to_f | |
puts "updated_at #{@updated_at}" | |
end | |
def run | |
Thread.new do | |
super | |
end | |
f5 = self | |
set :logging, false | |
get '/f5_status' do | |
(f5.updated_at*1000).to_s | |
end | |
get '/f5.js' do | |
f5.js | |
end | |
get '*' do | |
host = env['SERVER_NAME'] | |
path = env['REQUEST_PATH'] | |
begin | |
data = open('http://' + host + path) {|f| | |
content_type f.meta['content-type'] | |
f.read | |
} | |
data.gsub Regexp.new('</body>', Regexp::IGNORECASE), '<script type="text/javascript" src="/f5.js"></script></body>' | |
rescue | |
$!.message.match /\d+/ | |
[$&.to_i, {}, ''] | |
end | |
end | |
end | |
end | |
if __FILE__ == $0 | |
dir = ARGV[0] || '.' | |
mode = nil | |
opts = GetoptLong.new( | |
[ '--mode', '-m', GetoptLong::OPTIONAL_ARGUMENT], | |
[ '--help', '-h', GetoptLong::NO_ARGUMENT] | |
) | |
opts.each do|opt, arg| | |
case opt | |
when '--help' | |
puts <<EOT | |
ruby f5.rb [选项] [项目路径] | |
--help, -h | |
帮助 | |
--mode, -m | |
ajax 嵌入ajax模式, 默认 | |
key 发送F5键模式 | |
关于ajax模式: 访问 原域名:4567 | |
比如 127.0.0.1,则通过 127.0.0.1:4567 访问 | |
example.com 则通过 example.com:4567 访问 | |
仅支持 GET | |
EOT | |
exit | |
when '--mode' | |
mode = arg | |
end | |
end | |
if mode == 'key' | |
f5 = KeyF5.new dir | |
else | |
require 'sinatra' | |
require 'open-uri' | |
f5 = AjaxF5.new dir | |
end | |
f5.run | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment