Example #1
0
func StartGin() {
	gin.SetMode(gin.ReleaseMode)

	router := gin.New()
	router.Use(rateLimit, gin.Recovery())
	router.LoadHTMLGlob("resources/*.templ.html")
	router.Static("/static", "resources/static")
	router.GET("/", index)
	router.GET("/room/:roomid", roomGET)
	router.POST("/room-post/:roomid", roomPOST)
	router.GET("/stream/:roomid", streamRoom)

	router.Run(":80")
}
Example #2
0
// This function's name is a must. App Engine uses it to drive the requests properly.
func init() {
	// Starts a new Gin instance with no middle-ware
	r := gin.New()

	// Define your handlers
	r.GET("/", func(c *gin.Context) {
		c.String(200, "Hello World!")
	})
	r.GET("/ping", func(c *gin.Context) {
		c.String(200, "pong")
	})

	// Handle all requests using net/http
	http.Handle("/", r)
}
Example #3
0
func main() {
	port := os.Getenv("PORT")
	if port == "" {
		log.Fatal("$PORT must be set")
	}

	rooms = make(map[string]*room)
	router := gin.New()
	router.Use(gin.Logger())
	router.Static("/static", "static")
	router.LoadHTMLGlob("templates/*")

	router.GET("/poll/:slug/:code", func(c *gin.Context) {
		rmx.Lock()
		locked := true
		defer func() {
			if locked {
				rmx.Unlock()
			}
		}()

		r, ok := rooms[c.Param("slug")]
		if !ok {
			c.String(http.StatusNotFound, "That room does not exist.")
			return
		}

		if c.Param("code") == r.scode {
			c.String(http.StatusForbidden, "This page is only available to instructors.")
			return
		}
		if c.Param("code") != r.icode {
			c.String(http.StatusUnauthorized, "Wrong code given for this room.")
			return
		}

		since, err := strconv.Atoi(c.DefaultQuery("since", "0"))
		if err != nil || since < 0 {
			c.String(http.StatusBadRequest, "Non-integer 'since' given")
			return
		}

		first := time.Now()
		for since >= len(r.qs) {
			rmx.Unlock()
			locked = false

			// Heroku doesn't allow long-polling for more than 30s
			// without sending data. We could potentially send
			// parts of an empty JSON array or something, but this
			// is vastly simpler, and still improves on the simple
			// polling we used before.
			if time.Now().Sub(first) >= 20*time.Second {
				c.Status(http.StatusNoContent)
				//c.JSON(http.StatusOK, []question{})
				return
			}

			<-time.After(500 * time.Millisecond)
			rmx.Lock()
			locked = true
		}

		// For minimal latency between a student asking a question and
		// it appearing in the instructor's view, no caches should
		// store the reply to a poll. Note that this means that if many
		// instructors are accessing the instructor's view, every
		// single one will cause a request to be sent to the backend.
		// For most use-cases, this should not be an issue. That said,
		// if your class has *a lot* of instructors, you may want to
		// set this to something like max-age=5.
		c.Header("Cache-Control", "no-cache")
		c.JSON(http.StatusOK, r.qs[since:])
	})

	router.GET("/room/:slug/:code", func(c *gin.Context) {
		rmx.Lock()
		defer rmx.Unlock()
		r, ok := rooms[c.Param("slug")]
		if !ok {
			if len(c.Param("code")) == 8 {
				if _, err := hex.DecodeString(c.Param("code")); err == nil {
					c.String(http.StatusGone,
						"Cannot create rooms with an instructor key that resembles a hash.\nYou may get this error if the instructors haven't created the room yet.",
					)
					return
				}
			}

			h := sha3.Sum512([]byte(c.Param("code")))
			scode := hex.EncodeToString(h[:])[0:8]
			r = &room{
				qs: []question{{
					Text: fmt.Sprintf("Room created. Student code is '%s'", scode),
					Inst: true,
					By:   "<master>",
				}},
				icode: c.Param("code"),
				scode: scode,
			}
			rooms[c.Param("slug")] = r
		}

		if c.Param("code") != r.icode && c.Param("code") != r.scode {
			c.HTML(http.StatusUnauthorized, "bad.tmpl", gin.H{
				"room": c.Param("slug"),
			})
			return
		}

		revqs := make([]question, len(r.qs))
		for i := range r.qs {
			revqs[i] = r.qs[len(r.qs)-i-1]
		}
		c.HTML(http.StatusOK, "room.tmpl", gin.H{
			"room":       c.Param("slug"),
			"instructor": c.Param("code") == r.icode,
			"submitted":  c.DefaultQuery("submitted", "0"),
			"qs":         revqs,
			"scode":      r.scode,
		})
	})

	router.POST("/room/:slug/:code", func(c *gin.Context) {
		rmx.Lock()
		defer rmx.Unlock()

		r, ok := rooms[c.Param("slug")]
		if !ok {
			c.String(http.StatusNotFound, "That room does not exist.")
			return
		}

		if c.Param("code") != r.icode && c.Param("code") != r.scode {
			c.String(http.StatusUnauthorized, "Wrong code given for this room.")
			return
		}

		q := c.PostForm("question")
		if strings.TrimSpace(q) == "" {
			c.String(http.StatusBadRequest, "Question was empty.")
			return
		}

		nick := strings.TrimSpace(c.DefaultPostForm("nick", ""))
		r.qs = append(r.qs, question{
			Text: q,
			Inst: c.Param("code") == r.icode,
			By:   nick,
		})
		to := *c.Request.URL
		to.RawQuery = "submitted=1"
		c.Redirect(http.StatusFound, to.RequestURI())
	})

	router.Run(":" + port)
}