andrade-soulseek-downloader
Version:
Simple, safe Soulseek download library with built-in rate limiting to prevent bans
193 lines • 9.03 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.DefaultPeer = void 0;
const zlib = __importStar(require("zlib"));
const peer_1 = require("./peer");
const messages_1 = require("../messages");
const message_factory_1 = require("../message-factory");
const download_peer_file_1 = require("./download-peer-file");
const stack_1 = __importDefault(require("../stack"));
const debug = (msg) => {
if (process.env.DEBUG?.includes('slsk:peer:default')) {
console.log(`[slsk:peer:default] ${msg}`);
}
};
class DefaultPeer extends peer_1.Peer {
constructor(socket, peer) {
super(socket, peer);
this.conn.on('connect', () => {
if (peer.token) {
const buf = Buffer.from('05000000' + '00' + peer.token, 'hex');
this.conn.write(buf);
}
});
const msgs = new messages_1.Messages();
this.conn.on('data', data => {
msgs.write(data);
});
msgs.on('message', (msg) => {
const size = msg.int32();
if (size <= 4)
return;
const code = msg.int32();
switch (code) {
case 4: {
debug(`${peer.user} recv GetSharedFileList ${size}`);
const res = message_factory_1.MessageFactory.to.peer.sharedFileList(1, 'test', 1, '@@abcde\\test\\test-test.mp3');
debug(`${peer.user} sending SharedFileList`);
this.conn.write(res.getBuff());
break;
}
case 9: {
debug(`${peer.user} recv FileSearchResult size ${size}`);
const content = msg.data.slice(msg.pointer, size + 4);
zlib.unzip(content, (err, buffer) => {
if (err) {
debug(err.toString());
return;
}
const result = message_factory_1.MessageFactory.from.peer.fileSearchResult(buffer);
if (stack_1.default.search[result.currentToken]) {
result.files.forEach(file => {
stack_1.default.search[result.currentToken].cb({
user: file.user,
file: file.file,
size: file.size,
slots: result.slots === 1,
bitrate: file.attribs ? file.attribs[0] : undefined,
speed: result.speed,
queue: 0
});
});
}
});
break;
}
case 36: {
const numberOfFiles = msg.int32();
debug(`${peer.user} recv FolderContentsRequest, files: ${numberOfFiles}`);
break;
}
case 40: {
const dir = msg.int32();
const token = msg.rawHexStr(4);
const file = msg.str();
debug(`${peer.user} recv TransferRequest ${file}`);
// Don't overwrite if token already exists (preserve progressEmitter)
if (!stack_1.default.downloadTokens[token]) {
stack_1.default.downloadTokens[token] = {
user: peer.user,
file
};
}
else {
// Update fields but preserve existing properties like progressEmitter
stack_1.default.downloadTokens[token].user = peer.user;
stack_1.default.downloadTokens[token].file = file;
}
if (dir === 1) {
stack_1.default.downloadTokens[token].size = msg.int32();
}
const res = message_factory_1.MessageFactory.to.peer.transferResponse(token);
setTimeout(() => {
debug(`${peer.user} sending TransferResponse`);
this.conn.write(res.getBuff());
}, 200);
break;
}
case 41: {
const token = msg.rawHexStr(4);
const allowed = msg.int8();
debug(`${peer.user} recv TransferResponse token: ${token} allowed: ${allowed}`);
if (allowed === 0) {
const reason = msg.str();
debug(`reason: ${reason}, I will receive TransferRequest soon...`);
delete stack_1.default.downloadTokens[token];
}
else if (allowed === 1) {
debug(`Directly allowed. Connecting to peer with PeerInit + ${token}`);
const downloader = (0, download_peer_file_1.downloadPeerFile)(peer.host, peer.port, token, peer.user, true);
// Link the progress emitters
if (stack_1.default.downloadTokens[token] && stack_1.default.downloadTokens[token].progressEmitter) {
debug(`Found progressEmitter for token ${token}, linking events`);
const mainEmitter = stack_1.default.downloadTokens[token].progressEmitter;
downloader.on('start', (data) => {
debug(`Forwarding start event`);
mainEmitter.emit('start', data);
});
downloader.on('progress', (data) => {
debug(`Forwarding progress: ${data.percentage}%`);
mainEmitter.emit('progress', data);
});
downloader.on('complete', (data) => mainEmitter.emit('complete', data));
downloader.on('error', (err) => mainEmitter.emit('error', err));
}
else {
debug(`No progressEmitter found for token ${token}`);
}
}
break;
}
case 46: {
const filename = msg.str();
debug(`${peer.user} UploadFailed ${filename}`);
const down = stack_1.default.download[peer.user + '_' + filename];
if (down && typeof down.cb === 'function') {
down.cb(new Error('Peer error'));
}
else {
debug(`Cannot cb for ${peer.user} ${filename}`);
}
break;
}
case 50: {
const filename = msg.str();
const reason = msg.str();
debug(`${peer.user} QueueFailed ${filename} reason ${reason}`);
break;
}
default: {
debug(`${peer.user} unknown peer message code ${code}`);
}
}
});
}
}
exports.DefaultPeer = DefaultPeer;
//# sourceMappingURL=default-peer.js.map