Skip to content
This repository has been archived by the owner on Oct 25, 2019. It is now read-only.

Commit

Permalink
most simple working thing.
Browse files Browse the repository at this point in the history
  • Loading branch information
Romain Gautier committed Mar 28, 2017
1 parent 82637a6 commit 4bc245c
Show file tree
Hide file tree
Showing 5 changed files with 362 additions and 22 deletions.
8 changes: 7 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,10 @@ version = "0.1.0"
authors = ["Romain Gautier <[email protected]>"]

[dependencies]
discord = "^0.8.0"
discord = "^0.8.0"
futures = "^0.1.9"

hyper = "^0.9.18"
serde = "^0.9"
serde_json = "^0.9"
serde_derive = "^0.9"
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,8 @@
# rom-discord-bot
Discord bot for Rise of Midgard
Discord bot for Rise of Midgard.

TODO:
- pretty print location
- cache api calls
- assign a thread pool to prevent ddos on thread creation (very unlikely)
- get feedbacks
131 changes: 111 additions & 20 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,40 +3,131 @@

//https://discordapp.com/oauth2/authorize?&client_id=295890698417340417&scope=bot&permissions=0

/* Macros ****/
#![feature(conservative_impl_trait)]

extern crate discord;

extern crate futures;

use futures::Future;

use discord::Discord;
use discord::model::Event;

#[macro_use]
extern crate serde_derive;

mod vending;

use vending::VendingApi;
use vending::VendingApiError;
use vending::{ItemOnSale, BuyingItem};

use std::sync::Arc;

fn look_for_sale(vending_api: VendingApi, name: String) -> impl Future<Item=Vec<ItemOnSale>, Error=VendingApiError> {
vending_api.vending()
.map(move |items| {
//Filter by item name. Ignore case
let filtered: Vec<ItemOnSale> = items.into_iter().filter(move |sell_item| {
let sane_selling_item_name = sell_item.name().to_lowercase();
let sane_item_name = name.to_lowercase();
let sane_item_name = sane_item_name.trim();

sane_selling_item_name.contains(&sane_item_name)
}).collect();
filtered
})
}

fn look_for_buying(vending_api: VendingApi, name: String) -> impl Future<Item=Vec<BuyingItem>, Error=VendingApiError> {
vending_api.buying()
.map(move |items| {
// println!("items = {:?}", items);
//Filter by item name. Ignore case
let filtered: Vec<BuyingItem> = items.into_iter().filter(move |buying_item| {
let sane_buying_item_name = buying_item.name().to_lowercase();
let sane_item_name = name.to_lowercase();
let sane_item_name = sane_item_name.trim();

// println!("Compare {} with {}", sane_buying_item_name, sane_item_name);
sane_buying_item_name.contains(&sane_item_name)
}).collect();
filtered
})
}

fn main() {
let token_bot = "Mjk1ODkwNjk4NDE3MzQwNDE3.C7qTWA.uNinGhRhSMj3sun83Ke_uIF4kjw";

let discord = Discord::from_bot_token(&token_bot).expect("Unable to make bot from token.");
let discord = Arc::new(discord);

let vending_api = VendingApi::new();

let token_bot = "Mjk1ODkwNjk4NDE3MzQwNDE3.C7qTWA.uNinGhRhSMj3sun83Ke_uIF4kjw";
let (mut connection, _) = discord.connect().expect("Unable to connect.");

let discord = Discord::from_bot_token(&token_bot).expect("Unable to make bot from token.");
println!("Ready.");


let (mut connection, _) = discord.connect().expect("Unable to connect.");
loop {
match connection.recv_event() {
Ok(Event::MessageCreate(message)) => {
let content = message.content.clone();
if content.is_char_boundary(2) {
let (prefix, item) = content.split_at(2);

println!("Ready.");
let item_name = item.to_string();
let vending_api = vending_api.clone();
let channel_id = message.channel_id.clone();
let discord = discord.clone();

match prefix {
"B>" => {
println!("Look for selling {}", item);

loop {
std::thread::spawn(move || {
let items = look_for_sale(vending_api, item_name).wait().unwrap();

match connection.recv_event() {
Ok(Event::MessageCreate(message)) => {
println!("{} says: {}", message.author.name, message.content);
if items.len() == 0 {
discord.send_message(channel_id, "Sorry, the item you're looking for doesn't seem to be in sale", "", false);
}

if message.content == "!quit" {
println!("Quitting");
break
for item in items.into_iter() {
let msg : String = format!("**{}** **{}** for **{}**z each. Shop name: **{}**. **{}**", item.amount(), item.name(), item.price(), item.shop_name(), item.location());
discord.send_message(channel_id, &msg, "", false);
}
});
}
"S>" => {
println!("Look for buying {}", item);

std::thread::spawn(move || {
let items = look_for_buying(vending_api, item_name).wait().unwrap();

if items.len() == 0 {
discord.send_message(channel_id, "Sorry, the item you wanna sell doesn't seem to match any buy proposition right now", "", false);
}

for item in items.into_iter() {
let msg : String = format!("**{}** **{}** for **{}**z each. Shop name: **{}**. **{}**", item.amount(), item.name(), item.price(), item.shop_name(), item.location());
discord.send_message(channel_id, &msg, "", false);
}
});
}
_ => (),
}
}

println!("{} says: {}", message.author.name, message.content);
}
Ok(_) => {}
Err(discord::Error::Closed(code, body)) => {
println!("Gateway closed on us with code {:?}: {}", code, body);
break
}
}
Ok(_) => { }
Err(discord::Error::Closed(code, body)) => {
println!("Gateway closed on us with code {:?}: {}", code, body);
break
}
Err(err) => println!("Received error: {:?}", err)
}
}
Err(err) => println!("Received error: {:?}", err)
}
}
}
49 changes: 49 additions & 0 deletions src/vending/cache.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/**
Attempt to cache future. Replace with outdatable
*/

use std::time::{Duration, Instant};

pub trait Cache {
type Item;

fn cached_or<F>(&mut self, f: F) -> Self::Item
where F: Fn() -> Self::Item;

fn set_cache(&mut self, item: Self::Item) -> Self::Item;
}

pub struct TtlCache<T> {
ttl: u64,
last: Instant,

cached: Option<T>,
}

impl <T> TtlCache<T> {
fn new(ttl: u64) -> TtlCache<T> {
TtlCache { ttl: ttl, last: Instant::now(), cached: None }
}
}

impl <T> Cache for TtlCache<T> {
type Item = T;

fn cached_or<F>(&mut self, f: F) -> Self::Item where F: Fn() -> Self::Item {

//Refresh the cache
if self.cached == None || self.last.elapsed().as_secs() > ttl {
self.cached = f();
self.last = Instant::now();
}

self.cached
}

fn set_cache(&mut self, item: Self::Item) -> Self::Item {
self.cached = item;
self.last = Instant::now();

self.cached
}
}
Loading

0 comments on commit 4bc245c

Please sign in to comment.