/*
最近在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 parmsif account is None or pwd is None:return message.create_fail_message(101,'parms error')u = user.get_user(account, pwd)# check user infoif u is None:return message.create_fail_message(102,'auth error')# pass check ,and create tokentk = md5tool.create_md5_by_time()create_success = user.create_token(u,tk)# create token successif create_success :return message.create_handle_user_message(100,tk)# create token failelse: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).rowcountif affect ==1 :db.session.commit()return user_uuidelse:return Noneelse: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拖过去设置就好了。
打包后: