UNPKG

auto-pod

Version:

Automatically choose tunneling or direct connection for cocoapods. As easy as `pod` itself. Help you get rid of GFW of China.

261 lines (212 loc) 7.04 kB
import * as cli from 'commander'; import { spawn } from 'child_process'; import { existsSync, readFileSync } from 'fs'; import * as yaml from 'js-yaml'; import { AddressInfo } from 'net'; import { resolve } from 'path'; import * as shell from 'shelljs'; import * as url from 'url'; import { getLogger, init } from './Logger'; import { IConfig, IProxy, ProxyServer } from './ProxyServer'; let displayError = true; const optionNames = [ 'logLevel', 'config', 'debug', 'tunneling', ]; export interface ICmdOptions { logLevel?: string; config?: string; debug?: boolean; tunneling?: boolean; } export function getFileConfig(filePath: string): IConfig { const absFile = resolve(process.cwd(), filePath); if (!existsSync(absFile)) { getLogger() .error('Cannot find auto-pod.yaml. You may also use another config file by "-c" param.'); throw new Error(`Cannot find ${absFile}`); } const content = readFileSync(absFile).toString('utf8'); let config = null; try { config = yaml.safeLoad(content); } catch (err) { getLogger().error(`invalid yaml content: ${err.message}`); const error = new Error(`invalid yaml content: ${err.message}`); // error.code = err.code; throw error; } const fileConfig = { excludes: config.excludes || [], forceTunneling: false, includes: config.includes || [], proxies: [], }; // Parse each proxies as providers. if (!config.proxies || !(config.proxies instanceof Array)) { getLogger() .error('No proxies is set. Please provide us at least one element in `proxies` field.'); throw new Error("No proxies is set."); } if (config.proxies.length === 0) { throw new Error("No proxies is provided."); } for (const proxy of config.proxies) { let opts: IProxy = {}; if ('string' === typeof proxy) opts = url.parse(proxy); // prefer `hostname` over `host`, because of `url.parse()` opts.host = opts.hostname || opts.host; // SOCKS doesn't *technically* have a default port, but this is // the same default that `curl(1)` uses opts.nport = +opts.port || 1080; if (opts.host && opts.path) { // if both a `host` and `path` are specified then it's most likely the // result of a `url.parse()` call... we need to remove the `path` portion so // that `net.connect()` doesn't attempt to open that as a unix socket file. delete opts.path; delete opts.pathname; } const originalLookup = opts.lookup; // figure out if we want socks v4 or v5, based on the "protocol" used. // Defaults to 5. opts.lookup = false; switch (opts.protocol) { case 'socks4:': opts.lookup = true; // pass through case 'socks4a:': opts.version = 4; break; case 'socks5:': opts.lookup = true; // pass through case 'socks:': // no version specified, default to 5h case 'socks5h:': opts.version = 5; break; default: throw new TypeError( `A "socks" protocol must be specified! Got: ${proxy.protocol}`, ); } if (opts.auth) { const auth = opts.auth.split(':'); opts.authentication = { username: auth[0], password: auth[1] }; // opts.userid = auth[0]; } // Set to manually set lookup value. if (typeof originalLookup !== 'undefined') { opts.lookup = !!originalLookup; } fileConfig.proxies.push(opts); } if ('force-tunneling' in config) { fileConfig.forceTunneling = !!config['force-tunneling']; } return fileConfig; } export function getOptionsArgs(args): ICmdOptions { const options = {}; optionNames.forEach((name) => { if (Object.hasOwnProperty.apply(args, [name])) { if (typeof args[name] !== 'string') { throw new Error(`string "${name}" expected`); } options[name] = args[name]; } }); return options; } export function setUpGitProxy(port: number) { shell.exec(`git config --global http.proxy http://127.0.0.1:${port}/`); shell.exec(`git config --global https.proxy http://127.0.0.1:${port}/`); } export function unsetGitProxy() { shell.exec(`git config --unset --global http.proxy`); shell.exec(`git config --unset --global https.proxy`); } function unsafeMain() { const pkgJson = readFileSync(`${__dirname}/../package.json`, 'utf-8'); const version = JSON.parse(pkgJson).version; cli.version(version) // .option('-s, --socks [socks]', 'specify your socks proxy host, default: 127.0.0.1:1080') // .option('-p, --port [port]', // 'specify the listening port of http proxy server, default: 8080') // .option('-l, --host [host]', // 'specify the listening host of http proxy server, default: 127.0.0.1') .option('-c, --config [config]', 'read configs from file in json format') .option('-t, --tunneling', 'Force tunneling all traffic through proxies.') .option('--debug ', 'Enable debug mode') .option('--level [level]', 'log level, vals: info, error') .parse(process.argv); const options = getOptionsArgs(cli); if (!options.debug) { displayError = false; } if (options.logLevel && typeof options.logLevel === 'string') { init(options.logLevel); } // Find auto-pod.yaml. const configFile = options.config || 'auto-pod.yaml'; const fileConfig = getFileConfig(configFile); if (options.tunneling) { // Overwrites force tunneling fileConfig.forceTunneling = true; } // Startup the server. const server = new ProxyServer(fileConfig); server.on('listening', () => { // Get running port const address = server.address() as AddressInfo; getLogger().info(`Server listening on: ${address.address}:${address.port}`); // // Shell run the pod. setUpGitProxy(address.port); getLogger().info("Setup git proxy."); // Run shelljs. // shell.exec("pod") // Copy the process env. const env = JSON.parse(JSON.stringify(process.env)); env.http_proxy = `http://127.0.0.1:${address.port}`; env.https_proxy = `http://127.0.0.1:${address.port}`; getLogger().info("Starting pod..."); const pod = spawn('pod', cli.args, { env, shell: true, stdio: 'pipe', }); pod.stdout.on('data', (data) => { process.stdout.write(data); }); pod.stderr.on('data', (data) => { process.stdout.write(data); }); pod.on('close', (code: number) => { if (code !== 0) { getLogger().error('Failed to execute the pod.'); } else { getLogger().info("Pod finished."); } unsetGitProxy(); getLogger().info("Git proxy removed."); // Stop the server server.unref(); // Shutdown the http proxy server. server.close(); }); }); // Listening at any random port. server.listen({ host: '127.0.0.1', port: 0 }); } export function main() { try { unsafeMain(); } catch (e) { if (displayError) { getLogger().error(e); process.exit(1); } } }