added weblogger to display logs, timestamps and levels on the webpage
This commit is contained in:
		
							parent
							
								
									0498013d1d
								
							
						
					
					
						commit
						6ea4d31109
					
				| 
						 | 
					@ -5,3 +5,4 @@ build/
 | 
				
			||||||
build/*
 | 
					build/*
 | 
				
			||||||
pkg/*
 | 
					pkg/*
 | 
				
			||||||
agents/agents
 | 
					agents/agents
 | 
				
			||||||
 | 
					logs.db
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -11,6 +11,7 @@ import (
 | 
				
			||||||
	"math/rand"
 | 
						"math/rand"
 | 
				
			||||||
	"math"
 | 
						"math"
 | 
				
			||||||
	"strconv"
 | 
						"strconv"
 | 
				
			||||||
 | 
						// "gontrol/src/logger"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/gorilla/websocket"
 | 
						"github.com/gorilla/websocket"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
| 
						 | 
					@ -57,6 +58,7 @@ func registerAgent(agentName, agentId, agentIp, agentType string) error {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	log.Printf("Agent %s successfully registered.", agentName)
 | 
						log.Printf("Agent %s successfully registered.", agentName)
 | 
				
			||||||
 | 
						logger.LogEntries = append(logger.LogEntries, fmt.Sprintf("%s Agent successfully registered.", time.Now().Format(time.RFC3339)))
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -67,6 +69,7 @@ func connectToWebSocket(agentName, agentId, agentIp, agentType string) error {
 | 
				
			||||||
		conn, _, err = websocket.DefaultDialer.Dial(wsURL, nil)
 | 
							conn, _, err = websocket.DefaultDialer.Dial(wsURL, nil)
 | 
				
			||||||
		if err == nil {
 | 
							if err == nil {
 | 
				
			||||||
			log.Println("WeSocket connection established")
 | 
								log.Println("WeSocket connection established")
 | 
				
			||||||
 | 
								// logger.LogEntries = append(logger.LogEntries, fmt.Sprintf("%s websocket established", time.Now().Format(time.RFC3339)))
 | 
				
			||||||
			return nil
 | 
								return nil
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										1
									
								
								go.mod
								
								
								
								
							
							
						
						
									
										1
									
								
								go.mod
								
								
								
								
							| 
						 | 
					@ -7,6 +7,7 @@ require (
 | 
				
			||||||
	github.com/go-sql-driver/mysql v1.8.1
 | 
						github.com/go-sql-driver/mysql v1.8.1
 | 
				
			||||||
	github.com/gorilla/websocket v1.5.3
 | 
						github.com/gorilla/websocket v1.5.3
 | 
				
			||||||
	github.com/kelseyhightower/envconfig v1.4.0
 | 
						github.com/kelseyhightower/envconfig v1.4.0
 | 
				
			||||||
 | 
						github.com/mattn/go-sqlite3 v1.14.28
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
require (
 | 
					require (
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										2
									
								
								go.sum
								
								
								
								
							
							
						
						
									
										2
									
								
								go.sum
								
								
								
								
							| 
						 | 
					@ -11,6 +11,8 @@ github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aN
 | 
				
			||||||
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
 | 
					github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
 | 
				
			||||||
github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8=
 | 
					github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8=
 | 
				
			||||||
github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg=
 | 
					github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg=
 | 
				
			||||||
 | 
					github.com/mattn/go-sqlite3 v1.14.28 h1:ThEiQrnbtumT+QMknw63Befp/ce/nUPgBPMlRFEum7A=
 | 
				
			||||||
 | 
					github.com/mattn/go-sqlite3 v1.14.28/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
 | 
				
			||||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
 | 
					github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
 | 
				
			||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 | 
					golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 | 
				
			||||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
 | 
					golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										48
									
								
								main.go
								
								
								
								
							
							
						
						
									
										48
									
								
								main.go
								
								
								
								
							| 
						 | 
					@ -16,6 +16,7 @@ import (
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"gontrol/src/randomname"
 | 
						"gontrol/src/randomname"
 | 
				
			||||||
	"gontrol/src/server/database"
 | 
						"gontrol/src/server/database"
 | 
				
			||||||
 | 
						"gontrol/src/logger"
 | 
				
			||||||
	api "gontrol/src/server/api"
 | 
						api "gontrol/src/server/api"
 | 
				
			||||||
	websocketserver "gontrol/src/server/websocket"
 | 
						websocketserver "gontrol/src/server/websocket"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -25,8 +26,10 @@ import (
 | 
				
			||||||
	"github.com/kelseyhightower/envconfig"
 | 
						"github.com/kelseyhightower/envconfig"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var tmpl *template.Template
 | 
					var (
 | 
				
			||||||
var db 	 *sql.DB
 | 
						tmpl *template.Template
 | 
				
			||||||
 | 
						db 	 *sql.DB
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Config struct {
 | 
					type Config struct {
 | 
				
			||||||
	Database struct {
 | 
						Database struct {
 | 
				
			||||||
| 
						 | 
					@ -135,6 +138,24 @@ func getAgentIds(w http.ResponseWriter, r *http.Request) {
 | 
				
			||||||
	return
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func logsHandler(w http.ResponseWriter, r *http.Request) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						logs, err := logger.FetchLogs(10)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							http.Error(w, "Error fetching logs", http.StatusInternalServerError)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						fmt.Fprintf(w, "<div>")
 | 
				
			||||||
 | 
						// for _, logEntry := range logsToSend {
 | 
				
			||||||
 | 
						for _, logEntry := range logs {
 | 
				
			||||||
 | 
							fmt.Fprintf(w, "<p><strong>[%s] [%s]</strong> %s</p>", logEntry.Timestamp, logEntry.Level, logEntry.Message)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						fmt.Fprintf(w, "</div>")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func main() {
 | 
					func main() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var cfg Config
 | 
						var cfg Config
 | 
				
			||||||
| 
						 | 
					@ -153,8 +174,16 @@ func main() {
 | 
				
			||||||
	webMux.HandleFunc("/agentNames", getAgentNames)
 | 
						webMux.HandleFunc("/agentNames", getAgentNames)
 | 
				
			||||||
	webMux.HandleFunc("/agentIds", getAgentIds)
 | 
						webMux.HandleFunc("/agentIds", getAgentIds)
 | 
				
			||||||
	webMux.HandleFunc("/agents/{agentId}", agentsHandler)
 | 
						webMux.HandleFunc("/agents/{agentId}", agentsHandler)
 | 
				
			||||||
 | 
						webMux.HandleFunc("/logs", logsHandler)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Sqlite3
 | 
				
			||||||
 | 
						err := logger.InitDB("/tmp/gontrol_logs.db")
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							log.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						defer logger.CloseDB()
 | 
				
			||||||
	// initDB (cfg.Database.Username, cfg.Database.Password, cfg.Database.Host, cfg.Database.Port, cfg.Database.Name)
 | 
						// initDB (cfg.Database.Username, cfg.Database.Password, cfg.Database.Host, cfg.Database.Port, cfg.Database.Name)
 | 
				
			||||||
 | 
						// mysql
 | 
				
			||||||
	db = database.InitDB (cfg.Database.Username, cfg.Database.Password, cfg.Database.Host, cfg.Database.Port, cfg.Database.Name)
 | 
						db = database.InitDB (cfg.Database.Username, cfg.Database.Password, cfg.Database.Host, cfg.Database.Port, cfg.Database.Name)
 | 
				
			||||||
	defer db.Close()
 | 
						defer db.Close()
 | 
				
			||||||
	name := randomname.GenerateRandomName()
 | 
						name := randomname.GenerateRandomName()
 | 
				
			||||||
| 
						 | 
					@ -168,20 +197,31 @@ func main() {
 | 
				
			||||||
	wg.Add(1)
 | 
						wg.Add(1)
 | 
				
			||||||
	go func() {
 | 
						go func() {
 | 
				
			||||||
		defer wg.Done()
 | 
							defer wg.Done()
 | 
				
			||||||
		log.Println("Websocket server is running on port 5555")
 | 
							logLine := "Websocket server is running on port 5555"
 | 
				
			||||||
 | 
							log.Println(logLine)
 | 
				
			||||||
		if err := websocketServer.ListenAndServe(); err != http.ErrServerClosed {
 | 
							if err := websocketServer.ListenAndServe(); err != http.ErrServerClosed {
 | 
				
			||||||
			log.Fatalf("Websocket server failed: %s", err)
 | 
								log.Fatalf("Websocket server failed: %s", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							err = logger.InsertLog(logger.Info, logLine)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								log.Println("Error inserting log:", err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}()
 | 
						}()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wg.Add(1)
 | 
						wg.Add(1)
 | 
				
			||||||
	go func() {
 | 
						go func() {
 | 
				
			||||||
		defer wg.Done()
 | 
							defer wg.Done()
 | 
				
			||||||
		log.Println("Web server is running on port 3333")
 | 
							logLine := "Web server is running on port 3333"
 | 
				
			||||||
 | 
							log.Println(logLine)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if err := webServer.ListenAndServe(); err != http.ErrServerClosed {
 | 
							if err := webServer.ListenAndServe(); err != http.ErrServerClosed {
 | 
				
			||||||
			log.Fatalf("Web server failed: %s", err)
 | 
								log.Fatalf("Web server failed: %s", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							err = logger.InsertLog(logger.Info, logLine)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								log.Println("Error inserting log:", err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}()
 | 
						}()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	shutdownCh := make(chan os.Signal, 1)
 | 
						shutdownCh := make(chan os.Signal, 1)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,127 @@
 | 
				
			||||||
 | 
					package logger
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"database/sql"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"log"
 | 
				
			||||||
 | 
						// "net/http"
 | 
				
			||||||
 | 
						"sync"
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						_ "github.com/mattn/go-sqlite3"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var (
 | 
				
			||||||
 | 
						Lite_db *sql.DB
 | 
				
			||||||
 | 
						lite_dbMutex sync.Mutex
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						logMutex sync.Mutex
 | 
				
			||||||
 | 
						logLimit = 10
 | 
				
			||||||
 | 
						// LogEntries []string
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const (
 | 
				
			||||||
 | 
					    Debug   LogLevel = "DEBUG"
 | 
				
			||||||
 | 
					    Info    LogLevel = "INFO"
 | 
				
			||||||
 | 
					    Warning LogLevel = "WARNING"
 | 
				
			||||||
 | 
					    Error   LogLevel = "ERROR"
 | 
				
			||||||
 | 
					    Fatal   LogLevel = "FATAL"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type LogLevel string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type LogEntry struct {
 | 
				
			||||||
 | 
						Message 	string
 | 
				
			||||||
 | 
						Timestamp 	string
 | 
				
			||||||
 | 
						Level 		LogLevel
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func ToLog(logLine string) string {
 | 
				
			||||||
 | 
						log := fmt.Sprintf("%s",time.Now().Format(time.RFC3339) + " " + logLine)
 | 
				
			||||||
 | 
						return log
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func InitDB(dbPath string) error {
 | 
				
			||||||
 | 
						var err error
 | 
				
			||||||
 | 
						Lite_db, err = sql.Open("sqlite3", dbPath)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return fmt.Errorf("Error opening DB: %w", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						CreateTableQuery := `CREATE TABLE IF NOT EXISTS logs (
 | 
				
			||||||
 | 
							id INTEGER PRIMARY KEY AUTOINCREMENT,
 | 
				
			||||||
 | 
							message TEXT,
 | 
				
			||||||
 | 
							timestamp DATETIME DEFAULT CURRENT_TIMESTAMP,
 | 
				
			||||||
 | 
							level TEXT
 | 
				
			||||||
 | 
						);`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						_, err = Lite_db.Exec(CreateTableQuery)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return fmt.Errorf("Error creating table: %w", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func InsertLog(level LogLevel, message string) error {
 | 
				
			||||||
 | 
						lite_dbMutex.Lock()
 | 
				
			||||||
 | 
						defer lite_dbMutex.Unlock()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Future use may fulfill multiple transactions, a transaction is used
 | 
				
			||||||
 | 
						tx, err := Lite_db.Begin()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return fmt.Errorf("Error starting transaction: %w", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// insertQuery := `INSERT INTO logs (message) VALUES (?)`
 | 
				
			||||||
 | 
						insertQuery := `INSERT INTO logs (message, level) VALUES (?, ?)`
 | 
				
			||||||
 | 
						// _, err := Lite_db.Exec(insertQuery, message, level)
 | 
				
			||||||
 | 
						_, err = tx.Exec(insertQuery, message, level)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							tx.Rollback()
 | 
				
			||||||
 | 
							return fmt.Errorf("Error inserting log: %v", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = tx.Commit()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return fmt.Errorf("Error committing transaction: %w", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func FetchLogs(limit int) ([]LogEntry, error) {
 | 
				
			||||||
 | 
						lite_dbMutex.Lock()
 | 
				
			||||||
 | 
						defer lite_dbMutex.Unlock()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						query := `SELECT timestamp, level, message FROM logs ORDER BY timestamp DESC LIMIT ?`
 | 
				
			||||||
 | 
						rows, err := Lite_db.Query(query, limit)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return  nil, fmt.Errorf("Error fetching logs: %w", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						defer rows.Close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// var logs []string
 | 
				
			||||||
 | 
						var logs []LogEntry
 | 
				
			||||||
 | 
						for rows.Next() {
 | 
				
			||||||
 | 
							// var message string
 | 
				
			||||||
 | 
							var logEntry LogEntry
 | 
				
			||||||
 | 
							if err := rows.Scan( &logEntry.Timestamp, &logEntry.Level, &logEntry.Message); err != nil {
 | 
				
			||||||
 | 
								return nil, fmt.Errorf("Error scanning row: %w", err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							logs = append(logs, logEntry)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return logs, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func CloseDB() {
 | 
				
			||||||
 | 
						if Lite_db != nil {
 | 
				
			||||||
 | 
							err := Lite_db.Close()
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								log.Printf("Error closing database: %v", err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -6,6 +6,7 @@ import (
 | 
				
			||||||
	"encoding/json"
 | 
						"encoding/json"
 | 
				
			||||||
	"strconv"
 | 
						"strconv"
 | 
				
			||||||
	"log"
 | 
						"log"
 | 
				
			||||||
 | 
						// "gontrol/src/logger"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	_ "github.com/go-sql-driver/mysql"
 | 
						_ "github.com/go-sql-driver/mysql"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,6 +3,8 @@ package websocketserver
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"database/sql"
 | 
						"database/sql"
 | 
				
			||||||
	"encoding/json"
 | 
						"encoding/json"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"gontrol/src/logger"
 | 
				
			||||||
	"gontrol/src/randomname"
 | 
						"gontrol/src/randomname"
 | 
				
			||||||
	"gontrol/src/server/api"
 | 
						"gontrol/src/server/api"
 | 
				
			||||||
	"io"
 | 
						"io"
 | 
				
			||||||
| 
						 | 
					@ -63,7 +65,10 @@ func registerAgent(agentName, agentId, agentIp, agentType string) error {
 | 
				
			||||||
	defer resp.Body.Close()
 | 
						defer resp.Body.Close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if resp.StatusCode == http.StatusCreated {
 | 
						if resp.StatusCode == http.StatusCreated {
 | 
				
			||||||
		log.Printf("Agent %s successfully registered.", agentName)
 | 
							logLine := fmt.Sprintf("Agent %s successfully registered.", agentName)
 | 
				
			||||||
 | 
							log.Printf(logLine)
 | 
				
			||||||
 | 
							// logLine = logger.ToLog(logLine)
 | 
				
			||||||
 | 
							logger.InsertLog(logger.Info, logLine)
 | 
				
			||||||
		return nil
 | 
							return nil
 | 
				
			||||||
	} else if resp.StatusCode == http.StatusOK {
 | 
						} else if resp.StatusCode == http.StatusOK {
 | 
				
			||||||
		log.Printf("Agent %s already registered.", agentName)
 | 
							log.Printf("Agent %s already registered.", agentName)
 | 
				
			||||||
| 
						 | 
					@ -81,14 +86,14 @@ func getAgentDetails(agentId string) (*api.Agent, error) {
 | 
				
			||||||
	// var ids []string
 | 
						// var ids []string
 | 
				
			||||||
	resp, err := http.Get(agentURL)
 | 
						resp, err := http.Get(agentURL)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		log.Printf("Failed to make GET request: %w", err)
 | 
							log.Printf("Failed to make GET request: %s", err)
 | 
				
			||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	defer resp.Body.Close()
 | 
						defer resp.Body.Close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	doc, err := goquery.NewDocumentFromReader(resp.Body)
 | 
						doc, err := goquery.NewDocumentFromReader(resp.Body)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		log.Printf("Failed to parse HTML: %w", err)
 | 
							log.Printf("Failed to parse HTML: %s", err)
 | 
				
			||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -98,7 +103,7 @@ func getAgentDetails(agentId string) (*api.Agent, error) {
 | 
				
			||||||
		if strings.HasPrefix(text, "ID:") {
 | 
							if strings.HasPrefix(text, "ID:") {
 | 
				
			||||||
			agent.AgentID, err = strconv.Atoi(strings.TrimSpace(strings.TrimPrefix(text, "ID:")))
 | 
								agent.AgentID, err = strconv.Atoi(strings.TrimSpace(strings.TrimPrefix(text, "ID:")))
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				log.Printf("Converting string to integer failed in getAgentDetails(): %w", err)
 | 
									log.Printf("Converting string to integer failed in getAgentDetails(): %s", err)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		} else if strings.HasPrefix(text, "Name:") {
 | 
							} else if strings.HasPrefix(text, "Name:") {
 | 
				
			||||||
			agent.AgentName = strings.TrimSpace(strings.TrimPrefix(text, "Name:"))
 | 
								agent.AgentName = strings.TrimSpace(strings.TrimPrefix(text, "Name:"))
 | 
				
			||||||
| 
						 | 
					@ -124,7 +129,7 @@ func getAgentIds() ([]string, error) {
 | 
				
			||||||
	// var ids []string
 | 
						// var ids []string
 | 
				
			||||||
	resp, err := http.Get(idURL)
 | 
						resp, err := http.Get(idURL)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		log.Printf("Failed to make GET request: %w", err)
 | 
							log.Printf("Failed to make GET request: %s", err)
 | 
				
			||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	defer resp.Body.Close()
 | 
						defer resp.Body.Close()
 | 
				
			||||||
| 
						 | 
					@ -136,13 +141,13 @@ func getAgentIds() ([]string, error) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	body, err := io.ReadAll(resp.Body)
 | 
						body, err := io.ReadAll(resp.Body)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		log.Printf("Failed to read response body: %w", err)
 | 
							log.Printf("Failed to read response body: %s", err)
 | 
				
			||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var agentIds []string
 | 
						var agentIds []string
 | 
				
			||||||
	if err := json.Unmarshal(body, &agentIds); err != nil {
 | 
						if err := json.Unmarshal(body, &agentIds); err != nil {
 | 
				
			||||||
		log.Printf("Failed to parse JSON response: %w", err)
 | 
							log.Printf("Failed to parse JSON response: %s", err)
 | 
				
			||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -182,7 +187,9 @@ func (wsh webSocketHandler) ServeHTTP(w http.ResponseWriter, r *http.Request){
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	log.Printf("Agent %s connected: %s (%s)", agentId, agentName, agentIP)
 | 
						logLine := fmt.Sprintf("Agent %s connected: %s (%s)", agentId, agentName, agentIP)
 | 
				
			||||||
 | 
						log.Printf(logLine)
 | 
				
			||||||
 | 
						logger.InsertLog(logger.Info, logLine)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	agentSocketsMutex.Lock()
 | 
						agentSocketsMutex.Lock()
 | 
				
			||||||
	agentSockets[agentName] = c
 | 
						agentSockets[agentName] = c
 | 
				
			||||||
| 
						 | 
					@ -193,17 +200,22 @@ func (wsh webSocketHandler) ServeHTTP(w http.ResponseWriter, r *http.Request){
 | 
				
			||||||
		delete(agentSockets, agentName)
 | 
							delete(agentSockets, agentName)
 | 
				
			||||||
		agentSocketsMutex.Unlock()
 | 
							agentSocketsMutex.Unlock()
 | 
				
			||||||
		c.Close()
 | 
							c.Close()
 | 
				
			||||||
		log.Printf("Agent disconnected: %s (%s)", agentName, agentIP)
 | 
							logLine := fmt.Sprintf("Agent disconnected: %s (%s)", agentName, agentIP)
 | 
				
			||||||
 | 
							log.Printf(logLine)
 | 
				
			||||||
 | 
							logger.InsertLog(logger.Info, logLine)
 | 
				
			||||||
	}()
 | 
						}()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for {
 | 
						for {
 | 
				
			||||||
		_, message, err := c.ReadMessage()
 | 
							_, message, err := c.ReadMessage()
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			log.Printf("Error reading from agent %s: %v", agentName, err)
 | 
								logLine := fmt.Sprintf("Error reading from agent %s: %v", agentName, err)
 | 
				
			||||||
 | 
								log.Printf(logLine)
 | 
				
			||||||
 | 
								logger.InsertLog(logger.Error, logLine)
 | 
				
			||||||
			break
 | 
								break
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		log.Printf("Message from agent %s: %s", agentName, message)
 | 
							logLine := fmt.Sprintf("Message from agent %s: %s", agentName, message)
 | 
				
			||||||
 | 
							log.Printf(logLine)
 | 
				
			||||||
 | 
							logger.InsertLog(logger.Debug, logLine)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if ch, ok := responseChannels.Load(agentName); ok {
 | 
							if ch, ok := responseChannels.Load(agentName); ok {
 | 
				
			||||||
			responseChan := ch.(chan string)
 | 
								responseChan := ch.(chan string)
 | 
				
			||||||
| 
						 | 
					@ -274,8 +286,6 @@ var executeCommand http.HandlerFunc = func(w http.ResponseWriter, r *http.Reques
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func Server() (*http.Server) {
 | 
					func Server() (*http.Server) {
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	webSocketHandler := webSocketHandler {
 | 
						webSocketHandler := webSocketHandler {
 | 
				
			||||||
		upgrader: websocket.Upgrader{
 | 
							upgrader: websocket.Upgrader{
 | 
				
			||||||
			CheckOrigin: func(r *http.Request) bool {
 | 
								CheckOrigin: func(r *http.Request) bool {
 | 
				
			||||||
| 
						 | 
					@ -286,7 +296,7 @@ func Server() (*http.Server) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	corsMiddleware := func(next http.Handler) http.Handler {
 | 
						corsMiddleware := func(next http.Handler) http.Handler {
 | 
				
			||||||
        return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 | 
					        return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 | 
				
			||||||
            w.Header().Set("Access-Control-Allow-Origin", "*") // Allow the WebUI origin
 | 
					            w.Header().Set("Access-Control-Allow-Origin", "*") // Allow the WebUI origin, this needs to be changed before prod
 | 
				
			||||||
            w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS")
 | 
					            w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS")
 | 
				
			||||||
            w.Header().Set("Access-Control-Allow-Headers", "Content-Type, HX-Current-URL, HX-Request, HX-Target, HX-Trigger, HX-Trigger-Name")
 | 
					            w.Header().Set("Access-Control-Allow-Headers", "Content-Type, HX-Current-URL, HX-Request, HX-Target, HX-Trigger, HX-Trigger-Name")
 | 
				
			||||||
            if r.Method == "OPTIONS" {
 | 
					            if r.Method == "OPTIONS" {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -10,6 +10,7 @@
 | 
				
			||||||
    <!-- <script src="https://code.jquery.com/jquery-3.7.1.min.js"></script> -->
 | 
					    <!-- <script src="https://code.jquery.com/jquery-3.7.1.min.js"></script> -->
 | 
				
			||||||
    <title>g2: gommand & gontrol</title>
 | 
					    <title>g2: gommand & gontrol</title>
 | 
				
			||||||
    <script>
 | 
					    <script>
 | 
				
			||||||
 | 
					    // Query Agents for the Dropdown Menu
 | 
				
			||||||
    document.addEventListener('DOMContentLoaded', () => {
 | 
					    document.addEventListener('DOMContentLoaded', () => {
 | 
				
			||||||
        fetch('/agentNames')
 | 
					        fetch('/agentNames')
 | 
				
			||||||
            .then(response => response.json())
 | 
					            .then(response => response.json())
 | 
				
			||||||
| 
						 | 
					@ -23,43 +24,19 @@
 | 
				
			||||||
                });
 | 
					                });
 | 
				
			||||||
            })
 | 
					            })
 | 
				
			||||||
            .catch(error => console.error('Error fetching agent names:', error));
 | 
					            .catch(error => console.error('Error fetching agent names:', error));
 | 
				
			||||||
    fetch('http://localhost:5555/agentNames')
 | 
					 | 
				
			||||||
    .then(response => {
 | 
					 | 
				
			||||||
        console.log('Fetch response status:', response.status);
 | 
					 | 
				
			||||||
        return response.json();
 | 
					 | 
				
			||||||
    })
 | 
					 | 
				
			||||||
    .then(agentNames => {
 | 
					 | 
				
			||||||
        console.log('Connected agent names:', agentNames);
 | 
					 | 
				
			||||||
        // Your existing logic here
 | 
					 | 
				
			||||||
    })
 | 
					 | 
				
			||||||
    .catch(error => {
 | 
					 | 
				
			||||||
        console.error('Error fetching agent names:', error);
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
        const tableRows = document.querySelectorAll('#agentList table tbody tr');
 | 
					 | 
				
			||||||
        console.log('Number of rows found:', tableRows.length);
 | 
					 | 
				
			||||||
        tableRows.forEach((row, index) => {
 | 
					 | 
				
			||||||
        const nameCell = row.querySelector('td[data-column="Name"]');
 | 
					 | 
				
			||||||
        const statusCell = row.querySelector('td[data-column="Status"]');
 | 
					 | 
				
			||||||
        console.log(`Row ${index + 1} - Name: ${nameCell?.textContent}, Status Cell Found: ${!!statusCell}`);
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					    // Query agents currently connected to the websocket and put status into the table
 | 
				
			||||||
        const updateAgentStatuses = () => {
 | 
					        const updateAgentStatuses = () => {
 | 
				
			||||||
        fetch('http://localhost:5555/agentNames')
 | 
					        fetch('http://localhost:5555/agentNames')
 | 
				
			||||||
            .then(response => response.json())
 | 
					            .then(response => response.json())
 | 
				
			||||||
            .then(agentNames => {
 | 
					            .then(agentNames => {
 | 
				
			||||||
                console.log("Agent names fetched:", agentNames);
 | 
					                console.log("Agent names fetched:", agentNames);
 | 
				
			||||||
 | 
					 | 
				
			||||||
                // Get all rows in the table body
 | 
					 | 
				
			||||||
                const tableRows = document.querySelectorAll('#agentList table tbody tr');
 | 
					                const tableRows = document.querySelectorAll('#agentList table tbody tr');
 | 
				
			||||||
 | 
					 | 
				
			||||||
                // Loop through each row to find the Name and update Status
 | 
					 | 
				
			||||||
                tableRows.forEach(row => {
 | 
					                tableRows.forEach(row => {
 | 
				
			||||||
                    const nameCell = row.querySelector('td:nth-child(2)');  // Name is in the second column
 | 
					                    const nameCell = row.querySelector('td:nth-child(2)');
 | 
				
			||||||
                    const statusCell = row.querySelector('td:nth-child(5)');  // Status is in the fifth column
 | 
					                    const statusCell = row.querySelector('td:nth-child(5)');
 | 
				
			||||||
 | 
					 | 
				
			||||||
                    if (nameCell && statusCell) {
 | 
					                    if (nameCell && statusCell) {
 | 
				
			||||||
                        const agentName = nameCell.textContent.trim();
 | 
					                        const agentName = nameCell.textContent.trim();
 | 
				
			||||||
 | 
					 | 
				
			||||||
                        if (agentNames.includes(agentName)) {
 | 
					                        if (agentNames.includes(agentName)) {
 | 
				
			||||||
                            statusCell.innerHTML = '<span class="badge bg-success">Connected</span>';
 | 
					                            statusCell.innerHTML = '<span class="badge bg-success">Connected</span>';
 | 
				
			||||||
                        } else {
 | 
					                        } else {
 | 
				
			||||||
| 
						 | 
					@ -70,12 +47,8 @@
 | 
				
			||||||
            })
 | 
					            })
 | 
				
			||||||
            .catch(error => console.error('Error fetching agent names:', error));
 | 
					            .catch(error => console.error('Error fetching agent names:', error));
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Initial call to update statuses
 | 
					 | 
				
			||||||
    updateAgentStatuses();
 | 
					    updateAgentStatuses();
 | 
				
			||||||
 | 
					    setInterval(updateAgentStatuses, 1000);
 | 
				
			||||||
    // Set the function to run every 5 seconds
 | 
					 | 
				
			||||||
    setInterval(updateAgentStatuses, 5000);
 | 
					 | 
				
			||||||
    </script>
 | 
					    </script>
 | 
				
			||||||
</head>
 | 
					</head>
 | 
				
			||||||
<body>
 | 
					<body>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,24 @@
 | 
				
			||||||
 | 
					<!DOCTYPE html>
 | 
				
			||||||
 | 
					<html lang="en">
 | 
				
			||||||
 | 
					<head>
 | 
				
			||||||
 | 
					    <meta charset="UTF-8">
 | 
				
			||||||
 | 
					    <meta name="viewport" content="width=device-width, initial-scale=1.0">
 | 
				
			||||||
 | 
					    <title>Web Server Logs</title>
 | 
				
			||||||
 | 
					    <script src="https://unpkg.com/htmx.org@1.8.5"></script>
 | 
				
			||||||
 | 
					</head>
 | 
				
			||||||
 | 
					<body>
 | 
				
			||||||
 | 
					    <h1>Web Server Logs</h1>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <div id="logs-container">
 | 
				
			||||||
 | 
					        <!-- Logs will be injected here -->
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <button hx-get="/logs" hx-target="#logs-container" hx-swap="outerHTML">
 | 
				
			||||||
 | 
					        Load Logs
 | 
				
			||||||
 | 
					    </button>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <button hx-get="/logs" hx-target="#logs-container" hx-swap="outerHTML" hx-trigger="every 2s">
 | 
				
			||||||
 | 
					        Auto-Refresh Logs
 | 
				
			||||||
 | 
					    </button>
 | 
				
			||||||
 | 
					</body>
 | 
				
			||||||
 | 
					</html>
 | 
				
			||||||
		Loading…
	
		Reference in New Issue