Skip to content

Commit

Permalink
merge
Browse files Browse the repository at this point in the history
  • Loading branch information
davidnewhall committed Apr 18, 2024
2 parents 1312822 + 1487f12 commit 7402c23
Show file tree
Hide file tree
Showing 6 changed files with 78 additions and 77 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ require (
golift.io/cnfgfile v0.0.0-20230531075023-f880041cc0a0
golift.io/datacounter v1.0.4
golift.io/deluge v0.10.1
golift.io/mulery v0.0.7-0.20240417234159-5d2a1b2f43fb
golift.io/mulery v0.0.8
golift.io/nzbget v0.1.5
golift.io/qbit v0.0.0-20240407164833-5de994cfd55e
golift.io/rotatorr v0.0.0-20230911015553-cd2abbd726c7
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -445,8 +445,8 @@ golift.io/datacounter v1.0.4 h1:b2gLQCs8WYRtKjOMG0qM82rF1o0+oKUXB9QH7kjmxZ4=
golift.io/datacounter v1.0.4/go.mod h1:79Yf1ucynYvZzVS/hpfrAFt6y/w82FMlOJgh+MBaZvs=
golift.io/deluge v0.10.1 h1:wu1GzXsDYzWGnRl4mNEd2IeY0O7+jhYJ4IKBPfDEanM=
golift.io/deluge v0.10.1/go.mod h1:i6h0V+nRzG4XymHQ5kC4d4Z6JZw2M83gMqcZhWgiD1k=
golift.io/mulery v0.0.7-0.20240417234159-5d2a1b2f43fb h1:7+ZDYnyyTnSUsHoPji8lh8I39R7YzNTkFBaa4p4p95A=
golift.io/mulery v0.0.7-0.20240417234159-5d2a1b2f43fb/go.mod h1:4qn4yK/A4GdSKjl4pKBK0ORVHTF466Zfsy8YI0+9dps=
golift.io/mulery v0.0.8 h1:0D57orumzv9QORLLfTi4ao7uIACSyXkGSze32xLc04Q=
golift.io/mulery v0.0.8/go.mod h1:4qn4yK/A4GdSKjl4pKBK0ORVHTF466Zfsy8YI0+9dps=
golift.io/nzbget v0.1.5 h1:TE/TPldaLr/Qy5wy+7R4Lvur1SosOpjTLs6BLK3TMrU=
golift.io/nzbget v0.1.5/go.mod h1:YYGQsadsgvadzM6qlVBS21gz8DBhfbxexGMndsGelj8=
golift.io/qbit v0.0.0-20240407164833-5de994cfd55e h1:MUKqgMVV3RuXrWXQoDUD2sqWX6kAL3qHa/7nZpL5mGc=
Expand Down
17 changes: 9 additions & 8 deletions pkg/bindata/files/js/tunnel.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@

function pingTunnels() {
$("#tunnel-ping-spinner").show()
$("#tunnel-ping-spinner").show();
$.ajax({
type: 'GET',
url: URLBase+'tunnel/ping',
success: function (data){
toast('Tunnel Ping', "See response times on the right side of the list.", 'success');
$("#tunnel-ping-spinner").hide()
toast('Tunnel Ping', "Find the response times in the primary tunnel list.", 'success');
$("#tunnel-ping-spinner").hide();
const obj = JSON.parse(data)
for(var idx in obj) {
// loop data and update each tunnel with the ping time.
Expand All @@ -16,7 +16,7 @@ function pingTunnels() {
}
},
error: function (response, status, error) {
$("#tunnel-ping-spinner").hide()
$("#tunnel-ping-spinner").hide();
if (response.status == 0) {
toast('Web Server Error',
'Notifiarr client appears to be down! Hard refresh recommended.', 'error', 30000);
Expand All @@ -28,17 +28,18 @@ function pingTunnels() {
}

function saveTunnels() {
$("#tunnel-save-spinner").show()
$("#tunnel-save-spinner").show();
$.ajax({
type: 'POST',
url: URLBase+'tunnel/save',
data: $(".tunnel-param").serialize(),
success: function (data){
toast('Tunnels Saved', data, 'success');
$("#tunnel-save-spinner").hide()
$("#tunnel-save-spinner").hide();
refreshPage('tunnel', false);
},
error: function (response, status, error) {
$("#tunnel-save-spinner").hide()
$("#tunnel-save-spinner").hide();
if (response.status == 0) {
toast('Web Server Error',
'Notifiarr client appears to be down! Hard refresh recommended.', 'error', 30000);
Expand All @@ -47,4 +48,4 @@ function saveTunnels() {
}
}
});
}
}
51 changes: 28 additions & 23 deletions pkg/bindata/templates/tunnel.html
Original file line number Diff line number Diff line change
@@ -1,55 +1,60 @@
<h1><i class="fas fa-satellite"></i> Site Tunnel</h1>
<p>
This client keeps a persistent websocket connection to a notifiarr.com
This client keeps a persistent websocket connection to a notifiarr.com
<a href="https://github.com/golift/mulery">Mulery</a> tunnel.
This tunnel allows the website to make requests to your client without the need
for opening a port, or having a static IP. This page allows you to select your
primary tunnel and which tunnels you want to use as backups in case the primary
primary tunnel and which tunnel you wish to use as backup in case the primary
becomes inaccessible.
</p>
<p>
Click the Ping button, and select the tunnel with the fastest response time as your primary.
Select one or two tunnels as backups. Again, choose one with a faster response time.
The primary tunnel may also be selected in the backup tunnel list. That's expected and normal.
Click the <span class="text-brand">Ping</span> button, and select the tunnel with the fastest response time as your primary.
Select any other tunnel as backup. Again, choose one with a faster response time.
</p>
<p>
<li><i class="fas fa-star text-dgrey"></i> Active Tunnel: <b>{{(cache "activeTunnel").Data}}</b></li>
</p>

<p></p>
<hr>

<div class="row">
<div class="col-sm-12 text-center">
Primary Tunnel
</div>
<div class="col-sm-12">
<select name="primaryTunnel" class="tunnel-param form-control input-sm">
{{- range $mule := .ClientInfo.User.Mulery}}
{{$primary := (eq $mule.Socket (index $.Tunnel.Targets 0))}}
<option value="{{$mule.Socket}}"{{if $primary}} selected{{end}}>
{{$mule.Socket}}{{if $primary}} (current primary){{end}}
</option>
{{- end}}
</select>
</div>

<div class="col-sm-12 text-center">
Backup Tunnel
</div>
<div class="col-sm-12">
<form class="form-inline">
<div class="form-group" style="width:100%">
{{- range $idx, $mule := .ClientInfo.User.Mulery}}
{{$primary := and (gt (len $.ClientInfo.User.Tunnels) 0) (eq (index $.ClientInfo.User.Tunnels 0) $mule.Socket)}}
<div class="input-group" style="width:100%">
<div style="width:30px; max-width:30px;" class="input input-group-addon input-sm">
<input type="checkbox" value="{{$mule.Socket}}" class="tunnel-param" name="backupTunnel"{{if $.ClientInfo.User.Tunnels.Has $mule.Socket}} checked{{end}}>
</div>
<input readonly value="{{$mule.Socket}}" class="input form-control input-sm" type="text">
<div style="width:80px;" class="input-group-addon input-sm">
<span class="text-warning text-center" id="tunnel-ping{{$idx}}"></span>
</div>
<div style="width:30px; max-width:30px;" class="input input-group-addon input-sm">
<input type="radio" value="{{$mule.Socket}}" class="tunnel-param" name="primaryTunnel"{{if $primary}} checked{{end}}>
</div>
<input readonly value="{{$mule.Socket}}" class="input form-control input-sm" type="text">
</div>
{{- end}}
</div>
</form>
</div>
<div class="col-sm-12 text-center">
Backup Tunnel
</div>
<div class="col-sm-12">
<select name="backupTunnel" class="tunnel-param form-control input-sm">
{{- range $mule := .ClientInfo.User.Mulery}}
{{$backup := and (gt (len $.ClientInfo.User.Tunnels) 1) (eq (index $.ClientInfo.User.Tunnels 1) $mule.Socket)}}
<option value="{{$mule.Socket}}"{{if $backup}} selected{{end}}>
{{$mule.Socket}}
</option>
{{- end}}
</select>
</div>

<div class="col-sm-12 mt">
<button class="btn btn-brand btn-sm" onClick="pingTunnels();">Ping</button>
<button class="btn btn-success btn-sm" onClick="saveTunnels();">Save</button>
<span id="tunnel-ping-spinner" style="display:none;"><i class="fas fa-cog fa-spin"></i> Pinging ...</span>
Expand Down
67 changes: 37 additions & 30 deletions pkg/client/tunnel.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"time"

"github.com/Notifiarr/notifiarr/pkg/mnd"
"github.com/Notifiarr/notifiarr/pkg/triggers/data"
"github.com/Notifiarr/notifiarr/pkg/website"
"github.com/Notifiarr/notifiarr/pkg/website/clientinfo"
"github.com/gorilla/schema"
Expand Down Expand Up @@ -114,6 +115,7 @@ func (c *Client) roundRobinConfig(ci *clientinfo.ClientInfo) *mulery.RoundRobinC
return &mulery.RoundRobinConfig{
RetryInterval: interval,
Callback: func(_ context.Context, socket string) {
data.Save("activeTunnel", socket)
// Tell the website we connected to a new tunnel, so it knows how to reach us.
c.website.SendData(&website.Request{
Route: website.TunnelRoute,
Expand Down Expand Up @@ -207,7 +209,7 @@ func (l *tunnelLogger) Printf(format string, v ...interface{}) {
l.Logger.Printf(format, v...)
}

const pingTimeout = 2 * time.Second
const pingTimeout = 7 * time.Second

// pingTunnels is a gui request to check timing to each tunnel.
func (c *Client) pingTunnels(response http.ResponseWriter, request *http.Request) {
Expand Down Expand Up @@ -239,67 +241,72 @@ func (c *Client) pingTunnels(response http.ResponseWriter, request *http.Request
wait.Add(1)
time.Sleep(70 * time.Millisecond) //nolint:gomnd

client := &http.Client{}

go func(ctx context.Context, idx int) {
ctx, cancel := context.WithTimeout(ctx, pingTimeout)
defer cancel()
go c.pingTunnel(request.Context(), idx, tunnel.Socket, inCh)
}

req, err := http.NewRequestWithContext(ctx, http.MethodGet,
strings.Replace(tunnel.Socket, "wss://", "https://", 1), nil)
if err != nil {
c.Errorf("Pinging Tunnel: making request: %v", err)
return
}
wait.Wait()

start := time.Now()
if err := json.NewEncoder(response).Encode(list); err != nil {
c.Errorf("Pinging Tunnel: encoding json: %v", err)
}
}

if resp, err := client.Do(req); err == nil {
_, _ = io.Copy(io.Discard, resp.Body)
resp.Body.Close()
}
func (c *Client) pingTunnel(ctx context.Context, idx int, socket string, inCh chan map[int]string) {
ctx, cancel := context.WithTimeout(ctx, pingTimeout)
defer cancel()

inCh <- map[int]string{idx: time.Since(start).Round(time.Millisecond / 10).String()} //nolint:gomnd
}(request.Context(), idx)
req, err := http.NewRequestWithContext(ctx, http.MethodGet,
strings.Replace(socket, "wss://", "https://", 1), nil)
if err != nil {
c.Errorf("Pinging Tunnel: creating request: %v", err)
return
}

wait.Wait()
start := time.Now()

if err := json.NewEncoder(response).Encode(list); err != nil {
c.Errorf("Pinging Tunnel: encoding json: %v", err)
resp, err := http.DefaultClient.Do(req)
if err != nil {
c.Errorf("Pinging Tunnel: making request: %v", err)
inCh <- map[int]string{idx: "error"}

return
}
defer resp.Body.Close()

_, _ = io.Copy(io.Discard, resp.Body)
inCh <- map[int]string{idx: time.Since(start).Round(time.Millisecond).String()}
}

func (c *Client) saveTunnels(response http.ResponseWriter, request *http.Request) {
input, _ := io.ReadAll(request.Body)
body, _ := io.ReadAll(request.Body)

type tunnelS struct {
PrimaryTunnel string
BackupTunnel []string
}

var data tunnelS
var input tunnelS

decodedValue, err := url.ParseQuery(string(input))
decodedValue, err := url.ParseQuery(string(body))
if err != nil {
c.Errorf("Saving Tunnel: parsing request: %v", err)
http.Error(response, err.Error(), http.StatusInternalServerError)

return
}

err = schema.NewDecoder().Decode(&data, decodedValue)
err = schema.NewDecoder().Decode(&input, decodedValue)
if err != nil {
c.Errorf("Saving Tunnel: decoding request: %v", err)
http.Error(response, err.Error(), http.StatusInternalServerError)

return
}

sockets := []string{data.PrimaryTunnel}
sockets := []string{input.PrimaryTunnel}

for _, socket := range data.BackupTunnel {
if socket != data.PrimaryTunnel {
for _, socket := range input.BackupTunnel {
if socket != input.PrimaryTunnel {
sockets = append(sockets, socket)
}
}
Expand All @@ -320,5 +327,5 @@ func (c *Client) saveTunnels(response http.ResponseWriter, request *http.Request
c.makeTunnel(tl.ctx, ci) //nolint:contextcheck // these cannot be inherited from the http request.
c.tunnel.Start(tl.ctx) //nolint:contextcheck
http.Error(response, fmt.Sprintf("saved tunnel config. primary: %s, %d backups",
data.PrimaryTunnel, len(data.BackupTunnel)), http.StatusOK)
input.PrimaryTunnel, len(input.BackupTunnel)), http.StatusOK)
}
14 changes: 1 addition & 13 deletions pkg/website/clientinfo/clientinfo.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ type ClientInfo struct {
// It's just for info/debug here, and not used by the client.
TunnelURL string `json:"tunnelUrl"`
// This is the list of tunnels the website tells the client to connect to.
Tunnels Tunnels `json:"tunnels"`
Tunnels []string `json:"tunnels"`
// List of tunnels that notifiarr.com recognizes.
// Any of these may be used.
Mulery []*MuleryServer `json:"mulery"`
Expand All @@ -50,18 +50,6 @@ type ClientInfo struct {
} `json:"actions"`
}

type Tunnels []string

func (t Tunnels) Has(socket string) bool {
for _, tunnel := range t {
if tunnel == socket {
return true
}
}

return false
}

// MuleryServer is data from the website. It's a tunnel's https and wss urls.
type MuleryServer struct {
Tunnel string `json:"tunnel"` // ex: "https://africa.notifiarr.com/"
Expand Down

0 comments on commit 7402c23

Please sign in to comment.