using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Configuration; using Web.Core; using Web.Core.DB; using FLocal.Common; using FLocal.Common.dataobjects; using System.IO; using System.Threading; using FLocal.Patcher.Common; namespace FLocal.IISHandler { class Initializer { public static readonly Initializer instance = new Initializer(); private bool isInitialized; private bool isCached; private readonly object locker = new object(); /// /// We wouldn't want class constructor to throw an exception, so all "smart" things are inside the Initialize(); /// private Initializer() { this.isInitialized = false; this.isCached = false; } public void Initialize() { if(!this.isInitialized) { lock(this.locker) { if(!this.isInitialized) { this.DoInitialize(); this.isInitialized = true; } } } if(!this.isCached) { lock(this.locker) { if(!this.isCached) { this.DoCache(); this.isCached = true; } } } } private void DoInitialize() { Config.Init(ConfigurationManager.AppSettings); PatcherConfiguration.Init(ConfigurationManager.AppSettings); } private void DoCache() { if(!PatcherInfo.instance.IsNeedsPatching) { string dir = FLocal.Common.Config.instance.dataDir + "Logs\\"; using(StreamWriter writer = new StreamWriter(dir + DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss") + ".INITIALIZE.txt")) { writer.WriteLine("###INITIALIZE###"); foreach(var cacher in this.cachers) { System.Threading.ThreadPool.QueueUserWorkItem(this.GetCacheWrapper(cacher)); writer.WriteLine("Pending " + cacher.Key); } } } } private IEnumerable> cachers { get { yield return this.GetTableCacher(Machichara.LoadByIds, Machichara.TableSpec.instance); yield return this.GetTableCacher(ModernSkin.LoadByIds, ModernSkin.TableSpec.instance); yield return this.GetTableCacher(PostLayer.LoadByIds, PostLayer.TableSpec.instance); yield return this.GetTableCacher(PunishmentType.LoadByIds, PunishmentType.TableSpec.instance); yield return this.GetTableCacher(QuickLink.LoadByIds, QuickLink.TableSpec.instance); yield return this.GetTableCacher(Skin.LoadByIds, Skin.TableSpec.instance); yield return this.GetTableCacher(UserGroup.LoadByIds, UserGroup.TableSpec.instance); yield return new KeyValuePair("categories", this.CacheCategories); } } private WaitCallback GetCacheWrapper(KeyValuePair cacher) { return state => { string dir = FLocal.Common.Config.instance.dataDir + "Logs\\"; DateTime start = DateTime.Now; /*using(StreamWriter writer = new StreamWriter(dir + start.ToString("yyyy-MM-dd_HH-mm-ss") + ".init." + cacher.Key + ".txt")) { writer.WriteLine("###INITIALIZER/CACHER###"); writer.WriteLine("info: " + cacher.Value.Method.Name); writer.WriteLine(); }*/ FLocalException error = null; try { cacher.Value(); } catch(FLocalException e) { error = e; } DateTime end = DateTime.Now; using(StreamWriter writer = new StreamWriter(dir + end.ToString("yyyy-MM-dd_HH-mm-ss") + ".initend." + cacher.Key + ".txt")) { writer.WriteLine("###INITIALIZER/CACHER###"); writer.WriteLine("info: " + cacher.Value.Method.Name); writer.WriteLine("Start: " + start); writer.WriteLine(); if(error != null) { writer.WriteLine("Exception: " + error.GetType().FullName); writer.WriteLine("Guid: " + error.GetGuid().ToString()); writer.WriteLine(error.Message); if(error is FLocalException) { writer.WriteLine(((FLocalException)error).FullStackTrace); } else { writer.WriteLine(error.StackTrace); } } } }; } private KeyValuePair GetTableCacher(Func, List> objectsLoader, ITableSpec tableSpec) where SqlObjectType : SqlObject, new() { return new KeyValuePair( typeof(SqlObjectType).FullName, () => { foreach( SqlObjectType sqlObject in objectsLoader( from stringId in Config.instance.mainConnection.LoadIdsByConditions( tableSpec, new Web.Core.DB.conditions.EmptyCondition(), Diapasone.unlimited ) select int.Parse(stringId) ) ) { sqlObject.LoadIfNotLoaded(); } } ); } private void CacheCategories() { foreach(var category in Category.allCategories) { category.LoadIfNotLoaded(); foreach(var board in category.subBoards) { this.CacheBoard(board); } } int? _maxPostId = ( from category in Category.allCategories from board in category.subBoards select board.lastPostId ).Max(); if(_maxPostId.HasValue) { int maxPostId = _maxPostId.Value; int minPostId = Math.Max(maxPostId - 10000, 0); for(int i=maxPostId; i>minPostId; i--) { try { CachePost(Post.LoadById(i)); } catch(NotFoundInDBException) { } } } } private void CachePost(Post post) { post.LoadIfNotLoaded(); post.thread.LoadIfNotLoaded(); post.poster.LoadIfNotLoaded(); if(post.poster.avatarId != null) { post.poster.avatar.LoadIfNotLoaded(); } if(post.revision != null) { post.latestRevision.LoadIfNotLoaded(); } if(post.parentPostId != null) { post.parentPost.LoadIfNotLoaded(); if(post.parentPost.revision != null) { post.parentPost.latestRevision.LoadIfNotLoaded(); } } foreach(var punishment in post.punishments) { punishment.LoadIfNotLoaded(); punishment.moderator.LoadIfNotLoaded(); } if(post.id > post.thread.firstPostId) { CachePost(post.thread.firstPost); } } private void CacheBoard(Board board) { board.LoadIfNotLoaded(); foreach(var subBoard in board.subBoards) { CacheBoard(subBoard); } } } }