"use strict";
/*
 * Copyright © 2020 Atomist, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.FilePreferenceStore = exports.FilePreferenceStoreFactory = void 0;
const logger_1 = require("@atomist/automation-client/lib/util/logger");
const fs = require("fs-extra");
const _ = require("lodash");
const os = require("os");
const path = require("path");
const proper_lockfile_1 = require("proper-lockfile");
const AbstractPreferenceStore_1 = require("./AbstractPreferenceStore");
/**
 * Factory to create a new FilePreferenceStore instance
 */
const FilePreferenceStoreFactory = ctx => new FilePreferenceStore(ctx);
exports.FilePreferenceStoreFactory = FilePreferenceStoreFactory;
/**
 * PreferenceStore implementation that stores preferences in a shared file.
 * Note: this implementation attempts to lock the preference file before reading or writing to it
 * but it is not intended for production usage.
 */
class FilePreferenceStore extends AbstractPreferenceStore_1.AbstractPreferenceStore {
    constructor(context, filePath = path.join(os.homedir(), ".atomist", "prefs", "client.prefs.json")) {
        super(context);
        this.filePath = filePath;
        this.init();
    }
    async doGet(name, namespace) {
        const key = this.scopeKey(name, namespace);
        return this.doWithPreferenceFile(async (prefs) => {
            if (!!prefs[key]) {
                return {
                    save: false,
                    value: {
                        name,
                        namespace,
                        value: prefs[key].value,
                        ttl: prefs[key].ttl,
                    },
                };
            }
            else {
                return {
                    save: false,
                    value: undefined,
                };
            }
        });
    }
    async doPut(pref) {
        return this.doWithPreferenceFile(async (prefs) => {
            const key = this.scopeKey(pref.name, pref.namespace);
            prefs[key] = {
                name: pref.name,
                value: pref.value,
                ttl: typeof pref.ttl === "number" ? Date.now() + pref.ttl : undefined,
            };
            return {
                save: true,
            };
        });
    }
    doList(namespace) {
        return this.doWithPreferenceFile(async (prefs) => {
            const values = [];
            _.forEach(prefs, (v, k) => {
                if (!namespace || k.startsWith(`${namespace}_$_`)) {
                    values.push(v);
                }
            });
            return {
                save: false,
                value: values,
            };
        });
    }
    doDelete(pref, namespace) {
        return this.doWithPreferenceFile(async (prefs) => {
            const key = this.scopeKey(pref, namespace);
            delete prefs[key];
            return {
                save: true,
            };
        });
    }
    async read() {
        return (await fs.readJson(this.filePath));
    }
    async doWithPreferenceFile(withPreferenceFile) {
        await proper_lockfile_1.lock(this.filePath, { retries: 5 });
        const prefs = await this.read();
        let result;
        try {
            result = await withPreferenceFile(prefs);
            if (result.save) {
                await fs.writeJson(this.filePath, prefs);
            }
        }
        catch (e) {
            logger_1.logger.error(`Operation on preference file failed: ${e.message}`);
        }
        await proper_lockfile_1.unlock(this.filePath);
        return result.value;
    }
    init() {
        fs.ensureDirSync(path.dirname(this.filePath));
        try {
            fs.readFileSync(this.filePath);
        }
        catch (e) {
            fs.writeJsonSync(this.filePath, {});
        }
    }
}
exports.FilePreferenceStore = FilePreferenceStore;
//# sourceMappingURL=FilePreferenceStore.js.map