OLD | NEW |
1 package main | 1 package main |
2 | 2 |
3 import ( | 3 import ( |
4 "bytes" | 4 "bytes" |
5 "crypto/md5" | 5 "crypto/md5" |
6 "database/sql" | 6 "database/sql" |
7 "encoding/base64" | 7 "encoding/base64" |
8 "encoding/json" | 8 "encoding/json" |
9 "flag" | 9 "flag" |
10 "fmt" | 10 "fmt" |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
91 "waterfall", "river", "breeze", "moon", "rain", "wind", "sea", "
morning", | 91 "waterfall", "river", "breeze", "moon", "rain", "wind", "sea", "
morning", |
92 "snow", "lake", "sunset", "pine", "shadow", "leaf", "dawn", "gli
tter", | 92 "snow", "lake", "sunset", "pine", "shadow", "leaf", "dawn", "gli
tter", |
93 "forest", "hill", "cloud", "meadow", "sun", "glade", "bird", "br
ook", | 93 "forest", "hill", "cloud", "meadow", "sun", "glade", "bird", "br
ook", |
94 "butterfly", "bush", "dew", "dust", "field", "fire", "flower", "
firefly", | 94 "butterfly", "bush", "dew", "dust", "field", "fire", "flower", "
firefly", |
95 "feather", "grass", "haze", "mountain", "night", "pond", "darkne
ss", | 95 "feather", "grass", "haze", "mountain", "night", "pond", "darkne
ss", |
96 "snowflake", "silence", "sound", "sky", "shape", "surf", "thunde
r", | 96 "snowflake", "silence", "sound", "sky", "shape", "surf", "thunde
r", |
97 "violet", "water", "wildflower", "wave", "water", "resonance", "
sun", | 97 "violet", "water", "wildflower", "wave", "water", "resonance", "
sun", |
98 "wood", "dream", "cherry", "tree", "fog", "frost", "voice", "pap
er", | 98 "wood", "dream", "cherry", "tree", "fog", "frost", "voice", "pap
er", |
99 "frog", "smoke", "star", | 99 "frog", "smoke", "star", |
100 } | 100 } |
| 101 |
| 102 gitHash = "" |
| 103 gitInfo = "" |
101 ) | 104 ) |
102 | 105 |
103 // flags | 106 // flags |
104 var ( | 107 var ( |
105 useChroot = flag.Bool("use_chroot", false, "Run the compiled code in the
schroot jail.") | 108 useChroot = flag.Bool("use_chroot", false, "Run the compiled code in the
schroot jail.") |
106 port = flag.String("port", ":8000", "HTTP service address (e.g., ':
8000')") | 109 port = flag.String("port", ":8000", "HTTP service address (e.g., ':
8000')") |
107 ) | 110 ) |
108 | 111 |
109 // lineNumbers adds #line numbering to the user's code. | 112 // lineNumbers adds #line numbering to the user's code. |
110 func LineNumbers(c string) string { | 113 func LineNumbers(c string) string { |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
156 } | 159 } |
157 workspaceTemplate, err = htemplate.ParseFiles( | 160 workspaceTemplate, err = htemplate.ParseFiles( |
158 filepath.Join(cwd, "templates/workspace.html"), | 161 filepath.Join(cwd, "templates/workspace.html"), |
159 filepath.Join(cwd, "templates/titlebar.html"), | 162 filepath.Join(cwd, "templates/titlebar.html"), |
160 filepath.Join(cwd, "templates/content.html"), | 163 filepath.Join(cwd, "templates/content.html"), |
161 ) | 164 ) |
162 if err != nil { | 165 if err != nil { |
163 panic(err) | 166 panic(err) |
164 } | 167 } |
165 | 168 |
| 169 // The git command returns output of the format: |
| 170 // |
| 171 // f672cead70404080a991ebfb86c38316a4589b23 2014-04-27 19:21:51 +0000 |
| 172 // |
| 173 logOutput, err := doCmd(`git log --format=%H%x20%ai HEAD^..HEAD`, true) |
| 174 if err != nil { |
| 175 panic(err) |
| 176 } |
| 177 logInfo := strings.Split(logOutput, " ") |
| 178 gitHash = logInfo[0] |
| 179 gitInfo = logInfo[1] + " " + logInfo[2] + " " + logInfo[0][0:6] |
| 180 |
166 // Connect to MySQL server. First, get the password from the metadata se
rver. | 181 // Connect to MySQL server. First, get the password from the metadata se
rver. |
167 // See https://developers.google.com/compute/docs/metadata#custom. | 182 // See https://developers.google.com/compute/docs/metadata#custom. |
168 req, err := http.NewRequest("GET", "http://metadata/computeMetadata/v1/i
nstance/attributes/password", nil) | 183 req, err := http.NewRequest("GET", "http://metadata/computeMetadata/v1/i
nstance/attributes/password", nil) |
169 if err != nil { | 184 if err != nil { |
170 panic(err) | 185 panic(err) |
171 } | 186 } |
172 client := http.Client{} | 187 client := http.Client{} |
173 req.Header.Add("X-Google-Metadata-Request", "True") | 188 req.Header.Add("X-Google-Metadata-Request", "True") |
174 if resp, err := client.Do(req); err == nil { | 189 if resp, err := client.Do(req); err == nil { |
175 password, err := ioutil.ReadAll(resp.Body) | 190 password, err := ioutil.ReadAll(resp.Body) |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
214 hash CHAR(64) DEFAULT '' NOT NULL, | 229 hash CHAR(64) DEFAULT '' NOT NULL, |
215 hidden INTEGER DEFAULT 0 NOT NULL, | 230 hidden INTEGER DEFAULT 0 NOT NULL, |
216 | 231 |
217 FOREIGN KEY (name) REFERENCES workspace(name) | 232 FOREIGN KEY (name) REFERENCES workspace(name) |
218 )` | 233 )` |
219 _, err = db.Exec(sql) | 234 _, err = db.Exec(sql) |
220 log.Printf("Info: status creating sqlite table for workspace try
: %q\n", err) | 235 log.Printf("Info: status creating sqlite table for workspace try
: %q\n", err) |
221 } | 236 } |
222 } | 237 } |
223 | 238 |
| 239 // Titlebar is used in titlebar template expansion. |
| 240 type Titlebar struct { |
| 241 GitHash string |
| 242 GitInfo string |
| 243 } |
| 244 |
224 // userCode is used in template expansion. | 245 // userCode is used in template expansion. |
225 type userCode struct { | 246 type userCode struct { |
226 » Code string | 247 » Code string |
227 » Hash string | 248 » Hash string |
| 249 » Titlebar Titlebar |
228 } | 250 } |
229 | 251 |
230 // expandToFile expands the template and writes the result to the file. | 252 // expandToFile expands the template and writes the result to the file. |
231 func expandToFile(filename string, code string, t *template.Template) error { | 253 func expandToFile(filename string, code string, t *template.Template) error { |
232 f, err := os.Create(filename) | 254 f, err := os.Create(filename) |
233 if err != nil { | 255 if err != nil { |
234 return err | 256 return err |
235 } | 257 } |
236 defer f.Close() | 258 defer f.Close() |
237 » return t.Execute(f, userCode{Code: code}) | 259 » return t.Execute(f, userCode{Code: code, Titlebar: Titlebar{GitHash: git
Hash, GitInfo: gitInfo}}) |
238 } | 260 } |
239 | 261 |
240 // expandCode expands the template into a file and calculate the MD5 hash. | 262 // expandCode expands the template into a file and calculate the MD5 hash. |
241 func expandCode(code string) (string, error) { | 263 func expandCode(code string) (string, error) { |
242 h := md5.New() | 264 h := md5.New() |
243 h.Write([]byte(code)) | 265 h.Write([]byte(code)) |
244 hash := fmt.Sprintf("%x", h.Sum(nil)) | 266 hash := fmt.Sprintf("%x", h.Sum(nil)) |
245 // At this point we are running in skia/experimental/webtry, making cach
e a | 267 // At this point we are running in skia/experimental/webtry, making cach
e a |
246 // peer directory to skia. | 268 // peer directory to skia. |
247 // TODO(jcgregorio) Make all relative directories into flags. | 269 // TODO(jcgregorio) Make all relative directories into flags. |
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
358 filename := match[1] | 380 filename := match[1] |
359 http.ServeFile(w, r, fmt.Sprintf("../../../inout/%s", filename)) | 381 http.ServeFile(w, r, fmt.Sprintf("../../../inout/%s", filename)) |
360 } | 382 } |
361 | 383 |
362 type Try struct { | 384 type Try struct { |
363 Hash string `json:"hash"` | 385 Hash string `json:"hash"` |
364 CreateTS string `json:"create_ts"` | 386 CreateTS string `json:"create_ts"` |
365 } | 387 } |
366 | 388 |
367 type Recent struct { | 389 type Recent struct { |
368 » Tries []Try | 390 » Tries []Try |
| 391 » Titlebar Titlebar |
369 } | 392 } |
370 | 393 |
371 // recentHandler shows the last 20 tries. | 394 // recentHandler shows the last 20 tries. |
372 func recentHandler(w http.ResponseWriter, r *http.Request) { | 395 func recentHandler(w http.ResponseWriter, r *http.Request) { |
373 log.Printf("Recent Handler: %q\n", r.URL.Path) | 396 log.Printf("Recent Handler: %q\n", r.URL.Path) |
374 | 397 |
375 var err error | 398 var err error |
376 rows, err := db.Query("SELECT create_ts, hash FROM webtry ORDER BY creat
e_ts DESC LIMIT 20") | 399 rows, err := db.Query("SELECT create_ts, hash FROM webtry ORDER BY creat
e_ts DESC LIMIT 20") |
377 if err != nil { | 400 if err != nil { |
378 http.NotFound(w, r) | 401 http.NotFound(w, r) |
379 return | 402 return |
380 } | 403 } |
381 recent := []Try{} | 404 recent := []Try{} |
382 for rows.Next() { | 405 for rows.Next() { |
383 var hash string | 406 var hash string |
384 var create_ts time.Time | 407 var create_ts time.Time |
385 if err := rows.Scan(&create_ts, &hash); err != nil { | 408 if err := rows.Scan(&create_ts, &hash); err != nil { |
386 log.Printf("Error: failed to fetch from database: %q", e
rr) | 409 log.Printf("Error: failed to fetch from database: %q", e
rr) |
387 continue | 410 continue |
388 } | 411 } |
389 recent = append(recent, Try{Hash: hash, CreateTS: create_ts.Form
at("2006-02-01")}) | 412 recent = append(recent, Try{Hash: hash, CreateTS: create_ts.Form
at("2006-02-01")}) |
390 } | 413 } |
391 » if err := recentTemplate.Execute(w, Recent{Tries: recent}); err != nil { | 414 » if err := recentTemplate.Execute(w, Recent{Tries: recent, Titlebar: Titl
ebar{GitHash: gitHash, GitInfo: gitInfo}}); err != nil { |
392 log.Printf("ERROR: Failed to expand template: %q\n", err) | 415 log.Printf("ERROR: Failed to expand template: %q\n", err) |
393 } | 416 } |
394 } | 417 } |
395 | 418 |
396 type Workspace struct { | 419 type Workspace struct { |
397 » Name string | 420 » Name string |
398 » Code string | 421 » Code string |
399 » Hash string | 422 » Hash string |
400 » Tries []Try | 423 » Tries []Try |
| 424 » Titlebar Titlebar |
401 } | 425 } |
402 | 426 |
403 // newWorkspace generates a new random workspace name and stores it in the datab
ase. | 427 // newWorkspace generates a new random workspace name and stores it in the datab
ase. |
404 func newWorkspace() (string, error) { | 428 func newWorkspace() (string, error) { |
405 for i := 0; i < 10; i++ { | 429 for i := 0; i < 10; i++ { |
406 adj := workspaceNameAdj[rand.Intn(len(workspaceNameAdj))] | 430 adj := workspaceNameAdj[rand.Intn(len(workspaceNameAdj))] |
407 noun := workspaceNameNoun[rand.Intn(len(workspaceNameNoun))] | 431 noun := workspaceNameNoun[rand.Intn(len(workspaceNameNoun))] |
408 suffix := rand.Intn(1000) | 432 suffix := rand.Intn(1000) |
409 name := fmt.Sprintf("%s-%s-%d", adj, noun, suffix) | 433 name := fmt.Sprintf("%s-%s-%d", adj, noun, suffix) |
410 if _, err := db.Exec("INSERT INTO workspace (name) VALUES(?)", n
ame); err == nil { | 434 if _, err := db.Exec("INSERT INTO workspace (name) VALUES(?)", n
ame); err == nil { |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
450 } | 474 } |
451 } | 475 } |
452 var code string | 476 var code string |
453 var hash string | 477 var hash string |
454 if len(tries) == 0 { | 478 if len(tries) == 0 { |
455 code = DEFAULT_SAMPLE | 479 code = DEFAULT_SAMPLE |
456 } else { | 480 } else { |
457 hash = tries[len(tries)-1].Hash | 481 hash = tries[len(tries)-1].Hash |
458 code, _ = getCode(hash) | 482 code, _ = getCode(hash) |
459 } | 483 } |
460 » » if err := workspaceTemplate.Execute(w, Workspace{Tries: tries, C
ode: code, Name: name, Hash: hash}); err != nil { | 484 » » if err := workspaceTemplate.Execute(w, Workspace{Tries: tries, C
ode: code, Name: name, Hash: hash, Titlebar: Titlebar{GitHash: gitHash, GitInfo:
gitInfo}}); err != nil { |
461 log.Printf("ERROR: Failed to expand template: %q\n", err
) | 485 log.Printf("ERROR: Failed to expand template: %q\n", err
) |
462 } | 486 } |
463 } else if r.Method == "POST" { | 487 } else if r.Method == "POST" { |
464 name, err := newWorkspace() | 488 name, err := newWorkspace() |
465 if err != nil { | 489 if err != nil { |
466 http.Error(w, "Failed to create a new workspace.", 500) | 490 http.Error(w, "Failed to create a new workspace.", 500) |
467 return | 491 return |
468 } | 492 } |
469 http.Redirect(w, r, "/w/"+name, 302) | 493 http.Redirect(w, r, "/w/"+name, 302) |
470 } | 494 } |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
570 http.NotFound(w, r) | 594 http.NotFound(w, r) |
571 return | 595 return |
572 } | 596 } |
573 // Update 'code' with the code found in the database. | 597 // Update 'code' with the code found in the database. |
574 if err := db.QueryRow("SELECT code FROM webtry WHERE has
h=?", hash).Scan(&code); err != nil { | 598 if err := db.QueryRow("SELECT code FROM webtry WHERE has
h=?", hash).Scan(&code); err != nil { |
575 http.NotFound(w, r) | 599 http.NotFound(w, r) |
576 return | 600 return |
577 } | 601 } |
578 } | 602 } |
579 // Expand the template. | 603 // Expand the template. |
580 » » if err := indexTemplate.Execute(w, userCode{Code: code, Hash: ha
sh}); err != nil { | 604 » » if err := indexTemplate.Execute(w, userCode{Code: code, Hash: ha
sh, Titlebar: Titlebar{GitHash: gitHash, GitInfo: gitInfo}}); err != nil { |
581 log.Printf("ERROR: Failed to expand template: %q\n", err
) | 605 log.Printf("ERROR: Failed to expand template: %q\n", err
) |
582 } | 606 } |
583 } else if r.Method == "POST" { | 607 } else if r.Method == "POST" { |
584 w.Header().Set("Content-Type", "application/json") | 608 w.Header().Set("Content-Type", "application/json") |
585 buf := bytes.NewBuffer(make([]byte, 0, MAX_TRY_SIZE)) | 609 buf := bytes.NewBuffer(make([]byte, 0, MAX_TRY_SIZE)) |
586 n, err := buf.ReadFrom(r.Body) | 610 n, err := buf.ReadFrom(r.Body) |
587 if err != nil { | 611 if err != nil { |
588 reportTryError(w, r, err, "Failed to read a request body
.", "") | 612 reportTryError(w, r, err, "Failed to read a request body
.", "") |
589 return | 613 return |
590 } | 614 } |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
666 http.HandleFunc("/w/", workspaceHandler) | 690 http.HandleFunc("/w/", workspaceHandler) |
667 http.HandleFunc("/recent/", recentHandler) | 691 http.HandleFunc("/recent/", recentHandler) |
668 http.HandleFunc("/iframe/", iframeHandler) | 692 http.HandleFunc("/iframe/", iframeHandler) |
669 http.HandleFunc("/json/", tryInfoHandler) | 693 http.HandleFunc("/json/", tryInfoHandler) |
670 http.HandleFunc("/css/", cssHandler) | 694 http.HandleFunc("/css/", cssHandler) |
671 http.HandleFunc("/js/", jsHandler) | 695 http.HandleFunc("/js/", jsHandler) |
672 // TODO Break out /c/ as it's own handler. | 696 // TODO Break out /c/ as it's own handler. |
673 http.HandleFunc("/", mainHandler) | 697 http.HandleFunc("/", mainHandler) |
674 log.Fatal(http.ListenAndServe(*port, nil)) | 698 log.Fatal(http.ListenAndServe(*port, nil)) |
675 } | 699 } |
OLD | NEW |