chore: 初始开源发布
iotlcm-upstream-proxy:渠道缓存与转发网关。 - 内联原私有依赖:yunze-public → internal/pub/(18 文件), yunze-pb/pb → internal/pb/(9 文件);Consul 注册改用官方 gogf/gf/contrib/registry/consul/v2(API 兼容) - Go module:yz-svr → git.5iot.com/iotlcm-public/iotlcm-upstream-proxy - 凭据与内部标识脱敏:MySQL/Redis/Consul 凭据、私网与生产 IP、内网域名 - 移除内部资产:CI 触发器 - Dockerfile 改用公共基础镜像,移除写死的 registry 凭据 - 补 Apache-2.0 LICENSE,重写 README,LF 行尾 + .gitattributes
This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
package httpclient
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/pub/xjpubservice"
|
||||
|
||||
"github.com/gogf/gf/v2/encoding/gjson"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/net/gclient"
|
||||
"github.com/gogf/gf/v2/net/gsvc"
|
||||
)
|
||||
|
||||
type sHttpClient struct {
|
||||
client *gclient.Client
|
||||
}
|
||||
|
||||
func NewHttpClient() *sHttpClient {
|
||||
client := g.Client()
|
||||
return &sHttpClient{
|
||||
client: client,
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
xjpubservice.RegisterHttpClient(NewHttpClient())
|
||||
}
|
||||
|
||||
func (s *sHttpClient) PostObj(ctx context.Context, serviceName string, path string, req interface{}, res interface{}) (err error) {
|
||||
reqJson, err := gjson.Marshal(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
resJson, err := s.Post(ctx, serviceName, path, reqJson)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = gjson.Unmarshal(resJson, res)
|
||||
if err != nil {
|
||||
g.Log().Errorf(ctx, "sHttpClient.PostObj gjson.Unmarshal error: %v, resJson: %s", err, string(resJson))
|
||||
return err
|
||||
}
|
||||
g.Log().Debugf(ctx, "sHttpClient.PostObj res: %+v, resJson: %s", res, string(resJson))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *sHttpClient) Post(ctx context.Context, serviceName string, path string, req []byte) (res []byte, err error) {
|
||||
// s.client.SetHeader("Span-Id", "0.0.1")
|
||||
// s.client.SetHeader("Trace-Id", gctx.CtxId(ctx))
|
||||
|
||||
url := "http://" + serviceName + path
|
||||
s.client.SetDiscovery(gsvc.GetRegistry())
|
||||
// g.Log().Debugf(ctx, "sHttpClient.Post url: %s, req: %+v", url, string(req))
|
||||
response, err := s.client.Post(ctx, url, req)
|
||||
if err != nil {
|
||||
g.Log().Errorf(ctx, "sHttpClient.Post Post error: %v, url: %s, req: %+v", err, url, string(req))
|
||||
return nil, err
|
||||
}
|
||||
defer response.Close()
|
||||
res = response.ReadAll()
|
||||
g.Log().Debugf(ctx, "sHttpClient.Post url: %s, req: %+v, res: %+v", url, string(req), string(res))
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (s *sHttpClient) AllServerPost(ctx context.Context, serviceName string, path string, req []byte) (resMap map[string][]byte, err error) {
|
||||
// s.client.SetHeader("Span-Id", "0.0.1")
|
||||
// s.client.SetHeader("Trace-Id", gctx.CtxId(ctx))
|
||||
s.client.SetDiscovery(gsvc.GetRegistry())
|
||||
|
||||
servers, err := gsvc.Search(ctx, gsvc.SearchInput{
|
||||
Name: serviceName,
|
||||
})
|
||||
if len(servers) == 0 {
|
||||
g.Log().Errorf(ctx, "sHttpClient.AllServerPost gsvc.Search(ctx, serviceName) error: %v, serviceName: %s", err, serviceName)
|
||||
return nil, err
|
||||
}
|
||||
// g.Log().Debugf(ctx, "sHttpClient.AllServerPost servers: %+v", servers)
|
||||
endpoints := make([]string, 0)
|
||||
for _, server := range servers {
|
||||
endpoint := server.GetEndpoints()
|
||||
if len(endpoint) == 0 {
|
||||
g.Log().Errorf(ctx, "sHttpClient.AllServerPost server.GetEndpoints() error: %v, serviceName: %s", err, serviceName)
|
||||
continue
|
||||
}
|
||||
endpoints = append(endpoints, endpoint[0].String())
|
||||
}
|
||||
resMap = make(map[string][]byte)
|
||||
for _, e := range endpoints {
|
||||
url := "http://" + e + path
|
||||
res, err := s.Post(ctx, e, path, req)
|
||||
// g.Log().Debugf(ctx, "sHttpClient.AllServerPost Post url: %s, req: %+v res: %+v err: %+v", url, string(req), string(res), err)
|
||||
if err != nil {
|
||||
resMap[e] = nil
|
||||
g.Log().Errorf(ctx, "sHttpClient.AllServerPost Post error: %v, url: %s, req: %+v", err, url, string(req))
|
||||
continue
|
||||
}
|
||||
resMap[e] = res
|
||||
}
|
||||
return resMap, nil
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package httpclient
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/pub/xjpubconsts"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/pub/xjpubmodel"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/pub/xjpubmodel/response"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/pub/xjpubservice"
|
||||
)
|
||||
|
||||
type sUpstreamProxyClient struct {
|
||||
}
|
||||
|
||||
func NewUpstreamProxyClient() *sUpstreamProxyClient {
|
||||
return &sUpstreamProxyClient{}
|
||||
}
|
||||
|
||||
func init() {
|
||||
xjpubservice.RegisterUpstreamProxyClient(NewUpstreamProxyClient())
|
||||
}
|
||||
|
||||
// 物联网卡在线信息实时查询
|
||||
func (s *sUpstreamProxyClient) QuerySimSession(ctx context.Context, input *xjpubmodel.SimSessionInput) (output *xjpubmodel.SimSessionOutput, err error) {
|
||||
res := &response.ResponseGeneric[*xjpubmodel.SimSessionOutput]{}
|
||||
err = xjpubservice.HttpClient().PostObj(ctx, xjpubconsts.ServiceNameYzUpstreamChanSvc, "/query/sim-session", input, res)
|
||||
output = res.Data
|
||||
return output, err
|
||||
}
|
||||
|
||||
// 物联网卡卡状态查询
|
||||
func (s *sUpstreamProxyClient) QuerySimCardStatus(ctx context.Context, input *xjpubmodel.SimCardStatusInput) (output *xjpubmodel.SimCardStatusOutput, err error) {
|
||||
res := &response.ResponseGeneric[*xjpubmodel.SimCardStatusOutput]{}
|
||||
err = xjpubservice.HttpClient().PostObj(ctx, xjpubconsts.ServiceNameYzUpstreamChanSvc, "/query/sim-status", input, res)
|
||||
output = res.Data
|
||||
return output, err
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package info
|
||||
|
||||
import (
|
||||
"git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/pub/xjpubmodel"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/pub/xjpubservice"
|
||||
)
|
||||
|
||||
type sInfo struct {
|
||||
Info xjpubmodel.InfoModel
|
||||
}
|
||||
|
||||
func NewInfo() *sInfo {
|
||||
return &sInfo{
|
||||
Info: xjpubmodel.InfoModel{},
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
xjpubservice.RegisterInfo(NewInfo())
|
||||
}
|
||||
|
||||
func (s *sInfo) GetInfo() *xjpubmodel.InfoModel {
|
||||
return &s.Info
|
||||
}
|
||||
|
||||
func (s *sInfo) SetInfoName(Type, Name, Title, Description string) {
|
||||
if s.Info.Name == "" {
|
||||
s.Info.Type = Type
|
||||
s.Info.Name = Name
|
||||
s.Info.Title = Title
|
||||
s.Info.Description = Description
|
||||
}
|
||||
}
|
||||
|
||||
func (s *sInfo) SetInfoBuild(buildVersion, buildTime, commitID string) {
|
||||
s.Info.Version = buildVersion
|
||||
s.Info.Build = buildTime
|
||||
s.Info.Commit = commitID
|
||||
}
|
||||
|
||||
func (s *sInfo) SetInfoData(data map[string]interface{}) {
|
||||
s.Info.Data = data
|
||||
}
|
||||
|
||||
func (s *sInfo) GetInfoData() map[string]interface{} {
|
||||
return s.Info.Data
|
||||
}
|
||||
|
||||
func (s *sInfo) AddInfoData(key string, value interface{}) {
|
||||
if s.Info.Data == nil {
|
||||
s.Info.Data = make(map[string]interface{})
|
||||
}
|
||||
s.Info.Data[key] = value
|
||||
}
|
||||
|
||||
func (s *sInfo) DelInfoData(key string) {
|
||||
delete(s.Info.Data, key)
|
||||
}
|
||||
|
||||
func (s *sInfo) GetInfoDataByKey(key string) interface{} {
|
||||
if s.Info.Data == nil {
|
||||
return nil
|
||||
}
|
||||
if _, ok := s.Info.Data[key]; !ok {
|
||||
return nil
|
||||
}
|
||||
return s.Info.Data[key]
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
package info
|
||||
|
||||
import (
|
||||
"context"
|
||||
"runtime"
|
||||
|
||||
"git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/pub/xjpubmodel"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/pub/xjpubservice"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/glog"
|
||||
)
|
||||
|
||||
type sInfoRpc struct {
|
||||
Info *xjpubmodel.InfoModel
|
||||
}
|
||||
|
||||
func NewInfoRpc() *sInfoRpc {
|
||||
return &sInfoRpc{
|
||||
Info: xjpubmodel.NewInfoModel(),
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
xjpubservice.RegisterInfoRpc(NewInfoRpc())
|
||||
}
|
||||
|
||||
func (s *sInfoRpc) GetInfo() *xjpubmodel.InfoModel {
|
||||
ctx := context.Background()
|
||||
logLevel := g.Cfg().MustGet(ctx, "logger.level", "").String()
|
||||
if logLevel != "" {
|
||||
g.Log().SetLevelStr(logLevel)
|
||||
}
|
||||
s.AddInfoData("log_level_conf", logLevel)
|
||||
s.AddInfoData("log_level_real", toLogLevelStr(g.Log().GetLevel()))
|
||||
s.AddInfoData("Goroutines", runtime.NumGoroutine())
|
||||
var m runtime.MemStats
|
||||
runtime.ReadMemStats(&m)
|
||||
s.AddInfoData("MemAllocKB", m.Alloc/1024)
|
||||
s.AddInfoData("MemTotalAllocKB", m.TotalAlloc/1024)
|
||||
s.AddInfoData("MemSysKB", m.Sys/1024)
|
||||
s.AddInfoData("MemHeapAllocKB", m.HeapAlloc/1024)
|
||||
s.AddInfoData("MemHeapSysKB", m.HeapSys/1024)
|
||||
s.AddInfoData("MemHeapIdleKB", m.HeapIdle/1024)
|
||||
s.AddInfoData("MemHeapInuseKB", m.HeapInuse/1024)
|
||||
s.AddInfoData("MemHeapReleasedKB", m.HeapReleased/1024)
|
||||
s.AddInfoData("MemHeapObjects", m.HeapObjects)
|
||||
s.AddInfoData("MemStackInuseKB", m.StackInuse/1024)
|
||||
s.AddInfoData("MemStackSysKB", m.StackSys/1024)
|
||||
s.AddInfoData("MemNumGC", m.NumGC)
|
||||
return s.Info
|
||||
}
|
||||
|
||||
func toLogLevelStr(level int) string {
|
||||
if level == glog.LEVEL_NONE {
|
||||
return "NONE"
|
||||
}
|
||||
if level == glog.LEVEL_ALL {
|
||||
return "ALL"
|
||||
}
|
||||
if level == glog.LEVEL_DEV {
|
||||
return "DEV"
|
||||
}
|
||||
if level == glog.LEVEL_PROD {
|
||||
return "PROD"
|
||||
}
|
||||
str := ""
|
||||
if level&glog.LEVEL_DEBU != 0 {
|
||||
str += "DEBUG "
|
||||
}
|
||||
if level&glog.LEVEL_INFO != 0 {
|
||||
str += "INFO "
|
||||
}
|
||||
if level&glog.LEVEL_NOTI != 0 {
|
||||
str += "NOTI "
|
||||
}
|
||||
if level&glog.LEVEL_WARN != 0 {
|
||||
str += "WARN "
|
||||
}
|
||||
if level&glog.LEVEL_ERRO != 0 {
|
||||
str += "ERRO "
|
||||
}
|
||||
if level&glog.LEVEL_CRIT != 0 {
|
||||
str += "CRIT "
|
||||
}
|
||||
if level&glog.LEVEL_PANI != 0 {
|
||||
str += "PANI "
|
||||
}
|
||||
if level&glog.LEVEL_FATA != 0 {
|
||||
str += "FATA "
|
||||
}
|
||||
return str
|
||||
}
|
||||
|
||||
func (s *sInfoRpc) SetInfoName(Type, Name, Title, Description string) {
|
||||
if s.Info.Name == "" {
|
||||
s.Info.Type = Type
|
||||
s.Info.Name = Name
|
||||
s.Info.Title = Title
|
||||
s.Info.Description = Description
|
||||
}
|
||||
}
|
||||
|
||||
func (s *sInfoRpc) SetInfoBuild(buildVersion, buildTime, commitID string) {
|
||||
s.Info.Version = buildVersion
|
||||
s.Info.Build = buildTime
|
||||
s.Info.Commit = commitID
|
||||
}
|
||||
|
||||
func (s *sInfoRpc) SetInfoData(data map[string]interface{}) {
|
||||
s.Info.Data = data
|
||||
}
|
||||
|
||||
func (s *sInfoRpc) GetInfoData() map[string]interface{} {
|
||||
return s.Info.Data
|
||||
}
|
||||
|
||||
func (s *sInfoRpc) AddInfoData(key string, value interface{}) {
|
||||
s.Info.Data[key] = value
|
||||
}
|
||||
|
||||
func (s *sInfoRpc) DelInfoData(key string) {
|
||||
delete(s.Info.Data, key)
|
||||
}
|
||||
|
||||
func (s *sInfoRpc) GetInfoDataByKey(key string) interface{} {
|
||||
return s.Info.Data[key]
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
// package middleware
|
||||
// @Link https://github.com/xiujiecn/xiu-admin
|
||||
// @Copyright Copyright (c) 2025 LiXiujie
|
||||
// @Author Lxj <li@xiujie.cn>
|
||||
// @License https://github.com/xiujiecn/xiu-admin/blob/master/LICENSE
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"slices"
|
||||
|
||||
"github.com/gogf/gf/v2/errors/gcode"
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/net/ghttp"
|
||||
"github.com/gogf/gf/v2/util/gmeta"
|
||||
|
||||
"git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/pub/xjpubconsts"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/pub/xjpubmodel/response"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/pub/xjpubservice"
|
||||
)
|
||||
|
||||
type sMiddleware struct {
|
||||
}
|
||||
|
||||
func New() *sMiddleware {
|
||||
return &sMiddleware{}
|
||||
}
|
||||
|
||||
func init() {
|
||||
xjpubservice.RegisterMiddleware(New())
|
||||
}
|
||||
|
||||
func getContentType(r *ghttp.Request) (contentType string) {
|
||||
contentType = r.Response.Header().Get("Content-Type")
|
||||
if contentType != "" {
|
||||
return
|
||||
}
|
||||
|
||||
mime := gmeta.Get(r.GetHandlerResponse(), "mime").String()
|
||||
if mime == "" {
|
||||
contentType = xjpubconsts.HTTPContentTypeJson
|
||||
} else {
|
||||
contentType = mime
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 响应处理中间件
|
||||
func (m *sMiddleware) ResponseHandler(r *ghttp.Request) {
|
||||
r.Middleware.Next()
|
||||
if r.Response.BufferLength() > 0 {
|
||||
return
|
||||
}
|
||||
|
||||
contentType := getContentType(r)
|
||||
if contentType == xjpubconsts.HTTPContentTypeExcel {
|
||||
r.Response.Status = http.StatusOK
|
||||
return
|
||||
}
|
||||
// g.Log().Infof(r.GetCtx(), "sMiddleware.ResponseHandler,contentType %v", contentType)
|
||||
err := r.GetError()
|
||||
res := r.GetHandlerResponse()
|
||||
var code gcode.Code = gcode.CodeOK
|
||||
|
||||
if err != nil {
|
||||
code = gerror.Code(err)
|
||||
if code == gcode.CodeNil {
|
||||
code = gcode.CodeInternalError
|
||||
}
|
||||
response.JsonExit(r, code.Code(), err.Error())
|
||||
} else {
|
||||
response.Json(r, code.Code(), "", res)
|
||||
}
|
||||
}
|
||||
|
||||
// CORS 跨域处理
|
||||
func (s *sMiddleware) CORS(r *ghttp.Request) {
|
||||
r.SetCtx(r.GetNeverDoneCtx())
|
||||
|
||||
corsOptions := r.Response.DefaultCORSOptions()
|
||||
corsConfig := g.Cfg().MustGet(context.Background(), "server.allowedDomains").Strings()
|
||||
if len(corsConfig) == 0 {
|
||||
r.Response.CORSDefault()
|
||||
} else {
|
||||
corsOptions.AllowDomain = corsConfig
|
||||
r.Response.CORS(corsOptions)
|
||||
}
|
||||
r.Middleware.Next()
|
||||
}
|
||||
|
||||
// IsExceptLogin 判断是否需要验证登录
|
||||
func (s *sMiddleware) IsExceptLogin(ctx context.Context, path string) bool {
|
||||
pathList := g.Cfg().MustGet(ctx, "router.exceptLogin").Strings()
|
||||
return slices.Contains(pathList, path)
|
||||
}
|
||||
|
||||
// ResponseHandlerRaw 返回处理中间件
|
||||
func (s *sMiddleware) ResponseHandlerRaw(r *ghttp.Request) {
|
||||
r.Middleware.Next()
|
||||
// 如果已经有返回内容,那么该中间件什么也不做
|
||||
if r.Response.BufferLength() > 0 {
|
||||
g.Log().Infof(r.Context(), "ResponseHandler r.Response.BufferLength() %d buf:%s", r.Response.BufferLength(), r.Response.BufferString())
|
||||
return
|
||||
}
|
||||
|
||||
var (
|
||||
err = r.GetError()
|
||||
res = r.GetHandlerResponse()
|
||||
)
|
||||
if err != nil {
|
||||
r.Response.WriteJson(res)
|
||||
r.ExitAll()
|
||||
} else {
|
||||
r.Response.WriteJson(res)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
// ==========================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
||||
// ==========================================================================
|
||||
|
||||
package xjpublogic
|
||||
|
||||
import (
|
||||
_ "git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/pub/xjpublogic/httpclient"
|
||||
_ "git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/pub/xjpublogic/info"
|
||||
_ "git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/pub/xjpublogic/middleware"
|
||||
)
|
||||
Reference in New Issue
Block a user