github.com/angenalZZZ/gofunc@v0.0.0-20210507121333-48ff1be3917b/cmd/natsql/flag.go (about) 1 package main 2 3 import ( 4 "context" 5 "flag" 6 "fmt" 7 "os" 8 "path/filepath" 9 10 "github.com/nats-io/nats.go" 11 12 "github.com/dop251/goja" 13 14 "github.com/angenalZZZ/gofunc/data" 15 "github.com/angenalZZZ/gofunc/f" 16 "github.com/angenalZZZ/gofunc/js" 17 "github.com/angenalZZZ/gofunc/log" 18 nat "github.com/angenalZZZ/gofunc/rpc/nats" 19 ) 20 21 var ( 22 //flagMsgLimit = flag.Int("c", 100000000, "the nats-Limits for pending messages for this subscription") 23 //flagBytesLimit = flag.Int("d", 4096, "the nats-Limits for a message's bytes for this subscription") 24 flagConfig = flag.String("c", "natsql.yaml", "sets config file") 25 flagTest = flag.String("t", "", "sets json file and run SQL test") 26 flagAddr = flag.String("a", "", "the NatS-Server address") 27 flagName = flag.String("name", "", "the NatS-Subscription name prefix [required]") 28 flagToken = flag.String("token", "", "the NatS-Token auth string [required]") 29 flagCred = flag.String("cred", "", "the NatS-Cred file") 30 flagCert = flag.String("cert", "", "the NatS-TLS cert file") 31 flagKey = flag.String("key", "", "the NatS-TLS key file") 32 ) 33 34 var ( 35 isTest = false 36 // js test json data file 37 jsonFile string 38 // js runtime and register 39 jsr *js.GoRuntime 40 ) 41 42 // Your Arguments. 43 func initArgs() { 44 flag.Usage = func() { 45 fmt.Printf(" Usage of %s:\n", os.Args[0]) 46 flag.PrintDefaults() 47 } 48 flag.Parse() 49 } 50 51 // Check Arguments And Init Config. 52 func checkArgs() { 53 if *flagConfig != "" { 54 configFile = *flagConfig 55 } 56 57 if err := initConfig(); err != nil { 58 panic(err) 59 } 60 61 if *flagAddr != "" { 62 configInfo.Nats.Addr = *flagAddr 63 } 64 if *flagToken != "" { 65 configInfo.Nats.Token = *flagToken 66 } 67 if *flagCred != "" { 68 configInfo.Nats.Cred = *flagCred 69 } 70 if *flagCert != "" { 71 configInfo.Nats.Cert = *flagCert 72 } 73 if *flagKey != "" { 74 configInfo.Nats.Key = *flagKey 75 } 76 77 if *flagTest != "" { 78 jsonFile = *flagTest 79 } 80 if jsonFile != "" { 81 isTest = true 82 } 83 if isTest { 84 configInfo.Log.Level = "debug" 85 } 86 87 if log.Log == nil { 88 log.Log = log.Init(configInfo.Log) 89 } 90 if nat.Log == nil { 91 nat.Log = log.Log 92 } 93 js.RunLogTimeFormat = configInfo.Log.TimeFormat 94 95 // 全局订阅前缀:subject 96 if *flagName != "" { 97 subject = *flagName 98 } 99 if subject == "" { 100 subject = configInfo.Nats.Subscribe 101 } 102 if subject == "" { 103 panic("the subscription name prefix can't be empty.") 104 } 105 106 if cacheDir == "" { 107 if configInfo.Dir == "" { 108 cacheDir = filepath.Join(data.CurrentDir, subject) 109 } else { 110 cacheDir = filepath.Join(data.CurrentDir, configInfo.Dir) 111 } 112 } 113 if f.PathExists(cacheDir) == false { 114 panic("the cache disk directory is not found.") 115 } 116 117 if configInfo.Nats.Amount < 1 { 118 configInfo.Nats.Amount = -1 119 } 120 if configInfo.Nats.Bulk < 1 { 121 configInfo.Nats.Bulk = 1 122 } 123 if configInfo.Nats.Amount > 0 && configInfo.Nats.Amount < configInfo.Nats.Bulk { 124 configInfo.Nats.Amount = configInfo.Nats.Bulk 125 } 126 if configInfo.Nats.Interval < 1 { 127 configInfo.Nats.Interval = 1 128 } 129 130 nat.Log.Debug().Msgf("configuration complete") 131 } 132 133 // Create a subscriber for Client Connect. 134 func natClientConnect(isGlobal bool, subj string) (conn *nats.Conn) { 135 var err error 136 137 // NatS 138 if isGlobal { 139 nat.Subject = subj 140 nat.Conn, err = nat.New(subj, configInfo.Nats.Addr, configInfo.Nats.Cred, configInfo.Nats.Token, configInfo.Nats.Cert, configInfo.Nats.Key) 141 if err != nil { 142 nat.Log.Error().Msgf("[nats] failed connect to server: %v\n", err) 143 os.Exit(1) 144 } 145 return nat.Conn 146 } 147 148 conn, err = nat.New(subj, configInfo.Nats.Addr, configInfo.Nats.Cred, configInfo.Nats.Token, configInfo.Nats.Cert, configInfo.Nats.Key) 149 if err != nil { 150 nat.Log.Error().Msgf("[nats] failed connect to server: %v\n", err) 151 os.Exit(1) 152 } 153 return 154 } 155 156 // Init Subscribers And Handlers. 157 func createHandlers() { 158 if handlers == nil { 159 handlers = make([]*handler, 0) 160 } 161 162 stopHandlers() // Stop Subscribers And Handlers. 163 164 if jsr == nil { 165 p := js.GoRuntimeParam{ 166 CacheDir: cacheDir, 167 DbType: configInfo.Db.Type, 168 DbConn: configInfo.Db.Conn, 169 } 170 _ = f.Mkdir(p.CacheDir) 171 jsr = js.NewRuntime(&p) 172 } 173 defer jsr.Clear() 174 175 if _, err := jsr.RunString(configInfo.Nats.Script); err != nil { 176 return 177 } 178 self := jsr.Runtime.Get("subscribe") 179 if self == nil { 180 return 181 } 182 objs, ok := self.Export().([]interface{}) 183 if !ok { 184 return 185 } 186 187 dir1, js1 := cacheDir, configInfo.Js 188 if js1 == "" { 189 js1 = "natsql.js" 190 } 191 192 handlers = make([]*handler, 0) 193 194 for _, obj := range objs { 195 objMap, ok := obj.(map[string]interface{}) 196 if !ok { 197 return 198 } 199 200 var itemName, itemSpec, itemSubj, itemDir string 201 if itemName, ok = objMap["name"].(string); !ok || itemName == "" { 202 return 203 } 204 if itemSpec, ok = objMap["spec"].(string); !ok { 205 return 206 } 207 if itemSpec == "+" { 208 itemSubj = subject + itemName 209 } else { 210 itemSubj = itemName 211 } 212 itemFunc, ok := objMap["func"].(func(goja.FunctionCall) goja.Value) 213 if !ok { 214 return 215 } 216 res := itemFunc(goja.FunctionCall{This: jsr.ToValue(obj)}) 217 if res == nil || res.String() == "" { 218 itemDir = filepath.Join(dir1, itemName) 219 } else { 220 itemDir = filepath.Join(dir1, res.String()) 221 } 222 223 conf := f.Clone(configInfo).(*Config) 224 conf.Dir, conf.Js = itemDir, filepath.Join(itemDir, js1) 225 226 h := new(handler) 227 h.jsFile = conf.Js 228 h.isScriptMod() 229 if err := h.doScriptMod(); err != nil { 230 return 231 } 232 233 // js global variable 234 jso := make(map[string]interface{}) 235 jso["config"] = conf 236 h.jso = jso 237 238 // js runtime and register param 239 h.jsp = &js.GoRuntimeParam{ 240 CacheDir: filepath.Join(dir1, itemName), 241 DbType: conf.Db.Type, 242 DbConn: conf.Db.Conn, 243 NatSubject: itemSubj, 244 } 245 246 ctx, wait := f.ContextWithWait(context.TODO()) 247 248 // natS subscriber 249 if !isTest { 250 // Create a subscriber for Client Connect 251 conn := natClientConnect(false, itemSubj) 252 h.jsp.NatConn = conn 253 254 sub := nat.NewSubscriberFastCache(conn, itemSubj, itemDir) 255 sub.Hand = h.Handle 256 257 h.Context, h.sub = ctx, sub 258 } 259 260 p, err := goja.Compile(itemSubj, h.js, false) 261 if err != nil { 262 return 263 } 264 vm := js.NewRuntime(h.jsp) 265 if _, err = vm.Runtime.RunProgram(p); err != nil { 266 return 267 } 268 269 h.jsr, h.jsName = vm, "sql" 270 if val := vm.Runtime.Get(h.jsName); val == nil { 271 h.jsName = "records" 272 } else { 273 if err := vm.Runtime.ExportTo(val, &h.jsFunc); err != nil { 274 h.jsName = "records" 275 } 276 } 277 278 // Run natS subscriber 279 if !isTest { 280 go h.sub.Run(wait) 281 } 282 283 handlers = append(handlers, h) 284 } 285 } 286 287 // Stop Subscribers And Handlers. 288 func stopHandlers() { 289 for _, h := range handlers { 290 if h.sub != nil && h.sub.Running { 291 f.DoneContext(h.Context) 292 h.sub.Stop() 293 h.Stop() 294 } 295 } 296 } 297 298 // Init complete. 299 func runInit() { 300 if isTest { 301 return 302 } 303 304 createHandlers() // Init Subscribers And Handlers. 305 } 306 307 // Run script test. 308 func runTest() { 309 if !isTest { 310 return 311 } 312 313 createHandlers() // Init Subscribers And Handlers. 314 315 for _, h := range handlers { 316 itemDir := h.jso["configDir"].(string) 317 filename := filepath.Join(itemDir, jsonFile) 318 item, err := f.ReadFile(filename) 319 if err != nil { 320 panic(fmt.Errorf("test json file %q not opened: %s", jsonFile, err.Error())) 321 } 322 323 list, err := data.ListData(item) 324 if err != nil { 325 panic(err) 326 } 327 if len(list) == 0 { 328 panic(fmt.Errorf("test json file can't be empty")) 329 } 330 331 nat.Log.Debug().Msgf("test json file: %q %d records\r\n", jsonFile, len(list)) 332 333 if subject == "" { 334 subject = "test" 335 } 336 if err = h.Handle(list); err != nil { 337 panic(err) 338 } 339 } 340 341 nat.Log.Debug().Msg("test finished.") 342 os.Exit(0) 343 }