-
Notifications
You must be signed in to change notification settings - Fork 79
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'master' of https://github.com/handlino/FireApp
Conflicts: src/compile_version.rb
- Loading branch information
Showing
10 changed files
with
275 additions
and
11 deletions.
There are no files selected for viewing
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
|
||
# Fire.app Remote Control (Beta) | ||
|
||
Fire.app 在啟動後,會自動 listen 13425 port。 | ||
|
||
我們可以用 `nc localhost 13425` 來連上控制界面。並且鍵入 help 來查看支援的指令。 | ||
|
||
![starting-client](RemoteControl-Readme/starting-client.png) | ||
|
||
而在 Fire.app 那邊則可以看到: | ||
|
||
![starting-fireapp](RemoteControl-Readme/starting-fireapp.png) | ||
|
||
以下簡單說明目前有支援的指令 | ||
|
||
|
||
## Watch Project | ||
|
||
- 使用 `watch path [project_path]` 控制 Fire.app watch 此 project。 | ||
|
||
*注意: project_path 指的是與 Fire.app 同一臺電腦下的 path,而目前尚無法讓 Fire.app watch 其他電腦上的 project。 若是 client 與 Fire.app 不使用同一個 host 時請小心。* | ||
|
||
- 使用 `watch lastest` 直接 watch 最近一個使用過的 project 。 | ||
- 使用 `watch status` 可確認目前是否有 watch project 。若是有的話,一併回傳目前的 project path。 | ||
|
||
## Stop Watching | ||
|
||
- 使用 `watch stop` 終止目前的工作 | ||
|
||
|
||
## Others | ||
|
||
- 使用 `extension list` 列出 Fire.app 有支援的 extension 清單 | ||
- 使用 `quit` 關閉 Fire.app | ||
- 使用 `echo [msg]` 讓 Fire.app 回傳 msg (測試功能) 。 | ||
|
||
--- | ||
|
||
## Motivation | ||
|
||
需要有 remote interface 的原因有幾個,其中最主要的想法是希望可以結合 rspec ,方便做 unit test 。另外一點是, Fire.app 也算是一個吃記憶體的 app ,如果許多電腦可以共用某一檯電腦內的 Fire.app 來 compiler 自己的檔案,感覺也不錯。 | ||
*註:要達成 unit test 我目前還有另一個想法是使用 applescript 來控制 interface ,有機會可以研究。* | ||
|
||
|
||
## TODO | ||
|
||
1. 讓 remote interface 能回傳一致的資料格式 | ||
2. Fire.app 有很多動作必須選擇資料夾/檔案,如 create project / watch project 。之前寫 rspec 有解決這個問題,需要把它整合進來 | ||
3. 需要有 nc 的 ruby implement version ,除了不是所有作業系統都有 nc 指令這個原因之外,我們也需要讓 rspec 可以控制 nc | ||
4. 像是 Preference / Change Option 等功能,會開啟一個新視窗。新開的那個視窗的控制方法必須要研究一下。 | ||
|
||
*本功能的主要模組在 src/remote_control_server.rb* | ||
|
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains 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
This file contains 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
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,174 @@ | ||
|
||
require 'socket' | ||
require "singleton" | ||
|
||
|
||
|
||
Thread.abort_on_exception = true | ||
|
||
class RemoteControlServer | ||
include Singleton | ||
|
||
def initialize | ||
@server = nil | ||
@connected_pool = [] | ||
end | ||
|
||
def open(port = 13425) | ||
close | ||
@server = Thread.new do | ||
TCPServer.open(13425) do |sock_server| | ||
|
||
loop { | ||
begin | ||
@connected_pool << Thread.new(sock_server.accept) do |sock| | ||
client_port, client_ip = Socket.unpack_sockaddr_in(sock.getpeername) | ||
sock.puts "# Fireapp Remote Interface #" | ||
|
||
puts "Client Connected from #{client_ip}:#{client_port}" | ||
|
||
loop do | ||
input = sock.gets | ||
break if input.nil? | ||
|
||
input = input.strip | ||
puts "#{client_ip}:#{client_port} => #{input}" | ||
|
||
output = case input | ||
when /^watch path \s*(.*)\s*/i | ||
App.get_stdout { | ||
App.display.syncExec { | ||
Tray.instance.watch $1 # if exception occurred, it'll stop at here | ||
puts "Watching Success: #{$1}" | ||
} | ||
} | ||
|
||
|
||
when /^watch lastest$/i | ||
App.get_stdout { | ||
App.display.syncExec { | ||
if App.get_history[0] | ||
Tray.instance.watch App.get_history[0] | ||
puts "Watching Success: #{App.get_history[0]}" | ||
end | ||
} | ||
} | ||
|
||
when /^extension list$/i | ||
App.display.syncExec { | ||
output = JSON.pretty_generate fetch_menu_tree(Tray.instance.create_item) | ||
} | ||
output | ||
|
||
when /^create project$/i | ||
App.display.syncExec { | ||
click(["compass", "project"], Tray.instance.create_item) | ||
} | ||
|
||
when /^watch stop$/i | ||
App.display.syncExec { | ||
Tray.instance.stop_watch | ||
} | ||
|
||
when /^watch status$/i | ||
"Watching: #{Tray.instance.watching_dir || "Nothing"}" | ||
|
||
|
||
|
||
|
||
when /^echo (.*)/i | ||
$1 | ||
|
||
when /^quit$/i | ||
App.display.syncExec { | ||
Tray.instance.exit_handler.trigger | ||
} | ||
|
||
when /^help$/i | ||
help() | ||
else | ||
"Command '#{input.strip}' is not found.\n#{help()}" | ||
end | ||
|
||
sock.puts output | ||
puts "#{client_ip}:#{client_port} <= #{output}" | ||
|
||
end | ||
end | ||
|
||
rescue Exception => e | ||
puts "#{e.message}" | ||
end | ||
} | ||
end | ||
end | ||
|
||
end | ||
|
||
def close(disconnect_all = true) | ||
@server.kill if open? | ||
@server = nil | ||
if disconnect_all | ||
@connected_pool.each do |x| | ||
x.kill if x and x.alive? | ||
end | ||
@connected_pool = [] | ||
end | ||
end | ||
|
||
def open? | ||
return true if @server and @server.alive? | ||
return false | ||
end | ||
|
||
def help | ||
[ | ||
"** We support following commands:", | ||
"- watch path [path]", | ||
"- watch stop", | ||
"- watch status", | ||
"- watch lastest", | ||
"- extension list", | ||
"- quit", | ||
"- echo [msg]", | ||
"- help", | ||
"" | ||
].join("\n") | ||
end | ||
|
||
|
||
def fetch_menu_tree (menuitem) | ||
|
||
if menuitem.menu | ||
tree = Hash.new | ||
menuitem.menu.getItems.each do |item| | ||
tree[item.text] = fetch_menu_tree(item) | ||
end | ||
tree | ||
else | ||
"" | ||
end | ||
|
||
end | ||
|
||
def click (steps = [], menuitem = nil) | ||
menuitem = menuitem || Tray.instance.tray_item | ||
step = steps[0] | ||
if step and menuitem.menu | ||
next_menuitem = menuitem.menu.getItems.find {|f| f.text.strip =~ Regexp.new(step) } | ||
if next_menuitem and steps.size == 1 | ||
menuitem.getListeners(Swt::SWT::Selection).each { |l| l.trigger } | ||
elsif next_menuitem | ||
return click(steps[1..-1], next_menuitem) | ||
end | ||
else | ||
return false | ||
end | ||
|
||
end | ||
|
||
end | ||
|
||
|
||
|
||
#server_thread.join |
This file contains 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
This file contains 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
Oops, something went wrong.