<commit_before>// Copyright (c) 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be found
// in the LICENSE file.

package main

import (
	"bytes"
        "encoding/json"
	"flag"
	"fmt"
	"html/template"
	"math/rand"
	"net"
	"net/http"
	"os"
	"path/filepath"
	"regexp"
        "sort"
	"strconv"
	"time"
)

import (
	"github.com/fiorix/go-web/autogzip"
	"github.com/golang/glog"
	"github.com/rcrowley/go-metrics"
)

import (
	"config"
        "db"
)

var (
	// indexTemplate is the main index.html page we serve.
	indexTemplate *template.Template = nil

	// clusterTemplate is the /clusters/ page we serve.
	clusterTemplate *template.Template = nil

	jsonHandlerPath = regexp.MustCompile(`/json/([a-z]*)$`)

	clustersHandlerPath = regexp.MustCompile(`/clusters/([a-z]*)$`)

        shortcutHandlerPath = regexp.MustCompile(`/shortcuts/([0-9]*)$`)
)

// flags
var (
	port       = flag.String("port", ":8000", "HTTP service address (e.g., ':8000')")
	doOauth    = flag.Bool("oauth", true, "Run through the OAuth 2.0 flow on startup, otherwise use a GCE service account.")
	gitRepoDir = flag.String("git_repo_dir", "../../../skia", "Directory location for the Skia repo.")
	tileDir    = flag.String("tile_dir", "/tmp/tiles", "What directory to look for tiles in.")
)

var (
	data *Data
)

const (
	// Maximum allowed data POST size.
	MAX_POST_SIZE = 64000
)

func init() {
	flag.Parse()

	rand.Seed(time.Now().UnixNano())

	metrics.RegisterRuntimeMemStats(metrics.DefaultRegistry)
	go metrics.CaptureRuntimeMemStats(metrics.DefaultRegistry, 1*time.Minute)
	addr, _ := net.ResolveTCPAddr("tcp", "skia-monitoring-b:2003")
	go metrics.Graphite(metrics.DefaultRegistry, 1*time.Minute, "skiaperf", addr)

	// Change the current working directory to the directory of the executable.
	var err error
	cwd, err := filepath.Abs(filepath.Dir(os.Args[0]))
	if err != nil {
		glog.Fatalln(err)
	}
	if err := os.Chdir(cwd); err != nil {
		glog.Fatalln(err)
	}

	indexTemplate = template.Must(template.ParseFiles(filepath.Join(cwd, "templates/index.html")))
	clusterTemplate = template.Must(template.ParseFiles(filepath.Join(cwd, "templates/clusters.html")))

}

// reportError formats an HTTP error response and also logs the detailed error message.
func reportError(w http.ResponseWriter, r *http.Request, err error, message string) {
	glog.Errorln(message, err)
	w.Header().Set("Content-Type", "text/plain")
	http.Error(w, message, 500)
}

type TracesShortcut struct {
    Keys []string     `json:"keys"`
}

type ShortcutResponse struct {
    Id      int64       `json:"id"`
}

// showcutHandler handles the POST and GET requests of the shortcut page.
func shortcutHandler(w http.ResponseWriter, r *http.Request) {
    match := shortcutHandlerPath.FindStringSubmatch(r.URL.Path)
    if match == nil {
            http.NotFound(w, r)
            return
    }
    if r.Method == "GET" {
        var traces string
        err := db.DB.QueryRow(`SELECT traces FROM shortcuts WHERE id =?`, match[1]).Scan(&traces)
        if err != nil {
            reportError(w, r, err, "Error while looking up shortcut.")
            return
        }
        w.Header().Set("Content-Type", "application/json")
        w.Write([]byte(traces))
    } else if r.Method == "POST" {
        r.ParseForm()
        if traces := r.Form.Get("data"); len(traces) <= 0 {
            reportError(w, r, fmt.Errorf("Unable to extract list of traces."), "Unable to process request.")
            return
        } else {
            // Validate by successfully marshalling and unmarshalling
            var marshalledShortcuts TracesShortcut<commit_msg>Added TODO<commit_after>// Copyright (c) 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be found
// in the LICENSE file.

package main

import (
	"bytes"
        "encoding/json"
	"flag"
	"fmt"
	"html/template"
	"math/rand"
	"net"
	"net/http"
	"os"
	"path/filepath"
	"regexp"
        "sort"
	"strconv"
	"time"
)

import (
	"github.com/fiorix/go-web/autogzip"
	"github.com/golang/glog"
	"github.com/rcrowley/go-metrics"
)

import (
	"config"
        "db"
)

var (
	// indexTemplate is the main index.html page we serve.
	indexTemplate *template.Template = nil

	// clusterTemplate is the /clusters/ page we serve.
	clusterTemplate *template.Template = nil

	jsonHandlerPath = regexp.MustCompile(`/json/([a-z]*)$`)

	clustersHandlerPath = regexp.MustCompile(`/clusters/([a-z]*)$`)

        shortcutHandlerPath = regexp.MustCompile(`/shortcuts/([0-9]*)$`)
)

// flags
var (
	port       = flag.String("port", ":8000", "HTTP service address (e.g., ':8000')")
	doOauth    = flag.Bool("oauth", true, "Run through the OAuth 2.0 flow on startup, otherwise use a GCE service account.")
	gitRepoDir = flag.String("git_repo_dir", "../../../skia", "Directory location for the Skia repo.")
	tileDir    = flag.String("tile_dir", "/tmp/tiles", "What directory to look for tiles in.")
)

var (
	data *Data
)

const (
	// Maximum allowed data POST size.
	MAX_POST_SIZE = 64000
)

func init() {
	flag.Parse()

	rand.Seed(time.Now().UnixNano())

	metrics.RegisterRuntimeMemStats(metrics.DefaultRegistry)
	go metrics.CaptureRuntimeMemStats(metrics.DefaultRegistry, 1*time.Minute)
	addr, _ := net.ResolveTCPAddr("tcp", "skia-monitoring-b:2003")
	go metrics.Graphite(metrics.DefaultRegistry, 1*time.Minute, "skiaperf", addr)

	// Change the current working directory to the directory of the executable.
	var err error
	cwd, err := filepath.Abs(filepath.Dir(os.Args[0]))
	if err != nil {
		glog.Fatalln(err)
	}
	if err := os.Chdir(cwd); err != nil {
		glog.Fatalln(err)
	}

	indexTemplate = template.Must(template.ParseFiles(filepath.Join(cwd, "templates/index.html")))
	clusterTemplate = template.Must(template.ParseFiles(filepath.Join(cwd, "templates/clusters.html")))

}

// reportError formats an HTTP error response and also logs the detailed error message.
func reportError(w http.ResponseWriter, r *http.Request, err error, message string) {
	glog.Errorln(message, err)
	w.Header().Set("Content-Type", "text/plain")
	http.Error(w, message, 500)
}

type TracesShortcut struct {
    Keys []string     `json:"keys"`
}

type ShortcutResponse struct {
    Id      int64       `json:"id"`
}

// showcutHandler handles the POST and GET requests of the shortcut page.
func shortcutHandler(w http.ResponseWriter, r *http.Request) {
    // TODO(kelvinly/jcgregorio?): Add unit testing later
    match := shortcutHandlerPath.FindStringSubmatch(r.URL.Path)
    if match == nil {
            http.NotFound(w, r)
            return
    }
    if r.Method == "GET" {
        var traces string
        err := db.DB.QueryRow(`SELECT traces FROM shortcuts WHERE id =?`, match[1]).Scan(&traces)
        if err != nil {
            reportError(w, r, err, "Error while looking up shortcut.")
            return
        }
        w.Header().Set("Content-Type", "application/json")
        w.Write([]byte(traces))
    } else if r.Method == "POST" {
        r.ParseForm()
        if traces := r.Form.Get("data"); len(traces) <= 0 {
            reportError(w, r, fmt.Errorf("Unable to extract list of traces."), "Unable to process request.")
            return
        } else {
            // Validate by successfully marshalling and unmarshalling
            var marshalledShortcuts TracesShortcut
{'fraction_non_alphanumeric': 0.13938083006624308, 'fraction_numerical': 0.00946329593078275, 'mean_word_length': 3.244406196213425, 'pattern_counts': {'":': 2, '<': 5, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1053726', 'n_tokens_mistral': 2513, 'n_tokens_neox': 2405, 'n_words': 633}