// init is called before the application starts. func init() { m := martini.Classic() m.Use(render.Renderer()) m.Use(func(res http.ResponseWriter, req *http.Request) { authorization := &spark.Authorization{AccessToken: os.Getenv("SPARK_TOKEN")} spark.InitClient(authorization) ctx := appengine.NewContext(req) spark.SetHttpClient(urlfetch.Client(ctx), ctx) }) m.Post("/spark", binding.Json(SparkEvent{}), func(sparkEvent SparkEvent, res http.ResponseWriter, req *http.Request, r render.Render) { ctx := appengine.NewContext(req) client := urlfetch.Client(ctx) message := spark.Message{ID: sparkEvent.Id} message.Get() log.Infof(ctx, message.Text) if strings.HasPrefix(message.Text, "/") { s := strings.Split(sparkEvent.Text, " ") command := s[0] log.Infof(ctx, "command = %s", command) if command == "/routes" { resp, _ := client.Get("http://galwaybus.herokuapp.com/routes.json") defer resp.Body.Close() contents, _ := ioutil.ReadAll(resp.Body) log.Infof(ctx, "body = %s\n", contents) var routeMap map[string]BusRoute json.Unmarshal([]byte(contents), &routeMap) text := "Routes:\n\n" for _, route := range routeMap { text = text + strconv.Itoa(route.Id) + " " + route.LongName + "\n" } message := spark.Message{ RoomID: sparkEvent.RoomId, Text: text, } message.Post() } } }) http.Handle("/", m) }
func init() { renderer := render.New(render.Options{}) token := os.Getenv("SLACK_TOKEN") http.HandleFunc("/v1/cmd", func(w http.ResponseWriter, r *http.Request) { ctx := appengine.NewContext(r) req, err := goslash.ParseFormSlashCommandRequest(r) if err != nil { renderer.JSON(w, http.StatusInternalServerError, err.Error()) return } if req.Token != token { log.Errorf(ctx, "received invalid token:%v from %v", req.Token, r.RemoteAddr) renderer.JSON(w, http.StatusForbidden, "invalid token") return } slashPlugins := map[string]plugins.Plugin{ "echo": echo.New(), "time": time.New(), "突然": suddendeath.New(), "LGTM": lgtm.New(urlfetch.Client(ctx)), "akari": akari.New(), } slashCmd := plugins.New(urlfetch.Client(ctx), slashPlugins) if appengine.IsDevAppServer() { // development cmd, _ := req.CmdArgs() p, ok := slashPlugins[cmd] if !ok { renderer.JSON(w, http.StatusNotFound, "cmd not found") return } msg := p.Do(req) var jsonData bytes.Buffer if err := json.NewEncoder(&jsonData).Encode(&msg); err != nil { renderer.JSON(w, http.StatusInternalServerError, err.Error()) return } renderer.JSON(w, http.StatusOK, jsonData.String()) } else { // production renderer.Text(w, http.StatusOK, slashCmd.Execute(req)) } }) }
func textMessageHandler(w http.ResponseWriter, r *http.Request) { ctx := appengine.NewContext(r) to := r.FormValue("to") text := r.FormValue("text") log.Debugf(ctx, "to: %s, text: %s.", to, text) chi, _ := strconv.ParseInt(os.Getenv("CHANNEL_ID"), 10, 64) chs := os.Getenv("CHANNEL_SECRET") mid := os.Getenv("MID") client := urlfetch.Client(ctx) bot, err := linebot.NewClient(chi, chs, mid, linebot.WithHTTPClient(client)) if err != nil { log.Errorf(ctx, "Client initialization failure. to: %s, text: %s, context: %s", to, text, err.Error()) w.WriteHeader(http.StatusInternalServerError) return } res, err := bot.SendText([]string{to}, text) if err != nil { log.Errorf(ctx, "Message Send Failed. to: %s, text: %s, context: %s", to, text, err.Error()) w.WriteHeader(http.StatusInternalServerError) return } log.Infof(ctx, "Message send succeed. MessageID: %s, to: %s, text: %s", res.MessageID, to, text) w.WriteHeader(http.StatusOK) }
func jobV2adsbHandler(r *http.Request, f *oldfdb.Flight) (string, error) { ctx := req2ctx(r) str := "" // Allow overwrite, for the (36,0) disastery // if f.HasTrack("ADSB") { return "", nil } // Already has one err, deb := f.GetV2ADSBTrack(urlfetch.Client(ctx)) str += fmt.Sprintf("*getv2ADSB [%v]:-\n", err, deb) if err != nil { return str, err } if !f.HasTrack("ADSB") { return "", nil } // Didn't find one f.Analyse() // Retrigger Class-B stuff db := oldfgae.NewDB(r) if err := db.UpdateFlight(*f); err != nil { log.Errorf(ctx, "Persist Flight %s: %v", f, err) return str, err } log.Infof(ctx, "Updated flight %s", f) str += fmt.Sprintf("--\nFlight was updated\n") return str, nil }
func registerFeed(w http.ResponseWriter, r *http.Request) *appError { s := strings.TrimSpace(r.FormValue("url")) if s == "" { return &appError{ Error: errInvalidRequest, Message: "url is required", Code: http.StatusBadRequest, } } u, err := url.Parse(s) if err != nil { return &appError{ Error: err, Message: "can't parse url", Code: http.StatusBadRequest, } } if !u.IsAbs() { return &appError{ Error: errInvalidRequest, Message: "require an absolute url", Code: http.StatusBadRequest, } } c := appengine.NewContext(r) client := urlfetch.Client(c) f, err := fetchFeed(client, s) if err != nil { return &appError{ Error: err, Message: "failed to get", Code: http.StatusInternalServerError, } } m := Magazine{ Title: f.Title, URL: s, Creation: time.Now(), LastMod: time.Now(), } m.Init(c) usr := user.Current(c) if usr == nil { return &appError{ Error: errUserRejected, Message: "failed to initialize user environment", Code: http.StatusUnauthorized, } } err = RegisterMagazine(c, usr, &m, f) if err != nil { return &appError{ Error: err, Message: "failed to register", Code: http.StatusInternalServerError, } } http.Redirect(w, r, "/", http.StatusFound) return nil }
// count active users in channel with channels.info then users.getPresence // very slow due to network func activeUsersInChannel(c context.Context, channelId string) (users []string, err error) { bot := bot.WithClient(urlfetch.Client(c)) members, err := bot.ChannelsInfo(channelId) l.Infof(c, "check %v", members) active := make(chan string, len(members)) var wg sync.WaitGroup for i := range members { wg.Add(1) go func(user string, active chan string, wg *sync.WaitGroup) { defer wg.Done() l.Infof(c, "begin "+user) if p, err := bot.UsersGetPresence(user); err != nil { l.Errorf(c, "%s", err) return } else if p == "active" { active <- user } l.Infof(c, "done "+user) }(members[i], active, &wg) } wg.Wait() l.Infof(c, "done wait") close(active) users = make([]string, len(members)) for user := range active { users = append(users, user) } return }
func SendSimpleMessageHandler(w http.ResponseWriter, r *http.Request) { ctx := appengine.NewContext(r) httpc := urlfetch.Client(ctx) mg := mailgun.NewMailgun( "YOUR_DOMAIN_NAME", // Domain name "YOUR_API_KEY", // API Key "YOUR_PUBLIC_KEY", // Public Key ) mg.SetClient(httpc) msg, id, err := mg.Send(mg.NewMessage( /* From */ "Excited User <mailgun@YOUR_DOMAIN_NAME>", /* Subject */ "Hello", /* Body */ "Testing some Mailgun awesomness!", /* To */ "*****@*****.**", "YOU@YOUR_DOMAIN_NAME", )) if err != nil { msg := fmt.Sprintf("Could not send message: %v, ID %d, %+v", err, id, msg) http.Error(w, msg, http.StatusInternalServerError) return } w.Write([]byte("Message sent!")) }
func getAccessToken(ctx context.Context, state, code string) (string, error) { values := make(url.Values) values.Add("client_id", "vmqwbq2tj8l57k9") values.Add("client_secret", "rpcztciueyunhba") values.Add("grant_type", "authorization_code") values.Add("code", code) values.Add("redirect_uri", redirectURI) client := urlfetch.Client(ctx) response, err := client.PostForm("https://api.dropbox.com/1/oauth2/token", values) if err != nil { return "", err } defer response.Body.Close() bs, _ := ioutil.ReadAll(response.Body) var data struct { AccessToken string `json:"access_token"` TokenType string `json:"token_type"` UID string `json:"uid"` } err = json.Unmarshal(bs, &data) if err != nil { return "", err } if data.AccessToken == "" { return "", fmt.Errorf("Invalid Access Token:%s", string(bs)) } return data.AccessToken, nil }
func authCallbackHandler(w http.ResponseWriter, r *http.Request) { ctx := appengine.NewContext(r) c := NewTwitterClient(ctx) token := r.FormValue("oauth_token") verificationCode := r.FormValue("oauth_verifier") log.Debugf(ctx, "oauth_token:%v oauth_verifier:%v", token, verificationCode) requestToken := FindRequest(ctx, token) if requestToken == nil { fmt.Fprint(w, "token not found") w.WriteHeader(500) return } accessToken, err := c.AuthorizeToken(requestToken, verificationCode) if err != nil { fmt.Fprint(w, err) w.WriteHeader(500) return } fmt.Fprintln(w, accessToken.AdditionalData) api := anaconda.NewTwitterApi(accessToken.Token, accessToken.Secret) api.HttpClient = urlfetch.Client(ctx) ok, err := api.VerifyCredentials() if err != nil { fmt.Fprint(w, err) w.WriteHeader(500) return } fmt.Fprintln(w, ok) }
func updateFromSource2ForAppEngine(r *http.Request) (int64, bool, error) { var result int64 ctx := appengine.NewContext(r) client := urlfetch.Client(ctx) resp, err := client.Get(source2Url) if err != nil { return 0, false, err } defer resp.Body.Close() dec := json.NewDecoder(resp.Body) if resp.StatusCode == 200 { var rate entities.Rate2Response dec.Decode(&rate) result = rate.TimestampUnix repo := repository.New(repoSize, true, r) if err := repo.Push(entities.Rate{ Base: rate.Base, ID: rate.TimestampUnix, RUB: rate.Quotes["USDRUB"], JPY: rate.Quotes["USDJPY"], GBP: rate.Quotes["USDGBP"], USD: rate.Quotes["USDUSD"], EUR: rate.Quotes["USDEUR"], CNY: rate.Quotes["USDCNY"], CHF: rate.Quotes["USDCHF"]}); err != nil { return 0, false, fmt.Errorf("Push rate to repo error: %v", err) } } else { var err2Resp entities.Error2Response dec.Decode(&err2Resp) return 0, false, fmt.Errorf(err2Resp.ToString()) } return result, true, nil }
func notify(ctx context.Context, title, body string, to []string) error { b, err := json.Marshal(PostData{ Notification: Notification{ Title: title, Body: body, Icon: "ic_battery_alert_black", Tag: "battery_low", }, RegistrationIds: to, CollapseKey: "battery_low", }) if err != nil { return err } req, err := http.NewRequest("POST", "https://gcm-http.googleapis.com/gcm/send", bytes.NewReader(b)) if err != nil { return err } req.Header.Set("Content-Type", "application/json") req.Header.Set("Authorization", "key="+keys.GcmApplicationKey) c := urlfetch.Client(ctx) resp, err := c.Do(req) if err != nil { return err } log.Print(resp) return nil }
// serveTwitterCallback handles callbacks from the Twitter OAuth server. func serveTwitterCallback(c *context) error { token := c.r.FormValue("oauth_token") var ci connectInfo _, err := memcache.Gob.Get(c.c, token, &ci) if err != nil { return err } memcache.Delete(c.c, token) tempCred := &oauth.Credentials{ Token: token, Secret: ci.Secret, } httpClient := urlfetch.Client(c.c) tokenCred, _, err := oauthClient.RequestToken(httpClient, tempCred, c.r.FormValue("oauth_verifier")) if err != nil { return err } if err := c.updateUserInfo(func(u *userInfo) { u.TwitterCred = *tokenCred }); err != nil { return err } http.Redirect(c.w, c.r, ci.Redirect, 302) return nil }
//createAppendingeStripeClient creates an httpclient on a per-request basis for use in making api calls to Stripe //stripe's api is accessed via http requests, need a way to make these requests //urlfetch is the appengine way of making http requests //this func returns an httpclient *per request* aka per request to this app //otherwise one request could use another requests httpclient //this is for app engine only since the golang http.DefaultClient is unavailable func createAppengineStripeClient(c context.Context) *client.API { //create http client httpClient := urlfetch.Client(c) //returns "sc" stripe client return client.New(stripePrivateKey, stripe.NewBackends(httpClient)) }
func downloadAccessToken(c context.Context, url string, auth *osin.BasicAuth, output map[string]interface{}) error { // download access token log.Infof(c, "Downloading token from %v", url) preq, err := http.NewRequest("GET", url, nil) if err != nil { return err } if auth != nil { preq.SetBasicAuth(auth.Username, auth.Password) } pclient := urlfetch.Client(c) presp, err := pclient.Do(preq) if err != nil { return err } if presp.StatusCode != 200 { return errors.New("Invalid status code") } jdec := json.NewDecoder(presp.Body) err = jdec.Decode(&output) return err }
func giffy(res http.ResponseWriter, req *http.Request) { ctx := appengine.NewContext(req) t := req.FormValue("term") + "gaming" client := urlfetch.Client(ctx) result, err := client.Get("http://api.giphy.com/v1/gifs/search?q=" + t + "&api_key=dc6zaTOxFJmzC") if err != nil { http.Error(res, err.Error(), 500) return } defer result.Body.Close() var obj struct { Data []struct { URL string `json:"url"` Images struct { Original struct { URL string } } } } err = json.NewDecoder(result.Body).Decode(&obj) if err != nil { http.Error(res, err.Error(), 500) return } for _, img := range obj.Data { fmt.Fprintf(res, `<a href="%v">%v</a><img src="%v"><br>`, img.URL, img.URL, img.Images.Original.URL) } cookie := genCookie(res, req) m := Model(cookie) tpl.ExecuteTemplate(res, "gifs.html", m) }
func SendComplexMessageHandler(w http.ResponseWriter, r *http.Request) { ctx := appengine.NewContext(r) httpc := urlfetch.Client(ctx) mg := mailgun.NewMailgun( "YOUR_DOMAIN_NAME", // Domain name "YOUR_API_KEY", // API Key "YOUR_PUBLIC_KEY", // Public Key ) mg.SetClient(httpc) message := mg.NewMessage( /* From */ "Excited User <mailgun@YOUR_DOMAIN_NAME>", /* Subject */ "Hello", /* Body */ "Testing some Mailgun awesomness!", /* To */ "*****@*****.**", ) message.AddCC("*****@*****.**") message.AddBCC("*****@*****.**") message.SetHtml("<html>HTML version of the body</html>") message.AddAttachment("files/test.jpg") message.AddAttachment("files/test.txt") msg, id, err := mg.Send(message) if err != nil { msg := fmt.Sprintf("Could not send message: %v, ID %d, %+v", err, id, msg) http.Error(w, msg, http.StatusInternalServerError) return } w.Write([]byte("Message sent!")) }
func (session *Session) makeRequest(url string, params Params) ([]byte, error) { buf := &bytes.Buffer{} mime, err := params.Encode(buf) if err != nil { return nil, fmt.Errorf("cannot encode params. %v", err) } client := urlfetch.Client(session.context) //HACK: http://stackoverflow.com/questions/10523906/sslcertificateerror-the-handshake-operation-timed-out-when-trying-to-get-an transport := client.Transport.(*urlfetch.Transport) transport.AllowInvalidServerCertificate = true response, err := client.Post(url, mime, buf) if err != nil { return nil, fmt.Errorf("cannot reach facebook server. %v", err) } defer response.Body.Close() buf = &bytes.Buffer{} _, err = io.Copy(buf, response.Body) if err != nil { return nil, fmt.Errorf("cannot read facebook response. %v", err) } return buf.Bytes(), nil }
func (calculations *Calculations) GetMap(r *http.Request) (string, error) { var mapCountries = []string{} var mapColors = []string{"DBDCDD"} for _, country := range calculations.CountryShare.Countries { mapCountries = append(mapCountries, country.Code) mapColors = append(mapColors, MAP_HIGHLIGHTED_COLOR) } urlParams := []string{MAP_URL, "chld=" + strings.Join(mapCountries, "|"), "chco=" + strings.Join(mapColors, "|"), } ctx := newappengine.NewContext(r) client := urlfetch.Client(ctx) resp, err := client.Get(strings.Join(urlParams, "&")) if err != nil { return "", err } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { return "", err } result := base64.StdEncoding.EncodeToString(body) result = "data:image/png;base64," + result return result, nil }
func handleGetGif(res http.ResponseWriter, req *http.Request) { ctx := appengine.NewContext(req) t := req.FormValue("term") if t == "" { t = "funny+cat" } client := urlfetch.Client(ctx) result, err := client.Get("http://api.giphy.com/v1/gifs/search?q=" + t + "&api_key=dc6zaTOxFJmzC") if err != nil { http.Error(res, err.Error(), 500) return } defer result.Body.Close() var obj struct { Data []struct { URL string `json:"url"` Images struct { Original struct { URL string } } } } err = json.NewDecoder(result.Body).Decode(&obj) if err != nil { http.Error(res, err.Error(), 500) return } for _, img := range obj.Data { fmt.Fprintf(res, `<a href="%v">%v</a><img src="%v"><br>`, img.URL, img.URL, img.Images.Original.URL) } }
func chargeAccount(ctx context.Context, stripeToken string) error { // because we're on app engine, use a custom http client b := stripe.BackendConfiguration{ stripe.APIBackend, "https://api.stripe.com/v1", urlfetch.Client(ctx), } id, _ := uuid.NewV4() for { chargeParams := &stripe.ChargeParams{ Amount: 100 * 200000, Currency: "usd", Desc: "Charge for [email protected]", } chargeParams.IdempotencyKey = id.String() chargeParams.SetSource(stripeToken) chargeClient := &charge.Client{ Key: stripe.Key, B: b, } ch, err := chargeClient.New(chargeParams) if err != nil { if nerr, ok := err.(net.Error); ok && nerr.Temporary() { time.Sleep(time.Second) continue } return err } log.Infof(ctx, "CHARGE: %v", ch) return nil } }
// PrimaryPublicCertificates returns primary's PublicCertificates. func PrimaryPublicCertificates(c context.Context, primaryURL string) (*PublicCertificates, error) { cacheKey := fmt.Sprintf("pub_certs:%s", primaryURL) var pubCerts []byte setCache := false item, err := memcache.Get(c, cacheKey) if err != nil { setCache = true if err != memcache.ErrCacheMiss { log.Warningf(c, "failed to get cert from cache: %v", err) } pubCerts, err = downloadCert(urlfetch.Client(c), primaryURL) if err != nil { log.Errorf(c, "failed to download cert: %v", err) return nil, err } } else { pubCerts = item.Value } pc := &PublicCertificates{} if err = json.Unmarshal(pubCerts, pc); err != nil { log.Errorf(c, "failed to unmarshal cert: %v %v", string(pubCerts), err) return nil, err } if setCache { err = memcache.Set(c, &memcache.Item{ Key: cacheKey, Value: pubCerts, Expiration: time.Hour, }) if err != nil { log.Warningf(c, "failed to set cert to cache: %v", err) } } return pc, nil }
func (api *GithubAPI) getAccessToken(state, code string) (string, error) { values := make(url.Values) values.Add("client_id", "767154e6915134caade5") values.Add("client_secret", "50648a71510c21bb77e229692fc882dfbe8ea35d") values.Add("code", code) values.Add("state", state) client := urlfetch.Client(api.ctx) response, err := client.PostForm("https://github.com/login/oauth/access_token", values) if err != nil { return "", err } defer response.Body.Close() bs, err := ioutil.ReadAll(response.Body) if err != nil { return "", err } values, err = url.ParseQuery(string(bs)) if err != nil { return "", err } return values.Get("access_token"), nil }
func jobV2adsbHandler(r *http.Request, f *oldfdb.Flight) (string, error) { c := appengine.NewContext(r) str := "" if f.HasTrack("ADSB") { return "", nil } // Already has one err, deb := f.GetV2ADSBTrack(urlfetch.Client(c)) str += fmt.Sprintf("*getv2ADSB [%v]:-\n", err, deb) if err != nil { return str, err } if !f.HasTrack("ADSB") { return "", nil } // Didn't find one f.Analyse() // Retrigger Class-B stuff db := oldfgae.FlightDB{C: oldappengine.NewContext(r)} if err := db.UpdateFlight(*f); err != nil { log.Errorf(c, "Persist Flight %s: %v", f, err) return str, err } log.Infof(c, "Updated flight %s", f) str += fmt.Sprintf("--\nFlight was updated\n") return str, nil }
func recaptchaCheck(ctx context.Context, response, ip string) (bool, error) { if appengine.IsDevAppServer() { return true, nil } form := url.Values{} form.Add("secret", os.Getenv("SECRET")) form.Add("response", response) form.Add("remoteip", ip) req, err := http.NewRequest("POST", recaptchaURL, strings.NewReader(form.Encode())) if err != nil { return false, err } cli := urlfetch.Client(ctx) req.Header.Add("Content-Type", "application/x-www-form-urlencoded") resp, err := cli.Do(req) if err != nil { return false, err } var recaptcha recaptchaResponse if err := json.NewDecoder(resp.Body).Decode(&recaptcha); err != nil { return false, err } if !recaptcha.Success { log.Warningf(ctx, "%+v", recaptcha) return false, nil } return true, nil }
func (api *GithubAPI) getAccessToken(state, code string) (string, error) { values := make(url.Values) values.Add("client_id", "0ccd33716940f347065e") values.Add("client_secret", "4c21ab338de0449ae13019de25629a7b85e08641") values.Add("code", code) values.Add("state", state) client := urlfetch.Client(api.ctx) response, err := client.PostForm("https://github.com/login/oauth/access_token", values) if err != nil { return "", err } defer response.Body.Close() bs, err := ioutil.ReadAll(response.Body) if err != nil { return "", err } values, err = url.ParseQuery(string(bs)) if err != nil { return "", err } return values.Get("access_token"), nil }
func Client(c context.Context) *xmlsoccer.Client { return &xmlsoccer.Client{ BaseURL: xmlsoccer.DemoURL, APIKey: os.Getenv("XMLSOCCER_API_KEY"), Client: urlfetch.Client(c), } }
// Do performs the request, the json received in the response is decoded // and stored in the value pointed by v. // Do can be used to perform the request created with NewRequest, as the latter // it should be used only for API requests not implemented in this library. func (c *Client) Do(req *http.Request, v interface{}) (*http.Response, error) { resp, err := urlfetch.Client(c.ctx).Do(req) if err != nil { return nil, err } defer resp.Body.Close() if AuthTest { // If AuthTest is enabled, the reponse won't be the // one defined in the API endpoint. err = json.NewDecoder(resp.Body).Decode(&AuthTestResponse) } else { if c := resp.StatusCode; c < 200 || c > 299 { return resp, fmt.Errorf("Server returns status %d", c) } if v != nil { if w, ok := v.(io.Writer); ok { io.Copy(w, resp.Body) } else { err = json.NewDecoder(resp.Body).Decode(v) } } } return resp, err }
// Call out to the flight database, and get back a condensed summary of the flights (flightnumber, // times, waypoints) which flew to/from a NORCAL airport (SFO,SJC,OAK) for the time range (a day?) func GetProcedureMap(r *http.Request, s, e time.Time) (map[string]fdb.CondensedFlight, error) { ret := map[string]fdb.CondensedFlight{} // This procedure map stuff is expensive, and brittle; so disable by default. return ret, nil client := urlfetch.Client(req2ctx(r)) encoding := "gob" url := fmt.Sprintf("http://fdb.serfr1.org/api/procedures?encoding=%s&tags=:NORCAL:&s=%d&e=%d", encoding, s.Unix(), e.Unix()) condensedFlights := []fdb.CondensedFlight{} if resp, err := client.Get(url); err != nil { return ret, err } else { defer resp.Body.Close() if resp.StatusCode != http.StatusOK { return ret, fmt.Errorf("Bad status fetching proc map for %s: %v", url, resp.Status) } else if err := ReadEncodedData(resp, encoding, &condensedFlights); err != nil { return ret, err } } for _, cf := range condensedFlights { ret[cf.BestFlightNumber] = cf } return ret, nil }
func chargeAccount(ctx context.Context, stripeToken string) error { // because we're on app engine, use a custom http client // this is being set globally, however // if we wanted to do it this way, we'd have to use a lock // https://youtu.be/KT4ki_ClX2A?t=1018 hc := urlfetch.Client(ctx) stripe.SetHTTPClient(hc) id, _ := uuid.NewV4() for { chargeParams := &stripe.ChargeParams{ Amount: 100 * 200000, Currency: "usd", Desc: "Charge for [email protected]", } chargeParams.IdempotencyKey = id.String() chargeParams.SetSource(stripeToken) ch, err := charge.New(chargeParams) // https://youtu.be/KT4ki_ClX2A?t=1310 if err != nil { if nerr, ok := err.(net.Error); ok && nerr.Temporary() { time.Sleep(time.Second) continue } return err } log.Infof(ctx, "CHARGE: %v", ch) log.Infof(ctx, "IDEMPOTENCY: %v", chargeParams.IdempotencyKey) return nil } }
func handleCron(w http.ResponseWriter, r *http.Request) *appError { // X-Appengine-Cron: true c := appengine.NewContext(r) a, err := LoadMagazines(c) if err != nil { return &appError{ Error: err, Message: "failed to load", Code: http.StatusInternalServerError, } } client := urlfetch.Client(c) for _, m := range a { f, err := fetchFeed(client, m.URL) if err != nil { log.Errorf(c, "fetch url: %v", err) continue } if err = SendArticles(c, m, f); err != nil { log.Errorf(c, "send article: %v", err) continue } } return nil }