//ReverseString 反转字符串
func ReverseString(s string) string {
runes := []rune(s)
for from, to := 0, len(runes)-1; from < to; from, to = from+1, to-1 {
runes[from], runes[to] = runes[to], runes[from]
}
return string(runes)
}
//Exists 判断文件存在
func Exists(path string) bool {
_, e := os.Stat(path)
return e == nil || os.IsExist(e)
}
//ShellExec 运行命令
func ShellExec(command string, arg ...string) (string, error) {
var builder strings.Builder
_, _ = builder.WriteString(command)
for _, v := range arg {
_, _ = builder.WriteString(" ")
_, _ = builder.WriteString(v)
}
stdOut, stdErr, e := RunCmdAndGetOutput(exec.Command("/bin/bash", "-c", builder.String()))
if e != nil {
e = errors.New(stdErr)
}
return stdOut, e
}
//ShellExecBackends 后台运行命令
func ShellExecBackends(command string, arg ...string) error {
var builder strings.Builder
_, _ = builder.WriteString(command)
for _, v := range arg {
_, _ = builder.WriteString(" ")
_, _ = builder.WriteString(v)
}
cmd := exec.Command("/bin/bash", "-c", builder.String())
if e := cmd.Start(); e != nil {
return gerror.Wrap(e, "ShellExecBackends")
}
go cmd.Wait() //避免僵尸进程
return nil
}
//PostFormRequest post表单请求,超时30s
//url 请求api
//data 数据
//ssl 是否关闭ssl,true关闭
func PostFormRequest(url string, data url.Values, ssl bool) ([]byte, error) {
client := &http.Client{
Transport: &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: ssl},
},
}
client.Timeout = time.Second * 30
form, err := client.PostForm(url, data)
if err != nil {
return nil, gerror.Wrap(err, "PostFormRequest")
}
defer form.Body.Close()
res, err := io.ReadAll(form.Body)
if err != nil {
return nil, gerror.Wrap(err, "PostFormRequest1")
}
return res, nil
}
//GetRequest get请求
//url 请求api
//header 请求头
//ssl 是否关闭ssl,true关闭
func GetRequest(url string, header http.Header, ssl bool) ([]byte, error) {
request, err := http.NewRequest("GET", url, nil)
if err != nil {
return nil, gerror.Wrap(err, "GetRequest")
}
client := &http.Client{
Transport: &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: ssl},
},
}
request.Header = header
response, err := client.Do(request)
if err != nil {
return nil, gerror.Wrap(err, "GetRequest1")
}
defer response.Body.Close()
res, err := io.ReadAll(response.Body)
if err != nil {
return nil, gerror.Wrap(err, "GetRequest2")
}
return res, nil
}
//GetStringMd5 计算字符串md5
func GetStringMd5(str string) string {
h := md5.New()
_, _ = h.Write([]byte(str))
return hex.EncodeToString(h.Sum(nil))
}
//GetFileMd5 计算文件md5
func GetFileMd5(file string) (string, error) {
f, err := os.Open(file)
if err != nil {
return "", err
}
defer f.Close()
hash := md5.New()
if _, err = io.Copy(hash, f); err != nil {
return "", err
}
return hex.EncodeToString(hash.Sum(nil)[:16]), nil
}
//WatchFile 监听文件修改
func WatchFile(file string, fn func()) {
//创建一个监控对象
watcher, err := fsnotify.NewWatcher()
if err != nil {
logrus.Warning("WatchFile:", err)
return
}
if err = watcher.Add(file); err != nil {
logrus.Warning("WatchFile1:", err)
return
}
//启动一个协和监听config是否被修改
go func() {
ch := make(chan os.Signal, 1)
signal.Notify(ch, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT, syscall.SIGHUP)
<-ch
_ = watcher.Close()
}()
//另启一个goroutine来处理监控对象的事件
go func() {
for {
select {
case event, ok := <-watcher.Events:
if !ok {
return
}
if event.Op&fsnotify.Write == fsnotify.Write {
fn()
}
case err, ok := <-watcher.Errors:
if !ok {
return
}
logrus.Warning("WatchFile2:", err)
}
}
}()
}
//SwitchUserRight 切换到指定用户权限(用户及组)仅对文件操作生效,会影响当前协程的向下执行逻辑及所有子函数
//切换时注意需权限控制的异步io是否运行完毕,否则可能会才出现权限问题
//name 为空则切换回程序执行用户
func SwitchUserRight(name ...string) error {
var uid, gid int
var userInfo *user.User
if len(name) == 0 {
u, e := user.Current()
if e != nil {
return gerror.Wrap(e, "SwitchUserRight1")
}
userInfo = u
} else {
u, e := user.Lookup(name[0])
if e != nil {
return gerror.Wrap(e, "SwitchUserRight2")
}
userInfo = u
}
gid, e := strconv.Atoi(userInfo.Gid)
if e != nil {
return gerror.Wrap(e, "SwitchUserRight3")
}
uid, e = strconv.Atoi(userInfo.Uid)
if e != nil {
return gerror.Wrap(e, "SwitchUserRight4")
}
if e = syscall.Setfsgid(gid); e != nil {
return gerror.Wrap(e, "conversion failure1")
}
if e = syscall.Setfsuid(uid); e != nil {
return gerror.Wrap(e, "conversion failure2")
}
return nil
}
//CheckPort 检测端口是否占用
//return true被占用 false未被占用
func CheckPort(port uint16) (bool, error) {
conn, err := net.DialTimeout("tcp", fmt.Sprintf("0.0.0.0:%d", port), 3*time.Second)
if err != nil {
return false, nil
}
_ = conn.Close()
return true, nil
}
func main() {
//接收参数
daemon := flag.Bool("D", false, "Run in daemon mode")
flag.Parse()
//后台运行
if *daemon && os.Getppid() != 1 {
//判断当其是否是子进程,当父进程return之后,子进程会被系统1号进程接管
filePath, err := filepath.Abs(os.Args[0])
if err != nil {
log.Fatalln(err)
}
cmd := exec.Command(filePath)
cmd.Stdin = nil
cmd.Stdout = nil
cmd.Stderr = nil
if err = cmd.Start(); err != nil {
log.Fatalln(err)
}
return
}
//监听进程信号,优雅退出
go func() {
ch := make(chan os.Signal, 1)
signal.Notify(ch, unix.SIGINT, unix.SIGTERM, unix.SIGQUIT, unix.SIGHUP)
<-ch
os.Exit(0)
}()
}
//FileSizeFriendly 文件大小人性化
//size单位B
func FileSizeFriendly(size int64) string {
if size < 1024 {
return fmt.Sprintf("%.2fB", float64(size))
}
if size < (1024 * 1024) {
return fmt.Sprintf("%.2fKB", float64(size)/float64(1024))
}
if size < (1024 * 1024 * 1024) {
return fmt.Sprintf("%.2fMB", float64(size)/float64(1024*1024))
}
if size < (1024 * 1024 * 1024 * 1024) {
return fmt.Sprintf("%.2fGB", float64(size)/float64(1024*1024*1024))
}
if size < (1024 * 1024 * 1024 * 1024 * 1024) {
return fmt.Sprintf("%.2fTB", float64(size)/float64(1024*1024*1024*1024))
}
return fmt.Sprintf("%.2fEB", float64(size)/float64(1024*1024*1024*1024*1024))
}
版权属于:
流星aday
作品采用:
《
署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)
》许可协议授权
评论