mirror of https://git.sr.ht/~ashkeel/strimertul
refactor: remove jsoniter
This commit is contained in:
parent
edcc4fb7f9
commit
ce2ce81768
12
app.go
12
app.go
|
@ -3,6 +3,7 @@ package main
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
@ -15,6 +16,11 @@ import (
|
||||||
|
|
||||||
"git.sr.ht/~ashkeel/containers/sync"
|
"git.sr.ht/~ashkeel/containers/sync"
|
||||||
kv "git.sr.ht/~ashkeel/kilovolt/v12"
|
kv "git.sr.ht/~ashkeel/kilovolt/v12"
|
||||||
|
"github.com/nicklaw5/helix/v2"
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
|
"github.com/wailsapp/wails/v2/pkg/options"
|
||||||
|
"github.com/wailsapp/wails/v2/pkg/runtime"
|
||||||
|
|
||||||
"git.sr.ht/~ashkeel/strimertul/database"
|
"git.sr.ht/~ashkeel/strimertul/database"
|
||||||
"git.sr.ht/~ashkeel/strimertul/docs"
|
"git.sr.ht/~ashkeel/strimertul/docs"
|
||||||
"git.sr.ht/~ashkeel/strimertul/loyalty"
|
"git.sr.ht/~ashkeel/strimertul/loyalty"
|
||||||
|
@ -22,10 +28,6 @@ import (
|
||||||
"git.sr.ht/~ashkeel/strimertul/twitch"
|
"git.sr.ht/~ashkeel/strimertul/twitch"
|
||||||
"git.sr.ht/~ashkeel/strimertul/twitch/client"
|
"git.sr.ht/~ashkeel/strimertul/twitch/client"
|
||||||
"git.sr.ht/~ashkeel/strimertul/webserver"
|
"git.sr.ht/~ashkeel/strimertul/webserver"
|
||||||
"github.com/nicklaw5/helix/v2"
|
|
||||||
"github.com/urfave/cli/v2"
|
|
||||||
"github.com/wailsapp/wails/v2/pkg/options"
|
|
||||||
"github.com/wailsapp/wails/v2/pkg/runtime"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// App struct
|
// App struct
|
||||||
|
@ -155,7 +157,7 @@ func (a *App) initializeComponents() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize loyalty system
|
// Initialize loyalty system
|
||||||
a.loyaltyManager, err = loyalty.NewManager(a.db)
|
a.loyaltyManager, err = loyalty.NewManager(a.db, a.twitchManager)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("could not initialize loyalty manager: %w", err)
|
return fmt.Errorf("could not initialize loyalty manager: %w", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,12 @@
|
||||||
package database
|
package database
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
kv "git.sr.ht/~ashkeel/kilovolt/v12"
|
kv "git.sr.ht/~ashkeel/kilovolt/v12"
|
||||||
|
|
||||||
jsoniter "github.com/json-iterator/go"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestLocalDBClientPutKey(t *testing.T) {
|
func TestLocalDBClientPutKey(t *testing.T) {
|
||||||
|
@ -60,7 +59,7 @@ func TestLocalDBClientPutJSON(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var testStored test
|
var testStored test
|
||||||
err = jsoniter.ConfigFastest.UnmarshalFromString(stored, &testStored)
|
err = json.Unmarshal([]byte(stored), &testStored)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -107,13 +106,13 @@ func TestLocalDBClientPutJSONBulk(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var testStored1 test
|
var testStored1 test
|
||||||
err = jsoniter.ConfigFastest.UnmarshalFromString(keys["test"], &testStored1)
|
err = json.Unmarshal([]byte(keys["test"]), &testStored1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var testStored2 test
|
var testStored2 test
|
||||||
err = jsoniter.ConfigFastest.UnmarshalFromString(keys["test2"], &testStored2)
|
err = json.Unmarshal([]byte(keys["test2"]), &testStored2)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -171,12 +170,12 @@ func TestLocalDBClientGetJSON(t *testing.T) {
|
||||||
|
|
||||||
// Store a key directly in the store
|
// Store a key directly in the store
|
||||||
key := "test"
|
key := "test"
|
||||||
byt, err := jsoniter.ConfigFastest.MarshalToString(testStruct)
|
byt, err := json.Marshal(testStruct)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = store.Set(key, byt)
|
err = store.Set(key, string(byt))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"git.sr.ht/~ashkeel/strimertul/docs"
|
"git.sr.ht/~ashkeel/strimertul/docs"
|
||||||
jsoniter "github.com/json-iterator/go"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
enc := jsoniter.ConfigFastest.NewEncoder(os.Stdout)
|
enc := json.NewEncoder(os.Stdout)
|
||||||
enc.SetIndent("", " ")
|
enc.SetIndent("", " ")
|
||||||
_ = enc.Encode(docs.Keys)
|
_ = enc.Encode(docs.Keys)
|
||||||
}
|
}
|
||||||
|
|
3
go.mod
3
go.mod
|
@ -13,7 +13,6 @@ require (
|
||||||
github.com/cockroachdb/pebble v1.1.0
|
github.com/cockroachdb/pebble v1.1.0
|
||||||
github.com/gorilla/websocket v1.5.1
|
github.com/gorilla/websocket v1.5.1
|
||||||
github.com/hashicorp/golang-lru/v2 v2.0.7
|
github.com/hashicorp/golang-lru/v2 v2.0.7
|
||||||
github.com/json-iterator/go v1.1.12
|
|
||||||
github.com/nicklaw5/helix/v2 v2.28.1
|
github.com/nicklaw5/helix/v2 v2.28.1
|
||||||
github.com/samber/slog-multi v1.0.2
|
github.com/samber/slog-multi v1.0.2
|
||||||
github.com/urfave/cli/v2 v2.27.1
|
github.com/urfave/cli/v2 v2.27.1
|
||||||
|
@ -59,8 +58,6 @@ require (
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect
|
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect
|
||||||
github.com/mitchellh/copystructure v1.0.0 // indirect
|
github.com/mitchellh/copystructure v1.0.0 // indirect
|
||||||
github.com/mitchellh/reflectwalk v1.0.0 // indirect
|
github.com/mitchellh/reflectwalk v1.0.0 // indirect
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
|
||||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
|
||||||
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect
|
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect
|
||||||
github.com/pkg/errors v0.9.1 // indirect
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
github.com/prometheus/client_golang v1.12.0 // indirect
|
github.com/prometheus/client_golang v1.12.0 // indirect
|
||||||
|
|
3
go.sum
3
go.sum
|
@ -193,7 +193,6 @@ github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX
|
||||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||||
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||||
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
|
||||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||||
|
@ -245,11 +244,9 @@ github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFW
|
||||||
github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY=
|
github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY=
|
||||||
github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
|
||||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||||
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||||
|
|
|
@ -2,6 +2,7 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
|
@ -66,7 +67,7 @@ func (core *LogStorage) Handle(_ context.Context, record slog.Record) error {
|
||||||
attributes[attrs.Key] = attrs.Value.Any()
|
attributes[attrs.Key] = attrs.Value.Any()
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
attrJSON, _ := json.MarshalToString(attributes)
|
attrJSON, _ := json.Marshal(attributes)
|
||||||
|
|
||||||
// Generate unique log ID
|
// Generate unique log ID
|
||||||
id := fmt.Sprintf("%d-%d", time.Now().UnixNano(), rand.Int31())
|
id := fmt.Sprintf("%d-%d", time.Now().UnixNano(), rand.Int31())
|
||||||
|
@ -76,7 +77,7 @@ func (core *LogStorage) Handle(_ context.Context, record slog.Record) error {
|
||||||
Time: record.Time.Format(time.RFC3339),
|
Time: record.Time.Format(time.RFC3339),
|
||||||
Level: record.Level.String(),
|
Level: record.Level.String(),
|
||||||
Message: record.Message,
|
Message: record.Message,
|
||||||
Data: attrJSON,
|
Data: string(attrJSON),
|
||||||
}
|
}
|
||||||
lastLogs.Push(logEntry)
|
lastLogs.Push(logEntry)
|
||||||
if lastLogs.Size() > LogHistory {
|
if lastLogs.Size() > LogHistory {
|
||||||
|
|
|
@ -1,19 +1,19 @@
|
||||||
package chat
|
package loyalty
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.sr.ht/~ashkeel/strimertul/twitch"
|
"github.com/nicklaw5/helix/v2"
|
||||||
|
|
||||||
"git.sr.ht/~ashkeel/containers/sync"
|
"git.sr.ht/~ashkeel/containers/sync"
|
||||||
|
"git.sr.ht/~ashkeel/strimertul/twitch"
|
||||||
"git.sr.ht/~ashkeel/strimertul/loyalty"
|
"git.sr.ht/~ashkeel/strimertul/twitch/chat"
|
||||||
"github.com/nicklaw5/helix/v2"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -23,49 +23,49 @@ const (
|
||||||
commandContribute = "!contribute"
|
commandContribute = "!contribute"
|
||||||
)
|
)
|
||||||
|
|
||||||
type loyaltyIntegration struct {
|
type twitchIntegration struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
manager *loyalty.Manager
|
manager *Manager
|
||||||
module *Module
|
module *chat.Module
|
||||||
|
|
||||||
activeUsers *sync.Map[string, bool]
|
activeUsers *sync.Map[string, bool]
|
||||||
}
|
}
|
||||||
|
|
||||||
func setupLoyaltyIntegration(ctx context.Context, mod *Module, manager *loyalty.Manager) *loyaltyIntegration {
|
func setupTwitchIntegration(ctx context.Context, m *Manager, mod *chat.Module) *twitchIntegration {
|
||||||
li := &loyaltyIntegration{
|
li := &twitchIntegration{
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
manager: manager,
|
manager: m,
|
||||||
module: mod,
|
module: mod,
|
||||||
|
|
||||||
activeUsers: sync.NewMap[string, bool](),
|
activeUsers: sync.NewMap[string, bool](),
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add loyalty-based commands
|
// Add loyalty-based commands
|
||||||
mod.commands.SetKey(commandRedeem, Command{
|
mod.RegisterCommand(commandRedeem, chat.Command{
|
||||||
Description: "Redeem a reward with loyalty points",
|
Description: "Redeem a reward with loyalty points",
|
||||||
Usage: fmt.Sprintf("%s <reward-id> [request text]", commandRedeem),
|
Usage: fmt.Sprintf("%s <reward-id> [request text]", commandRedeem),
|
||||||
AccessLevel: ALTEveryone,
|
AccessLevel: chat.ALTEveryone,
|
||||||
Handler: li.cmdRedeemReward,
|
Handler: li.cmdRedeemReward,
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
})
|
})
|
||||||
mod.commands.SetKey(commandBalance, Command{
|
mod.RegisterCommand(commandBalance, chat.Command{
|
||||||
Description: "See your current point balance",
|
Description: "See your current point balance",
|
||||||
Usage: commandBalance,
|
Usage: commandBalance,
|
||||||
AccessLevel: ALTEveryone,
|
AccessLevel: chat.ALTEveryone,
|
||||||
Handler: li.cmdBalance,
|
Handler: li.cmdBalance,
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
})
|
})
|
||||||
mod.commands.SetKey(commandGoals, Command{
|
mod.RegisterCommand(commandGoals, chat.Command{
|
||||||
Description: "Check currently active community goals",
|
Description: "Check currently active community goals",
|
||||||
Usage: commandGoals,
|
Usage: commandGoals,
|
||||||
AccessLevel: ALTEveryone,
|
AccessLevel: chat.ALTEveryone,
|
||||||
Handler: li.cmdGoalList,
|
Handler: li.cmdGoalList,
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
})
|
})
|
||||||
mod.commands.SetKey(commandContribute, Command{
|
mod.RegisterCommand(commandContribute, chat.Command{
|
||||||
Description: "Contribute points to a community goal",
|
Description: "Contribute points to a community goal",
|
||||||
Usage: fmt.Sprintf("%s <points> [<goal-id>]", commandContribute),
|
Usage: fmt.Sprintf("%s <points> [<goal-id>]", commandContribute),
|
||||||
AccessLevel: ALTEveryone,
|
AccessLevel: chat.ALTEveryone,
|
||||||
Handler: li.cmdContributeGoal,
|
Handler: li.cmdContributeGoal,
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
})
|
})
|
||||||
|
@ -87,9 +87,9 @@ func setupLoyaltyIntegration(ctx context.Context, mod *Module, manager *loyalty.
|
||||||
|
|
||||||
// If stream is confirmed offline, don't give points away!
|
// If stream is confirmed offline, don't give points away!
|
||||||
var streamInfos []helix.Stream
|
var streamInfos []helix.Stream
|
||||||
err := mod.db.GetJSON(twitch.StreamInfoKey, &streamInfos)
|
err := m.db.GetJSON(twitch.StreamInfoKey, &streamInfos)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
mod.logger.Error("Error retrieving stream info", "error", err)
|
slog.Error("Error retrieving stream info", "error", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if len(streamInfos) < 1 {
|
if len(streamInfos) < 1 {
|
||||||
|
@ -97,32 +97,7 @@ func setupLoyaltyIntegration(ctx context.Context, mod *Module, manager *loyalty.
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get user list
|
// Get user list
|
||||||
cursor := ""
|
users := mod.GetChatters()
|
||||||
var users []string
|
|
||||||
for {
|
|
||||||
userClient, err := twitch.GetUserClient(mod.db, false)
|
|
||||||
if err != nil {
|
|
||||||
mod.logger.Error("Could not get user api client for list of chatters", "error", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
res, err := userClient.GetChannelChatChatters(&helix.GetChatChattersParams{
|
|
||||||
BroadcasterID: mod.user.ID,
|
|
||||||
ModeratorID: mod.user.ID,
|
|
||||||
First: "1000",
|
|
||||||
After: cursor,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
mod.logger.Error("Could not retrieve list of chatters", "error", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for _, user := range res.Data.Chatters {
|
|
||||||
users = append(users, user.UserLogin)
|
|
||||||
}
|
|
||||||
cursor = res.Data.Pagination.Cursor
|
|
||||||
if cursor == "" {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Iterate for each user in the list
|
// Iterate for each user in the list
|
||||||
pointsToGive := make(map[string]int64)
|
pointsToGive := make(map[string]int64)
|
||||||
|
@ -148,48 +123,48 @@ func setupLoyaltyIntegration(ctx context.Context, mod *Module, manager *loyalty.
|
||||||
if len(users) > 0 {
|
if len(users) > 0 {
|
||||||
err := li.manager.GivePoints(pointsToGive)
|
err := li.manager.GivePoints(pointsToGive)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
mod.logger.Error("Error awarding loyalty points to user", "error", err)
|
slog.Error("Error awarding loyalty points to user", "error", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
mod.logger.Info("Loyalty system integration with Twitch is ready")
|
slog.Info("Loyalty system integration with Twitch is ready")
|
||||||
|
|
||||||
return li
|
return li
|
||||||
}
|
}
|
||||||
|
|
||||||
func (li *loyaltyIntegration) Close() {
|
func (li *twitchIntegration) Close() {
|
||||||
li.module.commands.DeleteKey(commandRedeem)
|
li.module.UnregisterCommand(commandRedeem)
|
||||||
li.module.commands.DeleteKey(commandBalance)
|
li.module.UnregisterCommand(commandBalance)
|
||||||
li.module.commands.DeleteKey(commandGoals)
|
li.module.UnregisterCommand(commandGoals)
|
||||||
li.module.commands.DeleteKey(commandContribute)
|
li.module.UnregisterCommand(commandContribute)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (li *loyaltyIntegration) HandleMessage(message helix.EventSubChannelChatMessageEvent) {
|
func (li *twitchIntegration) HandleMessage(message helix.EventSubChannelChatMessageEvent) {
|
||||||
li.activeUsers.SetKey(message.ChatterUserLogin, true)
|
li.activeUsers.SetKey(message.ChatterUserLogin, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (li *loyaltyIntegration) IsActive(user string) bool {
|
func (li *twitchIntegration) IsActive(user string) bool {
|
||||||
active, ok := li.activeUsers.GetKey(user)
|
active, ok := li.activeUsers.GetKey(user)
|
||||||
return ok && active
|
return ok && active
|
||||||
}
|
}
|
||||||
|
|
||||||
func (li *loyaltyIntegration) ResetActivity() {
|
func (li *twitchIntegration) ResetActivity() {
|
||||||
li.activeUsers = sync.NewMap[string, bool]()
|
li.activeUsers = sync.NewMap[string, bool]()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (li *loyaltyIntegration) cmdBalance(message helix.EventSubChannelChatMessageEvent) {
|
func (li *twitchIntegration) cmdBalance(message helix.EventSubChannelChatMessageEvent) {
|
||||||
// Get user balance
|
// Get user balance
|
||||||
balance := li.manager.GetPoints(message.ChatterUserLogin)
|
balance := li.manager.GetPoints(message.ChatterUserLogin)
|
||||||
|
|
||||||
li.module.WriteMessage(WriteMessageRequest{
|
li.module.WriteMessage(chat.WriteMessageRequest{
|
||||||
Message: fmt.Sprintf("You have %d %s!", balance, li.manager.Config.Get().Currency),
|
Message: fmt.Sprintf("You have %d %s!", balance, li.manager.Config.Get().Currency),
|
||||||
ReplyTo: message.MessageID,
|
ReplyTo: message.MessageID,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (li *loyaltyIntegration) cmdRedeemReward(message helix.EventSubChannelChatMessageEvent) {
|
func (li *twitchIntegration) cmdRedeemReward(message helix.EventSubChannelChatMessageEvent) {
|
||||||
parts := strings.Fields(message.Message.Text)
|
parts := strings.Fields(message.Message.Text)
|
||||||
if len(parts) < 2 {
|
if len(parts) < 2 {
|
||||||
return
|
return
|
||||||
|
@ -213,7 +188,7 @@ func (li *loyaltyIntegration) cmdRedeemReward(message helix.EventSubChannelChatM
|
||||||
|
|
||||||
// Check if user can afford the reward
|
// Check if user can afford the reward
|
||||||
if balance-reward.Price < 0 {
|
if balance-reward.Price < 0 {
|
||||||
li.module.WriteMessage(WriteMessageRequest{
|
li.module.WriteMessage(chat.WriteMessageRequest{
|
||||||
Message: fmt.Sprintf("I'm sorry but you cannot afford this (have %d %s, need %d)", balance, config.Currency, reward.Price),
|
Message: fmt.Sprintf("I'm sorry but you cannot afford this (have %d %s, need %d)", balance, config.Currency, reward.Price),
|
||||||
ReplyTo: message.MessageID,
|
ReplyTo: message.MessageID,
|
||||||
})
|
})
|
||||||
|
@ -226,36 +201,36 @@ func (li *loyaltyIntegration) cmdRedeemReward(message helix.EventSubChannelChatM
|
||||||
}
|
}
|
||||||
|
|
||||||
// Perform redeem
|
// Perform redeem
|
||||||
if err := li.manager.PerformRedeem(loyalty.Redeem{
|
if err := li.manager.PerformRedeem(Redeem{
|
||||||
Username: message.ChatterUserLogin,
|
Username: message.ChatterUserLogin,
|
||||||
DisplayName: message.ChatterUserName,
|
DisplayName: message.ChatterUserName,
|
||||||
When: time.Now(),
|
When: time.Now(),
|
||||||
Reward: reward,
|
Reward: reward,
|
||||||
RequestText: text,
|
RequestText: text,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
if errors.Is(err, loyalty.ErrRedeemInCooldown) {
|
if errors.Is(err, ErrRedeemInCooldown) {
|
||||||
nextAvailable := li.manager.GetRewardCooldown(reward.ID)
|
nextAvailable := li.manager.GetRewardCooldown(reward.ID)
|
||||||
li.module.WriteMessage(WriteMessageRequest{
|
li.module.WriteMessage(chat.WriteMessageRequest{
|
||||||
Message: fmt.Sprintf("That reward is in cooldown (available in %s)",
|
Message: fmt.Sprintf("That reward is in cooldown (available in %s)",
|
||||||
time.Until(nextAvailable).Truncate(time.Second)),
|
time.Until(nextAvailable).Truncate(time.Second)),
|
||||||
ReplyTo: message.MessageID,
|
ReplyTo: message.MessageID,
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
li.module.logger.Error("Error while performing redeem", "error", err)
|
slog.Error("Error while performing redeem", "error", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
li.module.WriteMessage(WriteMessageRequest{
|
li.module.WriteMessage(chat.WriteMessageRequest{
|
||||||
Message: fmt.Sprintf("HolidayPresent %s has redeemed %s! (new balance: %d %s)",
|
Message: fmt.Sprintf("HolidayPresent %s has redeemed %s! (new balance: %d %s)",
|
||||||
message.ChatterUserName, reward.Name, li.manager.GetPoints(message.ChatterUserLogin), config.Currency),
|
message.ChatterUserName, reward.Name, li.manager.GetPoints(message.ChatterUserLogin), config.Currency),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (li *loyaltyIntegration) cmdGoalList(message helix.EventSubChannelChatMessageEvent) {
|
func (li *twitchIntegration) cmdGoalList(message helix.EventSubChannelChatMessageEvent) {
|
||||||
goals := li.manager.Goals.Get()
|
goals := li.manager.Goals.Get()
|
||||||
if len(goals) < 1 {
|
if len(goals) < 1 {
|
||||||
li.module.WriteMessage(WriteMessageRequest{
|
li.module.WriteMessage(chat.WriteMessageRequest{
|
||||||
Message: "There are no active community goals right now :(!",
|
Message: "There are no active community goals right now :(!",
|
||||||
ReplyTo: message.MessageID,
|
ReplyTo: message.MessageID,
|
||||||
})
|
})
|
||||||
|
@ -269,12 +244,12 @@ func (li *loyaltyIntegration) cmdGoalList(message helix.EventSubChannelChatMessa
|
||||||
msg += fmt.Sprintf("%s (%d/%d %s) [id: %s] | ", goal.Name, goal.Contributed, goal.TotalGoal, li.manager.Config.Get().Currency, goal.ID)
|
msg += fmt.Sprintf("%s (%d/%d %s) [id: %s] | ", goal.Name, goal.Contributed, goal.TotalGoal, li.manager.Config.Get().Currency, goal.ID)
|
||||||
}
|
}
|
||||||
msg += " Contribute with <!contribute POINTS GOALID>"
|
msg += " Contribute with <!contribute POINTS GOALID>"
|
||||||
li.module.WriteMessage(WriteMessageRequest{
|
li.module.WriteMessage(chat.WriteMessageRequest{
|
||||||
Message: msg,
|
Message: msg,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (li *loyaltyIntegration) cmdContributeGoal(message helix.EventSubChannelChatMessageEvent) {
|
func (li *twitchIntegration) cmdContributeGoal(message helix.EventSubChannelChatMessageEvent) {
|
||||||
goals := li.manager.Goals.Get()
|
goals := li.manager.Goals.Get()
|
||||||
|
|
||||||
// Set defaults if user doesn't provide them
|
// Set defaults if user doesn't provide them
|
||||||
|
@ -297,12 +272,12 @@ func (li *loyaltyIntegration) cmdContributeGoal(message helix.EventSubChannelCha
|
||||||
// Do we not have any goal we can contribute to? Hooray I guess?
|
// Do we not have any goal we can contribute to? Hooray I guess?
|
||||||
if goalIndex < 0 {
|
if goalIndex < 0 {
|
||||||
if hasGoals {
|
if hasGoals {
|
||||||
li.module.WriteMessage(WriteMessageRequest{
|
li.module.WriteMessage(chat.WriteMessageRequest{
|
||||||
Message: "All active community goals have been reached already! NewRecord",
|
Message: "All active community goals have been reached already! NewRecord",
|
||||||
ReplyTo: message.MessageID,
|
ReplyTo: message.MessageID,
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
li.module.WriteMessage(WriteMessageRequest{
|
li.module.WriteMessage(chat.WriteMessageRequest{
|
||||||
Message: "There are no active community goals right now :(!",
|
Message: "There are no active community goals right now :(!",
|
||||||
ReplyTo: message.MessageID,
|
ReplyTo: message.MessageID,
|
||||||
})
|
})
|
||||||
|
@ -316,7 +291,7 @@ func (li *loyaltyIntegration) cmdContributeGoal(message helix.EventSubChannelCha
|
||||||
newPoints, err := strconv.ParseInt(parts[1], 10, 64)
|
newPoints, err := strconv.ParseInt(parts[1], 10, 64)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
if newPoints <= 0 {
|
if newPoints <= 0 {
|
||||||
li.module.WriteMessage(WriteMessageRequest{
|
li.module.WriteMessage(chat.WriteMessageRequest{
|
||||||
Message: "Nice try SoBayed",
|
Message: "Nice try SoBayed",
|
||||||
ReplyTo: message.MessageID,
|
ReplyTo: message.MessageID,
|
||||||
})
|
})
|
||||||
|
@ -340,7 +315,7 @@ func (li *loyaltyIntegration) cmdContributeGoal(message helix.EventSubChannelCha
|
||||||
}
|
}
|
||||||
// Invalid goal ID provided
|
// Invalid goal ID provided
|
||||||
if !found {
|
if !found {
|
||||||
li.module.WriteMessage(WriteMessageRequest{
|
li.module.WriteMessage(chat.WriteMessageRequest{
|
||||||
Message: "I couldn't find that goal ID :(",
|
Message: "I couldn't find that goal ID :(",
|
||||||
ReplyTo: message.MessageID,
|
ReplyTo: message.MessageID,
|
||||||
})
|
})
|
||||||
|
@ -354,7 +329,7 @@ func (li *loyaltyIntegration) cmdContributeGoal(message helix.EventSubChannelCha
|
||||||
|
|
||||||
// Check if goal was reached already
|
// Check if goal was reached already
|
||||||
if selectedGoal.Contributed >= selectedGoal.TotalGoal {
|
if selectedGoal.Contributed >= selectedGoal.TotalGoal {
|
||||||
li.module.WriteMessage(WriteMessageRequest{
|
li.module.WriteMessage(chat.WriteMessageRequest{
|
||||||
Message: "This goal was already reached! ヾ(•ω•`)o",
|
Message: "This goal was already reached! ヾ(•ω•`)o",
|
||||||
ReplyTo: message.MessageID,
|
ReplyTo: message.MessageID,
|
||||||
})
|
})
|
||||||
|
@ -364,11 +339,11 @@ func (li *loyaltyIntegration) cmdContributeGoal(message helix.EventSubChannelCha
|
||||||
// Add points to goal
|
// Add points to goal
|
||||||
points, err := li.manager.PerformContribution(selectedGoal, message.ChatterUserLogin, points)
|
points, err := li.manager.PerformContribution(selectedGoal, message.ChatterUserLogin, points)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
li.module.logger.Error("Error while contributing to goal", "error", err)
|
slog.Error("Error while contributing to goal", "error", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if points == 0 {
|
if points == 0 {
|
||||||
li.module.WriteMessage(WriteMessageRequest{
|
li.module.WriteMessage(chat.WriteMessageRequest{
|
||||||
Message: "Sorry but you're broke",
|
Message: "Sorry but you're broke",
|
||||||
ReplyTo: message.MessageID,
|
ReplyTo: message.MessageID,
|
||||||
})
|
})
|
||||||
|
@ -378,13 +353,13 @@ func (li *loyaltyIntegration) cmdContributeGoal(message helix.EventSubChannelCha
|
||||||
selectedGoal = li.manager.Goals.Get()[goalIndex]
|
selectedGoal = li.manager.Goals.Get()[goalIndex]
|
||||||
config := li.manager.Config.Get()
|
config := li.manager.Config.Get()
|
||||||
newRemaining := selectedGoal.TotalGoal - selectedGoal.Contributed
|
newRemaining := selectedGoal.TotalGoal - selectedGoal.Contributed
|
||||||
li.module.WriteMessage(WriteMessageRequest{
|
li.module.WriteMessage(chat.WriteMessageRequest{
|
||||||
Message: fmt.Sprintf("NewRecord %s contributed %d %s to \"%s\"!! Only %d %s left!", message.ChatterUserName, points, config.Currency, selectedGoal.Name, newRemaining, config.Currency),
|
Message: fmt.Sprintf("NewRecord %s contributed %d %s to \"%s\"!! Only %d %s left!", message.ChatterUserName, points, config.Currency, selectedGoal.Name, newRemaining, config.Currency),
|
||||||
})
|
})
|
||||||
|
|
||||||
// Check if goal was reached!
|
// Check if goal was reached!
|
||||||
if newRemaining <= 0 {
|
if newRemaining <= 0 {
|
||||||
li.module.WriteMessage(WriteMessageRequest{
|
li.module.WriteMessage(chat.WriteMessageRequest{
|
||||||
Message: fmt.Sprintf("FallWinning The community goal \"%s\" was reached! FallWinning", selectedGoal.Name),
|
Message: fmt.Sprintf("FallWinning The community goal \"%s\" was reached! FallWinning", selectedGoal.Name),
|
||||||
Announce: true,
|
Announce: true,
|
||||||
})
|
})
|
|
@ -2,6 +2,7 @@ package loyalty
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
|
@ -10,12 +11,10 @@ import (
|
||||||
|
|
||||||
"git.sr.ht/~ashkeel/containers/sync"
|
"git.sr.ht/~ashkeel/containers/sync"
|
||||||
"git.sr.ht/~ashkeel/strimertul/database"
|
"git.sr.ht/~ashkeel/strimertul/database"
|
||||||
|
twitchclient "git.sr.ht/~ashkeel/strimertul/twitch/client"
|
||||||
"git.sr.ht/~ashkeel/strimertul/utils"
|
"git.sr.ht/~ashkeel/strimertul/utils"
|
||||||
jsoniter "github.com/json-iterator/go"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var json = jsoniter.ConfigFastest
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ErrRedeemNotFound = errors.New("redeem not found")
|
ErrRedeemNotFound = errors.New("redeem not found")
|
||||||
ErrRedeemInCooldown = errors.New("redeem is on cooldown")
|
ErrRedeemInCooldown = errors.New("redeem is on cooldown")
|
||||||
|
@ -36,9 +35,11 @@ type Manager struct {
|
||||||
cancelFn context.CancelFunc
|
cancelFn context.CancelFunc
|
||||||
cancelSub database.CancelFunc
|
cancelSub database.CancelFunc
|
||||||
restartTwitchHandler chan struct{}
|
restartTwitchHandler chan struct{}
|
||||||
|
twitchManager *twitchclient.Manager
|
||||||
|
twitchIntegration *twitchIntegration
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewManager(db database.Database) (*Manager, error) {
|
func NewManager(db database.Database, twitchManager *twitchclient.Manager) (*Manager, error) {
|
||||||
ctx, cancelFn := context.WithCancel(context.Background())
|
ctx, cancelFn := context.WithCancel(context.Background())
|
||||||
loyalty := &Manager{
|
loyalty := &Manager{
|
||||||
Config: sync.NewRWSync(Config{Enabled: false}),
|
Config: sync.NewRWSync(Config{Enabled: false}),
|
||||||
|
@ -53,6 +54,7 @@ func NewManager(db database.Database) (*Manager, error) {
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
cancelFn: cancelFn,
|
cancelFn: cancelFn,
|
||||||
restartTwitchHandler: make(chan struct{}),
|
restartTwitchHandler: make(chan struct{}),
|
||||||
|
twitchManager: twitchManager,
|
||||||
}
|
}
|
||||||
// Get data from DB
|
// Get data from DB
|
||||||
var config Config
|
var config Config
|
||||||
|
@ -103,7 +105,7 @@ func NewManager(db database.Database) (*Manager, error) {
|
||||||
|
|
||||||
for k, v := range points {
|
for k, v := range points {
|
||||||
var entry PointsEntry
|
var entry PointsEntry
|
||||||
err := json.UnmarshalFromString(v, &entry)
|
err := json.Unmarshal([]byte(v), &entry)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -119,10 +121,20 @@ func NewManager(db database.Database) (*Manager, error) {
|
||||||
|
|
||||||
loyalty.SetBanList(config.BanList)
|
loyalty.SetBanList(config.BanList)
|
||||||
|
|
||||||
|
// Start twitch handler
|
||||||
|
if twitchManager.Client() != nil {
|
||||||
|
loyalty.twitchIntegration = setupTwitchIntegration(ctx, loyalty, twitchManager.Client().Chat)
|
||||||
|
}
|
||||||
|
|
||||||
return loyalty, nil
|
return loyalty, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Manager) Close() error {
|
func (m *Manager) Close() error {
|
||||||
|
// Disable twitch integration
|
||||||
|
if m.twitchIntegration != nil {
|
||||||
|
m.twitchIntegration.Close()
|
||||||
|
}
|
||||||
|
|
||||||
// Stop subscription
|
// Stop subscription
|
||||||
if m.cancelSub != nil {
|
if m.cancelSub != nil {
|
||||||
m.cancelSub()
|
m.cancelSub()
|
||||||
|
@ -152,13 +164,13 @@ func (m *Manager) update(key, value string) {
|
||||||
err = utils.LoadJSONToWrapped[[]Redeem](value, m.Queue)
|
err = utils.LoadJSONToWrapped[[]Redeem](value, m.Queue)
|
||||||
case CreateRedeemRPC:
|
case CreateRedeemRPC:
|
||||||
var redeem Redeem
|
var redeem Redeem
|
||||||
err = json.UnmarshalFromString(value, &redeem)
|
err = json.Unmarshal([]byte(value), &redeem)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
err = m.AddRedeem(redeem)
|
err = m.AddRedeem(redeem)
|
||||||
}
|
}
|
||||||
case RemoveRedeemRPC:
|
case RemoveRedeemRPC:
|
||||||
var redeem Redeem
|
var redeem Redeem
|
||||||
err = json.UnmarshalFromString(value, &redeem)
|
err = json.Unmarshal([]byte(value), &redeem)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
err = m.RemoveRedeem(redeem)
|
err = m.RemoveRedeem(redeem)
|
||||||
}
|
}
|
||||||
|
@ -168,7 +180,7 @@ func (m *Manager) update(key, value string) {
|
||||||
// User point changed
|
// User point changed
|
||||||
case strings.HasPrefix(key, PointsPrefix):
|
case strings.HasPrefix(key, PointsPrefix):
|
||||||
var entry PointsEntry
|
var entry PointsEntry
|
||||||
err = json.UnmarshalFromString(value, &entry)
|
err = json.Unmarshal([]byte(value), &entry)
|
||||||
user := key[len(PointsPrefix):]
|
user := key[len(PointsPrefix):]
|
||||||
m.points.SetKey(user, entry)
|
m.points.SetKey(user, entry)
|
||||||
}
|
}
|
||||||
|
|
3
main.go
3
main.go
|
@ -12,7 +12,6 @@ import (
|
||||||
|
|
||||||
"git.sr.ht/~ashkeel/strimertul/utils"
|
"git.sr.ht/~ashkeel/strimertul/utils"
|
||||||
"github.com/apenwarr/fixconsole"
|
"github.com/apenwarr/fixconsole"
|
||||||
jsoniter "github.com/json-iterator/go"
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
"github.com/wailsapp/wails/v2"
|
"github.com/wailsapp/wails/v2"
|
||||||
"github.com/wailsapp/wails/v2/pkg/options"
|
"github.com/wailsapp/wails/v2/pkg/options"
|
||||||
|
@ -20,8 +19,6 @@ import (
|
||||||
"github.com/wailsapp/wails/v2/pkg/runtime"
|
"github.com/wailsapp/wails/v2/pkg/runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
var json = jsoniter.ConfigFastest
|
|
||||||
|
|
||||||
const devVersionMarker = "v0.0.0-UNKNOWN"
|
const devVersionMarker = "v0.0.0-UNKNOWN"
|
||||||
|
|
||||||
var appVersion = devVersionMarker
|
var appVersion = devVersionMarker
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
package alerts
|
package alerts
|
||||||
|
|
||||||
import (
|
import (
|
||||||
jsoniter "github.com/json-iterator/go"
|
"encoding/json"
|
||||||
|
|
||||||
"github.com/nicklaw5/helix/v2"
|
"github.com/nicklaw5/helix/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -10,7 +11,7 @@ const ConfigKey = "twitch/alerts/config"
|
||||||
type eventSubNotification struct {
|
type eventSubNotification struct {
|
||||||
Subscription helix.EventSubSubscription `json:"subscription"`
|
Subscription helix.EventSubSubscription `json:"subscription"`
|
||||||
Challenge string `json:"challenge"`
|
Challenge string `json:"challenge"`
|
||||||
Event jsoniter.RawMessage `json:"event" desc:"Event payload, as JSON object"`
|
Event json.RawMessage `json:"event" desc:"Event payload, as JSON object"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type subscriptionVariation struct {
|
type subscriptionVariation struct {
|
||||||
|
|
|
@ -2,23 +2,23 @@ package chat
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"strings"
|
"strings"
|
||||||
textTemplate "text/template"
|
textTemplate "text/template"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/nicklaw5/helix/v2"
|
||||||
|
|
||||||
"git.sr.ht/~ashkeel/containers/sync"
|
"git.sr.ht/~ashkeel/containers/sync"
|
||||||
"git.sr.ht/~ashkeel/strimertul/database"
|
"git.sr.ht/~ashkeel/strimertul/database"
|
||||||
|
"git.sr.ht/~ashkeel/strimertul/twitch"
|
||||||
"git.sr.ht/~ashkeel/strimertul/twitch/eventsub"
|
"git.sr.ht/~ashkeel/strimertul/twitch/eventsub"
|
||||||
"git.sr.ht/~ashkeel/strimertul/twitch/template"
|
"git.sr.ht/~ashkeel/strimertul/twitch/template"
|
||||||
"git.sr.ht/~ashkeel/strimertul/utils"
|
"git.sr.ht/~ashkeel/strimertul/utils"
|
||||||
jsoniter "github.com/json-iterator/go"
|
|
||||||
"github.com/nicklaw5/helix/v2"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var json = jsoniter.ConfigFastest
|
|
||||||
|
|
||||||
type Module struct {
|
type Module struct {
|
||||||
Config Config
|
Config Config
|
||||||
|
|
||||||
|
@ -97,8 +97,8 @@ func (mod *Module) onChatMessage(newValue string) {
|
||||||
var chatMessage struct {
|
var chatMessage struct {
|
||||||
Event helix.EventSubChannelChatMessageEvent `json:"event"`
|
Event helix.EventSubChannelChatMessageEvent `json:"event"`
|
||||||
}
|
}
|
||||||
if err := json.UnmarshalFromString(newValue, &chatMessage); err != nil {
|
if err := json.Unmarshal([]byte(newValue), &chatMessage); err != nil {
|
||||||
mod.logger.Error("Failed to decode incoming chat message", "error", err)
|
mod.logger.Error("Failed to decode incoming chat message", slog.String("error", err.Error()))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -222,3 +222,39 @@ func (mod *Module) updateTemplates() error {
|
||||||
func (mod *Module) WriteMessage(request WriteMessageRequest) {
|
func (mod *Module) WriteMessage(request WriteMessageRequest) {
|
||||||
WriteMessage(mod.db, mod.logger, request)
|
WriteMessage(mod.db, mod.logger, request)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (mod *Module) RegisterCommand(name string, command Command) {
|
||||||
|
mod.commands.SetKey(name, command)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mod *Module) UnregisterCommand(name string) {
|
||||||
|
mod.commands.DeleteKey(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mod *Module) GetChatters() (users []string) {
|
||||||
|
cursor := ""
|
||||||
|
for {
|
||||||
|
userClient, err := twitch.GetUserClient(mod.db, false)
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("Could not get user api client for list of chatters", "error", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
res, err := userClient.GetChannelChatChatters(&helix.GetChatChattersParams{
|
||||||
|
BroadcasterID: mod.user.ID,
|
||||||
|
ModeratorID: mod.user.ID,
|
||||||
|
First: "1000",
|
||||||
|
After: cursor,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
mod.logger.Error("Could not retrieve list of chatters", "error", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for _, user := range res.Data.Chatters {
|
||||||
|
users = append(users, user.UserLogin)
|
||||||
|
}
|
||||||
|
cursor = res.Data.Pagination.Cursor
|
||||||
|
if cursor == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package eventsub
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"time"
|
"time"
|
||||||
|
@ -10,12 +11,9 @@ import (
|
||||||
"git.sr.ht/~ashkeel/strimertul/utils"
|
"git.sr.ht/~ashkeel/strimertul/utils"
|
||||||
"github.com/gorilla/websocket"
|
"github.com/gorilla/websocket"
|
||||||
lru "github.com/hashicorp/golang-lru/v2"
|
lru "github.com/hashicorp/golang-lru/v2"
|
||||||
jsoniter "github.com/json-iterator/go"
|
|
||||||
"github.com/nicklaw5/helix/v2"
|
"github.com/nicklaw5/helix/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
var json = jsoniter.ConfigFastest
|
|
||||||
|
|
||||||
const websocketEndpoint = "wss://eventsub.wss.twitch.tv/ws"
|
const websocketEndpoint = "wss://eventsub.wss.twitch.tv/ws"
|
||||||
|
|
||||||
type Client struct {
|
type Client struct {
|
||||||
|
@ -259,8 +257,8 @@ func topicCondition(topic string, id string) helix.EventSubCondition {
|
||||||
}
|
}
|
||||||
|
|
||||||
type WebsocketMessage struct {
|
type WebsocketMessage struct {
|
||||||
Metadata Metadata `json:"metadata"`
|
Metadata Metadata `json:"metadata"`
|
||||||
Payload jsoniter.RawMessage `json:"payload"`
|
Payload json.RawMessage `json:"payload"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type WelcomeMessagePayload struct {
|
type WelcomeMessagePayload struct {
|
||||||
|
@ -275,7 +273,7 @@ type WelcomeMessagePayload struct {
|
||||||
|
|
||||||
type NotificationMessagePayload struct {
|
type NotificationMessagePayload struct {
|
||||||
Subscription helix.EventSubSubscription `json:"subscription"`
|
Subscription helix.EventSubSubscription `json:"subscription"`
|
||||||
Event jsoniter.RawMessage `json:"event"`
|
Event json.RawMessage `json:"event"`
|
||||||
Date time.Time `json:"date,omitempty"`
|
Date time.Time `json:"date,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ package timers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/json"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"time"
|
"time"
|
||||||
|
@ -9,11 +10,8 @@ import (
|
||||||
"git.sr.ht/~ashkeel/containers/sync"
|
"git.sr.ht/~ashkeel/containers/sync"
|
||||||
"git.sr.ht/~ashkeel/strimertul/database"
|
"git.sr.ht/~ashkeel/strimertul/database"
|
||||||
"git.sr.ht/~ashkeel/strimertul/twitch/chat"
|
"git.sr.ht/~ashkeel/strimertul/twitch/chat"
|
||||||
jsoniter "github.com/json-iterator/go"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var json = jsoniter.ConfigFastest
|
|
||||||
|
|
||||||
const AverageMessageWindow = 5
|
const AverageMessageWindow = 5
|
||||||
|
|
||||||
type Module struct {
|
type Module struct {
|
||||||
|
@ -56,7 +54,7 @@ func Setup(ctx context.Context, db database.Database, logger *slog.Logger) *Modu
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := db.SubscribeKeyContext(ctx, ConfigKey, func(value string) {
|
if err := db.SubscribeKeyContext(ctx, ConfigKey, func(value string) {
|
||||||
if err := json.UnmarshalFromString(value, &mod.Config); err != nil {
|
if err := json.Unmarshal([]byte(value), &mod.Config); err != nil {
|
||||||
logger.Warn("Error reloading timer config", "error", err)
|
logger.Warn("Error reloading timer config", "error", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
package utils
|
package utils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"git.sr.ht/~ashkeel/containers/sync"
|
"git.sr.ht/~ashkeel/containers/sync"
|
||||||
jsoniter "github.com/json-iterator/go"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestLoadJSONToWrapped(t *testing.T) {
|
func TestLoadJSONToWrapped(t *testing.T) {
|
||||||
|
@ -17,7 +17,7 @@ func TestLoadJSONToWrapped(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Encode test object to JSON
|
// Encode test object to JSON
|
||||||
testStr, err := jsoniter.ConfigFastest.MarshalToString(testObj)
|
testByt, err := json.Marshal(testObj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,7 @@ func TestLoadJSONToWrapped(t *testing.T) {
|
||||||
wrapped := sync.NewSync[test](test{})
|
wrapped := sync.NewSync[test](test{})
|
||||||
|
|
||||||
// Load JSON to wrapped
|
// Load JSON to wrapped
|
||||||
err = LoadJSONToWrapped[test](testStr, wrapped)
|
err = LoadJSONToWrapped[test](string(testByt), wrapped)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue