Skip to content

Commit

Permalink
Merge pull request #15 from TKYcraft/issue#9,14
Browse files Browse the repository at this point in the history
Issue#9,14 複数ギルドの対応および音声がバグる問題の修正
  • Loading branch information
ROBO358 committed May 27, 2022
2 parents c21767b + dc73e41 commit 802ade7
Show file tree
Hide file tree
Showing 3 changed files with 128 additions and 24 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
.DS_Store
.env
app/file/*
120 changes: 104 additions & 16 deletions app/src/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,27 @@ import (
"syscall"
"errors"
"log" // 標準log
"path/filepath" // ファイルパスからファイル名を取得するために使ってる
"sync"

"github.com/bwmarrin/discordgo"
"github.com/bwmarrin/dgvoice" // これを読み込まないように変更する場合はCGO_ENABLEDを変更する必要がありそう
)

var eLog *log.Logger
var DISCORD_TOKEN = os.Getenv("DISCORD_TOKEN")
var PREFIX = os.Getenv("PREFIX")

// IDのみをstringで管理
// IDのみをstringで管理(読み上げBOT実装において読み上げ箇所を保持していたことから存在していると思われる,要確認)
var cMessageChannelID = map[string][]string{}

// VoiceConnectionを保持
var cVoiceChannelVC = map[string]*discordgo.VoiceConnection{}

// 音声を流す処理を排他処理化するためのもの
// voiceMutex[ChannelID].Lock() or .Unlock()
var voiceMutex = map[string]*sync.Mutex{}

func init() {
// defaultのLOG設定
log.SetPrefix("[LOG]")
Expand All @@ -43,9 +50,6 @@ func init() {
}
}

// 再生する音源のバッファー(現状は複数guildに対応していない)
var buffer = make([][]byte, 0)

func main() {
// Create a new Discord session using the provided bot token.
dg, err := discordgo.New("Bot " + DISCORD_TOKEN)
Expand Down Expand Up @@ -123,6 +127,8 @@ func onMessageCreate(s *discordgo.Session, m *discordgo.MessageCreate) {

channelID, err := findVChannel_withUser(s, m.Author.ID, c.GuildID)
if err != nil {
sendReply(s, "何らかのエラーです。\nBOTはあなたがボイスチャンネルに参加していない可能性を疑っているみたい。", m.Reference())
eLog.Printf("BOT seems to have lost track of where the user is\n")
return
}
go sendReply(s, "tsuru.runを実行!", m.Reference())
Expand All @@ -137,7 +143,20 @@ func onMessageCreate(s *discordgo.Session, m *discordgo.MessageCreate) {
}

go sendVoice(cVoiceChannelVC[c.GuildID], "/go_usr/file/airhorn.dca")
sendReply(s, "airhorrrrrrrrn", m.Reference())
go sendReply(s, "airhorrrrrrrrn", m.Reference())

case "play":
// func化したい
if cVoiceChannelVC[c.GuildID] == nil{
sendReply(s, "tsuru-runはどこのボイスチャンネルにも居ないよ。", m.Reference())
eLog.Printf("BOT does not exist on any channels.\n")
return
}

path := "/go_usr/file/chino_and_cocoa.mp3"
go playAudioFile(cVoiceChannelVC[c.GuildID], path)

go sendReply(s, "play:" + path, m.Reference())

case "exit":
// func化したい
Expand All @@ -147,8 +166,13 @@ func onMessageCreate(s *discordgo.Session, m *discordgo.MessageCreate) {
return
}

sendReply(s, "ばいばい。", m.Reference())
go sendReply(s, "ばいばい。", m.Reference())
exitVoiceChannel(c.GuildID)

case "debug":
fmt.Printf(strings.Join(dirwalk("/usr/bin"), "\n"))
fmt.Printf(strings.Join(dirwalk("/go_usr/file"), "\n"))

}
}

Expand Down Expand Up @@ -270,6 +294,9 @@ func exitVoiceChannel(guildID string) {
// 実際に切断
cVoiceChannelVC[guildID].Disconnect()

// 音声の送信も停止されるため、排他処理用のマップからギルドを削除
delete(voiceMutex, cVoiceChannelVC[guildID].ChannelID)

// グローバル変数に存在するコネクションを明示的にnilへ
// これがないとコネクションが有効かを毎回確かめる必要あるかも
// (どっちみち、コネクションが有効か否かは実装する必要ありそう)
Expand All @@ -278,30 +305,32 @@ func exitVoiceChannel(guildID string) {
}


// dca音源送信のため、loadSound()及びplaySoundの呼び出し
// dca音源送信のため、loadSound()及びplaySound()の呼び出し
func sendVoice(vc *discordgo.VoiceConnection, dca_path string){
// ボイスコネクションが存在するか確認
if vc == nil {
eLog.Printf("VoiceConnection is nil.\n")
return
}

err := loadSound(dca_path)
buffer, err := loadSound(dca_path)
if err != nil {
eLog.Printf("Error loading sound: %s\n", dca_path)
return
}

playSound(vc)
playSound(vc, buffer)
}

// pathからサウンドをロードし、bufferへ
func loadSound(path string) error {
func loadSound(path string) ([][]byte, error) {
// 再生する音源のバッファー(現状は複数guildに対応していない)
var buffer = make([][]byte, 0)
// ファイルパスが有効か確認
file, err := os.Open(path)
if err != nil {
eLog.Println("Error opening dca file :", err)
return err
return buffer, err
}

var opuslen int16
Expand All @@ -314,14 +343,14 @@ func loadSound(path string) error {
if err == io.EOF || err == io.ErrUnexpectedEOF {
err := file.Close()
if err != nil {
return err
return buffer, err
}
return nil
return buffer, err
}

if err != nil {
eLog.Println("Error reading from dca file :", err, "\nfile path:", path)
return err
return buffer, err
}

// Read encoded pcm from dca file.
Expand All @@ -331,16 +360,27 @@ func loadSound(path string) error {
// Should not be any end of file errors
if err != nil {
eLog.Println("Error reading from dca file :", err, "\nfile path:", path)
return err
return buffer, err
}

// Append encoded pcm data to the buffer.
buffer = append(buffer, InBuf)
}
return buffer, err
}

// bufferから音源を再生
func playSound(vc *discordgo.VoiceConnection) {
func playSound(vc *discordgo.VoiceConnection, buffer [][]byte) {
// 現在のチャンネルで初めて再生した際に、`Mutex`を使うため初期化
if voiceMutex[vc.ChannelID] == nil {
voiceMutex[vc.ChannelID] = &sync.Mutex{}
}

// 再生開始前に排他処理をするためロック
voiceMutex[vc.ChannelID].Lock()
// 終了時にアンロック
defer voiceMutex[vc.ChannelID].Unlock()

// Speakingを有効化
vc.Speaking(true)

Expand All @@ -352,3 +392,51 @@ func playSound(vc *discordgo.VoiceConnection) {
// Speakingを無効化
vc.Speaking(false)
}

// dgvoice使用
// Takes inbound audio and sends it right back out.
func playAudioFile(vc *discordgo.VoiceConnection, fPath string) {
// 現在のチャンネルで初めて再生した際に、`Mutex`を使うため初期化
if voiceMutex[vc.ChannelID] == nil {
voiceMutex[vc.ChannelID] = &sync.Mutex{}
}

// 再生開始前に排他処理をするためロック
voiceMutex[vc.ChannelID].Lock()
// 終了時にアンロック
defer voiceMutex[vc.ChannelID].Unlock()

// Speakingを有効化
vc.Speaking(true)

// Start loop and attempt to play all files in the given folder
fmt.Println("Reading Folder: ", fPath)
_, err := os.ReadFile(fPath)
if err != nil {
eLog.Printf("ファイルの読み込みに失敗しました:%s", fPath)
return
}

fmt.Println("PlayAudioFile:", fPath)
dgvoice.PlayAudioFile(vc, fPath, make(chan bool))

// Speakingを無効化
vc.Speaking(false)
}

func dirwalk(dir string) []string {
files, err := os.ReadDir(dir)
if err != nil {
panic(err)
}

var paths []string
for _, file := range files {
if file.IsDir() {
paths = append(paths, dirwalk(filepath.Join(dir, file.Name()))...)
continue
}
paths = append(paths, (filepath.Join(dir, file.Name()) + "\n"))
}
return paths
}
31 changes: 23 additions & 8 deletions docker/go/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,37 +1,52 @@
# ビルド用の環境
FROM golang:1.18-alpine as builder

# go installにgitを使っているようなのでadd
RUN apk update && apk --no-cache add git
# go getにgit、glibcが必要となるためmusl-dev、cgoの関係でgccを使っているようなのでadd
RUN apk update && apk --no-cache add git gcc musl-dev

# ディレクトリの作成
RUN mkdir -p /go_usr/app/src /go_usr/app/build
RUN mkdir -p /go_usr/app/src /go_usr/app/build /go_usr/app/pkg

# ワーキングディレクトリの設定
WORKDIR /go_usr/app

RUN go mod init TKYcraft/tsuru-run

# ワーキングディレクトリの設定
WORKDIR /go_usr/app/pkg

# ffmpegのダウンロードと解凍
RUN wget https://johnvansickle.com/ffmpeg/builds/ffmpeg-git-amd64-static.tar.xz && \
tar xvf ffmpeg-git-amd64-static.tar.xz && \
cp -rpf $(ls -d ffmpeg-git*static/) /go_usr/app/pkg/ffmpeg

# 使用しているパッケージのインストール
RUN --mount=type=cache,target=${GOPATH}/src \
go get github.com/bwmarrin/discordgo
# RUN go get github.com/bwmarrin/dgvoice
go get \
github.com/bwmarrin/discordgo \
github.com/bwmarrin/dgvoice \
layeh.com/gopus

# ホストのファイルをコンテナの作業ディレクトリに移行
COPY ./app/src /go_usr/app/src

# ワーキングディレクトリの設定
WORKDIR /go_usr/app

# buildを超えてキャッシュを保持し、ファイルが変更されていなければキャッシュの利用ができる
RUN --mount=type=cache,target=/.cache/go-build \
CGO_ENABLED=0 \
go build -installsuffix cgo -o build/main.build src/main.go
CGO_ENABLED=1 \
# スタティックリンクにすることでバイナリのみで動作するように変更
go build -ldflags '-s -w -extldflags=-static' -o build/main.build src/main.go

# 実行ファイルのみの環境
FROM gcr.io/distroless/static as dev

COPY ./app/file /go_usr/file

# ビルド用の環境から実行ファイルをコピー
COPY --from=builder /go_usr/app/build/main.build /go_usr/app/build/main.build
COPY --from=builder /go_usr/app/pkg/ffmpeg/ffmpeg /usr/bin/ffmpeg
COPY --from=builder /go_usr/app/build /go_usr/app/build

# 実行
ENTRYPOINT [ "/go_usr/app/build/main.build" ]

0 comments on commit 802ade7

Please sign in to comment.