### Go Example: Setting up a Dynamic Reverse Proxy Source: https://github.com/go-dev-frame/sponge/blob/main/pkg/proxykit/README.md This Go code demonstrates how to initialize and configure the Proxy Kit to create a dynamic reverse proxy. It sets up a route manager, defines initial backend targets, starts health checks, and registers both proxy and management API handlers with a standard HTTP multiplexer. The example showcases dynamic route registration and basic HTTP server setup. ```go package main import ( "log" "net/http" "time" "github.com/go-dev-frame/sponge/pkg/proxykit" ) func main() { prefixPath := "/proxy/" // 1. Create the route manager manager := proxykit.NewRouteManager() // 2. Initialize backend targets initialTargets := []string{"http://localhost:8081", "http://localhost:8082"} backends, _ := proxykit.ParseBackends(prefixPath, initialTargets) proxykit.StartHealthChecks(backends, proxykit.HealthCheckConfig{Interval: 5 * time.Second}) balancer := proxykit.NewRoundRobin(backends) // Register route apiRoute, err := manager.AddRoute(prefixPath, balancer) if err != nil { log.Fatalf("Could not add initial route: %v", err) } // 3. Build standard library mux mux := http.NewServeMux() // 4. Register proxy handler (same as gin.Any) mux.Handle(prefixPath, apiRoute.Proxy) // 5. Management API (corresponds to /endpoints/...) mux.HandleFunc("/endpoints/add", manager.HandleAddBackends) mux.HandleFunc("/endpoints/remove", manager.HandleRemoveBackends) mux.HandleFunc("/endpoints/list", manager.HandleListBackends) mux.HandleFunc("/endpoints", manager.HandleGetBackend) // 6. Other normal routes mux.HandleFunc("/ping", func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") w.Write([]byte(`{"message": "pong"}`)) }) // 7. Start HTTP server log.Println("HTTP server with dynamic proxy started on http://localhost:8080") log.Printf("Proxying requests from %s*\n", prefixPath) log.Println("Management API available at /endpoints/*") err = http.ListenAndServe(":8080", mux) if err != nil { log.Fatal("ListenAndServe:", err) } } ``` -------------------------------- ### Install Recommended Jenkins Plugins Source: https://github.com/go-dev-frame/sponge/blob/main/test/server/jenkins/README.md This section lists essential plugins to install in Jenkins for enhanced functionality, including localization, extended choice parameters, Git integration, and role-based authorization. It assumes the user is within the Jenkins plugin management interface. ```bash # if required, install Chinese plugin Locale # adding parametric build plugin Extended Choice Parameter # adding the git parameters plugin Git Parameter # account Management Role-based Authorization Strategy ``` -------------------------------- ### Setup and Run Direct Exchange Producer and Consumer Source: https://github.com/go-dev-frame/sponge/blob/main/pkg/rabbitmq/README.md This example demonstrates setting up a direct exchange, a queue, and a route key to send and receive messages. It initializes a producer and a consumer, then enters a loop to publish messages periodically while the context is active. Error handling for publishing includes reconnection logic. ```go func main() { ctx, _ := context.WithTimeout(context.Background(), time.Hour) exchangeName := "direct-exchange-demo" queueName := "direct-queue" routeKey := "info" exchange := rabbitmq.NewDirectExchange(exchangeName, routeKey) err := runConsume(ctx, exchange, queueName) if err != nil { logger.Error("runConsume failed", logger.Err(err)) return } err = runProduce(ctx, exchange, queueName) if err != nil { logger.Error("runProduce failed", logger.Err(err)) return } } func runConsume(ctx context.Context, exchange *rabbitmq.Exchange, queueName string) error { connection, err := rabbitmq.NewConnection(url, rabbitmq.WithLogger(logger.Get())) if err != nil { return err } c, err := rabbitmq.NewConsumer(exchange, queueName, connection, rabbitmq.WithConsumerAutoAck(false)) if err != nil { return err } c.Consume(ctx, handler) return nil } ``` -------------------------------- ### Get User Example by ID Source: https://github.com/go-dev-frame/sponge/blob/main/docs/apis.html Retrieves a single user example by its unique identifier. ```APIDOC ## GET /api/v1/userExample/{id} ### Description Retrieves a single user example by its unique identifier. ### Method GET ### Endpoint /api/v1/userExample/{id} ### Path Parameters - **id** (uint64) - Required - The unique identifier of the user example to retrieve. ### Response #### Success Response (200) - **id** (uint64) - The unique identifier of the user example. - **name** (string) - The name of the user. - **email** (string) - The email address of the user. - **phone** (string) - The phone number of the user. - **avatar** (string) - The URL of the user's avatar. - **age** (int32) - The age of the user. - **gender** (GenderType) - The gender of the user. - **status** (int32) - The account status. - **login_at** (int64) - The timestamp of the last login. - **created_at** (int64) - The creation timestamp. - **updated_at** (int64) - The update timestamp. #### Response Example ```json { "id": 1, "name": "John Doe", "email": "john.doe@example.com", "phone": "123-456-7890", "avatar": "http://example.com/avatar.jpg", "age": 30, "gender": 1, "status": 1, "login_at": 1678886400, "created_at": 1678886400, "updated_at": 1678886400 } ``` ``` -------------------------------- ### Build and Push Docker Image for Jenkins Go Source: https://github.com/go-dev-frame/sponge/blob/main/test/server/jenkins/README.md This snippet demonstrates how to build a Docker image tagged 'zhufuyi/jenkins-go:2.37' and push it to a Docker registry. It includes logging into the registry, which is necessary for private repositories. ```shell docker build -t zhufuyi/jenkins-go:2.37 . docker login -u username docker push zhufuyi/jenkins-go:2.37 ``` -------------------------------- ### Run gRPC Server in Go Source: https://github.com/go-dev-frame/sponge/blob/main/pkg/grpc/server/README.md This Go code snippet demonstrates how to initialize and run a gRPC server using the 'github.com/go-dev-frame/sponge/pkg/grpc/server' library. It includes defining a service handler, registering it with the server, and starting the server to listen for incoming requests. Dependencies include the 'google.golang.org/grpc' package and a protobuf-generated service definition. ```go package main import ( "context" "fmt" "github.com/go-dev-frame/sponge/pkg/grpc/server" "google.golang.org/grpc" pb "google.golang.org/grpc/examples/helloworld/helloworld" ) type greeterServer struct { pb.UnimplementedGreeterServer } func (s *greeterServer) SayHello(_ context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) { fmt.Printf("Received: %v\n", in.GetName()) return &pb.HelloReply{Message: "Hello " + in.GetName()}, } func main() { port := 8282 registerFn := func(s *grpc.Server) { pb.RegisterGreeterServer(s, &greeterServer{}) // Register other services here } fmt.Printf("Starting server on port %d\n", port) srv, err := server.Run(port, registerFn, //server.WithSecure(credentials), //server.WithUnaryInterceptor(unaryInterceptors...), //server.WithStreamInterceptor(streamInterceptors...), //server.WithServiceRegister(srFn), // register service address to Consul/Etcd/Zookeeper... //server.WithStatConnections(metrics.WithConnectionsLogger(logger.Get()), metrics.WithConnectionsGauge()), ) if err != nil { panic(err) } defer srv.Stop() select {} } ``` -------------------------------- ### Go WebSocket Server: Default Setup Source: https://github.com/go-dev-frame/sponge/blob/main/pkg/ws/README.md Example of setting up a default WebSocket server using the 'ws' library. It handles incoming connections and processes messages received from clients. Dependencies include 'gorilla/websocket' and 'gin-gonic/gin'. ```go package main import ( "context" "log" "github.com/go-dev-frame/sponge/pkg/ws" "github.com/gin-gonic/gin" ) func main() { r := gin.Default() r.GET("/ws", func(c *gin.Context) { s := ws.NewServer(c.Writer, c.Request, loopReceiveMessage) // default setting err := s.Run(context.Background()) if err != nil { log.Println("webSocket server error:", err) } }) err := r.Run(":8080") if err != nil { panic(err) } } func loopReceiveMessage(ctx context.Context, conn *ws.Conn) { for { messageType, message, err := conn.ReadMessage() if err != nil { // release connection return } // handle message log.Println(messageType, message) } } ``` -------------------------------- ### Create User Example Source: https://github.com/go-dev-frame/sponge/blob/main/docs/apis.html Creates a new user example. Requires a request body containing the user's details. ```APIDOC ## POST /api/v1/userExample ### Description Creates a new user example. ### Method POST ### Endpoint /api/v1/userExample ### Request Body - **name** (string) - Required - The name of the user. - **email** (string) - Required - The email address of the user. - **password** (string) - Required - The password for the user account. - **phone** (string) - Optional - The phone number of the user. - **avatar** (string) - Optional - The URL of the user's avatar. - **age** (int32) - Optional - The age of the user. - **gender** (GenderType) - Optional - The gender of the user (1:Male, 2:Female, other:unknown). - **status** (int32) - Optional - The account status. - **login_at** (int64) - Optional - The timestamp of the last login. ### Request Example ```json { "name": "John Doe", "email": "john.doe@example.com", "password": "securepassword123", "phone": "123-456-7890", "avatar": "http://example.com/avatar.jpg", "age": 30, "gender": 1, "status": 1, "login_at": 1678886400 } ``` ### Response #### Success Response (200) - **id** (uint64) - The unique identifier of the created user example. - **name** (string) - The name of the user. - **email** (string) - The email address of the user. - **phone** (string) - The phone number of the user. - **avatar** (string) - The URL of the user's avatar. - **age** (int32) - The age of the user. - **gender** (GenderType) - The gender of the user. - **status** (int32) - The account status. - **login_at** (int64) - The timestamp of the last login. - **created_at** (int64) - The creation timestamp. - **updated_at** (int64) - The update timestamp. #### Response Example ```json { "id": 1, "name": "John Doe", "email": "john.doe@example.com", "phone": "123-456-7890", "avatar": "http://example.com/avatar.jpg", "age": 30, "gender": 1, "status": 1, "login_at": 1678886400, "created_at": 1678886400, "updated_at": 1678886400 } ``` ``` -------------------------------- ### List User Examples Source: https://github.com/go-dev-frame/sponge/blob/main/docs/apis.html Retrieves a list of user examples, potentially with filtering and pagination options. ```APIDOC ## POST /api/v1/userExample/list ### Description Retrieves a list of user examples, potentially with filtering and pagination options. ### Method POST ### Endpoint /api/v1/userExample/list ### Request Body - **params** (types.Params) - Optional - Parameters for filtering and pagination. This can include fields like `page`, `pageSize`, `orderBy`, etc. ### Request Example ```json { "params": { "page": 1, "pageSize": 10, "orderBy": "created_at DESC" } } ``` ### Response #### Success Response (200) - **total** (int64) - The total number of user examples available. - **userExamples** (array of UserExample) - A list of user examples. #### Response Example ```json { "total": 50, "userExamples": [ { "id": 1, "name": "John Doe", "email": "john.doe@example.com", "phone": "123-456-7890", "avatar": "http://example.com/avatar.jpg", "age": 30, "gender": 1, "status": 1, "login_at": 1678886400, "created_at": 1678886400, "updated_at": 1678886400 }, { "id": 2, "name": "Jane Smith", "email": "jane.smith@example.com", "phone": "987-654-3210", "avatar": "http://example.com/jane_avatar.jpg", "age": 25, "gender": 2, "status": 1, "login_at": 1678886400, "created_at": 1678886400, "updated_at": 1678886400 } ] } ``` ``` -------------------------------- ### Publish Headers Example in Go Source: https://github.com/go-dev-frame/sponge/blob/main/pkg/rabbitmq/README.md Demonstrates how to publish messages with headers using the rabbitmq library in Go. It sets up a producer, publishes messages with specific headers, and includes a consumer to receive them. This example requires a running RabbitMQ instance. ```Go func headersExample(url string) { exchangeName := "headers-exchange-demo" queueName := "headers-queue" routingKey := "headers-key" exchange := rabbitmq.NewHeadersExchange(exchangeName, rabbitmq.NewDirectExchange("", routingKey)) var queueArgs map[string]interface{} fmt.Printf("\n\n-------------------- headers message --------------------\n") // producer-side headers message { connection, err := rabbitmq.NewConnection(url, rabbitmq.WithLogger(logger.Get())) checkErr(err) defer connection.Close() p, err := rabbitmq.NewProducer(exchange, queueName, connection) checkErr(err) defer p.Close() queueArgs = p.QueueArgs() ctx := context.Background() headersKeys1 := map[string]interface{}{"key1": "value1"} headersKeys2 := map[string]interface{}{"key2": "value2"} for i := 1; i <= 100; i++ { err = p.PublishHeaders(ctx, headersKeys1, []byte("[headers] key1 message "+strconv.Itoa(i))) checkErr(err) err = p.PublishHeaders(ctx, headersKeys2, []byte("[headers] key2 message "+strconv.Itoa(i))) checkErr(err) } } // consumer-side headers message { c := runConsume(url, exchange, queueName, queueArgs) <-time.After(time.Second * 5) atomic.AddInt32(&consumerCount, int32(c.Count())) } printStat() } ``` -------------------------------- ### Install protoc and Go plugins Source: https://github.com/go-dev-frame/sponge/blob/main/cmd/protoc-gen-go-rpc-tmpl/README.md Installs the protobuf compiler (protoc) on Linux and the necessary Go plugins: protoc-gen-go and protoc-gen-go-grpc. Ensure Go is installed and GOROOT is set. ```bash # install protoc in linux mkdir -p protocDir \ && curl -L -o protocDir/protoc.zip https://github.com/protocolbuffers/protobuf/releases/download/v3.20.1/protoc-3.20.1-linux-x86_64.zip \ && unzip protocDir/protoc.zip -d protocDir\ && mv protocDir/bin/protoc protocDir/include/ $GOROOT/bin/ \ && rm -rf protocDir # install protoc-gen-go, protoc-gen-go-grpc go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.28.0 go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.2.0 ``` -------------------------------- ### Install protoc-gen-go-rpc-tmpl Source: https://github.com/go-dev-frame/sponge/blob/main/cmd/protoc-gen-go-rpc-tmpl/README.md Installs the protoc-gen-go-rpc-tmpl plugin using the Go install command. This plugin is required for generating RPC service and error code templates. ```bash go install github.com/go-dev-frame/sponge/cmd/protoc-gen-go-rpc-tmpl@latest ``` -------------------------------- ### Install protoc and Go plugins Source: https://github.com/go-dev-frame/sponge/blob/main/cmd/protoc-gen-go-gin/README.md Installs the protoc compiler on Linux and the necessary Go plugins: protoc-gen-go, protoc-gen-go-grpc, and protoc-gen-go-gin. These are essential for protobuf code generation. ```bash mkdir -p protocDir && curl -L -o protocDir/protoc.zip https://github.com/protocolbuffers/protobuf/releases/download/v3.20.1/protoc-3.20.1-linux-x86_64.zip && unzip protocDir/protoc.zip -d protocDir && mv protocDir/bin/protoc protocDir/include/ $GOROOT/bin/ && rm -rf protocDir go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.28.0 go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.2.0 # Install protoc-gen-go-gin go install github.com/go-dev-frame/sponge/cmd/protoc-gen-go-gin@latest ``` -------------------------------- ### Go SSE Client Example Source: https://github.com/go-dev-frame/sponge/blob/main/pkg/sse/README.md Provides an example of how to create and connect an SSE client using the sponge library. It connects to a specified URL, registers an event handler for default event types, and waits for incoming events. ```go package main import ( "fmt" "github.com/go-dev-frame/sponge/pkg/sse" ) func main() { url := "http://localhost:8080/events" // Create SSE client client := sse.NewClient(url) client.OnEvent(sse.DefaultEventType, func(event *sse.Event) { fmt.Printf("Received: %#v\n", event) }) err := client.Connect() if err != nil { fmt.Printf("Connection failed: %v\n", err) return } fmt.Println("SSE client started, press Ctrl+C to exit") <-client.Wait() } ``` -------------------------------- ### Helper Function to Run Consumer in Go Source: https://github.com/go-dev-frame/sponge/blob/main/pkg/rabbitmq/README.md A utility function to set up and run a RabbitMQ consumer in Go. It establishes a connection, creates a consumer instance with specified options (like auto-acknowledgement), and starts consuming messages using a provided handler. This function abstracts the common consumer setup logic. ```Go func runConsume(url string, exchange *rabbitmq.Exchange, queueName string, queueArgs map[string]interface{}) *rabbitmq.Consumer { connection, err := rabbitmq.NewConnection(url, rabbitmq.WithLogger(logger.Get())) checkErr(err) c, err := rabbitmq.NewConsumer(exchange, queueName, connection, rabbitmq.WithConsumerAutoAck(false), rabbitmq.WithConsumerQueueDeclareOptions( rabbitmq.WithQueueDeclareArgs(queueArgs), ), ) checkErr(err) c.Consume(context.Background(), handler) return c } ``` -------------------------------- ### List User Examples by IDs Source: https://github.com/go-dev-frame/sponge/blob/main/docs/apis.html Retrieves a list of user examples based on a provided list of IDs. ```APIDOC ## POST /api/v1/userExample/list/ids ### Description Retrieves a list of user examples based on a provided list of IDs. ### Method POST ### Endpoint /api/v1/userExample/list/ids ### Request Body - **ids** (array of uint64) - Required - A list of unique identifiers for the user examples to retrieve. ### Request Example ```json { "ids": [1, 2, 3] } ``` ### Response #### Success Response (200) - **userExamples** (array of UserExample) - A list of user examples matching the provided IDs. #### Response Example ```json { "userExamples": [ { "id": 1, "name": "John Doe", "email": "john.doe@example.com", "phone": "123-456-7890", "avatar": "http://example.com/avatar.jpg", "age": 30, "gender": 1, "status": 1, "login_at": 1678886400, "created_at": 1678886400, "updated_at": 1678886400 }, { "id": 2, "name": "Jane Smith", "email": "jane.smith@example.com", "phone": "987-654-3210", "avatar": "http://example.com/jane_avatar.jpg", "age": 25, "gender": 2, "status": 1, "login_at": 1678886400, "created_at": 1678886400, "updated_at": 1678886400 } ] } ``` ``` -------------------------------- ### Go WebSocket Client: Default Setup Source: https://github.com/go-dev-frame/sponge/blob/main/pkg/ws/README.md Example of establishing a default WebSocket client connection using the 'ws' library. This client connects to a server, sends messages periodically, and logs received messages. It relies on 'gorilla/websocket'. ```go package main import ( "strconv" "log" "time" "github.com/go-dev-frame/sponge/pkg/ws" "github.com/gorilla/websocket" ) var wsURL = "ws://localhost:8080/ws" func main() { c, err := ws.NewClient(wsURL) // default setting if err != nil { log.Println("connect error:", err) return } defer c.Close() go func() { for { _, message, err := c.GetConn().ReadMessage() if err != nil { log.Println("client read error:", err) return } log.Printf("client received: %s", message) } }() for i := 0; i < 5; i++ { data := "Hello, World " + strconv.Itoa(i) err = c.GetConn().WriteMessage(websocket.TextMessage, []byte(data)) if err != nil { log.Println("write error:", err) } time.Sleep(100 * time.Millisecond) } } ``` -------------------------------- ### Mock Handler Setup and HTTP Test in Go Source: https://github.com/go-dev-frame/sponge/blob/main/pkg/gotest/README.md Demonstrates setting up a mock handler using the gotest library and testing an HTTP GET request. It involves initializing mock cache and DAO layers, configuring routes, and using sqlmock to simulate database responses for the test. ```go package main import ( "net/http" "testing" "time" "github.com/DATA-DOG/go-sqlmock" "github.com/gin-gonic/gin" "github.com/zhufuyi/sponge/pkg/gotest" "github.com/zhufuyi/sponge/pkg/httpcli" ) type User struct { ID uint64 `json:"id"` Name string `json:"name"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` } type Handler struct { TestData interface{}/ ICache interface{}/ IDao interface{}/ IHandler interface{}/ MockDao *gotest.Dao } func (h *Handler) Close() {} func (h *Handler) GoRunHttpServer(routes []gotest.RouterInfo) {} func (h *Handler) GetRequestURL(funcName string, args ...interface{}) string { return "" } func newHandler() *Handler { now := time.Now() testData := &User{ ID: 1, Name: "foo", CreatedAt: now, UpdatedAt: now, } // init mock cache c := gotest.NewCache(map[string]interface{}{"no cache": testData}) c.ICache = struct{}{} // init mock dao d := gotest.NewDao(c, testData) d.IDao = struct{}{} // init mock handler h := gotest.NewHandler(d, testData) h.IHandler = struct{}{} h := newHandler() defer h.Close() h.GoRunHttpServer([]gotest.RouterInfo{ { FuncName: "GetByID", Method: http.MethodGet, Path: "/user/:id", HandlerFunc: func(c *gin.Context) { c.String(http.StatusOK, testData.Name) }, }, }) return h } func TestGetHello(t *testing.T) { h := newHandler() defer h.Close() testData := h.TestData.(*User) rows := sqlmock.NewRows([]string{"id", "created_at", "updated_at"}). AddRow(testData.ID, testData.CreatedAt, testData.UpdatedAt) h.MockDao.SqlMock.ExpectQuery("SELECT .*"). WithArgs(testData.ID). WillReturnRows(rows) result := &httpcli.StdResult{} err := httpcli.Get(result, h.GetRequestURL("GetByID", testData.ID)) if err != nil { t.Fatal(err) } if result.Code != 0 { t.Fatalf("%+v", result) } } ``` -------------------------------- ### Go SSE Server Example Source: https://github.com/go-dev-frame/sponge/blob/main/pkg/sse/README.md Demonstrates how to set up a Go SSE server using the sponge library. It initializes an SSE hub, configures a Gin router for event streams and push endpoints, and simulates event pushing. ```go package main import ( "net/http" "strconv" "time" "math/rand" "github.com/gin-gonic/gin" "github.com/go-dev-frame/sponge/pkg/sse" ) func main() { // Initialize SSE Hub hub := sse.NewHub() defer hub.Close() // Create Gin router r := gin.Default() // SSE Event Stream Interface, requires authentication to set uid r.GET("/events", func(c *gin.Context) { var uid string u, isExists := c.Get("uid") if !isExists { uid = strconv.Itoa(rand.Intn(99) + 100) // mock uid } else { uid, _ = u.(string) } hub.Serve(c, uid) }) // Register event push endpoint, supports pushing to specified users and broadcast pushing // Push to specified users // curl -X POST -H "Content-Type: application/json" -d '{"uids":["u001"],"events":[{"event":"message","data":"hello_world"}]}' http://localhost:8080/push // Broadcast push, not specifying users means pushing to all users // curl -X POST -H "Content-Type: application/json" -d '{"events":[{"event":"message","data":"hello_world"}]}' http://localhost:8080/push r.POST("/push", hub.PushEventHandler()) // simulated event push go func() { i := 0 for { time.Sleep(time.Second * 5) i++ e := &sse.Event{Event: sse.DefaultEventType, Data: "hello_world_" + strconv.Itoa(i)} _ = hub.Push(nil, e) // broadcast push //_ = hub.Push([]string{uid}, e) // specified user push } }() // Start HTTP server if err := http.ListenAndServe(":8080", r); err != nil { panic(err) } } ``` -------------------------------- ### Run Jenkins Server with Docker Compose Source: https://github.com/go-dev-frame/sponge/blob/main/test/server/jenkins/README.md This command starts the Jenkins server in detached mode using Docker Compose. It also provides instructions on how to retrieve the initial admin password for first-time login. ```shell docker-compose up -d docker exec jenkins-go cat /var/jenkins_home/secrets/initialAdminPassword ``` -------------------------------- ### Start Prometheus and Grafana Services Source: https://github.com/go-dev-frame/sponge/blob/main/pkg/grpc/metrics/monitor-example-en.md This snippet demonstrates how to start the Prometheus and Grafana monitoring services using docker-compose. It provides access URLs for both services. ```bash docker-compose up -d ``` -------------------------------- ### Terminate Process by PID in Go Source: https://github.com/go-dev-frame/sponge/blob/main/pkg/process/README.md Demonstrates how to start a process and then terminate it using the `process.Kill` function. This example highlights the graceful shutdown mechanism and the subsequent error from `cmd.Wait()` after the process is killed. It includes OS-specific commands for starting a long-running process. ```go package main import ( "fmt" "log" "os/exec" "runtime" "time" "github.com/go-dev-frame/sponge/pkg/process" ) func main() { var cmd *exec.Cmd // Start a long-running process appropriate for the OS. if runtime.GOOS == "windows" { cmd = exec.Command("timeout", "/t", "30") } else { cmd = exec.Command("sleep", "30") } err := cmd.Start() if err != nil { log.Fatalf("Failed to start command: %v", err) } pid := cmd.Process.Pid fmt.Printf("Started process with PID: %d\n", pid) // Give the process a moment to initialize. time.Sleep(1 * time.Second) fmt.Printf("Attempting to kill process %d...\n", pid) // Use the Kill function to terminate it. if err = process.Kill(pid); err != nil { log.Fatalf("Failed to kill process: %v", err) } fmt.Printf("Successfully terminated process %d.\n", pid) // The cmd.Wait() call will now return an error because the process was killed. err = cmd.Wait() fmt.Printf("Process wait result: %v\n", err) } ``` -------------------------------- ### Basic Gin Reverse Proxy Setup in Go Source: https://github.com/go-dev-frame/sponge/blob/main/pkg/gin/proxy/README.md Demonstrates how to initialize a Gin server and set up a reverse proxy with two distinct routing paths. It configures default settings for the proxy and its initial backend targets. ```go package main import ( "fmt" "github.com/go-dev-frame/sponge/pkg/gin/proxy" "github.com/gin-gonic/gin" ) func main() { r := gin.Default() p := proxy.New(r) // default configuration, managerPrefixPath = "/endpoints" pass1(p) pass2(p) // Other normal routes r.GET("/ping", func(c *gin.Context) { c.JSON(200, gin.H{"message": "pong"}) }) fmt.Println("Gin server with dynamic proxy started on http://localhost:8080") r.Run(":8080") } func pass1(p *proxy.Proxy) { prefixPath := "/proxy/" initialTargets := []string{"http://localhost:8081", "http://localhost:8082"} err := p.Pass(prefixPath, initialTargets) // default configuration, balancer = RoundRobin, healthCheckInterval = 5s, healthCheckTimeout = 3s if err != nil { panic(err) } } func pass2(p *proxy.Proxy) { prefixPath := "/personal/" initialTargets := []string{"http://localhost:8083", "http://localhost:8084"} err := p.Pass(prefixPath, initialTargets) if err != nil { panic(err) } } ``` -------------------------------- ### sgorm Transaction Example Source: https://github.com/go-dev-frame/sponge/blob/main/pkg/sgorm/README.md Illustrates how to perform database transactions using sgorm. It demonstrates starting a transaction, handling potential errors and panics with rollback, and committing the transaction. ```go func createUser() error { // note that you should use tx as the database handle when you are in a transaction tx := db.Begin() defer func() { if err := recover(); err != nil { // rollback after a panic during transaction execution tx.Rollback() fmt.Printf("transaction failed, err = %v\n", err) } }() var err error if err = tx.Error; err != nil { return err } if err = tx.Where("id = ?", 1).First(table).Error; err != nil { tx.Rollback() return err } panic("mock panic") if err = tx.Create(&userExample{Name: "Mr Li", Age: table.Age + 2, Gender: "male"}).Error; err != nil { tx.Rollback() return err } return tx.Commit().Error } ``` -------------------------------- ### Create Kubernetes Docker Registry Secret (Directly) Source: https://github.com/go-dev-frame/sponge/blob/main/test/server/jenkins/README.md This `kubectl` command creates a Kubernetes Secret of type `docker-registry` for authenticating with a Docker registry. This is used by pods to pull images. ```bash kubectl create secret docker-registry docker-auth-secret \ --docker-server=DOCKER_REGISTRY_SERVER \ --docker-username=DOCKER_USER \ --docker-password=DOCKER_PASSWORD \ --docker-email=DOCKER_EMAIL ``` -------------------------------- ### Authorize Private Docker Image Repository Source: https://github.com/go-dev-frame/sponge/blob/main/test/server/jenkins/README.md This command sequence logs the Jenkins container into a private Docker image repository. It requires the repository's IP address or hostname, username, and password. ```bash docker login # account # password ``` -------------------------------- ### Delayed Message Example in Go Source: https://github.com/go-dev-frame/sponge/blob/main/pkg/rabbitmq/README.md Illustrates sending and receiving delayed messages with RabbitMQ using the rabbitmq library in Go. It configures a delayed message exchange and publishes messages scheduled to be delivered after a specified delay. This requires a RabbitMQ setup that supports delayed messages. ```Go func delayedMessageExample(url string) { exchangeName := "delayed-message-exchange-demo" queueName := "delayed-message-queue" routingKey := "delayed-key" exchange := rabbitmq.NewDelayedMessageExchange(exchangeName, rabbitmq.NewDirectExchange("", routingKey)) var queueArgs map[string]interface{} fmt.Printf("\n\n-------------------- delayed message --------------------\n") // producer-side delayed message { connection, err := rabbitmq.NewConnection(url, rabbitmq.WithLogger(logger.Get())) checkErr(err) defer connection.Close() p, err := rabbitmq.NewProducer(exchange, queueName, connection) checkErr(err) defer p.Close() queueArgs = p.QueueArgs() ctx := context.Background() datetimeLayout := "2006-01-02 15:04:05.000" for i := 1; i <= 100; i++ { err = p.PublishDelayedMessage(ctx, time.Second*3, []byte("[delayed] message "+strconv.Itoa(i)+" at "+time.Now().Format(datetimeLayout))) checkErr(err) atomic.AddInt32(&producerCount, 1) } } // consumer-side delayed message { c := runConsume(url, exchange, queueName, queueArgs) <-time.After(time.Second * 5) atomic.AddInt32(&consumerCount, int32(c.Count())) } printStat() } ``` -------------------------------- ### Start Standard HTTP Server in Go Source: https://github.com/go-dev-frame/sponge/blob/main/pkg/httpsrv/README.md This Go code snippet demonstrates how to start a basic HTTP server using the `httpsrv` library. It requires no TLS configuration and is suitable for simple web services. The code sets up an HTTP Mux, defines a handler for the root path, configures the `http.Server`, and then runs it using `httpsrv.New`. ```go package main import ( "fmt" "net/http" "github.com/go-dev-frame/sponge/pkg/httpsrv" ) func main() { // Create an HTTP Mux mux := http.NewServeMux() mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { fmt.Fprintln(w, "Hello, HTTP World!") }) // Configure http.Server httpServer := &http.Server{ Addr: ":8080", Handler: mux, } // Create and run the service fmt.Println("HTTP server listening on :8080") server := httpsrv.New(httpServer) if err := server.Run(); err != nil { fmt.Printf("Server error: %v\n", err) } } ``` -------------------------------- ### gRPC Client Recovery Interceptor Example Source: https://github.com/go-dev-frame/sponge/blob/main/pkg/grpc/interceptor/README.md Illustrates the setup for a unary client recovery interceptor. This interceptor is designed to catch and handle panics that might occur during the client-side gRPC call execution, ensuring client stability. ```go import ( "github.com/go-dev-frame/sponge/pkg/grpc/interceptor" "google.golang.org/grpc" ) func setDialOptions() []grpc.DialOption { var options []grpc.DialOption option := grpc.WithChainUnaryInterceptor( interceptor.UnaryClientRecovery(), ) options = append(options, option) return options } ``` -------------------------------- ### Serve Static Files with Gin using StaticFS Source: https://github.com/go-dev-frame/sponge/blob/main/pkg/gin/staticfs/README.md This example demonstrates how to use StaticFS to serve static files from a local directory under a specific URL prefix in a Gin application. It maps a URL path (e.g., '/user/') to a local file system directory (e.g., '/var/www/dist'). ```go package main import ( "log" "github.com/gin-gonic/gin" "github.com/go-dev-frame/sponge/pkg/gin/staticfs" ) func main() { r := gin.Default() // Maps the URL prefix /user/ to the local /var/www/dist/index.html staticfs.StaticFS(r, "/user/", "/var/www/dist") log.Println("Server is running on http://localhost:8080") log.Println("Access static files at http://localhost:8080/user/") r.Run(":8080") } ``` -------------------------------- ### Start and Stop Services Gracefully in Go Source: https://github.com/go-dev-frame/sponge/blob/main/pkg/app/README.md This Go code snippet demonstrates how to initialize and run multiple services concurrently using the app package. It utilizes errgroup for managing service lifecycles and includes examples for creating HTTP servers and defining cleanup functions. ```go import "github.com/go-dev-frame/sponge/pkg/app" func main() { initApp() services := CreateServices() closes := Close(services) a := app.New(services, closes) a.Run() } func initApp() { // get configuration // initializing log // initializing database // ...... } func CreateServices() []app.IServer { var servers []app.IServer // create an HTTP service httpAddr := ":8080" // or get from configuration httpServer := server.NewHTTPServer( httpAddr, server.WithHTTPIsProd(true), // run in release mode ) servers = append(servers, httpServer) // create a gRPC service (optional) // grpcServer := server.NewGRPCServer( // // ) // servers = append(servers, grpcServer) return servers } func Close(servers []app.IServer) []app.Close { var closes []app.Close // close servers for _, s := range servers { closes = append(closes, s.Stop) } // close other resources (database, logger, tracing, etc.) closes = append(closes, func() error { // TODO: call db.Close() return nil }) return closes } ``` -------------------------------- ### Publisher Subscriber Example in Go Source: https://github.com/go-dev-frame/sponge/blob/main/pkg/rabbitmq/README.md Demonstrates the publisher-subscriber pattern using RabbitMQ in Go. It sets up a fanout exchange where messages published to the exchange are delivered to all bound queues. Multiple subscribers listen to the same channel, receiving copies of the published messages. ```Go func publisherSubscriberExample(url string) { channelName := "pub-sub" fmt.Printf("\n\n-------------------- publisher subscriber --------------------\n") // publisher-side message { connection, err := rabbitmq.NewConnection(url, rabbitmq.WithLogger(logger.Get())) checkErr(err) defer connection.Close() p, err := rabbitmq.NewPublisher(channelName, connection) checkErr(err) defer p.Close() for i := 1; i <= 100; i++ { err = p.Publish(context.Background(), []byte("[pub-sub] message "+strconv.Itoa(i))) checkErr(err) atomic.AddInt32(&producerCount, 1) } } // subscriber-side message { identifier := "pub-sub-queue-1" s1 := runSubscriber(url, channelName, identifier) identifier = "pub-sub-queue-2" s2 := runSubscriber(url, channelName, identifier) <-time.After(time.Second * 5) atomic.AddInt32(&consumerCount, int32(s1.Count())) fmt.Println("\n\nsubscriber 2 count:", s2.Count()) } printStat() } ``` -------------------------------- ### gRPC Client Logging Interceptor Example Source: https://github.com/go-dev-frame/sponge/blob/main/pkg/grpc/interceptor/README.md Shows how to configure a unary client logging interceptor for gRPC communications. This setup uses the sponge interceptor package and supports options like replacing the gRPC logger for consistent logging across the application. ```go import ( "github.com/go-dev-frame/sponge/pkg/grpc/interceptor" "google.golang.org/grpc" ) func setDialOptions() []grpc.DialOption { var options []grpc.DialOption option := grpc.WithChainUnaryInterceptor( interceptor.UnaryClientLog( // set unary client logging logger.Get(), interceptor.WithReplaceGRPCLogger(), ), ) options = append(options, option) return options } // you can also set stream client logging ``` -------------------------------- ### Test Cache Operations with Gotest in Go Source: https://github.com/go-dev-frame/sponge/blob/main/pkg/gotest/README.md Provides example test functions for cache operations using the gotest library. It demonstrates how to set up a mock Redis cache, populate it with test data, and then test the Set and Get methods of the UserExampleCache interface. ```go package main import ( "testing" "time" "github.com/stretchr/testify/assert" "github.com/zhufuyi/sponge/pkg/gotest" "github.com/zhufuyi/sponge/pkg/model" ) func newUserExampleCache() *gotest.RedisCache { testData := map[string]interface{}{ "1": &model.UserExample{ID: 1}, } rc := gotest.NewRedisCache(testData) rc.ICache = NewUserExampleCache(rc.RedisClient) return rc } func Test_userExampleCache_Set(t *testing.T) { c := newUserExampleCache() defer c.Close() record := c.TestDataSlice[0].(*model.UserExample) err := c.ICache.(UserExampleCache).Set(c.Ctx, record.ID, record, time.Hour) if err != nil { t.Fatal(err) } } func Test_userExampleCache_Get(t *testing.T) { c := newUserExampleCache() defer c.Close() record := c.TestDataSlice[0].(*model.UserExample) err := c.ICache.(UserExampleCache).Set(c.Ctx, record.ID, record, time.Hour) if err != nil { t.Fatal(err) } got, err := c.ICache.(UserExampleCache).Get(c.Ctx, record.ID) if err != nil { t.Fatal(err) } assert.Equal(t, record, got) } ``` -------------------------------- ### Generate Swagger Docs with Swag CLI Source: https://github.com/go-dev-frame/sponge/blob/main/pkg/gin/swagger/README.md This section provides the command-line instructions to install the Swag CLI and generate API documentation from Go annotations. The `swag init` command scans your project for Swagger annotations and creates the necessary documentation files. This is a prerequisite for using the Gin Swagger integration. ```bash go install github.com/swaggo/swag/cmd/swag@latest swag init ``` -------------------------------- ### Configure Pod to Use Image Pull Secret Source: https://github.com/go-dev-frame/sponge/blob/main/test/server/jenkins/README.md This YAML snippet shows how to configure a Kubernetes Pod's `spec` to use an `imagePullSecret` named 'docker-auth-secret'. This allows the pod to pull images from private registries authenticated by the specified secret. ```yaml # ...... spec: containers: - name: server-name-example image: project-name-example/server-name-example:latest # ...... imagePullSecrets: - name: docker-auth-secret ``` -------------------------------- ### Go Consumer Example: Registering Task Handlers Source: https://github.com/go-dev-frame/sponge/blob/main/pkg/sasynq/README.md This Go code demonstrates how to set up a sasynq consumer server and register task handlers. It shows three methods for registration: using RegisterTaskHandler with HandleFunc, registering a struct as a payload, and registering a function directly. The consumer requires Redis configuration and uses a logger. ```go package main import ( "github.com/go-dev-frame/sponge/pkg/sasynq" "github.com/go-dev-frame/sponge/pkg/logger" "example/common" ) func runConsumer(redisCfg sasynq.RedisConfig) (*sasynq.Server, error) { serverCfg := sasynq.DefaultServerConfig(sasynq.WithLogger(logger.Get())) // Uses critical, default, and low queues by default srv := sasynq.NewServer(redisCfg, serverCfg) // Attach logging middleware srv.Use(sasynq.LoggingMiddleware(sasynq.WithLogger(logger.Get()))) // Register task handlers (three methods available): sasynq.RegisterTaskHandler(srv.Mux(), common.TypeEmailSend, sasynq.HandleFunc(common.HandleEmailTask)) // Method 1 (recommended) srv.Register(common.TypeSMSSend, &common.SMSPayload{}) // Method 2: register struct as payload srv.RegisterFunc(common.TypeMsgNotification, common.HandleMsgNotificationTask) // Method 3: register function directly sasynq.RegisterTaskHandler(srv.Mux(), common.TypeUniqueEmailSend, sasynq.HandleFunc(common.HandleEmailTask)) srv.Run() return srv, nil } func main() { cfg := sasynq.RedisConfig{ Addr: "localhost:6379", } srv, err := runConsumer(cfg) if err != nil { panic(err) } srv.WaitShutdown() } ```