wip: 0.2.5

还未实现 rtc 握手
This commit is contained in:
loveuer
2025-05-23 18:01:16 +08:00
parent 013670b78f
commit b8645a68ed
4 changed files with 158 additions and 226 deletions

View File

@ -25,7 +25,6 @@ func Start(ctx context.Context) <-chan struct{} {
{
api := app.Group("/api/ulocal")
api.Post("/register", handler.LocalRegister())
api.Post("/offer", handler.LocalOffer())
api.Post("/answer", handler.LocalAnswer())
api.Get("/clients", handler.LocalClients())

View File

@ -55,12 +55,9 @@ type roomClient struct {
ClientType RoomClientType `json:"client_type"`
AppType RoomAppType `json:"app_type"`
IP string `json:"ip"`
Room string `json:"room"`
Name string `json:"name"`
Id string `json:"id"`
RegisterAt time.Time `json:"register_at"`
Offer *RoomOffer `json:"offer"`
Candidate *RoomCandidate `json:"candidate"`
msgChan chan any
}
@ -130,42 +127,25 @@ func (rc *roomClient) start(ctx context.Context) {
type roomController struct {
sync.Mutex
ctx context.Context
rooms map[string]map[string]*roomClient // map[room_id(remote-IP)][Id]
notReadies map[string]*roomClient
ctx context.Context
//rooms map[string]map[string]*roomClient // map[room_id(remote-IP)][Id]
clients map[string]*roomClient
}
var (
RoomController = &roomController{
rooms: make(map[string]map[string]*roomClient),
notReadies: make(map[string]*roomClient),
clients: make(map[string]*roomClient),
}
)
func (rc *roomController) Start(ctx context.Context) {
rc.ctx = ctx
go func() {
ticker := time.NewTicker(1 * time.Minute)
for {
select {
case <-rc.ctx.Done():
return
case now := <-ticker.C:
for _, nrc := range rc.notReadies {
if now.Sub(nrc.RegisterAt).Minutes() > 1 {
rc.Lock()
delete(rc.notReadies, nrc.Id)
rc.Unlock()
}
}
}
}
}()
}
func (rc *roomController) Register(ip, userAgent string, candidate *RoomCandidate, offer *RoomOffer) *roomClient {
func (rc *roomController) Register(conn *websocket.Conn, ip, userAgent string) *roomClient {
nrc := &roomClient{
controller: rc,
conn: conn,
ClientType: ClientTypeDesktop,
AppType: RoomAppTypeWeb,
IP: ip,
@ -173,8 +153,6 @@ func (rc *roomController) Register(ip, userAgent string, candidate *RoomCandidat
Name: tool.RandomName(),
msgChan: make(chan any, 1),
RegisterAt: time.Now(),
Candidate: candidate,
Offer: offer,
}
ua := useragent.Parse(userAgent)
@ -185,121 +163,71 @@ func (rc *roomController) Register(ip, userAgent string, candidate *RoomCandidat
nrc.ClientType = ClientTypeTablet
}
key := "local"
if !tool.IsPrivateIP(ip) {
key = ip
}
log.Debug("controller.room: registry client, IP = %s, Id = %s, Name = %s", nrc.IP, nrc.Id, nrc.Name)
nrc.Room = key
nrc.start(rc.ctx)
nrc.msgChan <- map[string]any{"type": "register", "time": time.Now().UnixMilli(), "body": nrc}
rc.Broadcast(map[string]any{"type": "enter", "time": time.Now().UnixMilli(), "body": nrc})
rc.Lock()
log.Debug("controller.room: registry client, IP = %s(%s), Id = %s, Name = %s", key, nrc.IP, nrc.Id, nrc.Name)
rc.notReadies[nrc.Id] = nrc
if _, ok := rc.rooms[nrc.Room]; !ok {
rc.rooms[nrc.Room] = make(map[string]*roomClient)
}
rc.clients[nrc.Id] = nrc
rc.Unlock()
return nrc
}
func (rc *roomController) Enter(conn *websocket.Conn, id string) {
client, ok := rc.notReadies[id]
if !ok {
log.Warn("controller.room: entry room id not exist, id = %s", id)
return
}
rc.Lock()
if _, ok = rc.rooms[client.Room]; !ok {
log.Warn("controller.room: entry room not exist, room = %s, id = %s, name = %s", client.Room, id, client.Name)
return
}
rc.rooms[client.Room][id] = client
client.conn = conn
rc.Unlock()
client.start(rc.ctx)
rc.Broadcast(client.Room, map[string]any{"type": RoomMessageTypeEnter, "time": time.Now().UnixMilli(), "body": client})
}
func (rc *roomController) List(room string) []*roomClient {
log.Debug("controller.room: list room = %s", room)
func (rc *roomController) List() []*roomClient {
clientList := make([]*roomClient, 0)
clients, ok := rc.rooms[room]
if !ok {
return clientList
}
for _, client := range clients {
for _, client := range rc.clients {
clientList = append(clientList, client)
}
return clientList
}
func (rc *roomController) Broadcast(room string, msg any) {
for _, client := range rc.rooms[room] {
func (rc *roomController) Broadcast(msg any) {
for _, client := range rc.clients {
select {
case client.msgChan <- msg:
case <-time.After(2 * time.Second):
log.Warn("RoomController: broadcast timeout, room = %s, client Id = %s, IP = %s", room, client.Id, client.IP)
log.Warn("RoomController: broadcast timeout, client Id = %s, IP = %s", client.Id, client.IP)
}
}
}
func (rc *roomController) Unregister(client *roomClient) {
key := "local"
if !tool.IsPrivateIP(client.IP) {
key = client.IP
}
log.Debug("controller.room: unregister client, IP = %s(%s), Id = %s, Name = %s", client.IP, key, client.Id, client.Name)
log.Debug("controller.room: unregister client, IP = %s, Id = %s, Name = %s", client.IP, client.Id, client.Name)
rc.Lock()
delete(rc.rooms[key], client.Id)
delete(rc.clients, client.Id)
rc.Unlock()
rc.Broadcast(key, map[string]any{"type": RoomMessageTypeLeave, "time": time.Now().UnixMilli(), "body": client})
rc.Broadcast(map[string]any{"type": RoomMessageTypeLeave, "time": time.Now().UnixMilli(), "body": client})
}
func (rc *roomController) Offer(room, id string, offer *RoomOffer) {
if _, ok := rc.rooms[room]; !ok {
func (rc *roomController) Offer(id string, offer *RoomOffer, candidate *RoomCandidate) {
if _, ok := rc.clients[id]; !ok {
return
}
if _, ok := rc.rooms[room][id]; !ok {
return
}
rc.rooms[room][id].msgChan <- map[string]any{
"type": "offer",
"id": id,
"room": room,
"offer": offer,
rc.clients[id].msgChan <- map[string]any{
"type": "offer",
"id": id,
"offer": offer,
"candidate": candidate,
}
}
func (rc *roomController) Answer(room, id string, answer *RoomOffer) {
if _, ok := rc.rooms[room]; !ok {
func (rc *roomController) Answer(id string, answer *RoomOffer) {
if _, ok := rc.clients[id]; !ok {
return
}
if _, ok := rc.rooms[room][id]; !ok {
return
}
rc.rooms[room][id].msgChan <- map[string]any{
rc.clients[id].msgChan <- map[string]any{
"type": "answer",
"id": id,
"room": room,
"answer": answer,
}
}

View File

@ -9,38 +9,9 @@ import (
"net/http"
)
func LocalRegister() nf.HandlerFunc {
return func(c *nf.Ctx) error {
type Req struct {
Candidate *controller.RoomCandidate `json:"candidate"`
Offer *controller.RoomOffer `json:"offer"`
}
var (
err error
req = new(Req)
ip = c.IP(true)
ua = c.Get("User-Agent")
)
if err = c.BodyParser(req); err != nil {
return c.Status(http.StatusBadRequest).JSON(map[string]interface{}{"msg": err.Error()})
}
client := controller.RoomController.Register(ip, ua, req.Candidate, req.Offer)
return resp.Resp200(c, client)
}
}
func LocalClients() nf.HandlerFunc {
return func(c *nf.Ctx) error {
room := c.Query("room")
if room == "" {
return c.Status(http.StatusBadRequest).JSON(map[string]string{"err": "room can't be empty"})
}
list := controller.RoomController.List(room)
list := controller.RoomController.List()
return resp.Resp200(c, list)
}
@ -56,12 +27,10 @@ func LocalWS() nf.HandlerFunc {
}
return func(c *nf.Ctx) error {
id := c.Query("id")
if id == "" {
return c.Status(http.StatusBadRequest).JSON(map[string]string{"error": "id is empty"})
}
var (
ip = c.IP(true)
ua = c.Get("User-Agent")
)
conn, err := upgrader.Upgrade(c.Writer, c.Request, nil)
if err != nil {
@ -69,7 +38,7 @@ func LocalWS() nf.HandlerFunc {
return err
}
controller.RoomController.Enter(conn, id)
controller.RoomController.Register(conn, ip, ua)
return nil
}
@ -78,9 +47,9 @@ func LocalWS() nf.HandlerFunc {
func LocalOffer() nf.HandlerFunc {
return func(c *nf.Ctx) error {
type Req struct {
Room string `json:"room"`
Id string `json:"id"`
Offer *controller.RoomOffer `json:"offer"`
Id string `json:"id"`
Offer *controller.RoomOffer `json:"offer"`
Candidate *controller.RoomCandidate `json:"candidate"`
}
var (
@ -92,7 +61,7 @@ func LocalOffer() nf.HandlerFunc {
return c.Status(http.StatusBadRequest).JSON(map[string]string{"err": err.Error()})
}
controller.RoomController.Offer(req.Room, req.Id, req.Offer)
controller.RoomController.Offer(req.Id, req.Offer, req.Candidate)
return resp.Resp200(c, req.Offer)
}
@ -101,7 +70,6 @@ func LocalOffer() nf.HandlerFunc {
func LocalAnswer() nf.HandlerFunc {
return func(c *nf.Ctx) error {
type Req struct {
Room string `json:"room"`
Id string `json:"id"`
Answer *controller.RoomOffer `json:"answer"`
}
@ -115,7 +83,7 @@ func LocalAnswer() nf.HandlerFunc {
return c.Status(http.StatusBadRequest).JSON(map[string]string{"err": err.Error()})
}
controller.RoomController.Answer(req.Room, req.Id, req.Answer)
controller.RoomController.Answer(req.Id, req.Answer)
return resp.Resp200(c, req)
}