Created
August 18, 2021 04:31
-
-
Save JiapengLi/c55e03e4aa203d659aee1227cb42d289 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import os, sys | |
| import datetime | |
| import re | |
| import json | |
| import time | |
| from math import radians, cos, sin, asin, sqrt, log10, pow, pi | |
| from numpy import random | |
| import concurrent | |
| import requests | |
| import sqlite3 | |
| import pandas as pd | |
| import numpy as np | |
| import simplekml | |
| import h3 | |
| from simplekml.base import check | |
| from .utils import * | |
| from . import kmlstyle | |
| import traceback | |
| from collections import UserList | |
| class HeliumApi: | |
| def __init__(self, url, proxy = False): | |
| self.url = url | |
| self.proxy = proxy | |
| self.s = requests.session() | |
| self.cursors = [] | |
| self.data = [] | |
| self.data_len = 0 | |
| self.data_cnt = 0 | |
| def fullurl(self, path): | |
| return f'{self.url}/{path}' | |
| def request(self, path, para={}, new=True): | |
| if new: | |
| s = requests.session() | |
| else: | |
| s = self.s | |
| url = self.fullurl(path) | |
| res = None | |
| #print(f"{url} {para} {new}") | |
| try: | |
| if para == {}: | |
| res = s.get(url) | |
| else: | |
| res = s.get(url, params=para) | |
| except Exception as e: | |
| print(traceback.format_exc()) | |
| res = None | |
| return res | |
| def recursion(self, path, latest=0, para={}, cursor="", known_cursors=[]): | |
| para_tmp = para.copy() | |
| if cursor == None: | |
| return self.data | |
| else: | |
| c = None | |
| if cursor == "": | |
| self.data = [] | |
| self.cursors = [] | |
| self.data_len = 0 | |
| self.data_cnt = 0 | |
| else: | |
| para_tmp['cursor'] = cursor | |
| self.cursors.append(cursor) | |
| t0 = time.time() | |
| cnt = 5 | |
| while cnt > 0: | |
| self.data_cnt += 1 | |
| res = self.request(path, para_tmp) | |
| if res and res.status_code == 200: | |
| break | |
| time.sleep(2) | |
| cnt -= 1 | |
| if res: | |
| print(f"error {res.status_code}") | |
| if 'data' in res.json() and len(res.json()['data']) > 0: | |
| self.data += res.json()['data'] | |
| dtlen = len(self.data) | |
| if dtlen - self.data_len >= 1000: | |
| print(f"{self.fullurl(path)}: {dtlen} downloaded") | |
| self.data_len = dtlen | |
| if 'cursor' in res.json() and len(res.json()['cursor']) > 0: | |
| c = res.json()['cursor'] | |
| # if | |
| if latest != 0 and len(self.data) >= latest: | |
| c = None | |
| # if cursor is a known one exit | |
| if c and c in known_cursors: | |
| c = None | |
| print(f"{self.data_cnt}, {self.data_len} {time.time() - t0:.2f}") | |
| return self.recursion(path, latest, para_tmp, c) | |
| # https://api.helium.io/v1/hotspots | |
| def hotspots(self, latest=0, hotspots=None): | |
| if not hotspots: | |
| # fetch all or `latest` number of hotspots | |
| return self.recursion(f"hotspots", latest) | |
| else: | |
| self.data = [None] * len(hotspots) | |
| params = zip([f'hotspots/{hotspot}' for hotspot in hotspots], [None] * len(hotspots), [True] * len(hotspots)) | |
| params = list(params) | |
| print(params) | |
| with concurrent.futures.ThreadPoolExecutor() as executor: | |
| futures = {executor.submit(self.request, a, b, c): (a, b, c) for a, b, c in params} | |
| for future in concurrent.futures.as_completed(futures): | |
| self.data[params.index(futures[future])] = future.result().json()['data'] | |
| return self.data | |
| #GET https://api.helium.io/v1/hotspots/:address | |
| def hotspot(self, hotspot): | |
| return self.request(f'hotspots/{hotspot}').json() | |
| def hotspot_activity(self, hotspot, latest=0): | |
| return self.recursion(f'hotspots/{hotspot}/activity', latest=latest) | |
| def hotspot_name(self, name): | |
| return self.request(f'hotspots/name/{name}').json()['data'] | |
| def hotspot_rewards_para(self, hotspot, min_time = None, max_time = None, date = None): | |
| if min_time == None: | |
| utc_time = datetime.datetime.now(tz=pytz.timezone('Asia/Shanghai')) | |
| min_time = "2018-01-01T00:00:00Z" | |
| max_time = utc_time.strftime('%Y-%m-%dT%H:%M:%SZ') | |
| if date != None: | |
| if date > 0: | |
| date = 0 - date | |
| utc_time = datetime.datetime.now(tz=pytz.timezone('Etc/GMT-8')) | |
| today = datetime.datetime.strptime(utc_time.strftime('%Y-%m-%d'), '%Y-%m-%d') | |
| today = today.replace(tzinfo=pytz.timezone('Etc/GMT-8')).astimezone(tz=pytz.timezone('UTC')) | |
| if isinstance(date, int): | |
| day_start = today + datetime.timedelta(hours=24*date) | |
| day_end = day_start + datetime.timedelta(hours=24) | |
| min_time = day_start.strftime('%Y-%m-%dT%H:%M:%SZ') | |
| max_time = day_end.strftime('%Y-%m-%dT%H:%M:%SZ') | |
| para = {'min_time': min_time, 'max_time': max_time} | |
| return para | |
| def hotspot_rewards(self, hotspot, min_time = None, max_time = None, date = None): | |
| para = self.hotspot_rewards_para(hotspot, min_time, max_time, date) | |
| res = self.request(f'hotspots/{hotspot}/rewards/sum', para) | |
| if res: | |
| #print(res.json()) | |
| return res.json() | |
| else: | |
| return { | |
| 'data': { | |
| 'total': 0 | |
| } | |
| } | |
| def hotspot_rewards_days(self, hotspot, dates=[]): | |
| self.data = [None] * len(dates) | |
| para = [self.hotspot_rewards_para(hotspot,date=date) for date in dates] | |
| params = list(zip([f'hotspots/{hotspot}/rewards/sum'] * len(dates), para, [True] * len(dates))) | |
| with concurrent.futures.ThreadPoolExecutor() as executor: | |
| futures = {executor.submit(self.request, a, b, c): (a, b, c) for a, b, c in params} | |
| for future in concurrent.futures.as_completed(futures): | |
| self.data[params.index(futures[future])] = future.result().json()['data'] | |
| return self.data | |
| def pending_transactions(self, hash): | |
| res = self.request(f'pending_transactions/{hash}') | |
| return res.json()['data'] | |
| def height(self): | |
| res = self.request('blocks/height') | |
| return res.json()['data']['height'] | |
| def vars_activity(self): | |
| return self.recursion(f'vars/activity', latest=0) | |
| def location_box(self, swlat, swlon, nelat, nelon): | |
| para = { | |
| 'swlat': swlat, | |
| 'swlon': swlon, | |
| 'nelat': nelat, | |
| 'nelon': nelon, | |
| } | |
| return self.recursion(f"hotspots/location/box", para=para) | |
| def accounts_activity(self, account): | |
| return self.recursion(f'accounts/{account}/activity') | |
| def accounts_hotspots(self, account, latest=0): | |
| return self.recursion(f'accounts/{account}/hotspots', latest=latest) | |
| def transactions(self, height): | |
| return self.recursion(f'blocks/{height}/transactions') |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment