/*
最近在B站上刷到一个视频,讲的是up主自己在上网课时和父母老师斗智斗勇,一边上课,一遍玩电脑游戏。我突然就感觉对于某些家长来说,监控电脑也许是个硬需求。市面上已经有诸如向日葵等远程监控,可以实现手机查看电脑,但有些弊端,就是操作过于复杂,我认为,对于一些人来说,功能足够简单甚至简陋都不是问题,动脑子学习才是问题,所以准备做出这个非常简陋的东西,玩一玩。
*/
系统结构:
一、桌面端
1、登记账号信息
2、上报
二、Web端
1、用户管理接口
2、桌面上报接口
3、查看桌面的web页
Web实现
一、目录结构
学习了flask,第一次写web项目,从实用的角度来对整个代码做如下的规划
--config
└─route_config.py
└─web_config.py
--controller
└─增删改拆.py
--handler
└─解析参数、调用controller、组装message,然后response
--main
└─webapp.py #解析配置,启动web
--model
└─消息model
└─sql model
--static
└─页面静态资源
--templates
└─模板.html
--tools
└─常用的方法集合
二、route config
按以往传统,route倾向于用配置文件记录,现在流行装饰模式替代route配置,但是我又希望能够一目了然的查看route,所以把所有的route单拉出来,集中放在route_config.py中。在这个文件中只写明route和处理函数,其他统统不管。
类似这样:
from main.webapp import app
from handler import watcherhandler
# ******************** 监控系统部分 ***********************
# 客服二维码图片
@app.route('/watcher/custom')
def watcher_custom_qrcode():
return watcherhandler.get_custom_qrcode()
# 查看地址
@app.route('/watcher/q/<uuid>')
def watcher_query(uuid):
return watcherhandler.get_user_watch_page(uuid)
# 验证admin
@app.route('/watcher/adm/check')
def watcher_admin_check():
return watcherhandler.handle_check_admin()
# 创建用户
@app.route('/watcher/adm/create')
def watcher_create_user():
return watcherhandler.handle_create_user()
# 用户接口
@app.route('/watcher/user', methods=['POST'])
def watcher_api_user():
return watcherhandler.handle_user_api()
# 用户上传截图
@app.route('/watcher/upload',methods=['POST'])
def watcher_api_upload():
return watcherhandler.handle_user_upload()
三、handler
handler层不必关心数据读写细节,只管调用controller来实现数据读写。更多的关心参数处理、状态判断等。
例如:
from flask import request
from controller import user
import json
from sql_model import message
from tools import md5tool
# checking user auth and return token
# ?account=***&pwd=***
def handle_request_user():
request_result = ''
account = request.args.get('account')
pwd = request.args.get('pwd')
# check parms
if account is None or pwd is None:
return message.create_fail_message(101,'parms error')
u = user.get_user(account, pwd)
# check user info
if u is None:
return message.create_fail_message(102,'auth error')
# pass check ,and create token
tk = md5tool.create_md5_by_time()
create_success = user.create_token(u,tk)
# create token success
if create_success :
return message.create_handle_user_message(100,tk)
# create token fail
else:
return message.create_fail_message(103,'token fail')
return request_result
四、controller
controller用来写与数据库打交道的逻辑。这种项目感觉用了orm会更繁琐,直接手写sql。
例如:
from sql import db
from tools import md5tool
# 创建一个新的用户
def create_new_user(account,pwd):
admin = get_admin(account,pwd)
if admin != None:
admin_id = admin['id']
user_uuid = md5tool.create_md5_by_time()
user_try_time = 1 # 试用天数
sql = \
('''
insert into watcher_user
(uuid,state,outdate,creator)
values ('{0}',1,adddate(now(),interval {1} day),{2});
''').format(user_uuid,user_try_time,admin_id)
affect = db.session.execute(sql).rowcount
if affect ==1 :
db.session.commit()
return user_uuid
else:
return None
else:
return None
五、template注意事项
资源放在static中时,资源的路径是 [域名/static/资源位置],template中使用的资源如果放在static中,那就要注意对应的route有多深,比如route配置的是[域名/a/b/c],那么在template中的资源应该地址配成[../../../static/资源位置]。
例如:
某个route配置是:
# 查看地址
@app.route('/watcher/q/<uuid>')
def watcher_query(uuid):
return watcherhandler.get_user_watch_page(uuid)
这个页面使用的template是:
该模板具体内容为:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta http-equiv="x-ua-compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>查 看</title>
</head>
<body style="background-image: url(../../static/watcher/bg.png);background-repeat: no-repeat;background-size: 100% 100%;">
<h4>上传时间:{{ uploadtime }}</h4>
<img src="../../static/watcher/mo/{{ imgurl }}.png" width="100%">
<div style="width: 100%;">
软件到期时间:{{ outdate }}
<br>
<br>
注:<br>
1、当PC端运行时,每隔5分钟上报一次 <br>
2、可能因为网络、安全软件、程序没运行等原因导致截屏没有上报<br>
3、如有疑问请联系客服微信
<br>
<br>
</div>
<div style="width: 100%;text-align: center;">
<img src="../../static/watcher/custom.png" width="60%">
</div>
</body>
</html>
PC端:
核心就是记录账号和上传截图的功能。没啥好说的,唯一需要注意的就是添加开机启动项,如果为所有用户添加,则需要管理员功能,在设置的时候弹出ua,于是单独写了一个exe,然后通过Process.Start去执行。
public static void SetStartWhenBoot()
{
//创建启动对象
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.UseShellExecute = true;
startInfo.WorkingDirectory = Environment.CurrentDirectory;
startInfo.FileName = "set-auto-start.exe";
startInfo.CreateNoWindow = false;
//设置启动动作,确保以管理员身份运行
startInfo.Verb = "runas";
try
{
Process.Start(startInfo);
}
catch
{
return;
}
}
vs安装的时候没装全,好像没带打包的功能。网上找了一个工具叫<AdvancedInstallerPortable>,感觉挺好用的,直接把debug文件夹下的exe拖过去设置就好了。
打包后: