Araeynn commited on
Commit
8a1db90
·
verified ·
1 Parent(s): c32a2ed

Upload 2 files

Browse files
Files changed (2) hide show
  1. app.py +815 -27
  2. requirements.txt +4 -1
app.py CHANGED
@@ -1,11 +1,13 @@
1
- from fastapi import FastAPI, WebSocket, WebSocketDisconnect, Form, HTTPException
2
- from fastapi.responses import JSONResponse
3
- from fastapi.middleware.cors import CORSMiddleware
4
- from pathlib import Path
5
- from argon2 import PasswordHasher
6
- from datetime import datetime
7
  import json
8
  import secrets
 
 
 
 
 
 
 
9
 
10
  # Constants
11
  USERS_FILE = Path("users.json")
@@ -19,26 +21,74 @@ app = FastAPI()
19
  ph = PasswordHasher()
20
 
21
  app.add_middleware(
22
- CORSMiddleware,
23
- allow_origins=["*"],
24
- allow_methods=["*"],
25
- allow_headers=["*"]
26
  )
27
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
  # ---------------------- Storage ---------------------- #
29
 
 
30
  def load_json(path: Path):
31
  if not path.exists():
32
  return {}
33
  with open(path, "r") as f:
34
  return json.load(f)
35
 
 
36
  def save_json(path: Path, data):
37
  with open(path, "w") as f:
38
  json.dump(data, f, indent=2)
39
 
 
40
  # ---------------------- Auth ---------------------- #
41
 
 
42
  def register_user(username: str, password: str):
43
  users = load_json(USERS_FILE)
44
  if username in users:
@@ -47,6 +97,7 @@ def register_user(username: str, password: str):
47
  users[username] = hashed
48
  save_json(USERS_FILE, users)
49
 
 
50
  def verify_user(username: str, password: str):
51
  users = load_json(USERS_FILE)
52
  if username not in users:
@@ -54,11 +105,14 @@ def verify_user(username: str, password: str):
54
  try:
55
  ph.verify(users[username], password)
56
  return True
57
- except:
 
58
  return False
59
 
 
60
  # ---------------------- Glares System ---------------------- #
61
 
 
62
  def get_updated_glares(username: str):
63
  glares = load_json(GLARES_FILE)
64
  now = datetime.utcnow()
@@ -73,7 +127,7 @@ def get_updated_glares(username: str):
73
  delta = (now - last).total_seconds()
74
 
75
  if current >= GLARE_CAP:
76
- return int(current)
77
 
78
  earn_rate = BASE_RATE * (1 - current / GLARE_CAP)
79
  earned = delta * earn_rate
@@ -81,27 +135,32 @@ def get_updated_glares(username: str):
81
 
82
  glares[username] = [int(new_total), now.strftime(TIME_FORMAT)]
83
  save_json(GLARES_FILE, glares)
84
- return int(new_total)
85
 
86
- def update_user_glares(username: str, new_total: int):
 
87
  glares = load_json(GLARES_FILE)
88
  now = datetime.utcnow().strftime(TIME_FORMAT)
89
- glares[username] = [new_total, now]
90
  save_json(GLARES_FILE, glares)
91
 
 
92
  # ---------------------- Routes ---------------------- #
93
 
 
94
  @app.post("/register")
95
  def register(username: str = Form(...), password: str = Form(...)):
96
  register_user(username, password)
97
  return JSONResponse(content={"message": "User registered successfully"})
98
 
 
99
  @app.post("/login")
100
  def login(username: str = Form(...), password: str = Form(...)):
101
  if verify_user(username, password):
102
  return JSONResponse(content={"message": "Login successful"})
103
  raise HTTPException(status_code=401, detail="Invalid credentials")
104
 
 
105
  @app.get("/glares")
106
  def get_glares(username: str, password: str):
107
  if not verify_user(username, password):
@@ -109,10 +168,13 @@ def get_glares(username: str, password: str):
109
  current = get_updated_glares(username)
110
  return {"username": username, "glares": current}
111
 
 
112
  # ---------------------- Coin Flip ---------------------- #
113
 
 
114
  @app.websocket("/ws/coinflip")
115
- async def coinflip_game(websocket: WebSocket):
 
116
  await websocket.accept()
117
  try:
118
  # First message must be auth
@@ -132,7 +194,11 @@ async def coinflip_game(websocket: WebSocket):
132
  while True:
133
  data = await websocket.receive_json()
134
  guess = data.get("guess")
135
- bet = int(data.get("bet", 0))
 
 
 
 
136
 
137
  if guess not in ["heads", "tails"] or bet <= 0:
138
  await websocket.send_json({"error": "Invalid bet or guess"})
@@ -145,15 +211,27 @@ async def coinflip_game(websocket: WebSocket):
145
 
146
  result = secrets.choice(["heads", "tails"])
147
  win = result == guess
148
- new_balance = current + bet if win else current - bet
149
- update_user_glares(username, new_balance)
150
 
151
- await websocket.send_json({
152
- "guess": guess,
153
- "result": result,
154
- "outcome": "win" if win else "lose",
155
- "new_balance": new_balance
156
- })
 
 
 
 
 
 
 
 
 
 
 
 
 
 
157
 
158
  except WebSocketDisconnect:
159
  print("Disconnected")
@@ -161,10 +239,443 @@ async def coinflip_game(websocket: WebSocket):
161
  await websocket.send_json({"error": str(e)})
162
  await websocket.close()
163
 
 
164
  # ---------------------- Roulette ---------------------- #
165
 
 
166
  @app.websocket("/ws/roulette")
167
- async def coinflip_game(websocket: WebSocket):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
168
  await websocket.accept()
169
  try:
170
  # First message must be auth
@@ -183,7 +694,69 @@ async def coinflip_game(websocket: WebSocket):
183
 
184
  while True:
185
  data = await websocket.receive_json()
186
- pass
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
187
 
188
  except WebSocketDisconnect:
189
  print("Disconnected")
@@ -191,6 +764,221 @@ async def coinflip_game(websocket: WebSocket):
191
  await websocket.send_json({"error": str(e)})
192
  await websocket.close()
193
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
194
  if __name__ == "__main__":
195
  import uvicorn
 
196
  uvicorn.run("app:app", host="0.0.0.0", port=7860, reload=False)
 
1
+ import asyncio
 
 
 
 
 
2
  import json
3
  import secrets
4
+ from datetime import datetime
5
+ from pathlib import Path
6
+
7
+ from argon2 import PasswordHasher
8
+ from fastapi import FastAPI, Form, HTTPException, WebSocket, WebSocketDisconnect
9
+ from fastapi.middleware.cors import CORSMiddleware
10
+ from fastapi.responses import JSONResponse
11
 
12
  # Constants
13
  USERS_FILE = Path("users.json")
 
21
  ph = PasswordHasher()
22
 
23
  app.add_middleware(
24
+ CORSMiddleware, allow_origins=["*"], allow_methods=["*"], allow_headers=["*"]
 
 
 
25
  )
26
 
27
+
28
+ # ---------------------- Helper Functions ---------------------- #
29
+
30
+
31
+ def secure_crash_point():
32
+ r = secrets.randbelow(10**6) / 10**6
33
+ if r == 1.0:
34
+ r = 0.999999
35
+ return round(max(1.0, 1.0 / (0.99 * (1.0 - r))), 2)
36
+
37
+
38
+ def secure_uniform(a, b):
39
+ # Generates a float in [a, b) using secrets
40
+ scale = secrets.randbelow(10**6) / 10**6 # 0.000000 to 0.999999
41
+ return a + (b - a) * scale
42
+
43
+
44
+ def weighted_choice(elements, probabilities):
45
+ # Ensure probabilities sum to 1
46
+ total = sum(probabilities)
47
+ if not abs(total - 1.0) < 1e-8:
48
+ raise ValueError("Probabilities must sum to 1.")
49
+
50
+ # Compute cumulative probabilities
51
+ cumulative = []
52
+ cumsum = 0.0
53
+ for p in probabilities:
54
+ cumsum += p
55
+ cumulative.append(cumsum)
56
+
57
+ # Generate a random float in [0, 1)
58
+ r = secrets.randbelow(10**8) / 10**8
59
+
60
+ # Find the element corresponding to r
61
+ for i, cp in enumerate(cumulative):
62
+ if r < cp:
63
+ return elements[i]
64
+ return elements[-1] # fallback in case of rounding
65
+
66
+
67
+ # Example usage:
68
+ elements = ["apple", "banana", "cherry"]
69
+ probabilities = [0.2, 0.5, 0.3]
70
+ result = weighted_choice(elements, probabilities)
71
+ print(result)
72
+
73
+
74
  # ---------------------- Storage ---------------------- #
75
 
76
+
77
  def load_json(path: Path):
78
  if not path.exists():
79
  return {}
80
  with open(path, "r") as f:
81
  return json.load(f)
82
 
83
+
84
  def save_json(path: Path, data):
85
  with open(path, "w") as f:
86
  json.dump(data, f, indent=2)
87
 
88
+
89
  # ---------------------- Auth ---------------------- #
90
 
91
+
92
  def register_user(username: str, password: str):
93
  users = load_json(USERS_FILE)
94
  if username in users:
 
97
  users[username] = hashed
98
  save_json(USERS_FILE, users)
99
 
100
+
101
  def verify_user(username: str, password: str):
102
  users = load_json(USERS_FILE)
103
  if username not in users:
 
105
  try:
106
  ph.verify(users[username], password)
107
  return True
108
+ except Exception as e:
109
+ print(f"Verification error: {e}")
110
  return False
111
 
112
+
113
  # ---------------------- Glares System ---------------------- #
114
 
115
+
116
  def get_updated_glares(username: str):
117
  glares = load_json(GLARES_FILE)
118
  now = datetime.utcnow()
 
127
  delta = (now - last).total_seconds()
128
 
129
  if current >= GLARE_CAP:
130
+ return current
131
 
132
  earn_rate = BASE_RATE * (1 - current / GLARE_CAP)
133
  earned = delta * earn_rate
 
135
 
136
  glares[username] = [int(new_total), now.strftime(TIME_FORMAT)]
137
  save_json(GLARES_FILE, glares)
138
+ return new_total
139
 
140
+
141
+ def update_user_glares(username: str, earnings: float):
142
  glares = load_json(GLARES_FILE)
143
  now = datetime.utcnow().strftime(TIME_FORMAT)
144
+ glares[username] = [glares[username][0] + earnings, now]
145
  save_json(GLARES_FILE, glares)
146
 
147
+
148
  # ---------------------- Routes ---------------------- #
149
 
150
+
151
  @app.post("/register")
152
  def register(username: str = Form(...), password: str = Form(...)):
153
  register_user(username, password)
154
  return JSONResponse(content={"message": "User registered successfully"})
155
 
156
+
157
  @app.post("/login")
158
  def login(username: str = Form(...), password: str = Form(...)):
159
  if verify_user(username, password):
160
  return JSONResponse(content={"message": "Login successful"})
161
  raise HTTPException(status_code=401, detail="Invalid credentials")
162
 
163
+
164
  @app.get("/glares")
165
  def get_glares(username: str, password: str):
166
  if not verify_user(username, password):
 
168
  current = get_updated_glares(username)
169
  return {"username": username, "glares": current}
170
 
171
+
172
  # ---------------------- Coin Flip ---------------------- #
173
 
174
+
175
  @app.websocket("/ws/coinflip")
176
+ async def coinflip(websocket: WebSocket):
177
+ """Edge: 1%"""
178
  await websocket.accept()
179
  try:
180
  # First message must be auth
 
194
  while True:
195
  data = await websocket.receive_json()
196
  guess = data.get("guess")
197
+ bet = data.get("bet", 0)
198
+
199
+ if not isinstance(bet, int):
200
+ await websocket.send_json({"error": "Invalid bet"})
201
+ continue
202
 
203
  if guess not in ["heads", "tails"] or bet <= 0:
204
  await websocket.send_json({"error": "Invalid bet or guess"})
 
211
 
212
  result = secrets.choice(["heads", "tails"])
213
  win = result == guess
 
 
214
 
215
+ if win:
216
+ # Take 2% commission on wins
217
+ commission = bet * 0.02
218
+ net_win = bet - commission
219
+ update_user_glares(username, net_win)
220
+ earnings = net_win
221
+ else:
222
+ commission = 0
223
+ update_user_glares(username, -bet)
224
+ earnings = -bet
225
+
226
+ await websocket.send_json(
227
+ {
228
+ "guess": guess,
229
+ "result": result,
230
+ "outcome": "win" if win else "lose",
231
+ "earnings": earnings,
232
+ "commission": commission if win else 0,
233
+ }
234
+ )
235
 
236
  except WebSocketDisconnect:
237
  print("Disconnected")
 
239
  await websocket.send_json({"error": str(e)})
240
  await websocket.close()
241
 
242
+
243
  # ---------------------- Roulette ---------------------- #
244
 
245
+
246
  @app.websocket("/ws/roulette")
247
+ async def roulette(websocket: WebSocket):
248
+ await websocket.accept()
249
+ try:
250
+ # First message must be auth
251
+ auth = await websocket.receive_json()
252
+ username = auth.get("username")
253
+ password = auth.get("password")
254
+
255
+ if not username or not password or not verify_user(username, password):
256
+ await websocket.send_json({"error": "Invalid credentials"})
257
+ await websocket.close()
258
+ return
259
+
260
+ # Get updated balance on connect
261
+ balance = get_updated_glares(username)
262
+ await websocket.send_json({"message": f"Welcome {username}", "glares": balance})
263
+
264
+ while True:
265
+ data = await websocket.receive_json()
266
+ bet = data.get("bet")
267
+
268
+ total_bet = sum(int(v) for v in bet.values())
269
+ for n in bet.values():
270
+ if not isinstance(n, int) or n < 0:
271
+ await websocket.send_json({"error": "Invalid bet"})
272
+ continue
273
+
274
+ balance = get_updated_glares(username)
275
+ if total_bet > balance:
276
+ await websocket.send_json({"error": "Insufficient glares"})
277
+ continue
278
+
279
+ if total_bet <= 0:
280
+ await websocket.send_json({"error": "Invalid bet"})
281
+ continue
282
+
283
+ earnings = 0
284
+
285
+ chosen = secrets.choice(range(37))
286
+
287
+ if chosen == 0:
288
+ color = "green"
289
+ elif chosen in [
290
+ 1,
291
+ 3,
292
+ 5,
293
+ 7,
294
+ 9,
295
+ 12,
296
+ 14,
297
+ 16,
298
+ 18,
299
+ 19,
300
+ 21,
301
+ 23,
302
+ 25,
303
+ 27,
304
+ 30,
305
+ 32,
306
+ 34,
307
+ ]:
308
+ color = "red"
309
+ else:
310
+ color = "black"
311
+
312
+ even_odd = "even" if chosen % 2 == 0 else "odd"
313
+
314
+ if isinstance(bet, dict):
315
+ for number in range(37):
316
+ if str(number) in bet:
317
+ if (
318
+ not isinstance(bet[str(number)], int)
319
+ or bet[str(number)] <= 0
320
+ ):
321
+ await websocket.send_json({"error": "Invalid bet"})
322
+ continue
323
+ if number == chosen:
324
+ earnings += int(bet[str(number)]) * 35
325
+ else:
326
+ earnings -= int(bet[str(number)])
327
+
328
+ for col in ["red", "black"]:
329
+ if col in bet:
330
+ if not isinstance(bet[col], int) or bet[col] <= 0:
331
+ await websocket.send_json({"error": "Invalid bet"})
332
+ continue
333
+ if color == col:
334
+ earnings += int(bet[col])
335
+ else:
336
+ earnings -= int(bet[col])
337
+
338
+ for eo in ["even", "odd"]:
339
+ if eo in bet:
340
+ if not isinstance(bet[even_odd], int) or bet[even_odd] <= 0:
341
+ await websocket.send_json({"error": "Invalid bet"})
342
+ continue
343
+ if eo == even_odd:
344
+ earnings += int(bet[eo])
345
+ else:
346
+ earnings -= int(bet[eo])
347
+
348
+ for dozen in ["d1", "d2", "d3"]:
349
+ if dozen in bet:
350
+ if not isinstance(bet[dozen], int) or bet[dozen] <= 0:
351
+ await websocket.send_json({"error": "Invalid bet"})
352
+ continue
353
+ if chosen in range(1, 13) and dozen == "d1":
354
+ earnings += int(bet[dozen]) * 2
355
+ elif chosen in range(13, 25) and dozen == "d2":
356
+ earnings += int(bet[dozen]) * 2
357
+ elif chosen in range(25, 37) and dozen == "d3":
358
+ earnings += int(bet[dozen]) * 2
359
+ else:
360
+ earnings -= int(bet[dozen])
361
+
362
+ for column in ["c1", "c2", "c3"]:
363
+ if column in bet:
364
+ if not isinstance(bet[column], int) or bet[column] <= 0:
365
+ await websocket.send_json({"error": "Invalid bet"})
366
+ continue
367
+ if chosen in range(1, 37):
368
+ if column == "c1" and chosen % 3 == 1:
369
+ earnings += int(bet[column]) * 2
370
+ elif column == "c2" and chosen % 3 == 2:
371
+ earnings += int(bet[column]) * 2
372
+ elif column == "c3" and chosen % 3 == 0:
373
+ earnings += int(bet[column]) * 2
374
+ else:
375
+ earnings -= int(bet[column])
376
+ for half in ["h1", "h2"]:
377
+ if half in bet:
378
+ if not isinstance(bet[half], int) or bet[half] <= 0:
379
+ await websocket.send_json({"error": "Invalid bet"})
380
+ continue
381
+ if chosen in range(1, 19) and half == "h1":
382
+ earnings += int(bet[half])
383
+ elif chosen in range(19, 37) and half == "h2":
384
+ earnings += int(bet[half])
385
+ else:
386
+ earnings -= int(bet[half])
387
+ for street in [
388
+ "s1",
389
+ "s2",
390
+ "s3",
391
+ "s4",
392
+ "s5",
393
+ "s6",
394
+ "s7",
395
+ "s8",
396
+ "s9",
397
+ "s10",
398
+ "s11",
399
+ "s12",
400
+ ]:
401
+ if street in bet:
402
+ if not isinstance(bet[street], int) or bet[street] <= 0:
403
+ await websocket.send_json({"error": "Invalid bet"})
404
+ continue
405
+ if street == f"s{(chosen - 1) // 3 + 1}":
406
+ earnings += int(bet[street]) * 11
407
+ else:
408
+ earnings -= int(bet[street])
409
+
410
+ update_user_glares(username, earnings)
411
+ await websocket.send_json(
412
+ {
413
+ "chosen": chosen,
414
+ "color": color,
415
+ "even_odd": even_odd,
416
+ "earnings": earnings,
417
+ }
418
+ )
419
+
420
+ print(
421
+ f"Bet details: chosen={chosen}, color={color}, even_odd={even_odd}, earnings={earnings}"
422
+ )
423
+ else:
424
+ await websocket.send_json({"error": "Invalid bet"})
425
+ except WebSocketDisconnect:
426
+ print("Disconnected")
427
+ except Exception as e:
428
+ await websocket.send_json({"error": str(e)})
429
+ await websocket.close()
430
+
431
+
432
+ # ---------------------- Spinner ---------------------- #
433
+
434
+
435
+ @app.websocket("/ws/spinner")
436
+ async def spinner(websocket: WebSocket):
437
+ """Edge: 0.988%"""
438
+ await websocket.accept()
439
+ try:
440
+ # First message must be auth
441
+ auth = await websocket.receive_json()
442
+ username = auth.get("username")
443
+ password = auth.get("password")
444
+
445
+ if not username or not password or not verify_user(username, password):
446
+ await websocket.send_json({"error": "Invalid credentials"})
447
+ await websocket.close()
448
+ return
449
+
450
+ # Get updated balance on connect
451
+ balance = get_updated_glares(username)
452
+ await websocket.send_json({"message": f"Welcome {username}", "glares": balance})
453
+
454
+ while True:
455
+ data = await websocket.receive_json()
456
+ bet = data.get("bet")
457
+
458
+ probs = [0.3333, 0.4291, 0.2376]
459
+ mults = [0.0, 1.2, 2.0]
460
+
461
+ multiplier = weighted_choice(mults, probs)
462
+
463
+ print(type(bet), bet)
464
+ if not isinstance(bet, int) or bet <= 0:
465
+ await websocket.send_json({"error": "Invalid bet"})
466
+ continue
467
+
468
+ balance = get_updated_glares(username)
469
+ if bet > balance:
470
+ await websocket.send_json({"error": "Insufficient glares"})
471
+ continue
472
+
473
+ earnings = multiplier * bet - bet
474
+ update_user_glares(username, earnings)
475
+ await websocket.send_json({"multiplier": multiplier, "earnings": earnings})
476
+ except WebSocketDisconnect:
477
+ print("Disconnected")
478
+ except Exception as e:
479
+ await websocket.send_json({"error": str(e)})
480
+ await websocket.close()
481
+
482
+
483
+ # ---------------------- Crash ---------------------- #
484
+
485
+
486
+ @app.websocket("/ws/crash")
487
+ async def crash(websocket: WebSocket):
488
+ """Edge: 1%"""
489
+ await websocket.accept()
490
+ try:
491
+ # First message must be auth
492
+ auth = await websocket.receive_json()
493
+ username = auth.get("username")
494
+ password = auth.get("password")
495
+
496
+ if not username or not password or not verify_user(username, password):
497
+ await websocket.send_json({"error": "Invalid credentials"})
498
+ await websocket.close()
499
+ return
500
+
501
+ # Get updated balance on connect
502
+ balance = get_updated_glares(username)
503
+ await websocket.send_json({"message": f"Welcome {username}", "glares": balance})
504
+
505
+ while True:
506
+ data = await websocket.receive_json()
507
+ bet = data.get("bet")
508
+
509
+ if not isinstance(bet, int) or bet <= 0:
510
+ await websocket.send_json({"error": "Invalid bet"})
511
+ continue
512
+
513
+ balance = get_updated_glares(username)
514
+ if bet > balance:
515
+ await websocket.send_json({"error": "Insufficient glares"})
516
+ continue
517
+
518
+ update_user_glares(username, -bet)
519
+
520
+ crash_point = round(min(secure_crash_point(), 100), 2)
521
+
522
+ multiplier = 1.0
523
+ cashout = 0.0
524
+ crashed = False
525
+
526
+ async def send_updates():
527
+ nonlocal multiplier, crashed
528
+ while not crashed:
529
+ await asyncio.sleep(0.01) # 10ms
530
+ multiplier += multiplier * 0.00075
531
+ await websocket.send_json({"multiplier": round(multiplier, 2)})
532
+ if multiplier >= crash_point:
533
+ crashed = True
534
+ await websocket.send_json({"crash": crash_point})
535
+
536
+ async def receive_cashout():
537
+ nonlocal cashout, crashed
538
+ while not crashed:
539
+ try:
540
+ msg = await asyncio.wait_for(
541
+ websocket.receive_json(), timeout=0.01
542
+ )
543
+ if msg.get("action") == "cashout":
544
+ cashout = multiplier
545
+ crashed = True
546
+ await websocket.send_json({"cashed_out": round(cashout, 2)})
547
+ except asyncio.TimeoutError:
548
+ continue
549
+
550
+ await asyncio.gather(send_updates(), receive_cashout())
551
+
552
+ if cashout:
553
+ earned = cashout * bet
554
+ update_user_glares(username, earned)
555
+ await websocket.send_json(
556
+ {
557
+ "message": f"Cashout successful! Multiplier: {round(cashout, 2)}",
558
+ "earnings": round(earned, 2),
559
+ }
560
+ )
561
+ elif crashed:
562
+ await websocket.send_json(
563
+ {
564
+ "message": f"Game crashed at {round(crash_point, 2)}x! You lost your bet.",
565
+ "earnings": 0,
566
+ }
567
+ )
568
+
569
+ except WebSocketDisconnect:
570
+ print("Disconnected")
571
+ except Exception as e:
572
+ await websocket.send_json({"error": str(e)})
573
+ await websocket.close()
574
+
575
+
576
+ # ---------------------- Mines ---------------------- #
577
+
578
+
579
+ @app.websocket("/ws/mines")
580
+ async def mines(websocket: WebSocket):
581
+ """Edge: 1%"""
582
+ await websocket.accept()
583
+ try:
584
+ # First message must be auth
585
+ auth = await websocket.receive_json()
586
+ username = auth.get("username")
587
+ password = auth.get("password")
588
+
589
+ if not username or not password or not verify_user(username, password):
590
+ await websocket.send_json({"error": "Invalid credentials"})
591
+ await websocket.close()
592
+ return
593
+
594
+ # Get updated balance on connect
595
+ balance = get_updated_glares(username)
596
+ await websocket.send_json({"message": f"Welcome {username}", "glares": balance})
597
+
598
+ while True:
599
+ data = await websocket.receive_json()
600
+ bet = data.get("bet")
601
+ mines = data.get("mines", 1)
602
+
603
+ if not isinstance(bet, int) or bet <= 0:
604
+ await websocket.send_json({"error": "Invalid bet"})
605
+ continue
606
+
607
+ balance = get_updated_glares(username)
608
+ if bet > balance:
609
+ await websocket.send_json({"error": "Insufficient glares"})
610
+ continue
611
+
612
+ update_user_glares(username, -bet)
613
+
614
+ if mines < 1 or mines > 24 or not isinstance(mines, int):
615
+ await websocket.send_json({"error": "Invalid number of mines"})
616
+ continue
617
+
618
+ positions = secrets.SystemRandom().sample(range(0, 25), mines)
619
+ safe_positions = set(range(0, 25)) - set(positions)
620
+ revealed = set()
621
+ multiplier = 1.0
622
+
623
+ while True:
624
+ data = await websocket.receive_json()
625
+ action = data.get("action")
626
+
627
+ if action == "reveal":
628
+ position = data.get("position")
629
+ if not isinstance(position, int) or position < 0 or position > 24:
630
+ await websocket.send_json({"error": "Invalid position"})
631
+ continue
632
+ if position in revealed:
633
+ await websocket.send_json(
634
+ {"error": "Position already revealed"}
635
+ )
636
+ continue
637
+ if position not in safe_positions:
638
+ multiplier = 0
639
+ break
640
+ revealed.add(position)
641
+ multiplier += (
642
+ 25 / (len(safe_positions) - len(revealed)) - 1
643
+ ) * 0.99
644
+ safe_positions.remove(position)
645
+ await websocket.send_json(
646
+ {
647
+ "multiplier": round(multiplier, 2),
648
+ "revealed": list(revealed),
649
+ }
650
+ )
651
+ elif action == "cashout":
652
+ break
653
+ else:
654
+ await websocket.send_json({"error": "Invalid action"})
655
+ continue
656
+ earned = bet * multiplier
657
+ update_user_glares(username, earned)
658
+ await websocket.send_json(
659
+ {
660
+ "multiplier": round(multiplier, 2),
661
+ "earnings": round(earned, 2),
662
+ "safe_positions": list(safe_positions),
663
+ }
664
+ )
665
+
666
+ except WebSocketDisconnect:
667
+ print("Disconnected")
668
+ except Exception as e:
669
+ await websocket.send_json({"error": str(e)})
670
+ await websocket.close()
671
+
672
+
673
+ # ---------------------- Tower ---------------------- #
674
+
675
+
676
+ @app.websocket("/ws/tower")
677
+ async def tower(websocket: WebSocket):
678
+ """Edge: 1%"""
679
  await websocket.accept()
680
  try:
681
  # First message must be auth
 
694
 
695
  while True:
696
  data = await websocket.receive_json()
697
+ bet = data.get("bet")
698
+ # difficulty = data.get("difficulty", 1)
699
+ difficulty = 1
700
+ if difficulty not in [1, 2, 3]:
701
+ await websocket.send_json({"error": "Invalid difficulty"})
702
+ continue
703
+
704
+ if not isinstance(bet, int) or bet <= 0:
705
+ await websocket.send_json({"error": "Invalid bet"})
706
+ continue
707
+
708
+ balance = get_updated_glares(username)
709
+ if bet > balance:
710
+ await websocket.send_json({"error": "Insufficient glares"})
711
+ continue
712
+
713
+ update_user_glares(username, -bet)
714
+ safe_positions = list()
715
+ if difficulty == 1:
716
+ safe_positions = [secrets.randbelow(4) for _ in range(8)]
717
+
718
+ level = 0
719
+
720
+ multiplier = 1.0
721
+
722
+ while True:
723
+ data = await websocket.receive_json()
724
+ action = data.get("action")
725
+
726
+ if action == "reveal":
727
+ position = data.get("position")
728
+ if difficulty == 1:
729
+ if position not in [0, 1, 2, 3]:
730
+ await websocket.send_json({"error": "Invalid position"})
731
+ continue
732
+ if position in safe_positions:
733
+ level += 1
734
+ multiplier += 1 / 4 * 0.99
735
+ safe_positions.remove(position)
736
+ await websocket.send_json(
737
+ {
738
+ "level": level,
739
+ "multiplier": round(multiplier, 2),
740
+ }
741
+ )
742
+ else:
743
+ multiplier = 0
744
+ break
745
+
746
+ elif action == "cashout":
747
+ break
748
+ else:
749
+ await websocket.send_json({"error": "Invalid action"})
750
+ continue
751
+ earned = bet * multiplier
752
+ update_user_glares(username, earned)
753
+ await websocket.send_json(
754
+ {
755
+ "multiplier": round(multiplier, 2),
756
+ "earnings": round(earned, 2),
757
+ "safe_positions": safe_positions,
758
+ }
759
+ )
760
 
761
  except WebSocketDisconnect:
762
  print("Disconnected")
 
764
  await websocket.send_json({"error": str(e)})
765
  await websocket.close()
766
 
767
+
768
+ # ---------------------- Blackjack ---------------------- #
769
+
770
+
771
+ @app.websocket("/ws/blackjack")
772
+ async def blackjack(websocket: WebSocket):
773
+ """Edge: 1%"""
774
+ await websocket.accept()
775
+ try:
776
+ # First message must be auth
777
+ auth = await websocket.receive_json()
778
+ username = auth.get("username")
779
+ password = auth.get("password")
780
+
781
+ if not username or not password or not verify_user(username, password):
782
+ await websocket.send_json({"error": "Invalid credentials"})
783
+ await websocket.close()
784
+ return
785
+
786
+ # Get updated balance on connect
787
+ balance = get_updated_glares(username)
788
+ await websocket.send_json({"message": f"Welcome {username}", "glares": balance})
789
+
790
+ while True:
791
+ data = await websocket.receive_json()
792
+
793
+ bet = data.get("bet")
794
+ update_user_glares(username, -bet)
795
+
796
+ if not isinstance(bet, int) or bet <= 0:
797
+ await websocket.send_json({"error": "Invalid bet"})
798
+ continue
799
+
800
+ balance = get_updated_glares(username)
801
+ if bet > balance:
802
+ await websocket.send_json({"error": "Insufficient glares"})
803
+ continue
804
+
805
+ update_user_glares(username, -bet)
806
+ deck = [2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10, 11] * 4
807
+ secrets.SystemRandom().shuffle(deck)
808
+
809
+ done = False
810
+
811
+ earnings = 0
812
+
813
+ while True:
814
+ player_hand = [deck.pop(), deck.pop()]
815
+ dealer_hand = [deck.pop(), deck.pop()]
816
+
817
+ player_total = sum(player_hand)
818
+ dealer_total = sum(dealer_hand)
819
+
820
+ if player_total == 21:
821
+ done = True
822
+ earnings = bet * 1.5 + bet
823
+ break
824
+
825
+ while True:
826
+ action = await websocket.receive_json()
827
+ if action.get("action") == "hit":
828
+ player_hand.append(deck.pop())
829
+ player_total = sum(player_hand)
830
+ if player_total > 21:
831
+ done = True
832
+ earnings = 0
833
+ break
834
+ await websocket.send_json(
835
+ {"player_hand": player_hand, "player_total": player_total}
836
+ )
837
+ elif action.get("action") == "stand":
838
+ break
839
+ else:
840
+ await websocket.send_json({"error": "Invalid action"})
841
+ continue
842
+ if done:
843
+ break
844
+ while dealer_total < 17:
845
+ dealer_hand.append(deck.pop())
846
+ dealer_total = sum(dealer_hand)
847
+ if dealer_total > 21:
848
+ done = True
849
+ earnings = bet * 1 + bet
850
+ break
851
+ if done:
852
+ break
853
+ if player_total > dealer_total:
854
+ earnings = bet * 1 + bet
855
+ done = True
856
+ elif player_total < dealer_total:
857
+ earnings = 0
858
+ done = True
859
+ else:
860
+ earnings = bet
861
+ done = True
862
+ await websocket.send_json(
863
+ {
864
+ "player_hand": player_hand,
865
+ "player_total": player_total,
866
+ "dealer_hand": dealer_hand,
867
+ "dealer_total": dealer_total,
868
+ "earnings": earnings,
869
+ }
870
+ )
871
+ except WebSocketDisconnect:
872
+ print("Disconnected")
873
+ except Exception as e:
874
+ await websocket.send_json({"error": str(e)})
875
+ await websocket.close()
876
+
877
+
878
+ # ---------------------- Hi-Lo ---------------------- #
879
+
880
+
881
+ @app.websocket("/ws/hilo")
882
+ async def hilo(websocket: WebSocket):
883
+ """Edge: 1%"""
884
+ await websocket.accept()
885
+ try:
886
+ # First message must be auth
887
+ auth = await websocket.receive_json()
888
+ username = auth.get("username")
889
+ password = auth.get("password")
890
+
891
+ if not username or not password or not verify_user(username, password):
892
+ await websocket.send_json({"error": "Invalid credentials"})
893
+ await websocket.close()
894
+ return
895
+
896
+ # Get updated balance on connect
897
+ balance = get_updated_glares(username)
898
+ await websocket.send_json({"message": f"Welcome {username}", "glares": balance})
899
+
900
+ while True:
901
+ data = await websocket.receive_json()
902
+ bet = data.get("bet")
903
+
904
+ if not isinstance(bet, int) or bet <= 0:
905
+ await websocket.send_json({"error": "Invalid bet"})
906
+ continue
907
+
908
+ balance = get_updated_glares(username)
909
+ if bet > balance:
910
+ await websocket.send_json({"error": "Insufficient glares"})
911
+ continue
912
+
913
+ update_user_glares(username, -bet)
914
+
915
+ cards = list(range(1, 53))
916
+ secrets.SystemRandom().shuffle(cards)
917
+
918
+ card = cards.pop()
919
+ card_value = card % 13
920
+ if card_value == 0:
921
+ card_value = 13
922
+
923
+ multiplier = 1.0
924
+
925
+ while True:
926
+ action = await websocket.receive_json()
927
+ if action.get("action") == "higher":
928
+ next_card = cards.pop()
929
+
930
+ next_card_value = next_card % 13
931
+
932
+ if next_card_value == 0:
933
+ next_card_value = 13
934
+
935
+ if next_card_value == card_value == 1: # Ace
936
+ multiplier = 0
937
+ break
938
+
939
+ if next_card_value >= card_value:
940
+ multiplier += (14 - card_value) / 12 * 0.99
941
+ else:
942
+ multiplier = 0
943
+ break
944
+ elif action.get("action") == "lower":
945
+ next_card = cards.pop()
946
+
947
+ next_card_value = next_card % 13
948
+
949
+ if next_card_value == card_value == 0: # King
950
+ multiplier = 0
951
+ break
952
+
953
+ if next_card_value <= card_value:
954
+ multiplier += (card_value) / 12 * 0.99
955
+ else:
956
+ multiplier = 0
957
+ break
958
+ elif action.get("action") == "skip":
959
+ next_card = cards.pop()
960
+ elif action.get("action") == "cashout":
961
+ break
962
+ else:
963
+ await websocket.send_json({"error": "Invalid action"})
964
+ continue
965
+
966
+ earnings = bet * multiplier
967
+ update_user_glares(username, earnings)
968
+ await websocket.send_json(
969
+ {"earnings": round(earnings, 2), "multiplier": round(multiplier, 2)}
970
+ )
971
+ except WebSocketDisconnect:
972
+ print("Disconnected")
973
+ except Exception as e:
974
+ await websocket.send_json({"error": str(e)})
975
+ await websocket.close()
976
+
977
+
978
+ # ---------------------- Main ---------------------- #
979
+
980
+
981
  if __name__ == "__main__":
982
  import uvicorn
983
+
984
  uvicorn.run("app:app", host="0.0.0.0", port=7860, reload=False)
requirements.txt CHANGED
@@ -1,4 +1,7 @@
1
  fastapi
2
  uvicorn
3
  argon2-cffi
4
- python-multipart
 
 
 
 
1
  fastapi
2
  uvicorn
3
  argon2-cffi
4
+ python-multipart
5
+ websockets
6
+ aiohttp
7
+ pydantic