Exemplo n.º 1
0
func main() {
	defer mustbe.Catched(func(err error) { log.Fatalln("Fatal error:", err) })

	var (
		botToken   string
		apiHost    string
		dbFileName string
	)

	flag.StringVar(&botToken, "token", "", "telegram bot token")
	flag.StringVar(&apiHost, "apihost", "freefeed.net", "backend API host")
	flag.StringVar(&dbFileName, "dbfile", "", "database file name")
	flag.Parse()

	if botToken == "" || dbFileName == "" {
		flag.Usage()
		return
	}

	db := mustbe.OKVal(bolt.Open(dbFileName, 0600, &bolt.Options{Timeout: 1 * time.Second})).(*bolt.DB)
	defer db.Close()

	mustbe.OK(db.Update(func(tx *bolt.Tx) error {
		mustbe.OKVal(tx.CreateBucketIfNotExists(StatesBucket))
		return nil
	}))

	bot := mustbe.OKVal(tgbotapi.NewBotAPI(botToken)).(*tgbotapi.BotAPI)

	u := tgbotapi.NewUpdate(0)
	u.Timeout = 60

	updates, err := bot.GetUpdatesChan(u)
	if err != nil {
		log.Fatalln("Can not get update chan:", err)
		return
	}

	log.Println("Starting bot", bot.Self.UserName)

	app := &App{
		db:      db,
		apiHost: apiHost,
		outbox:  make(chan tgbotapi.Chattable, 0),
		rts:     make(map[int]*Realtime),
		cache:   gcache.New(1000).ARC().Build(),
	}

	app.LoadRT()

	for {
		select {
		case update := <-updates:
			go app.HandleMessage(&update.Message)
		case msg := <-app.outbox:
			bot.Send(msg)
		}
	}
}
Exemplo n.º 2
0
func ExampleOK() {
	defer mustbe.Catched(func(err error) {
		fmt.Println("Catched", err)
	})

	err := errors.New("sample error")
	mustbe.OK(err)

	fmt.Println("Will not be printed")
	// Output: Catched sample error
}
Exemplo n.º 3
0
func main() {
	defer mustbe.Catched(func(err error) {
		log.Println("Fatal error:", err)
		os.Exit(1)
	})

	mustbeTrue(len(os.Args) >= 2, "Usage: frf-aprox conf.json")

	app := new(App)
	mustbe.OK(app.Load(os.Args[1]))

	s := &http.Server{
		Addr:           app.Listen,
		Handler:        http.HandlerFunc(app.Handler),
		ReadTimeout:    10 * time.Second,
		WriteTimeout:   10 * time.Second,
		MaxHeaderBytes: 1 << 20,
	}
	log.Printf("Starting server at %s\n", app.Listen)
	mustbe.OK(s.ListenAndServe())
}
Exemplo n.º 4
0
func (a *App) Handler(w http.ResponseWriter, r *http.Request) {
	defer mustbe.Catched(func(err error) {
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusBadRequest)
		json.NewEncoder(w).Encode(H{"err": err.Error(), "from": "aprx"})
	})

	// request path: /frf-domain/api-path
	pp := strings.SplitN(r.URL.Path, "/", 3)[1:]
	mustbeTrue(len(pp) == 2, "Invalid request path")
	domain, path := pp[0], "/"+pp[1]

	domainFound := false
	for _, d := range a.FRFDomains {
		if d == domain {
			domainFound = true
			break
		}
	}
	mustbeTrue(domainFound, "Invalid frf domain")

	var (
		accessToken    string
		frfRequestBody []byte
	)

	switch r.Header.Get("Content-Type") {
	case "application/x-www-form-urlencoded":
		r.ParseForm()
		accessToken = r.PostForm.Get("accessToken")
		r.PostForm.Del("accessToken")
		frfRequestBody = []byte(r.PostForm.Encode())

	case "application/json", "application/json; charset=utf-8":
		h := make(H)
		mustbe.OK(json.NewDecoder(r.Body).Decode(h))
		accessToken = h["accessToken"].(string)
		delete(h, "accessToken")
		frfRequestBody = mustbe.OKVal(json.Marshal(h)).([]byte)
	}

	req, err := http.NewRequest(
		r.Method,
		"https://"+domain+path,
		bytes.NewReader(frfRequestBody),
	)
	mustbe.OK(err)

	for _, h := range HeadersFromClient {
		if hh, ok := r.Header[h]; ok {
			req.Header[h] = hh
		}
	}

	if accessToken != "" {
		req.Header.Set("X-Authentication-Token", accessToken)
	}

	resp, err := http.DefaultClient.Do(req)
	mustbe.OK(err)

	defer resp.Body.Close()

	for _, h := range HeadersFromBackend {
		if hh, ok := resp.Header[h]; ok {
			w.Header()[h] = hh
		}
	}

	w.WriteHeader(resp.StatusCode)
	io.Copy(w, resp.Body)
}
Exemplo n.º 5
0
func mustbeTrue(test bool, errMsg string) {
	if !test {
		mustbe.OK(errors.New(errMsg))
	}
}
Exemplo n.º 6
0
func (a *App) PostPublicParam(r *http.Request) (respCode int, respValue interface{}) {
	defer mustbe.Catched(func(err error) {
		a.Log.WithField("error", err).Error(err.Error())
		respCode, respValue = http.StatusInternalServerError, "Internal server error"
	})

	req := &struct {
		AuthToken string          `json:"authToken"`
		Value     json.RawMessage `json:"value"`
	}{}

	pathVars := mux.Vars(r)
	site, username, paramName := pathVars["site"], pathVars["username"], pathVars["paramName"]
	pProps := a.PublicParams[paramName]
	siteInfo := a.Sites[site]

	if err := json.NewDecoder(io.LimitReader(r.Body, int64(pProps.MaxRequestSize))).Decode(req); err != nil {
		return http.StatusBadRequest, err.Error()
	}

	// валидность данных
	val, err := pProps.Schema.Validate(gojsonschema.NewStringLoader(string(req.Value)))
	mustbe.OK(err)

	if !val.Valid() {
		return http.StatusBadRequest, val.Errors()[0].Description()
	}

	api := ffapi.New(siteInfo.APIRoot, req.AuthToken)

	whoami, err := api.WhoAmI()
	mustbe.OK(err)

	if whoami.Users.Username != username {
		// возможно, редактируется группа
		uinfo, err := api.UserInfo(username)
		mustbe.OK(err)
		adminFound := false
		for _, adm := range uinfo.Admins {
			if adm.ID == whoami.Users.ID {
				adminFound = true
				break
			}
		}

		if !adminFound {
			return http.StatusBadRequest, "You can not manage this account"
		}
	}

	// всё в порядке
	mustbe.OK(a.DB.Update(func(tx *bolt.Tx) error {
		b := tx.Bucket([]byte(PublicBucketName))
		return b.Put(
			[]byte(site+"/"+username+"/"+paramName),
			[]byte(req.Value),
		)
	}))

	return http.StatusOK, nil
}