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" |
11 _ "github.com/go-sql-driver/mysql" | |
12 _ "github.com/mattn/go-sqlite3" | |
13 htemplate "html/template" | 11 htemplate "html/template" |
14 "io/ioutil" | 12 "io/ioutil" |
15 "log" | 13 "log" |
16 "math/rand" | 14 "math/rand" |
17 "net/http" | 15 "net/http" |
18 "os" | 16 "os" |
19 "os/exec" | 17 "os/exec" |
20 "path/filepath" | 18 "path/filepath" |
21 "regexp" | 19 "regexp" |
22 "strings" | 20 "strings" |
23 "text/template" | 21 "text/template" |
24 "time" | 22 "time" |
25 ) | 23 ) |
26 | 24 |
| 25 import ( |
| 26 "github.com/fiorix/go-web/autogzip" |
| 27 _ "github.com/go-sql-driver/mysql" |
| 28 _ "github.com/mattn/go-sqlite3" |
| 29 ) |
| 30 |
27 const ( | 31 const ( |
28 RESULT_COMPILE = `../../experimental/webtry/safec++ -DSK_GAMMA_SRGB -DSK
_GAMMA_APPLY_TO_A8 -DSK_SCALAR_TO_FLOAT_EXCLUDED -DSK_ALLOW_STATIC_GLOBAL_INITIA
LIZERS=1 -DSK_SUPPORT_GPU=0 -DSK_SUPPORT_OPENCL=0 -DSK_FORCE_DISTANCEFIELD_FONTS
=0 -DSK_SCALAR_IS_FLOAT -DSK_CAN_USE_FLOAT -DSK_SAMPLES_FOR_X -DSK_BUILD_FOR_UNI
X -DSK_USE_POSIX_THREADS -DSK_SYSTEM_ZLIB=1 -DSK_DEBUG -DSK_DEVELOPER=1 -I../../
src/core -I../../src/images -I../../tools/flags -I../../include/config -I../../i
nclude/core -I../../include/pathops -I../../include/pipe -I../../include/effects
-I../../include/ports -I../../src/sfnt -I../../include/utils -I../../src/utils
-I../../include/images -g -fno-exceptions -fstrict-aliasing -Wall -Wextra -Winit
-self -Wpointer-arith -Wno-unused-parameter -m64 -fno-rtti -Wnon-virtual-dtor -c
../../../cache/%s.cpp -o ../../../cache/%s.o` | 32 RESULT_COMPILE = `../../experimental/webtry/safec++ -DSK_GAMMA_SRGB -DSK
_GAMMA_APPLY_TO_A8 -DSK_SCALAR_TO_FLOAT_EXCLUDED -DSK_ALLOW_STATIC_GLOBAL_INITIA
LIZERS=1 -DSK_SUPPORT_GPU=0 -DSK_SUPPORT_OPENCL=0 -DSK_FORCE_DISTANCEFIELD_FONTS
=0 -DSK_SCALAR_IS_FLOAT -DSK_CAN_USE_FLOAT -DSK_SAMPLES_FOR_X -DSK_BUILD_FOR_UNI
X -DSK_USE_POSIX_THREADS -DSK_SYSTEM_ZLIB=1 -DSK_DEBUG -DSK_DEVELOPER=1 -I../../
src/core -I../../src/images -I../../tools/flags -I../../include/config -I../../i
nclude/core -I../../include/pathops -I../../include/pipe -I../../include/effects
-I../../include/ports -I../../src/sfnt -I../../include/utils -I../../src/utils
-I../../include/images -g -fno-exceptions -fstrict-aliasing -Wall -Wextra -Winit
-self -Wpointer-arith -Wno-unused-parameter -m64 -fno-rtti -Wnon-virtual-dtor -c
../../../cache/%s.cpp -o ../../../cache/%s.o` |
29 LINK = `../../experimental/webtry/safec++ -m64 -lstdc++ -lm -o
../../../inout/%s -Wl,--start-group ../../../cache/%s.o obj/experimental/webtry
/webtry.main.o obj/gyp/libflags.a libskia_images.a libskia_core.a libskia_effect
s.a obj/gyp/libjpeg.a obj/gyp/libwebp_dec.a obj/gyp/libwebp_demux.a obj/gyp/libw
ebp_dsp.a obj/gyp/libwebp_enc.a obj/gyp/libwebp_utils.a libskia_utils.a libskia_
opts.a libskia_opts_ssse3.a libskia_ports.a libskia_sfnt.a -Wl,--end-group -lpng
-lz -lgif -lpthread -lfontconfig -ldl -lfreetype` | 33 LINK = `../../experimental/webtry/safec++ -m64 -lstdc++ -lm -o
../../../inout/%s -Wl,--start-group ../../../cache/%s.o obj/experimental/webtry
/webtry.main.o obj/gyp/libflags.a libskia_images.a libskia_core.a libskia_effect
s.a obj/gyp/libjpeg.a obj/gyp/libwebp_dec.a obj/gyp/libwebp_demux.a obj/gyp/libw
ebp_dsp.a obj/gyp/libwebp_enc.a obj/gyp/libwebp_utils.a libskia_utils.a libskia_
opts.a libskia_opts_ssse3.a libskia_ports.a libskia_sfnt.a -Wl,--end-group -lpng
-lz -lgif -lpthread -lfontconfig -ldl -lfreetype` |
30 DEFAULT_SAMPLE = `void draw(SkCanvas* canvas) { | 34 DEFAULT_SAMPLE = `void draw(SkCanvas* canvas) { |
31 SkPaint p; | 35 SkPaint p; |
32 p.setColor(SK_ColorRED); | 36 p.setColor(SK_ColorRED); |
33 p.setAntiAlias(true); | 37 p.setAntiAlias(true); |
34 p.setStyle(SkPaint::kStroke_Style); | 38 p.setStyle(SkPaint::kStroke_Style); |
35 p.setStrokeWidth(10); | 39 p.setStrokeWidth(10); |
36 | 40 |
(...skipping 284 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
321 if err != nil { | 325 if err != nil { |
322 log.Printf("Exit status: %s\n", err.Error()) | 326 log.Printf("Exit status: %s\n", err.Error()) |
323 return string(message), fmt.Errorf("Failed to run command.") | 327 return string(message), fmt.Errorf("Failed to run command.") |
324 } | 328 } |
325 return string(message), nil | 329 return string(message), nil |
326 } | 330 } |
327 | 331 |
328 // reportError formats an HTTP error response and also logs the detailed error m
essage. | 332 // reportError formats an HTTP error response and also logs the detailed error m
essage. |
329 func reportError(w http.ResponseWriter, r *http.Request, err error, message stri
ng) { | 333 func reportError(w http.ResponseWriter, r *http.Request, err error, message stri
ng) { |
330 log.Printf("Error: %s\n%s", message, err.Error()) | 334 log.Printf("Error: %s\n%s", message, err.Error()) |
| 335 w.Header().Set("Content-Type", "text/plain") |
331 http.Error(w, message, 500) | 336 http.Error(w, message, 500) |
332 } | 337 } |
333 | 338 |
334 // reportTryError formats an HTTP error response in JSON and also logs the detai
led error message. | 339 // reportTryError formats an HTTP error response in JSON and also logs the detai
led error message. |
335 func reportTryError(w http.ResponseWriter, r *http.Request, err error, message,
hash string) { | 340 func reportTryError(w http.ResponseWriter, r *http.Request, err error, message,
hash string) { |
336 m := response{ | 341 m := response{ |
337 Message: message, | 342 Message: message, |
338 Hash: hash, | 343 Hash: hash, |
339 } | 344 } |
340 log.Printf("Error: %s\n%s", message, err.Error()) | 345 log.Printf("Error: %s\n%s", message, err.Error()) |
341 resp, err := json.Marshal(m) | 346 resp, err := json.Marshal(m) |
342 if err != nil { | 347 if err != nil { |
343 http.Error(w, "Failed to serialize a response", 500) | 348 http.Error(w, "Failed to serialize a response", 500) |
344 return | 349 return |
345 } | 350 } |
| 351 w.Header().Set("Content-Type", "text/plain") |
346 w.Write(resp) | 352 w.Write(resp) |
347 } | 353 } |
348 | 354 |
349 func writeToDatabase(hash string, code string, workspaceName string) { | 355 func writeToDatabase(hash string, code string, workspaceName string) { |
350 if db == nil { | 356 if db == nil { |
351 return | 357 return |
352 } | 358 } |
353 if _, err := db.Exec("INSERT INTO webtry (code, hash) VALUES(?, ?)", cod
e, hash); err != nil { | 359 if _, err := db.Exec("INSERT INTO webtry (code, hash) VALUES(?, ?)", cod
e, hash); err != nil { |
354 log.Printf("ERROR: Failed to insert code into database: %q\n", e
rr) | 360 log.Printf("ERROR: Failed to insert code into database: %q\n", e
rr) |
355 } | 361 } |
(...skipping 10 matching lines...) Expand all Loading... |
366 if r.Method != "GET" { | 372 if r.Method != "GET" { |
367 http.NotFound(w, r) | 373 http.NotFound(w, r) |
368 return | 374 return |
369 } | 375 } |
370 match := imageLink.FindStringSubmatch(r.URL.Path) | 376 match := imageLink.FindStringSubmatch(r.URL.Path) |
371 if len(match) != 2 { | 377 if len(match) != 2 { |
372 http.NotFound(w, r) | 378 http.NotFound(w, r) |
373 return | 379 return |
374 } | 380 } |
375 filename := match[1] | 381 filename := match[1] |
| 382 w.Header().Set("Content-Type", "image/png") |
376 http.ServeFile(w, r, fmt.Sprintf("../../../inout/%s", filename)) | 383 http.ServeFile(w, r, fmt.Sprintf("../../../inout/%s", filename)) |
377 } | 384 } |
378 | 385 |
379 type Try struct { | 386 type Try struct { |
380 Hash string `json:"hash"` | 387 Hash string `json:"hash"` |
381 CreateTS string `json:"create_ts"` | 388 CreateTS string `json:"create_ts"` |
382 } | 389 } |
383 | 390 |
384 type Recent struct { | 391 type Recent struct { |
385 Tries []Try | 392 Tries []Try |
(...skipping 13 matching lines...) Expand all Loading... |
399 recent := []Try{} | 406 recent := []Try{} |
400 for rows.Next() { | 407 for rows.Next() { |
401 var hash string | 408 var hash string |
402 var create_ts time.Time | 409 var create_ts time.Time |
403 if err := rows.Scan(&create_ts, &hash); err != nil { | 410 if err := rows.Scan(&create_ts, &hash); err != nil { |
404 log.Printf("Error: failed to fetch from database: %q", e
rr) | 411 log.Printf("Error: failed to fetch from database: %q", e
rr) |
405 continue | 412 continue |
406 } | 413 } |
407 recent = append(recent, Try{Hash: hash, CreateTS: create_ts.Form
at("2006-02-01")}) | 414 recent = append(recent, Try{Hash: hash, CreateTS: create_ts.Form
at("2006-02-01")}) |
408 } | 415 } |
| 416 w.Header().Set("Content-Type", "text/html") |
409 if err := recentTemplate.Execute(w, Recent{Tries: recent, Titlebar: Titl
ebar{GitHash: gitHash, GitInfo: gitInfo}}); err != nil { | 417 if err := recentTemplate.Execute(w, Recent{Tries: recent, Titlebar: Titl
ebar{GitHash: gitHash, GitInfo: gitInfo}}); err != nil { |
410 log.Printf("ERROR: Failed to expand template: %q\n", err) | 418 log.Printf("ERROR: Failed to expand template: %q\n", err) |
411 } | 419 } |
412 } | 420 } |
413 | 421 |
414 type Workspace struct { | 422 type Workspace struct { |
415 Name string | 423 Name string |
416 Code string | 424 Code string |
417 Hash string | 425 Hash string |
418 Tries []Try | 426 Tries []Try |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
469 } | 477 } |
470 } | 478 } |
471 var code string | 479 var code string |
472 var hash string | 480 var hash string |
473 if len(tries) == 0 { | 481 if len(tries) == 0 { |
474 code = DEFAULT_SAMPLE | 482 code = DEFAULT_SAMPLE |
475 } else { | 483 } else { |
476 hash = tries[len(tries)-1].Hash | 484 hash = tries[len(tries)-1].Hash |
477 code, _ = getCode(hash) | 485 code, _ = getCode(hash) |
478 } | 486 } |
| 487 w.Header().Set("Content-Type", "text/html") |
479 if err := workspaceTemplate.Execute(w, Workspace{Tries: tries, C
ode: code, Name: name, Hash: hash, Titlebar: Titlebar{GitHash: gitHash, GitInfo:
gitInfo}}); err != nil { | 488 if err := workspaceTemplate.Execute(w, Workspace{Tries: tries, C
ode: code, Name: name, Hash: hash, Titlebar: Titlebar{GitHash: gitHash, GitInfo:
gitInfo}}); err != nil { |
480 log.Printf("ERROR: Failed to expand template: %q\n", err
) | 489 log.Printf("ERROR: Failed to expand template: %q\n", err
) |
481 } | 490 } |
482 } else if r.Method == "POST" { | 491 } else if r.Method == "POST" { |
483 name, err := newWorkspace() | 492 name, err := newWorkspace() |
484 if err != nil { | 493 if err != nil { |
485 http.Error(w, "Failed to create a new workspace.", 500) | 494 http.Error(w, "Failed to create a new workspace.", 500) |
486 return | 495 return |
487 } | 496 } |
488 http.Redirect(w, r, "/w/"+name, 302) | 497 http.Redirect(w, r, "/w/"+name, 302) |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
522 http.NotFound(w, r) | 531 http.NotFound(w, r) |
523 return | 532 return |
524 } | 533 } |
525 var code string | 534 var code string |
526 code, err := getCode(hash) | 535 code, err := getCode(hash) |
527 if err != nil { | 536 if err != nil { |
528 http.NotFound(w, r) | 537 http.NotFound(w, r) |
529 return | 538 return |
530 } | 539 } |
531 // Expand the template. | 540 // Expand the template. |
| 541 w.Header().Set("Content-Type", "text/html") |
532 if err := iframeTemplate.Execute(w, userCode{Code: code, Hash: hash}); e
rr != nil { | 542 if err := iframeTemplate.Execute(w, userCode{Code: code, Hash: hash}); e
rr != nil { |
533 log.Printf("ERROR: Failed to expand template: %q\n", err) | 543 log.Printf("ERROR: Failed to expand template: %q\n", err) |
534 } | 544 } |
535 } | 545 } |
536 | 546 |
537 type TryInfo struct { | 547 type TryInfo struct { |
538 Hash string `json:"hash"` | 548 Hash string `json:"hash"` |
539 Code string `json:"code"` | 549 Code string `json:"code"` |
540 } | 550 } |
541 | 551 |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
589 http.NotFound(w, r) | 599 http.NotFound(w, r) |
590 return | 600 return |
591 } | 601 } |
592 // Update 'code' with the code found in the database. | 602 // Update 'code' with the code found in the database. |
593 if err := db.QueryRow("SELECT code FROM webtry WHERE has
h=?", hash).Scan(&code); err != nil { | 603 if err := db.QueryRow("SELECT code FROM webtry WHERE has
h=?", hash).Scan(&code); err != nil { |
594 http.NotFound(w, r) | 604 http.NotFound(w, r) |
595 return | 605 return |
596 } | 606 } |
597 } | 607 } |
598 // Expand the template. | 608 // Expand the template. |
| 609 w.Header().Set("Content-Type", "text/html") |
599 if err := indexTemplate.Execute(w, userCode{Code: code, Hash: ha
sh, Titlebar: Titlebar{GitHash: gitHash, GitInfo: gitInfo}}); err != nil { | 610 if err := indexTemplate.Execute(w, userCode{Code: code, Hash: ha
sh, Titlebar: Titlebar{GitHash: gitHash, GitInfo: gitInfo}}); err != nil { |
600 log.Printf("ERROR: Failed to expand template: %q\n", err
) | 611 log.Printf("ERROR: Failed to expand template: %q\n", err
) |
601 } | 612 } |
602 } else if r.Method == "POST" { | 613 } else if r.Method == "POST" { |
603 w.Header().Set("Content-Type", "application/json") | 614 w.Header().Set("Content-Type", "application/json") |
604 buf := bytes.NewBuffer(make([]byte, 0, MAX_TRY_SIZE)) | 615 buf := bytes.NewBuffer(make([]byte, 0, MAX_TRY_SIZE)) |
605 n, err := buf.ReadFrom(r.Body) | 616 n, err := buf.ReadFrom(r.Body) |
606 if err != nil { | 617 if err != nil { |
607 reportTryError(w, r, err, "Failed to read a request body
.", "") | 618 reportTryError(w, r, err, "Failed to read a request body
.", "") |
608 return | 619 return |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
668 Message: message, | 679 Message: message, |
669 StdOut: execMessage, | 680 StdOut: execMessage, |
670 Img: base64.StdEncoding.EncodeToString([]byte(png)), | 681 Img: base64.StdEncoding.EncodeToString([]byte(png)), |
671 Hash: hash, | 682 Hash: hash, |
672 } | 683 } |
673 resp, err := json.Marshal(m) | 684 resp, err := json.Marshal(m) |
674 if err != nil { | 685 if err != nil { |
675 reportTryError(w, r, err, "Failed to serialize a respons
e.", hash) | 686 reportTryError(w, r, err, "Failed to serialize a respons
e.", hash) |
676 return | 687 return |
677 } | 688 } |
| 689 w.Header().Set("Content-Type", "application/json") |
678 w.Write(resp) | 690 w.Write(resp) |
679 } | 691 } |
680 } | 692 } |
681 | 693 |
682 func main() { | 694 func main() { |
683 flag.Parse() | 695 flag.Parse() |
684 » http.HandleFunc("/i/", imageHandler) | 696 » http.HandleFunc("/i/", autogzip.HandleFunc(imageHandler)) |
685 » http.HandleFunc("/w/", workspaceHandler) | 697 » http.HandleFunc("/w/", autogzip.HandleFunc(workspaceHandler)) |
686 » http.HandleFunc("/recent/", recentHandler) | 698 » http.HandleFunc("/recent/", autogzip.HandleFunc(recentHandler)) |
687 » http.HandleFunc("/iframe/", iframeHandler) | 699 » http.HandleFunc("/iframe/", autogzip.HandleFunc(iframeHandler)) |
688 » http.HandleFunc("/json/", tryInfoHandler) | 700 » http.HandleFunc("/json/", autogzip.HandleFunc(tryInfoHandler)) |
689 | 701 |
690 // Resources are served directly | 702 // Resources are served directly |
691 // TODO add support for caching/etags/gzip | 703 // TODO add support for caching/etags/gzip |
692 » http.Handle("/res/", http.FileServer(http.Dir("./"))) | 704 » http.Handle("/res/", autogzip.Handle(http.FileServer(http.Dir("./")))) |
693 | 705 |
694 // TODO Break out /c/ as it's own handler. | 706 // TODO Break out /c/ as it's own handler. |
695 » http.HandleFunc("/", mainHandler) | 707 » http.HandleFunc("/", autogzip.HandleFunc(mainHandler)) |
696 log.Fatal(http.ListenAndServe(*port, nil)) | 708 log.Fatal(http.ListenAndServe(*port, nil)) |
697 } | 709 } |
OLD | NEW |