@dignetwork/dig-sdk 0.0.1-alpha.45 → 0.0.1-alpha.47

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.
@@ -21,7 +21,7 @@ class ContentServer {
21
21
  // Method to get the content of a specified key from the peer, with optional challenge query
22
22
  async getKey(key, rootHash, challengeHex) {
23
23
  // Construct the base URL
24
- let url = `http://${this.ipAddress}/chia.${this.storeId}.${rootHash}/${key}`;
24
+ let url = `https://${this.ipAddress}:${ContentServer.port}/chia.${this.storeId}.${rootHash}/${key}`;
25
25
  // If a challenge is provided, append it as a query parameter
26
26
  if (challengeHex) {
27
27
  url += `?challenge=${challengeHex}`;
@@ -42,32 +42,32 @@ class ContentServer {
42
42
  }
43
43
  // Method to get the .well-known information
44
44
  async getWellKnown() {
45
- const url = `http://${this.ipAddress}/.well-known`;
45
+ const url = `https://${this.ipAddress}:${ContentServer.port}/.well-known`;
46
46
  return this.fetchJson(url);
47
47
  }
48
48
  // Method to get the list of known stores
49
49
  async getKnownStores() {
50
- const url = `http://${this.ipAddress}/.well-known/stores`;
50
+ const url = `https://${this.ipAddress}:${ContentServer.port}/.well-known/stores`;
51
51
  return this.fetchJson(url);
52
52
  }
53
53
  // Method to get the index of all stores
54
54
  async getStoresIndex() {
55
- const url = `http://${this.ipAddress}/`;
55
+ const url = `https://${this.ipAddress}:${ContentServer.port}/`;
56
56
  return this.fetchJson(url);
57
57
  }
58
58
  // Method to get the index of keys in a store
59
59
  async getKeysIndex() {
60
- const url = `http://${this.ipAddress}/${this.storeId}`;
60
+ const url = `https://${this.ipAddress}:${ContentServer.port}/${this.storeId}`;
61
61
  return this.fetchJson(url);
62
62
  }
63
63
  // Method to check if a specific key exists (HEAD request)
64
64
  async headKey(key) {
65
- const url = `http://${this.ipAddress}/${this.storeId}/${key}`;
65
+ const url = `https://${this.ipAddress}:${ContentServer.port}/${this.storeId}/${key}`;
66
66
  return this.head(url);
67
67
  }
68
68
  // Method to check if a specific store exists (HEAD request)
69
69
  async headStore(options) {
70
- let url = `http://${this.ipAddress}/${this.storeId}`;
70
+ let url = `https://${this.ipAddress}:${ContentServer.port}/${this.storeId}`;
71
71
  if (options?.hasRootHash) {
72
72
  url += `?hasRootHash=${options.hasRootHash}`;
73
73
  }
@@ -75,7 +75,7 @@ class ContentServer {
75
75
  }
76
76
  streamKey(key) {
77
77
  return new Promise((resolve, reject) => {
78
- const url = `http://${this.ipAddress}/${this.storeId}/${key}`;
78
+ const url = `https://${this.ipAddress}:${ContentServer.port}/${this.storeId}/${key}`;
79
79
  const urlObj = new url_1.URL(url);
80
80
  const requestOptions = {
81
81
  hostname: urlObj.hostname,
@@ -102,7 +102,7 @@ class ContentServer {
102
102
  }
103
103
  });
104
104
  request.on("error", (error) => {
105
- console.error(`Request error for ${url}:`, error);
105
+ console.error(`GET Request error for ${url}:`, error);
106
106
  reject(error);
107
107
  });
108
108
  request.end();
@@ -161,7 +161,7 @@ class ContentServer {
161
161
  }
162
162
  });
163
163
  request.on("error", (error) => {
164
- console.error(`Request error for ${url}:`, error);
164
+ console.error(`HEAD ${url}:`, error.message);
165
165
  reject({ success: false });
166
166
  });
167
167
  request.end();
@@ -247,7 +247,7 @@ class ContentServer {
247
247
  }
248
248
  });
249
249
  request.on("error", (error) => {
250
- console.error(`Request error for ${url}:`, error);
250
+ console.error(`GET ${url}:`, error.message);
251
251
  reject(error);
252
252
  });
253
253
  request.end();
@@ -9,7 +9,7 @@ export declare class DigNetwork {
9
9
  uploadStoreHead(digPeer: DigPeer): Promise<void>;
10
10
  uploadStore(digPeer: DigPeer): Promise<void>;
11
11
  static subscribeToStore(storeId: string): Promise<void>;
12
- static findPeerWithStoreKey(storeId: string, rootHash: string, key?: string, intialBlackList?: string[]): Promise<string | null>;
12
+ static findPeerWithStoreKey(storeId: string, rootHash: string, key?: string, intialBlackList?: string[]): Promise<DigPeer | null>;
13
13
  static unsubscribeFromStore(storeId: string): void;
14
14
  downloadFiles(forceDownload?: boolean, renderProgressBar?: boolean, skipData?: boolean): Promise<void>;
15
15
  private fetchAvailablePeers;
@@ -1 +1 @@
1
- {"version":3,"file":"DigNetwork.d.ts","sourceRoot":"","sources":["../../src/DigNetwork/DigNetwork.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAWpC,qBAAa,UAAU;IACrB,OAAO,CAAC,SAAS,CAAY;IAC7B,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,aAAa,CAA2B;gBAEpC,OAAO,EAAE,MAAM;YAOb,eAAe;IA8ChB,eAAe,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAsDhD,WAAW,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;WA6BrC,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;WAQhD,oBAAoB,CACtC,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,GAAG,CAAC,EAAE,MAAM,EACZ,eAAe,GAAE,MAAM,EAAO,GAC7B,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;WAuCX,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAQ5C,aAAa,CACxB,aAAa,GAAE,OAAe,EAC9B,iBAAiB,GAAE,OAAc,EACjC,QAAQ,GAAE,OAAe,GACxB,OAAO,CAAC,IAAI,CAAC;YAsFF,mBAAmB;YAWnB,kBAAkB;YASlB,oBAAoB;YASpB,qBAAqB;YAsFrB,cAAc;CAoB7B"}
1
+ {"version":3,"file":"DigNetwork.d.ts","sourceRoot":"","sources":["../../src/DigNetwork/DigNetwork.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAWpC,qBAAa,UAAU;IACrB,OAAO,CAAC,SAAS,CAAY;IAC7B,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,aAAa,CAA2B;gBAEpC,OAAO,EAAE,MAAM;YAOb,eAAe;IA8ChB,eAAe,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAsDhD,WAAW,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;WA6BrC,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;WAQhD,oBAAoB,CACtC,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,GAAG,CAAC,EAAE,MAAM,EACZ,eAAe,GAAE,MAAM,EAAO,GAC7B,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC;WAyDZ,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAQ5C,aAAa,CACxB,aAAa,GAAE,OAAe,EAC9B,iBAAiB,GAAE,OAAc,EACjC,QAAQ,GAAE,OAAe,GACxB,OAAO,CAAC,IAAI,CAAC;YAqHF,mBAAmB;YAWnB,kBAAkB;YASlB,oBAAoB;YASpB,qBAAqB;YAsFrB,cAAc;CAoB7B"}
@@ -128,31 +128,47 @@ class DigNetwork {
128
128
  static async findPeerWithStoreKey(storeId, rootHash, key, intialBlackList = []) {
129
129
  const peerBlackList = intialBlackList;
130
130
  const serverCoin = new blockchain_1.ServerCoin(storeId);
131
+ let peerIp = null;
132
+ // Keep sampling peers until an empty array is returned
131
133
  while (true) {
132
134
  try {
135
+ // Sample a peer from the current epoch
133
136
  const digPeers = await serverCoin.sampleCurrentEpoch(1, peerBlackList);
134
- if (digPeers.length === 0)
137
+ // If no peers are returned, break out of the loop
138
+ if (digPeers.length === 0) {
139
+ console.log("No more peers found.");
135
140
  break;
136
- const peerIp = digPeers[0];
141
+ }
142
+ peerIp = digPeers[0];
137
143
  const digPeer = new DigPeer_1.DigPeer(peerIp, storeId);
144
+ // Try to fetch the head store information
138
145
  const storeResponse = await digPeer.contentServer.headStore({
139
146
  hasRootHash: rootHash,
140
147
  });
141
- console.log(peerIp, storeResponse.headers);
148
+ // If the peer has the correct root hash, check if key is required
142
149
  if (storeResponse.headers?.["x-has-roothash"] === "true") {
143
150
  console.log(`Found Peer at ${peerIp} for storeId: ${storeId}, root hash ${rootHash}`);
151
+ // If no key is provided, return the peer
144
152
  if (!key) {
145
- return peerIp;
153
+ return digPeer;
146
154
  }
155
+ // If key is provided, check if the peer has it
147
156
  const keyResponse = await digPeer.contentServer.headKey(key);
148
157
  if (keyResponse.headers?.["x-key-exists"] === "true") {
149
- return peerIp;
158
+ return digPeer;
150
159
  }
151
160
  }
161
+ // Add peer to blacklist if it doesn't meet criteria
152
162
  peerBlackList.push(peerIp);
153
163
  }
154
- catch { }
164
+ catch (error) {
165
+ console.error(`Error connecting to peer ${peerIp}. Resampling...`);
166
+ if (peerIp) {
167
+ peerBlackList.push(peerIp); // Add to blacklist if error occurs
168
+ }
169
+ }
155
170
  }
171
+ // Return null if no valid peer was found
156
172
  return null;
157
173
  }
158
174
  static unsubscribeFromStore(storeId) {
@@ -163,37 +179,54 @@ class DigNetwork {
163
179
  }
164
180
  // Downloads files from the network based on the manifest
165
181
  async downloadFiles(forceDownload = false, renderProgressBar = true, skipData = false) {
182
+ console.log("Starting file download process...");
183
+ let peerBlackList = [];
184
+ let selectedPeer = null;
166
185
  try {
167
186
  const rootHistory = await this.dataStore.getRootHistory();
168
187
  if (!rootHistory.length) {
169
188
  throw new Error("No roots found in rootHistory. Cannot proceed with file download.");
170
189
  }
171
190
  await this.downloadHeightFile(true);
172
- const rootHistorySorted = rootHistory
191
+ // Filter out rootInfo entries where the .dat file already exists
192
+ const rootHistoryFiltered = rootHistory
173
193
  .filter((item) => item.timestamp !== undefined)
174
- .sort((a, b) => b.timestamp - a.timestamp);
175
- // Process rootHistory sequentially
176
- for (const rootInfo of rootHistorySorted) {
177
- const peerIp = await DigNetwork.findPeerWithStoreKey(this.dataStore.StoreId, rootInfo.root_hash);
178
- if (fs.existsSync(`${this.storeDir}/${rootInfo.root_hash}.dat`)) {
179
- console.log(`Root hash ${rootInfo.root_hash} already exists locally. Skipping download.`);
180
- continue; // Skip to the next rootInfo
181
- }
182
- if (!peerIp) {
183
- console.error(`No peer found with root hash ${rootInfo.root_hash}. Skipping download.`);
184
- continue; // Skip to the next rootInfo
185
- }
186
- const digPeer = new DigPeer_1.DigPeer(peerIp, this.dataStore.StoreId);
187
- const rootResponse = await digPeer.propagationServer.getStoreData(`${rootInfo.root_hash}.dat`);
188
- fs.writeFileSync(`${this.storeDir}/${rootInfo.root_hash}.dat`, rootResponse);
189
- const root = JSON.parse(rootResponse);
190
- if (!skipData) {
191
- // Sequential file download
192
- for (const [storeKey, file] of Object.entries(root.files)) {
193
- const filePath = (0, hashUtils_1.getFilePathFromSha256)(file.sha256, `${this.storeDir}/data`);
194
- if (!fs.existsSync(filePath) || forceDownload) {
195
- console.log(`Downloading file with sha256: ${file.sha256}...`);
196
- await this.downloadFileFromPeers(`data/${file.sha256.match(/.{1,2}/g).join("/")}`, filePath, forceDownload);
194
+ .filter((item) => !fs.existsSync(`${this.storeDir}/${item.root_hash}.dat`))
195
+ .reverse();
196
+ if (!rootHistoryFiltered.length) {
197
+ console.log("All root hashes already exist locally. No need for download.");
198
+ return;
199
+ }
200
+ // Process filtered rootHistory sequentially
201
+ for (const rootInfo of rootHistoryFiltered) {
202
+ while (true) {
203
+ try {
204
+ selectedPeer = await DigNetwork.findPeerWithStoreKey(this.dataStore.StoreId, rootInfo.root_hash, undefined, peerBlackList);
205
+ if (!selectedPeer) {
206
+ console.error(`No peer found with root hash ${rootInfo.root_hash}. Skipping download.`);
207
+ break; // Exit loop if no more peers are found
208
+ }
209
+ const rootResponse = await selectedPeer.propagationServer.getStoreData(`${rootInfo.root_hash}.dat`);
210
+ const root = JSON.parse(rootResponse);
211
+ if (!skipData) {
212
+ // Sequential file download
213
+ for (const [storeKey, file] of Object.entries(root.files)) {
214
+ const filePath = (0, hashUtils_1.getFilePathFromSha256)(file.sha256, `${this.storeDir}/data`);
215
+ if (!fs.existsSync(filePath) || forceDownload) {
216
+ console.log(`Downloading file with sha256: ${file.sha256}...`);
217
+ await selectedPeer.downloadData(this.dataStore.StoreId, `data/${file.sha256.match(/.{1,2}/g).join("/")}`);
218
+ }
219
+ }
220
+ }
221
+ fs.writeFileSync(`${this.storeDir}/${rootInfo.root_hash}.dat`, rootResponse);
222
+ peerBlackList = []; // Clear the blacklist upon successful download
223
+ // Break out of the retry loop if the download succeeds
224
+ break;
225
+ }
226
+ catch (error) {
227
+ console.error(`Error downloading from peer. Retrying with another peer.`, error);
228
+ if (selectedPeer) {
229
+ peerBlackList.push(selectedPeer.IpAddress); // Add peer to blacklist and try again
197
230
  }
198
231
  }
199
232
  }
@@ -202,7 +235,9 @@ class DigNetwork {
202
235
  console.log("Syncing store complete.");
203
236
  }
204
237
  catch (error) {
205
- console.trace(error);
238
+ if (selectedPeer) {
239
+ peerBlackList.push(selectedPeer.IpAddress);
240
+ }
206
241
  throw error;
207
242
  }
208
243
  }
@@ -19,5 +19,6 @@ export declare class DigPeer {
19
19
  static sendBulkPayments(walletName: string, outputs: Output[]): Promise<void>;
20
20
  sendPayment(walletName: string, amount: bigint, memos?: Buffer[]): Promise<void>;
21
21
  static createPaymentHint(storeId: Buffer): Buffer;
22
+ downloadData(storeId: string, dataPath: string): Promise<void>;
22
23
  }
23
24
  //# sourceMappingURL=DigPeer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"DigPeer.d.ts","sourceRoot":"","sources":["../../src/DigNetwork/DigPeer.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAGpD,OAAO,EAKL,MAAM,EACP,MAAM,8BAA8B,CAAC;AAKtC,qBAAa,OAAO;IAClB,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,cAAc,CAAgB;IACtC,OAAO,CAAC,kBAAkB,CAAoB;IAC9C,OAAO,CAAC,gBAAgB,CAAkB;gBAE9B,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;IAS9C,IAAW,aAAa,IAAI,aAAa,CAExC;IAGD,IAAW,iBAAiB,IAAI,iBAAiB,CAEhD;IAGD,IAAW,eAAe,IAAI,eAAe,CAE5C;IAED,IAAW,SAAS,IAAI,MAAM,CAE7B;IAEY,aAAa,CACxB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,EAAE,GACb,OAAO,CAAC,OAAO,CAAC;IAgHN,QAAQ,IAAI,OAAO,CAAC,OAAO,CAAC;WA2B3B,qBAAqB,CACjC,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,EAAE,EACnB,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,MAAM,EAAE,GACd,OAAO,CAAC,IAAI,CAAC;WAuBI,gBAAgB,CAClC,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,EAAE,GAChB,OAAO,CAAC,IAAI,CAAC;IAwCH,WAAW,CACtB,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,EACd,KAAK,GAAE,MAAM,EAAO,GACnB,OAAO,CAAC,IAAI,CAAC;WAYF,iBAAiB,CAAC,OAAO,EAAE,MAAM;CAoBhD"}
1
+ {"version":3,"file":"DigPeer.d.ts","sourceRoot":"","sources":["../../src/DigNetwork/DigPeer.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAIpD,OAAO,EAKL,MAAM,EACP,MAAM,8BAA8B,CAAC;AAUtC,qBAAa,OAAO;IAClB,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,cAAc,CAAgB;IACtC,OAAO,CAAC,kBAAkB,CAAoB;IAC9C,OAAO,CAAC,gBAAgB,CAAkB;gBAE9B,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;IAS9C,IAAW,aAAa,IAAI,aAAa,CAExC;IAGD,IAAW,iBAAiB,IAAI,iBAAiB,CAEhD;IAGD,IAAW,eAAe,IAAI,eAAe,CAE5C;IAED,IAAW,SAAS,IAAI,MAAM,CAE7B;IAEY,aAAa,CACxB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,EAAE,GACb,OAAO,CAAC,OAAO,CAAC;IAgHN,QAAQ,IAAI,OAAO,CAAC,OAAO,CAAC;WA2B3B,qBAAqB,CACjC,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,EAAE,EACnB,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,MAAM,EAAE,GACd,OAAO,CAAC,IAAI,CAAC;WAuBI,gBAAgB,CAClC,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,EAAE,GAChB,OAAO,CAAC,IAAI,CAAC;IAwCH,WAAW,CACtB,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,EACd,KAAK,GAAE,MAAM,EAAO,GACnB,OAAO,CAAC,IAAI,CAAC;WAYF,iBAAiB,CAAC,OAAO,EAAE,MAAM;IAqBlC,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CA4C5E"}
@@ -4,16 +4,22 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.DigPeer = void 0;
7
+ const path_1 = __importDefault(require("path"));
7
8
  const crypto_1 = __importDefault(require("crypto"));
8
9
  const ContentServer_1 = require("./ContentServer");
9
10
  const PropagationServer_1 = require("./PropagationServer");
10
11
  const IncentiveServer_1 = require("./IncentiveServer");
11
12
  const blockchain_1 = require("../blockchain");
12
13
  const DataIntegrityTree_1 = require("../DataIntegrityTree");
14
+ const fs_1 = __importDefault(require("fs"));
13
15
  const datalayer_driver_1 = require("@dignetwork/datalayer-driver");
14
16
  const blockchain_2 = require("../blockchain");
15
17
  const blockchain_3 = require("../blockchain");
16
18
  const coins_1 = require("../blockchain/coins");
19
+ const config_1 = require("../utils/config");
20
+ const util_1 = require("util");
21
+ const rename = (0, util_1.promisify)(fs_1.default.rename);
22
+ const unlink = (0, util_1.promisify)(fs_1.default.unlink);
17
23
  class DigPeer {
18
24
  constructor(ipAddress, storeId) {
19
25
  this.ipAddress = ipAddress;
@@ -195,5 +201,41 @@ class DigPeer {
195
201
  // Return the 32-byte hash as a hex string
196
202
  return transformedBuffer;
197
203
  }
204
+ async downloadData(storeId, dataPath) {
205
+ const filePath = path_1.default.join(config_1.STORE_PATH, storeId, dataPath);
206
+ const tempFilePath = `${filePath}.tmp`;
207
+ try {
208
+ const headStoreResponse = await this.propagationServer.headStore();
209
+ if (!headStoreResponse.success) {
210
+ throw new Error("Data not accessible from store.");
211
+ }
212
+ const directory = path_1.default.dirname(tempFilePath);
213
+ if (!fs_1.default.existsSync(directory)) {
214
+ fs_1.default.mkdirSync(directory, { recursive: true });
215
+ }
216
+ const fileStream = fs_1.default.createWriteStream(tempFilePath);
217
+ const dataStream = await this.propagationServer.streamStoreData(dataPath);
218
+ await new Promise((resolve, reject) => {
219
+ dataStream.pipe(fileStream);
220
+ dataStream.on("end", resolve);
221
+ dataStream.on("error", reject);
222
+ fileStream.on("error", reject);
223
+ });
224
+ await rename(tempFilePath, filePath);
225
+ console.log(`Downloaded ${dataPath} from ${this.IpAddress}`);
226
+ }
227
+ catch (error) {
228
+ console.error(`Failed to download data: ${error.message}`);
229
+ if (fs_1.default.existsSync(tempFilePath)) {
230
+ await unlink(tempFilePath);
231
+ }
232
+ // Check if directory is empty and remove it if it is
233
+ const directory = path_1.default.dirname(tempFilePath);
234
+ if (fs_1.default.existsSync(directory) && fs_1.default.readdirSync(directory).length === 0) {
235
+ fs_1.default.rmdirSync(directory);
236
+ console.log(`Removed empty directory: ${directory}`);
237
+ }
238
+ }
239
+ }
198
240
  }
199
241
  exports.DigPeer = DigPeer;
@@ -271,7 +271,7 @@ class PropagationServer {
271
271
  }
272
272
  });
273
273
  request.on("error", (error) => {
274
- console.error(`Request error for ${url}:`, error);
274
+ console.error(`GET Request error for ${url}:`, error);
275
275
  reject(error);
276
276
  });
277
277
  request.end();
@@ -326,13 +326,13 @@ class PropagationServer {
326
326
  }
327
327
  });
328
328
  request.on("error", (error) => {
329
- console.error(`Request error for ${url}:`, error);
329
+ console.error(`HEAD ${url}:`, error.message);
330
330
  reject({ success: false });
331
331
  });
332
332
  request.end();
333
333
  }
334
334
  catch (err) {
335
- console.error(`Invalid URL: ${url}`, err);
335
+ console.error(`Invalid URL: ${url}`, err.message);
336
336
  reject({ success: false, message: "Invalid URL" });
337
337
  }
338
338
  });
@@ -432,7 +432,7 @@ class PropagationServer {
432
432
  }
433
433
  });
434
434
  request.on("error", (error) => {
435
- console.error(`Request error for ${url}:`, error);
435
+ console.error(`GET ${url}:`, error.message);
436
436
  reject(error);
437
437
  });
438
438
  request.end();
@@ -1 +1 @@
1
- {"version":3,"file":"ServerCoin.d.ts","sourceRoot":"","sources":["../../src/blockchain/ServerCoin.ts"],"names":[],"mappings":"AACA,OAAO,EAML,UAAU,IAAI,gBAAgB,EAE/B,MAAM,8BAA8B,CAAC;AAItC,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAMrD,qBAAa,UAAU;IACrB,OAAO,CAAC,OAAO,CAAS;IACxB,gBAAuB,iBAAiB,eAEtC;gBAEU,OAAO,EAAE,MAAM;IAKd,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;IA2DzD,kBAAkB,CAC7B,UAAU,EAAE,gBAAgB,EAC5B,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,IAAI,CAAC;IAqBH,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;YAoDjD,oBAAoB;IAerB,gBAAgB,CAC3B,KAAK,EAAE,MAAM,EACb,SAAS,GAAE,MAAM,EAAO,GACvB,OAAO,CAAC,MAAM,EAAE,CAAC;IAoCP,mBAAmB,CAC9B,SAAS,GAAE,MAAM,EAAO,GACvB,OAAO,CAAC,MAAM,EAAE,CAAC;IAMP,kBAAkB,CAC7B,UAAU,GAAE,MAAU,EACtB,SAAS,GAAE,MAAM,EAAO,GACvB,OAAO,CAAC,MAAM,EAAE,CAAC;IAMP,wBAAwB,CACnC,KAAK,EAAE,MAAM,EACb,UAAU,GAAE,MAAU,EACtB,SAAS,GAAE,MAAM,EAAO,GACvB,OAAO,CAAC,MAAM,EAAE,CAAC;WAMN,eAAe,IAAI;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE;IAKpD,sBAAsB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAiDrD,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;WA+B1C,uBAAuB;YAkE7B,sBAAsB;IAWvB,uBAAuB,CAClC,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,OAAO,CAAC;WAuBL,sBAAsB,CAAC,mBAAmB,EAAE,IAAI,GAAG;QAC/D,KAAK,EAAE,MAAM,CAAC;QACd,KAAK,EAAE,MAAM,CAAC;KACf;CA2BF"}
1
+ {"version":3,"file":"ServerCoin.d.ts","sourceRoot":"","sources":["../../src/blockchain/ServerCoin.ts"],"names":[],"mappings":"AACA,OAAO,EAML,UAAU,IAAI,gBAAgB,EAE/B,MAAM,8BAA8B,CAAC;AAItC,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAMrD,qBAAa,UAAU;IACrB,OAAO,CAAC,OAAO,CAAS;IACxB,gBAAuB,iBAAiB,eAEtC;gBAEU,OAAO,EAAE,MAAM;IAKd,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;IA2DzD,kBAAkB,CAC7B,UAAU,EAAE,gBAAgB,EAC5B,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,IAAI,CAAC;IAqBH,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;YAoDjD,oBAAoB;IAerB,gBAAgB,CAC3B,KAAK,EAAE,MAAM,EACb,SAAS,GAAE,MAAM,EAAO,GACvB,OAAO,CAAC,MAAM,EAAE,CAAC;IAoCP,mBAAmB,CAC9B,SAAS,GAAE,MAAM,EAAO,GACvB,OAAO,CAAC,MAAM,EAAE,CAAC;IAMP,kBAAkB,CAC7B,UAAU,GAAE,MAAU,EACtB,SAAS,GAAE,MAAM,EAAO,GACvB,OAAO,CAAC,MAAM,EAAE,CAAC;IAMP,wBAAwB,CACnC,KAAK,EAAE,MAAM,EACb,UAAU,GAAE,MAAU,EACtB,SAAS,GAAE,MAAM,EAAO,GACvB,OAAO,CAAC,MAAM,EAAE,CAAC;WAON,eAAe,IAAI;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE;IAKpD,sBAAsB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAiDrD,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;WA+B1C,uBAAuB;YAkE7B,sBAAsB;IAWvB,uBAAuB,CAClC,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,OAAO,CAAC;WAuBL,sBAAsB,CAAC,mBAAmB,EAAE,IAAI,GAAG;QAC/D,KAAK,EAAE,MAAM,CAAC;QACd,KAAK,EAAE,MAAM,CAAC;KACf;CA2BF"}
@@ -126,6 +126,7 @@ class ServerCoin {
126
126
  // Sample server coins by epoch
127
127
  async sampleServerCoinsByEpoch(epoch, sampleSize = 5, blacklist = []) {
128
128
  const serverCoinPeers = await this.getAllEpochPeers(epoch, blacklist);
129
+ console.log("Server Coin Peers: ", serverCoinPeers);
129
130
  return lodash_1.default.sampleSize(serverCoinPeers, sampleSize);
130
131
  }
131
132
  // Get the current epoch based on the current timestamp
@@ -0,0 +1,47 @@
1
+ import { Readable } from "stream";
2
+ export declare class FileTransfer {
3
+ private static certPath;
4
+ private static keyPath;
5
+ constructor();
6
+ /** ------------------------ UPLOAD FUNCTIONALITY ------------------------ **/
7
+ /**
8
+ * Upload a file to the server using a stream.
9
+ * @param filePath - Local path of the file.
10
+ * @param uploadUrl - Server URL to upload the file.
11
+ * @param headers - Additional headers for the request.
12
+ * @returns Promise<void>
13
+ */
14
+ uploadFile(filePath: string, uploadUrl: string, headers: Record<string, string>): Promise<void>;
15
+ /**
16
+ * Perform a POST request.
17
+ * @param url - The URL to POST to.
18
+ * @param data - Data to send.
19
+ * @param headers - Headers for the POST request.
20
+ * @returns Promise<void>
21
+ */
22
+ postRequest(url: string, data: string, headers: Record<string, string>): Promise<void>;
23
+ /** ------------------------ DOWNLOAD FUNCTIONALITY ------------------------ **/
24
+ /**
25
+ * Download data from a URL.
26
+ * @param url - The URL to download data from.
27
+ * @returns Promise<string>
28
+ */
29
+ downloadData(url: string): Promise<string>;
30
+ /**
31
+ * Stream data from a URL.
32
+ * @param url - The URL to stream data from.
33
+ * @returns Promise<Readable>
34
+ */
35
+ streamData(url: string): Promise<Readable>;
36
+ /** ------------------------ HEAD REQUEST FUNCTIONALITY ------------------------ **/
37
+ /**
38
+ * Perform a HEAD request to check if a resource exists on the server.
39
+ * @param url - The URL to check.
40
+ * @returns Promise<{ success: boolean; headers?: Record<string, string> }>
41
+ */
42
+ headRequest(url: string): Promise<{
43
+ success: boolean;
44
+ headers?: Record<string, string>;
45
+ }>;
46
+ }
47
+ //# sourceMappingURL=FileTransfer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FileTransfer.d.ts","sourceRoot":"","sources":["../../src/utils/FileTransfer.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAElC,qBAAa,YAAY;IACvB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAS;IAChC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAS;;IAU/B,8EAA8E;IAE9E;;;;;;OAMG;IACU,UAAU,CACrB,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC9B,OAAO,CAAC,IAAI,CAAC;IA0ChB;;;;;;OAMG;IACU,WAAW,CACtB,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC9B,OAAO,CAAC,IAAI,CAAC;IAsChB,gFAAgF;IAEhF;;;;OAIG;IACU,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IA0CvD;;;;OAIG;IACU,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC;IAuCvD,oFAAoF;IAEpF;;;;OAIG;IACU,WAAW,CACtB,GAAG,EAAE,MAAM,GACV,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,CAAC;CA8BnE"}
@@ -0,0 +1,209 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.FileTransfer = void 0;
7
+ const fs_1 = __importDefault(require("fs"));
8
+ const https_1 = __importDefault(require("https"));
9
+ const url_1 = require("url");
10
+ const ssl_1 = require("../utils/ssl");
11
+ class FileTransfer {
12
+ constructor() {
13
+ if (!FileTransfer.certPath || !FileTransfer.keyPath) {
14
+ const { certPath, keyPath } = (0, ssl_1.getOrCreateSSLCerts)();
15
+ FileTransfer.certPath = certPath;
16
+ FileTransfer.keyPath = keyPath;
17
+ }
18
+ }
19
+ /** ------------------------ UPLOAD FUNCTIONALITY ------------------------ **/
20
+ /**
21
+ * Upload a file to the server using a stream.
22
+ * @param filePath - Local path of the file.
23
+ * @param uploadUrl - Server URL to upload the file.
24
+ * @param headers - Additional headers for the request.
25
+ * @returns Promise<void>
26
+ */
27
+ async uploadFile(filePath, uploadUrl, headers) {
28
+ const fileStream = fs_1.default.createReadStream(filePath);
29
+ const fileSize = fs_1.default.statSync(filePath).size;
30
+ return new Promise((resolve, reject) => {
31
+ const url = new url_1.URL(uploadUrl);
32
+ const options = {
33
+ hostname: url.hostname,
34
+ port: url.port || 443,
35
+ path: url.pathname,
36
+ method: "PUT",
37
+ headers: {
38
+ ...headers,
39
+ "Content-Type": "application/octet-stream",
40
+ "Content-Length": fileSize,
41
+ },
42
+ key: fs_1.default.readFileSync(FileTransfer.keyPath),
43
+ cert: fs_1.default.readFileSync(FileTransfer.certPath),
44
+ rejectUnauthorized: false,
45
+ };
46
+ const req = https_1.default.request(options, (res) => {
47
+ if (res.statusCode === 200) {
48
+ resolve();
49
+ }
50
+ else {
51
+ reject(new Error(`Upload failed with status ${res.statusCode}: ${res.statusMessage}`));
52
+ }
53
+ });
54
+ req.on("error", (err) => reject(err));
55
+ fileStream.pipe(req);
56
+ fileStream.on("error", (err) => reject(err));
57
+ });
58
+ }
59
+ /**
60
+ * Perform a POST request.
61
+ * @param url - The URL to POST to.
62
+ * @param data - Data to send.
63
+ * @param headers - Headers for the POST request.
64
+ * @returns Promise<void>
65
+ */
66
+ async postRequest(url, data, headers) {
67
+ return new Promise((resolve, reject) => {
68
+ const urlObj = new url_1.URL(url);
69
+ const options = {
70
+ hostname: urlObj.hostname,
71
+ port: urlObj.port || 443,
72
+ path: urlObj.pathname,
73
+ method: "POST",
74
+ headers: {
75
+ ...headers,
76
+ "Content-Type": "application/json",
77
+ "Content-Length": Buffer.byteLength(data),
78
+ },
79
+ key: fs_1.default.readFileSync(FileTransfer.keyPath),
80
+ cert: fs_1.default.readFileSync(FileTransfer.certPath),
81
+ rejectUnauthorized: false,
82
+ };
83
+ const req = https_1.default.request(options, (res) => {
84
+ if (res.statusCode === 200) {
85
+ resolve();
86
+ }
87
+ else {
88
+ reject(new Error(`POST request failed with status ${res.statusCode}: ${res.statusMessage}`));
89
+ }
90
+ });
91
+ req.on("error", (err) => reject(err));
92
+ req.write(data);
93
+ req.end();
94
+ });
95
+ }
96
+ /** ------------------------ DOWNLOAD FUNCTIONALITY ------------------------ **/
97
+ /**
98
+ * Download data from a URL.
99
+ * @param url - The URL to download data from.
100
+ * @returns Promise<string>
101
+ */
102
+ async downloadData(url) {
103
+ return new Promise((resolve, reject) => {
104
+ const urlObj = new url_1.URL(url);
105
+ const options = {
106
+ hostname: urlObj.hostname,
107
+ port: urlObj.port || 443,
108
+ path: urlObj.pathname + urlObj.search,
109
+ method: "GET",
110
+ key: fs_1.default.readFileSync(FileTransfer.keyPath),
111
+ cert: fs_1.default.readFileSync(FileTransfer.certPath),
112
+ rejectUnauthorized: false,
113
+ };
114
+ const req = https_1.default.request(options, (res) => {
115
+ let data = "";
116
+ if (res.statusCode === 200) {
117
+ res.on("data", (chunk) => (data += chunk));
118
+ res.on("end", () => resolve(data));
119
+ }
120
+ else if (res.statusCode === 301 || res.statusCode === 302) {
121
+ const redirectUrl = res.headers.location;
122
+ if (redirectUrl) {
123
+ this.downloadData(redirectUrl).then(resolve).catch(reject);
124
+ }
125
+ else {
126
+ reject(new Error("Redirected without a location header"));
127
+ }
128
+ }
129
+ else {
130
+ reject(new Error(`Failed to retrieve data from ${url}. Status code: ${res.statusCode}`));
131
+ }
132
+ });
133
+ req.on("error", (error) => reject(error));
134
+ req.end();
135
+ });
136
+ }
137
+ /**
138
+ * Stream data from a URL.
139
+ * @param url - The URL to stream data from.
140
+ * @returns Promise<Readable>
141
+ */
142
+ async streamData(url) {
143
+ return new Promise((resolve, reject) => {
144
+ const urlObj = new url_1.URL(url);
145
+ const options = {
146
+ hostname: urlObj.hostname,
147
+ port: urlObj.port || 443,
148
+ path: urlObj.pathname + urlObj.search,
149
+ method: "GET",
150
+ key: fs_1.default.readFileSync(FileTransfer.keyPath),
151
+ cert: fs_1.default.readFileSync(FileTransfer.certPath),
152
+ rejectUnauthorized: false,
153
+ };
154
+ const req = https_1.default.request(options, (res) => {
155
+ if (res.statusCode === 200) {
156
+ resolve(res); // Return the readable stream
157
+ }
158
+ else if (res.statusCode === 301 || res.statusCode === 302) {
159
+ const redirectUrl = res.headers.location;
160
+ if (redirectUrl) {
161
+ this.streamData(redirectUrl).then(resolve).catch(reject);
162
+ }
163
+ else {
164
+ reject(new Error("Redirected without a location header"));
165
+ }
166
+ }
167
+ else {
168
+ reject(new Error(`Failed to retrieve stream from ${url}. Status code: ${res.statusCode}`));
169
+ }
170
+ });
171
+ req.on("error", (error) => reject(error));
172
+ req.end();
173
+ });
174
+ }
175
+ /** ------------------------ HEAD REQUEST FUNCTIONALITY ------------------------ **/
176
+ /**
177
+ * Perform a HEAD request to check if a resource exists on the server.
178
+ * @param url - The URL to check.
179
+ * @returns Promise<{ success: boolean; headers?: Record<string, string> }>
180
+ */
181
+ async headRequest(url) {
182
+ return new Promise((resolve, reject) => {
183
+ const urlObj = new url_1.URL(url);
184
+ const options = {
185
+ hostname: urlObj.hostname,
186
+ port: urlObj.port || 443,
187
+ path: urlObj.pathname,
188
+ method: "HEAD",
189
+ key: fs_1.default.readFileSync(FileTransfer.keyPath),
190
+ cert: fs_1.default.readFileSync(FileTransfer.certPath),
191
+ rejectUnauthorized: false,
192
+ };
193
+ const req = https_1.default.request(options, (res) => {
194
+ if (res.statusCode === 200) {
195
+ resolve({
196
+ success: true,
197
+ headers: res.headers,
198
+ });
199
+ }
200
+ else {
201
+ resolve({ success: false });
202
+ }
203
+ });
204
+ req.on("error", (err) => reject(err));
205
+ req.end();
206
+ });
207
+ }
208
+ }
209
+ exports.FileTransfer = FileTransfer;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dignetwork/dig-sdk",
3
- "version": "0.0.1-alpha.45",
3
+ "version": "0.0.1-alpha.47",
4
4
  "description": "",
5
5
  "type": "commonjs",
6
6
  "main": "./dist/index.js",