steam login

This commit is contained in:
Robin Appelman 2023-04-09 15:33:31 +02:00
commit fc5cd1d24f
12 changed files with 926 additions and 70 deletions

View file

@ -2,3 +2,4 @@ pub mod chat;
pub mod demo;
pub mod player;
pub mod steam_id;
pub mod user;

View file

@ -1,14 +1,14 @@
use maud::Render;
use serde::{Serialize, Serializer};
use serde::{Deserialize, Serialize};
use sqlx::database::HasValueRef;
use sqlx::error::BoxDynError;
use sqlx::{Database, Decode, Type};
use std::borrow::Cow;
use std::fmt::Write;
use std::fmt::{Debug, Formatter};
use std::fmt::{Display, Write};
use steamid_ng::SteamID;
#[derive(Clone, PartialEq, Eq, Hash)]
#[derive(Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum SteamId {
Id(u64),
Raw(Cow<'static, str>),
@ -51,25 +51,20 @@ impl SteamId {
let id = SteamID::from_steam3(s)?;
Ok(SteamId::Id(id.into()))
}
pub fn steamid64(&self) -> String {
match self {
SteamId::Id(id) => format!("{}", id),
SteamId::Raw(raw) => raw.to_string(),
}
}
}
impl Debug for SteamId {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
SteamId::Id(id) => SteamID::from(*id).fmt(f),
SteamId::Raw(raw) => raw.fmt(f),
}
}
}
impl Serialize for SteamId {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match self {
SteamId::Id(id) => serializer.collect_str(&SteamID::from(*id).steam3()),
SteamId::Raw(raw) => serializer.collect_str(raw),
SteamId::Id(id) => Debug::fmt(&SteamID::from(*id), f),
SteamId::Raw(raw) => Debug::fmt(raw, f),
}
}
}
@ -107,12 +102,18 @@ where
}
}
impl Display for SteamId {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
SteamId::Id(id) => write!(f, "{id}"),
SteamId::Raw(raw) => write!(f, "{raw}"),
}
}
}
impl Render for SteamId {
fn render_to(&self, buffer: &mut String) {
match self {
SteamId::Id(id) => write!(buffer, "{id}").unwrap(),
SteamId::Raw(raw) => buffer.push_str(raw),
}
write!(buffer, "{self}").unwrap()
}
}

80
src/data/user.rs Normal file
View file

@ -0,0 +1,80 @@
use crate::data::steam_id::SteamId;
use crate::Result;
use rand::distributions::Alphanumeric;
use rand::Rng;
use reqwest::get;
use serde::{Deserialize, Serialize};
use sqlx::{query, Executor, Postgres};
#[derive(Debug, Serialize, Deserialize)]
pub struct User {
pub steam_id: SteamId,
pub name: String,
pub token: String,
}
impl User {
pub async fn get(
connection: impl Executor<'_, Database = Postgres> + Copy,
steam_id: SteamId,
) -> Result<Self> {
let user = query!(
r#"SELECT
token as "token!", name as "name!"
FROM users_named WHERE steamid = $1"#,
steam_id.steamid64()
)
.fetch_optional(connection)
.await?;
if let Some(user) = user {
Ok(User {
steam_id,
token: user.token,
name: user.name,
})
} else {
let profile = Self::fetch(&steam_id).await?;
let token: String = rand::thread_rng()
.sample_iter(&Alphanumeric)
.take(64)
.map(char::from)
.collect();
query!(
r#"INSERT INTO users(steamid, name, avatar, token)
VALUES($1, $2, $3, $4)"#,
steam_id.steamid64(),
profile.name,
profile.avatar,
token
)
.execute(connection)
.await?;
Ok(User {
steam_id,
token,
name: profile.name,
})
}
}
async fn fetch(steam_id: &SteamId) -> Result<Profile> {
let response = get(format!(
"https://steamcommunity.com/profiles/{steam_id}?xml=1"
))
.await?
.error_for_status()?
.text()
.await?;
Ok(quick_xml::de::from_str(&response)?)
}
}
#[derive(Debug, Deserialize)]
struct Profile {
#[serde(rename = "steamID")]
name: String,
#[serde(rename = "avatarMedium")]
avatar: String,
}