/*
 * Copyright 2018-20 IBM Corporation
 *
 * 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.
 */
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    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) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
import Debug from 'debug';
import { inBrowser, isHeadless, hasProxy, i18n } from '@kui-shell/core';
const strings = i18n('plugin-kubectl');
const debug = Debug('plugin-kubectl/util/fetch-file');
function needle({ qexec }, method, url) {
    return __awaiter(this, void 0, void 0, function* () {
        if (isHeadless()) {
            const needle = yield import('needle');
            debug('fetch via needle', needle);
            return needle(method, url, { follow_max: 10 }).then(_ => ({ statusCode: _.statusCode, body: _.body }));
        }
        else if (inBrowser()) {
            // Unfortunately, we cannot rely on being able to fetch files
            // directly from a browser. For one, if the remote site does not
            // offer an Access-Control-Allow-Origin, then well behaving
            // browsers will refuse to load their content;
            // e.g. https://k8s.io/examples/controllers/nginx-deployment.yaml
            // Solution: have the kui proxy do this
            if (!hasProxy()) {
                throw new Error(strings('Unable to fetch remote file'));
            }
            else {
                debug('fetch via proxy');
                const body = yield qexec(`_fetchfile ${url}`);
                debug('fetched via proxy', body);
                return {
                    statusCode: 200,
                    body
                };
            }
            /* return new Promise((resolve, reject) => {
              const xhr = new XMLHttpRequest()
              xhr.open(method, url, true)
              xhr.withCredentials = true
              xhr.addEventListener('error', () => {
                console.error('error in xhr', xhr)
                reject(xhr.response || 'Internal Error')
              })
              xhr.addEventListener('load', () => {
                resolve({
                  statusCode: xhr.status,
                  body: typeof xhr.response === 'string' ? xhr.response : xhr.response.response
                })
              })
              xhr.send()
            }) */
        }
        else {
            debug('fetch via electron.net');
            const { net } = (yield import('electron')).remote;
            return new Promise((resolve, reject) => {
                const request = net.request({
                    method,
                    url,
                    redirect: 'follow'
                });
                request.on('response', response => {
                    const statusCode = response.statusCode;
                    debug('got response', statusCode);
                    // we will accumulate the body chunks below
                    let body = '';
                    // Warning: you must register 'end' before 'data'.
                    // https://github.com/electron/electron/issues/12545
                    response.on('end', () => {
                        debug('got end');
                        if (response.statusCode < 300) {
                            resolve({ statusCode, body });
                        }
                        else {
                            const error = new Error(body);
                            error.statusCode = statusCode;
                            reject(error);
                        }
                    });
                    response.on('data', chunk => {
                        // debug('got chunk', chunk.toString())
                        body += chunk.toString();
                    });
                });
                request.end();
            });
        }
    });
}
/**
 * Either fetch a remote file or read a local one
 *
 */
export function fetchFile(repl, url) {
    debug('fetchFile', url);
    const urls = url.split(/,/);
    return Promise.all(urls.map((url) => __awaiter(this, void 0, void 0, function* () {
        if (url.match(/http(s)?:\/\//)) {
            debug('fetch remote', url);
            const fetchOnce = () => needle(repl, 'get', url).then(_ => _.body);
            const retry = (delay) => (err) => __awaiter(this, void 0, void 0, function* () {
                if (/timeout/.test(err.message) || /hang up/.test(err.message) || /hangup/.test(err.message)) {
                    debug('retrying', err);
                    yield new Promise(resolve => setTimeout(resolve, delay));
                    return fetchOnce();
                }
                else {
                    throw err;
                }
            });
            // fetch with three retries
            return fetchOnce()
                .catch(retry(500))
                .catch(retry(1000))
                .catch(retry(5000));
        }
        else {
            const filepath = url;
            debug('fetch local', filepath);
            const stats = (yield repl.rexec(`fstat ${repl.encodeComponent(filepath)} --with-data`))
                .content;
            return stats.data;
        }
    })));
}
/** same as fetchFile, but returning a string rather than a Buffer */
export function fetchFileString(repl, url) {
    return __awaiter(this, void 0, void 0, function* () {
        const files = yield fetchFile(repl, url);
        return files.map(_ => _.toString());
    });
}
export function fetchFileKustomize(repl, url) {
    return __awaiter(this, void 0, void 0, function* () {
        const stats = (yield repl.rexec(`_fetchfile ${repl.encodeComponent(url)} --kustomize`)).content;
        return stats;
    });
}
export default fetchFileString;
//# sourceMappingURL=fetch-file.js.map