mirror of
https://github.com/ditatompel/xmr-remote-nodes.git
synced 2025-01-08 05:52:10 +07:00
List Probers CLI command #2
Listing probers is now only available from server CLI. The `ProbersQueryParams` struct also changed. I don't think that I will use more than 20 probers in this project, so paging is not required. The search param also simplified in one field struct `Search" which search both in `name` and `api_key` column.
This commit is contained in:
parent
49b786ed80
commit
59f1dd9421
4 changed files with 81 additions and 141 deletions
65
cmd/probers.go
Normal file
65
cmd/probers.go
Normal file
|
@ -0,0 +1,65 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
"time"
|
||||
"xmr-remote-nodes/internal/database"
|
||||
"xmr-remote-nodes/internal/repo"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var probersCmd = &cobra.Command{
|
||||
Use: "probers [search]",
|
||||
Short: "[server] Get registered probers",
|
||||
Long: `Get list of registered prober machines.
|
||||
|
||||
Use [search] args to filter results by name or api key.
|
||||
|
||||
"sort-by" flag can be "id" or "last_submit_ts"
|
||||
"sort-dir" flag can be "asc" or "desc"`,
|
||||
Example: `# To sort probers by last submit time in ascending order that contains "sin1":
|
||||
xmr-nodes probers -s last_submit_ts -d asc sin1`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if err := database.ConnectDB(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
sortBy, _ := cmd.Flags().GetString("sort-by")
|
||||
sortDir, _ := cmd.Flags().GetString("sort-dir")
|
||||
|
||||
probersRepo := repo.NewProberRepo(database.GetDB())
|
||||
probers, err := probersRepo.Probers(repo.ProbersQueryParams{
|
||||
Search: strings.Join(args, " "),
|
||||
SortBy: sortBy,
|
||||
SortDirection: sortDir,
|
||||
})
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
if len(probers) == 0 {
|
||||
fmt.Println("No probers found")
|
||||
return
|
||||
}
|
||||
w := tabwriter.NewWriter(os.Stdout, 1, 1, 1, ' ', 0)
|
||||
fmt.Fprintf(w, "ID\t| Name\t| Last Submit\t| API Key\n")
|
||||
for _, prober := range probers {
|
||||
fmt.Fprintf(w, "%d\t| %s\t| %s\t| %s\n",
|
||||
prober.Id,
|
||||
prober.Name,
|
||||
time.Unix(prober.LastSubmitTs, 0).Format(time.RFC3339),
|
||||
prober.ApiKey,
|
||||
)
|
||||
}
|
||||
w.Flush()
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(probersCmd)
|
||||
probersCmd.Flags().StringP("sort-by", "s", "last_submit_ts", "Sort by column name, can be id or last_submit_ts")
|
||||
probersCmd.Flags().StringP("sort-dir", "d", "desc", "Sort direction, can be asc or desc")
|
||||
}
|
|
@ -60,101 +60,6 @@ func Logout(c *fiber.Ctx) error {
|
|||
})
|
||||
}
|
||||
|
||||
func Prober(c *fiber.Ctx) error {
|
||||
proberRepo := repo.NewProberRepo(database.GetDB())
|
||||
|
||||
if c.Method() == "POST" {
|
||||
payload := repo.Prober{}
|
||||
if err := c.BodyParser(&payload); err != nil {
|
||||
return c.Status(fiber.StatusUnprocessableEntity).JSON(fiber.Map{
|
||||
"status": "error",
|
||||
"message": err.Error(),
|
||||
"data": nil,
|
||||
})
|
||||
}
|
||||
if payload.Name == "" {
|
||||
return c.Status(fiber.StatusUnprocessableEntity).JSON(fiber.Map{
|
||||
"status": "error",
|
||||
"message": "Please fill prober name",
|
||||
"data": nil,
|
||||
})
|
||||
}
|
||||
err := proberRepo.AddProber(payload.Name)
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||
"status": "error",
|
||||
"message": err.Error(),
|
||||
"data": nil,
|
||||
})
|
||||
}
|
||||
} else if c.Method() == "DELETE" {
|
||||
id, _ := strconv.Atoi(c.Params("id"))
|
||||
err := proberRepo.Delete(id)
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||
"status": "error",
|
||||
"message": err.Error(),
|
||||
"data": nil,
|
||||
})
|
||||
}
|
||||
|
||||
return c.JSON(fiber.Map{
|
||||
"status": "ok",
|
||||
"message": "Success",
|
||||
"data": nil,
|
||||
})
|
||||
} else if c.Method() == "PATCH" {
|
||||
payload := repo.Prober{}
|
||||
if err := c.BodyParser(&payload); err != nil {
|
||||
return c.Status(fiber.StatusUnprocessableEntity).JSON(fiber.Map{
|
||||
"status": "error",
|
||||
"message": err.Error(),
|
||||
"data": nil,
|
||||
})
|
||||
}
|
||||
if payload.Name == "" {
|
||||
return c.Status(fiber.StatusUnprocessableEntity).JSON(fiber.Map{
|
||||
"status": "error",
|
||||
"message": "Please fill prober name",
|
||||
"data": nil,
|
||||
})
|
||||
}
|
||||
id, _ := strconv.Atoi(c.Params("id"))
|
||||
err := proberRepo.Update(id, payload.Name)
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||
"status": "error",
|
||||
"message": err.Error(),
|
||||
"data": nil,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
query := repo.ProbersQueryParams{
|
||||
RowsPerPage: c.QueryInt("limit", 10),
|
||||
Page: c.QueryInt("page", 1),
|
||||
SortBy: c.Query("sort_by", "id"),
|
||||
SortDirection: c.Query("sort_direction", "desc"),
|
||||
Name: c.Query("name"),
|
||||
ApiKey: c.Query("api_key"),
|
||||
}
|
||||
|
||||
prober, err := proberRepo.Probers(query)
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||
"status": "error",
|
||||
"message": err.Error(),
|
||||
"data": nil,
|
||||
})
|
||||
}
|
||||
|
||||
return c.JSON(fiber.Map{
|
||||
"status": "ok",
|
||||
"message": "Success",
|
||||
"data": prober,
|
||||
})
|
||||
}
|
||||
|
||||
func MoneroNode(c *fiber.Ctx) error {
|
||||
nodeId, err := c.ParamsInt("id", 0)
|
||||
if err != nil {
|
||||
|
|
|
@ -12,10 +12,6 @@ func AppRoute(app *fiber.App) {
|
|||
func V1Api(app *fiber.App) {
|
||||
v1 := app.Group("/api/v1")
|
||||
|
||||
v1.Get("/prober", CookieProtected, Prober)
|
||||
v1.Post("/prober", CookieProtected, Prober)
|
||||
v1.Patch("/prober/:id", CookieProtected, Prober)
|
||||
v1.Delete("/prober/:id", CookieProtected, Prober)
|
||||
v1.Get("/crons", CookieProtected, Crons)
|
||||
v1.Get("/nodes", MoneroNodes)
|
||||
v1.Post("/nodes", AddNode)
|
||||
|
|
|
@ -12,7 +12,7 @@ import (
|
|||
type ProberRepository interface {
|
||||
AddProber(name string) error
|
||||
Update(id int, name string) error
|
||||
Probers(q ProbersQueryParams) (Probers, error)
|
||||
Probers(q ProbersQueryParams) ([]Prober, error)
|
||||
CheckApi(key string) (Prober, error)
|
||||
Delete(id int) error
|
||||
}
|
||||
|
@ -28,24 +28,6 @@ type Prober struct {
|
|||
LastSubmitTs int64 `json:"last_submit_ts" db:"last_submit_ts"`
|
||||
}
|
||||
|
||||
type ProbersQueryParams struct {
|
||||
Name string
|
||||
ApiKey string
|
||||
|
||||
RowsPerPage int
|
||||
Page int
|
||||
SortBy string
|
||||
SortDirection string
|
||||
}
|
||||
|
||||
type Probers struct {
|
||||
TotalRows int `json:"total_rows"`
|
||||
RowsPerPage int `json:"rows_per_page"`
|
||||
CurrentPage int `json:"current_page"`
|
||||
NextPage int `json:"next_page"`
|
||||
Items []*Prober `json:"items"`
|
||||
}
|
||||
|
||||
func NewProberRepo(db *database.DB) ProberRepository {
|
||||
return &ProberRepo{db}
|
||||
}
|
||||
|
@ -71,35 +53,31 @@ func (repo *ProberRepo) Delete(id int) error {
|
|||
return err
|
||||
}
|
||||
|
||||
func (repo *ProberRepo) Probers(q ProbersQueryParams) (Probers, error) {
|
||||
type ProbersQueryParams struct {
|
||||
Search string
|
||||
SortBy string
|
||||
SortDirection string
|
||||
}
|
||||
|
||||
func (repo *ProberRepo) Probers(q ProbersQueryParams) ([]Prober, error) {
|
||||
queryParams := []interface{}{}
|
||||
whereQueries := []string{}
|
||||
where := ""
|
||||
|
||||
if q.Name != "" {
|
||||
whereQueries = append(whereQueries, "name LIKE ?")
|
||||
queryParams = append(queryParams, "%"+q.Name+"%")
|
||||
}
|
||||
if q.ApiKey != "" {
|
||||
whereQueries = append(whereQueries, "api_key LIKE ?")
|
||||
queryParams = append(queryParams, "%"+q.ApiKey+"%")
|
||||
if q.Search != "" {
|
||||
whereQueries = append(whereQueries, "(name LIKE ? OR api_key LIKE ?)")
|
||||
queryParams = append(queryParams, "%"+q.Search+"%")
|
||||
queryParams = append(queryParams, "%"+q.Search+"%")
|
||||
}
|
||||
|
||||
if len(whereQueries) > 0 {
|
||||
where = "WHERE " + strings.Join(whereQueries, " AND ")
|
||||
}
|
||||
|
||||
probers := Probers{}
|
||||
queryTotalRows := fmt.Sprintf("SELECT COUNT(id) AS total_rows FROM tbl_prober %s", where)
|
||||
|
||||
err := repo.db.QueryRow(queryTotalRows, queryParams...).Scan(&probers.TotalRows)
|
||||
if err != nil {
|
||||
return probers, err
|
||||
}
|
||||
queryParams = append(queryParams, q.RowsPerPage, (q.Page-1)*q.RowsPerPage)
|
||||
probers := []Prober{}
|
||||
|
||||
allowedSort := []string{"id", "last_submit_ts"}
|
||||
sortBy := "id"
|
||||
sortBy := "last_submit_ts"
|
||||
if slices.Contains(allowedSort, q.SortBy) {
|
||||
sortBy = q.SortBy
|
||||
}
|
||||
|
@ -108,7 +86,7 @@ func (repo *ProberRepo) Probers(q ProbersQueryParams) (Probers, error) {
|
|||
sortDirection = "ASC"
|
||||
}
|
||||
|
||||
query := fmt.Sprintf("SELECT id, name, api_key, last_submit_ts FROM tbl_prober %s ORDER BY %s %s LIMIT ? OFFSET ?", where, sortBy, sortDirection)
|
||||
query := fmt.Sprintf("SELECT id, name, api_key, last_submit_ts FROM tbl_prober %s ORDER BY %s %s", where, sortBy, sortDirection)
|
||||
|
||||
row, err := repo.db.Query(query, queryParams...)
|
||||
if err != nil {
|
||||
|
@ -116,17 +94,13 @@ func (repo *ProberRepo) Probers(q ProbersQueryParams) (Probers, error) {
|
|||
}
|
||||
defer row.Close()
|
||||
|
||||
probers.RowsPerPage = q.RowsPerPage
|
||||
probers.CurrentPage = q.Page
|
||||
probers.NextPage = q.Page + 1
|
||||
|
||||
for row.Next() {
|
||||
prober := Prober{}
|
||||
err = row.Scan(&prober.Id, &prober.Name, &prober.ApiKey, &prober.LastSubmitTs)
|
||||
if err != nil {
|
||||
return probers, err
|
||||
}
|
||||
probers.Items = append(probers.Items, &prober)
|
||||
probers = append(probers, prober)
|
||||
}
|
||||
return probers, nil
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue