Untitled
unknown
golang
a year ago
5.8 kB
11
Indexable
Never
package main import ( "database/sql" "html/template" "log" "net/http" "strings" "github.com/gorilla/sessions" _ "github.com/lib/pq" ) /****************************************************************************** * * Begin execution * ******************************************************************************/ func main() { initdb() http.HandleFunc("/", handle_req) log.Fatal(http.ListenAndServe(":8080", nil)) } /****************************************************************************** * * Global vars * ******************************************************************************/ var db *sql.DB /****************************************************************************** * * Structs * ******************************************************************************/ // Node records type node struct { id int prompt string return_node_id int option_name string options []string } // List node options as a string for presentation. func (n node) optstr() string { var opts = n.options if n.return_node_id != 0 { // The "return" option is available opts = append(opts, "return") } var optstr = "Options: " + strings.Join(opts, ", ") return optstr } // HTML template variables type template_vars struct { Intro string Prompt string Options string } /****************************************************************************** * * Initialize database * ******************************************************************************/ func initdb() { var err error // postgres_url is defined in secrets.go db, err = sql.Open("postgres", postgres_url) // Exit program if the database does not connect if err != nil { panic(err) } } /****************************************************************************** * * Handle HTTP request * ******************************************************************************/ func handle_req(rw http.ResponseWriter, req *http.Request) { // Access session values var sess = load_session(req) var currn = currn(sess) // Access form values var opt = form_values(req) // Calculate next node var nextn = nextn(currn, opt) // Update session set_currn(sess, nextn) sess.Save(req, rw) // Render HTML template render_template(rw, nextn) } func load_session(req *http.Request) *sessions.Session { // sessionKey is defined in secrets.go var store = sessions.NewCookieStore([]byte(session_key)) var sess, _ = store.Get(req, "session") return sess } func form_values(req *http.Request) string { return req.FormValue("option") } /****************************************************************************** * * Render HTML template * ******************************************************************************/ func set_template_vars(nextn node) template_vars { return template_vars{ Intro: "Hello, welcome to the Yo'el Mikha'el simulator.", Prompt: nextn.prompt, Options: nextn.optstr(), } } func render_template(rw http.ResponseWriter, nextn node) { var tmpl, _ = template.ParseFiles("index.html") var tvars = set_template_vars(nextn) tmpl.Execute(rw, tvars) } /****************************************************************************** * * Access session data * ******************************************************************************/ // Find current node from session func currn(sess *sessions.Session) node { var value, ok = sess.Values["current_node_id"] var id int if ok { id = value.(int) } if id != 0 { // A current node is found in the session. return loadn(id) } else { // A current node has not been found in the session. id = select_default_node_id() sess.Values["current_node_id"] = id return loadn(id) } } // Set current node in session func set_currn(sess *sessions.Session, nextn node) { sess.Values["current_node_id"] = nextn.id } func select_default_node_id() int { var row = db.QueryRow( "SELECT id FROM nodes " + "WHERE return_node_id IS NULL ORDER BY id LIMIT 1") var id int row.Scan(&id) return id } /****************************************************************************** * * Select records from the database * ******************************************************************************/ func loadn(id int) node { var n node select_node_cols(&n, id) select_node_options(&n, id) return n } func select_node_cols(n *node, id int) { var row = db.QueryRow( "SELECT id, prompt, return_node_id, option_name "+ "FROM nodes WHERE id = $1", id) row.Scan(&n.id, &n.prompt, &n.return_node_id, &n.option_name) } func select_node_options(n *node, id int) { var rows, _ = db.Query( "SELECT option_name FROM nodes "+ "WHERE return_node_id = $1", id) var opt string for rows.Next() { rows.Scan(&opt) n.options = append(n.options, opt) } } /****************************************************************************** * * Calculate next node based on selected option * ******************************************************************************/ func nextn(currn node, opt string) node { var id = select_nextn_id(currn, opt) if id != 0 { // A next node has been found. return loadn(id) } if opt == "return" { return handle_return_opt(currn) } // There is neither a next node, nor a return node. return currn } func select_nextn_id(currn node, opt string) int { // Look for next node based on return node and option name. var row = db.QueryRow( "SELECT id FROM nodes "+ "WHERE return_node_id = $1 AND option_name = $2", currn.id, opt) var id int row.Scan(&id) return id } func handle_return_opt(currn node) node { if currn.return_node_id != 0 { // A return node is set return loadn(currn.return_node_id) } else { // No return node is set return currn } }