]> git.openfl.eu Git - twitch-chat.git/commitdiff
fixes and client
authorFl_GUI <flor.guilini@hotmail.com>
Thu, 9 May 2024 18:36:26 +0000 (20:36 +0200)
committerFl_GUI <flor.guilini@hotmail.com>
Thu, 9 May 2024 18:36:26 +0000 (20:36 +0200)
17 files changed:
irc/string.go
twitch/core/auth.go
twitch/core/capabilities.go
twitch/core/commands/commands.go
twitch/core/connection.go
twitch/core/errors.go
twitch/core/join.go
twitch/core/messages/acknak.go [deleted file]
twitch/core/messages/auth.go
twitch/core/messages/capability.go
twitch/core/messages/messages.go
twitch/core/messages/ping.go
x/clichat/go.mod [new file with mode: 0644]
x/clichat/go.sum [new file with mode: 0644]
x/corechatclient/corechatclient [new file with mode: 0755]
x/corechatclient/main.go [new file with mode: 0644]
x/corechatclient/out [new file with mode: 0644]

index aed67a46ab423da7f4c3f4ff49dfb6daf23e6b22..9482c0766a0b0e9698d8d5b1963811687e8fa459 100644 (file)
@@ -1,6 +1,7 @@
 package irc
 
 import (
+       "bytes"
        "io"
        "strings"
 )
@@ -15,11 +16,16 @@ func (c Message) String() string {
 // Writes the message to a io.Writer, using WriteString if implemented.
 // Returns total number of bytes written and first error encountered
 func (c Message) WriteTo(w io.Writer) (n int, err error) {
+       buff := new(bytes.Buffer)
+
+       defer buff.Write([]byte{'\r', '\n'})
+       defer io.Copy(w, buff)
+
        n = 0
        m := 0
        write := func(s string) {
                if err == nil {
-                       m, err = io.WriteString(w, s)
+                       m, err = io.WriteString(buff, s)
                        n += m
                }
        }
index 9f1b4ae85408b8c62e4865ea42d484f9a785275f..452f53156fe7bf25226af885bbb791f4dd6c52ae 100644 (file)
@@ -26,14 +26,16 @@ func (c *Conn) Authenticate(nickname, access_token string, msgs <-chan messages.
                        case "375":
                                fallthrough
                        case "372":
-                               fallthrough
+                               authResp <- msg
                        case "376":
                                authResp <- msg
+                               close(authResp)
                        case commands.Notice:
                                err := msg.ToNoticeError()
                                if errors.Is(err, messages.LoginFailedError) ||
                                        errors.Is(err, messages.InvalidAuthError) {
                                        authResp <- msg
+                                       close(authResp)
                                } else {
                                        res <- msg
                                }
index 6b4dbb684ad3b1bc2aa78a56e3385a5d55bcc53b..e80ca60ecc894296081548981429125a91def982 100644 (file)
@@ -22,19 +22,42 @@ func (c *Conn) WithCapability(msgs <-chan messages.Message, capabilities ...stri
                return msgs, fmt.Errorf("TagsCapability is unavailable: %v", errors.ErrUnsupported)
        }
 
+       res := make(chan messages.Message)
+       capResp := make(chan messages.Message, 2)
+
+       go func() {
+               requestedCount := len(capabilities)
+               receivedCount := 0
+               for msg := range msgs {
+                       if requestedCount == receivedCount || !messages.IsCapAckNak(msg) {
+                               res <- msg
+                               continue
+                       }
+                       capResp <- msg
+
+                       if msg.Params.Trailing != "" {
+                               receivedCount += strings.Count(msg.Params.Trailing, " ") + 1
+                               if receivedCount == requestedCount {
+                                       close(capResp)
+                               }
+                       }
+               }
+       }()
+
        c.WriteMessage(messages.Capability(caps))
-       msg := <-msgs
-
-       if messages.IsAck(msg) {
-               fmt.Fprintln(DebugLogger, "Capability request acknowledged")
-       } else if messages.IsNak(msg) {
-               badCaps := strings.Split(msg.Params.Trailing, " ")
-               return msgs, unsupportedCapabilities(badCaps)
-       } else {
-               // code error
-               fmt.Fprintf(DebugLogger, "Unexpected message after capability request: %v\n", msg)
-               return msgs, UnexpectedAnswerError
+
+       for msg := range capResp {
+               if messages.IsCapAck(msg) {
+                       fmt.Fprintln(DebugLogger, "Capability request acknowledged")
+               } else if messages.IsCapNak(msg) {
+                       badCaps := strings.Split(msg.Params.Trailing, " ")
+                       return res, UnsupportedCapabilities(badCaps)
+               } else {
+                       // code error
+                       fmt.Fprintf(DebugLogger, "Unexpected message after capability request: %v\n", msg)
+                       return res, UnexpectedAnswerError
+               }
        }
 
-       return msgs, nil
+       return res, nil
 }
index 1f47e7d7270b3d118c0ae848790cad0d1743aee1..5769dffe83bacf77c91694a425f02577436a64ee 100644 (file)
@@ -14,8 +14,6 @@ const (
 
        // not documented on the main page
        Cap = "CAP"
-       Ack = "ACK"
-       Nak = "NAK"
 
        // twitch specific IRC messages. These are all receive only
        ClearChat       = "CLEARCHAT"
index aea4ea676237afce4e04f7ea7191fddba7b62e32..149b6805ca6552efb3315680d5ab82ec2695bb39 100644 (file)
@@ -24,18 +24,13 @@ func Dial(origin string) (*Conn, error) {
 }
 
 func DialNoSsl(origin string) (*Conn, error) {
-       c, err := irc.Dial("wss://irc-ws.chat.twitch.tv:80", origin)
+       c, err := irc.Dial("ws://irc-ws.chat.twitch.tv:80", origin)
        return (*Conn)(c), err
 }
 
 func (w *Conn) WriteMessage(m messages.Message) error {
-       fmt.Fprintf(DebugLogger, "Writing %v\n", m)
-       if _, err := irc.Message(m).WriteTo(w); err != nil {
-               return err
-       }
-
-       // termination bytes
-       _, err := w.Write([]byte{'\r', '\n'})
+       fmt.Fprintf(DebugLogger, "Writing %#v\n", irc.Message(m).String())
+       _, err := irc.Message(m).WriteTo(w)
        return err
 }
 
@@ -53,6 +48,8 @@ func (w *Conn) ReadMessages() <-chan messages.Message {
                        msg, err := irc.ParseBytes(bytes)
                        if err != nil {
                                fmt.Fprintf(DebugLogger, "Could not parse %#v\n", bytes)
+                       } else {
+                               fmt.Fprintf(DebugLogger, "Received %s\n", irc.Message(msg))
                        }
                        res <- messages.Message(msg)
                }
index 0e25328d9de36e006c78b401272843d58f7f5eaf..3acc5aa8ef3c1a615db7f02d936526486adeaa30 100644 (file)
@@ -6,19 +6,19 @@ import (
        "strings"
 )
 
-type unsupportedCapabilities []string
+type UnsupportedCapabilities []string
 
 var UnexpectedAnswerError = errors.New("Unexpected result")
 var UnsupportedCapabilitiesError = errors.New("unsupported capabilities")
 
-func (u unsupportedCapabilities) Unwrap() error {
+func (u UnsupportedCapabilities) Unwrap() error {
        return UnsupportedCapabilitiesError
 }
 
-func (u unsupportedCapabilities) Error() string {
+func (u UnsupportedCapabilities) Error() string {
        return fmt.Sprintf("cannot request capabilities %v: %v", strings.Join(u, ", "), UnsupportedCapabilitiesError)
 }
 
-func (u unsupportedCapabilities) Is(target error) bool {
+func (u UnsupportedCapabilities) Is(target error) bool {
        return target == UnsupportedCapabilitiesError
 }
index 88bd7d0649f9985fbc70bca2d24e1fcfb276787d..a82baa4a8f972b86ac7bb9c737548e7efb92a236 100644 (file)
@@ -1,6 +1,9 @@
 package core
 
-import "twitchchat/twitch/core/messages"
+import (
+       "fmt"
+       "twitchchat/twitch/core/messages"
+)
 
 type ChannelMembers map[string][]string
 
@@ -8,10 +11,11 @@ func (w *Conn) Join(msgs <-chan messages.Message, channels ...string) (<-chan me
 
        w.WriteMessage(messages.Join(channels...))
 
-       var channelMembers ChannelMembers
+       channelMembers := make(ChannelMembers)
        for _, c := range channels {
                resp := <-msgs
 
+               fmt.Fprintf(DebugLogger, "Reading channel members for %s\n", resp)
                if messages.IsNotice(resp) {
                        return msgs, channelMembers, resp.ToNoticeError()
                } else if !messages.IsJoin(resp) {
diff --git a/twitch/core/messages/acknak.go b/twitch/core/messages/acknak.go
deleted file mode 100644 (file)
index b30bf4b..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-package messages
-
-import "twitchchat/twitch/core/commands"
-
-func IsAckNak(m Message) bool {
-       return IsAck(m) || IsNak(m)
-}
-
-func IsAck(m Message) bool {
-       return m.Command == commands.Ack
-}
-
-func IsNak(m Message) bool {
-       return m.Command == commands.Nak
-}
index ddab51c7e4b1c2170d228a119dacabb7d838730f..6993819fce13853ffa5a89ea5068092f831a1707 100644 (file)
@@ -11,7 +11,7 @@ func Pass(nickname string) Message {
                irc.Prefix{},
                irc.Command(commands.Pass),
                irc.Params{
-                       []string{fmt.Sprintf("oath:%s", nickname)},
+                       []string{fmt.Sprintf("oauth:%s", nickname)},
                        "",
                },
        }
index 0a472e1e4b1ba60df3919c9d36d5cc0b89533c93..cff9ce81ad6a619c910e9a73b4a3d585f9b5b4d3 100644 (file)
@@ -10,8 +10,26 @@ func Capability(capability string) Message {
                irc.Prefix{},
                irc.Command(commands.Cap),
                irc.Params{
-                       []string{},
+                       []string{"REQ"},
                        capability,
                },
        }
 }
+
+func IsCapAckNak(m Message) bool {
+       return IsCapAck(m) || IsCapNak(m)
+}
+
+func IsCapAck(m Message) bool {
+       return m.Command == commands.Cap &&
+               len(m.Params.Params) == 2 &&
+               m.Params.Params[0] == "*" &&
+               m.Params.Params[1] == "ACK"
+}
+
+func IsCapNak(m Message) bool {
+       return m.Command == commands.Cap &&
+               len(m.Params.Params) == 2 &&
+               m.Params.Params[0] == "*" &&
+               m.Params.Params[1] == "NAK"
+}
index 872f0b4d785bcc891186ee9f5386623011c51606..6605b727727ef5a8fae9a26b58924293d1b18110 100644 (file)
@@ -3,3 +3,7 @@ package messages
 import "twitchchat/irc"
 
 type Message irc.Message
+
+func (m Message) String() string {
+       return irc.Message(m).String()
+}
index 220f95f3fc1634169c736e77ee724f3ffff46e29..0e5d96301851324c9877b8a4c3d6e515b795aed6 100644 (file)
@@ -13,10 +13,18 @@ func (p Message) Text() string {
        return irc.Message(p).Params.Trailing
 }
 
+func Ping(s string) Message {
+       return Message{
+               irc.Prefix{},
+               irc.Command(commands.Ping),
+               irc.Params{[]string{s}, ""},
+       }
+}
+
 func (p Message) ToPong() Message {
        return Message{
                irc.Prefix{},
                irc.Command(commands.Pong),
-               irc.Params{[]string{}, p.Text()},
+               irc.Params{[]string{p.Text()}, ""},
        }
 }
diff --git a/x/clichat/go.mod b/x/clichat/go.mod
new file mode 100644 (file)
index 0000000..2caf2f3
--- /dev/null
@@ -0,0 +1,5 @@
+module clichat
+
+go 1.22.3
+
+require golang.org/x/net v0.25.0
diff --git a/x/clichat/go.sum b/x/clichat/go.sum
new file mode 100644 (file)
index 0000000..ec14cb3
--- /dev/null
@@ -0,0 +1,2 @@
+golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
+golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
diff --git a/x/corechatclient/corechatclient b/x/corechatclient/corechatclient
new file mode 100755 (executable)
index 0000000..468bc3d
Binary files /dev/null and b/x/corechatclient/corechatclient differ
diff --git a/x/corechatclient/main.go b/x/corechatclient/main.go
new file mode 100644 (file)
index 0000000..a4745f5
--- /dev/null
@@ -0,0 +1,46 @@
+package main
+
+import (
+       "errors"
+       "fmt"
+       "os"
+       "twitchchat/twitch/core"
+       "twitchchat/twitch/core/messages"
+)
+
+func main() {
+       conn, err := core.Dial("http://localhost")
+       if err != nil {
+               panic(err)
+       }
+       defer conn.Close()
+
+       core.DebugLogger = os.Stdout
+
+       msgs := conn.ReadMessages()
+
+       conn.WriteMessage(messages.Ping("foobar"))
+       <-msgs
+
+       if msgs, err = conn.Authenticate("fl_gui", "511j9db3a4xqk8jdukj11nh1eok2d2", msgs); err != nil {
+               panic(err)
+       }
+
+       if msgs, err = conn.WithCapability(msgs, core.MembershipCapability, "Unknown", "foobar"); err != nil {
+               if errors.Is(err, core.UnsupportedCapabilitiesError) {
+                       fmt.Printf("%#v\n", err.(core.UnsupportedCapabilities))
+               } else {
+                       panic(err)
+               }
+       }
+
+       var members core.ChannelMembers
+       if msgs, members, err = conn.Join(msgs, "fl_gui"); err != nil {
+               panic(err)
+       }
+  fmt.Printf("current members: %s", members)
+
+       for m := range msgs {
+               fmt.Println(m)
+       }
+}
diff --git a/x/corechatclient/out b/x/corechatclient/out
new file mode 100644 (file)
index 0000000..35e4cf6
--- /dev/null
@@ -0,0 +1 @@
+signal: interrupt