# Accounts v1

## Design Principles

* Decoupled, resilient behavior
    * If **_Accounts_ **goes down, the rest of Bigscreen singleplayer and multiplayer should continue to work
* Backup
    * Permanent data should be on a Redis instance that is frequently snapshotted to local disk and archived to s3 (or similar permanent reliable datastore)

## Anti-Principles

* Unnecessary features
    * Email, Username, password
    * Oculus, Steam account integration and single-sign on
    * Account recovery (new PC)
* Scalability
    * Today, we peak at a couple hundred concurrents. In one year, we may peak at a few thousand concurrents. Don't worry about scalable design now. Shortcuts and lazy coding are acceptable.

## Cross-Platform

localStorage and state between Steam and Oculus Home versions share the same underlying Chrome instances. This allows for seamless and intelligent cross-platform behavior. If you store Steam and Oculus IDs on the server, you'll also have account recovery on a new PC

USER connects to SIGNAL, provides a BSUID, list of FRIENDS (BSUIDs)
SIGNAL tells APP that BSUID is online, status
APP updates this user's BSUID presence (online, status, etc.)
APP looks up this user's BSUID subscribers, notifies them that this USER is online
for each BSUID in FRIENDS,
APP looks up their state, responds with friend state
APP subscribes this user's BSUID to that friend BSUID to receive future state updates

## Online Users Set (GEN)

`“online"`

`smembers “online”`
returns all BSUIDs that are online

when user `“asdfasdf”` disconnects from server,  `“sremove asdfasdf”` set

## Online Friends Set (GEN)

`“online-” + bsuid`
contains all bsuids of friends that are online

anytime user “asdfasdf” changes, publish changes to every bsuid in “online-asdfasdf”

## Invited Set (PERM)

`“invited-” + bsuid`
contains all bsuids that you want to be friends with

## Invites Set (PERM)

`“invites-” + bsuid`
contains all bsuids that want to be friends

## Friends Set (PERM)

`“friends-” + bsuid`
contains all bsuids of friends

## Reverse Hashes

`“oculusids”`

Key: `oculusid`
Value: `bsuid (String)`

`“steamids”`

Key: `steamid`
Value: `bsuid (String)`

## User Hash

`“user-” + bsuid`

Key: `“img”`
Value: `“url” (String)`

Key: `“state”`
Value: 0, 1 (Integer)

Key: `“steamid”`
Value: `“asdf” (String)`

Key: `“oculusid”`
Value: `“asdf” (String)`

*Future Features*

Key: `“spark”`
Value: `“jfjfjf” (String, spark)`

Key: `“server”`
Value: `“0", "s1”, “s2” (String)`

Key: `“status”`
Value: `“playing”, “in” (String)`

Key: `“detail”`
Value: `“Unity”, “Grand Theft Auto V”, “Watching Stranger Things ep3” (String)`

## Events

### user logs into the server, either with bsuid `asdfasdf`, steamid, or oculusid

- if `(steamid | oculusid)`
    - get bsuid
    - generate unique bsuid
- this user asdfasdf is online, `sadd online asdfasdf`
- generate online friends set (subscribers): `sinterstore online-asdfasdf friends-asdfasdf online`
- for each online friend, subscribe to their changes, notify them that this user is online
    - for each friend bsuid “xxxx” in online friends set: `smembers online-asdfasdf`
        - `sadd online-xxxx asdfasdf`
        - notify that friend with this user's data `{type: 'friend-online', bsuid: 'asdfasdf', img: 'url' }`
- get and send all friend data
    - for each friend bsuid “xxxx” in friends set: `smembers friends-asdfasdf`
        - `hmget user-xxxx img state`
        - `friends.push({ bsuid: xxxx, img: 'url', state: state })`
    - return `friends`
- return all pending invites
    - for each bsuid “xxxx” in invites set: `smembers invites-asdfasdf`
        - hmget user-xxxx img
- return all pending outbound invites: `smembers invited-asdfasdf`

### user `asdfasdf` disconnects from server
- not online. `srem online asdfasdf`
- unsubscribe from friends. 
    - for each online friend xxxx in `smembers online``-asdfasdf`
    - `srem online-xxxx asdfasdf`
- delete online friends set (friends subscribed to you) `del online-asdfasdf`

### user `asdfasdf` invites `xxxx` to be friends (AUTH?)
- fail if user `xxxx` doesn't exist: `exists user-xxxx`
- fail if already friends or already invited: `sismember friends-xxxx asdfasdf` `sismember invites-xxxx asdfasdf`
- else: `sadd invites-xxxx asdfasdf` `sadd invited-asdfasdf xxxx`

### user `asdfasdf` deletes invite to `xxxx` to be friends (AUTH?)
- fail if user `xxxx` doesn't exist: `exists user-xxxx`
- fail if no invite: `sismember invites-xxxx asdfasdf`
- else: `srem invites-xxxx asdfasdf` `srem invited-asdfasdf xxxx`

### user `xxxx` accepts invite from `asdfasdf` to be friends (AUTH?)
- fail if no invite: `sismember invites-xxxx asdfasdf`
- `srem invites-xxxx asdfasdf` `srem invited-asdfasdf xxxx`
- `sadd friends-asdfasdf xxxx` `sadd friends-xxxx asdfasdf`
- new friend flow
   - subscribe to updates if `asdfasdf` online. if `exist online asdfasdf`, `sadd online-asdfasdf xxxx`
   - send to `asdfasdf` `{type: 'friend-online', bsuid: 'xxxx', img: 'url' }`
   - subscribe to updates if `xxxx` online. if `exist online xxxx`, `sadd online-xxxx asdfasdf`
   - send to `xxxx` `{type: 'friend-online', bsuid: 'asdfasdf', img: 'url' }`

### user `xxxx` rejects invite from `asdfasdf` to be friends (AUTH?)
- fail if no invite: `sismember invites-xxxx asdfasdf`
- else: `srem invites-xxxx asdfasdf` `srem invited-asdfasdf xxxx`

## HTTP endpoints for App Server

POST `“inviteroom”`
bsuidFrom: `“asdfasdf”`
bsuidInvited: `“asdfasdf”`
content: `“room-id”`
server: `“s1”, “s2”`

POST `“invitefriend”`
bsuidFrom: `“asdfasdf”`
bsuidAdd: `“asdfasdf”`

POST `“deleteinvitefriend”`
bsuidFrom: `“asdfasdf”`
bsuidAdd: `“asdfasdf”`

POST `“acceptfriend”`
bsuidFrom: `“asdfasdf”`
bsuidAccepted: `“asdfasdf”`

POST `“rejectfriend”`
bsuidFrom: `“asdfasdf”`
bsuidRejected: `“asdfasdf”`

GET `“invites”`

GET `“friends”`
