← Back to portfolio Project Case Study

Riftsync - Cloud Settings Sync App for League of Legends

Electron app that syncs League of Legends settings across accounts using AWS API Gateway, Lambda, S3, and Riot’s LCU API.

Role
Frontend · Electron · AWS · API Integration
Tech
Electron, React, Node.js, AWS Lambda, S3, Riot LCU API
Focus
Settings automation, cloud sync, Riot client integration
Riftsync UI

1. Overview

League stores settings in PersistedSettings.json on the local pc when an account logs into the league client. Riftsync makes it easier to keep the same settings across PCs and accounts.

Goal diagram
Riftsync syncs settings between PCs and accounts via AWS.

2. System Design

On launch, Riftsync:

  • Reads the Riot lockfile to authenticate into LCU API
  • Identifies the correct settings path for the logged-in account
  • Pushes or pulls the JSON file via AWS API Gateway, Lambda, and S3

3. Push Request Flow

Push flow diagram
Push: Upload local settings to S3.
  • Initiated when the user clicks the Push Settings button.
  • 1. The Riftsync client sends a request to the League client API to get the Riot ID for the currently logged-in account.
  • 2. The League client API responds to the Riftsync client with the Riot ID.
  • 3. The Riftsync client retrieves PersistedSettings.json from the local file system.
  • 4. The Riftsync client sends a POST request with the settings to AWS API Gateway.
  • 5. API Gateway invokes a push Lambda function.
  • 6. The Lambda function writes the settings file to S3 using an object key that corresponds to the user’s Riot ID.
  • 7. S3 responds to the Lambda function indicating that the upload was successful.
  • 8. The Lambda function returns a success response to API Gateway.
  • 9. API Gateway responds to the Riftsync client, and the app displays to the user that the push completed successfully.

3.1 Lambda Push Function

Here are the contents of the Lambda push function that creates an S3 object containing the settings JSON.

Python – Push settings to S3
import json
import os
import boto3
import requests
import urllib.parse
from get_puuid import get_puuid

def lambda_handler(event, context):
    bucket_name = 'riftsync-settings-bucket'
    body_json = event.get('body')
    if body_json:
        try:
            body = json.loads(body_json)
        except Exception:
            body = {}
    else:
        body = {}

    gameName = body.get('gameName')
    tagLine = body.get('tagLine')
    settings_content = body.get('settings_content')

    # Validate required fields
    if not gameName or not tagLine or not settings_content:
        return {
            'statusCode': 400,
            'body': json.dumps('Error: gameName, tagLine, and settings_content are required.')
        }

    # Get PUUID using helper function
    try:
        puuid = get_puuid(gameName, tagLine)
    except Exception as e:
        return {
            'statusCode': 400,
            'body': json.dumps(f"Error fetching PUUID from Riot API: {str(e)}")
        }

    # Create S3 client and store settings
    s3 = boto3.client('s3')
    print(f"PUUID: {puuid} gameName: {gameName} tagLine: {tagLine}")

    try:
        s3.put_object(
            Bucket=bucket_name,
            Key=puuid,
            Body=settings_content
        )
        return {
            'statusCode': 200,
            'body': json.dumps('Object created successfully')
        }
    except Exception as e:
        return {
            'statusCode': 500,
            'body': json.dumps(f'Error: {str(e)}')
        }

4. Pull Request Flow

Pull flow diagram
Pull: Download settings from S3 to local storage.
  • Initiated when the user enters a valid Riot ID into the Pull Settings text box and clicks the pull button.
  • 1. The Riftsync client sends a request to the League client API to confirm that a user is currently logged in.
  • 2. The League client API responds to the Riftsync client indicating whether a user is logged in. If there is no logged-in user, the flow stops here.
  • 3. If a user is logged in, the Riftsync client sends a GET request to AWS API Gateway, including the Riot ID the user entered.
  • 4. API Gateway invokes a pull Lambda function.
  • 5. The Lambda function reads the settings file from S3 corresponding to the specified Riot ID.
  • 6. S3 responds to the Lambda function with the settings file.
  • 7. The Lambda function returns the settings JSON to API Gateway.
  • 8. API Gateway responds to the Riftsync client with the settings payload.
  • 9. The Riftsync client writes the downloaded JSON to the local PersistedSettings.json, updating the local settings.

4.1 Lambda Pull Function

Here are the contents of the Lambda pull function that retrieves the settings JSON from S3.

Python – Pull settings from S3
import json
import os
import boto3
import requests
import urllib.parse
from get_puuid import get_puuid

def lambda_handler(event, context):
    bucket_name = 'riftsync-settings-bucket'
    params = event.get('queryStringParameters') or {}
    gameName = params.get('gameName')
    tagLine = params.get('tagLine')

    # Validate required fields
    if not gameName or not tagLine:
        return {
            'statusCode': 400,
            'body': json.dumps('Error: gameName, and tagLine are required.')
        }
    
    # Get PUUID using helper function
    try:
        puuid = get_puuid(gameName, tagLine)
    except Exception as e:
        return {
            'statusCode': 400,
            'body': json.dumps(f"Error fetching PUUID from Riot API: {str(e)}")
        }

    # Create S3 client and pull settings
    s3 = boto3.client('s3')
    print(f"PUUID: {puuid} gameName: {gameName} tagLine: {tagLine}")

    try:
        response = s3.get_object(Bucket=bucket_name, Key=puuid)
        contents = response['Body'].read().decode('utf-8')
        return {
            'statusCode': 200,
            'body': contents  # No json.dumps() here!
        }
    except Exception as e:
        return {
            'statusCode': 500,
            'body': json.dumps({'error': str(e)})
        }

5. Demo

Push & Pull actions shown in the app.

6. Takeaways & Future Work

What I gained from this project:

  • Practical experience wiring together AWS API Gateway, Lambda, and S3 to push and pull user settings in a real application.
  • Hands-on familiarity with the Lambda development workflow. This includes iterating on code locally, packing dependencies, and deploying updates to Lambda.

Future improvements I’d like to explore:

  • Integrating Riot’s OAuth2 flow so that only the authenticated owner of an account can read or write the S3 object associated with that account’s settings.
  • Adding proper code signing (e.g., a trusted code-signing certificate and signed installer) so Windows Defender / SmartScreen treats the app as a trusted application instead of warning users on first run.
  • Packaging and distributing Riftsync through a public website with a simple download page so other players can easily install and update the app.