init
This commit is contained in:
		
							parent
							
								
									b246ef706c
								
							
						
					
					
						commit
						2131f370ee
					
				|  | @ -0,0 +1,2 @@ | |||
| gontrol | ||||
| bin/ | ||||
|  | @ -0,0 +1,10 @@ | |||
| module gontrol | ||||
| 
 | ||||
| go 1.23.4 | ||||
| 
 | ||||
| require ( | ||||
| 	github.com/go-sql-driver/mysql v1.8.1 | ||||
| 	github.com/gorilla/websocket v1.5.3 | ||||
| ) | ||||
| 
 | ||||
| require filippo.io/edwards25519 v1.1.0 // indirect | ||||
|  | @ -0,0 +1,6 @@ | |||
| filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= | ||||
| filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= | ||||
| github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= | ||||
| github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= | ||||
| github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= | ||||
| github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= | ||||
|  | @ -0,0 +1,11 @@ | |||
| /* create database 'gomatic'; */ | ||||
| 
 | ||||
| drop table if exists agents; | ||||
| create table agents ( | ||||
|     agentId int, | ||||
|     agentName varchar(255), | ||||
|     initialContact timestamp, | ||||
|     lastContact timestamp | ||||
| ); | ||||
| 
 | ||||
| insert into agents values ( 99, "testAgent", NOW(), NOW()); | ||||
|  | @ -0,0 +1,288 @@ | |||
| package main | ||||
| 
 | ||||
| import ( | ||||
| 	"context" | ||||
| 	"os" | ||||
| 	"strings" | ||||
| 	"time" | ||||
| 
 | ||||
| 	// "errors"
 | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"io/ioutil" | ||||
| 
 | ||||
| 	// "net"
 | ||||
| 	"database/sql" | ||||
| 	"html/template" | ||||
| 	"log" | ||||
| 	"net/http" | ||||
| 	"sync" | ||||
| 	"syscall" | ||||
| 
 | ||||
| 	"os/signal" | ||||
| 
 | ||||
| 	_ "github.com/go-sql-driver/mysql" | ||||
| 	"github.com/gorilla/websocket" | ||||
| ) | ||||
| 
 | ||||
| var tmpl *template.Template | ||||
| var db 	 *sql.DB | ||||
| 
 | ||||
| const ( | ||||
| 	keyServerAddr = "serverAddr" | ||||
| 	dbHost = "172.17.0.2" | ||||
| 	dbUser = "root" | ||||
| 	dbPort = 3306 | ||||
| 	dbPassword = "root" | ||||
| 	dbName = "gomatic" | ||||
| ) | ||||
| 
 | ||||
| type Agent struct { | ||||
| 	agentId int | ||||
| 	agentName string | ||||
| 	initialContact string | ||||
| 	lastContact string | ||||
| } | ||||
| 
 | ||||
| func init() { | ||||
| 	tmpl, _ = template.ParseGlob("templates/*.html") | ||||
| } | ||||
| 
 | ||||
| func initDB () { | ||||
| 	var err  error | ||||
| 	dbOpen := fmt.Sprintf("%s:%s@(%s:%d)/%s?parseTime=true", dbUser,dbPassword, dbHost, dbPort, dbName) | ||||
| 	db, err = sql.Open("mysql", dbOpen) | ||||
| 	if err != nil { | ||||
| 		log.Fatal(err) | ||||
| 	} | ||||
| 
 | ||||
| 	if err = db.Ping(); err != nil { | ||||
| 		log.Fatal(err) | ||||
| 	} | ||||
| 	log.Println("Connected to database") | ||||
| } | ||||
| 
 | ||||
| func fetchAgents(w http.ResponseWriter, r *http.Request) { | ||||
| 	agents, _ := getAgents(db) | ||||
| 
 | ||||
| 	log.Printf("%s",agents) | ||||
| 	tmpl.ExecuteTemplate(w, "agentList", agents) | ||||
| } | ||||
| 
 | ||||
| func getAgents(dbPointer *sql.DB) ([]Agent, error) { | ||||
| 	query := "Select agentId, agentName, initialContact, lastContact from agents" | ||||
| 	rows, err := dbPointer.Query(query) | ||||
| 
 | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	defer rows.Close() | ||||
| 
 | ||||
| 	var agents []Agent | ||||
| 	for rows.Next() { | ||||
| 		var agent Agent | ||||
| 
 | ||||
| 		rowErr := rows.Scan(&agent.agentId, &agent.agentName, &agent.initialContact, &agent.lastContact) | ||||
| 		if rowErr != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		agents = append(agents, agent) | ||||
| 	} | ||||
| 
 | ||||
| 	if err = rows.Err(); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	return agents, nil | ||||
| 	// return agents, rows.Err()
 | ||||
| } | ||||
| 
 | ||||
| func getRoot(w http.ResponseWriter, r *http.Request) { | ||||
| 	ctx := r.Context() | ||||
| 
 | ||||
| 	hasFirst := r.URL.Query().Has("first") | ||||
| 	first := r.URL.Query().Get("first") | ||||
| 	hasSecond := r.URL.Query().Has("second") | ||||
| 	second := r.URL.Query().Get("second") | ||||
| 
 | ||||
| 	body, err := ioutil.ReadAll(r.Body) | ||||
| 
 | ||||
| 	if err != nil { | ||||
| 		fmt.Printf("Could not read body: %s\n", err) | ||||
| 	} | ||||
| 
 | ||||
| 	fmt.Printf("%s: got / request. first(%t)=%s, second(%t)=%s body:\n%s\n", | ||||
| 		ctx.Value(keyServerAddr), | ||||
| 		hasFirst, first, | ||||
| 		hasSecond, second, | ||||
| 		body, | ||||
| 	) | ||||
| 
 | ||||
| 	// fmt.Printf("%s: got / request\n", ctx.Value(keyServerAddr))
 | ||||
| 	io.WriteString(w, "This is my website!\n") | ||||
| } | ||||
| 
 | ||||
| func getHello(w http.ResponseWriter, r *http.Request) { | ||||
| 	ctx := r.Context() | ||||
| 
 | ||||
| 	fmt.Printf("%s: go /hello request\n", ctx.Value(keyServerAddr)) | ||||
| 
 | ||||
| 	myName := r.PostFormValue("myName") | ||||
| 	if myName == "" { | ||||
| 		w.Header().Set("x-missing-field", "myName") | ||||
| 		w.WriteHeader(http.StatusBadRequest) | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	io.WriteString(w, fmt.Sprintf("Hello, %s!\n", myName)) | ||||
| } | ||||
| 
 | ||||
| func getHomepage(w http.ResponseWriter, r *http.Request) { | ||||
| 	tmpl.ExecuteTemplate(w, "index.html", nil) | ||||
| } | ||||
| 
 | ||||
| func agentHandler(w http.ResponseWriter, r *http.Request) { | ||||
| 	parts := strings.Split(strings.TrimPrefix(r.URL.Path, "/agents/"), "/") | ||||
| 	if len (parts) < 1 || parts[0] == "" { | ||||
| 		http.Error(w, "Agent ID required", http.StatusBadRequest) | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	agentId := parts[0] | ||||
| 
 | ||||
| 	switch r.Method { | ||||
| 		case http.MethodGet: | ||||
| 			getAgent(w, r, agentId) | ||||
| 		// case http.MethodPost:
 | ||||
| 		// 	createAgent(w, r, agentId)
 | ||||
| 		// case http.MethodPut:
 | ||||
| 		// 	updateAgent(w, r, agentId)
 | ||||
| 		// case http.MethodDelete:
 | ||||
| 		// 	deleteAgent(w, r, agentId)
 | ||||
| 		default: | ||||
| 			http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) | ||||
| 		} | ||||
| } | ||||
| 
 | ||||
| type webSocketHandler struct { | ||||
| 	upgrader websocket.Upgrader | ||||
| } | ||||
| 
 | ||||
| func getAgent(w http.ResponseWriter, r *http.Request, agentId string) { | ||||
| 	query := "Select agentId, agentName, initialContact, lastContact from agents where agentId = ?" | ||||
| 	var agent Agent | ||||
| 	err := db.QueryRow(query, agentId).Scan(&agentId, &agent.agentName, &agent.initialContact, &agent.lastContact) | ||||
| 	if err == sql.ErrNoRows { | ||||
| 		http.Error(w, "Agent not found", http.StatusNotFound) | ||||
| 		return | ||||
| 	} else if err != nil { | ||||
| 		http.Error(w, "Failed to fetch agent", http.StatusInternalServerError) | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	// return agent, nil
 | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| func (wsh webSocketHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { | ||||
| 	c, err := wsh.upgrader.Upgrade(w, r, nil) | ||||
| 	if err != nil { | ||||
| 		log.Printf("Error %s when upgrading connection to websocket", err) | ||||
| 		return | ||||
| 	} | ||||
| 	defer c.Close() | ||||
| 
 | ||||
| 	for { | ||||
| 		mt, message, err := c.ReadMessage() | ||||
| 		if err != nil { | ||||
| 			log.Printf("Error reading: message: %s", err) | ||||
| 		} | ||||
| 
 | ||||
| 		log.Printf("Received message: %s", message) | ||||
| 		if err = c.WriteMessage(mt, message); err !=nil { | ||||
| 			log.Printf("Error writing the message: %s", err) | ||||
| 			break | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func main() { | ||||
| 
 | ||||
| 	ctx, cancel := context.WithCancel(context.Background()) | ||||
| 	defer cancel() | ||||
| 
 | ||||
| 	var wg sync.WaitGroup | ||||
| 
 | ||||
| 	webSocketHandler := webSocketHandler { | ||||
| 		upgrader: websocket.Upgrader{}, | ||||
| 	} | ||||
| 
 | ||||
| 	webSocketMux := http.NewServeMux() | ||||
| 	webSocketMux.Handle("/data", webSocketHandler) | ||||
| 	websocketServer := &http.Server{ | ||||
| 		Addr: ":5555", | ||||
| 		Handler: webSocketMux, | ||||
| 	} | ||||
| 
 | ||||
| 	webMux := http.NewServeMux() | ||||
| 	webMux.HandleFunc("/", getHomepage) | ||||
| 	webMux.HandleFunc("/index", getRoot) | ||||
| 	webMux.HandleFunc("/hello", getHello) | ||||
| 	webMux.HandleFunc("/agents", fetchAgents) | ||||
| 	// webMux.HandleFunc("/newagentform", getAgentForm)
 | ||||
| 	// webMux.HandleFunc("/getagentupdateform/{agentId}", getAgentUpdateForm)
 | ||||
| 	webMux.HandleFunc("/agents/{agentId}", agentHandler) | ||||
| 	// webMux.HandleFunc
 | ||||
| 
 | ||||
| 
 | ||||
| 	initDB() | ||||
| 	defer db.Close() | ||||
| 
 | ||||
| 	webServer := &http.Server { | ||||
| 		Addr: ":3333", | ||||
| 		Handler: webMux, | ||||
| 		// BaseContext: func(l net.Listener) context.Context {
 | ||||
| 		// 	ctx = context.WithValue(ctx, keyServerAddr, l.Addr().String())
 | ||||
| 		// 	return ctx
 | ||||
| 		// },
 | ||||
| 	} | ||||
| 
 | ||||
| 	wg.Add(1) | ||||
| 	go func() { | ||||
| 		defer wg.Done() | ||||
| 		log.Println("Websocket server is running on port 5555") | ||||
| 		if err := websocketServer.ListenAndServe(); err != http.ErrServerClosed { | ||||
| 			log.Fatalf("Websocket server failed: %s", err) | ||||
| 		} | ||||
| 	}() | ||||
| 
 | ||||
| 	wg.Add(1) | ||||
| 	go func() { | ||||
| 		defer wg.Done() | ||||
| 		log.Println("Web server is running on port 3333") | ||||
| 
 | ||||
| 		if err := webServer.ListenAndServe(); err != http.ErrServerClosed { | ||||
| 			log.Fatalf("Web server failed: %s", err) | ||||
| 		} | ||||
| 	}() | ||||
| 
 | ||||
| 	shutdownCh := make(chan os.Signal, 1) | ||||
| 	signal.Notify(shutdownCh, os.Interrupt, syscall.SIGTERM) | ||||
| 
 | ||||
| 	<-shutdownCh | ||||
| 	log.Println("Shutdown signal received") | ||||
| 
 | ||||
| 	shutdownCtx, shutdownCancel := context.WithTimeout(ctx, 10*time.Second) | ||||
| 	defer shutdownCancel() | ||||
| 
 | ||||
| 	if err := websocketServer.Shutdown(shutdownCtx); err != nil { | ||||
| 		log.Printf("error shutting down websocket server: %s", err) | ||||
| 	} | ||||
| 
 | ||||
| 	if err := webServer.Shutdown(shutdownCtx); err != nil { | ||||
| 		log.Printf("Error shutting down web server: %s", err) | ||||
| 	} | ||||
| 
 | ||||
| 	wg.Wait() | ||||
| 	log.Println("All servers stopped") | ||||
| } | ||||
|  | @ -0,0 +1,5 @@ | |||
| #!/usr/bin/env bash | ||||
| # | ||||
| go mod edit -module "${2}" | ||||
| find . -type f -name '*.go' -exec sed -i -e "s,\"${1}/,\"${2}/,g" {} \; | ||||
| find . -type f -name '*.go' -exec sed -i -e "s,\"${1}\",\"${2}\",g" {} \; | ||||
|  | @ -0,0 +1,8 @@ | |||
| <html> | ||||
|   <head> | ||||
|     <title>Static Website</title> | ||||
|   </head> | ||||
|   <body> | ||||
|     <h2>Static Website</h2> | ||||
|   </body> | ||||
| </html> | ||||
|  | @ -0,0 +1,14 @@ | |||
| {{define "agentList"}} | ||||
| <ul> | ||||
|     {{range .}} | ||||
|         <li> | ||||
|             <span {{if .Done}} style="text-decoration:line-through" {{end}}>{{.Agents}}</span> | ||||
|             <!-- [<a href="#" hx-get="/gettaskupdateform/{{.Id}}" hx-target="#addTaskForm" hx-swap="innerHTML">Edit</a>] | --> | ||||
|             <a href="#" hx-delete="/agents/{{.agentId}}" | ||||
|                         hx-confirm="Are you sure you want to Delete this Task?" | ||||
|                         hx-target="#agentList">[Delete]</a> | ||||
|         </li> | ||||
|     {{end}} | ||||
| </ul> | ||||
| 
 | ||||
| {{end}} | ||||
|  | @ -0,0 +1,43 @@ | |||
| <!DOCTYPE html> | ||||
| <html lang="en"> | ||||
| <head> | ||||
|     <meta charset="UTF-8"> | ||||
|     <meta http-equiv="X-UA-Compatible" content="IE=edge"> | ||||
|     <meta name="viewport" content="width=device-width, initial-scale=1.0"> | ||||
|     <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous"> | ||||
|     <script src="https://unpkg.com/htmx.org@1.9.12"></script> | ||||
|     <title>To Do App</title> | ||||
| </head> | ||||
| <body> | ||||
| 
 | ||||
|     <div class="row"> | ||||
| 
 | ||||
|         <div class="col"> | ||||
|             <h2>Tasks</h2> | ||||
| 
 | ||||
|             <div> | ||||
|                 <a href="#" hx-get="/newtaskform" hx-target="#addTaskForm">Add New Item</a> | ||||
|             </div> | ||||
| 
 | ||||
|             <div id="taskList" hx-get="/tasks" hx-trigger="load" hx-swap="innerHTML"> | ||||
| 
 | ||||
|             </div> | ||||
| 
 | ||||
|         </div> | ||||
|         <!-- <div class="col"> | ||||
| 
 | ||||
|         </div> --> | ||||
|         <div class="col"> | ||||
|             <h2>Add New Task</h2> | ||||
| 
 | ||||
|             <div id="addTaskForm"> | ||||
|                 hello | ||||
|                 {{template "addTaskForm"}} | ||||
|             </div> | ||||
| 
 | ||||
|         </div> | ||||
| 
 | ||||
|     </div> | ||||
| 
 | ||||
| </body> | ||||
| </html> | ||||
|  | @ -0,0 +1,44 @@ | |||
| <!DOCTYPE html> | ||||
| <html lang="en"> | ||||
| <head> | ||||
|     <!-- <meta charset="UTF-8"> --> | ||||
|     <!-- <meta http-equiv="X-UA-Compatible" content="IE=edge"> --> | ||||
|     <!-- <meta name="viewport" content="width=device-width, initial-scale=1.0"> --> | ||||
|     <!-- <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous"> --> | ||||
|     <!-- <script src="https://unpkg.com/htmx.org@1.9.12"></script> --> | ||||
|     <title>Gomatic Agents</title> | ||||
| </head> | ||||
| <body> | ||||
| 
 | ||||
|     Test | ||||
|     <!-- <div class="row"> --> | ||||
| 
 | ||||
|         <!-- <div class="col"> --> | ||||
|             <h2>Tasks</h2> | ||||
| 
 | ||||
|             <!-- <div> --> | ||||
|             <!--     <a href="#" hx-get="/newtaskform" hx-target="#addTaskForm">Add New Item</a> --> | ||||
|             <!-- </div> --> | ||||
| 
 | ||||
|             <!-- <div id="agentList" hx-get="/agents" hx-trigger="load" hx-swap="innerHTML"> --> | ||||
| 
 | ||||
|             <!-- </div> --> | ||||
| 
 | ||||
|         <!-- </div> --> | ||||
|         <!-- <div class="col"> | ||||
| 
 | ||||
|         </div> --> | ||||
|         <!-- <div class="col"> --> | ||||
|         <!--     <h2>Add New Task</h2> --> | ||||
| 
 | ||||
|             <!-- <div id="addTaskForm"> --> | ||||
|             <!--     hello --> | ||||
|             <!--     {{template "addTaskForm"}} --> | ||||
|             <!-- </div> --> | ||||
| 
 | ||||
|         <!-- </div> --> | ||||
| 
 | ||||
|     <!-- </div> --> | ||||
| 
 | ||||
| </body> | ||||
| </html> | ||||
|  | @ -0,0 +1,27 @@ | |||
| <!DOCTYPE html> | ||||
| <html lang="en"> | ||||
| <head> | ||||
|     <meta charset="UTF-8"> | ||||
|     <meta http-equiv="X-UA-Compatible" content="IE=edge"> | ||||
|     <meta name="viewport" content="width=device-width, initial-scale=1.0"> | ||||
|     <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous"> | ||||
|     <script src="https://unpkg.com/htmx.org@1.9.12"></script> | ||||
|     <title>To Do App</title> | ||||
| </head> | ||||
| <body> | ||||
| 
 | ||||
|     <div class="row"> | ||||
| 
 | ||||
|         <div class="col"> | ||||
|             <h2>Tasks</h2> | ||||
| 
 | ||||
| 
 | ||||
|             <div id="agentList" hx-get="/agents" hx-trigger="load" hx-swap="innerHTML"> | ||||
| 
 | ||||
|             </div> | ||||
| 
 | ||||
| 
 | ||||
|     </div> | ||||
| 
 | ||||
| </body> | ||||
| </html> | ||||
		Loading…
	
		Reference in New Issue