Large python refactor to use 'pynode' and Premium+ basics
This commit is contained in:
parent
cd06269f9c
commit
4a5fe2f73c
|
@ -8,6 +8,7 @@ After=network-online.target
|
|||
|
||||
[Service]
|
||||
Type=simple
|
||||
KillMode=control-group
|
||||
ExecStart=/usr/local/bin/python3 /usr/bin/mynode_check_in.py
|
||||
User=root
|
||||
Group=root
|
||||
|
|
|
@ -8,7 +8,10 @@ After=lnd.service
|
|||
|
||||
[Service]
|
||||
Type=simple
|
||||
ExecStart=/usr/bin/mynode_lnd_channel_backup.sh
|
||||
ExecStartPre=/usr/bin/is_not_shutting_down.sh
|
||||
ExecStartPre=/usr/bin/wait_on_bitcoin.sh
|
||||
ExecStartPre=/usr/bin/wait_on_lnd.sh
|
||||
ExecStart=/usr/local/bin/python3 /usr/bin/mynode_backup_scb.py
|
||||
Restart=always
|
||||
RestartSec=1
|
||||
User=bitcoin
|
||||
|
|
|
@ -2,17 +2,15 @@
|
|||
import time
|
||||
import os
|
||||
import subprocess
|
||||
import signal
|
||||
import logging
|
||||
from threading import Thread
|
||||
from systemd import journal
|
||||
from utilities import *
|
||||
from drive_info import *
|
||||
|
||||
log = logging.getLogger('mynode')
|
||||
log.addHandler(journal.JournaldLogHandler())
|
||||
log.setLevel(logging.INFO)
|
||||
|
||||
def log_message(msg):
|
||||
global log
|
||||
print(msg)
|
||||
log.info(msg)
|
||||
set_logger(log)
|
||||
|
||||
def set_clone_state(state):
|
||||
log_message("Clone State: {}".format(state))
|
||||
|
@ -49,74 +47,6 @@ def wait_on_clone_error_dismiss():
|
|||
while os.path.isfile("/tmp/.clone_error"):
|
||||
time.sleep(1)
|
||||
|
||||
def get_drive_size(drive):
|
||||
size = -1
|
||||
try:
|
||||
lsblk_output = subprocess.check_output(f"lsblk -b /dev/{drive} | grep disk", shell=True).decode("utf-8")
|
||||
parts = lsblk_output.split()
|
||||
size = int(parts[3])
|
||||
except:
|
||||
pass
|
||||
log_message(f"Drive {drive} size: {size}")
|
||||
return size
|
||||
|
||||
|
||||
def check_partition_for_mynode(partition):
|
||||
is_mynode = False
|
||||
try:
|
||||
subprocess.check_output(f"mount -o ro /dev/{partition} /mnt/hdd", shell=True)
|
||||
if os.path.isfile("/mnt/hdd/.mynode"):
|
||||
is_mynode = True
|
||||
except Exception as e:
|
||||
# Mount failed, could be target drive
|
||||
pass
|
||||
finally:
|
||||
time.sleep(1)
|
||||
os.system("umount /mnt/hdd")
|
||||
|
||||
return is_mynode
|
||||
|
||||
def find_partitions_for_drive(drive):
|
||||
partitions = []
|
||||
try:
|
||||
ls_output = subprocess.check_output(f"ls /sys/block/{drive}/ | grep {drive}", shell=True).decode("utf-8")
|
||||
partitions = ls_output.split()
|
||||
except:
|
||||
pass
|
||||
return partitions
|
||||
|
||||
def is_drive_detected_by_fdisk(d):
|
||||
detected = False
|
||||
try:
|
||||
# Command fails and throws exception if not mounted
|
||||
ls_output = subprocess.check_output(f"fdisk -l /dev/{d}", shell=True).decode("utf-8")
|
||||
detected = True
|
||||
except:
|
||||
pass
|
||||
return detected
|
||||
|
||||
def is_drive_mounted(d):
|
||||
mounted = True
|
||||
try:
|
||||
# Command fails and throws exception if not mounted
|
||||
ls_output = subprocess.check_output(f"grep -qs '/dev/{d}' /proc/mounts", shell=True).decode("utf-8")
|
||||
except:
|
||||
mounted = False
|
||||
return mounted
|
||||
|
||||
def find_drives():
|
||||
drives = []
|
||||
try:
|
||||
ls_output = subprocess.check_output("ls /sys/block/ | egrep 'hd.*|vd.*|sd.*|nvme.*'", shell=True).decode("utf-8")
|
||||
all_drives = ls_output.split()
|
||||
|
||||
# Only return drives that are not mounted (VM may have /dev/sda as OS drive)
|
||||
for d in all_drives:
|
||||
if is_drive_detected_by_fdisk(d) and not is_drive_mounted(d):
|
||||
drives.append(d)
|
||||
except:
|
||||
pass
|
||||
return drives
|
||||
|
||||
def main():
|
||||
# Set initial state
|
||||
|
@ -130,7 +60,7 @@ def main():
|
|||
os.system("rm /tmp/.clone_target_drive_has_mynode")
|
||||
|
||||
# Detect drives
|
||||
drives = find_drives()
|
||||
drives = find_unmounted_drives()
|
||||
log_message(f"Drives: {drives}")
|
||||
|
||||
# Check exactly two drives found
|
||||
|
|
143
rootfs/standard/usr/bin/mynode_backup_scb.py
Executable file
143
rootfs/standard/usr/bin/mynode_backup_scb.py
Executable file
|
@ -0,0 +1,143 @@
|
|||
#!/usr/local/bin/python3
|
||||
import os
|
||||
import requests
|
||||
import time
|
||||
import subprocess
|
||||
import logging
|
||||
import shutil
|
||||
from utilities import *
|
||||
from drive_info import *
|
||||
from device_info import *
|
||||
from inotify_simple import INotify, flags
|
||||
from systemd import journal
|
||||
import random
|
||||
|
||||
BACKUP_SCB_URL = "https://www.mynodebtc.com/device_api/backup_scb.php"
|
||||
|
||||
LND_MAINNET_CHANNEL_FILE = "/mnt/hdd/mynode/lnd/data/chain/bitcoin/mainnet/channel.backup"
|
||||
LND_MAINNET_CHANNEL_FILE_BACKUP = "/home/bitcoin/lnd_backup/channel.backup"
|
||||
LND_TESTNET_CHANNEL_FILE = "/mnt/hdd/mynode/lnd/data/chain/bitcoin/testnet/channel.backup"
|
||||
LND_TESTNET_CHANNEL_FILE_BACKUP = "/home/bitcoin/lnd_backup/channel_testnet.backup"
|
||||
|
||||
|
||||
log = logging.getLogger('lndbackup')
|
||||
log.addHandler(journal.JournaldLogHandler())
|
||||
log.setLevel(logging.INFO)
|
||||
set_logger(log)
|
||||
|
||||
# Helper functions
|
||||
|
||||
|
||||
# Local Backup
|
||||
def local_backup(original_scb, backup_scb):
|
||||
if os.path.isfile(original_scb):
|
||||
md5_1 = get_md5_file_hash(original_scb)
|
||||
md5_2 = "REPLACE_FILE"
|
||||
if os.path.isfile(backup_scb):
|
||||
md5_2 = get_md5_file_hash(backup_scb)
|
||||
|
||||
log_message(" Hash 1: {}".format(md5_1))
|
||||
log_message(" Hash 2: {}".format(md5_2))
|
||||
|
||||
# If file is missing or different, back it up!
|
||||
if md5_1 != md5_2:
|
||||
shutil.copyfile(original_scb, backup_scb)
|
||||
log_message("Local Backup: Backup Updated!")
|
||||
else:
|
||||
log_message("Local Backup: Hashes Match. Skipping Backup.")
|
||||
else:
|
||||
log_message("Local Backup: Missing File")
|
||||
|
||||
# Remote Backup
|
||||
def remote_backup(original, backup):
|
||||
|
||||
# Mainnet only
|
||||
if is_testnet_enabled():
|
||||
log_message("Remote Backup: Skipping (testnet enabled")
|
||||
return
|
||||
|
||||
# Premium+ Feature
|
||||
if not has_premium_plus_token() or get_premium_plus_token_status != "OK":
|
||||
log_message("Remote Backup: Skipping (not Premium+)")
|
||||
return
|
||||
|
||||
# POST Data
|
||||
data = {
|
||||
"token": get_premium_plus_token(),
|
||||
"product_key": get_product_key(),
|
||||
"scb_file": "REPLACE ME WITH FILE CONTENTS"
|
||||
}
|
||||
|
||||
# Setup tor proxy
|
||||
session = requests.session()
|
||||
session.proxies = {}
|
||||
session.proxies['http'] = 'socks5h://localhost:9050'
|
||||
session.proxies['https'] = 'socks5h://localhost:9050'
|
||||
|
||||
# Backup to server
|
||||
fail_count = 0
|
||||
backup_success = False
|
||||
while not backup_success:
|
||||
try:
|
||||
# Use tor for check in unless there have been tor 5 failures in a row
|
||||
r = None
|
||||
if (fail_count+1) % 5 == 0:
|
||||
r = requests.post(BACKUP_SCB_URL, data=data, timeout=20)
|
||||
else:
|
||||
r = session.post(BACKUP_SCB_URL, data=data, timeout=20)
|
||||
|
||||
if r.status_code == 200:
|
||||
if r.text == "OK":
|
||||
log_message("Remote Backup: Success ({})".format(r.text))
|
||||
else:
|
||||
log_message("Remote Backup: Error: ({})".format(r.text))
|
||||
backup_success = True
|
||||
else:
|
||||
log_message("Remote Backup: Connect Failed. Retrying... Code {}".format(r.status_code))
|
||||
except Exception as e:
|
||||
log_message("Remote Backup: Connect Failed. Retrying... Exception {}".format(e))
|
||||
|
||||
if not backup_success:
|
||||
# Check in failed, try again in 1 minute
|
||||
time.sleep(60)
|
||||
fail_count = fail_count + 1
|
||||
|
||||
return True
|
||||
|
||||
def backup(original_scb, backup_scb):
|
||||
log_message("Backing up SCB file...")
|
||||
local_backup(original_scb, backup_scb)
|
||||
remote_backup(original_scb, backup_scb)
|
||||
log_message("Backup Complete.")
|
||||
|
||||
# Backup SCB file
|
||||
if __name__ == "__main__":
|
||||
one_hour_in_ms = 60 * 60 * 1000
|
||||
|
||||
while True:
|
||||
try:
|
||||
# Wait for drive to be mounted
|
||||
while not is_mynode_drive_mounted():
|
||||
log_message("Checking if drive mounted...")
|
||||
time.sleep(10)
|
||||
log_message("Drive mounted!")
|
||||
|
||||
# Determine backup file
|
||||
original_scb = LND_MAINNET_CHANNEL_FILE
|
||||
backup_scb = LND_MAINNET_CHANNEL_FILE_BACKUP
|
||||
if is_testnet_enabled():
|
||||
original_scb = LND_TESTNET_CHANNEL_FILE
|
||||
backup_scb = LND_TESTNET_CHANNEL_FILE_BACKUP
|
||||
|
||||
# Perform backup
|
||||
backup(original_scb, backup_scb)
|
||||
|
||||
# Watch for updates
|
||||
inotify = INotify()
|
||||
watch_flags = flags.CREATE | flags.DELETE | flags.MODIFY | flags.DELETE_SELF
|
||||
wd = inotify.add_watch(original_scb, watch_flags)
|
||||
for event in inotify.read(timeout=one_hour_in_ms):
|
||||
log_message("File changed: " + str(event))
|
||||
except Exception as e:
|
||||
log_message("Error: {}".format(e))
|
||||
time.sleep(60)
|
|
@ -4,79 +4,17 @@ import requests
|
|||
import time
|
||||
import subprocess
|
||||
import random
|
||||
from drive_info import *
|
||||
from device_info import *
|
||||
|
||||
CHECKIN_URL = "https://www.mynodebtc.com/device_api/check_in.php"
|
||||
|
||||
latest_version_check_count = 0
|
||||
|
||||
# Helper functions
|
||||
def unset_skipped_product_key():
|
||||
os.system("rm -rf /home/bitcoin/.mynode/.product_key_skipped")
|
||||
os.system("rm -rf /mnt/hdd/mynode/settings/.product_key_skipped")
|
||||
def delete_product_key_error():
|
||||
os.system("rm -rf /home/bitcoin/.mynode/.product_key_error")
|
||||
os.system("rm -rf /mnt/hdd/mynode/settings/.product_key_error")
|
||||
def has_product_key_error():
|
||||
if os.path.isfile("/home/bitcoin/.mynode/.product_key_error") or os.path.isfile("/mnt/hdd/mynode/settings/.product_key_error"):
|
||||
return True
|
||||
return False
|
||||
def get_current_version():
|
||||
current_version = "0.0"
|
||||
try:
|
||||
with open("/usr/share/mynode/version", "r") as f:
|
||||
current_version = f.read().strip()
|
||||
except:
|
||||
current_version = "error"
|
||||
return current_version
|
||||
def get_device_type():
|
||||
device = subprocess.check_output("mynode-get-device-type", shell=True).decode("utf-8").strip()
|
||||
return device
|
||||
def get_device_arch():
|
||||
arch = subprocess.check_output("uname -m", shell=True).decode("utf-8").strip()
|
||||
return arch
|
||||
def get_device_serial():
|
||||
serial = subprocess.check_output("mynode-get-device-serial", shell=True).decode("utf-8").strip()
|
||||
return serial
|
||||
def skipped_product_key():
|
||||
return os.path.isfile("/home/bitcoin/.mynode/.product_key_skipped") or \
|
||||
os.path.isfile("/mnt/hdd/mynode/settings/.product_key_skipped")
|
||||
def has_product_key():
|
||||
return os.path.isfile("/home/bitcoin/.mynode/.product_key")
|
||||
def get_product_key():
|
||||
product_key = "no_product_key"
|
||||
if skipped_product_key():
|
||||
return "community_edition"
|
||||
|
||||
if not has_product_key():
|
||||
return "product_key_missing"
|
||||
|
||||
try:
|
||||
with open("/home/bitcoin/.mynode/.product_key", "r") as f:
|
||||
product_key = f.read().strip()
|
||||
except:
|
||||
product_key = "product_key_error"
|
||||
return product_key
|
||||
def is_drive_mounted():
|
||||
mounted = True
|
||||
try:
|
||||
# Command fails and throws exception if not mounted
|
||||
output = subprocess.check_output(f"grep -qs '/mnt/hdd ext4' /proc/mounts", shell=True).decode("utf-8")
|
||||
except:
|
||||
mounted = False
|
||||
return mounted
|
||||
def get_drive_size():
|
||||
size = -1
|
||||
if not is_drive_mounted():
|
||||
return -3
|
||||
try:
|
||||
size = subprocess.check_output("df /mnt/hdd | grep /dev | awk '{print $2}'", shell=True).strip()
|
||||
size = int(size) / 1000 / 1000
|
||||
except Exception as e:
|
||||
size = -2
|
||||
return size
|
||||
def get_quicksync_enabled():
|
||||
enabled = 1
|
||||
if not is_drive_mounted():
|
||||
if not is_mynode_drive_mounted():
|
||||
return -3
|
||||
if os.path.isfile("/mnt/hdd/mynode/settings/quicksync_disabled"):
|
||||
enabled = 0
|
||||
|
@ -117,7 +55,7 @@ def check_in():
|
|||
"device_arch": get_device_arch(),
|
||||
"version": get_current_version(),
|
||||
"product_key": product_key,
|
||||
"drive_size": get_drive_size(),
|
||||
"drive_size": get_mynode_drive_size(),
|
||||
"quicksync_enabled": get_quicksync_enabled(),
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#!/bin/bash
|
||||
# NO LONGER USED - MIGRATED TO PYTHON
|
||||
|
||||
source /usr/share/mynode/mynode_config.sh
|
||||
|
||||
|
|
|
@ -206,12 +206,15 @@ if ! skip_base_upgrades ; then
|
|||
[ -d /usr/local/lib/python3.8/site-packages ] && echo "/var/pynode" > /usr/local/lib/python3.8/site-packages/pynode.pth
|
||||
|
||||
# Remove old python files so new copies are used (files migrated to pynode)
|
||||
set +x
|
||||
PYNODE_FILES="/var/pynode/*.py"
|
||||
for pynode_file in $PYNODE_FILES
|
||||
do
|
||||
echo "Migrating pynode file $pynode_file..."
|
||||
pynode_file="$(basename -- $pynode_file)"
|
||||
rm -f /var/www/mynode/$pynode_file*
|
||||
rm -f /var/www/mynode/${pynode_file} # .py
|
||||
rm -f /var/www/mynode/${pynode_file}c # .pyc
|
||||
done
|
||||
set -x
|
||||
|
||||
|
||||
# Install any pip3 software
|
||||
|
|
|
@ -6,99 +6,25 @@ import subprocess
|
|||
import logging
|
||||
from inotify_simple import INotify, flags
|
||||
from systemd import journal
|
||||
import random
|
||||
from utilities import *
|
||||
from device_info import *
|
||||
from drive_info import *
|
||||
|
||||
|
||||
PREMIUM_PLUS_CONNECT_URL = "https://www.mynodebtc.com/device_api/premium_plus_connect.php"
|
||||
|
||||
log = logging.getLogger('premium_plus_connect')
|
||||
log.addHandler(journal.JournaldLogHandler())
|
||||
log.setLevel(logging.INFO)
|
||||
set_logger(log)
|
||||
|
||||
# Helper functions
|
||||
def log_message(msg):
|
||||
global log
|
||||
print(msg)
|
||||
log.info(msg)
|
||||
|
||||
def set_premium_plus_token_error(msg):
|
||||
os.system("echo '{}' > /home/bitcoin/.mynode/.premium_plus_token_error".format(msg))
|
||||
def delete_premium_plus_token_error():
|
||||
os.system("rm -rf /home/bitcoin/.mynode/.premium_plus_token_error")
|
||||
os.system("rm -rf /mnt/hdd/mynode/settings/.premium_plus_token_error")
|
||||
def has_premium_plus_token_error():
|
||||
if os.path.isfile("/home/bitcoin/.mynode/.premium_plus_token_error") or \
|
||||
os.path.isfile("/mnt/hdd/mynode/settings/.premium_plus_token_error"):
|
||||
return True
|
||||
return False
|
||||
|
||||
def get_current_version():
|
||||
current_version = "0.0"
|
||||
try:
|
||||
with open("/usr/share/mynode/version", "r") as f:
|
||||
current_version = f.read().strip()
|
||||
except:
|
||||
current_version = "error"
|
||||
return current_version
|
||||
def get_device_type():
|
||||
device = subprocess.check_output("mynode-get-device-type", shell=True).decode("utf-8").strip()
|
||||
return device
|
||||
def get_device_arch():
|
||||
arch = subprocess.check_output("uname -m", shell=True).decode("utf-8").strip()
|
||||
return arch
|
||||
def get_device_serial():
|
||||
serial = subprocess.check_output("mynode-get-device-serial", shell=True).decode("utf-8").strip()
|
||||
return serial
|
||||
def has_premium_plus_token():
|
||||
return os.path.isfile("/home/bitcoin/.mynode/.premium_plus_token") or \
|
||||
os.path.isfile("/mnt/hdd/mynode/settings/.premium_plus_token")
|
||||
def get_premium_plus_token():
|
||||
token = "no_token"
|
||||
if not has_premium_plus_token():
|
||||
return "no_token"
|
||||
|
||||
try:
|
||||
if os.path.isfile("/home/bitcoin/.mynode/.premium_plus_token"):
|
||||
with open("/home/bitcoin/.mynode/.premium_plus_token", "r") as f:
|
||||
token = f.read().strip()
|
||||
elif os.path.isfile("/mnt/hdd/mynode/settings/.premium_plus_token"):
|
||||
with open("/mnt/hdd/mynode/settings/.premium_plus_token", "r") as f:
|
||||
token = f.read().strip()
|
||||
except:
|
||||
token = "token_error"
|
||||
return token
|
||||
def get_product_key():
|
||||
try:
|
||||
with open("/home/bitcoin/.mynode/.product_key", "r") as f:
|
||||
product_key = f.read().strip()
|
||||
except:
|
||||
product_key = "product_key_error"
|
||||
return product_key
|
||||
def is_drive_mounted():
|
||||
mounted = True
|
||||
try:
|
||||
# Command fails and throws exception if not mounted
|
||||
output = subprocess.check_output(f"grep -qs '/mnt/hdd ext4' /proc/mounts", shell=True).decode("utf-8")
|
||||
except:
|
||||
mounted = False
|
||||
return mounted
|
||||
def get_drive_size():
|
||||
size = -1
|
||||
if not is_drive_mounted():
|
||||
return -3
|
||||
try:
|
||||
size = subprocess.check_output("df /mnt/hdd | grep /dev | awk '{print $2}'", shell=True).strip()
|
||||
size = int(size) / 1000 / 1000
|
||||
except Exception as e:
|
||||
size = -2
|
||||
return size
|
||||
def get_drive_usage():
|
||||
return "TODO"
|
||||
|
||||
# Update hourly
|
||||
def premium_plus_connect():
|
||||
|
||||
# Check in
|
||||
token = get_premium_plus_token()
|
||||
data = {
|
||||
"serial": get_device_serial(),
|
||||
"device_type": get_device_type(),
|
||||
|
@ -106,8 +32,8 @@ def premium_plus_connect():
|
|||
"version": get_current_version(),
|
||||
"token": get_premium_plus_token(),
|
||||
"product_key": get_product_key(),
|
||||
"drive_size": get_drive_size(),
|
||||
"drive_usage": get_drive_usage(),
|
||||
"drive_size": get_mynode_drive_size(),
|
||||
"drive_usage": get_mynode_drive_usage(),
|
||||
}
|
||||
|
||||
# Setup tor proxy
|
||||
|
@ -129,10 +55,10 @@ def premium_plus_connect():
|
|||
r = session.post(PREMIUM_PLUS_CONNECT_URL, data=data, timeout=20)
|
||||
|
||||
if r.status_code == 200:
|
||||
set_premium_plus_token_status(r.text)
|
||||
if r.text == "OK":
|
||||
log_message("Premium+ Connect Success: {}".format(r.text))
|
||||
else:
|
||||
set_premium_plus_token_error(r.text)
|
||||
log_message("Check In Returned Error: {}".format(r.text))
|
||||
|
||||
os.system("rm -f /tmp/premium_plus_connect_error")
|
||||
|
@ -142,9 +68,11 @@ def premium_plus_connect():
|
|||
except Exception as e:
|
||||
log_message("Premium+ Connect Failed. Retrying... Exception {}".format(e))
|
||||
|
||||
update_premium_plus_last_sync_time()
|
||||
|
||||
if not premium_plus_connect_success:
|
||||
# Check in failed, try again in 1 minute
|
||||
os.system("touch /tmp/premium_plus_connect_error")
|
||||
set_premium_plus_token_status("CONNECTION_ERROR")
|
||||
time.sleep(60)
|
||||
fail_count = fail_count + 1
|
||||
|
||||
|
@ -157,26 +85,27 @@ if __name__ == "__main__":
|
|||
while True:
|
||||
try:
|
||||
# Wait for drive to be mounted
|
||||
while not is_drive_mounted():
|
||||
while not is_mynode_drive_mounted():
|
||||
log_message("Checking if drive mounted...")
|
||||
time.sleep(10)
|
||||
log_message("Drive mounted!")
|
||||
|
||||
# Wait on token
|
||||
log_message("Waiting on Premium+ Token")
|
||||
log_message("Looking for Premium+ Token...")
|
||||
while not os.path.isfile("/home/bitcoin/.mynode/.premium_plus_token"):
|
||||
time.sleep(10)
|
||||
log_message("Token found!")
|
||||
premium_plus_connect()
|
||||
|
||||
# Watch for updates
|
||||
log_message("")
|
||||
log_message("Watching for file changes or 1hr...")
|
||||
inotify = INotify()
|
||||
watch_flags = flags.CREATE | flags.DELETE | flags.MODIFY | flags.DELETE_SELF
|
||||
wd = inotify.add_watch('/home/bitcoin/.mynode/', watch_flags)
|
||||
for event in inotify.read(timeout=one_hour_in_ms):
|
||||
log_message("File changed: " + str(event))
|
||||
log_message("Running connect again: " + str(event))
|
||||
premium_plus_connect()
|
||||
except Exception as e:
|
||||
log_message("Error: {}".format(e))
|
||||
time.sleep(60)
|
||||
|
|
|
@ -78,6 +78,11 @@ rm -rf /etc/motd # Remove simple motd for update-motd.d
|
|||
mkdir -p /mnt/hdd
|
||||
mkdir -p /mnt/usb_extras
|
||||
|
||||
# Add to python path
|
||||
[ -d /usr/local/lib/python2.7/dist-packages ] && echo "/var/pynode" > /usr/local/lib/python2.7/dist-packages/pynode.pth
|
||||
[ -d /usr/local/lib/python3.7/site-packages ] && echo "/var/pynode" > /usr/local/lib/python3.7/site-packages/pynode.pth
|
||||
[ -d /usr/local/lib/python3.8/site-packages ] && echo "/var/pynode" > /usr/local/lib/python3.8/site-packages/pynode.pth
|
||||
|
||||
# Customize logo for resellers
|
||||
if [ -f /opt/mynode/custom/logo_custom.png ]; then
|
||||
cp -f /opt/mynode/custom/logo_custom.png /var/www/mynode/static/images/logo_custom.png
|
||||
|
|
|
@ -2,20 +2,20 @@
|
|||
import time
|
||||
import os
|
||||
import subprocess
|
||||
import signal
|
||||
import logging
|
||||
import random
|
||||
import string
|
||||
import json
|
||||
import atexit
|
||||
from http.server import HTTPServer, SimpleHTTPRequestHandler
|
||||
import pyudev
|
||||
from systemd import journal
|
||||
from threading import Thread
|
||||
from utilities import *
|
||||
from drive_info import *
|
||||
|
||||
log = logging.getLogger('mynode')
|
||||
log.addHandler(journal.JournaldLogHandler())
|
||||
log.setLevel(logging.INFO)
|
||||
set_logger(log)
|
||||
|
||||
################################
|
||||
## USB Device Cache
|
||||
|
@ -54,12 +54,6 @@ def write_usb_devices_json():
|
|||
################################
|
||||
## Utility Functions
|
||||
################################
|
||||
|
||||
def log_message(msg):
|
||||
global log
|
||||
print(msg)
|
||||
log.info(msg)
|
||||
|
||||
def set_usb_extras_state(state):
|
||||
log_message("USB Extras State: {}".format(state))
|
||||
try:
|
||||
|
@ -71,71 +65,6 @@ def set_usb_extras_state(state):
|
|||
return False
|
||||
return False
|
||||
|
||||
def get_drive_size(drive):
|
||||
size = -1
|
||||
try:
|
||||
lsblk_output = subprocess.check_output(f"lsblk -b /dev/{drive} | grep disk", shell=True).decode("utf-8")
|
||||
parts = lsblk_output.split()
|
||||
size = int(parts[3])
|
||||
except:
|
||||
pass
|
||||
log_message(f"Drive {drive} size: {size}")
|
||||
return size
|
||||
|
||||
def mount_partition(partition, folder_name, permissions="ro"):
|
||||
try:
|
||||
subprocess.check_output(f"mkdir -p /mnt/usb_extras/{folder_name}", shell=True)
|
||||
subprocess.check_output(f"mount -o {permissions} /dev/{partition} /mnt/usb_extras/{folder_name}", shell=True)
|
||||
return True
|
||||
except Exception as e:
|
||||
return False
|
||||
|
||||
def unmount_partition(folder_name):
|
||||
os.system(f"umount /mnt/usb_extras/{folder_name}")
|
||||
os.system(f"rm -rf /mnt/usb_extras/{folder_name}")
|
||||
time.sleep(1)
|
||||
|
||||
def find_partitions_for_drive(drive):
|
||||
partitions = []
|
||||
try:
|
||||
ls_output = subprocess.check_output(f"ls /sys/block/{drive}/ | grep {drive}", shell=True).decode("utf-8")
|
||||
partitions = ls_output.split()
|
||||
except:
|
||||
pass
|
||||
return partitions
|
||||
|
||||
def is_drive_detected_by_fdisk(d):
|
||||
detected = False
|
||||
try:
|
||||
# Command fails and throws exception if not mounted
|
||||
ls_output = subprocess.check_output(f"fdisk -l /dev/{d}", shell=True).decode("utf-8")
|
||||
detected = True
|
||||
except:
|
||||
pass
|
||||
return detected
|
||||
|
||||
def is_drive_mounted(d):
|
||||
mounted = True
|
||||
try:
|
||||
# Command fails and throws exception if not mounted
|
||||
ls_output = subprocess.check_output(f"grep -qs '/dev/{d}' /proc/mounts", shell=True).decode("utf-8")
|
||||
except:
|
||||
mounted = False
|
||||
return mounted
|
||||
|
||||
def find_unmounted_drives():
|
||||
drives = []
|
||||
try:
|
||||
ls_output = subprocess.check_output("ls /sys/block/ | egrep 'hd.*|vd.*|sd.*|nvme.*'", shell=True).decode("utf-8")
|
||||
all_drives = ls_output.split()
|
||||
|
||||
# Only return drives that are not mounted (VM may have /dev/sda as OS drive)
|
||||
for d in all_drives:
|
||||
if is_drive_detected_by_fdisk(d) and not is_drive_mounted(d):
|
||||
drives.append(d)
|
||||
except:
|
||||
pass
|
||||
return drives
|
||||
|
||||
################################
|
||||
## HTTP Server Functions
|
||||
|
|
|
@ -290,11 +290,11 @@
|
|||
"short_name": "premium_plus",
|
||||
"hide_status_icon": true,
|
||||
"can_enable_disable": false,
|
||||
"app_tile_button_text": "Open",
|
||||
"app_tile_button_text": "Manage",
|
||||
"app_tile_default_status_text": "Access and Backup",
|
||||
"app_tile_button_href": "/premium_plus",
|
||||
"app_tile_button_href": "/premium-plus",
|
||||
"show_on_application_page": false,
|
||||
"show_on_homepage": false,
|
||||
"show_on_homepage": true,
|
||||
"can_uninstall": false,
|
||||
"can_reinstall": false,
|
||||
"journalctl_log_name": "premium_plus_connect",
|
||||
|
|
|
@ -81,7 +81,7 @@ def check_and_mark_reboot_action(tmp_marker):
|
|||
def reload_throttled_data():
|
||||
global cached_data
|
||||
if os.path.isfile("/tmp/get_throttled_data"):
|
||||
cached_data["get_throttled_data"] = get_file_contents("/tmp/get_throttled_data")
|
||||
cached_data["get_throttled_data"] = to_string( get_file_contents("/tmp/get_throttled_data") )
|
||||
|
||||
def get_throttled_data():
|
||||
global cached_data
|
||||
|
@ -207,7 +207,7 @@ def cleanup_log(log):
|
|||
return log
|
||||
|
||||
def get_recent_upgrade_log():
|
||||
log = get_file_contents("/home/admin/upgrade_logs/upgrade_log_latest.txt").decode("utf8")
|
||||
log = to_string( get_file_contents("/home/admin/upgrade_logs/upgrade_log_latest.txt") )
|
||||
return cleanup_log(log)
|
||||
|
||||
def get_all_upgrade_logs():
|
||||
|
@ -237,7 +237,7 @@ def get_all_upgrade_logs():
|
|||
log["name"] = f
|
||||
modTimeSeconds = os.path.getmtime(fullpath)
|
||||
log["date"] = time.strftime('%Y-%m-%d', time.localtime(modTimeSeconds))
|
||||
log["log"] = cleanup_log( get_file_contents(fullpath).decode("utf8") )
|
||||
log["log"] = cleanup_log( to_string( get_file_contents(fullpath) ) )
|
||||
log_list.append( log )
|
||||
log_id += 1
|
||||
except Exception as e:
|
||||
|
@ -362,7 +362,7 @@ def set_swap_size(size):
|
|||
return set_file_contents("/mnt/hdd/mynode/settings/swap_size", size)
|
||||
|
||||
def get_swap_size():
|
||||
return get_file_contents("/mnt/hdd/mynode/settings/swap_size")
|
||||
return to_string( get_file_contents("/mnt/hdd/mynode/settings/swap_size") )
|
||||
|
||||
#==================================
|
||||
# myNode Status
|
||||
|
@ -423,19 +423,19 @@ CLONE_STATE_IN_PROGRESS = "in_progress"
|
|||
CLONE_STATE_COMPLETE = "complete"
|
||||
|
||||
def get_clone_state():
|
||||
return get_file_contents("/tmp/.clone_state")
|
||||
return to_string( get_file_contents("/tmp/.clone_state") )
|
||||
|
||||
def get_clone_error():
|
||||
return get_file_contents("/tmp/.clone_error")
|
||||
return to_string( get_file_contents("/tmp/.clone_error") )
|
||||
|
||||
def get_clone_progress():
|
||||
return get_file_contents("/tmp/.clone_progress")
|
||||
return to_string( get_file_contents("/tmp/.clone_progress") )
|
||||
|
||||
def get_clone_source_drive():
|
||||
return get_file_contents("/tmp/.clone_source")
|
||||
return to_string( get_file_contents("/tmp/.clone_source") )
|
||||
|
||||
def get_clone_target_drive():
|
||||
return get_file_contents("/tmp/.clone_target")
|
||||
return to_string( get_file_contents("/tmp/.clone_target") )
|
||||
|
||||
def get_clone_target_drive_has_mynode():
|
||||
return os.path.isfile("/tmp/.clone_target_drive_has_mynode")
|
||||
|
@ -563,7 +563,7 @@ def regen_https_cert():
|
|||
|
||||
def get_flask_secret_key():
|
||||
if os.path.isfile("/home/bitcoin/.mynode/flask_secret_key"):
|
||||
key = get_file_contents("/home/bitcoin/.mynode/flask_secret_key")
|
||||
key = to_string( get_file_contents("/home/bitcoin/.mynode/flask_secret_key") )
|
||||
else:
|
||||
letters = string.ascii_letters
|
||||
key = ''.join(random.choice(letters) for i in range(32))
|
||||
|
@ -573,7 +573,7 @@ def get_flask_secret_key():
|
|||
def get_flask_session_timeout():
|
||||
try:
|
||||
if os.path.isfile("/home/bitcoin/.mynode/flask_session_timeout"):
|
||||
timeout = get_file_contents("/home/bitcoin/.mynode/flask_session_timeout")
|
||||
timeout = to_string( get_file_contents("/home/bitcoin/.mynode/flask_session_timeout") )
|
||||
parts = timeout.split(",")
|
||||
d = parts[0]
|
||||
h = parts[1]
|
||||
|
@ -607,21 +607,6 @@ def set_www_python3(use_python3):
|
|||
delete_file("/home/bitcoin/.mynode/.www_use_python3")
|
||||
|
||||
|
||||
#==================================
|
||||
# Drive Functions
|
||||
#==================================
|
||||
def is_uas_usb_enabled():
|
||||
return os.path.isfile('/home/bitcoin/.mynode/.uas_usb_enabled') or \
|
||||
os.path.isfile('/mnt/hdd/mynode/settings/.uas_usb_enabled')
|
||||
|
||||
def set_uas_usb_enabled(use_uas):
|
||||
if use_uas:
|
||||
touch("/home/bitcoin/.mynode/.uas_usb_enabled")
|
||||
touch("/mnt/hdd/mynode/settings/.uas_usb_enabled")
|
||||
else:
|
||||
delete_file("/home/bitcoin/.mynode/.uas_usb_enabled")
|
||||
delete_file("/mnt/hdd/mynode/settings/.uas_usb_enabled")
|
||||
|
||||
#==================================
|
||||
# Web Server Functions
|
||||
#==================================
|
||||
|
@ -743,6 +728,74 @@ def recheck_product_key():
|
|||
os.system("systemctl restart check_in")
|
||||
|
||||
|
||||
#==================================
|
||||
# Premium+ Token Functions
|
||||
#==================================
|
||||
def delete_premium_plus_token():
|
||||
delete_file("/home/bitcoin/.mynode/.premium_plus_token")
|
||||
delete_file("/mnt/hdd/mynode/settings/.premium_plus_token")
|
||||
def has_premium_plus_token():
|
||||
return os.path.isfile("/home/bitcoin/.mynode/.premium_plus_token") or \
|
||||
os.path.isfile("/mnt/hdd/mynode/settings/.premium_plus_token")
|
||||
def get_premium_plus_token():
|
||||
token = "error_1"
|
||||
if not has_premium_plus_token():
|
||||
return ""
|
||||
|
||||
try:
|
||||
if os.path.isfile("/home/bitcoin/.mynode/.premium_plus_token"):
|
||||
with open("/home/bitcoin/.mynode/.premium_plus_token", "r") as f:
|
||||
token = f.read().strip()
|
||||
elif os.path.isfile("/mnt/hdd/mynode/settings/.premium_plus_token"):
|
||||
with open("/mnt/hdd/mynode/settings/.premium_plus_token", "r") as f:
|
||||
token = f.read().strip()
|
||||
except:
|
||||
token = "error_2"
|
||||
return token
|
||||
def reset_premium_plus_token_status():
|
||||
delete_file("/home/bitcoin/.mynode/.premium_plus_token_status")
|
||||
def set_premium_plus_token_status(msg):
|
||||
os.system("echo '{}' > /home/bitcoin/.mynode/.premium_plus_token_status".format(msg))
|
||||
def get_premium_plus_token_status():
|
||||
status = "UNKNOWN"
|
||||
if not has_premium_plus_token():
|
||||
return "No Token Set"
|
||||
if not os.path.isfile("/home/bitcoin/.mynode/.premium_plus_token_status"):
|
||||
return "Updating..."
|
||||
try:
|
||||
with open("/home/bitcoin/.mynode/.premium_plus_token_status", "r") as f:
|
||||
status = f.read().strip()
|
||||
except:
|
||||
status = "STATUS_ERROR_2"
|
||||
return status
|
||||
def get_premium_plus_is_connected():
|
||||
status = get_premium_plus_token_status()
|
||||
if status == "OK":
|
||||
return True
|
||||
return False
|
||||
def update_premium_plus_last_sync_time():
|
||||
t = int(round(time.time()))
|
||||
os.system("echo '{}' > /home/bitcoin/.mynode/.premium_plus_last_sync".format(t))
|
||||
def get_premium_plus_last_sync():
|
||||
try:
|
||||
now = int(round(time.time()))
|
||||
last = int(get_file_contents("/home/bitcoin/.mynode/.premium_plus_last_sync"))
|
||||
diff_min = int((now - last) / 60)
|
||||
if diff_min == 0:
|
||||
return "Now"
|
||||
else:
|
||||
return "{} minutes(s) ago".format(diff_min)
|
||||
except Exception as e:
|
||||
return "Unknown"
|
||||
def save_premium_plus_token(token):
|
||||
set_file_contents("/home/bitcoin/.mynode/.premium_plus_token", token)
|
||||
set_file_contents("/mnt/hdd/mynode/settings/.premium_plus_token", token)
|
||||
|
||||
def recheck_premium_plus_token():
|
||||
reset_premium_plus_token_status()
|
||||
os.system("systemctl restart premium_plus_connect")
|
||||
|
||||
|
||||
#==================================
|
||||
# Drive Repair Functions
|
||||
#==================================
|
137
rootfs/standard/var/pynode/drive_info.py
Normal file
137
rootfs/standard/var/pynode/drive_info.py
Normal file
|
@ -0,0 +1,137 @@
|
|||
from config import *
|
||||
from utilities import *
|
||||
import time
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
import random
|
||||
import string
|
||||
import re
|
||||
|
||||
|
||||
#==================================
|
||||
# Drive Functions
|
||||
#==================================
|
||||
def is_mynode_drive_mounted():
|
||||
mounted = True
|
||||
try:
|
||||
# Command fails and throws exception if not mounted
|
||||
output = to_string(subprocess.check_output("grep -qs '/mnt/hdd ext4' /proc/mounts", shell=True))
|
||||
except:
|
||||
mounted = False
|
||||
return mounted
|
||||
|
||||
def is_device_mounted(d):
|
||||
mounted = True
|
||||
try:
|
||||
# Command fails and throws exception if not mounted
|
||||
ls_output = to_string(subprocess.check_output("grep -qs '/dev/{}' /proc/mounts".format(d), shell=True))
|
||||
except:
|
||||
mounted = False
|
||||
return mounted
|
||||
|
||||
def get_drive_size(drive):
|
||||
size = -1
|
||||
try:
|
||||
lsblk_output = to_string(subprocess.check_output("lsblk -b /dev/{} | grep disk".format(drive), shell=True))
|
||||
parts = lsblk_output.split()
|
||||
size = int(parts[3])
|
||||
except:
|
||||
pass
|
||||
#log_message(f"Drive {drive} size: {size}")
|
||||
return size
|
||||
|
||||
def get_mynode_drive_size():
|
||||
size = -1
|
||||
if not is_mynode_drive_mounted():
|
||||
return -3
|
||||
try:
|
||||
size = to_string(subprocess.check_output("df /mnt/hdd | grep /dev | awk '{print $2}'", shell=True)).strip()
|
||||
size = int(size) / 1000 / 1000
|
||||
except Exception as e:
|
||||
size = -2
|
||||
return size
|
||||
|
||||
def get_mynode_drive_usage():
|
||||
return "TODO"
|
||||
|
||||
def check_partition_for_mynode(partition):
|
||||
is_mynode = False
|
||||
try:
|
||||
subprocess.check_output("mount -o ro /dev/{} /mnt/hdd".format(partition), shell=True)
|
||||
if os.path.isfile("/mnt/hdd/.mynode"):
|
||||
is_mynode = True
|
||||
except Exception as e:
|
||||
# Mount failed, could be target drive
|
||||
pass
|
||||
finally:
|
||||
time.sleep(1)
|
||||
os.system("umount /mnt/hdd")
|
||||
|
||||
return is_mynode
|
||||
|
||||
def find_partitions_for_drive(drive):
|
||||
partitions = []
|
||||
try:
|
||||
ls_output = to_string(subprocess.check_output("ls /sys/block/{}/ | grep {}".format(drive, drive), shell=True))
|
||||
partitions = ls_output.split()
|
||||
except:
|
||||
pass
|
||||
return partitions
|
||||
|
||||
def is_device_detected_by_fdisk(d):
|
||||
detected = False
|
||||
try:
|
||||
# Command fails and throws exception if not mounted
|
||||
output = to_string(subprocess.check_output("fdisk -l /dev/{}".format(d), shell=True))
|
||||
detected = True
|
||||
except:
|
||||
pass
|
||||
return detected
|
||||
|
||||
def find_unmounted_drives():
|
||||
drives = []
|
||||
try:
|
||||
ls_output = subprocess.check_output("ls /sys/block/ | egrep 'hd.*|vd.*|sd.*|nvme.*'", shell=True).decode("utf-8")
|
||||
all_drives = ls_output.split()
|
||||
|
||||
# Only return drives that are not mounted (VM may have /dev/sda as OS drive)
|
||||
for d in all_drives:
|
||||
if is_device_detected_by_fdisk(d) and not is_device_mounted(d):
|
||||
drives.append(d)
|
||||
except:
|
||||
pass
|
||||
return drives
|
||||
|
||||
|
||||
#==================================
|
||||
# Mount / Unmount Parition Functions
|
||||
#==================================
|
||||
def mount_partition(partition, folder_name, permissions="ro"):
|
||||
try:
|
||||
subprocess.check_output("mkdir -p /mnt/usb_extras/{}".format(folder_name), shell=True)
|
||||
subprocess.check_output("mount -o {} /dev/{} /mnt/usb_extras/{}".format(permissions, partition, folder_name), shell=True)
|
||||
return True
|
||||
except Exception as e:
|
||||
return False
|
||||
|
||||
def unmount_partition(folder_name):
|
||||
os.system("umount /mnt/usb_extras/{}".format(folder_name))
|
||||
os.system("rm -rf /mnt/usb_extras/{}".format(folder_name))
|
||||
time.sleep(1)
|
||||
|
||||
|
||||
#==================================
|
||||
# Drive Driver Functions
|
||||
#==================================
|
||||
def is_uas_usb_enabled():
|
||||
return os.path.isfile('/home/bitcoin/.mynode/.uas_usb_enabled') or \
|
||||
os.path.isfile('/mnt/hdd/mynode/settings/.uas_usb_enabled')
|
||||
|
||||
def set_uas_usb_enabled(use_uas):
|
||||
if use_uas:
|
||||
touch("/home/bitcoin/.mynode/.uas_usb_enabled")
|
||||
touch("/mnt/hdd/mynode/settings/.uas_usb_enabled")
|
||||
else:
|
||||
delete_file("/home/bitcoin/.mynode/.uas_usb_enabled")
|
||||
delete_file("/mnt/hdd/mynode/settings/.uas_usb_enabled")
|
|
@ -409,9 +409,6 @@ def restart_lnd():
|
|||
|
||||
time.sleep(1)
|
||||
|
||||
def is_testnet_enabled():
|
||||
return os.path.isfile("/mnt/hdd/mynode/settings/.testnet_enabled")
|
||||
|
||||
def get_lightning_wallet_file():
|
||||
if is_testnet_enabled():
|
||||
return "/mnt/hdd/mynode/lnd/data/chain/bitcoin/testnet/wallet.db"
|
|
@ -11,10 +11,10 @@ def clear_service_enabled_cache():
|
|||
global service_enabled_cache
|
||||
service_enabled_cache = {}
|
||||
|
||||
def is_service_enabled(service_name):
|
||||
def is_service_enabled(service_name, force_refresh=False):
|
||||
global service_enabled_cache
|
||||
|
||||
if service_name in service_enabled_cache:
|
||||
if service_name in service_enabled_cache and force_refresh == False:
|
||||
return service_enabled_cache[service_name]
|
||||
|
||||
code = os.system("systemctl is-enabled {} > /dev/null".format(service_name))
|
|
@ -18,23 +18,25 @@ def isPython3():
|
|||
def to_bytes(s):
|
||||
if type(s) is bytes:
|
||||
return s
|
||||
elif type(s) is str or (sys.version_info[0] < 3 and type(s) is unicode):
|
||||
elif type(s) is str or (not isPython3() and type(s) is unicode):
|
||||
return codecs.encode(s, 'utf-8', 'ignore')
|
||||
else:
|
||||
raise TypeError("to_bytes: Expected bytes or string, but got %s." % type(s))
|
||||
|
||||
def to_string(s):
|
||||
b = to_bytes(s)
|
||||
return b.decode("utf-8")
|
||||
r = b.decode("utf-8")
|
||||
print("S TYPE: "+str(type(r)))
|
||||
return r
|
||||
|
||||
def quote_plus(s):
|
||||
if (sys.version_info > (3, 0)):
|
||||
if isPython3():
|
||||
return urllib.parse.quote_plus(s)
|
||||
else:
|
||||
return urllib.quote_plus(s)
|
||||
|
||||
def unquote_plus(s):
|
||||
if (sys.version_info > (3, 0)):
|
||||
if isPython3():
|
||||
return urllib.parse.unquote_plus(s)
|
||||
else:
|
||||
return urllib.unquote_plus(s)
|
||||
|
@ -66,7 +68,7 @@ def get_file_contents(filename):
|
|||
contents = "UNKNOWN"
|
||||
try:
|
||||
with open(filename, "r") as f:
|
||||
contents = f.read().strip()
|
||||
contents = to_string(f.read()).strip()
|
||||
except:
|
||||
contents = "ERROR"
|
||||
return to_bytes(contents)
|
||||
|
@ -90,11 +92,12 @@ def log_message(msg):
|
|||
# Logs to www log
|
||||
global mynode_logger
|
||||
if mynode_logger != None:
|
||||
print(msg)
|
||||
mynode_logger.info(msg)
|
||||
|
||||
def set_logger(l):
|
||||
def set_logger(logger):
|
||||
global mynode_logger
|
||||
mynode_logger = l
|
||||
mynode_logger = logger
|
||||
|
||||
def get_logger():
|
||||
global mynode_logger
|
||||
|
@ -153,3 +156,15 @@ def download_file(directory, filename, downloaded_file_name=None, as_attachment=
|
|||
return send_from_directory(directory=directory, path=filename, filename=None, as_attachment=as_attachment)
|
||||
else:
|
||||
return send_from_directory(directory=directory, filename=filename, as_attachment=as_attachment)
|
||||
|
||||
#==================================
|
||||
# Hashing Functions
|
||||
#==================================
|
||||
def get_md5_file_hash(path):
|
||||
import hashlib
|
||||
if not os.path.isfile(path):
|
||||
return "MISSING_FILE"
|
||||
try:
|
||||
return hashlib.md5(open(path,'rb').read()).hexdigest()
|
||||
except Exception as e:
|
||||
return "ERROR ({})".format(e)
|
|
@ -381,9 +381,9 @@ def get_app_version_data():
|
|||
|
||||
def get_custom_app_version_data():
|
||||
if os.path.isfile("/usr/share/mynode/mynode_app_versions_custom.sh"):
|
||||
return get_file_contents("/usr/share/mynode/mynode_app_versions_custom.sh")
|
||||
return to_string( get_file_contents("/usr/share/mynode/mynode_app_versions_custom.sh") )
|
||||
if os.path.isfile("/mnt/hdd/mynode/settings/mynode_app_versions_custom.sh"):
|
||||
return get_file_contents("/mnt/hdd/mynode/settings/mynode_app_versions_custom.sh")
|
||||
return to_string( get_file_contents("/mnt/hdd/mynode/settings/mynode_app_versions_custom.sh") )
|
||||
return ""
|
||||
|
||||
def save_custom_app_version_data(data):
|
||||
|
|
|
@ -8,7 +8,6 @@ from subprocess import check_output, check_call
|
|||
from electrum_info import *
|
||||
from user_management import check_logged_in
|
||||
import socket
|
||||
import hashlib
|
||||
import json
|
||||
import time
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@ from wardenterminal import mynode_wardenterminal
|
|||
from lndmanage import mynode_lndmanage
|
||||
from manage_apps import mynode_manage_apps
|
||||
from usb_extras import mynode_usb_extras
|
||||
from premium_plus import mynode_premium_plus
|
||||
from tor import mynode_tor
|
||||
from vpn import mynode_vpn
|
||||
from electrum_server import *
|
||||
|
@ -97,6 +98,7 @@ app.register_blueprint(mynode_wardenterminal)
|
|||
app.register_blueprint(mynode_lndmanage)
|
||||
app.register_blueprint(mynode_manage_apps)
|
||||
app.register_blueprint(mynode_tor)
|
||||
app.register_blueprint(mynode_premium_plus)
|
||||
app.register_blueprint(mynode_electrum_server)
|
||||
app.register_blueprint(mynode_vpn)
|
||||
app.register_blueprint(mynode_usb_extras)
|
||||
|
@ -256,6 +258,8 @@ def index():
|
|||
return render_template('state.html', **templateData)
|
||||
elif status == STATE_DRIVE_CLONE:
|
||||
clone_state = get_clone_state()
|
||||
log_message("CLONE_STATE")
|
||||
log_message(clone_state)
|
||||
if clone_state == CLONE_STATE_DETECTING:
|
||||
templateData = {
|
||||
"title": "myNode Clone Tool",
|
||||
|
|
60
rootfs/standard/var/www/mynode/premium_plus.py
Normal file
60
rootfs/standard/var/www/mynode/premium_plus.py
Normal file
|
@ -0,0 +1,60 @@
|
|||
from flask import Blueprint, render_template, session, abort, Markup, request, redirect, flash
|
||||
from bitcoinrpc.authproxy import AuthServiceProxy, JSONRPCException
|
||||
from pprint import pprint, pformat
|
||||
from device_info import *
|
||||
from user_management import check_logged_in
|
||||
from enable_disable_functions import restart_service
|
||||
import json
|
||||
import time
|
||||
|
||||
mynode_premium_plus = Blueprint('mynode_premium_plus',__name__)
|
||||
|
||||
|
||||
### Page functions
|
||||
@mynode_premium_plus.route("/premium-plus")
|
||||
def premium_plus_page():
|
||||
check_logged_in()
|
||||
|
||||
|
||||
# Load page
|
||||
templateData = {
|
||||
"title": "myNode Premium+",
|
||||
"has_access_token": has_premium_plus_token(),
|
||||
"access_token": get_premium_plus_token(),
|
||||
"status": get_premium_plus_token_status(),
|
||||
"is_connected": get_premium_plus_is_connected(),
|
||||
"last_sync": get_premium_plus_last_sync(),
|
||||
"ui_settings": read_ui_settings()
|
||||
}
|
||||
return render_template('premium_plus.html', **templateData)
|
||||
|
||||
@mynode_premium_plus.route("/premium-plus/sync")
|
||||
def premium_plus_sync_page():
|
||||
check_logged_in()
|
||||
restart_service("premium_plus_connect")
|
||||
time.sleep(3)
|
||||
flash("Syncing...", category="message")
|
||||
return redirect("/premium-plus")
|
||||
|
||||
@mynode_premium_plus.route("/premium-plus/clear-token")
|
||||
def premium_plus_clear_token_page():
|
||||
check_logged_in()
|
||||
delete_premium_plus_token()
|
||||
reset_premium_plus_token_status()
|
||||
restart_service("premium_plus_connect")
|
||||
time.sleep(3)
|
||||
flash("Token Cleared", category="message")
|
||||
return redirect("/premium-plus")
|
||||
|
||||
@mynode_premium_plus.route("/premium-plus/set-token", methods=["POST"])
|
||||
def premium_plus_set_token_page():
|
||||
check_logged_in()
|
||||
token = request.form.get('token')
|
||||
if token == None:
|
||||
flash("Missing Token", category="error")
|
||||
return redirect("/premium-plus")
|
||||
save_premium_plus_token(token)
|
||||
restart_service("premium_plus_connect")
|
||||
time.sleep(3)
|
||||
flash("Token Set", category="message")
|
||||
return redirect("/premium-plus")
|
|
@ -11,6 +11,7 @@ from user_management import check_logged_in
|
|||
from lightning_info import *
|
||||
from price_info import *
|
||||
from utilities import *
|
||||
from drive_info import *
|
||||
from application_info import *
|
||||
import pam
|
||||
import time
|
||||
|
@ -346,7 +347,7 @@ def upgrade_beta_page():
|
|||
def get_upgrade_log_page():
|
||||
check_logged_in()
|
||||
|
||||
log = get_file_contents("/home/admin/upgrade_logs/upgrade_log_latest.txt").decode("utf8")
|
||||
log = to_string( get_file_contents("/home/admin/upgrade_logs/upgrade_log_latest.txt") )
|
||||
if (log == "ERROR"):
|
||||
log = "No log file found"
|
||||
|
||||
|
|
156
rootfs/standard/var/www/mynode/templates/premium_plus.html
Normal file
156
rootfs/standard/var/www/mynode/templates/premium_plus.html
Normal file
|
@ -0,0 +1,156 @@
|
|||
<!DOCTYPE html lang="en">
|
||||
<head>
|
||||
<title>{{ title }}</title>
|
||||
{% include 'includes/head.html' %}
|
||||
|
||||
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
|
||||
$( document ).tooltip();
|
||||
|
||||
token="{{access_token}}"
|
||||
|
||||
function set_token() {
|
||||
$("#set_token_form").submit();
|
||||
set_token_dialog.dialog( "close" );
|
||||
}
|
||||
set_token_dialog = $( "#set-token-dialog" ).dialog({
|
||||
autoOpen: false,
|
||||
resizable: false,
|
||||
height: "auto",
|
||||
width: 600,
|
||||
modal: true,
|
||||
position: { my: "center top", at: "center top", of: window, collision: "none" },
|
||||
buttons: {
|
||||
"Save": set_token,
|
||||
Cancel: function() {
|
||||
set_token_dialog.dialog( "close" );
|
||||
}
|
||||
},
|
||||
open: function() {
|
||||
$("#token").val(token)
|
||||
}
|
||||
});
|
||||
|
||||
$("#change_token_button").on("click", function() {
|
||||
set_token_dialog.dialog( "open" );
|
||||
});
|
||||
$("#set_token_button").on("click", function() {
|
||||
set_token_dialog.dialog( "open" );
|
||||
});
|
||||
$("#clear_token_button").on("click", function() {
|
||||
if (confirm("Are you sure you want to clear your Premium+ Access Token?")) {
|
||||
window.location.href='/premium-plus/clear-token';
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
{% include 'includes/logo_header.html' %}
|
||||
<div class="mynode_back_div">
|
||||
<a class="ui-button ui-widget ui-corner-all mynode_back" href="/"><span class="ui-icon ui-icon-home"></span>home </a>
|
||||
</div>
|
||||
|
||||
{% include 'includes/message_display.html' %}
|
||||
|
||||
<div class="main_header">Premium+</div>
|
||||
<br/>
|
||||
|
||||
<!-- Config and Status Row -->
|
||||
<div class="app_tile_row">
|
||||
<div class="info_tile">
|
||||
<div class="info_tile_header">Access Token and Status</div>
|
||||
<div class="info_tile_contents">
|
||||
<table class="info_table">
|
||||
<tr>
|
||||
<th>Access Token</th>
|
||||
<td>
|
||||
{% if has_access_token %}
|
||||
{{access_token}}
|
||||
<button id="change_token_button" class="ui-button ui-widget ui-corner-all settings_button_small">Change</button>
|
||||
<button id="clear_token_button" class="ui-button ui-widget ui-corner-all settings_button_small">Clear</button>
|
||||
{% else %}
|
||||
<button id="set_token_button" class="ui-button ui-widget ui-corner-all settings_button_small">Set Token</button>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% if has_access_token %}
|
||||
<tr>
|
||||
<th>Status</th>
|
||||
<td>{{status}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Last Sync</th>
|
||||
<td>{{last_sync}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Actions</th>
|
||||
<td><a href="/premium-plus/sync" class="ui-button ui-widget ui-corner-all mynode_button_small">Force Sync</a></td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<br/>
|
||||
|
||||
<!-- Premium+ Services -->
|
||||
<div class="app_tile_row">
|
||||
<div class="info_tile">
|
||||
<div class="info_tile_header">Premium+ Services</div>
|
||||
<div class="info_tile_contents">
|
||||
<table class="info_table">
|
||||
<tr>
|
||||
<th>Sync Device Status</th>
|
||||
<td>{{mempool_tx}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Backup Lightning SCB File</th>
|
||||
<td>{{mempool_tx}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>myNode Watchtower</th>
|
||||
<td>{{mempool_size}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Proxy</th>
|
||||
<td>
|
||||
<p id="rpc_password" style="display: none; margin: 0;">{{rpc_password}} <span id="copy_rpc_password" class="ui-icon ui-icon-copy" style="cursor: pointer; display: none;" title="Copy Password"></span></p>
|
||||
<a id="show_rpc_password" class="ui-button ui-widget ui-corner-all mynode_button_small" style="width: 70%;">show</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Peer Bloom Filters (BIP 37)</th>
|
||||
<td>
|
||||
<label class="switch">
|
||||
<input type="checkbox" id="bip37_checkbox" {% if bip37_enabled %}checked{% endif %}>
|
||||
<span class="slider round"></span>
|
||||
</label>
|
||||
<button id="bip37_save" style="display: none; float: right;" class="ui-button ui-widget ui-corner-all settings_button_small">Save</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div id="set-token-dialog" title="Set Premium+ Access Token" style="display:none;">
|
||||
<form id="set_token_form" name="set_token_form" action="/premium-plus/set-token" method="POST">
|
||||
<p>The Premium+ Access Token is the key that syncs your node data for backup and remote access.</p>
|
||||
<b>Access Token:</b>
|
||||
<br/>
|
||||
<input type="text" name="token" id="token" value="" class="text ui-widget-content ui-corner-all" size="40" maxlength="64">
|
||||
|
||||
<!-- Allow form submission with keyboard without duplicating the dialog button -->
|
||||
<input type="submit" tabindex="-1" style="position:absolute; top:-1000px">
|
||||
</form>
|
||||
</div>
|
||||
|
||||
{% include 'includes/footer.html' %}
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in New Issue
Block a user