diff --git a/core/src/avm1/globals.rs b/core/src/avm1/globals.rs index b2d1de888..7146ae631 100644 --- a/core/src/avm1/globals.rs +++ b/core/src/avm1/globals.rs @@ -61,6 +61,7 @@ pub(crate) mod transform; mod video; pub(crate) mod xml; mod xml_node; +pub(crate) mod xml_socket; const GLOBAL_DECLS: &[Declaration] = declare_properties! { "trace" => method(trace; DONT_ENUM); @@ -576,6 +577,7 @@ pub fn create_globals<'gc>( let video_proto = video::create_proto(context, object_proto, function_proto); let netstream_proto = netstream::create_proto(context, object_proto, function_proto); + let xml_socket_proto = xml_socket::create_proto(context, object_proto, function_proto); //TODO: These need to be constructors and should also set `.prototype` on each one let object = object::create_object_object(context, object_proto, function_proto); @@ -669,6 +671,7 @@ pub fn create_globals<'gc>( let boolean = boolean::create_boolean_object(context, boolean_proto, function_proto); let date = date::create_constructor(context, object_proto, function_proto); let netstream = netstream::create_class(context, netstream_proto, function_proto); + let xml_socket = xml_socket::create_class(context, xml_socket_proto, function_proto); let flash = ScriptObject::new(gc_context, Some(object_proto)); @@ -1051,6 +1054,12 @@ pub fn create_globals<'gc>( netstream.into(), Attribute::DONT_ENUM, ); + globals.define_value( + gc_context, + "XMLSocket", + xml_socket.into(), + Attribute::DONT_ENUM, + ); define_properties_on(GLOBAL_DECLS, context, globals, function_proto); diff --git a/core/src/avm1/globals/xml_socket.rs b/core/src/avm1/globals/xml_socket.rs new file mode 100644 index 000000000..88e7247a7 --- /dev/null +++ b/core/src/avm1/globals/xml_socket.rs @@ -0,0 +1,79 @@ +use crate::avm1::function::FunctionObject; +use crate::avm1::object::{NativeObject, Object}; +use crate::avm1::property_decl::define_properties_on; +use crate::avm1::{property_decl::Declaration, ScriptObject}; +use crate::avm1::{Activation, Error, Executable, TObject, Value}; +use crate::context::GcContext; +use crate::socket::SocketHandle; +use gc_arena::{Collect, GcCell, Mutation}; + +#[derive(Clone, Debug, Collect)] +#[collect(require_static)] +struct XmlSocketData { + handle: Option, + /// Connection timeout in milliseconds. + timeout: u32, +} + +#[derive(Clone, Debug, Collect)] +#[collect(no_drop)] +pub struct XmlSocket<'gc>(GcCell<'gc, XmlSocketData>); + +impl<'gc> XmlSocket<'gc> { + pub fn handle(&self) -> Option { + self.0.read().handle + } + + pub fn set_handle( + &self, + gc_context: &Mutation<'gc>, + handle: SocketHandle, + ) -> Option { + std::mem::replace(&mut self.0.write(gc_context).handle, Some(handle)) + } +} + +const PROTO_DECLS: &[Declaration] = declare_properties! {}; + +pub fn constructor<'gc>( + activation: &mut Activation<'_, 'gc>, + this: Object<'gc>, + _args: &[Value<'gc>], +) -> Result, Error<'gc>> { + let xml_socket = XmlSocket(GcCell::new( + activation.gc(), + XmlSocketData { + handle: None, + /// Default timeout is 20_000 milliseconds (20 seconds) + timeout: 20000, + }, + )); + + this.set_native(activation.gc(), NativeObject::XmlSocket(xml_socket)); + + Ok(this.into()) +} + +pub fn create_proto<'gc>( + context: &mut GcContext<'_, 'gc>, + proto: Object<'gc>, + fn_proto: Object<'gc>, +) -> Object<'gc> { + let xml_socket_proto = ScriptObject::new(context.gc_context, Some(proto)); + define_properties_on(PROTO_DECLS, context, xml_socket_proto, fn_proto); + xml_socket_proto.into() +} + +pub fn create_class<'gc>( + context: &mut GcContext<'_, 'gc>, + xml_socket_proto: Object<'gc>, + fn_proto: Object<'gc>, +) -> Object<'gc> { + FunctionObject::constructor( + context.gc_context, + Executable::Native(constructor), + constructor_to_fn!(constructor), + fn_proto, + xml_socket_proto, + ) +} diff --git a/core/src/avm1/object.rs b/core/src/avm1/object.rs index cb6d867a4..1d3484235 100644 --- a/core/src/avm1/object.rs +++ b/core/src/avm1/object.rs @@ -14,6 +14,7 @@ use crate::avm1::globals::gradient_filter::GradientFilter; use crate::avm1::globals::shared_object::SharedObject; use crate::avm1::globals::transform::TransformObject; use crate::avm1::globals::xml::Xml; +use crate::avm1::globals::xml_socket::XmlSocket; use crate::avm1::object::array_object::ArrayObject; use crate::avm1::object::super_object::SuperObject; use crate::avm1::object::value_object::ValueObject; @@ -59,6 +60,7 @@ pub enum NativeObject<'gc> { Xml(Xml<'gc>), XmlNode(XmlNode<'gc>), SharedObject(GcCell<'gc, SharedObject>), + XmlSocket(XmlSocket<'gc>), } /// Represents an object that can be directly interacted with by the AVM