| 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 |