/// <summary> /// Connects to a remote shared object on the server through the specified connection. Use this method after /// issuing SharedObject.GetRemote(...). After a successful connection, the sync event is dispatched. /// </summary> /// <param name="connection">A NetConnection object (such as one used to communicate with Flash Media Server) that is using the Real-Time Messaging Protocol (RTMP).</param> /// <param name="parameters">Parameters.</param> public void Connect(NetConnection connection, string parameters) { if (_initialSyncReceived) { throw new InvalidOperationException("SharedObject already connected"); } ValidationUtils.ArgumentNotNull(connection, "connection"); ValidationUtils.ArgumentNotNull(connection.Uri, "connection"); ValidationUtils.ArgumentConditionTrue(connection.Uri.Scheme == "rtmp", "connection", "NetConnection object must use the Real-Time Messaging Protocol (RTMP)"); ValidationUtils.ArgumentConditionTrue(connection.Connected, "connection", "NetConnection object must be connected"); _connection = connection; _initialSyncReceived = false; GodLesZ.Library.Amf.Messaging.Rtmp.SO.SharedObjectMessage message; if (connection.ObjectEncoding == ObjectEncoding.AMF0) { message = new GodLesZ.Library.Amf.Messaging.Rtmp.SO.SharedObjectMessage(_name, _version, _persistentSO); } else { message = new GodLesZ.Library.Amf.Messaging.Rtmp.SO.FlexSharedObjectMessage(_name, _version, _persistentSO); } GodLesZ.Library.Amf.Messaging.Rtmp.SO.SharedObjectEvent evt = new GodLesZ.Library.Amf.Messaging.Rtmp.SO.SharedObjectEvent(GodLesZ.Library.Amf.Messaging.Rtmp.SO.SharedObjectEventType.SERVER_CONNECT, null, null); message.AddEvent(evt); _connection.NetConnectionClient.Write(message); }
/// <summary> /// Initializes a new instance of the SharedObject class. /// </summary> /// <param name="data"></param> /// <param name="name"></param> /// <param name="path"></param> /// <param name="persistent"></param> public SharedObject(IDictionary data, string name, string path, bool persistent) { base.SetAttributes(data); _name = name; _path = path; _persistentSO = persistent; _ownerMessage = new SharedObjectMessage(null, name, 0, persistent); _creationTime = System.Environment.TickCount; }
/// <summary> /// Closes the connection between a remote shared object and the server. /// </summary> public void Close() { if (_initialSyncReceived && _connection != null && _connection.Connected) { GodLesZ.Library.Amf.Messaging.Rtmp.SO.SharedObjectMessage message; if (_connection.ObjectEncoding == ObjectEncoding.AMF0) { message = new GodLesZ.Library.Amf.Messaging.Rtmp.SO.SharedObjectMessage(_name, _version, _persistentSO); } else { message = new GodLesZ.Library.Amf.Messaging.Rtmp.SO.FlexSharedObjectMessage(_name, _version, _persistentSO); } GodLesZ.Library.Amf.Messaging.Rtmp.SO.SharedObjectEvent evt = new GodLesZ.Library.Amf.Messaging.Rtmp.SO.SharedObjectEvent(GodLesZ.Library.Amf.Messaging.Rtmp.SO.SharedObjectEventType.SERVER_DISCONNECT, null, null); message.AddEvent(evt); _connection.NetConnectionClient.Write(message); // clear collections base.RemoveAttributes(); _ownerMessage.Events.Clear(); } _initialSyncReceived = false; }
/// <summary> /// Send update notification over data channel of RTMP connection /// </summary> private void SendUpdates() { int currentVersion = _version.Value; bool persist = this.IsPersistentObject; //Get read-only version of events ConcurrentLinkedQueue <ISharedObjectEvent> events = new ConcurrentLinkedQueue <ISharedObjectEvent>(_ownerMessage.Events); //clear out previous events _ownerMessage.Events.Clear(); if (events.Count != 0) { //Send update to "owner" of this update request if (_source != null) { RtmpConnection connection = _source as RtmpConnection; // Only send updates when issued through RTMP request RtmpChannel channel = connection.GetChannel((byte)3); // Send update to "owner" of this update request SharedObjectMessage syncOwner; if (connection.ObjectEncoding == ObjectEncoding.AMF0) { syncOwner = new SharedObjectMessage(null, _name, currentVersion, persist); } else { syncOwner = new FlexSharedObjectMessage(null, _name, currentVersion, persist); } syncOwner.AddEvents(events); if (channel != null) { channel.Write(syncOwner); } else { log.Warn(__Res.GetString(__Res.Channel_NotFound)); } } } //Clear owner events events.Clear(); //Get read-only version of sync events events.AddRange(_syncEvents); //Clear out previous events _syncEvents.Clear(); if (events.Count != 0) { // Synchronize updates with all registered clients of this shared foreach (IEventListener listener in _listeners) { if (listener == _source) { // Don't re-send update to active client continue; } if (!(listener is RtmpConnection)) { log.Warn(__Res.GetString(__Res.SharedObject_SyncConnError)); continue; } // Create a new sync message for every client to avoid // concurrent access through multiple threads // TODO: perhaps we could cache the generated message RtmpConnection connection = listener as RtmpConnection; SharedObjectMessage syncMessage; if (connection.ObjectEncoding == ObjectEncoding.AMF0) { syncMessage = new SharedObjectMessage(null, _name, currentVersion, persist); } else { syncMessage = new FlexSharedObjectMessage(null, _name, currentVersion, persist); } syncMessage.AddEvents(events); RtmpChannel channel = connection.GetChannel((byte)3); log.Debug(__Res.GetString(__Res.SharedObject_Sync, channel)); channel.Write(syncMessage); } } }
/// <summary> /// Initializes a new instance of the SharedObject class. This is used by the persistence framework. /// </summary> public SharedObject() { _ownerMessage = new SharedObjectMessage(null, null, -1, false); _persistentSO = false; _creationTime = System.Environment.TickCount; }
/// <summary> /// Send update notification over data channel of RTMP connection /// </summary> private void SendUpdates() { int currentVersion = _version.Value; bool persist = this.IsPersistentObject; //Get read-only version of events ConcurrentLinkedQueue<ISharedObjectEvent> events = new ConcurrentLinkedQueue<ISharedObjectEvent>(_ownerMessage.Events); //clear out previous events _ownerMessage.Events.Clear(); if (events.Count != 0) { //Send update to "owner" of this update request if (_source != null) { RtmpConnection connection = _source as RtmpConnection; // Only send updates when issued through RTMP request RtmpChannel channel = connection.GetChannel((byte)3); // Send update to "owner" of this update request SharedObjectMessage syncOwner; if (connection.ObjectEncoding == ObjectEncoding.AMF0) syncOwner = new SharedObjectMessage(null, _name, currentVersion, persist); else syncOwner = new FlexSharedObjectMessage(null, _name, currentVersion, persist); syncOwner.AddEvents(events); if (channel != null) { channel.Write(syncOwner); } else { log.Warn(__Res.GetString(__Res.Channel_NotFound)); } } } //Clear owner events events.Clear(); //Get read-only version of sync events events.AddRange(_syncEvents); //Clear out previous events _syncEvents.Clear(); if (events.Count != 0) { // Synchronize updates with all registered clients of this shared foreach (IEventListener listener in _listeners) { if (listener == _source) { // Don't re-send update to active client continue; } if (!(listener is RtmpConnection)) { log.Warn(__Res.GetString(__Res.SharedObject_SyncConnError)); continue; } // Create a new sync message for every client to avoid // concurrent access through multiple threads // TODO: perhaps we could cache the generated message RtmpConnection connection = listener as RtmpConnection; SharedObjectMessage syncMessage; if (connection.ObjectEncoding == ObjectEncoding.AMF0) syncMessage = new SharedObjectMessage(null, _name, currentVersion, persist); else syncMessage = new FlexSharedObjectMessage(null, _name, currentVersion, persist); syncMessage.AddEvents(events); RtmpChannel channel = connection.GetChannel((byte)3); log.Debug(__Res.GetString(__Res.SharedObject_Sync, channel)); channel.Write(syncMessage); } } }
/// <summary> /// This method supports the infrastructure and is not intended to be used directly from your code. /// </summary> /// <param name="connection"></param> /// <param name="channel"></param> /// <param name="header"></param> /// <param name="message"></param> protected abstract void OnSharedObject(RtmpConnection connection, RtmpChannel channel, RtmpHeader header, SharedObjectMessage message);
static ISharedObjectMessage DecodeSharedObject(ByteBuffer stream) { RtmpReader reader = new RtmpReader(stream); string name = reader.ReadString(); // Read version of SO to modify int version = reader.ReadInt32(); // Read persistence informations bool persistent = reader.ReadInt32() == 2; // Skip unknown bytes //skip(4); reader.ReadInt32(); SharedObjectMessage so = new SharedObjectMessage(null, name, version, persistent); DecodeSharedObject(so, stream, reader); return so; }
static void DecodeSharedObject(SharedObjectMessage so, ByteBuffer stream, RtmpReader reader) { // Parse request body while (stream.HasRemaining) { byte typeCode = reader.ReadByte(); SharedObjectEventType type = SharedObjectTypeMapping.ToType(typeCode); string key = null; object value = null; int length = stream.GetInt();//reader.ReadInt32(); switch (type) { case SharedObjectEventType.CLIENT_STATUS: // Status code key = reader.ReadString(); // Status level value = reader.ReadString(); break; case SharedObjectEventType.CLIENT_UPDATE_DATA: { key = reader.ReadString(); value = reader.ReadData(); /* key = null; // Map containing new attribute values Hashtable map = new Hashtable(); int start = (int)stream.Position; while((int)stream.Position - start < length) { string tmp = reader.ReadString(); map[tmp] = reader.ReadData(); } value = map; */ } break; default: if (type != SharedObjectEventType.SERVER_SEND_MESSAGE && type != SharedObjectEventType.CLIENT_SEND_MESSAGE) { if (length > 0) { key = reader.ReadString(); if (length > key.Length + 2) { value = reader.ReadData(); } } } else { int start = (int)stream.Position; // the "send" event seems to encode the handler name // as complete AMF string including the string type byte key = reader.ReadData() as string; // read parameters #if !(NET_1_1) List<object> paramList = new List<object>(); #else ArrayList paramList = new ArrayList(); #endif while (stream.Position - start < length) { object tmp = reader.ReadData(); paramList.Add(tmp); } value = paramList; } break; } so.AddEvent(type, key, value); } }
private static void SendSOPersistenceMismatch(RtmpConnection connection, string name, bool persistent) { SharedObjectMessage msg; if (connection.ObjectEncoding == ObjectEncoding.AMF0) msg = new SharedObjectMessage(name, 0, persistent); else msg = new FlexSharedObjectMessage(name, 0, persistent); msg.AddEvent(new SharedObjectEvent(SharedObjectEventType.CLIENT_STATUS, StatusASO.SO_PERSISTENCE_MISMATCH, "error")); connection.GetChannel((byte)3).Write(msg); }
private static void SendSOCreationFailed(RtmpConnection connection, string name, bool persistent) { SharedObjectMessage msg; if (connection.ObjectEncoding == ObjectEncoding.AMF0) msg = new SharedObjectMessage(name, 0, persistent); else msg = new FlexSharedObjectMessage(name, 0, persistent); msg.AddEvent(new SharedObjectEvent(SharedObjectEventType.CLIENT_STATUS, StatusASO.SO_CREATION_FAILED, "error")); connection.GetChannel((byte)3).Write(msg); }
protected override void OnSharedObject(RtmpConnection connection, RtmpChannel channel, RtmpHeader header, SharedObjectMessage message) { ISharedObject so = null; string name = message.Name; IScope scope = connection.Scope; bool persistent = message.IsPersistent; if (scope == null) { // The scope already has been deleted. SendSOCreationFailed(connection, name, persistent); return; } ISharedObjectService sharedObjectService = ScopeUtils.GetScopeService(scope, typeof(ISharedObjectService)) as ISharedObjectService; if (!sharedObjectService.HasSharedObject(scope, name)) { ISharedObjectSecurityService securityService = ScopeUtils.GetScopeService(scope, typeof(ISharedObjectSecurityService)) as ISharedObjectSecurityService; if (securityService != null) { // Check handlers to see if creation is allowed IEnumerator enumerator = securityService.GetSharedObjectSecurity(); while (enumerator.MoveNext()) { ISharedObjectSecurity handler = enumerator.Current as ISharedObjectSecurity; if (!handler.IsCreationAllowed(scope, name, persistent)) { SendSOCreationFailed(connection, name, persistent); return; } } } if (!sharedObjectService.CreateSharedObject(scope, name, persistent)) { SendSOCreationFailed(connection, name, persistent); return; } } so = sharedObjectService.GetSharedObject(scope, name); if (so.IsPersistentObject != persistent) { log.Debug(string.Format("Shared object '{0}' persistence mismatch", name)); SendSOPersistenceMismatch(connection, name, persistent); return; } so.DispatchEvent(message); }