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 // } type Agent struct { AgentID int `json:"agentId"` AgentName string `json:"agentName"` InitialContact string `json:"initialContact"` LastContact string `json:"lastContact"` } func init() { tmpl, _ = template.ParseGlob("templates/*.html") } func renderTemplate(w http.ResponseWriter, tmpl string, data interface{}) { t, err := template.ParseFiles(tmpl) if err != nil { log.Printf("Failed to load template %s: %v", tmpl, err) http.Error(w, "Internal Server Error", http.StatusInternalServerError) return } if err := t.Execute(w, data); err != nil { log.Printf("Failed to render template %s: %v", tmpl, err) http.Error(w, "Internal Server Error", http.StatusInternalServerError) return } } 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 agentsHandler(w http.ResponseWriter, r *http.Request) { // if r.URL.Path == "/agents" { // if r.Method == http.MethodGet{ // agents, err := getAgentsFromDB() // if err != nil { // http.Error(w, "Failed to fetch agents", http.StatusInternalServerError) // return // } // renderTemplate(w, "templates/partials/agent_list.html", agents) // } else { // http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) // } // return // } parts := strings.Split(strings.TrimPrefix(r.URL.Path, "/agents/"), "/") agentId := "" if len(parts) > 0 && parts[0] != "" { agentId = parts[0] } // if len (parts) < 1 || parts[0] == "" { // http.Error(w, "Agent ID required", http.StatusBadRequest) // return // } // agentId := parts[0] switch r.Method { case http.MethodDelete: deleteAgent(w, r, agentId) case http.MethodGet: if agentId == "" { listAgents(w, r) } else { getAgent(w, r, agentId) } case http.MethodPost: createAgent(w, r) case http.MethodPut: updateAgent(w, r, agentId) default: http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) } } func listAgents(w http.ResponseWriter, r *http.Request) { agents, err := getAgentsFromDB() if err != nil { http.Error(w, "Failed to fetch agents", http.StatusInternalServerError) return } renderTemplate(w, "templates/partials/agent_list.html", agents) } func deleteAgent(w http.ResponseWriter, r *http.Request, agentID string) { query := "DELETE FROM agents WHERE agentId = ?" _, err := db.Exec(query, agentID) if err != nil { http.Error(w, "Failed to delete agent", http.StatusInternalServerError) return } agents, err := getAgentsFromDB() if err != nil { http.Error(w, "Failed to fetch agents", http.StatusInternalServerError) return } renderTemplate(w, "templates/partials/agent_list.html", agents) } func createAgent(w http.ResponseWriter, r * http.Request) { err := r.ParseForm() if err != nil { http.Error(w, "Invalid form data", http.StatusBadRequest) } agentName := r.FormValue("agentName") agentId := 42 // initalContact := r.FormValue("initialContact") // lastContact := r.FormValue("lastContact") query := "INSERT INTO agents (agentId, agentName, initialContact, lastContact) VALUES (?, ?, NOW(), NOW())" _, err = db.Exec(query, agentId, agentName) if err != nil { http.Error(w, "Failed to create agent", http.StatusInternalServerError) return } listAgents(w, r) } func updateAgent(w http.ResponseWriter, r *http.Request, agentId string) { err := r.ParseForm() if err != nil { http.Error(w, "Invalid form data", http.StatusBadRequest) return } agentName := r.FormValue("agentName") lastContact := r.FormValue("lastContact") query := "UPDATE agents SET agentName = ?, lastContact = ? where agentId = ?" _, err = db.Exec(query, agentName, lastContact, agentId) if err != nil { http.Error(w, "Failed to update agent", http.StatusInternalServerError) return } listAgents(w, r,) } func getAgentsFromDB() ([]Agent, error) { query := "SELECT agentId, agentName, initialContact, lastContact FROM agents" rows, err := db.Query(query) if err != nil { return nil, err } defer rows.Close() var agents []Agent for rows.Next() { var agent Agent err := rows.Scan(&agent.AgentID, &agent.AgentName, &agent.InitialContact, &agent.LastContact) if err != nil { return nil, err } agents = append(agents, agent) } return agents, rows.Err() } 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(&agent.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 // TODO: Add agent_detail.html renderTemplate(w, "templates/partials/agent_detail.html", agent) } 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("/agents", agentsHandler) // webMux.HandleFunc("/newagentform", getAgentForm) // webMux.HandleFunc("/getagentupdateform/{agentId}", getAgentUpdateForm) webMux.HandleFunc("/agents/{agentId}", agentsHandler) // 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") }