Player 2
Ahnaf An Nafee / December 01, 2022
react-native
react
expo
next.js
typescript
aws
java
spring-boot
postgresql
android
ios
π΄π΅ Player 2 - The Gamer's Companion
Overview
Player 2 is designed to be the foremost gamer networking app and website for players across PC, console, and mobile platforms. Whether a gamer needs teammates to complete an immediate activity, wants to make new friends to game with, or would like to join or start a gaming community, the app is designed to help gamers find the community where they play best, no matter who they are. Player 2 offers a comprehensive solution for a gamerβs social networking and team-building needs with our proprietary compatibility matchmaking algorithm. Our platform also includes features to make new friends to play games with and join or start a gaming community.
Responsibilities
- Create and Implement 6 new DevOps pipelines to deliver fast OTA application updates, backend build status, and Infrastructure as Code
- Spearhead backend migration to Amazon Elastic Beanstalk for auto-scaling server instances, reducing application load and costs by 80%
- Automate the build and deployment process with GitHub Actions and Maven and use Serverless Lambda functions for monitoring, eliminating 85% of manual work
- Manage 100% of existing AWS Cloud environments, automation, monitoring metrics, disaster recovery/backups, and capacity planning
- Develop a custom API layer to handle all CRUD transactions, and JWT token management and implemented interceptors to embed custom headers
- Translate designs & wireframes into high-quality code and developed responsive, reusable, universal components following React workflows
- Engineer Java service integration for STOMP WebSockets for in-app chat functionality
- Chart and Integrate Third-Party services and OAuth services with 20+ RESTful endpoints to create a scalable, user-facing application and increase user engagement
- Reduced performance bottlenecks in the custom chat service using Redux state management by 80%, making the user experience lag-free
- Designed and integrated APIs that processed match data to power matchmaking recommendations for thousands of users
- Collaborated in weekly meetings with stakeholders and the project team to ensure streamlined communication
Blog Links
Code Snippets
Auth Provider that auto refreshes auth tokens when they expire
const dispatch = useAppDispatch()
const { authState } = useAppSelector((state) => state.auth)
// States
const [loaded, setLoaded] = useState(false)
// for multiple requests
let isRefreshing = false
let failedQueue: any[] = []
const refreshTokenFunc: any = null
const processQueue = async (error: any, token = null) => {
console.log('processQueue')
failedQueue.forEach((prom) => {
if (error) {
prom.reject(error)
} else {
prom.resolve(token)
}
})
failedQueue = []
}
const logout = async () => {
console.log('Logout called!')
dispatch(authActions.resetAuthState())
dispatch(authThunks.signOut({}))
dispatch(authActions.resetState())
dispatch({ type: 'LOGOUT', payload: undefined })
}
const loadJWT = useCallback(async () => {
const jwt = await getJWTTokens()
jwt && dispatch(authActions.setAuthState(jwt))
setLoaded(true)
}, [])
useEffect(() => {
if (!loaded) {
loadJWT()
}
}, [loaded])
axios.interceptors.request.use(
async (config) => {
if (authState.authorizationToken && !config.headers!.Authorization) {
/*
* Does not add Bearer Token to auth URLs
*/
if (!whitelistedPaths.some((path) => config.url?.includes(path))) {
config.headers!.Authorization = 'Bearer ' + authState.authorizationToken
}
}
return config
},
async (error) => {
return Promise.reject(error)
}
)
axios.interceptors.response.use(
async (response) => {
return response
},
async (error) => {
const originalRequest = error.config
if (error.response.status === 401 && !originalRequest._retry) {
console.log('Failed Request', originalRequest)
if (isRefreshing) {
return new Promise((resolve, reject) => {
if (typeof originalRequest.url === 'string' && originalRequest.url.includes('players/refresh')) {
console.log('players/refresh fail')
logout()
}
failedQueue.push({ resolve, reject })
})
.then((token) => {
originalRequest.headers['Authorization'] = 'Bearer ' + token
return axios(originalRequest)
})
.catch((err) => {
return Promise.reject(err)
})
}
originalRequest._retry = true
isRefreshing = true
const jwt = await getJWTTokens()
if (jwt !== null) {
return new Promise((resolve, reject) => {
axios
.post<UserTokens>(`${config.api.baseUrl}/players/refresh`, {
tokens: { refreshToken: jwt?.refreshToken }
})
.then(async ({ data }) => {
dispatch(authActions.setAuthState(data))
originalRequest.headers['Authorization'] = 'Bearer ' + data.authorizationToken
processQueue(null, data.authorizationToken as any)
resolve(axios(originalRequest))
})
.catch((err) => {
logout()
processQueue(err, null)
reject(err)
})
.finally(() => {
isRefreshing = false
})
})
}
return Promise.reject(new Error('No token found'))
}
return Promise.reject(error)
}
)
Screenshots