Skip to content

Instantly share code, notes, and snippets.

@CarsonSlovoka
Created February 9, 2023 07:05
Show Gist options
  • Select an option

  • Save CarsonSlovoka/f51164f8fc7ccef71e5687678d1fab2c to your computer and use it in GitHub Desktop.

Select an option

Save CarsonSlovoka/f51164f8fc7ccef71e5687678d1fab2c to your computer and use it in GitHub Desktop.
回答discordgo用
package main
import (
"bufio"
"log"
"os"
"time"
)
type User struct {
name string
msg chan []byte
Active bool
buf []byte
start int // buf用
end int // buf用
off int // 紀錄Read當前讀到哪個位子
}
const startBufSize = 1024
func NewUser(name string) *User {
u := &User{name: name,
msg: make(chan []byte),
buf: make([]byte, 0),
Active: true,
}
go u.listenMsg()
return u
}
func (u *User) Read(b []byte) (n int, err error) {
n = copy(b, u.buf[u.off:])
u.off += n
return n, nil
}
func (u *User) listenMsg() {
for {
select {
case msg, isOpen := <-u.msg:
if !isOpen {
return
}
if !u.Active {
break
}
if u.end == len(u.buf) { // buffer full, so, resize
// https://github.com/golang/go/blob/8fb9565832e6dbacaaa057ffabc251a9341f8d23/src/bufio/scan.go#L189-L209
newSize := len(u.buf) * 2
if newSize == 0 {
newSize = startBufSize
}
newBuf := make([]byte, newSize)
copy(newBuf, u.buf[u.start:u.end])
u.buf = newBuf
u.end -= u.start
u.start = 0
}
n := copy(u.buf[u.end:len(u.buf)], msg)
u.end += n
}
}
}
type Hub struct {
userList map[*User]bool
Register chan *User
Unregister chan *User
Broadcast chan []byte
closed bool
}
func NewHub() *Hub {
return &Hub{
userList: make(map[*User]bool),
Register: make(chan *User),
Unregister: make(chan *User),
Broadcast: make(chan []byte),
}
}
func (h *Hub) Run() {
for {
if h.closed {
return
}
select {
case user, isOpen := <-h.Register:
if !isOpen {
return
}
h.userList[user] = true
case user, isOpen := <-h.Unregister:
if !isOpen {
return
}
h.deleteUser(user)
case data, isOpen := <-h.Broadcast:
if !isOpen {
return
}
for u := range h.userList {
if !u.Active {
continue
}
select {
case u.msg <- data:
case <-time.After(3 * time.Second):
log.Printf("此資料無法傳給使用者:%s 故將此使用者刪除\n", u.name)
h.deleteUser(u)
}
}
}
}
}
func (h *Hub) deleteUser(u *User) {
u.Active = false
close(u.msg)
delete(h.userList, u)
}
func (h *Hub) Release() {
for u := range h.userList {
h.deleteUser(u)
}
close(h.Unregister)
close(h.Register)
h.closed = true
}
func main() {
hub := NewHub()
defer hub.Release()
userCarson := NewUser("Carson")
userFoo := NewUser("Foo")
go hub.Run()
hub.Register <- userCarson
hub.Register <- userFoo
// Test
go func() {
<-time.After(4 * time.Second)
buf := make([]byte, 5)
_, _ = userCarson.Read(buf)
log.Printf("%s: %s\n", userCarson.name, buf)
<-time.After(8 * time.Second)
buf = make([]byte, 20)
_, _ = userCarson.Read(buf)
log.Printf("%s: %s\n", userCarson.name, buf)
buf = make([]byte, 1024)
_, _ = userFoo.Read(buf)
log.Printf("%s: %s\n", userFoo.name, buf)
log.Println("請輸入退出: -1")
return
}()
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
text := scanner.Text()
if text == "quit" || text == "exit" || text == "-1" {
return
}
hub.Broadcast <- []byte(text)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment