├── .gitignore ├── .env.dist ├── overview.png ├── api ├── Notification.go ├── telegram.go └── api.go ├── go-telegram-notifier-logo.jpg ├── main.go ├── Dockerfile ├── config └── config.go ├── helper └── error.go ├── README.md └── deployment.yaml /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .env -------------------------------------------------------------------------------- /.env.dist: -------------------------------------------------------------------------------- 1 | APP_PORT=5000 2 | TG_CHAT_ID= 3 | TG_BOT_TOKEN= 4 | TOKEN= -------------------------------------------------------------------------------- /overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SlitiBrahim/go-telegram-notifier/HEAD/overview.png -------------------------------------------------------------------------------- /api/Notification.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | type Notification struct { 4 | Message string `json:"message"` 5 | } 6 | -------------------------------------------------------------------------------- /go-telegram-notifier-logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SlitiBrahim/go-telegram-notifier/HEAD/go-telegram-notifier-logo.jpg -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "go-telegram-notifier/api" 5 | ) 6 | 7 | func main() { 8 | api.Start() 9 | } 10 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1.15 AS build 2 | WORKDIR /go/src/go-telegram-notifier 3 | COPY . . 4 | # install dependencies 5 | RUN go get -v ./... 6 | RUN go build -o telegram-notifier . 7 | 8 | CMD ["./telegram-notifier"] -------------------------------------------------------------------------------- /config/config.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | ) 7 | 8 | // TODO: better solution ? 9 | var Config = make(map[string]interface{}) 10 | 11 | func init() { 12 | Config["APP_PORT"] = os.Getenv("APP_PORT") 13 | Config["TG_CHAT_ID"] = os.Getenv("TG_CHAT_ID") 14 | Config["TG_BOT_TOKEN"] = os.Getenv("TG_BOT_TOKEN") 15 | Config["TOKEN"] = os.Getenv("TOKEN") 16 | Config["TG_API_BOT_BASE_URL"] = fmt.Sprintf("https://api.telegram.org/bot%s/", Config["TG_BOT_TOKEN"]) 17 | } 18 | -------------------------------------------------------------------------------- /helper/error.go: -------------------------------------------------------------------------------- 1 | package helper 2 | 3 | import ( 4 | "encoding/json" 5 | "log" 6 | "net/http" 7 | ) 8 | 9 | func FailOnError(err error) { 10 | if err != nil { 11 | log.Fatal(err) 12 | } 13 | } 14 | 15 | func SendApiError(w http.ResponseWriter, err error, httpStatus int) { 16 | if err != nil { 17 | httpErr := map[string]interface{}{ 18 | "error": err.Error(), 19 | } 20 | 21 | w.Header().Set("Content-Type", "application/json") 22 | w.WriteHeader(httpStatus) 23 | 24 | json.NewEncoder(w).Encode(httpErr) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /api/telegram.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | "go-telegram-notifier/config" 7 | "go-telegram-notifier/helper" 8 | "net/http" 9 | "net/url" 10 | "path" 11 | ) 12 | 13 | type Message struct { 14 | ChatID string `json:"chat_id"` 15 | Text string `json:"text"` 16 | } 17 | 18 | func getSendMessageURL() string { 19 | baseURL, err := url.Parse(config.Config["TG_API_BOT_BASE_URL"].(string)) 20 | helper.FailOnError(err) 21 | 22 | baseURL.Path = path.Join(baseURL.Path, "/sendMessage") 23 | 24 | return baseURL.String() 25 | } 26 | 27 | func sendMessage(message Message) (*http.Response, error) { 28 | body, err := json.Marshal(message) 29 | helper.FailOnError(err) 30 | 31 | return http.Post(getSendMessageURL(), "application/json", bytes.NewReader(body)) 32 | } 33 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 |

3 | 4 | Logo 5 | 6 | 7 |

go-telegram-notifier

8 |

9 | 10 | # go-telegram-notifier 11 | 12 | A Go REST API wrapping the official Telegram API and used to send myself notifications, on my phone, based on some events. 13 | 14 | ## What is the difference with the official API 15 | 16 | - This API is the program running behind the personal bot I created for my use. 17 | - This bot acts as my personnal assistant: 18 | I want it to push to me notifications on some events and answer me based on actions I ask him to perform (coming later). 19 | - Wanted to handle authentication as I want. 20 | - The application is stored on my own server and I can scale it depending on my needs. 21 | 22 | ## Overview 23 | 24 | Here is an overview of the use of that API (in production). 25 | 26 |
27 | 28 | Overview 29 | 30 |
31 | -------------------------------------------------------------------------------- /deployment.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Namespace 4 | metadata: 5 | name: telegram-notifier 6 | --- 7 | apiVersion: v1 8 | data: 9 | APP_PORT: "80" 10 | # set values here 11 | TG_BOT_TOKEN: 12 | TG_CHAT_ID: 13 | TOKEN: 14 | kind: ConfigMap 15 | metadata: 16 | name: notifier-cm 17 | namespace: telegram-notifier 18 | --- 19 | apiVersion: apps/v1 20 | kind: Deployment 21 | metadata: 22 | labels: 23 | app: telegram-notifier 24 | name: telegram-notifier 25 | namespace: telegram-notifier 26 | spec: 27 | replicas: 1 28 | selector: 29 | matchLabels: 30 | app: telegram-notifier 31 | template: 32 | metadata: 33 | labels: 34 | app: telegram-notifier 35 | spec: 36 | containers: 37 | - image: slitibrahim/telegram-notifier 38 | name: telegram-notifier 39 | ports: 40 | - name: http 41 | containerPort: 80 42 | envFrom: 43 | - configMapRef: 44 | name: notifier-cm 45 | --- 46 | apiVersion: v1 47 | kind: Service 48 | metadata: 49 | name: telegram-notifier-svc 50 | namespace: telegram-notifier 51 | spec: 52 | selector: 53 | app: telegram-notifier 54 | ports: 55 | - port: 80 56 | targetPort: 80 57 | protocol: TCP 58 | name: http 59 | --- 60 | apiVersion: extensions/v1beta1 61 | kind: Ingress 62 | metadata: 63 | name: telegram-notifier-ingress 64 | namespace: telegram-notifier 65 | spec: 66 | rules: 67 | - host: notifier.sliti-brahim.com 68 | http: 69 | paths: 70 | - backend: 71 | serviceName: telegram-notifier-svc 72 | servicePort: 80 73 | --- -------------------------------------------------------------------------------- /api/api.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "encoding/json" 5 | "errors" 6 | "fmt" 7 | "github.com/gorilla/mux" 8 | "go-telegram-notifier/config" 9 | "go-telegram-notifier/helper" 10 | "log" 11 | "net/http" 12 | ) 13 | 14 | func authenticatedReq(r *http.Request) bool { 15 | return r.Header.Get("token") == config.Config["TOKEN"] 16 | } 17 | 18 | func sendNotificationHandler(w http.ResponseWriter, r *http.Request) { 19 | if authenticatedReq(r) == false { 20 | helper.SendApiError(w, errors.New("invalid token"), http.StatusForbidden) 21 | return 22 | } 23 | 24 | var notification Notification 25 | err := json.NewDecoder(r.Body).Decode(¬ification) 26 | if err != nil { 27 | helper.SendApiError(w, errors.New("invalid request body: cannot parse body to Notification object"), http.StatusBadRequest) 28 | return 29 | } 30 | 31 | if notification.Message == "" { 32 | helper.SendApiError(w, errors.New("empty message passed"), http.StatusBadRequest) 33 | return 34 | } 35 | 36 | msg := Message{ 37 | ChatID: config.Config["TG_CHAT_ID"].(string), 38 | Text: notification.Message, 39 | } 40 | 41 | telegramResponse, err := sendMessage(msg) 42 | helper.SendApiError(w, err, http.StatusInternalServerError) 43 | 44 | if telegramResponse.StatusCode == http.StatusOK { 45 | res := map[string]interface{}{ 46 | "message": "Notification has been sent.", 47 | } 48 | 49 | err = ReturnResponse(w, res, http.StatusOK) 50 | helper.SendApiError(w, err, http.StatusInternalServerError) 51 | } else { 52 | res := map[string]interface{}{ 53 | "message": "Notification cannot be sent.", 54 | "error": err.Error(), 55 | } 56 | 57 | err = ReturnResponse(w, res, http.StatusBadRequest) 58 | helper.SendApiError(w, err, http.StatusInternalServerError) 59 | } 60 | } 61 | 62 | func Start() { 63 | router := mux.NewRouter() 64 | router.HandleFunc("/send-notification", sendNotificationHandler).Methods("POST") 65 | 66 | log.Printf("Listening on localhost:%v\n", config.Config["APP_PORT"]) 67 | err := http.ListenAndServe(fmt.Sprintf(":%v", config.Config["APP_PORT"]), router) 68 | helper.FailOnError(err) 69 | } 70 | 71 | func ReturnResponse(w http.ResponseWriter, res map[string]interface{}, httpStatus int) error { 72 | w.Header().Set("Content-Type", "application/json") 73 | w.WriteHeader(httpStatus) 74 | 75 | err := json.NewEncoder(w).Encode(res) 76 | 77 | return err 78 | } 79 | --------------------------------------------------------------------------------