Skip to main content
The Env trait defines the interface for platform-specific operations in Stremio Core. Implementations of this trait provide access to storage, networking, analytics, and other system-level functionality.

Overview

The Env trait abstracts platform differences, allowing Stremio Core to work across:
  • Web (WebAssembly)
  • Desktop (Native)
  • Mobile (Native)
Different platforms implement this trait to provide their specific capabilities.

Trait Definition

pub trait Env {
    // Required methods
    fn fetch<IN, OUT>(request: Request<IN>) -> TryEnvFuture<OUT>;
    fn get_storage<T>(key: &str) -> TryEnvFuture<Option<T>>;
    fn set_storage<T>(key: &str, value: Option<&T>) -> TryEnvFuture<()>;
    fn exec_concurrent<F>(future: F);
    fn exec_sequential<F>(future: F);
    fn now() -> DateTime<Utc>;
    fn flush_analytics() -> EnvFuture<'static, ()>;
    fn analytics_context(ctx: &Ctx, streaming_server: &StreamingServer, path: &str) -> serde_json::Value;
    
    // Provided methods
    fn addon_transport(transport_url: &Url) -> Box<dyn AddonTransport> { ... }
    fn migrate_storage_schema() -> TryEnvFuture<()> { ... }
}

Required Methods

fetch

Performs an HTTP request with serialization/deserialization.
fn fetch<
    IN: Serialize + ConditionalSend + 'static,
    OUT: for<'de> Deserialize<'de> + ConditionalSend + 'static,
>(
    request: Request<IN>,
) -> TryEnvFuture<OUT>
Type Parameters:
  • IN - Request body type (must be serializable)
  • OUT - Response body type (must be deserializable)
Parameters:
  • request - HTTP request with typed body
Returns: Future resolving to the deserialized response or an EnvError Example:
let request = Request::get("https://api.stremio.com/api/user")
    .header("Authorization", format!("Bearer {}", token))
    .body(())?;

let response: User = E::fetch(request).await?;

get_storage

Retrieves a value from persistent storage.
fn get_storage<T: for<'de> Deserialize<'de> + ConditionalSend + 'static>(
    key: &str,
) -> TryEnvFuture<Option<T>>
Type Parameters:
  • T - Type of the stored value
Parameters:
  • key - Storage key
Returns: Future resolving to the stored value or None if not found Example:
let profile: Option<Profile> = E::get_storage("profile").await?;

set_storage

Stores or removes a value from persistent storage.
fn set_storage<T: Serialize>(
    key: &str,
    value: Option<&T>
) -> TryEnvFuture<()>
Type Parameters:
  • T - Type of the value to store
Parameters:
  • key - Storage key
  • value - Value to store, or None to remove
Returns: Future resolving to success or an EnvError Example:
// Store a value
E::set_storage("profile", Some(&profile)).await?;

// Remove a value
E::set_storage::<Profile>("profile", None).await?;

exec_concurrent

Executes a future concurrently (fire and forget).
fn exec_concurrent<F: Future<Output = ()> + ConditionalSend + 'static>(
    future: F
)
Type Parameters:
  • F - Future type that returns ()
Parameters:
  • future - The future to execute
Example:
E::exec_concurrent(async move {
    // Background work
    let _ = process_analytics().await;
});

exec_sequential

Executes a future sequentially (queued execution).
fn exec_sequential<F: Future<Output = ()> + ConditionalSend + 'static>(
    future: F
)
Type Parameters:
  • F - Future type that returns ()
Parameters:
  • future - The future to execute
Example:
E::exec_sequential(async move {
    // Sequential work that shouldn't be parallelized
    let _ = update_storage().await;
});

now

Returns the current UTC timestamp.
fn now() -> DateTime<Utc>
Returns: Current UTC timestamp Example:
let current_time = E::now();

flush_analytics

Flushes any pending analytics data.
fn flush_analytics() -> EnvFuture<'static, ()>
Returns: Future that completes when analytics are flushed

analytics_context

Creates analytics context for tracking.
fn analytics_context(
    ctx: &Ctx,
    streaming_server: &StreamingServer,
    path: &str,
) -> serde_json::Value
Parameters:
  • ctx - Current context (profile, library, etc.)
  • streaming_server - Streaming server state
  • path - Current navigation path
Returns: JSON value with analytics context

log (Debug Only)

Logs a message (only available in debug builds).
#[cfg(debug_assertions)]
fn log(message: String)
Parameters:
  • message - Message to log

Provided Methods

addon_transport

Creates an addon transport for the given URL.
fn addon_transport(transport_url: &Url) -> Box<dyn AddonTransport>
Parameters:
  • transport_url - URL of the addon
Returns: Boxed addon transport implementation The default implementation supports HTTP/HTTPS transports.

migrate_storage_schema

Migrates storage schema to the latest version.
fn migrate_storage_schema() -> TryEnvFuture<()>
Returns: Future resolving to success or an EnvError This method automatically handles schema version upgrades from v0 to the current version.

EnvError

Errors returned by Env operations.
pub enum EnvError {
    Fetch(String),
    AddonTransport(String),
    Serde(String),
    StorageUnavailable,
    StorageSchemaVersionDowngrade(u32, u32),
    StorageSchemaVersionUpgrade(Box<EnvError>),
    StorageReadError(String),
    StorageWriteError(String),
    Other(String),
}
Methods:
  • message() -> String - Returns human-readable error message
  • code() -> u32 - Returns error code

Type Aliases

EnvFuture

Platform-specific future type.
// Without env-future-send feature (WASM)
pub type EnvFuture<'a, T> = LocalBoxFuture<'a, T>;

// With env-future-send feature (Native)
pub type EnvFuture<'a, T> = BoxFuture<'a, T>;

TryEnvFuture

Future that resolves to a Result.
pub type TryEnvFuture<T> = EnvFuture<'static, Result<T, EnvError>>;

ConditionalSend

Marker trait for types that are Send on native but not on WASM.
// Without env-future-send feature (WASM)
pub trait ConditionalSend {}
impl<T> ConditionalSend for T {}

// With env-future-send feature (Native)
pub trait ConditionalSend: Send {}
impl<T: Send> ConditionalSend for T {}

Implementing Env

Here’s a minimal example of implementing the Env trait:
use stremio_core::runtime::{Env, TryEnvFuture, EnvFuture, EnvError};
use chrono::{DateTime, Utc};

struct MyEnv;

impl Env for MyEnv {
    fn fetch<IN, OUT>(request: Request<IN>) -> TryEnvFuture<OUT>
    where
        IN: Serialize + ConditionalSend + 'static,
        OUT: for<'de> Deserialize<'de> + ConditionalSend + 'static,
    {
        async move {
            // Platform-specific HTTP implementation
            let response = my_http_client::request(request).await?;
            Ok(response)
        }.boxed_env()
    }
    
    fn get_storage<T>(key: &str) -> TryEnvFuture<Option<T>>
    where
        T: for<'de> Deserialize<'de> + ConditionalSend + 'static,
    {
        async move {
            // Platform-specific storage implementation
            let value = my_storage::get(key).await?;
            Ok(value)
        }.boxed_env()
    }
    
    // ... implement other required methods
}

See Also

  • Runtime - Runtime that uses the Env trait
  • Effects - Effects that may use Env operations

Build docs developers (and LLMs) love