Compare commits
11 Commits
Author | SHA1 | Date | |
---|---|---|---|
72883cf6bd
|
|||
ff08d5f180
|
|||
72d6b538f7
|
|||
48dd30fb94
|
|||
b7c5756f11
|
|||
2070a432a5
|
|||
34e6d1819d
|
|||
87fa6021e4
|
|||
297d6c52a8
|
|||
b9c46947d2
|
|||
412277b3e0
|
1
.idea/inspectionProfiles/Project_Default.xml
generated
1
.idea/inspectionProfiles/Project_Default.xml
generated
@@ -1,6 +1,7 @@
|
|||||||
<component name="InspectionProjectProfileManager">
|
<component name="InspectionProjectProfileManager">
|
||||||
<profile version="1.0">
|
<profile version="1.0">
|
||||||
<option name="myName" value="Project Default" />
|
<option name="myName" value="Project Default" />
|
||||||
|
<inspection_tool class="GoMixedReceiverTypes" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||||
<inspection_tool class="LanguageDetectionInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
<inspection_tool class="LanguageDetectionInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||||
<inspection_tool class="SpellCheckingInspection" enabled="false" level="TYPO" enabled_by_default="false">
|
<inspection_tool class="SpellCheckingInspection" enabled="false" level="TYPO" enabled_by_default="false">
|
||||||
<option name="processCode" value="true" />
|
<option name="processCode" value="true" />
|
||||||
|
73
cmdext/builder.go
Normal file
73
cmdext/builder.go
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
package cmdext
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CommandRunner struct {
|
||||||
|
program string
|
||||||
|
args []string
|
||||||
|
timeout *time.Duration
|
||||||
|
env []string
|
||||||
|
listener []CommandListener
|
||||||
|
}
|
||||||
|
|
||||||
|
func Runner(program string) *CommandRunner {
|
||||||
|
return &CommandRunner{
|
||||||
|
program: program,
|
||||||
|
args: make([]string, 0),
|
||||||
|
timeout: nil,
|
||||||
|
env: make([]string, 0),
|
||||||
|
listener: make([]CommandListener, 0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *CommandRunner) Arg(arg string) *CommandRunner {
|
||||||
|
r.args = append(r.args, arg)
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *CommandRunner) Args(arg []string) *CommandRunner {
|
||||||
|
r.args = append(r.args, arg...)
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *CommandRunner) Timeout(timeout time.Duration) *CommandRunner {
|
||||||
|
r.timeout = &timeout
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *CommandRunner) Env(key, value string) *CommandRunner {
|
||||||
|
r.env = append(r.env, fmt.Sprintf("%s=%s", key, value))
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *CommandRunner) RawEnv(env string) *CommandRunner {
|
||||||
|
r.env = append(r.env, env)
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *CommandRunner) Envs(env []string) *CommandRunner {
|
||||||
|
r.env = append(r.env, env...)
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *CommandRunner) Listen(lstr CommandListener) *CommandRunner {
|
||||||
|
r.listener = append(r.listener, lstr)
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *CommandRunner) ListenStdout(lstr func(string)) *CommandRunner {
|
||||||
|
r.listener = append(r.listener, genericCommandListener{_readStdoutLine: &lstr})
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *CommandRunner) ListenStderr(lstr func(string)) *CommandRunner {
|
||||||
|
r.listener = append(r.listener, genericCommandListener{_readStderrLine: &lstr})
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *CommandRunner) Run() (CommandResult, error) {
|
||||||
|
return run(*r)
|
||||||
|
}
|
@@ -2,6 +2,7 @@ package cmdext
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
|
"io"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
@@ -14,9 +15,10 @@ type CommandResult struct {
|
|||||||
CommandTimedOut bool
|
CommandTimedOut bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func RunCommand(program string, args []string, timeout *time.Duration) (CommandResult, error) {
|
func run(opt CommandRunner) (CommandResult, error) {
|
||||||
|
cmd := exec.Command(opt.program, opt.args...)
|
||||||
|
|
||||||
cmd := exec.Command(program, args...)
|
cmd.Env = append(cmd.Env, opt.env...)
|
||||||
|
|
||||||
stdoutPipe, err := cmd.StdoutPipe()
|
stdoutPipe, err := cmd.StdoutPipe()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -33,54 +35,126 @@ func RunCommand(program string, args []string, timeout *time.Duration) (CommandR
|
|||||||
return CommandResult{}, err
|
return CommandResult{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
errch := make(chan error, 1)
|
errch := make(chan error, 3)
|
||||||
go func() { errch <- cmd.Wait() }()
|
go func() { errch <- cmd.Wait() }()
|
||||||
|
|
||||||
|
// [1] read raw stdout
|
||||||
|
|
||||||
|
stdoutBufferReader, stdoutBufferWriter := io.Pipe()
|
||||||
|
stdout := ""
|
||||||
|
go func() {
|
||||||
|
buf := make([]byte, 128)
|
||||||
|
for true {
|
||||||
|
n, out := stdoutPipe.Read(buf)
|
||||||
|
|
||||||
|
if n > 0 {
|
||||||
|
txt := string(buf[:n])
|
||||||
|
stdout += txt
|
||||||
|
_, _ = stdoutBufferWriter.Write(buf[:n])
|
||||||
|
for _, lstr := range opt.listener {
|
||||||
|
lstr.ReadRawStdout(buf[:n])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if out == io.EOF {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if out != nil {
|
||||||
|
errch <- out
|
||||||
|
_ = cmd.Process.Kill()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ = stdoutBufferWriter.Close()
|
||||||
|
}()
|
||||||
|
|
||||||
|
// [2] read raw stderr
|
||||||
|
|
||||||
|
stderrBufferReader, stderrBufferWriter := io.Pipe()
|
||||||
|
stderr := ""
|
||||||
|
go func() {
|
||||||
|
buf := make([]byte, 128)
|
||||||
|
for true {
|
||||||
|
n, err := stderrPipe.Read(buf)
|
||||||
|
|
||||||
|
if n > 0 {
|
||||||
|
txt := string(buf[:n])
|
||||||
|
stderr += txt
|
||||||
|
_, _ = stderrBufferWriter.Write(buf[:n])
|
||||||
|
for _, lstr := range opt.listener {
|
||||||
|
lstr.ReadRawStderr(buf[:n])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err == io.EOF {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
errch <- err
|
||||||
|
_ = cmd.Process.Kill()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ = stderrBufferWriter.Close()
|
||||||
|
}()
|
||||||
|
|
||||||
combch := make(chan string, 32)
|
combch := make(chan string, 32)
|
||||||
stopCombch := make(chan bool)
|
stopCombch := make(chan bool)
|
||||||
|
|
||||||
stdout := ""
|
// [3] collect stdout line-by-line
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
scanner := bufio.NewScanner(stdoutPipe)
|
scanner := bufio.NewScanner(stdoutBufferReader)
|
||||||
for scanner.Scan() {
|
for scanner.Scan() {
|
||||||
txt := scanner.Text()
|
txt := scanner.Text()
|
||||||
stdout += txt
|
for _, lstr := range opt.listener {
|
||||||
|
lstr.ReadStdoutLine(txt)
|
||||||
|
}
|
||||||
combch <- txt
|
combch <- txt
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
stderr := ""
|
// [4] collect stderr line-by-line
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
scanner := bufio.NewScanner(stderrPipe)
|
scanner := bufio.NewScanner(stderrBufferReader)
|
||||||
for scanner.Scan() {
|
for scanner.Scan() {
|
||||||
txt := scanner.Text()
|
txt := scanner.Text()
|
||||||
stderr += txt
|
for _, lstr := range opt.listener {
|
||||||
|
lstr.ReadStderrLine(txt)
|
||||||
|
}
|
||||||
combch <- txt
|
combch <- txt
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
defer func() {
|
defer func() { stopCombch <- true }()
|
||||||
stopCombch <- true
|
|
||||||
}()
|
// [5] combine stdcombined
|
||||||
|
|
||||||
stdcombined := ""
|
stdcombined := ""
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case txt := <-combch:
|
case txt := <-combch:
|
||||||
stdcombined += txt
|
stdcombined += txt + "\n" // this comes from bufio.Scanner and has no newlines...
|
||||||
case <-stopCombch:
|
case <-stopCombch:
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
if timeout != nil {
|
// [6] run
|
||||||
|
|
||||||
|
var timeoutChan <-chan time.Time = make(chan time.Time, 1)
|
||||||
|
if opt.timeout != nil {
|
||||||
|
timeoutChan = time.After(*opt.timeout)
|
||||||
|
}
|
||||||
|
|
||||||
select {
|
select {
|
||||||
|
|
||||||
case <-time.After(*timeout):
|
case <-timeoutChan:
|
||||||
_ = cmd.Process.Kill()
|
_ = cmd.Process.Kill()
|
||||||
|
for _, lstr := range opt.listener {
|
||||||
|
lstr.Timeout()
|
||||||
|
}
|
||||||
return CommandResult{
|
return CommandResult{
|
||||||
StdOut: stdout,
|
StdOut: stdout,
|
||||||
StdErr: stderr,
|
StdErr: stderr,
|
||||||
@@ -91,16 +165,23 @@ func RunCommand(program string, args []string, timeout *time.Duration) (CommandR
|
|||||||
|
|
||||||
case err := <-errch:
|
case err := <-errch:
|
||||||
if exiterr, ok := err.(*exec.ExitError); ok {
|
if exiterr, ok := err.(*exec.ExitError); ok {
|
||||||
|
excode := exiterr.ExitCode()
|
||||||
|
for _, lstr := range opt.listener {
|
||||||
|
lstr.Finished(excode)
|
||||||
|
}
|
||||||
return CommandResult{
|
return CommandResult{
|
||||||
StdOut: stdout,
|
StdOut: stdout,
|
||||||
StdErr: stderr,
|
StdErr: stderr,
|
||||||
StdCombined: stdcombined,
|
StdCombined: stdcombined,
|
||||||
ExitCode: exiterr.ExitCode(),
|
ExitCode: excode,
|
||||||
CommandTimedOut: false,
|
CommandTimedOut: false,
|
||||||
}, nil
|
}, nil
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
return CommandResult{}, err
|
return CommandResult{}, err
|
||||||
} else {
|
} else {
|
||||||
|
for _, lstr := range opt.listener {
|
||||||
|
lstr.Finished(0)
|
||||||
|
}
|
||||||
return CommandResult{
|
return CommandResult{
|
||||||
StdOut: stdout,
|
StdOut: stdout,
|
||||||
StdErr: stderr,
|
StdErr: stderr,
|
||||||
@@ -109,34 +190,5 @@ func RunCommand(program string, args []string, timeout *time.Duration) (CommandR
|
|||||||
CommandTimedOut: false,
|
CommandTimedOut: false,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
select {
|
|
||||||
|
|
||||||
case err := <-errch:
|
|
||||||
if exiterr, ok := err.(*exec.ExitError); ok {
|
|
||||||
return CommandResult{
|
|
||||||
StdOut: stdout,
|
|
||||||
StdErr: stderr,
|
|
||||||
StdCombined: stdcombined,
|
|
||||||
ExitCode: exiterr.ExitCode(),
|
|
||||||
CommandTimedOut: false,
|
|
||||||
}, nil
|
|
||||||
} else if err != nil {
|
|
||||||
return CommandResult{}, err
|
|
||||||
} else {
|
|
||||||
return CommandResult{
|
|
||||||
StdOut: stdout,
|
|
||||||
StdErr: stderr,
|
|
||||||
StdCombined: stdcombined,
|
|
||||||
ExitCode: 0,
|
|
||||||
CommandTimedOut: false,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
59
cmdext/cmdrunner_test.go
Normal file
59
cmdext/cmdrunner_test.go
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
package cmdext
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestStdout(t *testing.T) {
|
||||||
|
|
||||||
|
res1, err := Runner("printf").Arg("hello").Run()
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("%v", err)
|
||||||
|
}
|
||||||
|
if res1.StdErr != "" {
|
||||||
|
t.Errorf("res1.StdErr == '%v'", res1.StdErr)
|
||||||
|
}
|
||||||
|
if res1.StdOut != "hello" {
|
||||||
|
t.Errorf("res1.StdOut == '%v'", res1.StdOut)
|
||||||
|
}
|
||||||
|
if res1.StdCombined != "hello\n" {
|
||||||
|
t.Errorf("res1.StdCombined == '%v'", res1.StdCombined)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStderr(t *testing.T) {
|
||||||
|
|
||||||
|
res1, err := Runner("python").Arg("-c").Arg("import sys; print(\"error\", file=sys.stderr, end='')").Run()
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("%v", err)
|
||||||
|
}
|
||||||
|
if res1.StdErr != "error" {
|
||||||
|
t.Errorf("res1.StdErr == '%v'", res1.StdErr)
|
||||||
|
}
|
||||||
|
if res1.StdOut != "" {
|
||||||
|
t.Errorf("res1.StdOut == '%v'", res1.StdOut)
|
||||||
|
}
|
||||||
|
if res1.StdCombined != "error\n" {
|
||||||
|
t.Errorf("res1.StdCombined == '%v'", res1.StdCombined)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStdcombined(t *testing.T) {
|
||||||
|
res1, err := Runner("python").
|
||||||
|
Arg("-c").
|
||||||
|
Arg("import sys; import time; print(\"1\", file=sys.stderr, flush=True); time.sleep(0.1); print(\"2\", file=sys.stdout, flush=True); time.sleep(0.1); print(\"3\", file=sys.stderr, flush=True)").
|
||||||
|
Run()
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("%v", err)
|
||||||
|
}
|
||||||
|
if res1.StdErr != "1\n3\n" {
|
||||||
|
t.Errorf("res1.StdErr == '%v'", res1.StdErr)
|
||||||
|
}
|
||||||
|
if res1.StdOut != "2\n" {
|
||||||
|
t.Errorf("res1.StdOut == '%v'", res1.StdOut)
|
||||||
|
}
|
||||||
|
if res1.StdCombined != "1\n2\n3\n" {
|
||||||
|
t.Errorf("res1.StdCombined == '%v'", res1.StdCombined)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
12
cmdext/helper.go
Normal file
12
cmdext/helper.go
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
package cmdext
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
func RunCommand(program string, args []string, timeout *time.Duration) (CommandResult, error) {
|
||||||
|
b := Runner(program)
|
||||||
|
b = b.Args(args)
|
||||||
|
if timeout != nil {
|
||||||
|
b = b.Timeout(*timeout)
|
||||||
|
}
|
||||||
|
return b.Run()
|
||||||
|
}
|
57
cmdext/listener.go
Normal file
57
cmdext/listener.go
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
package cmdext
|
||||||
|
|
||||||
|
type CommandListener interface {
|
||||||
|
ReadRawStdout([]byte)
|
||||||
|
ReadRawStderr([]byte)
|
||||||
|
|
||||||
|
ReadStdoutLine(string)
|
||||||
|
ReadStderrLine(string)
|
||||||
|
|
||||||
|
Finished(int)
|
||||||
|
Timeout()
|
||||||
|
}
|
||||||
|
|
||||||
|
type genericCommandListener struct {
|
||||||
|
_readRawStdout *func([]byte)
|
||||||
|
_readRawStderr *func([]byte)
|
||||||
|
_readStdoutLine *func(string)
|
||||||
|
_readStderrLine *func(string)
|
||||||
|
_finished *func(int)
|
||||||
|
_timeout *func()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g genericCommandListener) ReadRawStdout(v []byte) {
|
||||||
|
if g._readRawStdout != nil {
|
||||||
|
(*g._readRawStdout)(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g genericCommandListener) ReadRawStderr(v []byte) {
|
||||||
|
if g._readRawStderr != nil {
|
||||||
|
(*g._readRawStderr)(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g genericCommandListener) ReadStdoutLine(v string) {
|
||||||
|
if g._readStdoutLine != nil {
|
||||||
|
(*g._readStdoutLine)(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g genericCommandListener) ReadStderrLine(v string) {
|
||||||
|
if g._readStderrLine != nil {
|
||||||
|
(*g._readStderrLine)(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g genericCommandListener) Finished(v int) {
|
||||||
|
if g._finished != nil {
|
||||||
|
(*g._finished)(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g genericCommandListener) Timeout() {
|
||||||
|
if g._timeout != nil {
|
||||||
|
(*g._timeout)()
|
||||||
|
}
|
||||||
|
}
|
68
cryptext/aes.go
Normal file
68
cryptext/aes.go
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
package cryptext
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/aes"
|
||||||
|
"crypto/cipher"
|
||||||
|
"crypto/rand"
|
||||||
|
"encoding/base64"
|
||||||
|
"errors"
|
||||||
|
"golang.org/x/crypto/scrypt"
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
// https://stackoverflow.com/a/18819040/1761622
|
||||||
|
|
||||||
|
func EncryptAESSimple(password, text []byte) ([]byte, error) {
|
||||||
|
|
||||||
|
key, err := scrypt.Key(password, nil, 32768, 8, 1, 32) // this is not 100% correct, rounds too low and salt is missing
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
block, err := aes.NewCipher(key)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
b := base64.StdEncoding.EncodeToString(text)
|
||||||
|
ciphertext := make([]byte, aes.BlockSize+len(b))
|
||||||
|
|
||||||
|
iv := ciphertext[:aes.BlockSize]
|
||||||
|
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
cfb := cipher.NewCFBEncrypter(block, iv)
|
||||||
|
cfb.XORKeyStream(ciphertext[aes.BlockSize:], []byte(b))
|
||||||
|
|
||||||
|
return ciphertext, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func DecryptAESSimple(password, text []byte) ([]byte, error) {
|
||||||
|
|
||||||
|
key, err := scrypt.Key(password, nil, 32768, 8, 1, 32) // this is not 100% correct, rounds too low and salt is missing
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
block, err := aes.NewCipher(key)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(text) < aes.BlockSize {
|
||||||
|
return nil, errors.New("ciphertext too short")
|
||||||
|
}
|
||||||
|
|
||||||
|
iv := text[:aes.BlockSize]
|
||||||
|
text = text[aes.BlockSize:]
|
||||||
|
cfb := cipher.NewCFBDecrypter(block, iv)
|
||||||
|
cfb.XORKeyStream(text, text)
|
||||||
|
|
||||||
|
data, err := base64.StdEncoding.DecodeString(string(text))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return data, nil
|
||||||
|
}
|
22
cryptext/aes_test.go
Normal file
22
cryptext/aes_test.go
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
package cryptext
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestEncryptAESSimple(t *testing.T) {
|
||||||
|
|
||||||
|
pw := []byte("hunter12")
|
||||||
|
|
||||||
|
str1 := []byte("Hello World")
|
||||||
|
|
||||||
|
str2, err := EncryptAESSimple(pw, str1)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
str3, err := DecryptAESSimple(pw, str2)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEqual(t, string(str1), string(str3))
|
||||||
|
}
|
@@ -105,3 +105,12 @@ func (s *Stack[T]) Length() int {
|
|||||||
|
|
||||||
return len(s.data)
|
return len(s.data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Stack[T]) Empty() bool {
|
||||||
|
if s.lock != nil {
|
||||||
|
s.lock.Lock()
|
||||||
|
defer s.lock.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
return len(s.data) == 0
|
||||||
|
}
|
||||||
|
@@ -265,6 +265,16 @@ func ArrMap[T1 any, T2 any](arr []T1, conv func(v T1) T2) []T2 {
|
|||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ArrFilterMap[T1 any, T2 any](arr []T1, filter func(v T1) bool, conv func(v T1) T2) []T2 {
|
||||||
|
r := make([]T2, 0, len(arr))
|
||||||
|
for _, v := range arr {
|
||||||
|
if filter(v) {
|
||||||
|
r = append(r, conv(v))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
func ArrSum[T NumberConstraint](arr []T) T {
|
func ArrSum[T NumberConstraint](arr []T) T {
|
||||||
var r T = 0
|
var r T = 0
|
||||||
for _, v := range arr {
|
for _, v := range arr {
|
||||||
|
@@ -37,3 +37,21 @@ func IsSliceSorted[T any](arr []T, less func(v1, v2 T) bool) bool {
|
|||||||
return less(arr[i1], arr[i2])
|
return less(arr[i1], arr[i2])
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func SortBy[TElem any, TSel OrderedConstraint](arr []TElem, selector func(v TElem) TSel) {
|
||||||
|
sort.Slice(arr, func(i1, i2 int) bool {
|
||||||
|
return selector(arr[i1]) < selector(arr[i2])
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func SortByStable[TElem any, TSel OrderedConstraint](arr []TElem, selector func(v TElem) TSel) {
|
||||||
|
sort.SliceStable(arr, func(i1, i2 int) bool {
|
||||||
|
return selector(arr[i1]) < selector(arr[i2])
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsSortedBy[TElem any, TSel OrderedConstraint](arr []TElem, selector func(v TElem) TSel) {
|
||||||
|
sort.SliceStable(arr, func(i1, i2 int) bool {
|
||||||
|
return selector(arr[i1]) < selector(arr[i2])
|
||||||
|
})
|
||||||
|
}
|
||||||
|
45
rfctime/interface.go
Normal file
45
rfctime/interface.go
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
package rfctime
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
type RFCTime interface {
|
||||||
|
Time() time.Time
|
||||||
|
Serialize() string
|
||||||
|
|
||||||
|
UnmarshalJSON(bytes []byte) error
|
||||||
|
MarshalJSON() ([]byte, error)
|
||||||
|
|
||||||
|
MarshalBinary() ([]byte, error)
|
||||||
|
UnmarshalBinary(data []byte) error
|
||||||
|
|
||||||
|
GobEncode() ([]byte, error)
|
||||||
|
GobDecode(data []byte) error
|
||||||
|
|
||||||
|
MarshalText() ([]byte, error)
|
||||||
|
UnmarshalText(data []byte) error
|
||||||
|
|
||||||
|
After(u RFCTime) bool
|
||||||
|
Before(u RFCTime) bool
|
||||||
|
Equal(u RFCTime) bool
|
||||||
|
IsZero() bool
|
||||||
|
Date() (year int, month time.Month, day int)
|
||||||
|
Year() int
|
||||||
|
Month() time.Month
|
||||||
|
Day() int
|
||||||
|
Weekday() time.Weekday
|
||||||
|
ISOWeek() (year, week int)
|
||||||
|
Clock() (hour, min, sec int)
|
||||||
|
Hour() int
|
||||||
|
Minute() int
|
||||||
|
Second() int
|
||||||
|
Nanosecond() int
|
||||||
|
YearDay() int
|
||||||
|
Sub(u RFCTime) time.Duration
|
||||||
|
Unix() int64
|
||||||
|
UnixMilli() int64
|
||||||
|
UnixMicro() int64
|
||||||
|
UnixNano() int64
|
||||||
|
Format(layout string) string
|
||||||
|
GoString() string
|
||||||
|
String() string
|
||||||
|
}
|
182
rfctime/rfc3339.go
Normal file
182
rfctime/rfc3339.go
Normal file
@@ -0,0 +1,182 @@
|
|||||||
|
package rfctime
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type RFC3339Time time.Time
|
||||||
|
|
||||||
|
func (t RFC3339Time) Time() time.Time {
|
||||||
|
return time.Time(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339Time) MarshalBinary() ([]byte, error) {
|
||||||
|
return (time.Time)(t).MarshalBinary()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *RFC3339Time) UnmarshalBinary(data []byte) error {
|
||||||
|
return (*time.Time)(t).UnmarshalBinary(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339Time) GobEncode() ([]byte, error) {
|
||||||
|
return (time.Time)(t).GobEncode()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *RFC3339Time) GobDecode(data []byte) error {
|
||||||
|
return (*time.Time)(t).GobDecode(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *RFC3339Time) UnmarshalJSON(data []byte) error {
|
||||||
|
str := ""
|
||||||
|
if err := json.Unmarshal(data, &str); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
t0, err := time.Parse(t.FormatStr(), str)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
*t = RFC3339Time(t0)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339Time) MarshalJSON() ([]byte, error) {
|
||||||
|
str := t.Time().Format(t.FormatStr())
|
||||||
|
return json.Marshal(str)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339Time) MarshalText() ([]byte, error) {
|
||||||
|
b := make([]byte, 0, len(t.FormatStr()))
|
||||||
|
return t.Time().AppendFormat(b, t.FormatStr()), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *RFC3339Time) UnmarshalText(data []byte) error {
|
||||||
|
var err error
|
||||||
|
v, err := time.Parse(t.FormatStr(), string(data))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
tt := RFC3339Time(v)
|
||||||
|
*t = tt
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339Time) Serialize() string {
|
||||||
|
return t.Time().Format(t.FormatStr())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339Time) FormatStr() string {
|
||||||
|
return time.RFC3339
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339Time) After(u RFCTime) bool {
|
||||||
|
return t.Time().After(u.Time())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339Time) Before(u RFCTime) bool {
|
||||||
|
return t.Time().Before(u.Time())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339Time) Equal(u RFCTime) bool {
|
||||||
|
return t.Time().Equal(u.Time())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339Time) IsZero() bool {
|
||||||
|
return t.Time().IsZero()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339Time) Date() (year int, month time.Month, day int) {
|
||||||
|
return t.Time().Date()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339Time) Year() int {
|
||||||
|
return t.Time().Year()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339Time) Month() time.Month {
|
||||||
|
return t.Time().Month()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339Time) Day() int {
|
||||||
|
return t.Time().Day()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339Time) Weekday() time.Weekday {
|
||||||
|
return t.Time().Weekday()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339Time) ISOWeek() (year, week int) {
|
||||||
|
return t.Time().ISOWeek()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339Time) Clock() (hour, min, sec int) {
|
||||||
|
return t.Time().Clock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339Time) Hour() int {
|
||||||
|
return t.Time().Hour()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339Time) Minute() int {
|
||||||
|
return t.Time().Minute()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339Time) Second() int {
|
||||||
|
return t.Time().Second()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339Time) Nanosecond() int {
|
||||||
|
return t.Time().Nanosecond()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339Time) YearDay() int {
|
||||||
|
return t.Time().YearDay()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339Time) Add(d time.Duration) RFC3339Time {
|
||||||
|
return RFC3339Time(t.Time().Add(d))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339Time) Sub(u RFCTime) time.Duration {
|
||||||
|
return t.Time().Sub(u.Time())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339Time) AddDate(years int, months int, days int) RFC3339Time {
|
||||||
|
return RFC3339Time(t.Time().AddDate(years, months, days))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339Time) Unix() int64 {
|
||||||
|
return t.Time().Unix()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339Time) UnixMilli() int64 {
|
||||||
|
return t.Time().UnixMilli()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339Time) UnixMicro() int64 {
|
||||||
|
return t.Time().UnixMicro()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339Time) UnixNano() int64 {
|
||||||
|
return t.Time().UnixNano()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339Time) Format(layout string) string {
|
||||||
|
return t.Time().Format(layout)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339Time) GoString() string {
|
||||||
|
return t.Time().GoString()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339Time) String() string {
|
||||||
|
return t.Time().String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewRFC3339(t time.Time) RFC3339Time {
|
||||||
|
return RFC3339Time(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NowRFC3339() RFC3339Time {
|
||||||
|
return RFC3339Time(time.Now())
|
||||||
|
}
|
182
rfctime/rfc3339Nano.go
Normal file
182
rfctime/rfc3339Nano.go
Normal file
@@ -0,0 +1,182 @@
|
|||||||
|
package rfctime
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type RFC3339NanoTime time.Time
|
||||||
|
|
||||||
|
func (t RFC3339NanoTime) Time() time.Time {
|
||||||
|
return time.Time(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339NanoTime) MarshalBinary() ([]byte, error) {
|
||||||
|
return (time.Time)(t).MarshalBinary()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *RFC3339NanoTime) UnmarshalBinary(data []byte) error {
|
||||||
|
return (*time.Time)(t).UnmarshalBinary(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339NanoTime) GobEncode() ([]byte, error) {
|
||||||
|
return (time.Time)(t).GobEncode()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *RFC3339NanoTime) GobDecode(data []byte) error {
|
||||||
|
return (*time.Time)(t).GobDecode(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *RFC3339NanoTime) UnmarshalJSON(data []byte) error {
|
||||||
|
str := ""
|
||||||
|
if err := json.Unmarshal(data, &str); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
t0, err := time.Parse(t.FormatStr(), str)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
*t = RFC3339NanoTime(t0)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339NanoTime) MarshalJSON() ([]byte, error) {
|
||||||
|
str := t.Time().Format(t.FormatStr())
|
||||||
|
return json.Marshal(str)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339NanoTime) MarshalText() ([]byte, error) {
|
||||||
|
b := make([]byte, 0, len(t.FormatStr()))
|
||||||
|
return t.Time().AppendFormat(b, t.FormatStr()), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *RFC3339NanoTime) UnmarshalText(data []byte) error {
|
||||||
|
var err error
|
||||||
|
v, err := time.Parse(t.FormatStr(), string(data))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
tt := RFC3339NanoTime(v)
|
||||||
|
*t = tt
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339NanoTime) Serialize() string {
|
||||||
|
return t.Time().Format(t.FormatStr())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339NanoTime) FormatStr() string {
|
||||||
|
return time.RFC3339Nano
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339NanoTime) After(u RFCTime) bool {
|
||||||
|
return t.Time().After(u.Time())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339NanoTime) Before(u RFCTime) bool {
|
||||||
|
return t.Time().Before(u.Time())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339NanoTime) Equal(u RFCTime) bool {
|
||||||
|
return t.Time().Equal(u.Time())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339NanoTime) IsZero() bool {
|
||||||
|
return t.Time().IsZero()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339NanoTime) Date() (year int, month time.Month, day int) {
|
||||||
|
return t.Time().Date()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339NanoTime) Year() int {
|
||||||
|
return t.Time().Year()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339NanoTime) Month() time.Month {
|
||||||
|
return t.Time().Month()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339NanoTime) Day() int {
|
||||||
|
return t.Time().Day()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339NanoTime) Weekday() time.Weekday {
|
||||||
|
return t.Time().Weekday()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339NanoTime) ISOWeek() (year, week int) {
|
||||||
|
return t.Time().ISOWeek()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339NanoTime) Clock() (hour, min, sec int) {
|
||||||
|
return t.Time().Clock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339NanoTime) Hour() int {
|
||||||
|
return t.Time().Hour()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339NanoTime) Minute() int {
|
||||||
|
return t.Time().Minute()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339NanoTime) Second() int {
|
||||||
|
return t.Time().Second()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339NanoTime) Nanosecond() int {
|
||||||
|
return t.Time().Nanosecond()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339NanoTime) YearDay() int {
|
||||||
|
return t.Time().YearDay()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339NanoTime) Add(d time.Duration) RFC3339NanoTime {
|
||||||
|
return RFC3339NanoTime(t.Time().Add(d))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339NanoTime) Sub(u RFCTime) time.Duration {
|
||||||
|
return t.Time().Sub(u.Time())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339NanoTime) AddDate(years int, months int, days int) RFC3339NanoTime {
|
||||||
|
return RFC3339NanoTime(t.Time().AddDate(years, months, days))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339NanoTime) Unix() int64 {
|
||||||
|
return t.Time().Unix()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339NanoTime) UnixMilli() int64 {
|
||||||
|
return t.Time().UnixMilli()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339NanoTime) UnixMicro() int64 {
|
||||||
|
return t.Time().UnixMicro()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339NanoTime) UnixNano() int64 {
|
||||||
|
return t.Time().UnixNano()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339NanoTime) Format(layout string) string {
|
||||||
|
return t.Time().Format(layout)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339NanoTime) GoString() string {
|
||||||
|
return t.Time().GoString()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339NanoTime) String() string {
|
||||||
|
return t.Time().String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewRFC3339Nano(t time.Time) RFC3339NanoTime {
|
||||||
|
return RFC3339NanoTime(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NowRFC3339Nano() RFC3339NanoTime {
|
||||||
|
return RFC3339NanoTime(time.Now())
|
||||||
|
}
|
51
rfctime/rfc3339Nano_test.go
Normal file
51
rfctime/rfc3339Nano_test.go
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
package rfctime
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestRoundtrip(t *testing.T) {
|
||||||
|
|
||||||
|
type Wrap struct {
|
||||||
|
Value RFC3339NanoTime `json:"v"`
|
||||||
|
}
|
||||||
|
|
||||||
|
val1 := NewRFC3339Nano(time.Now())
|
||||||
|
w1 := Wrap{val1}
|
||||||
|
|
||||||
|
jstr1, err := json.Marshal(w1)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if string(jstr1) != "{\"v\":\"2023-01-29T20:32:36.149692117+01:00\"}" {
|
||||||
|
t.Errorf("repr differs")
|
||||||
|
}
|
||||||
|
|
||||||
|
w2 := Wrap{}
|
||||||
|
|
||||||
|
err = json.Unmarshal(jstr1, &w2)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
jstr2, err := json.Marshal(w2)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEqual(t, string(jstr1), string(jstr2))
|
||||||
|
|
||||||
|
if !w1.Value.Equal(&w2.Value) {
|
||||||
|
t.Errorf("time differs")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func assertEqual(t *testing.T, actual string, expected string) {
|
||||||
|
if actual != expected {
|
||||||
|
t.Errorf("values differ: Actual: '%v', Expected: '%v'", actual, expected)
|
||||||
|
}
|
||||||
|
}
|
176
rfctime/unix.go
Normal file
176
rfctime/unix.go
Normal file
@@ -0,0 +1,176 @@
|
|||||||
|
package rfctime
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UnixTime time.Time
|
||||||
|
|
||||||
|
func (t UnixTime) Time() time.Time {
|
||||||
|
return time.Time(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixTime) MarshalBinary() ([]byte, error) {
|
||||||
|
return (time.Time)(t).MarshalBinary()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *UnixTime) UnmarshalBinary(data []byte) error {
|
||||||
|
return (*time.Time)(t).UnmarshalBinary(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixTime) GobEncode() ([]byte, error) {
|
||||||
|
return (time.Time)(t).GobEncode()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *UnixTime) GobDecode(data []byte) error {
|
||||||
|
return (*time.Time)(t).GobDecode(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *UnixTime) UnmarshalJSON(data []byte) error {
|
||||||
|
str := ""
|
||||||
|
if err := json.Unmarshal(data, &str); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
t0, err := strconv.ParseInt(str, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
*t = UnixTime(time.Unix(t0, 0))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixTime) MarshalJSON() ([]byte, error) {
|
||||||
|
str := strconv.FormatInt(t.Time().Unix(), 10)
|
||||||
|
return json.Marshal(str)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixTime) MarshalText() ([]byte, error) {
|
||||||
|
return []byte(strconv.FormatInt(t.Time().Unix(), 10)), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *UnixTime) UnmarshalText(data []byte) error {
|
||||||
|
t0, err := strconv.ParseInt(string(data), 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
*t = UnixTime(time.Unix(t0, 0))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixTime) Serialize() string {
|
||||||
|
return strconv.FormatInt(t.Time().Unix(), 10)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixTime) After(u RFCTime) bool {
|
||||||
|
return t.Time().After(u.Time())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixTime) Before(u RFCTime) bool {
|
||||||
|
return t.Time().Before(u.Time())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixTime) Equal(u RFCTime) bool {
|
||||||
|
return t.Time().Equal(u.Time())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixTime) IsZero() bool {
|
||||||
|
return t.Time().IsZero()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixTime) Date() (year int, month time.Month, day int) {
|
||||||
|
return t.Time().Date()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixTime) Year() int {
|
||||||
|
return t.Time().Year()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixTime) Month() time.Month {
|
||||||
|
return t.Time().Month()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixTime) Day() int {
|
||||||
|
return t.Time().Day()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixTime) Weekday() time.Weekday {
|
||||||
|
return t.Time().Weekday()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixTime) ISOWeek() (year, week int) {
|
||||||
|
return t.Time().ISOWeek()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixTime) Clock() (hour, min, sec int) {
|
||||||
|
return t.Time().Clock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixTime) Hour() int {
|
||||||
|
return t.Time().Hour()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixTime) Minute() int {
|
||||||
|
return t.Time().Minute()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixTime) Second() int {
|
||||||
|
return t.Time().Second()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixTime) Nanosecond() int {
|
||||||
|
return t.Time().Nanosecond()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixTime) YearDay() int {
|
||||||
|
return t.Time().YearDay()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixTime) Add(d time.Duration) UnixTime {
|
||||||
|
return UnixTime(t.Time().Add(d))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixTime) Sub(u RFCTime) time.Duration {
|
||||||
|
return t.Time().Sub(u.Time())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixTime) AddDate(years int, months int, days int) UnixTime {
|
||||||
|
return UnixTime(t.Time().AddDate(years, months, days))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixTime) Unix() int64 {
|
||||||
|
return t.Time().Unix()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixTime) UnixMilli() int64 {
|
||||||
|
return t.Time().UnixMilli()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixTime) UnixMicro() int64 {
|
||||||
|
return t.Time().UnixMicro()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixTime) UnixNano() int64 {
|
||||||
|
return t.Time().UnixNano()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixTime) Format(layout string) string {
|
||||||
|
return t.Time().Format(layout)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixTime) GoString() string {
|
||||||
|
return t.Time().GoString()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixTime) String() string {
|
||||||
|
return t.Time().String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewUnix(t time.Time) UnixTime {
|
||||||
|
return UnixTime(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NowUnix() UnixTime {
|
||||||
|
return UnixTime(time.Now())
|
||||||
|
}
|
176
rfctime/unixMilli.go
Normal file
176
rfctime/unixMilli.go
Normal file
@@ -0,0 +1,176 @@
|
|||||||
|
package rfctime
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UnixMilliTime time.Time
|
||||||
|
|
||||||
|
func (t UnixMilliTime) Time() time.Time {
|
||||||
|
return time.Time(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixMilliTime) MarshalBinary() ([]byte, error) {
|
||||||
|
return (time.Time)(t).MarshalBinary()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *UnixMilliTime) UnmarshalBinary(data []byte) error {
|
||||||
|
return (*time.Time)(t).UnmarshalBinary(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixMilliTime) GobEncode() ([]byte, error) {
|
||||||
|
return (time.Time)(t).GobEncode()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *UnixMilliTime) GobDecode(data []byte) error {
|
||||||
|
return (*time.Time)(t).GobDecode(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *UnixMilliTime) UnmarshalJSON(data []byte) error {
|
||||||
|
str := ""
|
||||||
|
if err := json.Unmarshal(data, &str); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
t0, err := strconv.ParseInt(str, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
*t = UnixMilliTime(time.UnixMilli(t0))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixMilliTime) MarshalJSON() ([]byte, error) {
|
||||||
|
str := strconv.FormatInt(t.Time().UnixMilli(), 10)
|
||||||
|
return json.Marshal(str)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixMilliTime) MarshalText() ([]byte, error) {
|
||||||
|
return []byte(strconv.FormatInt(t.Time().UnixMilli(), 10)), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *UnixMilliTime) UnmarshalText(data []byte) error {
|
||||||
|
t0, err := strconv.ParseInt(string(data), 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
*t = UnixMilliTime(time.UnixMilli(t0))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixMilliTime) Serialize() string {
|
||||||
|
return strconv.FormatInt(t.Time().UnixMilli(), 10)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixMilliTime) After(u RFCTime) bool {
|
||||||
|
return t.Time().After(u.Time())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixMilliTime) Before(u RFCTime) bool {
|
||||||
|
return t.Time().Before(u.Time())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixMilliTime) Equal(u RFCTime) bool {
|
||||||
|
return t.Time().Equal(u.Time())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixMilliTime) IsZero() bool {
|
||||||
|
return t.Time().IsZero()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixMilliTime) Date() (year int, month time.Month, day int) {
|
||||||
|
return t.Time().Date()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixMilliTime) Year() int {
|
||||||
|
return t.Time().Year()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixMilliTime) Month() time.Month {
|
||||||
|
return t.Time().Month()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixMilliTime) Day() int {
|
||||||
|
return t.Time().Day()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixMilliTime) Weekday() time.Weekday {
|
||||||
|
return t.Time().Weekday()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixMilliTime) ISOWeek() (year, week int) {
|
||||||
|
return t.Time().ISOWeek()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixMilliTime) Clock() (hour, min, sec int) {
|
||||||
|
return t.Time().Clock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixMilliTime) Hour() int {
|
||||||
|
return t.Time().Hour()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixMilliTime) Minute() int {
|
||||||
|
return t.Time().Minute()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixMilliTime) Second() int {
|
||||||
|
return t.Time().Second()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixMilliTime) Nanosecond() int {
|
||||||
|
return t.Time().Nanosecond()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixMilliTime) YearDay() int {
|
||||||
|
return t.Time().YearDay()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixMilliTime) Add(d time.Duration) UnixMilliTime {
|
||||||
|
return UnixMilliTime(t.Time().Add(d))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixMilliTime) Sub(u RFCTime) time.Duration {
|
||||||
|
return t.Time().Sub(u.Time())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixMilliTime) AddDate(years int, months int, days int) UnixMilliTime {
|
||||||
|
return UnixMilliTime(t.Time().AddDate(years, months, days))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixMilliTime) Unix() int64 {
|
||||||
|
return t.Time().Unix()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixMilliTime) UnixMilli() int64 {
|
||||||
|
return t.Time().UnixMilli()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixMilliTime) UnixMicro() int64 {
|
||||||
|
return t.Time().UnixMicro()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixMilliTime) UnixNano() int64 {
|
||||||
|
return t.Time().UnixNano()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixMilliTime) Format(layout string) string {
|
||||||
|
return t.Time().Format(layout)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixMilliTime) GoString() string {
|
||||||
|
return t.Time().GoString()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixMilliTime) String() string {
|
||||||
|
return t.Time().String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewUnixMilli(t time.Time) UnixMilliTime {
|
||||||
|
return UnixMilliTime(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NowUnixMilli() UnixMilliTime {
|
||||||
|
return UnixMilliTime(time.Now())
|
||||||
|
}
|
176
rfctime/unixNano.go
Normal file
176
rfctime/unixNano.go
Normal file
@@ -0,0 +1,176 @@
|
|||||||
|
package rfctime
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UnixNanoTime time.Time
|
||||||
|
|
||||||
|
func (t UnixNanoTime) Time() time.Time {
|
||||||
|
return time.Time(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixNanoTime) MarshalBinary() ([]byte, error) {
|
||||||
|
return (time.Time)(t).MarshalBinary()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *UnixNanoTime) UnmarshalBinary(data []byte) error {
|
||||||
|
return (*time.Time)(t).UnmarshalBinary(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixNanoTime) GobEncode() ([]byte, error) {
|
||||||
|
return (time.Time)(t).GobEncode()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *UnixNanoTime) GobDecode(data []byte) error {
|
||||||
|
return (*time.Time)(t).GobDecode(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *UnixNanoTime) UnmarshalJSON(data []byte) error {
|
||||||
|
str := ""
|
||||||
|
if err := json.Unmarshal(data, &str); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
t0, err := strconv.ParseInt(str, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
*t = UnixNanoTime(time.Unix(0, t0))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixNanoTime) MarshalJSON() ([]byte, error) {
|
||||||
|
str := strconv.FormatInt(t.Time().UnixNano(), 10)
|
||||||
|
return json.Marshal(str)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixNanoTime) MarshalText() ([]byte, error) {
|
||||||
|
return []byte(strconv.FormatInt(t.Time().UnixNano(), 10)), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *UnixNanoTime) UnmarshalText(data []byte) error {
|
||||||
|
t0, err := strconv.ParseInt(string(data), 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
*t = UnixNanoTime(time.Unix(0, t0))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixNanoTime) Serialize() string {
|
||||||
|
return strconv.FormatInt(t.Time().UnixNano(), 10)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixNanoTime) After(u RFCTime) bool {
|
||||||
|
return t.Time().After(u.Time())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixNanoTime) Before(u RFCTime) bool {
|
||||||
|
return t.Time().Before(u.Time())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixNanoTime) Equal(u RFCTime) bool {
|
||||||
|
return t.Time().Equal(u.Time())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixNanoTime) IsZero() bool {
|
||||||
|
return t.Time().IsZero()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixNanoTime) Date() (year int, month time.Month, day int) {
|
||||||
|
return t.Time().Date()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixNanoTime) Year() int {
|
||||||
|
return t.Time().Year()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixNanoTime) Month() time.Month {
|
||||||
|
return t.Time().Month()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixNanoTime) Day() int {
|
||||||
|
return t.Time().Day()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixNanoTime) Weekday() time.Weekday {
|
||||||
|
return t.Time().Weekday()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixNanoTime) ISOWeek() (year, week int) {
|
||||||
|
return t.Time().ISOWeek()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixNanoTime) Clock() (hour, min, sec int) {
|
||||||
|
return t.Time().Clock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixNanoTime) Hour() int {
|
||||||
|
return t.Time().Hour()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixNanoTime) Minute() int {
|
||||||
|
return t.Time().Minute()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixNanoTime) Second() int {
|
||||||
|
return t.Time().Second()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixNanoTime) Nanosecond() int {
|
||||||
|
return t.Time().Nanosecond()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixNanoTime) YearDay() int {
|
||||||
|
return t.Time().YearDay()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixNanoTime) Add(d time.Duration) UnixNanoTime {
|
||||||
|
return UnixNanoTime(t.Time().Add(d))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixNanoTime) Sub(u RFCTime) time.Duration {
|
||||||
|
return t.Time().Sub(u.Time())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixNanoTime) AddDate(years int, months int, days int) UnixNanoTime {
|
||||||
|
return UnixNanoTime(t.Time().AddDate(years, months, days))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixNanoTime) Unix() int64 {
|
||||||
|
return t.Time().Unix()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixNanoTime) UnixMilli() int64 {
|
||||||
|
return t.Time().UnixNano()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixNanoTime) UnixMicro() int64 {
|
||||||
|
return t.Time().UnixMicro()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixNanoTime) UnixNano() int64 {
|
||||||
|
return t.Time().UnixNano()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixNanoTime) Format(layout string) string {
|
||||||
|
return t.Time().Format(layout)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixNanoTime) GoString() string {
|
||||||
|
return t.Time().GoString()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t UnixNanoTime) String() string {
|
||||||
|
return t.Time().String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewUnixNano(t time.Time) UnixNanoTime {
|
||||||
|
return UnixNanoTime(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NowUnixNano() UnixNanoTime {
|
||||||
|
return UnixNanoTime(time.Now())
|
||||||
|
}
|
@@ -2,58 +2,50 @@ package syncext
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"sync/atomic"
|
"gogs.mikescher.com/BlackForestBytes/goext/langext"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type AtomicBool struct {
|
type AtomicBool struct {
|
||||||
v int32
|
v bool
|
||||||
waiter chan bool // unbuffered
|
listener map[string]chan bool
|
||||||
|
lock sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewAtomicBool(value bool) *AtomicBool {
|
func NewAtomicBool(value bool) *AtomicBool {
|
||||||
if value {
|
return &AtomicBool{
|
||||||
return &AtomicBool{v: 1, waiter: make(chan bool)}
|
v: value,
|
||||||
} else {
|
listener: make(map[string]chan bool),
|
||||||
return &AtomicBool{v: 0, waiter: make(chan bool)}
|
lock: sync.Mutex{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *AtomicBool) Get() bool {
|
func (a *AtomicBool) Get() bool {
|
||||||
return atomic.LoadInt32(&a.v) == 1
|
a.lock.Lock()
|
||||||
|
defer a.lock.Unlock()
|
||||||
|
return a.v
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *AtomicBool) Set(value bool) {
|
func (a *AtomicBool) Set(value bool) {
|
||||||
if value {
|
a.lock.Lock()
|
||||||
atomic.StoreInt32(&a.v, 1)
|
defer a.lock.Unlock()
|
||||||
} else {
|
|
||||||
atomic.StoreInt32(&a.v, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
a.v = value
|
||||||
|
|
||||||
|
for k, v := range a.listener {
|
||||||
select {
|
select {
|
||||||
case a.waiter <- value:
|
case v <- value:
|
||||||
// message sent
|
// message sent
|
||||||
default:
|
default:
|
||||||
// no receiver on channel
|
// no receiver on channel
|
||||||
|
delete(a.listener, k)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *AtomicBool) Wait(waitFor bool) {
|
func (a *AtomicBool) Wait(waitFor bool) {
|
||||||
if a.Get() == waitFor {
|
_ = a.WaitWithContext(context.Background(), waitFor)
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
for {
|
|
||||||
if v, ok := ReadChannelWithTimeout(a.waiter, 128*time.Millisecond); ok {
|
|
||||||
if v == waitFor {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if a.Get() == waitFor {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *AtomicBool) WaitWithTimeout(timeout time.Duration, waitFor bool) error {
|
func (a *AtomicBool) WaitWithTimeout(timeout time.Duration, waitFor bool) error {
|
||||||
@@ -71,12 +63,25 @@ func (a *AtomicBool) WaitWithContext(ctx context.Context, waitFor bool) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uuid, _ := langext.NewHexUUID()
|
||||||
|
|
||||||
|
waitchan := make(chan bool)
|
||||||
|
|
||||||
|
a.lock.Lock()
|
||||||
|
a.listener[uuid] = waitchan
|
||||||
|
a.lock.Unlock()
|
||||||
|
defer func() {
|
||||||
|
a.lock.Lock()
|
||||||
|
delete(a.listener, uuid)
|
||||||
|
a.lock.Unlock()
|
||||||
|
}()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
if err := ctx.Err(); err != nil {
|
if err := ctx.Err(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
timeOut := 128 * time.Millisecond
|
timeOut := 1024 * time.Millisecond
|
||||||
|
|
||||||
if dl, ok := ctx.Deadline(); ok {
|
if dl, ok := ctx.Deadline(); ok {
|
||||||
timeOutMax := dl.Sub(time.Now())
|
timeOutMax := dl.Sub(time.Now())
|
||||||
@@ -87,7 +92,7 @@ func (a *AtomicBool) WaitWithContext(ctx context.Context, waitFor bool) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if v, ok := ReadChannelWithTimeout(a.waiter, timeOut); ok {
|
if v, ok := ReadChannelWithTimeout(waitchan, timeOut); ok {
|
||||||
if v == waitFor {
|
if v == waitFor {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user