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 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
72 // db is the database, nil if we don't have an SQL database to store dat
a into. | 72 // db is the database, nil if we don't have an SQL database to store dat
a into. |
73 db *sql.DB = nil | 73 db *sql.DB = nil |
74 | 74 |
75 // directLink is the regex that matches URLs paths that are direct links
. | 75 // directLink is the regex that matches URLs paths that are direct links
. |
76 directLink = regexp.MustCompile("^/c/([a-f0-9]+)$") | 76 directLink = regexp.MustCompile("^/c/([a-f0-9]+)$") |
77 | 77 |
78 // iframeLink is the regex that matches URLs paths that are links to ifr
ames. | 78 // iframeLink is the regex that matches URLs paths that are links to ifr
ames. |
79 iframeLink = regexp.MustCompile("^/iframe/([a-f0-9]+)$") | 79 iframeLink = regexp.MustCompile("^/iframe/([a-f0-9]+)$") |
80 | 80 |
81 // imageLink is the regex that matches URLs paths that are direct links
to PNGs. | 81 // imageLink is the regex that matches URLs paths that are direct links
to PNGs. |
82 » imageLink = regexp.MustCompile("^/i/([a-z0-9-]+.png)$") | 82 » imageLink = regexp.MustCompile("^/i/([a-z0-9-_]+.png)$") |
83 | 83 |
84 // tryInfoLink is the regex that matches URLs paths that are direct link
s to data about a single try. | 84 // tryInfoLink is the regex that matches URLs paths that are direct link
s to data about a single try. |
85 tryInfoLink = regexp.MustCompile("^/json/([a-f0-9]+)$") | 85 tryInfoLink = regexp.MustCompile("^/json/([a-f0-9]+)$") |
86 | 86 |
87 // workspaceLink is the regex that matches URLs paths for workspaces. | 87 // workspaceLink is the regex that matches URLs paths for workspaces. |
88 workspaceLink = regexp.MustCompile("^/w/([a-z0-9-]+)$") | 88 workspaceLink = regexp.MustCompile("^/w/([a-z0-9-]+)$") |
89 | 89 |
90 // errorRE is ther regex that matches compiler errors and extracts the l
ine / column information. | 90 // errorRE is ther regex that matches compiler errors and extracts the l
ine / column information. |
91 errorRE = regexp.MustCompile("^.*.cpp:(\\d+):(\\d+):\\s*(.*)") | 91 errorRE = regexp.MustCompile("^.*.cpp:(\\d+):(\\d+):\\s*(.*)") |
92 | 92 |
(...skipping 307 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
400 | 400 |
401 // expandGyp produces the GYP file needed to build the code | 401 // expandGyp produces the GYP file needed to build the code |
402 func expandGyp(hash string) error { | 402 func expandGyp(hash string) error { |
403 return writeTemplate(fmt.Sprintf("../../../cache/%s.gyp", hash), gypTemp
late, struct{ Hash string }{hash}) | 403 return writeTemplate(fmt.Sprintf("../../../cache/%s.gyp", hash), gypTemp
late, struct{ Hash string }{hash}) |
404 } | 404 } |
405 | 405 |
406 // response is serialized to JSON as a response to POSTs. | 406 // response is serialized to JSON as a response to POSTs. |
407 type response struct { | 407 type response struct { |
408 Message string `json:"message"` | 408 Message string `json:"message"` |
409 CompileErrors []compileError `json:"compileErrors"` | 409 CompileErrors []compileError `json:"compileErrors"` |
410 » Img string `json:"img"` | 410 » RasterImg string `json:"rasterImg"` |
| 411 » GPUImg string `json:"gpuImg"` |
411 Hash string `json:"hash"` | 412 Hash string `json:"hash"` |
412 } | 413 } |
413 | 414 |
414 // doCmd executes the given command line string; the command being | 415 // doCmd executes the given command line string; the command being |
415 // run is expected to not care what its current working directory is. | 416 // run is expected to not care what its current working directory is. |
416 // Returns the stdout and stderr. | 417 // Returns the stdout and stderr. |
417 func doCmd(commandLine string) (string, error) { | 418 func doCmd(commandLine string) (string, error) { |
418 glog.Infof("Command: %q\n", commandLine) | 419 glog.Infof("Command: %q\n", commandLine) |
419 programAndArgs := strings.SplitN(commandLine, " ", 2) | 420 programAndArgs := strings.SplitN(commandLine, " ", 2) |
420 program := programAndArgs[0] | 421 program := programAndArgs[0] |
(...skipping 296 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
717 } | 718 } |
718 } | 719 } |
719 return false | 720 return false |
720 } | 721 } |
721 | 722 |
722 type TryRequest struct { | 723 type TryRequest struct { |
723 Code string `json:"code"` | 724 Code string `json:"code"` |
724 Width int `json:"width"` | 725 Width int `json:"width"` |
725 Height int `json:"height"` | 726 Height int `json:"height"` |
726 GPU bool `json:"gpu"` | 727 GPU bool `json:"gpu"` |
| 728 Raster bool `json:"raster"` |
| 729 PDF bool `json:"pdf"` |
727 Name string `json:"name"` // Optional name of the workspace the code
is in. | 730 Name string `json:"name"` // Optional name of the workspace the code
is in. |
728 Source int `json:"source"` // ID of the source image, 0 if none. | 731 Source int `json:"source"` // ID of the source image, 0 if none. |
729 } | 732 } |
730 | 733 |
731 // iframeHandler handles the GET and POST of the main page. | 734 // iframeHandler handles the GET and POST of the main page. |
732 func iframeHandler(w http.ResponseWriter, r *http.Request) { | 735 func iframeHandler(w http.ResponseWriter, r *http.Request) { |
733 glog.Infof("IFrame Handler: %q\n", r.URL.Path) | 736 glog.Infof("IFrame Handler: %q\n", r.URL.Path) |
734 if r.Method != "GET" { | 737 if r.Method != "GET" { |
735 http.NotFound(w, r) | 738 http.NotFound(w, r) |
736 return | 739 return |
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
851 if n == MAX_TRY_SIZE { | 854 if n == MAX_TRY_SIZE { |
852 err := fmt.Errorf("Code length equal to, or exceeded, %d
", MAX_TRY_SIZE) | 855 err := fmt.Errorf("Code length equal to, or exceeded, %d
", MAX_TRY_SIZE) |
853 reportTryError(w, r, err, "Code too large.", "") | 856 reportTryError(w, r, err, "Code too large.", "") |
854 return | 857 return |
855 } | 858 } |
856 request := TryRequest{} | 859 request := TryRequest{} |
857 if err := json.Unmarshal(buf.Bytes(), &request); err != nil { | 860 if err := json.Unmarshal(buf.Bytes(), &request); err != nil { |
858 reportTryError(w, r, err, "Coulnd't decode JSON.", "") | 861 reportTryError(w, r, err, "Coulnd't decode JSON.", "") |
859 return | 862 return |
860 } | 863 } |
| 864 if !(request.GPU || request.Raster || request.PDF) { |
| 865 reportTryError(w, r, nil, "No run configuration supplied
...", "") |
| 866 return |
| 867 } |
861 if hasPreProcessor(request.Code) { | 868 if hasPreProcessor(request.Code) { |
862 err := fmt.Errorf("Found preprocessor macro in code.") | 869 err := fmt.Errorf("Found preprocessor macro in code.") |
863 reportTryError(w, r, err, "Preprocessor macros aren't al
lowed.", "") | 870 reportTryError(w, r, err, "Preprocessor macros aren't al
lowed.", "") |
864 return | 871 return |
865 } | 872 } |
866 hash, err := expandCode(LineNumbers(request.Code), request.Sourc
e, request.Width, request.Height) | 873 hash, err := expandCode(LineNumbers(request.Code), request.Sourc
e, request.Width, request.Height) |
867 if err != nil { | 874 if err != nil { |
868 reportTryError(w, r, err, "Failed to write the code to c
ompile.", hash) | 875 reportTryError(w, r, err, "Failed to write the code to c
ompile.", hash) |
869 return | 876 return |
870 } | 877 } |
871 writeToDatabase(hash, request.Code, request.Name, request.Source
, request.Width, request.Height) | 878 writeToDatabase(hash, request.Code, request.Name, request.Source
, request.Width, request.Height) |
872 err = expandGyp(hash) | 879 err = expandGyp(hash) |
873 if err != nil { | 880 if err != nil { |
874 reportTryError(w, r, err, "Failed to write the gyp file.
", hash) | 881 reportTryError(w, r, err, "Failed to write the gyp file.
", hash) |
875 return | 882 return |
876 } | 883 } |
877 cmd := fmt.Sprintf("scripts/fiddle_wrapper %s --width %d --heigh
t %d", hash, request.Width, request.Height) | 884 cmd := fmt.Sprintf("scripts/fiddle_wrapper %s --width %d --heigh
t %d", hash, request.Width, request.Height) |
| 885 if request.Raster { |
| 886 cmd += " --raster" |
| 887 } |
878 if request.GPU { | 888 if request.GPU { |
879 cmd += " --gpu" | 889 cmd += " --gpu" |
880 } | 890 } |
| 891 if request.PDF { |
| 892 cmd += " --pdf" |
| 893 } |
881 if *useChroot { | 894 if *useChroot { |
882 cmd = "schroot -c webtry --directory=/ -- /skia_build/sk
ia/experimental/webtry/" + cmd | 895 cmd = "schroot -c webtry --directory=/ -- /skia_build/sk
ia/experimental/webtry/" + cmd |
883 } | 896 } |
884 if request.Source > 0 { | 897 if request.Source > 0 { |
885 cmd += fmt.Sprintf(" --source image-%d.png", request.Sou
rce) | 898 cmd += fmt.Sprintf(" --source image-%d.png", request.Sou
rce) |
886 } | 899 } |
887 | 900 |
888 message, err := doCmd(cmd) | 901 message, err := doCmd(cmd) |
889 | 902 |
890 outputLines := strings.Split(message, "\n") | 903 outputLines := strings.Split(message, "\n") |
(...skipping 22 matching lines...) Expand all Loading... |
913 | 926 |
914 if err != nil { | 927 if err != nil { |
915 if len(errorLines) > 0 { | 928 if len(errorLines) > 0 { |
916 reportCompileError(w, r, errorLines, hash) | 929 reportCompileError(w, r, errorLines, hash) |
917 } else { | 930 } else { |
918 reportTryError(w, r, err, "Failed to run the cod
e:\n"+message, hash) | 931 reportTryError(w, r, err, "Failed to run the cod
e:\n"+message, hash) |
919 } | 932 } |
920 return | 933 return |
921 } | 934 } |
922 | 935 |
923 png, err := ioutil.ReadFile("../../../inout/" + hash + ".png") | |
924 if err != nil { | |
925 reportTryError(w, r, err, "Failed to open the generated
PNG.", hash) | |
926 return | |
927 } | |
928 | |
929 m := response{ | 936 m := response{ |
930 Img: base64.StdEncoding.EncodeToString([]byte(png)), | |
931 Hash: hash, | 937 Hash: hash, |
932 } | 938 } |
| 939 |
| 940 if request.Raster { |
| 941 png, err := ioutil.ReadFile("../../../inout/" + hash + "
_raster.png") |
| 942 if err != nil { |
| 943 reportTryError(w, r, err, "Failed to open the ra
ster-generated PNG.", hash) |
| 944 return |
| 945 } |
| 946 |
| 947 m.RasterImg = base64.StdEncoding.EncodeToString([]byte(p
ng)) |
| 948 } |
| 949 |
| 950 if request.GPU { |
| 951 png, err := ioutil.ReadFile("../../../inout/" + hash + "
_GPU.png") |
| 952 if err != nil { |
| 953 reportTryError(w, r, err, "Failed to open the GP
U-generated PNG.", hash) |
| 954 return |
| 955 } |
| 956 |
| 957 m.GPUImg = base64.StdEncoding.EncodeToString([]byte(png)
) |
| 958 } |
| 959 |
933 resp, err := json.Marshal(m) | 960 resp, err := json.Marshal(m) |
934 if err != nil { | 961 if err != nil { |
935 reportTryError(w, r, err, "Failed to serialize a respons
e.", hash) | 962 reportTryError(w, r, err, "Failed to serialize a respons
e.", hash) |
936 return | 963 return |
937 } | 964 } |
938 w.Header().Set("Content-Type", "application/json") | 965 w.Header().Set("Content-Type", "application/json") |
939 w.Write(resp) | 966 w.Write(resp) |
940 } | 967 } |
941 } | 968 } |
942 | 969 |
943 func main() { | 970 func main() { |
944 flag.Parse() | 971 flag.Parse() |
945 Init() | 972 Init() |
946 http.HandleFunc("/i/", autogzip.HandleFunc(imageHandler)) | 973 http.HandleFunc("/i/", autogzip.HandleFunc(imageHandler)) |
947 http.HandleFunc("/w/", autogzip.HandleFunc(workspaceHandler)) | 974 http.HandleFunc("/w/", autogzip.HandleFunc(workspaceHandler)) |
948 http.HandleFunc("/recent/", autogzip.HandleFunc(recentHandler)) | 975 http.HandleFunc("/recent/", autogzip.HandleFunc(recentHandler)) |
949 http.HandleFunc("/iframe/", autogzip.HandleFunc(iframeHandler)) | 976 http.HandleFunc("/iframe/", autogzip.HandleFunc(iframeHandler)) |
950 http.HandleFunc("/json/", autogzip.HandleFunc(tryInfoHandler)) | 977 http.HandleFunc("/json/", autogzip.HandleFunc(tryInfoHandler)) |
951 http.HandleFunc("/sources/", autogzip.HandleFunc(sourcesHandler)) | 978 http.HandleFunc("/sources/", autogzip.HandleFunc(sourcesHandler)) |
952 | 979 |
953 // Resources are served directly | 980 // Resources are served directly |
954 // TODO add support for caching/etags/gzip | 981 // TODO add support for caching/etags/gzip |
955 http.Handle("/res/", autogzip.Handle(http.FileServer(http.Dir("./")))) | 982 http.Handle("/res/", autogzip.Handle(http.FileServer(http.Dir("./")))) |
956 | 983 |
957 // TODO Break out /c/ as it's own handler. | 984 // TODO Break out /c/ as it's own handler. |
958 http.HandleFunc("/", autogzip.HandleFunc(mainHandler)) | 985 http.HandleFunc("/", autogzip.HandleFunc(mainHandler)) |
959 glog.Fatal(http.ListenAndServe(*port, nil)) | 986 glog.Fatal(http.ListenAndServe(*port, nil)) |
960 } | 987 } |
OLD | NEW |