-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathserver.py
More file actions
145 lines (121 loc) · 5 KB
/
Copy pathserver.py
File metadata and controls
145 lines (121 loc) · 5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
#!/usr/bin/env python3
"""Local server for the new-grad tier-list job board.
- Serves the project folder statically (so swe-tier-list.html can fetch
results/*.json).
- POST /api/applied {slug, job_id, applied} -> persists the `applied` flag
back into results/{slug}.json.
Run: python3 server.py [port] (default port 8000)
Open: http://localhost:8000/swe-tier-list.html
"""
import json
import os
import re
import sys
import tempfile
from http.server import SimpleHTTPRequestHandler, ThreadingHTTPServer
ROOT = os.path.dirname(os.path.abspath(__file__))
RESULTS_DIR = os.path.join(ROOT, "results")
SLUG_RE = re.compile(r"^[a-z0-9-]+$")
def resolve_result_path(slug):
"""Return the real path of results/<slug>.json, matched case-insensitively.
Lets the fetcher write Amazon.json / amazon.json / AMAZON.json interchangeably
while the page always asks for the lowercase slug. Returns None if absent."""
if not SLUG_RE.match(slug):
return None
target = (slug + ".json").lower()
if not os.path.isdir(RESULTS_DIR):
return None
for fn in os.listdir(RESULTS_DIR):
if fn.lower() == target:
return os.path.join(RESULTS_DIR, fn)
return None
class Handler(SimpleHTTPRequestHandler):
def __init__(self, *args, **kwargs):
super().__init__(*args, directory=ROOT, **kwargs)
# ----- helpers -----
def _send_json(self, status, payload):
body = json.dumps(payload).encode("utf-8")
self.send_response(status)
self.send_header("Content-Type", "application/json")
self.send_header("Content-Length", str(len(body)))
self.end_headers()
self.wfile.write(body)
# ----- routes -----
def do_GET(self):
# Serve results/<name>.json case-insensitively, e.g. a request for
# results/amazon.json resolves a file saved as Amazon.json.
path = self.path.split("?", 1)[0]
if path.lower().startswith("/results/") and path.lower().endswith(".json"):
slug = os.path.basename(path)[:-5] # strip ".json"
real = resolve_result_path(slug.lower())
if real:
try:
with open(real, "rb") as f:
body = f.read()
except OSError:
self._send_json(404, {"ok": False, "error": "not found"})
return
self.send_response(200)
self.send_header("Content-Type", "application/json; charset=utf-8")
self.send_header("Content-Length", str(len(body)))
self.send_header("Cache-Control", "no-store")
self.end_headers()
self.wfile.write(body)
return
self._send_json(404, {"ok": False, "error": "not fetched"})
return
return super().do_GET()
def do_POST(self):
if self.path != "/api/applied":
self._send_json(404, {"ok": False, "error": "unknown endpoint"})
return
try:
length = int(self.headers.get("Content-Length", 0))
data = json.loads(self.rfile.read(length) or b"{}")
except (ValueError, json.JSONDecodeError):
self._send_json(400, {"ok": False, "error": "invalid JSON body"})
return
slug = str(data.get("slug", ""))
job_id = data.get("job_id")
applied = bool(data.get("applied", False))
if not SLUG_RE.match(slug) or job_id is None:
self._send_json(400, {"ok": False, "error": "slug/job_id required"})
return
path = resolve_result_path(slug)
if not path:
self._send_json(404, {"ok": False, "error": "company file not found"})
return
with open(path, "r", encoding="utf-8") as f:
doc = json.load(f)
job = next((j for j in doc.get("jobs", []) if j.get("job_id") == job_id), None)
if job is None:
self._send_json(404, {"ok": False, "error": "job_id not found"})
return
job["applied"] = applied
# atomic write
fd, tmp = tempfile.mkstemp(dir=RESULTS_DIR, suffix=".tmp")
try:
with os.fdopen(fd, "w", encoding="utf-8") as f:
json.dump(doc, f, ensure_ascii=False, indent=2)
os.replace(tmp, path)
except Exception:
if os.path.exists(tmp):
os.remove(tmp)
raise
self._send_json(200, {"ok": True, "job_id": job_id, "applied": applied})
# quieter, single-line logging
def log_message(self, fmt, *args):
sys.stderr.write("%s - %s\n" % (self.address_string(), fmt % args))
def main():
port = int(sys.argv[1]) if len(sys.argv) > 1 else 8000
os.makedirs(RESULTS_DIR, exist_ok=True)
httpd = ThreadingHTTPServer(("127.0.0.1", port), Handler)
print(f"Serving {ROOT}")
print(f"Open http://localhost:{port}/swe-tier-list.html")
print("Ctrl+C to stop.")
try:
httpd.serve_forever()
except KeyboardInterrupt:
print("\nbye")
if __name__ == "__main__":
main()