diff --git a/convex-cli/src/main/java/convex/cli/mixins/EtchMixin.java b/convex-cli/src/main/java/convex/cli/mixins/EtchMixin.java index 0c2ad0303..db744b3b7 100644 --- a/convex-cli/src/main/java/convex/cli/mixins/EtchMixin.java +++ b/convex-cli/src/main/java/convex/cli/mixins/EtchMixin.java @@ -2,11 +2,14 @@ import java.io.File; import java.io.IOException; +import java.util.List; import convex.cli.CLIError; import convex.cli.Constants; +import convex.core.data.AccountKey; import convex.core.util.FileUtils; import convex.etch.EtchStore; +import convex.peer.API; import picocli.CommandLine.Option; import picocli.CommandLine.ScopeType; @@ -46,4 +49,15 @@ public synchronized EtchStore getEtchStore(String fileName) { public EtchStore getEtchStore() { return getEtchStore(etchStoreFilename); } + + public List getPeerList() { + EtchStore etchStore=getEtchStore(); + + try { + List keys=API.listPeers(getEtchStore()); + return keys; + } catch (IOException e) { + throw new CLIError("Unable to list peers in store: "+etchStore); + } + } } diff --git a/convex-cli/src/main/java/convex/cli/mixins/PeerKeyMixin.java b/convex-cli/src/main/java/convex/cli/mixins/PeerKeyMixin.java index ef392a4c1..ea0310340 100644 --- a/convex-cli/src/main/java/convex/cli/mixins/PeerKeyMixin.java +++ b/convex-cli/src/main/java/convex/cli/mixins/PeerKeyMixin.java @@ -3,6 +3,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import convex.core.data.AccountKey; import picocli.CommandLine.Option; import picocli.CommandLine.ScopeType; @@ -58,4 +59,12 @@ public char[] getKeyPassword() { } return keypass; } + + public AccountKey getAcountKey() { + String ks=getPublicKey(); + AccountKey result= AccountKey.parse(ks); + return result; + } + + } diff --git a/convex-cli/src/main/java/convex/cli/peer/Peer.java b/convex-cli/src/main/java/convex/cli/peer/Peer.java index f81ab67fa..a87f1344c 100644 --- a/convex-cli/src/main/java/convex/cli/peer/Peer.java +++ b/convex-cli/src/main/java/convex/cli/peer/Peer.java @@ -20,6 +20,7 @@ PeerCreate.class, PeerStart.class, PeerList.class, + PeerBackup.class, PeerGenesis.class, Help.class }, diff --git a/convex-cli/src/main/java/convex/cli/peer/PeerBackup.java b/convex-cli/src/main/java/convex/cli/peer/PeerBackup.java new file mode 100644 index 000000000..2c9501c04 --- /dev/null +++ b/convex-cli/src/main/java/convex/cli/peer/PeerBackup.java @@ -0,0 +1,86 @@ +package convex.cli.peer; + +import java.io.File; +import java.io.IOException; +import java.util.List; + +import convex.cli.CLIError; +import convex.core.data.ACell; +import convex.core.data.AMap; +import convex.core.data.AccountKey; +import convex.core.data.Keyword; +import convex.core.util.FileUtils; +import convex.core.util.Utils; +import picocli.CommandLine.Command; +import picocli.CommandLine.Option; + +@Command( + name = "backup", + mixinStandardHelpOptions = true, + description = "Backup stored data for a peer") +public class PeerBackup extends APeerCommand { + + @Option(names = { "--output-file" }, + description = "Output file for peer CAD3 data. Defaults to timestamped CAD3 file.") + private String outFile; + + + @SuppressWarnings("resource") + @Override + protected void execute() throws InterruptedException { + + AccountKey k= peerKeyMixin.getAcountKey(); + + if (k==null) { + List peerList=etchMixin.getPeerList(); + int n=peerList.size(); + if (n==0) { + throw new CLIError("No peers available in store: "+etchMixin.getEtchStore()); + } + + String s=peerKeyMixin.getPublicKey(); + if (s!=null) { + peerList.removeIf(pk->!pk.toHexString().startsWith(s)); + n=peerList.size(); + } + + if (n==0) { + throw new CLIError("No peer in store with prefix: "+s); + } if (n==1) { + k=peerList.get(0); + } else if (n==0) { + throw new CLIError("No peers available in store: "+etchMixin.getEtchStore()); + } else { + informWarning("Need to select peer to backup, available peers are:"); + for (AccountKey pk: peerList) { + inform(pk.toHexString()); + } + + throw new CLIError("Please specify which peer to backup with --peer-key"); + } + } + + AMap peerData; + try { + peerData=convex.core.cvm.Peer.getPeerData(etchMixin.getEtchStore(), k); + if (peerData==null) { + throw new CLIError("No peer data found for key: "+k); + } + } catch (Exception e) { + throw new CLIError("Unable to access peers data",e); + } + + if (outFile==null) { + outFile="peer-backup-"+k.toHexString(8)+"-"+Utils.timeString()+".cad3"; + } + File f=FileUtils.getFile(outFile); + + try { + FileUtils.writeCAD3(f.toPath(), peerData); + inform("Peer data written to: "+f); + } catch (IOException e) { + throw new CLIError("Unable to write peer data",e); + } + } + +} diff --git a/convex-cli/src/main/java/convex/cli/peer/PeerList.java b/convex-cli/src/main/java/convex/cli/peer/PeerList.java index 99c3ed53b..d7602ae65 100644 --- a/convex-cli/src/main/java/convex/cli/peer/PeerList.java +++ b/convex-cli/src/main/java/convex/cli/peer/PeerList.java @@ -1,13 +1,8 @@ package convex.cli.peer; -import java.io.IOException; import java.util.List; -import convex.cli.CLIError; -import convex.cli.ExitCodes; import convex.core.data.AccountKey; -import convex.etch.EtchStore; -import convex.peer.API; import picocli.CommandLine.Command; import picocli.CommandLine.ParentCommand; @@ -25,18 +20,10 @@ public class PeerList extends APeerCommand { @Override - public void execute() { - - EtchStore etch=etchMixin.getEtchStore(); - try { - List keys=API.listPeers(etch); - for (AccountKey k: keys) { - println(k.toHexString()); - } - } catch (IOException e) { - throw new CLIError(ExitCodes.IOERR,"IO Error reating etch store at "+etch,e); - } finally { - etch.close(); + public void execute() { + List keys=etchMixin.getPeerList(); + for (AccountKey k: keys) { + println(k.toHexString()); } } } diff --git a/convex-core/src/main/java/convex/core/cvm/Peer.java b/convex-core/src/main/java/convex/core/cvm/Peer.java index 4e2309222..c47c874e1 100644 --- a/convex-core/src/main/java/convex/core/cvm/Peer.java +++ b/convex-core/src/main/java/convex/core/cvm/Peer.java @@ -229,16 +229,6 @@ public static Peer restorePeer(AStore store, AKeyPair keyPair, ACell rootKey) th Peer peer=Peer.fromData(keyPair,peerData); return peer; } - - /** - * Like {@link #getPeerData(AStore, ACell)} but uses a null root key. - * @param store store from which to load Peer data - * @return Peer data map - * @throws IOException In case of IOException - */ - public static AMap getPeerData(AStore store) throws IOException { - return getPeerData(store, null); - } /** * Gets Peer Data from a Store. diff --git a/convex-peer/src/main/java/convex/peer/API.java b/convex-peer/src/main/java/convex/peer/API.java index 15b905306..34d2e634e 100644 --- a/convex-peer/src/main/java/convex/peer/API.java +++ b/convex-peer/src/main/java/convex/peer/API.java @@ -194,10 +194,10 @@ public static List launchLocalPeers(List keyPairs, State genes /** * Gets the list of peers registered in the given Etch Store * @param store Store from which to read peers - * @return null if peer list not present + * @return A new ArrayList of keys, or null if peer list not present * @throws IOException in case of IO error reading peers from store */ - public static List listPeers(AStore store) throws IOException { + public static ArrayList listPeers(AStore store) throws IOException { AMap data=store.getRootData(); ArrayList results=new ArrayList<>(); if (data==null) return results;