2020-08-04 14:28:25 +08:00
package main
import (
"bufio"
2020-09-25 20:05:25 +08:00
"bytes"
2021-02-11 15:18:46 +08:00
"context"
2020-08-04 14:28:25 +08:00
"database/sql"
2021-01-07 18:32:17 +08:00
"flag"
2020-08-04 14:28:25 +08:00
"fmt"
"github.com/joho/godotenv"
"github.com/zhenorzz/goploy/core"
"github.com/zhenorzz/goploy/model"
"github.com/zhenorzz/goploy/route"
"github.com/zhenorzz/goploy/task"
"github.com/zhenorzz/goploy/utils"
"github.com/zhenorzz/goploy/ws"
2021-02-11 15:18:46 +08:00
"io/ioutil"
2020-08-04 14:28:25 +08:00
"log"
"net/http"
"os"
2020-09-25 20:05:25 +08:00
"os/exec"
2021-02-11 15:18:46 +08:00
"os/signal"
"path"
"strconv"
"syscall"
2020-08-04 14:28:25 +08:00
"time"
_ "github.com/go-sql-driver/mysql"
)
2021-01-07 18:32:17 +08:00
var (
help bool
2021-02-11 15:18:46 +08:00
s string
2021-01-07 18:32:17 +08:00
)
func init ( ) {
flag . StringVar ( & core . AssetDir , "asset-dir" , "" , "default: ./" )
2021-02-11 15:18:46 +08:00
flag . StringVar ( & s , "s" , "" , "stop" )
flag . BoolVar ( & help , "help" , false , "list available subcommands and some concept guides" )
2021-01-07 18:32:17 +08:00
// 改变默认的 Usage
flag . Usage = usage
}
func usage ( ) {
fmt . Fprintf ( os . Stderr , ` Options :
` )
flag . PrintDefaults ( )
}
2020-08-04 14:28:25 +08:00
func main ( ) {
2021-01-07 18:32:17 +08:00
flag . Parse ( )
if help {
flag . Usage ( )
return
}
2021-02-11 15:18:46 +08:00
handleClientSignal ( )
2020-08-15 13:38:06 +08:00
println ( `
______ __
/ ____ / ___ ____ / / ___ __ __
/ / __ / __ \ / __ \ / / __ \ / / / /
/ / _ / / / _ / / / _ / / / / _ / / / _ / /
\ ____ / \ ____ / . ___ / _ / \ ____ / \ __ , /
2021-02-11 15:18:46 +08:00
/ _ / / ____ / v1 .1 .6
2020-08-15 13:38:06 +08:00
` )
2020-08-15 16:35:00 +08:00
install ( )
2021-02-11 15:18:46 +08:00
pid := strconv . Itoa ( os . Getpid ( ) )
2021-01-07 18:32:17 +08:00
godotenv . Load ( core . GetEnvFile ( ) )
2021-02-11 15:18:46 +08:00
ioutil . WriteFile ( path . Join ( core . GetAssetDir ( ) , "goploy.pid" ) , [ ] byte ( pid ) , 0755 )
2021-01-13 17:12:40 +08:00
println ( "Start at " + time . Now ( ) . String ( ) )
2021-02-11 15:18:46 +08:00
println ( "current pid: " + pid )
2021-01-13 17:12:40 +08:00
println ( "Config Loaded: " + core . GetEnvFile ( ) )
println ( "Log: " + os . Getenv ( "LOG_PATH" ) )
println ( "Listen: " + os . Getenv ( "PORT" ) )
2021-02-11 15:18:46 +08:00
flag . Usage ( )
2021-01-13 17:12:40 +08:00
println ( "Running..." )
2020-08-04 14:28:25 +08:00
core . CreateValidator ( )
model . Init ( )
ws . Init ( )
route . Init ( )
task . Init ( )
2021-02-11 15:18:46 +08:00
// server
srv := http . Server {
Addr : ":" + os . Getenv ( "PORT" ) ,
}
2021-02-12 11:48:36 +08:00
core . Gwg . Add ( 1 )
2021-02-11 15:18:46 +08:00
go func ( ) {
2021-02-12 11:48:36 +08:00
defer core . Gwg . Done ( )
2021-02-11 15:18:46 +08:00
c := make ( chan os . Signal , 1 )
signal . Notify ( c , os . Interrupt , syscall . SIGTERM )
println ( "Received the signal: " + ( <- c ) . String ( ) )
println ( "Server is trying to shutdown, wait for a minute" )
ctx , cancel := context . WithTimeout ( context . Background ( ) , 10 * time . Second )
defer cancel ( )
if err := srv . Shutdown ( ctx ) ; err != nil {
println ( "Server shutdown failed, err: %v\n" , err )
}
println ( "Server shutdown gracefully" )
2021-02-12 10:47:16 +08:00
println ( "Task is trying to shutdown, wait for a minute" )
if err := task . Shutdown ( ctx ) ; err != nil {
println ( "Task shutdown failed, err: %v\n" , err )
}
println ( "Task shutdown gracefully" )
2021-02-11 15:18:46 +08:00
} ( )
err := srv . ListenAndServe ( )
if err != nil && err != http . ErrServerClosed {
log . Fatal ( "ListenAndServe: " , err . Error ( ) )
}
os . Remove ( path . Join ( core . GetAssetDir ( ) , "goploy.pid" ) )
2021-02-12 11:48:36 +08:00
println ( "Goroutine is trying to shutdown, wait for a minute" )
core . Gwg . Wait ( )
println ( "Goroutine shutdown gracefully" )
println ( "Success" )
2021-02-11 15:18:46 +08:00
return
2020-08-04 14:28:25 +08:00
}
func install ( ) {
2021-01-07 18:32:17 +08:00
_ , err := os . Stat ( core . GetEnvFile ( ) )
2020-08-04 14:28:25 +08:00
if err == nil || os . IsExist ( err ) {
2021-01-13 17:12:40 +08:00
println ( "The configuration file already exists, no need to reinstall (if you need to reinstall, please back up the database `goploy` first, delete the .env file, then restart.)" )
2020-08-04 14:28:25 +08:00
return
}
2021-01-13 17:12:40 +08:00
println ( "Installation guide ↓" )
2020-09-25 20:05:25 +08:00
var stdout bytes . Buffer
var stderr bytes . Buffer
cmd := exec . Command ( "rsync" , "--version" )
cmd . Stdout = & stdout
cmd . Stderr = & stderr
if err := cmd . Run ( ) ; err != nil {
println ( err . Error ( ) + ", detail: " + stderr . String ( ) )
panic ( "Please check if rsync is installed correctly, see https://rsync.samba.org/download.html" )
}
git := utils . GIT { }
if err := git . Run ( "--version" ) ; err != nil {
println ( err . Error ( ) + ", detail: " + git . Err . String ( ) )
panic ( "Please check if git is installed correctly, see https://git-scm.com/downloads" )
}
2020-08-04 14:28:25 +08:00
inputReader := bufio . NewReader ( os . Stdin )
2020-08-15 13:38:06 +08:00
println ( "Installation guidelines (Enter to confirm input)" )
println ( "Please enter the mysql user:" )
2020-08-04 14:28:25 +08:00
mysqlUser , err := inputReader . ReadString ( '\n' )
if err != nil {
panic ( "There were errors reading, exiting program." )
}
mysqlUser = utils . ClearNewline ( mysqlUser )
2020-08-15 13:38:06 +08:00
println ( "Please enter the mysql password:" )
2020-08-04 14:28:25 +08:00
mysqlPassword , err := inputReader . ReadString ( '\n' )
if err != nil {
panic ( "There were errors reading, exiting program." )
}
mysqlPassword = utils . ClearNewline ( mysqlPassword )
if len ( mysqlPassword ) != 0 {
mysqlPassword = ":" + mysqlPassword
}
2020-08-15 13:38:06 +08:00
println ( "Please enter the mysql host(default 127.0.0.1, without port):" )
2020-08-04 14:28:25 +08:00
mysqlHost , err := inputReader . ReadString ( '\n' )
if err != nil {
panic ( "There were errors reading, exiting program." )
}
mysqlHost = utils . ClearNewline ( mysqlHost )
if len ( mysqlHost ) == 0 {
mysqlHost = "127.0.0.1"
}
2020-08-15 13:38:06 +08:00
println ( "Please enter the mysql port(default 3306):" )
2020-08-04 14:28:25 +08:00
mysqlPort , err := inputReader . ReadString ( '\n' )
if err != nil {
panic ( "There were errors reading, exiting program." )
}
mysqlPort = utils . ClearNewline ( mysqlPort )
if len ( mysqlPort ) == 0 {
mysqlPort = "3306"
}
2020-08-15 13:38:06 +08:00
println ( "Please enter the absolute path of the log directory(default /tmp/):" )
2020-08-04 14:28:25 +08:00
logPath , err := inputReader . ReadString ( '\n' )
if err != nil {
panic ( "There were errors reading, exiting program." )
}
logPath = utils . ClearNewline ( logPath )
if len ( logPath ) == 0 {
logPath = "/tmp/"
}
2020-08-15 13:38:06 +08:00
println ( "Please enter the listening port(default 80):" )
2020-08-04 14:28:25 +08:00
port , err := inputReader . ReadString ( '\n' )
if err != nil {
panic ( "There were errors reading, exiting program." )
}
port = utils . ClearNewline ( port )
if len ( port ) == 0 {
port = "80"
}
2020-08-15 13:38:06 +08:00
println ( "Start to install the database..." )
2020-08-04 14:28:25 +08:00
db , err := sql . Open ( "mysql" , fmt . Sprintf (
"%s%s@tcp(%s:%s)/?charset=utf8mb4,utf8\n" ,
mysqlUser ,
mysqlPassword ,
mysqlHost ,
mysqlPort ) )
if err != nil {
panic ( err )
}
defer db . Close ( )
if err := model . ImportSQL ( db ) ; err != nil {
panic ( err )
}
2020-08-15 13:38:06 +08:00
println ( "Database installation is complete" )
2020-08-04 14:28:25 +08:00
envContent := ""
envContent += "DB_TYPE=mysql\n"
envContent += fmt . Sprintf (
"DB_CONN=%s%s@tcp(%s:%s)/goploy?charset=utf8mb4,utf8\n" ,
mysqlUser ,
mysqlPassword ,
mysqlHost ,
mysqlPort )
envContent += fmt . Sprintf ( "SIGN_KEY=%d\n" , time . Now ( ) . Unix ( ) )
envContent += fmt . Sprintf ( "LOG_PATH=%s\n" , logPath )
envContent += "ENV=production\n"
envContent += fmt . Sprintf ( "PORT=%s\n" , port )
2020-08-15 13:38:06 +08:00
println ( "Start writing configuration file..." )
2021-01-07 18:32:17 +08:00
file , err := os . Create ( core . GetEnvFile ( ) )
2020-08-04 14:28:25 +08:00
if err != nil {
panic ( err )
}
defer file . Close ( )
file . WriteString ( envContent )
2020-08-15 13:38:06 +08:00
println ( "Write configuration file completed" )
2020-08-04 14:28:25 +08:00
}
2021-02-11 15:18:46 +08:00
func handleClientSignal ( ) {
switch s {
case "stop" :
pidStr , err := ioutil . ReadFile ( path . Join ( core . GetAssetDir ( ) , "goploy.pid" ) )
if err != nil {
log . Fatal ( "handle stop, " , err . Error ( ) , ", may be the server not start" )
}
pid , _ := strconv . Atoi ( string ( pidStr ) )
process , err := os . FindProcess ( pid )
if err != nil {
log . Fatal ( "handle stop, " , err . Error ( ) , ", may be the server not start" )
}
err = process . Signal ( syscall . SIGTERM )
if err != nil {
log . Fatal ( "handle stop, " , err . Error ( ) )
}
os . Exit ( 1 )
}
}