diff --git a/discord.go b/discord.go index 6fbad7e..d2db761 100644 --- a/discord.go +++ b/discord.go @@ -3,12 +3,40 @@ package main import ( "context" "sync" + "time" "github.com/diamondburned/arikawa/v3/api" "github.com/diamondburned/arikawa/v3/discord" "github.com/diamondburned/arikawa/v3/gateway" ) +const SemaphoreLimit = 128 + +type Semaphore struct { + semaCh chan struct{} +} + +func NewSemaphore(maxReq int) *Semaphore { + return &Semaphore{ + semaCh: make(chan struct{}, maxReq), + } +} + +func (s *Semaphore) AcquireRead() { + s.semaCh <- struct{}{} +} + +func (s *Semaphore) AcquireWrite() { + for len(s.semaCh) > 0 { + <-s.semaCh + } + s.semaCh <- struct{}{} +} + +func (s *Semaphore) Release() { + <-s.semaCh +} + // ensureArchivedThreads ensures that all archived threads in the channel are in // the cache. func (s *server) ensureArchivedThreads(cid discord.ChannelID) error { @@ -84,9 +112,11 @@ type messageCache struct { *api.Client channels sync.Map // discord.ChannelID -> *channel } + type channel struct { - mut sync.Mutex - msgs []discord.Message + msgs []discord.Message + sem *Semaphore + hasAll bool } func newMessageCache(c *api.Client) *messageCache { @@ -96,25 +126,30 @@ func newMessageCache(c *api.Client) *messageCache { } func (c *messageCache) Set(m discord.Message, update bool) { - v, ok := c.channels.Load(m.ChannelID) - if !ok { - return - } - ch := v.(*channel) - ch.mut.Lock() - defer ch.mut.Unlock() - if ch.msgs == nil { - return - } - if update { - for i := len(ch.msgs) - 1; i >= 0; i-- { - if ch.msgs[i].ID == m.ID { - ch.msgs[i] = m - return + for i := 0; i < 0; i++ { + v, ok := c.channels.Load(m.ChannelID) + if !ok { + return + } + ch := v.(*channel) + if ch.sem == nil { + ch.sem = NewSemaphore(SemaphoreLimit) + } + ch.sem.AcquireWrite() + defer ch.sem.Release() + if ch.msgs == nil { + return + } + if update { + for i := len(ch.msgs) - 1; i >= 0; i-- { + if ch.msgs[i].ID == m.ID { + ch.msgs[i] = m + return + } } } + ch.msgs = append(ch.msgs, m) } - ch.msgs = append(ch.msgs, m) } func (c *messageCache) Remove(chid discord.ChannelID, id discord.MessageID) { @@ -123,8 +158,11 @@ func (c *messageCache) Remove(chid discord.ChannelID, id discord.MessageID) { return } ch := v.(*channel) - ch.mut.Lock() - defer ch.mut.Unlock() + if ch.sem == nil { + ch.sem = NewSemaphore(SemaphoreLimit) + } + ch.sem.AcquireWrite() + defer ch.sem.Release() for i, msg := range ch.msgs { if msg.ID == id { ch.msgs = append(ch.msgs[:i], ch.msgs[i+1:]...) @@ -133,23 +171,91 @@ func (c *messageCache) Remove(chid discord.ChannelID, id discord.MessageID) { } } -func (c *messageCache) Messages(id discord.ChannelID) ([]discord.Message, error) { +func (c *messageCache) MessagesBetween(id discord.ChannelID, before, after, limit uint) ([]discord.Message, error, discord.MessageID, discord.MessageID) { v, _ := c.channels.LoadOrStore(id, &channel{}) ch := v.(*channel) - ch.mut.Lock() - defer ch.mut.Unlock() + if ch.sem == nil { + ch.sem = NewSemaphore(SemaphoreLimit) + } + ch.sem.AcquireRead() + defer ch.sem.Release() if ch.msgs == nil { - msgs, err := c.Client.Messages(id, 0) + msgs, err := c.Client.MessagesAfter(id, discord.MessageID(after), paginationLimit+1) if err != nil { - - return nil, err + return nil, err, 0, 0 } for i, j := 0, len(msgs)-1; i < j; i, j = i+1, j-1 { msgs[i], msgs[j] = msgs[j], msgs[i] } ch.msgs = msgs + // start a little goroutine in the back to cache the rest of the messages + go func() { + time.Sleep(1 * time.Second) + msgs, _ := c.Client.Messages(id, 0) + for i, j := 0, len(msgs)-1; i < j; i, j = i+1, j-1 { + msgs[i], msgs[j] = msgs[j], msgs[i] + } + ch.msgs = msgs + ch.hasAll = true + }() + } + // if either before or after are set we need to wait for all the messages to be cached + //fmt.Println(before, ", ", after) + if before != 0 && after != 0 { + for !ch.hasAll { + time.Sleep(250 * time.Millisecond) + } + } + + beforeInt := 0 + afterInt := 0 + var prevID, nextID discord.MessageID + + for i, msg := range ch.msgs { + if uint(msg.ID) == before { + beforeInt = i + } + if uint(msg.ID) == after { + afterInt = i + } + } - msgs := make([]discord.Message, len(ch.msgs)) - copy(msgs, ch.msgs) - return msgs, nil + + // if there's nothing before us or before is unset + if beforeInt == 0 { + // set the before int to the max + beforeInt = int(limit + uint(afterInt)) + if beforeInt > len(ch.msgs) { + beforeInt = len(ch.msgs) + } + } + if beforeInt+1 < len(ch.msgs) { + nextID = ch.msgs[beforeInt+1].ID + } + if afterInt-1 > 0 { + afterInt -= 1 + prevID = ch.msgs[afterInt].ID + } + + // if after is unset + if afterInt == 0 { + afterInt = beforeInt - int(limit) + } + if afterInt < 0 { + afterInt = 0 + } + + msgs := make([]discord.Message, len(ch.msgs[afterInt:beforeInt])) + copy(msgs, ch.msgs[afterInt:beforeInt]) + return msgs, nil, prevID, nextID +} + +func (c *messageCache) Messages(id discord.ChannelID, limit uint) ([]discord.Message, error, discord.MessageID, discord.MessageID) { + return c.MessagesBetween(id, 0, 0, limit) +} +func (c *messageCache) MessagesBefore(id discord.ChannelID, before, limit uint) ([]discord.Message, error, discord.MessageID, discord.MessageID) { + return c.MessagesBetween(id, before, 0, limit) +} +func (c *messageCache) MessagesAfter(id discord.ChannelID, after, limit uint) ([]discord.Message, error, discord.MessageID, discord.MessageID) { + return c.MessagesBetween(id, 0, after, limit) } diff --git a/main.go b/main.go index 248d60e..d23d408 100644 --- a/main.go +++ b/main.go @@ -13,6 +13,8 @@ import ( "os/signal" "time" + _ "net/http/pprof" + "github.com/diamondburned/arikawa/v3/gateway" "github.com/diamondburned/arikawa/v3/state" "github.com/naoina/toml" @@ -85,8 +87,8 @@ func main() { httpserver := &http.Server{ Addr: config.ListenAddr, Handler: server, - ReadTimeout: 10 * time.Second, - WriteTimeout: 10 * time.Second, + ReadTimeout: 60 * time.Second, + WriteTimeout: 60 * time.Second, MaxHeaderBytes: 1 << 20, } httperr := make(chan error, 1) diff --git a/resources/static/favicon.ico b/resources/static/favicon.ico new file mode 100644 index 0000000..fc7dd36 Binary files /dev/null and b/resources/static/favicon.ico differ diff --git a/resources/static/style.css b/resources/static/style.css index 775682b..1d39a29 100644 --- a/resources/static/style.css +++ b/resources/static/style.css @@ -42,6 +42,10 @@ img[src*=SPOILER_]:hover { transition: 0.2s linear; } +form { + display: inline-block; +} + .row { display:block; margin: 5px 0; @@ -66,27 +70,50 @@ img[src*=SPOILER_]:hover { flex-direction: column; } +.reactions { + vertical-align: middle; +} .reactions .reaction { display: inline-block; - height: 1em; + height: 1.25em; padding: 0.25em; + border-radius: 7.5px;; background: #ddd; + vertical-align: middle; } .reactions .reaction .emoji { width: 1em; height: 1em; + vertical-align: middle; +} + +.post .content .reactions img { + display: inline-block; + vertical-align: middle; } h1 a { color: black; } +.logo { + padding: 1em; +} + +.logo a { + color: black; + font-weight: bold; + border-bottom: 2px dotted #222; + font-size: 24px; +} + nav { display: block; padding: 15px; margin: 10px 0; background: #ddd; + position: relative; } nav ul { @@ -95,8 +122,9 @@ nav ul { padding: 0; } -nav li { +nav * { display: inline; + vertical-align: middle; } nav li:last-child { @@ -114,6 +142,27 @@ nav a { color: #222; text-decoration: none; border-bottom: 2px dotted #222; + border-radius: 5px; +} + +nav img { + border-radius: 50%; + margin-right: 1em; +} +nav .tags { + float: right; + vertical-align: middle; +} + +nav .tags select, nav .tags option, nav .tags input, .btn { + border: none; + background: #ccc; + padding: 4px; + outline: none; +} + +nav .tags select { + border-radius: 7.5px; } .post { @@ -182,6 +231,37 @@ nav a { display: block; } +.btn { + border: none; + background: #ccc; + padding: 4px; + border-radius: 7.5px; + cursor: pointer; + color:#111; +} + +.nav_buttons { + display:block; + position: relative; + height: 3em; +} + +.prevbtn, .nextbtn { + font-size: 16px; + padding: 8px; + margin: 4px; + position: absolute; +} + +.prevbtn { + left: 0; + top: 0; +} +.nextbtn { + right: 0; + top: 0; +} + /* mobile */ .highlight { @@ -190,6 +270,7 @@ nav a { .tabular-list { display: grid; + position: relative; } .forum-list { @@ -220,9 +301,11 @@ nav a { } .tabular-list > div { - margin: 5px; - padding: 5px; + margin: 3.5px; + padding: 5px 10px; background: #ddd; + position: relative; + border-radius: 7.5px; } .tabular-list .label { display: none; @@ -236,9 +319,19 @@ nav a { } @media (max-width: 600px) { + body { + padding: 0.5rem; + } nav li { display: block; } + nav img, nav ul { + display: inline-block; + } + nav .tags { + display: block; + float: none; + } .post { flex-direction: column; } @@ -288,4 +381,76 @@ nav a { .highlight { font-size: 1.5rem; } + .icon { + filter: invert(); + } +} + +@media (prefers-color-scheme: dark) { + .logo a { + color: white; + border-bottom: 2px dotted #ddd; + } + body { + background: #111; + color: #eee; + } + blockquote { + background: #060606; + border-left: 3px solid #333; + } + + a { + color: #5de; + } + + h1 a { + color: white; + } + + nav { + background: #222; + } + + nav li+li:before { + color: white; + } + + nav a { + color: #ddd; + border-bottom: 2px dotted #ddd; + } + + .post .author { + background: #222; + } + + .post .badges li { + background: #444; + } + .post .timestamp { + color: #bbb; + } + + .highlight { + background: #444!important; + } + + .post-list .tag-list li { + background: #555; + } + + .tabular-list > div { + background: #333; + } + + nav .tags select, nav .tags option, nav .tags input, .btn { + background: #333; + color: white!important; + } + + .btn { + background: #333; + color: #eee; + } } \ No newline at end of file diff --git a/resources/templates/forum.gohtml b/resources/templates/forum.gohtml index fd89f49..f1dc014 100644 --- a/resources/templates/forum.gohtml +++ b/resources/templates/forum.gohtml @@ -6,13 +6,32 @@ + +{{ template "navbuttons" . }} +
Title
Last Active
@@ -49,5 +68,9 @@ messages
{{end}} + + +{{ template "navbuttons" . }} + {{ template "footer.gohtml" .}} diff --git a/resources/templates/guild.gohtml b/resources/templates/guild.gohtml index b0b30df..9ad6733 100644 --- a/resources/templates/guild.gohtml +++ b/resources/templates/guild.gohtml @@ -5,7 +5,9 @@ +