淇敼锛?. 鏂板浜嗛攣鏈哄埗浠ラ槻姝㈠苟鍙戣闂啿绐侊紱2. 淇敼浜嗕竴浜涘彉閲忓悕浠ユ彁楂樹唬鐮佸彲璇绘€э紱 3. 淇浜嗕竴涓彲鑳藉鑷寸紦鍐插尯婧㈠嚭鐨?bug锛屽皢缂撳啿鍖哄ぇ灏忚缃负 4096锛?. 瀵逛唬鐮佽繘琛屼簡涓€浜涘叾浠栫殑灏忔敼杩涘拰浼樺寲銆?
git-svn-id: svn://47.119.165.148/zhub@121 e63fbceb-bcc3-4977-ac22-735b83d8d0f4
This commit is contained in:
2
app.go
2
app.go
@@ -7,6 +7,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
"zhub/cli"
|
"zhub/cli"
|
||||||
"zhub/conf"
|
"zhub/conf"
|
||||||
|
"zhub/monitor"
|
||||||
"zhub/zsub"
|
"zhub/zsub"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -46,6 +47,7 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if server {
|
if server {
|
||||||
|
go monitor.StartHttp()
|
||||||
zsub.ServerStart(addr) // 服务进程启动
|
zsub.ServerStart(addr) // 服务进程启动
|
||||||
} else {
|
} else {
|
||||||
cli.ClientRun(addr)
|
cli.ClientRun(addr)
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package cli
|
|||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/go-basic/uuid"
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
@@ -24,9 +25,18 @@ type Client struct {
|
|||||||
subFun map[string]func(v string) // subscribe topic and callback function
|
subFun map[string]func(v string) // subscribe topic and callback function
|
||||||
timerFun map[string]func() // subscribe timer amd callback function
|
timerFun map[string]func() // subscribe timer amd callback function
|
||||||
|
|
||||||
chSend chan []string // chan of send message
|
chSend chan []string // chan of send message
|
||||||
chReceive chan []string // chan of receive message
|
chReceive chan []string // chan of receive message
|
||||||
timerReceive chan []string // chan of timer
|
timerReceive chan []string // chan of timer
|
||||||
|
lockFlag map[string]*Lock // chan of lock
|
||||||
|
}
|
||||||
|
|
||||||
|
type Lock struct {
|
||||||
|
Key string // lock Key
|
||||||
|
Uuid string // lock Uuid
|
||||||
|
flagChan chan int //
|
||||||
|
// starttime uint32 // lock start time
|
||||||
|
// duration int // lock duration
|
||||||
}
|
}
|
||||||
|
|
||||||
func Create(addr string, groupid string) (*Client, error) {
|
func Create(addr string, groupid string) (*Client, error) {
|
||||||
@@ -48,6 +58,7 @@ func Create(addr string, groupid string) (*Client, error) {
|
|||||||
chSend: make(chan []string, 100),
|
chSend: make(chan []string, 100),
|
||||||
chReceive: make(chan []string, 100),
|
chReceive: make(chan []string, 100),
|
||||||
timerReceive: make(chan []string, 100),
|
timerReceive: make(chan []string, 100),
|
||||||
|
lockFlag: make(map[string]*Lock),
|
||||||
}
|
}
|
||||||
|
|
||||||
client.send("groupid " + groupid)
|
client.send("groupid " + groupid)
|
||||||
@@ -115,6 +126,8 @@ subscribe x y z
|
|||||||
func (c *Client) Subscribe(topic string, fun func(v string)) {
|
func (c *Client) Subscribe(topic string, fun func(v string)) {
|
||||||
c.send("subscribe " + topic)
|
c.send("subscribe " + topic)
|
||||||
if fun != nil {
|
if fun != nil {
|
||||||
|
c.wlock.Lock()
|
||||||
|
defer c.wlock.Unlock()
|
||||||
c.subFun[topic] = fun
|
c.subFun[topic] = fun
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -133,7 +146,7 @@ func (c *Client) ping() {
|
|||||||
c.send("ping")
|
c.send("ping")
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------------------- pub-sub --------------------------------------
|
//Publish -------------------------------------- pub-sub --------------------------------------
|
||||||
/*
|
/*
|
||||||
send topic message :
|
send topic message :
|
||||||
---
|
---
|
||||||
@@ -158,7 +171,9 @@ func (c *Client) Delay(topic string, message string, delay int) error {
|
|||||||
return c.send("delay", topic, message, strconv.Itoa(delay))
|
return c.send("delay", topic, message, strconv.Itoa(delay))
|
||||||
}
|
}
|
||||||
|
|
||||||
/*func (c *Client) Timer(topic string, expr string, fun func()) {
|
/*
|
||||||
|
Timer
|
||||||
|
func (c *Client) Timer(topic string, expr string, fun func()) {
|
||||||
c.timerFun[topic] = fun
|
c.timerFun[topic] = fun
|
||||||
c.send("timer", topic, expr, "x")
|
c.send("timer", topic, expr, "x")
|
||||||
}*/
|
}*/
|
||||||
@@ -185,6 +200,35 @@ func (c *Client) Close() {
|
|||||||
c.conn.Close()
|
c.conn.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Lock Key
|
||||||
|
func (c *Client) Lock(key string, duration int) Lock {
|
||||||
|
uuid := uuid.New()
|
||||||
|
c.send("lock", key, uuid, strconv.Itoa(duration))
|
||||||
|
|
||||||
|
lockChan := make(chan int, 2)
|
||||||
|
go func() {
|
||||||
|
c.wlock.Lock()
|
||||||
|
defer c.wlock.Unlock()
|
||||||
|
c.lockFlag[uuid] = &Lock{
|
||||||
|
Key: key,
|
||||||
|
Uuid: uuid,
|
||||||
|
flagChan: lockChan,
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-lockChan:
|
||||||
|
log.Println("lock-ok", time.Now().UnixNano()/1e6, uuid)
|
||||||
|
}
|
||||||
|
|
||||||
|
return Lock{Key: key, Uuid: uuid}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) Unlock(l Lock) {
|
||||||
|
c.send("unlock", l.Key, l.Uuid)
|
||||||
|
delete(c.lockFlag, l.Uuid)
|
||||||
|
}
|
||||||
|
|
||||||
/*func (c *Client) subscribes(topics ...string) error {
|
/*func (c *Client) subscribes(topics ...string) error {
|
||||||
if len(topics) == 0 {
|
if len(topics) == 0 {
|
||||||
return nil
|
return nil
|
||||||
@@ -269,6 +313,19 @@ func (c *Client) receive() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len(vs) == 3 && strings.EqualFold(vs[0], "message") {
|
if len(vs) == 3 && strings.EqualFold(vs[0], "message") {
|
||||||
|
if strings.EqualFold(vs[1], "lock") { // message lock Uuid
|
||||||
|
go func() {
|
||||||
|
log.Println("lock:" + vs[2])
|
||||||
|
c.wlock.Lock()
|
||||||
|
defer c.wlock.Unlock()
|
||||||
|
|
||||||
|
if c.lockFlag[vs[2]] == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.lockFlag[vs[2]].flagChan <- 0
|
||||||
|
}()
|
||||||
|
continue
|
||||||
|
}
|
||||||
c.chReceive <- vs
|
c.chReceive <- vs
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|||||||
32
cli_test.go
32
cli_test.go
@@ -1,6 +1,7 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"strconv"
|
"strconv"
|
||||||
"testing"
|
"testing"
|
||||||
@@ -108,12 +109,13 @@ func TestTimer(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestSendCmd(t *testing.T) {
|
func TestSendCmd(t *testing.T) {
|
||||||
client, err := cli.Create(addr, "")
|
client, err := cli.Create(addr, "group-admin")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
client.Cmd("reload-timer")
|
//client.Cmd("reload-timer")
|
||||||
|
client.Cmd("shutdown")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPublish(t *testing.T) {
|
func TestPublish(t *testing.T) {
|
||||||
@@ -127,3 +129,29 @@ func TestPublish(t *testing.T) {
|
|||||||
|
|
||||||
time.Sleep(time.Second)
|
time.Sleep(time.Second)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestLock(t *testing.T) {
|
||||||
|
client, _ := cli.Create(addr, "xx")
|
||||||
|
|
||||||
|
client.Subscribe("lock", func(v string) {
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
var fun = func(x string) {
|
||||||
|
log.Println("lock", time.Now().UnixNano()/1e6)
|
||||||
|
lock := client.Lock("a", 30)
|
||||||
|
defer client.Unlock(lock)
|
||||||
|
//client.Lock("a", 5)
|
||||||
|
|
||||||
|
for i := 0; i < 5; i++ {
|
||||||
|
time.Sleep(time.Second * 1)
|
||||||
|
fmt.Println(x + ":" + strconv.Itoa(i+1))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
go fun("x")
|
||||||
|
go fun("y")
|
||||||
|
go fun("z")
|
||||||
|
|
||||||
|
time.Sleep(time.Second * 30 * 10)
|
||||||
|
}
|
||||||
|
|||||||
1
go.mod
1
go.mod
@@ -3,6 +3,7 @@ module zhub
|
|||||||
go 1.16
|
go 1.16
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/go-basic/uuid v1.0.0 // indirect
|
||||||
github.com/go-sql-driver/mysql v1.5.0
|
github.com/go-sql-driver/mysql v1.5.0
|
||||||
github.com/robfig/cron v1.2.0
|
github.com/robfig/cron v1.2.0
|
||||||
)
|
)
|
||||||
|
|||||||
48
monitor/monitor.go
Normal file
48
monitor/monitor.go
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
package monitor
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"zhub/zsub"
|
||||||
|
)
|
||||||
|
|
||||||
|
func StartHttp() {
|
||||||
|
dir, _ := os.Getwd()
|
||||||
|
webDir := path.Join(dir, "/public")
|
||||||
|
|
||||||
|
http.Handle("/", http.FileServer(http.Dir(webDir)))
|
||||||
|
http.HandleFunc("/info", info)
|
||||||
|
http.HandleFunc("/cleanup", cleanup)
|
||||||
|
http.HandleFunc("/retimer", retimer)
|
||||||
|
|
||||||
|
http.ListenAndServe(":1217", nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func retimer(w http.ResponseWriter, r *http.Request) {
|
||||||
|
zsub.ZSubx().ReloadTimer()
|
||||||
|
renderJson(w, "+reload timer ok")
|
||||||
|
}
|
||||||
|
|
||||||
|
func cleanup(w http.ResponseWriter, r *http.Request) {
|
||||||
|
zsub.ZSubx().Clearup()
|
||||||
|
renderJson(w, "+OK")
|
||||||
|
}
|
||||||
|
|
||||||
|
func info(w http.ResponseWriter, r *http.Request) {
|
||||||
|
topics := zsub.Info()
|
||||||
|
renderJson(w, topics)
|
||||||
|
}
|
||||||
|
|
||||||
|
func renderJson(w http.ResponseWriter, d interface{}) {
|
||||||
|
var bytes []byte
|
||||||
|
|
||||||
|
if str, ok := d.(string); ok {
|
||||||
|
bytes = []byte(str)
|
||||||
|
} else {
|
||||||
|
bytes, _ = json.Marshal(d)
|
||||||
|
w.Header().Set("content-type", "application/json; charset=utf-8;")
|
||||||
|
}
|
||||||
|
w.Write(bytes)
|
||||||
|
}
|
||||||
8
pkg.bat
8
pkg.bat
@@ -3,8 +3,8 @@ SET GOARCH=amd64
|
|||||||
go build -o zhub.sh -ldflags "-s -w" ./app.go
|
go build -o zhub.sh -ldflags "-s -w" ./app.go
|
||||||
upx -9 zhub.sh
|
upx -9 zhub.sh
|
||||||
|
|
||||||
scp zhub.sh xhost:/opt/zhub
|
scp zhub.sh pro:/opt/zhub
|
||||||
scp zhub.sh zhost:/opt/zhub
|
scp zhub.sh dev:/opt/zhub
|
||||||
scp zhub.sh qhost:/opt/zhub
|
scp zhub.sh qc:/opt/zhub
|
||||||
scp zhub.sh nhost:/opt/zhub
|
scp zhub.sh my:/opt/zhub
|
||||||
del zhub.sh
|
del zhub.sh
|
||||||
|
|||||||
10
public/index.html
Normal file
10
public/index.html
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Title</title>
|
||||||
|
</head>
|
||||||
|
<body style="text-align: center;padding: 10px">
|
||||||
|
<h2>welcome zhub!</h2>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -2,6 +2,7 @@ package zsub
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
"log"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"zhub/conf"
|
"zhub/conf"
|
||||||
)
|
)
|
||||||
@@ -94,13 +95,28 @@ func msgAccept(v Message) {
|
|||||||
}
|
}
|
||||||
switch rcmd[1] {
|
switch rcmd[1] {
|
||||||
case "reload-timer":
|
case "reload-timer":
|
||||||
zsub.reloadTimer()
|
zsub.ReloadTimer()
|
||||||
case "shutdown":
|
case "shutdown":
|
||||||
if !strings.EqualFold(c.groupid, "group-admin") {
|
if !strings.EqualFold(c.groupid, "group-admin") {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
zsub.shutdown()
|
zsub.shutdown()
|
||||||
}
|
}
|
||||||
|
case "lock":
|
||||||
|
// lock key uuid 5
|
||||||
|
if len(rcmd) != 4 {
|
||||||
|
c.send("-Error: lock para number![" + strings.Join(rcmd, " ") + "]")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
d, _ := strconv.Atoi(rcmd[3])
|
||||||
|
zsub._lock(&Lock{key: rcmd[1], uuid: rcmd[2], duration: d})
|
||||||
|
case "unlock":
|
||||||
|
// unlock key uuid
|
||||||
|
if len(rcmd) != 3 {
|
||||||
|
c.send("-Error: unlock para number![" + strings.Join(rcmd, " ") + "]")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
zsub._unlock(Lock{key: rcmd[1], uuid: rcmd[2]})
|
||||||
default:
|
default:
|
||||||
c.send("-Error: default not supported:[" + strings.Join(rcmd, " ") + "]")
|
c.send("-Error: default not supported:[" + strings.Join(rcmd, " ") + "]")
|
||||||
return
|
return
|
||||||
|
|||||||
59
zsub/zdb.go
59
zsub/zdb.go
@@ -36,9 +36,10 @@ func Append(str string, fileName string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 数据持久化
|
// 数据持久化
|
||||||
func (s *ZSub) saveDelay() {
|
func (s *ZSub) dataStorage() {
|
||||||
s.Lock()
|
s.Lock()
|
||||||
defer s.Unlock()
|
defer s.Unlock()
|
||||||
|
// delay save
|
||||||
err := os.Remove(conf.DataDir + "/delay.z")
|
err := os.Remove(conf.DataDir + "/delay.z")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
@@ -49,9 +50,23 @@ func (s *ZSub) saveDelay() {
|
|||||||
str += fmt.Sprintf("%s %s %s\n", delay.topic, delay.value, strconv.FormatInt(delay.exectime.Unix(), 10))
|
str += fmt.Sprintf("%s %s %s\n", delay.topic, delay.value, strconv.FormatInt(delay.exectime.Unix(), 10))
|
||||||
}
|
}
|
||||||
Append(str, conf.DataDir+"/delay.z")
|
Append(str, conf.DataDir+"/delay.z")
|
||||||
|
|
||||||
|
// lock save
|
||||||
|
err = os.Remove(conf.DataDir + "/lock.z")
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
}
|
||||||
|
str = ""
|
||||||
|
for _, locks := range s.locks {
|
||||||
|
for _, lock := range locks {
|
||||||
|
str += fmt.Sprintf("%s %s %d %d\n", lock.key, lock.uuid, lock.duration, lock.start)
|
||||||
|
break // 只记录获得锁的记录
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Append(str, conf.DataDir+"/lock.z")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ZSub) reloadDelay() {
|
func (s *ZSub) loadDelay() {
|
||||||
f, err := os.Open(conf.DataDir + "/delay.z")
|
f, err := os.Open(conf.DataDir + "/delay.z")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
@@ -85,3 +100,43 @@ func (s *ZSub) reloadDelay() {
|
|||||||
s.delay([]string{"delay", split[0], split[1], strconv.FormatInt((exectime-time.Now().Unix())*1000, 10)}, nil)
|
s.delay([]string{"delay", split[0], split[1], strconv.FormatInt((exectime-time.Now().Unix())*1000, 10)}, nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *ZSub) loadLock() {
|
||||||
|
f, err := os.Open(conf.DataDir + "/lock.z")
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
r := bufio.NewReader(f)
|
||||||
|
for {
|
||||||
|
bytes, err := r.ReadBytes('\n')
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
line := string(bytes)
|
||||||
|
if len(line) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
line = strings.Trim(line, " \r\n")
|
||||||
|
split := strings.Split(line, " ")
|
||||||
|
if len(split) != 4 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
duration, err := strconv.Atoi(split[2])
|
||||||
|
start, err := strconv.ParseInt(split[3], 10, 64)
|
||||||
|
|
||||||
|
if start > 0 && time.Now().Unix()-start > 1 {
|
||||||
|
duration = int(time.Now().Unix() - start)
|
||||||
|
} else {
|
||||||
|
duration = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
s._lock(&Lock{
|
||||||
|
key: split[0],
|
||||||
|
uuid: split[1],
|
||||||
|
duration: duration,
|
||||||
|
// start: start,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
132
zsub/zsub.go
132
zsub/zsub.go
@@ -8,6 +8,7 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
"time"
|
||||||
"zhub/conf"
|
"zhub/conf"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -16,6 +17,7 @@ var (
|
|||||||
topics: make(map[string]*ZTopic),
|
topics: make(map[string]*ZTopic),
|
||||||
timers: make(map[string]*ZTimer),
|
timers: make(map[string]*ZTimer),
|
||||||
delays: make(map[string]*ZDelay),
|
delays: make(map[string]*ZDelay),
|
||||||
|
locks: make(map[string][]*Lock),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -24,6 +26,7 @@ type ZSub struct {
|
|||||||
topics map[string]*ZTopic
|
topics map[string]*ZTopic
|
||||||
timers map[string]*ZTimer
|
timers map[string]*ZTimer
|
||||||
delays map[string]*ZDelay
|
delays map[string]*ZDelay
|
||||||
|
locks map[string][]*Lock
|
||||||
}
|
}
|
||||||
|
|
||||||
type ZConn struct { //ZConn
|
type ZConn struct { //ZConn
|
||||||
@@ -36,6 +39,15 @@ type ZConn struct { //ZConn
|
|||||||
substoped map[string]chan int // 关闭信号量
|
substoped map[string]chan int // 关闭信号量
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Lock struct {
|
||||||
|
key string
|
||||||
|
uuid string
|
||||||
|
duration int
|
||||||
|
timer *time.Timer
|
||||||
|
start int64
|
||||||
|
//stop time.Time
|
||||||
|
}
|
||||||
|
|
||||||
func NewZConn(conn *net.Conn) *ZConn {
|
func NewZConn(conn *net.Conn) *ZConn {
|
||||||
return &ZConn{
|
return &ZConn{
|
||||||
conn: conn,
|
conn: conn,
|
||||||
@@ -60,7 +72,7 @@ func (c *ZConn) subscribe(topic string) { // 新增订阅 zconn{}
|
|||||||
ztopic = &ZTopic{
|
ztopic = &ZTopic{
|
||||||
groups: map[string]*ZGroup{},
|
groups: map[string]*ZGroup{},
|
||||||
topic: topic,
|
topic: topic,
|
||||||
chMsg: make(chan string, 10000),
|
chMsg: make(chan string, 500),
|
||||||
}
|
}
|
||||||
ztopic.init()
|
ztopic.init()
|
||||||
zsub.topics[topic] = ztopic
|
zsub.topics[topic] = ztopic
|
||||||
@@ -71,7 +83,7 @@ func (c *ZConn) subscribe(topic string) { // 新增订阅 zconn{}
|
|||||||
zgroup = &ZGroup{
|
zgroup = &ZGroup{
|
||||||
//conns: []*ZConn{},
|
//conns: []*ZConn{},
|
||||||
ztopic: ztopic,
|
ztopic: ztopic,
|
||||||
chMsg: make(chan string, 1000),
|
chMsg: make(chan string, 500),
|
||||||
}
|
}
|
||||||
ztopic.groups[c.groupid] = zgroup
|
ztopic.groups[c.groupid] = zgroup
|
||||||
}
|
}
|
||||||
@@ -187,8 +199,9 @@ func ServerStart(addr string) {
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
// 重新加载[定时、延时]
|
// 重新加载[定时、延时]
|
||||||
go zsub.reloadTimer()
|
go zsub.ReloadTimer()
|
||||||
go zsub.reloadDelay()
|
go zsub.loadDelay()
|
||||||
|
//go zsub.loadLock()
|
||||||
|
|
||||||
// 启动服务监听
|
// 启动服务监听
|
||||||
listen, err := net.Listen("tcp", addr)
|
listen, err := net.Listen("tcp", addr)
|
||||||
@@ -237,8 +250,15 @@ func (s *ZSub) acceptHandler(c *ZConn) {
|
|||||||
n, _ := strconv.Atoi(string(line[1:]))
|
n, _ := strconv.Atoi(string(line[1:]))
|
||||||
for i := 0; i < n; i++ {
|
for i := 0; i < n; i++ {
|
||||||
reader.ReadLine()
|
reader.ReadLine()
|
||||||
v, _, _ := reader.ReadLine()
|
var vx = ""
|
||||||
rcmd = append(rcmd, string(v))
|
a:
|
||||||
|
if v, prefix, _ := reader.ReadLine(); prefix {
|
||||||
|
vx += string(v)
|
||||||
|
goto a
|
||||||
|
} else {
|
||||||
|
vx += string(v)
|
||||||
|
}
|
||||||
|
rcmd = append(rcmd, vx)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
rcmd = append(rcmd, string(line))
|
rcmd = append(rcmd, string(line))
|
||||||
@@ -253,9 +273,9 @@ func (s *ZSub) acceptHandler(c *ZConn) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
accept topic message
|
accept stop message
|
||||||
1、send message to topic's chan
|
1、send message to stop's chan
|
||||||
2、feedback send success to sender, and sending message to topic's subscripts
|
2、feedback send success to sender, and sending message to stop's subscripts
|
||||||
*/
|
*/
|
||||||
func (s *ZSub) publish(topic, msg string) {
|
func (s *ZSub) publish(topic, msg string) {
|
||||||
s.RLock()
|
s.RLock()
|
||||||
@@ -274,6 +294,9 @@ send broadcast message
|
|||||||
func (s *ZSub) broadcast(topic, msg string) {
|
func (s *ZSub) broadcast(topic, msg string) {
|
||||||
s.RLock()
|
s.RLock()
|
||||||
defer s.RUnlock()
|
defer s.RUnlock()
|
||||||
|
if strings.EqualFold(topic, "lock") {
|
||||||
|
log.Println("lock", msg)
|
||||||
|
}
|
||||||
|
|
||||||
ztopic := s.topics[topic] //ZTopic
|
ztopic := s.topics[topic] //ZTopic
|
||||||
if ztopic == nil {
|
if ztopic == nil {
|
||||||
@@ -287,8 +310,95 @@ func (s *ZSub) broadcast(topic, msg string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
lock: lock key uuid t
|
||||||
|
unlock: unlock key uuid
|
||||||
|
*/
|
||||||
|
func (s *ZSub) _lock(lock *Lock) {
|
||||||
|
locks := s.locks[lock.key]
|
||||||
|
if locks == nil {
|
||||||
|
locks = make([]*Lock, 0)
|
||||||
|
}
|
||||||
|
if len(locks) == 0 { // lock success
|
||||||
|
lock.start = time.Now().Unix()
|
||||||
|
locks = append(locks, lock)
|
||||||
|
s.locks[lock.key] = locks
|
||||||
|
s.broadcast("lock", lock.uuid)
|
||||||
|
|
||||||
|
// 设置时间到解锁
|
||||||
|
locks[0].timer = time.NewTimer(time.Duration(locks[0].duration) * time.Second)
|
||||||
|
go func() {
|
||||||
|
select {
|
||||||
|
case <-locks[0].timer.C:
|
||||||
|
s._unlock(*locks[0])
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
} else {
|
||||||
|
s.locks[lock.key] = append(locks, lock)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func (s *ZSub) _unlock(l Lock) {
|
||||||
|
locks := s.locks[l.key]
|
||||||
|
if locks == nil || len(locks) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if strings.EqualFold(locks[0].uuid, l.uuid) {
|
||||||
|
locks[0].timer.Stop()
|
||||||
|
locks = locks[1:]
|
||||||
|
s.locks[l.key] = locks
|
||||||
|
}
|
||||||
|
if len(s.locks[l.key]) > 0 { // next lock
|
||||||
|
s.broadcast("lock", s.locks[l.key][0].uuid)
|
||||||
|
s.locks[l.key][0].start = time.Now().Unix()
|
||||||
|
s.locks[l.key][0].timer = time.NewTimer(time.Duration(s.locks[l.key][0].duration) * time.Second)
|
||||||
|
go func() {
|
||||||
|
select {
|
||||||
|
case <-s.locks[l.key][0].timer.C:
|
||||||
|
s._unlock(*s.locks[l.key][0])
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (s *ZSub) shutdown() {
|
func (s *ZSub) shutdown() {
|
||||||
s.saveDelay()
|
s.dataStorage()
|
||||||
s.Lock()
|
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Info() map[string]interface{} {
|
||||||
|
m := map[string]interface{}{}
|
||||||
|
|
||||||
|
for s, topic := range zsub.topics {
|
||||||
|
// {groups:[{name:xxx,size:xx}]}
|
||||||
|
arr := make([]map[string]interface{}, 0)
|
||||||
|
|
||||||
|
for groupname, group := range topic.groups {
|
||||||
|
arr = append(arr, map[string]interface{}{
|
||||||
|
"name": groupname,
|
||||||
|
"subsize": len(group.conns),
|
||||||
|
"offset": group.offset,
|
||||||
|
"mcount": topic.mcount,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
m[s] = arr
|
||||||
|
}
|
||||||
|
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ZSub) Clearup() {
|
||||||
|
for tn, topic := range s.topics {
|
||||||
|
for _, group := range topic.groups {
|
||||||
|
if len(group.conns) > 0 || topic.mcount > group.offset {
|
||||||
|
goto a
|
||||||
|
}
|
||||||
|
}
|
||||||
|
close(topic.chMsg)
|
||||||
|
delete(s.topics, tn)
|
||||||
|
a:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ZSubx() *ZSub {
|
||||||
|
return zsub
|
||||||
|
}
|
||||||
|
|||||||
@@ -165,7 +165,7 @@ func executeShell(command string) (string, error, string) {
|
|||||||
return stdout.String(), err, stderr.String()
|
return stdout.String(), err, stderr.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ZSub) reloadTimer() {
|
func (s *ZSub) ReloadTimer() {
|
||||||
db, err := sql.Open("mysql", fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8",
|
db, err := sql.Open("mysql", fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8",
|
||||||
conf.GetStr("ztimer.db.user", "root"),
|
conf.GetStr("ztimer.db.user", "root"),
|
||||||
conf.GetStr("ztimer.db.pwd", "123456"),
|
conf.GetStr("ztimer.db.pwd", "123456"),
|
||||||
@@ -207,7 +207,7 @@ func (s *ZSub) delay(rcmd []string, c *ZConn) {
|
|||||||
s.Lock()
|
s.Lock()
|
||||||
defer func() {
|
defer func() {
|
||||||
s.Unlock()
|
s.Unlock()
|
||||||
s.saveDelay()
|
s.dataStorage()
|
||||||
}()
|
}()
|
||||||
if len(rcmd) != 4 {
|
if len(rcmd) != 4 {
|
||||||
c.send("-Error: subscribe para number!")
|
c.send("-Error: subscribe para number!")
|
||||||
@@ -222,7 +222,7 @@ func (s *ZSub) delay(rcmd []string, c *ZConn) {
|
|||||||
|
|
||||||
delay := s.delays[rcmd[1]+"-"+rcmd[2]]
|
delay := s.delays[rcmd[1]+"-"+rcmd[2]]
|
||||||
if delay != nil {
|
if delay != nil {
|
||||||
if t == -1 {
|
if t < 0 {
|
||||||
delay.timer.Stop()
|
delay.timer.Stop()
|
||||||
delete(s.delays, rcmd[1]+"-"+rcmd[2])
|
delete(s.delays, rcmd[1]+"-"+rcmd[2])
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import "sync"
|
|||||||
type ZTopic struct { //ZTopic
|
type ZTopic struct { //ZTopic
|
||||||
sync.Mutex
|
sync.Mutex
|
||||||
groups map[string]*ZGroup
|
groups map[string]*ZGroup
|
||||||
mcount int
|
mcount int32
|
||||||
topic string // 主题名称
|
topic string // 主题名称
|
||||||
chMsg chan string // 主题消息投递
|
chMsg chan string // 主题消息投递
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user