├── .DS_Store ├── .gitignore ├── .idea ├── .gitignore ├── go-learning.iml ├── modules.xml └── vcs.xml ├── LICENSE ├── README.md ├── blog ├── gh-pages.yml └── hugo.toml ├── concurrence └── main.go ├── def └── main.go ├── di ├── helloworld │ ├── .gitignore │ ├── Dockerfile │ ├── LICENSE │ ├── Makefile │ ├── README.md │ ├── api │ │ └── helloworld │ │ │ └── v1 │ │ │ ├── error_reason.pb.go │ │ │ ├── error_reason.proto │ │ │ ├── greeter.pb.go │ │ │ ├── greeter.proto │ │ │ ├── greeter_grpc.pb.go │ │ │ └── greeter_http.pb.go │ ├── cmd │ │ └── helloworld │ │ │ ├── main.go │ │ │ ├── wire.go │ │ │ └── wire_gen.go │ ├── configs │ │ └── config.yaml │ ├── go.mod │ ├── go.sum │ ├── internal │ │ ├── biz │ │ │ ├── README.md │ │ │ ├── biz.go │ │ │ └── greeter.go │ │ ├── conf │ │ │ ├── conf.pb.go │ │ │ └── conf.proto │ │ ├── data │ │ │ ├── README.md │ │ │ ├── data.go │ │ │ └── greeter.go │ │ ├── server │ │ │ ├── grpc.go │ │ │ ├── http.go │ │ │ └── server.go │ │ └── service │ │ │ ├── README.md │ │ │ ├── greeter.go │ │ │ └── service.go │ ├── openapi.yaml │ └── third_party │ │ ├── README.md │ │ ├── errors │ │ └── errors.proto │ │ ├── google │ │ ├── api │ │ │ ├── annotations.proto │ │ │ ├── client.proto │ │ │ ├── field_behavior.proto │ │ │ ├── http.proto │ │ │ └── httpbody.proto │ │ └── protobuf │ │ │ ├── any.proto │ │ │ ├── api.proto │ │ │ ├── compiler │ │ │ └── plugin.proto │ │ │ ├── descriptor.proto │ │ │ ├── duration.proto │ │ │ ├── empty.proto │ │ │ ├── field_mask.proto │ │ │ ├── source_context.proto │ │ │ ├── struct.proto │ │ │ ├── timestamp.proto │ │ │ ├── type.proto │ │ │ └── wrappers.proto │ │ ├── openapi │ │ └── v3 │ │ │ ├── annotations.proto │ │ │ └── openapi.proto │ │ └── validate │ │ ├── README.md │ │ └── validate.proto ├── no_di │ └── main.go ├── simple_di │ └── main.go └── wire_di │ ├── go.mod │ ├── go.sum │ ├── main.go │ ├── wire.go │ └── wire_gen.go ├── doutok-course ├── .DS_Store ├── basic-knowledge │ ├── blog-demo │ │ └── backend │ │ │ └── blog-service │ │ │ ├── .gitignore │ │ │ ├── Dockerfile │ │ │ ├── LICENSE │ │ │ ├── Makefile │ │ │ ├── README.md │ │ │ ├── api │ │ │ └── blog │ │ │ │ └── v1 │ │ │ │ ├── blog.pb.go │ │ │ │ ├── blog.proto │ │ │ │ ├── blog_grpc.pb.go │ │ │ │ └── blog_http.pb.go │ │ │ ├── cmd │ │ │ └── blog-service │ │ │ │ ├── blogs.csv │ │ │ │ ├── main.go │ │ │ │ ├── wire.go │ │ │ │ └── wire_gen.go │ │ │ ├── configs │ │ │ └── config.yaml │ │ │ ├── go.mod │ │ │ ├── go.sum │ │ │ ├── internal │ │ │ ├── biz │ │ │ │ ├── README.md │ │ │ │ ├── biz.go │ │ │ │ └── blog.go │ │ │ ├── conf │ │ │ │ ├── conf.pb.go │ │ │ │ └── conf.proto │ │ │ ├── data │ │ │ │ ├── README.md │ │ │ │ ├── blog.go │ │ │ │ ├── data.go │ │ │ │ └── model │ │ │ │ │ └── blog.go │ │ │ ├── server │ │ │ │ ├── grpc.go │ │ │ │ ├── http.go │ │ │ │ └── server.go │ │ │ └── service │ │ │ │ ├── README.md │ │ │ │ ├── blog.go │ │ │ │ └── service.go │ │ │ ├── openapi.yaml │ │ │ └── third_party │ │ │ ├── README.md │ │ │ ├── errors │ │ │ └── errors.proto │ │ │ ├── google │ │ │ ├── api │ │ │ │ ├── annotations.proto │ │ │ │ ├── client.proto │ │ │ │ ├── field_behavior.proto │ │ │ │ ├── http.proto │ │ │ │ └── httpbody.proto │ │ │ └── protobuf │ │ │ │ ├── any.proto │ │ │ │ ├── api.proto │ │ │ │ ├── compiler │ │ │ │ └── plugin.proto │ │ │ │ ├── descriptor.proto │ │ │ │ ├── duration.proto │ │ │ │ ├── empty.proto │ │ │ │ ├── field_mask.proto │ │ │ │ ├── source_context.proto │ │ │ │ ├── struct.proto │ │ │ │ ├── timestamp.proto │ │ │ │ ├── type.proto │ │ │ │ └── wrappers.proto │ │ │ ├── openapi │ │ │ └── v3 │ │ │ │ ├── annotations.proto │ │ │ │ └── openapi.proto │ │ │ └── validate │ │ │ ├── README.md │ │ │ └── validate.proto │ ├── docker-intro │ │ ├── Dockerfile │ │ ├── README.md │ │ ├── app.js │ │ ├── docker-compose.yml │ │ ├── package-lock.json │ │ └── package.json │ ├── golang-intro │ │ ├── README.md │ │ ├── hello.go │ │ ├── syntax_examples.go │ │ └── syntax_examples_README.md │ ├── kratos-intro │ │ ├── README.md │ │ ├── main.go │ │ └── myproject │ │ │ ├── .gitignore │ │ │ ├── Dockerfile │ │ │ ├── LICENSE │ │ │ ├── Makefile │ │ │ ├── README.md │ │ │ ├── api │ │ │ └── helloworld │ │ │ │ └── v1 │ │ │ │ ├── error_reason.pb.go │ │ │ │ ├── error_reason.proto │ │ │ │ ├── greeter.pb.go │ │ │ │ ├── greeter.proto │ │ │ │ ├── greeter_grpc.pb.go │ │ │ │ └── greeter_http.pb.go │ │ │ ├── cmd │ │ │ └── myproject │ │ │ │ ├── main.go │ │ │ │ ├── wire.go │ │ │ │ └── wire_gen.go │ │ │ ├── configs │ │ │ └── config.yaml │ │ │ ├── go.mod │ │ │ ├── go.sum │ │ │ ├── internal │ │ │ ├── biz │ │ │ │ ├── README.md │ │ │ │ ├── biz.go │ │ │ │ └── greeter.go │ │ │ ├── conf │ │ │ │ ├── conf.pb.go │ │ │ │ └── conf.proto │ │ │ ├── data │ │ │ │ ├── README.md │ │ │ │ ├── data.go │ │ │ │ └── greeter.go │ │ │ ├── server │ │ │ │ ├── grpc.go │ │ │ │ ├── http.go │ │ │ │ └── server.go │ │ │ └── service │ │ │ │ ├── README.md │ │ │ │ ├── greeter.go │ │ │ │ └── service.go │ │ │ ├── openapi.yaml │ │ │ └── third_party │ │ │ ├── README.md │ │ │ ├── errors │ │ │ └── errors.proto │ │ │ ├── google │ │ │ ├── api │ │ │ │ ├── annotations.proto │ │ │ │ ├── client.proto │ │ │ │ ├── field_behavior.proto │ │ │ │ ├── http.proto │ │ │ │ └── httpbody.proto │ │ │ └── protobuf │ │ │ │ ├── any.proto │ │ │ │ ├── api.proto │ │ │ │ ├── compiler │ │ │ │ └── plugin.proto │ │ │ │ ├── descriptor.proto │ │ │ │ ├── duration.proto │ │ │ │ ├── empty.proto │ │ │ │ ├── field_mask.proto │ │ │ │ ├── source_context.proto │ │ │ │ ├── struct.proto │ │ │ │ ├── timestamp.proto │ │ │ │ ├── type.proto │ │ │ │ └── wrappers.proto │ │ │ ├── openapi │ │ │ └── v3 │ │ │ │ ├── annotations.proto │ │ │ │ └── openapi.proto │ │ │ └── validate │ │ │ ├── README.md │ │ │ └── validate.proto │ ├── nextjs-intro │ │ └── README.md │ └── react-intro │ │ ├── App.css │ │ ├── App.jsx │ │ └── README.md ├── doutok-mono │ └── readme.md ├── go.mod └── go.sum ├── dragon ├── .gitignore ├── README.md ├── basic.go ├── config.go ├── dragon.gif ├── dragon.go ├── go.mod ├── go.sum ├── logger.go ├── main.go ├── npc.go ├── printer.go ├── rank.db └── rank.go ├── eino_assistant ├── .env ├── Dockerfile ├── cmd │ └── knowledgeindexing │ │ ├── eino-docs │ │ ├── _index.md │ │ ├── agent_llm_with_tools.md │ │ ├── big_data.md │ │ └── deeplearning.md │ │ └── main.go ├── data │ ├── memory │ │ └── ce10d8a8-a866-474f-919a-c1ef094c8236.jsonl │ ├── redis │ │ └── dump.rdb │ └── task │ │ └── tasks.jsonl ├── docker-compose.yml ├── eino │ ├── knowledgeindexing │ │ ├── embedding.go │ │ ├── indexer.go │ │ ├── loader.go │ │ ├── orchestration.go │ │ └── transformer.go │ └── rag │ │ ├── cmd │ │ ├── main.go │ │ └── rag_cli │ │ ├── generator.go │ │ ├── orchestration.go │ │ └── retriever.go ├── go.mod ├── go.sum ├── pkg │ ├── env │ │ └── env.go │ └── redis │ │ └── redis.go └── readme.md ├── generics └── main.go ├── kit ├── i18n │ ├── Makefile │ ├── active.en.toml │ ├── active.zh.toml │ ├── go.mod │ ├── go.sum │ ├── main.go │ ├── message.go │ └── translate.zh.toml └── transaction │ └── helloworld │ ├── .gitignore │ ├── Dockerfile │ ├── LICENSE │ ├── Makefile │ ├── README.md │ ├── api │ └── helloworld │ │ └── v1 │ │ ├── error_reason.pb.go │ │ ├── error_reason.proto │ │ ├── greeter.pb.go │ │ ├── greeter.proto │ │ ├── greeter_grpc.pb.go │ │ └── greeter_http.pb.go │ ├── cmd │ └── helloworld │ │ ├── main.go │ │ ├── wire.go │ │ └── wire_gen.go │ ├── configs │ └── config.yaml │ ├── go.mod │ ├── go.sum │ ├── internal │ ├── biz │ │ ├── README.md │ │ ├── biz.go │ │ └── greeter.go │ ├── conf │ │ ├── conf.pb.go │ │ └── conf.proto │ ├── data │ │ ├── README.md │ │ ├── data.go │ │ └── greeter.go │ ├── server │ │ ├── grpc.go │ │ ├── http.go │ │ └── server.go │ └── service │ │ ├── README.md │ │ ├── greeter.go │ │ └── service.go │ ├── openapi.yaml │ ├── pkg │ └── db │ │ └── db.go │ ├── schema │ ├── 20240806134830_init.sql │ └── Makefile │ └── third_party │ ├── README.md │ ├── errors │ └── errors.proto │ ├── google │ ├── api │ │ ├── annotations.proto │ │ ├── client.proto │ │ ├── field_behavior.proto │ │ ├── http.proto │ │ └── httpbody.proto │ └── protobuf │ │ ├── any.proto │ │ ├── api.proto │ │ ├── compiler │ │ └── plugin.proto │ │ ├── descriptor.proto │ │ ├── duration.proto │ │ ├── empty.proto │ │ ├── field_mask.proto │ │ ├── source_context.proto │ │ ├── struct.proto │ │ ├── timestamp.proto │ │ ├── type.proto │ │ └── wrappers.proto │ ├── openapi │ └── v3 │ │ ├── annotations.proto │ │ └── openapi.proto │ └── validate │ ├── README.md │ └── validate.proto ├── storage ├── go.mod ├── go.sum └── mongodb │ ├── Makefile │ ├── config.go │ ├── docker-compose.yaml │ ├── mongodb.go │ └── mongodb_test.go ├── temporal ├── go.mod └── go.sum └── 《Go程序设计语言笔记》.md /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BaiZe1998/go-learning/ff9bb158730be78a5a6f327d9525c9f21876fb7c/.DS_Store -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .vscode/ -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Editor-based HTTP Client requests 5 | /httpRequests/ 6 | # Datasource local storage ignored files 7 | /dataSources/ 8 | /dataSources.local.xml 9 | -------------------------------------------------------------------------------- /.idea/go-learning.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /blog/gh-pages.yml: -------------------------------------------------------------------------------- 1 | name: generate github pages to gh-pages branch 2 | 3 | on: 4 | push: 5 | branches: 6 | - main ## Set a branch name to trigger deployment 7 | 8 | jobs: 9 | deploy: 10 | runs-on: ubuntu-20.04 11 | steps: 12 | - uses: actions/checkout@v2 13 | with: 14 | submodules: true # Fetch Hugo themes (true OR recursive) 15 | fetch-depth: 0 # Fetch all history for .GitInfo and .Lastmod 16 | 17 | - name: Setup Hugo 18 | uses: peaceiris/actions-hugo@v2 19 | with: 20 | hugo-version: 'latest' 21 | extended: true 22 | 23 | - name: Build 24 | run: hugo --minify 25 | 26 | - name: Deploy 27 | uses: peaceiris/actions-gh-pages@v3 28 | # If you're changing the branch from main, 29 | # also change the `main` in `refs/heads/main` 30 | # below accordingly. 31 | if: github.ref == 'refs/heads/main' 32 | with: 33 | github_token: ${{ secrets.GITHUB_TOKEN }} 34 | publish_dir: ./public 35 | -------------------------------------------------------------------------------- /blog/hugo.toml: -------------------------------------------------------------------------------- 1 | baseURL = "https://baize.github.io" # 网站的 URL 2 | languageCode = "zh" # 网站语言代码 3 | title = "白泽" # 网站标题 4 | theme = "hugo-theme-ladder" # 使用的主题名称 5 | defaultContentLanguage = "zh" 6 | 7 | [languages] 8 | [languages.zh] 9 | languageName = "简体中文" 10 | weight = 1 11 | contentDir = "content/" 12 | [languages.en] 13 | languageName = "English" 14 | weight = 2 15 | contentDir = "content/en" 16 | 17 | [params] 18 | brand = "主页" 19 | author = "白泽" 20 | authorDescription = "阅读|思考|产出|进步" 21 | info = "从未停止对未知的探索,尝试分享一些有趣的东西" 22 | avatarURL = "images/baize.png" 23 | darkModeTheme = "data-dark-mode" 24 | favicon = "images/baize.png" 25 | 26 | [params.options] 27 | showDarkMode = true 28 | 29 | [[params.social]] 30 | name = "GitHub" 31 | pre = '' 32 | url = "https://github.com/BaiZe1998" 33 | 34 | [[params.social]] 35 | name = "bilibili" 36 | pre = '' 37 | url = "https://space.bilibili.com/10399934?spm_id_from=333.1007.0.0" 38 | 39 | [params.analytics.umami] 40 | enable = true 41 | website_id = "ec55b2da-4f55-45ef-8aed-26e57078fd15" 42 | url = "https://umami-jlwf.vercel.app/hugo-ladder" 43 | 44 | [[menu.main]] 45 | name = "文章" 46 | url = "/blog/" 47 | weight = 1 48 | 49 | [[menu.main]] 50 | name = "归档" 51 | url = "/archive/" 52 | weight = 2 53 | 54 | [[menu.main]] 55 | name = "联系" 56 | url = "/contact/" 57 | weight = 3 58 | 59 | [[menu.main]] 60 | name = "网站统计" 61 | url = "https://umami-jlwf.vercel.app/share/ZKhEVgh56RlSfAMa/baize1998.github.io" 62 | weight = 4 63 | -------------------------------------------------------------------------------- /concurrence/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "math/rand" 6 | "sync" 7 | "time" 8 | ) 9 | 10 | // GenerateSlice 创建一个包含从 1 到 n 的整数的切片,并随机打乱顺序。 11 | func GenerateSlice(n int) []int { 12 | slice := make([]int, n) 13 | for i := 0; i < n; i++ { 14 | slice[i] = i + 1 15 | } 16 | // 打乱切片 17 | rand.Shuffle(n, func(i, j int) { 18 | slice[i], slice[j] = slice[j], slice[i] 19 | }) 20 | return slice 21 | } 22 | 23 | func main() { 24 | size := []int{128, 512, 1024, 2048, 100000, 1000000, 10000000} 25 | sortVersion := []struct { 26 | name string 27 | sort func([]int) 28 | }{ 29 | {"Mergesort V1", SequentialMergesortV1}, 30 | {"Mergesort V2", SequentialMergesortV2}, 31 | {"Mergesort V3", SequentialMergesortV3}, 32 | } 33 | for _, s := range size { 34 | fmt.Printf("Testing Size: %d\n", s) 35 | o := GenerateSlice(s) 36 | for _, v := range sortVersion { 37 | s := make([]int, len(o)) 38 | copy(s, o) 39 | start := time.Now() 40 | v.sort(s) 41 | elapsed := time.Since(start) 42 | fmt.Printf("%s: %s\n", v.name, elapsed) 43 | } 44 | fmt.Println() 45 | } 46 | } 47 | 48 | func SequentialMergesortV1(s []int) { 49 | if len(s) <= 1 { 50 | return 51 | } 52 | middle := len(s) / 2 53 | SequentialMergesortV1(s[:middle]) 54 | SequentialMergesortV1(s[middle:]) 55 | Merge(s, middle) 56 | } 57 | 58 | func Merge(s []int, middle int) { 59 | left := s[:middle] 60 | right := s[middle:] 61 | 62 | // 初始指针位置 63 | i := 0 // 左子切片的指针 64 | j := 0 // 右子切片的指针 65 | k := 0 // 原切片的指针 66 | 67 | // 合并两个子切片到原切片 68 | tmp := make([]int, len(s)) 69 | for i < len(left) && j < len(right) { 70 | if left[i] < right[j] { 71 | tmp[k] = left[i] 72 | i++ 73 | } else { 74 | tmp[k] = right[j] 75 | j++ 76 | } 77 | k++ 78 | } 79 | for i < len(left) { 80 | tmp[k] = left[i] 81 | i++ 82 | k++ 83 | } 84 | for j < len(right) { 85 | tmp[k] = right[j] 86 | j++ 87 | k++ 88 | } 89 | } 90 | 91 | func SequentialMergesortV2(s []int) { 92 | if len(s) <= 1 { 93 | return 94 | } 95 | middle := len(s) / 2 96 | 97 | var wg sync.WaitGroup 98 | wg.Add(2) 99 | 100 | go func() { 101 | defer wg.Done() 102 | SequentialMergesortV2(s[:middle]) 103 | }() 104 | go func() { 105 | defer wg.Done() 106 | SequentialMergesortV2(s[middle:]) 107 | }() 108 | wg.Wait() 109 | Merge(s, middle) 110 | } 111 | 112 | const mx = 2048 113 | 114 | func SequentialMergesortV3(s []int) { 115 | if len(s) <= 1 { 116 | return 117 | } 118 | if len(s) < mx { 119 | SequentialMergesortV1(s) 120 | } else { 121 | middle := len(s) / 2 122 | 123 | var wg sync.WaitGroup 124 | wg.Add(2) 125 | 126 | go func() { 127 | defer wg.Done() 128 | SequentialMergesortV3(s[:middle]) 129 | }() 130 | go func() { 131 | defer wg.Done() 132 | SequentialMergesortV3(s[middle:]) 133 | }() 134 | 135 | wg.Wait() 136 | Merge(s, middle) 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /def/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | ch := make(chan int) 7 | defer fmt.Println("defer: ", <-ch) 8 | ch <- 42 9 | fmt.Println("main: ", <-ch) 10 | } 11 | -------------------------------------------------------------------------------- /di/helloworld/.gitignore: -------------------------------------------------------------------------------- 1 | # Reference https://github.com/github/gitignore/blob/master/Go.gitignore 2 | # Binaries for programs and plugins 3 | *.exe 4 | *.exe~ 5 | *.dll 6 | *.dylib 7 | 8 | # Test binary, built with `go test -c` 9 | *.test 10 | 11 | # Output of the go coverage tool, specifically when used with LiteIDE 12 | *.out 13 | 14 | # Dependency directories (remove the comment below to include it) 15 | vendor/ 16 | 17 | # Go workspace file 18 | go.work 19 | 20 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 21 | *.o 22 | *.a 23 | *.so 24 | 25 | # OS General 26 | Thumbs.db 27 | .DS_Store 28 | 29 | # project 30 | *.cert 31 | *.key 32 | *.log 33 | bin/ 34 | 35 | # Develop tools 36 | .vscode/ 37 | .idea/ 38 | *.swp 39 | -------------------------------------------------------------------------------- /di/helloworld/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1.19 AS builder 2 | 3 | COPY . /src 4 | WORKDIR /src 5 | 6 | RUN GOPROXY=https://goproxy.cn make build 7 | 8 | FROM debian:stable-slim 9 | 10 | RUN apt-get update && apt-get install -y --no-install-recommends \ 11 | ca-certificates \ 12 | netbase \ 13 | && rm -rf /var/lib/apt/lists/ \ 14 | && apt-get autoremove -y && apt-get autoclean -y 15 | 16 | COPY --from=builder /src/bin /app 17 | 18 | WORKDIR /app 19 | 20 | EXPOSE 8000 21 | EXPOSE 9000 22 | VOLUME /data/conf 23 | 24 | CMD ["./server", "-conf", "/data/conf"] 25 | -------------------------------------------------------------------------------- /di/helloworld/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 go-kratos 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /di/helloworld/Makefile: -------------------------------------------------------------------------------- 1 | GOHOSTOS:=$(shell go env GOHOSTOS) 2 | GOPATH:=$(shell go env GOPATH) 3 | VERSION=$(shell git describe --tags --always) 4 | 5 | ifeq ($(GOHOSTOS), windows) 6 | #the `find.exe` is different from `find` in bash/shell. 7 | #to see https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/find. 8 | #changed to use git-bash.exe to run find cli or other cli friendly, caused of every developer has a Git. 9 | #Git_Bash= $(subst cmd\,bin\bash.exe,$(dir $(shell where git))) 10 | Git_Bash=$(subst \,/,$(subst cmd\,bin\bash.exe,$(dir $(shell where git)))) 11 | INTERNAL_PROTO_FILES=$(shell $(Git_Bash) -c "find internal -name *.proto") 12 | API_PROTO_FILES=$(shell $(Git_Bash) -c "find api -name *.proto") 13 | else 14 | INTERNAL_PROTO_FILES=$(shell find internal -name *.proto) 15 | API_PROTO_FILES=$(shell find api -name *.proto) 16 | endif 17 | 18 | .PHONY: init 19 | # init env 20 | init: 21 | go install google.golang.org/protobuf/cmd/protoc-gen-go@latest 22 | go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest 23 | go install github.com/go-kratos/kratos/cmd/kratos/v2@latest 24 | go install github.com/go-kratos/kratos/cmd/protoc-gen-go-http/v2@latest 25 | go install github.com/google/gnostic/cmd/protoc-gen-openapi@latest 26 | go install github.com/google/wire/cmd/wire@latest 27 | 28 | .PHONY: config 29 | # generate internal proto 30 | config: 31 | protoc --proto_path=./internal \ 32 | --proto_path=./third_party \ 33 | --go_out=paths=source_relative:./internal \ 34 | $(INTERNAL_PROTO_FILES) 35 | 36 | .PHONY: api 37 | # generate api proto 38 | api: 39 | protoc --proto_path=./api \ 40 | --proto_path=./third_party \ 41 | --go_out=paths=source_relative:./api \ 42 | --go-http_out=paths=source_relative:./api \ 43 | --go-grpc_out=paths=source_relative:./api \ 44 | --openapi_out=fq_schema_naming=true,default_response=false:. \ 45 | $(API_PROTO_FILES) 46 | 47 | .PHONY: build 48 | # build 49 | build: 50 | mkdir -p bin/ && go build -ldflags "-X main.Version=$(VERSION)" -o ./bin/ ./... 51 | 52 | .PHONY: generate 53 | # generate 54 | generate: 55 | go mod tidy 56 | go get github.com/google/wire/cmd/wire@latest 57 | go generate ./... 58 | 59 | .PHONY: all 60 | # generate all 61 | all: 62 | make api; 63 | make config; 64 | make generate; 65 | 66 | # show help 67 | help: 68 | @echo '' 69 | @echo 'Usage:' 70 | @echo ' make [target]' 71 | @echo '' 72 | @echo 'Targets:' 73 | @awk '/^[a-zA-Z\-\_0-9]+:/ { \ 74 | helpMessage = match(lastLine, /^# (.*)/); \ 75 | if (helpMessage) { \ 76 | helpCommand = substr($$1, 0, index($$1, ":")); \ 77 | helpMessage = substr(lastLine, RSTART + 2, RLENGTH); \ 78 | printf "\033[36m%-22s\033[0m %s\n", helpCommand,helpMessage; \ 79 | } \ 80 | } \ 81 | { lastLine = $$0 }' $(MAKEFILE_LIST) 82 | 83 | .DEFAULT_GOAL := help 84 | -------------------------------------------------------------------------------- /di/helloworld/README.md: -------------------------------------------------------------------------------- 1 | # Kratos Project Template 2 | 3 | ## Install Kratos 4 | ``` 5 | go install github.com/go-kratos/kratos/cmd/kratos/v2@latest 6 | ``` 7 | ## Create a service 8 | ``` 9 | # Create a template project 10 | kratos new server 11 | 12 | cd server 13 | # Add a proto template 14 | kratos proto add api/server/server.proto 15 | # Generate the proto code 16 | kratos proto client api/server/server.proto 17 | # Generate the source code of service by proto file 18 | kratos proto server api/server/server.proto -t internal/service 19 | 20 | go generate ./... 21 | go build -o ./bin/ ./... 22 | ./bin/server -conf ./configs 23 | ``` 24 | ## Generate other auxiliary files by Makefile 25 | ``` 26 | # Download and update dependencies 27 | make init 28 | # Generate API files (include: pb.go, http, grpc, validate, swagger) by proto file 29 | make api 30 | # Generate all files 31 | make all 32 | ``` 33 | ## Automated Initialization (wire) 34 | ``` 35 | # install wire 36 | go get github.com/google/wire/cmd/wire 37 | 38 | # generate wire 39 | cd cmd/server 40 | wire 41 | ``` 42 | 43 | ## Docker 44 | ```bash 45 | # build 46 | docker build -t . 47 | 48 | # run 49 | docker run --rm -p 8000:8000 -p 9000:9000 -v :/data/conf 50 | ``` 51 | 52 | -------------------------------------------------------------------------------- /di/helloworld/api/helloworld/v1/error_reason.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package helloworld.v1; 4 | 5 | option go_package = "helloworld/api/helloworld/v1;v1"; 6 | option java_multiple_files = true; 7 | option java_package = "helloworld.v1"; 8 | option objc_class_prefix = "APIHelloworldV1"; 9 | 10 | enum ErrorReason { 11 | GREETER_UNSPECIFIED = 0; 12 | USER_NOT_FOUND = 1; 13 | } 14 | -------------------------------------------------------------------------------- /di/helloworld/api/helloworld/v1/greeter.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package helloworld.v1; 4 | 5 | import "google/api/annotations.proto"; 6 | 7 | option go_package = "helloworld/api/helloworld/v1;v1"; 8 | option java_multiple_files = true; 9 | option java_package = "dev.kratos.api.helloworld.v1"; 10 | option java_outer_classname = "HelloworldProtoV1"; 11 | 12 | // The greeting service definition. 13 | service Greeter { 14 | // Sends a greeting 15 | rpc SayHello (HelloRequest) returns (HelloReply) { 16 | option (google.api.http) = { 17 | get: "/helloworld/{name}" 18 | }; 19 | } 20 | } 21 | 22 | // The request message containing the user's name. 23 | message HelloRequest { 24 | string name = 1; 25 | } 26 | 27 | // The response message containing the greetings 28 | message HelloReply { 29 | string message = 1; 30 | } 31 | -------------------------------------------------------------------------------- /di/helloworld/api/helloworld/v1/greeter_http.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go-http. DO NOT EDIT. 2 | // versions: 3 | // protoc-gen-go-http v2.1.3 4 | 5 | package v1 6 | 7 | import ( 8 | context "context" 9 | http "github.com/go-kratos/kratos/v2/transport/http" 10 | binding "github.com/go-kratos/kratos/v2/transport/http/binding" 11 | ) 12 | 13 | // This is a compile-time assertion to ensure that this generated file 14 | // is compatible with the kratos package it is being compiled against. 15 | var _ = new(context.Context) 16 | var _ = binding.EncodeURL 17 | 18 | const _ = http.SupportPackageIsVersion1 19 | 20 | type GreeterHTTPServer interface { 21 | SayHello(context.Context, *HelloRequest) (*HelloReply, error) 22 | } 23 | 24 | func RegisterGreeterHTTPServer(s *http.Server, srv GreeterHTTPServer) { 25 | r := s.Route("/") 26 | r.GET("/helloworld/{name}", _Greeter_SayHello0_HTTP_Handler(srv)) 27 | } 28 | 29 | func _Greeter_SayHello0_HTTP_Handler(srv GreeterHTTPServer) func(ctx http.Context) error { 30 | return func(ctx http.Context) error { 31 | var in HelloRequest 32 | if err := ctx.BindQuery(&in); err != nil { 33 | return err 34 | } 35 | if err := ctx.BindVars(&in); err != nil { 36 | return err 37 | } 38 | http.SetOperation(ctx, "/helloworld.v1.Greeter/SayHello") 39 | h := ctx.Middleware(func(ctx context.Context, req interface{}) (interface{}, error) { 40 | return srv.SayHello(ctx, req.(*HelloRequest)) 41 | }) 42 | out, err := h(ctx, &in) 43 | if err != nil { 44 | return err 45 | } 46 | reply := out.(*HelloReply) 47 | return ctx.Result(200, reply) 48 | } 49 | } 50 | 51 | type GreeterHTTPClient interface { 52 | SayHello(ctx context.Context, req *HelloRequest, opts ...http.CallOption) (rsp *HelloReply, err error) 53 | } 54 | 55 | type GreeterHTTPClientImpl struct { 56 | cc *http.Client 57 | } 58 | 59 | func NewGreeterHTTPClient(client *http.Client) GreeterHTTPClient { 60 | return &GreeterHTTPClientImpl{client} 61 | } 62 | 63 | func (c *GreeterHTTPClientImpl) SayHello(ctx context.Context, in *HelloRequest, opts ...http.CallOption) (*HelloReply, error) { 64 | var out HelloReply 65 | pattern := "/helloworld/{name}" 66 | path := binding.EncodeURL(pattern, in, true) 67 | opts = append(opts, http.Operation("/helloworld.v1.Greeter/SayHello")) 68 | opts = append(opts, http.PathTemplate(pattern)) 69 | err := c.cc.Invoke(ctx, "GET", path, nil, &out, opts...) 70 | if err != nil { 71 | return nil, err 72 | } 73 | return &out, err 74 | } 75 | -------------------------------------------------------------------------------- /di/helloworld/cmd/helloworld/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "os" 6 | 7 | "helloworld/internal/conf" 8 | 9 | "github.com/go-kratos/kratos/v2" 10 | "github.com/go-kratos/kratos/v2/config" 11 | "github.com/go-kratos/kratos/v2/config/file" 12 | "github.com/go-kratos/kratos/v2/log" 13 | "github.com/go-kratos/kratos/v2/middleware/tracing" 14 | "github.com/go-kratos/kratos/v2/transport/grpc" 15 | "github.com/go-kratos/kratos/v2/transport/http" 16 | 17 | _ "go.uber.org/automaxprocs" 18 | ) 19 | 20 | // go build -ldflags "-X main.Version=x.y.z" 21 | var ( 22 | // Name is the name of the compiled software. 23 | Name string 24 | // Version is the version of the compiled software. 25 | Version string 26 | // flagconf is the config flag. 27 | flagconf string 28 | 29 | id, _ = os.Hostname() 30 | ) 31 | 32 | func init() { 33 | flag.StringVar(&flagconf, "conf", "../../configs", "config path, eg: -conf config.yaml") 34 | } 35 | 36 | func newApp(logger log.Logger, gs *grpc.Server, hs *http.Server) *kratos.App { 37 | return kratos.New( 38 | kratos.ID(id), 39 | kratos.Name(Name), 40 | kratos.Version(Version), 41 | kratos.Metadata(map[string]string{}), 42 | kratos.Logger(logger), 43 | kratos.Server( 44 | gs, 45 | hs, 46 | ), 47 | ) 48 | } 49 | 50 | func main() { 51 | flag.Parse() 52 | logger := log.With(log.NewStdLogger(os.Stdout), 53 | "ts", log.DefaultTimestamp, 54 | "caller", log.DefaultCaller, 55 | "service.id", id, 56 | "service.name", Name, 57 | "service.version", Version, 58 | "trace.id", tracing.TraceID(), 59 | "span.id", tracing.SpanID(), 60 | ) 61 | c := config.New( 62 | config.WithSource( 63 | file.NewSource(flagconf), 64 | ), 65 | ) 66 | defer c.Close() 67 | 68 | if err := c.Load(); err != nil { 69 | panic(err) 70 | } 71 | 72 | var bc conf.Bootstrap 73 | if err := c.Scan(&bc); err != nil { 74 | panic(err) 75 | } 76 | 77 | app, cleanup, err := wireApp(bc.Server, bc.Data, logger) 78 | if err != nil { 79 | panic(err) 80 | } 81 | defer cleanup() 82 | 83 | // start and wait for stop signal 84 | if err := app.Run(); err != nil { 85 | panic(err) 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /di/helloworld/cmd/helloworld/wire.go: -------------------------------------------------------------------------------- 1 | //go:build wireinject 2 | // +build wireinject 3 | 4 | // The build tag makes sure the stub is not built in the final build. 5 | 6 | package main 7 | 8 | import ( 9 | "helloworld/internal/biz" 10 | "helloworld/internal/conf" 11 | "helloworld/internal/data" 12 | "helloworld/internal/server" 13 | "helloworld/internal/service" 14 | 15 | "github.com/go-kratos/kratos/v2" 16 | "github.com/go-kratos/kratos/v2/log" 17 | "github.com/google/wire" 18 | ) 19 | 20 | // wireApp init kratos application. 21 | func wireApp(*conf.Server, *conf.Data, log.Logger) (*kratos.App, func(), error) { 22 | panic(wire.Build(server.ProviderSet, data.ProviderSet, biz.ProviderSet, service.ProviderSet, newApp)) 23 | } 24 | -------------------------------------------------------------------------------- /di/helloworld/cmd/helloworld/wire_gen.go: -------------------------------------------------------------------------------- 1 | // Code generated by Wire. DO NOT EDIT. 2 | 3 | //go:generate go run github.com/google/wire/cmd/wire 4 | //go:build !wireinject 5 | // +build !wireinject 6 | 7 | package main 8 | 9 | import ( 10 | "helloworld/internal/biz" 11 | "helloworld/internal/conf" 12 | "helloworld/internal/data" 13 | "helloworld/internal/server" 14 | "helloworld/internal/service" 15 | 16 | "github.com/go-kratos/kratos/v2" 17 | "github.com/go-kratos/kratos/v2/log" 18 | ) 19 | 20 | // Injectors from simple_di.go: 21 | 22 | // wireApp init kratos application. 23 | func wireApp(confServer *conf.Server, confData *conf.Data, logger log.Logger) (*kratos.App, func(), error) { 24 | dataData, cleanup, err := data.NewData(confData, logger) 25 | if err != nil { 26 | return nil, nil, err 27 | } 28 | greeterRepo := data.NewGreeterRepo(dataData, logger) 29 | greeterUsecase := biz.NewGreeterUsecase(greeterRepo, logger) 30 | greeterService := service.NewGreeterService(greeterUsecase) 31 | grpcServer := server.NewGRPCServer(confServer, greeterService, logger) 32 | httpServer := server.NewHTTPServer(confServer, greeterService, logger) 33 | app := newApp(logger, grpcServer, httpServer) 34 | return app, func() { 35 | cleanup() 36 | }, nil 37 | } 38 | -------------------------------------------------------------------------------- /di/helloworld/configs/config.yaml: -------------------------------------------------------------------------------- 1 | server: 2 | http: 3 | addr: 0.0.0.0:8000 4 | timeout: 1s 5 | grpc: 6 | addr: 0.0.0.0:9000 7 | timeout: 1s 8 | data: 9 | database: 10 | driver: mysql 11 | source: root:root@tcp(127.0.0.1:3306)/test?parseTime=True&loc=Local 12 | redis: 13 | addr: 127.0.0.1:6379 14 | read_timeout: 0.2s 15 | write_timeout: 0.2s 16 | -------------------------------------------------------------------------------- /di/helloworld/go.mod: -------------------------------------------------------------------------------- 1 | module helloworld 2 | 3 | go 1.19 4 | 5 | require ( 6 | github.com/go-kratos/kratos/v2 v2.7.2 7 | github.com/google/wire v0.5.0 8 | go.uber.org/automaxprocs v1.5.1 9 | google.golang.org/genproto/googleapis/api v0.0.0-20230629202037-9506855d4529 10 | google.golang.org/grpc v1.56.3 11 | google.golang.org/protobuf v1.32.0 12 | ) 13 | 14 | require ( 15 | github.com/fsnotify/fsnotify v1.6.0 // indirect 16 | github.com/go-kratos/aegis v0.2.0 // indirect 17 | github.com/go-logr/logr v1.2.4 // indirect 18 | github.com/go-logr/stdr v1.2.2 // indirect 19 | github.com/go-playground/form/v4 v4.2.1 // indirect 20 | github.com/golang/protobuf v1.5.3 // indirect 21 | github.com/google/uuid v1.6.0 // indirect 22 | github.com/gorilla/mux v1.8.0 // indirect 23 | github.com/imdario/mergo v0.3.16 // indirect 24 | github.com/kr/text v0.2.0 // indirect 25 | go.opentelemetry.io/otel v1.16.0 // indirect 26 | go.opentelemetry.io/otel/metric v1.16.0 // indirect 27 | go.opentelemetry.io/otel/trace v1.16.0 // indirect 28 | golang.org/x/net v0.17.0 // indirect 29 | golang.org/x/sync v0.6.0 // indirect 30 | golang.org/x/sys v0.13.0 // indirect 31 | golang.org/x/text v0.13.0 // indirect 32 | google.golang.org/genproto v0.0.0-20230629202037-9506855d4529 // indirect 33 | google.golang.org/genproto/googleapis/rpc v0.0.0-20230629202037-9506855d4529 // indirect 34 | gopkg.in/yaml.v3 v3.0.1 // indirect 35 | ) 36 | -------------------------------------------------------------------------------- /di/helloworld/internal/biz/README.md: -------------------------------------------------------------------------------- 1 | # Biz 2 | -------------------------------------------------------------------------------- /di/helloworld/internal/biz/biz.go: -------------------------------------------------------------------------------- 1 | package biz 2 | 3 | import "github.com/google/wire" 4 | 5 | // ProviderSet is biz providers. 6 | var ProviderSet = wire.NewSet(NewGreeterUsecase) 7 | -------------------------------------------------------------------------------- /di/helloworld/internal/biz/greeter.go: -------------------------------------------------------------------------------- 1 | package biz 2 | 3 | import ( 4 | "context" 5 | 6 | v1 "helloworld/api/helloworld/v1" 7 | 8 | "github.com/go-kratos/kratos/v2/errors" 9 | "github.com/go-kratos/kratos/v2/log" 10 | ) 11 | 12 | var ( 13 | // ErrUserNotFound is user not found. 14 | ErrUserNotFound = errors.NotFound(v1.ErrorReason_USER_NOT_FOUND.String(), "user not found") 15 | ) 16 | 17 | // Greeter is a Greeter model. 18 | type Greeter struct { 19 | Hello string 20 | } 21 | 22 | // GreeterRepo is a Greater repo. 23 | type GreeterRepo interface { 24 | Save(context.Context, *Greeter) (*Greeter, error) 25 | Update(context.Context, *Greeter) (*Greeter, error) 26 | FindByID(context.Context, int64) (*Greeter, error) 27 | ListByHello(context.Context, string) ([]*Greeter, error) 28 | ListAll(context.Context) ([]*Greeter, error) 29 | } 30 | 31 | // GreeterUsecase is a Greeter usecase. 32 | type GreeterUsecase struct { 33 | repo GreeterRepo 34 | log *log.Helper 35 | } 36 | 37 | // NewGreeterUsecase new a Greeter usecase. 38 | func NewGreeterUsecase(repo GreeterRepo, logger log.Logger) *GreeterUsecase { 39 | return &GreeterUsecase{repo: repo, log: log.NewHelper(logger)} 40 | } 41 | 42 | // CreateGreeter creates a Greeter, and returns the new Greeter. 43 | func (uc *GreeterUsecase) CreateGreeter(ctx context.Context, g *Greeter) (*Greeter, error) { 44 | uc.log.WithContext(ctx).Infof("CreateGreeter: %v", g.Hello) 45 | return uc.repo.Save(ctx, g) 46 | } 47 | -------------------------------------------------------------------------------- /di/helloworld/internal/conf/conf.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package kratos.api; 3 | 4 | option go_package = "helloworld/internal/conf;conf"; 5 | 6 | import "google/protobuf/duration.proto"; 7 | 8 | message Bootstrap { 9 | Server server = 1; 10 | Data data = 2; 11 | } 12 | 13 | message Server { 14 | message HTTP { 15 | string network = 1; 16 | string addr = 2; 17 | google.protobuf.Duration timeout = 3; 18 | } 19 | message GRPC { 20 | string network = 1; 21 | string addr = 2; 22 | google.protobuf.Duration timeout = 3; 23 | } 24 | HTTP http = 1; 25 | GRPC grpc = 2; 26 | } 27 | 28 | message Data { 29 | message Database { 30 | string driver = 1; 31 | string source = 2; 32 | } 33 | message Redis { 34 | string network = 1; 35 | string addr = 2; 36 | google.protobuf.Duration read_timeout = 3; 37 | google.protobuf.Duration write_timeout = 4; 38 | } 39 | Database database = 1; 40 | Redis redis = 2; 41 | } 42 | -------------------------------------------------------------------------------- /di/helloworld/internal/data/README.md: -------------------------------------------------------------------------------- 1 | # Data 2 | -------------------------------------------------------------------------------- /di/helloworld/internal/data/data.go: -------------------------------------------------------------------------------- 1 | package data 2 | 3 | import ( 4 | "helloworld/internal/conf" 5 | 6 | "github.com/go-kratos/kratos/v2/log" 7 | "github.com/google/wire" 8 | ) 9 | 10 | // ProviderSet is data providers. 11 | var ProviderSet = wire.NewSet(NewData, NewGreeterRepo) 12 | 13 | // Data . 14 | type Data struct { 15 | // TODO wrapped database client 16 | } 17 | 18 | // NewData . 19 | func NewData(c *conf.Data, logger log.Logger) (*Data, func(), error) { 20 | cleanup := func() { 21 | log.NewHelper(logger).Info("closing the data resources") 22 | } 23 | return &Data{}, cleanup, nil 24 | } 25 | -------------------------------------------------------------------------------- /di/helloworld/internal/data/greeter.go: -------------------------------------------------------------------------------- 1 | package data 2 | 3 | import ( 4 | "context" 5 | 6 | "helloworld/internal/biz" 7 | 8 | "github.com/go-kratos/kratos/v2/log" 9 | ) 10 | 11 | type greeterRepo struct { 12 | data *Data 13 | log *log.Helper 14 | } 15 | 16 | // NewGreeterRepo . 17 | func NewGreeterRepo(data *Data, logger log.Logger) biz.GreeterRepo { 18 | return &greeterRepo{ 19 | data: data, 20 | log: log.NewHelper(logger), 21 | } 22 | } 23 | 24 | func (r *greeterRepo) Save(ctx context.Context, g *biz.Greeter) (*biz.Greeter, error) { 25 | return g, nil 26 | } 27 | 28 | func (r *greeterRepo) Update(ctx context.Context, g *biz.Greeter) (*biz.Greeter, error) { 29 | return g, nil 30 | } 31 | 32 | func (r *greeterRepo) FindByID(context.Context, int64) (*biz.Greeter, error) { 33 | return nil, nil 34 | } 35 | 36 | func (r *greeterRepo) ListByHello(context.Context, string) ([]*biz.Greeter, error) { 37 | return nil, nil 38 | } 39 | 40 | func (r *greeterRepo) ListAll(context.Context) ([]*biz.Greeter, error) { 41 | return nil, nil 42 | } 43 | -------------------------------------------------------------------------------- /di/helloworld/internal/server/grpc.go: -------------------------------------------------------------------------------- 1 | package server 2 | 3 | import ( 4 | v1 "helloworld/api/helloworld/v1" 5 | "helloworld/internal/conf" 6 | "helloworld/internal/service" 7 | 8 | "github.com/go-kratos/kratos/v2/log" 9 | "github.com/go-kratos/kratos/v2/middleware/recovery" 10 | "github.com/go-kratos/kratos/v2/transport/grpc" 11 | ) 12 | 13 | // NewGRPCServer new a gRPC server. 14 | func NewGRPCServer(c *conf.Server, greeter *service.GreeterService, logger log.Logger) *grpc.Server { 15 | var opts = []grpc.ServerOption{ 16 | grpc.Middleware( 17 | recovery.Recovery(), 18 | ), 19 | } 20 | if c.Grpc.Network != "" { 21 | opts = append(opts, grpc.Network(c.Grpc.Network)) 22 | } 23 | if c.Grpc.Addr != "" { 24 | opts = append(opts, grpc.Address(c.Grpc.Addr)) 25 | } 26 | if c.Grpc.Timeout != nil { 27 | opts = append(opts, grpc.Timeout(c.Grpc.Timeout.AsDuration())) 28 | } 29 | srv := grpc.NewServer(opts...) 30 | v1.RegisterGreeterServer(srv, greeter) 31 | return srv 32 | } 33 | -------------------------------------------------------------------------------- /di/helloworld/internal/server/http.go: -------------------------------------------------------------------------------- 1 | package server 2 | 3 | import ( 4 | v1 "helloworld/api/helloworld/v1" 5 | "helloworld/internal/conf" 6 | "helloworld/internal/service" 7 | 8 | "github.com/go-kratos/kratos/v2/log" 9 | "github.com/go-kratos/kratos/v2/middleware/recovery" 10 | "github.com/go-kratos/kratos/v2/transport/http" 11 | ) 12 | 13 | // NewHTTPServer new an HTTP server. 14 | func NewHTTPServer(c *conf.Server, greeter *service.GreeterService, logger log.Logger) *http.Server { 15 | var opts = []http.ServerOption{ 16 | http.Middleware( 17 | recovery.Recovery(), 18 | ), 19 | } 20 | if c.Http.Network != "" { 21 | opts = append(opts, http.Network(c.Http.Network)) 22 | } 23 | if c.Http.Addr != "" { 24 | opts = append(opts, http.Address(c.Http.Addr)) 25 | } 26 | if c.Http.Timeout != nil { 27 | opts = append(opts, http.Timeout(c.Http.Timeout.AsDuration())) 28 | } 29 | srv := http.NewServer(opts...) 30 | v1.RegisterGreeterHTTPServer(srv, greeter) 31 | return srv 32 | } 33 | -------------------------------------------------------------------------------- /di/helloworld/internal/server/server.go: -------------------------------------------------------------------------------- 1 | package server 2 | 3 | import ( 4 | "github.com/google/wire" 5 | ) 6 | 7 | // ProviderSet is server providers. 8 | var ProviderSet = wire.NewSet(NewGRPCServer, NewHTTPServer) 9 | -------------------------------------------------------------------------------- /di/helloworld/internal/service/README.md: -------------------------------------------------------------------------------- 1 | # Service 2 | -------------------------------------------------------------------------------- /di/helloworld/internal/service/greeter.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "context" 5 | 6 | v1 "helloworld/api/helloworld/v1" 7 | "helloworld/internal/biz" 8 | ) 9 | 10 | // GreeterService is a greeter service. 11 | type GreeterService struct { 12 | v1.UnimplementedGreeterServer 13 | 14 | uc *biz.GreeterUsecase 15 | } 16 | 17 | // NewGreeterService new a greeter service. 18 | func NewGreeterService(uc *biz.GreeterUsecase) *GreeterService { 19 | return &GreeterService{uc: uc} 20 | } 21 | 22 | // SayHello implements helloworld.GreeterServer. 23 | func (s *GreeterService) SayHello(ctx context.Context, in *v1.HelloRequest) (*v1.HelloReply, error) { 24 | g, err := s.uc.CreateGreeter(ctx, &biz.Greeter{Hello: in.Name}) 25 | if err != nil { 26 | return nil, err 27 | } 28 | return &v1.HelloReply{Message: "Hello " + g.Hello}, nil 29 | } 30 | -------------------------------------------------------------------------------- /di/helloworld/internal/service/service.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import "github.com/google/wire" 4 | 5 | // ProviderSet is service providers. 6 | var ProviderSet = wire.NewSet(NewGreeterService) 7 | -------------------------------------------------------------------------------- /di/helloworld/openapi.yaml: -------------------------------------------------------------------------------- 1 | # Generated with protoc-gen-openapi 2 | # https://github.com/google/gnostic/tree/master/cmd/protoc-gen-openapi 3 | 4 | openapi: 3.0.3 5 | info: 6 | title: Greeter API 7 | description: The greeting service definition. 8 | version: 0.0.1 9 | paths: 10 | /helloworld/{name}: 11 | get: 12 | tags: 13 | - Greeter 14 | - subgroup 15 | description: Sends a greeting 16 | operationId: Greeter_SayHello 17 | parameters: 18 | - name: name 19 | in: path 20 | required: true 21 | schema: 22 | type: string 23 | responses: 24 | "200": 25 | description: OK 26 | content: 27 | application/json: 28 | schema: 29 | $ref: '#/components/schemas/helloworld.v1.HelloReply' 30 | components: 31 | schemas: 32 | helloworld.v1.HelloReply: 33 | type: object 34 | properties: 35 | message: 36 | type: string 37 | description: The response message containing the greetings 38 | tags: 39 | - name: Greeter 40 | -------------------------------------------------------------------------------- /di/helloworld/third_party/README.md: -------------------------------------------------------------------------------- 1 | # third_party 2 | -------------------------------------------------------------------------------- /di/helloworld/third_party/errors/errors.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package errors; 4 | 5 | option go_package = "github.com/go-kratos/kratos/v2/errors;errors"; 6 | option java_multiple_files = true; 7 | option java_package = "com.github.kratos.errors"; 8 | option objc_class_prefix = "KratosErrors"; 9 | 10 | import "google/protobuf/descriptor.proto"; 11 | 12 | extend google.protobuf.EnumOptions { 13 | int32 default_code = 1108; 14 | } 15 | 16 | extend google.protobuf.EnumValueOptions { 17 | int32 code = 1109; 18 | } -------------------------------------------------------------------------------- /di/helloworld/third_party/google/api/annotations.proto: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, Google Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | syntax = "proto3"; 16 | 17 | package google.api; 18 | 19 | import "google/api/http.proto"; 20 | import "google/protobuf/descriptor.proto"; 21 | 22 | option go_package = "google.golang.org/genproto/googleapis/api/annotations;annotations"; 23 | option java_multiple_files = true; 24 | option java_outer_classname = "AnnotationsProto"; 25 | option java_package = "com.google.api"; 26 | option objc_class_prefix = "GAPI"; 27 | 28 | extend google.protobuf.MethodOptions { 29 | // See `HttpRule`. 30 | HttpRule http = 72295728; 31 | } 32 | -------------------------------------------------------------------------------- /di/helloworld/third_party/google/protobuf/empty.proto: -------------------------------------------------------------------------------- 1 | // Protocol Buffers - Google's data interchange format 2 | // Copyright 2008 Google Inc. All rights reserved. 3 | // https://developers.google.com/protocol-buffers/ 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions are 7 | // met: 8 | // 9 | // * Redistributions of source code must retain the above copyright 10 | // notice, this list of conditions and the following disclaimer. 11 | // * Redistributions in binary form must reproduce the above 12 | // copyright notice, this list of conditions and the following disclaimer 13 | // in the documentation and/or other materials provided with the 14 | // distribution. 15 | // * Neither the name of Google Inc. nor the names of its 16 | // contributors may be used to endorse or promote products derived from 17 | // this software without specific prior written permission. 18 | // 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | syntax = "proto3"; 32 | 33 | package google.protobuf; 34 | 35 | option csharp_namespace = "Google.Protobuf.WellKnownTypes"; 36 | option go_package = "google.golang.org/protobuf/types/known/emptypb"; 37 | option java_package = "com.google.protobuf"; 38 | option java_outer_classname = "EmptyProto"; 39 | option java_multiple_files = true; 40 | option objc_class_prefix = "GPB"; 41 | option cc_enable_arenas = true; 42 | 43 | // A generic empty message that you can re-use to avoid defining duplicated 44 | // empty messages in your APIs. A typical example is to use it as the request 45 | // or the response type of an API method. For instance: 46 | // 47 | // service Foo { 48 | // rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty); 49 | // } 50 | // 51 | // The JSON representation for `Empty` is empty JSON object `{}`. 52 | message Empty {} 53 | -------------------------------------------------------------------------------- /di/helloworld/third_party/google/protobuf/source_context.proto: -------------------------------------------------------------------------------- 1 | // Protocol Buffers - Google's data interchange format 2 | // Copyright 2008 Google Inc. All rights reserved. 3 | // https://developers.google.com/protocol-buffers/ 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions are 7 | // met: 8 | // 9 | // * Redistributions of source code must retain the above copyright 10 | // notice, this list of conditions and the following disclaimer. 11 | // * Redistributions in binary form must reproduce the above 12 | // copyright notice, this list of conditions and the following disclaimer 13 | // in the documentation and/or other materials provided with the 14 | // distribution. 15 | // * Neither the name of Google Inc. nor the names of its 16 | // contributors may be used to endorse or promote products derived from 17 | // this software without specific prior written permission. 18 | // 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | syntax = "proto3"; 32 | 33 | package google.protobuf; 34 | 35 | option csharp_namespace = "Google.Protobuf.WellKnownTypes"; 36 | option java_package = "com.google.protobuf"; 37 | option java_outer_classname = "SourceContextProto"; 38 | option java_multiple_files = true; 39 | option objc_class_prefix = "GPB"; 40 | option go_package = "google.golang.org/protobuf/types/known/sourcecontextpb"; 41 | 42 | // `SourceContext` represents information about the source of a 43 | // protobuf element, like the file in which it is defined. 44 | message SourceContext { 45 | // The path-qualified name of the .proto file that contained the associated 46 | // protobuf element. For example: `"google/protobuf/source_context.proto"`. 47 | string file_name = 1; 48 | } 49 | -------------------------------------------------------------------------------- /di/helloworld/third_party/openapi/v3/annotations.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Google LLC. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | syntax = "proto3"; 16 | 17 | package openapi.v3; 18 | 19 | import "openapi/v3/openapi.proto"; 20 | import "google/protobuf/descriptor.proto"; 21 | 22 | // This option lets the proto compiler generate Java code inside the package 23 | // name (see below) instead of inside an outer class. It creates a simpler 24 | // developer experience by reducing one-level of name nesting and be 25 | // consistent with most programming languages that don't support outer classes. 26 | option java_multiple_files = true; 27 | 28 | // The Java outer classname should be the filename in UpperCamelCase. This 29 | // class is only used to hold proto descriptor, so developers don't need to 30 | // work with it directly. 31 | option java_outer_classname = "AnnotationsProto"; 32 | 33 | // The Java package name must be proto package name with proper prefix. 34 | option java_package = "org.openapi_v3"; 35 | 36 | // A reasonable prefix for the Objective-C symbols generated from the package. 37 | // It should at a minimum be 3 characters long, all uppercase, and convention 38 | // is to use an abbreviation of the package name. Something short, but 39 | // hopefully unique enough to not conflict with things that may come along in 40 | // the future. 'GPB' is reserved for the protocol buffer implementation itself. 41 | option objc_class_prefix = "OAS"; 42 | 43 | // The Go package name. 44 | option go_package = "github.com/google/gnostic/openapiv3;openapi_v3"; 45 | 46 | extend google.protobuf.FileOptions { 47 | Document document = 1143; 48 | } 49 | 50 | extend google.protobuf.MethodOptions { 51 | Operation operation = 1143; 52 | } 53 | 54 | extend google.protobuf.MessageOptions { 55 | Schema schema = 1143; 56 | } 57 | 58 | extend google.protobuf.FieldOptions { 59 | Schema property = 1143; 60 | } -------------------------------------------------------------------------------- /di/helloworld/third_party/validate/README.md: -------------------------------------------------------------------------------- 1 | # protoc-gen-validate (PGV) 2 | 3 | * https://github.com/envoyproxy/protoc-gen-validate 4 | -------------------------------------------------------------------------------- /di/no_di/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | var ( 4 | mysqlUrl = "mysql://blabla" 5 | // 全局数据库实例 6 | db = NewMySQLClient(mysqlUrl) 7 | ) 8 | 9 | func NewMySQLClient(url string) *MySQLClient { 10 | return &MySQLClient{url: url} 11 | } 12 | 13 | type MySQLClient struct { 14 | url string 15 | } 16 | 17 | func (c *MySQLClient) Exec(query string, args ...interface{}) string { 18 | return "data" 19 | } 20 | 21 | func NewApp() *App { 22 | return &App{} 23 | } 24 | 25 | type App struct { 26 | } 27 | 28 | func (a *App) GetData(query string, args ...interface{}) string { 29 | data := db.Exec(query, args...) 30 | return data 31 | } 32 | 33 | // 不使用依赖注入 34 | func main() { 35 | app := NewApp() 36 | rest := app.GetData("select * from table where id = ?", "1") 37 | println(rest) 38 | } 39 | -------------------------------------------------------------------------------- /di/simple_di/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func NewMySQLClient(url string) *MySQLClient { 4 | return &MySQLClient{url: url} 5 | } 6 | 7 | type MySQLClient struct { 8 | url string 9 | } 10 | 11 | func (c *MySQLClient) Exec(query string, args ...interface{}) string { 12 | return "data" 13 | } 14 | 15 | func NewApp(client *MySQLClient) *App { 16 | return &App{client: client} 17 | } 18 | 19 | type App struct { 20 | // App 持有唯一的 MySQLClient 实例 21 | client *MySQLClient 22 | } 23 | 24 | func (a *App) GetData(query string, args ...interface{}) string { 25 | data := a.client.Exec(query, args...) 26 | return data 27 | } 28 | 29 | // 手动依赖注入 30 | func main() { 31 | client := NewMySQLClient("mysql://blabla") 32 | app := NewApp(client) 33 | rest := app.GetData("select * from table where id = ?", "1") 34 | println(rest) 35 | } 36 | -------------------------------------------------------------------------------- /di/wire_di/go.mod: -------------------------------------------------------------------------------- 1 | module demo 2 | 3 | go 1.22.2 4 | 5 | require ( 6 | github.com/google/subcommands v1.2.0 // indirect 7 | github.com/google/wire v0.6.0 // indirect 8 | github.com/pmezard/go-difflib v1.0.0 // indirect 9 | golang.org/x/mod v0.14.0 // indirect 10 | golang.org/x/tools v0.17.0 // indirect 11 | ) 12 | -------------------------------------------------------------------------------- /di/wire_di/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func NewMySQLClient(url string) *MySQLClient { 4 | return &MySQLClient{url: url} 5 | } 6 | 7 | type MySQLClient struct { 8 | url string 9 | } 10 | 11 | func (c *MySQLClient) Exec(query string, args ...interface{}) string { 12 | return "data" 13 | } 14 | 15 | func NewApp(client *MySQLClient) *App { 16 | return &App{client: client} 17 | } 18 | 19 | type App struct { 20 | // App 持有唯一的 MySQLClient 实例 21 | client *MySQLClient 22 | } 23 | 24 | func (a *App) GetData(query string, args ...interface{}) string { 25 | data := a.client.Exec(query, args...) 26 | return data 27 | } 28 | 29 | func main() { 30 | app := wireApp("mysql://blabla") 31 | rest := app.GetData("select * from table where id = ?", "1") 32 | println(rest) 33 | } 34 | -------------------------------------------------------------------------------- /di/wire_di/wire.go: -------------------------------------------------------------------------------- 1 | //go:build wireinject 2 | // +build wireinject 3 | 4 | // The build tag makes sure the stub is not built in the final build. 5 | 6 | package main 7 | 8 | import "github.com/google/wire" 9 | 10 | // wireApp init application. 11 | func wireApp(url string) *App { 12 | wire.Build(NewMySQLClient, NewApp) 13 | return nil 14 | } 15 | -------------------------------------------------------------------------------- /di/wire_di/wire_gen.go: -------------------------------------------------------------------------------- 1 | // Code generated by Wire. DO NOT EDIT. 2 | 3 | //go:generate go run -mod=mod github.com/google/wire/cmd/wire 4 | //go:build !wireinject 5 | // +build !wireinject 6 | 7 | package main 8 | 9 | // Injectors from wire.go: 10 | 11 | // wireApp init application. 12 | func wireApp(url string) *App { 13 | mySQLClient := NewMySQLClient(url) 14 | app := NewApp(mySQLClient) 15 | return app 16 | } 17 | -------------------------------------------------------------------------------- /doutok-course/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BaiZe1998/go-learning/ff9bb158730be78a5a6f327d9525c9f21876fb7c/doutok-course/.DS_Store -------------------------------------------------------------------------------- /doutok-course/basic-knowledge/blog-demo/backend/blog-service/.gitignore: -------------------------------------------------------------------------------- 1 | # Reference https://github.com/github/gitignore/blob/master/Go.gitignore 2 | # Binaries for programs and plugins 3 | *.exe 4 | *.exe~ 5 | *.dll 6 | *.dylib 7 | 8 | # Test binary, built with `go test -c` 9 | *.test 10 | 11 | # Output of the go coverage tool, specifically when used with LiteIDE 12 | *.out 13 | 14 | # Dependency directories (remove the comment below to include it) 15 | vendor/ 16 | 17 | # Go workspace file 18 | go.work 19 | 20 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 21 | *.o 22 | *.a 23 | *.so 24 | 25 | # OS General 26 | Thumbs.db 27 | .DS_Store 28 | 29 | # project 30 | *.cert 31 | *.key 32 | *.log 33 | bin/ 34 | 35 | # Develop tools 36 | .vscode/ 37 | .idea/ 38 | *.swp 39 | -------------------------------------------------------------------------------- /doutok-course/basic-knowledge/blog-demo/backend/blog-service/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1.19 AS builder 2 | 3 | COPY . /src 4 | WORKDIR /src 5 | 6 | RUN GOPROXY=https://goproxy.cn make build 7 | 8 | FROM debian:stable-slim 9 | 10 | RUN apt-get update && apt-get install -y --no-install-recommends \ 11 | ca-certificates \ 12 | netbase \ 13 | && rm -rf /var/lib/apt/lists/ \ 14 | && apt-get autoremove -y && apt-get autoclean -y 15 | 16 | COPY --from=builder /src/bin /app 17 | 18 | WORKDIR /app 19 | 20 | EXPOSE 8000 21 | EXPOSE 9000 22 | VOLUME /data/conf 23 | 24 | CMD ["./server", "-conf", "/data/conf"] 25 | -------------------------------------------------------------------------------- /doutok-course/basic-knowledge/blog-demo/backend/blog-service/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 go-kratos 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /doutok-course/basic-knowledge/blog-demo/backend/blog-service/Makefile: -------------------------------------------------------------------------------- 1 | GOHOSTOS:=$(shell go env GOHOSTOS) 2 | GOPATH:=$(shell go env GOPATH) 3 | VERSION=$(shell git describe --tags --always) 4 | 5 | ifeq ($(GOHOSTOS), windows) 6 | #the `find.exe` is different from `find` in bash/shell. 7 | #to see https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/find. 8 | #changed to use git-bash.exe to run find cli or other cli friendly, caused of every developer has a Git. 9 | #Git_Bash= $(subst cmd\,bin\bash.exe,$(dir $(shell where git))) 10 | Git_Bash=$(subst \,/,$(subst cmd\,bin\bash.exe,$(dir $(shell where git)))) 11 | INTERNAL_PROTO_FILES=$(shell $(Git_Bash) -c "find internal -name *.proto") 12 | API_PROTO_FILES=$(shell $(Git_Bash) -c "find api -name *.proto") 13 | else 14 | INTERNAL_PROTO_FILES=$(shell find internal -name *.proto) 15 | API_PROTO_FILES=$(shell find api -name *.proto) 16 | endif 17 | 18 | .PHONY: init 19 | # init env 20 | init: 21 | go install google.golang.org/protobuf/cmd/protoc-gen-go@latest 22 | go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest 23 | go install github.com/go-kratos/kratos/cmd/kratos/v2@latest 24 | go install github.com/go-kratos/kratos/cmd/protoc-gen-go-http/v2@latest 25 | go install github.com/google/gnostic/cmd/protoc-gen-openapi@latest 26 | go install github.com/google/wire/cmd/wire@latest 27 | 28 | .PHONY: config 29 | # generate internal proto 30 | config: 31 | protoc --proto_path=./internal \ 32 | --proto_path=./third_party \ 33 | --go_out=paths=source_relative:./internal \ 34 | $(INTERNAL_PROTO_FILES) 35 | 36 | .PHONY: api 37 | # generate api proto 38 | api: 39 | protoc --proto_path=./api \ 40 | --proto_path=./third_party \ 41 | --go_out=paths=source_relative:./api \ 42 | --go-http_out=paths=source_relative:./api \ 43 | --go-grpc_out=paths=source_relative:./api \ 44 | --openapi_out=fq_schema_naming=true,default_response=false:. \ 45 | $(API_PROTO_FILES) 46 | 47 | .PHONY: build 48 | # build 49 | build: 50 | mkdir -p bin/ && go build -ldflags "-X main.Version=$(VERSION)" -o ./bin/ ./... 51 | 52 | .PHONY: generate 53 | # generate 54 | generate: 55 | go generate ./... 56 | go mod tidy 57 | 58 | .PHONY: all 59 | # generate all 60 | all: 61 | make api; 62 | make config; 63 | make generate; 64 | 65 | # show help 66 | help: 67 | @echo '' 68 | @echo 'Usage:' 69 | @echo ' make [target]' 70 | @echo '' 71 | @echo 'Targets:' 72 | @awk '/^[a-zA-Z\-\_0-9]+:/ { \ 73 | helpMessage = match(lastLine, /^# (.*)/); \ 74 | if (helpMessage) { \ 75 | helpCommand = substr($$1, 0, index($$1, ":")); \ 76 | helpMessage = substr(lastLine, RSTART + 2, RLENGTH); \ 77 | printf "\033[36m%-22s\033[0m %s\n", helpCommand,helpMessage; \ 78 | } \ 79 | } \ 80 | { lastLine = $$0 }' $(MAKEFILE_LIST) 81 | 82 | .DEFAULT_GOAL := help 83 | -------------------------------------------------------------------------------- /doutok-course/basic-knowledge/blog-demo/backend/blog-service/README.md: -------------------------------------------------------------------------------- 1 | # Kratos Project Template 2 | 3 | ## Install Kratos 4 | ``` 5 | go install github.com/go-kratos/kratos/cmd/kratos/v2@latest 6 | ``` 7 | ## Create a service 8 | ``` 9 | # Create a template project 10 | kratos new server 11 | 12 | cd server 13 | # Add a proto template 14 | kratos proto add api/server/server.proto 15 | # Generate the proto code 16 | kratos proto client api/server/server.proto 17 | # Generate the source code of service by proto file 18 | kratos proto server api/server/server.proto -t internal/service 19 | 20 | go generate ./... 21 | go build -o ./bin/ ./... 22 | ./bin/server -conf ./configs 23 | ``` 24 | ## Generate other auxiliary files by Makefile 25 | ``` 26 | # Download and update dependencies 27 | make init 28 | # Generate API files (include: pb.go, http, grpc, validate, swagger) by proto file 29 | make api 30 | # Generate all files 31 | make all 32 | ``` 33 | ## Automated Initialization (wire) 34 | ``` 35 | # install wire 36 | go get github.com/google/wire/cmd/wire 37 | 38 | # generate wire 39 | cd cmd/server 40 | wire 41 | ``` 42 | 43 | ## Docker 44 | ```bash 45 | # build 46 | docker build -t . 47 | 48 | # run 49 | docker run --rm -p 8000:8000 -p 9000:9000 -v :/data/conf 50 | ``` 51 | 52 | -------------------------------------------------------------------------------- /doutok-course/basic-knowledge/blog-demo/backend/blog-service/api/blog/v1/blog.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package api.blog.v1; 4 | 5 | import "google/api/annotations.proto"; 6 | import "google/protobuf/timestamp.proto"; 7 | 8 | option go_package = "blog-service/api/blog/v1;v1"; 9 | option java_multiple_files = true; 10 | option java_package = "api.blog.v1"; 11 | 12 | service Blog { 13 | rpc ListBlogs (ListBlogsRequest) returns (ListBlogsReply) { 14 | option (google.api.http) = { 15 | get: "/v1/blogs" 16 | }; 17 | } 18 | rpc GetBlog (GetBlogRequest) returns (GetBlogReply) { 19 | option (google.api.http) = { 20 | get: "/v1/blogs/{id}" 21 | }; 22 | } 23 | rpc CreateBlog (CreateBlogRequest) returns (CreateBlogReply) { 24 | option (google.api.http) = { 25 | post: "/v1/blogs" 26 | body: "blog" 27 | }; 28 | } 29 | rpc UpdateBlog (UpdateBlogRequest) returns (UpdateBlogReply) { 30 | option (google.api.http) = { 31 | put: "/v1/blogs/{id}" 32 | body: "blog" 33 | }; 34 | } 35 | rpc DeleteBlog (DeleteBlogRequest) returns (DeleteBlogReply) { 36 | option (google.api.http) = { 37 | delete: "/v1/blogs/{id}" 38 | }; 39 | } 40 | } 41 | 42 | message BlogInfo { 43 | string id = 1; 44 | string title = 2; 45 | string content = 3; 46 | google.protobuf.Timestamp updated_at = 4; 47 | } 48 | 49 | message ListBlogsRequest {} 50 | 51 | message ListBlogsReply { 52 | repeated BlogInfo blogs = 1; 53 | } 54 | 55 | message GetBlogRequest { 56 | string id = 1; 57 | } 58 | 59 | message GetBlogReply { 60 | BlogInfo blog = 1; 61 | } 62 | 63 | message CreateBlogRequest { 64 | BlogInfo blog = 1; 65 | } 66 | 67 | message CreateBlogReply { 68 | BlogInfo blog = 1; 69 | } 70 | 71 | message UpdateBlogRequest { 72 | string id = 1; 73 | BlogInfo blog = 2; 74 | } 75 | 76 | message UpdateBlogReply { 77 | BlogInfo blog = 1; 78 | } 79 | 80 | message DeleteBlogRequest { 81 | string id = 1; 82 | } 83 | 84 | message DeleteBlogReply {} -------------------------------------------------------------------------------- /doutok-course/basic-knowledge/blog-demo/backend/blog-service/cmd/blog-service/blogs.csv: -------------------------------------------------------------------------------- 1 | id,title,content,updated_at 2 | 1745585384549783000,golang 入门,test,2025-04-25T20:49:44+08:00 3 | 1745585406657214000,白泽说,golang / ai 编程社区,2025-04-25T20:50:06+08:00 4 | 1745652170756714000,一个测试标题,测试 编辑,2025-04-26T15:23:00+08:00 5 | -------------------------------------------------------------------------------- /doutok-course/basic-knowledge/blog-demo/backend/blog-service/cmd/blog-service/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "os" 6 | 7 | "blog-service/internal/conf" 8 | 9 | "github.com/go-kratos/kratos/v2" 10 | "github.com/go-kratos/kratos/v2/config" 11 | "github.com/go-kratos/kratos/v2/config/file" 12 | "github.com/go-kratos/kratos/v2/log" 13 | "github.com/go-kratos/kratos/v2/middleware/tracing" 14 | "github.com/go-kratos/kratos/v2/transport/grpc" 15 | "github.com/go-kratos/kratos/v2/transport/http" 16 | 17 | _ "go.uber.org/automaxprocs" 18 | ) 19 | 20 | // go build -ldflags "-X main.Version=x.y.z" 21 | var ( 22 | // Name is the name of the compiled software. 23 | Name string 24 | // Version is the version of the compiled software. 25 | Version string 26 | // flagconf is the config flag. 27 | flagconf string 28 | 29 | id, _ = os.Hostname() 30 | ) 31 | 32 | func init() { 33 | flag.StringVar(&flagconf, "conf", "../../configs", "config path, eg: -conf config.yaml") 34 | } 35 | 36 | func newApp(logger log.Logger, gs *grpc.Server, hs *http.Server) *kratos.App { 37 | return kratos.New( 38 | kratos.ID(id), 39 | kratos.Name(Name), 40 | kratos.Version(Version), 41 | kratos.Metadata(map[string]string{}), 42 | kratos.Logger(logger), 43 | kratos.Server( 44 | gs, 45 | hs, 46 | ), 47 | ) 48 | } 49 | 50 | func main() { 51 | flag.Parse() 52 | logger := log.With(log.NewStdLogger(os.Stdout), 53 | "ts", log.DefaultTimestamp, 54 | "caller", log.DefaultCaller, 55 | "service.id", id, 56 | "service.name", Name, 57 | "service.version", Version, 58 | "trace.id", tracing.TraceID(), 59 | "span.id", tracing.SpanID(), 60 | ) 61 | c := config.New( 62 | config.WithSource( 63 | file.NewSource(flagconf), 64 | ), 65 | ) 66 | defer c.Close() 67 | 68 | if err := c.Load(); err != nil { 69 | panic(err) 70 | } 71 | 72 | var bc conf.Bootstrap 73 | if err := c.Scan(&bc); err != nil { 74 | panic(err) 75 | } 76 | 77 | app, cleanup, err := wireApp(bc.Server, bc.Data, logger) 78 | if err != nil { 79 | panic(err) 80 | } 81 | defer cleanup() 82 | 83 | // start and wait for stop signal 84 | if err := app.Run(); err != nil { 85 | panic(err) 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /doutok-course/basic-knowledge/blog-demo/backend/blog-service/cmd/blog-service/wire.go: -------------------------------------------------------------------------------- 1 | //go:build wireinject 2 | // +build wireinject 3 | 4 | // The build tag makes sure the stub is not built in the final build. 5 | 6 | package main 7 | 8 | import ( 9 | "blog-service/internal/biz" 10 | "blog-service/internal/conf" 11 | "blog-service/internal/data" 12 | "blog-service/internal/server" 13 | "blog-service/internal/service" 14 | 15 | "github.com/go-kratos/kratos/v2" 16 | "github.com/go-kratos/kratos/v2/log" 17 | "github.com/google/wire" 18 | ) 19 | 20 | // wireApp init kratos application. 21 | func wireApp(*conf.Server, *conf.Data, log.Logger) (*kratos.App, func(), error) { 22 | panic(wire.Build(server.ProviderSet, data.ProviderSet, biz.ProviderSet, service.ProviderSet, newApp)) 23 | } 24 | -------------------------------------------------------------------------------- /doutok-course/basic-knowledge/blog-demo/backend/blog-service/cmd/blog-service/wire_gen.go: -------------------------------------------------------------------------------- 1 | // Code generated by Wire. DO NOT EDIT. 2 | 3 | //go:generate go run -mod=mod github.com/google/wire/cmd/wire 4 | //go:build !wireinject 5 | // +build !wireinject 6 | 7 | package main 8 | 9 | import ( 10 | "blog-service/internal/biz" 11 | "blog-service/internal/conf" 12 | "blog-service/internal/data" 13 | "blog-service/internal/server" 14 | "blog-service/internal/service" 15 | "github.com/go-kratos/kratos/v2" 16 | "github.com/go-kratos/kratos/v2/log" 17 | ) 18 | 19 | import ( 20 | _ "go.uber.org/automaxprocs" 21 | ) 22 | 23 | // Injectors from wire.go: 24 | 25 | // wireApp init kratos application. 26 | func wireApp(confServer *conf.Server, confData *conf.Data, logger log.Logger) (*kratos.App, func(), error) { 27 | dataData, cleanup, err := data.NewData(confData, logger) 28 | if err != nil { 29 | return nil, nil, err 30 | } 31 | blogRepo := data.NewBlogRepo(dataData, logger) 32 | blogUsecase := biz.NewBlogUsecase(blogRepo, logger) 33 | blogService := service.NewBlogService(blogUsecase, logger) 34 | grpcServer := server.NewGRPCServer(confServer, blogService, logger) 35 | httpServer := server.NewHTTPServer(confServer, blogService, logger) 36 | app := newApp(logger, grpcServer, httpServer) 37 | return app, func() { 38 | cleanup() 39 | }, nil 40 | } 41 | -------------------------------------------------------------------------------- /doutok-course/basic-knowledge/blog-demo/backend/blog-service/configs/config.yaml: -------------------------------------------------------------------------------- 1 | server: 2 | http: 3 | addr: 0.0.0.0:8000 4 | timeout: 1s 5 | grpc: 6 | addr: 0.0.0.0:9000 7 | timeout: 1s 8 | data: 9 | database: 10 | driver: mysql 11 | source: root:root@tcp(127.0.0.1:3306)/test?parseTime=True&loc=Local 12 | redis: 13 | addr: 127.0.0.1:6379 14 | read_timeout: 0.2s 15 | write_timeout: 0.2s 16 | -------------------------------------------------------------------------------- /doutok-course/basic-knowledge/blog-demo/backend/blog-service/go.mod: -------------------------------------------------------------------------------- 1 | module blog-service 2 | 3 | go 1.21 4 | 5 | toolchain go1.22.6 6 | 7 | require ( 8 | github.com/go-kratos/kratos/v2 v2.8.0 9 | github.com/google/wire v0.6.0 10 | go.uber.org/automaxprocs v1.5.1 11 | google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157 12 | google.golang.org/grpc v1.65.0 13 | google.golang.org/protobuf v1.34.1 14 | ) 15 | 16 | require ( 17 | dario.cat/mergo v1.0.0 // indirect 18 | github.com/fsnotify/fsnotify v1.6.0 // indirect 19 | github.com/go-kratos/aegis v0.2.0 // indirect 20 | github.com/go-logr/logr v1.4.1 // indirect 21 | github.com/go-logr/stdr v1.2.2 // indirect 22 | github.com/go-playground/form/v4 v4.2.1 // indirect 23 | github.com/google/uuid v1.6.0 // indirect 24 | github.com/gorilla/mux v1.8.1 // indirect 25 | github.com/kr/text v0.2.0 // indirect 26 | go.opentelemetry.io/otel v1.24.0 // indirect 27 | go.opentelemetry.io/otel/metric v1.24.0 // indirect 28 | go.opentelemetry.io/otel/trace v1.24.0 // indirect 29 | golang.org/x/net v0.25.0 // indirect 30 | golang.org/x/sync v0.7.0 // indirect 31 | golang.org/x/sys v0.20.0 // indirect 32 | golang.org/x/text v0.15.0 // indirect 33 | google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157 // indirect 34 | gopkg.in/yaml.v3 v3.0.1 // indirect 35 | ) 36 | -------------------------------------------------------------------------------- /doutok-course/basic-knowledge/blog-demo/backend/blog-service/internal/biz/README.md: -------------------------------------------------------------------------------- 1 | # Biz 2 | -------------------------------------------------------------------------------- /doutok-course/basic-knowledge/blog-demo/backend/blog-service/internal/biz/biz.go: -------------------------------------------------------------------------------- 1 | package biz 2 | 3 | import ( 4 | "github.com/google/wire" 5 | ) 6 | 7 | // ProviderSet is biz providers. 8 | var ProviderSet = wire.NewSet(NewBlogUsecase) 9 | -------------------------------------------------------------------------------- /doutok-course/basic-knowledge/blog-demo/backend/blog-service/internal/biz/blog.go: -------------------------------------------------------------------------------- 1 | package biz 2 | 3 | import ( 4 | "context" 5 | "time" 6 | 7 | "github.com/go-kratos/kratos/v2/log" 8 | ) 9 | 10 | // Blog 博客业务对象 11 | type Blog struct { 12 | ID string `json:"id"` 13 | Title string `json:"title"` 14 | Content string `json:"content"` 15 | UpdatedAt time.Time `json:"updated_at"` 16 | } 17 | 18 | // BlogRepo 博客存储接口 19 | type BlogRepo interface { 20 | List(ctx context.Context) ([]*Blog, error) 21 | Get(ctx context.Context, id string) (*Blog, error) 22 | Create(ctx context.Context, blog *Blog) (*Blog, error) 23 | Update(ctx context.Context, id string, blog *Blog) (*Blog, error) 24 | Delete(ctx context.Context, id string) error 25 | } 26 | 27 | // BlogUsecase 博客用例 28 | type BlogUsecase struct { 29 | repo BlogRepo 30 | log *log.Helper 31 | } 32 | 33 | // NewBlogUsecase 创建博客用例 34 | func NewBlogUsecase(repo BlogRepo, logger log.Logger) *BlogUsecase { 35 | return &BlogUsecase{repo: repo, log: log.NewHelper(logger)} 36 | } 37 | 38 | // List 获取所有博客 39 | func (uc *BlogUsecase) List(ctx context.Context) ([]*Blog, error) { 40 | return uc.repo.List(ctx) 41 | } 42 | 43 | // Get 获取单个博客 44 | func (uc *BlogUsecase) Get(ctx context.Context, id string) (*Blog, error) { 45 | return uc.repo.Get(ctx, id) 46 | } 47 | 48 | // Create 创建博客 49 | func (uc *BlogUsecase) Create(ctx context.Context, blog *Blog) (*Blog, error) { 50 | return uc.repo.Create(ctx, blog) 51 | } 52 | 53 | // Update 更新博客 54 | func (uc *BlogUsecase) Update(ctx context.Context, id string, blog *Blog) (*Blog, error) { 55 | return uc.repo.Update(ctx, id, blog) 56 | } 57 | 58 | // Delete 删除博客 59 | func (uc *BlogUsecase) Delete(ctx context.Context, id string) error { 60 | return uc.repo.Delete(ctx, id) 61 | } 62 | -------------------------------------------------------------------------------- /doutok-course/basic-knowledge/blog-demo/backend/blog-service/internal/conf/conf.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package kratos.api; 3 | 4 | option go_package = "blog-service/internal/conf;conf"; 5 | 6 | import "google/protobuf/duration.proto"; 7 | 8 | message Bootstrap { 9 | Server server = 1; 10 | Data data = 2; 11 | } 12 | 13 | message Server { 14 | message HTTP { 15 | string network = 1; 16 | string addr = 2; 17 | google.protobuf.Duration timeout = 3; 18 | } 19 | message GRPC { 20 | string network = 1; 21 | string addr = 2; 22 | google.protobuf.Duration timeout = 3; 23 | } 24 | HTTP http = 1; 25 | GRPC grpc = 2; 26 | } 27 | 28 | message Data { 29 | message Database { 30 | string driver = 1; 31 | string source = 2; 32 | } 33 | message Redis { 34 | string network = 1; 35 | string addr = 2; 36 | google.protobuf.Duration read_timeout = 3; 37 | google.protobuf.Duration write_timeout = 4; 38 | } 39 | Database database = 1; 40 | Redis redis = 2; 41 | } 42 | -------------------------------------------------------------------------------- /doutok-course/basic-knowledge/blog-demo/backend/blog-service/internal/data/README.md: -------------------------------------------------------------------------------- 1 | # Data 2 | -------------------------------------------------------------------------------- /doutok-course/basic-knowledge/blog-demo/backend/blog-service/internal/data/blog.go: -------------------------------------------------------------------------------- 1 | package data 2 | 3 | import ( 4 | "context" 5 | "strconv" 6 | "time" 7 | 8 | "blog-service/internal/biz" 9 | "blog-service/internal/data/model" 10 | 11 | "github.com/go-kratos/kratos/v2/log" 12 | ) 13 | 14 | type blogRepo struct { 15 | data *Data 16 | log *log.Helper 17 | } 18 | 19 | // NewBlogRepo . 20 | func NewBlogRepo(data *Data, logger log.Logger) biz.BlogRepo { 21 | return &blogRepo{ 22 | data: data, 23 | log: log.NewHelper(logger), 24 | } 25 | } 26 | 27 | func (r *blogRepo) List(ctx context.Context) ([]*biz.Blog, error) { 28 | blogs, err := r.data.blogStore.List() 29 | if err != nil { 30 | return nil, err 31 | } 32 | 33 | result := make([]*biz.Blog, 0, len(blogs)) 34 | for _, b := range blogs { 35 | result = append(result, &biz.Blog{ 36 | ID: b.ID, 37 | Title: b.Title, 38 | Content: b.Content, 39 | UpdatedAt: b.UpdatedAt, 40 | }) 41 | } 42 | return result, nil 43 | } 44 | 45 | func (r *blogRepo) Get(ctx context.Context, id string) (*biz.Blog, error) { 46 | blog, err := r.data.blogStore.Get(id) 47 | if err != nil { 48 | return nil, err 49 | } 50 | return &biz.Blog{ 51 | ID: blog.ID, 52 | Title: blog.Title, 53 | Content: blog.Content, 54 | UpdatedAt: blog.UpdatedAt, 55 | }, nil 56 | } 57 | 58 | func (r *blogRepo) Create(ctx context.Context, blog *biz.Blog) (*biz.Blog, error) { 59 | blogModel := &model.Blog{ 60 | ID: strconv.FormatInt(time.Now().UnixNano(), 10), 61 | Title: blog.Title, 62 | Content: blog.Content, 63 | UpdatedAt: time.Now(), 64 | } 65 | 66 | r.log.Infof("blogRepo Create blogModel %v\n", blogModel) 67 | if err := r.data.blogStore.Save(blogModel); err != nil { 68 | return nil, err 69 | } 70 | 71 | return &biz.Blog{ 72 | ID: blogModel.ID, 73 | Title: blogModel.Title, 74 | Content: blogModel.Content, 75 | UpdatedAt: blogModel.UpdatedAt, 76 | }, nil 77 | } 78 | 79 | func (r *blogRepo) Update(ctx context.Context, id string, blog *biz.Blog) (*biz.Blog, error) { 80 | // 首先检查博客是否存在 81 | _, err := r.data.blogStore.Get(id) 82 | if err != nil { 83 | return nil, err 84 | } 85 | 86 | blogModel := &model.Blog{ 87 | ID: id, 88 | Title: blog.Title, 89 | Content: blog.Content, 90 | UpdatedAt: time.Now(), 91 | } 92 | 93 | if err := r.data.blogStore.Save(blogModel); err != nil { 94 | return nil, err 95 | } 96 | 97 | return &biz.Blog{ 98 | ID: blogModel.ID, 99 | Title: blogModel.Title, 100 | Content: blogModel.Content, 101 | UpdatedAt: blogModel.UpdatedAt, 102 | }, nil 103 | } 104 | 105 | func (r *blogRepo) Delete(ctx context.Context, id string) error { 106 | return r.data.blogStore.Delete(id) 107 | } 108 | -------------------------------------------------------------------------------- /doutok-course/basic-knowledge/blog-demo/backend/blog-service/internal/data/data.go: -------------------------------------------------------------------------------- 1 | package data 2 | 3 | import ( 4 | "blog-service/internal/conf" 5 | "blog-service/internal/data/model" 6 | 7 | "github.com/go-kratos/kratos/v2/log" 8 | "github.com/google/wire" 9 | ) 10 | 11 | // ProviderSet is data providers. 12 | var ProviderSet = wire.NewSet(NewData, NewBlogRepo) 13 | 14 | // Data . 15 | type Data struct { 16 | blogStore model.BlogStore 17 | } 18 | 19 | // NewData . 20 | func NewData(c *conf.Data, logger log.Logger) (*Data, func(), error) { 21 | blogStore, err := model.NewCSVBlogStore("blogs.csv") 22 | if err != nil { 23 | return nil, nil, err 24 | } 25 | 26 | cleanup := func() { 27 | log.NewHelper(logger).Info("closing the data resources") 28 | } 29 | 30 | return &Data{ 31 | blogStore: blogStore, 32 | }, cleanup, nil 33 | } 34 | -------------------------------------------------------------------------------- /doutok-course/basic-knowledge/blog-demo/backend/blog-service/internal/server/grpc.go: -------------------------------------------------------------------------------- 1 | package server 2 | 3 | import ( 4 | v1 "blog-service/api/blog/v1" 5 | "blog-service/internal/conf" 6 | "blog-service/internal/service" 7 | 8 | "github.com/go-kratos/kratos/v2/log" 9 | "github.com/go-kratos/kratos/v2/middleware/recovery" 10 | "github.com/go-kratos/kratos/v2/transport/grpc" 11 | ) 12 | 13 | // NewGRPCServer new a gRPC server. 14 | func NewGRPCServer(c *conf.Server, blog *service.BlogService, logger log.Logger) *grpc.Server { 15 | var opts = []grpc.ServerOption{ 16 | grpc.Middleware( 17 | recovery.Recovery(), 18 | ), 19 | } 20 | if c.Grpc.Network != "" { 21 | opts = append(opts, grpc.Network(c.Grpc.Network)) 22 | } 23 | if c.Grpc.Addr != "" { 24 | opts = append(opts, grpc.Address(c.Grpc.Addr)) 25 | } 26 | if c.Grpc.Timeout != nil { 27 | opts = append(opts, grpc.Timeout(c.Grpc.Timeout.AsDuration())) 28 | } 29 | srv := grpc.NewServer(opts...) 30 | v1.RegisterBlogServer(srv, blog) 31 | return srv 32 | } 33 | -------------------------------------------------------------------------------- /doutok-course/basic-knowledge/blog-demo/backend/blog-service/internal/server/http.go: -------------------------------------------------------------------------------- 1 | package server 2 | 3 | import ( 4 | v1 "blog-service/api/blog/v1" 5 | "blog-service/internal/conf" 6 | "blog-service/internal/service" 7 | 8 | nethttp "net/http" 9 | 10 | "github.com/go-kratos/kratos/v2/log" 11 | "github.com/go-kratos/kratos/v2/middleware/recovery" 12 | "github.com/go-kratos/kratos/v2/transport/http" 13 | ) 14 | 15 | // NewHTTPServer new an HTTP server. 16 | func NewHTTPServer(c *conf.Server, blog *service.BlogService, logger log.Logger) *http.Server { 17 | var opts = []http.ServerOption{ 18 | http.Middleware( 19 | recovery.Recovery(), 20 | ), 21 | // 添加CORS支持 22 | http.Filter( 23 | func(handler nethttp.Handler) nethttp.Handler { 24 | return nethttp.HandlerFunc(func(w nethttp.ResponseWriter, r *nethttp.Request) { 25 | w.Header().Set("Access-Control-Allow-Origin", "*") 26 | w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS") 27 | w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization") 28 | 29 | if r.Method == "OPTIONS" { 30 | w.WriteHeader(200) 31 | return 32 | } 33 | 34 | handler.ServeHTTP(w, r) 35 | }) 36 | }, 37 | ), 38 | } 39 | if c.Http.Network != "" { 40 | opts = append(opts, http.Network(c.Http.Network)) 41 | } 42 | if c.Http.Addr != "" { 43 | opts = append(opts, http.Address(c.Http.Addr)) 44 | } 45 | if c.Http.Timeout != nil { 46 | opts = append(opts, http.Timeout(c.Http.Timeout.AsDuration())) 47 | } 48 | srv := http.NewServer(opts...) 49 | v1.RegisterBlogHTTPServer(srv, blog) 50 | return srv 51 | } 52 | -------------------------------------------------------------------------------- /doutok-course/basic-knowledge/blog-demo/backend/blog-service/internal/server/server.go: -------------------------------------------------------------------------------- 1 | package server 2 | 3 | import ( 4 | "github.com/google/wire" 5 | ) 6 | 7 | // ProviderSet is server providers. 8 | var ProviderSet = wire.NewSet(NewGRPCServer, NewHTTPServer) 9 | -------------------------------------------------------------------------------- /doutok-course/basic-knowledge/blog-demo/backend/blog-service/internal/service/README.md: -------------------------------------------------------------------------------- 1 | # Service 2 | -------------------------------------------------------------------------------- /doutok-course/basic-knowledge/blog-demo/backend/blog-service/internal/service/service.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "github.com/google/wire" 5 | ) 6 | 7 | // ProviderSet is service providers. 8 | var ProviderSet = wire.NewSet(NewBlogService) 9 | -------------------------------------------------------------------------------- /doutok-course/basic-knowledge/blog-demo/backend/blog-service/third_party/README.md: -------------------------------------------------------------------------------- 1 | # third_party 2 | -------------------------------------------------------------------------------- /doutok-course/basic-knowledge/blog-demo/backend/blog-service/third_party/errors/errors.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package errors; 4 | 5 | option go_package = "github.com/go-kratos/kratos/v2/errors;errors"; 6 | option java_multiple_files = true; 7 | option java_package = "com.github.kratos.errors"; 8 | option objc_class_prefix = "KratosErrors"; 9 | 10 | import "google/protobuf/descriptor.proto"; 11 | 12 | extend google.protobuf.EnumOptions { 13 | int32 default_code = 1108; 14 | } 15 | 16 | extend google.protobuf.EnumValueOptions { 17 | int32 code = 1109; 18 | } -------------------------------------------------------------------------------- /doutok-course/basic-knowledge/blog-demo/backend/blog-service/third_party/google/api/annotations.proto: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, Google Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | syntax = "proto3"; 16 | 17 | package google.api; 18 | 19 | import "google/api/http.proto"; 20 | import "google/protobuf/descriptor.proto"; 21 | 22 | option go_package = "google.golang.org/genproto/googleapis/api/annotations;annotations"; 23 | option java_multiple_files = true; 24 | option java_outer_classname = "AnnotationsProto"; 25 | option java_package = "com.google.api"; 26 | option objc_class_prefix = "GAPI"; 27 | 28 | extend google.protobuf.MethodOptions { 29 | // See `HttpRule`. 30 | HttpRule http = 72295728; 31 | } 32 | -------------------------------------------------------------------------------- /doutok-course/basic-knowledge/blog-demo/backend/blog-service/third_party/google/protobuf/empty.proto: -------------------------------------------------------------------------------- 1 | // Protocol Buffers - Google's data interchange format 2 | // Copyright 2008 Google Inc. All rights reserved. 3 | // https://developers.google.com/protocol-buffers/ 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions are 7 | // met: 8 | // 9 | // * Redistributions of source code must retain the above copyright 10 | // notice, this list of conditions and the following disclaimer. 11 | // * Redistributions in binary form must reproduce the above 12 | // copyright notice, this list of conditions and the following disclaimer 13 | // in the documentation and/or other materials provided with the 14 | // distribution. 15 | // * Neither the name of Google Inc. nor the names of its 16 | // contributors may be used to endorse or promote products derived from 17 | // this software without specific prior written permission. 18 | // 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | syntax = "proto3"; 32 | 33 | package google.protobuf; 34 | 35 | option csharp_namespace = "Google.Protobuf.WellKnownTypes"; 36 | option go_package = "google.golang.org/protobuf/types/known/emptypb"; 37 | option java_package = "com.google.protobuf"; 38 | option java_outer_classname = "EmptyProto"; 39 | option java_multiple_files = true; 40 | option objc_class_prefix = "GPB"; 41 | option cc_enable_arenas = true; 42 | 43 | // A generic empty message that you can re-use to avoid defining duplicated 44 | // empty messages in your APIs. A typical example is to use it as the request 45 | // or the response type of an API method. For instance: 46 | // 47 | // service Foo { 48 | // rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty); 49 | // } 50 | // 51 | // The JSON representation for `Empty` is empty JSON object `{}`. 52 | message Empty {} 53 | -------------------------------------------------------------------------------- /doutok-course/basic-knowledge/blog-demo/backend/blog-service/third_party/google/protobuf/source_context.proto: -------------------------------------------------------------------------------- 1 | // Protocol Buffers - Google's data interchange format 2 | // Copyright 2008 Google Inc. All rights reserved. 3 | // https://developers.google.com/protocol-buffers/ 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions are 7 | // met: 8 | // 9 | // * Redistributions of source code must retain the above copyright 10 | // notice, this list of conditions and the following disclaimer. 11 | // * Redistributions in binary form must reproduce the above 12 | // copyright notice, this list of conditions and the following disclaimer 13 | // in the documentation and/or other materials provided with the 14 | // distribution. 15 | // * Neither the name of Google Inc. nor the names of its 16 | // contributors may be used to endorse or promote products derived from 17 | // this software without specific prior written permission. 18 | // 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | syntax = "proto3"; 32 | 33 | package google.protobuf; 34 | 35 | option csharp_namespace = "Google.Protobuf.WellKnownTypes"; 36 | option java_package = "com.google.protobuf"; 37 | option java_outer_classname = "SourceContextProto"; 38 | option java_multiple_files = true; 39 | option objc_class_prefix = "GPB"; 40 | option go_package = "google.golang.org/protobuf/types/known/sourcecontextpb"; 41 | 42 | // `SourceContext` represents information about the source of a 43 | // protobuf element, like the file in which it is defined. 44 | message SourceContext { 45 | // The path-qualified name of the .proto file that contained the associated 46 | // protobuf element. For example: `"google/protobuf/source_context.proto"`. 47 | string file_name = 1; 48 | } 49 | -------------------------------------------------------------------------------- /doutok-course/basic-knowledge/blog-demo/backend/blog-service/third_party/openapi/v3/annotations.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Google LLC. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | syntax = "proto3"; 16 | 17 | package openapi.v3; 18 | 19 | import "openapi/v3/openapi.proto"; 20 | import "google/protobuf/descriptor.proto"; 21 | 22 | // This option lets the proto compiler generate Java code inside the package 23 | // name (see below) instead of inside an outer class. It creates a simpler 24 | // developer experience by reducing one-level of name nesting and be 25 | // consistent with most programming languages that don't support outer classes. 26 | option java_multiple_files = true; 27 | 28 | // The Java outer classname should be the filename in UpperCamelCase. This 29 | // class is only used to hold proto descriptor, so developers don't need to 30 | // work with it directly. 31 | option java_outer_classname = "AnnotationsProto"; 32 | 33 | // The Java package name must be proto package name with proper prefix. 34 | option java_package = "org.openapi_v3"; 35 | 36 | // A reasonable prefix for the Objective-C symbols generated from the package. 37 | // It should at a minimum be 3 characters long, all uppercase, and convention 38 | // is to use an abbreviation of the package name. Something short, but 39 | // hopefully unique enough to not conflict with things that may come along in 40 | // the future. 'GPB' is reserved for the protocol buffer implementation itself. 41 | option objc_class_prefix = "OAS"; 42 | 43 | // The Go package name. 44 | option go_package = "github.com/google/gnostic/openapiv3;openapi_v3"; 45 | 46 | extend google.protobuf.FileOptions { 47 | Document document = 1143; 48 | } 49 | 50 | extend google.protobuf.MethodOptions { 51 | Operation operation = 1143; 52 | } 53 | 54 | extend google.protobuf.MessageOptions { 55 | Schema schema = 1143; 56 | } 57 | 58 | extend google.protobuf.FieldOptions { 59 | Schema property = 1143; 60 | } -------------------------------------------------------------------------------- /doutok-course/basic-knowledge/blog-demo/backend/blog-service/third_party/validate/README.md: -------------------------------------------------------------------------------- 1 | # protoc-gen-validate (PGV) 2 | 3 | * https://github.com/envoyproxy/protoc-gen-validate 4 | -------------------------------------------------------------------------------- /doutok-course/basic-knowledge/docker-intro/Dockerfile: -------------------------------------------------------------------------------- 1 | # 使用官方 Node.js 镜像作为基础镜像 2 | FROM node:16-alpine 3 | 4 | # 设置工作目录 5 | WORKDIR /app 6 | 7 | # 复制 package.json 和 package-lock.json 到工作目录 8 | COPY package*.json ./ 9 | 10 | # 安装依赖 11 | RUN npm install 12 | 13 | # 复制应用程序代码到工作目录 14 | COPY . . 15 | 16 | # 暴露应用程序运行的端口 17 | EXPOSE 3000 18 | 19 | # 定义环境变量 20 | ENV NODE_ENV=production 21 | 22 | # 运行应用程序 23 | CMD ["npm", "start"] -------------------------------------------------------------------------------- /doutok-course/basic-knowledge/docker-intro/app.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const app = express(); 3 | const port = process.env.PORT || 3000; 4 | 5 | app.get('/', (req, res) => { 6 | res.send(` 7 |

Docker 示例应用

8 |

这是一个运行在 Docker 容器中的简单 Node.js 应用。

9 |

环境: ${process.env.NODE_ENV || '开发'}

10 |

主机名: ${process.env.HOSTNAME || '未知'}

11 |

当前时间: ${new Date().toLocaleString()}

12 | `); 13 | }); 14 | 15 | app.get('/health', (req, res) => { 16 | res.status(200).json({ status: 'ok', timestamp: new Date().toISOString() }); 17 | }); 18 | 19 | app.listen(port, () => { 20 | console.log(`应用正在监听端口 ${port}`); 21 | console.log(`环境: ${process.env.NODE_ENV || '开发'}`); 22 | }); -------------------------------------------------------------------------------- /doutok-course/basic-knowledge/docker-intro/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | 3 | services: 4 | # Web 应用服务 5 | webapp: 6 | build: . 7 | container_name: my-web-app 8 | ports: 9 | - "3000:3000" 10 | environment: 11 | - NODE_ENV=production 12 | - DB_HOST=db 13 | - DB_PORT=5432 14 | - DB_USER=postgres 15 | - DB_PASSWORD=mysecretpassword 16 | - DB_NAME=mydatabase 17 | volumes: 18 | # - ./app:/app 19 | - /app/node_modules 20 | depends_on: 21 | - db 22 | restart: always 23 | networks: 24 | - app-network 25 | 26 | # 数据库服务 27 | db: 28 | image: postgres:13 29 | container_name: my-postgres 30 | ports: 31 | - "5432:5432" 32 | environment: 33 | - POSTGRES_USER=postgres 34 | - POSTGRES_PASSWORD=mysecretpassword 35 | - POSTGRES_DB=mydatabase 36 | volumes: 37 | - postgres-data:/var/lib/postgresql/data 38 | networks: 39 | - app-network 40 | 41 | # Redis 缓存服务 42 | redis: 43 | image: redis:6-alpine 44 | container_name: my-redis 45 | ports: 46 | - "6379:6379" 47 | networks: 48 | - app-network 49 | 50 | networks: 51 | app-network: 52 | driver: bridge 53 | 54 | volumes: 55 | postgres-data: -------------------------------------------------------------------------------- /doutok-course/basic-knowledge/docker-intro/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "docker-demo-app", 3 | "version": "1.0.0", 4 | "description": "Docker 示例应用", 5 | "main": "app.js", 6 | "scripts": { 7 | "start": "node app.js", 8 | "dev": "nodemon app.js", 9 | "test": "echo \"Error: no test specified\" && exit 1" 10 | }, 11 | "keywords": [ 12 | "docker", 13 | "nodejs", 14 | "express" 15 | ], 16 | "author": "Docker 学习者", 17 | "license": "MIT", 18 | "dependencies": { 19 | "express": "^4.17.1" 20 | }, 21 | "devDependencies": { 22 | "nodemon": "^2.0.15" 23 | } 24 | } -------------------------------------------------------------------------------- /doutok-course/basic-knowledge/golang-intro/hello.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "strconv" 7 | ) 8 | 9 | func main() { 10 | // 检查命令行参数 11 | if len(os.Args) > 1 && os.Args[1] == "syntax" { 12 | // 如果提供了syntax参数,则运行语法示例 13 | runSyntaxExamples() 14 | return 15 | } 16 | 17 | // 原来的Hello World程序 18 | // 打印 Hello World 19 | fmt.Println("Hello, Golang!") 20 | 21 | // 变量声明与使用 22 | var name string = "学习者" 23 | age := 25 24 | fmt.Printf("你好,%s!你今年 %d 岁。\n", name, age) 25 | 26 | // 简单的条件语句 27 | if age >= 18 { 28 | fmt.Println("你已经成年了") 29 | } else { 30 | fmt.Println("你还未成年") 31 | } 32 | 33 | // 创建一个切片并遍历 34 | languages := []string{"Go", "Python", "Java", "JavaScript"} 35 | fmt.Println("流行的编程语言:") 36 | for i, lang := range languages { 37 | fmt.Printf("%d: %s\n", i+1, lang) 38 | } 39 | 40 | // 调用函数 41 | result := add(10, 20) 42 | fmt.Printf("10 + 20 = %d\n", result) 43 | 44 | // 输出提示信息 45 | fmt.Println("\n提示: 运行 'go run hello.go syntax' 以查看更多语法示例") 46 | fmt.Println("或者运行 'go run hello.go syntax <数字>' 以查看特定类别的示例:") 47 | fmt.Println("1: 切片示例") 48 | fmt.Println("2: 映射示例") 49 | fmt.Println("3: 通道示例") 50 | fmt.Println("4: 遍历方法示例") 51 | fmt.Println("5: 错误处理示例") 52 | fmt.Println("6: 结构体和方法示例") 53 | } 54 | 55 | // 定义一个简单的函数 56 | func add(a, b int) int { 57 | return a + b 58 | } 59 | 60 | // 运行语法示例的函数 61 | func runSyntaxExamples() { 62 | if len(os.Args) > 2 { 63 | // 如果提供了第二个参数,根据参数运行特定示例 64 | category, err := strconv.Atoi(os.Args[2]) 65 | if err != nil { 66 | fmt.Println("无效的参数,请提供1-6之间的数字") 67 | return 68 | } 69 | 70 | switch category { 71 | case 1: 72 | RunSliceExamples() 73 | case 2: 74 | RunMapExamples() 75 | case 3: 76 | RunChannelExamples() 77 | case 4: 78 | RunIterationExamples() 79 | case 5: 80 | RunErrorHandlingExamples() 81 | case 6: 82 | RunStructExamples() 83 | default: 84 | fmt.Println("无效的类别,请提供1-6之间的数字") 85 | } 86 | } else { 87 | // 如果没有提供第二个参数,运行所有示例 88 | RunAllExamples() 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /doutok-course/basic-knowledge/golang-intro/syntax_examples_README.md: -------------------------------------------------------------------------------- 1 | # Go语言语法示例说明 2 | 3 | 这个文件包含了Go语言常用语法特性的示例代码,适合Go语言初学者参考。运行这个示例可以加深对Go语言核心特性的理解。 4 | 5 | ## 示例内容 6 | 7 | 该示例包含以下六个主要部分: 8 | 9 | 1. **切片(Slice)** - 展示了Go语言中切片的创建、操作和内部原理 10 | 2. **映射(Map)** - 介绍了映射的创建及常用操作 11 | 3. **通道(Channel)** - 演示了通道的基本用法和常见模式 12 | 4. **遍历方法** - 展示如何遍历不同类型的数据结构 13 | 5. **错误处理** - 包含错误返回、panic/recover和defer的示例 14 | 6. **结构体和方法** - 演示结构体定义、方法、接口和并发安全 15 | 16 | ## 如何运行 17 | 18 | 你可以通过以下方式运行这些示例: 19 | 20 | ```bash 21 | # 运行所有语法示例 22 | go run ./ syntax 23 | 24 | # 运行特定类别的示例(用1-6的数字替换) 25 | go run ./ syntax 26 | ``` 27 | 28 | 类别对应关系: 29 | 1. 切片示例 30 | 2. 映射示例 31 | 3. 通道示例 32 | 4. 遍历方法示例 33 | 5. 错误处理示例 34 | 6. 结构体和方法示例 35 | 36 | ## 关键特性详解 37 | 38 | ### 1. 切片(Slice) 39 | 40 | Go中的切片是对数组的抽象,它比数组更灵活、强大。示例展示了: 41 | 42 | - 通过字面量、make函数和从数组创建切片的不同方式 43 | - 切片的添加、复制、合并等操作 44 | - 切片的内部工作原理(底层数组共享和扩容机制) 45 | 46 | ### 2. 映射(Map) 47 | 48 | 映射是哈希表的实现,用于存储键值对: 49 | 50 | - 通过字面量和make函数创建映射 51 | - 添加、删除、查找元素的操作 52 | - 检查键是否存在 53 | - 映射的引用特性 54 | 55 | ### 3. 通道(Channel) 56 | 57 | 通道是Go并发编程的核心,用于goroutine之间的通信: 58 | 59 | - 无缓冲和有缓冲通道的创建 60 | - 通道的发送和接收操作 61 | - 通道方向限制(只读、只写) 62 | - 使用select处理多个通道 63 | - 使用通道进行goroutine同步 64 | 65 | ### 4. 遍历方法 66 | 67 | Go提供了灵活的遍历语法,适用于多种数据类型: 68 | 69 | - 数组和切片的遍历(索引遍历和range遍历) 70 | - 映射的遍历(键值对) 71 | - 字符串遍历(字节和Unicode字符) 72 | - 通道遍历 73 | 74 | ### 5. 错误处理 75 | 76 | Go的错误处理机制简单而有效: 77 | 78 | - 返回错误值 79 | - panic和recover机制 80 | - defer语句及其执行顺序 81 | - 资源清理的最佳实践 82 | 83 | ### 6. 结构体和方法 84 | 85 | Go的面向对象特性主要通过结构体和接口实现: 86 | 87 | - 结构体的定义和创建 88 | - 值接收者和指针接收者方法 89 | - 结构体嵌套 90 | - 接口定义和实现 91 | - 并发安全的结构体 92 | 93 | ## 学习建议 94 | 95 | 1. 先浏览整个代码文件,了解Go语言的核心特性 96 | 2. 运行代码,观察输出结果 97 | 3. 尝试修改代码,查看不同的行为 98 | 4. 针对感兴趣的部分深入学习相关知识 99 | 100 | Go语言强调简洁、效率和并发性,通过这些示例可以帮助你更好地理解Go的设计理念和编程模式。 -------------------------------------------------------------------------------- /doutok-course/basic-knowledge/kratos-intro/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | 7 | "github.com/go-kratos/kratos/v2" 8 | "github.com/go-kratos/kratos/v2/log" 9 | "github.com/go-kratos/kratos/v2/middleware/recovery" 10 | "github.com/go-kratos/kratos/v2/transport/http" 11 | ) 12 | 13 | // 这是一个简化的 Kratos 应用示例 14 | // 在真实环境中,需要安装 Kratos 并使用 kratos 命令行工具生成完整项目 15 | 16 | func main() { 17 | // 初始化 logger 18 | logger := log.NewStdLogger(os.Stdout) 19 | log := log.NewHelper(logger) 20 | 21 | // 创建 HTTP 服务器 22 | httpSrv := http.NewServer( 23 | http.Address(":8000"), 24 | http.Middleware( 25 | recovery.Recovery(), // 添加异常恢复中间件 26 | ), 27 | ) 28 | // 使用路由组 29 | r := httpSrv.Route("/") 30 | r.GET("", func(ctx http.Context) error { 31 | return ctx.String(200, "Hello Kratos!") 32 | }) 33 | 34 | r.GET("/hello", func(ctx http.Context) error { 35 | return ctx.String(200, "Hello Kratos API!") 36 | }) 37 | 38 | // 创建 Kratos 应用实例 39 | app := kratos.New( 40 | kratos.Name("kratos-demo"), 41 | kratos.Server( 42 | httpSrv, 43 | ), 44 | kratos.Logger(logger), 45 | ) 46 | 47 | // 启动应用 48 | if err := app.Run(); err != nil { 49 | log.Errorf("启动应用失败: %v", err) 50 | return 51 | } 52 | 53 | fmt.Println("服务启动成功,监听端口: 8000") 54 | } 55 | 56 | // 说明:这是示例代码,需要先安装依赖才能运行 57 | // 安装 Kratos: 58 | // go get github.com/go-kratos/kratos/v2 59 | // 60 | // 完整项目建议使用 Kratos 工具创建: 61 | // go install github.com/go-kratos/kratos/cmd/kratos/v2@latest 62 | // kratos new server 63 | -------------------------------------------------------------------------------- /doutok-course/basic-knowledge/kratos-intro/myproject/.gitignore: -------------------------------------------------------------------------------- 1 | # Reference https://github.com/github/gitignore/blob/master/Go.gitignore 2 | # Binaries for programs and plugins 3 | *.exe 4 | *.exe~ 5 | *.dll 6 | *.dylib 7 | 8 | # Test binary, built with `go test -c` 9 | *.test 10 | 11 | # Output of the go coverage tool, specifically when used with LiteIDE 12 | *.out 13 | 14 | # Dependency directories (remove the comment below to include it) 15 | vendor/ 16 | 17 | # Go workspace file 18 | go.work 19 | 20 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 21 | *.o 22 | *.a 23 | *.so 24 | 25 | # OS General 26 | Thumbs.db 27 | .DS_Store 28 | 29 | # project 30 | *.cert 31 | *.key 32 | *.log 33 | bin/ 34 | 35 | # Develop tools 36 | .vscode/ 37 | .idea/ 38 | *.swp 39 | -------------------------------------------------------------------------------- /doutok-course/basic-knowledge/kratos-intro/myproject/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1.19 AS builder 2 | 3 | COPY . /src 4 | WORKDIR /src 5 | 6 | RUN GOPROXY=https://goproxy.cn make build 7 | 8 | FROM debian:stable-slim 9 | 10 | RUN apt-get update && apt-get install -y --no-install-recommends \ 11 | ca-certificates \ 12 | netbase \ 13 | && rm -rf /var/lib/apt/lists/ \ 14 | && apt-get autoremove -y && apt-get autoclean -y 15 | 16 | COPY --from=builder /src/bin /app 17 | 18 | WORKDIR /app 19 | 20 | EXPOSE 8000 21 | EXPOSE 9000 22 | VOLUME /data/conf 23 | 24 | CMD ["./server", "-conf", "/data/conf"] 25 | -------------------------------------------------------------------------------- /doutok-course/basic-knowledge/kratos-intro/myproject/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 go-kratos 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /doutok-course/basic-knowledge/kratos-intro/myproject/Makefile: -------------------------------------------------------------------------------- 1 | GOHOSTOS:=$(shell go env GOHOSTOS) 2 | GOPATH:=$(shell go env GOPATH) 3 | VERSION=$(shell git describe --tags --always) 4 | 5 | ifeq ($(GOHOSTOS), windows) 6 | #the `find.exe` is different from `find` in bash/shell. 7 | #to see https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/find. 8 | #changed to use git-bash.exe to run find cli or other cli friendly, caused of every developer has a Git. 9 | #Git_Bash= $(subst cmd\,bin\bash.exe,$(dir $(shell where git))) 10 | Git_Bash=$(subst \,/,$(subst cmd\,bin\bash.exe,$(dir $(shell where git)))) 11 | INTERNAL_PROTO_FILES=$(shell $(Git_Bash) -c "find internal -name *.proto") 12 | API_PROTO_FILES=$(shell $(Git_Bash) -c "find api -name *.proto") 13 | else 14 | INTERNAL_PROTO_FILES=$(shell find internal -name *.proto) 15 | API_PROTO_FILES=$(shell find api -name *.proto) 16 | endif 17 | 18 | .PHONY: init 19 | # init env 20 | init: 21 | go install google.golang.org/protobuf/cmd/protoc-gen-go@latest 22 | go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest 23 | go install github.com/go-kratos/kratos/cmd/kratos/v2@latest 24 | go install github.com/go-kratos/kratos/cmd/protoc-gen-go-http/v2@latest 25 | go install github.com/google/gnostic/cmd/protoc-gen-openapi@latest 26 | go install github.com/google/wire/cmd/wire@latest 27 | 28 | .PHONY: config 29 | # generate internal proto 30 | config: 31 | protoc --proto_path=./internal \ 32 | --proto_path=./third_party \ 33 | --go_out=paths=source_relative:./internal \ 34 | $(INTERNAL_PROTO_FILES) 35 | 36 | .PHONY: api 37 | # generate api proto 38 | api: 39 | protoc --proto_path=./api \ 40 | --proto_path=./third_party \ 41 | --go_out=paths=source_relative:./api \ 42 | --go-http_out=paths=source_relative:./api \ 43 | --go-grpc_out=paths=source_relative:./api \ 44 | --openapi_out=fq_schema_naming=true,default_response=false:. \ 45 | $(API_PROTO_FILES) 46 | 47 | .PHONY: build 48 | # build 49 | build: 50 | mkdir -p bin/ && go build -ldflags "-X main.Version=$(VERSION)" -o ./bin/ ./... 51 | 52 | .PHONY: generate 53 | # generate 54 | generate: 55 | go generate ./... 56 | go mod tidy 57 | 58 | .PHONY: all 59 | # generate all 60 | all: 61 | make api; 62 | make config; 63 | make generate; 64 | 65 | # show help 66 | help: 67 | @echo '' 68 | @echo 'Usage:' 69 | @echo ' make [target]' 70 | @echo '' 71 | @echo 'Targets:' 72 | @awk '/^[a-zA-Z\-\_0-9]+:/ { \ 73 | helpMessage = match(lastLine, /^# (.*)/); \ 74 | if (helpMessage) { \ 75 | helpCommand = substr($$1, 0, index($$1, ":")); \ 76 | helpMessage = substr(lastLine, RSTART + 2, RLENGTH); \ 77 | printf "\033[36m%-22s\033[0m %s\n", helpCommand,helpMessage; \ 78 | } \ 79 | } \ 80 | { lastLine = $$0 }' $(MAKEFILE_LIST) 81 | 82 | .DEFAULT_GOAL := help 83 | -------------------------------------------------------------------------------- /doutok-course/basic-knowledge/kratos-intro/myproject/README.md: -------------------------------------------------------------------------------- 1 | # Kratos Project Template 2 | 3 | ## Install Kratos 4 | ``` 5 | go install github.com/go-kratos/kratos/cmd/kratos/v2@latest 6 | ``` 7 | ## Create a service 8 | ``` 9 | # Create a template project 10 | kratos new server 11 | 12 | cd server 13 | # Add a proto template 14 | kratos proto add api/server/server.proto 15 | # Generate the proto code 16 | kratos proto client api/server/server.proto 17 | # Generate the source code of service by proto file 18 | kratos proto server api/server/server.proto -t internal/service 19 | 20 | go generate ./... 21 | go build -o ./bin/ ./... 22 | ./bin/server -conf ./configs 23 | ``` 24 | ## Generate other auxiliary files by Makefile 25 | ``` 26 | # Download and update dependencies 27 | make init 28 | # Generate API files (include: pb.go, http, grpc, validate, swagger) by proto file 29 | make api 30 | # Generate all files 31 | make all 32 | ``` 33 | ## Automated Initialization (wire) 34 | ``` 35 | # install wire 36 | go get github.com/google/wire/cmd/wire 37 | 38 | # generate wire 39 | cd cmd/server 40 | wire 41 | ``` 42 | 43 | ## Docker 44 | ```bash 45 | # build 46 | docker build -t . 47 | 48 | # run 49 | docker run --rm -p 8000:8000 -p 9000:9000 -v :/data/conf 50 | ``` 51 | 52 | -------------------------------------------------------------------------------- /doutok-course/basic-knowledge/kratos-intro/myproject/api/helloworld/v1/error_reason.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package helloworld.v1; 4 | 5 | option go_package = "myproject/api/helloworld/v1;v1"; 6 | option java_multiple_files = true; 7 | option java_package = "helloworld.v1"; 8 | option objc_class_prefix = "APIHelloworldV1"; 9 | 10 | enum ErrorReason { 11 | GREETER_UNSPECIFIED = 0; 12 | USER_NOT_FOUND = 1; 13 | } 14 | -------------------------------------------------------------------------------- /doutok-course/basic-knowledge/kratos-intro/myproject/api/helloworld/v1/greeter.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package helloworld.v1; 4 | 5 | import "google/api/annotations.proto"; 6 | 7 | option go_package = "myproject/api/helloworld/v1;v1"; 8 | option java_multiple_files = true; 9 | option java_package = "dev.kratos.api.helloworld.v1"; 10 | option java_outer_classname = "HelloworldProtoV1"; 11 | 12 | // The greeting service definition. 13 | service Greeter { 14 | // Sends a greeting 15 | rpc SayHello (HelloRequest) returns (HelloReply) { 16 | option (google.api.http) = { 17 | get: "/helloworld/{name}" 18 | }; 19 | } 20 | } 21 | 22 | // The request message containing the user's name. 23 | message HelloRequest { 24 | string name = 1; 25 | } 26 | 27 | // The response message containing the greetings 28 | message HelloReply { 29 | string message = 1; 30 | } 31 | -------------------------------------------------------------------------------- /doutok-course/basic-knowledge/kratos-intro/myproject/api/helloworld/v1/greeter_http.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go-http. DO NOT EDIT. 2 | // versions: 3 | // protoc-gen-go-http v2.1.3 4 | 5 | package v1 6 | 7 | import ( 8 | context "context" 9 | http "github.com/go-kratos/kratos/v2/transport/http" 10 | binding "github.com/go-kratos/kratos/v2/transport/http/binding" 11 | ) 12 | 13 | // This is a compile-time assertion to ensure that this generated file 14 | // is compatible with the kratos package it is being compiled against. 15 | var _ = new(context.Context) 16 | var _ = binding.EncodeURL 17 | 18 | const _ = http.SupportPackageIsVersion1 19 | 20 | type GreeterHTTPServer interface { 21 | SayHello(context.Context, *HelloRequest) (*HelloReply, error) 22 | } 23 | 24 | func RegisterGreeterHTTPServer(s *http.Server, srv GreeterHTTPServer) { 25 | r := s.Route("/") 26 | r.GET("/helloworld/{name}", _Greeter_SayHello0_HTTP_Handler(srv)) 27 | } 28 | 29 | func _Greeter_SayHello0_HTTP_Handler(srv GreeterHTTPServer) func(ctx http.Context) error { 30 | return func(ctx http.Context) error { 31 | var in HelloRequest 32 | if err := ctx.BindQuery(&in); err != nil { 33 | return err 34 | } 35 | if err := ctx.BindVars(&in); err != nil { 36 | return err 37 | } 38 | http.SetOperation(ctx, "/helloworld.v1.Greeter/SayHello") 39 | h := ctx.Middleware(func(ctx context.Context, req interface{}) (interface{}, error) { 40 | return srv.SayHello(ctx, req.(*HelloRequest)) 41 | }) 42 | out, err := h(ctx, &in) 43 | if err != nil { 44 | return err 45 | } 46 | reply := out.(*HelloReply) 47 | return ctx.Result(200, reply) 48 | } 49 | } 50 | 51 | type GreeterHTTPClient interface { 52 | SayHello(ctx context.Context, req *HelloRequest, opts ...http.CallOption) (rsp *HelloReply, err error) 53 | } 54 | 55 | type GreeterHTTPClientImpl struct { 56 | cc *http.Client 57 | } 58 | 59 | func NewGreeterHTTPClient(client *http.Client) GreeterHTTPClient { 60 | return &GreeterHTTPClientImpl{client} 61 | } 62 | 63 | func (c *GreeterHTTPClientImpl) SayHello(ctx context.Context, in *HelloRequest, opts ...http.CallOption) (*HelloReply, error) { 64 | var out HelloReply 65 | pattern := "/helloworld/{name}" 66 | path := binding.EncodeURL(pattern, in, true) 67 | opts = append(opts, http.Operation("/helloworld.v1.Greeter/SayHello")) 68 | opts = append(opts, http.PathTemplate(pattern)) 69 | err := c.cc.Invoke(ctx, "GET", path, nil, &out, opts...) 70 | if err != nil { 71 | return nil, err 72 | } 73 | return &out, err 74 | } 75 | -------------------------------------------------------------------------------- /doutok-course/basic-knowledge/kratos-intro/myproject/cmd/myproject/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "os" 6 | 7 | "myproject/internal/conf" 8 | 9 | "github.com/go-kratos/kratos/v2" 10 | "github.com/go-kratos/kratos/v2/config" 11 | "github.com/go-kratos/kratos/v2/config/file" 12 | "github.com/go-kratos/kratos/v2/log" 13 | "github.com/go-kratos/kratos/v2/middleware/tracing" 14 | "github.com/go-kratos/kratos/v2/transport/grpc" 15 | "github.com/go-kratos/kratos/v2/transport/http" 16 | 17 | _ "go.uber.org/automaxprocs" 18 | ) 19 | 20 | // go build -ldflags "-X main.Version=x.y.z" 21 | var ( 22 | // Name is the name of the compiled software. 23 | Name string 24 | // Version is the version of the compiled software. 25 | Version string 26 | // flagconf is the config flag. 27 | flagconf string 28 | 29 | id, _ = os.Hostname() 30 | ) 31 | 32 | func init() { 33 | flag.StringVar(&flagconf, "conf", "../../configs", "config path, eg: -conf config.yaml") 34 | } 35 | 36 | func newApp(logger log.Logger, gs *grpc.Server, hs *http.Server) *kratos.App { 37 | return kratos.New( 38 | kratos.ID(id), 39 | kratos.Name(Name), 40 | kratos.Version(Version), 41 | kratos.Metadata(map[string]string{}), 42 | kratos.Logger(logger), 43 | kratos.Server( 44 | gs, 45 | hs, 46 | ), 47 | ) 48 | } 49 | 50 | func main() { 51 | flag.Parse() 52 | logger := log.With(log.NewStdLogger(os.Stdout), 53 | "ts", log.DefaultTimestamp, 54 | "caller", log.DefaultCaller, 55 | "service.id", id, 56 | "service.name", Name, 57 | "service.version", Version, 58 | "trace.id", tracing.TraceID(), 59 | "span.id", tracing.SpanID(), 60 | ) 61 | c := config.New( 62 | config.WithSource( 63 | file.NewSource(flagconf), 64 | ), 65 | ) 66 | defer c.Close() 67 | 68 | if err := c.Load(); err != nil { 69 | panic(err) 70 | } 71 | 72 | var bc conf.Bootstrap 73 | if err := c.Scan(&bc); err != nil { 74 | panic(err) 75 | } 76 | 77 | app, cleanup, err := wireApp(bc.Server, bc.Data, logger) 78 | if err != nil { 79 | panic(err) 80 | } 81 | defer cleanup() 82 | 83 | // start and wait for stop signal 84 | if err := app.Run(); err != nil { 85 | panic(err) 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /doutok-course/basic-knowledge/kratos-intro/myproject/cmd/myproject/wire.go: -------------------------------------------------------------------------------- 1 | //go:build wireinject 2 | // +build wireinject 3 | 4 | // The build tag makes sure the stub is not built in the final build. 5 | 6 | package main 7 | 8 | import ( 9 | "myproject/internal/biz" 10 | "myproject/internal/conf" 11 | "myproject/internal/data" 12 | "myproject/internal/server" 13 | "myproject/internal/service" 14 | 15 | "github.com/go-kratos/kratos/v2" 16 | "github.com/go-kratos/kratos/v2/log" 17 | "github.com/google/wire" 18 | ) 19 | 20 | // wireApp init kratos application. 21 | func wireApp(*conf.Server, *conf.Data, log.Logger) (*kratos.App, func(), error) { 22 | panic(wire.Build(server.ProviderSet, data.ProviderSet, biz.ProviderSet, service.ProviderSet, newApp)) 23 | } 24 | -------------------------------------------------------------------------------- /doutok-course/basic-knowledge/kratos-intro/myproject/cmd/myproject/wire_gen.go: -------------------------------------------------------------------------------- 1 | // Code generated by Wire. DO NOT EDIT. 2 | 3 | //go:generate go run -mod=mod github.com/google/wire/cmd/wire 4 | //go:build !wireinject 5 | // +build !wireinject 6 | 7 | package main 8 | 9 | import ( 10 | "myproject/internal/biz" 11 | "myproject/internal/conf" 12 | "myproject/internal/data" 13 | "myproject/internal/server" 14 | "myproject/internal/service" 15 | "github.com/go-kratos/kratos/v2" 16 | "github.com/go-kratos/kratos/v2/log" 17 | ) 18 | 19 | import ( 20 | _ "go.uber.org/automaxprocs" 21 | ) 22 | 23 | // Injectors from wire.go: 24 | 25 | // wireApp init kratos application. 26 | func wireApp(confServer *conf.Server, confData *conf.Data, logger log.Logger) (*kratos.App, func(), error) { 27 | dataData, cleanup, err := data.NewData(confData, logger) 28 | if err != nil { 29 | return nil, nil, err 30 | } 31 | greeterRepo := data.NewGreeterRepo(dataData, logger) 32 | greeterUsecase := biz.NewGreeterUsecase(greeterRepo, logger) 33 | greeterService := service.NewGreeterService(greeterUsecase) 34 | grpcServer := server.NewGRPCServer(confServer, greeterService, logger) 35 | httpServer := server.NewHTTPServer(confServer, greeterService, logger) 36 | app := newApp(logger, grpcServer, httpServer) 37 | return app, func() { 38 | cleanup() 39 | }, nil 40 | } 41 | -------------------------------------------------------------------------------- /doutok-course/basic-knowledge/kratos-intro/myproject/configs/config.yaml: -------------------------------------------------------------------------------- 1 | server: 2 | http: 3 | addr: 0.0.0.0:8000 4 | timeout: 1s 5 | grpc: 6 | addr: 0.0.0.0:9000 7 | timeout: 1s 8 | data: 9 | database: 10 | driver: mysql 11 | source: root:root@tcp(127.0.0.1:3306)/test?parseTime=True&loc=Local 12 | redis: 13 | addr: 127.0.0.1:6379 14 | read_timeout: 0.2s 15 | write_timeout: 0.2s 16 | -------------------------------------------------------------------------------- /doutok-course/basic-knowledge/kratos-intro/myproject/go.mod: -------------------------------------------------------------------------------- 1 | module myproject 2 | 3 | go 1.21 4 | 5 | toolchain go1.22.6 6 | 7 | require ( 8 | github.com/go-kratos/kratos/v2 v2.8.0 9 | github.com/google/wire v0.6.0 10 | go.uber.org/automaxprocs v1.5.1 11 | google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157 12 | google.golang.org/grpc v1.65.0 13 | google.golang.org/protobuf v1.34.1 14 | ) 15 | 16 | require ( 17 | dario.cat/mergo v1.0.0 // indirect 18 | github.com/fsnotify/fsnotify v1.6.0 // indirect 19 | github.com/go-kratos/aegis v0.2.0 // indirect 20 | github.com/go-logr/logr v1.4.1 // indirect 21 | github.com/go-logr/stdr v1.2.2 // indirect 22 | github.com/go-playground/form/v4 v4.2.1 // indirect 23 | github.com/google/uuid v1.6.0 // indirect 24 | github.com/gorilla/mux v1.8.1 // indirect 25 | github.com/kr/text v0.2.0 // indirect 26 | go.opentelemetry.io/otel v1.24.0 // indirect 27 | go.opentelemetry.io/otel/metric v1.24.0 // indirect 28 | go.opentelemetry.io/otel/trace v1.24.0 // indirect 29 | golang.org/x/net v0.25.0 // indirect 30 | golang.org/x/sync v0.7.0 // indirect 31 | golang.org/x/sys v0.20.0 // indirect 32 | golang.org/x/text v0.15.0 // indirect 33 | google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157 // indirect 34 | gopkg.in/yaml.v3 v3.0.1 // indirect 35 | ) 36 | -------------------------------------------------------------------------------- /doutok-course/basic-knowledge/kratos-intro/myproject/internal/biz/README.md: -------------------------------------------------------------------------------- 1 | # Biz 2 | -------------------------------------------------------------------------------- /doutok-course/basic-knowledge/kratos-intro/myproject/internal/biz/biz.go: -------------------------------------------------------------------------------- 1 | package biz 2 | 3 | import "github.com/google/wire" 4 | 5 | // ProviderSet is biz providers. 6 | var ProviderSet = wire.NewSet(NewGreeterUsecase) 7 | -------------------------------------------------------------------------------- /doutok-course/basic-knowledge/kratos-intro/myproject/internal/biz/greeter.go: -------------------------------------------------------------------------------- 1 | package biz 2 | 3 | import ( 4 | "context" 5 | 6 | v1 "myproject/api/helloworld/v1" 7 | 8 | "github.com/go-kratos/kratos/v2/errors" 9 | "github.com/go-kratos/kratos/v2/log" 10 | ) 11 | 12 | var ( 13 | // ErrUserNotFound is user not found. 14 | ErrUserNotFound = errors.NotFound(v1.ErrorReason_USER_NOT_FOUND.String(), "user not found") 15 | ) 16 | 17 | // Greeter is a Greeter model. 18 | type Greeter struct { 19 | Hello string 20 | } 21 | 22 | // GreeterRepo is a Greater repo. 23 | type GreeterRepo interface { 24 | Save(context.Context, *Greeter) (*Greeter, error) 25 | Update(context.Context, *Greeter) (*Greeter, error) 26 | FindByID(context.Context, int64) (*Greeter, error) 27 | ListByHello(context.Context, string) ([]*Greeter, error) 28 | ListAll(context.Context) ([]*Greeter, error) 29 | } 30 | 31 | // GreeterUsecase is a Greeter usecase. 32 | type GreeterUsecase struct { 33 | repo GreeterRepo 34 | log *log.Helper 35 | } 36 | 37 | // NewGreeterUsecase new a Greeter usecase. 38 | func NewGreeterUsecase(repo GreeterRepo, logger log.Logger) *GreeterUsecase { 39 | return &GreeterUsecase{repo: repo, log: log.NewHelper(logger)} 40 | } 41 | 42 | // CreateGreeter creates a Greeter, and returns the new Greeter. 43 | func (uc *GreeterUsecase) CreateGreeter(ctx context.Context, g *Greeter) (*Greeter, error) { 44 | uc.log.WithContext(ctx).Infof("CreateGreeter: %v", g.Hello) 45 | return uc.repo.Save(ctx, g) 46 | } 47 | -------------------------------------------------------------------------------- /doutok-course/basic-knowledge/kratos-intro/myproject/internal/conf/conf.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package kratos.api; 3 | 4 | option go_package = "myproject/internal/conf;conf"; 5 | 6 | import "google/protobuf/duration.proto"; 7 | 8 | message Bootstrap { 9 | Server server = 1; 10 | Data data = 2; 11 | } 12 | 13 | message Server { 14 | message HTTP { 15 | string network = 1; 16 | string addr = 2; 17 | google.protobuf.Duration timeout = 3; 18 | } 19 | message GRPC { 20 | string network = 1; 21 | string addr = 2; 22 | google.protobuf.Duration timeout = 3; 23 | } 24 | HTTP http = 1; 25 | GRPC grpc = 2; 26 | } 27 | 28 | message Data { 29 | message Database { 30 | string driver = 1; 31 | string source = 2; 32 | } 33 | message Redis { 34 | string network = 1; 35 | string addr = 2; 36 | google.protobuf.Duration read_timeout = 3; 37 | google.protobuf.Duration write_timeout = 4; 38 | } 39 | Database database = 1; 40 | Redis redis = 2; 41 | } 42 | -------------------------------------------------------------------------------- /doutok-course/basic-knowledge/kratos-intro/myproject/internal/data/README.md: -------------------------------------------------------------------------------- 1 | # Data 2 | -------------------------------------------------------------------------------- /doutok-course/basic-knowledge/kratos-intro/myproject/internal/data/data.go: -------------------------------------------------------------------------------- 1 | package data 2 | 3 | import ( 4 | "myproject/internal/conf" 5 | 6 | "github.com/go-kratos/kratos/v2/log" 7 | "github.com/google/wire" 8 | ) 9 | 10 | // ProviderSet is data providers. 11 | var ProviderSet = wire.NewSet(NewData, NewGreeterRepo) 12 | 13 | // Data . 14 | type Data struct { 15 | // TODO wrapped database client 16 | } 17 | 18 | // NewData . 19 | func NewData(c *conf.Data, logger log.Logger) (*Data, func(), error) { 20 | cleanup := func() { 21 | log.NewHelper(logger).Info("closing the data resources") 22 | } 23 | return &Data{}, cleanup, nil 24 | } 25 | -------------------------------------------------------------------------------- /doutok-course/basic-knowledge/kratos-intro/myproject/internal/data/greeter.go: -------------------------------------------------------------------------------- 1 | package data 2 | 3 | import ( 4 | "context" 5 | 6 | "myproject/internal/biz" 7 | 8 | "github.com/go-kratos/kratos/v2/log" 9 | ) 10 | 11 | type greeterRepo struct { 12 | data *Data 13 | log *log.Helper 14 | } 15 | 16 | // NewGreeterRepo . 17 | func NewGreeterRepo(data *Data, logger log.Logger) biz.GreeterRepo { 18 | return &greeterRepo{ 19 | data: data, 20 | log: log.NewHelper(logger), 21 | } 22 | } 23 | 24 | func (r *greeterRepo) Save(ctx context.Context, g *biz.Greeter) (*biz.Greeter, error) { 25 | return g, nil 26 | } 27 | 28 | func (r *greeterRepo) Update(ctx context.Context, g *biz.Greeter) (*biz.Greeter, error) { 29 | return g, nil 30 | } 31 | 32 | func (r *greeterRepo) FindByID(context.Context, int64) (*biz.Greeter, error) { 33 | return nil, nil 34 | } 35 | 36 | func (r *greeterRepo) ListByHello(context.Context, string) ([]*biz.Greeter, error) { 37 | return nil, nil 38 | } 39 | 40 | func (r *greeterRepo) ListAll(context.Context) ([]*biz.Greeter, error) { 41 | return nil, nil 42 | } 43 | -------------------------------------------------------------------------------- /doutok-course/basic-knowledge/kratos-intro/myproject/internal/server/grpc.go: -------------------------------------------------------------------------------- 1 | package server 2 | 3 | import ( 4 | v1 "myproject/api/helloworld/v1" 5 | "myproject/internal/conf" 6 | "myproject/internal/service" 7 | 8 | "github.com/go-kratos/kratos/v2/log" 9 | "github.com/go-kratos/kratos/v2/middleware/recovery" 10 | "github.com/go-kratos/kratos/v2/transport/grpc" 11 | ) 12 | 13 | // NewGRPCServer new a gRPC server. 14 | func NewGRPCServer(c *conf.Server, greeter *service.GreeterService, logger log.Logger) *grpc.Server { 15 | var opts = []grpc.ServerOption{ 16 | grpc.Middleware( 17 | recovery.Recovery(), 18 | ), 19 | } 20 | if c.Grpc.Network != "" { 21 | opts = append(opts, grpc.Network(c.Grpc.Network)) 22 | } 23 | if c.Grpc.Addr != "" { 24 | opts = append(opts, grpc.Address(c.Grpc.Addr)) 25 | } 26 | if c.Grpc.Timeout != nil { 27 | opts = append(opts, grpc.Timeout(c.Grpc.Timeout.AsDuration())) 28 | } 29 | srv := grpc.NewServer(opts...) 30 | v1.RegisterGreeterServer(srv, greeter) 31 | return srv 32 | } 33 | -------------------------------------------------------------------------------- /doutok-course/basic-knowledge/kratos-intro/myproject/internal/server/http.go: -------------------------------------------------------------------------------- 1 | package server 2 | 3 | import ( 4 | v1 "myproject/api/helloworld/v1" 5 | "myproject/internal/conf" 6 | "myproject/internal/service" 7 | 8 | "github.com/go-kratos/kratos/v2/log" 9 | "github.com/go-kratos/kratos/v2/middleware/recovery" 10 | "github.com/go-kratos/kratos/v2/transport/http" 11 | ) 12 | 13 | // NewHTTPServer new an HTTP server. 14 | func NewHTTPServer(c *conf.Server, greeter *service.GreeterService, logger log.Logger) *http.Server { 15 | var opts = []http.ServerOption{ 16 | http.Middleware( 17 | recovery.Recovery(), 18 | ), 19 | } 20 | if c.Http.Network != "" { 21 | opts = append(opts, http.Network(c.Http.Network)) 22 | } 23 | if c.Http.Addr != "" { 24 | opts = append(opts, http.Address(c.Http.Addr)) 25 | } 26 | if c.Http.Timeout != nil { 27 | opts = append(opts, http.Timeout(c.Http.Timeout.AsDuration())) 28 | } 29 | srv := http.NewServer(opts...) 30 | v1.RegisterGreeterHTTPServer(srv, greeter) 31 | return srv 32 | } 33 | -------------------------------------------------------------------------------- /doutok-course/basic-knowledge/kratos-intro/myproject/internal/server/server.go: -------------------------------------------------------------------------------- 1 | package server 2 | 3 | import ( 4 | "github.com/google/wire" 5 | ) 6 | 7 | // ProviderSet is server providers. 8 | var ProviderSet = wire.NewSet(NewGRPCServer, NewHTTPServer) 9 | -------------------------------------------------------------------------------- /doutok-course/basic-knowledge/kratos-intro/myproject/internal/service/README.md: -------------------------------------------------------------------------------- 1 | # Service 2 | -------------------------------------------------------------------------------- /doutok-course/basic-knowledge/kratos-intro/myproject/internal/service/greeter.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "context" 5 | 6 | v1 "myproject/api/helloworld/v1" 7 | "myproject/internal/biz" 8 | ) 9 | 10 | // GreeterService is a greeter service. 11 | type GreeterService struct { 12 | v1.UnimplementedGreeterServer 13 | 14 | uc *biz.GreeterUsecase 15 | } 16 | 17 | // NewGreeterService new a greeter service. 18 | func NewGreeterService(uc *biz.GreeterUsecase) *GreeterService { 19 | return &GreeterService{uc: uc} 20 | } 21 | 22 | // SayHello implements helloworld.GreeterServer. 23 | func (s *GreeterService) SayHello(ctx context.Context, in *v1.HelloRequest) (*v1.HelloReply, error) { 24 | g, err := s.uc.CreateGreeter(ctx, &biz.Greeter{Hello: in.Name}) 25 | if err != nil { 26 | return nil, err 27 | } 28 | return &v1.HelloReply{Message: "Hello " + g.Hello}, nil 29 | } 30 | -------------------------------------------------------------------------------- /doutok-course/basic-knowledge/kratos-intro/myproject/internal/service/service.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import "github.com/google/wire" 4 | 5 | // ProviderSet is service providers. 6 | var ProviderSet = wire.NewSet(NewGreeterService) 7 | -------------------------------------------------------------------------------- /doutok-course/basic-knowledge/kratos-intro/myproject/openapi.yaml: -------------------------------------------------------------------------------- 1 | # Generated with protoc-gen-openapi 2 | # https://github.com/google/gnostic/tree/master/cmd/protoc-gen-openapi 3 | 4 | openapi: 3.0.3 5 | info: 6 | title: Greeter API 7 | description: The greeting service definition. 8 | version: 0.0.1 9 | paths: 10 | /helloworld/{name}: 11 | get: 12 | tags: 13 | - Greeter 14 | - subgroup 15 | description: Sends a greeting 16 | operationId: Greeter_SayHello 17 | parameters: 18 | - name: name 19 | in: path 20 | required: true 21 | schema: 22 | type: string 23 | responses: 24 | "200": 25 | description: OK 26 | content: 27 | application/json: 28 | schema: 29 | $ref: '#/components/schemas/helloworld.v1.HelloReply' 30 | components: 31 | schemas: 32 | helloworld.v1.HelloReply: 33 | type: object 34 | properties: 35 | message: 36 | type: string 37 | description: The response message containing the greetings 38 | tags: 39 | - name: Greeter 40 | -------------------------------------------------------------------------------- /doutok-course/basic-knowledge/kratos-intro/myproject/third_party/README.md: -------------------------------------------------------------------------------- 1 | # third_party 2 | -------------------------------------------------------------------------------- /doutok-course/basic-knowledge/kratos-intro/myproject/third_party/errors/errors.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package errors; 4 | 5 | option go_package = "github.com/go-kratos/kratos/v2/errors;errors"; 6 | option java_multiple_files = true; 7 | option java_package = "com.github.kratos.errors"; 8 | option objc_class_prefix = "KratosErrors"; 9 | 10 | import "google/protobuf/descriptor.proto"; 11 | 12 | extend google.protobuf.EnumOptions { 13 | int32 default_code = 1108; 14 | } 15 | 16 | extend google.protobuf.EnumValueOptions { 17 | int32 code = 1109; 18 | } -------------------------------------------------------------------------------- /doutok-course/basic-knowledge/kratos-intro/myproject/third_party/google/api/annotations.proto: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, Google Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | syntax = "proto3"; 16 | 17 | package google.api; 18 | 19 | import "google/api/http.proto"; 20 | import "google/protobuf/descriptor.proto"; 21 | 22 | option go_package = "google.golang.org/genproto/googleapis/api/annotations;annotations"; 23 | option java_multiple_files = true; 24 | option java_outer_classname = "AnnotationsProto"; 25 | option java_package = "com.google.api"; 26 | option objc_class_prefix = "GAPI"; 27 | 28 | extend google.protobuf.MethodOptions { 29 | // See `HttpRule`. 30 | HttpRule http = 72295728; 31 | } 32 | -------------------------------------------------------------------------------- /doutok-course/basic-knowledge/kratos-intro/myproject/third_party/google/protobuf/empty.proto: -------------------------------------------------------------------------------- 1 | // Protocol Buffers - Google's data interchange format 2 | // Copyright 2008 Google Inc. All rights reserved. 3 | // https://developers.google.com/protocol-buffers/ 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions are 7 | // met: 8 | // 9 | // * Redistributions of source code must retain the above copyright 10 | // notice, this list of conditions and the following disclaimer. 11 | // * Redistributions in binary form must reproduce the above 12 | // copyright notice, this list of conditions and the following disclaimer 13 | // in the documentation and/or other materials provided with the 14 | // distribution. 15 | // * Neither the name of Google Inc. nor the names of its 16 | // contributors may be used to endorse or promote products derived from 17 | // this software without specific prior written permission. 18 | // 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | syntax = "proto3"; 32 | 33 | package google.protobuf; 34 | 35 | option csharp_namespace = "Google.Protobuf.WellKnownTypes"; 36 | option go_package = "google.golang.org/protobuf/types/known/emptypb"; 37 | option java_package = "com.google.protobuf"; 38 | option java_outer_classname = "EmptyProto"; 39 | option java_multiple_files = true; 40 | option objc_class_prefix = "GPB"; 41 | option cc_enable_arenas = true; 42 | 43 | // A generic empty message that you can re-use to avoid defining duplicated 44 | // empty messages in your APIs. A typical example is to use it as the request 45 | // or the response type of an API method. For instance: 46 | // 47 | // service Foo { 48 | // rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty); 49 | // } 50 | // 51 | // The JSON representation for `Empty` is empty JSON object `{}`. 52 | message Empty {} 53 | -------------------------------------------------------------------------------- /doutok-course/basic-knowledge/kratos-intro/myproject/third_party/google/protobuf/source_context.proto: -------------------------------------------------------------------------------- 1 | // Protocol Buffers - Google's data interchange format 2 | // Copyright 2008 Google Inc. All rights reserved. 3 | // https://developers.google.com/protocol-buffers/ 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions are 7 | // met: 8 | // 9 | // * Redistributions of source code must retain the above copyright 10 | // notice, this list of conditions and the following disclaimer. 11 | // * Redistributions in binary form must reproduce the above 12 | // copyright notice, this list of conditions and the following disclaimer 13 | // in the documentation and/or other materials provided with the 14 | // distribution. 15 | // * Neither the name of Google Inc. nor the names of its 16 | // contributors may be used to endorse or promote products derived from 17 | // this software without specific prior written permission. 18 | // 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | syntax = "proto3"; 32 | 33 | package google.protobuf; 34 | 35 | option csharp_namespace = "Google.Protobuf.WellKnownTypes"; 36 | option java_package = "com.google.protobuf"; 37 | option java_outer_classname = "SourceContextProto"; 38 | option java_multiple_files = true; 39 | option objc_class_prefix = "GPB"; 40 | option go_package = "google.golang.org/protobuf/types/known/sourcecontextpb"; 41 | 42 | // `SourceContext` represents information about the source of a 43 | // protobuf element, like the file in which it is defined. 44 | message SourceContext { 45 | // The path-qualified name of the .proto file that contained the associated 46 | // protobuf element. For example: `"google/protobuf/source_context.proto"`. 47 | string file_name = 1; 48 | } 49 | -------------------------------------------------------------------------------- /doutok-course/basic-knowledge/kratos-intro/myproject/third_party/openapi/v3/annotations.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Google LLC. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | syntax = "proto3"; 16 | 17 | package openapi.v3; 18 | 19 | import "openapi/v3/openapi.proto"; 20 | import "google/protobuf/descriptor.proto"; 21 | 22 | // This option lets the proto compiler generate Java code inside the package 23 | // name (see below) instead of inside an outer class. It creates a simpler 24 | // developer experience by reducing one-level of name nesting and be 25 | // consistent with most programming languages that don't support outer classes. 26 | option java_multiple_files = true; 27 | 28 | // The Java outer classname should be the filename in UpperCamelCase. This 29 | // class is only used to hold proto descriptor, so developers don't need to 30 | // work with it directly. 31 | option java_outer_classname = "AnnotationsProto"; 32 | 33 | // The Java package name must be proto package name with proper prefix. 34 | option java_package = "org.openapi_v3"; 35 | 36 | // A reasonable prefix for the Objective-C symbols generated from the package. 37 | // It should at a minimum be 3 characters long, all uppercase, and convention 38 | // is to use an abbreviation of the package name. Something short, but 39 | // hopefully unique enough to not conflict with things that may come along in 40 | // the future. 'GPB' is reserved for the protocol buffer implementation itself. 41 | option objc_class_prefix = "OAS"; 42 | 43 | // The Go package name. 44 | option go_package = "github.com/google/gnostic/openapiv3;openapi_v3"; 45 | 46 | extend google.protobuf.FileOptions { 47 | Document document = 1143; 48 | } 49 | 50 | extend google.protobuf.MethodOptions { 51 | Operation operation = 1143; 52 | } 53 | 54 | extend google.protobuf.MessageOptions { 55 | Schema schema = 1143; 56 | } 57 | 58 | extend google.protobuf.FieldOptions { 59 | Schema property = 1143; 60 | } -------------------------------------------------------------------------------- /doutok-course/basic-knowledge/kratos-intro/myproject/third_party/validate/README.md: -------------------------------------------------------------------------------- 1 | # protoc-gen-validate (PGV) 2 | 3 | * https://github.com/envoyproxy/protoc-gen-validate 4 | -------------------------------------------------------------------------------- /doutok-course/basic-knowledge/react-intro/App.css: -------------------------------------------------------------------------------- 1 | .app { 2 | max-width: 800px; 3 | margin: 0 auto; 4 | padding: 20px; 5 | font-family: Arial, sans-serif; 6 | } 7 | 8 | h1 { 9 | color: #333; 10 | text-align: center; 11 | } 12 | 13 | h2 { 14 | color: #555; 15 | } 16 | 17 | hr { 18 | margin: 30px 0; 19 | border: 0; 20 | height: 1px; 21 | background-color: #ddd; 22 | } 23 | 24 | /* 计数器样式 */ 25 | .counter { 26 | background-color: #f5f5f5; 27 | padding: 20px; 28 | border-radius: 5px; 29 | text-align: center; 30 | } 31 | 32 | .counter button { 33 | margin: 0 5px; 34 | padding: 5px 15px; 35 | background-color: #4caf50; 36 | color: white; 37 | border: none; 38 | border-radius: 3px; 39 | cursor: pointer; 40 | } 41 | 42 | .counter button:hover { 43 | background-color: #45a049; 44 | } 45 | 46 | /* 计时器样式 */ 47 | .timer { 48 | background-color: #e0f7fa; 49 | padding: 15px; 50 | text-align: center; 51 | font-size: 18px; 52 | border-radius: 5px; 53 | } 54 | 55 | /* 待办事项列表样式 */ 56 | .todo-list { 57 | background-color: #f9f9f9; 58 | padding: 20px; 59 | border-radius: 5px; 60 | } 61 | 62 | .add-todo { 63 | display: flex; 64 | margin-bottom: 15px; 65 | } 66 | 67 | .add-todo input { 68 | flex-grow: 1; 69 | padding: 8px; 70 | border: 1px solid #ddd; 71 | border-radius: 3px 0 0 3px; 72 | } 73 | 74 | .add-todo button { 75 | padding: 8px 15px; 76 | background-color: #2196f3; 77 | color: white; 78 | border: none; 79 | border-radius: 0 3px 3px 0; 80 | cursor: pointer; 81 | } 82 | 83 | .add-todo button:hover { 84 | background-color: #0b7dda; 85 | } 86 | 87 | ul { 88 | list-style-type: none; 89 | padding: 0; 90 | } 91 | 92 | li { 93 | display: flex; 94 | justify-content: space-between; 95 | align-items: center; 96 | padding: 10px; 97 | border-bottom: 1px solid #eee; 98 | } 99 | 100 | li:last-child { 101 | border-bottom: none; 102 | } 103 | 104 | li.completed span { 105 | text-decoration: line-through; 106 | color: #888; 107 | } 108 | 109 | li span { 110 | cursor: pointer; 111 | } 112 | 113 | li button { 114 | padding: 5px 10px; 115 | background-color: #f44336; 116 | color: white; 117 | border: none; 118 | border-radius: 3px; 119 | cursor: pointer; 120 | } 121 | 122 | li button:hover { 123 | background-color: #d32f2f; 124 | } -------------------------------------------------------------------------------- /doutok-course/basic-knowledge/react-intro/App.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from 'react'; 2 | import './App.css'; 3 | 4 | // 一个简单的计数器组件 5 | function Counter() { 6 | const [count, setCount] = useState(0); 7 | 8 | return ( 9 |
10 |

计数器: {count}

11 | 12 | 13 | 14 |
15 | ); 16 | } 17 | 18 | // 一个简单的待办事项组件 19 | function TodoList() { 20 | const [todos, setTodos] = useState([ 21 | { id: 1, text: '学习 React', completed: false }, 22 | { id: 2, text: '创建一个应用', completed: false }, 23 | { id: 3, text: '部署应用', completed: false } 24 | ]); 25 | const [newTodo, setNewTodo] = useState(''); 26 | 27 | const addTodo = () => { 28 | if (newTodo.trim() === '') return; 29 | setTodos([ 30 | ...todos, 31 | { 32 | id: Date.now(), 33 | text: newTodo, 34 | completed: false 35 | } 36 | ]); 37 | setNewTodo(''); 38 | }; 39 | 40 | const toggleTodo = (id) => { 41 | setTodos( 42 | todos.map(todo => 43 | todo.id === id ? { ...todo, completed: !todo.completed } : todo 44 | ) 45 | ); 46 | }; 47 | 48 | const deleteTodo = (id) => { 49 | setTodos(todos.filter(todo => todo.id !== id)); 50 | }; 51 | 52 | return ( 53 |
54 |

待办事项列表

55 |
56 | setNewTodo(e.target.value)} 60 | placeholder="添加新任务" 61 | /> 62 | 63 |
64 | 65 |
    66 | {todos.map(todo => ( 67 |
  • 68 | toggleTodo(todo.id)}>{todo.text} 69 | 70 |
  • 71 | ))} 72 |
73 |
74 | ); 75 | } 76 | 77 | // 使用 useEffect 的示例组件 78 | function Timer() { 79 | const [seconds, setSeconds] = useState(0); 80 | 81 | useEffect(() => { 82 | const interval = setInterval(() => { 83 | setSeconds(seconds => seconds + 1); 84 | }, 1000); 85 | 86 | // 清理函数 87 | return () => clearInterval(interval); 88 | }, []); 89 | 90 | return
计时器: {seconds} 秒
; 91 | } 92 | 93 | // 主应用组件 94 | function App() { 95 | return ( 96 |
97 |

React 基础示例

98 | 99 |
100 | 101 |
102 | 103 |
104 | ); 105 | } 106 | 107 | export default App; -------------------------------------------------------------------------------- /doutok-course/doutok-mono/readme.md: -------------------------------------------------------------------------------- 1 | 欢迎加入知识星球:[白泽说](https://wx.zsxq.com/group/51111852421224) 2 | 3 | 进阶课程录制中,敬请期待。 -------------------------------------------------------------------------------- /doutok-course/go.mod: -------------------------------------------------------------------------------- 1 | module doutok-course 2 | 3 | go 1.22 4 | 5 | require github.com/go-kratos/kratos/v2 v2.8.4 6 | 7 | require ( 8 | github.com/go-kratos/aegis v0.2.0 // indirect 9 | github.com/go-playground/form/v4 v4.2.0 // indirect 10 | github.com/golang/protobuf v1.5.4 // indirect 11 | github.com/google/uuid v1.4.0 // indirect 12 | github.com/gorilla/mux v1.8.1 // indirect 13 | github.com/kr/text v0.2.0 // indirect 14 | golang.org/x/sync v0.5.0 // indirect 15 | golang.org/x/sys v0.18.0 // indirect 16 | google.golang.org/genproto/googleapis/rpc v0.0.0-20240102182953-50ed04b92917 // indirect 17 | google.golang.org/grpc v1.61.1 // indirect 18 | google.golang.org/protobuf v1.33.0 // indirect 19 | gopkg.in/yaml.v3 v3.0.1 // indirect 20 | ) 21 | -------------------------------------------------------------------------------- /dragon/.gitignore: -------------------------------------------------------------------------------- 1 | log* -------------------------------------------------------------------------------- /dragon/basic.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type basic struct { 4 | maxLife int 5 | life int 6 | attack int 7 | defense int 8 | } 9 | 10 | func (b *basic) isAlive() bool { 11 | return b.life > 0 12 | } 13 | 14 | func (b *basic) attacked(attackPower int) int { 15 | if b.defense > attackPower { 16 | return 0 17 | } 18 | 19 | deduct := attackPower - b.defense 20 | b.life -= deduct 21 | if b.life < 0 { 22 | b.life = 0 23 | } 24 | return deduct 25 | } 26 | -------------------------------------------------------------------------------- /dragon/config.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/mum4k/termdash/cell" 5 | "github.com/mum4k/termdash/linestyle" 6 | "github.com/mum4k/termdash/widgets/text" 7 | ) 8 | 9 | const ( 10 | DEBUG = false 11 | 12 | // TotalBorderStyle 游戏区域边界样式 13 | TotalBorderStyle = linestyle.Double 14 | // TotalBorderColor 游戏区域边界颜色 15 | TotalBorderColor = cell.ColorYellow 16 | // TotalBorderTitle 游戏区域边界标题 17 | TotalBorderTitle = "按Ctrl + W退出" 18 | 19 | // OperateAreaBorderStyle 操作提示区边界样式 20 | OperateAreaBorderStyle = linestyle.Round 21 | // OperateAreaBorderColor 操作提示区边界颜色 22 | OperateAreaBorderColor = cell.ColorYellow 23 | // OperateAreaBorderTitle 操作提示区边界标题 24 | OperateAreaBorderTitle = "操作提示" 25 | 26 | // InputAreaBorderStyle 输入区边界样式 27 | InputAreaBorderStyle = linestyle.Round 28 | // InputAreaBorderColor 输入区边界颜色 29 | InputAreaBorderColor = cell.ColorYellow 30 | // InputAreaBorderTitle 输入区边界标题 31 | InputAreaBorderTitle = "按回车完成输入" 32 | 33 | // ValuesAreaBorderStyle 数值区边界样式 34 | ValuesAreaBorderStyle = linestyle.Round 35 | // ValuesAreaBorderColor 数值区边界颜色 36 | ValuesAreaBorderColor = cell.ColorYellow 37 | // ValuesAreaBorderTitle 数值区边界标题 38 | ValuesAreaBorderTitle = "龙の数值" 39 | 40 | // HistoryAreaBorderStyle 历史记录区边界样式 41 | HistoryAreaBorderStyle = linestyle.Round 42 | // HistoryAreaBorderColor 历史记录区边界颜色 43 | HistoryAreaBorderColor = cell.ColorYellow 44 | // HistoryAreaBorderTitle 历史记录区边界标题 45 | HistoryAreaBorderTitle = "龙生经历" 46 | 47 | // RankAreaBorderStyle 排行榜区边界样式 48 | RankAreaBorderStyle = linestyle.Round 49 | // RankAreaBorderColor 排行榜区边界颜色 50 | RankAreaBorderColor = cell.ColorYellow 51 | // RankAreaBorderTitle 排行榜区边界标题 52 | RankAreaBorderTitle = "龙の排行榜 TOP 10" 53 | ) 54 | 55 | var ( 56 | TextOptionBold = text.WriteCellOpts(cell.Bold()) 57 | TextOptionUnderline = text.WriteCellOpts(cell.Underline()) 58 | TextOptionItalic = text.WriteCellOpts(cell.Italic()) 59 | TextOptionBlink = text.WriteCellOpts(cell.Blink()) 60 | TextOptionInverse = text.WriteCellOpts(cell.Inverse()) 61 | TextOptionStrikethrough = text.WriteCellOpts(cell.Strikethrough()) 62 | 63 | TextOptionRed = text.WriteCellOpts(cell.FgColor(cell.ColorRed)) 64 | TextOptionBlue = text.WriteCellOpts(cell.FgColor(cell.ColorBlue)) 65 | TextOptionCyan = text.WriteCellOpts(cell.FgColor(cell.ColorCyan)) 66 | TextOptionGray = text.WriteCellOpts(cell.FgColor(cell.ColorGray)) 67 | TextOptionGreen = text.WriteCellOpts(cell.FgColor(cell.ColorGreen)) 68 | TextOptionMagenta = text.WriteCellOpts(cell.FgColor(cell.ColorMagenta)) 69 | TextOptionYellow = text.WriteCellOpts(cell.FgColor(cell.ColorYellow)) 70 | TextOptionWhite = text.WriteCellOpts(cell.FgColor(cell.ColorWhite)) 71 | TextOptionBlack = text.WriteCellOpts(cell.FgColor(cell.ColorBlack)) 72 | ) 73 | -------------------------------------------------------------------------------- /dragon/dragon.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BaiZe1998/go-learning/ff9bb158730be78a5a6f327d9525c9f21876fb7c/dragon/dragon.gif -------------------------------------------------------------------------------- /dragon/dragon.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | // Dragon 龙的结构体 8 | type Dragon struct { 9 | basic *basic 10 | ID int 11 | Name string 12 | Experience int 13 | ExperienceStage int 14 | Remaining int 15 | MaxRemaining int 16 | } 17 | 18 | func (d *Dragon) decreaseRemaining() { 19 | d.Remaining-- 20 | } 21 | 22 | // Fight 与 NPC 战斗 23 | func (d *Dragon) Fight(n *NPC) { 24 | // 根本打不过直接润 25 | if d.basic.attack <= n.basic.defense { 26 | p.addHistory(newHistoryInfo(fmt.Sprintf("绝无可能击败的敌人%s\n", n.Name))) 27 | deduct := d.basic.attacked(n.basic.attack) 28 | if d.basic.isAlive() { 29 | p.addHistory(newHistoryInfo(fmt.Sprintf("逃跑成功 耗费%d点血量\n", deduct))) 30 | } else { 31 | p.addHistory(newHistoryInfo("逃跑失败\n")) 32 | } 33 | return 34 | } 35 | 36 | for d.basic.isAlive() { 37 | n.basic.attacked(d.basic.attack) 38 | if !n.basic.isAlive() { 39 | p.addHistory(newHistoryInfo("你打败了")) 40 | p.addHistory(newHistoryInfo(n.Name, TextOptionUnderline)) 41 | appendExperience(d, n.Experience) 42 | return 43 | } 44 | d.basic.attacked(n.basic.attack) 45 | } 46 | 47 | p.addHistory(newHistoryInfo("你被")) 48 | p.addHistory(newHistoryInfo(n.Name, TextOptionUnderline)) 49 | p.addHistoryLn(newHistoryInfo("打败了")) 50 | appendExperience(d, -d.Experience/2) 51 | randomDecreaseState(d) 52 | } 53 | 54 | // Process 处理偶发事件 55 | func (d *Dragon) Process(e *Event) { 56 | p.addHistoryLn(newHistoryInfo(e.Name)) 57 | d.basic.attack += e.Attack 58 | d.basic.defense += e.Defense 59 | appendLife(d, e.Life) 60 | appendExperience(d, e.Experience) 61 | } 62 | -------------------------------------------------------------------------------- /dragon/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/BaiZe1998/go-learning/dragon 2 | 3 | go 1.21.3 4 | 5 | require github.com/mum4k/termdash v0.18.0 6 | 7 | require ( 8 | github.com/gdamore/encoding v1.0.0 // indirect 9 | github.com/gdamore/tcell/v2 v2.5.4 // indirect 10 | github.com/lucasb-eyer/go-colorful v1.2.0 // indirect 11 | github.com/mattn/go-runewidth v0.0.15 // indirect 12 | github.com/mattn/go-sqlite3 v1.14.19 // indirect 13 | github.com/rivo/uniseg v0.4.4 // indirect 14 | golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f // indirect 15 | golang.org/x/term v0.0.0-20220526004731-065cf7ba2467 // indirect 16 | golang.org/x/text v0.5.0 // indirect 17 | ) 18 | -------------------------------------------------------------------------------- /dragon/logger.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | "os" 6 | ) 7 | 8 | var logger = initLogger() 9 | 10 | func initLogger() *log.Logger { 11 | if !DEBUG { 12 | return nil 13 | } 14 | 15 | f, err := os.Create("log.txt") 16 | if err != nil { 17 | panic(err) 18 | } 19 | logger := log.New(f, "dragon: ", log.LstdFlags) 20 | return logger 21 | } 22 | 23 | func loggerInfo(format string, v ...interface{}) { 24 | if logger != nil { 25 | logger.Printf(format, v...) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /dragon/rank.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BaiZe1998/go-learning/ff9bb158730be78a5a6f327d9525c9f21876fb7c/dragon/rank.db -------------------------------------------------------------------------------- /eino_assistant/.env: -------------------------------------------------------------------------------- 1 | # ark model: https://console.volcengine.com/ark 2 | # 必填, 3 | # 火山云方舟 ChatModel 的 Endpoint ID 4 | export ARK_CHAT_MODEL="doubao-pro-32k-241215" # 这个替换成你自己申请的 5 | # 火山云方舟 向量化模型的 Endpoint ID 6 | export ARK_EMBEDDING_MODEL="doubao-embedding-large-text-240915" # 这个替换成你自己申请的 7 | # 火山云方舟的 API Key 8 | # export ARK_API_KEY="" 这个替换成你自己申请的 9 | export ARK_API_BASE_URL="https://ark.cn-beijing.volces.com/api/v3" # 这个替换成你自己申请的 10 | 11 | # apmplus: https://console.volcengine.com/apmplus-server 12 | # 下面必填环境变量如果为空,则不开启 apmplus callback 13 | # APMPlus 的 App Key,必填 14 | export APMPLUS_APP_KEY="" 15 | # APMPlus 的 Region,选填,不填写时,默认是 cn-beijing 16 | export APMPLUS_REGION="" 17 | 18 | # langfuse: https://cloud.langfuse.com/ 19 | # 下面两个环境变量如果为空,则不开启 langfuse callback 20 | # Langfuse Project 的 Public Key 21 | export LANGFUSE_PUBLIC_KEY="" 22 | # Langfuse Project 的 Secret Key。 注意,Secret Key 仅可在被创建时查看一次 23 | export LANGFUSE_SECRET_KEY="" 24 | 25 | # Redis Server 的地址,不填写时,默认是 localhost:6379 26 | export REDIS_ADDR= 27 | -------------------------------------------------------------------------------- /eino_assistant/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1.22 as builder 2 | 3 | WORKDIR /build 4 | 5 | COPY go.mod ./ 6 | COPY go.sum ./ 7 | RUN go mod download 8 | 9 | COPY . . 10 | 11 | RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o /out/main ./cmd/einoagent/*.go 12 | 13 | 14 | FROM alpine:3.21 15 | 16 | WORKDIR / 17 | 18 | RUN apk --no-cache add ca-certificates redis \ 19 | && update-ca-certificates 20 | 21 | COPY .env /.env 22 | COPY data /data 23 | COPY --from=builder /out/main /main 24 | 25 | EXPOSE 8080 26 | 27 | CMD [ "/main" ] -------------------------------------------------------------------------------- /eino_assistant/cmd/knowledgeindexing/eino-docs/_index.md: -------------------------------------------------------------------------------- 1 | 2 | > Eino 发音:美 / 'aino /,近似音: i know,有希望应用程序达到 "i know" 的愿景 3 | 4 | # Eino 是什么 5 | 6 | > 💡 7 | > Go AI 集成组件的研发框架。 8 | 9 | Eino 旨在提供 Golang 语言的 AI 应用开发框架。 Eino 参考了开源社区中诸多优秀的 AI 应用开发框架,例如 LangChain、LangGraph、LlamaIndex 等,提供了更符合 Golang 编程习惯的 AI 应用开发框架。 10 | 11 | Eino 提供了丰富的辅助 AI 应用开发的**原子组件**、**集成组件**、**组件编排**、**切面扩展**等能力,可以帮助开发者更加简单便捷地开发出架构清晰、易维护、高可用的 AI 应用。 12 | 13 | 以 React Agent 为例: 14 | 15 | - 提供了 ChatModel、ToolNode、PromptTemplate 等常用组件,并且业务可定制、可扩展。 16 | - 可基于现有组件进行灵活编排,产生集成组件,在业务服务中使用。 17 | 18 | ![](/img/eino/react_agent_graph.png) 19 | 20 | # Eino 组件 21 | 22 | > Eino 的其中一个目标是:搜集和完善 AI 应用场景下的组件体系,让业务可轻松找到一些通用的 AI 组件,方便业务的迭代。 23 | 24 | Eino 会围绕 AI 应用的场景,提供具有比较好的抽象的组件,并围绕该抽象提供一些常用的实现。 25 | 26 | - Eino 组件的抽象定义在:[eino/components](https://github.com/cloudwego/eino/tree/main/components) 27 | - Eino 组件的实现在:[eino-ext/components](https://github.com/cloudwego/eino-ext/tree/main/components) 28 | 29 | # Eino 应用场景 30 | 31 | 得益于 Eino 轻量化和内场亲和属性,用户只需短短数行代码就能给你的存量微服务引入强力的大模型能力,让传统微服务进化出 AI 基因。 32 | 33 | 可能大家听到【Graph 编排】这个词时,第一反应就是将整个应用接口的实现逻辑进行分段、分层的逻辑拆分,并将其转换成可编排的 Node。 这个过程中遇到的最大问题就是**长距离的上下文传递(跨 Node 节点的变量传递)**问题,无论是使用 Graph/Chain 的 State,还是使用 Options 透传,整个编排过程都极其复杂,远没有直接进行函数调用简单。 34 | 35 | 基于当前的 Graph 编排能力,适合编排的场景具有如下几个特点: 36 | 37 | - 整体是围绕模型的语义处理相关能力。这里的语义不限模态 38 | - 编排产物中有极少数节点是 Session 相关的。整体来看,绝大部分节点没有类似用户/设备等不可枚举地业务实体粒度的处理逻辑 39 | 40 | - 无论是通过 Graph/Chain 的 State、还是通过 CallOptions,对于读写或透传用户/设备粒度的信息的方式,均不简便 41 | - 需要公共的切面能力,基于此建设观测、限流、评测等横向治理能力 42 | 43 | 编排的意义是什么: 把长距离的编排元素上下文以固定的范式进行聚合控制和呈现。 44 | 45 | **整体来说,“Graph 编排”适用的场景是: 业务定制的 AI 集成组件。 ****即把 AI 相关的原子能力,进行灵活编排****,提供简单易用的场景化的 AI 组件。 并且该 AI 组件中,具有统一且完整的横向治理能力。** 46 | 47 | - 推荐的使用方式 48 | 49 | ![](/img/eino/recommend_way_of_handler.png) 50 | 51 | - 挑战较大的方式 -- 【业务全流程的节点编排】 52 | - Biz Handler 一般重业务逻辑,轻数据流,比较适合函数栈调用的方式进行开发 53 | - 如果采用图编排的方式进行逻辑划分与组合,会增大业务逻辑开发的难度 54 | 55 | ![](/img/eino/big_challenge_graph.png) 56 | -------------------------------------------------------------------------------- /eino_assistant/cmd/knowledgeindexing/eino-docs/big_data.md: -------------------------------------------------------------------------------- 1 | # 大数据 2 | 大数据(Big Data)是指规模庞大、结构复杂且无法通过传统数据处理工具在合理时间内进行有效捕捉、管理和处理的数据集合。其核心价值在于通过专业化分析挖掘数据中蕴含的信息,从而提升决策力、优化流程并创造新价值。 -------------------------------------------------------------------------------- /eino_assistant/cmd/knowledgeindexing/eino-docs/deeplearning.md: -------------------------------------------------------------------------------- 1 | # 神经网络 2 | 神经网络是深度学习的核心 3 | -------------------------------------------------------------------------------- /eino_assistant/data/memory/ce10d8a8-a866-474f-919a-c1ef094c8236.jsonl: -------------------------------------------------------------------------------- 1 | {"role":"user","content":"你好,可以帮我介绍一下 Eino 的优势吗? Thanks♪(・ω・)ノ"} 2 | {"role":"assistant","content":"Eino具有以下优势:\n- **借鉴优秀框架且符合Go语言习惯**:Eino参考了开源社区中诸多优秀的AI应用开发框架,例如LangChain、LangGraph、LlamaIndex 等,提供了更符合Golang编程习惯的AI应用开发框架。 \n- **编排优势明显**:以组件为第一编排对象,同时提供具有极强扩展能力的Lambda节点作为编排对象,能够实现快速上手和定制扩展的双优势。并且编排过程中强化了 “数据流” ,callbacks 提供了观测和调试的基础能力。 \n- **助力项目精准定义与成本控制**:其AI处理功能可帮助用户准确地定义项目,进而降低部署成本。\n- **响应灵活**:能快速响应不断变化的客户或项目需求,让用户对所做更改充满信心。 \n- **支持团队协作**:支持团队成员在单个项目上进行协作,并可通过编辑历史和项目状态进行管理。 \n\n你可以点击[此处](https://www.cloudwego.io/zh/docs/eino/overview/)查看更多相关信息。 ","response_meta":{"finish_reason":"stop","usage":{"prompt_tokens":1973,"completion_tokens":234,"total_tokens":2207}}} 3 | {"role":"user","content":"Eino 的项目地址是什么?官方文档在哪里?可以帮我打开下吗"} 4 | {"role":"assistant","content":"Eino 的官方文档地址为:https://www.cloudwego.io/zh/docs/eino/ ,我已经帮你打开了该文档链接。如果你需要了解 Eino 项目地址等更多信息,可以在文档中进一步查找。如果你还有其他需求,请随时告诉我。 ","response_meta":{"finish_reason":"stop","usage":{"prompt_tokens":1102,"completion_tokens":59,"total_tokens":1161}}} 5 | {"role":"user","content":"在网上查一下 cloudwego 有什么新的项目发布吗?"} 6 | {"role":"assistant","content":"为你查询到CloudWeGo的相关信息如下:\n- CloudWeGo是一套由字节跳动开源的、可快速构建企业级云原生微服务架构的中间件集合。该项目共同的特点是高性能、高扩展性、高可靠,专注于微服务通信与治理。\n- 第一批开源了四个项目:Kitex、Netpoll、Thriftgo和netpoll-http2, 以RPC框架Kitex和网络库Netpoll为主。最近又发布了面向 AI 应用场景的开发框架 Eino,致力于让开发者轻松构建高质量的 AI 应用。\n\n更多信息可查看[CloudWeGo官网](https://www.cloudwego.io/)。","response_meta":{"finish_reason":"stop","usage":{"prompt_tokens":2377,"completion_tokens":186,"total_tokens":2563}}} 7 | {"role":"user","content":"帮我定一个大后天晚上 19:00 的 todo,要把 Eino 的 example 通读一遍"} 8 | {"role":"assistant","content":"已成功为你添加一个待办事项:在2025-1-17 19:00,把 Eino 的 example 通读一遍。","response_meta":{"finish_reason":"stop","usage":{"prompt_tokens":1083,"completion_tokens":36,"total_tokens":1119}}} 9 | -------------------------------------------------------------------------------- /eino_assistant/data/redis/dump.rdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BaiZe1998/go-learning/ff9bb158730be78a5a6f327d9525c9f21876fb7c/eino_assistant/data/redis/dump.rdb -------------------------------------------------------------------------------- /eino_assistant/data/task/tasks.jsonl: -------------------------------------------------------------------------------- 1 | {"id":"a13f1db5-0a00-4a9f-8151-52fdc097b11a","title":"阅读 Eino example","content":"把 Eino 的 example 通读一遍","completed":false,"deadline":"2025-3-01 19:00:00","is_deleted":false,"created_at":"2025-02-25T14:45:13+08:00"} 2 | -------------------------------------------------------------------------------- /eino_assistant/docker-compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | redis-stack: 3 | image: redis/redis-stack:latest 4 | container_name: redis-stack 5 | ports: 6 | - "6379:6379" # Redis port 7 | - "8001:8001" # RedisInsight port 8 | volumes: 9 | - ./data/redis:/data 10 | environment: 11 | - REDIS_ARGS=--dir /data --appendonly no --save 1800 1 12 | restart: unless-stopped 13 | healthcheck: 14 | test: [ "CMD", "redis-cli", "ping" ] 15 | interval: 10s 16 | timeout: 5s 17 | retries: 3 18 | -------------------------------------------------------------------------------- /eino_assistant/eino/knowledgeindexing/embedding.go: -------------------------------------------------------------------------------- 1 | package knowledgeindexing 2 | 3 | import ( 4 | "context" 5 | "os" 6 | 7 | "github.com/cloudwego/eino-ext/components/embedding/ark" 8 | "github.com/cloudwego/eino/components/embedding" 9 | ) 10 | 11 | func newEmbedding(ctx context.Context) (eb embedding.Embedder, err error) { 12 | // TODO Modify component configuration here. 13 | config := &ark.EmbeddingConfig{ 14 | BaseURL: "https://ark.cn-beijing.volces.com/api/v3", 15 | APIKey: os.Getenv("ARK_API_KEY"), 16 | Model: os.Getenv("ARK_EMBEDDING_MODEL"), 17 | } 18 | eb, err = ark.NewEmbedder(ctx, config) 19 | if err != nil { 20 | return nil, err 21 | } 22 | return eb, nil 23 | } 24 | -------------------------------------------------------------------------------- /eino_assistant/eino/knowledgeindexing/indexer.go: -------------------------------------------------------------------------------- 1 | package knowledgeindexing 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | "fmt" 7 | "log" 8 | "os" 9 | 10 | "github.com/cloudwego/eino-ext/components/indexer/redis" 11 | "github.com/cloudwego/eino/components/indexer" 12 | "github.com/cloudwego/eino/schema" 13 | "github.com/google/uuid" 14 | redisCli "github.com/redis/go-redis/v9" 15 | 16 | redispkg "eino_assistant/pkg/redis" 17 | ) 18 | 19 | func init() { 20 | err := redispkg.Init() 21 | if err != nil { 22 | log.Fatalf("failed to init redis index: %v", err) 23 | } 24 | } 25 | 26 | // newIndexer component initialization function of node 'RedisIndexer' in graph 'KnowledgeIndexing' 27 | func newIndexer(ctx context.Context) (idr indexer.Indexer, err error) { 28 | // TODO Modify component configuration here. 29 | redisAddr := os.Getenv("REDIS_ADDR") 30 | redisClient := redisCli.NewClient(&redisCli.Options{ 31 | Addr: redisAddr, 32 | Protocol: 2, 33 | }) 34 | 35 | config := &redis.IndexerConfig{ 36 | Client: redisClient, 37 | KeyPrefix: redispkg.RedisPrefix, 38 | BatchSize: 1, 39 | DocumentToHashes: func(ctx context.Context, doc *schema.Document) (*redis.Hashes, error) { 40 | if doc.ID == "" { 41 | doc.ID = uuid.New().String() 42 | } 43 | key := doc.ID 44 | 45 | metadataBytes, err := json.Marshal(doc.MetaData) 46 | if err != nil { 47 | return nil, fmt.Errorf("failed to marshal metadata: %w", err) 48 | } 49 | 50 | return &redis.Hashes{ 51 | Key: key, 52 | Field2Value: map[string]redis.FieldValue{ 53 | redispkg.ContentField: {Value: doc.Content, EmbedKey: redispkg.VectorField}, 54 | redispkg.MetadataField: {Value: metadataBytes}, 55 | }, 56 | }, nil 57 | }, 58 | } 59 | embeddingIns11, err := newEmbedding(ctx) 60 | if err != nil { 61 | return nil, err 62 | } 63 | config.Embedding = embeddingIns11 64 | idr, err = redis.NewIndexer(ctx, config) 65 | if err != nil { 66 | return nil, err 67 | } 68 | return idr, nil 69 | } 70 | -------------------------------------------------------------------------------- /eino_assistant/eino/knowledgeindexing/loader.go: -------------------------------------------------------------------------------- 1 | package knowledgeindexing 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/cloudwego/eino-ext/components/document/loader/file" 7 | "github.com/cloudwego/eino/components/document" 8 | ) 9 | 10 | // newLoader component initialization function of node 'FileLoader' in graph 'KnowledgeIndexing' 11 | func newLoader(ctx context.Context) (ldr document.Loader, err error) { 12 | // TODO Modify component configuration here. 13 | config := &file.FileLoaderConfig{} 14 | ldr, err = file.NewFileLoader(ctx, config) 15 | if err != nil { 16 | return nil, err 17 | } 18 | return ldr, nil 19 | } 20 | -------------------------------------------------------------------------------- /eino_assistant/eino/knowledgeindexing/orchestration.go: -------------------------------------------------------------------------------- 1 | package knowledgeindexing 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/cloudwego/eino/components/document" 7 | "github.com/cloudwego/eino/compose" 8 | ) 9 | 10 | func BuildKnowledgeIndexing(ctx context.Context) (r compose.Runnable[document.Source, []string], err error) { 11 | const ( 12 | FileLoader = "FileLoader" 13 | MarkdownSplitter = "MarkdownSplitter" 14 | RedisIndexer = "RedisIndexer" 15 | ) 16 | g := compose.NewGraph[document.Source, []string]() 17 | fileLoaderKeyOfLoader, err := newLoader(ctx) 18 | if err != nil { 19 | return nil, err 20 | } 21 | _ = g.AddLoaderNode(FileLoader, fileLoaderKeyOfLoader) 22 | markdownSplitterKeyOfDocumentTransformer, err := newDocumentTransformer(ctx) 23 | if err != nil { 24 | return nil, err 25 | } 26 | _ = g.AddDocumentTransformerNode(MarkdownSplitter, markdownSplitterKeyOfDocumentTransformer) 27 | redisIndexerKeyOfIndexer, err := newIndexer(ctx) 28 | if err != nil { 29 | return nil, err 30 | } 31 | _ = g.AddIndexerNode(RedisIndexer, redisIndexerKeyOfIndexer) 32 | _ = g.AddEdge(compose.START, FileLoader) 33 | _ = g.AddEdge(RedisIndexer, compose.END) 34 | _ = g.AddEdge(FileLoader, MarkdownSplitter) 35 | _ = g.AddEdge(MarkdownSplitter, RedisIndexer) 36 | r, err = g.Compile(ctx, compose.WithGraphName("KnowledgeIndexing"), compose.WithNodeTriggerMode(compose.AllPredecessor)) 37 | if err != nil { 38 | return nil, err 39 | } 40 | return r, err 41 | } 42 | -------------------------------------------------------------------------------- /eino_assistant/eino/knowledgeindexing/transformer.go: -------------------------------------------------------------------------------- 1 | package knowledgeindexing 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/cloudwego/eino-ext/components/document/transformer/splitter/markdown" 7 | "github.com/cloudwego/eino/components/document" 8 | ) 9 | 10 | // newDocumentTransformer component initialization function of node 'MarkdownSplitter' in graph 'KnowledgeIndexing' 11 | func newDocumentTransformer(ctx context.Context) (tfr document.Transformer, err error) { 12 | // TODO Modify component configuration here. 13 | config := &markdown.HeaderConfig{ 14 | Headers: map[string]string{ 15 | "#": "title", 16 | }, 17 | TrimHeaders: false} 18 | tfr, err = markdown.NewHeaderSplitter(ctx, config) 19 | if err != nil { 20 | return nil, err 21 | } 22 | return tfr, nil 23 | } 24 | -------------------------------------------------------------------------------- /eino_assistant/eino/rag/cmd/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "context" 6 | "flag" 7 | "fmt" 8 | "os" 9 | "strings" 10 | 11 | "eino_assistant/eino/rag" 12 | "eino_assistant/pkg/env" 13 | ) 14 | 15 | func main() { 16 | // 定义命令行参数 17 | useRedis := flag.Bool("redis", true, "是否使用Redis进行检索增强") 18 | topK := flag.Int("topk", 3, "检索的文档数量") 19 | 20 | flag.Parse() 21 | 22 | // 检查环境变量 23 | env.MustHasEnvs("ARK_API_KEY") 24 | 25 | // 构建RAG系统 26 | ctx := context.Background() 27 | ragSystem, err := rag.BuildRAG(ctx, *useRedis, *topK) 28 | if err != nil { 29 | fmt.Fprintf(os.Stderr, "构建RAG系统失败: %v\n", err) 30 | os.Exit(1) 31 | } 32 | 33 | // 显示启动信息 34 | if *useRedis { 35 | fmt.Println("启动RAG系统 (使用Redis检索)") 36 | } else { 37 | fmt.Println("启动RAG系统 (不使用检索)") 38 | } 39 | fmt.Println("输入问题或输入'exit'退出") 40 | 41 | // 创建输入扫描器 42 | scanner := bufio.NewScanner(os.Stdin) 43 | 44 | // 主循环 45 | for { 46 | fmt.Print("\n问题> ") 47 | 48 | // 读取用户输入 49 | if !scanner.Scan() { 50 | break 51 | } 52 | 53 | input := strings.TrimSpace(scanner.Text()) 54 | if input == "" { 55 | continue 56 | } 57 | 58 | // 检查退出命令 59 | if strings.ToLower(input) == "exit" { 60 | break 61 | } 62 | 63 | // 处理问题 64 | answer, err := ragSystem.Answer(ctx, input) 65 | if err != nil { 66 | fmt.Fprintf(os.Stderr, "处理问题时出错: %v\n", err) 67 | continue 68 | } 69 | 70 | // 显示回答 71 | fmt.Println("\n回答:") 72 | fmt.Println(answer) 73 | } 74 | 75 | if err := scanner.Err(); err != nil { 76 | fmt.Fprintf(os.Stderr, "读取输入时出错: %v\n", err) 77 | } 78 | 79 | fmt.Println("再见!") 80 | } 81 | -------------------------------------------------------------------------------- /eino_assistant/eino/rag/cmd/rag_cli: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BaiZe1998/go-learning/ff9bb158730be78a5a6f327d9525c9f21876fb7c/eino_assistant/eino/rag/cmd/rag_cli -------------------------------------------------------------------------------- /eino_assistant/go.mod: -------------------------------------------------------------------------------- 1 | module eino_assistant 2 | 3 | go 1.22.10 4 | 5 | require ( 6 | github.com/cloudwego/eino v0.3.27 7 | github.com/cloudwego/eino-ext/components/document/loader/file v0.0.0-20250429121045-a2545a66f5cf 8 | github.com/cloudwego/eino-ext/components/document/transformer/splitter/markdown v0.0.0-20250429121045-a2545a66f5cf 9 | github.com/cloudwego/eino-ext/components/embedding/ark v0.0.0-20250429121045-a2545a66f5cf 10 | github.com/cloudwego/eino-ext/components/indexer/redis v0.0.0-20250429121045-a2545a66f5cf 11 | ) 12 | 13 | require ( 14 | github.com/bytedance/sonic v1.13.2 // indirect 15 | github.com/bytedance/sonic/loader v0.2.4 // indirect 16 | github.com/cespare/xxhash/v2 v2.2.0 // indirect 17 | github.com/cloudwego/base64x v0.1.5 // indirect 18 | github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect 19 | github.com/dustin/go-humanize v1.0.1 // indirect 20 | github.com/getkin/kin-openapi v0.118.0 // indirect 21 | github.com/go-openapi/jsonpointer v0.19.5 // indirect 22 | github.com/go-openapi/swag v0.19.5 // indirect 23 | github.com/google/uuid v1.3.0 // indirect 24 | github.com/goph/emperror v0.17.2 // indirect 25 | github.com/invopop/yaml v0.1.0 // indirect 26 | github.com/jmespath/go-jmespath v0.4.0 // indirect 27 | github.com/josharian/intern v1.0.0 // indirect 28 | github.com/json-iterator/go v1.1.12 // indirect 29 | github.com/klauspost/cpuid/v2 v2.0.9 // indirect 30 | github.com/mailru/easyjson v0.7.7 // indirect 31 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 32 | github.com/modern-go/reflect2 v1.0.2 // indirect 33 | github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect 34 | github.com/nikolalohinski/gonja v1.5.3 // indirect 35 | github.com/pelletier/go-toml/v2 v2.0.9 // indirect 36 | github.com/perimeterx/marshmallow v1.1.4 // indirect 37 | github.com/pkg/errors v0.9.1 // indirect 38 | github.com/redis/go-redis/v9 v9.7.0 // indirect 39 | github.com/sirupsen/logrus v1.9.3 // indirect 40 | github.com/slongfield/pyfmt v0.0.0-20220222012616-ea85ff4c361f // indirect 41 | github.com/twitchyliquid64/golang-asm v0.15.1 // indirect 42 | github.com/volcengine/volc-sdk-golang v1.0.23 // indirect 43 | github.com/volcengine/volcengine-go-sdk v1.0.181 // indirect 44 | github.com/yargevad/filepathx v1.0.0 // indirect 45 | golang.org/x/arch v0.11.0 // indirect 46 | golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 // indirect 47 | golang.org/x/sys v0.28.0 // indirect 48 | gopkg.in/yaml.v2 v2.4.0 // indirect 49 | gopkg.in/yaml.v3 v3.0.1 // indirect 50 | ) 51 | -------------------------------------------------------------------------------- /eino_assistant/pkg/env/env.go: -------------------------------------------------------------------------------- 1 | package env 2 | 3 | import ( 4 | "log" 5 | "os" 6 | ) 7 | 8 | // func init() { 9 | // err := godotenv.Load() 10 | // if err != nil { 11 | // log.Fatalf("❌ [ERROR] Error loading .env file: %v", err) 12 | // } 13 | 14 | // } 15 | 16 | func MustHasEnvs(envs ...string) { 17 | for _, env := range envs { 18 | if os.Getenv(env) == "" { 19 | log.Fatalf("❌ [ERROR] env [%s] is required, but is not set now, please check your .env file", env) 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /eino_assistant/readme.md: -------------------------------------------------------------------------------- 1 | 这个案例中,大部分代码取自 Eino 官方案例库:https://github.com/cloudwego/eino-examples 2 | 在此基础上进行了补充和文档的完善。 3 | 4 | 在运行案例之前,先确保: 5 | 1. 执行 docker-compose up -d 确保 redis 启动成功,可以查看:http://127.0.0.1:8001/redis-stack/browser 6 | 2. 执行 source .env 确保环境变量设置正确 -------------------------------------------------------------------------------- /generics/main.go: -------------------------------------------------------------------------------- 1 | // 一个简单的泛型示例 2 | package main 3 | 4 | import "fmt" 5 | 6 | type iface1 interface { 7 | Foo() 8 | } 9 | 10 | type iface2[T iface1] interface { 11 | Get() T 12 | } 13 | 14 | type s1 struct{} 15 | 16 | func (s *s1) Foo() { 17 | fmt.Println("this is s1.Foo") 18 | } 19 | 20 | type S2 struct { 21 | s1 *s1 22 | } 23 | 24 | func (s *S2) Get() *s1 { 25 | return s.s1 26 | } 27 | 28 | func NewS2() *S2 { 29 | return &S2{ 30 | s1: &s1{}, 31 | } 32 | } 33 | 34 | func test[T iface1](obj iface2[T]) { 35 | obj.Get().Foo() 36 | } 37 | 38 | func main() { 39 | obj := NewS2() 40 | test[*s1](obj) 41 | } 42 | -------------------------------------------------------------------------------- /kit/i18n/Makefile: -------------------------------------------------------------------------------- 1 | i18n-extract: 2 | goi18n extract 3 | goi18n merge active.*.toml 4 | 5 | i18n-merge: 6 | goi18n merge active.*.toml translate.*.toml 7 | -------------------------------------------------------------------------------- /kit/i18n/active.en.toml: -------------------------------------------------------------------------------- 1 | PersonCatsDII = "{{.Name}} hasfhudhfsa {{.Count}} cats." 2 | user_not_found = "User not found {{.UserID}}" 3 | -------------------------------------------------------------------------------- /kit/i18n/active.zh.toml: -------------------------------------------------------------------------------- 1 | [PersonCatsDII] 2 | hash = "sha1-60f5e91090a4d4b765315e11ebe5ebae7a927620" 3 | other = "{{.Name}} 有很多 {{.Count}} 猫." 4 | 5 | [user_not_found] 6 | hash = "sha1-9d093a4291e6fde9d899c9d50d6171c54859a5ec" 7 | other = "用户不存在 {{.UserID}}" 8 | -------------------------------------------------------------------------------- /kit/i18n/go.mod: -------------------------------------------------------------------------------- 1 | module i18n 2 | 3 | go 1.22.2 4 | 5 | require ( 6 | github.com/BurntSushi/toml v1.3.2 7 | github.com/nicksnyder/go-i18n/v2 v2.4.0 8 | golang.org/x/text v0.14.0 9 | ) 10 | -------------------------------------------------------------------------------- /kit/i18n/go.sum: -------------------------------------------------------------------------------- 1 | github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= 2 | github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= 3 | github.com/nicksnyder/go-i18n/v2 v2.4.0 h1:3IcvPOAvnCKwNm0TB0dLDTuawWEj+ax/RERNC+diLMM= 4 | github.com/nicksnyder/go-i18n/v2 v2.4.0/go.mod h1:nxYSZE9M0bf3Y70gPQjN9ha7XNHX7gMc814+6wVyEI4= 5 | golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= 6 | golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= 7 | -------------------------------------------------------------------------------- /kit/i18n/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "net/http" 7 | ) 8 | 9 | func helloHandler(w http.ResponseWriter, r *http.Request) { 10 | err := NewUserNotFoundErr(123) 11 | // 某些业务处零零落落、 12 | //err, _ := someFunc() 13 | fmt.Fprintf(w, FormatErr(err)) 14 | } 15 | 16 | func main() { 17 | http.HandleFunc("/", helloHandler) 18 | 19 | fmt.Println("Starting server on port 8080...") 20 | if err := http.ListenAndServe(":8080", nil); err != nil { 21 | log.Fatal(err) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /kit/i18n/message.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "github.com/BurntSushi/toml" 7 | "github.com/nicksnyder/go-i18n/v2/i18n" 8 | "golang.org/x/text/language" 9 | ) 10 | 11 | var ( 12 | bundle = i18n.NewBundle(language.English) 13 | ) 14 | 15 | func init() { 16 | bundle.RegisterUnmarshalFunc("toml", toml.Unmarshal) 17 | bundle.LoadMessageFile("active.zh.toml") 18 | } 19 | 20 | type BaseError struct { 21 | ID string 22 | DefaultMessage string 23 | TempData map[string]interface{} 24 | } 25 | 26 | func (b BaseError) Error() string { 27 | return b.DefaultMessage 28 | } 29 | 30 | func (b BaseError) LocalizedID() string { 31 | return b.ID 32 | } 33 | 34 | func (b BaseError) TemplateData() map[string]interface{} { 35 | return b.TempData 36 | } 37 | 38 | type LocalizedError interface { 39 | error 40 | LocalizedID() string 41 | TemplateData() map[string]interface{} 42 | } 43 | 44 | type UserNotFoundErr struct { 45 | BaseError 46 | } 47 | 48 | func NewUserNotFoundErr(userID int) LocalizedError { 49 | msg := i18n.Message{ 50 | ID: "user_not_found", 51 | Other: "User not found {{.UserID}}", 52 | } 53 | e := UserNotFoundErr{} 54 | e.ID = msg.ID 55 | e.DefaultMessage = msg.Other 56 | e.TempData = map[string]interface{}{ 57 | "UserID": userID, 58 | } 59 | return e 60 | } 61 | 62 | func GetLang(_ context.Context) string { 63 | return "zh" 64 | } 65 | 66 | func FormatErr(err error) string { 67 | lang := GetLang(context.Background()) 68 | loc := i18n.NewLocalizer(bundle, lang) 69 | var i18nErr LocalizedError 70 | if errors.As(err, &i18nErr) { 71 | msg, _ := loc.Localize(&i18n.LocalizeConfig{ 72 | DefaultMessage: &i18n.Message{ 73 | ID: i18nErr.LocalizedID(), 74 | Other: i18nErr.Error(), 75 | }, 76 | //MessageID: i18nErr.LocalizedID(), 77 | TemplateData: i18nErr.TemplateData(), 78 | }) 79 | return msg 80 | } 81 | return err.Error() 82 | } 83 | -------------------------------------------------------------------------------- /kit/i18n/translate.zh.toml: -------------------------------------------------------------------------------- 1 | [PersonCatsDII] 2 | hash = "sha1-60f5e91090a4d4b765315e11ebe5ebae7a927620" 3 | other = "{{.Name}} 有很多 {{.Count}} 猫." 4 | -------------------------------------------------------------------------------- /kit/transaction/helloworld/.gitignore: -------------------------------------------------------------------------------- 1 | # Reference https://github.com/github/gitignore/blob/master/Go.gitignore 2 | # Binaries for programs and plugins 3 | *.exe 4 | *.exe~ 5 | *.dll 6 | *.dylib 7 | 8 | # Test binary, built with `go test -c` 9 | *.test 10 | 11 | # Output of the go coverage tool, specifically when used with LiteIDE 12 | *.out 13 | 14 | # Dependency directories (remove the comment below to include it) 15 | vendor/ 16 | 17 | # Go workspace file 18 | go.work 19 | 20 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 21 | *.o 22 | *.a 23 | *.so 24 | 25 | # OS General 26 | Thumbs.db 27 | .DS_Store 28 | 29 | # project 30 | *.cert 31 | *.key 32 | *.log 33 | bin/ 34 | 35 | # Develop tools 36 | .vscode/ 37 | .idea/ 38 | *.swp 39 | -------------------------------------------------------------------------------- /kit/transaction/helloworld/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1.19 AS builder 2 | 3 | COPY . /src 4 | WORKDIR /src 5 | 6 | RUN GOPROXY=https://goproxy.cn make build 7 | 8 | FROM debian:stable-slim 9 | 10 | RUN apt-get update && apt-get install -y --no-install-recommends \ 11 | ca-certificates \ 12 | netbase \ 13 | && rm -rf /var/lib/apt/lists/ \ 14 | && apt-get autoremove -y && apt-get autoclean -y 15 | 16 | COPY --from=builder /src/bin /app 17 | 18 | WORKDIR /app 19 | 20 | EXPOSE 8000 21 | EXPOSE 9000 22 | VOLUME /data/conf 23 | 24 | CMD ["./server", "-conf", "/data/conf"] 25 | -------------------------------------------------------------------------------- /kit/transaction/helloworld/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 go-kratos 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /kit/transaction/helloworld/Makefile: -------------------------------------------------------------------------------- 1 | GOHOSTOS:=$(shell go env GOHOSTOS) 2 | GOPATH:=$(shell go env GOPATH) 3 | VERSION=$(shell git describe --tags --always) 4 | 5 | ifeq ($(GOHOSTOS), windows) 6 | #the `find.exe` is different from `find` in bash/shell. 7 | #to see https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/find. 8 | #changed to use git-bash.exe to run find cli or other cli friendly, caused of every developer has a Git. 9 | #Git_Bash= $(subst cmd\,bin\bash.exe,$(dir $(shell where git))) 10 | Git_Bash=$(subst \,/,$(subst cmd\,bin\bash.exe,$(dir $(shell where git)))) 11 | INTERNAL_PROTO_FILES=$(shell $(Git_Bash) -c "find internal -name *.proto") 12 | API_PROTO_FILES=$(shell $(Git_Bash) -c "find api -name *.proto") 13 | else 14 | INTERNAL_PROTO_FILES=$(shell find internal -name *.proto) 15 | API_PROTO_FILES=$(shell find api -name *.proto) 16 | endif 17 | 18 | .PHONY: init 19 | # init env 20 | init: 21 | go install google.golang.org/protobuf/cmd/protoc-gen-go@latest 22 | go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest 23 | go install github.com/go-kratos/kratos/cmd/kratos/v2@latest 24 | go install github.com/go-kratos/kratos/cmd/protoc-gen-go-http/v2@latest 25 | go install github.com/google/gnostic/cmd/protoc-gen-openapi@latest 26 | go install github.com/google/wire/cmd/wire@latest 27 | 28 | .PHONY: config 29 | # generate internal proto 30 | config: 31 | protoc --proto_path=./internal \ 32 | --proto_path=./third_party \ 33 | --go_out=paths=source_relative:./internal \ 34 | $(INTERNAL_PROTO_FILES) 35 | 36 | .PHONY: api 37 | # generate api proto 38 | api: 39 | protoc --proto_path=./api \ 40 | --proto_path=./third_party \ 41 | --go_out=paths=source_relative:./api \ 42 | --go-http_out=paths=source_relative:./api \ 43 | --go-grpc_out=paths=source_relative:./api \ 44 | --openapi_out=fq_schema_naming=true,default_response=false:. \ 45 | $(API_PROTO_FILES) 46 | 47 | .PHONY: build 48 | # build 49 | build: 50 | mkdir -p bin/ && go build -ldflags "-X main.Version=$(VERSION)" -o ./bin/ ./... 51 | 52 | .PHONY: generate 53 | # generate 54 | generate: 55 | go mod tidy 56 | go get github.com/google/wire/cmd/wire@latest 57 | go generate ./... 58 | 59 | .PHONY: all 60 | # generate all 61 | all: 62 | make api; 63 | make config; 64 | make generate; 65 | 66 | # show help 67 | help: 68 | @echo '' 69 | @echo 'Usage:' 70 | @echo ' make [target]' 71 | @echo '' 72 | @echo 'Targets:' 73 | @awk '/^[a-zA-Z\-\_0-9]+:/ { \ 74 | helpMessage = match(lastLine, /^# (.*)/); \ 75 | if (helpMessage) { \ 76 | helpCommand = substr($$1, 0, index($$1, ":")); \ 77 | helpMessage = substr(lastLine, RSTART + 2, RLENGTH); \ 78 | printf "\033[36m%-22s\033[0m %s\n", helpCommand,helpMessage; \ 79 | } \ 80 | } \ 81 | { lastLine = $$0 }' $(MAKEFILE_LIST) 82 | 83 | .DEFAULT_GOAL := help 84 | -------------------------------------------------------------------------------- /kit/transaction/helloworld/README.md: -------------------------------------------------------------------------------- 1 | # Kratos Project Template 2 | 3 | ## Install Kratos 4 | ``` 5 | go install github.com/go-kratos/kratos/cmd/kratos/v2@latest 6 | ``` 7 | ## Create a service 8 | ``` 9 | # Create a template project 10 | kratos new server 11 | 12 | cd server 13 | # Add a proto template 14 | kratos proto add api/server/server.proto 15 | # Generate the proto code 16 | kratos proto client api/server/server.proto 17 | # Generate the source code of service by proto file 18 | kratos proto server api/server/server.proto -t internal/service 19 | 20 | go generate ./... 21 | go build -o ./bin/ ./... 22 | ./bin/server -conf ./configs 23 | ``` 24 | ## Generate other auxiliary files by Makefile 25 | ``` 26 | # Download and update dependencies 27 | make init 28 | # Generate API files (include: pb.go, http, grpc, validate, swagger) by proto file 29 | make api 30 | # Generate all files 31 | make all 32 | ``` 33 | ## Automated Initialization (wire) 34 | ``` 35 | # install wire 36 | go get github.com/google/wire/cmd/wire 37 | 38 | # generate wire 39 | cd cmd/server 40 | wire 41 | ``` 42 | 43 | ## Docker 44 | ```bash 45 | # build 46 | docker build -t . 47 | 48 | # run 49 | docker run --rm -p 8000:8000 -p 9000:9000 -v :/data/conf 50 | ``` 51 | 52 | -------------------------------------------------------------------------------- /kit/transaction/helloworld/api/helloworld/v1/error_reason.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package helloworld.v1; 4 | 5 | option go_package = "helloworld/api/helloworld/v1;v1"; 6 | option java_multiple_files = true; 7 | option java_package = "helloworld.v1"; 8 | option objc_class_prefix = "APIHelloworldV1"; 9 | 10 | enum ErrorReason { 11 | GREETER_UNSPECIFIED = 0; 12 | USER_NOT_FOUND = 1; 13 | } 14 | -------------------------------------------------------------------------------- /kit/transaction/helloworld/api/helloworld/v1/greeter.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package helloworld.v1; 4 | 5 | import "google/api/annotations.proto"; 6 | 7 | option go_package = "helloworld/api/helloworld/v1;v1"; 8 | option java_multiple_files = true; 9 | option java_package = "dev.kratos.api.helloworld.v1"; 10 | option java_outer_classname = "HelloworldProtoV1"; 11 | 12 | // The greeting service definition. 13 | service Greeter { 14 | // Sends a greeting 15 | rpc SayHello (HelloRequest) returns (HelloReply) { 16 | option (google.api.http) = { 17 | get: "/helloworld/{name}" 18 | }; 19 | } 20 | } 21 | 22 | // The request message containing the user's name. 23 | message HelloRequest { 24 | string name = 1; 25 | } 26 | 27 | // The response message containing the greetings 28 | message HelloReply { 29 | string message = 1; 30 | } 31 | -------------------------------------------------------------------------------- /kit/transaction/helloworld/api/helloworld/v1/greeter_http.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go-http. DO NOT EDIT. 2 | // versions: 3 | // protoc-gen-go-http v2.1.3 4 | 5 | package v1 6 | 7 | import ( 8 | context "context" 9 | http "github.com/go-kratos/kratos/v2/transport/http" 10 | binding "github.com/go-kratos/kratos/v2/transport/http/binding" 11 | ) 12 | 13 | // This is a compile-time assertion to ensure that this generated file 14 | // is compatible with the kratos package it is being compiled against. 15 | var _ = new(context.Context) 16 | var _ = binding.EncodeURL 17 | 18 | const _ = http.SupportPackageIsVersion1 19 | 20 | type GreeterHTTPServer interface { 21 | SayHello(context.Context, *HelloRequest) (*HelloReply, error) 22 | } 23 | 24 | func RegisterGreeterHTTPServer(s *http.Server, srv GreeterHTTPServer) { 25 | r := s.Route("/") 26 | r.GET("/helloworld/{name}", _Greeter_SayHello0_HTTP_Handler(srv)) 27 | } 28 | 29 | func _Greeter_SayHello0_HTTP_Handler(srv GreeterHTTPServer) func(ctx http.Context) error { 30 | return func(ctx http.Context) error { 31 | var in HelloRequest 32 | if err := ctx.BindQuery(&in); err != nil { 33 | return err 34 | } 35 | if err := ctx.BindVars(&in); err != nil { 36 | return err 37 | } 38 | http.SetOperation(ctx, "/helloworld.v1.Greeter/SayHello") 39 | h := ctx.Middleware(func(ctx context.Context, req interface{}) (interface{}, error) { 40 | return srv.SayHello(ctx, req.(*HelloRequest)) 41 | }) 42 | out, err := h(ctx, &in) 43 | if err != nil { 44 | return err 45 | } 46 | reply := out.(*HelloReply) 47 | return ctx.Result(200, reply) 48 | } 49 | } 50 | 51 | type GreeterHTTPClient interface { 52 | SayHello(ctx context.Context, req *HelloRequest, opts ...http.CallOption) (rsp *HelloReply, err error) 53 | } 54 | 55 | type GreeterHTTPClientImpl struct { 56 | cc *http.Client 57 | } 58 | 59 | func NewGreeterHTTPClient(client *http.Client) GreeterHTTPClient { 60 | return &GreeterHTTPClientImpl{client} 61 | } 62 | 63 | func (c *GreeterHTTPClientImpl) SayHello(ctx context.Context, in *HelloRequest, opts ...http.CallOption) (*HelloReply, error) { 64 | var out HelloReply 65 | pattern := "/helloworld/{name}" 66 | path := binding.EncodeURL(pattern, in, true) 67 | opts = append(opts, http.Operation("/helloworld.v1.Greeter/SayHello")) 68 | opts = append(opts, http.PathTemplate(pattern)) 69 | err := c.cc.Invoke(ctx, "GET", path, nil, &out, opts...) 70 | if err != nil { 71 | return nil, err 72 | } 73 | return &out, err 74 | } 75 | -------------------------------------------------------------------------------- /kit/transaction/helloworld/cmd/helloworld/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "os" 6 | 7 | "helloworld/internal/conf" 8 | 9 | "github.com/go-kratos/kratos/v2" 10 | "github.com/go-kratos/kratos/v2/config" 11 | "github.com/go-kratos/kratos/v2/config/file" 12 | "github.com/go-kratos/kratos/v2/log" 13 | "github.com/go-kratos/kratos/v2/middleware/tracing" 14 | "github.com/go-kratos/kratos/v2/transport/grpc" 15 | "github.com/go-kratos/kratos/v2/transport/http" 16 | 17 | _ "go.uber.org/automaxprocs" 18 | ) 19 | 20 | // go build -ldflags "-X main.Version=x.y.z" 21 | var ( 22 | // Name is the name of the compiled software. 23 | Name string 24 | // Version is the version of the compiled software. 25 | Version string 26 | // flagconf is the config flag. 27 | flagconf string 28 | 29 | id, _ = os.Hostname() 30 | ) 31 | 32 | func init() { 33 | flag.StringVar(&flagconf, "conf", "./configs/config.yaml", "config path, eg: -conf config.yaml") 34 | } 35 | 36 | func newApp(logger log.Logger, gs *grpc.Server, hs *http.Server) *kratos.App { 37 | return kratos.New( 38 | kratos.ID(id), 39 | kratos.Name(Name), 40 | kratos.Version(Version), 41 | kratos.Metadata(map[string]string{}), 42 | kratos.Logger(logger), 43 | kratos.Server( 44 | gs, 45 | hs, 46 | ), 47 | ) 48 | } 49 | 50 | func main() { 51 | flag.Parse() 52 | logger := log.With(log.NewStdLogger(os.Stdout), 53 | "ts", log.DefaultTimestamp, 54 | "caller", log.DefaultCaller, 55 | "service.id", id, 56 | "service.name", Name, 57 | "service.version", Version, 58 | "trace.id", tracing.TraceID(), 59 | "span.id", tracing.SpanID(), 60 | ) 61 | c := config.New( 62 | config.WithSource( 63 | file.NewSource(flagconf), 64 | ), 65 | ) 66 | defer c.Close() 67 | 68 | if err := c.Load(); err != nil { 69 | panic(err) 70 | } 71 | 72 | var bc conf.Bootstrap 73 | if err := c.Scan(&bc); err != nil { 74 | panic(err) 75 | } 76 | 77 | app, cleanup, err := wireApp(bc.Server, bc.Data, logger) 78 | if err != nil { 79 | panic(err) 80 | } 81 | defer cleanup() 82 | 83 | // start and wait for stop signal 84 | if err := app.Run(); err != nil { 85 | panic(err) 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /kit/transaction/helloworld/cmd/helloworld/wire.go: -------------------------------------------------------------------------------- 1 | //go:build wireinject 2 | // +build wireinject 3 | 4 | //go:generate wire 5 | 6 | // The build tag makes sure the stub is not built in the final build. 7 | 8 | package main 9 | 10 | import ( 11 | "helloworld/internal/biz" 12 | "helloworld/internal/conf" 13 | "helloworld/internal/data" 14 | "helloworld/internal/server" 15 | "helloworld/internal/service" 16 | "helloworld/pkg/db" 17 | 18 | "github.com/go-kratos/kratos/v2" 19 | "github.com/go-kratos/kratos/v2/log" 20 | "github.com/google/wire" 21 | ) 22 | 23 | // wireApp init kratos application. 24 | func wireApp(*conf.Server, *conf.Data, log.Logger) (*kratos.App, func(), error) { 25 | panic(wire.Build(db.NewDBClient, server.ProviderSet, data.ProviderSet, biz.ProviderSet, service.ProviderSet, newApp)) 26 | } 27 | -------------------------------------------------------------------------------- /kit/transaction/helloworld/cmd/helloworld/wire_gen.go: -------------------------------------------------------------------------------- 1 | // Code generated by Wire. DO NOT EDIT. 2 | 3 | //go:generate go run -mod=mod github.com/google/wire/cmd/wire 4 | //go:build !wireinject 5 | // +build !wireinject 6 | 7 | package main 8 | 9 | import ( 10 | "github.com/go-kratos/kratos/v2" 11 | "github.com/go-kratos/kratos/v2/log" 12 | "helloworld/internal/biz" 13 | "helloworld/internal/conf" 14 | "helloworld/internal/data" 15 | "helloworld/internal/server" 16 | "helloworld/internal/service" 17 | "helloworld/pkg/db" 18 | ) 19 | 20 | import ( 21 | _ "go.uber.org/automaxprocs" 22 | ) 23 | 24 | // Injectors from wire.go: 25 | 26 | // wireApp init kratos application. 27 | func wireApp(confServer *conf.Server, confData *conf.Data, logger log.Logger) (*kratos.App, func(), error) { 28 | dbClient, err := db.NewDBClient(confData) 29 | if err != nil { 30 | return nil, nil, err 31 | } 32 | dataData, cleanup, err := data.NewData(dbClient, logger) 33 | if err != nil { 34 | return nil, nil, err 35 | } 36 | greeterRepo := data.NewGreeterRepo(dataData, logger) 37 | greeterUsecase := biz.NewGreeterUsecase(greeterRepo, dbClient, logger) 38 | greeterService := service.NewGreeterService(greeterUsecase) 39 | grpcServer := server.NewGRPCServer(confServer, greeterService, logger) 40 | httpServer := server.NewHTTPServer(confServer, greeterService, logger) 41 | app := newApp(logger, grpcServer, httpServer) 42 | return app, func() { 43 | cleanup() 44 | }, nil 45 | } 46 | -------------------------------------------------------------------------------- /kit/transaction/helloworld/configs/config.yaml: -------------------------------------------------------------------------------- 1 | server: 2 | http: 3 | addr: 0.0.0.0:8000 4 | timeout: 1s 5 | grpc: 6 | addr: 0.0.0.0:9000 7 | timeout: 1s 8 | data: 9 | database: 10 | driver: mysql 11 | source: root:root@tcp(127.0.0.1:3306)/dev?parseTime=True&loc=Local 12 | redis: 13 | addr: 127.0.0.1:6379 14 | read_timeout: 0.2s 15 | write_timeout: 0.2s 16 | -------------------------------------------------------------------------------- /kit/transaction/helloworld/go.mod: -------------------------------------------------------------------------------- 1 | module helloworld 2 | 3 | go 1.19 4 | 5 | require ( 6 | github.com/go-kratos/kratos/v2 v2.7.2 7 | github.com/google/wire v0.5.0 8 | go.uber.org/automaxprocs v1.5.1 9 | google.golang.org/genproto/googleapis/api v0.0.0-20230629202037-9506855d4529 10 | google.golang.org/grpc v1.56.3 11 | google.golang.org/protobuf v1.32.0 12 | gorm.io/driver/mysql v1.5.7 13 | gorm.io/gorm v1.25.11 14 | ) 15 | 16 | require ( 17 | github.com/fsnotify/fsnotify v1.6.0 // indirect 18 | github.com/go-kratos/aegis v0.2.0 // indirect 19 | github.com/go-logr/logr v1.2.4 // indirect 20 | github.com/go-logr/stdr v1.2.2 // indirect 21 | github.com/go-playground/form/v4 v4.2.1 // indirect 22 | github.com/go-sql-driver/mysql v1.7.0 // indirect 23 | github.com/golang/protobuf v1.5.3 // indirect 24 | github.com/google/uuid v1.6.0 // indirect 25 | github.com/gorilla/mux v1.8.0 // indirect 26 | github.com/imdario/mergo v0.3.16 // indirect 27 | github.com/jinzhu/inflection v1.0.0 // indirect 28 | github.com/jinzhu/now v1.1.5 // indirect 29 | github.com/kr/text v0.2.0 // indirect 30 | go.opentelemetry.io/otel v1.16.0 // indirect 31 | go.opentelemetry.io/otel/metric v1.16.0 // indirect 32 | go.opentelemetry.io/otel/trace v1.16.0 // indirect 33 | golang.org/x/net v0.17.0 // indirect 34 | golang.org/x/sync v0.6.0 // indirect 35 | golang.org/x/sys v0.13.0 // indirect 36 | golang.org/x/text v0.14.0 // indirect 37 | google.golang.org/genproto v0.0.0-20230629202037-9506855d4529 // indirect 38 | google.golang.org/genproto/googleapis/rpc v0.0.0-20230629202037-9506855d4529 // indirect 39 | gopkg.in/yaml.v3 v3.0.1 // indirect 40 | ) 41 | -------------------------------------------------------------------------------- /kit/transaction/helloworld/internal/biz/README.md: -------------------------------------------------------------------------------- 1 | # Biz 2 | -------------------------------------------------------------------------------- /kit/transaction/helloworld/internal/biz/biz.go: -------------------------------------------------------------------------------- 1 | package biz 2 | 3 | import "github.com/google/wire" 4 | 5 | // ProviderSet is biz providers. 6 | var ProviderSet = wire.NewSet(NewGreeterUsecase) 7 | -------------------------------------------------------------------------------- /kit/transaction/helloworld/internal/biz/greeter.go: -------------------------------------------------------------------------------- 1 | package biz 2 | 3 | import ( 4 | "context" 5 | "helloworld/pkg/db" 6 | 7 | v1 "helloworld/api/helloworld/v1" 8 | 9 | "github.com/go-kratos/kratos/v2/errors" 10 | "github.com/go-kratos/kratos/v2/log" 11 | ) 12 | 13 | var ( 14 | // ErrUserNotFound is user not found. 15 | ErrUserNotFound = errors.NotFound(v1.ErrorReason_USER_NOT_FOUND.String(), "user not found") 16 | ) 17 | 18 | // Greeter is a Greeter model. 19 | type Greeter struct { 20 | Hello string `gorm:"column:hello;type:varchar(20)"` 21 | } 22 | 23 | func (*Greeter) TableName() string { 24 | return "greater" 25 | } 26 | 27 | // GreeterRepo is a Greater repo. 28 | type GreeterRepo interface { 29 | Save(context.Context, *Greeter) (*Greeter, error) 30 | Update(context.Context, *Greeter) (*Greeter, error) 31 | FindByID(context.Context, int64) (*Greeter, error) 32 | ListByHello(context.Context, string) ([]*Greeter, error) 33 | ListAll(context.Context) ([]*Greeter, error) 34 | } 35 | 36 | // GreeterUsecase is a Greeter usecase. 37 | type GreeterUsecase struct { 38 | db *db.DBClient 39 | repo GreeterRepo 40 | log *log.Helper 41 | } 42 | 43 | // NewGreeterUsecase new a Greeter usecase. 44 | func NewGreeterUsecase(repo GreeterRepo, db *db.DBClient, logger log.Logger) *GreeterUsecase { 45 | return &GreeterUsecase{db: db, repo: repo, log: log.NewHelper(logger)} 46 | } 47 | 48 | // CreateGreeter creates a Greeter, and returns the new Greeter. 49 | func (uc *GreeterUsecase) CreateGreeter(ctx context.Context, g *Greeter) (*Greeter, error) { 50 | uc.log.WithContext(ctx).Infof("CreateGreeter: %v", g.Hello) 51 | var ( 52 | greater *Greeter 53 | err error 54 | ) 55 | err = uc.db.ExecTx(ctx, func(ctx context.Context) error { 56 | // 更新所有 hello 为 hello + "updated",且插入新的 hello 57 | greater, err = uc.repo.Save(ctx, g) 58 | _, err = uc.repo.Update(ctx, g) 59 | return err 60 | }) 61 | //greater, err = uc.repo.Save(ctx, g) 62 | //_, err = uc.repo.Update(ctx, g) 63 | if err != nil { 64 | return nil, err 65 | } 66 | return greater, nil 67 | } 68 | -------------------------------------------------------------------------------- /kit/transaction/helloworld/internal/conf/conf.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package kratos.api; 3 | 4 | option go_package = "helloworld/internal/conf;conf"; 5 | 6 | import "google/protobuf/duration.proto"; 7 | 8 | message Bootstrap { 9 | Server server = 1; 10 | Data data = 2; 11 | } 12 | 13 | message Server { 14 | message HTTP { 15 | string network = 1; 16 | string addr = 2; 17 | google.protobuf.Duration timeout = 3; 18 | } 19 | message GRPC { 20 | string network = 1; 21 | string addr = 2; 22 | google.protobuf.Duration timeout = 3; 23 | } 24 | HTTP http = 1; 25 | GRPC grpc = 2; 26 | } 27 | 28 | message Data { 29 | message Database { 30 | string driver = 1; 31 | string source = 2; 32 | } 33 | message Redis { 34 | string network = 1; 35 | string addr = 2; 36 | google.protobuf.Duration read_timeout = 3; 37 | google.protobuf.Duration write_timeout = 4; 38 | } 39 | Database database = 1; 40 | Redis redis = 2; 41 | } 42 | -------------------------------------------------------------------------------- /kit/transaction/helloworld/internal/data/README.md: -------------------------------------------------------------------------------- 1 | # Data 2 | -------------------------------------------------------------------------------- /kit/transaction/helloworld/internal/data/data.go: -------------------------------------------------------------------------------- 1 | package data 2 | 3 | import ( 4 | "helloworld/pkg/db" 5 | 6 | "github.com/go-kratos/kratos/v2/log" 7 | "github.com/google/wire" 8 | ) 9 | 10 | // ProviderSet is data providers. 11 | var ProviderSet = wire.NewSet(NewData, NewGreeterRepo) 12 | 13 | // Data . 14 | type Data struct { 15 | // TODO wrapped database client 16 | db *db.DBClient 17 | } 18 | 19 | // NewData . 20 | func NewData(c *db.DBClient, logger log.Logger) (*Data, func(), error) { 21 | cleanup := func() { 22 | log.NewHelper(logger).Info("closing the data resources") 23 | } 24 | return &Data{db: c}, cleanup, nil 25 | } 26 | -------------------------------------------------------------------------------- /kit/transaction/helloworld/internal/data/greeter.go: -------------------------------------------------------------------------------- 1 | package data 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | 7 | "helloworld/internal/biz" 8 | 9 | "github.com/go-kratos/kratos/v2/log" 10 | ) 11 | 12 | type greeterRepo struct { 13 | data *Data 14 | log *log.Helper 15 | } 16 | 17 | // NewGreeterRepo . 18 | func NewGreeterRepo(data *Data, logger log.Logger) biz.GreeterRepo { 19 | return &greeterRepo{ 20 | data: data, 21 | log: log.NewHelper(logger), 22 | } 23 | } 24 | 25 | func (r *greeterRepo) Save(ctx context.Context, g *biz.Greeter) (*biz.Greeter, error) { 26 | result := r.data.db.DB(ctx).Create(g) 27 | return g, result.Error 28 | } 29 | 30 | func (r *greeterRepo) Update(ctx context.Context, g *biz.Greeter) (*biz.Greeter, error) { 31 | result := r.data.db.DB(ctx).Model(&biz.Greeter{}).Where("hello = ?", g.Hello).Update("hello", g.Hello+"updated") 32 | if result.RowsAffected == 0 { 33 | return nil, fmt.Errorf("greeter %s not found", g.Hello) 34 | } 35 | return nil, fmt.Errorf("custom error") 36 | //return g, nil 37 | } 38 | 39 | func (r *greeterRepo) FindByID(context.Context, int64) (*biz.Greeter, error) { 40 | return nil, nil 41 | } 42 | 43 | func (r *greeterRepo) ListByHello(ctx context.Context, hello string) ([]*biz.Greeter, error) { 44 | var greeters []*biz.Greeter 45 | result := r.data.db.DB(ctx).Where("hello = ?", hello).Find(&greeters) 46 | return greeters, result.Error 47 | } 48 | 49 | func (r *greeterRepo) ListAll(context.Context) ([]*biz.Greeter, error) { 50 | return nil, nil 51 | } 52 | -------------------------------------------------------------------------------- /kit/transaction/helloworld/internal/server/grpc.go: -------------------------------------------------------------------------------- 1 | package server 2 | 3 | import ( 4 | v1 "helloworld/api/helloworld/v1" 5 | "helloworld/internal/conf" 6 | "helloworld/internal/service" 7 | 8 | "github.com/go-kratos/kratos/v2/log" 9 | "github.com/go-kratos/kratos/v2/middleware/recovery" 10 | "github.com/go-kratos/kratos/v2/transport/grpc" 11 | ) 12 | 13 | // NewGRPCServer new a gRPC server. 14 | func NewGRPCServer(c *conf.Server, greeter *service.GreeterService, logger log.Logger) *grpc.Server { 15 | var opts = []grpc.ServerOption{ 16 | grpc.Middleware( 17 | recovery.Recovery(), 18 | ), 19 | } 20 | if c.Grpc.Network != "" { 21 | opts = append(opts, grpc.Network(c.Grpc.Network)) 22 | } 23 | if c.Grpc.Addr != "" { 24 | opts = append(opts, grpc.Address(c.Grpc.Addr)) 25 | } 26 | if c.Grpc.Timeout != nil { 27 | opts = append(opts, grpc.Timeout(c.Grpc.Timeout.AsDuration())) 28 | } 29 | srv := grpc.NewServer(opts...) 30 | v1.RegisterGreeterServer(srv, greeter) 31 | return srv 32 | } 33 | -------------------------------------------------------------------------------- /kit/transaction/helloworld/internal/server/http.go: -------------------------------------------------------------------------------- 1 | package server 2 | 3 | import ( 4 | v1 "helloworld/api/helloworld/v1" 5 | "helloworld/internal/conf" 6 | "helloworld/internal/service" 7 | 8 | "github.com/go-kratos/kratos/v2/log" 9 | "github.com/go-kratos/kratos/v2/middleware/recovery" 10 | "github.com/go-kratos/kratos/v2/transport/http" 11 | ) 12 | 13 | // NewHTTPServer new an HTTP server. 14 | func NewHTTPServer(c *conf.Server, greeter *service.GreeterService, logger log.Logger) *http.Server { 15 | var opts = []http.ServerOption{ 16 | http.Middleware( 17 | recovery.Recovery(), 18 | ), 19 | } 20 | if c.Http.Network != "" { 21 | opts = append(opts, http.Network(c.Http.Network)) 22 | } 23 | if c.Http.Addr != "" { 24 | opts = append(opts, http.Address(c.Http.Addr)) 25 | } 26 | if c.Http.Timeout != nil { 27 | opts = append(opts, http.Timeout(c.Http.Timeout.AsDuration())) 28 | } 29 | srv := http.NewServer(opts...) 30 | v1.RegisterGreeterHTTPServer(srv, greeter) 31 | return srv 32 | } 33 | -------------------------------------------------------------------------------- /kit/transaction/helloworld/internal/server/server.go: -------------------------------------------------------------------------------- 1 | package server 2 | 3 | import ( 4 | "github.com/google/wire" 5 | ) 6 | 7 | // ProviderSet is server providers. 8 | var ProviderSet = wire.NewSet(NewGRPCServer, NewHTTPServer) 9 | -------------------------------------------------------------------------------- /kit/transaction/helloworld/internal/service/README.md: -------------------------------------------------------------------------------- 1 | # Service 2 | -------------------------------------------------------------------------------- /kit/transaction/helloworld/internal/service/greeter.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "context" 5 | 6 | v1 "helloworld/api/helloworld/v1" 7 | "helloworld/internal/biz" 8 | ) 9 | 10 | // GreeterService is a greeter service. 11 | type GreeterService struct { 12 | v1.UnimplementedGreeterServer 13 | 14 | uc *biz.GreeterUsecase 15 | } 16 | 17 | // NewGreeterService new a greeter service. 18 | func NewGreeterService(uc *biz.GreeterUsecase) *GreeterService { 19 | return &GreeterService{uc: uc} 20 | } 21 | 22 | // SayHello implements helloworld.GreeterServer. 23 | func (s *GreeterService) SayHello(ctx context.Context, in *v1.HelloRequest) (*v1.HelloReply, error) { 24 | g, err := s.uc.CreateGreeter(ctx, &biz.Greeter{Hello: in.Name}) 25 | if err != nil { 26 | return nil, err 27 | } 28 | return &v1.HelloReply{Message: "Hello " + g.Hello}, nil 29 | } 30 | -------------------------------------------------------------------------------- /kit/transaction/helloworld/internal/service/service.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import "github.com/google/wire" 4 | 5 | // ProviderSet is service providers. 6 | var ProviderSet = wire.NewSet(NewGreeterService) 7 | -------------------------------------------------------------------------------- /kit/transaction/helloworld/openapi.yaml: -------------------------------------------------------------------------------- 1 | # Generated with protoc-gen-openapi 2 | # https://github.com/google/gnostic/tree/master/cmd/protoc-gen-openapi 3 | 4 | openapi: 3.0.3 5 | info: 6 | title: Greeter API 7 | description: The greeting service definition. 8 | version: 0.0.1 9 | paths: 10 | /helloworld/{name}: 11 | get: 12 | tags: 13 | - Greeter 14 | - subgroup 15 | description: Sends a greeting 16 | operationId: Greeter_SayHello 17 | parameters: 18 | - name: name 19 | in: path 20 | required: true 21 | schema: 22 | type: string 23 | responses: 24 | "200": 25 | description: OK 26 | content: 27 | application/json: 28 | schema: 29 | $ref: '#/components/schemas/helloworld.v1.HelloReply' 30 | components: 31 | schemas: 32 | helloworld.v1.HelloReply: 33 | type: object 34 | properties: 35 | message: 36 | type: string 37 | description: The response message containing the greetings 38 | tags: 39 | - name: Greeter 40 | -------------------------------------------------------------------------------- /kit/transaction/helloworld/pkg/db/db.go: -------------------------------------------------------------------------------- 1 | package db 2 | 3 | import ( 4 | "context" 5 | "gorm.io/driver/mysql" 6 | "gorm.io/gorm" 7 | "helloworld/internal/conf" 8 | ) 9 | 10 | type DBClient struct { 11 | db *gorm.DB 12 | } 13 | 14 | func NewDBClient(c *conf.Data) (*DBClient, error) { 15 | dsn := c.Database.Source 16 | if c.Database.Driver == "mysql" { 17 | db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{ 18 | SkipDefaultTransaction: true, 19 | }) 20 | if err != nil { 21 | return nil, err 22 | } 23 | return &DBClient{db: db}, nil 24 | } 25 | return nil, nil 26 | } 27 | 28 | func (c *DBClient) GetDB() *gorm.DB { 29 | return c.db 30 | } 31 | 32 | type Transaction interface { 33 | ExecTx(context.Context, func(ctx context.Context) error) error 34 | } 35 | 36 | type contextTxKey struct{} 37 | 38 | // ExecTx gorm Transaction 39 | func (c *DBClient) ExecTx(ctx context.Context, fn func(ctx context.Context) error) error { 40 | return c.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error { 41 | ctx = context.WithValue(ctx, contextTxKey{}, tx) 42 | return fn(ctx) 43 | }) 44 | } 45 | 46 | func (c *DBClient) DB(ctx context.Context) *gorm.DB { 47 | tx, ok := ctx.Value(contextTxKey{}).(*gorm.DB) 48 | if ok { 49 | return tx 50 | } 51 | return c.db 52 | } 53 | -------------------------------------------------------------------------------- /kit/transaction/helloworld/schema/20240806134830_init.sql: -------------------------------------------------------------------------------- 1 | -- +goose Up 2 | -- +goose StatementBegin 3 | CREATE TABLE IF NOT EXISTS greater ( 4 | hello VARCHAR(20) NOT NULL 5 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; 6 | -- +goose StatementEnd 7 | 8 | -- +goose Down 9 | -- +goose StatementBegin 10 | DROP TABLE IF EXISTS account; 11 | -- +goose StatementEnd 12 | -------------------------------------------------------------------------------- /kit/transaction/helloworld/schema/Makefile: -------------------------------------------------------------------------------- 1 | up: 2 | goose mysql "root:root@tcp(localhost:3306)/dev?parseTime=true" up 3 | 4 | down: 5 | goose mysql "root:root@tcp(localhost:3306)/dev?parseTime=true" down 6 | 7 | create: 8 | goose mysql "root:root@tcp(localhost:3306)/dev?parseTime=true" create ${name} sql 9 | -------------------------------------------------------------------------------- /kit/transaction/helloworld/third_party/README.md: -------------------------------------------------------------------------------- 1 | # third_party 2 | -------------------------------------------------------------------------------- /kit/transaction/helloworld/third_party/errors/errors.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package errors; 4 | 5 | option go_package = "github.com/go-kratos/kratos/v2/errors;errors"; 6 | option java_multiple_files = true; 7 | option java_package = "com.github.kratos.errors"; 8 | option objc_class_prefix = "KratosErrors"; 9 | 10 | import "google/protobuf/descriptor.proto"; 11 | 12 | extend google.protobuf.EnumOptions { 13 | int32 default_code = 1108; 14 | } 15 | 16 | extend google.protobuf.EnumValueOptions { 17 | int32 code = 1109; 18 | } -------------------------------------------------------------------------------- /kit/transaction/helloworld/third_party/google/api/annotations.proto: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, Google Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | syntax = "proto3"; 16 | 17 | package google.api; 18 | 19 | import "google/api/http.proto"; 20 | import "google/protobuf/descriptor.proto"; 21 | 22 | option go_package = "google.golang.org/genproto/googleapis/api/annotations;annotations"; 23 | option java_multiple_files = true; 24 | option java_outer_classname = "AnnotationsProto"; 25 | option java_package = "com.google.api"; 26 | option objc_class_prefix = "GAPI"; 27 | 28 | extend google.protobuf.MethodOptions { 29 | // See `HttpRule`. 30 | HttpRule http = 72295728; 31 | } 32 | -------------------------------------------------------------------------------- /kit/transaction/helloworld/third_party/google/protobuf/empty.proto: -------------------------------------------------------------------------------- 1 | // Protocol Buffers - Google's data interchange format 2 | // Copyright 2008 Google Inc. All rights reserved. 3 | // https://developers.google.com/protocol-buffers/ 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions are 7 | // met: 8 | // 9 | // * Redistributions of source code must retain the above copyright 10 | // notice, this list of conditions and the following disclaimer. 11 | // * Redistributions in binary form must reproduce the above 12 | // copyright notice, this list of conditions and the following disclaimer 13 | // in the documentation and/or other materials provided with the 14 | // distribution. 15 | // * Neither the name of Google Inc. nor the names of its 16 | // contributors may be used to endorse or promote products derived from 17 | // this software without specific prior written permission. 18 | // 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | syntax = "proto3"; 32 | 33 | package google.protobuf; 34 | 35 | option csharp_namespace = "Google.Protobuf.WellKnownTypes"; 36 | option go_package = "google.golang.org/protobuf/types/known/emptypb"; 37 | option java_package = "com.google.protobuf"; 38 | option java_outer_classname = "EmptyProto"; 39 | option java_multiple_files = true; 40 | option objc_class_prefix = "GPB"; 41 | option cc_enable_arenas = true; 42 | 43 | // A generic empty message that you can re-use to avoid defining duplicated 44 | // empty messages in your APIs. A typical example is to use it as the request 45 | // or the response type of an API method. For instance: 46 | // 47 | // service Foo { 48 | // rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty); 49 | // } 50 | // 51 | // The JSON representation for `Empty` is empty JSON object `{}`. 52 | message Empty {} 53 | -------------------------------------------------------------------------------- /kit/transaction/helloworld/third_party/google/protobuf/source_context.proto: -------------------------------------------------------------------------------- 1 | // Protocol Buffers - Google's data interchange format 2 | // Copyright 2008 Google Inc. All rights reserved. 3 | // https://developers.google.com/protocol-buffers/ 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions are 7 | // met: 8 | // 9 | // * Redistributions of source code must retain the above copyright 10 | // notice, this list of conditions and the following disclaimer. 11 | // * Redistributions in binary form must reproduce the above 12 | // copyright notice, this list of conditions and the following disclaimer 13 | // in the documentation and/or other materials provided with the 14 | // distribution. 15 | // * Neither the name of Google Inc. nor the names of its 16 | // contributors may be used to endorse or promote products derived from 17 | // this software without specific prior written permission. 18 | // 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | syntax = "proto3"; 32 | 33 | package google.protobuf; 34 | 35 | option csharp_namespace = "Google.Protobuf.WellKnownTypes"; 36 | option java_package = "com.google.protobuf"; 37 | option java_outer_classname = "SourceContextProto"; 38 | option java_multiple_files = true; 39 | option objc_class_prefix = "GPB"; 40 | option go_package = "google.golang.org/protobuf/types/known/sourcecontextpb"; 41 | 42 | // `SourceContext` represents information about the source of a 43 | // protobuf element, like the file in which it is defined. 44 | message SourceContext { 45 | // The path-qualified name of the .proto file that contained the associated 46 | // protobuf element. For example: `"google/protobuf/source_context.proto"`. 47 | string file_name = 1; 48 | } 49 | -------------------------------------------------------------------------------- /kit/transaction/helloworld/third_party/openapi/v3/annotations.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Google LLC. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | syntax = "proto3"; 16 | 17 | package openapi.v3; 18 | 19 | import "openapi/v3/openapi.proto"; 20 | import "google/protobuf/descriptor.proto"; 21 | 22 | // This option lets the proto compiler generate Java code inside the package 23 | // name (see below) instead of inside an outer class. It creates a simpler 24 | // developer experience by reducing one-level of name nesting and be 25 | // consistent with most programming languages that don't support outer classes. 26 | option java_multiple_files = true; 27 | 28 | // The Java outer classname should be the filename in UpperCamelCase. This 29 | // class is only used to hold proto descriptor, so developers don't need to 30 | // work with it directly. 31 | option java_outer_classname = "AnnotationsProto"; 32 | 33 | // The Java package name must be proto package name with proper prefix. 34 | option java_package = "org.openapi_v3"; 35 | 36 | // A reasonable prefix for the Objective-C symbols generated from the package. 37 | // It should at a minimum be 3 characters long, all uppercase, and convention 38 | // is to use an abbreviation of the package name. Something short, but 39 | // hopefully unique enough to not conflict with things that may come along in 40 | // the future. 'GPB' is reserved for the protocol buffer implementation itself. 41 | option objc_class_prefix = "OAS"; 42 | 43 | // The Go package name. 44 | option go_package = "github.com/google/gnostic/openapiv3;openapi_v3"; 45 | 46 | extend google.protobuf.FileOptions { 47 | Document document = 1143; 48 | } 49 | 50 | extend google.protobuf.MethodOptions { 51 | Operation operation = 1143; 52 | } 53 | 54 | extend google.protobuf.MessageOptions { 55 | Schema schema = 1143; 56 | } 57 | 58 | extend google.protobuf.FieldOptions { 59 | Schema property = 1143; 60 | } -------------------------------------------------------------------------------- /kit/transaction/helloworld/third_party/validate/README.md: -------------------------------------------------------------------------------- 1 | # protoc-gen-validate (PGV) 2 | 3 | * https://github.com/envoyproxy/protoc-gen-validate 4 | -------------------------------------------------------------------------------- /storage/go.mod: -------------------------------------------------------------------------------- 1 | module storage 2 | 3 | go 1.21.3 4 | 5 | require go.mongodb.org/mongo-driver v1.14.0 6 | 7 | require ( 8 | github.com/davecgh/go-spew v1.1.1 // indirect 9 | github.com/golang/snappy v0.0.1 // indirect 10 | github.com/klauspost/compress v1.13.6 // indirect 11 | github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe // indirect 12 | github.com/pmezard/go-difflib v1.0.0 // indirect 13 | github.com/stretchr/testify v1.9.0 // indirect 14 | github.com/xdg-go/pbkdf2 v1.0.0 // indirect 15 | github.com/xdg-go/scram v1.1.2 // indirect 16 | github.com/xdg-go/stringprep v1.0.4 // indirect 17 | github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect 18 | golang.org/x/crypto v0.17.0 // indirect 19 | golang.org/x/sync v0.1.0 // indirect 20 | golang.org/x/text v0.14.0 // indirect 21 | gopkg.in/yaml.v3 v3.0.1 // indirect 22 | ) 23 | -------------------------------------------------------------------------------- /storage/mongodb/Makefile: -------------------------------------------------------------------------------- 1 | # 定义项目名称 2 | PROJECT_NAME := mongodb 3 | 4 | # 默认目标 5 | .DEFAULT_GOAL := help 6 | 7 | # 定义命令 8 | DOCKER_COMPOSE := docker-compose 9 | 10 | # 配置 Docker Compose 文件路径 11 | DOCKER_COMPOSE_FILE := docker-compose.yaml 12 | 13 | # 启动 MongoDB 服务 14 | up: 15 | $(DOCKER_COMPOSE) -f $(DOCKER_COMPOSE_FILE) up -d 16 | 17 | # 停止 MongoDB 服务 18 | down: 19 | $(DOCKER_COMPOSE) -f $(DOCKER_COMPOSE_FILE) down 20 | 21 | # 清理 MongoDB 数据卷 22 | clean: 23 | $(DOCKER_COMPOSE) -f $(DOCKER_COMPOSE_FILE) down -v 24 | 25 | # 帮助信息 26 | help: 27 | @echo "Usage:" 28 | @echo " make up Start MongoDB container" 29 | @echo " make down Stop MongoDB container" 30 | @echo " make clean Remove MongoDB data volume" 31 | @echo " make help Show this help message" 32 | -------------------------------------------------------------------------------- /storage/mongodb/config.go: -------------------------------------------------------------------------------- 1 | package mongodb 2 | 3 | // Config defines the config for storage. 4 | type Config struct { 5 | // Connection string to use for DB. Will override all other authentication values if used 6 | // 7 | // Optional. Default is "" 8 | ConnectionURI string 9 | 10 | // Host name where the DB is hosted 11 | // 12 | // Optional. Default is "127.0.0.1" 13 | Host string 14 | 15 | // Port where the DB is listening on 16 | // 17 | // Optional. Default is 27017 18 | Port int 19 | 20 | // Server username 21 | // 22 | // Optional. Default is "" 23 | Username string 24 | 25 | // Server password 26 | // 27 | // Optional. Default is "" 28 | Password string 29 | 30 | // Database name 31 | // 32 | // Optional. Default is "doutok" 33 | Database string 34 | 35 | // Collection name 36 | // 37 | // Optional. Default is "default" 38 | Collection string 39 | 40 | // Reset clears any existing keys in existing Table 41 | // 42 | // Optional. Default is false 43 | Reset bool 44 | } 45 | 46 | // ConfigDefault is the default config 47 | var ConfigDefault = Config{ 48 | ConnectionURI: "", 49 | Host: "127.0.0.1", 50 | Port: 27017, 51 | Database: "doutok", 52 | Collection: "default", 53 | Reset: false, 54 | } 55 | 56 | // Helper function to set default values 57 | func configDefault(config ...Config) Config { 58 | // Return default config if nothing provided 59 | if len(config) < 1 { 60 | return ConfigDefault 61 | } 62 | 63 | // Override default config 64 | cfg := config[0] 65 | 66 | // Set default values 67 | if cfg.Host == "" { 68 | cfg.Host = ConfigDefault.Host 69 | } 70 | if cfg.Port <= 0 { 71 | cfg.Port = ConfigDefault.Port 72 | } 73 | if cfg.Database == "" { 74 | cfg.Database = ConfigDefault.Database 75 | } 76 | if cfg.Collection == "" { 77 | cfg.Collection = ConfigDefault.Collection 78 | } 79 | return cfg 80 | } 81 | -------------------------------------------------------------------------------- /storage/mongodb/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: '3.8' 2 | 3 | services: 4 | mongodb: 5 | image: mongo:latest 6 | container_name: mongodb 7 | restart: always 8 | ports: 9 | - "27017:27017" 10 | environment: 11 | MONGO_INITDB_ROOT_USERNAME: root 12 | MONGO_INITDB_ROOT_PASSWORD: root 13 | volumes: 14 | - mongodb_data:/data/db 15 | 16 | volumes: 17 | mongodb_data: 18 | -------------------------------------------------------------------------------- /storage/mongodb/mongodb_test.go: -------------------------------------------------------------------------------- 1 | package mongodb 2 | 3 | import ( 4 | "context" 5 | "github.com/stretchr/testify/require" 6 | "testing" 7 | ) 8 | 9 | type User struct { 10 | Id string `json:"id" bson:"_id"` // 自定义的 Id 字段 11 | Username string `json:"username"` 12 | Password string `json:"password"` 13 | Email string `json:"email"` 14 | } 15 | 16 | // TestStorage_InsertAndFindOne 需要通过 Makefile 提前启动本地 MongoDB 服务 17 | func TestStorage_InsertAndFindOne(t *testing.T) { 18 | config := Config{ 19 | Username: "root", 20 | Password: "root", 21 | Database: "doutok", 22 | Collection: "default", 23 | } 24 | store := New(config) 25 | 26 | // 创建用户 27 | _, err := store.InsertOne(context.Background(), User{ 28 | Id: "123", // 手动指定自定义的 Id 值 29 | Username: "zhangsan", 30 | Password: "123456", 31 | Email: "123@.com", 32 | }) 33 | require.NoError(t, err) 34 | 35 | // 查询用户 36 | result := store.FindOne(context.Background(), map[string]interface{}{"_id": "123"}) 37 | 38 | // 解码查询结果 39 | var user map[string]interface{} 40 | err = result.Decode(&user) 41 | require.NoError(t, err) 42 | require.Equal(t, "123@.com", user["email"]) 43 | 44 | // 修改用户 45 | update := map[string]interface{}{ 46 | "$set": map[string]interface{}{ 47 | "email": "321@.com", 48 | }, 49 | } 50 | _, err = store.UpdateOne(context.Background(), 51 | map[string]interface{}{"_id": "123"}, 52 | update) 53 | require.NoError(t, err) 54 | 55 | // 查询用户 56 | result = store.FindOne(context.Background(), map[string]interface{}{"_id": "123"}) 57 | 58 | // 解码查询结果 59 | err = result.Decode(&user) 60 | require.NoError(t, err) 61 | require.Equal(t, "321@.com", user["email"]) 62 | 63 | // 删除用户 64 | count, err := store.DeleteOne(context.Background(), map[string]interface{}{"_id": "123"}) 65 | require.NoError(t, err) 66 | require.Equal(t, int64(1), count) 67 | 68 | // 查询用户 69 | result = store.FindOne(context.Background(), map[string]interface{}{"_id": "123"}) 70 | user2 := User{} 71 | err = result.Decode(&user2) 72 | require.Equal(t, "mongo: no documents in result", err.Error()) 73 | } 74 | -------------------------------------------------------------------------------- /temporal/go.mod: -------------------------------------------------------------------------------- 1 | module app 2 | 3 | go 1.22.2 4 | 5 | require go.temporal.io/sdk v1.29.1 // indirect 6 | -------------------------------------------------------------------------------- /temporal/go.sum: -------------------------------------------------------------------------------- 1 | go.temporal.io/sdk v1.29.1 h1:y+sUMbUhTU9rj50mwIZAPmcXCtgUdOWS9xHDYRYSgZ0= 2 | go.temporal.io/sdk v1.29.1/go.mod h1:kp//DRvn3CqQVBCtjL51Oicp9wrZYB2s6row1UgzcKQ= 3 | --------------------------------------------------------------------------------