/// <summary>called from controller only, when a module is open for editing, or created new</summary> /// <param name="moduleId"></param> /// <param name="db">db context passed from controller, must exist because controller creates it for every request</param> /// <returns>true if module exists in db</returns> public static bool PopulateModuleCache(int moduleId, Entities db) { try { if (moduleCache.Keys.Contains(moduleId)) { // if session was dead, but getTTS still used the cached module for download TTS, and we reopen the editor, // then mark SessionExpired = false, so that when getTTS finishes it does not clear module from cache moduleCache[moduleId].SessionExpired = false; return(true); } Module m = db.Modules.FirstOrDefault(o => o.Id == moduleId); // read module from db into the dict if (m == null) { return(false); } var cm = new CachedModule(); cm.ForeignLangCode = m.ForeignLang; cm.NativeLangCode = m.NativeLang; cm.Rows = string.IsNullOrWhiteSpace(m.Text) ? cm.Rows : m.Text.Split(new string[] { "\r\n", "\n" }, StringSplitOptions.None).Select((s, i) => new DirtyRow() { value = s, iRow = i, }).ToList(); moduleCache[moduleId] = cm; return(true); } catch (Exception ex) { Log($"{ex.Message}\r\n{ex.StackTrace}"); return(false); } }
/// <summary> /// for all cached modules with EnableTTS and not CompletedTTS: take each phrase, decompose into words, call DownloadTTS for each phrase/word; /// in AgentCallback() call getTTs() after FlushModuleCache(), /// this will block the thread, next thread created by agent will flush again, but getTTS() will exit if it is already running /// </summary> public static void getTTS() { if (getTTSIsRunning) { return; } getTTSIsRunning = true; // download for one module at a time foreach (var m in moduleCache.Where(mm => mm.Value.EnableTTS && !mm.Value.CompletedTTS)) { try { m.Value.CompletedTTS = true; m.Value.IsModified = false; // may be flipped in outside thread by UpdateModuleCach foreach (var r in m.Value.Rows.Where(rr => !rr.CompletedTTS && !string.IsNullOrWhiteSpace(rr.value))) { string langCode = m.Value.LangCode(r.iRow); r.CompletedTTS = DownloadTTS(r.value, langCode, ttsFilePath(r.value, langCode)); foreach (var word in r.value.Split(WordSeparators, StringSplitOptions.RemoveEmptyEntries)) { var _word = word.Where(c => !char.IsPunctuation(c)).Aggregate("", (current, c) => current + c); // remove remaining punctuation from separate words if (!string.IsNullOrWhiteSpace(_word)) { r.CompletedTTS &= DownloadTTS(_word, langCode, ttsFilePath(_word, langCode)); } } m.Value.CompletedTTS &= (r.CompletedTTS && !m.Value.IsModified); } // after module download finished, check if user's session is expired, then remove module from cache if (moduleCache[m.Key].SessionExpired && m.Value.CompletedTTS) { CachedModule val = null; moduleCache.TryRemove(m.Key, out val); } } catch (Exception ex) { // TODO: if we call UpdateModuleCache while getTTS is working, getTTS will throw "collection was modified" and will restart all modules in 2 mins // probably more graceful is to // 1. create a copy of module rows by calling Rows.ToList(), // 2. iterate all of them, // 3. after finishing each module, check a flag module.IsModified that is set outside of loop by UpdateModuleCache: if (m.IsModified) CompletedTTS = false; // so that external modification during getTTS will mark module dirty for another round m.Value.CompletedTTS = false; Log($"{ex.Message}\r\n{ex.StackTrace}"); } } getTTSIsRunning = false; }
/// <exception cref="IOException"/> private static ModuleMetadata GetOrCreateModuleFromFile(string fullPath) { ModuleMetadata module = null; // may throw FileKey key = FileKey.Create(fullPath); CachedModule cachedModule; bool existingKey = modulesFromFiles.TryGetValue(key, out cachedModule); if (existingKey && cachedModule.Metadata.TryGetTarget(out module)) { return(module); } // mempy-map the module: module = ModuleMetadata.CreateFromFile(fullPath); // refresh the timestamp (the file may have changed just before we memory-mapped it): bool fault = true; try { key = FileKey.Create(fullPath); fault = false; } finally { if (fault) { module.Dispose(); } } cachedModule = new CachedModule(module); modulesFromFiles[key] = cachedModule; if (!existingKey) { moduleKeys.Add(key); EnableCompactTimer(); } return(module); }
/// <summary> /// called from agent callback every N mins, also from Application_End /// </summary> /// <param name="moduleId">if null or not passed, we flush all dirty modules to db</param> /// <param name="db">db context created in the agent for just one task, or in the controller, and passed here</param> /// <returns>true if module exists</returns> /// <remarks>probably it is safe in the way, that with short timer interval we'll have multiple threads running this method in AgentCallback, /// and it will distribute work evenly among them, so it will finish faster that using one thread</remarks> public static bool FlushModuleCache(int moduleId = 0) { Entities db = new Entities(); // must be separate instance for each thread if (moduleId == 0) { foreach (var cm in moduleCache) { FlushModuleCache(cm.Key); } return(true); } try { if (!moduleCache[moduleId].IsDirty) { return(true); // skip unmodified modules, also skips modules currently being saved by other threads } moduleCache[moduleId].IsDirty = false; // to prevent other threads from saving this module again while current thread is still doing it Module m = db.Modules.FirstOrDefault(o => o.Id == moduleId); if (m == null) { CachedModule val = null; moduleCache.TryRemove(moduleId, out val); return(false); } m.Text = string.Join("\r\n", moduleCache[moduleId].Rows.Select(r => r.value)); db.SaveChanges(); // this can take long } catch (Exception ex) { moduleCache[moduleId].IsDirty = true; Log($"{ex.Message}\r\n{ex.StackTrace}"); return(false); } return(true); }
/// <summary> /// Thủ tục khởi tạo Module và chèn Module vào cột đã định. /// </summary> /// <param name="td">Ô (hay cột) chứa Module</param> /// <param name="tab">Tab chứa Module (cần để lấy thêm thông tin về Tab)</param> /// <param name="modules">Danh sách Module đã được định nghĩa thuộc cột này</param> private void RenderModules(HtmlTableCell td, PortalDefinition.Tab tab, ArrayList modules) { //if (Request.HttpMethod == "GET") //{ // Kiểm tra nếu không có Module nào trong cột thì chèn khoảng trắng để lưu vị trí cột if (modules.Count == 0) { _arrAllEmptyColumn.Add(td); } // Duyệt danh sách Module PortalDefinition.Module _objModuleDefinition; ChannelUsers objUser = new ChannelUsers(); // Khởi tạo Module Module _objModuleControl; CachedModule _objCachedModuleControl; for (int _intModuleCount = 0; _intModuleCount < modules.Count; _intModuleCount++) { _objModuleDefinition = modules[_intModuleCount] as PortalDefinition.Module; //DuongNA tạm thời bỏ Kiểm tra người dùng có quyền hiển thị Module hay không //if (objUser.HasViewRights(Page.User, _objModuleDefinition.roles)) { _objModuleControl = null; _objCachedModuleControl = null; // Nạp các thông số về Module _objModuleDefinition.LoadModuleSettings(); //DuongNA tạm thời bỏ trycatch //try { // Kiểm tra xem có thông số nào được xác lập không // Xây dựng chuỗi đường dẫn đến tệp ASCX string _strModuleSrc = Config.GetModuleVirtualPath(_objModuleDefinition.type); if (_objModuleDefinition.moduleSettings == null) { string[] strModulePath = _objModuleDefinition.type.Split("/".ToCharArray()); string strModule; if (strModulePath.Length == 2) { strModule = strModulePath[1]; } else { strModule = strModulePath[0]; } _strModuleSrc += strModule + ".ascx"; } else { _strModuleSrc += _objModuleDefinition.moduleSettings.ctrl; } //DuongNA tạm thời bỏ Kiểm tra xem Module có được phép hiển thị hay không //if((_objModuleControl != null && _objModuleControl.IsVisible() || (_objCachedModuleControl != null && _objCachedModuleControl.IsVisible()))) { // Kiểm tra xem trang hiện thời có nằm trong trạng thái cho phép kéo thả hay không // Nếu ở trạng thái hỗ trợ kéo thả thì tạo các khung chứa (Snap) để chứa nội dung của các Module // (nội dung này sẽ được nạp sử dụng Ajax khi người sử dụng mở rộng khung hoặc chế độ tự động mở rộng khung dc bật) if (_objModuleDefinition.CacheTime <= 0) { // Nếu Module không sử dụng Cache _objModuleControl = (Module)LoadModule(_strModuleSrc); // Khởi tạo nội dung Module _objModuleControl.InitModule(tab.reference, _objModuleDefinition.reference, _objModuleDefinition.type, Config.GetModuleVirtualPath(_objModuleDefinition.type), true); } else { // Nếu Module có sử dụng Cache _objCachedModuleControl = new CachedModule(); _objCachedModuleControl.ModuleCacheTime = _objModuleDefinition.CacheTime; // Khởi tạo nội dung Module _objCachedModuleControl.InitModule(tab.reference, _objModuleDefinition.reference, _objModuleDefinition.type, Config.GetModuleVirtualPath(_objModuleDefinition.type), true, _strModuleSrc); } if ((_objModuleControl != null && _objModuleControl.IsVisible() || (_objCachedModuleControl != null && _objCachedModuleControl.IsVisible()))) { // Hiển thị nội dung Module theo cách trình bày bình thường không hỗ trợ kéo thả HtmlTable _objSimpleModuleContainer = new HtmlTable(); _objSimpleModuleContainer.Width = "100%"; _objSimpleModuleContainer.CellPadding = 0; _objSimpleModuleContainer.CellSpacing = 0; _objSimpleModuleContainer.Rows.Add(new HtmlTableRow()); // Nạp dữ liệu của Module vào ô chứa Module HtmlTableCell _objCellContainer = new HtmlTableCell(); _objSimpleModuleContainer.Rows[0].Cells.Add(_objCellContainer); _objCellContainer.Attributes.Add("class", "Module_Simple_Block"); _objCellContainer.VAlign = "top"; if (_objModuleControl != null) { _objCellContainer.Controls.Add(_objModuleControl); } else { _objCellContainer.Controls.Add(_objCachedModuleControl); } //cách giữa header và body _objCellContainer.Attributes.Add("style", "padding-bottom:0px;"); td.Controls.Add(_objSimpleModuleContainer); } //} } } //catch (Exception e) //{ // Console.WriteLine(e.Message + e.StackTrace); //} } } }
/// <summary> /// Thủ tục khởi tạo Module và chèn Module vào cột đã định. /// </summary> /// <param name="td">Ô (hay cột) chứa Module</param> /// <param name="tab">Tab chứa Module (cần để lấy thêm thông tin về Tab)</param> /// <param name="modules">Danh sách Module đã được định nghĩa thuộc cột này</param> private void RenderModules(HtmlTableCell td, PortalDefinition.Tab tab, ArrayList modules) { //if (Request.HttpMethod == "GET") //{ #region Khi phuong thuc lay la get // Kiểm tra nếu không có Module nào trong cột thì chèn khoảng trắng để lưu vị trí cột if (modules.Count == 0) { _arrAllEmptyColumn.Add(td); } // Duyệt danh sách Module for (int _intModuleCount = 0; _intModuleCount < modules.Count; _intModuleCount++) { PortalDefinition.Module _objModuleDefinition = modules[_intModuleCount] as PortalDefinition.Module; ChannelUsers objUser = new ChannelUsers(); // Kiểm tra người dùng có quyền hiển thị Module hay không if (objUser.HasViewRights(Page.User, _objModuleDefinition.roles)) { // Nạp các thông số về Module _objModuleDefinition.LoadModuleSettings(); // Khởi tạo Module Module _objModuleControl = null; CachedModule _objCachedModuleControl = null; //try //{ // Kiểm tra xem có thông số nào được xác lập không // Xây dựng chuỗi đường dẫn đến tệp ASCX string _strModuleSrc = Config.GetModuleVirtualPath(_objModuleDefinition.type); if (_objModuleDefinition.moduleSettings == null) { //_objModuleDefinition.LoadRuntimeProperties(); //string strAjax=_objModuleDefinition.moduleRuntimeSettings.GetRuntimePropertyValue(true, "isAjax"); ////Xu ly truong hop co ajax request den ca trang. Neu Module k co Ajax thi k load //if ((strAjax == "false" || strAjax =="")&& Request.HttpMethod =="POST") // continue; string[] strModulePath = _objModuleDefinition.type.Split("/".ToCharArray()); string strModule; if (strModulePath.Length == 2) { strModule = strModulePath[1]; } else { strModule = strModulePath[0]; } _strModuleSrc += strModule + ".ascx"; } else { _strModuleSrc += _objModuleDefinition.moduleSettings.ctrl; } #region phan bo di // Kiểm tra xem Module có được phép hiển thị hay không //if((_objModuleControl != null && _objModuleControl.IsVisible() || (_objCachedModuleControl != null && _objCachedModuleControl.IsVisible()))) { #endregion // Kiểm tra xem trang hiện thời có nằm trong trạng thái cho phép kéo thả hay không // Nếu ở trạng thái hỗ trợ kéo thả thì tạo các khung chứa (Snap) để chứa nội dung của các Module // (nội dung này sẽ được nạp sử dụng Ajax khi người sử dụng mở rộng khung hoặc chế độ tự động mở rộng khung dc bật) if (IsAdmin) { #region Xu ly voi cac module quan tri // Khởi tạo phần tiêu đề của khung chứa Module (Khởi tạo 2 Control để tránh trùng lặp ID) // Header khi chưa thu gọn ModuleHeader _objModuleHeaderExpanded = (ModuleHeader)LoadControl("ModuleHeader.ascx"); _objModuleHeaderExpanded.SetModuleConfig(_objModuleDefinition); // Header khi đã thu gọn ModuleHeader _objModuleHeaderCollapsed = (ModuleHeader)LoadControl("ModuleHeader.ascx"); _objModuleHeaderCollapsed.SetModuleConfig(_objModuleDefinition); // Sử dụng Snap Component để chứa Module và hỗ trợ khả năng kéo thả // Khởi tạo Khung hiển thị của Module (Make Snap Instance) Snap _objSnap = new Snap(); _objSnap.ClientSideCookieEnabled = false; // Không lưu trữ Cookie khi thay đổi Snap _objSnap.DraggingStyle = SnapDraggingStyleType.TransparentRectangle; // Kiểu kéo khung, hiển thị 1 hình chữ nhật xám khi kéo khung _objSnap.DockingStyle = SnapDockingStyleType.TransparentRectangle; // Kiểu thả khung, hiển thị 1 hình chữ nhật xám tại nơi sẽ đặt _objSnap.ResizingMode = SnapResizingType.Horizontal; // Thay đổi kích thước tùy vào vùng đặt khung (đổi theo chiều ngang) _objSnap.MustBeDocked = true; // Khung chứa Module phải được gắn vào 1 vị trí cụ thể _objSnap.ID = _objModuleDefinition.reference.Replace('-', '_'); // Thiết lập mã tham chiếu cho khung (cần đổi - thành _) _objSnap.CurrentDockingIndex = _intModuleCount; // Thứ tự đặt khung hiển thị _objSnap.CollapseDuration = 0; _objSnap.CollapseSlide = SlideType.None; _objSnap.CollapseTransition = TransitionType.None; _objSnap.ExpandDuration = 0; _objSnap.ExpandSlide = SlideType.None; _objSnap.ExpandTransition = TransitionType.None; _objSnap.IsCollapsed = true; _objSnap.Width = Unit.Percentage(100); // Khai báo mã tham chiếu của các vùng có thể đặt Module _objSnap.DockingContainers = _strContainerList; // Xác lập mã tham thiếu của vùng đặt hiện thời _objSnap.CurrentDockingContainer = td.Attributes["ID"].ToString(); string _strNewsRef = Request.QueryString["NewsRef"] == null ? "" : Request.QueryString["NewsRef"]; // Khai báo mẫu sử dụng của khung chứa Module // Mẫu phần trên của khung ModuleContainerTemplate _objHeaderTemplate = new ModuleContainerTemplate(ListItemType.Header, tab.reference, _objModuleDefinition.reference, _strNewsRef); _objHeaderTemplate.HeaderContent = _objModuleDefinition.title; _objHeaderTemplate.EditModuleControl = _objModuleHeaderExpanded; // Lưu tham chiếu đến điều khiển chứa mã tham chiếu của Khung tại máy trạm _arrAllSnapHeaderDrag.Add(_objHeaderTemplate._renderClientIDOfControlForDrag); _arrAllSnapHeaderExpand.Add(_objHeaderTemplate._renderClientIDOfControlForExpand); // Mẫu chứa phần trên của khung khi thu gọn ModuleContainerTemplate _objCollapsedHeaderTemplate = new ModuleContainerTemplate(ListItemType.EditItem, tab.reference, _objModuleDefinition.reference, _strNewsRef); _objCollapsedHeaderTemplate.HeaderContent = _objModuleDefinition.title; _objCollapsedHeaderTemplate.EditModuleControl = _objModuleHeaderCollapsed; // Lưu tham chiếu đến điều khiển chứa mã tham chiếu của Khung tại máy trạm _arrAllSnapHeaderCollapsedDrag.Add(_objCollapsedHeaderTemplate._renderClientIDOfCollapsedControlForDrag); _arrAllSnapHeaderCollapsedExpand.Add(_objCollapsedHeaderTemplate._renderClientIDOfCollapsedControlForExpand); // Mẫu của phần giữa khung ModuleContainerTemplate _objContentTemplate = new ModuleContainerTemplate(ListItemType.Item, tab.reference, _objModuleDefinition.reference, _strNewsRef); Literal lh = new Literal(); lh.Text = ""; lh.EnableViewState = false; _objContentTemplate.ChildControl = lh; // Mẫu phần dưới của khung ModuleContainerTemplate _objFooterTemplate = new ModuleContainerTemplate(ListItemType.Footer); // Đặt mẫu vào các vị trí tương ứng của khung _objSnap.HeaderTemplate = _objHeaderTemplate; _objSnap.CollapsedHeaderTemplate = _objCollapsedHeaderTemplate; _objSnap.ContentTemplate = _objContentTemplate; _objSnap.FooterTemplate = _objFooterTemplate; // Display Module td.Controls.Add(_objSnap); // Lưu tham chiếu đến khung để lấy mã tham chiếu tại máy trạm _arrAllSnap.Add(_objSnap); #endregion } else { if (_objModuleDefinition.CacheTime <= 0) { // Nếu Module không sử dụng Cache _objModuleControl = (Module)LoadModule(_strModuleSrc); // Khởi tạo nội dung Module _objModuleControl.InitModule(tab.reference, _objModuleDefinition.reference, _objModuleDefinition.type, Config.GetModuleVirtualPath(_objModuleDefinition.type), true); } else { // Nếu Module có sử dụng Cache _objCachedModuleControl = new CachedModule(); _objCachedModuleControl.ModuleCacheTime = _objModuleDefinition.CacheTime; // Khởi tạo nội dung Module _objCachedModuleControl.InitModule(tab.reference, _objModuleDefinition.reference, _objModuleDefinition.type, Config.GetModuleVirtualPath(_objModuleDefinition.type), true, _strModuleSrc); } if ((_objModuleControl != null && _objModuleControl.IsVisible() || (_objCachedModuleControl != null && _objCachedModuleControl.IsVisible()))) { // Hiển thị nội dung Module theo cách trình bày bình thường không hỗ trợ kéo thả HtmlTable _objSimpleModuleContainer = new HtmlTable(); _objSimpleModuleContainer.Width = "100%"; _objSimpleModuleContainer.CellPadding = 0; _objSimpleModuleContainer.CellSpacing = 0; _objSimpleModuleContainer.Rows.Add(new HtmlTableRow()); // Nạp dữ liệu của Module vào ô chứa Module HtmlTableCell _objCellContainer = new HtmlTableCell(); _objSimpleModuleContainer.Rows[0].Cells.Add(_objCellContainer); // _objCellContainer.Attributes.Add("class", "Module_Simple_Block"); if (_objModuleControl != null) { _objCellContainer.Controls.Add(_objModuleControl); } else { _objCellContainer.Controls.Add(_objCachedModuleControl); } //cách giữa header và body _objCellContainer.Attributes.Add("style", "padding-bottom:3px;"); td.Controls.Add(_objSimpleModuleContainer); } } } } } #endregion #endregion }
/// <exception cref="IOException"/> private static ModuleMetadata GetOrCreateModuleFromFile(string fullPath) { ModuleMetadata module = null; // may throw FileKey key = FileKey.Create(fullPath); CachedModule cachedModule; bool existingKey = s_modulesFromFiles.TryGetValue(key, out cachedModule); if (existingKey && cachedModule.Metadata.TryGetTarget(out module)) { return module; } // memory-map the module: module = ModuleMetadata.CreateFromFile(fullPath); // refresh the timestamp (the file may have changed just before we memory-mapped it): bool fault = true; try { key = FileKey.Create(fullPath); fault = false; } finally { if (fault) { module.Dispose(); } } cachedModule = new CachedModule(module); s_modulesFromFiles[key] = cachedModule; if (!existingKey) { s_moduleKeys.Add(key); EnableCompactTimer(); } return module; }