private void ProcessDownloaderGen(ContentGenRecipes oRecipes, string sContentUniqueId, string sContentHashCode) { string sNewGUID = Guid.NewGuid().ToString().ToUpper(); string sWorkingFolder = ContentWorkingPath + "\\" + sContentUniqueId; // Initialization DownloaderGenTask oDG = new DownloaderGenTask( sWorkingFolder, sNewGUID, sWorkingFolder + "\\" + sContentHashCode + TorrentExtension, "", // No Banner Replacement Support oRecipes.IconFile == "" ? "" : IconResPath + "\\" + oRecipes.IconFile, oRecipes.PromotionEventID, sContentHashCode + DownloaderExtension, oRecipes.DownloaderDisplayName, oRecipes.DownloaderHomeUrl, oRecipes.DisclaimerFile == "" ? "" : DisclaimerResPath + "\\" + oRecipes.DisclaimerFile, oRecipes.OnlineFaqUrl, oRecipes.GAProfileId, oRecipes.PromotionEventServerUrl, oRecipes.UPXCompression); // Generate the downloader accordingly oDG.Generate(); }
internal static string ReadContentRecipesJson(string sContentUniqueId, string sContentHashCode) { lock (sigLock) { string sContentRecipesJsonFile = ContentWorkingPath + "\\" + sContentUniqueId + "\\" + sContentHashCode + ContentRecipesFileExtension; if (File.Exists(sContentRecipesJsonFile)) { return(File.ReadAllText(sContentRecipesJsonFile)); } else { return(ContentGenRecipes.GetJson( new ContentGenRecipes() { AutoDeploy = true, UPXCompression = true } )); } } }
private static ContentGenRecipes GetContentRecipes(string sContentUniqueId, string sContentHashCode) { string sRecipesJson = ContentGenJob.ReadContentRecipesJson(sContentUniqueId, sContentHashCode); if (sRecipesJson != null) { return(ContentGenRecipes.FromJson(sRecipesJson)); } return(null); }
public void GenerateContentReq(string sContentUniqueId, string sContentGenRecipesJson) { lock (quartzScheduler) { // Create a ContentGenJob per Content if none has existed if (null == quartzScheduler.GetJobDetail( sContentUniqueId, ContentGenConstants.ContentGenGroupName)) { // Create a durable ContentGenJob and add to the scheduler JobDetail oJob = new JobDetail( sContentUniqueId, ContentGenConstants.ContentGenGroupName, typeof(ContentGenJob), false, true, false); oJob.JobDataMap[ContentGenJobDataMapConstants.OverallCompletion] = "0%"; quartzScheduler.AddJob(oJob, true); } // Create and initialize the trigger for the specific job request string sTriggerName = sContentUniqueId + " (" + quartzScheduler.GetTriggersOfJob( sContentUniqueId, ContentGenConstants.ContentGenGroupName).Count + ")"; Trigger oTrigger = new SimpleTrigger( sTriggerName, ContentGenConstants.ContentGenGroupName, // Compute a time that is on the next round minute TriggerUtils.GetNextGivenSecondDate(DateTime.UtcNow, 5)); // #################################################################### oTrigger.MisfireInstruction = MisfireInstruction.SimpleTrigger.FireNow; // #################################################################### oTrigger.JobName = sContentUniqueId; oTrigger.JobGroup = ContentGenConstants.ContentGenGroupName; ContentGenRecipes oJson = ContentGenRecipes.FromJson(sContentGenRecipesJson); oTrigger.JobDataMap[GeneralJobDataMapConstants.ContentUniqueId] = sContentUniqueId; oTrigger.JobDataMap[ContentGenJobDataMapConstants.ContentRecipesJson] = ContentGenRecipes.GetJson(oJson); quartzScheduler.ScheduleJob(oTrigger); } }
public void Execute(JobExecutionContext context) { string sContentHashCode = ""; ContentGenRecipes oContentRecipes; JobDataMap oJobDataMap = context.JobDetail.JobDataMap; string sContentUniqueId = (string)context.MergedJobDataMap[GeneralJobDataMapConstants.ContentUniqueId]; string sContentRecipesJson = (string)context.MergedJobDataMap[ContentGenJobDataMapConstants.ContentRecipesJson]; #region Content (Metafiles / Torrents) Generating (support for interruption) try { //============================================================================= log.InfoFormat(AppResource.StartJobExecution, typeof(ContentGenJob).Name); //============================================================================= // Validate the settings & the input data map parameters Check.IsNullOrEmpty(sContentUniqueId, GeneralJobDataMapConstants.ContentUniqueId); Check.IsNullOrEmpty(sContentRecipesJson, ContentGenJobDataMapConstants.ContentRecipesJson); // Check the existence of the content versioning file CheckAndCreateContentVersionFile(sContentUniqueId); // Deserialize Content Recipes from the input Json oContentRecipes = ContentGenRecipes.FromJson(sContentRecipesJson); if (oContentRecipes.ContentHashCode == null || oContentRecipes.ContentHashCode == "") { // Do the torrent generating process oJobDataMap[ContentGenJobDataMapConstants.OverallCompletion] = "0%"; ProcessTorrentGen( sContentUniqueId, oContentRecipes, (o, ev) => { // Update the overall completion rate of the job oJobDataMap[ContentGenJobDataMapConstants.OverallCompletion] = ev.OverallCompletion.ToString("#0.##\\%"); }, out sContentHashCode); } else { // Skip the torrent generating process oJobDataMap[ContentGenJobDataMapConstants.OverallCompletion] = "100%"; sContentHashCode = oContentRecipes.ContentHashCode; } // Update the content hash code to the job data map oJobDataMap[GeneralJobDataMapConstants.ContentHashCode] = sContentHashCode; //============================================================================= log.InfoFormat(AppResource.TaskExecutionDone, AppResource.MetafileGenTaskName); //============================================================================= } catch (Exception oEx) { Rollback(sContentUniqueId, sContentHashCode); //=================================================================================================== log.ErrorFormat(AppResource.JobExecutionFailed, oEx, typeof(ContentGenJob).Name, oEx.Message); //=================================================================================================== return; } #endregion #region Downloader Generating // The most brutal way to make sure of the job be executed synchronouly try { // Validate the settings & the input data map parameters Check.IsNullOrEmpty(sContentHashCode, GeneralJobDataMapConstants.ContentHashCode); lock (sigResUpdateLock) // To protect the global memory used in the ResourceLib { // Generate the downloader accordingly ProcessDownloaderGen(oContentRecipes, sContentUniqueId, sContentHashCode); } // Save the Content Recipes Json when downloader generating successfully Uri uri = new Uri(oContentRecipes.ContentSourceUrl); oContentRecipes.ContentFileName = Path.GetFileName(uri.LocalPath); // Get the file name oContentRecipes.ContentHashCode = sContentHashCode; oContentRecipes.CreateDateTime = DateTime.Now; SaveContentRecipesJson( sContentUniqueId, sContentHashCode, ContentGenRecipes.GetJson(oContentRecipes)); // Update the history file when downloader generating successfully AppendHistoryFile(ContentRecipesPropHistory.DownloaderDisplayName, sContentUniqueId, oContentRecipes.DownloaderDisplayName); AppendHistoryFile(ContentRecipesPropHistory.DownloaderHomeUrl, sContentUniqueId, oContentRecipes.DownloaderHomeUrl); AppendHistoryFile(ContentRecipesPropHistory.GAProfileId, sContentUniqueId, oContentRecipes.GAProfileId); AppendHistoryFile(ContentRecipesPropHistory.OnlineFaqUrl, sContentUniqueId, oContentRecipes.OnlineFaqUrl); AppendHistoryFile(ContentRecipesPropHistory.PromoEventId, sContentUniqueId, oContentRecipes.PromotionEventID); AppendHistoryFile(ContentRecipesPropHistory.PromoEventServerUrl, sContentUniqueId, oContentRecipes.PromotionEventServerUrl); //============================================================================= log.InfoFormat(AppResource.TaskExecutionDone, AppResource.DownloaderGenTaskName); //============================================================================= } catch (Exception oEx) { Rollback(sContentUniqueId, sContentHashCode); //=================================================================================================== log.ErrorFormat(AppResource.JobExecutionFailed, oEx, typeof(ContentGenJob).Name, oEx.Message); //=================================================================================================== return; } #endregion #region Content Deployment if specified // Do the content deployment if specified if (oContentRecipes.AutoDeploy) { try { // Validate the settings & the input data map parameters Check.IsNullOrEmpty(sContentHashCode, GeneralJobDataMapConstants.ContentHashCode); // The most brutal way to make sure of the job be executed synchronouly lock (sigResUpdateLock) { // Do the content deployment task ContentDeployJob.ProcessContentDeploy(sContentUniqueId, sContentHashCode); } //============================================================================= log.InfoFormat(AppResource.TaskExecutionDone, AppResource.MetafileDeployTaskName); //============================================================================= } catch (Exception oEx) { // Do nothing here so users can re-deploy again without re-generating all the files // And keep on the next task for the aforementioned reason. //=================================================================================================== log.ErrorFormat(AppResource.JobExecutionFailed, oEx, typeof(ContentGenJob).Name, oEx.Message); //=================================================================================================== } } #endregion #region Update Content Version File try { // Update the content versioning file in the very end of the job // to maintain the consistence as possible AppendContentVersionFile(sContentUniqueId, sContentHashCode); //============================================================================= log.InfoFormat(AppResource.EndJobExecution, typeof(ContentGenJob).Name); //============================================================================= } catch (Exception oEx) { // Clear up all the generated files & the deployed files since it should be a sever error! if (oContentRecipes.AutoDeploy) { ContentDeployJob.Rollback(sContentHashCode); } Rollback(sContentUniqueId, sContentHashCode); //=================================================================================================== log.ErrorFormat(AppResource.JobExecutionFailed, oEx, typeof(ContentGenJob).Name, oEx.Message); //=================================================================================================== return; } #endregion }
private void ProcessTorrentGen(string sContentUniqueId, ContentGenRecipes oRecipes, EventHandler <TorrentCreatorEventArgs> callbackHashed, out string sContentHashCode) { long lPieceLengthKB = AppConfig.ContentGenJob.PieceLengthKB; string sCreatedBy = AppConfig.ContentGenJob.CreatedBy; string sTrackerAnnounceUrl = AppConfig.ContentGenJob.TrackerAnnounceUrl; string sInternalTrackerAnnounceUrl = AppConfig.ContentGenJob.InternalTrackerAnnounceUrl; // Initialization _InterruptFlag = false; sContentHashCode = ""; // Initialize the torrent creation task MetafileGenTask oMG = new MetafileGenTask(); oMG.Hashed += callbackHashed; // Set the torrent info oMG.PieceLength = lPieceLengthKB * 1024; // Torrent info: PieceLength oMG.StoreMD5 = false; // Don't store MD5SUM in the torrent file oMG.Private = true; // Always be private torrent oMG.CreatedBy = sCreatedBy; // Torrent info: CreatedBy if (oRecipes.HttpSeedsUrl != null && oRecipes.HttpSeedsUrl.Length > 0) { List <string> listUrls = oRecipes.HttpSeedsUrlList; listUrls.ForEach(sUrl => { oMG.GetrightHttpSeeds.Add(sUrl); }); // URL seed } List <string> oAnn = new List <string>(); oAnn.Add(sTrackerAnnounceUrl); oMG.Announces.Add(oAnn); // Torrent Info: Tracker Server // Assign the custom fields to the "info" section of the torrent oMG.AddCustomSecure("ga account name", new BEncodedString(oRecipes.GAProfileId)); oMG.AddCustomSecure("ga host name", new BEncodedString("http://www.gamania.com")); oMG.AddCustomSecure("custom display name", new BEncodedString(oRecipes.DownloaderDisplayName)); // Begin the async torrent creation process IAsyncResult asyncResult = oMG.BeginCreate( oRecipes.ContentSourceUrl, // Content Source URL null, // No callback needed oRecipes.ContentSourceUrl // Async state ); // Wait for the completion or the aborting if (!asyncResult.IsCompleted) { while (!asyncResult.AsyncWaitHandle.WaitOne(1000)) { if (_InterruptFlag) { oMG.AbortCreation(); // Try to abort the task } } } // End of the async torre creation BEncodedDictionary oTorrentBenDict = oMG.EndCreate(asyncResult); // Get the content hash code from the torrent file sContentHashCode = Torrent.Load(oTorrentBenDict).InfoHash.ToHex(); lock (sigLock) { // ========= Save 3 types of torrent files for 3 different usages ============== // 1. Save the torrent file which contains the public tracker announce URL File.WriteAllBytes( ContentWorkingPath + "\\" + sContentUniqueId + "\\" + sContentHashCode + TorrentExtension, oTorrentBenDict.Encode()); // 2. Save the VIP torrent file contains the public tracker announce URL if (oRecipes.VipHttpSeedsUrl != null && oRecipes.VipHttpSeedsUrl.Length > 0) { // Add more Url Seed Urls List <string> listUrls = oRecipes.VipHttpSeedsUrlList; listUrls.ForEach(sUrl => { oMG.GetrightHttpSeeds.Add(sUrl); }); // Add more URL seed // Convert to Ben-Encoded List BEncodedList listUrlSeeds = new BEncodedList(); listUrlSeeds.AddRange(oMG.GetrightHttpSeeds.ConvertAll <BEncodedValue>(s => { return((BEncodedString)s); })); oTorrentBenDict[TorrentInfoUrlListKey] = listUrlSeeds; } // Save the VIP Torrent file File.WriteAllBytes( ContentWorkingPath + "\\" + sContentUniqueId + "\\" + sContentHashCode + TorrentVipExtension, oTorrentBenDict.Encode()); // 3. Save the FQDN torrent file which contains the internal tracker announce URL // First, add the content source URL to the torrent to accelerate the download speed if (-1 == oRecipes.HttpSeedsUrlList.FindIndex(x => { return(x.Equals(oRecipes.ContentSourceUrl)); }) && -1 == oRecipes.VipHttpSeedsUrlList.FindIndex(x => { return(x.Equals(oRecipes.ContentSourceUrl)); })) { // Add the content source URL to the TorrentInfoUrlListKey // together with the VIP URL seeds just added previously oMG.GetrightHttpSeeds.Add(oRecipes.ContentSourceUrl); // Convert to Ben-Encoded List BEncodedList listUrlSeeds = new BEncodedList(); listUrlSeeds.AddRange(oMG.GetrightHttpSeeds.ConvertAll <BEncodedValue>(s => { return((BEncodedString)s); })); oTorrentBenDict[TorrentInfoUrlListKey] = listUrlSeeds; } // Second, replace the tracker announce URL with the internal tracker announce URL oTorrentBenDict[TorrentInfoAnnounceKey] = new BEncodedString(sInternalTrackerAnnounceUrl); // Save the FQDN Torrent file File.WriteAllBytes( ContentWorkingPath + "\\" + sContentUniqueId + "\\" + sContentHashCode + TorrentFqdnExtension, oTorrentBenDict.Encode()); } }
private static string ProcessContentMonitor(List <string> listVersion, JobExecutionContext context) { JobDataMap oJobDataMap = context.JobDetail.JobDataMap; string[] listSeedWebIP = AppConfig.ContentDeployJob.OfficalSeedWebIPList; ContentDetail oContentDetail = new ContentDetail(); // Construct the hierarchy per the Version list & registered Seed Web IP list first oContentDetail.Name = context.JobDetail.Name; oContentDetail.DateCreated = GetContentCreateDate(context.JobDetail.Name); foreach (string sVer in listVersion) { VersionDetail oVerDetail = new VersionDetail(); ContentGenRecipes oContentRecipes = GetContentRecipes(oContentDetail.Name, sVer); if (oContentRecipes != null) { oVerDetail.Name = oContentRecipes.ContentFileName; oVerDetail.DateCreated = oContentRecipes.CreateDateTime; } else { oVerDetail.Name = ""; oVerDetail.DateCreated = DateTime.MaxValue; } oVerDetail.Hash = sVer; oVerDetail.DeployToTracker = QueryTrackerTorrentDeploymentStatus(sVer); oContentDetail.Versions.Add(oVerDetail); foreach (string sIP in listSeedWebIP) { TorrentSeedDetail oDetail = new TorrentSeedDetail(); // Create the TorrentSeedDetail first with the unknown status // And replace the unkown status with the real status parsed from JSON later oDetail.IP = sIP; oDetail.Hash = oVerDetail.Hash.ToUpper(); oDetail.Name = ""; oDetail.TotalSize = 0; oDetail.PartDone = 0f; oDetail.StatusCode = TorrentStatus.Unknown; oDetail.DatePublished = DateTime.MaxValue; oDetail.Error = AppResource.SeedWebConnectionFailed; oVerDetail.TorrentSeeds.Add(oDetail); } } // Enumerate all the registered seed web IP for walking through all the seed monitors foreach (string sIP in listSeedWebIP) { JobDetail oSeedJob = context.Scheduler.GetJobDetail( sIP, SeedMonitorConstants.SeedMonitorGroupName); // Check to see if the seed monitor job exists if (oSeedJob != null) { string sTorrentDetails = (string)oSeedJob.JobDataMap[SeedMonitorJobDataMapConstants.TorrentDetails]; // Check to see if the seed monitor has torrent detail JSON ready if (sTorrentDetails != null) { List <TorrentDetail> listTorrentDetail = JsonConvert.DeserializeObject <List <TorrentDetail> >(sTorrentDetails); List <string> listTorrentInSeed = new List <string>(); // Enumerate all the TorrentDetail to update to the pre-created TorrentSeedDetail foreach (TorrentDetail oTorrentDetail in listTorrentDetail) { TorrentSeedDetail oDetail = new TorrentSeedDetail(); oDetail.IP = sIP; oDetail.Hash = oTorrentDetail.UniqueID.ToUpper(); oDetail.Name = oTorrentDetail.Name; oDetail.TotalSize = oTorrentDetail.TotalSize; oDetail.PartDone = oTorrentDetail.PartDone; oDetail.StatusCode = oTorrentDetail.StatusCode; oDetail.DatePublished = oTorrentDetail.DateAdded; oDetail.Error = oTorrentDetail.Error; // Use the TorrentSeedDetail object to update the corresponding list // in the VersionDetails list so the JSON just needs to be parsed just once UpdateTorrentSeedDetail(oContentDetail, oDetail); // Add the torrent hash for later use of checking the exclusion of the torrents listTorrentInSeed.Add(oDetail.Hash); } // Update TorrentSeedDetail not found in the seed's torrent list to "content not deployed" error foreach (VersionDetail oVersion in oContentDetail.Versions.FindAll (x => { return(!listTorrentInSeed.Contains(x.Hash)); })) { TorrentSeedDetail oTorrentSeed = oVersion.TorrentSeeds.Find(x => { return(x.IP == sIP); }); if (oTorrentSeed != null) { oTorrentSeed.Error = AppResource.ContentNotDeployToSeed; } } } } } // Serialize the content detail to JSON and return return(JsonConvert.SerializeObject(oContentDetail)); }