func Main() { // Read in any environment variables we care about readEnv() var err error AWS_AUTH, err = aws.EnvAuth() if err != nil { panic(err.Error()) } // Open database connection db, err := models.OpenDB("postgres", IRLMOJI_DBURI) if err != nil { log.Fatalf("Error opening database connection: %v", err.Error()) return } if err = createAllTables(db); err != nil { log.Fatalf("Error creating database table: %v", err.Error()) } // Start setting up martini m := martini.Classic() // Set up the middleware m.Use(gzip.All()) m.Use(render.Renderer()) m.Use(BackchannelAuth(IRLMOJI_API_BASIC_USER)) // Inject the database m.Map(db) // Map the URL routes m.Get("/", HandleIndex) // User routes (see handlers_user.go) m.Get("/api/v1/users/current.json", HandleGetCurrentUser) m.Post("/api/v1/users/twitter.json", binding.Json(models.UserForm{}), HandleCreateUserByTwitter) // IRLMoji routes (see handlers_irlmoji.go) m.Get("/api/v1/timelines/home.json", binding.Form(Limit{}), HandleGetHomeTimeline) m.Get("/api/v1/timelines/user/username/:username.json", binding.Form(Limit{}), HandleGetUserTimeline) m.Get("/api/v1/timelines/emoji/:emoji.json", binding.Form(Limit{}), HandleGetEmojiTimeline) m.Get("/api/v1/irlmoji/id/:irlmojiId.json", binding.Form(Limit{}), HandleGetIRLMoji) m.Delete("/api/v1/irlmoji/id/:irlmojiId.json", HandleDeleteIRLMoji) m.Post("/api/v1/irlmoji.json", binding.Json(models.IRLMoji{}), HandleCreateIRLMoji) m.Post("/api/v1/irlmoji/id/:irlmojiId/heart.json", binding.Json(models.Heart{}), HandleToggleHeart) m.Post("/upload", HandleUpload) m.NotFound(HandleNotFound) m.Run() }
func main() { m := martini.Classic() // specify the layout to use when rendering HTML m.Use(render.Renderer(render.Options{ Layout: "layout", })) // use the Mongo middleware m.Use(DB()) // list of all cribs m.Get("/", func(r render.Render, db *mgo.Database) { r.HTML(200, "list", All(db)) }) /* create a new crib the form submission. Contains some martini magic. The call to binding.Form(Crib{}) parses out form data when the request comes in. It binds the data to the struct, maps it to the request context and injects into our next handler function to insert into Mongodb. */ m.Post("/", binding.Form(Crib{}), func(crib Crib, r render.Render, db *mgo.Database) { db.C("cribs").Insert(crib) r.HTML(200, "list", All(db)) }) // display the crib for a specific user m.Get("/:handle", func(params martini.Params, r render.Render, db *mgo.Database) { r.HTML(200, "display", Fetch(db, params["handle"])) }) http.ListenAndServe(":8080", m) }
func main() { quotes := make([]Quote, 0, 50) m := martini.Classic() // render html templates from templates directory m.Use(render.Renderer(render.Options{ Layout: "layout", })) m.Use(martini.Static("assets")) m.Get("/", func(r render.Render) { r.Redirect("/list", 302) }) m.Get("/list", func(r render.Render) { r.HTML(200, "list", quotes) }) m.Get("/newitem.html", func(r render.Render) { r.HTML(200, "newitem", nil) }) m.Post("/list", binding.Form(Quote{}), func(q Quote, r render.Render) { quotes = append(quotes, q) r.Redirect("/list", 302) }) m.Run() }
func main() { m := martini.Classic() m.Use(render.Renderer()) m.Get("/post/:id", controllers.GetPost) m.Get("/posts", controllers.ListPosts) m.Post("/post", binding.Form(forms.Post{}), controllers.CreatePost) m.Run() }
func main() { m := martini.Classic() m.Use(render.Renderer()) m.Use(martini.Static("scripts")) collection := monitor.New() collection.AddMonitor(&monitor.Monitor{Name: "Motherbrain", HttpAddress: "10.10.8.81:80", MonitorType: "web"}) collection.AddMonitor(&monitor.Monitor{Name: "AQR Web 1", HttpAddress: "10.10.11.144:80", MonitorType: "web", ActiveRedirect: true}) collection.AddMonitor(&monitor.Monitor{Name: "AQR Web 2", HttpAddress: "10.10.9.8:80", MonitorType: "web"}) collection.AddMonitor(&monitor.Monitor{Name: "AQR Web 3", HttpAddress: "10.10.9.247:80", MonitorType: "web"}) collection.AddMonitor(&monitor.Monitor{Name: "AQR Web 4", HttpAddress: "10.10.8.32:80", MonitorType: "web"}) go collection.Run() m.Get("/", func(w http.ResponseWriter, r *http.Request) { if redirectAddress, err := collection.FetchActiveRedirect(); err == nil { http.Redirect(w, r, "http://"+redirectAddress, http.StatusMovedPermanently) } }) m.Get("/dashboard", func(r render.Render) { r.HTML(200, "master", nil) }) m.Get("/api/getMonitors", func() string { data, _ := json.Marshal(collection) return string(data) }) m.Post("/api/addMonitor", binding.Form(monitor.Monitor{}), func(monitor monitor.Monitor) { collection.AddMonitor(&monitor) }) m.Post("/api/removeMonitor", func(w http.ResponseWriter, r *http.Request) { name := r.FormValue("removeName") collection.Remove(name) http.Redirect(w, r, "/dashboard", http.StatusFound) }) m.Post("/api/activateMonitor", func(w http.ResponseWriter, r *http.Request) { name := r.FormValue("activateName") collection.ActivateMonitor(name) http.Redirect(w, r, "/dashboard", http.StatusFound) }) m.Run() }
func main() { m := martini.Classic() m.Use(render.Renderer()) m.Use(DB()) m.Get("/wishes", func(r render.Render, db *mgo.Database) { r.HTML(200, "list", GetAll(db)) }) m.Post("/wishes", binding.Form(Wish{}), func(wish Wish, r render.Render, db *mgo.Database) { db.C("wishes").Insert(wish) r.HTML(200, "list", GetAll(db)) }) m.Run() }
func main() { m := martini.Classic() db, err := gorm.Open("sqlite3", "./gorm.db") if err != nil { panic("Could not open db") } migrateDb(db) m.Use(render.Renderer()) //HTML & JSON renderer middleware m.Get("/", func() string { return "Hello world!" }) m.Get("/error", func() (int, string) { return 400, "i'm a teapot" // HTTP 418 : "i'm a teapot" }) m.Get("/error500", func() (int, string) { return 500, "i'm a teapot" // HTTP 418 : "i'm a teapot" }) m.Get("/api/user", func(r render.Render) { user := ormTest(db) r.JSON(201, user) }) m.Get("/user", func(r render.Render) { users := ormTest(db) r.HTML(200, "user", users) }) m.Get("/users", func(r render.Render) { users := GetAllUsers(db) r.HTML(200, "createUser", users) }) m.Post("/users", binding.Form(model.User{}), func(user model.User, r render.Render) { db.Create(&user) fmt.Printf("%v\n", user) users := GetAllUsers(db) r.HTML(200, "createUser", users) }) m.Run() }
func main() { m := martini.Classic() postsController := new(controllers.PostsController) m.Use(render.Renderer(render.Options{ Directory: "templates", Layout: "layout", })) m.Use(PopulateAppContext) m.Use(CloseDatabase) m.Use(martini.Static("public")) m.Get("/", postsController.Index) m.Get("/posts/new", postsController.New) m.Post("/posts/new", binding.Form(models.Post{}), postsController.Create) log.Fatal(http.ListenAndServe("192.168.1.60:8080", m)) }
func main() { var err error var latestheight, latestheightcache int var blockscached *[]*btcplex.Block usage := `BTCplex webapp/API server. Usage: btcplex-server [--config=<path>] btcplex-server -h | --help Options: -h --help Show this screen. -c <path>, --config <path> Path to config file [default: config.json]. ` arguments, _ := docopt.Parse(usage, nil, true, "btcplex-server", false) confFile := "config.json" if arguments["--config"] != nil { confFile = arguments["--config"].(string) } log.Println("Starting btcplex-server") conf, err = btcplex.LoadConfig(confFile) if err != nil { log.Fatalf("Can't load config file: %v\n", err) } // Used for pub/sub in the webapp and data like latest processed height pool, err := btcplex.GetRedis(conf) if err != nil { log.Fatalf("Can't connect to Redis: %v\n", err) } // Due to args injection I can't use two *redis.Pool with maritini rediswrapper := new(RedisWrapper) rediswrapper.Pool = pool ssdb, err := btcplex.GetSSDB(conf) if err != nil { log.Fatalf("Can't connect to SSDB: %v\n", err) } // Setup some pubsub: // Compute the unconfirmed transaction count in a ticker utxscnt := 0 utxscntticker := time.NewTicker(1 * time.Second) go func(pool *redis.Pool, utxscnt *int) { c := pool.Get() defer c.Close() for _ = range utxscntticker.C { *utxscnt, _ = redis.Int(c.Do("ZCARD", "btcplex:rawmempool")) } }(pool, &utxscnt) // Pool the latest height from BTCplex db, // also track the status/check if BTCplex goes out of sync latestheightticker := time.NewTicker(1 * time.Second) checkinprogress := false bitcoindheight := btcplex.GetBlockCountRPC(conf) btcplexsynced := true go func(pool *redis.Pool, latestheight *int) { c := pool.Get() defer c.Close() for _ = range latestheightticker.C { *latestheight, _ = redis.Int(c.Do("GET", "height:latest")) if latestheightcache != *latestheight { log.Println("Re-building homepage blocks cache") blocks, _ := btcplex.GetLastXBlocks(ssdb, uint(*latestheight), uint(*latestheight-30)) blockscached = &blocks latestheightcache = *latestheight } bitcoindheight = btcplex.GetBlockCountRPC(conf) if uint(latestheightcache) != bitcoindheight && !checkinprogress && btcplexsynced { checkinprogress = true go func(checkinprogress *bool) { if bitcoindheight-uint(latestheightcache) > 20 { btcplexsynced = false log.Printf("CRITICAL: OUT OF SYNC / btcplex:%v, bitcoind:%v\n", latestheightcache, bitcoindheight) } else { log.Println("WARNING: BTCplex Out of sync, waiting before another check") time.Sleep(synctimeout * time.Second) if btcplexsynced && uint(latestheightcache) != bitcoindheight { btcplexsynced = false log.Printf("CRITICAL: OUT OF SYNC / btcplex:%v, bitcoind:%v\n", latestheightcache, bitcoindheight) } } *checkinprogress = false }(&checkinprogress) } if uint(latestheightcache) == bitcoindheight && !btcplexsynced { log.Println("INFO: Sync with bitcoind done") btcplexsynced = true } } }(ssdb, &latestheight) // PubSub channel for blocknotify bitcoind RPC like blocknotifygroup := bcast.NewGroup() go blocknotifygroup.Broadcasting(0) go bcastToRedisPubSub(pool, blocknotifygroup, "btcplex:blocknotify2") // PubSub channel for unconfirmed txs / rawmemorypool utxgroup := bcast.NewGroup() go utxgroup.Broadcasting(0) go bcastToRedisPubSub(pool, utxgroup, "btcplex:utxs") // TODO Ticker for utxs count => events_unconfirmed newblockgroup := bcast.NewGroup() go newblockgroup.Broadcasting(0) go bcastToRedisPubSub(pool, newblockgroup, "btcplex:newblock") btcplexsyncedgroup := bcast.NewGroup() go btcplexsyncedgroup.Broadcasting(0) // Go template helper appHelpers := template.FuncMap{ "cut": func(addr string, length int) string { return fmt.Sprintf("%v...", addr[:length]) }, "cutmiddle": func(addr string, length int) string { return fmt.Sprintf("%v...%v", addr[:length], addr[len(addr)-length:]) }, "tokb": func(size uint32) string { return fmt.Sprintf("%.3f", float32(size)/1024) }, "computefee": func(tx *btcplex.Tx) string { if tx.TotalIn == 0 { return "0" } return fmt.Sprintf("%v", float32(tx.TotalIn-tx.TotalOut)/1e8) }, "generationmsg": func(tx *btcplex.Tx) string { reward := btcplex.GetBlockReward(tx.BlockHeight) fee := float64(tx.TotalOut-uint64(reward)) / 1e8 return fmt.Sprintf("%v MAZA + %.8f total fees", float64(reward)/1e8, fee) }, "tobtc": func(val uint64) string { return fmt.Sprintf("%.8f", float64(val)/1e8) }, "inttobtc": func(val int64) string { return fmt.Sprintf("%.8f", float64(val)/1e8) }, "formatprevout": func(prevout *btcplex.PrevOut) string { return fmt.Sprintf("%v:%v", prevout.Hash, prevout.Vout) }, "formattime": func(ts uint32) string { return fmt.Sprintf("%v", time.Unix(int64(ts), 0).UTC()) }, "formatiso": func(ts uint32) string { return fmt.Sprintf("%v", time.Unix(int64(ts), 0).Format(time.RFC3339)) }, "sub": func(h, p uint) uint { return h - p }, "add": func(h, p uint) uint { return h + p }, "iadd": func(h, p int) int { return h + p }, "confirmation": func(hash string, height uint) uint { bm, _ := btcplex.NewBlockMeta(ssdb, hash) if bm.Main == false { return 0 } return uint(latestheight) - height + 1 }, "is_orphaned": func(block *btcplex.Block) bool { if block.Height == uint(latestheight) { return false } return !block.Main }, } m := martini.Classic() m.Map(rediswrapper) m.Map(ssdb) tmpldir := "templates" if conf.AppTemplatesPath != "" { tmpldir = conf.AppTemplatesPath } m.Use(render.Renderer(render.Options{ Directory: tmpldir, Layout: "layout", Funcs: []template.FuncMap{appHelpers}, })) // We rate limit the API if enabled in the config if conf.AppApiRateLimited { m.Use(func(res http.ResponseWriter, req *http.Request, rediswrapper *RedisWrapper, log *log.Logger) { remoteIP := strings.Split(req.RemoteAddr, ":")[0] _, xforwardedfor := req.Header["X-Forwarded-For"] if xforwardedfor { remoteIP = req.Header["X-Forwarded-For"][1] } log.Printf("R:%v\nip:%+v\n", time.Now(), remoteIP) if strings.Contains(req.RequestURI, "/api/") { ratelimited, cnt, reset := rateLimited(rediswrapper, remoteIP) // Set X-RateLimit-* Header res.Header().Set("X-RateLimit-Limit", strconv.Itoa(ratelimitcnt)) res.Header().Set("X-RateLimit-Remaining", strconv.Itoa(ratelimitcnt-cnt)) res.Header().Set("X-RateLimit-Reset", strconv.Itoa(reset)) // Set CORS header res.Header().Set("Access-Control-Expose-Headers", " X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset") res.Header().Set("Access-Control-Allow-Origin", "*") if ratelimited { res.WriteHeader(429) } } }) } // Don't want Google to crawl API m.Get("/robots.txt", func() string { return "User-agent: *\nDisallow: /api" }) m.Get("/", func(r render.Render, db *redis.Pool) { pm := new(pageMeta) pm.BtcplexSynced = btcplexsynced pm.Blocks = blockscached pm.Title = "Latest Bitcoin blocks" pm.Description = "Open source Bitcoin block chain explorer with JSON API" pm.Menu = "latest_blocks" pm.LastHeight = uint(latestheight) pm.Analytics = conf.AppGoogleAnalytics r.HTML(200, "index", &pm) }) m.Get("/blocks/:currentheight", func(params martini.Params, r render.Render, db *redis.Pool) { pm := new(pageMeta) pm.BtcplexSynced = btcplexsynced currentheight, _ := strconv.ParseUint(params["currentheight"], 10, 0) blocks, _ := btcplex.GetLastXBlocks(db, uint(currentheight), uint(currentheight-30)) pm.Blocks = &blocks pm.Title = "Bitcoin blocks" pm.Menu = "blocks" pm.LastHeight = uint(latestheight) pm.CurrentHeight = uint(currentheight) pm.Analytics = conf.AppGoogleAnalytics r.HTML(200, "blocks", &pm) }) m.Get("/block/:hash", func(params martini.Params, r render.Render, db *redis.Pool) { pm := new(pageMeta) pm.BtcplexSynced = btcplexsynced pm.LastHeight = uint(latestheight) block, _ := btcplex.GetBlockCachedByHash(db, params["hash"]) block.FetchMeta(db) btcplex.By(btcplex.TxIndex).Sort(block.Txs) pm.Block = block pm.Title = fmt.Sprintf("Bitcoin block #%v", block.Height) pm.Description = fmt.Sprintf("Bitcoin block #%v summary and related transactions", block.Height) pm.Analytics = conf.AppGoogleAnalytics r.HTML(200, "block", &pm) }) m.Get("/api/block/:hash", func(params martini.Params, r render.Render, db *redis.Pool, req *http.Request) { block, _ := btcplex.GetBlockCachedByHash(db, params["hash"]) block.FetchMeta(db) btcplex.By(btcplex.TxIndex).Sort(block.Txs) block.Links = initHATEOAS(block.Links, req) if block.Parent != "" { block.Links = addHATEOAS(block.Links, "previous_block", fmt.Sprintf("%v/api/block/%v", conf.AppUrl, block.Parent)) } if block.Next != "" { block.Links = addHATEOAS(block.Links, "next_block", fmt.Sprintf("%v/api/block/%v", conf.AppUrl, block.Next)) } r.JSON(200, block) }) m.Get("/unconfirmed-transactions", func(params martini.Params, r render.Render, db *redis.Pool, rdb *RedisWrapper) { //rpool := rdb.Pool pm := new(pageMeta) pm.BtcplexSynced = btcplexsynced pm.LastHeight = uint(latestheight) pm.Menu = "utxs" pm.Title = "Unconfirmed transactions" pm.Description = "Transactions waiting to be included in a Bitcoin block, updated in real time." //utxs, _ := btcplex.GetUnconfirmedTxs(rpool) pm.Txs = &[]*btcplex.Tx{} pm.Analytics = conf.AppGoogleAnalytics r.HTML(200, "unconfirmed-transactions", &pm) }) m.Get("/tx/:hash", func(params martini.Params, r render.Render, db *redis.Pool, rdb *RedisWrapper) { var tx *btcplex.Tx rpool := rdb.Pool pm := new(pageMeta) pm.BtcplexSynced = btcplexsynced pm.LastHeight = uint(latestheight) isutx, _ := btcplex.IsUnconfirmedTx(rpool, params["hash"]) if isutx { pm.TxUnconfirmed = true tx, _ = btcplex.GetUnconfirmedTx(rpool, params["hash"]) } else { tx, _ = btcplex.GetTx(db, params["hash"]) tx.Build(db) } pm.Tx = tx pm.Title = fmt.Sprintf("Bitcoin transaction %v", tx.Hash) pm.Description = fmt.Sprintf("Bitcoin transaction %v summary.", tx.Hash) pm.Analytics = conf.AppGoogleAnalytics r.HTML(200, "tx", pm) }) m.Get("/api/tx/:hash", func(params martini.Params, r render.Render, db *redis.Pool, rdb *RedisWrapper, req *http.Request) { var tx *btcplex.Tx rpool := rdb.Pool isutx, _ := btcplex.IsUnconfirmedTx(rpool, params["hash"]) if isutx { tx, _ = btcplex.GetUnconfirmedTx(rpool, params["hash"]) } else { tx, _ = btcplex.GetTx(db, params["hash"]) tx.Build(db) } tx.Links = initHATEOAS(tx.Links, req) if tx.BlockHash != "" { tx.Links = addHATEOAS(tx.Links, "block", fmt.Sprintf("%v/api/block/%v", conf.AppUrl, tx.BlockHash)) } r.JSON(200, tx) }) m.Get("/address/:address", func(params martini.Params, r render.Render, db *redis.Pool, req *http.Request) { pm := new(pageMeta) pm.BtcplexSynced = btcplexsynced pm.LastHeight = uint(latestheight) pm.PaginationData = new(PaginationData) pm.Title = fmt.Sprintf("Bitcoin address %v", params["address"]) pm.Description = fmt.Sprintf("Transactions and summary for the Bitcoin address %v.", params["address"]) // AddressData addressdata, _ := btcplex.GetAddress(db, params["address"]) pm.AddressData = addressdata // Pagination d := float64(addressdata.TxCnt) / float64(txperpage) pm.PaginationData.MaxPage = int(math.Ceil(d)) currentPage := req.URL.Query().Get("page") if currentPage == "" { currentPage = "1" } pm.PaginationData.CurrentPage, _ = strconv.Atoi(currentPage) pm.PaginationData.Pages = N(pm.PaginationData.MaxPage) pm.PaginationData.Next = 0 pm.PaginationData.Prev = 0 if pm.PaginationData.CurrentPage > 1 { pm.PaginationData.Prev = pm.PaginationData.CurrentPage - 1 } if pm.PaginationData.CurrentPage < pm.PaginationData.MaxPage { pm.PaginationData.Next = pm.PaginationData.CurrentPage + 1 } fmt.Printf("%+v\n", pm.PaginationData) // Fetch txs given the pagination addressdata.FetchTxs(db, txperpage*(pm.PaginationData.CurrentPage-1), txperpage*pm.PaginationData.CurrentPage) r.HTML(200, "address", pm) }) m.Get("/api/address/:address", func(params martini.Params, r render.Render, db *redis.Pool, req *http.Request) { addressdata, _ := btcplex.GetAddress(db, params["address"]) lastPage := int(math.Ceil(float64(addressdata.TxCnt) / float64(txperpage))) currentPageStr := req.URL.Query().Get("page") if currentPageStr == "" { currentPageStr = "1" } currentPage, _ := strconv.Atoi(currentPageStr) // HATEOS section addressdata.Links = initHATEOAS(addressdata.Links, req) pageurl := "%v/api/address/%v?page=%v" if currentPage < lastPage { addressdata.Links = addHATEOAS(addressdata.Links, "last", fmt.Sprintf(pageurl, conf.AppUrl, params["address"], lastPage)) addressdata.Links = addHATEOAS(addressdata.Links, "next", fmt.Sprintf(pageurl, conf.AppUrl, params["address"], currentPage+1)) } if currentPage > 1 { addressdata.Links = addHATEOAS(addressdata.Links, "previous", fmt.Sprintf(pageurl, conf.AppUrl, params["address"], currentPage-1)) } addressdata.FetchTxs(db, txperpage*(currentPage-1), txperpage*currentPage) r.JSON(200, addressdata) }) m.Get("/about", func(r render.Render) { pm := new(pageMeta) pm.BtcplexSynced = btcplexsynced pm.LastHeight = uint(latestheight) pm.Title = "About" pm.Description = "Learn more about BTCPlex, an open source Bitcoin blockchain browser written in Go." pm.Menu = "about" pm.Analytics = conf.AppGoogleAnalytics r.HTML(200, "about", pm) }) m.Get("/status", func(r render.Render) { pm := new(pageMeta) pm.BtcplexSynced = btcplexsynced pm.LastHeight = uint(latestheight) pm.Title = "Status" pm.Description = "BTCplex status page." pm.Menu = "status" pm.Analytics = conf.AppGoogleAnalytics btcplexinfo, _ := btcplex.GetInfoRPC(conf) pm.BitcoindInfo = btcplexinfo r.HTML(200, "status", pm) }) m.Post("/search", binding.Form(searchForm{}), binding.ErrorHandler, func(search searchForm, r render.Render, db *redis.Pool, rdb *RedisWrapper) { rpool := rdb.Pool pm := new(pageMeta) pm.BtcplexSynced = btcplexsynced // Check if the query isa block height isblockheight, hash := btcplex.IsBlockHeight(db, search.Query) if isblockheight && hash != "" { r.Redirect(fmt.Sprintf("/block/%v", hash)) } // Check if the query is block hash isblockhash, hash := btcplex.IsBlockHash(db, search.Query) if isblockhash { r.Redirect(fmt.Sprintf("/block/%v", hash)) } // Check for TX istxhash, txhash := btcplex.IsTxHash(db, search.Query) if istxhash { r.Redirect(fmt.Sprintf("/tx/%v", txhash)) } isutx, txhash := btcplex.IsUnconfirmedTx(rpool, search.Query) if isutx { r.Redirect(fmt.Sprintf("/tx/%v", txhash)) } // Check for Bitcoin address isaddress, address := btcplex.IsAddress(search.Query) if isaddress { r.Redirect(fmt.Sprintf("/address/%v", address)) } pm.Title = "Search" pm.Error = "Nothing found" pm.Analytics = conf.AppGoogleAnalytics r.HTML(200, "search", pm) }) m.Get("/api/getblockcount", func(r render.Render) { r.JSON(200, latestheight) }) // m.Get("/api/latesthash", func(r render.Render) { // r.JSON(200, latesthash) // }) m.Get("/api/getblockhash/:height", func(r render.Render, params martini.Params, db *redis.Pool) { height, _ := strconv.ParseUint(params["height"], 10, 0) blockhash, _ := btcplex.GetBlockHash(db, uint(height)) r.JSON(200, blockhash) }) m.Get("/api/getreceivedbyaddress/:address", func(r render.Render, params martini.Params, db *redis.Pool) { res, _ := btcplex.GetReceivedByAddress(db, params["address"]) r.JSON(200, res) }) m.Get("/api/getsentbyaddress/:address", func(r render.Render, params martini.Params, db *redis.Pool) { res, _ := btcplex.GetSentByAddress(db, params["address"]) r.JSON(200, res) }) m.Get("/api/addressbalance/:address", func(r render.Render, params martini.Params, db *redis.Pool) { res, _ := btcplex.AddressBalance(db, params["address"]) r.JSON(200, res) }) m.Get("/api/checkaddress/:address", func(params martini.Params, r render.Render) { valid, _ := btcplex.ValidA58([]byte(params["address"])) r.JSON(200, valid) }) m.Get("/api/blocknotify", func(w http.ResponseWriter, r *http.Request) { incrementClient() defer decrementClient() running := true notifier := w.(http.CloseNotifier).CloseNotify() timer := time.NewTimer(time.Second * 1800) f, _ := w.(http.Flusher) w.Header().Set("Content-Type", "text/event-stream") w.Header().Set("Cache-Control", "no-cache") w.Header().Set("Connection", "keep-alive") bnotifier := blocknotifygroup.Join() defer bnotifier.Close() var ls interface{} for { if running { select { case ls = <-bnotifier.In: io.WriteString(w, fmt.Sprintf("data: %v\n\n", ls.(string))) f.Flush() case <-notifier: running = false log.Println("CLOSED") break case <-timer.C: running = false log.Println("TimeOUT") } } else { log.Println("DONE") break } } }) m.Get("/api/utxs/:address", func(w http.ResponseWriter, params martini.Params, r *http.Request, rdb *RedisWrapper) { incrementClient() defer decrementClient() rpool := rdb.Pool running := true notifier := w.(http.CloseNotifier).CloseNotify() timer := time.NewTimer(time.Second * 3600) f, _ := w.(http.Flusher) w.Header().Set("Content-Type", "text/event-stream") w.Header().Set("Cache-Control", "no-cache") w.Header().Set("Connection", "keep-alive") utxs := make(chan string) go func(rpool *redis.Pool, utxs chan<- string) { conn := rpool.Get() defer conn.Close() psc := redis.PubSubConn{Conn: conn} psc.Subscribe(fmt.Sprintf("addr:%v:txs", params["address"])) for { switch v := psc.Receive().(type) { case redis.Message: utxs <- string(v.Data) } } }(rpool, utxs) var ls string for { if running { select { case ls = <-utxs: io.WriteString(w, fmt.Sprintf("data: %v\n\n", ls)) f.Flush() case <-notifier: running = false log.Println("CLOSED") break case <-timer.C: running = false log.Println("TimeOUT") } } else { log.Println("DONE") break } } }) m.Get("/api/utxs", func(w http.ResponseWriter, r *http.Request) { incrementClient() defer decrementClient() running := true notifier := w.(http.CloseNotifier).CloseNotify() timer := time.NewTimer(time.Second * 3600) f, _ := w.(http.Flusher) w.Header().Set("Content-Type", "text/event-stream") w.Header().Set("Cache-Control", "no-cache") w.Header().Set("Connection", "keep-alive") utx := utxgroup.Join() defer utx.Close() var ls interface{} for { if running { select { case ls = <-utx.In: io.WriteString(w, fmt.Sprintf("data: %v\n\n", ls.(string))) f.Flush() case <-notifier: running = false log.Println("CLOSED") break case <-timer.C: running = false log.Println("TimeOUT") } } else { log.Println("DONE") break } } }) m.Get("/events", func(w http.ResponseWriter, r *http.Request) { running := true notifier := w.(http.CloseNotifier).CloseNotify() timer := time.NewTimer(time.Second * 8400) f, _ := w.(http.Flusher) w.Header().Set("Content-Type", "text/event-stream") w.Header().Set("Cache-Control", "no-cache") w.Header().Set("Connection", "keep-alive") newblockg := newblockgroup.Join() defer newblockg.Close() var ls interface{} for { if running { select { case ls = <-newblockg.In: io.WriteString(w, fmt.Sprintf("data: %v\n\n", ls.(string))) f.Flush() case <-notifier: running = false log.Println("CLOSED") break case <-timer.C: running = false log.Println("TimeOUT") } } else { log.Println("DONE") break } } }) m.Get("/events_unconfirmed", func(w http.ResponseWriter, r *http.Request) { running := true notifier := w.(http.CloseNotifier).CloseNotify() timer := time.NewTimer(time.Second * 3600) f, _ := w.(http.Flusher) w.Header().Set("Content-Type", "text/event-stream") w.Header().Set("Cache-Control", "no-cache") w.Header().Set("Connection", "keep-alive") utx := utxgroup.Join() defer utx.Close() var ls interface{} for { if running { select { case ls = <-utx.In: buf := bytes.NewBufferString("") utx := new(btcplex.Tx) json.Unmarshal([]byte(ls.(string)), utx) t := template.New("").Funcs(appHelpers) utxtmpl, _ := ioutil.ReadFile(fmt.Sprintf("%v/utx.tmpl", tmpldir)) t, err := t.Parse(string(utxtmpl)) if err != nil { log.Printf("ERR:%v", err) } err = t.Execute(buf, utx) if err != nil { log.Printf("ERR EXEC:%v", err) } res := map[string]interface{}{} // Full unconfirmed cnt from global variables res["cnt"] = utxscnt // HTML template of the transaction res["tmpl"] = buf.String() // Last updated time res["time"] = time.Now().UTC().Format(time.RFC3339) resjson, _ := json.Marshal(res) io.WriteString(w, fmt.Sprintf("data: %v\n\n", string(resjson))) f.Flush() case <-notifier: running = false log.Println("CLOSED") break case <-timer.C: running = false log.Println("TimeOUT") } } else { log.Println("DONE") break } } }) m.Get("/api/info", func(r render.Render) { activeclientsmutex.Lock() defer activeclientsmutex.Unlock() btcplexinfo, _ := btcplex.GetInfoRPC(conf) r.JSON(200, map[string]interface{}{"activeclients": activeclients, "info": btcplexinfo}) }) log.Printf("Listening on port: %v\n", conf.AppPort) http.ListenAndServe(fmt.Sprintf(":%v", conf.AppPort), m) }
func main() { //Change secret123 to something more secure and store session in backend instead of cookie store := sessions.NewCookieStore([]byte("secret123")) dbmap = initDb() defer dbmap.Db.Close() err := dbmap.TruncateTables() checkErr(err, "TruncateTables failed") u1 := newUser("*****@*****.**", "pass", "Bob", false) //insert rows err = dbmap.Insert(&u1) checkErr(err, "Insert failed") //create two posts, assign to user 1 above p1 := newPost("Post 1", "Lorem ipsum lorem ipsum", 1) p2 := newPost("Post 2", "This is my second post", 1) // insert rows err = dbmap.Insert(&p1, &p2) checkErr(err, "Insert failed") m := martini.Classic() m.Use(render.Renderer(render.Options{ Directory: "templates", Layout: "layout", Funcs: []template.FuncMap{ { "formatTime": func(args ...interface{}) string { t1 := time.Unix(args[0].(int64), 0) return t1.Format(time.Stamp) }, }, }, })) m.Use(sessions.Sessions("my_session", store)) m.Use(sessionauth.SessionUser(GenerateAnonymousUser)) sessionauth.RedirectUrl = "/login" sessionauth.RedirectParam = "next" //ROUTES m.Get("/register", func(r render.Render, user sessionauth.User) { //redirect to homepage if already authenticated if user.IsAuthenticated() { r.Redirect("/") } else { r.HTML(200, "register", nil) } }) m.Get("/login", func(r render.Render, user sessionauth.User) { //redirect to homepage if already authenticated if user.IsAuthenticated() { r.Redirect("/") } else { r.HTML(200, "login", nil) } }) m.Post("/login", binding.Form(User{}), func(session sessions.Session, postedUser User, r render.Render, ferr binding.Errors, req *http.Request) { log.Println(ferr) //Example of server side error validation for the client side form if ferr.Count() > 0 { newmap := map[string]interface{}{"metatitle": "Registration", "errormessage": "Error with Form Submission"} r.HTML(200, "login", newmap) } else { user := User{} //check login credentails with DataBase err := dbmap.SelectOne(&user, "SELECT * FROM users WHERE email = ? and password = ?", postedUser.Email, postedUser.Password) if err != nil { r.Redirect(sessionauth.RedirectUrl) return } else { err := sessionauth.AuthenticateSession(session, &user) if err != nil { r.JSON(500, err) } params := req.URL.Query() redirect := params.Get(sessionauth.RedirectParam) r.Redirect(redirect) return } } }) m.Get("/logout", sessionauth.LoginRequired, func(session sessions.Session, user sessionauth.User, r render.Render) { sessionauth.Logout(session, user) r.Redirect("/") }) m.Get("/", func(r render.Render, authuser sessionauth.User) { var posts []Post _, err = dbmap.Select(&posts, "select * from posts order by post_id") checkErr(err, "Select failed") newmap := map[string]interface{}{"metatitle": "HomePage", "authuser": authuser, "posts": posts} r.HTML(200, "posts", newmap) }) m.Get("/users", func(r render.Render, authuser sessionauth.User) { var users []User _, err = dbmap.Select(&users, "select * from users order by id") checkErr(err, "Select failed") newmap := map[string]interface{}{"metatitle": "Users listing", "authuser": authuser, "users": users} r.HTML(200, "users", newmap) }) m.Get("/users/:id", sessionauth.LoginRequired, func(args martini.Params, r render.Render, authuser sessionauth.User) { var user User err = dbmap.SelectOne(&user, "select * from users where id=?", args["id"]) //simple error check if err != nil { newmap := map[string]interface{}{"metatitle": "404 Error", "message": "User not found"} r.HTML(404, "error", newmap) } else { var posts []Post _, err = dbmap.Select(&posts, "select * from posts where UserId=?", args["id"]) checkErr(err, "Select failed") newmap := map[string]interface{}{"metatitle": user.Name + " profile page", "authuser": authuser, "user": user, "posts": posts} r.HTML(200, "user", newmap) } }) m.Post("/users", binding.Form(User{}), func(session sessions.Session, user User, ferr binding.Errors, r render.Render) { //Example of server side error validation for the client side form if ferr.Count() > 0 { fmt.Println(ferr) newmap := map[string]interface{}{"metatitle": "Registration", "errormessage": "Error with Form Submission"} r.HTML(200, "register", newmap) } else { u := newUser(user.Email, user.Password, user.Name, user.authenticated) err = dbmap.Insert(&u) checkErr(err, "Insert failed") //create the session and redirect always to homepage err := sessionauth.AuthenticateSession(session, &u) if err != nil { r.JSON(500, err) } r.Redirect("/") } }) m.Put("/users/:id", binding.Bind(User{}), func(args martini.Params, user User, r render.Render, authuser sessionauth.User) { //convert string to int64 so you can match the struct (passing userid via ajax does not work as it comes in as a string) f, _ := strconv.ParseInt(args["id"], 0, 64) //only allow the authenticated user to update his user attributes if authuser.UniqueId() == f { //specify the user id user.Id = f count, err := dbmap.Update(&user) checkErr(err, "Update failed") log.Println("Rows updated:", count) if count == 1 { newmap := map[string]interface{}{"responseText": "success"} r.JSON(200, newmap) } else { newmap := map[string]interface{}{"responseText": "error"} r.JSON(400, newmap) } } else { newmap := map[string]interface{}{"responseText": "You are not allowed to update this resource."} r.JSON(403, newmap) } }) m.Delete("/users/:id", func(args martini.Params, r render.Render, authuser sessionauth.User) { //convert id from string to int64 f, _ := strconv.ParseInt(args["id"], 0, 64) //only allow the authenticated user to delete him or her if authuser.UniqueId() == f { _, err = dbmap.Exec("delete from users where id=?", args["id"]) checkErr(err, "Delete failed") if err == nil { newmap := map[string]interface{}{"responseText": "success"} r.JSON(200, newmap) //if you delete yourself, Ajax should redirec you } else { newmap := map[string]interface{}{"responseText": "error"} r.JSON(400, newmap) } } else { newmap := map[string]interface{}{"responseText": "You are not allowed to delete this resource."} r.JSON(403, newmap) } }) m.Post("/posts", sessionauth.LoginRequired, binding.Bind(Post{}), func(post Post, r render.Render, authuser sessionauth.User) { //convert to int64 f := authuser.UniqueId().(int64) p1 := newPost(post.Title, post.Body, f) err = dbmap.Insert(&p1) checkErr(err, "Insert failed") r.Redirect("/") }) m.Get("/posts/:id", func(args martini.Params, r render.Render, authuser sessionauth.User) { var post Post err = dbmap.SelectOne(&post, "select * from posts where post_id=?", args["id"]) //simple error check if err != nil { newmap := map[string]interface{}{"metatitle": "404 Error", "message": "This is not found"} r.HTML(404, "error", newmap) } else { newmap := map[string]interface{}{"metatitle": post.Title + " more custom", "authuser": authuser, "post": post} r.HTML(200, "post", newmap) } }) m.Get("/p/:str", func(args martini.Params, r render.Render, authuser sessionauth.User) { var post Post err = dbmap.SelectOne(&post, "select * from posts where url=?", args["str"]) //simple error check if err != nil { newmap := map[string]interface{}{"metatitle": "404 Error", "message": "This is not found"} r.HTML(404, "error", newmap) } else { newmap := map[string]interface{}{"metatitle": post.Title + " more custom", "authuser": authuser, "post": post} r.HTML(200, "post", newmap) } }) m.Put("/posts/:id", binding.Bind(Post{}), func(args martini.Params, post Post, r render.Render, authuser sessionauth.User) { var newTitle = post.Title var newBody = post.Body err = dbmap.SelectOne(&post, "select * from posts where post_id=?", args["id"]) //simple database error check if err != nil { newmap := map[string]interface{}{"message": "Something went wrong."} r.JSON(400, newmap) } else { //owner check if authuser.UniqueId() == post.UserId { post.Title = newTitle post.Body = newBody count, err := dbmap.Update(&post) checkErr(err, "Update failed") if count == 1 { newmap := map[string]interface{}{"responseText": "success"} r.JSON(200, newmap) } else { newmap := map[string]interface{}{"responseText": "error"} r.JSON(400, newmap) } } else { newmap := map[string]interface{}{"responseText": "You are not allowed to modify this resource."} r.JSON(403, newmap) } } }) m.Delete("/posts/:id", func(args martini.Params, r render.Render, authuser sessionauth.User) { //retrieve the post to check the real owner var post Post err = dbmap.SelectOne(&post, "select * from posts where post_id=?", args["id"]) //simple DB error check if err != nil { newmap := map[string]interface{}{"message": "Something went wrong."} r.JSON(400, newmap) } else { //owner check if authuser.UniqueId() == post.UserId { //delete it _, err := dbmap.Delete(&post) checkErr(err, "Delete failed") newmap := map[string]interface{}{"responseText": "success"} r.JSON(200, newmap) } else { newmap := map[string]interface{}{"responseText": "You are not allowed to delete this resource."} r.JSON(403, newmap) } } }) m.Run() }
func main() { // Read the configuration file file, _ := os.Open("conf/app.json") decoder := json.NewDecoder(file) configuration := &Configuration{} decoder.Decode(&configuration) // Initialize background processing workers.Configure(map[string]string{ // Location of the redis instance. "server": configuration.RedisURI, // The number of connections to keep open with Redis. "pool": configuration.RedisConn, // Unique process id for this instance of workers; helps with proper // recovery of inprogress jobs on a crash. "process": "1", }) m := martini.Classic() m.Use(gzip.All()) m.Use(render.Renderer()) m.Use(martini.Static("assets")) m.Use(DB()) m.Get("/", func(r render.Render) { r.HTML(200, "welcome", nil) }) m.Post("/join", binding.Form(Account{}), func(account Account, r render.Render, db *mgo.Database) { u, err := uuid.NewV4() if err != nil { panic(err) } token := strings.Replace(u.String(), "-", "", -1) reflect.ValueOf(&account).Elem().FieldByName("EmailValidationToken").SetString(token) db.C("accounts").Insert(account) // Send the activation email r.HTML(200, "join_success", nil) }) m.Get("/accounts/activate/:token", func(r render.Render) { r.HTML(200, "registration", nil) }) /* m.Post("/accounts/new", binding.Form(Account{}), func(account Account, r render.Render, db *mgo.Database) { colQuerier := bson.M{"email": ""} change := bson.M{"$set": bson.M{}} err = db.C("accounts").Update(colQuerier, change) if err != nil { log.Fatal(err) } })*/ // Handle 404. m.NotFound(func(r render.Render) { r.HTML(404, "notfound", nil) }) s := &http.Server{ Addr: ":8080", Handler: m, ReadTimeout: 10 * time.Second, WriteTimeout: 10 * time.Second, MaxHeaderBytes: 1 << 20, } log.Fatal(s.ListenAndServe()) }
func main() { m := martini.Classic() store := sessions.NewCookieStore([]byte("battle_answers")) m.Use(sessions.Sessions("my_battle_answers_session", store)) m.Use(DB()) m.Use(render.Renderer(render.Options{ Directory: "templates", Layout: "layout", Funcs: []template.FuncMap{ { "addInClass": func(args ...interface{}) string { var i int var className string i = args[0].(int) if i == 0 { className = " in" } else { className = "" } return className }, "addSelected": func(args ...interface{}) string { var lastGameIdSearched string selectedString := "" lastGameIdSearched = args[1].(string) if args[0] == bson.ObjectIdHex(lastGameIdSearched) { selectedString = "selected" } return selectedString }, "addActiveClass": func(args ...interface{}) string { className := "" for _, path := range args[1:] { if path == args[0] { className = "active" break } } return className }, }, }, })) m.Get("/", func(r render.Render, db *mgo.Database, req *http.Request) { templateData := map[string]interface{}{"metatitle": "Battle Answers", "currentPath": req.URL.Path} r.HTML(200, "index", templateData) }) m.Get("/games", controllers.GamesIndex) m.Get("/games/new", controllers.GamesNew) m.Post("/games", binding.Form(controllers.GameForm{}), controllers.GamesCreate) m.Get("/battle_answers", controllers.BattleAnswersIndex) m.Get("/battle_answers/new", controllers.BattleAnswersNew) m.Post("/battle_answers", binding.Form(controllers.BattleAnswerForm{}), controllers.BattleAnswersCreate) m.Get("/search_answers", controllers.SearchAnswersIndex) m.Get("/search_answers/new", controllers.SearchAnswersNew) m.Post("/search_answers", binding.Form(controllers.SearchAnswerForm{}), controllers.SearchAnswersCreate) m.Run() }