mirror of
https://github.com/pezkuwichain/pezkuwi-subquery.git
synced 2026-10-20 18:56:24 +00:00
Move vulnerable dependencies to patched versions; drop the Nova scripts
yarn.lock: transitive bumps within declared ranges for @babel/core, ajv, axios (1.x), bn.js, body-parser, brace-expansion, browserslist, defu, dottie, fast-uri, flatted, follow-redirects, form-data, h3, handlebars, ip-address, js-yaml, lodash, minimatch, moment, path-to-regexp, picomatch, qs, simple-git, tar, ws, yaml and @modelcontextprotocol/sdk where in range. noter/package-lock.json: bn.js 5.2.2 -> 5.2.5, ws 8.19.0 -> 8.22.0. scripts/python_scripts and scripts/update_projects_description.sh are removed rather than patched (27 alerts on requirements.txt). They came in with the initial commit from the Nova project and were never changed: they call SubQuery's managed service (api.subquery.network) and write descriptions for the "nova-wallet" organisation. Nothing in CI, package.json or the other scripts calls them, and our indexers are self-hosted. Left for upstream SubQuery releases, all build/codegen tooling rather than the indexer runtime: axios 0.27 via @subql/network-clients, ws 8.18 and elliptic via its ethers 5, serialize-javascript 6 via terser-webpack-plugin, uuid 8 via @subql/x-sequelize, tmp via @inquirer/editor, got 9 via update-notifier. Checked: yarn install --immutable; subql codegen and build succeed for pezkuwi.yaml, pezkuwi-assethub.yaml and pezkuwi-governance.yaml.
This commit is contained in:
1 parent
22f0a6a087
commit
1268180634
11 files changed
+389
-835
No files matched your search
Generated
+6
-6
@@ -649,9 +649,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/bn.js": {
|
"node_modules/bn.js": {
|
||||||
"version": "5.2.2",
|
"version": "5.2.5",
|
||||||
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.5.tgz",
|
||||||
"integrity": "sha512-v2YAxEmKaBLahNwE1mjp4WON6huMNeuDvagFZW+ASCuA/ku0bXR9hSMw0XpiqMoA3+rmnyck/tPRSFQkoC9Cuw==",
|
"integrity": "sha512-Vq886eXykuP5E6HcKSSStP3bJgrE6In5WKxVUvJ8XGpWWYs2xZHWqUwzCtGgEtBcxyd57KBFDPFoUfNzdaHCNg==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/data-uri-to-buffer": {
|
"node_modules/data-uri-to-buffer": {
|
||||||
@@ -844,9 +844,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/ws": {
|
"node_modules/ws": {
|
||||||
"version": "8.19.0",
|
"version": "8.22.0",
|
||||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz",
|
"resolved": "https://registry.npmjs.org/ws/-/ws-8.22.0.tgz",
|
||||||
"integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==",
|
"integrity": "sha512-Ydggc987+RO0AnWtZ/7Wq9FtNvcrL1b/RO0ud9mWjUPgDrsAAwQSF51sm2hm1XofbU/4jkpGEsLFsZZxU+1DOg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=10.0.0"
|
"node": ">=10.0.0"
|
||||||
|
|||||||
@@ -1,58 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
|
|
||||||
import os
|
|
||||||
|
|
||||||
from jinja2 import Template
|
|
||||||
|
|
||||||
from table_representation import ProjectTableGenerator
|
|
||||||
from subquery_api import SubQueryDeploymentAPI
|
|
||||||
from telegram_notifications import TelegramNotifications
|
|
||||||
|
|
||||||
token = os.getenv("SUBQUERY_TOKEN")
|
|
||||||
organisation = "nova-wallet"
|
|
||||||
nova_network_list = "https://raw.githubusercontent.com/nova-wallet/nova-utils/master/chains/v11/chains_dev.json"
|
|
||||||
|
|
||||||
readme = Template("""
|
|
||||||
Projects' status is updated every 4 hours
|
|
||||||
|
|
||||||
SubQuery API data sources are grouped based on the following features:
|
|
||||||
|
|
||||||
📚 Operation History - Transfers and Extrinsics for Utility (main) token of the network <br />
|
|
||||||
✨ Multi-asset transfers - Support for transfer history for tokens from ORML and Assets pallets <br />
|
|
||||||
🥞 Staking rewards - Rewards history and accumulated total rewards, supports both Staking and ParachainStaking pallets <br />
|
|
||||||
📈 Staking analytics - Queries for current stake, validators statistics, and stake change history
|
|
||||||
|
|
||||||
# List of deployed projects
|
|
||||||
|
|
||||||
{{dapps_table}}
|
|
||||||
""")
|
|
||||||
|
|
||||||
|
|
||||||
def generate_project_table():
|
|
||||||
sub_query = SubQueryDeploymentAPI(auth_token=token, org=organisation)
|
|
||||||
sub_query.collect_all_project_data()
|
|
||||||
|
|
||||||
table_generator = ProjectTableGenerator(sub_query, nova_network_list)
|
|
||||||
table = table_generator.generate_table()
|
|
||||||
|
|
||||||
return table
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
|
|
||||||
dir_name = 'gh-pages-temp'
|
|
||||||
|
|
||||||
telegram = TelegramNotifications()
|
|
||||||
try:
|
|
||||||
os.makedirs(dir_name)
|
|
||||||
print("Directory ", dir_name, " Created ")
|
|
||||||
except FileExistsError:
|
|
||||||
print("Directory ", dir_name, " already exists")
|
|
||||||
|
|
||||||
with open("./gh-pages-temp/README.md", "w") as f:
|
|
||||||
f.write(readme.render(
|
|
||||||
dapps_table=generate_project_table()
|
|
||||||
))
|
|
||||||
|
|
||||||
# TODO: Temp remove, waiting for https://app.clickup.com/t/862kc4b47
|
|
||||||
# telegram.send_notification()
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
anyio==3.6.2
|
|
||||||
attrs==22.2.0
|
|
||||||
certifi==2022.12.7
|
|
||||||
chardet==5.1.0
|
|
||||||
charset-normalizer==3.0.1
|
|
||||||
DataProperty==0.55.0
|
|
||||||
exceptiongroup==1.1.0
|
|
||||||
h11==0.14.0
|
|
||||||
httpcore==0.16.3
|
|
||||||
httpx==0.23.3
|
|
||||||
idna==3.4
|
|
||||||
iniconfig==2.0.0
|
|
||||||
Jinja2==3.1.2
|
|
||||||
MarkupSafe==2.1.2
|
|
||||||
mbstrdecoder==1.1.1
|
|
||||||
packaging==23.0
|
|
||||||
pathvalidate==2.5.2
|
|
||||||
pluggy==1.0.0
|
|
||||||
pytablewriter==0.64.2
|
|
||||||
pytest==7.2.1
|
|
||||||
python-dateutil==2.8.2
|
|
||||||
python-telegram-bot==20.0
|
|
||||||
pytz==2022.7.1
|
|
||||||
PyYAML==6.0
|
|
||||||
requests==2.28.2
|
|
||||||
rfc3986==1.5.0
|
|
||||||
six==1.16.0
|
|
||||||
sniffio==1.3.0
|
|
||||||
tabledata==1.3.0
|
|
||||||
tcolorpy==0.1.2
|
|
||||||
tomli==2.0.1
|
|
||||||
typepy==1.3.0
|
|
||||||
urllib3==1.26.14
|
|
||||||
wget==3.2
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
class Singleton(type):
|
|
||||||
_instances = {}
|
|
||||||
def __call__(cls, *args, **kwargs):
|
|
||||||
if cls not in cls._instances:
|
|
||||||
cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
|
|
||||||
return cls._instances[cls]
|
|
||||||
@@ -1,158 +0,0 @@
|
|||||||
from typing import List
|
|
||||||
from datetime import datetime, timedelta
|
|
||||||
import re
|
|
||||||
import requests
|
|
||||||
|
|
||||||
|
|
||||||
class DeploymentInstance():
|
|
||||||
|
|
||||||
def __init__(self, **kwargs) -> None:
|
|
||||||
self.id = kwargs['id']
|
|
||||||
self.project_key = kwargs['projectKey']
|
|
||||||
self.version = kwargs['version']
|
|
||||||
self.status = kwargs['status']
|
|
||||||
self.type = kwargs['type']
|
|
||||||
self.configuration = kwargs['configuration']
|
|
||||||
|
|
||||||
|
|
||||||
class SubQueryProject():
|
|
||||||
|
|
||||||
def __init__(self, **kwargs) -> None:
|
|
||||||
self.id = kwargs['id']
|
|
||||||
self.key = kwargs['key']
|
|
||||||
self.name = kwargs['name']
|
|
||||||
self.network = kwargs['network']
|
|
||||||
self.metadata = kwargs['metadata']
|
|
||||||
self.query_url = kwargs['queryUrl']
|
|
||||||
self.deployments: List[DeploymentInstance] = []
|
|
||||||
|
|
||||||
deployments = kwargs.get('deployments')
|
|
||||||
if deployments:
|
|
||||||
for deployment in deployments:
|
|
||||||
self.deployments.append(DeploymentInstance(**deployment))
|
|
||||||
|
|
||||||
|
|
||||||
class SubQueryDeploymentAPI():
|
|
||||||
|
|
||||||
base_url = "https://api.subquery.network"
|
|
||||||
|
|
||||||
def __init__(self, auth_token, org) -> None:
|
|
||||||
self.org = org
|
|
||||||
self.headers = {
|
|
||||||
'authority': 'api.subquery.network',
|
|
||||||
'accept': 'application/json, text/plain, */*',
|
|
||||||
'accept-language': 'en-GB,en-US;q=0.9,en;q=0.8,ru;q=0.7',
|
|
||||||
'origin': 'https://managedservice.subquery.network',
|
|
||||||
'sec-ch-ua': '"Chromium";v="112", "Google Chrome";v="112", "Not:A-Brand";v="99"',
|
|
||||||
'sec-ch-ua-mobile': '?0',
|
|
||||||
'sec-ch-ua-platform': '"macOS"',
|
|
||||||
'sec-fetch-dest': 'empty',
|
|
||||||
'sec-fetch-mode': 'cors',
|
|
||||||
'sec-fetch-site': 'same-site',
|
|
||||||
'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36',
|
|
||||||
'Authorization': f'Bearer {auth_token}',
|
|
||||||
}
|
|
||||||
|
|
||||||
def _send_request(self, method, path, payload=None):
|
|
||||||
try:
|
|
||||||
response = requests.request(
|
|
||||||
method, self.base_url + path, headers=self.headers, data=payload)
|
|
||||||
if response.status_code == 401:
|
|
||||||
raise Exception(f"Unautorised:\n{response}")
|
|
||||||
|
|
||||||
return response
|
|
||||||
except Exception as e:
|
|
||||||
raise Exception(
|
|
||||||
f"Can't request to: {path} by method: {method} and payload: {payload} \nException: {e}")
|
|
||||||
|
|
||||||
def collect_all_project_data(self) -> List[SubQueryProject]:
|
|
||||||
self.get_all_projects_for_organisation()
|
|
||||||
print(
|
|
||||||
f"Organisation: {self.org}\nHas {len(self.org_projects)} projects")
|
|
||||||
print(f"Process of getting deployments have been started.")
|
|
||||||
for project in self.org_projects:
|
|
||||||
self.get_deployments_for_project(project)
|
|
||||||
print(
|
|
||||||
f"Project: {project.network} received: {len(project.deployments)} deployments.")
|
|
||||||
for deployment in project.deployments:
|
|
||||||
self.get_sync_status_for_deployment(deployment)
|
|
||||||
print(
|
|
||||||
f"Deployment for {project.network} status: {deployment.sync_status}, env: {deployment.type}")
|
|
||||||
|
|
||||||
return self.org_projects
|
|
||||||
|
|
||||||
def get_all_projects_for_organisation(self) -> List[SubQueryProject]:
|
|
||||||
projects = self._send_request(
|
|
||||||
method="GET", path=f"/user/projects?account={self.org}").json()
|
|
||||||
|
|
||||||
self.org_projects = [SubQueryProject(**project) for project in projects]
|
|
||||||
|
|
||||||
return self.org_projects
|
|
||||||
|
|
||||||
def get_sync_status_for_deployment(self, deployment: DeploymentInstance) -> DeploymentInstance:
|
|
||||||
if len(self.org_projects) == 0:
|
|
||||||
print("org_projects is empty, use get_all_projects_for_organisation first")
|
|
||||||
|
|
||||||
sync_status = self._send_request(
|
|
||||||
method="GET",
|
|
||||||
path=f"/v3/subqueries/{deployment.project_key}/deployments/{deployment.id}/sync-status"
|
|
||||||
).json()
|
|
||||||
if len(sync_status['networks']) == 0:
|
|
||||||
deployment.__setattr__('sync_status', None)
|
|
||||||
return deployment
|
|
||||||
deployment.__setattr__('sync_status', sync_status['networks'][0])
|
|
||||||
|
|
||||||
return deployment
|
|
||||||
|
|
||||||
def get_deployments_for_project(self, project: SubQueryProject) -> List[DeploymentInstance]:
|
|
||||||
if len(self.org_projects) == 0:
|
|
||||||
print("org_projects is empty, use get_all_projects_for_organisation first")
|
|
||||||
|
|
||||||
deployments = self._send_request(
|
|
||||||
method="GET",
|
|
||||||
path=f"/subqueries/{project.key}/deployments"
|
|
||||||
).json()
|
|
||||||
|
|
||||||
project.deployments = [DeploymentInstance(**deployment) for deployment in deployments]
|
|
||||||
|
|
||||||
return project.deployments
|
|
||||||
|
|
||||||
def find_project_by_parameter(self, parameter_name, parameter_value):
|
|
||||||
found_project = [project for project in self.org_projects if project.__getattribute__(
|
|
||||||
parameter_name) == parameter_value]
|
|
||||||
if found_project:
|
|
||||||
print("Project found")
|
|
||||||
for obj in found_project:
|
|
||||||
return obj
|
|
||||||
else:
|
|
||||||
print("Project not found.")
|
|
||||||
|
|
||||||
def get_logs(self, project_name: str, sid: str, level: str = 'info', stage: bool = False):
|
|
||||||
params = {
|
|
||||||
'level': level,
|
|
||||||
'stage': str(stage).lower(),
|
|
||||||
'sid': sid
|
|
||||||
}
|
|
||||||
|
|
||||||
response = self._send_request(method="GET", path=f'/v3/subqueries/{project_name}/logs')
|
|
||||||
|
|
||||||
if response.status_code == 200:
|
|
||||||
return response.json()
|
|
||||||
else:
|
|
||||||
response.raise_for_status()
|
|
||||||
|
|
||||||
def parse_logs(self, logs):
|
|
||||||
for log in logs['result']:
|
|
||||||
message = log.get('message')
|
|
||||||
timestamp = log.get('timestamp')
|
|
||||||
if message and 'Target height' in message and 'Current height' in message:
|
|
||||||
log_time = datetime.strptime(timestamp, '%Y-%m-%dT%H:%M:%S.%fZ')
|
|
||||||
if datetime.utcnow() - log_time <= timedelta(hours=1):
|
|
||||||
target_height = re.search('Target height: ([\d,]+)', message).group(1)
|
|
||||||
current_height = re.search('Current height: ([\d,]+)', message).group(1)
|
|
||||||
# Remove commas from the numbers
|
|
||||||
target_height = int(target_height.replace(',', ''))
|
|
||||||
current_height = int(current_height.replace(',', ''))
|
|
||||||
return target_height, current_height
|
|
||||||
return None, None
|
|
||||||
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
import subprocess
|
|
||||||
import wget
|
|
||||||
import os
|
|
||||||
import zipfile
|
|
||||||
import os
|
|
||||||
import platform
|
|
||||||
|
|
||||||
def get_subquery_cli(subquery_cli_version):
|
|
||||||
|
|
||||||
download_url = "https://github.com/fewensa/subquery-cli/releases/download/v" + subquery_cli_version
|
|
||||||
temporary_path = "./temporary"
|
|
||||||
|
|
||||||
current_platform = platform.system()
|
|
||||||
|
|
||||||
if current_platform == "Linux":
|
|
||||||
download_url += "/subquery-linux-x86_64.zip"
|
|
||||||
elif current_platform == "Darwin":
|
|
||||||
download_url += "/subquery-macos-x86_64.zip"
|
|
||||||
elif current_platform == "Windows":
|
|
||||||
download_url += "/subquery-windows-x86_64.zip"
|
|
||||||
else:
|
|
||||||
raise ValueError('Can\'t to recognize the operating system')
|
|
||||||
|
|
||||||
try:
|
|
||||||
os.makedirs(temporary_path, exist_ok=False)
|
|
||||||
wget.download(download_url, out = temporary_path)
|
|
||||||
for file in os.listdir(temporary_path):
|
|
||||||
with zipfile.ZipFile(temporary_path+'/'+file) as item:
|
|
||||||
item.extractall(temporary_path)
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
subprocess.call(['chmod', '-R', '777', temporary_path])
|
|
||||||
|
|
||||||
return temporary_path
|
|
||||||
|
|
||||||
|
|
||||||
def use_subquery_cli(subquery_cli_version, *args):
|
|
||||||
temporary_path = get_subquery_cli(subquery_cli_version)
|
|
||||||
data_from_subquery = subprocess.check_output([temporary_path+'/subquery', *args]).decode()
|
|
||||||
|
|
||||||
return data_from_subquery
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
# token = os.environ['SUBQUERY_TOKEN', '']
|
|
||||||
token=''
|
|
||||||
# project_key = os.environ['PROJECT_KEY', '']
|
|
||||||
project_key = ''
|
|
||||||
subquery_cli_version = '0.2.4'
|
|
||||||
|
|
||||||
use_subquery_cli(subquery_cli_version, '--token', token, 'deployment', 'list', '-o', 'json', '--org', 'nova-wallet', '--key', project_key)
|
|
||||||
@@ -1,144 +0,0 @@
|
|||||||
import json
|
|
||||||
import requests
|
|
||||||
from pytablewriter import MarkdownTableWriter
|
|
||||||
from telegram_notifications import TelegramNotifications
|
|
||||||
from subquery_api import SubQueryDeploymentAPI, SubQueryProject, DeploymentInstance
|
|
||||||
|
|
||||||
class ProjectTableGenerator:
|
|
||||||
def __init__(self, sub_query: SubQueryDeploymentAPI, nova_network_list_url: str):
|
|
||||||
self.sub_query = sub_query
|
|
||||||
self.nova_network_list_url = nova_network_list_url
|
|
||||||
|
|
||||||
def generate_table(self):
|
|
||||||
writer = MarkdownTableWriter(
|
|
||||||
headers=["--", "Network", "Features", "Stage status", "Prod status", "Stage commit", "Prod commit"],
|
|
||||||
value_matrix=self.generate_value_matrix_for_table(),
|
|
||||||
margin=1
|
|
||||||
)
|
|
||||||
writer.write_table()
|
|
||||||
return writer
|
|
||||||
|
|
||||||
def generate_value_matrix_for_table(self):
|
|
||||||
network_list = self.generate_network_list()
|
|
||||||
returning_array = []
|
|
||||||
for network in network_list:
|
|
||||||
network_data_array = self.generate_network_data_array(network)
|
|
||||||
returning_array.append(network_data_array)
|
|
||||||
print(f'{network.get("name").title()} generated!')
|
|
||||||
returning_array.sort()
|
|
||||||
increment = iter(range(1, len(returning_array)+1))
|
|
||||||
[network.insert(0, next(increment)) for network in returning_array]
|
|
||||||
return returning_array
|
|
||||||
|
|
||||||
def generate_network_data_array(self, network: dict):
|
|
||||||
network_data_array = []
|
|
||||||
subquery_project_data = self.sub_query.find_project_by_parameter('name', network.get('name'))
|
|
||||||
network_data_array.append(
|
|
||||||
f"[{network.get('name').title()}](https://explorer.subquery.network/subquery/{subquery_project_data.key})"
|
|
||||||
)
|
|
||||||
prod_status, prod_commit, stage_status, stage_comit = self.generate_progress_status(
|
|
||||||
next(filter(lambda project: project.name == network['name'], self.sub_query.org_projects))
|
|
||||||
)
|
|
||||||
network_data_array.extend([network.get('features'), stage_status, prod_status, stage_comit, prod_commit])
|
|
||||||
return network_data_array
|
|
||||||
|
|
||||||
def generate_network_list(self):
|
|
||||||
feature_list = []
|
|
||||||
chains_list = self._send_http_request(self.nova_network_list_url)
|
|
||||||
available_projects = self.sub_query.org_projects
|
|
||||||
for project in available_projects:
|
|
||||||
prod_genesis = self.get_prod_genesis(project)
|
|
||||||
if not prod_genesis: # Skip undeployed projects
|
|
||||||
continue
|
|
||||||
project_genesis = self._remove_hex_prefix(prod_genesis)
|
|
||||||
chain = next(iter([chain for chain in chains_list if chain.get('chainId') == project_genesis]), None)
|
|
||||||
feature_list.append({
|
|
||||||
"name": project.name,
|
|
||||||
"genesis": project_genesis,
|
|
||||||
"features": self.check_features(chain)
|
|
||||||
})
|
|
||||||
return feature_list
|
|
||||||
|
|
||||||
def get_prod_genesis(self, project):
|
|
||||||
try:
|
|
||||||
return [deploy.configuration['chainId'] for deploy in project.deployments if deploy.type == 'primary']
|
|
||||||
except:
|
|
||||||
print(f"Network: {project.network} has old deployment, need to redeploy")
|
|
||||||
return None
|
|
||||||
|
|
||||||
def generate_progress_status(self, project: SubQueryProject):
|
|
||||||
prod, stage = None, None
|
|
||||||
for deployment in project.deployments:
|
|
||||||
if deployment.type == 'primary':
|
|
||||||
prod = deployment
|
|
||||||
elif deployment.type == 'stage':
|
|
||||||
stage = deployment
|
|
||||||
else:
|
|
||||||
raise Exception(f"Unknown deployment type: {deployment.type} in project: {project}")
|
|
||||||
prod_status, prod_commit = self.fill_status_bar(prod, project)
|
|
||||||
stage_status, stage_commit = self.fill_status_bar(stage, project)
|
|
||||||
return prod_status, prod_commit, stage_status, stage_commit
|
|
||||||
|
|
||||||
def fill_status_bar(self, instance: DeploymentInstance, project: SubQueryProject):
|
|
||||||
if not instance:
|
|
||||||
return '', '-'
|
|
||||||
commit = instance.version[0:8]
|
|
||||||
if instance.status == 'processing':
|
|
||||||
return '', commit
|
|
||||||
if instance.status == 'error' and self.get_sync_percentage(instance, project) == '0':
|
|
||||||
return '', commit
|
|
||||||
percent = self.get_sync_percentage(instance, project)
|
|
||||||
return f'})', commit
|
|
||||||
|
|
||||||
def is_sync_status_valid(self, sync_status):
|
|
||||||
if sync_status is None:
|
|
||||||
return False
|
|
||||||
return all(key in sync_status and sync_status[key] is not None for key in ['processingBlock', 'targetBlock'])
|
|
||||||
|
|
||||||
def get_sync_percentage(self, instance: DeploymentInstance, project: SubQueryProject) -> str:
|
|
||||||
if not self.is_sync_status_valid(instance.sync_status):
|
|
||||||
logs = self.sub_query.get_logs(project.key, instance.id)
|
|
||||||
target_block, processing_block = self.sub_query.parse_logs(logs)
|
|
||||||
else:
|
|
||||||
processing_block = instance.sync_status.get('processingBlock')
|
|
||||||
target_block = instance.sync_status.get('targetBlock')
|
|
||||||
telegram = TelegramNotifications()
|
|
||||||
if processing_block and target_block:
|
|
||||||
if processing_block != -1:
|
|
||||||
return str(int((processing_block / target_block) * 100))
|
|
||||||
else:
|
|
||||||
telegram.add_row_in_telegram_notification(project=project, instance=instance)
|
|
||||||
return '0'
|
|
||||||
else:
|
|
||||||
telegram.add_row_in_telegram_notification(project=project, instance=instance)
|
|
||||||
return '0'
|
|
||||||
|
|
||||||
def check_features(self, chain: json):
|
|
||||||
def has_transfer_history(chain):
|
|
||||||
return True
|
|
||||||
def has_orml_or_asset(chain):
|
|
||||||
return any(asset.get('type') in ['orml', 'statemine'] for asset in chain.get('assets'))
|
|
||||||
def has_staking_analytics(chain):
|
|
||||||
return chain.get('assets')[0].get('staking') == 'relaychain'
|
|
||||||
def has_rewards_history(chain):
|
|
||||||
return bool(chain.get('assets')[0].get('staking'))
|
|
||||||
dict = {
|
|
||||||
"📚 Operation History": has_transfer_history,
|
|
||||||
"✨ Multi assets": has_orml_or_asset,
|
|
||||||
"📈 Staking analytics": has_staking_analytics,
|
|
||||||
"🥞 Staking rewards": has_rewards_history
|
|
||||||
}
|
|
||||||
if chain is None:
|
|
||||||
return list(dict.keys())[0]
|
|
||||||
features = [feature for feature, criteria in dict.items() if criteria(chain)]
|
|
||||||
return '<br />'.join(features)
|
|
||||||
|
|
||||||
def _send_http_request(self, url: str):
|
|
||||||
try:
|
|
||||||
response = requests.get(url)
|
|
||||||
except requests.exceptions.RequestException as e:
|
|
||||||
raise SystemExit(e)
|
|
||||||
return json.loads(response.text)
|
|
||||||
|
|
||||||
def _remove_hex_prefix(self, hex_string):
|
|
||||||
return hex_string[2:]
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
import os
|
|
||||||
import asyncio
|
|
||||||
import telegram
|
|
||||||
|
|
||||||
from subquery_api import SubQueryProject, DeploymentInstance
|
|
||||||
from singleton import Singleton
|
|
||||||
|
|
||||||
|
|
||||||
class TelegramNotifications(metaclass=Singleton):
|
|
||||||
notify_message_title = "⚠️ SubQuery projects error ⚠️"
|
|
||||||
notify_projects_message = []
|
|
||||||
|
|
||||||
def __init__(self) -> None:
|
|
||||||
self.token = os.getenv("TELEGRAM_BOT_TOKEN")
|
|
||||||
self.chat_id = os.getenv("TELEGRAM_CHAT_ID")
|
|
||||||
|
|
||||||
async def send_telegram_message(self, message):
|
|
||||||
bot = telegram.Bot(token=self.token)
|
|
||||||
await bot.send_message(chat_id=self.chat_id, text=message, parse_mode="MarkdownV2")
|
|
||||||
|
|
||||||
def send_notification(self):
|
|
||||||
if len(self.notify_projects_message) != 0:
|
|
||||||
notification_message = self.notify_message_title
|
|
||||||
|
|
||||||
for project_message in self.notify_projects_message:
|
|
||||||
notification_message += project_message
|
|
||||||
|
|
||||||
shielded_message = notification_message.replace('-', '\-')
|
|
||||||
asyncio.run(self.send_telegram_message(shielded_message))
|
|
||||||
else:
|
|
||||||
pass
|
|
||||||
|
|
||||||
def add_row_in_telegram_notification(self, project: SubQueryProject, instance: DeploymentInstance):
|
|
||||||
notify_project_name = project.name.title()
|
|
||||||
|
|
||||||
self.notify_projects_message.append(
|
|
||||||
f"\n\n*{notify_project_name}* Indexer is unhealthy\!\nProject URL: [Link to project](https://managedservice.subquery.network/orgs/nova-wallet/projects/{instance.project_key.split('/')[1]}/deployments?slot={instance.type})\nExplorer URL: [Link to explorer](https://explorer.subquery.network/subquery/{instance.project_key})\nEnvironment: {instance.type.capitalize()}"
|
|
||||||
)
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
import json
|
|
||||||
import pytest
|
|
||||||
import os
|
|
||||||
from subquery_cli import use_subquery_cli
|
|
||||||
|
|
||||||
subquery_cli_version = '0.2.4'
|
|
||||||
token = os.environ['SUBQUERY_TOKEN']
|
|
||||||
project_key = os.environ['PROJECT_KEY']
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def get_project_data():
|
|
||||||
project_data = json.loads(
|
|
||||||
use_subquery_cli(
|
|
||||||
subquery_cli_version, '--token', token, 'deployment', 'list', '-o', 'json', '--org', 'nova-wallet', '--key', project_key
|
|
||||||
))
|
|
||||||
stage_project = next(
|
|
||||||
item for item in project_data if item["type"] == "stage")
|
|
||||||
return stage_project
|
|
||||||
|
|
||||||
|
|
||||||
def test_project_status(get_project_data):
|
|
||||||
assert get_project_data['status'] == 'running'
|
|
||||||
|
|
||||||
|
|
||||||
def test_sync_status_test(get_project_data):
|
|
||||||
sync_status = use_subquery_cli(
|
|
||||||
subquery_cli_version, '--token', token, 'deployment', 'sync-status', '--id', str(get_project_data['id']), '--key', project_key, '--org', 'nova-wallet')
|
|
||||||
status = sync_status.split("percent: ")[1:]
|
|
||||||
assertion_value = status[0].split('%')[0:][0]
|
|
||||||
assert assertion_value == '100.00'
|
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
# Require bash v4+
|
|
||||||
#
|
|
||||||
# You should download cli file for your operation sistem and put it in root directory.
|
|
||||||
# https://github.com/fewensa/subquery-cli/releases/
|
|
||||||
|
|
||||||
SCRIPT_PATH=$(dirname "$0")
|
|
||||||
MAIN_DIRECTORY=${SCRIPT_PATH%/*}
|
|
||||||
|
|
||||||
SUBQUERY_TOKEN="${SUBQUERY_TOKEN}"
|
|
||||||
ORGANISATION="nova-wallet"
|
|
||||||
|
|
||||||
|
|
||||||
BASE_DESCRIPTION="Nova SubQuery project is indexing the blockchain and provides a convenient API for fetching operation history & analytics data. It is used by the <a href=\"https://novawallet.io\">Nova Wallet</a>
|
|
||||||
Feel free to use this API for your app! 💖</br>
|
|
||||||
<mark>Make sure that you add filters and sorting rules to your queries!</mark></br>
|
|
||||||
Following API & datasource is supported:
|
|
||||||
📚 Transfers and extrinsics (transactions). Both or either can be fetched, for example:
|
|
||||||
<code>query {historyElements{nodes{transfer extrinsic}}}</code>
|
|
||||||
</br>"
|
|
||||||
|
|
||||||
MULTIASSET_DESCRIPTION="✨ Transfer history for additional assets in the network (based on \"assets\"/\"ORML\" Substrate pallet):
|
|
||||||
<code>query {historyElements{nodes{assetTransfer}}}</code>
|
|
||||||
</br>"
|
|
||||||
|
|
||||||
STAKING_DESCRIPTION="🥞 Staking rewards history:
|
|
||||||
<code>query {historyElements{nodes{reward}}}</code>
|
|
||||||
|
|
||||||
🎁 Total staking rewards for the desired acocunt:
|
|
||||||
<code>query {accumulatedRewards{nodes{id amount}}}</code>
|
|
||||||
</br>"
|
|
||||||
|
|
||||||
STAKING_ANALITIC="📊 Current stake — returns bonded amount:
|
|
||||||
<code>query {accumulatedStakes{nodes{id amount}}}</code>
|
|
||||||
|
|
||||||
👨🔧 Validators statistics:
|
|
||||||
<code>query {eraValidatorInfos{nodes{address era total own others}}}</code>
|
|
||||||
|
|
||||||
📈 Stake change history:
|
|
||||||
<code>query {stakeChanges{nodes{blockNumber extrinsicHash address amount accumulatedAmount type}}}</code>
|
|
||||||
</br>"
|
|
||||||
|
|
||||||
MULTIASSET_PROJECTS=('statemine parallel parallel-heiko westmint moonbeam moonriver astar shiden karura acala bifrost interlay kintsugi')
|
|
||||||
HAS_STAKING=('polkadot kusama westend moonbeam moonriver')
|
|
||||||
HAS_STAKING_ANALYTIC=('polkadot kusama westend')
|
|
||||||
|
|
||||||
|
|
||||||
folders=($(ls ${MAIN_DIRECTORY}/networks))
|
|
||||||
|
|
||||||
for item in ${folders[*]}; do
|
|
||||||
DESCRIPTION=${BASE_DESCRIPTION}
|
|
||||||
|
|
||||||
if [[ " ${MULTIASSET_PROJECTS[*]} " =~ " ${item} " ]]; then
|
|
||||||
DESCRIPTION+=${MULTIASSET_DESCRIPTION}
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ " ${HAS_STAKING[*]} " =~ " ${item} " ]]; then
|
|
||||||
DESCRIPTION+=${STAKING_DESCRIPTION}
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ " ${HAS_STAKING_ANALYTIC[*]} " =~ " ${item} " ]]; then
|
|
||||||
DESCRIPTION+=${STAKING_ANALITIC}
|
|
||||||
fi
|
|
||||||
|
|
||||||
$MAIN_DIRECTORY/subquery --token ${SUBQUERY_TOKEN} project update --org ${ORGANISATION} --key $item --description "${DESCRIPTION}" --subtitle "Nova Wallet SubQuery project for ${item^} network"
|
|
||||||
|
|
||||||
done
|
|
||||||
|
|
||||||
echo "Done !"
|
|
||||||
Reference in new issue
Block a user