github.com/angenalZZZ/gofunc@v0.0.0-20210507121333-48ff1be3917b/js/goja.go (about)

     1  package js
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/xml"
     6  	"fmt"
     7  	"net/http"
     8  	"net/url"
     9  	"os"
    10  	"path/filepath"
    11  	"strings"
    12  	"time"
    13  
    14  	"github.com/angenalZZZ/gofunc/data/cache/fastcache"
    15  	"github.com/angenalZZZ/gofunc/data/id"
    16  	"github.com/angenalZZZ/gofunc/data/random"
    17  	"github.com/angenalZZZ/gofunc/f"
    18  	ht "github.com/angenalZZZ/gofunc/http"
    19  	"github.com/angenalZZZ/gofunc/log"
    20  	"github.com/dop251/goja"
    21  	"github.com/go-redis/redis/v7"
    22  	"github.com/go-resty/resty/v2"
    23  	"github.com/jmoiron/sqlx"
    24  	json "github.com/json-iterator/go"
    25  	"github.com/klauspost/crc32"
    26  	"github.com/nats-io/nats.go"
    27  )
    28  
    29  // Logger use log in javascript.
    30  // 	log.debug('%d', 123)
    31  // 	log.info('%v', {name:'hello'})
    32  // 	log.warn()
    33  // 	log.error()
    34  // 	log.fatal()
    35  // 	log.panic()
    36  // 	log.log()
    37  func Logger(r *goja.Runtime, log *log.Logger) {
    38  	logObj := r.NewObject()
    39  
    40  	// log.debug output log
    41  	_ = logObj.Set("debug", func(c goja.FunctionCall) goja.Value {
    42  		v, l := goja.Undefined(), len(c.Arguments)
    43  		if l == 0 {
    44  			return v
    45  		}
    46  		format, s := c.Arguments[0].String(), make([]interface{}, l-1)
    47  		for i := 1; i < l; i++ {
    48  			s = append(s, c.Arguments[i].Export())
    49  		}
    50  		log.Debug().Msgf(format, s...)
    51  		return v
    52  	})
    53  	// log.info output log
    54  	_ = logObj.Set("info", func(c goja.FunctionCall) goja.Value {
    55  		v, l := goja.Undefined(), len(c.Arguments)
    56  		if l == 0 {
    57  			return v
    58  		}
    59  		format, s := c.Arguments[0].String(), make([]interface{}, l-1)
    60  		for i := 1; i < l; i++ {
    61  			s = append(s, c.Arguments[i].Export())
    62  		}
    63  		log.Info().Msgf(format, s...)
    64  		return v
    65  	})
    66  	// log.warn output log
    67  	_ = logObj.Set("warn", func(c goja.FunctionCall) goja.Value {
    68  		v, l := goja.Undefined(), len(c.Arguments)
    69  		if l == 0 {
    70  			return v
    71  		}
    72  		format, s := c.Arguments[0].String(), make([]interface{}, l-1)
    73  		for i := 1; i < l; i++ {
    74  			s = append(s, c.Arguments[i].Export())
    75  		}
    76  		log.Warn().Msgf(format, s...)
    77  		return v
    78  	})
    79  	// log.error output log
    80  	_ = logObj.Set("error", func(c goja.FunctionCall) goja.Value {
    81  		v, l := goja.Undefined(), len(c.Arguments)
    82  		if l == 0 {
    83  			return v
    84  		}
    85  		format, s := c.Arguments[0].String(), make([]interface{}, l-1)
    86  		for i := 1; i < l; i++ {
    87  			s = append(s, c.Arguments[i].Export())
    88  		}
    89  		log.Error().Msgf(format, s...)
    90  		return v
    91  	})
    92  	// log.fatal output log
    93  	_ = logObj.Set("fatal", func(c goja.FunctionCall) goja.Value {
    94  		v, l := goja.Undefined(), len(c.Arguments)
    95  		if l == 0 {
    96  			return v
    97  		}
    98  		format, s := c.Arguments[0].String(), make([]interface{}, l-1)
    99  		for i := 1; i < l; i++ {
   100  			s = append(s, c.Arguments[i].Export())
   101  		}
   102  		log.Fatal().Msgf(format, s...)
   103  		return v
   104  	})
   105  	// log.panic output log
   106  	_ = logObj.Set("panic", func(c goja.FunctionCall) goja.Value {
   107  		v, l := goja.Undefined(), len(c.Arguments)
   108  		if l == 0 {
   109  			return v
   110  		}
   111  		format, s := c.Arguments[0].String(), make([]interface{}, l-1)
   112  		for i := 1; i < l; i++ {
   113  			s = append(s, c.Arguments[i].Export())
   114  		}
   115  		log.Panic().Msgf(format, s...)
   116  		return v
   117  	})
   118  	// log.log output log
   119  	_ = logObj.Set("log", func(c goja.FunctionCall) goja.Value {
   120  		v, l := goja.Undefined(), len(c.Arguments)
   121  		if l == 0 {
   122  			return v
   123  		}
   124  		format, s := c.Arguments[0].String(), make([]interface{}, l-1)
   125  		for i := 1; i < l; i++ {
   126  			s = append(s, c.Arguments[i].Export())
   127  		}
   128  		log.Log().Msgf(format, s...)
   129  		return v
   130  	})
   131  
   132  	r.Set("log", logObj)
   133  }
   134  
   135  // Console use console.log,dump in javascript.
   136  func Console(r *goja.Runtime) {
   137  	consoleObj := r.NewObject()
   138  
   139  	// console.log output content
   140  	_ = consoleObj.Set("log", func(c goja.FunctionCall) goja.Value {
   141  		fmt.Printf("    console.log:")
   142  		for _, a := range c.Arguments {
   143  			if v := a.Export(); v == nil {
   144  				fmt.Print(" null")
   145  			} else {
   146  				fmt.Printf(" %+v", v)
   147  			}
   148  		}
   149  		fmt.Println()
   150  		return goja.Undefined()
   151  	})
   152  
   153  	r.Set("console", consoleObj)
   154  
   155  	// dump output content
   156  	r.Set("dump", func(c goja.FunctionCall) goja.Value {
   157  		l := len(c.Arguments) - 1
   158  		fmt.Println()
   159  		for i, a := range c.Arguments {
   160  			if v := a.Export(); v == nil {
   161  				fmt.Print(" null")
   162  			} else {
   163  				fmt.Printf(" %+v", v)
   164  			}
   165  			if i < l {
   166  				fmt.Println()
   167  			}
   168  		}
   169  		fmt.Println()
   170  		return goja.Undefined()
   171  	})
   172  }
   173  
   174  // ID create a new random ID in javascript.
   175  // 	ID(): return a new random UUID.
   176  //  ID(9),ID(10),ID(20),ID(32),ID(36)
   177  func ID(r *goja.Runtime) {
   178  	r.Set("ID", func(c goja.FunctionCall) goja.Value {
   179  		var l int64 = 36
   180  		if len(c.Arguments) > 0 {
   181  			l = c.Arguments[0].ToInteger()
   182  		}
   183  		switch l {
   184  		case 9:
   185  			return r.ToValue(id.L9())
   186  		case 10:
   187  			return r.ToValue(id.L10())
   188  		case 20:
   189  			return r.ToValue(id.L20())
   190  		case 32:
   191  			return r.ToValue(id.L32())
   192  		case 36:
   193  			return r.ToValue(id.L36())
   194  		default:
   195  			return r.ToValue(id.L36())
   196  		}
   197  	})
   198  }
   199  
   200  // RD create a new random string in javascript.
   201  // 	RD(): return a new random string.
   202  //  RD(3),ID(4),ID(5),ID(6),ID(7)...
   203  func RD(r *goja.Runtime) {
   204  	r.Set("RD", func(c goja.FunctionCall) goja.Value {
   205  		var l int64 = 6
   206  		if len(c.Arguments) > 0 {
   207  			l = c.Arguments[0].ToInteger()
   208  			if l < 2 {
   209  				l = 2
   210  			} else if l > 2000 {
   211  				l = 2000
   212  			}
   213  		}
   214  		return r.ToValue(random.AlphaNumber(int(l)))
   215  	})
   216  }
   217  
   218  // Db use database and execute sql in javascript.
   219  // 	db.q: return ResultObject or Array of all rows
   220  // 	db.q('select * from table1 where id=?',1)
   221  // 	db.q('select * from table1 where id=:id',{id:1})
   222  //  db.q2: return Cache{ Memory = 0, Redis, Default } ResultObject or Array of all rows
   223  //  db.q2(0,'select * from table1 where id=:id',{id:1})
   224  // 	db.g: return ResultValue of first column in first row
   225  // 	db.g('select name from table1 where id=?',1)
   226  // 	db.g('select name from table1 where id=:id',{id:1})
   227  //  db.g2: return Cache{ Memory = 0, Redis, Default } ResultValue of first column in first row
   228  //  db.g2(0,'select name from table1 where id=:id',{id:1})
   229  // 	db.i: return LastInsertId must int in number-id-column
   230  // 	db.i('insert into table1 values(?,?)',1,'test')
   231  // 	db.i('insert into table1 values(:id,:name)',{id:1,name:'test'})
   232  //  db.x: return RowsAffected all inserted,updated,deleted
   233  //  db.x('update table1 set name=? where id=?','test',1)
   234  //  db.x('update table1 set name=:name where id=:id',{id:1,name:'test'})
   235  func Db(r *goja.Runtime, d *sqlx.DB, dbs ...string) {
   236  	dbObj := r.NewObject()
   237  
   238  	if d == nil && len(dbs) == 2 {
   239  		var err error
   240  		dbType, dbConn := dbs[0], dbs[1]
   241  		if d, err = sqlx.Connect(dbType, dbConn); err != nil {
   242  			_, _ = fmt.Fprintf(os.Stderr, "[js.Register.Db] %v\n", err)
   243  			return
   244  		}
   245  	}
   246  	if d == nil {
   247  		_, _ = fmt.Fprintln(os.Stderr, "[js.Register] failed connect to db")
   248  	}
   249  
   250  	driver := make(map[string]interface{})
   251  	driver["name"] = d.DriverName()
   252  	_ = dbObj.Set("driver", driver)
   253  
   254  	_ = dbObj.Set("q", func(c goja.FunctionCall) goja.Value {
   255  		v, l := goja.Null(), len(c.Arguments)
   256  		if l == 0 {
   257  			return v
   258  		}
   259  
   260  		var (
   261  			sql      = c.Arguments[0].String()
   262  			rows     *sqlx.Rows
   263  			err      error
   264  			value    map[string]interface{}
   265  			hasValue bool
   266  		)
   267  
   268  		if l == 2 {
   269  			value, hasValue = c.Arguments[1].Export().(map[string]interface{})
   270  		}
   271  
   272  		if hasValue {
   273  			if rows, err = d.NamedQuery(sql, value); err != nil {
   274  				return r.ToValue(err)
   275  			}
   276  		} else {
   277  			values := make([]interface{}, 0, l-1)
   278  			if l > 1 {
   279  				for _, a := range c.Arguments[1:] {
   280  					values = append(values, a.Export())
   281  				}
   282  			}
   283  			if rows, err = d.Queryx(sql, values...); err != nil {
   284  				return r.ToValue(err)
   285  			}
   286  		}
   287  
   288  		results := make([]map[string]interface{}, 0)
   289  		for rows.Next() {
   290  			result := make(map[string]interface{})
   291  			if err = rows.MapScan(result); err != nil {
   292  				return r.ToValue(err)
   293  			}
   294  			for k, v := range result {
   295  				if s, ok := v.([]byte); ok {
   296  					result[k] = string(s)
   297  				}
   298  			}
   299  			results = append(results, result)
   300  		}
   301  
   302  		if len(results) == 1 {
   303  			v = r.ToValue(results[0])
   304  		} else {
   305  			v = r.ToValue(results)
   306  		}
   307  
   308  		return v
   309  	})
   310  
   311  	_ = dbObj.Set("q2", func(c goja.FunctionCall) goja.Value {
   312  		v, l := goja.Null(), len(c.Arguments)
   313  		if l <= 1 {
   314  			return v
   315  		}
   316  
   317  		var (
   318  			typ      = c.Arguments[0].ToInteger()
   319  			sql      = c.Arguments[1].String()
   320  			rows     *sqlx.Rows
   321  			err      error
   322  			value    map[string]interface{}
   323  			hasValue bool
   324  		)
   325  
   326  		results := make([]map[string]interface{}, 0)
   327  
   328  		key := getCacheKeyFrom(c.Arguments)
   329  		val := getCacheValFrom(r, typ, key)
   330  		expiration := time.Hour
   331  		if val != nil {
   332  			if err := json.Unmarshal(val, &results); err != nil {
   333  				results = make([]map[string]interface{}, 0)
   334  			}
   335  		}
   336  
   337  		if len(results) == 0 {
   338  			if l == 3 {
   339  				value, hasValue = c.Arguments[2].Export().(map[string]interface{})
   340  			}
   341  
   342  			if hasValue {
   343  				if rows, err = d.NamedQuery(sql, value); err != nil {
   344  					return r.ToValue(err)
   345  				}
   346  			} else {
   347  				values := make([]interface{}, 0, l-2)
   348  				if l > 2 {
   349  					for _, a := range c.Arguments[2:] {
   350  						values = append(values, a.Export())
   351  					}
   352  				}
   353  				if rows, err = d.Queryx(sql, values...); err != nil {
   354  					return r.ToValue(err)
   355  				}
   356  			}
   357  
   358  			for rows.Next() {
   359  				result := make(map[string]interface{})
   360  				if err = rows.MapScan(result); err != nil {
   361  					return r.ToValue(err)
   362  				}
   363  				for k, v := range result {
   364  					if s, ok := v.([]byte); ok {
   365  						result[k] = string(s)
   366  					}
   367  				}
   368  				results = append(results, result)
   369  			}
   370  			if len(results) > 0 {
   371  				setCacheValFrom(r, typ, key, results, expiration)
   372  			}
   373  		}
   374  
   375  		if len(results) == 1 {
   376  			v = r.ToValue(results[0])
   377  		} else {
   378  			v = r.ToValue(results)
   379  		}
   380  
   381  		return v
   382  	})
   383  
   384  	_ = dbObj.Set("g", func(c goja.FunctionCall) goja.Value {
   385  		v, l := goja.Null(), len(c.Arguments)
   386  		if l == 0 {
   387  			return v
   388  		}
   389  
   390  		var (
   391  			sql      = c.Arguments[0].String()
   392  			rows     *sqlx.Rows
   393  			err      error
   394  			value    map[string]interface{}
   395  			hasValue bool
   396  		)
   397  
   398  		if l == 2 {
   399  			value, hasValue = c.Arguments[1].Export().(map[string]interface{})
   400  		}
   401  
   402  		if hasValue {
   403  			if rows, err = d.NamedQuery(sql, value); err != nil {
   404  				return r.ToValue(err)
   405  			}
   406  		} else {
   407  			values := make([]interface{}, 0, l-1)
   408  			if l > 1 {
   409  				for _, a := range c.Arguments[1:] {
   410  					values = append(values, a.Export())
   411  				}
   412  			}
   413  			if rows, err = d.Queryx(sql, values...); err != nil {
   414  				return r.ToValue(err)
   415  			}
   416  		}
   417  
   418  		for rows.Next() {
   419  			result := make(map[string]interface{})
   420  			if err = rows.MapScan(result); err != nil {
   421  				return r.ToValue(err)
   422  			}
   423  			for k, v := range result {
   424  				if s, ok := v.([]byte); ok {
   425  					result[k] = string(s)
   426  				}
   427  			}
   428  			if cols, err := rows.Columns(); err != nil || len(cols) > 1 {
   429  				v = r.ToValue(result)
   430  			} else if len(cols) > 0 {
   431  				v = r.ToValue(result[cols[0]])
   432  			}
   433  			break
   434  		}
   435  
   436  		return v
   437  	})
   438  
   439  	_ = dbObj.Set("g2", func(c goja.FunctionCall) goja.Value {
   440  		v, l := goja.Null(), len(c.Arguments)
   441  		if l <= 1 {
   442  			return v
   443  		}
   444  
   445  		var (
   446  			typ      = c.Arguments[0].ToInteger()
   447  			sql      = c.Arguments[1].String()
   448  			rows     *sqlx.Rows
   449  			err      error
   450  			value    map[string]interface{}
   451  			hasValue bool
   452  		)
   453  
   454  		var one interface{}
   455  		result := make(map[string]interface{})
   456  
   457  		key := getCacheKeyFrom(c.Arguments)
   458  		val := getCacheValFrom(r, typ, key)
   459  		expiration := time.Hour
   460  		if val != nil {
   461  			if val[0] == '{' {
   462  				if err := json.Unmarshal(val, &result); err != nil {
   463  					result = make(map[string]interface{})
   464  				} else {
   465  					v = r.ToValue(result)
   466  				}
   467  			} else {
   468  				if err := json.Unmarshal(val, &one); err == nil {
   469  					v = r.ToValue(one)
   470  				}
   471  			}
   472  		}
   473  
   474  		if one == nil && len(result) == 0 {
   475  			if l == 3 {
   476  				value, hasValue = c.Arguments[2].Export().(map[string]interface{})
   477  			}
   478  
   479  			if hasValue {
   480  				if rows, err = d.NamedQuery(sql, value); err != nil {
   481  					return r.ToValue(err)
   482  				}
   483  			} else {
   484  				values := make([]interface{}, 0, l-2)
   485  				if l > 2 {
   486  					for _, a := range c.Arguments[2:] {
   487  						values = append(values, a.Export())
   488  					}
   489  				}
   490  				if rows, err = d.Queryx(sql, values...); err != nil {
   491  					return r.ToValue(err)
   492  				}
   493  			}
   494  
   495  			for rows.Next() {
   496  				if err = rows.MapScan(result); err != nil {
   497  					return r.ToValue(err)
   498  				}
   499  				for k, v := range result {
   500  					if s, ok := v.([]byte); ok {
   501  						result[k] = string(s)
   502  					}
   503  				}
   504  				if cols, err := rows.Columns(); err != nil || len(cols) > 1 {
   505  					setCacheValFrom(r, typ, key, result, expiration)
   506  					v = r.ToValue(result)
   507  				} else if len(cols) > 0 {
   508  					setCacheValFrom(r, typ, key, result[cols[0]], expiration)
   509  					v = r.ToValue(result[cols[0]])
   510  				}
   511  				break
   512  			}
   513  		}
   514  
   515  		return v
   516  	})
   517  
   518  	_ = dbObj.Set("i", func(c goja.FunctionCall) goja.Value {
   519  		v, l := r.ToValue(-1), len(c.Arguments)
   520  		if l == 0 {
   521  			return v
   522  		}
   523  
   524  		var (
   525  			sql      = c.Arguments[0].String()
   526  			insertID int64
   527  			value    map[string]interface{}
   528  			hasValue bool
   529  		)
   530  
   531  		if l == 2 {
   532  			value, hasValue = c.Arguments[1].Export().(map[string]interface{})
   533  		}
   534  
   535  		if hasValue {
   536  			rows, err := d.Exec(sql, value)
   537  			if err != nil {
   538  				return r.ToValue(err)
   539  			}
   540  			insertID, _ = rows.LastInsertId()
   541  		} else {
   542  			values := make([]interface{}, 0, l-1)
   543  			if l > 1 {
   544  				for _, a := range c.Arguments[1:] {
   545  					values = append(values, a.Export())
   546  				}
   547  			}
   548  			rows, err := d.Exec(sql, values...)
   549  			if err != nil {
   550  				return r.ToValue(err)
   551  			}
   552  			insertID, _ = rows.LastInsertId()
   553  		}
   554  		v = r.ToValue(insertID)
   555  
   556  		return v
   557  	})
   558  
   559  	_ = dbObj.Set("x", func(c goja.FunctionCall) goja.Value {
   560  		v, l := r.ToValue(-1), len(c.Arguments)
   561  		if l == 0 {
   562  			return v
   563  		}
   564  
   565  		var (
   566  			sql      = c.Arguments[0].String()
   567  			affected int64
   568  			value    map[string]interface{}
   569  			hasValue bool
   570  		)
   571  
   572  		if l == 2 {
   573  			value, hasValue = c.Arguments[1].Export().(map[string]interface{})
   574  		}
   575  
   576  		if hasValue {
   577  			rows, err := d.Exec(sql, value)
   578  			if err != nil {
   579  				return r.ToValue(err)
   580  			}
   581  			affected, _ = rows.RowsAffected()
   582  		} else {
   583  			values := make([]interface{}, 0, l-1)
   584  			if l > 1 {
   585  				for _, a := range c.Arguments[1:] {
   586  					values = append(values, a.Export())
   587  				}
   588  			}
   589  			rows, err := d.Exec(sql, values...)
   590  			if err != nil {
   591  				return r.ToValue(err)
   592  			}
   593  			affected, _ = rows.RowsAffected()
   594  		}
   595  		v = r.ToValue(affected)
   596  
   597  		return v
   598  	})
   599  
   600  	r.Set("db", dbObj)
   601  }
   602  
   603  // Nats use nats in javascript.
   604  //  console.log(nats.name)
   605  //  console.log(nats.subject)
   606  // 	nats.pub('data'); nats.pub('subj','data')
   607  // 	nats.req('data'); nats.pub('data',3); nats.pub('subj','data',3) // timeout:3s
   608  func Nats(r *goja.Runtime, nc *nats.Conn, subj string) {
   609  	natsObj := r.NewObject()
   610  
   611  	_ = natsObj.Set("name", nc.Opts.Name)
   612  	_ = natsObj.Set("subject", subj)
   613  
   614  	_ = natsObj.Set("pub", func(c goja.FunctionCall) goja.Value {
   615  		v, l := goja.Null(), len(c.Arguments)
   616  		if l == 1 && subj != "" {
   617  			data := c.Arguments[0].String()
   618  			if err := nc.Publish(subj, f.Bytes(data)); err != nil {
   619  				return r.ToValue(err)
   620  			}
   621  			return r.ToValue(0)
   622  		} else if l == 2 {
   623  			subj, data := c.Arguments[0].String(), c.Arguments[1].String()
   624  			if err := nc.Publish(subj, f.Bytes(data)); err != nil {
   625  				return r.ToValue(err)
   626  			}
   627  			return r.ToValue(0)
   628  		}
   629  		return v
   630  	})
   631  
   632  	_ = natsObj.Set("req", func(c goja.FunctionCall) goja.Value {
   633  		v, l := goja.Null(), len(c.Arguments)
   634  		if l == 1 && subj != "" {
   635  			data := c.Arguments[0].String()
   636  			msg, err := nc.Request(subj, f.Bytes(data), 3*time.Second)
   637  			if err != nil {
   638  				return r.ToValue(err)
   639  			}
   640  			if msg.Data == nil {
   641  				return v
   642  			}
   643  			return r.ToValue(string(msg.Data))
   644  		} else if l == 2 && subj != "" {
   645  			data, ms := c.Arguments[0].String(), c.Arguments[1].ToInteger()
   646  			msg, err := nc.Request(subj, f.Bytes(data), time.Duration(ms)*time.Second)
   647  			if err != nil {
   648  				return r.ToValue(err)
   649  			}
   650  			if msg.Data == nil {
   651  				return v
   652  			}
   653  			return r.ToValue(string(msg.Data))
   654  		} else if l == 3 {
   655  			subj, data, ms := c.Arguments[0].String(), c.Arguments[1].String(), c.Arguments[2].ToInteger()
   656  			msg, err := nc.Request(subj, f.Bytes(data), time.Duration(ms)*time.Second)
   657  			if err != nil {
   658  				return r.ToValue(err)
   659  			}
   660  			if msg.Data == nil {
   661  				return v
   662  			}
   663  			return r.ToValue(string(msg.Data))
   664  		}
   665  		return v
   666  	})
   667  
   668  	r.Set("nats", natsObj)
   669  }
   670  
   671  // Ajax use $ in javascript.
   672  // 	dump($.header, $.user, $.trace, $.body, $.cookie, $.token)
   673  // 	var res = $.q("get",url)
   674  // 	var res = $.q("get",url,param)
   675  // 	var res = $.q("post",url,param,"json")
   676  // 	$.q("get",url,param,"",function(data,status))
   677  // 	$.q("post",url,param,"json",function(data,status))
   678  func Ajax(r *goja.Runtime) {
   679  	jObj := r.NewObject()
   680  
   681  	header := make(map[string]interface{})
   682  	header["Accept"] = "*/*"
   683  	header["Accept-Language"] = "zh-CN,zh;q=0.9,zh;q=0.8,en;q=0.7"
   684  	header["User-Agent"] = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.105 Safari/537.36"
   685  	_ = jObj.Set("header", header)
   686  
   687  	user := make(map[string]string)
   688  	user["username"] = ""
   689  	user["password"] = ""
   690  	_ = jObj.Set("user", user)
   691  	_ = jObj.Set("body", "")
   692  	_ = jObj.Set("cookie", "")
   693  	_ = jObj.Set("token", "")
   694  	_ = jObj.Set("trace", false)
   695  
   696  	var trace = func(req *resty.Request, res *resty.Response, result map[string]interface{}) {
   697  		if jObj.Get("trace").ToBoolean() {
   698  			cookies := make(map[string]interface{})
   699  			for _, cookie := range req.Cookies {
   700  				name, val := cookie.Name, cookie.Value
   701  				cookies[name] = val
   702  			}
   703  			dump := `
   704  ---- %s: %s
   705  ---- trace: %s
   706  ---- request-header: %s
   707  ---- request-cookie: %s
   708  ---- request-body: %s
   709  ---- response-body: %s
   710  ---- response-cookie: %s
   711  ---- response-result: %s
   712  `
   713  			fmt.Printf(dump, req.Method, req.URL, f.EncodedJson(req.TraceInfo()), f.EncodedJson(jObj.Get("header").Export()), f.EncodedJson(cookies), req.Body, res.Body(), f.EncodedJson(jObj.Get("cookie").Export()), f.EncodedJson(result))
   714  		}
   715  	}
   716  
   717  	var setReq = func(req *resty.Request, data interface{}) {
   718  		if jObj.Get("trace").ToBoolean() {
   719  			req.EnableTrace()
   720  		}
   721  
   722  		if tObj := jObj.Get("header").Export(); tObj != nil {
   723  			switch tVal := tObj.(type) {
   724  			case map[string]interface{}:
   725  				for name, val := range tVal {
   726  					req.SetHeader(name, f.ToString(val))
   727  				}
   728  			case string:
   729  				for _, line := range strings.Split(strings.TrimSpace(tVal), "\n") {
   730  					if str := strings.Split(strings.TrimSpace(line), ":"); len(str) == 2 {
   731  						req.SetHeader(strings.TrimSpace(str[0]), strings.TrimSpace(str[1]))
   732  					}
   733  				}
   734  			}
   735  		}
   736  
   737  		if tObj := jObj.Get("cookie").Export(); tObj != nil {
   738  			switch tVal := tObj.(type) {
   739  			case map[string]interface{}:
   740  				for name, val := range tVal {
   741  					req.SetCookie(&http.Cookie{Name: name, Value: f.ToString(val)})
   742  				}
   743  			case string:
   744  				for _, line := range strings.Split(strings.TrimSpace(tVal), "\n") {
   745  					if str := strings.Split(strings.TrimSpace(line), ":"); len(str) == 2 {
   746  						name, val := strings.TrimSpace(str[0]), strings.TrimSpace(str[1])
   747  						req.SetCookie(&http.Cookie{Name: name, Value: val})
   748  					}
   749  				}
   750  			}
   751  		}
   752  
   753  		if data == nil {
   754  			data = jObj.Get("body").Export()
   755  		}
   756  		if data != nil {
   757  			switch tVal := data.(type) {
   758  			case string:
   759  				if tVal != "" {
   760  					req.SetBody([]byte(tVal))
   761  				}
   762  			case map[string]interface{}:
   763  				switch req.Header.Get("Content-Type") {
   764  				case "application/json":
   765  					if buf, err := json.Marshal(tVal); err == nil {
   766  						req.SetBody(buf)
   767  					}
   768  				case "application/xml":
   769  					if buf, err := xml.Marshal(tVal); err == nil {
   770  						req.SetBody(buf)
   771  					}
   772  				default:
   773  					items := make([]string, 0, len(tVal))
   774  					for k, v := range tVal {
   775  						items = append(items, url.QueryEscape(k)+"="+url.QueryEscape(f.ToString(v)))
   776  					}
   777  					req.SetBody(f.Bytes(strings.Join(items, "&")))
   778  				}
   779  			case map[interface{}]interface{}:
   780  				switch req.Header.Get("Content-Type") {
   781  				case "application/json":
   782  					if buf, err := json.Marshal(tVal); err == nil {
   783  						req.SetBody(buf)
   784  					}
   785  				case "application/xml":
   786  					if buf, err := xml.Marshal(tVal); err == nil {
   787  						req.SetBody(buf)
   788  					}
   789  				default:
   790  					items := make([]string, 0, len(tVal))
   791  					for k, v := range tVal {
   792  						items = append(items, url.QueryEscape(f.ToString(k))+"="+url.QueryEscape(f.ToString(v)))
   793  					}
   794  					req.SetBody(f.Bytes(strings.Join(items, "&")))
   795  				}
   796  			default:
   797  				if buf, err := json.Marshal(tVal); err == nil {
   798  					req.SetBody(buf)
   799  				}
   800  			}
   801  		}
   802  	}
   803  
   804  	var setRes = func(res *resty.Response) {
   805  		cookie := make(map[string]interface{})
   806  		for _, cc := range res.Cookies() {
   807  			cookie[cc.Name] = cc.Value
   808  		}
   809  		_ = jObj.Set("cookie", cookie)
   810  		_ = jObj.Set("body", "")
   811  	}
   812  
   813  	_ = jObj.Set("q", func(c goja.FunctionCall) goja.Value {
   814  		v, l := goja.Null(), len(c.Arguments)
   815  		if l < 2 {
   816  			return v
   817  		}
   818  
   819  		method, urlStr := c.Arguments[0].String(), c.Arguments[1].String()
   820  		if method == "" || urlStr == "" {
   821  			return v
   822  		}
   823  
   824  		var fn func(map[string]interface{}, int)
   825  		callback := l == 5
   826  		if callback {
   827  			if err := r.ExportTo(c.Arguments[4], &fn); err != nil {
   828  				return r.ToValue(err)
   829  			}
   830  		}
   831  
   832  		var (
   833  			cont string
   834  			data interface{}
   835  			req  = ht.NewRestRequest()
   836  		)
   837  		if l > 3 {
   838  			data = c.Arguments[2].Export()
   839  			if err := r.ExportTo(c.Arguments[3], &fn); err == nil {
   840  				callback = true
   841  			} else {
   842  				cont = c.Arguments[3].String()
   843  			}
   844  		} else if l > 2 {
   845  			if err := r.ExportTo(c.Arguments[2], &fn); err == nil {
   846  				callback = true
   847  			} else {
   848  				data = c.Arguments[2].Export()
   849  			}
   850  		}
   851  
   852  		if strings.Contains(cont, "json") {
   853  			req.SetHeader("Content-Type", "application/json")
   854  		} else if strings.Contains(cont, "xml") {
   855  			req.SetHeader("Content-Type", "application/xml")
   856  		} else if strings.Contains(cont, "form") || strings.Contains(cont, "url") {
   857  			req.SetHeader("Content-Type", "application/x-www-form-urlencoded")
   858  		} else if strings.Contains(cont, "file") || strings.Contains(cont, "data") {
   859  			req.SetHeader("Content-Type", "multipart/form-data")
   860  		} else if strings.Contains(cont, "text") {
   861  			req.SetHeader("Content-Type", "text/plain")
   862  		} else if len(cont) > 10 {
   863  			req.SetHeader("Content-Type", cont)
   864  		}
   865  
   866  		if token := jObj.Get("token").String(); token != "" {
   867  			req.SetAuthToken(token)
   868  		}
   869  
   870  		if user, ok := jObj.Get("user").Export().(map[string]string); ok && user != nil && user["username"] != "" {
   871  			req.SetBasicAuth(user["username"], user["password"])
   872  		}
   873  
   874  		setReq(req, data)
   875  		method = strings.ToUpper(method)
   876  		result := make(map[string]interface{})
   877  		res, err := req.Execute(method, urlStr)
   878  		if err != nil {
   879  			result["error"] = err.Error()
   880  			result["code"] = -1
   881  			result["data"] = nil
   882  			// request did not occur and could not be traced
   883  			// trace(req, res, result)
   884  			if callback {
   885  				fn(result, -1)
   886  				return v
   887  			}
   888  			return r.ToValue(result)
   889  		}
   890  
   891  		statusCode := res.StatusCode()
   892  		result["error"] = res.Status()
   893  		result["code"] = statusCode
   894  		result["data"] = nil
   895  		setRes(res)
   896  		buf := res.Body()
   897  		if buf == nil || statusCode >= 400 {
   898  			trace(req, res, result)
   899  			if callback {
   900  				fn(result, statusCode)
   901  				return v
   902  			}
   903  			return r.ToValue(result)
   904  		}
   905  
   906  		buf = bytes.TrimSpace(buf)
   907  		st0, st1 := buf[0], buf[len(buf)-1]
   908  		if st0 == '[' && st1 == ']' {
   909  			var records []map[string]interface{}
   910  			if err := json.Unmarshal(buf, &records); err == nil {
   911  				result["data"] = records
   912  			} else {
   913  				result["data"] = f.String(buf)
   914  			}
   915  		} else if st0 == '{' || st1 == '}' {
   916  			var record map[string]interface{}
   917  			if err := json.Unmarshal(buf, &record); err == nil {
   918  				result["data"] = record
   919  			} else {
   920  				result["data"] = f.String(buf)
   921  			}
   922  		} else {
   923  			result["data"] = f.String(buf)
   924  		}
   925  
   926  		result["error"] = nil
   927  		trace(req, res, result)
   928  		if callback {
   929  			fn(result, statusCode)
   930  			return v
   931  		}
   932  		return r.ToValue(result)
   933  	})
   934  
   935  	r.Set("$", jObj)
   936  }
   937  
   938  // Cache use cache in javascript.
   939  // 	dump(cache.dir, cache.cap)
   940  //  var val = cache.get("key")
   941  //  var has = cache.has("key")
   942  //  cache.set("key",123)
   943  //  cache.del("key")
   944  //  cache.reset(); cache.clear(); cache.clear('cache-01');
   945  //  try { cache.save('cache-01'); cache.load('cache-01'); } catch (e) { throw(e) }
   946  func Cache(r *goja.Runtime, cache *fastcache.Cache, cacheDir string, maxBytes ...int) {
   947  	var err error
   948  	// default directory
   949  	currentDir := f.CurrentDir()
   950  	defaultDir := filepath.Join(currentDir, ".nats")
   951  	if cacheDir == "" {
   952  		cacheDir = defaultDir
   953  	}
   954  	// creates a fast cache instance
   955  	capacity := 1073741824 // 1GB cache capacity
   956  	if cache == nil {
   957  		if len(maxBytes) > 0 {
   958  			capacity = maxBytes[0]
   959  		}
   960  		cache = fastcache.New(capacity)
   961  	}
   962  
   963  	cObj := r.NewObject()
   964  
   965  	_ = cObj.Set("dir", cacheDir)
   966  	_ = cObj.Set("cap", capacity)
   967  
   968  	_ = cObj.Set("get", func(c goja.FunctionCall) goja.Value {
   969  		v, l := goja.Null(), len(c.Arguments)
   970  		if l < 1 {
   971  			return v
   972  		}
   973  		key := c.Arguments[0].String()
   974  		if key == "" {
   975  			return v
   976  		}
   977  
   978  		p := cache.Get(nil, f.Bytes(key))
   979  		if p == nil || len(p) == 0 {
   980  			return v
   981  		}
   982  
   983  		var val interface{}
   984  		if err := json.Unmarshal(p, &val); err == nil {
   985  			v = r.ToValue(val)
   986  		}
   987  
   988  		return v
   989  	})
   990  
   991  	_ = cObj.Set("set", func(c goja.FunctionCall) goja.Value {
   992  		v, l := goja.Null(), len(c.Arguments)
   993  		if l < 2 {
   994  			return v
   995  		}
   996  		key := c.Arguments[0].String()
   997  		if key == "" {
   998  			return v
   999  		}
  1000  
  1001  		val := c.Arguments[1].Export()
  1002  		if p, err := json.Marshal(val); err != nil {
  1003  			cache.Set(f.Bytes(key), []byte{})
  1004  		} else {
  1005  			cache.Set(f.Bytes(key), p)
  1006  		}
  1007  
  1008  		return v
  1009  	})
  1010  
  1011  	_ = cObj.Set("del", func(c goja.FunctionCall) goja.Value {
  1012  		v, l := goja.Undefined(), len(c.Arguments)
  1013  		if l < 1 {
  1014  			return v
  1015  		}
  1016  		key := c.Arguments[0].String()
  1017  		if key == "" {
  1018  			return v
  1019  		}
  1020  
  1021  		cache.Del(f.Bytes(key))
  1022  
  1023  		return v
  1024  	})
  1025  
  1026  	_ = cObj.Set("has", func(c goja.FunctionCall) goja.Value {
  1027  		v, l := r.ToValue(false), len(c.Arguments)
  1028  		if l < 1 {
  1029  			return v
  1030  		}
  1031  		key := c.Arguments[0].String()
  1032  		if key == "" {
  1033  			return v
  1034  		}
  1035  
  1036  		p := cache.Has(f.Bytes(key))
  1037  		v = r.ToValue(p)
  1038  
  1039  		return v
  1040  	})
  1041  
  1042  	_ = cObj.Set("reset", func(c goja.FunctionCall) goja.Value {
  1043  		cache.Reset()
  1044  		return goja.Undefined()
  1045  	})
  1046  	_ = cObj.Set("clear", func(c goja.FunctionCall) goja.Value {
  1047  		cache.Reset()
  1048  
  1049  		l, dir := len(c.Arguments), ""
  1050  		if l > 0 {
  1051  			dir = filepath.Join(currentDir, c.Arguments[0].String())
  1052  		}
  1053  		if dir == "" {
  1054  			dir = cacheDir
  1055  		}
  1056  		if f.IsDir(dir) {
  1057  			if err := os.RemoveAll(dir); err != nil {
  1058  				panic(err.Error())
  1059  			}
  1060  		}
  1061  		return goja.Undefined()
  1062  	})
  1063  
  1064  	_ = cObj.Set("load", func(c goja.FunctionCall) goja.Value {
  1065  		l, dir := len(c.Arguments), ""
  1066  		if l > 0 {
  1067  			dir = filepath.Join(currentDir, c.Arguments[0].String())
  1068  		}
  1069  		if dir == "" {
  1070  			dir = cacheDir
  1071  			if f.PathExists(dir) == false {
  1072  				return goja.Undefined()
  1073  			}
  1074  		}
  1075  		if f.PathExists(dir) == false {
  1076  			panic("The specified directory does not exist")
  1077  		}
  1078  		if f.PathExists(filepath.Join(dir, "metadata.bin")) == false {
  1079  			return goja.Undefined()
  1080  		}
  1081  		if cache, err = fastcache.LoadFromFile(dir); err != nil {
  1082  			panic(err.Error())
  1083  		}
  1084  		return goja.Undefined()
  1085  	})
  1086  
  1087  	_ = cObj.Set("save", func(c goja.FunctionCall) goja.Value {
  1088  		l, dir := len(c.Arguments), ""
  1089  		if l > 0 {
  1090  			dir = filepath.Join(currentDir, c.Arguments[0].String())
  1091  			// creates a new directory if does not exist
  1092  			if err = f.Mkdir(dir); err != nil {
  1093  				panic(err.Error())
  1094  			}
  1095  		}
  1096  		if dir == "" {
  1097  			dir = cacheDir
  1098  			// creates a new directory if does not exist
  1099  			if err = f.Mkdir(dir); err != nil {
  1100  				panic(err.Error())
  1101  			}
  1102  		}
  1103  		if f.PathExists(dir) == false {
  1104  			panic("The specified directory does not exist")
  1105  		}
  1106  		if err = cache.SaveToFileConcurrent(dir, 0); err != nil {
  1107  			panic(err.Error())
  1108  		}
  1109  		return goja.Undefined()
  1110  	})
  1111  
  1112  	r.Set("cache", cObj)
  1113  	setCacheClient(r, cache)
  1114  }
  1115  
  1116  // Redis use redis in javascript.
  1117  // 	redis.get(key)
  1118  // 	redis.del(key,key1,key2)
  1119  // 	redis.set(key,value,86400) // 1 days
  1120  // 	redis.setNX(key,value,86400)
  1121  // 	redis.incr(key), incr(key,2)
  1122  // 	redis.lpush(key,1,2,3)
  1123  // 	redis.rpush(key,1,2,3)
  1124  // 	redis.sort(key,0,10,'asc')
  1125  // 	redis.list(key,0,10)
  1126  // 	redis.do('SET', key, value)
  1127  // 	redis.eval('...')
  1128  //  http://www.runoob.com/redis/redis-tutorial.html
  1129  func Redis(r *goja.Runtime, client *redis.Client) {
  1130  	rObj := r.NewObject()
  1131  
  1132  	// GET key
  1133  	_ = rObj.Set("get", func(c goja.FunctionCall) goja.Value {
  1134  		v, l := goja.Null(), len(c.Arguments)
  1135  		if l < 1 {
  1136  			return v
  1137  		}
  1138  
  1139  		res, err := client.Get(c.Arguments[0].String()).Result()
  1140  		if err == redis.Nil {
  1141  			return v
  1142  		} else if err != nil {
  1143  			return r.ToValue(err)
  1144  		}
  1145  
  1146  		return r.ToValue(res)
  1147  	})
  1148  
  1149  	// TTL key
  1150  	_ = rObj.Set("ttl", func(c goja.FunctionCall) goja.Value {
  1151  		v, l := goja.Null(), len(c.Arguments)
  1152  		if l < 1 {
  1153  			return v
  1154  		}
  1155  
  1156  		res, err := client.TTL(c.Arguments[0].String()).Result()
  1157  		if err == redis.Nil {
  1158  			return v
  1159  		} else if err != nil {
  1160  			return r.ToValue(err)
  1161  		}
  1162  
  1163  		return r.ToValue(res)
  1164  	})
  1165  
  1166  	// DEL key
  1167  	_ = rObj.Set("del", func(c goja.FunctionCall) goja.Value {
  1168  		v, l := goja.Null(), len(c.Arguments)
  1169  		if l < 1 {
  1170  			return v
  1171  		}
  1172  
  1173  		args := make([]string, 0, l)
  1174  		for _, a := range c.Arguments {
  1175  			args = append(args, a.String())
  1176  		}
  1177  		res, err := client.Del(args...).Result()
  1178  		if err == redis.Nil {
  1179  			return v
  1180  		} else if err != nil {
  1181  			return r.ToValue(err)
  1182  		}
  1183  
  1184  		return r.ToValue(res)
  1185  	})
  1186  
  1187  	// SET key value EX 10
  1188  	_ = rObj.Set("set", func(c goja.FunctionCall) goja.Value {
  1189  		v, l := goja.Null(), len(c.Arguments)
  1190  		if l < 3 {
  1191  			return v
  1192  		}
  1193  
  1194  		res, err := client.Set(c.Arguments[0].String(), c.Arguments[1].Export(), time.Duration(c.Arguments[2].ToInteger())*time.Second).Result()
  1195  		if err != nil {
  1196  			return r.ToValue(err)
  1197  		}
  1198  
  1199  		return r.ToValue(res)
  1200  	})
  1201  
  1202  	// SET key value EX 10 NX
  1203  	_ = rObj.Set("setNX", func(c goja.FunctionCall) goja.Value {
  1204  		v, l := goja.Null(), len(c.Arguments)
  1205  		if l < 3 {
  1206  			return v
  1207  		}
  1208  
  1209  		res, err := client.SetNX(c.Arguments[0].String(), c.Arguments[1].Export(), time.Duration(c.Arguments[2].ToInteger())*time.Second).Result()
  1210  		if err != nil {
  1211  			return r.ToValue(err)
  1212  		}
  1213  
  1214  		return r.ToValue(res)
  1215  	})
  1216  
  1217  	// INCR key, IncrBy key 10
  1218  	_ = rObj.Set("incr", func(c goja.FunctionCall) goja.Value {
  1219  		v, l := goja.Null(), len(c.Arguments)
  1220  		if l < 1 {
  1221  			return v
  1222  		}
  1223  
  1224  		if l == 1 {
  1225  			res, err := client.Incr(c.Arguments[0].String()).Result()
  1226  			if err != nil {
  1227  				return r.ToValue(err)
  1228  			}
  1229  			return r.ToValue(res)
  1230  		}
  1231  
  1232  		res, err := client.IncrBy(c.Arguments[0].String(), c.Arguments[1].ToInteger()).Result()
  1233  		if err != nil {
  1234  			return r.ToValue(err)
  1235  		}
  1236  		return r.ToValue(res)
  1237  	})
  1238  
  1239  	// LPUSH list 1 10 100
  1240  	_ = rObj.Set("lpush", func(c goja.FunctionCall) goja.Value {
  1241  		v, l := goja.Null(), len(c.Arguments)
  1242  		if l < 2 {
  1243  			return v
  1244  		}
  1245  
  1246  		args := make([]interface{}, 0, l-1)
  1247  		for i, a := range c.Arguments {
  1248  			if i == 0 {
  1249  				continue
  1250  			}
  1251  			args = append(args, a.Export())
  1252  		}
  1253  		res, err := client.LPush(c.Arguments[0].String(), args...).Result()
  1254  		if err != nil {
  1255  			return r.ToValue(err)
  1256  		}
  1257  
  1258  		return r.ToValue(res)
  1259  	})
  1260  
  1261  	// RPUSH list 1 10 100
  1262  	_ = rObj.Set("rpush", func(c goja.FunctionCall) goja.Value {
  1263  		v, l := goja.Null(), len(c.Arguments)
  1264  		if l < 2 {
  1265  			return v
  1266  		}
  1267  
  1268  		args := make([]interface{}, 0, l-1)
  1269  		for i, a := range c.Arguments {
  1270  			if i == 0 {
  1271  				continue
  1272  			}
  1273  			args = append(args, a.Export())
  1274  		}
  1275  		res, err := client.RPush(c.Arguments[0].String(), args...).Result()
  1276  		if err != nil {
  1277  			return r.ToValue(err)
  1278  		}
  1279  
  1280  		return r.ToValue(res)
  1281  	})
  1282  
  1283  	// SORT list LIMIT 0 2 ASC
  1284  	_ = rObj.Set("sort", func(c goja.FunctionCall) goja.Value {
  1285  		v, l := goja.Null(), len(c.Arguments)
  1286  		if l < 4 {
  1287  			return v
  1288  		}
  1289  
  1290  		sort := redis.Sort{Offset: c.Arguments[1].ToInteger(), Count: c.Arguments[2].ToInteger(), Order: strings.ToUpper(c.Arguments[3].String())}
  1291  		res, err := client.Sort(c.Arguments[0].String(), &sort).Result()
  1292  		if err == redis.Nil {
  1293  			return v
  1294  		} else if err != nil {
  1295  			return r.ToValue(err)
  1296  		}
  1297  
  1298  		return r.ToValue(res)
  1299  	})
  1300  
  1301  	// GetRange list 0 10
  1302  	_ = rObj.Set("list", func(c goja.FunctionCall) goja.Value {
  1303  		v, l := goja.Null(), len(c.Arguments)
  1304  		if l < 3 {
  1305  			return v
  1306  		}
  1307  
  1308  		res, err := client.GetRange(c.Arguments[0].String(), c.Arguments[1].ToInteger(), c.Arguments[2].ToInteger()).Result()
  1309  		if err == redis.Nil {
  1310  			return v
  1311  		} else if err != nil {
  1312  			return r.ToValue(err)
  1313  		}
  1314  
  1315  		return r.ToValue(res)
  1316  	})
  1317  
  1318  	_ = rObj.Set("do", func(c goja.FunctionCall) goja.Value {
  1319  		v, l := goja.Null(), len(c.Arguments)
  1320  		if l < 2 {
  1321  			return v
  1322  		}
  1323  
  1324  		args := make([]interface{}, 0, l)
  1325  		for _, a := range c.Arguments {
  1326  			args = append(args, a.Export())
  1327  		}
  1328  
  1329  		res, err := client.Do(args...).Result()
  1330  		if err == redis.Nil {
  1331  			return v
  1332  		} else if err != nil {
  1333  			return r.ToValue(err)
  1334  		}
  1335  
  1336  		return r.ToValue(res)
  1337  	})
  1338  
  1339  	_ = rObj.Set("eval", func(c goja.FunctionCall) goja.Value {
  1340  		v, l := goja.Null(), len(c.Arguments)
  1341  		if l < 2 {
  1342  			return v
  1343  		}
  1344  
  1345  		var script string
  1346  		keys, args := make([]string, 0, l-1), make([]interface{}, 0, l-2)
  1347  		for i, a := range c.Arguments {
  1348  			if i == 0 {
  1349  				script = a.String()
  1350  				continue
  1351  			}
  1352  			switch tVal := a.Export().(type) {
  1353  			case string:
  1354  				keys = append(keys, tVal)
  1355  			default:
  1356  				args = append(args, tVal)
  1357  			}
  1358  		}
  1359  		if script == "" {
  1360  			return v
  1361  		}
  1362  
  1363  		res, err := client.Eval(script, keys, args...).Result()
  1364  		if err == redis.Nil {
  1365  			return v
  1366  		} else if err != nil {
  1367  			return r.ToValue(err)
  1368  		}
  1369  
  1370  		return r.ToValue(res)
  1371  	})
  1372  
  1373  	r.Set("redis", rObj)
  1374  	setRedisClient(r, client)
  1375  }
  1376  
  1377  // getCacheValFrom Cache{ Memory = 0, Redis, Default }
  1378  func getCacheValFrom(r *goja.Runtime, typ int64, key []byte) []byte {
  1379  	if typ == 0 {
  1380  		if c := getCacheClient(r); c != nil {
  1381  			val := c.Get(nil, key)
  1382  			if val == nil || len(val) == 0 {
  1383  				return nil
  1384  			}
  1385  			return val
  1386  		}
  1387  	} else if typ == 1 {
  1388  		if c := getRedisClient(r); c != nil {
  1389  			val, err := c.Get(f.String(key)).Result()
  1390  			if err != nil {
  1391  				return nil
  1392  			}
  1393  			return f.Bytes(val)
  1394  		}
  1395  	} else if typ == 2 {
  1396  		if c := getCacheClient(r); c != nil {
  1397  			val := c.Get(nil, key)
  1398  			if val == nil || len(val) == 0 {
  1399  				if c := getRedisClient(r); c != nil {
  1400  					val, err := c.Get(f.String(key)).Result()
  1401  					if err != nil {
  1402  						return nil
  1403  					}
  1404  					return f.Bytes(val)
  1405  				}
  1406  			}
  1407  			return val
  1408  		}
  1409  		if c := getRedisClient(r); c != nil {
  1410  			val, err := c.Get(f.String(key)).Result()
  1411  			if err != nil {
  1412  				return nil
  1413  			}
  1414  			return f.Bytes(val)
  1415  		}
  1416  	}
  1417  	return nil
  1418  }
  1419  
  1420  // setCacheValFrom Cache{ Memory = 0, Redis, Default }
  1421  func setCacheValFrom(r *goja.Runtime, typ int64, key []byte, value interface{}, expiration time.Duration) {
  1422  	p, err := json.Marshal(value)
  1423  	if err != nil {
  1424  		return
  1425  	}
  1426  	if typ == 0 {
  1427  		if c := getCacheClient(r); c != nil {
  1428  			c.Set(key, p)
  1429  		}
  1430  	} else if typ == 1 {
  1431  		if c := getRedisClient(r); c != nil {
  1432  			_ = c.Set(f.String(key), p, expiration).Err()
  1433  		}
  1434  	} else if typ == 2 {
  1435  		if c := getCacheClient(r); c != nil {
  1436  			c.Set(key, p)
  1437  		}
  1438  		if c := getRedisClient(r); c != nil {
  1439  			_ = c.Set(f.String(key), p, expiration).Err()
  1440  		}
  1441  	}
  1442  }
  1443  
  1444  func getCacheKeyFrom(args []goja.Value) []byte {
  1445  	data := make([]byte, 0, 256)
  1446  	for _, obj := range args[1:] {
  1447  		if goja.IsUndefined(obj) || goja.IsNull(obj) {
  1448  			//data = append(data, ' ')
  1449  			continue
  1450  		}
  1451  		v := obj.Export()
  1452  		if p, err := json.Marshal(v); err == nil {
  1453  			data = append(data, p...)
  1454  		}
  1455  	}
  1456  	data = f.BytesUint32(crc32.ChecksumIEEE(data))
  1457  	return data
  1458  }
  1459  
  1460  func setCacheClient(r *goja.Runtime, client *fastcache.Cache) {
  1461  	r.Set("_cache", client)
  1462  }
  1463  
  1464  func getCacheClient(r *goja.Runtime) *fastcache.Cache {
  1465  	obj := r.Get("_cache")
  1466  	if obj == nil || goja.IsUndefined(obj) || goja.IsNull(obj) {
  1467  		return nil
  1468  	}
  1469  	if client, ok := obj.Export().(*fastcache.Cache); ok {
  1470  		return client
  1471  	}
  1472  	return nil
  1473  }
  1474  
  1475  func setRedisClient(r *goja.Runtime, client *redis.Client) {
  1476  	r.Set("_redis", client)
  1477  }
  1478  
  1479  func getRedisClient(r *goja.Runtime) *redis.Client {
  1480  	obj := r.Get("_redis")
  1481  	if obj == nil || goja.IsUndefined(obj) || goja.IsNull(obj) {
  1482  		return nil
  1483  	}
  1484  	if client, ok := obj.Export().(*redis.Client); ok {
  1485  		return client
  1486  	}
  1487  	return nil
  1488  }