組み込みProgrammerのチラシの裏

Linenotify

| Comments

何かを自動化したときに、スマートフォンに通知を送りたいと思っていた。 そんな時、LINE Notifyを使えば簡単に解決できそうなので調査。 実際使ってみたところ、簡単に自分のスマートフォンに通知できるし、 グループに登録すれば複数人で通知を共有できるので非常に便利だった。

準備

を参考に進めると簡単にLINE Notifyへ登録できる。

curl編

curlからLINE Notifyに送信できるのでかなりお手軽。 つまり、shellからでも送信できてしまう。

1
$ curl -X POST -H "Authorization: Bearer ACCESS_TOKEN" -F "message=テスト" https://notify-api.line.me/api/notify

画像添付するのも簡単。

1
$ curl -X POST -H "Authorization: Bearer ACCESS_TOKEN" -F "message=テスト" -F "imageFile=@image_path.png" https://notify-api.line.me/api/notify

Go言語編

Goから送信するデファクトスタンダードライブラリが見つからなかったので自作。 そもそもcurlで送れるレベルなので、100行程度少し書けば良い。

  • func NotifyLineMessage(message, token string) error LINE Notifyにメッセージを送る
  • func NotifyLineImage(img io.Reader, filename, message, token string) error LINE Notifyに画像・メッセージを送る
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
package line

import (
  "bytes"
  "fmt"
  "image"
  _ "image/gif"
  _ "image/png"
  "image/jpeg"
  "io"
  "io/ioutil"
  "mime/multipart"
  "net/url"
  "net/http"
  "net/textproto"
  "strings"
)

const (
  lineNotifyURL = "https://notify-api.line.me/api/notify"
)

func NotifyLineMessage(message, token string) error {
  if token == "" {
      return fmt.Errorf("line: no token")
  } else if message == "" {
      return fmt.Errorf("line: no message")
  }

  data := url.Values{"message": {message}}
  r, _ := http.NewRequest("POST", lineNotifyURL, strings.NewReader(data.Encode()))
  r.Header.Set("Content-Type", "application/x-www-form-urlencoded")
  r.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token))
  resp, err := http.DefaultClient.Do(r)
  if err != nil {
      return fmt.Errorf("line: %v", err)
  }
  defer resp.Body.Close()
  respBody, err := ioutil.ReadAll(resp.Body)
  if err != nil {
      return fmt.Errorf("line: %v", err)
  }
  if resp.StatusCode != 200 {
      return fmt.Errorf("line: %s: %v", respBody, err)
  }
  return nil
}

func convert2Jpeg(img io.Reader) (io.Reader, error) {
  dimg, _, err := image.Decode(img)
  if err != nil {
      return nil, err
  }

  var b bytes.Buffer
  err = jpeg.Encode(&b, dimg, &jpeg.Options{Quality: 100})
  return &b, err
}

func NotifyLineImage(img io.Reader, filename, message, token string) error {
  if token == "" {
      return fmt.Errorf("line: no token")
  }

  body := &bytes.Buffer{}
  mw   := multipart.NewWriter(body)

  ffw, err := mw.CreateFormField("message")
  if err != nil {
      return fmt.Errorf("line: %v", err)
  }
  if _, err = ffw.Write([]byte(message)); err != nil {
      return fmt.Errorf("line: %v", err)
  }

  part := make(textproto.MIMEHeader)
  part.Set("Content-Disposition", `form-data; name="imageFile"; filename=`+filename)
  part.Set("Content-Type", "image/jpeg")

  fw, err := mw.CreatePart(part)
  if err != nil {
      return fmt.Errorf("line: %v", err)
  }

  cimg, err := convert2Jpeg(img)
  if err != nil {
      return fmt.Errorf("line: %v", err)
  }

  _, err = io.Copy(fw, cimg)
  if err != nil {
      return fmt.Errorf("line: %v", err)
  }
  err = mw.Close()
  if err != nil {
      return fmt.Errorf("line: %v", err)
  }

  r, _ := http.NewRequest("POST", lineNotifyURL, body)
  r.Header.Set("Content-Type", mw.FormDataContentType())
  r.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token))
  resp, err := http.DefaultClient.Do(r)
  if err != nil { 
      return fmt.Errorf("line: %v", err)
  }
  defer resp.Body.Close()
  respBody, err := ioutil.ReadAll(resp.Body)
  if err != nil {
      return fmt.Errorf("line: %v", err)
  }
  if resp.StatusCode != 200 {
      return fmt.Errorf("line: %s: %v", respBody, err)
  }
  return nil
}

参考ページ

Comments