Skip to content

Commit

Permalink
Added reconnect and swagger auto-patching
Browse files Browse the repository at this point in the history
  • Loading branch information
Pupix committed Jan 27, 2019
1 parent 5487369 commit d47ff55
Show file tree
Hide file tree
Showing 13 changed files with 267 additions and 118 deletions.
23 changes: 1 addition & 22 deletions README.md
Expand Up @@ -2,28 +2,7 @@

----

Always up to date documentation for the League of Legends client API.

### Post v8.14 requirements
Since League of Legends v8.14 RIOT hid some developer functionality behind a flag. To make Rift Explorer work with newer versions of the game you need to manually enable the *swagger endpoint* by hand.

To enable *swagger* you need to add the `enable_swagger: true` at the start of the `system.yaml` file before starting the LCU client.

![Swagger explainer](assets/swagger.png?raw=true)

The file can be found here based on your OS

- **Windows**

`C:\Riot Games\League of Legends\RADS\projects\league_client\releases\<LATEST_VERSION>\deploy\system.yaml`

- **MacOS**

`/Applications/League of Legends.app/Contents/LoL/RADS/projects/league_client/releases/<LATEST_VERSION>/deploy/system.yaml`

Some regions may have a different directory structure but the general gist is the same.

**This file will need to be updated everytime there's a new LCU version.**
Always up to date documentation for the League Client API.

### Prebuilt

Expand Down
82 changes: 70 additions & 12 deletions app.js
@@ -1,45 +1,103 @@
const electron = require('electron');
const LCUConnector = require('lcu-connector');
const fs = require('fs-extra');
const path = require('path');
const yaml = require('yaml');
const { getLCUPathFromProcess } = require('./util');

const connector = new LCUConnector('');
const connector = new LCUConnector();
const { app } = electron;
const { BrowserWindow } = electron;
const root = __dirname + '/app';

let mainWindow = null;

app.commandLine.appendSwitch('--ignore-certificate-errors');

app.on('ready', () => {
let mainWindow = null;
let windowLoaded = false;
let LCUData = null;
let swaggerDisabled = true;

mainWindow = new BrowserWindow({
center: true,
height: 720,
show: false,
title: 'Rift Explorer',
width: 1280
width: 1280,
title: 'Rift Explorer'
});

// Check if dev env FIXME
// mainWindow.openDevTools();

// Remove default menu
mainWindow.setMenu(null);
mainWindow.loadURL('file://' + root + '/index.html');

// Check if dev env FIXME
// mainWindow.openDevTools();

// Avoid white page on load.
mainWindow.webContents.on('did-finish-load', () => {
connector.on('connect', async (data) => {
mainWindow.webContents.send('lcu-load', data);
});
windowLoaded = true;

connector.start();
mainWindow.show();

if (!LCUData) {
return;
}

mainWindow.webContents.send(swaggerDisabled ? 'swagger-disabled' : 'swagger-enabled');
mainWindow.webContents.send('lcu-load', LCUData);
});

mainWindow.on('closed', () => {
mainWindow = null;
});

connector.on('connect', async (data) => {
// During multiple restarts of the client the backend server is not instantly
// ready to serve requests so we delay a bit
setTimeout(async () => {
LCUData = data;

try {
const LCUPath = await getLCUPathFromProcess();
const systemFile = path.join(LCUPath, 'system.yaml');

// File doesn't exist, do nothing
if (!(await fs.pathExists(systemFile))) {
throw new Error('system.yaml not found');
}

const file = await fs.readFile(systemFile, 'utf8');
const fileParsed = yaml.parse(file);

swaggerDisabled = !fileParsed.enable_swagger;
mainWindow.webContents.send(swaggerDisabled ? 'swagger-disabled' : 'swagger-enabled');

if (!fileParsed.enable_swagger) {
fileParsed.enable_swagger = true;
const stringifiedFile = yaml.stringify(fileParsed);

// Rito's file is prefixed with --- newline
await fs.outputFile(systemFile, `---\n${stringifiedFile}`);
}

} catch (error) {
console.error(error);
// No error handling for now
}

mainWindow.webContents.send('lcu-load', LCUData);
}, 5000);
});

connector.on('disconnect', () => {
LCUData = null;

if (windowLoaded) {
mainWindow.webContents.send('lcu-unload');
}
});

connector.start();
});

app.on('window-all-closed', () => {
Expand Down
12 changes: 12 additions & 0 deletions app/css/style.css
Expand Up @@ -4,6 +4,14 @@ html {
color: hsla(0, 0%, 0%, 0.87);
}

.swagger-section .logo {
width: 54px;
height: 54px;
display: block;
float: left;
margin: -6px 12px 0 0;
}

.swagger-section .github {
width: 24px;
height: 24px;
Expand Down Expand Up @@ -55,6 +63,10 @@ html {
text-shadow: rgba(0, 0, 0, 0.15) 0 0 1px;
}

.swagger-section .swagger-ui-wrap .info_title {
padding-bottom: 0;
}

@media (max-width: 960px) {
.swagger-section #swagger-ui-container {
margin: 24px auto;
Expand Down
Binary file modified app/fonts/DroidSans-Bold.ttf
Binary file not shown.
Binary file modified app/fonts/DroidSans.ttf
Binary file not shown.
Binary file added app/images/logo.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
196 changes: 126 additions & 70 deletions app/index.html
@@ -1,81 +1,137 @@

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Rift Explorer</title>
<link rel="icon" type="image/png" href="images/favicon-32x32.png" sizes="32x32" />
<link rel="icon" type="image/png" href="images/favicon-16x16.png" sizes="16x16" />
<link href='css/typography.css' media='screen' rel='stylesheet' type='text/css'/>
<link href='css/reset.css' media='screen' rel='stylesheet' type='text/css'/>
<link href='css/screen.css' media='screen' rel='stylesheet' type='text/css'/>
<link href='css/reset.css' media='print' rel='stylesheet' type='text/css'/>
<link href='css/print.css' media='print' rel='stylesheet' type='text/css'/>
<link href='css/style.css' rel='stylesheet' type='text/css'/>
<script src='lib/jquery-1.8.0.min.js' type='text/javascript'></script>
<script src='lib/jquery.slideto.min.js' type='text/javascript'></script>
<script src='lib/jquery.wiggle.min.js' type='text/javascript'></script>
<script src='lib/jquery.ba-bbq.min.js' type='text/javascript'></script>
<script src='lib/handlebars-2.0.0.js' type='text/javascript'></script>
<script src='lib/underscore-min.js' type='text/javascript'></script>
<script src='lib/backbone-min.js' type='text/javascript'></script>
<script src='swagger-ui.js' type='text/javascript'></script>
<script src='lib/highlight.7.3.pack.js' type='text/javascript'></script>
<script src='lib/jsoneditor.min.js' type='text/javascript'></script>
<script src='lib/marked.js' type='text/javascript'></script>
<script src='lib/swagger-oauth.js' type='text/javascript'></script>


<script type="text/javascript">

const IPC = require('electron').ipcRenderer;
const shell = require('electron').shell;
const REMOTE = require('electron').remote;

IPC.on('lcu-load', (event, data) => {

const { username, password, address, port } = data;
const header = `Basic ${btoa(`${username}:${password}`)}`;
const auth = new SwaggerClient.ApiKeyAuthorization("Authorization", header, "header");

window.swaggerUi = new SwaggerUi({
validatorUrl: null,
url: `https://${username}:${password}@${address}:${port}/swagger/v2/swagger.json`,
authorizations: { riot: auth },
dom_id: "swagger-ui-container",
onComplete(swaggerApi, swaggerUi) {
$('pre code').each(function(i, e) {
hljs.highlightBlock(e)
<head>
<meta charset="UTF-8">
<title>Rift Explorer</title>
<link rel="icon" type="image/png" href="images/favicon-32x32.png" sizes="32x32" />
<link rel="icon" type="image/png" href="images/favicon-16x16.png" sizes="16x16" />
<link href='css/typography.css' media='screen' rel='stylesheet' type='text/css'/>
<link href='css/reset.css' media='screen' rel='stylesheet' type='text/css'/>
<link href='css/screen.css' media='screen' rel='stylesheet' type='text/css'/>
<link href='css/reset.css' media='print' rel='stylesheet' type='text/css'/>
<link href='css/print.css' media='print' rel='stylesheet' type='text/css'/>
<link href='css/style.css' rel='stylesheet' type='text/css'/>
<script src='lib/jquery-1.8.0.min.js' type='text/javascript'></script>
<script src='lib/jquery.slideto.min.js' type='text/javascript'></script>
<script src='lib/jquery.wiggle.min.js' type='text/javascript'></script>
<script src='lib/jquery.ba-bbq.min.js' type='text/javascript'></script>
<script src='lib/handlebars-2.0.0.js' type='text/javascript'></script>
<script src='lib/underscore-min.js' type='text/javascript'></script>
<script src='lib/backbone-min.js' type='text/javascript'></script>
<script src='swagger-ui.js' type='text/javascript'></script>
<script src='lib/highlight.7.3.pack.js' type='text/javascript'></script>
<script src='lib/jsoneditor.min.js' type='text/javascript'></script>
<script src='lib/marked.js' type='text/javascript'></script>
<script src='lib/swagger-oauth.js' type='text/javascript'></script>

</head>

<body class="swagger-section">
<div id="message-bar" class="swagger-ui-wrap" data-sw-translate>Waiting for League to start...</div>
<div id="swagger-ui-container" class="swagger-ui-wrap"></div>

<script type="text/javascript">
const IPC = require('electron').ipcRenderer;
const shell = require('electron').shell;
const pkg = require('../package');

const swaggerContainer = document.querySelector('#swagger-ui-container');
const messageBar = document.querySelector('#message-bar');

let LCUData = null;
let swaggerDisabled = true;
let loadingSwagger = false;

// We all love global variables
window.RE = {
info: {
title: 'Rift Explorer',
description: pkg.description,
version: pkg.version,
}
};

const loadSwagger = () => {
const { username, password, address, port } = LCUData;
const header = `Basic ${btoa(`${username}:${password}`)}`;
const auth = new SwaggerClient.ApiKeyAuthorization("Authorization", header, "header");

loadingSwagger = true;

window.swaggerUi = new SwaggerUi({
validatorUrl: null,
url: `https://${username}:${password}@${address}:${port}/swagger/v2/swagger.json`,
authorizations: { riot: auth },
dom_id: "swagger-ui-container",
onComplete() {
loadingSwagger = false;

$('pre code').each((i, e) => {
hljs.highlightBlock(e);
});

window.swaggerUi.api.clientAuthorizations.add("riot", auth);
},
// Failure has been taken care of in the swagger-ui file
docExpansion: "none",
jsonEditor: false,
apisSorter: "alpha",
defaultModelRendering: 'schema',
showRequestHeaders: true
});

window.swaggerUi.api.clientAuthorizations.add("riot", auth);
},
onFailure(error) {
// alert('Couldn\'t load the swagger file. Make sure swagger is enabled. More info at https://github.com/Pupix/rift-explorer');
},
docExpansion: "none",
jsonEditor: false,
apisSorter: "alpha",
defaultModelRendering: 'schema',
showRequestHeaders: true
window.swaggerUi.load();
};

IPC.on('lcu-load', (event, data) => {
LCUData = data;

if (!swaggerDisabled && !loadingSwagger) {
loadSwagger();
}
});

IPC.on('lcu-unload', () => {
LCUData = null;
swaggerContainer.innerHTML = '';
messageBar.innerHTML = 'Waiting for League to start...';
});

window.swaggerUi.load();
});
IPC.on('swagger-disabled', () => {
swaggerDisabled = true;
messageBar.innerHTML = 'API has been auto-enabled. Please restart the League Client';

function _handleGithubLink(event) {
shell.openExternal('https://github.com/pupix/rift-explorer');
}
// Allow the DOM to render the new HTML
setTimeout(() => {
const allowedRestart = confirm('Rift Explorer needs to restart the League Client to enable the API documentation');

function _handleDiscordLink(event) {
shell.openExternal('https://discord.gg/hPtrMcx');
}
if (allowedRestart) {
const { username, password, address, port } = LCUData;

fetch(`https://${address}:${port}/process-control/v1/process/restart?delaySeconds=0`, {
method: 'POST',
headers: new Headers({ Authorization: `Basic ${btoa(`${username}:${password}`)}` })
});
}
}, 100);
});

IPC.on('swagger-enabled', () => {
swaggerDisabled = false;
messageBar.innerHTML = 'Waiting for League to start...';

if (LCUData && !loadingSwagger) {
loadSwagger();
}
});

</script>
</head>
function _handleGithubLink(event) {
shell.openExternal('https://github.com/pupix/rift-explorer');
}

<body class="swagger-section">
<div id="message-bar" class="swagger-ui-wrap" data-sw-translate>Waiting for League to start...</div>
<div id="swagger-ui-container" class="swagger-ui-wrap"></div>
</body>
function _handleDiscordLink(event) {
shell.openExternal('https://discord.gg/hPtrMcx');
}
</script>
</body>
</html>

0 comments on commit d47ff55

Please sign in to comment.