soiz1's picture
Upload 811 files
30c32c8 verified
raw
history blame
17 kB
const BlockType = require('../../extension-support/block-type');
const ArgumentType = require('../../extension-support/argument-type');
const Cast = require('../../util/cast');
const uid = require('../../util/uid');
/**
* Class for storage blocks
* @constructor
*/
class JgStorageBlocks {
constructor(runtime) {
/**
* The runtime instantiating this block package.
* @type {Runtime}
*/
this.runtime = runtime;
this.currentServer = "https://storage-ext.penguinmod.com/";
this.usePenguinMod = true;
this.useGlobal = true;
this.waitingForResponse = false;
this.serverFailedResponse = false;
this.serverError = "";
this.uniquePrefix = "u" + uid();
// A value stored in the PMP of the project.
// This value should always be globally unique to
// every project.
// The chance that 2 projects have the same "unique"
// prefix is about very small.
// The u at the start is to make sure that it can never
// be mistaken for a project id.
}
/**
* @returns {object} metadata for this extension and its blocks.
*/
getInfo() {
return {
id: 'jgStorage',
name: 'Storage',
color1: '#76A8FE',
color2: '#538EFC',
docsURI: 'https://docs.penguinmod.com/extensions/storage',
blocks: [
{
blockType: BlockType.LABEL,
text: "Local Storage"
},
{
opcode: 'getValue',
text: 'get [KEY]',
disableMonitor: true,
blockType: BlockType.REPORTER,
arguments: {
KEY: {
type: ArgumentType.STRING,
defaultValue: "key"
},
}
},
{
opcode: 'setValue',
text: 'set [KEY] to [VALUE]',
blockType: BlockType.COMMAND,
arguments: {
KEY: {
type: ArgumentType.STRING,
defaultValue: "key"
},
VALUE: {
type: ArgumentType.STRING,
defaultValue: "value"
},
}
},
{
opcode: 'deleteValue',
text: 'delete [KEY]',
blockType: BlockType.COMMAND,
arguments: {
KEY: {
type: ArgumentType.STRING,
defaultValue: "key"
}
}
},
{
opcode: 'getKeys',
text: 'get all stored names',
disableMonitor: true,
blockType: BlockType.REPORTER
},
{
blockType: BlockType.LABEL,
text: "Local Uploaded Project Storage"
},
{
opcode: 'getProjectValue',
text: 'get uploaded project [KEY]',
disableMonitor: true,
blockType: BlockType.REPORTER,
arguments: {
KEY: {
type: ArgumentType.STRING,
defaultValue: "key"
},
}
},
{
opcode: 'setProjectValue',
text: 'set uploaded project [KEY] to [VALUE]',
blockType: BlockType.COMMAND,
arguments: {
KEY: {
type: ArgumentType.STRING,
defaultValue: "key"
},
VALUE: {
type: ArgumentType.STRING,
defaultValue: "value"
},
}
},
{
opcode: 'deleteProjectValue',
text: 'delete uploaded project [KEY]',
blockType: BlockType.COMMAND,
arguments: {
KEY: {
type: ArgumentType.STRING,
defaultValue: "key"
}
}
},
{
opcode: 'getProjectKeys',
text: 'get all stored names in this uploaded project',
disableMonitor: true,
blockType: BlockType.REPORTER
},
{
blockType: BlockType.LABEL,
text: "Local Project Storage"
},
{
opcode: 'getUniqueValue',
text: 'get local project [KEY]',
disableMonitor: true,
blockType: BlockType.REPORTER,
arguments: {
KEY: {
type: ArgumentType.STRING,
defaultValue: "key"
},
}
},
{
opcode: 'setUniqueValue',
text: 'set local project [KEY] to [VALUE]',
blockType: BlockType.COMMAND,
arguments: {
KEY: {
type: ArgumentType.STRING,
defaultValue: "key"
},
VALUE: {
type: ArgumentType.STRING,
defaultValue: "value"
},
}
},
{
opcode: 'deleteUniqueValue',
text: 'delete local project [KEY]',
blockType: BlockType.COMMAND,
arguments: {
KEY: {
type: ArgumentType.STRING,
defaultValue: "key"
}
}
},
{
opcode: 'getUniqueKeys',
text: 'get all stored names in this local project',
disableMonitor: true,
blockType: BlockType.REPORTER
},
{
blockType: BlockType.LABEL,
text: "Server Storage"
},
{
opcode: 'isGlobalServer',
text: 'is using global server?',
disableMonitor: true,
blockType: BlockType.BOOLEAN
},
{
opcode: 'useCertainServer',
text: 'set server to [SERVER] server',
disableMonitor: true,
blockType: BlockType.COMMAND,
arguments: {
SERVER: {
type: ArgumentType.STRING,
menu: "serverType"
},
}
},
{
opcode: 'waitingForConnection',
text: 'waiting for server to respond?',
disableMonitor: true,
blockType: BlockType.BOOLEAN
},
{
opcode: 'connectionFailed',
text: 'server failed to respond?',
disableMonitor: true,
blockType: BlockType.BOOLEAN
},
{
opcode: 'serverErrorOutput',
text: 'server error',
disableMonitor: false,
blockType: BlockType.REPORTER
},
"---",
{
opcode: 'getServerValue',
text: 'get server [KEY]',
disableMonitor: true,
blockType: BlockType.REPORTER,
arguments: {
KEY: {
type: ArgumentType.STRING,
defaultValue: "key"
},
}
},
{
opcode: 'setServerValue',
text: 'set server [KEY] to [VALUE]',
blockType: BlockType.COMMAND,
arguments: {
KEY: {
type: ArgumentType.STRING,
defaultValue: "key"
},
VALUE: {
type: ArgumentType.STRING,
defaultValue: "value"
},
}
},
{
opcode: 'deleteServerValue',
text: 'delete server [KEY]',
blockType: BlockType.COMMAND,
arguments: {
KEY: {
type: ArgumentType.STRING,
defaultValue: "key"
}
}
}
],
menus: {
serverType: {
acceptReporters: true,
items: [
"project",
"global"
].map(item => ({ text: item, value: item }))
}
}
};
}
// Storage
serialize() {
return { uniqueId: this.uniquePrefix }
}
deserialize(data) {
this.uniquePrefix = data.uniqueId;
}
// utilities
/**
* @returns {string} Prefix for any keys saved
*/
getPrefix(projectId) {
return `PM_PROJECTSTORAGE_EXT_${projectId == null ? "" : `${projectId}_`}`;
}
getAllKeys(projectId) {
return Object.keys(localStorage).filter(key => key.startsWith(this.getPrefix(projectId))).map(key => key.replace(this.getPrefix(projectId), ""));
}
getProjectId() {
/* todo: get the project id in a like 190x better way lol */
const hash = String(window.location.hash).replace(/#/gmi, "");
return Cast.toNumber(hash);
}
runPenguinWebRequest(url, options, ifFailReturn) {
this.waitingForResponse = true;
this.serverFailedResponse = false;
this.serverError = "";
return new Promise((resolve) => {
let promise = null;
if (options !== null) {
promise = fetch(url, options);
} else {
promise = fetch(url);
}
promise.then(response => {
response.text().then(text => {
if (!response.ok) {
this.waitingForResponse = false;
this.serverFailedResponse = true;
this.serverError = Cast.toString(text);
if (ifFailReturn !== null) {
return resolve(ifFailReturn);
}
resolve(text);
return;
}
this.waitingForResponse = false;
this.serverFailedResponse = false;
this.serverError = "";
resolve(text);
}).catch(err => {
this.waitingForResponse = false;
this.serverFailedResponse = true;
this.serverError = Cast.toString(err);
if (ifFailReturn !== null) {
return resolve(ifFailReturn);
}
resolve(err);
})
}).catch(err => {
this.waitingForResponse = false;
this.serverFailedResponse = true;
this.serverError = Cast.toString(err);
if (ifFailReturn !== null) {
return resolve(ifFailReturn);
}
resolve(err);
})
})
}
getCurrentServer() {
return `https://storage-ext.penguinmod.com/`
}
// blocks
getKeys() {
return JSON.stringify(this.getAllKeys());
}
getValue(args) {
const key = this.getPrefix() + Cast.toString(args.KEY);
const returned = localStorage.getItem(key);
if (returned === null) return "";
return Cast.toString(returned);
}
setValue(args) {
const key = this.getPrefix() + Cast.toString(args.KEY);
const value = Cast.toString(args.VALUE);
return localStorage.setItem(key, value);
}
deleteValue(args) {
const key = this.getPrefix() + Cast.toString(args.KEY);
return localStorage.removeItem(key);
}
// project blocks
getProjectKeys() {
return JSON.stringify(this.getAllKeys(this.getProjectId()));
}
getProjectValue(args) {
const key = this.getPrefix(this.getProjectId()) + Cast.toString(args.KEY);
const returned = localStorage.getItem(key);
if (returned === null) return "";
return Cast.toString(returned);
}
setProjectValue(args) {
const key = this.getPrefix(this.getProjectId()) + Cast.toString(args.KEY);
const value = Cast.toString(args.VALUE);
return localStorage.setItem(key, value);
}
deleteProjectValue(args) {
const key = this.getPrefix(this.getProjectId()) + Cast.toString(args.KEY);
return localStorage.removeItem(key);
}
// global unique blocks
getUniqueKeys() {
return JSON.stringify(this.getAllKeys(this.uniquePrefix));
}
getUniqueValue(args) {
const key = this.getPrefix(this.uniquePrefix) + Cast.toString(args.KEY);
const returned = localStorage.getItem(key);
if (returned === null) return "";
return Cast.toString(returned);
}
setUniqueValue(args) {
const key = this.getPrefix(this.uniquePrefix) + Cast.toString(args.KEY);
const value = Cast.toString(args.VALUE);
return localStorage.setItem(key, value);
}
deleteUniqueValue(args) {
const key = this.getPrefix(this.uniquePrefix) + Cast.toString(args.KEY);
return localStorage.removeItem(key);
}
// server blocks
isGlobalServer() {
return this.useGlobal;
}
useCertainServer(args) {
const serverType = Cast.toString(args.SERVER).toLowerCase();
if (["project", "global"].includes(serverType)) {
// this is a menu option
this.currentServer = "https://storage-ext.penguinmod.com/";
this.usePenguinMod = true;
this.useGlobal = serverType === "global";
} else {
// this is a url
this.currentServer = Cast.toString(args.SERVER);
if (!this.currentServer.endsWith("/")) {
this.currentServer += "/";
}
this.usePenguinMod = false;
this.useGlobal = true;
}
// now lets wait until the server responds saying it is online
return this.runPenguinWebRequest(this.currentServer);
}
waitingForConnection() {
return this.waitingForResponse;
}
connectionFailed() {
return this.serverFailedResponse;
}
serverErrorOutput() {
return this.serverError;
}
getServerValue(args) {
const key = Cast.toString(args.KEY);
return this.runPenguinWebRequest(`${this.currentServer}get?key=${key}${this.useGlobal ? "" : `&project=${this.getProjectId()}`}`, null, "");
}
setServerValue(args) {
const key = Cast.toString(args.KEY);
const value = Cast.toString(args.VALUE);
return this.runPenguinWebRequest(`${this.currentServer}set?key=${key}${this.useGlobal ? "" : `&project=${this.getProjectId()}`}`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
"value": value
})
});
}
deleteServerValue(args) {
const key = Cast.toString(args.KEY);
return this.runPenguinWebRequest(`${this.currentServer}delete?key=${key}${this.useGlobal ? "" : `&project=${this.getProjectId()}`}`, {
method: "DELETE"
});
}
}
module.exports = JgStorageBlocks;