fusenapi/fsm/main.go
2023-07-25 19:32:51 +08:00

158 lines
3.0 KiB
Go

package fsm
import (
"bytes"
"encoding/gob"
"fmt"
"fusenapi/initalize"
"log"
"net"
"os"
"time"
"github.com/hashicorp/raft"
"gorm.io/gorm"
)
func test1() {
log.SetFlags(log.Llongfile)
fsm := StartNode("fs1", "localhost:5500", initalize.InitMysql("fusentest:XErSYmLELKMnf3Dh@tcp(110.41.19.98:3306)/fusentest"))
time.Sleep(time.Second * 5)
for i := 0; i < 30; i++ {
go log.Println(fsm.GetUserState(39))
}
log.Println(fsm.GetUserState(39))
select {}
}
// StartNode 启动节点
func StartNode(ServerID string, RaftBind string, gdb *gorm.DB) *StateCluster {
fsm := &StateCluster{
store: make(map[int64]*UserState),
waiter: NewWaitCallback(),
gdb: gdb,
}
var retainSnapshotCount = 2
// var ServerID string = "fs1"
// var RaftBind string = "localhost:5500"
var RaftDir string = fmt.Sprintf("/tmp/raftdir/%s", ServerID)
// Setup Raft configuration.
config := raft.DefaultConfig()
config.LocalID = raft.ServerID(ServerID)
// Setup Raft communication.
addr, err := net.ResolveTCPAddr("tcp", RaftBind)
if err != nil {
panic(err)
}
transport, err := raft.NewTCPTransport(RaftBind, addr, 3, 30*time.Second, os.Stderr)
if err != nil {
panic(err)
}
// Create the snapshot store. This allows the Raft to truncate the log.
snapshots, err := raft.NewFileSnapshotStore(RaftDir, retainSnapshotCount, os.Stderr)
if err != nil {
panic(fmt.Errorf("file snapshot store: %s", err))
}
// Create the log store and stable store.
logStore := raft.NewInmemStore()
stableStore := raft.NewInmemStore()
// Create the Raft system.
fsm.ra, err = raft.NewRaft(config, fsm, logStore, stableStore, snapshots, transport)
if err != nil {
panic(err)
}
configuration := raft.Configuration{
Servers: []raft.Server{
{
Suffrage: raft.Voter,
ID: config.LocalID,
Address: transport.LocalAddr(),
},
},
}
fu := fsm.ra.BootstrapCluster(configuration)
if err := fu.Error(); err != nil {
log.Println(err)
}
waitForLeader(fsm.ra)
return fsm
}
func waitForLeader(ra *raft.Raft) {
leaderCh := ra.LeaderCh()
for {
select {
case isLeader := <-leaderCh:
if isLeader {
return
}
case <-time.After(10 * time.Second):
log.Println("Still waiting for the leader...")
}
}
}
// var gdb *gorm.DB = initalize.InitMysql("fusentest:XErSYmLELKMnf3Dh@tcp(110.41.19.98:3306)/fusentest")
type UserState struct {
Expired time.Time
UserId int64
PwdHash uint64
}
func (us *UserState) Encode() []byte {
var buf = bytes.NewBuffer(nil)
err := gob.NewEncoder(buf).Encode(us)
if err != nil {
log.Panic(err)
return nil
}
return buf.Bytes()
}
// command is used for internal command representation.
type command struct {
Op string
Key int64
Value *UserState
}
func (cmd *command) Encode() []byte {
var buf = bytes.NewBuffer(nil)
err := gob.NewEncoder(buf).Encode(cmd)
if err != nil {
log.Panic(err)
return nil
}
return buf.Bytes()
}
func (cmd *command) Decode(sbuf []byte) error {
var buf = bytes.NewBuffer(sbuf)
err := gob.NewDecoder(buf).Decode(cmd)
if err != nil {
// log.Panic(err)
return err
}
return nil
}