├── .gitattributes ├── .gitignore ├── LICENSE ├── Master.proj ├── MongoDB.Messaging.sln ├── README.md ├── Samples ├── QueueBrowser │ ├── App_Start │ │ ├── BundleConfig.cs │ │ ├── FilterConfig.cs │ │ ├── RouteConfig.cs │ │ └── WebApiConfig.cs │ ├── Content │ │ ├── alert.css │ │ ├── angular-toastr.css │ │ ├── badge.css │ │ ├── bootstrap-dialog.css │ │ ├── bootstrap-theme.css │ │ ├── bootstrap.css │ │ ├── images │ │ │ └── alert.png │ │ ├── metric.css │ │ ├── site.css │ │ └── ui-bootstrap-csp.css │ ├── Controllers │ │ ├── HomeController.cs │ │ ├── LoggingController.cs │ │ └── QueueController.cs │ ├── Global.asax │ ├── Global.asax.cs │ ├── Models │ │ ├── AlertModel.cs │ │ ├── AlertTypes.cs │ │ ├── LogError.cs │ │ ├── LogEvent.cs │ │ ├── NameValueModel.cs │ │ ├── QueueActionModel.cs │ │ ├── QueueMessageModel.cs │ │ └── QueueStatusModel.cs │ ├── NLog.config │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── Query │ │ ├── QueryExtensions.cs │ │ ├── QueryOptions.cs │ │ ├── QueryOptionsBuilder.cs │ │ ├── QueryRequest.cs │ │ └── QueryResult.cs │ ├── QueueBrowser.csproj │ ├── Repositories │ │ ├── LoggingRepository.cs │ │ └── QueueRepository.cs │ ├── Scripts │ │ ├── _references.js │ │ ├── angular-animate.js │ │ ├── angular-messages.js │ │ ├── angular-mocks.js │ │ ├── angular-moment.js │ │ ├── angular-route.js │ │ ├── angular-sanitize.js │ │ ├── angular-signalr-hub.js │ │ ├── angular-toastr.js │ │ ├── angular-toastr.tpls.js │ │ ├── angular-ui │ │ │ ├── ui-bootstrap-tpls.js │ │ │ └── ui-bootstrap.js │ │ ├── angular.js │ │ ├── bootstrap-dialog.js │ │ ├── bootstrap.js │ │ ├── jquery-2.2.3.js │ │ ├── jquery.signalR-2.2.1.js │ │ ├── lodash.js │ │ ├── modernizr-2.8.3.js │ │ ├── moment.js │ │ └── typings │ │ │ ├── angular-toastr │ │ │ └── angular-toastr.d.ts │ │ │ ├── angular-ui-bootstrap │ │ │ └── angular-ui-bootstrap.d.ts │ │ │ ├── angularjs │ │ │ ├── angular-animate.d.ts │ │ │ ├── angular-component-router.d.ts │ │ │ ├── angular-cookies.d.ts │ │ │ ├── angular-mocks.d.ts │ │ │ ├── angular-resource.d.ts │ │ │ ├── angular-route.d.ts │ │ │ ├── angular-sanitize.d.ts │ │ │ └── angular.d.ts │ │ │ ├── bootstrap-dialog │ │ │ └── bootstrap-dialog.d.ts │ │ │ ├── bootstrap │ │ │ └── bootstrap.d.ts │ │ │ ├── jquery │ │ │ └── jquery.d.ts │ │ │ ├── lodash │ │ │ └── lodash.d.ts │ │ │ ├── moment │ │ │ └── moment.d.ts │ │ │ └── signalr │ │ │ └── signalr.d.ts │ ├── Services │ │ ├── LoggingController.cs │ │ └── QueueController.cs │ ├── Startup.cs │ ├── Views │ │ ├── Home │ │ │ └── Index.cshtml │ │ ├── Logging │ │ │ └── Index.cshtml │ │ ├── Queue │ │ │ └── Index.cshtml │ │ ├── Shared │ │ │ ├── Error.cshtml │ │ │ └── _Layout.cshtml │ │ ├── Web.config │ │ └── _ViewStart.cshtml │ ├── Web.config │ ├── app │ │ ├── .gitignore │ │ ├── _ref.ts │ │ ├── app.ts │ │ ├── logging │ │ │ └── LoggingController.ts │ │ ├── models │ │ │ ├── AlertOptions.ts │ │ │ ├── ChangeNotification.ts │ │ │ ├── LogError.ts │ │ │ ├── LogEvent.ts │ │ │ ├── NameValueModel.ts │ │ │ ├── QueryRequest.ts │ │ │ ├── QueryyResult.ts │ │ │ ├── QueueActionModel.ts │ │ │ ├── QueueMessageModel.ts │ │ │ └── QueueStatusModel.ts │ │ ├── queue │ │ │ └── QueueBrowserController.ts │ │ └── services │ │ │ ├── Logger.ts │ │ │ ├── LoggingRepository.ts │ │ │ ├── NotificationService.ts │ │ │ └── QueueRepository.ts │ ├── favicon.ico │ ├── fonts │ │ ├── glyphicons-halflings-regular.eot │ │ ├── glyphicons-halflings-regular.svg │ │ ├── glyphicons-halflings-regular.ttf │ │ ├── glyphicons-halflings-regular.woff │ │ └── glyphicons-halflings-regular.woff2 │ └── packages.config ├── Sleep.Client │ ├── App.config │ ├── EchoOptions.cs │ ├── Logging │ │ └── NLogWriter.cs │ ├── NLog.config │ ├── NativeMethods.cs │ ├── Program.cs │ ├── QuitOptions.cs │ ├── Sleep.Client.csproj │ └── SleepOptions.cs ├── Sleep.Messages │ ├── EchoMessage.cs │ ├── Sleep.Messages.csproj │ └── SleepMessage.cs └── Sleep.Service │ ├── App.config │ ├── EchoHandler.cs │ ├── Logging │ └── NLogWriter.cs │ ├── NLog.config │ ├── Program.cs │ ├── Sleep.Service.csproj │ └── SleepHandler.cs ├── appveyor.yml ├── bootstrap.cmd ├── global.json ├── src ├── GlobalAssemblyInfo.cs ├── MongoDB.Messaging.SignalR │ ├── ChangeNotification.cs │ ├── ChangeNotificationHandler.cs │ ├── ChangeNotificationHub.cs │ ├── ChangeNotificationService.cs │ ├── IChangeNotificationClient.cs │ └── MongoDB.Messaging.SignalR.csproj └── MongoDB.Messaging │ ├── Change │ ├── ChangeNotifier.cs │ ├── ChangeRecord.cs │ ├── IHandleChange.cs │ ├── ISubscription.cs │ └── Subscription.cs │ ├── Configuration │ ├── IQueueConfiguration.cs │ ├── IQueueContainer.cs │ ├── IQueueManager.cs │ ├── QueueConfiguration.cs │ ├── QueueContainer.cs │ └── QueueManager.cs │ ├── Extensions │ ├── DateTimeExtensions.cs │ ├── StringExtensions.cs │ └── TextEnumerator.cs │ ├── Fluent │ ├── MessageBuilderBase.cs │ ├── PublishQueueBuilder.cs │ ├── QueueConfigurationBase.cs │ ├── QueueConfigurationBuilder.cs │ ├── QueueManagerBase.cs │ ├── QueueManagerBuilder.cs │ ├── QueueNameBuilder.cs │ ├── ScheduleQueueBuilder.cs │ ├── SubscriberBuilder.cs │ └── SubscriberQueueBuilder.cs │ ├── Locks │ ├── DistributedLock.cs │ ├── ILockManager.cs │ ├── LockData.cs │ ├── LockManager.cs │ └── ThrottleLock.cs │ ├── Logging │ ├── AsynchronousContext.cs │ ├── DelegateLogWriter.cs │ ├── DisposeAction.cs │ ├── ILogBuilder.cs │ ├── ILogWriter.cs │ ├── ILogger.cs │ ├── IPropertyContext.cs │ ├── LogBuilder.cs │ ├── LogData.cs │ ├── LogLevel.cs │ ├── Logger.cs │ ├── LoggerCreateBuilder.cs │ ├── LoggerExtensions.cs │ ├── LoggerFactory.cs │ ├── ObjectPool.cs │ ├── PropertyContext.cs │ └── TraceLogWriter.cs │ ├── Message.cs │ ├── MessagePriority.cs │ ├── MessageQueue.cs │ ├── MessageResult.cs │ ├── MessageState.cs │ ├── MongoDB.Messaging.csproj │ ├── Service │ ├── HealthWorker.cs │ ├── IMessageProcessor.cs │ ├── IMessageService.cs │ ├── IMessageWorker.cs │ ├── MessageProcessor.cs │ ├── MessageService.cs │ ├── MessageWorker.cs │ └── MessageWorkerBase.cs │ ├── Storage │ ├── IQueueRepository.cs │ ├── MongoFactory.cs │ └── QueueRepository.cs │ ├── Subscription │ ├── IMessageRetry.cs │ ├── IMessageSubscriber.cs │ ├── MessageRetry.cs │ └── ProcessContext.cs │ └── TimeoutPolicy.cs └── test └── MongoDB.Messaging.Tests ├── App.config ├── Configuration └── QueueManagerTest.cs ├── Extensions └── DateTimeExtensionsTests.cs ├── Locks ├── DistributedLockTests.cs └── ThrottleLockTests.cs ├── Logging └── NLogWriter.cs ├── MessageQueueTest.cs ├── Messages └── UserMessage.cs ├── MongoDB.Messaging.Tests.csproj ├── NLog.config ├── Storage └── QueueRepositoryTest.cs └── Subscription └── MessageHandler.cs /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | 3 | *.doc diff=astextplain 4 | *.DOC diff=astextplain 5 | *.docx diff=astextplain 6 | *.DOCX diff=astextplain 7 | *.dot diff=astextplain 8 | *.DOT diff=astextplain 9 | *.pdf diff=astextplain 10 | *.PDF diff=astextplain 11 | *.rtf diff=astextplain 12 | *.RTF diff=astextplain 13 | 14 | *.bmp binary 15 | *.gif binary 16 | *.jpg binary 17 | *.png binary 18 | 19 | *.ascx text 20 | *.cmd text 21 | *.coffee text 22 | *.config text 23 | *.cs text diff=csharp 24 | *.csproj text merge=union 25 | *.css text 26 | *.cshtml text 27 | *.htm text 28 | *.html text 29 | *.htm text 30 | *.js text 31 | *.msbuild text 32 | *.resx text merge=union 33 | *.ruleset text 34 | *.Stylecop text 35 | *.sql text 36 | *.targets text 37 | *.tt text 38 | *.txt text 39 | *.vb text 40 | *.vbhtml text 41 | *.vbproj text merge=union 42 | *.xml text 43 | *.xunit text 44 | 45 | *.sln text eol=crlf merge=union 46 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Build Folders (you can keep bin if you'd like, to store dlls and pdbs) 2 | [Bb]in/ 3 | [Oo]bj/ 4 | 5 | # mstest test results 6 | TestResults 7 | 8 | ## Ignore Visual Studio temporary files, build results, and 9 | ## files generated by popular Visual Studio add-ons. 10 | 11 | # User-specific files 12 | *.suo 13 | *.user 14 | *.sln.docstates 15 | 16 | # Build results 17 | [Dd]ebug/ 18 | [Rr]elease/ 19 | x64/ 20 | *_i.c 21 | *_p.c 22 | *.ilk 23 | *.meta 24 | *.obj 25 | *.pch 26 | *.pdb 27 | *.pgc 28 | *.pgd 29 | *.rsp 30 | *.sbr 31 | *.tlb 32 | *.tli 33 | *.tlh 34 | *.tmp 35 | *.log 36 | *.vspscc 37 | *.vssscc 38 | .builds 39 | 40 | # Visual C++ cache files 41 | ipch/ 42 | *.aps 43 | *.ncb 44 | *.opensdf 45 | *.sdf 46 | 47 | # Visual Studio profiler 48 | *.psess 49 | *.vsp 50 | *.vspx 51 | 52 | # Guidance Automation Toolkit 53 | *.gpState 54 | 55 | # ReSharper is a .NET coding add-in 56 | _ReSharper* 57 | 58 | # NCrunch 59 | *.ncrunch* 60 | .*crunch*.local.xml 61 | 62 | # Installshield output folder 63 | [Ee]xpress 64 | 65 | # DocProject is a documentation generator add-in 66 | DocProject/buildhelp/ 67 | DocProject/Help/*.HxT 68 | DocProject/Help/*.HxC 69 | DocProject/Help/*.hhc 70 | DocProject/Help/*.hhk 71 | DocProject/Help/*.hhp 72 | DocProject/Help/Html2 73 | DocProject/Help/html 74 | 75 | # Click-Once directory 76 | publish 77 | 78 | # Publish Web Output 79 | *.Publish.xml 80 | 81 | # NuGet Packages Directory 82 | packages 83 | 84 | # Windows Azure Build Output 85 | csx 86 | *.build.csdef 87 | 88 | # Windows Store app package directory 89 | AppPackages/ 90 | 91 | # Others 92 | [Bb]in 93 | [Oo]bj 94 | sql 95 | TestResults 96 | [Tt]est[Rr]esult* 97 | *.Cache 98 | ClientBin 99 | [Ss]tyle[Cc]op.* 100 | ~$* 101 | *.dbmdl 102 | Generated_Code #added for RIA/Silverlight projects 103 | 104 | # Backup & report files from converting an old project file to a newer 105 | # Visual Studio version. Backup files are not needed, because we have git ;-) 106 | _UpgradeReport_Files/ 107 | Backup*/ 108 | UpgradeLog*.XML 109 | /Build 110 | /build.txt 111 | /Tools 112 | *.GhostDoc.xml 113 | .vs/config 114 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 LoreSoft 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Samples/QueueBrowser/App_Start/BundleConfig.cs: -------------------------------------------------------------------------------- 1 | using System.Web; 2 | using System.Web.Optimization; 3 | 4 | namespace QueueBrowser 5 | { 6 | public class BundleConfig 7 | { 8 | public static void RegisterBundles(BundleCollection bundles) 9 | { 10 | bundles.Add(new StyleBundle("~/content/css") 11 | .Include( 12 | "~/Content/bootstrap.css", 13 | "~/Content/bootstrap-theme.css", 14 | 15 | "~/Content/angular-toastr.css", 16 | "~/Content/bootstrap-dialog.css", 17 | 18 | "~/Content/alert.css", 19 | "~/Content/badge.css", 20 | "~/Content/metric.css", 21 | 22 | "~/Content/site.css" 23 | ) 24 | ); 25 | 26 | bundles.Add(new ScriptBundle("~/bundles/modernizr") 27 | .Include( 28 | "~/Scripts/modernizr-{version}.js" 29 | ) 30 | ); 31 | 32 | bundles.Add(new ScriptBundle("~/bundles/scripts") 33 | .Include( 34 | "~/Scripts/jquery-{version}.js", 35 | 36 | /* angular */ 37 | "~/Scripts/angular.js", 38 | "~/Scripts/angular-animate.js", 39 | "~/Scripts/angular-messages.js", 40 | "~/Scripts/angular-route.js", 41 | "~/Scripts/angular-sanitize.js", 42 | /* bootstrap */ 43 | "~/Scripts/bootstrap.js", 44 | 45 | /* other */ 46 | "~/Scripts/lodash.js", 47 | "~/Scripts/jquery.signalR-{version}.js", 48 | "~/Scripts/angular-signalr-hub.js", 49 | "~/Scripts/moment.js", 50 | "~/Scripts/angular-moment.js", 51 | "~/Scripts/bootstrap-dialog.js", 52 | "~/Scripts/angular-toastr.tpls.js", 53 | "~/Scripts/angular-ui/ui-bootstrap-tpls.js" 54 | ) 55 | ); 56 | 57 | bundles.Add(new ScriptBundle("~/bundles/app") 58 | 59 | .Include("~/app/app.js") 60 | 61 | .IncludeDirectory("~/app/models/", "*.js") 62 | .IncludeDirectory("~/app/services/", "*.js") 63 | 64 | .IncludeDirectory("~/app/queue/", "*.js") 65 | .IncludeDirectory("~/app/logging/", "*.js") 66 | ); 67 | 68 | #if !DEBUG 69 | BundleTable.EnableOptimizations = true; 70 | #endif 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /Samples/QueueBrowser/App_Start/FilterConfig.cs: -------------------------------------------------------------------------------- 1 | using System.Web; 2 | using System.Web.Mvc; 3 | 4 | namespace QueueBrowser 5 | { 6 | public class FilterConfig 7 | { 8 | public static void RegisterGlobalFilters(GlobalFilterCollection filters) 9 | { 10 | filters.Add(new HandleErrorAttribute()); 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Samples/QueueBrowser/App_Start/RouteConfig.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Web; 5 | using System.Web.Mvc; 6 | using System.Web.Routing; 7 | 8 | namespace QueueBrowser 9 | { 10 | public class RouteConfig 11 | { 12 | public static void RegisterRoutes(RouteCollection routes) 13 | { 14 | routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); 15 | 16 | routes.MapRoute( 17 | name: "Default", 18 | url: "{controller}/{action}/{id}", 19 | defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } 20 | ); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Samples/QueueBrowser/App_Start/WebApiConfig.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Web.Http; 5 | 6 | namespace QueueBrowser 7 | { 8 | public static class WebApiConfig 9 | { 10 | public static void Register(HttpConfiguration config) 11 | { 12 | // Web API configuration and services 13 | 14 | // Web API routes 15 | config.MapHttpAttributeRoutes(); 16 | 17 | config.Routes.MapHttpRoute( 18 | name: "DefaultApi", 19 | routeTemplate: "api/{controller}/{id}", 20 | defaults: new { id = RouteParameter.Optional } 21 | ); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Samples/QueueBrowser/Content/alert.css: -------------------------------------------------------------------------------- 1 | /* alert icon sprites */ 2 | .Alert { 3 | background-image: url('images/alert.png'); 4 | background-color: transparent; 5 | background-repeat: no-repeat; 6 | display: inline-block; 7 | height: 16px; 8 | line-height: 16px; 9 | width: 16px; 10 | vertical-align: text-top; 11 | margin-right: 3px; 12 | } 13 | 14 | .Error, .Fatal { 15 | background-position: 0px -64px; 16 | } 17 | .Help { 18 | background-position: 0px -48px; 19 | } 20 | 21 | .Info, .Debug, .Trace { 22 | background-position: 0px -32px; 23 | } 24 | 25 | .Success { 26 | background-position: 0px -16px; 27 | } 28 | 29 | .Warn { 30 | background-position: 0px 0px; 31 | } 32 | -------------------------------------------------------------------------------- /Samples/QueueBrowser/Content/badge.css: -------------------------------------------------------------------------------- 1 | /* badge styles*/ 2 | .badge-primary { 3 | background-color: #428bca; 4 | } 5 | 6 | .badge-primary[href]:hover, 7 | .badge-primary[href]:focus { 8 | background-color: #3071a9; 9 | } 10 | 11 | .badge-success { 12 | background-color: #5cb85c; 13 | } 14 | 15 | .badge-success[href]:hover, 16 | .badge-success[href]:focus { 17 | background-color: #449d44; 18 | } 19 | 20 | .badge-info { 21 | background-color: #5bc0de; 22 | } 23 | 24 | .badge-info[href]:hover, 25 | .badge-info[href]:focus { 26 | background-color: #31b0d5; 27 | } 28 | 29 | .badge-warning { 30 | background-color: #f0ad4e; 31 | } 32 | 33 | .badge-warning[href]:hover, 34 | .badge-warning[href]:focus { 35 | background-color: #ec971f; 36 | } 37 | 38 | .badge-danger { 39 | background-color: #d9534f; 40 | } 41 | 42 | .badge-danger[href]:hover, 43 | .badge-danger[href]:focus { 44 | background-color: #c9302c; 45 | } 46 | -------------------------------------------------------------------------------- /Samples/QueueBrowser/Content/bootstrap-dialog.css: -------------------------------------------------------------------------------- 1 | .bootstrap-dialog { 2 | 3 | } 4 | .bootstrap-dialog .modal-header { 5 | border-top-left-radius: 4px; 6 | border-top-right-radius: 4px; 7 | } 8 | .bootstrap-dialog .bootstrap-dialog-title { 9 | color: #fff; 10 | display: inline-block; 11 | } 12 | .bootstrap-dialog.type-default .bootstrap-dialog-title { 13 | color: #333; 14 | } 15 | .bootstrap-dialog .bootstrap-dialog-title { 16 | font-size: 16px; 17 | } 18 | .bootstrap-dialog.size-large .bootstrap-dialog-title { 19 | font-size: 24px; 20 | } 21 | .bootstrap-dialog .bootstrap-dialog-close-button { 22 | float: right; 23 | filter:alpha(opacity=90); 24 | -moz-opacity:0.9; 25 | -khtml-opacity: 0.9; 26 | opacity: 0.9; 27 | } 28 | .bootstrap-dialog .bootstrap-dialog-close-button { 29 | font-size: 20px; 30 | } 31 | .bootstrap-dialog.size-large .bootstrap-dialog-close-button { 32 | font-size: 30px; 33 | } 34 | .bootstrap-dialog .bootstrap-dialog-close-button:hover { 35 | cursor: pointer; 36 | filter: alpha(opacity=100); 37 | -moz-opacity: 1; 38 | -khtml-opacity: 1; 39 | opacity: 1; 40 | } 41 | .bootstrap-dialog .bootstrap-dialog-message { 42 | font-size: 14px; 43 | } 44 | .bootstrap-dialog.size-large .bootstrap-dialog-message { 45 | font-size: 18px; 46 | } 47 | .bootstrap-dialog.type-default .modal-header { 48 | background-color: #fff; 49 | } 50 | .bootstrap-dialog.type-info .modal-header { 51 | background-color: #5bc0de; 52 | } 53 | .bootstrap-dialog.type-primary .modal-header { 54 | background-color: #428bca; 55 | } 56 | .bootstrap-dialog.type-success .modal-header { 57 | background-color: #5cb85c; 58 | } 59 | .bootstrap-dialog.type-warning .modal-header { 60 | background-color: #f0ad4e; 61 | } 62 | .bootstrap-dialog.type-danger .modal-header { 63 | background-color: #d9534f; 64 | } 65 | .bootstrap-dialog .bootstrap-dialog-button-icon { 66 | margin-right: 3px; 67 | } 68 | 69 | /** 70 | * Icon animation 71 | * Copied from font-awesome: http://fontawesome.io/ 72 | **/ 73 | .icon-spin { 74 | display: inline-block; 75 | -moz-animation: spin 2s infinite linear; 76 | -o-animation: spin 2s infinite linear; 77 | -webkit-animation: spin 2s infinite linear; 78 | animation: spin 2s infinite linear; 79 | } 80 | @-moz-keyframes spin { 81 | 0% { 82 | -moz-transform: rotate(0deg); 83 | } 84 | 100% { 85 | -moz-transform: rotate(359deg); 86 | } 87 | } 88 | @-webkit-keyframes spin { 89 | 0% { 90 | -webkit-transform: rotate(0deg); 91 | } 92 | 100% { 93 | -webkit-transform: rotate(359deg); 94 | } 95 | } 96 | @-o-keyframes spin { 97 | 0% { 98 | -o-transform: rotate(0deg); 99 | } 100 | 100% { 101 | -o-transform: rotate(359deg); 102 | } 103 | } 104 | @-ms-keyframes spin { 105 | 0% { 106 | -ms-transform: rotate(0deg); 107 | } 108 | 100% { 109 | -ms-transform: rotate(359deg); 110 | } 111 | } 112 | @keyframes spin { 113 | 0% { 114 | transform: rotate(0deg); 115 | } 116 | 100% { 117 | transform: rotate(359deg); 118 | } 119 | } 120 | /** End of icon animation **/ -------------------------------------------------------------------------------- /Samples/QueueBrowser/Content/images/alert.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loresoft/MongoDB.Messaging/7e8210d7ea61d2c6f48fda7c9645604d27b9dcb6/Samples/QueueBrowser/Content/images/alert.png -------------------------------------------------------------------------------- /Samples/QueueBrowser/Content/metric.css: -------------------------------------------------------------------------------- 1 | div.metric-status { 2 | display: inline-block; 3 | padding: 4px 12px; 4 | margin-bottom: 0; 5 | font-size: 14px; 6 | line-height: 20px; 7 | color: #333333; 8 | text-align: center; 9 | text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75); 10 | vertical-align: middle; 11 | } 12 | 13 | span.metric { 14 | display: inline-block; 15 | min-width: 10px; 16 | padding: 2px 6px; 17 | font-size: 12px; 18 | line-height: 1; 19 | text-align: center; 20 | white-space: nowrap; 21 | vertical-align: baseline; 22 | background-color: transparent; 23 | border-radius: 10px; 24 | border: solid 1px; 25 | -webkit-transition: color .1s ease-out, background .1s ease-out, border .1s ease-out; 26 | -moz-transition: color .1s ease-out, background .1s ease-out, border .1s ease-out; 27 | -ms-transition: color .1s ease-out, background .1s ease-out, border .1s ease-out; 28 | -o-transition: color .1s ease-out, background .1s ease-out, border .1s ease-out; 29 | transition: color .1s ease-out, background .1s ease-out, border .1s ease-out; 30 | } 31 | 32 | span.metric.highlighted { 33 | font-weight: bold; 34 | color: #fff !important; 35 | } 36 | 37 | span.metric-default { 38 | color: #777; 39 | border-color: #777; 40 | } 41 | 42 | span.metric-default.highlighted { 43 | background-color: #777; 44 | } 45 | 46 | div.metric { 47 | border: solid 1px transparent; 48 | border-radius: 4px; 49 | -webkit-box-shadow: 0 1px 1px rgba(0,0,0,.05); 50 | box-shadow: 0 1px 1px rgba(0,0,0,.05); 51 | margin-bottom: 20px; 52 | transition: color .1s ease-out, background .1s ease-out, border .1s ease-out; 53 | } 54 | 55 | div.metric .metric-body { 56 | padding: 15px 15px 0; 57 | font-size: 26px; 58 | text-align: center; 59 | } 60 | 61 | div.metric .metric-description { 62 | padding: 0 15px 15px; 63 | text-align: center; 64 | } 65 | 66 | div.metric.metric-default { 67 | border-color: #ddd; 68 | } 69 | 70 | div.metric-info, 71 | span.metric-info { 72 | color: #31b0d5; 73 | border-color: #31b0d5; 74 | } 75 | 76 | span.metric-info.highlighted { 77 | background-color: #31b0d5; 78 | } 79 | 80 | div.metric-warning, 81 | span.metric-warning { 82 | color: #f0ad4e; 83 | border-color: #f0ad4e; 84 | } 85 | 86 | span.metric-warning.highlighted { 87 | background-color: #f0ad4e; 88 | } 89 | 90 | div.metric-success, 91 | span.metric-success { 92 | color: #5cb85c; 93 | border-color: #5cb85c; 94 | } 95 | 96 | span.metric-success.highlighted { 97 | background-color: #5cb85c; 98 | } 99 | 100 | div.metric-danger, 101 | span.metric-danger { 102 | color: #d9534f; 103 | border-color: #d9534f; 104 | } 105 | 106 | span.metric-danger.highlighted { 107 | background-color: #d9534f; 108 | } 109 | 110 | span.metric-null, 111 | div.metric-null { 112 | display: none; 113 | } 114 | -------------------------------------------------------------------------------- /Samples/QueueBrowser/Content/site.css: -------------------------------------------------------------------------------- 1 | body { 2 | padding-top: 60px; 3 | } 4 | 5 | 6 | footer, #footer { 7 | color: #999; 8 | text-align: center; 9 | line-height: normal; 10 | margin: 0 0 1em 0; 11 | font-size: .9em; 12 | } 13 | 14 | #section-main { 15 | min-height: 300px; 16 | } 17 | 18 | .carousel, .nav, .pagination, .panel-title a { 19 | cursor: pointer; 20 | } 21 | 22 | 23 | .tab-container .tab-content { 24 | padding: 15px; 25 | background-color: #fff; 26 | border: 1px solid #d5d5d5; 27 | border-top-width: 0; 28 | border-radius: 0 0 5px 5px; 29 | } 30 | 31 | .nav-tabs { 32 | border-color: #d5d5d5; 33 | } 34 | 35 | .nopadding { 36 | padding: 0 !important; 37 | } 38 | .nomargin { 39 | margin: 0 !important; 40 | } 41 | 42 | .panel-heading > .btn-group, 43 | .panel-heading > .input-group, 44 | .panel-heading > .filter-group { 45 | margin-top: -5px; 46 | margin-bottom: -5px; 47 | margin-left: 10px; 48 | } 49 | 50 | .panel-heading > .fa, 51 | .panel-icon { 52 | margin-right: 5px; 53 | } 54 | 55 | /* prevent wrap */ 56 | .nowrap { 57 | -ms-text-overflow: ellipsis !important; 58 | -o-text-overflow: ellipsis !important; 59 | -moz-text-overflow: ellipsis !important; 60 | text-overflow: ellipsis !important; 61 | white-space: nowrap !important; 62 | overflow: hidden !important; 63 | } 64 | 65 | select.no-style { 66 | -webkit-appearance: none; 67 | -moz-appearance: none; 68 | text-indent: 0.01px; 69 | -moz-text-overflow: ''; 70 | text-overflow: ''; 71 | padding-right: 12px !important; 72 | background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAAJ1BMVEUAAACIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIgln7UqAAAADHRSTlMAWYsN8/rWqkAwIxUw2c66AAAAJ0lEQVQI12MgEQgKChqAGTpnjkEY7GciIVJcPgpQRSoGUMYOBlIBAHo+BQDbgp9PAAAAAElFTkSuQmCC'); 73 | background-repeat: no-repeat; 74 | background-position: right; 75 | } 76 | 77 | select::-ms-expand { 78 | width: 12px; 79 | border: none; 80 | background: #fff; 81 | display: none; 82 | } 83 | 84 | [ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak { 85 | display: none !important; 86 | } 87 | 88 | .panel-footer > .pagination { 89 | margin: 0; 90 | } 91 | 92 | .table-property > tbody > tr > th { 93 | background-color: #f9f9f9; 94 | text-align: right; 95 | } 96 | 97 | .table > thead > tr > th > a, 98 | .table > thead > tr > th > a:link, 99 | .table > thead > tr > th > a:visited, 100 | .table > thead > tr > th > a:hover { 101 | cursor: pointer; 102 | color: #333; 103 | text-decoration: none; 104 | } 105 | 106 | .edit-row > td { 107 | padding: 0 !important; 108 | vertical-align: middle; 109 | } 110 | 111 | .edit-row .form-control { 112 | padding-right: 6px; 113 | padding-left: 6px; 114 | border-color: transparent; 115 | -ms-border-radius: 0; 116 | border-radius: 0; 117 | -webkit-box-shadow: none; 118 | -ms-box-shadow: none; 119 | box-shadow: none; 120 | } 121 | 122 | .edit-row .form-control:focus { 123 | border-color: #66afe9; 124 | -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075) inset, 0 0 8px rgba(102, 175, 233, 0.6); 125 | -ms-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075) inset, 0 0 8px rgba(102, 175, 233, 0.6); 126 | box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075) inset, 0 0 8px rgba(102, 175, 233, 0.6); 127 | outline: 0 none; 128 | } 129 | 130 | .edit-row .form-control-static { 131 | padding: 6px 12px; 132 | } 133 | -------------------------------------------------------------------------------- /Samples/QueueBrowser/Controllers/HomeController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Web.Mvc; 3 | 4 | namespace QueueBrowser.Controllers 5 | { 6 | public class HomeController : Controller 7 | { 8 | public ActionResult Index() 9 | { 10 | return View(); 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Samples/QueueBrowser/Controllers/LoggingController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Web.Mvc; 3 | 4 | namespace QueueBrowser.Controllers 5 | { 6 | public class LoggingController : Controller 7 | { 8 | public ActionResult Index() 9 | { 10 | return View(); 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Samples/QueueBrowser/Controllers/QueueController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Web.Mvc; 3 | 4 | namespace QueueBrowser.Controllers 5 | { 6 | public class QueueController : Controller 7 | { 8 | public ActionResult Index() 9 | { 10 | return View(); 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /Samples/QueueBrowser/Global.asax: -------------------------------------------------------------------------------- 1 | <%@ Application Codebehind="Global.asax.cs" Inherits="QueueBrowser.WebApiApplication" Language="C#" %> 2 | -------------------------------------------------------------------------------- /Samples/QueueBrowser/Global.asax.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Web; 5 | using System.Web.Http; 6 | using System.Web.Mvc; 7 | using System.Web.Optimization; 8 | using System.Web.Routing; 9 | using MongoDB.Messaging; 10 | using MongoDB.Messaging.SignalR; 11 | 12 | namespace QueueBrowser 13 | { 14 | public class WebApiApplication : System.Web.HttpApplication 15 | { 16 | private static readonly Lazy _changeService; 17 | 18 | static WebApiApplication() 19 | { 20 | _changeService = new Lazy(() => new ChangeNotificationService("MongoMessaging", "Messaging.*")); 21 | } 22 | 23 | 24 | protected void Application_Start() 25 | { 26 | AreaRegistration.RegisterAllAreas(); 27 | GlobalConfiguration.Configure(WebApiConfig.Register); 28 | FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); 29 | RouteConfig.RegisterRoutes(RouteTable.Routes); 30 | BundleConfig.RegisterBundles(BundleTable.Bundles); 31 | 32 | // config message queue 33 | MessageQueue.Default.Configure(c => c 34 | .Connection("MongoMessaging") 35 | ); 36 | 37 | // start broadcasting changes 38 | _changeService.Value.Start(); 39 | } 40 | 41 | 42 | protected void Application_Stop() 43 | { 44 | _changeService.Value.Stop(); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Samples/QueueBrowser/Models/AlertModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Newtonsoft.Json; 3 | using Newtonsoft.Json.Converters; 4 | 5 | namespace QueueBrowser.Models 6 | { 7 | [Serializable] 8 | [JsonObject(MemberSerialization = MemberSerialization.OptIn)] 9 | public class AlertModel 10 | { 11 | public const int SuccessTimeout = 8000; 12 | public const int ErrorTimeout = 20000; 13 | 14 | public const string DataKey = "Novus.Alert"; 15 | 16 | [JsonProperty(PropertyName = "type", DefaultValueHandling = DefaultValueHandling.Include)] 17 | [JsonConverter(typeof(StringEnumConverter))] 18 | public AlertTypes Type { get; set; } 19 | 20 | [JsonProperty(PropertyName = "title", NullValueHandling = NullValueHandling.Ignore)] 21 | public string Title { get; set; } 22 | 23 | [JsonProperty(PropertyName = "message", NullValueHandling = NullValueHandling.Ignore)] 24 | public string Message { get; set; } 25 | 26 | [JsonProperty(PropertyName = "timeOut")] 27 | public int Timeout { get; set; } 28 | 29 | public string ToJson() 30 | { 31 | string json = JsonConvert.SerializeObject(this, Formatting.None); 32 | return json; 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /Samples/QueueBrowser/Models/AlertTypes.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace QueueBrowser.Models 4 | { 5 | public enum AlertTypes 6 | { 7 | success, 8 | info, 9 | warn, 10 | error 11 | } 12 | } -------------------------------------------------------------------------------- /Samples/QueueBrowser/Models/LogError.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using MongoDB.Bson.Serialization.Attributes; 3 | 4 | namespace QueueBrowser.Models 5 | { 6 | [BsonIgnoreExtraElements(true, Inherited = true)] 7 | public class LogError 8 | { 9 | public string Message { get; set; } 10 | 11 | public string BaseMessage { get; set; } 12 | 13 | public string Text { get; set; } 14 | 15 | public string Type { get; set; } 16 | 17 | public string Source { get; set; } 18 | 19 | public string MethodName { get; set; } 20 | 21 | public string ModuleName { get; set; } 22 | 23 | public string ModuleVersion { get; set; } 24 | 25 | public int? ErrorCode { get; set; } 26 | } 27 | } -------------------------------------------------------------------------------- /Samples/QueueBrowser/Models/LogEvent.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using MongoDB.Bson; 4 | using MongoDB.Bson.Serialization.Attributes; 5 | using MongoDB.Bson.Serialization.IdGenerators; 6 | 7 | namespace QueueBrowser.Models 8 | { 9 | [BsonIgnoreExtraElements(true, Inherited = true)] 10 | public class LogEvent 11 | { 12 | public LogEvent() 13 | { 14 | Properties = new Dictionary(); 15 | } 16 | 17 | [BsonId(IdGenerator = typeof(StringObjectIdGenerator))] 18 | [BsonRepresentation(BsonType.ObjectId)] 19 | public string Id { get; set; } 20 | 21 | [BsonDateTimeOptions(Kind = DateTimeKind.Local)] 22 | public DateTime Date { get; set; } 23 | 24 | public string Level { get; set; } 25 | 26 | public string Logger { get; set; } 27 | 28 | public string Message { get; set; } 29 | 30 | [BsonIgnoreIfNull] 31 | public string Source { get; set; } 32 | 33 | [BsonIgnoreIfNull] 34 | public string Correlation { get; set; } 35 | 36 | [BsonIgnoreIfNull] 37 | public LogError Exception { get; set; } 38 | 39 | public Dictionary Properties { get; set; } 40 | 41 | public bool ShouldSerializeProperties() 42 | { 43 | return Properties != null && Properties.Count > 0; 44 | } 45 | } 46 | } -------------------------------------------------------------------------------- /Samples/QueueBrowser/Models/NameValueModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace QueueBrowser.Models 4 | { 5 | public class NameValueModel 6 | { 7 | public string Name { get; set; } 8 | public string Value { get; set; } 9 | } 10 | } -------------------------------------------------------------------------------- /Samples/QueueBrowser/Models/QueueActionModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace QueueBrowser.Models 5 | { 6 | public class QueueActionModel 7 | { 8 | public QueueActionModel() 9 | { 10 | Ids = new List(); 11 | } 12 | 13 | public string Name { get; set; } 14 | 15 | public List Ids { get; set; } 16 | } 17 | } -------------------------------------------------------------------------------- /Samples/QueueBrowser/Models/QueueMessageModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using MongoDB.Messaging; 3 | using Newtonsoft.Json; 4 | using Newtonsoft.Json.Converters; 5 | 6 | namespace QueueBrowser.Models 7 | { 8 | public class QueueMessageModel 9 | { 10 | public string Id { get; set; } 11 | 12 | public string Name { get; set; } 13 | 14 | public string Description { get; set; } 15 | 16 | public string Correlation { get; set; } 17 | 18 | [JsonConverter(typeof(StringEnumConverter))] 19 | public MessageState State { get; set; } 20 | 21 | [JsonConverter(typeof(StringEnumConverter))] 22 | public MessageResult Result { get; set; } 23 | 24 | public string ResponseQueue { get; set; } 25 | 26 | public int? Step { get; set; } 27 | 28 | public string Status { get; set; } 29 | 30 | public int Priority { get; set; } 31 | 32 | public int RetryCount { get; set; } 33 | 34 | public int ErrorCount { get; set; } 35 | 36 | public DateTime? Scheduled { get; set; } 37 | 38 | public DateTime? StartTime { get; set; } 39 | 40 | public DateTime? EndTime { get; set; } 41 | 42 | public DateTime? Expire { get; set; } 43 | 44 | public string UserName { get; set; } 45 | 46 | public DateTime Created { get; set; } 47 | 48 | public DateTime Updated { get; set; } 49 | } 50 | } -------------------------------------------------------------------------------- /Samples/QueueBrowser/Models/QueueStatusModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using MongoDB.Driver; 3 | 4 | namespace QueueBrowser.Models 5 | { 6 | public class QueueStatusModel 7 | { 8 | public string Name { get; set; } 9 | 10 | public string Namespace { get; set; } 11 | 12 | public long Queued { get; set; } 13 | public long Processing { get; set; } 14 | public long Complete { get; set; } 15 | public long Timeout { get; set; } 16 | public long Scheduled { get; set; } 17 | 18 | public long Successful { get; set; } 19 | public long Warning { get; set; } 20 | public long Error { get; set; } 21 | } 22 | } -------------------------------------------------------------------------------- /Samples/QueueBrowser/NLog.config: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 23 | 24 | 25 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /Samples/QueueBrowser/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | [assembly: AssemblyTitle("QueueBrowser")] 6 | [assembly: AssemblyDescription("")] 7 | [assembly: AssemblyConfiguration("")] 8 | [assembly: AssemblyCompany("")] 9 | [assembly: AssemblyProduct("QueueBrowser")] 10 | [assembly: AssemblyCopyright("Copyright © 2016")] 11 | [assembly: AssemblyTrademark("")] 12 | [assembly: AssemblyCulture("")] 13 | [assembly: ComVisible(false)] 14 | [assembly: Guid("a6a491b2-427c-4b2d-8139-a0ecf71f49ee")] 15 | [assembly: AssemblyVersion("1.0.0.0")] 16 | [assembly: AssemblyFileVersion("1.0.0.0")] 17 | -------------------------------------------------------------------------------- /Samples/QueueBrowser/Query/QueryOptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq.Expressions; 3 | 4 | namespace QueueBrowser.Query 5 | { 6 | public class QueryOptions 7 | { 8 | public int Page { get; set; } 9 | 10 | public int PageSize { get; set; } 11 | 12 | public string Sort { get; set; } 13 | 14 | public bool Descending { get; set; } 15 | 16 | public string Filter { get; set; } 17 | 18 | public Expression> Selector { get; set; } 19 | } 20 | } -------------------------------------------------------------------------------- /Samples/QueueBrowser/Query/QueryOptionsBuilder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq.Expressions; 3 | 4 | namespace QueueBrowser.Query 5 | { 6 | public class QueryOptionsBuilder 7 | { 8 | private readonly QueryOptions _queryOptions; 9 | 10 | public QueryOptions QueryOptions 11 | { 12 | get { return _queryOptions; } 13 | } 14 | 15 | public QueryOptionsBuilder(QueryOptions queryOptions) 16 | { 17 | _queryOptions = queryOptions; 18 | } 19 | 20 | public QueryOptionsBuilder Request(QueryRequest request) 21 | { 22 | if (request == null) 23 | throw new ArgumentNullException("request"); 24 | 25 | _queryOptions.Page = request.Page; 26 | _queryOptions.PageSize = request.PageSize; 27 | _queryOptions.Sort = request.Sort; 28 | _queryOptions.Descending = request.Descending; 29 | _queryOptions.Filter = request.Filter; 30 | 31 | return this; 32 | } 33 | 34 | public QueryOptionsBuilder Page(int page) 35 | { 36 | _queryOptions.Page = page; 37 | return this; 38 | } 39 | 40 | public QueryOptionsBuilder PageSize(int pageSize) 41 | { 42 | _queryOptions.PageSize = pageSize; 43 | return this; 44 | } 45 | 46 | public QueryOptionsBuilder Sort(string sortField) 47 | { 48 | _queryOptions.Sort = sortField; 49 | return this; 50 | } 51 | 52 | public QueryOptionsBuilder Filter(string filter) 53 | { 54 | _queryOptions.Filter = filter; 55 | return this; 56 | } 57 | 58 | public QueryOptionsBuilder Descending(bool value = true) 59 | { 60 | _queryOptions.Descending = value; 61 | return this; 62 | } 63 | 64 | public QueryOptionsBuilder Selector(Expression> selector) 65 | { 66 | if (selector == null) 67 | throw new ArgumentNullException("selector"); 68 | 69 | _queryOptions.Selector = selector; 70 | return this; 71 | } 72 | 73 | 74 | } 75 | } -------------------------------------------------------------------------------- /Samples/QueueBrowser/Query/QueryRequest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace QueueBrowser.Query 4 | { 5 | public class QueryRequest 6 | { 7 | public int Page { get; set; } 8 | 9 | public int PageSize { get; set; } 10 | 11 | public string Sort { get; set; } 12 | 13 | public bool Descending { get; set; } 14 | 15 | public string Filter { get; set; } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Samples/QueueBrowser/Query/QueryResult.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace QueueBrowser.Query 5 | { 6 | public class QueryResult 7 | { 8 | public IEnumerable Data { get; set; } 9 | 10 | public int Page { get; set; } 11 | 12 | public int PageSize { get; set; } 13 | 14 | public int PageCount { get; set; } 15 | 16 | 17 | public string Sort { get; set; } 18 | 19 | public bool Descending { get; set; } 20 | 21 | 22 | public string Filter { get; set; } 23 | 24 | 25 | public int Total { get; set; } 26 | } 27 | } -------------------------------------------------------------------------------- /Samples/QueueBrowser/Repositories/LoggingRepository.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Configuration; 3 | using MongoDB.Driver; 4 | using MongoDB.Messaging.Storage; 5 | using QueueBrowser.Models; 6 | using QueueBrowser.Query; 7 | 8 | namespace QueueBrowser.Repositories 9 | { 10 | public class LoggingRepository 11 | { 12 | private readonly Lazy> _collection; 13 | 14 | public LoggingRepository() 15 | { 16 | _collection = new Lazy>(CreateCollection); 17 | } 18 | 19 | public QueryResult GetLogs(int? page = null, int? pageSize = null, string sort = null, bool? descending = null, string filter = null) 20 | { 21 | var result = _collection.Value.AsQueryable() 22 | .ToDataResult(config => config 23 | .Page(page ?? 1) 24 | .PageSize(pageSize ?? 50) 25 | .Sort(sort ?? "Date") 26 | .Descending(descending ?? true) 27 | .Filter(filter) 28 | ); 29 | 30 | return result; 31 | } 32 | 33 | 34 | private IMongoCollection CreateCollection() 35 | { 36 | string collectionName = ConfigurationManager.AppSettings["LoggingCollectionName"]; 37 | if (string.IsNullOrEmpty(collectionName)) 38 | collectionName = "Logging"; 39 | 40 | var database = MongoFactory.GetDatabaseFromConnectionName("LoggingConnection"); 41 | 42 | var mongoCollection = database.GetCollection(collectionName); 43 | 44 | mongoCollection.Indexes.CreateOneAsync(Builders.IndexKeys.Descending(s => s.Date)); 45 | mongoCollection.Indexes.CreateOneAsync(Builders.IndexKeys.Ascending(s => s.Level)); 46 | mongoCollection.Indexes.CreateOneAsync(Builders.IndexKeys.Ascending(s => s.Source)); 47 | mongoCollection.Indexes.CreateOneAsync(Builders.IndexKeys.Ascending(s => s.Correlation)); 48 | 49 | return mongoCollection; 50 | } 51 | } 52 | } -------------------------------------------------------------------------------- /Samples/QueueBrowser/Scripts/_references.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loresoft/MongoDB.Messaging/7e8210d7ea61d2c6f48fda7c9645604d27b9dcb6/Samples/QueueBrowser/Scripts/_references.js -------------------------------------------------------------------------------- /Samples/QueueBrowser/Scripts/angular-signalr-hub.js: -------------------------------------------------------------------------------- 1 | angular.module('SignalR', []) 2 | .constant('$', window.jQuery) 3 | .factory('Hub', ['$', function ($) { 4 | //This will allow same connection to be used for all Hubs 5 | //It also keeps connection as singleton. 6 | var globalConnections = []; 7 | 8 | function initNewConnection(options) { 9 | var connection = null; 10 | if (options && options.rootPath) { 11 | connection = $.hubConnection(options.rootPath, { useDefaultPath: false }); 12 | } else { 13 | connection = $.hubConnection(); 14 | } 15 | 16 | connection.logging = (options && options.logging ? true : false); 17 | return connection; 18 | } 19 | 20 | function getConnection(options) { 21 | var useSharedConnection = !(options && options.useSharedConnection === false); 22 | if (useSharedConnection) { 23 | return typeof globalConnections[options.rootPath] === 'undefined' ? 24 | globalConnections[options.rootPath] = initNewConnection(options) : 25 | globalConnections[options.rootPath]; 26 | } 27 | else { 28 | return initNewConnection(options); 29 | } 30 | } 31 | 32 | return function (hubName, options) { 33 | var Hub = this; 34 | 35 | Hub.connection = getConnection(options); 36 | Hub.proxy = Hub.connection.createHubProxy(hubName); 37 | 38 | Hub.on = function (event, fn) { 39 | Hub.proxy.on(event, fn); 40 | }; 41 | Hub.invoke = function (method, args) { 42 | return Hub.proxy.invoke.apply(Hub.proxy, arguments) 43 | }; 44 | Hub.disconnect = function () { 45 | Hub.connection.stop(); 46 | }; 47 | Hub.connect = function (queryParams) { 48 | var startOptions = {}; 49 | if (options.transport) startOptions.transport = options.transport; 50 | if (options.jsonp) startOptions.jsonp = options.jsonp; 51 | if (angular.isDefined(options.withCredentials)) startOptions.withCredentials = options.withCredentials; 52 | if(queryParams) Hub.connection.qs = queryParams; 53 | return Hub.connection.start(startOptions); 54 | }; 55 | 56 | if (options && options.listeners) { 57 | Object.getOwnPropertyNames(options.listeners) 58 | .filter(function (propName) { 59 | return typeof options.listeners[propName] === 'function';}) 60 | .forEach(function (propName) { 61 | Hub.on(propName, options.listeners[propName]); 62 | }); 63 | } 64 | if (options && options.methods) { 65 | angular.forEach(options.methods, function (method) { 66 | Hub[method] = function () { 67 | var args = $.makeArray(arguments); 68 | args.unshift(method); 69 | return Hub.invoke.apply(Hub, args); 70 | }; 71 | }); 72 | } 73 | if (options && options.queryParams) { 74 | Hub.connection.qs = options.queryParams; 75 | } 76 | if (options && options.errorHandler) { 77 | Hub.connection.error(options.errorHandler); 78 | } 79 | if (options && options.stateChanged) { 80 | Hub.connection.stateChanged(options.stateChanged); 81 | } 82 | 83 | //Adding additional property of promise allows to access it in rest of the application. 84 | if(options.autoConnect === undefined || options.autoConnect){ 85 | Hub.promise = Hub.connect(); 86 | } 87 | 88 | return Hub; 89 | }; 90 | }]); 91 | 92 | // Common.js package manager support (e.g. ComponentJS, WebPack) 93 | if (typeof module !== 'undefined' && typeof exports !== 'undefined' && module.exports === exports) { 94 | module.exports = 'SignalR'; 95 | } 96 | -------------------------------------------------------------------------------- /Samples/QueueBrowser/Scripts/typings/angularjs/angular-cookies.d.ts: -------------------------------------------------------------------------------- 1 | // Type definitions for Angular JS 1.4 (ngCookies module) 2 | // Project: http://angularjs.org 3 | // Definitions by: Diego Vilar , Anthony Ciccarello 4 | // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped 5 | 6 | 7 | /// 8 | 9 | declare module "angular-cookies" { 10 | var _: string; 11 | export = _; 12 | } 13 | 14 | /** 15 | * ngCookies module (angular-cookies.js) 16 | */ 17 | declare namespace angular.cookies { 18 | 19 | /** 20 | * Cookies options 21 | * see https://docs.angularjs.org/api/ngCookies/provider/$cookiesProvider#defaults 22 | */ 23 | interface ICookiesOptions { 24 | /** 25 | * The cookie will be available only for this path and its sub-paths. 26 | * By default, this would be the URL that appears in your base tag. 27 | */ 28 | path?: string; 29 | /** 30 | * The cookie will be available only for this domain and its sub-domains. 31 | * For obvious security reasons the user agent will not accept the cookie if the 32 | * current domain is not a sub domain or equals to the requested domain. 33 | */ 34 | domain?: string; 35 | /** 36 | * String of the form "Wdy, DD Mon YYYY HH:MM:SS GMT" or a Date object 37 | * indicating the exact date/time this cookie will expire. 38 | */ 39 | expires?: string|Date; 40 | /** 41 | * The cookie will be available only in secured connection. 42 | */ 43 | secure?: boolean; 44 | } 45 | 46 | /** 47 | * CookieService 48 | * see http://docs.angularjs.org/api/ngCookies.$cookies 49 | */ 50 | interface ICookiesService { 51 | [index: string]: any; 52 | } 53 | 54 | /** 55 | * CookieStoreService 56 | * see http://docs.angularjs.org/api/ngCookies.$cookieStore 57 | */ 58 | interface ICookiesService { 59 | get(key: string): string; 60 | getObject(key: string): any; 61 | getObject(key: string): T; 62 | getAll(): any; 63 | put(key: string, value: string, options?: ICookiesOptions): void; 64 | putObject(key: string, value: any, options?: ICookiesOptions): void; 65 | remove(key: string, options?: ICookiesOptions): void; 66 | } 67 | 68 | /** 69 | * CookieStoreService DEPRECATED 70 | * see https://code.angularjs.org/1.2.26/docs/api/ngCookies/service/$cookieStore 71 | */ 72 | interface ICookieStoreService { 73 | /** 74 | * Returns the value of given cookie key 75 | * @param key Id to use for lookup 76 | */ 77 | get(key: string): any; 78 | /** 79 | * Sets a value for given cookie key 80 | * @param key Id for the value 81 | * @param value Value to be stored 82 | */ 83 | put(key: string, value: any): void; 84 | /** 85 | * Remove given cookie 86 | * @param key Id of the key-value pair to delete 87 | */ 88 | remove(key: string): void; 89 | } 90 | 91 | } 92 | -------------------------------------------------------------------------------- /Samples/QueueBrowser/Scripts/typings/angularjs/angular-sanitize.d.ts: -------------------------------------------------------------------------------- 1 | // Type definitions for Angular JS 1.3 (ngSanitize module) 2 | // Project: http://angularjs.org 3 | // Definitions by: Diego Vilar 4 | // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped 5 | 6 | 7 | /// 8 | 9 | declare module "angular-sanitize" { 10 | var _: string; 11 | export = _; 12 | } 13 | 14 | /////////////////////////////////////////////////////////////////////////////// 15 | // ngSanitize module (angular-sanitize.js) 16 | /////////////////////////////////////////////////////////////////////////////// 17 | declare namespace angular.sanitize { 18 | 19 | /////////////////////////////////////////////////////////////////////////// 20 | // SanitizeService 21 | // see http://docs.angularjs.org/api/ngSanitize.$sanitize 22 | /////////////////////////////////////////////////////////////////////////// 23 | interface ISanitizeService { 24 | (html: string): string; 25 | } 26 | 27 | /////////////////////////////////////////////////////////////////////////// 28 | // Filters included with the ngSanitize 29 | // see https://github.com/angular/angular.js/tree/v1.2.0/src/ngSanitize/filter 30 | /////////////////////////////////////////////////////////////////////////// 31 | export module filter { 32 | /** 33 | * Finds links in text input and turns them into html links. Supports http/https/ftp/mailto and plain email address links. 34 | * @param text Input text. 35 | * @param target ILinkyTargetType Window (_blank|_self|_parent|_top) or named frame to open links in. 36 | * @param attributes Add custom attributes to the link element. 37 | * @return Html-linkified and sanitized text. 38 | * see https://docs.angularjs.org/api/ngSanitize/filter/linky 39 | */ 40 | interface ILinky { 41 | (text: string, target: string, attributes?: { [attribute: string]: string } | ((url: string) => { [attribute: string]: string })): string; 42 | } 43 | 44 | } 45 | } 46 | /////////////////////////////////////////////////////////////////////////////// 47 | // Extend angular $filter declarations to include filters from angular.sanitize module 48 | /////////////////////////////////////////////////////////////////////////////// 49 | declare namespace angular { 50 | interface IFilterService { 51 | (name: 'linky'): angular.sanitize.filter.ILinky; 52 | } 53 | } -------------------------------------------------------------------------------- /Samples/QueueBrowser/Scripts/typings/bootstrap-dialog/bootstrap-dialog.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | declare var BootstrapDialog: IBootstrapDialog; 4 | 5 | interface IBootstrapDialog { 6 | /** For text localization. */ 7 | DEFAULT_TEXTS: string[]; 8 | BUTTON_SIZES: string[]; 9 | METHODS_TO_OVERRIDE: string[]; 10 | 11 | TYPE_DEFAULT: string; 12 | TYPE_INFO: string; 13 | TYPE_PRIMARY: string; 14 | TYPE_SUCCESS: string; 15 | TYPE_WARNING: string; 16 | TYPE_DANGER: string; 17 | 18 | (options: IBootstrapDialogOptions): IBootstrapDialogContext; 19 | alert(message: string, closeCallback?: () => void): void; 20 | confirm(message: string, closeCallback?: (result: boolean) => void): void; 21 | show(options: IBootstrapDialogOptions): IBootstrapDialogInstance; 22 | } 23 | 24 | interface IBootstrapDialogOptions { 25 | /** Dialog header type. See BootstrapDialog.TYPE_xxx constants. */ 26 | type: string; 27 | /** Text size. See BootstrapDialog.SIZE_xxx constants. By default - SIZE_NORMAL */ 28 | size: string; 29 | /** Dialog title. Either string or JQuery element. */ 30 | title: string|JQuery; 31 | /** Dialog message. Either string or JQuery element. */ 32 | message: string|JQuery; 33 | /** FALSE by default. */ 34 | closable: boolean; 35 | /** Whether dialog will close by clicking outside of it. */ 36 | closeByBackdrop: boolean; 37 | /** Whether dialog will close by ESC. */ 38 | closeByKeyboard: boolean; 39 | /** Whether fade-out background while showing the dialog. TRUE by default. */ 40 | animate: boolean; 41 | /** Whether dialog could be dragged by its header. Cursor could be changed (see doc)! FALSE by default. */ 42 | draggable: boolean; 43 | description: string; 44 | /** Default button title. OK by default. */ 45 | buttonLabel: string; 46 | buttons: IBootstrapDialogButton[]; 47 | /** Result will be true if button was click, while it will be false if users close the dialog directly. */ 48 | callback: (result: boolean) => void; 49 | onshow(dialog?: IBootstrapDialogContext): void; 50 | onshown(dialog?: IBootstrapDialogContext): void; 51 | /** Return FALSE to don`t close the dialog. Don`t return anything by default. */ 52 | onhide(dialog?: IBootstrapDialogContext): any; 53 | onhidden(dialog?: IBootstrapDialogContext): void; 54 | 55 | /** 'Cancel' by default. */ 56 | btnCancelLabel: string; 57 | /** 'OK' by default. */ 58 | btnOKLabel: string; 59 | /** If you didn't specify it, dialog type will be used. */ 60 | btnOKClass: string; 61 | } 62 | 63 | interface IBootstrapDialogInstance { 64 | $modal: JQuery; 65 | $modalBody: JQuery; 66 | $modalContent: JQuery; 67 | $modalDialog: JQuery; 68 | $modalHeader: JQuery; 69 | $modalFooter: JQuery; 70 | options: IBootstrapDialogOptions; 71 | opened: boolean; 72 | } 73 | 74 | interface IBootstrapDialogButton { 75 | id: string; 76 | label: string; 77 | /** Hotkey char code */ 78 | hotkey: number; 79 | icon: string; 80 | cssClass: string; 81 | autospin: boolean; 82 | action: (dialog: IBootstrapDialogContext) => void; 83 | } 84 | 85 | interface IBootstrapDialogContext { 86 | open(): void; 87 | close(): void; 88 | realize(): void; 89 | setTitle(title: string): void; 90 | setMessage(message: string): void; 91 | setData(dataName: string, value: any): void; 92 | getData(dataName: string): any; 93 | getButton(buttonId: string): JQuery; 94 | setClosable(closable: boolean): void; 95 | /** See BootstrapDialog.TYPE_xxx constants. */ 96 | setType(dialogType: string): void; 97 | /** Enable or disable all dialog`s buttons at once. */ 98 | enableButtons(enable: boolean): void; 99 | getModalHeader(): any; 100 | getModalFooter(): any; 101 | getModalBody(): JQuery; 102 | } -------------------------------------------------------------------------------- /Samples/QueueBrowser/Scripts/typings/bootstrap/bootstrap.d.ts: -------------------------------------------------------------------------------- 1 | // Type definitions for Bootstrap 3.3.5 2 | // Project: http://twitter.github.com/bootstrap/ 3 | // Definitions by: Boris Yankov 4 | // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped 5 | 6 | 7 | /// 8 | 9 | interface ModalOptions { 10 | backdrop?: boolean|string; 11 | keyboard?: boolean; 12 | show?: boolean; 13 | remote?: string; 14 | } 15 | 16 | interface ModalOptionsBackdropString { 17 | backdrop?: string; // for "static" 18 | keyboard?: boolean; 19 | show?: boolean; 20 | remote?: string; 21 | } 22 | 23 | interface ScrollSpyOptions { 24 | offset?: number; 25 | target?: string; 26 | } 27 | 28 | interface TooltipOptions { 29 | animation?: boolean; 30 | html?: boolean; 31 | placement?: string | Function; 32 | selector?: string; 33 | title?: string | Function; 34 | trigger?: string; 35 | template?: string; 36 | delay?: number | Object; 37 | container?: string | boolean; 38 | viewport?: string | Function | Object; 39 | } 40 | 41 | interface PopoverOptions { 42 | animation?: boolean; 43 | html?: boolean; 44 | placement?: string | Function; 45 | selector?: string; 46 | trigger?: string; 47 | title?: string | Function; 48 | template?: string; 49 | content?: any; 50 | delay?: number | Object; 51 | container?: string | boolean; 52 | viewport?: string | Function | Object; 53 | } 54 | 55 | interface CollapseOptions { 56 | parent?: any; 57 | toggle?: boolean; 58 | } 59 | 60 | interface CarouselOptions { 61 | interval?: number; 62 | pause?: string; 63 | wrap?: boolean; 64 | keybord?: boolean; 65 | } 66 | 67 | interface TypeaheadOptions { 68 | source?: any; 69 | items?: number; 70 | minLength?: number; 71 | matcher?: (item: any) => boolean; 72 | sorter?: (items: any[]) => any[]; 73 | updater?: (item: any) => any; 74 | highlighter?: (item: any) => string; 75 | } 76 | 77 | interface AffixOptions { 78 | offset?: number | Function | Object; 79 | target?: any; 80 | } 81 | 82 | interface TransitionEventNames { 83 | end: string; 84 | } 85 | 86 | interface JQuery { 87 | modal(options?: ModalOptions): JQuery; 88 | modal(options?: ModalOptionsBackdropString): JQuery; 89 | modal(command: string): JQuery; 90 | 91 | dropdown(): JQuery; 92 | dropdown(command: string): JQuery; 93 | 94 | scrollspy(command: string): JQuery; 95 | scrollspy(options?: ScrollSpyOptions): JQuery; 96 | 97 | tab(): JQuery; 98 | tab(command: string): JQuery; 99 | 100 | tooltip(options?: TooltipOptions): JQuery; 101 | tooltip(command: string): JQuery; 102 | 103 | popover(options?: PopoverOptions): JQuery; 104 | popover(command: string): JQuery; 105 | 106 | alert(): JQuery; 107 | alert(command: string): JQuery; 108 | 109 | button(): JQuery; 110 | button(command: string): JQuery; 111 | 112 | collapse(options?: CollapseOptions): JQuery; 113 | collapse(command: string): JQuery; 114 | 115 | carousel(options?: CarouselOptions): JQuery; 116 | carousel(command: string): JQuery; 117 | 118 | typeahead(options?: TypeaheadOptions): JQuery; 119 | 120 | affix(options?: AffixOptions): JQuery; 121 | 122 | emulateTransitionEnd(duration: number): JQuery; 123 | } 124 | 125 | interface JQuerySupport { 126 | transition: boolean | TransitionEventNames; 127 | } 128 | 129 | declare module "bootstrap" { 130 | } 131 | -------------------------------------------------------------------------------- /Samples/QueueBrowser/Services/LoggingController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Net; 5 | using System.Net.Http; 6 | using System.Web.Http; 7 | using QueueBrowser.Repositories; 8 | 9 | namespace QueueBrowser.Services 10 | { 11 | [RoutePrefix("api/Logging")] 12 | public class LoggingController : ApiController 13 | { 14 | private readonly LoggingRepository _repository = new LoggingRepository(); 15 | 16 | [HttpGet] 17 | [Route("", Name = "LoggingList")] 18 | public IHttpActionResult Get(int? page = null, int? pageSize = null, string sort = null, bool? descending = null, string filter = null) 19 | { 20 | var result = _repository.GetLogs(page, pageSize, sort, descending, filter); 21 | 22 | return Ok(result); 23 | } 24 | 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Samples/QueueBrowser/Services/QueueController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Net; 5 | using System.Net.Http; 6 | using System.Web.Http; 7 | using System.Web.Http.ModelBinding; 8 | using MongoDB.Driver; 9 | using MongoDB.Driver.Linq; 10 | using MongoDB.Messaging; 11 | using QueueBrowser.Models; 12 | using QueueBrowser.Query; 13 | using QueueBrowser.Repositories; 14 | 15 | namespace QueueBrowser.Services 16 | { 17 | [RoutePrefix("api/Queue")] 18 | public class QueueController : ApiController 19 | { 20 | private readonly QueueRepository _repository = new QueueRepository(); 21 | 22 | [HttpGet] 23 | [Route("", Name = "QueueList")] 24 | public IHttpActionResult Get() 25 | { 26 | var model = _repository.GetQueues(@"[\w]+Queue"); 27 | 28 | return Ok(model); 29 | } 30 | 31 | [HttpGet] 32 | [Route("{name}/Status", Name = "QueueStatus")] 33 | public IHttpActionResult GetStatus(string name) 34 | { 35 | var model = _repository.GetStatus(name); 36 | 37 | return Ok(model); 38 | } 39 | 40 | [HttpGet] 41 | [Route("{name}/Messages", Name = "QueueMessages")] 42 | public IHttpActionResult GetMessages(string name, int? page = null, int? pageSize = null, string sort = null, bool? descending = null, string filter = null) 43 | { 44 | var result = _repository.GetMessages(name, page, pageSize, sort, descending, filter); 45 | 46 | return Ok(result); 47 | } 48 | 49 | [HttpPost] 50 | [Route("{name}/Requeue", Name = "QueueRequeue")] 51 | public IHttpActionResult Requeue(string name, QueueActionModel model) 52 | { 53 | _repository.Requeue(name, model.Ids); 54 | 55 | return Ok(); 56 | } 57 | 58 | [HttpDelete] 59 | [Route("{name}/Messages", Name = "QueueDeleteMessages")] 60 | public IHttpActionResult DeleteMessages(string name, QueueActionModel model) 61 | { 62 | _repository.Delete(name, model.Ids); 63 | 64 | return Ok(); 65 | } 66 | 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /Samples/QueueBrowser/Startup.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using Microsoft.AspNet.SignalR; 7 | using Microsoft.Owin; 8 | using Microsoft.Owin.Cors; 9 | using Newtonsoft.Json; 10 | using Owin; 11 | 12 | [assembly: OwinStartup(typeof(QueueBrowser.Startup))] 13 | 14 | namespace QueueBrowser 15 | { 16 | public class Startup 17 | { 18 | public void Configuration(IAppBuilder app) 19 | { 20 | app.UseCors(CorsOptions.AllowAll); 21 | 22 | var hubConfiguration = new HubConfiguration(); 23 | hubConfiguration.EnableDetailedErrors = true; 24 | hubConfiguration.EnableJavaScriptProxies = true; 25 | 26 | app.MapSignalR("/signalr", hubConfiguration); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Samples/QueueBrowser/Views/Home/Index.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewBag.Title = "Home"; 3 | } 4 | 5 |
6 |
7 |
8 |

MongoDB Messaging Samples

9 |
10 |
11 | 12 |
13 | 14 |
15 |
16 |
17 |

Messaging

18 |
19 |
20 |

Messaging is a common framework for running async background work.

21 | 24 |
25 |
26 |
27 | 28 |
29 |
30 |
31 |

Logging

32 |
33 |
34 |

Logging is a common location for view logs.

35 | 38 |
39 |
40 |
41 | 42 |
43 |
44 | 45 | 46 | @section scripts { 47 | 55 | } -------------------------------------------------------------------------------- /Samples/QueueBrowser/Views/Shared/Error.cshtml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Error 6 | 7 | 8 |
9 |

Error.

10 |

An error occurred while processing your request.

11 |
12 | 13 | 14 | -------------------------------------------------------------------------------- /Samples/QueueBrowser/Views/Shared/_Layout.cshtml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | @(ViewBag.Title ?? "Messaging") 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | @Styles.Render("~/content/css") 14 | @Scripts.Render("~/bundles/modernizr") 15 | 16 | 17 | 18 | 38 | 39 |
40 | @RenderBody() 41 |
42 | 43 |
44 |
45 |
46 |

© @DateTime.Now.Year - MongoDB Messaging

47 |
48 |
49 | 50 | @Scripts.Render("~/bundles/scripts") 51 | @Scripts.Render("~/bundles/app") 52 | 53 | @RenderSection("scripts", required: false) 54 | 55 | 56 | -------------------------------------------------------------------------------- /Samples/QueueBrowser/Views/Web.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 |
7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /Samples/QueueBrowser/Views/_ViewStart.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | Layout = "~/Views/Shared/_Layout.cshtml"; 3 | } 4 | -------------------------------------------------------------------------------- /Samples/QueueBrowser/app/.gitignore: -------------------------------------------------------------------------------- 1 | *.js 2 | *.map 3 | -------------------------------------------------------------------------------- /Samples/QueueBrowser/app/_ref.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | /// 4 | /// 5 | /// 6 | /// 7 | /// 8 | /// 9 | /// 10 | /// 11 | /// 12 | /// 13 | /// 14 | /// 15 | -------------------------------------------------------------------------------- /Samples/QueueBrowser/app/app.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | module Messaging { 4 | "use strict"; 5 | 6 | export var applicationName: string = 'app'; 7 | 8 | export var application: angular.IModule = angular.module( 9 | Messaging.applicationName, 10 | [ 11 | 'ngAnimate', 12 | 'ngSanitize', 13 | 'ngMessages', 14 | 'angularMoment', 15 | 'ui.bootstrap', 16 | 'toastr', 17 | 'SignalR' 18 | ] 19 | ); 20 | } 21 | -------------------------------------------------------------------------------- /Samples/QueueBrowser/app/models/AlertOptions.ts: -------------------------------------------------------------------------------- 1 | /// 2 | module Messaging { 3 | "use strict"; 4 | 5 | export interface AlertOptions { 6 | type?: string; 7 | title?: string; 8 | message?: string; 9 | timeOut?: number; 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /Samples/QueueBrowser/app/models/ChangeNotification.ts: -------------------------------------------------------------------------------- 1 | /// 2 | module Messaging { 3 | "use strict"; 4 | 5 | export interface IChangeNotification { 6 | Timestamp?: Date; 7 | UniqueId?: number; 8 | Version?: number; 9 | Operation?: string; 10 | Namespace?: string; 11 | Key?: string; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Samples/QueueBrowser/app/models/LogError.ts: -------------------------------------------------------------------------------- 1 | /// 2 | module Messaging { 3 | "use strict"; 4 | 5 | export interface ILogError { 6 | Message?: string; 7 | BaseMessage?: string; 8 | Text?: string; 9 | Type?: string; 10 | Source?: string; 11 | MethodName?: string; 12 | ModuleName?: string; 13 | ModuleVersion?: string; 14 | ErrorCode?: number; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Samples/QueueBrowser/app/models/LogEvent.ts: -------------------------------------------------------------------------------- 1 | /// 2 | module Messaging { 3 | "use strict"; 4 | 5 | export interface ILogEvent { 6 | Id?: string; 7 | Date?: string; 8 | Level?: string; 9 | Logger?: string; 10 | Message?: string; 11 | Source?: string; 12 | Correlation?: string; 13 | Exception?: ILogError; 14 | Properties?: any; 15 | 16 | Expanded?: boolean; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Samples/QueueBrowser/app/models/NameValueModel.ts: -------------------------------------------------------------------------------- 1 | /// 2 | module Messaging { 3 | "use strict"; 4 | 5 | export interface INameValueModel { 6 | Name: string; 7 | Value: string; 8 | } 9 | 10 | } 11 | -------------------------------------------------------------------------------- /Samples/QueueBrowser/app/models/QueryRequest.ts: -------------------------------------------------------------------------------- 1 | /// 2 | module Messaging { 3 | "use strict"; 4 | 5 | export interface IQueryRequest { 6 | Page?: number; 7 | PageSize?: number; 8 | 9 | Sort?: string; 10 | Descending?: boolean; 11 | 12 | Filter?: any; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Samples/QueueBrowser/app/models/QueryyResult.ts: -------------------------------------------------------------------------------- 1 | /// 2 | module Messaging { 3 | "use strict"; 4 | 5 | export interface IQueryyResult { 6 | Data?: T[]; 7 | 8 | Page?: number; 9 | PageSize?: number; 10 | PageCount?: number; 11 | 12 | Sort?: string; 13 | Descending?: boolean; 14 | 15 | Filter?: any; 16 | 17 | Total?: number; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Samples/QueueBrowser/app/models/QueueActionModel.ts: -------------------------------------------------------------------------------- 1 | /// 2 | module Messaging { 3 | "use strict"; 4 | 5 | export interface IQueueActionModel { 6 | Name?: string; 7 | Ids?: string[]; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Samples/QueueBrowser/app/models/QueueMessageModel.ts: -------------------------------------------------------------------------------- 1 | /// 2 | module Messaging { 3 | "use strict"; 4 | 5 | export interface IQueueMessageModel { 6 | Id?: string; 7 | Name?: string; 8 | Description?: string; 9 | Correlation?: string; 10 | State?: string; 11 | Result?: string; 12 | ResponseQueue?: string; 13 | Step?: number; 14 | Status?: string; 15 | Priority?: number; 16 | RetryCount?: number; 17 | ErrorCount?: number; 18 | Scheduled?: Date; 19 | StartTime?: Date; 20 | EndTime?: Date; 21 | Expire?: Date; 22 | UserName?: string; 23 | Created?: Date; 24 | Updated?: Date; 25 | Selected?: boolean; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Samples/QueueBrowser/app/models/QueueStatusModel.ts: -------------------------------------------------------------------------------- 1 | /// 2 | module Messaging { 3 | "use strict"; 4 | 5 | export interface IQueueStatusModel { 6 | Name?: string; 7 | Namespace?: string; 8 | Queued?: number; 9 | Processing?: number; 10 | Complete?: number; 11 | Timeout?: number; 12 | Scheduled?: number; 13 | Successful?: number; 14 | Warning?: number; 15 | Error?: number; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Samples/QueueBrowser/app/services/Logger.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | module Messaging { 4 | "use strict"; 5 | 6 | 7 | export class Logger { 8 | static $inject = [ 9 | 'toastr' 10 | ]; 11 | 12 | 13 | constructor(toastr: angular.toastr.IToastrService) { 14 | var self = this; 15 | 16 | self.toastr = toastr; 17 | self.logError = >angular.bind(self, self.handelError); 18 | 19 | } 20 | 21 | toastr: angular.toastr.IToastrService; 22 | logError: angular.IHttpPromiseCallback; 23 | 24 | handelError(data: any, status: number, headers: angular.IHttpHeadersGetter, config: angular.IRequestConfig) { 25 | var self = this; 26 | var message = ''; 27 | 28 | if (status === 400) 29 | message = self.extractModelState(data); 30 | else if (status === 500) 31 | message = self.extractServerError(data); 32 | else if (status) 33 | message += 'An error has occurred:\n ' + status; 34 | else 35 | message += 'An error has occurred:\n Unrecognized server response'; 36 | 37 | // clear others to prevents flood of toast 38 | var options = { 39 | closeButton: true, 40 | progressBar: true, 41 | timeOut: 6000, 42 | 43 | } 44 | self.toastr.clear(); 45 | self.toastr.error(message, 'Error', options); 46 | } 47 | 48 | extractServerError(error): string { 49 | var message = 'An error has occurred:\n'; 50 | 51 | // get all inner errors 52 | var errors = []; 53 | var current = error; 54 | while (current) { 55 | if (current.ExceptionMessage) 56 | errors.push(current.ExceptionMessage); 57 | 58 | current = current.InnerException; 59 | } 60 | 61 | if (errors.length > 0) 62 | message += errors.join(' \n'); 63 | else 64 | message += ' Unknown error occurred'; 65 | 66 | return message; 67 | } 68 | 69 | extractModelState(error): string { 70 | var message = 'The request is invalid: \n'; 71 | 72 | if (!error.ModelState) 73 | return message; 74 | 75 | // get all model state errors 76 | var errors = []; 77 | for (var key in error.ModelState) { 78 | if (error.ModelState.hasOwnProperty(key)) { 79 | // property name 80 | var parts = key.split('.'); 81 | var name = parts.pop(); 82 | 83 | // all errors for property 84 | for (var i = 0; i < error.ModelState[key].length; i++) { 85 | errors.push(name + ': ' + error.ModelState[key][i]); 86 | } 87 | } 88 | } 89 | 90 | message += errors.join(' \n'); 91 | return message; 92 | } 93 | } 94 | 95 | // register service 96 | angular.module(Messaging.applicationName) 97 | .service('logger', [ 98 | 'toastr', 99 | Logger 100 | ]); 101 | } -------------------------------------------------------------------------------- /Samples/QueueBrowser/app/services/LoggingRepository.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | module Messaging { 4 | "use strict"; 5 | 6 | export class LoggingRepository { 7 | static $inject = [ 8 | '$http' 9 | ]; 10 | 11 | urlBase: string = 'api/Logging'; 12 | $http: angular.IHttpService; 13 | 14 | constructor( 15 | $http: angular.IHttpService) { 16 | this.$http = $http; 17 | } 18 | 19 | get(request: IQueryRequest): angular.IHttpPromise> { 20 | var url = this.urlBase + '/'; 21 | var config = { params: request }; 22 | return this.$http.get>(url, config); 23 | } 24 | 25 | } 26 | 27 | // register service 28 | angular.module(Messaging.applicationName).service('loggingRepository', [ 29 | '$http', 30 | LoggingRepository 31 | ]); 32 | } -------------------------------------------------------------------------------- /Samples/QueueBrowser/app/services/NotificationService.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | module Messaging { 4 | "use strict"; 5 | 6 | 7 | export class NotificationService { 8 | static $inject = [ 9 | '$rootScope', 10 | 'Hub' 11 | ]; 12 | 13 | private hubProxy: any; 14 | private $rootScope: angular.IScope; 15 | 16 | constructor($rootScope: angular.IScope, Hub: any) { 17 | var self = this; 18 | 19 | self.$rootScope = $rootScope; 20 | self.hubProxy = new Hub('changeNotificationHub', { 21 | listeners: { 22 | sendChange: self.onChange.bind(self) 23 | }, 24 | 25 | errorHandler: self.errorHandler.bind(self), 26 | stateChanged: self.stateChanged.bind(self) 27 | }); 28 | } 29 | 30 | 31 | onChange(notification: IChangeNotification) { 32 | var self = this; 33 | 34 | self.$rootScope.$broadcast('changeNotification', notification); 35 | } 36 | 37 | stateChanged(state: SignalR.StateChanged) { 38 | var self = this; 39 | 40 | self.$rootScope.$broadcast('changeNotificationState', state); 41 | } 42 | 43 | errorHandler(error) { 44 | console.error("error:" + error); 45 | } 46 | 47 | start() { 48 | console.log("Start Notification Service"); 49 | } 50 | } 51 | 52 | // register service 53 | angular.module(Messaging.applicationName) 54 | .service('notificationService', [ 55 | '$rootScope', 56 | 'Hub', 57 | NotificationService 58 | ]) 59 | .run(['notificationService', (notificationService: NotificationService) => { 60 | notificationService.start(); 61 | }]); 62 | } -------------------------------------------------------------------------------- /Samples/QueueBrowser/app/services/QueueRepository.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | module Messaging { 4 | "use strict"; 5 | 6 | export class QueueRepository { 7 | static $inject = [ 8 | '$http' 9 | ]; 10 | 11 | urlBase: string = 'api/Queue'; 12 | $http: angular.IHttpService; 13 | 14 | constructor( 15 | $http: angular.IHttpService) { 16 | this.$http = $http; 17 | } 18 | 19 | list(): angular.IHttpPromise { 20 | var url = this.urlBase; 21 | return this.$http.get(url); 22 | 23 | } 24 | 25 | status(queue: string): angular.IHttpPromise { 26 | var url = this.urlBase + '/' + encodeURIComponent(queue) + '/Status'; 27 | return this.$http.get(url); 28 | } 29 | 30 | messages(queue: string, request: IQueryRequest): angular.IHttpPromise> { 31 | var url = this.urlBase + '/' + encodeURIComponent(queue) + '/Messages'; 32 | var config = { params: request }; 33 | return this.$http.get>(url, config); 34 | } 35 | 36 | requeue(queue: string, action: IQueueActionModel): angular.IHttpPromise { 37 | var url = this.urlBase + '/' + encodeURIComponent(queue) + '/Requeue'; 38 | return this.$http.post(url, action); 39 | } 40 | 41 | delete(queue: string, action: IQueueActionModel): angular.IHttpPromise { 42 | var url = this.urlBase + '/' + encodeURIComponent(queue) + '/Messages'; 43 | var config = { 44 | headers: { 45 | 'Content-Type': 'application/json' 46 | }, 47 | data: action 48 | }; 49 | 50 | return this.$http.delete(url, config); 51 | } 52 | 53 | 54 | } 55 | 56 | // register service 57 | angular.module(Messaging.applicationName).service('queueRepository', [ 58 | '$http', 59 | QueueRepository 60 | ]); 61 | } -------------------------------------------------------------------------------- /Samples/QueueBrowser/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loresoft/MongoDB.Messaging/7e8210d7ea61d2c6f48fda7c9645604d27b9dcb6/Samples/QueueBrowser/favicon.ico -------------------------------------------------------------------------------- /Samples/QueueBrowser/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loresoft/MongoDB.Messaging/7e8210d7ea61d2c6f48fda7c9645604d27b9dcb6/Samples/QueueBrowser/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /Samples/QueueBrowser/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loresoft/MongoDB.Messaging/7e8210d7ea61d2c6f48fda7c9645604d27b9dcb6/Samples/QueueBrowser/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /Samples/QueueBrowser/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loresoft/MongoDB.Messaging/7e8210d7ea61d2c6f48fda7c9645604d27b9dcb6/Samples/QueueBrowser/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /Samples/QueueBrowser/fonts/glyphicons-halflings-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loresoft/MongoDB.Messaging/7e8210d7ea61d2c6f48fda7c9645604d27b9dcb6/Samples/QueueBrowser/fonts/glyphicons-halflings-regular.woff2 -------------------------------------------------------------------------------- /Samples/Sleep.Client/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /Samples/Sleep.Client/EchoOptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using CommandLine; 3 | 4 | namespace Sleep.Client 5 | { 6 | [Verb("echo", HelpText = "Send echo message")] 7 | public class EchoOptions 8 | { 9 | [Option("count", HelpText = "The number of messages to send", Default = 1)] 10 | public int Count { get; set; } = 1; 11 | 12 | [Option("when", HelpText = "The number minutes to delay processing")] 13 | public int When { get; set; } 14 | 15 | [Option("throw", HelpText = "Throw an error while processing")] 16 | public bool Throw { get; set; } 17 | 18 | [Option("message", HelpText = "The message to echo")] 19 | public string Message { get; set; } 20 | } 21 | } -------------------------------------------------------------------------------- /Samples/Sleep.Client/NLog.config: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 23 | 24 | 27 | 28 | 29 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /Samples/Sleep.Client/NativeMethods.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace Sleep.Client 5 | { 6 | internal static class NativeMethods 7 | { 8 | [DllImport("shell32.dll", SetLastError = true)] 9 | static extern IntPtr CommandLineToArgvW([MarshalAs(UnmanagedType.LPWStr)] string lpCmdLine, out int pNumArgs); 10 | 11 | public static string[] CommandLineToArgs(string commandLine) 12 | { 13 | int argc; 14 | var argv = CommandLineToArgvW(commandLine, out argc); 15 | if (argv == IntPtr.Zero) 16 | throw new System.ComponentModel.Win32Exception(); 17 | 18 | try 19 | { 20 | var args = new string[argc]; 21 | for (var i = 0; i < args.Length; i++) 22 | { 23 | var p = Marshal.ReadIntPtr(argv, i * IntPtr.Size); 24 | args[i] = Marshal.PtrToStringUni(p); 25 | } 26 | 27 | return args; 28 | } 29 | finally 30 | { 31 | Marshal.FreeHGlobal(argv); 32 | } 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /Samples/Sleep.Client/QuitOptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using CommandLine; 3 | 4 | namespace Sleep.Client 5 | { 6 | [Verb("quit", HelpText = "Quit and close client")] 7 | public class QuitOptions { } 8 | } -------------------------------------------------------------------------------- /Samples/Sleep.Client/Sleep.Client.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | Exe 4 | net46 5 | false 6 | false 7 | false 8 | false 9 | false 10 | false 11 | false 12 | false 13 | false 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | Always 35 | 36 | 37 | -------------------------------------------------------------------------------- /Samples/Sleep.Client/SleepOptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using CommandLine; 4 | using CommandLine.Text; 5 | 6 | namespace Sleep.Client 7 | { 8 | [Verb("sleep", HelpText = "Send sleep message")] 9 | public class SleepOptions 10 | { 11 | [Option("count", HelpText = "The number of messages to send", Default = 1)] 12 | public int Count { get; set; } 13 | 14 | [Option("when", HelpText = "The number minutes to delay processing")] 15 | public int When { get; set; } 16 | 17 | [Option("throw", HelpText = "Throw an error while processing")] 18 | public bool Throw { get; set; } 19 | 20 | [Usage(ApplicationAlias = "")] 21 | public static IEnumerable Examples 22 | { 23 | get 24 | { 25 | yield return new Example("Send Sleep message 10 times", new SleepOptions {Count = 10 }); 26 | yield return new Example("Send Sleep with error", new SleepOptions { Throw = true }); 27 | } 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /Samples/Sleep.Messages/EchoMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Sleep.Messages 4 | { 5 | public class EchoMessage 6 | { 7 | public const string QueueName = "EchoQueue"; 8 | 9 | public string Text { get; set; } 10 | 11 | public bool Throw { get; set; } 12 | 13 | public override string ToString() 14 | { 15 | return $"Echo Message Text: {Text}"; 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /Samples/Sleep.Messages/Sleep.Messages.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | net46 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /Samples/Sleep.Messages/SleepMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Sleep.Messages 8 | { 9 | public class SleepMessage 10 | { 11 | public const string QueueName = "SleepQueue"; 12 | 13 | public TimeSpan Time { get; set; } 14 | 15 | public string Text { get; set; } 16 | 17 | public bool Throw { get; set; } 18 | 19 | public override string ToString() 20 | { 21 | return $"Sleep Message Text: {Text}, Throw: {Throw}, Time: {Time}"; 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Samples/Sleep.Service/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Samples/Sleep.Service/EchoHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | using MongoDB.Messaging; 4 | using MongoDB.Messaging.Subscription; 5 | using Sleep.Messages; 6 | 7 | namespace Sleep.Service 8 | { 9 | public class EchoHandler : IMessageSubscriber 10 | { 11 | public MessageResult Process(ProcessContext context) 12 | { 13 | // get message data 14 | var sleepMessage = context.Data(); 15 | 16 | Console.WriteLine("Echo Received: '{0}', Id: {1}", sleepMessage.Text, context.Message.Id); 17 | 18 | Thread.Sleep(5000); 19 | 20 | if (sleepMessage.Throw) 21 | throw new InvalidOperationException("This is a test echo exception"); 22 | 23 | return MessageResult.Successful; 24 | } 25 | 26 | public void Dispose() 27 | { 28 | 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /Samples/Sleep.Service/NLog.config: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 23 | 24 | 27 | 28 | 29 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /Samples/Sleep.Service/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Configuration; 3 | using MongoDB.Messaging; 4 | using MongoDB.Messaging.Logging; 5 | using MongoDB.Messaging.Service; 6 | using Sleep.Messages; 7 | using Sleep.Service.Logging; 8 | 9 | namespace Sleep.Service 10 | { 11 | public class Program 12 | { 13 | private static MessageService _messageService; 14 | 15 | public static void Main(string[] args) 16 | { 17 | Logger.RegisterWriter(NLogWriter.Default); 18 | 19 | ShowVersion(); 20 | Initialize(); 21 | DebugRun(args); 22 | } 23 | 24 | private static void Initialize() 25 | { 26 | var connectionString = ConfigurationManager.ConnectionStrings["MongoMessaging"]?.ConnectionString 27 | ?? "mongodb://localhost/Messaging"; 28 | 29 | MessageQueue.Default.Configure(c => c 30 | .ConnectionString(connectionString) 31 | .Queue(q => q 32 | .Name(SleepMessage.QueueName) 33 | .Retry(5) 34 | ) 35 | .Subscribe(s => s 36 | .Queue(SleepMessage.QueueName) 37 | .Handler() 38 | .PollTime(TimeSpan.FromMinutes(5)) 39 | .Workers(4) 40 | .Trigger() 41 | ) 42 | .Subscribe(s => s 43 | .Queue(EchoMessage.QueueName) 44 | .Handler() 45 | .PollTime(TimeSpan.FromMinutes(5)) 46 | .Workers(1) 47 | .Trigger() 48 | ) 49 | ); 50 | 51 | _messageService = new MessageService(); 52 | } 53 | 54 | private static void ShowVersion() 55 | { 56 | Console.WriteLine("{0} {1}", ThisAssembly.AssemblyProduct, ThisAssembly.AssemblyFileVersion); 57 | Console.WriteLine(ThisAssembly.AssemblyCopyright); 58 | Console.WriteLine(); 59 | } 60 | 61 | private static void DebugRun(string[] args) 62 | { 63 | _messageService.Start(); 64 | 65 | DebugHelp(); 66 | 67 | while (true) 68 | { 69 | string line = Console.In.ReadLine() ?? string.Empty; 70 | if (string.Equals(line, "P", StringComparison.OrdinalIgnoreCase)) 71 | { 72 | Console.WriteLine("Pausing...."); 73 | _messageService.Stop(); 74 | } 75 | 76 | if (string.Equals(line, "C", StringComparison.OrdinalIgnoreCase)) 77 | { 78 | Console.WriteLine("Continuing...."); 79 | _messageService.Start(); 80 | } 81 | 82 | if (string.Equals(line, "R", StringComparison.OrdinalIgnoreCase)) 83 | { 84 | Console.WriteLine("Restarting..."); 85 | _messageService.Stop(); 86 | _messageService.Start(); 87 | } 88 | 89 | if (string.Equals(line, "Q", StringComparison.OrdinalIgnoreCase)) 90 | { 91 | _messageService.Stop(); 92 | break; 93 | } 94 | 95 | DebugHelp(); 96 | } 97 | 98 | _messageService.Stop(); 99 | } 100 | 101 | private static void DebugHelp() 102 | { 103 | Console.WriteLine("Service running in debug mode."); 104 | Console.WriteLine(" C. Continue service"); 105 | Console.WriteLine(" P. Pause service"); 106 | Console.WriteLine(" R. Restart service"); 107 | Console.WriteLine(" Q. Quit"); 108 | } 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /Samples/Sleep.Service/Sleep.Service.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | Exe 4 | net46 5 | false 6 | false 7 | false 8 | false 9 | false 10 | false 11 | false 12 | false 13 | false 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | Always 35 | 36 | 37 | -------------------------------------------------------------------------------- /Samples/Sleep.Service/SleepHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | using MongoDB.Messaging; 4 | using MongoDB.Messaging.Subscription; 5 | using Sleep.Messages; 6 | 7 | namespace Sleep.Service 8 | { 9 | public class SleepHandler : IMessageSubscriber 10 | { 11 | public MessageResult Process(ProcessContext context) 12 | { 13 | // get message data 14 | var sleepMessage = context.Data(); 15 | 16 | Console.WriteLine("Sleep Messeage Received: '{0}', Time: {1}, Id: {2}", 17 | sleepMessage.Text, sleepMessage.Time, context.Message.Id); 18 | 19 | Thread.Sleep(sleepMessage.Time); 20 | 21 | if (sleepMessage.Throw) 22 | throw new InvalidOperationException("This is a test sleep exception"); 23 | 24 | return MessageResult.Successful; 25 | } 26 | 27 | public void Dispose() 28 | { 29 | 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | version: 2.0.0.{build} 2 | os: Visual Studio 2017 3 | environment: 4 | Major: 2 5 | Minor: 0 6 | Patch: 0 7 | configuration: Release 8 | services: mongodb 9 | before_build: 10 | - .\bootstrap.cmd 11 | build: 12 | project: master.proj 13 | verbosity: minimal 14 | test: off 15 | artifacts: 16 | - path: Build\*.nupkg 17 | deploy: 18 | - provider: Environment 19 | name: MyGet -------------------------------------------------------------------------------- /bootstrap.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | NuGet.exe install MSBuildTasks -OutputDirectory .\Tools\ -ExcludeVersion -NonInteractive 3 | -------------------------------------------------------------------------------- /global.json: -------------------------------------------------------------------------------- 1 | { 2 | "sdk": { 3 | "version": "1.0.4" 4 | } 5 | } -------------------------------------------------------------------------------- /src/GlobalAssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | [assembly: System.Reflection.AssemblyProduct("MongoDB.Messaging")] 12 | [assembly: System.Reflection.AssemblyCompany("LoreSoft")] 13 | [assembly: System.Reflection.AssemblyCopyright("Copyright © 2017 LoreSoft")] 14 | [assembly: System.Reflection.AssemblyConfiguration("Release")] 15 | [assembly: System.Reflection.AssemblyVersion("2.0.0.0")] 16 | [assembly: System.Reflection.AssemblyFileVersion("2.0.0.0")] 17 | [assembly: System.Reflection.AssemblyInformationalVersion("2.0.0.0")] 18 | [assembly: System.Runtime.InteropServices.ComVisible(false)] 19 | 20 | 21 | 22 | internal sealed partial class ThisAssembly { 23 | 24 | internal const string AssemblyProduct = "MongoDB.Messaging"; 25 | 26 | internal const string AssemblyCompany = "LoreSoft"; 27 | 28 | internal const string AssemblyCopyright = "Copyright © 2017 LoreSoft"; 29 | 30 | internal const string AssemblyConfiguration = "Release"; 31 | 32 | internal const string AssemblyVersion = "2.0.0.0"; 33 | 34 | internal const string AssemblyFileVersion = "2.0.0.0"; 35 | 36 | internal const string AssemblyInformationalVersion = "2.0.0.0"; 37 | 38 | private ThisAssembly() { 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/MongoDB.Messaging.SignalR/ChangeNotification.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices.WindowsRuntime; 3 | using MongoDB.Bson; 4 | using MongoDB.Messaging.Change; 5 | 6 | namespace MongoDB.Messaging.SignalR 7 | { 8 | /// 9 | /// A change notification message 10 | /// 11 | public class ChangeNotification 12 | { 13 | /// 14 | /// Initializes a new instance of the class. 15 | /// 16 | public ChangeNotification() 17 | { 18 | } 19 | 20 | /// 21 | /// Initializes a new instance of the class. 22 | /// 23 | /// The change. 24 | /// 25 | public ChangeNotification(ChangeRecord change) 26 | { 27 | if (change == null) 28 | throw new ArgumentNullException(nameof(change)); 29 | 30 | Timestamp = GetDateTime(change.Timestamp); 31 | UniqueId = change.UniqueId; 32 | Version = change.Version; 33 | Operation = change.Operation; 34 | Namespace = change.Namespace; 35 | Key = GetKey(change)?.ToString(); 36 | } 37 | 38 | 39 | /// 40 | /// Gets or sets the change timestamp. 41 | /// 42 | /// 43 | /// The change timestamp. 44 | /// 45 | public DateTime? Timestamp { get; set; } 46 | 47 | /// 48 | /// Gets or sets the change unique identifier. 49 | /// 50 | /// 51 | /// The change unique identifier. 52 | /// 53 | public long UniqueId { get; set; } 54 | 55 | /// 56 | /// Gets or sets the change version. 57 | /// 58 | /// 59 | /// The change version. 60 | /// 61 | public int Version { get; set; } 62 | 63 | /// 64 | /// Gets or sets the change operation. 65 | /// 66 | /// 67 | /// The change operation. 68 | /// 69 | public string Operation { get; set; } 70 | 71 | /// 72 | /// Gets or sets the change namespace. 73 | /// 74 | /// 75 | /// The change namespace. 76 | /// 77 | public string Namespace { get; set; } 78 | 79 | /// 80 | /// Gets or sets the change key. 81 | /// 82 | /// 83 | /// The change key. 84 | /// 85 | public string Key { get; set; } 86 | 87 | 88 | private static BsonValue GetKey(ChangeRecord change) 89 | { 90 | if (change?.Document == null) 91 | return false; 92 | 93 | // insert, delete or update 94 | if (change.Operation == "i" || change.Operation == "d") 95 | return GetKey(change.Document); 96 | 97 | if (change.Operation == "u") 98 | return GetKey(change.Query); 99 | 100 | return null; 101 | } 102 | 103 | private static BsonValue GetKey(BsonDocument document) 104 | { 105 | if (!document.Contains("_id")) 106 | return null; 107 | 108 | return document["_id"]; 109 | } 110 | 111 | private static DateTime? GetDateTime(BsonTimestamp timestamp) 112 | { 113 | if (timestamp == null) 114 | return null; 115 | 116 | return new DateTime(1970, 1, 1).AddSeconds(timestamp.Timestamp); 117 | } 118 | 119 | } 120 | } -------------------------------------------------------------------------------- /src/MongoDB.Messaging.SignalR/ChangeNotificationHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.AspNet.SignalR; 3 | using MongoDB.Messaging.Change; 4 | 5 | namespace MongoDB.Messaging.SignalR 6 | { 7 | /// 8 | /// A change handler that forwards the change to the underling SignalR hub context. 9 | /// 10 | /// 11 | public class ChangeNotificationHandler : IHandleChange 12 | { 13 | private readonly IHubContext _context; 14 | 15 | /// 16 | /// Initializes a new instance of the class. 17 | /// 18 | /// The SignalR hub context. 19 | /// context is null 20 | public ChangeNotificationHandler(IHubContext context) 21 | { 22 | if (context == null) 23 | throw new ArgumentNullException(nameof(context)); 24 | 25 | _context = context; 26 | } 27 | 28 | /// 29 | /// Handle a MongoDB change record by forwarding the change to the underling SignalR hub context. 30 | /// 31 | /// The change record. 32 | /// 33 | /// This method is called on a thread-pool background thread. 34 | /// 35 | public virtual void HandleChange(ChangeRecord change) 36 | { 37 | var notification = new ChangeNotification(change); 38 | _context.Clients.All.SendChange(notification); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/MongoDB.Messaging.SignalR/ChangeNotificationHub.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.AspNet.SignalR; 3 | 4 | namespace MongoDB.Messaging.SignalR 5 | { 6 | /// 7 | /// A strongly typed SignalR hub for change notifications. 8 | /// 9 | public class ChangeNotificationHub : Hub 10 | { 11 | 12 | } 13 | } -------------------------------------------------------------------------------- /src/MongoDB.Messaging.SignalR/ChangeNotificationService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.AspNet.SignalR; 3 | using MongoDB.Messaging.Change; 4 | using MongoDB.Messaging.Logging; 5 | 6 | namespace MongoDB.Messaging.SignalR 7 | { 8 | /// 9 | /// A change notification service to orchestrate changes from MongoDB to a SignalR hub. 10 | /// 11 | public class ChangeNotificationService 12 | { 13 | private static readonly ILogger _logger = Logger.CreateLogger(); 14 | 15 | private readonly Lazy _notififer; 16 | private readonly Lazy _handler; 17 | private ISubscription _subscription; 18 | 19 | /// 20 | /// Initializes a new instance of the class. 21 | /// 22 | /// Name of the connection. 23 | /// The MongoDB collection namespace filter. 24 | public ChangeNotificationService(string connectionName, string filter = null) 25 | { 26 | _handler = new Lazy(CreateHandler); 27 | _notififer = new Lazy(() => CreateNotifier(connectionName)); 28 | 29 | Filter = filter ?? MessageQueue.Default.QueueManager.Database.DatabaseNamespace.DatabaseName + ".*"; 30 | 31 | } 32 | 33 | /// 34 | /// Gets or sets the MongoDB collection namespace filter. 35 | /// 36 | /// 37 | /// The MongoDB collection namespace filter. 38 | /// 39 | /// 40 | /// Filter to all collections in the Messaging database. 41 | /// Messaging.* 42 | /// 43 | public string Filter { get; set; } 44 | 45 | 46 | /// 47 | /// Start the change notification service. 48 | /// 49 | public void Start() 50 | { 51 | _logger.Debug() 52 | .Message("Change Notification Service Starting with filter '{0}'", Filter) 53 | .Write(); 54 | 55 | _subscription = _notififer.Value.Subscribe(_handler.Value, Filter); 56 | _notififer.Value.Start(); 57 | } 58 | 59 | /// 60 | /// Stop the change notification service. 61 | /// 62 | public void Stop() 63 | { 64 | if (!_notififer.IsValueCreated) 65 | return; 66 | 67 | _logger.Debug() 68 | .Message("Change Notification Service Stopping") 69 | .Write(); 70 | 71 | if (_subscription != null) 72 | _notififer.Value.Unsubscribe(_subscription); 73 | 74 | _notififer.Value.Stop(); 75 | } 76 | 77 | 78 | /// 79 | /// Creates an instance of . 80 | /// 81 | /// 82 | protected virtual ChangeNotificationHandler CreateHandler() 83 | { 84 | // get hub contact to send messages on 85 | var hubContext = GlobalHost.ConnectionManager.GetHubContext(); 86 | return new ChangeNotificationHandler(hubContext); 87 | } 88 | 89 | /// 90 | /// Creates an instance of from the specified . 91 | /// 92 | /// 93 | protected virtual ChangeNotifier CreateNotifier(string connectionName) 94 | { 95 | return new ChangeNotifier(connectionName); 96 | } 97 | 98 | } 99 | } -------------------------------------------------------------------------------- /src/MongoDB.Messaging.SignalR/IChangeNotificationClient.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace MongoDB.Messaging.SignalR 4 | { 5 | /// 6 | /// An for sending messages 7 | /// 8 | public interface IChangeNotificationClient 9 | { 10 | /// 11 | /// Send the specified message. 12 | /// 13 | /// The notification messages. 14 | void SendChange(ChangeNotification notification); 15 | } 16 | } -------------------------------------------------------------------------------- /src/MongoDB.Messaging.SignalR/MongoDB.Messaging.SignalR.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | The MongoDB Messaging SignalR library is a SignalR Hub for change notification. 4 | en-US 5 | 2.0.0.0 6 | LoreSoft 7 | net45 8 | true 9 | MongoDB.Messaging.SignalR 10 | MongoDB.Messaging.SignalR 11 | MongoDB;Messaging 12 | https://github.com/loresoft/MongoDB.Messaging 13 | https://raw.githubusercontent.com/loresoft/MongoDB.Messaging/master/LICENSE 14 | 1.6.0 15 | false 16 | false 17 | false 18 | false 19 | false 20 | false 21 | false 22 | false 23 | false 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /src/MongoDB.Messaging/Change/ChangeRecord.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using MongoDB.Bson; 3 | using MongoDB.Bson.Serialization.Attributes; 4 | 5 | namespace MongoDB.Messaging.Change 6 | { 7 | /// 8 | /// MongoDB change record for the oplog. 9 | /// 10 | [BsonIgnoreExtraElements] 11 | public class ChangeRecord 12 | { 13 | /// 14 | /// Gets or sets the timestamp for the operation. 15 | /// 16 | /// 17 | /// The timestamp for the change. 18 | /// 19 | /// 20 | /// The 'ts' field in the oplog document. 21 | /// 22 | [BsonElement("ts")] 23 | public BsonTimestamp Timestamp { get; set; } 24 | 25 | /// 26 | /// Gets or sets the unique identifier for the operation. 27 | /// 28 | /// 29 | /// The unique identifier for the operation. 30 | /// 31 | /// 32 | /// The 'h' field in the oplog document. 33 | /// 34 | [BsonElement("h")] 35 | public long UniqueId { get; set; } 36 | 37 | /// 38 | /// Gets or sets the version of the oplog format. 39 | /// 40 | /// 41 | /// The version. 42 | /// 43 | /// 44 | /// The 'v' field in the oplog document. 45 | /// 46 | [BsonElement("v")] 47 | public int Version { get; set; } 48 | 49 | /// 50 | /// Gets or sets the operation that took place. Known values can be 'i' for insert, 51 | /// 'u' for update, 'd' for delete, 'c' for commands and 'n' for no-ops". 52 | /// 53 | /// 54 | /// The operation. 55 | /// 56 | /// 57 | /// The 'op' field in the oplog document. 58 | /// 59 | [BsonElement("op")] 60 | public string Operation { get; set; } 61 | 62 | /// 63 | /// Gets or sets the namespace, database and collection, for the operation. 64 | /// 65 | /// 66 | /// The namespace for the operation. 67 | /// 68 | /// 69 | /// The 'ns' field in the oplog document. 70 | /// 71 | [BsonElement("ns")] 72 | public string Namespace { get; set; } 73 | 74 | /// 75 | /// Gets or sets the query for an update operation. 76 | /// 77 | /// 78 | /// The query for an update operation. 79 | /// 80 | /// 81 | /// The 'o2' field in the oplog document. 82 | /// 83 | [BsonElement("o2")] 84 | public BsonDocument Query { get; set; } 85 | 86 | /// 87 | /// Gets or sets the document for the operation. The document will be different based on the operation. 88 | /// 89 | /// 90 | /// The document for the operation. 91 | /// 92 | /// 93 | /// The 'o' field in the oplog document. 94 | /// 95 | [BsonElement("o")] 96 | public BsonDocument Document { get; set; } 97 | } 98 | } -------------------------------------------------------------------------------- /src/MongoDB.Messaging/Change/IHandleChange.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | 4 | namespace MongoDB.Messaging.Change 5 | { 6 | /// 7 | /// An to implement to receive change notifications. 8 | /// 9 | public interface IHandleChange 10 | { 11 | /// 12 | /// Handle a MongoDB change record. 13 | /// 14 | /// The change record. 15 | /// 16 | /// This method is called on a thread-pool background thread. 17 | /// 18 | void HandleChange(ChangeRecord change); 19 | } 20 | } -------------------------------------------------------------------------------- /src/MongoDB.Messaging/Change/ISubscription.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace MongoDB.Messaging.Change 4 | { 5 | /// 6 | /// An for a change subscription 7 | /// 8 | public interface ISubscription 9 | { 10 | /// 11 | /// Gets MongoDB collection namespace wildcard filter. 12 | /// 13 | /// 14 | /// The MongoDB collection namespace wildcard filter. 15 | /// 16 | string Filter { get; } 17 | /// 18 | /// Gets the change notification handler. 19 | /// 20 | /// 21 | /// The change notification handler. 22 | /// 23 | IHandleChange Handler { get; } 24 | 25 | /// 26 | /// Begin invoke of on the thread-pool background thread. 27 | /// 28 | /// The change record to send. 29 | /// true if the Handler is still alive and was able to be invoked; otherwise false. 30 | bool BeginInvoke(ChangeRecord change); 31 | } 32 | } -------------------------------------------------------------------------------- /src/MongoDB.Messaging/Change/Subscription.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | 4 | namespace MongoDB.Messaging.Change 5 | { 6 | /// 7 | /// A change subscription 8 | /// 9 | public class Subscription : ISubscription 10 | { 11 | private readonly WeakReference _reference; 12 | 13 | /// 14 | /// Initializes a new instance of the class. 15 | /// 16 | /// The change handler. 17 | /// The MongoDB collection namespace wildcard filter. 18 | /// is . 19 | public Subscription(IHandleChange handler, string filter) 20 | { 21 | if (handler == null) 22 | throw new ArgumentNullException(nameof(handler)); 23 | 24 | _reference = new WeakReference(handler); 25 | Filter = filter; 26 | } 27 | 28 | 29 | /// 30 | /// Gets MongoDB collection namespace wildcard filter. 31 | /// 32 | /// 33 | /// The MongoDB collection namespace wildcard filter. 34 | /// 35 | public string Filter { get; } 36 | 37 | /// 38 | /// Gets the change notification handler. 39 | /// 40 | /// 41 | /// The change notification handler. 42 | /// 43 | public IHandleChange Handler => _reference.Target as IHandleChange; 44 | 45 | 46 | /// 47 | /// Begin invoke of on the thread-pool background thread. 48 | /// 49 | /// The change record to send. 50 | /// true if the Handler is still alive and was able to be invoked; otherwise false. 51 | public bool BeginInvoke(ChangeRecord change) 52 | { 53 | // handler might have been disposed 54 | var handler = _reference.Target as IHandleChange; 55 | if (handler == null) 56 | return false; 57 | 58 | // fire and forget 59 | return ThreadPool.QueueUserWorkItem(state => handler.HandleChange(change)); 60 | } 61 | } 62 | } -------------------------------------------------------------------------------- /src/MongoDB.Messaging/Configuration/IQueueContainer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using MongoDB.Messaging.Storage; 3 | 4 | namespace MongoDB.Messaging.Configuration 5 | { 6 | /// 7 | /// An interface defining the components that make a up queue. 8 | /// 9 | public interface IQueueContainer 10 | { 11 | /// 12 | /// Gets the name of the queue. 13 | /// 14 | /// 15 | /// The name of the queue. 16 | /// 17 | string Name { get; } 18 | 19 | /// 20 | /// Gets the storage repository. 21 | /// 22 | /// 23 | /// The storage repository. 24 | /// 25 | IQueueRepository Repository { get; } 26 | 27 | /// 28 | /// Gets the queue configuration. 29 | /// 30 | /// 31 | /// The queue configuration. 32 | /// 33 | IQueueConfiguration Configuration { get; } 34 | 35 | 36 | /// 37 | /// Apply default settings to the specified . 38 | /// 39 | /// The message to update. 40 | void ApplyDefaults(Message message); 41 | } 42 | } -------------------------------------------------------------------------------- /src/MongoDB.Messaging/Configuration/IQueueManager.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Concurrent; 3 | using System.Collections.Generic; 4 | using MongoDB.Driver; 5 | 6 | namespace MongoDB.Messaging.Configuration 7 | { 8 | /// 9 | /// An interface defining the queue manager. 10 | /// 11 | public interface IQueueManager 12 | { 13 | /// 14 | /// Gets or sets the name of the connection string. 15 | /// 16 | /// 17 | /// The name of the connection. 18 | /// 19 | string ConnectionString { get; set; } 20 | 21 | /// 22 | /// Gets or sets the name of the connection string for change notification. 23 | /// 24 | /// 25 | /// The name of the connection for change notification. 26 | /// 27 | string NotificationConnection { get; set; } 28 | 29 | /// 30 | /// Gets or sets the name of the service control queue. 31 | /// 32 | /// 33 | /// The name of the service control queue. 34 | /// 35 | string ControlName { get; set; } 36 | 37 | /// 38 | /// Gets the configured queues. 39 | /// 40 | /// 41 | /// The configured queues. 42 | /// 43 | ConcurrentDictionary Queues { get; } 44 | 45 | /// 46 | /// Gets the queues with an active subscriber. 47 | /// 48 | /// 49 | /// The queues with an active subscriber. 50 | /// 51 | IEnumerable Subscriptions { get; } 52 | 53 | /// 54 | /// Gets the underlying storage database. 55 | /// 56 | /// 57 | /// The underlying storage database. 58 | /// 59 | IMongoDatabase Database { get; } 60 | 61 | 62 | /// 63 | /// Registers a queue with the specified configuration. 64 | /// 65 | /// The queue configuration to register. 66 | /// An instance of that was registered. 67 | IQueueContainer Register(IQueueConfiguration queueConfiguration); 68 | 69 | /// 70 | /// Loads the specified queue by name. If the queue has not been configured, it will be created. 71 | /// 72 | /// Name of the queue. 73 | /// An instance of with the queue name. 74 | IQueueContainer Load(string queueName); 75 | 76 | /// 77 | /// Sets the underlying storage . 78 | /// 79 | /// The underlying storage database. 80 | void SetDatabase(IMongoDatabase database); 81 | } 82 | } -------------------------------------------------------------------------------- /src/MongoDB.Messaging/Configuration/QueueContainer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using MongoDB.Messaging.Storage; 3 | 4 | namespace MongoDB.Messaging.Configuration 5 | { 6 | /// 7 | /// A class defining the components that make a up queue. 8 | /// 9 | public class QueueContainer : IQueueContainer 10 | { 11 | /// 12 | /// Initializes a new instance of the class. 13 | /// 14 | /// The queue configuration. 15 | /// The storage repository. 16 | /// 17 | /// configuration 18 | /// or 19 | /// repository 20 | /// 21 | public QueueContainer(IQueueConfiguration configuration, IQueueRepository repository) 22 | { 23 | if (configuration == null) 24 | throw new ArgumentNullException(nameof(configuration)); 25 | 26 | if (repository == null) 27 | throw new ArgumentNullException(nameof(repository)); 28 | 29 | Name = configuration.Name; 30 | Configuration = configuration; 31 | Repository = repository; 32 | } 33 | 34 | /// 35 | /// Gets the name of the queue. 36 | /// 37 | /// 38 | /// The name of the queue. 39 | /// 40 | public string Name { get; } 41 | 42 | /// 43 | /// Gets the storage repository. 44 | /// 45 | /// 46 | /// The storage repository. 47 | /// 48 | public IQueueRepository Repository { get; } 49 | 50 | /// 51 | /// Gets the queue configuration. 52 | /// 53 | /// 54 | /// The queue configuration. 55 | /// 56 | public IQueueConfiguration Configuration { get; } 57 | 58 | 59 | /// 60 | /// Apply default settings to the specified . 61 | /// 62 | /// The message to update. 63 | public void ApplyDefaults(Message message) 64 | { 65 | message.Name = Configuration.Name; 66 | message.RetryCount = Configuration.RetryCount; 67 | message.Priority = (int)Configuration.Priority; 68 | message.ResponseQueue = Configuration.ResponseQueue; 69 | } 70 | } 71 | } -------------------------------------------------------------------------------- /src/MongoDB.Messaging/Extensions/DateTimeExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace MongoDB.Messaging.Extensions 4 | { 5 | /// 6 | /// extension methods 7 | /// 8 | public static class DateTimeExtensions 9 | { 10 | private const long UnixEpochSeconds = 62135596800; 11 | private const long UnixEpochTicks = 621355968000000000; 12 | 13 | /// 14 | /// Returns the number of seconds that have elapsed since 1970-01-01T00:00:00Z. 15 | /// 16 | /// The date time. 17 | /// The number of seconds that have elapsed since 1970-01-01T00:00:00Z. 18 | public static long ToUnixTimeSeconds(this DateTime dateTime) 19 | { 20 | long seconds = dateTime.ToUniversalTime().Ticks / TimeSpan.TicksPerSecond; 21 | return seconds - UnixEpochSeconds; 22 | } 23 | 24 | /// 25 | /// Converts a Unix time expressed as the number of seconds that have elapsed since 1970-01-01T00:00:00Z to a value. 26 | /// 27 | /// A Unix time, expressed as the number of seconds that have elapsed since 1970-01-01T00:00:00Z. 28 | /// A date and time value that represents the same moment in time as the Unix time. 29 | public static DateTime FromUnixTimeSeconds(this long seconds) 30 | { 31 | long ticks = seconds * TimeSpan.TicksPerSecond + UnixEpochTicks; 32 | return new DateTime(ticks, DateTimeKind.Utc); 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /src/MongoDB.Messaging/Extensions/StringExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Text; 4 | using System.Threading.Tasks; 5 | 6 | namespace MongoDB.Messaging.Extensions 7 | { 8 | /// 9 | /// extension methods 10 | /// 11 | public static class StringExtensions 12 | { 13 | /// 14 | /// Compares a string against a wildcard pattern. 15 | /// 16 | /// The string to match. 17 | /// The wildcard pattern. 18 | /// true if the pattern is matched; otherwise false 19 | public static bool Like(this string input, string mask) 20 | { 21 | var inputEnumerator = new TextEnumerator(input); 22 | var maskEnumerator = new TextEnumerator(mask); 23 | 24 | return Like(inputEnumerator, maskEnumerator); 25 | } 26 | 27 | private static bool Like(TextEnumerator inputEnumerator, TextEnumerator maskEnumerator) 28 | { 29 | while (maskEnumerator.MoveNext()) 30 | { 31 | switch (maskEnumerator.Current) 32 | { 33 | case '?': 34 | if (!inputEnumerator.MoveNext()) 35 | return false; 36 | 37 | break; 38 | case '*': 39 | do 40 | { 41 | var inputTryAhead = (TextEnumerator)inputEnumerator.Clone(); 42 | var maskTryAhead = (TextEnumerator)maskEnumerator.Clone(); 43 | if (Like(inputTryAhead, maskTryAhead)) 44 | return true; 45 | 46 | } while (inputEnumerator.MoveNext()); 47 | 48 | return false; 49 | case '\\': // escape 50 | maskEnumerator.MoveNext(); 51 | goto default; 52 | default: 53 | if (!inputEnumerator.MoveNext() || inputEnumerator.Current != maskEnumerator.Current) 54 | return false; 55 | 56 | break; 57 | } 58 | } 59 | 60 | return !inputEnumerator.MoveNext(); 61 | } 62 | 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/MongoDB.Messaging/Extensions/TextEnumerator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | 5 | namespace MongoDB.Messaging.Extensions 6 | { 7 | internal sealed class TextEnumerator : IEnumerator 8 | { 9 | private String _value; 10 | private int _index; 11 | private char _currentElement; 12 | 13 | internal TextEnumerator(String value) 14 | { 15 | _value = value; 16 | _index = -1; 17 | } 18 | 19 | public object Clone() 20 | { 21 | return MemberwiseClone(); 22 | } 23 | 24 | public bool MoveNext() 25 | { 26 | if (_index < (_value.Length - 1)) 27 | { 28 | _index++; 29 | _currentElement = _value[_index]; 30 | return true; 31 | } 32 | 33 | _index = _value.Length; 34 | return false; 35 | } 36 | 37 | public void Dispose() 38 | { 39 | if (_value != null) 40 | _index = _value.Length; 41 | 42 | _value = null; 43 | } 44 | 45 | 46 | public char Current 47 | { 48 | get 49 | { 50 | if (_index == -1) 51 | throw new InvalidOperationException("Enumeration has not started. Call MoveNext."); 52 | 53 | if (_index >= _value.Length) 54 | throw new InvalidOperationException("The enumeration has already completed."); 55 | 56 | return _currentElement; 57 | } 58 | } 59 | 60 | public void Reset() 61 | { 62 | _currentElement = (char)0; 63 | _index = -1; 64 | } 65 | 66 | object IEnumerator.Current => Current; 67 | } 68 | } -------------------------------------------------------------------------------- /src/MongoDB.Messaging/Fluent/PublishQueueBuilder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using MongoDB.Messaging.Configuration; 3 | 4 | namespace MongoDB.Messaging.Fluent 5 | { 6 | /// 7 | /// A fluent builder to help publish a message to a queue 8 | /// 9 | public class PublishQueueBuilder : QueueManagerBase 10 | { 11 | private readonly Message _message; 12 | private IQueueContainer _queueContainer; 13 | 14 | /// 15 | /// Initializes a new instance of the class. 16 | /// 17 | /// The queue manager. 18 | /// The message to update. 19 | public PublishQueueBuilder(IQueueManager manager, Message message) 20 | : base(manager) 21 | { 22 | _message = message; 23 | } 24 | 25 | 26 | /// 27 | /// Gets the message being built. 28 | /// 29 | /// 30 | /// The message being build. 31 | /// 32 | public Message Message => _message; 33 | 34 | /// 35 | /// Gets the queue instance. 36 | /// 37 | /// 38 | /// The queue instance. 39 | /// 40 | public IQueueContainer Container => _queueContainer; 41 | 42 | 43 | /// 44 | /// Start building a message to a queue with the specified name. 45 | /// 46 | /// The name of the queue. 47 | /// A fluent interface to build the queue message. 48 | public MessageBuilder Queue(string name) 49 | { 50 | // load queue, apply defaults to message 51 | _queueContainer = Manager.Load(name); 52 | _queueContainer.ApplyDefaults(_message); 53 | 54 | return new MessageBuilder(_message); ; 55 | } 56 | 57 | } 58 | } -------------------------------------------------------------------------------- /src/MongoDB.Messaging/Fluent/QueueConfigurationBase.cs: -------------------------------------------------------------------------------- 1 | using MongoDB.Messaging.Configuration; 2 | 3 | namespace MongoDB.Messaging.Fluent 4 | { 5 | /// 6 | /// A base queue configuration builder 7 | /// 8 | public class QueueConfigurationBase 9 | { 10 | private readonly IQueueConfiguration _configuration; 11 | 12 | /// 13 | /// Initializes a new instance of the class. 14 | /// 15 | /// The queue configuration. 16 | public QueueConfigurationBase(IQueueConfiguration configuration) 17 | { 18 | _configuration = configuration; 19 | } 20 | 21 | /// 22 | /// Gets the queue configuration. 23 | /// 24 | /// 25 | /// The queue configuration. 26 | /// 27 | public IQueueConfiguration Configuration 28 | { 29 | get { return _configuration; } 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /src/MongoDB.Messaging/Fluent/QueueConfigurationBuilder.cs: -------------------------------------------------------------------------------- 1 | using MongoDB.Messaging.Configuration; 2 | 3 | namespace MongoDB.Messaging.Fluent 4 | { 5 | /// 6 | /// A queue configuration builder 7 | /// 8 | public class QueueConfigurationBuilder : QueueConfigurationBase 9 | { 10 | /// 11 | /// Initializes a new instance of the class. 12 | /// 13 | /// The queue configuration. 14 | public QueueConfigurationBuilder(IQueueConfiguration configuration) 15 | : base(configuration) 16 | { 17 | } 18 | 19 | /// 20 | /// Sets the queue description. 21 | /// 22 | /// The queue description. 23 | /// A fluent to build the queue message. 24 | public QueueConfigurationBuilder Description(string queueDescription) 25 | { 26 | Configuration.Description = queueDescription; 27 | return this; 28 | } 29 | 30 | /// 31 | /// Sets the number of times the message should retry on error. Use zero to prevent retry. 32 | /// 33 | /// The number of retries. 34 | /// 35 | /// A fluent to build the queue configuration. 36 | /// 37 | public QueueConfigurationBuilder Retry(int count) 38 | { 39 | Configuration.RetryCount = count; 40 | return this; 41 | } 42 | 43 | /// 44 | /// Sets the priority of the message in the queue. 45 | /// 46 | /// The priority of the message in the queue. 47 | /// 48 | /// A fluent to build the queue configuration. 49 | /// 50 | public QueueConfigurationBuilder Priority(MessagePriority value) 51 | { 52 | Configuration.Priority = value; 53 | return this; 54 | } 55 | 56 | /// 57 | /// Sets the response queue. 58 | /// 59 | /// Name of the response queue. 60 | /// 61 | /// A fluent to build the queue configuration. 62 | /// 63 | public QueueConfigurationBuilder ResponseQueue(string queueName) 64 | { 65 | Configuration.ResponseQueue = queueName; 66 | return this; 67 | } 68 | } 69 | } -------------------------------------------------------------------------------- /src/MongoDB.Messaging/Fluent/QueueManagerBase.cs: -------------------------------------------------------------------------------- 1 | using MongoDB.Messaging.Configuration; 2 | 3 | namespace MongoDB.Messaging.Fluent 4 | { 5 | /// 6 | /// A queue manager builder base class 7 | /// 8 | public class QueueManagerBase 9 | { 10 | private readonly IQueueManager _manager; 11 | 12 | /// 13 | /// Initializes a new instance of the class. 14 | /// 15 | /// The manager. 16 | public QueueManagerBase(IQueueManager manager) 17 | { 18 | _manager = manager; 19 | } 20 | 21 | /// 22 | /// Gets the queue manager. 23 | /// 24 | /// 25 | /// The queue manager. 26 | /// 27 | public IQueueManager Manager 28 | { 29 | get { return _manager; } 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /src/MongoDB.Messaging/Fluent/QueueManagerBuilder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using MongoDB.Messaging.Configuration; 7 | 8 | namespace MongoDB.Messaging.Fluent 9 | { 10 | /// 11 | /// A queue manager fluent builder. 12 | /// 13 | public class QueueManagerBuilder : QueueManagerBase 14 | { 15 | /// 16 | /// Initializes a new instance of the class. 17 | /// 18 | /// The queue manager. 19 | public QueueManagerBuilder(IQueueManager manager) 20 | : base(manager) 21 | { 22 | } 23 | 24 | /// 25 | /// Sets the name of the connection string. 26 | /// 27 | /// The connection string. 28 | /// 29 | /// A fluent for the queue manager. 30 | /// 31 | public QueueManagerBuilder ConnectionString(string connectionString) 32 | { 33 | Manager.ConnectionString = connectionString; 34 | return this; 35 | } 36 | 37 | /// 38 | /// Sets the name of the notification connection string. 39 | /// 40 | /// The name of the notification connection string. 41 | /// 42 | /// A fluent for the queue manager. 43 | /// 44 | public QueueManagerBuilder Notification(string name) 45 | { 46 | Manager.NotificationConnection = name; 47 | return this; 48 | } 49 | 50 | /// 51 | /// Sets the name of the service control queue. 52 | /// 53 | /// The name of the service control queue. 54 | /// 55 | /// A fluent for the queue manager. 56 | /// 57 | public QueueManagerBuilder ControlQueue(string name) 58 | { 59 | Manager.ControlName = name; 60 | return this; 61 | } 62 | 63 | /// 64 | /// Configure a message queue using the specified builder. 65 | /// 66 | /// The fluent builder. 67 | /// 68 | /// A fluent for the queue manager. 69 | /// 70 | public QueueManagerBuilder Queue(Action builder) 71 | { 72 | var queueLoaderBuilder = new QueueNameBuilder(Manager); 73 | builder(queueLoaderBuilder); 74 | 75 | return this; 76 | } 77 | 78 | /// 79 | /// Configure a subscription to a message queue using the specified builder. 80 | /// 81 | /// The fluent builder. 82 | /// 83 | /// A fluent for the queue manager. 84 | /// 85 | public QueueManagerBuilder Subscribe(Action builder) 86 | { 87 | var queueLoaderBuilder = new SubscriberQueueBuilder(Manager); 88 | builder(queueLoaderBuilder); 89 | 90 | return this; 91 | } 92 | 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/MongoDB.Messaging/Fluent/QueueNameBuilder.cs: -------------------------------------------------------------------------------- 1 | using MongoDB.Messaging.Configuration; 2 | 3 | namespace MongoDB.Messaging.Fluent 4 | { 5 | /// 6 | /// A queue configuration builder 7 | /// 8 | public class QueueNameBuilder : QueueManagerBase 9 | { 10 | /// 11 | /// Initializes a new instance of the class. 12 | /// 13 | /// The queue manager. 14 | public QueueNameBuilder(IQueueManager manager) 15 | : base(manager) 16 | { 17 | } 18 | 19 | /// 20 | /// The name of the queue to configure. 21 | /// 22 | /// The queue name. 23 | /// 24 | public QueueConfigurationBuilder Name(string name) 25 | { 26 | // load queue 27 | var queue = Manager.Load(name); 28 | var configuration = queue.Configuration; 29 | 30 | return new QueueConfigurationBuilder(configuration); 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /src/MongoDB.Messaging/Fluent/ScheduleQueueBuilder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using MongoDB.Messaging.Configuration; 3 | 4 | namespace MongoDB.Messaging.Fluent 5 | { 6 | /// 7 | /// A fluent builder to schedule a message for processing. 8 | /// 9 | public class ScheduleQueueBuilder : QueueManagerBase 10 | { 11 | private readonly Message _message; 12 | private PublishQueueBuilder _queueBuilder; 13 | 14 | 15 | /// 16 | /// Initializes a new instance of the class. 17 | /// 18 | /// The queue manager. 19 | /// The message to update. 20 | public ScheduleQueueBuilder(IQueueManager manager, Message message) : base(manager) 21 | { 22 | _message = message; 23 | } 24 | 25 | /// 26 | /// Gets the message being built. 27 | /// 28 | /// 29 | /// The message being build. 30 | /// 31 | public Message Message 32 | { 33 | get { return _message; } 34 | } 35 | 36 | /// 37 | /// Gets the queue instance. 38 | /// 39 | /// 40 | /// The queue instance. 41 | /// 42 | public IQueueContainer Container 43 | { 44 | get { return _queueBuilder?.Container; } 45 | } 46 | 47 | /// 48 | /// Start building a scheduled message to a queue with the specified date of processing. 49 | /// 50 | /// The the message is scheduled for processing on. 51 | /// 52 | /// A fluent interface to build the queue message. 53 | /// 54 | public PublishQueueBuilder Schedule(DateTime value) 55 | { 56 | _message.Scheduled = value; 57 | 58 | _queueBuilder = new PublishQueueBuilder(Manager, _message); 59 | 60 | return _queueBuilder; 61 | } 62 | } 63 | } -------------------------------------------------------------------------------- /src/MongoDB.Messaging/Fluent/SubscriberQueueBuilder.cs: -------------------------------------------------------------------------------- 1 | using MongoDB.Messaging.Configuration; 2 | 3 | namespace MongoDB.Messaging.Fluent 4 | { 5 | /// 6 | /// A queue subscriber configuration builder 7 | /// 8 | public class SubscriberQueueBuilder : QueueManagerBase 9 | { 10 | /// 11 | /// Initializes a new instance of the class. 12 | /// 13 | /// The queue manager. 14 | public SubscriberQueueBuilder(IQueueManager manager) 15 | : base(manager) 16 | { 17 | } 18 | 19 | /// 20 | /// The queue name to configure a subscriber for 21 | /// 22 | /// The queue name. 23 | /// 24 | public SubscriberBuilder Queue(string name) 25 | { 26 | // load queue, apply defaults to message 27 | var queue = Manager.Load(name); 28 | var configuration = queue.Configuration; 29 | 30 | return new SubscriberBuilder(configuration); 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /src/MongoDB.Messaging/Locks/ILockManager.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace MongoDB.Messaging.Locks 4 | { 5 | /// 6 | /// An defining a MongoDB lock manager. 7 | /// 8 | public interface ILockManager 9 | { 10 | /// 11 | /// Acquire a lock with the specified . 12 | /// 13 | /// The name of the lock. 14 | /// true if the lock was acquired; otherwise false 15 | bool Acquire(string name); 16 | 17 | /// 18 | /// Acquire a lock with the specified and . 19 | /// 20 | /// The name of the lock. 21 | /// The amount of time before the lock will expire and be free to be acquired again. 22 | /// true if the lock was acquired; otherwise false 23 | bool Acquire(string name, TimeSpan expiration); 24 | 25 | /// 26 | /// Gets the status of a lock the specified . 27 | /// 28 | /// The name of the lock. 29 | /// An object with status data about the lock. 30 | LockData Status(string name); 31 | 32 | /// 33 | /// Renew the expiration of a lock with the specified . 34 | /// 35 | /// The name of the lock. 36 | void Renew(string name); 37 | 38 | /// 39 | /// Renew the expiration of a lock with the specified and . 40 | /// 41 | /// The name of the lock. 42 | /// The amount of time before the lock will expire and be free to be acquired again. 43 | void Renew(string name, TimeSpan expiration); 44 | 45 | /// 46 | /// Release a lock with the specified . 47 | /// 48 | /// The name of the lock. 49 | void Release(string name); 50 | } 51 | } -------------------------------------------------------------------------------- /src/MongoDB.Messaging/Locks/LockData.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using MongoDB.Bson.Serialization.Attributes; 3 | using MongoDB.Bson.Serialization.IdGenerators; 4 | 5 | namespace MongoDB.Messaging.Locks 6 | { 7 | /// 8 | /// The status of a lock 9 | /// 10 | public class LockData 11 | { 12 | /// 13 | /// Gets or sets the identifier for the lock. 14 | /// 15 | /// 16 | /// The identifier for the lock. 17 | /// 18 | [BsonId(IdGenerator = typeof(NullIdChecker))] 19 | public string Id { get; set; } 20 | 21 | /// 22 | /// Gets or sets a value indicating whether this instance is locked. 23 | /// 24 | /// 25 | /// true if this instance is locked; otherwise, false. 26 | /// 27 | public bool IsLocked { get; set; } 28 | 29 | /// 30 | /// Gets or sets the name of the user who acquired the lock. 31 | /// 32 | /// 33 | /// The name of the user who acquired the lock. 34 | /// 35 | [BsonIgnoreIfNull] 36 | public string UserName { get; set; } 37 | 38 | /// 39 | /// Gets or sets the name of the machine. 40 | /// 41 | /// 42 | /// The name of the machine. 43 | /// 44 | [BsonIgnoreIfNull] 45 | public string MachineName { get; set; } 46 | 47 | /// 48 | /// Gets or sets the process identifier. 49 | /// 50 | /// 51 | /// The process identifier. 52 | /// 53 | [BsonIgnoreIfNull] 54 | public int? Process { get; set; } 55 | 56 | /// 57 | /// Gets or sets the date the lock was created in UTC time. 58 | /// 59 | /// 60 | /// The date the lock was created in UTC time. 61 | /// 62 | public DateTime Created { get; set; } 63 | 64 | /// 65 | /// Gets or sets the date the lock was updated in UTC time. 66 | /// 67 | /// 68 | /// The date the lock was updated in UTC time. 69 | /// 70 | public DateTime Updated { get; set; } 71 | 72 | /// 73 | /// Gets or sets the date and time that this lock will expire and be free to be acquired. 74 | /// 75 | /// 76 | /// The date and time that this lock will expire and be free to be acquired. 77 | /// 78 | [BsonIgnoreIfNull] 79 | public DateTime? Expire { get; set; } 80 | } 81 | } -------------------------------------------------------------------------------- /src/MongoDB.Messaging/Logging/DelegateLogWriter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace MongoDB.Messaging.Logging 4 | { 5 | /// 6 | /// A log writer. 7 | /// 8 | public class DelegateLogWriter : ILogWriter 9 | { 10 | private readonly Action _logAction; 11 | 12 | /// 13 | /// Initializes a new instance of the class. 14 | /// 15 | public DelegateLogWriter() : this(null) 16 | { 17 | } 18 | 19 | /// 20 | /// Initializes a new instance of the class. 21 | /// 22 | /// The log action. 23 | public DelegateLogWriter(Action logAction) 24 | { 25 | _logAction = logAction ?? DebugWrite; 26 | } 27 | 28 | /// 29 | /// Writes the specified to the underlying logger. 30 | /// 31 | /// The log data to write. 32 | public void WriteLog(LogData logData) 33 | { 34 | _logAction?.Invoke(logData); 35 | } 36 | 37 | private static void DebugWrite(LogData logData) 38 | { 39 | System.Diagnostics.Debug.WriteLine(logData); 40 | } 41 | 42 | } 43 | } -------------------------------------------------------------------------------- /src/MongoDB.Messaging/Logging/DisposeAction.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace MongoDB.Messaging.Logging 4 | { 5 | /// 6 | /// A class that will call an when Disposed. 7 | /// 8 | public class DisposeAction : IDisposable 9 | { 10 | private readonly Action _exitAction; 11 | 12 | /// 13 | /// Initializes a new instance of the class. 14 | /// 15 | /// The exit action. 16 | public DisposeAction(Action exitAction) 17 | { 18 | _exitAction = exitAction; 19 | } 20 | 21 | /// 22 | /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. 23 | /// 24 | void IDisposable.Dispose() 25 | { 26 | _exitAction.Invoke(); 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /src/MongoDB.Messaging/Logging/ILogWriter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace MongoDB.Messaging.Logging 4 | { 5 | /// 6 | /// An interface defining a log writer. 7 | /// 8 | public interface ILogWriter 9 | { 10 | /// 11 | /// Writes the specified to the underlying logger. 12 | /// 13 | /// The log data to write. 14 | void WriteLog(LogData logData); 15 | } 16 | } -------------------------------------------------------------------------------- /src/MongoDB.Messaging/Logging/ILogger.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace MongoDB.Messaging.Logging 4 | { 5 | /// 6 | /// A logger for starting log messages. 7 | /// 8 | public interface ILogger 9 | { 10 | /// 11 | /// Gets the logger name. 12 | /// 13 | /// 14 | /// The logger name. 15 | /// 16 | string Name { get; } 17 | 18 | /// 19 | /// Gets the logger initial default properties. All values are copied to each log. 20 | /// 21 | /// 22 | /// The logger initial default properties. 23 | /// 24 | IPropertyContext Properties { get; } 25 | 26 | 27 | /// 28 | /// Start a fluent with the specified . 29 | /// 30 | /// The log level. 31 | /// 32 | /// A fluent Logger instance. 33 | /// 34 | ILogBuilder Log(LogLevel logLevel); 35 | 36 | /// 37 | /// Start a fluent with the computed . 38 | /// 39 | /// The log level factory. 40 | /// 41 | /// A fluent Logger instance. 42 | /// 43 | ILogBuilder Log(Func logLevelFactory); 44 | 45 | /// 46 | /// Start a fluent logger. 47 | /// 48 | /// A fluent Logger instance. 49 | ILogBuilder Trace(); 50 | 51 | /// 52 | /// Start a fluent logger. 53 | /// 54 | /// A fluent Logger instance. 55 | ILogBuilder Debug(); 56 | 57 | /// 58 | /// Start a fluent logger. 59 | /// 60 | /// A fluent Logger instance. 61 | ILogBuilder Info(); 62 | 63 | /// 64 | /// Start a fluent logger. 65 | /// 66 | /// A fluent Logger instance. 67 | ILogBuilder Warn(); 68 | 69 | /// 70 | /// Start a fluent logger. 71 | /// 72 | /// A fluent Logger instance. 73 | ILogBuilder Error(); 74 | 75 | /// 76 | /// Start a fluent logger. 77 | /// 78 | /// A fluent Logger instance. 79 | ILogBuilder Fatal(); 80 | } 81 | } -------------------------------------------------------------------------------- /src/MongoDB.Messaging/Logging/IPropertyContext.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace MongoDB.Messaging.Logging 5 | { 6 | /// 7 | /// An defining a logger property context. 8 | /// 9 | public interface IPropertyContext 10 | { 11 | /// 12 | /// Applies the context properties to the specified . 13 | /// 14 | /// The builder to copy the properties to. 15 | void Apply(ILogBuilder builder); 16 | 17 | /// 18 | /// Removes all keys and values from the property context 19 | /// 20 | void Clear(); 21 | 22 | /// 23 | /// Determines whether the property context contains the specified . 24 | /// 25 | /// The key to locate in the property context. 26 | /// true if the property context contains an element with the specified ; otherwise, false. 27 | bool Contains(string key); 28 | 29 | /// 30 | /// Gets the value associated with the specified . 31 | /// 32 | /// The key of the value to get. 33 | /// The value associated with the specified , if the key is found; otherwise . 34 | object Get(string key); 35 | 36 | /// 37 | /// Gets the keys in the property context. 38 | /// 39 | /// The keys in the property context. 40 | IEnumerable Keys(); 41 | 42 | /// 43 | /// Removes the value with the specified from the property context. 44 | /// 45 | /// The key of the element to remove. 46 | /// true if the element is successfully found and removed; otherwise, false. This method returns false if key is not found. 47 | bool Remove(string key); 48 | 49 | /// 50 | /// Sets the associated with the specified . 51 | /// 52 | /// The key of the value to set. 53 | /// The value associated with the specified key. The value will be converted to a string. 54 | /// An that will remove the key on dispose. 55 | IDisposable Set(string key, object value); 56 | } 57 | } -------------------------------------------------------------------------------- /src/MongoDB.Messaging/Logging/LogLevel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace MongoDB.Messaging.Logging 4 | { 5 | /// 6 | /// Defines available log levels. 7 | /// 8 | public enum LogLevel 9 | { 10 | /// Trace log level. 11 | Trace = 0, 12 | /// Debug log level. 13 | Debug = 1, 14 | /// Info log level. 15 | Info = 2, 16 | /// Warn log level. 17 | Warn = 3, 18 | /// Error log level. 19 | Error = 4, 20 | /// Fatal log level. 21 | Fatal = 5, 22 | } 23 | } -------------------------------------------------------------------------------- /src/MongoDB.Messaging/Logging/LoggerCreateBuilder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace MongoDB.Messaging.Logging 4 | { 5 | /// 6 | /// A fluent class to build a logger. 7 | /// 8 | public class LoggerCreateBuilder 9 | { 10 | private readonly Logger _logger; 11 | 12 | /// 13 | /// Initializes a new instance of the class. 14 | /// 15 | /// The factory. 16 | public LoggerCreateBuilder(Logger logger) 17 | { 18 | if (logger == null) 19 | throw new ArgumentNullException(nameof(logger)); 20 | 21 | _logger = logger; 22 | } 23 | 24 | 25 | /// 26 | /// Sets the initial logger name for the logging event. 27 | /// 28 | /// The name of the logger. 29 | /// 30 | public LoggerCreateBuilder Logger(string logger) 31 | { 32 | _logger.Name = logger; 33 | 34 | return this; 35 | } 36 | 37 | /// 38 | /// Sets the initial logger name using the generic type. 39 | /// 40 | /// The type of the logger. 41 | /// 42 | public LoggerCreateBuilder Logger() 43 | { 44 | _logger.Name = typeof(TLogger).FullName; 45 | 46 | return this; 47 | } 48 | 49 | /// 50 | /// Sets the initial logger name using the specified type. 51 | /// 52 | /// The type of the logger. 53 | /// 54 | public LoggerCreateBuilder Logger(Type type) 55 | { 56 | if (type == null) 57 | throw new ArgumentNullException(nameof(type)); 58 | 59 | _logger.Name = type.FullName; 60 | 61 | return this; 62 | } 63 | 64 | 65 | /// 66 | /// Sets an initial log context property on the logging event. 67 | /// 68 | /// The name of the context property. 69 | /// The value of the context property. 70 | /// 71 | /// name 72 | public LoggerCreateBuilder Property(string name, object value) 73 | { 74 | if (name == null) 75 | throw new ArgumentNullException(nameof(name)); 76 | 77 | _logger.Properties.Set(name, value); 78 | return this; 79 | } 80 | } 81 | } -------------------------------------------------------------------------------- /src/MongoDB.Messaging/Logging/LoggerExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace MongoDB.Messaging.Logging 8 | { 9 | /// 10 | /// Extension methods for 11 | /// 12 | public static class LoggerExtensions 13 | { 14 | /// 15 | /// Write a trace level log with specified message formatting . 16 | /// 17 | /// The logger to write to. 18 | /// The used to generate the log message. 19 | public static void Trace(this ILogger logger, Func messageFormatter) 20 | { 21 | logger.Trace().Message(messageFormatter).Write(); 22 | } 23 | 24 | /// 25 | /// Write a debug level log with specified message formatting . 26 | /// 27 | /// The used to generate the log message. 28 | /// The logger to write to. 29 | public static void Debug(this ILogger logger, Func messageFormatter) 30 | { 31 | logger.Debug().Message(messageFormatter).Write(); 32 | } 33 | 34 | /// 35 | /// Write a info level log with specified message formatting . 36 | /// 37 | /// The used to generate the log message. 38 | /// The logger to write to. 39 | public static void Info(this ILogger logger, Func messageFormatter) 40 | { 41 | logger.Info().Message(messageFormatter).Write(); 42 | } 43 | 44 | /// 45 | /// Write a warn level log with specified message formatting . 46 | /// 47 | /// The used to generate the log message. 48 | /// The logger to write to. 49 | public static void Warn(this ILogger logger, Func messageFormatter) 50 | { 51 | logger.Warn().Message(messageFormatter).Write(); 52 | } 53 | 54 | /// 55 | /// Write a error level log with specified message formatting . 56 | /// 57 | /// The used to generate the log message. 58 | /// The logger to write to. 59 | public static void Error(this ILogger logger, Func messageFormatter) 60 | { 61 | logger.Error().Message(messageFormatter).Write(); 62 | } 63 | 64 | /// 65 | /// Write a fatal level log with specified message formatting . 66 | /// 67 | /// The used to generate the log message. 68 | /// The logger to write to. 69 | public static void Fatal(this ILogger logger, Func messageFormatter) 70 | { 71 | logger.Fatal().Message(messageFormatter).Write(); 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/MongoDB.Messaging/Logging/LoggerFactory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace MongoDB.Messaging.Logging 4 | { 5 | /// 6 | /// A factory for creating instances using as the name of the logger. 7 | /// 8 | /// The type used to name the . 9 | public interface ILoggerFactory 10 | { 11 | /// 12 | /// Create an instance of using as the logger name. 13 | /// 14 | /// An instace of . 15 | ILogger CreateLogger(); 16 | } 17 | 18 | /// 19 | /// A factory for creating instances using as the name of the logger. 20 | /// 21 | /// The type used to name the . 22 | public class LoggerFactory : ILoggerFactory 23 | { 24 | // lazy singleton of logger 25 | private static readonly Lazy _logger = new Lazy(Logger.CreateLogger); 26 | 27 | /// 28 | /// Create an instance of using as the logger name. 29 | /// 30 | /// 31 | /// An instace of . 32 | /// 33 | public ILogger CreateLogger() 34 | { 35 | return _logger.Value; 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/MongoDB.Messaging/Logging/TraceLogWriter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | 4 | #if !PORTABLE 5 | namespace MongoDB.Messaging.Logging 6 | { 7 | 8 | /// 9 | /// A system trace log writer 10 | /// 11 | public class TraceLogWriter : ILogWriter 12 | { 13 | private static readonly Lazy _traceSource; 14 | 15 | /// 16 | /// Initializes the class. 17 | /// 18 | static TraceLogWriter() 19 | { 20 | _traceSource = new Lazy(() => new TraceSource(typeof(Logger).FullName, SourceLevels.Information)); 21 | } 22 | 23 | /// 24 | /// Writes the specified LogData to the underlying logger. 25 | /// 26 | /// The log data. 27 | public void WriteLog(LogData logData) 28 | { 29 | var eventType = ToEventType(logData.LogLevel); 30 | if (logData.Parameters != null && logData.Parameters.Length > 0) 31 | _traceSource.Value.TraceEvent(eventType, 1, logData.Message, logData.Parameters); 32 | else 33 | _traceSource.Value.TraceEvent(eventType, 1, logData.Message); 34 | } 35 | 36 | private TraceEventType ToEventType(LogLevel logLevel) 37 | { 38 | switch (logLevel) 39 | { 40 | case LogLevel.Trace: 41 | return TraceEventType.Verbose; 42 | case LogLevel.Debug: 43 | return TraceEventType.Verbose; 44 | case LogLevel.Info: 45 | return TraceEventType.Information; 46 | case LogLevel.Warn: 47 | return TraceEventType.Warning; 48 | case LogLevel.Error: 49 | return TraceEventType.Error; 50 | case LogLevel.Fatal: 51 | return TraceEventType.Critical; 52 | default: 53 | return TraceEventType.Verbose; 54 | } 55 | } 56 | } 57 | } 58 | #endif -------------------------------------------------------------------------------- /src/MongoDB.Messaging/MessagePriority.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace MongoDB.Messaging 4 | { 5 | /// 6 | /// The priority of the message in the queue. 7 | /// 8 | public enum MessagePriority 9 | { 10 | /// 11 | /// The high priority messages will be processed first. 12 | /// 13 | High = 0, 14 | /// 15 | /// The normal prioritymessages will be processed in the order received. 16 | /// 17 | Normal = 1, 18 | /// 19 | /// The low priority messages are processed last. 20 | /// 21 | Low = 2 22 | } 23 | } -------------------------------------------------------------------------------- /src/MongoDB.Messaging/MessageResult.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace MongoDB.Messaging 4 | { 5 | /// 6 | /// The processing result state 7 | /// 8 | public enum MessageResult 9 | { 10 | /// 11 | /// The message has not been processed. 12 | /// 13 | None, 14 | 15 | /// 16 | /// The message processed successfully. 17 | /// 18 | Successful, 19 | /// 20 | /// The message processed succesfully with warnings. 21 | /// 22 | Warning, 23 | /// 24 | /// The message processed with an error. 25 | /// 26 | Error, 27 | 28 | } 29 | } -------------------------------------------------------------------------------- /src/MongoDB.Messaging/MessageState.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace MongoDB.Messaging 4 | { 5 | /// 6 | /// The state of a message in the processing queue. 7 | /// 8 | public enum MessageState 9 | { 10 | /// 11 | /// The messaging is being built and is not ready for processing. 12 | /// 13 | None, 14 | 15 | /// 16 | /// The message is queued and ready for processing. 17 | /// 18 | Queued, 19 | 20 | /// 21 | /// The message is currently being processed. 22 | /// 23 | Processing, 24 | 25 | /// 26 | /// The message has completed processing 27 | /// 28 | Complete, 29 | 30 | /// 31 | /// The message processing timed out 32 | /// 33 | Timeout, 34 | 35 | /// 36 | /// The message is scheduled for future processing. 37 | /// 38 | Scheduled 39 | } 40 | } -------------------------------------------------------------------------------- /src/MongoDB.Messaging/MongoDB.Messaging.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | The MongoDB Messaging library is a lightweight queue pub/sub processing library based on MongoDB data store. 4 | en-US 5 | 2.0.0.0 6 | LoreSoft 7 | net45;netstandard1.5 8 | true 9 | MongoDB.Messaging 10 | MongoDB.Messaging 11 | MongoDB;Messaging 12 | https://github.com/loresoft/MongoDB.Messaging 13 | https://raw.githubusercontent.com/loresoft/MongoDB.Messaging/master/LICENSE 14 | 1.6.0 15 | false 16 | false 17 | false 18 | false 19 | false 20 | false 21 | false 22 | false 23 | false 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /src/MongoDB.Messaging/Service/IMessageProcessor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using MongoDB.Messaging.Configuration; 4 | 5 | namespace MongoDB.Messaging.Service 6 | { 7 | /// 8 | /// 9 | /// 10 | public interface IMessageProcessor 11 | { 12 | /// 13 | /// Gets the name of the processor. 14 | /// 15 | /// 16 | /// The name of the processor. 17 | /// 18 | string Name { get; } 19 | 20 | 21 | /// 22 | /// Gets a value indicating whether the processor is busy. 23 | /// 24 | /// 25 | /// true if this instance is busy; otherwise, false. 26 | /// 27 | bool IsBusy { get; } 28 | 29 | /// 30 | /// The number active workers 31 | /// 32 | int ActiveWorkers { get; } 33 | 34 | 35 | /// 36 | /// Gets the parent service. 37 | /// 38 | /// 39 | /// The parent service. 40 | /// 41 | IMessageService Service { get; } 42 | 43 | /// 44 | /// Gets the queue container for the processor. 45 | /// 46 | /// 47 | /// The queue container for the processor. 48 | /// 49 | IQueueContainer Container { get; } 50 | 51 | /// 52 | /// Gets the queue configuration. 53 | /// 54 | /// 55 | /// The queue configuration. 56 | /// 57 | IQueueConfiguration Configuration { get; } 58 | 59 | /// 60 | /// Gets the list of workers. 61 | /// 62 | /// 63 | /// The list of workers. 64 | /// 65 | IList Workers { get; } 66 | 67 | 68 | /// 69 | /// Start the processor and all the . 70 | /// 71 | void Start(); 72 | 73 | /// 74 | /// Stop the processor and all the . 75 | /// 76 | void Stop(); 77 | 78 | 79 | /// 80 | /// Signal the processor that a worker has begun. 81 | /// 82 | void BeginWork(); 83 | 84 | /// 85 | /// Signal the processor that a worker has ended. 86 | /// 87 | void EndWork(); 88 | } 89 | } -------------------------------------------------------------------------------- /src/MongoDB.Messaging/Service/IMessageService.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using MongoDB.Messaging.Change; 3 | using MongoDB.Messaging.Configuration; 4 | 5 | namespace MongoDB.Messaging.Service 6 | { 7 | /// 8 | /// 9 | /// 10 | public interface IMessageService 11 | { 12 | /// 13 | /// Gets the queue manager for the service. 14 | /// 15 | /// 16 | /// The queue manager for the service. 17 | /// 18 | IQueueManager Manager { get; } 19 | 20 | /// 21 | /// Gets the list of message processors for the service. 22 | /// 23 | /// 24 | /// The list of message processors for the service. 25 | /// 26 | IList Processors { get; } 27 | 28 | /// 29 | /// The number active processes 30 | /// 31 | int ActiveProcesses { get; } 32 | 33 | /// 34 | /// Gets the change notifier service. 35 | /// 36 | /// 37 | /// The change notifier service. 38 | /// 39 | ChangeNotifier Notifier { get; } 40 | 41 | 42 | /// 43 | /// Start the service and all the . 44 | /// 45 | void Start(); 46 | 47 | /// 48 | /// Stop the service and all the . 49 | /// 50 | void Stop(); 51 | 52 | 53 | /// 54 | /// Signal the service that a worker has begun. 55 | /// 56 | void BeginWork(); 57 | 58 | /// 59 | /// Signal the service that a worker has ended. 60 | /// 61 | void EndWork(); 62 | 63 | } 64 | } -------------------------------------------------------------------------------- /src/MongoDB.Messaging/Service/IMessageWorker.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using MongoDB.Messaging.Configuration; 3 | using MongoDB.Messaging.Storage; 4 | 5 | namespace MongoDB.Messaging.Service 6 | { 7 | /// 8 | /// 9 | /// 10 | public interface IMessageWorker 11 | { 12 | /// 13 | /// Gets the name of the worker. 14 | /// 15 | /// 16 | /// The name of the worker. 17 | /// 18 | string Name { get; } 19 | 20 | /// 21 | /// Gets a value indicating whether the worker is busy. 22 | /// 23 | /// 24 | /// true if this instance is busy; otherwise, false. 25 | /// 26 | bool IsBusy { get; } 27 | 28 | /// 29 | /// Gets a value indicating whether the worker is awaiting shutdown. 30 | /// 31 | /// 32 | /// true if worker is awaiting shutdown; otherwise, false. 33 | /// 34 | bool IsAwaitingShutdown { get; } 35 | 36 | 37 | /// 38 | /// Gets the parent processor. 39 | /// 40 | /// 41 | /// The parent processor. 42 | /// 43 | IMessageProcessor Processor { get; } 44 | 45 | /// 46 | /// Gets the queue container for the processor. 47 | /// 48 | /// 49 | /// The queue container for the processor. 50 | /// 51 | IQueueContainer Container { get; } 52 | 53 | /// 54 | /// Gets the queue configuration. 55 | /// 56 | /// 57 | /// The queue configuration. 58 | /// 59 | IQueueConfiguration Configuration { get; } 60 | 61 | /// 62 | /// Gets the storage repository. 63 | /// 64 | /// 65 | /// The storage repository. 66 | /// 67 | IQueueRepository Repository { get; } 68 | 69 | 70 | 71 | /// 72 | /// Start the worker processing messages from the queue. 73 | /// 74 | void Start(); 75 | 76 | /// 77 | /// Stop the worker from processing messages from the queue. 78 | /// 79 | void Stop(); 80 | 81 | /// 82 | /// Trigger immediate processing of the queue. 83 | /// 84 | void Trigger(); 85 | 86 | 87 | /// 88 | /// Signal that the worker has begun. 89 | /// 90 | void BeginWork(); 91 | 92 | /// 93 | /// Signal that the worker has ended. 94 | /// 95 | void EndWork(); 96 | 97 | } 98 | } -------------------------------------------------------------------------------- /src/MongoDB.Messaging/Storage/MongoFactory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using MongoDB.Driver; 3 | 4 | namespace MongoDB.Messaging.Storage 5 | { 6 | /// 7 | /// A helper class for getting MongoDB database connection. 8 | /// 9 | public static class MongoFactory 10 | { 11 | /// 12 | /// Gets the with the specified connection string. 13 | /// 14 | /// The MongoDB connection string. 15 | /// An instance of . 16 | public static IMongoDatabase GetDatabaseFromConnectionString(string connectionString) 17 | { 18 | var mongoUrl = new MongoUrl(connectionString); 19 | return GetDatabaseFromMongoUrl(mongoUrl); 20 | } 21 | 22 | /// 23 | /// Gets the with the specified . 24 | /// 25 | /// The mongo URL. 26 | /// 27 | /// An instance of . 28 | /// 29 | public static IMongoDatabase GetDatabaseFromMongoUrl(MongoUrl mongoUrl) 30 | { 31 | var client = new MongoClient(mongoUrl); 32 | var mongoDatabase = client.GetDatabase(mongoUrl.DatabaseName); 33 | return mongoDatabase; 34 | } 35 | 36 | #if !NETSTANDARD1_5 37 | /// 38 | /// Gets the with the specified connection name. 39 | /// 40 | /// Name of the connection. 41 | /// 42 | /// An instance of . 43 | /// 44 | /// is . 45 | /// No connection string could be found in the application configuration file. 46 | public static IMongoDatabase GetDatabaseFromConnectionName(string connectionName) 47 | { 48 | var mongoUrl = GetMongoUrl(connectionName); 49 | return GetDatabaseFromMongoUrl(mongoUrl); 50 | } 51 | 52 | 53 | /// 54 | /// Gets the with the specified connection name. 55 | /// 56 | /// Name of the connection. 57 | /// 58 | /// An instance of . 59 | /// 60 | /// is . 61 | /// No connection string could be found in the application configuration file. 62 | public static MongoUrl GetMongoUrl(string connectionName) 63 | { 64 | if (connectionName == null) 65 | throw new ArgumentNullException(nameof(connectionName)); 66 | 67 | var settings = System.Configuration.ConfigurationManager.ConnectionStrings[connectionName]; 68 | if (settings == null) 69 | throw new System.Configuration.ConfigurationErrorsException($"No connection string named '{connectionName}' could be found in the application configuration file."); 70 | 71 | string connectionString = settings.ConnectionString; 72 | if (string.IsNullOrEmpty(connectionString)) 73 | throw new System.Configuration.ConfigurationErrorsException($"The connection string '{connectionName}' in the application's configuration file does not contain the required connectionString attribute."); 74 | 75 | var mongoUrl = new MongoUrl(settings.ConnectionString); 76 | return mongoUrl; 77 | } 78 | #endif 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/MongoDB.Messaging/Subscription/IMessageRetry.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace MongoDB.Messaging.Subscription 4 | { 5 | /// 6 | /// An to implement message error retry logic. 7 | /// 8 | public interface IMessageRetry 9 | { 10 | /// 11 | /// Determine if the the message should be retried. 12 | /// 13 | /// The process context. 14 | /// The exception thrown while processing message. 15 | /// true if the message should be retried; otherwise false. 16 | bool ShouldRetry(ProcessContext processContext, Exception exception); 17 | 18 | /// 19 | /// Get the next to attempt retry. 20 | /// 21 | /// The process context. 22 | /// the message should be retried. 23 | DateTime NextAttempt(ProcessContext processContext); 24 | } 25 | } -------------------------------------------------------------------------------- /src/MongoDB.Messaging/Subscription/IMessageSubscriber.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace MongoDB.Messaging.Subscription 4 | { 5 | /// 6 | /// An to implement to process message from a queue. 7 | /// 8 | public interface IMessageSubscriber : IDisposable 9 | { 10 | /// 11 | /// Process a message with the specified process context. 12 | /// 13 | /// The process context. 14 | /// The result to report after processing the message. 15 | MessageResult Process(ProcessContext processContext); 16 | } 17 | } -------------------------------------------------------------------------------- /src/MongoDB.Messaging/Subscription/MessageRetry.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace MongoDB.Messaging.Subscription 4 | { 5 | /// 6 | /// Default implementation of retry logic 7 | /// 8 | public class MessageRetry : IMessageRetry 9 | { 10 | /// 11 | /// Determine if the the message should be retried. 12 | /// 13 | /// The process context. 14 | /// The exception thrown while processing message. 15 | /// 16 | /// true if the message should be retried; otherwise false. 17 | /// 18 | public virtual bool ShouldRetry(ProcessContext processContext, Exception exception) 19 | { 20 | var message = processContext.Message; 21 | 22 | return message.ErrorCount < message.RetryCount; 23 | } 24 | 25 | /// 26 | /// Get the next to attempt retry. 27 | /// 28 | /// The process context. 29 | /// 30 | /// the message should be retried. 31 | /// 32 | public virtual DateTime NextAttempt(ProcessContext processContext) 33 | { 34 | var message = processContext.Message; 35 | 36 | // retry weight, 1 = 1 min, 2 = 30 min, 3 = 2 hrs, 4+ = 8 hrs 37 | if (message.ErrorCount > 3) 38 | return DateTime.Now.AddHours(8); 39 | 40 | if (message.ErrorCount == 3) 41 | return DateTime.Now.AddHours(2); 42 | 43 | if (message.ErrorCount == 2) 44 | return DateTime.Now.AddMinutes(30); 45 | 46 | // default 47 | return DateTime.Now.AddMinutes(1); 48 | } 49 | } 50 | } -------------------------------------------------------------------------------- /src/MongoDB.Messaging/Subscription/ProcessContext.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using MongoDB.Bson.Serialization; 3 | using MongoDB.Messaging.Configuration; 4 | 5 | namespace MongoDB.Messaging.Subscription 6 | { 7 | /// 8 | /// The message processing context. 9 | /// 10 | public class ProcessContext 11 | { 12 | private readonly Message _message; 13 | private readonly IQueueContainer _container; 14 | 15 | /// 16 | /// Initializes a new instance of the class. 17 | /// 18 | /// The message. 19 | /// The collection. 20 | public ProcessContext(Message message, IQueueContainer container) 21 | { 22 | _message = message; 23 | _container = container; 24 | } 25 | 26 | /// 27 | /// Gets the queue message to process. 28 | /// 29 | /// 30 | /// The queue message to process. 31 | /// 32 | public Message Message 33 | { 34 | get { return _message; } 35 | } 36 | 37 | /// 38 | /// Gets the message queue collection. 39 | /// 40 | /// 41 | /// The message queue collection. 42 | /// 43 | public IQueueContainer Container 44 | { 45 | get { return _container; } 46 | } 47 | 48 | /// 49 | /// Get data of type from the . 50 | /// 51 | /// The type of the data. 52 | /// An instance of type . 53 | public TData Data() 54 | { 55 | return BsonSerializer.Deserialize(_message.Data); 56 | } 57 | 58 | /// 59 | /// Writes a status message back to the for the current request. 60 | /// 61 | /// The status message. 62 | /// The current step. 63 | /// 64 | public void UpdateStatus(string message, int? step = null) 65 | { 66 | if (_message == null || _container == null) 67 | return; 68 | 69 | // fire and forget or block? 70 | _container.Repository.UpdateStatus(_message.Id, message, step); 71 | } 72 | } 73 | } -------------------------------------------------------------------------------- /src/MongoDB.Messaging/TimeoutPolicy.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace MongoDB.Messaging 4 | { 5 | /// 6 | /// How a message should be handled on timeout. 7 | /// 8 | public enum TimeoutPolicy 9 | { 10 | /// 11 | /// The message will be failed and no furture processing occurs. 12 | /// 13 | Fail, 14 | 15 | /// 16 | /// The message will be requeued for processing. 17 | /// 18 | Retry 19 | } 20 | } -------------------------------------------------------------------------------- /test/MongoDB.Messaging.Tests/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /test/MongoDB.Messaging.Tests/Configuration/QueueManagerTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using FluentAssertions; 3 | using MongoDB.Messaging.Configuration; 4 | using Xunit; 5 | 6 | namespace MongoDB.Messaging.Tests.Configuration 7 | { 8 | 9 | public class QueueManagerTest 10 | { 11 | [Fact] 12 | public void LoadQueueTest() 13 | { 14 | var manager = new QueueManager(); 15 | var q = manager.Load("test-queue"); 16 | 17 | q.Should().NotBeNull(); 18 | q.Name.Should().Be("test-queue"); 19 | 20 | q.Configuration.Should().NotBeNull(); 21 | q.Repository.Should().NotBeNull(); 22 | 23 | 24 | manager.Queues.Count.Should().Be(1); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /test/MongoDB.Messaging.Tests/Extensions/DateTimeExtensionsTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using FluentAssertions; 3 | using MongoDB.Messaging.Extensions; 4 | using Xunit; 5 | 6 | namespace MongoDB.Messaging.Tests.Extensions 7 | { 8 | public class DateTimeExtensionsTests 9 | { 10 | 11 | [Fact] 12 | public void ToUnix() 13 | { 14 | var dateTime = new DateTime(2016, 3, 24, 21, 44, 35, DateTimeKind.Utc); 15 | var unixTime = dateTime.ToUnixTimeSeconds(); 16 | 17 | unixTime.Should().Be(1458855875); 18 | } 19 | 20 | [Fact] 21 | public void Convert() 22 | { 23 | var dateTime = DateTime.UtcNow; 24 | 25 | var unixTime = dateTime.ToUnixTimeSeconds(); 26 | var fromUnix = unixTime.FromUnixTimeSeconds(); 27 | 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /test/MongoDB.Messaging.Tests/Locks/ThrottleLockTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | using FluentAssertions; 4 | using MongoDB.Driver; 5 | using MongoDB.Messaging.Locks; 6 | using MongoDB.Messaging.Storage; 7 | using Xunit; 8 | 9 | namespace MongoDB.Messaging.Tests.Locks 10 | { 11 | public class ThrottleLockTests 12 | { 13 | [Fact] 14 | public void AcquireBlock() 15 | { 16 | 17 | var lockName = "AcquireBlock" + DateTime.Now.Ticks; 18 | 19 | var collection = GetCollection(); 20 | collection.Should().NotBeNull(); 21 | 22 | var locker = new ThrottleLock(collection, TimeSpan.FromMinutes(5)); 23 | locker.Should().NotBeNull(); 24 | 25 | var result = locker.Acquire(lockName); 26 | result.Should().BeTrue(); 27 | 28 | var status = locker.Status(lockName); 29 | status.Should().NotBeNull(); 30 | status.IsLocked.Should().BeTrue(); 31 | 32 | var blocked = locker.Acquire(lockName); 33 | blocked.Should().BeFalse(); 34 | 35 | } 36 | 37 | [Fact] 38 | public void AcquireExpire() 39 | { 40 | 41 | var lockName = "AcquireExpire" + DateTime.Now.Ticks; 42 | 43 | var collection = GetCollection(); 44 | collection.Should().NotBeNull(); 45 | 46 | var locker = new ThrottleLock(collection); 47 | locker.Should().NotBeNull(); 48 | 49 | var result = locker.Acquire(lockName, TimeSpan.FromMilliseconds(5)); 50 | result.Should().BeTrue(); 51 | 52 | var status = locker.Status(lockName); 53 | status.Should().NotBeNull(); 54 | status.IsLocked.Should().BeTrue(); 55 | 56 | // wait for expire 57 | Thread.Sleep(5); 58 | 59 | var blocked = locker.Acquire(lockName, TimeSpan.FromMilliseconds(5)); 60 | blocked.Should().BeTrue(); 61 | 62 | } 63 | 64 | [Fact] 65 | public void AcquireRelease() 66 | { 67 | 68 | var lockName = "AcquireRelease" + DateTime.Now.Ticks; 69 | 70 | var collection = GetCollection(); 71 | collection.Should().NotBeNull(); 72 | 73 | var locker = new ThrottleLock(collection, TimeSpan.FromMinutes(5)); 74 | locker.Should().NotBeNull(); 75 | 76 | var result = locker.Acquire(lockName); 77 | result.Should().BeTrue(); 78 | 79 | var status = locker.Status(lockName); 80 | status.Should().NotBeNull(); 81 | status.IsLocked.Should().BeTrue(); 82 | 83 | locker.Release(lockName); 84 | 85 | status = locker.Status(lockName); 86 | status.Should().NotBeNull(); 87 | status.IsLocked.Should().BeFalse(); 88 | } 89 | 90 | private static IMongoCollection GetCollection() 91 | { 92 | var database = MongoFactory.GetDatabaseFromConnectionString("mongodb://localhost/Messaging"); 93 | var collection = database.GetCollection("throttle-lock"); 94 | 95 | return collection; 96 | } 97 | 98 | } 99 | } -------------------------------------------------------------------------------- /test/MongoDB.Messaging.Tests/Logging/NLogWriter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using MongoDB.Messaging.Logging; 3 | 4 | namespace MongoDB.Messaging.Tests.Logging 5 | { 6 | /// 7 | /// NLog log writer adapter 8 | /// 9 | public static class NLogWriter 10 | { 11 | /// 12 | /// Writes the specified LogData to NLog. 13 | /// 14 | /// The log data. 15 | public static void WriteLog(LogData logData) 16 | { 17 | var logEvent = logData.ToLogEvent(); 18 | var name = logData.Logger ?? typeof(NLogWriter).FullName; 19 | 20 | var logger = global::NLog.LogManager.GetLogger(name); 21 | logger.Log(logEvent); 22 | } 23 | 24 | /// 25 | /// Converts the LogData to LogEventInfo. 26 | /// 27 | /// The log data. 28 | /// 29 | public static global::NLog.LogEventInfo ToLogEvent(this LogData logData) 30 | { 31 | var logEvent = new global::NLog.LogEventInfo(); 32 | logEvent.TimeStamp = DateTime.Now; 33 | logEvent.Level = logData.LogLevel.ToLogLevel(); 34 | logEvent.LoggerName = logData.Logger; 35 | logEvent.Exception = logData.Exception; 36 | logEvent.FormatProvider = logData.FormatProvider; 37 | logEvent.Message = logData.Message; 38 | logEvent.Parameters = logData.Parameters; 39 | 40 | if (logData.Properties != null) 41 | foreach (var property in logData.Properties) 42 | logEvent.Properties[property.Key] = property.Value; 43 | 44 | logEvent.Properties["CallerMemberName"] = logData.MemberName; 45 | logEvent.Properties["CallerFilePath"] = logData.FilePath; 46 | logEvent.Properties["CallerLineNumber"] = logData.LineNumber; 47 | 48 | return logEvent; 49 | } 50 | 51 | /// 52 | /// Converts the LogLevel to NLog.LogLevel 53 | /// 54 | /// The log level. 55 | /// 56 | public static global::NLog.LogLevel ToLogLevel(this LogLevel logLevel) 57 | { 58 | switch (logLevel) 59 | { 60 | case LogLevel.Fatal: return global::NLog.LogLevel.Fatal; 61 | case LogLevel.Error: return global::NLog.LogLevel.Error; 62 | case LogLevel.Warn: return global::NLog.LogLevel.Warn; 63 | case LogLevel.Info: return global::NLog.LogLevel.Info; 64 | case LogLevel.Trace: return global::NLog.LogLevel.Trace; 65 | } 66 | 67 | return global::NLog.LogLevel.Debug; 68 | } 69 | } 70 | 71 | /// 72 | /// NLog writer adapter 73 | /// 74 | public class NLogAdapter : ILogWriter 75 | { 76 | /// 77 | /// Writes the log. 78 | /// 79 | /// The log data. 80 | public void WriteLog(LogData logData) 81 | { 82 | NLogWriter.WriteLog(logData); 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /test/MongoDB.Messaging.Tests/MessageQueueTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using FluentAssertions; 7 | using MongoDB.Messaging.Configuration; 8 | using MongoDB.Messaging.Tests.Messages; 9 | using MongoDB.Messaging.Tests.Subscription; 10 | using Xunit; 11 | 12 | namespace MongoDB.Messaging.Tests 13 | { 14 | 15 | public class MessageQueueTest 16 | { 17 | 18 | [Fact] 19 | public void Configure() 20 | { 21 | var manager = new QueueManager(); 22 | var messageQueue = new MessageQueue(manager); 23 | 24 | messageQueue.Configure(c => c 25 | .ConnectionString("mongodb://localhost/Messaging-Test") 26 | .ControlQueue("control-name") 27 | .Queue(q => q 28 | .Name("queue-name") 29 | .Description("description") 30 | .Retry(1) 31 | .Priority(MessagePriority.Normal) 32 | .ResponseQueue("response-name") 33 | ) 34 | .Queue(q => q 35 | .Name("queue-blah") 36 | .Description("description") 37 | .Retry(5) 38 | .Priority(MessagePriority.Normal) 39 | .ResponseQueue("response-blah") 40 | ) 41 | .Subscribe(s => s 42 | .Queue("queue-name") 43 | .Handler() 44 | .PollTime(TimeSpan.FromSeconds(10)) 45 | .Workers(2) 46 | ) 47 | .Subscribe(s => s 48 | .Queue("queue-blah") 49 | .PollTime(TimeSpan.FromSeconds(10)) 50 | .Handler(() => new MessageHandler()) 51 | .Workers(2) 52 | .Timeout(TimeSpan.FromMinutes(30)) 53 | .TimeoutAction(TimeoutPolicy.Retry) 54 | ) 55 | ); 56 | 57 | 58 | manager.Should().NotBeNull(); 59 | manager.ConnectionString.Should().Be("mongodb://localhost/Messaging-Test"); 60 | manager.ControlName.Should().Be("control-name"); 61 | 62 | manager.Queues.Count.Should().Be(2); 63 | 64 | var subscriptions = manager.Subscriptions.ToList(); 65 | subscriptions.Count.Should().Be(2); 66 | } 67 | 68 | [Fact] 69 | public async void Publish() 70 | { 71 | var userMessage = UserMessage.Tester(); 72 | 73 | var message = await MessageQueue.Default.Publish(c => c 74 | .Queue("queue-name") 75 | .Name("UserMessage") 76 | .Description("Update User Data") 77 | .Data(userMessage) 78 | ).ConfigureAwait(false); 79 | 80 | message.Id.Should().NotBeNullOrEmpty(); 81 | } 82 | 83 | [Fact] 84 | public async void Schedule() 85 | { 86 | var userMessage = UserMessage.Tester(); 87 | var date = DateTime.Now.AddHours(1); 88 | 89 | var message = await MessageQueue.Default.Schedule(c => c 90 | .Schedule(date) 91 | .Queue("queue-name") 92 | .Data(userMessage) 93 | ).ConfigureAwait(false); 94 | 95 | message.Id.Should().NotBeNullOrEmpty(); 96 | message.State.Should().Be(MessageState.Scheduled); 97 | message.Scheduled.Should().Be(date); 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /test/MongoDB.Messaging.Tests/Messages/UserMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace MongoDB.Messaging.Tests.Messages 4 | { 5 | public class UserMessage 6 | { 7 | public string FirstName { get; set; } 8 | 9 | public string LastName { get; set; } 10 | 11 | public string Email { get; set; } 12 | 13 | public string Phone { get; set; } 14 | 15 | 16 | public static UserMessage Tester() 17 | { 18 | return new UserMessage 19 | { 20 | FirstName = "Test", 21 | LastName = "User", 22 | Email = "test.user@gmail.com", 23 | Phone = "888-555-1212" 24 | }; 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /test/MongoDB.Messaging.Tests/MongoDB.Messaging.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | Library 4 | 5 | 6 | netcoreapp1.0;net452 7 | 1.0.3 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /test/MongoDB.Messaging.Tests/NLog.config: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 19 | 20 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /test/MongoDB.Messaging.Tests/Subscription/MessageHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using MongoDB.Messaging.Subscription; 3 | 4 | namespace MongoDB.Messaging.Tests.Subscription 5 | { 6 | public class MessageHandler : IMessageSubscriber 7 | { 8 | public MessageResult Process(ProcessContext context) 9 | { 10 | return MessageResult.None; 11 | } 12 | 13 | public void Dispose() 14 | { 15 | } 16 | } 17 | } --------------------------------------------------------------------------------