From e41caa70aa7ea0c59bd57bd59e086bd3d0f0fcb1 Mon Sep 17 00:00:00 2001
From: Reece Williams <31943163+Reecepbcups@users.noreply.github.com>
Date: Wed, 25 Jan 2023 22:37:46 -0600
Subject: [PATCH] Cleanup rewrite (#2)
* cache time, replace_rpc_text func, get settings endpoint
* moves to its own config
* cleanup
* auto set RPC from receiving domain base URL
* better cache_times json
* Disable endpoint,
* REST to config
* rest helper funcs, no RPC favicon
* remove old script
* cleanup rest setup guide
* cleanup comments
* before_first_request for wsgi
* .env
* cleanup cache times
---
.env | 36 ++--
CONFIG.py | 77 +++++++
HELPERS.py | 93 +++++++++
README.md | 7 +-
cache_times.json | 35 ++--
rest.py | 86 ++++++++
rest/rest.py | 136 -------------
rest/run_rest.sh | 33 ---
rpc.py | 189 ++++++++----------
run_rest.sh | 40 ++++
run_rpc.sh | 34 +++-
scripts/pain.sh | 8 -
{rest/static => static}/openapi.yml | 0
.../favicon.png => static/rest-favicon.png | Bin
todo.txt | 2 +-
15 files changed, 439 insertions(+), 337 deletions(-)
create mode 100644 CONFIG.py
create mode 100644 HELPERS.py
create mode 100644 rest.py
delete mode 100644 rest/rest.py
delete mode 100755 rest/run_rest.sh
create mode 100755 run_rest.sh
delete mode 100644 scripts/pain.sh
rename {rest/static => static}/openapi.yml (100%)
rename rest/static/favicon.png => static/rest-favicon.png (100%)
diff --git a/.env b/.env
index 43e1ee5..bf874a3 100644
--- a/.env
+++ b/.env
@@ -1,5 +1,8 @@
-# .env file
-#
+# === APPLICATION PORTS ===
+# you also need to update run_rest.sh and run_rpc.sh to these values if you change :)
+REST_PORT=5000
+RPC_PORT=5001
+
# === REDIS ===
# change 127.0.0.1 to the address or name of docker service
REDIS_URL=redis://127.0.0.1:6379/0
@@ -13,35 +16,20 @@ INCREASE_COUNTER_EVERY=25
# ====================================
# = RPCS & REST ENDPOINTS (TO QUERY) =
# ====================================
-RPC_URL="http://localhost:26657"
+# Note: These can be localhost if you wish to run on the node itself
+RPC_URL="http://15.204.143.232:26657"
BACKUP_RPC_URL="https://rpc.juno.strange.love"
-# REST_URL="http://15.204.143.232:1317"
-REST_URL="http://localhost:1317"
-BACKUP_REST_URL="https://api.juno.strange.love" # TODO
-
-# ====================================
-# = RPCS & REST ENDPOINTS (COSMETIC) =
-# ====================================
-# Basically remove non required ports (80/443) & no http(s)://
-# This repalces the RPCs HTML to match out endpoints on click
-BASE_RPC="localhost:26657"
-BACKUP_BASE_RPC="rpc.juno.strange.love"
+REST_URL="http://15.204.143.232:1317"
+BACKUP_REST_URL="https://api.juno.strange.love"
-# What your A record + domain is ( where the user goes without and ports or http(s):// )
-RPC_DOMAIN="juno-rpc.reece.sh"
+# === WEBSOCKET ===
+RPC_WEBSOCKET="15.204.143.232:26657"
-# === WEBSOCKETS ===
-WEBSOCKET_ADDR="15.204.143.232:26657"
-# BACKUP_WEBSOCKET_ADDR="rpc.juno.strange.love:443" ??
-# === APPLICATION PORTS ===
-# you also need to update run_rest.sh and run_rpc.sh to these values if you change :)
-REST_PORT=5000
-RPC_PORT=5001
# === Cosmetic ===
-API_TITLE="Juno Network API"
RPC_TITLE="Juno Network RPC"
+API_TITLE="Juno Network REST API"
RPC_CUSTOM_TEXT='Custom caching solution active for {RPC_DOMAIN} My Juno REST API '
\ No newline at end of file
diff --git a/CONFIG.py b/CONFIG.py
new file mode 100644
index 0000000..169fa7b
--- /dev/null
+++ b/CONFIG.py
@@ -0,0 +1,77 @@
+import json
+import os
+import re
+from os import getenv
+
+import redis
+from dotenv import load_dotenv
+
+CURRENT_DIR = os.path.dirname(os.path.realpath(__file__))
+
+load_dotenv(os.path.join(CURRENT_DIR, ".env"))
+
+# =============
+# === REDIS ===
+# =============
+REDIS_URL = getenv("REDIS_URL", "redis://127.0.0.1:6379/0")
+REDIS_DB = redis.Redis.from_url(REDIS_URL)
+
+ENABLE_COUNTER = getenv("ENABLE_COUNTER", "true").lower().startswith("t")
+INC_EVERY = int(getenv("INCREASE_COUNTER_EVERY", 10))
+
+# ===========
+# === RPC ===
+# ===========
+RPC_PORT = int(getenv("RPC_PORT", 5001))
+RPC_PREFIX = getenv("REDIS_RPC_PREFIX", "junorpc")
+RPC_URL = getenv("RPC_URL", "https://juno-rpc.reece.sh:443")
+
+BACKUP_RPC_URL = getenv("BACKUP_RPC_URL", "https://rpc.juno.strange.love:443")
+
+RPC_WEBSOCKET = f'ws://{getenv("WEBSOCKET_ADDR", "15.204.143.232:26657")}/websocket'
+
+RPC_DOMAIN = getenv("RPC_DOMAIN", "localhost:5001")
+
+# ============
+# === REST ===
+# ============
+REST_PORT = int(getenv("REST_PORT", 5000))
+
+API_TITLE = getenv("API_TITLE", "Swagger API")
+REST_PREFIX = getenv("REDIS_REST_PREFIX", "junorest")
+
+REST_URL = getenv("REST_URL", "https://juno-rest.reece.sh")
+BACKUP_REST_URL = getenv("BACKUP_REST_URL", f"https://api.juno.strange.love")
+
+OPEN_API = f"{REST_URL}/static/openapi.yml"
+
+# === Cache Times ===
+cache_times: dict = {}
+DEFAULT_CACHE_SECONDS: int = 6
+RPC_ENDPOINTS: dict = {}
+REST_ENDPOINTS: dict = {}
+
+# === CACHE HELPER ===
+def update_cache_times():
+ """
+ Updates any config variables which can be changed without restarting the server.
+ Useful for the /cache_info endpoint & actually applying said cache changes at any time
+ """
+ global cache_times, DEFAULT_CACHE_SECONDS, RPC_ENDPOINTS, REST_ENDPOINTS
+
+ with open(os.path.join(CURRENT_DIR, "cache_times.json"), "r") as f:
+ cache_times = json.loads(f.read())
+
+ DEFAULT_CACHE_SECONDS = cache_times.get("DEFAULT", 6)
+ RPC_ENDPOINTS = cache_times.get("rpc", {})
+ REST_ENDPOINTS = cache_times.get("rest", {})
+
+
+def get_cache_time_seconds(path: str, is_rpc: bool) -> int:
+ endpoints = RPC_ENDPOINTS if is_rpc else REST_ENDPOINTS
+
+ for k, seconds in endpoints.items():
+ if re.match(k, path):
+ return seconds
+
+ return DEFAULT_CACHE_SECONDS
diff --git a/HELPERS.py b/HELPERS.py
new file mode 100644
index 0000000..4f09b3a
--- /dev/null
+++ b/HELPERS.py
@@ -0,0 +1,93 @@
+import re
+from os import getenv
+
+import requests
+
+import CONFIG
+from CONFIG import REDIS_DB
+
+total_calls = {
+ # RPC:
+ "total_cache;get_rpc_endpoint": 0,
+ "total_outbound;get_rpc_endpoint": 0,
+ # RPC Cache:
+ "total_cache;post_endpoint": 0,
+ "total_outbound;post_endpoint": 0,
+ # REST:
+ "total_cache;get_all_rest": 0,
+ "total_outbound;get_all_rest": 0,
+}
+
+
+def increment_call_value(key):
+ global total_calls
+
+ if CONFIG.ENABLE_COUNTER == False:
+ return
+
+ if key not in total_calls:
+ total_calls[key] = 0
+
+ if total_calls[key] >= CONFIG.INC_EVERY:
+ REDIS_DB.incr(f"{CONFIG.RPC_PREFIX};{key}", amount=total_calls[key])
+ total_calls[key] = 0
+ else:
+ total_calls[key] += 1
+
+
+def download_openapi_locally():
+ r = requests.get(CONFIG.OPEN_API)
+ file_loc = f"{CONFIG.CURRENT_DIR}/static/openapi.yml"
+ with open(file_loc, "w") as f:
+ f.write(r.text)
+
+
+def get_swagger_code_from_source():
+ req = requests.get(f"{CONFIG.REST_URL}")
+
+ html = req.text.replace(
+ "//unpkg.com/swagger-ui-dist@3.40.0/favicon-16x16.png",
+ "/static/rest-favicon.png",
+ )
+ html = re.sub(r"
.*", f"{CONFIG.API_TITLE}", html)
+ return html
+
+
+def replace_rpc_text() -> str:
+ # we replace after on requests of the user, then repalce this text to our cache endpoint at time of requests to root endpoint
+ try:
+ RPC_ROOT_HTML = requests.get(f"{CONFIG.RPC_URL}/").text
+ except:
+ RPC_ROOT_HTML = requests.get(f"{CONFIG.BACKUP_RPC_URL}/").text
+
+ RPC_TITLE = getenv("RPC_TITLE", "")
+ if len(RPC_TITLE) > 0:
+ RPC_ROOT_HTML = RPC_ROOT_HTML.replace(
+ "",
+ f"{RPC_TITLE}",
+ )
+
+ # Puts text at the bottom, maybe put at the top in the future?
+ RPC_CUSTOM_TEXT = getenv("RPC_CUSTOM_TEXT", "").replace(
+ "{RPC_DOMAIN}", f"{CONFIG.RPC_DOMAIN}"
+ )
+ if len(RPC_CUSTOM_TEXT) > 0:
+ RPC_ROOT_HTML = RPC_ROOT_HTML.replace(
+ "Available endpoints: