Skip to content

Commit

Permalink
Merge pull request #1 from kaneshin/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
kaneshin authored Jan 1, 2020
2 parents a91e2e2 + 34a1f48 commit ca9ee36
Show file tree
Hide file tree
Showing 17 changed files with 2,279 additions and 563 deletions.
50 changes: 29 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,45 +1,53 @@
# Gate

[![GoDoc](https://godoc.org/github.com/kaneshin/gate?status.svg)](https://godoc.org/github.com/kaneshin/gate)
[![Build Status](https://travis-ci.org/kaneshin/gate.svg?branch=master)](https://travis-ci.org/kaneshin/gate)
[![codecov](https://codecov.io/gh/kaneshin/gate/branch/master/graph/badge.svg)](https://codecov.io/gh/kaneshin/gate)
[![Go Report Card](https://goreportcard.com/badge/github.com/kaneshin/gate)](https://goreportcard.com/report/github.com/kaneshin/gate)
Gate posts a message in Slack and LINE.

## Installation

```shell
go get github.com/kaneshin/gate/cmd/...
```

## Usage
## Setup

### gate
Gate loads its configuration in ~/.config/gate/config.yml as a default. You need to create it then setup your channels' configuration:

```shell
gate -config=/path/to/config.toml -port=8080
```yml
---
default_target: 'slack.incoming.channel-1'

env:
host: 'http://127.0.0.1'
port: 8080

slack:
incoming:
channel-1: '[YOUR-INCOMING-URL]'
channel-2: '[YOUR-INCOMING-URL]'

line:
notify:
service-1: '[YOUR-ACCESS-TOKEN]'
```
conf.toml
## Usage
```toml
[slack.incoming]
url = "[your-incoming-url]"
channel = "general"
username = "gate"
icon_emoji = ":ghost:"
### gate
[line.notify]
access_token = "[your-access-token]"
Run the gate server
[facebook.messenger]
id = "[sender-id]"
access_token = "[page-access-token]"
```shell
$ gate

# gate -config=/path/to/config.yml
```

### gatecli

```shell
echo "foobar" | gatecli
$ echo "foobar" | gatecli

# echo "foobar" | gatecli -config=/path/to/config.yml -target=slack.incomiong.channel-2
```

## License
Expand Down
236 changes: 76 additions & 160 deletions cmd/gate/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,192 +5,108 @@ import (
"log"
"net/http"
"os"
"syscall"
"sync"

"github.com/kaneshin/gate"
"github.com/kaneshin/gate/cmd/internal"
"github.com/kaneshin/gate/facebook"
"github.com/kaneshin/gate/slack"
)

var (
slackIncomingServices map[string]*gate.SlackIncomingService
lineNotifyService *gate.LINENotifyService
facebookMessengerService *gate.FacebookMessengerService
)

const slackIncomingDefaultKey = "github.com/kaneshin/gate/incoming_default"

func handler(w http.ResponseWriter, r *http.Request) {
defer func() {
if r := recover(); r != nil {
log.Println(r)
}
}()
type Data struct {
Target string
Text string `json:"text"`
}

if r.Method != http.MethodPost {
return
func postToSlackIncoming(data Data) error {
config := gate.NewConfig().WithHTTPClient(http.DefaultClient)
svc := gate.NewSlackIncomingService(config).WithBaseURL(data.Target)
_, err := svc.PostTextPayload(gate.TextPayload{
Text: data.Text,
})
if err != nil {
return err
}
return nil
}

var err error
message := r.FormValue("message")
color := r.FormValue("color")
image := r.FormValue("image")

if slackIncomingServices != nil {
ch := r.FormValue("slack.channel")
name := r.FormValue("slack.username")
emoji := r.FormValue("slack.emoji")

key := ""
if ch == "" {
if len(internal.Config.Slack.App.Incoming) > 0 {
ch = internal.Config.Slack.App.Incoming[0].Channel
key = ch
} else {
ch = internal.Config.Slack.Incoming.Channel
key = slackIncomingDefaultKey
}
} else {
for _, v := range internal.Config.Slack.App.Incoming {
if ch == v.Channel {
key = ch
break
}
}
if key == "" {
key = slackIncomingDefaultKey
}
}
if name != "" || emoji != "" {
key = slackIncomingDefaultKey
}
svc, ok := slackIncomingServices[key]
if !ok {
goto finish_slack
}

payload := svc.NewPayload(ch, message)
payload.Username = internal.Config.Slack.Incoming.Username
payload.IconEmoji = internal.Config.Slack.Incoming.IconEmoji

if name != "" {
payload.Username = name
}
if emoji != "" {
payload.IconEmoji = emoji
}

if color != "" {
att := slack.Attachment{
Color: color,
Text: message,
}
payload.Text = ""
payload.Attachments = append(payload.Attachments, att)
}

if image != "" {
att := slack.Attachment{
ImageURL: image,
}
payload.Attachments = append(payload.Attachments, att)
}

_, err = svc.Post(payload)
if err != nil {
log.Printf("[ERROR] %v", err)
}
func postToLINENotify(data Data) error {
config := gate.NewConfig().WithHTTPClient(http.DefaultClient)
config.WithAccessToken(data.Target)
svc := gate.NewLINENotifyService(config)
_, err := svc.PostMessagePayload(gate.MessagePayload{
Message: data.Text,
})
if err != nil {
return err
}
finish_slack:
return nil
}

if lineNotifyService != nil {
_, err = lineNotifyService.Post(message)
if err != nil {
log.Printf("[ERROR] %v", err)
}
func post(name, text string) string {
v, ok := internal.Config.Targets.Load(name)
if !ok {
return fmt.Sprintf("✘ %s not found in your config\n", name)
}

if facebookMessengerService != nil {
id := internal.Config.Facebook.Messenger.ID
payload := facebookMessengerService.NewPayload(id, message)
payload.NotificationType = facebook.NotificationTypeRegular
_, err = facebookMessengerService.Post(payload)
if err != nil {
log.Printf("[ERROR] %v", err)
}
data := Data{
Target: v.(string),
Text: text,
}
}

func newSlackIncomingServices(hcl *http.Client) map[string]*gate.SlackIncomingService {
svc := map[string]*gate.SlackIncomingService{}
url := internal.Config.Slack.Incoming.URL
if url == "" {
url = os.Getenv("SLACK_INCOMING_URL")
var err error
if internal.Config.Slack.IsIncoming(name) {
err = postToSlackIncoming(data)
}
if url != "" {
svc[slackIncomingDefaultKey] = gate.NewSlackIncomingService(
gate.NewConfig().WithHTTPClient(hcl),
).WithBaseURL(url)
if internal.Config.LINE.IsNotify(name) {
err = postToLINENotify(data)
}

for _, v := range internal.Config.Slack.App.Incoming {
if v.URL == "" || v.Channel == "" {
continue
}
svc[v.Channel] = gate.NewSlackIncomingService(
gate.NewConfig().WithHTTPClient(hcl),
).WithBaseURL(v.URL)
if err != nil {
return fmt.Sprintf("✘ %s %v\n", name, err)
}
return svc
return fmt.Sprintf("✔ %s\n", name)
}

func newLINENotifyService(hcl *http.Client) *gate.LINENotifyService {
token := internal.Config.LINE.Notify.AccessToken
if token == "" {
token = os.Getenv("LINE_NOTIFY_ACCESS_TOKEN")
}
if token == "" {
return nil
func handler(w http.ResponseWriter, r *http.Request) {
defer func() {
if r := recover(); r != nil {
log.Println(r)
}
}()

if r.Method != http.MethodPost {
http.Error(w, "405 Not Allowed", http.StatusMethodNotAllowed)
return
}
conf := gate.NewConfig().WithHTTPClient(hcl).WithAccessToken(token)
return gate.NewLINENotifyService(conf)
}

func newFacebookMessengerService(hcl *http.Client) *gate.FacebookMessengerService {
token := internal.Config.Facebook.Messenger.AccessToken
if token == "" {
token = os.Getenv("FACEBOOK_MESSENGER_ACCESS_TOKEN")
err := r.ParseForm()
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
if token == "" {
return nil

text := r.FormValue("text")
var wg sync.WaitGroup
var mu sync.Mutex
for _, name := range r.Form["target"] {
wg.Add(1)
name := name
go func(mu *sync.Mutex) {
defer wg.Done()
mu.Lock()
fmt.Fprint(w, post(name, text))
mu.Unlock()
}(&mu)
}
conf := gate.NewConfig().WithHTTPClient(hcl).WithAccessToken(token)
return gate.NewFacebookMessengerService(conf)
wg.Wait()
}

func main() {
internal.ParseFlag()

sigc := make(chan os.Signal)
internal.Trap(sigc, map[syscall.Signal]func(os.Signal){
syscall.SIGINT: func(sig os.Signal) {
log.Printf("interrupt: %v", sig)
os.Exit(1)
},
syscall.SIGTERM: func(sig os.Signal) {
log.Printf("interrupt: %v", sig)
os.Exit(1)
},
})

hcl := &http.Client{}
slackIncomingServices = newSlackIncomingServices(hcl)
lineNotifyService = newLINENotifyService(hcl)
facebookMessengerService = newFacebookMessengerService(hcl)
err := internal.Load()
if err != nil {
fmt.Printf("%v\n", err)
os.Exit(1)
}

http.HandleFunc("/", handler)

port := fmt.Sprintf(":%d", internal.Config.Gate.Port)
port := fmt.Sprintf(":%d", internal.Config.Env.Port)
fmt.Printf("Listening for HTTP on %s%s\n", internal.Config.Env.Host, port)
log.Fatal(http.ListenAndServe(port, http.DefaultServeMux))
}
Loading

0 comments on commit ca9ee36

Please sign in to comment.