Skip to content

Commit

Permalink
v1
Browse files Browse the repository at this point in the history
  • Loading branch information
wtks committed May 9, 2019
0 parents commit 11505dc
Show file tree
Hide file tree
Showing 8 changed files with 316 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.idea
32 changes: 32 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# traQ BOTサーバーライブラリ
traQ BOTサーバーを簡単に作るためのライブラリです。

`traQ--->BOTサーバー`へのイベントの受け取り部分を補助します。`BOTサーバー--->traQ`へのリクエストを行うための、traQ APIクライアントは含まれていません。

## サンプル
```go
package main

import (
"github.com/traPtitech/traq-bot"
"log"
"os"
)

func main() {
vt := os.Getenv("VERIFICATION_TOKEN")

handlers := traqbot.EventHandlers{}
handlers.SetMessageCreatedHandler(func(payload *traqbot.MessageCreatedPayload) {
log.Println("=================================================")
log.Printf("%sさんがメッセージを投稿しました。\n", payload.Message.User.DisplayName)
log.Println("メッセージ:")
log.Println(payload.Message.Text)
log.Println("=================================================")
})

server := traqbot.NewBotServer(vt, handlers)
log.Fatal(server.ListenAndServe(":80"))
}

```
73 changes: 73 additions & 0 deletions common_payload.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package traqbot

import "time"

// BasePayload ベースペイロード
type BasePayload struct {
// EventTime イベント発生日時
EventTime time.Time `json:"eventTime"`
}

// UserPayload ユーザー情報ペイロード
type UserPayload struct {
// ID ユーザーUUID
ID string `json:"id"`
// Name ユーザーのtraQ ID
Name string `json:"name"`
// DisplayName ユーザーの表示名
DisplayName string `json:"displayName"`
// IconID ユーザーアイコンのファイルUUID
IconID string `json:"iconId"`
// Bot ユーザーがBotかどうか
Bot bool `json:"bot"`
}

// ChannelPayload チャンネル情報ペイロード
type ChannelPayload struct {
// ID チャンネルUUID
ID string `json:"id"`
// Name チャンネル名
Name string `json:"name"`
// Path チャンネルパス
Path string `json:"path"`
// ParentID 親チャンネルのUUID
//
// ルートチャンネルの場合は"00000000-0000-0000-0000-000000000000"
ParentID string `json:"parentId"`
// Creator チャンネル作成者
Creator UserPayload `json:"creator"`
// CreatedAt チャンネル作成日時
CreatedAt time.Time `json:"createdAt"`
// UpdatedAt チャンネル更新日時
UpdatedAt time.Time `json:"updatedAt"`
}

// MessagePayload メッセージ情報ペイロード
type MessagePayload struct {
// ID メッセージUUID
ID string `json:"id"`
// User メッセージ投稿者
User UserPayload `json:"user"`
// ChannelID 投稿先チャンネルUUID
ChannelID string `json:"channelId"`
// Text 生メッセージ本文
Text string `json:"text"`
// PlainText メッセージ本文(埋め込み情報・改行なし)
PlainText string `json:"plainText"`
// Embedded メッセージ埋め込み情報の配列
Embedded []EmbeddedInfoPayload `json:"embedded"`
// CreatedAt メッセージ投稿日時
CreatedAt time.Time `json:"createdAt"`
// UpdatedAt メッセージ更新日時
UpdatedAt time.Time `json:"updatedAt"`
}

// EmbeddedInfoPayload メッセージ埋め込み情報
type EmbeddedInfoPayload struct {
// Raw 表示文字列
Raw string `json:"raw"`
// Type タイプ
Type string `json:"type"`
// ID 各種ID(タイプによる)
ID string `json:"id"`
}
48 changes: 48 additions & 0 deletions event_payload.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package traqbot

// PingPayload PINGイベントペイロード
type PingPayload struct {
BasePayload
}

// JoinedPayload JOINEDイベントペイロード
type JoinedPayload struct {
BasePayload
// Channel 参加したチャンネル
Channel ChannelPayload `json:"channel"`
}

// LeftPayload LEFTイベントペイロード
type LeftPayload struct {
BasePayload
// Channel 退出したチャンネル
Channel ChannelPayload `json:"channel"`
}

// MessageCreatedPayload MESSAGE_CREATEDイベントペイロード
type MessageCreatedPayload struct {
BasePayload
// Message 投稿されたメッセージ
Message MessagePayload `json:"message"`
}

// DirectMessageCreatedPayload DIRECT_MESSAGE_CREATEDイベントペイロード
type DirectMessageCreatedPayload struct {
BasePayload
// Message 投稿されたメッセージ
Message MessagePayload `json:"message"`
}

// ChannelCreatedPayload CHANNEL_CREATEDイベントペイロード
type ChannelCreatedPayload struct {
BasePayload
// Channel 作成されたチャンネル
Channel ChannelPayload `json:"channel"`
}

// UserCreatedPayload USER_CREATEDイベントペイロード
type UserCreatedPayload struct {
BasePayload
// User 作成されたユーザー
User UserPayload `json:"user"`
}
18 changes: 18 additions & 0 deletions events.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package traqbot

const (
// Ping PINGイベント
Ping = "PING"
// Joined JOINEDイベント
Joined = "JOINED"
// Left LEFTイベント
Left = "LEFT"
// MessageCreated MESSAGE_CREATEDイベント
MessageCreated = "MESSAGE_CREATED"
// DirectMessageCreated DIRECT_MESSAGE_CREATEDイベント
DirectMessageCreated = "DIRECT_MESSAGE_CREATED"
// ChannelCreated CHANNEL_CREATEDイベント
ChannelCreated = "CHANNEL_CREATED"
// UserCreated USER_CREATEDイベント
UserCreated = "USER_CREATED"
)
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module github.com/traPtitech/traq-bot
47 changes: 47 additions & 0 deletions helper.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package traqbot

// SetHandler イベントハンドラをセットします
//
// ハンドラにnilを指定すると、ハンドラは削除されます
func (hs EventHandlers) SetHandler(event string, h EventHandler) {
if h == nil {
delete(hs, event)
} else {
hs[event] = h
}
}

// SetPingHandler イベントハンドラをセットします
func (hs EventHandlers) SetPingHandler(h func(payload *PingPayload)) {
hs.SetHandler(Ping, func(event string, payload interface{}) { h(payload.(*PingPayload)) })
}

// SetJoinedHandler イベントハンドラをセットします
func (hs EventHandlers) SetJoinedHandler(h func(payload *JoinedPayload)) {
hs.SetHandler(Joined, func(event string, payload interface{}) { h(payload.(*JoinedPayload)) })
}

// SetLeftHandler イベントハンドラをセットします
func (hs EventHandlers) SetLeftHandler(h func(payload *LeftPayload)) {
hs.SetHandler(Left, func(event string, payload interface{}) { h(payload.(*LeftPayload)) })
}

// SetMessageCreatedHandler イベントハンドラをセットします
func (hs EventHandlers) SetMessageCreatedHandler(h func(payload *MessageCreatedPayload)) {
hs.SetHandler(MessageCreated, func(event string, payload interface{}) { h(payload.(*MessageCreatedPayload)) })
}

// SetDirectMessageCreatedHandler イベントハンドラをセットします
func (hs EventHandlers) SetDirectMessageCreatedHandler(h func(payload *DirectMessageCreatedPayload)) {
hs.SetHandler(DirectMessageCreated, func(event string, payload interface{}) { h(payload.(*DirectMessageCreatedPayload)) })
}

// SetChannelCreatedHandler イベントハンドラをセットします
func (hs EventHandlers) SetChannelCreatedHandler(h func(payload *ChannelCreatedPayload)) {
hs.SetHandler(ChannelCreated, func(event string, payload interface{}) { h(payload.(*ChannelCreatedPayload)) })
}

// SetUserCreatedHandler イベントハンドラをセットします
func (hs EventHandlers) SetUserCreatedHandler(h func(payload *UserCreatedPayload)) {
hs.SetHandler(UserCreated, func(event string, payload interface{}) { h(payload.(*UserCreatedPayload)) })
}
96 changes: 96 additions & 0 deletions server.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package traqbot

import (
"encoding/json"
"net/http"
"strings"
)

const (
contentTypeHeader = "Content-Type"
mimeApplicationJson = "application/json"
botTokenHeader = "X-TRAQ-BOT-TOKEN"
botEventHeader = "X-TRAQ-BOT-EVENT"
)

// EventHandler イベントハンドラ
type EventHandler func(event string, payload interface{})

// EventHandlers イベントハンドラマップ
type EventHandlers map[string]EventHandler

// BotServer BOTサーバー
type BotServer struct {
verificationToken string
handlers EventHandlers
}

// NewBotServer 新しくBOTサーバーを生成します
func NewBotServer(verification string, handlers EventHandlers) *BotServer {
return &BotServer{
verificationToken: verification,
handlers: handlers,
}
}

// ListenAndServe BOTサーバーを起動します
func (bs *BotServer) ListenAndServe(addr string) error {
mux := http.NewServeMux()
mux.Handle("/", bs)
server := &http.Server{Addr: addr, Handler: mux}
return server.ListenAndServe()
}

// ServeHTTP BOTサーバーハンドラ
func (bs *BotServer) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
// VerificationTokenチェック
if req.Header.Get(botTokenHeader) != bs.verificationToken {
rw.WriteHeader(http.StatusForbidden)
return
}

// Eventヘッダチェック
event := req.Header.Get(botEventHeader)
if len(event) == 0 {
rw.WriteHeader(http.StatusBadRequest)
return
}

// RequestがJSONかどうか
if !strings.HasPrefix(req.Header.Get(contentTypeHeader), mimeApplicationJson) {
rw.WriteHeader(http.StatusBadRequest)
return
}

var payload interface{}
switch event {
case Ping:
payload = &PingPayload{}
case Joined:
payload = &JoinedPayload{}
case Left:
payload = &LeftPayload{}
case MessageCreated:
payload = &MessageCreatedPayload{}
case DirectMessageCreated:
payload = &DirectMessageCreatedPayload{}
case ChannelCreated:
payload = &ChannelCreatedPayload{}
case UserCreated:
payload = &UserCreatedPayload{}
default:
rw.WriteHeader(http.StatusNotImplemented)
return
}

if err := json.NewDecoder(req.Body).Decode(payload); err != nil {
rw.WriteHeader(http.StatusBadRequest)
return
}
rw.WriteHeader(http.StatusNoContent)

h, ok := bs.handlers[event]
if ok && h != nil {
h(event, payload)
}
}

0 comments on commit 11505dc

Please sign in to comment.