alchemymvc 1.4.0-alpha.11 → 1.4.0-alpha.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -6,7 +6,7 @@ var iostream = alchemy.use('socket.io-stream'),
6
6
  *
7
7
  * @author Jelle De Loecker <jelle@elevenways.be>
8
8
  * @since 0.2.0
9
- * @version 1.3.10
9
+ * @version 1.4.0
10
10
  *
11
11
  * @param {Socker} socket
12
12
  * @param {Object} announcement
@@ -25,6 +25,10 @@ var SocketConduit = Function.inherits('Alchemy.Conduit', function Socket(socket,
25
25
  // Store the announcement data
26
26
  this.announcement = announcement;
27
27
 
28
+ if (!this.canCreateSocketConnection()) {
29
+ return;
30
+ }
31
+
28
32
  // Detect node clients
29
33
  if (this.headers['user-agent'] == 'node-XMLHttpRequest') {
30
34
  this.isNodeClient = true;
@@ -145,6 +149,22 @@ SocketConduit.setProperty(function is_connected() {
145
149
  return this.socket?.connected || false;
146
150
  });
147
151
 
152
+ /**
153
+ * Is this client allowed to create a socket connection?
154
+ *
155
+ * @author Jelle De Loecker <jelle@elevenways.be>
156
+ * @since 1.4.0
157
+ * @version 1.4.0
158
+ */
159
+ SocketConduit.setMethod(function canCreateSocketConnection() {
160
+
161
+ if (this.isCrawler()) {
162
+ return false;
163
+ }
164
+
165
+ return true;
166
+ });
167
+
148
168
  /**
149
169
  * Parse the request, get information from the url
150
170
  *
@@ -447,7 +447,7 @@ Conduit.setMethod(function setReqRes(req, res) {
447
447
  *
448
448
  * @author Jelle De Loecker <jelle@elevenways.be>
449
449
  * @since 0.3.3
450
- * @version 1.3.15
450
+ * @version 1.4.0
451
451
  */
452
452
  Conduit.setMethod(function initValues() {
453
453
 
@@ -493,6 +493,9 @@ Conduit.setMethod(function initValues() {
493
493
 
494
494
  // Make sure the tested routes are reset
495
495
  this[TESTED_ROUTES] = null;
496
+
497
+ // Is this a crawler?
498
+ this.is_crawler = null;
496
499
  });
497
500
 
498
501
  /**
@@ -2383,6 +2386,13 @@ Conduit.setMethod(function getSession(allow_create = true) {
2383
2386
  return this.session_instance;
2384
2387
  }
2385
2388
 
2389
+ if (this.isCrawler()) {
2390
+ // Create a dummy non-persistent session for crawlers
2391
+ let session = new Classes.Alchemy.ClientSession(this);
2392
+ this.session_instance = session;
2393
+ return session;
2394
+ }
2395
+
2386
2396
  let cookie_name = this.session_cookie_name,
2387
2397
  session_id,
2388
2398
  session;
@@ -2771,6 +2781,74 @@ Conduit.setMethod(function supports(feature) {
2771
2781
  return null;
2772
2782
  });
2773
2783
 
2784
+ /**
2785
+ * Is the connecting client a crawler?
2786
+ *
2787
+ * @author Jelle De Loecker <jelle@elevenways.be>
2788
+ * @since 1.4.0
2789
+ * @version 1.4.0
2790
+ *
2791
+ * @return {boolean}
2792
+ */
2793
+ Conduit.setMethod(function isCrawler() {
2794
+
2795
+ if (this.is_crawler == null) {
2796
+ let ua = this.useragent;
2797
+ let is_crawler = false;
2798
+
2799
+ if (ua) {
2800
+ let device = ua.device?.family;
2801
+
2802
+ // The Useragent parser already detects a lot of spiders/crawlers
2803
+ if (device == 'Spider') {
2804
+ is_crawler = true;
2805
+ } else {
2806
+ let family = String(ua.family);
2807
+
2808
+ if (family == 'Chrome'
2809
+ || family == 'Firefox'
2810
+ || family == 'Safari'
2811
+ || family == 'Mobile Safari'
2812
+ || family == 'Chrome Mobile'
2813
+ ) {
2814
+ // Ignore
2815
+ } else {
2816
+ family = family.toLowerCase();
2817
+
2818
+ if (family == 'other') {
2819
+ let source = ua.source.toLowerCase();
2820
+
2821
+ if (
2822
+ source.includes('perplexity')
2823
+ || source.includes('www.you.com')
2824
+ || source.includes(' youbot ')
2825
+ || source.includes('google')
2826
+ || source.includes('python')
2827
+ || source.includes('httpunit')
2828
+ || source.includes('go-http')
2829
+ ) {
2830
+ is_crawler = true;
2831
+ }
2832
+ } else if (family == 'gptbot'
2833
+ || family == 'linkedinbot'
2834
+ || family == 'wget'
2835
+ || family == 'libwww-perl'
2836
+ || family.includes('google')
2837
+ || family.includes('python')
2838
+ || family.includes('yandex')
2839
+ ) {
2840
+ is_crawler = true;
2841
+ }
2842
+ }
2843
+ }
2844
+ }
2845
+
2846
+ this.is_crawler = is_crawler;
2847
+ }
2848
+
2849
+ return this.is_crawler;
2850
+ });
2851
+
2774
2852
  /**
2775
2853
  * Should this request be delayed because the server is too busy?
2776
2854
  * This performs an early check, the controller might also check this later.
@@ -1549,6 +1549,56 @@ Alchemy.setMethod(function getCache(name, options) {
1549
1549
  return instance;
1550
1550
  });
1551
1551
 
1552
+ /**
1553
+ * Prune all the caches
1554
+ *
1555
+ * @author Jelle De Loecker <jelle@elevenways.be>
1556
+ * @since 1.4.0
1557
+ * @version 1.4.0
1558
+ */
1559
+ Alchemy.setMethod(function pruneCaches(force_log = true) {
1560
+
1561
+ let checked = 0,
1562
+ pruned = 0;
1563
+
1564
+ let do_log;
1565
+
1566
+ if (force_log === 'auto') {
1567
+ do_log = alchemy.settings.debugging.debug;
1568
+ } else {
1569
+ do_log = force_log;
1570
+ }
1571
+
1572
+ for (let key in this.caches) {
1573
+ let cache = this.caches[key];
1574
+
1575
+ if (!cache) {
1576
+ continue;
1577
+ }
1578
+
1579
+ checked++;
1580
+ let old_length = cache.length;
1581
+
1582
+ for (let entry of cache) {
1583
+ // This triggers a check of all the entries
1584
+ // @TODO: Use cache.prune() instead, which will be fixed in next Protoblast version
1585
+ }
1586
+
1587
+ let new_length = cache.length;
1588
+
1589
+ if (new_length != old_length) {
1590
+ pruned++;
1591
+ if (do_log) {
1592
+ console.log('Pruned cache', cache, 'from', old_length, 'to', new_length);
1593
+ }
1594
+ }
1595
+ }
1596
+
1597
+ if (do_log) {
1598
+ console.log('Checked', checked, 'caches and pruned', pruned, 'of them');
1599
+ }
1600
+ });
1601
+
1552
1602
  /**
1553
1603
  * Get a route
1554
1604
  *
@@ -186,6 +186,39 @@ performance.addSetting('janeway_lag_menu', {
186
186
  },
187
187
  });
188
188
 
189
+ let prune_cache_interval_id = null;
190
+
191
+ performance.addSetting('prune_cache', {
192
+ type : 'string',
193
+ default : '20 minutes',
194
+ description : 'Prune all the caches at a regular interval',
195
+ action : (value, value_instance) => {
196
+
197
+ if (prune_cache_interval_id != null) {
198
+ clearInterval(prune_cache_interval_id);
199
+ prune_cache_interval_id = null;
200
+ }
201
+
202
+ if (!value) {
203
+ return;
204
+ }
205
+
206
+ let duration_in_ms = Date.parseDuration(value);
207
+
208
+ if (!duration_in_ms) {
209
+ return;
210
+ }
211
+
212
+ if (duration_in_ms < 5000) {
213
+ duration_in_ms = 5000;
214
+ }
215
+
216
+ prune_cache_interval_id = setInterval(() => {
217
+ alchemy.pruneCaches('auto');
218
+ }, duration_in_ms);
219
+ },
220
+ });
221
+
189
222
  const debugging = system.createGroup('debugging');
190
223
 
191
224
  debugging.addSetting('debug', {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "alchemymvc",
3
3
  "description": "MVC framework for Node.js",
4
- "version": "1.4.0-alpha.11",
4
+ "version": "1.4.0-alpha.12",
5
5
  "author": "Jelle De Loecker <jelle@elevenways.be>",
6
6
  "keywords": [
7
7
  "alchemy",