Compare commits
122 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
b065fccf5c | ||
![]() |
489449c65d | ||
![]() |
7078a16983 | ||
![]() |
ba4b733a80 | ||
![]() |
d40b258a47 | ||
![]() |
ad5656a00a | ||
![]() |
ccfa6c4f99 | ||
![]() |
db5e615704 | ||
![]() |
b9c7e05031 | ||
![]() |
dd6cf60934 | ||
![]() |
f715cffbce | ||
![]() |
6d58535a91 | ||
![]() |
5c996e016a | ||
![]() |
a0122ba8e5 | ||
![]() |
883eff90e5 | ||
![]() |
91b9c416fb | ||
![]() |
8877d9e02a | ||
![]() |
763b161e26 | ||
![]() |
a26208f76e | ||
![]() |
9afe1aa679 | ||
![]() |
de3dc89691 | ||
![]() |
47f75d8247 | ||
![]() |
3ade5a2266 | ||
![]() |
e7e95ff498 | ||
![]() |
9048589a4d | ||
![]() |
06880e9f72 | ||
![]() |
4f7255c731 | ||
![]() |
0ec6d9a142 | ||
![]() |
75b0c72d72 | ||
![]() |
fc08e4f8c5 | ||
![]() |
70d3baf515 | ||
![]() |
9ab4817ec5 | ||
![]() |
3eeb9788ce | ||
![]() |
01573c9947 | ||
![]() |
67c14c72ff | ||
![]() |
7f080f238e | ||
![]() |
a6abd190f9 | ||
![]() |
61a612b594 | ||
![]() |
583a9d2358 | ||
![]() |
decda354c8 | ||
![]() |
3d4c6f692f | ||
![]() |
50cb269954 | ||
![]() |
ef6a02719b | ||
![]() |
72f4aa8132 | ||
![]() |
aa48a0c524 | ||
![]() |
b590bbd0fe | ||
![]() |
867867b5d6 | ||
![]() |
f0ba360bdc | ||
![]() |
a784d12ab4 | ||
![]() |
37aba94237 | ||
![]() |
fe65489de2 | ||
![]() |
2ce4c46c71 | ||
![]() |
a28a913a90 | ||
![]() |
50a75088ae | ||
![]() |
d72fab5c83 | ||
![]() |
87bea6ab2c | ||
![]() |
f913e480a2 | ||
![]() |
ed967899c4 | ||
![]() |
9823133648 | ||
![]() |
8716d301c6 | ||
![]() |
9377182985 | ||
![]() |
b343ad660a | ||
![]() |
aecf26a45c | ||
![]() |
7bffd9a638 | ||
![]() |
0644461bc7 | ||
![]() |
dacdd2a5db | ||
![]() |
efae915742 | ||
![]() |
2418793e3d | ||
![]() |
67c974caa2 | ||
![]() |
cadab4f094 | ||
![]() |
490774a7a3 | ||
![]() |
6a998e6eea | ||
![]() |
b62848491f | ||
![]() |
96e7c20cf0 | ||
![]() |
73c047e43f | ||
![]() |
85a82957ca | ||
![]() |
607a4887d0 | ||
![]() |
d82df9df79 | ||
![]() |
562242ca3f | ||
![]() |
bc3b2825a6 | ||
![]() |
03ffea28fe | ||
![]() |
c832144308 | ||
![]() |
a7c34b44d7 | ||
![]() |
70271a1b60 | ||
![]() |
56027b3c56 | ||
![]() |
1e70d9f893 | ||
![]() |
80edf5bfe5 | ||
![]() |
877ac12ec2 | ||
![]() |
e21d2e3b5d | ||
![]() |
f9776ebd7c | ||
![]() |
933ed5c972 | ||
![]() |
7442ad5d81 | ||
![]() |
ef23a486d3 | ||
![]() |
b50a0152e1 | ||
![]() |
0067fe79b2 | ||
![]() |
00b7f9e2ea | ||
![]() |
adf774f543 | ||
![]() |
1d9c4287fb | ||
![]() |
190668be5f | ||
![]() |
2a26b63c85 | ||
![]() |
f62a41fba7 | ||
![]() |
5b8b5563e9 | ||
![]() |
88b284f7de | ||
![]() |
6fd253d455 | ||
![]() |
e0ae331d17 | ||
![]() |
a3ab521064 | ||
![]() |
7ab75e421e | ||
![]() |
7749a036a0 | ||
![]() |
a3412f2da9 | ||
![]() |
8360f367bc | ||
![]() |
de0c368e4c | ||
![]() |
f58f61120a | ||
![]() |
a9b6ae14e7 | ||
![]() |
e934b0c6ca | ||
![]() |
9e16bd764d | ||
![]() |
4192dcc9fc | ||
![]() |
f54243a465 | ||
![]() |
5d0b0eacad | ||
![]() |
d1c788bb06 | ||
![]() |
a8b0821963 | ||
![]() |
924eed81d1 | ||
![]() |
3e730f5d26 |
29
algorithm.go
Normal file
29
algorithm.go
Normal file
@ -0,0 +1,29 @@
|
||||
package q5
|
||||
|
||||
import (
|
||||
"sort"
|
||||
)
|
||||
|
||||
type sortImpl[T any] struct {
|
||||
data []*T
|
||||
lessCb func(*T, *T) bool
|
||||
}
|
||||
|
||||
func (this *sortImpl[T]) Len() int {
|
||||
return len(this.data)
|
||||
}
|
||||
|
||||
func (this *sortImpl[T]) Swap(i int, j int) {
|
||||
this.data[i], this.data[j] = this.data[j], this.data[i]
|
||||
}
|
||||
|
||||
func (this *sortImpl[T]) Less(i int, j int) bool {
|
||||
return this.lessCb(this.data[i], this.data[j])
|
||||
}
|
||||
|
||||
func Sort[T any](data []*T, lessCb func(*T, *T) bool) {
|
||||
impl := new(sortImpl[T])
|
||||
impl.data = data
|
||||
impl.lessCb = lessCb
|
||||
sort.Sort(impl)
|
||||
}
|
228
convert.go
Normal file
228
convert.go
Normal file
@ -0,0 +1,228 @@
|
||||
package q5
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ToInt converts a value to an integer.
|
||||
func ToInt32[T string | int | int32 | int64 | float32 | float64](value T) int32 {
|
||||
return int32(ToInt64(value))
|
||||
}
|
||||
|
||||
// ToInt converts a value to an integer.
|
||||
func ToInt[T string | int32 | int64 | float32 | float64](value T) int {
|
||||
return int(ToInt64(value))
|
||||
}
|
||||
|
||||
// ToInt64 converts a value to an int64.
|
||||
func ToInt64[T string | int | int32 | int64 | float32 | float64](value T) int64 {
|
||||
var x interface{} = value
|
||||
switch i := x.(type) {
|
||||
case int:
|
||||
return int64(i)
|
||||
case int32:
|
||||
return int64(i)
|
||||
case int64:
|
||||
return i
|
||||
case float32:
|
||||
return int64(i)
|
||||
case float64:
|
||||
return int64(i)
|
||||
case string:
|
||||
intValue, err := strconv.ParseInt(i, 10, 64)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
return intValue
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func ToFloat32[T string | int | int32 | int64 | float32 | float64](value T) float32 {
|
||||
return float32(ToFloat64(value))
|
||||
}
|
||||
|
||||
// ToFloat converts a value to a float64.
|
||||
func ToFloat64[T string | int | int32 | int64 | float32 | float64](value T) float64 {
|
||||
var x interface{} = value
|
||||
switch i := x.(type) {
|
||||
case int:
|
||||
return float64(i)
|
||||
case int32:
|
||||
return float64(i)
|
||||
case int64:
|
||||
return float64(i)
|
||||
case float32:
|
||||
return float64(i)
|
||||
case float64:
|
||||
return i
|
||||
case string:
|
||||
f, _ := strconv.ParseFloat(strings.TrimSpace(i), 64)
|
||||
return f
|
||||
}
|
||||
return 0.0
|
||||
}
|
||||
|
||||
// ToString converts a value to a string.
|
||||
func ToString[T string | int | int32 | int64 | float32 | float64](value T) string {
|
||||
var x interface{} = value
|
||||
switch i := x.(type) {
|
||||
case int:
|
||||
return strconv.Itoa(i)
|
||||
case int32:
|
||||
return strconv.Itoa(int(i))
|
||||
case int64:
|
||||
return strconv.FormatInt(i, 10)
|
||||
case float32:
|
||||
return strconv.FormatFloat(float64(i), 'f', -1, 32)
|
||||
case float64:
|
||||
return strconv.FormatFloat(i, 'f', -1, 64)
|
||||
case string:
|
||||
return i
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func ToInt64Ex(x interface{}) (int64, error) {
|
||||
switch i := x.(type) {
|
||||
case int:
|
||||
return int64(i), nil
|
||||
case int32:
|
||||
return int64(i), nil
|
||||
case int64:
|
||||
return i, nil
|
||||
case float32:
|
||||
return int64(i), nil
|
||||
case float64:
|
||||
return int64(i), nil
|
||||
case string:
|
||||
intValue, err := strconv.ParseInt(i, 10, 64)
|
||||
if err != nil {
|
||||
return 0, nil
|
||||
}
|
||||
return intValue, nil
|
||||
}
|
||||
return 0, errors.New("ToInt64Ex error type")
|
||||
}
|
||||
|
||||
func SafeToInt64(x interface{}) int64 {
|
||||
val, _ := ToInt64Ex(x)
|
||||
return val
|
||||
}
|
||||
|
||||
func SafeToInt32(x interface{}) int32 {
|
||||
val, _ := ToInt64Ex(x)
|
||||
return int32(val)
|
||||
}
|
||||
|
||||
func ToFloat64Ex(x interface{}) (float64, error) {
|
||||
switch i := x.(type) {
|
||||
case int:
|
||||
return float64(i), nil
|
||||
case int32:
|
||||
return float64(i), nil
|
||||
case int64:
|
||||
return float64(i), nil
|
||||
case float32:
|
||||
return float64(i), nil
|
||||
case float64:
|
||||
return i, nil
|
||||
case string:
|
||||
f, _ := strconv.ParseFloat(strings.TrimSpace(i), 64)
|
||||
return f, nil
|
||||
}
|
||||
return 0, errors.New("ToFloat64Ex error type")
|
||||
}
|
||||
|
||||
func ToStringEx(x interface{}) (string, error) {
|
||||
switch i := x.(type) {
|
||||
case int:
|
||||
return strconv.Itoa(i), nil
|
||||
case int32:
|
||||
return strconv.Itoa(int(i)), nil
|
||||
case int64:
|
||||
return strconv.FormatInt(i, 10), nil
|
||||
case float32:
|
||||
return strconv.FormatFloat(float64(i), 'f', -1, 32), nil
|
||||
case float64:
|
||||
return strconv.FormatFloat(i, 'f', -1, 64), nil
|
||||
case string:
|
||||
return i, nil
|
||||
}
|
||||
return "", errors.New("ToStringEx error type")
|
||||
}
|
||||
|
||||
func SafeToString(x interface{}) string {
|
||||
val, _ := ToStringEx(x)
|
||||
return val
|
||||
}
|
||||
|
||||
func DuckToSimple[T string | int | int32 | int64 | float32 | float64](
|
||||
d interface{}, s *T) bool {
|
||||
var sx interface{} = s
|
||||
switch sv := sx.(type) {
|
||||
case *int:
|
||||
{
|
||||
if val, err := ToInt64Ex(d); err == nil {
|
||||
*sv = int(val)
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
case *int32:
|
||||
{
|
||||
if val, err := ToInt64Ex(d); err == nil {
|
||||
*sv = int32(val)
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
case *int64:
|
||||
{
|
||||
if val, err := ToInt64Ex(d); err == nil {
|
||||
*sv = val
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
case *float32:
|
||||
{
|
||||
if val, err := ToFloat64Ex(d); err == nil {
|
||||
*sv = float32(val)
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
case *float64:
|
||||
{
|
||||
if val, err := ToFloat64Ex(d); err == nil {
|
||||
*sv = val
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
case *string:
|
||||
{
|
||||
if val, err := ToStringEx(d); err == nil {
|
||||
*sv = val
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func ToBool[T int32 | int64 ](value T) bool {
|
||||
return value != 0
|
||||
}
|
||||
|
||||
func BoolToInt32(value bool) int32 {
|
||||
if value {
|
||||
return 1
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
}
|
63
functional.go
Normal file
63
functional.go
Normal file
@ -0,0 +1,63 @@
|
||||
package q5
|
||||
|
||||
func Map[T any](arr []T, cb func(T) T) []T {
|
||||
newList := []T{}
|
||||
for _, val := range arr {
|
||||
newList = append(newList, cb(val))
|
||||
}
|
||||
return newList
|
||||
}
|
||||
|
||||
func Reduce[T any](arr []T, cb func(T, T) T, initVal *T) T {
|
||||
var result T
|
||||
if initVal != nil {
|
||||
result = *initVal
|
||||
}
|
||||
if len(arr) > 0 {
|
||||
if initVal == nil {
|
||||
result = arr[0]
|
||||
for i := 1; i < len(arr); i++ {
|
||||
result = cb(result, arr[i])
|
||||
}
|
||||
} else {
|
||||
for i := 0; i < len(arr); i++ {
|
||||
result = cb(result, arr[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func Filter[T any](arr []T, cb func(T) bool) []T {
|
||||
newList := []T{}
|
||||
for _, val := range arr {
|
||||
if cb(val) {
|
||||
newList = append(newList, val)
|
||||
}
|
||||
}
|
||||
return newList
|
||||
}
|
||||
|
||||
func Max[T string | int | int32 | int64 | float32 | float64](a T, b T) T {
|
||||
if a < b {
|
||||
return b
|
||||
} else {
|
||||
return a
|
||||
}
|
||||
}
|
||||
|
||||
func Min[T string | int | int32 | int64 | float32 | float64](a T, b T) T {
|
||||
if a < b {
|
||||
return a
|
||||
} else {
|
||||
return b
|
||||
}
|
||||
}
|
||||
|
||||
func ToInterfaces[T any](values []T) []interface{} {
|
||||
result := []interface{}{}
|
||||
for _, val := range values {
|
||||
result = append(result, val)
|
||||
}
|
||||
return result
|
||||
}
|
10
go.mod
Normal file
10
go.mod
Normal file
@ -0,0 +1,10 @@
|
||||
module q5
|
||||
|
||||
go 1.20
|
||||
|
||||
require (
|
||||
github.com/garyburd/redigo v1.6.2
|
||||
github.com/go-sql-driver/mysql v1.5.0
|
||||
github.com/gomodule/redigo v1.8.3
|
||||
golang.org/x/crypto v0.13.0 // indirect
|
||||
)
|
18
go.sum
Normal file
18
go.sum
Normal file
@ -0,0 +1,18 @@
|
||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/garyburd/redigo v1.6.2 h1:yE/pwKCrbLpLpQICzYTeZ7JsTA/C53wFTJHaEtRqniM=
|
||||
github.com/garyburd/redigo v1.6.2/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY=
|
||||
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
|
||||
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
github.com/gomodule/redigo v1.8.3 h1:HR0kYDX2RJZvAup8CsiJwxB4dTCSC0AaUq6S4SiLwUc=
|
||||
github.com/gomodule/redigo v1.8.3/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck=
|
||||
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
120
httpcli.go
Normal file
120
httpcli.go
Normal file
@ -0,0 +1,120 @@
|
||||
package q5
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
net_url "net/url"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
HTTP_OPT_ADD_HEADER = iota
|
||||
HTTP_OPT_SET_PROXY = iota
|
||||
)
|
||||
|
||||
const (
|
||||
HTTP_HEADER_JSON = "application/json"
|
||||
)
|
||||
|
||||
func internalSetOpt(client *http.Client, request *http.Request, opt int32,
|
||||
key string, val string) {
|
||||
switch opt {
|
||||
case HTTP_OPT_ADD_HEADER:
|
||||
request.Header.Add(key, val)
|
||||
default:
|
||||
panic("error http opt")
|
||||
}
|
||||
}
|
||||
|
||||
func HttpGet(url string, params map[string]string) (string, error) {
|
||||
return HttpGetEx(url, params, nil)
|
||||
}
|
||||
|
||||
func HttpGetEx(url string, params map[string]string,
|
||||
initFunc func(setOpt func(int32, string, string))) (string, error) {
|
||||
if !StrContains(url, "?") {
|
||||
url = url + "?"
|
||||
}
|
||||
{
|
||||
u := net_url.Values{}
|
||||
for key, val := range params {
|
||||
u.Set(key, val)
|
||||
}
|
||||
url = url + u.Encode()
|
||||
}
|
||||
client := &http.Client{}
|
||||
request, err := http.NewRequest("GET", url, nil)
|
||||
if err != nil {
|
||||
panic("http.NewRequest error")
|
||||
}
|
||||
if initFunc != nil {
|
||||
initFunc(func(opt int32, key string, val string) {
|
||||
internalSetOpt(client, request, opt, key, val)
|
||||
})
|
||||
}
|
||||
if resp, err := client.Do(request); err == nil {
|
||||
if resp.StatusCode != 200 {
|
||||
return "", errors.New("HttpGet error Status:" + resp.Status)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
if bytes, err := ioutil.ReadAll(resp.Body); err == nil {
|
||||
return string(bytes), nil
|
||||
} else {
|
||||
return "", err
|
||||
}
|
||||
} else {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
func HttpGetEx2(url string, params map[string]string) (*http.Response, string, error) {
|
||||
if !StrContains(url, "?") {
|
||||
url = url + "?"
|
||||
}
|
||||
{
|
||||
u := net_url.Values{}
|
||||
for key, val := range params {
|
||||
u.Set(key, val)
|
||||
}
|
||||
url = url + u.Encode()
|
||||
}
|
||||
client := &http.Client{}
|
||||
request, err := http.NewRequest("GET", url, nil)
|
||||
if err != nil {
|
||||
panic("http.NewRequest error")
|
||||
}
|
||||
if resp, err := client.Do(request); err == nil {
|
||||
defer resp.Body.Close()
|
||||
if bytes, err := ioutil.ReadAll(resp.Body); err == nil {
|
||||
return resp, string(bytes), nil
|
||||
} else {
|
||||
return resp, "", err
|
||||
}
|
||||
} else {
|
||||
return nil, "", err
|
||||
}
|
||||
}
|
||||
|
||||
func HttpPost(url string, params map[string]string, contentType string, body string) (string, error) {
|
||||
if !StrContains(url, "?") {
|
||||
url = url + "?"
|
||||
}
|
||||
{
|
||||
u := net_url.Values{}
|
||||
for key, val := range params {
|
||||
u.Set(key, val)
|
||||
}
|
||||
url = url + u.Encode()
|
||||
}
|
||||
resp, err := http.Post(url, contentType, strings.NewReader(body))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
if bytes, err := ioutil.ReadAll(resp.Body); err == nil {
|
||||
return string(bytes), nil
|
||||
} else {
|
||||
return "", err
|
||||
}
|
||||
}
|
137
listhead.go
Normal file
137
listhead.go
Normal file
@ -0,0 +1,137 @@
|
||||
package q5
|
||||
|
||||
type ListHead_Foreach_Func func(interface{}) bool
|
||||
|
||||
type ListHead struct {
|
||||
next *ListHead
|
||||
prev *ListHead
|
||||
data interface{}
|
||||
}
|
||||
|
||||
func (this *ListHead) Init(data interface{}) {
|
||||
this.next = this
|
||||
this.prev = this
|
||||
this.data = data
|
||||
}
|
||||
|
||||
func (this *ListHead) GetData() interface{} {
|
||||
return this.data
|
||||
}
|
||||
|
||||
func (this *ListHead) Del() {
|
||||
this.next.prev = this.prev
|
||||
this.prev.next = this.next
|
||||
}
|
||||
|
||||
func (this *ListHead) AddTail(pnew *ListHead) {
|
||||
prev := this.prev
|
||||
next := this
|
||||
|
||||
next.prev = pnew
|
||||
pnew.next = next
|
||||
pnew.prev = prev
|
||||
prev.next = pnew
|
||||
}
|
||||
|
||||
func (this *ListHead) AddHead(pnew *ListHead) {
|
||||
prev := this
|
||||
next := this.prev
|
||||
|
||||
next.prev = pnew
|
||||
pnew.next = next
|
||||
pnew.prev = prev
|
||||
prev.next = pnew
|
||||
}
|
||||
|
||||
func (this *ListHead) FirstEntry() interface{} {
|
||||
if !this.next.isCursor() {
|
||||
return this.next.data
|
||||
}
|
||||
for pos := this.next; pos != this; pos = pos.next {
|
||||
if !pos.isCursor() {
|
||||
return pos.data
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (this *ListHead) Replace(pnew *ListHead) {
|
||||
pnew.next = this.next
|
||||
pnew.next.prev = pnew
|
||||
pnew.prev = this.prev
|
||||
pnew.prev.next = pnew
|
||||
}
|
||||
|
||||
func (this *ListHead) ReplaceInit(pnew *ListHead) {
|
||||
this.Replace(pnew)
|
||||
this.next = this
|
||||
this.prev = this
|
||||
}
|
||||
|
||||
func (this *ListHead) Empty() bool {
|
||||
if this.next == this {
|
||||
return true
|
||||
}
|
||||
if !this.next.isCursor() {
|
||||
return false
|
||||
}
|
||||
for pos := this.next; pos != this; pos = pos.next {
|
||||
if !pos.isCursor() {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (this *ListHead) DelInit() {
|
||||
this.Del()
|
||||
this.next = this
|
||||
this.prev = this
|
||||
}
|
||||
|
||||
func (this *ListHead) Size() int32 {
|
||||
num := int32(0)
|
||||
this.ForEach(
|
||||
func(data interface{}) bool {
|
||||
num++
|
||||
return true
|
||||
})
|
||||
return num
|
||||
}
|
||||
|
||||
func (this *ListHead) isCursor() bool {
|
||||
return this.data == this
|
||||
}
|
||||
|
||||
func (this *ListHead) IsFirst(entry* ListHead) bool {
|
||||
return this.next == entry
|
||||
}
|
||||
|
||||
func (this *ListHead) ForEach(cb ListHead_Foreach_Func) {
|
||||
for pos := this.next; pos != this; pos = pos.next {
|
||||
if !cb(pos.data) {
|
||||
break
|
||||
}
|
||||
}
|
||||
/*
|
||||
cursor := ListHead{}
|
||||
cursor.data = &cursor
|
||||
this.AddHead(&cursor)
|
||||
defer cursor.Del()
|
||||
for cursor.next != this {
|
||||
oldN := cursor.next
|
||||
if !cursor.next.isCursor() && !cb(cursor.next.data) {
|
||||
break
|
||||
}
|
||||
if cursor.next == oldN {
|
||||
oldN.Del()
|
||||
cursor.AddTail(oldN)
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
func NewListHead() *ListHead {
|
||||
l := new(ListHead)
|
||||
l.Init(nil)
|
||||
return l
|
||||
}
|
77
mysql.go
Normal file
77
mysql.go
Normal file
@ -0,0 +1,77 @@
|
||||
package q5
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
)
|
||||
|
||||
type Mysql struct {
|
||||
host string
|
||||
port int32
|
||||
user string
|
||||
passwd string
|
||||
database string
|
||||
db *sql.DB
|
||||
maxOpenConns int32
|
||||
maxIdleConns int32
|
||||
}
|
||||
|
||||
func (this *Mysql) init(host string, port int32, user string, passwd string, database string,
|
||||
maxOpenConns int32, maxIdleConns int32) {
|
||||
this.host = host
|
||||
this.port = port
|
||||
this.user = user
|
||||
this.passwd = passwd
|
||||
this.database = database
|
||||
this.maxOpenConns = maxOpenConns
|
||||
this.maxIdleConns = maxIdleConns
|
||||
}
|
||||
|
||||
func (this *Mysql) Open() error {
|
||||
connStr := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8",
|
||||
this.user,
|
||||
this.passwd,
|
||||
this.host,
|
||||
this.port,
|
||||
this.database)
|
||||
db, err := sql.Open("mysql", connStr)
|
||||
this.db = db
|
||||
if err == nil {
|
||||
this.db.SetMaxOpenConns(int(this.maxOpenConns))
|
||||
this.db.SetMaxIdleConns(int(this.maxIdleConns))
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (this *Mysql) Close() {
|
||||
if this.db != nil {
|
||||
this.db.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func (this *Mysql) Ping() error {
|
||||
return this.db.Ping()
|
||||
}
|
||||
|
||||
func (this *Mysql) Query(query string, args ...interface{}) (*sql.Rows, error) {
|
||||
rows, err := this.db.Query(query, args...)
|
||||
return rows, err
|
||||
}
|
||||
|
||||
/*
|
||||
func (this *Mysql) QueryRow(query string, args ...interface{}) *sql.Row {
|
||||
return this.db.QueryRow(query, args...)
|
||||
}
|
||||
*/
|
||||
|
||||
func (this *Mysql) Exec(query string, args ...interface{}) (sql.Result, error) {
|
||||
result, err := this.db.Exec(query, args...)
|
||||
return result, err
|
||||
}
|
||||
|
||||
func NewMysql(host string, port int32, user string, passwd string, database string, maxOpenConns int32, maxIdleConns int32) *Mysql {
|
||||
conn := new(Mysql)
|
||||
conn.init(host, port, user, passwd, database, maxOpenConns, maxIdleConns)
|
||||
return conn
|
||||
}
|
20
password.go
Normal file
20
password.go
Normal file
@ -0,0 +1,20 @@
|
||||
package q5
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
|
||||
// HashPassword returns the bcrypt hash of the password
|
||||
func HashPassword(password string) (string, error) {
|
||||
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to hash password: %w", err)
|
||||
}
|
||||
return string(hashedPassword), nil
|
||||
}
|
||||
|
||||
// CheckPassword checks if the provided password is correct or not
|
||||
func CheckPassword(password string, hashedPassword string) error {
|
||||
return bcrypt.CompareHashAndPassword([]byte(hashedPassword), []byte(password))
|
||||
}
|
41
queue.go
Normal file
41
queue.go
Normal file
@ -0,0 +1,41 @@
|
||||
package q5
|
||||
|
||||
import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
type Queue struct {
|
||||
msgMutex sync.Mutex
|
||||
msgList ListHead
|
||||
WorkList ListHead
|
||||
}
|
||||
|
||||
func (this *Queue) Init() {
|
||||
this.msgList.Init(nil)
|
||||
this.WorkList.Init(nil)
|
||||
}
|
||||
|
||||
func (this *Queue) Push(node *ListHead) {
|
||||
this.msgMutex.Lock()
|
||||
defer this.msgMutex.Unlock()
|
||||
this.msgList.AddTail(node)
|
||||
}
|
||||
|
||||
func (this *Queue) Fetch() {
|
||||
if this.WorkList.Empty() {
|
||||
this.msgMutex.Lock()
|
||||
defer this.msgMutex.Unlock()
|
||||
if !this.msgList.Empty() {
|
||||
this.msgList.ReplaceInit(&this.WorkList)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (this *Queue) IsEmpty() bool {
|
||||
if !this.WorkList.Empty() {
|
||||
return false
|
||||
}
|
||||
this.msgMutex.Lock()
|
||||
defer this.msgMutex.Unlock()
|
||||
return this.msgList.Empty()
|
||||
}
|
21
random.go
Normal file
21
random.go
Normal file
@ -0,0 +1,21 @@
|
||||
package q5
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// RandomString generates a random string of length n
|
||||
const alphabet = "abcdefghijklmnopqrstuvwxyz"
|
||||
|
||||
func RandomString(n int) string {
|
||||
var sb strings.Builder
|
||||
k := len(alphabet)
|
||||
|
||||
for i := 0; i < n; i++ {
|
||||
c := alphabet[rand.Intn(k)]
|
||||
sb.WriteByte(c)
|
||||
}
|
||||
|
||||
return sb.String()
|
||||
}
|
24
redis.go
Normal file
24
redis.go
Normal file
@ -0,0 +1,24 @@
|
||||
package q5
|
||||
|
||||
import (
|
||||
"github.com/gomodule/redigo/redis"
|
||||
)
|
||||
|
||||
type Redis struct {
|
||||
host string
|
||||
port int32
|
||||
passwd string
|
||||
conn *redis.Conn
|
||||
}
|
||||
|
||||
func (this *Redis) Init(host string, port int32, passwd string) {
|
||||
this.host = host
|
||||
this.port = port
|
||||
this.passwd = passwd
|
||||
}
|
||||
|
||||
func (this *Redis) Open() {
|
||||
}
|
||||
|
||||
func (this *Redis) Close() {
|
||||
}
|
200
reflect.go
Normal file
200
reflect.go
Normal file
@ -0,0 +1,200 @@
|
||||
package q5
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
)
|
||||
|
||||
func IsSimpleReflectKind(kind reflect.Kind) bool {
|
||||
switch kind {
|
||||
case reflect.Bool,
|
||||
reflect.Int,
|
||||
reflect.Int8,
|
||||
reflect.Int16,
|
||||
reflect.Int32,
|
||||
reflect.Int64,
|
||||
reflect.Uint,
|
||||
reflect.Uint8,
|
||||
reflect.Uint16,
|
||||
reflect.Uint32,
|
||||
reflect.Uint64,
|
||||
reflect.Float32,
|
||||
reflect.Float64,
|
||||
reflect.String:
|
||||
{
|
||||
return true
|
||||
}
|
||||
default:
|
||||
{
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func StrToSimpleReflectValue(val string, kind reflect.Kind) *reflect.Value {
|
||||
switch kind {
|
||||
case reflect.Bool:
|
||||
{
|
||||
v := reflect.ValueOf(val == "1" || val == "true")
|
||||
return &v
|
||||
}
|
||||
case reflect.Int:
|
||||
{
|
||||
v := reflect.ValueOf(int(ToInt64(val)))
|
||||
return &v
|
||||
}
|
||||
case reflect.Int8:
|
||||
{
|
||||
v := reflect.ValueOf(int8(ToInt64(val)))
|
||||
return &v
|
||||
}
|
||||
case reflect.Int16:
|
||||
{
|
||||
v := reflect.ValueOf(int16(ToInt64(val)))
|
||||
return &v
|
||||
}
|
||||
case reflect.Int32:
|
||||
{
|
||||
v := reflect.ValueOf(int32(ToInt64(val)))
|
||||
return &v
|
||||
}
|
||||
case reflect.Int64:
|
||||
{
|
||||
v := reflect.ValueOf(ToInt64(val))
|
||||
return &v
|
||||
}
|
||||
case reflect.Uint:
|
||||
{
|
||||
v := reflect.ValueOf(uint(ToInt64(val)))
|
||||
return &v
|
||||
}
|
||||
case reflect.Uint8:
|
||||
{
|
||||
v := reflect.ValueOf(uint8(ToInt64(val)))
|
||||
return &v
|
||||
}
|
||||
case reflect.Uint16:
|
||||
{
|
||||
v := reflect.ValueOf(uint16(ToInt64(val)))
|
||||
return &v
|
||||
}
|
||||
case reflect.Uint32:
|
||||
{
|
||||
v := reflect.ValueOf(uint32(ToInt64(val)))
|
||||
return &v
|
||||
}
|
||||
case reflect.Uint64:
|
||||
{
|
||||
v := reflect.ValueOf(uint64(ToInt64(val)))
|
||||
return &v
|
||||
}
|
||||
case reflect.Float32,
|
||||
reflect.Float64:
|
||||
{
|
||||
v := reflect.ValueOf(ToFloat64(val))
|
||||
return &v
|
||||
}
|
||||
case reflect.String:
|
||||
{
|
||||
v := reflect.ValueOf(val)
|
||||
return &v
|
||||
}
|
||||
default:
|
||||
{
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func StrToSimplePtrReflectValue(val string, kind reflect.Kind) *reflect.Value {
|
||||
result := reflect.Value{}
|
||||
switch kind {
|
||||
case reflect.Bool:
|
||||
{
|
||||
v := val == "1" || val == "true"
|
||||
result = reflect.ValueOf(&v)
|
||||
return &result
|
||||
}
|
||||
case reflect.Int:
|
||||
{
|
||||
v := int(ToInt64(val))
|
||||
result = reflect.ValueOf(&v)
|
||||
return &result
|
||||
}
|
||||
case reflect.Int8:
|
||||
{
|
||||
v := int8(ToInt64(val))
|
||||
result = reflect.ValueOf(&v)
|
||||
return &result
|
||||
}
|
||||
case reflect.Int16:
|
||||
{
|
||||
v := int16(ToInt64(val))
|
||||
result = reflect.ValueOf(&v)
|
||||
return &result
|
||||
}
|
||||
case reflect.Int32:
|
||||
{
|
||||
v := int32(ToInt64(val))
|
||||
result = reflect.ValueOf(&v)
|
||||
return &result
|
||||
}
|
||||
case reflect.Int64:
|
||||
{
|
||||
v := ToInt64(val)
|
||||
result = reflect.ValueOf(&v)
|
||||
return &result
|
||||
}
|
||||
case reflect.Uint:
|
||||
{
|
||||
v := uint(ToInt64(val))
|
||||
result = reflect.ValueOf(&v)
|
||||
return &result
|
||||
}
|
||||
case reflect.Uint8:
|
||||
{
|
||||
v := uint8(ToInt64(val))
|
||||
result = reflect.ValueOf(&v)
|
||||
return &result
|
||||
}
|
||||
case reflect.Uint16:
|
||||
{
|
||||
v := uint16(ToInt64(val))
|
||||
result = reflect.ValueOf(&v)
|
||||
return &result
|
||||
}
|
||||
case reflect.Uint32:
|
||||
{
|
||||
v := uint32(ToInt64(val))
|
||||
result = reflect.ValueOf(&v)
|
||||
return &result
|
||||
}
|
||||
case reflect.Uint64:
|
||||
{
|
||||
v := uint64(ToInt64(val))
|
||||
result = reflect.ValueOf(&v)
|
||||
return &result
|
||||
}
|
||||
case reflect.Float32:
|
||||
{
|
||||
v := float32(ToFloat64(val))
|
||||
result = reflect.ValueOf(&v)
|
||||
return &result
|
||||
}
|
||||
case reflect.Float64:
|
||||
{
|
||||
v := float64(ToFloat64(val))
|
||||
result = reflect.ValueOf(&v)
|
||||
return &result
|
||||
}
|
||||
case reflect.String:
|
||||
{
|
||||
v := val
|
||||
result = reflect.ValueOf(&v)
|
||||
return &result
|
||||
}
|
||||
default:
|
||||
{
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
142
strutils.go
142
strutils.go
@ -1,6 +1,144 @@
|
||||
package q5
|
||||
|
||||
func Test()(a string) {
|
||||
return "testa"
|
||||
import (
|
||||
"crypto/md5"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"hash/crc32"
|
||||
"io"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
JSON_NONE = 0
|
||||
JSON_ARRAY = iota
|
||||
JSON_OBJECT = iota
|
||||
)
|
||||
|
||||
func Md5Str(data string) string {
|
||||
h := md5.New()
|
||||
h.Write([]byte(data))
|
||||
return hex.EncodeToString(h.Sum(nil))
|
||||
}
|
||||
|
||||
func Base64Encode(data string) string {
|
||||
strbytes := []byte(data)
|
||||
encoded := base64.StdEncoding.EncodeToString(strbytes)
|
||||
return encoded
|
||||
}
|
||||
|
||||
func Base64Decode(data string) (string, error) {
|
||||
decoded, err := base64.StdEncoding.DecodeString(data)
|
||||
return string(decoded), err
|
||||
}
|
||||
|
||||
func Crc32(data string) uint32 {
|
||||
ieee := crc32.NewIEEE()
|
||||
io.WriteString(ieee, data)
|
||||
|
||||
code := ieee.Sum32()
|
||||
return code
|
||||
}
|
||||
|
||||
func JsonStrType(data string) int32 {
|
||||
arrayIdx := strings.IndexByte(data, '[')
|
||||
objectIdx := strings.IndexByte(data, '{')
|
||||
if arrayIdx < 0 && objectIdx < 0 {
|
||||
return JSON_NONE
|
||||
} else {
|
||||
if arrayIdx < 0 {
|
||||
return JSON_OBJECT
|
||||
}
|
||||
if objectIdx < 0 {
|
||||
return JSON_ARRAY
|
||||
}
|
||||
if arrayIdx < objectIdx {
|
||||
return JSON_ARRAY
|
||||
} else {
|
||||
return JSON_OBJECT
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func EncodeJson(p interface{}) string {
|
||||
if jsonBytes, err := json.Marshal(p); err == nil {
|
||||
return string(jsonBytes)
|
||||
} else {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
func DecodeJson(data string, p interface{}) error {
|
||||
err := json.Unmarshal([]byte(data), &p)
|
||||
return err
|
||||
}
|
||||
|
||||
func StrSplit(s string, sep string) []string {
|
||||
return strings.Split(s, sep)
|
||||
}
|
||||
|
||||
func StrContains(s string, substr string) bool {
|
||||
return strings.Contains(s, substr)
|
||||
}
|
||||
|
||||
func ConvertUpperCamelCase(name string) string {
|
||||
newName := ""
|
||||
preIs_ := false
|
||||
for i := 0; i < len(name); i++ {
|
||||
if i == 0 {
|
||||
newName += strings.ToUpper(name[i : i+1])
|
||||
preIs_ = name[i] == '_'
|
||||
} else {
|
||||
if preIs_ {
|
||||
if name[i] != '_' {
|
||||
newName += strings.ToUpper(name[i : i+1])
|
||||
}
|
||||
} else {
|
||||
if name[i] != '_' {
|
||||
newName += name[i : i+1]
|
||||
}
|
||||
}
|
||||
preIs_ = name[i] == '_'
|
||||
}
|
||||
}
|
||||
return newName
|
||||
}
|
||||
|
||||
func NewEmptyStrPtr() *string {
|
||||
tmpStr := ""
|
||||
return &tmpStr
|
||||
}
|
||||
|
||||
func IsPureNumber(str string) bool {
|
||||
for i := 0; i < len(str); i++ {
|
||||
if !(str[i] >= '0' && str[i] <= '9') {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func GenFieldKvEmptyAsNull(key string, val string) []string {
|
||||
if val == "" {
|
||||
return []string{"!" + key, "NULL"}
|
||||
} else {
|
||||
return []string{key, val}
|
||||
}
|
||||
}
|
||||
|
||||
func IsWeb3ZeroAddress(address string) bool {
|
||||
return address == "0x0000000000000000000000000000000000000000"
|
||||
}
|
||||
|
||||
func BigIntStrCmp(a string, b string) int {
|
||||
if len(a) == len(b) {
|
||||
return strings.Compare(a, b)
|
||||
} else {
|
||||
if len(a) < len(b) {
|
||||
return -1
|
||||
} else {
|
||||
return 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
88
sync.go
Normal file
88
sync.go
Normal file
@ -0,0 +1,88 @@
|
||||
package q5
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
type ConcurrentMap[T1 string | int | int32 | int64, T2 any] struct {
|
||||
kvHash sync.Map
|
||||
}
|
||||
|
||||
func (this *ConcurrentMap[T1, T2]) CompareAndDelete(key T1, old *T2) bool {
|
||||
return this.kvHash.CompareAndDelete(key, old)
|
||||
}
|
||||
|
||||
func (this *ConcurrentMap[T1, T2]) CompareAndSwap(key T1, old T2, new T2) bool {
|
||||
return this.kvHash.CompareAndSwap(key, old, new)
|
||||
}
|
||||
|
||||
func (this *ConcurrentMap[T1, T2]) Delete(key T1) {
|
||||
this.kvHash.Delete(key)
|
||||
}
|
||||
|
||||
func (this *ConcurrentMap[T1, T2]) Load(key T1) (*T2, bool) {
|
||||
value, ok := this.kvHash.Load(key)
|
||||
if ok {
|
||||
tmpValue := value.(T2)
|
||||
return &tmpValue, ok
|
||||
} else {
|
||||
return nil, ok
|
||||
}
|
||||
}
|
||||
|
||||
func (this *ConcurrentMap[T1, T2]) LoadAndDelete(key T1) (*T2, bool) {
|
||||
value, loaded := this.kvHash.LoadAndDelete(key)
|
||||
if loaded {
|
||||
tmpValue := value.(T2)
|
||||
return &tmpValue, loaded
|
||||
} else {
|
||||
return nil, loaded
|
||||
}
|
||||
}
|
||||
|
||||
func (this *ConcurrentMap[T1, T2]) LoadOrStore(key T1, value T2) (*T2, bool) {
|
||||
actual, loaded := this.kvHash.LoadOrStore(key, value)
|
||||
if loaded {
|
||||
tmpActual := actual.(T2)
|
||||
return &tmpActual, loaded
|
||||
} else {
|
||||
return nil, loaded
|
||||
}
|
||||
}
|
||||
|
||||
func (this *ConcurrentMap[T1, T2]) Range(f func(key T1, value T2) bool) {
|
||||
this.kvHash.Range(func (key, value interface{}) bool {
|
||||
return f(key.(T1), value.(T2))
|
||||
})
|
||||
}
|
||||
|
||||
func (this *ConcurrentMap[T1, T2]) GetSize() int {
|
||||
var size int
|
||||
this.kvHash.Range(func (key, value interface{}) bool {
|
||||
size += 1
|
||||
return true
|
||||
})
|
||||
return size
|
||||
}
|
||||
|
||||
func (this *ConcurrentMap[T1, T2]) Store(key T1, value T2) {
|
||||
this.kvHash.Store(key, value)
|
||||
}
|
||||
|
||||
func (this *ConcurrentMap[T1, T2]) Swap(key T1, value T2) (*T2, bool) {
|
||||
previous, loaded := this.kvHash.Swap(key, value)
|
||||
if loaded {
|
||||
tmpPrevious := previous.(T2)
|
||||
return &tmpPrevious, loaded
|
||||
} else {
|
||||
return nil, loaded
|
||||
}
|
||||
}
|
||||
|
||||
func AtomicStoreInt64WhenGreater(srcVal *int64, trgVal *int64) {
|
||||
tmpVal := atomic.LoadInt64(srcVal)
|
||||
if tmpVal > *trgVal {
|
||||
atomic.StoreInt64(trgVal, tmpVal)
|
||||
}
|
||||
}
|
381
sysutils.go
Normal file
381
sysutils.go
Normal file
@ -0,0 +1,381 @@
|
||||
package q5
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"hash/crc32"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
func GetDaySeconds(seconds int64, timeZone int64) int64 {
|
||||
return ((seconds+timeZone*3600)/3600/24)*3600*24 - 3600*timeZone
|
||||
}
|
||||
|
||||
func GetYesterDaySeconds(seconds int64, timeZone int64) int64 {
|
||||
return ((seconds+timeZone*3600)/3600/24)*3600*24 - 3600*timeZone
|
||||
}
|
||||
|
||||
func GetTickCount() int64 {
|
||||
return time.Now().UnixNano() / 1e6
|
||||
}
|
||||
|
||||
func MkUInt16(b1 byte, b2 byte) uint16 {
|
||||
return uint16(b1) + (uint16(b2) << 8)
|
||||
}
|
||||
|
||||
func MkUInt32(b1 byte, b2 byte, b3 byte, b4 byte) uint32 {
|
||||
return uint32(b1) +
|
||||
(uint32(b2) << 8) +
|
||||
(uint32(b3) << 16) +
|
||||
(uint32(b4) << 24)
|
||||
}
|
||||
|
||||
func MkInt64(lo32 int32, hi32 int32) int64 {
|
||||
return int64(lo32) + (int64(hi32) << 32)
|
||||
}
|
||||
|
||||
func Request(r *http.Request, name string) string {
|
||||
if r.Form == nil {
|
||||
r.ParseForm()
|
||||
}
|
||||
if vs, ok := r.Form[name]; ok {
|
||||
if len(vs) > 0 {
|
||||
return vs[0]
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func Response(w *http.ResponseWriter, data string) {
|
||||
(*w).Write([]byte(data))
|
||||
}
|
||||
|
||||
func ResponseOk(w *http.ResponseWriter) {
|
||||
(*w).Write([]byte(`{"errcode":0, "errmsg":""}`))
|
||||
}
|
||||
|
||||
func ResponseErr(w *http.ResponseWriter, errCode int32, errMsg string) {
|
||||
rspObj := map[string]interface{}{}
|
||||
rspObj["errcode"] = errCode
|
||||
rspObj["errmsg"] = errMsg
|
||||
jsonObj, _ := json.Marshal(rspObj)
|
||||
Response(w, string(jsonObj))
|
||||
}
|
||||
|
||||
func ResponseInt32Ok(w *http.ResponseWriter, key string, val int32) {
|
||||
(*w).Write([]byte(fmt.Sprintf(`{"errcode":0, "errmsg":"", "%s":%d}`, key, val)))
|
||||
}
|
||||
|
||||
func GetPostBody(r *http.Request) string {
|
||||
body, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return string(body)
|
||||
}
|
||||
|
||||
func GetRequestRemoteAddr(r *http.Request) string {
|
||||
remoteAddr := r.RemoteAddr
|
||||
if ip := r.Header.Get("X-Real-Ip"); ip != "" {
|
||||
remoteAddr = ip
|
||||
} else if ip = r.Header.Get("X-Forwarded-For"); ip != "" {
|
||||
remoteAddr = ip
|
||||
} else {
|
||||
remoteAddr, _, _ = net.SplitHostPort(remoteAddr)
|
||||
}
|
||||
|
||||
if remoteAddr == "::1" {
|
||||
remoteAddr = "127.0.0.1"
|
||||
}
|
||||
|
||||
return remoteAddr
|
||||
}
|
||||
|
||||
func ForceCreateDir(dir string) bool {
|
||||
os.MkdirAll(dir, os.ModePerm)
|
||||
return true
|
||||
}
|
||||
|
||||
func IsNumberType(v interface{}) bool {
|
||||
switch reflect.TypeOf(v).Kind() {
|
||||
case
|
||||
reflect.Int,
|
||||
reflect.Int8,
|
||||
reflect.Int16,
|
||||
reflect.Int32,
|
||||
reflect.Int64,
|
||||
reflect.Uint8,
|
||||
reflect.Uint16,
|
||||
reflect.Uint32,
|
||||
reflect.Uint64,
|
||||
reflect.Float32,
|
||||
reflect.Float64:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func FormatUnixDateTime(sec int64, loc *time.Location) string {
|
||||
strTime := time.Unix(sec, 0).In(loc).Format("2006-01-02 15:04:05")
|
||||
return strTime
|
||||
}
|
||||
|
||||
func FormatUnixDate(sec int64, loc *time.Location) string {
|
||||
strTime := time.Unix(sec, 0).In(loc).Format("2006-01-02")
|
||||
return strTime
|
||||
}
|
||||
|
||||
func FormatUnixDateEx(sec int64, loc *time.Location) string {
|
||||
strTime := time.Unix(sec, 0).In(loc).Format("20060102")
|
||||
return strTime
|
||||
}
|
||||
|
||||
func HasBitFlag(val int64, bitNum int32) bool {
|
||||
if bitNum < 0 || bitNum > 63 {
|
||||
return false
|
||||
}
|
||||
mask := int64(1) << bitNum
|
||||
return (val & mask) != 0
|
||||
}
|
||||
|
||||
func SetBitFlag(val *int64, bitNum int32) {
|
||||
if bitNum < 0 || bitNum > 63 {
|
||||
return
|
||||
}
|
||||
*val |= int64(1) << bitNum
|
||||
}
|
||||
|
||||
func UnSetBitFlag(val *int64, bitNum int32) {
|
||||
if bitNum < 0 || bitNum > 63 {
|
||||
return
|
||||
}
|
||||
*val &= ^(int64(1) << bitNum)
|
||||
}
|
||||
|
||||
func GetLocalIP() string {
|
||||
conn, err := net.Dial("udp", "8.8.8.8:80")
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
defer conn.Close()
|
||||
localAddr := conn.LocalAddr().(*net.UDPAddr)
|
||||
return localAddr.IP.String()
|
||||
|
||||
//interfaces, err := net.Interfaces()
|
||||
//if err != nil {
|
||||
// panic(err)
|
||||
//}
|
||||
//ipList := []string{}
|
||||
//for _, iface := range interfaces {
|
||||
// if iface.Flags&net.FlagUp == 0 || iface.Flags&net.FlagLoopback != 0 {
|
||||
// continue
|
||||
// }
|
||||
// addrs, err := iface.Addrs()
|
||||
// if err != nil {
|
||||
// panic(err)
|
||||
// }
|
||||
// for _, addr := range addrs {
|
||||
// ipnet, ok := addr.(*net.IPNet)
|
||||
// if !ok || ipnet.IP.IsLoopback() {
|
||||
// continue
|
||||
// }
|
||||
// if ipnet.IP.To4() != nil {
|
||||
// ipList = append(ipList, ipnet.IP.String())
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
//if len(ipList) != 1 {
|
||||
// panic("GetLocalIP error")
|
||||
//} else {
|
||||
// return ipList[0]
|
||||
//}
|
||||
}
|
||||
|
||||
func NewSlice[T any](s *[]T, len int32, cap int32) {
|
||||
*s = make([]T, len, cap)
|
||||
}
|
||||
|
||||
func NewSliceElement[T any](s *[]T) *T {
|
||||
v := new(T)
|
||||
*s = append(*s, *v)
|
||||
return &(*s)[len(*s)-1]
|
||||
}
|
||||
|
||||
func AppendSlice[T any](s *[]T, val T) {
|
||||
*s = append(*s, val)
|
||||
}
|
||||
|
||||
func GetTypeName(v interface{}) string {
|
||||
return reflect.TypeOf(v).String()
|
||||
}
|
||||
|
||||
func PrintCallStack() {
|
||||
// 获取当前函数的调用者信息
|
||||
pc, file, line, ok := runtime.Caller(1)
|
||||
if !ok {
|
||||
fmt.Println("runtime.Caller error")
|
||||
return
|
||||
}
|
||||
|
||||
funcName := runtime.FuncForPC(pc).Name()
|
||||
fmt.Printf("Function: %s\nFile: %s\nLine: %d\n", funcName, file, line)
|
||||
|
||||
// 使用Stack打印完整的调用栈信息,可以用于debug
|
||||
buf := make([]byte, 1024)
|
||||
for {
|
||||
n := runtime.Stack(buf, false)
|
||||
if n < len(buf) {
|
||||
break
|
||||
}
|
||||
buf = make([]byte, 2*len(buf))
|
||||
}
|
||||
fmt.Println(string(buf))
|
||||
}
|
||||
|
||||
func GetCallStack() string {
|
||||
// 获取当前函数的调用者信息
|
||||
//pc, file, line, ok := runtime.Caller(1)
|
||||
_, _, _, ok := runtime.Caller(1)
|
||||
if !ok {
|
||||
fmt.Println("runtime.Caller error")
|
||||
return ""
|
||||
}
|
||||
|
||||
//funcName := runtime.FuncForPC(pc).Name()
|
||||
//fmt.Printf("Function: %s\nFile: %s\nLine: %d\n", funcName, file, line)
|
||||
|
||||
// 使用Stack打印完整的调用栈信息,可以用于debug
|
||||
buf := make([]byte, 1024)
|
||||
for {
|
||||
n := runtime.Stack(buf, false)
|
||||
if n < len(buf) {
|
||||
break
|
||||
}
|
||||
buf = make([]byte, 2*len(buf))
|
||||
}
|
||||
return string(buf)
|
||||
}
|
||||
|
||||
func CalcCrc32(data string) uint32 {
|
||||
tbl := crc32.MakeTable(crc32.Castagnoli)
|
||||
c := crc32.New(tbl)
|
||||
|
||||
if _, err := c.Write([]byte(data)); err != nil {
|
||||
}
|
||||
|
||||
return c.Sum32()
|
||||
}
|
||||
|
||||
func SmartParseTimeToMills(timeStr string) int64 {
|
||||
if IsPureNumber(timeStr) {
|
||||
return ToInt64(timeStr) * 1000
|
||||
}
|
||||
if StrContains(timeStr, "T") {
|
||||
t, err := time.Parse(time.RFC3339, timeStr)
|
||||
if err == nil {
|
||||
return t.UnixNano() / int64(time.Millisecond)
|
||||
}
|
||||
} else if StrContains(timeStr, ".") {
|
||||
const layout = "2006-01-02 15:04:05.000"
|
||||
if len(timeStr) > len(layout) {
|
||||
timeStr = timeStr[0:len(layout)]
|
||||
}
|
||||
t, err := time.Parse(layout, timeStr)
|
||||
if err == nil {
|
||||
return t.UnixNano() / int64(time.Millisecond)
|
||||
}
|
||||
} else {
|
||||
const layout = "2006-01-02 15:04:05"
|
||||
t, err := time.Parse(layout, timeStr)
|
||||
if err == nil {
|
||||
return t.UnixNano() / int64(time.Millisecond)
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func LoadFileAsString(fileName string) (string, error) {
|
||||
if f, err := os.Open(fileName); err == nil {
|
||||
data, err1 := ioutil.ReadAll(bufio.NewReader(f))
|
||||
return string(data), err1
|
||||
} else {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
func GetSyncMapSize(m sync.Map) int {
|
||||
var size int
|
||||
m.Range(func(key, value interface{}) bool {
|
||||
size++
|
||||
return true
|
||||
})
|
||||
return size
|
||||
}
|
||||
|
||||
func MapClone(m map[string]interface{}) map[string]interface{} {
|
||||
result := map[string]interface{}{}
|
||||
for k, v := range m {
|
||||
result[k] = v
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func AdjustRangeValue[T int | int32 | int64 | float32 | float64](value T, minV T, maxV T) T {
|
||||
if value < minV {
|
||||
value = minV
|
||||
}
|
||||
if value > maxV {
|
||||
value = maxV
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
func CreateCondTimer(ch chan int64, cond *sync.Cond, initSeconds int64) {
|
||||
waitSecond := initSeconds
|
||||
for {
|
||||
select {
|
||||
case waitSecond = <-ch:
|
||||
if waitSecond < 10 {
|
||||
waitSecond = 10
|
||||
}
|
||||
case <-time.After(time.Second * time.Duration(waitSecond)):
|
||||
cond.Broadcast()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func ExcUntilOk(cb func() bool) {
|
||||
for !cb() {
|
||||
}
|
||||
}
|
||||
|
||||
func ReadTextFile(fileName string) (string, error) {
|
||||
if f, err := os.Open(fileName); err == nil {
|
||||
data, err := ioutil.ReadAll(bufio.NewReader(f))
|
||||
return string(data), err
|
||||
} else {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
func IsDebug() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func PowInt64(base int64, exponent int64) int64 {
|
||||
var result int64 = 1
|
||||
var i int64 = 0
|
||||
for ; i < exponent; i++ {
|
||||
result *= base
|
||||
}
|
||||
return result
|
||||
}
|
389
timer.go
Normal file
389
timer.go
Normal file
@ -0,0 +1,389 @@
|
||||
package q5
|
||||
|
||||
const CONFIG_BASE_SMALL = false
|
||||
const TVN_BITS = 6
|
||||
const TVR_BITS = 8
|
||||
const TVN_SIZE = 1 << TVN_BITS
|
||||
const TVR_SIZE = 1 << TVR_BITS
|
||||
const TVN_MASK = TVN_SIZE - 1
|
||||
const TVR_MASK = TVR_SIZE - 1
|
||||
|
||||
const (
|
||||
TIMEOUT_TIMER = 0
|
||||
INTERVAL_TIMER = iota
|
||||
)
|
||||
|
||||
type XTimerDestoryHandleNode struct {
|
||||
entry ListHead
|
||||
cb func()
|
||||
}
|
||||
|
||||
type XTimer struct {
|
||||
freeTimerNum int32
|
||||
freeTimerList ListHead
|
||||
runningTimer *XTimerList
|
||||
timerTick int64
|
||||
getTickCount func(interface{}) int64
|
||||
context interface{}
|
||||
cacheTimerNum int32
|
||||
tv1 [TVR_SIZE]ListHead
|
||||
tv2 [TVN_SIZE]ListHead
|
||||
tv3 [TVN_SIZE]ListHead
|
||||
tv4 [TVN_SIZE]ListHead
|
||||
tv5 [TVN_SIZE]ListHead
|
||||
}
|
||||
|
||||
func (this *XTimer) Init(
|
||||
getTickCount func(interface{}) int64,
|
||||
context interface{},
|
||||
gcTime int32,
|
||||
cacheTimerNum int32) {
|
||||
initListHeadFunc := func(head *ListHead) {
|
||||
head.Init(nil)
|
||||
}
|
||||
initListHeadFunc(&this.freeTimerList)
|
||||
for i := 0; i < len(this.tv1); i++ {
|
||||
initListHeadFunc(&this.tv1[i])
|
||||
}
|
||||
for i := 0; i < len(this.tv2); i++ {
|
||||
initListHeadFunc(&this.tv2[i])
|
||||
}
|
||||
for i := 0; i < len(this.tv3); i++ {
|
||||
initListHeadFunc(&this.tv3[i])
|
||||
}
|
||||
for i := 0; i < len(this.tv4); i++ {
|
||||
initListHeadFunc(&this.tv4[i])
|
||||
}
|
||||
for i := 0; i < len(this.tv5); i++ {
|
||||
initListHeadFunc(&this.tv5[i])
|
||||
}
|
||||
|
||||
this.timerTick = getTickCount(context)
|
||||
this.context = context
|
||||
this.getTickCount = getTickCount
|
||||
this.cacheTimerNum = cacheTimerNum
|
||||
this.SetInterval(gcTime, this.gcTimerFunc)
|
||||
}
|
||||
|
||||
func (this *XTimer) UnInit() {
|
||||
this.clear()
|
||||
}
|
||||
|
||||
func (this *XTimer) clear() {
|
||||
freeTimerFunc := func(head *ListHead) {
|
||||
for !head.Empty() {
|
||||
timerList := head.FirstEntry().(*XTimerList)
|
||||
this.detachTimer(timerList)
|
||||
if !timerList.attachEntry.Empty() {
|
||||
timerList.attachEntry.DelInit()
|
||||
}
|
||||
}
|
||||
}
|
||||
freeTimerFunc(&this.freeTimerList)
|
||||
for i := 0; i < len(this.tv1); i++ {
|
||||
freeTimerFunc(&this.tv1[i])
|
||||
}
|
||||
for i := 0; i < len(this.tv2); i++ {
|
||||
freeTimerFunc(&this.tv2[i])
|
||||
}
|
||||
for i := 0; i < len(this.tv3); i++ {
|
||||
freeTimerFunc(&this.tv3[i])
|
||||
}
|
||||
for i := 0; i < len(this.tv4); i++ {
|
||||
freeTimerFunc(&this.tv4[i])
|
||||
}
|
||||
for i := 0; i < len(this.tv5); i++ {
|
||||
freeTimerFunc(&this.tv5[i])
|
||||
}
|
||||
}
|
||||
|
||||
func (this *XTimer) Update() {
|
||||
for this.getTickCount(this.context) >= this.timerTick {
|
||||
index := uint32(this.timerTick & TVR_MASK)
|
||||
|
||||
if index == 0 &&
|
||||
this.cascade(&this.tv2, this.getTimerIndex(0)) == 0 &&
|
||||
this.cascade(&this.tv3, this.getTimerIndex(1)) == 0 &&
|
||||
this.cascade(&this.tv4, this.getTimerIndex(2)) == 0 {
|
||||
this.cascade(&this.tv5, this.getTimerIndex(3))
|
||||
}
|
||||
this.timerTick++
|
||||
|
||||
var workList ListHead
|
||||
this.tv1[index].ReplaceInit(&workList)
|
||||
for !workList.Empty() {
|
||||
timer := workList.FirstEntry().(*XTimerList)
|
||||
this.runningTimer = timer
|
||||
timer.cb(TIMER_EXEC_EVENT, nil)
|
||||
if this.runningTimer != nil {
|
||||
switch this.runningTimer.timerType {
|
||||
case TIMEOUT_TIMER:
|
||||
this.internalDelete(timer, false, true)
|
||||
case INTERVAL_TIMER:
|
||||
this.internalModifyTime(timer, timer.expireTime)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
this.runningTimer = nil
|
||||
}
|
||||
|
||||
func (this *XTimer) NewTimerAttacher() *XTimerAttacher {
|
||||
attacher := new(XTimerAttacher)
|
||||
attacher.timer = this
|
||||
attacher.timers.Init(nil)
|
||||
return attacher
|
||||
}
|
||||
|
||||
func (this *XTimer) SetTimeout(expireTime int32, cb TimerCb) {
|
||||
this.internalSetTimeout(expireTime, cb, nil, nil)
|
||||
}
|
||||
|
||||
func (this *XTimer) SetTimeoutEx(expireTime int32, cb TimerCb, attacher *XTimerAttacher) {
|
||||
this.internalSetTimeout(expireTime, cb, attacher, nil)
|
||||
}
|
||||
|
||||
func (this *XTimer) SetTimeoutWp(expireTime int32, cb TimerCb) *XTimerWp {
|
||||
var wp *XTimerWp
|
||||
this.internalSetTimeout(expireTime, cb, nil, &wp)
|
||||
return wp
|
||||
}
|
||||
|
||||
func (this *XTimer) SetTimeoutExWp(expireTime int32, cb TimerCb, attacher *XTimerAttacher) *XTimerWp {
|
||||
var wp *XTimerWp
|
||||
this.internalSetTimeout(expireTime, cb, attacher, &wp)
|
||||
return wp
|
||||
}
|
||||
|
||||
func (this *XTimer) SetInterval(expireTime int32, cb TimerCb) {
|
||||
this.internalSetInterval(expireTime, cb, nil, nil)
|
||||
}
|
||||
|
||||
func (this *XTimer) SetIntervalEx(expireTime int32, cb TimerCb, attacher *XTimerAttacher) {
|
||||
this.internalSetInterval(expireTime, cb, attacher, nil)
|
||||
}
|
||||
|
||||
func (this *XTimer) SetIntervalWp(expireTime int32, cb TimerCb) *XTimerWp {
|
||||
var wp *XTimerWp
|
||||
this.internalSetInterval(expireTime, cb, nil, &wp)
|
||||
return wp
|
||||
}
|
||||
|
||||
func (this *XTimer) SetIntervalExWp(expireTime int32, cb TimerCb, attacher *XTimerAttacher) *XTimerWp {
|
||||
var wp *XTimerWp
|
||||
this.internalSetInterval(expireTime, cb, attacher, &wp)
|
||||
return wp
|
||||
}
|
||||
|
||||
func (this *XTimer) internalSetTimeout(expireTime int32, cb TimerCb, attacher *XTimerAttacher, wpPp **XTimerWp) {
|
||||
timer := this.newTimerList()
|
||||
timer.initTimerList(this, TIMEOUT_TIMER, expireTime, cb)
|
||||
if attacher != nil {
|
||||
attacher.timers.AddTail(&timer.attachEntry)
|
||||
}
|
||||
this.internalModifyTime(timer, expireTime)
|
||||
if wpPp != nil {
|
||||
timer.wp = &XTimerWp{
|
||||
timer: timer,
|
||||
}
|
||||
*wpPp = timer.wp
|
||||
}
|
||||
}
|
||||
|
||||
func (this *XTimer) internalSetInterval(expireTime int32, cb TimerCb, attacher *XTimerAttacher, wpPp **XTimerWp) {
|
||||
timer := this.newTimerList()
|
||||
timer.initTimerList(this, INTERVAL_TIMER, expireTime, cb)
|
||||
if attacher != nil {
|
||||
attacher.timers.AddTail(&timer.attachEntry)
|
||||
}
|
||||
this.internalModifyTime(timer, expireTime)
|
||||
if wpPp != nil {
|
||||
timer.wp = &XTimerWp{
|
||||
timer: timer,
|
||||
}
|
||||
*wpPp = timer.wp
|
||||
}
|
||||
}
|
||||
|
||||
func (this *XTimer) ModifyTimer(timerWp *XTimerWp, expireTime int32) {
|
||||
if timerWp.Expired() {
|
||||
panic("Xtimer ModifyTimer expired timer")
|
||||
}
|
||||
this.internalModifyTime(timerWp.timer, expireTime)
|
||||
}
|
||||
|
||||
func (this *XTimer) Delete(timerWp *XTimerWp) {
|
||||
if timerWp.Expired() {
|
||||
panic("Xtimer Delete expired timer")
|
||||
}
|
||||
this.internalDelete(timerWp.timer, false, true)
|
||||
}
|
||||
|
||||
func (this *XTimer) GetRemainTime(timerWp *XTimerWp) int64 {
|
||||
if timerWp.Expired() {
|
||||
panic("Xtimer GetRemainTime expired timer")
|
||||
}
|
||||
return this.internalGetRemainTime(timerWp.timer)
|
||||
}
|
||||
|
||||
func (this *XTimer) internalGetRemainTime(timer *XTimerList) int64 {
|
||||
remainTime := timer.expires - this.getTickCount(this.context)
|
||||
if remainTime < 0 {
|
||||
return 0
|
||||
} else {
|
||||
return remainTime
|
||||
}
|
||||
}
|
||||
|
||||
func (this *XTimer) GetIdleTime() int64 {
|
||||
var idleTime int64 = 1
|
||||
for i := (this.timerTick & TVR_MASK); i < TVR_SIZE; i++ {
|
||||
if !this.tv1[i].Empty() {
|
||||
break
|
||||
}
|
||||
idleTime++
|
||||
}
|
||||
return idleTime
|
||||
}
|
||||
|
||||
func (this *XTimer) detachTimer(timerList *XTimerList) {
|
||||
if !timerList.entry.Empty() {
|
||||
timerList.entry.DelInit()
|
||||
}
|
||||
}
|
||||
|
||||
func (this *XTimer) addToFreeList(timerList *XTimerList) {
|
||||
timerList.reset()
|
||||
this.freeTimerList.AddTail(&timerList.entry)
|
||||
this.freeTimerNum++
|
||||
}
|
||||
|
||||
func (this *XTimer) cascade(tv *[TVN_SIZE]ListHead, index uint32) uint32 {
|
||||
var cascadeList ListHead
|
||||
tv[index].ReplaceInit(&cascadeList)
|
||||
|
||||
if !cascadeList.Empty() {
|
||||
pos := cascadeList.next
|
||||
next := pos.next
|
||||
for pos != &cascadeList {
|
||||
this.internalAddTimer(pos.data.(*XTimerList))
|
||||
pos = next
|
||||
next = pos.next
|
||||
}
|
||||
}
|
||||
return index
|
||||
}
|
||||
|
||||
func (this *XTimer) internalAddTimer(timerList *XTimerList) {
|
||||
timerList.entry.data = timerList
|
||||
expires := timerList.expires
|
||||
idx := expires - this.timerTick
|
||||
var vec *ListHead
|
||||
var index uint32
|
||||
|
||||
if idx < 0 {
|
||||
index = (uint32)(this.timerTick & TVR_MASK)
|
||||
vec = &this.tv1[index]
|
||||
} else if idx < TVR_SIZE {
|
||||
index = (uint32)(expires & TVR_MASK)
|
||||
vec = &this.tv1[index]
|
||||
} else if idx < (1 << (TVR_BITS + TVN_BITS)) {
|
||||
index = (uint32)((expires >> TVR_BITS) & TVN_MASK)
|
||||
vec = &this.tv2[index]
|
||||
} else if idx < (1 << (TVR_BITS + 2*TVN_BITS)) {
|
||||
index = (uint32)((expires >> (TVR_BITS + 1*TVN_BITS)) & TVN_MASK)
|
||||
vec = &this.tv3[index]
|
||||
} else if idx < (1 << (TVR_BITS + 3*TVN_BITS)) {
|
||||
index = (uint32)((expires >> (TVR_BITS + 2*TVN_BITS)) & TVN_MASK)
|
||||
vec = &this.tv4[index]
|
||||
} else {
|
||||
index = (uint32)((expires >> (TVR_BITS + 3*TVN_BITS)) & TVN_MASK)
|
||||
vec = &this.tv5[index]
|
||||
}
|
||||
vec.AddTail(&timerList.entry)
|
||||
}
|
||||
|
||||
func (this *XTimer) getTimerIndex(index uint32) uint32 {
|
||||
return (uint32)((this.timerTick >> (TVR_BITS + index*TVN_BITS)) & TVN_MASK)
|
||||
}
|
||||
|
||||
func (this *XTimer) newTimerList() *XTimerList {
|
||||
if !this.freeTimerList.Empty() {
|
||||
timerList := this.freeTimerList.FirstEntry().(*XTimerList)
|
||||
this.freeTimerNum--
|
||||
return timerList
|
||||
} else {
|
||||
timerList := new(XTimerList)
|
||||
timerList.init()
|
||||
return timerList
|
||||
}
|
||||
}
|
||||
|
||||
func (this *XTimer) gcTimerFunc(ev int32, args *Args) {
|
||||
if ev == TIMER_EXEC_EVENT {
|
||||
count := 0
|
||||
for !this.freeTimerList.Empty() && this.freeTimerNum > this.cacheTimerNum {
|
||||
timerList := this.freeTimerList.FirstEntry().(*XTimerList)
|
||||
timerList.entry.DelInit()
|
||||
this.freeTimerNum--
|
||||
count++
|
||||
if count > 1000 {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (this *XTimer) internalDelete(timer *XTimerList, isDestory bool, toFreeList bool) {
|
||||
if timer == nil {
|
||||
panic("Xtimer.internalDelete error")
|
||||
}
|
||||
if this.runningTimer == timer {
|
||||
this.runningTimer = nil
|
||||
}
|
||||
this.detachTimer(timer)
|
||||
if !timer.attachEntry.Empty() {
|
||||
timer.attachEntry.DelInit()
|
||||
}
|
||||
for !timer.destoryHandleList.Empty() {
|
||||
handle := timer.destoryHandleList.FirstEntry().(XTimerDestoryHandleNode)
|
||||
handle.entry.DelInit()
|
||||
handle.cb()
|
||||
}
|
||||
if isDestory {
|
||||
timer.cb(TIMER_DESTORY_EVENT, nil)
|
||||
} else {
|
||||
timer.cb(TIMER_DELETE_EVENT, nil)
|
||||
}
|
||||
timer.cb = nil
|
||||
if timer.wp != nil {
|
||||
timer.wp.timer = nil
|
||||
timer.wp = nil
|
||||
}
|
||||
if toFreeList {
|
||||
this.addToFreeList(timer)
|
||||
}
|
||||
}
|
||||
|
||||
func (this *XTimer) internalModifyTime(timer *XTimerList, expireTime int32) {
|
||||
this.detachTimer(timer)
|
||||
timer.expireTime = expireTime
|
||||
timer.expires = this.getTickCount(this.context) + int64(expireTime)
|
||||
this.internalAddTimer(timer)
|
||||
}
|
||||
|
||||
func (this *XTimer) clearAttacher(attacher *XTimerAttacher) {
|
||||
var workList ListHead
|
||||
attacher.timers.ReplaceInit(&workList)
|
||||
for !workList.Empty() {
|
||||
timer := workList.FirstEntry().(*XTimerList)
|
||||
this.internalDelete(timer, false, true)
|
||||
}
|
||||
}
|
||||
|
||||
func (this *XTimer) DeleteRunningTimer() {
|
||||
if this.runningTimer != nil {
|
||||
this.internalDelete(this.runningTimer, false, true)
|
||||
this.runningTimer = nil
|
||||
}
|
||||
}
|
60
timerlist.go
Normal file
60
timerlist.go
Normal file
@ -0,0 +1,60 @@
|
||||
package q5
|
||||
|
||||
type XTimerWp struct {
|
||||
timer *XTimerList
|
||||
}
|
||||
|
||||
type XTimerAttacher struct {
|
||||
timer *XTimer
|
||||
timers ListHead
|
||||
}
|
||||
|
||||
func (this *XTimerAttacher) ClearTimers() {
|
||||
this.timer.clearAttacher(this)
|
||||
}
|
||||
|
||||
type XTimerList struct {
|
||||
destoryHandleList ListHead
|
||||
entry ListHead
|
||||
attachEntry ListHead
|
||||
timerType int8
|
||||
expireTime int32
|
||||
expires int64
|
||||
|
||||
cb TimerCb
|
||||
wp *XTimerWp
|
||||
}
|
||||
|
||||
func (this *XTimerWp) Expired() bool {
|
||||
return this.timer == nil
|
||||
}
|
||||
|
||||
func (this *XTimerList) initTimerList(
|
||||
timer interface{},
|
||||
timerType int8,
|
||||
expireTime int32,
|
||||
cb TimerCb) {
|
||||
this.timerType = timerType
|
||||
this.expireTime = expireTime
|
||||
this.cb = cb
|
||||
}
|
||||
|
||||
func (this *XTimerList) reset() {
|
||||
if !this.entry.Empty() {
|
||||
this.entry.DelInit()
|
||||
}
|
||||
if !this.attachEntry.Empty() {
|
||||
this.attachEntry.DelInit()
|
||||
}
|
||||
this.cb = nil
|
||||
}
|
||||
|
||||
func (this *XTimerList) init() {
|
||||
this.entry.Init(this)
|
||||
this.attachEntry.Init(this)
|
||||
this.destoryHandleList.Init(nil)
|
||||
}
|
||||
|
||||
func (this *XTimerList) Attach(timerAttacher *XTimerAttacher) {
|
||||
timerAttacher.timers.AddTail(&this.attachEntry)
|
||||
}
|
13
types.go
Normal file
13
types.go
Normal file
@ -0,0 +1,13 @@
|
||||
package q5
|
||||
|
||||
type TimerCb func(int32, *Args)
|
||||
type Args []interface{}
|
||||
|
||||
type Module interface {
|
||||
Init()
|
||||
UnInit()
|
||||
}
|
||||
|
||||
const TIMER_EXEC_EVENT = 1
|
||||
const TIMER_DELETE_EVENT = 2
|
||||
const TIMER_DESTORY_EVENT = 3
|
51
uuid.go
Normal file
51
uuid.go
Normal file
@ -0,0 +1,51 @@
|
||||
package q5
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
const Q5_EPOCH = 1419120000000
|
||||
|
||||
const MACHINE_ID_BIT_NUM = 12
|
||||
const SEQUNCE_ID_BIT_NUM = 10
|
||||
const MAX_MACHINE_ID = (1 << MACHINE_ID_BIT_NUM) - 1
|
||||
const MAX_SEQUNCE_ID = (1 << SEQUNCE_ID_BIT_NUM) - 1
|
||||
|
||||
type Uuid struct {
|
||||
machineId int32
|
||||
sequenceId int32
|
||||
lastGenerateTick int64
|
||||
}
|
||||
|
||||
func (this *Uuid) Generate() int64 {
|
||||
var value int64
|
||||
tick := GetTickCount()
|
||||
if tick == this.lastGenerateTick {
|
||||
this.sequenceId++
|
||||
if this.sequenceId >= MAX_SEQUNCE_ID {
|
||||
for tick <= this.lastGenerateTick {
|
||||
time.Sleep(time.Millisecond * 1)
|
||||
tick = GetTickCount()
|
||||
}
|
||||
this.sequenceId = 0
|
||||
}
|
||||
} else {
|
||||
this.sequenceId = 0
|
||||
}
|
||||
this.lastGenerateTick = tick
|
||||
// 保留后41位时间
|
||||
value = (tick - Q5_EPOCH) << 22
|
||||
//中间12位是机器ID
|
||||
value |= int64((int64(this.machineId) & int64(MAX_MACHINE_ID)) << SEQUNCE_ID_BIT_NUM)
|
||||
//最后10位是sequenceID
|
||||
value |= int64(this.sequenceId & MAX_SEQUNCE_ID)
|
||||
return value
|
||||
}
|
||||
|
||||
func (this *Uuid) SetMachineId(macId int32) {
|
||||
if macId > MAX_MACHINE_ID || macId < 1 {
|
||||
panic(fmt.Sprintf("Uuid.SetMachineId error %d", macId))
|
||||
}
|
||||
this.machineId = macId
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user