main.go 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677
  1. package main
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "html/template"
  6. "io"
  7. "log"
  8. "math/rand"
  9. "net/http"
  10. "strings"
  11. glws "git.alfi.li/gamelang/frontend/webserver"
  12. glwss "git.alfi.li/gamelang/frontend/wsserver"
  13. bingoman "git.alfi.li/gamelang/games/bingo/bingoManager"
  14. gamelangpb "git.alfi.li/gamelang/protobuf/golang"
  15. glbingopb "git.alfi.li/gamelang/protobuf/golang-jeopardy"
  16. userman "git.alfi.li/gamelang/systems/usermanager"
  17. worldman "git.alfi.li/gamelang/systems/worldmanager"
  18. "github.com/labstack/echo/v4"
  19. "gopkg.in/gcfg.v1"
  20. )
  21. // Template wraps go's html template
  22. type Template struct {
  23. templates *template.Template
  24. }
  25. // Render renders a Template
  26. func (t *Template) Render(w io.Writer, name string, data interface{}, c echo.Context) error {
  27. return t.templates.ExecuteTemplate(w, name, data)
  28. }
  29. func initTemplates(e *echo.Echo) {
  30. t := &Template{
  31. templates: template.Must(template.ParseGlob("public/*.html")),
  32. }
  33. e.Renderer = t
  34. }
  35. type BingoConfig struct {
  36. Http struct {
  37. ListenIP string
  38. ListenPort string
  39. }
  40. WS struct {
  41. ListenIP string
  42. ListenPort string
  43. }
  44. Manager struct {
  45. UserManager string
  46. WorldManager string
  47. BingoManager string
  48. }
  49. }
  50. func getDefaultConfig() BingoConfig {
  51. bc := BingoConfig{}
  52. bc.Http.ListenIP = "0.0.0.0"
  53. bc.Http.ListenPort = "8080"
  54. bc.WS.ListenIP = "0.0.0.0"
  55. bc.WS.ListenPort = "8081"
  56. bc.Manager.UserManager = "localhost:9090"
  57. bc.Manager.WorldManager = "localhost:9091"
  58. bc.Manager.BingoManager = "localhost:9092"
  59. return bc
  60. }
  61. type BingoGame struct {
  62. um *userman.UserManager //gamelangpb.UserServiceClient
  63. wm *worldman.WorldManager //gamelangpb.WorldServiceClient
  64. bingomanager *bingoman.BingoManager
  65. webserver *glws.Webserver
  66. wssserver *glwss.WSServer
  67. notichan chan glbingopb.Event
  68. config BingoConfig
  69. }
  70. func (bg *BingoGame) Init(config BingoConfig) {
  71. //init userclient
  72. //userconn, err := grpc.Dial(config.Manager.UserManager, grpc.WithInsecure())
  73. //if err != nil {
  74. // panic(err.Error())
  75. //}
  76. //defer userconn.Close()
  77. bg.um = userman.NewUserManager([]string{}) //gamelangpb.NewUserServiceClient(userconn)
  78. //init wm
  79. //worldconn, err := grpc.Dial(config.Manager.WorldManager, grpc.WithInsecure())
  80. //if err != nil {
  81. // panic(err.Error())
  82. //}
  83. //defer worldconn.Close()
  84. bg.wm = worldman.NewWorldManager([]string{}) //gamelangpb.NewWorldServiceClient(worldconn)
  85. bg.notichan = make(chan glbingopb.Event)
  86. bg.bingomanager = bingoman.NewBingoManager([]string{}, bg.notichan)
  87. go bg.workNotifications()
  88. //init webserver
  89. wsConfig := glws.Config{}
  90. wsConfig.Http.ListenIP = config.Http.ListenIP
  91. wsConfig.Http.ListenPort = config.Http.ListenPort
  92. bg.webserver = glws.NewWebserver(wsConfig)
  93. }
  94. func (bg *BingoGame) 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 *BingoGame) 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", "/user", func(ctx echo.Context) error {
  160. log.Print("/user: get")
  161. log.Print("/user: sending register form")
  162. return ctx.Render(http.StatusOK, "registerform", "")
  163. }})
  164. // POST to /user creates a user
  165. endpoints = append(endpoints, glws.Endpoint{"POST", "/user", func(ctx echo.Context) error {
  166. username := ctx.FormValue("username")
  167. password := ctx.FormValue("password")
  168. log.Printf("new user request: %v", username)
  169. newUser := gamelangpb.User{Name: username, Password: []byte(password)}
  170. id := rand.Uint32()
  171. name := newUser.GetName()
  172. _, err := bg.um.Create(id, name, password)
  173. //user, err := bg.userclient.CreateUser(context.Background(), &newUser)
  174. if err != nil {
  175. return ctx.String(501, "user creation failed")
  176. }
  177. bg.webserver.NewSession(newUser, ctx)
  178. log.Printf("new user created: %v", username)
  179. return ctx.Redirect(302, "/")
  180. }})
  181. endpoints = append(endpoints, glws.Endpoint{"GET", "/login", func(ctx echo.Context) error {
  182. log.Print("/login: get")
  183. // check if the login page was called with failed parameter (set by /login POST)
  184. failedBefore := false
  185. if value := ctx.FormValue("failed"); value == "1" {
  186. failedBefore = true
  187. }
  188. ok, user := bg.webserver.CheckSess(ctx)
  189. if ok {
  190. // logged in
  191. log.Printf("/login: user %v logged in", user.Name)
  192. return ctx.String(http.StatusOK, "hello, "+user.Name+"\nyou are logged in.")
  193. }
  194. // not logged in
  195. log.Print("/login: not logged in")
  196. return ctx.Render(http.StatusOK, "loginform", failedBefore)
  197. }})
  198. endpoints = append(endpoints, glws.Endpoint{"POST", "/login", func(ctx echo.Context) error {
  199. log.Print("/login: post")
  200. username := ctx.FormValue("username")
  201. password := ctx.FormValue("password")
  202. // if the session is already set, the user is already logged in
  203. ok, _ := bg.webserver.CheckSess(ctx)
  204. if ok {
  205. return ctx.String(http.StatusOK, "you are already logged in.")
  206. }
  207. log.Printf("user login attempt: %v", username)
  208. //checkuser := gamelangpb.User{Name: username, Password: []byte(password)}
  209. user, ok := bg.um.CheckUser(username, password) //bg.userclient.CheckUser(context.Background(), &checkuser)
  210. if ok { //err == nil {
  211. bg.webserver.NewSession(user, ctx)
  212. log.Printf("user login suceeded: %v", username)
  213. return ctx.String(http.StatusOK, "hello, "+username+"\nyou are now logged in.")
  214. }
  215. log.Printf("user login failed: %v\n%s", username)
  216. return ctx.Redirect(302, "/login?failed=1")
  217. }})
  218. endpoints = append(endpoints, glws.Endpoint{"GET", "/admin", func(ctx echo.Context) error {
  219. log.Print("/admin: get")
  220. ok, user := bg.webserver.CheckSess(ctx)
  221. if !ok {
  222. log.Print("/admin: not logged in")
  223. return ctx.String(http.StatusUnauthorized, "not logged in")
  224. }
  225. log.Println("/admin:", user.Name)
  226. if user.Admin != true && user.Name != "admin" {
  227. log.Println("/admin: user is not an admin", user.Name)
  228. return ctx.String(http.StatusUnauthorized, "you are not an admin")
  229. }
  230. data := struct {
  231. Users []gamelangpb.User
  232. Sessions map[string]gamelangpb.User
  233. Worlds []gamelangpb.World
  234. }{
  235. Users: func() []gamelangpb.User {
  236. users := bg.um.List()
  237. return users
  238. }(),
  239. Sessions: bg.webserver.ListSess(),
  240. Worlds: func() []gamelangpb.World {
  241. worlds := bg.wm.List()
  242. return worlds
  243. }(),
  244. }
  245. err := ctx.Render(http.StatusOK, "admin", data)
  246. if err != nil {
  247. log.Println(err)
  248. }
  249. return err
  250. }})
  251. // worldbuilder
  252. // Get to /World returns register form
  253. endpoints = append(endpoints, glws.Endpoint{"GET", "/world", func(ctx echo.Context) error {
  254. ok, _ := bg.webserver.CheckSess(ctx)
  255. if !ok {
  256. log.Print("/World: not logged in")
  257. return ctx.String(http.StatusUnauthorized, "not logged in")
  258. }
  259. data := struct {
  260. Worlds []gamelangpb.World
  261. }{
  262. Worlds: func() []gamelangpb.World {
  263. worlds := bg.wm.List()
  264. return worlds
  265. }(),
  266. }
  267. err := ctx.Render(http.StatusOK, "worldlobby", data)
  268. if err != nil {
  269. log.Print(err)
  270. }
  271. return err
  272. }})
  273. endpoints = append(endpoints, glws.Endpoint{"POST", "/world", func(ctx echo.Context) error {
  274. ok, _ := bg.webserver.CheckSess(ctx)
  275. if !ok {
  276. log.Print("/World: not logged in")
  277. return ctx.String(http.StatusUnauthorized, "not logged in")
  278. }
  279. worldname := ctx.FormValue("worldname")
  280. world := &gamelangpb.World{Name: worldname}
  281. lobbygame := CraftLobbygame(fmt.Sprintf("%s\uffff%s", world.GetName(), "lobby"))
  282. world.Games = []string{lobbygame.Name}
  283. log.Println("/World: creating world_\n", world)
  284. id := rand.Uint32()
  285. world.Id = id
  286. _, err := bg.wm.Create(*world)
  287. if err != nil {
  288. log.Println("error creating world", err)
  289. return ctx.String(http.StatusInternalServerError, "error creating world")
  290. }
  291. err = bg.bingomanager.Create(lobbygame)
  292. if err != nil {
  293. log.Println("error creating world", err)
  294. return ctx.String(http.StatusInternalServerError, "error creating world")
  295. }
  296. return ctx.Redirect(http.StatusFound, "/world")
  297. }})
  298. endpoints = append(endpoints, glws.Endpoint{"POST", "/world/join", func(ctx echo.Context) error {
  299. log.Print("join attemt")
  300. ok, user := bg.webserver.CheckSess(ctx)
  301. if !ok {
  302. log.Print("/World/join: not logged in")
  303. return ctx.String(http.StatusUnauthorized, "not logged in")
  304. }
  305. worldname := ctx.FormValue("worldname")
  306. log.Println("joining", user.Name, "to", worldname)
  307. joinworld := gamelangpb.World{Name: worldname, Users: []*gamelangpb.User{}}
  308. joinworld.Users = append(joinworld.Users, &user)
  309. err := bg.wm.Join(worldname, &user)
  310. if err != nil {
  311. log.Printf("error joining %s to %s\n%s", user.Name, worldname, err.Error())
  312. return ctx.String(501, "join failed")
  313. }
  314. log.Println("join of", user.Name, "to", worldname, "complete")
  315. return ctx.Redirect(302, "/world")
  316. }})
  317. return endpoints
  318. }
  319. //RenderHandler renders the endpoints that will be served via websocket
  320. func (bg *BingoGame) RenderHandler() []glwss.Handler {
  321. handler := []glwss.Handler{}
  322. handler = append(handler, glwss.Handler{MType: "echo", Callback: func(msg glwss.WSMsg, user gamelangpb.User) (glwss.WSMsg, error) {
  323. log.Printf("echo from \"%v\" with \"%s\"", user, msg.Payload)
  324. remsg := glwss.WSMsg{Mtype: "echo", Payload: msg.Payload}
  325. return remsg, nil
  326. }})
  327. handler = append(handler, glwss.Handler{MType: "world:create", Callback: func(msg glwss.WSMsg, user gamelangpb.User) (glwss.WSMsg, error) {
  328. createWorld := gamelangpb.World{Name: msg.Payload}
  329. lobbygame := CraftLobbygame(fmt.Sprintf("%s\uffff%s", createWorld.GetName(), "lobby"))
  330. createWorld.Games = []string{lobbygame.Name}
  331. id := rand.Uint32()
  332. createWorld.Id = id
  333. _, err := bg.wm.Create(*&createWorld)
  334. if err != nil {
  335. remsg := glwss.WSMsg{Mtype: "world:create", Payload: "failed"}
  336. return remsg, err
  337. }
  338. err = bg.bingomanager.Create(lobbygame)
  339. if err != nil {
  340. remsg := glwss.WSMsg{Mtype: "world:create", Payload: "failed"}
  341. return remsg, err
  342. }
  343. log.Println("world:create created Lobbygame:\n", lobbygame)
  344. createworldJSON, _ := json.Marshal(createWorld)
  345. remsg := glwss.WSMsg{Mtype: "world:create", Payload: string(createworldJSON)}
  346. return remsg, nil
  347. }})
  348. handler = append(handler, glwss.Handler{MType: "world:remove", Callback: func(msg glwss.WSMsg, user gamelangpb.User) (glwss.WSMsg, error) {
  349. err := bg.wm.Remove(msg.Payload)
  350. if err != nil {
  351. remsg := glwss.WSMsg{Mtype: "world:remove", Payload: "failed"}
  352. return remsg, err
  353. }
  354. remsg := glwss.WSMsg{Mtype: "world:remove", Payload: "success"}
  355. return remsg, nil
  356. }})
  357. handler = append(handler, glwss.Handler{MType: "world:join", Callback: func(msg glwss.WSMsg, user gamelangpb.User) (glwss.WSMsg, error) {
  358. worldname := msg.Payload
  359. err := bg.wm.Join(worldname, &user)
  360. if err != nil {
  361. remsg := glwss.WSMsg{Mtype: "world:join", Payload: "failed"}
  362. return remsg, err
  363. }
  364. remsg := glwss.WSMsg{Mtype: "world:join", Payload: "success"}
  365. return remsg, nil
  366. }})
  367. handler = append(handler, glwss.Handler{MType: "world:list", Callback: func(msg glwss.WSMsg, user gamelangpb.User) (glwss.WSMsg, error) {
  368. log.Print("world:list")
  369. worldlist := bg.wm.List()
  370. worldlistJSON, err := json.Marshal(worldlist)
  371. if err != nil {
  372. log.Print(err.Error())
  373. msg := glwss.WSMsg{Mtype: "world:list", Payload: "failed"}
  374. return msg, err
  375. }
  376. log.Print("world:list", "sending list")
  377. remsg := glwss.WSMsg{Mtype: "world:list", Payload: string(worldlistJSON)}
  378. return remsg, nil
  379. }})
  380. handler = append(handler, glwss.Handler{MType: "game:get", Callback: func(msg glwss.WSMsg, user gamelangpb.User) (glwss.WSMsg, error) {
  381. log.Println("game:get new get request:\n\"", msg.Payload, "\"")
  382. var world gamelangpb.World
  383. worldname := msg.Payload
  384. worlds := bg.wm.List()
  385. for _, world = range worlds {
  386. if world.GetName() == worldname {
  387. log.Println("sending world\n", world)
  388. break
  389. }
  390. }
  391. log.Println("game:get got world:\n\"", world, "\"")
  392. lobbygame := glbingopb.Bingo{}
  393. commongame := glbingopb.Bingo{}
  394. usergame := glbingopb.Bingo{}
  395. for _, game := range world.GetGames() {
  396. log.Println("searching games", game)
  397. if game == fmt.Sprintf("%s\uffff%s", world.GetName(), "lobby") {
  398. log.Println("found lobbygame", game)
  399. searchGame := glbingopb.Bingo{Name: game}
  400. lobbygame = bg.bingomanager.Get(searchGame)
  401. }
  402. if game == fmt.Sprintf("%s\uffff%s", world.GetName(), "common") {
  403. log.Println("found commongame", game)
  404. searchGame := glbingopb.Bingo{Name: game}
  405. commongame = bg.bingomanager.Get(searchGame)
  406. }
  407. if user.Name == strings.Split(game, "\uffff")[1] {
  408. log.Println("found usergame", game)
  409. searchGame := glbingopb.Bingo{Name: game}
  410. usergame = bg.bingomanager.Get(searchGame)
  411. break
  412. }
  413. }
  414. returngame := glbingopb.Bingo{}
  415. if usergame.Name == fmt.Sprintf("%s\uffff%s", world.GetName(), user.Name) {
  416. log.Println("sending usergame", usergame.Name)
  417. returngame = usergame
  418. } else if commongame.Name == fmt.Sprintf("%s\uffff%s", world.GetName(), "common") {
  419. log.Println("sending commongame", commongame.Name)
  420. returngame = commongame
  421. } else if lobbygame.Name == fmt.Sprintf("%s\uffff%s", world.GetName(), "lobby") {
  422. log.Println("sending lobbygame", lobbygame.Name)
  423. returngame = lobbygame
  424. } else {
  425. // if get returned empty game
  426. returngame = CraftLobbygame(fmt.Sprintf("%s\uffff%s", world.GetName(), "lobby"))
  427. bg.bingomanager.Create(returngame)
  428. log.Print("could not find lobbygame, so created one")
  429. }
  430. gameJSON, err := json.Marshal(returngame)
  431. if err != nil {
  432. remsg := glwss.WSMsg{Mtype: "game:get", Payload: "failed"}
  433. return remsg, err
  434. }
  435. log.Println("game:get sending game:\n", string(gameJSON))
  436. remsg := glwss.WSMsg{Mtype: "game:get", Payload: string(gameJSON)}
  437. return remsg, nil
  438. }})
  439. handler = append(handler, glwss.Handler{MType: "game:start", Callback: func(msg glwss.WSMsg, user gamelangpb.User) (glwss.WSMsg, error) {
  440. log.Println("game:start new start request:\n", msg.Payload)
  441. startgame := glbingopb.Bingo{}
  442. err := json.Unmarshal([]byte(msg.Payload), &startgame)
  443. if err != nil {
  444. log.Printf("game:start - err unmarshalling startgame \"%s\"\n%s", msg, err.Error())
  445. remsg := glwss.WSMsg{Mtype: "game:start", Payload: "failed"}
  446. return remsg, err
  447. }
  448. var startworld gamelangpb.World
  449. worlds := bg.wm.List()
  450. for _, startworld = range worlds {
  451. if startworld.GetName() == strings.Split(startgame.Name, "\uffff")[0] {
  452. log.Println("sending world\n", startworld)
  453. break
  454. }
  455. }
  456. if err != nil {
  457. log.Printf("game:start - err unmarshalling startworld \"%s\"\n%s", msg, err.Error())
  458. remsg := glwss.WSMsg{Mtype: "game:start", Payload: "failed"}
  459. return remsg, err
  460. }
  461. // start game
  462. for _, option := range startgame.Options {
  463. if option.Key == "common game" && option.Bool {
  464. newGame := bg.bingomanager.CraftGame(rand.Uint32(), fmt.Sprintf("%s\uffffcommon", startworld.Name), startgame.Textlist, startgame.Numrows, startgame.Numcols, startgame.Options...)
  465. bg.bingomanager.Create(newGame)
  466. bg.wm.AddGame(startworld.Name, startworld.Name)
  467. jsonGame, err := json.Marshal(newGame)
  468. if err != nil {
  469. log.Printf("write: err marshalling game \"%s\"\n%s", msg, err.Error())
  470. }
  471. remsg := glwss.WSMsg{Mtype: "game:get", Payload: string(jsonGame)}
  472. if err != nil {
  473. log.Printf("write: err marshalling msg \"%s\"\n%s", msg, err.Error())
  474. }
  475. for _, user := range startworld.Users {
  476. go bg.wssserver.Write(user.Name, remsg)
  477. }
  478. }
  479. }
  480. remsg := glwss.WSMsg{Mtype: "game:start", Payload: "sucess"}
  481. return remsg, nil
  482. }})
  483. handler = append(handler, glwss.Handler{MType: "game:mod", Callback: func(msg glwss.WSMsg, user gamelangpb.User) (glwss.WSMsg, error) {
  484. modgame := &glbingopb.Bingo{}
  485. err := json.Unmarshal([]byte(msg.Payload), modgame)
  486. if err != nil {
  487. log.Printf("game:mod - err unmarshalling msg \"%s\"\n%s", msg, err.Error())
  488. remsg := glwss.WSMsg{Mtype: "game:mod", Payload: "failed"}
  489. return remsg, nil
  490. }
  491. bg.bingomanager.Modify(*modgame)
  492. var world gamelangpb.World
  493. worlds := bg.wm.List()
  494. for _, world = range worlds {
  495. if world.GetName() == strings.Split(modgame.Name, "\uffff")[0] {
  496. log.Println("sending world\n", world)
  497. break
  498. }
  499. }
  500. if err != nil {
  501. log.Printf("game:mod - err getting world msg \"%s\"\n%s", msg, err.Error())
  502. remsg := glwss.WSMsg{Mtype: "game:mod", Payload: "failed"}
  503. return remsg, nil
  504. }
  505. notify := glwss.WSMsg{Mtype: "game:get", Payload: msg.Payload}
  506. for _, user := range world.Users {
  507. go bg.wssserver.Write(user.Name, notify)
  508. }
  509. bg.bingomanager.CheckWin()
  510. remsg := glwss.WSMsg{Mtype: "game:mod", Payload: "success"}
  511. return remsg, nil
  512. }})
  513. handler = append(handler, glwss.Handler{MType: "game:event", Callback: func(msg glwss.WSMsg, user gamelangpb.User) (glwss.WSMsg, error) {
  514. newevent := &glbingopb.Event{}
  515. err := json.Unmarshal([]byte(msg.Payload), newevent)
  516. if err != nil {
  517. log.Printf("game:event - err unmarshalling msg \"%s\"\n%s", msg, err.Error())
  518. remsg := glwss.WSMsg{Mtype: "game:event", Payload: "failed"}
  519. return remsg, nil
  520. }
  521. newevent.Username = user.Name
  522. log.Println("game:event new event", newevent)
  523. worldgamename := strings.Split(newevent.Gamename, "\uffff")
  524. worldname := worldgamename[0]
  525. gamename := worldgamename[1]
  526. // if the game is not a common game add all games from that world to neighborgames
  527. if gamename != "common" {
  528. var world gamelangpb.World
  529. worlds := bg.wm.List()
  530. for _, world = range worlds {
  531. if world.GetName() == worldname {
  532. log.Println("sending world\n", world)
  533. break
  534. }
  535. }
  536. if err != nil {
  537. log.Printf("workNotifications - err getting world msg \"%s\"\n%s", worldname, err.Error())
  538. remsg := glwss.WSMsg{Mtype: "game:mod", Payload: "failed"}
  539. return remsg, nil
  540. }
  541. for _, game := range world.Games {
  542. if strings.Split(game, "\uffff")[1] != "lobby" {
  543. newevent.Neighborgames = append(newevent.Neighborgames, game)
  544. }
  545. }
  546. }
  547. err = bg.bingomanager.HandleEvent(*newevent)
  548. if err != nil {
  549. if err.Error() == "game finished" {
  550. reevent := glbingopb.Event{Type: "Win", Gamename: newevent.Gamename}
  551. eventJson, err := json.Marshal(reevent)
  552. if err != nil {
  553. log.Printf("workNotifications - err marshalling event \"%s\"\n%s", reevent, err.Error())
  554. }
  555. notify := glwss.WSMsg{Mtype: "game:event", Payload: string(eventJson)}
  556. return notify, nil
  557. }
  558. return glwss.WSMsg{Mtype: "game:event", Payload: "failed"}, err
  559. }
  560. remsg := glwss.WSMsg{Mtype: "game:event", Payload: "success"}
  561. bg.bingomanager.CheckWin()
  562. return remsg, nil
  563. }})
  564. return handler
  565. }
  566. func CraftLobbygame(name string) glbingopb.Bingo {
  567. lobbygame := glbingopb.Bingo{Name: name}
  568. lobbygame.Options = append(lobbygame.Options, &glbingopb.Option{Key: "unique fields", Bool: true, Type: 1})
  569. lobbygame.Options = append(lobbygame.Options, &glbingopb.Option{Key: "common game", Bool: true, Type: 1})
  570. lobbygame.Numcols = 5
  571. lobbygame.Numrows = 5
  572. lobbygame.Textlist = []string{"word"}
  573. return lobbygame
  574. }
  575. func main() {
  576. var config BingoConfig
  577. err := gcfg.ReadFileInto(&config, "config")
  578. if err != nil {
  579. if strings.Count(err.Error(), "no such file or directory") > 0 {
  580. config = getDefaultConfig()
  581. } else {
  582. log.Fatal(err)
  583. }
  584. }
  585. log.Print("config read")
  586. log.Printf("%+v", config)
  587. bingogame := BingoGame{}
  588. bingogame.Init(config)
  589. bingogame.webserver.InitEndpoints(bingogame.RenderEndpoints())
  590. go bingogame.webserver.Run()
  591. bingogame.wssserver = glwss.NewWSServer([]string{}, nil)
  592. handler := bingogame.RenderHandler()
  593. keys := ""
  594. for _, k := range handler {
  595. keys = fmt.Sprintf("%s\n%v", keys, k)
  596. }
  597. log.Println("available MTypes:\n", keys, "\n----")
  598. bingogame.wssserver.RegisterHandler(handler)
  599. http.HandleFunc("/ws", bingogame.wssserver.WebsocketHandler)
  600. log.Println("websocket listening on", fmt.Sprintf("%s:%s", config.WS.ListenIP, config.WS.ListenPort))
  601. log.Print(http.ListenAndServe(fmt.Sprintf("%s:%s", config.WS.ListenIP, config.WS.ListenPort), nil).Error())
  602. }