summary refs log tree commit diff stats
path: root/config/bindings_test.go
Commit message (Collapse)AuthorAgeFilesLines
* Implement key bindings subsystemDrew DeVault2019-03-151-0/+61
Which is not yet rigged up
' href='#n38'>38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
package svc // import "github.com/getwtxt/getwtxt/svc"

import (
	"crypto/sha256"
	"fmt"
	"log"
	"net/http"
	"strconv"
	"strings"

	"github.com/getwtxt/registry"
	"github.com/gorilla/mux"
)

func apiErrCheck(err error, r *http.Request) {
	if err != nil {
		uip := getIPFromCtx(r.Context())
		log.Printf("*** %v :: %v %v :: %v\n", uip, r.Method, r.URL, err.Error())
	}
}

func dedupe(list []string) []string {
	out := []string{}
	seen := make(map[string]bool)

	for _, e := range list {
		if !seen[e] {
			out = append(out, e)
			seen[e] = true
		}
	}

	return out
}

// Takes the output of queries and formats it for
// an HTTP response. Iterates over the string slice,
// appending each entry to a byte slice, and adding
// newlines where appropriate.
func parseQueryOut(out []string) []byte {
	var data []byte

	for i, e := range out {
		data = append(data, []byte(e)...)

		if !strings.HasSuffix(e, "\n") && i != len(out)-1 {
			data = append(data, byte('\n'))
		}
	}

	return data
}

// apiEndpointQuery is called via apiEndpointHandler when
// the endpoint is "users" and r.FormValue("q") is not empty.
// It queries the registry cache for users or user URLs
// matching the term supplied via r.FormValue("q")
func apiEndpointQuery(w http.ResponseWriter, r *http.Request) error {
	query := r.FormValue("q")
	urls := r.FormValue("url")
	pageVal := r.FormValue("page")
	var out []string
	var err error

	pageVal = strings.TrimSpace(pageVal)
	page, err := strconv.Atoi(pageVal)
	if err != nil {
		log.Printf("%v\n", err.Error())
	}

	vars := mux.Vars(r)
	endpoint := vars["endpoint"]

	// Handle user URL queries first, then nickname queries.
	// Concatenate both outputs if they're both set.
	// Also handle mention queries and status queries.
	// If we made it this far and 'default' is matched,
	// something went very wrong.
	switch endpoint {
	case "users":
		var out2 []string
		if query != "" {
			out, err = twtxtCache.QueryUser(query)
			apiErrCheck(err, r)
		}
		if urls != "" {
			out2, err = twtxtCache.QueryUser(urls)
			apiErrCheck(err, r)
		}

		if query != "" && urls != "" {
			out = joinQueryOuts(out2)
		}

	case "mentions":
		if urls == "" {
			return fmt.Errorf("missing URL in mention query")
		}
		urls += ">"
		out, err = twtxtCache.QueryInStatus(urls)
		apiErrCheck(err, r)

	case "tweets":
		out = compositeStatusQuery(query, r)

	default:
		return fmt.Errorf("endpoint query, no cases match")
	}

	out = registry.ReduceToPage(page, out)
	data := parseQueryOut(out)

	etag := fmt.Sprintf("%x", sha256.Sum256(data))
	w.Header().Set("ETag", etag)
	w.Header().Set("Content-Type", txtutf8)

	_, err = w.Write(data)

	return err
}

func joinQueryOuts(data ...[]string) []string {
	single := []string{}
	for _, e := range data {
		single = append(single, e...)
	}

	return dedupe(single)
}

func compositeStatusQuery(query string, r *http.Request) []string {
	query = strings.ToLower(query)
	out, err := twtxtCache.QueryInStatus(query)
	apiErrCheck(err, r)

	query = strings.Title(query)
	out2, err := twtxtCache.QueryInStatus(query)
	apiErrCheck(err, r)

	query = strings.ToUpper(query)
	out3, err := twtxtCache.QueryInStatus(query)
	apiErrCheck(err, r)

	final := joinQueryOuts(out, out2, out3)
	return final
}