mirror of
https://github.com/ditatompel/xmr-remote-nodes.git
synced 2024-12-23 12:09:47 +00:00
Basic add node action implemented
This commit is contained in:
parent
92acb52aac
commit
7cd802e640
4 changed files with 158 additions and 28 deletions
|
@ -1,26 +1,41 @@
|
||||||
<script>
|
<script>
|
||||||
import { applyAction, enhance } from '$app/forms';
|
import { invalidateAll, goto } from '$app/navigation';
|
||||||
import { slide } from 'svelte/transition';
|
import { apiUri } from '$lib/utils/common';
|
||||||
import { ProgressBar } from '@skeletonlabs/skeleton';
|
import { ProgressBar } from '@skeletonlabs/skeleton';
|
||||||
/** @type {import('./$types').PageData} */
|
/** @type {import('./$types').PageData} */
|
||||||
export let data;
|
export let data;
|
||||||
|
|
||||||
/** @type {import('./$types').ActionData} */
|
/**
|
||||||
export let form;
|
* @typedef formResult
|
||||||
|
* @type {object}
|
||||||
|
* @property {string} status
|
||||||
|
* @property {string} message
|
||||||
|
* @property {null | object} data
|
||||||
|
*/
|
||||||
|
/** @type {formResult} */
|
||||||
|
export let formResult;
|
||||||
|
|
||||||
let isProcessing = false;
|
let isProcessing = false;
|
||||||
|
|
||||||
/** @type {import('./$types').SubmitFunction} */
|
/** @param {{ currentTarget: EventTarget & HTMLFormElement}} event */
|
||||||
const handleForm = async () => {
|
async function handleSubmit(event) {
|
||||||
isProcessing = true;
|
isProcessing = true;
|
||||||
return async ({ result }) => {
|
const data = new FormData(event.currentTarget);
|
||||||
isProcessing = false;
|
|
||||||
if (result.type === 'success' || result.type === 'redirect') {
|
const response = await fetch(event.currentTarget.action, {
|
||||||
close();
|
method: 'POST',
|
||||||
}
|
body: data
|
||||||
await applyAction(result);
|
});
|
||||||
};
|
|
||||||
};
|
formResult = await response.json();
|
||||||
|
isProcessing = false;
|
||||||
|
|
||||||
|
if (formResult.status === 'ok') {
|
||||||
|
// rerun all `load` functions, following the successful update
|
||||||
|
await invalidateAll();
|
||||||
|
goto('/remote-nodes');
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<header id="hero" class="hero-gradient py-7">
|
<header id="hero" class="hero-gradient py-7">
|
||||||
|
@ -37,7 +52,12 @@
|
||||||
<div class="section-container text-center">
|
<div class="section-container text-center">
|
||||||
<p>Enter your Monero node information below (IPv4 host only):</p>
|
<p>Enter your Monero node information below (IPv4 host only):</p>
|
||||||
|
|
||||||
<form class="mx-auto w-full max-w-3xl py-2" method="POST" use:enhance={handleForm}>
|
<form
|
||||||
|
class="mx-auto w-full max-w-3xl py-2"
|
||||||
|
action={apiUri('/api/v1/nodes')}
|
||||||
|
method="POST"
|
||||||
|
on:submit|preventDefault={handleSubmit}
|
||||||
|
>
|
||||||
<div class="grid grid-cols-1 gap-4 py-6 md:grid-cols-4">
|
<div class="grid grid-cols-1 gap-4 py-6 md:grid-cols-4">
|
||||||
<label class="label">
|
<label class="label">
|
||||||
<span>Protocol *</span>
|
<span>Protocol *</span>
|
||||||
|
@ -50,7 +70,7 @@
|
||||||
<span>Host / IP *</span>
|
<span>Host / IP *</span>
|
||||||
<input
|
<input
|
||||||
class="input variant-form-material"
|
class="input variant-form-material"
|
||||||
name="host"
|
name="hostname"
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="Eg: node.example.com or 172.16.17.18"
|
placeholder="Eg: node.example.com or 172.16.17.18"
|
||||||
disabled={isProcessing}
|
disabled={isProcessing}
|
||||||
|
@ -74,24 +94,23 @@
|
||||||
|
|
||||||
<div class="mx-auto w-full max-w-3xl py-2">
|
<div class="mx-auto w-full max-w-3xl py-2">
|
||||||
{#if !isProcessing}
|
{#if !isProcessing}
|
||||||
{#if form?.status === 'error'}
|
{#if formResult?.status === 'error'}
|
||||||
<div class="alert variant-ghost-error" transition:slide={{ duration: 500 }}>
|
<div class="mx-4 p-4 mb-4 text-sm rounded-lg bg-gray-700 text-red-400" role="alert">
|
||||||
<div class="alert-message">
|
<span class="font-medium">Error:</span>
|
||||||
<h3 class="h3">Error!</h3>
|
{formResult.message}!
|
||||||
<p>{form.message}!</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
{#if form?.status === 'ok'}
|
{#if formResult?.status === 'ok'}
|
||||||
<div class="alert variant-ghost-success" transition:slide={{ duration: 500 }}>
|
<div class="mx-4 p-4 mb-4 text-sm rounded-lg bg-gray-700 text-green-400" role="alert">
|
||||||
<div class="alert-message">
|
<span class="font-medium">Success:</span>
|
||||||
<h3 class="h3">Success!</h3>
|
{formResult.message}!
|
||||||
<p>{form.message}!</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
{:else}
|
{:else}
|
||||||
<ProgressBar meter="bg-secondary-500" track="bg-secondary-500/30" value={undefined} />
|
<ProgressBar meter="bg-secondary-500" track="bg-secondary-500/30" value={undefined} />
|
||||||
|
<div class="mx-4 p-4 mb-4 text-sm rounded-lg bg-gray-700 text-blue-400" role="alert">
|
||||||
|
<span class="font-medium">Processing...</span>
|
||||||
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ package handler
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ditatompel/xmr-nodes/internal/database"
|
"github.com/ditatompel/xmr-nodes/internal/database"
|
||||||
|
@ -114,6 +115,36 @@ func Prober(c *fiber.Ctx) error {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func AddNode(c *fiber.Ctx) error {
|
||||||
|
formPort := c.FormValue("port")
|
||||||
|
port, err := strconv.Atoi(formPort)
|
||||||
|
if err != nil {
|
||||||
|
return c.JSON(fiber.Map{
|
||||||
|
"status": "error",
|
||||||
|
"message": "Invalid port number",
|
||||||
|
"data": nil,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
protocol := c.FormValue("protocol")
|
||||||
|
hostname := c.FormValue("hostname")
|
||||||
|
|
||||||
|
moneroRepo := repo.NewMoneroRepo(database.GetDB())
|
||||||
|
if err := moneroRepo.Add(protocol, hostname, uint(port)); err != nil {
|
||||||
|
return c.JSON(fiber.Map{
|
||||||
|
"status": "error",
|
||||||
|
"message": err.Error(),
|
||||||
|
"data": nil,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.JSON(fiber.Map{
|
||||||
|
"status": "ok",
|
||||||
|
"message": "Query Ok",
|
||||||
|
"data": nil,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func Crons(c *fiber.Ctx) error {
|
func Crons(c *fiber.Ctx) error {
|
||||||
cronRepo := repo.NewCron(database.GetDB())
|
cronRepo := repo.NewCron(database.GetDB())
|
||||||
|
|
||||||
|
|
|
@ -14,5 +14,6 @@ func V1Api(app *fiber.App) {
|
||||||
|
|
||||||
v1.Get("/prober", Prober)
|
v1.Get("/prober", Prober)
|
||||||
v1.Post("/prober", Prober)
|
v1.Post("/prober", Prober)
|
||||||
|
v1.Post("/nodes", AddNode)
|
||||||
v1.Get("/crons", Crons)
|
v1.Get("/crons", Crons)
|
||||||
}
|
}
|
||||||
|
|
79
internal/repo/monero.go
Normal file
79
internal/repo/monero.go
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
package repo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"net"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/ditatompel/xmr-nodes/internal/database"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MoneroRepository interface {
|
||||||
|
Add(protocol string, host string, port uint) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type MoneroRepo struct {
|
||||||
|
db *database.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewMoneroRepo(db *database.DB) MoneroRepository {
|
||||||
|
return &MoneroRepo{db}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (repo *MoneroRepo) Add(protocol string, hostname string, port uint) error {
|
||||||
|
if protocol != "http" && protocol != "https" {
|
||||||
|
return errors.New("Invalid protocol, must one of or HTTP/HTTPS")
|
||||||
|
}
|
||||||
|
|
||||||
|
if port > 65535 || port < 1 {
|
||||||
|
return errors.New("Invalid port number")
|
||||||
|
}
|
||||||
|
|
||||||
|
is_tor := false
|
||||||
|
if strings.HasSuffix(hostname, ".onion") {
|
||||||
|
is_tor = true
|
||||||
|
}
|
||||||
|
ip := ""
|
||||||
|
|
||||||
|
if !is_tor {
|
||||||
|
hostIps, err := net.LookupIP(hostname)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
hostIp := hostIps[0].To4()
|
||||||
|
if hostIp == nil {
|
||||||
|
return errors.New("Host IP is not IPv4")
|
||||||
|
}
|
||||||
|
if hostIp.IsPrivate() {
|
||||||
|
return errors.New("IP address is private")
|
||||||
|
}
|
||||||
|
if hostIp.IsLoopback() {
|
||||||
|
return errors.New("IP address is loopback address")
|
||||||
|
}
|
||||||
|
|
||||||
|
ip = hostIp.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
check := `SELECT id FROM tbl_node WHERE protocol = ? AND hostname = ? AND port = ? LIMIT 1`
|
||||||
|
row, err := repo.db.Query(check, protocol, hostname, port)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer row.Close()
|
||||||
|
|
||||||
|
if row.Next() {
|
||||||
|
return errors.New("Node already monitored")
|
||||||
|
}
|
||||||
|
statusDb, _ := json.Marshal([5]int{2, 2, 2, 2, 2})
|
||||||
|
|
||||||
|
query := `INSERT INTO tbl_node (protocol, hostname, port, is_tor, nettype, ip_addr, lat, lon, date_entered, last_checked, last_check_status) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
|
||||||
|
_, err = repo.db.Exec(query, protocol, hostname, port, is_tor, "", ip, 0, 0, time.Now().Unix(), 0, string(statusDb))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
Loading…
Reference in a new issue