Compare commits

..

10 Commits

Author SHA1 Message Date
Peter Stockings
28f011419c Fix progress bar 2026-01-01 17:29:00 +11:00
Peter Stockings
cbe39e76a2 Add logging to debug why the download doesnt progress when deployed to dokku 2026-01-01 17:22:53 +11:00
Peter Stockings
134c4b36c9 Bump bun version in Dockerfile and add fixes for downloads 2026-01-01 17:11:38 +11:00
Peter Stockings
e51fb204e0 Node modules wasnt copied over, and fixed issue with bun build by building each workspace individually 2026-01-01 16:46:54 +11:00
Peter Stockings
0af9fa02a0 Issue was with wildcard in bun build step 2026-01-01 16:39:03 +11:00
Peter Stockings
72334f3d78 Attempt to fix bun build error 2026-01-01 16:35:41 +11:00
Peter Stockings
67fe5ae406 Fix reference to bun lock file 2026-01-01 16:33:35 +11:00
Peter Stockings
ddd554d506 Remove .buildpacks and set port in Dockerfile 2026-01-01 16:32:01 +11:00
Peter Stockings
061f25fdcb Switch to using Docker file deployment 2026-01-01 16:29:57 +11:00
Peter Stockings
3a651c5bc8 Add logs for server start 2026-01-01 16:27:35 +11:00
8 changed files with 106 additions and 8 deletions

View File

@@ -1 +0,0 @@
https://github.com/jakeg/heroku-buildpack-bun

8
.dockerignore Normal file
View File

@@ -0,0 +1,8 @@
**/node_modules
dist
.git
.gitignore
.env
downloads
packages/client/dist
packages/server/dist

40
Dockerfile Normal file
View File

@@ -0,0 +1,40 @@
# Use the official Bun image
FROM oven/bun:latest
# Set working directory
WORKDIR /app
# Copy package files first for caching
COPY package.json bun.lock ./
COPY packages/client/package.json ./packages/client/
COPY packages/server/package.json ./packages/server/
COPY packages/shared/package.json ./packages/shared/
# Install dependencies
RUN bun install --frozen-lockfile
# Copy the rest of the application
COPY . .
# Build the client (Vite) and server (TSC)
# ensuring the environment variables are set for the build if needed
ENV NODE_ENV=production
ENV PORT=3000
# Build packages individually by changing directory
WORKDIR /app/packages/shared
RUN bun run build
WORKDIR /app/packages/server
RUN bun run build
WORKDIR /app/packages/client
RUN bun run build
# Reset working directory
WORKDIR /app
# Expose the port (Dokku will override PORT env var, but 3000 is a good default documentation)
EXPOSE 3000
# Start the server
CMD ["bun", "packages/server/src/index.ts"]

1
MagnetLink.txt Normal file
View File

@@ -0,0 +1 @@
magnet:?xt=urn:btih:A18230D43BDA105BE7DEF84CB711859018AAA92D&dn=Snow%20Crash%20by%20Neal%20Stephenson%20EPUB&tr=udp%3A%2F%2Ftracker.opentrackr.org%3A1337&tr=udp%3A%2F%2Fopen.stealth.si%3A80%2Fannounce&tr=udp%3A%2F%2Ftracker.torrent.eu.org%3A451%2Fannounce&tr=udp%3A%2F%2Ftracker.bittor.pw%3A1337%2Fannounce&tr=udp%3A%2F%2Fpublic.popcorn-tracker.org%3A6969%2Fannounce&tr=udp%3A%2F%2Ftracker.dler.org%3A6969%2Fannounce&tr=udp%3A%2F%2Fexodus.desync.com%3A6969&tr=udp%3A%2F%2Fopen.demonii.com%3A1337%2Fannounce&tr=udp%3A%2F%2Fglotorrents.pw%3A6969%2Fannounce&tr=udp%3A%2F%2Ftracker.coppersurfer.tk%3A6969&tr=udp%3A%2F%2Ftorrent.gresille.org%3A80%2Fannounce&tr=udp%3A%2F%2Fp4p.arenabg.com%3A1337&tr=udp%3A%2F%2Ftracker.internetwarriors.net%3A1337

View File

@@ -66,8 +66,8 @@ export class TorrentSession {
this.refillWorkers();
}
}
} catch (e) {
// Tracker error
} catch (e: any) {
console.error(`[Engine] Tracker ${tracker} failed: ${e?.message || e}`);
}
});
@@ -154,7 +154,7 @@ export class TorrentSession {
}
for (const worker of this.workers) {
if (worker.getPendingRequests().size >= 5) continue;
if (worker.getPendingRequests().size >= 5 || worker.isChoked()) continue;
// 1. Prioritize ongoing piece reassembly
let foundWork = false;
@@ -212,6 +212,7 @@ export class TorrentSession {
const actualHash = crypto.createHash('sha1').update(fullPiece).digest();
if (expectedHash && Buffer.compare(actualHash, expectedHash) === 0) {
console.log(`[Engine] Piece ${index} VERIFIED! Progress: ${this.progress}%`);
this.bitfield.set(index);
this.storage?.writePiece(index, this.pieceLength, fullPiece);
this.reassemblers.delete(index);
@@ -224,11 +225,26 @@ export class TorrentSession {
console.log(`[Engine] Torrent ${this.hash} download COMPLETED!`);
}
} else {
// Hash failed, restart piece
const expectedHex = expectedHash ? Buffer.from(expectedHash).toString('hex').slice(0, 8) : 'unknown';
const actualHex = actualHash.toString('hex').slice(0, 8);
console.error(`[Engine] Piece ${index} Hash Mismatch! Expected ${expectedHex}... Got ${actualHex}...`);
this.reassemblers.delete(index);
}
}
// Calculate granular progress
const verifiedBytes = Array.from({ length: this.bitfield.totalPieces })
.filter((_, i) => this.bitfield!.has(i))
.length * this.pieceLength;
let bufferedBytes = 0;
for (const r of this.reassemblers.values()) {
bufferedBytes += r.getBufferedBytes();
}
const currentBytes = Math.min(this.totalSize, verifiedBytes + bufferedBytes); // Cap at total size
this.progress = Math.floor((currentBytes / this.totalSize) * 100);
this.scheduleWork();
}

View File

@@ -31,9 +31,15 @@ export async function getPeersFromUDPTracker(trackerUrl: string, infoHashHex: st
const connectMsg = Buffer.concat([connectionId, Buffer.from([0, 0, 0, 0]), transactionId]);
const timeout = setTimeout(() => { client.close(); resolve([]); }, getCONFIG().TRACKER_TIMEOUT);
const timeout = setTimeout(() => {
console.warn(`[UDP] Tracker ${url.hostname} timed out`);
client.close();
resolve([]);
}, getCONFIG().TRACKER_TIMEOUT);
client.on("message", (msg) => {
// ... existing message handling check
// For brevity keeping logic same but assuming success logging could be added here if needed
const action = msg.readInt32BE(0);
const receivedTransactionId = msg.slice(4, 8);
if (!transactionId.equals(receivedTransactionId)) return;
@@ -47,17 +53,30 @@ export async function getPeersFromUDPTracker(trackerUrl: string, infoHashHex: st
Buffer.from([0, 0, 0, 2]), Buffer.alloc(4), Buffer.alloc(4),
Buffer.from([0xFF, 0xFF, 0xFF, 0xFF]), Buffer.from([0x1B, 0x39])
]);
client.send(announceMsg, parseInt(url.port), url.hostname);
client.send(announceMsg, parseInt(url.port), url.hostname, (err) => {
if (err) console.error(`[UDP] Announce send error to ${url.hostname}:`, err);
});
} else if (action === 1) {
const peers = [];
for (let i = 20; i + 6 <= msg.length; i += 6) {
peers.push(`${msg[i]}.${msg[i + 1]}.${msg[i + 2]}.${msg[i + 3]}:${msg.readUInt16BE(i + 4)}`);
}
console.log(`[UDP] Tracker ${url.hostname} returned ${peers.length} peers`);
clearTimeout(timeout); client.close(); resolve(peers);
}
});
client.send(connectMsg, parseInt(url.port), url.hostname, () => {});
client.on('error', (err) => {
console.error(`[UDP] Socket error for ${url.hostname}:`, err);
clearTimeout(timeout);
resolve([]);
});
// Explicitly handle DNS errors during send
client.send(connectMsg, parseInt(url.port), url.hostname, (err) => {
if (err) console.error(`[UDP] Connect send error to ${url.hostname}:`, err);
else console.log(`[UDP] Sent connect to ${url.hostname}`);
});
});
}

View File

@@ -35,4 +35,12 @@ export class PieceReassembler {
}
return missing;
}
public getBufferedBytes(): number {
let bytes = 0;
for (const data of this.blocks.values()) {
bytes += data.length;
}
return bytes;
}
}

View File

@@ -103,6 +103,7 @@ export class PeerWorker {
this.peerChoked = true;
break;
case 1: // unchoke
console.log(`[Worker] Unchoked by ${this.host}`);
this.peerChoked = false;
this.onReady(); // Ready to request blocks now!
break;
@@ -123,6 +124,7 @@ export class PeerWorker {
const begin = payload.readUInt32BE(4);
const block = payload.slice(8);
this.pendingRequests.delete(`${index}:${begin}`);
// console.log(`[Worker] Received block ${index}:${begin} (${block.length} bytes) from ${this.host}`);
this.onPiece(index, begin, block);
this.activeRequests--;
break;
@@ -166,6 +168,7 @@ export class PeerWorker {
const len = Buffer.alloc(4);
len.writeUInt32BE(13);
this.socket.write(Buffer.concat([len, req]));
console.log(`[Worker] Requested block ${index}:${begin} from ${this.host}`);
this.activeRequests++;
this.pendingRequests.add(key);
}
@@ -174,4 +177,8 @@ export class PeerWorker {
public hasPiece(index: number) {
return this.peerBitfield?.has(index) ?? false;
}
public isChoked() {
return this.peerChoked;
}
}