Metaverse connection is working.

This commit is contained in:
Kalila L 2021-09-06 03:12:55 -04:00
parent da464b2f40
commit 4ae378e90a
14 changed files with 358 additions and 151 deletions

View file

@ -1,109 +1,112 @@
const { resolve } = require('path');
module.exports = {
// https://eslint.org/docs/user-guide/configuring#configuration-cascading-and-hierarchy
// This option interrupts the configuration hierarchy at this file
// Remove this if you have an higher level ESLint config file (it usually happens into a monorepos)
root: true,
// https://eslint.org/docs/user-guide/configuring#configuration-cascading-and-hierarchy
// This option interrupts the configuration hierarchy at this file
// Remove this if you have an higher level ESLint config file (it usually happens into a monorepos)
root: true,
// https://eslint.vuejs.org/user-guide/#how-to-use-custom-parser
// Must use parserOptions instead of "parser" to allow vue-eslint-parser to keep working
// `parser: 'vue-eslint-parser'` is already included with any 'plugin:vue/**' config and should be omitted
parserOptions: {
// https://github.com/typescript-eslint/typescript-eslint/tree/master/packages/parser#configuration
// https://github.com/TypeStrong/fork-ts-checker-webpack-plugin#eslint
// Needed to make the parser take into account 'vue' files
extraFileExtensions: ['.vue'],
parser: '@typescript-eslint/parser',
project: resolve(__dirname, './tsconfig.json'),
tsconfigRootDir: __dirname,
ecmaVersion: 2018, // Allows for the parsing of modern ECMAScript features
sourceType: 'module' // Allows for the use of imports
},
// https://eslint.vuejs.org/user-guide/#how-to-use-custom-parser
// Must use parserOptions instead of "parser" to allow vue-eslint-parser to keep working
// `parser: 'vue-eslint-parser'` is already included with any 'plugin:vue/**' config and should be omitted
parserOptions: {
// https://github.com/typescript-eslint/typescript-eslint/tree/master/packages/parser#configuration
// https://github.com/TypeStrong/fork-ts-checker-webpack-plugin#eslint
// Needed to make the parser take into account 'vue' files
extraFileExtensions: ['.vue'],
parser: '@typescript-eslint/parser',
project: resolve(__dirname, './tsconfig.json'),
tsconfigRootDir: __dirname,
ecmaVersion: 2018, // Allows for the parsing of modern ECMAScript features
sourceType: 'module' // Allows for the use of imports
},
env: {
browser: true
},
env: {
browser: true
},
// Rules order is important, please avoid shuffling them
extends: [
// Base ESLint recommended rules
// 'eslint:recommended',
// Rules order is important, please avoid shuffling them
extends: [
// Base ESLint recommended rules
// 'eslint:recommended',
// https://github.com/typescript-eslint/typescript-eslint/tree/master/packages/eslint-plugin#usage
// ESLint typescript rules
'plugin:@typescript-eslint/recommended',
// consider disabling this class of rules if linting takes too long
'plugin:@typescript-eslint/recommended-requiring-type-checking',
// https://github.com/typescript-eslint/typescript-eslint/tree/master/packages/eslint-plugin#usage
// ESLint typescript rules
'plugin:@typescript-eslint/recommended',
// consider disabling this class of rules if linting takes too long
'plugin:@typescript-eslint/recommended-requiring-type-checking',
// Uncomment any of the lines below to choose desired strictness,
// but leave only one uncommented!
// See https://eslint.vuejs.org/rules/#available-rules
'plugin:vue/vue3-essential', // Priority A: Essential (Error Prevention)
// 'plugin:vue/vue3-strongly-recommended', // Priority B: Strongly Recommended (Improving Readability)
// 'plugin:vue/vue3-recommended', // Priority C: Recommended (Minimizing Arbitrary Choices and Cognitive Overhead)
// Uncomment any of the lines below to choose desired strictness,
// but leave only one uncommented!
// See https://eslint.vuejs.org/rules/#available-rules
'plugin:vue/vue3-essential', // Priority A: Essential (Error Prevention)
// 'plugin:vue/vue3-strongly-recommended', // Priority B: Strongly Recommended (Improving Readability)
// 'plugin:vue/vue3-recommended', // Priority C: Recommended (Minimizing Arbitrary Choices and Cognitive Overhead)
'standard'
'standard'
],
],
plugins: [
// required to apply rules which need type information
'@typescript-eslint',
plugins: [
// required to apply rules which need type information
'@typescript-eslint',
// https://eslint.vuejs.org/user-guide/#why-doesn-t-it-work-on-vue-file
// required to lint *.vue files
'vue',
// https://eslint.vuejs.org/user-guide/#why-doesn-t-it-work-on-vue-file
// required to lint *.vue files
'vue',
],
],
globals: {
ga: 'readonly', // Google Analytics
cordova: 'readonly',
__statics: 'readonly',
__QUASAR_SSR__: 'readonly',
__QUASAR_SSR_SERVER__: 'readonly',
__QUASAR_SSR_CLIENT__: 'readonly',
__QUASAR_SSR_PWA__: 'readonly',
process: 'readonly',
Capacitor: 'readonly',
chrome: 'readonly'
},
globals: {
ga: 'readonly', // Google Analytics
cordova: 'readonly',
__statics: 'readonly',
__QUASAR_SSR__: 'readonly',
__QUASAR_SSR_SERVER__: 'readonly',
__QUASAR_SSR_CLIENT__: 'readonly',
__QUASAR_SSR_PWA__: 'readonly',
process: 'readonly',
Capacitor: 'readonly',
chrome: 'readonly'
},
// add your custom rules here
rules: {
// allow async-await
'generator-star-spacing': 'off',
// allow paren-less arrow functions
'arrow-parens': 'off',
'one-var': 'off',
'no-void': 'off',
'multiline-ternary': 'off',
// add your custom rules here
rules: {
// allow async-await
'generator-star-spacing': 'off',
// allow paren-less arrow functions
'arrow-parens': 'off',
'one-var': 'off',
'no-void': 'off',
'multiline-ternary': 'off',
'quote-props': 'off',
'import/first': 'off',
'import/namespace': 'error',
'import/default': 'error',
'import/export': 'error',
'import/extensions': 'off',
'import/no-unresolved': 'off',
'import/no-extraneous-dependencies': 'off',
'prefer-promise-reject-errors': 'off',
'indent': ["error", 4],
'semi': ["error", "always"],
'import/first': 'off',
'import/namespace': 'error',
'import/default': 'error',
'import/export': 'error',
'import/extensions': 'off',
'import/no-unresolved': 'off',
'import/no-extraneous-dependencies': 'off',
'prefer-promise-reject-errors': 'off',
'indent': ["error", 4],
'semi': ["error", "always"],
// TypeScript
quotes: ['warn', 'double', { avoidEscape: true }],
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
// TypeScript
quotes: ['warn', 'double', { avoidEscape: true }],
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
// TypeScript -> Remove these when we start using TypeScript in the project.
'@typescript-eslint/no-unsafe-assignment': 'off',
'@typescript-eslint/no-unsafe-call': 'off',
'@typescript-eslint/unbound-method': 'off',
'@typescript-eslint/no-unsafe-member-access': 'off',
'@typescript-eslint/no-floating-promises': 'off',
'@typescript-eslint/restrict-template-expressions': 'off',
// TypeScript -> Remove these when we start using TypeScript in the project.
'@typescript-eslint/no-unsafe-assignment': 'off',
'@typescript-eslint/no-unsafe-call': 'off',
'@typescript-eslint/unbound-method': 'off',
'@typescript-eslint/no-unsafe-member-access': 'off',
'@typescript-eslint/no-floating-promises': 'off',
'@typescript-eslint/restrict-template-expressions': 'off',
'@typescript-eslint/no-var-requires': 'off',
'@typescript-eslint/no-unsafe-return': 'off',
// allow debugger during development only
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off'
}
// allow debugger during development only
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off'
}
}

View file

@ -1,3 +1,13 @@
<!--
// App.vue
//
// Created by Kalila L. on Sep. 4th, 2021.
// Copyright 2021 Vircadia contributors.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
-->
<template>
<router-view />
</template>

View file

@ -1,5 +1,6 @@
import { boot } from "quasar/wrappers";
import axios, { AxiosInstance } from "axios";
import Log from "../modules/utilities/log";
declare module "@vue/runtime-core" {
interface ComponentCustomProperties {
@ -7,6 +8,12 @@ declare module "@vue/runtime-core" {
}
}
Log.info(Log.types.OTHER, "Bootstrapping Axios.");
axios.defaults.headers.common = {
"x-vircadia-error-handle": "badrequest"
};
// Be careful when using SSR for cross-request state pollution
// due to creating a Singleton instance here;
// If any client changes this (global) instance, it might be a

View file

@ -51,6 +51,7 @@
</template>
<script>
// FIXME: Needs to be done correctly. Also universally? Maybe window.axios?
const axios = require("axios");
import Log from "../../../modules/utilities/log";
@ -64,43 +65,27 @@ export default {
username: "",
password: "",
showPassword: false,
// TODO: Needs to be stored somewhere central.
DEFAULT_METAVERSE_URL: "https://metaverse.vircadia.com/live"
}),
methods: {
async onSubmit () {
try {
const metaverseURL = await this.retrieveMetaverseUrl();
const result = await this.attemptLogin(metaverseURL, this.username, this.password);
const metaverseURL = await this.retrieveMetaverseUrl();
const result = await this.attemptLogin(metaverseURL, this.username, this.password);
this.$q.notify({
type: "positive",
textColor: "white",
icon: "cloud_done",
message: `Welcome ${this.username}.`
});
this.$emit("loginResult", true, result);
} catch (result) {
this.$q.notify({
type: "negative",
textColor: "white",
icon: "warning",
message: `Login attempted failed: ${result.error}`
});
this.$emit("loginResult", false, result);
}
this.$emit("loginResult", { "success": result.success, "metaverse": metaverseURL, "data": result.response });
},
// TODO: This needs to be addressed in a more modular fashion to reuse and save state across multiple components.
async retrieveMetaverseUrl () {
return new Promise((resolve, reject) => {
return new Promise((resolve) => {
axios.get("/api/metaverse_info")
.then((response) => {
Log.info(Log.types.METAVERSE, `Retrieved Metaverse URL ${response.metaverse_url}.`);
resolve(response.metaverse_url);
Log.info(Log.types.METAVERSE, `Retrieved Metaverse URL ${response.data.metaverse_url}.`);
resolve(response.data.metaverse_url);
}, (error) => {
Log.error(Log.types.METAVERSE, `Failed to retrieve Metaverse URL, using default URL ${this.DEFAULT_METAVERSE_URL} instead.`);
Log.error(Log.types.METAVERSE, `Failed to retrieve Metaverse URL, using default URL ${this.DEFAULT_METAVERSE_URL} instead. Error: ${error}`);
resolve(this.DEFAULT_METAVERSE_URL);
});
});
@ -109,7 +94,7 @@ export default {
async attemptLogin (metaverse, username, password) {
Log.info(Log.types.METAVERSE, `Attempting to login as ${username}.`);
return new Promise((resolve, reject) => {
return new Promise((resolve) => {
axios.post(`${metaverse}/oauth/token`, {
grant_type: "password",
scope: "owner", // as opposed to 'domain', we're asking for a user token
@ -118,13 +103,15 @@ export default {
})
.then((response) => {
Log.info(Log.types.METAVERSE, `Successfully got key and details for ${username}.`);
resolve(response.data);
resolve({ "success": true, "response": response.data });
}, (error) => {
Log.error(Log.types.METAVERSE, `Failed to get key and details for ${username}.`);
if (error.response && error.response.data) {
reject(error.response.data);
resolve({ "success": false, "response": error.response.data });
} else if (error) {
resolve({ "success": false, "response": error });
} else {
reject("Unknown reason.");
resolve({ "success": false, "response": "Unknown reason." });
}
});
});

View file

@ -21,12 +21,18 @@
<q-separator />
<q-card-section>
<MetaverseLogin></MetaverseLogin>
<MetaverseLogin @loginResult="onLoginAttempt"></MetaverseLogin>
</q-card-section>
</template>
<script>
// FIXME: Needs to be done correctly. Also universally? Maybe window.axios?
const axios = require("axios");
// Components
import MetaverseLogin from "../components/login/MetaverseLogin.vue";
// Modules
import Log from "../../modules/utilities/log";
export default {
name: "ConnectMetaverse",
@ -35,10 +41,90 @@ export default {
MetaverseLogin
},
emits: ["connectionResult"],
data: () => ({
}),
methods: {
onLoginAttempt (result) {
if (result.success === true) {
Log.info(Log.types.METAVERSE, `Successfully logged in as ${result.data.account_name} for Metaverse linking.`);
// Get a token for our server from the Metaverse.
axios.post(`${result.metaverse}/api/v1/token/new`, {}, {
params: {
// "asAdmin": store.account.useAsAdmin,
"scope": "domain"
},
headers: {
"Authorization": `Bearer ${result.data.access_token}`
}
})
.then(async (response) => {
Log.info(Log.types.METAVERSE, `Successfully got Domain token for Metaverse linking.`);
var settingsToCommit = {
"metaverse": {
"access_token": response.data.data.token
}
};
var committed = await this.commitSettings(settingsToCommit);
if (committed === true) {
Log.info(Log.types.METAVERSE, `Successfully committed Domain server access token for the Metaverse.`);
this.$q.notify({
type: "positive",
textColor: "white",
icon: "cloud_done",
message: `Successfully linked your server to the Metaverse.`
});
this.$emit("connectionResult", { "success": true });
} else {
Log.error(Log.types.METAVERSE, `Failed to link server with Metaverse: Could not commit token to settings.`);
this.$q.notify({
type: "negative",
textColor: "white",
icon: "warning",
message: `Metaverse link attempt failed because the settings were unable to be saved.`
});
this.$emit("connectionResult", { "success": false });
}
})
.catch((result) => {
Log.error(Log.types.METAVERSE, `Failed to link server with Metaverse: ${result.responseJSON.error}`);
this.$q.notify({
type: "negative",
textColor: "white",
icon: "warning",
message: `Metaverse link attempt failed: ${result.responseJSON.error}`
});
});
} else {
this.$q.notify({
type: "negative",
textColor: "white",
icon: "warning",
message: `Login attempt failed: ${result.data.error}`
});
}
},
// TODO: This needs to go somewhere universal.
commitSettings (settingsToCommit) {
// TODO: This and all other URL endpoints should be in centralized (in their respective module) constants files.
return axios.post(`/settings.json`, JSON.stringify(settingsToCommit))
.then((response) => {
Log.info(Log.types.DOMAIN, `Successfully committed settings.`);
return true;
})
.catch((response) => {
Log.error(Log.types.DOMAIN, `Failed to commit settings to Domain.`);
return false;
});
}
}
};
</script>

View file

@ -1,3 +1,13 @@
<!--
// FirstTimeWizard.vue
//
// Created by Kalila L. on Sep. 4th, 2021.
// Copyright 2021 Vircadia contributors.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
-->
<template>
<q-layout id="vantaBG" view="hHh lpR fFf">
<q-page-container>

View file

@ -13,6 +13,7 @@
const Log = (function () {
enum types {
OTHER = "[OTHER]",
DOMAIN = "[DOMAIN]",
METAVERSE = "[METAVERSE]"
}

View file

@ -1,25 +1,35 @@
<!--
// Index.vue
//
// Created by Kalila L. on Sep. 4th, 2021.
// Copyright 2021 Vircadia contributors.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
-->
<template>
<div class="fullscreen bg-blue text-white text-center q-pa-md flex flex-center">
<div>
<div style="font-size: 30vh">
404
</div>
<div class="fullscreen bg-blue text-white text-center q-pa-md flex flex-center">
<div>
<div style="font-size: 30vh">
404
</div>
<div class="text-h2" style="opacity:.4">
Oops. Nothing here...
</div>
<div class="text-h2" style="opacity:.4">
Oops. Nothing here...
</div>
<q-btn
class="q-mt-xl"
color="white"
text-color="blue"
unelevated
to="/"
label="Go Home"
no-caps
/>
<q-btn
class="q-mt-xl"
color="white"
text-color="blue"
unelevated
to="/"
label="Go Home"
no-caps
/>
</div>
</div>
</div>
</template>
<script lang="ts">

View file

@ -1,3 +1,13 @@
<!--
// Index.vue
//
// Created by Kalila L. on Sep. 4th, 2021.
// Copyright 2021 Vircadia contributors.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
-->
<style lang="scss" scoped>
$firstTimeWizardContainerBGstart: rgba(0, 0, 0, 0.0);
$firstTimeWizardContainerBGend: rgba(0, 0, 0, 0.75);
@ -196,7 +206,7 @@
<q-step
:name="4"
title="Metaverse"
:title="connectMetaverseSuccess ? 'Metaverse (Connected ✔️)' : 'Metaverse'"
caption="Optional"
:done="mainWizardStep > 4"
>
@ -213,21 +223,22 @@
@click="connectMetaverseTriggered"
class="q-mb-md"
size="md"
outline
:outline="!connectMetaverseSuccess"
:color="connectMetaverseSuccess ? 'green' : ''"
text-color="white"
icon-right="cloud"
:icon-right="connectMetaverseSuccess ? 'done' : 'cloud'"
>
Connect
{{ connectMetaverseSuccess ? 'Connected' : 'Connect' }}
</q-btn>
<q-btn
@click="$refs.stepper.next()"
class="q-mb-md"
size="sm"
:size="connectMetaverseSuccess ? 'md' : 'sm'"
outline
text-color="white"
icon-right="chevron_right"
>
Skip
{{ connectMetaverseSuccess ? 'Next' : 'Skip' }}
</q-btn>
<q-btn
@click="$refs.stepper.previous()"
@ -246,10 +257,46 @@
style="background: rgba(0, 0, 0, 0.95);"
dark
>
<ConnectMetaverse></ConnectMetaverse>
<ConnectMetaverse @connectionResult="onMetaverseConnectionAttempted"></ConnectMetaverse>
</q-card>
</q-dialog>
</q-step>
<q-step
:name="5"
title="Security"
caption="Optional"
:done="mainWizardStep > 5"
>
<q-card
class="wizardCard"
>
<q-card-section>
<div class="text-h6 text-weight-light text-center">Let's configure some security settings for your world.</div>
</q-card-section>
<q-card-actions vertical align="right">
<q-btn
@click="saveSecuritySettings"
class="q-mb-md"
size="md"
outline
text-color="white"
icon-right="chevron_right"
>
Next
</q-btn>
<q-btn
@click="$refs.stepper.previous()"
size="sm"
flat
icon-left="chevron_left"
>
Back
</q-btn>
</q-card-actions>
</q-card>
</q-step>
</q-stepper>
</transition>
</div>
@ -276,9 +323,11 @@ export default defineComponent({
welcomeText: true,
mainWizard: true,
mainWizardStep: ref(1),
// TODO: Needs to be based off of the actual state of the server's connection (using Vuex and retrieving settings on page load.)
connectMetaverseSuccess: true,
connectMetaverseDialog: false,
// Consts
WELCOME_TEXT_TIMEOUT: 2000,
WELCOME_TEXT_TIMEOUT: 4000,
MAIN_WIZARD_TRANSITION_TIME: 1000,
DEFAULT_METAVERSE_URL: "https://metaverse.vircadia.com/live"
};
@ -293,6 +342,15 @@ export default defineComponent({
methods: {
connectMetaverseTriggered () {
this.connectMetaverseDialog = true;
},
onMetaverseConnectionAttempted () {
this.connectMetaverseSuccess = true;
this.mainWizardStep++;
},
saveSecuritySettings () {
// TODO
}
}
});

View file

@ -1,5 +1,15 @@
<!--
// Index.vue
//
// Created by Kalila L. on Sep. 4th, 2021.
// Copyright 2021 Vircadia contributors.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
-->
<template>
<h1>hi</h1>
<h1>Test</h1>
</template>
<script lang="ts">

View file

@ -1,3 +1,12 @@
// index.ts
//
// Created by Kalila L. on Sep. 4th, 2021.
// Copyright 2021 Vircadia contributors.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
import { route } from "quasar/wrappers";
import {
createMemoryHistory,

View file

@ -1,3 +1,11 @@
// routes.ts
//
// Created by Kalila L. on Sep. 4th, 2021.
// Copyright 2021 Vircadia contributors.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
import { RouteRecordRaw } from "vue-router";
const routes: RouteRecordRaw[] = [

View file

@ -1,3 +1,11 @@
// index.ts
//
// Created by Kalila L. on Sep. 4th, 2021.
// Copyright 2021 Vircadia contributors.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
import { store } from "quasar/wrappers";
import { InjectionKey } from "vue";
import {

View file

@ -1,6 +1,6 @@
{
"extends": "@quasar/app/tsconfig-preset",
"compilerOptions": {
"baseUrl": "./web-new"
}
"extends": "@quasar/app/tsconfig-preset",
"compilerOptions": {
"baseUrl": "./web-new"
}
}