├── ch13-seckill
├── 架构图.jpeg
├── framework.png
├── sk-core
│ ├── main.go
│ ├── service
│ │ ├── srv_err
│ │ │ └── error.go
│ │ ├── service.go
│ │ ├── srv_limit
│ │ │ └── sec_limit.go
│ │ ├── srv_user
│ │ │ └── user_history.go
│ │ └── srv_product
│ │ │ └── product_count.go
│ ├── bootstrap.yaml
│ └── setup
│ │ ├── redis.go
│ │ ├── service.go
│ │ └── zk.go
├── pkg
│ ├── common
│ │ └── service_instance.go
│ ├── config
│ │ └── need_config.conf
│ ├── bootstrap
│ │ ├── BootstrapProperty.go
│ │ └── bootstrap_config.go
│ ├── ratelimiter
│ │ └── instruments.go
│ ├── discover
│ │ └── discovery_client.go
│ ├── mysql
│ │ └── mysql.go
│ ├── client
│ │ ├── user_test.go
│ │ ├── oauth.go
│ │ └── user.go
│ └── loadbalance
│ │ └── loadbalance.go
├── pb
│ ├── user.proto
│ ├── seckill.proto
│ ├── oauth.proto
│ └── activity.proto
├── user-service
│ ├── bootstrap.yaml
│ ├── user-script.sql
│ ├── transport
│ │ ├── grpc.go
│ │ └── user_model.go
│ ├── service
│ │ └── service.go
│ ├── plugins
│ │ ├── logging.go
│ │ └── instrument.go
│ ├── config
│ │ └── config.go
│ ├── model
│ │ └── user.go
│ └── endpoint
│ │ └── endpoints.go
├── sk-admin
│ ├── bootstrap.yaml
│ ├── setup
│ │ ├── zk.go
│ │ ├── etcd.go
│ │ ├── etcd_test.go
│ │ └── zk_test.go
│ ├── service
│ │ ├── service.go
│ │ └── product.go
│ ├── main.go
│ ├── etcd_test.go
│ ├── model
│ │ └── product.go
│ └── config
│ │ └── config.go
├── sk-app
│ ├── bootstrap.yaml
│ ├── main.go
│ ├── service
│ │ ├── srv_limit
│ │ │ ├── sec_limit.go
│ │ │ └── min_limit.go
│ │ ├── srv_err
│ │ │ └── error.go
│ │ └── srv_redis
│ │ │ └── redis_proc.go
│ ├── model
│ │ └── model.go
│ ├── plugins
│ │ └── logging.go
│ └── setup
│ │ └── zk.go
├── oauth-service
│ ├── bootstrap.yaml
│ ├── model
│ │ ├── user.go
│ │ └── token.go
│ ├── service
│ │ ├── common_service.go
│ │ ├── client_service.go
│ │ └── user_service.go
│ ├── oauth-script.sql
│ ├── transport
│ │ └── grpc.go
│ ├── plugins
│ │ └── instrument.go
│ ├── config
│ │ └── config.go
│ └── client_test.go
├── gateway
│ ├── bootstrap.yaml
│ └── config
│ │ ├── AuthPermission.go
│ │ └── config.go
└── README.md
├── ch4-feature
├── main
│ ├── hello.go
│ └── main.go
├── compute
│ └── add.go
├── concurrency
│ ├── first_concurrency.go
│ └── channel.go
└── synch
│ ├── wait_group.go
│ ├── mutex.go
│ ├── rw_mutex.go
│ └── sync_map.go
├── ch5-web
├── SimpleServer.go
├── forms
│ └── login.tpl
├── mysql
│ └── script.sql
├── helloweb.go
├── writeresponse.go
├── beego
│ └── main.go
├── webForm.go
├── memory
│ └── memory.go
├── mongo
│ └── mongo.go
└── gin
│ └── main.go
├── ch8-config
├── config
│ └── resume_config.yaml
├── resume.go
└── ViperDemo.go
├── ch11-security
├── model
│ ├── user.go
│ ├── client.go
│ └── token.go
├── config
│ └── config.go
└── service
│ ├── common_service.go
│ ├── user_service.go
│ └── client_service.go
├── ch7-rpc
├── README.md
├── pb
│ └── string.proto
├── basic
│ ├── server.go
│ ├── client.go
│ └── string-service
│ │ └── service.go
├── stream-pb
│ └── stream_string.proto
├── stream
│ ├── server.go
│ ├── string-service
│ │ └── service.go
│ └── client.go
├── grpc
│ ├── server.go
│ ├── client.go
│ └── string-service
│ │ └── service.go
└── go-kit
│ ├── server.go
│ ├── client.go
│ └── string-service
│ ├── logging.go
│ ├── service.go
│ └── transports.go
├── ch12-trace
├── zipkin-go
│ └── string-services
│ │ ├── Makefile
│ │ ├── svc2
│ │ ├── service.go
│ │ ├── httpserver.go
│ │ ├── cmd
│ │ │ └── main.go
│ │ ├── httpclient.go
│ │ └── implementation.go
│ │ ├── svc1
│ │ ├── service.go
│ │ ├── implementation.go
│ │ ├── cmd
│ │ │ └── main.go
│ │ └── httpserver.go
│ │ └── README.md
├── README.md
└── zipkin-kit
│ ├── pb
│ └── string.proto
│ ├── docker
│ ├── prometheus.yml
│ └── docker-compose.yml
│ ├── client
│ ├── string.go
│ └── stringModel.go
│ ├── string-service
│ ├── grpc.go
│ ├── register.go
│ ├── logging.go
│ └── service
│ │ └── service.go
│ └── cmd
│ └── client_test.go
├── ch3-basic
├── Callback.go
├── Variable.go
├── Embed.go
├── Anonymous.go
├── List.go
├── Map.go
├── Flag.go
├── Array.go
├── FunctionImplementor.go
├── Counter.go
├── Foreach.go
├── Pointer.go
├── Compose.go
├── Slice.go
├── StructImplementor.go
├── TypeAlias.go
├── Append.go
├── Person.go
└── HelloGo.go
├── ch6-discovery
├── config
│ └── config.go
├── string-service
│ ├── config
│ │ └── config.go
│ ├── plugins
│ │ └── logging.go
│ ├── service
│ │ └── service.go
│ └── endpoint
│ │ └── endpoints.go
├── discover
│ └── discover_client.go
├── service
│ └── service.go
└── endpoint
│ └── endpoints.go
├── ch10-resiliency
├── string-service
│ ├── config
│ │ └── config.go
│ ├── plugins
│ │ └── logging.go
│ ├── service
│ │ └── service.go
│ ├── endpoint
│ │ └── endpoints.go
│ └── transport
│ │ └── http.go
├── use-string-service
│ ├── config
│ │ └── config.go
│ ├── plugins
│ │ └── logging.go
│ └── endpoint
│ │ └── endpoints.go
├── hystrix-example.go
└── gateway.go
├── README.md
├── common
├── loadbalance
│ ├── loadbalance_test.go
│ └── loadbalance.go
└── discover
│ └── discover_client.go
├── LICENSE
└── ch9-gateway
└── string-service
├── register.go
├── logging.go
├── service.go
├── endpoints.go
├── main.go
└── transports.go
/ch13-seckill/架构图.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/longjoy/micro-go-book/HEAD/ch13-seckill/架构图.jpeg
--------------------------------------------------------------------------------
/ch13-seckill/framework.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/longjoy/micro-go-book/HEAD/ch13-seckill/framework.png
--------------------------------------------------------------------------------
/ch4-feature/main/hello.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import "fmt"
4 |
5 | func sayHello() {
6 | fmt.Println("Hello World")
7 | }
--------------------------------------------------------------------------------
/ch5-web/SimpleServer.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import "net/http"
4 |
5 | func main() {
6 | http.ListenAndServe("127.0.0.1:8080",nil)
7 | }
8 |
--------------------------------------------------------------------------------
/ch8-config/config/resume_config.yaml:
--------------------------------------------------------------------------------
1 | RegisterTime: "2019-6-18 10:00:00"
2 | Address: "Shanghai"
3 | ResumeInformation:
4 | Name: "aoho"
5 | Sex: "male"
6 | Age: 20
7 | Habits:
8 | - "Basketball"
9 | - "Running"
10 |
--------------------------------------------------------------------------------
/ch11-security/model/user.go:
--------------------------------------------------------------------------------
1 | package model
2 |
3 |
4 | type UserDetails struct {
5 | // 用户标识
6 | UserId int64
7 | // 用户名 唯一
8 | Username string
9 | // 用户密码
10 | Password string
11 | // 用户具有的权限
12 | Authorities []string // 具备的权限
13 | }
14 |
--------------------------------------------------------------------------------
/ch13-seckill/sk-core/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "github.com/longjoy/micro-go-book/ch13-seckill/sk-core/setup"
5 | )
6 |
7 | func main() {
8 |
9 | setup.InitZk()
10 | setup.InitRedis()
11 | setup.RunService()
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/ch13-seckill/pkg/common/service_instance.go:
--------------------------------------------------------------------------------
1 | package common
2 |
3 |
4 | type ServiceInstance struct {
5 | Host string // Host
6 | Port int // Port
7 | Weight int // 权重
8 | CurWeight int // 当前权重
9 |
10 | GrpcPort int
11 | }
12 |
13 |
--------------------------------------------------------------------------------
/ch7-rpc/README.md:
--------------------------------------------------------------------------------
1 | #### 安装 protobuf
2 | rpc 部分涉及到 protobuf
3 |
4 | ```
5 | protoc --version
6 | go get github.com/golang/protobuf
7 | go install github.com/golang/protobuf/protoc-gen-go/
8 | ```
9 |
10 | ```
11 | protoc string.proto --go_out=plugins=grpc:.
12 | ```
--------------------------------------------------------------------------------
/ch4-feature/main/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "github.com/longjoy/micro-go-book/ch4-feature/compute"
6 | )
7 |
8 | func main() {
9 |
10 | params := &compute.IntParams{
11 | P1:1,
12 | P2:2,
13 | }
14 | fmt.Println(params.Add())
15 |
16 | }
--------------------------------------------------------------------------------
/ch12-trace/zipkin-go/string-services/Makefile:
--------------------------------------------------------------------------------
1 | # builds the Cli and Svc1 & Svc2 projects
2 |
3 | all: clean
4 | @go get -v ./...
5 | @go build -v -o build/svc1 ./svc1/cmd
6 | @go build -v -o build/svc2 ./svc2/cmd
7 | @go build -v -o build/cli ./cli
8 |
9 | clean:
10 | @rm -rf build
11 |
--------------------------------------------------------------------------------
/ch5-web/forms/login.tpl:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
11 |
12 |
--------------------------------------------------------------------------------
/ch3-basic/Callback.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import "fmt"
4 |
5 | func proc(input string, processor func(str string)) {
6 | processor(input)
7 | }
8 |
9 | func main() {
10 |
11 | proc("王小二", func(str string) {
12 | for _, v := range str{
13 | fmt.Printf("%c\n", v)
14 | }
15 | })
16 | }
--------------------------------------------------------------------------------
/ch3-basic/Variable.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import "fmt"
4 | func main() {
5 | var a int = 100
6 | var b = "100"
7 | c := 0.17
8 | fmt.Printf("a value is %v, type is %T\n", a, a)
9 | fmt.Printf("b value is %v, type is %T\n", b, b)
10 | fmt.Printf("c value is %v, type is %T\n", c, c)
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/ch12-trace/README.md:
--------------------------------------------------------------------------------
1 | ## start consul
2 |
3 | ```
4 | sudo docker-compose -f docker/docker-compose.yml up
5 | ```
6 |
7 |
8 | ## start register-service
9 |
10 | ```
11 | ./register -consul.host localhost -consul.port 8500 -service.host 192.168.1.100 -service.port 9000
12 | ```
13 |
14 | ## start discover-service
--------------------------------------------------------------------------------
/ch13-seckill/sk-core/service/srv_err/error.go:
--------------------------------------------------------------------------------
1 | package srv_err
2 |
3 | const (
4 | ErrServiceBusy = 1001
5 | ErrSecKillSucc = 1002
6 | ErrNotFoundProduct = 1003
7 | ErrSoldout = 1004
8 | ErrRetry = 1005
9 | ErrAlreadyBuy = 1006
10 | )
11 |
12 | const (
13 | ProductStatusSoldout = 2001
14 | )
15 |
--------------------------------------------------------------------------------
/ch3-basic/Embed.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import "fmt"
4 |
5 | type Wheel struct {
6 | shape string
7 | }
8 |
9 | type Car struct {
10 | Wheel
11 | Name string
12 | }
13 |
14 | func main() {
15 |
16 | car := &Car{
17 | Wheel{
18 | "圆形的",
19 | },
20 | "福特",
21 | }
22 | fmt.Println(car.Name, car.shape, " ")
23 | }
24 |
--------------------------------------------------------------------------------
/ch4-feature/compute/add.go:
--------------------------------------------------------------------------------
1 | package compute
2 |
3 | type AddOperator interface {
4 |
5 | /**
6 | * 算术增加
7 | */
8 | Add() interface{}
9 |
10 | }
11 |
12 | type IntParams struct{
13 | P1 int // 加数
14 | P2 int // 被加数
15 | }
16 |
17 | func (params *IntParams) Add() interface{} {
18 | return params.P1 + params.P2
19 | }
20 |
21 |
22 |
--------------------------------------------------------------------------------
/ch5-web/mysql/script.sql:
--------------------------------------------------------------------------------
1 | create database user;
2 |
3 | drop table if exists `user`;
4 | CREATE TABLE `user`
5 | (
6 | `id` INT(10) NOT NULL AUTO_INCREMENT,
7 | `name` VARCHAR(64) NULL DEFAULT NULL,
8 | `habits` VARCHAR(128) NULL DEFAULT NULL,
9 | `created_time` DATE NULL DEFAULT NULL,
10 | PRIMARY KEY (`id`)
11 | );
--------------------------------------------------------------------------------
/ch13-seckill/pb/user.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package pb;
4 |
5 | service UserService{
6 | rpc Check(UserRequest) returns (UserResponse){}
7 | }
8 |
9 | message UserRequest {
10 | string username = 1;
11 | string password = 2;
12 | }
13 |
14 | message UserResponse {
15 | bool result = 1;
16 | int64 userId = 2;
17 | string err = 3;
18 | }
--------------------------------------------------------------------------------
/ch3-basic/Anonymous.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | // 返回一个人的姓和名
4 | func getName() (string, string){
5 | return "王", "小二"
6 | }
7 |
8 | func main() {
9 | //surname,_ := getName() // 使用匿名变量
10 | //_, personalName := getName() // 使用匿名变量
11 | //
12 | //fmt.Printf("My surname is %v and my personal name is %v", surname, personalName)
13 |
14 |
15 |
16 |
17 |
18 | }
19 |
--------------------------------------------------------------------------------
/ch12-trace/zipkin-kit/pb/string.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package pb;
4 |
5 | service StringService{
6 | rpc Diff(StringRequest) returns (StringResponse){}
7 | }
8 |
9 | message StringRequest {
10 | string request_type = 1;
11 | string a = 2;
12 | string b = 3;
13 | }
14 |
15 | message StringResponse {
16 | string result = 1;
17 | string err = 2;
18 | }
--------------------------------------------------------------------------------
/ch13-seckill/sk-core/bootstrap.yaml:
--------------------------------------------------------------------------------
1 | http:
2 | host: localhost
3 | port: 9032
4 |
5 | rpc:
6 | host: localhost
7 | port: 9132
8 |
9 | discover:
10 | Host: 114.67.98.210
11 | port: 8500
12 | instanceId: sk-core-localhost
13 | serviceName: sk-core # 要缓存sk-app
14 | weight: 10
15 |
16 |
17 | config:
18 | id: config-service
19 | profile: "dev"
20 | label: "master"
--------------------------------------------------------------------------------
/ch13-seckill/user-service/bootstrap.yaml:
--------------------------------------------------------------------------------
1 |
2 | http:
3 | host: 114.67.98.210
4 | port: 9009
5 |
6 | rpc:
7 | host: localhost
8 | port: 9108
9 |
10 | discover:
11 | Host: 114.67.98.210
12 | port: 8500
13 | instanceId: user-service-localhost
14 | serviceName: user
15 | weight: 10
16 |
17 | config:
18 | id: config-service
19 | profile: "dev"
20 | label: "master"
--------------------------------------------------------------------------------
/ch13-seckill/sk-admin/bootstrap.yaml:
--------------------------------------------------------------------------------
1 |
2 | http:
3 | host: localhost
4 | port: 9030
5 |
6 | rpc:
7 | host: localhost
8 | port: 9132
9 |
10 | discover:
11 | Host: 114.67.98.210
12 | port: 8500
13 | instanceId: sk-admin-localhost
14 | serviceName: sk-admin
15 | weight: 10
16 |
17 |
18 | config:
19 | id: config-service
20 | profile: "dev"
21 | label: "master"
22 |
--------------------------------------------------------------------------------
/ch13-seckill/sk-app/bootstrap.yaml:
--------------------------------------------------------------------------------
1 |
2 | http:
3 | host: localhost
4 | port: 9031
5 |
6 |
7 | rpc:
8 | host: localhost
9 | port: 9132
10 |
11 | discover:
12 | Host: 114.67.98.210
13 | port: 8500
14 | instanceId: sk-app-localhost
15 | serviceName: sk-app # 要缓存sk-app
16 | weight: 10
17 |
18 |
19 | config:
20 | id: config-service
21 | profile: "dev"
22 | label: "master"
--------------------------------------------------------------------------------
/ch13-seckill/oauth-service/bootstrap.yaml:
--------------------------------------------------------------------------------
1 |
2 | http:
3 | host: 114.67.98.210
4 | port: 9019
5 |
6 |
7 | rpc:
8 | host: localhost
9 | port: 9018
10 |
11 |
12 | discover:
13 | Host: 114.67.98.210
14 | port: 8500
15 | instanceId: oauth-service-localhost
16 | serviceName: oauth
17 | weight: 10
18 |
19 | config:
20 | id: config-service
21 | profile: "dev"
22 | label: "master"
--------------------------------------------------------------------------------
/ch11-security/model/client.go:
--------------------------------------------------------------------------------
1 | package model
2 |
3 |
4 | type ClientDetails struct {
5 | // client 的标识
6 | ClientId string
7 | // client 的密钥
8 | ClientSecret string
9 | // 访问令牌有效时间,秒
10 | AccessTokenValiditySeconds int
11 | // 刷新令牌有效时间,秒
12 | RefreshTokenValiditySeconds int
13 | // 重定向地址,授权码类型中使用
14 | RegisteredRedirectUri string
15 | // 可以使用的授权类型
16 | AuthorizedGrantTypes []string
17 | }
18 |
--------------------------------------------------------------------------------
/ch3-basic/List.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "container/list"
5 | "fmt"
6 | )
7 |
8 | func main() {
9 |
10 |
11 | tmpList := list.New()
12 |
13 | for i:= 1 ; i <= 10 ; i++ {
14 | tmpList.PushBack(i)
15 | }
16 |
17 | first := tmpList.PushFront(0)
18 | tmpList.Remove(first)
19 |
20 | for l := tmpList.Front(); l != nil; l = l.Next(){
21 | fmt.Print(l.Value, " ")
22 | }
23 |
24 | }
25 |
--------------------------------------------------------------------------------
/ch7-rpc/pb/string.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package pb;
4 |
5 | service StringService{
6 | rpc Concat(StringRequest) returns (StringResponse) {}
7 | rpc Diff(StringRequest) returns (StringResponse) {}
8 |
9 | }
10 |
11 | message StringRequest {
12 | string A = 1;
13 | string B = 2;
14 | }
15 |
16 | message StringResponse {
17 | string Ret = 1;
18 | string err = 2;
19 | }
20 |
--------------------------------------------------------------------------------
/ch13-seckill/sk-core/service/service.go:
--------------------------------------------------------------------------------
1 | package service
2 |
3 | // Service Define a service interface
4 | type Service interface {
5 |
6 | // Divide calculate a/b
7 | SecKill() (int, error)
8 | }
9 |
10 | //ArithmeticService implement Service interface
11 | type SecKillService struct {
12 | }
13 |
14 | // Add implement Add method
15 | func (s SecKillService) SecKill(a, b int) int {
16 | return a + b
17 | }
--------------------------------------------------------------------------------
/ch13-seckill/oauth-service/model/user.go:
--------------------------------------------------------------------------------
1 | package model
2 |
3 |
4 | type UserDetails struct {
5 | // 用户标识
6 | UserId int64
7 | // 用户名 唯一
8 | Username string
9 | // 用户密码
10 | Password string
11 | // 用户具有的权限
12 | Authorities []string // 具备的权限
13 | }
14 |
15 |
16 | func (userDetails *UserDetails) IsMatch (username string, password string) bool {
17 |
18 | return userDetails.Password == password && userDetails.Username == username
19 | }
--------------------------------------------------------------------------------
/ch3-basic/Map.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import "fmt"
4 |
5 | func main() {
6 |
7 | classMates1 := make(map[int]string)
8 |
9 | // 添加映射关系
10 | classMates1[0] = "小明"
11 | classMates1[1] = "小红"
12 | classMates1[2] = "小张"
13 |
14 | fmt.Printf("id %v is %v\n", 1, classMates1[1])
15 |
16 | // 在声明时初始化数据
17 | classMates2 := map[int]string{
18 | 0 : "小明",
19 | 1 : "小红",
20 | 2 : "小张",
21 | }
22 |
23 | fmt.Printf("id %v is %v\n", 3, classMates2[3])
24 |
25 | }
--------------------------------------------------------------------------------
/ch3-basic/Flag.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "flag"
5 | "fmt"
6 | )
7 |
8 | func main() {
9 |
10 |
11 | //参数依次是命令行参数的名称,默认值,提示
12 | surname := flag.String("surname", "王", "您的姓")
13 | //除了返回结果,还可以直接传入变量地址获取参数值
14 | var personalName string
15 | flag.StringVar(&personalName, "personalName", "小二", "您的名")
16 | id := flag.Int("id", 0, "您的ID")
17 | //解析命令行参数
18 | flag.Parse()
19 | fmt.Printf("I am %v %v, and my id is %v\n", *surname, personalName, *id)
20 |
21 |
22 | }
--------------------------------------------------------------------------------
/ch13-seckill/sk-admin/setup/zk.go:
--------------------------------------------------------------------------------
1 | package setup
2 |
3 | import (
4 | "fmt"
5 | conf "github.com/longjoy/micro-go-book/ch13-seckill/pkg/config"
6 | "github.com/samuel/go-zookeeper/zk"
7 | "time"
8 | )
9 |
10 | //初始化Etcd
11 | func InitZk() {
12 | var hosts = []string{"39.98.179.73:2181"}
13 | conn, _, err := zk.Connect(hosts, time.Second*5)
14 | if err != nil {
15 | fmt.Println(err)
16 | return
17 | }
18 | conf.Zk.ZkConn = conn
19 | conf.Zk.SecProductKey = "/product"
20 | }
21 |
--------------------------------------------------------------------------------
/ch13-seckill/user-service/user-script.sql:
--------------------------------------------------------------------------------
1 | create database user;
2 |
3 | drop table if exists `user`;
4 | CREATE TABLE `user`
5 | (
6 | `user_id` INT(10) NOT NULL AUTO_INCREMENT,
7 | `user_name` VARCHAR(64) NULL DEFAULT NULL,
8 | `password` VARCHAR(128) NULL DEFAULT NULL,
9 | `age` INT(10) NULL DEFAULT NULL,
10 |
11 |
12 | PRIMARY KEY (`user_id`)
13 | );
14 |
15 | insert into user (`user_name`, `password`, `age`) values ('user', 'password', 25);
--------------------------------------------------------------------------------
/ch13-seckill/oauth-service/service/common_service.go:
--------------------------------------------------------------------------------
1 | package service
2 |
3 |
4 |
5 | type Service interface {
6 | // HealthCheck check service health status
7 | HealthCheck() bool
8 | }
9 |
10 | type CommentService struct {
11 |
12 | }
13 |
14 | // HealthCheck implement Service method
15 | // 用于检查服务的健康状态,这里仅仅返回true
16 | func (s *CommentService) HealthCheck() bool {
17 | return true
18 | }
19 |
20 | func NewCommentService() *CommentService {
21 | return &CommentService{}
22 | }
23 |
24 |
--------------------------------------------------------------------------------
/ch13-seckill/sk-app/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "github.com/longjoy/micro-go-book/ch13-seckill/pkg/bootstrap"
5 | "github.com/longjoy/micro-go-book/ch13-seckill/sk-app/setup"
6 | )
7 |
8 | func main() {
9 | //mysql.InitMysql(conf.MysqlConfig.Host, conf.MysqlConfig.Port, conf.MysqlConfig.User, conf.MysqlConfig.Pwd, conf.MysqlConfig.Db) // conf.MysqlConfig.Db
10 | setup.InitZk()
11 | setup.InitRedis()
12 | setup.InitServer(bootstrap.HttpConfig.Host, bootstrap.HttpConfig.Port)
13 | }
14 |
--------------------------------------------------------------------------------
/ch6-discovery/config/config.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | import (
4 | kitlog "github.com/go-kit/kit/log"
5 | "log"
6 | "os"
7 | )
8 |
9 |
10 | var Logger *log.Logger
11 | var KitLogger kitlog.Logger
12 |
13 |
14 | func init() {
15 | Logger = log.New(os.Stderr, "", log.LstdFlags)
16 |
17 | KitLogger = kitlog.NewLogfmtLogger(os.Stderr)
18 | KitLogger = kitlog.With(KitLogger, "ts", kitlog.DefaultTimestampUTC)
19 | KitLogger = kitlog.With(KitLogger, "caller", kitlog.DefaultCaller)
20 |
21 | }
22 |
23 |
--------------------------------------------------------------------------------
/ch12-trace/zipkin-go/string-services/svc2/service.go:
--------------------------------------------------------------------------------
1 | // +build go1.7
2 |
3 | package svc2
4 |
5 | import (
6 | "context"
7 | "errors"
8 | )
9 |
10 | // Service constants
11 | const (
12 | Int64Max = 1<<63 - 1
13 | Int64Min = -(Int64Max + 1)
14 | )
15 |
16 | // Service errors
17 | var (
18 | ErrIntOverflow = errors.New("integer overflow occurred")
19 | )
20 |
21 | // Service interface to our svc2 service.
22 | type Service interface {
23 | Sum(ctx context.Context, a int64, b int64) (int64, error)
24 | }
25 |
--------------------------------------------------------------------------------
/ch13-seckill/sk-admin/service/service.go:
--------------------------------------------------------------------------------
1 | package service
2 |
3 | // Service Define a service interface
4 | type Service interface {
5 | // HealthCheck check service health status
6 | HealthCheck() bool
7 | }
8 |
9 | //UserService implement Service interface
10 | type SkAdminService struct {
11 | }
12 |
13 | // HealthCheck implement Service method
14 | // 用于检查服务的健康状态,这里仅仅返回true
15 | func (s SkAdminService) HealthCheck() bool {
16 | return true
17 | }
18 |
19 | type ServiceMiddleware func(Service) Service
20 |
--------------------------------------------------------------------------------
/ch4-feature/concurrency/first_concurrency.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | )
6 |
7 | func setVTo1(v *int) {
8 |
9 | *v = 1
10 | }
11 |
12 | func setVTo2(v *int) {
13 | *v = 2
14 | }
15 |
16 | func main() {
17 |
18 | v := new(int)
19 | go setVTo1(v)
20 | go setVTo2(v)
21 | fmt.Println(*v)
22 |
23 |
24 | //go func(name string) {
25 | // fmt.Println("Hello " + name )
26 | //}("xuan")
27 | //// 主 goroutine 阻塞 1 s
28 | //time.Sleep(time.Second)
29 |
30 | }
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/ch11-security/config/config.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | import (
4 | kitlog "github.com/go-kit/kit/log"
5 | "log"
6 | "os"
7 | )
8 |
9 |
10 | var Logger *log.Logger
11 | var KitLogger kitlog.Logger
12 |
13 |
14 | func init() {
15 | Logger = log.New(os.Stderr, "", log.LstdFlags)
16 |
17 | KitLogger = kitlog.NewLogfmtLogger(os.Stderr)
18 | KitLogger = kitlog.With(KitLogger, "ts", kitlog.DefaultTimestampUTC)
19 | KitLogger = kitlog.With(KitLogger, "caller", kitlog.DefaultCaller)
20 |
21 |
22 | }
23 |
24 |
25 |
--------------------------------------------------------------------------------
/ch12-trace/zipkin-go/string-services/svc1/service.go:
--------------------------------------------------------------------------------
1 | // +build go1.7
2 |
3 | package svc1
4 |
5 | import (
6 | "context"
7 | "errors"
8 | )
9 |
10 | // Service constants
11 | const (
12 | StrMaxSize = 1024
13 | )
14 |
15 | // Service errors
16 | var (
17 | ErrMaxSize = errors.New("maximum size of 1024 bytes exceeded")
18 | )
19 |
20 | // Service interface
21 | type Service interface {
22 | Concat(ctx context.Context, a, b string) (string, error)
23 | Sum(ctx context.Context, a, b int64) (int64, error)
24 | }
25 |
--------------------------------------------------------------------------------
/ch10-resiliency/string-service/config/config.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | import (
4 | kitlog "github.com/go-kit/kit/log"
5 | "log"
6 | "os"
7 | )
8 |
9 |
10 | var Logger *log.Logger
11 | var KitLogger kitlog.Logger
12 |
13 |
14 | func init() {
15 | Logger = log.New(os.Stderr, "", log.LstdFlags)
16 |
17 | KitLogger = kitlog.NewLogfmtLogger(os.Stderr)
18 | KitLogger = kitlog.With(KitLogger, "ts", kitlog.DefaultTimestampUTC)
19 | KitLogger = kitlog.With(KitLogger, "caller", kitlog.DefaultCaller)
20 |
21 |
22 | }
23 |
24 |
25 |
--------------------------------------------------------------------------------
/ch6-discovery/string-service/config/config.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | import (
4 | kitlog "github.com/go-kit/kit/log"
5 | "log"
6 | "os"
7 | )
8 |
9 |
10 | var Logger *log.Logger
11 | var KitLogger kitlog.Logger
12 |
13 |
14 | func init() {
15 | Logger = log.New(os.Stderr, "", log.LstdFlags)
16 |
17 | KitLogger = kitlog.NewLogfmtLogger(os.Stderr)
18 | KitLogger = kitlog.With(KitLogger, "ts", kitlog.DefaultTimestampUTC)
19 | KitLogger = kitlog.With(KitLogger, "caller", kitlog.DefaultCaller)
20 |
21 |
22 | }
23 |
24 |
25 |
--------------------------------------------------------------------------------
/ch10-resiliency/use-string-service/config/config.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | import (
4 | kitlog "github.com/go-kit/kit/log"
5 | "log"
6 | "os"
7 | )
8 |
9 |
10 | var Logger *log.Logger
11 | var KitLogger kitlog.Logger
12 |
13 |
14 | func init() {
15 | Logger = log.New(os.Stderr, "", log.LstdFlags)
16 |
17 | KitLogger = kitlog.NewLogfmtLogger(os.Stderr)
18 | KitLogger = kitlog.With(KitLogger, "ts", kitlog.DefaultTimestampUTC)
19 | KitLogger = kitlog.With(KitLogger, "caller", kitlog.DefaultCaller)
20 |
21 |
22 | }
23 |
24 |
25 |
--------------------------------------------------------------------------------
/ch11-security/model/token.go:
--------------------------------------------------------------------------------
1 | package model
2 |
3 | import "time"
4 |
5 | type OAuth2Token struct {
6 |
7 | // 刷新令牌
8 | RefreshToken *OAuth2Token
9 | // 令牌类型
10 | TokenType string
11 | // 令牌
12 | TokenValue string
13 | // 过期时间
14 | ExpiresTime *time.Time
15 |
16 | }
17 |
18 |
19 | func (oauth2Token *OAuth2Token) IsExpired() bool {
20 | return oauth2Token.ExpiresTime != nil &&
21 | oauth2Token.ExpiresTime.Before(time.Now())
22 | }
23 |
24 | type OAuth2Details struct {
25 | Client *ClientDetails
26 | User *UserDetails
27 | }
--------------------------------------------------------------------------------
/ch12-trace/zipkin-kit/docker/prometheus.yml:
--------------------------------------------------------------------------------
1 | global:
2 | scrape_interval: 15s
3 | external_labels:
4 | monitor: 'string-service-monitor'
5 |
6 | scrape_configs:
7 | - job_name: 'prometheus'
8 | scrape_interval: 5s
9 | static_configs:
10 | - targets: ['localhost:9090']
11 | labels:
12 | group: 'local'
13 |
14 | - job_name: 'string-service'
15 | scrape_interval: 5s
16 | static_configs:
17 | - targets: ['localhost:9000']
18 | labels:
19 | group: 'string-service'
20 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## Go语言高并发与微服务实战
2 | 近年来云原生技术发展迅猛,帮助开发者在云上快速和频繁地构建、发布和部署应用,以提高开发效率和快速定位故障。
3 |
4 | 微服务作为开展云原生技术落地的核心,它将复杂的单体应用按照业务划分并进行有效地拆分,每个微服务都可以进行独立部署和开发,大大提升了应用开发效率。Go语言作为新生代的编译型编程语言,具备语法简单、高并发性能良好和编译速度快等特点,是微服务架构落地实践的绝妙利器。
5 |
6 | 本书围绕云原生、微服务和Go语言,介绍如何通过Go语言进行微服务架构开发与实践。旨在帮助读者深入理解微服务架构并使用Go语言快速加入到微服务开发中。
7 |
8 | ### 环境搭建
9 |
10 | #### golang 安装
11 | 本书基于的 Go 版本为 1.12.4,使用 go mod 管理依赖。具体使用可参见本书基础部分。
12 |
13 | #### setup
14 |
15 | ```sh
16 | go mod tidy
17 | ```
18 | ### Q&A
19 | 如有问题,可在 [链接](https://github.com/longjoy/micro-go-book) 提出 issue。
20 |
--------------------------------------------------------------------------------
/ch3-basic/Array.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import "fmt"
4 |
5 | func main() {
6 |
7 | var classMates1 [3]string
8 |
9 | classMates1[0] = "小明"
10 | classMates1[1] = "小红"
11 | classMates1[2] = "小李"
12 | fmt.Println(classMates1)
13 | fmt.Println("The No.1 student is " + classMates1[0])
14 |
15 | classMates2 := [...]string{"小明", "小红", "小李"}
16 | fmt.Println(classMates2)
17 |
18 |
19 | classMates3 := new([3]string)
20 | classMates3[0] = "小明"
21 | classMates3[1] = "小红"
22 | classMates3[2] = "小李"
23 | fmt.Println(*classMates3)
24 |
25 |
26 | }
--------------------------------------------------------------------------------
/ch3-basic/FunctionImplementor.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import "fmt"
4 |
5 | type Printer interface {
6 | Print(p interface{})
7 | }
8 |
9 |
10 | // 函数定义为类型
11 | type FuncCaller func(p interface{})
12 |
13 | // 实现Printer的Print方法
14 | func (funcCaller FuncCaller) Print(p interface{}) {
15 | // 调用funcCaller函数本体
16 | funcCaller(p)
17 | }
18 |
19 | func main() {
20 | var printer Printer
21 | // 将匿名函数强转为FuncCaller赋值给printer
22 | printer = FuncCaller(func(p interface{}) {
23 | fmt.Println(p)
24 | })
25 | printer.Print("Golang is Good!")
26 | }
27 |
--------------------------------------------------------------------------------
/ch13-seckill/sk-core/setup/redis.go:
--------------------------------------------------------------------------------
1 | package setup
2 |
3 | import (
4 | "github.com/go-redis/redis"
5 | conf "github.com/longjoy/micro-go-book/ch13-seckill/pkg/config"
6 | "log"
7 | )
8 |
9 | //初始化redis
10 | func InitRedis() {
11 | client := redis.NewClient(&redis.Options{
12 | Addr: conf.Redis.Host,
13 | Password: conf.Redis.Password,
14 | DB: conf.Redis.Db,
15 | })
16 |
17 | _, err := client.Ping().Result()
18 | if err != nil {
19 | log.Printf("Connect redis failed. Error : %v", err)
20 | }
21 | conf.Redis.RedisConn = client
22 | }
23 |
--------------------------------------------------------------------------------
/ch13-seckill/gateway/bootstrap.yaml:
--------------------------------------------------------------------------------
1 |
2 | http:
3 | host: 114.67.98.210
4 | port: 9090
5 |
6 |
7 | discover:
8 | Host: 114.67.98.210
9 | port: 8500
10 | instanceId: gateway-service-localhost
11 | serviceName: gateway
12 | weight: 10
13 |
14 |
15 | config:
16 | id: config-service
17 | profile: "dev"
18 | label: "master"
19 |
20 | trace:
21 | host: 114.67.98.210
22 | port: 9411
23 | url: /api/v2/spans
24 |
25 | rpc:
26 | port: 1111
27 |
28 | auth:
29 | permitAll:
30 | -
31 | /oauth/**
32 | -
33 | /string/**
34 |
35 |
--------------------------------------------------------------------------------
/ch7-rpc/basic/server.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "github.com/longjoy/micro-go-book/ch7-rpc/basic/string-service"
5 | "log"
6 | "net"
7 | "net/http"
8 | "net/rpc"
9 | )
10 |
11 | func main() {
12 | stringService := new(service.StringService)
13 | registerError := rpc.Register(stringService)
14 | if registerError != nil {
15 | log.Fatal("Register error: ", registerError)
16 | }
17 | rpc.HandleHTTP()
18 | l, e := net.Listen("tcp", "127.0.0.1:1234")
19 | if e != nil {
20 | log.Fatal("listen error:", e)
21 | }
22 | http.Serve(l, nil)
23 | }
24 |
--------------------------------------------------------------------------------
/ch13-seckill/oauth-service/model/token.go:
--------------------------------------------------------------------------------
1 | package model
2 |
3 | import "time"
4 |
5 | type OAuth2Token struct {
6 |
7 | // 刷新令牌
8 | RefreshToken *OAuth2Token
9 | // 令牌类型
10 | TokenType string
11 | // 令牌
12 | TokenValue string
13 | // 过期时间
14 | ExpiresTime *time.Time
15 |
16 | }
17 |
18 |
19 | func (oauth2Token *OAuth2Token) IsExpired() bool {
20 | return oauth2Token.ExpiresTime != nil &&
21 | oauth2Token.ExpiresTime.Before(time.Now())
22 | }
23 |
24 | type OAuth2Details struct {
25 |
26 |
27 | Client *ClientDetails
28 |
29 | User *UserDetails
30 |
31 | }
--------------------------------------------------------------------------------
/ch4-feature/synch/wait_group.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "strconv"
6 | "sync"
7 | "time"
8 | )
9 |
10 | func main() {
11 |
12 | var waitGroup sync.WaitGroup
13 |
14 |
15 | waitGroup.Add(5)
16 |
17 | for i := 0 ; i < 5 ; i++{
18 | go func(i int) {
19 | fmt.Println("work " + strconv.Itoa(i) + " is done at " + time.Now().String())
20 | // 等待 1 s 后减少等待数
21 | time.Sleep(time.Second)
22 | waitGroup.Done()
23 | }(i)
24 | }
25 |
26 | waitGroup.Wait()
27 |
28 | fmt.Println("all works are done at " + time.Now().String())
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/ch13-seckill/sk-admin/setup/etcd.go:
--------------------------------------------------------------------------------
1 | package setup
2 |
3 | import (
4 | "github.com/coreos/etcd/clientv3"
5 | conf "github.com/longjoy/micro-go-book/ch13-seckill/pkg/config"
6 | "log"
7 | "time"
8 | )
9 |
10 | //初始化Etcd
11 | func InitEtcd() {
12 |
13 | cli, err := clientv3.New(clientv3.Config{
14 | Endpoints: []string{"39.98.179.73:2379"}, // conf.Etcd.Host
15 | DialTimeout: 5 * time.Second,
16 | })
17 | if err != nil {
18 | log.Printf("Connect etcd failed. Error : %v", err)
19 | }
20 | conf.Etcd.EtcdSecProductKey = "product"
21 | conf.Etcd.EtcdConn = cli
22 | }
23 |
--------------------------------------------------------------------------------
/ch13-seckill/sk-core/service/srv_limit/sec_limit.go:
--------------------------------------------------------------------------------
1 | package srv_limit
2 |
3 | //每秒限制
4 | type SecLimit struct {
5 | count int //次数
6 | preTime int64 //上一次记录时间
7 | }
8 |
9 | //当前秒的访问次数
10 | func (p *SecLimit) Count(nowTime int64) (curCount int) {
11 | if p.preTime != nowTime {
12 | p.count = 1
13 | p.preTime = nowTime
14 | curCount = p.count
15 | return
16 | }
17 |
18 | p.count++
19 | curCount = p.count
20 | return
21 | }
22 |
23 | func (p *SecLimit) Check(nowTime int64) int {
24 | if p.preTime != nowTime {
25 | return 0
26 | }
27 | return p.count
28 | }
29 |
--------------------------------------------------------------------------------
/ch8-config/resume.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "github.com/longjoy/micro-go-book/ch8-config/conf"
6 | "github.com/spf13/viper"
7 | "log"
8 | "net/http"
9 | )
10 |
11 | func main() {
12 | http.HandleFunc("/resumes", func(w http.ResponseWriter, req *http.Request) {
13 | //q := events.goreq.URL.Query().Get("q")
14 | _, _ = fmt.Fprintf(w, "个人信息:\n")
15 | _, _ = fmt.Fprintf(w, "姓名:%s,\n性别:%s,\n年龄 %d!", viper.GetString("resume.name"), conf.Resume.Sex, conf.Resume.Age) //这个写入到w的是输出到客户端的
16 | })
17 | log.Fatal(http.ListenAndServe(":8081", nil))
18 | }
19 |
20 |
--------------------------------------------------------------------------------
/ch3-basic/Counter.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import "fmt"
4 |
5 |
6 | type Tank interface{
7 | Walk()
8 | Fire()
9 | }
10 |
11 | func createCounter(initial int) func() int {
12 |
13 | if initial < 0{
14 | initial = 0
15 | }
16 |
17 | // 引用initial,创建一个闭包
18 | return func() int{
19 | initial++
20 | // 返回当前计数
21 | return initial;
22 | }
23 |
24 | }
25 |
26 | func main() {
27 |
28 | // 计数器1
29 | c1 := createCounter(1)
30 |
31 | fmt.Println(c1()) // 2
32 | fmt.Println(c1()) // 3
33 |
34 | // 计数器2
35 | c2 := createCounter(10)
36 |
37 | fmt.Println(c2()) // 11
38 | fmt.Println(c1()) // 4
39 |
40 | }
--------------------------------------------------------------------------------
/ch7-rpc/stream-pb/stream_string.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package stream_pb;
4 |
5 | service StringService{
6 | rpc Concat(StringRequest) returns (StringResponse) {}
7 | rpc LotsOfServerStream(StringRequest) returns (stream StringResponse) {}
8 | rpc LotsOfClientStream(stream StringRequest) returns (StringResponse) {}
9 | rpc LotsOfServerAndClientStream(stream StringRequest) returns (stream StringResponse) {}
10 | }
11 |
12 | message StringRequest {
13 | string A = 1;
14 | string B = 2;
15 | }
16 |
17 | message StringResponse {
18 | string Ret = 1;
19 | string err = 2;
20 | }
21 |
--------------------------------------------------------------------------------
/common/loadbalance/loadbalance_test.go:
--------------------------------------------------------------------------------
1 | package loadbalance
2 |
3 | //func TestMain(m *testing.M) {
4 | // instances := make([]*discover.ServiceInstance, 10)
5 | // for i := 0; i < len(instances); i++ {
6 | // instances[i] = &discover.ServiceInstance{
7 | // Host: string(i),
8 | // Port: i,
9 | // GrpcPort: (i + 1),
10 | // Weight: i,
11 | // CurWeight: 0,
12 | // }
13 | // }
14 | //
15 | // load := &WeightRoundRobinLoadBalance{}
16 | // for i := 0; i < 2*len(instances); i++ {
17 | // service, _ := load.SelectService(instances)
18 | // fmt.Println("service is : ", service.Host)
19 | // }
20 | //
21 | //}
22 |
--------------------------------------------------------------------------------
/ch13-seckill/sk-admin/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "github.com/longjoy/micro-go-book/ch13-seckill/pkg/bootstrap"
5 | conf "github.com/longjoy/micro-go-book/ch13-seckill/pkg/config"
6 | "github.com/longjoy/micro-go-book/ch13-seckill/pkg/mysql"
7 | "github.com/longjoy/micro-go-book/ch13-seckill/sk-admin/setup"
8 | )
9 |
10 | func main() {
11 | mysql.InitMysql(conf.MysqlConfig.Host, conf.MysqlConfig.Port, conf.MysqlConfig.User, conf.MysqlConfig.Pwd, conf.MysqlConfig.Db) // conf.MysqlConfig.Db
12 | //setup.InitEtcd()
13 | setup.InitZk()
14 | setup.InitServer(bootstrap.HttpConfig.Host, bootstrap.HttpConfig.Port)
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/ch7-rpc/stream/server.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "flag"
5 | pb "github.com/longjoy/micro-go-book/ch7-rpc/stream-pb"
6 | "github.com/longjoy/micro-go-book/ch7-rpc/stream/string-service"
7 | "github.com/prometheus/common/log"
8 | "google.golang.org/grpc"
9 | "net"
10 | )
11 |
12 | func main() {
13 | flag.Parse()
14 | lis, err := net.Listen("tcp", "127.0.0.1:1234")
15 | if err != nil {
16 | log.Fatalf("failed to listen: %v", err)
17 | }
18 | grpcServer := grpc.NewServer()
19 | stringService := new(string_service.StringService)
20 | pb.RegisterStringServiceServer(grpcServer, stringService)
21 | grpcServer.Serve(lis)
22 | }
23 |
--------------------------------------------------------------------------------
/ch13-seckill/pkg/config/need_config.conf:
--------------------------------------------------------------------------------
1 | ### 秒杀性能配置
2 |
3 | service:
4 | ip_sec_access_limit: 1000
5 | ip_min_access_limit: 1000
6 | user_sec_access_limit: 1000
7 | user_min_access_limit: 1000
8 | write_proxy2layer_goroutine_num: 100
9 | read_proxy2layer_goroutine_num: 100
10 | cookie_secretkey: zxfyazzaa
11 | refer_whitelist:
12 | - test
13 |
14 |
15 | redis:
16 | host: localhost
17 | password: 6378
18 | db: 0
19 | proxy2layer_queue_name: name
20 | ip_black_list_hash: 12
21 | id_black_list_queue: 12
22 |
23 | etcd:
24 | host: localhost
25 | product_key: zxfyazzaa
26 |
27 | http:
28 | host: localhost
29 |
30 |
--------------------------------------------------------------------------------
/ch7-rpc/grpc/server.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "flag"
5 | string_service "github.com/longjoy/micro-go-book/ch7-rpc/grpc/string-service"
6 | "github.com/longjoy/micro-go-book/ch7-rpc/pb"
7 | "github.com/prometheus/common/log"
8 | "google.golang.org/grpc"
9 | "net"
10 | )
11 |
12 | func main() {
13 | flag.Parse()
14 | lis, err := net.Listen("tcp", "127.0.0.1:1234")
15 | if err != nil {
16 | log.Fatalf("failed to listen: %v", err)
17 | }
18 | grpcServer := grpc.NewServer()
19 | stringService := new(string_service.StringService)
20 | pb.RegisterStringServiceServer(grpcServer, stringService)
21 | grpcServer.Serve(lis)
22 | }
23 |
--------------------------------------------------------------------------------
/ch7-rpc/grpc/client.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "context"
5 | "fmt"
6 | "github.com/longjoy/micro-go-book/ch7-rpc/pb"
7 | "google.golang.org/grpc"
8 | )
9 |
10 | func main() {
11 | serviceAddress := "127.0.0.1:1234"
12 | conn, err := grpc.Dial(serviceAddress, grpc.WithInsecure())
13 | if err != nil {
14 | panic("connect error")
15 | }
16 | defer conn.Close()
17 | bookClient := pb.NewStringServiceClient(conn)
18 | stringReq := &pb.StringRequest{A: "A", B: "B"}
19 | reply, _ := bookClient.Concat(context.Background(), stringReq)
20 | fmt.Printf("StringService Concat : %s concat %s = %s\n", stringReq.A, stringReq.B, reply.Ret)
21 | }
22 |
--------------------------------------------------------------------------------
/ch13-seckill/gateway/config/AuthPermission.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | import (
4 | "regexp"
5 | "strings"
6 | )
7 |
8 | var (
9 | AuthPermitConfig AuthPermitAll
10 | )
11 |
12 | //Http配置
13 | type AuthPermitAll struct {
14 | PermitAll []interface{}
15 | }
16 |
17 | func Match(str string) bool {
18 | if len(AuthPermitConfig.PermitAll) > 0 {
19 | targetValue := AuthPermitConfig.PermitAll
20 | for i := 0; i < len(targetValue); i++ {
21 | s := targetValue[i].(string)
22 | res, _ := regexp.MatchString(strings.ReplaceAll(s, "**", "(.*?)"), str)
23 | if res {
24 | return true
25 | }
26 |
27 | }
28 | }
29 |
30 | return false
31 | }
32 |
--------------------------------------------------------------------------------
/ch13-seckill/sk-app/service/srv_limit/sec_limit.go:
--------------------------------------------------------------------------------
1 | package srv_limit
2 |
3 | type Limit struct {
4 | secLimit TimeLimit
5 | minLimit TimeLimit
6 | }
7 |
8 | //秒限制
9 | type SecLimit struct {
10 | count int
11 | curTime int64
12 | }
13 |
14 | //一秒内访问的次数
15 | func (p *SecLimit) Count(nowTime int64) (curCount int) {
16 | if p.curTime != nowTime {
17 | p.count = 1
18 | p.curTime = nowTime
19 | curCount = p.count
20 | return
21 | }
22 |
23 | p.count++
24 | curCount = p.count
25 | return
26 | }
27 |
28 | //检查用户访问的次数
29 | func (p *SecLimit) Check(nowTime int64) int {
30 | if p.curTime != nowTime {
31 | return 0
32 | }
33 | return p.count
34 | }
35 |
--------------------------------------------------------------------------------
/ch3-basic/Foreach.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | )
6 |
7 | func main() {
8 |
9 | // 数组的遍历
10 | nums := [...]int{1,2,3,4,5,6,7,8}
11 |
12 | for k, v:= range nums{
13 | // k为下标,v为对应的值
14 | fmt.Println(k, v, " ")
15 | }
16 |
17 | fmt.Println()
18 |
19 | // 切片的遍历
20 | slis := []int{1,2,3,4,5,6,7,8}
21 | for k, v:= range slis{
22 | // k为下标,v为对应的值
23 | fmt.Println(k, v, " ")
24 | }
25 |
26 | fmt.Println()
27 |
28 |
29 | // 字典的遍历
30 | tmpMap := map[int]string{
31 | 0 : "小明",
32 | 1 : "小红",
33 | 2 : "小张",
34 | }
35 |
36 | for k, v:= range tmpMap{
37 | // k为键值,v为对应值
38 | fmt.Println(k, v, " ")
39 | }
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/ch13-seckill/sk-core/service/srv_user/user_history.go:
--------------------------------------------------------------------------------
1 | package srv_user
2 |
3 | import "sync"
4 |
5 | //用户购买历史记录
6 | type UserBuyHistory struct {
7 | History map[int]int
8 | Lock sync.RWMutex
9 | }
10 |
11 | func (p *UserBuyHistory) GetProductBuyCount(productId int) int {
12 | p.Lock.RLock()
13 | defer p.Lock.RUnlock()
14 |
15 | count, _ := p.History[productId]
16 | return count
17 | }
18 |
19 | func (p *UserBuyHistory) Add(productId, count int) {
20 | p.Lock.Lock()
21 | defer p.Lock.Unlock()
22 |
23 | cur, ok := p.History[productId]
24 | if !ok {
25 | cur = count
26 | } else {
27 | cur += count
28 | }
29 |
30 | p.History[productId] = cur
31 | }
32 |
--------------------------------------------------------------------------------
/ch13-seckill/pkg/bootstrap/BootstrapProperty.go:
--------------------------------------------------------------------------------
1 | package bootstrap
2 |
3 | var (
4 | HttpConfig HttpConf
5 | DiscoverConfig DiscoverConf
6 | ConfigServerConfig ConfigServerConf
7 | RpcConfig RpcConf
8 | )
9 |
10 | //Http配置
11 | type HttpConf struct {
12 | Host string
13 | Port string
14 | }
15 |
16 | // RPC配置
17 | type RpcConf struct {
18 | Port string
19 | }
20 |
21 | //服务发现与注册配置
22 | type DiscoverConf struct {
23 | Host string
24 | Port string
25 | ServiceName string
26 | Weight int
27 | InstanceId string
28 | }
29 |
30 | //配置中心
31 | type ConfigServerConf struct {
32 | Id string
33 | Profile string
34 | Label string
35 | }
36 |
--------------------------------------------------------------------------------
/ch13-seckill/pb/seckill.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package pb;
4 |
5 | service SecKillService{
6 | rpc secKill(SecRequest) returns (SecResponse){}
7 | }
8 |
9 |
10 | message SecRequest {
11 | int64 ProductId = 1;
12 | string Source = 2;
13 | string AuthCode = 3;
14 | string SecTime = 4;
15 | string Nance = 5;
16 | int64 UserId = 6;
17 | string UserAuthSign = 7;
18 | int64 AccessTime = 8;
19 | string ClientAddr = 9;
20 | string ClientRefence = 10;
21 | }
22 |
23 | message SecResponse {
24 | int64 ProductId = 1;
25 | int64 UserId = 2;
26 | string Token = 3;
27 | int64 TokenTime = 4;
28 | int64 Code = 5;
29 | }
30 |
31 |
32 |
--------------------------------------------------------------------------------
/ch13-seckill/sk-app/service/srv_limit/min_limit.go:
--------------------------------------------------------------------------------
1 | package srv_limit
2 |
3 | type TimeLimit interface {
4 | Count(nowTIme int64) (curCount int)
5 | Check(nowTIme int64) int
6 | }
7 |
8 | //分钟限制
9 | type MinLimit struct {
10 | count int
11 | curTime int64
12 | }
13 |
14 | //在1分钟之内访问的次数
15 | func (p *MinLimit) Count(nowTime int64) (curCount int) {
16 | if nowTime-p.curTime > 60 {
17 | p.count = 1
18 | p.curTime = nowTime
19 | curCount = p.count
20 | return
21 | }
22 |
23 | p.count++
24 | curCount = p.count
25 | return
26 | }
27 |
28 | //检查用户访问的次数
29 | func (p *MinLimit) Check(nowTime int64) int {
30 | if nowTime-p.curTime > 60 {
31 | return 0
32 | }
33 | return p.count
34 | }
35 |
--------------------------------------------------------------------------------
/ch3-basic/Pointer.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import "fmt"
4 |
5 | func main() {
6 |
7 |
8 | str := "Golang is Good!"
9 | strPrt := &str
10 |
11 | fmt.Printf("str type is %T, value is %v, address is %p\n", str, str, &str)
12 | fmt.Printf("strPtr type is %T, and value is %v\n", strPrt, strPrt)
13 |
14 | newStr := *strPrt //获取指针对应变量的值
15 | fmt.Printf("newStr type is %T, value is %v, and address is %p\n", newStr, newStr, &newStr)
16 |
17 | *strPrt = "Java is Good too!" //通过指针对变量进行赋值
18 | fmt.Printf("newStr type is %T, value is %v, and address is %p\n", newStr, newStr, &newStr)
19 | fmt.Printf("str type is %T, value is %v, address is %p\n", str, str, &str)
20 |
21 |
22 |
23 |
24 |
25 |
26 | }
--------------------------------------------------------------------------------
/ch13-seckill/README.md:
--------------------------------------------------------------------------------
1 | ### 简介
2 | 配套《Go语言高并发与微服务实战》使用,具体讲解见图书13章
3 |
4 | ### 依赖基础组件
5 | - redis
6 | - zookeeper
7 | - git仓库
8 | - consul
9 |
10 | #### 部署
11 | - 1 部署 consul
12 | 参考书籍第六章6.3小节内容,安装部署 consul
13 | - 2 部署 Redis,Zookeeper,MySQL。
14 | 参考对应组件的官方部署文档,安装完MySQL后,可以导入主目录下的seckill.sql
15 | - 3 新建git repo
16 | 可以参考 https://gitee.com/cloud-source/config-repo 创建对应项目的文件,修改Redis,MySQL,Zookeeper等组件的配置
17 | - 4 部署 Config-Service
18 | 参考书籍第八章8.3.1小节 在ch8-config文件夹下有 config-service项目,参考书上章节构建或者使用仓库 https://github.com/longjoy/config-server 进行构建。
19 | 在yml文件中配置对应的git项目地址和consul地址,构建并运行Java程序,将config-service注册到consul上
20 | - 5 修改bootstrap文件
21 | 修改各个项目中的bootstrap.yml文件discover相关的consul地址和config-service的相关配置
22 |
23 |
--------------------------------------------------------------------------------
/ch3-basic/Compose.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import "fmt"
4 |
5 | // 游泳特性
6 | type Swimming struct {
7 | }
8 |
9 | func (swim *Swimming) swim() {
10 | fmt.Println("swimming is my ability")
11 | }
12 |
13 | // 飞行特性
14 | type Flying struct {
15 | }
16 |
17 | func (fly *Flying) fly() {
18 | fmt.Println("flying is my ability")
19 | }
20 |
21 | // 野鸭,具备飞行和游泳特性
22 | type WildDuck struct {
23 | Swimming
24 | Flying
25 | }
26 |
27 | // 家鸭,具备游泳特性
28 | type DomesticDuck struct {
29 | Swimming
30 | }
31 |
32 | func main() {
33 |
34 | // 声明一只野鸭,可以飞,也可以游泳
35 | wild := WildDuck{}
36 | wild.fly()
37 | wild.swim()
38 |
39 | // 声明一只家鸭,只会游泳
40 | domestic := DomesticDuck{}
41 | domestic.swim()
42 |
43 |
44 | }
--------------------------------------------------------------------------------
/ch4-feature/synch/mutex.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "sync"
6 | "time"
7 | )
8 |
9 |
10 | func main() {
11 | var lock sync.Mutex
12 | go func() {
13 | // 加锁
14 | lock.Lock()
15 | defer lock.Unlock()
16 | fmt.Println("func1 get lock at " + time.Now().String())
17 | time.Sleep(time.Second)
18 | fmt.Println("func1 release lock " + time.Now().String())
19 | }()
20 |
21 | time.Sleep(time.Second / 10)
22 |
23 | go func() {
24 | lock.Lock()
25 | defer lock.Unlock()
26 | fmt.Println("func2 get lock " + time.Now().String())
27 | time.Sleep(time.Second)
28 | fmt.Println("func2 release lock " + time.Now().String())
29 | }()
30 |
31 | // 等待 所有 goroutine 执行完毕
32 | time.Sleep(time.Second * 4)
33 | }
34 |
--------------------------------------------------------------------------------
/ch3-basic/Slice.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import "fmt"
4 |
5 | func main() {
6 |
7 |
8 | source := [...]int{1,2,3}
9 | sli := source[0:1]
10 |
11 | fmt.Printf("sli value is %v\n", sli)
12 | fmt.Printf("sli len is %v\n", len(sli))
13 | fmt.Printf("sli cap is %v\n", cap(sli))
14 |
15 | sli[0] = 4
16 | fmt.Printf("sli value is %v\n", sli)
17 | fmt.Printf("source value is %v\n", source)
18 |
19 |
20 | sli = make([]int, 2, 4)
21 | fmt.Printf("sli value is %v\n", sli)
22 | fmt.Printf("sli len is %v\n", len(sli))
23 | fmt.Printf("sli cap is %v\n", cap(sli))
24 |
25 | ex := []int{1,2,3}
26 | fmt.Printf("ex value is %v\n", ex)
27 | fmt.Printf("ex len is %v\n", len(ex))
28 | fmt.Printf("ex cap is %v\n", cap(ex))
29 |
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/ch13-seckill/sk-core/setup/service.go:
--------------------------------------------------------------------------------
1 | package setup
2 |
3 | import (
4 | "fmt"
5 | register "github.com/longjoy/micro-go-book/ch13-seckill/pkg/discover"
6 | "github.com/longjoy/micro-go-book/ch13-seckill/sk-core/service/srv_redis"
7 | "os"
8 | "os/signal"
9 | "syscall"
10 | )
11 |
12 | func RunService() {
13 | //启动处理线程
14 | srv_redis.RunProcess()
15 | errChan := make(chan error)
16 | //http server
17 | go func() {
18 | //启动前执行注册
19 | register.Register()
20 | }()
21 |
22 | go func() {
23 | c := make(chan os.Signal, 1)
24 | signal.Notify(c, syscall.SIGINT, syscall.SIGTERM)
25 | errChan <- fmt.Errorf("%s", <-c)
26 | }()
27 |
28 | error := <-errChan
29 | //服务退出取消注册
30 | register.Deregister()
31 | fmt.Println(error)
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/ch5-web/helloweb.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "log"
6 | "net/http"
7 | "strings"
8 | )
9 |
10 | func sayHello(w http.ResponseWriter, r *http.Request) {
11 | _ = r.ParseForm() //解析参数,默认是不会解析的
12 | fmt.Println(r.Form) //这些信息是输出到服务器端的打印信息
13 | fmt.Println("Path: ", r.URL.Path)
14 | fmt.Println("Host: ", r.Host)
15 | for k, v := range r.Form {
16 | fmt.Println("key:", k)
17 | fmt.Println("val:", strings.Join(v, ""))
18 | }
19 | _, _ = fmt.Fprintf(w, "Hello Web, %s!", r.Form.Get("name")) //写入到 w 的是输出到客户端的内容
20 | }
21 |
22 | func main() {
23 | http.HandleFunc("/", sayHello) //设置访问的路由
24 | err := http.ListenAndServe(":8080", nil) //设置监听的端口
25 | if err != nil {
26 | log.Fatal("ListenAndServe: ", err)
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/ch5-web/writeresponse.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "encoding/json"
5 | "log"
6 | "net/http"
7 | )
8 |
9 | type User struct {
10 | Name string
11 | Habits []string
12 | }
13 |
14 | func write(w http.ResponseWriter, r *http.Request) {
15 | w.Header().Set("Content-Type", "application/json")
16 | w.Header().Set("X-Custom-Header", "custom")
17 | w.WriteHeader(201)
18 | user := &User{
19 | Name: "aoho",
20 | Habits: []string{"balls", "running", "hiking"},
21 | }
22 | json, _ := json.Marshal(user)
23 | w.Write(json)
24 | }
25 |
26 | func main() {
27 | http.HandleFunc("/write", write) //设置访问的路由
28 | err := http.ListenAndServe(":8080", nil) //设置监听的端口
29 | if err != nil {
30 | log.Fatal("ListenAndServe: ", err)
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/ch3-basic/StructImplementor.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import "fmt"
4 |
5 | // Cat接口
6 | type Cat interface {
7 | // 抓老鼠
8 | CatchMouse()
9 | }
10 |
11 | // Dog接口
12 | type Dog interface {
13 | // 吠叫
14 | Bark()
15 | }
16 |
17 | type CatDog struct {
18 | Name string
19 | }
20 |
21 | // 实现Cat接口
22 | func (catDog *CatDog) CatchMouse() {
23 | fmt.Printf("%v caught the mouse and ate it!\n", catDog.Name)
24 | }
25 |
26 | // Dog接口
27 | func (catDog *CatDog) Bark() {
28 | fmt.Printf("%v barked loudly!\n", catDog.Name)
29 | }
30 |
31 | func main() {
32 | catDog := &CatDog{
33 | "Lucy",
34 | }
35 |
36 | // 声明一个Cat接口,并将catDog指针类型赋值给cat
37 | var cat Cat
38 | cat = catDog
39 | cat.CatchMouse()
40 |
41 | // 声明一个Dog接口,并将catDog指针类型赋值给dog
42 | var dog Dog
43 | dog = catDog
44 | dog.Bark()
45 | }
--------------------------------------------------------------------------------
/ch12-trace/zipkin-kit/docker/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: '2'
2 |
3 | services:
4 | # prometheus:
5 | # image: prom/prometheus
6 | # ports:
7 | # - 9090:9090
8 | # volumes:
9 | # - ./prometheus.yml:/etc/prometheus/prometheus.yml
10 | # grafana:
11 | # image: grafana/grafana
12 | # ports:
13 | # - 3000:3000
14 | # environment:
15 | # - GF_SECURITY_ADMIN_PASSWORD=password
16 | # volumes:
17 | # - $PWD/extra/grafana_db:/var/lib/grafana grafana/grafana
18 |
19 | consul:
20 | image: progrium/consul:latest
21 | ports:
22 | - 8400:8400
23 | - 8500:8500
24 | - 8600:53/udp
25 | hostname: consulserver
26 | command: -server -bootstrap -ui-dir /ui
27 |
28 | zipkin:
29 | image: openzipkin/zipkin
30 | ports:
31 | - 9411:9411
--------------------------------------------------------------------------------
/ch13-seckill/pb/oauth.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package pb;
4 |
5 |
6 | service OAuthService{
7 | // token 校验
8 | rpc CheckToken(CheckTokenRequest) returns (CheckTokenResponse);
9 | }
10 |
11 | message CheckTokenRequest {
12 | string token = 1;
13 | }
14 |
15 |
16 | message ClientDetails {
17 | string clientId = 1;
18 | int32 accessTokenValiditySeconds = 2;
19 | int32 refreshTokenValiditySeconds = 3;
20 | repeated string authorizedGrantTypes = 4;
21 | }
22 |
23 | message UserDetails {
24 | int64 userId = 1;
25 | string username = 2;
26 | repeated string authorities = 3;
27 | }
28 |
29 |
30 | message CheckTokenResponse{
31 | UserDetails userDetails = 1;
32 | ClientDetails clientDetails = 2;
33 | bool isValidToken = 3;
34 | string err = 4;
35 | }
--------------------------------------------------------------------------------
/ch13-seckill/sk-admin/etcd_test.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "context"
5 | "github.com/coreos/etcd/clientv3"
6 | conf "github.com/longjoy/micro-go-book/ch13-seckill/pkg/config"
7 | "log"
8 | "testing"
9 | "time"
10 | )
11 |
12 | func TestMain(m *testing.M) {
13 |
14 | cli, err := clientv3.New(clientv3.Config{
15 | Endpoints: []string{"39.98.179.73:2379"}, // conf.Etcd.Host
16 | DialTimeout: 5 * time.Second,
17 | })
18 | if err != nil {
19 | log.Printf("Connect etcd failed. Error : %v", err)
20 | }
21 | conf.Etcd.EtcdSecProductKey = "product"
22 | conf.Etcd.EtcdConn = cli
23 |
24 | ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
25 | defer cancel()
26 | rsp, err := conf.Etcd.EtcdConn.Get(ctx, "product")
27 | log.Printf("get from etcd %v", rsp)
28 | }
29 |
--------------------------------------------------------------------------------
/common/discover/discover_client.go:
--------------------------------------------------------------------------------
1 | package discover
2 |
3 | import (
4 | "log"
5 | )
6 |
7 | type DiscoveryClient interface {
8 |
9 | /**
10 | * 服务注册接口
11 | * @param serviceName 服务名
12 | * @param instanceId 服务实例Id
13 | * @param instancePort 服务实例端口
14 | * @param healthCheckUrl 健康检查地址
15 | * @param instanceHost 服务实例地址
16 | * @param meta 服务实例元数据
17 | */
18 | Register(serviceName, instanceId, healthCheckUrl string, instanceHost string, instancePort int, meta map[string]string, logger *log.Logger) bool
19 |
20 | /**
21 | * 服务注销接口
22 | * @param instanceId 服务实例Id
23 | */
24 | DeRegister(instanceId string, logger *log.Logger) bool
25 |
26 | /**
27 | * 发现服务实例接口
28 | * @param serviceName 服务名
29 | */
30 | DiscoverServices(serviceName string, logger *log.Logger) []interface{}
31 | }
32 |
33 |
--------------------------------------------------------------------------------
/ch6-discovery/discover/discover_client.go:
--------------------------------------------------------------------------------
1 | package discover
2 |
3 | import (
4 | "log"
5 | )
6 |
7 | type DiscoveryClient interface {
8 |
9 | /**
10 | * 服务注册接口
11 | * @param serviceName 服务名
12 | * @param instanceId 服务实例Id
13 | * @param instancePort 服务实例端口
14 | * @param healthCheckUrl 健康检查地址
15 | * @param instanceHost 服务实例地址
16 | * @param meta 服务实例元数据
17 | */
18 | Register(serviceName, instanceId, healthCheckUrl string, instanceHost string, instancePort int, meta map[string]string, logger *log.Logger) bool
19 |
20 | /**
21 | * 服务注销接口
22 | * @param instanceId 服务实例Id
23 | */
24 | DeRegister(instanceId string, logger *log.Logger) bool
25 |
26 | /**
27 | * 发现服务实例接口
28 | * @param serviceName 服务名
29 | */
30 | DiscoverServices(serviceName string, logger *log.Logger) []interface{}
31 | }
32 |
33 |
--------------------------------------------------------------------------------
/ch13-seckill/oauth-service/oauth-script.sql:
--------------------------------------------------------------------------------
1 | create database oauth;
2 |
3 | drop table if exists `client_details`;
4 | CREATE TABLE `client_details`
5 | (
6 | `client_id` VARCHAR(128) NOT NULL,
7 | `client_secret` VARCHAR(128) NOT NULL,
8 | `access_token_validity_seconds` INT(10) NOT NULL,
9 | `refresh_token_validity_seconds` INT(10) NOT NULL,
10 | `registered_redirect_uri` VARCHAR(128) NOT NULL,
11 | `authorized_grant_types` VARCHAR(128) NOT NULL,
12 |
13 | PRIMARY KEY (`client_id`)
14 | );
15 |
16 | insert into client_details (`client_id`, `client_secret`, `access_token_validity_seconds`, `refresh_token_validity_seconds`, `registered_redirect_uri`, `authorized_grant_types`) values ('clientId', 'clientSecret', 1800, 18000, 'http://127.0.0.1','["password","refresh_token"]');
--------------------------------------------------------------------------------
/ch4-feature/synch/rw_mutex.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "strconv"
6 | "sync"
7 | "time"
8 | )
9 |
10 |
11 | var rwLock sync.RWMutex
12 |
13 |
14 | func main() {
15 |
16 | // 获取读锁
17 | for i := 0 ; i < 5 ;i ++{
18 | go func(i int) {
19 | rwLock.RLock()
20 | defer rwLock.RUnlock()
21 | fmt.Println("read func " + strconv.Itoa(i) +" get rlock at " + time.Now().String())
22 | time.Sleep(time.Second)
23 | }(i)
24 | }
25 |
26 | time.Sleep(time.Second / 10)
27 | // 获取写锁
28 | for i := 0 ; i < 5; i++{
29 | go func(i int) {
30 | rwLock.Lock()
31 | defer rwLock.Unlock()
32 | fmt.Println("write func " + strconv.Itoa(i) +" get wlock at " + time.Now().String())
33 | time.Sleep(time.Second)
34 | }(i)
35 | }
36 |
37 | // 保证所有的 goroutine 执行结束
38 | time.Sleep(time.Second * 10)
39 | }
40 |
--------------------------------------------------------------------------------
/ch13-seckill/gateway/config/config.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | import (
4 | "github.com/go-kit/kit/log"
5 | conf "github.com/longjoy/micro-go-book/ch13-seckill/pkg/config"
6 | "github.com/spf13/viper"
7 | "os"
8 | )
9 |
10 | const (
11 | kConfigType = "CONFIG_TYPE"
12 | )
13 |
14 | var Logger log.Logger
15 |
16 | func init() {
17 | Logger = log.NewLogfmtLogger(os.Stderr)
18 | Logger = log.With(Logger, "ts", log.DefaultTimestampUTC)
19 | Logger = log.With(Logger, "caller", log.DefaultCaller)
20 | viper.AutomaticEnv()
21 | initDefault()
22 |
23 | if err := conf.LoadRemoteConfig(); err != nil {
24 | Logger.Log("Fail to load remote config", err)
25 | }
26 | if err := conf.Sub("auth", &AuthPermitConfig); err != nil {
27 | Logger.Log("Fail to parse config", err)
28 | }
29 | }
30 | func initDefault() {
31 | viper.SetDefault(kConfigType, "yaml")
32 | }
33 |
--------------------------------------------------------------------------------
/ch11-security/service/common_service.go:
--------------------------------------------------------------------------------
1 | package service
2 |
3 |
4 |
5 | type Service interface {
6 |
7 | SimpleData(username string) string
8 |
9 | AdminData(username string) string
10 |
11 | // HealthCheck check service health status
12 | HealthCheck() bool
13 | }
14 |
15 | type CommonService struct {
16 |
17 | }
18 |
19 | func (s *CommonService) SimpleData(username string) string {
20 | return "hello " + username + " ,simple data, with simple authority"
21 | }
22 |
23 | func (s *CommonService) AdminData(username string) string {
24 | return "hello " + username + " ,admin data, with admin authority"
25 |
26 | }
27 |
28 | // HealthCheck implement Service method
29 | // 用于检查服务的健康状态,这里仅仅返回true
30 | func (s *CommonService) HealthCheck() bool {
31 | return true
32 | }
33 |
34 | func NewCommonService() *CommonService {
35 | return &CommonService{}
36 | }
37 |
38 |
--------------------------------------------------------------------------------
/ch12-trace/zipkin-kit/client/string.go:
--------------------------------------------------------------------------------
1 | package client
2 |
3 | import (
4 | grpctransport "github.com/go-kit/kit/transport/grpc"
5 | kitgrpc "github.com/go-kit/kit/transport/grpc"
6 | "github.com/longjoy/micro-go-book/ch12-trace/zipkin-kit/pb"
7 | endpts "github.com/longjoy/micro-go-book/ch12-trace/zipkin-kit/string-service/endpoint"
8 | "github.com/longjoy/micro-go-book/ch12-trace/zipkin-kit/string-service/service"
9 | "google.golang.org/grpc"
10 | )
11 |
12 | func StringDiff(conn *grpc.ClientConn, clientTracer kitgrpc.ClientOption) service.Service {
13 |
14 | var ep = grpctransport.NewClient(conn,
15 | "pb.StringService",
16 | "Diff",
17 | EncodeGRPCStringRequest,
18 | DecodeGRPCStringResponse,
19 | pb.StringResponse{},
20 | clientTracer,
21 | ).Endpoint()
22 |
23 | StringEp := endpts.StringEndpoints{
24 | StringEndpoint: ep,
25 | }
26 | return StringEp
27 | }
28 |
--------------------------------------------------------------------------------
/ch13-seckill/sk-core/service/srv_product/product_count.go:
--------------------------------------------------------------------------------
1 | package srv_product
2 |
3 | import (
4 | "sync"
5 | )
6 |
7 | //商品数量管理
8 | type ProductCountMgr struct {
9 | productCount map[int]int
10 | lock sync.RWMutex
11 | }
12 |
13 | func NewProductCountMgr() *ProductCountMgr {
14 | productMgr := &ProductCountMgr{
15 | productCount: make(map[int]int, 128),
16 | }
17 | return productMgr
18 | }
19 |
20 | //商品数量
21 | func (p *ProductCountMgr) Count(productId int) (count int) {
22 | p.lock.RLock()
23 | defer p.lock.RUnlock()
24 |
25 | count = p.productCount[productId]
26 | return
27 | }
28 |
29 | //添加商品
30 | func (p *ProductCountMgr) Add(productId, count int) {
31 | p.lock.Lock()
32 | defer p.lock.Unlock()
33 |
34 | cur, ok := p.productCount[productId]
35 | if !ok {
36 | cur = count
37 | } else {
38 | cur += count
39 | }
40 | p.productCount[productId] = cur
41 | }
42 |
--------------------------------------------------------------------------------
/ch7-rpc/basic/client.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "github.com/longjoy/micro-go-book/ch7-rpc/basic/string-service"
6 | "log"
7 | "net/rpc"
8 | )
9 |
10 | func main() {
11 | client, err := rpc.DialHTTP("tcp", "127.0.0.1:1234")
12 | if err != nil {
13 | log.Fatal("dialing:", err)
14 | }
15 |
16 | stringReq := &service.StringRequest{"A", "B"}
17 | // Synchronous call
18 | var reply string
19 | err = client.Call("StringService.Concat", stringReq, &reply)
20 | if err != nil {
21 | log.Fatal("StringService error:", err)
22 | }
23 | fmt.Printf("StringService Concat : %s concat %s = %s\n", stringReq.A, stringReq.B, reply)
24 |
25 | stringReq = &service.StringRequest{"ACD", "BDF"}
26 | call := client.Go("StringService.Diff", stringReq, &reply, nil)
27 | _ = <-call.Done
28 | fmt.Printf("StringService Diff : %s diff %s = %s\n", stringReq.A, stringReq.B, reply)
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/ch13-seckill/user-service/transport/grpc.go:
--------------------------------------------------------------------------------
1 | package transport
2 |
3 | import (
4 | "context"
5 | "github.com/go-kit/kit/transport/grpc"
6 | "github.com/longjoy/micro-go-book/ch13-seckill/pb"
7 | endpts "github.com/longjoy/micro-go-book/ch13-seckill/user-service/endpoint"
8 | )
9 |
10 | type grpcServer struct {
11 | check grpc.Handler
12 | }
13 |
14 | func (s *grpcServer) Check(ctx context.Context, r *pb.UserRequest) (*pb.UserResponse, error) {
15 | _, resp, err := s.check.ServeGRPC(ctx, r)
16 | if err != nil {
17 | return nil, err
18 | }
19 | return resp.(*pb.UserResponse), nil
20 | }
21 |
22 | func NewGRPCServer(ctx context.Context, endpoints endpts.UserEndpoints, serverTracer grpc.ServerOption) pb.UserServiceServer {
23 | return &grpcServer{
24 | check: grpc.NewServer(
25 | endpoints.UserEndpoint,
26 | DecodeGRPCUserRequest,
27 | EncodeGRPCUserResponse,
28 | serverTracer,
29 | ),
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/ch3-basic/TypeAlias.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import "fmt"
4 |
5 | type aliasInt = int // 定义一个类型别名
6 | type myInt int // 定义一个新的类型
7 |
8 | func main() {
9 |
10 | var alias aliasInt
11 | fmt.Printf("alias value is %v, type is %T\n", alias, alias)
12 |
13 | var myint myInt
14 | fmt.Printf("myint value is %v, type is %T\n", myint, myint)
15 |
16 | name := "小红"
17 | switch name {
18 | case "小明":
19 | fmt.Println("扫地")
20 | case "小红":
21 | fmt.Println("擦黑板")
22 | case "小刚":
23 | fmt.Println("倒垃圾")
24 | default:
25 | fmt.Println("没人干活")
26 | }
27 |
28 | score := 90
29 | switch {
30 | case score < 100 && score >= 90:
31 | fmt.Println("优秀")
32 | case score < 90 && score >= 80:
33 | fmt.Println("良好")
34 | case score < 80 && score >= 60:
35 | fmt.Println("及格")
36 | case score < 60 :
37 | fmt.Println("不及格")
38 | default:
39 | fmt.Println("分数错误")
40 |
41 | }
42 |
43 |
44 |
45 |
46 |
47 | }
48 |
49 |
--------------------------------------------------------------------------------
/ch4-feature/synch/sync_map.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "strconv"
6 | "sync"
7 | )
8 | var syncMap sync.Map
9 | var waitGroup sync.WaitGroup
10 |
11 | func main() {
12 |
13 | routineSize := 5
14 | // 让主线程等待数据添加完毕
15 | waitGroup.Add(routineSize)
16 | // 并发添加数据
17 | for i := 0 ; i < routineSize; i++{
18 | go addNumber(i * 10)
19 | }
20 |
21 | // 开始等待
22 | waitGroup.Wait()
23 | var size int
24 | // 统计数量
25 | syncMap.Range(func(key, value interface{}) bool {
26 | size++
27 | //fmt.Println("key-value pair is", key, value, " ")
28 | return true
29 | })
30 | fmt.Println("syncMap current size is " + strconv.Itoa(size))
31 | // 获取键为 0 的值
32 | value, ok := syncMap.Load(0); if ok{
33 | fmt.Println("key 0 has value", value, " ")
34 | }
35 |
36 | }
37 |
38 | func addNumber(begin int) {
39 | // 往 syncMap 中放入数据
40 | for i := begin ; i < begin + 3 ; i++{
41 | syncMap.Store(i, i)
42 | }
43 | // 通知数据已添加完毕
44 | waitGroup.Done()
45 | }
46 |
--------------------------------------------------------------------------------
/ch13-seckill/sk-app/service/srv_err/error.go:
--------------------------------------------------------------------------------
1 | package srv_err
2 |
3 | import (
4 | "errors"
5 | )
6 |
7 | const (
8 | ErrInvalidRequest = 1101
9 | ErrNotFoundProductId = 1102
10 | ErrUserCheckAuthFailed = 1103
11 | ErrUserServiceBusy = 1104
12 | ErrActiveNotStart = 1105
13 | ErrActiveAlreadyEnd = 1106
14 | ErrActiveSaleOut = 1107
15 | ErrProcessTimeout = 1108
16 | ErrClientClosed = 1109
17 | )
18 |
19 | const (
20 | ErrServiceBusy = 1001
21 | ErrSecKillSucc = 1002
22 | ErrNotFoundProduct = 1003
23 | ErrSoldout = 1004
24 | ErrRetry = 1005
25 | ErrAlreadyBuy = 1006
26 | )
27 |
28 | var errMsg = map[int]string{
29 | ErrServiceBusy: "服务器错误",
30 | ErrSecKillSucc: "抢购成功",
31 | ErrNotFoundProduct: "没有该商品",
32 | ErrSoldout: "商品售罄",
33 | ErrRetry: "请重试",
34 | ErrAlreadyBuy: "已经抢购",
35 | }
36 |
37 | func GetErrMsg(code int) error {
38 | return errors.New(errMsg[code])
39 | }
40 |
--------------------------------------------------------------------------------
/ch13-seckill/oauth-service/transport/grpc.go:
--------------------------------------------------------------------------------
1 | package transport
2 |
3 | import (
4 | "context"
5 | "github.com/go-kit/kit/transport/grpc"
6 | endpts "github.com/longjoy/micro-go-book/ch13-seckill/oauth-service/endpoint"
7 | "github.com/longjoy/micro-go-book/ch13-seckill/pb"
8 | )
9 |
10 | type grpcServer struct {
11 | checkTokenServer grpc.Handler
12 | }
13 |
14 | func (s *grpcServer) CheckToken(ctx context.Context, r *pb.CheckTokenRequest) (*pb.CheckTokenResponse, error) {
15 | _, resp, err := s.checkTokenServer.ServeGRPC(ctx, r)
16 | if err != nil {
17 | return nil, err
18 | }
19 | return resp.(*pb.CheckTokenResponse), nil
20 | }
21 |
22 | func NewGRPCServer(ctx context.Context, endpoints endpts.OAuth2Endpoints, serverTracer grpc.ServerOption) pb.OAuthServiceServer {
23 | return &grpcServer{
24 | checkTokenServer: grpc.NewServer(
25 | endpoints.GRPCCheckTokenEndpoint,
26 | DecodeGRPCCheckTokenRequest,
27 | EncodeGRPCCheckTokenResponse,
28 | serverTracer,
29 | ),
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/ch13-seckill/sk-admin/setup/etcd_test.go:
--------------------------------------------------------------------------------
1 | package setup
2 |
3 | import (
4 | "context"
5 | "fmt"
6 | "go.etcd.io/etcd/clientv3"
7 | "log"
8 | "testing"
9 | "time"
10 | )
11 |
12 | func TestInitEtcd(t *testing.T) {
13 | cli, err := clientv3.New(clientv3.Config{
14 | Endpoints: []string{"39.98.179.73:2379"},
15 | DialTimeout: 5 * time.Second,
16 | })
17 | if err != nil {
18 | log.Printf("Connect etcd failed. Error : %v", err)
19 | }
20 |
21 | ctx, cancel := context.WithTimeout(context.Background(), time.Second)
22 | defer cancel()
23 | _, err1 := cli.Put(ctx, "sec_kill_product", "sample")
24 | if err1 != nil {
25 | log.Printf("Get falied. Error : %v", err)
26 | }
27 |
28 | ctx, cancel = context.WithTimeout(context.Background(), time.Second)
29 | defer cancel()
30 | nresp, err := cli.Get(ctx, "sec_kill_product")
31 |
32 | if err != nil {
33 | log.Printf("Get falied. Error : %v", err)
34 | }
35 |
36 | for _, ev := range nresp.Kvs {
37 | fmt.Printf("%s : %s\n", ev.Key, ev.Value)
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/ch13-seckill/sk-app/model/model.go:
--------------------------------------------------------------------------------
1 | package model
2 |
3 | type SecRequest struct {
4 | ProductId int `json:"product_id"` //商品ID
5 | Source string `json:"source"`
6 | AuthCode string `json:"auth_code"`
7 | SecTime int64 `json:"sec_time"`
8 | Nance string `json:"nance"`
9 | UserId int `json:"user_id"`
10 | UserAuthSign string `json:"user_auth_sign"` //用户授权签名
11 | AccessTime int64 `json:"access_time"`
12 | ClientAddr string `json:"client_addr"`
13 | ClientRefence string `json:"client_refence"`
14 | CloseNotify <-chan bool `json:"-"`
15 | ResultChan chan *SecResult `json:"-"`
16 | }
17 |
18 | type SecResult struct {
19 | ProductId int `json:"product_id"` //商品ID
20 | UserId int `json:"user_id"` //用户ID
21 | Token string `json:"token"` //Token
22 | TokenTime int64 `json:"token_time"` //Token生成时间
23 | Code int `json:"code"` //状态码
24 | }
25 |
--------------------------------------------------------------------------------
/ch12-trace/zipkin-kit/string-service/grpc.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "context"
5 | "github.com/go-kit/kit/transport/grpc"
6 | "github.com/longjoy/micro-go-book/ch12-trace/zipkin-kit/client"
7 | "github.com/longjoy/micro-go-book/ch12-trace/zipkin-kit/pb"
8 | "github.com/longjoy/micro-go-book/ch12-trace/zipkin-kit/string-service/endpoint"
9 | )
10 |
11 | type grpcServer struct {
12 | diff grpc.Handler
13 | }
14 |
15 | func (s *grpcServer) Diff(ctx context.Context, r *pb.StringRequest) (*pb.StringResponse, error) {
16 | _, resp, err := s.diff.ServeGRPC(ctx, r)
17 | if err != nil {
18 | return nil, err
19 | }
20 | return resp.(*pb.StringResponse), nil
21 |
22 | }
23 |
24 | func NewGRPCServer(ctx context.Context, endpoints endpoint.StringEndpoints, serverTracer grpc.ServerOption) pb.StringServiceServer {
25 | return &grpcServer{
26 | diff: grpc.NewServer(
27 | endpoints.StringEndpoint,
28 | client.DecodeGRPCStringRequest,
29 | client.EncodeGRPCStringResponse,
30 | serverTracer,
31 | ),
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/ch13-seckill/pb/activity.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package pb;
4 |
5 | service ActivityService{
6 | rpc secKill(SecRequest) returns (SecResponse){}
7 | }
8 |
9 |
10 | message Activity {
11 | int64 ActivityId = 1; // 活动Id
12 | string ActivityName = 2; // 活动名称
13 | int64 ProductId = 3; // 商品Id
14 | int64 StartTime = 4; // 开始时间
15 | int64 EndTime = 5; // 结束时间
16 | int64 Total = 6; // 商品总数
17 | int64 Status = 7; // 状态
18 | string StartTimeStr = 8; //
19 | string EndTimeStr = 9;
20 | string StatusStr = 10;
21 | int64 Speed = 11;
22 | int64 BuyLimit = 12;
23 | double BuyRate = 13;
24 | }
25 |
26 | message SecProductInfoConf {
27 | int64 ProductId = 1; // 商品id
28 | int64 StartTime = 2; // 开始时间
29 | int64 EndTime = 3; // 结束时间
30 | int64 Status = 4; // 状态
31 | int64 Total = 5; // 商品总数
32 | int64 Left = 6; // 剩余商品数量
33 | int64 OnePersonBuyLimit = 7; // 一个人购买限制
34 | double BuyRate = 8; // 买中几率
35 | int64 SoldMaxLimit = 9; // 每秒最多能卖多少个
36 | }
--------------------------------------------------------------------------------
/ch13-seckill/sk-admin/service/product.go:
--------------------------------------------------------------------------------
1 | package service
2 |
3 | import (
4 | "github.com/gohouse/gorose/v2"
5 | "github.com/longjoy/micro-go-book/ch13-seckill/sk-admin/model"
6 | "log"
7 | )
8 |
9 | type ProductService interface {
10 | CreateProduct(product *model.Product) error
11 | GetProductList() ([]gorose.Data, error)
12 | }
13 |
14 | type ProductServiceMiddleware func(ProductService) ProductService
15 |
16 | type ProductServiceImpl struct {
17 | }
18 |
19 | func (p ProductServiceImpl) CreateProduct(product *model.Product) error {
20 | productEntity := model.NewProductModel()
21 | err := productEntity.CreateProduct(product)
22 | if err != nil {
23 | log.Printf("ProductEntity.CreateProduct, err : %v", err)
24 | return err
25 | }
26 | return nil
27 | }
28 |
29 | func (p ProductServiceImpl) GetProductList() ([]gorose.Data, error) {
30 | productEntity := model.NewProductModel()
31 | productList, err := productEntity.GetProductList()
32 | if err != nil {
33 | log.Printf("ProductEntity.CreateProduct, err : %v", err)
34 | return nil, err
35 | }
36 | return productList, nil
37 | }
38 |
--------------------------------------------------------------------------------
/ch13-seckill/pkg/ratelimiter/instruments.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "context"
5 | "errors"
6 | "github.com/go-kit/kit/endpoint"
7 | "golang.org/x/time/rate"
8 | "time"
9 | )
10 |
11 | var ErrLimitExceed = errors.New("Rate limit exceed!")
12 |
13 | // NewTokenBucketLimitterWithBuildIn 使用x/time/rate创建限流中间件
14 | func NewTokenBucketLimitterWithBuildIn(bkt *rate.Limiter) endpoint.Middleware {
15 | return func(next endpoint.Endpoint) endpoint.Endpoint {
16 | return func(ctx context.Context, request interface{}) (response interface{}, err error) {
17 | if !bkt.Allow() {
18 | return nil, ErrLimitExceed
19 | }
20 | return next(ctx, request)
21 | }
22 | }
23 | }
24 |
25 | func DynamicLimitter(interval int, burst int) endpoint.Middleware {
26 | bucket := rate.NewLimiter(rate.Every(time.Second*time.Duration(interval)), burst)
27 | return func(next endpoint.Endpoint) endpoint.Endpoint {
28 | return func(ctx context.Context, request interface{}) (response interface{}, err error) {
29 | if !bucket.Allow() {
30 | return nil, ErrLimitExceed
31 | }
32 | return next(ctx, request)
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 kidme
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 |
--------------------------------------------------------------------------------
/ch13-seckill/user-service/service/service.go:
--------------------------------------------------------------------------------
1 | package service
2 |
3 | import (
4 | "context"
5 | "github.com/longjoy/micro-go-book/ch13-seckill/user-service/model"
6 | "log"
7 | )
8 |
9 | // Service Define a service interface
10 | type Service interface {
11 | Check(ctx context.Context, username, password string) (int64, error)
12 |
13 | // HealthCheck check service health status
14 | HealthCheck() bool
15 | }
16 |
17 | //UserService implement Service interface
18 | type UserService struct {
19 | }
20 |
21 | // Add implement check method
22 | func (s UserService) Check(ctx context.Context, username string, password string) (int64, error) {
23 | userEntity := model.NewUserModel()
24 | res, err := userEntity.CheckUser(username, password)
25 | if err != nil {
26 | log.Printf("UserEntity.CreateUser, err : %v", err)
27 | return 0, err
28 | }
29 | return res.UserId, nil
30 | }
31 |
32 | // HealthCheck implement Service method
33 | // 用于检查服务的健康状态,这里仅仅返回true
34 | func (s UserService) HealthCheck() bool {
35 | return true
36 | }
37 |
38 | // ServiceMiddleware define service middleware
39 | type ServiceMiddleware func(Service) Service
40 |
--------------------------------------------------------------------------------
/ch13-seckill/oauth-service/plugins/instrument.go:
--------------------------------------------------------------------------------
1 | package plugins
2 |
3 | import (
4 | "context"
5 | "errors"
6 | "github.com/go-kit/kit/endpoint"
7 | "github.com/juju/ratelimit"
8 | "golang.org/x/time/rate"
9 | )
10 |
11 | var ErrLimitExceed = errors.New("Rate limit exceed!")
12 |
13 | // NewTokenBucketLimitterWithJuju 使用juju/ratelimit创建限流中间件
14 | func NewTokenBucketLimitterWithJuju(bkt *ratelimit.Bucket) endpoint.Middleware {
15 | return func(next endpoint.Endpoint) endpoint.Endpoint {
16 | return func(ctx context.Context, request interface{}) (response interface{}, err error) {
17 | if bkt.TakeAvailable(1) == 0 {
18 | return nil, ErrLimitExceed
19 | }
20 | return next(ctx, request)
21 | }
22 | }
23 | }
24 |
25 | // NewTokenBucketLimitterWithBuildIn 使用x/time/rate创建限流中间件
26 | func NewTokenBucketLimitterWithBuildIn(bkt *rate.Limiter) endpoint.Middleware {
27 | return func(next endpoint.Endpoint) endpoint.Endpoint {
28 | return func(ctx context.Context, request interface{}) (response interface{}, err error) {
29 | if !bkt.Allow() {
30 | return nil, ErrLimitExceed
31 | }
32 | return next(ctx, request)
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/ch13-seckill/pkg/discover/discovery_client.go:
--------------------------------------------------------------------------------
1 | package discover
2 |
3 | import (
4 | "github.com/go-kit/kit/sd/consul"
5 | "github.com/hashicorp/consul/api"
6 | "github.com/longjoy/micro-go-book/ch13-seckill/pkg/common"
7 | "log"
8 | "sync"
9 | )
10 |
11 | type DiscoveryClientInstance struct {
12 | Host string // Host
13 | Port int // Port
14 | // 连接 consul 的配置
15 | config *api.Config
16 | client consul.Client
17 | mutex sync.Mutex
18 | // 服务实例缓存字段
19 | instancesMap sync.Map
20 | }
21 |
22 | type DiscoveryClient interface {
23 | /**
24 | * 服务注册接口
25 | * @param serviceName 服务名
26 | * @param instanceId 服务实例Id
27 | * @param instancePort 服务实例端口
28 | * @param healthCheckUrl 健康检查地址
29 | * @param weight 权重
30 | * @param meta 服务实例元数据
31 | */
32 | Register(instanceId, svcHost, healthCheckUrl, svcPort string, svcName string, weight int, meta map[string]string, tags []string, logger *log.Logger) bool
33 |
34 | /**
35 | * 服务注销接口
36 | * @param instanceId 服务实例Id
37 | */
38 | DeRegister(instanceId string, logger *log.Logger) bool
39 |
40 | /**
41 | * 发现服务实例接口
42 | * @param serviceName 服务名
43 | */
44 | DiscoverServices(serviceName string, logger *log.Logger) []*common.ServiceInstance
45 | }
46 |
--------------------------------------------------------------------------------
/ch13-seckill/oauth-service/service/client_service.go:
--------------------------------------------------------------------------------
1 | package service
2 |
3 | import (
4 | "context"
5 | "errors"
6 | "github.com/longjoy/micro-go-book/ch13-seckill/oauth-service/model"
7 | )
8 |
9 |
10 | var (
11 |
12 | ErrClientMessage = errors.New("invalid client")
13 |
14 | )
15 |
16 | // Service Define a service interface
17 | type ClientDetailsService interface {
18 |
19 | GetClientDetailByClientId(ctx context.Context, clientId string, clientSecret string)(*model.ClientDetails, error)
20 |
21 | }
22 |
23 |
24 | type MysqlClientDetailsService struct {
25 | }
26 |
27 | func NewMysqlClientDetailsService() ClientDetailsService {
28 | return &MysqlClientDetailsService{}
29 | }
30 |
31 | func (service *MysqlClientDetailsService)GetClientDetailByClientId(ctx context.Context, clientId string, clientSecret string)(*model.ClientDetails, error) {
32 |
33 | clientDetailsModel := model.NewClientDetailsModel();
34 | if clientDetails, err := clientDetailsModel.GetClientDetailsByClientId(clientId); err == nil{
35 | if clientSecret == clientDetails.ClientSecret {
36 | return clientDetails, nil
37 | }else {
38 | return nil, ErrClientMessage
39 | }
40 | }else {
41 | return nil, err;
42 | }
43 |
44 |
45 | }
46 |
47 |
48 |
--------------------------------------------------------------------------------
/ch10-resiliency/hystrix-example.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "github.com/afex/hystrix-go/hystrix"
6 | "strconv"
7 | "time"
8 | )
9 |
10 | func main() {
11 |
12 | hystrix.ConfigureCommand("test_command", hystrix.CommandConfig{
13 | // 设置参数
14 | Timeout: hystrix.DefaultTimeout,
15 | })
16 |
17 | err := hystrix.Do("test_command", func() error {
18 | // 远程调用&或者其他需要保护的方法
19 | return nil
20 | }, func(err error) error {
21 | // 失败回滚方法
22 | return nil
23 | })
24 |
25 | if err != nil {
26 | fmt.Println(err)
27 | }
28 |
29 | resultChan := make(chan interface{}, 1)
30 | errChan := hystrix.Go("test_command", func() error {
31 | // 远程调用&或者其他需要保护的方法
32 | resultChan <- "success"
33 | return nil
34 | }, func(e error) error {
35 | // 失败回滚方法
36 | return nil
37 | })
38 |
39 | select {
40 | case err := <-errChan:
41 | // 执行失败
42 | fmt.Println(err)
43 | case result := <-resultChan:
44 | // 执行成功
45 | fmt.Println(result)
46 | case <-time.After(2 * time.Second): // 超时设置
47 | fmt.Println("Time out")
48 | return
49 | }
50 |
51 | circuit, _, _ := hystrix.GetCircuit("test_command")
52 | fmt.Println("command test_command's circuit open is " + strconv.FormatBool(circuit.IsOpen()))
53 |
54 | }
55 |
--------------------------------------------------------------------------------
/ch13-seckill/pkg/mysql/mysql.go:
--------------------------------------------------------------------------------
1 | package mysql
2 |
3 | import (
4 | "fmt"
5 | _ "github.com/go-sql-driver/mysql"
6 | "github.com/gohouse/gorose/v2"
7 | )
8 |
9 | var engin *gorose.Engin
10 | var err error
11 |
12 | func InitMysql(hostMysql, portMysql, userMysql, pwdMysql, dbMysql string) {
13 | fmt.Printf(userMysql)
14 | fmt.Printf(dbMysql)
15 |
16 | DbConfig := gorose.Config{
17 | // Default database configuration
18 | Driver: "mysql", // Database driver(mysql,sqlite,postgres,oracle,mssql)
19 | Dsn: userMysql + ":" + pwdMysql + "@tcp(" + hostMysql + ":" + portMysql + ")/" + dbMysql + "?charset=utf8&parseTime=true", // 数据库链接
20 | Prefix: "", // Table prefix
21 | // (Connection pool) Max open connections, default value 0 means unlimit.
22 | SetMaxOpenConns: 300,
23 | // (Connection pool) Max idle connections, default value is 1.
24 | SetMaxIdleConns: 10,
25 | }
26 |
27 | engin, err = gorose.Open(&DbConfig)
28 | if err != nil {
29 | fmt.Println(err)
30 | return
31 | }
32 | }
33 |
34 | func DB() gorose.IOrm {
35 | return engin.NewOrm()
36 | }
37 |
--------------------------------------------------------------------------------
/ch3-basic/Append.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import "fmt"
4 |
5 | func main() {
6 |
7 |
8 | arr1 := [...]int{1,2,3,4}
9 | arr2 := [...]int{1,2,3,4}
10 |
11 | sli1 := arr1[0:2] // 长度为2,容量为4
12 | sli2 := arr2[2:4] // 长度为2,容量为2
13 |
14 | fmt.Printf("sli1 pointer is %p, len is %v, cap is %v, value is %v\n", &sli1, len(sli1), cap(sli1), sli1)
15 | fmt.Printf("sli2 pointer is %p, len is %v, cap is %v, value is %v\n", &sli2, len(sli2), cap(sli2), sli2)
16 |
17 | newSli1 := append(sli1, 5)
18 | fmt.Printf("newSli1 pointer is %p, len is %v, cap is %v, value is %v\n", &newSli1, len(newSli1), cap(newSli1), newSli1)
19 | fmt.Printf("source arr1 become %v\n", arr1)
20 |
21 | newSli2 := append(sli2, 5)
22 | fmt.Printf("newSli2 pointer is %p, len is %v, cap is %v, value is %v\n", &newSli2, len(newSli2), cap(newSli2), newSli2)
23 | fmt.Printf("source arr2 become %v\n", arr2)
24 |
25 | arr3 := [...]int{1,2,3,4}
26 | sli3 := arr3[0:2:2] // 长度为2,容量为2
27 |
28 | fmt.Printf("sli3 pointer is %p, len is %v, cap is %v, value is %v\n", &sli3, len(sli3), cap(sli3), sli3)
29 |
30 | newSli3 := append(sli3,5)
31 | fmt.Printf("newSli3 pointer is %p, len is %v, cap is %v, value is %v\n", &newSli3, len(newSli3), cap(newSli3), newSli3)
32 | fmt.Printf("source arr3 become %v\n", arr3)
33 |
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/ch13-seckill/sk-admin/model/product.go:
--------------------------------------------------------------------------------
1 | package model
2 |
3 | import (
4 | "github.com/gohouse/gorose/v2"
5 | "github.com/longjoy/micro-go-book/ch13-seckill/pkg/mysql"
6 | "log"
7 | )
8 |
9 | type Product struct {
10 | ProductId int `json:"product_id"` //商品Id
11 | ProductName string `json:"product_name"` //商品名称
12 | Total int `json:"total"` //商品数量
13 | Status int `json:"status"` //商品状态
14 | }
15 |
16 | type ProductModel struct {
17 | }
18 |
19 | func NewProductModel() *ProductModel {
20 | return &ProductModel{}
21 | }
22 |
23 | func (p *ProductModel) getTableName() string {
24 | return "product"
25 | }
26 |
27 | func (p *ProductModel) GetProductList() ([]gorose.Data, error) {
28 | conn := mysql.DB()
29 | list, err := conn.Table(p.getTableName()).Get()
30 | if err != nil {
31 | log.Printf("Error : %v", err)
32 | return nil, err
33 | }
34 | return list, nil
35 | }
36 |
37 | func (p *ProductModel) CreateProduct(product *Product) error {
38 | conn := mysql.DB()
39 | _, err := conn.Table(p.getTableName()).Data(map[string]interface{}{
40 | "product_name": product.ProductName,
41 | "total": product.Total,
42 | "status": product.Status,
43 | }).Insert()
44 | if err != nil {
45 | log.Printf("Error : %v", err)
46 | return err
47 | }
48 | return nil
49 | }
50 |
--------------------------------------------------------------------------------
/ch7-rpc/go-kit/server.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "context"
5 | "flag"
6 | "github.com/go-kit/kit/log"
7 | service "github.com/longjoy/micro-go-book/ch7-rpc/go-kit/string-service"
8 | "github.com/longjoy/micro-go-book/ch7-rpc/pb"
9 | "google.golang.org/grpc"
10 | "net"
11 | "os"
12 | )
13 |
14 | func main() {
15 |
16 | flag.Parse()
17 |
18 | ctx := context.Background()
19 |
20 | var logger log.Logger
21 | {
22 | logger = log.NewLogfmtLogger(os.Stderr)
23 | logger = log.With(logger, "ts", log.DefaultTimestampUTC)
24 | logger = log.With(logger, "caller", log.DefaultCaller)
25 | }
26 |
27 | var svc service.Service
28 | svc = service.StringService{}
29 |
30 | // add logging middleware
31 | svc = service.LoggingMiddleware(logger)(svc)
32 |
33 | endpoint := service.MakeStringEndpoint(svc)
34 |
35 | //创建健康检查的Endpoint
36 | healthEndpoint := service.MakeHealthCheckEndpoint(svc)
37 |
38 | //把算术运算Endpoint和健康检查Endpoint封装至StringEndpoints
39 | endpts := service.StringEndpoints{
40 | StringEndpoint: endpoint,
41 | HealthCheckEndpoint: healthEndpoint,
42 | }
43 |
44 | handler := service.NewStringServer(ctx, endpts)
45 |
46 | ls, _ := net.Listen("tcp", "127.0.0.1:8080")
47 | gRPCServer := grpc.NewServer()
48 | pb.RegisterStringServiceServer(gRPCServer, handler)
49 | gRPCServer.Serve(ls)
50 |
51 | }
52 |
--------------------------------------------------------------------------------
/ch13-seckill/pkg/client/user_test.go:
--------------------------------------------------------------------------------
1 | package client
2 |
3 | import (
4 | "context"
5 | "fmt"
6 | "github.com/longjoy/micro-go-book/ch13-seckill/pb"
7 | "github.com/opentracing/opentracing-go"
8 | zipkin "github.com/openzipkin-contrib/zipkin-go-opentracing"
9 | "log"
10 | "testing"
11 | )
12 |
13 | func TestUserClientImpl_CheckUser(t *testing.T) {
14 | client, _ := NewUserClient("user", nil, genTracerAct(nil))
15 |
16 | if response, err := client.CheckUser(context.Background(), nil, &pb.UserRequest{
17 | Username: "xuan",
18 | Password: "xuan",
19 | }); err == nil {
20 | fmt.Println(response.Result)
21 | } else {
22 | fmt.Println(err.Error())
23 | }
24 | }
25 |
26 | func genTracerAct(tracer opentracing.Tracer) opentracing.Tracer {
27 | if tracer != nil {
28 | return tracer
29 | }
30 | zipkinUrl := "http://114.67.98.210:9411/api/v2/spans"
31 | zipkinRecorder := "localhost:12344"
32 | collector, err := zipkin.NewHTTPCollector(zipkinUrl)
33 | if err != nil {
34 | log.Fatalf("zipkin.NewHTTPCollector err: %v", err)
35 | }
36 |
37 | recorder := zipkin.NewRecorder(collector, false, zipkinRecorder, "user-client")
38 |
39 | res, err := zipkin.NewTracer(
40 | recorder, zipkin.ClientServerSameSpan(true),
41 | )
42 | if err != nil {
43 | log.Fatalf("zipkin.NewTracer err: %v", err)
44 | }
45 | return res
46 |
47 | }
48 |
--------------------------------------------------------------------------------
/ch3-basic/Person.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import "fmt"
4 |
5 |
6 | type Person struct {
7 | Name string // 姓名
8 | Birth string // 生日
9 | ID int64 // 身份证号
10 | }
11 |
12 | // 指针类型,修改个人信息
13 | func (person *Person) changeName(name string) {
14 | person.Name = name
15 | }
16 |
17 | // 非指针类型,打印个人信息
18 | func (person Person) printMess() {
19 | fmt.Printf("My name is %v, and my birthday is %v, and my id is %v\n",
20 | person.Name, person.Birth, person.ID)
21 |
22 | // 尝试修改个人信息,但是对原接收器并没有影响
23 | // person.ID = 3
24 |
25 | }
26 |
27 | func main() {
28 | p1 := Person{
29 | Name:"王小二",
30 | Birth: "1990-12-23",
31 | ID:1,
32 | }
33 |
34 | p1.printMess()
35 | p1.changeName("王老二")
36 | p1.printMess()
37 |
38 | }
39 |
40 |
41 | //func main() {
42 | // // 声明实例化
43 | // var p1 Person
44 | // p1.Name = "王小二"
45 | // p1.Birth = "1990-12-11"
46 | //
47 | //
48 | // // new函数实例化
49 | // p2 := new(Person)
50 | // p2.Name = "王二小"
51 | // p2.Birth = "1990-12-22"
52 | //
53 | //
54 | // // 取址实例化
55 | // p3 := &Person{}
56 | // p3.Name = "王三小"
57 | // p3.Birth = "1990-12-23"
58 | //
59 | // // 初始化
60 | // p4 := Person{
61 | // Name:"王小四",
62 | // Birth: "1990-12-23",
63 | // }
64 | //
65 | // // 初始化
66 | // p5 := &Person{
67 | // "王五",
68 | // "1990-12-23",
69 | // 5,
70 | // }
71 | //
72 | //
73 | //
74 | //
75 | //
76 | //}
77 |
--------------------------------------------------------------------------------
/ch13-seckill/pkg/bootstrap/bootstrap_config.go:
--------------------------------------------------------------------------------
1 | package bootstrap
2 |
3 | import (
4 | "fmt"
5 | "github.com/spf13/viper"
6 | "log"
7 | )
8 |
9 | func init() {
10 | viper.AutomaticEnv()
11 | initBootstrapConfig()
12 | //读取yaml文件
13 | //v := viper.New()
14 |
15 | if err := viper.ReadInConfig(); err != nil {
16 | fmt.Printf("err:%s\n", err)
17 | }
18 | if err := subParse("http", &HttpConfig); err != nil {
19 | log.Fatal("Fail to parse Http config", err)
20 | }
21 | if err := subParse("discover", &DiscoverConfig); err != nil {
22 | log.Fatal("Fail to parse Discover config", err)
23 | }
24 | if err := subParse("config", &ConfigServerConfig); err != nil {
25 | log.Fatal("Fail to parse config server", err)
26 | }
27 |
28 | if err := subParse("rpc", &RpcConfig); err != nil {
29 | log.Fatal("Fail to parse rpc server", err)
30 | }
31 | }
32 | func initBootstrapConfig() {
33 | //设置读取的配置文件
34 | viper.SetConfigName("bootstrap")
35 | //添加读取的配置文件路径
36 | viper.AddConfigPath("./")
37 | //windows环境下为%GOPATH,linux环境下为$GOPATH
38 | viper.AddConfigPath("$GOPATH/src/")
39 | //设置配置文件类型
40 | viper.SetConfigType("yaml")
41 | }
42 |
43 | func subParse(key string, value interface{}) error {
44 | log.Printf("配置文件的前缀为:%v", key)
45 | sub := viper.Sub(key)
46 | sub.AutomaticEnv()
47 | sub.SetEnvPrefix(key)
48 | return sub.Unmarshal(value)
49 | }
50 |
--------------------------------------------------------------------------------
/ch13-seckill/user-service/plugins/logging.go:
--------------------------------------------------------------------------------
1 | package plugins
2 |
3 | import (
4 | "context"
5 | "github.com/go-kit/kit/log"
6 | "github.com/longjoy/micro-go-book/ch13-seckill/user-service/service"
7 | "time"
8 | )
9 |
10 | // loggingMiddleware Make a new type
11 | // that contains Service interface and logger instance
12 | type loggingMiddleware struct {
13 | service.Service
14 | logger log.Logger
15 | }
16 |
17 | // LoggingMiddleware make logging middleware
18 | func LoggingMiddleware(logger log.Logger) service.ServiceMiddleware {
19 | return func(next service.Service) service.Service {
20 | return loggingMiddleware{next, logger}
21 | }
22 | }
23 |
24 | func (mw loggingMiddleware) Check(ctx context.Context, a, b string) (ret int64, err error) {
25 |
26 | defer func(begin time.Time) {
27 | _ = mw.logger.Log(
28 | "function", "Check",
29 | "username", a,
30 | "pwd", b,
31 | "result", ret,
32 | "took", time.Since(begin),
33 | )
34 | }(time.Now())
35 |
36 | ret, err = mw.Service.Check(ctx, a, b)
37 | return ret, err
38 | }
39 |
40 | func (mw loggingMiddleware) HealthCheck() (result bool) {
41 | defer func(begin time.Time) {
42 | _ = mw.logger.Log(
43 | "function", "HealthChcek",
44 | "result", result,
45 | "took", time.Since(begin),
46 | )
47 | }(time.Now())
48 | result = mw.Service.HealthCheck()
49 | return
50 | }
51 |
--------------------------------------------------------------------------------
/ch5-web/beego/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "github.com/astaxie/beego/orm"
6 | _ "github.com/go-sql-driver/mysql" // import your used driver
7 | )
8 |
9 | // Model Struct
10 | type User struct {
11 | UserId int `orm:"pk"`
12 | Name string `orm:"size(100)"`
13 | }
14 |
15 | func init() {
16 | // set default database
17 | orm.RegisterDataBase("default", "mysql", "root:root_test@tcp(114.67.98.210:3396)/user_tmp?charset=utf8", 30)
18 |
19 | // register model
20 | orm.RegisterModel(new(User))
21 |
22 | // create table
23 | orm.RunSyncdb("default", false, true)
24 | }
25 |
26 | func main() {
27 | o := orm.NewOrm()
28 |
29 | user := User{Name: "aoho"}
30 |
31 | // insert
32 | id, err := o.Insert(&user)
33 | fmt.Printf("ID: %d, ERR: %v\n", id, err)
34 |
35 | // update
36 | user.Name = "boho"
37 | num, err := o.Update(&user)
38 | fmt.Printf("NUM: %d, ERR: %v\n", num, err)
39 |
40 | // read one
41 | u := User{UserId: user.UserId}
42 | err = o.Read(&u)
43 | fmt.Printf("ERR: %v\n", err)
44 |
45 | var maps []orm.Params
46 |
47 | res, err := o.Raw("SELECT * FROM user").Values(&maps)
48 | fmt.Printf("NUM: %d, ERR: %v\n", res, err)
49 | for _, term := range maps {
50 | fmt.Println(term["user_id"], ":", term["name"])
51 | }
52 | // delete
53 | num, err = o.Delete(&u)
54 | fmt.Printf("NUM: %d, ERR: %v\n", num, err)
55 | }
56 |
--------------------------------------------------------------------------------
/ch13-seckill/user-service/transport/user_model.go:
--------------------------------------------------------------------------------
1 | package transport
2 |
3 | import (
4 | "context"
5 | "github.com/longjoy/micro-go-book/ch13-seckill/pb"
6 | "github.com/longjoy/micro-go-book/ch13-seckill/user-service/endpoint"
7 | )
8 |
9 | func EncodeGRPCUserRequest(_ context.Context, r interface{}) (interface{}, error) {
10 | req := r.(pb.UserRequest)
11 | return &pb.UserRequest{
12 | Username: string(req.Username),
13 | Password: string(req.Password),
14 | }, nil
15 | }
16 |
17 | func DecodeGRPCUserRequest(ctx context.Context, r interface{}) (interface{}, error) {
18 | req := r.(*pb.UserRequest)
19 | return endpoint.UserRequest{
20 | Username: string(req.Username),
21 | Password: string(req.Password),
22 | }, nil
23 | }
24 |
25 | func EncodeGRPCUserResponse(_ context.Context, r interface{}) (interface{}, error) {
26 | resp := r.(endpoint.UserResponse)
27 |
28 | if resp.Error != nil {
29 | return &pb.UserResponse{
30 | Result: bool(resp.Result),
31 | Err: "error",
32 | }, nil
33 | }
34 |
35 | return &pb.UserResponse{
36 | Result: bool(resp.Result),
37 | UserId:resp.UserId,
38 | Err: "",
39 | }, nil
40 | }
41 |
42 | func DecodeGRPCUserResponse(_ context.Context, r interface{}) (interface{}, error) {
43 | resp := r.(*pb.UserResponse)
44 | return pb.UserResponse{
45 | Result: bool(resp.Result),
46 | Err: resp.Err,
47 | }, nil
48 | }
49 |
--------------------------------------------------------------------------------
/ch10-resiliency/use-string-service/plugins/logging.go:
--------------------------------------------------------------------------------
1 | package plugins
2 |
3 | import (
4 | "github.com/go-kit/kit/log"
5 | "github.com/longjoy/micro-go-book/ch10-resiliency/use-string-service/service"
6 | "time"
7 | )
8 |
9 | // loggingMiddleware Make a new type
10 | // that contains Service interface and logger instance
11 | type loggingMiddleware struct {
12 | service.Service
13 | logger log.Logger
14 | }
15 |
16 | // LoggingMiddleware make logging middleware
17 | func LoggingMiddleware(logger log.Logger) service.ServiceMiddleware {
18 | return func(next service.Service) service.Service {
19 | return loggingMiddleware{next, logger}
20 | }
21 | }
22 |
23 |
24 | func (mw loggingMiddleware) UseStringService(operationType, a, b string) (ret string, err error) {
25 |
26 | defer func(begin time.Time) {
27 | mw.logger.Log(
28 | "function", "UseStringService",
29 | "a", a,
30 | "b", b,
31 | "result", ret,
32 | "took", time.Since(begin),
33 | )
34 | }(time.Now())
35 |
36 | ret, err = mw.Service.UseStringService(operationType, a, b)
37 | return ret, err
38 | }
39 |
40 | func (mw loggingMiddleware) HealthCheck() (result bool) {
41 | defer func(begin time.Time) {
42 | mw.logger.Log(
43 | "function", "HealthChcek",
44 | "result", result,
45 | "took", time.Since(begin),
46 | )
47 | }(time.Now())
48 | result = mw.Service.HealthCheck()
49 | return
50 | }
51 |
52 |
53 |
--------------------------------------------------------------------------------
/ch7-rpc/go-kit/client.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "context"
5 | "flag"
6 | "fmt"
7 | grpctransport "github.com/go-kit/kit/transport/grpc"
8 | service "github.com/longjoy/micro-go-book/ch7-rpc/go-kit/string-service"
9 | "github.com/longjoy/micro-go-book/ch7-rpc/pb"
10 | "google.golang.org/grpc"
11 | "time"
12 | )
13 |
14 | func main() {
15 | flag.Parse()
16 | ctx := context.Background()
17 | conn, err := grpc.Dial("127.0.0.1:8080", grpc.WithInsecure(), grpc.WithTimeout(1*time.Second))
18 | if err != nil {
19 | fmt.Println("gRPC dial err:", err)
20 | }
21 | defer conn.Close()
22 |
23 | svr := NewStringClient(conn)
24 | result, err := svr.Concat(ctx, "A", "B")
25 | if err != nil {
26 | fmt.Println("Check error", err.Error())
27 | }
28 |
29 | fmt.Println("result=", result)
30 | }
31 |
32 | func NewStringClient(conn *grpc.ClientConn) service.Service {
33 |
34 | var ep = grpctransport.NewClient(conn,
35 | "pb.StringService",
36 | "Concat",
37 | DecodeStringRequest,
38 | EncodeStringResponse,
39 | pb.StringResponse{},
40 | ).Endpoint()
41 |
42 | userEp := service.StringEndpoints{
43 | StringEndpoint: ep,
44 | }
45 | return userEp
46 | }
47 |
48 | func DecodeStringRequest(ctx context.Context, r interface{}) (interface{}, error) {
49 | return r, nil
50 | }
51 |
52 | func EncodeStringResponse(_ context.Context, r interface{}) (interface{}, error) {
53 | return r, nil
54 | }
55 |
--------------------------------------------------------------------------------
/ch12-trace/zipkin-go/string-services/svc1/implementation.go:
--------------------------------------------------------------------------------
1 | // +build go1.7
2 |
3 | package svc1
4 |
5 | import (
6 | "context"
7 |
8 | "github.com/opentracing/opentracing-go"
9 |
10 | "github.com/openzipkin-contrib/zipkin-go-opentracing/examples/cli_with_2_services/svc2"
11 | )
12 |
13 | // svc1 is our actual service implementation
14 | type svc1 struct {
15 | svc2Client svc2.Service
16 | }
17 |
18 | func (s *svc1) Concat(ctx context.Context, a, b string) (string, error) {
19 | // test for length overflow
20 | if len(a)+len(b) > StrMaxSize {
21 | // pull span from context (has already been created by our middleware)
22 | span := opentracing.SpanFromContext(ctx)
23 | span.SetTag("error", ErrMaxSize.Error())
24 | return "", ErrMaxSize
25 | }
26 |
27 | return a + b, nil
28 | }
29 |
30 | func (s *svc1) Sum(ctx context.Context, a, b int64) (int64, error) {
31 | // pull span from context (has already been created by our middleware)
32 | span := opentracing.SpanFromContext(ctx)
33 | span.SetTag("proxy-to", "svc2")
34 |
35 | // proxy request to svc2
36 | result, err := s.svc2Client.Sum(ctx, a, b)
37 | if err != nil {
38 | span.SetTag("error", err.Error())
39 | return 0, err
40 | }
41 |
42 | return result, nil
43 | }
44 |
45 | // NewService returns a new implementation of our Service.
46 | func NewService(svc2Client svc2.Service) Service {
47 | return &svc1{
48 | svc2Client: svc2Client,
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/ch9-gateway/string-service/register.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "github.com/go-kit/kit/log"
5 | "github.com/go-kit/kit/sd"
6 | "github.com/go-kit/kit/sd/consul"
7 | "github.com/hashicorp/consul/api"
8 | "github.com/pborman/uuid"
9 | "os"
10 | "strconv"
11 | )
12 |
13 | func Register(consulHost, consulPort, svcHost, svcPort string, logger log.Logger) (registar sd.Registrar) {
14 |
15 | // 创建Consul客户端连接
16 | var client consul.Client
17 | {
18 | consulCfg := api.DefaultConfig()
19 | consulCfg.Address = consulHost + ":" + consulPort
20 | consulClient, err := api.NewClient(consulCfg)
21 | if err != nil {
22 | logger.Log("create consul client error:", err)
23 | os.Exit(1)
24 | }
25 |
26 | client = consul.NewClient(consulClient)
27 | }
28 |
29 | // 设置Consul对服务健康检查的参数
30 | check := api.AgentServiceCheck{
31 | HTTP: "http://" + svcHost + ":" + svcPort + "/health",
32 | Interval: "10s",
33 | Timeout: "1s",
34 | Notes: "Consul check service health status.",
35 | }
36 |
37 | port, _ := strconv.Atoi(svcPort)
38 |
39 | //设置微服务Consul的注册信息
40 | reg := api.AgentServiceRegistration{
41 | ID: "string-service" + uuid.New(),
42 | Name: "string-service",
43 | Address: svcHost,
44 | Port: port,
45 | Tags: []string{"string-service", "aoho"},
46 | Check: &check,
47 | }
48 |
49 | // 执行注册
50 | registar = consul.NewRegistrar(client, ®, logger)
51 | return
52 | }
53 |
--------------------------------------------------------------------------------
/ch12-trace/zipkin-kit/string-service/register.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "github.com/go-kit/kit/log"
5 | "github.com/go-kit/kit/sd"
6 | "github.com/go-kit/kit/sd/consul"
7 | "github.com/hashicorp/consul/api"
8 | "github.com/pborman/uuid"
9 | "os"
10 | "strconv"
11 | )
12 |
13 | func Register(consulHost, consulPort, svcHost, svcPort string, logger log.Logger) (registar sd.Registrar) {
14 |
15 | // 创建Consul客户端连接
16 | var client consul.Client
17 | {
18 | consulCfg := api.DefaultConfig()
19 | consulCfg.Address = consulHost + ":" + consulPort
20 | consulClient, err := api.NewClient(consulCfg)
21 | if err != nil {
22 | logger.Log("create consul client error:", err)
23 | os.Exit(1)
24 | }
25 |
26 | client = consul.NewClient(consulClient)
27 | }
28 |
29 | // 设置Consul对服务健康检查的参数
30 | check := api.AgentServiceCheck{
31 | HTTP: "http://" + svcHost + ":" + svcPort + "/health",
32 | Interval: "10s",
33 | Timeout: "1s",
34 | Notes: "Consul check service health status.",
35 | }
36 |
37 | port, _ := strconv.Atoi(svcPort)
38 |
39 | //设置微服务想Consul的注册信息
40 | reg := api.AgentServiceRegistration{
41 | ID: "string-service" + uuid.New(),
42 | Name: "string-service",
43 | Address: svcHost,
44 | Port: port,
45 | Tags: []string{"string-service"},
46 | Check: &check,
47 | }
48 |
49 | // 执行注册
50 | registar = consul.NewRegistrar(client, ®, logger)
51 | return
52 | }
53 |
--------------------------------------------------------------------------------
/ch7-rpc/grpc/string-service/service.go:
--------------------------------------------------------------------------------
1 | package string_service
2 |
3 | import (
4 | "context"
5 | "errors"
6 | "github.com/longjoy/micro-go-book/ch7-rpc/pb"
7 | "strings"
8 | )
9 |
10 | const (
11 | StrMaxSize = 1024
12 | )
13 |
14 | // Service errors
15 | var (
16 | ErrMaxSize = errors.New("maximum size of 1024 bytes exceeded")
17 |
18 | ErrStrValue = errors.New("maximum size of 1024 bytes exceeded")
19 | )
20 |
21 | type StringService struct{}
22 |
23 | func (s *StringService) Concat(ctx context.Context, req *pb.StringRequest) (*pb.StringResponse, error) {
24 | if len(req.A)+len(req.B) > StrMaxSize {
25 | response := pb.StringResponse{Ret: ""}
26 | return &response, nil
27 | }
28 | response := pb.StringResponse{Ret: req.A + req.B}
29 | return &response, nil
30 | }
31 |
32 | func (s *StringService) Diff(ctx context.Context, req *pb.StringRequest) (*pb.StringResponse, error) {
33 | if len(req.A) < 1 || len(req.B) < 1 {
34 | response := pb.StringResponse{Ret: ""}
35 | return &response, nil
36 | }
37 | res := ""
38 | if len(req.A) >= len(req.B) {
39 | for _, char := range req.B {
40 | if strings.Contains(req.A, string(char)) {
41 | res = res + string(char)
42 | }
43 | }
44 | } else {
45 | for _, char := range req.A {
46 | if strings.Contains(req.B, string(char)) {
47 | res = res + string(char)
48 | }
49 | }
50 | }
51 | response := pb.StringResponse{Ret: res}
52 | return &response, nil
53 | }
54 |
--------------------------------------------------------------------------------
/ch5-web/webForm.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "html/template"
6 | "log"
7 | "net/http"
8 | "strings"
9 | )
10 |
11 | func login(w http.ResponseWriter, r *http.Request) {
12 | fmt.Println("method:", r.Method) //获取请求的方法
13 | if r.Method == "GET" {
14 | t, _ := template.ParseFiles("login.tpl")
15 | log.Println(t.Execute(w, nil))
16 | } else {
17 | //请求的是登录数据,那么执行登录的逻辑判断
18 | _ = r.ParseForm()
19 | fmt.Println("username:", r.Form["username"])
20 | fmt.Println("password:", r.Form["password"])
21 | if pwd := r.Form.Get("password"); pwd == "123456" { // 验证密码是否正确
22 | fmt.Fprintf(w, "欢迎登陆,Hello %s!", r.Form.Get("username")) //这个写入到w的是输出到客户端的
23 | } else {
24 | fmt.Fprintf(w, "密码错误,请重新输入!")
25 | }
26 | }
27 | }
28 |
29 | func sayHelloName(w http.ResponseWriter, r *http.Request) {
30 | _ = r.ParseForm() //解析url传递的参数,对于POST则解析响应包的主体(request body)
31 | //注意:如果没有调用ParseForm方法,下面无法获取表单的数据
32 | fmt.Println(r.Form) //这些信息是输出到服务器端的打印信息
33 | fmt.Println("path", r.URL.Path)
34 | for k, v := range r.Form {
35 | fmt.Println("key:", k)
36 | fmt.Println("val:", strings.Join(v, ""))
37 | }
38 | fmt.Fprintf(w, "Hello aoho!") //这个写入到w的是输出到客户端的
39 | }
40 |
41 | func main() {
42 | http.HandleFunc("/", sayHelloName) //设置访问的路由
43 | http.HandleFunc("/login", login) //设置访问的路由
44 | err := http.ListenAndServe(":8080", nil) //设置监听的端口
45 | if err != nil {
46 | log.Fatal("ListenAndServe: ", err)
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/ch13-seckill/pkg/loadbalance/loadbalance.go:
--------------------------------------------------------------------------------
1 | package loadbalance
2 |
3 | import (
4 | "errors"
5 | "github.com/longjoy/micro-go-book/ch13-seckill/pkg/common"
6 | "math/rand"
7 | )
8 |
9 | // 负载均衡器
10 | type LoadBalance interface {
11 | SelectService(service []*common.ServiceInstance) (*common.ServiceInstance, error)
12 | }
13 |
14 | type RandomLoadBalance struct {
15 | }
16 |
17 | // 随机负载均衡
18 | func (loadBalance *RandomLoadBalance) SelectService(services []*common.ServiceInstance) (*common.ServiceInstance, error) {
19 |
20 | if services == nil || len(services) == 0 {
21 | return nil, errors.New("service instances are not exist")
22 | }
23 |
24 | return services[rand.Intn(len(services))], nil
25 | }
26 |
27 | type WeightRoundRobinLoadBalance struct {
28 | }
29 |
30 | // 权重平滑负载均衡
31 | func (loadBalance *WeightRoundRobinLoadBalance) SelectService(services []*common.ServiceInstance) (best *common.ServiceInstance, err error) {
32 |
33 | if services == nil || len(services) == 0 {
34 | return nil, errors.New("service instances are not exist")
35 | }
36 |
37 | total := 0
38 | for i := 0; i < len(services); i++ {
39 | w := services[i]
40 | if w == nil {
41 | continue
42 | }
43 |
44 | w.CurWeight += w.Weight
45 |
46 | total += w.Weight
47 | if best == nil || w.CurWeight > best.CurWeight {
48 | best = w
49 | }
50 | }
51 |
52 | if best == nil {
53 | return nil, nil
54 | }
55 |
56 | best.CurWeight -= total
57 | return best, nil
58 | }
59 |
--------------------------------------------------------------------------------
/ch10-resiliency/gateway.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "flag"
5 | "fmt"
6 | kitlog "github.com/go-kit/kit/log"
7 | "github.com/longjoy/micro-go-book/common/discover"
8 | "github.com/longjoy/micro-go-book/common/loadbalance"
9 | "log"
10 | "net/http"
11 | "os"
12 | "os/signal"
13 | "syscall"
14 | )
15 |
16 | func main() {
17 |
18 | // 创建环境变量
19 | var (
20 | consulHost = flag.String("consul.host", "127.0.0.1", "consul server ip address")
21 | consulPort = flag.Int("consul.port", 8500, "consul server port")
22 | )
23 | flag.Parse()
24 |
25 | //创建日志组件
26 | var logger kitlog.Logger
27 | {
28 | logger = kitlog.NewLogfmtLogger(os.Stderr)
29 | logger = kitlog.With(logger, "ts", kitlog.DefaultTimestampUTC)
30 | logger = kitlog.With(logger, "caller", kitlog.DefaultCaller)
31 | }
32 |
33 |
34 |
35 | consulClient, err := discover.NewKitDiscoverClient(*consulHost, *consulPort)
36 |
37 | if err != nil {
38 | logger.Log("err", err)
39 | os.Exit(1)
40 | }
41 |
42 | //创建反向代理
43 | proxy := NewHystrixHandler(consulClient, new(loadbalance.RandomLoadBalance), log.New(os.Stderr, "", log.LstdFlags))
44 |
45 | errc := make(chan error)
46 | go func() {
47 | c := make(chan os.Signal)
48 | signal.Notify(c, syscall.SIGINT, syscall.SIGTERM)
49 | errc <- fmt.Errorf("%s", <-c)
50 | }()
51 |
52 | //开始监听
53 | go func() {
54 | logger.Log("transport", "HTTP", "addr", "9090")
55 | errc <- http.ListenAndServe(":9090", proxy)
56 | }()
57 |
58 | // 开始运行,等待结束
59 | logger.Log("exit", <-errc)
60 | }
61 |
--------------------------------------------------------------------------------
/ch6-discovery/service/service.go:
--------------------------------------------------------------------------------
1 | package service
2 |
3 | import (
4 | "context"
5 | "errors"
6 | "github.com/longjoy/micro-go-book/ch6-discovery/config"
7 | "github.com/longjoy/micro-go-book/ch6-discovery/discover"
8 | )
9 |
10 | type Service interface {
11 |
12 |
13 | // HealthCheck check service health status
14 | HealthCheck() bool
15 |
16 | // sayHelloService
17 | SayHello() string
18 |
19 | // discovery service from consul by serviceName
20 | DiscoveryService(ctx context.Context, serviceName string) ([]interface{}, error)
21 |
22 | }
23 |
24 |
25 | var ErrNotServiceInstances = errors.New("instances are not existed")
26 |
27 | type DiscoveryServiceImpl struct {
28 | discoveryClient discover.DiscoveryClient
29 | }
30 |
31 | func NewDiscoveryServiceImpl(discoveryClient discover.DiscoveryClient) Service {
32 | return &DiscoveryServiceImpl{
33 | discoveryClient:discoveryClient,
34 | }
35 | }
36 |
37 | func (*DiscoveryServiceImpl) SayHello() string {
38 | return "Hello World!"
39 | }
40 |
41 | func (service *DiscoveryServiceImpl) DiscoveryService(ctx context.Context, serviceName string) ([]interface{}, error) {
42 |
43 | instances := service.discoveryClient.DiscoverServices(serviceName, config.Logger)
44 |
45 | if instances == nil || len(instances) == 0 {
46 | return nil, ErrNotServiceInstances
47 | }
48 | return instances, nil
49 | }
50 |
51 |
52 | // HealthCheck implement Service method
53 | // 用于检查服务的健康状态,这里仅仅返回true
54 | func (*DiscoveryServiceImpl) HealthCheck() bool {
55 | return true
56 | }
57 |
58 |
--------------------------------------------------------------------------------
/ch12-trace/zipkin-kit/client/stringModel.go:
--------------------------------------------------------------------------------
1 | package client
2 |
3 | import (
4 | "context"
5 | "github.com/longjoy/micro-go-book/ch12-trace/zipkin-kit/pb"
6 | "github.com/longjoy/micro-go-book/ch12-trace/zipkin-kit/string-service/endpoint"
7 | "github.com/pkg/errors"
8 | )
9 |
10 | func EncodeGRPCStringRequest(_ context.Context, r interface{}) (interface{}, error) {
11 | req := r.(endpoint.StringRequest)
12 | return &pb.StringRequest{
13 | RequestType: string(req.RequestType),
14 | A: string(req.A),
15 | B: string(req.B),
16 | }, nil
17 | }
18 |
19 | func DecodeGRPCStringRequest(ctx context.Context, r interface{}) (interface{}, error) {
20 | req := r.(*pb.StringRequest)
21 | return endpoint.StringRequest{
22 | RequestType: string(req.RequestType),
23 | A: string(req.A),
24 | B: string(req.B),
25 | }, nil
26 | }
27 |
28 | func EncodeGRPCStringResponse(_ context.Context, r interface{}) (interface{}, error) {
29 | resp := r.(endpoint.StringResponse)
30 |
31 | if resp.Error != nil {
32 | return &pb.StringResponse{
33 | Result: string(resp.Result),
34 | Err: resp.Error.Error(),
35 | }, nil
36 | }
37 |
38 | return &pb.StringResponse{
39 | Result: string(resp.Result),
40 | Err: "",
41 | }, nil
42 | }
43 |
44 | func DecodeGRPCStringResponse(_ context.Context, r interface{}) (interface{}, error) {
45 | resp := r.(*pb.StringResponse)
46 | return endpoint.StringResponse{
47 | Result: string(resp.Result),
48 | Error: errors.New(resp.Err),
49 | }, nil
50 | }
51 |
--------------------------------------------------------------------------------
/ch9-gateway/string-service/logging.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "github.com/go-kit/kit/log"
5 | "time"
6 | )
7 |
8 | // loggingMiddleware Make a new type
9 | // that contains Service interface and logger instance
10 | type loggingMiddleware struct {
11 | Service
12 | logger log.Logger
13 | }
14 |
15 | // LoggingMiddleware make logging middleware
16 | func LoggingMiddleware(logger log.Logger) ServiceMiddleware {
17 | return func(next Service) Service {
18 | return loggingMiddleware{next, logger}
19 | }
20 | }
21 |
22 | func (mw loggingMiddleware) Concat(a, b string) (ret string, err error) {
23 |
24 | defer func(begin time.Time) {
25 | mw.logger.Log(
26 | "function", "Concat",
27 | "a", a,
28 | "b", b,
29 | "result", ret,
30 | "took", time.Since(begin),
31 | )
32 | }(time.Now())
33 |
34 | ret, err = mw.Service.Concat(a, b)
35 | return ret, err
36 | }
37 |
38 | func (mw loggingMiddleware) Diff(a, b string) (ret string, err error) {
39 |
40 | defer func(begin time.Time) {
41 | mw.logger.Log(
42 | "function", "Diff",
43 | "a", a,
44 | "b", b,
45 | "result", ret,
46 | "took", time.Since(begin),
47 | )
48 | }(time.Now())
49 |
50 | ret, err = mw.Service.Diff(a, b)
51 | return ret, err
52 | }
53 |
54 | func (mw loggingMiddleware) HealthCheck() (result bool) {
55 | defer func(begin time.Time) {
56 | mw.logger.Log(
57 | "function", "HealthChcek",
58 | "result", result,
59 | "took", time.Since(begin),
60 | )
61 | }(time.Now())
62 | result = mw.Service.HealthCheck()
63 | return
64 | }
65 |
--------------------------------------------------------------------------------
/common/loadbalance/loadbalance.go:
--------------------------------------------------------------------------------
1 | package loadbalance
2 |
3 | import (
4 | "errors"
5 | "github.com/hashicorp/consul/api"
6 | "math/rand"
7 | )
8 |
9 | // 负载均衡器
10 | type LoadBalance interface {
11 | SelectService(service []*api.AgentService) (*api.AgentService, error)
12 | }
13 |
14 | var ErrNoInstances = errors.New("service instances are not existed")
15 |
16 | type RandomLoadBalance struct {
17 | }
18 |
19 | // 随机负载均衡
20 | func (loadBalance *RandomLoadBalance) SelectService(services []*api.AgentService) (*api.AgentService, error) {
21 |
22 | if services == nil || len(services) == 0 {
23 | return nil, ErrNoInstances
24 | }
25 |
26 | return services[rand.Intn(len(services))], nil
27 | }
28 |
29 | type WeightRoundRobinLoadBalance struct {
30 | }
31 |
32 | //// 权重平滑负载均衡
33 | //func (loadBalance *WeightRoundRobinLoadBalance) SelectService(services []*discover.ServiceInstance) (best *discover.ServiceInstance, err error) {
34 | //
35 | // if services == nil || len(services) == 0 {
36 | // return nil, errors.New("service instances are not exist")
37 | // }
38 | //
39 | // total := 0
40 | // for i := 0; i < len(services); i++ {
41 | // w := services[i]
42 | // if w == nil {
43 | // continue
44 | // }
45 | //
46 | // w.CurWeight += w.Weight
47 | //
48 | // total += w.Weight
49 | // if w.Weight < w.Weight {
50 | // w.Weight++
51 | // }
52 | // if best == nil || w.CurWeight > best.CurWeight {
53 | // best = w
54 | // }
55 | // }
56 | //
57 | // if best == nil {
58 | // return nil, nil
59 | // }
60 | //
61 | // best.CurWeight -= total
62 | // return best, nil
63 | //}
64 |
--------------------------------------------------------------------------------
/ch11-security/service/user_service.go:
--------------------------------------------------------------------------------
1 | package service
2 |
3 | import (
4 | "context"
5 | "errors"
6 | "github.com/longjoy/micro-go-book/ch11-security/model"
7 | )
8 |
9 | var (
10 | ErrUserNotExist = errors.New("username is not exist")
11 | ErrPassword = errors.New("invalid password")
12 | )
13 | // Service Define a service interface
14 | type UserDetailsService interface {
15 | // Get UserDetails By username
16 | GetUserDetailByUsername(ctx context.Context, username, password string) (*model.UserDetails, error)
17 | }
18 |
19 | //UserService implement Service interface
20 | type InMemoryUserDetailsService struct {
21 | userDetailsDict map[string]*model.UserDetails
22 |
23 | }
24 |
25 | func (service *InMemoryUserDetailsService) GetUserDetailByUsername(ctx context.Context, username, password string) (*model.UserDetails, error) {
26 |
27 |
28 | // 根据 username 获取用户信息
29 | userDetails, ok := service.userDetailsDict[username]; if ok{
30 | // 比较 password 是否匹配
31 | if userDetails.Password == password{
32 | return userDetails, nil
33 | }else {
34 | return nil, ErrPassword
35 | }
36 | }else {
37 | return nil, ErrUserNotExist
38 | }
39 |
40 |
41 | }
42 |
43 | func NewInMemoryUserDetailsService(userDetailsList []*model.UserDetails) *InMemoryUserDetailsService {
44 | userDetailsDict := make(map[string]*model.UserDetails)
45 |
46 | if userDetailsList != nil {
47 | for _, value := range userDetailsList {
48 | userDetailsDict[value.Username] = value
49 | }
50 | }
51 |
52 | return &InMemoryUserDetailsService{
53 | userDetailsDict:userDetailsDict,
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/ch7-rpc/go-kit/string-service/logging.go:
--------------------------------------------------------------------------------
1 | package string_service
2 |
3 | import (
4 | "context"
5 | "github.com/go-kit/kit/log"
6 | "time"
7 | )
8 |
9 | // loggingMiddleware Make a new type
10 | // that contains Service interface and logger instance
11 | type loggingMiddleware struct {
12 | Service
13 | logger log.Logger
14 | }
15 |
16 | // LoggingMiddleware make logging middleware
17 | func LoggingMiddleware(logger log.Logger) ServiceMiddleware {
18 | return func(next Service) Service {
19 | return loggingMiddleware{next, logger}
20 | }
21 | }
22 |
23 | func (mw loggingMiddleware) Concat(ctx context.Context, a, b string) (ret string, err error) {
24 |
25 | defer func(begin time.Time) {
26 | mw.logger.Log(
27 | "function", "Concat",
28 | "a", a,
29 | "b", b,
30 | "result", ret,
31 | "took", time.Since(begin),
32 | )
33 | }(time.Now())
34 |
35 | ret, err = mw.Service.Concat(ctx, a, b)
36 | return ret, err
37 | }
38 |
39 | func (mw loggingMiddleware) Diff(ctx context.Context, a, b string) (ret string, err error) {
40 |
41 | defer func(begin time.Time) {
42 | mw.logger.Log(
43 | "function", "Diff",
44 | "a", a,
45 | "b", b,
46 | "result", ret,
47 | "took", time.Since(begin),
48 | )
49 | }(time.Now())
50 |
51 | ret, err = mw.Service.Diff(ctx, a, b)
52 | return ret, err
53 | }
54 |
55 | func (mw loggingMiddleware) HealthCheck() (result bool) {
56 | defer func(begin time.Time) {
57 | mw.logger.Log(
58 | "function", "HealthChcek",
59 | "result", result,
60 | "took", time.Since(begin),
61 | )
62 | }(time.Now())
63 | result = true
64 | return
65 | }
66 |
--------------------------------------------------------------------------------
/ch7-rpc/basic/string-service/service.go:
--------------------------------------------------------------------------------
1 | package service
2 |
3 | import (
4 | "errors"
5 | "strings"
6 | )
7 |
8 | // Service constants
9 | const (
10 | StrMaxSize = 1024
11 | )
12 |
13 | // Service errors
14 | var (
15 | ErrMaxSize = errors.New("maximum size of 1024 bytes exceeded")
16 |
17 | ErrStrValue = errors.New("maximum size of 1024 bytes exceeded")
18 | )
19 |
20 | type StringRequest struct {
21 | A string
22 | B string
23 | }
24 |
25 | type Service interface {
26 | // Concat a and b
27 | Concat(req StringRequest, ret *string) error
28 |
29 | // a,b pkg string value
30 | Diff(req StringRequest, ret *string) error
31 | }
32 |
33 | //ArithmeticService implement Service interface
34 | type StringService struct {
35 | }
36 |
37 | func (s StringService) Concat(req StringRequest, ret *string) error {
38 | // test for length overflow
39 | if len(req.A)+len(req.B) > StrMaxSize {
40 | *ret = ""
41 | return ErrMaxSize
42 | }
43 | *ret = req.A + req.B
44 | return nil
45 | }
46 |
47 | func (s StringService) Diff(req StringRequest, ret *string) error {
48 | if len(req.A) < 1 || len(req.B) < 1 {
49 | *ret = ""
50 | return nil
51 | }
52 | res := ""
53 | if len(req.A) >= len(req.B) {
54 | for _, char := range req.B {
55 | if strings.Contains(req.A, string(char)) {
56 | res = res + string(char)
57 | }
58 | }
59 | } else {
60 | for _, char := range req.A {
61 | if strings.Contains(req.B, string(char)) {
62 | res = res + string(char)
63 | }
64 | }
65 | }
66 | *ret = res
67 | return nil
68 | }
69 |
70 | // ServiceMiddleware define service middleware
71 | type ServiceMiddleware func(Service) Service
72 |
--------------------------------------------------------------------------------
/ch13-seckill/pkg/client/oauth.go:
--------------------------------------------------------------------------------
1 | package client
2 |
3 | import (
4 | "context"
5 | "github.com/longjoy/micro-go-book/ch13-seckill/pb"
6 | "github.com/longjoy/micro-go-book/ch13-seckill/pkg/discover"
7 | "github.com/longjoy/micro-go-book/ch13-seckill/pkg/loadbalance"
8 | "github.com/opentracing/opentracing-go"
9 | )
10 |
11 | type OAuthClient interface {
12 | CheckToken(ctx context.Context, tracer opentracing.Tracer, request *pb.CheckTokenRequest) (*pb.CheckTokenResponse, error)
13 | }
14 |
15 | type OAuthClientImpl struct {
16 | manager ClientManager
17 | serviceName string
18 | loadBalance loadbalance.LoadBalance
19 | tracer opentracing.Tracer
20 | }
21 |
22 | func (impl *OAuthClientImpl) CheckToken(ctx context.Context, tracer opentracing.Tracer, request *pb.CheckTokenRequest) (*pb.CheckTokenResponse, error) {
23 | response := new(pb.CheckTokenResponse)
24 | if err := impl.manager.DecoratorInvoke("/pb.OAuthService/CheckToken", "token_check", tracer, ctx, request, response); err == nil {
25 | return response, nil
26 | } else {
27 | return nil, err
28 | }
29 | }
30 | func NewOAuthClient(serviceName string, lb loadbalance.LoadBalance, tracer opentracing.Tracer) (OAuthClient, error) {
31 | if serviceName == "" {
32 | serviceName = "oauth"
33 | }
34 | if lb == nil {
35 | lb = defaultLoadBalance
36 | }
37 |
38 | return &OAuthClientImpl{
39 | manager: &DefaultClientManager{
40 | serviceName: serviceName,
41 | loadBalance: lb,
42 | discoveryClient:discover.ConsulService,
43 | logger:discover.Logger,
44 | },
45 | serviceName: serviceName,
46 | loadBalance: lb,
47 | tracer: tracer,
48 | }, nil
49 |
50 | }
51 |
--------------------------------------------------------------------------------
/ch7-rpc/go-kit/string-service/service.go:
--------------------------------------------------------------------------------
1 | package string_service
2 |
3 | import (
4 | "context"
5 | "errors"
6 | "fmt"
7 | "strings"
8 | )
9 |
10 | // Service constants
11 | const (
12 | StrMaxSize = 1024
13 | )
14 |
15 | // Service errors
16 | var (
17 | ErrMaxSize = errors.New("maximum size of 1024 bytes exceeded")
18 |
19 | ErrStrValue = errors.New("maximum size of 1024 bytes exceeded")
20 | )
21 |
22 | // Service Define a service interface
23 | type Service interface {
24 | // Concat a and b
25 | Concat(ctx context.Context, a, b string) (string, error)
26 |
27 | // a,b pkg string value
28 | Diff(ctx context.Context, a, b string) (string, error)
29 | }
30 |
31 | //ArithmeticService implement Service interface
32 | type StringService struct {
33 | }
34 |
35 | func (s StringService) Concat(ctx context.Context, a, b string) (string, error) {
36 | // test for length overflow
37 | if len(a)+len(b) > StrMaxSize {
38 | return "", ErrMaxSize
39 | }
40 | fmt.Printf("StringService Concat return %s", a+b)
41 | return a + b, nil
42 | }
43 |
44 | func (s StringService) Diff(ctx context.Context, a, b string) (string, error) {
45 | if len(a) < 1 || len(b) < 1 {
46 | return "", nil
47 | }
48 | res := ""
49 | if len(a) >= len(b) {
50 | for _, char := range b {
51 | if strings.Contains(a, string(char)) {
52 | res = res + string(char)
53 | }
54 | }
55 | } else {
56 | for _, char := range a {
57 | if strings.Contains(b, string(char)) {
58 | res = res + string(char)
59 | }
60 | }
61 | }
62 | return res, nil
63 | }
64 |
65 | // ServiceMiddleware define service middleware
66 | type ServiceMiddleware func(Service) Service
67 |
--------------------------------------------------------------------------------
/ch11-security/service/client_service.go:
--------------------------------------------------------------------------------
1 | package service
2 |
3 | import (
4 | "context"
5 | "errors"
6 | "github.com/longjoy/micro-go-book/ch11-security/model"
7 | )
8 |
9 | var (
10 |
11 | ErrClientNotExist = errors.New("clientId is not exist")
12 | ErrClientSecret = errors.New("invalid clientSecret")
13 |
14 | )
15 |
16 | // Service Define a service interface
17 | type ClientDetailsService interface {
18 |
19 | GetClientDetailByClientId(ctx context.Context, clientId string, clientSecret string)(*model.ClientDetails, error)
20 |
21 | }
22 |
23 | type InMemoryClientDetailsService struct {
24 | clientDetailsDict map[string]*model.ClientDetails
25 |
26 | }
27 |
28 | func NewInMemoryClientDetailService(clientDetailsList []*model.ClientDetails ) *InMemoryClientDetailsService{
29 | clientDetailsDict := make(map[string]*model.ClientDetails)
30 |
31 | if clientDetailsList != nil {
32 | for _, value := range clientDetailsList {
33 | clientDetailsDict[value.ClientId] = value
34 | }
35 | }
36 |
37 | return &InMemoryClientDetailsService{
38 | clientDetailsDict:clientDetailsDict,
39 | }
40 | }
41 |
42 |
43 | func (service *InMemoryClientDetailsService)GetClientDetailByClientId(ctx context.Context, clientId string, clientSecret string)(*model.ClientDetails, error) {
44 |
45 | // 根据 clientId 获取 clientDetails
46 | clientDetails, ok := service.clientDetailsDict[clientId]; if ok{
47 | // 比较 clientSecret 是否正确
48 | if clientDetails.ClientSecret == clientSecret{
49 | return clientDetails, nil
50 | }else {
51 | return nil, ErrClientSecret
52 | }
53 | }else {
54 | return nil, ErrClientNotExist
55 | }
56 |
57 |
58 |
59 | }
60 |
61 |
62 |
--------------------------------------------------------------------------------
/ch13-seckill/pkg/client/user.go:
--------------------------------------------------------------------------------
1 | package client
2 |
3 | import (
4 | "context"
5 | "github.com/longjoy/micro-go-book/ch13-seckill/pb"
6 | "github.com/longjoy/micro-go-book/ch13-seckill/pkg/discover"
7 | "github.com/longjoy/micro-go-book/ch13-seckill/pkg/loadbalance"
8 | "github.com/opentracing/opentracing-go"
9 | )
10 |
11 | type UserClient interface {
12 | CheckUser(ctx context.Context, tracer opentracing.Tracer, request *pb.UserRequest) (*pb.UserResponse, error)
13 | }
14 |
15 | type UserClientImpl struct {
16 | /**
17 | * 可以配置负载均衡策略,重试、等机制。也可以配置invokeAfter和invokerBefore
18 | */
19 | manager ClientManager
20 | serviceName string
21 | loadBalance loadbalance.LoadBalance
22 | tracer opentracing.Tracer
23 | }
24 |
25 | func (impl *UserClientImpl) CheckUser(ctx context.Context, tracer opentracing.Tracer, request *pb.UserRequest) (*pb.UserResponse, error) {
26 | response := new(pb.UserResponse)
27 | if err := impl.manager.DecoratorInvoke("/pb.UserService/Check", "user_check", tracer, ctx, request, response); err == nil {
28 | return response, nil
29 | } else {
30 | return nil, err
31 | }
32 | }
33 |
34 | func NewUserClient(serviceName string, lb loadbalance.LoadBalance, tracer opentracing.Tracer) (UserClient, error) {
35 | if serviceName == "" {
36 | serviceName = "user"
37 | }
38 | if lb == nil {
39 | lb = defaultLoadBalance
40 | }
41 |
42 | return &UserClientImpl{
43 | manager: &DefaultClientManager{
44 | serviceName: serviceName,
45 | loadBalance: lb,
46 | discoveryClient:discover.ConsulService,
47 | logger:discover.Logger,
48 | },
49 | serviceName: serviceName,
50 | loadBalance: lb,
51 | tracer: tracer,
52 | }, nil
53 |
54 | }
55 |
--------------------------------------------------------------------------------
/ch9-gateway/string-service/service.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "errors"
5 | "strings"
6 | )
7 |
8 | // Service constants
9 | const (
10 | StrMaxSize = 1024
11 | )
12 |
13 | // Service errors
14 | var (
15 | ErrMaxSize = errors.New("maximum size of 1024 bytes exceeded")
16 |
17 | ErrStrValue = errors.New("maximum size of 1024 bytes exceeded")
18 | )
19 |
20 | // Service Define a service interface
21 | type Service interface {
22 | // Concat a and b
23 | Concat(a, b string) (string, error)
24 |
25 | // a,b pkg string value
26 | Diff(a, b string) (string, error)
27 |
28 | // HealthCheck check service health status
29 | HealthCheck() bool
30 | }
31 |
32 | //ArithmeticService implement Service interface
33 | type StringService struct {
34 | }
35 |
36 | func (s StringService) Concat(a, b string) (string, error) {
37 | // test for length overflow
38 | if len(a)+len(b) > StrMaxSize {
39 | return "", ErrMaxSize
40 | }
41 | return a + b, nil
42 | }
43 |
44 | func (s StringService) Diff(a, b string) (string, error) {
45 | if len(a) < 1 || len(b) < 1 {
46 | return "", nil
47 | }
48 | res := ""
49 | if len(a) >= len(b) {
50 | for _, char := range b {
51 | if strings.Contains(a, string(char)) {
52 | res = res + string(char)
53 | }
54 | }
55 | } else {
56 | for _, char := range a {
57 | if strings.Contains(b, string(char)) {
58 | res = res + string(char)
59 | }
60 | }
61 | }
62 | return res, nil
63 | }
64 |
65 | // HealthCheck implement Service method
66 | // 用于检查服务的健康状态,这里仅仅返回true。
67 | func (s StringService) HealthCheck() bool {
68 | return true
69 | }
70 |
71 | // ServiceMiddleware define service middleware
72 | type ServiceMiddleware func(Service) Service
73 |
--------------------------------------------------------------------------------
/ch13-seckill/oauth-service/service/user_service.go:
--------------------------------------------------------------------------------
1 | package service
2 |
3 | import (
4 | "context"
5 | "errors"
6 | "github.com/longjoy/micro-go-book/ch13-seckill/oauth-service/model"
7 | "github.com/longjoy/micro-go-book/ch13-seckill/pb"
8 | "github.com/longjoy/micro-go-book/ch13-seckill/pkg/client"
9 | )
10 |
11 | var (
12 | InvalidAuthentication = errors.New("invalid auth")
13 | InvalidUserInfo = errors.New("invalid user info")
14 |
15 | )
16 | // Service Define a service interface
17 | type UserDetailsService interface {
18 | // Get UserDetails By username
19 | GetUserDetailByUsername(ctx context.Context, username, password string) (*model.UserDetails, error)
20 | }
21 |
22 | //UserService implement Service interface
23 | type RemoteUserService struct {
24 |
25 | userClient client.UserClient
26 |
27 |
28 | }
29 |
30 | func (service *RemoteUserService) GetUserDetailByUsername(ctx context.Context, username, password string) (*model.UserDetails, error) {
31 |
32 | response, err := service.userClient.CheckUser(ctx, nil, &pb.UserRequest{
33 | Username:username,
34 | Password:password,
35 | })
36 |
37 | if err == nil{
38 | if response.UserId != 0 {
39 | return &model.UserDetails{
40 | UserId:response.UserId,
41 | Username:username,
42 | Password:password,
43 | }, nil
44 | }else {
45 | return nil, InvalidUserInfo
46 | }
47 | }
48 | return nil, err
49 |
50 | }
51 |
52 | func NewRemoteUserDetailService() *RemoteUserService {
53 |
54 | userClient, _ := client.NewUserClient("user", nil, nil)
55 | return &RemoteUserService{
56 | userClient:userClient,
57 | }
58 | }
59 |
60 | // ServiceMiddleware define service middleware
61 | type ServiceMiddleware func(Service) Service
62 |
--------------------------------------------------------------------------------
/ch6-discovery/string-service/plugins/logging.go:
--------------------------------------------------------------------------------
1 | package plugins
2 |
3 | import (
4 | "github.com/go-kit/kit/log"
5 | "github.com/longjoy/micro-go-book/ch6-discovery/string-service/service"
6 | "time"
7 | )
8 |
9 | // loggingMiddleware Make a new type
10 | // that contains Service interface and logger instance
11 | type loggingMiddleware struct {
12 | service.Service
13 | logger log.Logger
14 | }
15 |
16 | // LoggingMiddleware make logging middleware
17 | func LoggingMiddleware(logger log.Logger) service.ServiceMiddleware {
18 | return func(next service.Service) service.Service {
19 | return loggingMiddleware{next, logger}
20 | }
21 | }
22 |
23 | func (mw loggingMiddleware) Concat(a, b string) (ret string, err error) {
24 | // 函数执行结束后打印日志
25 | defer func(begin time.Time) {
26 | mw.logger.Log(
27 | "function", "Concat",
28 | "a", a,
29 | "b", b,
30 | "result", ret,
31 | "took", time.Since(begin),
32 | )
33 | }(time.Now())
34 |
35 | ret, err = mw.Service.Concat(a, b)
36 | return ret, err
37 | }
38 |
39 | func (mw loggingMiddleware) Diff(a, b string) (ret string, err error) {
40 | // 函数执行结束后打印日志
41 | defer func(begin time.Time) {
42 | mw.logger.Log(
43 | "function", "Diff",
44 | "a", a,
45 | "b", b,
46 | "result", ret,
47 | "took", time.Since(begin),
48 | )
49 | }(time.Now())
50 |
51 | ret, err = mw.Service.Diff(a, b)
52 | return ret, err
53 | }
54 |
55 | func (mw loggingMiddleware) HealthCheck() (result bool) {
56 | defer func(begin time.Time) {
57 | mw.logger.Log(
58 | "function", "HealthChcek",
59 | "result", result,
60 | "took", time.Since(begin),
61 | )
62 | }(time.Now())
63 | result = mw.Service.HealthCheck()
64 | return
65 | }
66 |
67 |
68 |
--------------------------------------------------------------------------------
/ch10-resiliency/string-service/plugins/logging.go:
--------------------------------------------------------------------------------
1 | package plugins
2 |
3 | import (
4 | "github.com/go-kit/kit/log"
5 | "github.com/longjoy/micro-go-book/ch10-resiliency/string-service/service"
6 | "time"
7 | )
8 |
9 | // loggingMiddleware Make a new type
10 | // that contains Service interface and logger instance
11 | type loggingMiddleware struct {
12 | service.Service
13 | logger log.Logger
14 | }
15 |
16 | // LoggingMiddleware make logging middleware
17 | func LoggingMiddleware(logger log.Logger) service.ServiceMiddleware {
18 | return func(next service.Service) service.Service {
19 | return loggingMiddleware{next, logger}
20 | }
21 | }
22 |
23 | func (mw loggingMiddleware) Concat(a, b string) (ret string, err error) {
24 | // 函数执行结束后打印日志
25 | defer func(begin time.Time) {
26 | mw.logger.Log(
27 | "function", "Concat",
28 | "a", a,
29 | "b", b,
30 | "result", ret,
31 | "took", time.Since(begin),
32 | )
33 | }(time.Now())
34 |
35 | ret, err = mw.Service.Concat(a, b)
36 | return ret, err
37 | }
38 |
39 | func (mw loggingMiddleware) Diff(a, b string) (ret string, err error) {
40 | // 函数执行结束后打印日志
41 | defer func(begin time.Time) {
42 | mw.logger.Log(
43 | "function", "Diff",
44 | "a", a,
45 | "b", b,
46 | "result", ret,
47 | "took", time.Since(begin),
48 | )
49 | }(time.Now())
50 |
51 | ret, err = mw.Service.Diff(a, b)
52 | return ret, err
53 | }
54 |
55 | func (mw loggingMiddleware) HealthCheck() (result bool) {
56 | defer func(begin time.Time) {
57 | mw.logger.Log(
58 | "function", "HealthChcek",
59 | "result", result,
60 | "took", time.Since(begin),
61 | )
62 | }(time.Now())
63 | result = mw.Service.HealthCheck()
64 | return
65 | }
66 |
67 |
68 |
--------------------------------------------------------------------------------
/ch12-trace/zipkin-kit/string-service/logging.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "context"
5 | "github.com/go-kit/kit/log"
6 | "github.com/longjoy/micro-go-book/ch12-trace/zipkin-kit/string-service/service"
7 | "time"
8 | )
9 |
10 | // loggingMiddleware Make a new type
11 | // that contains Service interface and logger instance
12 | type loggingMiddleware struct {
13 | service.Service
14 | logger log.Logger
15 | }
16 |
17 | // LoggingMiddleware make logging middleware
18 | func LoggingMiddleware(logger log.Logger) service.ServiceMiddleware {
19 | return func(next service.Service) service.Service {
20 | return loggingMiddleware{next, logger}
21 | }
22 | }
23 |
24 | func (mw loggingMiddleware) Concat(a, b string) (ret string, err error) {
25 |
26 | defer func(begin time.Time) {
27 | mw.logger.Log(
28 | "function", "Concat",
29 | "a", a,
30 | "b", b,
31 | "result", ret,
32 | "took", time.Since(begin),
33 | )
34 | }(time.Now())
35 |
36 | ret, err = mw.Service.Concat(a, b)
37 | return ret, err
38 | }
39 |
40 | func (mw loggingMiddleware) Diff(ctx context.Context, a, b string) (ret string, err error) {
41 |
42 | defer func(begin time.Time) {
43 | mw.logger.Log(
44 | "function", "Diff",
45 | "a", a,
46 | "b", b,
47 | "result", ret,
48 | "took", time.Since(begin),
49 | )
50 | }(time.Now())
51 |
52 | ret, err = mw.Service.Diff(ctx, a, b)
53 | return ret, err
54 | }
55 |
56 | func (mw loggingMiddleware) HealthCheck() (result bool) {
57 | defer func(begin time.Time) {
58 | mw.logger.Log(
59 | "function", "HealthChcek",
60 | "result", result,
61 | "took", time.Since(begin),
62 | )
63 | }(time.Now())
64 | result = mw.Service.HealthCheck()
65 | return
66 | }
67 |
--------------------------------------------------------------------------------
/ch10-resiliency/string-service/service/service.go:
--------------------------------------------------------------------------------
1 | package service
2 |
3 | import (
4 | "errors"
5 | "strings"
6 | )
7 |
8 | // Service constants
9 | const (
10 | StrMaxSize = 1024
11 | )
12 |
13 | // Service errors
14 | var (
15 | ErrMaxSize = errors.New("maximum size of 1024 bytes exceeded")
16 |
17 | ErrStrValue = errors.New("maximum size of 1024 bytes exceeded")
18 | )
19 |
20 | // Service Define a service interface
21 | type Service interface {
22 | // Concat a and b
23 | Concat(a, b string) (string, error)
24 |
25 | // a,b pkg string value
26 | Diff(a, b string) (string, error)
27 |
28 | // HealthCheck check service health status
29 | HealthCheck() bool
30 | }
31 |
32 | //ArithmeticService implement Service interface
33 | type StringService struct {
34 | }
35 |
36 | func (s StringService) Concat(a, b string) (string, error) {
37 | // test for length overflow
38 | if len(a)+len(b) > StrMaxSize {
39 | return "", ErrMaxSize
40 | }
41 | return a + b, nil
42 | }
43 |
44 | func (s StringService) Diff(a, b string) (string, error) {
45 | if len(a) < 1 || len(b) < 1 {
46 | return "", nil
47 | }
48 | res := ""
49 | if len(a) >= len(b) {
50 | for _, char := range b {
51 | if strings.Contains(a, string(char)) {
52 | res = res + string(char)
53 | }
54 | }
55 | } else {
56 | for _, char := range a {
57 | if strings.Contains(b, string(char)) {
58 | res = res + string(char)
59 | }
60 | }
61 | }
62 | return res, nil
63 | }
64 |
65 | // HealthCheck implement Service method
66 | // 用于检查服务的健康状态,这里仅仅返回true。
67 | func (s StringService) HealthCheck() bool {
68 | return true
69 | }
70 |
71 | // ServiceMiddleware define service middleware
72 | type ServiceMiddleware func(Service) Service
73 |
--------------------------------------------------------------------------------
/ch12-trace/zipkin-go/string-services/README.md:
--------------------------------------------------------------------------------
1 | ## Zipkin tracing using OpenTracing API
2 |
3 | This directory contains a super simple command line client and two HTTP services
4 | which are instrumented using the OpenTracing API using the
5 | [zipkin-go-opentracing](https://github.com/openzipkin-contrib/zipkin-go-opentracing)
6 | tracer.
7 |
8 | The code is a quick hack to solely demonstrate the usage of
9 | [OpenTracing](http://opentracing.io) with a [Zipkin](http://zipkin.io) backend.
10 |
11 | ```
12 | note: the examples will only compile with Go 1.7 or higher
13 | ```
14 |
15 | ## Usage:
16 |
17 | Build `svc1`, `svc2` and `cli` with `make` and start both compiled services
18 | found in the newly created `build` subdirectory.
19 |
20 | When you call the `cli` program it will trigger two calls to `svc1` of which one
21 | call will be proxied from `svc1` over to `svc2` to handle the method and by that
22 | generating a couple of spans across services.
23 |
24 | Methods have been instrumented with some examples of
25 | [OpenTracing](http://opentracing.io) Tags which will be transformed into
26 | [Zipkin](http://zipkin.io) binary annotations and
27 | [OpenTracing](http://opentracing.io) LogEvents which will be transformed into
28 | [Zipkin](http://zipkin.io) annotations.
29 |
30 | The most interesting piece of code is found in `examples/middleware` which is
31 | kind of the missing link for people looking for a tracing framework. I advise
32 | you to seriously look into using [Go kit](https://gokit.io) and use its
33 | abstractions and OpenTracing middleware with which this Tracer is fully
34 | compatible, instead of rolling your own. If you still want to roll your own you
35 | can use `examples/middleware` as a starting point.
36 |
--------------------------------------------------------------------------------
/ch6-discovery/string-service/service/service.go:
--------------------------------------------------------------------------------
1 | package service
2 |
3 | import (
4 | "errors"
5 | "strings"
6 | )
7 |
8 | // Service constants
9 | const (
10 | StrMaxSize = 1024
11 | )
12 |
13 | // Service errors
14 | var (
15 | ErrMaxSize = errors.New("maximum size of 1024 bytes exceeded")
16 |
17 | ErrStrValue = errors.New("maximum size of 1024 bytes exceeded")
18 | )
19 |
20 | // Service Define a service interface
21 | type Service interface {
22 | // Concat a and b
23 | Concat(a, b string) (string, error)
24 |
25 | // a,b pkg string value
26 | Diff(a, b string) (string, error)
27 |
28 | // HealthCheck check service health status
29 | HealthCheck() bool
30 | }
31 |
32 | //ArithmeticService implement Service interface
33 | type StringService struct {
34 | }
35 |
36 | func (s StringService) Concat(a, b string) (string, error) {
37 | // test for length overflow
38 | if len(a)+len(b) > StrMaxSize {
39 | return "", ErrMaxSize
40 | }
41 | return a + b, nil
42 | }
43 |
44 | func (s StringService) Diff(a, b string) (string, error) {
45 | if len(a) < 1 || len(b) < 1 {
46 | return "", nil
47 | }
48 | res := ""
49 | if len(a) >= len(b) {
50 | for _, char := range b {
51 | if strings.Contains(a, string(char)) {
52 | res = res + string(char)
53 | }
54 | }
55 | } else {
56 | for _, char := range a {
57 | if strings.Contains(b, string(char)) {
58 | res = res + string(char)
59 | }
60 | }
61 | }
62 | return res, nil
63 | }
64 |
65 | // HealthCheck implement Service method
66 | // 用于检查服务的健康状态,这里仅仅返回true。
67 | func (s StringService) HealthCheck() bool {
68 | return true
69 | }
70 |
71 | // ServiceMiddleware define service middleware
72 | type ServiceMiddleware func(Service) Service
73 |
--------------------------------------------------------------------------------
/ch12-trace/zipkin-kit/string-service/service/service.go:
--------------------------------------------------------------------------------
1 | package service
2 |
3 | import (
4 | "context"
5 | "errors"
6 | "strings"
7 | )
8 |
9 | // Service constants
10 | const (
11 | StrMaxSize = 1024
12 | )
13 |
14 | // Service errors
15 | var (
16 | ErrMaxSize = errors.New("maximum size of 1024 bytes exceeded")
17 |
18 | ErrStrValue = errors.New("error str value to Integer")
19 | )
20 |
21 | // Service Define a service interface
22 | type Service interface {
23 | // Concat a and b
24 | Concat(a, b string) (string, error)
25 |
26 | // a,b pkg string value
27 | Diff(ctx context.Context, a, b string) (string, error)
28 |
29 | // HealthCheck check service health status
30 | HealthCheck() bool
31 | }
32 |
33 | //ArithmeticService implement Service interface
34 | type StringService struct {
35 | }
36 |
37 | func (s StringService) Concat(a, b string) (string, error) {
38 | // test for length overflow
39 | if len(a)+len(b) > StrMaxSize {
40 | return "", ErrMaxSize
41 | }
42 | return a + b, nil
43 | }
44 |
45 | func (s StringService) Diff(ctx context.Context, a, b string) (string, error) {
46 | if len(a) < 1 || len(b) < 1 {
47 | return "", nil
48 | }
49 | res := ""
50 | if len(a) >= len(b) {
51 | for _, char := range b {
52 | if strings.Contains(a, string(char)) {
53 | res = res + string(char)
54 | }
55 | }
56 | } else {
57 | for _, char := range a {
58 | if strings.Contains(b, string(char)) {
59 | res = res + string(char)
60 | }
61 | }
62 | }
63 | return res, nil
64 | }
65 |
66 | // HealthCheck implement Service method
67 | // 用于检查服务的健康状态,这里仅仅返回true。
68 | func (s StringService) HealthCheck() bool {
69 | return true
70 | }
71 |
72 | // ServiceMiddleware define service middleware
73 | type ServiceMiddleware func(Service) Service
74 |
--------------------------------------------------------------------------------
/ch12-trace/zipkin-go/string-services/svc2/httpserver.go:
--------------------------------------------------------------------------------
1 | // +build go1.7
2 |
3 | package svc2
4 |
5 | import (
6 | "fmt"
7 | "net/http"
8 | "strconv"
9 |
10 | opentracing "github.com/opentracing/opentracing-go"
11 |
12 | "github.com/openzipkin-contrib/zipkin-go-opentracing/examples/middleware"
13 | )
14 |
15 | type httpService struct {
16 | service Service
17 | }
18 |
19 | // sumHandler is our HTTP Handlerfunc for a Sum request.
20 | func (s *httpService) sumHandler(w http.ResponseWriter, req *http.Request) {
21 | // parse query parameters
22 | v := req.URL.Query()
23 | a, err := strconv.ParseInt(v.Get("a"), 10, 64)
24 | if err != nil {
25 | http.Error(w, err.Error(), http.StatusBadRequest)
26 | return
27 | }
28 | b, err := strconv.ParseInt(v.Get("b"), 10, 64)
29 | if err != nil {
30 | http.Error(w, err.Error(), http.StatusBadRequest)
31 | return
32 | }
33 | // call our Sum binding
34 | result, err := s.service.Sum(req.Context(), a, b)
35 | if err != nil {
36 | http.Error(w, err.Error(), http.StatusBadRequest)
37 | return
38 | }
39 | // return the result
40 | w.Write([]byte(fmt.Sprintf("%d", result)))
41 | }
42 |
43 | // NewHTTPHandler returns a new HTTP handler our svc2.
44 | func NewHTTPHandler(tracer opentracing.Tracer, service Service) http.Handler {
45 | // Create our HTTP Service.
46 | svc := &httpService{service: service}
47 |
48 | // Create the mux.
49 | mux := http.NewServeMux()
50 |
51 | // Create the Sum handler.
52 | var sumHandler http.Handler
53 | sumHandler = http.HandlerFunc(svc.sumHandler)
54 |
55 | // Wrap the Sum handler with our tracing middleware.
56 | sumHandler = middleware.FromHTTPRequest(tracer, "Sum")(sumHandler)
57 |
58 | // Wire up the mux.
59 | mux.Handle("/sum/", sumHandler)
60 |
61 | // Return the mux.
62 | return mux
63 | }
64 |
--------------------------------------------------------------------------------
/ch13-seckill/sk-admin/setup/zk_test.go:
--------------------------------------------------------------------------------
1 | package setup
2 |
3 | import (
4 | "fmt"
5 | conf "github.com/longjoy/micro-go-book/ch13-seckill/pkg/config"
6 | "github.com/samuel/go-zookeeper/zk"
7 | "log"
8 | "testing"
9 | "time"
10 | )
11 |
12 | func ZkStateStringFormat(s *zk.Stat) string {
13 | return fmt.Sprintf("Czxid:%d\nMzxid: %d\nCtime: %d\nMtime: %d\nVersion: %d\nCversion: %d\nAversion: %d\nEphemeralOwner: %d\nDataLength: %d\nNumChildren: %d\nPzxid: %d\n",
14 | s.Czxid, s.Mzxid, s.Ctime, s.Mtime, s.Version, s.Cversion, s.Aversion, s.EphemeralOwner, s.DataLength, s.NumChildren, s.Pzxid)
15 | }
16 |
17 | func waitSecProductEvent(event zk.Event) {
18 | log.Print(">>>>>>>>>>>>>>>>>>>")
19 | log.Println("path:", event.Path)
20 | log.Println("type:", event.Type.String())
21 | log.Println("state:", event.State.String())
22 | log.Println("<<<<<<<<<<<<<<<<<<<")
23 | if event.Path == conf.Zk.SecProductKey {
24 |
25 | }
26 | }
27 |
28 | func TestInitZK(t *testing.T) {
29 | var hosts = []string{"39.98.179.73:2181"}
30 | option := zk.WithEventCallback(waitSecProductEvent)
31 | conn, _, err := zk.Connect(hosts, time.Second*5, option)
32 | if err != nil {
33 | fmt.Println(err)
34 | return
35 | }
36 |
37 | var path = "/zk_test_g1o"
38 | var data = []byte("hello")
39 | var flags int32 = 0
40 | // permission
41 | var acls = zk.WorldACL(zk.PermAll)
42 |
43 | // create
44 | p, err_create := conn.Create(path, data, flags, acls)
45 | if err_create != nil {
46 | fmt.Println(err_create)
47 | return
48 | }
49 | fmt.Println("created:", p)
50 |
51 | // get
52 | v, s, err := conn.Get(path)
53 | if err != nil {
54 | fmt.Println(err)
55 | return
56 | }
57 |
58 | fmt.Printf("value of path[%s]=[%s].\n", path, v)
59 | fmt.Printf("state:\n")
60 | fmt.Printf("%s\n", ZkStateStringFormat(s))
61 |
62 | defer conn.Close()
63 | }
64 |
--------------------------------------------------------------------------------
/ch9-gateway/string-service/endpoints.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "context"
5 | "errors"
6 | "github.com/go-kit/kit/endpoint"
7 | "strings"
8 | )
9 |
10 | // CalculateEndpoint define endpoint
11 | type StringEndpoints struct {
12 | StringEndpoint endpoint.Endpoint
13 | HealthCheckEndpoint endpoint.Endpoint
14 | }
15 |
16 | var (
17 | ErrInvalidRequestType = errors.New("RequestType has only two type: Concat, Diff")
18 | )
19 |
20 | // StringRequest define request struct
21 | type StringRequest struct {
22 | RequestType string `json:"request_type"`
23 | A string `json:"a"`
24 | B string `json:"b"`
25 | }
26 |
27 | // StringResponse define response struct
28 | type StringResponse struct {
29 | Result string `json:"result"`
30 | Error error `json:"error"`
31 | }
32 |
33 | // MakeStringEndpoint make endpoint
34 | func MakeStringEndpoint(svc Service) endpoint.Endpoint {
35 | return func(ctx context.Context, request interface{}) (response interface{}, err error) {
36 | req := request.(StringRequest)
37 |
38 | var (
39 | res, a, b string
40 | opError error
41 | )
42 |
43 | a = req.A
44 | b = req.B
45 |
46 | if strings.EqualFold(req.RequestType, "Concat") {
47 | res, _ = svc.Concat(a, b)
48 | } else if strings.EqualFold(req.RequestType, "Diff") {
49 | res, _ = svc.Diff(a, b)
50 | } else {
51 | return nil, ErrInvalidRequestType
52 | }
53 |
54 | return StringResponse{Result: res, Error: opError}, nil
55 | }
56 | }
57 |
58 | // HealthRequest 健康检查请求结构
59 | type HealthRequest struct{}
60 |
61 | // HealthResponse 健康检查响应结构
62 | type HealthResponse struct {
63 | Status bool `json:"status"`
64 | }
65 |
66 | // MakeHealthCheckEndpoint 创建健康检查Endpoint
67 | func MakeHealthCheckEndpoint(svc Service) endpoint.Endpoint {
68 | return func(ctx context.Context, request interface{}) (response interface{}, err error) {
69 | status := svc.HealthCheck()
70 | return HealthResponse{status}, nil
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/ch7-rpc/stream/string-service/service.go:
--------------------------------------------------------------------------------
1 | package string_service
2 |
3 | import (
4 | "context"
5 | "errors"
6 | "github.com/longjoy/micro-go-book/ch7-rpc/stream-pb"
7 | "io"
8 | "log"
9 | "strings"
10 | )
11 |
12 | const (
13 | StrMaxSize = 1024
14 | )
15 |
16 | // Service errors
17 | var (
18 | ErrMaxSize = errors.New("maximum size of 1024 bytes exceeded")
19 |
20 | ErrStrValue = errors.New("maximum size of 1024 bytes exceeded")
21 | )
22 |
23 | type StringService struct{}
24 |
25 | func (s *StringService) LotsOfServerStream(req *stream_pb.StringRequest, qs stream_pb.StringService_LotsOfServerStreamServer) error {
26 | response := stream_pb.StringResponse{Ret: req.A + req.B}
27 | for i := 0; i < 10; i++ {
28 | qs.Send(&response)
29 | }
30 | return nil
31 | }
32 |
33 | func (s *StringService) LotsOfClientStream(qs stream_pb.StringService_LotsOfClientStreamServer) error {
34 | var params []string
35 | for {
36 | in, err := qs.Recv()
37 | if err == io.EOF {
38 | qs.SendAndClose(&stream_pb.StringResponse{Ret: strings.Join(params, "")})
39 | return nil
40 | }
41 | if err != nil {
42 | log.Printf("failed to recv: %v", err)
43 | return err
44 | }
45 | params = append(params, in.A, in.B)
46 | }
47 | }
48 | func (s *StringService) LotsOfServerAndClientStream(qs stream_pb.StringService_LotsOfServerAndClientStreamServer) error {
49 | for {
50 | in, err := qs.Recv()
51 | if err == io.EOF {
52 | return nil
53 | }
54 | if err != nil {
55 | log.Printf("failed to recv %v", err)
56 | return err
57 | }
58 | qs.Send(&stream_pb.StringResponse{Ret: in.A + in.B})
59 | }
60 | return nil
61 | }
62 |
63 | func (s *StringService) Concat(ctx context.Context, req *stream_pb.StringRequest) (*stream_pb.StringResponse, error) {
64 | if len(req.A)+len(req.B) > StrMaxSize {
65 | response := stream_pb.StringResponse{Ret: ""}
66 | return &response, nil
67 | }
68 | response := stream_pb.StringResponse{Ret: req.A + req.B}
69 | return &response, nil
70 | }
71 |
--------------------------------------------------------------------------------
/ch13-seckill/sk-app/service/srv_redis/redis_proc.go:
--------------------------------------------------------------------------------
1 | package srv_redis
2 |
3 | import (
4 | "encoding/json"
5 | "fmt"
6 | conf "github.com/longjoy/micro-go-book/ch13-seckill/pkg/config"
7 | "github.com/longjoy/micro-go-book/ch13-seckill/sk-app/config"
8 | "github.com/longjoy/micro-go-book/ch13-seckill/sk-app/model"
9 | "log"
10 | "time"
11 | )
12 |
13 | //写数据到Redis
14 | func WriteHandle() {
15 | for {
16 | fmt.Println("wirter data to redis.")
17 | req := <-config.SkAppContext.SecReqChan
18 | fmt.Println("accessTime : ", req.AccessTime)
19 | conn := conf.Redis.RedisConn
20 |
21 | data, err := json.Marshal(req)
22 | if err != nil {
23 | log.Printf("json.Marshal req failed. Error : %v, req : %v", err, req)
24 | continue
25 | }
26 |
27 | err = conn.LPush(conf.Redis.Proxy2layerQueueName, string(data)).Err()
28 | if err != nil {
29 | log.Printf("lpush req failed. Error : %v, req : %v", err, req)
30 | continue
31 | }
32 | log.Printf("lpush req success. req : %v", string(data))
33 | }
34 | }
35 |
36 | //从redis读取数据
37 | func ReadHandle() {
38 | for {
39 | conn := conf.Redis.RedisConn
40 | //阻塞弹出
41 | data, err := conn.BRPop(time.Second, conf.Redis.Layer2proxyQueueName).Result()
42 | if err != nil {
43 | continue
44 | }
45 |
46 | var result *model.SecResult
47 | err = json.Unmarshal([]byte(data[1]), &result)
48 | if err != nil {
49 | log.Printf("json.Unmarshal failed. Error : %v", err)
50 | continue
51 | }
52 |
53 | userKey := fmt.Sprintf("%d_%d", result.UserId, result.ProductId)
54 | fmt.Println("userKey : ", userKey)
55 | config.SkAppContext.UserConnMapLock.Lock()
56 | resultChan, ok := config.SkAppContext.UserConnMap[userKey]
57 | config.SkAppContext.UserConnMapLock.Unlock()
58 | if !ok {
59 | log.Printf("user not found : %v", userKey)
60 | continue
61 | }
62 | log.Printf("request result send to chan")
63 |
64 | resultChan <- result
65 | log.Printf("request result send to chan succeee, userKey : %v", userKey)
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/ch9-gateway/string-service/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "context"
5 | "flag"
6 | "fmt"
7 | "github.com/go-kit/kit/log"
8 | "net/http"
9 | "os"
10 | "os/signal"
11 | "syscall"
12 | )
13 |
14 | func main() {
15 |
16 | var (
17 | consulHost = flag.String("consul.host", "114.67.98.210", "consul ip address")
18 | consulPort = flag.String("consul.port", "8500", "consul port")
19 | serviceHost = flag.String("service.host", "localhost", "service ip address")
20 | servicePort = flag.String("service.port", "8080", "service port")
21 | )
22 |
23 | flag.Parse()
24 |
25 | ctx := context.Background()
26 | errChan := make(chan error)
27 |
28 | var logger log.Logger
29 | {
30 | logger = log.NewLogfmtLogger(os.Stderr)
31 | logger = log.With(logger, "ts", log.DefaultTimestampUTC)
32 | logger = log.With(logger, "caller", log.DefaultCaller)
33 | }
34 |
35 | var svc Service
36 | svc = StringService{}
37 |
38 | // add logging middleware
39 | svc = LoggingMiddleware(logger)(svc)
40 |
41 | endpoint := MakeStringEndpoint(svc)
42 |
43 | //创建健康检查的Endpoint
44 | healthEndpoint := MakeHealthCheckEndpoint(svc)
45 |
46 | //把算术运算Endpoint和健康检查Endpoint封装至StringEndpoints
47 | endpts := StringEndpoints{
48 | StringEndpoint: endpoint,
49 | HealthCheckEndpoint: healthEndpoint,
50 | }
51 |
52 | //创建http.Handler
53 | r := MakeHttpHandler(ctx, endpts, logger)
54 |
55 | //创建注册对象
56 | //TODO replace with pkg consul
57 | registar := Register(*consulHost, *consulPort, *serviceHost, *servicePort, logger)
58 |
59 | go func() {
60 | fmt.Println("Http Server start at port:" + *servicePort)
61 | //启动前执行注册
62 | registar.Register()
63 | handler := r
64 | errChan <- http.ListenAndServe(":"+*servicePort, handler)
65 | }()
66 |
67 | go func() {
68 | c := make(chan os.Signal, 1)
69 | signal.Notify(c, syscall.SIGINT, syscall.SIGTERM)
70 | errChan <- fmt.Errorf("%s", <-c)
71 | }()
72 |
73 | error := <-errChan
74 | //服务退出取消注册
75 | registar.Deregister()
76 | fmt.Println(error)
77 | }
78 |
--------------------------------------------------------------------------------
/ch4-feature/concurrency/channel.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "bufio"
5 | "fmt"
6 | "os"
7 | "time"
8 | )
9 |
10 | func printInput(ch chan string) {
11 |
12 |
13 | // 使用 for 循环从 channel 中读取数据
14 | for val := range ch{
15 | // 读取到结束符号
16 | if val == "EOF"{
17 | break
18 | }
19 | fmt.Printf("Input is %s\n", val)
20 | }
21 |
22 |
23 | }
24 |
25 | func consume(ch chan int) {
26 |
27 | // 线程休息 100s 再从 channel 读取数据
28 | time.Sleep(time.Second * 100)
29 | <- ch
30 |
31 | }
32 |
33 |
34 |
35 | func main() {
36 |
37 | // 创建一个无缓冲的 channel
38 | ch := make(chan string)
39 | go printInput(ch)
40 |
41 | // 从命令行读取输入
42 | scanner := bufio.NewScanner(os.Stdin)
43 | for scanner.Scan() {
44 | val := scanner.Text()
45 | ch <- val
46 | if val == "EOF"{
47 | fmt.Println("End the game!")
48 | break
49 | }
50 | }
51 | // 程序最后关闭 ch
52 | defer close(ch)
53 |
54 |
55 | //// 创建一个长度为 2 的 channel
56 | //ch := make(chan int, 2)
57 | //go consume(ch)
58 | //
59 | //ch <- 0
60 | //ch <- 1
61 | //// 发送数据不被阻塞
62 | //fmt.Println("I am free!")
63 | //ch <- 2
64 | //fmt.Println("I can not go there within 100s!")
65 | //
66 | //time.Sleep(time.Second)
67 |
68 |
69 | //ch1 := make(chan int)
70 | //ch2 := make(chan int)
71 | //
72 | //go send(ch1, 0)
73 | //go send(ch2, 10)
74 | //
75 | //// 主 goroutine 休眠 1s,保证调度成功
76 | //time.Sleep(time.Second)
77 | //
78 | //for {
79 | // select {
80 | // case val := <- ch1: // 从 ch1 读取数据
81 | // fmt.Printf("get value %d from ch1\n", val)
82 | // case val := <- ch2 : // 从 ch2 读取数据
83 | // fmt.Printf("get value %d from ch2\n", val)
84 | // case <-time.After(2 * time.Second): // 超时设置
85 | // fmt.Println("Time out")
86 | // return
87 | // }
88 | //}
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 | }
97 |
98 | func send(ch chan int, begin int ) {
99 |
100 | for i :=begin ; i< begin + 10 ;i++{
101 | ch <- i
102 |
103 | }
104 |
105 | }
106 |
--------------------------------------------------------------------------------
/ch13-seckill/sk-app/plugins/logging.go:
--------------------------------------------------------------------------------
1 | package plugins
2 |
3 | import (
4 | "github.com/go-kit/kit/log"
5 | "github.com/longjoy/micro-go-book/ch13-seckill/sk-app/model"
6 | "github.com/longjoy/micro-go-book/ch13-seckill/sk-app/service"
7 | "time"
8 | )
9 |
10 | // loggingMiddleware Make a new type
11 | // that contains Service interface and logger instance
12 | type skAppLoggingMiddleware struct {
13 | service.Service
14 | logger log.Logger
15 | }
16 |
17 | // LoggingMiddleware make logging middleware
18 | func SkAppLoggingMiddleware(logger log.Logger) service.ServiceMiddleware {
19 | return func(next service.Service) service.Service {
20 | return skAppLoggingMiddleware{next, logger}
21 | }
22 | }
23 |
24 | func (mw skAppLoggingMiddleware) HealthCheck() (result bool) {
25 | defer func(begin time.Time) {
26 | _ = mw.logger.Log(
27 | "function", "HealthChcek",
28 | "result", result,
29 | "took", time.Since(begin),
30 | )
31 | }(time.Now())
32 |
33 | result = mw.Service.HealthCheck()
34 | return
35 | }
36 |
37 | func (mw skAppLoggingMiddleware) SecInfo(productId int) map[string]interface{} {
38 |
39 | defer func(begin time.Time) {
40 | _ = mw.logger.Log(
41 | "function", "Check",
42 | "took", time.Since(begin),
43 | )
44 | }(time.Now())
45 |
46 | ret := mw.Service.SecInfo(productId)
47 | return ret
48 | }
49 |
50 | func (mw skAppLoggingMiddleware) SecInfoList() ([]map[string]interface{}, int, error) {
51 |
52 | defer func(begin time.Time) {
53 | _ = mw.logger.Log(
54 | "function", "Check",
55 | "took", time.Since(begin),
56 | )
57 | }(time.Now())
58 |
59 | data, num, error := mw.Service.SecInfoList()
60 | return data, num, error
61 | }
62 |
63 | func (mw skAppLoggingMiddleware) SecKill(req *model.SecRequest) (map[string]interface{}, int, error) {
64 | defer func(begin time.Time) {
65 | _ = mw.logger.Log(
66 | "function", "Check",
67 | "took", time.Since(begin),
68 | )
69 | }(time.Now())
70 |
71 | result, num, error := mw.Service.SecKill(req)
72 | return result, num, error
73 | }
74 |
--------------------------------------------------------------------------------
/ch5-web/memory/memory.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "html/template"
6 | "log"
7 | "net/http"
8 | )
9 |
10 | type User struct {
11 | Id int
12 | Name string
13 | Password string
14 | }
15 |
16 | var UserById = make(map[int]*User)
17 | var UserByName = make(map[string][]*User)
18 |
19 | var tpl = `
20 |
21 |
22 |
23 |
24 |
29 |
30 | `
31 |
32 | func loginMemory(w http.ResponseWriter, r *http.Request) {
33 | fmt.Println("method:", r.Method) //获取请求的方法
34 | if r.Method == "GET" {
35 | var t *template.Template
36 | t = template.New("Products") //创建一个模板
37 | t, _ = t.Parse(tpl)
38 | log.Println(t.Execute(w, nil))
39 | } else {
40 | //请求的是登录数据,那么执行登录的逻辑判断
41 | _ = r.ParseForm()
42 | fmt.Println("username:", r.Form["username"])
43 | fmt.Println("password:", r.Form["password"])
44 | user1 := User{1, r.Form.Get("username"), r.Form.Get("password")}
45 | store(user1)
46 | if pwd := r.Form.Get("password"); pwd == "123456" { // 验证密码是否正确
47 | fmt.Fprintf(w, "欢迎登陆,Hello %s!", r.Form.Get("username")) //这个写入到w的是输出到客户端的
48 | } else {
49 | fmt.Fprintf(w, "密码错误,请重新输入!")
50 | }
51 | }
52 | }
53 |
54 | func store(user User) {
55 | UserById[user.Id] = &user
56 | UserByName[user.Name] = append(UserByName[user.Name], &user)
57 | }
58 | func userInfo(w http.ResponseWriter, r *http.Request) {
59 | fmt.Println(UserById[1])
60 | r.ParseForm()
61 |
62 | for _, user := range UserByName[r.Form.Get("username")] {
63 | fmt.Println(user)
64 | fmt.Fprintf(w," %v",user ) //这个写入到w的是输出到客户端的
65 | }
66 | }
67 |
68 | func main() {
69 |
70 | http.HandleFunc("/login", loginMemory) //设置访问的路由
71 | http.HandleFunc("/info", userInfo) //设置访问的路由
72 | err := http.ListenAndServe(":8080", nil) //设置监听的端口
73 | if err != nil {
74 | log.Fatal("ListenAndServe: ", err)
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/ch6-discovery/endpoint/endpoints.go:
--------------------------------------------------------------------------------
1 | package endpoint
2 |
3 | import (
4 | "context"
5 | "github.com/go-kit/kit/endpoint"
6 | "github.com/longjoy/micro-go-book/ch6-discovery/service"
7 | )
8 |
9 | type DiscoveryEndpoints struct {
10 | SayHelloEndpoint endpoint.Endpoint
11 | DiscoveryEndpoint endpoint.Endpoint
12 | HealthCheckEndpoint endpoint.Endpoint
13 | }
14 |
15 | // 打招呼请求结构体
16 | type SayHelloRequest struct {
17 | }
18 | // 打招呼响应结构体
19 | type SayHelloResponse struct {
20 | Message string `json:"message"`
21 |
22 | }
23 | // 创建打招呼 Endpoint
24 | func MakeSayHelloEndpoint(svc service.Service) endpoint.Endpoint {
25 | return func(ctx context.Context, request interface{}) (response interface{}, err error) {
26 | message := svc.SayHello()
27 | return SayHelloResponse{
28 | Message:message,
29 | }, nil
30 | }
31 | }
32 |
33 | // 服务发现请求结构体
34 | type DiscoveryRequest struct {
35 | ServiceName string
36 | }
37 | // 服务发现响应结构体
38 | type DiscoveryResponse struct {
39 | Instances []interface{} `json:"instances"`
40 | Error string `json:"error"`
41 | }
42 | // 创建服务发现的 Endpoint
43 | func MakeDiscoveryEndpoint(svc service.Service) endpoint.Endpoint {
44 | return func(ctx context.Context, request interface{}) (response interface{}, err error) {
45 | req := request.(DiscoveryRequest)
46 | instances, err := svc.DiscoveryService(ctx, req.ServiceName)
47 | var errString = ""
48 | if err != nil{
49 | errString = err.Error()
50 | }
51 | return &DiscoveryResponse{
52 | Instances:instances,
53 | Error:errString,
54 | }, nil
55 | }
56 | }
57 |
58 | // HealthRequest 健康检查请求结构
59 | type HealthRequest struct{}
60 | // HealthResponse 健康检查响应结构
61 | type HealthResponse struct {
62 | Status bool `json:"status"`
63 | }
64 | // MakeHealthCheckEndpoint 创建健康检查Endpoint
65 | func MakeHealthCheckEndpoint(svc service.Service) endpoint.Endpoint {
66 | return func(ctx context.Context, request interface{}) (response interface{}, err error) {
67 | status := svc.HealthCheck()
68 | return HealthResponse{
69 | Status:status,
70 | }, nil
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/ch12-trace/zipkin-go/string-services/svc2/cmd/main.go:
--------------------------------------------------------------------------------
1 | // +build go1.7
2 |
3 | package main
4 |
5 | import (
6 | "fmt"
7 | "github.com/longjoy/micro-go-book/ch12-trace/zipkin-go/string-services/svc2"
8 | "net/http"
9 | "os"
10 |
11 | "github.com/opentracing/opentracing-go"
12 |
13 | zipkin "github.com/openzipkin-contrib/zipkin-go-opentracing"
14 | //"github.com/openzipkin-contrib/zipkin-go-opentracing/examples/string-services/svc2"
15 | )
16 |
17 | const (
18 | // Our service name.
19 | serviceName = "svc2"
20 |
21 | // Host + port of our service.
22 | hostPort = "127.0.0.1:61002"
23 |
24 | // Endpoint to send Zipkin spans to.
25 | zipkinHTTPEndpoint = "http://114.67.98.210:9411/api/v1/spans"
26 |
27 | // Debug mode.
28 | debug = false
29 |
30 | // same span can be set to true for RPC style spans (Zipkin V1) vs Node style (OpenTracing)
31 | sameSpan = true
32 |
33 | // make Tracer generate 128 bit traceID's for root spans.
34 | traceID128Bit = true
35 | )
36 |
37 | //svc2
38 | func main() {
39 | // create collector.
40 | collector, err := zipkin.NewHTTPCollector(zipkinHTTPEndpoint)
41 | if err != nil {
42 | fmt.Printf("unable to create Zipkin HTTP collector: %+v\n", err)
43 | os.Exit(-1)
44 | }
45 |
46 | // create recorder.
47 | recorder := zipkin.NewRecorder(collector, debug, hostPort, serviceName)
48 |
49 | // create tracer.
50 | tracer, err := zipkin.NewTracer(
51 | recorder,
52 | zipkin.ClientServerSameSpan(sameSpan),
53 | zipkin.TraceID128Bit(traceID128Bit),
54 | )
55 | if err != nil {
56 | fmt.Printf("unable to create Zipkin tracer: %+v\n", err)
57 | os.Exit(-1)
58 | }
59 |
60 | // explicitly set our tracer to be the default tracer.
61 | opentracing.InitGlobalTracer(tracer)
62 |
63 | // create the service implementation
64 | service := svc2.NewService()
65 |
66 | // create the HTTP Server Handler for the service
67 | handler := svc2.NewHTTPHandler(tracer, service)
68 |
69 | // start the service
70 | fmt.Printf("Starting %s on %s\n", serviceName, hostPort)
71 | http.ListenAndServe(hostPort, handler)
72 | }
73 |
--------------------------------------------------------------------------------
/ch6-discovery/string-service/endpoint/endpoints.go:
--------------------------------------------------------------------------------
1 | package endpoint
2 |
3 | import (
4 | "context"
5 | "errors"
6 | "github.com/go-kit/kit/endpoint"
7 | "github.com/longjoy/micro-go-book/ch10-resiliency/string-service/service"
8 | "strings"
9 | )
10 |
11 | // StringEndpoint define endpoint
12 | type StringEndpoints struct {
13 | StringEndpoint endpoint.Endpoint
14 | HealthCheckEndpoint endpoint.Endpoint
15 | }
16 |
17 |
18 | var (
19 | ErrInvalidRequestType = errors.New("RequestType has only two type: Concat, Diff")
20 | )
21 |
22 | // StringRequest define request struct
23 | type StringRequest struct {
24 | RequestType string `json:"request_type"`
25 | A string `json:"a"`
26 | B string `json:"b"`
27 | }
28 |
29 | // StringResponse define response struct
30 | type StringResponse struct {
31 | Result string `json:"result"`
32 | Error error `json:"error"`
33 | }
34 |
35 | // MakeStringEndpoint make endpoint
36 | func MakeStringEndpoint(svc service.Service) endpoint.Endpoint {
37 | return func(ctx context.Context, request interface{}) (response interface{}, err error) {
38 | req := request.(StringRequest)
39 |
40 | var (
41 | res, a, b string
42 | opError error
43 | )
44 |
45 | a = req.A
46 | b = req.B
47 | // 根据请求操作类型请求具体的操作方法
48 | if strings.EqualFold(req.RequestType, "Concat") {
49 | res, _ = svc.Concat(a, b)
50 | } else if strings.EqualFold(req.RequestType, "Diff") {
51 | res, _ = svc.Diff(a, b)
52 | } else {
53 | return nil, ErrInvalidRequestType
54 | }
55 |
56 | return StringResponse{Result: res, Error: opError}, nil
57 | }
58 | }
59 |
60 | // HealthRequest 健康检查请求结构
61 | type HealthRequest struct{}
62 |
63 | // HealthResponse 健康检查响应结构
64 | type HealthResponse struct {
65 | Status bool `json:"status"`
66 | }
67 |
68 | // MakeHealthCheckEndpoint 创建健康检查Endpoint
69 | func MakeHealthCheckEndpoint(svc service.Service) endpoint.Endpoint {
70 | return func(ctx context.Context, request interface{}) (response interface{}, err error) {
71 | status := svc.HealthCheck()
72 | return HealthResponse{status}, nil
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/ch10-resiliency/string-service/endpoint/endpoints.go:
--------------------------------------------------------------------------------
1 | package endpoint
2 |
3 | import (
4 | "context"
5 | "errors"
6 | "github.com/go-kit/kit/endpoint"
7 | "github.com/longjoy/micro-go-book/ch10-resiliency/string-service/service"
8 | "strings"
9 | )
10 |
11 | // CalculateEndpoint define endpoint
12 | type StringEndpoints struct {
13 | StringEndpoint endpoint.Endpoint
14 | HealthCheckEndpoint endpoint.Endpoint
15 | }
16 |
17 |
18 | var (
19 | ErrInvalidRequestType = errors.New("RequestType has only two type: Concat, Diff")
20 | )
21 |
22 | // StringRequest define request struct
23 | type StringRequest struct {
24 | RequestType string `json:"request_type"`
25 | A string `json:"a"`
26 | B string `json:"b"`
27 | }
28 |
29 | // StringResponse define response struct
30 | type StringResponse struct {
31 | Result string `json:"result"`
32 | Error error `json:"error"`
33 | }
34 |
35 | // MakeStringEndpoint make endpoint
36 | func MakeStringEndpoint(svc service.Service) endpoint.Endpoint {
37 | return func(ctx context.Context, request interface{}) (response interface{}, err error) {
38 | req := request.(StringRequest)
39 |
40 | var (
41 | res, a, b string
42 | opError error
43 | )
44 |
45 | a = req.A
46 | b = req.B
47 | // 根据请求操作类型请求具体的操作方法
48 | if strings.EqualFold(req.RequestType, "Concat") {
49 | res, _ = svc.Concat(a, b)
50 | } else if strings.EqualFold(req.RequestType, "Diff") {
51 | res, _ = svc.Diff(a, b)
52 | } else {
53 | return nil, ErrInvalidRequestType
54 | }
55 |
56 | return StringResponse{Result: res, Error: opError}, nil
57 | }
58 | }
59 |
60 | // HealthRequest 健康检查请求结构
61 | type HealthRequest struct{}
62 |
63 | // HealthResponse 健康检查响应结构
64 | type HealthResponse struct {
65 | Status bool `json:"status"`
66 | }
67 |
68 | // MakeHealthCheckEndpoint 创建健康检查Endpoint
69 | func MakeHealthCheckEndpoint(svc service.Service) endpoint.Endpoint {
70 | return func(ctx context.Context, request interface{}) (response interface{}, err error) {
71 | status := svc.HealthCheck()
72 | return HealthResponse{status}, nil
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/ch13-seckill/sk-admin/config/config.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | import (
4 | "github.com/go-kit/kit/log"
5 | "github.com/longjoy/micro-go-book/ch13-seckill/pkg/bootstrap"
6 | _ "github.com/longjoy/micro-go-book/ch13-seckill/pkg/bootstrap"
7 | conf "github.com/longjoy/micro-go-book/ch13-seckill/pkg/config"
8 | "github.com/openzipkin/zipkin-go"
9 | zipkinhttp "github.com/openzipkin/zipkin-go/reporter/http"
10 | _ "github.com/openzipkin/zipkin-go/reporter/recorder"
11 | "github.com/spf13/viper"
12 | "os"
13 | )
14 |
15 | const (
16 | kConfigType = "CONFIG_TYPE"
17 | )
18 |
19 | var ZipkinTracer *zipkin.Tracer
20 | var Logger log.Logger
21 |
22 | func init() {
23 | Logger = log.NewLogfmtLogger(os.Stderr)
24 | Logger = log.With(Logger, "ts", log.DefaultTimestampUTC)
25 | Logger = log.With(Logger, "caller", log.DefaultCaller)
26 | viper.AutomaticEnv()
27 | initDefault()
28 |
29 | if err := conf.LoadRemoteConfig(); err != nil {
30 | Logger.Log("Fail to load remote config", err)
31 | }
32 |
33 | if err := conf.Sub("mysql", &conf.MysqlConfig); err != nil {
34 | Logger.Log("Fail to parse mysql", err)
35 | }
36 | if err := conf.Sub("trace", &conf.TraceConfig); err != nil {
37 | Logger.Log("Fail to parse trace", err)
38 | }
39 | zipkinUrl := "http://" + conf.TraceConfig.Host + ":" + conf.TraceConfig.Port + conf.TraceConfig.Url
40 | Logger.Log("zipkin url", zipkinUrl)
41 | }
42 |
43 | func initDefault() {
44 | viper.SetDefault(kConfigType, "yaml")
45 | }
46 |
47 | func initTracer(zipkinURL string) {
48 | var (
49 | err error
50 | useNoopTracer = zipkinURL == ""
51 | reporter = zipkinhttp.NewReporter(zipkinURL)
52 | )
53 | //defer reporter.Close()
54 | zEP, _ := zipkin.NewEndpoint(bootstrap.DiscoverConfig.ServiceName, bootstrap.HttpConfig.Port)
55 | ZipkinTracer, err = zipkin.NewTracer(
56 | reporter, zipkin.WithLocalEndpoint(zEP), zipkin.WithNoopTracer(useNoopTracer),
57 | )
58 | if err != nil {
59 | Logger.Log("err", err)
60 | os.Exit(1)
61 | }
62 | if !useNoopTracer {
63 | Logger.Log("tracer", "Zipkin", "type", "Native", "URL", zipkinURL)
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/ch13-seckill/user-service/config/config.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | import (
4 | "github.com/go-kit/kit/log"
5 | "github.com/longjoy/micro-go-book/ch13-seckill/pkg/bootstrap"
6 | _ "github.com/longjoy/micro-go-book/ch13-seckill/pkg/bootstrap"
7 | conf "github.com/longjoy/micro-go-book/ch13-seckill/pkg/config"
8 | "github.com/openzipkin/zipkin-go"
9 | zipkinhttp "github.com/openzipkin/zipkin-go/reporter/http"
10 | _ "github.com/openzipkin/zipkin-go/reporter/recorder"
11 | "github.com/spf13/viper"
12 | "os"
13 | )
14 |
15 | const (
16 | kConfigType = "CONFIG_TYPE"
17 | )
18 |
19 | var ZipkinTracer *zipkin.Tracer
20 | var Logger log.Logger
21 |
22 | func init() {
23 | Logger = log.NewLogfmtLogger(os.Stderr)
24 | Logger = log.With(Logger, "ts", log.DefaultTimestampUTC)
25 | Logger = log.With(Logger, "caller", log.DefaultCaller)
26 | viper.AutomaticEnv()
27 | initDefault()
28 |
29 | if err := conf.LoadRemoteConfig(); err != nil {
30 | Logger.Log("Fail to load remote config", err)
31 | }
32 |
33 | if err := conf.Sub("mysql", &conf.MysqlConfig); err != nil {
34 | Logger.Log("Fail to parse mysql", err)
35 | }
36 | if err := conf.Sub("trace", &conf.TraceConfig); err != nil {
37 | Logger.Log("Fail to parse trace", err)
38 | }
39 | zipkinUrl := "http://" + conf.TraceConfig.Host + ":" + conf.TraceConfig.Port + conf.TraceConfig.Url
40 | Logger.Log("zipkin url", zipkinUrl)
41 | initTracer(zipkinUrl)
42 | }
43 |
44 | func initDefault() {
45 | viper.SetDefault(kConfigType, "yaml")
46 | }
47 |
48 | func initTracer(zipkinURL string) {
49 | var (
50 | err error
51 | useNoopTracer = zipkinURL == ""
52 | reporter = zipkinhttp.NewReporter(zipkinURL)
53 | )
54 | //defer reporter.Close()
55 | zEP, _ := zipkin.NewEndpoint(bootstrap.DiscoverConfig.ServiceName, bootstrap.HttpConfig.Port)
56 | ZipkinTracer, err = zipkin.NewTracer(
57 | reporter, zipkin.WithLocalEndpoint(zEP), zipkin.WithNoopTracer(useNoopTracer),
58 | )
59 | if err != nil {
60 | Logger.Log("err", err)
61 | os.Exit(1)
62 | }
63 | if !useNoopTracer {
64 | Logger.Log("tracer", "Zipkin", "type", "Native", "URL", zipkinURL)
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/ch13-seckill/oauth-service/config/config.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | import (
4 | "github.com/go-kit/kit/log"
5 | "github.com/longjoy/micro-go-book/ch13-seckill/pkg/bootstrap"
6 | _ "github.com/longjoy/micro-go-book/ch13-seckill/pkg/bootstrap"
7 | conf "github.com/longjoy/micro-go-book/ch13-seckill/pkg/config"
8 | "github.com/openzipkin/zipkin-go"
9 | zipkinhttp "github.com/openzipkin/zipkin-go/reporter/http"
10 | _ "github.com/openzipkin/zipkin-go/reporter/recorder"
11 | "github.com/spf13/viper"
12 | "os"
13 | )
14 |
15 | const (
16 | kConfigType = "CONFIG_TYPE"
17 | )
18 |
19 | var ZipkinTracer *zipkin.Tracer
20 | var Logger log.Logger
21 |
22 | func init() {
23 | Logger = log.NewLogfmtLogger(os.Stderr)
24 | Logger = log.With(Logger, "ts", log.DefaultTimestampUTC)
25 | Logger = log.With(Logger, "caller", log.DefaultCaller)
26 | viper.AutomaticEnv()
27 | initDefault()
28 |
29 | if err := conf.LoadRemoteConfig(); err != nil {
30 | Logger.Log("Fail to load remote config", err)
31 | }
32 |
33 | if err := conf.Sub("mysql", &conf.MysqlConfig); err != nil {
34 | Logger.Log("Fail to parse mysql", err)
35 | }
36 | if err := conf.Sub("trace", &conf.TraceConfig); err != nil {
37 | Logger.Log("Fail to parse trace", err)
38 | }
39 | zipkinUrl := "http://" + conf.TraceConfig.Host + ":" + conf.TraceConfig.Port + conf.TraceConfig.Url
40 | Logger.Log("zipkin url", zipkinUrl)
41 | initTracer(zipkinUrl)
42 | }
43 |
44 | func initDefault() {
45 | viper.SetDefault(kConfigType, "yaml")
46 | }
47 |
48 | func initTracer(zipkinURL string) {
49 | var (
50 | err error
51 | useNoopTracer = zipkinURL == ""
52 | reporter = zipkinhttp.NewReporter(zipkinURL)
53 | )
54 | //defer reporter.Close()
55 | zEP, _ := zipkin.NewEndpoint(bootstrap.DiscoverConfig.ServiceName, bootstrap.HttpConfig.Port)
56 | ZipkinTracer, err = zipkin.NewTracer(
57 | reporter, zipkin.WithLocalEndpoint(zEP), zipkin.WithNoopTracer(useNoopTracer),
58 | )
59 | if err != nil {
60 | Logger.Log("err", err)
61 | os.Exit(1)
62 | }
63 | if !useNoopTracer {
64 | Logger.Log("tracer", "Zipkin", "type", "Native", "URL", zipkinURL)
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/ch13-seckill/oauth-service/client_test.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "context"
5 | "fmt"
6 | "github.com/longjoy/micro-go-book/ch13-seckill/pb"
7 | "github.com/longjoy/micro-go-book/ch13-seckill/pkg/client"
8 | "testing"
9 | )
10 |
11 | func TestOauthClientImpl_Check(t *testing.T) {
12 | client, _ := client.NewOAuthClient("user", nil, nil)
13 |
14 | if response, err := client.CheckToken(context.Background(), nil, &pb.CheckTokenRequest{
15 | Token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJVc2VyRGV0YWlscyI6eyJVc2VySWQiOjEsIlVzZXJuYW1lIjoidXNlcm5hbWUiLCJQYXNzd29yZCI6IiIsIkF1dGhvcml0aWVzIjpbIkFkbWluIiwiU3VwZXIiXX0sIkNsaWVudERldGFpbHMiOnsiQ2xpZW50SWQiOiJjbGllbnRJZCIsIkNsaWVudFNlY3JldCI6IiIsIkFjY2Vzc1Rva2VuVmFsaWRpdHlTZWNvbmRzIjoxODAwLCJSZWZyZXNoVG9rZW5WYWxpZGl0eVNlY29uZHMiOjE4MDAwLCJSZWdpc3RlcmVkUmVkaXJlY3RVcmkiOiJodHRwOi8vMTI3LjAuMC4xIiwiQXV0aG9yaXplZEdyYW50VHlwZXMiOlsicGFzc3dvcmQiLCJyZWZyZXNoX3Rva2VuIl19LCJSZWZyZXNoVG9rZW4iOnsiUmVmcmVzaFRva2VuIjpudWxsLCJUb2tlblR5cGUiOiJqd3QiLCJUb2tlblZhbHVlIjoiZXlKaGJHY2lPaUpJVXpJMU5pSXNJblI1Y0NJNklrcFhWQ0o5LmV5SlZjMlZ5UkdWMFlXbHNjeUk2ZXlKVmMyVnlTV1FpT2pFc0lsVnpaWEp1WVcxbElqb2lkWE5sY201aGJXVWlMQ0pRWVhOemQyOXlaQ0k2SWlJc0lrRjFkR2h2Y21sMGFXVnpJanBiSWtGa2JXbHVJaXdpVTNWd1pYSWlYWDBzSWtOc2FXVnVkRVJsZEdGcGJITWlPbnNpUTJ4cFpXNTBTV1FpT2lKamJHbGxiblJKWkNJc0lrTnNhV1Z1ZEZObFkzSmxkQ0k2SWlJc0lrRmpZMlZ6YzFSdmEyVnVWbUZzYVdScGRIbFRaV052Ym1Seklqb3hPREF3TENKU1pXWnlaWE5vVkc5clpXNVdZV3hwWkdsMGVWTmxZMjl1WkhNaU9qRTRNREF3TENKU1pXZHBjM1JsY21Wa1VtVmthWEpsWTNSVmNta2lPaUpvZEhSd09pOHZNVEkzTGpBdU1DNHhJaXdpUVhWMGFHOXlhWHBsWkVkeVlXNTBWSGx3WlhNaU9sc2ljR0Z6YzNkdmNtUWlMQ0p5WldaeVpYTm9YM1J2YTJWdUlsMTlMQ0pTWldaeVpYTm9WRzlyWlc0aU9uc2lVbVZtY21WemFGUnZhMlZ1SWpwdWRXeHNMQ0pVYjJ0bGJsUjVjR1VpT2lJaUxDSlViMnRsYmxaaGJIVmxJam9pSWl3aVJYaHdhWEpsYzFScGJXVWlPbTUxYkd4OUxDSmxlSEFpT2pFMU56TTFOemN6TURRc0ltbHpjeUk2SWxONWMzUmxiU0o5LmJneEdtaGJyVmVVQWljMk1ZRWtmeFJFVFVvVHhPYUZmQXFTa2xoQk50N2ciLCJFeHBpcmVzVGltZSI6IjIwMTktMTEtMTNUMDA6NDg6MjQuMzU2OTY4KzA4OjAwIn0sImV4cCI6MTU3MzU2MTEwNCwiaXNzIjoiU3lzdGVtIn0.CRXA_vadztUpOuKPth7HSb-E4l0otZEr6YNU5ZQcEcc",
16 | }); err == nil {
17 | fmt.Println("Check error", err.Error())
18 | } else {
19 | fmt.Println("result=", response.ClientDetails.ClientId)
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/ch13-seckill/user-service/model/user.go:
--------------------------------------------------------------------------------
1 | package model
2 |
3 | import (
4 | "github.com/gohouse/gorose/v2"
5 | "github.com/longjoy/micro-go-book/ch13-seckill/pkg/mysql"
6 | "log"
7 | )
8 |
9 | type User struct {
10 | UserId int64 `json:"user_id"` //Id
11 | UserName string `json:"user_name"` //用户名称
12 | Password string `json:"password"` //密码
13 | Age int `json:"age"` //年龄
14 |
15 | }
16 |
17 | type UserModel struct {
18 | }
19 |
20 | func NewUserModel() *UserModel {
21 | return &UserModel{}
22 | }
23 |
24 | func (p *UserModel) getTableName() string {
25 | return "user"
26 | }
27 |
28 | func (p *UserModel) GetUserList() ([]gorose.Data, error) {
29 | conn := mysql.DB()
30 | list, err := conn.Table(p.getTableName()).Get()
31 | if err != nil {
32 | log.Printf("Error : %v", err)
33 | return nil, err
34 | }
35 | return list, nil
36 | }
37 |
38 | /*func (p *UserModel) GetUserByUsername(username string) (*User, error) {
39 |
40 | conn := mysql.DB()
41 | if result, err := conn.Table(p.getTableName()).Where(map[string]interface{}{"username": username}).First(); err == nil{
42 |
43 | }else {
44 | return nil, err
45 | }
46 |
47 | }*/
48 |
49 | func (p *UserModel) CheckUser(username string, password string) (*User, error) {
50 | conn := mysql.DB()
51 | data, err := conn.Table(p.getTableName()).Where(map[string]interface{}{"user_name": username, "password": password}).First()
52 | if err != nil {
53 | log.Printf("Error : %v", err)
54 | return nil, err
55 | }
56 | user := &User{
57 | UserId:data["user_id"].(int64),
58 | UserName:data["user_name"].(string),
59 | Password:data["password"].(string),
60 | Age:int(data["age"].(int64)),
61 |
62 |
63 | }
64 | return user, nil
65 | }
66 |
67 |
68 |
69 | func (p *UserModel) CreateUser(user *User) error {
70 | conn := mysql.DB()
71 | _, err := conn.Table(p.getTableName()).Data(map[string]interface{}{
72 | "user_id": user.UserId,
73 | "user_name": user.UserName,
74 | "password": user.Password,
75 | "age": user.Age,
76 |
77 | }).Insert()
78 | if err != nil {
79 | log.Printf("Error : %v", err)
80 | return err
81 | }
82 | return nil
83 | }
84 |
--------------------------------------------------------------------------------
/ch13-seckill/sk-core/setup/zk.go:
--------------------------------------------------------------------------------
1 | package setup
2 |
3 | import (
4 | "encoding/json"
5 | "fmt"
6 | conf "github.com/longjoy/micro-go-book/ch13-seckill/pkg/config"
7 | "github.com/samuel/go-zookeeper/zk"
8 | "log"
9 | "time"
10 | )
11 |
12 | //初始化Etcd
13 | func InitZk() {
14 | var hosts = []string{"39.98.179.73:2181"}
15 | option := zk.WithEventCallback(waitSecProductEvent)
16 | conn, _, err := zk.Connect(hosts, time.Second*5, option)
17 | if err != nil {
18 | fmt.Println(err)
19 | return
20 | }
21 |
22 | conf.Zk.ZkConn = conn
23 | conf.Zk.SecProductKey = "/product"
24 | go loadSecConf(conn)
25 | }
26 |
27 | //加载秒杀商品信息
28 | func loadSecConf(conn *zk.Conn) {
29 | log.Printf("Connect zk sucess %s", conf.Etcd.EtcdSecProductKey)
30 | v, _, err := conn.Get(conf.Zk.SecProductKey) //conf.Etcd.EtcdSecProductKey
31 | if err != nil {
32 | log.Printf("get product info failed, err : %v", err)
33 | return
34 | }
35 | log.Printf("get product info ")
36 | var secProductInfo []*conf.SecProductInfoConf
37 | err1 := json.Unmarshal(v, &secProductInfo)
38 | if err1 != nil {
39 | log.Printf("Unmsharl second product info failed, err : %v", err1)
40 | }
41 |
42 | updateSecProductInfo(secProductInfo)
43 | }
44 |
45 | func waitSecProductEvent(event zk.Event) {
46 | if event.Path == conf.Zk.SecProductKey {
47 |
48 | }
49 | }
50 |
51 | //监听秒杀商品配置
52 | //for wrsp := range rch {
53 | // for _, ev := range wrsp.Events {
54 | // //删除事件
55 | // if ev.Type == mvccpb.DELETE {
56 | // continue
57 | // }
58 | //
59 | // //更新事件
60 | // if ev.Type == mvccpb.PUT && string(ev.Kv.Key) == key {
61 | // err := json.Unmarshal(ev.Kv.Value, &secProductInfo)
62 | // if err != nil {
63 | // getConfSucc = false
64 | // continue
65 | // }
66 | // }
67 | // }
68 | //
69 | // if getConfSucc {
70 | // updateSecProductInfo(secProductInfo)
71 | // }
72 | //}
73 |
74 | //更新秒杀商品信息
75 | func updateSecProductInfo(secProductInfo []*conf.SecProductInfoConf) {
76 | tmp := make(map[int]*conf.SecProductInfoConf, 1024)
77 | for _, v := range secProductInfo {
78 | tmp[v.ProductId] = v
79 | }
80 | conf.SecKill.RWBlackLock.Lock()
81 | conf.SecKill.SecProductInfoMap = tmp
82 | conf.SecKill.RWBlackLock.Unlock()
83 | }
84 |
--------------------------------------------------------------------------------
/ch7-rpc/go-kit/string-service/transports.go:
--------------------------------------------------------------------------------
1 | package string_service
2 |
3 | import (
4 | "context"
5 | "errors"
6 | "github.com/go-kit/kit/transport/grpc"
7 | "github.com/longjoy/micro-go-book/ch7-rpc/pb"
8 | )
9 |
10 | var (
11 | ErrorBadRequest = errors.New("invalid request parameter")
12 | )
13 |
14 | type grpcServer struct {
15 | concat grpc.Handler
16 | diff grpc.Handler
17 | }
18 |
19 | func (s *grpcServer) Concat(ctx context.Context, r *pb.StringRequest) (*pb.StringResponse, error) {
20 | _, resp, err := s.concat.ServeGRPC(ctx, r)
21 | if err != nil {
22 | return nil, err
23 | }
24 | return resp.(*pb.StringResponse), nil
25 | }
26 |
27 | func (s *grpcServer) Diff(ctx context.Context, r *pb.StringRequest) (*pb.StringResponse, error) {
28 | _, resp, err := s.diff.ServeGRPC(ctx, r)
29 | if err != nil {
30 | return nil, err
31 | }
32 | return resp.(*pb.StringResponse), nil
33 | }
34 |
35 | func NewStringServer(ctx context.Context, endpoints StringEndpoints) pb.StringServiceServer {
36 | return &grpcServer{
37 | concat: grpc.NewServer(
38 | endpoints.StringEndpoint,
39 | DecodeConcatStringRequest,
40 | EncodeStringResponse,
41 | ),
42 | diff: grpc.NewServer(
43 | endpoints.StringEndpoint,
44 | DecodeDiffStringRequest,
45 | EncodeStringResponse,
46 | ),
47 | }
48 | }
49 |
50 | func DecodeConcatStringRequest(ctx context.Context, r interface{}) (interface{}, error) {
51 | req := r.(*pb.StringRequest)
52 | return StringRequest{
53 | RequestType: "Concat",
54 | A: string(req.A),
55 | B: string(req.B),
56 | }, nil
57 | }
58 |
59 | func DecodeDiffStringRequest(ctx context.Context, r interface{}) (interface{}, error) {
60 | req := r.(*pb.StringRequest)
61 | return StringRequest{
62 | RequestType: "Diff",
63 | A: string(req.A),
64 | B: string(req.B),
65 | }, nil
66 | }
67 |
68 | func EncodeStringResponse(_ context.Context, r interface{}) (interface{}, error) {
69 | resp := r.(StringResponse)
70 |
71 | if resp.Error != nil {
72 | return &pb.StringResponse{
73 | Ret: resp.Result,
74 | Err: resp.Error.Error(),
75 | }, nil
76 | }
77 |
78 | return &pb.StringResponse{
79 | Ret: resp.Result,
80 | Err: "",
81 | }, nil
82 | }
83 |
--------------------------------------------------------------------------------
/ch5-web/mongo/mongo.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "gopkg.in/mgo.v2"
6 | "gopkg.in/mgo.v2/bson"
7 | "html/template"
8 | "log"
9 | "net/http"
10 | )
11 |
12 | type User struct {
13 | Id string
14 | Name string
15 | Habits string
16 | CreatedTime string
17 | }
18 |
19 | var tpl = `
20 |
21 |
22 |
23 |
24 |
29 |
30 | `
31 |
32 | func connect(cName string) (*mgo.Session, *mgo.Collection) {
33 | session, err := mgo.Dial("mongodb://47.96.140.41:27017/") //Mongodb's connection
34 | checkErr(err)
35 | session.SetMode(mgo.Monotonic, true)
36 | //return a instantiated collect
37 | return session, session.DB("test").C(cName)
38 | }
39 |
40 | func queryByName(name string) []User {
41 | var user []User
42 | s, c := connect("user")
43 | defer s.Close()
44 | err := c.Find(bson.M{"name": name}).All(&user)
45 | checkErr(err)
46 | return user
47 | }
48 |
49 | func checkErr(err error) {
50 | if err != nil {
51 | panic(err)
52 | }
53 | }
54 |
55 | func submitForm(w http.ResponseWriter, r *http.Request) {
56 | fmt.Println("method:", r.Method) //获取请求的方法
57 | var t *template.Template
58 | t = template.New("Products") //创建一个模板
59 | t, _ = t.Parse(tpl)
60 | log.Println(t.Execute(w, nil))
61 | }
62 |
63 | func store(user User) error {
64 | //插入数据
65 | s, c := connect("user")
66 | defer s.Close()
67 | user.Id = bson.NewObjectId().Hex()
68 | return c.Insert(&user)
69 | }
70 |
71 | func userInfo(w http.ResponseWriter, r *http.Request) {
72 | //请求的是登录数据,那么执行登录的逻辑判断
73 | _ = r.ParseForm()
74 | if r.Method == "POST" {
75 | user1 := User{Name: r.Form.Get("username"), Habits: r.Form.Get("habits")}
76 | store(user1)
77 | fmt.Fprintf(w, " %v", queryByName("aoho")) //这个写入到w的是输出到客户端的
78 | }
79 | }
80 |
81 | func main() {
82 | http.HandleFunc("/form", submitForm) //设置访问的路由
83 | http.HandleFunc("/info", userInfo) //设置访问的路由
84 | err := http.ListenAndServe(":8080", nil) //设置监听的端口
85 | if err != nil {
86 | log.Fatal("ListenAndServe: ", err)
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/ch9-gateway/string-service/transports.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "context"
5 | "encoding/json"
6 | "errors"
7 | "github.com/go-kit/kit/log"
8 | kithttp "github.com/go-kit/kit/transport/http"
9 | "github.com/gorilla/mux"
10 | "github.com/prometheus/client_golang/prometheus/promhttp"
11 | "net/http"
12 | )
13 |
14 | var (
15 | ErrorBadRequest = errors.New("invalid request parameter")
16 | )
17 |
18 | // MakeHttpHandler make http handler use mux
19 | func MakeHttpHandler(ctx context.Context, endpoints StringEndpoints, logger log.Logger) http.Handler {
20 | r := mux.NewRouter()
21 |
22 | options := []kithttp.ServerOption{
23 | kithttp.ServerErrorLogger(logger),
24 | kithttp.ServerErrorEncoder(kithttp.DefaultErrorEncoder),
25 | }
26 |
27 | r.Methods("POST").Path("/op/{type}/{a}/{b}").Handler(kithttp.NewServer(
28 | endpoints.StringEndpoint,
29 | decodeStringRequest,
30 | encodeStringResponse,
31 | options...,
32 | ))
33 |
34 | r.Path("/metrics").Handler(promhttp.Handler())
35 |
36 | // create health check handler
37 | r.Methods("GET").Path("/health").Handler(kithttp.NewServer(
38 | endpoints.HealthCheckEndpoint,
39 | decodeHealthCheckRequest,
40 | encodeStringResponse,
41 | options...,
42 | ))
43 |
44 | return r
45 | }
46 |
47 | // decodeStringRequest decode request params to struct
48 | func decodeStringRequest(_ context.Context, r *http.Request) (interface{}, error) {
49 | vars := mux.Vars(r)
50 | requestType, ok := vars["type"]
51 | if !ok {
52 | return nil, ErrorBadRequest
53 | }
54 |
55 | pa, ok := vars["a"]
56 | if !ok {
57 | return nil, ErrorBadRequest
58 | }
59 |
60 | pb, ok := vars["b"]
61 | if !ok {
62 | return nil, ErrorBadRequest
63 | }
64 |
65 | return StringRequest{
66 | RequestType: requestType,
67 | A: pa,
68 | B: pb,
69 | }, nil
70 | }
71 |
72 | // encodeStringResponse encode response to return
73 | func encodeStringResponse(ctx context.Context, w http.ResponseWriter, response interface{}) error {
74 | w.Header().Set("Content-Type", "application/json;charset=utf-8")
75 | return json.NewEncoder(w).Encode(response)
76 | }
77 |
78 | // decodeHealthCheckRequest decode request
79 | func decodeHealthCheckRequest(ctx context.Context, r *http.Request) (interface{}, error) {
80 | return HealthRequest{}, nil
81 | }
82 |
--------------------------------------------------------------------------------
/ch8-config/ViperDemo.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "errors"
5 | "fmt"
6 | "github.com/spf13/viper"
7 | "log"
8 | "reflect"
9 | )
10 |
11 | var Resume ResumeInformation
12 |
13 | func init() {
14 | viper.AutomaticEnv()
15 | initDefault()
16 | //读取yaml文件
17 | //v := viper.New()
18 |
19 | if err := viper.ReadInConfig(); err != nil {
20 | fmt.Printf("err:%s\n", err)
21 | }
22 | if err := sub("ResumeInformation", &Resume); err != nil {
23 | log.Fatal("Fail to parse config", err)
24 | }
25 | }
26 | func initDefault() {
27 | //设置读取的配置文件
28 | viper.SetConfigName("resume_config")
29 | //添加读取的配置文件路径
30 | viper.AddConfigPath("./ch8-config/config/")
31 | //windows环境下为%GOPATH,linux环境下为$GOPATH
32 | viper.AddConfigPath("$GOPATH/src/")
33 | //设置配置文件类型
34 | viper.SetConfigType("yaml")
35 | }
36 | func main() {
37 | fmt.Printf(
38 | "姓名: %s\n爱好: %s\n性别: %s \n年龄: %d \n",
39 | Resume.Name,
40 | Resume.Habits,
41 | Resume.Sex,
42 | Resume.Age,
43 | )
44 | //反序列化
45 | parseYaml(viper.GetViper())
46 | fmt.Println(Contains("Basketball", Resume.Habits))
47 | }
48 |
49 | func Contains(obj interface{}, target interface{}) (bool, error) {
50 | targetValue := reflect.ValueOf(target)
51 | switch reflect.TypeOf(target).Kind() {
52 | case reflect.Slice, reflect.Array:
53 | for i := 0; i < targetValue.Len(); i++ {
54 | if targetValue.Index(i).Interface() == obj {
55 | return true, nil
56 | }
57 | }
58 | case reflect.Map:
59 | if targetValue.MapIndex(reflect.ValueOf(obj)).IsValid() {
60 | return true, nil
61 | }
62 | }
63 |
64 | return false, errors.New("not in array")
65 | }
66 |
67 | type ResumeInformation struct {
68 | Name string
69 | Sex string
70 | Age int
71 | Habits []interface{}
72 | }
73 |
74 | type ResumeSetting struct {
75 | RegisterTime string
76 | Address string
77 | ResumeInformation ResumeInformation
78 | }
79 |
80 | func parseYaml(v *viper.Viper) {
81 | var resumeConfig ResumeSetting
82 | if err := v.Unmarshal(&resumeConfig); err != nil {
83 | fmt.Printf("err:%s", err)
84 | }
85 | fmt.Println("resume config:\n ", resumeConfig)
86 | }
87 | func sub(key string, value interface{}) error {
88 | log.Printf("配置文件的前缀为:%v", key)
89 | sub := viper.Sub(key)
90 | sub.AutomaticEnv()
91 | sub.SetEnvPrefix(key)
92 | return sub.Unmarshal(value)
93 | }
94 |
--------------------------------------------------------------------------------
/ch3-basic/HelloGo.go:
--------------------------------------------------------------------------------
1 | // 每一个可执行的golang程序必定具备一个main包,并在该main包下具有执行函数main的go文件
2 | package main
3 |
4 | // 引入相关依赖
5 | import (
6 | "bytes"
7 | "encoding/json"
8 | "fmt"
9 | "io/ioutil"
10 | "math/rand"
11 | "net/http"
12 | "time"
13 | )
14 |
15 | // HelloGo.go
16 | // 基于图灵API一个简单的聊天机器人
17 |
18 | // 请求体结构体
19 | type requestBody struct {
20 | Key string `json:"key"`
21 | Info string `json:"info"`
22 | UserId string `json:"userid"`
23 | }
24 |
25 |
26 | // 结果体结构体
27 | type responseBody struct {
28 | Code int `json:"code"`
29 | Text string `json:"text"`
30 | List []string `json:"list"`
31 | Url string `json:"url"`
32 | }
33 |
34 | // 请求机器人
35 | func process(inputChan <-chan string, userid string) {
36 | for{
37 | // 从通道中接受输入
38 | input := <- inputChan
39 | if input == "EOF"{
40 | break
41 | }
42 | // 构建请求体
43 | reqData := &requestBody{
44 | Key: "792bcf45156d488c92e9d11da494b085",
45 | Info : input,
46 | UserId: userid,
47 | }
48 | // 转义为json
49 | byteData,_ := json.Marshal(&reqData)
50 | // 请求聊天机器人接口
51 | req, err := http.NewRequest("POST",
52 | "http://www.tuling123.com/openapi/api",
53 | bytes.NewReader(byteData))
54 |
55 | req.Header.Set("Content-Type", "application/json;charset=UTF-8")
56 |
57 | client := http.Client{
58 | Timeout: 2 * time.Second,
59 |
60 | }
61 |
62 | resp, err := client.Do(req)
63 |
64 | if err != nil {
65 | fmt.Println("Network Error!")
66 | fmt.Println(err)
67 | }else {
68 | // 将结果从json中解析并输出到命令行
69 | body, _ := ioutil.ReadAll(resp.Body)
70 | var respData responseBody
71 | json.Unmarshal(body, &respData)
72 | fmt.Println("AI: " + respData.Text)
73 |
74 | }
75 | if resp != nil {
76 | resp.Body.Close()
77 | }
78 | }
79 | }
80 |
81 | func main() {
82 |
83 | var input string
84 | fmt.Println("Enter 'EOF' to shut down: ")
85 | // 创建通道
86 | channel := make(chan string)
87 | // main结束时关闭通道
88 | defer close(channel)
89 | // 启动goroutine运行机器人回答线程
90 | go process(channel, string(rand.Int63()))
91 |
92 | for {
93 | // 从命令行中读取输入
94 | fmt.Scanf("%s", &input)
95 | // 将输入放到通道中
96 | channel <- input
97 | // 结束程序
98 | if input == "EOF"{
99 | fmt.Println("Bye!")
100 | break
101 | }
102 |
103 | }
104 |
105 | }
--------------------------------------------------------------------------------
/ch5-web/gin/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "github.com/gin-gonic/gin"
6 | "net/http"
7 | )
8 |
9 | func getApi(c *gin.Context) {
10 | fmt.Println(c.Query("id"))
11 | c.String(http.StatusOK, "ok")
12 | }
13 |
14 | func postApi(c *gin.Context) {
15 | fmt.Println(c.PostForm("id"))
16 | c.String(http.StatusOK, "ok")
17 | }
18 |
19 | func postjson(c *gin.Context) {
20 | var data = &struct {
21 | Name string `json:"title"`
22 | }{}
23 |
24 | c.BindJSON(data)
25 |
26 | fmt.Println(data)
27 | c.String(http.StatusOK, "ok")
28 |
29 | }
30 |
31 | //全局中间件 允许跨域
32 | func GlobalMiddleware(c *gin.Context) {
33 | c.Header("Access-Control-Allow-Origin", "*")
34 | c.Header("Access-Control-Allow-Headers", "Content-Type,AccessToken,X-CSRF-Token, Authorization, Token")
35 | c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS")
36 | c.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Content-Type")
37 | c.Header("Access-Control-Allow-Credentials", "true")
38 | c.Next()
39 | }
40 | func AuthMiddleWare() gin.HandlerFunc {
41 | return func(c *gin.Context) {
42 | token := c.Request.Header.Get("Authorization")
43 | authorized := check(token) //调用认证方法
44 | if authorized {
45 | c.Next()
46 | return
47 | }
48 | c.JSON(http.StatusUnauthorized, gin.H{
49 | "error": "Unauthorized",
50 | })
51 | c.Abort()
52 | return
53 | }
54 | }
55 |
56 | func main() {
57 | r := gin.Default()
58 |
59 | r.GET("/home", AuthMiddleWare(), func(c *gin.Context) {
60 | c.JSON(http.StatusOK, gin.H{"data": "home"})
61 | })
62 | r.GET("/", func(c *gin.Context) {
63 | c.String(http.StatusOK, "Hello World")
64 | })
65 | r.GET("/ping", func(c *gin.Context) {
66 | c.JSON(200, gin.H{
67 | "message": "pong",
68 | })
69 | })
70 | r.GET("/user/:name", func(c *gin.Context) {
71 | name := c.Param("name")
72 | c.String(http.StatusOK, "Hello %s", name)
73 | })
74 | r.GET("/user/:name/*action", func(c *gin.Context) {
75 | name := c.Param("name")
76 | action := c.Param("action")
77 | message := name + " is " + action
78 | c.String(http.StatusOK, message)
79 | })
80 | r.GET("/getApi", getApi) //注册接口
81 | r.POST("/postApi", postApi) //注册接口
82 | r.POST("/postjson", postjson) //注册接口
83 | //r.Use(GlobalMiddleware)
84 | _ = r.Run(":8000")
85 | }
86 |
--------------------------------------------------------------------------------
/ch12-trace/zipkin-go/string-services/svc1/cmd/main.go:
--------------------------------------------------------------------------------
1 | // +build go1.7
2 |
3 | package main
4 |
5 | import (
6 | "fmt"
7 | "github.com/longjoy/micro-go-book/ch12-trace/zipkin-go/string-services/svc1"
8 | "github.com/longjoy/micro-go-book/ch12-trace/zipkin-go/string-services/svc2"
9 | "net/http"
10 | "os"
11 |
12 | "github.com/opentracing/opentracing-go"
13 |
14 | zipkin "github.com/openzipkin-contrib/zipkin-go-opentracing"
15 | //"github.com/openzipkin-contrib/zipkin-go-opentracing/examples/string-services/svc1"
16 | //"github.com/openzipkin-contrib/zipkin-go-opentracing/examples/string-services/svc2"
17 | )
18 |
19 | const (
20 | // Our service name.
21 | serviceName = "svc1"
22 |
23 | // Host + port of our service.
24 | hostPort = "127.0.0.1:61001"
25 |
26 | // Endpoint to send Zipkin spans to.
27 | zipkinHTTPEndpoint = "http://114.67.98.210:9411/api/v1/spans"
28 |
29 | // Debug mode.
30 | debug = false
31 |
32 | // Base endpoint of our SVC2 service.
33 | svc2Endpoint = "http://localhost:61002"
34 |
35 | // same span can be set to true for RPC style spans (Zipkin V1) vs Node style (OpenTracing)
36 | sameSpan = true
37 |
38 | // make Tracer generate 128 bit traceID's for root spans.
39 | traceID128Bit = true
40 | )
41 |
42 | //svc1
43 | func main() {
44 | // create collector.
45 | collector, err := zipkin.NewHTTPCollector(zipkinHTTPEndpoint)
46 | if err != nil {
47 | fmt.Printf("unable to create Zipkin HTTP collector: %+v\n", err)
48 | os.Exit(-1)
49 | }
50 |
51 | // create recorder.
52 | recorder := zipkin.NewRecorder(collector, debug, hostPort, serviceName)
53 |
54 | // create tracer.
55 | tracer, err := zipkin.NewTracer(
56 | recorder,
57 | zipkin.TraceID128Bit(traceID128Bit),
58 | )
59 | if err != nil {
60 | fmt.Printf("unable to create Zipkin tracer: %+v\n", err)
61 | os.Exit(-1)
62 | }
63 |
64 | // explicitly set our tracer to be the default tracer.
65 | opentracing.InitGlobalTracer(tracer)
66 |
67 | // create the client to svc2
68 | svc2Client := svc2.NewHTTPClient(tracer, svc2Endpoint)
69 |
70 | // create the service implementation
71 | service := svc1.NewService(svc2Client)
72 |
73 | // create the HTTP Server Handler for the service
74 | handler := svc1.NewHTTPHandler(tracer, service)
75 |
76 | // start the service
77 | fmt.Printf("Starting %s on %s\n", serviceName, hostPort)
78 | http.ListenAndServe(hostPort, handler)
79 | }
80 |
--------------------------------------------------------------------------------
/ch12-trace/zipkin-go/string-services/svc2/httpclient.go:
--------------------------------------------------------------------------------
1 | // +build go1.7
2 |
3 | package svc2
4 |
5 | import (
6 | "context"
7 | "fmt"
8 | "io/ioutil"
9 | "net/http"
10 | "strconv"
11 |
12 | opentracing "github.com/opentracing/opentracing-go"
13 |
14 | "github.com/openzipkin-contrib/zipkin-go-opentracing/examples/middleware"
15 | )
16 |
17 | // client is our actual client implementation
18 | type client struct {
19 | baseURL string
20 | httpClient *http.Client
21 | tracer opentracing.Tracer
22 | traceRequest middleware.RequestFunc
23 | }
24 |
25 | // Sum implements our Service interface.
26 | func (c *client) Sum(ctx context.Context, a int64, b int64) (int64, error) {
27 | // create new span using span found in context as parent (if none is found,
28 | // our span becomes the trace root).
29 | span, ctx := opentracing.StartSpanFromContext(ctx, "Sum")
30 | defer span.Finish()
31 |
32 | // assemble URL query
33 | url := fmt.Sprintf("%s/sum/?a=%d&b=%d", c.baseURL, a, b)
34 |
35 | // create the HTTP request
36 | req, err := http.NewRequest("GET", url, nil)
37 | if err != nil {
38 | return 0, err
39 | }
40 |
41 | // use our middleware to propagate our trace
42 | req = c.traceRequest(req.WithContext(ctx))
43 |
44 | // execute the HTTP request
45 | resp, err := c.httpClient.Do(req)
46 | if err != nil {
47 | // annotate our span with the error condition
48 | span.SetTag("error", err.Error())
49 | return 0, err
50 | }
51 | defer resp.Body.Close()
52 |
53 | // read the http response body
54 | data, err := ioutil.ReadAll(resp.Body)
55 | if err != nil {
56 | // annotate our span with the error condition
57 | span.SetTag("error", err.Error())
58 | return 0, err
59 | }
60 |
61 | // convert html response to expected result type (int64)
62 | result, err := strconv.ParseInt(string(data), 10, 64)
63 | if err != nil {
64 | // annotate our span with the error condition
65 | span.SetTag("error", err.Error())
66 | return 0, err
67 | }
68 |
69 | // return the result
70 | return result, nil
71 | }
72 |
73 | // NewHTTPClient returns a new client instance to our svc2 using the HTTP
74 | // transport.
75 | func NewHTTPClient(tracer opentracing.Tracer, baseURL string) Service {
76 | return &client{
77 | baseURL: baseURL,
78 | httpClient: &http.Client{},
79 | tracer: tracer,
80 | traceRequest: middleware.ToHTTPRequest(tracer),
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/ch12-trace/zipkin-kit/cmd/client_test.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "context"
5 | "flag"
6 | "fmt"
7 | "github.com/go-kit/kit/log"
8 | kitzipkin "github.com/go-kit/kit/tracing/zipkin"
9 | "github.com/longjoy/micro-go-book/ch12-trace/zipkin-kit/client"
10 | "github.com/openzipkin/zipkin-go"
11 | zipkinhttp "github.com/openzipkin/zipkin-go/reporter/http"
12 | "google.golang.org/grpc"
13 | "os"
14 | "testing"
15 | "time"
16 | )
17 |
18 | func TestMain(m *testing.M) {
19 | var (
20 | grpcAddr = flag.String("addr", ":9008", "gRPC address")
21 | serviceHost = flag.String("service.host", "localhost", "service ip address")
22 | servicePort = flag.String("service.port", "8009", "service port")
23 | zipkinURL = flag.String("zipkin.url", "http://114.67.98.210:9411/api/v2/spans", "Zipkin server url")
24 | )
25 | flag.Parse()
26 | var logger log.Logger
27 | {
28 | logger = log.NewLogfmtLogger(os.Stderr)
29 | logger = log.With(logger, "ts", log.DefaultTimestampUTC)
30 | logger = log.With(logger, "caller", log.DefaultCaller)
31 | }
32 | var zipkinTracer *zipkin.Tracer
33 | {
34 | var (
35 | err error
36 | hostPort = *serviceHost + ":" + *servicePort
37 | serviceName = "test-service"
38 | useNoopTracer = (*zipkinURL == "")
39 | reporter = zipkinhttp.NewReporter(*zipkinURL)
40 | )
41 | defer reporter.Close()
42 | zEP, _ := zipkin.NewEndpoint(serviceName, hostPort)
43 | zipkinTracer, err = zipkin.NewTracer(
44 | reporter, zipkin.WithLocalEndpoint(zEP), zipkin.WithNoopTracer(useNoopTracer),
45 | )
46 | if err != nil {
47 | logger.Log("err", err)
48 | os.Exit(1)
49 | }
50 | if !useNoopTracer {
51 | logger.Log("tracer", "Zipkin", "type", "Native", "URL", *zipkinURL)
52 | }
53 | }
54 | tr := zipkinTracer
55 | parentSpan := tr.StartSpan("test")
56 | defer parentSpan.Flush()
57 |
58 | ctx := zipkin.NewContext(context.Background(), parentSpan)
59 |
60 | clientTracer := kitzipkin.GRPCClientTrace(tr)
61 | conn, err := grpc.Dial(*grpcAddr, grpc.WithInsecure(), grpc.WithTimeout(1*time.Second))
62 | if err != nil {
63 | fmt.Println("gRPC dial err:", err)
64 | }
65 | defer conn.Close()
66 |
67 | svr := client.StringDiff(conn, clientTracer)
68 | result, err := svr.Diff(ctx, "Add", "ppsdd")
69 | if err != nil {
70 | fmt.Println("Diff error", err.Error())
71 |
72 | }
73 |
74 | fmt.Println("result =", result)
75 | }
76 |
--------------------------------------------------------------------------------
/ch10-resiliency/use-string-service/endpoint/endpoints.go:
--------------------------------------------------------------------------------
1 | package endpoint
2 |
3 | import (
4 | "context"
5 | "github.com/go-kit/kit/endpoint"
6 | "github.com/longjoy/micro-go-book/ch10-resiliency/use-string-service/service"
7 | )
8 |
9 | // CalculateEndpoint define endpoint
10 | type UseStringEndpoints struct {
11 | UseStringEndpoint endpoint.Endpoint
12 | HealthCheckEndpoint endpoint.Endpoint
13 | }
14 |
15 |
16 | // StringRequest define request struct
17 | type UseStringRequest struct {
18 | RequestType string `json:"request_type"`
19 | A string `json:"a"`
20 | B string `json:"b"`
21 | }
22 |
23 | // StringResponse define response struct
24 | type UseStringResponse struct {
25 | Result string `json:"result"`
26 | Error string `json:"error"`
27 | }
28 |
29 | //// MakeStringEndpoint make endpoint
30 | //func MakeUseStringEndpoint(svc service.Service) endpoint.Endpoint {
31 | // return func(ctx context.Context, request interface{}) (response interface{}, err error) {
32 | // req := request.(UseStringRequest)
33 | //
34 | // var (
35 | // res, a, b, opErrorString string
36 | // opError error
37 | // )
38 | //
39 | // a = req.A
40 | // b = req.B
41 | //
42 | // res, opError = svc.UseStringService(req.RequestType, a, b)
43 | //
44 | // if opError != nil{
45 | // opErrorString = opError.Error()
46 | // }
47 | //
48 | // return UseStringResponse{Result: res, Error: opErrorString}, nil
49 | // }
50 | //}
51 |
52 | func MakeUseStringEndpoint(svc service.Service) endpoint.Endpoint {
53 | return func(ctx context.Context, request interface{}) (response interface{}, err error) {
54 | req := request.(UseStringRequest)
55 |
56 | var (
57 | res, a, b string
58 | opError error
59 | )
60 |
61 | a = req.A
62 | b = req.B
63 |
64 | res, opError = svc.UseStringService(req.RequestType, a, b)
65 |
66 | return UseStringResponse{Result: res}, opError
67 | }
68 | }
69 |
70 |
71 | // HealthRequest 健康检查请求结构
72 | type HealthRequest struct{}
73 |
74 | // HealthResponse 健康检查响应结构
75 | type HealthResponse struct {
76 | Status bool `json:"status"`
77 | }
78 |
79 | // MakeHealthCheckEndpoint 创建健康检查Endpoint
80 | func MakeHealthCheckEndpoint(svc service.Service) endpoint.Endpoint {
81 | return func(ctx context.Context, request interface{}) (response interface{}, err error) {
82 | status := svc.HealthCheck()
83 | return HealthResponse{status}, nil
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/ch7-rpc/stream/client.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "context"
5 | "fmt"
6 | "github.com/longjoy/micro-go-book/ch7-rpc/stream-pb"
7 | "google.golang.org/grpc"
8 | "io"
9 | "log"
10 | "strconv"
11 | )
12 |
13 | func main() {
14 | serviceAddress := "127.0.0.1:1234"
15 | conn, err := grpc.Dial(serviceAddress, grpc.WithInsecure())
16 | if err != nil {
17 | panic("connect error")
18 | }
19 | defer conn.Close()
20 | stringClient := stream_pb.NewStringServiceClient(conn)
21 | stringReq := &stream_pb.StringRequest{A: "A", B: "B"}
22 | stream, _ := stringClient.LotsOfServerStream(context.Background(), stringReq)
23 | for {
24 | item, stream_error := stream.Recv()
25 | if stream_error == io.EOF {
26 | break
27 | }
28 | if stream_error != nil {
29 | log.Printf("failed to recv: %v", stream_error)
30 | }
31 | fmt.Printf("StringService Concat : %s concat %s = %s\n", stringReq.A, stringReq.B, item.GetRet())
32 | }
33 |
34 | sendClientStreamRequest(stringClient)
35 |
36 | //sendClientAndServerStreamRequest(stringClient)
37 | }
38 |
39 | func sendClientStreamRequest(client stream_pb.StringServiceClient) {
40 | fmt.Printf("test sendClientStreamRequest \n")
41 |
42 | stream, err := client.LotsOfClientStream(context.Background())
43 | for i := 0; i < 10; i++ {
44 | if err != nil {
45 | log.Printf("failed to call: %v", err)
46 | break
47 | }
48 | stream.Send(&stream_pb.StringRequest{A: strconv.Itoa(i), B: strconv.Itoa(i + 1)})
49 | }
50 | reply, err := stream.CloseAndRecv()
51 | if err != nil {
52 | fmt.Printf("failed to recv: %v", err)
53 | }
54 | log.Printf("sendClientStreamRequest ret is : %s", reply.Ret)
55 | }
56 |
57 | func sendClientAndServerStreamRequest(client stream_pb.StringServiceClient) {
58 | fmt.Printf("test sendClientAndServerStreamRequest \n")
59 | var err error
60 | stream, err := client.LotsOfServerAndClientStream(context.Background())
61 | if err != nil {
62 | log.Printf("failed to call: %v", err)
63 | return
64 | }
65 | var i int
66 | for {
67 | err1 := stream.Send(&stream_pb.StringRequest{A: strconv.Itoa(i), B: strconv.Itoa(i + 1)})
68 | if err1 != nil {
69 | log.Printf("failed to send: %v", err)
70 | break
71 | }
72 | reply, err2 := stream.Recv()
73 | if err2 != nil {
74 | log.Printf("failed to recv: %v", err)
75 | break
76 | }
77 | log.Printf("sendClientAndServerStreamRequest Ret is : %s", reply.Ret)
78 | i++
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/ch13-seckill/sk-app/setup/zk.go:
--------------------------------------------------------------------------------
1 | package setup
2 |
3 | import (
4 | "encoding/json"
5 | "fmt"
6 | conf "github.com/longjoy/micro-go-book/ch13-seckill/pkg/config"
7 | "github.com/samuel/go-zookeeper/zk"
8 | "log"
9 | "time"
10 | )
11 |
12 | //初始化Etcd
13 | func InitZk() {
14 | var hosts = []string{"39.98.179.73:2181"}
15 | //option := zk.WithEventCallback(waitSecProductEvent)
16 | conn, _, err := zk.Connect(hosts, time.Second*5)
17 | if err != nil {
18 | fmt.Println(err)
19 | return
20 | }
21 |
22 | conf.Zk.ZkConn = conn
23 | conf.Zk.SecProductKey = "/product"
24 | loadSecConf(conn)
25 | }
26 |
27 | //加载秒杀商品信息
28 | func loadSecConf(conn *zk.Conn) {
29 | log.Printf("Connect zk sucess %s", conf.Zk.SecProductKey)
30 | v, _, err := conn.Get(conf.Zk.SecProductKey) //conf.Etcd.EtcdSecProductKey
31 | if err != nil {
32 | log.Printf("get product info failed, err : %v", err)
33 | return
34 | }
35 | log.Printf("get product info ")
36 | var secProductInfo []*conf.SecProductInfoConf
37 | err1 := json.Unmarshal(v, &secProductInfo)
38 | if err1 != nil {
39 | log.Printf("Unmsharl second product info failed, err : %v", err1)
40 | }
41 | updateSecProductInfo(secProductInfo)
42 | }
43 |
44 | func waitSecProductEvent(event zk.Event) {
45 | log.Print(">>>>>>>>>>>>>>>>>>>")
46 | log.Println("path:", event.Path)
47 | log.Println("type:", event.Type.String())
48 | log.Println("state:", event.State.String())
49 | log.Println("<<<<<<<<<<<<<<<<<<<")
50 | if event.Path == conf.Zk.SecProductKey {
51 |
52 | }
53 | }
54 |
55 | //监听秒杀商品配置
56 | //for wrsp := range rch {
57 | // for _, ev := range wrsp.Events {
58 | // //删除事件
59 | // if ev.Type == mvccpb.DELETE {
60 | // continue
61 | // }
62 | //
63 | // //更新事件
64 | // if ev.Type == mvccpb.PUT && string(ev.Kv.Key) == key {
65 | // err := json.Unmarshal(ev.Kv.Value, &secProductInfo)
66 | // if err != nil {
67 | // getConfSucc = false
68 | // continue
69 | // }
70 | // }
71 | // }
72 | //
73 | // if getConfSucc {
74 | // updateSecProductInfo(secProductInfo)
75 | // }
76 | //}
77 |
78 | //更新秒杀商品信息
79 | func updateSecProductInfo(secProductInfo []*conf.SecProductInfoConf) {
80 | tmp := make(map[int]*conf.SecProductInfoConf, 1024)
81 | for _, v := range secProductInfo {
82 | log.Printf("updateSecProductInfo %v", v)
83 | tmp[v.ProductId] = v
84 | }
85 | conf.SecKill.RWBlackLock.Lock()
86 | conf.SecKill.SecProductInfoMap = tmp
87 | conf.SecKill.RWBlackLock.Unlock()
88 | }
89 |
--------------------------------------------------------------------------------
/ch12-trace/zipkin-go/string-services/svc2/implementation.go:
--------------------------------------------------------------------------------
1 | // +build go1.7
2 |
3 | package svc2
4 |
5 | import (
6 | "context"
7 | "time"
8 |
9 | "github.com/opentracing/opentracing-go"
10 | "github.com/opentracing/opentracing-go/ext"
11 | )
12 |
13 | // svc2 is our actual service implementation.
14 | type svc2 struct{}
15 |
16 | // NewService returns a new implementation of our Service.
17 | func NewService() Service {
18 | return &svc2{}
19 | }
20 |
21 | // Sum implements our Service interface.
22 | func (s *svc2) Sum(ctx context.Context, a int64, b int64) (int64, error) {
23 | // We love starting up slow
24 | time.Sleep(5 * time.Millisecond)
25 |
26 | // Pull span from context.
27 | span := opentracing.SpanFromContext(ctx)
28 |
29 | // Example binary annotations.
30 | span.SetTag("service", "svc2")
31 | span.SetTag("string", "some value")
32 | span.SetTag("int", 123)
33 | span.SetTag("bool", true)
34 |
35 | // Example annotation
36 | span.LogEvent("MyEventAnnotation")
37 |
38 | // Let's wait a little so it shows up nicely in our tracing graphics.
39 | time.Sleep(10 * time.Millisecond)
40 |
41 | // Let's assume we want to trace a call we do to a database.
42 | s.fakeDBCall(span)
43 |
44 | // Check for Int overflow condition.
45 | if (b > 0 && a > (Int64Max-b)) || (b < 0 && a < (Int64Min-b)) {
46 | span.SetTag("error", ErrIntOverflow.Error())
47 | return 0, ErrIntOverflow
48 | }
49 |
50 | // calculate and return the result (all that boilerplate for this?) ;)
51 | return a + b, nil
52 | }
53 |
54 | func (s *svc2) fakeDBCall(span opentracing.Span) {
55 | resourceSpan := opentracing.StartSpan(
56 | "myComplexQuery",
57 | opentracing.ChildOf(span.Context()),
58 | )
59 | defer resourceSpan.Finish()
60 | // mark span as resource type
61 | ext.SpanKind.Set(resourceSpan, "resource")
62 | // name of the resource we try to reach
63 | ext.PeerService.Set(resourceSpan, "PostgreSQL")
64 | // hostname of the resource
65 | ext.PeerHostname.Set(resourceSpan, "localhost")
66 | // port of the resource
67 | ext.PeerPort.Set(resourceSpan, 3306)
68 | // let's binary annotate the query we run
69 | resourceSpan.SetTag(
70 | "query", "SELECT recipes FROM cookbook WHERE topic = 'world domination'",
71 | )
72 |
73 | // Let's assume the query is going to take some time. Finding the right
74 | // world domination recipes is like searching for a needle in a haystack.
75 | time.Sleep(20 * time.Millisecond)
76 |
77 | // sweet... all done
78 | }
79 |
--------------------------------------------------------------------------------
/ch10-resiliency/string-service/transport/http.go:
--------------------------------------------------------------------------------
1 | package transport
2 |
3 | import (
4 | "context"
5 | "encoding/json"
6 | "errors"
7 | "github.com/go-kit/kit/log"
8 | "github.com/go-kit/kit/transport"
9 | kithttp "github.com/go-kit/kit/transport/http"
10 | "github.com/gorilla/mux"
11 | "github.com/longjoy/micro-go-book/ch10-resiliency/string-service/endpoint"
12 | "github.com/prometheus/client_golang/prometheus/promhttp"
13 | "net/http"
14 | )
15 |
16 | var (
17 | ErrorBadRequest = errors.New("invalid request parameter")
18 | )
19 |
20 | // MakeHttpHandler make http handler use mux
21 | func MakeHttpHandler(ctx context.Context, endpoints endpoint.StringEndpoints, logger log.Logger) http.Handler {
22 | r := mux.NewRouter()
23 |
24 | options := []kithttp.ServerOption{
25 | kithttp.ServerErrorHandler(transport.NewLogErrorHandler(logger)),
26 | kithttp.ServerErrorEncoder(kithttp.DefaultErrorEncoder),
27 | }
28 |
29 | r.Methods("POST").Path("/op/{type}/{a}/{b}").Handler(kithttp.NewServer(
30 | endpoints.StringEndpoint,
31 | decodeStringRequest,
32 | encodeStringResponse,
33 | options...,
34 | ))
35 |
36 | r.Path("/metrics").Handler(promhttp.Handler())
37 |
38 | // create health check handler
39 | r.Methods("GET").Path("/health").Handler(kithttp.NewServer(
40 | endpoints.HealthCheckEndpoint,
41 | decodeHealthCheckRequest,
42 | encodeStringResponse,
43 | options...,
44 | ))
45 |
46 | return r
47 | }
48 |
49 | // decodeStringRequest decode request params to struct
50 | func decodeStringRequest(_ context.Context, r *http.Request) (interface{}, error) {
51 | vars := mux.Vars(r)
52 | requestType, ok := vars["type"]
53 | if !ok {
54 | return nil, ErrorBadRequest
55 | }
56 |
57 | pa, ok := vars["a"]
58 | if !ok {
59 | return nil, ErrorBadRequest
60 | }
61 |
62 | pb, ok := vars["b"]
63 | if !ok {
64 | return nil, ErrorBadRequest
65 | }
66 |
67 | return endpoint.StringRequest{
68 | RequestType: requestType,
69 | A: pa,
70 | B: pb,
71 | }, nil
72 | }
73 |
74 | // encodeStringResponse encode response to return
75 | func encodeStringResponse(ctx context.Context, w http.ResponseWriter, response interface{}) error {
76 | w.Header().Set("Content-Type", "application/json;charset=utf-8")
77 | return json.NewEncoder(w).Encode(response)
78 | }
79 |
80 | // decodeHealthCheckRequest decode request
81 | func decodeHealthCheckRequest(ctx context.Context, r *http.Request) (interface{}, error) {
82 | return endpoint.HealthRequest{}, nil
83 | }
84 |
--------------------------------------------------------------------------------
/ch13-seckill/user-service/endpoint/endpoints.go:
--------------------------------------------------------------------------------
1 | package endpoint
2 |
3 | import (
4 | "context"
5 | "errors"
6 | "github.com/go-kit/kit/endpoint"
7 | "github.com/longjoy/micro-go-book/ch13-seckill/user-service/service"
8 | "reflect"
9 | )
10 |
11 | type UserEndpoints struct {
12 | UserEndpoint endpoint.Endpoint
13 | HealthCheckEndpoint endpoint.Endpoint
14 | }
15 |
16 | // UserEndpoint define endpoint
17 | func (u *UserEndpoints) Check(ctx context.Context, username string, password string) (int64, error) {
18 | //ctx := context.Background()
19 | reflect.TypeOf(UserEndpoints{})
20 | resp, err := u.UserEndpoint(ctx, UserRequest{
21 | Username: username,
22 | Password: password,
23 | })
24 | response := resp.(UserResponse)
25 | err = errors.New("bad request!")
26 | return response.UserId, err
27 | }
28 |
29 | func (ue *UserEndpoints) HealthCheck() bool {
30 | return false
31 | }
32 |
33 | var (
34 | ErrInvalidRequestType = errors.New("invalid username, password")
35 | )
36 |
37 | // UserRequest define request struct
38 | type UserRequest struct {
39 | Username string `json:"username"`
40 | Password string `json:"password"`
41 | }
42 |
43 | // UserResponse define response struct
44 | type UserResponse struct {
45 | Result bool `json:"result"`
46 | UserId int64 `json:"user_id"`
47 | Error error `json:"error"`
48 | }
49 |
50 | // make endpoint
51 | func MakeUserEndpoint(svc service.Service) endpoint.Endpoint {
52 | return func(ctx context.Context, request interface{}) (response interface{}, err error) {
53 | req := request.(UserRequest)
54 |
55 | var (
56 | username, password string
57 | userId int64
58 | calError error
59 | )
60 |
61 | username = req.Username
62 | password = req.Password
63 |
64 | userId, calError = svc.Check(ctx, username, password)
65 | if calError != nil {
66 | return UserResponse{Result: false, Error: calError}, nil
67 | }
68 | return UserResponse{Result: true, UserId:userId, Error: calError}, nil
69 | }
70 | }
71 |
72 | // HealthRequest 健康检查请求结构
73 | type HealthRequest struct{}
74 |
75 | // HealthResponse 健康检查响应结构
76 | type HealthResponse struct {
77 | Status bool `json:"status"`
78 | }
79 |
80 | // MakeHealthCheckEndpoint 创建健康检查Endpoint
81 | func MakeHealthCheckEndpoint(svc service.Service) endpoint.Endpoint {
82 | return func(ctx context.Context, request interface{}) (response interface{}, err error) {
83 | status := svc.HealthCheck()
84 | return HealthResponse{status}, nil
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/ch13-seckill/user-service/plugins/instrument.go:
--------------------------------------------------------------------------------
1 | package plugins
2 |
3 | import (
4 | "context"
5 | "errors"
6 | "github.com/go-kit/kit/endpoint"
7 | "github.com/go-kit/kit/metrics"
8 | "github.com/juju/ratelimit"
9 | "github.com/longjoy/micro-go-book/ch13-seckill/user-service/service"
10 | "golang.org/x/time/rate"
11 | "time"
12 | )
13 |
14 | var ErrLimitExceed = errors.New("Rate limit exceed!")
15 |
16 | // NewTokenBucketLimitterWithJuju 使用juju/ratelimit创建限流中间件
17 | func NewTokenBucketLimitterWithJuju(bkt *ratelimit.Bucket) endpoint.Middleware {
18 | return func(next endpoint.Endpoint) endpoint.Endpoint {
19 | return func(ctx context.Context, request interface{}) (response interface{}, err error) {
20 | if bkt.TakeAvailable(1) == 0 {
21 | return nil, ErrLimitExceed
22 | }
23 | return next(ctx, request)
24 | }
25 | }
26 | }
27 |
28 | // NewTokenBucketLimitterWithBuildIn 使用x/time/rate创建限流中间件
29 | func NewTokenBucketLimitterWithBuildIn(bkt *rate.Limiter) endpoint.Middleware {
30 | return func(next endpoint.Endpoint) endpoint.Endpoint {
31 | return func(ctx context.Context, request interface{}) (response interface{}, err error) {
32 | if !bkt.Allow() {
33 | return nil, ErrLimitExceed
34 | }
35 | return next(ctx, request)
36 | }
37 | }
38 | }
39 |
40 | // metricMiddleware 定义监控中间件,嵌入Service
41 | // 新增监控指标项:requestCount和requestLatency
42 | type metricMiddleware struct {
43 | service.Service
44 | requestCount metrics.Counter
45 | requestLatency metrics.Histogram
46 | }
47 |
48 | // Metrics 封装监控方法
49 | func Metrics(requestCount metrics.Counter, requestLatency metrics.Histogram) service.ServiceMiddleware {
50 | return func(next service.Service) service.Service {
51 | return metricMiddleware{
52 | next,
53 | requestCount,
54 | requestLatency}
55 | }
56 | }
57 |
58 | func (mw metricMiddleware) Check(ctx context.Context, a, b string) (ret int64, err error) {
59 |
60 | defer func(beign time.Time) {
61 | lvs := []string{"method", "Add"}
62 | mw.requestCount.With(lvs...).Add(1)
63 | mw.requestLatency.With(lvs...).Observe(time.Since(beign).Seconds())
64 | }(time.Now())
65 |
66 | ret, err = mw.Service.Check(ctx, a, b)
67 | return ret, err
68 | }
69 |
70 | func (mw metricMiddleware) HealthCheck() (result bool) {
71 |
72 | defer func(begin time.Time) {
73 | lvs := []string{"method", "HealthCheck"}
74 | mw.requestCount.With(lvs...).Add(1)
75 | mw.requestLatency.With(lvs...).Observe(time.Since(begin).Seconds())
76 | }(time.Now())
77 |
78 | result = mw.Service.HealthCheck()
79 | return
80 | }
81 |
--------------------------------------------------------------------------------
/ch12-trace/zipkin-go/string-services/svc1/httpserver.go:
--------------------------------------------------------------------------------
1 | // +build go1.7
2 |
3 | package svc1
4 |
5 | import (
6 | "fmt"
7 | "net/http"
8 | "strconv"
9 |
10 | "github.com/opentracing/opentracing-go"
11 |
12 | "github.com/openzipkin-contrib/zipkin-go-opentracing/examples/middleware"
13 | )
14 |
15 | type httpService struct {
16 | service Service
17 | }
18 |
19 | // concatHandler is our HTTP HandlerFunc for a Concat request.
20 | func (s *httpService) concatHandler(w http.ResponseWriter, req *http.Request) {
21 | // parse query parameters
22 | v := req.URL.Query()
23 | result, err := s.service.Concat(req.Context(), v.Get("a"), v.Get("b"))
24 | if err != nil {
25 | http.Error(w, err.Error(), http.StatusBadRequest)
26 | return
27 | }
28 | // return the result
29 | w.Write([]byte(result))
30 | }
31 |
32 | // sumHandler is our HTTP Handlerfunc for a Sum request.
33 | func (s *httpService) sumHandler(w http.ResponseWriter, req *http.Request) {
34 | // parse query parameters
35 | v := req.URL.Query()
36 | a, err := strconv.ParseInt(v.Get("a"), 10, 64)
37 | if err != nil {
38 | http.Error(w, err.Error(), http.StatusBadRequest)
39 | return
40 | }
41 | b, err := strconv.ParseInt(v.Get("b"), 10, 64)
42 | if err != nil {
43 | http.Error(w, err.Error(), http.StatusBadRequest)
44 | return
45 | }
46 | // call our Sum binding
47 | result, err := s.service.Sum(req.Context(), a, b)
48 | if err != nil {
49 | http.Error(w, err.Error(), http.StatusBadRequest)
50 | return
51 | }
52 | // return the result
53 | w.Write([]byte(fmt.Sprintf("%d", result)))
54 | }
55 |
56 | // NewHTTPHandler returns a new HTTP handler our svc1.
57 | func NewHTTPHandler(tracer opentracing.Tracer, service Service) http.Handler {
58 | // Create our HTTP Service.
59 | svc := &httpService{service: service}
60 |
61 | // Create the mux.
62 | mux := http.NewServeMux()
63 |
64 | // Create the Concat handler.
65 | var concatHandler http.Handler
66 | concatHandler = http.HandlerFunc(svc.concatHandler)
67 |
68 | // Wrap the Concat handler with our tracing middleware.
69 | concatHandler = middleware.FromHTTPRequest(tracer, "Concat")(concatHandler)
70 |
71 | // Create the Sum handler.
72 | var sumHandler http.Handler
73 | sumHandler = http.HandlerFunc(svc.sumHandler)
74 |
75 | // Wrap the Sum handler with our tracing middleware.
76 | sumHandler = middleware.FromHTTPRequest(tracer, "Sum")(sumHandler)
77 |
78 | // Wire up the mux.
79 | mux.Handle("/concat/", concatHandler)
80 | mux.Handle("/sum/", sumHandler)
81 |
82 | // Return the mux.
83 | return mux
84 | }
85 |
--------------------------------------------------------------------------------