"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
Object.defineProperty(exports, "__esModule", { value: true });
const _1 = require("./");
const database_1 = require("../../database");
const compactd_models_1 = require("compactd-models");
const storyboard_1 = require("storyboard");
const config_1 = require("../../config");
const path = require("path");
const fs = require("fs");
const mkdirp = require("mkdirp");
const util = require("util");
const polytorrent_1 = require("polytorrent");
const http_event_1 = require("../../http-event");
const passwords = path.join(config_1.default.get('dataDirectory'), 'credentials');
const client = new polytorrent_1.DelugeClient({
    host: config_1.default.get('delugeHost'),
    port: config_1.default.get('delugePort'),
    password: config_1.default.get('delugePassword')
});
function createTracker(type, name, username) {
    return __awaiter(this, void 0, void 0, function* () {
        const trackers = new database_1.default('trackers');
        const props = { type, name, username };
        const id = compactd_models_1.trackerURI(compactd_models_1.mapTrackerToParams(props));
        yield trackers.put(Object.assign({ _id: id }, props));
        return yield trackers.get(id);
    });
}
exports.createTracker = createTracker;
function loadPasswords() {
    return new Promise((resolve, reject) => {
        if (!fs.existsSync(passwords))
            resolve({});
        return fs.readFile(passwords, (err, data) => {
            if (err)
                return reject(err);
            resolve(JSON.parse(data.toString()));
        });
    });
}
function writePasswords(data) {
    return new Promise((resolve, reject) => {
        return fs.writeFile(passwords, JSON.stringify(data), (err) => {
            if (err)
                reject(err);
            return resolve();
        });
    });
}
function updatePassword(data) {
    return __awaiter(this, void 0, void 0, function* () {
        const pass = yield loadPasswords();
        yield writePasswords(Object.assign({}, pass, data));
    });
}
/**
 * Store using keytar the password
 * @param id The tracker password id
 * @param password the apssword the username
 */
function setPassword(id, password) {
    return __awaiter(this, void 0, void 0, function* () {
        const trackers = new database_1.default('trackers');
        const tracker = yield trackers.get(id);
        yield updatePassword({ [tracker._id]: password });
        if (indexers[tracker._id]) {
            yield indexers[tracker._id].logout();
        }
    });
}
exports.setPassword = setPassword;
/**
 * Get user password
 * @param id The tracker password id
 */
function getPassword(id) {
    return __awaiter(this, void 0, void 0, function* () {
        const trackers = new database_1.default('trackers');
        const tracker = yield trackers.get(id);
        return (yield loadPasswords())[tracker._id];
    });
}
exports.getPassword = getPassword;
function listTrackers() {
    return __awaiter(this, void 0, void 0, function* () {
        const trackers = new database_1.default('trackers');
        const res = yield trackers.allDocs({ include_docs: true });
        return res.rows.map((r) => r.doc);
    });
}
exports.listTrackers = listTrackers;
const indexers = {};
function searchTracker(id, album) {
    return __awaiter(this, void 0, void 0, function* () {
        const trackers = new database_1.default('trackers');
        const tracker = yield trackers.get(id);
        const indexer = indexers[tracker._id] = indexers[tracker._id] || new (_1.default(tracker.type))({
            username: tracker.username,
            tracker: tracker.type,
            hostname: tracker.host
        });
        if (!indexer.signedIn) {
            const password = yield getPassword(id);
            yield indexer.login(password);
        }
        return yield indexer.searchAlbum(album);
    });
}
exports.searchTracker = searchTracker;
const POLLING_INTERVAL = 500;
function downloadFile(id, torrent) {
    return __awaiter(this, void 0, void 0, function* () {
        storyboard_1.mainStory.info('cascade', `Trying to download from '${id}' torrent id '${torrent}'`);
        const trackers = new database_1.default('trackers');
        const downloads = new database_1.default('downloads');
        const tracker = yield trackers.get(id);
        const indexer = indexers[tracker._id] = indexers[tracker._id] || new (_1.default(tracker.type))({
            username: tracker.username,
            tracker: tracker.type,
            hostname: tracker.host
        });
        const buffer = yield indexer.downloadRelease(torrent);
        const temp = path.join(config_1.default.get('dataDirectory'), 'temp');
        yield util.promisify(mkdirp)(temp, {});
        const download = yield client.addFile(buffer, {
            tempDirectory: temp,
            directory: config_1.default.get('downloadDirectory')
        });
        yield download.update();
        yield downloads.put({
            _id: `downloads/${download.hash}`,
            date: Date.now(),
            name: download.name,
            hash: download.hash,
            done: download.progress === 1,
        });
        watchTorrent([download.hash]);
        return {
            ok: true,
            hash: download.hash,
            name: download.name
        };
    });
}
exports.downloadFile = downloadFile;
const DATE_TS_TRESHOLD = 1000 * 60 * 60 * 24;
function getDownloads() {
    return __awaiter(this, void 0, void 0, function* () {
        const downloads = new database_1.default('downloads');
        const res = yield downloads.allDocs({ include_docs: true });
        const torrents = res.rows.map((doc) => {
            return doc.doc;
        }).filter((doc) => {
            if (!doc.done_ts)
                return true;
            return Date.now() - doc.done_ts < DATE_TS_TRESHOLD;
        });
        return torrents.map((t) => ({
            _id: t._id,
            hash: t.hash,
            name: t.name,
            done: t.done
        }));
    });
}
exports.getDownloads = getDownloads;
function watchTorrent(hashes) {
    return __awaiter(this, void 0, void 0, function* () {
        const dls = new database_1.default('downloads');
        const downloads = yield Promise.all(hashes.map((hash) => __awaiter(this, void 0, void 0, function* () {
            try {
                const t = yield client.getTorrent(hash);
                return t;
            }
            catch (err) {
                storyboard_1.mainStory.error('deluge', 'Deluge RPC error: ' + err.message);
                return Promise.resolve();
            }
        })));
        downloads.forEach((dl) => {
            if (!dl)
                return;
            dl.removeAllListeners();
            dl.once('finish', () => __awaiter(this, void 0, void 0, function* () {
                http_event_1.default.emit('client_call', {
                    method: 'torrentFinished',
                    args: [dl.hash, dl.name]
                });
                const doc = yield dls.get(`downloads/${dl.hash}`);
                yield dls.put({
                    date: doc.date,
                    hash: doc.hash,
                    name: doc.name,
                    _id: doc._id,
                    _rev: doc._rev,
                    done: true,
                    done_ts: Date.now()
                });
            }));
            dl.on('progress', (p) => {
                http_event_1.default.emit('client_call', {
                    method: 'torrentProgress',
                    args: [dl.hash, p]
                });
            });
            dl.liveFeed(POLLING_INTERVAL);
        });
    });
}
function watchDownloads() {
    return __awaiter(this, void 0, void 0, function* () {
        try {
            yield client.connect();
        }
        catch (err) {
            storyboard_1.mainStory.error('deluge', 'Deluge RPC error: ' + err.message);
            return;
        }
        const downloads = new database_1.default('downloads');
        const res = yield downloads.allDocs({ include_docs: true });
        const torrents = res.rows.map((doc) => {
            return doc.doc;
        }).filter((doc) => {
            return !doc.done;
        });
        watchTorrent(torrents.map((doc) => doc.hash)).catch((err) => {
            storyboard_1.mainStory.error('deluge', 'Deluge RPC error: ' + err.message);
        });
    });
}
process.nextTick(() => {
    watchDownloads();
});
//# sourceMappingURL=trackers.js.map