mirror of
https://github.com/openimsdk/open-im-server.git
synced 2025-11-05 11:52:10 +08:00
Optimize Docker configuration and script.
This commit is contained in:
parent
b1bc8324fb
commit
551dbb2a09
@ -25,4 +25,5 @@ func main() {
|
||||
if err := cmd.NewApiCmd().Exec(); err != nil {
|
||||
program.ExitWithError(err)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -60,4 +60,5 @@ func listenOnPort(port int) {
|
||||
// Normally, you would accept connections with l.Accept() in a loop here.
|
||||
// For this example, just sleep indefinitely to simulate a service.
|
||||
select {}
|
||||
|
||||
}
|
||||
|
||||
4
go.mod
4
go.mod
@ -15,7 +15,7 @@ require (
|
||||
github.com/mitchellh/mapstructure v1.5.0
|
||||
github.com/openimsdk/localcache v0.0.1
|
||||
github.com/openimsdk/protocol v0.0.60
|
||||
github.com/openimsdk/tools v0.0.47-alpha.16
|
||||
github.com/openimsdk/tools v0.0.47-alpha.14
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/prometheus/client_golang v1.18.0
|
||||
github.com/stretchr/testify v1.8.4
|
||||
@ -34,6 +34,7 @@ require (
|
||||
github.com/go-redis/redis v6.15.9+incompatible
|
||||
github.com/kelindar/bitmap v1.5.2
|
||||
github.com/likexian/gokit v0.25.13
|
||||
github.com/magefile/mage v1.15.0
|
||||
github.com/redis/go-redis/v9 v9.4.0
|
||||
github.com/robfig/cron/v3 v3.0.1
|
||||
github.com/shirou/gopsutil v3.21.11+incompatible
|
||||
@ -99,7 +100,6 @@ require (
|
||||
github.com/klauspost/cpuid/v2 v2.2.6 // indirect
|
||||
github.com/leodido/go-urn v1.4.0 // indirect
|
||||
github.com/lithammer/shortuuid v3.0.0+incompatible // indirect
|
||||
github.com/magefile/mage v1.15.0 // indirect
|
||||
github.com/magiconair/properties v1.8.7 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/openimsdk/tools/utils/mageutil"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/util/mageutil"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
@ -21,7 +21,7 @@ func Build() {
|
||||
mageutil.CompileForPlatform(platform)
|
||||
}
|
||||
|
||||
mageutil.PrintGreen("Compilation complete.")
|
||||
mageutil.PrintGreen("All binaries under cmd and tools were successfully compiled.")
|
||||
}
|
||||
|
||||
func Start() {
|
||||
|
||||
117
pkg/util/mageutil/bricks.go
Normal file
117
pkg/util/mageutil/bricks.go
Normal file
@ -0,0 +1,117 @@
|
||||
package mageutil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// StopBinaries iterates over all binary files and terminates their corresponding processes.
|
||||
func StopBinaries() {
|
||||
for binary := range serviceBinaries {
|
||||
fullPath := GetBinFullPath(binary)
|
||||
KillExistBinary(fullPath)
|
||||
}
|
||||
}
|
||||
|
||||
// StartBinaries Start all binary services.
|
||||
func StartBinaries() error {
|
||||
for binary, count := range serviceBinaries {
|
||||
binFullPath := filepath.Join(OpenIMOutputHostBin, binary)
|
||||
for i := 0; i < count; i++ {
|
||||
args := []string{"-i", strconv.Itoa(i), "-c", OpenIMOutputConfig}
|
||||
cmd := exec.Command(binFullPath, args...)
|
||||
fmt.Printf("Starting %s\n", cmd.String())
|
||||
cmd.Dir = OpenIMOutputHostBin
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
if err := cmd.Start(); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Failed to start %s with args %v: %v\n", binFullPath, args, err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// StartTools starts all tool binaries.
|
||||
func StartTools() error {
|
||||
for _, tool := range toolBinaries {
|
||||
toolFullPath := GetToolFullPath(tool)
|
||||
cmd := exec.Command(toolFullPath, "-c", OpenIMOutputConfig)
|
||||
fmt.Printf("Starting %s\n", cmd.String())
|
||||
cmd.Dir = OpenIMOutputHostBinTools
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
|
||||
if err := cmd.Start(); err != nil {
|
||||
fmt.Printf("Failed to start %s with error: %v\n", toolFullPath, err)
|
||||
return err
|
||||
}
|
||||
|
||||
if err := cmd.Wait(); err != nil {
|
||||
fmt.Printf("Failed to execute %s with exit code: %v\n", toolFullPath, err)
|
||||
return err
|
||||
}
|
||||
fmt.Printf("Starting %s successfully \n", cmd.String())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// KillExistBinaries iterates over all binary files and kills their corresponding processes.
|
||||
func KillExistBinaries() {
|
||||
for binary := range serviceBinaries {
|
||||
fullPath := GetBinFullPath(binary)
|
||||
KillExistBinary(fullPath)
|
||||
}
|
||||
}
|
||||
|
||||
// CheckBinariesStop checks if all binary files have stopped and returns an error if there are any binaries still running.
|
||||
func CheckBinariesStop() error {
|
||||
var runningBinaries []string
|
||||
|
||||
for binary := range serviceBinaries {
|
||||
fullPath := GetBinFullPath(binary)
|
||||
if CheckProcessNamesExist(fullPath) {
|
||||
runningBinaries = append(runningBinaries, binary)
|
||||
}
|
||||
}
|
||||
|
||||
if len(runningBinaries) > 0 {
|
||||
return fmt.Errorf("the following binaries are still running: %s", strings.Join(runningBinaries, ", "))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// CheckBinariesRunning checks if all binary files are running as expected and returns any errors encountered.
|
||||
func CheckBinariesRunning() error {
|
||||
var errorMessages []string
|
||||
|
||||
for binary, expectedCount := range serviceBinaries {
|
||||
fullPath := GetBinFullPath(binary)
|
||||
err := CheckProcessNames(fullPath, expectedCount)
|
||||
if err != nil {
|
||||
errorMessages = append(errorMessages, fmt.Sprintf("binary %s is not running as expected: %v", binary, err))
|
||||
}
|
||||
}
|
||||
|
||||
if len(errorMessages) > 0 {
|
||||
return fmt.Errorf(strings.Join(errorMessages, "\n"))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// PrintListenedPortsByBinaries iterates over all binary files and prints the ports they are listening on.
|
||||
func PrintListenedPortsByBinaries() {
|
||||
for binary, _ := range serviceBinaries {
|
||||
basePath := GetBinFullPath(binary)
|
||||
fullPath := basePath
|
||||
PrintBinaryPorts(fullPath)
|
||||
}
|
||||
}
|
||||
198
pkg/util/mageutil/bssc.go
Normal file
198
pkg/util/mageutil/bssc.go
Normal file
@ -0,0 +1,198 @@
|
||||
package mageutil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/magefile/mage/sh"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// CheckAndReportBinariesStatus checks the running status of all binary files and reports it.
|
||||
func CheckAndReportBinariesStatus() {
|
||||
err := CheckBinariesRunning()
|
||||
|
||||
if err != nil {
|
||||
PrintRed("Some programs are not running properly:")
|
||||
PrintRedNoTimeStamp(err.Error())
|
||||
return
|
||||
}
|
||||
PrintGreen("All services are running normally.")
|
||||
PrintBlue("Display details of the ports listened to by the service:")
|
||||
PrintListenedPortsByBinaries()
|
||||
}
|
||||
|
||||
// StopAndCheckBinaries stops all binary processes and checks if they have all stopped.
|
||||
func StopAndCheckBinaries() {
|
||||
KillExistBinaries()
|
||||
err := CheckBinariesStop()
|
||||
if err != nil {
|
||||
PrintRed("Some services have not been stopped, details are as follows:" + err.Error())
|
||||
return
|
||||
}
|
||||
PrintGreen("All services have been stopped")
|
||||
}
|
||||
|
||||
// StartToolsAndServices starts the process for tools and services.
|
||||
func StartToolsAndServices() {
|
||||
PrintBlue("Starting tools primarily involves component verification and other preparatory tasks.")
|
||||
if err := StartTools(); err != nil {
|
||||
PrintRed("Some tools failed to start, details are as follows, abort start")
|
||||
PrintRedNoTimeStamp(err.Error())
|
||||
return
|
||||
}
|
||||
PrintGreen("All tools executed successfully")
|
||||
|
||||
KillExistBinaries()
|
||||
err := CheckBinariesStop()
|
||||
if err != nil {
|
||||
PrintRed("Some services running, details are as follows, abort start " + err.Error())
|
||||
return
|
||||
}
|
||||
PrintBlue("Starting services involves multiple RPCs and APIs and may take some time. Please be patient")
|
||||
err = StartBinaries()
|
||||
if err != nil {
|
||||
PrintRed("Failed to start all binaries")
|
||||
PrintRedNoTimeStamp(err.Error())
|
||||
return
|
||||
}
|
||||
CheckAndReportBinariesStatus()
|
||||
}
|
||||
|
||||
// CompileForPlatform Main compile function
|
||||
func CompileForPlatform(platform string) {
|
||||
|
||||
PrintBlue(fmt.Sprintf("Compiling cmd for %s...", platform))
|
||||
|
||||
compileDir(filepath.Join(rootDirPath, "cmd"), platformsOutputBase, platform)
|
||||
|
||||
PrintBlue(fmt.Sprintf("Compiling tools for %s...", platform))
|
||||
compileDir(filepath.Join(rootDirPath, "tools"), toolsOutputBase, platform)
|
||||
|
||||
}
|
||||
|
||||
func compileDir(sourceDir, outputBase, platform string) {
|
||||
targetOS, targetArch := strings.Split(platform, "_")[0], strings.Split(platform, "_")[1]
|
||||
outputDir := filepath.Join(outputBase, targetOS, targetArch)
|
||||
|
||||
if err := os.MkdirAll(outputDir, 0755); err != nil {
|
||||
fmt.Printf("Failed to create directory %s: %v\n", outputDir, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
var wg sync.WaitGroup
|
||||
errors := make(chan error, 1)
|
||||
sem := make(chan struct{}, 4)
|
||||
|
||||
err := filepath.Walk(sourceDir, func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if info.IsDir() || filepath.Base(path) != "main.go" {
|
||||
return nil
|
||||
}
|
||||
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
sem <- struct{}{}
|
||||
defer wg.Done()
|
||||
defer func() { <-sem }()
|
||||
|
||||
dir := filepath.Dir(path)
|
||||
dirName := filepath.Base(dir)
|
||||
outputFileName := dirName
|
||||
if targetOS == "windows" {
|
||||
outputFileName += ".exe"
|
||||
}
|
||||
|
||||
PrintBlue(fmt.Sprintf("Compiling dir: %s for platform: %s binary: %s ...", dirName, platform, outputFileName))
|
||||
err := sh.RunWith(map[string]string{"GOOS": targetOS, "GOARCH": targetArch}, "go", "build", "-o", filepath.Join(outputDir, outputFileName), filepath.Join(dir, "main.go"))
|
||||
if err != nil {
|
||||
errors <- fmt.Errorf("failed to compile %s for %s: %v", dirName, platform, err)
|
||||
PrintRed("Compilation aborted. " + fmt.Sprintf("failed to compile %s for %s: %v", dirName, platform, err))
|
||||
os.Exit(1)
|
||||
return
|
||||
}
|
||||
PrintGreen(fmt.Sprintf("Successfully compiled. dir: %s for platform: %s binary: %s", dirName, platform, outputFileName))
|
||||
}()
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
fmt.Println("Error walking through directories:", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
close(errors)
|
||||
|
||||
// Check for errors
|
||||
if err, ok := <-errors; ok {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
// compileDir compiles Go programs in a specified directory, appending .exe extension for output files on Windows platform
|
||||
//func compileDir(sourceDir, outputBase, platform string) {
|
||||
// targetOS, targetArch := strings.Split(platform, "_")[0], strings.Split(platform, "_")[1]
|
||||
// outputDir := filepath.Join(outputBase, targetOS, targetArch)
|
||||
//
|
||||
// if err := os.MkdirAll(outputDir, 0755); err != nil {
|
||||
// fmt.Printf("Failed to create directory %s: %v\n", outputDir, err)
|
||||
// os.Exit(1)
|
||||
// }
|
||||
//
|
||||
// var wg sync.WaitGroup
|
||||
// errors := make(chan error, 1)
|
||||
//
|
||||
// err := filepath.Walk(sourceDir, func(path string, info os.FileInfo, err error) error {
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
// if info.IsDir() || filepath.Base(path) != "main.go" {
|
||||
// return nil
|
||||
// }
|
||||
//
|
||||
// wg.Add(1)
|
||||
// go func() {
|
||||
// defer wg.Done()
|
||||
//
|
||||
// dir := filepath.Dir(path)
|
||||
// dirName := filepath.Base(dir)
|
||||
// outputFileName := dirName
|
||||
// if targetOS == "windows" {
|
||||
// outputFileName += ".exe"
|
||||
// }
|
||||
//
|
||||
// PrintBlue(fmt.Sprintf("Compiling dir: %s for platform: %s binary: %s ...", dirName, platform, outputFileName))
|
||||
// err := sh.RunWith(map[string]string{"GOOS": targetOS, "GOARCH": targetArch}, "go", "build", "-o", filepath.Join(outputDir, outputFileName), filepath.Join(dir, "main.go"))
|
||||
// if err != nil {
|
||||
// errors <- fmt.Errorf("failed to compile %s for %s: %v", dirName, platform, err)
|
||||
// PrintRed("Compilation aborted. " + fmt.Sprintf("failed to compile %s for %s: %v", dirName, platform, err))
|
||||
// os.Exit(1)
|
||||
// return
|
||||
// }
|
||||
// PrintGreen(fmt.Sprintf("Compiling dir: %s for platform: %s binary: %s ...", dirName, platform, outputFileName))
|
||||
// }()
|
||||
//
|
||||
// return nil
|
||||
// })
|
||||
//
|
||||
// if err != nil {
|
||||
// fmt.Println("Error walking through directories:", err)
|
||||
// os.Exit(1)
|
||||
// }
|
||||
//
|
||||
// wg.Wait()
|
||||
// close(errors)
|
||||
//
|
||||
// // Check for errors
|
||||
// if err, ok := <-errors; ok {
|
||||
// fmt.Println(err)
|
||||
// fmt.Println("Compilation aborted.")
|
||||
// os.Exit(1)
|
||||
// }
|
||||
//}
|
||||
46
pkg/util/mageutil/define.go
Normal file
46
pkg/util/mageutil/define.go
Normal file
@ -0,0 +1,46 @@
|
||||
package mageutil
|
||||
|
||||
import (
|
||||
"gopkg.in/yaml.v3"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
var (
|
||||
serviceBinaries map[string]int
|
||||
toolBinaries []string
|
||||
MaxFileDescriptors int
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
ServiceBinaries map[string]int `yaml:"serviceBinaries"`
|
||||
ToolBinaries []string `yaml:"toolBinaries"`
|
||||
MaxFileDescriptors int `yaml:"maxFileDescriptors"`
|
||||
}
|
||||
|
||||
func init() {
|
||||
yamlFile, err := ioutil.ReadFile("start-config.yml")
|
||||
if err != nil {
|
||||
log.Fatalf("error reading YAML file: %v", err)
|
||||
}
|
||||
|
||||
// 解析YAML
|
||||
var config Config
|
||||
err = yaml.Unmarshal(yamlFile, &config)
|
||||
if err != nil {
|
||||
log.Fatalf("error unmarshalling YAML: %v", err)
|
||||
}
|
||||
|
||||
adjustedBinaries := make(map[string]int)
|
||||
for binary, count := range config.ServiceBinaries {
|
||||
if runtime.GOOS == "windows" {
|
||||
binary += ".exe"
|
||||
}
|
||||
adjustedBinaries[binary] = count
|
||||
}
|
||||
|
||||
serviceBinaries = adjustedBinaries
|
||||
toolBinaries = config.ToolBinaries
|
||||
MaxFileDescriptors = config.MaxFileDescriptors
|
||||
}
|
||||
56
pkg/util/mageutil/logging.go
Normal file
56
pkg/util/mageutil/logging.go
Normal file
@ -0,0 +1,56 @@
|
||||
package mageutil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
ColorBlue = "\033[0;34m"
|
||||
ColorGreen = "\033[0;32m"
|
||||
ColorRed = "\033[0;31m"
|
||||
ColorReset = "\033[0m"
|
||||
)
|
||||
|
||||
func PrintBlueTwoLine(message string) {
|
||||
currentTime := time.Now().Format("[2006-01-02 15:04:05 MST]")
|
||||
fmt.Println(currentTime)
|
||||
fmt.Printf("%s%s%s\n", ColorBlue, message, ColorReset)
|
||||
}
|
||||
|
||||
func PrintBlue(message string) {
|
||||
currentTime := time.Now().Format("[2006-01-02 15:04:05 MST]")
|
||||
fmt.Printf("%s %s%s%s\n", currentTime, ColorBlue, message, ColorReset)
|
||||
}
|
||||
|
||||
func PrintGreenTwoLine(message string) {
|
||||
currentTime := time.Now().Format("[2006-01-02 15:04:05 MST]")
|
||||
fmt.Println(currentTime)
|
||||
fmt.Printf("%s%s%s\n", ColorGreen, message, ColorReset)
|
||||
}
|
||||
|
||||
func PrintGreen(message string) {
|
||||
currentTime := time.Now().Format("[2006-01-02 15:04:05 MST]")
|
||||
fmt.Printf("%s %s%s%s\n", currentTime, ColorGreen, message, ColorReset)
|
||||
}
|
||||
|
||||
func PrintRed(message string) {
|
||||
currentTime := time.Now().Format("[2006-01-02 15:04:05 MST]")
|
||||
fmt.Printf("%s %s%s%s\n", currentTime, ColorRed, message, ColorReset)
|
||||
}
|
||||
|
||||
func PrintRedNoTimeStamp(message string) {
|
||||
fmt.Printf("%s%s%s\n", ColorRed, message, ColorReset)
|
||||
}
|
||||
|
||||
func PrintGreenNoTimeStamp(message string) {
|
||||
fmt.Printf("%s%s%s\n", ColorGreen, message, ColorReset)
|
||||
}
|
||||
|
||||
func PrintRedToStdErr(a ...interface{}) (n int, err error) {
|
||||
return fmt.Fprint(os.Stderr, "\033[31m", fmt.Sprint(a...), "\033[0m")
|
||||
}
|
||||
func PrintGreenToStdOut(a ...interface{}) (n int, err error) {
|
||||
return fmt.Fprint(os.Stdout, "\033[32m", fmt.Sprint(a...), "\033[0m")
|
||||
}
|
||||
85
pkg/util/mageutil/path.go
Normal file
85
pkg/util/mageutil/path.go
Normal file
@ -0,0 +1,85 @@
|
||||
package mageutil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
var (
|
||||
OpenIMRoot string
|
||||
OpenIMOutputConfig string
|
||||
OpenIMOutput string
|
||||
OpenIMOutputTools string
|
||||
OpenIMOutputTmp string
|
||||
OpenIMOutputLogs string
|
||||
OpenIMOutputBin string
|
||||
OpenIMOutputBinPath string
|
||||
OpenIMOutputBinToolPath string
|
||||
OpenIMInitErrLogFile string
|
||||
OpenIMInitLogFile string
|
||||
OpenIMOutputHostBin string
|
||||
OpenIMOutputHostBinTools string
|
||||
)
|
||||
|
||||
func init() {
|
||||
currentDir, err := os.Getwd()
|
||||
if err != nil {
|
||||
panic("Error getting current directory: " + err.Error())
|
||||
}
|
||||
|
||||
OpenIMRoot = currentDir
|
||||
|
||||
OpenIMOutputConfig = filepath.Join(OpenIMRoot, "config") + string(filepath.Separator)
|
||||
OpenIMOutput = filepath.Join(OpenIMRoot, "_output") + string(filepath.Separator)
|
||||
|
||||
OpenIMOutputTools = filepath.Join(OpenIMOutput, "tools") + string(filepath.Separator)
|
||||
OpenIMOutputTmp = filepath.Join(OpenIMOutput, "tmp") + string(filepath.Separator)
|
||||
OpenIMOutputLogs = filepath.Join(OpenIMOutput, "logs") + string(filepath.Separator)
|
||||
OpenIMOutputBin = filepath.Join(OpenIMOutput, "bin") + string(filepath.Separator)
|
||||
|
||||
OpenIMOutputBinPath = filepath.Join(OpenIMOutputBin, "platforms") + string(filepath.Separator)
|
||||
OpenIMOutputBinToolPath = filepath.Join(OpenIMOutputBin, "tools") + string(filepath.Separator)
|
||||
|
||||
OpenIMInitErrLogFile = filepath.Join(OpenIMOutputLogs, "openim-init-err.log")
|
||||
OpenIMInitLogFile = filepath.Join(OpenIMOutputLogs, "openim-init.log")
|
||||
|
||||
OpenIMOutputHostBin = filepath.Join(OpenIMOutputBinPath, OsArch()) + string(filepath.Separator)
|
||||
OpenIMOutputHostBinTools = filepath.Join(OpenIMOutputBinToolPath, OsArch()) + string(filepath.Separator)
|
||||
|
||||
dirs := []string{
|
||||
OpenIMOutputConfig,
|
||||
OpenIMOutput,
|
||||
OpenIMOutputTools,
|
||||
OpenIMOutputTmp,
|
||||
OpenIMOutputLogs,
|
||||
OpenIMOutputBin,
|
||||
OpenIMOutputBinPath,
|
||||
OpenIMOutputBinToolPath,
|
||||
OpenIMOutputHostBin,
|
||||
OpenIMOutputHostBinTools,
|
||||
}
|
||||
|
||||
for _, dir := range dirs {
|
||||
createDirIfNotExist(dir)
|
||||
}
|
||||
}
|
||||
|
||||
func createDirIfNotExist(dir string) {
|
||||
if err := os.MkdirAll(dir, 0755); err != nil {
|
||||
fmt.Printf("Failed to create directory %s: %v\n", dir, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
// GetBinFullPath constructs and returns the full path for the given binary name.
|
||||
func GetBinFullPath(binName string) string {
|
||||
binFullPath := filepath.Join(OpenIMOutputHostBin, binName)
|
||||
return binFullPath
|
||||
}
|
||||
|
||||
// GetToolFullPath constructs and returns the full path for the given tool name.
|
||||
func GetToolFullPath(toolName string) string {
|
||||
toolFullPath := filepath.Join(OpenIMOutputHostBinTools, toolName)
|
||||
return toolFullPath
|
||||
}
|
||||
208
pkg/util/mageutil/sys.go
Normal file
208
pkg/util/mageutil/sys.go
Normal file
@ -0,0 +1,208 @@
|
||||
package mageutil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/shirou/gopsutil/net"
|
||||
"github.com/shirou/gopsutil/process"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func OsArch() string {
|
||||
os := runtime.GOOS
|
||||
arch := runtime.GOARCH
|
||||
if os == "windows" {
|
||||
return fmt.Sprintf("%s\\%s", os, arch)
|
||||
}
|
||||
return fmt.Sprintf("%s/%s", os, arch)
|
||||
}
|
||||
|
||||
func CheckProcessNames(processPath string, expectedCount int) error {
|
||||
processes, err := process.Processes()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get processes: %v", err)
|
||||
}
|
||||
|
||||
runningCount := 0
|
||||
for _, p := range processes {
|
||||
exePath, err := p.Exe()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if strings.EqualFold(exePath, processPath) {
|
||||
runningCount++
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if runningCount == expectedCount {
|
||||
return nil
|
||||
} else {
|
||||
return fmt.Errorf("%s Expected %d processes, but %d running", processPath, expectedCount, runningCount)
|
||||
}
|
||||
}
|
||||
|
||||
// CheckProcessNamesExist checks if there are any processes running that match the specified path.
|
||||
func CheckProcessNamesExist(processPath string) bool {
|
||||
processes, err := process.Processes()
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to get processes: %v\n", err)
|
||||
return false
|
||||
}
|
||||
|
||||
for _, p := range processes {
|
||||
exePath, err := p.Exe()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if exePath == processPath {
|
||||
return true // 找到至少一个匹配的进程
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// PrintBinaryPorts prints the ports listened by the process of a specified binary file along with its command line arguments.
|
||||
func PrintBinaryPorts(binaryPath string) {
|
||||
pids, err := FindPIDsByBinaryPath(binaryPath)
|
||||
if err != nil {
|
||||
fmt.Println("Error finding PIDs:", err)
|
||||
return
|
||||
}
|
||||
|
||||
if len(pids) == 0 {
|
||||
fmt.Printf("No running processes found for binary: %s\n", binaryPath)
|
||||
return
|
||||
}
|
||||
|
||||
for _, pid := range pids {
|
||||
|
||||
proc, err := process.NewProcess(int32(pid))
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to create process object for PID %d: %v\n", pid, err)
|
||||
continue
|
||||
}
|
||||
|
||||
cmdline, err := proc.Cmdline()
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to get command line for PID %d: %v\n", pid, err)
|
||||
continue
|
||||
}
|
||||
|
||||
connections, err := net.ConnectionsPid("all", int32(pid))
|
||||
if err != nil {
|
||||
fmt.Printf("Error getting connections for PID %d: %v\n", pid, err)
|
||||
continue
|
||||
}
|
||||
|
||||
portsMap := make(map[string]struct{})
|
||||
for _, conn := range connections {
|
||||
if conn.Status == "LISTEN" {
|
||||
port := fmt.Sprintf("%d", conn.Laddr.Port)
|
||||
portsMap[port] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
if len(portsMap) == 0 {
|
||||
PrintGreen(fmt.Sprintf("Cmdline: %s, PID: %d is not listening on any ports.", cmdline, pid))
|
||||
} else {
|
||||
ports := make([]string, 0, len(portsMap))
|
||||
for port := range portsMap {
|
||||
ports = append(ports, port)
|
||||
}
|
||||
PrintGreen(fmt.Sprintf("Cmdline: %s, PID: %d is listening on ports: %s", cmdline, pid, strings.Join(ports, ", ")))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FindPIDsByBinaryPath finds all matching process PIDs by binary path.
|
||||
func FindPIDsByBinaryPath(binaryPath string) ([]int, error) {
|
||||
var pids []int
|
||||
processes, err := process.Processes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, proc := range processes {
|
||||
exePath, err := proc.Exe()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if strings.EqualFold(exePath, binaryPath) {
|
||||
pids = append(pids, int(proc.Pid))
|
||||
}
|
||||
}
|
||||
|
||||
return pids, nil
|
||||
}
|
||||
|
||||
// KillExistBinary kills all processes matching the given binary file path.
|
||||
func KillExistBinary(binaryPath string) {
|
||||
processes, err := process.Processes()
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to get processes: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
for _, p := range processes {
|
||||
exePath, err := p.Exe()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if strings.Contains(strings.ToLower(exePath), strings.ToLower(binaryPath)) {
|
||||
|
||||
//if strings.EqualFold(exePath, binaryPath) {
|
||||
cmdline, err := p.Cmdline()
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to get command line for process %d: %v\n", p.Pid, err)
|
||||
continue
|
||||
}
|
||||
|
||||
err = p.Terminate()
|
||||
if err != nil {
|
||||
|
||||
err = p.Kill()
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to kill process cmdline: %s, pid: %d, err: %v\n", cmdline, p.Pid, err)
|
||||
} else {
|
||||
fmt.Printf("Killed process cmdline: %s, pid: %d\n", cmdline, p.Pid)
|
||||
}
|
||||
} else {
|
||||
fmt.Printf("Terminated process cmdline: %s, pid: %d\n", cmdline, p.Pid)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DetectPlatform detects the operating system and architecture.
|
||||
func DetectPlatform() string {
|
||||
targetOS, targetArch := runtime.GOOS, runtime.GOARCH
|
||||
switch targetArch {
|
||||
case "amd64", "arm64":
|
||||
default:
|
||||
fmt.Printf("Unsupported architecture: %s\n", targetArch)
|
||||
os.Exit(1)
|
||||
}
|
||||
return fmt.Sprintf("%s_%s", targetOS, targetArch)
|
||||
}
|
||||
|
||||
// rootDir gets the absolute path of the current directory.
|
||||
func rootDir() string {
|
||||
dir, err := os.Getwd()
|
||||
if err != nil {
|
||||
fmt.Println("Failed to get current directory:", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
return dir
|
||||
}
|
||||
|
||||
var rootDirPath = rootDir()
|
||||
var platformsOutputBase = filepath.Join(rootDirPath, "_output/bin/platforms")
|
||||
var toolsOutputBase = filepath.Join(rootDirPath, "_output/bin/tools")
|
||||
67
pkg/util/mageutil/usage-guide/README_zh_CN.md
Normal file
67
pkg/util/mageutil/usage-guide/README_zh_CN.md
Normal file
@ -0,0 +1,67 @@
|
||||
# mageutil使用指南
|
||||
|
||||
**mageutil** 是基于 mage 构建的一个工具,它提供了跨平台和多架构的编译支持,同时也简化了服务的启动、停止、检测流程。
|
||||
|
||||
## 使用指南
|
||||
|
||||
### 准备工作
|
||||
|
||||
1. 将此目录下除README以外的6个文件复制到项目的根目录:
|
||||
2. 项目根目录下需要包含三个目录:`cmd`、`tools`和`config`。
|
||||
- `cmd` 目录专门用于存放那些作为后台服务运行的应用的启动代码。
|
||||
- `tools`目录用于存放那些作为工具应用(不以后台服务形式运行)的启动代码。
|
||||
- `config`目录用于存放配置文件。
|
||||
3. `cmd`和`tools`目录可以包含多层多个子目录。对于包含`main`函数的`main package`文件,需以`main.go`命名。例如:
|
||||
- `cmd/openim-rpc/openim-rpc-msg/main.go`
|
||||
- `tools/check-free-memory/main.go`
|
||||
- 所有代码都应属于同一个项目,子目录不应使用独立的`go.mod`和`go.sum`文件。
|
||||
|
||||
### 初始化项目
|
||||
|
||||
- 对于Linux/Mac系统,先执行`bootstrap.sh`脚本。
|
||||
- 对于Windows系统,先执行`bootstrap.bat`脚本。
|
||||
|
||||
### 编译项目
|
||||
|
||||
- 执行`mage`或`mage build`来编译项目。
|
||||
- 编译完成后,二进制文件将生成在`_output/bin/platforms/<操作系统>/<架构>`目录下,其中二进制文件的命名规则为对应的`main.go`所在的目录名。例如:
|
||||
- `_output/bin/platforms/linux/amd64/openim-rpc-msg`
|
||||
- `_output/bin/tools/linux/amd64/check-free-memory`
|
||||
- **注意:** Windows平台的二进制文件会自动添加`.exe`扩展名。
|
||||
|
||||
### 启动工具和服务
|
||||
|
||||
1. 首先,编辑`start-config.yml`文件,指定服务和工具相关配置,例如:
|
||||
|
||||
```yaml
|
||||
#cmd服务子目录名: 实例数
|
||||
serviceBinaries:
|
||||
openim-rpc-msg: 2
|
||||
|
||||
#tools工具子目录名
|
||||
toolBinaries:
|
||||
- check-free-memory
|
||||
|
||||
maxFileDescriptors: 10000
|
||||
```
|
||||
|
||||
**注意:**服务和工具名与`cmd`和`tools`下的子目录名保持一致
|
||||
|
||||
3. 执行`mage start`来启动服务和工具。
|
||||
|
||||
- 工具将以同步方式执行,如果工具执行失败(退出代码非零),则整个启动过程中断。
|
||||
- 服务将以异步方式启动。
|
||||
|
||||
对于所有工具,将采用以下命令格式启动:`[程序绝对路径] -i 0 -c [配置文件绝对目录]`。
|
||||
|
||||
若服务实例数设置为`n`,则服务将启动`n`个实例,每个实例使用的命令格式为:`[程序路径] -i [实例索引] -c [配置文件目录]`,其中实例索引从`0`到`n-1`。
|
||||
|
||||
**注意**:本项目仅指定了配置文件的路径,并不负责读取配置文件内容。这样做的目的是为了支持使用多个配置文件的情况。程序和配置文件的路径都自动使用绝对路径。
|
||||
|
||||
### 检查和停止服务
|
||||
|
||||
- 执行`mage check`来检查服务状态和监听的端口。
|
||||
- 执行`mage stop`来停止服务,该命令会向服务发送停止信号。
|
||||
|
||||
---
|
||||
|
||||
31
pkg/util/mageutil/usage-guide/bootstrap.bat
Normal file
31
pkg/util/mageutil/usage-guide/bootstrap.bat
Normal file
@ -0,0 +1,31 @@
|
||||
@echo off
|
||||
SETLOCAL
|
||||
|
||||
mage -version >nul 2>&1
|
||||
IF %ERRORLEVEL% EQU 0 (
|
||||
echo Mage is already installed.
|
||||
GOTO DOWNLOAD
|
||||
)
|
||||
|
||||
go version >nul 2>&1
|
||||
IF NOT %ERRORLEVEL% EQU 0 (
|
||||
echo Go is not installed. Please install Go and try again.
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
echo Installing Mage...
|
||||
go install github.com/magefile/mage@latest
|
||||
|
||||
mage -version >nul 2>&1
|
||||
IF NOT %ERRORLEVEL% EQU 0 (
|
||||
echo Mage installation failed.
|
||||
echo Please ensure that %GOPATH%/bin is in your PATH.
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
echo Mage installed successfully.
|
||||
|
||||
:DOWNLOAD
|
||||
go mod download
|
||||
|
||||
ENDLOCAL
|
||||
23
pkg/util/mageutil/usage-guide/bootstrap.sh
Normal file
23
pkg/util/mageutil/usage-guide/bootstrap.sh
Normal file
@ -0,0 +1,23 @@
|
||||
#!/bin/bash
|
||||
|
||||
if [[ ":$PATH:" == *":$HOME/.local/bin:"* ]]; then
|
||||
TARGET_DIR="$HOME/.local/bin"
|
||||
else
|
||||
TARGET_DIR="/usr/local/bin"
|
||||
echo "Using /usr/local/bin as the installation directory. Might require sudo permissions."
|
||||
fi
|
||||
|
||||
if ! command -v mage &> /dev/null; then
|
||||
echo "Installing Mage to $TARGET_DIR ..."
|
||||
GOBIN=$TARGET_DIR go install github.com/magefile/mage@latest
|
||||
fi
|
||||
|
||||
if ! command -v mage &> /dev/null; then
|
||||
echo "Mage installation failed."
|
||||
echo "Please ensure that $TARGET_DIR is in your \$PATH."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Mage installed successfully."
|
||||
|
||||
go mod download
|
||||
38
pkg/util/mageutil/usage-guide/magefile.go
Normal file
38
pkg/util/mageutil/usage-guide/magefile.go
Normal file
@ -0,0 +1,38 @@
|
||||
//go:build mage
|
||||
// +build mage
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/openimsdk/tools/utils/mageutil"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var Default = Build
|
||||
|
||||
func Build() {
|
||||
platforms := os.Getenv("PLATFORMS")
|
||||
if platforms == "" {
|
||||
platforms = mageutil.DetectPlatform()
|
||||
}
|
||||
|
||||
for _, platform := range strings.Split(platforms, " ") {
|
||||
mageutil.CompileForPlatform(platform)
|
||||
}
|
||||
|
||||
mageutil.PrintGreen("Compilation complete.")
|
||||
}
|
||||
|
||||
func Start() {
|
||||
setMaxOpenFiles()
|
||||
mageutil.StartToolsAndServices()
|
||||
}
|
||||
|
||||
func Stop() {
|
||||
mageutil.StopAndCheckBinaries()
|
||||
}
|
||||
|
||||
func Check() {
|
||||
mageutil.CheckAndReportBinariesStatus()
|
||||
}
|
||||
20
pkg/util/mageutil/usage-guide/magefile_unix.go
Normal file
20
pkg/util/mageutil/usage-guide/magefile_unix.go
Normal file
@ -0,0 +1,20 @@
|
||||
//go:build mage && !windows
|
||||
// +build mage,!windows
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/openimsdk/tools/utils/mageutil"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func setMaxOpenFiles() error {
|
||||
var rLimit syscall.Rlimit
|
||||
err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rLimit)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rLimit.Max = uint64(mageutil.MaxFileDescriptors)
|
||||
rLimit.Cur = uint64(mageutil.MaxFileDescriptors)
|
||||
return syscall.Setrlimit(syscall.RLIMIT_NOFILE, &rLimit)
|
||||
}
|
||||
8
pkg/util/mageutil/usage-guide/magefile_windows.go
Normal file
8
pkg/util/mageutil/usage-guide/magefile_windows.go
Normal file
@ -0,0 +1,8 @@
|
||||
//go:build mage
|
||||
// +build mage
|
||||
|
||||
package main
|
||||
|
||||
func setMaxOpenFiles() error {
|
||||
return nil
|
||||
}
|
||||
8
pkg/util/mageutil/usage-guide/start-config.yml
Normal file
8
pkg/util/mageutil/usage-guide/start-config.yml
Normal file
@ -0,0 +1,8 @@
|
||||
serviceBinaries:
|
||||
openim-no-port: 1
|
||||
openim-test: 1
|
||||
|
||||
toolBinaries:
|
||||
- check-free-memory
|
||||
|
||||
maxFileDescriptors: 10000
|
||||
@ -24,7 +24,6 @@ import (
|
||||
"github.com/openimsdk/tools/db/redisutil"
|
||||
"github.com/openimsdk/tools/discovery/zookeeper"
|
||||
"github.com/openimsdk/tools/mq/kafka"
|
||||
"github.com/openimsdk/tools/s3/minio"
|
||||
"github.com/openimsdk/tools/system/program"
|
||||
"path/filepath"
|
||||
"time"
|
||||
@ -45,8 +44,8 @@ func CheckRedis(ctx context.Context, config *config.Redis) error {
|
||||
}
|
||||
|
||||
func CheckMinIO(ctx context.Context, config *config.Minio) error {
|
||||
return minio.Check()
|
||||
|
||||
//return minio.Check()
|
||||
return nil
|
||||
}
|
||||
|
||||
func CheckKafka(ctx context.Context, conf *config.Kafka) error {
|
||||
|
||||
@ -25,6 +25,7 @@ import (
|
||||
"github.com/openimsdk/protocol/auth"
|
||||
"github.com/openimsdk/protocol/constant"
|
||||
"github.com/openimsdk/protocol/third"
|
||||
"github.com/openimsdk/tools/errs"
|
||||
)
|
||||
|
||||
type Api struct {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user