Servers
Overview
Fountain provides multi-protocol server implementations under libs/fnet. Each server implements the AppInstance lifecycle (Initialize / Serving / Destroy) and is wired into the framework with fountain.New().WithAppInstances(...).
Available servers:
fhttp— HTTP server built on Fiber, with routing, middleware, and optional payload encryption.fgrpc— gRPC server with interceptors, metadata, and service discovery integration.ftcp— raw and wrapped TCP servers.fudp— UDP server.fquic— QUIC server with streams and datagrams.
Example
A gRPC server instance:
go
/* !!
* File: server.go
* File Created: Monday, 6th June 2022 10:07:23 am
* Author: Kim Ericko ([email protected])
* -----
* Last Modified: Monday, 6th June 2022 10:07:23 am
* Modified By: Kim Ericko ([email protected])
* -----
* Copyright 2022 Soludian, soludian.com
* All rights reserved.
*
* Licensed under the SOLUDIAN TECHNOLOGY SOLUTION CO., LTD Software License Agreement.
* Unauthorized use, reproduction, or distribution is prohibited (the "License");
*
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* [email protected] / https://www.soludian.com/license
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* -----
*
* HISTORY:
*
* Date By Comments
* ---------- --- ---------------------------------------------------------
*/
package main
import (
"context"
"fmt"
"log"
"net"
"gitlab.soludian.com/soludian/fountain/examples/grpc/chat"
"google.golang.org/grpc"
)
func main() {
fmt.Println("Go gRPC Beginners Tutorial!")
lis, err := net.Listen("tcp", fmt.Sprintf(":%d", 9000))
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
s := &ChatService{}
grpcServer := grpc.NewServer()
chat.RegisterChatServiceServer(grpcServer, s)
if err := grpcServer.Serve(lis); err != nil {
log.Fatalf("failed to serve: %s", err)
}
}
type ChatService struct {
chat.UnimplementedChatServiceServer
}
func (s *ChatService) SayHello(ctx context.Context, req *chat.Message) (*chat.Message, error) {
log.Printf("Receive message body from client: %s", req.Body)
return &chat.Message{Body: "Hello From the Server!"}, nil
}An HTTP server with payload encryption:
go
/* !!
* File: main.go
* File Created: Friday, 28th October 2022 5:19:38 pm
* Author: Kim Ericko ([email protected])
* -----
* Last Modified: Wednesday, 8th March 2023 4:40:18 pm
* Modified By: Kim Ericko ([email protected])
* -----
* Copyright 2022 Soludian, soludian.com
* All rights reserved.
*
* Licensed under the SOLUDIAN TECHNOLOGY SOLUTION CO., LTD Software License Agreement.
* Unauthorized use, reproduction, or distribution is prohibited (the "License");
*
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* [email protected] / https://www.soludian.com/license
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* -----
*
* HISTORY:
*
* Date By Comments
* ---------- --- ---------------------------------------------------------
*/
package main
import (
"fmt"
"log"
"time"
"github.com/gofiber/fiber/v3"
"gitlab.soludian.com/soludian/fountain"
"gitlab.soludian.com/soludian/fountain/biz/core"
"gitlab.soludian.com/soludian/fountain/libs/base/lib_3rd"
"gitlab.soludian.com/soludian/fountain/libs/crypto"
"gitlab.soludian.com/soludian/fountain/libs/flog"
"gitlab.soludian.com/soludian/fountain/libs/fnet/fhttp"
)
var logger = flog.NewFountainLoggerOnce()
type NoModule struct {
}
func (NoModule) Liveness() bool {
return true
}
func (NoModule) Readiness() bool {
return false
}
type APIServer struct {
*fhttp.Server
}
func (s *APIServer) Initialize() error {
s.Server = fhttp.WithConfigKey("server.fhttp").InstallFountainInstance()
core.InstallCoreControllers()
cr := crypto.InstallFountainInstances()
log.Printf("Initializing: %+v", cr.GetFountainInstanceNames())
s.Server.Get("/panic", func(ctx fiber.Ctx) error {
err := fmt.Errorf("route panic")
logger.WErr(err).Panicf(err.Error())
return err
})
s.Server.Get("/200", func(ctx fiber.Ctx) error {
return ctx.SendString("hello")
})
s.Server.Get("/hello", func(ctx fiber.Ctx) error {
logger.Infof(ctx.Route().Path)
return ctx.JSON("Hello client: " + ctx.Get("app"))
})
s.Server.Get("/encrypt", func(ctx fiber.Ctx) error {
logger.Infof(ctx.Route().Path)
return fhttp.WithContext(ctx).WithEncryption().WithStatus(200).WriteSuccess("Hello client: " + ctx.Get("app"))
})
s.Server.Get("/encrypt-cbc", func(ctx fiber.Ctx) error {
data := make(map[string]any)
data["server"] = "encrypt-cbc"
data["time"] = time.Now().String()
logger.Infof(ctx.Route().Path)
return fhttp.WithContext(ctx).WithEncryptionFunc(crypto.GetFountainInstance("AES-CBC")).WithStatus(200).WriteSuccess(data)
})
s.Server.Get("/encrypt-ctr", func(ctx fiber.Ctx) error {
data := make(map[string]any)
data["server"] = "encrypt-ctr"
data["time"] = time.Now().String()
logger.Infof(ctx.Route().Path)
return fhttp.WithContext(ctx).WithEncryptionFunc(crypto.GetFountainInstance("AES-CTR")).WithStatus(200).WriteSuccess(data)
})
s.Server.Get("/500", func(ctx fiber.Ctx) error {
return ctx.Status(500).JSON("Hello client: " + ctx.Get("app"))
})
lib_3rd.RegisterHealthCheck("NoModule", &NoModule{})
s.Server.InitHealthCheckPath("/")
return nil
}
func main() {
server := &APIServer{}
fountain.WithAppInstances(server).Serving()
}