From e425ada97e9faf1d68f76fce3ae18d645901dc4e Mon Sep 17 00:00:00 2001 From: Mitchell Gerber Date: Wed, 2 Aug 2017 23:26:39 -0500 Subject: [PATCH 1/2] wip ui for pubg --- client/app/pages/Pubg/Pubg.scss | 19 ++++++ client/app/pages/Pubg/Pubg.tsx | 102 +++++++++++++++++++++++++++++++- client/package.json | 2 + client/yarn.lock | 6 +- config.template.json | 7 ++- main.go | 6 +- server/bot/bot.go | 26 ++++---- server/config/config.go | 5 ++ server/webserver/pubg/pubg.go | 54 +++++++++++++++++ server/webserver/server.go | 8 +++ 10 files changed, 216 insertions(+), 19 deletions(-) create mode 100644 client/app/pages/Pubg/Pubg.scss create mode 100644 server/webserver/pubg/pubg.go diff --git a/client/app/pages/Pubg/Pubg.scss b/client/app/pages/Pubg/Pubg.scss new file mode 100644 index 0000000..c24d1b1 --- /dev/null +++ b/client/app/pages/Pubg/Pubg.scss @@ -0,0 +1,19 @@ +@import "../../scss/variables"; + +.pubg__container { + padding: 10px; +} + +.pubg__table { + border-collapse: collapse; + width: 100%; + text-align: left; + + tr { + border-top: 1px solid $gray3; + } + + td, th { + padding: 5px; + } +} diff --git a/client/app/pages/Pubg/Pubg.tsx b/client/app/pages/Pubg/Pubg.tsx index b6fae2b..3347966 100644 --- a/client/app/pages/Pubg/Pubg.tsx +++ b/client/app/pages/Pubg/Pubg.tsx @@ -1,10 +1,108 @@ import React from 'react'; +import axios from 'axios'; +import * as _ from 'lodash'; +import './Pubg.scss'; -export class Pubg extends React.Component { +interface Props { + +} + +interface State { + players: Player[]; +} + +interface Player { + PlayerName: string; + agg?: any; + as?: any; + na?: any; + sa?: any; +} + +export class Pubg extends React.Component { + + constructor() { + super(); + this.state = { + players: [], + }; + } + + componentDidMount() { + axios.get("/stats/pubg").then((res) => { + + console.log(res.data); + this.setState({ + players: this.filterData(res.data), + }); + + console.log(this.state.players); + }); + } + + filterData(data: any): Player[] { + return _.map(_.values(data), (data: any) => { + + let regions: any = _.chain(data.Stats).groupBy('Region') + /* + .mapValues((val: any) => { + return _.groupBy(val, 'Match'); + }) + */ + .value(); + + + _.forIn(regions, (val: any, key: string) => { + regions[key] = _.groupBy(val, 'Match'); + + _.forIn(regions[key], (val2: any, key2: string) => { + //regions[key][key2] = _.groupBy(regions[key][key2][0].Stats, 'field'); + regions[key][key2] = _.groupBy(_.flatten(regions[key][key2][0].Stats), 'field'); + _.each(regions[key][key2], s => s = _.flatten(s)); + + //console.log(regions[key][key2][0]); + + }); + }); + + //console.log(regions); + + return { + ...{ PlayerName: data.PlayerName }, + ...regions, + }; + }); + } + + insertTableData() { + + return this.state.players.map((stat: any, index: number) => { + return ( + + {stat.PlayerName} + + ); + }); + } render() { return ( -
test 123
+
+
+
PUBG Stats
+ + + + + + + + {this.insertTableData()} + +
Name
+ +
+
); } } diff --git a/client/package.json b/client/package.json index fece963..7e2fdab 100644 --- a/client/package.json +++ b/client/package.json @@ -10,6 +10,7 @@ "author": "Mitchell Gerber", "license": "MIT", "devDependencies": { + "@types/lodash": "^4.14.71", "@types/react": "^16.0.0", "@types/react-dom": "^15.5.1", "@types/react-dropzone": "^3.13.1", @@ -29,6 +30,7 @@ "extract-text-webpack-plugin": "2.0.0-rc.1", "file-loader": "^0.10.0", "html-webpack-plugin": "^2.24.1", + "lodash": "^4.17.4", "node-sass": "^4.5.3", "postcss-loader": "^1.2.1", "react": "15.6.1", diff --git a/client/yarn.lock b/client/yarn.lock index b99317c..6b53943 100644 --- a/client/yarn.lock +++ b/client/yarn.lock @@ -6,6 +6,10 @@ version "3.2.1" resolved "https://registry.yarnpkg.com/@types/history/-/history-3.2.1.tgz#0039ab0e0be2a0cc22bac171d27a44588103d123" +"@types/lodash@^4.14.71": + version "4.14.71" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.71.tgz#0dc383f78981216ac76e2f2c3afd998e0450e4c1" + "@types/react-dom@^15.5.1": version "15.5.1" resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-15.5.1.tgz#f3c3e14c682785923c7d64583537df319442dec1" @@ -2955,7 +2959,7 @@ lodash.uniq@^4.3.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" -lodash@^4.0.0, lodash@^4.14.0, lodash@^4.17.2, lodash@^4.17.3, lodash@^4.2.0, lodash@^4.3.0: +lodash@^4.0.0, lodash@^4.14.0, lodash@^4.17.2, lodash@^4.17.3, lodash@^4.17.4, lodash@^4.2.0, lodash@^4.3.0: version "4.17.4" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" diff --git a/config.template.json b/config.template.json index 9c5d374..7daa397 100644 --- a/config.template.json +++ b/config.template.json @@ -3,5 +3,10 @@ "BotPrefix": "#", "SoundsPath": "./sounds/", "UploadPassword": "", - "ServerAddr": ":80" + "ServerAddr": ":80", + "pubg": { + "apiKey": "", + "enabled": true, + "players": ["player1"] + } } diff --git a/main.go b/main.go index 420a04a..4fa1d76 100644 --- a/main.go +++ b/main.go @@ -16,11 +16,9 @@ func main() { //add handlers bot.AddHandler(bothandlers.SoundsHandler) - // remove gif functionality for not - //bot.AddHandler(bothandlers.GifHandler) - // start new go routine for the discord websockets - go bot.Start() + // start the bot + bot.Start() // start the web server webserver.Start() diff --git a/server/bot/bot.go b/server/bot/bot.go index 6c85709..5da0675 100644 --- a/server/bot/bot.go +++ b/server/bot/bot.go @@ -39,18 +39,22 @@ func Connect(token string) { // Start - blocking function that starts a websocket listenting for discord callbacks func Start() { - // Open the websocket and begin listening. - err := Session.Open() - if err != nil { - fmt.Println("error opening connection,", err) + + // start new non blocking go routine + go func() { + // Open the websocket and begin listening. + err := Session.Open() + if err != nil { + fmt.Println("error opening connection,", err) + return + } + + fmt.Println("Bot is now running...") + + // Simple way to keep program running until CTRL-C is pressed. + <-make(chan struct{}) return - } - - fmt.Println("Bot is now running...") - - // Simple way to keep program running until CTRL-C is pressed. - <-make(chan struct{}) - return + }() } func AddHandler(handler interface{}) { diff --git a/server/config/config.go b/server/config/config.go index c291484..5a1169c 100644 --- a/server/config/config.go +++ b/server/config/config.go @@ -20,6 +20,11 @@ type configFile struct { SoundsPath string `json:"SoundsPath"` UploadPassword string `json:"UploadPassword"` ServerAddr string `json:"ServerAddr` + Pubg struct { + Enabled bool `json:"enabled"` + APIKey string `json:"apiKey"` + Players []string `json:"players"` + } `json:"pubg"` } type configFlags struct { diff --git a/server/webserver/pubg/pubg.go b/server/webserver/pubg/pubg.go new file mode 100644 index 0000000..5574dfc --- /dev/null +++ b/server/webserver/pubg/pubg.go @@ -0,0 +1,54 @@ +package pubg + +import ( + "log" + "net/http" + "sync" + "time" + + "github.com/mgerb/chi_auth_server/response" + pubgClient "github.com/mgerb/go-pubg" +) + +var ( + apiKey string + stats = map[string]*pubgClient.Player{} + mut = &sync.Mutex{} +) + +// Start - +func Start(key string, players []string) { + + apiKey = key + + log.Println("Gathering pubg data...") + + go fetchStats(players) +} + +func fetchStats(players []string) { + + api := pubgClient.New(apiKey) + + // fetch new stats every 30 seconds + for { + + for _, player := range players { + newStats := api.GetPlayer(player) + + mut.Lock() + stats[player] = newStats + mut.Unlock() + + time.Sleep(time.Second * 2) + } + + time.Sleep(time.Second * 30) + } + +} + +// Handler - returns the pubg stats +func Handler(w http.ResponseWriter, r *http.Request) { + response.JSON(w, stats) +} diff --git a/server/webserver/server.go b/server/webserver/server.go index 0b34ee1..f34e566 100644 --- a/server/webserver/server.go +++ b/server/webserver/server.go @@ -13,6 +13,7 @@ import ( "github.com/go-chi/chi/middleware" "github.com/mgerb/go-discord-bot/server/config" "github.com/mgerb/go-discord-bot/server/webserver/handlers" + "github.com/mgerb/go-discord-bot/server/webserver/pubg" ) func getRouter() *chi.Mux { @@ -40,12 +41,19 @@ func getRouter() *chi.Mux { r.Get("/soundlist", handlers.SoundList) r.Put("/upload", handlers.FileUpload) r.Get("/ytdownloader", handlers.Downloader) + r.Get("/stats/pubg", pubg.Handler) return r } // Start - func Start() { + + // start gathering pubg data from the api + if config.Config.Pubg.Enabled { + pubg.Start(config.Config.Pubg.APIKey, config.Config.Pubg.Players) + } + router := getRouter() if config.Flags.TLS { From 5112bac349e975a7c69a98994582e4dce515e690 Mon Sep 17 00:00:00 2001 From: Mitchell Gerber Date: Thu, 3 Aug 2017 22:49:31 -0500 Subject: [PATCH 2/2] finished ui for pubg --- .gitignore | 1 + client/.eslintrc.js | 45 ------------ client/.jsbeautifyrc | 15 ---- client/app/pages/Pubg/Pubg.scss | 15 +++- client/app/pages/Pubg/Pubg.tsx | 123 +++++++++++++++++++++----------- 5 files changed, 95 insertions(+), 104 deletions(-) delete mode 100644 client/.eslintrc.js delete mode 100644 client/.jsbeautifyrc diff --git a/.gitignore b/.gitignore index 1f1f18e..07f7dd0 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ bot sounds debug youtube +go-discord-bot diff --git a/client/.eslintrc.js b/client/.eslintrc.js deleted file mode 100644 index 15cd681..0000000 --- a/client/.eslintrc.js +++ /dev/null @@ -1,45 +0,0 @@ -module.exports = { - "env": { - "browser": true, - "commonjs": true, - "es6": true, - "node": true - }, - "extends": "eslint:recommended", - "installedESLint": true, - "parserOptions": { - "ecmaFeatures": { - "experimentalObjectRestSpread": true, - "jsx": true - }, - "sourceType": "module" - }, - "plugins": [ - "react" - ], - "rules": { - "indent": [ - "error", - 4 - ], - "semi": [ - "error", - "always" - ], - - "react/display-name": 0, // Prevent missing displayName in a React component definition - "react/jsx-no-undef": 2, // Disallow undeclared variables in JSX - "react/jsx-sort-props": 0, // Enforce props alphabetical sorting - "react/jsx-uses-react": 2, // Prevent React to be incorrectly marked as unused - "react/jsx-uses-vars": 2, // Prevent variables used in JSX to be incorrectly marked as unused - "react/no-did-mount-set-state": 2, // Prevent usage of setState in componentDidMount - "react/no-did-update-set-state": 2, // Prevent usage of setState in componentDidUpdate - "react/no-multi-comp": 0, // Prevent multiple component definition per file - "react/no-unknown-property": 2, // Prevent usage of unknown DOM property - "react/prop-types": 2, // Prevent missing props validation in a React component definition - "react/react-in-jsx-scope": 2, // Prevent missing React when using JSX - "react/self-closing-comp": 2, // Prevent extra closing tags for components without children - "react/wrap-multilines": 2 // Prevent missing parentheses around multilines JSX - } - -}; \ No newline at end of file diff --git a/client/.jsbeautifyrc b/client/.jsbeautifyrc deleted file mode 100644 index c35339e..0000000 --- a/client/.jsbeautifyrc +++ /dev/null @@ -1,15 +0,0 @@ -{ - "indent_size": 4, - "beautify.language": { - "js": { - "type": ["javascript", "json", "jsx"], - "filename": [".jshintrc", ".jsbeautify"], - "e4x": true - // "ext": ["js", "json"] - // ^^ to set extensions to be beautified using the javascript beautifier - }, - "css": ["css", "scss"], - "html": ["htm", "html"] - // ^^ providing just an array sets the VS Code file type - } -} \ No newline at end of file diff --git a/client/app/pages/Pubg/Pubg.scss b/client/app/pages/Pubg/Pubg.scss index c24d1b1..275c12b 100644 --- a/client/app/pages/Pubg/Pubg.scss +++ b/client/app/pages/Pubg/Pubg.scss @@ -8,8 +8,9 @@ border-collapse: collapse; width: 100%; text-align: left; + margin-top: 20px; - tr { + tr + tr { border-top: 1px solid $gray3; } @@ -17,3 +18,15 @@ padding: 5px; } } + +.pubg__button-row { + margin-bottom: 10px; + + .button { + min-width: 100px; + + & + .button { + margin-left: 5px; + } + } +} diff --git a/client/app/pages/Pubg/Pubg.tsx b/client/app/pages/Pubg/Pubg.tsx index 3347966..1bfee08 100644 --- a/client/app/pages/Pubg/Pubg.tsx +++ b/client/app/pages/Pubg/Pubg.tsx @@ -9,6 +9,9 @@ interface Props { interface State { players: Player[]; + selectedRegion: string; + selectedMatch: string; + statList: string[]; } interface Player { @@ -25,79 +28,113 @@ export class Pubg extends React.Component { super(); this.state = { players: [], + selectedRegion: 'agg', + selectedMatch: 'squad', + statList: [], }; } componentDidMount() { axios.get("/stats/pubg").then((res) => { - console.log(res.data); this.setState({ - players: this.filterData(res.data), + players: _.map(res.data) as any, }); - console.log(this.state.players); + this.setStatList(); }); } - filterData(data: any): Player[] { - return _.map(_.values(data), (data: any) => { + // get stat list + setStatList() { + + // hacky way to find existing content -- to tired to make it pretty + let i = 0; + let stats; + while (!stats) { + if (i > this.state.players.length) { + return; + } - let regions: any = _.chain(data.Stats).groupBy('Region') - /* - .mapValues((val: any) => { - return _.groupBy(val, 'Match'); - }) - */ - .value(); + stats = _.find(_.get(this.state, `players[${i}].Stats`), (s: any) => s.Match === this.state.selectedMatch.toLowerCase()); + i++; + } - - _.forIn(regions, (val: any, key: string) => { - regions[key] = _.groupBy(val, 'Match'); - - _.forIn(regions[key], (val2: any, key2: string) => { - //regions[key][key2] = _.groupBy(regions[key][key2][0].Stats, 'field'); - regions[key][key2] = _.groupBy(_.flatten(regions[key][key2][0].Stats), 'field'); - _.each(regions[key][key2], s => s = _.flatten(s)); - - //console.log(regions[key][key2][0]); - - }); + if (stats) { + this.setState({ + statList: _.sortBy(_.map(stats.Stats, 'field')) as any, }); - - //console.log(regions); - - return { - ...{ PlayerName: data.PlayerName }, - ...regions, - }; - }); + } } - insertTableData() { - - return this.state.players.map((stat: any, index: number) => { + insertRows(): any { + return this.state.statList.map((val: any, index: any) => { return ( - {stat.PlayerName} + {val} + {this.state.players.map((player: any, i: number) => { + // find player stats for field + let playerStat = _.find(player.Stats, (p: any) => { + return p.Match === this.state.selectedMatch.toLowerCase() && p.Region === this.state.selectedRegion.toLowerCase(); + }); + + return {_.get(_.find(_.get(playerStat, 'Stats'), (p: any) => p.field === val), 'displayValue')} + })} ); }); } + buttonRegion(title: string) { + let lowerTitle = title === 'All' ? 'agg' : title.toLowerCase() + return ( + + ); + } + + buttonMatch(title: string) { + let lowerTitle = title.toLowerCase() + return ( + + ); + } + render() { return (
-
+
PUBG Stats
+ +
+ {this.buttonMatch('Solo')} + {this.buttonMatch('Duo')} + {this.buttonMatch('Squad')} +
+ +
+ {this.buttonRegion('All')} + {this.buttonRegion('Na')} + {this.buttonRegion('As')} + {this.buttonRegion('Au')} +
+ - - - - - - {this.insertTableData()} + + + {this.state.players.map((val: any, index: number) => { + return ; + })} + + {this.insertRows()}
Name
{val.PlayerName}