{
    "go-package": {
        "prefix": "package",
        "body": [
            "package ${1}",
            "  ${2}"
        ],
        "description": "declare go package"
    },
    "go-import-m": {
        "prefix": "importmultiple",
        "body": [
            "import (",
            "  \"${1}\"",
            ")"
        ],
        "description": "multiple packages"
    },
    "go-import-s": {
        "prefix": "importsingle",
        "body": [
            "import \"${1}\""
        ],
        "description": "single packages"
    },
    "go-func": {
        "prefix": "func _err",
        "body": [
            "func ${1}() (_err err) {",
            "  ${2}",
            "}"
        ],
        "description": "function"
    },
    "go-struct": {
        "prefix": "type",
        "body": [
            "type ${1} struct {",
            "  ${2}",
            "}"
        ],
        "description": "struct"
    },
    "分隔线": {
        "prefix": [
            "fgx"
        ],
        "body": [
            "fmt.Printf(\"%s\\r\\n\", strings.Repeat(\"${1:=}\", ${2:30}))"
        ],
        "description": "分隔线"
    },
    "_err return": {
        "prefix": [
            "iferr"
        ],
        "body": [
            "if err != nil {",
            "  log.Printf(\"错误:%+v\", err)",
            "${1|  _err = err, |}",
            "${2|  return,  return nil, err|}",
            "}"
        ],
        "description": "打印错误"
    },
    "error printf": {
        "prefix": [
            "if_err"
        ],
        "body": [
            "if _err != nil {",
            "  log.Printf(\"错误:%+v\", _err)",
            "  return",
            "}"
        ],
        "description": "打印错误"
    },
    "匿名函数": {
        "prefix": [
            "deferfunc"
        ],
        "body": [
            "defer func() {",
            "   $1",
            "}()"
        ],
        "description": "匿名函数"
    },
    "主函数main": {
        "scope": "go",
        "prefix": "funcmain",
        "body": [
            "func main()  {",
            "  ${1}",
            "}"
        ],
        "description": "主函数main"
    },
    "[]byte转string": {
        "scope": "go",
        "prefix": [
            "f[]byte2string"
        ],
        "body": [
            "$2 := *(*string)(unsafe.Pointer(&$1))"
        ],
        "description": "[]byte转string"
    },
    "退出": {
        "scope": "go",
        "prefix": [
            "fgood_quit"
        ],
        "body": [
            "sig := make(chan os.Signal)",
            "signal.Notify(sig, syscall.SIGINT /*Ctrl+c、panic()*/, syscall.SIGQUIT /*正常退出*/, syscall.SIGTERM, syscall.SIGHUP /*kill*/)",
            "go func() {",
            "  for s := range sig {",
            "    switch s {",
            "    case syscall.SIGINT, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGHUP:",
            "      //退出时处理",
            "      // quit()",
            "      if i, ok := s.(syscall.Signal); ok {",
            "        fmt.Printf(\"退出 Code: %d\", int(i))",
            "        os.Exit(int(i))",
            "      } else {",
            "        os.Exit(0)",
            "      }",
            "    default:",
            "      runtime.Gosched()",
            "    }",
            "  }",
            "}()"
        ],
        "description": "退出"
    },
    "文件下载带进度条": {
        "scope": "go",
        "prefix": [
            "fdownload"
        ],
        "body": [
            "import (",
            "   \"github.com/schollz/progressbar/v3\"",
            ")",
            "func DownloadFile() {",
            "  golangPkg := \"https://golang.google.cn/dl/go1.16.4.darwin-amd64.pkg\"",
            "  req, _ := http.NewRequest(\"GET\", golangPkg, nil)",
            "  resp, _ := http.DefaultClient.Do(req)",
            "  defer resp.Body.Close()",
            "  f, _ := os.OpenFile(\"go1.16.4.darwin-amd64.pkg\", os.O_CREATE|os.O_WRONLY, 0644)",
            "  defer f.Close()",
            "  bar := progressbar.DefaultBytes(",
            "    resp.ContentLength,",
            "    \"正在下载\",",
            "  )",
            "  io.Copy(io.MultiWriter(f, bar), resp.Body)",
            "}"
        ],
        "description": "文件下载带进度条"
    },
    "打开文件": {
        "scope": "go",
        "prefix": [
            "fopen file"
        ],
        "body": [
            "file_path := \"${1:E:\\data\\test.txt}\"",
            "file, _err = os.Open(file_path)",
            "if _err != nil {",
            "",
            "}",
            "defer func() {",
            "  file.Close()",
            "}()",
            "",
            "file_name := filepath.Base(file_path)",
            "buf := bytes.NewBuffer(nil)",
            "if _, err := io.Copy(buf, file); err != nil {",
            "",
            "}",
            "fmt.Println(buf.Bytes())",
            "paths, fileName := filepath.Split(file_path)",
            "fmt.Println(paths, fileName)      //获取路径中的目录及文件名 E:\\data\\  test.txt",
            "fmt.Println(filepath.Base(files)) //获取路径中的文件名test.txt",
            "fmt.Println(path.Ext(files))      //获取路径中的文件的后缀 .txt"
        ],
        "description": "打开文件"
    },
    "TCP端口复用": {
        "prefix": [
            "ftcp"
        ],
        "body": [
            "func main() {",
            "  cfg := net.ListenConfig{",
            "      Control: func(network, address string, c syscall.RawConn) error {",
            "          return c.Control(func(fd uintptr) {",
            "              syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, unix.SO_REUSEADDR, 1)",
            "              syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, unix.SO_REUSEPORT, 1)",
            "          })",
            "      },",
            "  }",
            "  tcp, err := cfg.Listen(context.Background(), \"tcp\", \"127.0.0.1:1234\")",
            "  if err != nil {",
            "      fmt.Println(\"listen failed\", err)",
            "      return",
            "  }",
            "",
            "  buf := make([]byte, 1024)",
            "  for {",
            "      conn, err := tcp.Accept()",
            "      if err != nil {",
            "          fmt.Println(\"accept failed\", err)",
            "          continue",
            "      }",
            "      for {",
            "          n, err := conn.Read(buf)",
            "          if err != nil {",
            "              fmt.Println(\"read failed\", err)",
            "              break",
            "          }",
            "",
            "          fmt.Println(string(buf[:n]))",
            "      }",
            "  }",
            "}"
        ],
        "description": "TCP端口复用"
    },
    "UDP端口复用": {
        "scope": "go",
        "prefix": [
            "fudp"
        ],
        "body": [
            "func serve(addr string) {",
            "  cfg := net.ListenConfig{",
            "      Control: func(network, address string, c syscall.RawConn) error {",
            "          return c.Control(func(fd uintptr) {",
            "              syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, unix.SO_REUSEADDR, 1)",
            "          })",
            "      },",
            "  }",
            "  udp, err := cfg.ListenPacket(context.Background(), \"udp\", addr)",
            "",
            "  if err != nil {",
            "      fmt.Println(\"listen failed\", err)",
            "      return",
            "  }",
            "",
            "  buf := make([]byte, 1024)",
            "  for {",
            "      n, caddr, err := udp.ReadFrom(buf)",
            "      if err != nil {",
            "          fmt.Println(\"read failed\", err)",
            "          continue",
            "      }",
            "",
            "      fmt.Println(addr, caddr, string(buf[:n]))",
            "  }",
            "}",
            "",
            "func main() {",
            "    go serve(\"127.0.0.1:1234\")",
            "    go serve(\"0.0.0.0:1234\")",
            "    select {}",
            "}"
        ],
        "description": "UDP端口复用"
    },
    "优雅退出": {
        "scope": "go",
        "prefix": [
            "fexit"
        ],
        "body": [
            "import (",
            " \"context\"",
            " \"fmt\"",
            " \"log\"",
            " \"net/http\"",
            " \"os\"",
            " \"os/signal\"",
            " \"syscall\"",
            " \"time\"",
            "",
            " \"github.com/cloudflare/tableflip\"",
            ")",
            "",
            "// 当前程序的版本",
            "const version = \"v0.0.1\"",
            "",
            "func main() {",
            " upg, err := tableflip.New(tableflip.Options{})",
            " if err != nil {",
            "    panic(err)",
            " }",
            " defer upg.Stop()",
            "",
            " // 为了演示方便，为程序启动强行加入 1s 的延时，并在日志中附上进程 pid",
            " time.Sleep(time.Second)",
            " log.SetPrefix(fmt.Sprintf(\"[PID: %d] \", os.Getpid()))",
            "",
            " // 监听系统的 SIGHUP 信号，以此信号触发进程重启",
            " go func() {",
            "    sig := make(chan os.Signal, 1)",
            "    signal.Notify(sig, syscall.SIGHUP)",
            "    for range sig {",
            "      // 核心的 Upgrade 调用",
            "      err := upg.Upgrade()",
            "      if err != nil {",
            "       log.Println(\"Upgrade failed:\", err)",
            "      }",
            "    }",
            " }()",
            "",
            " // 注意必须使用 upg.Listen 对端口进行监听",
            " ln, err := upg.Listen(\"tcp\", \":8080\")",
            " if err != nil {",
            "    log.Fatalln(\"Can't listen:\", err)",
            " }",
            "",
            " // 创建一个简单的 http server, version 返回当前的程序版本",
            " mux := http.NewServeMux()",
            " mux.HandleFunc(\"/version\", func(rw http.ResponseWriter, r *http.Request) {",
            "    log.Println(version)",
            "    rw.Write([]byte(version + \"\n\"))",
            " })",
            " server := http.Server{",
            "    Handler: mux,",
            " }",
            "",
            " // 照常启动 http server",
            " go func() {",
            "    err := server.Serve(ln)",
            "    if err != http.ErrServerClosed {",
            "      log.Println(\"HTTP server:\", err)",
            "    }",
            " }()",
            "",
            " if err := upg.Ready(); err != nil {",
            "    panic(err)",
            " }",
            " <-upg.Exit()",
            "",
            " // 给老进程的退出设置一个 30s 的超时时间，保证老进程的退出",
            " time.AfterFunc(30*time.Second, func() {",
            "    log.Println(\"Graceful shutdown timed out\")",
            "    os.Exit(1)",
            " })",
            "",
            " // 等待 http server 的优雅退出",
            " server.Shutdown(context.Background())",
            "}"
        ],
        "description": "优雅退出"
    },
    "HTTP请求": {
        "scope": "go",
        "prefix": [
            "fhttp"
        ],
        "body": [
            "func Http() {",
            "",
            " url := \"http://192.168.103.251:38090/v1/watcher\"",
            " method := \"POST\"",
            " payload := strings.NewReader(`{\"service_name\": \"LabelCenter\"}`)",
            "",
            " client := &http.Client{}",
            " req, err := http.NewRequest(method, url, payload)",
            "",
            " if err != nil {",
            "   fmt.Println(err)",
            "   return",
            " }",
            " req.Header.Add(\"User-Agent\", \"Apifox/1.0.0 (https://www.apifox.cn)\")",
            " req.Header.Add(\"Content-Type\", \"application/json\")",
            " req.Header.Add(\"Accept\", \"*/*\")",
            " req.Header.Add(\"Host\", \"192.168.103.251:38090\")",
            " req.Header.Add(\"Connection\", \"keep-alive\")",
            "",
            " res, err := client.Do(req)",
            " if err != nil {",
            "   fmt.Println(err)",
            "   return",
            " }",
            " defer res.Body.Close()",
            "",
            " body, err := io.ReadAll(res.Body)",
            " if err != nil {",
            "   fmt.Println(err)",
            "   return",
            " }",
            " fmt.Printf(\"%s\\r\\n\", strings.Repeat(\"**\", 30))",
            " fmt.Println(string(body))",
            " fmt.Printf(\"%s\\r\\n\", strings.Repeat(\"**\", 30))",
            "}"
        ],
        "description": "HTTP请求"
    },
    "log日志文件": {
        "scope": "go",
        "prefix": [
            "flog"
        ],
        "body": [
            "func init() {",
            "  logFile, err := os.OpenFile(\"./log.txt\", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0766)",
            "  if err != nil {",
            "     panic(err)",
            "  }",
            "  log.SetOutput(logFile)",
            "  log.SetPrefix(\"[${1}]\")",
            "  log.SetFlags(log.LstdFlags | log.Lshortfile | log.Ltime)",
            "}"
        ],
        "description": "log日志文件"
    },
    "自定义GORM数据类型": {
        "scope": "go",
        "prefix": [
            "fgorm"
        ],
        "body": [
            "func (t *${1}) Scan(value interface{}) error {",
            "  b, ok := value.([]byte)",
            "  if !ok {",
            "    return errors.New(\"failed to unmarshal ${1} value\")",
            "  }",
            "  var instance ${1}",
            "  err := json.Unmarshal(b, &instance)",
            "  if err != nil {",
            "    return err",
            "  }",
            "  *t = instance",
            "  return nil",
            "}",
            "func (t ${1}) Value() (driver.Value, error) {",
            "  return json.Marshal(t)",
            "}",
            "func (t *${1}) UnmarshalJSON(data []byte) (err error) {",
            "  if len(data) == 2 {",
            "    *t = ${1}{}",
            "    return",
            "  }",
            "  *t = ${1}{}",
            "  return",
            "}",
            "func (t ${1}) MarshalJSON() ([]byte, error) {",
            "  if t.Time.IsZero() {",
            "    return []byte(\"null\"), nil",
            "  }",
            "  formatted := fmt.Sprintf(\"%v\", t)",
            "  return []byte(formatted), nil",
            "}"
        ],
        "description": "自定义GORM数据类型"
    },
    "序列化反序列化": {
        "scope": "go",
        "prefix": [
            "ffxl"
        ],
        "body": [
            "//序列化",
            "func serialize(value interface{}) ([]byte, error) {",
            "  if bytes, ok := value.([]byte); ok {",
            "    return bytes, nil",
            "  }",
            "",
            "  switch v := reflect.ValueOf(value); v.Kind() {",
            "  case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:",
            "    return []byte(strconv.FormatInt(v.Int(), 10)), nil",
            "  case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:",
            "    return []byte(strconv.FormatUint(v.Uint(), 10)), nil",
            "  }",
            "",
            "  var b bytes.Buffer",
            "  encoder := gob.NewEncoder(&b)",
            "  if err := encoder.Encode(value); err != nil {//编码",
            "    return nil, err",
            "  }",
            "  return b.Bytes(), nil",
            "}",
            "",
            "//反序列化",
            "func deserialize(byt []byte, ptr interface{}) (err error) {",
            "  if bytes, ok := ptr.(*[]byte); ok {",
            "    *bytes = byt",
            "  ",
            "    return nil",
            "  }",
            "",
            "  if v := reflect.ValueOf(ptr); v.Kind() == reflect.Ptr { // 通过反射得到ptr类型，判断ptr是指针类型",
            "    switch p := v.Elem(); p.Kind() {",
            "    case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64://符号整型",
            "      var i int64",
            "      i, err = strconv.ParseInt(string(byt), 10, 64)",
            "      if err != nil {",
            "        return err",
            "      } else {",
            "        p.SetInt(i)",
            "      }",
            "      return nil",
            "    ",
            "    case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64://无符号整型",
            "      var i uint64",
            "      i, err = strconv.ParseUint(string(byt), 10, 64)",
            "      if err != nil {",
            "        return err",
            "      } else {",
            "        p.SetUint(i)",
            "      }",
            "      return nil",
            "    }",
            "  }",
            "",
            "  b := bytes.NewBuffer(byt)",
            "  decoder := gob.NewDecoder(b)",
            "  if err = decoder.Decode(ptr); err != nil {//解码",
            "    return err",
            "  }",
            "  return nil",
            "}"
        ],
        "description": "序列化反序列化"
    }
}