added DM support, mostly working

This commit is contained in:
diamondburned 2020-12-19 21:44:26 -08:00
parent 6c1a11706f
commit 918719599f
51 changed files with 580 additions and 356 deletions

4
go.mod
View File

@ -3,9 +3,9 @@ module github.com/diamondburned/cchat-discord
go 1.14
require (
github.com/diamondburned/arikawa v1.3.6
github.com/diamondburned/arikawa/v2 v2.0.0-20201220032235-088b30430377
github.com/diamondburned/cchat v0.3.15
github.com/diamondburned/ningen v0.2.1-0.20201023061015-ce64ffb0bb12
github.com/diamondburned/ningen/v2 v2.0.0-20201220054153-c69c4f7057b4
github.com/dustin/go-humanize v1.0.0
github.com/go-test/deep v1.0.7
github.com/lithammer/fuzzysearch v1.1.1

42
go.sum
View File

@ -42,9 +42,25 @@ github.com/diamondburned/arikawa v1.2.0 h1:3dFmpk/G4UwO+Kto0tXd5AbaCKC9KH2ZfnA8U
github.com/diamondburned/arikawa v1.2.0/go.mod h1:nIhVIatzTQhPUa7NB8w4koG1RF9gYbpAr8Fj8sKq660=
github.com/diamondburned/arikawa v1.3.0 h1:up5q5Ya/QbiFqhMejvl+c03YdsgzkzspsJOWW30A2lk=
github.com/diamondburned/arikawa v1.3.0/go.mod h1:nIhVIatzTQhPUa7NB8w4koG1RF9gYbpAr8Fj8sKq660=
github.com/diamondburned/arikawa v1.3.2 h1:ftWgP95IJGXNvCvtO5x0QBYsnFSnIBY0SvDdGoC3ILA=
github.com/diamondburned/arikawa v1.3.2/go.mod h1:nIhVIatzTQhPUa7NB8w4koG1RF9gYbpAr8Fj8sKq660=
github.com/diamondburned/arikawa v1.3.6 h1:DhxWDO4fyXAZ4VFrWdJOqiiJKJRpkrehGJwPtZ2eos0=
github.com/diamondburned/arikawa v1.3.6/go.mod h1:nIhVIatzTQhPUa7NB8w4koG1RF9gYbpAr8Fj8sKq660=
github.com/diamondburned/arikawa/v2 v2.0.0-20201208195035-9911a3d6627a/go.mod h1:e+lhS20ni2luFEU06Pc8paCxgZL99/RZb77dOC82CF0=
github.com/diamondburned/arikawa/v2 v2.0.0-20201218230021-9df396bb7f14 h1:2+j49uXPC44gEFstt0hlY17Wz88HU7DXgOmQmgIf28E=
github.com/diamondburned/arikawa/v2 v2.0.0-20201218230021-9df396bb7f14/go.mod h1:e+lhS20ni2luFEU06Pc8paCxgZL99/RZb77dOC82CF0=
github.com/diamondburned/arikawa/v2 v2.0.0-20201219061804-88911a7d1117 h1:n769tNSjYU2EDCkM3PBLTaB0LQwN9Sr3Rab9KXVxhoc=
github.com/diamondburned/arikawa/v2 v2.0.0-20201219061804-88911a7d1117/go.mod h1:e+lhS20ni2luFEU06Pc8paCxgZL99/RZb77dOC82CF0=
github.com/diamondburned/arikawa/v2 v2.0.0-20201219063311-c9dd51aeb654 h1:z4/LcUUQ/B7l3+G1fh16/ByW206/oueKLANdygetEyA=
github.com/diamondburned/arikawa/v2 v2.0.0-20201219063311-c9dd51aeb654/go.mod h1:e+lhS20ni2luFEU06Pc8paCxgZL99/RZb77dOC82CF0=
github.com/diamondburned/arikawa/v2 v2.0.0-20201219065126-f11edb7260b2 h1:73ukkYNYZztR3wUXzeyza6AG4zBZjA8ER6qO0QGZPPA=
github.com/diamondburned/arikawa/v2 v2.0.0-20201219065126-f11edb7260b2/go.mod h1:e+lhS20ni2luFEU06Pc8paCxgZL99/RZb77dOC82CF0=
github.com/diamondburned/arikawa/v2 v2.0.0-20201219075756-36c2f166becd h1:HCaw0YrlQWKTao7QE6s8tjYImZEpH7Lad85bnYel1V0=
github.com/diamondburned/arikawa/v2 v2.0.0-20201219075756-36c2f166becd/go.mod h1:/vapSS3yfYRAt5hhgI6JiPkca+wKhgi0MdanT1dBBQY=
github.com/diamondburned/arikawa/v2 v2.0.0-20201220000828-3e2814748f9a h1:aA8K3+JfXdJPcK9Ms4WmHLGp+qnKT0VuNWOUZUP9YpY=
github.com/diamondburned/arikawa/v2 v2.0.0-20201220000828-3e2814748f9a/go.mod h1:e+lhS20ni2luFEU06Pc8paCxgZL99/RZb77dOC82CF0=
github.com/diamondburned/arikawa/v2 v2.0.0-20201220032235-088b30430377 h1:71BLnECSl0/Ns7iZmEm7MpE5+qSuWw/BQBQY2XCUmVc=
github.com/diamondburned/arikawa/v2 v2.0.0-20201220032235-088b30430377/go.mod h1:e+lhS20ni2luFEU06Pc8paCxgZL99/RZb77dOC82CF0=
github.com/diamondburned/cchat v0.0.34 h1:BGiVxMRA9dmW3rLilIldBvjVan7eTTpaWCCfX9IKBYU=
github.com/diamondburned/cchat v0.0.34/go.mod h1:+zXktogE45A0om4fT6B/z6Ii7FXNafjxsNspI0rlhbU=
github.com/diamondburned/cchat v0.0.35 h1:WiMGl8BQJgbP9E4xRxgLGlqUsHpTcJgDKDt8/6a7lBk=
@ -163,6 +179,24 @@ github.com/diamondburned/ningen v0.1.1-0.20200820222640-35796f938a58 h1:sQvq5Dgm
github.com/diamondburned/ningen v0.1.1-0.20200820222640-35796f938a58/go.mod h1:aXm69MB+Qu04OjBiixQw28zRijDc49vruMJMaHZ2c0Q=
github.com/diamondburned/ningen v0.2.1-0.20201023061015-ce64ffb0bb12 h1:hcabAq2jPmEhrfSRrl2hHkpQXtPTIh7L58fvCxBO/C4=
github.com/diamondburned/ningen v0.2.1-0.20201023061015-ce64ffb0bb12/go.mod h1:TcvJV0bK4bp7t+7m29/Tz9dCqgA0sJBKM/Igt0WkvT4=
github.com/diamondburned/ningen v1.0.0 h1:fr+7oDWA0Db73CuVeLY8SScWdW6ft/aWwkULXD0flKw=
github.com/diamondburned/ningen v1.0.0/go.mod h1:TcvJV0bK4bp7t+7m29/Tz9dCqgA0sJBKM/Igt0WkvT4=
github.com/diamondburned/ningen/v2 v2.0.0-20201210080809-a14408097980 h1:g/ndgdW9sdL2KEIORhbRafnwreDksZVTPQtRF3SgriU=
github.com/diamondburned/ningen/v2 v2.0.0-20201210080809-a14408097980/go.mod h1:ub/rJpU3cD1Izpa1g+JDuzmtbfP/grV2ZSK5GzL94nc=
github.com/diamondburned/ningen/v2 v2.0.0-20201219070301-15610044db9a h1:w8CWPYiwH9p2XGlHHeTqRWx7e8CJJLN8i4orAkOa27Y=
github.com/diamondburned/ningen/v2 v2.0.0-20201219070301-15610044db9a/go.mod h1:Pw4ZPQmZUonCytlKhHgan98CZeCQ4AWh0DWqvnhsuNE=
github.com/diamondburned/ningen/v2 v2.0.0-20201219225720-58beeea47f6d h1:2DWG8srhOrOJDffCk37L66p5yLJssY5wGdt7OPd7Y68=
github.com/diamondburned/ningen/v2 v2.0.0-20201219225720-58beeea47f6d/go.mod h1:9ZWVTlDzwR0/tGFrBF6iiQV8qPXlJSKsIqRIRyXtDDU=
github.com/diamondburned/ningen/v2 v2.0.0-20201219233304-7023c9c95229 h1:Or3Qy+gwKeIECMv2S9rWsF3xRy90kpHKgCgmixG7ybE=
github.com/diamondburned/ningen/v2 v2.0.0-20201219233304-7023c9c95229/go.mod h1:9ZWVTlDzwR0/tGFrBF6iiQV8qPXlJSKsIqRIRyXtDDU=
github.com/diamondburned/ningen/v2 v2.0.0-20201219234158-543154247f29 h1:rwyTYHlPHSO8dAAqgeSIaXLQLPlX1NC8Ebd1py1JTVg=
github.com/diamondburned/ningen/v2 v2.0.0-20201219234158-543154247f29/go.mod h1:9ZWVTlDzwR0/tGFrBF6iiQV8qPXlJSKsIqRIRyXtDDU=
github.com/diamondburned/ningen/v2 v2.0.0-20201219235002-2c75ebf8f5fc h1:cV3WgIGTNeh8MFqRRgcxjgjTLBrU/1h24jVEeA2qySg=
github.com/diamondburned/ningen/v2 v2.0.0-20201219235002-2c75ebf8f5fc/go.mod h1:9ZWVTlDzwR0/tGFrBF6iiQV8qPXlJSKsIqRIRyXtDDU=
github.com/diamondburned/ningen/v2 v2.0.0-20201220032656-1096439b9379 h1:gcmMWHBtgJD+HVDQqSoy1C5L4g1CVSYadwrdeYgVL30=
github.com/diamondburned/ningen/v2 v2.0.0-20201220032656-1096439b9379/go.mod h1:2ZjyeHqO9jCdlfmJhhVhk8eCumx418n39uVaC/LgEgY=
github.com/diamondburned/ningen/v2 v2.0.0-20201220054153-c69c4f7057b4 h1:qzh5ghfgvUllilOhkrGP29IGQT6DGfcc3lhk9uSA6nU=
github.com/diamondburned/ningen/v2 v2.0.0-20201220054153-c69c4f7057b4/go.mod h1:2ZjyeHqO9jCdlfmJhhVhk8eCumx418n39uVaC/LgEgY=
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
@ -199,6 +233,8 @@ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/gorilla/schema v1.1.0 h1:CamqUDOFUBqzrvxuz2vEwo8+SUdwsluFh7IlzJh30LY=
github.com/gorilla/schema v1.1.0/go.mod h1:kgLaKoK1FELgZqMAVxx/5cbj0kT+57qxUrAlIO2eleU=
github.com/gorilla/schema v1.2.0 h1:YufUaxZYCKGFuAq3c96BOhjgd5nmXiOY9NGzF247Tsc=
github.com/gorilla/schema v1.2.0/go.mod h1:kgLaKoK1FELgZqMAVxx/5cbj0kT+57qxUrAlIO2eleU=
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
@ -206,6 +242,8 @@ github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
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/kawasin73/umutex v0.2.1 h1:Onkzz3LKs1HThskVwdhhBocqdRQqwCZ03quDJzuPzPo=
github.com/kawasin73/umutex v0.2.1/go.mod h1:A02N2muKVFMvFlp5c+hBycgdH964YtieGs+7mYB16NU=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
@ -237,6 +275,7 @@ golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200423211502-4bdfaf469ed5/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@ -300,6 +339,7 @@ golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201018230417-eeed37f84f13/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@ -309,6 +349,8 @@ golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxb
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1 h1:NusfzzA6yGQ+ua51ck7E3omNUX/JuqbFSaRGqU8CcLI=
golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e h1:EHBhcS0mlXEAVwNyO2dLfjToGsyY4j24pTs2ScHnX7s=
golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=

View File

@ -1,7 +1,7 @@
package authenticate
import (
"github.com/diamondburned/arikawa/api"
"github.com/diamondburned/arikawa/v2/api"
"github.com/diamondburned/cchat"
"github.com/diamondburned/cchat-discord/internal/discord/session"
"github.com/diamondburned/cchat-discord/internal/discord/state"

View File

@ -1,7 +1,7 @@
package authenticate
import (
"github.com/diamondburned/arikawa/api"
"github.com/diamondburned/arikawa/v2/api"
"github.com/diamondburned/cchat"
"github.com/diamondburned/cchat-discord/internal/discord/session"
"github.com/diamondburned/cchat-discord/internal/discord/state"

View File

@ -3,7 +3,7 @@ package category
import (
"sort"
"github.com/diamondburned/arikawa/discord"
"github.com/diamondburned/arikawa/v2/discord"
"github.com/diamondburned/cchat"
"github.com/diamondburned/cchat-discord/internal/discord/channel"
"github.com/diamondburned/cchat-discord/internal/discord/state"

View File

@ -1,11 +1,15 @@
package channel
import (
"github.com/diamondburned/arikawa/discord"
"context"
"github.com/diamondburned/arikawa/v2/discord"
"github.com/diamondburned/arikawa/v2/gateway"
"github.com/diamondburned/cchat"
"github.com/diamondburned/cchat-discord/internal/discord/channel/message"
"github.com/diamondburned/cchat-discord/internal/discord/channel/shared"
"github.com/diamondburned/cchat-discord/internal/discord/state"
"github.com/diamondburned/cchat-discord/internal/urlutils"
"github.com/diamondburned/cchat/text"
"github.com/diamondburned/cchat/utils/empty"
"github.com/pkg/errors"
@ -29,9 +33,11 @@ func New(s *state.Instance, ch discord.Channel) (cchat.Server, error) {
func NewChannel(s *state.Instance, ch discord.Channel) (Channel, error) {
// Ensure the state keeps the channel's permission.
_, err := s.Permissions(ch.ID, s.UserID)
if err != nil {
return Channel{}, errors.Wrap(err, "Failed to get permission")
if ch.GuildID.IsValid() {
_, err := s.Permissions(ch.ID, s.UserID)
if err != nil {
return Channel{}, errors.Wrap(err, "failed to get permission")
}
}
sharedCh := shared.Channel{
@ -56,11 +62,7 @@ func (ch Channel) Name() text.Rich {
return text.Rich{Content: ch.ID()}
}
if c.NSFW {
return text.Rich{Content: "#" + c.Name + " (nsfw)"}
} else {
return text.Rich{Content: "#" + c.Name}
}
return text.Plain(shared.ChannelName(*c))
}
func (ch Channel) AsCommander() cchat.Commander {
@ -74,3 +76,52 @@ func (ch Channel) AsMessenger() cchat.Messenger {
return message.New(ch.Channel)
}
func (ch Channel) AsIconer() cchat.Iconer {
// Guild channels never have an icon.
if ch.GuildID.IsValid() {
return nil
}
c, err := ch.Self()
if err != nil {
return nil
}
// Only DM channels should have an icon.
if c.Type != discord.DirectMessage {
return nil
}
return PresenceAvatar{
user: c.DMRecipients[0],
guild: ch.GuildID,
state: ch.State,
}
}
type PresenceAvatar struct {
user discord.User
guild discord.GuildID
state *state.Instance
}
func (avy PresenceAvatar) Icon(ctx context.Context, iconer cchat.IconContainer) (func(), error) {
if avy.user.Avatar != "" {
iconer.SetIcon(urlutils.AvatarURL(avy.user.AvatarURL()))
}
// There are so many other places that could be checked, but this is good
// enough.
c, err := avy.state.Presence(avy.guild, avy.user.ID)
if err == nil && c.User.Avatar != "" {
iconer.SetIcon(urlutils.AvatarURL(c.User.AvatarURL()))
}
return avy.state.AddHandler(func(update *gateway.PresenceUpdateEvent) {
if avy.user.ID == update.User.ID {
iconer.SetIcon(urlutils.AvatarURL(update.User.AvatarURL()))
}
}), nil
}

View File

@ -8,8 +8,8 @@ import (
"io/ioutil"
"strings"
"github.com/diamondburned/arikawa/bot/extras/arguments"
"github.com/diamondburned/arikawa/discord"
"github.com/diamondburned/arikawa/v2/bot/extras/arguments"
"github.com/diamondburned/arikawa/v2/discord"
"github.com/diamondburned/cchat-discord/internal/discord/channel/shared"
"github.com/pkg/errors"
)

View File

@ -1,7 +1,7 @@
package action
import (
"github.com/diamondburned/arikawa/discord"
"github.com/diamondburned/arikawa/v2/discord"
"github.com/diamondburned/cchat"
"github.com/diamondburned/cchat-discord/internal/discord/channel/shared"
"github.com/pkg/errors"
@ -43,13 +43,13 @@ func (ac Actioner) Actions(id string) []string {
return nil
}
m, err := ac.State.Store.Message(ac.ID, discord.MessageID(s))
m, err := ac.State.Cabinet.Message(ac.ID, discord.MessageID(s))
if err != nil {
return nil
}
// Get the current user.
u, err := ac.State.Store.Me()
u, err := ac.State.Cabinet.Me()
if err != nil {
return nil
}
@ -91,7 +91,7 @@ func (ac Actioner) canManageMessages(userID discord.UserID) bool {
return false
}
m, err := ac.State.Store.Member(ac.GuildID, userID)
m, err := ac.State.Cabinet.Member(ac.GuildID, userID)
if err != nil {
return false
}

View File

@ -3,7 +3,7 @@ package backlog
import (
"context"
"github.com/diamondburned/arikawa/discord"
"github.com/diamondburned/arikawa/v2/discord"
"github.com/diamondburned/cchat"
"github.com/diamondburned/cchat-discord/internal/discord/channel/shared"
"github.com/diamondburned/cchat-discord/internal/discord/message"

View File

@ -1,7 +1,7 @@
package edit
import (
"github.com/diamondburned/arikawa/discord"
"github.com/diamondburned/arikawa/v2/discord"
"github.com/diamondburned/cchat"
"github.com/diamondburned/cchat-discord/internal/discord/channel/shared"
"github.com/pkg/errors"
@ -23,7 +23,7 @@ func (ed Editor) IsEditable(id string) bool {
return false
}
m, err := ed.State.Store.Message(ed.ID, discord.MessageID(s))
m, err := ed.State.Cabinet.Message(ed.ID, discord.MessageID(s))
if err != nil {
return false
}
@ -38,7 +38,7 @@ func (ed Editor) RawContent(id string) (string, error) {
return "", errors.Wrap(err, "Failed to parse ID")
}
m, err := ed.State.Store.Message(ed.ID, discord.MessageID(s))
m, err := ed.State.Cabinet.Message(ed.ID, discord.MessageID(s))
if err != nil {
return "", errors.Wrap(err, "Failed to get the message")
}

View File

@ -3,7 +3,7 @@ package indicate
import (
"time"
"github.com/diamondburned/arikawa/gateway"
"github.com/diamondburned/arikawa/v2/gateway"
"github.com/diamondburned/cchat"
"github.com/diamondburned/cchat-discord/internal/discord/channel/shared"
"github.com/diamondburned/cchat-discord/internal/discord/channel/typer"

View File

@ -3,7 +3,7 @@ package indicate
import (
"github.com/diamondburned/cchat"
"github.com/diamondburned/cchat-discord/internal/discord/channel/shared"
"github.com/diamondburned/ningen/states/read"
"github.com/diamondburned/ningen/v2/states/read"
"github.com/pkg/errors"
)

View File

@ -5,8 +5,8 @@ import (
"fmt"
"strings"
"github.com/diamondburned/arikawa/discord"
"github.com/diamondburned/arikawa/gateway"
"github.com/diamondburned/arikawa/v2/discord"
"github.com/diamondburned/arikawa/v2/gateway"
"github.com/diamondburned/cchat"
"github.com/diamondburned/cchat-discord/internal/discord/channel/shared"
"github.com/diamondburned/cchat-discord/internal/segments/colored"
@ -36,12 +36,12 @@ func (l *Member) ID() cchat.ID {
}
func (l *Member) Name() text.Rich {
g, err := l.channel.State.Store.Guild(l.channel.GuildID)
g, err := l.channel.State.Cabinet.Guild(l.channel.GuildID)
if err != nil {
return text.Plain(l.origName)
}
m, err := l.channel.State.Store.Member(l.channel.GuildID, l.userID)
m, err := l.channel.State.Cabinet.Member(l.channel.GuildID, l.userID)
if err != nil {
return text.Plain(l.origName)
}
@ -80,19 +80,19 @@ func (l *Member) Icon(ctx context.Context, c cchat.IconContainer) (func(), error
}
func (l *Member) Status() cchat.Status {
p, err := l.channel.State.Store.Presence(l.channel.GuildID, l.userID)
p, err := l.channel.State.Cabinet.Presence(l.channel.GuildID, l.userID)
if err != nil {
return cchat.StatusUnknown
}
switch p.Status {
case discord.OnlineStatus:
case gateway.OnlineStatus:
return cchat.StatusOnline
case discord.DoNotDisturbStatus:
case gateway.DoNotDisturbStatus:
return cchat.StatusBusy
case discord.IdleStatus:
case gateway.IdleStatus:
return cchat.StatusAway
case discord.OfflineStatus, discord.InvisibleStatus:
case gateway.OfflineStatus, gateway.InvisibleStatus:
return cchat.StatusOffline
default:
return cchat.StatusUnknown
@ -100,15 +100,11 @@ func (l *Member) Status() cchat.Status {
}
func (l *Member) Secondary() text.Rich {
p, err := l.channel.State.Store.Presence(l.channel.GuildID, l.userID)
p, err := l.channel.State.Cabinet.Presence(l.channel.GuildID, l.userID)
if err != nil {
return text.Plain("")
}
if p.Game != nil {
return formatSmallActivity(*p.Game)
}
if len(p.Activities) > 0 {
return formatSmallActivity(p.Activities[0])
}

View File

@ -3,10 +3,10 @@ package memberlist
import (
"context"
"github.com/diamondburned/arikawa/gateway"
"github.com/diamondburned/arikawa/v2/gateway"
"github.com/diamondburned/cchat"
"github.com/diamondburned/cchat-discord/internal/discord/channel/shared"
"github.com/diamondburned/ningen/states/member"
"github.com/diamondburned/ningen/v2/states/member"
)
func seekPrevGroup(l *member.List, ix int) (item, group gateway.GuildMemberListOpItem) {

View File

@ -3,8 +3,8 @@ package memberlist
import (
"fmt"
"github.com/diamondburned/arikawa/discord"
"github.com/diamondburned/arikawa/gateway"
"github.com/diamondburned/arikawa/v2/discord"
"github.com/diamondburned/arikawa/v2/gateway"
"github.com/diamondburned/cchat"
"github.com/diamondburned/cchat-discord/internal/discord/channel/shared"
"github.com/diamondburned/cchat/text"

View File

@ -4,8 +4,8 @@ import (
"context"
"sort"
"github.com/diamondburned/arikawa/discord"
"github.com/diamondburned/arikawa/gateway"
"github.com/diamondburned/arikawa/v2/discord"
"github.com/diamondburned/arikawa/v2/gateway"
"github.com/diamondburned/cchat"
"github.com/diamondburned/cchat-discord/internal/discord/channel/message/action"
"github.com/diamondburned/cchat-discord/internal/discord/channel/message/backlog"

View File

@ -2,74 +2,91 @@ package nickname
import (
"context"
"fmt"
"github.com/diamondburned/arikawa/gateway"
"github.com/diamondburned/arikawa/v2/discord"
"github.com/diamondburned/arikawa/v2/gateway"
"github.com/diamondburned/cchat"
"github.com/diamondburned/cchat-discord/internal/discord/channel/shared"
"github.com/diamondburned/cchat-discord/internal/funcutil"
"github.com/diamondburned/cchat-discord/internal/segments/colored"
"github.com/diamondburned/cchat/text"
"github.com/pkg/errors"
)
type Nicknamer struct {
userID discord.UserID
shared.Channel
}
func New(ch shared.Channel) cchat.Nicknamer {
return Nicknamer{ch}
return NewMember(ch.State.UserID, ch)
}
func NewMember(userID discord.UserID, ch shared.Channel) cchat.Nicknamer {
return Nicknamer{userID, ch}
}
func (nn Nicknamer) Nickname(ctx context.Context, labeler cchat.LabelContainer) (func(), error) {
// We don't have a nickname if we're not in a guild.
if !nn.GuildID.IsValid() {
// Use the current user.
u, err := nn.State.Cabinet.Me()
if err == nil {
labeler.SetLabel(text.Plain(fmt.Sprintf("%s#%s", u.Username, u.Discriminator)))
}
return func() {}, nil
}
return funcutil.JoinCancels(
nn.State.AddHandler(func(chunks *gateway.GuildMembersChunkEvent) {
if chunks.GuildID != nn.GuildID {
return
}
for _, member := range chunks.Members {
if member.User.ID == nn.userID {
nn.setMember(labeler, member)
break
}
}
}),
nn.State.AddHandler(func(g *gateway.GuildMemberUpdateEvent) {
if g.GuildID == nn.GuildID && g.User.ID == nn.userID {
nn.setMember(labeler, discord.Member{
User: g.User,
Nick: g.Nick,
RoleIDs: g.RoleIDs,
})
}
}),
), nil
}
func (nn Nicknamer) tryNicknameLabel(ctx context.Context, labeler cchat.LabelContainer) {
state := nn.State.WithContext(ctx)
// MemberColor should fill up the state cache.
c, err := state.MemberColor(nn.GuildID, nn.State.UserID)
m, err := state.Cabinet.Member(nn.GuildID, nn.userID)
if err != nil {
return nil, errors.Wrap(err, "Failed to get self member color")
return
}
m, err := state.Member(nn.GuildID, nn.State.UserID)
if err != nil {
return nil, errors.Wrap(err, "Failed to get self member")
}
nn.setMember(labeler, *m)
}
func (nn Nicknamer) setMember(labeler cchat.LabelContainer, m discord.Member) {
var rich = text.Rich{Content: m.User.Username}
if m.Nick != "" {
rich.Content = m.Nick
}
if c > 0 {
rich.Segments = []text.Segment{
colored.New(len(rich.Content), c.Uint32()),
guild, err := nn.State.Cabinet.Guild(nn.GuildID)
if err == nil {
if color := discord.MemberColor(*guild, m); color > 0 {
rich.Segments = []text.Segment{
colored.New(len(rich.Content), color.Uint32()),
}
}
}
labeler.SetLabel(rich)
// Copy the user ID to use.
var selfID = m.User.ID
return nn.State.AddHandler(func(g *gateway.GuildMemberUpdateEvent) {
if g.GuildID != nn.GuildID || g.User.ID != selfID {
return
}
var rich = text.Rich{Content: m.User.Username}
if m.Nick != "" {
rich.Content = m.Nick
}
c, err := nn.State.MemberColor(g.GuildID, selfID)
if err == nil {
rich.Segments = []text.Segment{
colored.New(len(rich.Content), c.Uint32()),
}
}
labeler.SetLabel(rich)
}), nil
}

View File

@ -1,7 +1,7 @@
package complete
import (
"github.com/diamondburned/arikawa/discord"
"github.com/diamondburned/arikawa/v2/discord"
"github.com/diamondburned/cchat"
"github.com/diamondburned/cchat-discord/internal/discord/channel/shared"
"github.com/diamondburned/cchat-discord/internal/discord/state"
@ -19,7 +19,7 @@ func (ch ChannelCompleter) CompleteChannels(word string) []cchat.CompletionEntry
return nil
}
c, err := ch.State.Store.Channels(ch.GuildID)
c, err := ch.State.Cabinet.Channels(ch.GuildID)
if err != nil {
return nil
}
@ -28,7 +28,7 @@ func (ch ChannelCompleter) CompleteChannels(word string) []cchat.CompletionEntry
}
func DMChannels(s *state.Instance, word string) []cchat.CompletionEntry {
channels, err := s.Store.PrivateChannels()
channels, err := s.Cabinet.PrivateChannels()
if err != nil {
return nil
}
@ -40,7 +40,7 @@ func DMChannels(s *state.Instance, word string) []cchat.CompletionEntry {
func rankChannel(word string, ch discord.Channel) int {
switch ch.Type {
case discord.GroupDM, discord.DirectMessage:
return rankFunc(word, ch.Name+" "+shared.PrivateName(ch))
return rankFunc(word, ch.Name+" "+shared.ChannelName(ch))
default:
return rankFunc(word, ch.Name)
}
@ -60,7 +60,7 @@ func completeChannels(
var category string
if s != nil && channel.CategoryID.IsValid() {
if cat, _ := s.Store.Channel(channel.CategoryID); cat != nil {
if cat, _ := s.Cabinet.Channel(channel.CategoryID); cat != nil {
category = cat.Name
}
}
@ -86,5 +86,4 @@ func completeChannels(
sortDistances(entries, distances)
return entries
}

View File

@ -14,16 +14,23 @@ type ChannelCompleter struct {
shared.Channel
}
type Completer map[byte]CompleterFunc
type CompleterPrefixes map[byte]CompleterFunc
type Completer struct {
Prefixes CompleterPrefixes
SlashHandler cchat.Completer
}
const MaxCompletion = 15
func New(ch shared.Channel) cchat.Completer {
completer := ChannelCompleter{ch}
return Completer{
'@': completer.CompleteMentions,
'#': completer.CompleteChannels,
':': completer.CompleteEmojis,
Prefixes: map[byte]CompleterFunc{
'@': completer.CompleteMentions,
'#': completer.CompleteChannels,
':': completer.CompleteEmojis,
},
}
}
@ -31,20 +38,24 @@ func New(ch shared.Channel) cchat.Completer {
// This method supports user mentions, channel mentions and emojis.
//
// For the individual implementations, refer to channel_completion.go.
func (ch Completer) Complete(words []string, i int64) []cchat.CompletionEntry {
func (cc Completer) Complete(words []string, i int64) []cchat.CompletionEntry {
var word = words[i]
// Word should have at least a character for the char check.
if len(word) < 1 {
if len(word) == 0 {
return nil
}
fn, ok := ch[word[0]]
// Always check the first word for slash, not the current word.
if cc.SlashHandler != nil && words[0][0] == '/' {
return cc.SlashHandler.Complete(words, i)
}
fn, ok := cc.Prefixes[word[0]]
if !ok {
return nil
}
fn(word[1:])
return nil
return fn(word[1:])
}
// rankFunc is the default rank function to use.

View File

@ -1,7 +1,7 @@
package complete
import (
"github.com/diamondburned/arikawa/discord"
"github.com/diamondburned/arikawa/v2/discord"
"github.com/diamondburned/cchat"
"github.com/diamondburned/cchat-discord/internal/discord/state"
"github.com/diamondburned/cchat-discord/internal/urlutils"

View File

@ -1,9 +1,8 @@
package complete
import (
"strings"
"github.com/diamondburned/arikawa/discord"
"github.com/diamondburned/arikawa/v2/discord"
"github.com/diamondburned/arikawa/v2/gateway"
"github.com/diamondburned/cchat"
"github.com/diamondburned/cchat-discord/internal/discord/message"
"github.com/diamondburned/cchat-discord/internal/discord/state"
@ -29,8 +28,8 @@ func GuildMessageMentions(
// Keep track of the number of authors.
// TODO: fix excess allocations
var entries []cchat.CompletionEntry
var authors map[discord.UserID]struct{}
var entries = make([]cchat.CompletionEntry, 0, MaxCompletion)
var authors = make(map[discord.UserID]struct{}, MaxCompletion)
for _, msg := range msgs {
// If we've already added the author into the list, then skip.
@ -38,13 +37,12 @@ func GuildMessageMentions(
continue
}
ensureAuthorMapMade(&authors)
authors[msg.Author.ID] = struct{}{}
var rich text.Rich
if guild != nil && state != nil {
m, err := state.Store.Member(guild.ID, msg.Author.ID)
m, err := state.Cabinet.Member(guild.ID, msg.Author.ID)
if err == nil {
rich = message.RenderMemberName(*m, *guild, state)
}
@ -55,8 +53,6 @@ func GuildMessageMentions(
rich = text.Plain(msg.Author.Username)
}
ensureEntriesMade(&entries)
entries = append(entries, cchat.CompletionEntry{
Raw: msg.Author.Mention(),
Text: rich,
@ -72,72 +68,131 @@ func GuildMessageMentions(
return entries
}
func ensureAuthorMapMade(authors *map[discord.UserID]struct{}) {
if *authors == nil {
*authors = make(map[discord.UserID]struct{}, MaxCompletion)
}
}
func Presences(s *state.Instance, word string) []cchat.CompletionEntry {
presences, err := s.Presences(0)
if err != nil {
return nil
}
// AllUsers checks for friends and presences.
func AllUsers(s *state.Instance, word string) []cchat.CompletionEntry {
var full bool
var friends map[discord.UserID]struct{}
var entries []cchat.CompletionEntry
var distances map[string]int
for _, presence := range presences {
rank := rankFunc(word, presence.User.Username)
// Search for friends first.
s.RelationshipState.Each(func(r *discord.Relationship) bool {
// Skip blocked users or strangers.
if r.Type == 0 || r.Type == discord.BlockedRelationship {
return false
}
rank := rankFunc(word, r.User.Username)
if rank == -1 {
continue
return false
}
if friends == nil {
friends = map[discord.UserID]struct{}{}
}
friends[r.UserID] = struct{}{}
ensureEntriesMade(&entries)
ensureDistancesMade(&distances)
raw := r.User.Mention()
var status = gateway.UnknownStatus
if p, _ := s.PresenceState.Presence(0, r.UserID); p != nil {
status = p.Status
}
entries = append(entries, cchat.CompletionEntry{
Raw: raw,
Text: text.Plain(r.User.Username + "#" + r.User.Discriminator),
Secondary: text.Plain(FormatStatus(status) + " - " + FormatRelationshipType(r.Type)),
IconURL: r.User.AvatarURL(),
})
distances[raw] = rank
full = len(entries) >= MaxCompletion
return full
})
if full {
goto Full
}
// Search for presences.
s.PresenceState.Each(0, func(p *gateway.Presence) bool {
// Avoid duplicates.
if _, ok := friends[p.User.ID]; ok {
return false
}
rank := rankFunc(word, p.User.Username)
if rank == -1 {
return false
}
ensureEntriesMade(&entries)
ensureDistancesMade(&distances)
raw := presence.User.Mention()
raw := p.User.Mention()
entries = append(entries, cchat.CompletionEntry{
Raw: raw,
Text: text.Plain(presence.User.Username + "#" + presence.User.Discriminator),
Secondary: text.Plain(FormatStatus(presence.Status)),
IconURL: presence.User.AvatarURL(),
Text: text.Plain(p.User.Username + "#" + p.User.Discriminator),
Secondary: text.Plain(FormatStatus(p.Status)),
IconURL: p.User.AvatarURL(),
})
distances[raw] = rank
if len(entries) >= MaxCompletion {
break
}
}
full = len(entries) >= MaxCompletion
return full
})
Full:
sortDistances(entries, distances)
return entries
}
func FormatStatus(status discord.Status) string {
func FormatStatus(status gateway.Status) string {
switch status {
case discord.OnlineStatus:
case gateway.OnlineStatus:
return "Online"
case discord.DoNotDisturbStatus:
case gateway.DoNotDisturbStatus:
return "Busy"
case discord.IdleStatus:
case gateway.IdleStatus:
return "Idle"
case discord.InvisibleStatus:
case gateway.InvisibleStatus:
return "Invisible"
case discord.OfflineStatus:
return "Offline"
case gateway.OfflineStatus:
fallthrough
default:
return strings.Title(string(status))
return "Offline"
}
}
func FormatRelationshipType(relaType discord.RelationshipType) string {
switch relaType {
case discord.BlockedRelationship:
return "Blocked"
case discord.FriendRelationship:
return "Friend"
case discord.IncomingFriendRequest:
return "Incoming friend request"
case discord.SentFriendRequest:
return "Friend request sent"
default:
return ""
}
}
func (ch ChannelCompleter) CompleteMentions(word string) []cchat.CompletionEntry {
// If there is no input, then we should grab the latest messages.
if word == "" {
msgs, _ := ch.State.Store.Messages(ch.ID)
g, _ := ch.State.Store.Guild(ch.GuildID) // nil is fine
msgs, _ := ch.State.Cabinet.Messages(ch.ID)
g, _ := ch.State.Cabinet.Guild(ch.GuildID) // nil is fine
return GuildMessageMentions(msgs, ch.State, g)
}
@ -147,7 +202,7 @@ func (ch ChannelCompleter) CompleteMentions(word string) []cchat.CompletionEntry
// If we're not in a guild, then we can check the list of recipients.
if !ch.GuildID.IsValid() {
c, err := ch.State.Store.Channel(ch.ID)
c, err := ch.State.Cabinet.Channel(ch.ID)
if err != nil {
return nil
}
@ -182,8 +237,8 @@ func (ch ChannelCompleter) CompleteMentions(word string) []cchat.CompletionEntry
}
// If we're in a guild, then we should search for (all) members.
m, merr := ch.State.Store.Members(ch.GuildID)
g, gerr := ch.State.Store.Guild(ch.GuildID)
m, merr := ch.State.Cabinet.Members(ch.GuildID)
g, gerr := ch.State.Cabinet.Guild(ch.GuildID)
if merr != nil || gerr != nil {
return nil

View File

@ -1,8 +1,9 @@
package send
import (
"github.com/diamondburned/arikawa/api"
"github.com/diamondburned/arikawa/discord"
"github.com/diamondburned/arikawa/v2/api"
"github.com/diamondburned/arikawa/v2/discord"
"github.com/diamondburned/arikawa/v2/utils/sendpart"
"github.com/diamondburned/cchat"
"github.com/diamondburned/cchat-discord/internal/discord/channel/message/send/complete"
"github.com/diamondburned/cchat-discord/internal/discord/channel/shared"
@ -50,10 +51,10 @@ func (s Sender) AsCompleter() cchat.Completer {
return complete.New(s.Channel)
}
func addAttachments(atts []cchat.MessageAttachment) []api.SendMessageFile {
var files = make([]api.SendMessageFile, len(atts))
func addAttachments(atts []cchat.MessageAttachment) []sendpart.File {
var files = make([]sendpart.File, len(atts))
for i, a := range atts {
files[i] = api.SendMessageFile{
files[i] = sendpart.File{
Name: a.Name,
Reader: a,
}

View File

@ -1,75 +0,0 @@
package channel
import (
"context"
"github.com/diamondburned/arikawa/discord"
"github.com/diamondburned/arikawa/gateway"
"github.com/diamondburned/cchat"
"github.com/diamondburned/cchat-discord/internal/discord/channel/shared"
"github.com/diamondburned/cchat-discord/internal/discord/state"
"github.com/diamondburned/cchat-discord/internal/urlutils"
"github.com/diamondburned/cchat/text"
"github.com/pkg/errors"
)
type Private struct {
Channel
}
var _ cchat.Server = (*Private)(nil)
func NewPrivate(s *state.Instance, ch discord.Channel) (cchat.Server, error) {
if ch.GuildID.IsValid() {
return nil, errors.New("channel has valid guild ID: not a DM")
}
channel, err := NewChannel(s, ch)
if err != nil {
return nil, err
}
return Private{Channel: channel}, nil
}
func (priv Private) Name() text.Rich {
c, err := priv.Self()
if err != nil {
return text.Rich{Content: priv.ID()}
}
return text.Plain(shared.PrivateName(*c))
}
func (priv Private) AsIconer() cchat.Iconer {
return NewAvatarIcon(priv.State)
}
type AvatarIcon struct {
State *state.Instance
}
func NewAvatarIcon(state *state.Instance) cchat.Iconer {
return AvatarIcon{state}
}
func (avy AvatarIcon) Icon(ctx context.Context, iconer cchat.IconContainer) (func(), error) {
u, err := avy.State.WithContext(ctx).Me()
if err != nil {
// This shouldn't happen.
return nil, errors.Wrap(err, "Failed to get guild")
}
// Used for comparison.
if u.Avatar != "" {
iconer.SetIcon(urlutils.AvatarURL(u.AvatarURL()))
}
selfID := u.ID
return avy.State.AddHandler(func(update *gateway.UserUpdateEvent) {
if selfID == update.ID {
iconer.SetIcon(urlutils.AvatarURL(update.AvatarURL()))
}
}), nil
}

View File

@ -5,18 +5,32 @@ import (
"errors"
"strings"
"github.com/diamondburned/arikawa/discord"
"github.com/diamondburned/arikawa/v2/discord"
"github.com/diamondburned/cchat-discord/internal/discord/state"
)
// PrivateName returns the channel name if any, otherwise it formats its own
// ChannelName returns the channel name if any, otherwise it formats its own
// name into a list of recipients.
func PrivateName(privCh discord.Channel) string {
if privCh.Name != "" {
return privCh.Name
func ChannelName(ch discord.Channel) string {
switch ch.Type {
case discord.DirectMessage, discord.GroupDM:
if len(ch.DMRecipients) > 0 {
return FormatRecipients(ch.DMRecipients)
}
default:
if ch.Name == "" {
break
}
if ch.NSFW {
return "#" + ch.Name + " (nsfw)"
} else {
return "#" + ch.Name
}
}
return FormatRecipients(privCh.DMRecipients)
return ch.ID.String()
}
// FormatRecipients joins the given list of users into a string listing all
@ -24,14 +38,14 @@ func PrivateName(privCh discord.Channel) string {
func FormatRecipients(users []discord.User) string {
switch len(users) {
case 0:
return "<Nobody>"
return ""
case 1:
return users[0].Username
case 2:
return users[0].Username + " and " + users[1].Username
}
var usernames = make([]string, len(users))
var usernames = make([]string, len(users)-1)
for i, user := range users[:len(users)-1] {
usernames[i] = user.Username
}
@ -48,6 +62,11 @@ type Channel struct {
// HasPermission returns true if the current user has the given permissions in
// the channel.
func (ch Channel) HasPermission(perms ...discord.Permissions) bool {
// Assume we have permissions in a direct message channel.
if !ch.GuildID.IsValid() {
return true
}
p, err := ch.State.StateOnly().Permissions(ch.ID, ch.State.UserID)
if err != nil {
return false
@ -63,16 +82,16 @@ func (ch Channel) HasPermission(perms ...discord.Permissions) bool {
}
func (ch Channel) Messages() ([]discord.Message, error) {
return ch.State.Store.Messages(ch.ID)
return ch.State.Cabinet.Messages(ch.ID)
}
func (ch Channel) Guild() (*discord.Guild, error) {
if !ch.GuildID.IsValid() {
return nil, errors.New("channel not in guild")
}
return ch.State.Store.Guild(ch.GuildID)
return ch.State.Cabinet.Guild(ch.GuildID)
}
func (ch Channel) Self() (*discord.Channel, error) {
return ch.State.Store.Channel(ch.ID)
return ch.State.Cabinet.Channel(ch.ID)
}

View File

@ -4,8 +4,8 @@ import (
"errors"
"time"
"github.com/diamondburned/arikawa/discord"
"github.com/diamondburned/arikawa/gateway"
"github.com/diamondburned/arikawa/v2/discord"
"github.com/diamondburned/arikawa/v2/gateway"
"github.com/diamondburned/cchat"
"github.com/diamondburned/cchat-discord/internal/discord/message"
"github.com/diamondburned/cchat-discord/internal/discord/state"
@ -27,13 +27,13 @@ func NewFromAuthor(author message.Author, ev *gateway.TypingStartEvent) Typer {
func New(s *state.Instance, ev *gateway.TypingStartEvent) (*Typer, error) {
if ev.GuildID.IsValid() {
g, err := s.Store.Guild(ev.GuildID)
g, err := s.Cabinet.Guild(ev.GuildID)
if err != nil {
return nil, err
}
if ev.Member == nil {
ev.Member, err = s.Store.Member(ev.GuildID, ev.UserID)
ev.Member, err = s.Cabinet.Member(ev.GuildID, ev.UserID)
if err != nil {
return nil, err
}
@ -45,7 +45,7 @@ func New(s *state.Instance, ev *gateway.TypingStartEvent) (*Typer, error) {
}, nil
}
c, err := s.Store.Channel(ev.ChannelID)
c, err := s.Cabinet.Channel(ev.ChannelID)
if err != nil {
return nil, err
}

View File

@ -4,7 +4,7 @@ import (
"strconv"
"strings"
"github.com/diamondburned/arikawa/gateway"
"github.com/diamondburned/arikawa/v2/gateway"
"github.com/diamondburned/cchat"
"github.com/diamondburned/cchat-discord/internal/discord/guild"
"github.com/diamondburned/cchat-discord/internal/discord/state"
@ -25,7 +25,7 @@ func New(s *state.Instance, gf gateway.GuildFolder) cchat.Server {
var names = make([]string, 0, len(gf.GuildIDs))
for _, id := range gf.GuildIDs {
g, err := s.Store.Guild(id)
g, err := s.Cabinet.Guild(id)
if err == nil {
names = append(names, g.Name)
}

View File

@ -4,8 +4,8 @@ import (
"context"
"sort"
"github.com/diamondburned/arikawa/discord"
"github.com/diamondburned/arikawa/gateway"
"github.com/diamondburned/arikawa/v2/discord"
"github.com/diamondburned/arikawa/v2/gateway"
"github.com/diamondburned/cchat"
"github.com/diamondburned/cchat-discord/internal/discord/category"
"github.com/diamondburned/cchat-discord/internal/discord/channel"
@ -43,7 +43,7 @@ func (g *Guild) self(ctx context.Context) (*discord.Guild, error) {
}
func (g *Guild) selfState() (*discord.Guild, error) {
return g.state.Store.Guild(g.id)
return g.state.Cabinet.Guild(g.id)
}
func (g *Guild) ID() cchat.ID {

View File

@ -1,7 +1,7 @@
package message
import (
"github.com/diamondburned/arikawa/discord"
"github.com/diamondburned/arikawa/v2/discord"
"github.com/diamondburned/cchat"
"github.com/diamondburned/cchat-discord/internal/discord/state"
"github.com/diamondburned/cchat-discord/internal/segments/colored"
@ -132,25 +132,31 @@ func (a *Author) AddReply(name string) {
// richMember(&a.name, m, g, s)
// }
func (a *Author) addAuthorReference(msgref discord.Message, s *state.Instance) {
a.name.Content += authorReplyingTo
start, end := richUser(&a.name, msgref.Author, s)
a.name.Segments = append(a.name.Segments,
reference.NewMessageSegment(start, end, msgref.ID),
)
}
// AddMessageReference adds a message reference to the author.
func (a *Author) AddMessageReference(msgref discord.Message, s *state.Instance) {
if !msgref.GuildID.IsValid() {
a.name.Content += authorReplyingTo
start, end := richUser(&a.name, msgref.Author, s)
a.name.Segments = append(a.name.Segments,
reference.NewMessageSegment(start, end, msgref.ID),
)
a.addAuthorReference(msgref, s)
return
}
g, err := s.Guild(msgref.GuildID)
g, err := s.Cabinet.Guild(msgref.GuildID)
if err != nil {
a.addAuthorReference(msgref, s)
return
}
m, err := s.Member(g.ID, msgref.Author.ID)
m, err := s.Cabinet.Member(g.ID, msgref.Author.ID)
if err != nil {
a.addAuthorReference(msgref, s)
return
}

View File

@ -3,8 +3,8 @@ package message
import (
"time"
"github.com/diamondburned/arikawa/discord"
"github.com/diamondburned/arikawa/gateway"
"github.com/diamondburned/arikawa/v2/discord"
"github.com/diamondburned/arikawa/v2/gateway"
"github.com/diamondburned/cchat"
"github.com/diamondburned/cchat-discord/internal/discord/state"
"github.com/diamondburned/cchat-discord/internal/segments"
@ -85,13 +85,13 @@ func NewMessageUpdateContent(msg discord.Message, s *state.Instance) Message {
// Check if content is empty.
if msg.Content == "" {
// Then grab the content from the state.
m, err := s.Store.Message(msg.ChannelID, msg.ID)
m, err := s.Cabinet.Message(msg.ChannelID, msg.ID)
if err == nil {
msg.Content = m.Content
}
}
var content = segments.ParseMessage(&msg, s.Store)
var content = segments.ParseMessage(&msg, s.Cabinet)
return Message{
messageHeader: newHeader(msg),
content: content,
@ -116,13 +116,13 @@ func NewGuildMessageCreate(c *gateway.MessageCreateEvent, s *state.Instance) Mes
message.Nonce = s.Nonces.Load(c.Nonce)
// This should not error.
g, err := s.Store.Guild(c.GuildID)
g, err := s.Cabinet.Guild(c.GuildID)
if err != nil {
return NewMessage(message, s, NewUser(c.Author, s))
}
if c.Member == nil {
c.Member, _ = s.Store.Member(c.GuildID, c.Author.ID)
c.Member, _ = s.Cabinet.Member(c.GuildID, c.Author.ID)
}
if c.Member == nil {
s.MemberState.RequestMember(c.GuildID, c.Author.ID)
@ -142,7 +142,7 @@ func NewBacklogMessage(m discord.Message, s *state.Instance, g discord.Guild) Me
return NewMessage(m, s, NewUser(m.Author, s))
}
mem, err := s.Store.Member(m.GuildID, m.Author.ID)
mem, err := s.Cabinet.Member(m.GuildID, m.Author.ID)
if err != nil {
s.MemberState.RequestMember(m.GuildID, m.Author.ID)
return NewMessage(m, s, NewUser(m.Author, s))
@ -157,7 +157,7 @@ func NewDirectMessage(m discord.Message, s *state.Instance) Message {
func NewMessage(m discord.Message, s *state.Instance, author Author) Message {
// Render the message content.
var content = segments.ParseMessage(&m, s.Store)
var content = segments.ParseMessage(&m, s.Cabinet)
// Request members in mentions if we're in a guild.
if m.GuildID.IsValid() {

View File

@ -4,8 +4,8 @@ import (
"context"
"sync"
"github.com/diamondburned/arikawa/discord"
"github.com/diamondburned/arikawa/gateway"
"github.com/diamondburned/arikawa/v2/discord"
"github.com/diamondburned/arikawa/v2/gateway"
"github.com/diamondburned/cchat"
"github.com/diamondburned/cchat-discord/internal/discord/channel/message/send/complete"
"github.com/diamondburned/cchat-discord/internal/discord/channel/shared"
@ -83,13 +83,13 @@ func NewMessages(s *state.Instance, acList *activeList, adder ChannelAdder) *Mes
messages: make(messageList, 0, 100),
}
hubServer.sender.completers = complete.Completer{
hubServer.sender.completers.Prefixes = complete.CompleterPrefixes{
':': func(word string) []cchat.CompletionEntry {
return complete.Emojis(s, 0, word)
},
'@': func(word string) []cchat.CompletionEntry {
if word != "" {
return complete.Presences(s, word)
return complete.AllUsers(s, word)
}
hubServer.msgMutex.Lock()
@ -175,7 +175,7 @@ func (msgs *Messages) JoinServer(ctx context.Context, ct cchat.MessagesContainer
case discord.DirectMessage:
author.AddUserReply(c.DMRecipients[0], msgs.state)
case discord.GroupDM:
author.AddReply(shared.PrivateName(*c))
author.AddReply(shared.ChannelName(*c))
}
}
}

View File

@ -4,7 +4,7 @@ import (
"regexp"
"strings"
"github.com/diamondburned/arikawa/discord"
"github.com/diamondburned/arikawa/v2/discord"
"github.com/diamondburned/cchat"
"github.com/diamondburned/cchat-discord/internal/discord/channel/message/send"
"github.com/diamondburned/cchat-discord/internal/discord/channel/message/send/complete"
@ -61,8 +61,6 @@ func (s *Sender) Send(sendable cchat.SendableMessage) error {
return errors.New("message must start with a user or channel mention")
}
// TODO: account for channel names
targetID, err := discord.ParseSnowflake(matches[2])
if err != nil {
return errors.Wrap(err, "failed to parse recipient ID")
@ -79,8 +77,17 @@ func (s *Sender) Send(sendable cchat.SendableMessage) error {
return errors.New("unknown channel")
}
s.adder.AddChannel(s.state, channel)
s.acList.add(channel.ID)
switch channel.Type {
case discord.DirectMessage, discord.GroupDM:
// valid
default:
return errors.New("not a [group] direct message channel")
}
// We should only add the channel if it's not already in the active list.
if s.acList.add(channel.ID) {
s.adder.AddChannel(s.state, channel)
}
sendData := send.WrapMessage(s.state, sendable)
sendData.Content = strings.TrimPrefix(content, matches[0])

View File

@ -4,7 +4,7 @@ import (
"sync"
"time"
"github.com/diamondburned/arikawa/discord"
"github.com/diamondburned/arikawa/v2/discord"
"github.com/diamondburned/cchat"
"github.com/diamondburned/cchat-discord/internal/discord/state"
"github.com/diamondburned/cchat/text"
@ -12,8 +12,8 @@ import (
"github.com/pkg/errors"
)
// automatically add all channels with active messages within the past 48 hours.
const autoAddActive = 24 * time.Hour
// automatically add all channels with active messages within the past 5 days.
const autoAddActive = 5 * 24 * time.Hour
// activeList contains a list of channel IDs that should be put into its own
// channels.
@ -32,7 +32,14 @@ func makeActiveList(s *state.Instance) (*activeList, error) {
now := time.Now()
for _, channel := range channels {
if channel.LastMessageID.Time().Add(autoAddActive).After(now) {
switch channel.Type {
case discord.DirectMessage, discord.GroupDM:
// valid
default:
continue
}
if channelIsActive(s, channel, now) {
ids[channel.ID] = struct{}{}
}
}
@ -40,6 +47,42 @@ func makeActiveList(s *state.Instance) (*activeList, error) {
return &activeList{active: ids}, nil
}
func channelIsActive(s *state.Instance, ch discord.Channel, now time.Time) bool {
// Never show a muted channel, unless requested.
muted := s.MutedState.Channel(ch.ID)
if muted {
return false
}
read := s.ReadState.FindLast(ch.ID)
// recently created channel
if ch.ID.Time().Add(autoAddActive).After(now) {
return true
}
var lastMsg discord.MessageID
if read != nil && read.LastMessageID.IsValid() {
lastMsg = read.LastMessageID
}
if ch.LastMessageID > lastMsg {
// We have a valid message ID in the read state and it is smaller than
// the last message in the channel, so this channel is not read.
if lastMsg.IsValid() {
return true
}
lastMsg = ch.LastMessageID
}
// last message is recent
if lastMsg.IsValid() && lastMsg.Time().Add(autoAddActive).After(now) {
return true
}
return false
}
func (acList *activeList) list() []discord.ChannelID {
acList.mut.Lock()
defer acList.mut.Unlock()

View File

@ -4,7 +4,8 @@ import (
"sort"
"sync"
"github.com/diamondburned/arikawa/discord"
"github.com/diamondburned/arikawa/v2/discord"
"github.com/diamondburned/arikawa/v2/gateway"
"github.com/diamondburned/cchat"
"github.com/diamondburned/cchat-discord/internal/discord/channel"
"github.com/diamondburned/cchat-discord/internal/discord/private/hub"
@ -37,8 +38,13 @@ func (cset *containerSet) Register(container cchat.ServersContainer) {
// top of the servers container.
type prependServer struct{ cchat.Server }
var _ cchat.ServerUpdate = (*prependServer)(nil)
// PreviousID returns the appropriate parameters to prepend this server.
func (ps prependServer) PreviousID() (cchat.ID, bool) { return "", false }
func (ps prependServer) PreviousID() (cchat.ID, bool) {
// Return the private container's ID so this server goes right after it.
return "!!!private-container!!!", false
}
func (cset *containerSet) AddChannel(s *state.Instance, ch *discord.Channel) {
c, err := channel.New(s, *ch)
@ -90,9 +96,29 @@ func (priv Private) Name() text.Rich {
func (priv Private) AsLister() cchat.Lister { return priv }
type activeChannel struct {
*discord.Channel
*gateway.ReadState // used for sorting
}
func (active activeChannel) LastMessageID() discord.MessageID {
if active.ReadState == nil {
return active.Channel.LastMessageID
}
if active.ReadState.LastMessageID > active.Channel.LastMessageID {
return active.ReadState.LastMessageID
}
if active.Channel.LastMessageID.IsValid() {
return active.Channel.LastMessageID
}
// Whatever.
return discord.MessageID(active.Channel.ID)
}
func (priv Private) Servers(container cchat.ServersContainer) error {
activeIDs := priv.hub.ActiveChannelIDs()
channels := make([]*discord.Channel, 0, len(activeIDs))
channels := make([]activeChannel, 0, len(activeIDs))
for _, id := range activeIDs {
c, err := priv.state.Channel(id)
@ -100,25 +126,28 @@ func (priv Private) Servers(container cchat.ServersContainer) error {
return errors.Wrap(err, "failed to get private channel")
}
channels = append(channels, c)
channels = append(channels, activeChannel{
Channel: c,
ReadState: priv.state.ReadState.FindLast(id),
})
}
// Sort so that channels with the largest last message ID (and therefore the
// latest message) will be on top.
sort.Slice(channels, func(i, j int) bool {
return channels[i].LastMessageID > channels[j].LastMessageID
return channels[i].LastMessageID() > channels[j].LastMessageID()
})
servers := make([]cchat.Server, len(channels)+1)
servers[0] = priv.hub
for i, ch := range channels {
c, err := channel.New(priv.state, *ch)
c, err := channel.New(priv.state, *ch.Channel)
if err != nil {
return errors.Wrap(err, "failed to create server for private channel")
}
servers[i] = c
servers[i+1] = c
}
container.SetServers(servers)

View File

@ -3,8 +3,8 @@ package session
import (
"context"
"github.com/diamondburned/arikawa/gateway"
"github.com/diamondburned/arikawa/session"
"github.com/diamondburned/arikawa/v2/gateway"
"github.com/diamondburned/arikawa/v2/session"
"github.com/diamondburned/cchat"
"github.com/diamondburned/cchat-discord/internal/discord/folder"
"github.com/diamondburned/cchat-discord/internal/discord/guild"
@ -13,7 +13,7 @@ import (
"github.com/diamondburned/cchat-discord/internal/urlutils"
"github.com/diamondburned/cchat/text"
"github.com/diamondburned/cchat/utils/empty"
"github.com/diamondburned/ningen"
"github.com/diamondburned/ningen/v2"
"github.com/pkg/errors"
)
@ -42,7 +42,7 @@ func (s *Session) ID() cchat.ID {
}
func (s *Session) Name() text.Rich {
u, err := s.state.Store.Me()
u, err := s.state.Cabinet.Me()
if err != nil {
// This shouldn't happen, ever.
return text.Rich{Content: "<@" + s.state.UserID.String() + ">"}
@ -64,7 +64,7 @@ func (s *Session) Icon(ctx context.Context, iconer cchat.IconContainer) (func(),
return s.state.AddHandler(func(*gateway.UserUpdateEvent) {
// Bypass the event and use the state cache.
if u, err := s.state.Store.Me(); err == nil {
if u, err := s.state.Cabinet.Me(); err == nil {
iconer.SetIcon(urlutils.AvatarURL(u.AvatarURL()))
}
}), nil
@ -91,17 +91,16 @@ func (s *Session) Servers(container cchat.ServersContainer) error {
}
func (s *Session) servers(container cchat.ServersContainer) error {
// TODO: remove this once v2 is used, so we could swap it with a getter.
ready := s.state.Ready
ready := s.state.Ready()
switch {
// If the user has guild folders:
case len(ready.Settings.GuildFolders) > 0:
case len(ready.UserSettings.GuildFolders) > 0:
// TODO: account for missing guilds.
toplevels := make([]cchat.Server, 1, len(ready.Settings.GuildFolders)+1)
toplevels := make([]cchat.Server, 1, len(ready.UserSettings.GuildFolders)+1)
toplevels[0] = s.private
for _, guildFolder := range ready.Settings.GuildFolders {
for _, guildFolder := range ready.UserSettings.GuildFolders {
// TODO: correct.
switch {
case guildFolder.ID != 0:
@ -122,11 +121,11 @@ func (s *Session) servers(container cchat.ServersContainer) error {
// If the user doesn't have guild folders but has sorted their guilds
// before:
case len(ready.Settings.GuildPositions) > 0:
guilds := make([]cchat.Server, 1, len(ready.Settings.GuildPositions)+1)
case len(ready.UserSettings.GuildPositions) > 0:
guilds := make([]cchat.Server, 1, len(ready.UserSettings.GuildPositions)+1)
guilds[0] = s.private
for _, id := range ready.Settings.GuildPositions {
for _, id := range ready.UserSettings.GuildPositions {
g, err := guild.NewFromID(s.state, id)
if err != nil {
continue

View File

@ -5,13 +5,14 @@ import (
"context"
"log"
"github.com/diamondburned/arikawa/discord"
"github.com/diamondburned/arikawa/session"
"github.com/diamondburned/arikawa/state"
"github.com/diamondburned/arikawa/utils/httputil/httpdriver"
"github.com/diamondburned/arikawa/v2/discord"
"github.com/diamondburned/arikawa/v2/session"
"github.com/diamondburned/arikawa/v2/state"
"github.com/diamondburned/arikawa/v2/state/store/defaultstore"
"github.com/diamondburned/arikawa/v2/utils/httputil/httpdriver"
"github.com/diamondburned/cchat"
"github.com/diamondburned/cchat-discord/internal/discord/state/nonce"
"github.com/diamondburned/ningen"
"github.com/diamondburned/ningen/v2"
"github.com/pkg/errors"
)
@ -19,7 +20,8 @@ type Instance struct {
*ningen.State
Nonces *nonce.Map
// UserID is a constant user ID. It is guaranteed to be valid.
// UserID is a constant user ID of the current user. It is guaranteed to be
// valid.
UserID discord.UserID
}
@ -52,17 +54,13 @@ func Login(email, password, mfa string) (*Instance, error) {
return nil, err
}
state, _ := state.NewFromSession(session, state.NewDefaultStore(nil))
return New(state)
cabinet := defaultstore.New()
cabinet.MessageStore = defaultstore.NewMessage(50)
return New(state.NewFromSession(session, cabinet))
}
func New(s *state.State) (*Instance, error) {
// Prefetch user.
u, err := s.Me()
if err != nil {
return nil, errors.Wrap(err, "failed to get current user")
}
n, err := ningen.FromState(s)
if err != nil {
return nil, errors.Wrap(err, "failed to create a state wrapper")
@ -77,6 +75,12 @@ func New(s *state.State) (*Instance, error) {
return nil, err
}
// Prefetch user.
u, err := s.Me()
if err != nil {
return nil, errors.Wrap(err, "failed to get current user")
}
return &Instance{
UserID: u.ID,
State: n,

View File

@ -1,7 +1,7 @@
package embed
import (
"github.com/diamondburned/arikawa/discord"
"github.com/diamondburned/arikawa/v2/discord"
"github.com/diamondburned/cchat-discord/internal/segments/emoji"
"github.com/diamondburned/cchat/text"
"github.com/diamondburned/cchat/utils/empty"

View File

@ -4,15 +4,15 @@ import (
"fmt"
"time"
"github.com/diamondburned/arikawa/discord"
"github.com/diamondburned/arikawa/state"
"github.com/diamondburned/arikawa/v2/discord"
"github.com/diamondburned/arikawa/v2/state/store"
"github.com/diamondburned/cchat-discord/internal/segments/colored"
"github.com/diamondburned/cchat-discord/internal/segments/inline"
"github.com/diamondburned/cchat-discord/internal/segments/link"
"github.com/diamondburned/cchat-discord/internal/segments/renderer"
"github.com/diamondburned/cchat-discord/internal/urlutils"
"github.com/diamondburned/cchat/text"
"github.com/diamondburned/ningen/md"
"github.com/diamondburned/ningen/v2/md"
"github.com/dustin/go-humanize"
)
@ -24,7 +24,7 @@ func writeEmbedSep(r *renderer.Text, embedColor discord.Color) {
}
}
func RenderEmbeds(r *renderer.Text, embeds []discord.Embed, m *discord.Message, s state.Store) {
func RenderEmbeds(r *renderer.Text, embeds []discord.Embed, m *discord.Message, s store.Cabinet) {
for _, embed := range embeds {
r.StartBlock()
writeEmbedSep(r, embed.Color)
@ -38,7 +38,7 @@ func RenderEmbeds(r *renderer.Text, embeds []discord.Embed, m *discord.Message,
}
}
func RenderEmbed(r *renderer.Text, embed discord.Embed, m *discord.Message, s state.Store) {
func RenderEmbed(r *renderer.Text, embed discord.Embed, m *discord.Message, s store.Cabinet) {
if a := embed.Author; a != nil && a.Name != "" {
if a.ProxyIcon != "" {
r.Append(Author(r.Buffer.Len(), *a))

View File

@ -3,7 +3,7 @@ package embed
import (
"fmt"
"github.com/diamondburned/arikawa/discord"
"github.com/diamondburned/arikawa/v2/discord"
"github.com/diamondburned/cchat-discord/internal/urlutils"
"github.com/diamondburned/cchat/text"
"github.com/diamondburned/cchat/utils/empty"

View File

@ -3,11 +3,11 @@ package emoji
import (
"net/url"
"github.com/diamondburned/arikawa/discord"
"github.com/diamondburned/arikawa/v2/discord"
"github.com/diamondburned/cchat-discord/internal/segments/renderer"
"github.com/diamondburned/cchat/text"
"github.com/diamondburned/cchat/utils/empty"
"github.com/diamondburned/ningen/md"
"github.com/diamondburned/ningen/v2/md"
"github.com/yuin/goldmark/ast"
)

View File

@ -4,7 +4,7 @@ import (
"github.com/diamondburned/cchat-discord/internal/segments/renderer"
"github.com/diamondburned/cchat/text"
"github.com/diamondburned/cchat/utils/empty"
"github.com/diamondburned/ningen/md"
"github.com/diamondburned/ningen/v2/md"
"github.com/yuin/goldmark/ast"
)
@ -48,6 +48,20 @@ func (attr Attribute) Attribute() text.Attribute {
return text.Attribute(attr)
}
// DimSuffix creates a string with the suffix dimmed.
func DimSuffix(prefix, suffix string) text.Rich {
return text.Rich{
Content: prefix + suffix,
Segments: []text.Segment{
Segment{
start: len(prefix),
end: len(prefix) + len(suffix),
attributes: Attribute(text.AttributeDimmed),
},
},
}
}
type Segment struct {
empty.TextSegment
start, end int

View File

@ -1,12 +1,12 @@
package segments
import (
"github.com/diamondburned/arikawa/discord"
"github.com/diamondburned/arikawa/state"
"github.com/diamondburned/arikawa/v2/discord"
"github.com/diamondburned/arikawa/v2/state/store"
"github.com/diamondburned/cchat-discord/internal/segments/embed"
"github.com/diamondburned/cchat-discord/internal/segments/renderer"
"github.com/diamondburned/cchat/text"
"github.com/diamondburned/ningen/md"
"github.com/diamondburned/ningen/v2/md"
_ "github.com/diamondburned/cchat-discord/internal/segments/blockquote"
_ "github.com/diamondburned/cchat-discord/internal/segments/codeblock"
@ -17,7 +17,7 @@ import (
_ "github.com/diamondburned/cchat-discord/internal/segments/mention"
)
func ParseMessage(m *discord.Message, s state.Store) text.Rich {
func ParseMessage(m *discord.Message, s store.Cabinet) text.Rich {
var content = []byte(m.Content)
var node = md.ParseWithMessage(content, s, m, true)
@ -36,7 +36,7 @@ func ParseMessage(m *discord.Message, s state.Store) text.Rich {
}
}
func ParseWithMessage(b []byte, m *discord.Message, s state.Store, msg bool) text.Rich {
func ParseWithMessage(b []byte, m *discord.Message, s store.Cabinet, msg bool) text.Rich {
node := md.ParseWithMessage(b, s, m, msg)
return renderer.RenderNode(b, node)
}

View File

@ -5,8 +5,8 @@ import (
"log"
"testing"
"github.com/diamondburned/arikawa/discord"
"github.com/diamondburned/arikawa/state"
"github.com/diamondburned/arikawa/v2/discord"
"github.com/diamondburned/arikawa/v2/state"
"github.com/diamondburned/cchat/text"
"github.com/go-test/deep"
)

View File

@ -4,14 +4,14 @@ import (
"bytes"
"fmt"
"github.com/diamondburned/arikawa/discord"
"github.com/diamondburned/arikawa/v2/discord"
"github.com/diamondburned/cchat-discord/internal/segments/emoji"
"github.com/diamondburned/cchat-discord/internal/segments/inline"
"github.com/diamondburned/cchat-discord/internal/segments/segutil"
"github.com/diamondburned/cchat-discord/internal/urlutils"
"github.com/diamondburned/cchat/text"
"github.com/diamondburned/cchat/utils/empty"
"github.com/diamondburned/ningen"
"github.com/diamondburned/ningen/v2"
)
type LargeActivityImage struct {
@ -128,7 +128,7 @@ func getPresence(
return &p.Activities[0]
}
return p.Game
return nil
}
func findRole(roles []discord.Role, id discord.RoleID) (discord.Role, bool) {

View File

@ -1,7 +1,7 @@
package mention
import (
"github.com/diamondburned/arikawa/discord"
"github.com/diamondburned/arikawa/v2/discord"
"github.com/diamondburned/cchat-discord/internal/segments/renderer"
"github.com/diamondburned/cchat/text"
)

View File

@ -4,7 +4,7 @@ import (
"github.com/diamondburned/cchat-discord/internal/segments/renderer"
"github.com/diamondburned/cchat/text"
"github.com/diamondburned/cchat/utils/empty"
"github.com/diamondburned/ningen/md"
"github.com/diamondburned/ningen/v2/md"
"github.com/yuin/goldmark/ast"
)

View File

@ -1,7 +1,7 @@
package mention
import (
"github.com/diamondburned/arikawa/discord"
"github.com/diamondburned/arikawa/v2/discord"
"github.com/diamondburned/cchat-discord/internal/segments/colored"
"github.com/diamondburned/cchat/text"
)

View File

@ -4,14 +4,14 @@ import (
"bytes"
"strings"
"github.com/diamondburned/arikawa/discord"
"github.com/diamondburned/arikawa/state"
"github.com/diamondburned/arikawa/v2/discord"
"github.com/diamondburned/arikawa/v2/state/store"
"github.com/diamondburned/cchat-discord/internal/segments/colored"
"github.com/diamondburned/cchat-discord/internal/segments/inline"
"github.com/diamondburned/cchat-discord/internal/segments/segutil"
"github.com/diamondburned/cchat/text"
"github.com/diamondburned/cchat/utils/empty"
"github.com/diamondburned/ningen"
"github.com/diamondburned/ningen/v2"
)
// NameSegment represents a clickable member name; it does not implement colors.
@ -29,6 +29,7 @@ func UserSegment(start, end int, u discord.User) NameSegment {
start: start,
end: end,
um: User{
store: store.NoopCabinet,
Member: discord.Member{User: u},
},
}
@ -39,6 +40,7 @@ func MemberSegment(start, end int, guild discord.Guild, m discord.Member) NameSe
start: start,
end: end,
um: User{
store: store.NoopCabinet,
Guild: guild,
Member: m,
},
@ -48,7 +50,7 @@ func MemberSegment(start, end int, guild discord.Guild, m discord.Member) NameSe
// WithState assigns a ningen state into the given name segment. This allows the
// popovers to have additional information such as user notes.
func (m *NameSegment) WithState(state *ningen.State) {
m.um.state = state
m.um.WithState(state)
}
func (m NameSegment) Bounds() (start, end int) {
@ -67,7 +69,9 @@ func (m NameSegment) AsColorer() text.Colorer {
}
type User struct {
state state.Store
ningen *ningen.State
store store.Cabinet
Guild discord.Guild
Member discord.Member
}
@ -80,9 +84,9 @@ var (
// NewUser creates a new user mention. If state is of type *ningen.State, then
// it'll fetch additional information asynchronously.
func NewUser(state state.Store, guild discord.GuildID, guser discord.GuildUser) *User {
func NewUser(store store.Cabinet, guild discord.GuildID, guser discord.GuildUser) *User {
if guser.Member == nil {
m, err := state.Member(guild, guser.ID)
m, err := store.Member(guild, guser.ID)
if err != nil {
guser.Member = &discord.Member{}
} else {
@ -93,18 +97,22 @@ func NewUser(state state.Store, guild discord.GuildID, guser discord.GuildUser)
guser.Member.User = guser.User
// Get the guild for the role slice. If not, then too bad.
g, err := state.Guild(guild)
g, err := store.Guild(guild)
if err != nil {
g = &discord.Guild{}
}
return &User{
state: state,
store: store,
Guild: *g,
Member: *guser.Member,
}
}
func (um *User) WithState(state *ningen.State) {
um.ningen = state
}
// HasColor returns true if the current user has a color.
func (um User) HasColor() bool {
// We don't have any member color if we have neither the member nor guild.
@ -112,7 +120,7 @@ func (um User) HasColor() bool {
return false
}
g, err := um.state.Guild(um.Guild.ID)
g, err := um.store.Guild(um.Guild.ID)
if err != nil {
return false
}
@ -121,7 +129,7 @@ func (um User) HasColor() bool {
}
func (um User) Color() uint32 {
g, err := um.state.Guild(um.Guild.ID)
g, err := um.store.Guild(um.Guild.ID)
if err != nil {
return colored.Blurple
}
@ -190,9 +198,9 @@ func (um User) MentionInfo() text.Rich {
// These information can only be obtained from the state. As such, we check
// if the state is given.
if ningenState, ok := um.state.(*ningen.State); ok {
if um.ningen != nil {
// Does the user have rich presence? If so, write.
if p, err := um.state.Presence(um.Guild.ID, um.Member.User.ID); err == nil {
if p, err := um.store.Presence(um.Guild.ID, um.Member.User.ID); err == nil {
for _, ac := range p.Activities {
formatActivity(&segment, &content, ac)
content.WriteString("\n\n")
@ -200,11 +208,11 @@ func (um User) MentionInfo() text.Rich {
} else if um.Guild.ID.IsValid() {
// If we're still in a guild, then we can ask Discord for that
// member with their presence attached.
ningenState.MemberState.RequestMember(um.Guild.ID, um.Member.User.ID)
um.ningen.MemberState.RequestMember(um.Guild.ID, um.Member.User.ID)
}
// Write the user's note if any.
if note := ningenState.NoteState.Note(um.Member.User.ID); note != "" {
if note := um.ningen.NoteState.Note(um.Member.User.ID); note != "" {
formatSectionf(&segment, &content, "Note")
content.WriteRune('\n')

View File

@ -1,7 +1,7 @@
package reference
import (
"github.com/diamondburned/arikawa/discord"
"github.com/diamondburned/arikawa/v2/discord"
"github.com/diamondburned/cchat"
"github.com/diamondburned/cchat/text"
"github.com/diamondburned/cchat/utils/empty"

View File

@ -1,7 +1,7 @@
package renderer
import (
"github.com/diamondburned/ningen/md"
"github.com/diamondburned/ningen/v2/md"
)
// InlineState assists in keeping a stateful inline segment builder.

View File

@ -3,13 +3,12 @@ package renderer
import (
"bytes"
"fmt"
"log"
"github.com/diamondburned/arikawa/discord"
"github.com/diamondburned/arikawa/state"
"github.com/diamondburned/arikawa/v2/discord"
"github.com/diamondburned/arikawa/v2/state/store"
"github.com/diamondburned/cchat-discord/internal/segments/segutil"
"github.com/diamondburned/cchat/text"
"github.com/diamondburned/ningen/md"
"github.com/diamondburned/ningen/v2/md"
"github.com/yuin/goldmark/ast"
)
@ -19,7 +18,6 @@ var renderers = map[ast.NodeKind]Renderer{}
// Register registers a renderer to a node kind.
func Register(kind ast.NodeKind, r Renderer) {
log.Printf("Registering kind %v", kind)
renderers[kind] = r
}
@ -50,7 +48,7 @@ type Text struct {
// these fields can be nil
Message *discord.Message
Store state.Store
Store store.Cabinet
}
func New(src []byte, node ast.Node) *Text {
@ -64,7 +62,7 @@ func New(src []byte, node ast.Node) *Text {
}
}
func (r *Text) WithState(m *discord.Message, s state.Store) {
func (r *Text) WithState(m *discord.Message, s store.Cabinet) {
r.Message = m
r.Store = s
}

View File

@ -6,7 +6,7 @@ import (
"strconv"
"strings"
"github.com/diamondburned/arikawa/discord"
"github.com/diamondburned/arikawa/v2/discord"
)
// AvatarURL wraps the URL with URL queries for the avatar.