github.com/Azareal/Gosora@v0.0.0-20210729070923-553e66b59003/cmd/elasticsearch/setup.go (about)

     1  // Work in progress
     2  package main
     3  
     4  import (
     5  	"context"
     6  	"database/sql"
     7  	"encoding/json"
     8  	"errors"
     9  	"log"
    10  	"os"
    11  	"strconv"
    12  
    13  	c "github.com/Azareal/Gosora/common"
    14  	"github.com/Azareal/Gosora/query_gen"
    15  	"gopkg.in/olivere/elastic.v6"
    16  )
    17  
    18  func main() {
    19  	log.Print("Loading the configuration data")
    20  	err := c.LoadConfig()
    21  	if err != nil {
    22  		log.Fatal(err)
    23  	}
    24  
    25  	log.Print("Processing configuration data")
    26  	err = c.ProcessConfig()
    27  	if err != nil {
    28  		log.Fatal(err)
    29  	}
    30  
    31  	if c.DbConfig.Adapter != "mysql" && c.DbConfig.Adapter != "" {
    32  		log.Fatal("Only MySQL is supported for upgrades right now, please wait for a newer build of the patcher")
    33  	}
    34  
    35  	err = prepMySQL()
    36  	if err != nil {
    37  		log.Fatal(err)
    38  	}
    39  
    40  	client, err := elastic.NewClient(elastic.SetErrorLog(log.New(os.Stdout, "ES ", log.LstdFlags)))
    41  	if err != nil {
    42  		log.Fatal(err)
    43  	}
    44  	_, _, err = client.Ping("http://127.0.0.1:9200").Do(context.Background())
    45  	if err != nil {
    46  		log.Fatal(err)
    47  	}
    48  
    49  	err = setupIndices(client)
    50  	if err != nil {
    51  		log.Fatal(err)
    52  	}
    53  
    54  	err = setupData(client)
    55  	if err != nil {
    56  		log.Fatal(err)
    57  	}
    58  }
    59  
    60  func prepMySQL() error {
    61  	return qgen.Builder.Init("mysql", map[string]string{
    62  		"host":      c.DbConfig.Host,
    63  		"port":      c.DbConfig.Port,
    64  		"name":      c.DbConfig.Dbname,
    65  		"username":  c.DbConfig.Username,
    66  		"password":  c.DbConfig.Password,
    67  		"collation": "utf8mb4_general_ci",
    68  	})
    69  }
    70  
    71  type ESIndexBase struct {
    72  	Mappings ESIndexMappings `json:"mappings"`
    73  }
    74  
    75  type ESIndexMappings struct {
    76  	Doc ESIndexDoc `json:"_doc"`
    77  }
    78  
    79  type ESIndexDoc struct {
    80  	Properties map[string]map[string]string `json:"properties"`
    81  }
    82  
    83  type ESDocMap map[string]map[string]string
    84  
    85  func (d ESDocMap) Add(column string, cType string) {
    86  	d["column"] = map[string]string{"type": cType}
    87  }
    88  
    89  func setupIndices(client *elastic.Client) error {
    90  	exists, err := client.IndexExists("topics").Do(context.Background())
    91  	if err != nil {
    92  		return err
    93  	}
    94  	if exists {
    95  		deleteIndex, err := client.DeleteIndex("topics").Do(context.Background())
    96  		if err != nil {
    97  			return err
    98  		}
    99  		if !deleteIndex.Acknowledged {
   100  			return errors.New("delete not acknowledged")
   101  		}
   102  	}
   103  
   104  	docMap := make(ESDocMap)
   105  	docMap.Add("tid", "integer")
   106  	docMap.Add("title", "text")
   107  	docMap.Add("content", "text")
   108  	docMap.Add("createdBy", "integer")
   109  	docMap.Add("ip", "ip")
   110  	docMap.Add("suggest", "completion")
   111  	indexBase := ESIndexBase{ESIndexMappings{ESIndexDoc{docMap}}}
   112  	oBytes, err := json.Marshal(indexBase)
   113  	if err != nil {
   114  		return err
   115  	}
   116  	createIndex, err := client.CreateIndex("topics").Body(string(oBytes)).Do(context.Background())
   117  	if err != nil {
   118  		return err
   119  	}
   120  	if !createIndex.Acknowledged {
   121  		return errors.New("not acknowledged")
   122  	}
   123  
   124  	exists, err = client.IndexExists("replies").Do(context.Background())
   125  	if err != nil {
   126  		return err
   127  	}
   128  	if exists {
   129  		deleteIndex, err := client.DeleteIndex("replies").Do(context.Background())
   130  		if err != nil {
   131  			return err
   132  		}
   133  		if !deleteIndex.Acknowledged {
   134  			return errors.New("delete not acknowledged")
   135  		}
   136  	}
   137  
   138  	docMap = make(ESDocMap)
   139  	docMap.Add("rid", "integer")
   140  	docMap.Add("tid", "integer")
   141  	docMap.Add("content", "text")
   142  	docMap.Add("createdBy", "integer")
   143  	docMap.Add("ip", "ip")
   144  	docMap.Add("suggest", "completion")
   145  	indexBase = ESIndexBase{ESIndexMappings{ESIndexDoc{docMap}}}
   146  	oBytes, err = json.Marshal(indexBase)
   147  	if err != nil {
   148  		return err
   149  	}
   150  	createIndex, err = client.CreateIndex("replies").Body(string(oBytes)).Do(context.Background())
   151  	if err != nil {
   152  		return err
   153  	}
   154  	if !createIndex.Acknowledged {
   155  		return errors.New("not acknowledged")
   156  	}
   157  
   158  	return nil
   159  }
   160  
   161  type ESTopic struct {
   162  	ID        int    `json:"tid"`
   163  	Title     string `json:"title"`
   164  	Content   string `json:"content"`
   165  	CreatedBy int    `json:"createdBy"`
   166  	IP string `json:"ip"`
   167  }
   168  
   169  type ESReply struct {
   170  	ID        int    `json:"rid"`
   171  	TID       int    `json:"tid"`
   172  	Content   string `json:"content"`
   173  	CreatedBy int    `json:"createdBy"`
   174  	IP string `json:"ip"`
   175  }
   176  
   177  func setupData(client *elastic.Client) error {
   178  	tcount := 4
   179  	errs := make(chan error)
   180  
   181  	go func() {
   182  		tin := make([]chan ESTopic, tcount)
   183  		tf := func(tin chan ESTopic) {
   184  			for {
   185  				topic, more := <-tin
   186  				if !more {
   187  					break
   188  				}
   189  				_, err := client.Index().Index("topics").Type("_doc").Id(strconv.Itoa(topic.ID)).BodyJson(topic).Do(context.Background())
   190  				if err != nil {
   191  					errs <- err
   192  				}
   193  			}
   194  		}
   195  		for i := 0; i < 4; i++ {
   196  			go tf(tin[i])
   197  		}
   198  
   199  		oi := 0
   200  		err := qgen.NewAcc().Select("topics").Cols("tid,title,content,createdBy,ip").Each(func(rows *sql.Rows) error {
   201  			t := ESTopic{}
   202  			err := rows.Scan(&t.ID, &t.Title, &t.Content, &t.CreatedBy, &t.IP)
   203  			if err != nil {
   204  				return err
   205  			}
   206  			tin[oi] <- t
   207  			if oi < 3 {
   208  				oi++
   209  			}
   210  			return nil
   211  		})
   212  		for i := 0; i < 4; i++ {
   213  			close(tin[i])
   214  		}
   215  		errs <- err
   216  	}()
   217  
   218  	go func() {
   219  		rin := make([]chan ESReply, tcount)
   220  		rf := func(rin chan ESReply) {
   221  			for {
   222  				reply, more := <-rin
   223  				if !more {
   224  					break
   225  				}
   226  				_, err := client.Index().Index("replies").Type("_doc").Id(strconv.Itoa(reply.ID)).BodyJson(reply).Do(context.Background())
   227  				if err != nil {
   228  					errs <- err
   229  				}
   230  			}
   231  		}
   232  		for i := 0; i < 4; i++ {
   233  			rf(rin[i])
   234  		}
   235  		oi := 0
   236  		err := qgen.NewAcc().Select("replies").Cols("rid,tid,content,createdBy,ip").Each(func(rows *sql.Rows) error {
   237  			r := ESReply{}
   238  			err := rows.Scan(&r.ID, &r.TID, &r.Content, &r.CreatedBy, &r.IP)
   239  			if err != nil {
   240  				return err
   241  			}
   242  			rin[oi] <- r
   243  			if oi < 3 {
   244  				oi++
   245  			}
   246  			return nil
   247  		})
   248  		for i := 0; i < 4; i++ {
   249  			close(rin[i])
   250  		}
   251  		errs <- err
   252  	}()
   253  
   254  	fin := 0
   255  	for {
   256  		err := <-errs
   257  		if err == nil {
   258  			fin++
   259  			if fin == 2 {
   260  				return nil
   261  			}
   262  		} else {
   263  			return err
   264  		}
   265  	}
   266  }