Index: experimental/webtry/webtry.go |
diff --git a/experimental/webtry/webtry.go b/experimental/webtry/webtry.go |
index d0588d558a5ce9e7e46a39af60b6c51311f68d9d..fb53b593e36e0e3d67ca6c413d20bdc47b4adfa9 100644 |
--- a/experimental/webtry/webtry.go |
+++ b/experimental/webtry/webtry.go |
@@ -3,10 +3,12 @@ package main |
import ( |
"bytes" |
"crypto/md5" |
+ "database/sql" |
"encoding/base64" |
"encoding/json" |
"flag" |
"fmt" |
+ _ "github.com/go-sql-driver/mysql" |
"io/ioutil" |
"log" |
"net/http" |
@@ -28,11 +30,15 @@ var ( |
// index is the main index.html page we serve. |
index []byte |
+ |
+ // db is the database, nil if we don't have an SQL database to store data into. |
+ db *sql.DB = nil |
) |
// flags |
var ( |
useChroot = flag.Bool("use_chroot", false, "Run the compiled code in the schroot jail.") |
+ port = flag.String("port", ":8000", "HTTP service address (e.g., ':8000')") |
) |
// lineNumbers adds #line numbering to the user's code. |
@@ -63,6 +69,32 @@ func init() { |
if err != nil { |
panic(err) |
} |
+ |
+ // Connect to MySQL server. First, get the password from the metadata server. |
+ // See https://developers.google.com/compute/docs/metadata#custom. |
+ req, err := http.NewRequest("GET", "http://metadata/computeMetadata/v1/instance/attributes/password", nil) |
+ if err != nil { |
+ panic(err) |
+ } |
+ client := http.Client{} |
+ req.Header.Add("X-Google-Metadata-Request", "True") |
+ if resp, err := client.Do(req); err == nil { |
+ password, err := ioutil.ReadAll(resp.Body) |
+ if err != nil { |
+ log.Printf("ERROR: Failed to read password from metadata server: %q\n", err) |
+ panic(err) |
+ } |
+ // The IP address of the database is found here: |
+ // https://console.developers.google.com/project/31977622648/sql/instances/webtry/overview |
+ // And 3306 is the default port for MySQL. |
+ db, err = sql.Open("mysql", fmt.Sprintf("webtry:%s@tcp(173.194.83.52:3306)/webtry", password)) |
+ if err != nil { |
+ log.Printf("ERROR: Failed to open connection to SQL server: %q\n", err) |
+ panic(err) |
+ } |
+ } else { |
+ log.Printf("INFO: Failed to find metadata, unable to connect to MySQL server (Expected when running locally): %q\n", err) |
+ } |
} |
// userCode is used in template expansion. |
@@ -155,6 +187,15 @@ func reportError(w http.ResponseWriter, r *http.Request, err error, message stri |
w.Write(resp) |
} |
+func writeToDatabase(hash string, code string) { |
+ if db == nil { |
+ return |
+ } |
+ if _, err := db.Exec("INSERT INTO webtry (code, hash) VALUES(?, ?)", code, hash); err != nil { |
+ log.Printf("ERROR: Failed to insert code into database: %q\n", err) |
+ } |
+} |
+ |
// mainHandler handles the GET and POST of the main page. |
func mainHandler(w http.ResponseWriter, r *http.Request) { |
if r.Method == "GET" { |
@@ -166,11 +207,13 @@ func mainHandler(w http.ResponseWriter, r *http.Request) { |
reportError(w, r, err, "Failed to read a request body.") |
return |
} |
- hash, err := expandCode(LineNumbers(string(b))) |
+ code := string(b) |
+ hash, err := expandCode(LineNumbers(code)) |
if err != nil { |
reportError(w, r, err, "Failed to write the code to compile.") |
return |
} |
+ writeToDatabase(hash, code) |
message, err := doCmd(fmt.Sprintf(RESULT_COMPILE, hash, hash), true) |
if err != nil { |
reportError(w, r, err, "Failed to compile the code:\n"+message) |
@@ -222,5 +265,5 @@ func main() { |
flag.Parse() |
http.HandleFunc("/", mainHandler) |
- log.Fatal(http.ListenAndServe(":8000", nil)) |
+ log.Fatal(http.ListenAndServe(*port, nil)) |
} |