mirror of
https://github.com/aljazceru/plugins.git
synced 2025-12-21 15:14:19 +01:00
backup: Implement the restore method for all backends
Also implements the `stream_changes` function in the FileBackend which is used by `restore` to get all the changes.
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
from pyln.client import Plugin
|
from pyln.client import Plugin
|
||||||
|
from tqdm import tqdm
|
||||||
from typing import Mapping, Type, Iterator
|
from typing import Mapping, Type, Iterator
|
||||||
from urllib.parse import urlparse
|
from urllib.parse import urlparse
|
||||||
import json
|
import json
|
||||||
@@ -8,6 +9,7 @@ import logging
|
|||||||
import os
|
import os
|
||||||
import struct
|
import struct
|
||||||
import sys
|
import sys
|
||||||
|
import sqlite3
|
||||||
|
|
||||||
|
|
||||||
plugin = Plugin()
|
plugin = Plugin()
|
||||||
@@ -78,6 +80,27 @@ class Backend(object):
|
|||||||
"""
|
"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
|
def restore(self, dest: str, remove_existing: bool = False) -> bool:
|
||||||
|
"""Restore the backup in this backend to its former glory.
|
||||||
|
"""
|
||||||
|
if os.path.exists(dest):
|
||||||
|
os.unlink(dest)
|
||||||
|
db = sqlite3.connect(dest)
|
||||||
|
for c in tqdm(self.stream_changes(), total=self.version):
|
||||||
|
if c.snapshot is not None:
|
||||||
|
if os.path.exists(dest):
|
||||||
|
os.unlink(dest)
|
||||||
|
with open(dest, 'wb') as f:
|
||||||
|
f.write(c.snapshot)
|
||||||
|
db = sqlite3.connect(dest)
|
||||||
|
if c.transaction is not None:
|
||||||
|
cur = db.cursor()
|
||||||
|
for q in c.transaction:
|
||||||
|
cur.execute(q.decode('UTF-8'))
|
||||||
|
db.commit()
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
class FileBackend(Backend):
|
class FileBackend(Backend):
|
||||||
def __init__(self, destination: str):
|
def __init__(self, destination: str):
|
||||||
@@ -160,6 +183,27 @@ class FileBackend(Backend):
|
|||||||
self.prev_version, self.offsets[1] = 0, 0
|
self.prev_version, self.offsets[1] = 0, 0
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def stream_changes(self) -> Iterator[Change]:
|
||||||
|
self.read_metadata()
|
||||||
|
version = -1
|
||||||
|
with open(self.url.path, 'rb') as f:
|
||||||
|
# Skip the header
|
||||||
|
f.seek(512)
|
||||||
|
while version < self.version:
|
||||||
|
length, version, typ = struct.unpack("!IIb", f.read(9))
|
||||||
|
payload = f.read(length)
|
||||||
|
if typ == 1:
|
||||||
|
yield Change(version=version, snapshot=None, transaction=payload.split(b'\x00'))
|
||||||
|
elif typ == 2:
|
||||||
|
yield Change(version=version, snapshot=payload, transaction=None)
|
||||||
|
else:
|
||||||
|
raise ValueError("Unknown FileBackend entry type {}".format(typ))
|
||||||
|
|
||||||
|
if version != self.version:
|
||||||
|
raise ValueError("Versions do not match up: restored version {}, backend version {}".format(version, self.version))
|
||||||
|
assert(version == self.version)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def resolve_backend_class(backend_url):
|
def resolve_backend_class(backend_url):
|
||||||
backend_map: Mapping[str, Type[Backend]] = {
|
backend_map: Mapping[str, Type[Backend]] = {
|
||||||
|
|||||||
@@ -1 +1,2 @@
|
|||||||
Click==7.0
|
Click==7.0
|
||||||
|
tqdm>=4.45
|
||||||
|
|||||||
Reference in New Issue
Block a user