Compare commits

...

122 Commits

Author SHA1 Message Date
aozhiwei
b065fccf5c 1 2024-08-07 15:02:42 +08:00
aozhiwei
489449c65d 1 2024-08-06 22:28:19 +08:00
aozhiwei
7078a16983 1 2024-08-06 22:16:40 +08:00
azw
ba4b733a80 1 2024-08-03 16:17:36 +08:00
aozhiwei
d40b258a47 1 2024-07-24 09:41:44 +08:00
aozhiwei
ad5656a00a 1 2024-07-23 15:38:58 +08:00
aozhiwei
ccfa6c4f99 1 2024-07-23 11:42:41 +08:00
aozhiwei
db5e615704 1 2024-07-22 13:47:12 +08:00
aozhiwei
b9c7e05031 1 2024-07-20 15:35:08 +08:00
aozhiwei
dd6cf60934 1 2024-07-10 14:20:26 +08:00
aozhiwei
f715cffbce 1 2024-06-29 20:56:28 +08:00
aozhiwei
6d58535a91 1 2024-06-29 20:49:08 +08:00
aozhiwei
5c996e016a 1 2024-06-29 14:57:15 +08:00
aozhiwei
a0122ba8e5 1 2024-06-28 14:46:30 +08:00
aozhiwei
883eff90e5 1 2024-06-28 12:34:13 +08:00
aozhiwei
91b9c416fb 1 2024-06-26 21:38:48 +08:00
aozhiwei
8877d9e02a 1 2024-06-25 20:50:19 +08:00
aozhiwei
763b161e26 1 2024-06-22 21:21:04 +08:00
aozhiwei
a26208f76e 1 2024-06-21 17:36:23 +08:00
aozhiwei
9afe1aa679 1 2024-06-21 16:49:38 +08:00
aozhiwei
de3dc89691 1 2024-06-20 17:09:30 +08:00
aozhiwei
47f75d8247 1 2024-06-16 14:06:10 +08:00
aozhiwei
3ade5a2266 1 2024-06-16 14:04:58 +08:00
aozhiwei
e7e95ff498 1 2024-06-16 12:57:13 +08:00
aozhiwei
9048589a4d 1 2024-06-05 16:47:05 +08:00
aozhiwei
06880e9f72 1 2024-05-09 13:24:10 +08:00
aozhiwei
4f7255c731 1 2024-04-26 13:24:04 +08:00
aozhiwei
0ec6d9a142 1 2024-04-26 11:18:12 +08:00
aozhiwei
75b0c72d72 1 2024-04-20 15:57:18 +08:00
aozhiwei
fc08e4f8c5 1 2024-04-18 14:22:45 +08:00
aozhiwei
70d3baf515 1 2024-04-15 11:24:14 +08:00
aozhiwei
9ab4817ec5 1 2024-04-13 12:50:58 +08:00
aozhiwei
3eeb9788ce 1 2024-04-09 19:30:17 +08:00
aozhiwei
01573c9947 1 2024-04-09 15:22:30 +08:00
aozhiwei
67c14c72ff 1 2024-04-09 15:00:34 +08:00
aozhiwei
7f080f238e 1 2024-04-09 14:56:56 +08:00
aozhiwei
a6abd190f9 1 2024-04-07 14:32:38 +08:00
aozhiwei
61a612b594 1 2024-03-24 08:43:31 +08:00
aozhiwei
583a9d2358 1 2023-12-12 11:48:02 +08:00
aozhiwei
decda354c8 add NewEmptyStrPtr 2023-12-11 17:48:10 +08:00
aozhiwei
3d4c6f692f 1 2023-12-05 15:30:18 +08:00
殷勇
50cb269954 save 2023-10-25 15:46:41 +08:00
殷勇
ef6a02719b 更新 listhead, timer 添加方法 DeleteRunningTimer() 删除当前运行定时器。 2023-10-23 11:50:27 +08:00
殷勇
72f4aa8132 修改函数 GetLocalIP 2023-09-25 15:15:52 +08:00
aozhiwei
aa48a0c524 1 2023-09-16 09:59:08 +08:00
aozhiwei
b590bbd0fe 1 2023-09-15 15:09:58 +08:00
aozhiwei
867867b5d6 1 2023-09-15 11:07:34 +08:00
aozhiwei
f0ba360bdc 1 2023-09-15 08:25:59 +08:00
aozhiwei
a784d12ab4 1 2023-09-15 07:35:10 +08:00
aozhiwei
37aba94237 优化list——head 2023-09-14 22:25:58 +08:00
aozhiwei
fe65489de2 1 2023-09-13 10:31:49 +08:00
aozhiwei
2ce4c46c71 1 2023-09-11 19:13:42 +08:00
aozhiwei
a28a913a90 1 2023-09-09 18:21:43 +08:00
aozhiwei
50a75088ae Merge branch 'master' of git.kingsome.cn:server_common/q5 2023-09-09 10:52:14 +08:00
aozhiwei
d72fab5c83 1 2023-09-09 10:51:49 +08:00
殷勇
87bea6ab2c add password 2023-09-08 17:01:58 +08:00
aozhiwei
f913e480a2 1 2023-09-08 13:34:31 +08:00
aozhiwei
ed967899c4 1 2023-09-07 16:19:52 +08:00
殷勇
9823133648 Add HasBitFlag, SetBitFlag, UnSetBitFlag 2023-08-25 16:17:22 +08:00
azw
8716d301c6 1 2023-08-20 15:29:28 +08:00
azw
9377182985 1 2023-08-19 20:52:10 +08:00
殷勇
b343ad660a Add random.go 2023-08-18 11:38:43 +08:00
azw
aecf26a45c 1 2023-08-13 12:39:23 +08:00
aozhiwei
7bffd9a638 1 2023-08-12 20:31:39 +08:00
aozhiwei
0644461bc7 1 2023-08-12 20:23:16 +08:00
aozhiwei
dacdd2a5db 1 2023-08-12 19:47:54 +08:00
aozhiwei
efae915742 1 2023-08-12 18:51:47 +08:00
aozhiwei
2418793e3d 1 2023-08-12 15:13:55 +08:00
aozhiwei
67c974caa2 1 2023-08-12 15:09:40 +08:00
aozhiwei
cadab4f094 1 2023-08-12 14:59:56 +08:00
aozhiwei
490774a7a3 1 2023-08-12 13:35:55 +08:00
aozhiwei
6a998e6eea 1 2023-08-11 14:45:11 +08:00
aozhiwei
b62848491f Merge branch 'master' of git.kingsome.cn:server_common/q5 2023-08-11 13:12:50 +08:00
aozhiwei
96e7c20cf0 1 2023-08-11 13:12:33 +08:00
殷勇
73c047e43f 添加函数GetLocalIP 2023-08-10 14:48:33 +08:00
殷勇
85a82957ca Add convert 2023-08-09 17:55:41 +08:00
aozhiwei
607a4887d0 1 2021-08-12 15:43:51 +08:00
aozhiwei
d82df9df79 添加urlencode 2021-08-12 13:41:05 +08:00
aozhiwei
562242ca3f 1 2021-01-22 13:56:55 +08:00
aozhiwei
bc3b2825a6 1 2020-12-19 16:47:12 +08:00
aozhiwei
03ffea28fe 1 2020-12-16 20:02:00 +08:00
aozhiwei
c832144308 add httppostcontent 2020-12-16 17:55:55 +08:00
aozhiwei
a7c34b44d7 1 2020-12-04 16:47:45 +08:00
aozhiwei
70271a1b60 1 2020-11-30 17:59:36 +08:00
aozhiwei
56027b3c56 add ResponseErr 2020-11-12 17:36:44 +08:00
aozhiwei
1e70d9f893 1 2020-11-03 17:22:58 +08:00
aozhiwei
80edf5bfe5 1 2020-10-30 19:09:47 +08:00
aozhiwei
877ac12ec2 1 2020-10-30 13:54:25 +08:00
aozhiwei
e21d2e3b5d 1 2020-10-28 19:18:47 +08:00
aozhiwei
f9776ebd7c 1 2020-10-28 16:59:47 +08:00
aozhiwei
933ed5c972 1 2020-10-28 16:25:29 +08:00
aozhiwei
7442ad5d81 1 2020-10-27 15:42:56 +08:00
aozhiwei
ef23a486d3 1 2020-10-26 20:04:00 +08:00
aozhiwei
b50a0152e1 1 2020-10-26 17:56:50 +08:00
aozhiwei
0067fe79b2 1 2020-10-26 16:21:53 +08:00
aozhiwei
00b7f9e2ea 1 2020-10-26 15:10:16 +08:00
aozhiwei
adf774f543 1 2020-10-26 14:56:17 +08:00
aozhiwei
1d9c4287fb 1 2020-10-26 14:04:33 +08:00
aozhiwei
190668be5f 1 2020-10-26 12:58:22 +08:00
aozhiwei
2a26b63c85 1 2020-10-26 10:12:41 +08:00
aozhiwei
f62a41fba7 1 2020-10-23 17:51:35 +08:00
aozhiwei
5b8b5563e9 1 2020-10-23 11:14:30 +08:00
aozhiwei
88b284f7de 1 2020-09-10 11:24:57 +08:00
aozhiwei
6fd253d455 1 2020-09-08 18:26:02 +08:00
aozhiwei
e0ae331d17 1 2020-09-08 17:36:26 +08:00
aozhiwei
a3ab521064 1 2020-09-08 17:00:41 +08:00
aozhiwei
7ab75e421e 1 2020-09-08 15:28:10 +08:00
aozhiwei
7749a036a0 2 2020-09-08 15:20:32 +08:00
aozhiwei
a3412f2da9 1 2020-09-08 15:13:23 +08:00
aozhiwei
8360f367bc 1 2020-09-08 12:54:43 +08:00
aozhiwei
de0c368e4c 1 2020-09-07 19:29:17 +08:00
aozhiwei
f58f61120a 1 2020-09-07 16:57:34 +08:00
aozhiwei
a9b6ae14e7 1 2020-09-04 12:36:40 +08:00
aozhiwei
e934b0c6ca 1 2020-09-04 11:27:47 +08:00
aozhiwei
9e16bd764d 1 2020-09-03 20:25:00 +08:00
aozhiwei
4192dcc9fc 1 2020-09-03 20:06:44 +08:00
aozhiwei
f54243a465 1 2020-08-28 23:27:02 +08:00
aozhiwei
5d0b0eacad 1 2020-08-28 11:48:15 +08:00
aozhiwei
d1c788bb06 1 2020-08-27 23:24:51 +08:00
aozhiwei
a8b0821963 1 2020-08-27 21:12:17 +08:00
aozhiwei
924eed81d1 1 2020-08-27 20:03:26 +08:00
aozhiwei
3e730f5d26 1 2020-08-26 14:42:46 +08:00
20 changed files with 2110 additions and 2 deletions

29
algorithm.go Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
}
}
}

View File

@ -1,6 +1,144 @@
package q5 package q5
func Test()(a string) { import (
return "testa" "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
View 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
View 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
View 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
View 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
View 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
View 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
}