animated-sniffle/app/worker.go

285 lines
6.3 KiB
Go
Raw Normal View History

2022-07-27 11:28:07 +03:00
package main
import (
"fmt"
"github.com/gorilla/websocket"
jsoniter "github.com/json-iterator/go"
"net/http"
"net/url"
"strings"
"time"
//"bytes"
)
var uptime = time.Now().Unix()
type AuthResponse struct {
Status string `json:"status"`
LocalData struct {
DataKey string `json:"dataKey"`
} `json:"localData"`
UserData struct {
Username string `json:"username"`
DisplayName string `json:"displayName"`
Location string `json:"location"`
Chathost string `json:"chathost"`
IsRu bool `json:"isRu"`
} `json:"userData"`
}
type ServerResponse struct {
TS int64 `json:"ts"`
Type string `json:"type"`
Body jsoniter.RawMessage `json:"body"`
}
type DonateResponse struct {
F struct {
Username string `json:"username"`
} `json:"f"`
A int64 `json:"a"`
}
type AnnounceCount struct {
Count int `json:"count"`
}
type AnnounceDonate struct {
Room string `json:"room"`
Donator string `json:"donator"`
Amount int64 `json:"amount"`
}
func mapRooms() {
data := make(map[string]*Info)
for {
select {
case m := <-rooms.Add:
data[m.room] = &Info{Server: m.Server, Proxy: m.Proxy, Start: m.Start, Last: m.Last, Income: m.Income}
case s := <-rooms.Json:
j, err := json.Marshal(data)
if err == nil {
s = string(j)
}
rooms.Json <- s
case <-rooms.Count:
rooms.Count <- len(data)
case key := <-rooms.Del:
delete(data, key)
removeRoom(key)
}
}
}
func announceCount() {
for {
time.Sleep(30 * time.Second)
rooms.Count <- 0
l := <-rooms.Count
msg, err := json.Marshal(AnnounceCount{Count: l})
if err == nil {
hub.broadcast <- msg
}
}
}
func getAMF(room string) (bool, *AuthResponse) {
v := &AuthResponse{}
req, err := http.NewRequest(http.MethodPost, "https://rt.bongocams.com/tools/amf.php?res=771840&t=1654437233142", strings.NewReader(`method=getRoomData&args[]=`+room))
if err != nil {
fmt.Println(err.Error())
return false, v
}
req.Header.Add("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8")
req.Header.Add("X-Requested-With", "XMLHttpRequest")
req.Header.Add("Accept", "application/json")
req.Header.Add("Referrer", "https://bongacams.com")
req.Header.Add("User-agent", "curl/7.79.1")
rsp, err := http.DefaultClient.Do(req)
if err != nil {
fmt.Println(err.Error())
return false, v
}
defer rsp.Body.Close()
if err = json.NewDecoder(rsp.Body).Decode(v); err != nil {
fmt.Println(err.Error())
return false, v
}
return true, v
}
func statRoom(chQuit chan struct{}, room, server, proxy string, info *tID, u url.URL) {
//fmt.Println("Start", room, "server", server, "proxy", proxy)
ok, v := getAMF(room)
if !ok {
fmt.Println("exit: no amf parms")
return
}
Dialer := *websocket.DefaultDialer
if _, ok := conf.Proxy[proxy]; ok {
Dialer = websocket.Dialer{
Proxy: http.ProxyURL(&url.URL{
Scheme: "http", // or "https" depending on your proxy
Host: conf.Proxy[proxy],
Path: "/",
}),
HandshakeTimeout: 45 * time.Second, // https://pkg.go.dev/github.com/gorilla/websocket
}
}
now := time.Now().Unix()
workerData := Info{room, server, proxy, now, now, 0}
rooms.Add <- workerData
defer func() {
fmt.Println("defer remove map", room)
rooms.Del <- room
}()
c, _, err := Dialer.Dial(u.String(), nil)
if err != nil {
fmt.Println(err.Error(), room)
return
}
defer func() {
fmt.Println("defer close", room)
c.Close()
}()
c.SetReadDeadline(time.Now().Add(60 * time.Second))
fmt.Println("send first", room)
if err = c.WriteMessage(websocket.TextMessage, []byte(fmt.Sprintf(`{"id":%d,"name":"joinRoom","args":["%s",{"username":"%s","displayName":"%s","location":"%s","chathost":"%s","isRu":%t,"isPerformer":false,"hasStream":false,"isLogged":false,"isPayable":false,"showType":"public"},"%s"]}`, 1, v.UserData.Chathost, v.UserData.Username, v.UserData.DisplayName, v.UserData.Location, v.UserData.Chathost, v.UserData.IsRu, v.LocalData.DataKey))); err != nil {
fmt.Println(err.Error())
return
}
fmt.Println("read first", room)
_, message, err := c.ReadMessage()
if err != nil {
fmt.Println(err.Error(), room)
return
}
fmt.Println(room, len(string(message)), string(message))
slog <- saveLog{info.Id, now, string(message)}
if string(message) == `{"id":1,"result":{"audioAvailable":false,"freeShow":false},"error":null}` {
fmt.Println("room offline, exit", room)
return
}
fmt.Println("send second", room)
if err = c.WriteMessage(websocket.TextMessage, []byte(fmt.Sprintf(`{"id":%d,"name":"ChatModule.connect","args":["public-chat"]}`, 2))); err != nil {
fmt.Println(err.Error(), room)
return
}
fmt.Println("read second", room)
_, message, err = c.ReadMessage()
if err != nil {
fmt.Println(err.Error(), room)
return
}
fmt.Println(room, len(string(message)), string(message))
slog <- saveLog{info.Id, now, string(message)}
quit := make(chan bool)
pid := 3
defer func() {
fmt.Println("defer quit", room)
quit <- true
}()
go func() {
ticker := time.NewTicker(30 * time.Second)
defer ticker.Stop()
for {
select {
case <-quit:
return
case <-ticker.C:
if err = c.WriteMessage(websocket.TextMessage, []byte(fmt.Sprintf(`{"id":%d,"name":"ping"}`, pid))); err != nil {
fmt.Println(err.Error(), room)
close(chWorker.Map[room].chQuit)
return
}
pid++
break
}
}
}()
for {
select {
case <-chQuit:
fmt.Println("Exit room:", room)
return
default:
c.SetReadDeadline(time.Now().Add(30 * time.Minute))
_, message, err := c.ReadMessage()
if err != nil {
fmt.Println(err.Error())
return
}
now = time.Now().Unix()
slog <- saveLog{info.Id, now, string(message)}
m := &ServerResponse{}
if err = json.Unmarshal(message, m); err != nil {
fmt.Println(err.Error(), room)
continue
}
workerData.Last = now
rooms.Add <- workerData
if m.Type == "ServerMessageEvent:PERFORMER_STATUS_CHANGE" && string(m.Body) == `"offline"` {
fmt.Println(m.Type, room)
return
}
if m.Type == "ServerMessageEvent:ROOM_CLOSE" {
fmt.Println(m.Type, room)
return
}
if m.Type == "ServerMessageEvent:INCOMING_TIP" {
d := &DonateResponse{}
if err = json.Unmarshal(m.Body, d); err == nil {
//fmt.Println(d.F.Username, " send ", d.A, "tokens")
save <- saveData{room, d.F.Username, info.Id, d.A, now}
workerData.Income += d.A
rooms.Add <- workerData
}
}
}
}
}