use env_logger;
use log::{debug, warn};
use rivescript::RiveScript;
use futures::FutureExt;
use rivescript_core::macros::Proxy;
use std::{env, fs, io, io::Write, path::PathBuf, process::exit};
use structopt::StructOpt;
#[derive(StructOpt, Debug)]
#[structopt(
name = "rivescript",
about = "A stand-alone RiveScript chatbot shell for command line use.",
)]
struct Opt {
#[structopt(short, short, long)]
debug: bool,
#[structopt(short, short, long)]
utf8: bool,
#[structopt(name = "FILES", parse(from_os_str))]
files: Vec<PathBuf>,
}
#[tokio::main]
async fn main() {
let opt = Opt::from_args();
println!("{:#?}", opt);
if opt.files.len() == 0 {
println!("Usage: rivescript [options] path/to/brain");
println!("See `rivescript --help` for documentation.");
exit(1);
}
if opt.debug {
unsafe {
env::set_var("RUST_LOG", "debug");
}
}
env_logger::init();
println!(" . .
.:...:: RiveScript Interpreter (Rust)
.:: ::. Library Version: v{} (build {})
..:;;. ' .;;:..
. ''' . Type '/quit' to quit.
:;,:,;: Type '/help' for more options.
: :
Using the RiveScript bot found in: {:?}
Type a message to the bot and press Return to send it.",
rivescript::VERSION,
"n/a",
opt.files,
);
let mut bot = RiveScript::new();
bot.utf8 = opt.utf8;
warn!("RiveScript-rs v{}", rivescript::VERSION);
#[cfg(feature = "javascript")]
{
println!("Note: JavaScript object macros enabled.");
rivescript::register_default_js_handler(&mut bot);
}
bot.set_subroutine("rust-set", |proxy, args| {
async move {
if args.len() >= 2 {
let username = proxy.current_username();
let name = args.get(0).unwrap();
let value = args.get(1).unwrap();
let orig_value = proxy.get_uservar(&username, &name).await;
proxy.set_uservar(&username, name, value).await.expect("Couldn't set user variable!");
let staged_value = proxy.get_uservar(&username, &name).await;
return proxy.finish(format!("For username {username}: The original variable '{name}' was '{orig_value}' and I have updated it to '{value}' (staged value: '{staged_value}')"));
}
proxy.finish("Usage: rust-set name value".to_string())
}.boxed()
});
bot.set_subroutine("rust-bot-set", |proxy, args| {
async move {
if args.len() >= 2 {
let name = args.get(0).unwrap();
let value = args.get(1).unwrap();
let orig_value = proxy.get_variable(&name);
proxy.set_variable(name, value);
let staged_value = proxy.get_variable(&name);
return proxy.finish(format!("The original bot variable '{name}' was '{orig_value}' and I have updated it to '{value}' (staged value: '{staged_value}')"));
}
proxy.finish("Usage: rust-set name value".to_string())
}.boxed()
});
for pathbuf in opt.files {
let filename = pathbuf.to_str().unwrap();
let attr = fs::metadata(filename).expect(format!("{}: file not found", filename).as_str());
if attr.is_dir() {
bot.load_directory(filename)
.expect(format!("Error loading from directory {}", filename).as_str());
} else if attr.is_file() {
bot.load_file(filename).expect(format!("Error loading file {}", filename).as_str());
}
}
bot.sort_triggers();
loop {
print!("You> ");
io::stdout()
.flush()
.expect("oops");
let mut message = String::new();
io::stdin()
.read_line(&mut message)
.expect("Failed to read line");
match message.trim() {
"/help" => {
println!("/dump-ast: pretty-print the loaded brain AST contents");
println!("/help: show this help message");
println!("/quit: exit the program");
},
"/dump-ast" => {
bot.debug_print_brain();
},
"/dump-sorted" => {
bot.debug_sorted_replies();
},
"/quit" => {
println!("Bye!");
break;
}
_ => {
match bot.reply("localuser", &message).await {
Ok(reply) => {
println!("Bot> {reply}");
},
Err(e) => {
debug!("Error: {e}");
}
};
}
}
}
}