1
0
mirror of https://github.com/go-micro/go-micro.git synced 2025-08-10 21:52:01 +02:00

remove dashboard

This commit is contained in:
Asim Aslam
2022-04-07 11:45:58 +01:00
parent 27b98c450e
commit efa2c4f2d2
34 changed files with 0 additions and 2906 deletions

View File

@@ -1,21 +0,0 @@
# Go Micro Dashboard
## Installation
```
go install github.com/asim/go-micro/cmd/dashboard/v4@latest
```
## Usage
```
dashboard --registry etcd --server_address :4000
```
## Docker
```
docker run -d --name micro-dashboard -p 8082:8082 xpunch/go-micro-dashboard:latest
```
Visit: [http://localhost:4000](http://localhost:4000)(deafult admin@micro)

View File

@@ -1,42 +0,0 @@
package config
import "time"
const (
Name = "go.micro.dashboard"
Version = "1.2.0"
)
type Config struct {
Server ServerConfig
}
type ServerConfig struct {
Address string
Auth AuthConfig
CORS CORSConfig
}
type AuthConfig struct {
Username string
Password string
TokenSecret string
TokenExpiration time.Duration
}
type CORSConfig struct {
Enable bool `toml:"enable"`
Origin string `toml:"origin"`
}
func GetConfig() Config {
return *_cfg
}
func GetServerConfig() ServerConfig {
return _cfg.Server
}
func GetAuthConfig() AuthConfig {
return _cfg.Server.Auth
}

View File

@@ -1,88 +0,0 @@
package config
import (
"os"
"strings"
"time"
"github.com/asim/go-micro/cmd/dashboard/v4/util"
"github.com/asim/go-micro/plugins/config/encoder/toml/v4"
"github.com/asim/go-micro/plugins/config/encoder/yaml/v4"
"github.com/pkg/errors"
"go-micro.dev/v4/config"
"go-micro.dev/v4/config/reader"
"go-micro.dev/v4/config/reader/json"
"go-micro.dev/v4/config/source/env"
"go-micro.dev/v4/config/source/file"
"go-micro.dev/v4/logger"
)
// internal instance of Config
var _cfg *Config = &Config{
Server: ServerConfig{
Address: ":8082",
Auth: AuthConfig{
Username: "admin",
Password: "micro",
TokenSecret: "modifyme",
TokenExpiration: 24 * time.Hour,
},
},
}
// Load will load configurations and update it when changed
func Load() error {
var configor config.Config
var err error
switch strings.ToLower(os.Getenv("CONFIG_TYPE")) {
case "toml":
filename := "config.toml"
if name := os.Getenv("CONFIG_FILE"); len(name) > 0 {
filename = name
}
configor, err = config.NewConfig(
config.WithSource(file.NewSource(file.WithPath(filename))),
config.WithReader(json.NewReader(reader.WithEncoder(toml.NewEncoder()))),
)
case "yaml":
filename := "config.yaml"
if name := os.Getenv("CONFIG_FILE"); len(name) > 0 {
filename = name
}
configor, err = config.NewConfig(
config.WithSource(file.NewSource(file.WithPath(filename))),
config.WithReader(json.NewReader(reader.WithEncoder(yaml.NewEncoder()))),
)
default:
configor, err = config.NewConfig(
config.WithSource(env.NewSource()),
)
}
if err != nil {
return errors.Wrap(err, "configor.New")
}
if err := configor.Load(); err != nil {
return errors.Wrap(err, "configor.Load")
}
if err := configor.Scan(_cfg); err != nil {
return errors.Wrap(err, "configor.Scan")
}
w, err := configor.Watch()
if err != nil {
return errors.Wrap(err, "configor.Watch")
}
util.GoSafe(func() {
for {
v, err := w.Next()
if err != nil {
logger.Error(err)
return
}
if err := v.Scan(_cfg); err != nil {
logger.Error(err)
return
}
}
})
return nil
}

View File

@@ -1,150 +0,0 @@
module github.com/asim/go-micro/cmd/dashboard/v4
go 1.17
require (
github.com/asim/go-micro/plugins/broker/kafka/v4 v4.0.0-20211201082631-1e4dd94b71f1
github.com/asim/go-micro/plugins/broker/mqtt/v4 v4.0.0-20211201082631-1e4dd94b71f1
github.com/asim/go-micro/plugins/broker/nats/v4 v4.0.0-20211201082631-1e4dd94b71f1
github.com/asim/go-micro/plugins/broker/rabbitmq/v4 v4.0.0-20211201082631-1e4dd94b71f1
github.com/asim/go-micro/plugins/broker/redis/v4 v4.0.0-20211201082631-1e4dd94b71f1
github.com/asim/go-micro/plugins/client/grpc/v4 v4.0.0-20211202051538-c0e0b2b22508
github.com/asim/go-micro/plugins/client/http/v4 v4.0.0-20211201082631-1e4dd94b71f1
github.com/asim/go-micro/plugins/client/mucp/v4 v4.0.0-20211201082631-1e4dd94b71f1
github.com/asim/go-micro/plugins/config/encoder/toml/v4 v4.0.0-20211201082631-1e4dd94b71f1
github.com/asim/go-micro/plugins/config/encoder/yaml/v4 v4.0.0-20211201082631-1e4dd94b71f1
github.com/asim/go-micro/plugins/registry/consul/v4 v4.0.0-20211201082631-1e4dd94b71f1
github.com/asim/go-micro/plugins/registry/etcd/v4 v4.0.0-20211202051538-c0e0b2b22508
github.com/asim/go-micro/plugins/registry/eureka/v4 v4.0.0-20211201082631-1e4dd94b71f1
github.com/asim/go-micro/plugins/registry/gossip/v4 v4.0.0-20211201082631-1e4dd94b71f1
github.com/asim/go-micro/plugins/registry/kubernetes/v4 v4.0.0-20211205115617-97f169c424fe
github.com/asim/go-micro/plugins/registry/nacos/v4 v4.0.0-20211201082631-1e4dd94b71f1
github.com/asim/go-micro/plugins/registry/nats/v4 v4.0.0-20211201082631-1e4dd94b71f1
github.com/asim/go-micro/plugins/registry/zookeeper/v4 v4.0.0-20211201082631-1e4dd94b71f1
github.com/asim/go-micro/plugins/server/http/v4 v4.0.0-20211201082631-1e4dd94b71f1
github.com/dgrijalva/jwt-go v3.2.0+incompatible
github.com/gin-gonic/gin v1.7.7
github.com/pkg/errors v0.9.1
go-micro.dev/v4 v4.4.0
golang.org/x/net v0.0.0-20210614182718-04defd469f4e
)
require (
github.com/BurntSushi/toml v0.3.1 // indirect
github.com/Microsoft/go-winio v0.5.0 // indirect
github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7 // indirect
github.com/Shopify/sarama v1.29.1 // indirect
github.com/acomagu/bufpipe v1.0.3 // indirect
github.com/aliyun/alibaba-cloud-sdk-go v1.61.976 // indirect
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da // indirect
github.com/bitly/go-simplejson v0.5.0 // indirect
github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23 // indirect
github.com/cenkalti/backoff v2.2.1+incompatible // indirect
github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec // indirect
github.com/coreos/go-semver v0.3.0 // indirect
github.com/coreos/go-systemd/v22 v22.3.2 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/eapache/go-resiliency v1.2.0 // indirect
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21 // indirect
github.com/eapache/queue v1.1.0 // indirect
github.com/eclipse/paho.mqtt.golang v1.3.5 // indirect
github.com/emirpasic/gods v1.12.0 // indirect
github.com/fatih/color v1.9.0 // indirect
github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8 // indirect
github.com/fsnotify/fsnotify v1.4.9 // indirect
github.com/ghodss/yaml v1.0.0 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/go-errors/errors v1.0.1 // indirect
github.com/go-git/gcfg v1.5.0 // indirect
github.com/go-git/go-billy/v5 v5.3.1 // indirect
github.com/go-git/go-git/v5 v5.4.2 // indirect
github.com/go-playground/locales v0.13.0 // indirect
github.com/go-playground/universal-translator v0.17.0 // indirect
github.com/go-playground/validator/v10 v10.4.1 // indirect
github.com/go-zookeeper/zk v1.0.2 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/golang/snappy v0.0.3 // indirect
github.com/gomodule/redigo v1.8.5 // indirect
github.com/google/btree v1.0.0 // indirect
github.com/google/uuid v1.2.0 // indirect
github.com/gorilla/websocket v1.4.2 // indirect
github.com/hashicorp/consul/api v1.9.0 // indirect
github.com/hashicorp/errwrap v1.0.0 // indirect
github.com/hashicorp/go-cleanhttp v0.5.1 // indirect
github.com/hashicorp/go-hclog v0.12.0 // indirect
github.com/hashicorp/go-immutable-radix v1.0.0 // indirect
github.com/hashicorp/go-msgpack v0.5.3 // indirect
github.com/hashicorp/go-multierror v1.1.0 // indirect
github.com/hashicorp/go-rootcerts v1.0.2 // indirect
github.com/hashicorp/go-sockaddr v1.0.0 // indirect
github.com/hashicorp/go-uuid v1.0.2 // indirect
github.com/hashicorp/golang-lru v0.5.1 // indirect
github.com/hashicorp/memberlist v0.2.2 // indirect
github.com/hashicorp/serf v0.9.5 // indirect
github.com/hudl/fargo v1.3.0 // indirect
github.com/imdario/mergo v0.3.12 // indirect
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
github.com/jcmturner/aescts/v2 v2.0.0 // indirect
github.com/jcmturner/dnsutils/v2 v2.0.0 // indirect
github.com/jcmturner/gofork v1.0.0 // indirect
github.com/jcmturner/gokrb5/v8 v8.4.2 // indirect
github.com/jcmturner/rpc/v2 v2.0.3 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/json-iterator/go v1.1.11 // indirect
github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 // indirect
github.com/klauspost/compress v1.12.2 // indirect
github.com/leodido/go-urn v1.2.0 // indirect
github.com/lestrrat/go-file-rotatelogs v0.0.0-20180223000712-d3151e2a480f // indirect
github.com/lestrrat/go-strftime v0.0.0-20180220042222-ba3bf9c1d042 // indirect
github.com/mattn/go-colorable v0.1.8 // indirect
github.com/mattn/go-isatty v0.0.12 // indirect
github.com/miekg/dns v1.1.43 // indirect
github.com/minio/highwayhash v1.0.2 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mitchellh/hashstructure v1.1.0 // indirect
github.com/mitchellh/mapstructure v1.3.3 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.1 // indirect
github.com/nacos-group/nacos-sdk-go/v2 v2.0.0-Beta.1 // indirect
github.com/nats-io/jwt/v2 v2.2.0 // indirect
github.com/nats-io/nats.go v1.11.1-0.20210623165838-4b75fc59ae30 // indirect
github.com/nats-io/nkeys v0.3.0 // indirect
github.com/nats-io/nuid v1.0.1 // indirect
github.com/nxadm/tail v1.4.8 // indirect
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7 // indirect
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c // indirect
github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
github.com/pierrec/lz4 v2.6.0+incompatible // indirect
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect
github.com/russross/blackfriday/v2 v2.0.1 // indirect
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 // indirect
github.com/sergi/go-diff v1.1.0 // indirect
github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect
github.com/streadway/amqp v1.0.0 // indirect
github.com/toolkits/concurrent v0.0.0-20150624120057-a4371d70e3e3 // indirect
github.com/ugorji/go/codec v1.1.7 // indirect
github.com/urfave/cli/v2 v2.3.0 // indirect
github.com/xanzy/ssh-agent v0.3.0 // indirect
go.etcd.io/etcd/api/v3 v3.5.0 // indirect
go.etcd.io/etcd/client/pkg/v3 v3.5.0 // indirect
go.etcd.io/etcd/client/v3 v3.5.0 // indirect
go.uber.org/atomic v1.7.0 // indirect
go.uber.org/multierr v1.6.0 // indirect
go.uber.org/zap v1.17.0 // indirect
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e // indirect
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d // indirect
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 // indirect
golang.org/x/text v0.3.6 // indirect
google.golang.org/appengine v1.6.5 // indirect
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c // indirect
google.golang.org/grpc v1.42.0 // indirect
google.golang.org/protobuf v1.27.1 // indirect
gopkg.in/gcfg.v1 v1.2.3 // indirect
gopkg.in/ini.v1 v1.62.0 // indirect
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
)

File diff suppressed because it is too large Load Diff

View File

@@ -1,80 +0,0 @@
package account
import (
"time"
"github.com/asim/go-micro/cmd/dashboard/v4/config"
"github.com/asim/go-micro/cmd/dashboard/v4/handler/route"
"github.com/dgrijalva/jwt-go"
"github.com/gin-gonic/gin"
"github.com/gin-gonic/gin/render"
)
type service struct{}
func NewRouteRegistrar() route.Registrar {
return service{}
}
func (s service) RegisterRoute(router gin.IRoutes) {
router.POST("/api/account/login", s.Login)
router.Use(route.AuthRequired()).GET("/api/account/profile", s.Profile)
}
type loginRequest struct {
Username string `json:"username" binding:"required"`
Password string `json:"password" binding:"required"`
}
type loginResponse struct {
Token string `json:"token" binding:"required"`
}
// @Tags Account
// @ID account_login
// @Param input body loginRequest true "request"
// @Success 200 {object} loginResponse "success"
// @Failure 400 {object} string
// @Failure 401 {object} string
// @Failure 500 {object} string
// @Router /api/account/login [post]
func (s *service) Login(ctx *gin.Context) {
var req loginRequest
if err := ctx.ShouldBindJSON(&req); nil != err {
ctx.Render(400, render.String{Format: err.Error()})
return
}
if req.Username != config.GetServerConfig().Auth.Username ||
req.Password != config.GetServerConfig().Auth.Password {
ctx.Render(400, render.String{Format: "incorrect username or password"})
return
}
claims := jwt.StandardClaims{
Subject: req.Username,
IssuedAt: time.Now().Unix(),
ExpiresAt: time.Now().Add(config.GetAuthConfig().TokenExpiration).Unix(),
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
signedToken, err := token.SignedString([]byte(config.GetAuthConfig().TokenSecret))
if err != nil {
ctx.Render(400, render.String{Format: err.Error()})
return
}
ctx.JSON(200, loginResponse{Token: signedToken})
}
type profileResponse struct {
Name string `json:"name"`
}
// @Security ApiKeyAuth
// @Tags Account
// @ID account_profile
// @Success 200 {object} profileResponse "success"
// @Failure 400 {object} string
// @Failure 401 {object} string
// @Failure 500 {object} string
// @Router /api/account/profile [get]
func (s *service) Profile(ctx *gin.Context) {
ctx.JSON(200, profileResponse{Name: config.GetAuthConfig().Username})
}

View File

@@ -1,14 +0,0 @@
package client
type callRequest struct {
Service string `json:"service" binding:"required"`
Version string `json:"version"`
Endpoint string `json:"endpoint" binding:"required"`
Request string `json:"request"`
Timeout int64 `json:"timeout"`
}
type publishRequest struct {
Topic string `json:"topic" binding:"required"`
Message string `json:"message" binding:"required"`
}

View File

@@ -1,164 +0,0 @@
package client
import (
"context"
"encoding/json"
"sync"
"time"
"github.com/asim/go-micro/cmd/dashboard/v4/handler/route"
cgrpc "github.com/asim/go-micro/plugins/client/grpc/v4"
chttp "github.com/asim/go-micro/plugins/client/http/v4"
cmucp "github.com/asim/go-micro/plugins/client/mucp/v4"
"github.com/gin-gonic/gin"
"github.com/gin-gonic/gin/render"
"go-micro.dev/v4/client"
"go-micro.dev/v4/errors"
"go-micro.dev/v4/registry"
"go-micro.dev/v4/selector"
)
type service struct {
client client.Client
registry registry.Registry
clients map[string]client.Client
clientsMu sync.Mutex
}
func NewRouteRegistrar(client client.Client, registry registry.Registry) route.Registrar {
return &service{client: client, registry: registry}
}
func (s *service) RegisterRoute(router gin.IRoutes) {
router.Use(route.AuthRequired()).
POST("/api/client/call", s.Call).
POST("/api/client/publish", s.Publish)
}
// @Security ApiKeyAuth
// @Tags Client
// @ID client_call
// @Param input body callRequest true "request"
// @Success 200 {object} object "success"
// @Failure 400 {object} string
// @Failure 401 {object} string
// @Failure 500 {object} string
// @Router /api/client/call [post]
func (s *service) Call(ctx *gin.Context) {
var req callRequest
if err := ctx.ShouldBindJSON(&req); nil != err {
ctx.Render(400, render.String{Format: err.Error()})
return
}
var callReq json.RawMessage
if len(req.Request) > 0 {
if err := json.Unmarshal([]byte(req.Request), &callReq); err != nil {
ctx.Render(400, render.String{Format: "parse request failed: %s", Data: []interface{}{err.Error()}})
return
}
}
services, err := s.registry.GetService(req.Service)
if err != nil {
ctx.Render(400, render.String{Format: err.Error()})
return
}
var c client.Client
for _, srv := range services {
if len(req.Version) > 0 && req.Version != srv.Version {
continue
}
if len(srv.Nodes) == 0 {
ctx.Render(400, render.String{Format: "service node not found"})
return
}
c = s.getClient(srv.Nodes[0].Metadata["server"])
break
}
if c == nil {
ctx.Render(400, render.String{Format: "service not found"})
return
}
var resp json.RawMessage
callOpts := []client.CallOption{}
if len(req.Version) > 0 {
callOpts = append(callOpts, client.WithSelectOption(selector.WithFilter(selector.FilterVersion(req.Version))))
}
requestOpts := []client.RequestOption{client.WithContentType("application/json")}
if req.Timeout > 0 {
callOpts = append(callOpts, client.WithRequestTimeout(time.Duration(req.Timeout)*time.Second))
}
if err := c.Call(context.TODO(), client.NewRequest(req.Service, req.Endpoint, callReq, requestOpts...), &resp, callOpts...); err != nil {
if merr := errors.Parse(err.Error()); merr != nil {
ctx.JSON(200, gin.H{"success": false, "error": merr})
} else {
ctx.JSON(200, gin.H{"success": false, "error": err.Error})
}
return
}
ctx.JSON(200, resp)
}
// @Security ApiKeyAuth
// @Tags Client
// @ID client_publish
// @Param input body publishRequest true "request"
// @Success 200 {object} object "success"
// @Failure 400 {object} string
// @Failure 401 {object} string
// @Failure 500 {object} string
// @Router /api/client/publish [post]
func (s *service) Publish(ctx *gin.Context) {
var req publishRequest
if err := ctx.ShouldBindJSON(&req); nil != err {
ctx.Render(400, render.String{Format: err.Error()})
return
}
var msg json.RawMessage
if len(req.Message) > 0 {
if err := json.Unmarshal([]byte(req.Message), &msg); err != nil {
ctx.Render(400, render.String{Format: "parse request failed: %s", Data: []interface{}{err.Error()}})
return
}
}
err := s.client.Publish(ctx, client.NewMessage(req.Topic, msg, client.WithMessageContentType("application/json")))
if err != nil {
if merr := errors.Parse(err.Error()); merr != nil {
ctx.JSON(200, gin.H{"success": false, "error": merr})
} else {
ctx.JSON(200, gin.H{"success": false, "error": err.Error})
}
return
}
ctx.JSON(200, gin.H{"success": true})
}
func (s *service) getClient(serverType string) client.Client {
if serverType == s.client.String() {
return s.client
}
s.clientsMu.Lock()
defer s.clientsMu.Unlock()
if s.clients == nil {
s.clients = make(map[string]client.Client)
} else {
if c, ok := s.clients[serverType]; ok {
return c
}
}
var c client.Client
switch serverType {
case "grpc":
c = cgrpc.NewClient()
s.clients[serverType] = c
case "http":
c = chttp.NewClient()
s.clients[serverType] = c
case "mucp":
c = cmucp.NewClient()
s.clients[serverType] = c
default:
c = s.client
}
return c
}

View File

@@ -1,23 +0,0 @@
package client
import (
"testing"
"go-micro.dev/v4/client"
)
func TestGetClient(t *testing.T) {
s := &service{client: client.DefaultClient}
if s.getClient("grpc").String() != "grpc" {
t.Fail()
}
if s.getClient("http").String() != "http" {
t.Fail()
}
if s.getClient("mucp").String() != "mucp" {
t.Fail()
}
if s.getClient("other").String() != client.DefaultClient.String() {
t.Fail()
}
}

View File

@@ -1,37 +0,0 @@
package handler
import (
"github.com/asim/go-micro/cmd/dashboard/v4/config"
"github.com/asim/go-micro/cmd/dashboard/v4/handler/account"
handlerclient "github.com/asim/go-micro/cmd/dashboard/v4/handler/client"
"github.com/asim/go-micro/cmd/dashboard/v4/handler/registry"
"github.com/asim/go-micro/cmd/dashboard/v4/handler/route"
"github.com/asim/go-micro/cmd/dashboard/v4/handler/statistics"
"github.com/asim/go-micro/cmd/dashboard/v4/web"
"github.com/gin-gonic/gin"
"go-micro.dev/v4/client"
)
type Options struct {
Client client.Client
Router *gin.Engine
}
func Register(opts Options) error {
router := opts.Router
if err := web.RegisterRoute(router); err != nil {
return err
}
if cfg := config.GetServerConfig().CORS; cfg.Enable {
router.Use(route.CorsHandler(cfg.Origin))
}
for _, r := range []route.Registrar{
account.NewRouteRegistrar(),
handlerclient.NewRouteRegistrar(opts.Client, opts.Client.Options().Registry),
registry.NewRouteRegistrar(opts.Client.Options().Registry),
statistics.NewRouteRegistrar(opts.Client.Options().Registry),
} {
r.RegisterRoute(router.Group(""))
}
return nil
}

View File

@@ -1,67 +0,0 @@
package registry
import "go-micro.dev/v4/registry"
type registryServiceSummary struct {
Name string `json:"name" binding:"required"`
Versions []string `json:"versions,omitempty"`
}
type getServiceListResponse struct {
Services []registryServiceSummary `json:"services" binding:"required"`
}
type registryService struct {
Name string `json:"name" binding:"required"`
Version string `json:"version" binding:"required"`
Metadata map[string]string `json:"metadata,omitempty"`
Handlers []registryEndpoint `json:"handlers,omitempty"`
Subscribers []registryEndpoint `json:"subscribers,omitempty"`
Nodes []registryNode `json:"nodes,omitempty"`
}
type registryEndpoint struct {
Name string `json:"name" binding:"required"`
Request registryValue `json:"request" binding:"required"`
Response registryValue `json:"response"`
Metadata map[string]string `json:"metadata,omitempty"`
}
type registryNode struct {
Id string `json:"id" binding:"required"`
Address string `json:"address" binding:"required"`
Metadata map[string]string `json:"metadata,omitempty"`
}
type registryValue struct {
Name string `json:"name" binding:"required"`
Type string `json:"type" binding:"required"`
Values []registryValue `json:"values,omitempty"`
}
type getServiceDetailResponse struct {
Services []registryService `json:"services"`
}
type getServiceHandlersResponse struct {
Handlers []registryEndpoint `json:"handlers"`
}
type getServiceSubscribersResponse struct {
Subscribers []registryEndpoint `json:"subscribers"`
}
func convertRegistryValue(v *registry.Value) registryValue {
if v == nil {
return registryValue{}
}
res := registryValue{
Name: v.Name,
Type: v.Type,
Values: make([]registryValue, 0, len(v.Values)),
}
for _, vv := range v.Values {
res.Values = append(res.Values, convertRegistryValue(vv))
}
return res
}

View File

@@ -1,221 +0,0 @@
package registry
import (
"sort"
"github.com/asim/go-micro/cmd/dashboard/v4/handler/route"
"github.com/gin-gonic/gin"
"github.com/gin-gonic/gin/render"
"go-micro.dev/v4/registry"
)
type service struct {
registry registry.Registry
}
func NewRouteRegistrar(registry registry.Registry) route.Registrar {
return service{registry: registry}
}
func (s service) RegisterRoute(router gin.IRoutes) {
router.Use(route.AuthRequired()).
GET("/api/registry/services", s.GetServices).
GET("/api/registry/service", s.GetServiceDetail).
GET("/api/registry/service/handlers", s.GetServiceHandlers).
GET("/api/registry/service/subscribers", s.GetServiceSubscribers)
}
// @Security ApiKeyAuth
// @Tags Registry
// @ID registry_getServices
// @Success 200 {object} getServiceListResponse
// @Failure 400 {object} string
// @Failure 401 {object} string
// @Failure 500 {object} string
// @Router /api/registry/services [get]
func (s *service) GetServices(ctx *gin.Context) {
services, err := s.registry.ListServices()
if err != nil {
ctx.Render(500, render.String{Format: err.Error()})
return
}
tmp := make(map[string][]string)
resp := getServiceListResponse{Services: make([]registryServiceSummary, 0, len(services))}
for _, s := range services {
if sr, ok := tmp[s.Name]; ok {
sr = append(sr, s.Version)
tmp[s.Name] = sr
} else {
tmp[s.Name] = []string{s.Version}
}
}
for k, v := range tmp {
sort.Strings(v)
resp.Services = append(resp.Services, registryServiceSummary{Name: k, Versions: v})
}
sort.Slice(resp.Services, func(i, j int) bool {
return resp.Services[i].Name < resp.Services[j].Name
})
ctx.JSON(200, resp)
}
// @Security ApiKeyAuth
// @Tags Registry
// @ID registry_getServiceDetail
// @Param name query string true "service name"
// @Param version query string false "service version"
// @Success 200 {object} getServiceDetailResponse
// @Failure 400 {object} string
// @Failure 401 {object} string
// @Failure 500 {object} string
// @Router /api/registry/service [get]
func (s *service) GetServiceDetail(ctx *gin.Context) {
name := ctx.Query("name")
if len(name) == 0 {
ctx.Render(400, render.String{Format: "service name required"})
return
}
services, err := s.registry.GetService(name)
if err != nil {
ctx.Render(500, render.String{Format: err.Error()})
return
}
version := ctx.Query("version")
resp := getServiceDetailResponse{Services: make([]registryService, 0, len(services))}
for _, s := range services {
if len(version) > 0 && s.Version != version {
continue
}
handlers := make([]registryEndpoint, 0)
subscribers := make([]registryEndpoint, 0)
for _, e := range s.Endpoints {
if isSubscriber(e) {
subscribers = append(subscribers, registryEndpoint{
Name: e.Metadata["topic"],
Request: convertRegistryValue(e.Request),
Metadata: e.Metadata,
})
} else {
handlers = append(handlers, registryEndpoint{
Name: e.Name,
Request: convertRegistryValue(e.Request),
Response: convertRegistryValue(e.Response),
Metadata: e.Metadata,
})
}
}
nodes := make([]registryNode, 0, len(s.Nodes))
for _, n := range s.Nodes {
nodes = append(nodes, registryNode{
Id: n.Id,
Address: n.Address,
Metadata: n.Metadata,
})
}
resp.Services = append(resp.Services, registryService{
Name: s.Name,
Version: s.Version,
Metadata: s.Metadata,
Handlers: handlers,
Subscribers: subscribers,
Nodes: nodes,
})
}
ctx.JSON(200, resp)
}
// @Security ApiKeyAuth
// @Tags Registry
// @ID registry_getServiceHandlers
// @Param name query string true "service name"
// @Param version query string false "service version"
// @Success 200 {object} getServiceHandlersResponse
// @Failure 400 {object} string
// @Failure 401 {object} string
// @Failure 500 {object} string
// @Router /api/registry/service/handlers [get]
func (s *service) GetServiceHandlers(ctx *gin.Context) {
name := ctx.Query("name")
if len(name) == 0 {
ctx.Render(400, render.String{Format: "service name required"})
return
}
services, err := s.registry.GetService(name)
if err != nil {
ctx.Render(500, render.String{Format: err.Error()})
return
}
version := ctx.Query("version")
resp := getServiceHandlersResponse{}
for _, s := range services {
if s.Version != version {
continue
}
handlers := make([]registryEndpoint, 0, len(s.Endpoints))
for _, e := range s.Endpoints {
if isSubscriber(e) {
continue
}
handlers = append(handlers, registryEndpoint{
Name: e.Name,
Request: convertRegistryValue(e.Request),
})
}
resp.Handlers = handlers
break
}
ctx.JSON(200, resp)
}
// @Security ApiKeyAuth
// @Tags Registry
// @ID registry_getServiceSubscribers
// @Param name query string true "service name"
// @Param version query string false "service version"
// @Success 200 {object} getServiceSubscribersResponse
// @Failure 400 {object} string
// @Failure 401 {object} string
// @Failure 500 {object} string
// @Router /api/registry/service/subscribers [get]
func (s *service) GetServiceSubscribers(ctx *gin.Context) {
name := ctx.Query("name")
if len(name) == 0 {
ctx.Render(400, render.String{Format: "service name required"})
return
}
services, err := s.registry.GetService(name)
if err != nil {
ctx.Render(500, render.String{Format: err.Error()})
return
}
version := ctx.Query("version")
resp := getServiceSubscribersResponse{}
for _, s := range services {
if s.Version != version {
continue
}
subscribers := make([]registryEndpoint, 0, len(s.Endpoints))
for _, e := range s.Endpoints {
if !isSubscriber(e) {
continue
}
subscribers = append(subscribers, registryEndpoint{
Name: e.Metadata["topic"],
Request: convertRegistryValue(e.Request),
})
}
resp.Subscribers = subscribers
break
}
ctx.JSON(200, resp)
}
func isSubscriber(ep *registry.Endpoint) bool {
if ep == nil || len(ep.Metadata) == 0 {
return false
}
if s, ok := ep.Metadata["subscriber"]; ok && s == "true" {
return true
}
return false
}

View File

@@ -1,51 +0,0 @@
package route
import (
"net/http"
"strings"
"github.com/asim/go-micro/cmd/dashboard/v4/config"
"github.com/dgrijalva/jwt-go"
"github.com/gin-gonic/gin"
)
func AuthRequired() gin.HandlerFunc {
return func(ctx *gin.Context) {
if ctx.Request.Method == "OPTIONS" {
ctx.Next()
return
}
tokenString := ctx.GetHeader("Authorization")
if len(tokenString) == 0 || !strings.HasPrefix(tokenString, "Bearer ") {
ctx.AbortWithStatusJSON(http.StatusUnauthorized, "")
return
}
tokenString = tokenString[7:]
claims := jwt.StandardClaims{}
token, err := jwt.ParseWithClaims(tokenString, &claims, func(t *jwt.Token) (interface{}, error) {
return []byte(config.GetAuthConfig().TokenSecret), nil
})
if err != nil {
ctx.AbortWithError(http.StatusUnauthorized, err)
}
if !token.Valid {
ctx.AbortWithStatus(http.StatusUnauthorized)
}
ctx.Set("username", claims.Subject)
ctx.Next()
}
}
func CorsHandler(allowOrigin string) gin.HandlerFunc {
return func(ctx *gin.Context) {
ctx.Header("Access-Control-Allow-Origin", allowOrigin)
ctx.Header("Access-Control-Allow-Headers", "Content-Type, Authorization, token")
ctx.Header("Access-Control-Allow-Methods", "POST, GET, DELETE, PUT, OPTIONS")
ctx.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Content-Type")
ctx.Header("Access-Control-Allow-Credentials", "true")
if ctx.Request.Method == "OPTIONS" {
ctx.AbortWithStatus(http.StatusNoContent)
}
ctx.Next()
}
}

View File

@@ -1,7 +0,0 @@
package route
import "github.com/gin-gonic/gin"
type Registrar interface {
RegisterRoute(gin.IRoutes)
}

View File

@@ -1,16 +0,0 @@
package statistics
type getSummaryResponse struct {
Registry registrySummary `json:"registry"`
Services servicesSummary `json:"services"`
}
type registrySummary struct {
Type string `json:"type"`
Addrs []string `json:"addrs"`
}
type servicesSummary struct {
Count int `json:"count"`
NodesCount int `json:"nodes_count"`
}

View File

@@ -1,62 +0,0 @@
package statistics
import (
"github.com/asim/go-micro/cmd/dashboard/v4/config"
"github.com/asim/go-micro/cmd/dashboard/v4/handler/route"
"github.com/gin-gonic/gin"
"go-micro.dev/v4/registry"
)
type service struct {
registry registry.Registry
}
func NewRouteRegistrar(registry registry.Registry) route.Registrar {
return service{registry: registry}
}
func (s service) RegisterRoute(router gin.IRoutes) {
router.GET("/version", s.GetVersion)
router.Use(route.AuthRequired()).GET("/api/summary", s.GetSummary)
}
// @Security ApiKeyAuth
// @Tags Statistics
// @ID statistics_getSummary
// @Success 200 {object} getSummaryResponse
// @Failure 400 {object} string
// @Failure 401 {object} string
// @Failure 500 {object} string
// @Router /api/summary [get]
func (s *service) GetSummary(ctx *gin.Context) {
services, err := s.registry.ListServices()
if err != nil {
ctx.AbortWithStatusJSON(500, err)
}
servicesByName := make(map[string]struct{})
var servicesNodesCount int
for _, s := range services {
if _, ok := servicesByName[s.Name]; !ok {
servicesByName[s.Name] = struct{}{}
}
servicesNodesCount += len(s.Nodes)
}
var resp = getSummaryResponse{
Registry: registrySummary{
Type: s.registry.String(),
Addrs: s.registry.Options().Addrs,
},
Services: servicesSummary{
Count: len(servicesByName),
NodesCount: servicesNodesCount,
},
}
ctx.JSON(200, resp)
}
// @ID getVersion
// @Success 200 {object} object
// @Router /version [get]
func (s *service) GetVersion(ctx *gin.Context) {
ctx.JSON(200, gin.H{"version": config.Version})
}

View File

@@ -1,35 +0,0 @@
package main
import (
"github.com/asim/go-micro/cmd/dashboard/v4/config"
"github.com/asim/go-micro/cmd/dashboard/v4/handler"
mhttp "github.com/asim/go-micro/plugins/server/http/v4"
"github.com/gin-gonic/gin"
"go-micro.dev/v4"
"go-micro.dev/v4/logger"
)
func main() {
if err := config.Load(); err != nil {
logger.Fatal(err)
}
srv := micro.NewService(micro.Server(mhttp.NewServer()))
opts := []micro.Option{
micro.Name(config.Name),
micro.Address(config.GetServerConfig().Address),
micro.Version(config.Version),
}
srv.Init(opts...)
gin.SetMode(gin.ReleaseMode)
router := gin.New()
router.Use(gin.Recovery(), gin.Logger())
if err := handler.Register(handler.Options{Client: srv.Client(), Router: router}); err != nil {
logger.Fatal(err)
}
if err := micro.RegisterHandler(srv.Server(), router); err != nil {
logger.Fatal(err)
}
if err := srv.Run(); err != nil {
logger.Fatal(err)
}
}

View File

@@ -1,18 +0,0 @@
package main
import (
_ "github.com/asim/go-micro/plugins/broker/kafka/v4"
_ "github.com/asim/go-micro/plugins/broker/mqtt/v4"
_ "github.com/asim/go-micro/plugins/broker/nats/v4"
_ "github.com/asim/go-micro/plugins/broker/rabbitmq/v4"
_ "github.com/asim/go-micro/plugins/broker/redis/v4"
_ "github.com/asim/go-micro/plugins/registry/consul/v4"
_ "github.com/asim/go-micro/plugins/registry/etcd/v4"
_ "github.com/asim/go-micro/plugins/registry/eureka/v4"
_ "github.com/asim/go-micro/plugins/registry/gossip/v4"
_ "github.com/asim/go-micro/plugins/registry/kubernetes/v4"
_ "github.com/asim/go-micro/plugins/registry/nacos/v4"
_ "github.com/asim/go-micro/plugins/registry/nats/v4"
_ "github.com/asim/go-micro/plugins/registry/zookeeper/v4"
)

View File

@@ -1,22 +0,0 @@
package util
import (
"runtime/debug"
"go-micro.dev/v4/logger"
)
// GoSafe will run func in goroutine safely, avoid crash from unexpected panic
func GoSafe(fn func()) {
if fn == nil {
return
}
go func() {
defer func() {
if e := recover(); e != nil {
logger.Errorf("[panic]%v\n%s", e, debug.Stack())
}
}()
fn()
}()
}

View File

@@ -1,144 +0,0 @@
// Code generated by fileb0x at "2021-12-07 10:11:10.4808383 +0800 CST m=+0.057013201" from config file "b0x.yaml" DO NOT EDIT.
// modification hash(fecae112933101acf070cd0740e400a2.8be3f833d63e3c844663716446e13a42)
package web
import (
"bytes"
"context"
"io"
"net/http"
"os"
"path"
"golang.org/x/net/webdav"
)
var (
// CTX is a context for webdav vfs
CTX = context.Background()
// FS is a virtual memory file system
FS = webdav.NewMemFS()
// Handler is used to server files through a http handler
Handler *webdav.Handler
// HTTP is the http file system
HTTP http.FileSystem = new(HTTPFS)
)
// HTTPFS implements http.FileSystem
type HTTPFS struct {
// Prefix allows to limit the path of all requests. F.e. a prefix "css" would allow only calls to /css/*
Prefix string
}
func init() {
err := CTX.Err()
if err != nil {
panic(err)
}
err = FS.Mkdir(CTX, "/assets/", 0777)
if err != nil && err != os.ErrExist {
panic(err)
}
Handler = &webdav.Handler{
FileSystem: FS,
LockSystem: webdav.NewMemLS(),
}
}
// Open a file
func (hfs *HTTPFS) Open(path string) (http.File, error) {
path = hfs.Prefix + path
f, err := FS.OpenFile(CTX, path, os.O_RDONLY, 0644)
if err != nil {
return nil, err
}
return f, nil
}
// ReadFile is adapTed from ioutil
func ReadFile(path string) ([]byte, error) {
f, err := FS.OpenFile(CTX, path, os.O_RDONLY, 0644)
if err != nil {
return nil, err
}
buf := bytes.NewBuffer(make([]byte, 0, bytes.MinRead))
// If the buffer overflows, we will get bytes.ErrTooLarge.
// Return that as an error. Any other panic remains.
defer func() {
e := recover()
if e == nil {
return
}
if panicErr, ok := e.(error); ok && panicErr == bytes.ErrTooLarge {
err = panicErr
} else {
panic(e)
}
}()
_, err = buf.ReadFrom(f)
return buf.Bytes(), err
}
// WriteFile is adapTed from ioutil
func WriteFile(filename string, data []byte, perm os.FileMode) error {
f, err := FS.OpenFile(CTX, filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm)
if err != nil {
return err
}
n, err := f.Write(data)
if err == nil && n < len(data) {
err = io.ErrShortWrite
}
if err1 := f.Close(); err == nil {
err = err1
}
return err
}
// WalkDirs looks for files in the given dir and returns a list of files in it
// usage for all files in the b0x: WalkDirs("", false)
func WalkDirs(name string, includeDirsInList bool, files ...string) ([]string, error) {
f, err := FS.OpenFile(CTX, name, os.O_RDONLY, 0)
if err != nil {
return nil, err
}
fileInfos, err := f.Readdir(0)
if err != nil {
return nil, err
}
err = f.Close()
if err != nil {
return nil, err
}
for _, info := range fileInfos {
filename := path.Join(name, info.Name())
if includeDirsInList || !info.IsDir() {
files = append(files, filename)
}
if info.IsDir() {
files, err = WalkDirs(filename, includeDirsInList, files...)
if err != nil {
return nil, err
}
}
}
return files, nil
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,59 +0,0 @@
package web
import (
"os"
"os/exec"
"path/filepath"
"github.com/gin-gonic/gin"
)
func RegisterRoute(router *gin.Engine) error {
files, err := WalkDirs("", false)
if err != nil {
return err
}
for _, f := range files {
router.GET(f, func(name string) gin.HandlerFunc {
return func(c *gin.Context) {
data, err := ReadFile(name)
if err != nil {
c.AbortWithError(500, err)
return
}
switch filepath.Ext(name) {
case ".html":
c.Header("Content-Type", "text/html; charset=utf-8")
case ".css":
c.Header("Content-Type", "text/css; charset=utf-8")
case ".js":
c.Header("Content-Type", "text/javascript")
case ".svg":
c.Header("Content-Type", "image/svg+xml")
}
if path, err := exec.LookPath(os.Args[0]); err == nil {
if file, err := os.Stat(path); err == nil {
c.Header("Last-Modified", file.ModTime().UTC().Format("Mon, 02 Jan 2006 15:04:05 GMT"))
}
}
if _, err := c.Writer.Write(data); err != nil {
c.AbortWithError(500, err)
return
}
}
}(f))
}
router.GET("/", func(c *gin.Context) {
data, err := ReadFile("index.html")
if err != nil {
c.AbortWithError(500, err)
return
}
c.Header("Content-Type", "text/html; charset=utf-8")
if _, err := c.Writer.Write(data); err != nil {
c.AbortWithError(500, err)
return
}
})
return nil
}