data-analytics/data-dash/webapp/main.py (84 lines of code) (raw):

#!/usr/bin/python # Copyright 2024 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import os import eventlet import time from datetime import datetime import google.cloud.bigtable.row_filters as row_filters from flask import Flask, render_template from flask_cors import CORS from flask_socketio import SocketIO from google.cloud import bigtable async_mode = "eventlet" app = Flask(__name__) CORS(app, resources={r"/*": {"origins": "*"}}) socketio = SocketIO(app, async_mode=async_mode, cors_allowed_origins="*") DEFAULT_ID = 999999999999 OK = 0 WIN = 1 LOSE = 2 DONE = 3 project_id = os.environ["PROJECT_ID"] instance_id = "data-dash" table_id = "races" client = bigtable.Client(project=project_id) instance = client.instance(instance_id) table = instance.table(table_id) column_family_id = "cf" def get_data(track_id): # get_track_data returns the data for the last race on a track data = {} _r = table.read_rows( filter_=row_filters.RowKeyRegexFilter(bytes(f"^track{track_id}#.*", "utf-8")), limit=1, ) # Expand Bigtable read to a reusable object row = None for _ in _r: row = _ data["car_id"] = row.cells["cf"][b"car_id"][0].value.decode("utf-8") data["timestamp"] = datetime.timestamp(row.cells["cf"][b"car_id"][0].timestamp) col_strf = "t{i}_s" checkpoints = {} for i in range(1, 9): col_name = bytes(col_strf.format(i=i), "utf-8") col = row.cells["cf"].get(col_name) checkpoints[str(i)] = float(col[0].value.decode("utf-8")) if col else None data["checkpoints"] = checkpoints data["status"] = DONE if checkpoints.get("8") else OK return data def background_thread(): while True: socketio.sleep(1) lt = time.time() print("GETTING LEFT DATA") left_data = get_data(1) print(f"RECEIVED LEFT DATA AFTER {time.time() - lt} SECONDS") rt = time.time() print("GETTING RIGHT DATA") right_data = get_data(2) print(f"RECEIVED RIGHT DATA AFTER {time.time() - rt} SECONDS") # Determine if there's a winner if left_data["status"] == DONE and right_data["status"] == DONE: if left_data["checkpoints"]["8"] < right_data["checkpoints"]["8"]: left_data["status"] = WIN right_data["status"] = LOSE else: right_data["status"] = WIN left_data["status"] = LOSE elif left_data["status"] == DONE: left_data["status"] = WIN right_data["status"] = LOSE elif right_data["status"] == DONE: right_data["status"] = WIN left_data["status"] = LOSE print("EMITTING DATA") socketio.emit("send_data", {"left": left_data, "right": right_data}) print("DATA EMITTED") @app.route("/") def index(): return render_template("index.html", async_mode=socketio.async_mode) @socketio.on('connect') def connect(): socketio.start_background_task(background_thread) print('connecting') socketio.emit( "set_default", {"left_id": f"{DEFAULT_ID}", "right_id": f"{DEFAULT_ID}"} ) if __name__ == "__main__": socketio.run(app, host="0.0.0.0", port=int(os.environ.get("PORT", 8080)))