nodio-cli 1.0.2 → 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodio-cli",
3
- "version": "1.0.2",
3
+ "version": "1.0.3",
4
4
  "description": "Nodio distributed storage network",
5
5
  "main": "src/server/index.js",
6
6
  "type": "commonjs",
@@ -101,11 +101,13 @@ class NodioNodeRuntime {
101
101
  async registerNode() {
102
102
  const deviceKey = await getOrCreateDeviceKey();
103
103
  const nodeKey = await this.shardStore.getOrCreateNodeKey();
104
+ const knownNodeIds = await this.shardStore.discoverKnownNodeIds();
104
105
 
105
106
  const response = await axios.post(`${this.serverUrl}/api/nodes/register`, {
106
107
  nodeId: this.nodeId,
107
108
  deviceKey,
108
109
  nodeKey,
110
+ knownNodeIds,
109
111
  url: this.publicUrl,
110
112
  capacityBytes: this.capacityBytes,
111
113
  freeBytes: await this.freeBytes()
@@ -67,6 +67,43 @@ class LocalShardStore {
67
67
  return identity.nodeId || null;
68
68
  }
69
69
 
70
+ async discoverKnownNodeIds() {
71
+ const known = new Set();
72
+
73
+ const current = await this.readIdentity();
74
+ if (current.nodeId) {
75
+ known.add(current.nodeId);
76
+ }
77
+
78
+ const parentDir = path.dirname(this.baseDir);
79
+ let entries = [];
80
+ try {
81
+ entries = await fs.readdir(parentDir, { withFileTypes: true });
82
+ } catch {
83
+ return [...known];
84
+ }
85
+
86
+ for (const entry of entries) {
87
+ if (!entry.isDirectory()) {
88
+ continue;
89
+ }
90
+
91
+ const identityPath = path.join(parentDir, entry.name, 'node-identity.json');
92
+ try {
93
+ // eslint-disable-next-line no-await-in-loop
94
+ const raw = await fs.readFile(identityPath, 'utf-8');
95
+ const parsed = JSON.parse(raw);
96
+ if (parsed?.nodeId && typeof parsed.nodeId === 'string') {
97
+ known.add(parsed.nodeId);
98
+ }
99
+ } catch {
100
+ continue;
101
+ }
102
+ }
103
+
104
+ return [...known];
105
+ }
106
+
70
107
  async saveAssignedNodeId(nodeId) {
71
108
  if (!nodeId) {
72
109
  return;
@@ -31,7 +31,7 @@ function buildRoutes(config) {
31
31
 
32
32
  router.post('/nodes/register', async (req, res, next) => {
33
33
  try {
34
- const { nodeId, deviceKey, nodeKey, url, capacityBytes, freeBytes } = req.body;
34
+ const { nodeId, deviceKey, nodeKey, knownNodeIds, url, capacityBytes, freeBytes } = req.body;
35
35
 
36
36
  if (!url) {
37
37
  return res.status(400).json({ error: 'url is required' });
@@ -45,6 +45,13 @@ function buildRoutes(config) {
45
45
  if (deviceKey && typeof deviceKey !== 'string') {
46
46
  return res.status(400).json({ error: 'deviceKey must be a string when provided' });
47
47
  }
48
+ if (knownNodeIds !== undefined && !Array.isArray(knownNodeIds)) {
49
+ return res.status(400).json({ error: 'knownNodeIds must be an array when provided' });
50
+ }
51
+
52
+ const normalizedKnownNodeIds = Array.isArray(knownNodeIds)
53
+ ? [...new Set(knownNodeIds.filter((value) => typeof value === 'string' && value.length > 0))]
54
+ : [];
48
55
 
49
56
  let existingByNodeKey = null;
50
57
  if (nodeKey) {
@@ -55,7 +62,25 @@ function buildRoutes(config) {
55
62
  return res.status(409).json({ error: 'nodeKey is already associated with a different nodeId' });
56
63
  }
57
64
 
58
- const effectiveNodeId = nodeId || existingByNodeKey?.nodeId || `donor-${uuidv4().slice(0, 8)}`;
65
+ let effectiveNodeId = nodeId || existingByNodeKey?.nodeId || null;
66
+
67
+ if (!effectiveNodeId && deviceKey && normalizedKnownNodeIds.length > 0) {
68
+ const oldestOfflineKnownNode = await NodeModel.findOne({
69
+ deviceKey,
70
+ status: 'offline',
71
+ nodeId: { $in: normalizedKnownNodeIds }
72
+ })
73
+ .sort({ createdAt: 1 })
74
+ .lean();
75
+
76
+ if (oldestOfflineKnownNode) {
77
+ effectiveNodeId = oldestOfflineKnownNode.nodeId;
78
+ }
79
+ }
80
+
81
+ if (!effectiveNodeId) {
82
+ effectiveNodeId = `donor-${uuidv4().slice(0, 8)}`;
83
+ }
59
84
 
60
85
  const node = await NodeModel.findOneAndUpdate(
61
86
  { nodeId: effectiveNodeId },