euler314 commited on
Commit
89408c1
Β·
verified Β·
1 Parent(s): fb4f63a

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +71 -30
app.py CHANGED
@@ -1,20 +1,29 @@
1
  # app.py
2
 
3
  from flask import Flask, Response, request, jsonify
4
-
5
  import os
6
 
7
  app = Flask(__name__)
8
 
9
  # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
10
- # Pre-generate a 10 MiB random blob for download tests
 
 
 
 
 
11
  # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
12
- DOWNLOAD_SIZE_BYTES = 10 * 1024 * 1024
13
- _blob = os.urandom(DOWNLOAD_SIZE_BYTES)
 
 
 
 
 
14
 
15
 
16
  # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
17
- # Route: Root – serve the HTML + JS speed‐test page
18
  # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
19
  @app.route("/")
20
  def index():
@@ -23,7 +32,7 @@ def index():
23
  <html lang="en">
24
  <head>
25
  <meta charset="UTF-8" />
26
- <title>Client-Side Speed Test</title>
27
  <style>
28
  body { font-family: sans-serif; max-width: 600px; margin: 2em auto; }
29
  button { padding: 0.5em 1em; font-size: 1rem; }
@@ -32,8 +41,8 @@ def index():
32
  </style>
33
  </head>
34
  <body>
35
- <h2>Wi-Fi / Ethernet Speed Test</h2>
36
- <p>This runs entirely in your browserβ€”download a 10 MiB file and upload random data to measure your real Internet link.</p>
37
  <button id="startBtn">Start Speed Test</button>
38
 
39
  <div class="result" id="results" style="display: none;">
@@ -61,7 +70,7 @@ def index():
61
  ulSpan.textContent = "Testing…";
62
  pingSpan.textContent = "Testing…";
63
 
64
- // 1) Ping: 5 small GETs to /ping_test
65
  let pingTimes = [];
66
  for (let i = 0; i < 5; i++) {
67
  const t0 = performance.now();
@@ -72,31 +81,55 @@ def index():
72
  const avgPing = pingTimes.reduce((a, b) => a + b, 0) / pingTimes.length;
73
  pingSpan.textContent = avgPing.toFixed(2) + " ms";
74
 
75
- // 2) Download test: fetch 10 MiB blob
76
  const dlStart = performance.now();
77
  const response = await fetch("/download_test", { cache: "no-store" });
78
- const blob = await response.blob();
 
 
 
 
 
 
79
  const dlEnd = performance.now();
80
- const dlBytes = blob.size;
81
  const dlBits = dlBytes * 8;
82
  const dlDurationSec = (dlEnd - dlStart) / 1000;
83
  const dlSpeedBps = dlBits / dlDurationSec;
84
  dlSpan.textContent = toMbps(dlSpeedBps);
85
 
86
- // 3) Upload test: send 10 MiB random data
87
- const uploadSizeBytes = dlBytes;
88
- const randomBuffer = new Uint8Array(uploadSizeBytes);
89
- window.crypto.getRandomValues(randomBuffer);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
90
 
91
  const ulStart = performance.now();
92
  await fetch("/upload_test", {
93
  method: "POST",
94
  headers: { "Content-Type": "application/octet-stream" },
95
- body: randomBuffer
96
  });
97
  const ulEnd = performance.now();
98
  const ulDurationSec = (ulEnd - ulStart) / 1000;
99
- const ulBits = uploadSizeBytes * 8;
100
  const ulSpeedBps = ulBits / ulDurationSec;
101
  ulSpan.textContent = toMbps(ulSpeedBps);
102
 
@@ -110,7 +143,7 @@ def index():
110
 
111
 
112
  # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
113
- # Route: /ping_test – empty 200 response (used for ping measurement)
114
  # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
115
  @app.route("/ping_test")
116
  def ping_test():
@@ -118,32 +151,40 @@ def ping_test():
118
 
119
 
120
  # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
121
- # Route: /download_test – serve the 10 MiB random blob
122
  # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
123
  @app.route("/download_test")
124
  def download_test():
 
 
 
 
 
125
  return Response(
126
- _blob,
127
  mimetype="application/octet-stream",
128
- headers={
129
- "Content-Disposition": f"attachment; filename=\"test_{DOWNLOAD_SIZE_BYTES}.bin\""
130
- }
131
  )
132
 
133
 
134
  # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
135
- # Route: /upload_test – accept upload, return JSON with received size
136
  # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
137
  @app.route("/upload_test", methods=["POST"])
138
  def upload_test():
139
- data = request.get_data() # read all bytes
140
- size = len(data)
141
- return jsonify({"received_bytes": size})
 
 
 
 
 
 
142
 
143
 
144
  # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
145
- # Run the Flask app
146
  # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
147
  if __name__ == "__main__":
148
- # Bind to 0.0.0.0 so HF’s runtime can route traffic correctly
149
  app.run(host="0.0.0.0", port=7860, debug=False)
 
1
  # app.py
2
 
3
  from flask import Flask, Response, request, jsonify
 
4
  import os
5
 
6
  app = Flask(__name__)
7
 
8
  # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
9
+ # Configuration: Test size = 1 GiB
10
+ # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
11
+ DOWNLOAD_SIZE_BYTES = 1 * 1024 * 1024 * 1024 # 1 GiB
12
+
13
+ # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
14
+ # Generator for streaming 1 GiB of random bytes in 10 MiB chunks
15
  # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
16
+ def generate_random_blob():
17
+ sent = 0
18
+ chunk_size = 10 * 1024 * 1024 # 10 MiB per chunk
19
+ while sent < DOWNLOAD_SIZE_BYTES:
20
+ to_send = min(chunk_size, DOWNLOAD_SIZE_BYTES - sent)
21
+ yield os.urandom(to_send)
22
+ sent += to_send
23
 
24
 
25
  # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
26
+ # Route: β€œ/” – serve the HTML + JS client
27
  # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
28
  @app.route("/")
29
  def index():
 
32
  <html lang="en">
33
  <head>
34
  <meta charset="UTF-8" />
35
+ <title>Client-Side Speed Test (1 GiB)</title>
36
  <style>
37
  body { font-family: sans-serif; max-width: 600px; margin: 2em auto; }
38
  button { padding: 0.5em 1em; font-size: 1rem; }
 
41
  </style>
42
  </head>
43
  <body>
44
+ <h2>Wi-Fi / Ethernet Speed Test (Up to 1 GiB)</h2>
45
+ <p>This test will measure your real Internet speed by downloading <strong>1 GiB</strong> of random data and uploading <strong>1 GiB</strong> back to the server. All timing runs entirely in your browser.</p>
46
  <button id="startBtn">Start Speed Test</button>
47
 
48
  <div class="result" id="results" style="display: none;">
 
70
  ulSpan.textContent = "Testing…";
71
  pingSpan.textContent = "Testing…";
72
 
73
+ // 1) Measure ping: 5 tiny GETs to /ping_test
74
  let pingTimes = [];
75
  for (let i = 0; i < 5; i++) {
76
  const t0 = performance.now();
 
81
  const avgPing = pingTimes.reduce((a, b) => a + b, 0) / pingTimes.length;
82
  pingSpan.textContent = avgPing.toFixed(2) + " ms";
83
 
84
+ // 2) Download test: stream 1 GiB from /download_test
85
  const dlStart = performance.now();
86
  const response = await fetch("/download_test", { cache: "no-store" });
87
+ const reader = response.body.getReader();
88
+ let dlBytes = 0;
89
+ while (true) {
90
+ const { done, value } = await reader.read();
91
+ if (done) break;
92
+ dlBytes += value.length;
93
+ }
94
  const dlEnd = performance.now();
 
95
  const dlBits = dlBytes * 8;
96
  const dlDurationSec = (dlEnd - dlStart) / 1000;
97
  const dlSpeedBps = dlBits / dlDurationSec;
98
  dlSpan.textContent = toMbps(dlSpeedBps);
99
 
100
+ // 3) Upload test: stream 1 GiB of random data to /upload_test
101
+ const uploadTotalBytes = dlBytes; // should be 1 GiB
102
+ const chunkSize = 10 * 1024 * 1024; // 10 MiB
103
+ let sentBytes = 0;
104
+
105
+ const uploadStream = new ReadableStream({
106
+ start(controller) {
107
+ function pushChunk() {
108
+ if (sentBytes >= uploadTotalBytes) {
109
+ controller.close();
110
+ return;
111
+ }
112
+ const size = Math.min(chunkSize, uploadTotalBytes - sentBytes);
113
+ const chunk = new Uint8Array(size);
114
+ window.crypto.getRandomValues(chunk);
115
+ controller.enqueue(chunk);
116
+ sentBytes += size;
117
+ // immediately queue next
118
+ pushChunk();
119
+ }
120
+ pushChunk();
121
+ }
122
+ });
123
 
124
  const ulStart = performance.now();
125
  await fetch("/upload_test", {
126
  method: "POST",
127
  headers: { "Content-Type": "application/octet-stream" },
128
+ body: uploadStream
129
  });
130
  const ulEnd = performance.now();
131
  const ulDurationSec = (ulEnd - ulStart) / 1000;
132
+ const ulBits = uploadTotalBytes * 8;
133
  const ulSpeedBps = ulBits / ulDurationSec;
134
  ulSpan.textContent = toMbps(ulSpeedBps);
135
 
 
143
 
144
 
145
  # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
146
+ # Route: /ping_test – empty 200 response for ping
147
  # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
148
  @app.route("/ping_test")
149
  def ping_test():
 
151
 
152
 
153
  # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
154
+ # Route: /download_test – stream 1 GiB of random data
155
  # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
156
  @app.route("/download_test")
157
  def download_test():
158
+ headers = {
159
+ "Content-Disposition": f"attachment; filename=\"test_{DOWNLOAD_SIZE_BYTES}.bin\"",
160
+ "Content-Length": str(DOWNLOAD_SIZE_BYTES),
161
+ "Cache-Control": "no-store"
162
+ }
163
  return Response(
164
+ generate_random_blob(),
165
  mimetype="application/octet-stream",
166
+ headers=headers
 
 
167
  )
168
 
169
 
170
  # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
171
+ # Route: /upload_test – consume uploaded data in chunks and return JSON
172
  # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
173
  @app.route("/upload_test", methods=["POST"])
174
  def upload_test():
175
+ total = 0
176
+ # Read the incoming stream in 1 MiB chunks and discard
177
+ while True:
178
+ chunk = request.stream.read(1 * 1024 * 1024)
179
+ if not chunk:
180
+ break
181
+ total += len(chunk)
182
+ # total should be near 1 GiB if upload completed
183
+ return jsonify({"received_bytes": total})
184
 
185
 
186
  # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
187
+ # Run the Flask app on port 7860
188
  # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
189
  if __name__ == "__main__":
 
190
  app.run(host="0.0.0.0", port=7860, debug=False)