modio/util/download/info/
mod.rs

1use std::fmt;
2use std::future::Future;
3use std::pin::Pin;
4use std::task::{ready, Context, Poll};
5
6use pin_project_lite::pin_project;
7use url::Url;
8
9use crate::types::files::File;
10use crate::types::id::FileId;
11use crate::Client;
12
13use super::{DownloadAction, Error};
14
15mod get_file;
16mod get_file_by_version;
17mod get_primary_file;
18
19use self::get_file::GetFile;
20use self::get_file_by_version::GetFileByVersion;
21use self::get_primary_file::GetPrimaryFile;
22
23#[non_exhaustive]
24pub struct Info {
25    pub file_id: FileId,
26    pub download_url: Url,
27    pub filesize: u64,
28    pub filesize_uncompressed: u64,
29    pub filehash: String,
30}
31
32impl fmt::Debug for Info {
33    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
34        f.debug_struct("Info")
35            .field("file_id", &self.file_id)
36            .field("download_url", &self.download_url.as_str())
37            .field("filesize", &self.filesize)
38            .field("filesize_uncompressed", &self.filesize_uncompressed)
39            .field("filehash", &self.filehash)
40            .finish_non_exhaustive()
41    }
42}
43
44pin_project! {
45    pub struct GetInfo {
46        #[pin]
47        future: FileFuture,
48    }
49}
50
51pin_project! {
52    #[project = FileFutureProj]
53    enum FileFuture {
54        Primary {
55            #[pin]
56            future: GetPrimaryFile,
57        },
58        File {
59            #[pin]
60            future: GetFile,
61        },
62        FileObj {
63            file: Option<Box<File>>,
64        },
65        Version {
66            #[pin]
67            future: GetFileByVersion,
68        }
69    }
70}
71
72impl Future for FileFuture {
73    type Output = Result<File, Error>;
74
75    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
76        match self.project() {
77            FileFutureProj::Primary { future } => future.poll(cx),
78            FileFutureProj::File { future } => future.poll(cx),
79            FileFutureProj::FileObj { file } => {
80                Poll::Ready(Ok(*file.take().expect("polled after completion")))
81            }
82            FileFutureProj::Version { future } => future.poll(cx),
83        }
84    }
85}
86
87impl GetInfo {
88    pub(crate) fn new(http: &Client, action: DownloadAction) -> Self {
89        let future = match action {
90            DownloadAction::Primary { game_id, mod_id } => FileFuture::Primary {
91                future: GetPrimaryFile::new(http, game_id, mod_id),
92            },
93            DownloadAction::File {
94                game_id,
95                mod_id,
96                file_id,
97            } => FileFuture::File {
98                future: GetFile::new(http, game_id, mod_id, file_id),
99            },
100            DownloadAction::FileObj(file) => FileFuture::FileObj { file: Some(file) },
101            DownloadAction::Version {
102                game_id,
103                mod_id,
104                version,
105                policy,
106            } => FileFuture::Version {
107                future: GetFileByVersion::new(http, game_id, mod_id, version, policy),
108            },
109        };
110        Self { future }
111    }
112}
113
114impl Future for GetInfo {
115    type Output = Result<Info, Error>;
116
117    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
118        let file = ready!(self.project().future.poll(cx))?;
119
120        Poll::Ready(Ok(Info {
121            file_id: file.id,
122            download_url: file.download.binary_url,
123            filesize: file.filesize,
124            filesize_uncompressed: file.filesize_uncompressed,
125            filehash: file.filehash.md5,
126        }))
127    }
128}
129
130pub fn download_info(http: &Client, action: DownloadAction) -> GetInfo {
131    GetInfo::new(http, action)
132}