Compare commits
20 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1333eb85bb | |||
| dae84c0a85 | |||
|
ed85eb7616
|
|||
|
d8c0d86ca0
|
|||
|
bbd85885df
|
|||
|
c615c4bb00
|
|||
| 5353429b8c | |||
| cf453821ef | |||
| 3501166592 | |||
| d981a03b14 | |||
| fd5cf2c1f6 | |||
| c3ca057b96 | |||
| c3a165e64a | |||
| ad5c18667a | |||
| cdf3a18981 | |||
| 6de9af62cc | |||
| bca0d42559 | |||
| 26da8c8b88 | |||
| 5c2cce2da2 | |||
| a94fc8d19d |
@@ -0,0 +1,2 @@
|
|||||||
|
.idea
|
||||||
|
.vscode
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
// +build darwin
|
||||||
|
|
||||||
|
package staros
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// DefaultFreq - frequency, in Hz, middle A
|
||||||
|
DefaultFreq = 0.0
|
||||||
|
// DefaultDuration - duration in milliseconds
|
||||||
|
DefaultDuration = 0
|
||||||
|
)
|
||||||
|
|
||||||
|
// Beep beeps the PC speaker (https://en.wikipedia.org/wiki/PC_speaker).
|
||||||
|
func Beep(freq float64, duration int) error {
|
||||||
|
osa, err := exec.LookPath("osascript")
|
||||||
|
if err != nil {
|
||||||
|
// Output the only beep we can
|
||||||
|
_, err = os.Stdout.Write([]byte{7})
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd := exec.Command(osa, "-e", `beep`)
|
||||||
|
return cmd.Run()
|
||||||
|
}
|
||||||
+138
@@ -0,0 +1,138 @@
|
|||||||
|
// +build linux
|
||||||
|
|
||||||
|
package staros
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"os"
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Constants
|
||||||
|
const (
|
||||||
|
// This number represents the fixed frequency of the original PC XT's timer chip, which is approximately 1.193 MHz. This number
|
||||||
|
// is divided with the desired frequency to obtain a counter value, that is subsequently fed into the timer chip, tied to the PC speaker.
|
||||||
|
clockTickRate = 1193180
|
||||||
|
|
||||||
|
// linux/kd.h, start sound generation (0 for off)
|
||||||
|
kiocsound = 0x4B2F
|
||||||
|
|
||||||
|
// linux/input-event-codes.h
|
||||||
|
evSnd = 0x12 // Event type
|
||||||
|
sndTone = 0x02 // Sound
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// DefaultFreq - frequency, in Hz, middle A
|
||||||
|
DefaultFreq = 440.0
|
||||||
|
// DefaultDuration - duration in milliseconds
|
||||||
|
DefaultDuration = 200
|
||||||
|
)
|
||||||
|
|
||||||
|
// inputEvent represents linux/input.h event structure.
|
||||||
|
type inputEvent struct {
|
||||||
|
Time syscall.Timeval // time in seconds since epoch at which event occurred
|
||||||
|
Type uint16 // event type
|
||||||
|
Code uint16 // event code related to the event type
|
||||||
|
Value int32 // event value related to the event type
|
||||||
|
}
|
||||||
|
|
||||||
|
// ioctl system call manipulates the underlying device parameters of special files.
|
||||||
|
func ioctl(fd, name, data uintptr) error {
|
||||||
|
_, _, e := syscall.Syscall(syscall.SYS_IOCTL, fd, name, data)
|
||||||
|
if e != 0 {
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Beep beeps the PC speaker (https://en.wikipedia.org/wiki/PC_speaker).
|
||||||
|
//
|
||||||
|
// On Linux it needs permission to access `/dev/tty0` or `/dev/input/by-path/platform-pcspkr-event-spkr` files for writing,
|
||||||
|
// and `pcspkr` module must be loaded. User must be in correct groups, usually `input` and/or `tty`.
|
||||||
|
//
|
||||||
|
// If it can not open device files, it will fallback to sending Bell character (https://en.wikipedia.org/wiki/Bell_character).
|
||||||
|
// For bell character in X11 terminals you can enable bell with `xset b on`. For console check `setterm` and `--blength` or `--bfreq` options.
|
||||||
|
//
|
||||||
|
// On macOS this just sends bell character. Enable `Audible bell` in Terminal --> Preferences --> Settings --> Advanced.
|
||||||
|
//
|
||||||
|
// On Windows it uses Beep function via syscall.
|
||||||
|
//
|
||||||
|
// On Web it plays hard coded beep sound.
|
||||||
|
func Beep(freq float64, duration int) error {
|
||||||
|
if freq == 0 {
|
||||||
|
freq = DefaultFreq
|
||||||
|
} else if freq > 20000 {
|
||||||
|
freq = 20000
|
||||||
|
} else if freq < 0 {
|
||||||
|
freq = DefaultFreq
|
||||||
|
}
|
||||||
|
|
||||||
|
if duration == 0 {
|
||||||
|
duration = DefaultDuration
|
||||||
|
}
|
||||||
|
|
||||||
|
period := int(float64(clockTickRate) / freq)
|
||||||
|
|
||||||
|
var evdev bool
|
||||||
|
|
||||||
|
f, err := os.OpenFile("/dev/tty0", os.O_WRONLY, 0644)
|
||||||
|
if err != nil {
|
||||||
|
e := err
|
||||||
|
f, err = os.OpenFile("/dev/input/by-path/platform-pcspkr-event-spkr", os.O_WRONLY, 0644)
|
||||||
|
if err != nil {
|
||||||
|
e = errors.New("beeep: " + e.Error() + "; " + err.Error())
|
||||||
|
|
||||||
|
// Output the only beep we can
|
||||||
|
_, err = os.Stdout.Write([]byte{7})
|
||||||
|
if err != nil {
|
||||||
|
return errors.New(e.Error() + "; " + err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
evdev = true
|
||||||
|
}
|
||||||
|
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
if evdev { // Use Linux evdev API
|
||||||
|
ev := inputEvent{}
|
||||||
|
ev.Type = evSnd
|
||||||
|
ev.Code = sndTone
|
||||||
|
ev.Value = int32(freq)
|
||||||
|
|
||||||
|
d := *(*[unsafe.Sizeof(ev)]byte)(unsafe.Pointer(&ev))
|
||||||
|
|
||||||
|
// Start beep
|
||||||
|
f.Write(d[:])
|
||||||
|
|
||||||
|
time.Sleep(time.Duration(duration) * time.Millisecond)
|
||||||
|
|
||||||
|
ev.Value = 0
|
||||||
|
d = *(*[unsafe.Sizeof(ev)]byte)(unsafe.Pointer(&ev))
|
||||||
|
|
||||||
|
// Stop beep
|
||||||
|
f.Write(d[:])
|
||||||
|
} else { // Use ioctl
|
||||||
|
// Start beep
|
||||||
|
err = ioctl(f.Fd(), kiocsound, uintptr(period))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
time.Sleep(time.Duration(duration) * time.Millisecond)
|
||||||
|
|
||||||
|
// Stop beep
|
||||||
|
err = ioctl(f.Fd(), kiocsound, uintptr(0))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
package staros
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
rat float64 = 1.059463094 //2^(1/12)
|
||||||
|
C float64 = 493.8833013 * rat
|
||||||
|
CU = C * rat * rat
|
||||||
|
D = CU * rat
|
||||||
|
DU = D * rat
|
||||||
|
E = DU * rat
|
||||||
|
F = E * rat
|
||||||
|
FU = F * rat
|
||||||
|
G = FU * rat
|
||||||
|
GU = G * rat
|
||||||
|
A = GU * rat
|
||||||
|
AU = A * rat
|
||||||
|
B = AU * rat
|
||||||
|
)
|
||||||
|
|
||||||
|
func beepMusic(qual ...float64) {
|
||||||
|
for _, v := range qual {
|
||||||
|
fmt.Println(v)
|
||||||
|
Beep(v, 700)
|
||||||
|
time.Sleep(time.Millisecond * 1000)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Music(t *testing.T) {
|
||||||
|
beepMusic(G, D, A, AU, A, G, F, D, DU, D, C, D, AU/2, C, G/2, C, D)
|
||||||
|
time.Sleep(time.Second * 3)
|
||||||
|
beepMusic(D,AU,A,G,A,D*2,F*2,G*2,F*2,D*2,D*2,C*2,D*2,DU*2,D*2,AU,A,E,G,FU)
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
// +build windows
|
||||||
|
|
||||||
|
package staros
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// DefaultFreq - frequency, in Hz, middle A
|
||||||
|
DefaultFreq = 587.0
|
||||||
|
// DefaultDuration - duration in milliseconds
|
||||||
|
DefaultDuration = 500
|
||||||
|
)
|
||||||
|
|
||||||
|
// Beep beeps the PC speaker (https://en.wikipedia.org/wiki/PC_speaker).
|
||||||
|
func Beep(freq float64, duration int) error {
|
||||||
|
if freq == 0 {
|
||||||
|
freq = DefaultFreq
|
||||||
|
} else if freq > 32767 {
|
||||||
|
freq = 32767
|
||||||
|
} else if freq < 37 {
|
||||||
|
freq = DefaultFreq
|
||||||
|
}
|
||||||
|
|
||||||
|
if duration == 0 {
|
||||||
|
duration = DefaultDuration
|
||||||
|
}
|
||||||
|
|
||||||
|
kernel32, _ := syscall.LoadLibrary("kernel32.dll")
|
||||||
|
beep32, _ := syscall.GetProcAddress(kernel32, "Beep")
|
||||||
|
|
||||||
|
defer syscall.FreeLibrary(kernel32)
|
||||||
|
|
||||||
|
_, _, e := syscall.Syscall(uintptr(beep32), uintptr(2), uintptr(int(freq)), uintptr(duration), 0)
|
||||||
|
if e != 0 {
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -1,6 +1,18 @@
|
|||||||
package staros
|
package staros
|
||||||
|
|
||||||
import "os"
|
import (
|
||||||
|
"errors"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
var ERR_ALREADY_LOCKED = errors.New("ALREADY LOCKED")
|
||||||
|
var ERR_TIMEOUT = errors.New("TIME OUT")
|
||||||
|
|
||||||
|
func NewFileLock(filepath string) FileLock {
|
||||||
|
return FileLock{
|
||||||
|
filepath: filepath,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 检测文件/文件夹是否存在
|
// 检测文件/文件夹是否存在
|
||||||
func Exists(path string) bool {
|
func Exists(path string) bool {
|
||||||
|
|||||||
@@ -0,0 +1,91 @@
|
|||||||
|
//+build darwin
|
||||||
|
|
||||||
|
package staros
|
||||||
|
|
||||||
|
import (
|
||||||
|
"b612.me/stario"
|
||||||
|
"os"
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type FileLock struct {
|
||||||
|
fd int
|
||||||
|
filepath string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FileLock) openFileForLock() error {
|
||||||
|
fd, err := syscall.Open(f.filepath, syscall.O_CREAT|syscall.O_RDONLY, 0600)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
f.filepath = f.filepath
|
||||||
|
f.fd = fd
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FileLock) Lock(Exclusive bool) error {
|
||||||
|
var lockType int
|
||||||
|
if Exclusive {
|
||||||
|
lockType = syscall.LOCK_EX
|
||||||
|
} else {
|
||||||
|
lockType = syscall.LOCK_SH
|
||||||
|
}
|
||||||
|
if err := f.openFileForLock(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return syscall.Flock(f.fd, lockType)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FileLock) LockNoBlocking(Exclusive bool) error {
|
||||||
|
var lockType int
|
||||||
|
if Exclusive {
|
||||||
|
lockType = syscall.LOCK_EX
|
||||||
|
} else {
|
||||||
|
lockType = syscall.LOCK_SH
|
||||||
|
}
|
||||||
|
if err := f.openFileForLock(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err := syscall.Flock(f.fd, lockType|syscall.LOCK_NB)
|
||||||
|
if err != nil {
|
||||||
|
syscall.Close(f.fd)
|
||||||
|
if err == syscall.EWOULDBLOCK {
|
||||||
|
return ERR_ALREADY_LOCKED
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FileLock) Unlock() error {
|
||||||
|
err := syscall.Flock(f.fd, syscall.LOCK_UN)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return syscall.Close(f.fd)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FileLock) LockWithTimeout(tm time.Duration, Exclusive bool) error {
|
||||||
|
return stario.WaitUntilTimeout(tm, func(tmout chan struct{}) error {
|
||||||
|
err := f.Lock(Exclusive)
|
||||||
|
select {
|
||||||
|
case <-tmout:
|
||||||
|
f.Unlock()
|
||||||
|
return nil
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func timespecToTime(ts syscall.Timespec) time.Time {
|
||||||
|
return time.Unix(int64(ts.Sec), int64(ts.Nsec))
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetFileCreationTime(fileinfo os.FileInfo) time.Time {
|
||||||
|
return timespecToTime(fileinfo.Sys().(*syscall.Stat_t).Ctimespec)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetFileAccessTime(fileinfo os.FileInfo) time.Time {
|
||||||
|
return timespecToTime(fileinfo.Sys().(*syscall.Stat_t).Atimespec)
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package staros
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_FileLock(t *testing.T) {
|
||||||
|
filename := "./test.file"
|
||||||
|
lock := NewFileLock(filename)
|
||||||
|
lock2 := NewFileLock(filename)
|
||||||
|
fmt.Println("lock1", lock.LockNoBlocking(false))
|
||||||
|
time.Sleep(time.Second)
|
||||||
|
fmt.Println("lock2", lock2.LockWithTimeout(time.Second*5, false))
|
||||||
|
fmt.Println("unlock1", lock.Unlock())
|
||||||
|
time.Sleep(time.Second)
|
||||||
|
fmt.Println("unlock2", lock2.Unlock())
|
||||||
|
fmt.Println("lock2", lock2.LockNoBlocking(true))
|
||||||
|
fmt.Println("unlock2", lock2.Unlock())
|
||||||
|
os.Remove(filename)
|
||||||
|
}
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
//+build linux
|
||||||
|
|
||||||
|
package staros
|
||||||
|
|
||||||
|
import (
|
||||||
|
"b612.me/stario"
|
||||||
|
"os"
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type FileLock struct {
|
||||||
|
fd int
|
||||||
|
filepath string
|
||||||
|
}
|
||||||
|
|
||||||
|
func timespecToTime(ts syscall.Timespec) time.Time {
|
||||||
|
return time.Unix(int64(ts.Sec), int64(ts.Nsec))
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetFileCreationTime(fileinfo os.FileInfo) time.Time {
|
||||||
|
return timespecToTime(fileinfo.Sys().(*syscall.Stat_t).Ctim)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetFileAccessTime(fileinfo os.FileInfo) time.Time {
|
||||||
|
return timespecToTime(fileinfo.Sys().(*syscall.Stat_t).Atim)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FileLock) openFileForLock() error {
|
||||||
|
fd, err := syscall.Open(f.filepath, syscall.O_CREAT|syscall.O_RDONLY, 0600)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
f.filepath = f.filepath
|
||||||
|
f.fd = fd
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FileLock) Lock(Exclusive bool) error {
|
||||||
|
var lockType int
|
||||||
|
if Exclusive {
|
||||||
|
lockType = syscall.LOCK_EX
|
||||||
|
} else {
|
||||||
|
lockType = syscall.LOCK_SH
|
||||||
|
}
|
||||||
|
if err := f.openFileForLock(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return syscall.Flock(f.fd, lockType)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FileLock) LockNoBlocking(Exclusive bool) error {
|
||||||
|
var lockType int
|
||||||
|
if Exclusive {
|
||||||
|
lockType = syscall.LOCK_EX
|
||||||
|
} else {
|
||||||
|
lockType = syscall.LOCK_SH
|
||||||
|
}
|
||||||
|
if err := f.openFileForLock(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err := syscall.Flock(f.fd, lockType|syscall.LOCK_NB)
|
||||||
|
if err != nil {
|
||||||
|
syscall.Close(f.fd)
|
||||||
|
if err == syscall.EWOULDBLOCK {
|
||||||
|
return ERR_ALREADY_LOCKED
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FileLock) Unlock() error {
|
||||||
|
err := syscall.Flock(f.fd, syscall.LOCK_UN)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return syscall.Close(f.fd)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FileLock) LockWithTimeout(tm time.Duration, Exclusive bool) error {
|
||||||
|
return stario.WaitUntilTimeout(tm, func(tmout chan struct{}) error {
|
||||||
|
err := f.Lock(Exclusive)
|
||||||
|
select {
|
||||||
|
case <-tmout:
|
||||||
|
f.Unlock()
|
||||||
|
return nil
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -0,0 +1,123 @@
|
|||||||
|
// +build windows
|
||||||
|
|
||||||
|
package staros
|
||||||
|
|
||||||
|
import (
|
||||||
|
"b612.me/win32api"
|
||||||
|
"os"
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type FileLock struct {
|
||||||
|
filepath string
|
||||||
|
handle win32api.HANDLE
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetFileCreationTime(fileinfo os.FileInfo) time.Time {
|
||||||
|
d := fileinfo.Sys().(*syscall.Win32FileAttributeData)
|
||||||
|
return time.Unix(0, d.CreationTime.Nanoseconds())
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetFileAccessTime(fileinfo os.FileInfo) time.Time {
|
||||||
|
d := fileinfo.Sys().(*syscall.Win32FileAttributeData)
|
||||||
|
return time.Unix(0, d.LastAccessTime.Nanoseconds())
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetFileTimes(file *os.File, info os.FileInfo) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetFileTimesbyTime(file *os.File) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FileLock) openFileForLock() error {
|
||||||
|
name, err := syscall.UTF16PtrFromString(f.filepath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
handle, err := syscall.CreateFile(
|
||||||
|
name,
|
||||||
|
syscall.GENERIC_READ,
|
||||||
|
syscall.FILE_SHARE_READ,
|
||||||
|
nil,
|
||||||
|
syscall.OPEN_ALWAYS,
|
||||||
|
syscall.FILE_FLAG_OVERLAPPED|0x00000080,
|
||||||
|
0)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
f.handle = win32api.HANDLE(handle)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FileLock) lockForTimeout(timeout time.Duration, lockType win32api.DWORD) error {
|
||||||
|
var err error
|
||||||
|
if err = f.openFileForLock(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
event, err := win32api.CreateEventW(nil, true, false, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
myEvent := &syscall.Overlapped{HEvent: syscall.Handle(event)}
|
||||||
|
defer syscall.CloseHandle(myEvent.HEvent)
|
||||||
|
_, err = win32api.LockFileEx(f.handle, lockType, 0, 1, 0, myEvent)
|
||||||
|
if err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if err != syscall.ERROR_IO_PENDING {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
millis := uint32(syscall.INFINITE)
|
||||||
|
if timeout >= 0 {
|
||||||
|
millis = uint32(timeout.Nanoseconds() / 1000000)
|
||||||
|
}
|
||||||
|
s, err := syscall.WaitForSingleObject(myEvent.HEvent, millis)
|
||||||
|
switch s {
|
||||||
|
case syscall.WAIT_OBJECT_0:
|
||||||
|
// success!
|
||||||
|
return nil
|
||||||
|
case syscall.WAIT_TIMEOUT:
|
||||||
|
f.Unlock()
|
||||||
|
return ERR_TIMEOUT
|
||||||
|
default:
|
||||||
|
f.Unlock()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FileLock) Lock(Exclusive bool) error {
|
||||||
|
var lockType win32api.DWORD
|
||||||
|
if Exclusive {
|
||||||
|
lockType = win32api.LOCKFILE_EXCLUSIVE_LOCK
|
||||||
|
} else {
|
||||||
|
lockType = 0
|
||||||
|
}
|
||||||
|
return f.lockForTimeout(0, lockType)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FileLock) LockWithTimeout(tm time.Duration, Exclusive bool) error {
|
||||||
|
var lockType win32api.DWORD
|
||||||
|
if Exclusive {
|
||||||
|
lockType = win32api.LOCKFILE_EXCLUSIVE_LOCK
|
||||||
|
} else {
|
||||||
|
lockType = 0
|
||||||
|
}
|
||||||
|
return f.lockForTimeout(tm, lockType)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FileLock) LockNoBlocking(Exclusive bool) error {
|
||||||
|
var lockType win32api.DWORD
|
||||||
|
if Exclusive {
|
||||||
|
lockType = win32api.LOCKFILE_EXCLUSIVE_LOCK
|
||||||
|
} else {
|
||||||
|
lockType = 0
|
||||||
|
}
|
||||||
|
return f.lockForTimeout(0, lockType|win32api.LOCKFILE_FAIL_IMMEDIATELY)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FileLock) Unlock() error {
|
||||||
|
return syscall.Close(syscall.Handle(f.handle))
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
module b612.me/staros
|
||||||
|
|
||||||
|
go 1.16
|
||||||
|
|
||||||
|
require (
|
||||||
|
b612.me/stario v0.0.7
|
||||||
|
b612.me/win32api v0.0.1
|
||||||
|
b612.me/wincmd v0.0.2
|
||||||
|
golang.org/x/sys v0.4.0
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
golang.org/x/crypto v0.0.0-20220321153916-2c7772ba3064 // indirect
|
||||||
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
|
||||||
|
)
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
b612.me/stario v0.0.7 h1:QbQcsHCVLE6vRgVrPN4+9DGiSaC6IWdtm4ClL2tpMUg=
|
||||||
|
b612.me/stario v0.0.7/go.mod h1:or4ssWcxQSjMeu+hRKEgtp0X517b3zdlEOAms8Qscvw=
|
||||||
|
b612.me/win32api v0.0.1 h1:vLFB1xhO6pd9+zB2EyaapKB459Urv3v+C1YwgwOFEWo=
|
||||||
|
b612.me/win32api v0.0.1/go.mod h1:MHu0JBQjzxQ2yxpZPUBbn5un45o67eF5iWKa4Q9e0yE=
|
||||||
|
b612.me/wincmd v0.0.2 h1:Ub1WtelVT6a3vD4B6zDYo3UPO/t9ymnI3x1dQPJcrGw=
|
||||||
|
b612.me/wincmd v0.0.2/go.mod h1:bwpyCKfSDY8scSMo3Lrd0Qnqvpz7/CILL7oodfG0wgo=
|
||||||
|
golang.org/x/crypto v0.0.0-20220313003712-b769efc7c000/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
|
golang.org/x/crypto v0.0.0-20220321153916-2c7772ba3064 h1:S25/rfnfsMVgORT4/J61MJ7rdyseOZOyvLIrZEZ7s6s=
|
||||||
|
golang.org/x/crypto v0.0.0-20220321153916-2c7772ba3064/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
|
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18=
|
||||||
|
golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
|
||||||
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
@@ -0,0 +1,305 @@
|
|||||||
|
package staros
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"math"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Calc(math string) (float64, error) {
|
||||||
|
math = strings.Replace(math, " ", "", -1)
|
||||||
|
math = strings.ToLower(math)
|
||||||
|
if err := check(math); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
result,err:=calc(math)
|
||||||
|
if err!=nil {
|
||||||
|
return 0,err
|
||||||
|
}
|
||||||
|
return floatRound(result,15),nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func floatRound(f float64, n int) float64 {
|
||||||
|
format := "%." + strconv.Itoa(n) + "f"
|
||||||
|
res, _ := strconv.ParseFloat(fmt.Sprintf(format, f), 64)
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
func check(math string) error {
|
||||||
|
math = strings.Replace(math, " ", "", -1)
|
||||||
|
math = strings.ToLower(math)
|
||||||
|
var bracketSum int
|
||||||
|
var signReady bool
|
||||||
|
for k, v := range math {
|
||||||
|
if string([]rune{v}) == "(" {
|
||||||
|
bracketSum++
|
||||||
|
}
|
||||||
|
if string([]rune{v}) == ")" {
|
||||||
|
bracketSum--
|
||||||
|
}
|
||||||
|
if bracketSum < 0 {
|
||||||
|
return fmt.Errorf("err at position %d.Reason is right bracket position not correct,except (", k)
|
||||||
|
}
|
||||||
|
if containSign(string([]rune{v})) {
|
||||||
|
if signReady {
|
||||||
|
if string([]rune{v}) != "+" && string([]rune{v}) != "-" {
|
||||||
|
return fmt.Errorf("err at position %d.Reason is sign %s not correct", k, string([]rune{v}))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
signReady = true
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
signReady = false
|
||||||
|
}
|
||||||
|
if bracketSum != 0 {
|
||||||
|
return fmt.Errorf("Error:right bracket is not equal as left bracket")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func calc(math string) (float64, error) {
|
||||||
|
var bracketLeft int
|
||||||
|
var bracketRight int
|
||||||
|
var DupStart int = -1
|
||||||
|
for pos, str := range math {
|
||||||
|
if string(str) == "(" {
|
||||||
|
bracketLeft = pos
|
||||||
|
}
|
||||||
|
if string(str) == ")" {
|
||||||
|
bracketRight = pos
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if bracketRight == 0 && bracketLeft != 0 || (bracketLeft > bracketRight) {
|
||||||
|
return 0, fmt.Errorf("Error:bracket not correct at %d ,except )", bracketLeft)
|
||||||
|
}
|
||||||
|
if bracketRight == 0 && bracketLeft == 0 {
|
||||||
|
return calcLong(math)
|
||||||
|
}
|
||||||
|
line := math[bracketLeft+1 : bracketRight]
|
||||||
|
num, err := calcLong(line)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
for i := bracketLeft - 1; i >= 0; i-- {
|
||||||
|
if !containSign(math[i : i+1]) {
|
||||||
|
DupStart = i
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if DupStart != -1 {
|
||||||
|
sign := math[DupStart:bracketLeft]
|
||||||
|
num, err := calcDuaFloat(sign, num)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
math = math[:DupStart] + fmt.Sprintf("%.15f", num) + math[bracketRight+1:]
|
||||||
|
DupStart = -1
|
||||||
|
} else {
|
||||||
|
math = math[:bracketLeft] + fmt.Sprintf("%.15f", num) + math[bracketRight+1:]
|
||||||
|
}
|
||||||
|
return calc(math)
|
||||||
|
}
|
||||||
|
|
||||||
|
func calcLong(str string) (float64, error) {
|
||||||
|
var sigReady bool = false
|
||||||
|
var sigApply bool = false
|
||||||
|
var numPool []float64
|
||||||
|
var operPool []string
|
||||||
|
var numStr string
|
||||||
|
var oper string
|
||||||
|
if str[0:1] == "+" || str[0:1] == "-" {
|
||||||
|
sigReady = true
|
||||||
|
}
|
||||||
|
for _, stp := range str {
|
||||||
|
if sigReady && containSign(string(stp)) {
|
||||||
|
sigReady = false
|
||||||
|
sigApply = true
|
||||||
|
oper = string(stp)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if !containSign(string(stp)) {
|
||||||
|
sigReady = false
|
||||||
|
numStr = string(append([]rune(numStr), stp))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if !sigReady {
|
||||||
|
sigReady = true
|
||||||
|
}
|
||||||
|
if sigApply {
|
||||||
|
num, err := calcDua(oper, numStr)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
sigApply = false
|
||||||
|
numPool = append(numPool, num)
|
||||||
|
} else {
|
||||||
|
num, err := parseNumbic(numStr)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
numPool = append(numPool, num)
|
||||||
|
}
|
||||||
|
numStr = ""
|
||||||
|
operPool = append(operPool, string(stp))
|
||||||
|
}
|
||||||
|
if sigApply {
|
||||||
|
num, err := calcDua(oper, numStr)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
numPool = append(numPool, num)
|
||||||
|
} else {
|
||||||
|
num, err := parseNumbic(numStr)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
numPool = append(numPool, num)
|
||||||
|
}
|
||||||
|
return calcPool(numPool, operPool)
|
||||||
|
}
|
||||||
|
|
||||||
|
func calcPool(numPool []float64, operPool []string) (float64, error) {
|
||||||
|
if len(numPool) == 1 && len(operPool) == 0 {
|
||||||
|
return numPool[0], nil
|
||||||
|
}
|
||||||
|
if len(numPool) < len(operPool) {
|
||||||
|
return 0, errors.New(("Operate Signal Is too much"))
|
||||||
|
}
|
||||||
|
calcFunc := func(k int, v string) (float64, error) {
|
||||||
|
num, err := calcSigFloat(numPool[k], v, numPool[k+1])
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
tmp := append(numPool[:k], num)
|
||||||
|
numPool = append(tmp, numPool[k+2:]...)
|
||||||
|
operPool = append(operPool[:k], operPool[k+1:]...)
|
||||||
|
return calcPool(numPool, operPool)
|
||||||
|
}
|
||||||
|
for k, v := range operPool {
|
||||||
|
if v == "^" {
|
||||||
|
return calcFunc(k, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for k, v := range operPool {
|
||||||
|
if v == "*" || v == "/" {
|
||||||
|
return calcFunc(k, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for k, v := range operPool {
|
||||||
|
return calcFunc(k, v)
|
||||||
|
}
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func calcSigFloat(floatA float64, b string, floatC float64) (float64, error) {
|
||||||
|
switch b {
|
||||||
|
case "+":
|
||||||
|
return floatRound(floatA + floatC,15), nil
|
||||||
|
case "-":
|
||||||
|
return floatRound(floatA - floatC,15), nil
|
||||||
|
case "*":
|
||||||
|
return floatRound(floatA * floatC,15), nil
|
||||||
|
case "/":
|
||||||
|
if floatC == 0 {
|
||||||
|
return 0, errors.New("Divisor cannot be 0")
|
||||||
|
}
|
||||||
|
return floatRound(floatA / floatC,15), nil
|
||||||
|
case "^":
|
||||||
|
return math.Pow(floatA, floatC), nil
|
||||||
|
}
|
||||||
|
return 0, fmt.Errorf("unexpect method:%s", b)
|
||||||
|
}
|
||||||
|
|
||||||
|
func calcSig(a, b, c string) (float64, error) {
|
||||||
|
floatA, err := parseNumbic(a)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
floatC, err := parseNumbic(c)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return calcSigFloat(floatA, b, floatC)
|
||||||
|
}
|
||||||
|
|
||||||
|
func calcDuaFloat(a string, floatB float64) (float64, error) {
|
||||||
|
switch a {
|
||||||
|
case "sin":
|
||||||
|
return math.Sin(floatB), nil
|
||||||
|
case "cos":
|
||||||
|
return math.Cos(floatB), nil
|
||||||
|
case "tan":
|
||||||
|
return math.Tan(floatB), nil
|
||||||
|
case "abs":
|
||||||
|
return math.Abs(floatB), nil
|
||||||
|
case "arcsin":
|
||||||
|
return math.Asin(floatB), nil
|
||||||
|
case "arccos":
|
||||||
|
return math.Acos(floatB), nil
|
||||||
|
case "arctan":
|
||||||
|
return math.Atan(floatB), nil
|
||||||
|
case "sqrt":
|
||||||
|
return math.Sqrt(floatB), nil
|
||||||
|
case "loge":
|
||||||
|
return math.Log(floatB), nil
|
||||||
|
case "log10":
|
||||||
|
return math.Log10(floatB), nil
|
||||||
|
case "log2":
|
||||||
|
return math.Log2(floatB), nil
|
||||||
|
case "floor":
|
||||||
|
return math.Floor(floatB), nil
|
||||||
|
case "ceil":
|
||||||
|
return math.Ceil(floatB), nil
|
||||||
|
case "round":
|
||||||
|
return math.Round(floatB), nil
|
||||||
|
case "trunc":
|
||||||
|
return math.Trunc(floatB), nil
|
||||||
|
case "+":
|
||||||
|
return 0 + floatB, nil
|
||||||
|
case "-":
|
||||||
|
return 0 - floatB, nil
|
||||||
|
}
|
||||||
|
return 0, fmt.Errorf("unexpect method:%s", a)
|
||||||
|
}
|
||||||
|
func calcDua(a, b string) (float64, error) {
|
||||||
|
floatB, err := parseNumbic(b)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return calcDuaFloat(a, floatB)
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseNumbic(str string) (float64, error) {
|
||||||
|
switch str {
|
||||||
|
case "pi":
|
||||||
|
return float64(math.Pi), nil
|
||||||
|
case "e":
|
||||||
|
return float64(math.E), nil
|
||||||
|
default:
|
||||||
|
return strconv.ParseFloat(str, 64)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func containSign(str string) bool {
|
||||||
|
var sign []string = []string{"+", "-", "*", "/", "^"}
|
||||||
|
for _, v := range sign {
|
||||||
|
if str == v {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func contain(pool []string, str string) bool {
|
||||||
|
for _, v := range pool {
|
||||||
|
if v == str {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
@@ -0,0 +1,101 @@
|
|||||||
|
//+build darwin
|
||||||
|
|
||||||
|
package staros
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"fmt"
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
"os/exec"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Memory 系统内存信息
|
||||||
|
func Memory() (MemStatus,error) {
|
||||||
|
return darwinMemory()
|
||||||
|
}
|
||||||
|
|
||||||
|
type swapUsage struct {
|
||||||
|
Total uint64
|
||||||
|
Avail uint64
|
||||||
|
Used uint64
|
||||||
|
Pagesize int32
|
||||||
|
Encrypted bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func darwinMemory() (MemStatus, error) {
|
||||||
|
var err error
|
||||||
|
var res MemStatus
|
||||||
|
vm_stat, err := exec.LookPath("vm_stat")
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
out, err := exec.Command(vm_stat).CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
totalString, err := unix.Sysctl("hw.memsize")
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// unix.sysctl() helpfully assumes the result is a null-terminated string and
|
||||||
|
// removes the last byte of the result if it's 0 :/
|
||||||
|
totalString += "\x00"
|
||||||
|
|
||||||
|
res.All = uint64(binary.LittleEndian.Uint64([]byte(totalString)))
|
||||||
|
|
||||||
|
lines := strings.Split(string(out), "\n")
|
||||||
|
pagesize := uint64(unix.Getpagesize())
|
||||||
|
for _, line := range lines {
|
||||||
|
fields := strings.Split(line, ":")
|
||||||
|
if len(fields) < 2 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
key := strings.TrimSpace(fields[0])
|
||||||
|
value := strings.Trim(fields[1], " .")
|
||||||
|
switch key {
|
||||||
|
case "Pages free":
|
||||||
|
free, e := strconv.ParseUint(value, 10, 64)
|
||||||
|
if e != nil {
|
||||||
|
err = e
|
||||||
|
}
|
||||||
|
res.Free = free * pagesize
|
||||||
|
case "Pages inactive":
|
||||||
|
inactive, e := strconv.ParseUint(value, 10, 64)
|
||||||
|
if e != nil {
|
||||||
|
err = e
|
||||||
|
}
|
||||||
|
res.Available = inactive * pagesize
|
||||||
|
case "Pages active":
|
||||||
|
active, e := strconv.ParseUint(value, 10, 64)
|
||||||
|
if e != nil {
|
||||||
|
err = e
|
||||||
|
}
|
||||||
|
_ = active * pagesize
|
||||||
|
case "Pages wired down":
|
||||||
|
wired, e := strconv.ParseUint(value, 10, 64)
|
||||||
|
if e != nil {
|
||||||
|
err = e
|
||||||
|
}
|
||||||
|
_ = wired * pagesize
|
||||||
|
}
|
||||||
|
}
|
||||||
|
res.Available += res.Free
|
||||||
|
res.Used = res.All - res.Available
|
||||||
|
//swap
|
||||||
|
value, err := unix.SysctlRaw("vm.swapusage")
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
if len(value) != 32 {
|
||||||
|
return res, fmt.Errorf("unexpected output of sysctl vm.swapusage: %v (len: %d)", value, len(value))
|
||||||
|
}
|
||||||
|
swap := (*swapUsage)(unsafe.Pointer(&value[0]))
|
||||||
|
res.SwapAll = swap.Total
|
||||||
|
res.SwapUsed = swap.Used
|
||||||
|
res.SwapFree = swap.Avail
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
//+build linux
|
||||||
|
|
||||||
|
package staros
|
||||||
|
|
||||||
|
import "syscall"
|
||||||
|
|
||||||
|
// Memory 系统内存信息
|
||||||
|
func Memory() (MemStatus, error) {
|
||||||
|
var mem MemStatus
|
||||||
|
ram := new(syscall.Sysinfo_t)
|
||||||
|
if err := syscall.Sysinfo(ram); err != nil {
|
||||||
|
return mem, err
|
||||||
|
}
|
||||||
|
mem.All = uint64(ram.Totalram)
|
||||||
|
mem.BuffCache = uint64(ram.Bufferram)
|
||||||
|
mem.Free = uint64(ram.Freeram)
|
||||||
|
mem.Shared = uint64(ram.Sharedram)
|
||||||
|
mem.Available = uint64(ram.Freeram + ram.Sharedram + ram.Bufferram)
|
||||||
|
mem.SwapAll = uint64(ram.Totalswap)
|
||||||
|
mem.SwapFree = uint64(ram.Freeswap)
|
||||||
|
mem.SwapUsed = uint64(mem.SwapAll - mem.SwapFree)
|
||||||
|
mem.Used = uint64(mem.All - mem.Free)
|
||||||
|
return mem, nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
// +build windows
|
||||||
|
|
||||||
|
package staros
|
||||||
|
|
||||||
|
import "b612.me/win32api"
|
||||||
|
|
||||||
|
// Memory 系统内存信息
|
||||||
|
func Memory() (MemStatus, error) {
|
||||||
|
var mem MemStatus
|
||||||
|
ram := new(win32api.MEMORYSTATUSEX)
|
||||||
|
_, err := win32api.GlobalMemoryStatusEx(ram)
|
||||||
|
if err != nil {
|
||||||
|
return mem, err
|
||||||
|
}
|
||||||
|
mem.All = uint64(ram.UllTotalPhys)
|
||||||
|
mem.Free = uint64(ram.UllAvailPhys)
|
||||||
|
mem.Available = uint64(ram.UllAvailPhys)
|
||||||
|
mem.Used = uint64(mem.All - mem.Free)
|
||||||
|
mem.SwapAll = uint64(ram.UllTotalPageFile)
|
||||||
|
mem.SwapFree = uint64(ram.UllAvailPageFile)
|
||||||
|
mem.SwapUsed = mem.SwapAll - mem.SwapFree
|
||||||
|
mem.VirtualAll = uint64(mem.VirtualAll)
|
||||||
|
mem.VirtualAvail = uint64(mem.VirtualAvail)
|
||||||
|
mem.VirtualUsed = mem.VirtualAll - mem.VirtualUsed
|
||||||
|
return mem, nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package staros
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_TrimSpace(t *testing.T) {
|
||||||
|
|
||||||
|
}
|
||||||
+326
@@ -0,0 +1,326 @@
|
|||||||
|
//go:build !windows
|
||||||
|
// +build !windows
|
||||||
|
|
||||||
|
package staros
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NetUsage() ([]NetAdapter, error) {
|
||||||
|
data, err := ioutil.ReadFile("/proc/net/dev")
|
||||||
|
if err != nil {
|
||||||
|
return []NetAdapter{}, err
|
||||||
|
}
|
||||||
|
sps := strings.Split(strings.TrimSpace(string(data)), "\n")
|
||||||
|
if len(sps) < 3 {
|
||||||
|
return []NetAdapter{}, errors.New("No Adaptor")
|
||||||
|
}
|
||||||
|
var res []NetAdapter
|
||||||
|
netLists := sps[2:]
|
||||||
|
for _, v := range netLists {
|
||||||
|
v = strings.ReplaceAll(v, " ", " ")
|
||||||
|
for strings.Contains(v, " ") {
|
||||||
|
v = strings.ReplaceAll(v, " ", " ")
|
||||||
|
}
|
||||||
|
v = strings.TrimSpace(v)
|
||||||
|
card := strings.Split(v, " ")
|
||||||
|
name := strings.ReplaceAll(card[0], ":", "")
|
||||||
|
recvBytes, _ := strconv.Atoi(card[1])
|
||||||
|
sendBytes, _ := strconv.Atoi(card[9])
|
||||||
|
res = append(res, NetAdapter{name, uint64(recvBytes), uint64(sendBytes)})
|
||||||
|
}
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func NetUsageByname(name string) (NetAdapter, error) {
|
||||||
|
ada, err := NetUsage()
|
||||||
|
if err != nil {
|
||||||
|
return NetAdapter{}, err
|
||||||
|
}
|
||||||
|
for _, v := range ada {
|
||||||
|
if v.Name == name {
|
||||||
|
return v, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NetAdapter{}, errors.New("Not Found")
|
||||||
|
}
|
||||||
|
|
||||||
|
func NetSpeeds(duration time.Duration) ([]NetSpeed, error) {
|
||||||
|
list1, err := NetUsage()
|
||||||
|
if err != nil {
|
||||||
|
return []NetSpeed{}, err
|
||||||
|
}
|
||||||
|
time.Sleep(duration)
|
||||||
|
list2, err := NetUsage()
|
||||||
|
if err != nil {
|
||||||
|
return []NetSpeed{}, err
|
||||||
|
}
|
||||||
|
if len(list1) > len(list2) {
|
||||||
|
return []NetSpeed{}, errors.New("NetWork Adaptor Num Not ok")
|
||||||
|
}
|
||||||
|
var res []NetSpeed
|
||||||
|
for k, v := range list1 {
|
||||||
|
recv := float64(list2[k].RecvBytes-v.RecvBytes) / duration.Seconds()
|
||||||
|
send := float64(list2[k].SendBytes-v.SendBytes) / duration.Seconds()
|
||||||
|
res = append(res, NetSpeed{
|
||||||
|
Name: v.Name,
|
||||||
|
RecvSpeeds: recv,
|
||||||
|
SendSpeeds: send,
|
||||||
|
RecvBytes: list2[k].RecvBytes,
|
||||||
|
SendBytes: list2[k].SendBytes,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func NetSpeedsByName(duration time.Duration, name string) (NetSpeed, error) {
|
||||||
|
ada, err := NetSpeeds(duration)
|
||||||
|
if err != nil {
|
||||||
|
return NetSpeed{}, err
|
||||||
|
}
|
||||||
|
for _, v := range ada {
|
||||||
|
if v.Name == name {
|
||||||
|
return v, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NetSpeed{}, errors.New("Not Found")
|
||||||
|
}
|
||||||
|
|
||||||
|
// NetConnections return all TCP/UDP/UNIX DOMAIN SOCKET Connections
|
||||||
|
// if your uid != 0 ,and analysePid==true ,you should have CAP_SYS_PRTACE and CAP_DAC_OVERRIDE/CAP_DAC_READ_SEARCH Caps
|
||||||
|
func NetConnections(analysePid bool, types string) ([]NetConn, error) {
|
||||||
|
var result []NetConn
|
||||||
|
var inodeMap map[string]int64
|
||||||
|
var err error
|
||||||
|
var fileList []string
|
||||||
|
if types == "" || strings.Contains(strings.ToLower(types), "all") {
|
||||||
|
fileList = []string{
|
||||||
|
"/proc/net/tcp",
|
||||||
|
"/proc/net/tcp6",
|
||||||
|
"/proc/net/udp",
|
||||||
|
"/proc/net/udp6",
|
||||||
|
"/proc/net/unix",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if strings.Contains(strings.ToLower(types), "tcp") {
|
||||||
|
fileList = append(fileList, "/proc/net/tcp", "/proc/net/tcp6")
|
||||||
|
}
|
||||||
|
if strings.Contains(strings.ToLower(types), "udp") {
|
||||||
|
fileList = append(fileList, "/proc/net/udp", "/proc/net/udp6")
|
||||||
|
}
|
||||||
|
if strings.Contains(strings.ToLower(types), "unix") {
|
||||||
|
fileList = append(fileList, "/proc/net/unix")
|
||||||
|
}
|
||||||
|
if analysePid {
|
||||||
|
inodeMap, err = GetInodeMap()
|
||||||
|
if err != nil {
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, file := range fileList {
|
||||||
|
data, err := ioutil.ReadFile(file)
|
||||||
|
if err != nil {
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
tmpRes, err := analyseNetFiles(data, inodeMap, file[strings.LastIndex(file, "/")+1:])
|
||||||
|
if err != nil {
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
result = append(result, tmpRes...)
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetInodeMap() (map[string]int64, error) {
|
||||||
|
res := make(map[string]int64)
|
||||||
|
paths, err := ioutil.ReadDir("/proc")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, v := range paths {
|
||||||
|
if v.IsDir() && Exists("/proc/"+v.Name()+"/fd") {
|
||||||
|
fds, err := ioutil.ReadDir("/proc/" + v.Name() + "/fd")
|
||||||
|
if err != nil && Exists("/proc/"+v.Name()+"/fd") {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, fd := range fds {
|
||||||
|
socket, err := os.Readlink("/proc/" + v.Name() + "/fd/" + fd.Name())
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if !strings.Contains(socket, "socket") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
start := strings.Index(socket, "[")
|
||||||
|
if start < 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
pid, err := strconv.ParseInt(v.Name(), 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
res[socket[start+1:len(socket)-1]] = pid
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func analyseNetFiles(data []byte, inodeMap map[string]int64, typed string) ([]NetConn, error) {
|
||||||
|
if typed == "unix" {
|
||||||
|
return analyseUnixFiles(data, inodeMap, typed)
|
||||||
|
}
|
||||||
|
var result []NetConn
|
||||||
|
strdata := strings.TrimSpace(string(data))
|
||||||
|
strdata = remainOne(strdata, " ", " ")
|
||||||
|
csvData := strings.Split(strdata, "\n")
|
||||||
|
pidMap := make(map[int64]*Process)
|
||||||
|
for line, lineData := range csvData {
|
||||||
|
if line == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
v := strings.Split(strings.TrimSpace(lineData), " ")
|
||||||
|
var res NetConn
|
||||||
|
ip, port, err := parseHexIpPort(v[1])
|
||||||
|
if err != nil {
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
res.LocalAddr = ip
|
||||||
|
res.LocalPort = port
|
||||||
|
ip, port, err = parseHexIpPort(v[2])
|
||||||
|
if err != nil {
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
res.RemoteAddr = ip
|
||||||
|
res.RemotePort = port
|
||||||
|
//connection state
|
||||||
|
if strings.Contains(typed, "tcp") {
|
||||||
|
state, err := strconv.ParseInt(strings.TrimSpace(v[3]), 16, 64)
|
||||||
|
if err != nil {
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
res.Status = TCP_STATE[state]
|
||||||
|
}
|
||||||
|
txrx_queue := strings.Split(strings.TrimSpace(v[4]), ":")
|
||||||
|
if len(txrx_queue) != 2 {
|
||||||
|
return result, errors.New("not a valid net file")
|
||||||
|
}
|
||||||
|
tx_queue, err := strconv.ParseInt(txrx_queue[0], 16, 64)
|
||||||
|
if err != nil {
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
res.TX_Queue = tx_queue
|
||||||
|
rx_queue, err := strconv.ParseInt(txrx_queue[1], 16, 64)
|
||||||
|
if err != nil {
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
res.RX_Queue = rx_queue
|
||||||
|
timer := strings.Split(strings.TrimSpace(v[5]), ":")
|
||||||
|
if len(timer) != 2 {
|
||||||
|
return result, errors.New("not a valid net file")
|
||||||
|
}
|
||||||
|
switch timer[0] {
|
||||||
|
case "00":
|
||||||
|
res.TimerActive = "NO_TIMER"
|
||||||
|
case "01":
|
||||||
|
//重传定时器
|
||||||
|
res.TimerActive = "RETRANSMIT"
|
||||||
|
case "02":
|
||||||
|
//连接定时器、FIN_WAIT_2定时器或TCP保活定时器
|
||||||
|
res.TimerActive = "KEEPALIVE"
|
||||||
|
case "03":
|
||||||
|
//TIME_WAIT定时器
|
||||||
|
res.TimerActive = "TIME_WAIT"
|
||||||
|
case "04":
|
||||||
|
//持续定时器
|
||||||
|
res.TimerActive = "ZERO_WINDOW_PROBE"
|
||||||
|
default:
|
||||||
|
res.TimerActive = "UNKNOWN"
|
||||||
|
}
|
||||||
|
timerJif, err := strconv.ParseInt(timer[1], 16, 64)
|
||||||
|
if err != nil {
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
res.TimerJiffies = timerJif
|
||||||
|
timerCnt, err := strconv.ParseInt(strings.TrimSpace(v[6]), 16, 64)
|
||||||
|
if err != nil {
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
res.RtoTimer = timerCnt
|
||||||
|
res.Uid, err = strconv.ParseInt(v[7], 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
res.Inode = v[9]
|
||||||
|
if inodeMap != nil && len(inodeMap) > 0 {
|
||||||
|
var ok bool
|
||||||
|
res.Pid, ok = inodeMap[res.Inode]
|
||||||
|
if !ok {
|
||||||
|
res.Pid = -1
|
||||||
|
} else {
|
||||||
|
_, ok := pidMap[res.Pid]
|
||||||
|
if !ok {
|
||||||
|
tmp, err := FindProcessByPid(res.Pid)
|
||||||
|
if err != nil {
|
||||||
|
pidMap[res.Pid] = nil
|
||||||
|
} else {
|
||||||
|
pidMap[res.Pid] = &tmp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
res.Process = pidMap[res.Pid]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
res.Typed = typed
|
||||||
|
result = append(result, res)
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func analyseUnixFiles(data []byte, inodeMap map[string]int64, typed string) ([]NetConn, error) {
|
||||||
|
var result []NetConn
|
||||||
|
strdata := strings.TrimSpace(string(data))
|
||||||
|
strdata = remainOne(strdata, " ", " ")
|
||||||
|
csvData := strings.Split(strdata, "\n")
|
||||||
|
pidMap := make(map[int64]*Process)
|
||||||
|
for line, lineData := range csvData {
|
||||||
|
if line == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
v := strings.Split(strings.TrimSpace(lineData), " ")
|
||||||
|
var res NetConn
|
||||||
|
res.Inode = v[6]
|
||||||
|
if len(v) == 8 {
|
||||||
|
res.Socket = v[7]
|
||||||
|
}
|
||||||
|
if inodeMap != nil && len(inodeMap) > 0 {
|
||||||
|
var ok bool
|
||||||
|
res.Pid, ok = inodeMap[res.Inode]
|
||||||
|
if !ok {
|
||||||
|
res.Pid = -1
|
||||||
|
} else {
|
||||||
|
_, ok := pidMap[res.Pid]
|
||||||
|
if !ok || pidMap[res.Pid] == nil {
|
||||||
|
tmp, err := FindProcessByPid(res.Pid)
|
||||||
|
if err != nil {
|
||||||
|
pidMap[res.Pid] = nil
|
||||||
|
} else {
|
||||||
|
pidMap[res.Pid] = &tmp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if pidMap[res.Pid] != nil {
|
||||||
|
res.Uid = int64(pidMap[res.Pid].RUID)
|
||||||
|
res.Process = pidMap[res.Pid]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
res.Typed = typed
|
||||||
|
result = append(result, res)
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
// +build windows
|
||||||
|
|
||||||
|
package staros
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NetUsage() ([]NetAdapter, error) {
|
||||||
|
var res []NetAdapter
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func NetUsageByname(name string) (NetAdapter, error) {
|
||||||
|
return NetAdapter{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func NetSpeeds(duration time.Duration) ([]NetSpeed, error) {
|
||||||
|
var res []NetSpeed
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func NetSpeedsByName(duration time.Duration, name string) (NetSpeed, error) {
|
||||||
|
|
||||||
|
return NetSpeed{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NetConnections return all TCP/UDP/UNIX DOMAIN SOCKET Connections
|
||||||
|
// if your uid != 0 ,and analysePid==true ,you should have CAP_SYS_PRTACE and CAP_DAC_OVERRIDE/CAP_DAC_READ_SEARCH Caps
|
||||||
|
func NetConnections(analysePid bool) ([]NetConn, error) {
|
||||||
|
var result []NetConn
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
+56
-25
@@ -1,8 +1,9 @@
|
|||||||
// +build linux darwin
|
// +build linux darwin unix
|
||||||
|
|
||||||
package staros
|
package staros
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os/user"
|
"os/user"
|
||||||
@@ -12,6 +13,8 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var clockTicks = 100 // default value
|
||||||
|
|
||||||
// StartTime 开机时间
|
// StartTime 开机时间
|
||||||
func StartTime() time.Time {
|
func StartTime() time.Time {
|
||||||
tmp, _ := readAsString("/proc/stat")
|
tmp, _ := readAsString("/proc/stat")
|
||||||
@@ -29,25 +32,6 @@ func IsRoot() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Memory 系统内存信息
|
|
||||||
func Memory() MemStatus {
|
|
||||||
var mem MemStatus
|
|
||||||
ram := new(syscall.Sysinfo_t)
|
|
||||||
if err := syscall.Sysinfo(ram); err != nil {
|
|
||||||
return mem
|
|
||||||
}
|
|
||||||
mem.All = ram.Totalram
|
|
||||||
mem.BuffCache = ram.Bufferram
|
|
||||||
mem.Free = ram.Freeram
|
|
||||||
mem.Shared = ram.Sharedram
|
|
||||||
mem.Available = ram.Freeram + ram.Sharedram + ram.Bufferram
|
|
||||||
mem.SwapAll = ram.Totalswap
|
|
||||||
mem.SwapFree = ram.Freeswap
|
|
||||||
mem.SwapUsed = mem.SwapAll - mem.SwapFree
|
|
||||||
mem.Used = mem.All - mem.Free
|
|
||||||
return mem
|
|
||||||
}
|
|
||||||
|
|
||||||
func Whoami() (uid, gid int, uname, gname, home string, err error) {
|
func Whoami() (uid, gid int, uname, gname, home string, err error) {
|
||||||
var me *user.User
|
var me *user.User
|
||||||
var gup *user.Group
|
var gup *user.Group
|
||||||
@@ -82,9 +66,9 @@ func getCPUSample() (idle, total uint64) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Error: ", i, fields[i], err)
|
fmt.Println("Error: ", i, fields[i], err)
|
||||||
}
|
}
|
||||||
total += val // tally up all the numbers to get total ticks
|
total += val // tally up all the numbers to get total ticks
|
||||||
if i == 4 { // idle is the 5th field in the cpu line
|
if i == 4 || i == 5 { // idle is the 5th field in the cpu line
|
||||||
idle = val
|
idle += val
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
@@ -92,6 +76,55 @@ func getCPUSample() (idle, total uint64) {
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
func splitProcStat(content []byte) []string {
|
||||||
|
nameStart := bytes.IndexByte(content, '(')
|
||||||
|
nameEnd := bytes.LastIndexByte(content, ')')
|
||||||
|
restFields := strings.Fields(string(content[nameEnd+2:])) // +2 skip ') '
|
||||||
|
name := content[nameStart+1 : nameEnd]
|
||||||
|
pid := strings.TrimSpace(string(content[:nameStart]))
|
||||||
|
fields := make([]string, 3, len(restFields)+3)
|
||||||
|
fields[1] = string(pid)
|
||||||
|
fields[2] = string(name)
|
||||||
|
fields = append(fields, restFields...)
|
||||||
|
return fields
|
||||||
|
}
|
||||||
|
|
||||||
|
func getCPUSampleByPid(pid int) float64 {
|
||||||
|
contents, err := ioutil.ReadFile("/proc/" + strconv.Itoa(pid) + "/stat")
|
||||||
|
if err != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
fields := splitProcStat(contents)
|
||||||
|
utime, err := strconv.ParseFloat(fields[14], 64)
|
||||||
|
if err != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
stime, err := strconv.ParseFloat(fields[15], 64)
|
||||||
|
if err != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// There is no such thing as iotime in stat file. As an approximation, we
|
||||||
|
// will use delayacct_blkio_ticks (aggregated block I/O delays, as per Linux
|
||||||
|
// docs). Note: I am assuming at least Linux 2.6.18
|
||||||
|
var iotime float64
|
||||||
|
if len(fields) > 42 {
|
||||||
|
iotime, err = strconv.ParseFloat(fields[42], 64)
|
||||||
|
if err != nil {
|
||||||
|
iotime = 0 // Ancient linux version, most likely
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
iotime = 0 // e.g. SmartOS containers
|
||||||
|
}
|
||||||
|
return utime/float64(clockTicks) + stime/float64(clockTicks) + iotime/float64(clockTicks)
|
||||||
|
}
|
||||||
|
func CpuUsageByPid(pid int, sleep time.Duration) float64 {
|
||||||
|
total1 := getCPUSampleByPid(pid)
|
||||||
|
time.Sleep(sleep)
|
||||||
|
total2 := getCPUSampleByPid(pid)
|
||||||
|
return (total2 - total1) / sleep.Seconds() * 100
|
||||||
|
}
|
||||||
|
|
||||||
// CpuUsage 获取CPU使用量
|
// CpuUsage 获取CPU使用量
|
||||||
func CpuUsage(sleep time.Duration) float64 {
|
func CpuUsage(sleep time.Duration) float64 {
|
||||||
@@ -105,8 +138,6 @@ func CpuUsage(sleep time.Duration) float64 {
|
|||||||
//fmt.Printf("CPU usage is %f%% [busy: %f, total: %f]\n", cpuUsage, totalTicks-idleTicks, totalTicks)
|
//fmt.Printf("CPU usage is %f%% [busy: %f, total: %f]\n", cpuUsage, totalTicks-idleTicks, totalTicks)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
func DiskUsage(path string) (disk DiskStatus) {
|
func DiskUsage(path string) (disk DiskStatus) {
|
||||||
fs := syscall.Statfs_t{}
|
fs := syscall.Statfs_t{}
|
||||||
err := syscall.Statfs(path, &fs)
|
err := syscall.Statfs(path, &fs)
|
||||||
+4
-17
@@ -27,23 +27,6 @@ func IsRoot() bool {
|
|||||||
return wincmd.Isas()
|
return wincmd.Isas()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Memory 系统内存信息
|
|
||||||
func Memory() MemStatus {
|
|
||||||
var mem MemStatus
|
|
||||||
ram := new(win32api.MEMORYSTATUSEX)
|
|
||||||
win32api.GlobalMemoryStatusEx(ram)
|
|
||||||
mem.All = uint64(ram.UllTotalPhys)
|
|
||||||
mem.Free = uint64(ram.UllAvailPhys)
|
|
||||||
mem.Available = uint64(ram.UllAvailPhys)
|
|
||||||
mem.Used = uint64(mem.All - mem.Free)
|
|
||||||
mem.SwapAll = uint64(ram.UllTotalPageFile)
|
|
||||||
mem.SwapFree = uint64(ram.UllAvailPageFile)
|
|
||||||
mem.SwapUsed = mem.SwapAll - mem.SwapFree
|
|
||||||
mem.VirtualAll = uint64(mem.VirtualAll)
|
|
||||||
mem.VirtualAvail = uint64(mem.VirtualAvail)
|
|
||||||
mem.VirtualUsed = mem.VirtualAll - mem.VirtualUsed
|
|
||||||
return mem
|
|
||||||
}
|
|
||||||
|
|
||||||
func DiskUsage(path string) (disk DiskStatus) {
|
func DiskUsage(path string) (disk DiskStatus) {
|
||||||
kernel32, err := syscall.LoadLibrary("Kernel32.dll")
|
kernel32, err := syscall.LoadLibrary("Kernel32.dll")
|
||||||
@@ -71,3 +54,7 @@ func DiskUsage(path string) (disk DiskStatus) {
|
|||||||
disk.Available = uint64(lpFreeBytesAvailable)
|
disk.Available = uint64(lpFreeBytesAvailable)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func CpuUsage(sleep time.Duration) float64 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|||||||
+347
@@ -0,0 +1,347 @@
|
|||||||
|
package staros
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
//StarCmd Is Here
|
||||||
|
|
||||||
|
type StarCmd struct {
|
||||||
|
CMD *exec.Cmd
|
||||||
|
outfile io.ReadCloser
|
||||||
|
infile io.WriteCloser
|
||||||
|
errfile io.ReadCloser
|
||||||
|
running int32
|
||||||
|
//Store AlL of the Standed Outputs
|
||||||
|
stdout []byte
|
||||||
|
//Store All of the Standed Errors
|
||||||
|
errout []byte
|
||||||
|
runerr error
|
||||||
|
exitcode int
|
||||||
|
stdoutBuf *bytes.Buffer
|
||||||
|
stderrBuf *bytes.Buffer
|
||||||
|
stdoutpoint int
|
||||||
|
stderrpoint int
|
||||||
|
lock sync.Mutex
|
||||||
|
prewrite []string
|
||||||
|
prewritetime time.Duration
|
||||||
|
stopctxfunc context.CancelFunc
|
||||||
|
stopctx context.Context
|
||||||
|
}
|
||||||
|
|
||||||
|
func Command(command string, args ...string) (*StarCmd, error) {
|
||||||
|
var err error
|
||||||
|
shell := new(StarCmd)
|
||||||
|
shell.running = 0
|
||||||
|
shell.prewritetime = time.Millisecond * 200
|
||||||
|
shell.stdoutBuf = bytes.NewBuffer(make([]byte, 0))
|
||||||
|
shell.stderrBuf = bytes.NewBuffer(make([]byte, 0))
|
||||||
|
shell.stopctx, shell.stopctxfunc = context.WithCancel(context.Background())
|
||||||
|
cmd := exec.Command(command, args...)
|
||||||
|
shell.CMD = cmd
|
||||||
|
shell.infile, err = shell.CMD.StdinPipe()
|
||||||
|
if err != nil {
|
||||||
|
return shell, err
|
||||||
|
}
|
||||||
|
shell.errfile, err = shell.CMD.StderrPipe()
|
||||||
|
if err != nil {
|
||||||
|
return shell, err
|
||||||
|
}
|
||||||
|
shell.outfile, err = shell.CMD.StdoutPipe()
|
||||||
|
if err != nil {
|
||||||
|
return shell, err
|
||||||
|
}
|
||||||
|
shell.runerr = nil
|
||||||
|
shell.exitcode = -999
|
||||||
|
return shell, nil
|
||||||
|
}
|
||||||
|
func CommandContext(ctx context.Context, command string, args ...string) (*StarCmd, error) {
|
||||||
|
var err error
|
||||||
|
shell := new(StarCmd)
|
||||||
|
shell.running = 0
|
||||||
|
shell.stdoutBuf = bytes.NewBuffer(make([]byte, 0))
|
||||||
|
shell.stderrBuf = bytes.NewBuffer(make([]byte, 0))
|
||||||
|
shell.prewritetime = time.Millisecond * 200
|
||||||
|
shell.stopctx, shell.stopctxfunc = context.WithCancel(context.Background())
|
||||||
|
cmd := exec.CommandContext(ctx, command, args...)
|
||||||
|
shell.CMD = cmd
|
||||||
|
shell.infile, err = shell.CMD.StdinPipe()
|
||||||
|
if err != nil {
|
||||||
|
return shell, err
|
||||||
|
}
|
||||||
|
shell.errfile, err = shell.CMD.StderrPipe()
|
||||||
|
if err != nil {
|
||||||
|
return shell, err
|
||||||
|
}
|
||||||
|
shell.outfile, err = shell.CMD.StdoutPipe()
|
||||||
|
if err != nil {
|
||||||
|
return shell, err
|
||||||
|
}
|
||||||
|
shell.runerr = nil
|
||||||
|
shell.exitcode = -999
|
||||||
|
return shell, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (starcli *StarCmd) queryStdout(ctx context.Context) {
|
||||||
|
for starcli.IsRunning() && starcli.CMD != nil {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
out := make([]byte, 65535)
|
||||||
|
n, err := starcli.outfile.Read(out)
|
||||||
|
if n != 0 {
|
||||||
|
starcli.lock.Lock()
|
||||||
|
starcli.stdoutBuf.Write(out[:n])
|
||||||
|
starcli.lock.Unlock()
|
||||||
|
for _, v := range out[:n] {
|
||||||
|
starcli.stdout = append(starcli.stdout, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
if err == io.EOF {
|
||||||
|
break
|
||||||
|
} else {
|
||||||
|
if !strings.Contains(err.Error(), "file already closed") {
|
||||||
|
starcli.runerr = err
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (starcli *StarCmd) queryStderr(ctx context.Context) {
|
||||||
|
for starcli.IsRunning() && starcli.CMD != nil {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
out := make([]byte, 65535)
|
||||||
|
n, err := starcli.errfile.Read(out)
|
||||||
|
if n != 0 {
|
||||||
|
starcli.lock.Lock()
|
||||||
|
starcli.stderrBuf.Write(out[:n])
|
||||||
|
starcli.lock.Unlock()
|
||||||
|
for _, v := range out[:n] {
|
||||||
|
starcli.errout = append(starcli.errout, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
if err == io.EOF {
|
||||||
|
break
|
||||||
|
} else {
|
||||||
|
if !strings.Contains(err.Error(), "file already closed") {
|
||||||
|
starcli.runerr = err
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
func (starcli *StarCmd) NowLineOutput() (string, error) {
|
||||||
|
starcli.lock.Lock()
|
||||||
|
buf, _ := starcli.stdoutBuf.ReadBytes('\n')
|
||||||
|
buferr, _ := starcli.stderrBuf.ReadBytes(byte('\n'))
|
||||||
|
starcli.lock.Unlock()
|
||||||
|
if len(buferr) != 0 {
|
||||||
|
return string(buf), errors.New(string(buferr))
|
||||||
|
}
|
||||||
|
return string(buf), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (starcli *StarCmd) NowLineStdOut() string {
|
||||||
|
starcli.lock.Lock()
|
||||||
|
defer starcli.lock.Unlock()
|
||||||
|
buf, _ := starcli.stdoutBuf.ReadBytes('\n')
|
||||||
|
return string(buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (starcli *StarCmd) NowLineStdErr() error {
|
||||||
|
starcli.lock.Lock()
|
||||||
|
defer starcli.lock.Unlock()
|
||||||
|
buferr, _ := starcli.stderrBuf.ReadBytes(byte('\n'))
|
||||||
|
if len(buferr) != 0 {
|
||||||
|
return errors.New(string(buferr))
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (starcli *StarCmd) NowAllOutput() (string, error) {
|
||||||
|
var outstr string
|
||||||
|
starcli.lock.Lock()
|
||||||
|
buf := make([]byte, starcli.stdoutBuf.Len())
|
||||||
|
n, _ := starcli.stdoutBuf.Read(buf)
|
||||||
|
starcli.lock.Unlock()
|
||||||
|
if n != 0 {
|
||||||
|
outstr = string(buf[:n])
|
||||||
|
}
|
||||||
|
if starcli.runerr != nil {
|
||||||
|
return outstr, starcli.runerr
|
||||||
|
}
|
||||||
|
starcli.lock.Lock()
|
||||||
|
buf = make([]byte, starcli.stderrBuf.Len())
|
||||||
|
n, _ = starcli.stderrBuf.Read(buf)
|
||||||
|
starcli.lock.Unlock()
|
||||||
|
if n != 0 {
|
||||||
|
return outstr, errors.New(string(buf[:n]))
|
||||||
|
}
|
||||||
|
return outstr, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (starcli *StarCmd) NowStdOut() string {
|
||||||
|
var outstr string
|
||||||
|
starcli.lock.Lock()
|
||||||
|
buf := make([]byte, starcli.stdoutBuf.Len())
|
||||||
|
n, _ := starcli.stdoutBuf.Read(buf)
|
||||||
|
starcli.lock.Unlock()
|
||||||
|
if n != 0 {
|
||||||
|
outstr = string(buf[:n])
|
||||||
|
}
|
||||||
|
return outstr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (starcli *StarCmd) NowStdErr() error {
|
||||||
|
starcli.lock.Lock()
|
||||||
|
buf := make([]byte, starcli.stderrBuf.Len())
|
||||||
|
n, _ := starcli.stderrBuf.Read(buf)
|
||||||
|
starcli.lock.Unlock()
|
||||||
|
if n != 0 {
|
||||||
|
return errors.New(string(buf[:n]))
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (starcli *StarCmd) AllOutPut() (string, error) {
|
||||||
|
err := starcli.runerr
|
||||||
|
if err == nil && len(starcli.errout) != 0 {
|
||||||
|
err = errors.New(string(starcli.errout))
|
||||||
|
}
|
||||||
|
return string(starcli.stdout), err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (starcli *StarCmd) AllStdOut() string {
|
||||||
|
return string(starcli.stdout)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (starcli *StarCmd) AllStdErr() error {
|
||||||
|
err := starcli.runerr
|
||||||
|
if err == nil && len(starcli.errout) != 0 {
|
||||||
|
err = errors.New(string(starcli.errout))
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (starcli *StarCmd) setRunning(alive bool) {
|
||||||
|
if alive {
|
||||||
|
val := atomic.LoadInt32(&starcli.running)
|
||||||
|
if val == 0 {
|
||||||
|
atomic.AddInt32(&starcli.running, 1)
|
||||||
|
} else {
|
||||||
|
atomic.AddInt32(&starcli.running, 1-val)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val := atomic.LoadInt32(&starcli.running)
|
||||||
|
if val == 1 {
|
||||||
|
atomic.AddInt32(&starcli.running, -1)
|
||||||
|
} else {
|
||||||
|
atomic.AddInt32(&starcli.running, -val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func (starcli *StarCmd) Start() error {
|
||||||
|
if err := starcli.CMD.Start(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
starcli.setRunning(true)
|
||||||
|
go func() {
|
||||||
|
err := starcli.CMD.Wait()
|
||||||
|
if err != nil {
|
||||||
|
starcli.runerr = err
|
||||||
|
}
|
||||||
|
starcli.stopctxfunc()
|
||||||
|
starcli.setRunning(false)
|
||||||
|
if starcli.CMD.ProcessState != nil {
|
||||||
|
starcli.exitcode = starcli.CMD.ProcessState.Sys().(syscall.WaitStatus).ExitStatus()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
go starcli.queryStdout(starcli.stopctx)
|
||||||
|
go starcli.queryStderr(starcli.stopctx)
|
||||||
|
go func(ctx context.Context) {
|
||||||
|
if len(starcli.prewrite) != 0 {
|
||||||
|
for _, v := range starcli.prewrite {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
starcli.WriteCmd(v)
|
||||||
|
time.Sleep(starcli.prewritetime)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}(starcli.stopctx)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (starcli *StarCmd) IsRunning() bool {
|
||||||
|
return 0 != atomic.LoadInt32(&starcli.running)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (starcli *StarCmd) Stoped() <-chan struct{} {
|
||||||
|
return starcli.stopctx.Done()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (starcli *StarCmd) Exec(cmd string, wait int) (string, error) {
|
||||||
|
starcli.infile.Write([]byte(cmd + "\n"))
|
||||||
|
time.Sleep(time.Millisecond * time.Duration(wait))
|
||||||
|
return starcli.NowAllOutput()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (starcli *StarCmd) WriteCmd(cmdstr string) {
|
||||||
|
starcli.infile.Write([]byte(cmdstr + "\n"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (starcli *StarCmd) PreWrite(cmd ...string) {
|
||||||
|
for _, v := range cmd {
|
||||||
|
starcli.prewrite = append(starcli.prewrite, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (starcli *StarCmd) PreWriteInterval(dt time.Duration) {
|
||||||
|
starcli.prewritetime = dt
|
||||||
|
}
|
||||||
|
|
||||||
|
func (starcli *StarCmd) ExitCode() int {
|
||||||
|
return starcli.exitcode
|
||||||
|
}
|
||||||
|
|
||||||
|
func (starcli *StarCmd) Kill() error {
|
||||||
|
err := starcli.CMD.Process.Kill()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
starcli.setRunning(false)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (starcli *StarCmd) GetPid() int {
|
||||||
|
return starcli.CMD.Process.Pid
|
||||||
|
}
|
||||||
|
|
||||||
|
func (starcli *StarCmd) Signal(sig os.Signal) error {
|
||||||
|
return starcli.CMD.Process.Signal(sig)
|
||||||
|
}
|
||||||
@@ -1,147 +0,0 @@
|
|||||||
// +build linux darwin
|
|
||||||
|
|
||||||
package staros
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
|
||||||
"os/exec"
|
|
||||||
"path/filepath"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"syscall"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// FindProcessByName 通过进程名来查询应用信息
|
|
||||||
func FindProcessByName(pname string) (datas []Process, err error) {
|
|
||||||
var name, main string
|
|
||||||
var mainb []byte
|
|
||||||
paths, errs := ioutil.ReadDir("/proc")
|
|
||||||
if errs != nil {
|
|
||||||
err = errs
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for _, v := range paths {
|
|
||||||
if v.IsDir() && Exists("/proc/"+v.Name()+"/comm") {
|
|
||||||
name, err = readAsString("/proc/" + v.Name() + "/comm")
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if strings.TrimSpace(name) == pname {
|
|
||||||
var tmp Process
|
|
||||||
main, err = readAsString("/proc/" + v.Name() + "/status")
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
data := splitBy(main, ":")
|
|
||||||
tmp.Name = pname
|
|
||||||
tmp.Pid, _ = strconv.ParseInt(data["Pid"], 10, 64)
|
|
||||||
tmp.PPid, _ = strconv.ParseInt(data["PPid"], 10, 64)
|
|
||||||
tmp.TPid, _ = strconv.ParseInt(data["TracerPid"], 10, 64)
|
|
||||||
uids := splitBySpace(data["Uid"])
|
|
||||||
gids := splitBySpace(data["Gid"])
|
|
||||||
tmp.RUID, _ = strconv.Atoi(uids[0])
|
|
||||||
tmp.EUID, _ = strconv.Atoi(uids[1])
|
|
||||||
tmp.RGID, _ = strconv.Atoi(gids[0])
|
|
||||||
tmp.EGID, _ = strconv.Atoi(gids[1])
|
|
||||||
mainb, err = ioutil.ReadFile("/proc/" + v.Name() + "/cmdline")
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
args := bytes.Split(mainb, []byte{0})
|
|
||||||
for _, v := range args {
|
|
||||||
tmp.Args = append(tmp.Args, string(v))
|
|
||||||
}
|
|
||||||
tmp.LocalPath, err = os.Readlink("/proc/" + v.Name() + "/exe")
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
tmp.LocalPath = filepath.Dir(tmp.LocalPath)
|
|
||||||
tmp.ExecPath, err = os.Readlink("/proc/" + v.Name() + "/cwd")
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
main, err = readAsString("/proc/" + v.Name() + "/stat")
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
times := splitBySpace(main)
|
|
||||||
uptime, _ := strconv.ParseInt(strings.TrimSpace(times[21]), 10, 64)
|
|
||||||
tmp.Uptime = time.Unix(StartTime().Unix()+uptime/100, int64((float64(uptime)/100-float64(uptime/100))*1000000000))
|
|
||||||
datas = append(datas, tmp)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// FindProcessByPid 通过Pid来查询应用信息
|
|
||||||
func FindProcessByPid(pid int64) (datas Process, err error) {
|
|
||||||
var name, main string
|
|
||||||
var mainb []byte
|
|
||||||
if !Exists("/proc/" + fmt.Sprint(pid) + "/comm") {
|
|
||||||
err = errors.New("Not Found")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
name, err = readAsString("/proc/" + fmt.Sprint(pid) + "/comm")
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
main, err = readAsString("/proc/" + fmt.Sprint(pid) + "/status")
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
data := splitBy(main, ":")
|
|
||||||
datas.Name = strings.TrimSpace(name)
|
|
||||||
datas.Pid, _ = strconv.ParseInt(data["Pid"], 10, 64)
|
|
||||||
datas.PPid, _ = strconv.ParseInt(data["PPid"], 10, 64)
|
|
||||||
datas.TPid, _ = strconv.ParseInt(data["TracerPid"], 10, 64)
|
|
||||||
uids := splitBySpace(data["Uid"])
|
|
||||||
gids := splitBySpace(data["Gid"])
|
|
||||||
datas.RUID, _ = strconv.Atoi(uids[0])
|
|
||||||
datas.EUID, _ = strconv.Atoi(uids[1])
|
|
||||||
datas.RGID, _ = strconv.Atoi(gids[0])
|
|
||||||
datas.EGID, _ = strconv.Atoi(gids[1])
|
|
||||||
mainb, err = ioutil.ReadFile("/proc/" + fmt.Sprint(pid) + "/cmdline")
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
args := bytes.Split(mainb, []byte{0})
|
|
||||||
for _, v := range args {
|
|
||||||
datas.Args = append(datas.Args, string(v))
|
|
||||||
}
|
|
||||||
datas.LocalPath, err = os.Readlink("/proc/" + fmt.Sprint(pid) + "/exe")
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
datas.LocalPath = filepath.Dir(datas.LocalPath)
|
|
||||||
datas.ExecPath, err = os.Readlink("/proc/" + fmt.Sprint(pid) + "/cwd")
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
main, err = readAsString("/proc/" + fmt.Sprint(pid) + "/stat")
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
times := splitBySpace(main)
|
|
||||||
uptime, _ := strconv.ParseInt(strings.TrimSpace(times[21]), 10, 64)
|
|
||||||
datas.Uptime = time.Unix(StartTime().Unix()+uptime/100, int64((float64(uptime)/100-float64(uptime/100))*1000000000))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func Daemon(path string, args ...string) (int, error) {
|
|
||||||
cmd := exec.Command(path, args...)
|
|
||||||
cmd.SysProcAttr = &syscall.SysProcAttr{
|
|
||||||
Setsid: true,
|
|
||||||
}
|
|
||||||
if err := cmd.Start(); err != nil {
|
|
||||||
return -1, err
|
|
||||||
}
|
|
||||||
pid := cmd.Process.Pid
|
|
||||||
err := cmd.Process.Release()
|
|
||||||
return pid, err
|
|
||||||
}
|
|
||||||
@@ -1,10 +1,27 @@
|
|||||||
package staros
|
package staros
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Test_Process(t *testing.T) {
|
func Test_Process(t *testing.T) {
|
||||||
fmt.Println(FindProcessByPid(16652))
|
fmt.Println(FindProcessByPid(16652))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Test_StarCmd(t *testing.T) {
|
||||||
|
ctx, _ := context.WithTimeout(context.Background(), time.Second*5)
|
||||||
|
cmd, _ := CommandContext(ctx, "cmd.exe", "/c", "ping -t 127.0.0.1")
|
||||||
|
cmd.Start()
|
||||||
|
for cmd.IsRunning() {
|
||||||
|
fmt.Print(cmd.NowLineOutput())
|
||||||
|
time.Sleep(time.Millisecond * 50)
|
||||||
|
}
|
||||||
|
fmt.Println(cmd.NowAllOutput())
|
||||||
|
fmt.Print("all is ")
|
||||||
|
fmt.Println(cmd.AllOutPut())
|
||||||
|
fmt.Println(cmd.ExitCode())
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
+348
@@ -0,0 +1,348 @@
|
|||||||
|
// +build linux darwin
|
||||||
|
|
||||||
|
package staros
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
//FindProcessByName 通过进程名来查询应用信息
|
||||||
|
func FindProcessByName(name string) (datas []Process, err error) {
|
||||||
|
return FindProcess(func(in Process) bool {
|
||||||
|
if name == in.Name {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// FindProcess 通过进程信息来查询应用信息
|
||||||
|
func FindProcess(compare func(Process) bool) (datas []Process, err error) {
|
||||||
|
var name, main string
|
||||||
|
var mainb []byte
|
||||||
|
var netErr error
|
||||||
|
var netInfo []NetConn
|
||||||
|
paths, err := ioutil.ReadDir("/proc")
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
netInfo, netErr = NetConnections(false, "")
|
||||||
|
appendNetInfo := func(p *Process) {
|
||||||
|
if netErr != nil {
|
||||||
|
p.netErr = netErr
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fds, err := ioutil.ReadDir("/proc/" + strconv.Itoa(int(p.Pid)) + "/fd")
|
||||||
|
if err != nil && Exists("/proc/"+strconv.Itoa(int(p.Pid))+"/fd") {
|
||||||
|
p.netErr = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for _, fd := range fds {
|
||||||
|
socket, err := os.Readlink("/proc/" + strconv.Itoa(int(p.Pid)) + "/fd/" + fd.Name())
|
||||||
|
if err != nil {
|
||||||
|
p.netErr = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
start := strings.Index(socket, "[")
|
||||||
|
if start < 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
sid := socket[start+1 : len(socket)-1]
|
||||||
|
for _, v := range netInfo {
|
||||||
|
if v.Inode == sid {
|
||||||
|
v.Pid = p.Pid
|
||||||
|
v.Process = p
|
||||||
|
p.netConn = append(p.netConn, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, v := range paths {
|
||||||
|
if v.IsDir() && Exists("/proc/"+v.Name()+"/comm") {
|
||||||
|
name, err = readAsString("/proc/" + v.Name() + "/comm")
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
var tmp Process
|
||||||
|
tmp.LocalPath, err = os.Readlink("/proc/" + v.Name() + "/exe")
|
||||||
|
tmp.Path = tmp.LocalPath
|
||||||
|
tmp.LocalPath = filepath.Dir(tmp.LocalPath)
|
||||||
|
tmp.ExecPath, err = os.Readlink("/proc/" + v.Name() + "/cwd")
|
||||||
|
tmp.Name = strings.TrimSpace(name)
|
||||||
|
main, err = readAsString("/proc/" + v.Name() + "/status")
|
||||||
|
if err != nil {
|
||||||
|
tmp.Err = err
|
||||||
|
if compare(tmp) {
|
||||||
|
appendNetInfo(&tmp)
|
||||||
|
datas = append(datas, tmp)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
data := splitBy(main, ":")
|
||||||
|
tmp.Pid, _ = strconv.ParseInt(data["Pid"], 10, 64)
|
||||||
|
tmp.PPid, _ = strconv.ParseInt(data["PPid"], 10, 64)
|
||||||
|
tmp.TPid, _ = strconv.ParseInt(data["TracerPid"], 10, 64)
|
||||||
|
uids := splitBySpace(data["Uid"])
|
||||||
|
gids := splitBySpace(data["Gid"])
|
||||||
|
tmp.RUID, _ = strconv.Atoi(uids[0])
|
||||||
|
tmp.EUID, _ = strconv.Atoi(uids[1])
|
||||||
|
tmp.RGID, _ = strconv.Atoi(gids[0])
|
||||||
|
tmp.EGID, _ = strconv.Atoi(gids[1])
|
||||||
|
tmp.VmPeak, _ = strconv.ParseInt(splitBySpace(data["VmPeak"])[0], 10, 64)
|
||||||
|
tmp.VmSize, _ = strconv.ParseInt(splitBySpace(data["VmSize"])[0], 10, 64)
|
||||||
|
tmp.VmHWM, _ = strconv.ParseInt(splitBySpace(data["VmHWM"])[0], 10, 64)
|
||||||
|
tmp.VmRSS, _ = strconv.ParseInt(splitBySpace(data["VmRSS"])[0], 10, 64)
|
||||||
|
tmp.VmLck, _ = strconv.ParseInt(splitBySpace(data["VmLck"])[0], 10, 64)
|
||||||
|
tmp.VmData, _ = strconv.ParseInt(splitBySpace(data["VmData"])[0], 10, 64)
|
||||||
|
tmp.VmLck *= 1024
|
||||||
|
tmp.VmData *= 1024
|
||||||
|
tmp.VmPeak *= 1024
|
||||||
|
tmp.VmSize *= 1024
|
||||||
|
tmp.VmHWM *= 1024
|
||||||
|
tmp.VmRSS *= 1024
|
||||||
|
}
|
||||||
|
mainb, err = ioutil.ReadFile("/proc/" + v.Name() + "/cmdline")
|
||||||
|
if err != nil {
|
||||||
|
tmp.Err = err
|
||||||
|
if compare(tmp) {
|
||||||
|
appendNetInfo(&tmp)
|
||||||
|
datas = append(datas, tmp)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
args := bytes.Split(mainb, []byte{0})
|
||||||
|
for _, v := range args {
|
||||||
|
tmp.Args = append(tmp.Args, string(v))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mainb, err = ioutil.ReadFile("/proc/" + v.Name() + "/environ")
|
||||||
|
if err != nil {
|
||||||
|
tmp.Err = err
|
||||||
|
if compare(tmp) {
|
||||||
|
appendNetInfo(&tmp)
|
||||||
|
datas = append(datas, tmp)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
args := bytes.Split(mainb, []byte{0})
|
||||||
|
for _, v := range args {
|
||||||
|
tmp.Env = append(tmp.Env, string(v))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
main, err = readAsString("/proc/" + v.Name() + "/stat")
|
||||||
|
if err != nil {
|
||||||
|
tmp.Err = err
|
||||||
|
if compare(tmp) {
|
||||||
|
appendNetInfo(&tmp)
|
||||||
|
datas = append(datas, tmp)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
times := splitBySpace(main)
|
||||||
|
uptime, _ := strconv.ParseInt(strings.TrimSpace(times[21]), 10, 64)
|
||||||
|
tmp.Uptime = time.Unix(StartTime().Unix()+uptime/100, int64((float64(uptime)/100-float64(uptime/100))*1000000000))
|
||||||
|
}
|
||||||
|
if compare(tmp) {
|
||||||
|
appendNetInfo(&tmp)
|
||||||
|
datas = append(datas, tmp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// FindProcessByPid 通过Pid来查询应用信息
|
||||||
|
func FindProcessByPid(pid int64) (datas Process, err error) {
|
||||||
|
var name, main string
|
||||||
|
var mainb []byte
|
||||||
|
if !Exists("/proc/" + fmt.Sprint(pid) + "/comm") {
|
||||||
|
err = errors.New("Not Found")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
netInfo, netErr := NetConnections(false, "")
|
||||||
|
appendNetInfo := func(p *Process) {
|
||||||
|
if netErr != nil {
|
||||||
|
p.netErr = netErr
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fds, err := ioutil.ReadDir("/proc/" + strconv.Itoa(int(p.Pid)) + "/fd")
|
||||||
|
if err != nil && Exists("/proc/"+strconv.Itoa(int(p.Pid))+"/fd") {
|
||||||
|
p.netErr = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for _, fd := range fds {
|
||||||
|
socket, err := os.Readlink("/proc/" + strconv.Itoa(int(p.Pid)) + "/fd/" + fd.Name())
|
||||||
|
if err != nil {
|
||||||
|
p.netErr = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
start := strings.Index(socket, "[")
|
||||||
|
if start < 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
sid := socket[start+1 : len(socket)-1]
|
||||||
|
for _, v := range netInfo {
|
||||||
|
if v.Inode == sid {
|
||||||
|
v.Pid = p.Pid
|
||||||
|
v.Process = p
|
||||||
|
p.netConn = append(p.netConn, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
name, err = readAsString("/proc/" + fmt.Sprint(pid) + "/comm")
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
main, err = readAsString("/proc/" + fmt.Sprint(pid) + "/status")
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
data := splitBy(main, ":")
|
||||||
|
datas.Name = strings.TrimSpace(name)
|
||||||
|
datas.Pid, _ = strconv.ParseInt(data["Pid"], 10, 64)
|
||||||
|
datas.PPid, _ = strconv.ParseInt(data["PPid"], 10, 64)
|
||||||
|
datas.TPid, _ = strconv.ParseInt(data["TracerPid"], 10, 64)
|
||||||
|
uids := splitBySpace(data["Uid"])
|
||||||
|
gids := splitBySpace(data["Gid"])
|
||||||
|
datas.RUID, _ = strconv.Atoi(uids[0])
|
||||||
|
datas.EUID, _ = strconv.Atoi(uids[1])
|
||||||
|
datas.RGID, _ = strconv.Atoi(gids[0])
|
||||||
|
datas.EGID, _ = strconv.Atoi(gids[1])
|
||||||
|
datas.VmPeak, _ = strconv.ParseInt(splitBySpace(data["VmPeak"])[0], 10, 64)
|
||||||
|
datas.VmSize, _ = strconv.ParseInt(splitBySpace(data["VmSize"])[0], 10, 64)
|
||||||
|
datas.VmHWM, _ = strconv.ParseInt(splitBySpace(data["VmHWM"])[0], 10, 64)
|
||||||
|
datas.VmRSS, _ = strconv.ParseInt(splitBySpace(data["VmRSS"])[0], 10, 64)
|
||||||
|
datas.VmLck, _ = strconv.ParseInt(splitBySpace(data["VmLck"])[0], 10, 64)
|
||||||
|
datas.VmData, _ = strconv.ParseInt(splitBySpace(data["VmData"])[0], 10, 64)
|
||||||
|
datas.VmLck *= 1024
|
||||||
|
datas.VmData *= 1024
|
||||||
|
datas.VmPeak *= 1024
|
||||||
|
datas.VmSize *= 1024
|
||||||
|
datas.VmHWM *= 1024
|
||||||
|
datas.VmRSS *= 1024
|
||||||
|
appendNetInfo(&datas)
|
||||||
|
mainb, err = ioutil.ReadFile("/proc/" + fmt.Sprint(pid) + "/cmdline")
|
||||||
|
if err != nil {
|
||||||
|
datas.Err = err
|
||||||
|
err = nil
|
||||||
|
} else {
|
||||||
|
args := bytes.Split(mainb, []byte{0})
|
||||||
|
for _, v := range args {
|
||||||
|
datas.Args = append(datas.Args, string(v))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mainb, err = ioutil.ReadFile("/proc/" + fmt.Sprint(pid) + "/environ")
|
||||||
|
if err != nil {
|
||||||
|
datas.Err = err
|
||||||
|
err = nil
|
||||||
|
} else {
|
||||||
|
args := bytes.Split(mainb, []byte{0})
|
||||||
|
for _, v := range args {
|
||||||
|
datas.Env = append(datas.Env, string(v))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
datas.LocalPath, err = os.Readlink("/proc/" + fmt.Sprint(pid) + "/exe")
|
||||||
|
datas.Path = datas.LocalPath
|
||||||
|
datas.LocalPath = filepath.Dir(datas.LocalPath)
|
||||||
|
datas.ExecPath, err = os.Readlink("/proc/" + fmt.Sprint(pid) + "/cwd")
|
||||||
|
main, err = readAsString("/proc/" + fmt.Sprint(pid) + "/stat")
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
times := splitBySpace(main)
|
||||||
|
uptime, _ := strconv.ParseInt(strings.TrimSpace(times[21]), 10, 64)
|
||||||
|
datas.Uptime = time.Unix(StartTime().Unix()+uptime/100, int64((float64(uptime)/100-float64(uptime/100))*1000000000))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func Daemon(path string, args ...string) (int, error) {
|
||||||
|
cmd := exec.Command(path, args...)
|
||||||
|
cmd.SysProcAttr = &syscall.SysProcAttr{
|
||||||
|
Setsid: true,
|
||||||
|
}
|
||||||
|
if err := cmd.Start(); err != nil {
|
||||||
|
return -1, err
|
||||||
|
}
|
||||||
|
pid := cmd.Process.Pid
|
||||||
|
err := cmd.Process.Release()
|
||||||
|
return pid, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func DaemonWithUser(uid, gid uint32, groups []uint32, path string, args ...string) (int, error) {
|
||||||
|
cmd := exec.Command(path, args...)
|
||||||
|
cmd.SysProcAttr = &syscall.SysProcAttr{
|
||||||
|
Credential: &syscall.Credential{
|
||||||
|
Uid: uid,
|
||||||
|
Gid: gid,
|
||||||
|
Groups: groups,
|
||||||
|
},
|
||||||
|
Setsid: true,
|
||||||
|
}
|
||||||
|
if err := cmd.Start(); err != nil {
|
||||||
|
return -1, err
|
||||||
|
}
|
||||||
|
pid := cmd.Process.Pid
|
||||||
|
err := cmd.Process.Release()
|
||||||
|
return pid, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (starcli *StarCmd) SetRunUser(uid, gid uint32, groups []uint32) {
|
||||||
|
starcli.CMD.SysProcAttr = &syscall.SysProcAttr{
|
||||||
|
Credential: &syscall.Credential{
|
||||||
|
Uid: uid,
|
||||||
|
Gid: gid,
|
||||||
|
Groups: groups,
|
||||||
|
},
|
||||||
|
Setsid: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (starcli *StarCmd) Release() error {
|
||||||
|
if starcli.CMD.SysProcAttr == nil {
|
||||||
|
starcli.CMD.SysProcAttr = &syscall.SysProcAttr{
|
||||||
|
Setsid: true,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if !starcli.CMD.SysProcAttr.Setsid {
|
||||||
|
starcli.CMD.SysProcAttr.Setsid = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !starcli.IsRunning() {
|
||||||
|
if err := starcli.CMD.Start(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
time.Sleep(time.Millisecond * 10)
|
||||||
|
return starcli.CMD.Process.Release()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (starcli *StarCmd) SetKeepCaps() error {
|
||||||
|
_, _, err := syscall.RawSyscall(157 /*SYS PRCTL */, 0x8 /*PR SET KEEPCAPS*/, 1, 0)
|
||||||
|
if 0 != err {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetKeepCaps() error {
|
||||||
|
_, _, err := syscall.RawSyscall(157 /*SYS PRCTL */, 0x8 /*PR SET KEEPCAPS*/, 1, 0)
|
||||||
|
if 0 != err {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -58,3 +58,15 @@ func Daemon(path string, args ...string) (int, error) {
|
|||||||
cmd.Process.Release()
|
cmd.Process.Release()
|
||||||
return pid, nil
|
return pid, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (starcli *StarCmd) SetRunUser(uid, gid uint32, groups []uint32) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (starcli *StarCmd) Release() error {
|
||||||
|
if err := starcli.CMD.Start(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
starcli.CMD.Process.Release()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
+261
@@ -0,0 +1,261 @@
|
|||||||
|
package sysconf
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CSV struct {
|
||||||
|
header []string
|
||||||
|
text [][]string
|
||||||
|
}
|
||||||
|
|
||||||
|
type CSVRow struct {
|
||||||
|
header []string
|
||||||
|
data []string
|
||||||
|
}
|
||||||
|
|
||||||
|
type CSVValue struct {
|
||||||
|
key string
|
||||||
|
value string
|
||||||
|
}
|
||||||
|
|
||||||
|
func ParseCSV(data []byte, hasHeader bool) (csv CSV, err error) {
|
||||||
|
strData := strings.Split(string(bytes.TrimSpace(data)), "\n")
|
||||||
|
if len(strData) < 1 {
|
||||||
|
err = fmt.Errorf("cannot parse data,invalid data format")
|
||||||
|
}
|
||||||
|
var header []string
|
||||||
|
var text [][]string
|
||||||
|
if hasHeader {
|
||||||
|
header = csvAnalyse(strData[0])
|
||||||
|
strData = strData[1:]
|
||||||
|
} else {
|
||||||
|
num := len(csvAnalyse(strData[0]))
|
||||||
|
for i := 0; i < num; i++ {
|
||||||
|
header = append(header, strconv.Itoa(i))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for k, v := range strData {
|
||||||
|
tmpData := csvAnalyse(v)
|
||||||
|
if len(tmpData) != len(header) {
|
||||||
|
err = fmt.Errorf("cannot parse data line %d,got %d values but need %d", k, len(tmpData), len(header))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
text = append(text, tmpData)
|
||||||
|
}
|
||||||
|
csv.header = header
|
||||||
|
csv.text = text
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (csv *CSV) Header() []string {
|
||||||
|
return csv.header
|
||||||
|
}
|
||||||
|
|
||||||
|
func (csv *CSV) Data() [][]string {
|
||||||
|
return csv.text
|
||||||
|
}
|
||||||
|
|
||||||
|
func (csv *CSV) Row(row int) *CSVRow {
|
||||||
|
if row >= len(csv.Data()) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return &CSVRow{
|
||||||
|
header: csv.Header(),
|
||||||
|
data: csv.Data()[row],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (csv *CSVRow) Get(key string) *CSVValue {
|
||||||
|
for k, v := range csv.header {
|
||||||
|
if v == key {
|
||||||
|
return &CSVValue{
|
||||||
|
key: key,
|
||||||
|
value: csv.data[k],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (csv *CSVRow) Col(key int) *CSVValue {
|
||||||
|
if key >= len(csv.header) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return &CSVValue{
|
||||||
|
key: csv.header[key],
|
||||||
|
value: csv.data[key],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (csv *CSVRow) Header() []string {
|
||||||
|
return csv.header
|
||||||
|
}
|
||||||
|
|
||||||
|
func (csv *CSV) MapData() []map[string]string {
|
||||||
|
var result []map[string]string
|
||||||
|
for _, v := range csv.text {
|
||||||
|
tmp := make(map[string]string)
|
||||||
|
for k, v2 := range csv.header {
|
||||||
|
tmp[v2] = v[k]
|
||||||
|
}
|
||||||
|
result = append(result, tmp)
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func CsvAnalyse(data string) []string {
|
||||||
|
return csvAnalyse(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func csvAnalyse(data string) []string {
|
||||||
|
var segStart bool = false
|
||||||
|
var segReady bool = false
|
||||||
|
var segSign string = ""
|
||||||
|
var dotReady bool = false
|
||||||
|
data = strings.TrimSpace(data)
|
||||||
|
var result []string
|
||||||
|
var seg string
|
||||||
|
for k, v := range []rune(data) {
|
||||||
|
if k == 0 && v != []rune(`"`)[0] {
|
||||||
|
dotReady = true
|
||||||
|
}
|
||||||
|
if v != []rune(`,`)[0] && dotReady {
|
||||||
|
segSign = `,`
|
||||||
|
segStart = true
|
||||||
|
dotReady = false
|
||||||
|
if v == []rune(`"`)[0] {
|
||||||
|
segSign = `"`
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if dotReady && v == []rune(`,`)[0] {
|
||||||
|
//dotReady = false
|
||||||
|
result = append(result, "")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if v == []rune(`"`)[0] && segStart {
|
||||||
|
if !segReady {
|
||||||
|
segReady = true
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
seg += `"`
|
||||||
|
segReady = false
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if segReady && segSign == `"` && segStart {
|
||||||
|
segReady = false
|
||||||
|
segStart = false
|
||||||
|
result = append(result, seg)
|
||||||
|
segSign = ``
|
||||||
|
seg = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
if v == []rune(`"`)[0] && !segStart {
|
||||||
|
segStart = true
|
||||||
|
segReady = false
|
||||||
|
segSign = `"`
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if v == []rune(`,`)[0] && !segStart {
|
||||||
|
dotReady = true
|
||||||
|
}
|
||||||
|
if v == []rune(`,`)[0] && segStart && segSign == "," {
|
||||||
|
segStart = false
|
||||||
|
result = append(result, seg)
|
||||||
|
dotReady = true
|
||||||
|
segSign = ``
|
||||||
|
seg = ""
|
||||||
|
}
|
||||||
|
if segStart {
|
||||||
|
seg = string(append([]rune(seg), v))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(data) != 0 && len(result) == 0 && seg == "" {
|
||||||
|
result = append(result, data)
|
||||||
|
} else {
|
||||||
|
result = append(result, seg)
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func MarshalCSV(header []string, ins interface{}) ([]byte, error) {
|
||||||
|
var result [][]string
|
||||||
|
t := reflect.TypeOf(ins)
|
||||||
|
v := reflect.ValueOf(ins)
|
||||||
|
if v.Kind() != reflect.Slice && v.Kind() != reflect.Array {
|
||||||
|
return nil, errors.New("not a Slice or Array")
|
||||||
|
}
|
||||||
|
if t.Kind() == reflect.Ptr {
|
||||||
|
t = t.Elem()
|
||||||
|
v = v.Elem()
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < v.Len(); i++ {
|
||||||
|
subT := reflect.TypeOf(v.Index(i).Interface())
|
||||||
|
subV := reflect.ValueOf(v.Index(i).Interface())
|
||||||
|
if subV.Kind() == reflect.Slice || subV.Kind() == reflect.Array {
|
||||||
|
if subT.Kind() == reflect.Ptr {
|
||||||
|
subV = subV.Elem()
|
||||||
|
}
|
||||||
|
var tmp []string
|
||||||
|
for j := 0; j < subV.Len(); j++ {
|
||||||
|
tmp = append(tmp, fmt.Sprint(reflect.ValueOf(subV.Index(j))))
|
||||||
|
}
|
||||||
|
result = append(result, tmp)
|
||||||
|
}
|
||||||
|
if subV.Kind() == reflect.Struct {
|
||||||
|
var tmp []string
|
||||||
|
if subT.Kind() == reflect.Ptr {
|
||||||
|
subV = subV.Elem()
|
||||||
|
}
|
||||||
|
for i := 0; i < subV.NumField(); i++ {
|
||||||
|
tmp = append(tmp, fmt.Sprint(subV.Field(i)))
|
||||||
|
}
|
||||||
|
result = append(result, tmp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return buildCSV(header,result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildCSV(header []string, data [][]string) ([]byte, error) {
|
||||||
|
var result []string
|
||||||
|
var length int
|
||||||
|
build := func(slc []string) string {
|
||||||
|
for k, v := range slc {
|
||||||
|
if strings.Index(v, `"`) >= 0 {
|
||||||
|
v = strings.ReplaceAll(v, `"`, `""`)
|
||||||
|
}
|
||||||
|
if strings.Index(v,"\n")>=0 {
|
||||||
|
v=strings.ReplaceAll(v,"\n",`\n`)
|
||||||
|
}
|
||||||
|
if strings.Index(v,"\r")>=0 {
|
||||||
|
v=strings.ReplaceAll(v,"\r",`\r`)
|
||||||
|
}
|
||||||
|
v = `"` + v + `"`
|
||||||
|
slc[k] = v
|
||||||
|
}
|
||||||
|
return strings.Join(slc, ",")
|
||||||
|
}
|
||||||
|
if len(header) != 0 {
|
||||||
|
result = append(result, build(header))
|
||||||
|
length = len(header)
|
||||||
|
} else {
|
||||||
|
length = len(data[0])
|
||||||
|
}
|
||||||
|
for k, v := range data {
|
||||||
|
if len(v) != length {
|
||||||
|
return nil, fmt.Errorf("line %d got length %d ,but need %d", k, len(v), length)
|
||||||
|
}
|
||||||
|
result = append(result, build(v))
|
||||||
|
}
|
||||||
|
return []byte(strings.Join(result, "\n")), nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
package sysconf
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_csv(t *testing.T) {
|
||||||
|
//var test Sqlplus
|
||||||
|
var text=`
|
||||||
|
姓名,班级,性别,年龄
|
||||||
|
张三,"我,不""知道",boy,23
|
||||||
|
"里斯","哈哈",girl,23
|
||||||
|
`
|
||||||
|
fmt.Println(csvAnalyse(`请求权,lkjdshck,dsvdsv,"sdvkjsdv,",=dsvdsv,"=,dsvsdv"`))
|
||||||
|
a,b:=ParseCSV([]byte(text),true)
|
||||||
|
fmt.Println(b)
|
||||||
|
fmt.Println(a.Row(0).Col(3).MustInt())
|
||||||
|
}
|
||||||
|
|
||||||
|
type csvtest struct {
|
||||||
|
A string
|
||||||
|
B int
|
||||||
|
}
|
||||||
|
func Test_Masharl(t *testing.T) {
|
||||||
|
//var test Sqlplus
|
||||||
|
/*
|
||||||
|
var a []csvtest = []csvtest{
|
||||||
|
{"lala",1},
|
||||||
|
{"haha",34},
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
var a [][]string
|
||||||
|
a=append(a,[]string{"a","b","c"})
|
||||||
|
a=append(a,[]string{"1",`s"s"d`,"3"})
|
||||||
|
b,_:=MarshalCSV([]string{},a)
|
||||||
|
fmt.Println(string(b))
|
||||||
|
}
|
||||||
@@ -0,0 +1,120 @@
|
|||||||
|
package sysconf
|
||||||
|
|
||||||
|
import "strconv"
|
||||||
|
|
||||||
|
func (csv *CSVValue)Key()string {
|
||||||
|
return csv.key
|
||||||
|
}
|
||||||
|
|
||||||
|
func (csv *CSVValue)Int()(int,error) {
|
||||||
|
tmp,err:=strconv.Atoi(csv.value)
|
||||||
|
return tmp,err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (csv *CSVValue)MustInt()int {
|
||||||
|
tmp,err:=csv.Int()
|
||||||
|
if err!=nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return tmp
|
||||||
|
}
|
||||||
|
|
||||||
|
func (csv *CSVValue)Int64()(int64,error) {
|
||||||
|
tmp,err:=strconv.ParseInt(csv.value,10,64)
|
||||||
|
return tmp,err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (csv *CSVValue)MustInt64()int64 {
|
||||||
|
tmp,err:=csv.Int64()
|
||||||
|
if err!=nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return tmp
|
||||||
|
}
|
||||||
|
|
||||||
|
func (csv *CSVValue)Int32()(int32,error) {
|
||||||
|
tmp,err:=strconv.ParseInt(csv.value,10,32)
|
||||||
|
return int32(tmp),err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (csv *CSVValue)MustInt32()int32 {
|
||||||
|
tmp,err:=csv.Int32()
|
||||||
|
if err!=nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return tmp
|
||||||
|
}
|
||||||
|
|
||||||
|
func (csv *CSVValue)Uint64()(uint64,error) {
|
||||||
|
tmp,err:=strconv.ParseUint(csv.value,10,64)
|
||||||
|
return tmp,err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (csv *CSVValue)MustUint64()uint64 {
|
||||||
|
tmp,err:=csv.Uint64()
|
||||||
|
if err!=nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return tmp
|
||||||
|
}
|
||||||
|
|
||||||
|
func (csv *CSVValue)Uint32()(uint32,error) {
|
||||||
|
tmp,err:=strconv.ParseUint(csv.value,10,32)
|
||||||
|
return uint32(tmp),err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (csv *CSVValue)MustUint32()uint32 {
|
||||||
|
tmp,err:=csv.Uint32()
|
||||||
|
if err!=nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return tmp
|
||||||
|
}
|
||||||
|
|
||||||
|
func (csv *CSVValue)String()string {
|
||||||
|
return csv.value
|
||||||
|
}
|
||||||
|
|
||||||
|
func (csv *CSVValue)Byte()[]byte {
|
||||||
|
return []byte(csv.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func (csv *CSVValue)Bool()(bool,error) {
|
||||||
|
tmp,err:=strconv.ParseBool(csv.value)
|
||||||
|
return tmp,err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (csv *CSVValue)MustBool()bool {
|
||||||
|
tmp,err:=csv.Bool()
|
||||||
|
if err!=nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return tmp
|
||||||
|
}
|
||||||
|
|
||||||
|
func (csv *CSVValue)Float64()(float64,error) {
|
||||||
|
tmp,err:=strconv.ParseFloat(csv.value,64)
|
||||||
|
return tmp,err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (csv *CSVValue)MustFloat64()float64 {
|
||||||
|
tmp,err:=csv.Float64()
|
||||||
|
if err!=nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return tmp
|
||||||
|
}
|
||||||
|
|
||||||
|
func (csv *CSVValue)Float32()(float32,error) {
|
||||||
|
tmp,err:=strconv.ParseFloat(csv.value,32)
|
||||||
|
return float32(tmp),err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (csv *CSVValue)MustFloat32()float32 {
|
||||||
|
tmp,err:=csv.Float32()
|
||||||
|
if err!=nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return tmp
|
||||||
|
}
|
||||||
+27
-15
@@ -9,8 +9,6 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"b612.me/staros"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type SysConf struct {
|
type SysConf struct {
|
||||||
@@ -47,6 +45,18 @@ type SysNode struct {
|
|||||||
lock sync.RWMutex
|
lock sync.RWMutex
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewIni() *SysConf {
|
||||||
|
ini := NewSysConf("=")
|
||||||
|
ini.CommentCR = true
|
||||||
|
ini.CommentFlag = []string{"#", ";"}
|
||||||
|
ini.HaveSegMent = true
|
||||||
|
ini.SegStart = "["
|
||||||
|
ini.SegEnd = "]"
|
||||||
|
ini.SpaceStr = " "
|
||||||
|
ini.EscapeFlag = "\\"
|
||||||
|
return ini
|
||||||
|
}
|
||||||
|
|
||||||
func NewSysConf(EqualFlag string) *SysConf {
|
func NewSysConf(EqualFlag string) *SysConf {
|
||||||
syscnf := new(SysConf)
|
syscnf := new(SysConf)
|
||||||
syscnf.EqualFlag = EqualFlag
|
syscnf.EqualFlag = EqualFlag
|
||||||
@@ -64,15 +74,11 @@ func NewLinuxConf(EqualFlag string) *SysConf {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (syscfg *SysConf) ParseFromFile(filepath string) error {
|
func (syscfg *SysConf) ParseFromFile(filepath string) error {
|
||||||
if !staros.Exists(filepath) {
|
|
||||||
return errors.New(filepath + " 不存在")
|
|
||||||
}
|
|
||||||
data, err := ioutil.ReadFile(filepath)
|
data, err := ioutil.ReadFile(filepath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
syscfg.Parse(data)
|
return syscfg.Parse(data)
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse 生成INI文件结构
|
// Parse 生成INI文件结构
|
||||||
@@ -470,7 +476,7 @@ func SliceIn(slice interface{}, data interface{}) bool {
|
|||||||
|
|
||||||
// Unmarshal 输出结果到结构体中
|
// Unmarshal 输出结果到结构体中
|
||||||
func (cfg *SysConf) Unmarshal(ins interface{}) error {
|
func (cfg *SysConf) Unmarshal(ins interface{}) error {
|
||||||
var structSet func(t reflect.Type, v reflect.Value) error
|
var structSet func(t reflect.Type, v reflect.Value,oriSeg string) error
|
||||||
t := reflect.TypeOf(ins)
|
t := reflect.TypeOf(ins)
|
||||||
v := reflect.ValueOf(ins).Elem()
|
v := reflect.ValueOf(ins).Elem()
|
||||||
if v.Kind() != reflect.Struct {
|
if v.Kind() != reflect.Struct {
|
||||||
@@ -480,7 +486,7 @@ func (cfg *SysConf) Unmarshal(ins interface{}) error {
|
|||||||
return errors.New("Cannot Write!")
|
return errors.New("Cannot Write!")
|
||||||
}
|
}
|
||||||
t = t.Elem()
|
t = t.Elem()
|
||||||
structSet = func(t reflect.Type, v reflect.Value) error {
|
structSet = func(t reflect.Type, v reflect.Value,oriSeg string) error {
|
||||||
for i := 0; i < t.NumField(); i++ {
|
for i := 0; i < t.NumField(); i++ {
|
||||||
tp := t.Field(i)
|
tp := t.Field(i)
|
||||||
vl := v.Field(i)
|
vl := v.Field(i)
|
||||||
@@ -488,11 +494,14 @@ func (cfg *SysConf) Unmarshal(ins interface{}) error {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if vl.Type().Kind() == reflect.Struct {
|
if vl.Type().Kind() == reflect.Struct {
|
||||||
structSet(vl.Type(), vl)
|
structSet(vl.Type(), vl,tp.Tag.Get("seg"))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
seg := tp.Tag.Get("seg")
|
seg := tp.Tag.Get("seg")
|
||||||
key := tp.Tag.Get("key")
|
key := tp.Tag.Get("key")
|
||||||
|
if oriSeg!="" {
|
||||||
|
seg=oriSeg
|
||||||
|
}
|
||||||
if seg == "" || key == "" {
|
if seg == "" || key == "" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -520,12 +529,12 @@ func (cfg *SysConf) Unmarshal(ins interface{}) error {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return structSet(t, v)
|
return structSet(t, v,"")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Marshal 输出结果到结构体中
|
// Marshal 输出结果到结构体中
|
||||||
func (cfg *SysConf) Marshal(ins interface{}) ([]byte, error) {
|
func (cfg *SysConf) Marshal(ins interface{}) ([]byte, error) {
|
||||||
var structSet func(t reflect.Type, v reflect.Value)
|
var structSet func(t reflect.Type, v reflect.Value,oriSeg string)
|
||||||
t := reflect.TypeOf(ins)
|
t := reflect.TypeOf(ins)
|
||||||
v := reflect.ValueOf(ins)
|
v := reflect.ValueOf(ins)
|
||||||
if v.Kind() != reflect.Struct {
|
if v.Kind() != reflect.Struct {
|
||||||
@@ -535,18 +544,21 @@ func (cfg *SysConf) Marshal(ins interface{}) ([]byte, error) {
|
|||||||
t = t.Elem()
|
t = t.Elem()
|
||||||
v = v.Elem()
|
v = v.Elem()
|
||||||
}
|
}
|
||||||
structSet = func(t reflect.Type, v reflect.Value) {
|
structSet = func(t reflect.Type, v reflect.Value,oriSeg string) {
|
||||||
for i := 0; i < t.NumField(); i++ {
|
for i := 0; i < t.NumField(); i++ {
|
||||||
var seg, key, comment string = "", "", ""
|
var seg, key, comment string = "", "", ""
|
||||||
tp := t.Field(i)
|
tp := t.Field(i)
|
||||||
vl := v.Field(i)
|
vl := v.Field(i)
|
||||||
if vl.Type().Kind() == reflect.Struct {
|
if vl.Type().Kind() == reflect.Struct {
|
||||||
structSet(vl.Type(), vl)
|
structSet(vl.Type(), vl,tp.Tag.Get("seg"))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
seg = tp.Tag.Get("seg")
|
seg = tp.Tag.Get("seg")
|
||||||
key = tp.Tag.Get("key")
|
key = tp.Tag.Get("key")
|
||||||
comment = tp.Tag.Get("comment")
|
comment = tp.Tag.Get("comment")
|
||||||
|
if oriSeg != "" {
|
||||||
|
seg=oriSeg
|
||||||
|
}
|
||||||
if seg == "" || key == "" {
|
if seg == "" || key == "" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -557,7 +569,7 @@ func (cfg *SysConf) Marshal(ins interface{}) ([]byte, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
structSet(t, v)
|
structSet(t, v,"")
|
||||||
return cfg.Build(), nil
|
return cfg.Build(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -36,3 +36,33 @@ func Test_Parse(t *testing.T) {
|
|||||||
//fmt.Println(cfg.Data[0].Comment)
|
//fmt.Println(cfg.Data[0].Comment)
|
||||||
fmt.Println(string(cfg.Build()))
|
fmt.Println(string(cfg.Build()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type slicetest struct {
|
||||||
|
A string `seg:"s" key:"a"`
|
||||||
|
B string `seg:"a" key:"b"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type testme struct {
|
||||||
|
Love slicetest `seg:"love"`
|
||||||
|
Star slicetest `seg:"star"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Marshal(t *testing.T) {
|
||||||
|
|
||||||
|
var info string =`
|
||||||
|
[love]
|
||||||
|
a=abc
|
||||||
|
b=123
|
||||||
|
[star]
|
||||||
|
a=456
|
||||||
|
b=789
|
||||||
|
`
|
||||||
|
var tmp testme
|
||||||
|
ini:=NewIni()
|
||||||
|
ini.Parse([]byte(info))
|
||||||
|
ini.Unmarshal(&tmp)
|
||||||
|
fmt.Printf("%+v\n",tmp)
|
||||||
|
b,_:=ini.Marshal(tmp)
|
||||||
|
fmt.Println(string(b))
|
||||||
|
}
|
||||||
@@ -2,7 +2,9 @@ package staros
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"errors"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -42,3 +44,116 @@ func readAsString(path string) (string, error) {
|
|||||||
}
|
}
|
||||||
return string(data), nil
|
return string(data), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func remainOne(data, old, new string) string {
|
||||||
|
data = strings.TrimSpace(data)
|
||||||
|
if !strings.Contains(data, old) {
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
data = strings.ReplaceAll(data, old, new)
|
||||||
|
return remainOne(data, old, new)
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseHexIpPort(str string) (string, int, error) {
|
||||||
|
str = strings.TrimSpace(str)
|
||||||
|
if len(str) != 13 && len(str) != 37 {
|
||||||
|
return "", 0, errors.New("Not a valid ip:port addr:" + str)
|
||||||
|
}
|
||||||
|
ipPort := strings.Split(str, ":")
|
||||||
|
if len(ipPort) != 2 {
|
||||||
|
return "", 0, errors.New("Not a valid ip:port addr:" + str)
|
||||||
|
}
|
||||||
|
if len(ipPort[0]) == 8 {
|
||||||
|
ip, err := parseHexIPv4(ipPort[0])
|
||||||
|
if err != nil {
|
||||||
|
return "", 0, err
|
||||||
|
}
|
||||||
|
port, err := parseHexPort(ipPort[1])
|
||||||
|
return ip, port, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(ipPort[0]) == 32 {
|
||||||
|
ip, err := parseHexIPv6(ipPort[0])
|
||||||
|
if err != nil {
|
||||||
|
return "", 0, err
|
||||||
|
}
|
||||||
|
port, err := parseHexPort(ipPort[1])
|
||||||
|
return ip, port, err
|
||||||
|
}
|
||||||
|
return "", 0, errors.New("Invalid ip address:" + str)
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseHexPort(str string) (int, error) {
|
||||||
|
tmpUint32, err := strconv.ParseUint(str, 16, 32)
|
||||||
|
return int(tmpUint32), err
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseHexIPv4(str string) (string, error) {
|
||||||
|
var result string
|
||||||
|
if len(str) != 8 {
|
||||||
|
return "", errors.New("Not a vaild ipv4:" + str)
|
||||||
|
}
|
||||||
|
tmpUint64, err := strconv.ParseUint(str, 16, 32)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
numicIp := uint32(tmpUint64)
|
||||||
|
for i := 0; i < 4; i++ {
|
||||||
|
result += strconv.FormatUint(uint64(uint8(numicIp>>(8*uint8(i)))), 10) + "."
|
||||||
|
}
|
||||||
|
return result[0 : len(result)-1], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseHexIPv6(str string) (string, error) {
|
||||||
|
var result string
|
||||||
|
if len(str) != 32 {
|
||||||
|
return "", errors.New("Not a vaild ipv6:" + str)
|
||||||
|
}
|
||||||
|
for i := 0; i < 4; i++ {
|
||||||
|
part := str[i*8 : (i+1)*8]
|
||||||
|
tmpUint64, err := strconv.ParseUint(part, 16, 32)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
tmpUint32 := uint32(tmpUint64)
|
||||||
|
//07C2022A
|
||||||
|
for i := 0; i < 4; i++ {
|
||||||
|
tmp := strconv.FormatUint(uint64(uint8(tmpUint32>>uint8(8*i))), 16)
|
||||||
|
if len(tmp) == 1 {
|
||||||
|
tmp = "0" + tmp
|
||||||
|
}
|
||||||
|
result += tmp
|
||||||
|
if (i+1)%2 == 0 {
|
||||||
|
result += ":"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ipv6 := result[0 : len(result)-1]
|
||||||
|
ipv6List := strings.Split(ipv6, ":")
|
||||||
|
prepareZero := false
|
||||||
|
alreadyZero := false
|
||||||
|
for k, v := range ipv6List {
|
||||||
|
if v == "0000" && !alreadyZero {
|
||||||
|
ipv6List[k] = ""
|
||||||
|
prepareZero = true
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if v != "0000" && prepareZero {
|
||||||
|
alreadyZero = true
|
||||||
|
}
|
||||||
|
var nonZero = 0
|
||||||
|
for i := 0; i < 4; i++ {
|
||||||
|
sig := v[i : i+1]
|
||||||
|
if sig != "0" {
|
||||||
|
nonZero = i
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ipv6List[k] = v[nonZero:4]
|
||||||
|
}
|
||||||
|
ipv6 = strings.TrimSuffix(remainOne(strings.Join(ipv6List, ":"), ":::", "::"), "::")
|
||||||
|
if ipv6 == "" {
|
||||||
|
ipv6 = "::0"
|
||||||
|
}
|
||||||
|
return ipv6, nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,6 +4,44 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
KB = 1024
|
||||||
|
MB = KB << 10
|
||||||
|
GB = MB << 10
|
||||||
|
TB = GB << 10
|
||||||
|
PB = TB << 10
|
||||||
|
)
|
||||||
|
const (
|
||||||
|
TCP_UNKNOWN = iota
|
||||||
|
TCP_ESTABLISHED
|
||||||
|
TCP_SYN_SENT
|
||||||
|
TCP_SYN_RECV
|
||||||
|
TCP_FIN_WAIT1
|
||||||
|
TCP_FIN_WAIT2
|
||||||
|
TCP_TIME_WAIT
|
||||||
|
TCP_CLOSE
|
||||||
|
TCP_CLOSE_WAIT
|
||||||
|
TCP_LAST_ACL
|
||||||
|
TCP_LISTEN
|
||||||
|
TCP_CLOSING
|
||||||
|
)
|
||||||
|
|
||||||
|
var TCP_STATE = []string{"TCP_UNKNOWN", "TCP_ESTABLISHED", "TCP_SYN_SENT", "TCP_SYN_RECV", "TCP_FIN_WAIT1", "TCP_FIN_WAIT2", "TCP_TIME_WAIT", "TCP_CLOSE", "TCP_CLOSE_WAIT", "TCP_LAST_ACL", "TCP_LISTEN", "TCP_CLOSING"}
|
||||||
|
|
||||||
|
type NetAdapter struct {
|
||||||
|
Name string
|
||||||
|
RecvBytes uint64
|
||||||
|
SendBytes uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
type NetSpeed struct {
|
||||||
|
Name string
|
||||||
|
RecvSpeeds float64
|
||||||
|
SendSpeeds float64
|
||||||
|
RecvBytes uint64
|
||||||
|
SendBytes uint64
|
||||||
|
}
|
||||||
|
|
||||||
// Process 定义一个进程的信息
|
// Process 定义一个进程的信息
|
||||||
type Process struct {
|
type Process struct {
|
||||||
PPid int64
|
PPid int64
|
||||||
@@ -11,13 +49,28 @@ type Process struct {
|
|||||||
Name string
|
Name string
|
||||||
ExecPath string
|
ExecPath string
|
||||||
LocalPath string
|
LocalPath string
|
||||||
|
Path string
|
||||||
Args []string
|
Args []string
|
||||||
|
Env []string
|
||||||
RUID int
|
RUID int
|
||||||
EUID int
|
EUID int
|
||||||
RGID int
|
RGID int
|
||||||
EGID int
|
EGID int
|
||||||
TPid int64
|
TPid int64
|
||||||
Uptime time.Time
|
Uptime time.Time
|
||||||
|
VmPeak int64
|
||||||
|
VmSize int64
|
||||||
|
VmLck int64
|
||||||
|
VmHWM int64
|
||||||
|
VmRSS int64
|
||||||
|
VmData int64
|
||||||
|
netConn []NetConn
|
||||||
|
netErr error
|
||||||
|
Err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p Process) GetNetConns() ([]NetConn, error) {
|
||||||
|
return p.netConn, p.netErr
|
||||||
}
|
}
|
||||||
|
|
||||||
type MemStatus struct {
|
type MemStatus struct {
|
||||||
@@ -42,3 +95,22 @@ type DiskStatus struct {
|
|||||||
Free uint64
|
Free uint64
|
||||||
Available uint64
|
Available uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type NetConn struct {
|
||||||
|
LocalAddr string
|
||||||
|
LocalPort int
|
||||||
|
Typed string
|
||||||
|
RemoteAddr string
|
||||||
|
RemotePort int
|
||||||
|
Socket string
|
||||||
|
Inode string
|
||||||
|
Status string
|
||||||
|
TX_Queue int64
|
||||||
|
RX_Queue int64
|
||||||
|
TimerActive string
|
||||||
|
TimerJiffies int64
|
||||||
|
RtoTimer int64
|
||||||
|
Pid int64
|
||||||
|
Uid int64
|
||||||
|
Process *Process
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user