M Cargo.lock => Cargo.lock +1 -0
@@ 1849,6 1849,7 @@ name = "twitch-rss"
version = "0.1.0"
dependencies = [
"anyhow",
+ "async-lock",
"async-std",
"async-trait",
"rss",
M Cargo.toml => Cargo.toml +1 -0
@@ 19,6 19,7 @@ async-std = "1.8"
surf = { version = "2.2", default-features = false, features = ["h1-client-rustls"] }
serde = "1.0"
# http server
+async-lock = "2.3"
async-trait = "0.1"
tide = { version = "0.16", default-features = false, features = ["h1-server"] }
# logging
M src/http.rs => src/http.rs +28 -10
@@ 1,4 1,5 @@
use anyhow::{anyhow, Context, Result};
+use async_lock::Mutex;
use async_std::task;
use rss::{ChannelBuilder, ImageBuilder, ItemBuilder};
use tide::Request;
@@ 10,13 11,13 @@ use crate::twitch;
#[derive(Clone)]
struct State {
- twitch_auth: Arc<twitch::TwitchAuth>,
+ twitch_auth: Arc<Mutex<twitch::TwitchAuth>>,
account_cache: HashMap<String, String>, // TODO use a TTL cache here
}
pub fn run(listen_endpoint: String, twitch_auth: twitch::TwitchAuth) -> Result<()> {
let state = State {
- twitch_auth: Arc::new(twitch_auth),
+ twitch_auth: Arc::new(Mutex::new(twitch_auth)),
account_cache: HashMap::new()
};
@@ 46,22 47,39 @@ async fn handle_index(req: Request<State>) -> tide::Result {
async fn handle_rss(req: Request<State>) -> tide::Result {
let mut query_account = None;
- let mut include_live = false;
for (key, val) in req.url().query_pairs() {
if key == "account" {
query_account = Some(val.to_string());
}
- if key == "live" {
- include_live = true;
- }
}
match query_account {
Some(account) => {
// TODO check userid cache, then try get_user_id
// TODO check video cache, then try get_videos
- let user = twitch::get_user(&mut req.state().twitch_auth, account).await?;
- let videos = twitch::get_videos(&mut req.state().twitch_auth, user.id).await?;
+ let user: twitch::GetUsersEntry;
+ let videos: Vec<twitch::GetVideosEntry>;
+ {
+ let mut auth = req.state().twitch_auth.lock().await;
+ match twitch::get_user(&mut auth, account).await {
+ Ok(u) => { user = u; }
+ Err(e) => {
+ return Ok(tide::Response::builder(400)
+ .body(format!("400 Bad Request: {}", e))
+ .content_type(tide::http::mime::PLAIN)
+ .build());
+ }
+ };
+ match twitch::get_videos(&mut auth, user.id).await {
+ Ok(v) => { videos = v; }
+ Err(e) => {
+ return Ok(tide::Response::builder(400)
+ .body(format!("400 Bad Request: {}", e))
+ .content_type(tide::http::mime::PLAIN)
+ .build());
+ }
+ };
+ }
let mut items = vec![];
for video in videos {
items.push(
@@ 69,8 87,8 @@ async fn handle_rss(req: Request<State>) -> tide::Result {
.title(format!("{} [{}]", video.title, video.duration))
// TODO embed player in content?
.content(format!("<img src='{}'>", video.thumbnail_url))
- .link(video.url)
- .description(video.description)
+ .link(video.url.clone()) // TODO TEMP: clone to be removed
+ .description(format!("{:?}", video)) // TODO TEMP
.pub_date(video.published_at)
.build()
.map_err(|e| anyhow!("Error when rendering RSS item: {}", e))?
M src/twitch.rs => src/twitch.rs +0 -5
@@ 1,11 1,6 @@
use anyhow::{anyhow, bail, Result};
use serde::{Deserialize, Serialize};
-struct AccountInfo {
- name: String,
- id: usize,
-}
-
// Request parameters for GET id.twitch.tv/oauth2/token
#[derive(Debug, Serialize)]
struct LoginQuery {