Browse Source

auto update script executed

Toby Chui 1 year ago
parent
commit
609cd55efb
10 changed files with 258 additions and 102 deletions
  1. 2 1
      api.go
  2. 0 39
      handlers.go
  3. 97 0
      helpers.go
  4. 14 8
      main.go
  5. 35 0
      mod/dynamicproxy/dynamicproxy.go
  6. 30 4
      mod/uptime/uptime.go
  7. 26 0
      reverseproxy.go
  8. 16 48
      web/components/uptime.html
  9. 0 2
      web/index.html
  10. 38 0
      web/main.css

+ 2 - 1
api.go

@@ -68,9 +68,10 @@ func initAPIs() {
 	authRouter.HandleFunc("/api/blacklist/ip/remove", handleIpBlacklistRemove)
 	authRouter.HandleFunc("/api/blacklist/enable", handleBlacklistEnable)
 
-	//Statistic API
+	//Statistic & uptime monitoring API
 	authRouter.HandleFunc("/api/stats/summary", statisticCollector.HandleTodayStatLoad)
 	authRouter.HandleFunc("/api/stats/countries", HandleCountryDistrSummary)
+	authRouter.HandleFunc("/api/utm/list", HandleUptimeMonitorListing)
 	//Upnp
 	authRouter.HandleFunc("/api/upnp/discover", handleUpnpDiscover)
 	//If you got APIs to add, append them here

+ 0 - 39
handlers.go

@@ -1,39 +0,0 @@
-package main
-
-import (
-	"encoding/json"
-	"net/http"
-
-	"imuslab.com/zoraxy/mod/utils"
-)
-
-func HandleCountryDistrSummary(w http.ResponseWriter, r *http.Request) {
-	requestClientCountry := map[string]int{}
-	statisticCollector.DailySummary.RequestClientIp.Range(func(key, value interface{}) bool {
-		//Get this client country of original
-		clientIp := key.(string)
-		//requestCount := value.(int)
-
-		ci, err := geodbStore.ResolveCountryCodeFromIP(clientIp)
-		if err != nil {
-			return true
-		}
-
-		isoCode := ci.CountryIsoCode
-		if isoCode == "" {
-			//local or reserved addr
-			isoCode = "local"
-		}
-		uc, ok := requestClientCountry[isoCode]
-		if !ok {
-			//Create the counter
-			requestClientCountry[isoCode] = 1
-		} else {
-			requestClientCountry[isoCode] = uc + 1
-		}
-		return true
-	})
-
-	js, _ := json.Marshal(requestClientCountry)
-	utils.SendJSONResponse(w, string(js))
-}

+ 97 - 0
helpers.go

@@ -0,0 +1,97 @@
+package main
+
+import (
+	"encoding/json"
+	"net/http"
+
+	"imuslab.com/zoraxy/mod/dynamicproxy"
+	"imuslab.com/zoraxy/mod/uptime"
+	"imuslab.com/zoraxy/mod/utils"
+)
+
+/*
+	Statistic Summary
+*/
+//Handle conversion of statistic daily summary to country summary
+func HandleCountryDistrSummary(w http.ResponseWriter, r *http.Request) {
+	requestClientCountry := map[string]int{}
+	statisticCollector.DailySummary.RequestClientIp.Range(func(key, value interface{}) bool {
+		//Get this client country of original
+		clientIp := key.(string)
+		//requestCount := value.(int)
+
+		ci, err := geodbStore.ResolveCountryCodeFromIP(clientIp)
+		if err != nil {
+			return true
+		}
+
+		isoCode := ci.CountryIsoCode
+		if isoCode == "" {
+			//local or reserved addr
+			isoCode = "local"
+		}
+		uc, ok := requestClientCountry[isoCode]
+		if !ok {
+			//Create the counter
+			requestClientCountry[isoCode] = 1
+		} else {
+			requestClientCountry[isoCode] = uc + 1
+		}
+		return true
+	})
+
+	js, _ := json.Marshal(requestClientCountry)
+	utils.SendJSONResponse(w, string(js))
+}
+
+/*
+	Up Time Monitor
+*/
+//Generate uptime monitor targets from reverse proxy rules
+func GetUptimeTargetsFromReverseProxyRules(dp *dynamicproxy.Router) []*uptime.Target {
+	subds := dp.GetSDProxyEndpointsAsMap()
+	vdirs := dp.GetVDProxyEndpointsAsMap()
+
+	UptimeTargets := []*uptime.Target{}
+	for subd, target := range subds {
+		url := "http://" + target.Domain
+		protocol := "http"
+		if target.RequireTLS {
+			url = "https://" + target.Domain
+			protocol = "https"
+		}
+		UptimeTargets = append(UptimeTargets, &uptime.Target{
+			ID:       subd,
+			Name:     subd,
+			URL:      url,
+			Protocol: protocol,
+		})
+	}
+
+	for vdir, target := range vdirs {
+		url := "http://" + target.Domain
+		protocol := "http"
+		if target.RequireTLS {
+			url = "https://" + target.Domain
+			protocol = "https"
+		}
+		UptimeTargets = append(UptimeTargets, &uptime.Target{
+			ID:       vdir,
+			Name:     "*" + vdir,
+			URL:      url,
+			Protocol: protocol,
+		})
+	}
+
+	return UptimeTargets
+}
+
+//Handle rendering up time monitor data
+func HandleUptimeMonitorListing(w http.ResponseWriter, r *http.Request) {
+	if uptimeMonitor != nil {
+		uptimeMonitor.HandleUptimeLogRead(w, r)
+	} else {
+		http.Error(w, "500 - Internal Server Error", http.StatusInternalServerError)
+		return
+	}
+}

+ 14 - 8
main.go

@@ -18,6 +18,7 @@ import (
 	"imuslab.com/zoraxy/mod/statistic"
 	"imuslab.com/zoraxy/mod/tlscert"
 	"imuslab.com/zoraxy/mod/upnp"
+	"imuslab.com/zoraxy/mod/uptime"
 )
 
 //General flags
@@ -28,14 +29,15 @@ var (
 	name    = "Zoraxy"
 	version = "2.1"
 
-	handler            *aroz.ArozHandler
-	sysdb              *database.Database
-	authAgent          *auth.AuthAgent
-	tlsCertManager     *tlscert.Manager
-	redirectTable      *redirection.RuleTable
-	geodbStore         *geodb.Store
-	statisticCollector *statistic.Collector
-	upnpClient         *upnp.UPnPClient
+	handler            *aroz.ArozHandler      //Handle arozos managed permission system
+	sysdb              *database.Database     //System database
+	authAgent          *auth.AuthAgent        //Authentication agent
+	tlsCertManager     *tlscert.Manager       //TLS / SSL management
+	redirectTable      *redirection.RuleTable //Handle special redirection rule sets
+	geodbStore         *geodb.Store           //GeoIP database
+	statisticCollector *statistic.Collector   //Collecting statistic from visitors
+	upnpClient         *upnp.UPnPClient       //UPnP Client for poking holes
+	uptimeMonitor      *uptime.Monitor        //Uptime monitor service worker
 )
 
 // Kill signal handler. Do something before the system the core terminate.
@@ -121,6 +123,10 @@ func main() {
 		panic(err)
 	}
 
+	if err != nil {
+		panic(err)
+	}
+
 	//Create a upnp client
 	err = initUpnp()
 	if err != nil {

+ 35 - 0
mod/dynamicproxy/dynamicproxy.go

@@ -308,3 +308,38 @@ func (router *Router) SetRootProxy(proxyLocation string, requireTLS bool) error
 	router.Root = &rootEndpoint
 	return nil
 }
+
+//Helpers to export the syncmap for easier processing
+func (r *Router) GetSDProxyEndpointsAsMap() map[string]*SubdomainEndpoint {
+	m := make(map[string]*SubdomainEndpoint)
+	r.SubdomainEndpoint.Range(func(key, value interface{}) bool {
+		k, ok := key.(string)
+		if !ok {
+			return true
+		}
+		v, ok := value.(*SubdomainEndpoint)
+		if !ok {
+			return true
+		}
+		m[k] = v
+		return true
+	})
+	return m
+}
+
+func (r *Router) GetVDProxyEndpointsAsMap() map[string]*ProxyEndpoint {
+	m := make(map[string]*ProxyEndpoint)
+	r.ProxyEndpoints.Range(func(key, value interface{}) bool {
+		k, ok := key.(string)
+		if !ok {
+			return true
+		}
+		v, ok := value.(*ProxyEndpoint)
+		if !ok {
+			return true
+		}
+		m[k] = v
+		return true
+	})
+	return m
+}

+ 30 - 4
mod/uptime/uptime.go

@@ -28,10 +28,9 @@ type Target struct {
 }
 
 type Config struct {
-	Targets       []*Target
-	Interval      int
-	RecordsInJson int
-	LogToFile     bool
+	Targets         []*Target
+	Interval        int
+	MaxRecordsStore int
 }
 
 type Monitor struct {
@@ -108,6 +107,11 @@ func (m *Monitor) ExecuteUptimeCheck() {
 			//Append to the previous record
 			thisRecords = append(thisRecords, &thisRecord)
 
+			//Check if the record is longer than the logged record. If yes, clear out the old records
+			if len(thisRecords) > m.Config.MaxRecordsStore {
+				thisRecords = thisRecords[1:]
+			}
+
 			m.OnlineStatusLog[target.ID] = thisRecords
 		}
 	}
@@ -136,6 +140,28 @@ func (m *Monitor) RemoveTargetFromMonitor(targetId string) {
 	delete(m.OnlineStatusLog, targetId)
 }
 
+//Scan the config target. If a target exists in m.OnlineStatusLog no longer
+//exists in m.Monitor.Config.Targets, it remove it from the log as well.
+func (m *Monitor) CleanRecords() {
+	// Create a set of IDs for all targets in the config
+	targetIDs := make(map[string]bool)
+	for _, target := range m.Config.Targets {
+		targetIDs[target.ID] = true
+	}
+
+	// Iterate over all log entries and remove any that have a target ID that
+	// is not in the set of current target IDs
+	newStatusLog := m.OnlineStatusLog
+	for id, _ := range m.OnlineStatusLog {
+		_, idExistsInTargets := targetIDs[id]
+		if !idExistsInTargets {
+			delete(newStatusLog, id)
+		}
+	}
+
+	m.OnlineStatusLog = newStatusLog
+}
+
 /*
 	Web Interface Handler
 */

+ 26 - 0
reverseproxy.go

@@ -11,6 +11,7 @@ import (
 	"time"
 
 	"imuslab.com/zoraxy/mod/dynamicproxy"
+	"imuslab.com/zoraxy/mod/uptime"
 	"imuslab.com/zoraxy/mod/utils"
 )
 
@@ -95,6 +96,18 @@ func ReverseProxtInit() {
 	dynamicProxyRouter.StartProxyService()
 	log.Println("Dynamic Reverse Proxy service started")
 
+	//Add all proxy services to uptime monitor
+	//Create a uptime monitor service
+	go func() {
+		//This must be done in go routine to prevent blocking on system startup
+		uptimeMonitor, _ = uptime.NewUptimeMonitor(&uptime.Config{
+			Targets:         GetUptimeTargetsFromReverseProxyRules(dynamicProxyRouter),
+			Interval:        300, //5 minutes
+			MaxRecordsStore: 288, //1 day
+		})
+		log.Println("Uptime Monitor background service started")
+	}()
+
 }
 
 func ReverseProxyHandleOnOff(w http.ResponseWriter, r *http.Request) {
@@ -178,6 +191,12 @@ func ReverseProxyHandleAddEndpoint(w http.ResponseWriter, r *http.Request) {
 	//Save it
 	SaveReverseProxyConfig(eptype, rootname, endpoint, useTLS)
 
+	//Update utm if exists
+	if uptimeMonitor != nil {
+		uptimeMonitor.Config.Targets = GetUptimeTargetsFromReverseProxyRules(dynamicProxyRouter)
+		uptimeMonitor.CleanRecords()
+	}
+
 	utils.SendOK(w)
 
 }
@@ -199,6 +218,13 @@ func DeleteProxyEndpoint(w http.ResponseWriter, r *http.Request) {
 	}
 
 	RemoveReverseProxyConfig(ep)
+
+	//Update utm if exists
+	if uptimeMonitor != nil {
+		uptimeMonitor.Config.Targets = GetUptimeTargetsFromReverseProxyRules(dynamicProxyRouter)
+		uptimeMonitor.CleanRecords()
+	}
+
 	utils.SendOK(w)
 }
 

+ 16 - 48
web/components/uptime.html

@@ -1,41 +1,4 @@
-<!-- css override -->
-<style>
-    #utm{
-        background-color: white;
-        border-radius: 1em;
-    }
-
-
-    .domain{
-        margin-bottom: 1em;
-        position: relative;
-    }
-
-    .statusDot{
-        height: 1.8em;
-        border-radius: 0.4em;
-        width: 0.4em;
-        background-color: #e8e8e8;
-        display:inline-block;
-        cursor: pointer;
-        margin-left: 0.1em;
-    }
-    
-    .online.statusDot{
-        background-color: #3bd671;
-    }
-    .error.statusDot{
-        background-color: #f29030;
-    }
-    .offline.statusDot{
-        background-color: #df484a;
-    }
-    .padding.statusDot{
-        cursor: auto;
-    }
-    
-</style>
-<div id="utm" class="ui basic segment">
+<div id="utmrender" class="ui basic segment">
     <div class="ui basic segment">
         <h4 class="ui header">
             <i class="red remove icon"></i>
@@ -46,27 +9,32 @@
         </h4> 
     </div>
 </div>
+<div align="center">
+    <button class="ui basic circular green icon button"><i class="refresh icon"></i></button>   
+</div>
+
+
 
 <script>
-    AOS.init();
-    
     function initUptimeTable(){
-        
+        $.get("/api/utm/list", function(data){
+            let records = data;
+            renderRecords(records);
+        })
     }
-    let records = JSON.parse(`<?php echo file_get_contents("http://localhost:8089/")?>`);
-    renderRecords(records);
+    initUptimeTable();
 
     //For every 5 minutes
     setInterval(function(){
-        $.get("api.php?token=fbda065b-3662-415b-af4d-41cb998e619d", function(data){
+        $.get("/api/utm/list", function(data){
             console.log("Status Updated");
             records = data;
-            renderRecords();
+            renderRecords(records);
         });
     }, (300 * 1000));
     
-    function renderRecords(){
-        $("#utm").html("");
+    function renderRecords(records){
+        $("#utmrender").html("");
         for (let [key, value] of Object.entries(records)) {
             renderUptimeData(key, value);
         }
@@ -134,7 +102,7 @@
         }
 
         //Generate the html
-        $("#utm").append(`<div class="ui basic segment statusbar">
+        $("#utmrender").append(`<div class="ui basic segment statusbar">
             <div class="domain">
                 <div style="position: absolute; top: 0; right: 0.4em;">
                     <p class="onlineStatus" style="display: inline-block; font-size: 1.3em; padding-right: 0.5em; padding-left: 0.3em; ${onlineStatusCss}">${currentOnlineStatus}</p>

+ 0 - 2
web/index.html

@@ -229,8 +229,6 @@
             $(window).on("resize", function(){
                 if (window.innerWidth >= 750 && $(".toolbar").is(":visible") == false){
                     $(".toolbar").show();
-                }else if (window.innerWidth < 750 && $(".toolbar").is(":visible") == true){
-                    $(".toolbar").hide();
                 }
             });
 

+ 38 - 0
web/main.css

@@ -41,6 +41,7 @@ body{
 
 .toolbar{
     width: 240px;
+    min-width: 240px;
 }
 
 .contentWindow{
@@ -130,3 +131,40 @@ body{
 .statustab.summary span, .statustab.summary i{
     color: rgb(37, 37, 37);
 }
+
+/*
+    Uptime Monitor
+*/
+#utm{
+    background-color: white;
+    border-radius: 1em;
+}
+
+
+.domain{
+    margin-bottom: 1em;
+    position: relative;
+}
+
+.statusDot{
+    height: 1.8em;
+    border-radius: 0.4em;
+    width: 0.4em;
+    background-color: #e8e8e8;
+    display:inline-block;
+    cursor: pointer;
+    margin-left: 0.1em;
+}
+
+.online.statusDot{
+    background-color: #3bd671;
+}
+.error.statusDot{
+    background-color: #f29030;
+}
+.offline.statusDot{
+    background-color: #df484a;
+}
+.padding.statusDot{
+    cursor: auto;
+}