diff --git a/README.md b/README.md index 3cf4f8e9..98781037 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,11 @@ a google reader clone built with go on app engine and angularjs +# Current build instructions: +* Use this: + Building: `GOPATH=$(GOPATH) GO111MODULE=auto go build app.go` + Deploy: `GOPATH=$(GOPATH) gcloud beta app deploy` + ## setting up a local dev environment 1. Install [Python 2.7](http://www.python.org/download/releases/2.7.5/) and make sure it is in your `PATH`. (Google App Engine doesn't yet work with Python 3.) diff --git a/_third_party/github.com/MiniProfiler/go/miniprofiler_gae/miniprofiler_gae.go b/_third_party/github.com/MiniProfiler/go/miniprofiler_gae/miniprofiler_gae.go index 8aad19ac..e0598f41 100644 --- a/_third_party/github.com/MiniProfiler/go/miniprofiler_gae/miniprofiler_gae.go +++ b/_third_party/github.com/MiniProfiler/go/miniprofiler_gae/miniprofiler_gae.go @@ -20,10 +20,10 @@ import ( "fmt" "net/http" - "appengine" - "appengine/memcache" - "appengine/user" - "appengine_internal" + "golang.org/x/net/context" + "google.golang.org/appengine/v2" + "google.golang.org/appengine/v2/memcache" + "google.golang.org/appengine/v2/user" "github.com/mjibson/goread/_third_party/github.com/MiniProfiler/go/miniprofiler" "github.com/mjibson/goread/_third_party/github.com/mjibson/appstats" ) @@ -84,16 +84,17 @@ type Context struct { miniprofiler.Timer } -func (c Context) Call(service, method string, in, out appengine_internal.ProtoMessage, opts *appengine_internal.CallOptions) (err error) { +/* +func (c Context) Call(service, method string, in, out internal.Proto.Message) (err error) { if c.Timer != nil && service != "__go__" { c.StepCustomTiming(service, method, fmt.Sprintf("%v\n\n%v", method, in.String()), func() { - err = c.Context.Call(service, method, in, out, opts) + err = c.Context.Call(service, method, in, out) }) } else { - err = c.Context.Call(service, method, in, out, opts) + err = c.Context.Call(service, method, in, out) } return -} +}*/ func (c Context) Step(name string, f func(Context)) { if c.Timer != nil { @@ -110,7 +111,7 @@ func (c Context) Step(name string, f func(Context)) { // NewHandler returns a profiled, appstats-aware appengine.Context. func NewHandler(f func(Context, http.ResponseWriter, *http.Request)) http.Handler { - return appstats.NewHandler(func(c appengine.Context, w http.ResponseWriter, r *http.Request) { + return appstats.NewHandler(func(c context.Context, w http.ResponseWriter, r *http.Request) { h := miniprofiler.NewHandler(func(t miniprofiler.Timer, w http.ResponseWriter, r *http.Request) { pc := Context{ Context: c.(appstats.Context), diff --git a/_third_party/github.com/mjibson/appstats/appstats.go b/_third_party/github.com/mjibson/appstats/appstats.go index 5b9b6c1f..ed457832 100644 --- a/_third_party/github.com/mjibson/appstats/appstats.go +++ b/_third_party/github.com/mjibson/appstats/appstats.go @@ -23,13 +23,13 @@ import ( "math/rand" "net/http" "net/url" - "runtime/debug" "time" - "appengine" - "appengine/memcache" - "appengine/user" - "appengine_internal" + "golang.org/x/net/context" + "google.golang.org/appengine/v2" + "google.golang.org/appengine/v2/log" + "google.golang.org/appengine/v2/memcache" + "google.golang.org/appengine/v2/user" ) var ( @@ -69,20 +69,21 @@ func DefaultShouldRecord(r *http.Request) bool { return rand.Float64() < RecordFraction } -// Context is a timing-aware appengine.Context. +// Context is a timing-aware context.Context. type Context struct { - appengine.Context + context.Context header http.Header stats *requestStats } -// Call times an appengine.Context Call. Internal use only. -func (c Context) Call(service, method string, in, out appengine_internal.ProtoMessage, opts *appengine_internal.CallOptions) error { +// Call times an context.Context Call. Internal use only. +/* +func (c Context) Call(service, method string, in, out internal.Proto.Message) error { c.stats.wg.Add(1) defer c.stats.wg.Done() if service == "__go__" { - return c.Context.Call(service, method, in, out, opts) + return c.Context.Call(service, method, in, out) } stat := rpcStat{ @@ -92,7 +93,7 @@ func (c Context) Call(service, method string, in, out appengine_internal.ProtoMe Offset: time.Since(c.stats.Start), StackData: string(debug.Stack()), } - err := c.Context.Call(service, method, in, out, opts) + err := c.Context.Call(service, method, in, out) stat.Duration = time.Since(stat.Start) stat.In = in.String() stat.Out = out.String() @@ -110,7 +111,7 @@ func (c Context) Call(service, method string, in, out appengine_internal.ProtoMe c.stats.Cost += stat.Cost c.stats.lock.Unlock() return err -} +}*/ // NewContext creates a new timing-aware context from req. func NewContext(req *http.Request) Context { @@ -137,7 +138,7 @@ func NewContext(req *http.Request) Context { // WithContext enables profiling of functions without a corresponding request, // as in the appengine/delay package. method and path may be empty. -func WithContext(context appengine.Context, method, path string, f func(Context)) { +func WithContext(context context.Context, method, path string, f func(Context)) { var uname string var admin bool if u := user.Current(context); u != nil { @@ -170,7 +171,7 @@ func (c Context) save() { Stats: c.stats, } if err := gob.NewEncoder(&buf_full).Encode(&full); err != nil { - c.Errorf("appstats Save error: %v", err) + log.Errorf(c.Context, "appstats Save error: %v", err) return } else if buf_full.Len() > bufMaxLen { // first try clearing stack traces @@ -187,7 +188,7 @@ func (c Context) save() { part.RPCStats[i].Out = "" } if err := gob.NewEncoder(&buf_part).Encode(&part); err != nil { - c.Errorf("appstats Save error: %v", err) + log.Errorf(c.Context, "appstats Save error: %v", err) return } @@ -201,7 +202,7 @@ func (c Context) save() { Value: buf_full.Bytes(), } - c.Infof("Saved; %s: %s, %s: %s, link: %v", + log.Infof(c.Context, "Saved; %s: %s, %s: %s, link: %v", item_part.Key, byteSize(len(item_part.Value)), item_full.Key, @@ -222,12 +223,12 @@ func (c Context) URL() string { return u.String() } -func (c Context) storeContext() appengine.Context { +func (c Context) storeContext() context.Context { nc, _ := appengine.Namespace(c.Context, Namespace) return nc } -func context(r *http.Request) appengine.Context { +func _context(r *http.Request) context.Context { c := appengine.NewContext(r) nc, _ := appengine.Namespace(c, Namespace) return nc @@ -235,18 +236,18 @@ func context(r *http.Request) appengine.Context { // handler is an http.Handler that records RPC statistics. type handler struct { - f func(appengine.Context, http.ResponseWriter, *http.Request) + f func(context.Context, http.ResponseWriter, *http.Request) } // NewHandler returns a new Handler that will execute f. -func NewHandler(f func(appengine.Context, http.ResponseWriter, *http.Request)) http.Handler { +func NewHandler(f func(context.Context, http.ResponseWriter, *http.Request)) http.Handler { return handler{ f: f, } } // NewHandlerFunc returns a new HandlerFunc that will execute f. -func NewHandlerFunc(f func(appengine.Context, http.ResponseWriter, *http.Request)) http.HandlerFunc { +func NewHandlerFunc(f func(context.Context, http.ResponseWriter, *http.Request)) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { h := handler{ f: f, diff --git a/_third_party/github.com/mjibson/appstats/handler.go b/_third_party/github.com/mjibson/appstats/handler.go index a4a0436a..46bc1732 100644 --- a/_third_party/github.com/mjibson/appstats/handler.go +++ b/_third_party/github.com/mjibson/appstats/handler.go @@ -28,9 +28,9 @@ import ( "strings" "time" - "appengine" - "appengine/memcache" - "appengine/user" + "google.golang.org/appengine/v2" + "google.golang.org/appengine/v2/memcache" + "google.golang.org/appengine/v2/user" ) var templates *template.Template @@ -91,7 +91,7 @@ func index(w http.ResponseWriter, r *http.Request) { keys[i] = fmt.Sprintf(keyPart, i*distance) } - c := context(r) + c := _context(r) items, err := memcache.GetMulti(c, keys) if err != nil { return @@ -238,7 +238,7 @@ func details(w http.ResponseWriter, r *http.Request) { qtime := roundTime(i) key := fmt.Sprintf(keyFull, qtime) - c := context(r) + c := _context(r) v := struct { Env map[string]string @@ -306,7 +306,7 @@ func file(w http.ResponseWriter, r *http.Request) { fname := r.URL.Query().Get("f") n := r.URL.Query().Get("n") lineno, _ := strconv.Atoi(n) - c := context(r) + c := _context(r) f, err := ioutil.ReadFile(fname) if err != nil { diff --git a/_third_party/github.com/mjibson/goon/doc.go b/_third_party/github.com/mjibson/goon/doc.go index 81a25fd7..d49e0614 100644 --- a/_third_party/github.com/mjibson/goon/doc.go +++ b/_third_party/github.com/mjibson/goon/doc.go @@ -88,7 +88,7 @@ datastore: type Group struct { Name string } - c := appengine.NewContext(r) + c := r.NewContext() g := &Group{Name: "name"} k := datastore.NewIncompleteKey(c, "Group", nil) err := datastore.Put(c, k, g) @@ -110,7 +110,7 @@ datastore: type Group struct { Name string } - c := appengine.NewContext(r) + c := r.NewContext() g := &Group{} k := datastore.NewKey(c, "Group", "", 1, nil) err := datastore.Get(c, k, g) diff --git a/_third_party/github.com/mjibson/goon/entity.go b/_third_party/github.com/mjibson/goon/entity.go index a9c46cd2..46d5403f 100644 --- a/_third_party/github.com/mjibson/goon/entity.go +++ b/_third_party/github.com/mjibson/goon/entity.go @@ -26,8 +26,8 @@ import ( "sync" "time" - "appengine" - "appengine/datastore" + "google.golang.org/appengine/v2" + "google.golang.org/appengine/v2/datastore" ) type fieldInfo struct { diff --git a/_third_party/github.com/mjibson/goon/goon.go b/_third_party/github.com/mjibson/goon/goon.go index 087c6e84..b6886859 100644 --- a/_third_party/github.com/mjibson/goon/goon.go +++ b/_third_party/github.com/mjibson/goon/goon.go @@ -26,15 +26,18 @@ import ( "sync" "time" - "appengine" - "appengine/datastore" - "appengine/memcache" + "golang.org/x/net/context" + + "google.golang.org/appengine/v2" + "google.golang.org/appengine/v2/log" + "google.golang.org/appengine/v2/datastore" + "google.golang.org/appengine/v2/memcache" ) var ( - // LogErrors issues appengine.Context.Errorf on any error. + // LogErrors issues context.Context.Errorf on any error. LogErrors = true - // LogTimeoutErrors issues appengine.Context.Warningf on memcache timeout errors. + // LogTimeoutErrors issues context.Context.Warningf on memcache timeout errors. LogTimeoutErrors = false // MemcachePutTimeoutThreshold is the number of bytes at which the memcache @@ -53,7 +56,7 @@ var ( // Goon holds the app engine context and the request memory cache. type Goon struct { - Context appengine.Context + Context context.Context cache map[string]interface{} cacheLock sync.RWMutex // protect the cache from concurrent goroutines to speed up RPC access inTransaction bool @@ -75,9 +78,9 @@ func NewGoon(r *http.Request) *Goon { return FromContext(appengine.NewContext(r)) } -// FromContext creates a new Goon object from the given appengine Context. +// FromContext creates a new Goon object from the given context Context. // Useful with profiling packages like appstats. -func FromContext(c appengine.Context) *Goon { +func FromContext(c context.Context) *Goon { return &Goon{ Context: c, cache: make(map[string]interface{}), @@ -91,15 +94,15 @@ func (g *Goon) error(err error) { } _, filename, line, ok := runtime.Caller(1) if ok { - g.Context.Errorf("goon - %s:%d - %v", filepath.Base(filename), line, err) + log.Errorf(g.Context, "goon - %s:%d - %v", filepath.Base(filename), line, err) } else { - g.Context.Errorf("goon - %v", err) + log.Errorf(g.Context, "goon - %v", err) } } func (g *Goon) timeoutError(err error) { if LogTimeoutErrors { - g.Context.Warningf("goon memcache timeout: %v", err) + log.Warningf(g.Context, "goon memcache timeout: %v", err) } } @@ -158,7 +161,7 @@ func (g *Goon) KeyError(src interface{}) (*datastore.Key, error) { // https://developers.google.com/appengine/docs/go/datastore/reference#RunInTransaction func (g *Goon) RunInTransaction(f func(tg *Goon) error, opts *datastore.TransactionOptions) error { var ng *Goon - err := datastore.RunInTransaction(g.Context, func(tc appengine.Context) error { + err := datastore.RunInTransaction(g.Context, func(tc context.Context) error { ng = &Goon{ Context: tc, inTransaction: true, @@ -346,7 +349,8 @@ func (g *Goon) putMemcache(srcs []interface{}, exists []byte) error { } errc := make(chan error) go func() { - errc <- memcache.SetMulti(appengine.Timeout(g.Context, memcacheTimeout), items) + c, _ := context.WithTimeout(g.Context, memcacheTimeout) + errc <- memcache.SetMulti(c, items) }() g.putMemoryMulti(srcs, exists) err := <-errc @@ -440,7 +444,8 @@ func (g *Goon) GetMulti(dst interface{}) error { multiErr, any := make(appengine.MultiError, len(keys)), false - memvalues, err := memcache.GetMulti(appengine.Timeout(g.Context, MemcacheGetTimeout), memkeys) + c, _ := context.WithTimeout(g.Context, MemcacheGetTimeout) + memvalues, err := memcache.GetMulti(c, memkeys) if appengine.IsTimeoutError(err) { g.timeoutError(err) err = nil diff --git a/_third_party/github.com/mjibson/goon/goon_test.go b/_third_party/github.com/mjibson/goon/goon_test.go index d0f03e82..d0f3fe73 100644 --- a/_third_party/github.com/mjibson/goon/goon_test.go +++ b/_third_party/github.com/mjibson/goon/goon_test.go @@ -22,10 +22,10 @@ import ( "testing" "time" - "appengine" - "appengine/aetest" - "appengine/datastore" - "appengine/memcache" + "google.golang.org/appengine/v2" + "google.golang.org/appengine/v2/aetest" + "google.golang.org/appengine/v2/datastore" + "google.golang.org/appengine/v2/memcache" ) // *[]S, *[]*S, *[]I, []S, []*S, []I diff --git a/_third_party/github.com/mjibson/goon/query.go b/_third_party/github.com/mjibson/goon/query.go index 1b4acca9..bebc90ec 100644 --- a/_third_party/github.com/mjibson/goon/query.go +++ b/_third_party/github.com/mjibson/goon/query.go @@ -20,7 +20,7 @@ import ( "fmt" "reflect" - "appengine/datastore" + "google.golang.org/appengine/v2/datastore" ) // Count returns the number of results for the query. diff --git a/admin.go b/admin.go index 4f9f5c83..b247658f 100644 --- a/admin.go +++ b/admin.go @@ -24,8 +24,9 @@ import ( "strings" "time" - "appengine/datastore" - "appengine/memcache" + "google.golang.org/appengine/v2/datastore" + "google.golang.org/appengine/v2/log" + "google.golang.org/appengine/v2/memcache" mpg "github.com/mjibson/goread/_third_party/github.com/MiniProfiler/go/miniprofiler_gae" "github.com/mjibson/goread/_third_party/github.com/mjibson/goon" @@ -90,28 +91,13 @@ func AdminFeed(c mpg.Context, w http.ResponseWriter, r *http.Request) { } } gn.GetMulti(stories) - lk := gn.Key(&Log{Parent: fk, Id: time.Now().Add(-time.Hour * 6).UnixNano()}) - q = datastore.NewQuery(lk.Kind()).KeysOnly() - q = q.Ancestor(fk) - q = q.Filter("__key__ >", lk) - keys, _ = gn.GetAll(q, nil) - logs := make([]*Log, len(keys)) - for j, key := range keys { - logs[j] = &Log{ - Id: key.IntID(), - Parent: fk, - } - } - gn.GetMulti(logs) templates.ExecuteTemplate(w, "admin-feed.html", struct { Feed *Feed - Logs []*Log Stories []*Story Now time.Time }{ &f, - logs, stories, time.Now(), }) @@ -175,8 +161,7 @@ func AdminUser(c mpg.Context, w http.ResponseWriter, r *http.Request) { it := gn.Run(q) var u User ud := UserData{Id: "data"} - var h []Log - k, err := it.Next(&u) + _, err := it.Next(&u) if err != nil { serveError(w, err) return @@ -199,18 +184,14 @@ func AdminUser(c mpg.Context, w http.ResponseWriter, r *http.Request) { serveError(w, err) return } - c.Infof("opml updated") + log.Infof(c, "opml updated") } - q = datastore.NewQuery(gn.Kind(&Log{})).Ancestor(k) - _, err = gn.GetAll(q, &h) if err := templates.ExecuteTemplate(w, "admin-user.html", struct { User User Data UserData - Log []Log }{ u, ud, - h, }); err != nil { serveError(w, err) } diff --git a/app/.gcloudignore b/app/.gcloudignore new file mode 100644 index 00000000..199e6d9f --- /dev/null +++ b/app/.gcloudignore @@ -0,0 +1,25 @@ +# This file specifies files that are *not* uploaded to Google Cloud Platform +# using gcloud. It follows the same syntax as .gitignore, with the addition of +# "#!include" directives (which insert the entries of the given .gitignore-style +# file at that point). +# +# For more information, run: +# $ gcloud topic gcloudignore +# +.gcloudignore +# If you would like to upload your .git directory, .gitignore file or files +# from your .gitignore file, remove the corresponding line +# below: +.git +.gitignore + +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib +# Test binary, build with `go test -c` +*.test +# Output of the go coverage tool, specifically when used with LiteIDE +*.out \ No newline at end of file diff --git a/app/app.go b/app/app.go index e23c23cb..89df3e49 100644 --- a/app/app.go +++ b/app/app.go @@ -1,15 +1,39 @@ -package app +package main +/* import ( + "log" + "os" "net/http" - + "google.golang.org/appengine" "github.com/mjibson/goread/_third_party/github.com/gorilla/mux" - app "github.com/mjibson/goread" ) -func init() { +func main() { router := mux.NewRouter() app.RegisterHandlers(router) http.Handle("/", router) + + port := os.Getenv("PORT") + if port == "" { + port = "8080" + log.Printf("Defaulting to port %s", port) + } + + log.Printf("Listening on port %s", port) + if err := http.ListenAndServe(":"+port, nil); err != nil { + log.Fatal(err) + } +} +*/ + +import ( + "google.golang.org/appengine/v2" + _ "github.com/mjibson/goread" + _ "github.com/mjibson/goread/_third_party/github.com/mjibson/appstats" +) + +func main() { + appengine.Main() } diff --git a/app/app.sample.yaml b/app/app.sample.yaml index 6d689217..8b5a49e8 100644 --- a/app/app.sample.yaml +++ b/app/app.sample.yaml @@ -1,7 +1,5 @@ -application: go-read -version: 1 -runtime: go -api_version: go1 +runtime: go116 +app_engine_apis: true automatic_scaling: min_idle_instances: 1 @@ -26,34 +24,33 @@ handlers: - url: /index.html static_files: static/index.html upload: static/index.html - application_readable: true - url: /static static_dir: static - url: /login/google login: required - script: _go_app + script: auto secure: always - url: /user/.* login: required - script: _go_app + script: auto secure: always - url: /task/.* login: admin - script: _go_app + script: auto secure: always - url: /admin/.* login: admin - script: _go_app + script: auto secure: always - url: /push - script: _go_app + script: auto - url: /.* - script: _go_app + script: auto secure: always diff --git a/app/templates/admin-feed.html b/app/templates/admin-feed.html index 66e5d90c..51405ea5 100644 --- a/app/templates/admin-feed.html +++ b/app/templates/admin-feed.html @@ -25,17 +25,6 @@
| {{nanotime .Id | since}} | -{{nanotime .Id}} | -{{.Text}} | -