Beispiel #1
0
 /*
  * -----------------------
  * PlaySound()
  * -----------------------
  */
 static public int PlaySound(AudioClip clip, float volume, EmitterChannel src = EmitterChannel.Any, float delay = 0.0f, float pitchVariance = 1.0f, bool loop = false)
 {
     if (!SoundEnabled)
     {
         return(-1);
     }
     return(PlaySoundAt((staticListenerPosition != null) ? staticListenerPosition.position : Vector3.zero, clip, volume, src, delay, pitchVariance, loop));
 }
Beispiel #2
0
 /*
  * -----------------------
  * PlaySound()
  * -----------------------
  */
 static public int PlaySound(SoundFX soundFX, EmitterChannel src = EmitterChannel.Any, float delay = 0.0f)
 {
     if (!SoundEnabled)
     {
         return(-1);
     }
     return(PlaySoundAt((staticListenerPosition != null) ? staticListenerPosition.position : Vector3.zero, soundFX, src, delay));
 }
Beispiel #3
0
        /// <summary>
        /// Constructs a new instance of a profiler, bound to a particular thread.
        /// </summary>
        /// <param name="channel">The channel for emitter.io.</param>
        /// <param name="interval">The interval to publish measurements info.</param>
        public Instrument(string channel, TimeSpan interval) : base(interval)
        {
            this.Channel = channel;

            // Get the channel
            if (!EmitterChannel.TryParse(this.Channel, false, out Info))
            {
                throw new ArgumentException("Invalid channel");
            }
        }
Beispiel #4
0
        /// <summary>
        /// Attempts to generate the key and returns the result.
        /// </summary>
        /// <param name="client">The remote client.</param>
        /// <param name="channel">The full channel string.</param>
        /// <param name="message">The message to publish.</param>
        public static EmitterResponse Process(IClient client, EmitterChannel channel, KeyGenRequest request)
        {
            // Parse the channel
            EmitterChannel info;

            if (!EmitterChannel.TryParse(request.Channel, false, out info))
            {
                return(EmitterError.BadRequest);
            }

            // Should be a static (non-wildcard) channel string.
            if (info.Type != ChannelType.Static)
            {
                return(EmitterError.BadRequest);
            }

            // Attempt to parse the key, this should be a master key
            SecurityKey masterKey;

            if (!SecurityKey.TryParse(request.Key, out masterKey) || !masterKey.IsMaster || masterKey.IsExpired)
            {
                return(EmitterError.Unauthorized);
            }

            // Attempt to fetch the contract using the key. Underneath, it's cached.
            var contract = Services.Contract.GetByKey(masterKey.Contract) as EmitterContract;

            if (contract == null)
            {
                return(EmitterError.NotFound);
            }

            // Validate the contract
            if (!contract.Validate(ref masterKey))
            {
                return(EmitterError.Unauthorized);
            }

            // Generate the key
            var key = SecurityKey.Create();

            key.Master      = masterKey.Master;
            key.Contract    = contract.Oid;
            key.Signature   = contract.Signature;
            key.Permissions = request.Access;
            key.Target      = SecurityHash.GetHash(request.Channel);
            key.Expires     = request.Expires;

            return(new KeyGenResponse()
            {
                Key = key.Value,
                Channel = request.Channel
            });
        }
Beispiel #5
0
        /// <summary>
        /// Attempts to get an option.
        /// </summary>
        public static bool TryGet(EmitterChannel channel, string option, int defaultValue, out int value)
        {
            // Do we have the option?
            value = defaultValue;
            if (channel.Options == null || !channel.Options.ContainsKey(option))
            {
                return(false);
            }

            // Do we have a TTL with the message?
            return(int.TryParse(channel.Options[option], out value));
        }
Beispiel #6
0
        /// <summary>
        /// Attempts to generate the key and returns the result.
        /// </summary>
        /// <param name="client">The remote client.</param>
        /// <param name="info">The full channel string.</param>
        /// <param name="message">The message to publish.</param>
        public static bool TryProcess(IClient client, EmitterChannel info, ArraySegment <byte> message)
        {
            // Is this a special api request?
            if (info.Key != EmitterConst.ApiPrefix)
            {
                return(false);
            }

            // The response to send out, default to bad request
            EmitterResponse response = EmitterError.BadRequest;

            try
            {
                switch (info.Target)
                {
                case 548658350:
                    // Handle the 'keygen' request.
                    response = HandleKeyGen.Process(client, info, message.As <KeyGenRequest>());
                    return(true);

                case 3869262148:
                    // Handle the 'presence' request.
                    response = HandlePresence.Process(client, info, message.As <PresenceRequest>());
                    return(true);

                default:
                    // We've got a bad request
                    response = EmitterError.BadRequest;
                    return(true);
                }
            }
            catch (NotImplementedException)
            {
                // We've got a not implemented exception
                response = EmitterError.NotImplemented;
                return(true);
            }
            catch (Exception ex)
            {
                // We've got a an internal error
                Service.Logger.Log(ex);
                response = EmitterError.ServerError;
                return(true);
            }
            finally
            {
                // Send the response, always
                if (response != null)
                {
                    SendResponse(client, "emitter/" + info.Channel, response);
                }
            }
        }
	/*
	-----------------------
	FindFreeEmitter()
	-----------------------
	*/
	static private int FindFreeEmitter( EmitterChannel src, SoundPriority priority ) {
		// default to the reserved emitter
		SoundEmitter next = theAudioManager.soundEmitters[0]:
		if ( src == EmitterChannel.Any ) {
			// pull from the free emitter list if possible
			if ( theAudioManager.nextFreeEmitters.size > 0 ) {
				// return the first in the list
				next = theAudioManager.nextFreeEmitters[0]:
				// remove it from the free list
				theAudioManager.nextFreeEmitters.RemoveAtFast( 0 ):
			} else {
				// no free emitters available so pull from the lowest priority sound
				if ( priority == SoundPriority.VeryLow ) {
					// skip low priority sounds
					return -1:
				} else {
					// find a playing emitter that has a lower priority than what we're requesting
					// TODO - we could first search for Very Low, then Low, etc ... TBD if it's worth the effort
					next = theAudioManager.playingEmitters.Find( item => item != null && item.priority < priority ):
					if ( next == null ) {
						// last chance to find a free emitter
						if ( priority < SoundPriority.Default ) {
							// skip sounds less than the default priority
							if ( theAudioManager.verboseLogging ) {
								Debug.LogWarning( "[AudioManager] skipping sound " + priority ):
							}
							return -1:
						} else {
							// grab a default priority emitter so that we don't cannabalize a high priority sound
							next = theAudioManager.playingEmitters.Find( item => item != null && item.priority <= SoundPriority.Default ): :
						}
					}
					if ( next != null ) {
						if ( theAudioManager.verboseLogging ) {
							Debug.LogWarning( "[AudioManager] cannabalizing " + next.originalIdx + " Time: " + Time.time ):
						}
						// remove it from the playing list
						next.Stop():
						theAudioManager.playingEmitters.RemoveFast( next ):
					}
				}
			}
		}
		if ( next == null ) {
			Debug.LogError( "[AudioManager] ERROR - absolutely couldn't find a free emitter! Priority = " + priority + " TOO MANY PlaySound* calls!" ):
			showPlayingEmitterCount = true:
			return -1:
		}
		return next.originalIdx:
	}
Beispiel #8
0
        /*
         * -----------------------
         * PlaySoundAt()
         * -----------------------
         */
        static public int PlaySoundAt(Vector3 position, AudioClip clip, float volume = 1.0f, EmitterChannel src = EmitterChannel.Any, float delay = 0.0f, float pitch = 1.0f, bool loop = false)
        {
            if (!SoundEnabled)
            {
                return(-1);
            }

            if (clip == null)
            {
                return(-1);
            }

            // check the distance from the local player and ignore sounds out of range
            if (staticListenerPosition != null)
            {
                if ((staticListenerPosition.position - position).sqrMagnitude > theAudioManager.audioMaxFallOffDistanceSqr)
                {
                    // no chance of being heard
                    return(-1);
                }
            }

            int idx = FindFreeEmitter(src, 0);

            if (idx == -1)
            {
                // no free emitters	- should only happen on very low priority sounds
                return(-1);
            }
            SoundEmitter emitter = theAudioManager.soundEmitters[idx];

            // make sure to detach the emitter from a previous parent
            emitter.ResetParent(soundEmitterParent.transform);
            emitter.gameObject.SetActive(true);

            // set up the sound emitter
            AudioSource     audioSource = emitter.audioSource;
            ONSPAudioSource osp         = emitter.osp;

            audioSource.enabled      = true;
            audioSource.volume       = Mathf.Clamp01(theAudioManager.volumeSoundFX * volume);
            audioSource.pitch        = pitch;
            audioSource.spatialBlend = 0.8f;
            audioSource.rolloffMode  = AudioRolloffMode.Linear;
            audioSource.SetCustomCurve(AudioSourceCurveType.ReverbZoneMix, defaultReverbZoneMix);
            audioSource.dopplerLevel          = 0.0f;
            audioSource.clip                  = clip;
            audioSource.spread                = 0.0f;
            audioSource.loop                  = loop;
            audioSource.mute                  = false;
            audioSource.minDistance           = theAudioManager.audioMinFallOffDistance;
            audioSource.maxDistance           = theAudioManager.audioMaxFallOffDistance;
            audioSource.outputAudioMixerGroup = AudioManager.EmitterGroup;
            // set the play time so we can check when sounds are done
            emitter.endPlayTime = Time.time + clip.length + delay;
            // cache the default volume for fading
            emitter.defaultVolume = audioSource.volume;
            // default priority
            emitter.priority = 0;
            // reset this
            emitter.onFinished = null;
            // update the sound group limits
            emitter.SetPlayingSoundGroup(null);
            // add to the playing list
            if (src == EmitterChannel.Any)
            {
                theAudioManager.playingEmitters.AddUnique(emitter);
            }

            // disable spatialization (by default for regular AudioClips)
            if (osp != null)
            {
                osp.EnableSpatialization = false;
            }

            audioSource.transform.position = position;

            if (theAudioManager.verboseLogging)
            {
                Debug.Log("[AudioManager] PlaySoundAt() channel = " + idx + " clip = " + clip.name + " volume = " + emitter.volume + " Delay = " + delay + " time = " + Time.time + "\n");
            }

            // play the sound
            if (delay > 0f)
            {
                audioSource.PlayDelayed(delay);
            }
            else
            {
                audioSource.Play();
            }

            return(idx);
        }
Beispiel #9
0
        /*
         * -----------------------
         * PlayRandomSoundAt()
         * -----------------------
         */
        static public int PlayRandomSoundAt(Vector3 position, AudioClip[] clips, float volume, EmitterChannel src = EmitterChannel.Any, float delay = 0.0f, float pitch = 1.0f, bool loop = false)
        {
            if ((clips == null) || (clips.Length == 0))
            {
                return(-1);
            }
            int idx = Random.Range(0, clips.Length);

            return(PlaySoundAt(position, clips[idx], volume, src, delay, pitch, loop));
        }
Beispiel #10
0
        /*
         * -----------------------
         * PlaySoundAt()
         * -----------------------
         */
        static public int PlaySoundAt(Vector3 position, SoundFX soundFX, EmitterChannel src = EmitterChannel.Any, float delay = 0.0f, float volumeOverride = 1.0f, float pitchMultiplier = 1.0f)
        {
            if (!SoundEnabled)
            {
                return(-1);
            }

            AudioClip clip = soundFX.GetClip();

            if (clip == null)
            {
                return(-1);
            }

            // check the distance from the local player and ignore sounds out of range
            if (staticListenerPosition != null)
            {
                float distFromListener = (staticListenerPosition.position - position).sqrMagnitude;
                if (distFromListener > theAudioManager.audioMaxFallOffDistanceSqr)
                {
                    return(-1);
                }
                if (distFromListener > soundFX.MaxFalloffDistSquared)
                {
                    return(-1);
                }
            }

            // check max playing sounds
            if (soundFX.ReachedGroupPlayLimit())
            {
                if (theAudioManager.verboseLogging)
                {
                    Debug.Log("[AudioManager] PlaySoundAt() with " + soundFX.name + " skipped due to group play limit");
                }
                return(-1);
            }

            int idx = FindFreeEmitter(src, soundFX.priority);

            if (idx == -1)
            {
                // no free emitters	- should only happen on very low priority sounds
                return(-1);
            }
            SoundEmitter emitter = theAudioManager.soundEmitters[idx];

            // make sure to detach the emitter from a previous parent
            emitter.ResetParent(soundEmitterParent.transform);
            emitter.gameObject.SetActive(true);

            // set up the sound emitter
            AudioSource     audioSource = emitter.audioSource;
            ONSPAudioSource osp         = emitter.osp;

            audioSource.enabled      = true;
            audioSource.volume       = Mathf.Clamp01(Mathf.Clamp01(theAudioManager.volumeSoundFX * soundFX.volume) * volumeOverride * soundFX.GroupVolumeOverride);
            audioSource.pitch        = soundFX.GetPitch() * pitchMultiplier;
            audioSource.time         = 0.0f;
            audioSource.spatialBlend = 1.0f;
            audioSource.rolloffMode  = soundFX.falloffCurve;
            if (soundFX.falloffCurve == AudioRolloffMode.Custom)
            {
                audioSource.SetCustomCurve(AudioSourceCurveType.CustomRolloff, soundFX.volumeFalloffCurve);
            }
            audioSource.SetCustomCurve(AudioSourceCurveType.ReverbZoneMix, soundFX.reverbZoneMix);
            audioSource.dopplerLevel          = 0;
            audioSource.clip                  = clip;
            audioSource.spread                = soundFX.spread;
            audioSource.loop                  = soundFX.looping;
            audioSource.mute                  = false;
            audioSource.minDistance           = soundFX.falloffDistance.x;
            audioSource.maxDistance           = soundFX.falloffDistance.y;
            audioSource.outputAudioMixerGroup = soundFX.GetMixerGroup(AudioManager.EmitterGroup);
            // set the play time so we can check when sounds are done
            emitter.endPlayTime = Time.time + clip.length + delay;
            // cache the default volume for fading
            emitter.defaultVolume = audioSource.volume;
            // sound priority
            emitter.priority = soundFX.priority;
            // reset this
            emitter.onFinished = null;
            // update the sound group limits
            emitter.SetPlayingSoundGroup(soundFX.Group);
            // add to the playing list
            if (src == EmitterChannel.Any)
            {
                theAudioManager.playingEmitters.AddUnique(emitter);
            }

            // OSP properties
            if (osp != null)
            {
                osp.EnableSpatialization = soundFX.ospProps.enableSpatialization;
                osp.EnableRfl            = theAudioManager.enableSpatializedFastOverride || soundFX.ospProps.useFastOverride ? true : false;
                osp.Gain                 = soundFX.ospProps.gain;
                osp.UseInvSqr            = soundFX.ospProps.enableInvSquare;
                osp.Near                 = soundFX.ospProps.invSquareFalloff.x;
                osp.Far                  = soundFX.ospProps.invSquareFalloff.y;
                audioSource.spatialBlend = (soundFX.ospProps.enableSpatialization) ? 1.0f : 0.8f;

                // make sure to set the properties in the audio source before playing
                osp.SetParameters(ref audioSource);
            }

            audioSource.transform.position = position;

            if (theAudioManager.verboseLogging)
            {
                Debug.Log("[AudioManager] PlaySoundAt() channel = " + idx + " soundFX = " + soundFX.name + " volume = " + emitter.volume + " Delay = " + delay + " time = " + Time.time + "\n");
            }

            // play the sound
            if (delay > 0f)
            {
                audioSource.PlayDelayed(delay);
            }
            else
            {
                audioSource.Play();
            }

            return(idx);
        }
Beispiel #11
0
        /// <summary>
        /// Attempts to publish and returns the result.
        /// </summary>
        /// <param name="client">The remote client.</param>
        /// <param name="channel">The full channel string.</param>
        /// <param name="message">The message to publish.</param>
        public static EmitterEventCode Process(IClient client, string channel, ArraySegment <byte> message)
        {
            try
            {
                // Parse the channel
                EmitterChannel info;
                if (!EmitterChannel.TryParse(channel, true, out info))
                {
                    return(EmitterEventCode.BadRequest);
                }

                // Is this a special api request?
                if (HandleRequest.TryProcess(client, info, message))
                {
                    return(EmitterEventCode.Success);
                }

                // Publish should only have static channel strings
                if (info.Type != ChannelType.Static)
                {
                    return(EmitterEventCode.Forbidden);
                }

                // Attempt to parse the key
                SecurityKey key;
                if (!SecurityKey.TryParse(info.Key, out key))
                {
                    return(EmitterEventCode.BadRequest);
                }

                // Has the key expired?
                if (key.IsExpired)
                {
                    return(EmitterEventCode.Unauthorized);
                }

                // Attempt to fetch the contract using the key. Underneath, it's cached.
                var contract = Services.Contract.GetByKey(key.Contract) as EmitterContract;
                if (contract == null)
                {
                    return(EmitterEventCode.NotFound);
                }

                // Check if the payment state is valid
                if (contract.Status == EmitterContractStatus.Refused)
                {
                    return(EmitterEventCode.PaymentRequired);
                }

                // Validate the contract
                if (!contract.Validate(ref key))
                {
                    return(EmitterEventCode.Unauthorized);
                }

                // Check if the key has the permission to write here
                if (!key.HasPermission(SecurityAccess.Write))
                {
                    return(EmitterEventCode.Unauthorized);
                }

                // Check if the key has the permission for the required channel
                if (key.Target != 0 && info.Target != key.Target)
                {
                    return(EmitterEventCode.Unauthorized);
                }

                // Do we have a TTL with the message?
                int ttl;
                info.HasTimeToLive(out ttl);

                // Check if the key has a TTL and also can store (soft permission)
                if (ttl > 0 && !key.HasPermission(SecurityAccess.Store))
                {
                    ttl = 0;
                }

                // Publish within the service
                Dispatcher.Publish(contract, info.Target, info.Channel, message, ttl);

                // Successfully published
                return(EmitterEventCode.Success);
            }
            catch (NotImplementedException)
            {
                // We've got a not implemented exception
                return(EmitterEventCode.NotImplemented);
            }
            catch (Exception ex)
            {
                // We need to log it
                Service.Logger.Log(ex);

                // We've got a an internal error
                return(EmitterEventCode.ServerError);
            }
        }
Beispiel #12
0
 /*
  * -----------------------
  * SetChannel()
  * -----------------------
  */
 public void SetChannel(int _channel)
 {
     channel = (EmitterChannel)_channel;
 }
Beispiel #13
0
        /// <summary>
        /// Occurs when the remote client attempts to subscribe to a hub.
        /// </summary>
        /// <param name="client">The remote client.</param>
        /// <param name="channel">The full channel string.</param>
        public static EmitterEventCode Process(IClient client, string channel)
        {
            try
            {
                // Parse the channel
                EmitterChannel info;
                if (!EmitterChannel.TryParse(channel, true, out info))
                {
                    return(EmitterEventCode.BadRequest);
                }

                // Simple ACK for api subscribe. We don't really need to subscribe as
                // this uses request/response topology and hence the response is sent
                // through the same TCP connection.
                if (info.Key == "emitter")
                {
                    return(EmitterEventCode.Success);
                }

                // Attempt to parse the key
                SecurityKey key;
                if (!SecurityKey.TryParse(info.Key, out key))
                {
                    return(EmitterEventCode.BadRequest);
                }

                // Has the key expired?
                if (key.IsExpired)
                {
                    return(EmitterEventCode.Unauthorized);
                }

                // Have we already subscribed?
                //if (client[channel] != null)
                //    return EmitterEventCode.Success;

                // Attempt to fetch the contract using the key. Underneath, it's cached.
                var contract = Services.Contract.GetByKey(key.Contract) as EmitterContract;
                if (contract == null)
                {
                    return(EmitterEventCode.NotFound);
                }

                // Check if the payment state is valid
                if (contract.Status == EmitterContractStatus.Refused)
                {
                    return(EmitterEventCode.PaymentRequired);
                }

                // Validate the contract
                if (!contract.Validate(ref key))
                {
                    return(EmitterEventCode.Unauthorized);
                }

                // Check if the key has the permission to read here
                if (!key.HasPermission(SecurityAccess.Read))
                {
                    return(EmitterEventCode.Unauthorized);
                }

                // Check if the key has the permission for the required channel
                if (key.Target != 0 && info.Target != key.Target)
                {
                    return(EmitterEventCode.Unauthorized);
                }

                // Subscribe to the channel
                var subs = Dispatcher.Subscribe(client, key.Contract, info.Channel, SubscriptionInterest.Messages);

                // Check if the history was also requested and we have the permission to do so
                var last = 0;
                if (!info.RequestedLast(out last) || !key.HasPermission(SecurityAccess.Load))
                {
                    return(EmitterEventCode.Success);
                }

                // Get the ssid
                var ssid = EmitterChannel.Ssid(key.Contract, info.Channel);

                // Stream the history
                Services.Storage
                .GetLastAsync(key.Contract, ssid, last)
                .ContinueWith(async(t) =>
                {
                    // Now send each message in order
                    var stream = t.Result;
                    while (stream.HasNext)
                    {
                        // Get the message asyncronously
                        var item = await stream.GetNext();
                        if (item.Count == 0)
                        {
                            continue;
                        }

                        // Increment the counter
                        Service.MessageSent?.Invoke(contract, channel, item.Count);

                        // Send the message out
                        var msg     = MqttPublishPacket.Acquire();
                        msg.Channel = info.Channel;
                        msg.Message = item;
                        client.Send(msg);
                    }
                });

                // We have successfully subscribed
                return(EmitterEventCode.Success);
            }
            catch (NotImplementedException)
            {
                // We've got a not implemented exception
                return(EmitterEventCode.NotImplemented);
            }
            catch (Exception ex)
            {
                // We need to log it
                Service.Logger.Log(ex);

                // We've got a an internal error
                return(EmitterEventCode.ServerError);
            }
        }
Beispiel #14
0
        /// <summary>
        /// Attempts to generate the key and returns the result.
        /// </summary>
        /// <param name="client">The remote client.</param>
        /// <param name="channel">The full channel string.</param>
        /// <param name="message">The message to publish.</param>
        public static EmitterResponse Process(IClient client, EmitterChannel channel, PresenceRequest request)
        {
            // Parse the channel
            EmitterChannel info;

            if (!EmitterChannel.TryParse(request.Channel, false, out info))
            {
                return(EmitterError.BadRequest);
            }

            // Should be a static (non-wildcard) channel string.
            if (info.Type != ChannelType.Static)
            {
                return(EmitterError.BadRequest);
            }

            // Attempt to parse the key, this should be a master key
            SecurityKey channelKey;

            if (!SecurityKey.TryParse(request.Key, out channelKey) || !channelKey.HasPermission(SecurityAccess.Presence) || channelKey.IsExpired)
            {
                return(EmitterError.Unauthorized);
            }

            // Make sure the channel name ends with
            if (!request.Channel.EndsWith("/"))
            {
                request.Channel += "/";
            }

            // Subscription
            Subscription sub;

            if (request.Changes)
            {
                // If we requested changes, register a subscription with this new interest
                Subscription.Register(client, channelKey.Contract, request.Channel, SubscriptionInterest.Presence);
            }
            else
            {
                // If the changes flag is set to false, unregister the client from presence
                Subscription.Unregister(client, channelKey.Contract, request.Channel, SubscriptionInterest.Presence, out sub);
            }

            // If we didn't request a presence, send an OK response only
            if (!request.Status)
            {
                return(new EmitterResponse(200));
            }

            // Find the subscription
            if (!Subscription.TryGet(channelKey.Contract, request.Channel, out sub))
            {
                // No subscription found, return an empty one
                return(new PresenceResponse(request.Channel, 0, null));
            }

            // Current list
            var presenceList = sub.Presence
                               .Where(p => !p.Deleted)
                               .Take(1000)
                               .Select(p => p.Value.AsInfo())
                               .ToList();

            // If we requested a presence, prepare a response
            return(new PresenceResponse(request.Channel, sub.Occupancy, presenceList));
        }
Beispiel #15
0
        /// <summary>
        /// Periodically publishes the usage monitors.
        /// </summary>
        private void Publish()
        {
            try
            {
                // Prepare options
                var ourContract = SecurityLicense.Current.Contract;
                var builder     = new StringBuilder();

                // Publish every monitor as a separate message
                foreach (var c in Services.Contract)
                {
                    // Get the usage from the contract
                    var contract = c as EmitterContract;
                    if (contract == null)
                    {
                        continue;
                    }

                    // If the monitor didn't change, we don't need to publish it
                    var usage = contract.Usage;
                    if (usage.IsZero)
                    {
                        continue;
                    }

                    try
                    {
                        // Reuse the builder
                        builder.Clear();

                        // Sample to the througput limiter
                        usage.MessageFrequency.Sample(usage.IncomingMessages.Value + usage.OutgoingMessages.Value);

                        // Write and reset the usage
                        usage.Write(builder, contract.Oid);
                        usage.Reset();

                        // Convert to a message, TODO: remove unnecessary allocations
                        var message = builder
                                      .ToString()
                                      .AsASCII()
                                      .AsSegment();

                        // The channel to publish into
                        var channel = "usage/" + contract.Oid + "/";

                        // Get the channel hash for query
                        EmitterChannel info;
                        if (!EmitterChannel.TryParse(channel, false, out info))
                        {
                            return;
                        }

                        // Publish the message in the cluster, don't need to store it as it might slow everything down
                        Dispatcher.Publish(ourContract, info.Target, channel, message, 60);
                    }
                    catch (Exception ex)
                    {
                        // Log the exception
                        Service.Logger.Log(ex);
                    }
                }
            }
            catch (Exception ex)
            {
                // Log the exception
                Service.Logger.Log(ex);
            }
        }
Beispiel #16
0
        /// <summary>
        /// Occurs when the remote client attempts to unsubscribe from a hub.
        /// </summary>
        /// <param name="client">The remote client.</param>
        /// <param name="channel">The full channel string.</param>
        public static EmitterEventCode Process(IClient client, string channel)
        {
            try
            {
                // Parse the channel
                EmitterChannel info;
                if (!EmitterChannel.TryParse(channel, true, out info))
                {
                    return(EmitterEventCode.BadRequest);
                }

                // Attempt to parse the key
                SecurityKey key;
                if (!SecurityKey.TryParse(info.Key, out key))
                {
                    return(EmitterEventCode.BadRequest);
                }

                // Has the key expired?
                if (key.IsExpired)
                {
                    return(EmitterEventCode.Unauthorized);
                }

                // Have we already unsubscribed?
                //if (client[channel] == null)
                //    return EmitterEventCode.Success;

                // Attempt to fetch the contract using the key. Underneath, it's cached.
                var contract = Services.Contract.GetByKey(key.Contract) as EmitterContract;
                if (contract == null)
                {
                    return(EmitterEventCode.NotFound);
                }

                // Check if the payment state is valid
                if (contract.Status == EmitterContractStatus.Refused)
                {
                    return(EmitterEventCode.PaymentRequired);
                }

                // Validate the contract
                if (!contract.Validate(ref key))
                {
                    return(EmitterEventCode.Unauthorized);
                }

                // Check if the key has the permission to read here
                if (!key.HasPermission(SecurityAccess.Read))
                {
                    return(EmitterEventCode.Unauthorized);
                }

                // Check if the key has the permission for the required channel
                if (info.Target != key.Target)
                {
                    return(EmitterEventCode.Unauthorized);
                }

                // Get the subscription id from the storage
                if (!Dispatcher.Unsubscribe(client, key.Contract, info.Channel, SubscriptionInterest.Messages))
                {
                    return(EmitterEventCode.Unauthorized);
                }

                // Successfully unsubscribed
                return(EmitterEventCode.Success);
            }
            catch (NotImplementedException)
            {
                // We've got a not implemented exception
                return(EmitterEventCode.NotImplemented);
            }
            catch (Exception ex)
            {
                // We need to log it
                Service.Logger.Log(ex);

                // We've got a an internal error
                return(EmitterEventCode.ServerError);
            }
        }