2017-09-03 04:50:31 +00:00
/ *
*
* Gosora MySQL Interface
2019-02-23 06:55:34 +00:00
* Copyright Azareal 2017 - 2020
2017-09-03 04:50:31 +00:00
*
* /
2017-10-14 07:39:22 +00:00
package install
2017-07-12 11:05:18 +00:00
import (
"bytes"
2017-09-03 04:50:31 +00:00
"database/sql"
"fmt"
2019-05-06 04:04:00 +00:00
"os"
2017-07-12 11:05:18 +00:00
"io/ioutil"
"path/filepath"
2017-09-03 04:50:31 +00:00
"strconv"
"strings"
2019-05-06 04:04:00 +00:00
"sync"
2017-08-13 11:22:34 +00:00
2018-10-27 03:21:02 +00:00
"github.com/Azareal/Gosora/query_gen"
2017-07-12 11:05:18 +00:00
_ "github.com/go-sql-driver/mysql"
)
2017-09-03 04:50:31 +00:00
//var dbCollation string = "utf8mb4_general_ci"
2017-07-12 11:05:18 +00:00
2017-10-14 07:39:22 +00:00
func init ( ) {
adapters [ "mysql" ] = & MysqlInstaller { dbHost : "" }
2017-07-12 11:05:18 +00:00
}
2017-10-14 07:39:22 +00:00
type MysqlInstaller struct {
db * sql . DB
dbHost string
dbUsername string
dbPassword string
dbName string
dbPort string
}
func ( ins * MysqlInstaller ) SetConfig ( dbHost string , dbUsername string , dbPassword string , dbName string , dbPort string ) {
ins . dbHost = dbHost
ins . dbUsername = dbUsername
ins . dbPassword = dbPassword
ins . dbName = dbName
ins . dbPort = dbPort
}
func ( ins * MysqlInstaller ) Name ( ) string {
return "mysql"
}
func ( ins * MysqlInstaller ) DefaultPort ( ) string {
return "3306"
}
2017-11-13 05:22:37 +00:00
func ( ins * MysqlInstaller ) dbExists ( dbName string ) ( bool , error ) {
var waste string
err := ins . db . QueryRow ( "SHOW DATABASES LIKE '" + dbName + "'" ) . Scan ( & waste )
if err != nil && err != sql . ErrNoRows {
return false , err
} else if err == sql . ErrNoRows {
return false , nil
}
return true , nil
}
2017-10-14 07:39:22 +00:00
func ( ins * MysqlInstaller ) InitDatabase ( ) ( err error ) {
_dbPassword := ins . dbPassword
2017-09-03 04:50:31 +00:00
if _dbPassword != "" {
_dbPassword = ":" + _dbPassword
2017-07-12 11:05:18 +00:00
}
2017-10-14 07:39:22 +00:00
db , err := sql . Open ( "mysql" , ins . dbUsername + _dbPassword + "@tcp(" + ins . dbHost + ":" + ins . dbPort + ")/" )
2017-07-12 11:05:18 +00:00
if err != nil {
return err
}
// Make sure that the connection is alive..
err = db . Ping ( )
if err != nil {
return err
}
fmt . Println ( "Successfully connected to the database" )
2017-08-13 11:22:34 +00:00
2017-11-13 05:22:37 +00:00
ins . db = db
ok , err := ins . dbExists ( ins . dbName )
if err != nil {
2017-07-12 11:05:18 +00:00
return err
}
2017-11-13 05:22:37 +00:00
if ! ok {
2017-07-12 11:05:18 +00:00
fmt . Println ( "Unable to find the database. Attempting to create it" )
2017-10-14 07:39:22 +00:00
_ , err = db . Exec ( "CREATE DATABASE IF NOT EXISTS " + ins . dbName )
2017-07-12 11:05:18 +00:00
if err != nil {
return err
}
fmt . Println ( "The database was successfully created" )
}
2019-05-06 04:04:00 +00:00
/ * fmt . Println ( "Switching to database " , ins . dbName )
2017-10-14 07:39:22 +00:00
_ , err = db . Exec ( "USE " + ins . dbName )
2019-05-06 04:04:00 +00:00
if err != nil {
return err
} * /
db . Close ( )
db , err = sql . Open ( "mysql" , ins . dbUsername + _dbPassword + "@tcp(" + ins . dbHost + ":" + ins . dbPort + ")/" + ins . dbName )
2017-07-12 11:05:18 +00:00
if err != nil {
return err
}
2017-08-13 11:22:34 +00:00
2019-05-06 04:04:00 +00:00
// Make sure that the connection is alive..
err = db . Ping ( )
if err != nil {
return err
}
fmt . Println ( "Successfully connected to the database" )
2019-05-08 07:36:47 +00:00
_ , err = db . Exec ( "SET FOREIGN_KEY_CHECKS = 0;" )
if err != nil {
return err
}
2017-07-12 11:05:18 +00:00
// Ready the query builder
2019-05-06 04:04:00 +00:00
ins . db = db
2017-07-12 11:05:18 +00:00
qgen . Builder . SetConn ( db )
2017-11-13 05:22:37 +00:00
return qgen . Builder . SetAdapter ( "mysql" )
2017-07-12 11:05:18 +00:00
}
2019-05-06 04:04:00 +00:00
func ( ins * MysqlInstaller ) createTable ( f os . FileInfo ) error {
table := strings . TrimPrefix ( f . Name ( ) , "query_" )
ext := filepath . Ext ( table )
if ext != ".sql" {
return nil
}
table = strings . TrimSuffix ( table , ext )
// ? - This is mainly here for tests, although it might allow the installer to overwrite a production database, so we might want to proceed with caution
q := "DROP TABLE IF EXISTS `" + table + "`;"
_ , err := ins . db . Exec ( q )
if err != nil {
fmt . Println ( "Failed query:" , q )
fmt . Println ( "e:" , err )
return err
}
data , err := ioutil . ReadFile ( "./schema/mysql/" + f . Name ( ) )
if err != nil {
return err
}
data = bytes . TrimSpace ( data )
_ , err = ins . db . Exec ( string ( data ) )
if err != nil {
fmt . Println ( "Failed query:" , string ( data ) )
fmt . Println ( "e:" , err )
return err
}
fmt . Printf ( "Created table '%s'\n" , table )
return nil
}
2017-10-21 00:27:47 +00:00
func ( ins * MysqlInstaller ) TableDefs ( ) ( err error ) {
2018-04-23 21:08:31 +00:00
fmt . Println ( "Creating the tables" )
2019-05-06 04:04:00 +00:00
files , err := ioutil . ReadDir ( "./schema/mysql/" )
if err != nil {
return err
}
// TODO: Can we reduce the amount of boilerplate here?
after := [ ] string { "activity_stream_matches" }
c1 := make ( chan os . FileInfo )
c2 := make ( chan os . FileInfo )
e := make ( chan error )
var wg sync . WaitGroup
r := func ( c chan os . FileInfo ) {
wg . Add ( 1 )
for f := range c {
err := ins . createTable ( f )
if err != nil {
e <- err
}
}
wg . Done ( )
}
go r ( c1 )
go r ( c2 )
var a [ ] os . FileInfo
Outer :
for i , f := range files {
2017-09-03 04:50:31 +00:00
if ! strings . HasPrefix ( f . Name ( ) , "query_" ) {
2017-07-12 11:05:18 +00:00
continue
}
2019-05-06 04:04:00 +00:00
table := strings . TrimPrefix ( f . Name ( ) , "query_" )
ext := filepath . Ext ( table )
2017-07-12 11:05:18 +00:00
if ext != ".sql" {
continue
}
2017-09-03 04:50:31 +00:00
table = strings . TrimSuffix ( table , ext )
2019-05-06 04:04:00 +00:00
for _ , tbl := range after {
if tbl == table {
a = append ( a , f )
continue Outer
}
2017-10-21 00:27:47 +00:00
}
2019-05-06 04:04:00 +00:00
if i % 2 == 0 {
c1 <- f
} else {
c2 <- f
}
}
close ( c1 )
close ( c2 )
wg . Wait ( )
close ( e )
var first error
for err := range e {
if first == nil {
first = err
2017-07-12 11:05:18 +00:00
}
2019-05-06 04:04:00 +00:00
}
if first != nil {
return first
}
2017-08-13 11:22:34 +00:00
2019-05-06 04:04:00 +00:00
for _ , f := range a {
if ! strings . HasPrefix ( f . Name ( ) , "query_" ) {
continue
}
err := ins . createTable ( f )
2017-07-12 11:05:18 +00:00
if err != nil {
return err
}
}
2019-05-06 04:04:00 +00:00
2019-05-08 07:36:47 +00:00
_ , err = ins . db . Exec ( "SET FOREIGN_KEY_CHECKS = 1;" )
return err
2017-07-12 11:05:18 +00:00
}
2017-09-22 05:36:15 +00:00
// ? - Moved this here since it was breaking the installer, we need to add this at some point
/* TODO: Implement the html-attribute setting type before deploying this */
/*INSERT INTO settings(`name`,`content`,`type`) VALUES ('meta_desc','','html-attribute');*/
2017-10-14 07:39:22 +00:00
func ( ins * MysqlInstaller ) InitialData ( ) error {
2018-04-23 21:08:31 +00:00
fmt . Println ( "Seeding the tables" )
2017-07-12 11:05:18 +00:00
data , err := ioutil . ReadFile ( "./schema/mysql/inserts.sql" )
if err != nil {
return err
}
data = bytes . TrimSpace ( data )
2017-08-13 11:22:34 +00:00
2017-10-14 07:39:22 +00:00
statements := bytes . Split ( data , [ ] byte ( ";" ) )
2018-04-23 21:08:31 +00:00
for key , sBytes := range statements {
statement := string ( sBytes )
if statement == "" {
2017-07-12 11:05:18 +00:00
continue
}
2018-04-23 21:08:31 +00:00
statement += ";"
2017-07-12 11:05:18 +00:00
2018-04-23 21:08:31 +00:00
fmt . Println ( "Executing query #" + strconv . Itoa ( key ) + " " + statement )
_ , err = ins . db . Exec ( statement )
2017-07-12 11:05:18 +00:00
if err != nil {
return err
}
}
return nil
}
2017-10-14 07:39:22 +00:00
func ( ins * MysqlInstaller ) CreateAdmin ( ) error {
return createAdmin ( )
}
func ( ins * MysqlInstaller ) DBHost ( ) string {
return ins . dbHost
}
func ( ins * MysqlInstaller ) DBUsername ( ) string {
return ins . dbUsername
}
func ( ins * MysqlInstaller ) DBPassword ( ) string {
return ins . dbPassword
}
func ( ins * MysqlInstaller ) DBName ( ) string {
return ins . dbName
}
func ( ins * MysqlInstaller ) DBPort ( ) string {
return ins . dbPort
}