# chaineye
**Repository Path**: shengjian-tech/chaineye
## Basic Information
- **Project Name**: chaineye
- **Description**: 链眼 开源联盟链监控平台,已支持XuperChain
- **Primary Language**: Go
- **License**: Apache-2.0
- **Default Branch**: main
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 1
- **Forks**: 1
- **Created**: 2022-07-05
- **Last Updated**: 2024-06-29
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
>chaineye是一款开源的区块链监控平台,目前已经支持百度XuperChain,基于[nightingale](https://github.com/ccfos/nightingale)二次开发,开箱即用的产品体验。
夜莺Nightingale是中国计算机学会托管的开源云原生可观测工具,最早由滴滴于 2020 年孵化并开源,并于 2022 年正式捐赠予中国计算机学会。夜莺采用 All-in-One 的设计理念,集数据采集、可视化、监控告警、数据分析于一体,与云原生生态紧密集成,融入了顶级互联网公司可观测性最佳实践,沉淀了众多社区专家经验,开箱即用。
## 预览
## 快速安装
- 前置:需要安装Prometheus或者其他工具作为数据源。已有正在运行的XuperChain网络。
- 克隆项目到本地 项目地址 https://github.com/shengjian-tech/chaineye
- `go mod tidy`下载依赖, `go build -ldflags "-w -s" -o chaineye ./cmd/center/main.go`编译完成。
- 执行sql文件[./docker/initsql/a-n9e.sql](./docker/initsql/a-n9e.sql)
- 修改 [./etc/config.toml](./etc/config.toml) 配置文件。 配置Redis连接,数据库连接,Prometheus服务地址,`XuperSdkYmlPath` 配置文件,将```#UseFileAssets = true```的注释解开。
- 修改完配置文件后,在根目录执行命令即可启动`chaineye`服务。命令 `nohup ./chaineye &` , 随后可以通过查看日志输出,判断服务是否正常启动。
- 下载`chaineye`对应前端项目`front_chaineye`,仓库路径 https://github.com/shengjian-tech/front_chaineye
- 下载前端最新的release版本或者自行编译,解压后,将`pub`目录放到`chaineye`可执行文件同级目录。
- 访问`http://127.0.0.1:17000` 页面, 账号:root 密码:root.2020
- 导入XuperChain监控大盘,XuperChain大盘文件路径 [xuper_metric.json](./xuper_metric.json) 下载后,在监控大盘中,导入即可。
## 超级链监控大盘预览
## 鸣谢
[夜莺nightingale](https://github.com/ccfos/nightingale)
[XuperChain](https://github.com/xuperchain/xuperchain)
## 第三方集成
### 1.拉取链眼项目
```
git clone https://github.com/shengjian-tech/chaineye.git
```
### 2.修改文件
修改此文件 [router_mw.go](./center/router/router_mw.go) 中方法jwtAuth()
```go
func (rt *Router) jwtAuth() gin.HandlerFunc {
return func(c *gin.Context) {
tok := c.Request.Header.Get("Authorization")
tokenRsa := ""
if len(tok) > 6 && strings.ToUpper(tok[0:7]) == "BEARER " {
tokenRsa = tok[7:]
} else {
ginx.Bomb(http.StatusUnauthorized, "unauthorized")
}
if len(tokenRsa) < 1 {
ginx.Bomb(http.StatusUnauthorized, "unauthorized")
}
token, err := rt.parseRSAToken(tokenRsa)
if err != nil || token == "" {
ginx.Bomb(http.StatusUnauthorized, "unauthorized")
}
seg := strings.Split(token, ".")[1]
result, err := base64.RawURLEncoding.DecodeString(seg)
if err != nil {
ginx.Bomb(http.StatusUnauthorized, "unauthorized")
}
var tmp = make(map[string]interface{})
err = json.Unmarshal(result, &tmp)
if err != nil {
ginx.Bomb(http.StatusUnauthorized, "unauthorized")
}
userId := tmp["userId"].(string)
jwtSecret := getJwtSecret(userId, rt.HTTP.JWTAuth.SigningKey)
userId, err = userIdByToken(token, jwtSecret)
if err != nil || userId == "" {
ginx.Bomb(http.StatusUnauthorized, "unauthorized")
}
c.Set("userid", int64(1))
c.Set("username", "root")
c.Next()
}
}
```
在此文件 [router_mw.go](./center/router/router_mw.go) 添加如下方法
```go
// parseRSAToken 用公钥解密 RSA 私钥加密的方法
func (rt *Router) parseRSAToken(token string) (string, error) {
token = fmt.Sprintf("%x", token)
resultToken, err := gorsa.PublicDecrypt(token, rt.HTTP.JWTAuth.RsaPublickey)
if err != nil {
return "", err
}
return resultToken, nil
}
// getJwtSecret 获取加密字符串
func getJwtSecret(userId string, jwtSecret string) string {
h := md5.New()
h.Write([]byte(userId + jwtSecret))
return hex.EncodeToString(h.Sum(nil))
}
// userIdByToken 校验token是否有效
func userIdByToken(tokenString string, jwtSecret string) (string, error) {
if tokenString == "" {
return "", errors.New("token不能为空")
}
token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
return []byte(jwtSecret), nil
})
if !token.Valid {
return "", errors.New("token is not valid")
} else if errors.Is(err, jwt.ErrTokenMalformed) {
return "", fmt.Errorf("that's not even a token:%w", err)
} else if errors.Is(err, jwt.ErrTokenExpired) || errors.Is(err, jwt.ErrTokenNotValidYet) {
return "", fmt.Errorf("timing is everything:%w", err)
} else if err != nil {
return "", fmt.Errorf("couldn't handle this token:%w", err)
}
mapClaims, ok := token.Claims.(jwt.MapClaims)
if ok && token.Valid {
userId := mapClaims["userId"].(string)
return userId, nil
}
return "", errors.New("token错误或过期")
}
```
### 3.导入工具包
1.拉取项目改过之后,用go mod tidy下载依赖
2.若是go mod tidy操作之后,如果`router_mw.go`出错,报找不放变量或者方法的错,可以看下导入的包是否正确
`jwt`导入的是`"github.com/golang-jwt/jwt/v5"`.
`gorsa`导入的是`"github.com/wenzhenxi/gorsa"`.
### 4.修改配置文件
进入到`chaineye/etc/config.toml`,修改配置文件.
1.修改`SigningKey`
`SigningKey = "xxxxxxxxxxxxxxxxxxxxxxxxxx"`,可以去配置文件中找到.
2.修改`RsaPublickey`
```
# Rsa公钥配置,仅用于第三方集成,必须有-----BEGIN PUBLIC KEY-----\n和\n-----END PUBLIC KEY-----
RsaPublickey = "-----BEGIN PUBLIC KEY-----\n你的项目公钥\n-----END PUBLIC KEY-----"
```
修改完配置文件后,进行编译,运行即可.
## 6.前端适配
进入链眼首页,看到缓冲中主要存入了三个值
```
curBusiId #1
access_token #和我们项目的token值一样
refresh_token #和我们项目的token值一样
```
在要集成的前端的缓存中存入这三个值就可以实现单点登录.