From 8a7c325f7f1612a9c4fa8e42e1a53c9f56a4f75c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B1=AA=E4=BA=91=E8=BE=89?= <15655267350@163.com> Date: Sun, 15 Aug 2021 19:20:16 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E6=B7=BBim?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- im/__init__.py | 0 im/chat.py | 14 +++++++ im/main.py | 36 +++++++++++++++++ im/notify.py | 29 ++++++++++++++ im/server.py | 14 +++++++ mis/__init__.py | 0 mp/__init__.py | 0 requirements.txt | 2 + scripts/__init__.py | 0 scripts/im.sh | 5 +++ scripts/toutiao_app.sh | 6 +++ wyh_web_tools/resources/user/__init__.py | 20 +++++++++- wyh_web_tools/resources/user/views.py | 51 ++++++++++++------------ 13 files changed, 149 insertions(+), 28 deletions(-) create mode 100644 im/__init__.py create mode 100644 im/chat.py create mode 100644 im/main.py create mode 100644 im/notify.py create mode 100644 im/server.py create mode 100644 mis/__init__.py create mode 100644 mp/__init__.py create mode 100644 scripts/__init__.py create mode 100644 scripts/im.sh create mode 100644 scripts/toutiao_app.sh diff --git a/im/__init__.py b/im/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/im/chat.py b/im/chat.py new file mode 100644 index 0000000..70c2480 --- /dev/null +++ b/im/chat.py @@ -0,0 +1,14 @@ +from server import sio + + +# 监听聊天事件 +@sio.on("chat") +def message(sid, data): + + # TODO 将客户端的消息发送给AI聊天机器人, 并将响应数据返回给IM客户端 RPC + response = '机器人的回复: xxxx' + + # 给指定的客户端发送消息 + sio.emit('chat', response, room=sid) + + diff --git a/im/main.py b/im/main.py new file mode 100644 index 0000000..e9def4b --- /dev/null +++ b/im/main.py @@ -0,0 +1,36 @@ +import os + +from eventlet import monkey_patch + +from server import app + +monkey_patch() + +import eventlet.wsgi +import sys + +# 获取到项目的绝对路径 +BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +# 将项目中的common目录加入查询路径中 (方便导入common中的模块) +sys.path.insert(0, os.path.join(BASE_DIR, 'common')) + +from chat import * +from notify import * + +if len(sys.argv) < 2: + print('Usage: python main.py [port]') + exit(1) + +port = int(sys.argv[1]) + + +# 4.监听端口 +socket = eventlet.listen(('', port)) + +# 5.启动服务器 +eventlet.wsgi.server(socket, app) + + + + + diff --git a/im/notify.py b/im/notify.py new file mode 100644 index 0000000..90754ec --- /dev/null +++ b/im/notify.py @@ -0,0 +1,29 @@ +from flask import Request +from server import sio, JWT_SECRET +from utils.jwt_util import verify_jwt + +def check_token(token): + payload = verify_jwt(token, secret=JWT_SECRET) + if payload: + return payload.get('payload') + else: + return None + + +@sio.on('connect') +def connect(sid, envron): + request = Request(envron) + token = request.args.get('token') + # 解析token + user_id = check_token(token) + # 一旦用户连接到IM服务器, 就让他进入其user_id对应的房间 (一个人对应一个房间) + sio.enter_room(sid, room=user_id) + print("进入了房间:%s" % user_id) + + +@sio.on('disconnect') +def disconnect(sid): + # 断开连接后退出房间 + rooms = sio.rooms(sid) + for room in rooms: + sio.leave_room(sid, room=room) diff --git a/im/server.py b/im/server.py new file mode 100644 index 0000000..6ca08d1 --- /dev/null +++ b/im/server.py @@ -0,0 +1,14 @@ +import socketio + +# JWT +JWT_SECRET = 'TPmi4aLWRbyVq8zu9v82dWYW17/z+UvRnYTt4P6fAXA' # 默认消息认证的秘钥 +# 消息队列的连接地址 +RABBITMQ = 'amqp://guest:guest@192.168.105.128:5672' + +# 创建消息队列管理器 +mgr = socketio.KombuManager(RABBITMQ) + +# 2.创建服务器对象 设置client_manager参数后, im服务器就会从消息队列中取出消息发给指定的房间 +sio = socketio.Server(async_mode='eventlet', client_manager=mgr) +# 3.创建应用 +app = socketio.Middleware(sio) \ No newline at end of file diff --git a/mis/__init__.py b/mis/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/mp/__init__.py b/mp/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/requirements.txt b/requirements.txt index 5b36e52..94d0b3c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -32,3 +32,5 @@ flask_sqlalchemy jwt celery aliyunsdkcore +eventlet +socketio diff --git a/scripts/__init__.py b/scripts/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/scripts/im.sh b/scripts/im.sh new file mode 100644 index 0000000..c03b140 --- /dev/null +++ b/scripts/im.sh @@ -0,0 +1,5 @@ +#! /bin/bash +source ~/.bash_profile +cd /home/python/toutiao-backend/im/ +workon toutiao +exec python main.py 8001 \ No newline at end of file diff --git a/scripts/toutiao_app.sh b/scripts/toutiao_app.sh new file mode 100644 index 0000000..5101b7b --- /dev/null +++ b/scripts/toutiao_app.sh @@ -0,0 +1,6 @@ +#! /bin/bash +source ~/.bash_profile +export FLASK_ENV=production +cd /home/python/toutiao-backend/ +workon toutiao +exec gunicorn -b 0.0.0.0:8000 --access-logfile /home/python/logs/access_app.log --error-logfile /home/python/logs/error_app.log toutiao.main:app \ No newline at end of file diff --git a/wyh_web_tools/resources/user/__init__.py b/wyh_web_tools/resources/user/__init__.py index 60cc9d8..946c1e5 100644 --- a/wyh_web_tools/resources/user/__init__.py +++ b/wyh_web_tools/resources/user/__init__.py @@ -2,10 +2,26 @@ from flask import Blueprint from flask_restful import Api from utils.output import output_json + # from . import passport, profile, following -# 创建蓝图对象 -user_bp = Blueprint('user', __name__) + +# 1.创建蓝图对象 +# 细节1: 可以使用url_prefix对蓝图注册的所有路由添加统一的资源段前缀 +user_bp = Blueprint('user_b', __name__, static_folder='static', url_prefix='/user') + + +# 细节3: 蓝图设置请求钩子 只会监听该蓝图注册的路由 +@user_bp.before_request +def news_prepare(): + print("news_prepare") + + +# 只要出现ImportError: cannot import name xx, 一定是导入的内容没有被定义 +# 解决办法: 查看并修改代码的执行顺序 + +# 4.让程序关联视图文件 +from . import views # 从当前包中导入views文件 # 4.让程序关联视图文件 from . import views # 从当前包中导入views文件 diff --git a/wyh_web_tools/resources/user/views.py b/wyh_web_tools/resources/user/views.py index ed655ff..5b838fb 100644 --- a/wyh_web_tools/resources/user/views.py +++ b/wyh_web_tools/resources/user/views.py @@ -1,12 +1,11 @@ -from flask import url_for, render_template, make_response, redirect, jsonify, session, abort, g +from flask import url_for, render_template, make_response, redirect, jsonify, session, abort, g, current_app from flask import request -from main import app -from user import user_blu +from user import user_bp # 2.使用蓝图对象来注册路由 -@user_blu.route('/') +@user_bp.route('/') def index(): # 细节2: 蓝图注册的路由, 其视图函数的标记为: 蓝图名.函数名 url1 = url_for('user_b.index') @@ -14,18 +13,18 @@ def index(): return "个人中心-首页" -@user_blu.route('/basic_info') +@user_bp.route('/basic_info') def basic_info(): return "个人中心-基本信息" -@user_blu.route('/articles') +@user_bp.route('/articles') def get_articles(): channel_id = request.args.get('channel_id') return 'you wanna get articles of channel {}'.format(channel_id) -@user_blu.route('/upload', methods=['GET', 'POST']) +@user_bp.route('/upload', methods=['GET', 'POST']) def upload_file(): f = request.files['pic'] # with open('./demo.png', 'wb') as new_file: @@ -37,7 +36,7 @@ def upload_file(): #####################################如何在不同的场景里返回不同的响应信息########################################## # 1)自定义响应对象 -@user_blu.route('/demo0002') +@user_bp.route('/demo0002') def demo0002(): # 视图函数可以返回str/bytes, 并且都会最终包装为Response响应对象 @@ -51,7 +50,7 @@ def demo0002(): # 使用render_template方法渲染模板并返回 # 例如,新建一个模板index.html -@user_blu.route('/index001') +@user_bp.route('/index001') def index001(): mstr = 'Hello 黑马程序员' mint = 10 @@ -59,7 +58,7 @@ def index001(): # 3)重定向 -@user_blu.route('/demo002') +@user_bp.route('/demo002') def demo002(): # 如果想要获取视图函数的动态url,必须手动设置路由变量的值(可以传参) url = url_for("demo003", user_id=11) @@ -70,14 +69,14 @@ def demo002(): # return redirect(url_for(index)) # 配合url_for使用,index为endpoint -@user_blu.route('/demo003/') +@user_bp.route('/demo003/') def demo003(user_id): print(user_id) return "hello" # 4)返回json -@user_blu.route('/demo3') +@user_bp.route('/demo3') def demo3(): json_dict = { "user_id": 10, @@ -94,7 +93,7 @@ def demo3(): # 5)自定义状态码和响应头 # 5.1) 元祖方式 # 可以返回一个元组,这样的元组必须是 (response, status, headers) 的形式,且至少包含一个元素。 status 值会覆盖状态代码, headers 可以是一个列表或字典,作为额外的消息标头值。 -@user_blu.route('/demo4') +@user_bp.route('/demo4') def demo4(): # 目的是为了和前端进行交互,定义一套自定义的交互规则 # return '状态码为 666', 666 @@ -104,7 +103,7 @@ def demo4(): # 5.2) make_response方式 -@user_blu.route('/demo5') +@user_bp.route('/demo5') def demo5(): # 手动创建响应对象,主要为了实现设置响应头 resp = make_response('make response测试') @@ -115,7 +114,7 @@ def demo5(): #####################################如何在不同的场景里返回不同的响应信息########################################## # 1)设置Cookie -@user_blu.route('/cookie') +@user_bp.route('/cookie') def cookie(): # 每次请求时, 从请求头中取出cookie数据, 进行判断 is_help = request.cookies.get("is_help") @@ -136,7 +135,7 @@ def cookie(): # 设置有效期 -@user_blu.route('/set_cookie') +@user_bp.route('/set_cookie') def set_cookie(): response = make_response('hello world') response.set_cookie('username', 'itheima', max_age=3600) @@ -144,26 +143,26 @@ def set_cookie(): # 获取Cookie -@user_blu.route('/get_cookie') +@user_bp.route('/get_cookie') def get_cookie(): resp = request.cookies.get('username') return resp -@user_blu.route('/delete_cookie') +@user_bp.route('/delete_cookie') def delete_cookie(): response = make_response('hello world') response.delete_cookie('username') return response -@user_blu.route('/set_session') +@user_bp.route('/set_session') def set_session(): session['username'] = 'itcast' return 'set session ok' -@user_blu.route('/login') +@user_bp.route('/login') def login(): # 获取session中的数据, 进行判断 name = session.get('username') @@ -174,18 +173,18 @@ def login(): return "首页" # 未登录 -@user_blu.route('/get_session') +@user_bp.route('/get_session') def get_session(): username = session.get('username') return 'get session username {}'.format(username) -@user_blu.route('/login_use_session', methods=['GET', 'POST']) +@user_bp.route('/login_use_session', methods=['GET', 'POST']) def login_use_session(): if request.method == 'GET': # GET 展示页面 # 会读取出静态文件的内容包装为响应对象, 并且根据文件类型自动设置content-type - return app.send_static_file('login.html') + return current_app.send_static_file('login.html') else: # POST 获取提交的表单数据, 进行登录认证 @@ -211,12 +210,12 @@ def login_use_session(): # flask中对http错误封装了异常处理, 可以对http错误进行异常捕获, 以及主动抛出http错误 # 2.捕获指定异常 -@user_blu.errorhandler(ZeroDivisionError) +@user_bp.errorhandler(ZeroDivisionError) def error_zero(e): return '除数不能为0' -@user_blu.route('/index_error') +@user_bp.route('/index_error') def index_error(): a = 1 / 0 @@ -233,7 +232,7 @@ def db_query(): print('user_id={} user_name={}'.format(user_id, user_name)) -@user_blu.route('/get_user_profile') +@user_bp.route('/get_user_profile') def get_user_profile(): g.user_id = 123 g.user_name = 'itcast' -- GitLab