Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion core/src/avm1/globals/local_connection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ impl<'gc> LocalConnection<'gc> {
&LocalConnections::get_domain(activation.context.root_swf.url()),
this,
&name,
activation.context.local_connection_backend,
);
let result = connection_handle.is_some();
*self.0.handle.borrow_mut() = connection_handle;
Expand All @@ -61,7 +62,10 @@ impl<'gc> LocalConnection<'gc> {

pub fn disconnect(self, activation: &mut Activation<'_, 'gc>) {
if let Some(conn_handle) = self.0.handle.take() {
activation.context.local_connections.close(conn_handle);
activation
.context
.local_connections
.close(conn_handle, activation.context.local_connection_backend);
}
}

Expand Down Expand Up @@ -235,6 +239,7 @@ pub fn send<'gc>(
*connection_name,
*method_name,
amf_arguments,
activation.context.local_connection_backend,
);
Ok(true.into())
}
Expand Down
1 change: 1 addition & 0 deletions core/src/avm2/globals/flash/net/local_connection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ pub fn send<'gc>(
connection_name,
method_name,
amf_arguments,
activation.context.local_connection_backend,
);
}

Expand Down
6 changes: 5 additions & 1 deletion core/src/avm2/object/local_connection_object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ impl<'gc> LocalConnectionObject<'gc> {
&LocalConnections::get_domain(activation.context.root_swf.url()),
(activation.domain(), self),
&name,
activation.context.local_connection_backend,
);
let result = connection_handle.is_some();

Expand All @@ -97,7 +98,10 @@ impl<'gc> LocalConnectionObject<'gc> {

pub fn disconnect(self, activation: &mut Activation<'_, 'gc>) {
if let Some(conn_handle) = self.0.connection_handle.borrow_mut().take() {
activation.context.local_connections.close(conn_handle);
activation
.context
.local_connections
.close(conn_handle, activation.context.local_connection_backend);
}
}

Expand Down
1 change: 1 addition & 0 deletions core/src/backend.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
pub mod audio;
pub mod local_connection;
pub mod log;
pub mod navigator;
pub mod storage;
Expand Down
71 changes: 71 additions & 0 deletions core/src/backend/local_connection.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/// Backend trait for cross-context LocalConnection transport.
///
/// This trait abstracts the transport mechanism used to send and receive
/// LocalConnection messages between different Ruffle player instances
/// (e.g., different browser tabs or iframes).
///
/// In Flash Player, LocalConnection used shared memory to allow SWF files
/// to communicate across different player instances on the same machine.
/// This trait enables similar functionality in Ruffle by allowing different
/// platform backends to provide cross-context message passing.
pub trait LocalConnectionBackend {
/// Called when a LocalConnection.connect() is made in this player.
/// The backend should register interest in messages for this connection name
/// so that other contexts know a listener exists.
fn register_listener(&mut self, connection_name: &str);

/// Called when a LocalConnection.close() is made.
/// The backend should unregister interest in messages for this connection name.
fn unregister_listener(&mut self, connection_name: &str);

/// Check whether a listener for the given connection name exists in another context.
/// Used by connect() to enforce cross-tab uniqueness and by send() to determine
/// the correct status event when no local listener exists.
fn has_remote_listener(&self, connection_name: &str) -> bool;

/// Broadcast a message to other contexts.
/// Called from send() so that other Ruffle instances can receive it.
///
/// `connection_name` is the fully-qualified connection name (including superdomain prefix).
/// `method_name` is the method to invoke on the receiver.
/// `amf_data` is the AMF-serialized arguments.
fn send_message(&mut self, connection_name: &str, method_name: &str, amf_data: &[u8]);

/// Poll for incoming messages from other contexts.
/// Called once per frame during update_connections().
/// Returns a Vec of received messages that should be delivered to local listeners.
fn poll_incoming(&mut self) -> Vec<ExternalLocalConnectionMessage>;

/// Provide a reference to the core Player.
/// Used by asynchronous backends to instantly wake the Player upon receiving messages.
fn set_player(&mut self, _player: std::sync::Weak<std::sync::Mutex<crate::Player>>) {}
}

/// A message received from another Ruffle context via the LocalConnection backend.
#[derive(Debug, Clone)]
pub struct ExternalLocalConnectionMessage {
/// The fully-qualified connection name (e.g., "someDomain.com:myConnection").
pub connection_name: String,
/// The method name to invoke on the receiver.
pub method_name: String,
/// The AMF-serialized arguments.
pub amf_data: Vec<u8>,
}

/// No-op backend for desktop, tests, and contexts where cross-context
/// LocalConnection is not supported.
#[derive(Default)]
pub struct NullLocalConnectionBackend;

impl LocalConnectionBackend for NullLocalConnectionBackend {
fn register_listener(&mut self, _connection_name: &str) {}
fn unregister_listener(&mut self, _connection_name: &str) {}
fn has_remote_listener(&self, _connection_name: &str) -> bool {
false
}
fn send_message(&mut self, _connection_name: &str, _method_name: &str, _amf_data: &[u8]) {}
fn poll_incoming(&mut self) -> Vec<ExternalLocalConnectionMessage> {
vec![]
}
fn set_player(&mut self, _player: std::sync::Weak<std::sync::Mutex<crate::Player>>) {}
}
4 changes: 4 additions & 0 deletions core/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use crate::avm2::api_version::ApiVersion;
use crate::avm2::{Avm2, LoaderInfoObject, SharedObjectObject, SoundChannelObject};
use crate::backend::{
audio::{AudioBackend, AudioManager, SoundHandle, SoundInstanceHandle},
local_connection::LocalConnectionBackend,
log::LogBackend,
navigator::NavigatorBackend,
storage::StorageBackend,
Expand Down Expand Up @@ -108,6 +109,9 @@ pub struct UpdateContext<'gc> {
/// The storage backend, used for storing persistent state
pub storage: &'gc mut dyn StorageBackend,

/// The local connection backend, used for cross-context LocalConnection transport.
pub local_connection_backend: &'gc mut dyn LocalConnectionBackend,

/// The logging backend, used for trace output capturing.
///
/// **DO NOT** use this field directly, use the `avm_trace` method instead.
Expand Down
Loading
Loading