2022-03-17 15:54:34 +01:00
|
|
|
|
# standard imports
|
|
|
|
|
import uuid
|
|
|
|
|
import os
|
|
|
|
|
import logging
|
|
|
|
|
|
|
|
|
|
# external imports
|
|
|
|
|
from shep.store.file import SimpleFileStoreFactory
|
|
|
|
|
from shep.persist import PersistedState
|
|
|
|
|
|
2022-03-17 20:36:27 +01:00
|
|
|
|
# local imports
|
|
|
|
|
from chainsyncer.state import SyncState
|
2022-04-20 13:59:12 +02:00
|
|
|
|
from chainsyncer.store import (
|
|
|
|
|
SyncItem,
|
|
|
|
|
SyncStore,
|
2022-03-17 23:07:19 +01:00
|
|
|
|
)
|
2022-03-17 15:54:34 +01:00
|
|
|
|
|
2022-04-20 13:59:12 +02:00
|
|
|
|
logg = logging.getLogger(__name__)
|
2022-03-17 15:54:34 +01:00
|
|
|
|
|
|
|
|
|
|
2022-04-20 13:59:12 +02:00
|
|
|
|
class SyncFsStore(SyncStore):
|
2022-03-17 15:54:34 +01:00
|
|
|
|
|
2022-03-24 00:36:17 +01:00
|
|
|
|
def __init__(self, base_path, session_id=None, state_event_callback=None, filter_state_event_callback=None):
|
2022-04-20 13:59:12 +02:00
|
|
|
|
super(SyncFsStore, self).__init__(session_id=session_id)
|
2022-03-17 15:54:34 +01:00
|
|
|
|
|
|
|
|
|
default_path = os.path.join(base_path, 'default')
|
|
|
|
|
|
|
|
|
|
if session_id == None:
|
|
|
|
|
self.session_path = os.path.realpath(default_path)
|
|
|
|
|
self.is_default = True
|
|
|
|
|
else:
|
|
|
|
|
if session_id == 'default':
|
|
|
|
|
self.is_default = True
|
|
|
|
|
given_path = os.path.join(base_path, session_id)
|
|
|
|
|
self.session_path = os.path.realpath(given_path)
|
|
|
|
|
|
|
|
|
|
create_path = False
|
|
|
|
|
try:
|
|
|
|
|
os.stat(self.session_path)
|
|
|
|
|
except FileNotFoundError:
|
|
|
|
|
create_path = True
|
|
|
|
|
|
|
|
|
|
if create_path:
|
|
|
|
|
self.__create_path(base_path, default_path, session_id=session_id)
|
2022-03-19 01:52:47 +01:00
|
|
|
|
self.session_id = os.path.basename(self.session_path)
|
2022-03-17 15:54:34 +01:00
|
|
|
|
|
|
|
|
|
logg.info('session id {} resolved {} path {}'.format(session_id, self.session_id, self.session_path))
|
|
|
|
|
|
|
|
|
|
factory = SimpleFileStoreFactory(self.session_path, binary=True)
|
2022-03-24 00:36:17 +01:00
|
|
|
|
self.state = PersistedState(factory.add, 2, event_callback=state_event_callback)
|
2022-03-17 15:54:34 +01:00
|
|
|
|
self.state.add('SYNC')
|
|
|
|
|
self.state.add('DONE')
|
|
|
|
|
|
2022-03-17 20:36:27 +01:00
|
|
|
|
base_filter_path = os.path.join(self.session_path, 'filter')
|
|
|
|
|
factory = SimpleFileStoreFactory(base_filter_path, binary=True)
|
2022-03-24 00:36:17 +01:00
|
|
|
|
filter_state_backend = PersistedState(factory.add, 0, check_alias=False, event_callback=filter_state_event_callback)
|
|
|
|
|
self.filter_state = SyncState(filter_state_backend, scan_path=base_filter_path)
|
2022-03-19 02:24:08 +01:00
|
|
|
|
self.filters = [] # used by SyncSession
|
2022-03-17 23:07:19 +01:00
|
|
|
|
|
2022-03-17 15:54:34 +01:00
|
|
|
|
|
|
|
|
|
def __create_path(self, base_path, default_path, session_id=None):
|
|
|
|
|
logg.debug('fs store path {} does not exist, creating'.format(self.session_path))
|
|
|
|
|
if session_id == None:
|
|
|
|
|
session_id = str(uuid.uuid4())
|
|
|
|
|
self.session_path = os.path.join(base_path, session_id)
|
|
|
|
|
os.makedirs(self.session_path)
|
|
|
|
|
|
|
|
|
|
if self.is_default:
|
|
|
|
|
try:
|
|
|
|
|
os.symlink(self.session_path, default_path)
|
|
|
|
|
except FileExistsError:
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
2022-04-20 13:59:12 +02:00
|
|
|
|
def load(self, target):
|
2022-03-17 15:54:34 +01:00
|
|
|
|
self.state.sync(self.state.NEW)
|
|
|
|
|
self.state.sync(self.state.SYNC)
|
|
|
|
|
|
2022-03-17 20:36:27 +01:00
|
|
|
|
thresholds_sync = []
|
2022-03-17 15:54:34 +01:00
|
|
|
|
for v in self.state.list(self.state.SYNC):
|
|
|
|
|
block_number = int(v)
|
2022-03-17 20:36:27 +01:00
|
|
|
|
thresholds_sync.append(block_number)
|
2022-03-17 15:54:34 +01:00
|
|
|
|
logg.debug('queue resume {}'.format(block_number))
|
2022-03-17 20:36:27 +01:00
|
|
|
|
thresholds_new = []
|
2022-03-17 15:54:34 +01:00
|
|
|
|
for v in self.state.list(self.state.NEW):
|
|
|
|
|
block_number = int(v)
|
2022-03-17 20:36:27 +01:00
|
|
|
|
thresholds_new.append(block_number)
|
2022-03-17 15:54:34 +01:00
|
|
|
|
logg.debug('queue new range {}'.format(block_number))
|
|
|
|
|
|
2022-03-17 20:36:27 +01:00
|
|
|
|
thresholds_sync.sort()
|
|
|
|
|
thresholds_new.sort()
|
|
|
|
|
thresholds = thresholds_sync + thresholds_new
|
2022-03-17 15:54:34 +01:00
|
|
|
|
lim = len(thresholds) - 1
|
2022-04-20 13:59:12 +02:00
|
|
|
|
|
|
|
|
|
logg.debug('thresholds {}'.format(thresholds))
|
2022-03-17 15:54:34 +01:00
|
|
|
|
for i in range(len(thresholds)):
|
|
|
|
|
item_target = target
|
|
|
|
|
if i < lim:
|
|
|
|
|
item_target = thresholds[i+1]
|
2022-04-20 13:59:12 +02:00
|
|
|
|
o = SyncItem(block_number, item_target, self.state, self.filter_state, started=True)
|
2022-03-17 15:54:34 +01:00
|
|
|
|
self.items[block_number] = o
|
2022-03-18 00:48:23 +01:00
|
|
|
|
self.item_keys.append(block_number)
|
2022-03-19 01:52:47 +01:00
|
|
|
|
logg.info('added existing {}'.format(o))
|
2022-03-17 15:54:34 +01:00
|
|
|
|
|
2022-03-19 02:13:37 +01:00
|
|
|
|
fp = os.path.join(self.session_path, 'target')
|
2022-04-02 09:33:12 +02:00
|
|
|
|
have_target = False
|
|
|
|
|
try:
|
|
|
|
|
f = open(fp, 'r')
|
|
|
|
|
v = f.read()
|
2022-03-17 15:54:34 +01:00
|
|
|
|
f.close()
|
2022-04-02 09:33:12 +02:00
|
|
|
|
self.target = int(v)
|
|
|
|
|
have_target = True
|
|
|
|
|
except FileNotFoundError as e:
|
|
|
|
|
pass
|
2022-03-17 15:54:34 +01:00
|
|
|
|
|
2022-04-02 09:33:12 +02:00
|
|
|
|
if len(thresholds) == 0:
|
|
|
|
|
if have_target:
|
|
|
|
|
logg.warning('sync "{}" is already done, nothing to do'.format(self.session_id))
|
|
|
|
|
else:
|
|
|
|
|
logg.info('syncer first run target {}'.format(target))
|
|
|
|
|
self.first = True
|
|
|
|
|
f = open(fp, 'w')
|
|
|
|
|
f.write(str(target))
|
|
|
|
|
f.close()
|
|
|
|
|
self.target = target
|