2022-07-08 03:48:28 +00:00
package main
import (
"database/sql"
"fmt"
_ "github.com/go-sql-driver/mysql"
"html"
"html/template"
"io/ioutil"
"log"
"net/http"
"net/url"
"strconv"
"strings"
"unicode/utf8"
// "sync"
// "time"
)
type indexPage struct { }
type errorReport struct { Error string }
type surpriseURL struct { Url string }
type settingsPage struct { Worksafe , FilterHTTPS bool }
type MySQLResults struct { Id , Url , Title , Description , Body string }
type PageData struct {
DBResults [ ] MySQLResults
2023-03-09 02:17:53 +00:00
Query , Page string
FindMore bool
2022-07-08 03:48:28 +00:00
}
func main ( ) {
http . HandleFunc ( "/" , handler )
http . HandleFunc ( "/json" , handler )
http . HandleFunc ( "/json/" , handler )
http . HandleFunc ( "/surprise" , surprise )
http . HandleFunc ( "/surprise/" , surprise )
http . HandleFunc ( "/settings/" , settings )
http . HandleFunc ( "/settings" , settings )
2023-09-10 02:49:23 +00:00
log . Fatal ( http . ListenAndServe ( "0.0.0.0:8080" , nil ) ) //set IP to localhost if reverse proxy is on the same machine
2022-07-08 03:48:28 +00:00
}
//https://golang.org/pkg/net/http/#Request
func handler ( w http . ResponseWriter , r * http . Request ) {
//fmt.Fprintf(w, "%s %s \n", r.Method, r.URL)
//fmt.Fprintf(w, "%s \n", r.URL.RawQuery)
2023-03-25 03:27:14 +00:00
//Indicate whether or not you are using shard tables
2023-08-13 22:28:10 +00:00
shards := true
2023-03-25 03:27:14 +00:00
2022-07-08 03:48:28 +00:00
//check if worksafe+https cookie enabled.
filterHTTPS := false
worksafe := true
worksafeHTTPSCookie , err := r . Cookie ( "ws" )
if err != nil {
worksafe = true
filterHTTPS = false
} else if worksafeHTTPSCookie . Value == "0" {
worksafe = false
filterHTTPS = false
} else if worksafeHTTPSCookie . Value == "1" {
worksafe = true
filterHTTPS = false
} else if worksafeHTTPSCookie . Value == "2" {
worksafe = false
filterHTTPS = true
} else if worksafeHTTPSCookie . Value == "3" {
worksafe = true
filterHTTPS = true
}
//setup for error report
error := errorReport { }
//Get the raw query
m , _ := url . ParseQuery ( r . URL . RawQuery )
//Get the query parameters (q and o)
//fmt.Fprintf(w,"%s\n%s\n", m["q"][0], m["o"][0])
json := false
if strings . Contains ( r . URL . Path , "/json" ) {
json = true
if _ , ok := m [ "nsfw" ] ; ok { //check if &nsfw added to json url
worksafe = false
}
}
query := ""
queryNoQuotes := ""
offset := "0"
2023-03-09 02:17:53 +00:00
page := "0"
2022-07-08 03:48:28 +00:00
2022-10-17 05:46:12 +00:00
//Check if query and page params exist
2022-07-08 03:48:28 +00:00
if _ , ok := m [ "q" ] ; ok {
2023-09-28 05:01:42 +00:00
query = m [ "q" ] [ 0 ]
query = strings . Replace ( query , "'" , "''" , - 1 )
query = strings . Replace ( query , "- " , " " , - 1 )
2023-09-10 02:38:54 +00:00
queryNoQuotes = query
2022-07-08 03:48:28 +00:00
}
2022-10-17 05:46:12 +00:00
if _ , ok := m [ "p" ] ; ok { //gets page num, will convert to offset further down
2023-09-28 05:01:42 +00:00
page = m [ "p" ] [ 0 ]
page = strings . Replace ( page , "'" , "''" , - 1 )
2023-03-09 02:17:53 +00:00
offset = page
}
2022-07-08 03:48:28 +00:00
lim := "12"
// limDistributedInt :=
if query == "" { //what do if no query found?
//load index if no query detected
if r . URL . Path == "/" {
p := indexPage { }
t , _ := template . ParseFiles ( "coreassets/form.html.go" )
t . Execute ( w , p )
} else if strings . Contains ( r . URL . Path , "/json" ) { //load json info page if json selected
p := indexPage { }
t , _ := template . ParseFiles ( "coreassets/json/json.html.go" )
t . Execute ( w , p )
} else {
p := indexPage { }
t , _ := template . ParseFiles ( "coreassets/form.html.go" )
t . Execute ( w , p )
}
} else {
//Make sure offset is a number
offsetInt , err := strconv . Atoi ( offset )
if err != nil {
offset = "0"
offsetInt = 0
}
2022-10-17 05:46:12 +00:00
2023-03-09 02:17:53 +00:00
//Make sure page is a number
pageInt , err := strconv . Atoi ( page )
if err != nil {
page = "0"
pageInt = 0
}
2022-10-17 05:46:12 +00:00
//Convert lim to number
2022-07-08 03:48:28 +00:00
limInt , _ := strconv . Atoi ( lim )
2022-10-17 05:46:12 +00:00
//convert page num to offset
if offsetInt > 0 {
offsetInt -- ;
}
offsetInt = offsetInt * limInt
offset = strconv . Itoa ( offsetInt )
2022-07-08 03:48:28 +00:00
//get some details from the raw query
var additions string
querylen := len ( query )
//see if a search redirect (! or &) is used for a different search engine
if json == false && ( strings . Contains ( m [ "q" ] [ 0 ] , "!" ) || strings . Contains ( m [ "q" ] [ 0 ] , "&" ) ) {
searchredirect ( w , r , m [ "q" ] [ 0 ] )
}
//phone users
if query [ querylen - 1 ] == ' ' {
query = query [ : querylen - 1 ]
queryNoQuotes = queryNoQuotes [ : len ( queryNoQuotes ) - 1 ]
querylen = len ( query )
2023-04-01 03:47:01 +00:00
}
if querylen > 1 && query [ 0 ] == ' ' {
query = query [ 1 : querylen ]
queryNoQuotes = queryNoQuotes [ 1 : len ( queryNoQuotes ) ]
querylen = len ( query )
2022-07-08 03:48:28 +00:00
}
//check if user wants to limit search to a specific website
sitePos := - 1
siteEnd := 0
siteURL := ""
if strings . Index ( strings . ToLower ( query ) , "site:" ) > - 1 {
//get url user wants to search and remove it from the query string
sitePos = strings . Index ( strings . ToLower ( query ) , "site:" )
siteEnd = strings . Index ( query [ sitePos : ] , " " )
//fmt.Printf("\n%d\n%d\n",sitePos,siteEnd)
if siteEnd > - 1 && sitePos > 1 { //site is not last part of query
siteURL = query [ sitePos + 5 : siteEnd + sitePos ]
query = query [ : sitePos - 1 ] + query [ siteEnd + sitePos : ]
queryNoQuotes = queryNoQuotes [ : sitePos - 1 ] + queryNoQuotes [ siteEnd + sitePos : ]
additions = additions + "AND url LIKE '%" + siteURL + "%' "
} else if siteEnd > - 1 && sitePos == 0 { //site is at beginning
siteURL = query [ sitePos + 5 : siteEnd ]
query = query [ siteEnd + 1 : ]
queryNoQuotes = queryNoQuotes [ siteEnd + 1 : ]
additions = additions + "AND url LIKE '%" + siteURL + "%' "
} else if siteEnd < 0 && sitePos > 1 { //site is at end
siteURL = query [ sitePos + 5 : ]
query = query [ : sitePos - 1 ]
queryNoQuotes = queryNoQuotes [ : sitePos - 1 ]
additions = additions + "AND url LIKE '%" + siteURL + "%' "
} else if querylen > 5 {
query = query [ 5 : ]
}
querylen = len ( query )
}
//fmt.Printf("Addition: \n%s\nQuery: '%s'\n",additions,query)
//see if user uses -https flag (instead of cookie settings option)
if querylen > 7 && strings . ToLower ( query [ querylen - 7 : querylen ] ) == " -https" {
filterHTTPS = true
query = query [ 0 : querylen - 7 ]
querylen = len ( query )
}
//check if user wants to search within a time window (day,week,month)
option := ""
//fmt.Printf("\n'%s'\n",query)
location := strings . Index ( query , " !" )
if location == - 1 {
location = strings . Index ( query , " &" )
}
if location > - 1 && strings . Index ( query [ location + 1 : querylen ] , " " ) == - 1 { //option is at end of query
option = query [ location + 2 : querylen ]
query = query [ : location ]
queryNoQuotes = queryNoQuotes [ : location ]
querylen = len ( query )
} else if querylen > 0 && ( query [ 0 ] == '!' || query [ 0 ] == '&' ) && strings . Index ( query , " " ) > - 1 { //option is at start of query
option = query [ 1 : strings . Index ( query , " " ) ]
query = query [ strings . Index ( query , " " ) + 1 : ]
queryNoQuotes = queryNoQuotes [ strings . Index ( queryNoQuotes , " " ) + 1 : ]
querylen = len ( query )
}
option = strings . ToLower ( option )
if option != "" {
if option == "td" { //day
additions = additions + "AND date > NOW() - INTERVAL 1 DAY "
} else if option == "tw" { //week
additions = additions + "AND date > NOW() - INTERVAL 7 DAY "
} else if option == "tm" { //month
additions = additions + "AND date > NOW() - INTERVAL 30 DAY "
} else if option == "ty" { //year
additions = additions + "AND date > NOW() - INTERVAL 365 DAY "
}
}
//check if worksafe and filterHTTPS flags set
if worksafe == true {
additions = additions + "AND worksafe = '1' "
}
if filterHTTPS == true {
additions = additions + "AND http = '1' "
}
//search if query has quotes and remove them (so we can find the longest word in the query)
exactMatch := false
//queryNoQuotes := query
if strings . Contains ( query , "\"" ) {
exactMatch = true
2023-09-29 03:49:35 +00:00
queryNoQuotes = strings . Replace ( queryNoQuotes , "\"" , "" , - 1 )
2022-07-08 03:48:28 +00:00
//fmt.Printf("%s \n", queryNoQuotes)
}
2023-09-10 02:38:54 +00:00
//remove the '*' if contained anywhere in queryNoQuotes
if strings . Contains ( queryNoQuotes , "*" ) && exactMatch == false {
queryNoQuotes = strings . Replace ( queryNoQuotes , "*" , "" , - 1 )
}
2022-07-08 03:48:28 +00:00
//Prepare to find longest word in query
words := strings . Split ( queryNoQuotes , " " )
longestWordLength := 0
longestWord := ""
wordcount := 0
longestwordelementnum := 0
2023-09-10 02:38:54 +00:00
queryNoQuotesOrFlags := queryNoQuotes
2022-07-08 03:48:28 +00:00
requiredword := ""
2023-03-09 02:17:53 +00:00
flags := ""
2023-09-18 22:24:19 +00:00
flagssetbyuser := 0
wordlen := 0
numRequiredWords := 0
2022-07-08 03:48:28 +00:00
//queryNoFlags := ""
2023-09-29 03:49:35 +00:00
2022-07-08 03:48:28 +00:00
//first remove any flags inside var queryNoQuotes, also grab any required words (+ prefix)
if strings . Contains ( queryNoQuotes , "-" ) || strings . Contains ( queryNoQuotes , "+" ) {
2023-09-10 02:38:54 +00:00
queryNoQuotesOrFlags = ""
2022-07-08 03:48:28 +00:00
for i , wordNoFlags := range words {
2023-03-09 02:17:53 +00:00
if i > 0 && strings . HasPrefix ( wordNoFlags , "-" ) == false && strings . HasPrefix ( wordNoFlags , "+" ) == false { //add a space after
2022-07-08 03:48:28 +00:00
queryNoQuotesOrFlags += " "
}
if strings . HasPrefix ( wordNoFlags , "-" ) == false && strings . HasPrefix ( wordNoFlags , "+" ) == false {
queryNoQuotesOrFlags += wordNoFlags
}
2023-09-12 05:50:24 +00:00
if strings . HasPrefix ( wordNoFlags , "+" ) == true && len ( wordNoFlags ) > 1 && requiredword == "" { //get requiredword
2022-07-08 03:48:28 +00:00
requiredword = wordNoFlags [ 1 : len ( wordNoFlags ) ]
}
2023-03-09 02:17:53 +00:00
if i > 0 && strings . HasPrefix ( wordNoFlags , "-" ) == true || strings . HasPrefix ( wordNoFlags , "+" ) == true {
flags += " " + wordNoFlags
2023-09-18 22:24:19 +00:00
flagssetbyuser ++
if strings . HasPrefix ( wordNoFlags , "+" ) == true {
numRequiredWords ++
}
2023-03-09 02:17:53 +00:00
}
2022-07-08 03:48:28 +00:00
}
2023-09-29 03:49:35 +00:00
flags = checkformat ( flags )
2022-07-08 03:48:28 +00:00
}
2023-09-10 20:18:51 +00:00
//now find longest word, and build extra locate statements for partial matches (when sorting results returned from replicas)
partialLocate := ""
2023-09-11 02:55:09 +00:00
locateWords := false
2023-09-17 04:33:44 +00:00
words = strings . Split ( queryNoQuotesOrFlags , " " )
2023-09-29 03:49:35 +00:00
for _ , word := range words {
if len ( word ) > longestWordLength {
longestWordLength = len ( word )
longestWord = word
longestwordelementnum = wordcount
}
if wordcount < 5 && len ( word ) > 3 {
if locateWords == false {
partialLocate += " WHEN LOCATE('" + word + "', title) "
} else {
partialLocate += "OR LOCATE('" + word + "', title) "
2023-09-18 22:24:19 +00:00
}
2023-09-29 03:49:35 +00:00
locateWords = true
2022-07-08 03:48:28 +00:00
}
2023-09-29 03:49:35 +00:00
if word != "" {
wordcount ++
2023-09-11 02:55:09 +00:00
}
2022-07-08 03:48:28 +00:00
}
2023-09-29 03:49:35 +00:00
if locateWords == true {
partialLocate += "THEN 10"
}
2023-09-10 20:18:51 +00:00
//fmt.Printf("\n%s",partialLocate)
2022-07-08 03:48:28 +00:00
2023-10-02 01:29:08 +00:00
//create another query where all compatible words are marked as required
2023-09-17 04:33:44 +00:00
reqwordQuery := ""
2023-09-10 02:38:54 +00:00
for i , word := range words {
wordlen = len ( word )
if i == 0 && ( strings . HasPrefix ( word , "+" ) == true || strings . HasPrefix ( word , "-" ) == true ) && wordlen > 3 {
2023-09-17 04:33:44 +00:00
reqwordQuery += word
2023-09-10 02:38:54 +00:00
}
if i == 0 && ( strings . HasPrefix ( word , "+" ) == false && strings . HasPrefix ( word , "-" ) == false ) {
if wordlen > 2 {
2023-09-17 04:33:44 +00:00
reqwordQuery += "+"
2023-09-10 02:38:54 +00:00
}
2023-09-17 04:33:44 +00:00
reqwordQuery += word
2023-09-10 02:38:54 +00:00
}
if i != 0 && ( strings . HasPrefix ( word , "+" ) == true || strings . HasPrefix ( word , "-" ) == true ) && wordlen > 3 {
2023-09-17 04:33:44 +00:00
reqwordQuery += " "
reqwordQuery += word
2023-09-10 02:38:54 +00:00
}
if i != 0 && ( strings . HasPrefix ( word , "+" ) == false && strings . HasPrefix ( word , "-" ) == false ) {
2023-09-17 04:33:44 +00:00
reqwordQuery += " "
2023-09-10 02:38:54 +00:00
if wordlen > 2 {
2023-09-17 04:33:44 +00:00
reqwordQuery += "+"
2023-09-10 02:38:54 +00:00
}
2023-09-17 04:33:44 +00:00
reqwordQuery += word
2023-09-10 02:38:54 +00:00
}
2022-07-08 03:48:28 +00:00
}
2023-10-01 02:18:01 +00:00
reqwordQuery = checkformat ( reqwordQuery )
2023-09-18 22:24:19 +00:00
reqwordQuery += flags
2022-07-08 03:48:28 +00:00
//fmt.Fprintf(w,"%s\n%s\n", query,offset)
//fmt.Printf("hai\n")
//get copy of original query because we might have to modify it somewhat
queryOriginal := query
tRes := MySQLResults { }
var res = PageData { }
2023-03-25 03:27:14 +00:00
//Check if query is a url.
2022-07-08 03:48:28 +00:00
urlDetected := false
isURL := ""
2023-08-15 02:29:55 +00:00
isURLlocate := ""
2022-07-08 03:48:28 +00:00
if strings . Index ( query , " " ) == - 1 && strings . Index ( query , "\"" ) == - 1 && strings . Index ( query , "." ) > - 1 { //note this will also flag on file extensions
if len ( query ) > 6 && ( query [ 0 : 7 ] == "http://" || query [ 0 : 7 ] == "HTTP://" ) {
query = query [ 7 : ]
} else if len ( query ) > 7 && ( query [ 0 : 8 ] == "https://" || query [ 0 : 8 ] == "HTTPS://" ) {
query = query [ 8 : ]
}
2023-09-10 02:38:54 +00:00
if len ( queryNoQuotes ) > 6 && ( queryNoQuotes [ 0 : 7 ] == "http://" || queryNoQuotes [ 0 : 7 ] == "HTTP://" ) {
queryNoQuotes = queryNoQuotes [ 7 : ]
} else if len ( queryNoQuotes ) > 7 && ( queryNoQuotes [ 0 : 8 ] == "https://" || queryNoQuotes [ 0 : 8 ] == "HTTPS://" ) {
queryNoQuotes = queryNoQuotes [ 8 : ]
2022-07-08 03:48:28 +00:00
}
query = "\"" + query + "\""
urlDetected = true
2023-09-10 02:38:54 +00:00
isURL = "WHEN MATCH(url) AGAINST('\"" + queryNoQuotes + "\"' IN BOOLEAN MODE) THEN 25"
isURLlocate = "WHEN LOCATE('" + queryNoQuotesOrFlags + "', url) THEN 25"
2022-07-08 03:48:28 +00:00
}
2023-09-17 04:33:44 +00:00
//if no required words set, make the longest word in the query required.
querywithrequiredword := ""
if numRequiredWords == 0 && wordcount > 1 && longestWordLength > 2 {
querywithrequiredword = query + " +"
querywithrequiredword = querywithrequiredword + longestWord
2023-09-18 22:24:19 +00:00
}
2023-09-17 04:33:44 +00:00
2022-07-08 03:48:28 +00:00
//perform full text search FOR InnoDB or MyISAM
var sqlQuery , id , url , title , description , body , idList string
rangeOffset := 0
serverCount := 0
var servers [ ] string
numServers := 0
//parse res.csv
2023-03-25 03:27:14 +00:00
noservers := false
2022-07-08 03:48:28 +00:00
repLim , _ := strconv . Atoi ( lim )
repOffset , _ := strconv . Atoi ( offset )
repLimStr := ""
repOffsetStr := ""
2023-03-25 03:27:14 +00:00
shard := ""
2022-07-08 03:48:28 +00:00
noresults := 0
repsearchfail := 0
var idListChans [ ] chan string
2023-03-25 03:27:14 +00:00
oneword := false
2023-08-13 19:15:14 +00:00
if strings . Index ( query , " " ) == - 1 {
2023-03-25 03:27:14 +00:00
oneword = true
}
2022-07-08 03:48:28 +00:00
resourceFile , err := ioutil . ReadFile ( "res.csv" )
if err != nil {
2023-03-25 03:27:14 +00:00
noservers = true
2022-07-08 03:48:28 +00:00
} else {
if len ( resourceFile ) < 2 {
2023-03-25 03:27:14 +00:00
noservers = true
2022-07-08 03:48:28 +00:00
}
}
2023-03-09 02:17:53 +00:00
//this switches off use of multiple connections to process a one word query. Should remove this if the database grows significantly larger
2023-08-13 19:15:14 +00:00
/ * if strings . Contains ( query , " " ) == false && oneletterquery == 0 {
2023-03-25 03:27:14 +00:00
noservers = true
2023-08-13 19:15:14 +00:00
} * /
2022-07-08 03:48:28 +00:00
2023-09-10 02:38:54 +00:00
queryWithQuotesAndFlags := "\"" + queryNoQuotesOrFlags + "\"" + flags
2023-09-29 03:49:35 +00:00
queryWithQuotes := "\"" + queryNoQuotesOrFlags + "\""
2023-09-10 02:38:54 +00:00
//if query is just 1 or 2 letters, help make it work.
if utf8 . RuneCountInString ( queryOriginal ) < 3 {
queryfix := "" + query + "*"
query = queryfix
queryWithQuotesAndFlags = queryfix
2023-09-17 04:33:44 +00:00
reqwordQuery = queryfix
2023-09-10 02:38:54 +00:00
}
2023-09-18 22:24:19 +00:00
if strings . Contains ( queryOriginal , "c++" ) == true || strings . Contains ( queryOriginal , "C++" ) == true { // :) :( :) :(
exactMatch = true
queryWithQuotesAndFlags += " +programming"
if strings . Contains ( queryOriginal , " " ) == true && longestWordLength > 3 {
queryWithQuotesAndFlags += " +"
queryWithQuotesAndFlags += longestWord
}
2023-09-10 02:38:54 +00:00
}
2023-03-09 02:17:53 +00:00
2023-09-12 05:50:24 +00:00
querytouse := query
2023-09-17 04:33:44 +00:00
if querywithrequiredword != "" {
querytouse = querywithrequiredword
2023-09-18 22:24:19 +00:00
} else if numRequiredWords > 0 {
2023-09-17 04:33:44 +00:00
querytouse = reqwordQuery
2023-09-12 05:50:24 +00:00
}
2023-09-29 03:49:35 +00:00
if exactMatch == false && urlDetected == false {
querytouse = checkformat ( querytouse )
reqwordQuery = checkformat ( reqwordQuery )
}
2023-09-23 18:18:28 +00:00
reqwordQuery_filtered := strings . Replace ( reqwordQuery , "'" , "" , - 1 )
//For a less restrictive search, replace only the first instance of reqwordQuery_filtered with querytouse_filtered in the SQL query used when calling the distributedQuery go routine
querytouse_filtered := strings . Replace ( querytouse , "'" , "" , - 1 )
queryWithQuotesAndFlags_filtered := strings . Replace ( queryWithQuotesAndFlags , "'" , "" , - 1 )
2023-09-29 03:49:35 +00:00
queryWithQuotes_filtered := strings . Replace ( queryWithQuotes , "'" , "" , - 1 )
2023-09-12 05:50:24 +00:00
2023-03-25 03:27:14 +00:00
if noservers == false {
2022-07-08 03:48:28 +00:00
//send query to go routines.
resourceFilestring := string ( resourceFile )
//just in case user is messing around res.csv with a text editor and the editor ads a line feed to the end of the file
if len ( resourceFilestring ) > 0 && resourceFilestring [ len ( resourceFilestring ) - 1 ] == byte ( '\n' ) {
resourceFilestring = resourceFilestring [ 0 : len ( resourceFilestring ) - 1 ]
}
servers = strings . Split ( resourceFilestring , "\n" )
numServers = len ( servers )
2023-03-20 06:13:12 +00:00
2023-03-25 03:27:14 +00:00
if ( shards == false ) {
//numServers must divide evenly into lim, or lim must divide evenly into numservers
//if they do not, automatically adjust numServers until they divide evenly
//calculate number of servers to use based on lim size
if limInt > numServers {
for limInt % numServers > 0 {
numServers -= 1
}
} else if numServers > limInt {
for numServers % limInt > 0 {
numServers -= 1
}
2022-07-08 03:48:28 +00:00
}
}
//calculate limit and offset on distributed servers.
if numServers < limInt {
repLim = limInt / numServers
} else {
repLim = 1
}
repOffset = offsetInt / numServers
//calculate rangeOffset (offset for the range of returned results, important if numServers > 2*lim)
rangeOffset = offsetInt - ( repOffset * numServers )
repLimStr = strconv . Itoa ( repLim )
repOffsetStr = strconv . Itoa ( repOffset )
//create a channel for each available server
for i := 0 ; i < numServers ; i ++ {
idListChans = append ( idListChans , make ( chan string ) )
}
2023-08-15 02:29:55 +00:00
2023-03-25 03:27:14 +00:00
for _ , server := range servers {
serverSettings := strings . Split ( server , "," )
if len ( serverSettings ) == 4 { //if line contains all 4 settings
//ip, database, startID, endID
//create SQL connection string //db, err := sql.Open("mysql", "remote_guest:d0gemuchw0w@tcp(192.168.1.xxx:3306)/wiby?charset=utf8mb4")
serverIP := serverSettings [ 0 ]
shard = serverSettings [ 1 ]
startID := serverSettings [ 2 ]
endID := serverSettings [ 3 ]
sqlString := "remote_guest:d0gemuchw0w@tcp(" + serverIP + ":3306)/wiby?charset=utf8mb4"
// fmt.Printf("%s %s %s %d\n",sqlString,startID,endID,numServers)
//send special distributed query, only need ID returned
2023-08-13 19:15:14 +00:00
if ( shards == false ) { //depricated
2023-09-10 02:38:54 +00:00
/ * if ( exactMatch == false && urlDetected == false && oneword == false ) {
2023-03-25 03:27:14 +00:00
sqlQuery = "SELECT id FROM windex WHERE id BETWEEN " + startID + " AND " + endID + " AND enable = '1' " + additions + "ORDER BY CASE WHEN MATCH(tags) AGAINST('" + queryWithQuotesAndFlags + "' IN BOOLEAN MODE) THEN 30 " + isURL + " WHEN MATCH(title) AGAINST('" + queryWithQuotesAndFlags + "' IN BOOLEAN MODE) AND Match(title) AGAINST('" + query + "' IN BOOLEAN MODE) THEN 20 WHEN MATCH(body) AGAINST('" + queryWithQuotesAndFlags + "' IN BOOLEAN MODE) THEN 19 WHEN MATCH(title) AGAINST('" + queryWithQuotesAndFlags + "' IN BOOLEAN MODE) THEN 16 WHEN MATCH(description) AGAINST('" + queryWithQuotesAndFlags + "' IN BOOLEAN MODE) THEN 15 WHEN Match(title) AGAINST('" + query + "' IN BOOLEAN MODE) THEN Match(title) AGAINST('" + query + "' IN BOOLEAN MODE) WHEN MATCH(body) AGAINST('" + query + "' IN BOOLEAN MODE) THEN 1 WHEN MATCH(url) AGAINST('" + query + "' IN BOOLEAN MODE) THEN 0 END DESC, id DESC LIMIT " + repLimStr + " OFFSET " + repOffsetStr + ""
} else {
sqlQuery = "SELECT id FROM windex WHERE id BETWEEN " + startID + " AND " + endID + " AND enable = '1' " + additions + "ORDER BY CASE WHEN MATCH(tags) AGAINST('" + queryWithQuotesAndFlags + "' IN BOOLEAN MODE) THEN 30 " + isURL + " WHEN MATCH(title) AGAINST('" + queryWithQuotesAndFlags + "' IN BOOLEAN MODE) THEN 20 WHEN MATCH(body) AGAINST('" + queryWithQuotesAndFlags + "' IN BOOLEAN MODE) THEN 19 WHEN MATCH(description) AGAINST('" + queryWithQuotesAndFlags + "' IN BOOLEAN MODE) THEN 15 WHEN MATCH(url) AGAINST('" + query + "' IN BOOLEAN MODE) THEN 0 END DESC, id DESC LIMIT " + repLimStr + " OFFSET " + repOffsetStr + ""
2023-09-10 02:38:54 +00:00
} * /
2023-03-25 03:27:14 +00:00
} else {
2023-09-29 03:49:35 +00:00
if ( exactMatch == false || flagssetbyuser > 0 ) && urlDetected == false && strings . Index ( query , " " ) != - 1 && flagssetbyuser + wordcount != flagssetbyuser {
sqlQuery = "SELECT id FROM " + shard + " WHERE MATCH(tags, body, description, title, url) AGAINST('" + reqwordQuery_filtered + "' IN BOOLEAN MODE) AND enable = '1' " + additions + "ORDER BY CASE WHEN MATCH(tags) AGAINST('" + queryWithQuotes_filtered + "' IN BOOLEAN MODE) THEN 30 " + isURL + " WHEN MATCH(title) AGAINST('" + queryWithQuotes_filtered + "' IN BOOLEAN MODE) THEN 20 WHEN MATCH(body) AGAINST('" + queryWithQuotes_filtered + "' IN BOOLEAN MODE) OR MATCH(description) AGAINST('" + queryWithQuotes_filtered + "' IN BOOLEAN MODE) THEN 15 WHEN MATCH(title) AGAINST('" + reqwordQuery_filtered + "' IN BOOLEAN MODE) THEN 14 WHEN MATCH(title) AGAINST('" + querytouse_filtered + "' IN BOOLEAN MODE) THEN 13 END DESC, id DESC LIMIT " + repLimStr + " OFFSET " + repOffsetStr + ""
2023-03-25 03:27:14 +00:00
} else {
2023-09-23 18:18:28 +00:00
sqlQuery = "SELECT id FROM " + shard + " WHERE MATCH(tags, body, description, title, url) AGAINST('" + queryWithQuotesAndFlags_filtered + "' IN BOOLEAN MODE) AND enable = '1' " + additions + "ORDER BY CASE WHEN MATCH(tags) AGAINST('" + queryWithQuotesAndFlags_filtered + "' IN BOOLEAN MODE) THEN 30 " + isURL + " WHEN MATCH(title) AGAINST('" + queryWithQuotesAndFlags_filtered + "' IN BOOLEAN MODE) THEN 20 END DESC, id DESC LIMIT " + repLimStr + " OFFSET " + repOffsetStr + ""
2023-03-25 03:27:14 +00:00
}
2023-03-09 02:17:53 +00:00
}
2023-03-25 03:27:14 +00:00
go distributedQuery ( sqlString , sqlQuery , startID , endID , idListChans [ serverCount ] )
serverCount ++
2022-07-08 03:48:28 +00:00
}
2023-03-25 03:27:14 +00:00
}
for i := 0 ; i < serverCount ; i ++ {
//wait for channels to complete and collect results
idList += <- idListChans [ i ]
}
if len ( idList ) > 0 {
switch strings . Contains ( idList , "e" ) {
case true :
repsearchfail = 1
default :
idList = idList [ 1 : len ( idList ) ] //trim the first comma in the list
2023-03-09 02:17:53 +00:00
}
2023-03-25 03:27:14 +00:00
} else {
noresults = 1
2022-07-08 03:48:28 +00:00
}
2023-03-25 03:27:14 +00:00
//fmt.Printf("\nChan: %s",idList)
2022-07-08 03:48:28 +00:00
}
//init the db and set charset
//create SQL connection string
db , err := sql . Open ( "mysql" , "guest:qwer@/wiby?charset=utf8mb4" )
if err != nil {
p := indexPage { }
t , _ := template . ParseFiles ( "coreassets/error.html.go" )
t . Execute ( w , p )
}
defer db . Close ( )
2023-03-09 02:17:53 +00:00
// If Open doesn't open a connection. Validate DSN data:
2022-07-08 03:48:28 +00:00
err = db . Ping ( )
if err != nil {
error . Error = err . Error ( )
t , _ := template . ParseFiles ( "coreassets/error.html.go" )
t . Execute ( w , error )
}
count := 0
countResults := 0
2023-03-09 02:17:53 +00:00
var ids [ ] string
2023-03-25 03:27:14 +00:00
//if all went well with replication servers, send query to master containing idList and use the rangeOffset
if numServers == serverCount && numServers > 0 && repsearchfail == 0 {
2023-09-10 20:18:51 +00:00
sqlQuery = "SELECT id, url, title, description, body FROM windex WHERE id IN (" + idList + ") AND enable = '1' " + additions + "ORDER BY CASE WHEN LOCATE('" + queryNoQuotesOrFlags + "', tags) THEN 30 " + isURLlocate + " WHEN LOCATE('" + queryNoQuotesOrFlags + "', title) THEN 20 WHEN LOCATE('" + queryNoQuotesOrFlags + "', body) OR LOCATE('" + queryNoQuotesOrFlags + "', description) THEN 15" + partialLocate + " END DESC, id DESC LIMIT " + lim + " OFFSET " + strconv . Itoa ( rangeOffset ) + ""
2023-03-25 03:27:14 +00:00
} else { //else, if no replication servers or there was some sort of error, just search the database locally instead
2023-09-18 22:24:19 +00:00
if ( exactMatch == false && urlDetected == false && oneword == false && flagssetbyuser + wordcount != flagssetbyuser ) {
2023-09-29 23:00:32 +00:00
sqlQuery = "SELECT id, url, title, description, body FROM windex WHERE MATCH(tags, body, description, title, url) AGAINST('" + querytouse + "' IN BOOLEAN MODE) AND enable = '1' " + additions + "ORDER BY CASE WHEN MATCH(tags) AGAINST('" + queryWithQuotes + "' IN BOOLEAN MODE) THEN 30 " + isURL + " WHEN MATCH(title) AGAINST('" + queryWithQuotes + "' IN BOOLEAN MODE) THEN 20 WHEN MATCH(body) AGAINST('" + queryWithQuotes + "' IN BOOLEAN MODE) OR MATCH(description) AGAINST('" + queryWithQuotes + "' IN BOOLEAN MODE) THEN 15 WHEN MATCH(title) AGAINST('" + reqwordQuery + "' IN BOOLEAN MODE) THEN 14 WHEN MATCH(title) AGAINST('" + querytouse + "' IN BOOLEAN MODE) THEN 13 END DESC, id DESC LIMIT " + lim + " OFFSET " + offset + ""
2023-03-25 03:27:14 +00:00
} else {
2023-09-10 02:38:54 +00:00
if ( shards == false ) { //depricated
/*sqlQuery = "SELECT id, url, title, description, body FROM windex WHERE enable = '1' " + additions + "ORDER BY CASE WHEN MATCH(tags) AGAINST('" + queryWithQuotesAndFlags + "' IN BOOLEAN MODE) THEN 30 " + isURL + " WHEN MATCH(title) AGAINST('" + queryWithQuotesAndFlags + "' IN BOOLEAN MODE) THEN 20 WHEN MATCH(body) AGAINST('" + queryWithQuotesAndFlags + "' IN BOOLEAN MODE) THEN 19 WHEN MATCH(description) AGAINST('" + queryWithQuotesAndFlags + "' IN BOOLEAN MODE) THEN 15 WHEN MATCH(url) AGAINST('" + query + "' IN BOOLEAN MODE) THEN 0 END DESC, id DESC LIMIT " + lim + " OFFSET " + offset + ""*/
2023-04-22 05:33:13 +00:00
} else {
2023-09-10 02:38:54 +00:00
sqlQuery = "SELECT id, url, title, description, body FROM windex WHERE MATCH(tags, body, description, title, url) AGAINST('" + queryWithQuotesAndFlags + "' IN BOOLEAN MODE) AND enable = '1' " + additions + "ORDER BY CASE WHEN MATCH(tags) AGAINST('" + queryWithQuotesAndFlags + "' IN BOOLEAN MODE) THEN 30 " + isURL + " WHEN MATCH(title) AGAINST('" + queryWithQuotesAndFlags + "' IN BOOLEAN MODE) THEN 20 END DESC, id DESC LIMIT " + lim + " OFFSET " + offset + ""
2023-04-22 05:33:13 +00:00
}
2022-07-08 03:48:28 +00:00
}
2023-03-25 03:27:14 +00:00
}
2023-09-29 03:49:35 +00:00
//fmt.Printf("\n%s",sqlQuery)
2023-03-25 03:27:14 +00:00
switch noresults { //if noresults == 1, no results were found during search on active replication servers
case 0 :
// Send the query
rows , err := db . Query ( sqlQuery )
if err != nil {
fmt . Printf ( "\n%s" , err )
res . Page = strconv . Itoa ( 0 )
res . Query = m [ "q" ] [ 0 ] //get original unsafe query
if json {
w . Header ( ) . Set ( "Content-Type" , "application/json" )
t , _ := template . ParseFiles ( "coreassets/json/results.json.go" )
t . Execute ( w , res )
} else {
t , _ := template . ParseFiles ( "coreassets/results.html.go" )
t . Execute ( w , res )
2023-03-09 02:17:53 +00:00
}
2023-03-25 03:27:14 +00:00
//p := indexPage{}
//t, _ := template.ParseFiles("coreassets/form.html.go")
//t.Execute(w, p)
return
}
2022-07-08 03:48:28 +00:00
2023-03-25 03:27:14 +00:00
if urlDetected == true {
query = queryOriginal
}
2023-03-09 02:17:53 +00:00
2023-09-26 02:21:09 +00:00
wordtocheck := ""
stringtofind := strings . ToLower ( queryNoQuotesOrFlags )
stringtofind = strings . Replace ( stringtofind , "''" , "'" , - 1 )
requiredwordtofind := strings . ToLower ( requiredword )
requiredwordtofind = strings . Replace ( requiredwordtofind , "''" , "'" , - 1 )
longestWordtofind := strings . ToLower ( longestWord )
longestWordtofind = strings . Replace ( longestWordtofind , "''" , "'" , - 1 )
2023-03-25 03:27:14 +00:00
for rows . Next ( ) {
count ++
countResults ++
2023-03-09 02:17:53 +00:00
2023-03-25 03:27:14 +00:00
//this will get set if position of longest word of query is found within body
pos := - 1
2022-07-08 03:48:28 +00:00
2023-03-25 03:27:14 +00:00
err := rows . Scan ( & id , & url , & title , & description , & body )
if err != nil {
error . Error = err . Error ( )
t , _ := template . ParseFiles ( "coreassets/error.html.go" )
t . Execute ( w , error )
}
2023-03-09 02:17:53 +00:00
2023-03-25 03:27:14 +00:00
ids = append ( ids , id )
2023-03-09 02:17:53 +00:00
2023-03-25 03:27:14 +00:00
//find query inside body of page
2023-09-26 02:21:09 +00:00
if exactMatch == false && ( numRequiredWords == 0 || numRequiredWords + wordcount == numRequiredWords ) {
2023-03-25 03:27:14 +00:00
if len ( requiredword ) > 0 { //search for position of required word if any, else search for position of whole query
2023-09-26 02:21:09 +00:00
pos = strings . Index ( strings . ToLower ( body ) , requiredwordtofind )
2023-03-25 03:27:14 +00:00
} else if pos == - 1 {
2023-09-26 02:21:09 +00:00
pos = strings . Index ( strings . ToLower ( body ) , stringtofind )
2022-07-08 03:48:28 +00:00
}
2023-03-09 02:17:53 +00:00
2023-09-26 02:21:09 +00:00
if pos == - 1 { //not found? find position of longest query word
pos = strings . Index ( strings . ToLower ( body ) , longestWordtofind )
//not found?, set position to a different word
2023-03-25 03:27:14 +00:00
if pos == - 1 && wordcount > 1 {
if longestwordelementnum > 0 {
2023-09-26 02:21:09 +00:00
//wordtocheck = strings.Replace(words[0], "*", "", -1)
wordtocheck = strings . Replace ( words [ 0 ] , "''" , "'" , - 1 )
pos = strings . Index ( strings . ToLower ( body ) , strings . ToLower ( wordtocheck ) )
2023-03-25 03:27:14 +00:00
}
if longestwordelementnum == 0 {
2023-09-26 02:21:09 +00:00
//wordtocheck = strings.Replace(words[1], "*", "", -1)
wordtocheck = strings . Replace ( words [ 1 ] , "''" , "'" , - 1 )
pos = strings . Index ( strings . ToLower ( body ) , strings . ToLower ( wordtocheck ) )
2023-03-25 03:27:14 +00:00
}
2023-03-09 02:17:53 +00:00
}
}
2023-03-25 03:27:14 +00:00
} else { //if exact match, find position of query within body
2023-09-26 02:21:09 +00:00
pos = strings . Index ( strings . ToLower ( body ) , stringtofind )
2022-07-08 03:48:28 +00:00
}
2023-09-26 02:21:09 +00:00
2023-03-25 03:27:14 +00:00
//still not found?, set position to 0
if pos == - 1 {
pos = 0
2022-07-08 03:48:28 +00:00
}
2023-03-25 03:27:14 +00:00
//Adjust position for runes within body
pos = utf8 . RuneCountInString ( body [ : pos ] )
2022-07-08 03:48:28 +00:00
2023-03-25 03:27:14 +00:00
starttext := 0
//ballpark := 0
ballparktext := ""
2022-07-08 03:48:28 +00:00
2023-03-25 03:27:14 +00:00
//figure out how much preceding text to use
if pos < 32 {
starttext = 0
} else if pos > 25 {
starttext = pos - 25
} else if pos > 20 {
starttext = pos - 15
2023-03-09 02:17:53 +00:00
}
2022-07-08 03:48:28 +00:00
2023-03-25 03:27:14 +00:00
//total length of the ballpark
textlength := 180
2023-03-09 02:17:53 +00:00
2023-03-25 03:27:14 +00:00
//populate the ballpark
if pos >= 0 {
ballparktext = substr ( body , starttext , starttext + textlength )
} //else{ ballpark = 0}//looks unused
2023-03-09 02:17:53 +00:00
2023-03-25 03:27:14 +00:00
//find position of nearest Period
//foundPeriod := true
posPeriod := strings . Index ( ballparktext , ". " ) + starttext + 1
2023-03-09 02:17:53 +00:00
2023-03-25 03:27:14 +00:00
//find position of nearest Space
//foundSpace := true
posSpace := strings . Index ( ballparktext , " " ) + starttext
2023-03-09 02:17:53 +00:00
2023-03-25 03:27:14 +00:00
//if longest word in query is after a period+space within ballpark, reset starttext to that point
if ( pos - starttext ) > posPeriod {
starttext = posPeriod
//populate the bodymatch
if ( pos - starttext ) >= 0 {
body = substr ( body , starttext , starttext + textlength )
} else {
body = ""
2022-07-08 03:48:28 +00:00
}
2023-03-25 03:27:14 +00:00
} else if pos > posSpace { //else if longest word in query is after a space within ballpark, reset starttext to that point
//else if(pos-starttext) > posSpace//else if longest word in query is after a space within ballpark, reset starttext to that point
starttext = posSpace
//populate the bodymatch
if ( pos - starttext ) >= 0 {
body = substr ( body , starttext , starttext + textlength )
} else {
body = ""
2023-03-09 02:17:53 +00:00
}
2023-03-25 03:27:14 +00:00
} else //else just set the bodymatch to the ballparktext
{
//populate the bodymatch
if ( pos - starttext ) >= 0 {
body = ballparktext
} else {
body = ""
2023-03-09 02:17:53 +00:00
}
2022-07-08 03:48:28 +00:00
}
2023-03-25 03:27:14 +00:00
tRes . Id = id
tRes . Url = url
tRes . Title = html . UnescapeString ( title )
tRes . Description = html . UnescapeString ( description )
tRes . Body = html . UnescapeString ( body )
if json == true {
tRes . Title = JSONRealEscapeString ( tRes . Title )
tRes . Description = JSONRealEscapeString ( tRes . Description )
tRes . Body = JSONRealEscapeString ( tRes . Body )
2023-03-09 02:17:53 +00:00
}
2023-03-25 03:27:14 +00:00
res . DBResults = append ( res . DBResults , tRes )
}
defer rows . Close ( )
rows . Close ( )
if count > 0 { //new search method may cause less than the limit of row results per page even if there are more results to come, so we force a full count
count = limInt
}
} //end switch
2022-07-08 03:48:28 +00:00
//================================================================================================================================
2023-04-22 05:33:13 +00:00
//no results found (count==0), so do a wildcard search (repeat the above process) - this section will probably be removed, no longer useful
2022-07-08 03:48:28 +00:00
addWildcard := false
2023-09-10 02:38:54 +00:00
/ * if count == 0 && offset == "0" && urlDetected == false && exactMatch == false {
2023-03-25 03:27:14 +00:00
2022-07-08 03:48:28 +00:00
addWildcard = true
query = strings . Replace ( query , "\"" , "" , - 1 ) //remove some things innodb gets fussy over
query = strings . Replace ( query , "*" , "" , - 1 )
query = strings . Replace ( query , "'" , "" , - 1 )
2023-09-10 02:38:54 +00:00
queryNoQuotes = strings . Replace ( queryNoQuotes , "\"" , "" , - 1 )
queryNoQuotes = strings . Replace ( queryNoQuotes , "*" , "" , - 1 )
queryNoQuotes = strings . Replace ( queryNoQuotes , "'" , "" , - 1 )
2022-07-08 03:48:28 +00:00
query = query + "*"
2023-04-22 05:33:13 +00:00
if shards == false {
sqlQuery = "SELECT id, url, title, description, body FROM windex WHERE enable = '1' " + additions + "ORDER BY CASE WHEN MATCH(tags) AGAINST('" + query + "' IN BOOLEAN MODE) THEN 30 END DESC, id DESC LIMIT " + lim + " OFFSET " + offset + ""
} else {
sqlQuery = "SELECT id, url, title, description, body FROM windex WHERE Match(tags, body, description, title, url) Against('" + query + "' IN BOOLEAN MODE) AND enable = '1' " + additions + "ORDER BY CASE WHEN MATCH(tags) AGAINST('" + query + "' IN BOOLEAN MODE) THEN 30 END DESC, id DESC LIMIT " + lim + " OFFSET " + offset + ""
}
2022-07-08 03:48:28 +00:00
2023-03-25 03:27:14 +00:00
if repsearchfail == 0 && noservers == false {
2022-07-08 03:48:28 +00:00
serverCount = 0
idList = ""
for _ , server := range servers {
serverSettings := strings . Split ( server , "," )
if len ( serverSettings ) == 4 { //if line contains all 4 settings
//ip, database, startID, endID
//create SQL connection string //db, err := sql.Open("mysql", "remote_guest:d0gemuchw0w@tcp(10.8.0.102:3306)/wiby?charset=utf8mb4")
serverIP := serverSettings [ 0 ]
2023-03-20 06:13:12 +00:00
shard := serverSettings [ 1 ]
2022-07-08 03:48:28 +00:00
startID := serverSettings [ 2 ]
endID := serverSettings [ 3 ]
2023-03-20 06:13:12 +00:00
sqlString := "remote_guest:d0gemuchw0w@tcp(" + serverIP + ":3306)/wiby?charset=utf8mb4"
2022-07-08 03:48:28 +00:00
//fmt.Printf("%s %s %s %d\n",sqlString,startID,endID,numServers)
2023-03-20 06:13:12 +00:00
//send special distributed query, only need ID returned
2023-08-13 19:15:14 +00:00
if ( shards == false ) { //depricated
2023-04-22 05:33:13 +00:00
sqlQuery = "SELECT id FROM windex WHERE id BETWEEN " + startID + " AND " + endID + " AND enable = '1' " + additions + " ORDER BY CASE WHEN MATCH(tags) AGAINST('" + query + "' IN BOOLEAN MODE) THEN 30 END DESC, id DESC LIMIT " + repLimStr + " OFFSET " + repOffsetStr + ""
2023-03-25 03:27:14 +00:00
} else {
2023-04-22 05:33:13 +00:00
sqlQuery = "SELECT id FROM " + shard + " WHERE Match(tags, body, description, title, url) Against('" + query + "' IN BOOLEAN MODE) AND enable = '1' " + additions + "ORDER BY CASE WHEN MATCH(tags) AGAINST('" + query + "' IN BOOLEAN MODE) THEN 30 END DESC, id DESC LIMIT " + repLimStr + " OFFSET " + repOffsetStr + ""
2023-03-25 03:27:14 +00:00
}
2022-07-08 03:48:28 +00:00
go distributedQuery ( sqlString , sqlQuery , startID , endID , idListChans [ serverCount ] )
serverCount ++
}
}
for i := 0 ; i < serverCount ; i ++ {
//wait for channels to complete and collect results
idList += <- idListChans [ i ]
}
if len ( idList ) > 0 {
switch strings . Contains ( idList , "e" ) {
case true :
repsearchfail = 1
default :
idList = idList [ 1 : len ( idList ) ] //trim the first comma in the list
}
} else {
noresults = 1
}
2023-03-09 02:17:53 +00:00
//if all went well with replication servers, send query to local database containing idList and use the rangeOffset
2022-07-08 03:48:28 +00:00
if numServers == serverCount && numServers > 0 && repsearchfail == 0 {
2023-09-10 02:38:54 +00:00
sqlQuery = "SELECT id, url, title, description, body FROM windex WHERE id IN (" + idList + ") AND enable = '1' " + additions + "ORDER BY CASE WHEN LOCATE('" + queryNoQuotes + "', tags) THEN 30 END DESC, id DESC LIMIT " + lim + " OFFSET " + strconv . Itoa ( rangeOffset ) + ""
2023-03-09 02:17:53 +00:00
} else { //else, if no replication servers or there was some sort of error, search the whole local database instead
2023-04-22 05:33:13 +00:00
if shards == false {
sqlQuery = "SELECT id, url, title, description, body FROM windex WHERE enable = '1' " + additions + "ORDER BY CASE WHEN MATCH(tags) AGAINST('" + query + "' IN BOOLEAN MODE) THEN 30 END DESC, id DESC LIMIT " + lim + " OFFSET " + offset + ""
} else {
sqlQuery = "SELECT id, url, title, description, body FROM windex WHERE Match(tags, body, description, title, url) Against('" + query + "' IN BOOLEAN MODE) AND enable = '1' " + additions + "ORDER BY CASE WHEN MATCH(tags) AGAINST('" + query + "' IN BOOLEAN MODE) THEN 30 END DESC, id DESC LIMIT " + lim + " OFFSET " + offset + ""
}
2022-07-08 03:48:28 +00:00
}
}
2023-03-25 03:27:14 +00:00
rows2 , err := db . Query ( sqlQuery )
2022-07-08 03:48:28 +00:00
if err != nil {
2023-03-09 02:17:53 +00:00
res . Page = strconv . Itoa ( 0 )
2022-07-08 03:48:28 +00:00
res . Query = m [ "q" ] [ 0 ] //get original unsafe query
if json {
w . Header ( ) . Set ( "Content-Type" , "application/json" )
t , _ := template . ParseFiles ( "coreassets/json/results.json.go" )
t . Execute ( w , res )
} else {
t , _ := template . ParseFiles ( "coreassets/results.html.go" )
t . Execute ( w , res )
}
return
}
2023-09-26 02:21:09 +00:00
wordtocheck := ""
stringtofind := strings . ToLower ( queryNoQuotesOrFlags )
stringtofind = strings . Replace ( stringtofind , "''" , "'" , - 1 )
requiredwordtofind := strings . ToLower ( requiredword )
requiredwordtofind = strings . Replace ( requiredwordtofind , "''" , "'" , - 1 )
longestWordtofind := strings . ToLower ( longestWord )
longestWordtofind = strings . Replace ( longestWordtofind , "''" , "'" , - 1 )
2023-03-25 03:27:14 +00:00
for rows2 . Next ( ) {
2022-07-08 03:48:28 +00:00
count ++
//this will get set if position of longest word of query is found within body
pos := - 1
2023-03-25 03:27:14 +00:00
err := rows2 . Scan ( & id , & url , & title , & description , & body )
2022-07-08 03:48:28 +00:00
if err != nil {
error . Error = err . Error ( )
t , _ := template . ParseFiles ( "coreassets/error.html.go" )
t . Execute ( w , error )
}
//find query inside body of page
2023-09-26 02:21:09 +00:00
if exactMatch == false && ( numRequiredWords == 0 || numRequiredWords + wordcount == numRequiredWords ) {
2022-07-08 03:48:28 +00:00
if len ( requiredword ) > 0 { //search for position of required word if any, else search for position of whole query
2023-09-26 02:21:09 +00:00
pos = strings . Index ( strings . ToLower ( body ) , requiredwordtofind )
2022-07-08 03:48:28 +00:00
} else if pos == - 1 {
2023-09-26 02:21:09 +00:00
pos = strings . Index ( strings . ToLower ( body ) , stringtofind )
2022-07-08 03:48:28 +00:00
}
2023-09-26 02:21:09 +00:00
if pos == - 1 { //not found? find position of longest query word
pos = strings . Index ( strings . ToLower ( body ) , longestWordtofind )
//not found?, set position to a different word
2022-07-08 03:48:28 +00:00
if pos == - 1 && wordcount > 1 {
if longestwordelementnum > 0 {
2023-09-26 02:21:09 +00:00
//wordtocheck = strings.Replace(words[0], "*", "", -1)
wordtocheck = strings . Replace ( words [ 0 ] , "''" , "'" , - 1 )
pos = strings . Index ( strings . ToLower ( body ) , strings . ToLower ( wordtocheck ) )
2022-07-08 03:48:28 +00:00
}
if longestwordelementnum == 0 {
2023-09-26 02:21:09 +00:00
//wordtocheck = strings.Replace(words[1], "*", "", -1)
wordtocheck = strings . Replace ( words [ 1 ] , "''" , "'" , - 1 )
pos = strings . Index ( strings . ToLower ( body ) , strings . ToLower ( wordtocheck ) )
2022-07-08 03:48:28 +00:00
}
}
}
} else { //if exact match, find position of query within body
2023-09-26 02:21:09 +00:00
pos = strings . Index ( strings . ToLower ( body ) , stringtofind )
2022-07-08 03:48:28 +00:00
}
2023-09-26 02:21:09 +00:00
2022-07-08 03:48:28 +00:00
//still not found?, set position to 0
if pos == - 1 {
pos = 0
}
//Adjust position for runes within body
pos = utf8 . RuneCountInString ( body [ : pos ] )
starttext := 0
//ballpark := 0
ballparktext := ""
//figure out how much preceding text to use
if pos < 32 {
starttext = 0
} else if pos > 25 {
starttext = pos - 25
} else if pos > 20 {
starttext = pos - 15
}
//total length of the ballpark
textlength := 180
//populate the ballpark
if pos >= 0 {
ballparktext = substr ( body , starttext , starttext + textlength )
} //else{ ballpark = 0}//looks unused
//find position of nearest Period
//foundPeriod := true
posPeriod := strings . Index ( ballparktext , ". " ) + starttext + 1
//find position of nearest Space
//foundSpace := true
posSpace := strings . Index ( ballparktext , " " ) + starttext
//if longest word in query is after a period+space within ballpark, reset starttext to that point
if ( pos - starttext ) > posPeriod {
starttext = posPeriod
//populate the bodymatch
if ( pos - starttext ) >= 0 {
body = substr ( body , starttext , starttext + textlength )
} else {
body = ""
}
} else if pos > posSpace { //else if longest word in query is after a space within ballpark, reset starttext to that point
//else if(pos-starttext) > posSpace//else if longest word in query is after a space within ballpark, reset starttext to that point
starttext = posSpace
//populate the bodymatch
if ( pos - starttext ) >= 0 {
body = substr ( body , starttext , starttext + textlength )
} else {
body = ""
}
} else //else just set the bodymatch to the ballparktext
{
//populate the bodymatch
if ( pos - starttext ) >= 0 {
body = ballparktext
} else {
body = ""
}
}
tRes . Id = id
tRes . Url = url
tRes . Title = html . UnescapeString ( title )
tRes . Description = html . UnescapeString ( description )
tRes . Body = html . UnescapeString ( body )
if json == true {
tRes . Title = JSONRealEscapeString ( tRes . Title )
tRes . Description = JSONRealEscapeString ( tRes . Description )
tRes . Body = JSONRealEscapeString ( tRes . Body )
}
res . DBResults = append ( res . DBResults , tRes )
}
2023-03-25 03:27:14 +00:00
defer rows2 . Close ( )
rows2 . Close ( )
2023-09-10 02:38:54 +00:00
} * /
2022-07-08 03:48:28 +00:00
//=======================================================================================================================
//http://go-database-sql.org/retrieving.html
//Close DB
db . Close ( )
2023-03-09 02:17:53 +00:00
//allow the find more link
2023-03-25 03:27:14 +00:00
if ( countResults >= limInt || countResults > 2 ) && addWildcard == false {
2022-07-08 03:48:28 +00:00
res . FindMore = true
} else {
res . FindMore = false
}
2022-10-17 05:46:12 +00:00
2023-03-09 02:17:53 +00:00
if ( pageInt == 0 ) {
pageInt += 2
} else {
pageInt ++ ;
}
res . Page = strconv . Itoa ( pageInt )
2022-07-08 03:48:28 +00:00
res . Query = m [ "q" ] [ 0 ] //get original unsafe query
if json {
w . Header ( ) . Set ( "Content-Type" , "application/json" )
t , _ := template . ParseFiles ( "coreassets/json/results.json.go" )
t . Execute ( w , res )
} else {
t , _ := template . ParseFiles ( "coreassets/results.html.go" )
t . Execute ( w , res )
}
}
}
func settings ( w http . ResponseWriter , r * http . Request ) {
//setup for error report
error := errorReport { }
//check if worksafe (adult content) cookie enabled.
filterHTTPS := false
worksafe := true
worksafewasoff := false
worksafeHTTPSCookie , err := r . Cookie ( "ws" )
if err != nil {
worksafe = true
filterHTTPS = false
} else if worksafeHTTPSCookie . Value == "0" {
worksafe = false
filterHTTPS = false
worksafewasoff = true
} else if worksafeHTTPSCookie . Value == "1" {
worksafe = true
filterHTTPS = false
} else if worksafeHTTPSCookie . Value == "2" {
worksafe = false
filterHTTPS = true
worksafewasoff = true
} else if worksafeHTTPSCookie . Value == "3" {
worksafe = true
filterHTTPS = true
}
//check if and what is the user posting
switch r . Method {
case "POST" :
if err := r . ParseForm ( ) ; err != nil {
error . Error = err . Error ( )
t , _ := template . ParseFiles ( "coreassets/error.html.go" )
t . Execute ( w , error )
}
worksafebox := r . Form . Get ( "worksafe" )
agreecheck := r . Form . Get ( "agree" )
agreesubmit := r . Form . Get ( "agreesubmit" )
httpsbox := r . Form . Get ( "filterHTTPS" )
//if user agrees to terms to disable adult content, set cookie and return to index
if agreecheck == "on" {
worksafe = false
//expiration := time.Now().Add(365 * 24 * time.Hour)
if filterHTTPS == false {
cookie := http . Cookie { Name : "ws" , Value : "0" , Path : "/" }
http . SetCookie ( w , & cookie )
} else {
cookie := http . Cookie { Name : "ws" , Value : "2" , Path : "/" }
http . SetCookie ( w , & cookie )
}
p := indexPage { }
t , _ := template . ParseFiles ( "coreassets/settings/gohome.html" )
t . Execute ( w , p )
//else if worksafebox is checked, return to index with worksafe on
} else if worksafebox == "on" || agreesubmit == "on" {
//expiration := time.Now().Add(365 * 24 * time.Hour)
if httpsbox != "on" {
cookie := http . Cookie { Name : "ws" , Value : "1" , Path : "/" }
http . SetCookie ( w , & cookie )
} else {
cookie := http . Cookie { Name : "ws" , Value : "3" , Path : "/" }
http . SetCookie ( w , & cookie )
}
p := indexPage { }
t , _ := template . ParseFiles ( "coreassets/settings/gohome.html" )
t . Execute ( w , p )
//else if worksafebox unchecked and no cookie, go to content agreement section
} else if worksafebox != "on" && worksafewasoff == false && agreesubmit != "on" {
p := indexPage { }
if httpsbox == "on" {
cookie := http . Cookie { Name : "ws" , Value : "3" , Path : "/" }
http . SetCookie ( w , & cookie )
} else {
cookie := http . Cookie { Name : "ws" , Value : "1" , Path : "/" }
http . SetCookie ( w , & cookie )
}
t , _ := template . ParseFiles ( "coreassets/settings/agree.html.go" )
t . Execute ( w , p )
//else if worksafebox unchecked and cookie alredy agreed, go back to index
} else if worksafebox != "on" && worksafewasoff == true {
if httpsbox == "on" {
cookie := http . Cookie { Name : "ws" , Value : "2" , Path : "/" }
http . SetCookie ( w , & cookie )
} else {
cookie := http . Cookie { Name : "ws" , Value : "0" , Path : "/" }
http . SetCookie ( w , & cookie )
}
p := indexPage { }
t , _ := template . ParseFiles ( "coreassets/settings/gohome.html" )
t . Execute ( w , p )
}
default :
//load the settings page if no post value
settingspage := settingsPage { }
settingspage . Worksafe = worksafe
settingspage . FilterHTTPS = filterHTTPS
t , _ := template . ParseFiles ( "coreassets/settings/settings.html.go" )
t . Execute ( w , settingspage )
}
}
func surprise ( w http . ResponseWriter , r * http . Request ) {
surprise := surpriseURL { }
//check if worksafe+HTTPS cookie enabled.
filterHTTPS := false
worksafeHTTPSCookie , err := r . Cookie ( "ws" )
if err != nil {
filterHTTPS = false
} else if worksafeHTTPSCookie . Value == "2" {
filterHTTPS = true
} else if worksafeHTTPSCookie . Value == "3" {
filterHTTPS = true
}
//setup for error report
error := errorReport { }
//init the db and set charset
db , err := sql . Open ( "mysql" , "guest:qwer@/wiby?charset=utf8mb4" )
if err != nil {
error . Error = err . Error ( )
t , _ := template . ParseFiles ( "coreassets/error.html.go" )
t . Execute ( w , error )
}
defer db . Close ( )
// Open doesn't open a connection. Validate DSN data:
err = db . Ping ( )
if err != nil {
error . Error = err . Error ( )
t , _ := template . ParseFiles ( "coreassets/error.html.go" )
t . Execute ( w , error )
}
//grab a random page
var sqlQuery string
if filterHTTPS == false {
sqlQuery = "select url from windex where worksafe = 1 and surprise = 1 order by rand() limit 1"
} else {
sqlQuery = "select url from windex where worksafe = 1 and surprise = 1 and http = 1 order by rand() limit 1"
}
rows , err := db . Query ( sqlQuery )
if err != nil {
error . Error = err . Error ( )
t , _ := template . ParseFiles ( "coreassets/error.html.go" )
t . Execute ( w , error )
}
var url string
for rows . Next ( ) {
err := rows . Scan ( & url )
if err != nil {
error . Error = err . Error ( )
t , _ := template . ParseFiles ( "coreassets/error.html.go" )
t . Execute ( w , error )
}
surprise . Url = url
}
defer rows . Close ( )
rows . Close ( )
db . Close ( )
t , _ := template . ParseFiles ( "coreassets/surprise.html.go" )
t . Execute ( w , surprise )
}
func MysqlRealEscapeString ( value string ) string {
replace := map [ string ] string { "\\" : "\\\\" , "'" : ` \' ` , "\\0" : "\\\\0" , "\n" : "\\n" , "\r" : "\\r" , ` " ` : ` \" ` , "\x1a" : "\\Z" }
for b , a := range replace {
value = strings . Replace ( value , b , a , - 1 )
}
return value
}
func JSONRealEscapeString ( value string ) string {
replace := map [ string ] string { "\\" : "\\\\" , "\t" : "\\t" , "\b" : "\\b" , "\n" : "\\n" , "\r" : "\\r" , "\f" : "\\f" /*, `"`:`\"`*/ }
for b , a := range replace {
value = strings . Replace ( value , b , a , - 1 )
}
2022-10-09 03:22:38 +00:00
//remove control characters
buf := [ ] rune ( value )
for i , v := range buf {
if v < 32 || v == 127 {
buf [ i ] = 32
}
}
return string ( buf )
2022-07-08 03:48:28 +00:00
}
func substr ( s string , start int , end int ) string {
start_str_idx := 0
i := 0
for j := range s {
if i == start {
start_str_idx = j
}
if i == end {
return s [ start_str_idx : j ]
}
i ++
}
return s [ start_str_idx : ]
}
2023-09-29 03:49:35 +00:00
func checkformat ( query string ) string {
//Check if query contains a hyphenated word. Replace hyphens with a space, drop at hyphen if set as required word.
if strings . Contains ( query , "-" ) || strings . Contains ( query , "+" ) {
hyphenwords := strings . Split ( query , " " )
query = ""
quotes := 0
for i , word := range hyphenwords {
if strings . Contains ( word , "\"" ) {
quotes ++
}
if ( strings . Contains ( word , "-" ) || strings . Contains ( word , "+" ) ) && word [ 0 ] != '-' && word [ 0 ] != '+' && quotes % 2 == 0 { //if hyphen or plus exists, not a flag, not wrapped in quotes already
word = strings . Replace ( word , "-" , " " , - 1 )
} else if strings . Contains ( word , "-" ) && ( word [ 0 ] == '+' ) { //if hyphen exists and is a required word
word = strings . Replace ( word , "-" , " " , - 1 )
spos := strings . Index ( word , " " )
if spos != - 1 {
word = word [ : spos ]
}
if spos < 4 && spos > 0 {
word = ""
}
}
if len ( word ) > 1 && word [ 0 ] == '+' && len ( word ) < 4 {
word = word [ 1 : ]
}
if i > 0 {
query += " "
}
query += word
}
}
return query
}
2022-07-08 03:48:28 +00:00
func searchredirect ( w http . ResponseWriter , r * http . Request , query string ) {
//separate actual query from search redirect
actualquery := ""
redirect := ""
lenquery := len ( query )
if strings . Index ( query , " " ) > - 1 {
location := strings . Index ( query , " !" )
if location == - 1 {
location = strings . Index ( query , " &" )
}
if location > - 1 && strings . Index ( query [ location + 1 : lenquery ] , " " ) == - 1 { //redirect is at end of query
redirect = query [ location + 2 : lenquery ]
actualquery = query [ : location ]
} else if ( strings . Index ( query , "!" ) == 0 || strings . Index ( query , "&" ) == 0 ) { //redirect is at start of query
redirect = query [ 1 : strings . Index ( query , " " ) ]
actualquery = query [ strings . Index ( query , " " ) + 1 : ]
//fmt.Printf("\nRedirect: %s\nquery: %s\n",redirect,actualquery)
}
redirect = strings . ToLower ( redirect )
} else if ( query [ 0 ] == '!' || query [ 0 ] == '&' ) && lenquery > 1 {
redirect = query [ 1 : ]
}
if redirect != "" {
//determine which search engine to redirect
if redirect == "g" { //if google text search
http . Redirect ( w , r , "http://google.com/search?q=" + actualquery , http . StatusSeeOther )
} else if redirect == "b" { //if bing text search
http . Redirect ( w , r , "http://bing.com/search?q=" + actualquery , http . StatusSeeOther )
} else if redirect == "gi" { //if google image search
http . Redirect ( w , r , "http://www.google.com/search?tbm=isch&q=" + actualquery , http . StatusSeeOther )
} else if redirect == "bi" { //if bing image search
http . Redirect ( w , r , "http://www.bing.com/images/search?q=" + actualquery , http . StatusSeeOther )
} else if redirect == "gv" { //if google video search
http . Redirect ( w , r , "http://www.google.com/search?tbm=vid&q=" + actualquery , http . StatusSeeOther )
} else if redirect == "bv" { //if bing video search
http . Redirect ( w , r , "http://www.bing.com/videos/search?q=" + actualquery , http . StatusSeeOther )
} else if redirect == "gm" { //if google maps search
http . Redirect ( w , r , "http://www.google.com/maps/search/" + actualquery , http . StatusSeeOther )
} else if redirect == "bm" { //if bing maps search
http . Redirect ( w , r , "http://www.bing.com/maps?q=" + actualquery , http . StatusSeeOther )
} / * else {
http . Redirect ( w , r , "/?q=" + actualquery , http . StatusSeeOther )
} * /
}
}
func distributedQuery ( con string , sqlQuery string , startID string , endID string , idListChan chan <- string ) {
var id string
var idList string
count := 0
//defer wg.Done()
//init the db
db , err := sql . Open ( "mysql" , con )
if err != nil {
idList = idList + "e" //will look for this when channels are processed
}
defer db . Close ( )
// If Open doesn't open a connection. Validate DSN data:
err = db . Ping ( )
if err != nil {
}
2022-10-17 05:46:12 +00:00
//fmt.Printf("%s\n", sqlQuery)
2022-07-08 03:48:28 +00:00
// Send the query
rows , err := db . Query ( sqlQuery )
if err == nil {
for rows . Next ( ) {
err := rows . Scan ( & id )
if err != nil {
}
//idString = idstring + "id = " + id + " or "
idList += "," + id
count ++
}
} else {
idList = idList + "e" //will look for this when channels are processed
fmt . Printf ( "%s" , err )
}
2022-10-17 05:46:12 +00:00
//fmt.Printf("%s - %s\n", idList,con)
2022-07-08 03:48:28 +00:00
idListChan <- idList
}