| 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" | 11         _ "github.com/go-sql-driver/mysql" | 
| 12         _ "github.com/mattn/go-sqlite3" | 12         _ "github.com/mattn/go-sqlite3" | 
| 13         htemplate "html/template" | 13         htemplate "html/template" | 
| 14         "io/ioutil" | 14         "io/ioutil" | 
| 15         "log" | 15         "log" | 
|  | 16         "math/rand" | 
| 16         "net/http" | 17         "net/http" | 
| 17         "os" | 18         "os" | 
| 18         "os/exec" | 19         "os/exec" | 
| 19         "path/filepath" | 20         "path/filepath" | 
| 20         "regexp" | 21         "regexp" | 
| 21         "strings" | 22         "strings" | 
| 22         "text/template" | 23         "text/template" | 
| 23         "time" | 24         "time" | 
| 24 ) | 25 ) | 
| 25 | 26 | 
| (...skipping 12 matching lines...) Expand all  Loading... | 
| 38         MAX_TRY_SIZE = 64000 | 39         MAX_TRY_SIZE = 64000 | 
| 39 ) | 40 ) | 
| 40 | 41 | 
| 41 var ( | 42 var ( | 
| 42         // codeTemplate is the cpp code template the user's code is copied into. | 43         // codeTemplate is the cpp code template the user's code is copied into. | 
| 43         codeTemplate *template.Template = nil | 44         codeTemplate *template.Template = nil | 
| 44 | 45 | 
| 45         // indexTemplate is the main index.html page we serve. | 46         // indexTemplate is the main index.html page we serve. | 
| 46         indexTemplate *htemplate.Template = nil | 47         indexTemplate *htemplate.Template = nil | 
| 47 | 48 | 
| 48 »       // recentTemplate is a list of recent  images. | 49 »       // recentTemplate is a list of recent images. | 
| 49         recentTemplate *htemplate.Template = nil | 50         recentTemplate *htemplate.Template = nil | 
| 50 | 51 | 
|  | 52         // workspaceTemplate is the page for workspaces, a series of webtrys. | 
|  | 53         workspaceTemplate *htemplate.Template = nil | 
|  | 54 | 
| 51         // db is the database, nil if we don't have an SQL database to store dat
     a into. | 55         // db is the database, nil if we don't have an SQL database to store dat
     a into. | 
| 52         db *sql.DB = nil | 56         db *sql.DB = nil | 
| 53 | 57 | 
| 54         // directLink is the regex that matches URLs paths that are direct links
     . | 58         // directLink is the regex that matches URLs paths that are direct links
     . | 
| 55         directLink = regexp.MustCompile("^/c/([a-f0-9]+)$") | 59         directLink = regexp.MustCompile("^/c/([a-f0-9]+)$") | 
| 56 | 60 | 
| 57         // imageLink is the regex that matches URLs paths that are direct links 
     to PNGs. | 61         // imageLink is the regex that matches URLs paths that are direct links 
     to PNGs. | 
| 58         imageLink = regexp.MustCompile("^/i/([a-f0-9]+.png)$") | 62         imageLink = regexp.MustCompile("^/i/([a-f0-9]+.png)$") | 
|  | 63 | 
|  | 64         // workspaceLink is the regex that matches URLs paths for workspaces. | 
|  | 65         workspaceLink = regexp.MustCompile("^/w/([a-z0-9-]+)$") | 
|  | 66 | 
|  | 67         workspaceNameAdj = []string{ | 
|  | 68                 "autumn", "hidden", "bitter", "misty", "silent", "empty", "dry",
      "dark", | 
|  | 69                 "summer", "icy", "delicate", "quiet", "white", "cool", "spring",
      "winter", | 
|  | 70                 "patient", "twilight", "dawn", "crimson", "wispy", "weathered", 
     "blue", | 
|  | 71                 "billowing", "broken", "cold", "damp", "falling", "frosty", "gre
     en", | 
|  | 72                 "long", "late", "lingering", "bold", "little", "morning", "muddy
     ", "old", | 
|  | 73                 "red", "rough", "still", "small", "sparkling", "throbbing", "shy
     ", | 
|  | 74                 "wandering", "withered", "wild", "black", "young", "holy", "soli
     tary", | 
|  | 75                 "fragrant", "aged", "snowy", "proud", "floral", "restless", "div
     ine", | 
|  | 76                 "polished", "ancient", "purple", "lively", "nameless", | 
|  | 77         } | 
|  | 78 | 
|  | 79         workspaceNameNoun = []string{ | 
|  | 80                 "waterfall", "river", "breeze", "moon", "rain", "wind", "sea", "
     morning", | 
|  | 81                 "snow", "lake", "sunset", "pine", "shadow", "leaf", "dawn", "gli
     tter", | 
|  | 82                 "forest", "hill", "cloud", "meadow", "sun", "glade", "bird", "br
     ook", | 
|  | 83                 "butterfly", "bush", "dew", "dust", "field", "fire", "flower", "
     firefly", | 
|  | 84                 "feather", "grass", "haze", "mountain", "night", "pond", "darkne
     ss", | 
|  | 85                 "snowflake", "silence", "sound", "sky", "shape", "surf", "thunde
     r", | 
|  | 86                 "violet", "water", "wildflower", "wave", "water", "resonance", "
     sun", | 
|  | 87                 "wood", "dream", "cherry", "tree", "fog", "frost", "voice", "pap
     er", | 
|  | 88                 "frog", "smoke", "star", | 
|  | 89         } | 
| 59 ) | 90 ) | 
| 60 | 91 | 
| 61 // flags | 92 // flags | 
| 62 var ( | 93 var ( | 
| 63         useChroot = flag.Bool("use_chroot", false, "Run the compiled code in the
      schroot jail.") | 94         useChroot = flag.Bool("use_chroot", false, "Run the compiled code in the
      schroot jail.") | 
| 64         port      = flag.String("port", ":8000", "HTTP service address (e.g., ':
     8000')") | 95         port      = flag.String("port", ":8000", "HTTP service address (e.g., ':
     8000')") | 
| 65 ) | 96 ) | 
| 66 | 97 | 
| 67 // lineNumbers adds #line numbering to the user's code. | 98 // lineNumbers adds #line numbering to the user's code. | 
| 68 func LineNumbers(c string) string { | 99 func LineNumbers(c string) string { | 
| (...skipping 24 matching lines...) Expand all  Loading... | 
| 93         indexTemplate, err = htemplate.ParseFiles(filepath.Join(cwd, "templates/
     index.html")) | 124         indexTemplate, err = htemplate.ParseFiles(filepath.Join(cwd, "templates/
     index.html")) | 
| 94         if err != nil { | 125         if err != nil { | 
| 95                 panic(err) | 126                 panic(err) | 
| 96         } | 127         } | 
| 97 | 128 | 
| 98         recentTemplate, err = htemplate.ParseFiles(filepath.Join(cwd, "templates
     /recent.html")) | 129         recentTemplate, err = htemplate.ParseFiles(filepath.Join(cwd, "templates
     /recent.html")) | 
| 99         if err != nil { | 130         if err != nil { | 
| 100                 panic(err) | 131                 panic(err) | 
| 101         } | 132         } | 
| 102 | 133 | 
|  | 134         workspaceTemplate, err = htemplate.ParseFiles(filepath.Join(cwd, "templa
     tes/workspace.html")) | 
|  | 135         if err != nil { | 
|  | 136                 panic(err) | 
|  | 137         } | 
|  | 138 | 
| 103         // Connect to MySQL server. First, get the password from the metadata se
     rver. | 139         // Connect to MySQL server. First, get the password from the metadata se
     rver. | 
| 104         // See https://developers.google.com/compute/docs/metadata#custom. | 140         // See https://developers.google.com/compute/docs/metadata#custom. | 
| 105         req, err := http.NewRequest("GET", "http://metadata/computeMetadata/v1/i
     nstance/attributes/password", nil) | 141         req, err := http.NewRequest("GET", "http://metadata/computeMetadata/v1/i
     nstance/attributes/password", nil) | 
| 106         if err != nil { | 142         if err != nil { | 
| 107                 panic(err) | 143                 panic(err) | 
| 108         } | 144         } | 
| 109         client := http.Client{} | 145         client := http.Client{} | 
| 110         req.Header.Add("X-Google-Metadata-Request", "True") | 146         req.Header.Add("X-Google-Metadata-Request", "True") | 
| 111         if resp, err := client.Do(req); err == nil { | 147         if resp, err := client.Do(req); err == nil { | 
| 112                 password, err := ioutil.ReadAll(resp.Body) | 148                 password, err := ioutil.ReadAll(resp.Body) | 
| 113                 if err != nil { | 149                 if err != nil { | 
| 114                         log.Printf("ERROR: Failed to read password from metadata
      server: %q\n", err) | 150                         log.Printf("ERROR: Failed to read password from metadata
      server: %q\n", err) | 
| 115                         panic(err) | 151                         panic(err) | 
| 116                 } | 152                 } | 
| 117                 // The IP address of the database is found here: | 153                 // The IP address of the database is found here: | 
| 118                 //    https://console.developers.google.com/project/31977622648/
     sql/instances/webtry/overview | 154                 //    https://console.developers.google.com/project/31977622648/
     sql/instances/webtry/overview | 
| 119                 // And 3306 is the default port for MySQL. | 155                 // And 3306 is the default port for MySQL. | 
| 120                 db, err = sql.Open("mysql", fmt.Sprintf("webtry:%s@tcp(173.194.8
     3.52:3306)/webtry?parseTime=true", password)) | 156                 db, err = sql.Open("mysql", fmt.Sprintf("webtry:%s@tcp(173.194.8
     3.52:3306)/webtry?parseTime=true", password)) | 
| 121                 if err != nil { | 157                 if err != nil { | 
| 122                         log.Printf("ERROR: Failed to open connection to SQL serv
     er: %q\n", err) | 158                         log.Printf("ERROR: Failed to open connection to SQL serv
     er: %q\n", err) | 
| 123                         panic(err) | 159                         panic(err) | 
| 124                 } | 160                 } | 
| 125         } else { | 161         } else { | 
|  | 162                 log.Printf("INFO: Failed to find metadata, unable to connect to 
     MySQL server (Expected when running locally): %q\n", err) | 
| 126                 // Fallback to sqlite for local use. | 163                 // Fallback to sqlite for local use. | 
| 127                 db, err = sql.Open("sqlite3", "./webtry.db") | 164                 db, err = sql.Open("sqlite3", "./webtry.db") | 
| 128                 if err != nil { | 165                 if err != nil { | 
| 129                         log.Printf("ERROR: Failed to open: %q\n", err) | 166                         log.Printf("ERROR: Failed to open: %q\n", err) | 
| 130                         panic(err) | 167                         panic(err) | 
| 131                 } | 168                 } | 
| 132                 sql := `CREATE TABLE webtry ( | 169                 sql := `CREATE TABLE webtry ( | 
| 133              code      TEXT      DEFAULT ''                 NOT NULL, | 170              code      TEXT      DEFAULT ''                 NOT NULL, | 
| 134              create_ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP  NOT NULL, | 171              create_ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP  NOT NULL, | 
| 135              hash      CHAR(64)  DEFAULT ''                 NOT NULL, | 172              hash      CHAR(64)  DEFAULT ''                 NOT NULL, | 
| 136              PRIMARY KEY(hash) | 173              PRIMARY KEY(hash) | 
| 137             )` | 174             )` | 
| 138 »       »       db.Exec(sql) | 175 »       »       _, err = db.Exec(sql) | 
| 139 »       »       log.Printf("INFO: Failed to find metadata, unable to connect to 
     MySQL server (Expected when running locally): %q\n", err) | 176 »       »       log.Printf("Info: status creating sqlite table for webtry: %q\n"
     , err) | 
|  | 177 »       »       sql = `CREATE TABLE workspace ( | 
|  | 178           name      TEXT      DEFAULT ''                 NOT NULL, | 
|  | 179           create_ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP  NOT NULL, | 
|  | 180           PRIMARY KEY(name) | 
|  | 181         )` | 
|  | 182 »       »       _, err = db.Exec(sql) | 
|  | 183 »       »       log.Printf("Info: status creating sqlite table for workspace: %q
     \n", err) | 
|  | 184 »       »       sql = `CREATE TABLE workspacetry ( | 
|  | 185           name      TEXT      DEFAULT ''                 NOT NULL, | 
|  | 186           create_ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP  NOT NULL, | 
|  | 187           hash      CHAR(64)  DEFAULT ''                 NOT NULL, | 
|  | 188           hidden    INTEGER   DEFAULT 0                  NOT NULL, | 
|  | 189           FOREIGN KEY (name) REFERENCES workspace(name) | 
|  | 190         )` | 
|  | 191 »       »       _, err = db.Exec(sql) | 
|  | 192 »       »       log.Printf("Info: status creating sqlite table for workspace try
     : %q\n", err) | 
| 140         } | 193         } | 
| 141 } | 194 } | 
| 142 | 195 | 
| 143 // userCode is used in template expansion. | 196 // userCode is used in template expansion. | 
| 144 type userCode struct { | 197 type userCode struct { | 
| 145         UserCode string | 198         UserCode string | 
| 146 } | 199 } | 
| 147 | 200 | 
| 148 // expandToFile expands the template and writes the result to the file. | 201 // expandToFile expands the template and writes the result to the file. | 
| 149 func expandToFile(filename string, code string, t *template.Template) error { | 202 func expandToFile(filename string, code string, t *template.Template) error { | 
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 224         } | 277         } | 
| 225         log.Printf("Error: %s\n%s", message, err.Error()) | 278         log.Printf("Error: %s\n%s", message, err.Error()) | 
| 226         resp, err := json.Marshal(m) | 279         resp, err := json.Marshal(m) | 
| 227         if err != nil { | 280         if err != nil { | 
| 228                 http.Error(w, "Failed to serialize a response", 500) | 281                 http.Error(w, "Failed to serialize a response", 500) | 
| 229                 return | 282                 return | 
| 230         } | 283         } | 
| 231         w.Write(resp) | 284         w.Write(resp) | 
| 232 } | 285 } | 
| 233 | 286 | 
| 234 func writeToDatabase(hash string, code string) { | 287 func writeToDatabase(hash string, code string, workspaceName string) { | 
| 235         if db == nil { | 288         if db == nil { | 
| 236                 return | 289                 return | 
| 237         } | 290         } | 
| 238         if _, err := db.Exec("INSERT INTO webtry (code, hash) VALUES(?, ?)", cod
     e, hash); err != nil { | 291         if _, err := db.Exec("INSERT INTO webtry (code, hash) VALUES(?, ?)", cod
     e, hash); err != nil { | 
| 239                 log.Printf("ERROR: Failed to insert code into database: %q\n", e
     rr) | 292                 log.Printf("ERROR: Failed to insert code into database: %q\n", e
     rr) | 
| 240         } | 293         } | 
|  | 294         if workspaceName != "" { | 
|  | 295                 if _, err := db.Exec("INSERT INTO workspacetry (name, hash) VALU
     ES(?, ?)", workspaceName, hash); err != nil { | 
|  | 296                         log.Printf("ERROR: Failed to insert into workspacetry ta
     ble: %q\n", err) | 
|  | 297                 } | 
|  | 298         } | 
| 241 } | 299 } | 
| 242 | 300 | 
| 243 func cssHandler(w http.ResponseWriter, r *http.Request) { | 301 func cssHandler(w http.ResponseWriter, r *http.Request) { | 
| 244         http.ServeFile(w, r, "css/webtry.css") | 302         http.ServeFile(w, r, "css/webtry.css") | 
| 245 } | 303 } | 
| 246 | 304 | 
| 247 // imageHandler serves up the PNG of a specific try. | 305 // imageHandler serves up the PNG of a specific try. | 
| 248 func imageHandler(w http.ResponseWriter, r *http.Request) { | 306 func imageHandler(w http.ResponseWriter, r *http.Request) { | 
| 249         log.Printf("Image Handler: %q\n", r.URL.Path) | 307         log.Printf("Image Handler: %q\n", r.URL.Path) | 
| 250         if r.Method != "GET" { | 308         if r.Method != "GET" { | 
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 287                         log.Printf("Error: failed to fetch from database: %q", e
     rr) | 345                         log.Printf("Error: failed to fetch from database: %q", e
     rr) | 
| 288                         continue | 346                         continue | 
| 289                 } | 347                 } | 
| 290                 recent = append(recent, Try{Hash: hash, CreateTS: create_ts.Form
     at("2006-02-01")}) | 348                 recent = append(recent, Try{Hash: hash, CreateTS: create_ts.Form
     at("2006-02-01")}) | 
| 291         } | 349         } | 
| 292         if err := recentTemplate.Execute(w, Recent{Tries: recent}); err != nil { | 350         if err := recentTemplate.Execute(w, Recent{Tries: recent}); err != nil { | 
| 293                 log.Printf("ERROR: Failed to expand template: %q\n", err) | 351                 log.Printf("ERROR: Failed to expand template: %q\n", err) | 
| 294         } | 352         } | 
| 295 } | 353 } | 
| 296 | 354 | 
|  | 355 type Workspace struct { | 
|  | 356         Name  string | 
|  | 357         Code  string | 
|  | 358         Tries []Try | 
|  | 359 } | 
|  | 360 | 
|  | 361 func newWorkspace() (string, error) { | 
|  | 362         for i := 0; i < 10; i++ { | 
|  | 363                 adj := workspaceNameAdj[rand.Intn(len(workspaceNameAdj))] | 
|  | 364                 noun := workspaceNameNoun[rand.Intn(len(workspaceNameNoun))] | 
|  | 365                 suffix := rand.Intn(1000) | 
|  | 366                 name := fmt.Sprintf("%s-%s-%d", adj, noun, suffix) | 
|  | 367                 if _, err := db.Exec("INSERT INTO workspace (name) VALUES(?)", n
     ame); err == nil { | 
|  | 368                         return name, nil | 
|  | 369                 } else { | 
|  | 370                         log.Printf("ERROR: Failed to insert workspace into datab
     ase: %q\n", err) | 
|  | 371                 } | 
|  | 372         } | 
|  | 373         return "", fmt.Errorf("Failed to create a new workspace") | 
|  | 374 } | 
|  | 375 | 
|  | 376 func getCode(hash string) string { | 
|  | 377         code := "" | 
|  | 378         if err := db.QueryRow("SELECT code FROM webtry WHERE hash=?", hash).Scan
     (&code); err != nil { | 
|  | 379                 log.Printf("ERROR: Code for hash is missing: %q\n", err) | 
|  | 380         } | 
|  | 381         return code | 
|  | 382 } | 
|  | 383 | 
|  | 384 func workspaceHandler(w http.ResponseWriter, r *http.Request) { | 
|  | 385         // POST creates a new workspace and redirect to the newly created worksp
     ace. | 
|  | 386         // GET w/o a namespace name just gets the 'create' page. | 
|  | 387         // GET w/name gets that workspace doc, which is just a list of tries. | 
|  | 388         // What's the difference? The 'create' flow has a 'Create' button | 
|  | 389         // and no code. A workspace has a 'Run' button | 
|  | 390         // and shows the code for the most recent try. Also includes a list | 
|  | 391         // of all the tries in this workspace with a fingernail for each one. | 
|  | 392         // Run is actually handled by a POST to /. | 
|  | 393         log.Printf("Workspace Handler: %q\n", r.URL.Path) | 
|  | 394         if r.Method == "GET" { | 
|  | 395                 tries := []Try{} | 
|  | 396                 match := workspaceLink.FindStringSubmatch(r.URL.Path) | 
|  | 397                 name := "" | 
|  | 398                 if len(match) == 2 { | 
|  | 399                         log.Printf("Got a valid match %q\n", match) | 
|  | 400                         name = match[1] | 
|  | 401                         // Load all the tries for this workspace. | 
|  | 402                         rows, err := db.Query("SELECT create_ts, hash FROM works
     pacetry WHERE name=? ORDER BY create_ts DESC ", name) | 
|  | 403                         if err != nil { | 
|  | 404                                 reportError(w, r, err, "Failed to select.") | 
|  | 405                                 return | 
|  | 406                         } | 
|  | 407                         for rows.Next() { | 
|  | 408                                 var hash string | 
|  | 409                                 var create_ts time.Time | 
|  | 410                                 if err := rows.Scan(&create_ts, &hash); err != n
     il { | 
|  | 411                                         log.Printf("Error: failed to fetch from 
     database: %q", err) | 
|  | 412                                         continue | 
|  | 413                                 } | 
|  | 414                                 tries = append(tries, Try{Hash: hash, CreateTS: 
     create_ts.Format("2006-02-01")}) | 
|  | 415                         } | 
|  | 416                 } | 
|  | 417                 var code string | 
|  | 418                 if len(tries) == 0 { | 
|  | 419                         code = DEFAULT_SAMPLE | 
|  | 420                 } else { | 
|  | 421                         code = getCode(tries[len(tries)-1].Hash) | 
|  | 422                 } | 
|  | 423                 // If len(tries) == 0 then return the 'default code', otherwise 
     include the most recent code. | 
|  | 424                 // We don't worry about existence of a workspace with this name 
     since trying to | 
|  | 425                 // add a new try will fail. | 
|  | 426 | 
|  | 427                 if err := workspaceTemplate.Execute(w, Workspace{Tries: tries, C
     ode: code, Name: name}); err != nil { | 
|  | 428                         log.Printf("ERROR: Failed to expand template: %q\n", err
     ) | 
|  | 429                 } | 
|  | 430                 // Update POST to / so that it takes a JSON document that includ
     es not only | 
|  | 431                 // the code but an optional 'name' parameter. If the name is pre
     sent the | 
|  | 432                 // POST handler should also add a row to the workspacetry table. | 
|  | 433         } else if r.Method == "POST" { | 
|  | 434                 // Create a name and try to insert it into the db. | 
|  | 435                 // Redirect to /w/<name> | 
|  | 436                 if _, err := db.Exec("INSERT INTO workspace (name) VALUES(?)", "
     autumn-breeze-123"); err != nil { | 
|  | 437                         log.Printf("ERROR: Failed to insert workspace into datab
     ase: %q\n", err) | 
|  | 438                 } | 
|  | 439                 name, err := newWorkspace() | 
|  | 440                 if err != nil { | 
|  | 441                         http.Error(w, "Failed to create a new workspace.", 500) | 
|  | 442                         return | 
|  | 443                 } | 
|  | 444                 http.Redirect(w, r, "/w/"+name, 302) | 
|  | 445         } | 
|  | 446 } | 
|  | 447 | 
| 297 // hasPreProcessor returns true if any line in the code begins with a # char. | 448 // hasPreProcessor returns true if any line in the code begins with a # char. | 
| 298 func hasPreProcessor(code string) bool { | 449 func hasPreProcessor(code string) bool { | 
| 299         lines := strings.Split(code, "\n") | 450         lines := strings.Split(code, "\n") | 
| 300         for _, s := range lines { | 451         for _, s := range lines { | 
| 301                 if strings.HasPrefix(strings.TrimSpace(s), "#") { | 452                 if strings.HasPrefix(strings.TrimSpace(s), "#") { | 
| 302                         return true | 453                         return true | 
| 303                 } | 454                 } | 
| 304         } | 455         } | 
| 305         return false | 456         return false | 
| 306 } | 457 } | 
| 307 | 458 | 
|  | 459 type TryRequest struct { | 
|  | 460         Code string `json:"code"` | 
|  | 461         Name string `json:"name"` | 
|  | 462 } | 
|  | 463 | 
| 308 // mainHandler handles the GET and POST of the main page. | 464 // mainHandler handles the GET and POST of the main page. | 
| 309 func mainHandler(w http.ResponseWriter, r *http.Request) { | 465 func mainHandler(w http.ResponseWriter, r *http.Request) { | 
| 310         log.Printf("Main Handler: %q\n", r.URL.Path) | 466         log.Printf("Main Handler: %q\n", r.URL.Path) | 
| 311         if r.Method == "GET" { | 467         if r.Method == "GET" { | 
| 312                 code := DEFAULT_SAMPLE | 468                 code := DEFAULT_SAMPLE | 
| 313                 match := directLink.FindStringSubmatch(r.URL.Path) | 469                 match := directLink.FindStringSubmatch(r.URL.Path) | 
| 314                 if len(match) == 2 && r.URL.Path != "/" { | 470                 if len(match) == 2 && r.URL.Path != "/" { | 
| 315                         hash := match[1] | 471                         hash := match[1] | 
| 316                         if db == nil { | 472                         if db == nil { | 
| 317                                 http.NotFound(w, r) | 473                                 http.NotFound(w, r) | 
| (...skipping 15 matching lines...) Expand all  Loading... | 
| 333                 n, err := buf.ReadFrom(r.Body) | 489                 n, err := buf.ReadFrom(r.Body) | 
| 334                 if err != nil { | 490                 if err != nil { | 
| 335                         reportError(w, r, err, "Failed to read a request body.") | 491                         reportError(w, r, err, "Failed to read a request body.") | 
| 336                         return | 492                         return | 
| 337                 } | 493                 } | 
| 338                 if n == MAX_TRY_SIZE { | 494                 if n == MAX_TRY_SIZE { | 
| 339                         err := fmt.Errorf("Code length equal to, or exceeded, %d
     ", MAX_TRY_SIZE) | 495                         err := fmt.Errorf("Code length equal to, or exceeded, %d
     ", MAX_TRY_SIZE) | 
| 340                         reportError(w, r, err, "Code too large.") | 496                         reportError(w, r, err, "Code too large.") | 
| 341                         return | 497                         return | 
| 342                 } | 498                 } | 
| 343 »       »       code := string(buf.Bytes()) | 499 »       »       request := TryRequest{} | 
| 344 »       »       if hasPreProcessor(code) { | 500 »       »       if err := json.Unmarshal(buf.Bytes(), &request); err != nil { | 
|  | 501 »       »       »       reportError(w, r, err, "Coulnd't decode JSON.") | 
|  | 502 »       »       »       return | 
|  | 503 »       »       } | 
|  | 504 »       »       if hasPreProcessor(request.Code) { | 
| 345                         err := fmt.Errorf("Found preprocessor macro in code.") | 505                         err := fmt.Errorf("Found preprocessor macro in code.") | 
| 346                         reportError(w, r, err, "Preprocessor macros aren't allow
     ed.") | 506                         reportError(w, r, err, "Preprocessor macros aren't allow
     ed.") | 
| 347                         return | 507                         return | 
| 348                 } | 508                 } | 
| 349 »       »       hash, err := expandCode(LineNumbers(code)) | 509 »       »       hash, err := expandCode(LineNumbers(request.Code)) | 
| 350                 if err != nil { | 510                 if err != nil { | 
| 351                         reportError(w, r, err, "Failed to write the code to comp
     ile.") | 511                         reportError(w, r, err, "Failed to write the code to comp
     ile.") | 
| 352                         return | 512                         return | 
| 353                 } | 513                 } | 
| 354 »       »       writeToDatabase(hash, code) | 514 »       »       writeToDatabase(hash, request.Code, request.Name) | 
| 355                 message, err := doCmd(fmt.Sprintf(RESULT_COMPILE, hash, hash), t
     rue) | 515                 message, err := doCmd(fmt.Sprintf(RESULT_COMPILE, hash, hash), t
     rue) | 
| 356                 if err != nil { | 516                 if err != nil { | 
| 357                         reportError(w, r, err, "Failed to compile the code:\n"+m
     essage) | 517                         reportError(w, r, err, "Failed to compile the code:\n"+m
     essage) | 
| 358                         return | 518                         return | 
| 359                 } | 519                 } | 
| 360                 linkMessage, err := doCmd(fmt.Sprintf(LINK, hash, hash), true) | 520                 linkMessage, err := doCmd(fmt.Sprintf(LINK, hash, hash), true) | 
| 361                 if err != nil { | 521                 if err != nil { | 
| 362                         reportError(w, r, err, "Failed to link the code:\n"+link
     Message) | 522                         reportError(w, r, err, "Failed to link the code:\n"+link
     Message) | 
| 363                         return | 523                         return | 
| 364                 } | 524                 } | 
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 396                         reportError(w, r, err, "Failed to serialize a response."
     ) | 556                         reportError(w, r, err, "Failed to serialize a response."
     ) | 
| 397                         return | 557                         return | 
| 398                 } | 558                 } | 
| 399                 w.Write(resp) | 559                 w.Write(resp) | 
| 400         } | 560         } | 
| 401 } | 561 } | 
| 402 | 562 | 
| 403 func main() { | 563 func main() { | 
| 404         flag.Parse() | 564         flag.Parse() | 
| 405         http.HandleFunc("/i/", imageHandler) | 565         http.HandleFunc("/i/", imageHandler) | 
|  | 566         http.HandleFunc("/w/", workspaceHandler) | 
| 406         http.HandleFunc("/recent/", recentHandler) | 567         http.HandleFunc("/recent/", recentHandler) | 
| 407         http.HandleFunc("/css/", cssHandler) | 568         http.HandleFunc("/css/", cssHandler) | 
| 408         http.HandleFunc("/", mainHandler) | 569         http.HandleFunc("/", mainHandler) | 
| 409         log.Fatal(http.ListenAndServe(*port, nil)) | 570         log.Fatal(http.ListenAndServe(*port, nil)) | 
| 410 } | 571 } | 
| OLD | NEW | 
|---|