From a6db1787f96670ec06104f022df15b2fbcf94154 Mon Sep 17 00:00:00 2001
From: jbhusson <jonah@elixxir.io>
Date: Fri, 2 Sep 2022 14:43:19 -0400
Subject: [PATCH] Add separate isonline func for webconn

---
 connect/connection.go |  2 ++
 connect/grpcConn.go   | 20 +++++++++++++++
 connect/host.go       | 18 +-------------
 connect/webConn.go    | 57 +++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 80 insertions(+), 17 deletions(-)

diff --git a/connect/connection.go b/connect/connection.go
index c035d55..31b7464 100644
--- a/connect/connection.go
+++ b/connect/connection.go
@@ -4,6 +4,7 @@ import (
 	"git.xx.network/elixxir/grpc-web-go-client/grpcweb"
 	jww "github.com/spf13/jwalterweatherman"
 	"google.golang.org/grpc"
+	"time"
 )
 
 const (
@@ -49,6 +50,7 @@ type Connection interface {
 	// Close closes the underlying connection
 	Close() error
 
+	IsOnline() (time.Duration, bool)
 	clientConnHelpers
 }
 
diff --git a/connect/grpcConn.go b/connect/grpcConn.go
index 2dc9e6e..e9b0aba 100644
--- a/connect/grpcConn.go
+++ b/connect/grpcConn.go
@@ -8,6 +8,7 @@ import (
 	"google.golang.org/grpc"
 	"google.golang.org/grpc/connectivity"
 	"math"
+	"net"
 	"sync/atomic"
 	"time"
 )
@@ -148,3 +149,22 @@ func (gc *grpcConn) isAlive() bool {
 	return state == connectivity.Idle || state == connectivity.Connecting ||
 		state == connectivity.Ready
 }
+
+func (gc *grpcConn) IsOnline() (time.Duration, bool) {
+	addr := gc.h.GetAddress()
+	start := time.Now()
+	conn, err := net.DialTimeout("tcp", addr, gc.h.params.PingTimeout)
+	if err != nil {
+		// If we cannot connect, mark the connection as failed
+		jww.DEBUG.Printf("Failed to verify connectivity for address %s", addr)
+		return 0, false
+	}
+	// Attempt to close the connection
+	if conn != nil {
+		errClose := conn.Close()
+		if errClose != nil {
+			jww.DEBUG.Printf("Failed to close connection for address %s", addr)
+		}
+	}
+	return time.Since(start), true
+}
diff --git a/connect/host.go b/connect/host.go
index 681f27e..3c5ee9b 100644
--- a/connect/host.go
+++ b/connect/host.go
@@ -22,7 +22,6 @@ import (
 	"gitlab.com/xx_network/primitives/rateLimiting"
 	"google.golang.org/grpc/credentials"
 	"math"
-	"net"
 	"strings"
 	"sync"
 	"sync/atomic"
@@ -251,22 +250,7 @@ func (h *Host) conditionalDisconnect(count uint64) {
 // before the timeout by attempting to dial a tcp connection
 // Returns how long the ping took, and whether it was successful
 func (h *Host) IsOnline() (time.Duration, bool) {
-	addr := h.GetAddress()
-	start := time.Now()
-	conn, err := net.DialTimeout("tcp", addr, h.params.PingTimeout)
-	if err != nil {
-		// If we cannot connect, mark the connection as failed
-		jww.DEBUG.Printf("Failed to verify connectivity for address %s", addr)
-		return 0, false
-	}
-	// Attempt to close the connection
-	if conn != nil {
-		errClose := conn.Close()
-		if errClose != nil {
-			jww.DEBUG.Printf("Failed to close connection for address %s", addr)
-		}
-	}
-	return time.Since(start), true
+	return h.connection.IsOnline()
 }
 
 // send checks that the host has a connection and sends if it does.
diff --git a/connect/webConn.go b/connect/webConn.go
index c19d435..82bf288 100644
--- a/connect/webConn.go
+++ b/connect/webConn.go
@@ -1,11 +1,15 @@
 package connect
 
 import (
+	"crypto/tls"
 	"fmt"
 	"git.xx.network/elixxir/grpc-web-go-client/grpcweb"
 	"github.com/pkg/errors"
 	jww "github.com/spf13/jwalterweatherman"
 	"google.golang.org/grpc"
+	"net/http"
+	"net/http/httptrace"
+	"strings"
 	"time"
 )
 
@@ -163,3 +167,56 @@ func (wc *webConn) isAlive() bool {
 	}
 	return wc.connection.IsAlive()
 }
+
+func (wc *webConn) IsOnline() (time.Duration, bool) {
+	addr := wc.h.GetAddress()
+	start := time.Now()
+	tr := &http.Transport{
+		TLSClientConfig: &tls.Config{
+			InsecureSkipVerify: true,
+		},
+	}
+	client := http.Client{
+		Transport: tr,
+		Timeout:   wc.h.params.PingTimeout,
+	}
+	req, err := http.NewRequest("GET", addr, nil)
+	if err != nil {
+		fmt.Print("Failed to initiate request ", err)
+	}
+
+	trace := &httptrace.ClientTrace{
+		DNSDone: func(dnsInfo httptrace.DNSDoneInfo) {
+			fmt.Println("DNS Info: %+v\n", dnsInfo)
+		},
+		GotConn: func(connInfo httptrace.GotConnInfo) {
+			fmt.Println("Got Conn: %+v\n", connInfo)
+		},
+		GotFirstResponseByte: func() {
+			fmt.Println("Got first byte!")
+		},
+	}
+
+	// IMPORTANT - enables better HTTP(S) discovery, because many browsers block CORS by default.
+	req.Header.Add("js.fetch:mode", "no-cors")
+	fmt.Println("(GO request): ", fmt.Sprintf("%+v", req))
+
+	req = req.WithContext(httptrace.WithClientTrace(req.Context(), trace))
+	if _, err := client.Do(req); err != nil {
+		fmt.Println(err)
+		fmt.Println("(GO error): ", err.Error())
+
+		// TODO: Get more exception strings for major browsers
+		errString := strings.ToLower(err.Error())
+		if strings.Contains(errString, "exceeded while awaiting") ||
+			strings.Contains(errString, "ssl") ||
+			strings.Contains(errString, "cors") ||
+			strings.Contains(errString, "invalid") ||
+			strings.Contains(errString, "protocol") {
+			return time.Since(start), true
+		} else {
+			return time.Since(start), false
+		}
+	}
+	return time.Since(start), true
+}
-- 
GitLab