Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Backup and restore network #1439

Merged
merged 5 commits into from
Dec 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import java.io.OutputStreamWriter;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand All @@ -27,6 +28,7 @@
import com.zsmartsystems.zigbee.database.ZclAttributeDao;
import com.zsmartsystems.zigbee.database.ZclClusterDao;
import com.zsmartsystems.zigbee.database.ZigBeeEndpointDao;
import com.zsmartsystems.zigbee.database.ZigBeeNetworkBackupDao;
import com.zsmartsystems.zigbee.database.ZigBeeNetworkDataStore;
import com.zsmartsystems.zigbee.database.ZigBeeNodeDao;
import com.zsmartsystems.zigbee.security.ZigBeeKey;
Expand All @@ -47,19 +49,25 @@
*/
private final static Logger logger = LoggerFactory.getLogger(ZigBeeDataStore.class);

private final static String CHARSET = "UTF-8";
private final static String DATABASE = "database/";
private final static String KEYSTORE = "keystore";
private final static String BACKUP = "backup";

private final String networkId;

public ZigBeeDataStore(String networkId) {
this.networkId = "database/" + networkId + "/";
File file = new File(this.networkId + "/" + KEYSTORE);
if (file.exists()) {
return;
}
if (!file.mkdirs()) {
this.networkId = DATABASE + networkId + "/";
File file;

file = new File(this.networkId + "/" + KEYSTORE);
if (!file.exists() && !file.mkdirs()) {
logger.error("Error creating network database folder {}", file);
}
file = new File(DATABASE + BACKUP);
if (!file.exists() && !file.mkdirs()) {
logger.error("Error creating network backup folder {}", file);
}
}

private XStream openStream() {
Expand Down Expand Up @@ -99,6 +107,10 @@
return new File(networkId + address + ".xml");
}

private File getFile(UUID uuid) {
return new File(DATABASE + BACKUP + "/" + uuid + ".xml");
}

private File getFile(String key) {
return new File(networkId + KEYSTORE + "/" + key + ".xml");
}
Expand Down Expand Up @@ -135,10 +147,9 @@
File file = getFile(address);

ZigBeeNodeDao node = null;
try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"))) {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), CHARSET))) {

Check warning

Code scanning / CodeQL

Potential input resource leak Warning

This FileInputStream is not always closed on method exit.
node = (ZigBeeNodeDao) stream.fromXML(reader);
reader.close();
logger.info("{}: ZigBee reading network state complete.", address);
} catch (Exception e) {
logger.error("{}: Error reading network state: ", address, e);
}
Expand All @@ -151,10 +162,9 @@
XStream stream = openStream();
File file = getFile(node.getIeeeAddress());

try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), "UTF-8"))) {
try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), CHARSET))) {

Check warning

Code scanning / CodeQL

Potential output resource leak Warning

This FileOutputStream is not always closed on method exit.
stream.marshal(node, new PrettyPrintWriter(writer));
writer.close();
logger.info("{}: ZigBee saving network state complete.", node.getIeeeAddress());
} catch (Exception e) {
logger.error("{}: Error writing network state: ", node.getIeeeAddress(), e);
}
Expand All @@ -173,10 +183,9 @@
XStream stream = openStream();
File file = getFile(key);

try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), "UTF-8"))) {
try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), CHARSET))) {

Check warning

Code scanning / CodeQL

Potential output resource leak Warning

This FileOutputStream is not always closed on method exit.
stream.marshal(object, new PrettyPrintWriter(writer));
writer.close();
logger.info("{}: ZigBee saving key complete.", key);
} catch (Exception e) {
logger.error("{}: Error writing key: ", key, e);
}
Expand All @@ -187,4 +196,67 @@
return null;
}

@Override
public boolean writeBackup(ZigBeeNetworkBackupDao backup) {
XStream stream = openStream();
File file = getFile(backup.getUuid());

try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), CHARSET))) {

Check warning

Code scanning / CodeQL

Potential output resource leak Warning

This FileOutputStream is not always closed on method exit.
stream.marshal(backup, new PrettyPrintWriter(writer));
writer.close();
} catch (Exception e) {
logger.error("{}: Error writing network backup: ", backup.getUuid(), e);
return false;
}

return true;
}

@Override
public ZigBeeNetworkBackupDao readBackup(UUID uuid) {
XStream stream = openStream();
File file = getFile(uuid);

ZigBeeNetworkBackupDao backup = null;
try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), CHARSET))) {

Check warning

Code scanning / CodeQL

Potential input resource leak Warning

This FileInputStream is not always closed on method exit.
backup = (ZigBeeNetworkBackupDao) stream.fromXML(reader);
reader.close();
} catch (Exception e) {
logger.error("{}: Error reading network backup: ", uuid, e);
}

return backup;
}

@Override
public Set<ZigBeeNetworkBackupDao> listBackups() {
Set<ZigBeeNetworkBackupDao> backups = new HashSet<>();
File dir = new File(DATABASE + BACKUP);
File[] files = dir.listFiles();

if (files == null) {
return backups;
}

for (File file : files) {
if (!file.getName().toLowerCase().endsWith(".xml")) {
continue;
}

try {
String filename = file.getName();
UUID uuid = UUID.fromString(filename.substring(0, filename.length() - 4));
ZigBeeNetworkBackupDao backup = readBackup(uuid);
for (ZigBeeNodeDao node : backup.getNodes()) {
node.setEndpoints(null);
node.setBindingTable(null);
}
backups.add(backup);
} catch (IllegalArgumentException e) {
logger.error("Error parsing database filename: {}", file.getName());
}
}

return backups;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public String getCommand() {

@Override
public String getDescription() {
return "Sets the link key int the dongle, optionally computing the MMO Hash from the join code";
return "Sets the link key in the dongle, optionally computing the MMO Hash from the join code";
}

@Override
Expand Down
Loading
Loading