fusen-render/websocket.go

239 lines
5.2 KiB
Go
Raw Normal View History

2023-08-03 10:34:20 +00:00
package fusenrender
import (
"context"
"encoding/json"
"fmt"
"io"
"log"
"net/http"
2023-11-14 03:41:12 +00:00
"sync"
2023-08-03 10:34:20 +00:00
"time"
2023-11-14 03:41:12 +00:00
"github.com/474420502/execute/triggered"
2023-08-03 10:34:20 +00:00
"github.com/gorilla/websocket"
"github.com/lni/dragonboat/v4"
2023-08-05 20:26:57 +00:00
"github.com/lni/dragonboat/v4/client"
2023-08-03 10:34:20 +00:00
)
2023-11-13 13:17:13 +00:00
var PopChannel chan *QueueItem = make(chan *QueueItem, 100) // chan *QueueItem = make(chan *QueueItem, 1)
2023-08-03 10:34:20 +00:00
var upgrader = websocket.Upgrader{
2023-11-13 13:23:50 +00:00
ReadBufferSize: 10240,
WriteBufferSize: 10240,
2023-08-03 10:34:20 +00:00
}
2023-08-05 20:26:57 +00:00
func HttpListen(ns *dragonboat.NodeHost, port int) {
2023-08-16 03:42:49 +00:00
// http.HandleFunc("/api/render/render_notify", callbackHandler)
http.HandleFunc("/api/render/queue/push", pushRenderTaskHandler)
http.HandleFunc("/api/ws/render/queue/pop", queueHandler)
2023-08-09 06:15:11 +00:00
log.Printf(":%d", port)
http.ListenAndServe(fmt.Sprintf(":%d", port), nil)
}
2023-11-14 03:41:12 +00:00
type CountPutPop struct {
PutCount uint64
PopCount uint64
SelfCount map[string]uint64
mu sync.Mutex
}
func (pp *CountPutPop) Use(do func(item *CountPutPop)) {
pp.mu.Lock()
defer pp.mu.Unlock()
do(pp)
}
2023-11-13 13:28:07 +00:00
2023-11-14 03:41:12 +00:00
var countPutPop *CountPutPop = &CountPutPop{
SelfCount: map[string]uint64{},
}
var logIntervalTimeHandler = triggered.RegisterExecute[*CountPutPop](func(params *triggered.Params[*CountPutPop]) {
params.Value.Use(func(item *CountPutPop) {
2023-11-14 03:45:46 +00:00
log.Printf("all pop count: %d all put count: %d\n", item.PutCount, item.PopCount)
2023-11-14 03:41:12 +00:00
for k, v := range item.SelfCount {
2023-11-14 03:45:46 +00:00
log.Printf("uinty3d[%s] pop count: %d\n", k, v)
2023-11-14 03:41:12 +00:00
}
})
time.Sleep(time.Second * 15)
})
func queueHandler(w http.ResponseWriter, r *http.Request) {
2023-11-13 13:28:07 +00:00
2023-08-03 10:34:20 +00:00
var err error
2023-08-04 10:59:53 +00:00
conn, err := upgrader.Upgrade(w, r, nil)
if err != nil {
log.Println(err)
return
}
defer conn.Close()
2023-09-08 03:21:38 +00:00
raddr := conn.RemoteAddr()
2023-09-08 03:41:16 +00:00
// laddr := conn.LocalAddr()
2023-10-07 06:02:59 +00:00
log.Printf("%s 建立连接 当前unity处理机器数量 %d\n", raddr, DequeueHandler.RefCountAdd(1))
2023-08-04 10:59:53 +00:00
defer func() {
2023-10-07 06:02:59 +00:00
log.Printf("%s 退出连接 当前unity处理机器数量 %d\n", raddr, DequeueHandler.RefCountAdd(-1))
2023-08-04 10:59:53 +00:00
}()
2023-11-14 03:41:12 +00:00
countPutPop.Use(func(item *CountPutPop) {
item.SelfCount[raddr.String()] = 0
})
2023-08-03 10:34:20 +00:00
for {
2023-08-07 11:03:22 +00:00
item := <-PopChannel
2023-10-07 06:02:59 +00:00
2023-08-07 11:03:22 +00:00
if item == nil {
continue
}
2023-08-03 10:34:20 +00:00
2023-08-16 05:13:45 +00:00
var wdata []byte
switch data := item.Data.(type) {
case string:
wdata = []byte(data)
case []byte:
wdata = data
default:
wdata, err = json.Marshal(data)
if err != nil {
log.Println(err)
continue
}
}
2023-11-14 03:41:12 +00:00
err = conn.SetWriteDeadline(time.Now().Add(time.Second * 3))
2023-08-16 08:20:20 +00:00
if err != nil {
log.Println(err)
log.Println("重新回队")
stateClient.PushItem(nil, item)
return
}
2023-08-03 10:34:20 +00:00
// 写回消息
2023-08-16 05:13:45 +00:00
err = conn.WriteMessage(websocket.BinaryMessage, wdata)
2023-08-03 10:34:20 +00:00
if err != nil {
2023-08-04 10:59:53 +00:00
log.Println(err)
log.Println("重新回队")
2023-08-07 11:03:22 +00:00
stateClient.PushItem(nil, item)
2023-08-03 10:34:20 +00:00
return
}
2023-11-14 02:50:56 +00:00
2023-11-14 03:54:14 +00:00
countPutPop.Use(func(citem *CountPutPop) {
citem.PopCount++
citem.SelfCount[raddr.String()]++
log.Printf("all put %d, all pop %d source[%s] -> self[%s] pop %d\n", citem.PutCount, citem.PopCount, item.Source, raddr.String(), citem.SelfCount[raddr.String()])
2023-11-14 03:41:12 +00:00
})
logIntervalTimeHandler.Notify(countPutPop)
2023-08-03 10:34:20 +00:00
// 打印消息
2023-10-07 04:25:12 +00:00
log.Printf("source: [%s] 数据 推送到unity [%s]\n", item.Source, raddr.String())
2023-08-03 10:34:20 +00:00
}
}
2023-08-09 06:15:11 +00:00
type Form struct {
UserID int `json:"user_id"`
GuestID int `json:"guest_id"`
APIType int `json:"api_type"`
UploadBucket int `json:"upload_bucket"`
FileKey string `json:"file_key"`
FileData []byte `json:"file_data"`
MetaData string `json:"meta_data"`
}
// RequestCallback结构体
type RequestCallback struct {
Sign string `json:"sign"`
Time int64 `json:"time"`
Info Info `json:"info"`
}
// Info结构体
type Info struct {
TaskID string `json:"task_id"`
Image string `json:"image"`
}
func pushRenderTaskHandler(w http.ResponseWriter, r *http.Request) {
2023-08-03 10:34:20 +00:00
// 1. 读取Body内容
body, err := io.ReadAll(r.Body)
if err != nil {
panic(err)
}
// 2. 定义结构体
item := QueueItem{}
2023-08-03 10:34:20 +00:00
// 3. 解析JSON到结构体
err = json.Unmarshal(body, &item)
2023-08-03 10:34:20 +00:00
if err != nil {
panic(err)
}
2023-08-04 10:59:53 +00:00
2023-08-05 20:26:57 +00:00
stateClient.PushItem(nil, &item)
}
type StateClient struct {
nh *dragonboat.NodeHost
2023-08-03 10:34:20 +00:00
}
var stateClient *StateClient
2023-08-03 10:34:20 +00:00
2023-08-05 20:26:57 +00:00
func (cli *StateClient) GetNoOPSession() *client.Session {
return cli.nh.GetNoOPSession(shardID)
}
func (cli *StateClient) PushItem(cs *client.Session, item *QueueItem) {
if cs == nil {
cs = cli.GetNoOPSession()
}
2023-08-16 03:42:49 +00:00
cmd := &CmdEnqueue{Command: Command{Group: "unity3d"}}
2023-08-03 10:34:20 +00:00
cmd.Item = item
data, err := FsPasser.PackToBytes(cmd)
if err != nil {
log.Println(err)
}
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
_, err = cli.nh.SyncPropose(ctx, cs, data)
2023-08-03 10:34:20 +00:00
if err != nil {
log.Println(err)
}
// log.Println("enqueue", len(result.Data))
cancel()
}
2023-08-05 20:26:57 +00:00
func (cli *StateClient) PopItem(cs *client.Session, group string) (*QueueItem, error) {
if cs == nil {
cs = cli.GetNoOPSession()
}
2023-08-16 03:42:49 +00:00
cmd := &CmdDequeue{Command{Group: "unity3d"}}
2023-08-05 20:26:57 +00:00
data, err := FsPasser.PackToBytes(cmd)
if err != nil {
log.Println(err)
}
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
result, err := cli.nh.SyncPropose(ctx, cs, data)
cancel()
if err != nil {
return nil, err
}
if len(result.Data) == 0 {
return nil, nil
}
var item QueueItem
err = item.Decode(result.Data)
if err != nil {
log.Println(err)
}
return &item, nil
}