【部署与升级-会议签到的web安装】
部署与升级-会议的远程安装
- 技术路线
- 界面规划
- flaskAPI以及socketio.emit 'shellout'
- 浏览器和后端交互
- 到处是偶遇
技术路线
运行的基础是Flask-Soketio,
并借鉴了后台运行系统指令的代码
和scrncpy项目,app安装的脚本
界面规划
固定标题不会滚动消失,texarea滚动回馈,断开连接,释放,以让其他管理机使用.
<head>
<style>
body {
padding-top: 100px; /* Required padding for .navbar-fixed-top */
}
</style>
<meta charset="UTF-8">
<title>部署和撤销</title>
<link href="/static/bootstrap.min1.css" rel="stylesheet" >
<script type="text/javascript" src="/js/socket.io.min.js"></script>
<script type="text/javascript" src="/js/jquery.min.js"></script>
<body>
<nav class="navbar navbar-default navbar-fixed-top" role="navigation">
<div class="container-fluid">
<div class="navbar-header">
<a class="navbar-brand" href="#">运行结果:</a>
</div>
<div>
<form class="navbar-form navbar-left" role="search" style="height: 80px;width:80%;" >
<div class="form-group" style="height: 80px;width:80%;" >
<textarea id="shstatus" style="height: 80px;width:100%;"> </textarea> </div>
<button type="button" class="btn btn-default" onclick='$.get("/api/disconnect")'>断开连接</button></li>
</button>
</form>
</div>
</nav>
<table class="table" >
<caption class="h4"> 部署和撤销</caption>
<thead>
<tr><th>点位名</th><th>状态</th><th>更新时刻</th><th>操作</th><th>IP</th>
<tbody id="mytable">
</table>
</body></html>
初始化列表
$.get("/list" function (stas)
{
Object.keys( stas).forEach(function(key) {
$('#mytable').append(`<tr><td>${stas[key].sta}</td>.........<td><button onclick="$.get('/api/myconnect/${stas[key].sta}')">连接</button></td>
...
}
})
flaskAPI以及socketio.emit ‘shellout’
分二部分.执行和回馈 参考关于socketio的配置
from checkout.she import sh
.......
@app.route('/api/myinstall/<sta>')
def install(sta):
if ip4sta(sta):
target=ip4sta(sta)+":Port"
sh.install(target)
return json.dumps("install"+ip4sta(sta))
@app.route('/api/myconnect/<sta>')
def connect(sta):
if ip4sta(sta):
target=ip4sta(sta)+":Port"
sh.connect(target)
return json.dumps("install"+ip4sta(sta))
@app.route('/api/myuninstall/<sta>')
def uninstall(sta):
if ip4sta(sta):
target=ip4sta(sta)+":Port"
sh.uninstall(target)
return json.dumps("uninstall"+ip4sta(sta))
@app.route('/api/mydisconnect')
def disconnect():
sh.disconnect()
return "OK"
def shellout(msg):
socketio.emit('shellout',msg,namespace='/chat')
sh.callback=shellout
#运行本地shell的py
上代码
# 存储ping数据的redis 1号库
#from redis import StrictRedis
import subprocess
import os
import threading
#redis_sh = StrictRedis(host='192.168.1.231', port=6379, decode_responses=True, db=2)
callback=print
def sh(command, callback):
cwd=os.getcwd()
if (not cwd.endswith('she')):
cwd=os.getcwd()+"/she"
p = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,cwd=cwd)
callback(command)
for line in iter(p.stdout.readline, b''):
callback(line.decode())
def run(command):
global callback
try:
# 起线程执行命令
task = threading.Thread(target=sh, args=(command, callback))
task.start()
except Exception as e:
print(e)
def install(target):
command = "./sndcpy.sh %s i" % target
run(command)
def uninstall(target):
command = ["./adb -s %s remount" % target,"./adb -s %s uninstall com.tumuyan.fixedplay" % target
,
"./adb -s %s shell mv /tmp/Launcher_1.apk /system/app/" % target
]
for com in command:
run(com )
def connect(target):
command = "./adb connect %s" % target
run(command)
def disconnect():
run("./adb disconnect")
if __name__=="__main__":
ip="ip:Port"
uninstall(ip)
根据网友关于redis,flask ip的代码做出的调节,
- redis换成socketio,简化前端的逻辑,和信息的处理.callback了所有.
- flask的threading,转移到了sh.py其中一个函数,让所有command共用.
- 对目录进行了分级,subprocess.Popen使用了cwd参数.一般来说,flask的当前路径在上一级.
附加:
针对adb connect等待时间过长,使用ping3判断在线
pip install ping3
@app.route('/api/connect/<sta>')
def connect(sta):
if ip4sta(sta):
target=ip4sta(sta)
tgp=ping3.ping( target,timeout=1)
if tgp is not False and tgp is not None:
shellout("ping SUUCESS, 连接中<-->%s\n" %target)
sh.connect(target+":5555")
else:
shellout("ping FAIL,设备离线 ><%s\n" %target)
shellout("请联系[%s],开机后再测试!\n"%sta)
return json.dumps("connect"+target)
浏览器和后端交互
以前文章的内容
-
取得所有当前信息表格,布局页面.
-
取得当前已经安装app的客户端信息,方便查看安装结果
-
定制功能按钮,获取回馈消息通知
onclick='$.get("/api/mydisconnect")'---断开连接
...<button onclick="$.get('/api/myconnect/${stas[key].sta}')">连接</button>
取得io的消息shellout
var socket = io.connect('http://ip:port/chat' );
socket.on('shellout',handleshell);
function handleshell(msg){
var text = document.getElementById('shstatus');
text.scrollTop = text.scrollHeight; //滚动到最后
$("#shstatus").text($("#shstatus").text()+msg)
}
到处是偶遇
那天在逛微信,推送了一个开源手机同屏控制的项目QTscncpy.结果会议机版本低4个数字,无法安装.在ubuntu下,才25M.一个前端,窗口程序,一个adb.一个apk,一段安装脚本.前端在调试时的输出代码,有不错的监测,一直的等待安装后的启动,可惜我这里都是错误.
在很多天无聊之后,浏览了一下它的内容.
如下
#!/bin/bash
echo Begin Runing...
SNDCPY_PORT=28200
SNDCPY_APK=sndcpy.apk
ADB=./adb
serial=
if [[ $# -ge 2 ]]
then
serial="-s $1"
SNDCPY_PORT=$2
fi
echo "Waiting for device $1..."
$ADB $serial wait-for-device
echo "Find device $1"
sndcpy_installed=$($ADB $serial shell pm path com.rom1v.sndcpy)
if [[ $sndcpy_installed == "" ]]; then
echo Install $SNDCPY_APK...
$ADB $serial uninstall com.rom1v.sndcpy || echo uninstall failed
$ADB $serial install -t -r -g $SNDCPY_APK
echo Install $SNDCPY_APK success
fi
echo Request PROJECT_MEDIA permission...
$ADB $serial shell appops set com.rom1v.sndcpy PROJECT_MEDIA allow
echo Forward port $SNDCPY_PORT...
$ADB $serial forward tcp:$SNDCPY_PORT localabstract:sndcpy
echo Start $SNDCPY_APK...
$ADB $serial shell am start com.rom1v.sndcpy/.MainActivity
while ((1))
do
echo Waiting $SNDCPY_APK start...
sleep 0.1
sndcpy_started=$($ADB shell 'ps | grep com.rom1v.sndcpy')
if [[ $sndcpy_started != "" ]]; then
break
fi
done
echo Ready playing...
短短一段代码,
提供了,一客户监测等待, 安装后的赋权,启动后的观测.几乎涵盖了我需要的所有,所有唯一目前我没有的就是web端的便捷.于是把以前搁置的功能补齐了.