init commit

This commit is contained in:
MeexReay 2025-03-19 01:12:43 +03:00
parent 3a2e36e487
commit 8bd84c5af5
31 changed files with 1337 additions and 0 deletions

35
app/hello/hello.js Normal file
View File

@ -0,0 +1,35 @@
/*
Hello message
*/
const message = `Приветствуем в PoshlostiOS!!!!
Стандартные komandi:
* cd <dir> - перемещение по папкам
* hello - эт кодмана
* ls [dir] - посмотреть список файлов
* meow <text> - чтото пробормотать
* posh [command] - типа херня которая команды обрабатывает
* vget <url> <file> - скачать файлы из интернетов
* clear - стереть терминал
* rm <file> - удалить файл
* mv <src> <dest> - переместить файл
* bump <file> - создать файл
* cp <src> <dest> - скопировать файл
* mkdir <dir> - создать папку
* reset - УНИЧТОЖИТЬ СИСТЕМУ, и установить заново :3
* cat <file> - показать содержимое файла
* ppm <i/s/r/u/A/a/l> [package] - пакетный менеджер
Планируется:
* сделать hex цвета
* прога Worldwide Objective Manuals (WOMan) которая пишет туторы по пакетам, написанию прог и описание стандартных прог
* прога чтото наподобе nano или vi
`
async function main(args) {
writeStdout(message)
return 0
}

8
app/hello/package.json Normal file
View File

@ -0,0 +1,8 @@
{
"name": "hello",
"version": "0.1.2",
"description": "Hello Message",
"author": "MeexReay",
"apps": [ "hello.js" ],
"configs": []
}

82
app/neofetch/neofetch.js Normal file
View File

@ -0,0 +1,82 @@
/*
neofetch - neofetch
*/
function getDurationString(start_time) {
const now = new Date();
const diffMs = now - start_time;
const seconds = Math.floor(diffMs / 1000);
const minutes = Math.floor(seconds / 60);
const hours = Math.floor(minutes / 60);
const days = Math.floor(hours / 24);
const remainingHours = hours % 24;
const remainingMinutes = minutes % 60;
let result = [];
if (days > 0) result.push(`${days}d`);
if (remainingHours > 0) result.push(`${remainingHours}h`);
result.push(`${remainingMinutes}m`);
return result.join(" ");
}
// Function to get CPU, GPU, and memory information
function getSystemInfo() {
const cpuInfo = navigator.hardwareConcurrency;
const memoryInfo = navigator.deviceMemory;
const totalJSHeap = performance.memory.totalJSHeapSize / (1024 * 1024);
const canvas = document.createElement('canvas');
const gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
let gpuInfo = null;
if (gl) {
const debugInfo = gl.getExtension('WEBGL_debug_renderer_info');
if (debugInfo) {
gpuInfo = {
vendor: gl.getParameter(debugInfo.UNMASKED_VENDOR_WEBGL),
renderer: gl.getParameter(debugInfo.UNMASKED_RENDERER_WEBGL)
};
}
}
return [
cpuInfo + " cores",
memoryInfo ? memoryInfo * 1024 + ' MB' : 'Not supported',
totalJSHeap.toFixed(2) + ' MB',
gpuInfo ? `${gpuInfo.renderer}` : 'GPU Info not available'
]
}
async function main(args) {
let [cpu, max_mem, now_mem, gpu] = getSystemInfo()
writeStdout(`
user@poshlosti
------------------
OS: PoshlostiOS
Uptime: ${getDurationString(start_date)}
Packages: ${(await listPackages()).length} (ppm)
Shell: posh ${(await getInstalledPackage("posh")).version}
Resolution: ${window.innerWidth}x${window.innerHeight}
Memory: ${now_mem} / ${max_mem}
CPU: ${cpu}
GPU: ${gpu}
`)
return 0
}

View File

@ -0,0 +1,8 @@
{
"name": "neofetch",
"version": "0.1.1",
"description": "neofetch damn",
"author": "MeexReay",
"apps": [ "neofetch.js" ],
"configs": []
}

9
app/posh/cd.js Normal file
View File

@ -0,0 +1,9 @@
async function main(args) {
if (!hasFile(args[1])) {
writeStdout(`нет такой папки бро\n`)
return 1
}
cwd = simplifyPath(args[1])
writeStdout(`бро переместил тебя в ${args[1]} без б ваще обращайся\n`)
return 0
}

4
app/posh/clear.js Normal file
View File

@ -0,0 +1,4 @@
async function main(args) {
clearTerminal()
return 0
}

4
app/posh/meow.js Normal file
View File

@ -0,0 +1,4 @@
async function main(args) {
writeStdout(args.slice(1).join(" ")+"\n")
return 0
}

8
app/posh/package.json Normal file
View File

@ -0,0 +1,8 @@
{
"name": "posh",
"version": "0.1.1",
"description": "Poshlosti Shell",
"author": "MeexReay",
"apps": [ "posh.js", "meow.js", "cd.js", "clear.js" ],
"configs": [ "posh.json" ]
}

93
app/posh/posh.js Normal file
View File

@ -0,0 +1,93 @@
/*
PoSh - Poshlosti Shell
*/
async function processCommand(command, args) {
let executable = command
if (!executable.startsWith("/")) {
if (executable.includes("/")) {
executable = cwd + "/" + executable
} else {
executable = "/app/" + executable
}
}
if (!hasFile(executable) && hasFile(executable+".js")) {
executable = executable + ".js"
}
executable = simplifyPath(executable)
if (hasFile(executable)) {
try {
let code = await executeCommand([executable].concat(args)).promise
if (code != 0) {
await writeStdout("\nСтатус код: "+code+"\n")
}
} catch (e) {
console.log(e)
await writeStdout("Не запустилася\n")
}
} else {
await writeStdout("Твоя команда "+executable+" не найдена :3\n")
}
}
async function main(args) {
if (args.length > 1) {
await processCommand(args[1], args.slice(2))
}
let history = [""]
let history_index = 0
let config = JSON.parse(readFile("/config/posh.json"))
let prompt = config["prompt"]
let startup = config["startup"]
for (let command of startup) {
let args = command.split(" ")
await processCommand(args[0], args.slice(1))
}
while (true) {
await writeStdout(prompt.replace("{cwd}", cwd))
let command = await readLine((key, ctrl, alt, shift, content, pos) => {
console.log(history, content, pos, key)
if (key == "ArrowDown") {
history_index = Math.max(0, history_index - 1)
return [history[history_index], history[history_index].length]
}
if (key == "ArrowUp") {
history_index = Math.min(history.length-1, history_index + 1)
return [history[history_index], history[history_index].length]
}
return [content, pos]
})
if (command.length > 0) {
history.splice(1, 0, command);
history_index = 0
let args = command.split(" ")
command = args[0]
args = args.slice(1)
if (command == "exit") {
if (args.length == 0) {
return 0
} else {
return parseInt(args[0])
}
} else {
await processCommand(command, args)
}
}
}
return 0
}

7
app/posh/posh.json Normal file
View File

@ -0,0 +1,7 @@
{
"prompt": "[posh {cwd}]$ ",
"startup": [
"hello",
"meow"
]
}

8
app/ppm/package.json Normal file
View File

@ -0,0 +1,8 @@
{
"name": "ppm",
"version": "0.1.3",
"description": "Poshliy Package Manager",
"author": "MeexReay",
"apps": [ "ppm.js" ],
"configs": [ "ppm.json" ]
}

124
app/ppm/ppm.js Normal file
View File

@ -0,0 +1,124 @@
/*
PPM - Poshliy Package Manager
*/
async function main(args) {
if (args.length == 3 && "iurs".includes(args[1])) {
let package = args[2]
if (args[1] == "i") {
let config = JSON.parse(readFile("/config/ppm.json"))
for (const repo of config["repositories"]) {
// await writeStdout(`Фетчим ${package} на репозитории ${repo}\n`)
let status = await installPackage(repo+"/"+package)
if (status == 0) {
let pkg = await getInstalledPackage(package)
await writeStdout(`Пакет ${pkg['name']}-${pkg['version']} установлен\n`)
return 0
} else if (status == 1) {
await writeStdout("Пакет не установлен тк он уже установлен чувааак\n")
return 1
}
}
} else if (args[1] == "u") {
let config = JSON.parse(readFile("/config/ppm.json"))
for (const repo of config["repositories"]) {
let status = await updatePackage(package, repo+"/"+package)
if (status == 0) {
let pkg = await getInstalledPackage(package)
await writeStdout(`Пакет ${pkg['name']}-${pkg['version']} обновлен\n`)
return 0
} else if (status == 1) {
await writeStdout("Пакет не найден ты его установи сначала чел\n")
return 1
}
}
await writeStdout("обнова не прошла успешна\n")
return 1
} else if (args[1] == "r") {
if (await removePackage(package)) {
await writeStdout(`Пакет ${package} удален\n`)
} else {
await writeStdout("Биспокойся произошла ошибко\n")
return 1
}
} else if (args[1] == "s") {
let pkg = await getInstalledPackage(package)
for (const [key, value] of Object.entries(pkg)) {
await writeStdout(key.charAt(0).toUpperCase()+key.slice(1)+": "+value+"\n")
}
}
} else if (args.length == 2 && args[1] == "l") {
await writeStdout("ваши покеты:\n")
for (const package of (await listPackages())) {
await writeStdout("- "+package["name"]+"-"+package["version"]+"\n")
}
} else if (args.length == 2 && args[1] == "a") {
let config = JSON.parse(readFile("/config/ppm.json"))
for (const package of (await listPackages())) {
for (const repo of config["repositories"]) {
// await writeStdout(`Фетчим ${package["name"]} на репозитории ${repo}\n`)
let fetched = await fetchPackage(repo+"/"+package["name"])
if (fetched != null) {
if (fetched["version"] == package["version"]) {
await writeStdout(`Пакет ${package['name']}-${package['version']} уже на последней версии\n`)
break
}
let status = await updatePackage(package["name"], repo+"/"+package["name"])
if (status == 0) {
let pkg = await getInstalledPackage(package["name"])
await writeStdout(`Пакет ${pkg['name']}-${pkg['version']} обновлен\n`)
break
} else if (status == 1) {
break
}
}
}
}
await writeStdout("Обнова прошла успешна\n")
return 0
} else if (args.length == 2 && args[1] == "A") {
let config = JSON.parse(readFile("/config/ppm.json"))
for (const package of (await listPackages())) {
for (const repo of config["repositories"]) {
let status = await updatePackage(package["name"], repo+"/"+package["name"])
if (status == 0) {
let pkg = await getInstalledPackage(package["name"])
await writeStdout(`Пакет ${pkg['name']}-${pkg['version']} обновлен\n`)
break
} else{
console.log(status, repo, package)
}
}
}
await writeStdout("Обнова прошла успешна\n")
return 0
} else {
await writeStdout("Использование:\n")
await writeStdout(" ppm i <пакет> - установить пакет\n")
await writeStdout(" ppm u <пакет> - обновить пакет\n")
await writeStdout(" ppm r <пакет> - удалить пакет\n")
await writeStdout(" ppm s <пакет> - показать инфу о пакете\n")
await writeStdout(" ppm l - показать инфу о пакете\n")
await writeStdout(" ppm a - обновить все пакеты\n")
await writeStdout(" ppm A - обновить все пакеты принудительно\n")
}
return 0
}

5
app/ppm/ppm.json Normal file
View File

@ -0,0 +1,5 @@
{
"repositories": [
"https://poshlostios.meex.lol/app"
]
}

5
app/putils/bump.js Normal file
View File

@ -0,0 +1,5 @@
async function main(args) {
writeFile(args[1], "")
writeStdout(`все твой файл создан ${args[1]} такой же ты хотел жа\n`)
return 0
}

8
app/putils/cat.js Normal file
View File

@ -0,0 +1,8 @@
async function main(args) {
if (!hasFile(args[1])) {
writeStdout(`нет такой faila бро\n`)
return 1
}
writeStdout(readFile(args[1])+"\n")
return 0
}

55
app/putils/cp.js Normal file
View File

@ -0,0 +1,55 @@
async function main(args=["","",""]) {
let source = simplifyPath(args[1])
let target = simplifyPath(args[2])
if (!hasFile(args[1])) {
writeStdout(`нет такой херни чо мне ты даешь долбан X нету :x: :regional_symbol_x: :cross:\n`)
return 1
}
if (isFolder(source)) {
if (!hasFile(target) || isFolder(target)) {
let create_dirs = hasFile(target) ? [] : [target]
let write_files = []
let recursive = (folder) => {
for (const file of listFiles(folder)) {
let path = folder+"/"+file
if (isFolder(path)) {
create_dirs.push(path)
recursive(path)
} else {
write_files.push(path)
}
}
}
recursive(source)
for (const dir of create_dirs) {
createFolder(target + dir.slice(source.length))
}
for (const file of write_files) {
let path = target + file.slice(source.length)
writeFile(path, readFile(file))
}
} else {
writeStdout("ой сукаа я вахуе\n")
return 1
}
} else {
if (isFolder(target)) {
target = target+"/"+source.split("/").reverse()[0]
}
let content = readFile(source)
writeFile(target, content)
}
removeFile(source)
writeStdout(`все скопировано бро ${source} в ${target} скопировано спомощье команды CP (ЦП)\n`)
return 0
}

12
app/putils/ls.js Normal file
View File

@ -0,0 +1,12 @@
async function main(args) {
if (args.length < 2) {
writeStdout(listFiles(".").map(o => {
return (isFolder(o) ? "DIR " : "FILE") + " " + simplifyPath(o)
}).join("\n")+"\n")
} else {
writeStdout(listFiles(args[1]).map(o => {
return (isFolder(args[1]+"/"+o) ? "DIR " : "FILE") + " " + simplifyPath(args[1]+"/"+o)
}).join("\n")+"\n")
}
return 0
}

5
app/putils/mkdir.js Normal file
View File

@ -0,0 +1,5 @@
async function main(args) {
createFolder(args[1])
writeStdout(`папка создана ${args[1]}\n`)
return 0
}

55
app/putils/mv.js Normal file
View File

@ -0,0 +1,55 @@
async function main(args=["","",""]) {
let source = simplifyPath(args[1])
let target = simplifyPath(args[2])
if (!hasFile(args[1])) {
writeStdout(`бро я б помог сделал что ты хочешь но сука нет такого файла бай бай\n`)
return 1
}
if (isFolder(source)) {
if (!hasFile(target) || isFolder(target)) {
let create_dirs = hasFile(target) ? [] : [target]
let write_files = []
let recursive = (folder) => {
for (const file of listFiles(folder)) {
let path = folder+"/"+file
if (isFolder(path)) {
create_dirs.push(path)
recursive(path)
} else {
write_files.push(path)
}
}
}
recursive(source)
for (const dir of create_dirs) {
createFolder(target + dir.slice(source.length))
}
for (const file of write_files) {
let path = target + file.slice(source.length)
writeFile(path, readFile(file))
}
} else {
writeStdout("как по твоему я должен блять переместить папку в файл ты ебнутый сука\n")
return 1
}
} else {
if (isFolder(target)) {
target = target+"/"+source.split("/").reverse()[0]
}
let content = readFile(source)
writeFile(target, content)
}
removeFile(source)
writeStdout(`все перемещено чо надо то есть ${source} в ${target} ну изи получается\n`)
return 0
}

8
app/putils/package.json Normal file
View File

@ -0,0 +1,8 @@
{
"name": "putils",
"version": "0.1.0",
"description": "Poshliye Utiliti",
"author": "MeexReay",
"apps": [ "bump.js", "cat.js", "cp.js", "ls.js", "mkdir.js", "mv.js", "rm.js" ],
"configs": []
}

9
app/putils/rm.js Normal file
View File

@ -0,0 +1,9 @@
async function main(args) {
if (!hasFile(args[1])) {
writeStdout(`я вахуе ну ты же знаешь что такого файла нет нахуй ты это делаешь\n`)
return 1
}
removeFile(args[1])
writeStdout(`ну все твой файл ${args[1]} удален ДОВОЛЕН ЧТО ТЫ СДЕЛАЛ?\n`)
return 0
}

8
app/reset/package.json Normal file
View File

@ -0,0 +1,8 @@
{
"name": "reset",
"version": "0.1.0",
"description": "Resets system to a newborn",
"author": "MeexReay",
"apps": [ "reset.js" ],
"configs": []
}

18
app/reset/reset.js Normal file
View File

@ -0,0 +1,18 @@
async function main(args) {
await writeStdout("Ты уверен, что хочешь стереть систему, и установить снова?? (y/n) > ")
let confirm = (await readLine()).toLowerCase() == "y"
if (confirm) {
await new Promise(r => setTimeout(r, 100));
await writeStdout("Прощай...")
await new Promise(r => setTimeout(r, 2000));
await resetSystem()
document.location.reload()
for (const c of Array.from("\nвелосипе")) {
await writeStdout(c)
await new Promise(r => setTimeout(r, 30));
}
await new Promise(r => setTimeout(r, 999999));
}
return 0
}

8
app/vget/package.json Normal file
View File

@ -0,0 +1,8 @@
{
"name": "vget",
"version": "0.1.0",
"description": "Vulgar get",
"author": "MeexReay",
"apps": [ "vget.js" ],
"configs": []
}

17
app/vget/vget.js Normal file
View File

@ -0,0 +1,17 @@
/*
VGet - Vulgar Get
*/
async function main(args) {
if (args.length != 3) {
writeStdout("vget <url> <path>\n")
return 1
}
writeFile(args[2], await (await fetch(args[0])).text())
writeStdout("Файл "+args[1]+" вставлен внутрь пути "+args[2]+"\n")
return 0
}

BIN
font/terminus.ttf Normal file

Binary file not shown.

77
index.html Normal file
View File

@ -0,0 +1,77 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>PoshlostiOS</title>
<link rel="apple-touch-icon" sizes="180x180" href="/icon/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="/icon/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/icon/favicon-16x16.png">
<link rel="manifest" href="/icon/site.webmanifest">
<style>
@font-face {
font-family: 'terminus';
src: url('font/terminus.ttf'); /* Legacy iOS */
}
:root {
--BLACK: rgb(12,12,12);
--DARK_BLUE: rgb(0,55,218);
--DARK_GREEN: rgb(19,161,14);
--DARK_CYAN: rgb(58,150,221);
--DARK_RED: rgb(197,15,31);
--DARK_MAGENTA: rgb(136,23,152);
--DARK_YELLOW: rgb(193,156,0);
--DARK_WHITE: rgb(204,204,204);
--BRIGHT_BLACK: rgb(118,118,118);
--BRIGHT_BLUE: rgb(59,120,255);
--BRIGHT_GREEN: rgb(22,198,12);
--BRIGHT_CYAN: rgb(97,214,214);
--BRIGHT_RED: rgb(231,72,86);
--BRIGHT_MAGENTA: rgb(180,0,158);
--BRIGHT_YELLOW: rgb(249,241,165);
--WHITE: rgb(242,242,242);
}
* {
font-family: "terminus";
font-size: 20px
}
body {
background-color: var(--BLACK);
color: var(--WHITE);
/* overflow: hidden; */
user-select: none;
}
#cursor {
position: absolute;
}
#clipboard-collect {
opacity: 0;
position: absolute;
left: 0;
right: 0;
}
#terminal {
white-space: pre;
width: 100%;
display: block;
}
</style>
</head>
<body>
<span id="terminal"></span><span id="cursor">_<input type="text" id="clipboard-collect"></span>
</body>
<script src="sys/terminal.js"></script>
<script src="sys/fs.js"></script>
<script src="sys/ppm.js"></script>
<script src="sys/system.js"></script>
</html>

223
sys/fs.js Normal file
View File

@ -0,0 +1,223 @@
var fs_mapping = {}
function saveMapping() {
localStorage.setItem("fs_mapping", JSON.stringify(fs_mapping))
}
function loadMapping() {
if (localStorage.getItem("fs_mapping") == null) {
fs_mapping = {}
} else {
fs_mapping = JSON.parse(localStorage.getItem("fs_mapping"))
}
}
loadMapping()
function getMappingCode(path) {
let parts = (path.startsWith("/") ? path.slice(1) : path).split("/")
let now = fs_mapping
let index = 0
for (const part of parts) {
if (Object.keys(now).includes(part)) {
if (index == parts.length-1) {
return "file_"+now[part]
} else {
now = now[part]
}
} else {
return null
}
index++
}
return null
}
function createMappingCode(path) {
if (path.length === 0) return null
let code = 0, i, chr
for (i = 0; i < path.length; i++) {
chr = path.charCodeAt(i)
code = ((code << 5) - code) + chr
code |= 0
}
let parts = (path.startsWith("/") ? path.slice(1) : path).split("/")
let now = fs_mapping
let index = 0
for (const part of parts) {
if (index == parts.length-1) {
now[part] = code
} else if (Object.keys(now).includes(part)) {
now = now[part]
} else {
return null
}
index++
}
saveMapping()
return "file_"+code
}
function createMappingFolder(path) {
let parts = (path.startsWith("/") ? path.slice(1) : path).split("/")
let now = fs_mapping
let index = 0
for (const part of parts) {
if (index == parts.length-1) {
now[part] = {}
} else if (Object.keys(now).includes(part)) {
now = now[part]
} else {
return null
}
index++
}
saveMapping()
return null
}
function listMappingFolder(path) {
if (path == "/") return Object.keys(fs_mapping)
let parts = (path.startsWith("/") ? path.slice(1) : path).split("/")
let now = fs_mapping
let index = 0
for (const part of parts) {
if (Object.keys(now).includes(part)) {
if (index == parts.length-1) {
return Object.keys(now[part])
} else {
now = now[part]
}
} else {
return null
}
index++
}
return null
}
function isMappingFolder(path) {
let parts = (path.startsWith("/") ? path.slice(1) : path).split("/")
let now = fs_mapping
let index = 0
for (const part of parts) {
if (Object.keys(now).includes(part)) {
if (index == parts.length-1) {
return typeof now[part] === "object"
} else {
now = now[part]
}
} else {
return null
}
index++
}
return null
}
function removeMappingEntry(path) {
let parts = (path.startsWith("/") ? path.slice(1) : path).split("/")
let now = fs_mapping
let index = 0
for (const part of parts) {
if (Object.keys(now).includes(part)) {
if (index == parts.length-1) {
delete now[part]
saveMapping()
} else {
now = now[part]
}
} else {
return null
}
index++
}
return null
}
function readFile(path) {
path = simplifyPath(path)
return localStorage.getItem(getMappingCode(path))
}
function writeFile(path, content) {
path = simplifyPath(path)
let code = getMappingCode(path)
if (code == null) code = createMappingCode(path)
localStorage.setItem(code, content)
}
function hasFile(path) {
path = simplifyPath(path)
return getMappingCode(path) != null
}
function listFiles(path) {
path = simplifyPath(path)
return listMappingFolder(path)
}
function createFolder(path) {
createMappingFolder(simplifyPath(path))
}
function removeFile(path) {
path = simplifyPath(path)
if (!isFolder(path)) {
localStorage.removeItem(getMappingCode(path))
}
removeMappingEntry(path)
}
function isFolder(path) {
path = simplifyPath(path)
return isMappingFolder(path)
}
function simplifyPath(path) {
if (!path.startsWith("/")) path = cwd+"/" + path;
const segments = path.split('/');
const stack = [];
for (let segment of segments) {
if (segment === '' || segment === '.') {
continue;
} else if (segment === '..') {
if (stack.length > 0) {
stack.pop();
}
} else {
stack.push(segment);
}
}
const simplifiedPath = '/' + stack.join('/');
return simplifiedPath;
}
function clearFileSystem() {
let callback = (x) => {
for (const o of Object.values(x)) {
if (typeof o === "object") {
callback(o)
} else {
localStorage.removeItem("file_"+o)
}
}
}
callback(fs_mapping)
fs_mapping = {}
saveMapping()
}

128
sys/ppm.js Normal file
View File

@ -0,0 +1,128 @@
async function fetchPackage(url) {
try {
return await fetchJson(url+"/package.json")
} catch (error) {
return null
}
}
async function getInstalledPackage(name) {
if (!hasFile("/etc/ppm/"+name)) {
return null
}
return JSON.parse(readFile("/etc/ppm/"+name))
}
async function listPackages() {
let packages = []
for (const name of listFiles("/etc/ppm")) {
packages.push(JSON.parse(readFile("/etc/ppm/"+name)))
}
return packages
}
async function fetchJson(url) {
for (let i = 0; i < 10; i++) {
try {
return await fetch(url).then(o => o.json())
} catch (error) {
continue
}
}
return null
}
async function fetchText(url) {
for (let i = 0; i < 10; i++) {
try {
return await fetch(url).then(o => o.text())
} catch (error) {
continue
}
}
return null
}
async function installPackage(url) {
let package
try {
package = await fetch(url+"/package.json").then(o => o.json())
} catch (error) {
return 2
}
if (!hasFile("/etc/ppm")) {
createFolder("/etc/ppm")
}
if (hasFile("/etc/ppm/"+package["name"])) {
return 1
}
if ("apps" in package) {
for (const app of package.apps) {
writeFile("/app/"+app, await fetchText(url+"/"+app))
}
}
if ("configs" in package) {
for (const config of package.configs) {
writeFile("/config/"+config, await fetchText(url+"/"+config))
}
}
writeFile("/etc/ppm/"+package["name"], JSON.stringify(package))
return 0
}
async function removePackage(name) {
let package = await getInstalledPackage(name)
if (package == null) return false
if ("apps" in package) {
for (const app of package.apps) {
removeFile("/app/"+app)
}
}
if ("configs" in package) {
for (const config of package.configs) {
removeFile("/config/"+config)
}
}
removeFile("/etc/ppm/"+name)
return true
}
async function updatePackage(name, url) {
let package = await getInstalledPackage(name)
if (package == null) return 1
if ("apps" in package) {
for (const app of package.apps) {
removeFile("/app/"+app)
}
}
try {
package = await fetch(url+"/package.json").then(o => o.json())
} catch (error) {
return 2
}
if ("apps" in package) {
for (const app of package.apps) {
writeFile("/app/"+app, await fetchText(url+"/"+app))
}
}
writeFile("/etc/ppm/"+name, JSON.stringify(package))
return 0
}

190
sys/system.js Normal file
View File

@ -0,0 +1,190 @@
var cwd = "/home"
var stdout = ""
var stdin = ""
var disable_stdin = true
var silent_stdin = false
var processes = []
const RENDER_STDIN = 1
const SILENT_STDIN = 2
const DISABLE_STDIN = 3
const ENABLE_STDIN = 4
async function readLine(on_key=(key, ctrl, alt, shift, content, pos) => [content, pos]) {
setStdinFlag(ENABLE_STDIN)
let start_cursor_pos = getCursor()
let pos = 0
let content = ""
while (true) {
let event = await pollStdinEvent()
if (event.type == "key") {
if (event.key == "Backspace") {
if (content.length >= 1) {
content = content.substring(0, content.length-1)
trimTerminal(1)
}
} else if (event.key == "ArrowLeft") {
let cursor = getCursor()
if (cursor[0] > start_cursor_pos[0]) {
setCursor(cursor[0]-1, cursor[1])
pos -= 1
}
} else if (event.key == "ArrowRight") {
let cursor = getCursor()
if (cursor[0] < start_cursor_pos[0] + content.length) {
setCursor(cursor[0]+1, cursor[1])
pos += 1
}
} else {
let res = on_key(key, is_ctrl, is_alt, is_shift, content, pos)
terminal_text = terminal_text.slice(0, terminal_text.length - content.length) + res[0]
updateTerminal()
setCursor(start_cursor_pos[0] + res[1], start_cursor_pos[1])
content = res[0]
pos = res[1]
}
continue
} else if (event.type == "char") {
if (event.char == "\n") break
content = content.slice(0, pos) + event.char + content.slice(pos)
pos += 1
}
}
setStdinFlag(DISABLE_STDIN)
return content
}
async function pollStdinEvent() {
let char = await readStdin()
if (char == "\r") {
let key = ""
char = await readStdin()
while (char != "\r") {
key += char
char = await readStdin()
}
let is_ctrl = key.charAt(0) == "1"
let is_alt = key.charAt(1) == "1"
let is_shift = key.charAt(2) == "1"
key = key.slice(3)
return {
"type": "key",
"ctrl": is_ctrl,
"alt": is_alt,
"shift": is_shift,
"key": key
}
}
return {
"type": "char",
"char": char
}
}
async function readStdin() {
while (stdin.length == 0) {
await new Promise(resolve => setTimeout(resolve, 10))
}
let was_stdin = stdin.charAt(0)
stdin = stdin.slice(1)
return was_stdin
}
async function writeStdout(content) {
stdout += content
writeTerminal(content)
}
function setStdinFlag(flag) {
if (flag == 1) {
silent_stdin = true
} else if (flag == 2) {
silent_stdin = false
} else if (flag == 3) {
disable_stdin = true
} else if (flag == 4) {
disable_stdin = false
}
}
function executeCommand(args, read=readStdin, write=writeStdout) {
let id = new Date().getMilliseconds().toString()+(Math.random()*100)
let func_content = readFile(args[0])
if (func_content == null || !func_content.includes("function main")) return
let func = new Function("args", "readStdin", "writeStdout", func_content+"\n\nreturn main(args)")
let process = {
"id": id,
"name": args.join(" "),
"promise": new Promise((resolve, reject) => {
setTimeout(() => {
try {
resolve(func(args, read, write))
} catch (e) {
console.log(e)
reject(e)
}
}, 0)
}).then(o => {
processes = processes.filter(x => x.id != id)
return o
})
}
processes.push(process)
return process
}
function loadApp(name) {
fetch("app/"+name+".js")
.then(o => o.text())
.then(o => {
writeFile("/app/"+name+".js", o)
})
}
function loadAppAndExecute(name) {
fetch("app/"+name+".js")
.then(o => o.text())
.then(o => {
writeFile("/app/"+name+".js", o)
})
}
async function resetSystem() {
clearFileSystem()
createFolder("/")
createFolder("/home")
createFolder("/app")
createFolder("/config")
createFolder("/temp")
createFolder("/etc")
await installPackage("app/hello")
await installPackage("app/posh")
await installPackage("app/ppm")
await installPackage("app/putils")
await installPackage("app/reset")
await installPackage("app/vget")
}
if (Object.keys(fs_mapping).length == 0) {
resetSystem()
}
executeCommand(["/app/posh.js"])
var start_date = new Date()

116
sys/terminal.js Normal file
View File

@ -0,0 +1,116 @@
const CHAR_SIZE = [10, 22]
const CURSOR_OFFSET = [10, 10]
var terminal = document.getElementById("terminal")
var terminal_text = ""
var last_stdin_length = 0
function writeTerminalAtCursor(content) {
let cursor_index = getCursorIndex()
terminal_text = terminal_text.slice(0, cursor_index) + content + terminal_text.slice(cursor_index)
setCursor(cursor_pos[0]+1, cursor_pos[1])
last_stdin_length += 1
updateTerminalWOCursor()
}
function writeTerminal(content) {
terminal_text += content
last_stdin_length = 0
updateTerminal()
}
function replaceTerminal(content) {
terminal_text = content
updateTerminal()
}
function trimTerminal(length) {
terminal_text = terminal_text.substring(0, terminal_text.length-length)
updateTerminal()
}
function clearTerminal() {
terminal_text = ""
updateTerminal()
}
function updateTerminalWOCursor() {
terminal.innerText = terminal_text
}
function updateTerminal() {
setCursor(
terminal_text.split("\n").reverse()[0].length,
terminal_text.split("\n").length-1
)
updateTerminalWOCursor()
}
var cursor = document.getElementById("cursor")
var cursor_pos = [0, 0]
function getCursorIndex() {
let lines = terminal_text.split("\n")
let index = 0
for (let y = 0; y < lines.length; y++) {
const line = lines[y];
const length = line.length
if (y == cursor_pos[1]) {
return index + cursor_pos[0]
}
index += length + 1
}
return 0
}
function getCursor() {
return cursor_pos
}
function setCursor(x, y) {
cursor_pos = [x, y]
updateCursor()
}
function updateCursor() {
cursor.style["top"] = cursor_pos[1] * CHAR_SIZE[1] + CURSOR_OFFSET[1] + "px"
cursor.style["left"] = cursor_pos[0] * CHAR_SIZE[0] + CURSOR_OFFSET[0] + "px"
cursor.scrollIntoView({behavior: "smooth", inline: "end"})
}
document.onkeydown = (e) => {
let key = e.key;
if (!disable_stdin) {
if (key == "Enter") {
stdin += "\n"
if (!silent_stdin) {
writeTerminal("\n")
}
} else if (key.length == 1) {
if (e.ctrlKey && key == "v") return
stdin += key
if (!silent_stdin) {
writeTerminalAtCursor(key)
}
} else {
stdin += "\r"+(e.ctrlKey ? "1" : "0")+(e.altKey ? "1" : "0")+(e.shiftKey ? "1" : "0")+e.key+"\r"
}
}
}
var clipboard_collect = document.getElementById("clipboard-collect")
setInterval(() => {
clipboard_collect.focus()
});
clipboard_collect.onpaste = (e) => {
let paste = (e.clipboardData || window.clipboardData).getData("text");
if (paste != null) {
stdin += paste.replace("\r", "")
writeTerminal(paste)
}
}