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/binary" | 8 "encoding/binary" |
9 "encoding/json" | 9 "encoding/json" |
10 "flag" | 10 "flag" |
(...skipping 237 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
248 )` | 248 )` |
249 _, err = db.Exec(sql) | 249 _, err = db.Exec(sql) |
250 if err != nil { | 250 if err != nil { |
251 log.Printf("Info: status creating sqlite table for sourc
es: %q\n", err) | 251 log.Printf("Info: status creating sqlite table for sourc
es: %q\n", err) |
252 } | 252 } |
253 | 253 |
254 sql = `CREATE TABLE IF NOT EXISTS webtry ( | 254 sql = `CREATE TABLE IF NOT EXISTS webtry ( |
255 code TEXT DEFAULT '' NOT NULL, | 255 code TEXT DEFAULT '' NOT NULL, |
256 create_ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, | 256 create_ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, |
257 hash CHAR(64) DEFAULT '' NOT NULL, | 257 hash CHAR(64) DEFAULT '' NOT NULL, |
258 width »» » INTEGER DEFAULT 256 NOT
NULL, | 258 width INTEGER DEFAULT 256 NOT NULL, |
259 height »» » INTEGER DEFAULT 256 NOT
NULL, | 259 height INTEGER DEFAULT 256 NOT NULL, |
| 260 gpu BOOL DEFAULT 0 NOT NULL, |
260 source_image_id INTEGER DEFAULT 0 NOT NULL, | 261 source_image_id INTEGER DEFAULT 0 NOT NULL, |
261 | 262 |
262 PRIMARY KEY(hash) | 263 PRIMARY KEY(hash) |
263 )` | 264 )` |
264 _, err = db.Exec(sql) | 265 _, err = db.Exec(sql) |
265 if err != nil { | 266 if err != nil { |
266 log.Printf("Info: status creating sqlite table for webtr
y: %q\n", err) | 267 log.Printf("Info: status creating sqlite table for webtr
y: %q\n", err) |
267 } | 268 } |
268 | 269 |
269 sql = `CREATE TABLE IF NOT EXISTS workspace ( | 270 sql = `CREATE TABLE IF NOT EXISTS workspace ( |
270 name CHAR(64) DEFAULT '' NOT NULL, | 271 name CHAR(64) DEFAULT '' NOT NULL, |
271 create_ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, | 272 create_ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, |
272 PRIMARY KEY(name) | 273 PRIMARY KEY(name) |
273 )` | 274 )` |
274 _, err = db.Exec(sql) | 275 _, err = db.Exec(sql) |
275 if err != nil { | 276 if err != nil { |
276 log.Printf("Info: status creating sqlite table for works
pace: %q\n", err) | 277 log.Printf("Info: status creating sqlite table for works
pace: %q\n", err) |
277 } | 278 } |
278 | 279 |
279 sql = `CREATE TABLE IF NOT EXISTS workspacetry ( | 280 sql = `CREATE TABLE IF NOT EXISTS workspacetry ( |
280 name CHAR(64) DEFAULT '' NOT NULL, | 281 name CHAR(64) DEFAULT '' NOT NULL, |
281 create_ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, | 282 create_ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, |
282 hash CHAR(64) DEFAULT '' NOT NULL, | 283 hash CHAR(64) DEFAULT '' NOT NULL, |
283 width » » INTEGER DEFAULT 256 NOT NULL, | 284 width INTEGER DEFAULT 256 NOT NULL, |
284 height » » INTEGER DEFAULT 256 NOT NULL, | 285 height INTEGER DEFAULT 256 NOT NULL, |
| 286 gpu BOOL DEFAULT 0 NOT NULL, |
285 hidden INTEGER DEFAULT 0 NOT NULL, | 287 hidden INTEGER DEFAULT 0 NOT NULL, |
286 source_image_id INTEGER DEFAULT 0 NOT NULL, | 288 source_image_id INTEGER DEFAULT 0 NOT NULL, |
287 | 289 |
288 FOREIGN KEY (name) REFERENCES workspace(name) | 290 FOREIGN KEY (name) REFERENCES workspace(name) |
289 )` | 291 )` |
290 _, err = db.Exec(sql) | 292 _, err = db.Exec(sql) |
291 if err != nil { | 293 if err != nil { |
292 log.Printf("Info: status creating sqlite table for works
pace try: %q\n", err) | 294 log.Printf("Info: status creating sqlite table for works
pace try: %q\n", err) |
293 } | 295 } |
294 } | 296 } |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
347 GitHash string | 349 GitHash string |
348 GitInfo string | 350 GitInfo string |
349 } | 351 } |
350 | 352 |
351 // userCode is used in template expansion. | 353 // userCode is used in template expansion. |
352 type userCode struct { | 354 type userCode struct { |
353 Code string | 355 Code string |
354 Hash string | 356 Hash string |
355 Width int | 357 Width int |
356 Height int | 358 Height int |
| 359 GPU bool |
357 Source int | 360 Source int |
358 Titlebar Titlebar | 361 Titlebar Titlebar |
359 } | 362 } |
360 | 363 |
361 // writeTemplate creates a given output file and writes the template | 364 // writeTemplate creates a given output file and writes the template |
362 // result there. | 365 // result there. |
363 func writeTemplate(filename string, t *template.Template, context interface{}) e
rror { | 366 func writeTemplate(filename string, t *template.Template, context interface{}) e
rror { |
364 f, err := os.Create(filename) | 367 f, err := os.Create(filename) |
365 if err != nil { | 368 if err != nil { |
366 return err | 369 return err |
367 } | 370 } |
368 defer f.Close() | 371 defer f.Close() |
369 return t.Execute(f, context) | 372 return t.Execute(f, context) |
370 } | 373 } |
371 | 374 |
372 // expandToFile expands the template and writes the result to the file. | 375 // expandToFile expands the template and writes the result to the file. |
373 func expandToFile(filename string, code string, t *template.Template) error { | 376 func expandToFile(filename string, code string, t *template.Template) error { |
374 return writeTemplate(filename, t, userCode{ | 377 return writeTemplate(filename, t, userCode{ |
375 Code: code, | 378 Code: code, |
376 Titlebar: Titlebar{GitHash: gitHash, GitInfo: gitInfo}, | 379 Titlebar: Titlebar{GitHash: gitHash, GitInfo: gitInfo}, |
377 }) | 380 }) |
378 } | 381 } |
379 | 382 |
380 // expandCode expands the template into a file and calculates the MD5 hash. | 383 // expandCode expands the template into a file and calculates the MD5 hash. |
381 // We include the width and height here so that a single hash can capture | 384 // We include the width and height here so that a single hash can capture |
382 // both the code and the supplied width/height parameters. | 385 // both the code and the supplied width/height parameters. |
383 func expandCode(code string, source int, width, height int) (string, error) { | 386 func expandCode(code string, source int, width, height int, gpu bool) (string, e
rror) { |
384 // in order to support fonts in the chroot jail, we need to make sure | 387 // in order to support fonts in the chroot jail, we need to make sure |
385 // we're using portable typefaces. | 388 // we're using portable typefaces. |
386 // TODO(humper): Make this more robust, supporting things like setTypef
ace | 389 // TODO(humper): Make this more robust, supporting things like setTypef
ace |
387 | 390 |
388 inputCodeLines := strings.Split(code, "\n") | 391 inputCodeLines := strings.Split(code, "\n") |
389 » outputCodeLines := []string{"DECLARE_bool(portableFonts);", fmt.Sprintf(
"// WxH: %d, %d", width, height)} | 392 » outputCodeLines := []string{ |
| 393 » » "DECLARE_bool(portableFonts);", |
| 394 » » fmt.Sprintf("// WxH: %d, %d", width, height), |
| 395 » » fmt.Sprintf("// GPU: %v", gpu), |
| 396 » } |
390 for _, line := range inputCodeLines { | 397 for _, line := range inputCodeLines { |
391 outputCodeLines = append(outputCodeLines, line) | 398 outputCodeLines = append(outputCodeLines, line) |
392 if strings.HasPrefix(strings.TrimSpace(line), "SkPaint p") { | 399 if strings.HasPrefix(strings.TrimSpace(line), "SkPaint p") { |
393 outputCodeLines = append(outputCodeLines, "FLAGS_portabl
eFonts = true;") | 400 outputCodeLines = append(outputCodeLines, "FLAGS_portabl
eFonts = true;") |
394 outputCodeLines = append(outputCodeLines, "sk_tool_utils
::set_portable_typeface(&p, \"Helvetica\", SkTypeface::kNormal);") | 401 outputCodeLines = append(outputCodeLines, "sk_tool_utils
::set_portable_typeface(&p, \"Helvetica\", SkTypeface::kNormal);") |
395 } | 402 } |
396 } | 403 } |
397 | 404 |
398 fontFriendlyCode := strings.Join(outputCodeLines, "\n") | 405 fontFriendlyCode := strings.Join(outputCodeLines, "\n") |
399 | 406 |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
458 log.Printf("Error: %s\n%s", message, err.Error()) | 465 log.Printf("Error: %s\n%s", message, err.Error()) |
459 resp, err := json.Marshal(m) | 466 resp, err := json.Marshal(m) |
460 if err != nil { | 467 if err != nil { |
461 http.Error(w, "Failed to serialize a response", 500) | 468 http.Error(w, "Failed to serialize a response", 500) |
462 return | 469 return |
463 } | 470 } |
464 w.Header().Set("Content-Type", "text/plain") | 471 w.Header().Set("Content-Type", "text/plain") |
465 w.Write(resp) | 472 w.Write(resp) |
466 } | 473 } |
467 | 474 |
468 func writeToDatabase(hash string, code string, workspaceName string, source int,
width, height int) { | 475 func writeToDatabase(hash string, code string, workspaceName string, source int,
width, height int, gpu bool) { |
469 if db == nil { | 476 if db == nil { |
470 return | 477 return |
471 } | 478 } |
472 » if _, err := db.Exec("INSERT INTO webtry (code, hash, width, height, sou
rce_image_id) VALUES(?, ?, ?, ?, ?)", code, hash, width, height, source); err !=
nil { | 479 » if _, err := db.Exec("INSERT INTO webtry (code, hash, width, height, gpu
, source_image_id) VALUES(?, ?, ?, ?, ?, ?)", code, hash, width, height, gpu, so
urce); err != nil { |
473 log.Printf("ERROR: Failed to insert code into database: %q\n", e
rr) | 480 log.Printf("ERROR: Failed to insert code into database: %q\n", e
rr) |
474 } | 481 } |
475 if workspaceName != "" { | 482 if workspaceName != "" { |
476 » » if _, err := db.Exec("INSERT INTO workspacetry (name, hash, widt
h, height, source_image_id) VALUES(?, ?, ?, ?, ?)", workspaceName, hash, width,
height, source); err != nil { | 483 » » if _, err := db.Exec("INSERT INTO workspacetry (name, hash, widt
h, height, gpu, source_image_id) VALUES(?, ?, ?, ?, ?, ?)", workspaceName, hash,
width, height, gpu, source); err != nil { |
477 log.Printf("ERROR: Failed to insert into workspacetry ta
ble: %q\n", err) | 484 log.Printf("ERROR: Failed to insert into workspacetry ta
ble: %q\n", err) |
478 } | 485 } |
479 } | 486 } |
480 } | 487 } |
481 | 488 |
482 type Sources struct { | 489 type Sources struct { |
483 Id int `json:"id"` | 490 Id int `json:"id"` |
484 } | 491 } |
485 | 492 |
486 // sourcesHandler serves up the PNG of a specific try. | 493 // sourcesHandler serves up the PNG of a specific try. |
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
609 } | 616 } |
610 } | 617 } |
611 | 618 |
612 type Workspace struct { | 619 type Workspace struct { |
613 Name string | 620 Name string |
614 Code string | 621 Code string |
615 Hash string | 622 Hash string |
616 Width int | 623 Width int |
617 Height int | 624 Height int |
618 Source int | 625 Source int |
| 626 GPU bool |
619 Tries []Try | 627 Tries []Try |
620 Titlebar Titlebar | 628 Titlebar Titlebar |
621 } | 629 } |
622 | 630 |
623 // newWorkspace generates a new random workspace name and stores it in the datab
ase. | 631 // newWorkspace generates a new random workspace name and stores it in the datab
ase. |
624 func newWorkspace() (string, error) { | 632 func newWorkspace() (string, error) { |
625 for i := 0; i < 10; i++ { | 633 for i := 0; i < 10; i++ { |
626 adj := workspaceNameAdj[rand.Intn(len(workspaceNameAdj))] | 634 adj := workspaceNameAdj[rand.Intn(len(workspaceNameAdj))] |
627 noun := workspaceNameNoun[rand.Intn(len(workspaceNameNoun))] | 635 noun := workspaceNameNoun[rand.Intn(len(workspaceNameNoun))] |
628 suffix := rand.Intn(1000) | 636 suffix := rand.Intn(1000) |
629 name := fmt.Sprintf("%s-%s-%d", adj, noun, suffix) | 637 name := fmt.Sprintf("%s-%s-%d", adj, noun, suffix) |
630 if _, err := db.Exec("INSERT INTO workspace (name) VALUES(?)", n
ame); err == nil { | 638 if _, err := db.Exec("INSERT INTO workspace (name) VALUES(?)", n
ame); err == nil { |
631 return name, nil | 639 return name, nil |
632 } else { | 640 } else { |
633 log.Printf("ERROR: Failed to insert workspace into datab
ase: %q\n", err) | 641 log.Printf("ERROR: Failed to insert workspace into datab
ase: %q\n", err) |
634 } | 642 } |
635 } | 643 } |
636 return "", fmt.Errorf("Failed to create a new workspace") | 644 return "", fmt.Errorf("Failed to create a new workspace") |
637 } | 645 } |
638 | 646 |
639 // getCode returns the code for a given hash, or the empty string if not found. | 647 // getCode returns the code for a given hash, or the empty string if not found. |
640 func getCode(hash string) (string, int, int, int, error) { | 648 func getCode(hash string) (string, int, int, int, bool, error) { |
641 code := "" | 649 code := "" |
642 width := 0 | 650 width := 0 |
643 height := 0 | 651 height := 0 |
644 source := 0 | 652 source := 0 |
645 » if err := db.QueryRow("SELECT code, width, height, source_image_id FROM
webtry WHERE hash=?", hash).Scan(&code, &width, &height, &source); err != nil { | 653 » gpu := false |
| 654 » if err := db.QueryRow("SELECT code, width, height, gpu, source_image_id
FROM webtry WHERE hash=?", hash).Scan(&code, &width, &height, &gpu, &source); er
r != nil { |
646 log.Printf("ERROR: Code for hash is missing: %q\n", err) | 655 log.Printf("ERROR: Code for hash is missing: %q\n", err) |
647 » » return code, width, height, source, err | 656 » » return code, width, height, source, gpu, err |
648 } | 657 } |
649 » return code, width, height, source, nil | 658 » return code, width, height, source, gpu, nil |
650 } | 659 } |
651 | 660 |
652 func workspaceHandler(w http.ResponseWriter, r *http.Request) { | 661 func workspaceHandler(w http.ResponseWriter, r *http.Request) { |
653 log.Printf("Workspace Handler: %q\n", r.URL.Path) | 662 log.Printf("Workspace Handler: %q\n", r.URL.Path) |
654 if r.Method == "GET" { | 663 if r.Method == "GET" { |
655 tries := []Try{} | 664 tries := []Try{} |
656 match := workspaceLink.FindStringSubmatch(r.URL.Path) | 665 match := workspaceLink.FindStringSubmatch(r.URL.Path) |
657 name := "" | 666 name := "" |
658 if len(match) == 2 { | 667 if len(match) == 2 { |
659 name = match[1] | 668 name = match[1] |
(...skipping 11 matching lines...) Expand all Loading... |
671 continue | 680 continue |
672 } | 681 } |
673 tries = append(tries, Try{Hash: hash, Source: so
urce, CreateTS: create_ts.Format("2006-02-01")}) | 682 tries = append(tries, Try{Hash: hash, Source: so
urce, CreateTS: create_ts.Format("2006-02-01")}) |
674 } | 683 } |
675 } | 684 } |
676 var code string | 685 var code string |
677 var hash string | 686 var hash string |
678 var width int | 687 var width int |
679 var height int | 688 var height int |
680 source := 0 | 689 source := 0 |
| 690 gpu := false |
681 if len(tries) == 0 { | 691 if len(tries) == 0 { |
682 code = DEFAULT_SAMPLE | 692 code = DEFAULT_SAMPLE |
683 width = 256 | 693 width = 256 |
684 height = 256 | 694 height = 256 |
685 } else { | 695 } else { |
686 hash = tries[len(tries)-1].Hash | 696 hash = tries[len(tries)-1].Hash |
687 » » » code, width, height, source, _ = getCode(hash) | 697 » » » code, width, height, source, gpu, _ = getCode(hash) |
688 } | 698 } |
689 w.Header().Set("Content-Type", "text/html") | 699 w.Header().Set("Content-Type", "text/html") |
690 » » if err := workspaceTemplate.Execute(w, Workspace{Tries: tries, C
ode: code, Name: name, Hash: hash, Width: width, Height: height, Source: source,
Titlebar: Titlebar{GitHash: gitHash, GitInfo: gitInfo}}); err != nil { | 700 » » if err := workspaceTemplate.Execute(w, Workspace{Tries: tries, C
ode: code, Name: name, Hash: hash, Width: width, Height: height, GPU: gpu, Sourc
e: source, Titlebar: Titlebar{GitHash: gitHash, GitInfo: gitInfo}}); err != nil
{ |
691 log.Printf("ERROR: Failed to expand template: %q\n", err
) | 701 log.Printf("ERROR: Failed to expand template: %q\n", err
) |
692 } | 702 } |
693 } else if r.Method == "POST" { | 703 } else if r.Method == "POST" { |
694 name, err := newWorkspace() | 704 name, err := newWorkspace() |
695 if err != nil { | 705 if err != nil { |
696 http.Error(w, "Failed to create a new workspace.", 500) | 706 http.Error(w, "Failed to create a new workspace.", 500) |
697 return | 707 return |
698 } | 708 } |
699 http.Redirect(w, r, "/w/"+name, 302) | 709 http.Redirect(w, r, "/w/"+name, 302) |
700 } | 710 } |
701 } | 711 } |
702 | 712 |
703 // hasPreProcessor returns true if any line in the code begins with a # char. | 713 // hasPreProcessor returns true if any line in the code begins with a # char. |
704 func hasPreProcessor(code string) bool { | 714 func hasPreProcessor(code string) bool { |
705 lines := strings.Split(code, "\n") | 715 lines := strings.Split(code, "\n") |
706 for _, s := range lines { | 716 for _, s := range lines { |
707 if strings.HasPrefix(strings.TrimSpace(s), "#") { | 717 if strings.HasPrefix(strings.TrimSpace(s), "#") { |
708 return true | 718 return true |
709 } | 719 } |
710 } | 720 } |
711 return false | 721 return false |
712 } | 722 } |
713 | 723 |
714 type TryRequest struct { | 724 type TryRequest struct { |
715 Code string `json:"code"` | 725 Code string `json:"code"` |
716 Width int `json:"width"` | 726 Width int `json:"width"` |
717 Height int `json:"height"` | 727 Height int `json:"height"` |
| 728 GPU bool `json:"gpu"` |
718 Name string `json:"name"` // Optional name of the workspace the code
is in. | 729 Name string `json:"name"` // Optional name of the workspace the code
is in. |
719 Source int `json:"source"` // ID of the source image, 0 if none. | 730 Source int `json:"source"` // ID of the source image, 0 if none. |
720 } | 731 } |
721 | 732 |
722 // iframeHandler handles the GET and POST of the main page. | 733 // iframeHandler handles the GET and POST of the main page. |
723 func iframeHandler(w http.ResponseWriter, r *http.Request) { | 734 func iframeHandler(w http.ResponseWriter, r *http.Request) { |
724 log.Printf("IFrame Handler: %q\n", r.URL.Path) | 735 log.Printf("IFrame Handler: %q\n", r.URL.Path) |
725 if r.Method != "GET" { | 736 if r.Method != "GET" { |
726 http.NotFound(w, r) | 737 http.NotFound(w, r) |
727 return | 738 return |
728 } | 739 } |
729 match := iframeLink.FindStringSubmatch(r.URL.Path) | 740 match := iframeLink.FindStringSubmatch(r.URL.Path) |
730 if len(match) != 2 { | 741 if len(match) != 2 { |
731 http.NotFound(w, r) | 742 http.NotFound(w, r) |
732 return | 743 return |
733 } | 744 } |
734 hash := match[1] | 745 hash := match[1] |
735 if db == nil { | 746 if db == nil { |
736 http.NotFound(w, r) | 747 http.NotFound(w, r) |
737 return | 748 return |
738 } | 749 } |
739 var code string | 750 var code string |
740 » code, width, height, source, err := getCode(hash) | 751 » code, width, height, source, gpu, err := getCode(hash) |
741 if err != nil { | 752 if err != nil { |
742 http.NotFound(w, r) | 753 http.NotFound(w, r) |
743 return | 754 return |
744 } | 755 } |
745 // Expand the template. | 756 // Expand the template. |
746 w.Header().Set("Content-Type", "text/html") | 757 w.Header().Set("Content-Type", "text/html") |
747 » if err := iframeTemplate.Execute(w, userCode{Code: code, Width: width, H
eight: height, Hash: hash, Source: source}); err != nil { | 758 » if err := iframeTemplate.Execute(w, userCode{Code: code, Width: width, H
eight: height, GPU: gpu, Hash: hash, Source: source}); err != nil { |
748 log.Printf("ERROR: Failed to expand template: %q\n", err) | 759 log.Printf("ERROR: Failed to expand template: %q\n", err) |
749 } | 760 } |
750 } | 761 } |
751 | 762 |
752 type TryInfo struct { | 763 type TryInfo struct { |
753 Hash string `json:"hash"` | 764 Hash string `json:"hash"` |
754 Code string `json:"code"` | 765 Code string `json:"code"` |
755 Width int `json:"width"` | 766 Width int `json:"width"` |
756 Height int `json:"height"` | 767 Height int `json:"height"` |
| 768 GPU bool `json:"gpu"` |
757 Source int `json:"source"` | 769 Source int `json:"source"` |
758 } | 770 } |
759 | 771 |
760 // tryInfoHandler returns information about a specific try. | 772 // tryInfoHandler returns information about a specific try. |
761 func tryInfoHandler(w http.ResponseWriter, r *http.Request) { | 773 func tryInfoHandler(w http.ResponseWriter, r *http.Request) { |
762 log.Printf("Try Info Handler: %q\n", r.URL.Path) | 774 log.Printf("Try Info Handler: %q\n", r.URL.Path) |
763 if r.Method != "GET" { | 775 if r.Method != "GET" { |
764 http.NotFound(w, r) | 776 http.NotFound(w, r) |
765 return | 777 return |
766 } | 778 } |
767 match := tryInfoLink.FindStringSubmatch(r.URL.Path) | 779 match := tryInfoLink.FindStringSubmatch(r.URL.Path) |
768 if len(match) != 2 { | 780 if len(match) != 2 { |
769 http.NotFound(w, r) | 781 http.NotFound(w, r) |
770 return | 782 return |
771 } | 783 } |
772 hash := match[1] | 784 hash := match[1] |
773 » code, width, height, source, err := getCode(hash) | 785 » code, width, height, source, gpu, err := getCode(hash) |
774 if err != nil { | 786 if err != nil { |
775 http.NotFound(w, r) | 787 http.NotFound(w, r) |
776 return | 788 return |
777 } | 789 } |
778 m := TryInfo{ | 790 m := TryInfo{ |
779 Hash: hash, | 791 Hash: hash, |
780 Code: code, | 792 Code: code, |
781 Width: width, | 793 Width: width, |
782 Height: height, | 794 Height: height, |
| 795 GPU: gpu, |
783 Source: source, | 796 Source: source, |
784 } | 797 } |
785 resp, err := json.Marshal(m) | 798 resp, err := json.Marshal(m) |
786 if err != nil { | 799 if err != nil { |
787 reportError(w, r, err, "Failed to serialize a response.") | 800 reportError(w, r, err, "Failed to serialize a response.") |
788 return | 801 return |
789 } | 802 } |
790 w.Header().Set("Content-Type", "application/json") | 803 w.Header().Set("Content-Type", "application/json") |
791 w.Write(resp) | 804 w.Write(resp) |
792 } | 805 } |
793 | 806 |
794 func cleanCompileOutput(s, hash string) string { | 807 func cleanCompileOutput(s, hash string) string { |
795 old := "../../../cache/src/" + hash + ".cpp:" | 808 old := "../../../cache/src/" + hash + ".cpp:" |
796 log.Printf("INFO: replacing %q\n", old) | 809 log.Printf("INFO: replacing %q\n", old) |
797 return strings.Replace(s, old, "usercode.cpp:", -1) | 810 return strings.Replace(s, old, "usercode.cpp:", -1) |
798 } | 811 } |
799 | 812 |
800 // mainHandler handles the GET and POST of the main page. | 813 // mainHandler handles the GET and POST of the main page. |
801 func mainHandler(w http.ResponseWriter, r *http.Request) { | 814 func mainHandler(w http.ResponseWriter, r *http.Request) { |
802 log.Printf("Main Handler: %q\n", r.URL.Path) | 815 log.Printf("Main Handler: %q\n", r.URL.Path) |
803 requestsCounter.Inc(1) | 816 requestsCounter.Inc(1) |
804 if r.Method == "GET" { | 817 if r.Method == "GET" { |
805 code := DEFAULT_SAMPLE | 818 code := DEFAULT_SAMPLE |
806 source := 0 | 819 source := 0 |
807 width := 256 | 820 width := 256 |
808 height := 256 | 821 height := 256 |
| 822 gpu := false |
809 match := directLink.FindStringSubmatch(r.URL.Path) | 823 match := directLink.FindStringSubmatch(r.URL.Path) |
810 var hash string | 824 var hash string |
811 if len(match) == 2 && r.URL.Path != "/" { | 825 if len(match) == 2 && r.URL.Path != "/" { |
812 hash = match[1] | 826 hash = match[1] |
813 if db == nil { | 827 if db == nil { |
814 http.NotFound(w, r) | 828 http.NotFound(w, r) |
815 return | 829 return |
816 } | 830 } |
817 // Update 'code' with the code found in the database. | 831 // Update 'code' with the code found in the database. |
818 » » » if err := db.QueryRow("SELECT code, width, height, sourc
e_image_id FROM webtry WHERE hash=?", hash).Scan(&code, &width, &height, &source
); err != nil { | 832 » » » if err := db.QueryRow("SELECT code, width, height, gpu,
source_image_id FROM webtry WHERE hash=?", hash).Scan(&code, &width, &height, &g
pu, &source); err != nil { |
819 http.NotFound(w, r) | 833 http.NotFound(w, r) |
820 return | 834 return |
821 } | 835 } |
822 } | 836 } |
823 // Expand the template. | 837 // Expand the template. |
824 w.Header().Set("Content-Type", "text/html") | 838 w.Header().Set("Content-Type", "text/html") |
825 » » if err := indexTemplate.Execute(w, userCode{Code: code, Hash: ha
sh, Source: source, Width: width, Height: height, Titlebar: Titlebar{GitHash: gi
tHash, GitInfo: gitInfo}}); err != nil { | 839 » » if err := indexTemplate.Execute(w, userCode{Code: code, Hash: ha
sh, Source: source, Width: width, Height: height, GPU: gpu, Titlebar: Titlebar{G
itHash: gitHash, GitInfo: gitInfo}}); err != nil { |
826 log.Printf("ERROR: Failed to expand template: %q\n", err
) | 840 log.Printf("ERROR: Failed to expand template: %q\n", err
) |
827 } | 841 } |
828 } else if r.Method == "POST" { | 842 } else if r.Method == "POST" { |
829 w.Header().Set("Content-Type", "application/json") | 843 w.Header().Set("Content-Type", "application/json") |
830 buf := bytes.NewBuffer(make([]byte, 0, MAX_TRY_SIZE)) | 844 buf := bytes.NewBuffer(make([]byte, 0, MAX_TRY_SIZE)) |
831 n, err := buf.ReadFrom(r.Body) | 845 n, err := buf.ReadFrom(r.Body) |
832 if err != nil { | 846 if err != nil { |
833 reportTryError(w, r, err, "Failed to read a request body
.", "") | 847 reportTryError(w, r, err, "Failed to read a request body
.", "") |
834 return | 848 return |
835 } | 849 } |
836 if n == MAX_TRY_SIZE { | 850 if n == MAX_TRY_SIZE { |
837 err := fmt.Errorf("Code length equal to, or exceeded, %d
", MAX_TRY_SIZE) | 851 err := fmt.Errorf("Code length equal to, or exceeded, %d
", MAX_TRY_SIZE) |
838 reportTryError(w, r, err, "Code too large.", "") | 852 reportTryError(w, r, err, "Code too large.", "") |
839 return | 853 return |
840 } | 854 } |
841 request := TryRequest{} | 855 request := TryRequest{} |
842 if err := json.Unmarshal(buf.Bytes(), &request); err != nil { | 856 if err := json.Unmarshal(buf.Bytes(), &request); err != nil { |
843 reportTryError(w, r, err, "Coulnd't decode JSON.", "") | 857 reportTryError(w, r, err, "Coulnd't decode JSON.", "") |
844 return | 858 return |
845 } | 859 } |
846 if hasPreProcessor(request.Code) { | 860 if hasPreProcessor(request.Code) { |
847 err := fmt.Errorf("Found preprocessor macro in code.") | 861 err := fmt.Errorf("Found preprocessor macro in code.") |
848 reportTryError(w, r, err, "Preprocessor macros aren't al
lowed.", "") | 862 reportTryError(w, r, err, "Preprocessor macros aren't al
lowed.", "") |
849 return | 863 return |
850 } | 864 } |
851 » » hash, err := expandCode(LineNumbers(request.Code), request.Sourc
e, request.Width, request.Height) | 865 » » hash, err := expandCode(LineNumbers(request.Code), request.Sourc
e, request.Width, request.Height, request.GPU) |
852 if err != nil { | 866 if err != nil { |
853 reportTryError(w, r, err, "Failed to write the code to c
ompile.", hash) | 867 reportTryError(w, r, err, "Failed to write the code to c
ompile.", hash) |
854 return | 868 return |
855 } | 869 } |
856 » » writeToDatabase(hash, request.Code, request.Name, request.Source
, request.Width, request.Height) | 870 » » writeToDatabase(hash, request.Code, request.Name, request.Source
, request.Width, request.Height, request.GPU) |
857 err = expandGyp(hash) | 871 err = expandGyp(hash) |
858 if err != nil { | 872 if err != nil { |
859 reportTryError(w, r, err, "Failed to write the gyp file.
", hash) | 873 reportTryError(w, r, err, "Failed to write the gyp file.
", hash) |
860 return | 874 return |
861 } | 875 } |
862 cmd := fmt.Sprintf("scripts/fiddle_wrapper %s --width %d --heigh
t %d", hash, request.Width, request.Height) | 876 cmd := fmt.Sprintf("scripts/fiddle_wrapper %s --width %d --heigh
t %d", hash, request.Width, request.Height) |
| 877 if request.GPU { |
| 878 cmd += " --gpu" |
| 879 } |
863 if *useChroot { | 880 if *useChroot { |
864 cmd = "schroot -c webtry --directory=/ -- /skia_build/sk
ia/experimental/webtry/" + cmd | 881 cmd = "schroot -c webtry --directory=/ -- /skia_build/sk
ia/experimental/webtry/" + cmd |
865 } | 882 } |
866 if request.Source > 0 { | 883 if request.Source > 0 { |
867 cmd += fmt.Sprintf(" --source image-%d.png", request.Sou
rce) | 884 cmd += fmt.Sprintf(" --source image-%d.png", request.Sou
rce) |
868 } | 885 } |
869 | 886 |
870 message, err := doCmd(cmd) | 887 message, err := doCmd(cmd) |
871 if err != nil { | 888 if err != nil { |
872 reportTryError(w, r, err, "Failed to run the code:\n"+me
ssage, hash) | 889 reportTryError(w, r, err, "Failed to run the code:\n"+me
ssage, hash) |
(...skipping 30 matching lines...) Expand all Loading... |
903 http.HandleFunc("/sources/", autogzip.HandleFunc(sourcesHandler)) | 920 http.HandleFunc("/sources/", autogzip.HandleFunc(sourcesHandler)) |
904 | 921 |
905 // Resources are served directly | 922 // Resources are served directly |
906 // TODO add support for caching/etags/gzip | 923 // TODO add support for caching/etags/gzip |
907 http.Handle("/res/", autogzip.Handle(http.FileServer(http.Dir("./")))) | 924 http.Handle("/res/", autogzip.Handle(http.FileServer(http.Dir("./")))) |
908 | 925 |
909 // TODO Break out /c/ as it's own handler. | 926 // TODO Break out /c/ as it's own handler. |
910 http.HandleFunc("/", autogzip.HandleFunc(mainHandler)) | 927 http.HandleFunc("/", autogzip.HandleFunc(mainHandler)) |
911 log.Fatal(http.ListenAndServe(*port, nil)) | 928 log.Fatal(http.ListenAndServe(*port, nil)) |
912 } | 929 } |
OLD | NEW |