Refactor to use KV exclusively

This commit is contained in:
Nariman Jelveh 2024-06-17 14:33:24 -07:00
parent 5f8b8a2147
commit 21c537fe22
5 changed files with 270 additions and 341 deletions

View File

@ -185,89 +185,45 @@ window.addEventListener('message', async (event) => {
// setItem
//--------------------------------------------------------
else if(event.data.msg === 'setItem' && event.data.key && event.data.value){
// todo: validate key and value to avoid unnecessary api calls
return await $.ajax({
url: window.api_origin + "/setItem",
type: 'POST',
data: JSON.stringify({
app: app_uuid,
key: event.data.key,
value: event.data.value,
}),
async: true,
contentType: "application/json",
headers: {
"Authorization": "Bearer "+window.auth_token
},
statusCode: {
401: function () {
window.logout();
},
},
success: function (fsentry){
}
puter.kv.set({
key: event.data.key,
value: event.data.value,
app: app_uuid,
}).then(() => {
// send confirmation to requester window
target_iframe.contentWindow.postMessage({
original_msg_id: msg_id,
}, '*');
})
}
//--------------------------------------------------------
// getItem
//--------------------------------------------------------
else if(event.data.msg === 'getItem' && event.data.key){
// todo: validate key to avoid unnecessary api calls
$.ajax({
url: window.api_origin + "/getItem",
type: 'POST',
data: JSON.stringify({
key: event.data.key,
app: app_uuid,
}),
async: true,
contentType: "application/json",
headers: {
"Authorization": "Bearer "+window.auth_token
},
statusCode: {
401: function () {
window.logout();
},
},
success: function (result){
// send confirmation to requester window
target_iframe.contentWindow.postMessage({
original_msg_id: msg_id,
msg: 'getItemSucceeded',
value: result ? result.value : null,
}, '*');
}
puter.kv.get({
key: event.data.key,
app: app_uuid,
}).then((result) => {
// send confirmation to requester window
target_iframe.contentWindow.postMessage({
original_msg_id: msg_id,
msg: 'getItemSucceeded',
value: result ?? null,
}, '*');
})
}
//--------------------------------------------------------
// removeItem
//--------------------------------------------------------
else if(event.data.msg === 'removeItem' && event.data.key){
// todo: validate key to avoid unnecessary api calls
$.ajax({
url: window.api_origin + "/removeItem",
type: 'POST',
data: JSON.stringify({
key: event.data.key,
app: app_uuid,
}),
async: true,
contentType: "application/json",
headers: {
"Authorization": "Bearer "+window.auth_token
},
statusCode: {
401: function () {
window.logout();
},
},
success: function (result){
// send confirmation to requester window
target_iframe.contentWindow.postMessage({
original_msg_id: msg_id,
}, '*');
}
puter.kv.del({
key: event.data.key,
app: app_uuid,
}).then(() => {
// send confirmation to requester window
target_iframe.contentWindow.postMessage({
original_msg_id: msg_id,
}, '*');
})
}
//--------------------------------------------------------

View File

@ -540,14 +540,11 @@ async function UIDesktop(options){
h += `</div>`;
// Get window sidebar width
window.getItem({
key: "window_sidebar_width",
success: async function(res){
let value = parseInt(res.value);
// if value is a valid number
if(!isNaN(value) && value > 0){
window.window_sidebar_width = value;
}
puter.kv.get('window_sidebar_width').then(async (val) => {
let value = parseInt(val);
// if value is a valid number
if(!isNaN(value) && value > 0){
window.window_sidebar_width = value;
}
})
@ -1072,18 +1069,15 @@ async function UIDesktop(options){
// show referral notice window
if(window.show_referral_notice && !window.user.email_confirmed){
window.getItem({
key: "shown_referral_notice",
success: async function(res){
if(!res){
setTimeout(() => {
UIWindowClaimReferral();
}, 1000);
window.setItem({
key: "shown_referral_notice",
value: true,
})
}
puter.kv.get('shown_referral_notice').then(async (val) => {
if(!val || val === 'false' || val === false){
setTimeout(() => {
UIWindowClaimReferral();
}, 1000);
puter.kv.set({
key: "shown_referral_notice",
value: true,
})
}
})
}

View File

@ -1776,7 +1776,7 @@ async function UIWindow(options) {
$('.window').css('pointer-events', 'initial');
const new_width = $(el_window_sidebar).width();
// save new width in the cloud, to user's settings
window.setItem({key: "window_sidebar_width", value: new_width});
puter.kv.set({key: "window_sidebar_width", value: new_width});
// save new width locally, to window object
window.window_sidebar_width = new_width;
}

View File

@ -30,6 +30,7 @@ import content_type_to_icon from './helpers/content_type_to_icon.js';
import truncate_filename from './helpers/truncate_filename.js';
import UIWindowProgress from './UI/UIWindowProgress.js';
import launch_app from "./helpers/launch_app.js";
import globToRegExp from "./helpers/globToRegExp.js";
window.is_auth = ()=>{
if(localStorage.getItem("auth_token") === null || window.auth_token === null)
@ -162,203 +163,6 @@ window.scrollParentToChild = (parent, child)=>{
}
}
window.getItem = async function(options){
return $.ajax({
url: window.api_origin + "/getItem",
type: 'POST',
data: JSON.stringify({
key: options.key,
app: options.app_uid,
}),
async: true,
contentType: "application/json",
headers: {
"Authorization": "Bearer "+window.auth_token
},
statusCode: {
401: function () {
window.logout();
},
},
success: function (result){
if(options.success && typeof(options.success) === "function")
options.success(result);
}
})
}
window.setItem = async function(options){
return $.ajax({
url: window.api_origin + "/setItem",
type: 'POST',
data: JSON.stringify({
app: options.app_uid,
key: options.key,
value: options.value,
}),
async: true,
contentType: "application/json",
headers: {
"Authorization": "Bearer "+window.auth_token
},
statusCode: {
401: function () {
window.logout();
},
},
success: function (fsentry){
if(options.success && typeof(options.success) === "function")
options.success(fsentry)
}
})
}
/**
* Converts a glob pattern to a regular expression, with optional extended or globstar matching.
*
* @param {string} glob - The glob pattern to convert.
* @param {Object} [opts] - Optional options for the conversion.
* @param {boolean} [opts.extended=false] - If true, enables extended matching with single character matching, character ranges, group matching, etc.
* @param {boolean} [opts.globstar=false] - If true, uses globstar matching, where '*' matches zero or more path segments.
* @param {string} [opts.flags] - Regular expression flags to include (e.g., 'i' for case-insensitive).
* @returns {RegExp} The generated regular expression.
* @throws {TypeError} If the provided glob pattern is not a string.
*/
window.globToRegExp = function (glob, opts) {
if (typeof glob !== 'string') {
throw new TypeError('Expected a string');
}
var str = String(glob);
// The regexp we are building, as a string.
var reStr = "";
// Whether we are matching so called "extended" globs (like bash) and should
// support single character matching, matching ranges of characters, group
// matching, etc.
var extended = opts ? !!opts.extended : false;
// When globstar is _false_ (default), '/foo/*' is translated a regexp like
// '^\/foo\/.*$' which will match any string beginning with '/foo/'
// When globstar is _true_, '/foo/*' is translated to regexp like
// '^\/foo\/[^/]*$' which will match any string beginning with '/foo/' BUT
// which does not have a '/' to the right of it.
// E.g. with '/foo/*' these will match: '/foo/bar', '/foo/bar.txt' but
// these will not '/foo/bar/baz', '/foo/bar/baz.txt'
// Lastely, when globstar is _true_, '/foo/**' is equivelant to '/foo/*' when
// globstar is _false_
var globstar = opts ? !!opts.globstar : false;
// If we are doing extended matching, this boolean is true when we are inside
// a group (eg {*.html,*.js}), and false otherwise.
var inGroup = false;
// RegExp flags (eg "i" ) to pass in to RegExp constructor.
var flags = opts && typeof (opts.flags) === "string" ? opts.flags : "";
var c;
for (var i = 0, len = str.length; i < len; i++) {
c = str[i];
switch (c) {
case "/":
case "$":
case "^":
case "+":
case ".":
case "(":
case ")":
case "=":
case "!":
case "|":
reStr += "\\" + c;
break;
case "?":
if (extended) {
reStr += ".";
break;
}
// fallthrough
case "[":
case "]":
if (extended) {
reStr += c;
break;
}
// fallthrough
case "{":
if (extended) {
inGroup = true;
reStr += "(";
break;
}
// fallthrough
case "}":
if (extended) {
inGroup = false;
reStr += ")";
break;
}
// fallthrough
case ",":
if (inGroup) {
reStr += "|";
break;
}
reStr += "\\" + c;
break;
case "*":
// Move over all consecutive "*"'s.
// Also store the previous and next characters
var prevChar = str[i - 1];
var starCount = 1;
while (str[i + 1] === "*") {
starCount++;
i++;
}
var nextChar = str[i + 1];
if (!globstar) {
// globstar is disabled, so treat any number of "*" as one
reStr += ".*";
} else {
// globstar is enabled, so determine if this is a globstar segment
var isGlobstar = starCount > 1 // multiple "*"'s
&& (prevChar === "/" || prevChar === undefined) // from the start of the segment
&& (nextChar === "/" || nextChar === undefined) // to the end of the segment
if (isGlobstar) {
// it's a globstar, so match zero or more path segments
reStr += "((?:[^/]*(?:/|$))*)";
i++; // move over the "/"
} else {
// it's not a globstar, so only match one path segment
reStr += "([^/]*)";
}
}
break;
default:
reStr += c;
}
}
// When regexp 'g' flag is specified don't
// constrain the regular expression with ^ & $
if (!flags || !~flags.indexOf('g')) {
reStr = "^" + reStr + "$";
}
return new RegExp(reStr, flags);
};
/**
* Validates the provided file system entry name.
*
@ -488,7 +292,7 @@ window.check_fsentry_against_allowed_file_types_string =function (fsentry, allow
}
// MIME types (e.g. text/plain)
else if(window.globToRegExp(allowed_file_type).test(fsentry.type?.toLowerCase())){
else if(globToRegExp(allowed_file_type).test(fsentry.type?.toLowerCase())){
passes_allowed_file_type_filter = true;
break;
}
@ -1014,64 +818,65 @@ window.item_icon = async (fsentry)=>{
*/
window.show_save_account_notice_if_needed = function(message){
window.getItem({
puter.kv.get({
key: "save_account_notice_shown",
success: async function(value){
if(!value && window.user?.is_temp){
window.setItem({key: "save_account_notice_shown", value: true});
}).then(async function(value){
if(!value && window.user?.is_temp){
puter.kv.set({
key: "save_account_notice_shown",
value: true,
});
// Show the notice
setTimeout(async () => {
const alert_resp = await UIAlert({
message: message ?? `<strong>Congrats on storing data!</strong><p>Don't forget to save your session! You are in a temporary session. Save session to avoid accidentally losing your work.</p>`,
body_icon: window.icons['reminder.svg'],
buttons:[
{
label: i18n('save_session'),
value: 'save-session',
type: 'primary',
},
// {
// label: 'Log into an existing account',
// value: 'login',
// },
{
label: `I'll do it later`,
value: 'remind-later',
},
],
window_options: {
backdrop: true,
close_on_backdrop_click: false,
}
})
if(alert_resp === 'remind-later'){
// TODO
}
if(alert_resp === 'save-session'){
let saved = await UIWindowSaveAccount({
send_confirmation_code: false,
});
// Show the notice
setTimeout(async () => {
const alert_resp = await UIAlert({
message: message ?? `<strong>Congrats on storing data!</strong><p>Don't forget to save your session! You are in a temporary session. Save session to avoid accidentally losing your work.</p>`,
body_icon: window.icons['reminder.svg'],
buttons:[
{
label: i18n('save_session'),
value: 'save-session',
type: 'primary',
},
// {
// label: 'Log into an existing account',
// value: 'login',
// },
{
label: `I'll do it later`,
value: 'remind-later',
},
],
}else if (alert_resp === 'login'){
let login_result = await UIWindowLogin({
show_signup_button: false,
reload_on_success: true,
send_confirmation_code: false,
window_options: {
show_in_taskbar: false,
backdrop: true,
close_on_backdrop_click: false,
}
})
if(alert_resp === 'remind-later'){
// TODO
}
if(alert_resp === 'save-session'){
let saved = await UIWindowSaveAccount({
send_confirmation_code: false,
});
}else if (alert_resp === 'login'){
let login_result = await UIWindowLogin({
show_signup_button: false,
reload_on_success: true,
send_confirmation_code: false,
window_options: {
show_in_taskbar: false,
backdrop: true,
close_on_backdrop_click: false,
}
});
// FIXME: Report login error.
}
}, window.desktop_loading_fade_delay + 1000);
}
});
// FIXME: Report login error.
}
}, window.desktop_loading_fade_delay + 1000);
}
})
});
}
window.onpopstate = (event) => {

174
src/helpers/globToRegExp.js Normal file
View File

@ -0,0 +1,174 @@
/**
* Copyright (C) 2024 Puter Technologies Inc.
*
* This file is part of Puter.
*
* Puter is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
/* globToRegExp is derived from: https://github.com/fitzgen/glob-to-regexp
*
* Copyright (c) 2013, Nick Fitzgerald All rights reserved.
* See full license text here: https://github.com/fitzgen/glob-to-regexp#license
*/
/**
* Converts a glob pattern to a regular expression, with optional extended or globstar matching.
*
* @param {string} glob - The glob pattern to convert.
* @param {Object} [opts] - Optional options for the conversion.
* @param {boolean} [opts.extended=false] - If true, enables extended matching with single character matching, character ranges, group matching, etc.
* @param {boolean} [opts.globstar=false] - If true, uses globstar matching, where '*' matches zero or more path segments.
* @param {string} [opts.flags] - Regular expression flags to include (e.g., 'i' for case-insensitive).
* @returns {RegExp} The generated regular expression.
* @throws {TypeError} If the provided glob pattern is not a string.
*/
const globToRegExp = function (glob, opts) {
if (typeof glob !== 'string') {
throw new TypeError('Expected a string');
}
var str = String(glob);
// The regexp we are building, as a string.
var reStr = "";
// Whether we are matching so called "extended" globs (like bash) and should
// support single character matching, matching ranges of characters, group
// matching, etc.
var extended = opts ? !!opts.extended : false;
// When globstar is _false_ (default), '/foo/*' is translated a regexp like
// '^\/foo\/.*$' which will match any string beginning with '/foo/'
// When globstar is _true_, '/foo/*' is translated to regexp like
// '^\/foo\/[^/]*$' which will match any string beginning with '/foo/' BUT
// which does not have a '/' to the right of it.
// E.g. with '/foo/*' these will match: '/foo/bar', '/foo/bar.txt' but
// these will not '/foo/bar/baz', '/foo/bar/baz.txt'
// Lastely, when globstar is _true_, '/foo/**' is equivelant to '/foo/*' when
// globstar is _false_
var globstar = opts ? !!opts.globstar : false;
// If we are doing extended matching, this boolean is true when we are inside
// a group (eg {*.html,*.js}), and false otherwise.
var inGroup = false;
// RegExp flags (eg "i" ) to pass in to RegExp constructor.
var flags = opts && typeof (opts.flags) === "string" ? opts.flags : "";
var c;
for (var i = 0, len = str.length; i < len; i++) {
c = str[i];
switch (c) {
case "/":
case "$":
case "^":
case "+":
case ".":
case "(":
case ")":
case "=":
case "!":
case "|":
reStr += "\\" + c;
break;
case "?":
if (extended) {
reStr += ".";
break;
}
// fallthrough
case "[":
case "]":
if (extended) {
reStr += c;
break;
}
// fallthrough
case "{":
if (extended) {
inGroup = true;
reStr += "(";
break;
}
// fallthrough
case "}":
if (extended) {
inGroup = false;
reStr += ")";
break;
}
// fallthrough
case ",":
if (inGroup) {
reStr += "|";
break;
}
reStr += "\\" + c;
break;
case "*":
// Move over all consecutive "*"'s.
// Also store the previous and next characters
var prevChar = str[i - 1];
var starCount = 1;
while (str[i + 1] === "*") {
starCount++;
i++;
}
var nextChar = str[i + 1];
if (!globstar) {
// globstar is disabled, so treat any number of "*" as one
reStr += ".*";
} else {
// globstar is enabled, so determine if this is a globstar segment
var isGlobstar = starCount > 1 // multiple "*"'s
&& (prevChar === "/" || prevChar === undefined) // from the start of the segment
&& (nextChar === "/" || nextChar === undefined) // to the end of the segment
if (isGlobstar) {
// it's a globstar, so match zero or more path segments
reStr += "((?:[^/]*(?:/|$))*)";
i++; // move over the "/"
} else {
// it's not a globstar, so only match one path segment
reStr += "([^/]*)";
}
}
break;
default:
reStr += c;
}
}
// When regexp 'g' flag is specified don't
// constrain the regular expression with ^ & $
if (!flags || !~flags.indexOf('g')) {
reStr = "^" + reStr + "$";
}
return new RegExp(reStr, flags);
};
export default globToRegExp;