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

     1  package js
     2  
     3  import (
     4  	"io/ioutil"
     5  	"path/filepath"
     6  	"time"
     7  
     8  	"github.com/angenalZZZ/gofunc/f"
     9  
    10  	"github.com/angenalZZZ/gofunc/data"
    11  	"github.com/angenalZZZ/gofunc/data/cache/fastcache"
    12  	"github.com/angenalZZZ/gofunc/data/cache/store"
    13  	"github.com/angenalZZZ/gofunc/log"
    14  	nat "github.com/angenalZZZ/gofunc/rpc/nats"
    15  	"github.com/dop251/goja"
    16  	"github.com/go-redis/redis/v7"
    17  	"github.com/jmoiron/sqlx"
    18  	"github.com/nats-io/nats.go"
    19  )
    20  
    21  // Runtime vm for javascript runtime and register
    22  var Runtime *GoRuntime
    23  
    24  // GoRuntime javascript runtime and register
    25  type GoRuntime struct {
    26  	// is already registered
    27  	registered bool
    28  	// new javascript runtime
    29  	*goja.Runtime
    30  	// load javascript modules
    31  	Modules map[string]goja.Value
    32  	// field: *log.Logger
    33  	*log.Logger
    34  	// field: *sqlx.DB
    35  	*sqlx.DB
    36  	DbType, DbConn string
    37  	// field: *nats.Conn
    38  	NatConn    *nats.Conn
    39  	NatSubject string
    40  	// field: *redis.Client
    41  	RedisClient *redis.Client
    42  	// field: *fastcache.Cache new fast thread-safe inmemory cache optimized for big number of entries
    43  	*fastcache.Cache
    44  	// field: CacheDir sets cache persist to disk directory
    45  	CacheDir string
    46  }
    47  
    48  // GoRuntimeParam all parameters of javascript runtime and register
    49  type GoRuntimeParam struct {
    50  	// parameter: *log.Logger
    51  	Log *log.Logger
    52  	// parameter: *sqlx.DB
    53  	*sqlx.DB
    54  	DbType, DbConn string
    55  	// parameter: *nats.Conn
    56  	NatConn    *nats.Conn
    57  	NatSubject string
    58  	// parameter: *redis.Client
    59  	RedisClient *redis.Client
    60  	// parameter: *fastcache.Cache new fast thread-safe inmemory cache optimized for big number of entries
    61  	*fastcache.Cache
    62  	// parameter: CacheDir sets cache persist to disk directory
    63  	CacheDir string
    64  }
    65  
    66  // NewRuntime create a javascript runtime and register from parameter or global vars.
    67  func NewRuntime(parameter *GoRuntimeParam) *GoRuntime {
    68  	var (
    69  		db  *sqlx.DB
    70  		vm  = goja.New()
    71  		r   = new(GoRuntime)
    72  		err error
    73  	)
    74  
    75  	// new javascript runtime
    76  	r.Runtime, r.Modules = vm, make(map[string]goja.Value)
    77  
    78  	// parameter: *log.Logger
    79  	logger := log.Log
    80  	if parameter != nil && parameter.Log != nil {
    81  		logger = parameter.Log
    82  	}
    83  	if logger != nil {
    84  		r.Logger = logger
    85  	}
    86  
    87  	// parameter: *sqlx.DB
    88  	dbType, dbConn := data.DbType, data.DbConn
    89  	if parameter != nil && parameter.DbType != "" && parameter.DbConn != "" {
    90  		dbType, dbConn = parameter.DbType, parameter.DbConn
    91  	}
    92  	if parameter != nil && parameter.DB != nil {
    93  		r.DB = parameter.DB
    94  	} else if dbType != "" && dbConn != "" {
    95  		r.DbType, r.DbConn = dbType, dbConn
    96  		db, err = sqlx.Open(dbType, dbConn)
    97  		if err != nil && logger != nil {
    98  			logger.Error().Msgf("failed connect to db: %v\n", err)
    99  		}
   100  		if db != nil {
   101  			db.SetConnMaxLifetime(time.Minute)
   102  			db.SetMaxIdleConns(4)
   103  			db.SetMaxOpenConns(40)
   104  			r.DB = db
   105  		}
   106  		if parameter != nil {
   107  			parameter.DB = db
   108  		}
   109  	}
   110  
   111  	// parameter: *nats.Conn
   112  	natConn, natSubject := nat.Conn, nat.Subject
   113  	if parameter != nil && parameter.NatConn != nil && parameter.NatSubject != "" {
   114  		natConn, natSubject = parameter.NatConn, parameter.NatSubject
   115  	}
   116  	if natConn != nil && natSubject != "" {
   117  		r.NatConn, r.NatSubject = natConn, natSubject
   118  	}
   119  
   120  	// parameter: *redis.Client
   121  	redisClient := store.RedisClient
   122  	if parameter != nil && parameter.RedisClient != nil {
   123  		redisClient = parameter.RedisClient
   124  	}
   125  	if redisClient != nil {
   126  		r.RedisClient = redisClient
   127  	}
   128  
   129  	// parameter: *fastcache.Cache
   130  	var (
   131  		cache    *fastcache.Cache
   132  		cacheDir string
   133  		maxBytes = 1073741824 // 1GB cache capacity
   134  	)
   135  	if parameter != nil && parameter.Cache != nil {
   136  		cache = parameter.Cache
   137  	} else {
   138  		cache = fastcache.New(maxBytes)
   139  	}
   140  	if parameter != nil && parameter.CacheDir != "" {
   141  		cacheDir = parameter.CacheDir
   142  	}
   143  	r.Cache, r.CacheDir = cache, cacheDir
   144  
   145  	r.Register()
   146  	return r
   147  }
   148  
   149  // Register init runtime register if not registered.
   150  func (r *GoRuntime) Register() {
   151  	if r.Runtime == nil || r.registered {
   152  		return
   153  	}
   154  
   155  	r.loadModules()
   156  
   157  	if r.Logger != nil {
   158  		Logger(r.Runtime, r.Logger)
   159  	}
   160  
   161  	if r.DB != nil {
   162  		Db(r.Runtime, r.DB)
   163  	} else if r.DbType != "" && r.DbConn != "" {
   164  		Db(r.Runtime, nil, r.DbType, r.DbConn)
   165  	}
   166  
   167  	if r.NatConn != nil && r.NatSubject != "" {
   168  		Nats(r.Runtime, r.NatConn, r.NatSubject)
   169  	}
   170  
   171  	if r.RedisClient != nil {
   172  		Redis(r.Runtime, r.RedisClient)
   173  	}
   174  
   175  	// create all registers
   176  	Console(r.Runtime)
   177  	ID(r.Runtime)
   178  	RD(r.Runtime)
   179  	Ajax(r.Runtime)
   180  	Cache(r.Runtime, r.Cache, r.CacheDir)
   181  
   182  	// sets registered
   183  	r.registered = true
   184  }
   185  
   186  // loadModules load javascript modules.
   187  func (r *GoRuntime) loadModules() {
   188  	r.Runtime.Set("require", func(c goja.FunctionCall) goja.Value {
   189  		v, p := goja.Undefined(), c.Argument(0).String()
   190  		if p == "" {
   191  			return v
   192  		}
   193  
   194  		p = filepath.Clean(p)
   195  		if pkg, ok := r.Modules[p]; ok {
   196  			return pkg
   197  		}
   198  
   199  		code, err1 := ioutil.ReadFile(p)
   200  		if err1 != nil {
   201  			return v
   202  		}
   203  
   204  		text := "(function(module,exports){\n" + f.String(code) + "\nif(exports)module.exports=exports;})"
   205  		prg, err2 := goja.Compile(p, text, false)
   206  		if err2 != nil {
   207  			return v
   208  		}
   209  
   210  		res, err3 := r.Runtime.RunProgram(prg)
   211  		if err3 != nil {
   212  			return v
   213  		}
   214  
   215  		fun, ok := goja.AssertFunction(res)
   216  		if !ok {
   217  			return v
   218  		}
   219  
   220  		m, e := r.Runtime.NewObject(), r.Runtime.NewObject()
   221  		_ = m.Set("exports", e)
   222  		_, err4 := fun(e, m, v)
   223  		if err4 != nil {
   224  			return v
   225  		}
   226  
   227  		return m.Get("exports")
   228  	})
   229  }
   230  
   231  // Clear runtime interrupt and fields.
   232  func (r *GoRuntime) Clear() {
   233  	r.ClearInterrupt()
   234  	// field: *log.Logger
   235  	if r.Logger != nil {
   236  	}
   237  	// field: *sqlx.DB
   238  	if r.DB != nil {
   239  		//_ = r.DB.Close()
   240  	}
   241  	// field: *nats.Conn
   242  	if r.NatConn != nil {
   243  		//_ = r.NatConn.FlushTimeout(time.Second)
   244  	}
   245  	// field: *redis.Client
   246  	if r.RedisClient != nil {
   247  	}
   248  }