Skip to content
This repository was archived by the owner on Jan 16, 2021. It is now read-only.

Commit 50b6fe2

Browse files
committed
Import talksapp
2 parents f2c2de4 + bdf4e34 commit 50b6fe2

File tree

8 files changed

+355
-0
lines changed

8 files changed

+355
-0
lines changed

talksapp/.gitignore

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# Compiled Object files, Static and Dynamic libs (Shared Objects)
2+
*.o
3+
*.a
4+
*.so
5+
6+
# Folders
7+
_obj
8+
_test
9+
10+
# Architecture specific extensions/prefixes
11+
*.[568vq]
12+
[568vq].out
13+
14+
*.cgo1.go
15+
*.cgo2.c
16+
_cgo_defun.c
17+
_cgo_gotypes.go
18+
_cgo_export.*
19+
20+
_testmain.go
21+
22+
*.exe

talksapp/README.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
talksapp
2+
========
3+
4+
This directory contains the source for [go-talks.appspot.com](http://go-talks.appspot.com).
5+
6+
Development Environment Setup
7+
-----------------------------
8+
9+
- Copy config.go.template to config.go and edit the file as described in the comments.
10+
- Install Go App Engine SDK
11+
- $ sh setup.sh
12+
- Run the server using the dev_appserver command.

talksapp/app.yaml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
application: go-talks
2+
version: 1
3+
runtime: go
4+
api_version: go1
5+
6+
handlers:
7+
- url: /robots\.txt
8+
static_files: assets/robots.txt
9+
upload: assets/robots.txt
10+
- url: /favicon\.ico
11+
static_files: present/static/favicon.ico
12+
upload: present/static/favicon.ico
13+
- url: /static
14+
static_dir: present/static
15+
- url: /play\.js
16+
static_files: present/play.js
17+
upload: present/play.js
18+
- url: /.*
19+
script: _go_app

talksapp/assets/home.article

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
go-talks.appspot.org
2+
3+
Francesc Campoy (maintainer)
4+
@francesc
5+
6+
Gary Burd
7+
@gburd
8+
9+
* Introduction
10+
11+
This site plays slide presentations and articles stored on GitHub in the
12+
[[http://godoc.org/code.google.com/p/go.tools/present][present format]].
13+
14+
The syntax for URLs is:
15+
16+
http://go-talks.appspot.com/github.com/owner/project/file.ext
17+
http://go-talks.appspot.com/github.com/owner/project/sub/directory/file.ext
18+
19+
The supported file extensions (.ext) are .slide and .article.
20+
21+
The .html command is not supported.
22+
23+
This page is [[/github.com/golang/gddo/talksapp/assets/home.article][an article]].
24+
25+
* Feedback
26+
27+
Report bugs and request features using the [[https://github.com/golang/gddo/issues/new][GitHub Issue Tracker]].

talksapp/assets/robots.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
User-agent: *
2+
Disallow: /

talksapp/config.go.template

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package talksapp
2+
3+
func init() {
4+
// Register an application at https://github.com/settings/applications/new
5+
// and enter the client ID and client secret here.
6+
gitHubCredentials = "client_id=<id>&client_secret=<secret>"
7+
8+
// Set contact email for /bot.html
9+
contactEmail = "[email protected]"
10+
}

talksapp/main.go

Lines changed: 249 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,249 @@
1+
// Copyright 2013 The Go Authors. All rights reserved.
2+
//
3+
// Use of this source code is governed by a BSD-style
4+
// license that can be found in the LICENSE file or at
5+
// https://developers.google.com/open-source/licenses/bsd.
6+
7+
// Package talksapp implements the go-talks.appspot.com server.
8+
package talksapp
9+
10+
import (
11+
"bytes"
12+
"errors"
13+
"fmt"
14+
"html/template"
15+
"io"
16+
"net/http"
17+
"os"
18+
"path"
19+
"time"
20+
21+
"appengine"
22+
"appengine/memcache"
23+
"appengine/urlfetch"
24+
25+
"code.google.com/p/go.tools/present"
26+
"github.com/golang/gddo/gosrc"
27+
)
28+
29+
var (
30+
presentTemplates = map[string]*template.Template{
31+
".article": parsePresentTemplate("article.tmpl"),
32+
".slide": parsePresentTemplate("slides.tmpl"),
33+
}
34+
homeArticle = loadHomeArticle()
35+
contactEmail = "[email protected]"
36+
gitHubCredentials = ""
37+
)
38+
39+
func init() {
40+
http.Handle("/", handlerFunc(serveRoot))
41+
http.Handle("/compile", handlerFunc(serveCompile))
42+
http.Handle("/bot.html", handlerFunc(serveBot))
43+
present.PlayEnabled = true
44+
}
45+
46+
func playable(c present.Code) bool {
47+
return present.PlayEnabled && c.Play && c.Ext == ".go"
48+
}
49+
50+
func parsePresentTemplate(name string) *template.Template {
51+
t := present.Template()
52+
t = t.Funcs(template.FuncMap{"playable": playable})
53+
if _, err := t.ParseFiles("present/templates/"+name, "present/templates/action.tmpl"); err != nil {
54+
panic(err)
55+
}
56+
t = t.Lookup("root")
57+
if t == nil {
58+
panic("root template not found for " + name)
59+
}
60+
return t
61+
}
62+
63+
func loadHomeArticle() []byte {
64+
const fname = "assets/home.article"
65+
f, err := os.Open(fname)
66+
if err != nil {
67+
panic(err)
68+
}
69+
defer f.Close()
70+
doc, err := present.Parse(f, fname, 0)
71+
if err != nil {
72+
panic(err)
73+
}
74+
var buf bytes.Buffer
75+
if err := renderPresentation(&buf, fname, doc); err != nil {
76+
panic(err)
77+
}
78+
return buf.Bytes()
79+
}
80+
81+
func renderPresentation(w io.Writer, fname string, doc *present.Doc) error {
82+
t := presentTemplates[path.Ext(fname)]
83+
if t == nil {
84+
return errors.New("unknown template extension")
85+
}
86+
data := struct {
87+
*present.Doc
88+
Template *template.Template
89+
PlayEnabled bool
90+
}{
91+
doc,
92+
t,
93+
true,
94+
}
95+
return t.Execute(w, &data)
96+
}
97+
98+
type presFileNotFoundError string
99+
100+
func (s presFileNotFoundError) Error() string { return fmt.Sprintf("File %s not found.", string(s)) }
101+
102+
func writeHTMLHeader(w http.ResponseWriter, status int) {
103+
w.Header().Set("Content-Type", "text/html; charset=utf-8")
104+
w.WriteHeader(status)
105+
}
106+
107+
func writeTextHeader(w http.ResponseWriter, status int) {
108+
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
109+
w.WriteHeader(status)
110+
}
111+
112+
type transport struct {
113+
rt http.RoundTripper
114+
ua string
115+
}
116+
117+
func (t transport) RoundTrip(r *http.Request) (*http.Response, error) {
118+
r.Header.Set("User-Agent", t.ua)
119+
if r.URL.Host == "api.github.com" && gitHubCredentials != "" {
120+
if r.URL.RawQuery == "" {
121+
r.URL.RawQuery = gitHubCredentials
122+
} else {
123+
r.URL.RawQuery += "&" + gitHubCredentials
124+
}
125+
}
126+
return t.rt.RoundTrip(r)
127+
}
128+
129+
func httpClient(r *http.Request) *http.Client {
130+
c := appengine.NewContext(r)
131+
return &http.Client{
132+
Transport: &transport{
133+
rt: &urlfetch.Transport{Context: c, Deadline: 10 * time.Second},
134+
ua: fmt.Sprintf("%s (+http://%s/bot.html)", appengine.AppID(c), r.Host),
135+
},
136+
}
137+
}
138+
139+
type handlerFunc func(http.ResponseWriter, *http.Request) error
140+
141+
func (f handlerFunc) ServeHTTP(w http.ResponseWriter, r *http.Request) {
142+
c := appengine.NewContext(r)
143+
err := f(w, r)
144+
if err == nil {
145+
return
146+
} else if gosrc.IsNotFound(err) {
147+
writeTextHeader(w, 400)
148+
io.WriteString(w, "Not Found.")
149+
} else if e, ok := err.(*gosrc.RemoteError); ok {
150+
writeTextHeader(w, 500)
151+
fmt.Fprintf(w, "Error accessing %s.\n%v", e.Host, e)
152+
c.Infof("Remote error %s: %v", e.Host, e)
153+
} else if e, ok := err.(presFileNotFoundError); ok {
154+
writeTextHeader(w, 200)
155+
io.WriteString(w, e.Error())
156+
} else if err != nil {
157+
writeTextHeader(w, 500)
158+
io.WriteString(w, "Internal server error.")
159+
c.Errorf("Internal error %v", err)
160+
}
161+
}
162+
163+
func serveRoot(w http.ResponseWriter, r *http.Request) error {
164+
switch {
165+
case r.Method != "GET" && r.Method != "HEAD":
166+
writeTextHeader(w, 405)
167+
_, err := io.WriteString(w, "Method not supported.")
168+
return err
169+
case r.URL.Path == "/":
170+
writeHTMLHeader(w, 200)
171+
_, err := w.Write(homeArticle)
172+
return err
173+
default:
174+
return servePresentation(w, r)
175+
}
176+
}
177+
178+
func servePresentation(w http.ResponseWriter, r *http.Request) error {
179+
c := appengine.NewContext(r)
180+
importPath := r.URL.Path[1:]
181+
182+
item, err := memcache.Get(c, importPath)
183+
if err == nil {
184+
writeHTMLHeader(w, 200)
185+
w.Write(item.Value)
186+
return nil
187+
} else if err != memcache.ErrCacheMiss {
188+
return err
189+
}
190+
191+
c.Infof("Fetching presentation %s.", importPath)
192+
pres, err := gosrc.GetPresentation(httpClient(r), importPath)
193+
if err != nil {
194+
return err
195+
}
196+
197+
ctx := &present.Context{
198+
ReadFile: func(name string) ([]byte, error) {
199+
if p, ok := pres.Files[name]; ok {
200+
return p, nil
201+
}
202+
return nil, presFileNotFoundError(name)
203+
},
204+
}
205+
206+
doc, err := ctx.Parse(bytes.NewReader(pres.Files[pres.Filename]), pres.Filename, 0)
207+
if err != nil {
208+
return err
209+
}
210+
211+
var buf bytes.Buffer
212+
if err := renderPresentation(&buf, importPath, doc); err != nil {
213+
return err
214+
}
215+
216+
if err := memcache.Add(c, &memcache.Item{
217+
Key: importPath,
218+
Value: buf.Bytes(),
219+
Expiration: time.Hour,
220+
}); err != nil {
221+
return err
222+
}
223+
224+
writeHTMLHeader(w, 200)
225+
_, err = w.Write(buf.Bytes())
226+
return err
227+
}
228+
229+
func serveCompile(w http.ResponseWriter, r *http.Request) error {
230+
client := urlfetch.Client(appengine.NewContext(r))
231+
if err := r.ParseForm(); err != nil {
232+
return err
233+
}
234+
resp, err := client.PostForm("http://play.golang.org/compile", r.Form)
235+
if err != nil {
236+
return err
237+
}
238+
defer resp.Body.Close()
239+
w.Header().Set("Content-Type", resp.Header.Get("Content-Type"))
240+
_, err = io.Copy(w, resp.Body)
241+
return err
242+
}
243+
244+
func serveBot(w http.ResponseWriter, r *http.Request) error {
245+
c := appengine.NewContext(r)
246+
writeTextHeader(w, 200)
247+
_, err := fmt.Fprintf(w, "Contact %s for help with the %s bot.", contactEmail, appengine.AppID(c))
248+
return err
249+
}

talksapp/setup.sh

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#!/bin/sh
2+
go get golang.org/x/tools/cmd/present
3+
go get golang.org/x/tools/godoc
4+
present=`go list -f '{{.Dir}}' golang.org/x/tools/cmd/present`
5+
godoc=`go list -f '{{.Dir}}' golang.org/x/tools/godoc`
6+
mkdir -p present
7+
8+
(cat $godoc/static/jquery.js $godoc/static/playground.js $godoc/static/play.js && echo "initPlayground(new HTTPTransport());") > present/play.js
9+
10+
cd ./present
11+
for i in templates static
12+
do
13+
ln -is $present/$i
14+
done

0 commit comments

Comments
 (0)