about summary refs log tree commit diff
path: root/src/brain.rs
blob: 0ec6a59142c27ba39ee9dd66c111f60e774c7f10 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
use crate::database::Database;

use twilight_cache_inmemory::DefaultInMemoryCache;
use twilight_gateway::Event;
use twilight_http::{Client as HttpClient, client::InteractionClient};
use twilight_model::{
	channel::message::Embed,
	gateway::payload::incoming::InteractionCreate,
	http::interaction::{InteractionResponse, InteractionResponseData, InteractionResponseType},
	id::{
		Id,
		marker::{ChannelMarker, GuildMarker, MessageMarker, UserMarker},
	},
};
const PROD_APP_ID: u64 = 1363055126264283136;
const DEV_APP_ID: u64 = 1363494986699771984;
const APP_ID: u64 = PROD_APP_ID;

// A Absolutely Remarkably Terrible Thing
macro_rules! aumau {
	($meow:expr) => {
		$meow.await.unwrap().model().await.unwrap()
	};
}

pub struct Brain {
	pub db: Database,
	http: HttpClient,
	cache: DefaultInMemoryCache,
}

impl Brain {
	pub fn new(db: Database, http: HttpClient, cache: DefaultInMemoryCache) -> Self {
		Self { db, http, cache }
	}

	pub fn update_cache(&self, event: &Event) {
		self.cache.update(event);
	}

	/// Get the interaction client. Used for responding to interactions
	pub fn interaction(&self) -> InteractionClient<'_> {
		self.http.interaction(Id::new(APP_ID))
	}

	/// Respond to the interaction indicated by `create`. This method will
	/// respond as an `InteractionResponseType::ChannelMessageWithSource`
	pub async fn interaction_respond(
		&self,
		create: &InteractionCreate,
		data: InteractionResponseData,
	) {
		self.interaction()
			.create_response(
				create.id,
				&create.token,
				&InteractionResponse {
					kind: InteractionResponseType::ChannelMessageWithSource,
					data: Some(data),
				},
			)
			.await
			.unwrap();
	}

	pub async fn send_message_with_embed<S: AsRef<str>>(
		&self,
		channel: Id<ChannelMarker>,
		msg: S,
		embed: Embed,
	) -> Id<MessageMarker> {
		aumau!(
			self.http
				.create_message(channel)
				.embeds(&[embed])
				.content(msg.as_ref())
		)
		.id
	}

	/// Retrieve information about a member of a guild. This method checks the
	/// cache first, and then makes a request if it isn't there
	pub async fn guild_member(&self, guild_id: Id<GuildMarker>, user_id: Id<UserMarker>) -> Member {
		let user = self.cache.user(user_id);
		let member = self.cache.member(guild_id, user_id);

		match user.zip(member) {
			Some((user, member)) => Member {
				id: user_id,
				handle: user.name.clone(),
				global_name: user.global_name.clone(),
				nick: member.nick().map(<_>::to_owned),
			},
			None => {
				let member = aumau!(self.http.guild_member(guild_id, user_id));

				Member {
					id: user_id,
					handle: member.user.name,
					global_name: member.user.global_name,
					nick: member.nick,
				}
			}
		}
	}

	/// Check the database for a leaderboard belonging to this guild. If it
	/// does not exist, create one. Returns whether or not one existed before
	/// this function was called
	pub fn create_leaderboard_if_not_exists(&self, guild: Id<GuildMarker>) -> bool {
		if !self.db.leaderboard_exits(guild.get()) {
			self.db.create_leaderboard(guild.get()).unwrap();
			false
		} else {
			true
		}
	}
}

pub struct Member {
	pub id: Id<UserMarker>,
	pub handle: String,
	pub global_name: Option<String>,
	pub nick: Option<String>,
}