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.
Stremio Core is built on the Elm Architecture, a pattern for building reliable, maintainable applications using a unidirectional data flow.
Core Concepts
The Elm Architecture has three main components:
Model : The state of your application
Messages : Events that describe state changes
Update : A function that produces new state and effects
The Msg Type
Messages are the only way to change state in Stremio Core. Every user interaction, API response, or timer event becomes a message:
pub enum Msg {
Action ( Action ), // User actions
Internal ( Internal ), // Internal state changes
Event ( Event ), // Events emitted to the UI
}
Action Messages
Actions are dispatched by the application UI:
// src/runtime/msg/action.rs:113
#[derive( Clone , Deserialize , Debug )]
#[serde(tag = "action" , content = "args" )]
pub enum ActionCtx {
Authenticate ( AuthRequest ),
Logout ,
InstallAddon ( Descriptor ),
UpdateSettings ( ProfileSettings ),
AddToLibrary ( MetaItemPreview ),
// ...
}
Internal Messages
Internal messages are used for state transitions that don’t come from user actions:
Internal :: CtxAuthResult ( auth_request , result )
Internal :: ProfileChanged
Internal :: ResourceRequestResult ( request , result )
Event Messages
Events are emitted to the UI to notify about important state changes:
Event :: UserAuthenticated { auth_request }
Event :: UserLoggedOut { uid }
Event :: Error { error , source }
The Update Trait
The Update trait defines how models respond to messages:
// src/runtime/update.rs:18
pub trait Update < E : Env > {
fn update ( & mut self , msg : & Msg ) -> Effects ;
}
Models that need access to the global context use UpdateWithCtx:
// src/runtime/update.rs:22
pub trait UpdateWithCtx < E : Env > {
fn update ( & mut self , msg : & Msg , ctx : & Ctx ) -> Effects ;
}
Update Implementation Example
Here’s how the Ctx model handles authentication:
// src/models/ctx/ctx.rs:110
impl < E : Env + ' static > Update < E > for Ctx {
fn update ( & mut self , msg : & Msg ) -> Effects {
match msg {
Msg :: Action ( Action :: Ctx ( ActionCtx :: Authenticate ( auth_request ))) => {
// Set loading state
self . status = CtxStatus :: Loading ( auth_request . to_owned ());
// Return effect to perform authentication
Effects :: one ( authenticate :: < E >( auth_request )) . unchanged ()
}
Msg :: Action ( Action :: Ctx ( ActionCtx :: Logout )) => {
// Convert to internal message
Effects :: msg ( Msg :: Internal ( Internal :: Logout ( false ))) . unchanged ()
}
// ...
}
}
}
Effects
Effects represent asynchronous operations or additional messages to process:
// src/runtime/effects.rs:14
pub enum Effect {
Msg ( Box < Msg >), // Immediate message
Future ( EffectFuture ), // Async operation
}
pub enum EffectFuture {
Concurrent ( Future ), // Run in parallel
Sequential ( Future ), // Run in order
}
Creating Effects
The Effects builder provides convenient methods:
// No effects, state changed
Effects :: none ()
// Single message effect
Effects :: msg ( Msg :: Event ( Event :: UserLoggedOut { uid }))
// Multiple messages
Effects :: msgs ( vec! [ msg1 , msg2 , msg3 ])
// Async effect
Effects :: future ( EffectFuture :: Concurrent ( fetch_data ()))
// Mark state as unchanged
Effects :: none () . unchanged ()
// Combine multiple effects
effect1 . join ( effect2 ) . join ( effect3 )
The unchanged() Method
Effects track whether the model state changed:
// src/runtime/effects.rs:81
pub fn unchanged ( mut self ) -> Self {
self . has_changed = false ;
self
}
When has_changed is true, the runtime emits a NewState event to notify the UI. Use .unchanged() when effects don’t modify the model:
// State changed, notify UI
self . status = CtxStatus :: Loading ( ... );
Effects :: one ( effect )
// State unchanged, don't notify UI
Effects :: one ( effect ) . unchanged ()
Example: CatalogWithFilters Update
Here’s a complete example from the catalog model:
// src/models/catalog_with_filters.rs:155
impl < E , T > UpdateWithCtx < E > for CatalogWithFilters < T >
where
E : Env + ' static ,
T : CatalogResourceAdapter + PartialEq ,
{
fn update ( & mut self , msg : & Msg , ctx : & Ctx ) -> Effects {
match msg {
Msg :: Action ( Action :: Load ( ActionLoad :: CatalogWithFilters ( selected ))) => {
// Update selected filters
let selected_effects =
selected_update :: < T >( & mut self . selected, & self . selectable, selected );
// Load catalog data
let catalog_effects = match self . selected . as_ref () {
Some ( selected ) => catalog_update :: < E , _ >(
& mut self . catalog,
CatalogPageRequest :: First ,
& selected . request,
),
_ => Effects :: none () . unchanged (),
};
// Update selectable options
let selectable_effects = selectable_update (
& mut self . selectable,
& self . selected,
& self . catalog,
& ctx . profile,
);
// Combine all effects
selected_effects
. join ( catalog_effects )
. join ( selectable_effects )
}
// Handle other messages...
}
}
}
Benefits of This Pattern
Predictability All state changes go through update functions, making the data flow easy to trace.
Testability Update functions are pure (except for effects), making them easy to test.
Composability Effects can be combined using .join(), making complex updates manageable.
Type Safety The compiler ensures all messages are handled correctly.
Next Steps
Models and State Learn how models manage application state
Effects and Runtime Understand how effects are executed