/// <summary> /// Initializes a new instance of the <see cref="JsonStoreWriter"/> class. /// </summary> /// <param name="name">The name of the application that generated the persisted files, or the root name of the files.</param> /// <param name="path">The directory in which the main persisted file resides or will reside, or null to create a volatile data store.</param> /// <param name="createSubdirectory">If true, a numbered subdirectory is created for this store.</param> /// <param name="extension">The extension for the underlying file.</param> public JsonStoreWriter(string name, string path, bool createSubdirectory = true, string extension = DefaultExtension) : base(extension) { ushort id = 0; this.Name = name; this.Path = System.IO.Path.GetFullPath(path); if (createSubdirectory) { // if the root directory already exists, look for the next available id if (Directory.Exists(this.Path)) { var existingIds = Directory.EnumerateDirectories(this.Path, this.Name + ".????") .Select(d => d.Split('.').Last()) .Where(n => ushort.TryParse(n, out ushort i)) .Select(n => ushort.Parse(n)); id = (ushort)(existingIds.Count() == 0 ? 0 : existingIds.Max() + 1); } this.Path = System.IO.Path.Combine(this.Path, $"{this.Name}.{id:0000}"); } if (!Directory.Exists(this.Path)) { Directory.CreateDirectory(this.Path); } string dataPath = System.IO.Path.Combine(this.Path, PsiStoreCommon.GetDataFileName(this.Name) + this.Extension); this.streamWriter = File.CreateText(dataPath); this.jsonWriter = new JsonTextWriter(this.streamWriter); this.jsonWriter.WriteStartArray(); }
/// <summary> /// Seek to envelope in stream according to specified replay descriptor. /// </summary> /// <param name="descriptor">The replay descriptor.</param> public void Seek(ReplayDescriptor descriptor) { this.descriptor = descriptor; // load data string dataPath = System.IO.Path.Combine(this.Path, PsiStoreCommon.GetDataFileName(this.Name) + this.Extension); this.streamReader?.Dispose(); this.streamReader = File.OpenText(dataPath); this.jsonReader = new JsonTextReader(this.streamReader); // iterate through data store until we either reach the end or we find the start of the replay descriptor while (this.jsonReader.Read()) { // data stores are arrays of messages, messages start as objects if (this.jsonReader.TokenType == JsonToken.StartObject) { // read envelope if (!this.jsonReader.Read() || !this.ReadEnvelope(out this.envelope)) { throw new InvalidDataException("Messages must be an ordered object: {\"Envelope\": <Envelope>, \"Data\": <Data>}. Deserialization needs to read the envelope before the data to know what type of data to deserialize."); } if (this.descriptor.Interval.Left < this.envelope.OriginatingTime) { // found start of interval break; } // skip data if (!this.ReadData(out this.data)) { throw new InvalidDataException("Messages must be an ordered object: {\"Envelope\": <Envelope>, \"Data\": <Data>}. Deserialization needs to read the envelope before the data to know what type of data to deserialize."); } } } }