From 95e9e0b308bc0cfaa5af5330c575387e8f9c40c0 Mon Sep 17 00:00:00 2001 From: Jack Christensen Date: Sat, 1 Nov 2014 10:44:22 -0500 Subject: [PATCH] Add example of listen/notify support refs #43 --- examples/README.md | 1 + examples/chat/README.md | 25 +++++++++++ examples/chat/main.go | 95 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 121 insertions(+) create mode 100644 examples/chat/README.md create mode 100644 examples/chat/main.go diff --git a/examples/README.md b/examples/README.md index 7c3d3dc8..6a97bc09 100644 --- a/examples/README.md +++ b/examples/README.md @@ -1,5 +1,6 @@ # Examples +* chat is a command line chat program using listen/notify. * todo is a command line todo list that demonstrates basic CRUD actions. * url_shortener contains a simple example of using pgx in a web context. * [Tern](https://github.com/jackc/tern) is a migration tool that uses pgx (uses v1 of pgx). diff --git a/examples/chat/README.md b/examples/chat/README.md new file mode 100644 index 00000000..a0935255 --- /dev/null +++ b/examples/chat/README.md @@ -0,0 +1,25 @@ +# Description + +This is a sample chat program implemented using PostgreSQL's listen/notify +functionality with pgx. + +Start multiple instances of this program connected to the same database to chat +between them. + +## Connection configuration + +The database connection is configured via enviroment variables. + +* CHAT_DB_HOST - defaults to localhost +* CHAT_DB_USER - defaults to current OS user +* CHAT_DB_PASSWORD - defaults to empty string +* CHAT_DB_DATABASE - defaults to postgres + +You can either export them then run chat: + + export CHAT_DB_HOST=/private/tmp + ./chat + +Or you can prefix the chat execution with the environment variables: + + CHAT_DB_HOST=/private/tmp ./chat diff --git a/examples/chat/main.go b/examples/chat/main.go new file mode 100644 index 00000000..517508cc --- /dev/null +++ b/examples/chat/main.go @@ -0,0 +1,95 @@ +package main + +import ( + "bufio" + "fmt" + "github.com/jackc/pgx" + "os" + "time" +) + +var pool *pgx.ConnPool + +func main() { + var err error + pool, err = pgx.NewConnPool(extractConfig()) + if err != nil { + fmt.Fprintln(os.Stderr, "Unable to connect to database:", err) + os.Exit(1) + } + + go listen() + + fmt.Println(`Type a message and press enter. + +This message should appear in any other chat instances connected to the same +database. + +Type "exit" to quit. +`) + + scanner := bufio.NewScanner(os.Stdin) + for scanner.Scan() { + msg := scanner.Text() + if msg == "exit" { + os.Exit(0) + } + + _, err = pool.Exec("select pg_notify('chat', $1)", msg) + if err != nil { + fmt.Fprintln(os.Stderr, "Error sending notification:", err) + os.Exit(1) + } + } + if err := scanner.Err(); err != nil { + fmt.Fprintln(os.Stderr, "Error scanning from stdin:", err) + os.Exit(1) + } +} + +func listen() { + conn, err := pool.Acquire() + if err != nil { + fmt.Fprintln(os.Stderr, "Error acquiring connection:", err) + os.Exit(1) + } + defer pool.Release(conn) + + conn.Listen("chat") + + for { + notification, err := conn.WaitForNotification(time.Second) + if err == pgx.ErrNotificationTimeout { + continue + } + if err != nil { + fmt.Fprintln(os.Stderr, "Error waiting for notification:", err) + os.Exit(1) + } + + fmt.Println("PID:", notification.Pid, "Channel:", notification.Channel, "Payload:", notification.Payload) + } +} + +func extractConfig() pgx.ConnPoolConfig { + var config pgx.ConnPoolConfig + + config.Host = os.Getenv("CHAT_DB_HOST") + if config.Host == "" { + config.Host = "localhost" + } + + config.User = os.Getenv("CHAT_DB_USER") + if config.User == "" { + config.User = os.Getenv("USER") + } + + config.Password = os.Getenv("CHAT_DB_PASSWORD") + + config.Database = os.Getenv("CHAT_DB_DATABASE") + if config.Database == "" { + config.Database = "postgres" + } + + return config +}