123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283 |
- package main
- import (
- "encoding/json"
- "fmt"
- "html/template"
- "io"
- "log"
- "net/http"
- "strings"
- glws "git.alfi.li/gamelang/frontend/webserver"
- glwss "git.alfi.li/gamelang/frontend/wsserver"
- jeopardyman "git.alfi.li/gamelang/games/jeopardy/jeopardyManager"
- gamelangpb "git.alfi.li/gamelang/protobuf/gamelang"
- gljeopardypb "git.alfi.li/gamelang/protobuf/gamelang-jeopardy"
- userman "git.alfi.li/gamelang/systems/usermanager"
- worldman "git.alfi.li/gamelang/systems/worldmanager"
- "github.com/labstack/echo/v4"
- "gopkg.in/gcfg.v1"
- )
- // Template wraps go's html template
- type Template struct {
- templates *template.Template
- }
- // Render renders a Template
- func (t *Template) Render(w io.Writer, name string, data interface{}, c echo.Context) error {
- return t.templates.ExecuteTemplate(w, name, data)
- }
- func initTemplates(e *echo.Echo) {
- t := &Template{
- templates: template.Must(template.ParseGlob("public/*.html")),
- }
- e.Renderer = t
- }
- type JeopardyConfig struct {
- Http struct {
- ListenIP string
- ListenPort string
- }
- WS struct {
- ListenIP string
- ListenPort string
- }
- Manager struct {
- UserManager string
- WorldManager string
- JeopardyManager string
- }
- }
- func getDefaultConfig() JeopardyConfig {
- bc := JeopardyConfig{}
- bc.Http.ListenIP = "0.0.0.0"
- bc.Http.ListenPort = "8080"
- bc.WS.ListenIP = "0.0.0.0"
- bc.WS.ListenPort = "8081"
- bc.Manager.UserManager = "localhost:9090"
- bc.Manager.WorldManager = "localhost:9091"
- bc.Manager.JeopardyManager = "localhost:9092"
- return bc
- }
- type JeopardyGameServer struct {
- um *userman.UserManager //gamelangpb.UserServiceClient
- wm *worldman.WorldManager //gamelangpb.WorldServiceClient
- jeopardymanager *jeopardyman.JeopardyManager
- webserver *glws.Webserver
- wssserver *glwss.WSServer
- notichan chan gljeopardypb.Event
- config JeopardyConfig
- }
- func (bg *JeopardyGameServer) Init(config JeopardyConfig) {
- //init userclient
- //userconn, err := grpc.Dial(config.Manager.UserManager, grpc.WithInsecure())
- //if err != nil {
- // panic(err.Error())
- //}
- //defer userconn.Close()
- bg.um = userman.NewUserManager([]string{}) //gamelangpb.NewUserServiceClient(userconn)
- //init wm
- //worldconn, err := grpc.Dial(config.Manager.WorldManager, grpc.WithInsecure())
- //if err != nil {
- // panic(err.Error())
- //}
- //defer worldconn.Close()
- bg.wm = worldman.NewWorldManager([]string{}) //gamelangpb.NewWorldServiceClient(worldconn)
- bg.notichan = make(chan gljeopardypb.Event)
- bg.jeopardymanager = jeopardyman.NewJeopardyManager([]string{}, bg.notichan)
- go bg.workNotifications()
- //init webserver
- wsConfig := glws.Config{}
- wsConfig.Http.ListenIP = config.Http.ListenIP
- wsConfig.Http.ListenPort = config.Http.ListenPort
- bg.webserver = glws.NewWebserver(wsConfig)
- bg.wssserver = glwss.NewWSServer([]string{}, nil, bg.um)
- }
- func (bg *JeopardyGameServer) workNotifications() {
- for {
- log.Print("waiting for notification")
- event := <-bg.notichan
- log.Println("new notification", event)
- eventJson, err := json.Marshal(event)
- if err != nil {
- log.Printf("workNotifications - err marshalling event \"%s\"\n%s", event, err.Error())
- }
- notify := glwss.WSMsg{Mtype: "game:event", Payload: string(eventJson)}
- worldgamename := strings.Split(event.Gamename, "\uffff")
- worldname := worldgamename[0]
- gamename := worldgamename[1]
- // if the game is a common game or its a win event all players have to be notified
- if gamename == "common" || event.Type == "Win" {
- world := gamelangpb.World{}
- worlds := bg.wm.List()
- for _, world := range worlds {
- if world.GetName() == worldname {
- log.Println("sending world\n", world)
- break
- }
- }
- //world, err := bg.wm.GetWorld(context.Background(), &gamelangpb.World{Name: worldname})
- if err != nil {
- log.Printf("workNotifications - err getting world msg \"%s\"\n%s", worldname, err.Error())
- return
- }
- for _, user := range world.Users {
- go bg.wssserver.Write(user.Name, notify)
- }
- } else {
- bg.wssserver.Write(event.Username, notify)
- }
- }
- }
- // RenderEndpoints returns the endpoints that are served by the webserver
- func (bg *JeopardyGameServer) RenderEndpoints() []glws.Endpoint {
- endpoints := []glws.Endpoint{}
- endpoints = append(endpoints, glws.Endpoint{"GET", "/",
- func(ctx echo.Context) error {
- log.Print("/: get")
- ok, user := bg.webserver.CheckSess(ctx)
- if !ok {
- log.Print("/: not found")
- return ctx.Redirect(301, "/login")
- }
- data := struct {
- Username string
- Worlds []gamelangpb.World
- Items []string
- }{
- Username: user.Name,
- Worlds: func() []gamelangpb.World {
- worlds := bg.wm.List()
- return worlds
- }(),
- Items: []string{
- "user",
- "world",
- },
- }
- log.Printf("/: user \"%v\" found", user.Name)
- return ctx.Render(http.StatusOK, "index", data)
- }})
- endpoints = append(endpoints, glws.Endpoint{"GET", "/admin", func(ctx echo.Context) error {
- log.Print("/admin: get")
- ok, user := bg.webserver.CheckSess(ctx)
- if !ok {
- log.Print("/admin: not logged in")
- return ctx.String(http.StatusUnauthorized, "not logged in")
- }
- log.Println("/admin:", user.Name)
- if user.Admin != true && user.Name != "admin" {
- log.Println("/admin: user is not an admin", user.Name)
- return ctx.String(http.StatusUnauthorized, "you are not an admin")
- }
- data := struct {
- Users []gamelangpb.User
- Sessions map[string]gamelangpb.User
- Worlds []gamelangpb.World
- }{
- Users: func() []gamelangpb.User {
- users := bg.um.List()
- return users
- }(),
- Sessions: bg.webserver.ListSess(),
- Worlds: func() []gamelangpb.World {
- worlds := bg.wm.List()
- return worlds
- }(),
- }
- err := ctx.Render(http.StatusOK, "admin", data)
- if err != nil {
- log.Println(err)
- }
- return err
- }})
- endpoints = append(endpoints, userEndpoints(bg)...)
- endpoints = append(endpoints, worldEndpoints(bg)...)
- // worldbuilder
- // Get to /World returns register form
- }
- //RenderHandler renders the endpoints that will be served via websocket
- func (bg *JeopardyGameServer) RenderHandler() []glwss.Handler {
- handler := []glwss.Handler{}
- handler = append(handler, glwss.Handler{MType: "echo", Callback: func(msg glwss.WSMsg, user gamelangpb.User) (glwss.WSMsg, error) {
- log.Printf("echo from \"%v\" with \"%s\"", user, msg.Payload)
- remsg := glwss.WSMsg{Mtype: "echo", Payload: msg.Payload}
- return remsg, nil
- }})
- handler = append(handler, worldHandler()...)
- return handler
- }
- func CraftLobbygame(name string) gljeopardypb.Jeopardy {
- lobbygame := gljeopardypb.Jeopardy{Name: name}
- lobbygame.Options = append(lobbygame.Options, &gljeopardypb.Option{Key: "unique fields", Bool: true, Type: 1})
- lobbygame.Options = append(lobbygame.Options, &gljeopardypb.Option{Key: "common game", Bool: true, Type: 1})
- lobbygame.Numcols = 5
- lobbygame.Numrows = 5
- lobbygame.Textlist = []string{"word"}
- return lobbygame
- }
- func main() {
- var config JeopardyConfig
- err := gcfg.ReadFileInto(&config, "config")
- if err != nil {
- if strings.Count(err.Error(), "no such file or directory") > 0 {
- config = getDefaultConfig()
- } else {
- log.Fatal(err)
- }
- }
- log.Print("config read")
- log.Printf("%+v", config)
- jeopardygame := JeopardyGameServer{}
- jeopardygame.Init(config)
- jeopardygame.webserver.InitEndpoints(jeopardygame.RenderEndpoints())
- go jeopardygame.webserver.Run()
- handler := jeopardygame.RenderHandler()
- keys := ""
- for _, k := range handler {
- keys = fmt.Sprintf("%s\n%v", keys, k)
- }
- log.Println("available MTypes:\n", keys, "\n----")
- jeopardygame.wssserver.RegisterHandler(handler)
- http.HandleFunc("/ws", jeopardygame.wssserver.WebsocketHandler)
- log.Println("websocket listening on", fmt.Sprintf("%s:%s", config.WS.ListenIP, config.WS.ListenPort))
- log.Print(http.ListenAndServe(fmt.Sprintf("%s:%s", config.WS.ListenIP, config.WS.ListenPort), nil).Error())
- }
|