Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/Stremio/stremio-core/llms.txt

Use this file to discover all available pages before exploring further.

The Env trait is the core abstraction that allows Stremio Core to run on different platforms. It defines the interface for platform-specific operations like network requests, storage, and task execution.

Overview

The Env trait is defined in src/runtime/env.rs and provides a platform-agnostic interface for:
  • HTTP requests (fetch)
  • Persistent storage (get/set)
  • Task execution (concurrent and sequential)
  • Time operations
  • Analytics
  • Logging
  • Add-on transport
  • Storage schema migration

Core Methods

Network Operations

fetch

fn fetch<IN, OUT>(request: Request<IN>) -> TryEnvFuture<OUT>
where
    IN: Serialize + ConditionalSend + 'static,
    OUT: for<'de> Deserialize<'de> + ConditionalSend + 'static;
Performs HTTP requests with automatic serialization/deserialization.
use http::Request;
use stremio_core::runtime::Env;

// GET request
let request = Request::get("https://api.example.com/data")
    .body(())
    .unwrap();

let response: MyResponseType = YourEnv::fetch(request).await?;

// POST request with body
let request = Request::post("https://api.example.com/submit")
    .header("content-type", "application/json")
    .body(my_data)
    .unwrap();

let response: SubmitResponse = YourEnv::fetch(request).await?;

Storage Operations

get_storage

fn get_storage<T>(key: &str) -> TryEnvFuture<Option<T>>
where
    for<'de> T: Deserialize<'de> + 'static;
Retrieves data from persistent storage with automatic deserialization.

set_storage

fn set_storage<T: Serialize>(key: &str, value: Option<&T>) -> TryEnvFuture<()>;
Stores data in persistent storage. Pass None to delete the key.
use stremio_core::runtime::Env;
use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize)]
struct UserSettings {
    theme: String,
    language: String,
}

// Save settings
let settings = UserSettings {
    theme: "dark".to_owned(),
    language: "en".to_owned(),
};
YourEnv::set_storage("user_settings", Some(&settings)).await?;

// Load settings
let settings: Option<UserSettings> = YourEnv::get_storage("user_settings").await?;

// Delete settings
YourEnv::set_storage::<UserSettings>("user_settings", None).await?;

Task Execution

exec_concurrent

fn exec_concurrent<F: Future<Output = ()> + ConditionalSend + 'static>(future: F);
Executes a future without waiting for completion. Use for background tasks.

exec_sequential

fn exec_sequential<F: Future<Output = ()> + ConditionalSend + 'static>(future: F);
Executes a future sequentially (may be the same as concurrent on some platforms).
use stremio_core::runtime::Env;

// Background analytics task
YourEnv::exec_concurrent(async {
    // Send analytics
    log_event("user_action").await;
});

// Sequential task
YourEnv::exec_sequential(async {
    // Process queue item
    process_next_item().await;
});

Time Operations

now

fn now() -> DateTime<Utc>;
Returns the current UTC time.
use stremio_core::runtime::Env;

let current_time = YourEnv::now();
println!("Current time: {}", current_time);

Analytics

flush_analytics

fn flush_analytics() -> EnvFuture<'static, ()>;
Flushes any pending analytics events.

analytics_context

fn analytics_context(
    ctx: &Ctx,
    streaming_server: &StreamingServer,
    path: &str,
) -> serde_json::Value;
Generates analytics context for the current state.

Debugging

log (debug builds only)

#[cfg(debug_assertions)]
fn log(message: String);
Logs a message in debug builds.
#[cfg(debug_assertions)]
YourEnv::log(format!("Debug info: {:?}", data));

Default Implementations

addon_transport

fn addon_transport(transport_url: &Url) -> Box<dyn AddonTransport>;
Creates an add-on transport for the given URL. Default implementation supports HTTP/HTTPS.

migrate_storage_schema

fn migrate_storage_schema() -> TryEnvFuture<()>;
Migrates storage schema to the current version. Has a default implementation.

Error Handling

The EnvError enum defines all possible error types:
pub enum EnvError {
    Fetch(String),
    AddonTransport(String),
    Serde(String),
    StorageUnavailable,
    StorageSchemaVersionDowngrade(u32, u32),
    StorageSchemaVersionUpgrade(Box<EnvError>),
    StorageReadError(String),
    StorageWriteError(String),
    Other(String),
}
Each error has a numeric code and message accessible via code() and message() methods.

Future Types

EnvFuture<'a, T>

The return type for async operations. Automatically handles platform differences:
  • WASM (default): Uses LocalBoxFuture (not Send)
  • Native (with env-future-send feature): Uses BoxFuture (requires Send)

ConditionalSend

A marker trait that is:
  • Empty trait on WASM (all types implement it)
  • Equivalent to Send on native platforms

Implementation Example

Here’s a minimal native implementation:
use stremio_core::runtime::{Env, EnvError, TryEnvFuture, EnvFutureExt};
use chrono::{DateTime, Utc};
use http::Request;
use serde::{Deserialize, Serialize};
use std::future::Future;
use std::sync::Mutex;
use std::collections::HashMap;

pub struct NativeEnv;

static STORAGE: Mutex<HashMap<String, String>> = Mutex::new(HashMap::new());

impl Env for NativeEnv {
    fn fetch<IN, OUT>(request: Request<IN>) -> TryEnvFuture<OUT>
    where
        IN: Serialize + 'static,
        OUT: for<'de> Deserialize<'de> + 'static,
    {
        async move {
            // Implement HTTP request using reqwest or similar
            let client = reqwest::Client::new();
            let response = client
                .request(request.method().clone(), request.uri().to_string())
                .json(&request.body())
                .send()
                .await
                .map_err(|e| EnvError::Fetch(e.to_string()))?;
            
            response
                .json::<OUT>()
                .await
                .map_err(|e| EnvError::Serde(e.to_string()))
        }
        .boxed_env()
    }

    fn get_storage<T>(key: &str) -> TryEnvFuture<Option<T>>
    where
        for<'de> T: Deserialize<'de> + 'static,
    {
        let key = key.to_owned();
        async move {
            let storage = STORAGE.lock().unwrap();
            storage
                .get(&key)
                .map(|value| serde_json::from_str(value))
                .transpose()
                .map_err(|e| EnvError::StorageReadError(e.to_string()))
        }
        .boxed_env()
    }

    fn set_storage<T: Serialize>(key: &str, value: Option<&T>) -> TryEnvFuture<()> {
        let key = key.to_owned();
        let value = value
            .map(|v| serde_json::to_string(v))
            .transpose()
            .map_err(|e| EnvError::StorageWriteError(e.to_string()));
        
        async move {
            let value = value?;
            let mut storage = STORAGE.lock().unwrap();
            match value {
                Some(v) => storage.insert(key, v),
                None => storage.remove(&key),
            };
            Ok(())
        }
        .boxed_env()
    }

    fn exec_concurrent<F>(future: F)
    where
        F: Future<Output = ()> + 'static,
    {
        tokio::spawn(future);
    }

    fn exec_sequential<F>(future: F)
    where
        F: Future<Output = ()> + 'static,
    {
        tokio::spawn(future);
    }

    fn now() -> DateTime<Utc> {
        Utc::now()
    }

    fn flush_analytics() -> EnvFuture<'static, ()> {
        async {}.boxed_env()
    }

    fn analytics_context(
        ctx: &Ctx,
        streaming_server: &StreamingServer,
        path: &str,
    ) -> serde_json::Value {
        serde_json::json!({
            "app_type": "native",
            "path": path
        })
    }

    #[cfg(debug_assertions)]
    fn log(message: String) {
        println!("[Stremio] {}", message);
    }
}

Storage Keys

Stremio Core uses these storage keys (defined in src/constants.rs):
  • SCHEMA_VERSION_STORAGE_KEY: Storage schema version
  • PROFILE_STORAGE_KEY: User profile
  • LIBRARY_STORAGE_KEY: Library data
  • LIBRARY_RECENT_STORAGE_KEY: Recently watched
  • STREAMS_STORAGE_KEY: Cached streams
  • SEARCH_HISTORY_STORAGE_KEY: Search history
  • STREAMING_SERVER_URLS_STORAGE_KEY: Streaming server URLs
  • DISMISSED_EVENTS_STORAGE_KEY: Dismissed events
Do not modify these keys directly. Use the Context model’s methods instead.

Platform-Specific Considerations

WASM

  • Cannot use Send trait
  • Must use LocalBoxFuture
  • See WASM Bindings for complete implementation

Native

  • Can enable env-future-send feature for Send futures
  • Use async runtime like Tokio
  • See Native Apps for complete guide

Next Steps

WASM Bindings

Learn how to use stremio-core-web package

Native Apps

Build native applications with stremio-core

Build docs developers (and LLMs) love