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
2023-08-05 19:54: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" `
}
2023-08-05 19:54:11 +00:00
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. 定义结构体
2023-08-05 19:54:11 +00:00
item := QueueItem { }
2023-08-03 10:34:20 +00:00
// 3. 解析JSON到结构体
2023-08-05 19:54:11 +00:00
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 )
2023-08-05 19:54:11 +00:00
}
type StateClient struct {
nh * dragonboat . NodeHost
2023-08-03 10:34:20 +00:00
}
2023-08-05 19:54:11 +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 )
2023-08-05 19:54:11 +00:00
_ , 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
}