Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HelixClient: custom base url without mock_api feature #444

Open
Disorrder opened this issue Nov 3, 2024 · 2 comments
Open

HelixClient: custom base url without mock_api feature #444

Disorrder opened this issue Nov 3, 2024 · 2 comments
Labels
enhancement New feature or request

Comments

@Disorrder
Copy link

I'm trying to use Twitch CLI and utilize its websocket mock server.
The websocket server is hosted on ws://127.0.0.1:8080/ws
And I need to send subscriptions to http://127.0.0.1:8080/eventsub/subscriptions
Thanks to this example I can specify websocket url:

        let (socket, _) = tokio_tungstenite::connect_async_with_config(
            twitch_api::TWITCH_EVENTSUB_WEBSOCKET_URL.clone().as_str(),
            Some(config),
            false,
        )

but there're no way to specify url for HelixClient (to call create_eventsub_subscription)

    fn get_uri(&self) -> Result<http::Uri, InvalidUri> {
        let query = self.query()?;
        let url = crate::TWITCH_HELIX_URL
            .join(<Self as Request>::PATH)
            .map(|mut u| {
                u.set_query(Some(&query));
                u
            })?;
        http::Uri::from_str(url.as_str()).map_err(Into::into)
    }

If I set TWITCH_HELIX_URL and TWITCH_EVENTSUB_WEBSOCKET_URL in .env, I can't use HelixClient for production request like getting channel info etc. So, I think there's only a workaround to use custom client to send subscription requests, but I would have it in your crate like HelixClient::with_config(...)

@Emilgardis Emilgardis added the enhancement New feature or request label Nov 3, 2024
@Emilgardis
Copy link
Member

Emilgardis commented Nov 3, 2024

One way to do this would be to wrap the underlying http/s client and replace the host.

use twitch_api::eventsub;

#[tokio::main]
async fn main() {
    let client = Wrapper::<reqwest::Client>::new(
        twitch_api::client::ClientDefault::default_client(),
        "http://127.0.0.1:8080".to_string(),
    );
    let mock_client = twitch_api::HelixClient::with_client(client);
    let token = twitch_api::twitch_oauth2::UserToken::from_existing_unchecked(
        "validtoken",
        None,
        "123456789",
        None,
        "user".into(),
        "1234".into(),
        None,
        None,
    );
    mock_client.create_eventsub_subscription(
        eventsub::user::UserUpdateV1::new("1234"),
        eventsub::Transport::websocket("12"),
        &token,
    ).await.unwrap();
}

struct Wrapper<T> {
    client: T,
    replace_host: String,
}

impl Wrapper<reqwest::Client> {
    fn new(client: reqwest::Client, replace_host: String) -> Self {
        Wrapper {
            client,
            replace_host,
        }
    }
}

impl<C> twitch_api::HttpClient for Wrapper<C>
where
    C: twitch_api::HttpClient,
{
    type Error = C::Error;

    fn req(
        &self,
        request: twitch_api::client::Request,
    ) -> twitch_api::client::BoxedFuture<
        '_,
        Result<twitch_api::client::Response, <Self as twitch_api::HttpClient>::Error>,
    > {
        let (mut parts, rest) = request.into_parts();
        parts.uri = format!(
            "{}{}",
            self.replace_host,
            parts
                .uri
                .path_and_query()
                .expect("a path should be set")
                .as_str()
        )
        .parse()
        .unwrap();
        self.client
            .req(twitch_api::client::Request::from_parts(parts, rest))
    }
}

another way would be to make a new endpoint and in a similar fashion change what get_uri returns
yet another way would be to just get the http request and change it

Does this satisfy your needs?

@Disorrder
Copy link
Author

Disorrder commented Nov 4, 2024

@Emilgardis thank you so much! You saved my week :D I'm not really good at rust, just learning. Your workaround works good, just need a "helix/" to be removed in the mock url, but the rest code works good

            parts
                .uri
                .path_and_query()
                .expect("a path should be set")
                .as_str()
                .replace("helix/", "") // <--- added this

Anyway, this approach needs additional struct in the code just for modifying base url. It's fine for temporary solution, but would be more happy to have it as an option.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants