sync
This commit is contained in:
@@ -1,7 +1,8 @@
|
||||
import os
|
||||
import secrets
|
||||
import time
|
||||
from collections import defaultdict, deque
|
||||
from threading import Lock
|
||||
from threading import Lock, Thread
|
||||
|
||||
from flask import Flask, jsonify, render_template, request
|
||||
from scraper import ScrapeError, get_rating_distribution, validate_maps_url
|
||||
@@ -11,6 +12,8 @@ app.config["MAX_CONTENT_LENGTH"] = 4096
|
||||
_scrape_lock = Lock() # jeden Chromium naraz, żeby nie zamęczyć RPi
|
||||
_rate_lock = Lock()
|
||||
_requests = defaultdict(deque)
|
||||
_jobs = {}
|
||||
_jobs_lock = Lock()
|
||||
|
||||
|
||||
def _rate_limited(ip, limit=6, window=60):
|
||||
@@ -60,16 +63,52 @@ def reviews():
|
||||
return jsonify(error=str(exc)), 400
|
||||
if not _scrape_lock.acquire(blocking=False):
|
||||
return jsonify(error="Trwa już inne sprawdzanie. Spróbuj za chwilę."), 429
|
||||
|
||||
job_id = secrets.token_urlsafe(24)
|
||||
with _jobs_lock:
|
||||
cutoff = time.monotonic() - 600
|
||||
for old_id in [key for key, job in _jobs.items() if job["created"] < cutoff]:
|
||||
del _jobs[old_id]
|
||||
_jobs[job_id] = {
|
||||
"status": "running", "progress": 0,
|
||||
"message": "Rozpoczynam sprawdzanie", "created": time.monotonic(),
|
||||
}
|
||||
|
||||
Thread(target=_run_job, args=(job_id, url), daemon=True).start()
|
||||
return jsonify(job_id=job_id), 202
|
||||
|
||||
|
||||
def _run_job(job_id, url):
|
||||
def update(percent, message):
|
||||
with _jobs_lock:
|
||||
_jobs[job_id].update(progress=percent, message=message)
|
||||
|
||||
try:
|
||||
return jsonify(get_rating_distribution(url))
|
||||
result = get_rating_distribution(url, progress=update)
|
||||
with _jobs_lock:
|
||||
_jobs[job_id].update(status="complete", progress=100, message="Gotowe", result=result)
|
||||
except ScrapeError as exc:
|
||||
return jsonify(error=str(exc)), 422
|
||||
with _jobs_lock:
|
||||
_jobs[job_id].update(status="error", message=str(exc))
|
||||
except Exception:
|
||||
app.logger.exception("Unexpected scraper failure")
|
||||
return jsonify(error="Google Maps nie odpowiedziało poprawnie. Spróbuj później."), 502
|
||||
with _jobs_lock:
|
||||
_jobs[job_id].update(
|
||||
status="error", message="Google Maps nie odpowiedziało poprawnie. Spróbuj później."
|
||||
)
|
||||
finally:
|
||||
_scrape_lock.release()
|
||||
|
||||
|
||||
@app.get("/api/reviews/<job_id>")
|
||||
def review_status(job_id):
|
||||
with _jobs_lock:
|
||||
job = _jobs.get(job_id)
|
||||
if not job:
|
||||
return jsonify(error="Nie znaleziono tego sprawdzenia."), 404
|
||||
response = {key: value for key, value in job.items() if key != "created"}
|
||||
return jsonify(response)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
app.run(host=os.environ.get("HOST", "127.0.0.1"), port=int(os.environ.get("PORT", 8080)), debug=False)
|
||||
|
||||
Reference in New Issue
Block a user