Skip to content

Commit

Permalink
feat(nnr): add nnr support
Browse files Browse the repository at this point in the history
add nnr support

Signed-off-by: ysicing <i@ysicing.me>
  • Loading branch information
ysicing committed Oct 5, 2023
1 parent 5e6ffd6 commit 17662e3
Show file tree
Hide file tree
Showing 5 changed files with 249 additions and 0 deletions.
121 changes: 121 additions & 0 deletions cmd/nnr/nnr.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
// Copyright (c) 2023 ysicing(ysicing.me, ysicing@12306.work) All rights reserved.
// Use of this source code is covered by the following dual licenses:
// (1) Y PUBLIC LICENSE 1.0 (YPL 1.0)
// (2) Affero General Public License 3.0 (AGPL 3.0)
// License that can be found in the LICENSE file.

package nnr

import (
"fmt"
"os"
"sort"
"strings"

"github.com/ergoapi/util/output"
"github.com/gosuri/uitable"
"github.com/spf13/cobra"
"github.com/ysicing/tiga/internal/pkg/nnr"
"github.com/ysicing/tiga/internal/util"
"github.com/ysicing/tiga/pkg/factory"
)

var token string

func NewCmdNNR(f factory.Factory) *cobra.Command {
cmd := &cobra.Command{
Use: "nnr",
Short: "nnr tools",
Version: "2023.10.0519",
}
cmd.AddCommand(listServers(f))
cmd.AddCommand(listRules(f))
cmd.AddCommand(addRule(f))
cmd.AddCommand(delRule(f))
cmd.AddCommand(updateRule(f))
cmd.PersistentFlags().StringVarP(&token, "token", "t", os.Getenv("NNR_TOKEN"), "token")
return cmd
}

func listServers(f factory.Factory) *cobra.Command {
cmd := &cobra.Command{
Use: "nodes",
Aliases: []string{"servers"},
Short: "list servers",
RunE: func(cmd *cobra.Command, args []string) error {
api := nnr.New(token)
s, err := api.ListServers()
if err != nil {
return err
}
if len(s) == 0 {
f.GetLog().Infof("no servers found")
return nil
}
f.GetLog().Infof("found %d servers", len(s))
sort.Slice(s, func(i, j int) bool {
return s[i].Mf >= s[j].Mf
})
table := uitable.New()
table.AddRow("标识", "节点", "IP", "倍率", "支持TCP+UDP", "描述")
for _, index := range s {
table.AddRow(index.Sid, index.Name, index.Host, index.Mf, len(index.Types) == 3, strings.ReplaceAll(index.Detail, "\n", " "))
}
return output.EncodeTable(os.Stdout, table)
},
}
return cmd
}

func listRules(f factory.Factory) *cobra.Command {
cmd := &cobra.Command{
Use: "rules",
Short: "list rules",
RunE: func(cmd *cobra.Command, args []string) error {
api := nnr.New(token)
s, err := api.ListRules()
if err != nil {
return err
}
if len(s) == 0 {
f.GetLog().Infof("no rules found")
return nil
}
f.GetLog().Infof("found %d rules", len(s))
sort.Slice(s, func(i, j int) bool {
return s[i].Traffic >= s[j].Traffic
})
table := uitable.New()
table.AddRow("规则标识", "节点标识", "转发地址", "远程地址", "类型", "流量")
for _, index := range s {
table.AddRow(index.Rid, index.Sid, fmt.Sprintf("%v:%v", index.Host, index.Port), fmt.Sprintf("%v:%v", index.Remote, index.RPort), index.Type, util.Traffic(index.Traffic))
}
return output.EncodeTable(os.Stdout, table)
},
}
return cmd
}

func addRule(f factory.Factory) *cobra.Command {
cmd := &cobra.Command{
Use: "add",
Short: "add rule",
}
return cmd
}

func delRule(f factory.Factory) *cobra.Command {
cmd := &cobra.Command{
Use: "del",
Short: "del rule",
}
return cmd
}

func updateRule(f factory.Factory) *cobra.Command {
cmd := &cobra.Command{
Use: "update",
Short: "update rule",
}
return cmd
}
5 changes: 5 additions & 0 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"github.com/spf13/cobra"
"github.com/ysicing/tiga/cmd/clash"
"github.com/ysicing/tiga/cmd/flags"
"github.com/ysicing/tiga/cmd/nnr"
"github.com/ysicing/tiga/cmd/xray"
"github.com/ysicing/tiga/common"
"github.com/ysicing/tiga/pkg/factory"
Expand Down Expand Up @@ -68,8 +69,12 @@ func BuildRoot(f factory.Factory) *cobra.Command {
if zos.IsLinux() {
rootCmd.AddCommand(newCmdApp(f))
rootCmd.AddCommand(newCmdRepo(f))
}

if zos.IsUnix() {
rootCmd.AddCommand(xray.NewCmdXray(f))
rootCmd.AddCommand(clash.NewCmdClash(f))
rootCmd.AddCommand(nnr.NewCmdNNR(f))
}

rootCmd.AddCommand(newManCmd())
Expand Down
53 changes: 53 additions & 0 deletions internal/pkg/nnr/nnr.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// Copyright (c) 2023 ysicing(ysicing.me, ysicing@12306.work) All rights reserved.
// Use of this source code is covered by the following dual licenses:
// (1) Y PUBLIC LICENSE 1.0 (YPL 1.0)
// (2) Affero General Public License 3.0 (AGPL 3.0)
// License that can be found in the LICENSE file.

package nnr

import (
"github.com/cockroachdb/errors"
"github.com/imroc/req/v3"
"github.com/ysicing/tiga/common"
)

type Option struct {
*req.Request
}

func New(token string) *Option {
reqClient := req.C().
SetUserAgent(common.GetUG()).
R().
SetHeader("accept", "application/json").
SetHeaders(map[string]string{
"Content-Type": "application/json",
"Token": token,
})
return &Option{reqClient}
}

func (o *Option) ListServers() ([]Server, error) {
var serversResp ServersResp
_, err := o.SetSuccessResult(&serversResp).Post("https://nnr.moe/api/servers")
if err != nil {
return nil, err
}
if serversResp.Status != 1 {
return nil, errors.New("list servers failed")
}
return serversResp.Data, nil
}

func (o *Option) ListRules() ([]Rule, error) {
var rulesResp RulesResp
_, err := o.SetSuccessResult(&rulesResp).Post("https://nnr.moe/api/rules")
if err != nil {
return nil, err
}
if rulesResp.Status != 1 {
return nil, errors.New("list rules failed")
}
return rulesResp.Data, nil
}
44 changes: 44 additions & 0 deletions internal/pkg/nnr/types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// Copyright (c) 2023 ysicing(ysicing.me, ysicing@12306.work) All rights reserved.
// Use of this source code is covered by the following dual licenses:
// (1) Y PUBLIC LICENSE 1.0 (YPL 1.0)
// (2) Affero General Public License 3.0 (AGPL 3.0)
// License that can be found in the LICENSE file.

package nnr

type Server struct {
Sid string `json:"sid,omitempty"`
Name string `json:"name,omitempty"`
Host string `json:"host,omitempty"`
Mf int `json:"mf,omitempty"`
Level int `json:"level,omitempty"`
Top int `json:"top,omitempty"`
Status int `json:"status,omitempty"`
Detail string `json:"detail,omitempty"`
Types []string `json:"types,omitempty"`
}

type ServersResp struct {
Status int `json:"status,omitempty"`
Data []Server `json:"data,omitempty"`
}

type Rule struct {
Rid string `json:"rid,omitempty"`
Uid string `json:"uid,omitempty"`
Sid string `json:"sid,omitempty"`
Host string `json:"host,omitempty"`
Port int `json:"port,omitempty"`
Remote string `json:"remote,omitempty"`
RPort int `json:"rport,omitempty"`
Type string `json:"type,omitempty"`
Status int `json:"status,omitempty"`
Name string `json:"name,omitempty"`
Traffic int64 `json:"traffic,omitempty"`
Date int64 `json:"date,omitempty"`
}

type RulesResp struct {
Status int `json:"status,omitempty"`
Data []Rule `json:"data,omitempty"`
}
26 changes: 26 additions & 0 deletions internal/util/util.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Copyright (c) 2023 ysicing(ysicing.me, ysicing@12306.work) All rights reserved.
// Use of this source code is covered by the following dual licenses:
// (1) Y PUBLIC LICENSE 1.0 (YPL 1.0)
// (2) Affero General Public License 3.0 (AGPL 3.0)
// License that can be found in the LICENSE file.

package util

import (
"fmt"
"math"
)

func Traffic(k int64) string {
t := math.Round(float64(k)/1024.0/1024.0*100) / 100
tunit := "MB"
if t >= 1024.0 {
t = t / 1024.0
tunit = "GB"
}
if t >= 1024.0 {
t = t / 1024.0
tunit = "TB"
}
return fmt.Sprintf("%v%v", t, tunit)
}

0 comments on commit 17662e3

Please sign in to comment.