Compare commits

..

1 Commits

Author SHA1 Message Date
poka 70916e7577 Add skeleton for Django 2020-10-01 05:04:41 +02:00
28 changed files with 419 additions and 506 deletions

View File

@ -1,4 +1,3 @@
DUNITER="https://duniter-g1.p2p.legal" # Adresse du noeud Duniter qui sera scanné
ESNODE="http://g1.data.duniter.fr" # Adresse du noeud ElasticSearch qui sera scanné (Si nécessaire)
WEBPATH="/var/www/g1-stats" # Dossier qui sera créé si vous choisissez l'option web pour la mise en ligne des données (nécessite une configuration apache ou nginx)
SILKAJ="" # Chemin vers Silkaj (Récupéré automatiquement si non renseigné)

1
.gitignore vendored
View File

@ -5,4 +5,3 @@ cache
debug.log
bk-debug.log
bk
.gitPushToMaster.sh

View File

@ -2,7 +2,7 @@
## Sous forme d'un fichier JSON journalisé et d'outils d'exploitation de ce JSON
### Visible sur: [https://g1-stats.axiom-team.fr/](https://g1-stats.axiom-team.fr/)
Utilise l'[API BMA](https://github.com/duniter/duniter-bma/blob/master/doc/API.md) pour l'extraction et l'indexation des données de la [blockchain Duniter/Ḡ1](https://duniter.org).<br>
Utilise l'[API BMA](https://github.com/duniter/duniter-bma/blob/master/doc/API.md) pour l'extraction et l'indexation des données de la [blockchain Duniter/Ḡ1](https://duniter.org).
A exécuter dans un environnement Bash Debian/Ubuntu.
*Si vous souhaitez modifier les paramètres par defaut, copiez le fichier .env.example en .env et adaptez les variables selon votre usage.*
@ -13,8 +13,8 @@ Lancer le scan ainsi que tout le processus d'indexation depuis le début de la b
```
./g1-stats.sh
```
*A la première execution, ce scan peut durer plusieurs heures!*<br>
Pour pourrez suivre la progression du scan en temps réel.<br>
*A la première execution, ce scan peut durer plusieurs heures!*
Pour pourrez suivre la progression du scan en temps réel.
Pour les exécutions ultérieures, un cache est géneré permettant de reprendre le scan là où il s'est arrêté, diminuant drastiquement le temps d'execution.
Le fichier JSON est alors généré: `db/daily.json`
@ -27,17 +27,12 @@ Pour générer la page web static:
## Exploration
Une fois le fichier JSON correctement généré, vous pouvez utiliser `explorer.sh` pour l'exploiter.<br>
Pour obtenir l'aide:
Une fois le fichier JSON correctement généré, vous pouvez l'exploiter via la commande:
```
./explorer.sh -h
./explorer.sh
```
**Ce script explorer.sh fonctionne de manière standalone, c'est à dire que vous pouvez l'utiliser en dehors de l'environnement Ḡ1Stats sans aucune dépendance:**
```
wget https://git.p2p.legal/axiom-team/g1-stats/raw/master/explorer.sh
chmod u+x explorer.sh
```
*TODO: Détailler cette partie ...*
## Sauvegarde/Restauration
@ -58,7 +53,7 @@ Pour restaurer un backup à partir d'un bloc précis, par exemple le bloc 4242 (
## Automatisation
Vous pouvez décider d'exécuter ce script régulièrement grâce à une tache cron.<br>
Vous pouvez décider d'exécuter ce script régulièrement grâce à une tache cron.
Par exemple pour l'exécuter toutes les 3 heures:
```

View File

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

16
backend/backend/asgi.py Normal file
View File

@ -0,0 +1,16 @@
"""
ASGI config for backend project.
It exposes the ASGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/3.1/howto/deployment/asgi/
"""
import os
from django.core.asgi import get_asgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'backend.settings')
application = get_asgi_application()

120
backend/backend/settings.py Normal file
View File

@ -0,0 +1,120 @@
"""
Django settings for backend project.
Generated by 'django-admin startproject' using Django 3.1.1.
For more information on this file, see
https://docs.djangoproject.com/en/3.1/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/3.1/ref/settings/
"""
from pathlib import Path
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/3.1/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'kkw+99i97l4#@d6f!hj=nz60v^p@0f3l8jgew10vfz%1h5elwp'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = []
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
ROOT_URLCONF = 'backend.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
WSGI_APPLICATION = 'backend.wsgi.application'
# Database
# https://docs.djangoproject.com/en/3.1/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
}
# Password validation
# https://docs.djangoproject.com/en/3.1/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
# Internationalization
# https://docs.djangoproject.com/en/3.1/topics/i18n/
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.1/howto/static-files/
STATIC_URL = '/static/'

21
backend/backend/urls.py Normal file
View File

@ -0,0 +1,21 @@
"""backend URL Configuration
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/3.1/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path
urlpatterns = [
path('admin/', admin.site.urls),
]

16
backend/backend/wsgi.py Normal file
View File

@ -0,0 +1,16 @@
"""
WSGI config for backend project.
It exposes the WSGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/3.1/howto/deployment/wsgi/
"""
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'backend.settings')
application = get_wsgi_application()

0
backend/db.sqlite3 Normal file
View File

22
backend/manage.py Executable file
View File

@ -0,0 +1,22 @@
#!/usr/bin/env python3
"""Django's command-line utility for administrative tasks."""
import os
import sys
def main():
"""Run administrative tasks."""
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'backend.settings')
try:
from django.core.management import execute_from_command_line
except ImportError as exc:
raise ImportError(
"Couldn't import Django. Are you sure it's installed and "
"available on your PYTHONPATH environment variable? Did you "
"forget to activate a virtual environment?"
) from exc
execute_from_command_line(sys.argv)
if __name__ == '__main__':
main()

View File

@ -1,140 +1,65 @@
#!/bin/bash
################################################################################
# Author: Poka (poka@p2p.legal)
# Version: 0.0.3
# License: AGPL-3.0 (https://choosealicense.com/licenses/agpl-3.0/)
# Git: https://git.p2p.legal/axiom-team/g1-stats
################################################################################
###
# Please change this path if needed, in relative path from explorer.sh script
# If no file found, then this script will download it from https://g1-stats.axiom-team.fr and prompt it
jsonFile="db/daily.json"
###
# Check if jq, jo and curl are installed, or install them
[[ -z $(which jq) || -z $(which jo) || -z $(which curl) ]] && sudo apt update && sudo apt install jq jo bc curl -y
# Path of the current script
# Récupération du chemin absolut du répertoir du script actuel
GPATH="$( cd "$(dirname "$0")" ; pwd -P )"
jsonFile="$GPATH/$jsonFile"
source $GPATH/.env
if [[ -f $jsonFile ]]; then
jsonData=$(cat $jsonFile)
else
echo "Warning: No JSON file found, we download it from https://g1-stats.axiom-team.fr/data/daily.json" >&2
jsonData="$(curl -s https://g1-stats.axiom-team.fr/data/daily.json)"
fi
jsonFile="$GPATH/db/daily.json"
cmd=$1
dateRange=$2
[[ -z $dateRange ]] && dateRange=$(jq -r '.[].date' $jsonFile | tail -n1)
lineNbr=$(grep -n "$dateRange" $jsonFile | cut -d : -f 1)
[[ -z $lineNbr ]] && echo "La date $dateRange n'existe pas en cache G1Stats" && exit 1
# Help display
helpOpt() {
echo -e "Welcome to Ḡ1Stats Explorer V$(head $0 | awk '/# Version:/ { print $3 }')
\rThis tool can be use in 2 differents mode:
\r- Isolate mode (default): Display data of a selected day
\r- Cumulative mode (option -c or --cumulate): Display cumulative data from begining of Ḡ1 Blockchain (08-03-17) until selected day
cumulate() {
lineNbr=$(($lineNbr+7))
\rExamples:
\r$0
Default view show last day data in cumulative mode
jsonDated=$(head -n$lineNbr $jsonFile)
jsonDated=$(echo -e "$jsonDated\n }\n]")
\r$0 day 08-03-20
Display 8th Mars 2020's data
sumRWBrut=$(jq -r '.[].rWallets' <<<$jsonDated | awk '{ SUM += $1} END { printf "%.2f", SUM }')
sumRMBrut=$(jq -r '.[].rMembers' <<<$jsonDated | awk '{ SUM += $1} END { printf "%.2f", SUM }')
sumRTBrut=$(jq -r '.[] | .rWallets, .rMembers' <<<$jsonDated | awk '{ SUM += $1} END { printf "%.2f", SUM }')
sumSWBrut=$(jq -r '.[].sWallets' <<<$jsonDated | awk '{ SUM += $1} END { printf "%.2f", SUM }')
sumSMBrut=$(jq -r '.[].sMembers' <<<$jsonDated | awk '{ SUM += $1} END { printf "%.2f", SUM }')
sumSTBrut=$(jq -r '.[] | .sWallets, .sMembers' <<<$jsonDated | awk '{ SUM += $1} END { printf "%.2f", SUM }')
\r$0 day 08-03-20 -c
Display 8th Mars 2020's cumulative data from begining
nbrMembers=$(jq -r '.[].nbrMembers' <<<$jsonDated | awk '{ SUM += $1} END { printf "%.0f", SUM }')
nbrWallets=$(jq -r '.[].nbrWallets' <<<$jsonDated | awk '{ SUM += $1} END { printf "%.0f", SUM }')
\r$0 mass -c [day]
Display monetary mass on current day, or selected day
soldeWBrut=$(echo "$sumRWBrut-$sumSWBrut" | bc)
soldeMBrut=$(echo "$sumRMBrut-$sumSMBrut" | bc)
\r$0 solde [day]
Display solde (Received - Sent) for simple wallets and members wallets on a day
UD=$(jq -r '.[].UD' <<<$jsonDated | tail -n1)
\r$0 total [day]
Display Sent and Received Ḡ1 in total on a day
\r$0 custom \".rMembers==0 and .sMembers==0\"
Display custom filter. Here we get only days where members received and sent nothing
\r$0 anniversary -c
Display UD reassessment days, the new UD value and the number of members this day"
echo "{
\"date\": "\"$dateRange\"",
\"UD\": $UD,
\"rWallets\": $sumRWBrut,
\"sWallets\": $sumSWBrut,
\"soldeWallets\": $soldeWBrut,
\"rMembers\": $sumRMBrut,
\"sMembers\": $sumSMBrut,
\"soldeMembers\": $soldeMBrut,
\"nbrMembers\": $nbrMembers,
\"nbrWallets\": $nbrWallets
}
" | jq .
}
jqCumulate="def roundit: (.*100.0)+ 0.5|floor/100.0;
[foreach .[] as \$row (null;
.nbrMembers += \$row.nbrMembers |
.nbrWallets += \$row.nbrWallets |
.sMembers = (\$row.sMembers + .sMembers|roundit) |
.rMembers = (\$row.rMembers + .rMembers|roundit) |
.sWallets = (\$row.sWallets + .sWallets|roundit) |
.rWallets = (\$row.rWallets + .rWallets|roundit);
\$row + . )]"
# Parse options
for i in $@; do
case "$i" in
-c|--cumulate) jsonData="$(jq "$jqCumulate" <<<$jsonData)";;
-h|--help) helpOpt && exit 0;;
*) isArg+="$i|";;
esac
done
# Load arguments in respective variables
cmd=$(cut -d'|' -f1 <<<"$isArg")
dateRange=$(cut -d'|' -f2 <<<"$isArg")
args="$(cut -d'|' -f2- <<<"$isArg" | sed 's/.$//' | tr '|' ' ')"
# If no date, set last available
[[ -z "$dateRange" ]] && dateRange=$(jq -r '.[].date' <<<$jsonData | tail -n1)
# Check if date existe un JSON
[[ ! $(grep -w "$dateRange" <<<$jsonData) && $cmd != "custom" ]] && echo "La date $dateRange n'existe pas en cache G1Stats" && exit 1
day() {
jq '.[] | select(.date=="'$dateRange'")' <<<$jsonData
lineNbr=$(($lineNbr+8))
jsonDated=$(head -n$lineNbr $jsonFile | tail -n10 | sed 's/},/}/g')
jq . <<<"$jsonDated"
}
mass() {
local jsonDated=$(jq '.[0: map(.date) | index("'$dateRange'")+1]' <<<$jsonData)
local mMass=$(jq '.[] | .UD*.nbrMembers' <<<"$jsonDated" | awk '{ SUM += $1} END { printf "%.2f", SUM }')
jo -p date=$dateRange monetaryMass=$mMass | jq .
lineNbr=$(($lineNbr+7))
jsonDated="$(head -n$lineNbr $jsonFile)}]"
jq -f $GPATH/lib/cumulate.jq <<<"$jsonDated" | jq '.[] | .UD*.nbrMembers' | awk '{ SUM += $1} END { printf "%.2f", SUM }'; echo
}
total() {
local cumDay=$(day)
local totalExchange=$(jq '(.rWallets+.rMembers)*100.0+ 0.5|floor/100.0' <<<$cumDay)
local soldeWallets=$(jq '(.rWallets-.sWallets)*100.0+ 0.5|floor/100.0' <<<$cumDay)
local soldeMembers=$(jq '(.rMembers-.sMembers)*100.0+ 0.5|floor/100.0' <<<$cumDay)
jo -p date=$dateRange totalExchange=$totalExchange soldeWallets=$soldeWallets soldeMembers=$soldeMembers | jq .
}
[[ -z $cmd ]] && cmd=cumulate
totall() {
for i in $(jq -r .[].date <<<$jsonData); do
dateRange=$i
total
done
}
custom() {
jq '.[] | select('"$args"')' <<<$jsonData
}
anniversary() {
local jqNewUD="reduce .[] as \$x (null;
if . == null then [\$x]
elif .[-1].UD == \$x.UD then .
else . + [\$x] end) | .[] |=
{date: .date, UD: .UD, nbrMembers: .nbrMembers}"
jq "$jqNewUD" <<<$jsonData
}
print() {
jq . <<<"$jsonData"
}
# Load functions
case $cmd in
'') day;;
solde) total;;
*) [[ $(type -t $cmd) == "function" ]] && $cmd || (echo -e "$cmd: Commande inconnue\n" && helpOpt);;
esac
$cmd

View File

@ -11,7 +11,7 @@
# Exit script if error
set -e
# Récupération du chemin absolu du répertoir du script actuel
# Récupération du chemin absolut du répertoir du script actuel
GPATH="$( cd "$(dirname "$0")" ; pwd -P )"
[[ ! -f $GPATH/.env ]] && cp $GPATH/.env.example $GPATH/.env
source $GPATH/.env
@ -21,7 +21,7 @@ startTime=$(date +'%H:%M')
day=$(date +'%y-%m-%d')
dayP=$(date +'%d-%m-%y')
echo -e "\n############# $day à $startTime #############\n"
[[ -z $(which jq) || -z $(which jo) || -z $(which bc) || -z $(which curl) ]] && sudo apt update && sudo apt install jq jo bc curl -y
[[ -z $(which jq) || -z $(which bc) || -z $(which curl) ]] && sudo apt update && sudo apt install jq bc curl
echo "Initialisation ..."
if $debug; then
TXBLOCKS=$(cat $GPATH/db/debug/txblocs)
@ -51,6 +51,7 @@ source $GPATH/lib/scanTxWallets.sh
### Extraction des adresses Ḡ1 actives
scanTxWallets
### Calcul la somme des soldes portefeuilles et membres
sumSoldes

12
lib/cumulate.jq Normal file
View File

@ -0,0 +1,12 @@
def roundit: .*100.0|round/100.0;
[foreach .[] as $row ({nbrMembers: 0, nbrWallets: 0, sMembers: 0, rMembers: 0, sWallets: 0, rWallets: 0};
{
nbrMembers: ($row.nbrMembers + .nbrMembers),
nbrWallets: ($row.nbrWallets + .nbrWallets),
sMembers: ($row.sMembers + .sMembers|roundit),
rMembers: ($row.rMembers + .rMembers|roundit),
sWallets: ($row.sWallets + .sWallets|roundit),
rWallets: ($row.rWallets + .rWallets|roundit)
};
$row * .
)]

View File

@ -61,16 +61,12 @@ web() {
echo "$wallets" | grep . > $WEBPATH/data/wallets-g1.txt
echo -e "$membresPubkeys" | sed 's/ /\n/g' > $WEBPATH/data/wallets-g1-membres.txt
echo -e "$simpleWallets" > $WEBPATH/data/wallets-g1-simple.txt
cp $GPATH/db/daily.json $WEBPATH/data/
$GPATH/explorer.sh print -c > $WEBPATH/data/cum-daily.json
cp $GPATH/db/{daily.json,cum-daily.json} $WEBPATH/data/
if [[ "$startTime" == "00:00" ]]; then
cp $indexhtml $WEBPATH/history/index_$day.html
sed -i "s/css\/style.css/..\/css\/style.css/g" $WEBPATH/history/index_$day.html
sed -i "s/logo-axiom-team.svg/..\/logo-axiom-team.svg/g" $WEBPATH/history/index_$day.html
sed -i 's/id="charts">/id="charts" style="display:none;">/g' $WEBPATH/history/index_$day.html
sed -i '/href="css\/charts.css"/d' $WEBPATH/history/index_$day.html
sed -i '/type="text\/javascript"/d' $WEBPATH/history/index_$day.html
sed -i "s/_dateNext/$day/g" $WEBPATH/history/index_$datePrevious.html
sed -i "s/style=\"display:none;\" class=\"next\"/class=\"next\"/g" $WEBPATH/history/index_$datePrevious.html
fi
@ -80,20 +76,19 @@ web() {
}
sumSoldes() {
source $GPATH/explorer.sh -c > /dev/null
sumRW=$(day | jq '.rWallets' | sed ':a;s/\B[0-9]\{3\}\>/ &/;ta')
sumRM=$(day | jq '.rMembers' | sed ':a;s/\B[0-9]\{3\}\>/ &/;ta')
sumRT=$(total | jq '.totalExchange' | sed ':a;s/\B[0-9]\{3\}\>/ &/;ta')
sumSW=$(day | jq '.sWallets' | sed ':a;s/\B[0-9]\{3\}\>/ &/;ta')
sumSM=$(day | jq '.sMembers' | sed ':a;s/\B[0-9]\{3\}\>/ &/;ta')
sumSTBrut=$(total | jq '.totalExchange')
sumST=$(sed ':a;s/\B[0-9]\{3\}\>/ &/;ta' <<<"$sumSTBrut")
soldeWBrut=$(total | jq '.soldeWallets')
soldeW=$(sed ':a;s/\B[0-9]\{3\}\>/ &/;ta' <<<"$soldeWBrut")
soldeM=$(total | jq '.soldeMembers' | sed ':a;s/\B[0-9]\{3\}\>/ &/;ta')
source $GPATH/explorer.sh > /dev/null
sumRW=$(echo $sumRWBrut | sed ':a;s/\B[0-9]\{3\}\>/ &/;ta')
sumRM=$(echo $sumRMBrut | sed ':a;s/\B[0-9]\{3\}\>/ &/;ta')
sumRT=$(echo $sumRTBrut | sed ':a;s/\B[0-9]\{3\}\>/ &/;ta')
sumSW=$(echo $sumSWBrut | sed ':a;s/\B[0-9]\{3\}\>/ &/;ta')
sumSM=$(echo $sumSMBrut | sed ':a;s/\B[0-9]\{3\}\>/ &/;ta')
sumST=$(echo $sumSTBrut | sed ':a;s/\B[0-9]\{3\}\>/ &/;ta')
soldeW=$(echo $soldeWBrut | sed ':a;s/\B[0-9]\{3\}\>/ &/;ta')
soldeM=$(echo $soldeMBrut | sed ':a;s/\B[0-9]\{3\}\>/ &/;ta')
### Calcul de la masse monétaire et du pourcentage de Ḡ1 sur les simples portefeuilles
monetaryMassBrut=$(mass | jq .monetaryMass)
monetaryMassBrut=$($GPATH/explorer.sh mass)
monetaryMass=$(echo "$monetaryMassBrut" | sed ':a;s/\B[0-9]\{3\}\>/ &/;ta')
pourcentSimpleWallet=$(echo "$soldeWBrut*100/$monetaryMassBrut/1" | bc -l | xargs printf %.1f)

View File

@ -40,9 +40,6 @@ scanTxWallets() {
# Récupération de la date du block
local blockDate=$(jq '.medianTime' <<<"$blocBrut")
#kopa echo "$blocBrut"
# echo "---"
# echo "$blockDate"
blockDate=$(date -d"@$blockDate" +%d-%m-%y -u)
local walletsReceivedBloc=$(jq '.transactions[]' <<<"$blocBrut")
@ -243,6 +240,9 @@ scanTxWallets() {
sed -i '$ s/,//g' $jsonFile
echo "]" >> $jsonFile
# On génère le JSON équivalent avec données cumulatives
jq -f $GPATH/lib/cumulate.jq $jsonFile > $GPATH/db/cum-daily.json
# On supprime les doublons et les lignes vides
wallets=$(echo -e "$wallets" | sort -u | awk 'NF')
# On écrit les pubkeys avec transaction dans un fichier de cache pour la prochaine itération

View File

@ -14,9 +14,9 @@ chainMbr=$(head -n1 <<<"$chainData")
((day--))
Date=$(date -d "17-03-08+${day}day" '+%d-%m-%y')
jsonMass=$($GPATH/explorer.sh mass $Date -c | jq .monetaryMass)
jsonMass=$($GPATH/explorer.sh mass $Date)
jsonMbr=$($GPATH/explorer.sh day $Date -c | jq .nbrMembers)
jsonMbr=$($GPATH/explorer.sh cumulate $Date | jq .nbrMembers)
#if [[ $jsonMbr != $chainMbr ]]; then
echo "$Date - $bloc - $day

View File

@ -1,70 +0,0 @@
#!/bin/bash
# Récupération du chemin absolu du répertoire du script actuel
GPATH="$( cd "$(dirname "$0")" ; pwd -P )/.."
[[ ! -f $GPATH/.env ]] && cp $GPATH/.env.example $GPATH/.env
source $GPATH/.env
node=$(cut -d '/' -f3 <<<"$DUNITER")
#Check if ed is installed
which ed || { echo "$0: Error: please install ed" >&2 ; exit 1 ; }
#Check if Jaklis or silkaj is installed
if [[ "$JAKLIS" ]] ; then
exec() {
jsonResult=$($JAKLIS idBalance -p $i) || return $?
balance=$(echo "$jsonResult" | jq -r '.balance')
username=$(echo "$jsonResult" | jq -r '.username')
}
elif which silkaj ; then
exec() {
balance=$(silkaj -p "$node" balance "$i") || return $?
balance=$(sed -n 's,.* \([\.0-9]\+\) Ğ1.*,\1,p' <<<$balance)
username=$(silkaj -p "$node" id "$i") || return $?
username=$(sed -n 's,.*: \(.*\)$,\1,p' <<<$username)
}
else
echo "$0: Error: you should use Jaklis or install silkaj." >&2
exit 1
fi
work() {
for i in $wallets; do
((j++))
# For tests only
#(( j > 42 )) && break
unset k
while ! exec ; do echo "Erreur $?: retry=$((k)) wallet=$i"; ((k++ > 9999)) && break ; sleep $((RANDOM%8)) ; done
formatedBalance=$(printf "%-10s | %-45s | %-1s" $balance $i $username)
[[ $1 == "members" ]] && username="<b>$username</b>"
htmlBloc="$htmlBloc<td>$balance</td><td><a id=\"k$i\" href=\"payto://g1/$i\">$i</a></td><td><b>$username</b></td>"$'\n'
echo "$formatedBalance" | tee -a /tmp/balance-g1.txt | sed "s,^,$j | ,"
totalBalance="$totalBalance$formatedBalance"$'\n'
done
}
wallets=$(cat $WEBPATH/data/wallets-g1-membres.txt 2>/dev/null)
[[ -z $wallets ]] && wallets=$(curl -s https://g1-stats.axiom-team.fr/data/wallets-g1-membres.txt)
work members && unset wallets
wallets=$(cat $WEBPATH/data/wallets-g1-simple.txt 2>/dev/null)
[[ -z $wallets ]] && wallets=$(curl -s https://g1-stats.axiom-team.fr/data/wallets-g1-simple.txt)
work && unset wallets
totalBalance=$(sort -nr <<<$totalBalance)
[[ ! -d $GPATH/db ]] && mkdir $GPATH/db
grep . <<<"$totalBalance" > $GPATH/db/wallets_balance.txt && rm /tmp/balance-g1.txt
# Construct HTML
cp $GPATH/tpl/css/wallets_balance.css $WEBPATH/css/
cp $GPATH/tpl/js/wallets_balance.js $WEBPATH/js/
cp $GPATH/tpl/wallets_balance.html $WEBPATH/data/wallets_balance.html
sort -Vr <<<"$htmlBloc" | awk '{ print "<tr id=\"p"NR"\"><td>"NR"</td>"$0"</tr>" ; }' > /tmp/solde_g1_html.txt
printf '%s\n' '/_LINE/r /tmp/solde_g1_html.txt' 1 '/_LINE/d' w | ed $WEBPATH/data/wallets_balance.html > /dev/null
sed -i "0,/_DATE/s//$(date '+%d-%m-%Y')/" $WEBPATH/data/wallets_balance.html
rm /tmp/solde_g1_html.txt

View File

@ -2,40 +2,12 @@
width: 98%;
margin-left: 0px;
overflow-x: scroll;
/* display: none; */
}
.chartWrapper {
position: relative;
background-color: #DFCFBE;
border-radius: 30px;
padding: 10px;
}
.chartWrapper > canvas {
position: absolute;
left: 0;
top: 0;
pointer-events:none;
}
.chartAreaWrapper {
overflow-x: scroll;
position: relative;
width: 100%;
height: 400px;
}
.chartAreaWrapper2 {
position: relative;
height: 300px;
width: 3000px;
}
@media only screen and (max-width: 1100px) {
#charts {
width: 95%;
}
#charts {
width: 95%;
}
}

View File

@ -1,55 +0,0 @@
body {
background-color: #c4a787;
margin-top: 10px;
margin-left: 20px;
font-family: "Gill Sans", sans-serif;
}
.date {
margin-left: 2px;
}
#pseudo, #key {
background-position: 10px 12px; /* Position the search icon */
background-repeat: no-repeat; /* Do not repeat the icon image */
width: 300px; /* Full-width */
font-size: 16px; /* Increase font-size */
padding: 12px 20px 12px 20px; /* Add some padding */
border: 1px solid #ddd; /* Add a grey border */
margin-bottom: 12px; /* Add some space below the input */
margin-top: 7px;
}
#soldes {
border-collapse: collapse; /* Collapse borders */
width: 50%; /* Full-width */
border: 1px solid #ddd; /* Add a grey border */
font-size: 16px; /* Increase font-size */
background-color: #DFCFBE;
}
#soldes th, #soldes td {
text-align: left; /* Left-align text */
padding: 8px; /* Add padding */
}
#soldes tr {
/* Add a bottom border to all table rows */
border-bottom: 1px solid #ddd;
}
#soldes tr:hover {
/* Add a grey background color to the table header and on hover */
background-color: #f1f1f1;
}
#soldes th {
/* Add a grey background color to the table header and on hover */
background-color: #B69776;
cursor: pointer;
top: 0px;
}
#splw {
margin-left: 20px;
}

134
tpl/graph.js Normal file
View File

@ -0,0 +1,134 @@
var jsonfileRW = $.getJSON( "daily.json", function(data) {
var date = jsonfileRW.responseJSON.map(function(e) {
return e.date;
});
var rwallets = jsonfileRW.responseJSON.map(function(e) {
return e.rWallets;
});
var rmembers = jsonfileRW.responseJSON.map(function(e) {
return e.rMembers;
});
var nbrwallets = jsonfileRW.responseJSON.map(function(e) {
return e.nbrWallets;
});
var nbrmembers = jsonfileRW.responseJSON.map(function(e) {
return e.nbrMembers;
});
//ReceivedGraph
var ctx = document.getElementById("chartRW");
var config = {
type: 'line',
data: {
labels: date,
datasets: [{
label: 'Ḡ1 reçus sur les simples portefeuilles',
data: rwallets,
backgroundColor: 'rgba(0, 119, 204, 0.3)',
pointBorderWidth: 1,
pointHoverRadius: 8,
pointHoverBackgroundColor: "beige",
pointHoverBorderColor: "brown",
pointHoverBorderWidth: 2,
pointRadius: 3,
pointHitRadius: 8
}, {
label: 'Ḡ1 reçus sur les portefeuilles membres',
data: rmembers,
backgroundColor: 'rgba(0, 178, 0, 0.3)',
pointBorderWidth: 1,
pointHoverRadius: 8,
pointHoverBackgroundColor: "beige",
pointHoverBorderColor: "brown",
pointHoverBorderWidth: 2,
pointRadius: 3,
pointHitRadius: 8
}]
},
options: {
maintainAspectRatio: true,
responsive: true
}
};
var myChartRW = new Chart(ctx, config);
// NbrWallets Graph
var ctx = document.getElementById("chartNBRW");
var config = {
type: 'line',
data: {
labels: date,
datasets: [{
label: 'Nombre de simple portefeuilles',
data: nbrwallets,
backgroundColor: 'rgba(0, 119, 204, 0.3)',
pointBorderWidth: 1,
pointHoverRadius: 8,
pointHoverBackgroundColor: "beige",
pointHoverBorderColor: "brown",
pointHoverBorderWidth: 2,
pointRadius: 3,
pointHitRadius: 8
}, {
label: 'Nombre de portefeuilles membres',
data: nbrmembers,
backgroundColor: 'rgba(0, 178, 0, 0.3)',
pointBorderWidth: 1,
pointHoverRadius: 8,
pointHoverBackgroundColor: "beige",
pointHoverBorderColor: "brown",
pointHoverBorderWidth: 2,
pointRadius: 3,
pointHitRadius: 8
}]
},
options: {
maintainAspectRatio: true,
responsive: true
}
};
var myChartNBRW = new Chart(ctx, config);
});
/*var jqxhr = $.getJSON( "example.json", function() {
console.log( "success" );
})
.done(function() {
console.log( "second success" );
})
.fail(function() {
console.log( "error" );
})
.always(function() {
console.log( "complete" );
});*/

View File

@ -16,8 +16,7 @@
| <a href="/data/daily.json">Voir le fichier JSON</a>
| <a href="/data/wallets-g1.txt">Liste de tous les wallets</a>
| <a href="/data/wallets-g1-membres.txt">Liste des wallets membres</a>
| <a href="/data/wallets-g1-simple.txt">Liste des simples portefeuilles</a>
| <a href="/data/wallets_balance.html">Classement FORBES</a> |
| <a href="/data/wallets-g1-simple.txt">Liste des simples portefeuilles</a> |
</center>
</div>

View File

@ -1,96 +0,0 @@
var jsonfileRW = $.getJSON( "../data/cum-daily.json", function(data) {
var date = jsonfileRW.responseJSON.map(function(e) {
return e.date;
});
var rwallets = jsonfileRW.responseJSON.map(function(e) {
return e.rWallets;
});
var rmembers = jsonfileRW.responseJSON.map(function(e) {
return e.rMembers;
});
var nbrwallets = jsonfileRW.responseJSON.map(function(e) {
return e.nbrWallets;
});
var nbrmembers = jsonfileRW.responseJSON.map(function(e) {
return e.nbrMembers;
});
//var optionsGen = 'pointBorderWidth: 1, pointHoverRadius: 6, pointHoverBackgroundColor: "beige", pointHoverBorderColor: "brown", pointHoverBorderWidth: 2, pointRadius: 1, pointHitRadius: 4';
//Received Graph
var ctx = document.getElementById("chartRW");
var config = {
type: 'line',
data: {
labels: date,
datasets: [{
label: 'Ḡ1 reçus sur les simples portefeuilles',
data: rwallets,
backgroundColor: 'rgba(0, 119, 204, 0.3)',
pointBorderWidth: 1,
pointHoverRadius: 6,
pointHoverBackgroundColor: "beige",
pointHoverBorderColor: "brown",
pointHoverBorderWidth: 2,
pointRadius: 1,
pointHitRadius: 4
}, {
label: 'Ḡ1 reçus sur les portefeuilles membres',
data: rmembers,
backgroundColor: 'rgba(0, 178, 0, 0.3)',
pointBorderWidth: 1,
pointHoverRadius: 6,
pointHoverBackgroundColor: "beige",
pointHoverBorderColor: "brown",
pointHoverBorderWidth: 2,
pointRadius: 1,
pointHitRadius: 4
}]
},
options: {
maintainAspectRatio: false,
responsive: true
}
};
var myChartRW = new Chart(ctx, config);
// NbrWallets Graph
var ctx = document.getElementById("chartNBRW");
var config = {
type: 'line',
data: {
labels: date,
datasets: [{
label: 'Nombre de simple portefeuilles',
data: nbrwallets,
backgroundColor: 'rgba(0, 119, 204, 0.3)',
pointBorderWidth: 1,
pointHoverRadius: 6,
pointHoverBackgroundColor: "beige",
pointHoverBorderColor: "brown",
pointHoverBorderWidth: 2,
pointRadius: 1,
pointHitRadius: 4
}, {
label: 'Nombre de portefeuilles membres',
data: nbrmembers,
backgroundColor: 'rgba(0, 178, 0, 0.3)',
pointBorderWidth: 1,
pointHoverRadius: 6,
pointHoverBackgroundColor: "beige",
pointHoverBorderColor: "brown",
pointHoverBorderWidth: 2,
pointRadius: 1,
pointHitRadius: 4
}]
},
options: {
maintainAspectRatio: true,
responsive: true
}
};
var myChartNBRW = new Chart(ctx, config);
});

View File

@ -1,72 +0,0 @@
const getCellValue = (tr, idx) => tr.children[idx].innerText || tr.children[idx].textContent;
const comparer = (idx, asc) => (a, b) => ((v1, v2) =>
v1 !== '' && v2 !== '' && !isNaN(v1) && !isNaN(v2) ? v1 - v2 : v1.toString().localeCompare(v2)
)(getCellValue(asc ? a : b, idx), getCellValue(asc ? b : a, idx));
// Sort work
document.querySelectorAll('th').forEach(th => th.addEventListener('click', (() => {
const table = th.closest('table');
Array.from(table.querySelectorAll('tr:nth-child(n+2)'))
.sort(comparer(Array.from(th.parentNode.children).indexOf(th), this.asc = !this.asc))
.forEach(tr => table.appendChild(tr) );
})));
// Search
function recherche(select) {
// Declare variables
var input, filter, table, tr, td, i, txtValue;
input = document.getElementById(select);
filter = input.value.toUpperCase();
table = document.getElementById("soldes");
tr = table.getElementsByTagName("tr");
// Loop through all table rows, and hide those who don't match the search query
for (i = 0; i < tr.length; i++) {
if (select == "pseudo") { td = tr[i].getElementsByTagName("td")[2]; }
else if (select == "key") { td = tr[i].getElementsByTagName("td")[1]; }
if (td) {
txtValue = td.textContent || td.innerText;
if (txtValue.toUpperCase().indexOf(filter) > -1) {
tr[i].style.display = "";
} else {
tr[i].style.display = "none";
}
}
}
}
// Affichage des simples portefeuilles
var checkWallets = document.querySelector('input[value="splw"]');
checkWallets.onchange = function() {
var table, tr, td, i, txtValue;
table = document.getElementById("soldes");
tr = table.getElementsByTagName("tr");
if(checkWallets.checked) {
for (i = 0; i < tr.length; i++) {
td = tr[i].getElementsByTagName("td")[2];
if (td) {
txtValue = td.textContent || td.innerText;
if (txtValue == " ") {
tr[i].style.display = "";
}
}
}
} else {
for (i = 0; i < tr.length; i++) {
td = tr[i].getElementsByTagName("td")[2];
if (td) {
txtValue = td.textContent || td.innerText;
if (txtValue == " ") {
tr[i].style.display = "none";
}
}
}
}
};

View File

@ -1,20 +0,0 @@
<html>
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="../css/wallets_balance.css">
</head>
<body>
<div class="date"> Données générées le _DATE<br></div>
<input type="text" id="pseudo" onkeyup="recherche('pseudo')" placeholder="Rechercher un pseudo...">
<input type="text" id="key" onkeyup="recherche('key')" placeholder="Rechercher une clé publique...">
<input type="checkbox" id="splw" value="splw" checked><label for="splw">Afficher les simples portefeuilles</label>
<table id="soldes">
<tr><th>Position</th><th>Solde (Ḡ1)</th><th>Clé publique</th><th>Identifiant utilisateur</th></tr>
_LINE
</table>
<script type="text/javascript" src="../js/wallets_balance.js"></script>
</body>
</html>