Browse Source

Made tracking operations go to a background queue to be processed.

Teknikode 1 month ago
parent
commit
89ba60b593
31 changed files with 292 additions and 111 deletions
  1. 1
    1
      Teknik/Areas/API/V1/Controllers/AccountAPIv1Controller.cs
  2. 1
    1
      Teknik/Areas/API/V1/Controllers/PasteAPIv1Controller.cs
  3. 1
    1
      Teknik/Areas/API/V1/Controllers/ShortenAPIv1Controller.cs
  4. 1
    1
      Teknik/Areas/API/V1/Controllers/UploadAPIv1Controller.cs
  5. 1
    1
      Teknik/Areas/About/Controllers/AboutController.cs
  6. 1
    1
      Teknik/Areas/Abuse/Controllers/AbuseController.cs
  7. 4
    4
      Teknik/Areas/Admin/Controllers/AdminController.cs
  8. 4
    4
      Teknik/Areas/Blog/Controllers/BlogController.cs
  9. 1
    1
      Teknik/Areas/Contact/Controllers/ContactController.cs
  10. 6
    6
      Teknik/Areas/Error/Controllers/ErrorController.cs
  11. 1
    1
      Teknik/Areas/FAQ/Controllers/FAQController.cs
  12. 1
    1
      Teknik/Areas/Help/Controllers/HelpController.cs
  13. 1
    1
      Teknik/Areas/Home/Controllers/HomeController.cs
  14. 3
    3
      Teknik/Areas/Paste/Controllers/PasteController.cs
  15. 3
    3
      Teknik/Areas/Podcast/Controllers/PodcastController.cs
  16. 1
    1
      Teknik/Areas/Privacy/Controllers/PrivacyController.cs
  17. 3
    3
      Teknik/Areas/RSS/Controllers/RSSController.cs
  18. 2
    2
      Teknik/Areas/Shortener/Controllers/ShortenerController.cs
  19. 1
    1
      Teknik/Areas/Stats/Controllers/StatsController.cs
  20. 1
    1
      Teknik/Areas/TOS/Controllers/TOSController.cs
  21. 3
    3
      Teknik/Areas/Upload/Controllers/UploadController.cs
  22. 17
    17
      Teknik/Areas/User/Controllers/UserController.cs
  23. 4
    4
      Teknik/Areas/Vault/Controllers/VaultController.cs
  24. 31
    18
      Teknik/Filters/TrackDownload.cs
  25. 40
    29
      Teknik/Filters/TrackPageView.cs
  26. 6
    2
      Teknik/Startup.cs
  27. 2
    0
      Tracking/Tracking.csproj
  28. 48
    0
      Tracking/TrackingService.cs
  29. 38
    0
      Utilities/BackgroundTaskQueue.cs
  30. 49
    0
      Utilities/HostedService.cs
  31. 16
    0
      Utilities/IBackgroundTaskQueue.cs

+ 1
- 1
Teknik/Areas/API/V1/Controllers/AccountAPIv1Controller.cs View File

@@ -19,7 +19,7 @@ namespace Teknik.Areas.API.V1.Controllers
19 19
         public AccountAPIv1Controller(ILogger<Logger> logger, Config config, TeknikEntities dbContext) : base(logger, config, dbContext) { }
20 20
 
21 21
         [HttpGet]
22
-        [ServiceFilter(typeof(TrackPageView))]
22
+        [TrackPageView]
23 23
         public IActionResult GetClaims()
24 24
         {
25 25
             return new JsonResult(from c in User.Claims select new { c.Type, c.Value });

+ 1
- 1
Teknik/Areas/API/V1/Controllers/PasteAPIv1Controller.cs View File

@@ -25,7 +25,7 @@ namespace Teknik.Areas.API.V1.Controllers
25 25
 
26 26
         [HttpPost]
27 27
         [AllowAnonymous]
28
-        [ServiceFilter(typeof(TrackPageView))]
28
+        [TrackPageView]
29 29
         public IActionResult Paste(PasteAPIv1Model model)
30 30
         {
31 31
             try

+ 1
- 1
Teknik/Areas/API/V1/Controllers/ShortenAPIv1Controller.cs View File

@@ -26,7 +26,7 @@ namespace Teknik.Areas.API.V1.Controllers
26 26
 
27 27
         [HttpPost]
28 28
         [AllowAnonymous]
29
-        [ServiceFilter(typeof(TrackPageView))]
29
+        [TrackPageView]
30 30
         public IActionResult Shorten(ShortenAPIv1Model model)
31 31
         {
32 32
             try

+ 1
- 1
Teknik/Areas/API/V1/Controllers/UploadAPIv1Controller.cs View File

@@ -30,7 +30,7 @@ namespace Teknik.Areas.API.V1.Controllers
30 30
 
31 31
         [HttpPost]
32 32
         [AllowAnonymous]
33
-        [ServiceFilter(typeof(TrackPageView))]
33
+        [TrackPageView]
34 34
         public async Task<IActionResult> Upload(UploadAPIv1Model model)
35 35
         {
36 36
             try

+ 1
- 1
Teknik/Areas/About/Controllers/AboutController.cs View File

@@ -22,7 +22,7 @@ namespace Teknik.Areas.About.Controllers
22 22
         public AboutController(ILogger<Logger> logger, Config config, TeknikEntities dbContext) : base(logger, config, dbContext) { }
23 23
 
24 24
         [AllowAnonymous]
25
-        [ServiceFilter(typeof(TrackPageView))]
25
+        [TrackPageView]
26 26
         public IActionResult Index([FromServices] Config config)
27 27
         {
28 28
             ViewBag.Title = "About";

+ 1
- 1
Teknik/Areas/Abuse/Controllers/AbuseController.cs View File

@@ -22,7 +22,7 @@ namespace Teknik.Areas.Abuse.Controllers
22 22
         public AbuseController(ILogger<Logger> logger, Config config, TeknikEntities dbContext) : base(logger, config, dbContext) { }
23 23
         
24 24
         [AllowAnonymous]
25
-        [ServiceFilter(typeof(TrackPageView))]
25
+        [TrackPageView]
26 26
         public IActionResult Index()
27 27
         {
28 28
             ViewBag.Title = "Abuse Reporting";

+ 4
- 4
Teknik/Areas/Admin/Controllers/AdminController.cs View File

@@ -29,7 +29,7 @@ namespace Teknik.Areas.Admin.Controllers
29 29
         public AdminController(ILogger<Logger> logger, Config config, TeknikEntities dbContext) : base (logger, config, dbContext) { }
30 30
 
31 31
         [HttpGet]
32
-        [ServiceFilter(typeof(TrackPageView))]
32
+        [TrackPageView]
33 33
         public IActionResult Dashboard()
34 34
         {
35 35
             DashboardViewModel model = new DashboardViewModel();
@@ -37,7 +37,7 @@ namespace Teknik.Areas.Admin.Controllers
37 37
         }
38 38
 
39 39
         [HttpGet]
40
-        [ServiceFilter(typeof(TrackPageView))]
40
+        [TrackPageView]
41 41
         public IActionResult UserSearch()
42 42
         {
43 43
             UserSearchViewModel model = new UserSearchViewModel();
@@ -45,7 +45,7 @@ namespace Teknik.Areas.Admin.Controllers
45 45
         }
46 46
 
47 47
         [HttpGet]
48
-        [ServiceFilter(typeof(TrackPageView))]
48
+        [TrackPageView]
49 49
         public async Task<IActionResult> UserInfo(string username)
50 50
         {
51 51
             if (UserHelper.UserExists(_dbContext, username))
@@ -66,7 +66,7 @@ namespace Teknik.Areas.Admin.Controllers
66 66
         }
67 67
 
68 68
         [HttpGet]
69
-        [ServiceFilter(typeof(TrackPageView))]
69
+        [TrackPageView]
70 70
         public IActionResult UploadSearch()
71 71
         {
72 72
             UploadSearchViewModel model = new UploadSearchViewModel();

+ 4
- 4
Teknik/Areas/Blog/Controllers/BlogController.cs View File

@@ -30,7 +30,7 @@ namespace Teknik.Areas.Blog.Controllers
30 30
         public BlogController(ILogger<Logger> logger, Config config, TeknikEntities dbContext) : base(logger, config, dbContext) { }
31 31
         
32 32
         [AllowAnonymous]
33
-        [ServiceFilter(typeof(TrackPageView))]
33
+        [TrackPageView]
34 34
         public IActionResult Blog(string username)
35 35
         {
36 36
             BlogViewModel model = new BlogViewModel();
@@ -120,7 +120,7 @@ namespace Teknik.Areas.Blog.Controllers
120 120
 
121 121
         #region Posts
122 122
         [AllowAnonymous]
123
-        [ServiceFilter(typeof(TrackPageView))]
123
+        [TrackPageView]
124 124
         public IActionResult Post(string username, int id)
125 125
         {
126 126
             if (string.IsNullOrEmpty(username))
@@ -163,7 +163,7 @@ namespace Teknik.Areas.Blog.Controllers
163 163
             return View("~/Areas/Blog/Views/Blog/ViewPost.cshtml", model);
164 164
         }
165 165
 
166
-        [ServiceFilter(typeof(TrackPageView))]
166
+        [TrackPageView]
167 167
         public IActionResult NewPost(string username, int blogID)
168 168
         {
169 169
             if (string.IsNullOrEmpty(username))
@@ -203,7 +203,7 @@ namespace Teknik.Areas.Blog.Controllers
203 203
             return View("~/Areas/Blog/Views/Blog/Blog.cshtml", model);
204 204
         }
205 205
 
206
-        [ServiceFilter(typeof(TrackPageView))]
206
+        [TrackPageView]
207 207
         public IActionResult EditPost(string username, int id)
208 208
         {
209 209
             if (string.IsNullOrEmpty(username))

+ 1
- 1
Teknik/Areas/Contact/Controllers/ContactController.cs View File

@@ -26,7 +26,7 @@ namespace Teknik.Areas.Contact.Controllers
26 26
         public ContactController(ILogger<Logger> logger, Config config, TeknikEntities dbContext) : base(logger, config, dbContext) { }
27 27
         
28 28
         [AllowAnonymous]
29
-        [ServiceFilter(typeof(TrackPageView))]
29
+        [TrackPageView]
30 30
         public IActionResult Index()
31 31
         {
32 32
             ViewBag.Title = "Contact Us";

+ 6
- 6
Teknik/Areas/Error/Controllers/ErrorController.cs View File

@@ -28,7 +28,7 @@ namespace Teknik.Areas.Error.Controllers
28 28
         public ErrorController(ILogger<Logger> logger, Config config, TeknikEntities dbContext) : base(logger, config, dbContext) { }
29 29
 
30 30
         [AllowAnonymous]
31
-        [ServiceFilter(typeof(TrackPageView))]
31
+        [TrackPageView]
32 32
         public IActionResult HttpError(int statusCode)
33 33
         {
34 34
             switch (statusCode)
@@ -45,7 +45,7 @@ namespace Teknik.Areas.Error.Controllers
45 45
         }
46 46
 
47 47
         [AllowAnonymous]
48
-        [ServiceFilter(typeof(TrackPageView))]
48
+        [TrackPageView]
49 49
         public IActionResult HttpGeneral(int statusCode)
50 50
         {
51 51
             ViewBag.Title = statusCode;
@@ -59,7 +59,7 @@ namespace Teknik.Areas.Error.Controllers
59 59
         }
60 60
 
61 61
         [AllowAnonymous]
62
-        [ServiceFilter(typeof(TrackPageView))]
62
+        [TrackPageView]
63 63
         public IActionResult Http401()
64 64
         {
65 65
             Response.StatusCode = StatusCodes.Status401Unauthorized;
@@ -76,7 +76,7 @@ namespace Teknik.Areas.Error.Controllers
76 76
         }
77 77
 
78 78
         [AllowAnonymous]
79
-        [ServiceFilter(typeof(TrackPageView))]
79
+        [TrackPageView]
80 80
         public IActionResult Http403()
81 81
         {
82 82
             Response.StatusCode = StatusCodes.Status403Forbidden;
@@ -93,7 +93,7 @@ namespace Teknik.Areas.Error.Controllers
93 93
         }
94 94
 
95 95
         [AllowAnonymous]
96
-        [ServiceFilter(typeof(TrackPageView))]
96
+        [TrackPageView]
97 97
         public IActionResult Http404()
98 98
         {
99 99
             Response.StatusCode = StatusCodes.Status404NotFound;
@@ -110,7 +110,7 @@ namespace Teknik.Areas.Error.Controllers
110 110
         }
111 111
         
112 112
         [AllowAnonymous]
113
-        [ServiceFilter(typeof(TrackPageView))]
113
+        [TrackPageView]
114 114
         public IActionResult Http500(Exception exception)
115 115
         {
116 116
             try

+ 1
- 1
Teknik/Areas/FAQ/Controllers/FAQController.cs View File

@@ -18,7 +18,7 @@ namespace Teknik.Areas.FAQ.Controllers
18 18
         public FAQController(ILogger<Logger> logger, Config config, TeknikEntities dbContext) : base(logger, config, dbContext) { }
19 19
         
20 20
         [AllowAnonymous]
21
-        [ServiceFilter(typeof(TrackPageView))]
21
+        [TrackPageView]
22 22
         public IActionResult Index()
23 23
         {
24 24
             ViewBag.Title = "Frequently Asked Questions";

+ 1
- 1
Teknik/Areas/Help/Controllers/HelpController.cs View File

@@ -14,7 +14,7 @@ namespace Teknik.Areas.Help.Controllers
14 14
 {
15 15
     [Authorize]
16 16
     [Area("Help")]
17
-    [ServiceFilter(typeof(TrackPageView))]
17
+    [TrackPageView]
18 18
     public class HelpController : DefaultController
19 19
     {
20 20
         public HelpController(ILogger<Logger> logger, Config config, TeknikEntities dbContext) : base(logger, config, dbContext) { }

+ 1
- 1
Teknik/Areas/Home/Controllers/HomeController.cs View File

@@ -23,7 +23,7 @@ namespace Teknik.Areas.Home.Controllers
23 23
         public HomeController(ILogger<Logger> logger, Config config, TeknikEntities dbContext) : base(logger, config, dbContext) { }
24 24
         
25 25
         [AllowAnonymous]
26
-        [ServiceFilter(typeof(TrackPageView))]
26
+        [TrackPageView]
27 27
         public IActionResult Index()
28 28
         {
29 29
             HomeViewModel model = new HomeViewModel();

+ 3
- 3
Teknik/Areas/Paste/Controllers/PasteController.cs View File

@@ -31,7 +31,7 @@ namespace Teknik.Areas.Paste.Controllers
31 31
         public PasteController(ILogger<Logger> logger, Config config, TeknikEntities dbContext) : base(logger, config, dbContext) { }
32 32
         
33 33
         [AllowAnonymous]
34
-        [ServiceFilter(typeof(TrackPageView))]
34
+        [TrackPageView]
35 35
         public IActionResult Index()
36 36
         {
37 37
             ViewBag.Title = "Pastebin";
@@ -41,7 +41,7 @@ namespace Teknik.Areas.Paste.Controllers
41 41
         }
42 42
         
43 43
         [AllowAnonymous]
44
-        [ServiceFilter(typeof(TrackPageView))]
44
+        [TrackPageView]
45 45
         public async Task<IActionResult> ViewPaste(string type, string url, string password)
46 46
         {
47 47
             Models.Paste paste = _dbContext.Pastes.Where(p => p.Url == url).FirstOrDefault();
@@ -205,7 +205,7 @@ namespace Teknik.Areas.Paste.Controllers
205 205
             return View("~/Areas/Paste/Views/Paste/Index.cshtml", model);
206 206
         }
207 207
 
208
-        [ServiceFilter(typeof(TrackPageView))]
208
+        [TrackPageView]
209 209
         public async Task<IActionResult> Edit(string url, string password)
210 210
         {
211 211
             Models.Paste paste = _dbContext.Pastes.Where(p => p.Url == url).FirstOrDefault();

+ 3
- 3
Teknik/Areas/Podcast/Controllers/PodcastController.cs View File

@@ -29,7 +29,7 @@ namespace Teknik.Areas.Podcast.Controllers
29 29
         public PodcastController(ILogger<Logger> logger, Config config, TeknikEntities dbContext) : base(logger, config, dbContext) { }
30 30
         
31 31
         [AllowAnonymous]
32
-        [ServiceFilter(typeof(TrackPageView))]
32
+        [TrackPageView]
33 33
         public IActionResult Index()
34 34
         {
35 35
             MainViewModel model = new MainViewModel();
@@ -64,7 +64,7 @@ namespace Teknik.Areas.Podcast.Controllers
64 64
 
65 65
         #region Podcasts
66 66
         [AllowAnonymous]
67
-        [ServiceFilter(typeof(TrackPageView))]
67
+        [TrackPageView]
68 68
         public IActionResult View(int episode)
69 69
         {
70 70
             PodcastViewModel model = new PodcastViewModel();
@@ -86,7 +86,7 @@ namespace Teknik.Areas.Podcast.Controllers
86 86
         [HttpGet]
87 87
         [AllowAnonymous]
88 88
         [ResponseCache(Duration = 31536000, Location = ResponseCacheLocation.Any)]
89
-        [ServiceFilter(typeof(TrackDownload))]
89
+        [TrackDownload]
90 90
         public IActionResult Download(int episode, string fileName)
91 91
         {
92 92
             string path = string.Empty;

+ 1
- 1
Teknik/Areas/Privacy/Controllers/PrivacyController.cs View File

@@ -18,7 +18,7 @@ namespace Teknik.Areas.Privacy.Controllers
18 18
         public PrivacyController(ILogger<Logger> logger, Config config, TeknikEntities dbContext) : base(logger, config, dbContext) { }
19 19
         
20 20
         [AllowAnonymous]
21
-        [ServiceFilter(typeof(TrackPageView))]
21
+        [TrackPageView]
22 22
         public IActionResult Index()
23 23
         {
24 24
             ViewBag.Title = "Privacy Policy";

+ 3
- 3
Teknik/Areas/RSS/Controllers/RSSController.cs View File

@@ -32,7 +32,7 @@ namespace Teknik.Areas.RSS.Controllers
32 32
         public RSSController(ILogger<Logger> logger, Config config, TeknikEntities dbContext) : base(logger, config, dbContext) { }
33 33
         
34 34
         [AllowAnonymous]
35
-        [ServiceFilter(typeof(TrackPageView))]
35
+        [TrackPageView]
36 36
         public async Task Index()
37 37
         {
38 38
             Response.ContentType = "application/rss+xml";
@@ -50,7 +50,7 @@ namespace Teknik.Areas.RSS.Controllers
50 50
         }
51 51
         
52 52
         [AllowAnonymous]
53
-        [ServiceFilter(typeof(TrackPageView))]
53
+        [TrackPageView]
54 54
         public async Task Blog(string username)
55 55
         {
56 56
             Response.ContentType = "application/rss+xml";
@@ -156,7 +156,7 @@ namespace Teknik.Areas.RSS.Controllers
156 156
         }
157 157
         
158 158
         [AllowAnonymous]
159
-        [ServiceFilter(typeof(TrackPageView))]
159
+        [TrackPageView]
160 160
         public async Task Podcast()
161 161
         {
162 162
             Response.ContentType = "application/rss+xml";

+ 2
- 2
Teknik/Areas/Shortener/Controllers/ShortenerController.cs View File

@@ -24,7 +24,7 @@ namespace Teknik.Areas.Shortener.Controllers
24 24
         public ShortenerController(ILogger<Logger> logger, Config config, TeknikEntities dbContext) : base(logger, config, dbContext) { }
25 25
         
26 26
         [AllowAnonymous]
27
-        [ServiceFilter(typeof(TrackPageView))]
27
+        [TrackPageView]
28 28
         public IActionResult Index()
29 29
         {
30 30
             ViewBag.Title = "Url Shortener";
@@ -33,7 +33,7 @@ namespace Teknik.Areas.Shortener.Controllers
33 33
         }
34 34
         
35 35
         [AllowAnonymous]
36
-        [ServiceFilter(typeof(TrackPageView))]
36
+        [TrackPageView]
37 37
         public IActionResult RedirectToUrl(string url)
38 38
         {
39 39
             ShortenedUrl shortUrl = _dbContext.ShortenedUrls.Where(s => s.ShortUrl == url).FirstOrDefault();

+ 1
- 1
Teknik/Areas/Stats/Controllers/StatsController.cs View File

@@ -24,7 +24,7 @@ namespace Teknik.Areas.Stats.Controllers
24 24
         public StatsController(ILogger<Logger> logger, Config config, TeknikEntities dbContext) : base(logger, config, dbContext) { }
25 25
         
26 26
         [AllowAnonymous]
27
-        [ServiceFilter(typeof(TrackPageView))]
27
+        [TrackPageView]
28 28
         public IActionResult Index()
29 29
         {
30 30
             ViewBag.Title = "System Statistics";

+ 1
- 1
Teknik/Areas/TOS/Controllers/TOSController.cs View File

@@ -18,7 +18,7 @@ namespace Teknik.Areas.TOS.Controllers
18 18
         public TOSController(ILogger<Logger> logger, Config config, TeknikEntities dbContext) : base(logger, config, dbContext) { }
19 19
         
20 20
         [AllowAnonymous]
21
-        [ServiceFilter(typeof(TrackPageView))]
21
+        [TrackPageView]
22 22
         public IActionResult Index()
23 23
         {
24 24
             ViewBag.Title = "Terms of Service";

+ 3
- 3
Teknik/Areas/Upload/Controllers/UploadController.cs View File

@@ -33,7 +33,7 @@ namespace Teknik.Areas.Upload.Controllers
33 33
         
34 34
         [HttpGet]
35 35
         [AllowAnonymous]
36
-        [ServiceFilter(typeof(TrackPageView))]
36
+        [TrackPageView]
37 37
         public async Task<IActionResult> Index()
38 38
         {
39 39
             ViewBag.Title = "Upload Files";
@@ -181,8 +181,8 @@ namespace Teknik.Areas.Upload.Controllers
181 181
         
182 182
         [HttpGet]
183 183
         [AllowAnonymous]
184
-        [ServiceFilter(typeof(TrackDownload))]
185
-        [ServiceFilter(typeof(TrackPageView))]
184
+        [TrackDownload]
185
+        [TrackPageView]
186 186
         [ResponseCache(Duration = 31536000, Location = ResponseCacheLocation.Any)]
187 187
         public async Task<IActionResult> Download(string file)
188 188
         {

+ 17
- 17
Teknik/Areas/User/Controllers/UserController.cs View File

@@ -62,7 +62,7 @@ namespace Teknik.Areas.Users.Controllers
62 62
         }
63 63
 
64 64
         [HttpGet]
65
-        [ServiceFilter(typeof(TrackPageView))]
65
+        [TrackPageView]
66 66
         public IActionResult Login(string returnUrl)
67 67
         {
68 68
             // Let's double check their email and git accounts to make sure they exist
@@ -86,7 +86,7 @@ namespace Teknik.Areas.Users.Controllers
86 86
         }
87 87
 
88 88
         [HttpGet]
89
-        [ServiceFilter(typeof(TrackPageView))]
89
+        [TrackPageView]
90 90
         public async Task Logout()
91 91
         {
92 92
             // these are the sub & sid to signout
@@ -100,7 +100,7 @@ namespace Teknik.Areas.Users.Controllers
100 100
         }
101 101
 
102 102
         [AllowAnonymous]
103
-        [ServiceFilter(typeof(TrackPageView))]
103
+        [TrackPageView]
104 104
         public IActionResult GetPremium()
105 105
         {
106 106
             ViewBag.Title = "Get a Premium Account";
@@ -112,7 +112,7 @@ namespace Teknik.Areas.Users.Controllers
112 112
 
113 113
         [HttpGet]
114 114
         [AllowAnonymous]
115
-        [ServiceFilter(typeof(TrackPageView))]
115
+        [TrackPageView]
116 116
         public IActionResult Register(string inviteCode, string ReturnUrl)
117 117
         {
118 118
             RegisterViewModel model = new RegisterViewModel();
@@ -206,7 +206,7 @@ namespace Teknik.Areas.Users.Controllers
206 206
 
207 207
         // GET: Profile/Profile
208 208
         [AllowAnonymous]
209
-        [ServiceFilter(typeof(TrackPageView))]
209
+        [TrackPageView]
210 210
         public async Task<IActionResult> ViewProfile(string username)
211 211
         {
212 212
             if (string.IsNullOrEmpty(username))
@@ -264,7 +264,7 @@ namespace Teknik.Areas.Users.Controllers
264 264
             return View(model);
265 265
         }
266 266
 
267
-        [ServiceFilter(typeof(TrackPageView))]
267
+        [TrackPageView]
268 268
         public IActionResult ViewServiceData()
269 269
         {
270 270
             string username = User.Identity.Name;
@@ -303,13 +303,13 @@ namespace Teknik.Areas.Users.Controllers
303 303
             return View(model);
304 304
         }
305 305
 
306
-        [ServiceFilter(typeof(TrackPageView))]
306
+        [TrackPageView]
307 307
         public IActionResult Settings()
308 308
         {
309 309
             return Redirect(Url.SubRouteUrl("account", "User.ProfileSettings"));
310 310
         }
311 311
 
312
-        [ServiceFilter(typeof(TrackPageView))]
312
+        [TrackPageView]
313 313
         public IActionResult ProfileSettings()
314 314
         {
315 315
             string username = User.Identity.Name;
@@ -334,7 +334,7 @@ namespace Teknik.Areas.Users.Controllers
334 334
             return new StatusCodeResult(StatusCodes.Status403Forbidden);
335 335
         }
336 336
 
337
-        [ServiceFilter(typeof(TrackPageView))]
337
+        [TrackPageView]
338 338
         public IActionResult AccountSettings()
339 339
         {
340 340
             string username = User.Identity.Name;
@@ -356,7 +356,7 @@ namespace Teknik.Areas.Users.Controllers
356 356
             return new StatusCodeResult(StatusCodes.Status403Forbidden);
357 357
         }
358 358
 
359
-        [ServiceFilter(typeof(TrackPageView))]
359
+        [TrackPageView]
360 360
         public async Task<IActionResult> SecuritySettings()
361 361
         {
362 362
             string username = User.Identity.Name;
@@ -399,7 +399,7 @@ namespace Teknik.Areas.Users.Controllers
399 399
             return new StatusCodeResult(StatusCodes.Status403Forbidden);
400 400
         }
401 401
 
402
-        [ServiceFilter(typeof(TrackPageView))]
402
+        [TrackPageView]
403 403
         public async Task<IActionResult> DeveloperSettings()
404 404
         {
405 405
             string username = User.Identity.Name;
@@ -447,7 +447,7 @@ namespace Teknik.Areas.Users.Controllers
447 447
             return new StatusCodeResult(StatusCodes.Status403Forbidden);
448 448
         }
449 449
 
450
-        [ServiceFilter(typeof(TrackPageView))]
450
+        [TrackPageView]
451 451
         public IActionResult InviteSettings()
452 452
         {
453 453
             string username = User.Identity.Name;
@@ -493,7 +493,7 @@ namespace Teknik.Areas.Users.Controllers
493 493
             return new StatusCodeResult(StatusCodes.Status403Forbidden);
494 494
         }
495 495
 
496
-        [ServiceFilter(typeof(TrackPageView))]
496
+        [TrackPageView]
497 497
         public IActionResult BlogSettings()
498 498
         {
499 499
             string username = User.Identity.Name;
@@ -517,7 +517,7 @@ namespace Teknik.Areas.Users.Controllers
517 517
             return new StatusCodeResult(StatusCodes.Status403Forbidden);
518 518
         }
519 519
 
520
-        [ServiceFilter(typeof(TrackPageView))]
520
+        [TrackPageView]
521 521
         public IActionResult UploadSettings()
522 522
         {
523 523
             string username = User.Identity.Name;
@@ -544,7 +544,7 @@ namespace Teknik.Areas.Users.Controllers
544 544
 
545 545
         [HttpGet]
546 546
         [AllowAnonymous]
547
-        [ServiceFilter(typeof(TrackPageView))]
547
+        [TrackPageView]
548 548
         public async Task<IActionResult> ViewRawPGP(string username)
549 549
         {
550 550
             ViewBag.Title = username + "'s Public Key";
@@ -839,7 +839,7 @@ namespace Teknik.Areas.Users.Controllers
839 839
 
840 840
         [HttpGet]
841 841
         [AllowAnonymous]
842
-        [ServiceFilter(typeof(TrackPageView))]
842
+        [TrackPageView]
843 843
         public IActionResult ResetPassword(string username)
844 844
         {
845 845
             ResetPasswordViewModel model = new ResetPasswordViewModel();
@@ -883,7 +883,7 @@ namespace Teknik.Areas.Users.Controllers
883 883
 
884 884
         [HttpGet]
885 885
         [AllowAnonymous]
886
-        [ServiceFilter(typeof(TrackPageView))]
886
+        [TrackPageView]
887 887
         public async Task<IActionResult> VerifyResetPassword(string username, string code)
888 888
         {
889 889
             bool verified = true;

+ 4
- 4
Teknik/Areas/Vault/Controllers/VaultController.cs View File

@@ -34,7 +34,7 @@ namespace Teknik.Areas.Vault.Controllers
34 34
         public VaultController(ILogger<Logger> logger, Config config, TeknikEntities dbContext) : base(logger, config, dbContext) { }
35 35
         
36 36
         [AllowAnonymous]
37
-        [ServiceFilter(typeof(TrackPageView))]
37
+        [TrackPageView]
38 38
         public async Task<IActionResult> ViewVault(string id)
39 39
         {
40 40
             Models.Vault foundVault = _dbContext.Vaults.Where(v => v.Url == id).FirstOrDefault();
@@ -136,7 +136,7 @@ namespace Teknik.Areas.Vault.Controllers
136 136
 
137 137
         [HttpGet]
138 138
         [AllowAnonymous]
139
-        [ServiceFilter(typeof(TrackPageView))]
139
+        [TrackPageView]
140 140
         public IActionResult NewVault()
141 141
         {
142 142
             ViewBag.Title = "Create Vault";
@@ -147,7 +147,7 @@ namespace Teknik.Areas.Vault.Controllers
147 147
 
148 148
         [HttpGet]
149 149
         [AllowAnonymous]
150
-        [ServiceFilter(typeof(TrackPageView))]
150
+        [TrackPageView]
151 151
         public IActionResult NewVaultFromService(string type, string items)
152 152
         {
153 153
             ViewBag.Title = "Create Vault";
@@ -184,7 +184,7 @@ namespace Teknik.Areas.Vault.Controllers
184 184
         }
185 185
 
186 186
         [HttpGet]
187
-        [ServiceFilter(typeof(TrackPageView))]
187
+        [TrackPageView]
188 188
         public IActionResult EditVault(string url, string type, string items)
189 189
         {
190 190
             ViewBag.Title = "Edit Vault";

+ 31
- 18
Teknik/Filters/TrackDownload.cs View File

@@ -10,39 +10,52 @@ using Teknik.Tracking;
10 10
 using Microsoft.AspNetCore.Mvc.Filters;
11 11
 using Microsoft.AspNetCore.Http;
12 12
 using Microsoft.AspNetCore.Http.Extensions;
13
+using Microsoft.AspNetCore.Mvc;
13 14
 
14 15
 namespace Teknik.Filters
15 16
 {
16
-    public class TrackDownload : ActionFilterAttribute
17
+    public class TrackDownloadAttribute : TypeFilterAttribute
17 18
     {
18
-        private readonly Config _config;
19
-
20
-        public TrackDownload(Config config)
19
+        public TrackDownloadAttribute() : base(typeof(TrackDownload))
21 20
         {
22
-            _config = config;
23 21
         }
24 22
 
25
-        public override void OnActionExecuting(ActionExecutingContext filterContext)
23
+        public class TrackDownload : ActionFilterAttribute
26 24
         {
27
-        }
25
+            private readonly IBackgroundTaskQueue _queue;
26
+            private readonly Config _config;
28 27
 
29
-        public override void OnActionExecuted(ActionExecutedContext filterContext)
30
-        {
31
-            HttpRequest request = filterContext.HttpContext.Request;
28
+            public TrackDownload(IBackgroundTaskQueue queue, Config config)
29
+            {
30
+                _queue = queue;
31
+                _config = config;
32
+            }
32 33
 
33
-            string doNotTrack = request.Headers["DNT"];
34
-            if (string.IsNullOrEmpty(doNotTrack) || doNotTrack != "1")
34
+            public override void OnActionExecuting(ActionExecutingContext filterContext)
35 35
             {
36
-                string userAgent = request.Headers["User-Agent"].ToString();
36
+            }
37
+
38
+            public override void OnActionExecuted(ActionExecutedContext filterContext)
39
+            {
40
+                HttpRequest request = filterContext.HttpContext.Request;
41
+
42
+                string doNotTrack = request.Headers["DNT"];
43
+                if (string.IsNullOrEmpty(doNotTrack) || doNotTrack != "1")
44
+                {
45
+                    string userAgent = request.Headers["User-Agent"].ToString();
37 46
 
38
-                string clientIp = request.ClientIPFromRequest(true);
47
+                    string clientIp = request.ClientIPFromRequest(true);
39 48
 
40
-                string urlReferrer = request.Headers["Referer"].ToString();
49
+                    string urlReferrer = request.Headers["Referer"].ToString();
41 50
 
42
-                string url = UriHelper.GetEncodedUrl(request);
51
+                    string url = UriHelper.GetEncodedUrl(request);
43 52
 
44
-                // Fire and forget.  Don't need to wait for it.
45
-                Tracking.Tracking.TrackDownload(filterContext.HttpContext, _config, userAgent, clientIp, url, urlReferrer);
53
+                    // Fire and forget.  Don't need to wait for it.
54
+                    _queue.QueueBackgroundWorkItem(async token =>
55
+                    {
56
+                        Tracking.Tracking.TrackDownload(filterContext.HttpContext, _config, userAgent, clientIp, url, urlReferrer);
57
+                    });
58
+                }
46 59
             }
47 60
         }
48 61
     }

+ 40
- 29
Teknik/Filters/TrackPageView.cs View File

@@ -14,53 +14,64 @@ using Microsoft.AspNetCore.Mvc;
14 14
 
15 15
 namespace Teknik.Filters
16 16
 {
17
-    public class TrackPageView : ActionFilterAttribute
17
+    public class TrackPageViewAttribute : TypeFilterAttribute
18 18
     {
19
-        private readonly Config _config;
20
-
21
-        public TrackPageView(Config config)
19
+        public TrackPageViewAttribute() : base(typeof(TrackPageView))
22 20
         {
23
-            _config = config;
24 21
         }
25
-
26
-        public override void OnActionExecuting(ActionExecutingContext filterContext)
22
+        public class TrackPageView : ActionFilterAttribute
27 23
         {
28
-        }
24
+            private readonly IBackgroundTaskQueue _queue;
25
+            private readonly Config _config;
29 26
 
30
-        public override void OnActionExecuted(ActionExecutedContext filterContext)
31
-        {
32
-            HttpRequest request = filterContext.HttpContext.Request;
27
+            public TrackPageView(IBackgroundTaskQueue queue, Config config)
28
+            {
29
+                _queue = queue;
30
+                _config = config;
31
+            }
33 32
 
34
-            string doNotTrack = request.Headers["DNT"];
35
-            if (string.IsNullOrEmpty(doNotTrack) || doNotTrack != "1")
33
+            public override void OnActionExecuting(ActionExecutingContext filterContext)
36 34
             {
37
-                string title = (filterContext.Controller as Controller)?.ViewBag?.Title;
35
+            }
36
+
37
+            public override void OnActionExecuted(ActionExecutedContext filterContext)
38
+            {
39
+                HttpRequest request = filterContext.HttpContext.Request;
38 40
 
39
-                string sub = filterContext.RouteData.Values["sub"].ToString();
40
-                if (string.IsNullOrEmpty(sub))
41
+                string doNotTrack = request.Headers["DNT"];
42
+                if (string.IsNullOrEmpty(doNotTrack) || doNotTrack != "1")
41 43
                 {
42
-                    sub = request.Host.ToUriComponent().GetSubdomain();
43
-                }
44
+                    string title = (filterContext.Controller as Controller)?.ViewBag?.Title;
45
+
46
+                    string sub = filterContext.RouteData.Values["sub"].ToString();
47
+                    if (string.IsNullOrEmpty(sub))
48
+                    {
49
+                        sub = request.Host.ToUriComponent().GetSubdomain();
50
+                    }
44 51
 
45
-                string clientIp = request.ClientIPFromRequest(true);
52
+                    string clientIp = request.ClientIPFromRequest(true);
46 53
 
47
-                string url = UriHelper.GetEncodedUrl(request);
54
+                    string url = UriHelper.GetEncodedUrl(request);
48 55
 
49
-                string urlReferrer = request.Headers["Referer"].ToString();
56
+                    string urlReferrer = request.Headers["Referer"].ToString();
50 57
 
51
-                string userAgent = request.Headers["User-Agent"].ToString();
58
+                    string userAgent = request.Headers["User-Agent"].ToString();
52 59
 
53
-                int pixelWidth = 0;
54
-                int pixelHeight = 0;
60
+                    int pixelWidth = 0;
61
+                    int pixelHeight = 0;
55 62
 
56
-                bool hasCookies = false;
63
+                    bool hasCookies = false;
57 64
 
58
-                string acceptLang = request.Headers["Accept-Language"];
65
+                    string acceptLang = request.Headers["Accept-Language"];
59 66
 
60
-                bool hasJava = false;
67
+                    bool hasJava = false;
61 68
 
62
-                // Fire and forget.  Don't need to wait for it.
63
-                Tracking.Tracking.TrackPageView(filterContext.HttpContext, _config, title, sub, clientIp, url, urlReferrer, userAgent, pixelWidth, pixelHeight, hasCookies, acceptLang, hasJava);
69
+                    // Fire and forget.  Don't need to wait for it.
70
+                    _queue.QueueBackgroundWorkItem(async token =>
71
+                    {
72
+                        Tracking.Tracking.TrackPageView(filterContext.HttpContext, _config, title, sub, clientIp, url, urlReferrer, userAgent, pixelWidth, pixelHeight, hasCookies, acceptLang, hasJava);
73
+                    });
74
+                }
64 75
             }
65 76
         }
66 77
     }

+ 6
- 2
Teknik/Startup.cs View File

@@ -39,6 +39,7 @@ using Microsoft.AspNetCore.Routing;
39 39
 using Microsoft.AspNetCore.Mvc.Internal;
40 40
 using Microsoft.AspNetCore.Authorization;
41 41
 using System.Text.Encodings.Web;
42
+using Teknik.Tracking;
42 43
 
43 44
 namespace Teknik
44 45
 {
@@ -96,10 +97,13 @@ namespace Teknik
96 97
 #endif
97 98
             });
98 99
 
100
+            services.AddHostedService<TrackingService>();
101
+            services.AddSingleton<IBackgroundTaskQueue, BackgroundTaskQueue>();
102
+
99 103
             // Add Tracking Filter scopes
100
-            services.AddScoped<TrackDownload>();
104
+            //services.AddScoped<TrackDownload>();
101 105
             //services.AddScoped<TrackLink>();
102
-            services.AddScoped<TrackPageView>();
106
+            //services.AddScoped<TrackPageView>();
103 107
 
104 108
             // Create the Database Context
105 109
             services.AddDbContext<TeknikEntities>(options => options

+ 2
- 0
Tracking/Tracking.csproj View File

@@ -13,6 +13,8 @@
13 13
 
14 14
   <ItemGroup>
15 15
     <ProjectReference Include="..\Configuration\Configuration.csproj" />
16
+    <ProjectReference Include="..\Logging\Logging.csproj" />
17
+    <ProjectReference Include="..\Utilities\Utilities.csproj" />
16 18
   </ItemGroup>
17 19
 
18 20
   <ItemGroup>

+ 48
- 0
Tracking/TrackingService.cs View File

@@ -0,0 +1,48 @@
1
+using Microsoft.Extensions.Hosting;
2
+using Microsoft.Extensions.Logging;
3
+using System;
4
+using System.Collections.Generic;
5
+using System.Text;
6
+using System.Threading;
7
+using System.Threading.Tasks;
8
+using Teknik.Logging;
9
+using Teknik.Utilities;
10
+
11
+namespace Teknik.Tracking
12
+{
13
+    public class TrackingService : BackgroundService
14
+    {
15
+        private readonly ILogger<Logger> _logger;
16
+
17
+        public TrackingService(IBackgroundTaskQueue taskQueue,
18
+                                ILogger<Logger> logger)
19
+        {
20
+            TaskQueue = taskQueue;
21
+            _logger = logger;
22
+        }
23
+
24
+        public IBackgroundTaskQueue TaskQueue { get; }
25
+
26
+        protected async override Task ExecuteAsync(CancellationToken cancellationToken)
27
+        {
28
+            _logger.LogInformation("Queued Hosted Service is starting.");
29
+
30
+            while (!cancellationToken.IsCancellationRequested)
31
+            {
32
+                var workItem = await TaskQueue.DequeueAsync(cancellationToken);
33
+
34
+                try
35
+                {
36
+                    await workItem(cancellationToken);
37
+                }
38
+                catch (Exception ex)
39
+                {
40
+                    _logger.LogError(ex,
41
+                       $"Error occurred executing {nameof(workItem)}.");
42
+                }
43
+            }
44
+
45
+            _logger.LogInformation("Queued Hosted Service is stopping.");
46
+        }
47
+    }
48
+}

+ 38
- 0
Utilities/BackgroundTaskQueue.cs View File

@@ -0,0 +1,38 @@
1
+using System;
2
+using System.Collections.Concurrent;
3
+using System.Collections.Generic;
4
+using System.Text;
5
+using System.Threading;
6
+using System.Threading.Tasks;
7
+
8
+namespace Teknik.Utilities
9
+{
10
+    public class BackgroundTaskQueue : IBackgroundTaskQueue
11
+    {
12
+        private ConcurrentQueue<Func<CancellationToken, Task>> _workItems =
13
+            new ConcurrentQueue<Func<CancellationToken, Task>>();
14
+
15
+        private SemaphoreSlim _signal = new SemaphoreSlim(0);
16
+
17
+        public void QueueBackgroundWorkItem(
18
+            Func<CancellationToken, Task> workItem)
19
+        {
20
+            if (workItem == null)
21
+            {
22
+                throw new ArgumentNullException(nameof(workItem));
23
+            }
24
+
25
+            _workItems.Enqueue(workItem);
26
+            _signal.Release();
27
+        }
28
+
29
+        public async Task<Func<CancellationToken, Task>> DequeueAsync(
30
+            CancellationToken cancellationToken)
31
+        {
32
+            await _signal.WaitAsync(cancellationToken);
33
+            _workItems.TryDequeue(out var workItem);
34
+
35
+            return workItem;
36
+        }
37
+    }
38
+}

+ 49
- 0
Utilities/HostedService.cs View File

@@ -0,0 +1,49 @@
1
+using Microsoft.Extensions.Hosting;
2
+using System;
3
+using System.Collections.Generic;
4
+using System.Text;
5
+using System.Threading;
6
+using System.Threading.Tasks;
7
+
8
+namespace Teknik.Utilities
9
+{
10
+    public abstract class HostedService : IHostedService
11
+    {
12
+        private Task _executingTask;
13
+        private CancellationTokenSource _cts;
14
+
15
+        public Task StartAsync(CancellationToken cancellationToken)
16
+        {
17
+            // Create a linked token so we can trigger cancellation outside of this token's cancellation
18
+            _cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
19
+
20
+            // Store the task we're executing
21
+            _executingTask = ExecuteAsync(_cts.Token);
22
+
23
+            // If the task is completed then return it, otherwise it's running
24
+            return _executingTask.IsCompleted ? _executingTask : Task.CompletedTask;
25
+        }
26
+
27
+        public async Task StopAsync(CancellationToken cancellationToken)
28
+        {
29
+            // Stop called without start
30
+            if (_executingTask == null)
31
+            {
32
+                return;
33
+            }
34
+
35
+            // Signal cancellation to the executing method
36
+            _cts.Cancel();
37
+
38
+            // Wait until the task completes or the stop token triggers
39
+            await Task.WhenAny(_executingTask, Task.Delay(-1, cancellationToken));
40
+
41
+            // Throw if cancellation triggered
42
+            cancellationToken.ThrowIfCancellationRequested();
43
+        }
44
+
45
+        // Derived classes should override this and execute a long running method until 
46
+        // cancellation is requested
47
+        protected abstract Task ExecuteAsync(CancellationToken cancellationToken);
48
+    }
49
+}

+ 16
- 0
Utilities/IBackgroundTaskQueue.cs View File

@@ -0,0 +1,16 @@
1
+using System;
2
+using System.Collections.Generic;
3
+using System.Text;
4
+using System.Threading;
5
+using System.Threading.Tasks;
6
+
7
+namespace Teknik.Utilities
8
+{
9
+    public interface IBackgroundTaskQueue
10
+    {
11
+        void QueueBackgroundWorkItem(Func<CancellationToken, Task> workItem);
12
+
13
+        Task<Func<CancellationToken, Task>> DequeueAsync(
14
+            CancellationToken cancellationToken);
15
+    }
16
+}

Loading…
Cancel
Save