Compare commits

..

No commits in common. "4548419946daabe6f866d3bbd1f0302d16c2d6bd" and "d174ee7bc7f9bd7ed195b58f83888e0a7a744c2e" have entirely different histories.

3 changed files with 20 additions and 194 deletions

View File

@ -49,10 +49,7 @@ function start_buttons() {
const dateFormated = formatDate(now); const dateFormated = formatDate(now);
// return 1 // return 1
return [ return dateFormated
[{name: {name: dateFormated}, callback_name: "no"}],
[{name: {name: "Hello!"}, callback_name: "no"}],
]
} }
const config = { const config = {

View File

@ -1,8 +1,6 @@
use std::collections::HashMap; use std::collections::HashMap;
use crate::db::{CallDB, DbError, DB};
use crate::utils::parcelable::{ParcelType, Parcelable, ParcelableError, ParcelableResult}; use crate::utils::parcelable::{ParcelType, Parcelable, ParcelableError, ParcelableResult};
use futures::future::join_all;
use itertools::Itertools; use itertools::Itertools;
use quickjs_rusty::serde::from_js; use quickjs_rusty::serde::from_js;
use quickjs_rusty::utils::create_empty_object; use quickjs_rusty::utils::create_empty_object;
@ -28,16 +26,6 @@ pub enum ScriptError {
ValueError(#[from] ValueError), ValueError(#[from] ValueError),
#[error("error bot function execution: {0:?}")] #[error("error bot function execution: {0:?}")]
BotFunctionError(String), BotFunctionError(String),
#[error("error from DB: {0:?}")]
DBError(#[from] DbError),
#[error("error resolving data: {0:?}")]
ResolveError(#[from] ResolveError),
}
#[derive(thiserror::Error, Debug)]
pub enum ResolveError {
#[error("wrong literal: {0:?}")]
IncorrectLiteral(String),
} }
pub type ScriptResult<T> = Result<T, ScriptError>; pub type ScriptResult<T> = Result<T, ScriptError>;
@ -257,8 +245,7 @@ pub struct BotConfig {
pub trait ResolveValue { pub trait ResolveValue {
type Value; type Value;
fn resolve(self) -> ScriptResult<Self::Value>; fn resolve(self, runner: &Runner) -> ScriptResult<Self::Value>;
fn resolve_with(self, runner: &Runner) -> ScriptResult<Self::Value>;
} }
#[derive(Serialize, Deserialize, Debug, Clone)] #[derive(Serialize, Deserialize, Debug, Clone)]
@ -286,22 +273,11 @@ impl Parcelable<BotFunction> for KeyboardDefinition {
impl ResolveValue for KeyboardDefinition { impl ResolveValue for KeyboardDefinition {
type Value = Vec<<RowDefinition as ResolveValue>::Value>; type Value = Vec<<RowDefinition as ResolveValue>::Value>;
fn resolve(self) -> ScriptResult<Self::Value> { fn resolve(self, runner: &Runner) -> ScriptResult<Self::Value> {
match self { match self {
KeyboardDefinition::Rows(rows) => rows.into_iter().map(|r| r.resolve()).collect(), KeyboardDefinition::Rows(rows) => rows.into_iter().map(|r| r.resolve(runner)).collect(),
KeyboardDefinition::Function(f) => { KeyboardDefinition::Function(f) => {
<Self as ResolveValue>::resolve(f.call()?.js_into()?) <Self as ResolveValue>::resolve(f.call_context(runner)?.js_into()?, runner)
}
}
}
fn resolve_with(self, runner: &Runner) -> ScriptResult<Self::Value> {
match self {
KeyboardDefinition::Rows(rows) => {
rows.into_iter().map(|r| r.resolve_with(runner)).collect()
}
KeyboardDefinition::Function(f) => {
<Self as ResolveValue>::resolve_with(f.call_context(runner)?.js_into()?, runner)
} }
} }
} }
@ -332,21 +308,13 @@ impl Parcelable<BotFunction> for RowDefinition {
impl ResolveValue for RowDefinition { impl ResolveValue for RowDefinition {
type Value = Vec<<ButtonDefinition as ResolveValue>::Value>; type Value = Vec<<ButtonDefinition as ResolveValue>::Value>;
fn resolve(self) -> ScriptResult<Self::Value> { fn resolve(self, runner: &Runner) -> ScriptResult<Self::Value> {
match self { match self {
RowDefinition::Buttons(buttons) => buttons.into_iter().map(|b| b.resolve()).collect(), RowDefinition::Buttons(buttons) => {
RowDefinition::Function(f) => <Self as ResolveValue>::resolve(f.call()?.js_into()?), buttons.into_iter().map(|b| b.resolve(runner)).collect()
} }
}
fn resolve_with(self, runner: &Runner) -> ScriptResult<Self::Value> {
match self {
RowDefinition::Buttons(buttons) => buttons
.into_iter()
.map(|b| b.resolve_with(runner))
.collect(),
RowDefinition::Function(f) => { RowDefinition::Function(f) => {
<Self as ResolveValue>::resolve_with(f.call_context(runner)?.js_into()?, runner) <Self as ResolveValue>::resolve(f.call_context(runner)?.js_into()?, runner)
} }
} }
} }
@ -363,20 +331,12 @@ pub enum ButtonDefinition {
impl ResolveValue for ButtonDefinition { impl ResolveValue for ButtonDefinition {
type Value = ButtonRaw; type Value = ButtonRaw;
fn resolve(self) -> ScriptResult<Self::Value> { fn resolve(self, runner: &Runner) -> ScriptResult<Self::Value> {
match self {
ButtonDefinition::Button(button) => Ok(button),
ButtonDefinition::ButtonLiteral(l) => Ok(ButtonRaw::from_literal(l)),
ButtonDefinition::Function(f) => <Self as ResolveValue>::resolve(f.call()?.js_into()?),
}
}
fn resolve_with(self, runner: &Runner) -> ScriptResult<Self::Value> {
match self { match self {
ButtonDefinition::Button(button) => Ok(button), ButtonDefinition::Button(button) => Ok(button),
ButtonDefinition::ButtonLiteral(l) => Ok(ButtonRaw::from_literal(l)), ButtonDefinition::ButtonLiteral(l) => Ok(ButtonRaw::from_literal(l)),
ButtonDefinition::Function(f) => { ButtonDefinition::Function(f) => {
<Self as ResolveValue>::resolve_with(f.call_context(runner)?.js_into()?, runner) <Self as ResolveValue>::resolve(f.call_context(runner)?.js_into()?, runner)
} }
} }
} }
@ -419,21 +379,6 @@ impl ButtonRaw {
callback_name: literal, callback_name: literal,
} }
} }
pub fn name(&self) -> &ButtonName {
&self.name
}
pub fn callback_name(&self) -> &str {
&self.callback_name
}
pub fn literal(&self) -> Option<String> {
match self.name() {
ButtonName::Value { .. } => None,
ButtonName::Literal { literal } => Some(literal.to_string()),
}
}
} }
#[derive(Serialize, Deserialize, Debug, Clone)] #[derive(Serialize, Deserialize, Debug, Clone)]
@ -443,24 +388,6 @@ pub enum ButtonName {
Literal { literal: String }, Literal { literal: String },
} }
impl ButtonName {
pub async fn resolve_name(self, db: &mut DB) -> ScriptResult<String> {
match self {
ButtonName::Value { name } => Ok(name),
ButtonName::Literal { literal } => {
let value = db.get_literal_value(&literal).await?;
Ok(match value {
Some(value) => Ok(value),
None => Err(ResolveError::IncorrectLiteral(format!(
"not found literal `{literal}` in DB"
))),
}?)
}
}
}
}
#[derive(Serialize, Deserialize, Debug, Clone)] #[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Button { pub struct Button {
name: String, name: String,
@ -469,74 +396,12 @@ pub struct Button {
#[derive(Serialize, Deserialize, Debug, Clone)] #[derive(Serialize, Deserialize, Debug, Clone)]
pub struct BotMessage { pub struct BotMessage {
// buttons: Vec<Button> // buttons: Vec<Button>
literal: Option<String>,
buttons: Option<KeyboardDefinition>, buttons: Option<KeyboardDefinition>,
state: Option<String>, state: Option<String>,
handler: Option<BotFunction>, handler: Option<BotFunction>,
} }
impl BotMessage {
pub fn fill_literal(&self, l: String) -> Self {
BotMessage {
literal: self.clone().literal.or(Some(l)),
..self.clone()
}
}
}
impl BotMessage {
pub async fn resolve_buttons(
&self,
db: &mut DB,
) -> ScriptResult<Option<Vec<Vec<ButtonLayout>>>> {
let raw_buttons = self.buttons.clone().map(|b| b.resolve()).transpose()?;
match raw_buttons {
Some(braws) => {
let kbd: Vec<Vec<_>> = join_all(braws.into_iter().map(|rows| async {
join_all(rows.into_iter().map(|b| async {
let mut db = db.clone();
ButtonLayout::resolve_raw(b, &mut db).await
}))
.await
.into_iter()
.collect()
}))
.await
.into_iter()
.collect::<Result<_, _>>()?;
Ok(Some(kbd))
}
None => Ok(None),
}
}
pub fn literal(&self) -> Option<&String> {
self.literal.as_ref()
}
}
pub enum ButtonLayout {
Callback {
name: String,
literal: Option<String>,
callback: String,
},
}
impl ButtonLayout {
pub async fn resolve_raw(braw: ButtonRaw, db: &mut DB) -> ScriptResult<Self> {
let name = braw.name().clone().resolve_name(db).await?;
let literal = braw.literal();
let callback = braw.callback_name().to_string();
Ok(Self::Callback {
name,
literal,
callback,
})
}
}
impl Parcelable<BotFunction> for BotMessage { impl Parcelable<BotFunction> for BotMessage {
fn get_field(&mut self, name: &str) -> ParcelableResult<ParcelType<BotFunction>> { fn get_field(&mut self, name: &str) -> ParcelableResult<ParcelType<BotFunction>> {
match name { match name {
@ -574,15 +439,6 @@ pub struct RunnerConfig {
pub dialog: BotDialog, pub dialog: BotDialog,
} }
impl RunnerConfig {
/// command without starting `/`
pub fn get_command_message(&self, command: &str) -> Option<BotMessage> {
let bm = self.dialog.commands.get(command).cloned();
bm.map(|bm| bm.fill_literal(command.to_string()))
}
}
impl Parcelable<BotFunction> for RunnerConfig { impl Parcelable<BotFunction> for RunnerConfig {
fn get_field(&mut self, name: &str) -> Result<ParcelType<BotFunction>, ParcelableError> { fn get_field(&mut self, name: &str) -> Result<ParcelType<BotFunction>, ParcelableError> {
match name { match name {

View File

@ -5,13 +5,14 @@ pub mod db;
pub mod mongodb_storage; pub mod mongodb_storage;
pub mod utils; pub mod utils;
use botscript::{BotMessage, Runner, RunnerConfig, ScriptError}; use botscript::{BotMessage, Runner, RunnerConfig};
use commands::BotCommand; use commands::BotCommand;
use db::application::Application; use db::application::Application;
use db::callback_info::CallbackInfo; use db::callback_info::CallbackInfo;
use db::message_forward::MessageForward; use db::message_forward::MessageForward;
use itertools::Itertools; use itertools::Itertools;
use log::{error, info, warn}; use log::{error, info, warn};
use std::collections::HashMap;
use std::str::FromStr; use std::str::FromStr;
use std::sync::RwLock; use std::sync::RwLock;
use std::time::Duration; use std::time::Duration;
@ -133,7 +134,6 @@ pub enum BotError {
MsgTooOld(String), MsgTooOld(String),
BotLogicError(String), BotLogicError(String),
AdminMisconfiguration(String), AdminMisconfiguration(String),
ScriptError(#[from] ScriptError),
} }
pub type BotResult<T> = Result<T, BotError>; pub type BotResult<T> = Result<T, BotError>;
@ -169,7 +169,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
} }
} }
// //
let rc: std::sync::Arc<RwLock<RunnerConfig>> = std::sync::Arc::new(RwLock::new(bc.rc)); let cmdmap: std::sync::Arc<RwLock<HashMap<_, _>>> =
std::sync::Arc::new(RwLock::new(bc.rc.dialog.commands));
let handler = dptree::entry() let handler = dptree::entry()
.inspect(|u: Update| { .inspect(|u: Update| {
@ -179,12 +180,11 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
Update::filter_message() Update::filter_message()
.filter_map(|m: Message| m.text().and_then(|t| BotCommand::from_str(t).ok())) .filter_map(|m: Message| m.text().and_then(|t| BotCommand::from_str(t).ok()))
.filter_map(move |bc: BotCommand| { .filter_map(move |bc: BotCommand| {
let rc = std::sync::Arc::clone(&rc); let rc = std::sync::Arc::clone(&cmdmap);
let command = bc.command();
let rc = rc.read().expect("RwLock lock on commands map failed"); let cmdmap = rc.read().expect("RwLock lock on commands map failed");
rc.get_command_message(command) cmdmap.get(bc.command()).cloned()
}) })
.endpoint(botscript_command_handler), .endpoint(botscript_command_handler),
) )
@ -255,35 +255,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
Ok(()) Ok(())
} }
async fn botscript_command_handler( async fn botscript_command_handler(bot: Bot, bm: BotMessage) -> BotResult<()> {
bot: Bot,
mut db: DB,
bm: BotMessage,
msg: Message,
) -> BotResult<()> {
info!("Eval BM: {:?}", bm); info!("Eval BM: {:?}", bm);
let buttons = bm
.resolve_buttons(&mut db)
.await?
.map(|buttons| InlineKeyboardMarkup {
inline_keyboard: buttons
.iter()
.map(|r| {
r.iter()
.map(|b| match b {
botscript::ButtonLayout::Callback {
name,
literal: _,
callback,
} => InlineKeyboardButton::callback(name, callback),
})
.collect()
})
.collect(),
});
let literal = bm.literal().map_or("", |s| s.as_str());
answer_message_varianted(&bot, msg.chat.id.0, &mut db, literal, None, buttons).await?;
Ok(()) Ok(())
} }