Commits

Miki Tebeka committed b35225e

counter

Comments (0)

Files changed (6)

4-counter/app.yaml

+application: go-shortie
+version: 1
+runtime: go
+api_version: go1
+
+handlers:
+- url: /static
+  static_dir: static
+- url: /.*
+  script: _go_app

4-counter/run-local.sh

+#!/bin/bash
+# Run server locally
+
+/opt/google_appengine_go/dev_appserver.py . $@

4-counter/shortie/html.go

+package shortie
+
+const homeHTML = `
+<html>
+    <head>
+        <title>Shortie - The URL Shortener</title>
+        <link rel="stylesheet" href="/static/style.css" />
+        <link rel="shortcut icon" href="/static/logo.png" />
+    </head>
+    <body>
+        <div class="header">
+            The URL Shortener
+            <span class="right">
+				<a href="{{ .LoginURL }}">{{ .LoginTitle }}</a>
+            </span>
+        </div>
+
+        {{ if .Error }}
+        <div class="error">
+            ERROR: {{ .Error | html}}
+        </div>
+        {{ end }}
+
+        <form method="post">
+            <label for="url">Url:</label><input name="url" /> 
+            <input type="submit" value="Shorten">
+        </form>
+
+        <div class="footer">
+            G'day {{ .User }}, we've shortened {{ .Count }} urls so far.
+        </div>
+	</body>
+</html>
+`
+
+// vim: ft=html

4-counter/shortie/shortie.go

+/* AppEngine demo - a URL shortener */
+package shortie
+
+import (
+	"html/template"
+	"net/http"
+
+	"appengine"
+	"appengine/datastore"
+	"appengine/user"
+)
+
+const (
+	counterKeyName = "counter-key-name"
+	counterKind    = "Counter"
+)
+
+// Global counter of urls
+type Counter struct {
+	Count int64
+}
+
+// Parameters for homeTemplate.
+type homeParams struct {
+	User       string
+	LoginTitle string
+	LoginURL   string
+	Error      string
+	Count      int64
+}
+
+var homeTemplate *template.Template
+
+func init() {
+	homeTemplate = template.Must(template.New("home").Parse(homeHTML))
+	http.HandleFunc("/", rootHandler)
+}
+
+// rootHandler handles the main page.
+func rootHandler(w http.ResponseWriter, r *http.Request) {
+	ctx := appengine.NewContext(r)
+	var err error
+	params := new(homeParams)
+
+	// Run at end. We check "err" and update params if needed. Then serve homeTemplate.
+	defer func() {
+		if err != nil {
+			params.Error = err.Error()
+			ctx.Errorf("%v", err) // Log error
+		}
+		homeTemplate.Execute(w, params)
+	}()
+
+	err = fillUser(r, ctx, params)
+	if err != nil {
+		return
+	}
+	params.Count, err = urlCount(ctx)
+}
+
+// fillUser fills user details in template parameters
+func fillUser(r *http.Request, ctx appengine.Context, params *homeParams) error {
+	var err error
+	u := user.Current(ctx)
+
+	if u != nil {
+		params.User = u.String()
+		params.LoginTitle = "Logout"
+		params.LoginURL, err = user.LogoutURL(ctx, r.URL.String())
+	} else {
+		params.User = "Stranger"
+		params.LoginTitle = "Login"
+		params.LoginURL, err = user.LoginURL(ctx, r.URL.String())
+	}
+
+	return err
+}
+
+// urlCount return the current count of urls.
+func urlCount(ctx appengine.Context) (int64, error) {
+	key := datastore.NewKey(ctx, counterKind, counterKeyName, 0, nil)
+	counter := new(Counter)
+	if err := datastore.Get(ctx, key, counter); err != nil && err != datastore.ErrNoSuchEntity {
+		return 0, err
+	}
+
+	return counter.Count, nil
+}
Add a comment to this file

4-counter/static/logo.png

Added
New image

4-counter/static/style.css

+body {
+    margin: 20px;
+    border: 2px solid blue;
+    padding: 1px;
+}
+
+input[name=url] {
+    width: 80%;
+    margin-left: 4px;
+}
+
+span.right {
+    float: right;
+    margin-right: 5px;
+}
+
+div.header {
+    padding: 2px;
+    background: silver;
+    border-bottom: 1px solid gray;
+    margin-bottom: 10px;
+}
+
+table.urls {
+    border-collapse: collapse;
+    width: 100%;
+    border: 1px dashed blue;
+}
+
+table.urls th {
+    text-align: left;
+}
+
+div.footer {
+    margin-top: 10px;
+    padding-top: 5px;
+    border-top: 1px dashed gray;
+    padding-left: 10px;
+    font-family: Monospace;
+}
+
+div.error {
+    color: red;
+}
+
+tr.even {
+    background: #DCDCDC;
+}
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.