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 }