updated web-tinkertoy to use new db package and broke out endpoints to their own files
This commit is contained in:
parent
fcc302dcfe
commit
59879ceb70
@ -5,10 +5,12 @@ import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
|
||||
"github.com/jchenry/jchenry/db"
|
||||
"rsc.io/dbstore"
|
||||
)
|
||||
|
||||
type DBFunc func(db *sql.DB)
|
||||
|
||||
type DBActor struct {
|
||||
DB *sql.DB
|
||||
ActionChan chan DBFunc
|
||||
@ -25,29 +27,44 @@ func (a *DBActor) Run(ctx context.Context) error {
|
||||
}
|
||||
}
|
||||
|
||||
func DBStoreInsert(store *dbstore.Storage, e interface{}) DBFunc {
|
||||
func DBStoreInsert(store *dbstore.Storage, e interface{}) db.Func {
|
||||
return func(db *sql.DB) {
|
||||
err := store.Insert(db, e)
|
||||
fmt.Println(err)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func DBStoreDelete(store *dbstore.Storage, e interface{}) DBFunc {
|
||||
func DBStoreDelete(store *dbstore.Storage, e interface{}) db.Func {
|
||||
return func(db *sql.DB) {
|
||||
store.Delete(db, e)
|
||||
}
|
||||
}
|
||||
|
||||
func DBStoreSelect(store *dbstore.Storage, e interface{}, query string, args ...interface{}) DBFunc {
|
||||
func DBStoreSelect(store *dbstore.Storage,
|
||||
err chan error,
|
||||
results chan interface{},
|
||||
ent interface{},
|
||||
query string,
|
||||
args ...interface{}) db.Func {
|
||||
return func(db *sql.DB) {
|
||||
err := store.Select(db, e, query, args...)
|
||||
fmt.Println(err)
|
||||
if e := store.Select(db, ent, query, args...); e != nil {
|
||||
err <- e
|
||||
} else {
|
||||
results <- ent
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// func DBStoreRead(store *dbstore.Storage, e interface{}, IDCol string) DBFunc {
|
||||
// return func(db *sql.DB) {
|
||||
// store.Read(db, e, IDCol)
|
||||
// }
|
||||
// }
|
||||
func DBStoreRead(store *dbstore.Storage,
|
||||
err chan error,
|
||||
results chan interface{},
|
||||
ent interface{},
|
||||
columns ...string) db.Func {
|
||||
return func(db *sql.DB) {
|
||||
if e := store.Read(db, ent, columns...); e != nil {
|
||||
err <- e
|
||||
} else {
|
||||
results <- ent
|
||||
}
|
||||
}
|
||||
}
|
||||
|
36
cmd/web-tinkertoy/echo.go
Normal file
36
cmd/web-tinkertoy/echo.go
Normal file
@ -0,0 +1,36 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"sync"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
func (s *server) handleEcho() http.HandlerFunc {
|
||||
var (
|
||||
init sync.Once
|
||||
tmpl *template.Template
|
||||
tplerr error
|
||||
)
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
init.Do(func() {
|
||||
tmpl, tplerr = template.ParseFiles("echoform.tmpl")
|
||||
})
|
||||
if tplerr != nil {
|
||||
http.Error(w, tplerr.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
switch r.Method {
|
||||
case http.MethodPost:
|
||||
r.ParseForm()
|
||||
s.echoMessage = r.Form.Get("msg")
|
||||
http.Redirect(w, r, "/echo", 301)
|
||||
return
|
||||
case http.MethodGet:
|
||||
if err := tmpl.Execute(w, map[string]string{"Message": s.echoMessage}); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
96
cmd/web-tinkertoy/fortune.go
Normal file
96
cmd/web-tinkertoy/fortune.go
Normal file
@ -0,0 +1,96 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"sync"
|
||||
"text/template"
|
||||
|
||||
"github.com/jchenry/jchenry/db"
|
||||
"rsc.io/dbstore"
|
||||
)
|
||||
|
||||
func (s *server) handleFortune() http.HandlerFunc {
|
||||
var (
|
||||
init sync.Once
|
||||
dba *db.Actor
|
||||
storage *dbstore.Storage
|
||||
tmpl *template.Template
|
||||
tplerr error
|
||||
)
|
||||
|
||||
type fortuneWrapper struct {
|
||||
Fortune string
|
||||
}
|
||||
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
init.Do(func() {
|
||||
ctx, _ := context.WithCancel(context.Background())
|
||||
dba = &db.Actor{
|
||||
DB: s.db,
|
||||
ActionChan: make(chan db.Func),
|
||||
}
|
||||
go dba.Run(ctx)
|
||||
storage = new(dbstore.Storage)
|
||||
storage.Register(&fortuneWrapper{})
|
||||
err := storage.CreateTables(dba.DB)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
tmpl, tplerr = template.ParseFiles("fortunesupload.tmpl")
|
||||
})
|
||||
|
||||
if tplerr != nil {
|
||||
http.Error(w, tplerr.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
switch r.Method {
|
||||
case http.MethodPost:
|
||||
r.ParseMultipartForm(10 << 20)
|
||||
file, _, err := r.FormFile("fortunes")
|
||||
if err != nil {
|
||||
fmt.Println("Error Retrieving the File")
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
scanner := bufio.NewScanner(file)
|
||||
var fortune string
|
||||
for scanner.Scan() {
|
||||
switch scanner.Text() {
|
||||
case "%":
|
||||
dba.ActionChan <- DBStoreInsert(storage, &fortuneWrapper{Fortune: fortune})
|
||||
default:
|
||||
fortune = scanner.Text()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if err := scanner.Err(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
case http.MethodGet:
|
||||
f := fortuneWrapper{}
|
||||
results := make(chan interface{})
|
||||
err := make(chan error)
|
||||
|
||||
dba.ActionChan <- DBStoreSelect(storage, err, results, &f, "ORDER BY RANDOM() LIMIT 1", "*")
|
||||
select {
|
||||
case r := <-results:
|
||||
if err := tmpl.Execute(w, map[string]string{"Message": r.(*fortuneWrapper).Fortune}); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
case e := <-err:
|
||||
http.Error(w, e.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -1,8 +1,22 @@
|
||||
module github.com/jchenry/jch
|
||||
module github.com/jchenry/jchenry/cmd/web-tinkertoy
|
||||
|
||||
go 1.14
|
||||
|
||||
require (
|
||||
github.com/codegangsta/negroni v1.0.0 // indirect
|
||||
github.com/coreos/go-oidc v2.1.0+incompatible // indirect
|
||||
github.com/gorilla/sessions v1.2.0 // indirect
|
||||
github.com/jchenry/jchenry v0.0.0-00010101000000-000000000000
|
||||
github.com/julienschmidt/httprouter v1.2.0 // indirect
|
||||
github.com/mattn/go-sqlite3 v2.0.3+incompatible
|
||||
github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35 // indirect
|
||||
github.com/stretchr/testify v1.4.0 // indirect
|
||||
github.com/stripe/stripe-go v63.4.0+incompatible // indirect
|
||||
golang.org/x/crypto v0.0.0-20190927123631-a832865fa7ad // indirect
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 // indirect
|
||||
gopkg.in/auth0.v1 v1.2.7 // indirect
|
||||
gopkg.in/square/go-jose.v2 v2.3.1 // indirect
|
||||
rsc.io/dbstore v0.1.1
|
||||
)
|
||||
|
||||
replace github.com/jchenry/jchenry => ../../
|
||||
|
@ -1,6 +1,42 @@
|
||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
github.com/PuerkitoBio/rehttp v0.0.0-20180310210549-11cf6ea5d3e9/go.mod h1:ItsOiHl4XeMOV3rzbZqQRjLc3QQxbE6391/9iNG7rE8=
|
||||
github.com/PuloV/ics-golang v0.0.0-20190808201353-a3394d3bcade/go.mod h1:f1P3hjG+t54/IrnXMnnw+gRmFCDR/ryj9xSQ7MPMkQw=
|
||||
github.com/channelmeter/iso8601duration v0.0.0-20150204201828-8da3af7a2a61/go.mod h1:Rp8e0DCtEKwXFOC6JPJQVTz8tuGoGvw6Xfexggh/ed0=
|
||||
github.com/codegangsta/negroni v1.0.0/go.mod h1:v0y3T5G7Y1UlFfyxFn/QLRU4a2EuNau2iZY63YTKWo0=
|
||||
github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
|
||||
github.com/gorilla/sessions v1.2.0/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
|
||||
github.com/jchenry/jchenry v0.0.0-20191107034549-4697006d1099 h1:qUy+BhiLM5LzN0cOGtqvuC2v7FNfmQFg1cjZbNcMnBY=
|
||||
github.com/jchenry/jchenry v0.0.0-20191107034549-4697006d1099/go.mod h1:5ywsKLPV6YOTZ7oNNmQo7EQRDKhlGCD311r/ZRZgHDM=
|
||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||
github.com/mattn/go-sqlite3 v1.13.0 h1:LnJI81JidiW9r7pS/hXe6cFeO5EXNq7KbfvoJLRI69c=
|
||||
github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U=
|
||||
github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stripe/stripe-go v63.4.0+incompatible/go.mod h1:A1dQZmO/QypXmsL0T8axYZkSN/uA/T/A64pfKdBAMiY=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190927123631-a832865fa7ad/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
gopkg.in/auth0.v1 v1.2.7/go.mod h1:1FRtMXwYDgygZcO7Of7kj/I4mf9UjHGhMHUOqNT0d0M=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
rsc.io/dbstore v0.1.1 h1:LI4gBJUwbejn0wHJWe0KTwgCM33zUVP3BsNz5y2fkEE=
|
||||
rsc.io/dbstore v0.1.1/go.mod h1:zI7k1PCSLg9r/T2rBM4E/SctbGmqdtt3kjQSemVh1Rs=
|
||||
rsc.io/sqlite v0.5.0/go.mod h1:fqHuveM9iIqMzjD0WiZIvKYMty/WqTo2bxE9+zC54WE=
|
||||
|
@ -18,16 +18,6 @@ func main() {
|
||||
}
|
||||
|
||||
func run(args []string, stdout io.Writer) error {
|
||||
// ctx, cancel := context.WithCancel(context.Background())
|
||||
// defer cancel()
|
||||
// if db, err := sql.Open("sqlite3", "foo.db"); err == nil {
|
||||
// dba := DBActor{
|
||||
// DB: db,
|
||||
// ActionChan: make(chan DBFunc, 1),
|
||||
// }
|
||||
// go dba.Run(ctx)
|
||||
// }
|
||||
|
||||
s := server{
|
||||
router: http.NewServeMux(),
|
||||
}
|
||||
|
@ -1,18 +1,8 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"sync"
|
||||
"text/template"
|
||||
"time"
|
||||
|
||||
"rsc.io/dbstore"
|
||||
)
|
||||
|
||||
type server struct {
|
||||
@ -27,111 +17,3 @@ func (s *server) routes() {
|
||||
s.router.HandleFunc("/fortune", s.handleFortune())
|
||||
|
||||
}
|
||||
|
||||
func (s *server) handleTime() http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(200)
|
||||
io.WriteString(w, time.Now().String())
|
||||
}
|
||||
}
|
||||
|
||||
func (s *server) handleEcho() http.HandlerFunc {
|
||||
var (
|
||||
init sync.Once
|
||||
tmpl *template.Template
|
||||
tplerr error
|
||||
)
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
init.Do(func() {
|
||||
tmpl, tplerr = template.ParseFiles("echoform.tmpl")
|
||||
})
|
||||
if tplerr != nil {
|
||||
http.Error(w, tplerr.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
switch r.Method {
|
||||
case http.MethodPost:
|
||||
r.ParseForm()
|
||||
s.echoMessage = r.Form.Get("msg")
|
||||
http.Redirect(w, r, "/echo", 301)
|
||||
return
|
||||
case http.MethodGet:
|
||||
if err := tmpl.Execute(w, map[string]string{"Message": s.echoMessage}); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *server) handleFortune() http.HandlerFunc {
|
||||
var (
|
||||
init sync.Once
|
||||
dba *DBActor
|
||||
storage *dbstore.Storage
|
||||
tmpl *template.Template
|
||||
tplerr error
|
||||
)
|
||||
|
||||
type fortuneWrapper struct {
|
||||
Fortune string
|
||||
}
|
||||
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
init.Do(func() {
|
||||
ctx, _ := context.WithCancel(context.Background())
|
||||
dba = &DBActor{
|
||||
DB: s.db,
|
||||
ActionChan: make(chan DBFunc),
|
||||
}
|
||||
go dba.Run(ctx)
|
||||
storage = new(dbstore.Storage)
|
||||
storage.Register(&fortuneWrapper{})
|
||||
err := storage.CreateTables(dba.DB)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
tmpl, tplerr = template.ParseFiles("fortunesupload.tmpl")
|
||||
})
|
||||
|
||||
if tplerr != nil {
|
||||
http.Error(w, tplerr.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
switch r.Method {
|
||||
case http.MethodPost:
|
||||
r.ParseMultipartForm(10 << 20)
|
||||
file, _, err := r.FormFile("fortunes")
|
||||
if err != nil {
|
||||
fmt.Println("Error Retrieving the File")
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
scanner := bufio.NewScanner(file)
|
||||
var fortune string
|
||||
for scanner.Scan() {
|
||||
switch scanner.Text() {
|
||||
case "%":
|
||||
dba.ActionChan <- DBStoreInsert(storage, &fortuneWrapper{Fortune: fortune})
|
||||
default:
|
||||
fortune = scanner.Text()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if err := scanner.Err(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
case http.MethodGet:
|
||||
f := fortuneWrapper{}
|
||||
DBStoreSelect(storage, &f, "ORDER BY RANDOM() LIMIT 1", "*")(s.db)
|
||||
if err := tmpl.Execute(w, map[string]string{"Message": f.Fortune}); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
14
cmd/web-tinkertoy/time.go
Normal file
14
cmd/web-tinkertoy/time.go
Normal file
@ -0,0 +1,14 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
func (s *server) handleTime() http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(200)
|
||||
io.WriteString(w, time.Now().String())
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user