arsse.php conf save-defaults [] arsse.php user [list] arsse.php user add [] arsse.php user remove arsse.php user set-pass [] [--oldpass=] [--fever] arsse.php user unset-pass [--oldpass=] [--fever] arsse.php user auth [--fever] arsse.php export [] [-f | --flat] arsse.php import [] [-f | --flat] [-r | --replace] arsse.php --version arsse.php --help | -h The Arsse command-line interface currently allows you to start the refresh daemon, refresh all feeds or a specific feed by numeric ID, manage users, or save default configuration to a sample file. USAGE_TEXT; protected function usage($prog): string { $prog = basename($prog); return str_replace("arsse.php", $prog, self::USAGE); } protected function command(array $options, $args): string { foreach ($options as $cmd) { foreach (explode(" ", $cmd) as $part) { if (!$args[$part]) { continue 2; } } return $cmd; } return ""; } protected function loadConf(): bool { $conf = file_exists(BASE."config.php") ? new Conf(BASE."config.php") : new Conf; Arsse::load($conf); return true; } protected function resolveFile($file, string $mode): string { // TODO: checking read/write permissions on the provided path may be useful $stdinOrStdout = in_array($mode, ["r", "r+"]) ? "php://input" : "php://output"; return ($file === "-" ? null : $file) ?? $stdinOrStdout; } public function dispatch(array $argv = null) { $argv = $argv ?? $_SERVER['argv']; $argv0 = array_shift($argv); $args = \Docopt::handle($this->usage($argv0), [ 'argv' => $argv, 'help' => false, ]); try { $cmd = $this->command(["--help", "--version", "daemon", "feed refresh", "feed refresh-all", "conf save-defaults", "user", "export", "import"], $args); if ($cmd && !in_array($cmd, ["--help", "--version", "conf save-defaults"])) { // only certain commands don't require configuration to be loaded $this->loadConf(); } switch ($cmd) { case "--help": echo $this->usage($argv0).\PHP_EOL; return 0; case "--version": echo Arsse::VERSION.\PHP_EOL; return 0; case "daemon": $this->getInstance(Service::class)->watch(true); return 0; case "feed refresh": return (int) !Arsse::$db->feedUpdate((int) $args[''], true); case "feed refresh-all": $this->getInstance(Service::class)->watch(false); return 0; case "conf save-defaults": $file = $this->resolveFile($args[''], "w"); return (int) !$this->getInstance(Conf::class)->exportFile($file, true); case "user": return $this->userManage($args); case "export": $u = $args['']; $file = $this->resolveFile($args[''], "w"); return (int) !$this->getInstance(OPML::class)->exportFile($file, $u, $args['--flat']); case "import": $u = $args['']; $file = $this->resolveFile($args[''], "w"); return (int) !$this->getInstance(OPML::class)->importFile($file, $u, $args['--flat'], $args['--replace']); } } catch (AbstractException $e) { $this->logError($e->getMessage()); return $e->getCode(); } } /** @codeCoverageIgnore */ protected function logError(string $msg) { fwrite(STDERR, $msg.\PHP_EOL); } protected function getInstance(string $class) { return new $class; } protected function userManage($args): int { switch ($this->command(["add", "remove", "set-pass", "unset-pass", "list", "auth"], $args)) { case "add": return $this->userAddOrSetPassword("add", $args[""], $args[""]); case "set-pass": if ($args['--fever']) { $passwd = $this->getInstance(Fever::class)->register($args[""], $args[""]); if (is_null($args[""])) { echo $passwd.\PHP_EOL; } return 0; } else { return $this->userAddOrSetPassword("passwordSet", $args[""], $args[""], $args["--oldpass"]); } // no break case "unset-pass": if ($args['--fever']) { $this->getInstance(Fever::class)->unregister($args[""]); } else { Arsse::$user->passwordUnset($args[""], $args["--oldpass"]); } return 0; case "remove": return (int) !Arsse::$user->remove($args[""]); case "auth": return $this->userAuthenticate($args[""], $args[""], $args["--fever"]); case "list": case "": return $this->userList(); } } protected function userAddOrSetPassword(string $method, string $user, string $password = null, string $oldpass = null): int { $passwd = Arsse::$user->$method(...array_slice(func_get_args(), 1)); if (is_null($password)) { echo $passwd.\PHP_EOL; } return 0; } protected function userList(): int { $list = Arsse::$user->list(); if ($list) { echo implode(\PHP_EOL, $list).\PHP_EOL; } return 0; } protected function userAuthenticate(string $user, string $password, bool $fever = false): int { $result = $fever ? $this->getInstance(Fever::class)->authenticate($user, $password) : Arsse::$user->auth($user, $password); if ($result) { echo Arsse::$lang->msg("CLI.Auth.Success").\PHP_EOL; return 0; } else { echo Arsse::$lang->msg("CLI.Auth.Failure").\PHP_EOL; return 1; } } }