Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions src/block_loader.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
from arq.connections import RedisSettings

from src.config import main_config
from src.services.tonapi import TonAPIClient


async def load_block(ctx, block_id):
api = TonAPIClient()
txs_data = api.tx_by_block(block_id)
# todo: save data to the DB


async def main():
pass


async def startup(ctx):
pass


async def shutdown(ctx):
pass


class WorkerSettings:
redis_settings = RedisSettings.from_dsn(main_config().cache.redis_url)
functions = [load_block]

on_startup = startup
on_shutdown = shutdown
23 changes: 23 additions & 0 deletions src/services/rate_limiter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
from typing import Union


def rate_limiter(limit: Union[int, float] = 1):
def decorator_function(func):
import time

last_request_time = 0

def wrapper(*args, **kwargs):
nonlocal last_request_time

interval = 1 / limit
current_time = time.time()
time_since_last_request = current_time - last_request_time
if time_since_last_request < interval:
time.sleep(interval - time_since_last_request)
last_request_time = time.time()
return func(*args, **kwargs)

return wrapper

return decorator_function
27 changes: 27 additions & 0 deletions src/services/ton_scan_service.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import requests


class TonAPIClientError(Exception):
pass


class TonAPIClient:
def __init__(self, base_url):
self.base_url = base_url

def _request(self, address, params=None):
params = {} if params is None else params
end_point = self.base_url + address
response = requests.get(end_point, params)
if response.status_code != 200:
raise TonAPIClientError(
f"Ton Scan Service response with error code: {response.status_code}, error: {response.text}")
return response.json()

def address_list(self, page=0, count=100):
addresses = self._request("/address_list/", {"page": page, "count": count})
return addresses

def address_details(self, address):
details = self._request(f"/address_details/{address}/")
return details
61 changes: 61 additions & 0 deletions src/services/tonapi.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# -*- coding: utf-8 -*-
import requests
import os
from rate_limiter import rate_limiter

TONAPI_KEY = os.getenv("TONAPI_KEY") or None
TONAPI_BASE_URL = "https://tonapi.io/v2"


class TonAPIClientError(Exception):
pass


class TonAPIClient:
def _request(self, address, params=None):
params = {} if params is None else params

# Making a request to tonapi.io
if TONAPI_KEY:
response = requests.get(TONAPI_BASE_URL + address, params, headers={"Authorization": f"Bearer {TONAPI_KEY}"})
else:
response = requests.get(TONAPI_BASE_URL + address, params)

# Checking the response
if response.status_code != requests.codes.ok:
raise TonAPIClientError(
f"Tonapi response with error code: {response.status_code}, error: {response.text}")
return response.json()

@rate_limiter(limit=0.9)
def tx_by_block(self, block_id):
"""
Find transactions by block id.

:param str block_id: Block id e.g. "(-1,8000000000000000,4234234)"
"""
request_url = f"/blockchain/blocks/{block_id}/transactions"
transactions = self._request(request_url)
return transactions

@rate_limiter(limit=0.9)
def tx_by_account(self, account_id):
"""
Find transactions by account id.

:param str account_id: Account id in any format
"""
request_url = f"/blockchain/accounts/{account_id}/transactions"
transactions = self._request(request_url)
return transactions

@rate_limiter(limit=0.9)
def raw_request(self, request_url, params):
"""
Make any request to tonapi.io

:param request_url: Endpoint. e.g. "/rates"
:param params: Any parameters. e.g. {"tokens": "ton", "currencies": "rub"}
"""
response = self._request(request_url, params)
return response
3 changes: 2 additions & 1 deletion tests/test_redis.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@
import pytest
from redis import asyncio

from src.config import main_config
from src.databases.redis import RedisRepo


@pytest.fixture(scope='module')
def redis_client():
"""Test connection provider."""
redis = asyncio.Redis()
redis = asyncio.Redis().from_url(main_config().cache.redis_url)
# try:
yield RedisRepo(redis)
# finally:
Expand Down