main.go 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. package main
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "html/template"
  6. "io"
  7. "log"
  8. "net/http"
  9. "strings"
  10. glws "git.alfi.li/gamelang/frontend/webserver"
  11. glwss "git.alfi.li/gamelang/frontend/wsserver"
  12. jeopardyman "git.alfi.li/gamelang/games/jeopardy/jeopardyManager"
  13. gamelangpb "git.alfi.li/gamelang/protobuf/gamelang"
  14. gljeopardypb "git.alfi.li/gamelang/protobuf/gamelang-jeopardy"
  15. userman "git.alfi.li/gamelang/systems/usermanager"
  16. worldman "git.alfi.li/gamelang/systems/worldmanager"
  17. "github.com/labstack/echo/v4"
  18. "gopkg.in/gcfg.v1"
  19. )
  20. // Template wraps go's html template
  21. type Template struct {
  22. templates *template.Template
  23. }
  24. // Render renders a Template
  25. func (t *Template) Render(w io.Writer, name string, data interface{}, c echo.Context) error {
  26. return t.templates.ExecuteTemplate(w, name, data)
  27. }
  28. func initTemplates(e *echo.Echo) {
  29. t := &Template{
  30. templates: template.Must(template.ParseGlob("public/*.html")),
  31. }
  32. e.Renderer = t
  33. }
  34. type JeopardyConfig struct {
  35. Http struct {
  36. ListenIP string
  37. ListenPort string
  38. }
  39. WS struct {
  40. ListenIP string
  41. ListenPort string
  42. }
  43. Manager struct {
  44. UserManager string
  45. WorldManager string
  46. JeopardyManager string
  47. }
  48. }
  49. func getDefaultConfig() JeopardyConfig {
  50. bc := JeopardyConfig{}
  51. bc.Http.ListenIP = "0.0.0.0"
  52. bc.Http.ListenPort = "8080"
  53. bc.WS.ListenIP = "0.0.0.0"
  54. bc.WS.ListenPort = "8081"
  55. bc.Manager.UserManager = "localhost:9090"
  56. bc.Manager.WorldManager = "localhost:9091"
  57. bc.Manager.JeopardyManager = "localhost:9092"
  58. return bc
  59. }
  60. type JeopardyGameServer struct {
  61. um *userman.UserManager //gamelangpb.UserServiceClient
  62. wm *worldman.WorldManager //gamelangpb.WorldServiceClient
  63. jeopardymanager *jeopardyman.JeopardyManager
  64. webserver *glws.Webserver
  65. wssserver *glwss.WSServer
  66. notichan chan gljeopardypb.Event
  67. config JeopardyConfig
  68. }
  69. func (bg *JeopardyGameServer) Init(config JeopardyConfig) {
  70. //init userclient
  71. //userconn, err := grpc.Dial(config.Manager.UserManager, grpc.WithInsecure())
  72. //if err != nil {
  73. // panic(err.Error())
  74. //}
  75. //defer userconn.Close()
  76. bg.um = userman.NewUserManager([]string{}) //gamelangpb.NewUserServiceClient(userconn)
  77. //init wm
  78. //worldconn, err := grpc.Dial(config.Manager.WorldManager, grpc.WithInsecure())
  79. //if err != nil {
  80. // panic(err.Error())
  81. //}
  82. //defer worldconn.Close()
  83. bg.wm = worldman.NewWorldManager([]string{}) //gamelangpb.NewWorldServiceClient(worldconn)
  84. bg.notichan = make(chan gljeopardypb.Event)
  85. bg.jeopardymanager = jeopardyman.NewJeopardyManager([]string{}, bg.notichan)
  86. go bg.workNotifications()
  87. //init webserver
  88. wsConfig := glws.Config{}
  89. wsConfig.Http.ListenIP = config.Http.ListenIP
  90. wsConfig.Http.ListenPort = config.Http.ListenPort
  91. bg.webserver = glws.NewWebserver(wsConfig)
  92. bg.wssserver = glwss.NewWSServer([]string{}, nil, bg.um)
  93. }
  94. func (bg *JeopardyGameServer) workNotifications() {
  95. for {
  96. log.Print("waiting for notification")
  97. event := <-bg.notichan
  98. log.Println("new notification", event)
  99. eventJson, err := json.Marshal(event)
  100. if err != nil {
  101. log.Printf("workNotifications - err marshalling event \"%s\"\n%s", event, err.Error())
  102. }
  103. notify := glwss.WSMsg{Mtype: "game:event", Payload: string(eventJson)}
  104. worldgamename := strings.Split(event.Gamename, "\uffff")
  105. worldname := worldgamename[0]
  106. gamename := worldgamename[1]
  107. // if the game is a common game or its a win event all players have to be notified
  108. if gamename == "common" || event.Type == "Win" {
  109. world := gamelangpb.World{}
  110. worlds := bg.wm.List()
  111. for _, world := range worlds {
  112. if world.GetName() == worldname {
  113. log.Println("sending world\n", world)
  114. break
  115. }
  116. }
  117. //world, err := bg.wm.GetWorld(context.Background(), &gamelangpb.World{Name: worldname})
  118. if err != nil {
  119. log.Printf("workNotifications - err getting world msg \"%s\"\n%s", worldname, err.Error())
  120. return
  121. }
  122. for _, user := range world.Users {
  123. go bg.wssserver.Write(user.Name, notify)
  124. }
  125. } else {
  126. bg.wssserver.Write(event.Username, notify)
  127. }
  128. }
  129. }
  130. // RenderEndpoints returns the endpoints that are served by the webserver
  131. func (bg *JeopardyGameServer) RenderEndpoints() []glws.Endpoint {
  132. endpoints := []glws.Endpoint{}
  133. endpoints = append(endpoints, glws.Endpoint{"GET", "/",
  134. func(ctx echo.Context) error {
  135. log.Print("/: get")
  136. ok, user := bg.webserver.CheckSess(ctx)
  137. if !ok {
  138. log.Print("/: not found")
  139. return ctx.Redirect(301, "/login")
  140. }
  141. data := struct {
  142. Username string
  143. Worlds []gamelangpb.World
  144. Items []string
  145. }{
  146. Username: user.Name,
  147. Worlds: func() []gamelangpb.World {
  148. worlds := bg.wm.List()
  149. return worlds
  150. }(),
  151. Items: []string{
  152. "user",
  153. "world",
  154. },
  155. }
  156. log.Printf("/: user \"%v\" found", user.Name)
  157. return ctx.Render(http.StatusOK, "index", data)
  158. }})
  159. endpoints = append(endpoints, glws.Endpoint{"GET", "/admin", func(ctx echo.Context) error {
  160. log.Print("/admin: get")
  161. ok, user := bg.webserver.CheckSess(ctx)
  162. if !ok {
  163. log.Print("/admin: not logged in")
  164. return ctx.String(http.StatusUnauthorized, "not logged in")
  165. }
  166. log.Println("/admin:", user.Name)
  167. if user.Admin != true && user.Name != "admin" {
  168. log.Println("/admin: user is not an admin", user.Name)
  169. return ctx.String(http.StatusUnauthorized, "you are not an admin")
  170. }
  171. data := struct {
  172. Users []gamelangpb.User
  173. Sessions map[string]gamelangpb.User
  174. Worlds []gamelangpb.World
  175. }{
  176. Users: func() []gamelangpb.User {
  177. users := bg.um.List()
  178. return users
  179. }(),
  180. Sessions: bg.webserver.ListSess(),
  181. Worlds: func() []gamelangpb.World {
  182. worlds := bg.wm.List()
  183. return worlds
  184. }(),
  185. }
  186. err := ctx.Render(http.StatusOK, "admin", data)
  187. if err != nil {
  188. log.Println(err)
  189. }
  190. return err
  191. }})
  192. endpoints = append(endpoints, userEndpoints(bg)...)
  193. endpoints = append(endpoints, worldEndpoints(bg)...)
  194. // worldbuilder
  195. // Get to /World returns register form
  196. }
  197. //RenderHandler renders the endpoints that will be served via websocket
  198. func (bg *JeopardyGameServer) RenderHandler() []glwss.Handler {
  199. handler := []glwss.Handler{}
  200. handler = append(handler, glwss.Handler{MType: "echo", Callback: func(msg glwss.WSMsg, user gamelangpb.User) (glwss.WSMsg, error) {
  201. log.Printf("echo from \"%v\" with \"%s\"", user, msg.Payload)
  202. remsg := glwss.WSMsg{Mtype: "echo", Payload: msg.Payload}
  203. return remsg, nil
  204. }})
  205. handler = append(handler, worldHandler()...)
  206. return handler
  207. }
  208. func CraftLobbygame(name string) gljeopardypb.Jeopardy {
  209. lobbygame := gljeopardypb.Jeopardy{Name: name}
  210. lobbygame.Options = append(lobbygame.Options, &gljeopardypb.Option{Key: "unique fields", Bool: true, Type: 1})
  211. lobbygame.Options = append(lobbygame.Options, &gljeopardypb.Option{Key: "common game", Bool: true, Type: 1})
  212. lobbygame.Numcols = 5
  213. lobbygame.Numrows = 5
  214. lobbygame.Textlist = []string{"word"}
  215. return lobbygame
  216. }
  217. func main() {
  218. var config JeopardyConfig
  219. err := gcfg.ReadFileInto(&config, "config")
  220. if err != nil {
  221. if strings.Count(err.Error(), "no such file or directory") > 0 {
  222. config = getDefaultConfig()
  223. } else {
  224. log.Fatal(err)
  225. }
  226. }
  227. log.Print("config read")
  228. log.Printf("%+v", config)
  229. jeopardygame := JeopardyGameServer{}
  230. jeopardygame.Init(config)
  231. jeopardygame.webserver.InitEndpoints(jeopardygame.RenderEndpoints())
  232. go jeopardygame.webserver.Run()
  233. handler := jeopardygame.RenderHandler()
  234. keys := ""
  235. for _, k := range handler {
  236. keys = fmt.Sprintf("%s\n%v", keys, k)
  237. }
  238. log.Println("available MTypes:\n", keys, "\n----")
  239. jeopardygame.wssserver.RegisterHandler(handler)
  240. http.HandleFunc("/ws", jeopardygame.wssserver.WebsocketHandler)
  241. log.Println("websocket listening on", fmt.Sprintf("%s:%s", config.WS.ListenIP, config.WS.ListenPort))
  242. log.Print(http.ListenAndServe(fmt.Sprintf("%s:%s", config.WS.ListenIP, config.WS.ListenPort), nil).Error())
  243. }