mirror of
https://github.com/statbate/fantastic-engine.git
synced 2026-08-11 03:02:41 +00:00
update
This commit is contained in:
parent
86f1cc2fff
commit
c124de90e9
5 changed files with 806 additions and 0 deletions
113
app/cmd.go
Normal file
113
app/cmd.go
Normal file
|
|
@ -0,0 +1,113 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var memInfo runtime.MemStats
|
||||||
|
|
||||||
|
type Info struct {
|
||||||
|
ch chan struct{}
|
||||||
|
room string
|
||||||
|
Key string `json:"key"`
|
||||||
|
Proxy string `json:"proxy"`
|
||||||
|
Online string `json:"online"`
|
||||||
|
Rid int64 `json:"rid"`
|
||||||
|
Start int64 `json:"start"`
|
||||||
|
Last int64 `json:"last"`
|
||||||
|
Income int64 `json:"income"`
|
||||||
|
Dons int64 `json:"dons"`
|
||||||
|
Tips int64 `json:"tips"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateFileRooms() string {
|
||||||
|
for {
|
||||||
|
rooms.Json <- ""
|
||||||
|
s := <-rooms.Json
|
||||||
|
err := os.WriteFile(conf.Conn["start"], []byte(s), 0644)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
}
|
||||||
|
time.Sleep(10 * time.Second)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func listHandler(w http.ResponseWriter, _ *http.Request) {
|
||||||
|
dat, err := os.ReadFile(conf.Conn["start"])
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Fprint(w, string(dat))
|
||||||
|
}
|
||||||
|
|
||||||
|
func debugHandler(w http.ResponseWriter, _ *http.Request) {
|
||||||
|
runtime.ReadMemStats(&memInfo)
|
||||||
|
j, err := json.Marshal(struct {
|
||||||
|
Goroutines int
|
||||||
|
Uptime int64
|
||||||
|
Alloc uint64
|
||||||
|
HeapSys uint64
|
||||||
|
}{
|
||||||
|
Goroutines: runtime.NumGoroutine(),
|
||||||
|
Alloc: memInfo.Alloc,
|
||||||
|
HeapSys: memInfo.HeapSys,
|
||||||
|
Uptime: uptime,
|
||||||
|
})
|
||||||
|
if err == nil {
|
||||||
|
fmt.Fprint(w, string(j))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func cmdHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if !conf.List[r.Header.Get("X-REAL-IP")] {
|
||||||
|
fmt.Fprint(w, "403")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
params := r.URL.Query()
|
||||||
|
if len(params["room"]) > 0 && len(params["key"]) > 0 && len(params["proxy"]) > 0 {
|
||||||
|
now := time.Now().Unix()
|
||||||
|
workerData := Info{
|
||||||
|
room: params["room"][0],
|
||||||
|
Key: params["key"][0],
|
||||||
|
Proxy: params["proxy"][0],
|
||||||
|
Online: "0",
|
||||||
|
Start: now,
|
||||||
|
Last: now,
|
||||||
|
Rid: 0,
|
||||||
|
Income: 0,
|
||||||
|
Dons: 0,
|
||||||
|
Tips: 0,
|
||||||
|
}
|
||||||
|
startRoom(workerData)
|
||||||
|
}
|
||||||
|
if len(params["exit"]) > 0 {
|
||||||
|
rooms.Stop <- strings.Join(params["exit"], "")
|
||||||
|
}
|
||||||
|
fmt.Fprint(w, string("ok"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func startRoom(workerData Info) {
|
||||||
|
rooms.Check <- workerData.room
|
||||||
|
testRoom := <-rooms.Check
|
||||||
|
if testRoom == workerData.room {
|
||||||
|
fmt.Println("Already track:", workerData.room)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
rid, ok := getRoomInfo(workerData.room)
|
||||||
|
if !ok {
|
||||||
|
fmt.Println("No room in MySQL:", workerData.room)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
workerData.Rid = rid
|
||||||
|
workerData.ch = make(chan struct{})
|
||||||
|
|
||||||
|
go xWorker(workerData)
|
||||||
|
}
|
||||||
34
app/conf.go
Normal file
34
app/conf.go
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
type Conf struct {
|
||||||
|
Conn map[string]string
|
||||||
|
Proxy map[string]string
|
||||||
|
List map[string]bool
|
||||||
|
}
|
||||||
|
|
||||||
|
var conf = &Conf{
|
||||||
|
Conn: make(map[string]string),
|
||||||
|
Proxy: make(map[string]string),
|
||||||
|
List: make(map[string]bool),
|
||||||
|
}
|
||||||
|
|
||||||
|
func startConfig() {
|
||||||
|
// DB
|
||||||
|
conf.Conn = map[string]string{
|
||||||
|
"mysql": "user:passwd@unix(/var/run/mysqld/mysqld.sock)/base?interpolateParams=true",
|
||||||
|
"click": "tcp://127.0.0.1:9000/base?compress=true&debug=false",
|
||||||
|
"start": "/tmp/sodaStart.txt",
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3proxy
|
||||||
|
conf.Proxy = map[string]string{
|
||||||
|
"us": "ip:port",
|
||||||
|
"fi": "ip:port",
|
||||||
|
}
|
||||||
|
|
||||||
|
// allow ips
|
||||||
|
conf.List = map[string]bool{
|
||||||
|
"::1": true,
|
||||||
|
"127.0.0.1": true,
|
||||||
|
}
|
||||||
|
}
|
||||||
157
app/main.go
Normal file
157
app/main.go
Normal file
|
|
@ -0,0 +1,157 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
_ "github.com/ClickHouse/clickhouse-go"
|
||||||
|
_ "github.com/go-sql-driver/mysql"
|
||||||
|
"github.com/jmoiron/sqlx"
|
||||||
|
jsoniter "github.com/json-iterator/go"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Rooms struct {
|
||||||
|
Count chan int
|
||||||
|
Json chan string
|
||||||
|
Check chan string
|
||||||
|
Stop chan string
|
||||||
|
Del chan string
|
||||||
|
Add chan Info
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
Mysql, Clickhouse *sqlx.DB
|
||||||
|
|
||||||
|
json = jsoniter.ConfigCompatibleWithStandardLibrary
|
||||||
|
|
||||||
|
socketServer = make(chan []byte, 100)
|
||||||
|
|
||||||
|
save = make(chan saveData, 100)
|
||||||
|
slog = make(chan saveLog, 100)
|
||||||
|
|
||||||
|
rooms = &Rooms{
|
||||||
|
Count: make(chan int),
|
||||||
|
Json: make(chan string),
|
||||||
|
Check: make(chan string),
|
||||||
|
Stop: make(chan string),
|
||||||
|
Del: make(chan string),
|
||||||
|
Add: make(chan Info),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
startConfig()
|
||||||
|
|
||||||
|
initMysql()
|
||||||
|
initClickhouse()
|
||||||
|
|
||||||
|
go mapRooms()
|
||||||
|
go announceCount()
|
||||||
|
go saveDB()
|
||||||
|
go saveLogs()
|
||||||
|
go socketHandler()
|
||||||
|
|
||||||
|
http.HandleFunc("/camsoda/cmd/", cmdHandler)
|
||||||
|
http.HandleFunc("/camsoda/list/", listHandler)
|
||||||
|
http.HandleFunc("/camsoda/debug/", debugHandler)
|
||||||
|
|
||||||
|
go fastStart()
|
||||||
|
|
||||||
|
const SOCK = "/tmp/camsoda.sock"
|
||||||
|
os.Remove(SOCK)
|
||||||
|
unixListener, err := net.Listen("unix", SOCK)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("Listen (UNIX socket): ", err)
|
||||||
|
}
|
||||||
|
defer unixListener.Close()
|
||||||
|
os.Chmod(SOCK, 0777)
|
||||||
|
log.Fatal(http.Serve(unixListener, nil))
|
||||||
|
}
|
||||||
|
|
||||||
|
func initMysql() {
|
||||||
|
db, err := sqlx.Connect("mysql", conf.Conn["mysql"])
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
Mysql = db
|
||||||
|
}
|
||||||
|
|
||||||
|
func initClickhouse() {
|
||||||
|
db, err := sqlx.Connect("clickhouse", conf.Conn["click"])
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
Clickhouse = db
|
||||||
|
}
|
||||||
|
|
||||||
|
func socketHandler() {
|
||||||
|
|
||||||
|
var (
|
||||||
|
err error
|
||||||
|
conn net.Conn
|
||||||
|
)
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case b := <-socketServer:
|
||||||
|
|
||||||
|
if conn == nil {
|
||||||
|
conn, err = net.Dial("unix", "/tmp/echo.sock")
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err.Error())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if conn != nil {
|
||||||
|
if _, err = conn.Write(b); err != nil {
|
||||||
|
fmt.Println(err.Error())
|
||||||
|
conn.Close()
|
||||||
|
conn = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func fastStart() {
|
||||||
|
defer func() {
|
||||||
|
go updateFileRooms()
|
||||||
|
}()
|
||||||
|
dat, err := os.ReadFile(conf.Conn["start"])
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
list := make(map[string]Info)
|
||||||
|
if err := json.Unmarshal(dat, &list); err != nil {
|
||||||
|
fmt.Println(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
now := time.Now().Unix()
|
||||||
|
for k, v := range list {
|
||||||
|
if now > v.Last+60*20 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
fmt.Println("fastStart:", k, v.Key, v.Proxy)
|
||||||
|
workerData := Info{
|
||||||
|
room: k,
|
||||||
|
Key: v.Key,
|
||||||
|
Proxy: v.Proxy,
|
||||||
|
Online: v.Online,
|
||||||
|
Start: v.Start,
|
||||||
|
Last: now,
|
||||||
|
Rid: v.Rid,
|
||||||
|
Income: v.Income,
|
||||||
|
Dons: v.Dons,
|
||||||
|
Tips: v.Tips,
|
||||||
|
}
|
||||||
|
startRoom(workerData)
|
||||||
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
}
|
||||||
|
}
|
||||||
212
app/save.go
Normal file
212
app/save.go
Normal file
|
|
@ -0,0 +1,212 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type saveData struct {
|
||||||
|
Room string
|
||||||
|
From string
|
||||||
|
Rid int64
|
||||||
|
Amount int64
|
||||||
|
Now int64
|
||||||
|
}
|
||||||
|
|
||||||
|
type saveLog struct {
|
||||||
|
Rid int64
|
||||||
|
Now int64
|
||||||
|
Mes string
|
||||||
|
}
|
||||||
|
|
||||||
|
type DonatorCache struct {
|
||||||
|
Id int64
|
||||||
|
Last int64
|
||||||
|
}
|
||||||
|
|
||||||
|
func getDonId(name string) int64 {
|
||||||
|
var id int64
|
||||||
|
err := Mysql.Get(&id, "SELECT id FROM donator WHERE name=?", name)
|
||||||
|
if err != nil {
|
||||||
|
res, _ := Mysql.Exec("INSERT INTO donator (`name`) VALUES (?)", name)
|
||||||
|
id, _ = res.LastInsertId()
|
||||||
|
}
|
||||||
|
return id
|
||||||
|
}
|
||||||
|
|
||||||
|
func getRoomInfo(name string) (int64, bool) {
|
||||||
|
var id int64
|
||||||
|
result := true
|
||||||
|
err := Mysql.Get(&id, "SELECT id FROM room WHERE name=?", name)
|
||||||
|
if err != nil {
|
||||||
|
result = false
|
||||||
|
}
|
||||||
|
return id, result
|
||||||
|
}
|
||||||
|
|
||||||
|
func getSumTokens() int64 {
|
||||||
|
r := struct {
|
||||||
|
Date string
|
||||||
|
Sum int64
|
||||||
|
}{}
|
||||||
|
err := Clickhouse.Get(&r, "SELECT toStartOfHour(toDateTime(`unix`)) as date, SUM(`token`) as sum FROM `stat` WHERE time = today() GROUP BY date ORDER BY date DESC LIMIT 1")
|
||||||
|
if err == nil && r.Sum > 0 {
|
||||||
|
return r.Sum
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func saveDB() {
|
||||||
|
hours, _, _ := time.Now().Clock()
|
||||||
|
|
||||||
|
bulk := []saveData{}
|
||||||
|
update := []struct {
|
||||||
|
Rid int64
|
||||||
|
Now int64
|
||||||
|
}{}
|
||||||
|
|
||||||
|
data := make(map[string]*DonatorCache)
|
||||||
|
index := make(map[string]int64)
|
||||||
|
|
||||||
|
ticker := time.NewTicker(10 * time.Second)
|
||||||
|
defer ticker.Stop()
|
||||||
|
|
||||||
|
cleanCache := time.NewTicker(12 * time.Hour)
|
||||||
|
defer cleanCache.Stop()
|
||||||
|
|
||||||
|
index = map[string]int64{"hours": int64(hours), "tokens": getSumTokens(), "last": time.Now().Unix()}
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-cleanCache.C:
|
||||||
|
l := len(data)
|
||||||
|
now := time.Now().Unix()
|
||||||
|
for k, v := range data {
|
||||||
|
if now > v.Last+60*60*48 {
|
||||||
|
delete(data, k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt.Println("Clean map:", l, "=>", len(data))
|
||||||
|
case <-ticker.C:
|
||||||
|
if len(bulk) > 0 {
|
||||||
|
tx, err := Mysql.Begin()
|
||||||
|
if err == nil {
|
||||||
|
st, _ := tx.Prepare("INSERT INTO `stat` (`did`, `rid`, `token`, `time`) VALUES (?, ?, ?, ?)")
|
||||||
|
for _, v := range bulk {
|
||||||
|
st.Exec(data[v.From].Id, v.Rid, v.Amount, v.Now)
|
||||||
|
}
|
||||||
|
tx.Commit()
|
||||||
|
st.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
tx, err = Mysql.Begin()
|
||||||
|
if err == nil {
|
||||||
|
st, _ := tx.Prepare("UPDATE `room` SET `last` = ? WHERE `id` = ?")
|
||||||
|
for _, v := range update {
|
||||||
|
st.Exec(v.Now, v.Rid)
|
||||||
|
}
|
||||||
|
tx.Commit()
|
||||||
|
st.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
tx, err = Clickhouse.Begin()
|
||||||
|
if err == nil {
|
||||||
|
st, _ := tx.Prepare("INSERT INTO stat VALUES (?, ?, ?, ?, ?)")
|
||||||
|
for _, v := range bulk {
|
||||||
|
st.Exec(uint32(data[v.From].Id), uint32(v.Rid), uint32(v.Amount), time.Unix(v.Now, 0), uint32(v.Now))
|
||||||
|
}
|
||||||
|
tx.Commit()
|
||||||
|
st.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
bulk = nil
|
||||||
|
update = nil
|
||||||
|
}
|
||||||
|
case m := <-save:
|
||||||
|
//fmt.Println("Save channel:", len(save), cap(save))
|
||||||
|
|
||||||
|
now := time.Now().Unix()
|
||||||
|
|
||||||
|
if _, ok := data[m.From]; ok {
|
||||||
|
data[m.From].Last = now
|
||||||
|
} else {
|
||||||
|
data[m.From] = &DonatorCache{Id: getDonId(m.From), Last: now}
|
||||||
|
}
|
||||||
|
|
||||||
|
bulk = append(bulk, m)
|
||||||
|
update = append(update, struct {
|
||||||
|
Rid int64
|
||||||
|
Now int64
|
||||||
|
}{
|
||||||
|
Rid: m.Rid,
|
||||||
|
Now: m.Now,
|
||||||
|
})
|
||||||
|
|
||||||
|
if m.Amount > 49 {
|
||||||
|
msg, err := json.Marshal(struct {
|
||||||
|
Chanel string `json:"chanel"`
|
||||||
|
Room string `json:"room"`
|
||||||
|
Donator string `json:"donator"`
|
||||||
|
Amount int64 `json:"amount"`
|
||||||
|
}{
|
||||||
|
Chanel: "camsoda",
|
||||||
|
Room: m.Room,
|
||||||
|
Donator: m.From,
|
||||||
|
Amount: m.Amount,
|
||||||
|
})
|
||||||
|
if err == nil {
|
||||||
|
socketServer <- msg
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hours, minutes, seconds := time.Now().Clock()
|
||||||
|
if int64(hours) == index["hours"] {
|
||||||
|
index["tokens"] += m.Amount
|
||||||
|
} else {
|
||||||
|
index = map[string]int64{"hours": int64(hours), "tokens": 0, "last": 0}
|
||||||
|
}
|
||||||
|
|
||||||
|
if minutes >= 5 && now > index["last"]+30 {
|
||||||
|
seconds += minutes * 60
|
||||||
|
msg, err := json.Marshal(struct {
|
||||||
|
Chanel string `json:"chanel"`
|
||||||
|
Index float64 `json:"index"`
|
||||||
|
}{
|
||||||
|
Chanel: "camsoda",
|
||||||
|
Index: float64(index["tokens"]) / float64(seconds) * 3600 * 0.05 / 1000,
|
||||||
|
})
|
||||||
|
if err == nil {
|
||||||
|
socketServer <- msg
|
||||||
|
}
|
||||||
|
index["last"] = now
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func saveLogs() {
|
||||||
|
bulk := []saveLog{}
|
||||||
|
ticker := time.NewTicker(10 * time.Second)
|
||||||
|
defer ticker.Stop()
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-ticker.C:
|
||||||
|
if len(bulk) > 0 {
|
||||||
|
tx, err := Mysql.Begin()
|
||||||
|
if err == nil {
|
||||||
|
st, _ := tx.Prepare("INSERT INTO `logs` (`rid`, `time`, `mes`) VALUES (?, ?, ?)")
|
||||||
|
for _, v := range bulk {
|
||||||
|
st.Exec(v.Rid, v.Now, v.Mes)
|
||||||
|
}
|
||||||
|
tx.Commit()
|
||||||
|
st.Close()
|
||||||
|
}
|
||||||
|
bulk = nil
|
||||||
|
}
|
||||||
|
case m := <-slog:
|
||||||
|
if len(m.Mes) > 0 {
|
||||||
|
bulk = append(bulk, m)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
290
app/worker.go
Normal file
290
app/worker.go
Normal file
|
|
@ -0,0 +1,290 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/gorilla/websocket"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
"encoding/base64"
|
||||||
|
)
|
||||||
|
|
||||||
|
var uptime = time.Now().Unix()
|
||||||
|
|
||||||
|
func mapRooms() {
|
||||||
|
|
||||||
|
data := make(map[string]*Info)
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case m := <-rooms.Add:
|
||||||
|
data[m.room] = &Info{Rid: m.Rid, Key: m.Key, Proxy: m.Proxy, Start: m.Start, Last: m.Last, Online: m.Online, Income: m.Income, Dons: m.Dons, Tips: m.Tips, ch: m.ch}
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
case room := <-rooms.Check:
|
||||||
|
if _, ok := data[room]; !ok {
|
||||||
|
room = ""
|
||||||
|
}
|
||||||
|
rooms.Check <- room
|
||||||
|
|
||||||
|
case room := <-rooms.Stop:
|
||||||
|
if _, ok := data[room]; ok {
|
||||||
|
close(data[room].ch)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func announceCount() {
|
||||||
|
for {
|
||||||
|
time.Sleep(30 * time.Second)
|
||||||
|
rooms.Count <- 0
|
||||||
|
l := <-rooms.Count
|
||||||
|
msg, err := json.Marshal(struct {
|
||||||
|
Chanel string `json:"chanel"`
|
||||||
|
Count int `json:"count"`
|
||||||
|
}{
|
||||||
|
Chanel: "camsoda",
|
||||||
|
Count: l,
|
||||||
|
})
|
||||||
|
if err == nil {
|
||||||
|
socketServer <- msg
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func reconnectRoom(workerData Info) {
|
||||||
|
time.Sleep(5 * time.Second)
|
||||||
|
fmt.Println("reconnect:", workerData.room, workerData.Proxy)
|
||||||
|
startRoom(workerData)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getMessageID(s string) int {
|
||||||
|
i := strings.IndexByte(s, ',')
|
||||||
|
if i != -1 {
|
||||||
|
if v, err := strconv.Atoi(s[1:i]); err == nil {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func getMessageData(s string) string {
|
||||||
|
a := strings.IndexByte(s, '{')
|
||||||
|
b := strings.LastIndexByte(s, '}')
|
||||||
|
if a != -1 && b != -1 {
|
||||||
|
return s[a : b+1]
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func getWS(workerData Info, key []byte) string {
|
||||||
|
Dialer := *websocket.DefaultDialer
|
||||||
|
if _, ok := conf.Proxy[workerData.Proxy]; ok {
|
||||||
|
Dialer = websocket.Dialer{
|
||||||
|
Proxy: http.ProxyURL(&url.URL{
|
||||||
|
Scheme: "http", // or "https" depending on your proxy
|
||||||
|
Host: conf.Proxy[workerData.Proxy],
|
||||||
|
Path: "/",
|
||||||
|
}),
|
||||||
|
HandshakeTimeout: 45 * time.Second, // https://pkg.go.dev/github.com/gorilla/websocket
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
u := url.URL{Scheme: "wss", Host: "node2-ord.livemediahost.com:3000"}
|
||||||
|
c, _, err := Dialer.Dial(u.String(), nil)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err.Error(), u.String(), workerData.room)
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
defer c.Close()
|
||||||
|
|
||||||
|
if err = c.WriteMessage(websocket.TextMessage, []byte(`["v3.authorize",{"token":"`+string(key)+`"}]`)); err != nil {
|
||||||
|
fmt.Println(err.Error())
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
c.SetReadDeadline(time.Now().Add(45 * time.Second))
|
||||||
|
_, message, err := c.ReadMessage()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err.Error())
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
//fmt.Println(string(message))
|
||||||
|
|
||||||
|
messageID := getMessageID(string(message))
|
||||||
|
|
||||||
|
if messageID == 2 {
|
||||||
|
if err = c.WriteMessage(websocket.TextMessage, []byte(`[5,{"room": "`+workerData.room+`"}]`)); err != nil {
|
||||||
|
fmt.Println(err.Error())
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
fmt.Println("send message!")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if messageID == 6 {
|
||||||
|
input := struct {
|
||||||
|
Url string `json:"url"`
|
||||||
|
Room string `json:"room"`
|
||||||
|
}{}
|
||||||
|
if err := json.Unmarshal([]byte(getMessageData(string(message))), &input); err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
}
|
||||||
|
return input.Url
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func xWorker(workerData Info) {
|
||||||
|
fmt.Println("Start", workerData.room, "proxy", workerData.Proxy)
|
||||||
|
|
||||||
|
rooms.Add <- workerData
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
rooms.Del <- workerData.room
|
||||||
|
}()
|
||||||
|
|
||||||
|
|
||||||
|
if len(workerData.Key) < 50 {
|
||||||
|
fmt.Println(workerData.Key, workerData.room)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
key, err := base64.StdEncoding.DecodeString(workerData.Key)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err, workerData.room)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
u, err := url.Parse(getWS(workerData, key))
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err, workerData.room)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
Dialer := *websocket.DefaultDialer
|
||||||
|
|
||||||
|
if _, ok := conf.Proxy[workerData.Proxy]; ok {
|
||||||
|
Dialer = websocket.Dialer{
|
||||||
|
Proxy: http.ProxyURL(&url.URL{
|
||||||
|
Scheme: "http", // or "https" depending on your proxy
|
||||||
|
Host: conf.Proxy[workerData.Proxy],
|
||||||
|
Path: "/",
|
||||||
|
}),
|
||||||
|
HandshakeTimeout: 45 * time.Second, // https://pkg.go.dev/github.com/gorilla/websocket
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
c, _, err := Dialer.Dial(u.String(), nil)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err.Error(), u.String(), workerData.room)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
defer c.Close()
|
||||||
|
|
||||||
|
if err = c.WriteMessage(websocket.TextMessage, []byte(`["v3.authorize",{"token":"`+string(key)+`"}]`)); err != nil {
|
||||||
|
fmt.Println(err.Error(), workerData.room)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
dons := make(map[string]struct{})
|
||||||
|
|
||||||
|
ticker := time.NewTicker(60 * 60 * 8 * time.Second)
|
||||||
|
defer ticker.Stop()
|
||||||
|
|
||||||
|
var income int64
|
||||||
|
income = 0
|
||||||
|
|
||||||
|
for {
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-ticker.C:
|
||||||
|
fmt.Println("too_long exit:", workerData.room)
|
||||||
|
return
|
||||||
|
case <-workerData.ch:
|
||||||
|
fmt.Println("Exit room:", workerData.room)
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
c.SetReadDeadline(time.Now().Add(30 * time.Minute))
|
||||||
|
_, message, err := c.ReadMessage()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err.Error(), workerData.room)
|
||||||
|
if income > 1 && websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway) {
|
||||||
|
go reconnectRoom(workerData)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
now := time.Now().Unix()
|
||||||
|
slog <- saveLog{workerData.Rid, now, string(message)}
|
||||||
|
|
||||||
|
if now > workerData.Last+60*60 {
|
||||||
|
fmt.Println("no_tips exit:", workerData.room)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
messageID := getMessageID(string(message))
|
||||||
|
|
||||||
|
if messageID == 27 {
|
||||||
|
input := struct {
|
||||||
|
Value int64 `json:"value"`
|
||||||
|
Username string `json:"subject_username"`
|
||||||
|
Tip bool `json:"is_tip"`
|
||||||
|
Stealth bool `json:"is_stealth"`
|
||||||
|
}{}
|
||||||
|
//[27,{"recent_tips":88,"value":1,"subject_username":"max4you","is_tip":true,"is_stealth":false},1,["<b>max4you</b> tipped <b>1</b> tokens"]]
|
||||||
|
if err := json.Unmarshal([]byte(getMessageData(string(message))), &input); err != nil {
|
||||||
|
//fmt.Println(string(message))
|
||||||
|
//fmt.Println(err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if !input.Tip || input.Value < 1 {
|
||||||
|
//fmt.Println(input.Tip, input.Value, "continue")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if input.Stealth || len(input.Username) < 3 {
|
||||||
|
input.Username = "anon_tips"
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := dons[input.Username]; !ok {
|
||||||
|
dons[input.Username] = struct{}{}
|
||||||
|
workerData.Dons++
|
||||||
|
}
|
||||||
|
|
||||||
|
save <- saveData{workerData.room, strings.ToLower(input.Username), workerData.Rid, input.Value, now}
|
||||||
|
|
||||||
|
income += input.Value
|
||||||
|
|
||||||
|
workerData.Tips++
|
||||||
|
workerData.Last = now
|
||||||
|
workerData.Income += input.Value
|
||||||
|
rooms.Add <- workerData
|
||||||
|
|
||||||
|
fmt.Println(input.Username, "send", input.Value, "tokens to", workerData.room)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue