筆者所知有兩條途徑
libubox 是 OpenWrt 12.9 之後加入的基本程式庫,前面提到的 uHTTPd、netifd 就是奠基在此之上,如果你想用 C/C++ 開發(也有 Lua binding),想要有自己的事件迴圈,追求效能極大化,那你就要了解他。
rpcd 也是建立在 libubox 上,rpcd 之於 ubus 就好比 xinetd 之於 internet,在筆者另一篇文章「Raspberry Pi 筆記: 解決嵌入式系統列印困境」也有提及 xinetd。簡單來說您可以把你的程式掛在 rpcd 之下(稱為 plugin),當 rpcd 收到遠端呼叫(Remote Procedure Call)時(例如前文提到的 jsonrpc),就可以喚起你的 plugin:
接下來看如何開發 plugin。
1. 編寫 plugin script
基本上只要 7688 內能讀寫 stdin/stdout 的程式語言都行,無論是 shell script, Python, Lua, Node...
以 Lua 為例(myrpc):
以 Lua 為例(myrpc):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | #!/usr/bin/lua -- /usr/libexec/rpcd/myprc require "luci.json" local json = luci.json if arg [1] == "list" then io.write (json.encode({echo = {arg1 = "str" }})) elseif arg [1] == "call" and arg [2] == "echo" then local echo_arg = io.read ( "*all" ) local echo_decoded_arg = json.decode(echo_arg) if echo_decoded_arg.arg1 == nil or type(echo_decoded_arg.arg1) ~= "string" then io.write (json.encode({ret1 = "" , ret2 = "invalid argument" })) else io.write (json.encode({ret1 = echo_decoded_arg.arg1})) end end |
Line 6-7 列出此 plugin 支援哪些 function 與參數型態。
如果到這裡還是看不懂沒關係,等等實際執行就一目了然了。
2. 測試 plugin
將 myrpc 拷貝到 /usr/libexec/rpcd,然後輸入以下指令:
檢查是否有成功載入:
從這裡可以看到 arg1 參數型態為 String
呼叫測試:
這裡附上 Python 版,因本人非 Python 專家,難免貽笑大方,還請各位見諒 m(_ _)m
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | #!/usr/bin/python #/usr/libexec/rpcd/myprc2 import sys import json arg = sys.argv if len (arg) = = 2 and arg[ 1 ] = = "list" : sys.stdout.write(json.dumps({ 'echo' : { 'arg1' : 'str' }})) elif len (arg) = = 3 and arg[ 1 ] = = "call" and arg[ 2 ] = = "echo" : echo_arg = json.loads(sys.stdin.read()) if 'arg1' not in echo_arg or echo_arg[ 'arg1' ] = = None : sys.stdout.write(json.dumps({ "ret1" : " ", " ret2 " : " invalid argument"})) else : sys.stdout.write(json.dumps({ "ret1" : echo_arg[ 'arg1' ]})) |
3. jsonrpc 測試
同樣拿 rpc_demo.html 進行修改,首先增加一些標籤:1 2 3 4 5 6 7 | < h3 > Echo test <⁄h3> Send < input type = "input" id = "EchoSend" > Receive < input type = "input" id = "EchoRecv" > < input type = "button" value = "Echo" id = "BtnEcho" > |
1 2 3 4 5 6 7 8 9 10 11 12 | function rpc_echo(){ config = { "jsonrpc" : "2.0" , "id" : id++, "method" : "call" , "params" : [ session, "myrpc" , "echo" , { "arg1" : $( "#EchoSend" ).val() } ] }; do_ajax(config, function (reply) { if (!reply.result || reply.result[0] != 0){ alert( "failed to echo" ); } else { $( '#EchoRecv' ).val(reply.result[1].ret1); } }); } |
1 2 3 4 5 6 7 | $( document ).ready( function () { $( "#BtnLogin" ).click( function () { rpc_login( "root" , $( "#Password" ).val()); }); $( "#BtnLogout" ).click( function () { rpc_logout(); }); $( "#BtnMode" ).click( function () { rpc_wifi_mode($( "#Mode" ).val()); }); //...... $( "#BtnEcho" ).click( function () { rpc_echo(); }); }); |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | function rpc_login(user, pass) { //...... do_ajax(login, function (reply) { //...... session = reply.result[1].ubus_rpc_session; var grant = { "jsonrpc" : "2.0" , "id" : id++, "method" : "call" , "params" : [ session, "session" , "grant" , { "scope" : "uci" , "objects" : [ [ "*" , "read" ], [ "*" , "write" ] ] } ]}; do_ajax(grant, function (reply) { if (!reply.result || reply.result[0] != 0) { alert( "failed to grant object permissions" ); return ; } }); var grant2 = { "jsonrpc" : "2.0" , "id" : id++, "method" : "call" , "params" : [ session, "session" , "grant" , { "scope" : "ubus" , "objects" : [ [ "myrpc" , "echo" ] ] } ]}; do_ajax(grant2, function (reply) { if (!reply.result || reply.result[0] != 0) { alert( "failed to grant2 object permissions" ); return ; } $( "#Session" ).val(session); $( "#fwSession" ).val(session); rpc_board_load(); rpc_system_load(); rpc_wifi_load(); //... }); }); } |
範例下載
- myrpc(Lua)
- myrpc(Python)
- rpc_demo3.html
沒有留言:
張貼留言