예제 #1
0
        public string GetData(StreamData stream, int start, int count = -1)
        {
            lock (stream.Lock)
            {
                if (start < 0)
                {
                    throw new InvalidOperationException("Start less than zero!");
                }

                //I don't care what the inputs are, if the stream is empty, you can have it
                if (stream.Data.Length == 0)
                {
                    return("");
                }

                if (start >= stream.Data.Length)
                {
                    throw new InvalidOperationException($"Start beyond end of data: {stream.Data.Length}!");
                }

                if (count < 0 || count > stream.Data.Length - start)
                {
                    count = stream.Data.Length - start;
                }

                return(stream.Data.ToString(start, count));
            }
        }
예제 #2
0
        /// <summary>
        /// Get an existing stream from memory. If it's not in memory, check disk. If it's not on disk, create a new one.
        /// In any case, at the end of this call, a stream is guaranteed to be in memory.
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public StreamData GetStream(string name)
        {
            //Don't let ANYBODY else mess with the dictionary while we're doing it!
            lock (Lock)
            {
                if (!Streams.ContainsKey(name))
                {
                    //Look for the stream in permament storage.
                    var existing = LoadStream(name);

                    //Oops it didn't exist, set to a new one
                    if (existing == null)
                    {
                        logger.LogInformation($"Creating new room {name}");
                        existing = new StreamData();
                    }
                    else
                    {
                        //Just log that it was found
                        logger.LogInformation($"Reviving dead room {name}");
                    }

                    Streams.Add(name, existing);
                }

                //NOTE: because we don't get rid of readonly key associations, we ASSUME that if
                //we have an existing stream, there IS a readonly key for it!
                return(Streams[name]);
            }
        }
예제 #3
0
        protected void SaveStream(string name, StreamData s, bool forceEmpty = false)
        {
            if (!Directory.Exists(Config.StoreLocation))
            {
                Directory.CreateDirectory(Config.StoreLocation);
            }

            //Don't save empty rooms (unless we're forced to!)
            if (s.Data.Length > 0 || forceEmpty)
            {
                File.WriteAllText(Path.Combine(Config.StoreLocation, name), s.Data.ToString());
            }

            s.SaveDate = DateTime.Now;
        }
예제 #4
0
        public async Task <ReadyData> GetDataWhenReady(StreamData stream, int start, int count = -1)
        {
            //JUST IN CASE we need it later (can't make it in the lock section, needed outside!)
            bool           completed = false;
            StreamListener listener  = null;
            ReadyData      result    = new ReadyData();

            lock (stream.Lock)
            {
                if (start < stream.Data.Length)
                {
                    //No waiting! We're already done! The stream can never get smaller!
                    completed = true;
                }
                else
                {
                    //Oh, waiting... we're a new listener so add it!
                    listener        = new StreamListener();
                    listener.Waiter = Task.Run(() => completed = stream.Signal.WaitOne(Config.ListenTimeout));
                    stream.Listeners.Add(listener);
                }
            }

            //Don't need to listen if there's no listener!
            if (listener != null)
            {
                //CANNOT wait in the lock! We're just waiting to see if we get data. If we DOOOO, "completed" will be true!
                try
                {
                    await listener.Waiter;
                }
                finally
                {
                    //We're done. Doesn't matter what happened, whether it finished or we threw an exception,
                    //we are NO LONGER listening!
                    result.SignalData = listener.SignalData; //this might be nothing
                    stream.Listeners.Remove(listener);
                }
            }

            if (completed)
            {
                result.Data = GetData(stream, start, count);
            }

            return(result);
        }
예제 #5
0
        public void AddData(StreamData stream, string data)
        {
            lock (stream.Lock)
            {
                if (data.Length == 0)
                {
                    throw new InvalidOperationException("Can't add 0 length data!");
                }

                if (data.Length > Config.SingleDataLimit)
                {
                    throw new InvalidOperationException($"Too much data at once!: {Config.SingleDataLimit}");
                }

                //Don't allow data additions that would allow the limit to go beyond thingy!
                if (stream.Data.Length >= Config.StreamDataLimit)
                {
                    throw new InvalidOperationException($"Stream at data limit: {Config.StreamDataLimit}");
                }

                stream.Data.Append(data);
                stream.UpdateDate = DateTime.Now;

                var signalData = new SignalData()
                {
                    ListenersBeforeSignal = stream.Listeners.Count
                };

                //Set the signal data before signalling so they have "communication" from us. NOT SAFE
                //since someone could... you know, add a listener... or could they? We hold the lock for
                //the stream and you can't add a listener without the lock! So probably safe...
                stream.Listeners.ForEach(x => x.SignalData = signalData);

                //Set the signal so all the listeners know they have data!
                stream.Signal.Set();

                try
                {
                    var signalStart = DateTime.Now;

                    //Wait for OUR listeners to clear out! Notice that the listener wait and removal is NOT
                    //in a lock: this allows US to hold the lock (since it's probably safer...? we're doing the signalling).
                    while (stream.Listeners.Count > 0)
                    {
                        System.Threading.Thread.Sleep(Config.SignalWaitInterval);

                        if (DateTime.Now - signalStart > Config.SignalTimeout)
                        {
                            logger.LogWarning("Timed out while waiting for listeners to process signal!");
                            break;
                        }
                    }
                }
                finally
                {
                    //ALWAYS get rid of listeners and reset the signal! we don't want to be left in an unknown state!
                    stream.Listeners.Clear(); //This might be dangerous? IDK, we don't want to wait forever!
                    stream.Signal.Reset();
                }
            }
        }