puvox-library 1.0.11 → 1.0.13

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.
@@ -10,6 +10,7 @@
10
10
  * const helpers = new PuvoxLibrary();
11
11
  * console.log ( helpers.get_last_child_of_array(array) );
12
12
  * console.log ( helpers.get_visitor_ip() );
13
+ * console.log ( helpers.telegramMessage("hello world", "1234567890", "BOTKEY123:456789") );
13
14
  * ... etc
14
15
  *
15
16
  */
@@ -158,6 +159,150 @@ const puvox_library =
158
159
  return this.stringArrayToNumeric(this.stringToArray(arr));
159
160
  },
160
161
 
162
+
163
+
164
+ // region: ####### from CCXT ##########
165
+ keys: Object.keys,
166
+ values: (x) => ((!isArray (x)) ? Object.values (x) : x),
167
+ extend: (...args) => Object.assign ({}, ...args), // NB: side-effect free
168
+ clone:(x) => (isArray (x) ? Array.from (x) : extend (x)),
169
+ index: (x) => new Set (values (x)),
170
+ ordered: (x) => x, // a stub to keep assoc keys in order (in JS it does nothing, it's mostly for Python)
171
+ unique: (x) => Array.from (index (x)),
172
+ arrayConcat: (a, b) => a.concat (b),
173
+ inArray (needle, haystack) {
174
+ return haystack.includes (needle);
175
+ },
176
+ toArray (object) {
177
+ return Object.values (object);
178
+ },
179
+ isEmpty (object) {
180
+ if (!object) {
181
+ return true;
182
+ }
183
+ return (Array.isArray (object) ? object : Object.keys (object)).length < 1;
184
+ },
185
+ keysort (x, out = {}) {
186
+ for (const k of keys (x).sort ()) {
187
+ out[k] = x[k];
188
+ }
189
+ return out;
190
+ },
191
+ indexBy (x, k, out = {}) {
192
+ // description: https://github.com/ccxt/ccxt/blob/master/js/base/functions/generic.js
193
+ for (const v of values (x)) {
194
+ if (k in v) {
195
+ out[v[k]] = v;
196
+ }
197
+ }
198
+
199
+ return out;
200
+ },
201
+ groupBy (x, k, out = {}) {
202
+ // description: https://github.com/ccxt/ccxt/blob/master/js/base/functions/generic.js
203
+ for (const v of values (x)) {
204
+ if (k in v) {
205
+ const p = v[k];
206
+ out[p] = out[p] || [];
207
+ out[p].push (v);
208
+ }
209
+ }
210
+ return out;
211
+ },
212
+ filterBy (x, k, value = undefined, out = []) {
213
+ // description: https://github.com/ccxt/ccxt/blob/master/js/base/functions/generic.js
214
+ for (const v of values (x)) {
215
+ if (v[k] === value) {
216
+ out.push (v);
217
+ }
218
+ }
219
+ return out;
220
+ },
221
+ sortBy: (array, key, descending = false, direction = descending ? -1 : 1) => array.sort ((a, b) => {
222
+ if (a[key] < b[key]) {
223
+ return -direction;
224
+ } else if (a[key] > b[key]) {
225
+ return direction;
226
+ } else {
227
+ return 0;
228
+ }
229
+ }),
230
+ sortBy2: (array, key1, key2, descending = false, direction = descending ? -1 : 1) => array.sort ((a, b) => {
231
+ if (a[key1] < b[key1]) {
232
+ return -direction;
233
+ } else if (a[key1] > b[key1]) {
234
+ return direction;
235
+ } else {
236
+ if (a[key2] < b[key2]) {
237
+ return -direction;
238
+ } else if (a[key2] > b[key2]) {
239
+ return direction;
240
+ } else {
241
+ return 0;
242
+ }
243
+ }
244
+ }),
245
+ flatten: function flatten (x, out = []) {
246
+
247
+ for (const v of x) {
248
+ if (isArray (v)) {
249
+ flatten (v, out);
250
+ } else {
251
+ out.push (v);
252
+ }
253
+ }
254
+
255
+ return out;
256
+ },
257
+ pluck: (x, k) => values (x).filter ((v) => k in v).map ((v) => v[k]),
258
+ omit (x, ...args) {
259
+ if (!Array.isArray (x)) {
260
+
261
+ const out = clone (x);
262
+
263
+ for (const k of args) {
264
+ if (isArray (k)) { // omit (x, ['a', 'b'])
265
+ for (const kk of k) {
266
+ delete out[kk];
267
+ }
268
+ } else {
269
+ delete out[k]; // omit (x, 'a', 'b')
270
+ }
271
+ }
272
+
273
+ return out;
274
+ }
275
+
276
+ return x;
277
+ },
278
+ sum (...xs) {
279
+ const ns = xs.filter (isNumber); // leave only numbers
280
+ return (ns.length > 0) ? ns.reduce ((a, b) => a + b, 0) : undefined;
281
+ },
282
+ deepExtend: function deepExtend (...xs) {
283
+ let out = undefined;
284
+ for (const x of xs) {
285
+ if (isDictionary (x)) {
286
+ if (!isDictionary (out)) {
287
+ out = {};
288
+ }
289
+ for (const k in x) { // eslint-disable-line guard-for-in
290
+ out[k] = deepExtend (out[k], x[k]);
291
+ }
292
+ } else {
293
+ out = x;
294
+ }
295
+ }
296
+ return out;
297
+ },
298
+ // endregion: ####### from CCXT ##########
299
+
300
+
301
+
302
+
303
+
304
+
305
+
161
306
  objectCopy(obj){
162
307
  return JSON.parse(JSON.stringify(obj));
163
308
  },
@@ -382,8 +527,9 @@ const puvox_library =
382
527
  isArray(x) { return ( (!!x) && (x.constructor === Array) ) || (Array.isArray(x)); },
383
528
 
384
529
  isSimpleVariableType(obj){ return this.isSimpleVariableTypeName(typeof obj); },
385
- isSimpleVariableTypeName(type_){ return this.inArray( [ "boolean", "integer", "float", "double", "decimal", "string"], type_); },
386
- isNumericVariableTypeName(type_){ return this.inArray( [ "integer", "float", "double", "decimal"], type_); },
530
+ isSimpleVariableTypeName(typeName_){ return this.inArray( [ "boolean", "integer", "float", "double", "decimal", "string"], typeName_); },
531
+ isNumericVariableType(obj){ return this.isNumericVariableTypeName(typeof obj); },
532
+ isNumericVariableTypeName(typeName_){ return this.inArray( [ "integer", "float", "double", "decimal"], typeName_); },
387
533
 
388
534
  stringToBoolean(string){
389
535
  switch(string.toLowerCase().trim()){
@@ -460,12 +606,18 @@ const puvox_library =
460
606
  trimOnlyFromEnd(content){
461
607
  return content.replace(/\s*$/,"");
462
608
  },
609
+ startsWith(content, what){
610
+ return content.startsWith(what);
611
+ },
463
612
  startsWithArray(content,array){
464
613
  array.forEach(function(val){
465
614
  if (content.startsWith(val)) return true;
466
615
  })
467
616
  return false;
468
617
  },
618
+ endsWith(content, what){
619
+ return content.endsWith(what);
620
+ },
469
621
  endsWithArray(content,array){
470
622
  array.forEach(function(val){
471
623
  if (content.endsWith(val)) return true;
@@ -1295,6 +1447,8 @@ const puvox_library =
1295
1447
  )
1296
1448
  },
1297
1449
 
1450
+ milliseconds(){ return (new Date().getTime()); },
1451
+
1298
1452
  fancyTimeFormat(time)
1299
1453
  {
1300
1454
  var time = time.toFixed(0);
@@ -2467,36 +2621,68 @@ const puvox_library =
2467
2621
 
2468
2622
 
2469
2623
  // region ### TELEGRAM FUNCTIONS ###
2470
- // public function telegram($text) { return $helpers->telegram_message( ['chat_id'=>'-1001234567890', 'text'=>$text, 'parse_mode'=>'html', 'disable_web_page_preview'=>true ], $bot_key ); } | resp: pastebin_com/u0J1Cph3
2471
- async telegram_message(opts = {text: 'Hi', chat_id:'-1001234567890'}, bot_id, is_repeated_call=false){
2472
- opts['disable_web_page_preview'] = 'disable_web_page_preview' in opts ? opts['disable_web_page_preview'] : true;
2473
- // opts['chat_id'] = opts['chat_id'].toString().substring(0,4) == '-100' ? opts['chat_id'].toString() : '-100' + opts['chat_id'].toString(); opts['chat_id'] = parseInt(opts['chat_id']);
2474
- opts['text'] = this.stripTags(this.br2nl(opts['text']),'<b><strong><i><em><u><ins><s><strike><del><a><code><pre>'); // allowed: https://core.telegram.org/bots/api#html-style
2475
- opts['text'] = opts['text'].substring(0, 4095); //max telegram message length 4096
2476
- const responseText = await (await fetch('https://api.telegram.org/bot'+ bot_id +'/sendMessage', { method: 'POST', headers: { 'Content-Type': 'application/json' + (0 ? 'application/x-www-form-urlencoded':'') }, body: JSON.stringify(opts)})).text(); //'sendMessage?'.http_build_query($array, '');
2624
+ async telegramMessage(text, chat_id, bot_key, extra_opts={}){
2625
+ const is_repeated_call = 'is_repeated_call' in extra_opts;
2626
+ const use_cache = 'cache' in extra_opts;
2627
+ if (! ('parse_mode' in extra_opts)){
2628
+ extra_opts['parse_mode'] = 'html';
2629
+ }
2630
+ if (! ('disable_web_page_preview' in extra_opts)){
2631
+ extra_opts['disable_web_page_preview'] = true;
2632
+ }
2633
+ // whether it's without `-100` prefix
2634
+ chat_id = chat_id.toString();
2635
+ if (!this.startsWith(chat_id, '-100')) chat_id = '-100' + chat_id;
2636
+ text = this.br2nl(text);
2637
+ text = this.stripTags(text,'<b><strong><i><em><u><ins><s><strike><del><a><code><pre>'); // allowed: https://core.telegram.org/bots/api#html-style
2638
+ text = text.substring(0, 4095); //max telegram message length 4096
2639
+ const requestOpts = Object.assign({'chat_id':chat_id, 'text':text}, extra_opts);
2640
+ delete requestOpts['cache'];
2641
+ delete requestOpts['is_repeated_call'];
2642
+ const responseText = await this.getRemoteData('https://api.telegram.org/bot'+ bot_key +'/sendMessage', requestOpts); // pastebin_com/u0J1Cph3 //'sendMessage?'.http_build_query(opts, '');
2477
2643
  try {
2478
2644
  const responseJson = JSON.parse(responseText);
2479
2645
  if (responseJson.ok){
2480
- return response;
2481
- } else {
2482
- //i.e. {"ok":false,"error_code":400,"description":"Bad Request: can't parse entities: Unsupported start tag \"br/\" at byte offset 43"}
2483
- // for some reason, if still unsupported format submitted, resubmit the plain format
2484
- const txt = "Bad Request: can't parse entities";
2485
- if( response.description.indexOf (txt)> -1 ){
2486
- const newOpts = this.objectCopy(opts);
2487
- newOpts['text'] = "[SecondSend] \r\n". this.stripTags(newOpts['text']) ;
2488
- if ( ! repeated_call ){
2489
- return this.telegram_message(newOpts, bot_id, true);
2490
- } else {
2491
- return response;
2646
+ return responseJson;
2647
+ }
2648
+ // for some reason, if still unsupported format submitted, resubmit the plain format
2649
+ //i.e. {"ok":false,"error_code":400,"description":"Bad Request: can't parse entities: Unsupported start tag \"br/\" at byte offset 43"}
2650
+ else {
2651
+ if( responseJson.description.indexOf ('Bad Request: can\'t parse entities')> -1 ){
2652
+ if ( ! is_repeated_call ){
2653
+ const extraOpts2 = this.objectCopy(opts);
2654
+ text = "[SecondSend with stipped tags] \r\n" + this.stripTags(text) ;
2655
+ extraOpts2['is_repeated_call'] = true;
2656
+ return this.telegram_message(text, chat_id, bot_key, extraOpts2);
2492
2657
  }
2493
- } else {
2494
- return response;
2495
2658
  }
2659
+ return responseJson;
2496
2660
  }
2497
2661
  } catch (ex) {
2498
- return {'ok': false, 'description': responseText };
2662
+ return {'ok': false, 'description': ex.message + ':::' + responseText };
2663
+ }
2664
+ },
2665
+
2666
+ telegram_interval_ms: 50, // telegram seems to accept around 30 times per second, so we'd better wait around that milliseconds
2667
+ telegram_last_sent_time: 0,
2668
+
2669
+ async telegramMessageCached(text, chat_id, bot_key, extra_opts={}){
2670
+ const curMS = this.milliseconds();
2671
+ const goneMS = curMS - this.telegram_last_sent_time;
2672
+ if ( goneMS < this.telegram_interval_ms ){
2673
+ await this.sleep (this.telegram_interval_ms - goneMS);
2499
2674
  }
2675
+ this.telegram_last_sent_time = curMS;
2676
+ const cacheId = this.cache.file.idForContent( text +'_'+ chat_id +'_'+ bot_key +'_'+ JSON.stringify(extra_opts) );
2677
+ if (this.cache.file.addIdIfNotExists('function_telegram_message', cacheId) ){
2678
+ return this.telegramMessage(text, chat_id, bot_key, extra_opts);
2679
+ }
2680
+ else {
2681
+ return false;
2682
+ }
2683
+ //if(is_callable([$this,'notifications_db_entry']))
2684
+ // $this->notifications_db_entry($key, $array['chat_id'], $this->stringify($res), time(), $ok );
2685
+ //return $res;
2500
2686
  },
2501
2687
 
2502
2688
  openUrlInBrowser(url)
@@ -2657,26 +2843,27 @@ const puvox_library =
2657
2843
  // } catch (ex) { reject (ex); }
2658
2844
  // });
2659
2845
  },
2660
-
2661
-
2662
2846
  // if(setHashInAddress) { window.location.hash = id_or_Name; }
2663
2847
 
2664
2848
 
2665
2849
 
2666
2850
 
2667
2851
  // ######## CACHE ITEMS (client-side JS) ########
2668
- AppName : 'puvox_', //override with anything you want
2669
- setAppName (name){ this.AppName = name; },
2670
-
2671
- cache : {
2672
- localStorage : {
2673
- parent(){ return puvox_library; },
2674
- AppName(){ return puvox_library.AppName; },
2852
+ _privateAppName : null, //override with anything you want
2853
+ setAppName (name){ this._privateAppName = name; },
2854
+ getAppName(){
2855
+ if (!this._privateAppName || this._privateAppName === ''){
2856
+ throw new Error ('Before you start using caching functions, please at first define your appplication\'s name(identifier) at first with .setAppName("whatever_my_app_name"), so it will get its own cache-storage');
2857
+ }
2858
+ return this._privateAppName;
2859
+ },
2675
2860
 
2861
+ cache: {
2862
+ localStorage : {
2676
2863
  storage: typeof window !== 'undefined' ? window.localStorage : null,
2677
2864
 
2678
2865
  get(name, defaultValue, expireSeconds = 0){
2679
- let appName = this.AppName();
2866
+ let appName = puvox_library.getAppName();
2680
2867
  let val = this.storage.getItem(appName + '_' + name);
2681
2868
  let expireVal = this.storage.getItem(appName + '_createtime_' + name);
2682
2869
  if (val === null) {
@@ -2696,15 +2883,17 @@ const puvox_library =
2696
2883
  },
2697
2884
  set(name, value){
2698
2885
  try{
2699
- this.storage.setItem(this.AppName() + '_' +name, value);
2700
- this.storage.setItem(this.AppName() + '_createtime_' +name, (new Date()).getTime());
2886
+ const appName = puvox_library.getAppName();
2887
+ this.storage.setItem(appName + '_' +name, value);
2888
+ this.storage.setItem(appName + '_createtime_' +name, (new Date()).getTime());
2701
2889
  return true;
2702
2890
  }
2703
2891
  catch(ex){ alert("Cache storage quote exceeded. can't save value. err598"); return false; }
2704
2892
  },
2705
- remove(name, value){
2706
- this.storage.removeItem(this.AppName() + '_' +name);
2707
- this.storage.removeItem(this.AppName() + '_createtime_' +name);
2893
+ remove(name){
2894
+ const appName = puvox_library.getAppName();
2895
+ this.storage.removeItem(appName + '_' + name);
2896
+ this.storage.removeItem(appName + '_createtime_' + name);
2708
2897
  },
2709
2898
  getItem(name, subItemName, defaultValue){
2710
2899
  let val = this.get(name, '{}');
@@ -2725,30 +2914,27 @@ const puvox_library =
2725
2914
  return this.set(name, JSON.stringify(parsed) );
2726
2915
  }
2727
2916
  },
2728
- file : {
2917
+ file: {
2729
2918
  // ########## CACHE DIRS (server-side JS) ##########
2730
- parent(){ return puvox_library; },
2731
- AppName(){ return puvox_library.AppName; },
2732
-
2733
2919
  customCacheDir:null,
2734
- dirPath(){
2920
+ dir(){
2735
2921
  if (!this.customCacheDir){
2736
- this.customCacheDir = this.parent().file.getTempDir() + '/';
2922
+ this.customCacheDir = puvox_library.file.getTempDir() + '/';
2737
2923
  }
2738
- let finaldir = this.customCacheDir + '_cache' + this.AppName() + '/';
2924
+ let finaldir = this.customCacheDir + '_cache_' + puvox_library.getAppName() + '/';
2739
2925
  return finaldir;
2740
2926
  },
2741
2927
  filePath(uniqFileName){
2742
- const parent = this.parent();
2928
+ const parent = puvox_library;
2743
2929
  uniqFileName = parent.isString(uniqFileName) || parent.isNumeric(uniqFileName) ? uniqFileName : JSON.stringify(uniqFileName);
2744
2930
  uniqFileName = parent.sanitize_key_dashed(parent.getCharsFromStart(uniqFileName, 15)) + "_"+ parent.md5(uniqFileName);
2745
- filePath= this.dirPath() + uniqFileName + "_tmp"; //"/".
2931
+ filePath= this.dir() + uniqFileName + "_tmp"; //"/".
2746
2932
  return filePath;
2747
2933
  },
2748
2934
  //
2749
2935
  get(uniqFileName, defaultContent ='', expire_seconds=8640000, decode = true)
2750
2936
  {
2751
- const parent = this.parent();
2937
+ const parent = puvox_library;
2752
2938
  let filePath = this.filePath(uniqFileName);
2753
2939
  if ( filePath.length < 3) return "too tiny filename";
2754
2940
 
@@ -2783,7 +2969,7 @@ const puvox_library =
2783
2969
  },
2784
2970
  set(uniqFileName, content)
2785
2971
  {
2786
- const parent = this.parent();
2972
+ const parent = puvox_library;
2787
2973
  let filePath= this.filePath(uniqFileName);
2788
2974
  let contentFinal = parent.isString(content) ? content : ((parent.isArray(content) || parent.isObject(content)) ? JSON.stringify(content) : content);
2789
2975
  return parent.file.write(filePath, contentFinal);
@@ -2809,6 +2995,37 @@ const puvox_library =
2809
2995
  // console.log("writeFileAppendJson", e);
2810
2996
  // }
2811
2997
  // },
2998
+ containerDefaultPrefix: "_cached_ids_",
2999
+ tempIds:{},
3000
+ idForContent(slugOrContent){
3001
+ return puvox_library.md5(puvox_library.isSimpleVariableType(slugOrContent) ? slugOrContent : JSON.stringify(slugOrContent));
3002
+ },
3003
+ existsId(containerSlug, id){
3004
+ return (id in this.getIds(containerSlug));
3005
+ },
3006
+ getIds(containerSlug) {
3007
+ if (! (containerSlug in this.tempIds)) {
3008
+ const content = puvox_library.file.read(this.dir() + this.containerDefaultPrefix + containerSlug, '{}');
3009
+ this.tempIds[containerSlug] = JSON.parse(content);
3010
+ }
3011
+ return this.tempIds[containerSlug];
3012
+ },
3013
+ setIds(containerSlug, idsDict) {
3014
+ this.tempIds[containerSlug] = idsDict;
3015
+ return puvox_library.file.write(this.dir() + this.containerDefaultPrefix + containerSlug, JSON.stringify(this.tempIds[containerSlug]));
3016
+ },
3017
+ addId(containerSlug, id){
3018
+ const ids = this.getIds(containerSlug);
3019
+ ids[id] = 1;
3020
+ this.setIds(containerSlug, ids);
3021
+ },
3022
+ addIdIfNotExists(containerSlug, id){
3023
+ if (! this.existsId(containerSlug, id)){
3024
+ this.addId(containerSlug, id);
3025
+ return true;
3026
+ }
3027
+ return false;
3028
+ },
2812
3029
  }
2813
3030
  },
2814
3031
 
@@ -2823,7 +3040,7 @@ const puvox_library =
2823
3040
  return this._required_instances[name];
2824
3041
  }
2825
3042
  },
2826
- file : {
3043
+ file: {
2827
3044
  parent() {return puvox_library;},
2828
3045
  fs() {return puvox_library.modules('fs');},
2829
3046
  os() {return puvox_library.modules('os');},
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "puvox-library",
3
- "version": "1.0.11",
3
+ "version": "1.0.13",
4
4
  "description": "library-class-javascript",
5
5
  "main": "library_standard.js",
6
6
  "scripts": {
package/test.js ADDED
@@ -0,0 +1,8 @@
1
+ const h = require('./library_standard.js');
2
+ function c(...args){console.log(...args);} function cc(o){console.dir(o, {'maxArrayLength': null});} function x(...args){c(...args);process.exit();} function xx(o){cc(o);process.exit();}
3
+
4
+ h.setAppName("myApp");
5
+ async function x(){
6
+ c(await h.telegramMessageCached('Hello World', 1668904096, '1651207488:AAF0KDLW6tmDUElN7RxVbp5RwQK5u77znhU'));
7
+ }
8
+ x();