ManTea commited on
Commit
d27bdcb
·
1 Parent(s): 6ac0477

Redis + Websocket

Browse files
Files changed (2) hide show
  1. app.py +99 -93
  2. requirements.txt +1 -1
app.py CHANGED
@@ -1,20 +1,31 @@
1
- from flask import Flask, request, jsonify
2
- from flask_cors import CORS
3
- from flask_socketio import SocketIO, emit
 
 
4
  import pymongo
5
  from bson.objectid import ObjectId
6
  import redis
7
  import json
8
  from redis.exceptions import RedisError
9
-
10
- # Khởi tạo Flask app và SocketIO
11
- app = Flask(__name__)
12
- CORS(app)
13
- socketio = SocketIO(app, cors_allowed_origins="*")
14
-
15
- # Khởi tạo Redis client
 
 
 
 
 
 
 
 
 
16
  redis_client = redis.Redis(host='localhost', port=6379, db=0)
17
- CACHE_EXPIRE_TIME = 300 # 5 phút
18
 
19
  # MongoDB connection
20
  mongo_url = "mongodb+srv://ip6ofme:[email protected]/"
@@ -23,125 +34,121 @@ db = client["test"]
23
  pdf_collection = db["PdfDetails"]
24
  voter_collection = db["Voters"]
25
 
26
- # API để upload file và lưu thông tin vào MongoDB
27
- @app.route('/upload-files', methods=['POST'])
28
- def upload_file():
29
- # Chỉ lưu thông tin vào MongoDB
30
- title = request.form.get('title')
31
- group = request.form.get('group')
32
- firebase_url = request.form.get('url')
 
 
 
 
 
 
 
 
 
 
33
  new_pdf = {
34
  'title': title,
35
  'group': group,
36
- 'url': firebase_url,
37
  'votes': 0
38
  }
39
  result = pdf_collection.insert_one(new_pdf)
40
- return jsonify({'status': 'ok', 'id': str(result.inserted_id)})
41
-
42
- # API để lấy số lượng votes của file theo ID
43
- @app.route('/get-votes', methods=['GET'])
44
- def get_votes():
45
- file_id = request.args.get('id')
46
 
 
 
47
  try:
48
  file = pdf_collection.find_one({'_id': ObjectId(file_id)})
49
  if not file:
50
- return jsonify({'status': 'error', 'message': 'File not found'}), 404
51
-
52
- return jsonify({'status': 'ok', 'votes': file.get('votes', 0)})
53
  except Exception as e:
54
- return jsonify({'status': 'error', 'message': str(e)}), 500
55
 
56
- # API để lấy danh sách tất cả các file
57
- @app.route('/get-files', methods=['GET'])
58
- def get_files():
59
  try:
60
  files = pdf_collection.find({})
61
- file_list = []
62
- for file in files:
63
- file_list.append({
64
  'id': str(file['_id']),
65
  'title': file['title'],
66
  'group': file['group'],
67
  'url': file['url'],
68
  'votes': file.get('votes', 0)
69
- })
70
- return jsonify({'status': 'ok', 'data': file_list})
 
 
71
  except Exception as e:
72
- print(f"Error: {str(e)}")
73
- return jsonify({'status': 'error', 'message': str(e)}), 500
74
-
75
- # API để đăng ký người bình chọn
76
- @app.route('/register-voter', methods=['POST'])
77
- def register_voter():
78
- data = request.json
79
- name = data.get('name')
80
- group = data.get('group')
81
- role = data.get('role') # Thêm trường role
82
-
83
  new_voter = {
84
- 'name': name,
85
- 'group': group,
86
- 'role': role, # Lưu role vào MongoDB
87
  'number_of_votes': 0
88
  }
89
  result = voter_collection.insert_one(new_voter)
90
- return jsonify({'status': 'ok', 'id': str(result.inserted_id)})
91
-
92
- # API để bình chọn
93
- @app.route('/vote-by-voter', methods=['POST'])
94
- def vote_by_voter():
95
- data = request.json
96
- voter_id = data.get('voter_id')
97
- file_id = data.get('file_id')
98
- vote_count = data.get('vote_count', 1)
99
 
100
- if vote_count <= 0:
101
- return jsonify({'status': 'error', 'message': 'Vote count must be greater than 0'}), 400
 
 
102
 
103
- voter = voter_collection.find_one({'_id': ObjectId(voter_id)})
104
  if not voter:
105
- return jsonify({'status': 'error', 'message': 'Voter not found'}), 404
106
 
107
  max_votes = 10 if voter['role'] == 'judge' else 2
108
 
109
- if voter['number_of_votes'] + vote_count > max_votes:
110
- return jsonify({'status': 'error', 'message': 'Maximum votes exceeded'}), 400
111
 
112
  try:
113
- # Cập nhật MongoDB
114
- voter_collection.update_one({'_id': ObjectId(voter_id)}, {'$inc': {'number_of_votes': vote_count}})
115
- pdf_collection.update_one({'_id': ObjectId(file_id)}, {'$inc': {'votes': vote_count}})
 
 
 
 
 
 
116
 
117
- # Xóa cache
118
  redis_client.delete('all_files')
119
- redis_client.delete(f'voter:{voter_id}')
120
 
121
  # Emit socket event
122
- updated_file = pdf_collection.find_one({'_id': ObjectId(file_id)})
123
- socketio.emit('vote_update', {
124
- 'file_id': file_id,
125
  'votes': updated_file.get('votes', 0)
126
  })
127
 
128
- return jsonify({'status': 'ok', 'message': f'Vote recorded successfully with {vote_count} votes'})
129
  except Exception as e:
130
- return jsonify({'status': 'error', 'message': str(e)}), 500
131
 
132
- # API để lấy thông tin người bình chọn
133
- @app.route('/get-voter', methods=['GET'])
134
- def get_voter():
135
- voter_id = request.args.get('id')
136
-
137
- # Kiểm tra cache
138
  cached_voter = redis_client.get(f'voter:{voter_id}')
139
  if cached_voter:
140
- return jsonify(json.loads(cached_voter))
141
 
142
  voter = voter_collection.find_one({'_id': ObjectId(voter_id)})
143
  if not voter:
144
- return jsonify({'status': 'error', 'message': 'Voter not found'}), 404
145
 
146
  voter_data = {
147
  'status': 'ok',
@@ -151,19 +158,18 @@ def get_voter():
151
  'number_of_votes': voter['number_of_votes']
152
  }
153
 
154
- # Lưu vào cache
155
  redis_client.setex(f'voter:{voter_id}', CACHE_EXPIRE_TIME, json.dumps(voter_data))
156
- return jsonify(voter_data)
157
 
158
- # Socket events
159
- @socketio.on('connect')
160
- def handle_connect():
161
  print('Client connected')
162
 
163
- @socketio.on('disconnect')
164
- def handle_disconnect():
165
  print('Client disconnected')
166
 
167
- # Khởi chạy server
168
  if __name__ == "__main__":
169
- socketio.run(app, port=5000, debug=True)
 
 
1
+ from fastapi import FastAPI, HTTPException, Form, Request
2
+ from fastapi.middleware.cors import CORSMiddleware
3
+ from fastapi.responses import JSONResponse
4
+ from fastapi_socketio import SocketManager
5
+ from typing import Optional
6
  import pymongo
7
  from bson.objectid import ObjectId
8
  import redis
9
  import json
10
  from redis.exceptions import RedisError
11
+ from pydantic import BaseModel
12
+
13
+ # Initialize FastAPI app
14
+ app = FastAPI()
15
+ socket_manager = SocketManager(app=app)
16
+
17
+ # Add CORS middleware
18
+ app.add_middleware(
19
+ CORSMiddleware,
20
+ allow_origins=["*"],
21
+ allow_credentials=True,
22
+ allow_methods=["*"],
23
+ allow_headers=["*"],
24
+ )
25
+
26
+ # Initialize Redis client
27
  redis_client = redis.Redis(host='localhost', port=6379, db=0)
28
+ CACHE_EXPIRE_TIME = 300 # 5 minutes
29
 
30
  # MongoDB connection
31
  mongo_url = "mongodb+srv://ip6ofme:[email protected]/"
 
34
  pdf_collection = db["PdfDetails"]
35
  voter_collection = db["Voters"]
36
 
37
+ # Pydantic models for request validation
38
+ class VoterRegistration(BaseModel):
39
+ name: str
40
+ group: str
41
+ role: str
42
+
43
+ class VoteRequest(BaseModel):
44
+ voter_id: str
45
+ file_id: str
46
+ vote_count: Optional[int] = 1
47
+
48
+ @app.post("/upload-files")
49
+ async def upload_file(
50
+ title: str = Form(...),
51
+ group: str = Form(...),
52
+ url: str = Form(...)
53
+ ):
54
  new_pdf = {
55
  'title': title,
56
  'group': group,
57
+ 'url': url,
58
  'votes': 0
59
  }
60
  result = pdf_collection.insert_one(new_pdf)
61
+ return {'status': 'ok', 'id': str(result.inserted_id)}
 
 
 
 
 
62
 
63
+ @app.get("/get-votes")
64
+ async def get_votes(file_id: str):
65
  try:
66
  file = pdf_collection.find_one({'_id': ObjectId(file_id)})
67
  if not file:
68
+ raise HTTPException(status_code=404, detail="File not found")
69
+ return {'status': 'ok', 'votes': file.get('votes', 0)}
 
70
  except Exception as e:
71
+ raise HTTPException(status_code=500, detail=str(e))
72
 
73
+ @app.get("/get-files")
74
+ async def get_files():
 
75
  try:
76
  files = pdf_collection.find({})
77
+ file_list = [
78
+ {
 
79
  'id': str(file['_id']),
80
  'title': file['title'],
81
  'group': file['group'],
82
  'url': file['url'],
83
  'votes': file.get('votes', 0)
84
+ }
85
+ for file in files
86
+ ]
87
+ return {'status': 'ok', 'data': file_list}
88
  except Exception as e:
89
+ raise HTTPException(status_code=500, detail=str(e))
90
+
91
+ @app.post("/register-voter")
92
+ async def register_voter(voter: VoterRegistration):
 
 
 
 
 
 
 
93
  new_voter = {
94
+ 'name': voter.name,
95
+ 'group': voter.group,
96
+ 'role': voter.role,
97
  'number_of_votes': 0
98
  }
99
  result = voter_collection.insert_one(new_voter)
100
+ return {'status': 'ok', 'id': str(result.inserted_id)}
 
 
 
 
 
 
 
 
101
 
102
+ @app.post("/vote-by-voter")
103
+ async def vote_by_voter(vote_request: VoteRequest):
104
+ if vote_request.vote_count <= 0:
105
+ raise HTTPException(status_code=400, detail="Vote count must be greater than 0")
106
 
107
+ voter = voter_collection.find_one({'_id': ObjectId(vote_request.voter_id)})
108
  if not voter:
109
+ raise HTTPException(status_code=404, detail="Voter not found")
110
 
111
  max_votes = 10 if voter['role'] == 'judge' else 2
112
 
113
+ if voter['number_of_votes'] + vote_request.vote_count > max_votes:
114
+ raise HTTPException(status_code=400, detail="Maximum votes exceeded")
115
 
116
  try:
117
+ # Update MongoDB
118
+ voter_collection.update_one(
119
+ {'_id': ObjectId(vote_request.voter_id)},
120
+ {'$inc': {'number_of_votes': vote_request.vote_count}}
121
+ )
122
+ pdf_collection.update_one(
123
+ {'_id': ObjectId(vote_request.file_id)},
124
+ {'$inc': {'votes': vote_request.vote_count}}
125
+ )
126
 
127
+ # Clear cache
128
  redis_client.delete('all_files')
129
+ redis_client.delete(f'voter:{vote_request.voter_id}')
130
 
131
  # Emit socket event
132
+ updated_file = pdf_collection.find_one({'_id': ObjectId(vote_request.file_id)})
133
+ await socket_manager.emit('vote_update', {
134
+ 'file_id': vote_request.file_id,
135
  'votes': updated_file.get('votes', 0)
136
  })
137
 
138
+ return {'status': 'ok', 'message': f'Vote recorded successfully with {vote_request.vote_count} votes'}
139
  except Exception as e:
140
+ raise HTTPException(status_code=500, detail=str(e))
141
 
142
+ @app.get("/get-voter")
143
+ async def get_voter(voter_id: str):
144
+ # Check cache
 
 
 
145
  cached_voter = redis_client.get(f'voter:{voter_id}')
146
  if cached_voter:
147
+ return json.loads(cached_voter)
148
 
149
  voter = voter_collection.find_one({'_id': ObjectId(voter_id)})
150
  if not voter:
151
+ raise HTTPException(status_code=404, detail="Voter not found")
152
 
153
  voter_data = {
154
  'status': 'ok',
 
158
  'number_of_votes': voter['number_of_votes']
159
  }
160
 
161
+ # Save to cache
162
  redis_client.setex(f'voter:{voter_id}', CACHE_EXPIRE_TIME, json.dumps(voter_data))
163
+ return voter_data
164
 
165
+ @socket_manager.on('connect')
166
+ async def handle_connect():
 
167
  print('Client connected')
168
 
169
+ @socket_manager.on('disconnect')
170
+ async def handle_disconnect():
171
  print('Client disconnected')
172
 
 
173
  if __name__ == "__main__":
174
+ import uvicorn
175
+ uvicorn.run(app, host="0.0.0.0", port=5000)
requirements.txt CHANGED
@@ -6,6 +6,6 @@ python-multipart
6
  pymongo
7
  redis
8
  flask
9
- flask-socketio
10
  python-socketio
11
  flask-cors
 
6
  pymongo
7
  redis
8
  flask
9
+ fastapi_socketio
10
  python-socketio
11
  flask-cors