mirror of
https://github.com/diamondburned/arikawa.git
synced 2025-03-22 18:09:21 +00:00
Added simple example
This commit is contained in:
parent
842daaa957
commit
2dc983d243
|
@ -1,7 +1,7 @@
|
|||
# arikawa
|
||||
|
||||
[](https://godoc.org/github.com/diamondburned/arikawa)
|
||||
[]()
|
||||
[](https://github.com/diamondburned/arikawa/tree/master/_example)
|
||||
[](https://discord.gg/kF9mYBV )
|
||||
[](https://hime-goto.fandom.com/wiki/Hime_Arikawa )
|
||||
|
||||
|
|
45
_example/simple/main.go
Normal file
45
_example/simple/main.go
Normal file
|
@ -0,0 +1,45 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/diamondburned/arikawa/gateway"
|
||||
"github.com/diamondburned/arikawa/session"
|
||||
)
|
||||
|
||||
// To run, do `BOT_TOKEN="TOKEN HERE" go run .`
|
||||
|
||||
func main() {
|
||||
var token = os.Getenv("BOT_TOKEN")
|
||||
if token == "" {
|
||||
log.Fatalln("No $BOT_TOKEN given.")
|
||||
}
|
||||
|
||||
s, err := session.New("Bot " + token)
|
||||
if err != nil {
|
||||
log.Fatalln("Session failed:", err)
|
||||
}
|
||||
|
||||
s.AddHandler(func(c *gateway.MessageCreateEvent) {
|
||||
log.Println(c.Author.Username, "sent", c.Content)
|
||||
})
|
||||
|
||||
if err := s.Open(); err != nil {
|
||||
log.Fatalln("Failed to connect:", err)
|
||||
}
|
||||
|
||||
defer s.Close()
|
||||
|
||||
u, err := s.Me()
|
||||
if err != nil {
|
||||
log.Fatalln("Failed to get myself:", err)
|
||||
}
|
||||
|
||||
log.Println("Started as", u.Username)
|
||||
|
||||
// Wait is optional.
|
||||
if err := s.Wait(); err != nil {
|
||||
log.Fatalln("Fatal error:", err)
|
||||
}
|
||||
}
|
|
@ -1,32 +1,47 @@
|
|||
package discord
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const DiscordEpoch = 1420070400000 * int64(time.Millisecond)
|
||||
|
||||
type Snowflake uint64
|
||||
type Snowflake int64
|
||||
|
||||
func NewSnowflake(t time.Time) Snowflake {
|
||||
return Snowflake(TimeToDiscordEpoch(t) << 22)
|
||||
}
|
||||
|
||||
const Me = Snowflake(-1)
|
||||
|
||||
func (s *Snowflake) UnmarshalJSON(v []byte) error {
|
||||
v = bytes.Trim(v, `"`)
|
||||
u, err := strconv.ParseUint(string(v), 10, 64)
|
||||
id := strings.Trim(string(v), `"`)
|
||||
if id == "null" {
|
||||
return nil
|
||||
}
|
||||
|
||||
i, err := strconv.ParseInt(id, 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*s = Snowflake(u)
|
||||
*s = Snowflake(i)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Snowflake) MarshalJSON() ([]byte, error) {
|
||||
return []byte(`"` + strconv.FormatUint(uint64(*s), 10) + `"`), nil
|
||||
var id string
|
||||
|
||||
switch i := int64(*s); i {
|
||||
case -1: // @me
|
||||
id = "@me"
|
||||
default:
|
||||
id = strconv.FormatInt(i, 10)
|
||||
}
|
||||
|
||||
return []byte(`"` + id + `"`), nil
|
||||
}
|
||||
|
||||
func (s Snowflake) String() string {
|
||||
|
|
|
@ -2,6 +2,7 @@ package discord
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
@ -15,7 +16,12 @@ var (
|
|||
)
|
||||
|
||||
func (t *Timestamp) UnmarshalJSON(v []byte) error {
|
||||
r, err := time.Parse(TimestampFormat, string(v))
|
||||
str := strings.Trim(string(v), `"`)
|
||||
if str == "null" {
|
||||
return nil
|
||||
}
|
||||
|
||||
r, err := time.Parse(TimestampFormat, str)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -40,6 +40,9 @@ var (
|
|||
WSRetries = uint(5)
|
||||
// WSError is the default error handler
|
||||
WSError = func(err error) {}
|
||||
// WSExtraReadTimeout is the duration to be added to Hello, as a read
|
||||
// timeout for the websocket.
|
||||
WSExtraReadTimeout = time.Second
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -138,7 +141,7 @@ func NewGatewayWithDriver(token string, driver json.Driver) (*Gateway, error) {
|
|||
g.WS = ws
|
||||
|
||||
// Try and dial it
|
||||
return g, g.connect()
|
||||
return g, nil
|
||||
}
|
||||
|
||||
// Close closes the underlying Websocket connection.
|
||||
|
@ -158,7 +161,53 @@ func (g *Gateway) Reconnect() error {
|
|||
// Close, but we don't care about the error (I think)
|
||||
g.Close()
|
||||
// Actually a reconnect at this point.
|
||||
return g.connect()
|
||||
return g.Open()
|
||||
}
|
||||
|
||||
func (g *Gateway) Open() error {
|
||||
// Reconnect timeout
|
||||
ctx, cancel := context.WithTimeout(context.Background(), g.WSTimeout)
|
||||
defer cancel()
|
||||
|
||||
var Lerr error
|
||||
|
||||
for i := uint(0); i < g.WSRetries; i++ {
|
||||
// Check if context is expired
|
||||
if err := ctx.Err(); err != nil {
|
||||
// Don't bother if it's expired
|
||||
return err
|
||||
}
|
||||
|
||||
// Reconnect to the Gateway
|
||||
if err := g.WS.Redial(ctx); err != nil {
|
||||
// Save the error, retry again
|
||||
Lerr = errors.Wrap(err, "Failed to reconnect")
|
||||
continue
|
||||
}
|
||||
|
||||
// Try to resume the connection
|
||||
if err := g.Start(); err != nil {
|
||||
// If the connection is rate limited (documented behavior):
|
||||
// https://discordapp.com/developers/docs/topics/gateway#rate-limiting
|
||||
if err == ErrInvalidSession {
|
||||
continue // retry
|
||||
}
|
||||
|
||||
// Else, fatal
|
||||
return errors.Wrap(err, "Failed to start gateway")
|
||||
}
|
||||
|
||||
// Started successfully, return
|
||||
return nil
|
||||
}
|
||||
|
||||
// Check if any earlier errors are fatal
|
||||
if Lerr != nil {
|
||||
return Lerr
|
||||
}
|
||||
|
||||
// We tried.
|
||||
return ErrWSMaxTries
|
||||
}
|
||||
|
||||
// Start authenticates with the websocket, or resume from a dead Websocket
|
||||
|
@ -254,49 +303,3 @@ func (g *Gateway) Send(code OPCode, v interface{}) error {
|
|||
|
||||
return g.WS.Send(ctx, b)
|
||||
}
|
||||
|
||||
func (g *Gateway) connect() error {
|
||||
// Reconnect timeout
|
||||
ctx, cancel := context.WithTimeout(context.Background(), g.WSTimeout)
|
||||
defer cancel()
|
||||
|
||||
var Lerr error
|
||||
|
||||
for i := uint(0); i < g.WSRetries; i++ {
|
||||
// Check if context is expired
|
||||
if err := ctx.Err(); err != nil {
|
||||
// Don't bother if it's expired
|
||||
return err
|
||||
}
|
||||
|
||||
// Reconnect to the Gateway
|
||||
if err := g.WS.Redial(ctx); err != nil {
|
||||
// Save the error, retry again
|
||||
Lerr = errors.Wrap(err, "Failed to reconnect")
|
||||
continue
|
||||
}
|
||||
|
||||
// Try to resume the connection
|
||||
if err := g.Start(); err != nil {
|
||||
// If the connection is rate limited (documented behavior):
|
||||
// https://discordapp.com/developers/docs/topics/gateway#rate-limiting
|
||||
if err == ErrInvalidSession {
|
||||
continue // retry
|
||||
}
|
||||
|
||||
// Else, fatal
|
||||
return errors.Wrap(err, "Failed to start gateway")
|
||||
}
|
||||
|
||||
// Started successfully, return
|
||||
return nil
|
||||
}
|
||||
|
||||
// Check if any earlier errors are fatal
|
||||
if Lerr != nil {
|
||||
return Lerr
|
||||
}
|
||||
|
||||
// We tried.
|
||||
return ErrWSMaxTries
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@ import (
|
|||
"context"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/diamondburned/arikawa/internal/json"
|
||||
"github.com/pkg/errors"
|
||||
|
@ -43,8 +42,6 @@ type Conn struct {
|
|||
*websocket.Conn
|
||||
json.Driver
|
||||
|
||||
ReadTimeout time.Duration // DefaultTimeout
|
||||
|
||||
events chan Event
|
||||
}
|
||||
|
||||
|
@ -52,9 +49,8 @@ var _ Connection = (*Conn)(nil)
|
|||
|
||||
func NewConn(driver json.Driver) *Conn {
|
||||
return &Conn{
|
||||
Driver: driver,
|
||||
ReadTimeout: DefaultTimeout,
|
||||
events: make(chan Event, WSBuffer),
|
||||
Driver: driver,
|
||||
events: make(chan Event, WSBuffer),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -81,11 +77,7 @@ func (c *Conn) Listen() <-chan Event {
|
|||
|
||||
func (c *Conn) readLoop(ch chan Event) {
|
||||
for {
|
||||
ctx, cancel := context.WithTimeout(
|
||||
context.Background(), c.ReadTimeout)
|
||||
defer cancel()
|
||||
|
||||
b, err := c.readAll(ctx)
|
||||
b, err := c.readAll(context.Background())
|
||||
if err != nil {
|
||||
// Check if the error is a fatal one
|
||||
if code := websocket.CloseStatus(err); code > -1 {
|
||||
|
|
|
@ -69,7 +69,7 @@ func NewWithGateway(gw *gateway.Gateway) *Session {
|
|||
}
|
||||
|
||||
func (s *Session) Open() error {
|
||||
if err := s.gateway.Start(); err != nil {
|
||||
if err := s.gateway.Open(); err != nil {
|
||||
return errors.Wrap(err, "Failed to start gateway")
|
||||
}
|
||||
|
||||
|
@ -91,6 +91,10 @@ func (s *Session) startHandler(stop <-chan struct{}) {
|
|||
}
|
||||
}
|
||||
|
||||
func (s *Session) Wait() error {
|
||||
return s.gateway.Wait()
|
||||
}
|
||||
|
||||
func (s *Session) Close() error {
|
||||
// Stop the event handler
|
||||
if s.hstop != nil {
|
||||
|
|
|
@ -56,6 +56,7 @@ func (s *State) hookSession() error {
|
|||
}
|
||||
|
||||
switch ev := iface.(type) {
|
||||
case *gateway.ReadyEvent:
|
||||
case *gateway.MessageCreateEvent:
|
||||
_ = ev
|
||||
panic("IMPLEMENT ME")
|
||||
|
|
Loading…
Reference in a new issue