mirror of
https://github.com/HeyPuter/puter.git
synced 2026-11-13 20:12:57 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1f659f7c01 | ||
|
|
c84e15ba20 | ||
|
|
86fd2f4bc4 | ||
|
|
1f3eb08a70 | ||
|
|
cb8f0aa359 | ||
|
|
58ff7c279d | ||
|
|
1f8cd7f613 | ||
|
|
94c0449437 | ||
|
|
6603c45093 | ||
|
|
30f9f29982 | ||
|
|
594424444a | ||
|
|
4078a63fe1 | ||
|
|
ad56091c2f | ||
|
|
fd39f92ea6 | ||
|
|
283f409a66 | ||
|
|
a8474054cc | ||
|
|
10f4d7d50c | ||
|
|
e73d55b2c0 | ||
|
|
f2b551d5be | ||
|
|
af083b0800 | ||
|
|
fd41ae217c | ||
|
|
fdea7907be | ||
|
|
11cfa83193 | ||
|
|
c88ce8e68c | ||
|
|
c47556d1b7 | ||
|
|
e6cdca09cc | ||
|
|
5e5a18565f | ||
|
|
2fbe6a6b26 | ||
|
|
c5f4ff5a49 | ||
|
|
841c8bf9f2 | ||
|
|
70b9b6f088 | ||
|
|
45840067f9 | ||
|
|
2a91edb965 | ||
|
|
edc5743a61 | ||
|
|
d3f3e089d3 | ||
|
|
7c227ad967 | ||
|
|
a43cab0c93 | ||
|
|
c23e8931ab | ||
|
|
d6dd04f195 | ||
|
|
7811294f33 | ||
|
|
016633cfbb | ||
|
|
4c26ebe3ac | ||
|
|
ce50718f84 | ||
|
|
cb5184f2f1 | ||
|
|
ce2b38c084 | ||
|
|
69332e14e7 | ||
|
|
37dca86506 | ||
|
|
812480bbd0 | ||
|
|
ef298ce3aa | ||
|
|
c8abe2380f | ||
|
|
d0cb0a96de | ||
|
|
ac7fe1e436 | ||
|
|
28a9469914 | ||
|
|
bf27811167 | ||
|
|
31bf69f10e | ||
|
|
5e78690b97 | ||
|
|
d0758631ea | ||
|
|
c9e2427ad6 | ||
|
|
a9c33da151 | ||
|
|
7d2f6d256f | ||
|
|
4af279a72f | ||
|
|
0855f2b36e | ||
|
|
dcbca2f829 | ||
|
|
de7e2adabd | ||
|
|
d55f38ca68 | ||
|
|
3633349700 | ||
|
|
77211c4f71 | ||
|
|
c0063a871f | ||
|
|
80ea655d05 | ||
|
|
d9c4fbbd1d | ||
|
|
75a989a7b6 | ||
|
|
d76e7130cb | ||
|
|
4539408a21 | ||
|
|
e2ea57fcf9 | ||
|
|
b7133760df | ||
|
|
91e9fa7c25 | ||
|
|
2f5b9cc4ee | ||
|
|
2f163221bd | ||
|
|
a0f4292072 | ||
|
|
1429d6f57c | ||
|
|
b10302ad74 | ||
|
|
88d6bee954 | ||
|
|
9ad04cd33f | ||
|
|
332371fccb | ||
|
|
95e1268527 | ||
|
|
d077504f9b | ||
|
|
711dbc0d2f | ||
|
|
adcd3db0ed | ||
|
|
45cdfcb5bf | ||
|
|
351d3f50ba | ||
|
|
73d0f5a90c | ||
|
|
dd10a37749 | ||
|
|
fa3df72f6e | ||
|
|
2e4259d267 | ||
|
|
bab5204209 | ||
|
|
4ba8a32b45 | ||
|
|
a68037111a | ||
|
|
b6906bbcaa | ||
|
|
60976b1ed6 | ||
|
|
955154468f | ||
|
|
057b3acf00 | ||
|
|
2c9b1a3ffc | ||
|
|
d6dd1a5bb0 | ||
|
|
364d580ff8 | ||
|
|
8c70229a18 | ||
|
|
3cad1ec436 | ||
|
|
c436460b8c | ||
|
|
a68194090e | ||
|
|
c0562d78a2 | ||
|
|
622b6a9b92 | ||
|
|
49c2f16351 | ||
|
|
eb2b6a08b0 | ||
|
|
1822ace296 | ||
|
|
35e4453930 | ||
|
|
98a4b9ede3 | ||
|
|
c86e4dfdce | ||
|
|
ad4f13255d | ||
|
|
43ce0d5b45 | ||
|
|
95c8235a4a | ||
|
|
fa81dca950 | ||
|
|
e1e76c6be7 | ||
|
|
ecb997885c | ||
|
|
2faaeaedb3 | ||
|
|
e9ee3191e9 | ||
|
|
c374b0cbca | ||
|
|
4216346384 | ||
|
|
00149402e0 | ||
|
|
b817a78efa | ||
|
|
0ddb13e8ee | ||
|
|
e132a203d1 | ||
|
|
fbc02a5f62 | ||
|
|
8a763eab6f | ||
|
|
b78c83a4ab | ||
|
|
5551326c98 | ||
|
|
d81f6e5ede | ||
|
|
00765d0fce | ||
|
|
9033f6f8c7 | ||
|
|
9751fd92a5 | ||
|
|
13e2f72c9f | ||
|
|
0cf90ee39a | ||
|
|
46eb4ed2b9 | ||
|
|
a136ee5edd | ||
|
|
15465bfc50 | ||
|
|
c79f500364 | ||
|
|
266e41f95c | ||
|
|
2839e74420 | ||
|
|
742f625309 | ||
|
|
b0e067e4ae | ||
|
|
16b1649ff6 | ||
|
|
a094ae5683 | ||
|
|
a521ff3d7c | ||
|
|
a58aa3f2e6 | ||
|
|
0bd0eaf890 | ||
|
|
a72ec9799a | ||
|
|
704a4ead17 | ||
|
|
e31625d0da | ||
|
|
d0e3da9b3e | ||
|
|
61961b565e | ||
|
|
265f4d9d64 | ||
|
|
27ec2d7f1c | ||
|
|
88ce871601 | ||
|
|
2d4f5778a2 | ||
|
|
5cb5a75455 | ||
|
|
5a49074f95 | ||
|
|
301ffaf61d | ||
|
|
db5990a989 | ||
|
|
fc4ae19d99 | ||
|
|
bf63144f7a | ||
|
|
1c2ba76db2 | ||
|
|
6f0706ffc5 | ||
|
|
a834fbcc6c | ||
|
|
c0fb470719 | ||
|
|
dd5fde5130 | ||
|
|
18f9959776 | ||
|
|
5f4b922b19 | ||
|
|
2355a43efa | ||
|
|
1500f84d46 | ||
|
|
82f86ee4ab | ||
|
|
16c4907be5 | ||
|
|
f6a4413411 | ||
|
|
feabbaf564 | ||
|
|
3ae0081b41 | ||
|
|
3b9a74c0cb | ||
|
|
f2f3d6ff46 | ||
|
|
7006dcc31c | ||
|
|
219cb63b73 | ||
|
|
0726a11d11 | ||
|
|
55c609b3fe | ||
|
|
7f5f6f83d7 | ||
|
|
ceba309dbd | ||
|
|
2008db0852 | ||
|
|
44d340d429 | ||
|
|
ad079cdcc5 | ||
|
|
d14a30e089 | ||
|
|
eb17d61fc1 | ||
|
|
bfd896041e | ||
|
|
bd958b3820 | ||
|
|
c67674c889 | ||
|
|
41e307bd5b | ||
|
|
892750788b | ||
|
|
4bd62c02dc | ||
|
|
5cda51e184 | ||
|
|
fb1e2f21fb | ||
|
|
581964b655 | ||
|
|
c1647a5982 | ||
|
|
a813fbbb88 | ||
|
|
86fca17fb1 | ||
|
|
e7c0b8320a | ||
|
|
616f28d1d4 | ||
|
|
56e527d3ee | ||
|
|
360ad2e252 | ||
|
|
3e98f1a8a8 | ||
|
|
174e2b7781 | ||
|
|
cd65217f5c | ||
|
|
1d083efb67 | ||
|
|
1904b92a9d | ||
|
|
5dc640bec1 | ||
|
|
d96f924cad | ||
|
|
85c6798448 | ||
|
|
7eabb43bd4 | ||
|
|
de5886698e | ||
|
|
10cbf08233 | ||
|
|
b126b67094 | ||
|
|
e63ab3a67f | ||
|
|
4aa72eaf15 | ||
|
|
91b7f7db1e | ||
|
|
e9af6358bb | ||
|
|
7f516896be | ||
|
|
34d4d606c3 | ||
|
|
831c29f23b | ||
|
|
bbf09eb74e | ||
|
|
11a135c7b7 | ||
|
|
807addb4ef | ||
|
|
6cdbc92ae3 | ||
|
|
846fdc20d4 | ||
|
|
afe37a69d6 | ||
|
|
ce0eee3e29 | ||
|
|
f7a054956b | ||
|
|
21c537fe22 | ||
|
|
5f8b8a2147 | ||
|
|
2a748f1884 | ||
|
|
b2f2c557e9 | ||
|
|
ccf6ebef4d | ||
|
|
04adade80e | ||
|
|
fe2c8bc249 | ||
|
|
f185c02f4c | ||
|
|
35cbec43e6 | ||
|
|
4ef6fd6148 | ||
|
|
2a0fb8fe6d | ||
|
|
b789bb7078 | ||
|
|
31d4eb090e | ||
|
|
a2a10b94be | ||
|
|
9b39309e18 | ||
|
|
6d1c1d3ed2 | ||
|
|
cb050b079a | ||
|
|
f7216b9567 | ||
|
|
8ebf1cec3f | ||
|
|
0fea080ba9 | ||
|
|
632c536616 | ||
|
|
c35ecec5a4 | ||
|
|
e466dc8057 | ||
|
|
476f408a13 | ||
|
|
8c49ba2553 | ||
|
|
0dbc6aad0f | ||
|
|
705b9de28c | ||
|
|
b648817f27 | ||
|
|
1389298f8c | ||
|
|
2f6c428a40 | ||
|
|
f9d2a87d25 | ||
|
|
0f05a41ea8 | ||
|
|
9ac8535832 | ||
|
|
ea84c2f26d | ||
|
|
f2c6e01296 | ||
|
|
d128ceed6f | ||
|
|
19a5eb0076 | ||
|
|
8424d44609 | ||
|
|
1166e69c76 | ||
|
|
079e25a9fe | ||
|
|
5d214c7b52 | ||
|
|
1859668257 | ||
|
|
7015cfcd31 | ||
|
|
d5d987ead6 | ||
|
|
6f333bf262 | ||
|
|
5f5bd6bd24 | ||
|
|
20542b0565 | ||
|
|
ef8f4de962 | ||
|
|
f06cb30447 | ||
|
|
c5334b0e19 | ||
|
|
d5cbc24cfe | ||
|
|
0101f425d4 | ||
|
|
02fc4d86b7 | ||
|
|
a1e6887bf9 | ||
|
|
7e13ab16c9 | ||
|
|
a623c94728 | ||
|
|
ba58c3fbeb | ||
|
|
7b724ff1eb | ||
|
|
b74315c7f5 | ||
|
|
e18766a651 | ||
|
|
9ecd5170e7 | ||
|
|
82c60414b9 | ||
|
|
502c9a36c7 | ||
|
|
40c0ef4567 | ||
|
|
5a47ba4110 | ||
|
|
f047c6b738 | ||
|
|
e77c5f8bbc | ||
|
|
6c20ababfb | ||
|
|
1207a158bd | ||
|
|
3ae0773ce8 | ||
|
|
d6d6fb0c37 | ||
|
|
2cc1c5ac6c | ||
|
|
981066c4a1 | ||
|
|
cb60759687 | ||
|
|
cf08244b6f | ||
|
|
0c4728fbc1 | ||
|
|
72641c66a2 | ||
|
|
cdff12e4e0 | ||
|
|
dfdf1dd973 | ||
|
|
d38bf63f8e | ||
|
|
8e0f150fab | ||
|
|
684b0dc059 | ||
|
|
8d22276f13 | ||
|
|
b85cb50ea2 | ||
|
|
431b0da027 | ||
|
|
eb05fbd2dc | ||
|
|
fa7bec3854 | ||
|
|
f88c4a5c9c | ||
|
|
6ef283d7ef | ||
|
|
5e9617f6cc | ||
|
|
30550fcddd | ||
|
|
1416807c9d | ||
|
|
41f378e403 | ||
|
|
0b0707363c | ||
|
|
04fefc0761 | ||
|
|
de974f0551 | ||
|
|
aec5cd5148 | ||
|
|
2a2a42c153 | ||
|
|
66639ea110 | ||
|
|
1ae82b3210 | ||
|
|
a81f461b54 | ||
|
|
cf8a07286a | ||
|
|
6efff83616 | ||
|
|
233a2719c6 | ||
|
|
49f61c4782 | ||
|
|
665b2d4e4e | ||
|
|
ce328b7245 | ||
|
|
135b5eccc5 | ||
|
|
2d8e6240c6 | ||
|
|
4bdad75766 | ||
|
|
522664d415 | ||
|
|
71e2310fa4 | ||
|
|
d2b37fc436 | ||
|
|
e6e058c0a0 | ||
|
|
6de4c89c25 | ||
|
|
0d4f907b66 | ||
|
|
e047b0bf30 | ||
|
|
f250f86446 | ||
|
|
4067c82486 | ||
|
|
306014adc7 | ||
|
|
6aae8fc63b | ||
|
|
9b4d16fbe9 | ||
|
|
d46b043c5d | ||
|
|
5656d9d42f | ||
|
|
c9a43ce5c0 | ||
|
|
7c8492ba43 | ||
|
|
16d5ac6abb | ||
|
|
a8515e0a41 | ||
|
|
fccabf1bc0 | ||
|
|
dd1d129693 | ||
|
|
124596058a | ||
|
|
be38df32ec | ||
|
|
577bd59b6c | ||
|
|
f8780d032b | ||
|
|
38ba42575c | ||
|
|
60f0ade3c1 | ||
|
|
8e083d20d2 | ||
|
|
a62a56fd7b | ||
|
|
895358e6e5 | ||
|
|
d57980c6cb | ||
|
|
0672562c8a | ||
|
|
d047abf31c | ||
|
|
e050506a05 | ||
|
|
cd574c87ef | ||
|
|
4e3a24e609 | ||
|
|
c495ccff65 | ||
|
|
51bac4486f | ||
|
|
146ce659e2 | ||
|
|
c0cb1cd2b8 | ||
|
|
f4d41891d9 | ||
|
|
06f41659f5 | ||
|
|
cbfad2ef7a | ||
|
|
8de94d3f1c | ||
|
|
f20870544d | ||
|
|
4d91ef14f4 | ||
|
|
6ed9f0a01d | ||
|
|
94e9f8fd34 | ||
|
|
fc51424f86 | ||
|
|
5146dc4981 | ||
|
|
03123faa8a | ||
|
|
7fccf79591 | ||
|
|
d3dff8c20e | ||
|
|
0bc4c3fde2 | ||
|
|
873dee7e51 | ||
|
|
837ec68371 | ||
|
|
f8525c6f6c | ||
|
|
a1cfe7aef2 | ||
|
|
5042d49935 | ||
|
|
c89b50bf31 | ||
|
|
103f9d209d | ||
|
|
4508bfac73 | ||
|
|
3184d3482c | ||
|
|
5de3052026 | ||
|
|
7674da4cd2 | ||
|
|
b15dc316d3 | ||
|
|
10f715f726 | ||
|
|
0377015190 | ||
|
|
98c33fb3cc | ||
|
|
b4e2ba4544 | ||
|
|
32c172d145 | ||
|
|
5a308a2a53 | ||
|
|
71873a9c27 | ||
|
|
5e3db870ec | ||
|
|
85b7587c42 | ||
|
|
b75c42b39f | ||
|
|
0d2ffdb380 | ||
|
|
8f1c4fcda9 | ||
|
|
bf33fd752d | ||
|
|
c08c8bd073 | ||
|
|
8098dc9dcc | ||
|
|
e43b21387c | ||
|
|
1f6a2093fb | ||
|
|
90463a0732 | ||
|
|
acf7eabef9 | ||
|
|
017077f8cb | ||
|
|
e798576a87 | ||
|
|
cc45a08388 | ||
|
|
8cca067991 | ||
|
|
80b763c47c | ||
|
|
8786024559 | ||
|
|
bbb43f53d0 | ||
|
|
639e40d355 | ||
|
|
f964f06f3f | ||
|
|
e4543c5f35 | ||
|
|
6900233c5a | ||
|
|
03fe3b6a0d | ||
|
|
a9c89cef19 | ||
|
|
340b9202c0 | ||
|
|
99ca8755f3 | ||
|
|
eaf1e96fa2 | ||
|
|
f9b5353058 | ||
|
|
e0af914c90 | ||
|
|
8f19f4dc5b | ||
|
|
5f47e7f0fa | ||
|
|
9c39b0453d | ||
|
|
545fc103b8 | ||
|
|
c55b1e4680 | ||
|
|
297db58e68 | ||
|
|
e3f57ee20e | ||
|
|
5031cea040 | ||
|
|
6fe126ad5a | ||
|
|
49b257ecff | ||
|
|
f042b095f1 | ||
|
|
43d0936533 | ||
|
|
b68873c5f4 | ||
|
|
e1ae9241af | ||
|
|
b6ea37c517 | ||
|
|
bee0e19eaf | ||
|
|
f54657a569 | ||
|
|
1aa27084d0 | ||
|
|
691c8f1436 | ||
|
|
b72e5b7e02 | ||
|
|
c70e378973 | ||
|
|
21444daefb | ||
|
|
2e0d7361cb | ||
|
|
6e0b6d84d2 | ||
|
|
ec59abe3ae | ||
|
|
062e23b5c9 | ||
|
|
a8160a8cdc | ||
|
|
0b093dd57e | ||
|
|
923d5878c3 | ||
|
|
9c5849fbce | ||
|
|
4ef3e53de3 | ||
|
|
2656b47640 | ||
|
|
fafbc292ca | ||
|
|
800aef1942 | ||
|
|
da7f73baa6 | ||
|
|
afb9d866b5 | ||
|
|
7dc5929cfd | ||
|
|
c2f1694107 | ||
|
|
23215bd6f7 | ||
|
|
1493cacb69 | ||
|
|
9076fddc0d | ||
|
|
a89c9d59cf | ||
|
|
15dec21118 | ||
|
|
d800b12569 | ||
|
|
89ac491120 | ||
|
|
981a0f08fe | ||
|
|
e53bfe6b62 | ||
|
|
9bb4570126 | ||
|
|
5b43358219 | ||
|
|
cf605c8a38 | ||
|
|
e304f6fc3a | ||
|
|
09cee986f2 | ||
|
|
3992fe1a45 | ||
|
|
17e08cafce | ||
|
|
7243ed718f | ||
|
|
387cfd758f | ||
|
|
c75a0bd311 | ||
|
|
18633dcd88 | ||
|
|
5800350b25 | ||
|
|
cd2daa1910 | ||
|
|
8b6bbe003d | ||
|
|
edebbee9e7 | ||
|
|
f3269693de | ||
|
|
c2c87bf0ba | ||
|
|
e525747002 | ||
|
|
6d8c709de8 | ||
|
|
f07c13a50c | ||
|
|
c12312cbd3 | ||
|
|
cb6c098f95 | ||
|
|
09ca82e1d8 | ||
|
|
5b565a69d7 | ||
|
|
52ddfc8801 | ||
|
|
df3f7e9a6e | ||
|
|
05aaa5b667 | ||
|
|
df24c663df | ||
|
|
45e7f162a2 | ||
|
|
fbda8c8286 | ||
|
|
8c70efa058 | ||
|
|
65b489883d | ||
|
|
1b2608d6ee | ||
|
|
9267b50666 | ||
|
|
2604dae83c | ||
|
|
6778aa4343 | ||
|
|
5890b7e7bf | ||
|
|
d58aa33d2b | ||
|
|
f62617a8bf | ||
|
|
d20249f29a | ||
|
|
0e16a3f3b4 | ||
|
|
5409547bba | ||
|
|
db8e2c3bf2 | ||
|
|
4c53ec6dd3 | ||
|
|
b2d678ca95 | ||
|
|
adbefb4622 | ||
|
|
429b7033a4 | ||
|
|
7f3e2852c6 | ||
|
|
57d9c246c0 | ||
|
|
7fce223a6d | ||
|
|
abbbf0d030 | ||
|
|
a628358c9f | ||
|
|
918eb3bb67 | ||
|
|
ecae1997aa | ||
|
|
e4c7caa8ea | ||
|
|
54d1f05851 | ||
|
|
1592bc44fc | ||
|
|
77fedee58a | ||
|
|
63e72a22e0 | ||
|
|
00c8ece07e | ||
|
|
60a561c84c | ||
|
|
5cbe256120 | ||
|
|
4ad50b14d6 | ||
|
|
df88373519 | ||
|
|
099699198c | ||
|
|
75bd1bc4c8 | ||
|
|
12c883b6fd | ||
|
|
144d647540 | ||
|
|
c8a6d109ce | ||
|
|
5fa3c6511f | ||
|
|
a2a8f9de74 | ||
|
|
d72d83d0f3 | ||
|
|
c91c0afa71 | ||
|
|
a95fcc96be | ||
|
|
f9c5a688b1 | ||
|
|
e9b8c452b9 | ||
|
|
3e380ba844 | ||
|
|
22234ad1c1 | ||
|
|
662fd13548 | ||
|
|
a672b8a58c | ||
|
|
6e0cdb8a6b | ||
|
|
0baa678c8b | ||
|
|
c99747d7f2 | ||
|
|
2681a78501 | ||
|
|
3bf7737790 | ||
|
|
455d3946d6 | ||
|
|
2dfecb5287 | ||
|
|
abc12bd407 | ||
|
|
bbf352caa4 | ||
|
|
d7c5c37cf8 | ||
|
|
038373cbbc | ||
|
|
321520741d | ||
|
|
2c75c636af | ||
|
|
01b7e523d0 | ||
|
|
05d4a28adc | ||
|
|
b89142c45c | ||
|
|
f9359bfb73 | ||
|
|
4d30740198 | ||
|
|
2d6dfd9002 | ||
|
|
3914a14a2a | ||
|
|
2949f71691 | ||
|
|
551121524c | ||
|
|
038c5e9a6e | ||
|
|
467aabe5ee | ||
|
|
4f73641f46 | ||
|
|
48e97b5ec2 | ||
|
|
a86106c0c1 | ||
|
|
c9f3693785 | ||
|
|
5151863a94 | ||
|
|
16a81cdc7f | ||
|
|
ebb6cf2a91 | ||
|
|
1d546d9ef7 | ||
|
|
6bef35b406 | ||
|
|
ecd9d5493f | ||
|
|
33a6f4c49f | ||
|
|
3c92cd3198 | ||
|
|
4d0e6b4772 | ||
|
|
ebdf0d9148 | ||
|
|
44aa4f1b0a | ||
|
|
fa7c6bee96 | ||
|
|
fa3b86fa7e | ||
|
|
52d5299374 | ||
|
|
23d959bf64 | ||
|
|
5198081c2b | ||
|
|
b6c491171c | ||
|
|
eefc0d41e1 | ||
|
|
e5cd2bed87 | ||
|
|
766da39138 | ||
|
|
72c0e118c3 | ||
|
|
66cdf98190 | ||
|
|
e5d4be6250 | ||
|
|
130b57b986 | ||
|
|
2f30ae7a82 | ||
|
|
e983e9e9b7 | ||
|
|
b042f3c738 | ||
|
|
ece37b62f2 | ||
|
|
abc70f2e92 | ||
|
|
2ed258cb69 | ||
|
|
6903ce0043 | ||
|
|
0ebcbe516c | ||
|
|
c44e0ca737 | ||
|
|
7f050dc61a | ||
|
|
93e13cdb06 | ||
|
|
dea3bc1a7f | ||
|
|
2f6fcdb878 | ||
|
|
3de32c2acc | ||
|
|
ff28d2919b | ||
|
|
e3fb25cf45 | ||
|
|
d39fd8659e | ||
|
|
126b00b35c | ||
|
|
94291c4968 | ||
|
|
a5821815bf | ||
|
|
c5612beff9 | ||
|
|
eecaf759ea | ||
|
|
620a1a1334 | ||
|
|
9fc983f54a | ||
|
|
dd7361441d | ||
|
|
63347843cb | ||
|
|
c2ef0a9578 | ||
|
|
d17e0b80b3 | ||
|
|
8d4a1e0ed3 | ||
|
|
280479c0c6 | ||
|
|
ca65ed1258 | ||
|
|
33785b3786 | ||
|
|
96e9c154bd | ||
|
|
c8a20cadbf | ||
|
|
71f8afab9a | ||
|
|
6ad8f5e06a | ||
|
|
50d75cd2f9 | ||
|
|
6d895dff42 | ||
|
|
d4c2b492ef | ||
|
|
64c886bfeb | ||
|
|
2094e05a2e | ||
|
|
0df0de6507 | ||
|
|
01ab6b88ea | ||
|
|
9b3dd6b753 | ||
|
|
60523dc7a7 | ||
|
|
ca3f9a823d | ||
|
|
0c0846eef9 | ||
|
|
b4af28a91b | ||
|
|
4879ee93bf | ||
|
|
8ab1cd0ca8 | ||
|
|
11f3e29604 | ||
|
|
8cf6379de3 | ||
|
|
4a426ce045 | ||
|
|
25b35769c5 | ||
|
|
4b0c474537 | ||
|
|
a74b8e32fa | ||
|
|
251368e749 | ||
|
|
0b1f963f0b | ||
|
|
4ea54823b0 | ||
|
|
c6ffa6e9e1 | ||
|
|
8e6ee9ea79 | ||
|
|
e7e7363fa7 | ||
|
|
5a76bad28d | ||
|
|
c1e4eeec32 | ||
|
|
d2de46edfb | ||
|
|
04432df554 | ||
|
|
c44028f413 | ||
|
|
8cad610a54 | ||
|
|
f807a28e95 | ||
|
|
4c1d5a4b6d | ||
|
|
ecfbc44a20 | ||
|
|
63c81d6fff | ||
|
|
42d85abfc2 | ||
|
|
fd4e2f59dc | ||
|
|
053728a03f | ||
|
|
92f6c8003b | ||
|
|
826afd7653 | ||
|
|
0df9519f76 | ||
|
|
d5d0f67797 | ||
|
|
219cc94fbf | ||
|
|
bfa6419070 | ||
|
|
d7d6ff0cca | ||
|
|
79d6f64451 | ||
|
|
fd59a6c994 | ||
|
|
cb4776cc0e | ||
|
|
2ee00ca8e6 | ||
|
|
a3ec7bb5ad | ||
|
|
faa72fd97c | ||
|
|
378b87459a | ||
|
|
30f17ade3a | ||
|
|
ecec8bf75d | ||
|
|
736ebb6f28 | ||
|
|
928dd90f61 | ||
|
|
eb166a67a9 | ||
|
|
51a6d1ea1d | ||
|
|
3cce0e88df | ||
|
|
e2dcc813ec | ||
|
|
a572a0a640 | ||
|
|
c4b2d9861f | ||
|
|
ed70314686 | ||
|
|
f5f35f2c37 | ||
|
|
ccf1afc93c | ||
|
|
7800ef6102 | ||
|
|
25eea41f60 | ||
|
|
c21c16026b | ||
|
|
74e9270d58 | ||
|
|
b2e72adba9 | ||
|
|
1eac147918 | ||
|
|
3f6f4bb4c0 | ||
|
|
a8d1d3b87a | ||
|
|
fb3dfc5672 | ||
|
|
cdd0231a76 | ||
|
|
e9e43c059a | ||
|
|
548e975cac | ||
|
|
cf0eee1fa3 | ||
|
|
dc5b010d09 | ||
|
|
a854a0dc0a | ||
|
|
d733119456 | ||
|
|
670673ab8d | ||
|
|
028b37b9d4 | ||
|
|
916e1bb95c | ||
|
|
c9e8207e4b | ||
|
|
aef6df048c | ||
|
|
f8b2b18185 | ||
|
|
ce411ed728 | ||
|
|
9859a32e15 | ||
|
|
3be7af8fb8 | ||
|
|
5538649125 | ||
|
|
97ee951b1f | ||
|
|
44aac16991 | ||
|
|
ab5fee1562 | ||
|
|
65a73b5b45 | ||
|
|
74e213a534 | ||
|
|
f9d561d40b | ||
|
|
5066128c72 | ||
|
|
a2de5e3da2 | ||
|
|
458f2eae4c | ||
|
|
c166560ff4 | ||
|
|
03f05f316f | ||
|
|
331d9e7542 | ||
|
|
ec31007c4b | ||
|
|
e615c7ee7f | ||
|
|
35d4d4f755 | ||
|
|
195468c4e1 | ||
|
|
15f274e662 | ||
|
|
7cb898457c | ||
|
|
aa4050ee32 | ||
|
|
f392de722a | ||
|
|
07d95d5d3c | ||
|
|
22c61d8221 | ||
|
|
8fb0a66ef2 | ||
|
|
d5cd828cba | ||
|
|
0119ae36a8 | ||
|
|
87852d125f | ||
|
|
d3969b0122 | ||
|
|
3cba4cab1e | ||
|
|
ef35a04c4a | ||
|
|
874928e845 | ||
|
|
c3d1574f8c | ||
|
|
eee5c9e48b | ||
|
|
2f5780d1d1 | ||
|
|
fa60f66057 | ||
|
|
a741bd5419 | ||
|
|
4d2d4a7ca3 | ||
|
|
5c1e6ab16b | ||
|
|
f5f75dbef8 | ||
|
|
6577051d64 | ||
|
|
b2f5cc11b5 | ||
|
|
a1252f66cc | ||
|
|
e8d9e8b42b | ||
|
|
ced7265eb0 | ||
|
|
14098b2ff2 | ||
|
|
fb93a0863b | ||
|
|
4088bff216 | ||
|
|
915152d3b9 | ||
|
|
2ecea9a7b0 | ||
|
|
dc2a620b4e | ||
|
|
8648a303f1 | ||
|
|
6a65ca4ebd | ||
|
|
58b83c27f2 | ||
|
|
338d925bcc | ||
|
|
7e2c4a0a1c | ||
|
|
9822be5df4 | ||
|
|
cf5c62bcfc | ||
|
|
27553ef926 | ||
|
|
3f249fcc89 | ||
|
|
c3654ab148 | ||
|
|
0e9e8d41d9 | ||
|
|
2f49c1c9b0 | ||
|
|
072dbe8db5 | ||
|
|
da208e23f5 | ||
|
|
222a617c44 | ||
|
|
e355c77a4a | ||
|
|
639653dac2 | ||
|
|
0aa5543397 | ||
|
|
dfdda4f3b9 | ||
|
|
8cf58d7fc6 | ||
|
|
4783e3eae4 | ||
|
|
4931ad3960 | ||
|
|
5ad78a5ebb | ||
|
|
dc95f2e065 | ||
|
|
0361ceba6c | ||
|
|
4ecc7372f9 | ||
|
|
dbcd627815 | ||
|
|
6061c81c36 | ||
|
|
c1aee61da1 | ||
|
|
f0d3346ca7 | ||
|
|
e8ca6376be | ||
|
|
c48c134869 | ||
|
|
49e334521d | ||
|
|
04a641adc2 | ||
|
|
2210652643 | ||
|
|
8713db3d55 | ||
|
|
f2e8b5ee3e | ||
|
|
7e0c6c6470 | ||
|
|
19c49db538 | ||
|
|
ea40ac1e53 | ||
|
|
653898b463 | ||
|
|
c07d0a2bc7 | ||
|
|
9bb221a0d7 | ||
|
|
e4f2c4a28b | ||
|
|
3a4858b83c | ||
|
|
826ea36502 | ||
|
|
397819d45e | ||
|
|
66fecf88ef | ||
|
|
e8dc220981 | ||
|
|
1c2b05d8f6 | ||
|
|
f3495f3098 | ||
|
|
081b093e7e | ||
|
|
4d30753958 | ||
|
|
c72e0cb0e0 | ||
|
|
25f8dbf120 | ||
|
|
868202ba41 | ||
|
|
c6b0ed32bf | ||
|
|
17adef11a6 | ||
|
|
6d1c807879 | ||
|
|
0ed5b20627 | ||
|
|
f5175941d9 | ||
|
|
e2f048ec2d | ||
|
|
2717444c29 | ||
|
|
b21755b5a3 | ||
|
|
37ff97b52f | ||
|
|
b897598fac | ||
|
|
95cb92abed | ||
|
|
5730dc642a | ||
|
|
7c2a3b4612 | ||
|
|
dbf796d698 | ||
|
|
7f739a53f8 | ||
|
|
2dbde52338 | ||
|
|
61f1caa122 | ||
|
|
695d7b8654 | ||
|
|
6e7fd2ca95 | ||
|
|
79bfcf226b | ||
|
|
9d9e091a7a | ||
|
|
be1bb6bc06 | ||
|
|
d39bb412f3 | ||
|
|
e71b586fe5 | ||
|
|
2fcac12340 | ||
|
|
0847395c92 | ||
|
|
49c3df2328 | ||
|
|
58192cacb3 | ||
|
|
b81284e2c6 | ||
|
|
5b39e39e1f | ||
|
|
b944217410 | ||
|
|
dca7304be9 | ||
|
|
61a4b10adf | ||
|
|
231878266c | ||
|
|
51bf8fdde6 | ||
|
|
18134629d2 | ||
|
|
f6b737e45d | ||
|
|
3b7be8a719 | ||
|
|
aae1d194c7 | ||
|
|
ef0da306a8 | ||
|
|
bfaaa914f1 | ||
|
|
2f101c4a39 | ||
|
|
765eb43568 | ||
|
|
aa61e005e5 | ||
|
|
5b2e2b037b | ||
|
|
bcfd685826 | ||
|
|
5d8d25f370 | ||
|
|
6679318207 | ||
|
|
255e80d077 | ||
|
|
965d99d137 | ||
|
|
3b65523da9 | ||
|
|
3cfee32ae0 | ||
|
|
497c633b8a | ||
|
|
df45e22813 | ||
|
|
199b68a964 | ||
|
|
8db8ec3574 | ||
|
|
4a36670417 | ||
|
|
77ac503bfc | ||
|
|
be55e447bb | ||
|
|
00e9f922c0 | ||
|
|
361e51060a | ||
|
|
fbbc73308e | ||
|
|
a31e4c19cb | ||
|
|
b69a85f10e | ||
|
|
d919b1f312 | ||
|
|
cb81579c53 | ||
|
|
0306a395a2 | ||
|
|
5fbbfb4c18 | ||
|
|
b725c4c7b4 | ||
|
|
24e3ec89f3 | ||
|
|
f8d3fdbefb | ||
|
|
352f1bc23e | ||
|
|
413cb79683 | ||
|
|
d06f856e46 | ||
|
|
09c3cc6db1 | ||
|
|
eb96dd952b | ||
|
|
1da3a769c4 | ||
|
|
356a3284fa | ||
|
|
0eedcf567e | ||
|
|
f4f58dbfb9 | ||
|
|
8135e076c2 | ||
|
|
22b3415866 | ||
|
|
5effca4bbc | ||
|
|
aa14541e50 | ||
|
|
13525c85a0 | ||
|
|
2f6f7e39bb | ||
|
|
2d76025c9c | ||
|
|
bb9edc4f65 | ||
|
|
afcd821f50 | ||
|
|
b8e66cada9 | ||
|
|
f1dedf5a74 | ||
|
|
2ebda29f02 | ||
|
|
fc5025a2a8 | ||
|
|
e3d238f897 | ||
|
|
fa841582a9 | ||
|
|
2b28388fa7 | ||
|
|
a6b7ec5c66 | ||
|
|
9ab3e3ccd8 | ||
|
|
7abf5faa3c | ||
|
|
4052c7995c | ||
|
|
776b6831f3 | ||
|
|
902a242f6b | ||
|
|
a2d231dc23 | ||
|
|
d6a327ea86 | ||
|
|
21ef0598f9 | ||
|
|
2405ee90e9 | ||
|
|
1aeedd8696 | ||
|
|
4815eb10a9 | ||
|
|
d13efbbe23 | ||
|
|
9b1fbea7e1 | ||
|
|
09bf422686 | ||
|
|
18b3e06fe8 | ||
|
|
e436693d3e | ||
|
|
eb66848aee | ||
|
|
0eded34c8c | ||
|
|
367c18bfc5 | ||
|
|
92dc0a7671 | ||
|
|
8e553b4ee0 | ||
|
|
21c64e827b | ||
|
|
c69a0abfa9 | ||
|
|
cce6531d45 | ||
|
|
84a31b3520 | ||
|
|
59cdb6e8c6 | ||
|
|
068e620249 | ||
|
|
80aa87023e | ||
|
|
626d63c91d | ||
|
|
5bf0411015 | ||
|
|
b2fcb8d104 | ||
|
|
79f98795c7 | ||
|
|
24ad365047 | ||
|
|
72286fd642 | ||
|
|
a0f46c326a | ||
|
|
b1f2750cdb | ||
|
|
8aee3f8174 | ||
|
|
ea61799b3d | ||
|
|
b1e6e0c25a | ||
|
|
f7916cfa74 | ||
|
|
3f37ef2fad | ||
|
|
3297940bab | ||
|
|
821d33b8d8 | ||
|
|
72129ca16f | ||
|
|
12fa88b149 | ||
|
|
c83069bd03 | ||
|
|
5661605884 | ||
|
|
d1bbbb8e93 | ||
|
|
178f851684 | ||
|
|
cb4b8c5914 | ||
|
|
8018a607a8 | ||
|
|
dc5a7ca431 | ||
|
|
95d33eab94 | ||
|
|
725cbf2e20 | ||
|
|
674cebd9e1 | ||
|
|
0dd66463df | ||
|
|
beeeb7bcbf | ||
|
|
bf4bc214b2 | ||
|
|
b99534ebdf | ||
|
|
c6fb75c65f | ||
|
|
38e8b19b50 | ||
|
|
90ce840234 | ||
|
|
fc6eda392b | ||
|
|
343edbff51 | ||
|
|
fe88880486 | ||
|
|
1c2e4968e2 | ||
|
|
f9b375a39b | ||
|
|
eb18e74e88 | ||
|
|
487553a00c | ||
|
|
c78927d5db | ||
|
|
26e9822344 | ||
|
|
207fa139d4 | ||
|
|
e2236d43fd | ||
|
|
6006767a9f | ||
|
|
35abf9a6bc | ||
|
|
c3a4223bbf | ||
|
|
4a2fa5a29f | ||
|
|
17ae6668b4 | ||
|
|
06a31fd67b | ||
|
|
1a13ef6921 | ||
|
|
17a323298c | ||
|
|
27c99fd90a | ||
|
|
6c7175c109 | ||
|
|
cdd9dbf748 | ||
|
|
1b72b80241 | ||
|
|
be53a9472a | ||
|
|
accdec3af4 | ||
|
|
95b6dbd140 | ||
|
|
08838c989e | ||
|
|
74bff84226 | ||
|
|
b1a3124fcc | ||
|
|
3e1c7eb434 | ||
|
|
2125367683 | ||
|
|
809e33b053 | ||
|
|
0efe163591 | ||
|
|
e8935f5582 | ||
|
|
0da9e1fab3 | ||
|
|
802370eb9d | ||
|
|
4e722b47b5 | ||
|
|
b055c5cdad | ||
|
|
b7a1f21e31 | ||
|
|
a04cac60e6 | ||
|
|
274b69d017 | ||
|
|
5fab338ba1 | ||
|
|
6cd77384a5 | ||
|
|
5290d78e20 | ||
|
|
4054e822ed | ||
|
|
2ce02db1b5 | ||
|
|
fff46a6b63 | ||
|
|
369037e269 | ||
|
|
6f7264b60b | ||
|
|
9881fecacd | ||
|
|
cf9338c35f | ||
|
|
a9947ad97f | ||
|
|
ac2e3e2873 | ||
|
|
8f4eb5627b | ||
|
|
e4bd62b84c | ||
|
|
0e033348f0 | ||
|
|
0651aab1be | ||
|
|
f8a7f1c1f9 | ||
|
|
c90931d004 | ||
|
|
a973f66092 | ||
|
|
5d81ff4cbe | ||
|
|
7442b48157 | ||
|
|
59003a9ab9 | ||
|
|
40c2e3f442 | ||
|
|
65b61fc90d | ||
|
|
05c6cd6c3d | ||
|
|
15fcc5680f | ||
|
|
fdd9f30c39 | ||
|
|
0049c9ef00 | ||
|
|
f097f2e10a | ||
|
|
4009f4f331 | ||
|
|
8f8b7f0fbf | ||
|
|
29b3b4ecba | ||
|
|
b111e05ef7 | ||
|
|
c2f73c37c5 | ||
|
|
cc648be854 | ||
|
|
483e2835c4 | ||
|
|
daa90286d3 | ||
|
|
5e1d6a7db3 | ||
|
|
ab4f222e92 | ||
|
|
5da46a15fb | ||
|
|
9438355a36 |
No files matched your search
@@ -0,0 +1,6 @@
|
||||
# === FOR EMPTY COMMITS ===
|
||||
# Select reason for empty commit:
|
||||
- [ ] Add conventional commit message for changelog
|
||||
- [x] Forgot to use conventional commit style
|
||||
# Increment this value if nothing above was changed
|
||||
0
|
||||
@@ -1,3 +1,4 @@
|
||||
.dockerignore
|
||||
Dockerfile
|
||||
node_modules
|
||||
/puter
|
||||
+1
-1
@@ -1 +1 @@
|
||||
PORT=4000
|
||||
PORT=4000
|
||||
@@ -0,0 +1,25 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Issue Description**
|
||||
|
||||
**Steps to Reproduce**
|
||||
|
||||
**Expected & Actual Behavior**
|
||||
|
||||
**Addition Information or Screenshots (if applicable)**
|
||||
|
||||
**Deployment**
|
||||
- [ ] Production (puter.com)
|
||||
- [ ] Development (`npm run start`)
|
||||
- [ ] Docker (via `docker run`)
|
||||
- [ ] Docker (via `docker-compose`)
|
||||
|
||||
**Puter version (if accessible)**
|
||||
> Click the profile button on the top-right, then "Settings". The version number will be printed at the bottom
|
||||
@@ -0,0 +1,10 @@
|
||||
---
|
||||
name: Driver Request
|
||||
about: Request a driver on Puter
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
> Drivers are services that apps on Puter can use. For example, drivers support many of the features in the [Puter SDK](https://docs.puter.com/). If you're not sure if what you're suggesting is a driver, you should use the "Feature Request" template instead.
|
||||
@@ -0,0 +1,10 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for Puter
|
||||
title: ''
|
||||
labels: idea
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
---
|
||||
name: Idea for Improvement
|
||||
about: An enhancement for an existing feature on Puter
|
||||
title: ''
|
||||
labels: enhancement
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
# This workflow will do a clean installation of node dependencies, cache/restore them, build the source code and run tests across different versions of node
|
||||
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-nodejs
|
||||
|
||||
name: Node.js CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "main" ]
|
||||
pull_request:
|
||||
branches: [ "main" ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [20.x, 21.x, 22.x]
|
||||
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
cache: 'npm'
|
||||
- run: npm ci
|
||||
- run: npm run build --if-present
|
||||
- run: npm test
|
||||
@@ -1,28 +0,0 @@
|
||||
# This workflow runs the tools/check-translations.js script to make sure that the translation data is valid.
|
||||
|
||||
name: Check Translations
|
||||
|
||||
env:
|
||||
NODE_VERSION: 21.x
|
||||
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "main" ]
|
||||
pull_request:
|
||||
branches: [ "main" ]
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Use Node.js ${{ env.NODE_VERSION }}
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
cache: 'npm'
|
||||
cache-dependency-path: ./package-lock.json
|
||||
- run: npm ci
|
||||
- run: npm run check-translations
|
||||
@@ -5,8 +5,10 @@ name: Docker Image CI
|
||||
# branch called `main`.
|
||||
on:
|
||||
push:
|
||||
branches: ['main']
|
||||
|
||||
tags:
|
||||
- '*.*.*'
|
||||
branches:
|
||||
- 'main'
|
||||
|
||||
# Defines two custom environment variables for the workflow. These are used
|
||||
# for the Container registry domain, and a name for the Docker image that
|
||||
@@ -41,6 +43,12 @@ jobs:
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
# This step uses [docker/metadata-action](https://github.com/docker/metadata-action#about)
|
||||
# to extract tags and labels that will be applied to the specified image.
|
||||
# The `id` "meta" allows the output of this step to be referenced in
|
||||
@@ -50,16 +58,10 @@ jobs:
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||
images: "${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}"
|
||||
tags: |
|
||||
type=schedule
|
||||
type=ref,event=branch
|
||||
type=ref,event=pr
|
||||
type=semver,pattern={{version}}
|
||||
type=semver,pattern={{major}}.{{minor}}
|
||||
type=semver,pattern={{major}},enable=${{ !startsWith(github.ref, 'refs/tags/v0.') }}
|
||||
type=sha
|
||||
type=raw,value=latest,enable=${{ github.ref == format('refs/heads/{0}', github.event.repository.default_branch) }}
|
||||
type=ref,event=branch
|
||||
|
||||
# This step uses the `docker/build-push-action` action to build the
|
||||
# image, based on your repository's `Dockerfile`. If the build succeeds,
|
||||
@@ -73,7 +75,10 @@ jobs:
|
||||
- name: Build and push Docker image
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
platforms: linux/amd64,linux/arm64
|
||||
context: .
|
||||
push: true
|
||||
push: ${{ github.event_name != 'pull_request' }}
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
@@ -0,0 +1,40 @@
|
||||
name: Maintain Release Merge PR
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
update-release-pr:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Setup Git
|
||||
run: |
|
||||
git config user.name github-actions
|
||||
git config user.email [email protected]
|
||||
- name: Check for existing PR
|
||||
id: find-pr
|
||||
uses: juliangruber/find-pull-request-action@v1
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
branch: release
|
||||
- uses: actions/checkout@v4
|
||||
if: steps.find-pr.outputs.number == ''
|
||||
with:
|
||||
ref: release
|
||||
- name: Reset release branch
|
||||
if: steps.find-pr.outputs.number == ''
|
||||
run: |
|
||||
git fetch origin main:main
|
||||
git reset --hard main
|
||||
- name: Create/Update PR
|
||||
if: steps.find-pr.outputs.number == ''
|
||||
uses: peter-evans/create-pull-request@v6
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
commit-message: Update release branch
|
||||
title: Merge Release Auto-PR
|
||||
body: Merging this PR will invoke release actions
|
||||
branch: auto-update/release
|
||||
@@ -0,0 +1,18 @@
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
|
||||
name: release-please
|
||||
|
||||
jobs:
|
||||
release-please:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: google-github-actions/release-please-action@v4
|
||||
with:
|
||||
release-type: node
|
||||
+19
-2
@@ -1,11 +1,28 @@
|
||||
# Misc
|
||||
.DS_Store
|
||||
|
||||
# Dependencies
|
||||
node_modules/
|
||||
|
||||
*.zip
|
||||
*.tgz
|
||||
license.config.json
|
||||
license-header.txt
|
||||
|
||||
# Build Outputs
|
||||
dist/
|
||||
.vscode/
|
||||
|
||||
# VS Code IDE
|
||||
.vscode/**/*
|
||||
!.vscode/extensions.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
|
||||
# Local env files
|
||||
.env
|
||||
!.env.example
|
||||
|
||||
# this is for jetbrain IDEs
|
||||
.idea/
|
||||
.idea/
|
||||
/puter
|
||||
Vendored
+7
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"cSpell.words": [
|
||||
"dnsmasq",
|
||||
"heyputer",
|
||||
"Puter"
|
||||
]
|
||||
}
|
||||
+213
@@ -0,0 +1,213 @@
|
||||
# Changelog
|
||||
|
||||
## 2.4.0 (2024-07-08)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add (pt-br) translation for system settings. ([77211c4](https://github.com/HeyPuter/puter/commit/77211c4f71b0285fb3060f7e5c8d493b4d7c4f0c))
|
||||
* add /group/list endpoint ([d55f38c](https://github.com/HeyPuter/puter/commit/d55f38ca68899c3574cfe328d2b206b1143ff0d4))
|
||||
* add /share/file-by-username endpoint ([5d214c7](https://github.com/HeyPuter/puter/commit/5d214c7b52887b594af6be497f1892baf7d77679))
|
||||
* add /sharelink/request endpoint ([742f625](https://github.com/HeyPuter/puter/commit/742f625309f9f4cfa70cf7d2fe5b03fd164913ea))
|
||||
* add /show urls ([079e25a](https://github.com/HeyPuter/puter/commit/079e25a9fe8e179f26d72378856058eb656e2314))
|
||||
* add app metadata ([f7216b9](https://github.com/HeyPuter/puter/commit/f7216b95672b38802b288ef5b022e947017ff311))
|
||||
* add appdata permission (if applicable) on app share ([9751fd9](https://github.com/HeyPuter/puter/commit/9751fd92a50e75385cffed0ca847d5076ba98c92))
|
||||
* add cookie for site token ([a813fbb](https://github.com/HeyPuter/puter/commit/a813fbbb88bcfb8b9a61976e2a4fc4aab943fc88))
|
||||
* add cross-server event broadcasting ([1207a15](https://github.com/HeyPuter/puter/commit/1207a158bdc88a90b14d31d03387ce353c176a9c))
|
||||
* add debug mod ([16b1649](https://github.com/HeyPuter/puter/commit/16b1649ff62fd87a4dda5d2e1c68941c864c5da4))
|
||||
* add endpoints for share tokens ([301ffaf](https://github.com/HeyPuter/puter/commit/301ffaf61dbb4fca1a855650ab80707ae6d9f602))
|
||||
* Add exit status code to apps ([7674da4](https://github.com/HeyPuter/puter/commit/7674da4cd225bcad34079251c5600fc32e32248b))
|
||||
* add external mod loading ([eb05fbd](https://github.com/HeyPuter/puter/commit/eb05fbd2dc4877553b5118a069a9afdc32bea137))
|
||||
* add group management endpoints ([4216346](https://github.com/HeyPuter/puter/commit/4216346384d90dcba429dbcb175e6f86482d19f4))
|
||||
* add group permission endpoints ([c374b0c](https://github.com/HeyPuter/puter/commit/c374b0cbca761e7c8a47d56a09551f2e9378066a))
|
||||
* add mark-read endpoint ([0101f42](https://github.com/HeyPuter/puter/commit/0101f425d480705c20df4919a76f66e987f5790f))
|
||||
* add permission rewriter for app by name ([16c4907](https://github.com/HeyPuter/puter/commit/16c4907be592dae31ed3c1aa3fac3b9655255d6f))
|
||||
* add protected apps ([f2f3d6f](https://github.com/HeyPuter/puter/commit/f2f3d6ff460932698fb8da7309fbce3e96132950))
|
||||
* add protected subdomains ([86fca17](https://github.com/HeyPuter/puter/commit/86fca17fb17c0c24397c29b49b133deadea1de8b))
|
||||
* add querystring-informed errors ([e7c0b83](https://github.com/HeyPuter/puter/commit/e7c0b8320a6829315d9154d6d513bab4491c47ea))
|
||||
* add readdir delegate for shares in a user directory ([8424d44](https://github.com/HeyPuter/puter/commit/8424d446099ac30ccf829c57d43eef1f235618e4))
|
||||
* add readdir delegate for sharing user homedirs ([19a5eb0](https://github.com/HeyPuter/puter/commit/19a5eb00763f3ac31df8483fb59cb7a96c448745))
|
||||
* add service for notifications ([a1e6887](https://github.com/HeyPuter/puter/commit/a1e6887bf93da21b9482040b3e30ee083fb23477))
|
||||
* add service to test file share logic ([332371f](https://github.com/HeyPuter/puter/commit/332371fccb198462948a440419adc7a26d671a23))
|
||||
* add share list to stat ([8c49ba2](https://github.com/HeyPuter/puter/commit/8c49ba2553ce6bee20eb5b6f2721bc80f639e98a))
|
||||
* add share service and share-by-email to /share ([db5990a](https://github.com/HeyPuter/puter/commit/db5990a98935817c0e16d30e921bb99c57a98fc8))
|
||||
* add subdomain permission (if applicable) on app share ([13e2f72](https://github.com/HeyPuter/puter/commit/13e2f72c9f33f485570f13f45341246b1a05879f))
|
||||
* add user-group permission check ([0014940](https://github.com/HeyPuter/puter/commit/00149402e041443aa3ac571fbe97a9a85f95564b))
|
||||
* **backend:** add script service ([30550fc](https://github.com/HeyPuter/puter/commit/30550fcddda18469735499546de502d29b85e2ad))
|
||||
* **backend:** Add tab completion to server console command arguments ([fa81dca](https://github.com/HeyPuter/puter/commit/fa81dca9507b7fa0f82099b75f2ab89c865626ac))
|
||||
* **backend:** Add tab-completion to server console command names ([e1e76c6](https://github.com/HeyPuter/puter/commit/e1e76c6be71fdeb3b6246307b626734d8dc26f86))
|
||||
* **backend:** add tip of day ([2d8e624](https://github.com/HeyPuter/puter/commit/2d8e6240c61dc6301f49cbdcd1c3b04736f9ca93))
|
||||
* **backend:** allow services to provide user properties ([522664d](https://github.com/HeyPuter/puter/commit/522664d415c33342500defec309c2ff15bc94804))
|
||||
* **backend:** allow services to provide whoami values ([fccabf1](https://github.com/HeyPuter/puter/commit/fccabf1bc0c4418f3599222616dd63bf98c14fe1))
|
||||
* **backend:** improve logger and reduce logs ([4bdad75](https://github.com/HeyPuter/puter/commit/4bdad75766d0617a164024b39b79bf5373c495a6))
|
||||
* Display app icon and description in embeds ([ef298ce](https://github.com/HeyPuter/puter/commit/ef298ce3aa3ce90224e883fb0ba33f9cd3a3da44))
|
||||
* get first test working on share-test service ([88d6bee](https://github.com/HeyPuter/puter/commit/88d6bee9546f36d689c53ec7fe95f01f772f5211))
|
||||
* **git:** Add --color and --no-color options ([d6dd1a5](https://github.com/HeyPuter/puter/commit/d6dd1a5bb0a2b2bba2cfe86d2e51ff2a6e42841c))
|
||||
* **git:** Add a --debug option, which sets the DEBUG global ([fa3df72](https://github.com/HeyPuter/puter/commit/fa3df72f6ed2d45a440ebc2aacbbae67bf042478))
|
||||
* **git:** Add authentication to clone, fetch, and pull. ([364d580](https://github.com/HeyPuter/puter/commit/364d580ff896691ee70d3735f495c720651a9f41))
|
||||
* **git:** Add diff display to `show` and `log` subcommands ([3cad1ec](https://github.com/HeyPuter/puter/commit/3cad1ec436f99a78f782ab9576325d4341284964))
|
||||
* **git:** Add start-revision and file arguments to `git log` ([49c2f16](https://github.com/HeyPuter/puter/commit/49c2f163515d2130c17a6f6a6a16bc27ea69336a))
|
||||
* **git:** Allow checking out a commit instead of a branch ([057b3ac](https://github.com/HeyPuter/puter/commit/057b3acf00af49c005b9bf7069c5d22983a32e1e))
|
||||
* **git:** Color output for `git status` files ([bab5204](https://github.com/HeyPuter/puter/commit/bab5204209aa2efc0c053643677a78db6ede0929))
|
||||
* **git:** Display file contents as a string for `git show FILE_OID` ([a680371](https://github.com/HeyPuter/puter/commit/a68037111a04580cfa2688694a68ef6ac7a495fa))
|
||||
* **git:** Display ref names in `git log` and `git show` ([45cdfcb](https://github.com/HeyPuter/puter/commit/45cdfcb5bfa66937b33054a127e0b17001f3faa4))
|
||||
* **git:** Format output closer to canonical git ([60976b1](https://github.com/HeyPuter/puter/commit/60976b1ed61984d9d290f3a0ae99dd97632e9909))
|
||||
* **git:** Handle detached HEAD in `git status` and `git branch --list` ([2c9b1a3](https://github.com/HeyPuter/puter/commit/2c9b1a3ffc3d5e282ffe5b83a86314e99445bbc6))
|
||||
* **git:** Implement `git branch` ([ad4f132](https://github.com/HeyPuter/puter/commit/ad4f13255d52f8226f22800c16b388cf0e6384d7))
|
||||
* **git:** Implement `git checkout` ([35e4453](https://github.com/HeyPuter/puter/commit/35e4453930bc4e151887f83c97efec19cc15da70))
|
||||
* **git:** Implement `git cherry-pick` ([2e4259d](https://github.com/HeyPuter/puter/commit/2e4259d267b3cfafd5cefc57a02643c6432fec4d))
|
||||
* **git:** Implement `git clone` ([95c8235](https://github.com/HeyPuter/puter/commit/95c8235a4a1fea39a46c40df04cb1004a2fe7b23))
|
||||
* **git:** Implement `git diff` ([622b6a9](https://github.com/HeyPuter/puter/commit/622b6a9b921c3c03efc0b519c9a26c6701d80e50))
|
||||
* **git:** Implement `git fetch` ([98a4b9e](https://github.com/HeyPuter/puter/commit/98a4b9ede39b94c0c6b6b8345d7551359961186a))
|
||||
* **git:** Implement `git pull` ([eb2b6a0](https://github.com/HeyPuter/puter/commit/eb2b6a08b03cee0612885412cd4b03c9564044e3))
|
||||
* **git:** Implement `git push` ([8c70229](https://github.com/HeyPuter/puter/commit/8c70229a188b743220db076a740a992fd7971301))
|
||||
* **git:** Implement `git remote` ([43ce0d5](https://github.com/HeyPuter/puter/commit/43ce0d5b45d4eb4f296afcaaa1ecadc125c53e89))
|
||||
* **git:** Implement `git restore` ([4ba8a32](https://github.com/HeyPuter/puter/commit/4ba8a32b45d395f28433572db5644d630776789e))
|
||||
* **git:** Make `git add` work for deleted files ([9551544](https://github.com/HeyPuter/puter/commit/955154468f48e45028dad2e916708d6a763affad))
|
||||
* **git:** Make shorten_hash() guaranteed to produce a unique hash ([dd10a37](https://github.com/HeyPuter/puter/commit/dd10a377493c0d8f10a1ac8779dc27f3f3bf6c37))
|
||||
* **git:** Resolve more forms of commit reference ([b6906bb](https://github.com/HeyPuter/puter/commit/b6906bbcaaa50fc8a8c60beb6d2d38bcb7dda758))
|
||||
* **git:** Understand references like `HEAD^` and `main~3` ([711dbc0](https://github.com/HeyPuter/puter/commit/711dbc0d2fde9c2ddc6c86f64fb4caa7837c9dcb))
|
||||
* implicit access from apps to shared appdata dirs ([31d4eb0](https://github.com/HeyPuter/puter/commit/31d4eb090efb340fdfb7cb6b751145e859624eeb))
|
||||
* introduce notification selection via driver ([c5334b0](https://github.com/HeyPuter/puter/commit/c5334b0e19cf9762f536ec482c3ff872e9c12399))
|
||||
* multi-recipient multi-file share endpoint ([846fdc2](https://github.com/HeyPuter/puter/commit/846fdc20d4a887a1f8a4f3bda4fafe41efab2733))
|
||||
* **parsely:** Add a fail() parser ([5656d9d](https://github.com/HeyPuter/puter/commit/5656d9d42f76202a534ad640d3a4e287e0e40418))
|
||||
* **parsely:** Add stringUntil() parser ([d46b043](https://github.com/HeyPuter/puter/commit/d46b043c5d16f1205d61de3f3ba43ed8ad7bff93))
|
||||
* **phoenix:** Add --dump and --file options to sed ([f250f86](https://github.com/HeyPuter/puter/commit/f250f86446a506f24fa2ad396328e3a2212a68d0))
|
||||
* **phoenix:** Add more commands to sed, including labels and branching ([306014a](https://github.com/HeyPuter/puter/commit/306014adc77a7ca155feb95d1146cb46ee075b52))
|
||||
* **phoenix:** Expose parsed arg tokens to apps that request them ([4067c82](https://github.com/HeyPuter/puter/commit/4067c82486c99cad20f41927ad39ebea438b717f))
|
||||
* **phoenix:** Implement an `exit` builtin ([3184d34](https://github.com/HeyPuter/puter/commit/3184d3482c7b95c0fd1fc0745555ff82fc9a8c99))
|
||||
* **phoenix:** Implement parsing of sed scripts ([0d4f907](https://github.com/HeyPuter/puter/commit/0d4f907b6675b15bd50a55f50aa28f0803b18b7b))
|
||||
* **phoenix:** Make `clear` clear scrollback unless `-x` is given ([75a989a](https://github.com/HeyPuter/puter/commit/75a989a7b69bfdfdf69e5f0365027c5b27d8bfc6))
|
||||
* **Phoenix:** Pass command line arguments and ENV when launching apps ([8f1c4fc](https://github.com/HeyPuter/puter/commit/8f1c4fcda98e72a7b970e8c6fc2fe39a5e012264))
|
||||
* **phoenix:** Respond to exit status codes ([5de3052](https://github.com/HeyPuter/puter/commit/5de305202656a172b187dac87543d6c1c69a2958))
|
||||
* **phoenix:** Show actual host name in prompt and neofetch ([4539408](https://github.com/HeyPuter/puter/commit/4539408a218a50244dc615cf7de56c29dcac53e6))
|
||||
* rate-limit for excessive groups ([4af279a](https://github.com/HeyPuter/puter/commit/4af279a72fc9de89ddc3ba51806ca3760a36265d))
|
||||
* re-send unreads on login ([02fc4d8](https://github.com/HeyPuter/puter/commit/02fc4d86b7166fb4803be5d28e2a593d6b7d9785))
|
||||
* register dev center to apps ([10f4d7d](https://github.com/HeyPuter/puter/commit/10f4d7d50ce9314f9c3888c74cb17c8ebbecee98))
|
||||
* send notification when file gets shared ([2f6c428](https://github.com/HeyPuter/puter/commit/2f6c428a403a006f7878861d2f0356c3294519be))
|
||||
* start directory index frame ([fb1e2f2](https://github.com/HeyPuter/puter/commit/fb1e2f21fb67aefe0602f6c978199c7cd019bbf7))
|
||||
* support canonical puter.js url in dev ([fd41ae2](https://github.com/HeyPuter/puter/commit/fd41ae217c7a9f7229326f62a829471580a744bd))
|
||||
* **ui:** add new components ([577bd59](https://github.com/HeyPuter/puter/commit/577bd59b6cc94810e851ad544f8234e25a4e6e27))
|
||||
* **ui:** add new components ([38ba425](https://github.com/HeyPuter/puter/commit/38ba42575ce9f3506f8ce219b9580202b3ed9993))
|
||||
* **ui:** allow component-based settings tabs ([1245960](https://github.com/HeyPuter/puter/commit/124596058a286241b51dd87ce2fc1a68478cb5b8))
|
||||
* update share endpoint to support more things ([dd5fde5](https://github.com/HeyPuter/puter/commit/dd5fde5130c1840ab598e6622766ae835142e58a))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* add app_uid param to kv interface ([f7a0549](https://github.com/HeyPuter/puter/commit/f7a054956b8739a3bc305a49faee929ea0da1e15))
|
||||
* add missing columns for public directory update ([b10302a](https://github.com/HeyPuter/puter/commit/b10302ad744fd9c58f9735743e075815183c772c))
|
||||
* Add missing file extension to 0009_app-prefix-fix.sql in DB init ([a8160a8](https://github.com/HeyPuter/puter/commit/a8160a8cdcdd6aff98728a6f1643d93386e6bb5a))
|
||||
* add permission implicator for file modes ([e63ab3a](https://github.com/HeyPuter/puter/commit/e63ab3a67f6555eb13d6af477a8da9f1b54d6608))
|
||||
* add stream limit ([ceba309](https://github.com/HeyPuter/puter/commit/ceba309dbd4df89f310d1a530f939a5b7991f4c7))
|
||||
* **backend:** remove a bad thing that really doesn't work ([8d22276](https://github.com/HeyPuter/puter/commit/8d22276f13106f7642d11da30b1500817a20ad43))
|
||||
* bug introduced when refactoring /share to Sequence ([ecb9978](https://github.com/HeyPuter/puter/commit/ecb997885c1efb766827c84d2ffb8dc6ddabe992))
|
||||
* check subdomain earlier for /apps ([4e3a24e](https://github.com/HeyPuter/puter/commit/4e3a24e6093e279e210765e07e436f4e63b74072))
|
||||
* column nullability blunder ([1429d6f](https://github.com/HeyPuter/puter/commit/1429d6f57c67dff51fc41ca0c2868f8d000845f1))
|
||||
* Correct APIError imports ([062e23b](https://github.com/HeyPuter/puter/commit/062e23b5c9673db1f8b0ff0469289d52dd1e3f99))
|
||||
* correct shown flag behavior ([632c536](https://github.com/HeyPuter/puter/commit/632c5366161ff8fbbd4d60c61dfbe52dad488a2c))
|
||||
* database migration ([9b39309](https://github.com/HeyPuter/puter/commit/9b39309e18a2927d25fe794d91da4e4d068c4bca))
|
||||
* do not delegate to select on read like ever that is really dumb ([a2a10b9](https://github.com/HeyPuter/puter/commit/a2a10b94be59403e03fb08bec5d7c056ce5b554f))
|
||||
* docker runtime fail because stdout columns ([94c0449](https://github.com/HeyPuter/puter/commit/94c0449437ce4cb26d00a15a3f277bc7b09367b4))
|
||||
* fix issues with apps in /share endpoint ([0cf90ee](https://github.com/HeyPuter/puter/commit/0cf90ee39af6548d271dec45ed8ee9e6df1cd14d))
|
||||
* fix owner ids for default apps ([283f409](https://github.com/HeyPuter/puter/commit/283f409a662d126e7f3ce811f1467ac6fab9a522))
|
||||
* fix permission cascade properly this time ([de58866](https://github.com/HeyPuter/puter/commit/de5886698e1eae2b250baac174b57029f3244e96))
|
||||
* Fix phoenix app prefix and TokenService test ([afb9d86](https://github.com/HeyPuter/puter/commit/afb9d866b5091058711db931cde904947e661c15))
|
||||
* fix that fix ([b126b67](https://github.com/HeyPuter/puter/commit/b126b670940a0e20cfe7bd0eba3db891bab5c142))
|
||||
* fix typo ([ce328b7](https://github.com/HeyPuter/puter/commit/ce328b7245ad741b64c5885f64f806fc98a55d84))
|
||||
* **git:** Make git commit display detached HEAD correctly ([73d0f5a](https://github.com/HeyPuter/puter/commit/73d0f5a90cb5dcbadfc6d0fd22f14e8bc0e61f86))
|
||||
* group permission audit table ([7d2f6d2](https://github.com/HeyPuter/puter/commit/7d2f6d256f56e30d752e9999c6e8bde68f9d9637))
|
||||
* handle subpaths under another user ([d128cee](https://github.com/HeyPuter/puter/commit/d128ceed6f4928fa0793815feb2e2715cd273ff8))
|
||||
* handling of batch requests with zero files ([c0063a8](https://github.com/HeyPuter/puter/commit/c0063a871fd891a1774f1bee00e86170fed249fa))
|
||||
* i forgot to test reloading ([7eabb43](https://github.com/HeyPuter/puter/commit/7eabb43bd4257b4129d67eaeda2aa27e8268dc78))
|
||||
* improve console experience on mac ([15465bf](https://github.com/HeyPuter/puter/commit/15465bfc5035a64762f7c86a3d38af8be6be5b59))
|
||||
* incorrect error from suggested_apps ([b648817](https://github.com/HeyPuter/puter/commit/b648817f2743c2b6214ebe4177d921c9b9027594))
|
||||
* Make polyfilled import.meta.filename getter a valid function ([85c6798](https://github.com/HeyPuter/puter/commit/85c679844869b6b05fcbda231d8dc7026a66da97))
|
||||
* null email in request to /share ([bf63144](https://github.com/HeyPuter/puter/commit/bf63144f7a79c48bd650ae851ddd0c8a10d748c3))
|
||||
* Only run Component initialization functions once ([5b43358](https://github.com/HeyPuter/puter/commit/5b43358219402bee3eadf4a0f184a4b924d3293b))
|
||||
* oops ([a136ee5](https://github.com/HeyPuter/puter/commit/a136ee5edd3149798a0d82f494f423f503b65f00))
|
||||
* **parsely:** Make Repeat parser work when no separator is given ([9b4d16f](https://github.com/HeyPuter/puter/commit/9b4d16fbe9d5698c57f9da725a22b528a7d7cac2))
|
||||
* peers array assumption ([10cbf08](https://github.com/HeyPuter/puter/commit/10cbf08233620440aa39f5302deaac4f59f02247))
|
||||
* **phoenix:** Add missing newlines to sed command output ([e047b0b](https://github.com/HeyPuter/puter/commit/e047b0bf302284da61e677432e4cc25b531b24f2))
|
||||
* **phoenix:** Gracefully handle completing a non-existent path ([d76e713](https://github.com/HeyPuter/puter/commit/d76e7130cba9f0ca05940abafe4fd1a41464aa83))
|
||||
* property validation on some permission endpoints ([0855f2b](https://github.com/HeyPuter/puter/commit/0855f2b36eca3bbdaa8429cbde3aa1242e8e96ee))
|
||||
* readdir on file ([a72ec97](https://github.com/HeyPuter/puter/commit/a72ec9799ac3bd76ceafa22cce149e373a13f3b9))
|
||||
* remove last component when share URL is file ([1166e69](https://github.com/HeyPuter/puter/commit/1166e69c76688d1811701c56cd4df9d38e286793))
|
||||
* remove legacy permission check in stat ([f2c6e01](https://github.com/HeyPuter/puter/commit/f2c6e01296e4214336e63bc2d69bcbf17f59890f))
|
||||
* Remove null or duplicate app entries from suggest_app_for_fsentry() ([6900233](https://github.com/HeyPuter/puter/commit/6900233c5aaa2d1a49f495e9f9a060796757a91e))
|
||||
* **security:** Move token for socket.io to request body ([49b257e](https://github.com/HeyPuter/puter/commit/49b257ecffbb1e12090b86a67528a5ad09da69db))
|
||||
* switch share notif username to sender ([cd65217](https://github.com/HeyPuter/puter/commit/cd65217f5cda1c986ee231e2eeeef5abefa36ecb))
|
||||
* **Terminal:** Accept input from Chrome on Android ([4ef3e53](https://github.com/HeyPuter/puter/commit/4ef3e53de34f0097950a7e707ca2483863beafb5))
|
||||
* Throw an error when readdir is called on a non-directory ([46eb4ed](https://github.com/HeyPuter/puter/commit/46eb4ed2b96c235e10e15645a30d2f192a1af0de))
|
||||
* type error in puter-site ([d96f924](https://github.com/HeyPuter/puter/commit/d96f924cad7a13ea6e9084bb0ebb79ecc5fcb8a3))
|
||||
* ui color input attributes ([d9c4fbb](https://github.com/HeyPuter/puter/commit/d9c4fbbd1dcce12ee05ee33652a5fa518196463d))
|
||||
* **ui:** improve Component base class ([f8780d0](https://github.com/HeyPuter/puter/commit/f8780d032b10138851c22af53b8610c578139acc))
|
||||
* update email share object ([9033f6f](https://github.com/HeyPuter/puter/commit/9033f6f8c74ef8739294d640ac1c7eba95519bbd))
|
||||
* update PD alert custom details ([2f16322](https://github.com/HeyPuter/puter/commit/2f163221bdde09425cae11ef7f8e4eb0b10c7103))
|
||||
* update test kernel ([55c609b](https://github.com/HeyPuter/puter/commit/55c609b3fec4ef018febc6e88c44a6277960d728))
|
||||
* validate size metadata ([2008db0](https://github.com/HeyPuter/puter/commit/2008db08524259264a0c8186a34fc75d7a133f5f))
|
||||
|
||||
## 2.3.0 (2024-05-22)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add /healthcheck endpoint ([c166560](https://github.com/HeyPuter/puter/commit/c166560ff4ab5a453d3ec4f97326c995deb7f522))
|
||||
* Add command names to phoenix tab-completion ([cf0eee1](https://github.com/HeyPuter/puter/commit/cf0eee1fa35328e05aefc8a425b5977efe5f4ec9))
|
||||
* add option to change desktop background to default ([03f05f3](https://github.com/HeyPuter/puter/commit/03f05f316f11e8afe5fcee40b2b80a0de5e6826f))
|
||||
* allow apps to add a menubar via puter.js ([331d9e7](https://github.com/HeyPuter/puter/commit/331d9e75428ec7609394f59b1755374c7340f83e))
|
||||
* Allow querying puter-apps driver by partial app names ([dc5b010](https://github.com/HeyPuter/puter/commit/dc5b010d0913d2151b4851f8da5df72d2c8f42e7))
|
||||
* Display upload errors in UIWindowProgress dialog ([edebbee](https://github.com/HeyPuter/puter/commit/edebbee9e7e9efbb33bf709b637c103be40d15a8))
|
||||
* Implement 'Like' predicate in entity storage ([a854a0d](https://github.com/HeyPuter/puter/commit/a854a0dc0aa79a31695db833184c5ca3698632a9))
|
||||
* improve password recovery experience ([04432df](https://github.com/HeyPuter/puter/commit/04432df5540811710ce1cc47ce6c136e5453bccb))
|
||||
* **security:** add ip rate limiting ([ccf1afc](https://github.com/HeyPuter/puter/commit/ccf1afc93c24ee7f9a126216209a185d6b4d9fe4))
|
||||
* Show "Deleting /foo" in progress window when deleting files ([f07c13a](https://github.com/HeyPuter/puter/commit/f07c13a50cee790eec44bce2f6e56fbcbf73f9b0))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Add missing file extension to 0009_app-prefix-fix.sql in DB init ([a8160a8](https://github.com/HeyPuter/puter/commit/a8160a8cdcdd6aff98728a6f1643d93386e6bb5a))
|
||||
* Add missing TextEncoder to PTT ([8d4a1e0](https://github.com/HeyPuter/puter/commit/8d4a1e0ed3872e2c82b9e4be9b6d8b359e9cea09))
|
||||
* Correct APIError imports ([062e23b](https://github.com/HeyPuter/puter/commit/062e23b5c9673db1f8b0ff0469289d52dd1e3f99))
|
||||
* Correct grep output when asking for line numbers ([c8a20ca](https://github.com/HeyPuter/puter/commit/c8a20cadbfd539d185d32f4558916825fcf265ba))
|
||||
* Correct inverted instanceof check in SignalReader.read() ([d4c2b49](https://github.com/HeyPuter/puter/commit/d4c2b492ef4864804776d3cb7d24797fdc536886))
|
||||
* Correct variables used in errors in sign.js ([fa7c6be](https://github.com/HeyPuter/puter/commit/fa7c6bee9699527028be0ae9759155bc67c52324))
|
||||
* Eliminates duplicate translation keys ([5800350](https://github.com/HeyPuter/puter/commit/5800350b253994dea410afff64e3df2a171e7775))
|
||||
* fix error handling for outdated node versions ([4c1d5a4](https://github.com/HeyPuter/puter/commit/4c1d5a4b6d009ce075897d499d3517219bd745a4))
|
||||
* Fix phoenix app prefix and TokenService test ([afb9d86](https://github.com/HeyPuter/puter/commit/afb9d866b5091058711db931cde904947e661c15))
|
||||
* increase QR code size ([d2de46e](https://github.com/HeyPuter/puter/commit/d2de46edfbc05d132d5c929f6935b82515fbbda0))
|
||||
* Make PathCommandProvider reject queries with path separators ([d733119](https://github.com/HeyPuter/puter/commit/d73311945610417a1ebc7bb0723ced0a599594b4))
|
||||
* Make url variable accessible to all users of it ([2f30ae7](https://github.com/HeyPuter/puter/commit/2f30ae7a825adcd8da95888c38fe39c34acee0ff))
|
||||
* Only run Component initialization functions once ([5b43358](https://github.com/HeyPuter/puter/commit/5b43358219402bee3eadf4a0f184a4b924d3293b))
|
||||
* Parse octal echo escapes ([6ad8f5e](https://github.com/HeyPuter/puter/commit/6ad8f5e06abd050d319271f818d72debf5bc8e44))
|
||||
* reduce token lengths ([5a76bad](https://github.com/HeyPuter/puter/commit/5a76bad28dfd8ec89a309941e410a54927fae22d))
|
||||
* reliability issue :bug: ([1d546d9](https://github.com/HeyPuter/puter/commit/1d546d9ef70ef9066ad5838e9782ae330d289f29))
|
||||
* Remove null or duplicate app entries from suggest_app_for_fsentry() ([6900233](https://github.com/HeyPuter/puter/commit/6900233c5aaa2d1a49f495e9f9a060796757a91e))
|
||||
* **security:** always use application/octet-stream ([74e213a](https://github.com/HeyPuter/puter/commit/74e213a534dbf2844c8cebeee7eb59ec70de306e))
|
||||
* **security:** Fix session revocation ([eb166a6](https://github.com/HeyPuter/puter/commit/eb166a67a9f0caf4fd77f9e27dc8209c2fc51f4c))
|
||||
* **security:** Move token for socket.io to request body ([49b257e](https://github.com/HeyPuter/puter/commit/49b257ecffbb1e12090b86a67528a5ad09da69db))
|
||||
* **security:** Prevent email enumeration ([ed70314](https://github.com/HeyPuter/puter/commit/ed703146863f896df76c98fad7127c6748c0ef9b))
|
||||
* **security:** skip cache when checking old passwd ([7800ef6](https://github.com/HeyPuter/puter/commit/7800ef61029c8d1ba47491b4028a0cb972298725))
|
||||
* **Terminal:** Accept input from Chrome on Android ([4ef3e53](https://github.com/HeyPuter/puter/commit/4ef3e53de34f0097950a7e707ca2483863beafb5))
|
||||
* test release-please action [#3](https://github.com/HeyPuter/puter/issues/3) ([8fb0a66](https://github.com/HeyPuter/puter/commit/8fb0a66ef21921990e564e5f61c0e80e7f929dc7))
|
||||
* test release-please action [#4](https://github.com/HeyPuter/puter/issues/4) ([f392de7](https://github.com/HeyPuter/puter/commit/f392de722a5232b622ed91b656a31cdc443c2e84))
|
||||
* typographical error :bug: ([2949f71](https://github.com/HeyPuter/puter/commit/2949f71691eb0a258888c5d2a5bb496d2fe64a23))
|
||||
* typographical errors :bug: ([4d30740](https://github.com/HeyPuter/puter/commit/4d30740198402cd1cc61b9ea4c45e006b69ec87e))
|
||||
* Use correct variable for version number ([52d5299](https://github.com/HeyPuter/puter/commit/52d52993744dffa9f7f59a232da5df9077560731))
|
||||
* use primary read in signup ([30f17ad](https://github.com/HeyPuter/puter/commit/30f17ade3a893d2283316e581836607e2029f9b9))
|
||||
|
||||
## [2.2.0](https://github.com/HeyPuter/puter/compare/v2.1.1...v2.2.0) (2024-04-23)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add /healthcheck endpoint ([c166560](https://github.com/HeyPuter/puter/commit/c166560ff4ab5a453d3ec4f97326c995deb7f522))
|
||||
* allow apps to add a menubar via puter.js ([331d9e7](https://github.com/HeyPuter/puter/commit/331d9e75428ec7609394f59b1755374c7340f83e))
|
||||
|
||||
## [2.1.1](https://github.com/HeyPuter/puter/compare/v2.1.0...v2.1.1) (2024-04-22)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* test release-please action [#3](https://github.com/HeyPuter/puter/issues/3) ([8fb0a66](https://github.com/HeyPuter/puter/commit/8fb0a66ef21921990e564e5f61c0e80e7f929dc7))
|
||||
* test release-please action [#4](https://github.com/HeyPuter/puter/issues/4) ([f392de7](https://github.com/HeyPuter/puter/commit/f392de722a5232b622ed91b656a31cdc443c2e84))
|
||||
@@ -57,6 +57,28 @@ See [doc/contributors/index.md](./doc/contributors/index.md) for more informatio
|
||||
|
||||
<br>
|
||||
|
||||
## Commit Messages
|
||||
|
||||
Use the imperative, as is the convention in the Linux kernel:
|
||||
|
||||
- correct: `Improve performance of readdir`
|
||||
- incorrect: `Improved readdir`
|
||||
- incorrect: `Improving readdir`
|
||||
|
||||
We have the following exceptions to this rule:
|
||||
- If the commit message is in _past tense_, it's a shorthand for the following:
|
||||
- `Apply changes that would be applied after one had <past tense message>`
|
||||
- If the commit message is in _present tense_, it's shorthand for the following:
|
||||
- `Apply changes that would be applied after <present-tense message>`
|
||||
|
||||
For example, the following are correct:
|
||||
- `Improved readdir`
|
||||
- interpret this as: `Apply changes that would be applied after one had improved readdir`
|
||||
- `Improving readdir`
|
||||
- interpret this as: `Apply changes that would be applied after improving readdir`
|
||||
|
||||
<br>
|
||||
|
||||
## Code Review
|
||||
|
||||
Once you've submitted your pull request, the project maintainers will review your changes. We may suggest some changes or improvements. This is a normal part of the process, and your contributions are greatly appreciated!
|
||||
|
||||
+45
-11
@@ -1,30 +1,64 @@
|
||||
# /!\ NOTICE /!\
|
||||
|
||||
# Many of the developers DO NOT USE the Dockerfile or image.
|
||||
# While we do test new changes to Docker configuration, it's
|
||||
# possible that future changes to the repo might break it.
|
||||
# When changing this file, please try to make it as resiliant
|
||||
# to such changes as possible; developers shouldn't need to
|
||||
# worry about Docker unless the build/run process changes.
|
||||
|
||||
# Build stage
|
||||
FROM node:21-alpine AS build
|
||||
|
||||
# Install build dependencies
|
||||
RUN apk add --no-cache git python3 make g++ \
|
||||
&& ln -sf /usr/bin/python3 /usr/bin/python
|
||||
|
||||
# Set up working directory
|
||||
WORKDIR /app
|
||||
|
||||
# Copy package.json and package-lock.json
|
||||
COPY package*.json ./
|
||||
|
||||
# Copy the source files
|
||||
COPY . .
|
||||
|
||||
# Install node modules
|
||||
RUN npm cache clean --force \
|
||||
&& npm ci
|
||||
|
||||
# Run the build command if necessary
|
||||
RUN cd src/gui && npm run build && cd -
|
||||
|
||||
# Production stage
|
||||
FROM node:21-alpine
|
||||
|
||||
# Set labels
|
||||
LABEL repo="https://github.com/HeyPuter/puter"
|
||||
LABEL license="AGPL-3.0,https://github.com/HeyPuter/puter/blob/master/LICENSE.txt"
|
||||
LABEL version="v1.2.40-beta"
|
||||
LABEL version="1.2.46-beta-1"
|
||||
|
||||
# Debugging
|
||||
RUN apk add --no-cache bash # useful for debugging
|
||||
# Install git (required by Puter to check version)
|
||||
RUN apk add --no-cache git
|
||||
|
||||
# Setup working directory
|
||||
# Set up working directory
|
||||
RUN mkdir -p /opt/puter/app
|
||||
WORKDIR /opt/puter/app
|
||||
|
||||
# Add source files
|
||||
# NOTE: This might change (https://github.com/HeyPuter/puter/discussions/32)
|
||||
# Copy built artifacts and necessary files from the build stage
|
||||
COPY --from=build /app/src/gui/dist ./dist
|
||||
COPY --from=build /app/node_modules ./node_modules
|
||||
COPY . .
|
||||
|
||||
# Set permissions
|
||||
RUN chown -R node:node /opt/puter/app
|
||||
USER node
|
||||
|
||||
# Install node modules
|
||||
RUN npm cache clean --force \
|
||||
&& npm install
|
||||
|
||||
EXPOSE 4100
|
||||
|
||||
HEALTHCHECK --interval=30s --timeout=3s \
|
||||
CMD wget --no-verbose --tries=1 --spider http://puter.localhost:4100/test || exit 1
|
||||
|
||||
CMD [ "npm", "start" ]
|
||||
ENV NO_VAR_RUNTUME=1
|
||||
|
||||
CMD ["npm", "start"]
|
||||
@@ -1,6 +1,6 @@
|
||||
<h3 align="center"><img width="80" alt="Puter.com, The Personal Cloud Computer: All your files, apps, and games in one place accessible from anywhere at any time." src="https://assets.puter.site/puter-logo.png"></h3>
|
||||
|
||||
<h3 align="center">The Internet OS! Free, Open-Source, and Self-Hostable!</h3>
|
||||
<h3 align="center">The Internet OS! Free, Open-Source, and Self-Hostable.</h3>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://puter.com/"><strong>« LIVE DEMO »</strong></a>
|
||||
@@ -15,25 +15,35 @@
|
||||
<a href="https://reddit.com/r/puter">Reddit</a>
|
||||
·
|
||||
<a href="https://twitter.com/HeyPuter">X (Twitter)</a>
|
||||
·
|
||||
<a href="https://hackerone.com/puter_h1b">Bug Bounty</a>
|
||||
</p>
|
||||
|
||||
<h3 align="center"><img width="700" style="border-radius:5px;" alt="screenshot" src="https://assets.puter.site/puter.com-screenshot-2.webp"></h3>
|
||||
<h3 align="center"><img width="700" style="border-radius:5px;" alt="screenshot" src="https://assets.puter.site/puter.com-screenshot-3.webp"></h3>
|
||||
|
||||
<br/>
|
||||
|
||||
## Puter
|
||||
|
||||
Puter is an advanced, open-source internet operating system designed to be feature-rich, exceptionally fast, and highly extensible. It can be used to build remote desktop environments or serve as an interface for cloud storage services, remote servers, web hosting platforms, and more.
|
||||
Puter is an advanced, open-source internet operating system designed to be feature-rich, exceptionally fast, and highly extensible. Puter can be used as:
|
||||
|
||||
- A privacy-first personal cloud to keep all your files, apps, and games in one secure place, accessible from anywhere at any time.
|
||||
- A platform for building and publishing websites, web apps, and games.
|
||||
- An alternative to Dropbox, Google Drive, OneDrive, etc. with a fresh interface and powerful features.
|
||||
- A remote desktop environment for servers and workstations.
|
||||
- A friendly, open-source project and community to learn about web development, cloud computing, distributed systems, and much more!
|
||||
|
||||
<br/>
|
||||
|
||||
## Getting Started
|
||||
|
||||
### Local Development
|
||||
|
||||
### 💻 Local Development
|
||||
|
||||
```bash
|
||||
git clone https://github.com/HeyPuter/puter
|
||||
cd puter
|
||||
cp .env.example .env
|
||||
npm install
|
||||
npm start
|
||||
```
|
||||
@@ -42,87 +52,54 @@ This will launch Puter at http://localhost:4000 (or the next available port).
|
||||
|
||||
<br/>
|
||||
|
||||
### Using Docker
|
||||
### 🐳 Docker
|
||||
|
||||
|
||||
```bash
|
||||
git clone https://github.com/HeyPuter/puter
|
||||
cd puter
|
||||
docker compose up
|
||||
mkdir puter && cd puter && mkdir -p puter/config puter/data && sudo chown -R 1000:1000 puter && docker run --rm -p 4100:4100 -v `pwd`/puter/config:/etc/puter -v `pwd`/puter/data:/var/puter ghcr.io/heyputer/puter
|
||||
```
|
||||
|
||||
<br/>
|
||||
|
||||
See [Configuration](#configuration) for next steps.
|
||||
|
||||
### 🐙 Docker Compose
|
||||
|
||||
|
||||
```bash
|
||||
mkdir -p puter/config puter/data
|
||||
sudo chown -R 1000:1000 puter
|
||||
wget https://raw.githubusercontent.com/HeyPuter/puter/main/docker-compose.yml
|
||||
docker compose up
|
||||
```
|
||||
<br/>
|
||||
|
||||
## ⚠️ Self-Hosting ⚠️
|
||||
The self-hosted version of Puter is currently in alpha stage and should not be used in production yet. It is under active development and may contain bugs, other issues. Please exercise caution and use it for testing and evaluation purposes only.
|
||||
### ☁️ Puter.com
|
||||
|
||||
## Configuration
|
||||
|
||||
Running the server will generate a configuration file at `volatile/config/config.json`.
|
||||
|
||||
### Domain Name
|
||||
|
||||
To access Puter on your device, you can simply go to the address printed in
|
||||
the server console (usually `puter.localhost:4100`).
|
||||
|
||||
To access Puter from another device, a domain name must be configured, as well as
|
||||
an `api` subdomain. For example, `example.local` might be the domain name pointing
|
||||
to the IP address of the server running puter, and `api.example.com` must point to
|
||||
this address as well. This domain must be specified in the configuration file
|
||||
(usually `volatile/config/config.json`) as well.
|
||||
|
||||
See [domain configuration](./doc/self-hosters/domains.md) for more information.
|
||||
|
||||
### Default User
|
||||
|
||||
By default, Puter will create a user called `default_user` with the password
|
||||
`changeme`. A warning will persist in the dev console until this user's
|
||||
password is changed. Please login to this user and change the password as
|
||||
your first step. This user by default has 10GB storage instead of the default
|
||||
(500MB storage) for new/temporary users.
|
||||
|
||||
<br/>
|
||||
|
||||
## FAQ
|
||||
|
||||
### ❓ What's the use case for Puter?
|
||||
|
||||
Puter can be used as:
|
||||
|
||||
- An alternative to Dropbox, Google Drive, OneDrive, etc. with a fresh interface and powerful features.
|
||||
- Remote desktop environment for servers and workstations.
|
||||
- A platform for building and hosting websites, web apps, and games.
|
||||
- A friendly, open-source project and community to learn about web development, cloud computing, distributed systems, and much more!
|
||||
Puter is available as a hosted service at [**puter.com**](https://puter.com).
|
||||
|
||||
<br/>
|
||||
|
||||
|
||||
### ❓ Why isn't Puter built with React, Angular, Vue, etc.?
|
||||
|
||||
For performance reasons, Puter is built with vanilla JavaScript and jQuery. Additionally, we'd like to avoid complex abstractions and to remain in control of the entire stack, as much as possible.
|
||||
## License
|
||||
|
||||
Also partly inspired by some of our favorite projects that are not built with frameworks: [VSCode](https://github.com/microsoft/vscode), [Photopea](https://www.photopea.com/), and [OnlyOffice](https://www.onlyoffice.com/).
|
||||
|
||||
<br/>
|
||||
|
||||
### ❓ Why jQuery?
|
||||
|
||||
Puter interacts directly with the DOM and jQuery provides an elegant yet powerful API to manipulate the DOM, handle events, and much more. It's also fast, mature, and battle-tested.
|
||||
This repository is licensed under AGPL-3.0; However, our SDK (puter.js) is also available under Apache 2.0, as indicated by the license file in that section (packages/puter-js) of this repository.
|
||||
|
||||
<br/>
|
||||
|
||||
## #DoesItRunPuter
|
||||
|
||||
- [Minecraft](https://twitter.com/HeyPuter/status/1771957571496092036) | [video](https://www.youtube.com/watch?v=GIowZUXkg5g)
|
||||
- [Samsung Watch](https://twitter.com/CharmunkDev/status/1781501714543030554)
|
||||
- [PlayStation 4](https://twitter.com/HeyPuter/status/1767978053014270059)
|
||||
- [Skyworth TV](https://twitter.com/ericalexdube/status/1767983049277411564)
|
||||
- [A Fridge!](https://twitter.com/HeyPuter/status/1778890003797745842)
|
||||
- [Oculus Quest 2](https://twitter.com/HeyPuter/status/1768664081756754012)
|
||||
- [Tesla Model 3](https://twitter.com/EricLighthall/status/1781479732997214501)
|
||||
- [Tesla Model S](https://twitter.com/HeyPuter/status/1767971178864587057)
|
||||
- [Tesla Model Y](https://twitter.com/HeyPuter/status/1772858333751636310)
|
||||
- Tesla Model 3
|
||||
- [Nintendo Switch](https://twitter.com/HeyPuter/status/1780645795240538518)
|
||||
- [Steam Deck](https://twitter.com/everythingSung/status/1782162352403828793)
|
||||
|
||||
<br/>
|
||||
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
# API Documentation
|
||||
|
||||
Note that this documentation is different from the [puter.js docs](https://docs.puter.com).
|
||||
The scope of the documentation in this directory includes both stable API endpoints that
|
||||
are used by **puter.js**, as well as API endpoints that may be subject to future changes.
|
||||
@@ -0,0 +1,9 @@
|
||||
# Share Links
|
||||
|
||||
A **share link** is a link to Puter's origin which contains a token
|
||||
in the query string (the key is `share_token`; ex:
|
||||
`http://puter.localhost:4100?share_token=...`).
|
||||
|
||||
This token can be used to apply permissions to the user of the
|
||||
current session **if and only if** this user's email is confirmed
|
||||
and matches the share link's associated email.
|
||||
@@ -0,0 +1,219 @@
|
||||
# Group Endpoints
|
||||
|
||||
## POST `/group/create` (auth required)
|
||||
|
||||
### Description
|
||||
|
||||
Creates a group and returns a UID (UUID formatted).
|
||||
Groups do not have names, or any other descriptive attributes.
|
||||
Instead they are always identified with a UUID, and they have
|
||||
a `metadata` property.
|
||||
|
||||
The `metadata` property will always be given back to the client
|
||||
in the same way it was provided. The `extra` property, also an
|
||||
object, may be changed by the backend. The behavior of setting
|
||||
any property on `extra` is currently undefined as all properties
|
||||
are reserved for future use.
|
||||
|
||||
### Parameters
|
||||
|
||||
- **metadata:** _- optional_
|
||||
- **accepts:** `object`
|
||||
- **description:** arbitrary metadata to describe the group
|
||||
- **extra:** _- optional_
|
||||
- **accepts:** `object`
|
||||
- **description:** extra parameters (server may change these)
|
||||
|
||||
### Request Example
|
||||
|
||||
```javascript
|
||||
await fetch(`${window.api_origin}/group/create`, {
|
||||
"headers": {
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": `Bearer ${puter.authToken}`,
|
||||
},
|
||||
"body": JSON.stringify({
|
||||
metadata: { title: 'Some Title' }
|
||||
}),
|
||||
"method": "POST",
|
||||
});
|
||||
|
||||
// { uid: '9c644a1c-3e43-4df4-ab67-de5b68b235b6' }
|
||||
```
|
||||
|
||||
### Response Example
|
||||
|
||||
```json
|
||||
{
|
||||
"uid": "9c644a1c-3e43-4df4-ab67-de5b68b235b6"
|
||||
}
|
||||
```
|
||||
|
||||
## POST `/group/add-users`
|
||||
|
||||
### Description
|
||||
|
||||
Adds one or more users to a group
|
||||
|
||||
### Parameters
|
||||
|
||||
- **uid:** _- required_
|
||||
- **accepts:** `string`
|
||||
UUID of an existing group
|
||||
- **users:** `Array<string>`
|
||||
usernames of users to add to the group
|
||||
|
||||
### Request Example
|
||||
|
||||
```javascript
|
||||
await fetch(`${window.api_origin}/group/add-users`, {
|
||||
"headers": {
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": `Bearer ${puter.authToken}`,
|
||||
},
|
||||
"body": JSON.stringify({
|
||||
uid: '9c644a1c-3e43-4df4-ab67-de5b68b235b6',
|
||||
users: ['first_user', 'second_user'],
|
||||
}),
|
||||
"method": "POST",
|
||||
});
|
||||
```
|
||||
|
||||
## POST `/group/remove-users`
|
||||
|
||||
### Description
|
||||
|
||||
Remove one or more users from a group
|
||||
|
||||
### Parameters
|
||||
|
||||
- **uid:** _- required_
|
||||
- **accepts:** `string`
|
||||
UUID of an existing group
|
||||
- **users:** `Array<string>`
|
||||
usernames of users to remove from the group
|
||||
|
||||
### Request Example
|
||||
|
||||
```javascript
|
||||
await fetch(`${window.api_origin}/group/add-users`, {
|
||||
"headers": {
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": `Bearer ${puter.authToken}`,
|
||||
},
|
||||
"body": JSON.stringify({
|
||||
uid: '9c644a1c-3e43-4df4-ab67-de5b68b235b6',
|
||||
users: ['first_user', 'second_user'],
|
||||
}),
|
||||
"method": "POST",
|
||||
});
|
||||
```
|
||||
|
||||
## GET `/group/list`
|
||||
|
||||
### Description
|
||||
|
||||
List groups associated with the current user
|
||||
|
||||
### Parameters
|
||||
|
||||
_none_
|
||||
|
||||
### Response Example
|
||||
|
||||
```json
|
||||
{
|
||||
"owned_groups": [
|
||||
{
|
||||
"uid": "c3bd4047-fc65-4da8-9363-e52195890de4",
|
||||
"metadata": {},
|
||||
"members": [
|
||||
"default_user"
|
||||
]
|
||||
}
|
||||
],
|
||||
"in_groups": [
|
||||
{
|
||||
"uid": "c3bd4047-fc65-4da8-9363-e52195890de4",
|
||||
"metadata": {},
|
||||
"members": [
|
||||
"default_user"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
# Group Permission Endpoints
|
||||
|
||||
## POST `/grant-user-group`
|
||||
|
||||
Grant permission from the current user to a group.
|
||||
This creates an association between the user and the
|
||||
group for this permission; the group will only have
|
||||
the permission effectively while the user who granted
|
||||
permission has the permission.
|
||||
|
||||
### Parameters
|
||||
|
||||
- **group_uid:** _- required_
|
||||
- **accepts:** `string`
|
||||
UUID of an existing group
|
||||
- **permission:** _- required_
|
||||
- **accepts:** `string`
|
||||
A permission string
|
||||
|
||||
### Request Example
|
||||
|
||||
```javascript
|
||||
await fetch("http://puter.localhost:4100/auth/grant-user-group", {
|
||||
"headers": {
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": `Bearer ${puter.authToken}`,
|
||||
},
|
||||
"body": JSON.stringify({
|
||||
group_uid: '9c644a1c-3e43-4df4-ab67-de5b68b235b6',
|
||||
permission: 'fs:/someuser/somedir/somefile:read'
|
||||
}),
|
||||
"method": "POST",
|
||||
});
|
||||
```
|
||||
|
||||
## POST `/revoke-user-group`
|
||||
|
||||
Revoke permission granted from the current user
|
||||
to a group.
|
||||
|
||||
### Parameters
|
||||
|
||||
- **group_uid:** _- required_
|
||||
- **accepts:** `string`
|
||||
UUID of an existing group
|
||||
- **permission:** _- required_
|
||||
- **accepts:** `string`
|
||||
A permission string
|
||||
|
||||
### Request Example
|
||||
|
||||
```javascript
|
||||
await fetch("http://puter.localhost:4100/auth/grant-user-group", {
|
||||
"headers": {
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": `Bearer ${puter.authToken}`,
|
||||
},
|
||||
"body": JSON.stringify({
|
||||
group_uid: '9c644a1c-3e43-4df4-ab67-de5b68b235b6',
|
||||
permission: 'fs:/someuser/somedir/somefile:read'
|
||||
}),
|
||||
"method": "POST",
|
||||
});
|
||||
```
|
||||
|
||||
- > **TODO** figure out how to manage documentation that could
|
||||
reasonably show up in two files. For example: this is a group
|
||||
endpoint as well as a permission system endpoint.
|
||||
(architecturally it's a permission system endpoint, and
|
||||
the permissions feature depends on the groups feature;
|
||||
at least until a time when PermissionService is refactored
|
||||
so a service like GroupService can mutate the permission
|
||||
check sequences)
|
||||
@@ -0,0 +1,112 @@
|
||||
# Notification Endpoints
|
||||
|
||||
Endpoints for managing notifications.
|
||||
|
||||
## POST `/notif/mark-ack` (auth required)
|
||||
|
||||
### Description
|
||||
|
||||
The `/notif/mark-ack` endpoint marks the specified notification
|
||||
as "acknowledged". This indicates that the user has chosen to either
|
||||
dismiss or act on this notification.
|
||||
|
||||
### Parameters
|
||||
|
||||
| Name | Description | Default Value |
|
||||
| ---- | ----------- | -------- |
|
||||
| uid | UUID associated with the notification | **required** |
|
||||
|
||||
### Response
|
||||
|
||||
This endpoint responds with an empty object (`{}`).
|
||||
|
||||
|
||||
## POST `/notif/mark-read` (auth required)
|
||||
|
||||
### Description
|
||||
|
||||
The `/notif/mark-read` endpoint marks that the specified notification
|
||||
has been shown to the user. It will not "pop up" as a new notification
|
||||
if they load the gui again.
|
||||
|
||||
### Parameters
|
||||
|
||||
| Name | Description | Default Value |
|
||||
| ---- | ----------- | -------- |
|
||||
| uid | UUID associated with the notification | **required** |
|
||||
|
||||
### Response
|
||||
|
||||
This endpoint responds with an empty object (`{}`).
|
||||
|
||||
### Request Example
|
||||
|
||||
```javascript
|
||||
await fetch("https://api.puter.local/notif/mark-read", {
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": `Bearer ${puter.authToken}`,
|
||||
},
|
||||
body: JSON.stringify({
|
||||
uid: 'a14ea3d5-828b-42f9-9613-35f43b0a3cb8',
|
||||
}),
|
||||
method: "POST",
|
||||
});
|
||||
```
|
||||
## ENTITY STORAGE `puter-notifications`
|
||||
|
||||
The `puter-notifications` driver is an Entity Storage driver.
|
||||
It is read-only.
|
||||
|
||||
### Request Examples
|
||||
|
||||
#### Select Unread Notifications
|
||||
|
||||
```javascript
|
||||
await fetch("http://api.puter.localhost:4100/drivers/call", {
|
||||
"headers": {
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": `Bearer ${puter.authToken}`,
|
||||
},
|
||||
"body": JSON.stringify({
|
||||
interface: 'puter-notifications',
|
||||
method: 'select',
|
||||
args: { predicate: ['unread'] }
|
||||
}),
|
||||
"method": "POST",
|
||||
});
|
||||
```
|
||||
|
||||
#### Select First 200 Notifications
|
||||
|
||||
```javascript
|
||||
await fetch("http://api.puter.localhost:4100/drivers/call", {
|
||||
"headers": {
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": `Bearer ${puter.authToken}`,
|
||||
},
|
||||
"body": JSON.stringify({
|
||||
interface: 'puter-notifications',
|
||||
method: 'select',
|
||||
args: {}
|
||||
}),
|
||||
"method": "POST",
|
||||
});
|
||||
```
|
||||
|
||||
#### Select Next 200 Notifications
|
||||
|
||||
```javascript
|
||||
await fetch("http://api.puter.localhost:4100/drivers/call", {
|
||||
"headers": {
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": `Bearer ${puter.authToken}`,
|
||||
},
|
||||
"body": JSON.stringify({
|
||||
interface: 'puter-notifications',
|
||||
method: 'select',
|
||||
args: { offset: 200 }
|
||||
}),
|
||||
"method": "POST",
|
||||
});
|
||||
```
|
||||
@@ -0,0 +1,367 @@
|
||||
# Share Endpoints
|
||||
|
||||
Share endpoints allow sharing files with other users.
|
||||
|
||||
## POST `/share` (auth required)
|
||||
|
||||
### Description
|
||||
|
||||
The `/share` endpoint shares 1 or more filesystem items
|
||||
with one or more recipients. The recipients will receive
|
||||
some notification about the shared item, making this
|
||||
different from calling `/grant-user-user` with a permission.
|
||||
|
||||
When users are **specified by email** they will receive
|
||||
a [share link](./concepts/share-link.md).
|
||||
|
||||
Each item specified in the `shares` property is a tag-typed
|
||||
object of type `fs-share` or `app-share`.
|
||||
|
||||
#### File Shares (`fs-share`)
|
||||
|
||||
File shares grant permission to a file or directory. By default
|
||||
this is read permission. If `access` is specified as `"write"`,
|
||||
then write permission will be granted.
|
||||
|
||||
#### App Shares (`app-share`)
|
||||
|
||||
App shares grant permission to read a protected app.
|
||||
|
||||
##### subdomain permission
|
||||
If there is a subdomain associated with the app, and the owner
|
||||
of the subdomain is the same as the owner of the app, then
|
||||
permission to access the subdomain will be granted.
|
||||
Note that the subdomain is only associated if the subdomain
|
||||
entry has `associated_app_id` set according to the app's id,
|
||||
and will not be considered "associated" if only the index_url
|
||||
happens to match the subdomain url.
|
||||
|
||||
##### appdata permission
|
||||
If the app has `shared_appdata` set to `true` in its metadata
|
||||
object, the recipient of the share will also get write permission
|
||||
to the app owner's corresponding appdata directory. The appdata
|
||||
directory must exist for this to work as expected
|
||||
(otherwise the permission rewrite rule fails since the uuid
|
||||
can't be determined).
|
||||
|
||||
### Example
|
||||
|
||||
```json
|
||||
{
|
||||
"recipients": [
|
||||
"user_that_gets_shared_to",
|
||||
"[email protected]"
|
||||
],
|
||||
"shares": [
|
||||
{
|
||||
"$": "app-share",
|
||||
"name": "some-app-name"
|
||||
},
|
||||
{
|
||||
"$": "app-share",
|
||||
"uid": "app-SOME-APP-UID"
|
||||
},
|
||||
{
|
||||
"$": "fs-share",
|
||||
"path": "/some/file/or/directory"
|
||||
},
|
||||
{
|
||||
"$": "fs-share",
|
||||
"path": "SOME-FILE-UUID"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Parameters
|
||||
|
||||
- **recipients** _- required_
|
||||
- **accepts:** `string | Array<string>`
|
||||
- **description:**
|
||||
recipients for the filesystem entries being shared.
|
||||
- **notes:**
|
||||
- validation on `string`: email or username
|
||||
- requirement of at least one value
|
||||
- **shares:** _- required_
|
||||
- **accepts:** `object | Array<object>`
|
||||
- object is [type-tagged](./type-tagged.md)
|
||||
- type is either [file-share](./types/file-share.md)
|
||||
or [app-share](./types/app-share.md)
|
||||
- **notes:**
|
||||
- requirement that file/directory or app exists
|
||||
- requirement of at least one entry
|
||||
- **dry_run:** _- optional_
|
||||
- **accepts:** `bool`
|
||||
- **description:**
|
||||
when true, only validation will occur
|
||||
|
||||
### Response
|
||||
|
||||
- **$:** `api:share`
|
||||
- **$version:** `v0.0.0`
|
||||
- **status:** one of: `"success"`, `"mixed"`, `"aborted"`
|
||||
- **recipients:** array of: `api:status-report` or
|
||||
`heyputer:api/APIError`
|
||||
- **paths:** array of: `api:status-report` or
|
||||
`heyputer:api/APIError`
|
||||
- **dry_run:** `true` if present
|
||||
|
||||
### Request Example
|
||||
|
||||
```javascript
|
||||
await fetch("http://puter.localhost:4100/share", {
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": `Bearer ${puter.authToken}`,
|
||||
},
|
||||
body: JSON.stringify({
|
||||
recipients: [
|
||||
"user_that_gets_shared_to",
|
||||
"[email protected]"
|
||||
],
|
||||
shares: [
|
||||
{
|
||||
$: "app-share",
|
||||
name: "some-app-name"
|
||||
},
|
||||
{
|
||||
$: "app-share",
|
||||
uid: "app-SOME-APP-UID"
|
||||
},
|
||||
{
|
||||
$: "fs-share",
|
||||
path: "/some/file/or/directory"
|
||||
},
|
||||
{
|
||||
$: "fs-share",
|
||||
path: "SOME-FILE-UUID"
|
||||
}
|
||||
]
|
||||
}),
|
||||
method: "POST",
|
||||
});
|
||||
```
|
||||
|
||||
### Success Response
|
||||
|
||||
```json
|
||||
{
|
||||
"$": "api:share",
|
||||
"$version": "v0.0.0",
|
||||
"status": "success",
|
||||
"recipients": [
|
||||
{
|
||||
"$": "api:status-report",
|
||||
"status": "success"
|
||||
}
|
||||
],
|
||||
"paths": [
|
||||
{
|
||||
"$": "api:status-report",
|
||||
"status": "success"
|
||||
}
|
||||
],
|
||||
"dry_run": true
|
||||
}
|
||||
```
|
||||
|
||||
### Error response (missing file)
|
||||
|
||||
```json
|
||||
{
|
||||
"$": "api:share",
|
||||
"$version": "v0.0.0",
|
||||
"status": "mixed",
|
||||
"recipients": [
|
||||
{
|
||||
"$": "api:status-report",
|
||||
"status": "success"
|
||||
}
|
||||
],
|
||||
"paths": [
|
||||
{
|
||||
"$": "heyputer:api/APIError",
|
||||
"code": "subject_does_not_exist",
|
||||
"message": "File or directory not found.",
|
||||
"status": 404
|
||||
}
|
||||
],
|
||||
"dry_run": true
|
||||
}
|
||||
```
|
||||
|
||||
### Error response (missing user)
|
||||
|
||||
```json
|
||||
{
|
||||
"$": "api:share",
|
||||
"$version": "v0.0.0",
|
||||
"status": "mixed",
|
||||
"recipients": [
|
||||
{
|
||||
"$": "heyputer:api/APIError",
|
||||
"code": "user_does_not_exist",
|
||||
"message": "The user `non_existing_user` does not exist.",
|
||||
"username": "non_existing_user",
|
||||
"status": 422
|
||||
}
|
||||
],
|
||||
"paths": [
|
||||
{
|
||||
"$": "api:status-report",
|
||||
"status": "success"
|
||||
}
|
||||
],
|
||||
"dry_run": true
|
||||
}
|
||||
```
|
||||
|
||||
## POST `/sharelink/check` (no auth)
|
||||
|
||||
### Description
|
||||
|
||||
The `/sharelink/check` endpoint verifies that a token provided
|
||||
by a share link is valid.
|
||||
|
||||
### Example
|
||||
|
||||
```javascript
|
||||
await fetch(`${config.api_origin}/sharelink/check`, {
|
||||
"headers": {
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": `Bearer ${puter.authToken}`,
|
||||
},
|
||||
"body": JSON.stringify({
|
||||
token: '...',
|
||||
}),
|
||||
"method": "POST",
|
||||
});
|
||||
```
|
||||
|
||||
### Parameters
|
||||
|
||||
- **token:** _- required_
|
||||
- **accepts:** `string`
|
||||
The token from the querystring parameter
|
||||
|
||||
### Response
|
||||
|
||||
A type-tagged object, either of type `api:share` or `api:error`
|
||||
|
||||
### Success Response
|
||||
|
||||
```json
|
||||
{
|
||||
"$": "api:share",
|
||||
"uid": "836671d4-ac5d-4bd3-bc0a-ec357e0d8f02",
|
||||
"email": "[email protected]"
|
||||
}
|
||||
```
|
||||
|
||||
### Error Response
|
||||
|
||||
```json
|
||||
{
|
||||
"$": "api:error",
|
||||
"message":"Field `token` is required.",
|
||||
"key":"token",
|
||||
"code":"field_missing"
|
||||
}
|
||||
```
|
||||
|
||||
## POST `/sharelink/apply` (no auth)
|
||||
|
||||
### Description
|
||||
|
||||
The `/sharelink/apply` endpoint applies a share to the current
|
||||
user **if and only if** that user's email is confirmed and matches
|
||||
the email associated with the share.
|
||||
|
||||
### Example
|
||||
|
||||
```javascript
|
||||
await fetch(`${config.api_origin}/sharelink/apply`, {
|
||||
"headers": {
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": `Bearer ${puter.authToken}`,
|
||||
},
|
||||
"body": JSON.stringify({
|
||||
uid: '836671d4-ac5d-4bd3-bc0a-ec357e0d8f02',
|
||||
}),
|
||||
"method": "POST",
|
||||
});
|
||||
```
|
||||
|
||||
### Parameters
|
||||
|
||||
- **uid:** _- required_
|
||||
- **accepts:** `string`
|
||||
The uid of an existing share, received using `/sharelink/check`
|
||||
|
||||
### Response
|
||||
|
||||
A type-tagged object, either of type `api:status-report` or `api:error`
|
||||
|
||||
### Success Response
|
||||
|
||||
```json
|
||||
{"$":"api:status-report","status":"success"}
|
||||
```
|
||||
|
||||
### Error Response
|
||||
|
||||
```json
|
||||
{
|
||||
"message": "This share can not be applied to this user.",
|
||||
"code": "can_not_apply_to_this_user"
|
||||
}
|
||||
```
|
||||
|
||||
## POST `/sharelink/request` (no auth)
|
||||
|
||||
### Description
|
||||
|
||||
The `/sharelink/request` endpoint requests the permissions associated
|
||||
with a share link to the issuer of the share (user that sent the share).
|
||||
This can be used when a user is logged in, but that user's email does
|
||||
not match the email associated with the share.
|
||||
|
||||
### Example
|
||||
|
||||
```javascript
|
||||
await fetch(`${config.api_origin}/sharelink/request`, {
|
||||
"headers": {
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": `Bearer ${puter.authToken}`,
|
||||
},
|
||||
"body": JSON.stringify({
|
||||
uid: '836671d4-ac5d-4bd3-bc0a-ec357e0d8f02',
|
||||
}),
|
||||
"method": "POST",
|
||||
});
|
||||
```
|
||||
|
||||
### Parameters
|
||||
|
||||
- **uid:** _- required_
|
||||
- **accepts:** `string`
|
||||
The uid of an existing share, received using `/sharelink/check`
|
||||
|
||||
### Response
|
||||
|
||||
A type-tagged object, either of type `api:status-report` or `api:error`
|
||||
|
||||
### Success Response
|
||||
|
||||
```json
|
||||
{"$":"api:status-report","status":"success"}
|
||||
```
|
||||
|
||||
### Error Response
|
||||
|
||||
```json
|
||||
{
|
||||
"message": "This share is already valid for this user; POST to /apply for access",
|
||||
"code": "no_need_to_request"
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,79 @@
|
||||
# Type-Tagged Objects
|
||||
|
||||
```js
|
||||
{
|
||||
"$": "some-type",
|
||||
"$version": "0.0.0",
|
||||
|
||||
"some_property": "some value",
|
||||
}
|
||||
```
|
||||
|
||||
## What's a Type-Tagged Object?
|
||||
|
||||
Type-Tagged objects are a convention understood by Puter's backend
|
||||
to communicate meta information along with a JSON object.
|
||||
The key feature of Type-Tagged Objects is the type key: `"$"`.
|
||||
|
||||
## Why Type-Tagged Objects?
|
||||
|
||||
The primary reason: to have a consistent convention we can use
|
||||
anywhere.
|
||||
|
||||
- Since other services rarely use `$` in their property names,
|
||||
we can safely use this without introducing reserved words and
|
||||
re-mapping property names.
|
||||
- Some places we use this convention might not need it, but
|
||||
staying consistent means API end-users can
|
||||
[do more with less code](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself).
|
||||
|
||||
## Specification
|
||||
|
||||
- The `"$"` key indicates a type (or class) of object
|
||||
- Any other key beginning with `$` is a **meta-key**
|
||||
- Other keys are not allowed to contain `$`
|
||||
- `"$version"` must follow [semver](https://semver.org/)
|
||||
- Keys with multiple `"$"` symbols are reserved for future use
|
||||
|
||||
## Alternative Representations
|
||||
|
||||
Puter's API will always send results in the format described
|
||||
above, which is called the "Standard Representation"
|
||||
|
||||
Any endpoint which accepts a Type-Tagged Object will also
|
||||
accept these alternative representations:
|
||||
|
||||
### Structured Representation
|
||||
|
||||
Depending on the architecture of your client, this format
|
||||
may be more convenient to work with:
|
||||
```json
|
||||
{
|
||||
"$": "$meta-body",
|
||||
"type": "some-type",
|
||||
"meta": { "version": "0.0.0" },
|
||||
"body": { "some_property": "some value" }
|
||||
}
|
||||
```
|
||||
|
||||
### Array Representation
|
||||
|
||||
In the array representation, meta values go at the end.
|
||||
```json
|
||||
["some-type",
|
||||
{ "some_property": "some value" },
|
||||
{ "version": "0.0.0" }
|
||||
]
|
||||
```
|
||||
|
||||
If the second element of the list is not an object, it
|
||||
will implicitly be placed in a property called value.
|
||||
The following are equivalent:
|
||||
|
||||
```json
|
||||
["some-type", "hello"]
|
||||
```
|
||||
|
||||
```json
|
||||
["some-type", { "value": "hello" }]
|
||||
```
|
||||
@@ -0,0 +1,26 @@
|
||||
# `{"$": "app-share"}` - File Share
|
||||
|
||||
## Structure
|
||||
- **name:** name of the app
|
||||
- **uid:** name of the app
|
||||
|
||||
## Notes
|
||||
- One of `name` or `uid` **must** be specified
|
||||
|
||||
## Examples
|
||||
|
||||
Share app by name
|
||||
```json
|
||||
{
|
||||
"$": "app-share",
|
||||
"name": "some-app-name"
|
||||
}
|
||||
```
|
||||
|
||||
Share app by uid
|
||||
```json
|
||||
{
|
||||
"$": "app-share",
|
||||
"uid": "app-0a7337f7-0f8a-49ca-b71a-38d39304fe04"
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,32 @@
|
||||
# `{"$": "file-share"}` - File Share
|
||||
|
||||
## Structure
|
||||
- **path:** file or directory's path or uuid
|
||||
- **access:** one of: `"read"`, `"write"` (default: `"read"`)
|
||||
|
||||
## Examples
|
||||
|
||||
Share with read access
|
||||
```json
|
||||
{
|
||||
"$": "file-share",
|
||||
"path": "/some/path"
|
||||
}
|
||||
```
|
||||
|
||||
Share with write access
|
||||
```json
|
||||
{
|
||||
"$": "file-share",
|
||||
"path": "/some/path",
|
||||
"access": "write"
|
||||
}
|
||||
```
|
||||
|
||||
Using a UUID
|
||||
```json
|
||||
{
|
||||
"$": "file-share",
|
||||
"path": "b912c381-0c0b-466c-95a6-f9a4fc680a7d"
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,28 @@
|
||||
# Comment Prefixes
|
||||
|
||||
Comments have prefixes using
|
||||
[Conventional: Comments](https://conventionalcomments.org/)
|
||||
as a **loose** guideline, and using this markdown file as a
|
||||
the actual guideline.
|
||||
|
||||
This document will be updated on an _as-needed_ basis.
|
||||
|
||||
## The rules
|
||||
|
||||
- A comment line always looks like this:
|
||||
- A whitespace character
|
||||
- Optional prefix matching `/[a-z-]+\([a-z-]a+\):/`
|
||||
- A whitespace character
|
||||
- The comment
|
||||
- Formalized prefixes must follow the rules below
|
||||
- Any other prefix can be used. After some uses it
|
||||
might be good to formalize it, but that's not a hard rule.
|
||||
|
||||
## Formalized prefixes
|
||||
|
||||
- `todo:` is interchangable with the famous `TODO:`, **except:**
|
||||
when lowercase (`todo:`) it can include a scope: `todo(security):`.
|
||||
- `track:` is used to track common patterns.
|
||||
- Anything written after `track:` must be registered in
|
||||
[track-comments.md](../devmeta/track-comments.md)
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
### `vscode`
|
||||
- `es6-string-html`
|
||||
@@ -0,0 +1,59 @@
|
||||
# Track Comments
|
||||
|
||||
Comments beginning with `// track:`. See
|
||||
[comment_prefixes.md](../contributors/comment_prefixes.md)
|
||||
|
||||
## Track Comment Registry
|
||||
|
||||
- `track: type check`:
|
||||
A condition that's used to check the type of an imput.
|
||||
- `track: adapt`
|
||||
A value can by adapted from another type at this line.
|
||||
- `track: bounds check`:
|
||||
A condition that's used to check the bounds of an array
|
||||
or other list-like entity.
|
||||
- `track: ruleset`
|
||||
A series of conditions that early-return or `continue`
|
||||
- `track: object description in comment`
|
||||
A comment above the creation of some object which
|
||||
could potentially have a `description` property.
|
||||
This is especially relevant if the object is stored
|
||||
in some kind of registry where multiple objects
|
||||
could be listed in the console.
|
||||
- `track: slice a prefix`
|
||||
A common pattern where a prefix string is "sliced off"
|
||||
of another string to obtain a significant value, such
|
||||
as an indentifier.
|
||||
- `track: actor type`
|
||||
The sub-type of an Actor object is checked.
|
||||
- `track: scoping iife`
|
||||
An immediately-invoked function expression specifically
|
||||
used to reduce scope clutter.
|
||||
- `track: good candidate for sequence`
|
||||
Some code involves a series of similar steps,
|
||||
or there's a common behavior that should happen
|
||||
in between. The Sequence class is good for this so
|
||||
it might be a worthy migration.
|
||||
- `track: opposite condition of sibling`
|
||||
A sibling class, function, method, or other construct of
|
||||
source code has a boolean expression which always evaluates
|
||||
to the opposite of the one below this track comment.
|
||||
- `track: null check before processing`
|
||||
An object could be undefined or null, additional processing
|
||||
occurs after a null check, and the unprocessed object is not
|
||||
relevant to the rest of the code. If the code for obtaining
|
||||
the object and processing it is moved to a function outside,
|
||||
then the null check should result in a early return of null;
|
||||
this code with the track comment may have additional logic
|
||||
for the null/undefined case.
|
||||
- `track: manual safe object`
|
||||
This code manually creates a new "client-safe" version of
|
||||
some object that's in scope. This could be either to pass
|
||||
onto the browser or to pass to something like the
|
||||
notification service.
|
||||
- `track: common operations on multiple items`
|
||||
A patterm which emerges when multiple variables have
|
||||
common operations done upon them in sequence.
|
||||
It may be applicable to write an iterator in the
|
||||
future, or something will come up that require
|
||||
these to be handled with a modular approach instead.
|
||||
@@ -0,0 +1,12 @@
|
||||
# Meta Documentation
|
||||
|
||||
## Notes
|
||||
|
||||
- > This document is a work-in-progress
|
||||
|
||||
## Rules
|
||||
|
||||
### "is" and "is not"
|
||||
|
||||
- When "A is B", always bold "is": "A **is** B" (`A **is** B`)
|
||||
- When "A is not B", always bold "not": "A is **not** B" (`A is **not** B`)
|
||||
@@ -0,0 +1,136 @@
|
||||
### Problem
|
||||
|
||||
When sending metadata along with arbitrary JSON objects,
|
||||
a collision of property names may occur. For example, the
|
||||
driver system can't place a "type" property on an arbitrary
|
||||
response coming from a driver because that might also be
|
||||
the name of a property in the response.
|
||||
|
||||
|
||||
#### Example:
|
||||
```json
|
||||
{
|
||||
"type": "api:thing",
|
||||
"version": "v1.0.0",
|
||||
"some": "info"
|
||||
}
|
||||
```
|
||||
|
||||
#### Awful Solution
|
||||
|
||||
Reserved words. Drivers need to know their response can't have
|
||||
keys like `type` or `version`. If we'd like to add more meta
|
||||
keys in the future we need to verify that no existing drivers
|
||||
use the new key we'd like to reserve. If we have have such features
|
||||
as user-submitted drivers this will be impossibe.
|
||||
A `meta` key as a single reserved word could work, which is one
|
||||
of the solutions discussed below.
|
||||
|
||||
#### Obvious Solution:
|
||||
|
||||
The obvious solution is to return an object with a
|
||||
`head` property and a `body` propery:
|
||||
|
||||
```json
|
||||
{
|
||||
"head": {
|
||||
"type": "api:thing",
|
||||
"version": "v1.0.0"
|
||||
},
|
||||
"body": {
|
||||
"some": "info"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
I don't mind this solution. I've come up with some alternatives though,
|
||||
because this solution has a couple drawbacks:
|
||||
- it looks a little verbose
|
||||
- it's not backwards-compatible with arbitrary JSON-object responses
|
||||
|
||||
## Solutions
|
||||
|
||||
### Dollar-Sign Convention
|
||||
|
||||
- Objects have two classes of keys:
|
||||
- "meta" keys begin with "$"
|
||||
- other keys must validate against the
|
||||
usual identifier rules: `/[A-Za-z_][A-Za-z0-9_]*/`
|
||||
- The meta key `$` indicates the schema or class of
|
||||
the object.
|
||||
- Example:
|
||||
```json
|
||||
{
|
||||
"$": "api:thing",
|
||||
"$version": "v1.0.0",
|
||||
|
||||
"some": "info"
|
||||
}
|
||||
```
|
||||
- what sucks about it:
|
||||
- `$` might be surprising or confusing
|
||||
- response is a subset of valid JSON keys
|
||||
(those not including `$`)
|
||||
- what's nice about it:
|
||||
- backwards-compatible with arbitrary JSON-object responses
|
||||
which don't already use `$`
|
||||
|
||||
### Underscore Convention
|
||||
- Same as above, but `_` instead of `$`
|
||||
```json
|
||||
{
|
||||
"_": "api:thing",
|
||||
"_version": "v1.0.0",
|
||||
|
||||
"some": "info"
|
||||
}
|
||||
```
|
||||
- what sucks about it:
|
||||
- `_` might be confusing
|
||||
- response is a subset of valid JSON keys
|
||||
(those not including `_`)
|
||||
- what's nice about it:
|
||||
- `_` is conventionally used for private property names,
|
||||
so this might be a little less surprising
|
||||
- backwards-compatible with arbitrary JSON-object responses
|
||||
which don't already use `_`
|
||||
|
||||
### Nesting Convention, simplified
|
||||
|
||||
- Similar to the "obvious solution" except
|
||||
metadata fields are lifted up a level.
|
||||
It's relatively inconsequential if meta keys
|
||||
have reserved words compared to value keys.
|
||||
```json
|
||||
{
|
||||
"type": "api:thing",
|
||||
"version": "v1.0.0",
|
||||
"value": {
|
||||
"some": "info"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Modified Dollar/Underscore convention
|
||||
- Using `_` in this example, but instead of prefixing
|
||||
meta properties they all go under one key.
|
||||
```json
|
||||
{
|
||||
"_": {
|
||||
"type": "api:thing",
|
||||
"version": "v1.0.0"
|
||||
},
|
||||
|
||||
"some": "info"
|
||||
}
|
||||
```
|
||||
- what sucks about it:
|
||||
- `_` might be confusing
|
||||
- response is a subset of valid JSON keys
|
||||
(those not **exactly** `_`)
|
||||
- what's nice about it:
|
||||
- `_` is conventionally used for private property names,
|
||||
so this might be a little less surprising
|
||||
- backwards-compatible with arbitrary JSON-object responses
|
||||
which don't already use `_` as an exact key
|
||||
- only one reserved key
|
||||
@@ -0,0 +1,12 @@
|
||||
# Micro Modules
|
||||
|
||||
**CoreModule** has a large number of services. Each service handles
|
||||
a general concern, like "notifications", but increasing this granularity
|
||||
a little put more could allow a lot more code re-use.
|
||||
|
||||
One specific example that comes to mind is services that provide
|
||||
CRUD operations for a database table. The **EntityStoreService** can
|
||||
be used for a lot of these even though right now it's specifically
|
||||
used for drivers. Having a common class of service like this can also
|
||||
allow quickly configuring the equivalent service for providing those
|
||||
CRUD operations through an API.
|
||||
@@ -1,4 +1,4 @@
|
||||
# Configurating Domains for Self-Hosted Puter
|
||||
# Configuring Domains for Self-Hosted Puter
|
||||
|
||||
## Local Network Configuration
|
||||
|
||||
@@ -20,7 +20,7 @@ The hosts file is a straightforward way to map domain names to IP addresses on i
|
||||
192.168.1.10 api.puter.local
|
||||
```
|
||||
|
||||
### For macOS and Linux:
|
||||
#### For macOS and Linux:
|
||||
1. Open a terminal.
|
||||
2. Edit the hosts file with a text editor, e.g., `sudo nano /etc/hosts`.
|
||||
3. Add lines for your domain and subdomain with the server's IP address, in the
|
||||
@@ -51,7 +51,7 @@ Setting up a local DNS server on your network allows for flexible and scalable d
|
||||
|
||||
- **Pi-hole**: Acts as both an ad-blocker and a DNS server. Ideal for easy setup and maintenance.
|
||||
- **BIND9**: Offers comprehensive DNS server capabilities for complex setups.
|
||||
- **Dnsmasq**: Lightweight and suitable for smaller networks or those new to running a DNS server.
|
||||
- **dnsmasq**: Lightweight and suitable for smaller networks or those new to running a DNS server.
|
||||
|
||||
**contributors note:** feel free to add any software you're aware of
|
||||
which might help with this to the list. Also, feel free to add instructions here for specific software; our goal is for Puter to be easy to setup with tools you're already familiar with.
|
||||
@@ -60,7 +60,7 @@ which might help with this to the list. Also, feel free to add instructions here
|
||||
|
||||
1. Choose and install DNS server software on a device within your network.
|
||||
2. Configure the DNS server to resolve `puter.local` and `api.puter.local` to the IP address of your Puter hosting device.
|
||||
3. Update your router’s DHCP settings to distribute the DNS server's IP address to all devices on the network.
|
||||
3. Update your router's DHCP settings to distribute the DNS server's IP address to all devices on the network.
|
||||
|
||||
By setting up a local DNS server, you gain the most flexibility and control over your network's domain name resolution, ensuring that all devices can access Puter and its API without manual configuration.
|
||||
|
||||
@@ -68,5 +68,5 @@ By setting up a local DNS server, you gain the most flexibility and control over
|
||||
|
||||
Please note the self-hosting feature is still in alpha and a public production
|
||||
deployment is not recommended at this time. However, if you wish to host
|
||||
publically you can do so following the same steps you normally would to configure
|
||||
publicly you can do so following the same steps you normally would to configure
|
||||
a domain name and ensuring the `api` subdomain points to the server as well.
|
||||
@@ -0,0 +1,58 @@
|
||||
# Self-Hosting Puter
|
||||
|
||||
> [!WARNING]
|
||||
> The self-hosted version of Puter is currently in alpha stage and should not be used in production yet. It is under active development and may contain bugs, other issues. Please exercise caution and use it for testing and evaluation purposes only.
|
||||
|
||||
### Self-Hosting Differences
|
||||
Currently, the self-hosted version of Puter is different in a few ways from [Puter.com](https://puter.com):
|
||||
- There is no built-in way to install or create other apps (see below)
|
||||
- Several "core" apps are missing, such as **Code** or **Draw**, because we can't include them in this repository
|
||||
- Some icons are different
|
||||
|
||||
Work is ongoing to improve the **App Center** and make it available on self-hosted.
|
||||
Until then, it's possible to add other apps by manually editing the database file.
|
||||
This process is not recommended unless you know what you are doing.
|
||||
The file will appear after you first launch Puter, and should be found in `puter/data/puter-database.sqlite` for Docker,
|
||||
or `volatile/runtime/puter-database.sqlite` otherwise.
|
||||
You will need a database tool that can understand SQLite databases.
|
||||
|
||||
<br/>
|
||||
|
||||
## Configuration
|
||||
|
||||
Running the server will generate a configuration file in one of these locations:
|
||||
- `config/config.json` when [Using Docker](#using-docker)
|
||||
- `volatile/config/config.json` in [Local Development](#local-development)
|
||||
- `/etc/puter/config.json` on a server (or within a Docker container)
|
||||
|
||||
### Domain Name
|
||||
|
||||
To access Puter on your device, you can simply go to the address printed in
|
||||
the server console (usually `puter.localhost:4100`).
|
||||
|
||||
To access Puter from another device, a domain name must be configured, as well as
|
||||
an `api` subdomain. For example, `example.local` might be the domain name pointing
|
||||
to the IP address of the server running puter, and `api.example.com` must point to
|
||||
this address as well. This domain must be specified in the configuration file
|
||||
(usually `volatile/config/config.json`) as well.
|
||||
|
||||
See [domain configuration](./domains.md) for more information.
|
||||
|
||||
### Configure the Port
|
||||
|
||||
- You can specify a custom port by setting `http_port` to a desired value
|
||||
- If you're using a reverse-proxy such as nginx or cloudflare, you should
|
||||
also set `pub_port` to the public (external) port (usually `443`)
|
||||
- If you have HTTPS enabled on your reverse-proxy, ensure that
|
||||
`protocol` in config.json is set accordingly
|
||||
|
||||
### Default User
|
||||
|
||||
By default, Puter will create a user called `default_user`.
|
||||
This user will have a randomly generated password, which will be printed
|
||||
in the development console.
|
||||
A warning will persist in the dev console until this user's
|
||||
password is changed. Please login to this user and change the password as
|
||||
your first step.
|
||||
|
||||
<br/>
|
||||
@@ -0,0 +1,39 @@
|
||||
## Puter Support Levels for Repository Updates
|
||||
|
||||
This document describes issues requiring repository changes;
|
||||
which issues will be fixed by Puter's core team, and which ones
|
||||
will be fixed if the community makes a contribution.
|
||||
|
||||
This document is not "law". It is provided only as a helpful guide
|
||||
on what to expect.
|
||||
|
||||
### Level Glossary
|
||||
|
||||
| Name | Description |
|
||||
| ---- | ----------- |
|
||||
| Core | Core developers will fix this |
|
||||
| Community | We will accept contributions to fix this |
|
||||
| Mixed | Core developers will fix this if it's currently a priority |
|
||||
|
||||
### Issues and their Levels
|
||||
|
||||
| Issue | Priority |
|
||||
| ----- | -------- |
|
||||
| Security vulnerability | Core |
|
||||
| Breaking change to SDK or API | Core |
|
||||
| Bug in service in CoreModule | Core |
|
||||
| Bug in a built-in app | Core |
|
||||
| Login/init failure in Docker on `release` branch | Core |
|
||||
| Login/init failure in Linux or OSX | Core |
|
||||
| Login/init failure in Docker on `main` branch | Mixed |
|
||||
| Login/init failure with specific configuration | Mixed |
|
||||
| Login/init failure in Windows | Community |
|
||||
|
||||
|
||||
## Puter Support for a Particular Deployment
|
||||
|
||||
If you experience issues on a self-hosted deployment we're here to
|
||||
help. Some issues are related to configuration or environment, so
|
||||
we may only be able to help in a limited capacity. Issues related
|
||||
to data loss, data corruption, or security will have higher priority
|
||||
over other issues with particular deployments.
|
||||
@@ -0,0 +1,31 @@
|
||||
# Testing with Email
|
||||
|
||||
Testing anything involving email is really simple using [mailhog](https://github.com/mailhog/MailHog)
|
||||
|
||||
### Step 1: Configure email service
|
||||
|
||||
In your `config.json` for Puter (`volatile/config/config.json` usually, `/var/puter/config.json` in containers),
|
||||
add this entry to the `"services`" map:
|
||||
|
||||
```javascript
|
||||
"services": {
|
||||
|
||||
// ... there are probably other service configs
|
||||
|
||||
"email": {
|
||||
"host": "localhost",
|
||||
"port": 1025
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Step 2: Install and run mailhog
|
||||
|
||||
Follow the instructions on [MailHog](https://github.com/mailhog/MailHog)'s
|
||||
repository, or install through your distro's package manager.
|
||||
|
||||
Run the command: `mailhog`.
|
||||
|
||||
You should now have an inbox at [http://127.0.0.1:8025](http://127.0.0.1:8025).
|
||||
|
||||
Every email that Puter sends will show up on this page.
|
||||
@@ -0,0 +1,9 @@
|
||||
# Uncategorized Documentation
|
||||
|
||||
Any document in this directory may be moved in the future to
|
||||
a more suitable location. This is a good place to put any
|
||||
documentation that needs to be written when it's unclear what
|
||||
the best place for it is. This is to avoid situations where
|
||||
documentation _doesn't_ get written simply because it's not clear
|
||||
where it belongs (something which the author of this very document
|
||||
has been guilty of at times).
|
||||
@@ -0,0 +1,46 @@
|
||||
# Notes about ES6 Class Syntax
|
||||
|
||||
## Document Meta
|
||||
|
||||
> **backend focus:** This documentation is more relevant to
|
||||
> Puter's backend than frontend, but is placed here because
|
||||
> it could apply to other areas in the future.
|
||||
|
||||
## Expressions as Methods
|
||||
|
||||
One important shortcoming in the ES6 class syntax to be aware of
|
||||
is that it discourages the use of expressions as methods.
|
||||
|
||||
For example:
|
||||
|
||||
```javascript
|
||||
class ExampleClass extends SomeBase {
|
||||
intuitive_method_definition () {}
|
||||
|
||||
constructor () {
|
||||
this.less_intuitive = some_expr();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Even if it is known that the return type of `some_expr` is a function,
|
||||
it is still unclear whether it's being used as a callback or
|
||||
as a method without other context in the code, since this is
|
||||
how we typically assign instance members rather than methods.
|
||||
|
||||
We solve this in Puter's backend using a **trait** called
|
||||
[AssignableMethodsTrait](../../packages/backend/src/traits/AssignableMethodsTrait.js)
|
||||
which allows a static member called `METHODS` to contain
|
||||
method definitions.
|
||||
|
||||
### Uses for Expressions as Methods
|
||||
|
||||
#### Method Composition
|
||||
|
||||
Method Composition is the act of composing methods from other
|
||||
constituents. For example,
|
||||
[Sequence](../../packages/backend/src/codex/Sequence.js)
|
||||
allows composing a method from smaller functions, allowing
|
||||
easier definition of "in-betwewen-each" behaviors and ways
|
||||
to track which values from the arguments are actually read
|
||||
during a particular call.
|
||||
@@ -0,0 +1,66 @@
|
||||
# Puter Mods
|
||||
|
||||
## What is a Puter Mod?
|
||||
|
||||
Currently, the definition of a Puter mod is:
|
||||
|
||||
> A [Module](../../packages/backend/doc/contributors/modules.md)
|
||||
> which is exported by a package directory which itself exists
|
||||
> within a directory specified in the `mod_directories` array
|
||||
> in `config.json`.
|
||||
|
||||
## Enabling Puter Mods
|
||||
|
||||
### Step 1: Update Configuration
|
||||
|
||||
First update the configuration (usually at `./volatile/config.json`
|
||||
or `/var/puter/config.json`) to specify mod directories.
|
||||
|
||||
```json
|
||||
{
|
||||
"config_name": "example config",
|
||||
|
||||
"mod_directories": [
|
||||
"{source}/mods/mods_enabled"
|
||||
]
|
||||
|
||||
// ... other config options
|
||||
}
|
||||
```
|
||||
|
||||
The first path you'll want to add is
|
||||
`"{source}/mods/mods_enabled"`
|
||||
which adds all the mods included in Puter's official repository.
|
||||
You don't need to change `{source}` unless your entry javascript
|
||||
file is in a different location than the default.
|
||||
|
||||
If you want to enable all the mods, you can change the path above
|
||||
to `mods_available` instead and skip step 2 below.
|
||||
|
||||
### Step 2: Select Mods
|
||||
|
||||
To enable a Puter mod, create a symbolic link (AKA symlink) in
|
||||
`mods/mods_enabled`, pointing to
|
||||
a directory in `mods/mods_available`. This follows the same convention
|
||||
as managing sites/mods in Apache or Nginx servers.
|
||||
|
||||
For example to enable KDMOD (which you can read as "Kernel Dev" mod,
|
||||
or "the mod that GitHub user KernelDeimos created to help with testing")
|
||||
you would run this command:
|
||||
```sh
|
||||
ln -rs ./mods/mods_available/kdmod ./mods/mods_enabled/
|
||||
```
|
||||
|
||||
This will create a symlink at `./mods/mods_enabled/kdmod` pointing
|
||||
to the directory `./mods/mods_available/kdmod`.
|
||||
|
||||
> **note:** here are some helpful tips for the `ln` command:
|
||||
> - You can remember `ln`'s first argument is the unaffected
|
||||
> source file by remembering `cp` and `mv` are the same in
|
||||
> this way.
|
||||
> - If you don't add `-s` you get a hard link. You will rarely
|
||||
> find yourself needing to do that.
|
||||
> - The `-r` flag allows you to write both paths relative to
|
||||
> the directory from which you are calling the command, which
|
||||
> is sometimes more intuitive.
|
||||
|
||||
+23
-5
@@ -1,7 +1,25 @@
|
||||
version: '3'
|
||||
|
||||
---
|
||||
version: "3.8"
|
||||
services:
|
||||
app:
|
||||
build: ./
|
||||
puter:
|
||||
container_name: puter
|
||||
image: ghcr.io/heyputer/puter:latest
|
||||
pull_policy: always
|
||||
# build: ./
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- 4100:4100
|
||||
- '4100:4100'
|
||||
environment:
|
||||
# TZ: Europe/Paris
|
||||
# CONFIG_PATH: /etc/puter
|
||||
PUID: 1000
|
||||
PGID: 1000
|
||||
volumes:
|
||||
- ./puter/config:/etc/puter
|
||||
- ./puter/data:/var/puter
|
||||
healthcheck:
|
||||
test: wget --no-verbose --tries=1 --spider http://puter.localhost:4100/test || exit 1
|
||||
interval: 30s
|
||||
timeout: 3s
|
||||
retries: 3
|
||||
start_period: 30s
|
||||
@@ -0,0 +1,139 @@
|
||||
import js from "@eslint/js";
|
||||
import globals from "globals";
|
||||
|
||||
export default [
|
||||
js.configs.recommended,
|
||||
|
||||
{
|
||||
// Global ignores
|
||||
ignores: [
|
||||
"**/*.min.js",
|
||||
"**/src/lib/**",
|
||||
"**/dist/",
|
||||
"src/backend/src/public/assets/**",
|
||||
"incubator/**"
|
||||
],
|
||||
},
|
||||
{
|
||||
// Top-level and tools use Node
|
||||
files: [
|
||||
"tools/**/*.js",
|
||||
],
|
||||
languageOptions: {
|
||||
globals: {
|
||||
...globals.node,
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
// Back end
|
||||
files: [
|
||||
"src/backend/**/*.js",
|
||||
"mods/**/*.js",
|
||||
"dev-server.js",
|
||||
"utils.js",
|
||||
],
|
||||
languageOptions: {
|
||||
globals: {
|
||||
...globals.node,
|
||||
"kv": true,
|
||||
"def": true,
|
||||
"use": true,
|
||||
"ll":true,
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
// Front end
|
||||
files: [
|
||||
"src/**/*.js",
|
||||
],
|
||||
ignores: [
|
||||
"src/backend/**/*.js",
|
||||
],
|
||||
languageOptions: {
|
||||
globals: {
|
||||
...globals.browser,
|
||||
...globals.commonjs,
|
||||
// Weird false positives
|
||||
"Buffer": true,
|
||||
// Puter Common
|
||||
"puter": true,
|
||||
"i18n": true,
|
||||
"html_encode": true,
|
||||
"html_decode": true,
|
||||
"isMobile": true,
|
||||
// Class Registry
|
||||
"logger": true,
|
||||
"def": true,
|
||||
"use": true,
|
||||
// Libraries
|
||||
"saveAs": true, // FileSaver
|
||||
"iro": true, // iro.js color picker
|
||||
"$": true, // jQuery
|
||||
"jQuery": true, // jQuery
|
||||
"JSZip": true, // JSZip
|
||||
"_": true, // lodash
|
||||
"QRCode": true, // qrcode
|
||||
"io": true, // socket.io
|
||||
"timeago": true, // timeago
|
||||
"SelectionArea": true, // viselect
|
||||
// Puter GUI Globals
|
||||
"set_menu_item_prop": true,
|
||||
"determine_active_container_parent": true,
|
||||
"privacy_aware_path": true,
|
||||
"api_origin": true,
|
||||
"auth_token": true,
|
||||
"logout": true,
|
||||
"is_email": true,
|
||||
"select_ctxmenu_item": true,
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
// Mods
|
||||
// NOTE: Mods have backend and frontend parts, so this just includes the globals for both.
|
||||
files: [
|
||||
"mods/**/*.js",
|
||||
],
|
||||
languageOptions: {
|
||||
globals: {
|
||||
...globals.node,
|
||||
"use": true,
|
||||
"window": true,
|
||||
"puter": true,
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
// Tests
|
||||
files: [
|
||||
"**/test/**/*.js",
|
||||
],
|
||||
languageOptions: {
|
||||
globals: {
|
||||
...globals.mocha,
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
// Phoenix
|
||||
files: [
|
||||
"src/phoenix/**/*.js",
|
||||
],
|
||||
languageOptions: {
|
||||
globals: {
|
||||
...globals.node,
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
// Global rule settings
|
||||
rules: {
|
||||
"no-prototype-builtins": "off", // Complains about any use of hasOwnProperty()
|
||||
"no-unused-vars": "off", // Temporary, we just have a lot of these
|
||||
"no-debugger": "warn",
|
||||
"no-async-promise-executor": "off", // We do this quite often and it's fine
|
||||
}
|
||||
},
|
||||
];
|
||||
@@ -0,0 +1,2 @@
|
||||
*.bin
|
||||
*.wasm
|
||||
@@ -0,0 +1,22 @@
|
||||
Copyright (c) 2012, The v86 contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
@@ -0,0 +1,91 @@
|
||||
FROM i386/debian:buster
|
||||
|
||||
ENV DEBIAN_FRONTEND noninteractive
|
||||
|
||||
# Update and install necessary packages
|
||||
RUN apt update && \
|
||||
apt --yes --no-install-recommends install \
|
||||
linux-image-686 grub2 systemd \
|
||||
libterm-readline-perl-perl \
|
||||
gcc make libc6-dev \
|
||||
unzip bzip2 xz-utils \
|
||||
fluxbox \
|
||||
i3-wm \
|
||||
cmake \
|
||||
fuse \
|
||||
xorg xserver-xorg-input-kbd xserver-xorg-input-mouse xserver-xorg-input-evdev \
|
||||
xserver-xorg-video-fbdev xserver-xorg-video-vesa \
|
||||
xserver-xorg x11-xserver-utils xinit dbus-x11 \
|
||||
libgdk-pixbuf2.0 libpango-1.0 libpangocairo-1.0 libgtk2.0-bin \
|
||||
libc-l10n locales \
|
||||
fonts-noto fonts-droid-fallback \
|
||||
strace file xterm vim apt-file \
|
||||
dhcpcd5 \
|
||||
ca-certificates \
|
||||
git \
|
||||
wget curl \
|
||||
net-tools netcat \
|
||||
wmctrl xdotool \
|
||||
libssl-dev \
|
||||
mesa-utils libgl1-mesa-dri \
|
||||
&& \
|
||||
touch /root/.Xdefaults && \
|
||||
echo "en_US.UTF-8 UTF-8" >> /etc/locale.gen && \
|
||||
locale-gen && \
|
||||
echo 'LANG="en_US.UTF-8"' > /etc/default/locale && \
|
||||
chsh -s /bin/bash && \
|
||||
echo "root:root" | chpasswd && \
|
||||
mkdir -p /etc/systemd/system/[email protected]/ && \
|
||||
systemctl enable [email protected] && \
|
||||
rm /lib/systemd/system/getty.target.wants/getty-static.service && \
|
||||
rm /etc/motd /etc/issue && \
|
||||
systemctl disable systemd-timesyncd.service && \
|
||||
systemctl disable apt-daily.timer && \
|
||||
systemctl disable apt-daily-upgrade.timer && \
|
||||
systemctl disable dhcpcd.service && \
|
||||
echo "tmpfs /tmp tmpfs nodev,nosuid 0 0" >> /etc/fstab && \
|
||||
cd /root/ && \
|
||||
wget http://www.math.utah.edu/~mayer/linux/nbench-byte-2.2.3.tar.gz && \
|
||||
tar xfv nbench-byte-2.2.3.tar.gz && \
|
||||
rm nbench-byte-2.2.3.tar.gz && \
|
||||
mv nbench-byte-2.2.3 bench && \
|
||||
cd bench && \
|
||||
make
|
||||
|
||||
# Copy necessary configuration files
|
||||
COPY getty-noclear.conf getty-override.conf /etc/systemd/system/[email protected]/
|
||||
COPY getty-autologin-serial.conf /etc/systemd/system/[email protected]/
|
||||
COPY logind.conf /etc/systemd/logind.conf
|
||||
# COPY xinitrc /root/.xinitrc
|
||||
COPY xorg.conf /etc/X11/
|
||||
COPY networking.sh /root/
|
||||
COPY boot-9p /etc/initramfs-tools/scripts/boot-9p
|
||||
|
||||
# this needs to be commented out in order to boot from hdd
|
||||
RUN printf '%s\n' 9p 9pnet 9pnet_virtio virtio virtio_ring virtio_pci | tee -a /etc/initramfs-tools/modules && \
|
||||
echo 'BOOT=boot-9p' | tee -a /etc/initramfs-tools/initramfs.conf && \
|
||||
update-initramfs -u
|
||||
|
||||
# Clean up unnecessary files
|
||||
RUN apt-get --yes clean && \
|
||||
rm -r /var/lib/apt/lists/* && \
|
||||
rm -r /usr/share/doc/* && \
|
||||
rm -r /usr/share/man/* && \
|
||||
rm -r /usr/share/locale/?? && \
|
||||
rm /var/log/*.log /var/log/lastlog /var/log/wtmp /var/log/apt/*.log /var/log/apt/*.xz
|
||||
|
||||
# Install Tailscale
|
||||
RUN curl -fsSL https://tailscale.com/install.sh | sh
|
||||
RUN chmod +x /root/networking.sh
|
||||
|
||||
# Install Go and puter-fuse
|
||||
RUN wget https://go.dev/dl/go1.22.1.linux-386.tar.gz && \
|
||||
tar -C /usr/local -xzf go1.22.1.linux-386.tar.gz && \
|
||||
rm go1.22.1.linux-386.tar.gz && \
|
||||
export PATH=$PATH:/usr/local/go/bin && \
|
||||
go install github.com/HeyPuter/[email protected] && \
|
||||
mv /root/go/bin/puter-fuse /usr/local/bin && \
|
||||
rm -rf /root/go && \
|
||||
rm -f /go1.22.1.linux-386.tar.gz
|
||||
|
||||
RUN echo "kernel.printk = 3 4 1 3" >>/etc/sysctl.conf
|
||||
@@ -0,0 +1,5 @@
|
||||
rmmod ne2k-pci && modprobe ne2k-pci
|
||||
ifconfig enp0s5 192.168.1.5 netmask 255.255.255.0 up
|
||||
route add default gw 192.168.1.1
|
||||
echo "nameserver 1.1.1.1" > /etc/resolv.conf
|
||||
dhcpcd -w4 enp0s5
|
||||
@@ -0,0 +1,20 @@
|
||||
FROM library/node:lts-bookworm
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get install -y nodejs nasm gdb unzip p7zip-full openjdk-17-jre wget python3 qemu-system-x86 git git-core build-essential libc6-dev-i386-cross libc6-dev-i386 clang curl time
|
||||
|
||||
RUN curl https://sh.rustup.rs -sSf | sh -s -- -y
|
||||
RUN /root/.cargo/bin/rustup toolchain install stable && \
|
||||
/root/.cargo/bin/rustup target add wasm32-unknown-unknown && \
|
||||
/root/.cargo/bin/rustup component add rustfmt-preview && \
|
||||
/root/.cargo/bin/rustup update && /root/.cargo/bin/rustup update nightly
|
||||
|
||||
RUN git clone https://github.com/copy/v86
|
||||
|
||||
WORKDIR /app/v86
|
||||
|
||||
ENV PATH="$PATH:/root/.cargo/bin"
|
||||
|
||||
RUN make all
|
||||
@@ -0,0 +1,208 @@
|
||||
---
|
||||
Language: Cpp
|
||||
# BasedOnStyle: LLVM
|
||||
AccessModifierOffset: 0
|
||||
AlignAfterOpenBracket: Align
|
||||
AlignArrayOfStructures: None
|
||||
AlignConsecutiveAssignments:
|
||||
Enabled: false
|
||||
AcrossEmptyLines: false
|
||||
AcrossComments: false
|
||||
AlignCompound: false
|
||||
PadOperators: true
|
||||
AlignConsecutiveBitFields:
|
||||
Enabled: false
|
||||
AcrossEmptyLines: false
|
||||
AcrossComments: false
|
||||
AlignCompound: false
|
||||
PadOperators: false
|
||||
AlignConsecutiveDeclarations:
|
||||
Enabled: true
|
||||
AcrossEmptyLines: true
|
||||
AcrossComments: true
|
||||
AlignCompound: true
|
||||
PadOperators: true
|
||||
AlignConsecutiveMacros:
|
||||
Enabled: true
|
||||
AcrossEmptyLines: true
|
||||
AcrossComments: true
|
||||
AlignCompound: true
|
||||
PadOperators: true
|
||||
AlignEscapedNewlines: Right
|
||||
AlignOperands: Align
|
||||
AlignTrailingComments:
|
||||
Kind: Always
|
||||
OverEmptyLines: 0
|
||||
AllowAllArgumentsOnNextLine: true
|
||||
AllowAllParametersOfDeclarationOnNextLine: true
|
||||
AllowShortBlocksOnASingleLine: Never
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortEnumsOnASingleLine: true
|
||||
AllowShortFunctionsOnASingleLine: Empty
|
||||
AllowShortIfStatementsOnASingleLine: Never
|
||||
AllowShortLambdasOnASingleLine: All
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AlwaysBreakAfterDefinitionReturnType: None
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakBeforeMultilineStrings: false
|
||||
AlwaysBreakTemplateDeclarations: MultiLine
|
||||
AttributeMacros:
|
||||
- __capability
|
||||
BinPackArguments: true
|
||||
BinPackParameters: true
|
||||
BitFieldColonSpacing: Both
|
||||
BraceWrapping:
|
||||
AfterCaseLabel: false
|
||||
AfterClass: false
|
||||
AfterControlStatement: Never
|
||||
AfterEnum: false
|
||||
AfterExternBlock: false
|
||||
AfterFunction: false
|
||||
AfterNamespace: false
|
||||
AfterObjCDeclaration: false
|
||||
AfterStruct: false
|
||||
AfterUnion: false
|
||||
BeforeCatch: false
|
||||
BeforeElse: false
|
||||
BeforeLambdaBody: false
|
||||
BeforeWhile: false
|
||||
IndentBraces: false
|
||||
SplitEmptyFunction: true
|
||||
SplitEmptyRecord: true
|
||||
SplitEmptyNamespace: true
|
||||
BreakAfterAttributes: Never
|
||||
BreakAfterJavaFieldAnnotations: false
|
||||
BreakArrays: true
|
||||
BreakBeforeBinaryOperators: None
|
||||
BreakBeforeConceptDeclarations: Always
|
||||
BreakBeforeBraces: Allman
|
||||
BreakBeforeInlineASMColon: OnlyMultiline
|
||||
BreakBeforeTernaryOperators: true
|
||||
BreakConstructorInitializers: BeforeColon
|
||||
BreakInheritanceList: BeforeColon
|
||||
BreakStringLiterals: true
|
||||
ColumnLimit: 100
|
||||
CommentPragmas: '^ IWYU pragma:'
|
||||
CompactNamespaces: false
|
||||
ConstructorInitializerIndentWidth: 4
|
||||
ContinuationIndentWidth: 4
|
||||
Cpp11BracedListStyle: true
|
||||
DerivePointerAlignment: false
|
||||
DisableFormat: false
|
||||
EmptyLineAfterAccessModifier: Never
|
||||
EmptyLineBeforeAccessModifier: Always
|
||||
ExperimentalAutoDetectBinPacking: false
|
||||
FixNamespaceComments: true
|
||||
ForEachMacros:
|
||||
- foreach
|
||||
- Q_FOREACH
|
||||
- BOOST_FOREACH
|
||||
IfMacros:
|
||||
- KJ_IF_MAYBE
|
||||
IncludeBlocks: Merge
|
||||
IncludeIsMainRegex: '(Test)?$'
|
||||
IncludeIsMainSourceRegex: ''
|
||||
IndentAccessModifiers: true
|
||||
IndentCaseBlocks: false
|
||||
IndentCaseLabels: true
|
||||
IndentExternBlock: AfterExternBlock
|
||||
IndentGotoLabels: true
|
||||
IndentPPDirectives: None
|
||||
IndentRequiresClause: true
|
||||
IndentWidth: 4
|
||||
IndentWrappedFunctionNames: false
|
||||
InsertBraces: false
|
||||
InsertNewlineAtEOF: true
|
||||
InsertTrailingCommas: None
|
||||
IntegerLiteralSeparator:
|
||||
Binary: 0
|
||||
BinaryMinDigits: 0
|
||||
Decimal: 0
|
||||
DecimalMinDigits: 0
|
||||
Hex: 0
|
||||
HexMinDigits: 0
|
||||
JavaScriptQuotes: Leave
|
||||
JavaScriptWrapImports: true
|
||||
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||
LambdaBodyIndentation: Signature
|
||||
LineEnding: DeriveLF
|
||||
MacroBlockBegin: ''
|
||||
MacroBlockEnd: ''
|
||||
MaxEmptyLinesToKeep: 1
|
||||
NamespaceIndentation: All
|
||||
ObjCBinPackProtocolList: Auto
|
||||
ObjCBlockIndentWidth: 2
|
||||
ObjCBreakBeforeNestedBlockParam: true
|
||||
ObjCSpaceAfterProperty: false
|
||||
ObjCSpaceBeforeProtocolList: true
|
||||
PackConstructorInitializers: BinPack
|
||||
PenaltyBreakAssignment: 2
|
||||
PenaltyBreakBeforeFirstCallParameter: 19
|
||||
PenaltyBreakComment: 300
|
||||
PenaltyBreakFirstLessLess: 120
|
||||
PenaltyBreakOpenParenthesis: 0
|
||||
PenaltyBreakString: 1000
|
||||
PenaltyBreakTemplateDeclaration: 10
|
||||
PenaltyExcessCharacter: 1000000
|
||||
PenaltyIndentedWhitespace: 0
|
||||
PenaltyReturnTypeOnItsOwnLine: 60
|
||||
PointerAlignment: Left
|
||||
PPIndentWidth: 1
|
||||
QualifierAlignment: Left
|
||||
ReferenceAlignment: Pointer
|
||||
ReflowComments: true
|
||||
RemoveBracesLLVM: false
|
||||
RemoveSemicolon: false
|
||||
RequiresClausePosition: OwnLine
|
||||
RequiresExpressionIndentation: OuterScope
|
||||
SeparateDefinitionBlocks: Leave
|
||||
ShortNamespaceLines: 1
|
||||
SortIncludes: Never
|
||||
SortJavaStaticImport: Before
|
||||
SortUsingDeclarations: LexicographicNumeric
|
||||
SpaceAfterCStyleCast: false
|
||||
SpaceAfterLogicalNot: false
|
||||
SpaceAfterTemplateKeyword: true
|
||||
SpaceAroundPointerQualifiers: Default
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeCaseColon: false
|
||||
SpaceBeforeCpp11BracedList: false
|
||||
SpaceBeforeCtorInitializerColon: true
|
||||
SpaceBeforeInheritanceColon: true
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceBeforeParensOptions:
|
||||
AfterControlStatements: true
|
||||
AfterForeachMacros: true
|
||||
AfterFunctionDefinitionName: false
|
||||
AfterFunctionDeclarationName: false
|
||||
AfterIfMacros: true
|
||||
AfterOverloadedOperator: false
|
||||
AfterRequiresInClause: false
|
||||
AfterRequiresInExpression: false
|
||||
BeforeNonEmptyParentheses: false
|
||||
SpaceBeforeRangeBasedForLoopColon: true
|
||||
SpaceBeforeSquareBrackets: false
|
||||
SpaceInEmptyBlock: false
|
||||
SpacesBeforeTrailingComments: 1
|
||||
SpacesInAngles: Never
|
||||
SpacesInContainerLiterals: true
|
||||
SpacesInLineCommentPrefix:
|
||||
Minimum: 1
|
||||
Maximum: -1
|
||||
SpacesInSquareBrackets: false
|
||||
Standard: Latest
|
||||
StatementAttributeLikeMacros:
|
||||
- Q_EMIT
|
||||
StatementMacros:
|
||||
- Q_UNUSED
|
||||
- QT_REQUIRE_VERSION
|
||||
TabWidth: 4
|
||||
UseTab: Never
|
||||
WhitespaceSensitiveMacros:
|
||||
- BOOST_PP_STRINGIZE
|
||||
- CF_SWIFT_NAME
|
||||
- NS_SWIFT_NAME
|
||||
- PP_STRINGIZE
|
||||
- STRINGIZE
|
||||
...
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Canvas Manipulation</title>
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: Arial, sans-serif;
|
||||
}
|
||||
|
||||
#canvasContainer {
|
||||
position: relative;
|
||||
display: block;
|
||||
}
|
||||
|
||||
#controls {
|
||||
position: fixed;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
z-index: 999;
|
||||
background-color: #f1f1f1;
|
||||
padding: 10px;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
#canvasContainer canvas {
|
||||
border: 1px solid #000;
|
||||
margin-top: 10px;
|
||||
display: block;
|
||||
position: relative;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="controls">
|
||||
<label for="width">Width:</label>
|
||||
<input type="number" id="width" min="1">
|
||||
<label for="height">Height:</label>
|
||||
<input type="number" id="height" min="1">
|
||||
<button onclick="createCanvas()">Create Canvas</button>
|
||||
</div>
|
||||
<div id="canvasContainer">
|
||||
</div>
|
||||
|
||||
<script>
|
||||
let canvasCount = 0;
|
||||
|
||||
function createCanvas() {
|
||||
const width = document.getElementById("width").value;
|
||||
const height = document.getElementById("height").value;
|
||||
|
||||
if (width <= 0 || height <= 0 || width >= 1080 || height >= 1920) {
|
||||
alert("Please enter valid width and height values.");
|
||||
return;
|
||||
}
|
||||
|
||||
const canvasId = `canvas_${canvasCount}`;
|
||||
const canvasContainer = document.getElementById("canvasContainer");
|
||||
const canvas = document.createElement("canvas");
|
||||
canvas.id = canvasId;
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
canvasContainer.appendChild(canvas);
|
||||
|
||||
const canvasControls = document.createElement("div");
|
||||
canvasControls.classList.add("canvasControls");
|
||||
|
||||
const clearButton = document.createElement("button");
|
||||
clearButton.textContent = "Clear";
|
||||
clearButton.onclick = function() {
|
||||
const ctx = canvas.getContext("2d");
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
};
|
||||
|
||||
const pauseButton = document.createElement("button");
|
||||
pauseButton.textContent = "Pause";
|
||||
pauseButton.onclick = function() {
|
||||
const ctx = canvas.getContext("2d");
|
||||
console.log("Pausing v86");
|
||||
};
|
||||
|
||||
const consoleButton = document.createElement("button");
|
||||
consoleButton.textContent = "Get console";
|
||||
consoleButton.onclick = function() {
|
||||
const ctx = canvas.getContext("2d");
|
||||
console.log("Getting v86 console");
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
};
|
||||
|
||||
const deleteButton = document.createElement("button");
|
||||
deleteButton.textContent = "Delete";
|
||||
deleteButton.onclick = function() {
|
||||
canvas.remove();
|
||||
canvasControls.remove();
|
||||
};
|
||||
|
||||
canvasControls.appendChild(clearButton);
|
||||
canvasControls.appendChild(deleteButton);
|
||||
canvasControls.appendChild(pauseButton);
|
||||
canvasControls.appendChild(consoleButton);
|
||||
canvasContainer.appendChild(canvasControls);
|
||||
canvasCount++;
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,82 @@
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
const char* PIPE_NAME = "/tmp/bash_pipe";
|
||||
|
||||
int main()
|
||||
{
|
||||
mkfifo(PIPE_NAME, 0666);
|
||||
|
||||
while (true)
|
||||
{
|
||||
int pipe_fd = open(PIPE_NAME, O_RDONLY);
|
||||
if (pipe_fd == -1)
|
||||
{
|
||||
perror("open");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
std::string command;
|
||||
char buffer[128];
|
||||
ssize_t bytes_read;
|
||||
while ((bytes_read = read(pipe_fd, buffer, sizeof(buffer))) > 0)
|
||||
{
|
||||
command.append(buffer, bytes_read);
|
||||
}
|
||||
close(pipe_fd);
|
||||
|
||||
int pipe_to_child[2];
|
||||
int pipe_from_child[2];
|
||||
|
||||
if (pipe(pipe_to_child) == -1 || pipe(pipe_from_child) == -1)
|
||||
{
|
||||
std::cerr << "Failed to create pipes\n";
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
pid_t pid = fork();
|
||||
|
||||
if (pid < 0)
|
||||
{
|
||||
std::cerr << "Fork failed\n";
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
else if (pid == 0)
|
||||
{
|
||||
close(pipe_to_child[1]);
|
||||
close(pipe_from_child[0]);
|
||||
dup2(pipe_to_child[0], STDIN_FILENO);
|
||||
dup2(pipe_from_child[1], STDOUT_FILENO);
|
||||
execl("/bin/bash", "/bin/bash", "-i", nullptr);
|
||||
perror("exec");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
else
|
||||
{
|
||||
close(pipe_to_child[0]);
|
||||
close(pipe_from_child[1]);
|
||||
write(pipe_to_child[1], command.c_str(), command.size());
|
||||
close(pipe_to_child[1]);
|
||||
char output_buffer[128];
|
||||
ssize_t output_bytes_read;
|
||||
std::ofstream pipe_out(PIPE_NAME, std::ofstream::trunc);
|
||||
while ((output_bytes_read =
|
||||
read(pipe_from_child[0], output_buffer, sizeof(output_buffer))) > 0)
|
||||
{
|
||||
pipe_out.write(output_buffer, output_bytes_read);
|
||||
}
|
||||
close(pipe_from_child[0]);
|
||||
pipe_out.close();
|
||||
}
|
||||
}
|
||||
unlink(PIPE_NAME);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
// Compile and pipe into aplay in emu for sound check
|
||||
main(i){for(i=0;;++i)putchar((i+(i>>2)|(i>>8)|(i>>6)));}
|
||||
Executable
+64
@@ -0,0 +1,64 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
ROOT_DIR="$(pwd)"
|
||||
|
||||
# This has to be something, that isn't wrapped by a repo with a package.json
|
||||
VM_DIR="/tmp/vm"
|
||||
|
||||
# Goes from 1 to 22
|
||||
ZSTD_LEVEL=22
|
||||
|
||||
build()
|
||||
{
|
||||
mkdir -p "$VM_DIR"
|
||||
rm -rf "$VM_DIR/v86"
|
||||
cd "$ROOT_DIR/make_container" || exit
|
||||
docker build . -t v86builder
|
||||
docker run --name v86build v86builder
|
||||
docker cp v86build:/app/v86 "$VM_DIR"
|
||||
docker rm v86build
|
||||
|
||||
# Overwrite v86'd debian Dockerfile with our own
|
||||
cat "$ROOT_DIR/imagegen/Dockerfile" > "$VM_DIR/v86/tools/docker/debian/Dockerfile"
|
||||
|
||||
# Navigate to the Dockerfile directory
|
||||
cd "$VM_DIR/v86/tools/docker/debian" || exit
|
||||
|
||||
# Build the container which will be used to serve v86
|
||||
chmod +x build-container.sh
|
||||
./build-container.sh
|
||||
|
||||
# Build the state of the VM
|
||||
chmod +x build-state.js
|
||||
./build-state.js
|
||||
|
||||
# Compress the generated state image
|
||||
zstd --ultra -$ZSTD_LEVEL < "$VM_DIR/v86/images/debian-state-base.bin" > "$VM_DIR/v86/images/image.bin"
|
||||
|
||||
# Make project directories
|
||||
mkdir -p "$ROOT_DIR/www/third-party"
|
||||
mkdir -p "$ROOT_DIR/www/static"
|
||||
|
||||
# Copy/move necessary files to deployment directory
|
||||
mv "$VM_DIR/v86/images/image.bin" "$ROOT_DIR/www/static/image.bin"
|
||||
cp "$VM_DIR/v86/build/libv86.js" "$ROOT_DIR/www/third-party/libv86.js"
|
||||
cp "$VM_DIR/v86/build/v86.wasm" "$ROOT_DIR/www/third-party/v86.wasm"
|
||||
cp -r "$VM_DIR/v86/images/debian-9p-rootfs-flat/" "$ROOT_DIR/www/static/9p-rootfs/"
|
||||
}
|
||||
|
||||
if [ ! -d "$VM_DIR/v86" ]
|
||||
then
|
||||
build
|
||||
else
|
||||
echo "V86 appears to be built"
|
||||
read -p "Do you want to rebuild V86? (yes/no): " rebuild_choice
|
||||
if [ "$rebuild_choice" = "yes" ]; then
|
||||
echo "Rebuilding v86..."
|
||||
build
|
||||
fi
|
||||
fi
|
||||
|
||||
# Start a HTTP server
|
||||
cd "$ROOT_DIR/www/" || exit
|
||||
echo "Opening a server on localhost with port 8080"
|
||||
python3 -m http.server -b 127.0.0.1 8080
|
||||
@@ -0,0 +1,20 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<script src="./third-party/libv86.js"></script>
|
||||
<link rel="stylesheet" href="./third-party/xterm.css" />
|
||||
<script src="./third-party/xterm.js"></script>
|
||||
<script type="module" defer>
|
||||
"use strict";
|
||||
import InstanceManager from "./js/InstanceManager.mjs"
|
||||
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
const manager = new InstanceManager({spawnRoot: document.body, term: true});
|
||||
manager.createInstance({spawnRoot: document.body, term: true});
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,104 @@
|
||||
import { V86 } from "./V86Wrapper.mjs";
|
||||
/**
|
||||
* Class representing an Instance of an emulator machine.
|
||||
*/
|
||||
class Instance {
|
||||
/**
|
||||
* Create an Instance.
|
||||
* @param {Object} options - Options for configuring the instance.
|
||||
* @param {boolean} [options.term=true] - Terminal option.
|
||||
* @param {boolean} [options.screen=false] - Screen option.
|
||||
* @param {number} [options.memory=1024] - Memory size for the instance; must be power of two.
|
||||
* @param {HTMLElement} [options.spawnRoot=undefined] - Html element where instance should be spawned.
|
||||
* @param {boolean} [options.autoStart=true] - Whether to automatically start the instance.
|
||||
* @param {string} [options.remote="./"] - Remote URL, defaults to origin.
|
||||
* @param {string} [options.wsUrl=""] - Websocket URL option for communication with the outside world.
|
||||
* @throws Will throw an error if remote URL does not end with a slash. @throws Will throw an error if the amount of memory provided is not a power of two.
|
||||
*/
|
||||
constructor(options) {
|
||||
const defaultOptions = {
|
||||
term: false,
|
||||
screen: false,
|
||||
memory: 1024,
|
||||
spawnRoot: undefined,
|
||||
autoStart: true,
|
||||
remote: "./",
|
||||
instanceName: [...Array(10)].map(() => Math.random().toString(36)[2]).join(''),
|
||||
wsUrl: "",
|
||||
};
|
||||
const instanceOptions = { ...defaultOptions, ...options };
|
||||
|
||||
if (!instanceOptions.remote.endsWith('/'))
|
||||
throw new Error("Instance ctor: Remote URL must end with a slash");
|
||||
if (typeof self !== 'undefined' && self.crypto) {
|
||||
this.instanceID = self.crypto.randomUUID();
|
||||
} else {
|
||||
this.instanceID = "Node";
|
||||
}
|
||||
this.terminals = [];
|
||||
let v86Options = {
|
||||
wasm_path: instanceOptions.remote + "third-party/v86.wasm",
|
||||
preserve_mac_from_state_image: true,
|
||||
memory_size: instanceOptions.memory * 1024 * 1024,
|
||||
vga_memory_size: 8 * 1024 * 1024,
|
||||
initial_state: { url: instanceOptions.remote + "static/image.bin" },
|
||||
filesystem: { baseurl: instanceOptions.remote + "static/9p-rootfs/" },
|
||||
autostart: instanceOptions.autoStart,
|
||||
};
|
||||
if (!(instanceOptions.wsUrl === ""))
|
||||
v86Options.network_relay_url = instanceOptions.wsUrl;
|
||||
if (!((Math.log(v86Options.memory_size) / Math.log(2)) % 1 === 0))
|
||||
throw new Error("Instance ctor: Amount of memory provided isn't a power of two");
|
||||
if (instanceOptions.screen === true) {
|
||||
if (instanceOptions.spawnRoot === undefined)
|
||||
throw new Error("Instance ctor: spawnRoot is undefined, cannot continue")
|
||||
instanceOptions.spawnRoot.appendChild((() => {
|
||||
const div = document.createElement("div");
|
||||
div.setAttribute("id", instanceOptions.instanceName + '-screen');
|
||||
|
||||
const child_div = document.createElement("div");
|
||||
child_div.setAttribute("style", "white-space: pre; font: 14px monospace; line-height: 14px");
|
||||
|
||||
const canvas = document.createElement("canvas");
|
||||
canvas.setAttribute("style", "display: none");
|
||||
|
||||
div.appendChild(child_div);
|
||||
div.appendChild(canvas);
|
||||
return div;
|
||||
})());
|
||||
v86Options.screen_container = document.getElementById(instanceOptions.instanceName + '-screen');
|
||||
}
|
||||
this.vm = new V86(v86Options);
|
||||
if (instanceOptions.term === true) {
|
||||
if (instanceOptions.spawnRoot === undefined)
|
||||
throw new Error("Instance ctor: spawnRoot is undefined, cannot continue")
|
||||
var term = new Terminal({
|
||||
allowTransparency: true,
|
||||
});
|
||||
instanceOptions.spawnRoot.appendChild((() => {
|
||||
const div = document.createElement("div");
|
||||
div.setAttribute("id", instanceOptions.instanceName + '-terminal');
|
||||
return div;
|
||||
})());
|
||||
term.open(document.getElementById(instanceOptions.instanceName + '-terminal'));
|
||||
term.write("Now booting emu, please stand by ...");
|
||||
this.vm.add_listener("emulator-started", () => {
|
||||
// emulator.serial0_send("\nsh networking.sh > /dev/null 2>&1 &\n\n");
|
||||
// emulator.serial0_send("clear\n");
|
||||
term.write("Welcome to psl!");
|
||||
this.vm.serial0_send("\n");
|
||||
});
|
||||
this.vm.add_listener("serial0-output-byte", (byte) => {
|
||||
var chr = String.fromCharCode(byte);
|
||||
if (chr <= "~") {
|
||||
term.write(chr);
|
||||
}
|
||||
});
|
||||
term.onData(data => {
|
||||
this.vm.serial0_send(data);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default Instance
|
||||
@@ -0,0 +1,139 @@
|
||||
import Instance from "./Instance.mjs"
|
||||
|
||||
/**
|
||||
* Class representing the basic interface for managing instances of emulated machines.
|
||||
*/
|
||||
class InstanceManager {
|
||||
/**
|
||||
* Create an Instance Manager.
|
||||
* @param {Object} [options] - Options for configuring the instance manager.
|
||||
* @param {boolean} [options.screen=true] - Spawn screen option.
|
||||
* @param {boolean} [options.term=false] - Spawn terminal option.
|
||||
* @param {string} [options.instanceName="Host"] - Name of the instance.
|
||||
* @param {number} [options.memory=1024] - Memory size for the instance; must be power of two.
|
||||
* @param {HTMLElement} [options.spawnRoot=undefined] - Htlm element where instance should be spawned.
|
||||
* @param {boolean} [options.autoStart=true] - Whether to automatically start the instance.
|
||||
* @param {string} [options.remote="./"] - Remote URL, defaults to origin.
|
||||
* @param {string} [options.wsUrl=""] - Websocket URL option.
|
||||
*/
|
||||
constructor(options) {
|
||||
const defaultOptions = {
|
||||
term: false,
|
||||
screen: false,
|
||||
instanceName: "Host",
|
||||
memory: 1024,
|
||||
spawnRoot: undefined,
|
||||
autoStart: true,
|
||||
remote: "./",
|
||||
wsUrl: "",
|
||||
};
|
||||
const instanceOptions = { ...defaultOptions, ...options };
|
||||
this.instances = {};
|
||||
this.instanceNames = [];
|
||||
this.curr_inst = 0;
|
||||
this.instanceNames.push(instanceOptions.instanceName);
|
||||
this.instances[instanceOptions.instanceName] = new Instance(instanceOptions);
|
||||
}
|
||||
/**
|
||||
* Create an instance with given options and adds it to the pool of instances.
|
||||
* @param {Object} options - Options for configuring the instance.
|
||||
* @returns {Promise<Object>} - Resolves with the initialized instance.
|
||||
*/
|
||||
async createInstance(options) {
|
||||
const instance = new Instance(options);
|
||||
this.instanceNames.push(instance.instanceName);
|
||||
this.instances[instance.instanceName] = instance;
|
||||
return instance;
|
||||
}
|
||||
/**
|
||||
* Continue running a suspended instance.
|
||||
* @param {string} instName - instName of the instance to continue.
|
||||
*/
|
||||
async continueInstance(instName) {
|
||||
var instance = await this.getInstanceByinstName(instName);
|
||||
if (!instance.vm.cpu_is_running)
|
||||
await instance.vm.run();
|
||||
}
|
||||
/**
|
||||
* Suspend a running instance.
|
||||
* @param {string} instName - instName of the instance to suspend.
|
||||
*/
|
||||
async suspendInstance(instName) {
|
||||
var instance = await this.getInstanceByinstName(instName);
|
||||
if (instance.vm.cpu_is_running)
|
||||
await instance.vm.stop();
|
||||
}
|
||||
/**
|
||||
* Save the state of a running instance.
|
||||
* @param {string} instName - instName of the instance to save state.
|
||||
* @returns {Promise} - Promise resolving once state is saved.
|
||||
*/
|
||||
async saveState(instName) {
|
||||
const instance = this.getInstanceByinstName(instName);
|
||||
if (instance.vm.cpu_is_running)
|
||||
return instance.vm.save_state();
|
||||
}
|
||||
/**
|
||||
* Load the state of a previously saved instance.
|
||||
* @param {string} instName - instName of the instance to load state.
|
||||
* @param {any} state - State to load.
|
||||
* @returns {Promise} - Promise resolving once state is loaded.
|
||||
*/
|
||||
async loadState(instName, state) {
|
||||
const instance = this.getInstanceByinstName(instName);
|
||||
if (instance.vm.cpu_is_running)
|
||||
await instance.vm.save_state(state);
|
||||
}
|
||||
/**
|
||||
* Connect two instances for communication through NIC's.
|
||||
* @param {string} destinationinstName - instName of the destination instance.
|
||||
* @param {string} sourceinstName - instName of the source instance.
|
||||
*/
|
||||
async connectInstances(destinationinstName, sourceinstName) {
|
||||
const destinationInstance = this.getInstanceByinstName(destinationinstName);
|
||||
const sourceInstance = this.getInstanceByinstName(sourceinstName);
|
||||
destinationInstance.add_listener("net0-send", (data) => {
|
||||
source.bus.send("net0-receive", data);
|
||||
});
|
||||
sourceInstance.add_listener("net0-send", (data) => {
|
||||
destination.bus.send("net0-receive", data);
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Execute a command within an instance.
|
||||
* @param {Object} inst - Instance object.
|
||||
* @param {string} cmd - Command to execute.
|
||||
* @param {Object} env - Environment variables.
|
||||
* @param {number} [timeout=60] - Timeout for the command execution.
|
||||
*/
|
||||
async exec(inst, cmd, env, timeout = 60) {
|
||||
// TODO: instNamed pipes on the instance would make this super nice so multiple terminals can be had
|
||||
}
|
||||
/**
|
||||
* Destroy a specific instance.
|
||||
* @param {string} instName - instName of the instance to destroy.
|
||||
*/
|
||||
async destroyInstance(instName) {
|
||||
await this.getInstanceByinstName(instName).destroy();
|
||||
}
|
||||
/**
|
||||
* Destroy all instances.
|
||||
*/
|
||||
async destroyInstances() {
|
||||
for (const instance in this.instances)
|
||||
destroyInstance(instance)
|
||||
}
|
||||
/**
|
||||
* Get an instance by its instName.
|
||||
* @param {string} instName - instName of the instance.
|
||||
* @returns {Object} - The instance object.
|
||||
* @throws Will throw an error if the instance instName is not found.
|
||||
*/
|
||||
async getInstanceByinstName(instName) {
|
||||
if (!(instName in this.instances))
|
||||
throw Error("getInstance: instName not found in instances object");
|
||||
return this.instances[instName];
|
||||
}
|
||||
}
|
||||
|
||||
export default InstanceManager
|
||||
@@ -0,0 +1,16 @@
|
||||
let V86;
|
||||
|
||||
if (typeof window !== 'undefined') {
|
||||
V86 = window.V86;
|
||||
} else {
|
||||
try {
|
||||
const { createRequire } = await import('module');
|
||||
const require = createRequire(import.meta.url);
|
||||
const NodeV86 = require("../third-party/libv86.js");
|
||||
V86 = NodeV86.V86;
|
||||
} catch (error) {
|
||||
console.error('Failed to load V86 in Node.js environment:', error);
|
||||
}
|
||||
}
|
||||
|
||||
export { V86 };
|
||||
Executable
+44
@@ -0,0 +1,44 @@
|
||||
#!/usr/bin/env node
|
||||
"use strict";
|
||||
|
||||
import('./js/InstanceManager.mjs').then(module => {
|
||||
const InstanceManager = module.default;
|
||||
|
||||
process.stdin.setRawMode(true);
|
||||
process.stdin.resume();
|
||||
process.stdin.setEncoding("utf8");
|
||||
|
||||
console.log("Now booting, please stand by ...");
|
||||
|
||||
const manager = new InstanceManager({ screen: false, term: false, spawnRoot: undefined });
|
||||
manager.getInstanceByinstName("Host").then(result => {
|
||||
const hostvm = result.vm;
|
||||
|
||||
hostvm.add_listener("emulator-started", () => {
|
||||
process.stdout.write("Welcome to psl!");
|
||||
hostvm.serial0_send("\n");
|
||||
});
|
||||
|
||||
hostvm.add_listener("serial0-output-byte", (byte) => {
|
||||
var chr = String.fromCharCode(byte);
|
||||
if (chr <= "~") {
|
||||
process.stdout.write(chr);
|
||||
}
|
||||
});
|
||||
|
||||
process.stdin.on("data", (c) => {
|
||||
if (c === "\u0004") {
|
||||
hostvm.stop();
|
||||
process.stdin.pause();
|
||||
}
|
||||
else {
|
||||
hostvm.serial0_send(c);
|
||||
}
|
||||
});
|
||||
}).catch(error => {
|
||||
console.error(error);
|
||||
throw Error("Error in getting host inastance, quitting");
|
||||
});
|
||||
}).catch(error => {
|
||||
console.error('Error loading InstanceManager:', error);
|
||||
});
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"name": "x86incubator",
|
||||
"version": "1.0.0",
|
||||
"description": "x86emu experimental repo for puter",
|
||||
"main": "main.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"author": "Puter Technologies Inc.",
|
||||
"license": "AGPL-3.0-only"
|
||||
}
|
||||
File renamed without changes.
+626
@@ -0,0 +1,626 @@
|
||||
;(function(){'use strict';function ba(a,b){function c(x){x=x.toString(16);return"#"+"0".repeat(6-x.length)+x}function d(x,C,S,P){x.style.width="";x.style.height="";P&&(x.style.transform="");var aa=x.getBoundingClientRect();P?x.style.transform=(1===C?"":" scaleX("+C+")")+(1===S?"":" scaleY("+S+")"):(0===C%1&&0===S%1?(e.style.imageRendering="crisp-edges",e.style.imageRendering="pixelated",e.style["-ms-interpolation-mode"]="nearest-neighbor"):(e.style.imageRendering="",e.style["-ms-interpolation-mode"]=""),P=window.devicePixelRatio||
|
||||
1,0!==P%1&&(C/=P,S/=P));1!==C&&(x.style.width=aa.width*C+"px");1!==S&&(x.style.height=aa.height*S+"px")}console.assert(a,"1st argument must be a DOM container");var e=a.getElementsByTagName("canvas")[0],g=e.getContext("2d",{alpha:!1}),f=a.getElementsByTagName("div")[0],k=document.createElement("div"),l,m,n=1,p=1,t=1,q,z=!1,w,u,I,U=!1,ea=this;a=new Uint16Array([8962,199,252,233,226,228,224,229,231,234,235,232,239,238,236,196,197,201,230,198,244,246,242,251,249,255,214,220,162,163,165,8359,402,225,
|
||||
237,243,250,241,209,170,186,191,8976,172,189,188,161,171,187,9617,9618,9619,9474,9508,9569,9570,9558,9557,9571,9553,9559,9565,9564,9563,9488,9492,9524,9516,9500,9472,9532,9566,9567,9562,9556,9577,9574,9568,9552,9580,9575,9576,9572,9573,9561,9560,9554,9555,9579,9578,9496,9484,9608,9604,9612,9616,9600,945,223,915,960,931,963,181,964,934,920,937,948,8734,966,949,8745,8801,177,8805,8804,8992,8993,247,8776,176,8729,183,8730,8319,178,9632,160]);for(var Ab=new Uint16Array([32,9786,9787,9829,9830,9827,9824,
|
||||
8226,9688,9675,9689,9794,9792,9834,9835,9788,9658,9668,8597,8252,182,167,9644,8616,8593,8595,8594,8592,8735,8596,9650,9660]),Ra=[],db,sa=0;256>sa;sa++)db=126<sa?a[sa-127]:32>sa?Ab[sa]:sa,Ra[sa]=String.fromCharCode(db);g.imageSmoothingEnabled=!1;k.style.position="absolute";k.style.backgroundColor="#ccc";k.style.width="7px";k.style.display="inline-block";f.style.display="block";e.style.display="none";this.bus=b;b.register("screen-set-mode",function(x){this.set_mode(x)},this);b.register("screen-fill-buffer-end",
|
||||
function(x){this.update_buffer(x)},this);b.register("screen-put-char",function(x){this.put_char(x[0],x[1],x[2],x[3],x[4])},this);b.register("screen-update-cursor",function(x){this.update_cursor(x[0],x[1])},this);b.register("screen-update-cursor-scanline",function(x){this.update_cursor_scanline(x[0],x[1])},this);b.register("screen-clear",function(){this.clear_screen()},this);b.register("screen-set-size-text",function(x){this.set_size_text(x[0],x[1])},this);b.register("screen-set-size-graphical",function(x){this.set_size_graphical(x[0],
|
||||
x[1],x[2],x[3])},this);this.init=function(){this.set_size_text(80,25);this.timer()};this.make_screenshot=function(){const x=new Image;if(z)x.src=e.toDataURL("image/png");else{const C=[9,16],S=document.createElement("canvas");S.width=u*C[0];S.height=I*C[1];const P=S.getContext("2d");P.imageSmoothingEnabled=!1;P.font=window.getComputedStyle(f).font;P.textBaseline="top";for(let aa=0;aa<u;aa++)for(let fa=0;fa<I;fa++){const ta=3*(fa*u+aa);P.fillStyle=c(w[ta+1]);P.fillRect(aa*C[0],fa*C[1],C[0],C[1]);P.fillStyle=
|
||||
c(w[ta+2]);P.fillText(Ra[w[ta]],aa*C[0],fa*C[1])}"none"!==k.style.display&&(P.fillStyle=k.style.backgroundColor,P.fillRect(m*C[0],l*C[1]+parseInt(k.style.marginTop,10)-1,parseInt(k.style.width,10),parseInt(k.style.height,10)));x.src=S.toDataURL("image/png")}return x};this.put_char=function(x,C,S,P,aa){x<I&&C<u&&(C=3*(x*u+C),w[C]=S,w[C+1]=P,w[C+2]=aa,q[x]=1)};this.timer=function(){U||requestAnimationFrame(z?Bb:Cb)};var Cb=function(){for(var x=0;x<I;x++)q[x]&&(ea.text_update_row(x),q[x]=0);this.timer()}.bind(this),
|
||||
Bb=function(){this.bus.send("screen-fill-buffer");this.timer()}.bind(this);this.destroy=function(){U=!0};this.set_mode=function(x){(z=x)?(f.style.display="none",e.style.display="block"):(f.style.display="block",e.style.display="none")};this.clear_screen=function(){g.fillStyle="#000";g.fillRect(0,0,e.width,e.height)};this.set_size_text=function(x,C){if(x!==u||C!==I){q=new Int8Array(C);w=new Int32Array(x*C*3);u=x;for(I=C;f.childNodes.length>C;)f.removeChild(f.firstChild);for(;f.childNodes.length<C;)f.appendChild(document.createElement("div"));
|
||||
for(x=0;x<C;x++)this.text_update_row(x);d(f,n,p,!0)}};this.set_size_graphical=function(x,C){e.style.display="block";e.width=x;e.height=C;t=640>=x&&2*x<window.innerWidth*window.devicePixelRatio&&2*C<window.innerHeight*window.devicePixelRatio?2:1;d(e,n*t,p*t,!1)};this.set_scale=function(x,C){n=x;p=C;d(f,n,p,!0);d(e,n*t,p*t,!1)};this.set_scale(n,p);this.update_cursor_scanline=function(x,C){x&32?k.style.display="none":(k.style.display="inline",k.style.height=Math.min(15,C-x)+"px",k.style.marginTop=Math.min(15,
|
||||
x)+"px")};this.update_cursor=function(x,C){if(x!==l||C!==m)q[x]=1,q[l]=1,l=x,m=C};this.text_update_row=function(x){var C=3*x*u,S;var P=f.childNodes[x];var aa=document.createElement("div");for(var fa=0;fa<u;){var ta=document.createElement("span");var eb=w[C+1];var fb=w[C+2];ta.style.backgroundColor=c(eb);ta.style.color=c(fb);for(S="";fa<u&&w[C+1]===eb&&w[C+2]===fb;)if(S+=Ra[w[C]],fa++,C+=3,x===l)if(fa===m)break;else if(fa===m+1){aa.appendChild(k);break}ta.textContent=S;aa.appendChild(ta)}P.parentNode.replaceChild(aa,
|
||||
P)};this.update_buffer=function(x){x.forEach(C=>{g.putImageData(C.image_data,C.screen_x-C.buffer_x,C.screen_y-C.buffer_y,C.buffer_x,C.buffer_y,C.buffer_width,C.buffer_height)})};this.init()};const ca=Object.freeze(["shared","exclusive","unlock"]);
|
||||
function da(a,b,c){this.fs=a;this.bus=c;this.configspace_tagname=[104,111,115,116,57,112];this.configspace_taglen=this.configspace_tagname.length;this.VERSION="9P2000.L";this.msize=this.BLOCKSIZE=8192;this.replybuffer=new Uint8Array(2*this.msize);this.replybuffersize=0;this.fids=[];this.virtio=new h(b,{name:"virtio-9p",pci_id:48,device_id:4169,subsystem_device_id:9,common:{initial_port:43008,queues:[{size_supported:32,notify_offset:0}],features:[0,32,29,28],on_driver_ok:()=>{}},notification:{initial_port:43264,
|
||||
single_handler:!1,handlers:[d=>{if(0===d){for(;this.virtqueue.has_request();)d=this.virtqueue.pop_request(),this.ReceiveRequest(d);this.virtqueue.notify_me_after(0)}}]},isr_status:{initial_port:42752},device_specific:{initial_port:42496,struct:[{bytes:2,name:"mount tag length",read:()=>this.configspace_taglen,write:()=>{}}].concat(r.range(254).map(d=>({bytes:1,name:"mount tag name "+d,read:()=>this.configspace_tagname[d]||0,write:()=>{}})))}});this.virtqueue=this.virtio.queues[0]}
|
||||
da.prototype.get_state=function(){var a=[];a[0]=this.configspace_tagname;a[1]=this.configspace_taglen;a[2]=this.virtio;a[3]=this.VERSION;a[4]=this.BLOCKSIZE;a[5]=this.msize;a[6]=this.replybuffer;a[7]=this.replybuffersize;a[8]=this.fids.map(function(b){return[b.inodeid,b.type,b.uid,b.dbg_name]});a[9]=this.fs;return a};
|
||||
da.prototype.set_state=function(a){this.configspace_tagname=a[0];this.configspace_taglen=a[1];this.virtio.set_state(a[2]);this.virtqueue=this.virtio.queues[0];this.VERSION=a[3];this.BLOCKSIZE=a[4];this.msize=a[5];this.replybuffer=a[6];this.replybuffersize=a[7];this.fids=a[8].map(function(b){return{inodeid:b[0],type:b[1],uid:b[2],dbg_name:b[3]}});this.fs.set_state(a[9])};da.prototype.Createfid=function(a,b,c,d){return{inodeid:a,type:b,uid:c,dbg_name:d}};
|
||||
da.prototype.update_dbg_name=function(a,b){for(const c of this.fids)c.inodeid===a&&(c.dbg_name=b)};da.prototype.Reset=function(){this.fids=[]};da.prototype.BuildReply=function(a,b,c){v.Marshall(["w","b","h"],[c+7,a+1,b],this.replybuffer,0);c+7>=this.replybuffer.length&&y.Debug("Error in 9p: payloadsize exceeds maximum length");this.replybuffersize=c+7};da.prototype.SendError=function(a,b,c){b=v.Marshall(["w"],[c],this.replybuffer,7);this.BuildReply(6,a,b)};
|
||||
da.prototype.SendReply=function(a){a.set_next_blob(this.replybuffer.subarray(0,this.replybuffersize));this.virtqueue.push_reply(a);this.virtqueue.flush_replies()};
|
||||
da.prototype.ReceiveRequest=async function(a){var b=new Uint8Array(a.length_readable);a.get_next_blob(b);var c={offset:0},d=v.Unmarshall(["w","b","h"],b,c),e=d[0],g=d[1],f=d[2];switch(g){case 8:e=this.fs.GetTotalSize();b=this.fs.GetSpace();d=[16914839];d[1]=this.BLOCKSIZE;d[2]=Math.floor(b/d[1]);d[3]=d[2]-Math.floor(e/d[1]);d[4]=d[2]-Math.floor(e/d[1]);d[5]=this.fs.CountUsedInodes();d[6]=this.fs.CountFreeInodes();d[7]=0;d[8]=256;e=v.Marshall("wwddddddw".split(""),d,this.replybuffer,7);this.BuildReply(g,
|
||||
f,e);this.SendReply(a);break;case 112:case 12:d=v.Unmarshall(["w","w"],b,c);var k=d[0];c=d[1];y.Debug("[open] fid="+k+", mode="+c);b=this.fids[k].inodeid;var l=this.fs.GetInode(b);y.Debug("file open "+this.fids[k].dbg_name);e=this.fs.OpenInode(b,c);this.fs.AddEvent(this.fids[k].inodeid,function(){y.Debug("file opened "+this.fids[k].dbg_name+" tag:"+f);var t=[];t[0]=l.qid;t[1]=this.msize-24;v.Marshall(["Q","w"],t,this.replybuffer,7);this.BuildReply(g,f,17);this.SendReply(a)}.bind(this));break;case 70:d=
|
||||
v.Unmarshall(["w","w","s"],b,c);b=d[0];k=d[1];e=d[2];y.Debug("[link] dfid="+b+", name="+e);e=this.fs.Link(this.fids[b].inodeid,this.fids[k].inodeid,e);if(0>e){this.SendError(f,-1===e?"Operation not permitted":"Unknown error: "+-e,-e);this.SendReply(a);break}this.BuildReply(g,f,0);this.SendReply(a);break;case 16:d=v.Unmarshall(["w","s","s","w"],b,c);k=d[0];e=d[1];b=d[2];d=d[3];y.Debug("[symlink] fid="+k+", name="+e+", symgt="+b+", gid="+d);b=this.fs.CreateSymlink(e,this.fids[k].inodeid,b);l=this.fs.GetInode(b);
|
||||
l.uid=this.fids[k].uid;l.gid=d;v.Marshall(["Q"],[l.qid],this.replybuffer,7);this.BuildReply(g,f,13);this.SendReply(a);break;case 18:d=v.Unmarshall("wswwww".split(""),b,c);k=d[0];e=d[1];c=d[2];b=d[3];var m=d[4];d=d[5];y.Debug("[mknod] fid="+k+", name="+e+", major="+b+", minor="+m);b=this.fs.CreateNode(e,this.fids[k].inodeid,b,m);l=this.fs.GetInode(b);l.mode=c;l.uid=this.fids[k].uid;l.gid=d;v.Marshall(["Q"],[l.qid],this.replybuffer,7);this.BuildReply(g,f,13);this.SendReply(a);break;case 22:d=v.Unmarshall(["w"],
|
||||
b,c);k=d[0];l=this.fs.GetInode(this.fids[k].inodeid);y.Debug("[readlink] fid="+k+" name="+this.fids[k].dbg_name+" target="+l.symlink);e=v.Marshall(["s"],[l.symlink],this.replybuffer,7);this.BuildReply(g,f,e);this.SendReply(a);break;case 72:d=v.Unmarshall(["w","s","w","w"],b,c);k=d[0];e=d[1];c=d[2];d=d[3];y.Debug("[mkdir] fid="+k+", name="+e+", mode="+c+", gid="+d);b=this.fs.CreateDirectory(e,this.fids[k].inodeid);l=this.fs.GetInode(b);l.mode=c|ha;l.uid=this.fids[k].uid;l.gid=d;v.Marshall(["Q"],[l.qid],
|
||||
this.replybuffer,7);this.BuildReply(g,f,13);this.SendReply(a);break;case 14:d=v.Unmarshall(["w","s","w","w","w"],b,c);k=d[0];e=d[1];b=d[2];c=d[3];d=d[4];this.bus.send("9p-create",[e,this.fids[k].inodeid]);y.Debug("[create] fid="+k+", name="+e+", flags="+b+", mode="+c+", gid="+d);b=this.fs.CreateFile(e,this.fids[k].inodeid);this.fids[k].inodeid=b;this.fids[k].type=1;this.fids[k].dbg_name=e;l=this.fs.GetInode(b);l.uid=this.fids[k].uid;l.gid=d;l.mode=c;v.Marshall(["Q","w"],[l.qid,this.msize-24],this.replybuffer,
|
||||
7);this.BuildReply(g,f,17);this.SendReply(a);break;case 52:d=v.Unmarshall("wbwddws".split(""),b,c);k=d[0];b=d[2];e=0===d[4]?Infinity:d[4];d=this.fs.DescribeLock(d[1],d[3],e,d[5],d[6]);y.Debug("[lock] fid="+k+", type="+ca[d.type]+", start="+d.start+", length="+d.length+", proc_id="+d.proc_id);e=this.fs.Lock(this.fids[k].inodeid,d,b);v.Marshall(["b"],[e],this.replybuffer,7);this.BuildReply(g,f,1);this.SendReply(a);break;case 54:d=v.Unmarshall("wbddws".split(""),b,c);k=d[0];e=0===d[3]?Infinity:d[3];
|
||||
d=this.fs.DescribeLock(d[1],d[2],e,d[4],d[5]);y.Debug("[getlock] fid="+k+", type="+ca[d.type]+", start="+d.start+", length="+d.length+", proc_id="+d.proc_id);e=this.fs.GetLock(this.fids[k].inodeid,d);e||(e=d,e.type=2);e=v.Marshall(["b","d","d","w","s"],[e.type,e.start,Infinity===e.length?0:e.length,e.proc_id,e.client_id],this.replybuffer,7);this.BuildReply(g,f,e);this.SendReply(a);break;case 24:d=v.Unmarshall(["w","d"],b,c);k=d[0];l=this.fs.GetInode(this.fids[k].inodeid);y.Debug("[getattr]: fid="+
|
||||
k+" name="+this.fids[k].dbg_name+" request mask="+d[1]);if(!l||l.status===ia){y.Debug("getattr: unlinked");this.SendError(f,"No such file or directory",2);this.SendReply(a);break}d[0]|=4096;d[0]=d[1];d[1]=l.qid;d[2]=l.mode;d[3]=l.uid;d[4]=l.gid;d[5]=l.nlinks;d[6]=l.major<<8|l.minor;d[7]=l.size;d[8]=this.BLOCKSIZE;d[9]=Math.floor(l.size/512+1);d[10]=l.atime;d[11]=0;d[12]=l.mtime;d[13]=0;d[14]=l.ctime;d[15]=0;d[16]=0;d[17]=0;d[18]=0;d[19]=0;v.Marshall("dQwwwddddddddddddddd".split(""),d,this.replybuffer,
|
||||
7);this.BuildReply(g,f,153);this.SendReply(a);break;case 26:d=v.Unmarshall("wwwwwddddd".split(""),b,c);k=d[0];l=this.fs.GetInode(this.fids[k].inodeid);y.Debug("[setattr]: fid="+k+" request mask="+d[1]+" name="+this.fids[k].dbg_name);d[1]&1&&(l.mode=d[2]);d[1]&2&&(l.uid=d[3]);d[1]&4&&(l.gid=d[4]);d[1]&16&&(l.atime=Math.floor((new Date).getTime()/1E3));d[1]&32&&(l.mtime=Math.floor((new Date).getTime()/1E3));d[1]&64&&(l.ctime=Math.floor((new Date).getTime()/1E3));d[1]&128&&(l.atime=d[6]);d[1]&256&&(l.mtime=
|
||||
d[8]);d[1]&8&&await this.fs.ChangeSize(this.fids[k].inodeid,d[5]);this.BuildReply(g,f,0);this.SendReply(a);break;case 50:d=v.Unmarshall(["w","d"],b,c);k=d[0];this.BuildReply(g,f,0);this.SendReply(a);break;case 40:case 116:d=v.Unmarshall(["w","d","w"],b,c);k=d[0];e=d[1];m=d[2];l=this.fs.GetInode(this.fids[k].inodeid);40==g&&y.Debug("[treaddir]: fid="+k+" offset="+e+" count="+m);116==g&&y.Debug("[read]: fid="+k+" ("+this.fids[k].dbg_name+") offset="+e+" count="+m+" fidtype="+this.fids[k].type);if(!l||
|
||||
l.status===ia){y.Debug("read/treaddir: unlinked");this.SendError(f,"No such file or directory",2);this.SendReply(a);break}if(2==this.fids[k].type)for(l.caps.length<e+m&&(m=l.caps.length-e),d=0;d<m;d++)this.replybuffer[11+d]=l.caps[e+d];else this.fs.OpenInode(this.fids[k].inodeid,void 0),d=this.fids[k].inodeid,m=Math.min(m,this.replybuffer.length-11),l.size<e+m?m=l.size-e:40==g&&(m=this.fs.RoundToDirentry(d,e+m)-e),e>l.size&&(m=0),this.bus.send("9p-read-start",[this.fids[k].dbg_name]),d=await this.fs.Read(d,
|
||||
e,m),this.bus.send("9p-read-end",[this.fids[k].dbg_name,m]),d&&this.replybuffer.set(d,11);v.Marshall(["w"],[m],this.replybuffer,7);this.BuildReply(g,f,4+m);this.SendReply(a);break;case 118:d=v.Unmarshall(["w","d","w"],b,c);k=d[0];e=d[1];m=d[2];d=this.fids[k].dbg_name;y.Debug("[write]: fid="+k+" ("+d+") offset="+e+" count="+m+" fidtype="+this.fids[k].type);if(2===this.fids[k].type){this.SendError(f,"Setxattr not supported",95);this.SendReply(a);break}else await this.fs.Write(this.fids[k].inodeid,e,
|
||||
m,b.subarray(c.offset));this.bus.send("9p-write-end",[d,m]);v.Marshall(["w"],[m],this.replybuffer,7);this.BuildReply(g,f,4);this.SendReply(a);break;case 74:d=v.Unmarshall(["w","s","w","s"],b,c);e=d[0];b=d[1];c=d[2];d=d[3];y.Debug("[renameat]: oldname="+b+" newname="+d);e=await this.fs.Rename(this.fids[e].inodeid,b,this.fids[c].inodeid,d);if(0>e){this.SendError(f,-2===e?"No such file or directory":-1===e?"Operation not permitted":-39===e?"Directory not empty":"Unknown error: "+-e,-e);this.SendReply(a);
|
||||
break}this.BuildReply(g,f,0);this.SendReply(a);break;case 76:d=v.Unmarshall(["w","s","w"],b,c);c=d[0];e=d[1];b=d[2];y.Debug("[unlink]: dirfd="+c+" name="+e+" flags="+b);k=this.fs.Search(this.fids[c].inodeid,e);if(-1==k){this.SendError(f,"No such file or directory",2);this.SendReply(a);break}e=this.fs.Unlink(this.fids[c].inodeid,e);if(0>e){this.SendError(f,-39===e?"Directory not empty":-1===e?"Operation not permitted":"Unknown error: "+-e,-e);this.SendReply(a);break}this.BuildReply(g,f,0);this.SendReply(a);
|
||||
break;case 100:d=v.Unmarshall(["w","s"],b,c);y.Debug("[version]: msize="+d[0]+" version="+d[1]);this.msize=d[0];e=v.Marshall(["w","s"],[this.msize,this.VERSION],this.replybuffer,7);this.BuildReply(g,f,e);this.SendReply(a);break;case 104:d=v.Unmarshall(["w","w","s","s","w"],b,c);k=d[0];e=d[4];y.Debug("[attach]: fid="+k+" afid="+A(d[1])+" uname="+d[2]+" aname="+d[3]);this.fids[k]=this.Createfid(0,1,e,"");l=this.fs.GetInode(this.fids[k].inodeid);v.Marshall(["Q"],[l.qid],this.replybuffer,7);this.BuildReply(g,
|
||||
f,13);this.SendReply(a);this.bus.send("9p-attach");break;case 108:d=v.Unmarshall(["h"],b,c);y.Debug("[flush] "+f);this.BuildReply(g,f,0);this.SendReply(a);break;case 110:d=v.Unmarshall(["w","w","h"],b,c);k=d[0];m=d[1];var n=d[2];y.Debug("[walk]: fid="+d[0]+" nwfid="+d[1]+" nwname="+n);if(0==n){this.fids[m]=this.Createfid(this.fids[k].inodeid,1,this.fids[k].uid,this.fids[k].dbg_name);v.Marshall(["h"],[0],this.replybuffer,7);this.BuildReply(g,f,2);this.SendReply(a);break}e=[];for(d=0;d<n;d++)e.push("s");
|
||||
c=v.Unmarshall(e,b,c);b=this.fids[k].inodeid;e=9;var p=0;y.Debug("walk in dir "+this.fids[k].dbg_name+" to: "+c.toString());for(d=0;d<n;d++){b=this.fs.Search(b,c[d]);if(-1==b){y.Debug("Could not find: "+c[d]);break}e+=v.Marshall(["Q"],[this.fs.GetInode(b).qid],this.replybuffer,e);p++;this.fids[m]=this.Createfid(b,1,this.fids[k].uid,c[d])}v.Marshall(["h"],[p],this.replybuffer,7);this.BuildReply(g,f,e-7);this.SendReply(a);break;case 120:d=v.Unmarshall(["w"],b,c);y.Debug("[clunk]: fid="+d[0]);this.fids[d[0]]&&
|
||||
0<=this.fids[d[0]].inodeid&&(await this.fs.CloseInode(this.fids[d[0]].inodeid),this.fids[d[0]].inodeid=-1,this.fids[d[0]].type=-1);this.BuildReply(g,f,0);this.SendReply(a);break;case 32:d=v.Unmarshall(["w","s","d","w"],b,c);k=d[0];e=d[1];c=d[2];b=d[3];y.Debug("[txattrcreate]: fid="+k+" name="+e+" attr_size="+c+" flags="+b);this.fids[k].type=2;this.BuildReply(g,f,0);this.SendReply(a);break;case 30:d=v.Unmarshall(["w","w","s"],b,c);k=d[0];e=d[2];y.Debug("[xattrwalk]: fid="+d[0]+" newfid="+d[1]+" name="+
|
||||
d[2]);this.SendError(f,"Setxattr not supported",95);this.SendReply(a);break;default:y.Debug("Error in Virtio9p: Unknown id "+g+" received"),y.Abort()}};function B(a){this.ports=[];this.cpu=a;for(var b=0;65536>b;b++)this.ports[b]=this.create_empty_entry();var c=a.memory_size[0];for(b=0;b<<17<c;b++)a.memory_map_read8[b]=a.memory_map_write8[b]=void 0,a.memory_map_read32[b]=a.memory_map_write32[b]=void 0;this.mmap_register(c,4294967296-c,function(d){A(d>>>0,8);return 255},function(d,e){A(d>>>0,8);A(e,2)},function(d){A(d>>>0,8);return-1},function(d,e){A(d>>>0,8);A(e>>>0,8)})}
|
||||
B.prototype.create_empty_entry=function(){return{read8:this.empty_port_read8,read16:this.empty_port_read16,read32:this.empty_port_read32,write8:this.empty_port_write,write16:this.empty_port_write,write32:this.empty_port_write,device:void 0}};B.prototype.empty_port_read8=function(){return 255};B.prototype.empty_port_read16=function(){return 65535};B.prototype.empty_port_read32=function(){return-1};B.prototype.empty_port_write=function(){};
|
||||
B.prototype.register_read=function(a,b,c,d,e){c&&(this.ports[a].read8=c);d&&(this.ports[a].read16=d);e&&(this.ports[a].read32=e);this.ports[a].device=b};B.prototype.register_write=function(a,b,c,d,e){c&&(this.ports[a].write8=c);d&&(this.ports[a].write16=d);e&&(this.ports[a].write32=e);this.ports[a].device=b};
|
||||
B.prototype.register_read_consecutive=function(a,b,c,d,e,g){function f(){return c.call(this)|d.call(this)<<8}function k(){return e.call(this)|g.call(this)<<8}function l(){return c.call(this)|d.call(this)<<8|e.call(this)<<16|g.call(this)<<24}e&&g?(this.register_read(a,b,c,f,l),this.register_read(a+1,b,d),this.register_read(a+2,b,e,k),this.register_read(a+3,b,g)):(this.register_read(a,b,c,f),this.register_read(a+1,b,d))};
|
||||
B.prototype.register_write_consecutive=function(a,b,c,d,e,g){function f(m){c.call(this,m&255);d.call(this,m>>8&255)}function k(m){e.call(this,m&255);g.call(this,m>>8&255)}function l(m){c.call(this,m&255);d.call(this,m>>8&255);e.call(this,m>>16&255);g.call(this,m>>>24)}e&&g?(this.register_write(a,b,c,f,l),this.register_write(a+1,b,d),this.register_write(a+2,b,e,k),this.register_write(a+3,b,g)):(this.register_write(a,b,c,f),this.register_write(a+1,b,d))};
|
||||
B.prototype.mmap_read32_shim=function(a){var b=this.cpu.memory_map_read8[a>>>17];return b(a)|b(a+1)<<8|b(a+2)<<16|b(a+3)<<24};B.prototype.mmap_write32_shim=function(a,b){var c=this.cpu.memory_map_write8[a>>>17];c(a,b&255);c(a+1,b>>8&255);c(a+2,b>>16&255);c(a+3,b>>>24)};
|
||||
B.prototype.mmap_register=function(a,b,c,d,e,g){A(a>>>0,8);A(b,8);e||(e=this.mmap_read32_shim.bind(this));g||(g=this.mmap_write32_shim.bind(this));for(a>>>=17;0<b;a++)this.cpu.memory_map_read8[a]=c,this.cpu.memory_map_write8[a]=d,this.cpu.memory_map_read32[a]=e,this.cpu.memory_map_write32[a]=g,b-=131072};B.prototype.port_write8=function(a,b){var c=this.ports[a];c.write8===this.empty_port_write&&(A(a,4),A(b,2),this.get_port_description(a));return c.write8.call(c.device,b)};
|
||||
B.prototype.port_write16=function(a,b){var c=this.ports[a];c.write16===this.empty_port_write&&(A(a,4),A(b,4),this.get_port_description(a));return c.write16.call(c.device,b)};B.prototype.port_write32=function(a,b){var c=this.ports[a];c.write32===this.empty_port_write&&(A(a,4),A(b>>>0,8),this.get_port_description(a));return c.write32.call(c.device,b)};
|
||||
B.prototype.port_read8=function(a){var b=this.ports[a];b.read8===this.empty_port_read8&&(A(a,4),this.get_port_description(a));b=b.read8.call(b.device);A(a);return b};B.prototype.port_read16=function(a){var b=this.ports[a];b.read16===this.empty_port_read16&&(A(a,4),this.get_port_description(a));b=b.read16.call(b.device);A(a);return b};B.prototype.port_read32=function(a){var b=this.ports[a];b.read32===this.empty_port_read32&&(A(a,4),this.get_port_description(a));return b.read32.call(b.device)};
|
||||
var ja={4:"PORT_DMA_ADDR_2",5:"PORT_DMA_CNT_2",10:"PORT_DMA1_MASK_REG",11:"PORT_DMA1_MODE_REG",12:"PORT_DMA1_CLEAR_FF_REG",13:"PORT_DMA1_MASTER_CLEAR",32:"PORT_PIC1_CMD",33:"PORT_PIC1_DATA",64:"PORT_PIT_COUNTER0",65:"PORT_PIT_COUNTER1",66:"PORT_PIT_COUNTER2",67:"PORT_PIT_MODE",96:"PORT_PS2_DATA",97:"PORT_PS2_CTRLB",100:"PORT_PS2_STATUS",112:"PORT_CMOS_INDEX",113:"PORT_CMOS_DATA",128:"PORT_DIAG",129:"PORT_DMA_PAGE_2",146:"PORT_A20",160:"PORT_PIC2_CMD",161:"PORT_PIC2_DATA",178:"PORT_SMI_CMD",179:"PORT_SMI_STATUS",
|
||||
212:"PORT_DMA2_MASK_REG",214:"PORT_DMA2_MODE_REG",218:"PORT_DMA2_MASTER_CLEAR",240:"PORT_MATH_CLEAR",368:"PORT_ATA2_CMD_BASE",496:"PORT_ATA1_CMD_BASE",632:"PORT_LPT2",744:"PORT_SERIAL4",760:"PORT_SERIAL2",884:"PORT_ATA2_CTRL_BASE",888:"PORT_LPT1",1E3:"PORT_SERIAL3",1008:"PORT_FD_BASE",1010:"PORT_FD_DOR",1012:"PORT_FD_STATUS",1013:"PORT_FD_DATA",1014:"PORT_HD_DATA",1015:"PORT_FD_DIR",1016:"PORT_SERIAL1",3320:"PORT_PCI_CMD",3321:"PORT_PCI_REBOOT",3324:"PORT_PCI_DATA",1026:"PORT_BIOS_DEBUG",1296:"PORT_QEMU_CFG_CTL",
|
||||
1297:"PORT_QEMU_CFG_DATA",45056:"PORT_ACPI_PM_BASE",45312:"PORT_SMB_BASE",35072:"PORT_BIOS_APM"};B.prototype.get_port_description=function(a){return ja[a]?" ("+ja[a]+")":""};function D(a,b){this.stopping=this.running=!1;this.tick_counter=0;this.worker=null;this.cpu=new E(a,b,()=>{this.idle&&this.next_tick(0)});this.bus=a;a.register("cpu-init",this.init,this);a.register("cpu-run",this.run,this);a.register("cpu-stop",this.stop,this);a.register("cpu-restart",this.restart,this);this.register_yield()}D.prototype.run=function(){this.stopping=!1;this.running||(this.running=!0,this.bus.send("emulator-started"));this.next_tick(0)};
|
||||
D.prototype.do_tick=function(){if(this.stopping||!this.running)this.stopping=this.running=!1,this.bus.send("emulator-stopped");else{this.idle=!1;var a=this.cpu.main_loop();this.next_tick(a)}};D.prototype.next_tick=function(a){const b=++this.tick_counter;this.idle=!0;this.yield(a,b)};D.prototype.yield_callback=function(a){a===this.tick_counter&&this.do_tick()};D.prototype.stop=function(){this.running&&(this.stopping=!0)};D.prototype.destroy=function(){this.unregister_yield()};
|
||||
D.prototype.restart=function(){this.cpu.reset_cpu();this.cpu.load_bios()};D.prototype.init=function(a){this.cpu.init(a,this.bus);this.bus.send("emulator-ready")};
|
||||
if("undefined"!==typeof process)D.prototype.yield=function(a,b){1>a?global.setImmediate(c=>this.yield_callback(c),b):setTimeout(c=>this.yield_callback(c),a,b)},D.prototype.register_yield=function(){},D.prototype.unregister_yield=function(){};else if("undefined"!==typeof Worker){function a(){globalThis.onmessage=function(b){const c=b.data.t;1>c?postMessage(b.data.tick):setTimeout(()=>postMessage(b.data.tick),c)}}D.prototype.register_yield=function(){const b=URL.createObjectURL(new Blob(["("+a.toString()+
|
||||
")()"],{type:"text/javascript"}));this.worker=new Worker(b);this.worker.onmessage=c=>this.yield_callback(c.data);URL.revokeObjectURL(b)};D.prototype.yield=function(b,c){this.worker.postMessage({t:b,tick:c})};D.prototype.unregister_yield=function(){this.worker&&this.worker.terminate();this.worker=null}}else D.prototype.yield=function(a){setTimeout(()=>{this.do_tick()},a)},D.prototype.register_yield=function(){},D.prototype.unregister_yield=function(){};D.prototype.save_state=function(){return this.cpu.save_state()};
|
||||
D.prototype.restore_state=function(a){return this.cpu.restore_state(a)};if("object"===typeof performance&&performance.now)D.microtick=performance.now.bind(performance);else if("function"===typeof require){const {performance:a}=require("perf_hooks");D.microtick=a.now.bind(a)}else D.microtick="object"===typeof process&&process.hrtime?function(){var a=process.hrtime();return 1E3*a[0]+a[1]/1E6}:Date.now;var F=F||{};F.exportSymbol=function(){};F.exportProperty=function(){};var r=r||{};r.pads=function(a,b){return(a||0===a?a+"":"").padEnd(b," ")};r.pad0=function(a,b){return(a||0===a?a+"":"").padStart(b,"0")};r.zeros=function(a){return Array(a).fill(0)};r.range=function(a){return Array.from(Array(a).keys())};
|
||||
r.view=function(a,b,c,d){return new Proxy({},{get:function(e,g){e=new a(b.buffer,c,d);const f=e[g];if("function"===typeof f)return f.bind(e);/^\d+$/.test(g);return f},set:function(e,g,f){/^\d+$/.test(g);(new a(b.buffer,c,d))[g]=f;return!0}})};function A(a,b){a=a?a.toString(16):"";return"0x"+r.pad0(a.toUpperCase(),b||1)}
|
||||
if("undefined"!==typeof crypto&&crypto.getRandomValues){let a=new Int32Array(1);r.get_rand_int=function(){crypto.getRandomValues(a);return a[0]}}else if("undefined"!==typeof require){const a=require("crypto");r.get_rand_int=function(){return a.randomBytes(4).readInt32LE(0)}}
|
||||
(function(){if("function"===typeof Math.clz32)r.int_log2_byte=function(d){return 31-Math.clz32(d)},r.int_log2=function(d){return 31-Math.clz32(d)};else{for(var a=new Int8Array(256),b=0,c=-2;256>b;b++)b&b-1||c++,a[b]=c;r.int_log2_byte=function(d){return a[d]};r.int_log2=function(d){d>>>=0;var e=d>>>16;if(e){var g=e>>>8;return g?24+a[g]:16+a[e]}return(g=d>>>8)?8+a[g]:a[d]}}})();
|
||||
function ka(a){var b=new Uint8Array(a),c,d;this.length=0;this.push=function(e){this.length!==a&&this.length++;b[d]=e;d=d+1&a-1};this.shift=function(){if(this.length){var e=b[c];c=c+1&a-1;this.length--;return e}return-1};this.peek=function(){return this.length?b[c]:-1};this.clear=function(){this.length=d=c=0};this.clear()}function la(a){this.size=a;this.data=new Float32Array(a);this.length=this.end=this.start=0}
|
||||
la.prototype.push=function(a){this.length===this.size?this.start=this.start+1&this.size-1:this.length++;this.data[this.end]=a;this.end=this.end+1&this.size-1};la.prototype.shift=function(){if(this.length){var a=this.data[this.start];this.start=this.start+1&this.size-1;this.length--;return a}};
|
||||
la.prototype.shift_block=function(a){var b=new Float32Array(a);a>this.length&&(a=this.length);var c=this.start+a,d=this.data.subarray(this.start,c);b.set(d);c>=this.size&&(c-=this.size,b.set(this.data.subarray(0,c),d.length));this.start=c;this.length-=a;return b};la.prototype.peek=function(){if(this.length)return this.data[this.start]};la.prototype.clear=function(){this.length=this.end=this.start=0};
|
||||
r.Bitmap=function(a){"number"===typeof a?this.view=new Uint8Array(a+7>>3):a instanceof ArrayBuffer&&(this.view=new Uint8Array(a))};r.Bitmap.prototype.set=function(a,b){const c=a>>3;a=1<<(a&7);this.view[c]=b?this.view[c]|a:this.view[c]&~a};r.Bitmap.prototype.get=function(a){return this.view[a>>3]>>(a&7)&1};r.Bitmap.prototype.get_buffer=function(){return this.view.buffer};r.load_file="undefined"===typeof XMLHttpRequest?ma:na;
|
||||
function na(a,b,c){function d(){const l=c||0;setTimeout(()=>{na(a,b,l+1)},1E3*([1,1,2,3,5,8,13,21][l]||34))}var e=new XMLHttpRequest;e.open(b.method||"get",a,!0);e.responseType=b.as_json?"json":"arraybuffer";if(b.headers)for(var g=Object.keys(b.headers),f=0;f<g.length;f++){var k=g[f];e.setRequestHeader(k,b.headers[k])}b.range&&(g=b.range.start,e.setRequestHeader("Range","bytes="+g+"-"+(g+b.range.length-1)),e.setRequestHeader("X-Accept-Encoding","identity"),e.onreadystatechange=function(){200===e.status&&
|
||||
e.abort()});e.onload=function(){if(4===e.readyState)if(200!==e.status&&206!==e.status)console.error("Loading the image "+a+" failed (status %d)",e.status),500<=e.status&&600>e.status&&d();else if(e.response){if(b.range){let l=e.getResponseHeader("Content-Encoding");l&&"identity"!==l&&console.error("Server sent Content-Encoding in response to ranged request",{filename:a,enc:l})}b.done&&b.done(e.response,e)}};e.onerror=function(l){console.error("Loading the image "+a+" failed",l);d()};b.progress&&(e.onprogress=
|
||||
function(l){b.progress(l)});e.send(null)}function ma(a,b){let c=require("fs");b.range?c.open(a,"r",(d,e)=>{if(d)throw d;d=b.range.length;var g=Buffer.allocUnsafe(d);c.read(e,g,0,d,b.range.start,f=>{if(f)throw f;b.done&&b.done(new Uint8Array(g));c.close(e,k=>{if(k)throw k;})})}):c.readFile(a,{encoding:b.as_json?"utf-8":null},function(d,e){d?console.log("Could not read file:",a,d):(d=e,d=b.as_json?JSON.parse(d):(new Uint8Array(d)).buffer,b.done(d))})}
|
||||
r.read_sized_string_from_mem=function(a,b,c){return String.fromCharCode(...(new Uint8Array(a.buffer,b>>>0,c>>>0)))};(function(){function a(f){this.buffer=f;this.byteLength=f.byteLength;this.onprogress=this.onload=void 0}function b(f,k,l){this.filename=f;this.byteLength=k;this.block_cache=new Map;this.block_cache_is_write=new Set;this.fixed_chunk_size=l;this.cache_reads=!!l;this.onprogress=this.onload=void 0}function c(f,k,l,m,n){const p=f.match(/\.[^\.]+(\.zst)?$/);this.extension=p?p[0]:"";this.basename=f.substring(0,f.length-this.extension.length);this.is_zstd=this.extension.endsWith(".zst");this.basename.endsWith("/")||
|
||||
(this.basename+="-");this.block_cache=new Map;this.block_cache_is_write=new Set;this.byteLength=k;this.fixed_chunk_size=l;this.partfile_alt_format=!!m;this.zstd_decompress=n;this.cache_reads=!!l;this.onprogress=this.onload=void 0}function d(f){this.file=f;this.byteLength=f.size;1073741824<f.size&&console.warn("SyncFileBuffer: Allocating buffer of "+(f.size>>20)+" MB ...");this.buffer=new ArrayBuffer(f.size);this.onprogress=this.onload=void 0}function e(f){this.file=f;this.byteLength=f.size;this.block_cache=
|
||||
new Map;this.block_cache_is_write=new Set;this.onprogress=this.onload=void 0}r.SyncBuffer=a;r.AsyncXHRBuffer=b;r.AsyncXHRPartfileBuffer=c;r.AsyncFileBuffer=e;r.SyncFileBuffer=d;r.buffer_from_object=function(f,k){if(f.buffer instanceof ArrayBuffer)return new r.SyncBuffer(f.buffer);if("undefined"!==typeof File&&f.buffer instanceof File)return k=f.async,void 0===k&&(k=268435456<=f.buffer.size),k?new r.AsyncFileBuffer(f.buffer):new r.SyncFileBuffer(f.buffer);if(f.url)return f.use_parts?new r.AsyncXHRPartfileBuffer(f.url,
|
||||
f.size,f.fixed_chunk_size,!1,k):new r.AsyncXHRBuffer(f.url,f.size,f.fixed_chunk_size)};a.prototype.load=function(){this.onload&&this.onload({buffer:this.buffer})};a.prototype.get=function(f,k,l){l(new Uint8Array(this.buffer,f,k))};a.prototype.set=function(f,k,l){(new Uint8Array(this.buffer,f,k.byteLength)).set(k);l()};a.prototype.get_buffer=function(f){f(this.buffer)};a.prototype.get_state=function(){const f=[];f[0]=this.byteLength;f[1]=new Uint8Array(this.buffer);return f};a.prototype.set_state=
|
||||
function(f){this.byteLength=f[0];this.buffer=f[1].slice().buffer};b.prototype.load=function(){void 0!==this.byteLength?this.onload&&this.onload(Object.create(null)):g(this.filename,(f,k)=>{if(f)throw Error("Cannot use: "+this.filename+". "+f);this.byteLength=k;this.onload&&this.onload(Object.create(null))})};b.prototype.get_from_cache=function(f,k){var l=k/256;f/=256;for(var m=0;m<l;m++)if(!this.block_cache.get(f+m))return;if(1===l)return this.block_cache.get(f);k=new Uint8Array(k);for(m=0;m<l;m++)k.set(this.block_cache.get(f+
|
||||
m),256*m);return k};b.prototype.get=function(f,k,l){var m=this.get_from_cache(f,k);if(m)l(m);else{var n=f,p=k;this.fixed_chunk_size&&(n=f-f%this.fixed_chunk_size,p=Math.ceil((f-n+k)/this.fixed_chunk_size)*this.fixed_chunk_size);r.load_file(this.filename,{done:function(t){t=new Uint8Array(t);this.handle_read(n,p,t);n===f&&p===k?l(t):l(t.subarray(f-n,f-n+k))}.bind(this),range:{start:n,length:p}})}};b.prototype.set=function(f,k,l){f/=256;for(var m=k.length/256,n=0;n<m;n++){var p=this.block_cache.get(f+
|
||||
n);if(void 0===p)p=k.slice(256*n,256*(n+1)),this.block_cache.set(f+n,p);else{const t=k.subarray(256*n,256*(n+1));p.set(t)}this.block_cache_is_write.add(f+n)}l()};b.prototype.handle_read=function(f,k,l){f/=256;k/=256;for(var m=0;m<k;m++){const n=this.block_cache.get(f+m);n?l.set(n,256*m):this.cache_reads&&this.block_cache.set(f+m,l.slice(256*m,256*(m+1)))}};b.prototype.get_buffer=function(f){f()};b.prototype.get_state=function(){const f=[],k=[];for(let [l,m]of this.block_cache)isFinite(l),this.block_cache_is_write.has(l)&&
|
||||
k.push([l,m]);f[0]=k;return f};b.prototype.set_state=function(f){f=f[0];this.block_cache.clear();this.block_cache_is_write.clear();for(let [k,l]of f)isFinite(k),this.block_cache.set(k,l),this.block_cache_is_write.add(k)};c.prototype.load=function(){this.onload&&this.onload(Object.create(null))};c.prototype.get=function(f,k,l){var m=this.get_from_cache(f,k);if(m)l(m);else if(this.fixed_chunk_size){const p=Math.floor(f/this.fixed_chunk_size),t=f-p*this.fixed_chunk_size,q=Math.ceil((t+k)/this.fixed_chunk_size),
|
||||
z=new Uint8Array(q*this.fixed_chunk_size);let w=0;for(let u=0;u<q;u++){var n=(p+u)*this.fixed_chunk_size;m=this.partfile_alt_format?this.basename+(p+u+"").padStart(8,"0")+this.extension:this.basename+n+"-"+(n+this.fixed_chunk_size)+this.extension;(n=this.get_from_cache(n,this.fixed_chunk_size))?(z.set(n,u*this.fixed_chunk_size),w++,w===q&&l(z.subarray(t,t+k))):r.load_file(m,{done:async function(I){I=new Uint8Array(I);this.is_zstd&&(I=await this.zstd_decompress(this.fixed_chunk_size,I),I=new Uint8Array(I));
|
||||
z.set(I,u*this.fixed_chunk_size);this.handle_read((p+u)*this.fixed_chunk_size,this.fixed_chunk_size|0,I);w++;w===q&&l(z.subarray(t,t+k))}.bind(this)})}}else r.load_file(this.basename+f+"-"+(f+k)+this.extension,{done:function(p){p=new Uint8Array(p);this.handle_read(f,k,p);l(p)}.bind(this)})};c.prototype.get_from_cache=b.prototype.get_from_cache;c.prototype.set=b.prototype.set;c.prototype.handle_read=b.prototype.handle_read;c.prototype.get_state=b.prototype.get_state;c.prototype.set_state=b.prototype.set_state;
|
||||
d.prototype.load=function(){this.load_next(0)};d.prototype.load_next=function(f){var k=new FileReader;k.onload=function(m){m=new Uint8Array(m.target.result);(new Uint8Array(this.buffer,f)).set(m);this.load_next(f+4194304)}.bind(this);if(this.onprogress)this.onprogress({loaded:f,total:this.byteLength,lengthComputable:!0});if(f<this.byteLength){var l=this.file.slice(f,Math.min(f+4194304,this.byteLength));k.readAsArrayBuffer(l)}else this.file=void 0,this.onload&&this.onload({buffer:this.buffer})};d.prototype.get=
|
||||
a.prototype.get;d.prototype.set=a.prototype.set;d.prototype.get_buffer=a.prototype.get_buffer;d.prototype.get_state=a.prototype.get_state;d.prototype.set_state=a.prototype.set_state;e.prototype.load=function(){this.onload&&this.onload(Object.create(null))};e.prototype.get=function(f,k,l){var m=this.get_from_cache(f,k);m?l(m):(m=new FileReader,m.onload=function(n){n=new Uint8Array(n.target.result);this.handle_read(f,k,n);l(n)}.bind(this),m.readAsArrayBuffer(this.file.slice(f,f+k)))};e.prototype.get_from_cache=
|
||||
b.prototype.get_from_cache;e.prototype.set=b.prototype.set;e.prototype.handle_read=b.prototype.handle_read;e.prototype.get_state=b.prototype.get_state;e.prototype.set_state=b.prototype.set_state;e.prototype.get_buffer=function(f){f()};e.prototype.get_as_file=function(f){for(var k=[],l=Array.from(this.block_cache.keys()).sort(function(q,z){return q-z}),m=0,n=0;n<l.length;n++){var p=l[n],t=this.block_cache.get(p);p*=256;p!==m&&(k.push(this.file.slice(m,p)),m=p);k.push(t);m+=t.length}m!==this.file.size&&
|
||||
k.push(this.file.slice(m));return new File(k,f)};var g="undefined"===typeof XMLHttpRequest?function(f,k){require("fs").stat(f,(l,m)=>{l?k(l):k(null,m.size)})}:function(f,k){r.load_file(f,{done:(l,m)=>{l=m.getResponseHeader("Content-Range")||"";(m=l.match(/\/(\d+)\s*$/))?k(null,+m[1]):k("`Range: bytes=...` header not supported (Got `"+l+"`)")},headers:{Range:"bytes=0-0","X-Accept-Encoding":"identity"}})}})();function G(a,b,c,d,e,g){this.master=new H(this,a,b,d,e,0,g);this.slave=new H(this,a,c,!1,e,1,g);this.current_interface=this.master;this.cpu=a;0===e?(this.ata_port=496,this.irq=14,this.pci_id=240):1===e&&(this.ata_port=368,this.irq=15,this.pci_id=248);this.ata_port_high=this.ata_port|516;this.master_port=46080;this.pci_space=[134,128,16,112,5,0,160,2,0,128,1,1,0,0,0,0,this.ata_port&255|1,this.ata_port>>8,0,0,this.ata_port_high&255|1,this.ata_port_high>>8,0,0,0,0,0,0,0,0,0,0,this.master_port&255|1,
|
||||
this.master_port>>8,0,0,0,0,0,0,0,0,0,0,67,16,212,130,0,0,0,0,0,0,0,0,0,0,0,0,this.irq,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];this.pci_bars=[{size:8},{size:4},void 0,void 0,{size:16}];this.name="ide"+e;this.device_control=2;a.io.register_read(this.ata_port|7,this,function(){this.cpu.device_lower_irq(this.irq);return this.read_status()});a.io.register_read(this.ata_port_high|
|
||||
2,this,this.read_status);a.io.register_write(this.ata_port_high|2,this,this.write_control);a.io.register_read(this.ata_port|0,this,function(){return this.current_interface.read_data(1)},function(){return this.current_interface.read_data(2)},function(){return this.current_interface.read_data(4)});a.io.register_read(this.ata_port|1,this,function(){A(this.current_interface.error&255);return this.current_interface.error&255});a.io.register_read(this.ata_port|2,this,function(){A(this.current_interface.bytecount&
|
||||
255);return this.current_interface.bytecount&255});a.io.register_read(this.ata_port|3,this,function(){A(this.current_interface.sector&255);return this.current_interface.sector&255});a.io.register_read(this.ata_port|4,this,function(){A(this.current_interface.cylinder_low&255);return this.current_interface.cylinder_low&255});a.io.register_read(this.ata_port|5,this,function(){A(this.current_interface.cylinder_high&255);return this.current_interface.cylinder_high&255});a.io.register_read(this.ata_port|
|
||||
6,this,function(){return this.current_interface.drive_head&255});a.io.register_write(this.ata_port|0,this,function(f){this.current_interface.write_data_port8(f)},function(f){this.current_interface.write_data_port16(f)},function(f){this.current_interface.write_data_port32(f)});a.io.register_write(this.ata_port|1,this,function(f){A(f);this.master.lba_count=(this.master.lba_count<<8|f)&65535;this.slave.lba_count=(this.slave.lba_count<<8|f)&65535});a.io.register_write(this.ata_port|2,this,function(f){A(f);
|
||||
this.master.bytecount=(this.master.bytecount<<8|f)&65535;this.slave.bytecount=(this.slave.bytecount<<8|f)&65535});a.io.register_write(this.ata_port|3,this,function(f){A(f);this.master.sector=(this.master.sector<<8|f)&65535;this.slave.sector=(this.slave.sector<<8|f)&65535});a.io.register_write(this.ata_port|4,this,function(f){A(f);this.master.cylinder_low=(this.master.cylinder_low<<8|f)&65535;this.slave.cylinder_low=(this.slave.cylinder_low<<8|f)&65535});a.io.register_write(this.ata_port|5,this,function(f){A(f);
|
||||
this.master.cylinder_high=(this.master.cylinder_high<<8|f)&65535;this.slave.cylinder_high=(this.slave.cylinder_high<<8|f)&65535});a.io.register_write(this.ata_port|6,this,function(f){var k=f&16;A(f,2);this.current_interface=k?this.slave:this.master;this.master.drive_head=f;this.slave.drive_head=f;this.master.is_lba=this.slave.is_lba=f>>6&1;this.master.head=this.slave.head=f&15});this.dma_command=this.dma_status=this.prdt_addr=0;a.io.register_write(this.ata_port|7,this,function(f){this.cpu.device_lower_irq(this.irq);
|
||||
this.current_interface.ata_command(f)});a.io.register_read(this.master_port|4,this,void 0,void 0,this.dma_read_addr);a.io.register_write(this.master_port|4,this,void 0,void 0,this.dma_set_addr);a.io.register_read(this.master_port,this,this.dma_read_command8,void 0,this.dma_read_command);a.io.register_write(this.master_port,this,this.dma_write_command8,void 0,this.dma_write_command);a.io.register_read(this.master_port|2,this,this.dma_read_status);a.io.register_write(this.master_port|2,this,this.dma_write_status);
|
||||
a.io.register_read(this.master_port|8,this,function(){return 0});a.io.register_read(this.master_port|10,this,function(){return 0});a.devices.pci.register_device(this)}G.prototype.read_status=function(){if(this.current_interface.buffer){var a=this.current_interface.status;A(a,2);return a}return 0};G.prototype.write_control=function(a){A(a,2);a&4&&(this.cpu.device_lower_irq(this.irq),this.master.device_reset(),this.slave.device_reset());this.device_control=a};
|
||||
G.prototype.dma_read_addr=function(){A(this.prdt_addr,8);return this.prdt_addr};G.prototype.dma_set_addr=function(a){A(a,8);this.prdt_addr=a};G.prototype.dma_read_status=function(){A(this.dma_status);return this.dma_status};G.prototype.dma_write_status=function(a){A(a);this.dma_status&=~(a&6)};G.prototype.dma_read_command=function(){return this.dma_read_command8()|this.dma_read_status()<<16};G.prototype.dma_read_command8=function(){A(this.dma_command);return this.dma_command};
|
||||
G.prototype.dma_write_command=function(a){A(a);this.dma_write_command8(a&255);this.dma_write_status(a>>16&255)};
|
||||
G.prototype.dma_write_command8=function(a){A(a);let b=this.dma_command;this.dma_command=a&9;if((b&1)!==(a&1))if(0===(a&1))this.dma_status&=-2;else switch(this.dma_status|=1,this.current_interface.current_command){case 37:case 200:this.current_interface.do_ata_read_sectors_dma();break;case 202:case 53:this.current_interface.do_ata_write_sectors_dma();break;case 160:this.current_interface.do_atapi_dma();break;default:A(this.current_interface.current_command)}};
|
||||
G.prototype.push_irq=function(){0===(this.device_control&2)&&(this.dma_status|=4,this.cpu.device_raise_irq(this.irq))};G.prototype.get_state=function(){var a=[];a[0]=this.master;a[1]=this.slave;a[2]=this.ata_port;a[3]=this.irq;a[4]=this.pci_id;a[5]=this.ata_port_high;a[6]=this.master_port;a[7]=this.name;a[8]=this.device_control;a[9]=this.prdt_addr;a[10]=this.dma_status;a[11]=this.current_interface===this.master;a[12]=this.dma_command;return a};
|
||||
G.prototype.set_state=function(a){this.master.set_state(a[0]);this.slave.set_state(a[1]);this.ata_port=a[2];this.irq=a[3];this.pci_id=a[4];this.ata_port_high=a[5];this.master_port=a[6];this.name=a[7];this.device_control=a[8];this.prdt_addr=a[9];this.dma_status=a[10];this.current_interface=a[11]?this.master:this.slave;this.dma_command=a[12]};
|
||||
function H(a,b,c,d,e,g,f){this.device=a;this.bus=f;this.nr=e;this.cpu=b;this.buffer=c;this.sector_size=d?2048:512;this.is_atapi=d;this.cylinder_count=this.sectors_per_track=this.head_count=this.sector_count=0;this.buffer&&(this.sector_count=this.buffer.byteLength/this.sector_size,this.sector_count!==(this.sector_count|0)&&(this.sector_count=Math.ceil(this.sector_count)),d?(this.head_count=1,this.sectors_per_track=0):(this.head_count=16,this.sectors_per_track=63),this.cylinder_count=this.sector_count/
|
||||
this.head_count/this.sectors_per_track,this.cylinder_count!==(this.cylinder_count|0)&&(this.cylinder_count=Math.floor(this.cylinder_count)),a=b.devices.rtc,a.cmos_write(57,a.cmos_read(57)|1<<4*this.nr),a.cmos_write(18,a.cmos_read(18)&15|240),a.cmos_write(27,this.cylinder_count&255),a.cmos_write(28,this.cylinder_count>>8&255),a.cmos_write(29,this.head_count&255),a.cmos_write(30,255),a.cmos_write(31,255),a.cmos_write(32,200),a.cmos_write(33,this.cylinder_count&255),a.cmos_write(34,this.cylinder_count>>
|
||||
8&255),a.cmos_write(35,this.sectors_per_track&255));this.stats={sectors_read:0,sectors_written:0,bytes_read:0,bytes_written:0,loading:!1};this.buffer=c;this.drive_head=this.head=this.cylinder_high=this.cylinder_low=this.lba_count=this.sector=this.bytecount=this.is_lba=0;this.status=80;this.sectors_per_drq=128;this.data_pointer=this.error=0;this.data=new Uint8Array(65536);this.data16=new Uint16Array(this.data.buffer);this.data32=new Int32Array(this.data.buffer);this.data_end=this.data_length=0;this.current_atapi_command=
|
||||
this.current_command=-1;this.last_io_id=this.write_dest=0;this.in_progress_io_ids=new Set;this.cancelled_io_ids=new Set;Object.seal(this)}H.prototype.device_reset=function(){this.is_atapi?(this.status=0,this.sector=this.error=this.bytecount=1,this.cylinder_low=20,this.cylinder_high=235):(this.status=81,this.sector=this.error=this.bytecount=1,this.cylinder_high=this.cylinder_low=0);this.cancel_io_operations()};H.prototype.push_irq=function(){this.device.push_irq()};
|
||||
H.prototype.ata_command=function(a){A(a);if(this.buffer)switch(this.current_command=a,this.error=0,a){case 8:this.data_length=this.data_end=this.data_pointer=0;this.device_reset();this.push_irq();break;case 16:this.status=80;this.cylinder_low=0;this.push_irq();break;case 248:this.status=80;a=this.sector_count-1;this.sector=a&255;this.cylinder_low=a>>8&255;this.cylinder_high=a>>16&255;this.drive_head=this.drive_head&240|a>>24&15;this.push_irq();break;case 39:this.status=80;a=this.sector_count-1;this.sector=
|
||||
a&255;this.cylinder_low=a>>8&255;this.cylinder_high=a>>16&255;this.sector|=a>>24<<8&65280;this.push_irq();break;case 32:case 36:case 41:case 196:this.ata_read_sectors(a);break;case 48:case 52:case 57:case 197:this.ata_write_sectors(a);break;case 144:this.push_irq();this.error=257;this.status=80;break;case 145:this.status=80;this.push_irq();break;case 160:this.is_atapi&&(this.status=88,this.data_allocate(12),this.data_end=12,this.bytecount=1,this.push_irq());break;case 161:this.is_atapi?(this.create_identify_packet(),
|
||||
this.status=88,this.cylinder_low=20,this.cylinder_high=235):this.status=65;this.push_irq();break;case 198:A(this.bytecount&255);this.sectors_per_drq=this.bytecount&255;this.status=80;this.push_irq();break;case 37:case 200:this.ata_read_sectors_dma(a);break;case 53:case 202:this.ata_write_sectors_dma(a);break;case 64:this.status=80;this.push_irq();break;case 218:this.status=65;this.error=4;this.push_irq();break;case 224:this.status=80;this.push_irq();break;case 225:this.status=80;this.push_irq();break;
|
||||
case 231:this.status=80;this.push_irq();break;case 236:if(this.is_atapi){this.status=65;this.error=4;this.push_irq();break}this.create_identify_packet();this.status=88;this.push_irq();break;case 234:this.status=80;this.push_irq();break;case 239:A(this.bytecount&255);this.status=80;this.push_irq();break;case 222:this.status=80;this.push_irq();break;case 245:this.status=80;this.push_irq();break;case 249:this.status=65;this.error=4;break;default:A(a),this.status=65,this.error=4}else this.error=4,this.status=
|
||||
65,this.push_irq()};
|
||||
H.prototype.atapi_handle=function(){A(this.data[0]);this.data_pointer=0;this.current_atapi_command=this.data[0];switch(this.current_atapi_command){case 0:this.data_allocate(0);this.data_end=this.data_length;this.status=80;break;case 3:this.data_allocate(this.data[4]);this.data_end=this.data_length;this.status=88;this.data[0]=240;this.data[2]=5;this.data[7]=8;break;case 18:var a=this.data[4];this.status=88;A(this.data[1],2);this.data.set([5,128,1,49,31,0,0,0,83,79,78,89,32,32,32,32,67,68,45,82,79,
|
||||
77,32,67,68,85,45,49,48,48,48,32,49,46,49,97]);this.data_end=this.data_length=Math.min(36,a);break;case 26:this.data_allocate(this.data[4]);this.data_end=this.data_length;this.status=88;break;case 30:this.data_allocate(0);this.data_end=this.data_length;this.status=80;break;case 37:a=this.sector_count-1;this.data_set(new Uint8Array([a>>24&255,a>>16&255,a>>8&255,a&255,0,0,this.sector_size>>8&255,this.sector_size&255]));this.data_end=this.data_length;this.status=88;break;case 40:this.lba_count&1?this.atapi_read_dma(this.data):
|
||||
this.atapi_read(this.data);break;case 66:a=this.data[8];this.data_allocate(Math.min(8,a));this.data_end=this.data_length;this.status=88;break;case 67:a=this.data[8]|this.data[7]<<8;var b=this.data[9]>>6;this.data_allocate(a);this.data_end=this.data_length;A(b,2);A(this.data[6]);0===b?(a=this.sector_count,this.data.set(new Uint8Array([0,18,1,1,0,20,1,0,0,0,0,0,0,22,170,0,a>>24,a>>16&255,a>>8&255,a&255]))):1===b&&this.data.set(new Uint8Array([0,10,1,1,0,0,0,0,0,0,0,0]));this.status=88;break;case 70:a=
|
||||
this.data[8]|this.data[7]<<8;a=Math.min(a,32);this.data_allocate(a);this.data_end=this.data_length;this.data[0]=a-4>>24&255;this.data[1]=a-4>>16&255;this.data[2]=a-4>>8&255;this.data[3]=a-4&255;this.data[6]=8;this.data[10]=3;this.status=88;break;case 81:this.data_allocate(0);this.data_end=this.data_length;this.status=80;break;case 82:A(this.data[0]);this.status=81;this.data_length=0;this.error=80;break;case 90:a=this.data[8]|this.data[7]<<8;b=this.data[2];A(b);42===b&&this.data_allocate(Math.min(30,
|
||||
a));this.data_end=this.data_length;this.status=88;break;case 189:this.data_allocate(this.data[9]|this.data[8]<<8);this.data_end=this.data_length;this.data[5]=1;this.status=88;break;case 74:this.status=81;this.data_length=0;this.error=80;A(this.data[0]);break;case 190:A(this.data[0]);this.data_allocate(0);this.data_end=this.data_length;this.status=80;break;default:this.status=81,this.data_length=0,this.error=80,A(this.data[0])}this.bytecount=this.bytecount&-8|2;0===(this.status&128)&&this.push_irq();
|
||||
0===(this.status&128)&&0===this.data_length&&(this.bytecount|=1,this.status&=-9)};H.prototype.do_write=function(){this.status=80;var a=this.data.subarray(0,this.data_length);this.ata_advance(this.current_command,this.data_length/512);this.push_irq();this.buffer.set(this.write_dest,a,function(){});this.report_write(this.data_length)};
|
||||
H.prototype.atapi_read=function(a){var b=a[2]<<24|a[3]<<16|a[4]<<8|a[5],c=a[7]<<8|a[8];a=a[1];var d=c*this.sector_size,e=b*this.sector_size;J("CD read lba="+A(b)+" lbacount="+A(c)+" bytecount="+A(d)+" flags="+A(a),32768);this.data_length=0;var g=this.cylinder_high<<8&65280|this.cylinder_low&255;J(A(this.cylinder_high,2)+" "+A(this.cylinder_low,2),32768);this.cylinder_low=this.cylinder_high=0;65535===g&&g--;g>d&&(g=d);e>=this.buffer.byteLength?(oa(!1,"CD read: Outside of disk end="+A(e+d)+" size="+
|
||||
A(this.buffer.byteLength),32768),this.status=255,this.push_irq()):0===d?(this.status=80,this.data_pointer=0):(d=Math.min(d,this.buffer.byteLength-e),this.status=208,this.report_read_start(),this.read_buffer(e,d,f=>{this.data_set(f);this.status=88;this.bytecount=this.bytecount&-8|2;this.push_irq();this.data_end=g&=-4;this.data_end>this.data_length&&(this.data_end=this.data_length);this.cylinder_low=this.data_end&255;this.cylinder_high=this.data_end>>8&255;this.report_read_end(d)}))};
|
||||
H.prototype.atapi_read_dma=function(a){var b=a[2]<<24|a[3]<<16|a[4]<<8|a[5],c=a[7]<<8|a[8];a=a[1];var d=c*this.sector_size,e=b*this.sector_size;J("CD read DMA lba="+A(b)+" lbacount="+A(c)+" bytecount="+A(d)+" flags="+A(a),32768);e>=this.buffer.byteLength?(oa(!1,"CD read: Outside of disk end="+A(e+d)+" size="+A(this.buffer.byteLength),32768),this.status=255,this.push_irq()):(this.status=208,this.report_read_start(),this.read_buffer(e,d,g=>{this.report_read_end(d);this.status=88;this.bytecount=this.bytecount&
|
||||
-8|2;this.data_set(g);this.do_atapi_dma()}))};
|
||||
H.prototype.do_atapi_dma=function(){if(0!==(this.device.dma_status&1)&&0!==(this.status&8)){var a=this.device.prdt_addr,b=0,c=this.data;do{var d=this.cpu.read32s(a),e=this.cpu.read16(a+4),g=this.cpu.read8(a+7)&128;e||(e=65536);A(d);A(e);A(this.data_length);this.cpu.write_blob(c.subarray(b,Math.min(b+e,this.data_length)),d);b+=e;a+=8;if(b>=this.data_length&&!g){A(b);A(this.data_length);A(this.current_command);break}}while(!g);this.status=80;this.device.dma_status&=-2;this.bytecount=this.bytecount&
|
||||
-8|3;this.push_irq()}};H.prototype.read_data=function(a){if(this.data_pointer<this.data_end){A(this.data_pointer);var b=1===a?this.data[this.data_pointer]:2===a?this.data16[this.data_pointer>>>1]:this.data32[this.data_pointer>>>2];this.data_pointer+=a;0===(this.data_pointer&(0===(this.data_end&4095)?4095:255))&&(A(this.data[this.data_pointer],2),A(this.data_pointer),A(this.data_length));this.data_pointer>=this.data_end&&this.read_end();return b}this.data_pointer+=a;return 0};
|
||||
H.prototype.read_end=function(){A(this.current_command);A(this.data_pointer);A(this.data_end);A(this.data_length);if(160===this.current_command)if(this.data_end===this.data_length)this.status=80,this.bytecount=this.bytecount&-8|3,this.push_irq();else{this.status=88;this.bytecount=this.bytecount&-8|2;this.push_irq();var a=this.cylinder_high<<8&65280|this.cylinder_low&255;this.data_end+a>this.data_length?(this.cylinder_low=this.data_length-this.data_end&255,this.cylinder_high=this.data_length-this.data_end>>
|
||||
8&255,this.data_end=this.data_length):this.data_end+=a;A(this.data_end)}else this.error=0,this.data_pointer>=this.data_length?this.status=80:(a=196===this.current_command||41===this.current_command?Math.min(this.sectors_per_drq,(this.data_length-this.data_end)/512):1,this.ata_advance(this.current_command,a),this.data_end+=512*a,this.status=88,this.push_irq())};
|
||||
H.prototype.write_data_port=function(a,b){if(this.data_pointer>=this.data_end)A(a),A(this.data_end),A(this.data_pointer);else{if(0===(this.data_pointer+b&(0===(this.data_end&4095)?4095:255))||20>this.data_end)A(a>>>0),A(this.data_end),A(this.data_pointer);1===b?this.data[this.data_pointer++]=a:2===b?(this.data16[this.data_pointer>>>1]=a,this.data_pointer+=2):(this.data32[this.data_pointer>>>2]=a,this.data_pointer+=4);this.data_pointer===this.data_end&&this.write_end()}};
|
||||
H.prototype.write_data_port8=function(a){this.write_data_port(a,1)};H.prototype.write_data_port16=function(a){this.write_data_port(a,2)};H.prototype.write_data_port32=function(a){this.write_data_port(a,4)};H.prototype.write_end=function(){160===this.current_command?this.atapi_handle():(A(this.data_pointer),A(this.data_length),this.data_pointer>=this.data_length?this.do_write():(A(this.current_command),this.status=88,this.data_end+=512,this.push_irq()))};
|
||||
H.prototype.ata_advance=function(a,b){this.bytecount-=b;36===a||41===a||52===a||57===a||37===a||53===a?(a=b+this.get_lba48(),this.sector=a&255|a>>16&65280,this.cylinder_low=a>>8&255,this.cylinder_high=a>>16&255):this.is_lba?(a=b+this.get_lba28(),this.sector=a&255,this.cylinder_low=a>>8&255,this.cylinder_high=a>>16&255,this.head=this.head&-16|a&15):(a=b+this.get_chs(),b=a/(this.head_count*this.sectors_per_track)|0,this.cylinder_low=b&255,this.cylinder_high=b>>8&255,this.head=(a/this.sectors_per_track|
|
||||
0)%this.head_count&15,this.sector=a%this.sectors_per_track+1&255,this.get_chs())};
|
||||
H.prototype.ata_read_sectors=function(a){var b=36===a||41===a,c=this.get_count(b);b=this.get_lba(b);var d=32===a||36===a,e=c*this.sector_size,g=b*this.sector_size;J("ATA read cmd="+A(a)+" mode="+(this.is_lba?"lba":"chs")+" lba="+A(b)+" lbacount="+A(c)+" bytecount="+A(e),32768);g+e>this.buffer.byteLength?(this.status=255,this.push_irq()):(this.status=192,this.report_read_start(),this.read_buffer(g,e,f=>{this.data_set(f);this.status=88;this.data_end=d?512:Math.min(e,512*this.sectors_per_drq);this.ata_advance(a,
|
||||
d?1:Math.min(c,this.sectors_per_track));this.push_irq();this.report_read_end(e)}))};H.prototype.ata_read_sectors_dma=function(a){var b=37===a;a=this.get_count(b);b=this.get_lba(b);var c=a*this.sector_size,d=b*this.sector_size;A(b);A(a);A(c);d+c>this.buffer.byteLength?(this.status=255,this.push_irq()):(this.status=88,this.device.dma_status|=1)};
|
||||
H.prototype.do_ata_read_sectors_dma=function(){var a=37===this.current_command,b=this.get_count(a);a=this.get_lba(a);var c=b*this.sector_size;a*=this.sector_size;this.report_read_start();this.read_buffer(a,c,d=>{var e=this.device.prdt_addr,g=0;do{var f=this.cpu.read32s(e),k=this.cpu.read16(e+4),l=this.cpu.read8(e+7)&128;k||(k=65536);A(f);A(k);this.cpu.write_blob(d.subarray(g,g+k),f);g+=k;e+=8}while(!l);this.ata_advance(this.current_command,b);this.status=80;this.device.dma_status&=-2;this.current_command=
|
||||
-1;this.push_irq();this.report_read_end(c)})};H.prototype.ata_write_sectors=function(a){var b=52===a||57===a,c=this.get_count(b);b=this.get_lba(b);a=48===a||52===a;var d=c*this.sector_size,e=b*this.sector_size;A(b);A(c);A(d);e+d>this.buffer.byteLength?(this.status=255,this.push_irq()):(this.status=88,this.data_allocate_noclear(d),this.data_end=a?512:Math.min(d,512*this.sectors_per_drq),this.write_dest=e)};
|
||||
H.prototype.ata_write_sectors_dma=function(a){var b=53===a;a=this.get_count(b);b=this.get_lba(b);var c=a*this.sector_size,d=b*this.sector_size;A(b);A(a);A(c);d+c>this.buffer.byteLength?(this.status=255,this.push_irq()):(this.status=88,this.device.dma_status|=1)};
|
||||
H.prototype.do_ata_write_sectors_dma=function(){var a=53===this.current_command,b=this.get_count(a),c=this.get_lba(a);a=b*this.sector_size;c*=this.sector_size;var d=this.device.prdt_addr,e=0;J("prdt addr: "+A(d,8),32768);const g=new Uint8Array(a);do{var f=this.cpu.read32s(d),k=this.cpu.read16(d+4),l=this.cpu.read8(d+7)&128;k||(k=65536);J("dma write transfer dest="+A(f)+" prd_count="+A(k),32768);f=this.cpu.mem8.subarray(f,f+k);g.set(f,e);e+=k;d+=8}while(!l);this.buffer.set(c,g,()=>{this.ata_advance(this.current_command,
|
||||
b);this.status=80;this.push_irq();this.device.dma_status&=-2;this.current_command=-1});this.report_write(a)};H.prototype.get_chs=function(){return((this.cylinder_low&255|this.cylinder_high<<8&65280)*this.head_count+this.head)*this.sectors_per_track+(this.sector&255)-1};H.prototype.get_lba28=function(){return this.sector&255|this.cylinder_low<<8&65280|this.cylinder_high<<16&16711680|(this.head&15)<<24};
|
||||
H.prototype.get_lba48=function(){return(this.sector&255|this.cylinder_low<<8&65280|this.cylinder_high<<16&16711680|this.sector>>8<<24&4278190080)>>>0};H.prototype.get_lba=function(a){return a?this.get_lba48():this.is_lba?this.get_lba28():this.get_chs()};H.prototype.get_count=function(a){a?(a=this.bytecount,0===a&&(a=65536)):(a=this.bytecount&255,0===a&&(a=256));return a};
|
||||
H.prototype.create_identify_packet=function(){if(this.drive_head&16)this.data_allocate(0);else{for(var a=0;512>a;a++)this.data[a]=0;a=Math.min(16383,this.cylinder_count);this.data_set([64,this.is_atapi?133:0,a,a>>8,0,0,this.head_count,this.head_count>>8,this.sectors_per_track/512,this.sectors_per_track/512>>8,0,2,this.sectors_per_track,this.sectors_per_track>>8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,2,4,0,0,0,0,0,0,0,0,0,56,118,32,54,68,72,32,32,32,32,32,32,32,32,32,32,32,32,32,
|
||||
32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,128,0,1,0,0,2,0,0,0,2,0,2,7,0,a,a>>8,this.head_count,this.head_count>>8,this.sectors_per_track,0,this.sector_count&255,this.sector_count>>8&255,this.sector_count>>16&255,this.sector_count>>24&255,0,0,this.sector_count&255,this.sector_count>>8&255,this.sector_count>>16&255,this.sector_count>>24&255,0,0,160===this.current_command?0:7,160===this.current_command?0:4,0,0,30,0,30,0,30,0,30,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,126,0,
|
||||
0,0,0,0,0,116,0,64,0,64,0,116,0,64,0,0,0,0,0,0,0,0,0,0,1,96,0,0,0,0,0,0,0,0,0,0,0,0,this.sector_count&255,this.sector_count>>8&255,this.sector_count>>16&255,this.sector_count>>24&255]);this.data_end=this.data_length=512}};H.prototype.data_allocate=function(a){this.data_allocate_noclear(a);for(var b=0;b<a+3>>2;b++)this.data32[b]=0};
|
||||
H.prototype.data_allocate_noclear=function(a){this.data.length<a&&(this.data=new Uint8Array(a+3&-4),this.data16=new Uint16Array(this.data.buffer),this.data32=new Int32Array(this.data.buffer));this.data_length=a;this.data_pointer=0};H.prototype.data_set=function(a){this.data_allocate_noclear(a.length);this.data.set(a)};H.prototype.report_read_start=function(){this.stats.loading=!0;this.bus.send("ide-read-start")};
|
||||
H.prototype.report_read_end=function(a){this.stats.loading=!1;var b=a/this.sector_size|0;this.stats.sectors_read+=b;this.stats.bytes_read+=a;this.bus.send("ide-read-end",[this.nr,a,b])};H.prototype.report_write=function(a){var b=a/this.sector_size|0;this.stats.sectors_written+=b;this.stats.bytes_written+=a;this.bus.send("ide-write-end",[this.nr,a,b])};
|
||||
H.prototype.read_buffer=function(a,b,c){const d=this.last_io_id++;this.in_progress_io_ids.add(d);this.buffer.get(a,b,e=>{this.cancelled_io_ids.delete(d)?this.in_progress_io_ids.has(d):(this.in_progress_io_ids.delete(d),c(e))})};H.prototype.cancel_io_operations=function(){for(const a of this.in_progress_io_ids)this.cancelled_io_ids.add(a);this.in_progress_io_ids.clear()};
|
||||
H.prototype.get_state=function(){var a=[];a[0]=this.bytecount;a[1]=this.cylinder_count;a[2]=this.cylinder_high;a[3]=this.cylinder_low;a[4]=this.data_pointer;a[5]=0;a[6]=0;a[7]=0;a[8]=0;a[9]=this.drive_head;a[10]=this.error;a[11]=this.head;a[12]=this.head_count;a[13]=this.is_atapi;a[14]=this.is_lba;a[15]=this.lba_count;a[16]=this.data;a[17]=this.data_length;a[18]=this.sector;a[19]=this.sector_count;a[20]=this.sector_size;a[21]=this.sectors_per_drq;a[22]=this.sectors_per_track;a[23]=this.status;a[24]=
|
||||
this.write_dest;a[25]=this.current_command;a[26]=this.data_end;a[27]=this.current_atapi_command;a[28]=this.buffer;return a};
|
||||
H.prototype.set_state=function(a){this.bytecount=a[0];this.cylinder_count=a[1];this.cylinder_high=a[2];this.cylinder_low=a[3];this.data_pointer=a[4];this.drive_head=a[9];this.error=a[10];this.head=a[11];this.head_count=a[12];this.is_atapi=a[13];this.is_lba=a[14];this.lba_count=a[15];this.data=a[16];this.data_length=a[17];this.sector=a[18];this.sector_count=a[19];this.sector_size=a[20];this.sectors_per_drq=a[21];this.sectors_per_track=a[22];this.status=a[23];this.write_dest=a[24];this.current_command=
|
||||
a[25];this.data_end=a[26];this.current_atapi_command=a[27];this.data16=new Uint16Array(this.data.buffer);this.data32=new Int32Array(this.data.buffer);this.buffer&&this.buffer.set_state(a[28])};function pa(a){this.pci_addr=new Uint8Array(4);this.pci_value=new Uint8Array(4);this.pci_response=new Uint8Array(4);this.pci_status=new Uint8Array(4);this.pci_addr32=new Int32Array(this.pci_addr.buffer);this.pci_value32=new Int32Array(this.pci_value.buffer);this.pci_response32=new Int32Array(this.pci_response.buffer);this.pci_status32=new Int32Array(this.pci_status.buffer);this.device_spaces=[];this.devices=[];this.cpu=a;for(var b=0;256>b;b++)this.device_spaces[b]=void 0,this.devices[b]=void 0;this.io=
|
||||
a.io;a.io.register_write(3324,this,function(c){this.pci_write8(this.pci_addr32[0],c)},function(c){this.pci_write16(this.pci_addr32[0],c)},function(c){this.pci_write32(this.pci_addr32[0],c)});a.io.register_write(3325,this,function(c){this.pci_write8(this.pci_addr32[0]+1|0,c)});a.io.register_write(3326,this,function(c){this.pci_write8(this.pci_addr32[0]+2|0,c)},function(c){this.pci_write16(this.pci_addr32[0]+2|0,c)});a.io.register_write(3327,this,function(c){this.pci_write8(this.pci_addr32[0]+3|0,c)});
|
||||
a.io.register_read_consecutive(3324,this,function(){return this.pci_response[0]},function(){return this.pci_response[1]},function(){return this.pci_response[2]},function(){return this.pci_response[3]});a.io.register_read_consecutive(3320,this,function(){return this.pci_status[0]},function(){return this.pci_status[1]},function(){return this.pci_status[2]},function(){return this.pci_status[3]});a.io.register_write_consecutive(3320,this,function(c){this.pci_addr[0]=c&252},function(c){2===(this.pci_addr[1]&
|
||||
6)&&6===(c&6)?a.reboot_internal():this.pci_addr[1]=c},function(c){this.pci_addr[2]=c},function(c){this.pci_addr[3]=c;this.pci_query()});this.register_device({pci_id:0,pci_space:[134,128,55,18,0,0,0,0,2,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,0,0,0,0,0,0],pci_bars:[],name:"82441FX PMC"});this.isa_bridge={pci_id:8,pci_space:[134,128,0,112,7,0,0,2,0,0,1,6,0,0,128,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],pci_bars:[],name:"82371SB PIIX3 ISA"};this.isa_bridge_space=this.register_device(this.isa_bridge);this.isa_bridge_space8=new Uint8Array(this.isa_bridge_space.buffer)}pa.prototype.get_state=function(){for(var a=[],b=0;256>b;b++)a[b]=this.device_spaces[b];a[256]=this.pci_addr;a[257]=this.pci_value;a[258]=this.pci_response;a[259]=this.pci_status;return a};
|
||||
pa.prototype.set_state=function(a){for(var b=0;256>b;b++){var c=this.devices[b],d=a[b];if(c&&d){for(var e=0;e<c.pci_bars.length;e++){var g=d[4+e];if(g&1){var f=c.pci_bars[e];this.set_io_bars(f,f.original_bar&65534,g&65534)}}this.device_spaces[b].set(d)}else d&&A(b,2)}this.pci_addr.set(a[256]);this.pci_value.set(a[257]);this.pci_response.set(a[258]);this.pci_status.set(a[259])};
|
||||
pa.prototype.pci_query=function(){var a=this.pci_addr[2]<<8|this.pci_addr[1],b=this.pci_addr[0]&252,c=a>>3&31;var d="query enabled="+(this.pci_addr[3]>>7)+(" bdf="+A(a,4));d+=" dev="+A(c,2);d+=" addr="+A(b,2);a=this.device_spaces[a];void 0!==a?(this.pci_status32[0]=-2147483648,this.pci_response32[0]=b<a.byteLength?a[b>>2]:0,d+=" "+A(this.pci_addr32[0]>>>0,8)+" -> "+A(this.pci_response32[0]>>>0,8)):(this.pci_response32[0]=-1,this.pci_status32[0]=0)};
|
||||
pa.prototype.pci_write8=function(a,b){var c=a>>8&65535;a&=255;var d=new Uint8Array(this.device_spaces[c].buffer);A(a);A(c>>3,2);A(a,4);A(b,2);d[a]=b};pa.prototype.pci_write16=function(a,b){var c=a>>8&65535;a&=255;var d=new Uint16Array(this.device_spaces[c].buffer);16<=a&&44>a?A(a):(A(a),A(c>>3,2),A(a,4),A(b,4),d[a>>>1]=b)};
|
||||
pa.prototype.pci_write32=function(a,b){var c=a>>8&65535;a&=255;var d=this.device_spaces[c],e=this.devices[c];if(d)if(16<=a&&40>a){e=e.pci_bars[a-16>>2];A(b>>>0);A(c>>3,2);if(e){c=a>>2;var g=d[c]&1;-1===(b|3|e.size-1)?(b=~(e.size-1)|g,0===g&&(d[c]=b)):0===g&&(d[c]=e.original_bar);if(1===g){g=d[c]&65534;var f=b&65534;A(g>>>0,8);A(f>>>0,8);this.set_io_bars(e,g,f);d[c]=b|1}}else d[a>>2]=0;A(d[a>>2]>>>0)}else 48===a?(A(c>>3,2),A(b>>>0,8),d[a>>2]=e.pci_rom_size?-1===(b|2047)?-e.pci_rom_size|0:e.pci_rom_address|
|
||||
0:0):4===a?(A(c>>3,2),A(a,4),A(b>>>0,8)):(A(c>>3,2),A(a,4),A(b>>>0,8),d[a>>>2]=b)};pa.prototype.register_device=function(a){var b=a.pci_id;A(b);var c=new Int32Array(64);c.set(new Int32Array((new Uint8Array(a.pci_space)).buffer));this.device_spaces[b]=c;this.devices[b]=a;b=c.slice(4,10);for(var d=0;d<a.pci_bars.length;d++){var e=a.pci_bars[d];if(e){var g=b[d],f=g&1;e.original_bar=g;e.entries=[];if(0!==f)for(g&=-2,f=0;f<e.size;f++)e.entries[f]=this.io.ports[g+f]}}return c};
|
||||
pa.prototype.set_io_bars=function(a,b,c){var d=a.size;A(b);A(c);for(var e=this.io.ports,g=0;g<d;g++){var f=e[b+g];4096<=b+g&&(e[b+g]=this.io.create_empty_entry());f.read8===this.io.empty_port_read8&&f.read16===this.io.empty_port_read16&&f.read32===this.io.empty_port_read32&&f.write8===this.io.empty_port_write&&f.write16===this.io.empty_port_write&&f.write32===this.io.empty_port_write&&A(b+g,4);f=a.entries[g];var k=e[c+g];4096<=c+g&&(e[c+g]=f);k.read8!==this.io.empty_port_read8&&k.read16!==this.io.empty_port_read16&&
|
||||
k.read32!==this.io.empty_port_read32&&k.write8!==this.io.empty_port_write&&k.write16!==this.io.empty_port_write&&k.write32!==this.io.empty_port_write||A(c+g,4)}};pa.prototype.raise_irq=function(a){this.cpu.device_raise_irq(this.isa_bridge_space8[96+((this.device_spaces[a][15]>>8&255)-1+((a>>3)-1&255)&3)])};pa.prototype.lower_irq=function(a){this.cpu.device_lower_irq(this.isa_bridge_space8[96+((this.device_spaces[a][15]>>8&255)+(a>>3&255)-2&3)])};function K(a,b){this.io=a.io;this.cpu=a;this.dma=a.devices.dma;this.bytes_expecting=0;this.receiving_command=new Uint8Array(10);this.receiving_index=0;this.next_command=null;this.response_data=new Uint8Array(10);this.last_head=this.last_cylinder=this.drive=this.status_reg2=this.status_reg1=this.status_reg0=this.response_length=this.response_index=0;this.last_sector=1;this.dir=this.dor=0;this.fdb_image=this.fda_image=null;b?this.set_fda(b):(this.eject_fda(),this.cpu.devices.rtc.cmos_write(16,64));
|
||||
this.io.register_read(1008,this,this.port3F0_read);this.io.register_read(1010,this,this.port3F2_read);this.io.register_read(1012,this,this.port3F4_read);this.io.register_read(1013,this,this.port3F5_read);this.io.register_read(1015,this,this.port3F7_read);this.io.register_write(1010,this,this.port3F2_write);this.io.register_write(1012,this,this.port3F4_write);this.io.register_write(1013,this,this.port3F5_write)}
|
||||
K.prototype.eject_fda=function(){this.fda_image=null;this.number_of_cylinders=this.number_of_heads=this.sectors_per_track=0;this.dir=128};
|
||||
K.prototype.set_fda=function(a){var b={[163840]:{type:1,tracks:40,sectors:8,heads:1},[184320]:{type:1,tracks:40,sectors:9,heads:1},[204800]:{type:1,tracks:40,sectors:10,heads:1},[327680]:{type:1,tracks:40,sectors:8,heads:2},[368640]:{type:1,tracks:40,sectors:9,heads:2},[409600]:{type:1,tracks:40,sectors:10,heads:2},[737280]:{type:3,tracks:80,sectors:9,heads:2},[1228800]:{type:2,tracks:80,sectors:15,heads:2},[1474560]:{type:4,tracks:80,sectors:18,heads:2},[1763328]:{type:5,tracks:82,sectors:21,heads:2},
|
||||
[2949120]:{type:5,tracks:80,sectors:36,heads:2},512:{type:1,tracks:1,sectors:1,heads:1}};let c=a.byteLength,d=b[c];d||(c=1474560<a.byteLength?2949120:1474560,d=b[c],b=new Uint8Array(c),b.set(new Uint8Array(a.buffer)),a=new r.SyncBuffer(b.buffer));this.sectors_per_track=d.sectors;this.number_of_heads=d.heads;this.number_of_cylinders=d.tracks;this.fda_image=a;this.dir=128;this.cpu.devices.rtc.cmos_write(16,d.type<<4)};
|
||||
K.prototype.get_state=function(){var a=[];a[0]=this.bytes_expecting;a[1]=this.receiving_command;a[2]=this.receiving_index;a[4]=this.response_data;a[5]=this.response_index;a[6]=this.response_length;a[8]=this.status_reg0;a[9]=this.status_reg1;a[10]=this.status_reg2;a[11]=this.drive;a[12]=this.last_cylinder;a[13]=this.last_head;a[14]=this.last_sector;a[15]=this.dor;a[16]=this.sectors_per_track;a[17]=this.number_of_heads;a[18]=this.number_of_cylinders;return a};
|
||||
K.prototype.set_state=function(a){this.bytes_expecting=a[0];this.receiving_command=a[1];this.receiving_index=a[2];this.next_command=a[3];this.response_data=a[4];this.response_index=a[5];this.response_length=a[6];this.status_reg0=a[8];this.status_reg1=a[9];this.status_reg2=a[10];this.drive=a[11];this.last_cylinder=a[12];this.last_head=a[13];this.last_sector=a[14];this.dor=a[15];this.sectors_per_track=a[16];this.number_of_heads=a[17];this.number_of_cylinders=a[18]};K.prototype.port3F0_read=function(){return 0};
|
||||
K.prototype.port3F4_read=function(){var a=128;this.response_index<this.response_length&&(a|=80);0===(this.dor&8)&&(a|=32);return a};K.prototype.port3F7_read=function(){return this.dir};K.prototype.port3F5_read=function(){return this.response_index<this.response_length?(this.cpu.device_lower_irq(6),this.response_data[this.response_index++]):255};K.prototype.port3F4_write=function(a){A(a);a&128&&(this.status_reg0=192,this.cpu.device_raise_irq(6))};
|
||||
K.prototype.port3F5_write=function(a){J("3F5 write "+A(a),8192);if(0<this.bytes_expecting)this.receiving_command[this.receiving_index++]=a,this.bytes_expecting--,0===this.bytes_expecting&&this.next_command.call(this,this.receiving_command);else{switch(a){case 3:this.next_command=this.fix_drive_data;this.bytes_expecting=2;break;case 19:this.next_command=this.configure;this.bytes_expecting=3;break;case 4:this.next_command=this.check_drive_status;this.bytes_expecting=1;break;case 5:case 69:case 197:this.next_command=
|
||||
function(b){this.do_sector(!0,b)};this.bytes_expecting=8;break;case 6:case 70:case 230:this.next_command=function(b){this.do_sector(!1,b)};this.bytes_expecting=8;break;case 7:this.next_command=this.calibrate;this.bytes_expecting=1;break;case 8:this.check_interrupt_status();break;case 74:this.next_command=this.read_sector_id;this.bytes_expecting=1;break;case 15:this.bytes_expecting=2;this.next_command=this.seek;break;case 14:case 16:this.status_reg0=128;this.response_data[0]=this.status_reg0;this.response_index=
|
||||
0;this.response_length=1;this.bytes_expecting=0;break;default:oa(!1,"Unimplemented floppy command call "+A(a))}this.receiving_index=0}};K.prototype.port3F2_read=function(){return this.dor};K.prototype.port3F2_write=function(a){4===(a&4)&&0===(this.dor&4)&&(this.status_reg0=192,this.cpu.device_raise_irq(6));A(a>>4);A(a);this.dor=a};K.prototype.check_drive_status=function(){this.status_reg1=this.fda_image?0:5;this.response_index=0;this.response_length=1;this.response_data[0]=0};
|
||||
K.prototype.seek=function(a){if(0===(a[0]&3)){var b=a[1];a=a[0]>>2&1;b!==this.last_cylinder&&(this.dir=0);this.status_reg1=this.fda_image?0:5;this.status_reg0=32;this.last_cylinder=b;this.last_head=a}this.raise_irq()};K.prototype.calibrate=function(a){this.seek([a[0],0])};K.prototype.check_interrupt_status=function(){this.response_index=0;this.response_length=2;this.response_data[0]=this.status_reg0;this.response_data[1]=this.last_cylinder};
|
||||
K.prototype.do_sector=function(a,b){var c=b[2],d=b[1],e=b[3],g=128<<b[4],f=b[5]-b[3]+1,k=((c+this.number_of_heads*d)*this.sectors_per_track+e-1)*g;A(k);A(f*g);this.fda_image?(this.status_reg1=0,a?this.dma.do_write(this.fda_image,k,f*g,2,this.done.bind(this,b,d,c,e)):this.dma.do_read(this.fda_image,k,f*g,2,this.done.bind(this,b,d,c,e))):this.status_reg1=5};
|
||||
K.prototype.done=function(a,b,c,d,e){e||(d++,d>this.sectors_per_track&&(d=1,c++,c>=this.number_of_heads&&(c=0,b++)),b!==this.last_cylinder&&(this.dir=0),this.status_reg0=32,this.last_cylinder=b,this.last_head=c,this.last_sector=d,this.response_index=0,this.response_length=7,this.response_data[0]=c<<2|32,this.response_data[1]=0,this.response_data[2]=0,this.response_data[3]=b,this.response_data[4]=c,this.response_data[5]=d,this.response_data[6]=a[4],this.raise_irq())};
|
||||
K.prototype.fix_drive_data=function(a){a.slice(0,this.bytes_expecting)};K.prototype.configure=function(a){a.slice(0,this.bytes_expecting)};K.prototype.read_sector_id=function(){this.response_index=0;this.response_length=7;this.response_data[0]=0;this.response_data[1]=0;this.response_data[2]=0;this.response_data[3]=0;this.response_data[4]=0;this.response_data[5]=0;this.response_data[6]=0;this.raise_irq()};K.prototype.raise_irq=function(){this.dor&8&&this.cpu.device_raise_irq(6)};E.prototype.mmap_read8=function(a){return this.memory_map_read8[a>>>17](a)};E.prototype.mmap_write8=function(a,b){this.memory_map_write8[a>>>17](a,b)};E.prototype.mmap_read16=function(a){var b=this.memory_map_read8[a>>>17];return b(a)|b(a+1|0)<<8};E.prototype.mmap_write16=function(a,b){var c=this.memory_map_write8[a>>>17];c(a,b&255);c(a+1|0,b>>8)};E.prototype.mmap_read32=function(a){return this.memory_map_read32[a>>>17](a)};
|
||||
E.prototype.mmap_write32=function(a,b){this.memory_map_write32[a>>>17](a,b)};E.prototype.mmap_write64=function(a,b,c){var d=this.memory_map_write32[a>>>17];d(a,b);d(a+4,c)};E.prototype.mmap_write128=function(a,b,c,d,e){var g=this.memory_map_write32[a>>>17];g(a,b);g(a+4,c);g(a+8,d);g(a+12,e)};E.prototype.write_blob=function(a,b){a.length&&(this.in_mapped_range(b),this.in_mapped_range(b+a.length-1),this.jit_dirty_cache(b,b+a.length),this.mem8.set(a,b))};
|
||||
E.prototype.read_blob=function(a,b){b&&(this.in_mapped_range(a),this.in_mapped_range(a+b-1));return this.mem8.subarray(a,a+b)};function L(a){this.cpu=a;this.channel_page=new Uint8Array(8);this.channel_pagehi=new Uint8Array(8);this.channel_addr=new Uint16Array(8);this.channel_addr_init=new Uint16Array(8);this.channel_count=new Uint16Array(8);this.channel_count_init=new Uint16Array(8);this.channel_mask=new Uint8Array(8);this.channel_mode=new Uint8Array(8);this.unmask_listeners=[];this.lsb_msb_flipflop=0;a=a.io;a.register_write(0,this,this.port_addr_write.bind(this,0));a.register_write(2,this,this.port_addr_write.bind(this,
|
||||
1));a.register_write(4,this,this.port_addr_write.bind(this,2));a.register_write(6,this,this.port_addr_write.bind(this,3));a.register_write(1,this,this.port_count_write.bind(this,0));a.register_write(3,this,this.port_count_write.bind(this,1));a.register_write(5,this,this.port_count_write.bind(this,2));a.register_write(7,this,this.port_count_write.bind(this,3));a.register_read(0,this,this.port_addr_read.bind(this,0));a.register_read(2,this,this.port_addr_read.bind(this,1));a.register_read(4,this,this.port_addr_read.bind(this,
|
||||
2));a.register_read(6,this,this.port_addr_read.bind(this,3));a.register_read(1,this,this.port_count_read.bind(this,0));a.register_read(3,this,this.port_count_read.bind(this,1));a.register_read(5,this,this.port_count_read.bind(this,2));a.register_read(7,this,this.port_count_read.bind(this,3));a.register_write(192,this,this.port_addr_write.bind(this,4));a.register_write(196,this,this.port_addr_write.bind(this,5));a.register_write(200,this,this.port_addr_write.bind(this,6));a.register_write(204,this,
|
||||
this.port_addr_write.bind(this,7));a.register_write(194,this,this.port_count_write.bind(this,4));a.register_write(198,this,this.port_count_write.bind(this,5));a.register_write(202,this,this.port_count_write.bind(this,6));a.register_write(206,this,this.port_count_write.bind(this,7));a.register_read(192,this,this.port_addr_read.bind(this,4));a.register_read(196,this,this.port_addr_read.bind(this,5));a.register_read(200,this,this.port_addr_read.bind(this,6));a.register_read(204,this,this.port_addr_read.bind(this,
|
||||
7));a.register_read(194,this,this.port_count_read.bind(this,4));a.register_read(198,this,this.port_count_read.bind(this,5));a.register_read(202,this,this.port_count_read.bind(this,6));a.register_read(206,this,this.port_count_read.bind(this,7));a.register_write(135,this,this.port_page_write.bind(this,0));a.register_write(131,this,this.port_page_write.bind(this,1));a.register_write(129,this,this.port_page_write.bind(this,2));a.register_write(130,this,this.port_page_write.bind(this,3));a.register_write(143,
|
||||
this,this.port_page_write.bind(this,4));a.register_write(139,this,this.port_page_write.bind(this,5));a.register_write(137,this,this.port_page_write.bind(this,6));a.register_write(138,this,this.port_page_write.bind(this,7));a.register_read(135,this,this.port_page_read.bind(this,0));a.register_read(131,this,this.port_page_read.bind(this,1));a.register_read(129,this,this.port_page_read.bind(this,2));a.register_read(130,this,this.port_page_read.bind(this,3));a.register_read(143,this,this.port_page_read.bind(this,
|
||||
4));a.register_read(139,this,this.port_page_read.bind(this,5));a.register_read(137,this,this.port_page_read.bind(this,6));a.register_read(138,this,this.port_page_read.bind(this,7));a.register_write(1159,this,this.port_pagehi_write.bind(this,0));a.register_write(1155,this,this.port_pagehi_write.bind(this,1));a.register_write(1153,this,this.port_pagehi_write.bind(this,2));a.register_write(1154,this,this.port_pagehi_write.bind(this,3));a.register_write(1163,this,this.port_pagehi_write.bind(this,5));
|
||||
a.register_write(1161,this,this.port_pagehi_write.bind(this,6));a.register_write(1162,this,this.port_pagehi_write.bind(this,7));a.register_read(1159,this,this.port_pagehi_read.bind(this,0));a.register_read(1155,this,this.port_pagehi_read.bind(this,1));a.register_read(1153,this,this.port_pagehi_read.bind(this,2));a.register_read(1154,this,this.port_pagehi_read.bind(this,3));a.register_read(1163,this,this.port_pagehi_read.bind(this,5));a.register_read(1161,this,this.port_pagehi_read.bind(this,6));a.register_read(1162,
|
||||
this,this.port_pagehi_read.bind(this,7));a.register_write(10,this,this.port_singlemask_write.bind(this,0));a.register_write(212,this,this.port_singlemask_write.bind(this,4));a.register_write(15,this,this.port_multimask_write.bind(this,0));a.register_write(222,this,this.port_multimask_write.bind(this,4));a.register_read(15,this,this.port_multimask_read.bind(this,0));a.register_read(222,this,this.port_multimask_read.bind(this,4));a.register_write(11,this,this.port_mode_write.bind(this,0));a.register_write(214,
|
||||
this,this.port_mode_write.bind(this,4));a.register_write(12,this,this.portC_write);a.register_write(216,this,this.portC_write)}L.prototype.get_state=function(){return[this.channel_page,this.channel_pagehi,this.channel_addr,this.channel_addr_init,this.channel_count,this.channel_count_init,this.channel_mask,this.channel_mode,this.lsb_msb_flipflop]};
|
||||
L.prototype.set_state=function(a){this.channel_page=a[0];this.channel_pagehi=a[1];this.channel_addr=a[2];this.channel_addr_init=a[3];this.channel_count=a[4];this.channel_count_init=a[5];this.channel_mask=a[6];this.channel_mode=a[7];this.lsb_msb_flipflop=a[8]};L.prototype.port_count_write=function(a,b){A(b);this.channel_count[a]=this.flipflop_get(this.channel_count[a],b,!1);this.channel_count_init[a]=this.flipflop_get(this.channel_count_init[a],b,!0)};
|
||||
L.prototype.port_count_read=function(a){A(this.channel_count[a]);return this.flipflop_read(this.channel_count[a])};L.prototype.port_addr_write=function(a,b){A(b);this.channel_addr[a]=this.flipflop_get(this.channel_addr[a],b,!1);this.channel_addr_init[a]=this.flipflop_get(this.channel_addr_init[a],b,!0)};L.prototype.port_addr_read=function(a){A(this.channel_addr[a]);return this.flipflop_read(this.channel_addr[a])};L.prototype.port_pagehi_write=function(a,b){A(b);this.channel_pagehi[a]=b};
|
||||
L.prototype.port_pagehi_read=function(a){return this.channel_pagehi[a]};L.prototype.port_page_write=function(a,b){A(b);this.channel_page[a]=b};L.prototype.port_page_read=function(a){return this.channel_page[a]};L.prototype.port_singlemask_write=function(a,b){this.update_mask((b&3)+a,b&4?1:0)};L.prototype.port_multimask_write=function(a,b){A(b);for(var c=0;4>c;c++)this.update_mask(a+c,b&1<<c)};
|
||||
L.prototype.port_multimask_read=function(a){var b=0|this.channel_mask[a+0];b|=this.channel_mask[a+1]<<1;b|=this.channel_mask[a+2]<<2;b|=this.channel_mask[a+3]<<3;A(b);return b};L.prototype.port_mode_write=function(a,b){a=(b&3)+a;A(b);this.channel_mode[a]=b};L.prototype.portC_write=function(){this.lsb_msb_flipflop=0};L.prototype.on_unmask=function(a,b){this.unmask_listeners.push({fn:a,this_value:b})};
|
||||
L.prototype.update_mask=function(a,b){if(this.channel_mask[a]!==b&&(this.channel_mask[a]=b,!b))for(b=0;b<this.unmask_listeners.length;b++)this.unmask_listeners[b].fn.call(this.unmask_listeners[b].this_value,a)};
|
||||
L.prototype.do_read=function(a,b,c,d,e){var g=this.count_get_8bit(d),f=this.address_get_8bit(d);J("to "+A(f)+" len "+A(g),16);c<g&&J("DMA should read more than provided: "+A(c)+" "+A(g),16);if(b+g>a.byteLength)e(!0);else{var k=this.cpu;this.channel_addr[d]+=g;a.get(b,g,function(l){k.write_blob(l,f);e(!1)})}};
|
||||
L.prototype.do_write=function(a,b,c,d,e){var g=this.channel_count[d]+1&65535,f=5<=d?2:1,k=g*f,l=this.address_get_8bit(d),m=!1,n=!1,p=this.channel_mode[d]&16;J("to "+A(l)+" len "+A(k),16);c<k?(g=Math.floor(c/f),k=g*f,m=!0):c>k&&(n=!0);b+k>a.byteLength?e(!0):(this.channel_addr[d]+=g,this.channel_count[d]-=g,!m&&p&&(this.channel_addr[d]=this.channel_addr_init[d],this.channel_count[d]=this.channel_count_init[d]),a.set(b,this.cpu.mem8.subarray(l,l+k),()=>{n&&p?this.do_write(a,b+k,c-k,d,e):e(!1)}))};
|
||||
L.prototype.address_get_8bit=function(a){var b=this.channel_addr[a];5<=a&&(b<<=1);b=b&65535|this.channel_page[a]<<16;return b|=this.channel_pagehi[a]<<24};L.prototype.count_get_8bit=function(a){var b=this.channel_count[a]+1;5<=a&&(b*=2);return b};L.prototype.flipflop_get=function(a,b,c){c||(this.lsb_msb_flipflop^=1);return this.lsb_msb_flipflop?a&-256|b:a&-65281|b<<8};L.prototype.flipflop_read=function(a){return(this.lsb_msb_flipflop^=1)?a&255:a>>8&255};function qa(a,b){this.cpu=a;this.bus=b;this.counter_start_time=new Float64Array(3);this.counter_start_value=new Uint16Array(3);this.counter_next_low=new Uint8Array(4);this.counter_enabled=new Uint8Array(4);this.counter_mode=new Uint8Array(4);this.counter_read_mode=new Uint8Array(4);this.counter_latch=new Uint8Array(4);this.counter_latch_value=new Uint16Array(3);this.counter_reload=new Uint16Array(3);a.io.register_read(97,this,function(){var c=D.microtick(),d=66.66666666666667*c&1;c=this.did_rollover(2,
|
||||
c);return d<<4|c<<5});a.io.register_write(97,this,function(c){c&1?this.bus.send("pcspeaker-enable"):this.bus.send("pcspeaker-disable")});a.io.register_read(64,this,function(){return this.counter_read(0)});a.io.register_read(65,this,function(){return this.counter_read(1)});a.io.register_read(66,this,function(){return this.counter_read(2)});a.io.register_write(64,this,function(c){this.counter_write(0,c)});a.io.register_write(65,this,function(c){this.counter_write(1,c)});a.io.register_write(66,this,
|
||||
function(c){this.counter_write(2,c);this.bus.send("pcspeaker-update",[this.counter_mode[2],this.counter_reload[2]])});a.io.register_write(67,this,this.port43_write)}qa.prototype.get_state=function(){var a=[];a[0]=this.counter_next_low;a[1]=this.counter_enabled;a[2]=this.counter_mode;a[3]=this.counter_read_mode;a[4]=this.counter_latch;a[5]=this.counter_latch_value;a[6]=this.counter_reload;a[7]=this.counter_start_time;a[8]=this.counter_start_value;return a};
|
||||
qa.prototype.set_state=function(a){this.counter_next_low=a[0];this.counter_enabled=a[1];this.counter_mode=a[2];this.counter_read_mode=a[3];this.counter_latch=a[4];this.counter_latch_value=a[5];this.counter_reload=a[6];this.counter_start_time=a[7];this.counter_start_value=a[8]};
|
||||
qa.prototype.timer=function(a,b){var c=100;b||(this.counter_enabled[0]&&this.did_rollover(0,a)?(this.counter_start_value[0]=this.get_counter_value(0,a),this.counter_start_time[0]=a,this.cpu.device_lower_irq(0),this.cpu.device_raise_irq(0),0===this.counter_mode[0]&&(this.counter_enabled[0]=0)):this.cpu.device_lower_irq(0),this.counter_enabled[0]&&(c=(this.counter_start_value[0]-Math.floor(1193.1816666*(a-this.counter_start_time[0])))/1193.1816666));return c};
|
||||
qa.prototype.get_counter_value=function(a,b){if(!this.counter_enabled[a])return 0;b=this.counter_start_value[a]-Math.floor(1193.1816666*(b-this.counter_start_time[a]));a=this.counter_reload[a];b>=a?b%=a:0>b&&(b=b%a+a);return b};qa.prototype.did_rollover=function(a,b){b-=this.counter_start_time[a];return 0>b?!0:this.counter_start_value[a]<Math.floor(1193.1816666*b)};
|
||||
qa.prototype.counter_read=function(a){var b=this.counter_latch[a];if(b)return this.counter_latch[a]--,2===b?this.counter_latch_value[a]&255:this.counter_latch_value[a]>>8;b=this.counter_next_low[a];3===this.counter_mode[a]&&(this.counter_next_low[a]^=1);a=this.get_counter_value(a,D.microtick());return b?a&255:a>>8};
|
||||
qa.prototype.counter_write=function(a,b){this.counter_reload[a]=this.counter_next_low[a]?this.counter_reload[a]&-256|b:this.counter_reload[a]&255|b<<8;3===this.counter_read_mode[a]&&this.counter_next_low[a]||(this.counter_reload[a]||(this.counter_reload[a]=65535),this.counter_start_value[a]=this.counter_reload[a],this.counter_enabled[a]=!0,this.counter_start_time[a]=D.microtick(),A(this.counter_reload[a]));3===this.counter_read_mode[a]&&(this.counter_next_low[a]^=1)};
|
||||
qa.prototype.port43_write=function(a){var b=a>>1&7,c=a>>6&3;a=a>>4&3;3!==c&&(0===a?(this.counter_latch[c]=2,b=this.get_counter_value(c,D.microtick()),this.counter_latch_value[c]=b?b-1:0):(6<=b&&(b&=-5),this.counter_next_low[c]=1===a?0:1,0===c&&this.cpu.device_lower_irq(0),0!==b&&3!==b&&2!==b&&A(b),this.counter_mode[c]=b,this.counter_read_mode[c]=a,2===c&&this.bus.send("pcspeaker-update",[this.counter_mode[2],this.counter_reload[2]])))};qa.prototype.dump=function(){};var ra=Uint32Array.from([655360,655360,720896,753664]),ua=Uint32Array.from([131072,65536,32768,32768]);
|
||||
function M(a,b,c){this.cpu=a;this.bus=b;this.vga_memory_size=c;this.cursor_address=0;this.cursor_scanline_start=14;this.cursor_scanline_end=15;this.max_cols=80;this.max_rows=25;this.virtual_height=this.virtual_width=this.screen_height=this.screen_width=0;this.layers=[];this.start_address_latched=this.start_address=0;this.crtc=new Uint8Array(25);this.line_compare=this.offset_register=this.preset_row_scan=this.underline_location_register=this.vertical_blank_start=this.vertical_display_enable_end=this.horizontal_blank_start=
|
||||
this.horizontal_display_enable_end=this.crtc_mode=0;this.graphical_mode_is_linear=!0;this.graphical_mode=!1;setTimeout(()=>{b.send("screen-set-mode",this.graphical_mode)},0);this.vga256_palette=new Int32Array(256);this.latch_dword=0;this.svga_version=45253;this.svga_height=this.svga_width=0;this.svga_enabled=!1;this.svga_bpp=32;this.svga_offset_y=this.svga_offset=this.svga_bank_offset=0;this.pci_space=[52,18,17,17,3,1,0,0,0,0,0,3,0,0,0,0,8,14680064,57344,224,0,0,0,0,0,0,191,254,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,244,26,0,17,0,0,190,254,0,0,0,0,0,0,0,0,0,0,0,0];this.pci_id=144;this.pci_bars=[{size:c}];this.pci_rom_size=65536;this.pci_rom_address=4272947200;this.name="vga";this.stats={is_graphical:!1,res_x:0,res_y:0,bpp:0};this.dac_state=this.dac_color_index_read=this.dac_color_index_write=this.index_crtc=0;this.dac_mask=255;this.dac_map=new Uint8Array(16);this.attribute_controller_index=-1;this.palette_source=32;this.color_select=this.horizontal_panning=this.color_plane_enable=this.attribute_mode=
|
||||
0;this.sequencer_index=-1;this.plane_write_bm=15;this.clocking_mode=this.sequencer_memory_mode=0;this.graphics_index=-1;this.planar_rotate_reg=this.planar_mode=this.plane_read=0;this.planar_bitmap=255;this.max_scan_line=this.color_dont_care=this.color_compare=this.miscellaneous_graphics_register=this.planar_setreset_enable=this.planar_setreset=0;this.port_3DA_value=this.miscellaneous_output_register=255;c=a.io;c.register_write(960,this,this.port3C0_write);c.register_read(960,this,this.port3C0_read,
|
||||
this.port3C0_read16);c.register_read(961,this,this.port3C1_read);c.register_write(962,this,this.port3C2_write);c.register_write_consecutive(964,this,this.port3C4_write,this.port3C5_write);c.register_read(964,this,this.port3C4_read);c.register_read(965,this,this.port3C5_read);c.register_write_consecutive(974,this,this.port3CE_write,this.port3CF_write);c.register_read(974,this,this.port3CE_read);c.register_read(975,this,this.port3CF_read);c.register_read(966,this,this.port3C6_read);c.register_write(966,
|
||||
this,this.port3C6_write);c.register_write(967,this,this.port3C7_write);c.register_read(967,this,this.port3C7_read);c.register_write(968,this,this.port3C8_write);c.register_read(968,this,this.port3C8_read);c.register_write(969,this,this.port3C9_write);c.register_read(969,this,this.port3C9_read);c.register_read(972,this,this.port3CC_read);c.register_write_consecutive(980,this,this.port3D4_write,this.port3D5_write);c.register_read(980,this,this.port3D4_read);c.register_read(981,this,this.port3D5_read,
|
||||
()=>this.port3D5_read());c.register_read(970,this,function(){return 0});c.register_read(986,this,this.port3DA_read);c.register_read(954,this,this.port3DA_read);this.dispi_index=-1;this.dispi_enable_value=0;c.register_write(462,this,void 0,this.port1CE_write);c.register_write(463,this,void 0,this.port1CF_write);c.register_read(463,this,void 0,this.port1CF_read);void 0===this.vga_memory_size||262144>this.vga_memory_size?this.vga_memory_size=262144:268435456<this.vga_memory_size?this.vga_memory_size=
|
||||
268435456:this.vga_memory_size&65535&&(this.vga_memory_size|=65535,this.vga_memory_size++);const d=a.svga_allocate_memory(this.vga_memory_size)>>>0;this.svga_memory=r.view(Uint8Array,a.wasm_memory,d,this.vga_memory_size);this.diff_addr_min=this.vga_memory_size;this.diff_addr_max=0;this.diff_plot_min=this.vga_memory_size;this.diff_plot_max=0;this.image_data=null;b.register("screen-fill-buffer",function(){this.screen_fill_buffer()},this);this.vga_memory=new Uint8Array(262144);this.plane0=new Uint8Array(this.vga_memory.buffer,
|
||||
0,65536);this.plane1=new Uint8Array(this.vga_memory.buffer,65536,65536);this.plane2=new Uint8Array(this.vga_memory.buffer,131072,65536);this.plane3=new Uint8Array(this.vga_memory.buffer,196608,65536);this.pixel_buffer=new Uint8Array(524288);var e=this;c.mmap_register(655360,131072,function(g){return e.vga_memory_read(g)},function(g,f){e.vga_memory_write(g,f)});a.devices.pci.register_device(this)}
|
||||
M.prototype.get_state=function(){var a=[];a[0]=this.vga_memory_size;a[1]=this.cursor_address;a[2]=this.cursor_scanline_start;a[3]=this.cursor_scanline_end;a[4]=this.max_cols;a[5]=this.max_rows;a[6]=this.vga_memory;a[7]=this.dac_state;a[8]=this.start_address;a[9]=this.graphical_mode;a[10]=this.vga256_palette;a[11]=this.latch_dword;a[12]=this.color_compare;a[13]=this.color_dont_care;a[14]=this.miscellaneous_graphics_register;a[15]=this.svga_width;a[16]=this.svga_height;a[17]=this.crtc_mode;a[18]=this.svga_enabled;
|
||||
a[19]=this.svga_bpp;a[20]=this.svga_bank_offset;a[21]=this.svga_offset;a[22]=this.index_crtc;a[23]=this.dac_color_index_write;a[24]=this.dac_color_index_read;a[25]=this.dac_map;a[26]=this.sequencer_index;a[27]=this.plane_write_bm;a[28]=this.sequencer_memory_mode;a[29]=this.graphics_index;a[30]=this.plane_read;a[31]=this.planar_mode;a[32]=this.planar_rotate_reg;a[33]=this.planar_bitmap;a[34]=this.max_scan_line;a[35]=this.miscellaneous_output_register;a[36]=this.port_3DA_value;a[37]=this.dispi_index;
|
||||
a[38]=this.dispi_enable_value;a[39]=this.svga_memory;a[40]=this.graphical_mode_is_linear;a[41]=this.attribute_controller_index;a[42]=this.offset_register;a[43]=this.planar_setreset;a[44]=this.planar_setreset_enable;a[45]=this.start_address_latched;a[46]=this.crtc;a[47]=this.horizontal_display_enable_end;a[48]=this.horizontal_blank_start;a[49]=this.vertical_display_enable_end;a[50]=this.vertical_blank_start;a[51]=this.underline_location_register;a[52]=this.preset_row_scan;a[53]=this.offset_register;
|
||||
a[54]=this.palette_source;a[55]=this.attribute_mode;a[56]=this.color_plane_enable;a[57]=this.horizontal_panning;a[58]=this.color_select;a[59]=this.clocking_mode;a[60]=this.line_compare;a[61]=this.pixel_buffer;a[62]=this.dac_mask;return a};
|
||||
M.prototype.set_state=function(a){this.vga_memory_size=a[0];this.cursor_address=a[1];this.cursor_scanline_start=a[2];this.cursor_scanline_end=a[3];this.max_cols=a[4];this.max_rows=a[5];a[6]&&this.vga_memory.set(a[6]);this.dac_state=a[7];this.start_address=a[8];this.graphical_mode=a[9];this.vga256_palette=a[10];this.latch_dword=a[11];this.color_compare=a[12];this.color_dont_care=a[13];this.miscellaneous_graphics_register=a[14];this.svga_width=a[15];this.svga_height=a[16];this.crtc_mode=a[17];this.svga_enabled=
|
||||
a[18];this.svga_bpp=a[19];this.svga_bank_offset=a[20];this.svga_offset=a[21];this.index_crtc=a[22];this.dac_color_index_write=a[23];this.dac_color_index_read=a[24];this.dac_map=a[25];this.sequencer_index=a[26];this.plane_write_bm=a[27];this.sequencer_memory_mode=a[28];this.graphics_index=a[29];this.plane_read=a[30];this.planar_mode=a[31];this.planar_rotate_reg=a[32];this.planar_bitmap=a[33];this.max_scan_line=a[34];this.miscellaneous_output_register=a[35];this.port_3DA_value=a[36];this.dispi_index=
|
||||
a[37];this.dispi_enable_value=a[38];this.svga_memory.set(a[39]);this.graphical_mode_is_linear=a[40];this.attribute_controller_index=a[41];this.offset_register=a[42];this.planar_setreset=a[43];this.planar_setreset_enable=a[44];this.start_address_latched=a[45];this.crtc.set(a[46]);this.horizontal_display_enable_end=a[47];this.horizontal_blank_start=a[48];this.vertical_display_enable_end=a[49];this.vertical_blank_start=a[50];this.underline_location_register=a[51];this.preset_row_scan=a[52];this.offset_register=
|
||||
a[53];this.palette_source=a[54];this.attribute_mode=a[55];this.color_plane_enable=a[56];this.horizontal_panning=a[57];this.color_select=a[58];this.clocking_mode=a[59];this.line_compare=a[60];a[61]&&this.pixel_buffer.set(a[61]);this.dac_mask=void 0===a[62]?255:a[62];this.bus.send("screen-set-mode",this.graphical_mode);this.graphical_mode?(this.screen_height=this.screen_width=0,this.svga_enabled?(this.set_size_graphical(this.svga_width,this.svga_height,this.svga_bpp,this.svga_width,this.svga_height),
|
||||
this.update_layers()):(this.update_vga_size(),this.update_layers(),this.complete_replot())):(this.set_size_text(this.max_cols,this.max_rows),this.update_cursor_scanline(),this.update_cursor());this.complete_redraw()};
|
||||
M.prototype.vga_memory_read=function(a){if(this.svga_enabled&&this.graphical_mode_is_linear)return this.cpu.read8((a-655360|this.svga_bank_offset)+3758096384|0);var b=this.miscellaneous_graphics_register>>2&3;a-=ra[b];if(0>a||a>=ua[b])return A(a),0;this.latch_dword=this.plane0[a];this.latch_dword|=this.plane1[a]<<8;this.latch_dword|=this.plane2[a]<<16;this.latch_dword|=this.plane3[a]<<24;if(this.planar_mode&8)return b=255,this.color_dont_care&1&&(b&=this.plane0[a]^~(this.color_compare&1?255:0)),this.color_dont_care&
|
||||
2&&(b&=this.plane1[a]^~(this.color_compare&2?255:0)),this.color_dont_care&4&&(b&=this.plane2[a]^~(this.color_compare&4?255:0)),this.color_dont_care&8&&(b&=this.plane3[a]^~(this.color_compare&8?255:0)),b;b=this.plane_read;this.graphical_mode?this.sequencer_memory_mode&8?(b=a&3,a&=-4):this.planar_mode&16&&(b=a&1,a&=-2):b=0;return this.vga_memory[b<<16|a]};
|
||||
M.prototype.vga_memory_write=function(a,b){if(this.svga_enabled&&this.graphical_mode&&this.graphical_mode_is_linear)this.cpu.write8((a-655360|this.svga_bank_offset)+3758096384|0,b);else{var c=this.miscellaneous_graphics_register>>2&3;a-=ra[c];0>a||a>=ua[c]?(A(a),A(b)):this.graphical_mode?this.vga_memory_write_graphical(a,b):this.plane_write_bm&3&&this.vga_memory_write_text_mode(a,b)}};
|
||||
M.prototype.vga_memory_write_graphical=function(a,b){var c=this.planar_mode&3,d=this.apply_feed(this.planar_bitmap),e=this.apply_expand(this.planar_setreset),g=this.apply_expand(this.planar_setreset_enable);switch(c){case 0:b=this.apply_rotate(b);var f=this.apply_feed(b);f=this.apply_setreset(f,g);f=this.apply_logical(f,this.latch_dword);f=this.apply_bitmask(f,d);break;case 1:f=this.latch_dword;break;case 2:f=this.apply_expand(b);f=this.apply_logical(f,this.latch_dword);f=this.apply_bitmask(f,d);
|
||||
break;case 3:b=this.apply_rotate(b),d&=this.apply_feed(b),f=this.apply_bitmask(e,d)}b=15;switch(this.sequencer_memory_mode&12){case 0:b=5<<(a&1);a&=-2;break;case 8:case 12:b=1<<(a&3),a&=-4}b&=this.plane_write_bm;b&1&&(this.plane0[a]=f>>0&255);b&2&&(this.plane1[a]=f>>8&255);b&4&&(this.plane2[a]=f>>16&255);b&8&&(this.plane3[a]=f>>24&255);a=this.vga_addr_to_pixel(a);this.partial_replot(a,a+7)};M.prototype.apply_feed=function(a){return a|a<<8|a<<16|a<<24};
|
||||
M.prototype.apply_expand=function(a){return(a&1?255:0)|(a&2?255:0)<<8|(a&4?255:0)<<16|(a&8?255:0)<<24};M.prototype.apply_rotate=function(a){return(a|a<<8)>>>(this.planar_rotate_reg&7)&255};M.prototype.apply_setreset=function(a,b){var c=this.apply_expand(this.planar_setreset);return(a|b&c)&(~b|c)};M.prototype.apply_logical=function(a,b){switch(this.planar_rotate_reg&24){case 8:return a&b;case 16:return a|b;case 24:return a^b}return a};M.prototype.apply_bitmask=function(a,b){return b&a|~b&this.latch_dword};
|
||||
M.prototype.text_mode_redraw=function(){var a=this.start_address<<1;const b=this.scan_line_to_screen_row(this.line_compare),c=Math.max(0,2*(2*this.offset_register-this.max_cols));for(var d=0;d<this.max_rows;d++){d===b&&(a=0);for(var e=0;e<this.max_cols;e++){var g=this.vga_memory[a];var f=this.vga_memory[a|1];this.bus.send("screen-put-char",[d,e,g,this.vga256_palette[this.dac_mask&this.dac_map[f>>4&15]],this.vga256_palette[this.dac_mask&this.dac_map[f&15]]]);a+=2}a+=c}};
|
||||
M.prototype.vga_memory_write_text_mode=function(a,b){var c=Math.max(this.max_cols,2*this.offset_register);let d;if(a>>1>=this.start_address){var e=(a>>1)-this.start_address;d=e/c|0;c=e%c}else e=a>>1,d=(e/c|0)+this.scan_line_to_screen_row(this.line_compare),c=e%c;if(!(c>=this.max_cols||d>=this.max_rows)){if(a&1){var g=b;e=this.vga_memory[a&-2]}else e=b,g=this.vga_memory[a|1];this.bus.send("screen-put-char",[d,c,e,this.vga256_palette[this.dac_mask&this.dac_map[g>>4&15]],this.vga256_palette[this.dac_mask&
|
||||
this.dac_map[g&15]]]);this.vga_memory[a]=b}};M.prototype.update_cursor=function(){var a=Math.max(this.max_cols,2*this.offset_register);let b;this.cursor_address>=this.start_address?(b=(this.cursor_address-this.start_address)/a|0,a=(this.cursor_address-this.start_address)%a):(b=(this.cursor_address/a|0)+this.scan_line_to_screen_row(this.line_compare),a=this.cursor_address%a);b=Math.min(this.max_rows-1,b);a=Math.min(this.max_cols-1,a);this.bus.send("screen-update-cursor",[b,a])};
|
||||
M.prototype.complete_redraw=function(){this.graphical_mode?this.svga_enabled?this.cpu.svga_mark_dirty():(this.diff_addr_min=0,this.diff_addr_max=524288):this.text_mode_redraw()};M.prototype.complete_replot=function(){this.graphical_mode&&!this.svga_enabled&&(this.diff_plot_min=0,this.diff_plot_max=524288,this.complete_redraw())};M.prototype.partial_redraw=function(a,b){a<this.diff_addr_min&&(this.diff_addr_min=a);b>this.diff_addr_max&&(this.diff_addr_max=b)};
|
||||
M.prototype.partial_replot=function(a,b){a<this.diff_plot_min&&(this.diff_plot_min=a);b>this.diff_plot_max&&(this.diff_plot_max=b);this.partial_redraw(a,b)};M.prototype.reset_diffs=function(){this.diff_addr_min=this.vga_memory_size;this.diff_addr_max=0;this.diff_plot_min=this.vga_memory_size;this.diff_plot_max=0};M.prototype.destroy=function(){};M.prototype.vga_bytes_per_line=function(){var a=this.offset_register<<2;this.underline_location_register&64?a<<=1:this.crtc_mode&64&&(a>>>=1);return a};
|
||||
M.prototype.vga_addr_shift_count=function(){var a=128+(~this.underline_location_register&this.crtc_mode&64);a-=this.underline_location_register&64;a-=this.attribute_mode&64;return a>>>6};
|
||||
M.prototype.vga_addr_to_pixel=function(a){var b=this.vga_addr_shift_count();if(~this.crtc_mode&3){var c=a-this.start_address;c&=this.crtc_mode<<13|-24577;c<<=b;var d=c/this.virtual_width|0;c%=this.virtual_width;switch(this.crtc_mode&3){case 2:d=d<<1|a>>13&1;break;case 1:d=d<<1|a>>14&1;break;case 0:d=d<<2|a>>13&3}return d*this.virtual_width+c+(this.start_address<<b)}return a<<b};
|
||||
M.prototype.scan_line_to_screen_row=function(a){this.max_scan_line&128&&(a>>>=1);a=Math.ceil(a/(1+(this.max_scan_line&31)));this.crtc_mode&1||(a<<=1);this.crtc_mode&2||(a<<=1);return a};M.prototype.set_size_text=function(a,b){this.max_cols=a;this.max_rows=b;this.bus.send("screen-set-size-text",[a,b])};
|
||||
M.prototype.set_size_graphical=function(a,b,c,d,e){if(!this.stats.is_graphical||this.stats.bpp!==c||this.screen_width!==a||this.screen_height!==b||this.virtual_width!==d||this.virtual_height!==e){this.screen_width=a;this.screen_height=b;this.virtual_width=d;this.virtual_height=e;this.stats.bpp=c;this.stats.is_graphical=!0;this.stats.res_x=a;this.stats.res_y=b;if("undefined"!==typeof ImageData){const g=d*e,f=this.cpu.svga_allocate_dest_buffer(g)>>>0;this.dest_buffet_offset=f;this.image_data=new ImageData(new Uint8ClampedArray(this.cpu.wasm_memory.buffer,
|
||||
f,4*g),d,e);this.cpu.svga_mark_dirty()}this.bus.send("screen-set-size-graphical",[a,b,d,e,c])}};
|
||||
M.prototype.update_vga_size=function(){if(!this.svga_enabled){var a=Math.min(1+this.horizontal_display_enable_end,this.horizontal_blank_start),b=Math.min(1+this.vertical_display_enable_end,this.vertical_blank_start);if(a&&b)if(this.graphical_mode){a<<=3;var c=this.offset_register<<4;this.attribute_mode&64&&(a>>>=1,c>>>=1);b=this.scan_line_to_screen_row(b);var d=Math.ceil(ua[0]/this.vga_bytes_per_line());this.set_size_graphical(a,b,8,c,d);this.update_vertical_retrace();this.update_layers()}else this.max_scan_line&
|
||||
128&&(b>>>=1),c=b/(1+(this.max_scan_line&31))|0,a&&c&&this.set_size_text(a,c)}};
|
||||
M.prototype.update_layers=function(){this.graphical_mode||this.text_mode_redraw();if(this.svga_enabled)this.layers=[];else if(this.virtual_width&&this.screen_width)if(!this.palette_source||this.clocking_mode&32)this.layers=[],this.bus.send("screen-clear");else{var a=this.start_address_latched,b=this.horizontal_panning;this.attribute_mode&64&&(b>>>=1);var c=this.preset_row_scan>>5&3,d=this.vga_addr_to_pixel(a+c);a=d/this.virtual_width|0;var e=d%this.virtual_width+b;d=this.scan_line_to_screen_row(1+
|
||||
this.line_compare);d=Math.min(d,this.screen_height);var g=this.screen_height-d;this.layers=[];e=-e;for(var f=0;e<this.screen_width;e+=this.virtual_width,f++)this.layers.push({image_data:this.image_data,screen_x:e,screen_y:0,buffer_x:0,buffer_y:a+f,buffer_width:this.virtual_width,buffer_height:d});a=0;this.attribute_mode&32||(a=this.vga_addr_to_pixel(c)+b);e=-a;for(f=0;e<this.screen_width;e+=this.virtual_width,f++)this.layers.push({image_data:this.image_data,screen_x:e,screen_y:d,buffer_x:0,buffer_y:f,
|
||||
buffer_width:this.virtual_width,buffer_height:g})}};M.prototype.update_vertical_retrace=function(){this.port_3DA_value|=8;this.start_address_latched!==this.start_address&&(this.start_address_latched=this.start_address,this.update_layers())};M.prototype.update_cursor_scanline=function(){this.bus.send("screen-update-cursor-scanline",[this.cursor_scanline_start,this.cursor_scanline_end])};
|
||||
M.prototype.port3C0_write=function(a){if(-1===this.attribute_controller_index)A(a),this.attribute_controller_index=a&31,A(this.attribute_controller_index),this.palette_source!==(a&32)&&(this.palette_source=a&32,this.update_layers());else{if(16>this.attribute_controller_index)A(this.attribute_controller_index),A(a),this.dac_map[this.attribute_controller_index]=a,this.attribute_mode&64||this.complete_redraw();else switch(this.attribute_controller_index){case 16:A(a);if(this.attribute_mode!==a){var b=
|
||||
this.attribute_mode;this.attribute_mode=a;var c=0<(a&1);this.svga_enabled||this.graphical_mode===c||(this.graphical_mode=c,this.bus.send("screen-set-mode",this.graphical_mode));(b^a)&64&&this.complete_replot();this.update_vga_size();this.complete_redraw()}break;case 18:A(a);this.color_plane_enable!==a&&(this.color_plane_enable=a,this.complete_redraw());break;case 19:A(a);this.horizontal_panning!==a&&(this.horizontal_panning=a&15,this.update_layers());break;case 20:A(a);this.color_select!==a&&(this.color_select=
|
||||
a,this.complete_redraw());break;default:A(this.attribute_controller_index),A(a)}this.attribute_controller_index=-1}};M.prototype.port3C0_read=function(){return(this.attribute_controller_index|this.palette_source)&255};M.prototype.port3C0_read16=function(){return this.port3C0_read()|this.port3C1_read()<<8&65280};
|
||||
M.prototype.port3C1_read=function(){if(16>this.attribute_controller_index)return A(this.attribute_controller_index),A(this.dac_map[this.attribute_controller_index]),this.dac_map[this.attribute_controller_index]&255;switch(this.attribute_controller_index){case 16:return A(this.attribute_mode),this.attribute_mode;case 18:return A(this.color_plane_enable),this.color_plane_enable;case 19:return A(this.horizontal_panning),this.horizontal_panning;case 20:return A(this.color_select),this.color_select;default:A(this.attribute_controller_index)}return 255};
|
||||
M.prototype.port3C2_write=function(a){A(a);this.miscellaneous_output_register=a};M.prototype.port3C4_write=function(a){this.sequencer_index=a};M.prototype.port3C4_read=function(){return this.sequencer_index};M.prototype.port3C5_write=function(a){switch(this.sequencer_index){case 1:A(a);var b=this.clocking_mode;this.clocking_mode=a;(b^a)&32&&this.update_layers();break;case 2:A(a);this.plane_write_bm=a;break;case 4:A(a);this.sequencer_memory_mode=a;break;default:A(this.sequencer_index),A(a)}};
|
||||
M.prototype.port3C5_read=function(){A(this.sequencer_index);switch(this.sequencer_index){case 1:return this.clocking_mode;case 2:return this.plane_write_bm;case 4:return this.sequencer_memory_mode;case 6:return 18}return 0};M.prototype.port3C6_write=function(a){this.dac_mask=a};M.prototype.port3C6_read=function(){return this.dac_mask};M.prototype.port3C7_write=function(a){A(a);this.dac_color_index_read=3*a;this.dac_state&=0};M.prototype.port3C7_read=function(){return this.dac_state};
|
||||
M.prototype.port3C8_write=function(a){this.dac_color_index_write=3*a;this.dac_state|=3};M.prototype.port3C8_read=function(){return this.dac_color_index_write/3&255};
|
||||
M.prototype.port3C9_write=function(a){var b=this.dac_color_index_write/3|0,c=this.dac_color_index_write%3,d=this.vga256_palette[b];if(0===(this.dispi_enable_value&32)){a&=63;const e=a&1;a=a<<2|e<<1|e}0===c?d=d&-16711681|a<<16:1===c?d=d&-65281|a<<8:(d=d&-256|a,A(b),A(d));this.vga256_palette[b]!==d&&(this.vga256_palette[b]=d,this.complete_redraw());this.dac_color_index_write++};
|
||||
M.prototype.port3C9_read=function(){var a=this.vga256_palette[this.dac_color_index_read/3|0]>>8*(2-this.dac_color_index_read%3)&255;this.dac_color_index_read++;return this.dispi_enable_value&32?a:a>>2};M.prototype.port3CC_read=function(){return this.miscellaneous_output_register};M.prototype.port3CE_write=function(a){this.graphics_index=a};M.prototype.port3CE_read=function(){return this.graphics_index};
|
||||
M.prototype.port3CF_write=function(a){switch(this.graphics_index){case 0:this.planar_setreset=a;A(a);break;case 1:this.planar_setreset_enable=a;A(a);break;case 2:this.color_compare=a;A(a);break;case 3:this.planar_rotate_reg=a;A(a);break;case 4:this.plane_read=a;A(a);break;case 5:var b=this.planar_mode;this.planar_mode=a;A(a);(b^a)&96&&this.complete_replot();break;case 6:A(a);this.miscellaneous_graphics_register!==a&&(this.miscellaneous_graphics_register=a,this.update_vga_size());break;case 7:this.color_dont_care=
|
||||
a;A(a);break;case 8:this.planar_bitmap=a;A(a);break;default:A(this.graphics_index),A(a)}};M.prototype.port3CF_read=function(){A(this.graphics_index);switch(this.graphics_index){case 0:return this.planar_setreset;case 1:return this.planar_setreset_enable;case 2:return this.color_compare;case 3:return this.planar_rotate_reg;case 4:return this.plane_read;case 5:return this.planar_mode;case 6:return this.miscellaneous_graphics_register;case 7:return this.color_dont_care;case 8:return this.planar_bitmap}return 0};
|
||||
M.prototype.port3D4_write=function(a){this.index_crtc=a};M.prototype.port3D4_read=function(){return this.index_crtc};
|
||||
M.prototype.port3D5_write=function(a){switch(this.index_crtc){case 1:A(a);this.horizontal_display_enable_end!==a&&(this.horizontal_display_enable_end=a,this.update_vga_size());break;case 2:this.horizontal_blank_start!==a&&(this.horizontal_blank_start=a,this.update_vga_size());break;case 7:A(a);var b=this.vertical_display_enable_end;this.vertical_display_enable_end&=255;this.vertical_display_enable_end=this.vertical_display_enable_end|a<<3&512|a<<7&256;b!=this.vertical_display_enable_end&&this.update_vga_size();
|
||||
this.line_compare=this.line_compare&767|a<<4&256;b=this.vertical_blank_start;this.vertical_blank_start=this.vertical_blank_start&767|a<<5&256;b!==this.vertical_blank_start&&this.update_vga_size();this.update_layers();break;case 8:A(a);this.preset_row_scan=a;this.update_layers();break;case 9:A(a);this.max_scan_line=a;this.line_compare=this.line_compare&511|a<<3&512;b=this.vertical_blank_start;this.vertical_blank_start=this.vertical_blank_start&511|a<<4&512;b!==this.vertical_blank_start&&this.update_vga_size();
|
||||
this.update_layers();break;case 10:A(a);this.cursor_scanline_start=a;this.update_cursor_scanline();break;case 11:A(a);this.cursor_scanline_end=a;this.update_cursor_scanline();break;case 12:(this.start_address>>8&255)!==a&&(this.start_address=this.start_address&255|a<<8,this.update_layers(),~this.crtc_mode&3&&this.complete_replot());A(a);A(this.start_address,4);break;case 13:(this.start_address&255)!==a&&(this.start_address=this.start_address&65280|a,this.update_layers(),~this.crtc_mode&3&&this.complete_replot());
|
||||
A(a);A(this.start_address,4);break;case 14:A(a);this.cursor_address=this.cursor_address&255|a<<8;this.update_cursor();break;case 15:A(a);this.cursor_address=this.cursor_address&65280|a;this.update_cursor();break;case 18:A(a);(this.vertical_display_enable_end&255)!==a&&(this.vertical_display_enable_end=this.vertical_display_enable_end&768|a,this.update_vga_size());break;case 19:A(a);this.offset_register!==a&&(this.offset_register=a,this.update_vga_size(),~this.crtc_mode&3&&this.complete_replot());
|
||||
break;case 20:A(a);this.underline_location_register!==a&&(b=this.underline_location_register,this.underline_location_register=a,this.update_vga_size(),(b^a)&64&&this.complete_replot());break;case 21:A(a);(this.vertical_blank_start&255)!==a&&(this.vertical_blank_start=this.vertical_blank_start&768|a,this.update_vga_size());break;case 23:A(a);this.crtc_mode!==a&&(b=this.crtc_mode,this.crtc_mode=a,this.update_vga_size(),(b^a)&67&&this.complete_replot());break;case 24:A(a);this.line_compare=this.line_compare&
|
||||
768|a;this.update_layers();break;default:this.index_crtc<this.crtc.length&&(this.crtc[this.index_crtc]=a),A(this.index_crtc),A(a)}};
|
||||
M.prototype.port3D5_read=function(){A(this.index_crtc);switch(this.index_crtc){case 1:return this.horizontal_display_enable_end;case 2:return this.horizontal_blank_start;case 7:return this.vertical_display_enable_end>>7&2|this.vertical_blank_start>>5&8|this.line_compare>>4&16|this.vertical_display_enable_end>>3&64;case 8:return this.preset_row_scan;case 9:return this.max_scan_line;case 10:return this.cursor_scanline_start;case 11:return this.cursor_scanline_end;case 12:return this.start_address&255;
|
||||
case 13:return this.start_address>>8;case 14:return this.cursor_address>>8;case 15:return this.cursor_address&255;case 18:return this.vertical_display_enable_end&255;case 19:return this.offset_register;case 20:return this.underline_location_register;case 21:return this.vertical_blank_start&255;case 23:return this.crtc_mode;case 24:return this.line_compare&255}return this.index_crtc<this.crtc.length?this.crtc[this.index_crtc]:0};
|
||||
M.prototype.port3DA_read=function(){var a=this.port_3DA_value;this.graphical_mode?(this.port_3DA_value^=1,this.port_3DA_value&=1):(this.port_3DA_value&1&&(this.port_3DA_value^=8),this.port_3DA_value^=1);this.attribute_controller_index=-1;return a};M.prototype.port1CE_write=function(a){this.dispi_index=a};
|
||||
M.prototype.port1CF_write=function(a){A(this.dispi_index);A(a);switch(this.dispi_index){case 0:45248<=a&&45253>=a?this.svga_version=a:A(a);break;case 1:this.svga_width=a;2560<this.svga_width&&(this.svga_width=2560);break;case 2:this.svga_height=a;1600<this.svga_height&&(this.svga_height=1600);break;case 3:this.svga_bpp=a;break;case 4:this.svga_enabled=1===(a&1);this.dispi_enable_value=a;break;case 5:A(a<<16);this.svga_bank_offset=a<<16;break;case 9:const b=a*this.svga_width;A(b);A(a);this.svga_offset_y!==
|
||||
a&&(this.svga_offset_y=a,this.svga_offset=b,this.complete_redraw());break;default:A(this.dispi_index)}!this.svga_enabled||this.svga_width&&this.svga_height||(this.svga_enabled=!1);this.svga_enabled&&4===this.dispi_index&&(this.set_size_graphical(this.svga_width,this.svga_height,this.svga_bpp,this.svga_width,this.svga_height),this.bus.send("screen-set-mode",!0),this.graphical_mode_is_linear=this.graphical_mode=!0);this.svga_enabled||(this.svga_bank_offset=0);this.update_layers()};
|
||||
M.prototype.port1CF_read=function(){A(this.dispi_index);return this.svga_register_read(this.dispi_index)};
|
||||
M.prototype.svga_register_read=function(a){switch(a){case 0:return this.svga_version;case 1:return this.dispi_enable_value&2?2560:this.svga_width;case 2:return this.dispi_enable_value&2?1600:this.svga_height;case 3:return this.dispi_enable_value&2?32:this.svga_bpp;case 4:return this.dispi_enable_value;case 5:return this.svga_bank_offset>>>16;case 6:return this.screen_width?this.screen_width:1;case 8:return 0;case 9:return this.svga_offset_y;case 10:return this.vga_memory_size/65536|0;default:A(this.dispi_index)}return 255};
|
||||
M.prototype.vga_replot=function(){for(var a=this.diff_plot_min&-16,b=Math.min(this.diff_plot_max|15,524287),c=this.vga_addr_shift_count(),d=~this.crtc_mode&3,e=this.planar_mode&96,g=this.attribute_mode&64;a<=b;){var f=a>>>c;if(d){var k=a/this.virtual_width|0,l=a-this.virtual_width*k;switch(d){case 1:f=(k&1)<<13;k>>>=1;break;case 2:f=(k&1)<<14;k>>>=1;break;case 3:f=(k&3)<<13,k>>>=2}f|=(k*this.virtual_width+l>>>c)+this.start_address}k=this.plane0[f];l=this.plane1[f];var m=this.plane2[f],n=this.plane3[f];
|
||||
f=new Uint8Array(8);switch(e){case 0:k<<=0;l<<=1;m<<=2;n<<=3;for(var p=7;0<=p;p--)f[7-p]=k>>p&1|l>>p&2|m>>p&4|n>>p&8;break;case 32:f[0]=k>>6&3|m>>4&12;f[1]=k>>4&3|m>>2&12;f[2]=k>>2&3|m>>0&12;f[3]=k>>0&3|m<<2&12;f[4]=l>>6&3|n>>4&12;f[5]=l>>4&3|n>>2&12;f[6]=l>>2&3|n>>0&12;f[7]=l>>0&3|n<<2&12;break;case 64:case 96:f[0]=k>>4&15,f[1]=k>>0&15,f[2]=l>>4&15,f[3]=l>>0&15,f[4]=m>>4&15,f[5]=m>>0&15,f[6]=n>>4&15,f[7]=n>>0&15}if(g)for(k=p=0;4>p;p++,a++,k+=2)this.pixel_buffer[a]=f[k]<<4|f[k+1];else for(p=0;8>p;p++,
|
||||
a++)this.pixel_buffer[a]=f[p]}};
|
||||
M.prototype.vga_redraw=function(){var a=this.diff_addr_min,b=Math.min(this.diff_addr_max,524287);const c=new Int32Array(this.cpu.wasm_memory.buffer,this.dest_buffet_offset,this.virtual_width*this.virtual_height);var d=255,e=0;this.attribute_mode&128&&(d&=207,e|=this.color_select<<4&48);if(this.attribute_mode&64)for(;a<=b;a++){var g=this.pixel_buffer[a]&d|e;g=this.vga256_palette[g];c[a]=g&65280|g<<16|g>>16|4278190080}else for(d&=63,e|=this.color_select<<4&192;a<=b;a++)g=this.dac_map[this.pixel_buffer[a]&
|
||||
this.color_plane_enable]&d|e,g=this.vga256_palette[g],c[a]=g&65280|g<<16|g>>16|4278190080};
|
||||
M.prototype.screen_fill_buffer=function(){if(this.graphical_mode){if(0===this.image_data.data.byteLength){var a=new Uint8ClampedArray(this.cpu.wasm_memory.buffer,this.dest_buffet_offset,4*this.virtual_width*this.virtual_height);this.image_data=new ImageData(a,this.virtual_width,this.virtual_height);this.update_layers()}if(this.svga_enabled){a=0;let d=this.svga_height;if(8===this.svga_bpp){const e=new Int32Array(this.cpu.wasm_memory.buffer,this.dest_buffet_offset,this.screen_width*this.screen_height),
|
||||
g=new Uint8Array(this.cpu.wasm_memory.buffer,this.svga_memory.byteOffset,this.vga_memory_size);for(var b=0;b<e.length;b++){var c=this.vga256_palette[g[b]];e[b]=c&65280|c<<16|c>>16|4278190080}}else this.cpu.svga_fill_pixel_buffer(this.svga_bpp,this.svga_offset),b=15===this.svga_bpp?2:this.svga_bpp/8,a=((this.cpu.svga_dirty_bitmap_min_offset[0]/b|0)-this.svga_offset)/this.svga_width|0,d=(((this.cpu.svga_dirty_bitmap_max_offset[0]/b|0)-this.svga_offset)/this.svga_width|0)+1;a<d&&(a=Math.max(a,0),d=Math.min(d,
|
||||
this.svga_height),this.bus.send("screen-fill-buffer-end",[{image_data:this.image_data,screen_x:0,screen_y:a,buffer_x:0,buffer_y:a,buffer_width:this.svga_width,buffer_height:d-a}]))}else this.vga_replot(),this.vga_redraw(),this.bus.send("screen-fill-buffer-end",this.layers);this.reset_diffs()}this.update_vertical_retrace()};function N(a,b){this.cpu=a;this.bus=b;this.use_mouse=this.enable_mouse_stream=!1;this.have_mouse=!0;this.mouse_clicks=this.mouse_delta_y=this.mouse_delta_x=0;this.have_keyboard=!0;this.next_read_resolution=this.next_read_rate=this.next_handle_scan_code_set=this.next_read_led=this.next_read_sample=this.next_is_mouse_command=this.enable_keyboard_stream=!1;this.kbd_buffer=new ka(1024);this.last_port60_byte=0;this.sample_rate=100;this.mouse_id=this.mouse_detect_state=0;this.mouse_reset_workaround=!1;
|
||||
this.wheel_movement=0;this.resolution=4;this.scaling2=!1;this.last_mouse_packet=-1;this.mouse_buffer=new ka(1024);this.next_byte_is_aux=this.next_byte_is_ready=!1;this.bus.register("keyboard-code",function(c){this.kbd_send_code(c)},this);this.bus.register("mouse-click",function(c){this.mouse_send_click(c[0],c[1],c[2])},this);this.bus.register("mouse-delta",function(c){this.mouse_send_delta(c[0],c[1])},this);this.bus.register("mouse-wheel",function(c){this.wheel_movement-=c[0];this.wheel_movement-=
|
||||
2*c[1];this.wheel_movement=Math.min(7,Math.max(-8,this.wheel_movement));this.send_mouse_packet(0,0)},this);this.command_register=5;this.controller_output_port=0;this.read_controller_output_port=this.read_command_register=this.read_output_register=!1;a.io.register_read(96,this,this.port60_read);a.io.register_read(100,this,this.port64_read);a.io.register_write(96,this,this.port60_write);a.io.register_write(100,this,this.port64_write)}
|
||||
N.prototype.get_state=function(){var a=[];a[0]=this.enable_mouse_stream;a[1]=this.use_mouse;a[2]=this.have_mouse;a[3]=this.mouse_delta_x;a[4]=this.mouse_delta_y;a[5]=this.mouse_clicks;a[6]=this.have_keyboard;a[7]=this.enable_keyboard_stream;a[8]=this.next_is_mouse_command;a[9]=this.next_read_sample;a[10]=this.next_read_led;a[11]=this.next_handle_scan_code_set;a[12]=this.next_read_rate;a[13]=this.next_read_resolution;a[15]=this.last_port60_byte;a[16]=this.sample_rate;a[17]=this.resolution;a[18]=this.scaling2;
|
||||
a[20]=this.command_register;a[21]=this.read_output_register;a[22]=this.read_command_register;a[23]=this.controller_output_port;a[24]=this.read_controller_output_port;a[25]=this.mouse_id;a[26]=this.mouse_detect_state;a[27]=this.mouse_reset_workaround;return a};
|
||||
N.prototype.set_state=function(a){this.enable_mouse_stream=a[0];this.use_mouse=a[1];this.have_mouse=a[2];this.mouse_delta_x=a[3];this.mouse_delta_y=a[4];this.mouse_clicks=a[5];this.have_keyboard=a[6];this.enable_keyboard_stream=a[7];this.next_is_mouse_command=a[8];this.next_read_sample=a[9];this.next_read_led=a[10];this.next_handle_scan_code_set=a[11];this.next_read_rate=a[12];this.next_read_resolution=a[13];this.last_port60_byte=a[15];this.sample_rate=a[16];this.resolution=a[17];this.scaling2=a[18];
|
||||
this.command_register=a[20];this.read_output_register=a[21];this.read_command_register=a[22];this.controller_output_port=a[23];this.read_controller_output_port=a[24];this.mouse_id=a[25]||0;this.mouse_detect_state=a[26]||0;this.mouse_reset_workaround=a[27]||!1;this.next_byte_is_aux=this.next_byte_is_ready=!1;this.kbd_buffer.clear();this.mouse_buffer.clear();this.bus.send("mouse-enable",this.use_mouse)};
|
||||
N.prototype.raise_irq=function(){this.next_byte_is_ready||(this.kbd_buffer.length?this.kbd_irq():this.mouse_buffer.length&&this.mouse_irq())};N.prototype.mouse_irq=function(){this.next_byte_is_aux=this.next_byte_is_ready=!0;this.command_register&2&&(this.cpu.device_lower_irq(12),this.cpu.device_raise_irq(12))};N.prototype.kbd_irq=function(){this.next_byte_is_ready=!0;this.next_byte_is_aux=!1;this.command_register&1&&(this.cpu.device_lower_irq(1),this.cpu.device_raise_irq(1))};
|
||||
N.prototype.kbd_send_code=function(a){this.enable_keyboard_stream&&(A(a),this.kbd_buffer.push(a),this.raise_irq())};N.prototype.mouse_send_delta=function(a,b){if(this.have_mouse&&this.use_mouse){var c=this.resolution*this.sample_rate/80;this.mouse_delta_x+=a*c;this.mouse_delta_y+=b*c;this.enable_mouse_stream&&(a=this.mouse_delta_x|0,b=this.mouse_delta_y|0,a||b)&&(Date.now(),this.mouse_delta_x-=a,this.mouse_delta_y-=b,this.send_mouse_packet(a,b))}};
|
||||
N.prototype.mouse_send_click=function(a,b,c){this.have_mouse&&this.use_mouse&&(this.mouse_clicks=a|c<<1|b<<2,this.enable_mouse_stream&&this.send_mouse_packet(0,0))};
|
||||
N.prototype.send_mouse_packet=function(a,b){var c=(0>b)<<5|(0>a)<<4|8|this.mouse_clicks;this.last_mouse_packet=Date.now();this.mouse_buffer.push(c);this.mouse_buffer.push(a);this.mouse_buffer.push(b);4===this.mouse_id?(this.mouse_buffer.push(0|this.wheel_movement&15),this.wheel_movement=0):3===this.mouse_id&&(this.mouse_buffer.push(this.wheel_movement&255),this.wheel_movement=0);this.raise_irq()};
|
||||
N.prototype.apply_scaling2=function(a){var b=a>>31;switch(Math.abs(a)){case 0:case 1:case 3:return a;case 2:return b;case 4:return 6*b;case 5:return 9*b;default:return a<<1}};
|
||||
N.prototype.port60_read=function(){this.next_byte_is_ready=!1;if(!this.kbd_buffer.length&&!this.mouse_buffer.length)return this.last_port60_byte;this.next_byte_is_aux?(this.cpu.device_lower_irq(12),this.last_port60_byte=this.mouse_buffer.shift()):(this.cpu.device_lower_irq(1),this.last_port60_byte=this.kbd_buffer.shift());A(this.last_port60_byte);(this.kbd_buffer.length||this.mouse_buffer.length)&&this.raise_irq();return this.last_port60_byte};
|
||||
N.prototype.port64_read=function(){var a=16;this.next_byte_is_ready&&(a|=1);this.next_byte_is_aux&&(a|=32);A(a);return a};
|
||||
N.prototype.port60_write=function(a){A(a);if(this.read_command_register)this.command_register=a,this.read_command_register=!1,A(this.command_register);else if(this.read_output_register)this.read_output_register=!1,this.mouse_buffer.clear(),this.mouse_buffer.push(a),this.mouse_irq();else if(this.next_read_sample){this.next_read_sample=!1;this.mouse_buffer.clear();this.mouse_buffer.push(250);this.sample_rate=a;switch(this.mouse_detect_state){case -1:60===a?(this.mouse_reset_workaround=!0,this.mouse_detect_state=
|
||||
0):(this.mouse_reset_workaround=!1,this.mouse_detect_state=200===a?1:0);break;case 0:200===a&&(this.mouse_detect_state=1);break;case 1:this.mouse_detect_state=100===a?2:200===a?3:0;break;case 2:80===a&&(this.mouse_id=3);this.mouse_detect_state=-1;break;case 3:80===a&&(this.mouse_id=4),this.mouse_detect_state=-1}A(a);A(this.mouse_id);this.sample_rate||(this.sample_rate=100);this.mouse_irq()}else if(this.next_read_resolution)this.next_read_resolution=!1,this.mouse_buffer.clear(),this.mouse_buffer.push(250),
|
||||
this.resolution=3<a?4:1<<a,this.mouse_irq();else if(this.next_read_led)this.next_read_led=!1,this.kbd_buffer.push(250),this.kbd_irq();else if(this.next_handle_scan_code_set)this.next_handle_scan_code_set=!1,this.kbd_buffer.push(250),this.kbd_irq(),a||this.kbd_buffer.push(2);else if(this.next_read_rate)this.next_read_rate=!1,this.kbd_buffer.push(250),this.kbd_irq();else if(this.next_is_mouse_command){if(this.next_is_mouse_command=!1,A(a),this.have_mouse){this.kbd_buffer.clear();this.mouse_buffer.clear();
|
||||
this.mouse_buffer.push(250);switch(a){case 230:this.scaling2=!1;break;case 231:this.scaling2=!0;break;case 232:this.next_read_resolution=!0;break;case 233:this.send_mouse_packet(0,0);break;case 235:this.send_mouse_packet(0,0);break;case 242:A(this.mouse_id);this.mouse_buffer.push(this.mouse_id);this.mouse_clicks=this.mouse_delta_x=this.mouse_delta_y=0;this.raise_irq();break;case 243:this.next_read_sample=!0;break;case 244:this.use_mouse=this.enable_mouse_stream=!0;this.bus.send("mouse-enable",!0);
|
||||
this.mouse_clicks=this.mouse_delta_x=this.mouse_delta_y=0;break;case 245:this.enable_mouse_stream=!1;break;case 246:this.enable_mouse_stream=!1;this.sample_rate=100;this.scaling2=!1;this.resolution=4;break;case 255:this.mouse_buffer.push(170);this.mouse_buffer.push(0);this.use_mouse=!0;this.bus.send("mouse-enable",!0);this.enable_mouse_stream=!1;this.sample_rate=100;this.scaling2=!1;this.resolution=4;this.mouse_reset_workaround||(this.mouse_id=0);this.mouse_clicks=this.mouse_delta_x=this.mouse_delta_y=
|
||||
0;break;default:A(a)}this.mouse_irq()}}else if(this.read_controller_output_port)this.read_controller_output_port=!1,this.controller_output_port=a;else{A(a);this.mouse_buffer.clear();this.kbd_buffer.clear();this.kbd_buffer.push(250);switch(a){case 237:this.next_read_led=!0;break;case 240:this.next_handle_scan_code_set=!0;break;case 242:this.kbd_buffer.push(171);this.kbd_buffer.push(83);break;case 243:this.next_read_rate=!0;break;case 244:this.enable_keyboard_stream=!0;break;case 245:this.enable_keyboard_stream=
|
||||
!1;break;case 246:break;case 255:this.kbd_buffer.clear();this.kbd_buffer.push(250);this.kbd_buffer.push(170);this.kbd_buffer.push(0);break;default:A(a)}this.kbd_irq()}};
|
||||
N.prototype.port64_write=function(a){A(a);switch(a){case 32:this.kbd_buffer.clear();this.mouse_buffer.clear();this.kbd_buffer.push(this.command_register);this.kbd_irq();break;case 96:this.read_command_register=!0;break;case 209:this.read_controller_output_port=!0;break;case 211:this.read_output_register=!0;break;case 212:this.next_is_mouse_command=!0;break;case 167:this.command_register|=32;break;case 168:this.command_register&=-33;break;case 169:this.kbd_buffer.clear();this.mouse_buffer.clear();
|
||||
this.kbd_buffer.push(0);this.kbd_irq();break;case 170:this.kbd_buffer.clear();this.mouse_buffer.clear();this.kbd_buffer.push(85);this.kbd_irq();break;case 171:this.kbd_buffer.clear();this.mouse_buffer.clear();this.kbd_buffer.push(0);this.kbd_irq();break;case 173:this.command_register|=16;break;case 174:this.command_register&=-17;break;case 254:this.cpu.reboot_internal();break;default:A(a)}};function va(a){this.cpu=a;this.cmos_index=0;this.cmos_data=new Uint8Array(128);this.last_update=this.rtc_time=Date.now();this.next_interrupt_alarm=this.next_interrupt=0;this.periodic_interrupt=!1;this.periodic_interrupt_time=.9765625;this.cmos_a=38;this.cmos_b=2;this.nmi_disabled=this.cmos_c=0;a.io.register_write(112,this,function(b){this.cmos_index=b&127;this.nmi_disabled=b>>7});a.io.register_write(113,this,this.cmos_port_write);a.io.register_read(113,this,this.cmos_port_read)}
|
||||
va.prototype.get_state=function(){var a=[];a[0]=this.cmos_index;a[1]=this.cmos_data;a[2]=this.rtc_time;a[3]=this.last_update;a[4]=this.next_interrupt;a[5]=this.next_interrupt_alarm;a[6]=this.periodic_interrupt;a[7]=this.periodic_interrupt_time;a[8]=this.cmos_a;a[9]=this.cmos_b;a[10]=this.cmos_c;a[11]=this.nmi_disabled;return a};
|
||||
va.prototype.set_state=function(a){this.cmos_index=a[0];this.cmos_data=a[1];this.rtc_time=a[2];this.last_update=a[3];this.next_interrupt=a[4];this.next_interrupt_alarm=a[5];this.periodic_interrupt=a[6];this.periodic_interrupt_time=a[7];this.cmos_a=a[8];this.cmos_b=a[9];this.cmos_c=a[10];this.nmi_disabled=a[11]};
|
||||
va.prototype.timer=function(a){a=Date.now();this.rtc_time+=a-this.last_update;this.last_update=a;this.periodic_interrupt&&this.next_interrupt<a?(this.cpu.device_raise_irq(8),this.cmos_c|=192,this.next_interrupt+=this.periodic_interrupt_time*Math.ceil((a-this.next_interrupt)/this.periodic_interrupt_time)):this.next_interrupt_alarm&&this.next_interrupt_alarm<a&&(this.cpu.device_raise_irq(8),this.cmos_c|=160,this.next_interrupt_alarm=0);let b=100;this.periodic_interrupt&&this.next_interrupt&&(b=Math.min(b,
|
||||
Math.max(0,this.next_interrupt-a)));this.next_interrupt_alarm&&(b=Math.min(b,Math.max(0,this.next_interrupt_alarm-a)));return b};va.prototype.bcd_pack=function(a){for(var b=0,c=0,d;a;)d=a%10,c|=d<<4*b,b++,a=(a-d)/10;return c};va.prototype.bcd_unpack=function(a){return(a&15)+10*(a>>4&15)};va.prototype.encode_time=function(a){return this.cmos_b&4?a:this.bcd_pack(a)};va.prototype.decode_time=function(a){return this.cmos_b&4?a:this.bcd_unpack(a)};
|
||||
va.prototype.cmos_port_read=function(){var a=this.cmos_index;switch(a){case 0:return this.encode_time((new Date(this.rtc_time)).getUTCSeconds());case 2:return this.encode_time((new Date(this.rtc_time)).getUTCMinutes());case 4:return this.encode_time((new Date(this.rtc_time)).getUTCHours());case 7:return this.encode_time((new Date(this.rtc_time)).getUTCDate());case 8:return this.encode_time((new Date(this.rtc_time)).getUTCMonth()+1);case 9:return this.encode_time((new Date(this.rtc_time)).getUTCFullYear()%
|
||||
100);case 10:return 999<=D.microtick()%1E3?this.cmos_a|128:this.cmos_a;case 11:return this.cmos_b;case 12:return this.cpu.device_lower_irq(8),a=this.cmos_c,this.cmos_c&=-241,a;case 13:return 0;case 50:return this.encode_time((new Date(this.rtc_time)).getUTCFullYear()/100|0);default:return A(a),this.cmos_data[this.cmos_index]}};
|
||||
va.prototype.cmos_port_write=function(a){switch(this.cmos_index){case 10:this.cmos_a=a&127;this.periodic_interrupt_time=1E3/(32768>>(this.cmos_a&15)-1);A(this.cmos_a,2);break;case 11:this.cmos_b=a;this.cmos_b&64&&(this.next_interrupt=Date.now());if(this.cmos_b&32){a=new Date;const b=this.decode_time(this.cmos_data[1]),c=this.decode_time(this.cmos_data[3]),d=this.decode_time(this.cmos_data[5]);this.next_interrupt_alarm=+new Date(Date.UTC(a.getUTCFullYear(),a.getUTCMonth(),a.getUTCDate(),d,c,b))}A(this.cmos_b,
|
||||
2);break;case 1:case 3:case 5:this.cmos_write(this.cmos_index,a);break;default:A(this.cmos_index),A(a)}this.periodic_interrupt=64===(this.cmos_b&64)&&0<(this.cmos_a&15)};va.prototype.cmos_read=function(a){return this.cmos_data[a]};va.prototype.cmos_write=function(a,b){A(a);A(b);this.cmos_data[a]=b};function wa(a,b,c){this.bus=c;this.cpu=a;this.ints=4;this.line_control=this.baud_rate=0;this.lsr=96;this.ier=this.fifo_control=0;this.iir=1;this.irq=this.scratch_register=this.modem_status=this.modem_control=0;this.input=[];this.current_line="";switch(b){case 1016:this.com=0;this.irq=4;break;case 760:this.com=1;this.irq=3;break;case 1E3:this.com=2;this.irq=4;break;case 744:this.irq=this.com=3;break;default:J("Invalid serial port: "+A(b),16384),this.com=0,this.irq=4}this.bus.register("serial"+this.com+
|
||||
"-input",function(d){this.data_received(d)},this);this.bus.register("serial"+this.com+"-modem-status-input",function(d){this.set_modem_status(d)},this);this.bus.register("serial"+this.com+"-carrier-detect-input",function(d){this.set_modem_status(d?this.modem_status|136:this.modem_status&-137)},this);this.bus.register("serial"+this.com+"-ring-indicator-input",function(d){this.set_modem_status(d?this.modem_status|68:this.modem_status&-69)},this);this.bus.register("serial"+this.com+"-data-set-ready-input",
|
||||
function(d){this.set_modem_status(d?this.modem_status|34:this.modem_status&-35)},this);this.bus.register("serial"+this.com+"-clear-to-send-input",function(d){this.set_modem_status(d?this.modem_status|17:this.modem_status&-18)},this);a=a.io;a.register_write(b,this,function(d){this.write_data(d)},function(d){this.write_data(d&255);this.write_data(d>>8)});a.register_write(b|1,this,function(d){this.line_control&128?(this.baud_rate=this.baud_rate&255|d<<8,A(this.baud_rate)):(0===(this.ier&2)&&d&2&&this.ThrowInterrupt(2),
|
||||
this.ier=d&15,A(d),this.CheckInterrupt())});a.register_read(b,this,function(){if(this.line_control&128)return this.baud_rate&255;let d=0;0!==this.input.length&&(d=this.input.shift(),A(d));0===this.input.length&&(this.lsr&=-2,this.ClearInterrupt(12),this.ClearInterrupt(4));return d});a.register_read(b|1,this,function(){return this.line_control&128?this.baud_rate>>8:this.ier&15});a.register_read(b|2,this,function(){var d=this.iir&15;A(this.iir);2==this.iir&&this.ClearInterrupt(2);this.fifo_control&
|
||||
1&&(d|=192);return d});a.register_write(b|2,this,function(d){A(d);this.fifo_control=d});a.register_read(b|3,this,function(){A(this.line_control);return this.line_control});a.register_write(b|3,this,function(d){A(d);this.line_control=d});a.register_read(b|4,this,function(){return this.modem_control});a.register_write(b|4,this,function(d){A(d);this.modem_control=d});a.register_read(b|5,this,function(){A(this.lsr);return this.lsr});a.register_write(b|5,this,function(){});a.register_read(b|6,this,function(){A(this.modem_status);
|
||||
return this.modem_status&=240});a.register_write(b|6,this,function(d){A(d);this.set_modem_status(d)});a.register_read(b|7,this,function(){return this.scratch_register});a.register_write(b|7,this,function(d){this.scratch_register=d})}wa.prototype.get_state=function(){var a=[];a[0]=this.ints;a[1]=this.baud_rate;a[2]=this.line_control;a[3]=this.lsr;a[4]=this.fifo_control;a[5]=this.ier;a[6]=this.iir;a[7]=this.modem_control;a[8]=this.modem_status;a[9]=this.scratch_register;a[10]=this.irq;return a};
|
||||
wa.prototype.set_state=function(a){this.ints=a[0];this.baud_rate=a[1];this.line_control=a[2];this.lsr=a[3];this.fifo_control=a[4];this.ier=a[5];this.iir=a[6];this.modem_control=a[7];this.modem_status=a[8];this.scratch_register=a[9];this.irq=a[10]};
|
||||
wa.prototype.CheckInterrupt=function(){this.ints&4096&&this.ier&1?(this.iir=12,this.cpu.device_raise_irq(this.irq)):this.ints&16&&this.ier&1?(this.iir=4,this.cpu.device_raise_irq(this.irq)):this.ints&4&&this.ier&2?(this.iir=2,this.cpu.device_raise_irq(this.irq)):this.ints&1&&this.ier&8?(this.iir=0,this.cpu.device_raise_irq(this.irq)):(this.iir=1,this.cpu.device_lower_irq(this.irq))};wa.prototype.ThrowInterrupt=function(a){this.ints|=1<<a;this.CheckInterrupt()};
|
||||
wa.prototype.ClearInterrupt=function(a){this.ints&=~(1<<a);this.CheckInterrupt()};wa.prototype.data_received=function(a){A(a);this.input.push(a);this.lsr|=1;this.fifo_control&1?this.ThrowInterrupt(12):this.ThrowInterrupt(4)};wa.prototype.write_data=function(a){this.line_control&128?this.baud_rate=this.baud_rate&-256|a:(A(a),this.ThrowInterrupt(2),this.bus.send("serial"+this.com+"-output-byte",a))};
|
||||
wa.prototype.set_modem_status=function(a){A(a);const b=this.modem_status&15;let c=(this.modem_status^a)>>4;this.modem_status=a;this.modem_status=this.modem_status|c|b};function xa(a){this.cpu=a;var b=a.io;a.devices.pci.register_device({pci_id:56,pci_space:[134,128,19,113,7,0,128,2,8,0,128,6,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,1,0,0],pci_bars:[],name:"acpi"});this.timer_imprecision_offset=this.timer_last_value=0;this.status=1;this.pm1_enable=this.pm1_status=0;this.last_timer=this.get_timer(D.microtick());this.gpe=new Uint8Array(4);b.register_read(45056,this,void 0,function(){return this.pm1_status});
|
||||
b.register_write(45056,this,void 0,function(c){A(c,4);this.pm1_status&=~c});b.register_read(45058,this,void 0,function(){return this.pm1_enable});b.register_write(45058,this,void 0,function(c){A(c);this.pm1_enable=c});b.register_read(45060,this,void 0,function(){return this.status});b.register_write(45060,this,void 0,function(c){A(c);this.status=c});b.register_read(45064,this,void 0,void 0,function(){return this.get_timer(D.microtick())&16777215});b.register_read(45024,this,function(){return this.gpe[0]});
|
||||
b.register_read(45025,this,function(){return this.gpe[1]});b.register_read(45026,this,function(){return this.gpe[2]});b.register_read(45027,this,function(){return this.gpe[3]});b.register_write(45024,this,function(c){A(c);this.gpe[0]=c});b.register_write(45025,this,function(c){A(c);this.gpe[1]=c});b.register_write(45026,this,function(c){A(c);this.gpe[2]=c});b.register_write(45027,this,function(c){A(c);this.gpe[3]=c})}
|
||||
xa.prototype.timer=function(a){a=this.get_timer(a);var b=0!==((a^this.last_timer)&8388608);this.pm1_enable&1&&b?(this.pm1_status|=1,this.cpu.device_raise_irq(9)):this.cpu.device_lower_irq(9);this.last_timer=a;return 100};
|
||||
xa.prototype.get_timer=function(a){a=Math.round(3579.545*a);a===this.timer_last_value?3579.545>this.timer_imprecision_offset&&this.timer_imprecision_offset++:this.timer_last_value+this.timer_imprecision_offset<=a&&(this.timer_imprecision_offset=0,this.timer_last_value=a);return this.timer_last_value+this.timer_imprecision_offset};xa.prototype.get_state=function(){var a=[];a[0]=this.status;a[1]=this.pm1_status;a[2]=this.pm1_enable;a[3]=this.gpe;return a};
|
||||
xa.prototype.set_state=function(a){this.status=a[0];this.pm1_status=a[1];this.pm1_enable=a[2];this.gpe=a[3]};function O(a){this.cpu=a;this.timer_divider=this.apic_id=0;this.timer_divider_shift=1;this.timer_current_count=this.timer_initial_count=0;this.next_tick=D.microtick();this.lvt_error=this.lvt_int1=this.lvt_int0=this.lvt_perf_counter=this.lvt_timer=65536;this.icr1=this.icr0=this.tpr=0;this.irr=new Int32Array(8);this.isr=new Int32Array(8);this.tmr=new Int32Array(8);this.spurious_vector=254;this.destination_format=-1;this.read_error=this.error=this.local_destination=0;a.io.mmap_register(4276092928,1048576,
|
||||
b=>{A(b>>>0);var c=b&3;return this.read32(b&-4)>>8*c&255},(b,c)=>{A(b);A(c)},b=>this.read32(b),(b,c)=>this.write32(b,c))}
|
||||
O.prototype.read32=function(a){a=a-4276092928|0;switch(a){case 32:return this.apic_id;case 48:return 327700;case 128:return this.tpr;case 208:return this.local_destination;case 224:return this.destination_format;case 240:return this.spurious_vector;case 256:case 272:case 288:case 304:case 320:case 336:case 352:case 368:return a=a-256>>4,A(this.isr[a]>>>0,8),this.isr[a];case 384:case 400:case 416:case 432:case 448:case 464:case 480:case 496:return a=a-384>>4,A(this.tmr[a]>>>0,8),this.tmr[a];case 512:case 528:case 544:case 560:case 576:case 592:case 608:case 624:return a=
|
||||
a-512>>4,A(this.irr[a]>>>0,8),this.irr[a];case 640:return A(this.read_error>>>0,8),this.read_error;case 768:return this.icr0;case 784:return this.icr1;case 800:return this.lvt_timer;case 832:return this.lvt_perf_counter;case 848:return this.lvt_int0;case 864:return this.lvt_int1;case 880:return this.lvt_error;case 992:return this.timer_divider;case 896:return this.timer_initial_count;case 912:return A(this.timer_current_count>>>0,8),this.timer_current_count;default:return A(a),0}};
|
||||
O.prototype.write32=function(a,b){a=a-4276092928|0;switch(a){case 48:A(b>>>0,8);break;case 128:this.tpr=b&255;this.check_vector();break;case 176:b=this.highest_isr();-1!==b&&(this.register_clear_bit(this.isr,b),this.register_get_bit(this.tmr,b)&&this.cpu.devices.ioapic.remote_eoi(b),this.check_vector());break;case 208:A(b>>>0,8);this.local_destination=b&4278190080;break;case 224:A(b>>>0,8);this.destination_format=b|16777215;break;case 240:A(b>>>0,8);this.spurious_vector=b;break;case 640:A(b>>>0,8);
|
||||
this.read_error=this.error;this.error=0;break;case 768:a=b&255;var c=b>>8&7,d=b>>11&1,e=b>>15&1,g=b>>18&3,f=this.icr1>>>24;A(b,8);A(a,2);this.icr0=b&-4097;0===g?this.route(a,c,e,f,d):1===g?this.deliver(a,0,e):2===g&&this.deliver(a,c,e);break;case 784:A(b>>>0,8);this.icr1=b;break;case 800:A(b>>>0,8);this.lvt_timer=b;break;case 832:A(b>>>0,8);this.lvt_perf_counter=b;break;case 848:A(b>>>0,8);this.lvt_int0=b;break;case 864:A(b>>>0,8);this.lvt_int1=b;break;case 880:A(b>>>0,8);this.lvt_error=b;break;case 992:A(b>>>
|
||||
0,8);this.timer_divider=b;b=b&3|(b&8)>>1;this.timer_divider_shift=7===b?0:b+1;break;case 896:A(b>>>0,8);this.timer_initial_count=b>>>0;this.timer_current_count=b>>>0;this.next_tick=D.microtick();this.timer_active=!0;break;case 912:A(b>>>0,8);break;default:A(a),A(b>>>0,8)}};
|
||||
O.prototype.timer=function(a){if(0===this.timer_current_count)return 100;const b=1E6/(1<<this.timer_divider_shift);a=(a-this.next_tick)*b>>>0;this.next_tick+=a/b;this.timer_current_count-=a;0>=this.timer_current_count&&(a=this.lvt_timer&393216,131072===a?(this.timer_current_count%=this.timer_initial_count,0>=this.timer_current_count&&(this.timer_current_count+=this.timer_initial_count),0===(this.lvt_timer&65536)&&this.deliver(this.lvt_timer&255,0,!1)):0===a&&(this.timer_current_count=0,0===(this.lvt_timer&
|
||||
65536)&&this.deliver(this.lvt_timer&255,0,!1)));return Math.max(0,this.timer_current_count/b)};O.prototype.route=function(a,b,c){this.deliver(a,b,c)};O.prototype.deliver=function(a,b,c){5!==b&&4!==b&&(this.register_get_bit(this.irr,a)?A(a,2):(this.register_set_bit(this.irr,a),c?this.register_set_bit(this.tmr,a):this.register_clear_bit(this.tmr,a),this.check_vector()))};O.prototype.highest_irr=function(){return this.register_get_highest_bit(this.irr)};O.prototype.highest_isr=function(){return this.register_get_highest_bit(this.isr)};
|
||||
O.prototype.check_vector=function(){var a=this.highest_irr();-1!==a&&(this.highest_isr()>=a||(a&240)<=(this.tpr&240)||this.cpu.handle_irqs())};O.prototype.acknowledge_irq=function(){var a=this.highest_irr();if(-1===a||this.highest_isr()>=a||(a&240)<=(this.tpr&240))return-1;this.register_clear_bit(this.irr,a);this.register_set_bit(this.isr,a);this.check_vector();return a};
|
||||
O.prototype.get_state=function(){var a=[];a[0]=this.apic_id;a[1]=this.timer_divider;a[2]=this.timer_divider_shift;a[3]=this.timer_initial_count;a[4]=this.timer_current_count;a[5]=this.next_tick;a[6]=this.lvt_timer;a[7]=this.lvt_perf_counter;a[8]=this.lvt_int0;a[9]=this.lvt_int1;a[10]=this.lvt_error;a[11]=this.tpr;a[12]=this.icr0;a[13]=this.icr1;a[14]=this.irr;a[15]=this.isr;a[16]=this.tmr;a[17]=this.spurious_vector;a[18]=this.destination_format;a[19]=this.local_destination;a[20]=this.error;a[21]=
|
||||
this.read_error;return a};
|
||||
O.prototype.set_state=function(a){this.apic_id=a[0];this.timer_divider=a[1];this.timer_divider_shift=a[2];this.timer_initial_count=a[3];this.timer_current_count=a[4];this.next_tick=a[5];this.lvt_timer=a[6];this.lvt_perf_counter=a[7];this.lvt_int0=a[8];this.lvt_int1=a[9];this.lvt_error=a[10];this.tpr=a[11];this.icr0=a[12];this.icr1=a[13];this.irr=a[14];this.isr=a[15];this.tmr=a[16];this.spurious_vector=a[17];this.destination_format=a[18];this.local_destination=a[19];this.error=a[20];this.read_error=
|
||||
a[21]};O.prototype.register_get_bit=function(a,b){return a[b>>5]>>(b&31)&1};O.prototype.register_set_bit=function(a,b){a[b>>5]|=1<<(b&31)};O.prototype.register_clear_bit=function(a,b){a[b>>5]&=~(1<<(b&31))};O.prototype.register_get_highest_bit=function(a){for(var b=7;0<=b;b--){var c=a[b];if(c)return r.int_log2(c>>>0)|b<<5}return-1};function ya(a){this.cpu=a;this.ioredtbl_config=new Int32Array(24);this.ioredtbl_destination=new Int32Array(24);for(var b=0;b<this.ioredtbl_config.length;b++)this.ioredtbl_config[b]=65536;this.irq_value=this.irr=this.ioapic_id=this.ioregsel=0;a.io.mmap_register(4273995776,131072,c=>{c=c-4273995776|0;if(16<=c&&20>c)return c-=16,A(this.ioregsel),this.read(this.ioregsel)>>8*c&255;A(c>>>0);return 0},c=>{A(c>>>0)},c=>{c=c-4273995776|0;if(0===c)return this.ioregsel;if(16===c)return this.read(this.ioregsel);
|
||||
A(c>>>0);return 0},(c,d)=>{c=c-4273995776|0;0===c?this.ioregsel=d:16===c?this.write(this.ioregsel,d):(A(c>>>0),A(d>>>0,8))})}ya.prototype.remote_eoi=function(a){for(var b=0;24>b;b++){var c=this.ioredtbl_config[b];(c&255)===a&&c&16384&&(A(b),this.ioredtbl_config[b]&=-16385,this.check_irq(b))}};
|
||||
ya.prototype.check_irq=function(a){var b=1<<a;if(0!==(this.irr&b)){var c=this.ioredtbl_config[a];if(0===(c&65536)){var d=c>>8&7,e=this.ioredtbl_destination[a]>>>24;if(0===(c&32768))this.irr&=~b;else if(this.ioredtbl_config[a]|=16384,c&16384)return;0!==d&&1!==d||this.cpu.devices.apic.route(c&255,d,32768===(c&32768),e,c>>11&1);this.ioredtbl_config[a]&=-4097}}};
|
||||
ya.prototype.set_irq=function(a){if(!(24<=a)){var b=1<<a;0===(this.irq_value&b)&&(this.irq_value|=b,65536!==(this.ioredtbl_config[a]&98304)&&(this.irr|=b,this.check_irq(a)))}};ya.prototype.clear_irq=function(a){if(!(24<=a)){var b=1<<a;(this.irq_value&b)===b&&(this.irq_value&=~b,this.ioredtbl_config[a]&32768&&(this.irr&=~b))}};
|
||||
ya.prototype.read=function(a){if(0===a)return this.ioapic_id<<24;if(1===a)return 1507345;if(2===a)return this.ioapic_id<<24;if(16<=a&&64>a){var b=a-16>>1;a=a&1?this.ioredtbl_destination[b]:this.ioredtbl_config[b];A(b);A(a,8);return a}A(a);return 0};
|
||||
ya.prototype.write=function(a,b){if(0===a)this.ioapic_id=b>>>24&15;else if(1!==a&&2!==a)if(16<=a&&64>a){var c=a-16>>1;a&1?(this.ioredtbl_destination[c]=b&4278190080,A(b>>>0,8),A(c),A(b>>>24,2)):(this.ioredtbl_config[c]=b&110591|this.ioredtbl_config[c]&-110592,a=b&255,A(b>>>0,8),A(c),A(a,2),this.check_irq(c))}else A(a),A(b>>>0,8)};
|
||||
ya.prototype.get_state=function(){var a=[];a[0]=this.ioredtbl_config;a[1]=this.ioredtbl_destination;a[2]=this.ioregsel;a[3]=this.ioapic_id;a[4]=this.irr;a[5]=this.irq_value;return a};ya.prototype.set_state=function(a){this.ioredtbl_config=a[0];this.ioredtbl_destination=a[1];this.ioregsel=a[2];this.ioapic_id=a[3];this.irr=a[4];this.irq_value=a[5]};function za(a){this.message=a}za.prototype=Error();const Aa={Uint8Array,Int8Array,Uint16Array,Int16Array,Uint32Array,Int32Array,Float32Array,Float64Array};
|
||||
function Ba(a,b){if("object"!==typeof a||null===a)return a;if(a instanceof Array)return a.map(e=>Ba(e,b));a.constructor===Object&&console.log(a);if(a.BYTES_PER_ELEMENT){var c=new Uint8Array(a.buffer,a.byteOffset,a.length*a.BYTES_PER_ELEMENT);return{__state_type__:a.constructor.name.replace("bound ",""),buffer_id:b.push(c)-1}}a=a.get_state();c=[];for(var d=0;d<a.length;d++)c[d]=Ba(a[d],b);return c}
|
||||
function Ca(a,b){if("object"!==typeof a||null===a)return a;if(a instanceof Array){for(let c=0;c<a.length;c++)a[c]=Ca(a[c],b);return a}return new Aa[a.__state_type__](b[a.buffer_id])}
|
||||
E.prototype.save_state=function(){for(var a=[],b=Ba(this,a),c=[],d=0,e=0;e<a.length;e++){var g=a[e].byteLength;c[e]={offset:d,length:g};d+=g;d=d+3&-4}e=JSON.stringify({buffer_infos:c,state:b});e=(new TextEncoder).encode(e);b=16+e.length;b=b+3&-4;g=b+d;d=new ArrayBuffer(g);var f=new Int32Array(d,0,4);(new Uint8Array(d,16,e.length)).set(e);b=new Uint8Array(d,b);f[0]=-2039052682;f[1]=6;f[2]=g;f[3]=e.length;for(e=0;e<a.length;e++)b.set(a[e],c[e].offset);return d};
|
||||
E.prototype.restore_state=function(a){function b(p,t){const q=p.length;if(16>q)throw new za("Invalid length: "+q);p=new Int32Array(p.buffer,p.byteOffset,4);if(-2039052682!==p[0])throw new za("Invalid header: "+A(p[0]>>>0));if(6!==p[1])throw new za("Version mismatch: dump="+p[1]+" we=6");if(t&&p[2]!==q)throw new za("Length doesn't match header: real="+q+" header="+p[2]);return p[3]}function c(p){p=(new TextDecoder).decode(p);return JSON.parse(p)}a=new Uint8Array(a);if(4247762216===(new Uint32Array(a.buffer,
|
||||
0,1))[0]){var d=this.zstd_create_ctx(a.length);(new Uint8Array(this.wasm_memory.buffer,this.zstd_get_src_ptr(d),a.length)).set(a);var e=this.zstd_read(d,16),g=new Uint8Array(this.wasm_memory.buffer,e,16),f=b(g,!1);this.zstd_read_free(e,16);e=this.zstd_read(d,f);g=new Uint8Array(this.wasm_memory.buffer,e,f);g=c(g);this.zstd_read_free(e,f);e=g.state;var k=g.buffer_infos;g=[];f=16+f;for(var l of k){k=(f+3&-4)-f;if(1048576<l.length){var m=this.zstd_read(d,k);this.zstd_read_free(m,k);m=new Uint8Array(l.length);
|
||||
g.push(m.buffer);for(var n=0;n<l.length;){const p=Math.min(l.length-n,1048576),t=this.zstd_read(d,p);m.set(new Uint8Array(this.wasm_memory.buffer,t,p),n);this.zstd_read_free(t,p);n+=p}}else m=this.zstd_read(d,k+l.length),n=m+k,g.push(this.wasm_memory.buffer.slice(n,n+l.length)),this.zstd_read_free(m,k+l.length);f+=k+l.length}e=Ca(e,g);this.set_state(e);this.zstd_free_ctx(d)}else{d=b(a,!0);if(0>d||d+12>=a.length)throw new za("Invalid info block length: "+d);l=a.subarray(16,16+d);e=c(l);l=e.state;e=
|
||||
e.buffer_infos;let p=16+d;p=p+3&-4;d=e.map(t=>{const q=p+t.offset;return a.buffer.slice(q,q+t.length)});l=Ca(l,d);this.set_state(l)}};function Da(a,b,c){a[0]===b[0]&&a[1]===b[1]&&a[2]===b[2]&&a[3]===b[3]&&a[4]===b[4]&&a[5]===b[5]&&(a[0]=c[0],a[1]=c[1],a[2]=c[2],a[3]=c[3],a[4]=c[4],a[5]=c[5]);a[6]===b[0]&&a[7]===b[1]&&a[8]===b[2]&&a[9]===b[3]&&a[10]===b[4]&&a[11]===b[5]&&(a[6]=c[0],a[7]=c[1],a[8]=c[2],a[9]=c[3],a[10]=c[4],a[11]=c[5]);var d=a[12]<<8|a[13];if(2048===d){if(a=a.subarray(14),4===a[0]>>4&&17===a[9]){a=a.subarray(20);d=a[0]<<8|a[1];var e=a[2]<<8|a[3];A(a[6]<<8|a[7],4);if(67===d||67===e)if(d=a.subarray(8),e=d[236]<<24|d[237]<<
|
||||
16|d[238]<<8|d[239],1669485411!==e)A(e,8);else for(d[28]===b[0]&&d[29]===b[1]&&d[30]===b[2]&&d[31]===b[3]&&d[32]===b[4]&&d[33]===b[5]&&(d[28]=c[0],d[29]=c[1],d[30]=c[2],d[31]=c[3],d[32]=c[4],d[33]=c[5],a[6]=a[7]=0),e=240;e<d.length;){const g=d[e++];if(255===g)break;const f=d[e++];61===g&&1===d[e+0]&&d[e+1]===b[0]&&d[e+2]===b[1]&&d[e+3]===b[2]&&d[e+4]===b[3]&&d[e+5]===b[4]&&d[e+6]===b[5]&&(d[e+1]=c[0],d[e+2]=c[1],d[e+3]=c[2],d[e+4]=c[3],d[e+5]=c[4],d[e+6]=c[5],a[6]=a[7]=0);e+=f}}}else 2054===d&&(a=
|
||||
a.subarray(14),Ea(a.subarray(8,14)),Ea(a.subarray(18,24)),a[8]===b[0]&&a[9]===b[1]&&a[10]===b[2]&&a[11]===b[3]&&a[12]===b[4]&&a[13]===b[5]&&(a[8]=c[0],a[9]=c[1],a[10]=c[2],a[11]=c[3],a[12]=c[4],a[13]=c[5]))}function Ea(a){return[a[0].toString(16).padStart(2,"0"),a[1].toString(16).padStart(2,"0"),a[2].toString(16).padStart(2,"0"),a[3].toString(16).padStart(2,"0"),a[4].toString(16).padStart(2,"0"),a[5].toString(16).padStart(2,"0")].join(":")}
|
||||
function Fa(a,b,c,d){this.cpu=a;this.pci=a.devices.pci;this.preserve_mac_from_state_image=c;this.mac_address_translation=d;this.bus=b;this.bus.register("net0-receive",function(e){this.receive(e)},this);this.port=768;this.name="ne2k";this.pci_space=[236,16,41,128,3,1,0,0,0,0,0,2,0,0,0,0,this.port&255|1,this.port>>8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,244,26,0,17,0,0,184,254,0,0,0,0,0,0,0,0,0,1,0,0];this.pci_id=40;this.pci_bars=[{size:32}];this.imr=this.isr=0;this.cr=1;this.tpsr=this.tcnt=
|
||||
this.rcnt=this.dcfg=0;this.memory=new Uint8Array(32768);this.txcr=this.rxcr=0;this.tsr=1;this.mac=new Uint8Array([0,34,21,255*Math.random()|0,255*Math.random()|0,255*Math.random()|0]);this.mar=Uint8Array.of(255,255,255,255,255,255,255,255);this.mac_address_in_state=null;for(b=0;6>b;b++)this.memory[b<<1]=this.memory[b<<1|1]=this.mac[b];this.memory[28]=this.memory[29]=87;this.memory[30]=this.memory[31]=87;J("Mac: "+Ea(this.mac),1048576);this.rsar=0;this.pstart=64;this.pstop=128;this.boundary=this.curpg=
|
||||
76;b=a.io;b.register_read(this.port|0,this,function(){return this.cr});b.register_write(this.port|0,this,function(e){this.cr=e;A(e,2);A(this.txcr,2);this.cr&1||(e&24&&0===this.rcnt&&this.do_interrupt(64),e&4&&(e=this.tpsr<<8,e=this.memory.subarray(e,e+this.tcnt),this.mac_address_in_state&&(e=new Uint8Array(e),Da(e,this.mac_address_in_state,this.mac)),this.bus.send("net0-send",e),this.bus.send("eth-transmit-end",[e.length]),this.cr&=-5,this.do_interrupt(2),A(e.byteLength)))});b.register_read(this.port|
|
||||
13,this,function(){return 1===this.get_page()?this.mar[5]:0});b.register_read(this.port|14,this,function(){return 1===this.get_page()?this.mar[6]:0},function(){this.get_page();return 0});b.register_read(this.port|15,this,function(){return 1===this.get_page()?this.mar[7]:0});b.register_read(this.port|31,this,function(){this.get_page();this.do_interrupt(128);return 0});b.register_write(this.port|31,this,function(e){this.get_page();A(e,2)});b.register_read(this.port|1,this,function(){var e=this.get_page();
|
||||
return 0===e?this.pstart:1===e?this.mac[0]:2===e?this.pstart:0});b.register_write(this.port|1,this,function(e){var g=this.get_page();0===g?(A(e,2),this.pstart=e):1===g?(A(e),this.mac[0]=e):A(e)});b.register_read(this.port|2,this,function(){var e=this.get_page();return 0===e?this.pstop:1===e?this.mac[1]:2===e?this.pstop:0});b.register_write(this.port|2,this,function(e){var g=this.get_page();0===g?(A(e,2),e>this.memory.length>>8&&(e=this.memory.length>>8,A(e)),this.pstop=e):1===g?(A(e),this.mac[1]=
|
||||
e):A(e)});b.register_read(this.port|7,this,function(){var e=this.get_page();return 0===e?(A(this.isr,2),this.isr):1===e?(A(this.curpg,2),this.curpg):0});b.register_write(this.port|7,this,function(e){var g=this.get_page();0===g?(A(e,2),this.isr&=~e,this.update_irq()):1===g&&(A(e,2),this.curpg=e)});b.register_write(this.port|13,this,function(e){0===this.get_page()&&(this.txcr=e);A(e,2)});b.register_write(this.port|14,this,function(e){0===this.get_page()?(A(e,2),this.dcfg=e):A(e,2)});b.register_read(this.port|
|
||||
10,this,function(){var e=this.get_page();return 0===e?80:1===e?this.mar[2]:0});b.register_write(this.port|10,this,function(e){0===this.get_page()?(A(e,2),this.rcnt=this.rcnt&65280|e&255):A(e,2)});b.register_read(this.port|11,this,function(){var e=this.get_page();return 0===e?67:1===e?this.mar[3]:0});b.register_write(this.port|11,this,function(e){0===this.get_page()?(A(e,2),this.rcnt=this.rcnt&255|e<<8&65280):A(e,2)});b.register_read(this.port|8,this,function(){var e=this.get_page();return 0===e?this.rsar&
|
||||
255:1===e?this.mar[0]:0});b.register_write(this.port|8,this,function(e){0===this.get_page()?(A(e,2),this.rsar=this.rsar&65280|e&255):A(e,2)});b.register_read(this.port|9,this,function(){var e=this.get_page();return 0===e?this.rsar>>8&255:1===e?this.mar[1]:0});b.register_write(this.port|9,this,function(e){0===this.get_page()?(A(e,2),this.rsar=this.rsar&255|e<<8&65280):A(e,2)});b.register_write(this.port|15,this,function(e){0===this.get_page()?(A(e,2),A(this.isr,2),this.imr=e,this.update_irq()):A(e,
|
||||
2)});b.register_read(this.port|3,this,function(){var e=this.get_page();return 0===e?(A(this.boundary,2),this.boundary):1===e?this.mac[2]:0});b.register_write(this.port|3,this,function(e){var g=this.get_page();0===g?(A(e,2),this.boundary=e):1===g?(A(e),this.mac[2]=e):A(e)});b.register_read(this.port|4,this,function(){var e=this.get_page();return 0===e?this.tsr:1===e?this.mac[3]:0});b.register_write(this.port|4,this,function(e){var g=this.get_page();0===g?(A(e,2),this.tpsr=e):1===g?(A(e),this.mac[3]=
|
||||
e):A(e)});b.register_read(this.port|5,this,function(){var e=this.get_page();return 0===e?0:1===e?this.mac[4]:0});b.register_write(this.port|5,this,function(e){var g=this.get_page();0===g?(A(e,2),this.tcnt=this.tcnt&-256|e):1===g?(A(e),this.mac[4]=e):A(e)});b.register_read(this.port|6,this,function(){var e=this.get_page();return 0===e?0:1===e?this.mac[5]:0});b.register_write(this.port|6,this,function(e){var g=this.get_page();0===g?(A(e,2),this.tcnt=this.tcnt&255|e<<8):1===g?(A(e),this.mac[5]=e):A(e)});
|
||||
b.register_read(this.port|12,this,function(){var e=this.get_page();return 0===e?9:1===e?this.mar[4]:0});b.register_write(this.port|12,this,function(e){0===this.get_page()?(A(e,2),this.rxcr=e):A(e)});b.register_read(this.port|16,this,this.data_port_read8,this.data_port_read16,this.data_port_read32);b.register_write(this.port|16,this,this.data_port_write16,this.data_port_write16,this.data_port_write32);a.devices.pci.register_device(this)}
|
||||
Fa.prototype.get_state=function(){var a=[];a[0]=this.isr;a[1]=this.imr;a[2]=this.cr;a[3]=this.dcfg;a[4]=this.rcnt;a[5]=this.tcnt;a[6]=this.tpsr;a[7]=this.rsar;a[8]=this.pstart;a[9]=this.curpg;a[10]=this.boundary;a[11]=this.pstop;a[12]=this.rxcr;a[13]=this.txcr;a[14]=this.tsr;a[15]=this.mac;a[16]=this.memory;return a};
|
||||
Fa.prototype.set_state=function(a){this.isr=a[0];this.imr=a[1];this.cr=a[2];this.dcfg=a[3];this.rcnt=a[4];this.tcnt=a[5];this.tpsr=a[6];this.rsar=a[7];this.pstart=a[8];this.curpg=a[9];this.boundary=a[10];this.pstop=a[11];this.rxcr=a[12];this.txcr=a[13];this.tsr=a[14];this.preserve_mac_from_state_image?(this.mac=a[15],this.memory=a[16]):this.mac_address_translation&&(this.mac_address_in_state=a[15],this.memory=a[16],Ea(this.mac_address_in_state),Ea(this.mac))};
|
||||
Fa.prototype.do_interrupt=function(a){A(a,2);this.isr|=a;this.update_irq()};Fa.prototype.update_irq=function(){this.imr&this.isr?this.pci.raise_irq(this.pci_id):this.pci.lower_irq(this.pci_id)};Fa.prototype.data_port_write=function(a){if(16>=this.rsar||16384<=this.rsar&&32768>this.rsar)this.memory[this.rsar]=a;this.rsar++;this.rcnt--;this.rsar>=this.pstop<<8&&(this.rsar+=this.pstart-this.pstop<<8);0===this.rcnt&&this.do_interrupt(64)};
|
||||
Fa.prototype.data_port_write16=function(a){this.data_port_write(a);this.dcfg&1&&this.data_port_write(a>>8)};Fa.prototype.data_port_write32=function(a){this.data_port_write(a);this.data_port_write(a>>8);this.data_port_write(a>>16);this.data_port_write(a>>24)};Fa.prototype.data_port_read=function(){let a=0;32768>this.rsar&&(a=this.memory[this.rsar]);this.rsar++;this.rcnt--;this.rsar>=this.pstop<<8&&(this.rsar+=this.pstart-this.pstop<<8);0===this.rcnt&&this.do_interrupt(64);return a};
|
||||
Fa.prototype.data_port_read8=function(){return this.data_port_read16()&255};Fa.prototype.data_port_read16=function(){return this.dcfg&1?this.data_port_read()|this.data_port_read()<<8:this.data_port_read()};Fa.prototype.data_port_read32=function(){return this.data_port_read()|this.data_port_read()<<8|this.data_port_read()<<16|this.data_port_read()<<24};
|
||||
Fa.prototype.receive=function(a){if(!(this.cr&1)&&(this.bus.send("eth-receive-end",[a.length]),this.rxcr&16||this.rxcr&4&&255===a[0]&&255===a[1]&&255===a[2]&&255===a[3]&&255===a[4]&&255===a[5]||!(this.rxcr&8&&1===(a[0]&1)||a[0]!==this.mac[0]||a[1]!==this.mac[1]||a[2]!==this.mac[2]||a[3]!==this.mac[3]||a[4]!==this.mac[4]||a[5]!==this.mac[5]))){this.mac_address_in_state&&(a=new Uint8Array(a),Da(a,this.mac,this.mac_address_in_state));var b=this.curpg<<8,c=Math.max(60,a.length)+4,d=b+4,e=this.curpg+1+
|
||||
(c>>8),g=b+c,f=1+(c>>8),k=this.boundary>this.curpg?this.boundary-this.curpg:this.pstop-this.curpg+this.boundary-this.pstart;k<f&&0!==this.boundary?(A(this.pstart),A(this.pstop),A(this.curpg),A(f),A(this.boundary),A(k)):(g>this.pstop<<8?(g=(this.pstop<<8)-d,this.memory.set(a.subarray(0,g),d),this.memory.set(a.subarray(g),this.pstart<<8),A(g)):(this.memory.set(a,d),60>a.length&&this.memory.fill(0,d+a.length,d+60)),e>=this.pstop&&(e+=this.pstart-this.pstop),this.memory[b]=1,this.memory[b+1]=e,this.memory[b+
|
||||
2]=c,this.memory[b+3]=c>>8,this.curpg=e,A(b),A(c),A(e),this.do_interrupt(1))}};Fa.prototype.get_page=function(){return this.cr>>6&3};var Ga=new Uint8Array(256),Ha=[],Ia=[],Ja=[],Ka=new Uint8Array(256),La=[];
|
||||
function Q(a,b){this.cpu=a;this.bus=b;this.write_buffer=new ka(64);this.read_buffer=new ka(64);this.mixer_current_address=this.command_size=this.command=this.read_buffer_lastvalue=0;this.mixer_registers=new Uint8Array(256);this.mixer_reset();this.dummy_speaker_enabled=!1;this.test_register=0;this.dsp_signed=this.dsp_16bit=this.dsp_stereo=this.dsp_highspeed=!1;this.dac_buffers=[new la(65536),new la(65536)];this.dma=a.devices.dma;this.dma_channel=this.dma_irq=this.dma_bytes_block=this.dma_bytes_left=
|
||||
this.dma_bytes_count=this.dma_sample_count=0;this.dma_channel_8bit=1;this.dma_channel_16bit=5;this.dma_autoinit=!1;this.dma_buffer=new ArrayBuffer(65536);this.dma_buffer_int8=new Int8Array(this.dma_buffer);this.dma_buffer_uint8=new Uint8Array(this.dma_buffer);this.dma_buffer_int16=new Int16Array(this.dma_buffer);this.dma_buffer_uint16=new Uint16Array(this.dma_buffer);this.dma_syncbuffer=new r.SyncBuffer(this.dma_buffer);this.dma_paused=this.dma_waiting_transfer=!1;this.sampling_rate=22050;b.send("dac-tell-sampling-rate",
|
||||
this.sampling_rate);this.bytes_per_sample=1;this.e2_value=170;this.e2_count=0;this.asp_registers=new Uint8Array(256);this.mpu_read_buffer=new ka(64);this.fm_current_address1=this.fm_current_address0=this.mpu_read_buffer_lastvalue=0;this.fm_waveform_select_enable=!1;this.irq=5;this.irq_triggered=new Uint8Array(16);a.io.register_read_consecutive(544,this,this.port2x0_read,this.port2x1_read,this.port2x2_read,this.port2x3_read);a.io.register_read_consecutive(904,this,this.port2x0_read,this.port2x1_read);
|
||||
a.io.register_read_consecutive(548,this,this.port2x4_read,this.port2x5_read);a.io.register_read(550,this,this.port2x6_read);a.io.register_read(551,this,this.port2x7_read);a.io.register_read(552,this,this.port2x8_read);a.io.register_read(553,this,this.port2x9_read);a.io.register_read(554,this,this.port2xA_read);a.io.register_read(555,this,this.port2xB_read);a.io.register_read(556,this,this.port2xC_read);a.io.register_read(557,this,this.port2xD_read);a.io.register_read_consecutive(558,this,this.port2xE_read,
|
||||
this.port2xF_read);a.io.register_write_consecutive(544,this,this.port2x0_write,this.port2x1_write,this.port2x2_write,this.port2x3_write);a.io.register_write_consecutive(904,this,this.port2x0_write,this.port2x1_write);a.io.register_write_consecutive(548,this,this.port2x4_write,this.port2x5_write);a.io.register_write(550,this,this.port2x6_write);a.io.register_write(551,this,this.port2x7_write);a.io.register_write_consecutive(552,this,this.port2x8_write,this.port2x9_write);a.io.register_write(554,this,
|
||||
this.port2xA_write);a.io.register_write(555,this,this.port2xB_write);a.io.register_write(556,this,this.port2xC_write);a.io.register_write(557,this,this.port2xD_write);a.io.register_write(558,this,this.port2xE_write);a.io.register_write(559,this,this.port2xF_write);a.io.register_read_consecutive(816,this,this.port3x0_read,this.port3x1_read);a.io.register_write_consecutive(816,this,this.port3x0_write,this.port3x1_write);this.dma.on_unmask(this.dma_on_unmask,this);b.register("dac-request-data",function(){this.dac_handle_request()},
|
||||
this);b.register("speaker-has-initialized",function(){this.mixer_reset()},this);b.send("speaker-confirm-initialized");this.dsp_reset()}
|
||||
Q.prototype.dsp_reset=function(){this.write_buffer.clear();this.read_buffer.clear();this.command_size=this.command=0;this.dummy_speaker_enabled=!1;this.test_register=0;this.dsp_signed=this.dsp_16bit=this.dsp_stereo=this.dsp_highspeed=!1;this.dac_buffers[0].clear();this.dac_buffers[1].clear();this.dma_channel=this.dma_irq=this.dma_bytes_block=this.dma_bytes_left=this.dma_bytes_count=this.dma_sample_count=0;this.dma_autoinit=!1;this.dma_buffer_uint8.fill(0);this.dma_paused=this.dma_waiting_transfer=
|
||||
!1;this.e2_value=170;this.e2_count=0;this.sampling_rate=22050;this.bytes_per_sample=1;this.lower_irq(1);this.irq_triggered.fill(0);this.asp_registers.fill(0);this.asp_registers[5]=1;this.asp_registers[9]=248};
|
||||
Q.prototype.get_state=function(){var a=[];a[2]=this.read_buffer_lastvalue;a[3]=this.command;a[4]=this.command_size;a[5]=this.mixer_current_address;a[6]=this.mixer_registers;a[7]=this.dummy_speaker_enabled;a[8]=this.test_register;a[9]=this.dsp_highspeed;a[10]=this.dsp_stereo;a[11]=this.dsp_16bit;a[12]=this.dsp_signed;a[15]=this.dma_sample_count;a[16]=this.dma_bytes_count;a[17]=this.dma_bytes_left;a[18]=this.dma_bytes_block;a[19]=this.dma_irq;a[20]=this.dma_channel;a[21]=this.dma_channel_8bit;a[22]=
|
||||
this.dma_channel_16bit;a[23]=this.dma_autoinit;a[24]=this.dma_buffer_uint8;a[25]=this.dma_waiting_transfer;a[26]=this.dma_paused;a[27]=this.sampling_rate;a[28]=this.bytes_per_sample;a[29]=this.e2_value;a[30]=this.e2_count;a[31]=this.asp_registers;a[33]=this.mpu_read_buffer_last_value;a[34]=this.irq;a[35]=this.irq_triggered;return a};
|
||||
Q.prototype.set_state=function(a){this.read_buffer_lastvalue=a[2];this.command=a[3];this.command_size=a[4];this.mixer_current_address=a[5];this.mixer_registers=a[6];this.mixer_full_update();this.dummy_speaker_enabled=a[7];this.test_register=a[8];this.dsp_highspeed=a[9];this.dsp_stereo=a[10];this.dsp_16bit=a[11];this.dsp_signed=a[12];this.dma_sample_count=a[15];this.dma_bytes_count=a[16];this.dma_bytes_left=a[17];this.dma_bytes_block=a[18];this.dma_irq=a[19];this.dma_channel=a[20];this.dma_channel_8bit=
|
||||
a[21];this.dma_channel_16bit=a[22];this.dma_autoinit=a[23];this.dma_buffer_uint8=a[24];this.dma_waiting_transfer=a[25];this.dma_paused=a[26];this.sampling_rate=a[27];this.bytes_per_sample=a[28];this.e2_value=a[29];this.e2_count=a[30];this.asp_registers=a[31];this.mpu_read_buffer_last_value=a[33];this.irq=a[34];this.irq_triggered=a[35];this.dma_buffer=this.dma_buffer_uint8.buffer;this.dma_buffer_int8=new Int8Array(this.dma_buffer);this.dma_buffer_int16=new Int16Array(this.dma_buffer);this.dma_buffer_uint16=
|
||||
new Uint16Array(this.dma_buffer);this.dma_syncbuffer=new r.SyncBuffer(this.dma_buffer);this.dma_paused?this.bus.send("dac-disable"):this.bus.send("dac-enable")};Q.prototype.port2x0_read=function(){return 255};Q.prototype.port2x1_read=function(){return 255};Q.prototype.port2x2_read=function(){return 255};Q.prototype.port2x3_read=function(){return 255};Q.prototype.port2x4_read=function(){return this.mixer_current_address};Q.prototype.port2x5_read=function(){return this.mixer_read(this.mixer_current_address)};
|
||||
Q.prototype.port2x6_read=function(){return 255};Q.prototype.port2x7_read=function(){return 255};Q.prototype.port2x8_read=function(){return 255};Q.prototype.port2x9_read=function(){return 255};Q.prototype.port2xA_read=function(){this.read_buffer.length&&(this.read_buffer_lastvalue=this.read_buffer.shift());A(this.read_buffer_lastvalue);String.fromCharCode(this.read_buffer_lastvalue);return this.read_buffer_lastvalue};Q.prototype.port2xB_read=function(){return 255};Q.prototype.port2xC_read=function(){return 127};
|
||||
Q.prototype.port2xD_read=function(){return 255};Q.prototype.port2xE_read=function(){this.irq_triggered[1]&&this.lower_irq(1);return(this.read_buffer.length&&!this.dsp_highspeed)<<7|127};Q.prototype.port2xF_read=function(){this.lower_irq(2);return 0};Q.prototype.port2x0_write=function(a){A(a);this.fm_current_address0=0};Q.prototype.port2x1_write=function(a){A(a);var b=La[this.fm_current_address0];b||(b=this.fm_default_write);b.call(this,a,0,this.fm_current_address0)};
|
||||
Q.prototype.port2x2_write=function(a){A(a);this.fm_current_address1=0};Q.prototype.port2x3_write=function(a){A(a);var b=La[this.fm_current_address1];b||(b=this.fm_default_write);b.call(this,a,1,this.fm_current_address1)};Q.prototype.port2x4_write=function(a){A(a);this.mixer_current_address=a};Q.prototype.port2x5_write=function(a){A(a);this.mixer_write(this.mixer_current_address,a)};
|
||||
Q.prototype.port2x6_write=function(a){A(a);this.dsp_highspeed?this.dsp_highspeed=!1:a&&this.dsp_reset();this.read_buffer.clear();this.read_buffer.push(170)};Q.prototype.port2x7_write=function(){};Q.prototype.port2x8_write=function(){};Q.prototype.port2x9_write=function(){};Q.prototype.port2xA_write=function(){};Q.prototype.port2xB_write=function(){};
|
||||
Q.prototype.port2xC_write=function(a){0===this.command?(A(a),this.command=a,this.write_buffer.clear(),this.command_size=Ga[a]):(A(a),this.write_buffer.push(a));this.write_buffer.length>=this.command_size&&this.command_do()};Q.prototype.port2xD_write=function(){};Q.prototype.port2xE_write=function(){};Q.prototype.port2xF_write=function(){};
|
||||
Q.prototype.port3x0_read=function(){this.mpu_read_buffer.length&&(this.mpu_read_buffer_lastvalue=this.mpu_read_buffer.shift());A(this.mpu_read_buffer_lastvalue);return this.mpu_read_buffer_lastvalue};Q.prototype.port3x0_write=function(a){A(a)};Q.prototype.port3x1_read=function(){return 0|128*!this.mpu_read_buffer.length};Q.prototype.port3x1_write=function(a){A(a);255==a&&(this.mpu_read_buffer.clear(),this.mpu_read_buffer.push(254))};
|
||||
Q.prototype.command_do=function(){var a=Ha[this.command];a||(a=this.dsp_default_handler);a.call(this);this.command_size=this.command=0;this.write_buffer.clear()};Q.prototype.dsp_default_handler=function(){A(this.command)};function R(a,b,c){c||(c=Q.prototype.dsp_default_handler);for(var d=0;d<a.length;d++)Ga[a[d]]=b,Ha[a[d]]=c}function Ma(a){for(var b=[],c=0;16>c;c++)b.push(a+c);return b}R([14],2,function(){this.asp_registers[this.write_buffer.shift()]=this.write_buffer.shift()});
|
||||
R([15],1,function(){this.read_buffer.clear();this.read_buffer.push(this.asp_registers[this.write_buffer.shift()])});R([16],1,function(){var a=this.write_buffer.shift();a=Na(a/127.5+-1,-1,1);this.dac_buffers[0].push(a);this.dac_buffers[1].push(a);this.bus.send("dac-enable")});R([20,21],2,function(){this.dma_irq=1;this.dma_channel=this.dma_channel_8bit;this.dsp_highspeed=this.dsp_16bit=this.dsp_signed=this.dma_autoinit=!1;this.dma_transfer_size_set();this.dma_transfer_start()});R([22],2);R([23],2);
|
||||
R([28],0,function(){this.dma_irq=1;this.dma_channel=this.dma_channel_8bit;this.dma_autoinit=!0;this.dsp_highspeed=this.dsp_16bit=this.dsp_signed=!1;this.dma_transfer_start()});R([31],0);R([32],0,function(){this.read_buffer.clear();this.read_buffer.push(127)});R([36],2);R([44],0);R([48],0);R([49],0);R([52],0);R([53],0);R([54],0);R([55],0);R([56],0);R([64],1,function(){this.sampling_rate_change(1E6/(256-this.write_buffer.shift())/this.get_channel_count())});
|
||||
R([65,66],2,function(){this.sampling_rate_change(this.write_buffer.shift()<<8|this.write_buffer.shift())});R([72],2,function(){this.dma_transfer_size_set()});R([116],2);R([117],2);R([118],2);R([119],2);R([125],0);R([127],0);R([128],2);R([144],0,function(){this.dma_irq=1;this.dma_channel=this.dma_channel_8bit;this.dma_autoinit=!0;this.dsp_signed=!1;this.dsp_highspeed=!0;this.dsp_16bit=!1;this.dma_transfer_start()});R([145],0);R([152],0);R([153],0);R([160],0);R([168],0);
|
||||
R(Ma(176),3,function(){if(this.command&8)this.dsp_default_handler();else{var a=this.write_buffer.shift();this.dma_irq=2;this.dma_channel=this.dma_channel_16bit;this.dma_autoinit=!!(this.command&4);this.dsp_signed=!!(a&16);this.dsp_stereo=!!(a&32);this.dsp_16bit=!0;this.dma_transfer_size_set();this.dma_transfer_start()}});
|
||||
R(Ma(192),3,function(){if(this.command&8)this.dsp_default_handler();else{var a=this.write_buffer.shift();this.dma_irq=1;this.dma_channel=this.dma_channel_8bit;this.dma_autoinit=!!(this.command&4);this.dsp_signed=!!(a&16);this.dsp_stereo=!!(a&32);this.dsp_16bit=!1;this.dma_transfer_size_set();this.dma_transfer_start()}});R([208],0,function(){this.dma_paused=!0;this.bus.send("dac-disable")});R([209],0,function(){this.dummy_speaker_enabled=!0});R([211],0,function(){this.dummy_speaker_enabled=!1});
|
||||
R([212],0,function(){this.dma_paused=!1;this.bus.send("dac-enable")});R([213],0,function(){this.dma_paused=!0;this.bus.send("dac-disable")});R([214],0,function(){this.dma_paused=!1;this.bus.send("dac-enable")});R([216],0,function(){this.read_buffer.clear();this.read_buffer.push(255*this.dummy_speaker_enabled)});R([217,218],0,function(){this.dma_autoinit=!1});R([224],1,function(){this.read_buffer.clear();this.read_buffer.push(~this.write_buffer.shift())});
|
||||
R([225],0,function(){this.read_buffer.clear();this.read_buffer.push(4);this.read_buffer.push(5)});R([226],1);R([227],0,function(){this.read_buffer.clear();for(var a=0;44>a;a++)this.read_buffer.push("COPYRIGHT (C) CREATIVE TECHNOLOGY LTD, 1992.".charCodeAt(a));this.read_buffer.push(0)});R([228],1,function(){this.test_register=this.write_buffer.shift()});R([232],0,function(){this.read_buffer.clear();this.read_buffer.push(this.test_register)});R([242,243],0,function(){this.raise_irq()});var Oa=new Uint8Array(256);
|
||||
Oa[14]=255;Oa[15]=7;Oa[55]=56;R([249],1,function(){var a=this.write_buffer.shift();this.read_buffer.clear();this.read_buffer.push(Oa[a])});Q.prototype.mixer_read=function(a){var b=Ia[a];b?b=b.call(this):(b=this.mixer_registers[a],A(a),A(b));return b};Q.prototype.mixer_write=function(a,b){var c=Ja[a];c?c.call(this,b):(A(a),A(b))};Q.prototype.mixer_default_read=function(){A(this.mixer_current_address);return this.mixer_registers[this.mixer_current_address]};
|
||||
Q.prototype.mixer_default_write=function(a){A(this.mixer_current_address);A(a);this.mixer_registers[this.mixer_current_address]=a};
|
||||
Q.prototype.mixer_reset=function(){this.mixer_registers[4]=204;this.mixer_registers[34]=204;this.mixer_registers[38]=204;this.mixer_registers[40]=0;this.mixer_registers[46]=0;this.mixer_registers[10]=0;this.mixer_registers[48]=192;this.mixer_registers[49]=192;this.mixer_registers[50]=192;this.mixer_registers[51]=192;this.mixer_registers[52]=192;this.mixer_registers[53]=192;this.mixer_registers[54]=0;this.mixer_registers[55]=0;this.mixer_registers[56]=0;this.mixer_registers[57]=0;this.mixer_registers[59]=
|
||||
0;this.mixer_registers[60]=31;this.mixer_registers[61]=21;this.mixer_registers[62]=11;this.mixer_registers[63]=0;this.mixer_registers[64]=0;this.mixer_registers[65]=0;this.mixer_registers[66]=0;this.mixer_registers[67]=0;this.mixer_registers[68]=128;this.mixer_registers[69]=128;this.mixer_registers[70]=128;this.mixer_registers[71]=128;this.mixer_full_update()};Q.prototype.mixer_full_update=function(){for(var a=1;a<this.mixer_registers.length;a++)Ka[a]||this.mixer_write(a,this.mixer_registers[a])};
|
||||
function Pa(a,b){b||(b=Q.prototype.mixer_default_read);Ia[a]=b}function Qa(a,b){b||(b=Q.prototype.mixer_default_write);Ja[a]=b}function Sa(a,b,c){Ka[a]=1;Ia[a]=function(){return this.mixer_registers[b]&240|this.mixer_registers[c]>>>4};Ja[a]=function(d){this.mixer_registers[a]=d;var e=d<<4&240|this.mixer_registers[c]&15;this.mixer_write(b,d&240|this.mixer_registers[b]&15);this.mixer_write(c,e)}}
|
||||
function Ta(a,b,c){Ia[a]=Q.prototype.mixer_default_read;Ja[a]=function(d){this.mixer_registers[a]=d;this.bus.send("mixer-volume",[b,c,(d>>>2)-62])}}Pa(0,function(){this.mixer_reset();return 0});Qa(0);Sa(4,50,51);Sa(34,48,49);Sa(38,52,53);Sa(40,54,55);Sa(46,56,57);Ta(48,0,0);Ta(49,0,1);Ta(50,2,0);Ta(51,2,1);Pa(59);Qa(59,function(a){this.mixer_registers[59]=a;this.bus.send("mixer-volume",[1,2,6*(a>>>6)-18])});Pa(65);
|
||||
Qa(65,function(a){this.mixer_registers[65]=a;this.bus.send("mixer-gain-left",6*(a>>>6))});Pa(66);Qa(66,function(a){this.mixer_registers[66]=a;this.bus.send("mixer-gain-right",6*(a>>>6))});Pa(68);Qa(68,function(a){this.mixer_registers[68]=a;a>>>=3;this.bus.send("mixer-treble-left",a-(16>a?14:16))});Pa(69);Qa(69,function(a){this.mixer_registers[69]=a;a>>>=3;this.bus.send("mixer-treble-right",a-(16>a?14:16))});Pa(70);
|
||||
Qa(70,function(a){this.mixer_registers[70]=a;a>>>=3;this.bus.send("mixer-bass-right",a-(16>a?14:16))});Pa(71);Qa(71,function(a){this.mixer_registers[71]=a;a>>>=3;this.bus.send("mixer-bass-right",a-(16>a?14:16))});Pa(128,function(){switch(this.irq){case 2:return 1;case 5:return 2;case 7:return 4;case 10:return 8;default:return 0}});Qa(128,function(a){a&1&&(this.irq=2);a&2&&(this.irq=5);a&4&&(this.irq=7);a&8&&(this.irq=10)});
|
||||
Pa(129,function(){var a=0;switch(this.dma_channel_8bit){case 0:a|=1;break;case 1:a|=2;break;case 3:a|=8}switch(this.dma_channel_16bit){case 5:a|=32;break;case 6:a|=64;break;case 7:a|=128}return a});Qa(129,function(a){a&1&&(this.dma_channel_8bit=0);a&2&&(this.dma_channel_8bit=1);a&8&&(this.dma_channel_8bit=3);a&32&&(this.dma_channel_16bit=5);a&64&&(this.dma_channel_16bit=6);a&128&&(this.dma_channel_16bit=7)});Pa(130,function(){for(var a=32,b=0;16>b;b++)a|=b*this.irq_triggered[b];return a});
|
||||
Q.prototype.fm_default_write=function(a,b,c){A(c);A(a)};function T(a,b){b||(b=Q.prototype.fm_default_write);for(var c=0;c<a.length;c++)La[a[c]]=b}function Ua(a,b){for(var c=[];a<=b;a++)c.push(a);return c}var V=new Uint8Array(32);V[0]=0;V[1]=1;V[2]=2;V[3]=3;V[4]=4;V[5]=5;V[8]=6;V[9]=7;V[10]=8;V[11]=9;V[12]=10;V[13]=11;V[16]=12;V[17]=13;V[18]=14;V[19]=15;V[20]=16;V[21]=17;T([1],function(a,b){this.fm_waveform_select_enable[b]=a&1;this.fm_update_waveforms()});T([2]);T([3]);T([4],function(){});
|
||||
T([5],function(a,b,c){0===b&&this.fm_default_write(a,b,c)});T([8],function(){});T(Ua(32,53),function(){});T(Ua(64,85),function(){});T(Ua(96,117),function(){});T(Ua(128,149),function(){});T(Ua(160,168),function(){});T(Ua(176,184),function(){});T([189],function(){});T(Ua(192,200),function(){});T(Ua(224,245),function(){});Q.prototype.fm_update_waveforms=function(){};Q.prototype.sampling_rate_change=function(a){this.sampling_rate=a;this.bus.send("dac-tell-sampling-rate",a)};
|
||||
Q.prototype.get_channel_count=function(){return this.dsp_stereo?2:1};Q.prototype.dma_transfer_size_set=function(){this.dma_sample_count=1+(this.write_buffer.shift()<<0)+(this.write_buffer.shift()<<8)};
|
||||
Q.prototype.dma_transfer_start=function(){this.bytes_per_sample=1;this.dsp_16bit&&(this.bytes_per_sample*=2);this.dma_bytes_count=this.dma_sample_count*this.bytes_per_sample;this.dma_bytes_block=1024*this.bytes_per_sample;this.dma_bytes_block=Math.min(Math.max(this.dma_bytes_count>>2&-4,32),this.dma_bytes_block);this.dma_waiting_transfer=!0;this.dma.channel_mask[this.dma_channel]||this.dma_on_unmask(this.dma_channel)};
|
||||
Q.prototype.dma_on_unmask=function(a){a===this.dma_channel&&this.dma_waiting_transfer&&(this.dma_waiting_transfer=!1,this.dma_bytes_left=this.dma_bytes_count,this.dma_paused=!1,this.bus.send("dac-enable"))};
|
||||
Q.prototype.dma_transfer_next=function(){var a=Math.min(this.dma_bytes_left,this.dma_bytes_block),b=Math.floor(a/this.bytes_per_sample);this.dma.do_write(this.dma_syncbuffer,0,a,this.dma_channel,c=>{c||(this.dma_to_dac(b),this.dma_bytes_left-=a,this.dma_bytes_left||(this.raise_irq(this.dma_irq),this.dma_autoinit&&(this.dma_bytes_left=this.dma_bytes_count)))})};
|
||||
Q.prototype.dma_to_dac=function(a){var b=this.dsp_16bit?32767.5:127.5,c=this.dsp_signed?0:-1,d=this.dsp_stereo?1:2;var e=this.dsp_16bit?this.dsp_signed?this.dma_buffer_int16:this.dma_buffer_uint16:this.dsp_signed?this.dma_buffer_int8:this.dma_buffer_uint8;for(var g=0,f=0;f<a;f++)for(var k=Na(e[f]/b+c,-1,1),l=0;l<d;l++)this.dac_buffers[g].push(k),g^=1;this.dac_send()};Q.prototype.dac_handle_request=function(){!this.dma_bytes_left||this.dma_paused?this.dac_send():this.dma_transfer_next()};
|
||||
Q.prototype.dac_send=function(){if(this.dac_buffers[0].length){var a=this.dac_buffers[0].shift_block(this.dac_buffers[0].length),b=this.dac_buffers[1].shift_block(this.dac_buffers[1].length);this.bus.send("dac-send-data",[a,b],[a.buffer,b.buffer])}};Q.prototype.raise_irq=function(a){this.irq_triggered[a]=1;this.cpu.device_raise_irq(this.irq)};Q.prototype.lower_irq=function(a){this.irq_triggered[a]=0;this.cpu.device_lower_irq(this.irq)};function Na(a,b,c){return(a<b)*b+(a>c)*c+(b<=a&&a<=c)*a};function h(a,b){this.cpu=a;this.pci=a.devices.pci;this.device_id=b.device_id;this.pci_space=[244,26,b.device_id&255,b.device_id>>8,7,5,16,0,1,0,2,0,0,0,0,0,1,168,0,0,0,16,191,254,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,244,26,b.subsystem_device_id&255,b.subsystem_device_id>>8,0,0,0,0,64,0,0,0,0,0,0,0,0,1,0,0];this.pci_space=this.pci_space.concat(r.zeros(256-this.pci_space.length));this.pci_id=b.pci_id;this.pci_bars=[];this.name=b.name;this.driver_feature_select=this.device_feature_select=0;this.device_feature=
|
||||
new Uint32Array(4);this.driver_feature=new Uint32Array(4);for(var c of b.common.features)this.device_feature[c>>>5]|=1<<(c&31),this.driver_feature[c>>>5]|=1<<(c&31);b.common.features.includes(32);this.features_ok=!0;this.device_status=0;this.config_has_changed=!1;this.config_generation=0;this.queues=[];for(const d of b.common.queues)this.queues.push(new W(a,this,d));this.queue_select=0;this.queue_selected=this.queues[0];this.isr_status=0;c=[];c.push(this.create_common_capability(b.common));c.push(this.create_notification_capability(b.notification));
|
||||
c.push(this.create_isr_capability(b.isr_status));b.device_specific&&c.push(this.create_device_specific_capability(b.device_specific));this.init_capabilities(c);a.devices.pci.register_device(this);this.reset()}
|
||||
h.prototype.create_common_capability=function(a){return{type:1,bar:0,port:a.initial_port,use_mmio:!1,offset:0,extra:new Uint8Array(0),struct:[{bytes:4,name:"device_feature_select",read:()=>this.device_feature_select,write:b=>{this.device_feature_select=b}},{bytes:4,name:"device_feature",read:()=>this.device_feature[this.device_feature_select]||0,write:()=>{}},{bytes:4,name:"driver_feature_select",read:()=>this.driver_feature_select,write:b=>{this.driver_feature_select=b}},{bytes:4,name:"driver_feature",
|
||||
read:()=>this.driver_feature[this.driver_feature_select]||0,write:b=>{const c=this.device_feature[this.driver_feature_select];this.driver_feature_select<this.driver_feature.length&&(this.driver_feature[this.driver_feature_select]=b&c);this.features_ok=this.features_ok&&!(b&~c)}},{bytes:2,name:"msix_config",read:()=>65535,write:()=>{}},{bytes:2,name:"num_queues",read:()=>this.queues.length,write:()=>{}},{bytes:1,name:"device_status",read:()=>this.device_status,write:b=>{0===b&&this.reset();b&~this.device_status&
|
||||
4&&this.device_status&64&&this.notify_config_changes();this.features_ok||(b&=-9);this.device_status=b;if(b&~this.device_status&4)a.on_driver_ok()}},{bytes:1,name:"config_generation",read:()=>this.config_generation,write:()=>{}},{bytes:2,name:"queue_select",read:()=>this.queue_select,write:b=>{this.queue_select=b;this.queue_selected=this.queue_select<this.queues.length?this.queues[this.queue_select]:null}},{bytes:2,name:"queue_size",read:()=>this.queue_selected?this.queue_selected.size:0,write:b=>
|
||||
{this.queue_selected&&(b&b-1&&(b=1<<r.int_log2(b-1)+1),b>this.queue_selected.size_supported&&(b=this.queue_selected.size_supported),this.queue_selected.set_size(b))}},{bytes:2,name:"queue_msix_vector",read:()=>65535,write:()=>{}},{bytes:2,name:"queue_enable",read:()=>this.queue_selected?this.queue_selected.enabled|0:0,write:b=>{this.queue_selected&&1===b&&this.queue_selected.is_configured()&&this.queue_selected.enable()}},{bytes:2,name:"queue_notify_off",read:()=>this.queue_selected?this.queue_selected.notify_offset:
|
||||
0,write:()=>{}},{bytes:4,name:"queue_desc (low dword)",read:()=>this.queue_selected?this.queue_selected.desc_addr:0,write:b=>{this.queue_selected&&(this.queue_selected.desc_addr=b)}},{bytes:4,name:"queue_desc (high dword)",read:()=>0,write:()=>{}},{bytes:4,name:"queue_avail (low dword)",read:()=>this.queue_selected?this.queue_selected.avail_addr:0,write:b=>{this.queue_selected&&(this.queue_selected.avail_addr=b)}},{bytes:4,name:"queue_avail (high dword)",read:()=>0,write:()=>{}},{bytes:4,name:"queue_used (low dword)",
|
||||
read:()=>this.queue_selected?this.queue_selected.used_addr:0,write:b=>{this.queue_selected&&(this.queue_selected.used_addr=b)}},{bytes:4,name:"queue_used (high dword)",read:()=>0,write:()=>{}}]}};
|
||||
h.prototype.create_notification_capability=function(a){const b=[];let c;c=a.single_handler?0:2;for(const [d,e]of a.handlers.entries())b.push({bytes:2,name:"notify"+d,read:()=>65535,write:e||(()=>{})});return{type:2,bar:1,port:a.initial_port,use_mmio:!1,offset:0,extra:new Uint8Array([c&255,c>>8&255,c>>16&255,c>>24]),struct:b}};
|
||||
h.prototype.create_isr_capability=function(a){return{type:3,bar:2,port:a.initial_port,use_mmio:!1,offset:0,extra:new Uint8Array(0),struct:[{bytes:1,name:"isr_status",read:()=>{const b=this.isr_status;this.lower_irq();return b},write:()=>{}}]}};h.prototype.create_device_specific_capability=function(a){return{type:4,bar:3,port:a.initial_port,use_mmio:!1,offset:0,extra:new Uint8Array(0),struct:a.struct}};
|
||||
h.prototype.init_capabilities=function(a){let b=this.pci_space[52]=64;var c=b;for(const e of a){a=16+e.extra.length;c=b;b=c+a;var d=e.struct.reduce((g,f)=>g+f.bytes,0);d+=e.offset;d=16>d?16:1<<r.int_log2(d-1)+1;this.pci_bars[e.bar]={size:d};this.pci_space[c]=9;this.pci_space[c+1]=b;this.pci_space[c+2]=a;this.pci_space[c+3]=e.type;this.pci_space[c+4]=e.bar;this.pci_space[c+5]=0;this.pci_space[c+6]=0;this.pci_space[c+7]=0;this.pci_space[c+8]=e.offset&255;this.pci_space[c+9]=e.offset>>>8&255;this.pci_space[c+
|
||||
10]=e.offset>>>16&255;this.pci_space[c+11]=e.offset>>>24;this.pci_space[c+12]=d&255;this.pci_space[c+13]=d>>>8&255;this.pci_space[c+14]=d>>>16&255;this.pci_space[c+15]=d>>>24;for(const [g,f]of e.extra.entries())this.pci_space[c+16+g]=f;c=16+4*e.bar;this.pci_space[c]=e.port&254|!e.use_mmio;this.pci_space[c+1]=e.port>>>8&255;this.pci_space[c+2]=e.port>>>16&255;this.pci_space[c+3]=e.port>>>24&255;c=e.port+e.offset;for(const g of e.struct){let f=g.read;a=g.write;if(!e.use_mmio){d=function(l){return f(l&
|
||||
-2)>>((l&1)<<3)&255};const k=function(l){return f(l&-4)>>((l&3)<<3)&255};switch(g.bytes){case 4:this.cpu.io.register_read(c,this,k,void 0,f);this.cpu.io.register_write(c,this,void 0,void 0,a);break;case 2:this.cpu.io.register_read(c,this,d,f);this.cpu.io.register_write(c,this,void 0,a);break;case 1:this.cpu.io.register_read(c,this,f),this.cpu.io.register_write(c,this,a)}}c+=g.bytes}}this.pci_space[b]=9;this.pci_space[b+1]=0;this.pci_space[b+2]=20;this.pci_space[b+3]=5;this.pci_space[b+4]=0;this.pci_space[b+
|
||||
5]=0;this.pci_space[b+6]=0;this.pci_space[b+7]=0;this.pci_space[b+8]=0;this.pci_space[b+9]=0;this.pci_space[b+10]=0;this.pci_space[b+11]=0;this.pci_space[b+12]=0;this.pci_space[b+13]=0;this.pci_space[b+14]=0;this.pci_space[b+15]=0;this.pci_space[b+16]=0;this.pci_space[b+17]=0;this.pci_space[b+18]=0;this.pci_space[b+19]=0};
|
||||
h.prototype.get_state=function(){let a=[];a[0]=this.device_feature_select;a[1]=this.driver_feature_select;a[2]=this.device_feature;a[3]=this.driver_feature;a[4]=this.features_ok;a[5]=this.device_status;a[6]=this.config_has_changed;a[7]=this.config_generation;a[8]=this.isr_status;a[9]=this.queue_select;return a=a.concat(this.queues)};
|
||||
h.prototype.set_state=function(a){this.device_feature_select=a[0];this.driver_feature_select=a[1];this.device_feature=a[2];this.driver_feature=a[3];this.features_ok=a[4];this.device_status=a[5];this.config_has_changed=a[6];this.config_generation=a[7];this.isr_status=a[8];this.queue_select=a[9];let b=0;for(let c of a.slice(10))this.queues[b].set_state(c),b++;this.queue_selected=this.queues[this.queue_select]||null};
|
||||
h.prototype.reset=function(){this.driver_feature_select=this.device_feature_select=0;this.driver_feature.set(this.device_feature);this.features_ok=!0;this.queue_select=this.device_status=0;this.queue_selected=this.queues[0];for(const a of this.queues)a.reset();this.config_has_changed=!1;this.config_generation=0;this.lower_irq()};h.prototype.notify_config_changes=function(){this.config_has_changed=!0;this.device_status&4&&this.raise_irq(2)};
|
||||
h.prototype.update_config_generation=function(){this.config_has_changed&&(this.config_generation++,this.config_generation&=255,this.config_has_changed=!1)};h.prototype.is_feature_negotiated=function(a){return 0<(this.driver_feature[a>>>5]&1<<(a&31))};h.prototype.needs_reset=function(){this.device_status|=64;this.device_status&4&&this.notify_config_changes()};h.prototype.raise_irq=function(a){A(a);this.isr_status|=a;this.pci.raise_irq(this.pci_id)};
|
||||
h.prototype.lower_irq=function(){this.isr_status=0;this.pci.lower_irq(this.pci_id)};function W(a,b,c){this.cpu=a;this.virtio=b;this.size_supported=this.size=c.size_supported;this.mask=this.size-1;this.enabled=!1;this.notify_offset=c.notify_offset;this.num_staged_replies=this.used_addr=this.avail_last_idx=this.avail_addr=this.desc_addr=0;this.reset()}
|
||||
W.prototype.get_state=function(){const a=[];a[0]=this.size;a[1]=this.size_supported;a[2]=this.enabled;a[3]=this.notify_offset;a[4]=this.desc_addr;a[5]=this.avail_addr;a[6]=this.avail_last_idx;a[7]=this.used_addr;a[8]=this.num_staged_replies;return a};
|
||||
W.prototype.set_state=function(a){this.size=a[0];this.size_supported=a[1];this.enabled=a[2];this.notify_offset=a[3];this.desc_addr=a[4];this.avail_addr=a[5];this.avail_last_idx=a[6];this.used_addr=a[7];this.num_staged_replies=a[8];this.mask=this.size-1};W.prototype.reset=function(){this.enabled=!1;this.num_staged_replies=this.used_addr=this.avail_last_idx=this.avail_addr=this.desc_addr=0;this.set_size(this.size_supported)};
|
||||
W.prototype.is_configured=function(){return this.desc_addr&&this.avail_addr&&this.used_addr};W.prototype.enable=function(){this.is_configured();this.enabled=!0};W.prototype.set_size=function(a){this.size=a;this.mask=a-1};W.prototype.count_requests=function(){return this.avail_get_idx()-this.avail_last_idx&this.mask};W.prototype.has_request=function(){return(this.avail_get_idx()&this.mask)!==this.avail_last_idx};
|
||||
W.prototype.pop_request=function(){this.has_request();var a=this.avail_get_entry(this.avail_last_idx);a=new Va(this,a);this.avail_last_idx=this.avail_last_idx+1&this.mask;return a};W.prototype.push_reply=function(a){const b=this.used_get_idx()+this.num_staged_replies&this.mask;this.used_set_entry(b,a.head_idx,a.length_written);this.num_staged_replies++};
|
||||
W.prototype.flush_replies=function(){if(0!==this.num_staged_replies){var a=this.used_get_idx()+this.num_staged_replies&65535;this.used_set_idx(a);this.num_staged_replies=0;this.virtio.is_feature_negotiated(29)?(this.avail_get_used_event(),this.virtio.raise_irq(1)):~this.avail_get_flags()&1&&this.virtio.raise_irq(1)}};W.prototype.notify_me_after=function(a){a=this.avail_get_idx()+a&65535;this.used_set_avail_event(a)};
|
||||
W.prototype.get_descriptor=function(a,b){return{addr_low:this.cpu.read32s(a+16*b),addr_high:this.cpu.read32s(a+16*b+4),len:this.cpu.read32s(a+16*b+8),flags:this.cpu.read16(a+16*b+12),next:this.cpu.read16(a+16*b+14)}};W.prototype.avail_get_flags=function(){return this.cpu.read16(this.avail_addr)};W.prototype.avail_get_idx=function(){return this.cpu.read16(this.avail_addr+2)};W.prototype.avail_get_entry=function(a){return this.cpu.read16(this.avail_addr+4+2*a)};
|
||||
W.prototype.avail_get_used_event=function(){return this.cpu.read16(this.avail_addr+4+2*this.size)};W.prototype.used_get_flags=function(){return this.cpu.read16(this.used_addr)};W.prototype.used_set_flags=function(a){this.cpu.write16(this.used_addr,a)};W.prototype.used_get_idx=function(){return this.cpu.read16(this.used_addr+2)};W.prototype.used_set_idx=function(a){this.cpu.write16(this.used_addr+2,a)};
|
||||
W.prototype.used_set_entry=function(a,b,c){this.cpu.write32(this.used_addr+4+8*a,b);this.cpu.write32(this.used_addr+8+8*a,c)};W.prototype.used_set_avail_event=function(a){this.cpu.write16(this.used_addr+4+8*this.size,a)};
|
||||
function Va(a,b){this.cpu=a.cpu;this.virtio=a.virtio;this.head_idx=b;this.read_buffers=[];this.length_readable=this.read_buffer_offset=this.read_buffer_idx=0;this.write_buffers=[];this.length_writable=this.length_written=this.write_buffer_offset=this.write_buffer_idx=0;let c=a.desc_addr,d=0,e=a.size,g=!1;const f=this.virtio.is_feature_negotiated(28);do{const k=a.get_descriptor(c,b);A(k.addr_high,8);A(k.addr_low,8);A(k.len,8);A(k.flags,4);A(k.next,4);if(f&&k.flags&4)c=k.addr_low,d=b=0,e=k.len/16;else{if(k.flags&
|
||||
2)g=!0,this.write_buffers.push(k),this.length_writable+=k.len;else{if(g)break;this.read_buffers.push(k);this.length_readable+=k.len}d++;if(d>e)break;if(k.flags&1)b=k.next;else break}}while(1)}
|
||||
Va.prototype.get_next_blob=function(a){let b=0,c=a.length;for(;c&&this.read_buffer_idx!==this.read_buffers.length;){var d=this.read_buffers[this.read_buffer_idx];const e=d.addr_low+this.read_buffer_offset;d=d.len-this.read_buffer_offset;d>c?(d=c,this.read_buffer_offset+=c):(this.read_buffer_idx++,this.read_buffer_offset=0);a.set(this.cpu.read_blob(e,d),b);b+=d;c-=d}return b};
|
||||
Va.prototype.set_next_blob=function(a){let b=0,c=a.length;for(;c&&this.write_buffer_idx!==this.write_buffers.length;){var d=this.write_buffers[this.write_buffer_idx];const e=d.addr_low+this.write_buffer_offset;d=d.len-this.write_buffer_offset;d>c?(d=c,this.write_buffer_offset+=c):(this.write_buffer_idx++,this.write_buffer_offset=0);this.cpu.write_blob(a.subarray(b,b+d),e);b+=d;c-=d}this.length_written+=b;return b};function Wa(a,b){this.bus=b;this.rows=25;this.cols=80;this.ports=4;b=[{size_supported:16,notify_offset:0},{size_supported:16,notify_offset:1},{size_supported:16,notify_offset:2},{size_supported:16,notify_offset:3}];for(let c=1;c<this.ports;++c)b.push({size_supported:16,notify_offset:0}),b.push({size_supported:8,notify_offset:1});this.virtio=new h(a,{name:"virtio-console",pci_id:56,device_id:4163,subsystem_device_id:3,common:{initial_port:47104,queues:b,features:[0,1,32],on_driver_ok:()=>{}},notification:{initial_port:47360,
|
||||
single_handler:!1,handlers:[c=>{for(c=this.virtio.queues[c];c.count_requests()>c.size-2;)c.pop_request()},c=>{let d=this.virtio.queues[c],e=3<c?c-3>>1:0;for(;d.has_request();){const g=d.pop_request(),f=new Uint8Array(g.length_readable);g.get_next_blob(f);this.bus.send("virtio-console"+e+"-output-bytes",f);this.Ack(c,g)}},c=>{if(2==c)for(c=this.virtio.queues[c];c.count_requests()>c.size-2;)c.pop_request()},c=>{if(3==c)for(var d=this.virtio.queues[c];d.has_request();){var e=d.pop_request(),g=new Uint8Array(e.length_readable);
|
||||
e.get_next_blob(g);var f=v.Unmarshall(["w","h","h"],g,{offset:0});g=f[0];f=f[1];this.Ack(c,e);switch(f){case 0:for(e=0;e<this.ports;++e)this.SendEvent(e,1,0);break;case 3:this.Ack(c,e);this.SendEvent(g,4,1);this.SendName(g,"virtio-"+g);this.SendEvent(g,6,1);break;case 6:this.Ack(c,e);0==g&&this.SendWindowSize(g);break;default:return}}}]},isr_status:{initial_port:46848},device_specific:{initial_port:46592,struct:[{bytes:2,name:"cols",read:()=>this.cols,write:()=>{}},{bytes:2,name:"rows",read:()=>this.rows,
|
||||
write:()=>{}},{bytes:4,name:"max_nr_ports",read:()=>this.ports,write:()=>{}},{bytes:4,name:"emerg_wr",read:()=>0,write:()=>{}}]}});for(let c=0;c<this.ports;++c){let d=0==c?0:2*c+2;this.bus.register("virtio-console"+c+"-input-bytes",function(e){var g=this.virtio.queues[d];g.has_request()&&(g=g.pop_request(),this.Send(d,g,new Uint8Array(e)))},this);this.bus.register("virtio-console"+c+"-resize",function(e){this.cols=e[0];this.rows=e[1];this.virtio.queues[2].is_configured()&&this.virtio.queues[2].has_request()&&
|
||||
this.SendWindowSize(c)},this)}}Wa.prototype.SendWindowSize=function(a){const b=this.virtio.queues[2].pop_request();let c=new Uint8Array(12);v.Marshall(["w","h","h","h","h"],[a,5,0,this.rows,this.cols],c,0);this.Send(2,b,c)};Wa.prototype.SendName=function(a,b){const c=this.virtio.queues[2].pop_request();b=(new TextEncoder).encode(b);let d=new Uint8Array(8+b.length+1);v.Marshall(["w","h","h"],[a,7,1],d,0);for(a=0;a<b.length;++a)d[a+8]=b[a];d[8+b.length]=0;this.Send(2,c,d)};
|
||||
Wa.prototype.get_state=function(){let a=[];a[0]=this.virtio;a[1]=this.rows;a[2]=this.cols;a[3]=this.ports;return a};Wa.prototype.set_state=function(a){this.virtio.set_state(a[0]);this.rows=a[1];this.cols=a[2];this.ports=a[3]};Wa.prototype.Reset=function(){};Wa.prototype.SendEvent=function(a,b,c){const d=this.virtio.queues[2].pop_request();let e=new Uint8Array(8);v.Marshall(["w","h","h"],[a,b,c],e,0);this.Send(2,d,e)};
|
||||
Wa.prototype.Send=function(a,b,c){b.set_next_blob(c);this.virtio.queues[a].push_reply(b);this.virtio.queues[a].flush_replies()};Wa.prototype.Ack=function(a,b){b.set_next_blob(new Uint8Array(0));this.virtio.queues[a].push_reply(b);this.virtio.queues[a].flush_replies()};var Xa={};function Ya(){this.listeners={};this.pair=void 0}Ya.prototype.register=function(a,b,c){var d=this.listeners[a];void 0===d&&(d=this.listeners[a]=[]);d.push({fn:b,this_value:c})};Ya.prototype.unregister=function(a,b){var c=this.listeners[a];void 0!==c&&(this.listeners[a]=c.filter(function(d){return d.fn!==b}))};Ya.prototype.send=function(a,b){if(this.pair&&(a=this.pair.listeners[a],void 0!==a))for(var c=0;c<a.length;c++){var d=a[c];d.fn.call(d.this_value,b)}};
|
||||
Ya.prototype.send_async=function(a,b){setTimeout(this.send.bind(this,a,b),0)};Xa.create=function(){var a=new Ya,b=new Ya;a.pair=b;b.pair=a;return[a,b]};function J(){}function oa(){};function E(a,b,c){this.next_tick_immediately=c;this.wm=b;this.wasm_patch();this.create_jit_imports();this.wasm_memory=b=this.wm.exports.memory;this.memory_size=r.view(Uint32Array,b,812,1);this.mem8=new Uint8Array(0);this.mem32s=new Int32Array(this.mem8.buffer);this.segment_is_null=r.view(Uint8Array,b,724,8);this.segment_offsets=r.view(Int32Array,b,736,8);this.segment_limits=r.view(Uint32Array,b,768,8);this.protected_mode=r.view(Int32Array,b,800,1);this.idtr_size=r.view(Int32Array,b,564,1);this.idtr_offset=
|
||||
r.view(Int32Array,b,568,1);this.gdtr_size=r.view(Int32Array,b,572,1);this.gdtr_offset=r.view(Int32Array,b,576,1);this.tss_size_32=r.view(Int32Array,b,1128,1);this.page_fault=r.view(Uint32Array,b,540,8);this.cr=r.view(Int32Array,b,580,8);this.cpl=r.view(Uint8Array,b,612,1);this.is_32=r.view(Int32Array,b,804,1);this.stack_size_32=r.view(Int32Array,b,808,1);this.in_hlt=r.view(Uint8Array,b,616,1);this.last_virt_eip=r.view(Int32Array,b,620,1);this.eip_phys=r.view(Int32Array,b,624,1);this.sysenter_cs=r.view(Int32Array,
|
||||
b,636,1);this.sysenter_esp=r.view(Int32Array,b,640,1);this.sysenter_eip=r.view(Int32Array,b,644,1);this.prefixes=r.view(Int32Array,b,648,1);this.flags=r.view(Int32Array,b,120,1);this.flags_changed=r.view(Int32Array,b,100,1);this.last_op_size=r.view(Int32Array,b,96,1);this.last_op1=r.view(Int32Array,b,104,1);this.last_result=r.view(Int32Array,b,112,1);this.current_tsc=r.view(Uint32Array,b,960,2);this.devices={};this.instruction_pointer=r.view(Int32Array,b,556,1);this.previous_ip=r.view(Int32Array,
|
||||
b,560,1);this.apic_enabled=r.view(Uint8Array,b,548,1);this.acpi_enabled=r.view(Uint8Array,b,552,1);this.memory_map_read8=[];this.memory_map_write8=[];this.memory_map_read32=[];this.memory_map_write32=[];this.bios={main:null,vga:null};this.instruction_counter=r.view(Uint32Array,b,664,1);this.reg32=r.view(Int32Array,b,64,8);this.fpu_st=r.view(Int32Array,b,1152,32);this.fpu_stack_empty=r.view(Uint8Array,b,816,1);this.fpu_stack_empty[0]=255;this.fpu_stack_ptr=r.view(Uint8Array,b,1032,1);this.fpu_stack_ptr[0]=
|
||||
0;this.fpu_control_word=r.view(Uint16Array,b,1036,1);this.fpu_control_word[0]=895;this.fpu_status_word=r.view(Uint16Array,b,1040,1);this.fpu_status_word[0]=0;this.fpu_ip=r.view(Int32Array,b,1048,1);this.fpu_ip[0]=0;this.fpu_ip_selector=r.view(Int32Array,b,1052,1);this.fpu_ip_selector[0]=0;this.fpu_opcode=r.view(Int32Array,b,1044,1);this.fpu_opcode[0]=0;this.fpu_dp=r.view(Int32Array,b,1056,1);this.fpu_dp[0]=0;this.fpu_dp_selector=r.view(Int32Array,b,1060,1);this.fpu_dp_selector[0]=0;this.reg_xmm32s=
|
||||
r.view(Int32Array,b,832,32);this.mxcsr=r.view(Int32Array,b,824,1);this.sreg=r.view(Uint16Array,b,668,8);this.dreg=r.view(Int32Array,b,684,8);this.reg_pdpte=r.view(Int32Array,b,968,8);this.svga_dirty_bitmap_min_offset=r.view(Uint32Array,b,716,1);this.svga_dirty_bitmap_max_offset=r.view(Uint32Array,b,720,1);this.fw_value=[];this.fw_pointer=0;this.option_roms=[];this.io=void 0;this.bus=a;this.set_tsc(0,0);this.debug_init()}
|
||||
E.prototype.clear_opstats=function(){(new Uint8Array(this.wasm_memory.buffer,32768,131072)).fill(0);this.wm.exports.profiler_init()};E.prototype.create_jit_imports=function(){const a=Object.create(null);a.m=this.wm.exports.memory;for(let b of Object.keys(this.wm.exports))b.startsWith("_")||b.startsWith("zstd")||b.endsWith("_js")||(a[b]=this.wm.exports[b]);this.jit_imports=a};
|
||||
E.prototype.wasm_patch=function(){const a=c=>this.wm.exports[c],b=c=>{const d=a(c);console.assert(d,"Missing import: "+c);return d};this.reset_cpu=b("reset_cpu");this.getiopl=b("getiopl");this.get_eflags=b("get_eflags");this.handle_irqs=b("handle_irqs");this.main_loop=b("main_loop");this.set_jit_config=b("set_jit_config");this.read8=b("read8");this.read16=b("read16");this.read32s=b("read32s");this.write8=b("write8");this.write16=b("write16");this.write32=b("write32");this.in_mapped_range=b("in_mapped_range");
|
||||
this.fpu_load_tag_word=b("fpu_load_tag_word");this.fpu_load_status_word=b("fpu_load_status_word");this.fpu_get_sti_f64=b("fpu_get_sti_f64");this.translate_address_system_read=b("translate_address_system_read_js");this.get_seg_cs=b("get_seg_cs");this.get_real_eip=b("get_real_eip");this.clear_tlb=b("clear_tlb");this.full_clear_tlb=b("full_clear_tlb");this.update_state_flags=b("update_state_flags");this.set_tsc=b("set_tsc");this.store_current_tsc=b("store_current_tsc");this.set_cpuid_level=b("set_cpuid_level");
|
||||
this.pic_set_irq=b("pic_set_irq");this.pic_clear_irq=b("pic_clear_irq");this.jit_clear_cache=b("jit_clear_cache_js");this.jit_dirty_cache=b("jit_dirty_cache");this.codegen_finalize_finished=b("codegen_finalize_finished");this.allocate_memory=b("allocate_memory");this.zero_memory=b("zero_memory");this.svga_allocate_memory=b("svga_allocate_memory");this.svga_allocate_dest_buffer=b("svga_allocate_dest_buffer");this.svga_fill_pixel_buffer=b("svga_fill_pixel_buffer");this.svga_mark_dirty=b("svga_mark_dirty");
|
||||
this.get_pic_addr_master=b("get_pic_addr_master");this.get_pic_addr_slave=b("get_pic_addr_slave");this.zstd_create_ctx=b("zstd_create_ctx");this.zstd_get_src_ptr=b("zstd_get_src_ptr");this.zstd_free_ctx=b("zstd_free_ctx");this.zstd_read=b("zstd_read");this.zstd_read_free=b("zstd_read_free");this.port20_read=b("port20_read");this.port21_read=b("port21_read");this.portA0_read=b("portA0_read");this.portA1_read=b("portA1_read");this.port20_write=b("port20_write");this.port21_write=b("port21_write");this.portA0_write=
|
||||
b("portA0_write");this.portA1_write=b("portA1_write");this.port4D0_read=b("port4D0_read");this.port4D1_read=b("port4D1_read");this.port4D0_write=b("port4D0_write");this.port4D1_write=b("port4D1_write")};E.prototype.jit_force_generate=function(a){this.jit_force_generate_unsafe&&this.jit_force_generate_unsafe(a)};E.prototype.jit_clear_func=function(a){this.wm.wasm_table.set(a+1024,null)};E.prototype.jit_clear_all_funcs=function(){const a=this.wm.wasm_table;for(let b=0;900>b;b++)a.set(1024+b,null)};
|
||||
E.prototype.get_state=function(){var a=[];a[0]=this.memory_size[0];a[1]=this.segment_is_null;a[2]=this.segment_offsets;a[3]=this.segment_limits;a[4]=this.protected_mode[0];a[5]=this.idtr_offset[0];a[6]=this.idtr_size[0];a[7]=this.gdtr_offset[0];a[8]=this.gdtr_size[0];a[9]=this.page_fault[0];a[10]=this.cr;a[11]=this.cpl[0];a[13]=this.is_32[0];a[16]=this.stack_size_32[0];a[17]=this.in_hlt[0];a[18]=this.last_virt_eip[0];a[19]=this.eip_phys[0];a[22]=this.sysenter_cs[0];a[23]=this.sysenter_eip[0];a[24]=
|
||||
this.sysenter_esp[0];a[25]=this.prefixes[0];a[26]=this.flags[0];a[27]=this.flags_changed[0];a[28]=this.last_op1[0];a[30]=this.last_op_size[0];a[37]=this.instruction_pointer[0];a[38]=this.previous_ip[0];a[39]=this.reg32;a[40]=this.sreg;a[41]=this.dreg;a[42]=this.reg_pdpte;this.store_current_tsc();a[43]=this.current_tsc;a[45]=this.devices.virtio_9p;a[46]=this.devices.apic;a[47]=this.devices.rtc;a[48]=this.devices.pci;a[49]=this.devices.dma;a[50]=this.devices.acpi;a[52]=this.devices.vga;a[53]=this.devices.ps2;
|
||||
a[54]=this.devices.uart0;a[55]=this.devices.fdc;a[56]=this.devices.cdrom;a[57]=this.devices.hda;a[58]=this.devices.pit;a[59]=this.devices.net;a[60]=this.get_state_pic();a[61]=this.devices.sb16;a[62]=this.fw_value;a[63]=this.devices.ioapic;a[64]=this.tss_size_32[0];a[66]=this.reg_xmm32s;a[67]=this.fpu_st;a[68]=this.fpu_stack_empty[0];a[69]=this.fpu_stack_ptr[0];a[70]=this.fpu_control_word[0];a[71]=this.fpu_ip[0];a[72]=this.fpu_ip_selector[0];a[73]=this.fpu_dp[0];a[74]=this.fpu_dp_selector[0];a[75]=
|
||||
this.fpu_opcode[0];const {packed_memory:b,bitmap:c}=this.pack_memory();a[77]=b;a[78]=new Uint8Array(c.get_buffer());a[79]=this.devices.uart1;a[80]=this.devices.uart2;a[81]=this.devices.uart3;a[82]=this.devices.virtio_console;return a};
|
||||
E.prototype.get_state_pic=function(){const a=new Uint8Array(this.wasm_memory.buffer,this.get_pic_addr_master(),13),b=new Uint8Array(this.wasm_memory.buffer,this.get_pic_addr_slave(),13),c=[],d=[];c[0]=a[0];c[1]=a[1];c[2]=a[2];c[3]=a[3];c[4]=a[4];c[5]=d;c[6]=a[6];c[7]=a[7];c[8]=a[8];c[9]=a[9];c[10]=a[10];c[11]=a[11];c[12]=a[12];d[0]=b[0];d[1]=b[1];d[2]=b[2];d[3]=b[3];d[4]=b[4];d[5]=null;d[6]=b[6];d[7]=b[7];d[8]=b[8];d[9]=b[9];d[10]=b[10];d[12]=b[12];d[12]=b[12];return c};
|
||||
E.prototype.set_state=function(a){this.memory_size[0]=a[0];this.mem8.length!==this.memory_size[0]&&console.warn("Note: Memory size mismatch. we="+this.mem8.length+" state="+this.memory_size[0]);this.segment_is_null.set(a[1]);this.segment_offsets.set(a[2]);this.segment_limits.set(a[3]);this.protected_mode[0]=a[4];this.idtr_offset[0]=a[5];this.idtr_size[0]=a[6];this.gdtr_offset[0]=a[7];this.gdtr_size[0]=a[8];this.page_fault[0]=a[9];this.cr.set(a[10]);this.cpl[0]=a[11];this.is_32[0]=a[13];this.stack_size_32[0]=
|
||||
a[16];this.in_hlt[0]=a[17];this.last_virt_eip[0]=a[18];this.eip_phys[0]=a[19];this.sysenter_cs[0]=a[22];this.sysenter_eip[0]=a[23];this.sysenter_esp[0]=a[24];this.prefixes[0]=a[25];this.flags[0]=a[26];this.flags_changed[0]=a[27];this.last_op1[0]=a[28];this.last_op_size[0]=a[30];this.instruction_pointer[0]=a[37];this.previous_ip[0]=a[38];this.reg32.set(a[39]);this.sreg.set(a[40]);this.dreg.set(a[41]);a[42]&&this.reg_pdpte.set(a[42]);this.set_tsc(a[43][0],a[43][1]);this.devices.virtio_9p&&this.devices.virtio_9p.set_state(a[45]);
|
||||
this.devices.apic&&this.devices.apic.set_state(a[46]);this.devices.rtc&&this.devices.rtc.set_state(a[47]);this.devices.pci&&this.devices.pci.set_state(a[48]);this.devices.dma&&this.devices.dma.set_state(a[49]);this.devices.acpi&&this.devices.acpi.set_state(a[50]);this.devices.vga&&this.devices.vga.set_state(a[52]);this.devices.ps2&&this.devices.ps2.set_state(a[53]);this.devices.uart0&&this.devices.uart0.set_state(a[54]);this.devices.fdc&&this.devices.fdc.set_state(a[55]);this.devices.cdrom&&this.devices.cdrom.set_state(a[56]);
|
||||
this.devices.hda&&this.devices.hda.set_state(a[57]);this.devices.pit&&this.devices.pit.set_state(a[58]);this.devices.net&&this.devices.net.set_state(a[59]);this.set_state_pic(a[60]);this.devices.sb16&&this.devices.sb16.set_state(a[61]);this.devices.uart1&&this.devices.uart1.set_state(a[79]);this.devices.uart2&&this.devices.uart2.set_state(a[80]);this.devices.uart3&&this.devices.uart3.set_state(a[81]);this.devices.virtio_console&&this.devices.virtio_console.set_state(a[82]);this.fw_value=a[62];this.devices.ioapic&&
|
||||
this.devices.ioapic.set_state(a[63]);this.tss_size_32[0]=a[64];this.reg_xmm32s.set(a[66]);this.fpu_st.set(a[67]);this.fpu_stack_empty[0]=a[68];this.fpu_stack_ptr[0]=a[69];this.fpu_control_word[0]=a[70];this.fpu_ip[0]=a[71];this.fpu_ip_selector[0]=a[72];this.fpu_dp[0]=a[73];this.fpu_dp_selector[0]=a[74];this.fpu_opcode[0]=a[75];const b=new r.Bitmap(a[78].buffer);this.unpack_memory(b,a[77]);this.update_state_flags();this.full_clear_tlb();this.jit_clear_cache()};
|
||||
E.prototype.set_state_pic=function(a){const b=new Uint8Array(this.wasm_memory.buffer,this.get_pic_addr_master(),13),c=new Uint8Array(this.wasm_memory.buffer,this.get_pic_addr_slave(),13);b[0]=a[0];b[1]=a[1];b[2]=a[2];b[3]=a[3];b[4]=a[4];const d=a[5];b[6]=a[6];b[7]=a[7];b[8]=a[8];b[9]=a[9];b[10]=a[10];b[11]=a[11];b[12]=a[12];c[0]=d[0];c[1]=d[1];c[2]=d[2];c[3]=d[3];c[4]=d[4];c[6]=d[6];c[7]=d[7];c[8]=d[8];c[9]=d[9];c[10]=d[10];c[12]=d[12];c[12]=d[12]};
|
||||
E.prototype.pack_memory=function(){var a=this.mem8.length>>12,b=[];for(var c=0;c<a;c++){var d=c<<12;d=this.mem32s.subarray(d>>2,d+4096>>2);let e=!0;for(let g=0;g<d.length;g++)if(0!==d[g]){e=!1;break}e||b.push(c)}a=new r.Bitmap(a);c=new Uint8Array(b.length<<12);for(let [e,g]of b.entries())a.set(g,1),b=g<<12,b=this.mem8.subarray(b,b+4096),c.set(b,e<<12);return{bitmap:a,packed_memory:c}};
|
||||
E.prototype.unpack_memory=function(a,b){this.zero_memory(this.memory_size[0]);const c=this.memory_size[0]>>12;let d=0;for(let g=0;g<c;g++)if(a.get(g)){var e=d<<12;e=b.subarray(e,e+4096);this.mem8.set(e,g<<12);d++}};E.prototype.reboot_internal=function(){this.reset_cpu();this.fw_value=[];this.devices.virtio_9p&&this.devices.virtio_9p.reset();this.devices.virtio_console&&this.devices.virtio_console.reset();this.load_bios()};E.prototype.reset_memory=function(){this.mem8.fill(0)};
|
||||
E.prototype.create_memory=function(a){1048576>a?a=1048576:0>(a|0)&&(a=Math.pow(2,31)-131072);a=(a-1|131071)+1|0;console.assert(0===this.memory_size[0],"Expected uninitialised memory");this.memory_size[0]=a;const b=this.allocate_memory(a);this.mem8=r.view(Uint8Array,this.wasm_memory,b,a);this.mem32s=r.view(Uint32Array,this.wasm_memory,b,a>>2)};F.exportProperty(E.prototype,"create_memory",E.prototype.create_memory);
|
||||
E.prototype.init=function(a,b){this.create_memory("number"===typeof a.memory_size?a.memory_size:67108864);a.disable_jit&&this.set_jit_config(0,1);a.cpuid_level&&this.set_cpuid_level(a.cpuid_level);this.acpi_enabled[0]=+a.acpi;this.reset_cpu();var c=new B(this);this.io=c;this.bios.main=a.bios;this.bios.vga=a.vga_bios;this.load_bios();if(a.bzimage){const e=Za(this.mem8,a.bzimage,a.initrd,a.cmdline||"");e&&this.option_roms.push(e)}c.register_read(179,this,function(){return 0});var d=0;c.register_read(146,
|
||||
this,function(){return d});c.register_write(146,this,function(e){d=e});c.register_read(1297,this,function(){return this.fw_pointer<this.fw_value.length?this.fw_value[this.fw_pointer++]:0});c.register_write(1296,this,void 0,function(e){function g(l){return new Uint8Array(Int32Array.of(l).buffer)}function f(l){return l>>8|l<<8&65280}function k(l){return l<<24|l<<8&16711680|l>>8&65280|l>>>24}J("bios config port, index="+A(e));this.fw_pointer=0;if(0===e)this.fw_value=g(1431127377);else if(1===e)this.fw_value=
|
||||
g(0);else if(3===e)this.fw_value=g(this.memory_size[0]);else if(5===e)this.fw_value=g(1);else if(15===e)this.fw_value=g(1);else if(13===e)this.fw_value=new Uint8Array(16);else if(25===e){e=new Int32Array(4+64*this.option_roms.length);const l=new Uint8Array(e.buffer);e[0]=k(this.option_roms.length);for(let m=0;m<this.option_roms.length;m++){const {name:n,data:p}=this.option_roms[m],t=4+64*m;e[t+0>>2]=k(p.length);e[t+4>>2]=f(49152+m);for(let q=0;q<n.length;q++)l[t+8+q]=n.charCodeAt(q)}this.fw_value=
|
||||
l}else 32768<=e&&49152>e?this.fw_value=g(0):49152<=e&&e-49152<this.option_roms.length?this.fw_value=this.option_roms[e-49152].data:(J("Warning: Unimplemented fw index: "+A(e)),this.fw_value=g(0))});c.register_read(32,this,this.port20_read);c.register_read(33,this,this.port21_read);c.register_read(160,this,this.portA0_read);c.register_read(161,this,this.portA1_read);c.register_write(32,this,this.port20_write);c.register_write(33,this,this.port21_write);c.register_write(160,this,this.portA0_write);
|
||||
c.register_write(161,this,this.portA1_write);c.register_read(1232,this,this.port4D0_read);c.register_read(1233,this,this.port4D1_read);c.register_write(1232,this,this.port4D0_write);c.register_write(1233,this,this.port4D1_write);this.devices={};a.load_devices&&(this.devices.pci=new pa(this),this.acpi_enabled[0]&&(this.devices.ioapic=new ya(this),this.devices.apic=new O(this),this.devices.acpi=new xa(this)),this.devices.rtc=new va(this),this.fill_cmos(this.devices.rtc,a),this.devices.dma=new L(this),
|
||||
this.devices.vga=new M(this,b,a.vga_memory_size||8388608),this.devices.ps2=new N(this,b),this.devices.uart0=new wa(this,1016,b),a.uart1&&(this.devices.uart1=new wa(this,760,b)),a.uart2&&(this.devices.uart2=new wa(this,1E3,b)),a.uart3&&(this.devices.uart3=new wa(this,744,b)),this.devices.fdc=new K(this,a.fda,a.fdb),c=0,a.hda&&(this.devices.hda=new G(this,a.hda,a.hdb,!1,c++,b)),a.cdrom&&(this.devices.cdrom=new G(this,a.cdrom,void 0,!0,c++,b)),this.devices.pit=new qa(this,b),a.enable_ne2k&&(this.devices.net=
|
||||
new Fa(this,b,a.preserve_mac_from_state_image,a.mac_address_translation)),a.fs9p&&(this.devices.virtio_9p=new da(a.fs9p,this,b)),a.virtio_console&&(this.devices.virtio_console=new Wa(this,b)),this.devices.sb16=new Q(this,b));a.multiboot&&(a=this.load_multiboot_option_rom(a.multiboot,a.initrd,a.cmdline))&&(this.bios.main?this.option_roms.push(a):this.reg32[0]=this.io.port_read32(244))};E.prototype.load_multiboot=function(a){this.load_multiboot_option_rom(a,void 0,"")&&(this.reg32[0]=this.io.port_read32(244))};
|
||||
E.prototype.load_multiboot_option_rom=function(a,b,c){if(8192>a.byteLength){var d=new Int32Array(2048);(new Uint8Array(d.buffer)).set(new Uint8Array(a))}else d=new Int32Array(a,0,2048);for(var e=0;8192>e;e+=4){if(464367618===d[e>>2]){var g=d[e+4>>2];if(464367618+g+d[e+8>>2]|0)continue}else continue;J("Multiboot magic found, flags: "+A(g>>>0,8),2);var f=this;this.io.register_read(244,this,function(){return 0},function(){return 0},function(){var n=31860,p=0;if(c){p|=4;f.write32(31760,n);c+="\x00";var t=
|
||||
(new TextEncoder).encode(c);f.write_blob(t,n);n+=t.length}if(g&2){p|=64;t=0;f.write32(31788,0);f.write32(31792,n);var q=0;var z=!1;for(let u=0;4294967296>u;u+=131072)z&&void 0!==f.memory_map_read8[u>>>17]?(f.write32(n,20),f.write32(n+4,q),f.write32(n+8,0),f.write32(n+12,u-q),f.write32(n+16,0),f.write32(n+20,1),n+=24,t+=24,z=!1):z||void 0!==f.memory_map_read8[u>>>17]||(q=u,z=!0);f.write32(31788,t)}f.write32(31744,p);t=p=0;if(g&65536){z=d[e+12>>2];p=d[e+16>>2];var w=d[e+20>>2];t=d[e+24>>2];q=d[e+28>>
|
||||
2];A(z,8);A(p,8);A(w,8);A(t,8);A(q,8);z=new Uint8Array(a,e-(z-p),0===w?void 0:w-p);f.write_blob(z,p);p=q|0;t=Math.max(w,t)}else if(1179403647===d[0]){q=new DataView(a);let [u,I]=$a(q,ab);console.assert(52===I);console.assert(1179403647===u.magic,"Bad magic");console.assert(1===u.class,"Unimplemented: 64 bit elf");console.assert(1===u.data,"Unimplemented: big endian");console.assert(1===u.version0,"Bad version0");console.assert(2===u.type,"Unimplemented type");console.assert(1===u.version1,"Bad version1");
|
||||
console.assert(52===u.ehsize,"Bad header size");console.assert(32===u.phentsize,"Bad program header size");console.assert(40===u.shentsize,"Bad section header size");[p]=bb(new DataView(q.buffer,q.byteOffset+u.phoff,u.phentsize*u.phnum),cb,u.phnum);bb(new DataView(q.buffer,q.byteOffset+u.shoff,u.shentsize*u.shnum),gb,u.shnum);q=u;z=p;p=q.entry;for(w of z)0!==w.type&&(1===w.type?w.paddr+w.memsz<f.memory_size[0]?(w.filesz&&(z=new Uint8Array(a,w.offset,w.filesz),f.write_blob(z,w.paddr)),t=Math.max(t,
|
||||
w.paddr+w.memsz),p===q.entry&&w.vaddr<=p&&w.vaddr+w.memsz>p&&(p=p-w.vaddr+w.paddr)):A(w.paddr):2===w.type||3===w.type||4===w.type||6===w.type||7===w.type||1685382480===w.type||1685382481===w.type||1685382482===w.type||1685382483===w.type||A(w.type))}b&&(f.write32(31764,1),f.write32(31768,n),w=t,0!==(w&4095)&&(w=(w&-4096)+4096),t=w+b.byteLength,f.write32(n,w),f.write32(n+4,t),f.write32(n+8,0),f.write32(n+12,0),f.write_blob(new Uint8Array(b),w));f.reg32[3]=31744;f.cr[0]=1;f.protected_mode[0]=1;f.flags[0]=
|
||||
2;f.is_32[0]=1;f.stack_size_32[0]=1;for(n=0;6>n;n++)f.segment_is_null[n]=0,f.segment_offsets[n]=0,f.segment_limits[n]=4294967295,f.sreg[n]=45058;f.instruction_pointer[0]=f.get_seg_cs()+p|0;f.update_state_flags();f.debug.dump_state();f.debug.dump_regs();return 732803074});this.io.register_write_consecutive(244,this,function(n){console.log("Test exited with code "+A(n,2));throw"HALT";},function(){},function(){},function(){});for(let n=0;15>=n;n++){function p(t){A(n);A(t,2);t?this.device_raise_irq(n):
|
||||
this.device_lower_irq(n)}this.io.register_write(8192+n,this,p,p,p)}const l=new Uint8Array(512);(new Uint16Array(l.buffer))[0]=43605;l[2]=1;var k=3;l[k++]=102;l[k++]=229;l[k++]=244;let m=l[k]=0;for(let n=0;n<l.length;n++)m+=l[n];l[k]=-m;return{name:"genroms/multiboot.bin",data:l}}};
|
||||
E.prototype.fill_cmos=function(a,b){var c=b.boot_order||291;a.cmos_write(56,1|c>>4&240);a.cmos_write(61,c&255);a.cmos_write(21,128);a.cmos_write(22,2);c=0;1048576<=this.memory_size[0]&&(c=this.memory_size[0]-1048576>>10,c=Math.min(c,65535));a.cmos_write(23,c&255);a.cmos_write(24,c>>8&255);a.cmos_write(48,c&255);a.cmos_write(49,c>>8&255);c=0;16777216<=this.memory_size[0]&&(c=this.memory_size[0]-16777216>>16,c=Math.min(c,65535));a.cmos_write(52,c&255);a.cmos_write(53,c>>8&255);a.cmos_write(91,0);a.cmos_write(92,
|
||||
0);a.cmos_write(93,0);a.cmos_write(20,47);a.cmos_write(95,0);b.fastboot&&a.cmos_write(63,1)};
|
||||
E.prototype.load_bios=function(){var a=this.bios.main,b=this.bios.vga;if(a){var c=new Uint8Array(a);this.write_blob(c,1048576-a.byteLength);if(b){var d=new Uint8Array(b);this.write_blob(d,786432);this.io.mmap_register(4272947200,1048576,function(e){e=e-4272947200|0;return e<d.length?d[e]:0},function(){})}this.io.mmap_register(4293918720,1048576,function(e){return this.mem8[e&1048575]}.bind(this),function(e,g){this.mem8[e&1048575]=g}.bind(this))}};
|
||||
E.prototype.codegen_finalize=function(a,b,c,d,e){const g=new Uint8Array(this.wasm_memory.buffer,d>>>0,e>>>0);WebAssembly.instantiate(g,{e:this.jit_imports}).then(f=>{this.wm.wasm_table.set(a+1024,f.instance.exports.f);this.codegen_finalize_finished(a,b,c);this.test_hook_did_finalize_wasm&&this.test_hook_did_finalize_wasm(g)})};E.prototype.log_uncompiled_code=function(){};E.prototype.dump_function_code=function(){};
|
||||
E.prototype.run_hardware_timers=function(a,b){const c=this.devices.pit.timer(b,!1),d=this.devices.rtc.timer(b,!1);let e=100,g=100;a&&(e=this.devices.acpi.timer(b),g=this.devices.apic.timer(b));return Math.min(c,d,e,g)};E.prototype.device_raise_irq=function(a){this.pic_set_irq(a);this.devices.ioapic&&this.devices.ioapic.set_irq(a)};E.prototype.device_lower_irq=function(a){this.pic_clear_irq(a);this.devices.ioapic&&this.devices.ioapic.clear_irq(a)};
|
||||
"undefined"!==typeof window?window.CPU=E:"undefined"!==typeof module&&"undefined"!==typeof module.exports?module.exports.CPU=E:"function"===typeof importScripts&&(self.CPU=E);E.prototype.debug_init=function(){var a=this,b={};this.debug=b;b.init=function(){};b.get_regs_short=function(){};b.dump_regs=function(){};b.get_state=function(){};b.dump_state=function(){};b.dump_stack=function(){};b.dump_page_structures=function(){if(a.cr[4]&32)for(var g=0;4>g;g++)a.read32s(a.cr[3]+8*g)};b.dump_gdt_ldt=function(){};b.dump_idt=function(){};b.get_memory_dump=function(){};b.memory_hex_dump=function(){};b.used_memory_dump=function(){};b.debug_interrupt=function(){};let c,d;b.dump_code=
|
||||
function(g,f,k){if(!d){if(void 0===c&&(c="function"===typeof require?require("./capstone-x86.min.js"):window.cs,void 0===c))return;d=[new c.Capstone(c.ARCH_X86,c.MODE_16),new c.Capstone(c.ARCH_X86,c.MODE_32)]}try{d[g].disasm(f,k).forEach(function(l){J(A(l.address>>>0)+": "+r.pads(l.bytes.map(m=>A(m,2).slice(-2)).join(" "),20)+" "+l.mnemonic+" "+l.op_str)})}catch(l){J("Could not disassemble: "+Array.from(f).map(m=>A(m,2)).join(" "))}};let e;b.dump_wasm=function(g){if(void 0===e&&(e="function"===typeof require?
|
||||
require("./libwabt.js"):new window.WabtModule,void 0===e))return;g=g.slice();try{var f=e.readWasm(g,{readDebugNames:!1});f.generateNames();f.applyNames();f.toText({foldExprs:!0,inlineExport:!0})}catch(m){var k=new Blob([g]),l=document.createElement("a");l.download="failed.wasm";l.href=window.URL.createObjectURL(k);l.dataset.downloadurl=["application/octet-stream",l.download,l.href].join(":");l.click();window.URL.revokeObjectURL(l.src);console.log(m.toString())}finally{f&&f.destroy()}}};let hb=DataView.prototype,ib={size:1,get:hb.getUint8,set:hb.setUint8},jb={size:2,get:hb.getUint16,set:hb.setUint16},X={size:4,get:hb.getUint32,set:hb.setUint32},ab=kb([{magic:X},{class:ib},{data:ib},{version0:ib},{osabi:ib},{abiversion:ib},{pad0:function(a){return{size:a,get:()=>-1}}(7)},{type:jb},{machine:jb},{version1:X},{entry:X},{phoff:X},{shoff:X},{flags:X},{ehsize:jb},{phentsize:jb},{phnum:jb},{shentsize:jb},{shnum:jb},{shstrndx:jb}]);console.assert(52===ab.reduce((a,b)=>a+b.size,0));
|
||||
let cb=kb([{type:X},{offset:X},{vaddr:X},{paddr:X},{filesz:X},{memsz:X},{flags:X},{align:X}]);console.assert(32===cb.reduce((a,b)=>a+b.size,0));let gb=kb([{name:X},{type:X},{flags:X},{addr:X},{offset:X},{size:X},{link:X},{info:X},{addralign:X},{entsize:X}]);console.assert(40===gb.reduce((a,b)=>a+b.size,0));function kb(a){return a.map(function(b){var c=Object.keys(b);console.assert(1===c.length);c=c[0];b=b[c];console.assert(0<b.size);return{name:c,type:b,size:b.size,get:b.get,set:b.set}})}
|
||||
function $a(a,b){let c={},d=0;for(let e of b)b=e.get.call(a,d,!0),console.assert(void 0===c[e.name]),c[e.name]=b,d+=e.size;return[c,d]}function bb(a,b,c){let d=[],e=0;for(var g=0;g<c;g++){let [f,k]=$a(new DataView(a.buffer,a.byteOffset+e,void 0),b);d.push(f);e+=k}return[d,e]};function Za(a,b,c,d){var e=new Uint8Array(b);const g=new Uint16Array(b);var f=new Uint32Array(b),k=e[497]||4,l=g[255];if(43605!==l)A(l);else if(l=g[257]|g[258]<<16,1400005704!==l)A(l);else{l=e[529];var m=g[283],n=f[139],p=f[140],t=e[565],q=f[142],z=f[146],w=f[147],u=f[150],I=f[151],U=f[152];A(g[259]);A(l);A(m);A(f[133]);A(n);A(p);A(t);A(q);A(z);A(w);A(I);A(u);A(U);e[528]=255;e[529]=l&-97|128;g[274]=56832;g[253]=65535;A(56832);d+="\x00";A(581632);f[138]=581632;for(e=0;e<d.length;e++)a[581632+e]=d.charCodeAt(e);
|
||||
k=512*(k+1);A(k);d=new Uint8Array(b,0,k);b=new Uint8Array(b,k);e=k=0;c&&(k=67108864,e=c.byteLength,a.set(new Uint8Array(c),k));f[134]=k;f[135]=e;a.set(d,524288);a.set(b,1048576);a=new Uint8Array(512);(new Uint16Array(a.buffer))[0]=43605;a[2]=1;c=3;a[c++]=250;a[c++]=184;a[c++]=32768;a[c++]=128;a[c++]=142;a[c++]=192;a[c++]=142;a[c++]=216;a[c++]=142;a[c++]=224;a[c++]=142;a[c++]=232;a[c++]=142;a[c++]=208;a[c++]=188;a[c++]=57344;a[c++]=224;a[c++]=234;a[c++]=0;a[c++]=0;a[c++]=32800;a[c++]=128;f=a[c]=0;
|
||||
for(b=0;b<a.length;b++)f+=a[b];a[c]=-f;return{name:"genroms/kernel.bin",data:a}}};function lb(a){function b(q){!q.altKey&&k[56]&&g(56,!1);return e(q,!1)}function c(q){!q.altKey&&k[56]&&g(56,!1);return e(q,!0)}function d(){for(var q=Object.keys(k),z,w=0;w<q.length;w++)z=+q[w],k[z]&&g(z,!1);k={}}function e(q,z){var w;if(w=l.bus)w=q.shiftKey&&q.ctrlKey&&(73===q.keyCode||74===q.keyCode||75===q.keyCode)||!l.emu_enabled?!1:q.target?q.target.classList.contains("phone_keyboard")||"INPUT"!==q.target.nodeName&&"TEXTAREA"!==q.target.nodeName:!0;if(w){a:{if(void 0!==q.code&&(w=t[q.code],void 0!==
|
||||
w))break a;w=m[q.keyCode]}if(w)return g(w,z,q.repeat),q.preventDefault&&q.preventDefault(),!1;console.log("Missing char in map: keyCode="+(q.keyCode||-1).toString(16)+" code="+q.code)}}function g(q,z,w){if(z)k[q]&&!w&&g(q,!1);else if(!k[q])return;(k[q]=z)||(q|=128);255<q?(f(q>>8),f(q&255)):f(q)}function f(q){l.bus.send("keyboard-code",q)}var k={},l=this;this.emu_enabled=!0;var m=new Uint16Array([0,0,0,0,0,0,0,0,14,15,0,0,0,28,0,0,42,29,56,0,58,0,0,0,0,0,0,1,0,0,0,0,57,57417,57425,57423,57415,57419,
|
||||
57416,57421,80,0,0,0,0,82,83,0,11,2,3,4,5,6,7,8,9,10,0,39,0,13,0,0,0,30,48,46,32,18,33,34,35,23,36,37,38,50,49,24,25,16,19,31,20,22,47,17,45,21,44,57435,57436,57437,0,0,82,79,80,81,75,76,77,71,72,73,0,0,0,0,0,0,59,60,61,62,63,64,65,66,67,68,87,88,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,69,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0,0,39,13,51,12,52,53,41,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,43,27,40,0,57435,57400,0,0,0,0,0,0,0,0,0,0,0,0,0,0]),
|
||||
n={8:8,10:13,32:32,39:222,44:188,45:189,46:190,47:191,48:48,49:49,50:50,51:51,52:52,53:53,54:54,55:55,56:56,57:57,59:186,61:187,91:219,92:220,93:221,96:192,97:65,98:66,99:67,100:68,101:69,102:70,103:71,104:72,105:73,106:74,107:75,108:76,109:77,110:78,111:79,112:80,113:81,114:82,115:83,116:84,117:85,118:86,119:87,120:88,121:89,122:90},p={33:49,34:222,35:51,36:52,37:53,38:55,40:57,41:48,42:56,43:187,58:186,60:188,62:190,63:191,64:50,65:65,66:66,67:67,68:68,69:69,70:70,71:71,72:72,73:73,74:74,75:75,
|
||||
76:76,77:77,78:78,79:79,80:80,81:81,82:82,83:83,84:84,85:85,86:86,87:87,88:88,89:89,90:90,94:54,95:189,123:219,124:220,125:221,126:192},t={Escape:1,Digit1:2,Digit2:3,Digit3:4,Digit4:5,Digit5:6,Digit6:7,Digit7:8,Digit8:9,Digit9:10,Digit0:11,Minus:12,Equal:13,Backspace:14,Tab:15,KeyQ:16,KeyW:17,KeyE:18,KeyR:19,KeyT:20,KeyY:21,KeyU:22,KeyI:23,KeyO:24,KeyP:25,BracketLeft:26,BracketRight:27,Enter:28,ControlLeft:29,KeyA:30,KeyS:31,KeyD:32,KeyF:33,KeyG:34,KeyH:35,KeyJ:36,KeyK:37,KeyL:38,Semicolon:39,Quote:40,
|
||||
Backquote:41,ShiftLeft:42,Backslash:43,KeyZ:44,KeyX:45,KeyC:46,KeyV:47,KeyB:48,KeyN:49,KeyM:50,Comma:51,Period:52,Slash:53,IntlRo:53,ShiftRight:54,NumpadMultiply:55,AltLeft:56,Space:57,CapsLock:58,F1:59,F2:60,F3:61,F4:62,F5:63,F6:64,F7:65,F8:66,F9:67,F10:68,NumLock:69,ScrollLock:70,Numpad7:71,Numpad8:72,Numpad9:73,NumpadSubtract:74,Numpad4:75,Numpad5:76,Numpad6:77,NumpadAdd:78,Numpad1:79,Numpad2:80,Numpad3:81,Numpad0:82,NumpadDecimal:83,IntlBackslash:86,F11:87,F12:88,NumpadEnter:57372,ControlRight:57373,
|
||||
NumpadDivide:57397,AltRight:57400,Home:57415,ArrowUp:57416,PageUp:57417,ArrowLeft:57419,ArrowRight:57421,End:57423,ArrowDown:57424,PageDown:57425,Insert:57426,Delete:57427,OSLeft:57435,OSRight:57436,ContextMenu:57437};this.bus=a;this.destroy=function(){"undefined"!==typeof window&&(window.removeEventListener("keyup",b,!1),window.removeEventListener("keydown",c,!1),window.removeEventListener("blur",d,!1))};this.init=function(){"undefined"!==typeof window&&(this.destroy(),window.addEventListener("keyup",
|
||||
b,!1),window.addEventListener("keydown",c,!1),window.addEventListener("blur",d,!1))};this.init();this.simulate_press=function(q){q={keyCode:q};e(q,!0);e(q,!1)};this.simulate_char=function(q){var z=q.charCodeAt(0);z in n?this.simulate_press(n[z]):z in p?(f(42),this.simulate_press(p[z]),f(170)):console.log("ascii -> keyCode not found: ",z,q)}};function mb(a,b){function c(u){if(!w.enabled||!w.emu_enabled)return!1;var I=b||document.body,U;if(!(U=document.pointerLockElement))a:{for(u=u.target;u.parentNode;){if(u===I){U=!0;break a}u=u.parentNode}U=!1}return U}function d(u){c(u)&&(u=u.changedTouches)&&u.length&&(u=u[u.length-1],q=u.clientX,z=u.clientY)}function e(){if(n||t||p)w.bus.send("mouse-click",[!1,!1,!1]),n=t=p=!1}function g(u){if(w.bus&&c(u)&&w.is_running){var I=0,U=0,ea=u.changedTouches;ea?ea.length&&(ea=ea[ea.length-1],I=ea.clientX-
|
||||
q,U=ea.clientY-z,q=ea.clientX,z=ea.clientY,u.preventDefault()):"number"===typeof u.movementX?(I=u.movementX,U=u.movementY):"number"===typeof u.webkitMovementX?(I=u.webkitMovementX,U=u.webkitMovementY):"number"===typeof u.mozMovementX?(I=u.mozMovementX,U=u.mozMovementY):(I=u.clientX-q,U=u.clientY-z,q=u.clientX,z=u.clientY);w.bus.send("mouse-delta",[.15*I,-(.15*U)]);b&&w.bus.send("mouse-absolute",[u.pageX-b.offsetLeft,u.pageY-b.offsetTop,b.offsetWidth,b.offsetHeight])}}function f(u){c(u)&&l(u,!0)}function k(u){c(u)&&
|
||||
l(u,!1)}function l(u,I){w.bus&&(1===u.which?n=I:2===u.which?t=I:3===u.which&&(p=I),w.bus.send("mouse-click",[n,t,p]),u.preventDefault())}function m(u){if(c(u)){var I=u.wheelDelta||-u.detail;0>I?I=-1:0<I&&(I=1);w.bus.send("mouse-wheel",[I,0]);u.preventDefault()}}var n=!1,p=!1,t=!1,q=0,z=0,w=this;this.enabled=!1;this.emu_enabled=!0;this.bus=a;this.bus.register("mouse-enable",function(u){this.enabled=u},this);this.is_running=!1;this.bus.register("emulator-stopped",function(){this.is_running=!1},this);
|
||||
this.bus.register("emulator-started",function(){this.is_running=!0},this);this.destroy=function(){"undefined"!==typeof window&&(window.removeEventListener("touchstart",d,!1),window.removeEventListener("touchend",e,!1),window.removeEventListener("touchmove",g,!1),window.removeEventListener("mousemove",g,!1),window.removeEventListener("mousedown",f,!1),window.removeEventListener("mouseup",k,!1),window.removeEventListener("wheel",m,{passive:!1}))};this.init=function(){"undefined"!==typeof window&&(this.destroy(),
|
||||
window.addEventListener("touchstart",d,!1),window.addEventListener("touchend",e,!1),window.addEventListener("touchmove",g,!1),window.addEventListener("mousemove",g,!1),window.addEventListener("mousedown",f,!1),window.addEventListener("mouseup",k,!1),window.addEventListener("wheel",m,{passive:!1}))};this.init()};function nb(a){if("undefined"!==typeof window)if(window.AudioContext||window.webkitAudioContext){var b=window.AudioWorklet?ob:pb;this.bus=a;this.audio_context=window.AudioContext?new AudioContext:new webkitAudioContext;this.mixer=new qb(a,this.audio_context);this.pcspeaker=new rb(a,this.audio_context,this.mixer);this.dac=new b(a,this.audio_context,this.mixer);this.pcspeaker.start();a.register("emulator-stopped",function(){this.audio_context.suspend()},this);a.register("emulator-started",function(){this.audio_context.resume()},
|
||||
this);a.register("speaker-confirm-initialized",function(){a.send("speaker-has-initialized")},this);a.send("speaker-has-initialized")}else console.warn("Web browser doesn't support Web Audio API")}nb.prototype.destroy=function(){this.audio_context&&this.audio_context.close();this.audio_context=null;this.dac&&this.dac.node_processor&&this.dac.node_processor.port.close();this.dac=null};
|
||||
function qb(a,b){function c(d){return function(e){d.gain.setValueAtTime(e,this.audio_context.currentTime)}}this.audio_context=b;this.sources=new Map;this.gain_right=this.gain_left=this.volume_right=this.volume_left=this.volume_both=1;this.node_treble_left=this.audio_context.createBiquadFilter();this.node_treble_right=this.audio_context.createBiquadFilter();this.node_treble_left.type="highshelf";this.node_treble_right.type="highshelf";this.node_treble_left.frequency.setValueAtTime(2E3,this.audio_context.currentTime);
|
||||
this.node_treble_right.frequency.setValueAtTime(2E3,this.audio_context.currentTime);this.node_bass_left=this.audio_context.createBiquadFilter();this.node_bass_right=this.audio_context.createBiquadFilter();this.node_bass_left.type="lowshelf";this.node_bass_right.type="lowshelf";this.node_bass_left.frequency.setValueAtTime(200,this.audio_context.currentTime);this.node_bass_right.frequency.setValueAtTime(200,this.audio_context.currentTime);this.node_gain_left=this.audio_context.createGain();this.node_gain_right=
|
||||
this.audio_context.createGain();this.node_merger=this.audio_context.createChannelMerger(2);this.input_left=this.node_treble_left;this.input_right=this.node_treble_right;this.node_treble_left.connect(this.node_bass_left);this.node_bass_left.connect(this.node_gain_left);this.node_gain_left.connect(this.node_merger,0,0);this.node_treble_right.connect(this.node_bass_right);this.node_bass_right.connect(this.node_gain_right);this.node_gain_right.connect(this.node_merger,0,1);this.node_merger.connect(this.audio_context.destination);
|
||||
a.register("mixer-connect",function(d){this.connect_source(d[0],d[1])},this);a.register("mixer-disconnect",function(d){this.disconnect_source(d[0],d[1])},this);a.register("mixer-volume",function(d){var e=d[0],g=d[1];d=Math.pow(10,d[2]/20);e=0===e?this:this.sources.get(e);void 0===e||e.set_volume(d,g)},this);a.register("mixer-gain-left",function(d){this.gain_left=Math.pow(10,d/20);this.update()},this);a.register("mixer-gain-right",function(d){this.gain_right=Math.pow(10,d/20);this.update()},this);
|
||||
a.register("mixer-treble-left",c(this.node_treble_left),this);a.register("mixer-treble-right",c(this.node_treble_right),this);a.register("mixer-bass-left",c(this.node_bass_left),this);a.register("mixer-bass-right",c(this.node_bass_right),this)}qb.prototype.add_source=function(a,b){a=new sb(this.audio_context,a,this.input_left,this.input_right);this.sources.has(b);this.sources.set(b,a);return a};qb.prototype.connect_source=function(a,b){a=this.sources.get(a);void 0===a||a.connect(b)};
|
||||
qb.prototype.disconnect_source=function(a,b){a=this.sources.get(a);void 0===a||a.disconnect(b)};qb.prototype.set_volume=function(a,b){void 0===b&&(b=2);switch(b){case 0:this.volume_left=a;break;case 1:this.volume_right=a;break;case 2:this.volume_both=a;break;default:return}this.update()};
|
||||
qb.prototype.update=function(){var a=this.volume_both*this.volume_right*this.gain_right;this.node_gain_left.gain.setValueAtTime(this.volume_both*this.volume_left*this.gain_left,this.audio_context.currentTime);this.node_gain_right.gain.setValueAtTime(a,this.audio_context.currentTime)};
|
||||
function sb(a,b,c,d){this.audio_context=a;this.connected_right=this.connected_left=!0;this.volume_right=this.volume_left=this.volume_both=this.gain_hidden=1;this.node_splitter=a.createChannelSplitter(2);this.node_gain_left=a.createGain();this.node_gain_right=a.createGain();b.connect(this.node_splitter);this.node_splitter.connect(this.node_gain_left,0);this.node_gain_left.connect(c);this.node_splitter.connect(this.node_gain_right,1);this.node_gain_right.connect(d)}
|
||||
sb.prototype.update=function(){var a=this.connected_right*this.gain_hidden*this.volume_both*this.volume_right;this.node_gain_left.gain.setValueAtTime(this.connected_left*this.gain_hidden*this.volume_both*this.volume_left,this.audio_context.currentTime);this.node_gain_right.gain.setValueAtTime(a,this.audio_context.currentTime)};sb.prototype.connect=function(a){var b=!a||2===a;if(b||0===a)this.connected_left=!0;if(b||1===a)this.connected_right=!0;this.update()};
|
||||
sb.prototype.disconnect=function(a){var b=!a||2===a;if(b||0===a)this.connected_left=!1;if(b||1===a)this.connected_right=!1;this.update()};sb.prototype.set_volume=function(a,b){void 0===b&&(b=2);switch(b){case 0:this.volume_left=a;break;case 1:this.volume_right=a;break;case 2:this.volume_both=a;break;default:return}this.update()};sb.prototype.set_gain_hidden=function(a){this.gain_hidden=a};
|
||||
function rb(a,b,c){this.node_oscillator=b.createOscillator();this.node_oscillator.type="square";this.node_oscillator.frequency.setValueAtTime(440,b.currentTime);this.mixer_connection=c.add_source(this.node_oscillator,1);this.mixer_connection.disconnect();a.register("pcspeaker-enable",function(){c.connect_source(1)},this);a.register("pcspeaker-disable",function(){c.disconnect_source(1)},this);a.register("pcspeaker-update",function(d){var e=d[1],g=0;3===d[0]&&(g=Math.min(1193181.6665999999/e,this.node_oscillator.frequency.maxValue),
|
||||
g=Math.max(g,0));this.node_oscillator.frequency.setValueAtTime(g,b.currentTime)},this)}rb.prototype.start=function(){this.node_oscillator.start()};
|
||||
function ob(a,b,c){this.bus=a;this.audio_context=b;this.enabled=!1;this.sampling_rate=48E3;b=function(){function f(m){if(0===m)return 1;m*=Math.PI;return Math.sin(m)/m}function k(){var m=Reflect.construct(AudioWorkletProcessor,[],k);m.kernel_size=3;m.queue_data=Array(1024);m.queue_start=0;m.queue_end=0;m.queue_length=0;m.queue_size=m.queue_data.length;m.queued_samples=0;m.source_buffer_previous=l;m.source_buffer_current=l;m.source_samples_per_destination=1;m.source_block_start=0;m.source_time=0;m.source_offset=
|
||||
0;m.port.onmessage=n=>{switch(n.data.type){case "queue":m.queue_push(n.data.value);break;case "sampling-rate":m.source_samples_per_destination=n.data.value/sampleRate}};return m}var l=[new Float32Array(256),new Float32Array(256)];Reflect.setPrototypeOf(k.prototype,AudioWorkletProcessor.prototype);Reflect.setPrototypeOf(k,AudioWorkletProcessor);k.prototype.process=k.prototype.process=function(m,n){for(m=0;m<n[0][0].length;m++){for(var p=0,t=0,q=this.source_offset+this.kernel_size,z=this.source_offset-
|
||||
this.kernel_size+1;z<=q;z++){var w=this.source_block_start+z;p+=this.get_sample(w,0)*this.kernel(this.source_time-z);t+=this.get_sample(w,1)*this.kernel(this.source_time-z)}if(isNaN(p)||isNaN(t))p=t=0,this.dbg_log("ERROR: NaN values! Ignoring for now.");n[0][0][m]=p;n[0][1][m]=t;this.source_time+=this.source_samples_per_destination;this.source_offset=Math.floor(this.source_time)}n=this.source_offset;n+=this.kernel_size+2;this.source_time-=this.source_offset;this.source_block_start+=this.source_offset;
|
||||
this.source_offset=0;this.ensure_enough_data(n);return!0};k.prototype.kernel=function(m){return f(m)*f(m/this.kernel_size)};k.prototype.get_sample=function(m,n){return 0>m?(m+=this.source_buffer_previous[0].length,this.source_buffer_previous[n][m]):this.source_buffer_current[n][m]};k.prototype.ensure_enough_data=function(m){var n=this.source_buffer_current[0].length;n-this.source_block_start<m&&(this.prepare_next_buffer(),this.source_block_start-=n)};k.prototype.prepare_next_buffer=function(){256>
|
||||
this.queued_samples&&this.queue_length&&this.dbg_log("Not enough samples - should not happen during midway of playback");this.source_buffer_previous=this.source_buffer_current;this.source_buffer_current=this.queue_shift();var m=this.source_buffer_current[0].length;if(256>m){for(var n=this.queue_start,p=0;256>m&&p<this.queue_length;)m+=this.queue_data[n][0].length,n=n+1&this.queue_size-1,p++;m=Math.max(m,256);m=[new Float32Array(m),new Float32Array(m)];m[0].set(this.source_buffer_current[0]);m[1].set(this.source_buffer_current[1]);
|
||||
n=this.source_buffer_current[0].length;for(var t=0;t<p;t++){var q=this.queue_shift();m[0].set(q[0],n);m[1].set(q[1],n);n+=q[0].length}this.source_buffer_current=m}this.pump()};k.prototype.pump=function(){1024>this.queued_samples/this.source_samples_per_destination&&this.port.postMessage({type:"pump"})};k.prototype.queue_push=function(m){this.queue_length<this.queue_size&&(this.queue_data[this.queue_end]=m,this.queue_end=this.queue_end+1&this.queue_size-1,this.queue_length++,this.queued_samples+=m[0].length,
|
||||
this.pump())};k.prototype.queue_shift=function(){if(!this.queue_length)return l;var m=this.queue_data[this.queue_start];this.queue_data[this.queue_start]=null;this.queue_start=this.queue_start+1&this.queue_size-1;this.queue_length--;this.queued_samples-=m[0].length;return m};k.prototype.dbg_log=function(){};registerProcessor("dac-processor",k)}.toString();var d=b.indexOf("{")+1,e=b.lastIndexOf("}");b=b.substring(d,e);b=new Blob([b],{type:"application/javascript"});var g=URL.createObjectURL(b);this.node_processor=
|
||||
null;this.node_output=this.audio_context.createGain();this.audio_context.audioWorklet.addModule(g).then(()=>{URL.revokeObjectURL(g);this.node_processor=new AudioWorkletNode(this.audio_context,"dac-processor",{numberOfInputs:0,numberOfOutputs:1,outputChannelCount:[2],parameterData:{},processorOptions:{}});this.node_processor.port.postMessage({type:"sampling-rate",value:this.sampling_rate});this.node_processor.port.onmessage=f=>{switch(f.data.type){case "pump":this.pump()}};this.node_processor.connect(this.node_output)});
|
||||
this.mixer_connection=c.add_source(this.node_output,2);this.mixer_connection.set_gain_hidden(3);a.register("dac-send-data",function(f){this.queue(f)},this);a.register("dac-enable",function(){this.enabled=!0},this);a.register("dac-disable",function(){this.enabled=!1},this);a.register("dac-tell-sampling-rate",function(f){this.sampling_rate=f;this.node_processor&&this.node_processor.port.postMessage({type:"sampling-rate",value:f})},this)}
|
||||
ob.prototype.queue=function(a){this.node_processor&&this.node_processor.port.postMessage({type:"queue",value:a},[a[0].buffer,a[1].buffer])};ob.prototype.pump=function(){this.enabled&&this.bus.send("dac-request-data")};
|
||||
function pb(a,b,c){this.bus=a;this.audio_context=b;this.enabled=!1;this.sampling_rate=22050;this.buffered_time=0;this.rate_ratio=1;this.node_lowpass=this.audio_context.createBiquadFilter();this.node_lowpass.type="lowpass";this.node_output=this.node_lowpass;this.mixer_connection=c.add_source(this.node_output,2);this.mixer_connection.set_gain_hidden(3);a.register("dac-send-data",function(d){this.queue(d)},this);a.register("dac-enable",function(){this.enabled=!0;this.pump()},this);a.register("dac-disable",
|
||||
function(){this.enabled=!1},this);a.register("dac-tell-sampling-rate",function(d){this.sampling_rate=d;this.rate_ratio=Math.ceil(8E3/d);this.node_lowpass.frequency.setValueAtTime(d/2,this.audio_context.currentTime)},this)}
|
||||
pb.prototype.queue=function(a){var b=a[0].length,c=b/this.sampling_rate;if(1<this.rate_ratio){var d=this.audio_context.createBuffer(2,b*this.rate_ratio,this.sampling_rate*this.rate_ratio);for(var e=d.getChannelData(0),g=d.getChannelData(1),f=0,k=0;k<b;k++)for(var l=0;l<this.rate_ratio;l++,f++)e[f]=a[0][k],g[f]=a[1][k]}else d=this.audio_context.createBuffer(2,b,this.sampling_rate),d.copyToChannel?(d.copyToChannel(a[0],0),d.copyToChannel(a[1],1)):(d.getChannelData(0).set(a[0]),d.getChannelData(1).set(a[1]));
|
||||
a=this.audio_context.createBufferSource();a.buffer=d;a.connect(this.node_lowpass);a.addEventListener("ended",this.pump.bind(this));d=this.audio_context.currentTime;if(this.buffered_time<d)for(this.buffered_time=d,d=.2-c,b=0;b<=d;)b+=c,this.buffered_time+=c,setTimeout(()=>this.pump(),1E3*b);a.start(this.buffered_time);this.buffered_time+=c;setTimeout(()=>this.pump(),0)};pb.prototype.pump=function(){this.enabled&&(.2<this.buffered_time-this.audio_context.currentTime||this.bus.send("dac-request-data"))};function tb(a,b){function c(k){f.bus&&f.enabled&&(f.send_char(k.which),k.preventDefault())}function d(k){var l=k.which;8===l?(f.send_char(127),k.preventDefault()):9===l&&(f.send_char(9),k.preventDefault())}function e(k){if(f.enabled){for(var l=k.clipboardData.getData("text/plain"),m=0;m<l.length;m++)f.send_char(l.charCodeAt(m));k.preventDefault()}}function g(k){k.target!==a&&a.blur()}var f=this;this.enabled=!0;this.bus=b;this.text="";this.text_new_line=!1;this.last_update=0;this.bus.register("serial0-output-byte",
|
||||
function(k){k=String.fromCharCode(k);this.show_char(k)},this);this.destroy=function(){a.removeEventListener("keypress",c,!1);a.removeEventListener("keydown",d,!1);a.removeEventListener("paste",e,!1);window.removeEventListener("mousedown",g,!1)};this.init=function(){this.destroy();a.style.display="block";a.addEventListener("keypress",c,!1);a.addEventListener("keydown",d,!1);a.addEventListener("paste",e,!1);window.addEventListener("mousedown",g,!1)};this.init();this.show_char=function(k){"\b"===k?(this.text=
|
||||
this.text.slice(0,-1),this.update()):"\r"!==k&&(this.text+=k,"\n"===k&&(this.text_new_line=!0),this.update())};this.update=function(){var k=Date.now(),l=k-this.last_update;16>l?void 0===this.update_timer&&(this.update_timer=setTimeout(()=>{this.update_timer=void 0;this.last_update=Date.now();this.render()},16-l)):(void 0!==this.update_timer&&(clearTimeout(this.update_timer),this.update_timer=void 0),this.last_update=k,this.render())};this.render=function(){a.value=this.text;this.text_new_line&&(this.text_new_line=
|
||||
!1,a.scrollTop=1E9)};this.send_char=function(k){f.bus&&f.bus.send("serial0-input",k)}}
|
||||
function ub(a,b){this.element=a;if(window.Terminal){var c=this.term=new window.Terminal({logLevel:"off"});c.write("This is the serial console. Whatever you type or paste here will be sent to COM1");var d=c.onData(function(e){for(let g=0;g<e.length;g++)b.send("serial0-input",e.charCodeAt(g))});b.register("serial0-output-byte",function(e){c.write(Uint8Array.of(e))},this);this.destroy=function(){d.dispose();c.dispose()}}}ub.prototype.show=function(){this.term&&this.term.open(this.element)};function vb(a,b){this.bus=b;this.socket=void 0;this.send_queue=[];this.url=a;this.reconnect_interval=1E4;this.last_connect_attempt=Date.now()-this.reconnect_interval;this.send_queue_limit=64;this.bus.register("net0-send",function(c){this.send(c)},this)}vb.prototype.handle_message=function(a){this.bus&&this.bus.send("net0-receive",new Uint8Array(a.data))};vb.prototype.handle_close=function(){this.connect();setTimeout(this.connect.bind(this),this.reconnect_interval)};
|
||||
vb.prototype.handle_open=function(){for(var a=0;a<this.send_queue.length;a++)this.send(this.send_queue[a]);this.send_queue=[]};vb.prototype.handle_error=function(){};vb.prototype.destroy=function(){this.socket&&this.socket.close()};
|
||||
vb.prototype.connect=function(){if("undefined"!==typeof WebSocket){if(this.socket){var a=this.socket.readyState;if(0===a||1===a)return}a=Date.now();this.last_connect_attempt+this.reconnect_interval>a||(this.last_connect_attempt=Date.now(),this.socket=new WebSocket(this.url),this.socket.binaryType="arraybuffer",this.socket.onopen=this.handle_open.bind(this),this.socket.onmessage=this.handle_message.bind(this),this.socket.onclose=this.handle_close.bind(this),this.socket.onerror=this.handle_error.bind(this))}};
|
||||
vb.prototype.send=function(a){this.socket&&1===this.socket.readyState?this.socket.send(a):(this.send_queue.push(a),this.send_queue.length>2*this.send_queue_limit&&(this.send_queue=this.send_queue.slice(-this.send_queue_limit)),this.connect())};vb.prototype.change_proxy=function(a){this.url=a;this.socket&&(this.socket.onclose=function(){},this.socket.onerror=function(){},this.socket.close(),this.socket=void 0)};function Y(a){this.cpu_is_running=!1;this.cpu_exception_hook=function(){};var b=Xa.create();this.bus=b[0];this.emulator_bus=b[1];var c,d;const e=new WebAssembly.Table({element:"anyfunc",initial:1924});b={cpu_exception_hook:f=>this.cpu_exception_hook(f),run_hardware_timers:function(f,k){return c.run_hardware_timers(f,k)},cpu_event_halt:()=>{this.emulator_bus.send("cpu-event-halt")},abort:function(){},microtick:D.microtick,get_rand_int:function(){return r.get_rand_int()},apic_acknowledge_irq:function(){return c.devices.apic.acknowledge_irq()},
|
||||
io_port_read8:function(f){return c.io.port_read8(f)},io_port_read16:function(f){return c.io.port_read16(f)},io_port_read32:function(f){return c.io.port_read32(f)},io_port_write8:function(f,k){c.io.port_write8(f,k)},io_port_write16:function(f,k){c.io.port_write16(f,k)},io_port_write32:function(f,k){c.io.port_write32(f,k)},mmap_read8:function(f){return c.mmap_read8(f)},mmap_read16:function(f){return c.mmap_read16(f)},mmap_read32:function(f){return c.mmap_read32(f)},mmap_write8:function(f,k){c.mmap_write8(f,
|
||||
k)},mmap_write16:function(f,k){c.mmap_write16(f,k)},mmap_write32:function(f,k){c.mmap_write32(f,k)},mmap_write64:function(f,k,l){c.mmap_write64(f,k,l)},mmap_write128:function(f,k,l,m,n){c.mmap_write128(f,k,l,m,n)},log_from_wasm:function(f,k){r.read_sized_string_from_mem(d,f,k)},console_log_from_wasm:function(f,k){f=r.read_sized_string_from_mem(d,f,k);console.error(f)},dbg_trace_from_wasm:function(){},codegen_finalize:(f,k,l,m,n)=>{c.codegen_finalize(f,k,l,m,n)},jit_clear_func:f=>c.jit_clear_func(f),
|
||||
jit_clear_all_funcs:()=>c.jit_clear_all_funcs(),__indirect_function_table:e};let g=a.wasm_fn;g||(g=f=>new Promise(k=>{let l="v86.wasm",m="v86-fallback.wasm";if(a.wasm_path){l=a.wasm_path;const n=l.lastIndexOf("/");m=(-1===n?"":l.substr(0,n))+"/"+m}else"undefined"===typeof window&&"string"===typeof __dirname?(l=__dirname+"/"+l,m=__dirname+"/"+m):(l="build/"+l,m="build/"+m);r.load_file(l,{done:async n=>{try{const {instance:p}=await WebAssembly.instantiate(n,f);this.wasm_source=n;k(p.exports)}catch(p){r.load_file(m,
|
||||
{done:async t=>{const {instance:q}=await WebAssembly.instantiate(t,f);this.wasm_source=t;k(q.exports)}})}},progress:n=>{this.emulator_bus.send("download-progress",{file_index:0,file_count:1,file_name:l,lengthComputable:n.lengthComputable,total:n.total,loaded:n.loaded})}})}));g({env:b}).then(f=>{d=f.memory;f.rust_init();f=this.v86=new D(this.emulator_bus,{exports:f,wasm_table:e});c=f.cpu;this.continue_init(f,a)});this.zstd_worker=null;this.zstd_worker_request_id=0}
|
||||
Y.prototype.continue_init=async function(a,b){function c(t,q){switch(t){case "hda":e.hda=this.disk_images.hda=q;break;case "hdb":e.hdb=this.disk_images.hdb=q;break;case "cdrom":e.cdrom=this.disk_images.cdrom=q;break;case "fda":e.fda=this.disk_images.fda=q;break;case "fdb":e.fdb=this.disk_images.fdb=q;break;case "multiboot":e.multiboot=this.disk_images.multiboot=q.buffer;break;case "bzimage":e.bzimage=this.disk_images.bzimage=q.buffer;break;case "initrd":e.initrd=this.disk_images.initrd=q.buffer;break;
|
||||
case "bios":e.bios=q.buffer;break;case "vga_bios":e.vga_bios=q.buffer;break;case "initial_state":e.initial_state=q.buffer;break;case "fs9p_json":e.fs9p_json=q}}async function d(){if(e.fs9p&&e.fs9p_json&&(e.initial_state||e.fs9p.load_from_json(e.fs9p_json),b.bzimage_initrd_from_filesystem)){const {bzimage_path:t,initrd_path:q}=this.get_bzimage_initrd_from_filesystem(e.fs9p),[z,w]=await Promise.all([e.fs9p.read_file(q),e.fs9p.read_file(t)]);c.call(this,"initrd",new r.SyncBuffer(z.buffer));c.call(this,
|
||||
"bzimage",new r.SyncBuffer(w.buffer))}this.serial_adapter&&this.serial_adapter.show&&this.serial_adapter.show();this.bus.send("cpu-init",e);e.initial_state&&(a.restore_state(e.initial_state),e.initial_state=void 0);b.autostart&&this.bus.send("cpu-run");this.emulator_bus.send("emulator-loaded")}this.bus.register("emulator-stopped",function(){this.cpu_is_running=!1},this);this.bus.register("emulator-started",function(){this.cpu_is_running=!0},this);var e={};this.disk_images={fda:void 0,fdb:void 0,hda:void 0,
|
||||
hdb:void 0,cdrom:void 0};var g=b.boot_order?b.boot_order:b.fda?801:b.hda?786:291;e.acpi=b.acpi;e.disable_jit=b.disable_jit;e.load_devices=!0;e.log_level=b.log_level;e.memory_size=b.memory_size||67108864;e.vga_memory_size=b.vga_memory_size||8388608;e.boot_order=g;e.fastboot=b.fastboot||!1;e.fda=void 0;e.fdb=void 0;e.uart1=b.uart1;e.uart2=b.uart2;e.uart3=b.uart3;e.cmdline=b.cmdline;e.preserve_mac_from_state_image=b.preserve_mac_from_state_image;e.mac_address_translation=b.mac_address_translation;e.cpuid_level=
|
||||
b.cpuid_level;e.virtio_console=b.virtio_console;b.network_adapter?this.network_adapter=b.network_adapter(this.bus):b.network_relay_url&&(this.network_adapter=new vb(b.network_relay_url,this.bus));e.enable_ne2k=!0;b.disable_keyboard||(this.keyboard_adapter=new lb(this.bus));b.disable_mouse||(this.mouse_adapter=new mb(this.bus,b.screen_container));b.screen_container?this.screen_adapter=new ba(b.screen_container,this.bus):b.screen_dummy&&(this.screen_adapter=new wb(this.bus));b.serial_container&&(this.serial_adapter=
|
||||
new tb(b.serial_container,this.bus));b.serial_container_xtermjs&&(this.serial_adapter=new ub(b.serial_container_xtermjs,this.bus));b.disable_speaker||(this.speaker_adapter=new nb(this.bus));var f=[];g=(t,q)=>{if(q)if(q.get&&q.set&&q.load)f.push({name:t,loadable:q});else{if("bios"===t||"vga_bios"===t||"initial_state"===t||"multiboot"===t||"bzimage"===t||"initrd"===t)q.async=!1;q.url&&!q.async?f.push({name:t,url:q.url,size:q.size}):f.push({name:t,loadable:r.buffer_from_object(q,this.zstd_decompress_worker.bind(this))})}};
|
||||
b.state&&console.warn("Warning: Unknown option 'state'. Did you mean 'initial_state'?");g("bios",b.bios);g("vga_bios",b.vga_bios);g("cdrom",b.cdrom);g("hda",b.hda);g("hdb",b.hdb);g("fda",b.fda);g("fdb",b.fdb);g("initial_state",b.initial_state);g("multiboot",b.multiboot);g("bzimage",b.bzimage);g("initrd",b.initrd);if(b.filesystem){g=b.filesystem.basefs;var k=b.filesystem.baseurl;let t=new xb;k&&(t=new yb(t,k));e.fs9p=this.fs9p=new Z(t);if(g){if("object"===typeof g){var l=g.size;g=g.url}f.push({name:"fs9p_json",
|
||||
url:g,size:l,as_json:!0})}}var m=this,n=f.length,p=function(t){if(t===n)setTimeout(d.bind(this),0);else{var q=f[t];q.loadable?(q.loadable.onload=function(){c.call(this,q.name,q.loadable);p(t+1)}.bind(this),q.loadable.load()):r.load_file(q.url,{done:function(z){q.url.endsWith(".zst")&&"initial_state"!==q.name&&(z=this.zstd_decompress(q.size,new Uint8Array(z)));c.call(this,q.name,q.as_json?z:new r.SyncBuffer(z));p(t+1)}.bind(this),progress:function(z){200===z.target.status?m.emulator_bus.send("download-progress",
|
||||
{file_index:t,file_count:n,file_name:q.url,lengthComputable:z.lengthComputable,total:z.total||q.size,loaded:z.loaded}):m.emulator_bus.send("download-error",{file_index:t,file_count:n,file_name:q.url,request:z.target})},as_json:q.as_json})}}.bind(this);p(0)};
|
||||
Y.prototype.zstd_decompress=function(a,b){const c=this.v86.cpu;this.zstd_context=c.zstd_create_ctx(b.length);(new Uint8Array(c.wasm_memory.buffer)).set(b,c.zstd_get_src_ptr(this.zstd_context));b=c.zstd_read(this.zstd_context,a);const d=c.wasm_memory.buffer.slice(b,b+a);c.zstd_read_free(b,a);c.zstd_free_ctx(this.zstd_context);this.zstd_context=null;return d};
|
||||
Y.prototype.zstd_decompress_worker=async function(a,b){if(!this.zstd_worker){const c=URL.createObjectURL(new Blob(["("+function(){let d;globalThis.onmessage=function(e){if(d){var {src:g,decompressed_size:f,id:k}=e.data;e=d.exports;var l=e.zstd_create_ctx(g.length);(new Uint8Array(e.memory.buffer)).set(g,e.zstd_get_src_ptr(l));var m=e.zstd_read(l,f),n=e.memory.buffer.slice(m,m+f);e.zstd_read_free(m,f);e.zstd_free_ctx(l);postMessage({result:n,id:k},[n])}else l=Object.fromEntries("cpu_exception_hook run_hardware_timers cpu_event_halt microtick get_rand_int apic_acknowledge_irq io_port_read8 io_port_read16 io_port_read32 io_port_write8 io_port_write16 io_port_write32 mmap_read8 mmap_read16 mmap_read32 mmap_write8 mmap_write16 mmap_write32 mmap_write64 mmap_write128 codegen_finalize jit_clear_func jit_clear_all_funcs".split(" ").map(p=>
|
||||
[p,()=>console.error("zstd worker unexpectedly called "+p)])),l.__indirect_function_table=new WebAssembly.Table({element:"anyfunc",initial:1024}),l.abort=()=>{throw Error("zstd worker aborted");},l.log_from_wasm=l.console_log_from_wasm=(p,t)=>{console.log(String.fromCharCode(...(new Uint8Array(d.exports.memory.buffer,p,t))))},l.dbg_trace_from_wasm=()=>console.trace(),d=new WebAssembly.Instance(new WebAssembly.Module(e.data),{env:l})}}.toString()+")()"],{type:"text/javascript"}));this.zstd_worker=
|
||||
new Worker(c);URL.revokeObjectURL(c);this.zstd_worker.postMessage(this.wasm_source,[this.wasm_source])}return new Promise(c=>{const d=this.zstd_worker_request_id++,e=async g=>{g.data.id===d&&(this.zstd_worker.removeEventListener("message",e),c(g.data.result))};this.zstd_worker.addEventListener("message",e);this.zstd_worker.postMessage({src:b,decompressed_size:a,id:d},[b.buffer])})};
|
||||
Y.prototype.get_bzimage_initrd_from_filesystem=function(a){const b=(a.read_dir("/")||[]).map(e=>"/"+e);a=(a.read_dir("/boot/")||[]).map(e=>"/boot/"+e);let c,d;for(let e of[].concat(b,a)){const g=/old/i.test(e)||/fallback/i.test(e),f=/vmlinuz/i.test(e)||/bzimage/i.test(e),k=/initrd/i.test(e)||/initramfs/i.test(e);!f||d&&g||(d=e);!k||c&&g||(c=e)}c&&d||(console.log("Failed to find bzimage or initrd in filesystem. Files:"),console.log(b.join(" ")),console.log(a.join(" ")));return{initrd_path:c,bzimage_path:d}};
|
||||
Y.prototype.run=async function(){this.bus.send("cpu-run")};F.exportProperty(Y.prototype,"run",Y.prototype.run);Y.prototype.stop=async function(){this.cpu_is_running&&await new Promise(a=>{const b=()=>{this.remove_listener("emulator-stopped",b);a()};this.add_listener("emulator-stopped",b);this.bus.send("cpu-stop")})};F.exportProperty(Y.prototype,"stop",Y.prototype.stop);
|
||||
Y.prototype.destroy=async function(){await this.stop();this.v86.destroy();this.keyboard_adapter&&this.keyboard_adapter.destroy();this.network_adapter&&this.network_adapter.destroy();this.mouse_adapter&&this.mouse_adapter.destroy();this.screen_adapter&&this.screen_adapter.destroy();this.serial_adapter&&this.serial_adapter.destroy();this.speaker_adapter&&this.speaker_adapter.destroy()};F.exportProperty(Y.prototype,"destroy",Y.prototype.destroy);Y.prototype.restart=function(){this.bus.send("cpu-restart")};
|
||||
F.exportProperty(Y.prototype,"restart",Y.prototype.restart);Y.prototype.add_listener=function(a,b){this.bus.register(a,b,this)};F.exportProperty(Y.prototype,"add_listener",Y.prototype.add_listener);Y.prototype.remove_listener=function(a,b){this.bus.unregister(a,b)};F.exportProperty(Y.prototype,"remove_listener",Y.prototype.remove_listener);Y.prototype.restore_state=async function(a){this.v86.restore_state(a)};F.exportProperty(Y.prototype,"restore_state",Y.prototype.restore_state);
|
||||
Y.prototype.save_state=async function(){return this.v86.save_state()};F.exportProperty(Y.prototype,"save_state",Y.prototype.save_state);Y.prototype.get_instruction_counter=function(){return this.v86?this.v86.cpu.instruction_counter[0]>>>0:0};F.exportProperty(Y.prototype,"get_instruction_counter",Y.prototype.get_instruction_counter);Y.prototype.is_running=function(){return this.cpu_is_running};F.exportProperty(Y.prototype,"is_running",Y.prototype.is_running);
|
||||
Y.prototype.set_fda=async function(a){if(a.url&&!a.async)r.load_file(a.url,{done:b=>{this.v86.cpu.devices.fdc.set_fda(new r.SyncBuffer(b))}});else{const b=r.buffer_from_object(a,this.zstd_decompress_worker.bind(this));b.onload=()=>{this.v86.cpu.devices.fdc.set_fda(b)};await b.load()}};F.exportProperty(Y.prototype,"set_fda",Y.prototype.set_fda);Y.prototype.eject_fda=function(){this.v86.cpu.devices.fdc.eject_fda()};F.exportProperty(Y.prototype,"eject_fda",Y.prototype.eject_fda);
|
||||
Y.prototype.keyboard_send_scancodes=function(a){for(var b=0;b<a.length;b++)this.bus.send("keyboard-code",a[b])};F.exportProperty(Y.prototype,"keyboard_send_scancodes",Y.prototype.keyboard_send_scancodes);Y.prototype.keyboard_send_keys=function(a){for(var b=0;b<a.length;b++)this.keyboard_adapter.simulate_press(a[b])};F.exportProperty(Y.prototype,"keyboard_send_keys",Y.prototype.keyboard_send_keys);Y.prototype.keyboard_send_text=function(a){for(var b=0;b<a.length;b++)this.keyboard_adapter.simulate_char(a[b])};
|
||||
F.exportProperty(Y.prototype,"keyboard_send_text",Y.prototype.keyboard_send_text);Y.prototype.screen_make_screenshot=function(){return this.screen_adapter?this.screen_adapter.make_screenshot():null};F.exportProperty(Y.prototype,"screen_make_screenshot",Y.prototype.screen_make_screenshot);Y.prototype.screen_set_scale=function(a,b){this.screen_adapter&&this.screen_adapter.set_scale(a,b)};F.exportProperty(Y.prototype,"screen_set_scale",Y.prototype.screen_set_scale);
|
||||
Y.prototype.screen_go_fullscreen=function(){if(this.screen_adapter){var a=document.getElementById("screen_container");if(a){var b=a.requestFullScreen||a.webkitRequestFullscreen||a.mozRequestFullScreen||a.msRequestFullScreen;b&&(b.call(a),(a=document.getElementsByClassName("phone_keyboard")[0])&&a.focus());try{navigator.keyboard.lock()}catch(c){}this.lock_mouse()}}};F.exportProperty(Y.prototype,"screen_go_fullscreen",Y.prototype.screen_go_fullscreen);
|
||||
Y.prototype.lock_mouse=function(){var a=document.body,b=a.requestPointerLock||a.mozRequestPointerLock||a.webkitRequestPointerLock;b&&b.call(a)};F.exportProperty(Y.prototype,"lock_mouse",Y.prototype.lock_mouse);Y.prototype.mouse_set_status=function(a){this.mouse_adapter&&(this.mouse_adapter.emu_enabled=a)};Y.prototype.keyboard_set_status=function(a){this.keyboard_adapter&&(this.keyboard_adapter.emu_enabled=a)};F.exportProperty(Y.prototype,"keyboard_set_status",Y.prototype.keyboard_set_status);
|
||||
Y.prototype.serial0_send=function(a){for(var b=0;b<a.length;b++)this.bus.send("serial0-input",a.charCodeAt(b))};F.exportProperty(Y.prototype,"serial0_send",Y.prototype.serial0_send);Y.prototype.serial_send_bytes=function(a,b){for(var c=0;c<b.length;c++)this.bus.send("serial"+a+"-input",b[c])};F.exportProperty(Y.prototype,"serial_send_bytes",Y.prototype.serial_send_bytes);Y.prototype.serial_set_modem_status=function(a,b){this.bus.send("serial"+a+"-modem-status-input",b)};
|
||||
Y.prototype.serial_set_carrier_detect=function(a,b){this.bus.send("serial"+a+"-carrier-detect-input",b)};Y.prototype.serial_set_ring_indicator=function(a,b){this.bus.send("serial"+a+"-ring-indicator-input",b)};Y.prototype.serial_set_data_set_ready=function(a,b){this.bus.send("serial"+a+"-data-set-ready-input",b)};Y.prototype.serial_set_clear_to_send=function(a,b){this.bus.send("serial"+a+"-clear-to-send-input",b)};
|
||||
Y.prototype.mount_fs=async function(a,b,c,d){let e=new xb;b&&(e=new yb(e,b));const g=new Z(e,this.fs9p.qidcounter),f=()=>{const k=this.fs9p.Mount(a,g);d&&(-2===k?d(new zb):-17===k?d(new Db):0>k?d(Error("Failed to mount. Error number: "+-k)):d(null))};b?g.load_from_json(c,()=>f()):f()};F.exportProperty(Y.prototype,"mount_fs",Y.prototype.mount_fs);
|
||||
Y.prototype.create_file=async function(a,b){var c=this.fs9p;if(c){var d=a.split("/");d=d[d.length-1];a=c.SearchPath(a).parentid;if(""!==d&&-1!==a)await c.CreateBinaryFile(d,a,b);else return Promise.reject(new zb)}};F.exportProperty(Y.prototype,"create_file",Y.prototype.create_file);Y.prototype.read_file=async function(a){var b=this.fs9p;if(b)return(a=await b.read_file(a))?a:Promise.reject(new zb)};F.exportProperty(Y.prototype,"read_file",Y.prototype.read_file);
|
||||
Y.prototype.automatically=function(a){const b=c=>{const d=c[0];if(d){var e=c.slice(1);if(d.sleep)setTimeout(()=>b(e),1E3*d.sleep);else if(d.vga_text){const g=this.screen_adapter.get_text_screen();for(let f of g)if(f.includes(d.vga_text)){b(e);return}setTimeout(()=>b(c),1E3)}else d.keyboard_send?(d.keyboard_send instanceof Array?this.keyboard_send_scancodes(d.keyboard_send):this.keyboard_send_text(d.keyboard_send),b(e)):d.call&&(d.call(),b(e))}};b(a)};
|
||||
Y.prototype.read_memory=function(a,b){return this.v86.cpu.read_blob(a,b)};Y.prototype.write_memory=function(a,b){this.v86.cpu.write_blob(a,b)};Y.prototype.set_serial_container_xtermjs=function(a){this.serial_adapter&&this.serial_adapter.destroy&&this.serial_adapter.destroy();this.serial_adapter=new ub(a,this.bus);this.serial_adapter.show()};function Db(a){this.message=a||"File already exists"}Db.prototype=Error.prototype;function zb(a){this.message=a||"File not found"}zb.prototype=Error.prototype;
|
||||
"undefined"!==typeof window?(window.V86Starter=Y,window.V86=Y):"undefined"!==typeof module&&"undefined"!==typeof module.exports?(module.exports.V86Starter=Y,module.exports.V86=Y):"function"===typeof importScripts&&(self.V86Starter=Y,self.V86=Y);var Eb={Connector:function(a){this.listeners={};this.pair=a;a.addEventListener("message",function(b){b=b.data;for(var c=this.listeners[b[0]],d=0;d<c.length;d++){var e=c[d];e.fn.call(e.this_value,b[1])}}.bind(this),!1)}};Eb.Connector.prototype.register=function(a,b,c){var d=this.listeners[a];void 0===d&&(d=this.listeners[a]=[]);d.push({fn:b,this_value:c})};Eb.Connector.prototype.send=function(a,b,c){this.pair&&this.pair.postMessage([a,b],c)};Eb.init=function(a){return new Eb.Connector(a)};function wb(a){var b,c,d,e,g;this.bus=a;a.register("screen-set-mode",function(f){this.set_mode(f)},this);a.register("screen-fill-buffer-end",function(f){this.update_buffer(f[0],f[1])},this);a.register("screen-put-char",function(f){this.put_char(f[0],f[1],f[2],f[3],f[4])},this);a.register("screen-text-scroll",function(f){console.log("scroll",f)},this);a.register("screen-update-cursor",function(f){this.update_cursor(f[0],f[1])},this);a.register("screen-update-cursor-scanline",function(f){this.update_cursor_scanline(f[0],
|
||||
f[1])},this);a.register("screen-set-size-text",function(f){this.set_size_text(f[0],f[1])},this);a.register("screen-set-size-graphical",function(f){this.set_size_graphical(f[0],f[1])},this);this.put_char=function(f,k,l,m,n){f<g&&k<e&&(f=3*(f*e+k),d[f]=l,d[f+1]=m,d[f+2]=n)};this.destroy=function(){};this.set_mode=function(){};this.clear_screen=function(){};this.set_size_text=function(f,k){if(f!==e||k!==g)d=new Int32Array(f*k*3),e=f,g=k};this.set_size_graphical=function(){};this.set_scale=function(){};
|
||||
this.update_cursor_scanline=function(){};this.update_cursor=function(f,k){if(f!==b||k!==c)b=f,c=k};this.update_buffer=function(){};this.get_text_screen=function(){for(var f=[],k=0;k<g;k++)f.push(this.get_text_row(k));return f};this.get_text_row=function(f){var k="";f=3*f*e;for(var l=0;l<e;l++)k+=String.fromCharCode(d[f+3*l]);return k}};const Fb={stats_to_string:function(a){return Fb.print_misc_stats(a)+Fb.print_instruction_counts(a)},print_misc_stats:function(a){let b="";var c="COMPILE COMPILE_SKIPPED_NO_NEW_ENTRY_POINTS COMPILE_WRONG_ADDRESS_SPACE COMPILE_CUT_OFF_AT_END_OF_PAGE COMPILE_WITH_LOOP_SAFETY COMPILE_PAGE COMPILE_PAGE/COMPILE COMPILE_BASIC_BLOCK COMPILE_DUPLICATED_BASIC_BLOCK COMPILE_WASM_BLOCK COMPILE_WASM_LOOP COMPILE_DISPATCHER COMPILE_ENTRY_POINT COMPILE_WASM_TOTAL_BYTES COMPILE_WASM_TOTAL_BYTES/COMPILE_PAGE RUN_INTERPRETED RUN_INTERPRETED_NEW_PAGE RUN_INTERPRETED_PAGE_HAS_CODE RUN_INTERPRETED_PAGE_HAS_ENTRY_AFTER_PAGE_WALK RUN_INTERPRETED_NEAR_END_OF_PAGE RUN_INTERPRETED_DIFFERENT_STATE RUN_INTERPRETED_DIFFERENT_STATE_CPL3 RUN_INTERPRETED_DIFFERENT_STATE_FLAT RUN_INTERPRETED_DIFFERENT_STATE_IS32 RUN_INTERPRETED_DIFFERENT_STATE_SS32 RUN_INTERPRETED_MISSED_COMPILED_ENTRY_RUN_INTERPRETED RUN_INTERPRETED_STEPS RUN_FROM_CACHE RUN_FROM_CACHE_STEPS RUN_FROM_CACHE_STEPS/RUN_FROM_CACHE RUN_FROM_CACHE_STEPS/RUN_INTERPRETED_STEPS DIRECT_EXIT INDIRECT_JUMP INDIRECT_JUMP_NO_ENTRY NORMAL_PAGE_CHANGE NORMAL_FALLTHRU NORMAL_FALLTHRU_WITH_TARGET_BLOCK NORMAL_BRANCH NORMAL_BRANCH_WITH_TARGET_BLOCK CONDITIONAL_JUMP CONDITIONAL_JUMP_PAGE_CHANGE CONDITIONAL_JUMP_EXIT CONDITIONAL_JUMP_FALLTHRU CONDITIONAL_JUMP_FALLTHRU_WITH_TARGET_BLOCK CONDITIONAL_JUMP_BRANCH CONDITIONAL_JUMP_BRANCH_WITH_TARGET_BLOCK DISPATCHER_SMALL DISPATCHER_LARGE LOOP LOOP_SAFETY CONDITION_OPTIMISED CONDITION_UNOPTIMISED CONDITION_UNOPTIMISED_PF CONDITION_UNOPTIMISED_UNHANDLED_L CONDITION_UNOPTIMISED_UNHANDLED_LE FAILED_PAGE_CHANGE SAFE_READ_FAST SAFE_READ_SLOW_PAGE_CROSSED SAFE_READ_SLOW_NOT_VALID SAFE_READ_SLOW_NOT_USER SAFE_READ_SLOW_IN_MAPPED_RANGE SAFE_WRITE_FAST SAFE_WRITE_SLOW_PAGE_CROSSED SAFE_WRITE_SLOW_NOT_VALID SAFE_WRITE_SLOW_NOT_USER SAFE_WRITE_SLOW_IN_MAPPED_RANGE SAFE_WRITE_SLOW_READ_ONLY SAFE_WRITE_SLOW_HAS_CODE SAFE_READ_WRITE_FAST SAFE_READ_WRITE_SLOW_PAGE_CROSSED SAFE_READ_WRITE_SLOW_NOT_VALID SAFE_READ_WRITE_SLOW_NOT_USER SAFE_READ_WRITE_SLOW_IN_MAPPED_RANGE SAFE_READ_WRITE_SLOW_READ_ONLY SAFE_READ_WRITE_SLOW_HAS_CODE PAGE_FAULT TLB_MISS MAIN_LOOP MAIN_LOOP_IDLE DO_MANY_CYCLES CYCLE_INTERNAL INVALIDATE_ALL_MODULES_NO_FREE_WASM_INDICES INVALIDATE_MODULE_WRITTEN_WHILE_COMPILED INVALIDATE_MODULE_UNUSED_AFTER_OVERWRITE INVALIDATE_MODULE_DIRTY_PAGE INVALIDATE_PAGE_HAD_CODE INVALIDATE_PAGE_HAD_ENTRY_POINTS DIRTY_PAGE_DID_NOT_HAVE_CODE RUN_FROM_CACHE_EXIT_SAME_PAGE RUN_FROM_CACHE_EXIT_NEAR_END_OF_PAGE RUN_FROM_CACHE_EXIT_DIFFERENT_PAGE CLEAR_TLB FULL_CLEAR_TLB TLB_FULL TLB_GLOBAL_FULL MODRM_SIMPLE_REG MODRM_SIMPLE_REG_WITH_OFFSET MODRM_SIMPLE_CONST_OFFSET MODRM_COMPLEX SEG_OFFSET_OPTIMISED SEG_OFFSET_NOT_OPTIMISED SEG_OFFSET_NOT_OPTIMISED_ES SEG_OFFSET_NOT_OPTIMISED_FS SEG_OFFSET_NOT_OPTIMISED_GS SEG_OFFSET_NOT_OPTIMISED_NOT_FLAT".split(" "),
|
||||
d=0;const e={};for(let f=0;f<c.length;f++){const k=c[f];var g=void 0;if(k.includes("/")){d++;const [l,m]=k.split("/");g=e[l]/e[m]}else g=e[k]=a.wm.exports.profiler_stat_get(f-d),g=1E8<=g?Math.round(g/1E6)+"m":1E5<=g?Math.round(g/1E3)+"k":g;b+=k+"="+g+"\n"}b+="\n";c=a.wm.exports.get_valid_tlb_entries_count();d=a.wm.exports.get_valid_global_tlb_entries_count();b=b+("TLB_ENTRIES="+c+" ("+d+" global, "+(c-d)+" non-global)\nWASM_TABLE_FREE=")+(a.wm.exports.jit_get_wasm_table_index_free_list_count()+"\n");
|
||||
b+="JIT_CACHE_SIZE="+a.wm.exports.jit_get_cache_size()+"\n";b+="FLAT_SEGMENTS="+a.wm.exports.has_flat_segmentation()+"\n";b+="wasm memory size: "+(a.wasm_memory.buffer.byteLength>>20)+"m\n";b=b+"Config:\nJIT_DISABLED="+(a.wm.exports.get_jit_config(0)+"\n");b+="MAX_PAGES="+a.wm.exports.get_jit_config(1)+"\n";b+="JIT_USE_LOOP_SAFETY="+!!a.wm.exports.get_jit_config(2)+"\n";return b+="MAX_EXTRA_BASIC_BLOCKS="+a.wm.exports.get_jit_config(3)+"\n"},print_instruction_counts:function(a){return[Fb.print_instruction_counts_offset(a,
|
||||
!1,!1,!1,!1),Fb.print_instruction_counts_offset(a,!0,!1,!1,!1),Fb.print_instruction_counts_offset(a,!1,!0,!1,!1),Fb.print_instruction_counts_offset(a,!1,!1,!0,!1),Fb.print_instruction_counts_offset(a,!1,!1,!1,!0)].join("\n\n")},print_instruction_counts_offset:function(a,b,c,d,e){let g="";var f=[],k=b?"compiled":c?"jit exit":d?"unguarded register":e?"wasm size":"executed";for(let n=0;256>n;n++)for(let p=0;8>p;p++)for(let t of[!1,!0]){var l=a.wm.exports.get_opstats_buffer(b,c,d,e,n,!1,t,p);f.push({opcode:n,
|
||||
count:l,is_mem:t,fixed_g:p});l=a.wm.exports.get_opstats_buffer(b,c,d,e,n,!0,t,p);f.push({opcode:3840|n,count:l,is_mem:t,fixed_g:p})}a=0;b=new Set([38,46,54,62,100,101,102,103,240,242,243]);for(let {count:n,opcode:p}of f)b.has(p)||(a+=n);if(0===a)return"";c=new Uint32Array(256);b=new Uint32Array(256);for(let {opcode:n,count:p}of f)3840==(n&65280)?b[n&255]+=p:c[n&255]+=p;g=g+"------------------\nTotal: "+(a+"\n");const m=1E7<a?1E3:1;d=Math.max.apply(Math,f.map(({count:n})=>Math.round(n/m)));d=String(d).length;
|
||||
g+=`Instruction counts ${k} (in ${m}):\n`;for(e=0;256>e;e++)g+=e.toString(16).padStart(2,"0")+":"+r.pads(Math.round(c[e]/m),d),g=15==e%16?g+"\n":g+" ";g=g+"\n"+`Instruction counts ${k} (0f, in ${m}):\n`;for(k=0;256>k;k++)g+=(k&255).toString(16).padStart(2,"0")+":"+r.pads(Math.round(b[k]/m),d),g=15==k%16?g+"\n":g+" ";g+="\n";f=f.filter(({count:n})=>n).sort(({count:n},{count:p})=>p-n);for(let {opcode:n,is_mem:p,fixed_g:t,count:q}of f.slice(0,200))f=n.toString(16)+"_"+t+(p?"_m":"_r"),g+=f+":"+(q/a*100).toFixed(2)+
|
||||
" ";return g+"\n"}};"undefined"!==typeof module&&"undefined"!==typeof module.exports&&(module.exports.print_stats=Fb);function xb(){this.filedata=new Map}xb.prototype.read=async function(a,b,c){return(a=this.filedata.get(a))?a.subarray(b,b+c):null};xb.prototype.cache=async function(a,b){this.filedata.set(a,b)};xb.prototype.uncache=function(a){this.filedata.delete(a)};function yb(a,b){this.storage=a;this.baseurl=b}yb.prototype.load_from_server=function(a){return new Promise(b=>{r.load_file(this.baseurl+a,{done:async c=>{c=new Uint8Array(c);await this.cache(a,c);b(c)}})})};
|
||||
yb.prototype.read=async function(a,b,c){const d=await this.storage.read(a,b,c);return d?d:(await this.load_from_server(a)).subarray(b,b+c)};yb.prototype.cache=async function(a,b){return await this.storage.cache(a,b)};yb.prototype.uncache=function(a){this.storage.uncache(a)};
|
||||
"undefined"!==typeof window?(window.MemoryFileStorage=xb,window.ServerFileStorageWrapper=yb):"undefined"!==typeof module&&"undefined"!==typeof module.exports?(module.exports.MemoryFileStorage=xb,module.exports.ServerFileStorageWrapper=yb):"function"===typeof importScripts&&(self.MemoryFileStorage=xb,self.ServerFileStorageWrapper=yb);var ha=16384,ia=4;function Z(a,b){this.inodes=[];this.events=[];this.storage=a;this.qidcounter=b||{last_qidnumber:0};this.inodedata={};this.total_size=274877906944;this.used_size=0;this.mounts=[];this.CreateDirectory("",-1)}Z.prototype.get_state=function(){let a=[];a[0]=this.inodes;a[1]=this.qidcounter.last_qidnumber;a[2]=[];for(const [b,c]of Object.entries(this.inodedata))0===(this.inodes[b].mode&ha)&&a[2].push([b,c]);a[3]=this.total_size;a[4]=this.used_size;return a=a.concat(this.mounts)};
|
||||
Z.prototype.set_state=function(a){this.inodes=a[0].map(b=>{const c=new Gb(0);c.set_state(b);return c});this.qidcounter.last_qidnumber=a[1];this.inodedata={};for(let [b,c]of a[2])c.buffer.byteLength!==c.byteLength&&(c=c.slice()),this.inodedata[b]=c;this.total_size=a[3];this.used_size=a[4];this.mounts=a.slice(5)};Z.prototype.AddEvent=function(a,b){var c=this.inodes[a];0==c.status||2==c.status?b():this.is_forwarder(c)?this.follow_fs(c).AddEvent(c.foreign_id,b):this.events.push({id:a,OnEvent:b})};
|
||||
Z.prototype.HandleEvent=function(a){var b=this.inodes[a];this.is_forwarder(b)&&this.follow_fs(b).HandleEvent(b.foreign_id);b=[];for(var c=0;c<this.events.length;c++)this.events[c].id==a?this.events[c].OnEvent():b.push(this.events[c]);this.events=b};
|
||||
Z.prototype.load_from_json=function(a,b){if(3!==a.version)throw"The filesystem JSON format has changed. Please update your fs2json (https://github.com/copy/fs2json) and recreate the filesystem JSON.";var c=a.fsroot;this.used_size=a.size;for(a=0;a<c.length;a++)this.LoadRecursive(c[a],0);b&&b()};
|
||||
Z.prototype.LoadRecursive=function(a,b){var c=this.CreateInode();const d=a[0];c.size=a[1];c.mtime=a[2];c.ctime=c.mtime;c.atime=c.mtime;c.mode=a[3];c.uid=a[4];c.gid=a[5];var e=c.mode&61440;e===ha?(this.PushInode(c,b,d),this.LoadDir(this.inodes.length-1,a[6])):32768===e?(c.status=2,c.sha256sum=a[6],this.PushInode(c,b,d)):40960===e?(c.symlink=a[6],this.PushInode(c,b,d)):49152!==e&&A(e)};Z.prototype.LoadDir=function(a,b){for(var c=0;c<b.length;c++)this.LoadRecursive(b[c],a)};
|
||||
Z.prototype.should_be_linked=function(a){return!this.is_forwarder(a)||0===a.foreign_id};Z.prototype.link_under_dir=function(a,b,c){const d=this.inodes[b],e=this.inodes[a];this.is_forwarder(e);this.IsDirectory(a);this.should_be_linked(d);e.direntries.has(c);e.direntries.set(c,b);d.nlinks++;this.IsDirectory(b)&&(d.direntries.has(".."),d.direntries.has(".")||d.nlinks++,d.direntries.set(".",b),d.direntries.set("..",a),e.nlinks++)};
|
||||
Z.prototype.unlink_from_dir=function(a,b){const c=this.Search(a,b),d=this.inodes[c],e=this.inodes[a];this.is_forwarder(e);this.IsDirectory(a);e.direntries.delete(b)&&(d.nlinks--,this.IsDirectory(c)&&(d.direntries.get(".."),d.direntries.delete(".."),e.nlinks--))};
|
||||
Z.prototype.PushInode=function(a,b,c){-1!=b?(this.inodes.push(a),a.fid=this.inodes.length-1,this.link_under_dir(b,a.fid,c)):0==this.inodes.length?(this.inodes.push(a),a.direntries.set(".",0),a.direntries.set("..",0),a.nlinks=2):(y.Debug("Error in Filesystem: Pushed inode with name = "+c+" has no parent"),y.Abort())};
|
||||
function Gb(a){this.direntries=new Map;this.minor=this.major=this.mtime=this.atime=this.ctime=this.fid=this.gid=this.uid=this.size=this.status=0;this.symlink="";this.mode=493;this.qid={type:0,version:0,path:a};this.caps=void 0;this.nlinks=0;this.sha256sum="";this.locks=[];this.foreign_id=this.mount_id=-1}
|
||||
Gb.prototype.get_state=function(){const a=[];a[0]=this.mode;a[1]=(this.mode&61440)===ha?[...this.direntries]:32768===(this.mode&61440)?this.sha256sum:40960===(this.mode&61440)?this.symlink:49152===(this.mode&61440)?[this.minor,this.major]:null;a[2]=this.locks;a[3]=this.status;a[4]=this.size;a[5]=this.uid;a[6]=this.gid;a[7]=this.fid;a[8]=this.ctime;a[9]=this.atime;a[10]=this.mtime;a[11]=this.qid.version;a[12]=this.qid.path;a[13]=this.nlinks;return a};
|
||||
Gb.prototype.set_state=function(a){this.mode=a[0];if((this.mode&61440)===ha){this.direntries=new Map;for(const [b,c]of a[1])this.direntries.set(b,c)}else 32768===(this.mode&61440)?this.sha256sum=a[1]:40960===(this.mode&61440)?this.symlink=a[1]:49152===(this.mode&61440)&&([this.minor,this.major]=a[1]);this.locks=[];for(const b of a[2]){const c=new Hb;c.set_state(b);this.locks.push(c)}this.status=a[3];this.size=a[4];this.uid=a[5];this.gid=a[6];this.fid=a[7];this.ctime=a[8];this.atime=a[9];this.mtime=
|
||||
a[10];this.qid.type=(this.mode&61440)>>8;this.qid.version=a[11];this.qid.path=a[12];this.nlinks=a[13]};
|
||||
Z.prototype.divert=function(a,b){const c=this.Search(a,b),d=this.inodes[c],e=new Gb(-1);this.IsDirectory(c);Object.assign(e,d);const g=this.inodes.length;this.inodes.push(e);e.fid=g;this.is_forwarder(d)&&this.mounts[d.mount_id].backtrack.set(d.foreign_id,g);this.should_be_linked(d)&&(this.unlink_from_dir(a,b),this.link_under_dir(a,g,b));if(this.IsDirectory(c)&&!this.is_forwarder(d))for(const [f,k]of e.direntries)"."!==f&&".."!==f&&this.IsDirectory(k)&&this.inodes[k].direntries.set("..",g);this.inodedata[g]=
|
||||
this.inodedata[c];delete this.inodedata[c];d.direntries=new Map;d.nlinks=0;return g};Z.prototype.copy_inode=function(a,b){Object.assign(b,a,{fid:b.fid,direntries:b.direntries,nlinks:b.nlinks})};Z.prototype.CreateInode=function(){const a=Math.round(Date.now()/1E3),b=new Gb(++this.qidcounter.last_qidnumber);b.atime=b.ctime=b.mtime=a;return b};
|
||||
Z.prototype.CreateDirectory=function(a,b){var c=this.inodes[b];if(0<=b&&this.is_forwarder(c))return b=c.foreign_id,a=this.follow_fs(c).CreateDirectory(a,b),this.create_forwarder(c.mount_id,a);c=this.CreateInode();c.mode=511|ha;0<=b&&(c.uid=this.inodes[b].uid,c.gid=this.inodes[b].gid,c.mode=this.inodes[b].mode&511|ha);c.qid.type=ha>>8;this.PushInode(c,b,a);this.NotifyListeners(this.inodes.length-1,"newdir");return this.inodes.length-1};
|
||||
Z.prototype.CreateFile=function(a,b){var c=this.inodes[b];if(this.is_forwarder(c))return b=c.foreign_id,a=this.follow_fs(c).CreateFile(a,b),this.create_forwarder(c.mount_id,a);c=this.CreateInode();c.uid=this.inodes[b].uid;c.gid=this.inodes[b].gid;c.qid.type=128;c.mode=this.inodes[b].mode&438|32768;this.PushInode(c,b,a);this.NotifyListeners(this.inodes.length-1,"newfile");return this.inodes.length-1};
|
||||
Z.prototype.CreateNode=function(a,b,c,d){var e=this.inodes[b];if(this.is_forwarder(e))return b=e.foreign_id,a=this.follow_fs(e).CreateNode(a,b,c,d),this.create_forwarder(e.mount_id,a);e=this.CreateInode();e.major=c;e.minor=d;e.uid=this.inodes[b].uid;e.gid=this.inodes[b].gid;e.qid.type=192;e.mode=this.inodes[b].mode&438;this.PushInode(e,b,a);return this.inodes.length-1};
|
||||
Z.prototype.CreateSymlink=function(a,b,c){var d=this.inodes[b];if(this.is_forwarder(d))return b=d.foreign_id,a=this.follow_fs(d).CreateSymlink(a,b,c),this.create_forwarder(d.mount_id,a);d=this.CreateInode();d.uid=this.inodes[b].uid;d.gid=this.inodes[b].gid;d.qid.type=160;d.symlink=c;d.mode=40960;this.PushInode(d,b,a);return this.inodes.length-1};
|
||||
Z.prototype.CreateTextFile=async function(a,b,c){var d=this.inodes[b];if(this.is_forwarder(d))return b=d.foreign_id,c=await this.follow_fs(d).CreateTextFile(a,b,c),this.create_forwarder(d.mount_id,c);d=this.CreateFile(a,b);b=this.inodes[d];a=new Uint8Array(c.length);b.size=c.length;for(b=0;b<c.length;b++)a[b]=c.charCodeAt(b);await this.set_data(d,a);return d};
|
||||
Z.prototype.CreateBinaryFile=async function(a,b,c){var d=this.inodes[b];if(this.is_forwarder(d))return b=d.foreign_id,c=await this.follow_fs(d).CreateBinaryFile(a,b,c),this.create_forwarder(d.mount_id,c);d=this.CreateFile(a,b);a=this.inodes[d];b=new Uint8Array(c.length);b.set(c);await this.set_data(d,b);a.size=c.length;return d};
|
||||
Z.prototype.OpenInode=function(a,b){var c=this.inodes[a];if(this.is_forwarder(c))return this.follow_fs(c).OpenInode(c.foreign_id,b);(c.mode&61440)==ha&&this.FillDirectory(a);return!0};Z.prototype.CloseInode=async function(a){var b=this.inodes[a];if(this.is_forwarder(b))return await this.follow_fs(b).CloseInode(b.foreign_id);2===b.status&&this.storage.uncache(b.sha256sum);b.status==ia&&(b.status=-1,await this.DeleteData(a))};
|
||||
Z.prototype.Rename=async function(a,b,c,d){if(a==c&&b==d)return 0;var e=this.Search(a,b);if(-1===e)return-2;var g=this.GetFullPath(a)+"/"+b;if(-1!=this.Search(c,d)){var f=this.Unlink(c,d);if(0>f)return f}var k=this.inodes[e],l=this.inodes[a];f=this.inodes[c];if(this.is_forwarder(l)||this.is_forwarder(f))if(this.is_forwarder(l)&&l.mount_id===f.mount_id){if(a=await this.follow_fs(l).Rename(l.foreign_id,b,f.foreign_id,d),0>a)return a}else{if(this.is_a_root(e)||!this.IsDirectory(e)&&1<this.GetInode(e).nlinks)return-1;
|
||||
l=this.divert(a,b);const m=this.GetInode(e),n=await this.Read(l,0,m.size);this.is_forwarder(f)?(c=this.follow_fs(f),d=this.IsDirectory(l)?c.CreateDirectory(d,f.foreign_id):c.CreateFile(d,f.foreign_id),c=c.GetInode(d),this.copy_inode(m,c),this.set_forwarder(e,f.mount_id,d)):(this.delete_forwarder(k),this.copy_inode(m,k),this.link_under_dir(c,e,d));await this.ChangeSize(e,m.size);n&&n.length&&await this.Write(e,0,n.length,n);if(this.IsDirectory(e))for(const p of this.GetChildren(l))if(f=await this.Rename(l,
|
||||
p,e,p),0>f)return f;await this.DeleteData(l);a=this.Unlink(a,b);if(0>a)return a}else this.unlink_from_dir(a,b),this.link_under_dir(c,e,d),k.qid.version++;this.NotifyListeners(e,"rename",{oldpath:g});return 0};
|
||||
Z.prototype.Write=async function(a,b,c,d){this.NotifyListeners(a,"write");var e=this.inodes[a];if(this.is_forwarder(e))a=e.foreign_id,await this.follow_fs(e).Write(a,b,c,d);else{var g=await this.get_buffer(a);!g||g.length<b+c?(await this.ChangeSize(a,Math.floor(3*(b+c)/2)),e.size=b+c,g=await this.get_buffer(a)):e.size<b+c&&(e.size=b+c);d&&g.set(d.subarray(0,c),b);await this.set_data(a,g)}};
|
||||
Z.prototype.Read=async function(a,b,c){const d=this.inodes[a];return this.is_forwarder(d)?(a=d.foreign_id,await this.follow_fs(d).Read(a,b,c)):await this.get_data(a,b,c)};Z.prototype.Search=function(a,b){a=this.inodes[a];if(this.is_forwarder(a)){const c=a.foreign_id;b=this.follow_fs(a).Search(c,b);return-1===b?-1:this.get_forwarder(a.mount_id,b)}b=a.direntries.get(b);return void 0===b?-1:b};
|
||||
Z.prototype.CountUsedInodes=function(){let a=this.inodes.length;for(const {fs:b,backtrack:c}of this.mounts)a+=b.CountUsedInodes(),a-=c.size;return a};Z.prototype.CountFreeInodes=function(){let a=1048576;for(const {fs:b}of this.mounts)a+=b.CountFreeInodes();return a};Z.prototype.GetTotalSize=function(){let a=this.used_size;for(const {fs:b}of this.mounts)a+=b.GetTotalSize();return a};Z.prototype.GetSpace=function(){let a=this.total_size;for(const {fs:b}of this.mounts)a+=b.GetSpace();return this.total_size};
|
||||
Z.prototype.GetDirectoryName=function(a){const b=this.inodes[this.GetParent(a)];if(this.is_forwarder(b))return this.follow_fs(b).GetDirectoryName(this.inodes[a].foreign_id);if(!b)return"";for(const [c,d]of b.direntries)if(d===a)return c;return""};Z.prototype.GetFullPath=function(a){this.IsDirectory(a);for(var b="";0!=a;)b="/"+this.GetDirectoryName(a)+b,a=this.GetParent(a);return b.substring(1)};
|
||||
Z.prototype.Link=function(a,b,c){if(this.IsDirectory(b))return-1;const d=this.inodes[a],e=this.inodes[b];if(this.is_forwarder(d))return this.is_forwarder(e)&&e.mount_id===d.mount_id?this.follow_fs(d).Link(d.foreign_id,e.foreign_id,c):-1;if(this.is_forwarder(e))return-1;this.link_under_dir(a,b,c);return 0};
|
||||
Z.prototype.Unlink=function(a,b){if("."===b||".."===b)return-1;const c=this.Search(a,b),d=this.inodes[c],e=this.inodes[a];if(this.is_forwarder(e))return this.is_forwarder(d),a=e.foreign_id,this.follow_fs(e).Unlink(a,b);if(this.IsDirectory(c)&&!this.IsEmpty(c))return-39;this.unlink_from_dir(a,b);0===d.nlinks&&(d.status=ia,this.NotifyListeners(c,"delete"));return 0};
|
||||
Z.prototype.DeleteData=async function(a){const b=this.inodes[a];this.is_forwarder(b)?await this.follow_fs(b).DeleteData(b.foreign_id):(b.size=0,delete this.inodedata[a])};Z.prototype.get_buffer=async function(a){const b=this.inodes[a];return this.inodedata[a]?this.inodedata[a]:2===b.status?await this.storage.read(b.sha256sum,0,b.size):null};
|
||||
Z.prototype.get_data=async function(a,b,c){const d=this.inodes[a];return this.inodedata[a]?this.inodedata[a].subarray(b,b+c):2===d.status?await this.storage.read(d.sha256sum,b,c):null};Z.prototype.set_data=async function(a,b){this.inodedata[a]=b;2===this.inodes[a].status&&(this.inodes[a].status=0,this.storage.uncache(this.inodes[a].sha256sum))};Z.prototype.GetInode=function(a){isNaN(a);a=this.inodes[a];return this.is_forwarder(a)?this.follow_fs(a).GetInode(a.foreign_id):a};
|
||||
Z.prototype.ChangeSize=async function(a,b){var c=this.GetInode(a),d=await this.get_data(a,0,c.size);if(b!=c.size){var e=new Uint8Array(b);c.size=b;d&&e.set(d.subarray(0,Math.min(d.length,c.size)),0);await this.set_data(a,e)}};
|
||||
Z.prototype.SearchPath=function(a){a=a.replace("//","/");a=a.split("/");0<a.length&&0===a[a.length-1].length&&a.pop();0<a.length&&0===a[0].length&&a.shift();const b=a.length;var c=-1,d=0;let e=null;for(var g=0;g<b;g++)if(c=d,d=this.Search(c,a[g]),!e&&this.is_forwarder(this.inodes[c])&&(e="/"+a.slice(g).join("/")),-1==d)return g<b-1?{id:-1,parentid:-1,name:a[g],forward_path:e}:{id:-1,parentid:c,name:a[g],forward_path:e};return{id:d,parentid:c,name:a[g],forward_path:e}};
|
||||
Z.prototype.GetRecursiveList=function(a,b){if(this.is_forwarder(this.inodes[a])){const c=this.follow_fs(this.inodes[a]),d=this.inodes[a].mount_id,e=b.length;c.GetRecursiveList(this.inodes[a].foreign_id,b);for(a=e;a<b.length;a++)b[a].parentid=this.get_forwarder(d,b[a].parentid)}else for(const [c,d]of this.inodes[a].direntries)"."!==c&&".."!==c&&(b.push({parentid:a,name:c}),this.IsDirectory(d)&&this.GetRecursiveList(d,b))};
|
||||
Z.prototype.RecursiveDelete=function(a){var b=[];a=this.SearchPath(a);if(-1!==a.id)for(this.GetRecursiveList(a.id,b),a=b.length-1;0<=a;a--)this.Unlink(b[a].parentid,b[a].name)};Z.prototype.DeleteNode=function(a){var b=this.SearchPath(a);-1!=b.id&&(32768==(this.inodes[b.id].mode&61440)?this.Unlink(b.parentid,b.name):(this.inodes[b.id].mode&61440)==ha&&(this.RecursiveDelete(a),this.Unlink(b.parentid,b.name)))};Z.prototype.NotifyListeners=function(){};
|
||||
Z.prototype.Check=function(){for(var a=1;a<this.inodes.length;a++)if(-1!=this.inodes[a].status){var b=this.GetInode(a);0>b.nlinks&&y.Debug("Error in filesystem: negative nlinks="+b.nlinks+" at id ="+a);if(this.IsDirectory(a)){b=this.GetInode(a);this.IsDirectory(a)&&0>this.GetParent(a)&&y.Debug("Error in filesystem: negative parent id "+a);for(const [c,d]of b.direntries){0===c.length&&y.Debug("Error in filesystem: inode with no name and id "+d);for(const e of c)32>e&&y.Debug("Error in filesystem: Unallowed char in filename")}}}};
|
||||
Z.prototype.FillDirectory=function(a){var b=this.inodes[a];if(this.is_forwarder(b))this.follow_fs(b).FillDirectory(b.foreign_id);else{var c=0;for(const d of b.direntries.keys())c+=24+Ib.UTF8Length(d);a=this.inodedata[a]=new Uint8Array(c);b.size=c;c=0;for(const [d,e]of b.direntries)b=this.GetInode(e),c+=v.Marshall(["Q","d","b","s"],[b.qid,c+13+8+1+2+Ib.UTF8Length(d),b.mode>>12,d],a,c)}};
|
||||
Z.prototype.RoundToDirentry=function(a,b){a=this.inodedata[a];if(b>=a.length)return a.length;let c=0;for(;;){const d=v.Unmarshall(["Q","d"],a,{offset:c})[1];if(d>b)break;c=d}return c};Z.prototype.IsDirectory=function(a){a=this.inodes[a];return this.is_forwarder(a)?this.follow_fs(a).IsDirectory(a.foreign_id):(a.mode&61440)===ha};
|
||||
Z.prototype.IsEmpty=function(a){a=this.inodes[a];if(this.is_forwarder(a))return this.follow_fs(a).IsDirectory(a.foreign_id);for(const b of a.direntries.keys())if("."!==b&&".."!==b)return!1;return!0};Z.prototype.GetChildren=function(a){this.IsDirectory(a);a=this.inodes[a];if(this.is_forwarder(a))return this.follow_fs(a).GetChildren(a.foreign_id);const b=[];for(const c of a.direntries.keys())"."!==c&&".."!==c&&b.push(c);return b};
|
||||
Z.prototype.GetParent=function(a){this.IsDirectory(a);a=this.inodes[a];if(this.should_be_linked(a))return a.direntries.get("..");const b=this.follow_fs(a).GetParent(a.foreign_id);return this.get_forwarder(a.mount_id,b)};
|
||||
Z.prototype.PrepareCAPs=function(a){a=this.GetInode(a);if(a.caps)return a.caps.length;a.caps=new Uint8Array(20);a.caps[0]=0;a.caps[1]=0;a.caps[2]=0;a.caps[3]=2;a.caps[4]=255;a.caps[5]=255;a.caps[6]=255;a.caps[7]=255;a.caps[8]=255;a.caps[9]=255;a.caps[10]=255;a.caps[11]=255;a.caps[12]=63;a.caps[13]=0;a.caps[14]=0;a.caps[15]=0;a.caps[16]=63;a.caps[17]=0;a.caps[18]=0;a.caps[19]=0;return a.caps.length};function Jb(a){this.fs=a;this.backtrack=new Map}
|
||||
Jb.prototype.get_state=function(){const a=[];a[0]=this.fs;a[1]=[...this.backtrack];return a};Jb.prototype.set_state=function(a){this.fs=a[0];this.backtrack=new Map(a[1])};Z.prototype.set_forwarder=function(a,b,c){const d=this.inodes[a];this.is_forwarder(d)&&this.mounts[d.mount_id].backtrack.delete(d.foreign_id);d.status=5;d.mount_id=b;d.foreign_id=c;this.mounts[b].backtrack.set(c,a)};
|
||||
Z.prototype.create_forwarder=function(a,b){const c=this.CreateInode(),d=this.inodes.length;this.inodes.push(c);c.fid=d;this.set_forwarder(d,a,b);return d};Z.prototype.is_forwarder=function(a){return 5===a.status};Z.prototype.is_a_root=function(a){return 0===this.GetInode(a).fid};Z.prototype.get_forwarder=function(a,b){const c=this.mounts[a].backtrack.get(b);return void 0===c?this.create_forwarder(a,b):c};Z.prototype.delete_forwarder=function(a){this.is_forwarder(a);a.status=-1;this.mounts[a.mount_id].backtrack.delete(a.foreign_id)};
|
||||
Z.prototype.follow_fs=function(a){const b=this.mounts[a.mount_id];this.is_forwarder(a);return b.fs};Z.prototype.Mount=function(a,b){a=this.SearchPath(a);if(-1===a.parentid)return-2;if(-1!==a.id)return-17;if(a.forward_path){var c=this.inodes[a.parentid];b=this.follow_fs(c).Mount(a.forward_path,b);return 0>b?b:this.get_forwarder(c.mount_id,b)}c=this.mounts.length;this.mounts.push(new Jb(b));b=this.create_forwarder(c,0);this.link_under_dir(a.parentid,b,a.name);return b};
|
||||
function Hb(){this.type=2;this.start=0;this.length=Infinity;this.proc_id=-1;this.client_id=""}Hb.prototype.get_state=function(){const a=[];a[0]=this.type;a[1]=this.start;a[2]=Infinity===this.length?0:this.length;a[3]=this.proc_id;a[4]=this.client_id;return a};Hb.prototype.set_state=function(a){this.type=a[0];this.start=a[1];this.length=0===a[2]?Infinity:a[2];this.proc_id=a[3];this.client_id=a[4]};Hb.prototype.clone=function(){const a=new Hb;a.set_state(this.get_state());return a};
|
||||
Hb.prototype.conflicts_with=function(a){return this.proc_id===a.proc_id&&this.client_id===a.client_id||2===this.type||2===a.type||1!==this.type&&1!==a.type||this.start+this.length<=a.start||a.start+a.length<=this.start?!1:!0};Hb.prototype.is_alike=function(a){return a.proc_id===this.proc_id&&a.client_id===this.client_id&&a.type===this.type};Hb.prototype.may_merge_after=function(a){return this.is_alike(a)&&a.start+a.length===this.start};
|
||||
Z.prototype.DescribeLock=function(a,b,c,d,e){const g=new Hb;g.type=a;g.start=b;g.length=c;g.proc_id=d;g.client_id=e;return g};Z.prototype.GetLock=function(a,b){a=this.inodes[a];if(this.is_forwarder(a)){var c=a.foreign_id;return this.follow_fs(a).GetLock(c,b)}for(c of a.locks)if(b.conflicts_with(c))return c.clone();return null};
|
||||
Z.prototype.Lock=function(a,b,c){const d=this.inodes[a];if(this.is_forwarder(d))return a=d.foreign_id,this.follow_fs(d).Lock(a,b,c);b=b.clone();if(2!==b.type&&this.GetLock(a,b))return 1;for(c=0;c<d.locks.length;c++){a=d.locks[c];if(a.start+a.length<=b.start)continue;if(b.start+b.length<=a.start)break;if(a.proc_id!==b.proc_id||a.client_id!==b.client_id){a.conflicts_with(b);continue}var e=b.start+b.length;const g=b.start-a.start,f=a.start+a.length-e;if(0<g&&0<f&&a.type===b.type)return 0;0<g&&(a.length=
|
||||
g);if(0>=g&&0<f)a.start=e,a.length=f;else if(0<f){for(;c<d.locks.length&&d.locks[c].start<e;)c++;d.locks.splice(c,0,this.DescribeLock(a.type,e,f,a.proc_id,a.client_id))}else 0>=g&&(d.locks.splice(c,1),c--)}if(2!==b.type){c=b;a=!1;for(e=0;e<d.locks.length&&!(c.may_merge_after(d.locks[e])&&(d.locks[e].length+=b.length,c=d.locks[e],a=!0),b.start<=d.locks[e].start);e++);a||(d.locks.splice(e,0,c),e++);for(;e<d.locks.length;e++)if(d.locks[e].is_alike(c)){d.locks[e].may_merge_after(c)&&(c.length+=d.locks[e].length,
|
||||
d.locks.splice(e,1));break}}return 0};Z.prototype.read_dir=function(a){a=this.SearchPath(a);if(-1!==a.id)return a=this.GetInode(a.id),Array.from(a.direntries.keys()).filter(b=>"."!==b&&".."!==b)};Z.prototype.read_file=function(a){a=this.SearchPath(a);if(-1===a.id)return Promise.resolve(null);const b=this.GetInode(a.id);return this.Read(a.id,0,b.size)};var y={Debug:function(a){[].slice.apply(arguments).join(" ")},Abort:function(){}};var v={Marshall:function(a,b,c,d){for(var e,g=0,f=0;f<a.length;f++)switch(e=b[f],a[f]){case "w":c[d++]=e&255;c[d++]=e>>8&255;c[d++]=e>>16&255;c[d++]=e>>24&255;g+=4;break;case "d":c[d++]=e&255;c[d++]=e>>8&255;c[d++]=e>>16&255;c[d++]=e>>24&255;c[d++]=0;c[d++]=0;c[d++]=0;c[d++]=0;g+=8;break;case "h":c[d++]=e&255;c[d++]=e>>8;g+=2;break;case "b":c[d++]=e;g+=1;break;case "s":var k=d,l=0;c[d++]=0;c[d++]=0;g+=2;for(var m of e)Kb(m.charCodeAt(0)).forEach(function(n){c[d++]=n;g+=1;l++});c[k+0]=l&255;c[k+1]=
|
||||
l>>8&255;break;case "Q":v.Marshall(["b","w","d"],[e.type,e.version,e.path],c,d);d+=13;g+=13;break;default:y.Debug("Marshall: Unknown type="+a[f])}return g},Unmarshall:function(a,b,c){let d=c.offset;for(var e=[],g=0;g<a.length;g++)switch(a[g]){case "w":var f=b[d++];f+=b[d++]<<8;f+=b[d++]<<16;f+=b[d++]<<24>>>0;e.push(f);break;case "d":f=b[d++];f+=b[d++]<<8;f+=b[d++]<<16;f+=b[d++]<<24>>>0;d+=4;e.push(f);break;case "h":f=b[d++];e.push(f+(b[d++]<<8));break;case "b":e.push(b[d++]);break;case "s":f=b[d++];
|
||||
f+=b[d++]<<8;for(var k="",l=new Lb,m=0;m<f;m++){var n=l.Put(b[d++]);-1!=n&&(k+=String.fromCharCode(n))}e.push(k);break;case "Q":c.offset=d;f=v.Unmarshall(["b","w","d"],b,c);d=c.offset;e.push({type:f[0],version:f[1],path:f[2]});break;default:y.Debug("Error in Unmarshall: Unknown type="+a[g])}c.offset=d;return e}};var Ib={};function Lb(){this.stream=new Uint8Array(5);this.ofs=0;this.Put=function(a){this.stream[this.ofs]=a;this.ofs++;switch(this.ofs){case 1:if(128>this.stream[0])return this.ofs=0,this.stream[0];break;case 2:if(192==(this.stream[0]&224)&&128==(this.stream[1]&192))return this.ofs=0,(this.stream[0]&31)<<6|this.stream[1]&63}return-1}}function Kb(a){if(128>a)return[a];if(2048>a)return[192|a>>6&31,128|a&63]}
|
||||
Ib.UTF8Length=function(a){for(var b=0,c=0;c<a.length;c++){var d=a.charCodeAt(c);b+=128>d?1:2}return b};}).call(this);
|
||||
+1417
File diff suppressed because it is too large.
Load diff
+218
@@ -0,0 +1,218 @@
|
||||
/**
|
||||
* Copyright (c) 2014 The xterm.js authors. All rights reserved.
|
||||
* Copyright (c) 2012-2013, Christopher Jeffrey (MIT License)
|
||||
* https://github.com/chjj/term.js
|
||||
* @license MIT
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* Originally forked from (with the author's permission):
|
||||
* Fabrice Bellard's javascript vt100 for jslinux:
|
||||
* http://bellard.org/jslinux/
|
||||
* Copyright (c) 2011 Fabrice Bellard
|
||||
* The original design remains. The terminal itself
|
||||
* has been extended to include xterm CSI codes, among
|
||||
* other features.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Default styles for xterm.js
|
||||
*/
|
||||
|
||||
.xterm {
|
||||
cursor: text;
|
||||
position: relative;
|
||||
user-select: none;
|
||||
-ms-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
}
|
||||
|
||||
.xterm.focus,
|
||||
.xterm:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.xterm .xterm-helpers {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
/**
|
||||
* The z-index of the helpers must be higher than the canvases in order for
|
||||
* IMEs to appear on top.
|
||||
*/
|
||||
z-index: 5;
|
||||
}
|
||||
|
||||
.xterm .xterm-helper-textarea {
|
||||
padding: 0;
|
||||
border: 0;
|
||||
margin: 0;
|
||||
/* Move textarea out of the screen to the far left, so that the cursor is not visible */
|
||||
position: absolute;
|
||||
opacity: 0;
|
||||
left: -9999em;
|
||||
top: 0;
|
||||
width: 0;
|
||||
height: 0;
|
||||
z-index: -5;
|
||||
/** Prevent wrapping so the IME appears against the textarea at the correct position */
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
resize: none;
|
||||
}
|
||||
|
||||
.xterm .composition-view {
|
||||
/* TODO: Composition position got messed up somewhere */
|
||||
background: #000;
|
||||
color: #FFF;
|
||||
display: none;
|
||||
position: absolute;
|
||||
white-space: nowrap;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.xterm .composition-view.active {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.xterm .xterm-viewport {
|
||||
/* On OS X this is required in order for the scroll bar to appear fully opaque */
|
||||
background-color: #000;
|
||||
overflow-y: scroll;
|
||||
cursor: default;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
left: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.xterm .xterm-screen {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.xterm .xterm-screen canvas {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.xterm .xterm-scroll-area {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.xterm-char-measure-element {
|
||||
display: inline-block;
|
||||
visibility: hidden;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: -9999em;
|
||||
line-height: normal;
|
||||
}
|
||||
|
||||
.xterm.enable-mouse-events {
|
||||
/* When mouse events are enabled (eg. tmux), revert to the standard pointer cursor */
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.xterm.xterm-cursor-pointer,
|
||||
.xterm .xterm-cursor-pointer {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.xterm.column-select.focus {
|
||||
/* Column selection mode */
|
||||
cursor: crosshair;
|
||||
}
|
||||
|
||||
.xterm .xterm-accessibility:not(.debug),
|
||||
.xterm .xterm-message {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
z-index: 10;
|
||||
color: transparent;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.xterm .xterm-accessibility-tree:not(.debug) *::selection {
|
||||
color: transparent;
|
||||
}
|
||||
|
||||
.xterm .xterm-accessibility-tree {
|
||||
user-select: text;
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
.xterm .live-region {
|
||||
position: absolute;
|
||||
left: -9999px;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.xterm-dim {
|
||||
/* Dim should not apply to background, so the opacity of the foreground color is applied
|
||||
* explicitly in the generated class and reset to 1 here */
|
||||
opacity: 1 !important;
|
||||
}
|
||||
|
||||
.xterm-underline-1 { text-decoration: underline; }
|
||||
.xterm-underline-2 { text-decoration: double underline; }
|
||||
.xterm-underline-3 { text-decoration: wavy underline; }
|
||||
.xterm-underline-4 { text-decoration: dotted underline; }
|
||||
.xterm-underline-5 { text-decoration: dashed underline; }
|
||||
|
||||
.xterm-overline {
|
||||
text-decoration: overline;
|
||||
}
|
||||
|
||||
.xterm-overline.xterm-underline-1 { text-decoration: overline underline; }
|
||||
.xterm-overline.xterm-underline-2 { text-decoration: overline double underline; }
|
||||
.xterm-overline.xterm-underline-3 { text-decoration: overline wavy underline; }
|
||||
.xterm-overline.xterm-underline-4 { text-decoration: overline dotted underline; }
|
||||
.xterm-overline.xterm-underline-5 { text-decoration: overline dashed underline; }
|
||||
|
||||
.xterm-strikethrough {
|
||||
text-decoration: line-through;
|
||||
}
|
||||
|
||||
.xterm-screen .xterm-decoration-container .xterm-decoration {
|
||||
z-index: 6;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.xterm-screen .xterm-decoration-container .xterm-decoration.xterm-decoration-top-layer {
|
||||
z-index: 7;
|
||||
}
|
||||
|
||||
.xterm-decoration-overview-ruler {
|
||||
z-index: 8;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.xterm-decoration-top {
|
||||
z-index: 2;
|
||||
position: relative;
|
||||
}
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
!function(e,t){if("object"==typeof exports&&"object"==typeof module)module.exports=t();else if("function"==typeof define&&define.amd)define([],t);else{var i=t();for(var s in i)("object"==typeof exports?exports:e)[s]=i[s]}}(globalThis,(()=>(()=>{"use strict";var e={4567:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(o=(n<3?r(o):n>3?r(t,i,o):r(t,i))||o);return n>3&&o&&Object.defineProperty(t,i,o),o},r=this&&this.__param||function(e,t){return function(i,s){t(i,s,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.AccessibilityManager=void 0;const n=i(9042),o=i(9924),a=i(844),h=i(4725),c=i(2585),l=i(3656);let d=t.AccessibilityManager=class extends a.Disposable{constructor(e,t,i,s){super(),this._terminal=e,this._coreBrowserService=i,this._renderService=s,this._rowColumns=new WeakMap,this._liveRegionLineCount=0,this._charsToConsume=[],this._charsToAnnounce="",this._accessibilityContainer=this._coreBrowserService.mainDocument.createElement("div"),this._accessibilityContainer.classList.add("xterm-accessibility"),this._rowContainer=this._coreBrowserService.mainDocument.createElement("div"),this._rowContainer.setAttribute("role","list"),this._rowContainer.classList.add("xterm-accessibility-tree"),this._rowElements=[];for(let e=0;e<this._terminal.rows;e++)this._rowElements[e]=this._createAccessibilityTreeNode(),this._rowContainer.appendChild(this._rowElements[e]);if(this._topBoundaryFocusListener=e=>this._handleBoundaryFocus(e,0),this._bottomBoundaryFocusListener=e=>this._handleBoundaryFocus(e,1),this._rowElements[0].addEventListener("focus",this._topBoundaryFocusListener),this._rowElements[this._rowElements.length-1].addEventListener("focus",this._bottomBoundaryFocusListener),this._refreshRowsDimensions(),this._accessibilityContainer.appendChild(this._rowContainer),this._liveRegion=this._coreBrowserService.mainDocument.createElement("div"),this._liveRegion.classList.add("live-region"),this._liveRegion.setAttribute("aria-live","assertive"),this._accessibilityContainer.appendChild(this._liveRegion),this._liveRegionDebouncer=this.register(new o.TimeBasedDebouncer(this._renderRows.bind(this))),!this._terminal.element)throw new Error("Cannot enable accessibility before Terminal.open");this._terminal.element.insertAdjacentElement("afterbegin",this._accessibilityContainer),this.register(this._terminal.onResize((e=>this._handleResize(e.rows)))),this.register(this._terminal.onRender((e=>this._refreshRows(e.start,e.end)))),this.register(this._terminal.onScroll((()=>this._refreshRows()))),this.register(this._terminal.onA11yChar((e=>this._handleChar(e)))),this.register(this._terminal.onLineFeed((()=>this._handleChar("\n")))),this.register(this._terminal.onA11yTab((e=>this._handleTab(e)))),this.register(this._terminal.onKey((e=>this._handleKey(e.key)))),this.register(this._terminal.onBlur((()=>this._clearLiveRegion()))),this.register(this._renderService.onDimensionsChange((()=>this._refreshRowsDimensions()))),this.register((0,l.addDisposableDomListener)(document,"selectionchange",(()=>this._handleSelectionChange()))),this.register(this._coreBrowserService.onDprChange((()=>this._refreshRowsDimensions()))),this._refreshRows(),this.register((0,a.toDisposable)((()=>{this._accessibilityContainer.remove(),this._rowElements.length=0})))}_handleTab(e){for(let t=0;t<e;t++)this._handleChar(" ")}_handleChar(e){this._liveRegionLineCount<21&&(this._charsToConsume.length>0?this._charsToConsume.shift()!==e&&(this._charsToAnnounce+=e):this._charsToAnnounce+=e,"\n"===e&&(this._liveRegionLineCount++,21===this._liveRegionLineCount&&(this._liveRegion.textContent+=n.tooMuchOutput)))}_clearLiveRegion(){this._liveRegion.textContent="",this._liveRegionLineCount=0}_handleKey(e){this._clearLiveRegion(),/\p{Control}/u.test(e)||this._charsToConsume.push(e)}_refreshRows(e,t){this._liveRegionDebouncer.refresh(e,t,this._terminal.rows)}_renderRows(e,t){const i=this._terminal.buffer,s=i.lines.length.toString();for(let r=e;r<=t;r++){const e=i.lines.get(i.ydisp+r),t=[],n=e?.translateToString(!0,void 0,void 0,t)||"",o=(i.ydisp+r+1).toString(),a=this._rowElements[r];a&&(0===n.length?(a.innerText=" ",this._rowColumns.set(a,[0,1])):(a.textContent=n,this._rowColumns.set(a,t)),a.setAttribute("aria-posinset",o),a.setAttribute("aria-setsize",s))}this._announceCharacters()}_announceCharacters(){0!==this._charsToAnnounce.length&&(this._liveRegion.textContent+=this._charsToAnnounce,this._charsToAnnounce="")}_handleBoundaryFocus(e,t){const i=e.target,s=this._rowElements[0===t?1:this._rowElements.length-2];if(i.getAttribute("aria-posinset")===(0===t?"1":`${this._terminal.buffer.lines.length}`))return;if(e.relatedTarget!==s)return;let r,n;if(0===t?(r=i,n=this._rowElements.pop(),this._rowContainer.removeChild(n)):(r=this._rowElements.shiftLine truncated
|
||||
//# sourceMappingURL=xterm.js.map
|
||||
@@ -0,0 +1,13 @@
|
||||
# Puter Mods
|
||||
|
||||
A list of Puter mods which may be expanded in the future.
|
||||
|
||||
**Contributions of new mods are welcome.**
|
||||
|
||||
## kdmod
|
||||
|
||||
- **location:** [./kdmod](./kdmod)
|
||||
- **description:**
|
||||
> "kernel dev mod"; specifically for the devex needs of
|
||||
> GitHub user KernelDeimos and provided in case anyone else
|
||||
> finds it of any use.
|
||||
@@ -0,0 +1,60 @@
|
||||
const path = require('path');
|
||||
|
||||
class CustomPuterService extends use.Service {
|
||||
async _init () {
|
||||
const svc_commands = this.services.get('commands');
|
||||
this._register_commands(svc_commands);
|
||||
|
||||
const svc_puterHomepage = this.services.get('puter-homepage');
|
||||
svc_puterHomepage.register_script('/custom-gui/main.js');
|
||||
}
|
||||
['__on_install.routes'] (_, { app }) {
|
||||
const require = this.require;
|
||||
const express = require('express');
|
||||
const path_ = require('path');
|
||||
|
||||
app.use('/custom-gui',
|
||||
express.static(path.join(__dirname, 'gui')));
|
||||
}
|
||||
async ['__on_boot.consolidation'] () {
|
||||
const then = Date.now();
|
||||
this.tod_widget = () => {
|
||||
const s = 5 - Math.floor(
|
||||
(Date.now() - then) / 1000);
|
||||
const lines = [
|
||||
"\x1B[36;1mKDMOD ENABLED\x1B[0m" +
|
||||
` (👁️ ${s}s)`
|
||||
];
|
||||
// It would be super cool to be able to use this here
|
||||
// surrounding_box('33;1', lines);
|
||||
return lines;
|
||||
}
|
||||
|
||||
const svc_devConsole = this.services.get('dev-console', { optional: true });
|
||||
if ( ! svc_devConsole ) return;
|
||||
svc_devConsole.add_widget(this.tod_widget);
|
||||
|
||||
setTimeout(() => {
|
||||
svc_devConsole.remove_widget(this.tod_widget);
|
||||
}, 5000)
|
||||
}
|
||||
|
||||
_register_commands (commands) {
|
||||
commands.registerCommands('o', [
|
||||
{
|
||||
id: 'k',
|
||||
description: '',
|
||||
handler: async (_, log) => {
|
||||
const svc_devConsole = this.services.get('dev-console', { optional: true });
|
||||
if ( ! svc_devConsole ) return;
|
||||
svc_devConsole.remove_widget(this.tod_widget);
|
||||
const lines = this.tod_widget();
|
||||
for ( const line of lines ) log.log(line);
|
||||
this.tod_widget = null;
|
||||
}
|
||||
}
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { CustomPuterService };
|
||||
@@ -0,0 +1,7 @@
|
||||
# Kernel Dev Mod
|
||||
|
||||
This mod makes testing and debugging easier.
|
||||
|
||||
## Current Features:
|
||||
- A service-script adds `reqex` to the `window` object in the client,
|
||||
which contains a bunch of example requests to internal API endpoints.
|
||||
@@ -0,0 +1,233 @@
|
||||
// TODO: accessing these imports directly from a mod is not really
|
||||
// the way mods are intended to work; this is temporary until
|
||||
// we have these things registered in "useapi".
|
||||
const {
|
||||
get_user,
|
||||
generate_system_fsentries,
|
||||
invalidate_cached_user,
|
||||
deleteUser,
|
||||
} = require('../../../packages/backend/src/helpers');
|
||||
const { HLWrite } = require('../../../packages/backend/src/filesystem/hl_operations/hl_write');
|
||||
const { LLRead } = require('../../../packages/backend/src/filesystem/ll_operations/ll_read');
|
||||
const { Actor, UserActorType }
|
||||
= require('../../../packages/backend/src/services/auth/Actor');
|
||||
const { DB_WRITE } = require('../../../packages/backend/src/services/database/consts');
|
||||
const {
|
||||
RootNodeSelector,
|
||||
NodeChildSelector,
|
||||
NodePathSelector,
|
||||
} = require('../../../packages/backend/src/filesystem/node/selectors');
|
||||
const { Context } = require('../../../packages/backend/src/util/context');
|
||||
|
||||
|
||||
class ShareTestService extends use.Service {
|
||||
static MODULES = {
|
||||
uuidv4: require('uuid').v4,
|
||||
}
|
||||
|
||||
async _init () {
|
||||
const svc_commands = this.services.get('commands');
|
||||
this._register_commands(svc_commands);
|
||||
|
||||
this.scenarios = require('./data/sharetest_scenarios');
|
||||
|
||||
const svc_db = this.services.get('database');
|
||||
this.db = svc_db.get(svc_db.DB_WRITE, 'share-test');
|
||||
}
|
||||
|
||||
_register_commands (commands) {
|
||||
commands.registerCommands('share-test', [
|
||||
{
|
||||
id: 'start',
|
||||
description: '',
|
||||
handler: async (_, log) => {
|
||||
const results = await this.runit();
|
||||
|
||||
for ( const result of results ) {
|
||||
log.log(`=== ${result.title} ===`);
|
||||
if ( ! result.report ) {
|
||||
log.log(`\x1B[32;1mSUCCESS\x1B[0m`);
|
||||
continue;
|
||||
}
|
||||
log.log(
|
||||
`\x1B[31;1mSTOPPED\x1B[0m at ` +
|
||||
`${result.report.step}: ` +
|
||||
result.report.report.message,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
]);
|
||||
}
|
||||
|
||||
async runit () {
|
||||
await this.teardown_();
|
||||
await this.setup_();
|
||||
|
||||
const results = [];
|
||||
|
||||
for ( const scenario of this.scenarios ) {
|
||||
if ( ! scenario.title ) {
|
||||
scenario.title = scenario.sequence.map(
|
||||
step => step.title).join('; ')
|
||||
}
|
||||
results.push({
|
||||
title: scenario.title,
|
||||
report: await this.run_scenario_(scenario)
|
||||
});
|
||||
}
|
||||
|
||||
await this.teardown_();
|
||||
return results;
|
||||
}
|
||||
|
||||
async setup_ () {
|
||||
await this.create_test_user_('testuser_eric');
|
||||
await this.create_test_user_('testuser_stan');
|
||||
await this.create_test_user_('testuser_kyle');
|
||||
await this.create_test_user_('testuser_kenny');
|
||||
}
|
||||
async run_scenario_ (scenario) {
|
||||
let error;
|
||||
// Run sequence
|
||||
for ( const step of scenario.sequence ) {
|
||||
const method = this[`__scenario:${step.call}`];
|
||||
const user = await get_user({ username: step.as })
|
||||
const actor = await Actor.create(UserActorType, { user });
|
||||
const generated = { user, actor };
|
||||
const report = await Context.get().sub({ user, actor })
|
||||
.arun(async () => {
|
||||
return await method.call(this, generated, step.with);
|
||||
});
|
||||
if ( report ) {
|
||||
error = { step: step.title, report };
|
||||
break;
|
||||
}
|
||||
}
|
||||
return error;
|
||||
}
|
||||
async teardown_ () {
|
||||
await this.delete_test_user_('testuser_eric');
|
||||
await this.delete_test_user_('testuser_stan');
|
||||
await this.delete_test_user_('testuser_kyle');
|
||||
await this.delete_test_user_('testuser_kenny');
|
||||
}
|
||||
|
||||
async create_test_user_ (username) {
|
||||
await this.db.write(
|
||||
`
|
||||
INSERT INTO user (uuid, username, email, free_storage, password)
|
||||
VALUES (?, ?, ?, ?, ?)
|
||||
`,
|
||||
[
|
||||
this.modules.uuidv4(),
|
||||
username,
|
||||
username + '@example.com',
|
||||
1024 * 1024 * 500, // 500 MiB
|
||||
this.modules.uuidv4(),
|
||||
],
|
||||
);
|
||||
const user = await get_user({ username });
|
||||
await generate_system_fsentries(user);
|
||||
invalidate_cached_user(user);
|
||||
return user;
|
||||
}
|
||||
|
||||
async delete_test_user_ (username) {
|
||||
const user = await get_user({ username });
|
||||
if ( ! user ) return;
|
||||
await deleteUser(user.id);
|
||||
}
|
||||
|
||||
// API for scenarios
|
||||
async ['__scenario:create-example-file'] (
|
||||
{ actor, user },
|
||||
{ name, contents },
|
||||
) {
|
||||
const svc_fs = this.services.get('filesystem');
|
||||
const parent = await svc_fs.node(new NodePathSelector(
|
||||
`/${user.username}/Desktop`
|
||||
));
|
||||
console.log('test -> create-example-file',
|
||||
user, name, contents);
|
||||
const buffer = Buffer.from(contents);
|
||||
const file = {
|
||||
size: buffer.length,
|
||||
name: name,
|
||||
type: 'application/octet-stream',
|
||||
buffer,
|
||||
};
|
||||
const hl_write = new HLWrite();
|
||||
await hl_write.run({
|
||||
actor,
|
||||
user,
|
||||
destination_or_parent: parent,
|
||||
specified_name: name,
|
||||
file,
|
||||
});
|
||||
}
|
||||
async ['__scenario:assert-no-access'] (
|
||||
{ actor, user },
|
||||
{ path },
|
||||
) {
|
||||
const svc_fs = this.services.get('filesystem');
|
||||
const node = await svc_fs.node(new NodePathSelector(path));
|
||||
const ll_read = new LLRead();
|
||||
let expected_e; try {
|
||||
const stream = await ll_read.run({
|
||||
fsNode: node,
|
||||
actor,
|
||||
})
|
||||
} catch (e) {
|
||||
expected_e = e;
|
||||
}
|
||||
if ( ! expected_e ) {
|
||||
return { message: 'expected error, got none' };
|
||||
}
|
||||
}
|
||||
async ['__scenario:grant'] (
|
||||
{ actor, user },
|
||||
{ to, permission },
|
||||
) {
|
||||
const svc_permission = this.services.get('permission');
|
||||
await svc_permission.grant_user_user_permission(
|
||||
actor, to, permission, {}, {},
|
||||
);
|
||||
}
|
||||
async ['__scenario:assert-access'] (
|
||||
{ actor, user },
|
||||
{ path, level }
|
||||
) {
|
||||
const svc_fs = this.services.get('filesystem');
|
||||
const svc_acl = this.services.get('acl');
|
||||
const node = await svc_fs.node(new NodePathSelector(path));
|
||||
const has_read = await svc_acl.check(actor, node, 'read');
|
||||
const has_write = await svc_acl.check(actor, node, 'write');
|
||||
|
||||
if ( level !== 'write' && level !== 'read' ) {
|
||||
return {
|
||||
message: 'unexpected value for "level" parameter'
|
||||
};
|
||||
}
|
||||
|
||||
if ( level === 'read' && has_write ) {
|
||||
return {
|
||||
message: 'expected read-only but actor can write'
|
||||
};
|
||||
}
|
||||
if ( level === 'read' && !has_read ) {
|
||||
return {
|
||||
message: 'expected read access but no read access'
|
||||
};
|
||||
}
|
||||
if ( level === 'write' && (!has_write || !has_read) ) {
|
||||
return {
|
||||
message: 'expected write access but no write access'
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
ShareTestService,
|
||||
};
|
||||
@@ -0,0 +1,75 @@
|
||||
module.exports = [
|
||||
{
|
||||
sequence: [
|
||||
{
|
||||
title: 'Kyle creates a file',
|
||||
call: 'create-example-file',
|
||||
as: 'testuser_kyle',
|
||||
with: {
|
||||
name: 'example.txt',
|
||||
contents: 'secret file',
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Eric tries to access it',
|
||||
call: 'assert-no-access',
|
||||
as: 'testuser_eric',
|
||||
with: {
|
||||
path: '/testuser_kyle/Desktop/example.txt'
|
||||
}
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
sequence: [
|
||||
{
|
||||
title: 'Stan creates a file',
|
||||
call: 'create-example-file',
|
||||
as: 'testuser_stan',
|
||||
with: {
|
||||
name: 'example.txt',
|
||||
contents: 'secret file',
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Stan grants permission to Eric',
|
||||
call: 'grant',
|
||||
as: 'testuser_stan',
|
||||
with: {
|
||||
to: 'testuser_eric',
|
||||
permission: 'fs:/testuser_stan/Desktop/example.txt:read'
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Eric tries to access it',
|
||||
call: 'assert-access',
|
||||
as: 'testuser_eric',
|
||||
with: {
|
||||
path: '/testuser_stan/Desktop/example.txt',
|
||||
level: 'read'
|
||||
}
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
sequence: [
|
||||
{
|
||||
title: 'Stan grants Kyle\'s file to Eric',
|
||||
call: 'grant',
|
||||
as: 'testuser_stan',
|
||||
with: {
|
||||
to: 'testuser_eric',
|
||||
permission: 'fs:/testuser_kyle/Desktop/example.txt:read'
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Eric tries to access it',
|
||||
call: 'assert-no-access',
|
||||
as: 'testuser_eric',
|
||||
with: {
|
||||
path: '/testuser_kyle/Desktop/example.txt',
|
||||
}
|
||||
},
|
||||
]
|
||||
},
|
||||
];
|
||||
@@ -0,0 +1,107 @@
|
||||
const request_examples = [
|
||||
{
|
||||
name: 'entity storage app read',
|
||||
fetch: async (args) => {
|
||||
return await fetch(`${window.api_origin}/drivers/call`, {
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": `Bearer ${puter.authToken}`,
|
||||
},
|
||||
body: JSON.stringify({
|
||||
interface: 'puter-apps',
|
||||
method: 'read',
|
||||
args,
|
||||
}),
|
||||
method: "POST",
|
||||
});
|
||||
},
|
||||
out: async (resp) => {
|
||||
const data = await resp.json();
|
||||
if ( ! data.success ) return data;
|
||||
return data.result;
|
||||
},
|
||||
exec: async function exec (...a) {
|
||||
const resp = await this.fetch(...a);
|
||||
return await this.out(resp);
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'entity storage app select all',
|
||||
fetch: async () => {
|
||||
return await fetch(`${window.api_origin}/drivers/call`, {
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": `Bearer ${puter.authToken}`,
|
||||
},
|
||||
body: JSON.stringify({
|
||||
interface: 'puter-apps',
|
||||
method: 'select',
|
||||
args: { predicate: [] },
|
||||
}),
|
||||
method: "POST",
|
||||
});
|
||||
},
|
||||
out: async (resp) => {
|
||||
const data = await resp.json();
|
||||
if ( ! data.success ) return data;
|
||||
return data.result;
|
||||
},
|
||||
exec: async function exec (...a) {
|
||||
const resp = await this.fetch(...a);
|
||||
return await this.out(resp);
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'grant permission from a user to a user',
|
||||
fetch: async (user, perm) => {
|
||||
return await fetch(`${window.api_origin}/auth/grant-user-user`, {
|
||||
"headers": {
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": `Bearer ${puter.authToken}`,
|
||||
},
|
||||
"body": JSON.stringify({
|
||||
target_username: user,
|
||||
permission: perm,
|
||||
}),
|
||||
"method": "POST",
|
||||
});
|
||||
},
|
||||
out: async (resp) => {
|
||||
const data = await resp.json();
|
||||
return data;
|
||||
},
|
||||
exec: async function exec (...a) {
|
||||
const resp = await this.fetch(...a);
|
||||
return await this.out(resp);
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'write file',
|
||||
fetch: async (path, str) => {
|
||||
const endpoint = `${window.api_origin}/write`;
|
||||
const token = puter.authToken;
|
||||
|
||||
const blob = new Blob([str], { type: 'text/plain' });
|
||||
const formData = new FormData();
|
||||
formData.append('create_missing_ancestors', true);
|
||||
formData.append('path', path);
|
||||
formData.append('size', 8);
|
||||
formData.append('overwrite', true);
|
||||
formData.append('file', blob, 'something.txt');
|
||||
|
||||
const response = await fetch(endpoint, {
|
||||
method: 'POST',
|
||||
headers: { 'Authorization': `Bearer ${token}` },
|
||||
body: formData
|
||||
});
|
||||
return await response.json();
|
||||
},
|
||||
}
|
||||
];
|
||||
|
||||
globalThis.reqex = request_examples;
|
||||
|
||||
globalThis.service_script(api => {
|
||||
api.on_ready(() => {
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,11 @@
|
||||
module.exports = class BillingModule extends use.Module {
|
||||
install (context) {
|
||||
const services = context.get('services');
|
||||
|
||||
const { CustomPuterService } = require('./CustomPuterService.js');
|
||||
services.registerService('__custom-puter', CustomPuterService);
|
||||
|
||||
const { ShareTestService } = require('./ShareTestService.js');
|
||||
services.registerService('__share-test', ShareTestService);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"name": "custom-puter-mod",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "module.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC"
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
*
|
||||
!.gitignore
|
||||
Generated
+4470
-1485
File diff suppressed because it is too large.
Load diff
+8
-3
@@ -11,10 +11,13 @@
|
||||
"lib": "lib"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.1.1",
|
||||
"chalk": "^4.1.0",
|
||||
"clean-css": "^5.3.2",
|
||||
"dotenv": "^16.4.5",
|
||||
"eslint": "^9.1.1",
|
||||
"express": "^4.18.2",
|
||||
"globals": "^15.0.0",
|
||||
"html-entities": "^2.3.3",
|
||||
"nodemon": "^3.1.0",
|
||||
"uglify-js": "^3.17.4",
|
||||
@@ -22,14 +25,14 @@
|
||||
"webpack-cli": "^5.1.1"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"test": "mocha ./src/phoenix/test ./src/phoenix/packages/contextlink/test",
|
||||
"start=gui": "nodemon --exec \"node dev-server.js\" ",
|
||||
"start": "node run-selfhosted.js",
|
||||
"build": "node ./build.js",
|
||||
"build": "cd src/gui; node ./build.js",
|
||||
"check-translations": "node tools/check-translations.js"
|
||||
},
|
||||
"workspaces": [
|
||||
"packages/*"
|
||||
"src/*"
|
||||
],
|
||||
"nodemonConfig": {
|
||||
"ext": "js, json, mjs, jsx, svg, css",
|
||||
@@ -39,6 +42,8 @@
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"json-colorizer": "^3.0.1",
|
||||
"string-template": "^1.0.0",
|
||||
"uuid": "^9.0.1"
|
||||
}
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
class BasicBase {
|
||||
_get_inheritance_chain () {
|
||||
const chain = [];
|
||||
let cls = this.constructor;
|
||||
while ( cls && cls !== BasicBase ) {
|
||||
chain.push(cls);
|
||||
cls = cls.__proto__;
|
||||
}
|
||||
return chain.reverse();
|
||||
}
|
||||
|
||||
_get_merged_static_array (key) {
|
||||
const chain = this._get_inheritance_chain();
|
||||
const values = [];
|
||||
for ( const cls of chain ) {
|
||||
if ( cls[key] ) {
|
||||
values.push(...cls[key]);
|
||||
}
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
_get_merged_static_object (key) {
|
||||
const chain = this._get_inheritance_chain();
|
||||
const values = {};
|
||||
for ( const cls of chain ) {
|
||||
if ( cls[key] ) {
|
||||
Object.assign(values, cls[key]);
|
||||
}
|
||||
}
|
||||
return values;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
BasicBase,
|
||||
};
|
||||
@@ -1,59 +0,0 @@
|
||||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
/**
|
||||
* This trait allows dependency injection of node modules.
|
||||
* This is incredibly useful for passing mock implementations
|
||||
* of modules for unit testing.
|
||||
*
|
||||
* @example
|
||||
* class MyClass extends AdvancedBase {
|
||||
* static MODULES = {
|
||||
* axios,
|
||||
* };
|
||||
* }
|
||||
*
|
||||
* const my_class = new MyClass({
|
||||
* modules: {
|
||||
* axios: MY_AXIOS_MOCK,
|
||||
* }
|
||||
* });
|
||||
*/
|
||||
module.exports = {
|
||||
install_in_instance: (instance, { parameters }) => {
|
||||
const modules = instance._get_merged_static_object('MODULES');
|
||||
|
||||
if ( parameters.modules ) {
|
||||
for ( const k in parameters.modules ) {
|
||||
modules[k] = parameters.modules[k];
|
||||
}
|
||||
}
|
||||
|
||||
instance.modules = modules;
|
||||
|
||||
// This "require" function can shadow the real one so
|
||||
// that editor tools are aware of the modules that
|
||||
// are being used.
|
||||
instance.require = (name) => {
|
||||
if ( modules[name] ) {
|
||||
return modules[name];
|
||||
}
|
||||
return require(name);
|
||||
}
|
||||
},
|
||||
};
|
||||
@@ -1,72 +0,0 @@
|
||||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
const { expect } = require('chai');
|
||||
const { BasicBase } = require('../src/bases/BasicBase');
|
||||
const { AdvancedBase } = require('../src/AdvancedBase');
|
||||
|
||||
class ClassA extends BasicBase {
|
||||
static STATIC_OBJ = {
|
||||
a: 1,
|
||||
b: 2,
|
||||
};
|
||||
static STATIC_ARR = ['a', 'b'];
|
||||
}
|
||||
|
||||
class ClassB extends ClassA {
|
||||
static STATIC_OBJ = {
|
||||
c: 3,
|
||||
d: 4,
|
||||
};
|
||||
static STATIC_ARR = ['c', 'd'];
|
||||
}
|
||||
|
||||
describe('testing', () => {
|
||||
it('does a thing', () => {
|
||||
const b = new ClassB();
|
||||
|
||||
console.log(b._get_inheritance_chain());
|
||||
console.log([ClassA, ClassB]);
|
||||
expect(b._get_inheritance_chain()).deep.equal([ClassA, ClassB]);
|
||||
expect(b._get_merged_static_array('STATIC_ARR'))
|
||||
.deep.equal(['a', 'b', 'c', 'd']);
|
||||
expect(b._get_merged_static_object('STATIC_OBJ'))
|
||||
.deep.equal({ a: 1, b: 2, c: 3, d: 4 });
|
||||
});
|
||||
});
|
||||
|
||||
class ClassWithModule extends AdvancedBase {
|
||||
static MODULES = {
|
||||
axios: 'axios',
|
||||
};
|
||||
}
|
||||
|
||||
describe('AdvancedBase', () => {
|
||||
it('passes DI modules to instance', () => {
|
||||
const c1 = new ClassWithModule();
|
||||
expect(c1.modules.axios).to.equal('axios');
|
||||
|
||||
const c2 = new ClassWithModule({
|
||||
modules: {
|
||||
axios: 'my-axios',
|
||||
},
|
||||
});
|
||||
expect(c2.modules.axios).to.equal('my-axios');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
const { TeePromise } = require('../util/promise');
|
||||
|
||||
const es_import_promise = new TeePromise();
|
||||
let stringLength;
|
||||
(async () => {
|
||||
stringLength = (await import('string-length')).default;
|
||||
es_import_promise.resolve();
|
||||
// console.log('STRING LENGTH', stringLength);
|
||||
// process.exit(0);
|
||||
})();
|
||||
const surrounding_box = (col, lines, lengths) => {
|
||||
if ( ! lengths ) {
|
||||
lengths = lines.map(line => stringLength(line));
|
||||
}
|
||||
|
||||
const max_length = Math.max(...lengths);
|
||||
const c = str => `\x1b[${col}m${str}\x1b[0m`;
|
||||
const bar = c(Array(max_length + 4).fill('━').join(''));
|
||||
for ( let i = 0 ; i < lines.length ; i++ ) {
|
||||
while ( stringLength(lines[i]) < max_length ) {
|
||||
lines[i] += ' ';
|
||||
}
|
||||
lines[i] = `${c('┃ ')} ${lines[i]} ${c(' ┃')}`;
|
||||
}
|
||||
lines.unshift(`${c('┏')}${bar}${c('┓')}`);
|
||||
lines.push(`${c('┗')}${bar}${c('┛')}`);
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
surrounding_box,
|
||||
es_import_promise,
|
||||
};
|
||||
@@ -1,67 +0,0 @@
|
||||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
const eggspress = require("../../api/eggspress");
|
||||
const { get_app } = require("../../helpers");
|
||||
const { UserActorType } = require("../../services/auth/Actor");
|
||||
const { DB_READ } = require("../../services/database/consts");
|
||||
const { Context } = require("../../util/context");
|
||||
|
||||
module.exports = eggspress('/auth/list-permissions', {
|
||||
subdomain: 'api',
|
||||
auth2: true,
|
||||
allowedMethods: ['GET'],
|
||||
}, async (req, res, next) => {
|
||||
const x = Context.get();
|
||||
|
||||
const actor = x.get('actor');
|
||||
|
||||
// Apps cannot (currently) check permissions on behalf of users
|
||||
if ( ! ( actor.type instanceof UserActorType ) ) {
|
||||
throw APIError.create('forbidden');
|
||||
}
|
||||
|
||||
const db = x.get('services').get('database').get(DB_READ, 'permissions');
|
||||
|
||||
const permissions = [];
|
||||
|
||||
const rows = await db.read(
|
||||
'SELECT * FROM `user_to_app_permissions` WHERE user_id=?',
|
||||
[ actor.type.user.id ]
|
||||
);
|
||||
|
||||
for ( const row of rows ) {
|
||||
const app = await get_app({ id: row.app_id });
|
||||
|
||||
delete app.id;
|
||||
delete app.approved_for_listing;
|
||||
delete app.approved_for_opening_items;
|
||||
delete app.godmode;
|
||||
delete app.owner_user_id;
|
||||
|
||||
const permission = {
|
||||
app,
|
||||
permission: row.permission,
|
||||
extra: row.extra
|
||||
};
|
||||
|
||||
permissions.push(permission);
|
||||
}
|
||||
|
||||
res.json(permissions);
|
||||
});
|
||||
@@ -1,105 +0,0 @@
|
||||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
"use strict"
|
||||
const validator = require('validator');
|
||||
const crypto = require('crypto');
|
||||
const eggspress = require('../api/eggspress.js');
|
||||
const APIError = require('../api/APIError.js');
|
||||
const { DB_READ, DB_WRITE } = require('../services/database/consts.js');
|
||||
|
||||
const CHANGE_EMAIL_START = eggspress('/change_email/start', {
|
||||
subdomain: 'api',
|
||||
auth: true,
|
||||
verified: true,
|
||||
allowedMethods: ['POST'],
|
||||
}, async (req, res, next) => {
|
||||
const user = req.user;
|
||||
const new_email = req.body.new_email;
|
||||
|
||||
// TODO: DRY: signup.js
|
||||
// validation
|
||||
if( ! new_email ) {
|
||||
throw APIError.create('field_missing', null, { key: 'new_email' });
|
||||
}
|
||||
if ( typeof new_email !== 'string' ) {
|
||||
throw APIError.create('field_invalid', null, {
|
||||
key: 'new_email', expected: 'a valid email address' });
|
||||
}
|
||||
if ( ! validator.isEmail(new_email) ) {
|
||||
throw APIError.create('field_invalid', null, {
|
||||
key: 'new_email', expected: 'a valid email address' });
|
||||
}
|
||||
|
||||
// check if email is already in use
|
||||
const svc_mysql = req.services.get('mysql');
|
||||
const db = req.services.get('database').get(DB_WRITE, 'auth');
|
||||
const rows = await db.read(
|
||||
'SELECT COUNT(*) AS `count` FROM `user` WHERE `email` = ?',
|
||||
[new_email]
|
||||
);
|
||||
if ( rows[0].count > 0 ) {
|
||||
throw APIError.create('email_already_in_use', null, { email: new_email });
|
||||
}
|
||||
|
||||
// generate confirmation token
|
||||
const token = crypto.randomBytes(4).toString('hex');
|
||||
|
||||
// update user
|
||||
await db.write(
|
||||
'UPDATE `user` SET `unconfirmed_change_email` = ?, `change_email_confirm_token` = ? WHERE `id` = ?',
|
||||
[new_email, token, user.id]
|
||||
);
|
||||
});
|
||||
|
||||
const CHANGE_EMAIL_CONFIRM = eggspress('/change_email/confirm', {
|
||||
subdomain: 'api',
|
||||
auth: true,
|
||||
verified: true,
|
||||
allowedMethods: ['POST'],
|
||||
}, async (req, res, next) => {
|
||||
const user = req.user;
|
||||
const token = req.body.token;
|
||||
|
||||
if ( ! token ) {
|
||||
throw APIError.create('field_missing', null, { key: 'token' });
|
||||
}
|
||||
|
||||
const svc_mysql = req.services.get('mysql');
|
||||
const dbrr = svc_mysql.get(DB_MODE_READ, 'change-email-confirm');
|
||||
const [rows] = await dbrr.promise().query(
|
||||
'SELECT `unconfirmed_change_email` FROM `user` WHERE `id` = ? AND `change_email_confirm_token` = ?',
|
||||
[user.id, token]
|
||||
);
|
||||
if ( rows.length === 0 ) {
|
||||
throw APIError.create('token_invalid');
|
||||
}
|
||||
|
||||
const new_email = rows[0].unconfirmed_change_email;
|
||||
|
||||
const db = req.services.get('database').get(DB_WRITE, 'auth');
|
||||
await db.write(
|
||||
'UPDATE `user` SET `email` = ?, `unconfirmed_change_email` = NULL, `change_email_confirm_token` = NULL WHERE `id` = ?',
|
||||
[new_email, user.id]
|
||||
);
|
||||
});
|
||||
|
||||
module.exports = app => {
|
||||
app.use(CHANGE_EMAIL_START);
|
||||
app.use(CHANGE_EMAIL_CONFIRM);
|
||||
}
|
||||
@@ -1,121 +0,0 @@
|
||||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
"use strict"
|
||||
const express = require('express');
|
||||
const router = new express.Router();
|
||||
const { get_user, body_parser_error_handler } = require('../helpers');
|
||||
const config = require('../config');
|
||||
|
||||
// -----------------------------------------------------------------------//
|
||||
// POST /file
|
||||
// -----------------------------------------------------------------------//
|
||||
router.post('/login', express.json(), body_parser_error_handler, async (req, res, next)=>{
|
||||
// either api. subdomain or no subdomain
|
||||
if(require('../helpers').subdomain(req) !== 'api' && require('../helpers').subdomain(req) !== '')
|
||||
next();
|
||||
|
||||
// modules
|
||||
const bcrypt = require('bcrypt')
|
||||
const jwt = require('jsonwebtoken')
|
||||
const validator = require('validator')
|
||||
|
||||
// either username or email must be provided
|
||||
if(!req.body.username && !req.body.email)
|
||||
return res.status(400).send('Username or email is required.')
|
||||
// password is required
|
||||
else if(!req.body.password)
|
||||
return res.status(400).send('Password is required.')
|
||||
// password must be a string
|
||||
else if (typeof req.body.password !== 'string' && !(req.body.password instanceof String))
|
||||
return res.status(400).send('Password must be a string.')
|
||||
// if password is too short it's invalid, no need to do a db lookup
|
||||
else if(req.body.password.length < config.min_pass_length)
|
||||
return res.status(400).send('Invalid password.')
|
||||
// username, if present, must be a string
|
||||
else if (req.body.username && typeof req.body.username !== 'string' && !(req.body.username instanceof String))
|
||||
return res.status(400).send('username must be a string.')
|
||||
// if username doesn't pass regex test it's invalid anyway, no need to do DB lookup
|
||||
else if(req.body.username && !req.body.username.match(config.username_regex))
|
||||
return res.status(400).send('Invalid username.')
|
||||
// email, if present, must be a string
|
||||
else if (req.body.email && typeof req.body.email !== 'string' && !(req.body.email instanceof String))
|
||||
return res.status(400).send('email must be a string.')
|
||||
// if email is invalid, no need to do DB lookup anyway
|
||||
else if(req.body.email && !validator.isEmail(req.body.email))
|
||||
return res.status(400).send('Invalid email.')
|
||||
|
||||
// Increment & check rate limit
|
||||
if(kv.incr(`login|${req.ip}|${req.body.email ?? req.body.username}`) > 10)
|
||||
return res.status(429).send('Too many requests.');
|
||||
// Set expiry for rate limit
|
||||
kv.expire(`login|${req.ip}|${req.body.email ?? req.body.username}`, 60*10, 'NX')
|
||||
|
||||
try{
|
||||
let user;
|
||||
// log in using username
|
||||
if(req.body.username){
|
||||
user = await get_user({ username: req.body.username, cached: false });
|
||||
if(!user)
|
||||
return res.status(400).send('Username not found.')
|
||||
}
|
||||
// log in using email
|
||||
else if(validator.isEmail(req.body.email)){
|
||||
user = await get_user({ email: req.body.email, cached: false });
|
||||
if(!user)
|
||||
return res.status(400).send('Email not found.')
|
||||
}
|
||||
// is user suspended?
|
||||
if(user.suspended)
|
||||
return res.status(401).send('This account is suspended.')
|
||||
// pseudo user?
|
||||
// todo make this better, maybe ask them to create an account or send them an activation link
|
||||
if(user.password === null)
|
||||
return res.status(400).send('Incorrect password.')
|
||||
// check password
|
||||
if(await bcrypt.compare(req.body.password, user.password)){
|
||||
const token = await jwt.sign({uuid: user.uuid}, config.jwt_secret)
|
||||
//set cookie
|
||||
// res.cookie(config.cookie_name, token);
|
||||
res.cookie(config.cookie_name, token, {
|
||||
sameSite: 'none',
|
||||
secure: true,
|
||||
httpOnly: true,
|
||||
});
|
||||
|
||||
// send response
|
||||
return res.send({
|
||||
token: token,
|
||||
user:{
|
||||
username: user.username,
|
||||
uuid: user.uuid,
|
||||
email: user.email,
|
||||
email_confirmed: user.email_confirmed,
|
||||
is_temp: (user.password === null && user.email === null),
|
||||
}
|
||||
})
|
||||
}else{
|
||||
return res.status(400).send('Incorrect password.')
|
||||
}
|
||||
}catch(e){
|
||||
return res.status(400).send(e);
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
module.exports = router
|
||||
@@ -1,196 +0,0 @@
|
||||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
"use strict"
|
||||
const express = require('express');
|
||||
const router = new express.Router();
|
||||
const {get_taskbar_items, username_exists, send_email_verification_code, send_email_verification_token, invalidate_cached_user} = require('../helpers');
|
||||
const auth = require('../middleware/auth.js');
|
||||
const config = require('../config');
|
||||
const { Context } = require('../util/context');
|
||||
const { DB_WRITE } = require('../services/database/consts');
|
||||
|
||||
// -----------------------------------------------------------------------//
|
||||
// POST /save_account
|
||||
// -----------------------------------------------------------------------//
|
||||
router.post('/save_account', auth, express.json(), async (req, res, next)=>{
|
||||
// either api. subdomain or no subdomain
|
||||
if(require('../helpers').subdomain(req) !== 'api' && require('../helpers').subdomain(req) !== '')
|
||||
next();
|
||||
|
||||
// modules
|
||||
const db = req.services.get('database').get(DB_WRITE, 'auth');
|
||||
const validator = require('validator')
|
||||
const bcrypt = require('bcrypt')
|
||||
const jwt = require('jsonwebtoken')
|
||||
const { v4: uuidv4 } = require('uuid');
|
||||
|
||||
// validation
|
||||
if(req.user.password !== null)
|
||||
return res.status(400).send('User account already saved.');
|
||||
else if(!req.body.username)
|
||||
return res.status(400).send('Username is required');
|
||||
// username must be a string
|
||||
else if (typeof req.body.username !== 'string')
|
||||
return res.status(400).send('username must be a string.')
|
||||
else if(!req.body.username.match(config.username_regex))
|
||||
return res.status(400).send('Username can only contain letters, numbers and underscore (_).')
|
||||
else if(req.body.username.length > config.username_max_length)
|
||||
return res.status(400).send(`Username cannot have more than ${config.username_max_length} characters.`)
|
||||
// check if username matches any reserved words
|
||||
else if(config.reserved_words.includes(req.body.username))
|
||||
return res.status(400).send({message: 'This username is not available.'});
|
||||
else if(!req.body.email)
|
||||
return res.status(400).send('Email is required')
|
||||
// email must be a string
|
||||
else if (typeof req.body.email !== 'string')
|
||||
return res.status(400).send('email must be a string.')
|
||||
else if(!validator.isEmail(req.body.email))
|
||||
return res.status(400).send('Please enter a valid email address.')
|
||||
else if(!req.body.password)
|
||||
return res.status(400).send('Password is required')
|
||||
// password must be a string
|
||||
else if (typeof req.body.password !== 'string')
|
||||
return res.status(400).send('password must be a string.')
|
||||
else if(req.body.password.length < config.min_pass_length)
|
||||
return res.status(400).send(`Password must be at least ${config.min_pass_length} characters long.`)
|
||||
|
||||
// duplicate username check, do this only if user has supplied a new username
|
||||
if(req.body.username !== req.user.username && await username_exists(req.body.username))
|
||||
return res.status(400).send('This username already exists in our database. Please use another one.');
|
||||
// duplicate email check (pseudo-users don't count)
|
||||
let rows2 = await db.read(`SELECT EXISTS(SELECT 1 FROM user WHERE email=? AND password IS NOT NULL) AS email_exists`, [req.body.email]);
|
||||
if(rows2[0].email_exists)
|
||||
return res.status(400).send('This email already exists in our database. Please use another one.');
|
||||
// get pseudo user, if exists
|
||||
let pseudo_user = await db.read(`SELECT * FROM user WHERE email = ? AND password IS NULL`, [req.body.email]);
|
||||
pseudo_user = pseudo_user[0];
|
||||
// get uuid user, if exists
|
||||
if(req.body.uuid){
|
||||
uuid_user = await db.read(`SELECT * FROM user WHERE uuid = ? LIMIT 1`, [req.body.uuid]);
|
||||
uuid_user = uuid_user[0];
|
||||
}
|
||||
|
||||
// send_confirmation_code
|
||||
req.body.send_confirmation_code = req.body.send_confirmation_code ?? true;
|
||||
|
||||
// todo email confirmation is required by default unless:
|
||||
// Pseudo user converting and matching uuid is provided
|
||||
let email_confirmation_required = 0;
|
||||
|
||||
// -----------------------------------
|
||||
// Get referral user
|
||||
// -----------------------------------
|
||||
let referred_by_user = undefined;
|
||||
if ( req.body.referral_code ) {
|
||||
referred_by_user = await get_user({ referral_code: req.body.referral_code });
|
||||
if ( ! referred_by_user ) {
|
||||
return res.status(400).send('Referral code not found');
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------
|
||||
// New User
|
||||
// -----------------------------------
|
||||
const user_uuid = req.user.uuid;
|
||||
let email_confirm_code = Math.floor(100000 + Math.random() * 900000);
|
||||
const email_confirm_token = uuidv4();
|
||||
|
||||
if(pseudo_user === undefined){
|
||||
await db.write(
|
||||
`UPDATE user
|
||||
SET
|
||||
username = ?, email = ?, password = ?, email_confirm_code = ?, email_confirm_token = ?${
|
||||
referred_by_user ? ', referred_by = ?' : '' }
|
||||
WHERE
|
||||
id = ?`,
|
||||
[
|
||||
// username
|
||||
req.body.username,
|
||||
// email
|
||||
req.body.email,
|
||||
// password
|
||||
await bcrypt.hash(req.body.password, 8),
|
||||
// email_confirm_code
|
||||
email_confirm_code,
|
||||
//email_confirm_token
|
||||
email_confirm_token,
|
||||
// referred_by
|
||||
...(referred_by_user ? [referred_by_user.id] : []),
|
||||
// id
|
||||
req.user.id
|
||||
]
|
||||
);
|
||||
invalidate_cached_user(req.user);
|
||||
|
||||
// Update root directory name
|
||||
await db.write(
|
||||
`UPDATE fsentries SET name = ? WHERE user_id = ? and parent_uid IS NULL`,
|
||||
[
|
||||
// name
|
||||
req.body.username,
|
||||
// id
|
||||
req.user.id,
|
||||
]
|
||||
);
|
||||
const filesystem = req.services.get('filesystem');
|
||||
await filesystem.update_child_paths(`/${req.user.username}`, `/${req.body.username}`, req.user.id);
|
||||
|
||||
if(req.body.send_confirmation_code)
|
||||
send_email_verification_code(email_confirm_code, req.body.email);
|
||||
else
|
||||
send_email_verification_token(email_confirm_token, req.body.email, user_uuid);
|
||||
}
|
||||
|
||||
// create token for login
|
||||
const token = await jwt.sign({uuid: user_uuid}, config.jwt_secret);
|
||||
|
||||
// user id
|
||||
// todo if pseudo user, assign directly no need to do another DB lookup
|
||||
const user_id = req.user.id;
|
||||
const user_res = await db.read('SELECT * FROM `user` WHERE `id` = ? LIMIT 1', [user_id]);
|
||||
const user = user_res[0];
|
||||
|
||||
// todo send LINK-based verification email
|
||||
|
||||
//set cookie
|
||||
res.cookie(config.cookie_name, token);
|
||||
|
||||
{
|
||||
const svc_event = req.services.get('event');
|
||||
svc_event.emit('user.save_account', { user });
|
||||
}
|
||||
|
||||
// return results
|
||||
return res.send({
|
||||
token: token,
|
||||
user:{
|
||||
username: user.username,
|
||||
uuid: user.uuid,
|
||||
email: user.email,
|
||||
is_temp: false,
|
||||
requires_email_confirmation: user.requires_email_confirmation,
|
||||
email_confirmed: user.email_confirmed,
|
||||
email_confirmation_required: email_confirmation_required,
|
||||
taskbar_items: await get_taskbar_items(user),
|
||||
referral_code: user.referral_code,
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
module.exports = router
|
||||
@@ -1,100 +0,0 @@
|
||||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
const { AdvancedBase } = require("puter-js-common");
|
||||
|
||||
class Emailservice extends AdvancedBase {
|
||||
static MODULES = {
|
||||
nodemailer: require('nodemailer'),
|
||||
handlebars: require('handlebars'),
|
||||
};
|
||||
|
||||
constructor ({ services, config }) {
|
||||
super();
|
||||
this.config = config;
|
||||
|
||||
this.templates = {
|
||||
'new-referral': {
|
||||
subject: `You've made a referral!`,
|
||||
html: `<p>Hi there,</p>
|
||||
<p>A new user has used your referral code. Enjoy an extra {{storage_increase}} of storage, on the house!</p>
|
||||
<p>Sincerely,</p>
|
||||
<p>Puter</p>
|
||||
`,
|
||||
},
|
||||
'approved-for-listing': {
|
||||
subject: '\u{1f389} Your app has been approved for listing!',
|
||||
html: `
|
||||
<p>Hi there,</p>
|
||||
<p>
|
||||
Exciting news! <a href="https://puter.com/app/{{app_name}}">{{app_title}}</a> is now approved and live on <a href="https://puter.com/app/app-center" target="_blank">Puter App Center</a>. It's now ready for users worldwide to discover and enjoy.
|
||||
</p>
|
||||
<p>
|
||||
<strong>Next Step</strong>: As your app begins to gain traction with more users, we will conduct periodic reviews to assess its performance and user engagement. Once your app meets our criteria, we'll invite you to our Incentive Program. This exclusive program will allow you to earn revenue each time users open your app. So, keep an eye out for updates and stay tuned for this exciting opportunity! Make sure to share your app with your fans, friends and family to help it gain traction: <a href="https://puter.com/app/{{app_name}}">https://puter.com/app/{{app_name}}</a>
|
||||
</p>
|
||||
|
||||
<p>Best,<br />
|
||||
The Puter Team
|
||||
</p>
|
||||
`,
|
||||
},
|
||||
};
|
||||
|
||||
this.template_fns = {};
|
||||
for ( const k in this.templates ) {
|
||||
const template = this.templates[k];
|
||||
this.template_fns[k] = values => {
|
||||
const html = this.modules.handlebars.compile(template.html);
|
||||
return {
|
||||
...template,
|
||||
html: html(values),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async send_email (user, template, values) {
|
||||
const config = this.config;
|
||||
const nodemailer = this.modules.nodemailer;
|
||||
|
||||
let transporter = nodemailer.createTransport({
|
||||
host: config.smtp_server,
|
||||
port: config.smpt_port,
|
||||
secure: true, // STARTTLS
|
||||
auth: {
|
||||
user: config.smtp_username,
|
||||
pass: config.smtp_password,
|
||||
},
|
||||
});
|
||||
|
||||
const email = user.email;
|
||||
|
||||
const template_fn = this.template_fns[template];
|
||||
const { subject, html } = template_fn(values);
|
||||
|
||||
transporter.sendMail({
|
||||
from: '"Puter" [email protected]', // sender address
|
||||
to: email, // list of receivers
|
||||
subject, html,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
Emailservice
|
||||
};
|
||||
@@ -1,47 +0,0 @@
|
||||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
const { Context } = require("../util/context");
|
||||
const BaseService = require("./BaseService");
|
||||
const { DB_WRITE } = require("./database/consts");
|
||||
|
||||
class PuterSiteService extends BaseService {
|
||||
async _init () {
|
||||
const services = this.services;
|
||||
this.db = services.get('database').get(DB_WRITE, 'sites');
|
||||
}
|
||||
|
||||
async get_subdomain (subdomain) {
|
||||
if ( subdomain === 'devtest' && this.global_config.env === 'dev' ) {
|
||||
return {
|
||||
user_id: null,
|
||||
root_dir_id: this.config.devtest_directory,
|
||||
};
|
||||
}
|
||||
const rows = await this.read(
|
||||
`SELECT * FROM subdomains WHERE subdomain = ? LIMIT 1`,
|
||||
[subdomain]
|
||||
);
|
||||
if ( rows.length === 0 ) return null;
|
||||
return rows[0];
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
PuterSiteService,
|
||||
};
|
||||
@@ -1,93 +0,0 @@
|
||||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
const { AdvancedBase } = require("puter-js-common");
|
||||
const { NodeUIDSelector } = require("../filesystem/node/selectors");
|
||||
const { get_user } = require("../helpers");
|
||||
const { TeePromise } = require("../util/promise");
|
||||
const { StreamBuffer } = require("../util/streamutil");
|
||||
|
||||
class PuterVersionService extends AdvancedBase {
|
||||
static MODULES = {
|
||||
_path: require('path'),
|
||||
fs: require('fs'),
|
||||
_exec: require('child_process').execSync,
|
||||
axios: require('axios'),
|
||||
}
|
||||
|
||||
constructor ({ services, config }) {
|
||||
super();
|
||||
this.fs = services.get('filesystem');
|
||||
this.config = config;
|
||||
|
||||
this._init({ config });
|
||||
this.ready_ = new TeePromise();
|
||||
}
|
||||
|
||||
async _init ({ config }) {
|
||||
// this.node = await this.fs.node(new NodeUIDSelector(config.puter_hosted_data.puter_versions));
|
||||
// this.user = await get_user({ username: 'puter' });
|
||||
|
||||
// await this._poll_versions({ config });
|
||||
|
||||
// setInterval(async () => {
|
||||
// await this._poll_versions({ config });
|
||||
// }, 60 * 1000);
|
||||
}
|
||||
|
||||
// not used anymore - this was for getting version numbers from a file hosted on puter
|
||||
async _poll_versions ({ config }) {
|
||||
const resp = await this.modules.axios.get(
|
||||
config.puter_hosted_data.puter_versions
|
||||
);
|
||||
this.versions_ = resp.data.versions;
|
||||
this.ready_.resolve();
|
||||
}
|
||||
|
||||
get_version () {
|
||||
let git_version;
|
||||
let deploy_timestamp;
|
||||
if ( this.config.env === 'dev' ) {
|
||||
// get commit hash from git
|
||||
git_version = this.modules._exec('git describe --tags', {
|
||||
cwd: this.modules._path.join(__dirname, '../../'),
|
||||
encoding: 'utf8',
|
||||
}).trim();
|
||||
deploy_timestamp = Date.now();
|
||||
} else {
|
||||
// get git version from file
|
||||
const path = this.modules._path.join(__dirname, '../../git_version');
|
||||
|
||||
git_version = this.modules.fs.readFileSync(path, 'utf8').trim();
|
||||
deploy_timestamp = Number.parseInt((this.modules.fs.readFileSync(
|
||||
this.modules._path.join(__dirname, '../../deploy_timestamp'),
|
||||
'utf8'
|
||||
)).trim());
|
||||
}
|
||||
return {
|
||||
version: git_version,
|
||||
environment: this.config.env,
|
||||
location: this.config.server_id,
|
||||
deploy_timestamp,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
PuterVersionService,
|
||||
};
|
||||
@@ -1,430 +0,0 @@
|
||||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
const { get_user, get_app } = require("../../helpers");
|
||||
const BaseService = require("../BaseService");
|
||||
const { DB_WRITE } = require("../database/consts");
|
||||
const { UserActorType, Actor, AppUnderUserActorType, AccessTokenActorType } = require("./Actor");
|
||||
|
||||
const default_implicit_user_app_permissions = {
|
||||
'driver:helloworld:greet': {},
|
||||
'driver:puter-kvstore': {},
|
||||
'driver:puter-ocr:recognize': {},
|
||||
'driver:puter-chat-completion': {},
|
||||
'driver:puter-image-generation': {},
|
||||
'driver:puter-tts': {},
|
||||
'driver:puter-apps': {},
|
||||
'driver:puter-subdomains': {},
|
||||
};
|
||||
|
||||
const implicit_user_app_permissions = [
|
||||
{
|
||||
id: 'builtin-apps',
|
||||
apps: [
|
||||
'app-0bef044f-918f-4cbf-a0c0-b4a17ee81085', // about
|
||||
'app-838dfbc4-bf8b-48c2-b47b-c4adc77fab58', // editor
|
||||
'app-58282b08-990a-4906-95f7-fa37ff92452b', // draw
|
||||
'app-0087b701-da09-4f49-a37d-2d6bcabc81ee', // minipaint
|
||||
'app-3fea7529-266e-47d9-8776-31649cd06557', // terminal
|
||||
'app-5584fbf7-ed69-41fc-99cd-85da21b1ef51', // camera
|
||||
'app-7bdca1a4-6373-4c98-ad97-03ff2d608ca1', // recorder
|
||||
'app-240a43f4-43b1-49bc-b9fc-c8ae719dab77', // dev-center
|
||||
'app-a2ae72a4-1ba3-4a29-b5c0-6de1be5cf178', // app-center
|
||||
'app-74378e84-b9cd-5910-bcb1-3c50fa96d6e7', // https://nj.puter.site
|
||||
'app-13a38aeb-f9f6-54f0-9bd3-9d4dd655ccfe', // https://cdpn.io
|
||||
'app-dce8f797-82b0-5d95-a2f8-ebe4d71b9c54', // https://null.jsbin.com
|
||||
'app-93005ce0-80d1-50d9-9b1e-9c453c375d56', // https://markus.puter.com
|
||||
],
|
||||
permissions: {
|
||||
'driver:helloworld:greet': {},
|
||||
'driver:puter-ocr:recognize': {},
|
||||
'driver:puter-kvstore:get': {},
|
||||
'driver:puter-kvstore:set': {},
|
||||
'driver:puter-kvstore:del': {},
|
||||
'driver:puter-kvstore:list': {},
|
||||
'driver:puter-kvstore:flush': {},
|
||||
'driver:puter-chat-completion:complete': {},
|
||||
'driver:puter-image-generation:generate': {},
|
||||
'driver:puter-analytics:create_trace': {},
|
||||
'driver:puter-analytics:record': {},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'local-testing',
|
||||
apps: [
|
||||
'app-a392f3e5-35ca-5dac-ae10-785696cc7dec', // https://localhost
|
||||
'app-a6263561-6a84-5d52-9891-02956f9fac65', // https://127.0.0.1
|
||||
'app-26149f0b-8304-5228-b995-772dadcf410e', // http://localhost
|
||||
'app-c2e27728-66d9-54dd-87cd-6f4e9b92e3e3', // http://127.0.0.1
|
||||
],
|
||||
permissions: {
|
||||
'driver:helloworld:greet': {},
|
||||
'driver:puter-ocr:recognize': {},
|
||||
'driver:puter-kvstore:get': {},
|
||||
'driver:puter-kvstore:set': {},
|
||||
'driver:puter-kvstore:del': {},
|
||||
'driver:puter-kvstore:list': {},
|
||||
'driver:puter-kvstore:flush': {},
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
class PermissionRewriter {
|
||||
static create ({ id, matcher, rewriter }) {
|
||||
return new PermissionRewriter({ id, matcher, rewriter });
|
||||
}
|
||||
|
||||
constructor ({ id, matcher, rewriter }) {
|
||||
this.id = id;
|
||||
this.matcher = matcher;
|
||||
this.rewriter = rewriter;
|
||||
}
|
||||
|
||||
matches (permission) {
|
||||
return this.matcher(permission);
|
||||
}
|
||||
|
||||
async rewrite (permission) {
|
||||
return await this.rewriter(permission);
|
||||
}
|
||||
}
|
||||
|
||||
class PermissionUtil {
|
||||
static unescape_permission_component (component) {
|
||||
let unescaped_str = '';
|
||||
const STATE_NORMAL = {};
|
||||
const STATE_ESCAPE = {};
|
||||
let state = STATE_NORMAL;
|
||||
const const_escapes = { C: ':' };
|
||||
for ( let i = 0 ; i < component.length ; i++ ) {
|
||||
const c = component[i];
|
||||
if ( state === STATE_NORMAL ) {
|
||||
if ( c === '\\' ) {
|
||||
state = STATE_ESCAPE;
|
||||
} else {
|
||||
unescaped_str += c;
|
||||
}
|
||||
} else if ( state === STATE_ESCAPE ) {
|
||||
unescaped_str += const_escapes.hasOwnProperty(c)
|
||||
? const_escapes[c] : c;
|
||||
state = STATE_NORMAL;
|
||||
}
|
||||
}
|
||||
return unescaped_str;
|
||||
}
|
||||
|
||||
static split (permission) {
|
||||
return permission
|
||||
.split(':')
|
||||
.map(PermissionUtil.unescape_permission_component)
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
class PermissionService extends BaseService {
|
||||
async _init () {
|
||||
this.db = this.services.get('database').get(DB_WRITE, 'permissions');
|
||||
this._register_commands(this.services.get('commands'));
|
||||
|
||||
this._permission_rewriters = [];
|
||||
}
|
||||
|
||||
async _rewrite_permission (permission) {
|
||||
for ( const rewriter of this._permission_rewriters ) {
|
||||
if ( ! rewriter.matches(permission) ) continue;
|
||||
permission = await rewriter.rewrite(permission);
|
||||
}
|
||||
return permission;
|
||||
}
|
||||
|
||||
|
||||
async check (actor, permission) {
|
||||
permission = await this._rewrite_permission(permission);
|
||||
|
||||
this.log.info(`checking permission ${permission} for actor ${actor.uid}`, {
|
||||
actor: actor.uid,
|
||||
permission,
|
||||
});
|
||||
// For now we're only checking driver permissions, and users have all of them
|
||||
if ( actor.type instanceof UserActorType ) {
|
||||
return {};
|
||||
}
|
||||
|
||||
if ( actor.type instanceof AccessTokenActorType ) {
|
||||
return await this.check_access_token_permission(
|
||||
actor.type.authorizer, actor.type.token, permission
|
||||
);
|
||||
}
|
||||
|
||||
// Prevent undefined behaviour
|
||||
if ( ! (actor.type instanceof AppUnderUserActorType) ) {
|
||||
throw new Error('actor must be an app under a user');
|
||||
}
|
||||
|
||||
// Now it's an app under a user
|
||||
const app_uid = actor.type.app.uid;
|
||||
return await this.check_user_app_permission(actor, app_uid, permission);
|
||||
}
|
||||
|
||||
async check_access_token_permission (authorizer, token, permission) {
|
||||
// Authorizer must have permission
|
||||
const authorizer_permission = await this.check(authorizer, permission);
|
||||
if ( ! authorizer_permission ) return false;
|
||||
|
||||
const rows = await this.db.read(
|
||||
'SELECT * FROM `access_token_permissions` ' +
|
||||
'WHERE `token_uid` = ? AND `permission` = ?',
|
||||
[
|
||||
token,
|
||||
permission,
|
||||
]
|
||||
);
|
||||
|
||||
// Token must have permission
|
||||
if ( ! rows[0] ) return undefined;
|
||||
|
||||
return rows[0].extra;
|
||||
}
|
||||
|
||||
async check_user_app_permission (actor, app_uid, permission) {
|
||||
permission = await this._rewrite_permission(permission);
|
||||
|
||||
let app = await get_app({ uid: app_uid });
|
||||
if ( ! app ) app = await get_app({ name: app_uid });
|
||||
const app_id = app.id;
|
||||
|
||||
const parent_perms = [];
|
||||
{
|
||||
// We don't use PermissionUtil.split here because it unescapes
|
||||
// components; we want to keep the components escaped for matching.
|
||||
const parts = permission.split(':');
|
||||
|
||||
// Add sub-permissions
|
||||
for ( let i = 1 ; i < parts.length ; i++ ) {
|
||||
parent_perms.push(parts.slice(0, i + 1).join(':'));
|
||||
}
|
||||
}
|
||||
parent_perms.reverse();
|
||||
|
||||
for ( const permission of parent_perms ) {
|
||||
// Check hardcoded permissions
|
||||
if ( default_implicit_user_app_permissions[permission] ) {
|
||||
return default_implicit_user_app_permissions[permission];
|
||||
}
|
||||
|
||||
// Check implicit permissions
|
||||
const implicit_permissions = {};
|
||||
for ( const implicit_permission of implicit_user_app_permissions ) {
|
||||
if ( implicit_permission.apps.includes(app_uid) ) {
|
||||
implicit_permissions[permission] = implicit_permission.permissions[permission];
|
||||
}
|
||||
}
|
||||
if ( implicit_permissions[permission] ) {
|
||||
return implicit_permissions[permission];
|
||||
}
|
||||
}
|
||||
|
||||
// My biggest gripe with SQL is doing string manipulation for queries.
|
||||
// If the grammar for SQL was simpler we could model it, write this as
|
||||
// data, and even implement macros for common patterns.
|
||||
let sql_perm = parent_perms.map((perm) =>
|
||||
`\`permission\` = ?`).join(' OR ');
|
||||
if ( parent_perms.length > 1 ) sql_perm = '(' + sql_perm + ')';
|
||||
|
||||
// SELECT permission
|
||||
const rows = await this.db.read(
|
||||
'SELECT * FROM `user_to_app_permissions` ' +
|
||||
'WHERE `user_id` = ? AND `app_id` = ? AND ' +
|
||||
sql_perm,
|
||||
[
|
||||
actor.type.user.id,
|
||||
app_id,
|
||||
...parent_perms,
|
||||
]
|
||||
);
|
||||
|
||||
if ( ! rows[0] ) return undefined;
|
||||
|
||||
return rows[0].extra;
|
||||
}
|
||||
|
||||
async grant_user_app_permission (actor, app_uid, permission, extra = {}, meta) {
|
||||
permission = await this._rewrite_permission(permission);
|
||||
|
||||
let app = await get_app({ uid: app_uid });
|
||||
if ( ! app ) app = await get_app({ name: app_uid });
|
||||
|
||||
const app_id = app.id;
|
||||
|
||||
// UPSERT permission
|
||||
await this.db.write(
|
||||
'INSERT INTO `user_to_app_permissions` (`user_id`, `app_id`, `permission`, `extra`) ' +
|
||||
'VALUES (?, ?, ?, ?) ' +
|
||||
this.db.case({
|
||||
mysql: 'ON DUPLICATE KEY UPDATE `extra` = ?',
|
||||
otherwise: 'ON CONFLICT(`user_id`, `app_id`, `permission`) DO UPDATE SET `extra` = ?',
|
||||
}),
|
||||
[
|
||||
actor.type.user.id,
|
||||
app_id,
|
||||
permission,
|
||||
JSON.stringify(extra),
|
||||
JSON.stringify(extra),
|
||||
]
|
||||
);
|
||||
|
||||
// INSERT audit table
|
||||
const audit_values = {
|
||||
user_id: actor.type.user.id,
|
||||
user_id_keep: actor.type.user.id,
|
||||
app_id: app_id,
|
||||
app_id_keep: app_id,
|
||||
permission,
|
||||
action: 'grant',
|
||||
reason: meta?.reason || 'granted via PermissionService',
|
||||
};
|
||||
|
||||
const sql_cols = Object.keys(audit_values).map((key) => `\`${key}\``).join(', ');
|
||||
const sql_vals = Object.keys(audit_values).map((key) => `?`).join(', ');
|
||||
|
||||
await this.db.write(
|
||||
'INSERT INTO `audit_user_to_app_permissions` (' + sql_cols + ') ' +
|
||||
'VALUES (' + sql_vals + ')',
|
||||
Object.values(audit_values)
|
||||
);
|
||||
}
|
||||
|
||||
async revoke_user_app_permission (actor, app_uid, permission, meta) {
|
||||
permission = await this._rewrite_permission(permission);
|
||||
|
||||
// For now, actor MUST be a user
|
||||
if ( ! (actor.type instanceof UserActorType) ) {
|
||||
throw new Error('actor must be a user');
|
||||
}
|
||||
|
||||
let app = await get_app({ uid: app_uid });
|
||||
if ( ! app ) app = await get_app({ name: app_uid });
|
||||
const app_id = app.id;
|
||||
|
||||
// DELETE permission
|
||||
await this.db.write(
|
||||
'DELETE FROM `user_to_app_permissions` ' +
|
||||
'WHERE `user_id` = ? AND `app_id` = ? AND `permission` = ?',
|
||||
[
|
||||
actor.type.user.id,
|
||||
app_id,
|
||||
permission,
|
||||
]
|
||||
);
|
||||
|
||||
// INSERT audit table
|
||||
const audit_values = {
|
||||
user_id: actor.type.user.id,
|
||||
user_id_keep: actor.type.user.id,
|
||||
app_id: app_id,
|
||||
app_id_keep: app_id,
|
||||
permission,
|
||||
action: 'revoke',
|
||||
reason: meta?.reason || 'revoked via PermissionService',
|
||||
};
|
||||
|
||||
const sql_cols = Object.keys(audit_values).map((key) => `\`${key}\``).join(', ');
|
||||
const sql_vals = Object.keys(audit_values).map((key) => `?`).join(', ');
|
||||
|
||||
await this.db.write(
|
||||
'INSERT INTO `audit_user_to_app_permissions` (' + sql_cols + ') ' +
|
||||
'VALUES (' + sql_vals + ')',
|
||||
Object.values(audit_values)
|
||||
);
|
||||
}
|
||||
|
||||
async revoke_user_app_all (actor, app_uid, meta) {
|
||||
// For now, actor MUST be a user
|
||||
if ( ! (actor.type instanceof UserActorType) ) {
|
||||
throw new Error('actor must be a user');
|
||||
}
|
||||
|
||||
let app = await get_app({ uid: app_uid });
|
||||
if ( ! app ) app = await get_app({ name: app_uid });
|
||||
const app_id = app.id;
|
||||
|
||||
// DELETE permissions
|
||||
await this.db.write(
|
||||
'DELETE FROM `user_to_app_permissions` ' +
|
||||
'WHERE `user_id` = ? AND `app_id` = ?',
|
||||
[
|
||||
actor.type.user.id,
|
||||
app_id,
|
||||
]
|
||||
);
|
||||
|
||||
// INSERT audit table
|
||||
const audit_values = {
|
||||
user_id: actor.type.user.id,
|
||||
user_id_keep: actor.type.user.id,
|
||||
app_id: app_id,
|
||||
app_id_keep: app_id,
|
||||
permission: '*',
|
||||
action: 'revoke',
|
||||
reason: meta?.reason || 'revoked all via PermissionService',
|
||||
};
|
||||
|
||||
const sql_cols = Object.keys(audit_values).map((key) => `\`${key}\``).join(', ');
|
||||
const sql_vals = Object.keys(audit_values).map((key) => `?`).join(', ');
|
||||
|
||||
await this.db.write(
|
||||
'INSERT INTO `audit_user_to_app_permissions` (' + sql_cols + ') ' +
|
||||
'VALUES (' + sql_vals + ')',
|
||||
Object.values(audit_values)
|
||||
);
|
||||
}
|
||||
|
||||
register_rewriter (translator) {
|
||||
if ( ! (translator instanceof PermissionRewriter) ) {
|
||||
throw new Error('translator must be a PermissionRewriter');
|
||||
}
|
||||
|
||||
this._permission_rewriters.push(translator);
|
||||
}
|
||||
|
||||
_register_commands (commands) {
|
||||
commands.registerCommands('perms', [
|
||||
{
|
||||
id: 'grant-user-app',
|
||||
handler: async (args, log) => {
|
||||
const [ username, app_uid, permission, extra ] = args;
|
||||
|
||||
// actor from username
|
||||
const actor = new Actor({
|
||||
type: new UserActorType({
|
||||
user: await get_user({ username }),
|
||||
}),
|
||||
})
|
||||
|
||||
await this.grant_user_app_permission(actor, app_uid, permission, extra);
|
||||
}
|
||||
}
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
PermissionRewriter,
|
||||
PermissionUtil,
|
||||
PermissionService,
|
||||
};
|
||||
@@ -1,157 +0,0 @@
|
||||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
const { BaseDatabaseAccessService } = require("./BaseDatabaseAccessService");
|
||||
|
||||
class SqliteDatabaseAccessService extends BaseDatabaseAccessService {
|
||||
static ENGINE_NAME = 'sqlite';
|
||||
|
||||
static MODULES = {
|
||||
// Documentation calls it 'Database'; it's new-able so
|
||||
// I'll stick with their convention over ours.
|
||||
Database: require('better-sqlite3'),
|
||||
};
|
||||
|
||||
async _init () {
|
||||
const require = this.require;
|
||||
const Database = require('better-sqlite3');
|
||||
|
||||
this._register_commands(this.services.get('commands'));
|
||||
|
||||
const fs = require('fs');
|
||||
const path_ = require('path');
|
||||
const do_setup = ! fs.existsSync(this.config.path);
|
||||
|
||||
this.db = new Database(this.config.path);
|
||||
|
||||
if ( do_setup ) {
|
||||
const sql_files = [
|
||||
'0001_create-tables.sql',
|
||||
'0002_add-default-apps.sql',
|
||||
].map(p => path_.join(__dirname, 'sqlite_setup', p));
|
||||
const fs = require('fs');
|
||||
for ( const filename of sql_files ) {
|
||||
const contents = fs.readFileSync(filename, 'utf8');
|
||||
this.db.exec(contents);
|
||||
}
|
||||
}
|
||||
|
||||
// Create the tables if they don't exist.
|
||||
const check =
|
||||
`SELECT name FROM sqlite_master WHERE type='table' AND name='fsentries'`;
|
||||
const rows = await this.db.prepare(check).all();
|
||||
if ( rows.length === 0 ) {
|
||||
throw new Error('it works');
|
||||
}
|
||||
}
|
||||
|
||||
async _read (query, params = []) {
|
||||
query = this.sqlite_transform_query_(query);
|
||||
params = this.sqlite_transform_params_(params);
|
||||
return this.db.prepare(query).all(...params);
|
||||
}
|
||||
|
||||
async _requireRead (query, params) {
|
||||
return this._read(query, params);
|
||||
}
|
||||
|
||||
async _write (query, params) {
|
||||
query = this.sqlite_transform_query_(query);
|
||||
params = this.sqlite_transform_params_(params);
|
||||
|
||||
try {
|
||||
const stmt = this.db.prepare(query);
|
||||
const info = stmt.run(...params);
|
||||
|
||||
return {
|
||||
insertId: info.lastInsertRowid,
|
||||
anyRowsAffected: info.changes > 0,
|
||||
};
|
||||
} catch ( e ) {
|
||||
console.error(e);
|
||||
console.log('everything', {
|
||||
query, params,
|
||||
})
|
||||
console.log(params.map(p => typeof p));
|
||||
// throw e;
|
||||
}
|
||||
}
|
||||
|
||||
async _batch_write (entries) {
|
||||
this.db.transaction(() => {
|
||||
for ( let { statement, values } of entries ) {
|
||||
statement = this.sqlite_transform_query_(statement);
|
||||
values = this.sqlite_transform_params_(values);
|
||||
this.db.prepare(statement).run(values);
|
||||
}
|
||||
})();
|
||||
}
|
||||
|
||||
|
||||
sqlite_transform_query_ (query) {
|
||||
// replace `now()` with `datetime('now')`
|
||||
query = query.replace(/now\(\)/g, 'datetime(\'now\')');
|
||||
|
||||
return query;
|
||||
}
|
||||
|
||||
sqlite_transform_params_ (params) {
|
||||
return params.map(p => {
|
||||
if ( typeof p === 'boolean' ) {
|
||||
return p ? 1 : 0;
|
||||
}
|
||||
return p;
|
||||
});
|
||||
}
|
||||
|
||||
_register_commands (commands) {
|
||||
commands.registerCommands('sqlite', [
|
||||
{
|
||||
id: 'execfile',
|
||||
description: 'execute a file',
|
||||
handler: async (args, log) => {
|
||||
try {
|
||||
const [filename] = args;
|
||||
const fs = require('fs');
|
||||
const contents = fs.readFileSync(filename, 'utf8');
|
||||
this.db.exec(contents);
|
||||
} catch (err) {
|
||||
log.error(err.message);
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 'read',
|
||||
description: 'read a query',
|
||||
handler: async (args, log) => {
|
||||
try {
|
||||
const [query] = args;
|
||||
const rows = this._read(query, []);
|
||||
log.log(rows);
|
||||
} catch (err) {
|
||||
log.error(err.message);
|
||||
}
|
||||
}
|
||||
},
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
SqliteDatabaseAccessService,
|
||||
};
|
||||
@@ -1,55 +0,0 @@
|
||||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
const { AdvancedBase } = require("puter-js-common");
|
||||
|
||||
const ENDPOINT = 'https://api.puter.com/drivers/call';
|
||||
|
||||
/*
|
||||
|
||||
Fetch example:
|
||||
|
||||
await fetch("https://api.puter.local/drivers/call", {
|
||||
"headers": {
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": "Bearer <actor token>",
|
||||
},
|
||||
"body": JSON.stringify({ interface: '...', method: '...', args: { ... } }),
|
||||
"method": "POST",
|
||||
});
|
||||
|
||||
*/
|
||||
|
||||
class PuterDriverProxy extends AdvancedBase {
|
||||
static MODULES = {
|
||||
axios: require('axios'),
|
||||
}
|
||||
|
||||
constructor ({ target }) {
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
async call (method, args) {
|
||||
const require = this.require;
|
||||
const axios = require('axios');
|
||||
|
||||
// TODO: We need the BYOK feature before we can implement this
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = PuterDriverProxy;
|
||||
@@ -1,161 +0,0 @@
|
||||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
const {encode} = require('html-entities');
|
||||
const path_ = require('path');
|
||||
const fs_ = require('fs');
|
||||
|
||||
const generate_puter_page_html = ({
|
||||
manifest,
|
||||
gui_path,
|
||||
|
||||
app_origin,
|
||||
api_origin,
|
||||
|
||||
meta,
|
||||
|
||||
gui_params,
|
||||
}) => {
|
||||
const e = encode;
|
||||
|
||||
const {
|
||||
title,
|
||||
description,
|
||||
short_description,
|
||||
company,
|
||||
canonical_url,
|
||||
} = meta;
|
||||
|
||||
gui_params = {
|
||||
...meta,
|
||||
...gui_params,
|
||||
app_origin,
|
||||
api_origin,
|
||||
gui_origin: app_origin,
|
||||
};
|
||||
|
||||
return `<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<title>${e(title)}</title>
|
||||
<meta name="author" content="${e(company)}">
|
||||
<meta name="description" content="${e((description).replace(/\n/g, " "))}">
|
||||
<meta name="facebook-domain-verification" content="e29w3hjbnnnypf4kzk2cewcdaxym1y" />
|
||||
<link rel="canonical" href="${e(canonical_url)}">
|
||||
|
||||
<!-- Meta meta tags -->
|
||||
<meta property="og:url" content="${app_origin}">
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:title" content="${e(title)}">
|
||||
<meta property="og:description" content="${e((short_description).replace(/\n/g, " "))}">
|
||||
<meta property="og:image" content="/dist/images/screenshot.png">
|
||||
|
||||
<!-- Twitter meta tags -->
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
<meta property="twitter:domain" content="puter.com">
|
||||
<meta property="twitter:url" content="${app_origin}">
|
||||
<meta name="twitter:title" content="${e(title)}">
|
||||
<meta name="twitter:description" content="${e((short_description).replace(/\n/g, " "))}">
|
||||
<meta name="twitter:image" content="/dist/images/screenshot.png">
|
||||
|
||||
<!-- favicons -->
|
||||
<link rel="apple-touch-icon" sizes="57x57" href="/dist/favicons/apple-icon-57x57.png">
|
||||
<link rel="apple-touch-icon" sizes="60x60" href="/dist/favicons/apple-icon-60x60.png">
|
||||
<link rel="apple-touch-icon" sizes="72x72" href="/dist/favicons/apple-icon-72x72.png">
|
||||
<link rel="apple-touch-icon" sizes="76x76" href="/dist/favicons/apple-icon-76x76.png">
|
||||
<link rel="apple-touch-icon" sizes="114x114" href="/dist/favicons/apple-icon-114x114.png">
|
||||
<link rel="apple-touch-icon" sizes="120x120" href="/dist/favicons/apple-icon-120x120.png">
|
||||
<link rel="apple-touch-icon" sizes="144x144" href="/dist/favicons/apple-icon-144x144.png">
|
||||
<link rel="apple-touch-icon" sizes="152x152" href="/dist/favicons/apple-icon-152x152.png">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/dist/favicons/apple-icon-180x180.png">
|
||||
<link rel="icon" type="image/png" sizes="192x192" href="/dist/favicons/android-icon-192x192.png">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="/dist/favicons/favicon-32x32.png">
|
||||
<link rel="icon" type="image/png" sizes="96x96" href="/dist/favicons/favicon-96x96.png">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="/dist/favicons/favicon-16x16.png">
|
||||
<link rel="manifest" href="/dist/manifest.json">
|
||||
<meta name="msapplication-TileColor" content="#ffffff">
|
||||
<meta name="msapplication-TileImage" content="/dist/favicons/ms-icon-144x144.png">
|
||||
<meta name="theme-color" content="#ffffff">
|
||||
|
||||
<!-- Preload images when applicable -->
|
||||
<link rel="preload" as="image" href="/dist/images/wallpaper.webp">
|
||||
|
||||
<!-- Files from JSON (may be empty) -->
|
||||
${
|
||||
(manifest?.css_paths
|
||||
? manifest.css_paths.map(path => `<link rel="stylesheet" href="${path}">\n`)
|
||||
: []).join('')
|
||||
}
|
||||
<!-- END Files from JSON -->
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<script>window.puter_gui_enabled = true;</script>
|
||||
${
|
||||
(manifest?.lib_paths
|
||||
? manifest.lib_paths.map(path => `<script type="text/javascript" src="${path}"></script>\n`)
|
||||
: []).join('')
|
||||
}
|
||||
|
||||
<script>
|
||||
window.icons = {};
|
||||
|
||||
${(() => {
|
||||
if ( ! manifest ) return '';
|
||||
const html = [];
|
||||
fs_.readdirSync(path_.join(gui_path, 'src/icons')).forEach(file => {
|
||||
// skip dotfiles
|
||||
if(file.startsWith('.'))
|
||||
return;
|
||||
// load image
|
||||
let buff = new Buffer.from(fs_.readFileSync(path_.join(gui_path, 'src/icons') + '/' + file));
|
||||
// convert to base64
|
||||
let base64data = buff.toString('base64');
|
||||
// add to `window.icons`
|
||||
if(file.endsWith('.png'))
|
||||
html.push(`window.icons['${file}'] = "data:image/png;base64,${base64data}";\n`);
|
||||
else if(file.endsWith('.svg'))
|
||||
html.push(`window.icons['${file}'] = "data:image/svg+xml;base64,${base64data}";\n`);
|
||||
})
|
||||
return html.join('');
|
||||
})()}
|
||||
</script>
|
||||
|
||||
${
|
||||
(manifest?.js_paths
|
||||
? manifest.js_paths.map(path => `<script type="module" src="${path}"></script>\n`)
|
||||
: []).join('')
|
||||
}
|
||||
<!-- Load the GUI script -->
|
||||
<script ${ manifest.index ? ' type="module"' : ''} src="${manifest?.index ?? '/dist/gui.js'}"></script>
|
||||
<!-- Initialize GUI when document is loaded -->
|
||||
<script>
|
||||
window.addEventListener('load', function() {
|
||||
gui(${JSON.stringify(gui_params)});
|
||||
});
|
||||
</script>
|
||||
<div id="templates" style="display: none;"></div>
|
||||
</body>
|
||||
|
||||
</html>`;
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
generate_puter_page_html,
|
||||
};
|
||||
@@ -1,31 +0,0 @@
|
||||
{
|
||||
"index": "/src/index.js",
|
||||
"lib_paths": [
|
||||
"/lib/jquery-3.6.1/jquery-3.6.1.min.js",
|
||||
"/lib/viselect.min.js",
|
||||
"/lib/FileSaver.min.js",
|
||||
"/lib/socket.io/socket.io.min.js",
|
||||
"/lib/qrcode.min.js",
|
||||
"/lib/jquery-ui-1.13.2/jquery-ui.min.js",
|
||||
"/lib/[email protected]",
|
||||
"/lib/jquery.dragster.js",
|
||||
"/lib/jquery.menu-aim.js",
|
||||
"/lib/html-entities.js",
|
||||
"/lib/timeago.min.js",
|
||||
"/lib/iro.min.js",
|
||||
"/lib/isMobile.min.js",
|
||||
"/lib/jszip-3.10.1.min.js"
|
||||
],
|
||||
"css_paths": [
|
||||
"/css/normalize.css",
|
||||
"/lib/jquery-ui-1.13.2/jquery-ui.min.css",
|
||||
"/css/style.css"
|
||||
],
|
||||
"js_paths": [
|
||||
"/src/initgui.js",
|
||||
"/src/helpers.js",
|
||||
"/src/IPC.js",
|
||||
"/src/globals.js",
|
||||
"/src/i18n/i18n.js"
|
||||
]
|
||||
}
|
||||
+148
-14
@@ -1,16 +1,150 @@
|
||||
import backend from '@heyputer/backend';
|
||||
// surrounding_box function
|
||||
//
|
||||
// It's really hard to see an error message without using
|
||||
// the surrounding_box function to highlight its location.
|
||||
// The implementation of this in packages/backend might not
|
||||
// work in older versions of node, so we instead re-implement
|
||||
// it here.
|
||||
import console from 'node:console';
|
||||
import process from 'node:process';
|
||||
|
||||
const {
|
||||
Kernel,
|
||||
CoreModule,
|
||||
DatabaseModule,
|
||||
PuterDriversModule,
|
||||
LocalDiskStorageModule,
|
||||
} = backend;
|
||||
const surrounding_box = (col, lines) => {
|
||||
const lengths = lines.map(line => line.length);
|
||||
|
||||
const k = new Kernel();
|
||||
k.add_module(new CoreModule());
|
||||
k.add_module(new DatabaseModule());
|
||||
k.add_module(new PuterDriversModule());
|
||||
k.add_module(new LocalDiskStorageModule());
|
||||
k.boot();
|
||||
const max_length = Math.max(...lengths);
|
||||
const c = str => `\x1b[${col}m${str}\x1b[0m`;
|
||||
const bar = c(Array(max_length + 4).fill('━').join(''));
|
||||
for ( let i = 0 ; i < lines.length ; i++ ) {
|
||||
while ( lines[i].length < max_length ) {
|
||||
lines[i] += ' ';
|
||||
}
|
||||
lines[i] = `${c('┃ ')} ${lines[i]} ${c(' ┃')}`;
|
||||
}
|
||||
lines.unshift(`${c('┏')}${bar}${c('┓')}`);
|
||||
lines.push(`${c('┗')}${bar}${c('┛')}`);
|
||||
};
|
||||
|
||||
// node version check
|
||||
{
|
||||
// Keeping track of WHY certain versions don't work
|
||||
const ver_info = [
|
||||
{ under: 14, reasons: ['optional chaining is not available'] },
|
||||
{ under: 16, reasons: ['disk usage package ABI mismatch'] },
|
||||
];
|
||||
|
||||
const lowest_allowed = Math.max(...ver_info.map(r => r.under));
|
||||
|
||||
// ACTUAL VERSION CHECK
|
||||
const [major, minor] = process.versions.node.split('.').map(Number);
|
||||
if ( major < lowest_allowed ) {
|
||||
const lines = [];
|
||||
lines.push(`Please use a version of Node.js ${lowest_allowed} or newer.`);
|
||||
lines.push(`Issues with node ${process.versions.node}:`);
|
||||
// We also show the user the reasons in case they want to know
|
||||
for ( const { under, reasons } of ver_info ) {
|
||||
if ( major < under ) {
|
||||
lines.push(` - ${reasons.join(', ')}`);
|
||||
}
|
||||
}
|
||||
surrounding_box('31;1', lines);
|
||||
console.error(lines.join('\n'));
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// Annoying polyfill for inconsistency in different node versions
|
||||
if ( ! import.meta.filename ) {
|
||||
Object.defineProperty(import.meta, 'filename', {
|
||||
get: () => import.meta.url.slice('file://'.length),
|
||||
})
|
||||
}
|
||||
|
||||
const main = async () => {
|
||||
const {
|
||||
Kernel,
|
||||
CoreModule,
|
||||
DatabaseModule,
|
||||
LocalDiskStorageModule,
|
||||
SelfHostedModule
|
||||
} = (await import('@heyputer/backend')).default;
|
||||
|
||||
const k = new Kernel({
|
||||
entry_path: import.meta.filename
|
||||
});
|
||||
k.add_module(new CoreModule());
|
||||
k.add_module(new DatabaseModule());
|
||||
k.add_module(new LocalDiskStorageModule());
|
||||
k.add_module(new SelfHostedModule());
|
||||
k.boot();
|
||||
};
|
||||
|
||||
const early_init_errors = [
|
||||
{
|
||||
text: `Cannot find package '@heyputer/backend'`,
|
||||
notes: [
|
||||
'this usually happens if you forget `npm install`'
|
||||
],
|
||||
suggestions: [
|
||||
'try running `npm install`'
|
||||
],
|
||||
technical_notes: [
|
||||
'@heyputer/backend is in an npm workspace'
|
||||
]
|
||||
},
|
||||
{
|
||||
text: `Cannot find package`,
|
||||
notes: [
|
||||
'this usually happens if you forget `npm install`'
|
||||
],
|
||||
suggestions: [
|
||||
'try running `npm install`'
|
||||
],
|
||||
}
|
||||
];
|
||||
|
||||
// null coalescing operator
|
||||
const nco = (...args) => {
|
||||
for ( const arg of args ) {
|
||||
if ( arg !== undefined && arg !== null ) {
|
||||
return arg;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const _print_error_help = (error_help) => {
|
||||
const lines = [];
|
||||
lines.push(nco(error_help.title, error_help.text));
|
||||
for ( const note of (nco(error_help.notes, [])) ) {
|
||||
lines.push(`📝 ${note}`)
|
||||
}
|
||||
if ( error_help.suggestions ) {
|
||||
lines.push('Suggestions:');
|
||||
for ( const suggestion of error_help.suggestions ) {
|
||||
lines.push(`- ${suggestion}`);
|
||||
}
|
||||
}
|
||||
if ( error_help.technical_notes ) {
|
||||
lines.push('Technical Notes:');
|
||||
for ( const note of error_help.technical_notes ) {
|
||||
lines.push(`- ${note}`);
|
||||
}
|
||||
}
|
||||
surrounding_box('31;1', lines);
|
||||
console.error(lines.join('\n'));
|
||||
}
|
||||
|
||||
(async () => {
|
||||
try {
|
||||
await main();
|
||||
} catch (e) {
|
||||
for ( const error_help of early_init_errors ) {
|
||||
const message = e && e.message;
|
||||
if ( e.message && e.message.includes(error_help.text) ) {
|
||||
_print_error_help(error_help);
|
||||
break;
|
||||
}
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
})();
|
||||
@@ -1,96 +0,0 @@
|
||||
/**
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
// About
|
||||
function UITabAbout(){
|
||||
let h = ``;
|
||||
|
||||
h += `<div class="settings-content active" data-settings="about">`;
|
||||
h += `<div class="about-container">`
|
||||
h += `<div class="about">
|
||||
<a href="https://puter.com" target="_blank" class="logo"><img src="/images/logo.png"></a>
|
||||
<p class="description">${i18n('puter_description')}</p>
|
||||
<p class="links">
|
||||
<a href="mailto:[email protected]" target="_blank">[email protected]</a>
|
||||
<span style="color: #CCC;">•</span>
|
||||
<a href="https://docs.puter.com" target="_blank">${i18n('developers')}</a>
|
||||
<span style="color: #CCC;">•</span>
|
||||
<a href="https://status.puter.com" target="_blank">${i18n('status')}</a>
|
||||
<span style="color: #CCC;">•</span>
|
||||
<a href="https://puter.com/terms" target="_blank">${i18n('terms')}</a>
|
||||
<span style="color: #CCC;">•</span>
|
||||
<a href="https://puter.com/privacy" target="_blank">${i18n('privacy')}</a>
|
||||
<span style="color: #CCC;">•</span>
|
||||
<a href="#" class="show-credits">${i18n('credits')}</a>
|
||||
</p>
|
||||
<div class="social-links">
|
||||
<a href="https://twitter.com/HeyPuter/" target="_blank">
|
||||
<svg viewBox="0 0 24 24" aria-hidden="true" style="opacity: 0.7;"><g><path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z"></path></g></svg>
|
||||
</a>
|
||||
<a href="https://github.com/HeyPuter/" target="_blank">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="48px" height="48px" viewBox="0 0 48 48">
|
||||
<g transform="translate(0, 0)">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" fill="#5a606b" d="M24,0.6c-13.3,0-24,10.7-24,24c0,10.6,6.9,19.6,16.4,22.8 c1.2,0.2,1.6-0.5,1.6-1.2c0-0.6,0-2.1,0-4.1c-6.7,1.5-8.1-3.2-8.1-3.2c-1.1-2.8-2.7-3.5-2.7-3.5c-2.2-1.5,0.2-1.5,0.2-1.5 c2.4,0.2,3.7,2.5,3.7,2.5c2.1,3.7,5.6,2.6,7,2c0.2-1.6,0.8-2.6,1.5-3.2c-5.3-0.6-10.9-2.7-10.9-11.9c0-2.6,0.9-4.8,2.5-6.4 c-0.2-0.6-1.1-3,0.2-6.4c0,0,2-0.6,6.6,2.5c1.9-0.5,4-0.8,6-0.8c2,0,4.1,0.3,6,0.8c4.6-3.1,6.6-2.5,6.6-2.5c1.3,3.3,0.5,5.7,0.2,6.4 c1.5,1.7,2.5,3.8,2.5,6.4c0,9.2-5.6,11.2-11,11.8c0.9,0.7,1.6,2.2,1.6,4.4c0,3.2,0,5.8,0,6.6c0,0.6,0.4,1.4,1.7,1.2 C41.1,44.2,48,35.2,48,24.6C48,11.3,37.3,0.6,24,0.6z">
|
||||
</path>
|
||||
</g>
|
||||
</svg>
|
||||
</a>
|
||||
<a href="https://discord.gg/PQcx7Teh8u" target="_blank">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="48px" height="48px" viewBox="0 0 48 48"><g transform="translate(0, 0)"><path d="M19.837,20.3a2.562,2.562,0,0,0,0,5.106,2.562,2.562,0,0,0,0-5.106Zm8.4,0a2.562,2.562,0,1,0,2.346,2.553A2.45,2.45,0,0,0,28.232,20.3Z" fill="#444444" data-color="color-2"></path> <path d="M39.41,1H8.59A4.854,4.854,0,0,0,4,6V37a4.482,4.482,0,0,0,4.59,4.572H34.672l-1.219-4.255L36.4,40.054,39.18,42.63,44,47V6A4.854,4.854,0,0,0,39.41,1ZM30.532,31.038s-.828-.989-1.518-1.863a7.258,7.258,0,0,0,4.163-2.737A13.162,13.162,0,0,1,30.532,27.8a15.138,15.138,0,0,1-3.335.989,16.112,16.112,0,0,1-5.957-.023,19.307,19.307,0,0,1-3.381-.989,13.112,13.112,0,0,1-2.622-1.357,7.153,7.153,0,0,0,4.025,2.714c-.69.874-1.541,1.909-1.541,1.909-5.083-.161-7.015-3.5-7.015-3.5a30.8,30.8,0,0,1,3.312-13.409,11.374,11.374,0,0,1,6.463-2.415l.23.276a15.517,15.517,0,0,0-6.049,3.013s.506-.276,1.357-.667a17.272,17.272,0,0,1,5.221-1.449,2.266,2.266,0,0,1,.391-.046,19.461,19.461,0,0,1,4.646-.046A18.749,18.749,0,0,1,33.2,15.007a15.307,15.307,0,0,0-5.727-2.921l.322-.368a11.374,11.374,0,0,1,6.463,2.415A30.8,30.8,0,0,1,37.57,27.542S35.615,30.877,30.532,31.038Z" fill="#444444"></path></g></svg> </a>
|
||||
<a href="https://www.linkedin.com/company/puter/" target="_blank">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="48px" height="48px" viewBox="0 0 48 48">
|
||||
<g transform="translate(0, 0)">
|
||||
<path fill="#5a606b" d="M46,0H2C0.9,0,0,0.9,0,2v44c0,1.1,0.9,2,2,2h44c1.1,0,2-0.9,2-2V2C48,0.9,47.1,0,46,0z M14.2,40.9H7.1V18 h7.1V40.9z M10.7,14.9c-2.3,0-4.1-1.8-4.1-4.1c0-2.3,1.8-4.1,4.1-4.1c2.3,0,4.1,1.8,4.1,4.1C14.8,13,13,14.9,10.7,14.9z M40.9,40.9 h-7.1V29.8c0-2.7,0-6.1-3.7-6.1c-3.7,0-4.3,2.9-4.3,5.9v11.3h-7.1V18h6.8v3.1h0.1c0.9-1.8,3.3-3.7,6.7-3.7c7.2,0,8.5,4.7,8.5,10.9 V40.9z">
|
||||
</path>
|
||||
</g>
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="version"></div>
|
||||
|
||||
<dialog class="credits">
|
||||
<div class="credit-content">
|
||||
<p style="margin: 0; font-size: 18px; text-align: center;">${i18n('oss_code_and_content')}</p>
|
||||
<div style="max-height: 300px; overflow-y: scroll;">
|
||||
<ul style="padding-left: 25px; padding-top:15px;">
|
||||
<li>FileSaver.js <a target="_blank" href="https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md">${i18n('license')}</a></li>
|
||||
<li>html-entities <a target="_blank" href="https://github.com/mdevils/html-entities/blob/master/LICENSE">${i18n('license')}</a></li>
|
||||
<li>iro.js <a target="_blank" href="https://github.com/jaames/iro.js/blob/master/LICENSE.txt">${i18n('license')}</a></li>
|
||||
<li>jQuery <a target="_blank" href="https://jquery.org/license/">${i18n('license')}</a></li>
|
||||
<li>jQuery-dragster <a target="_blank" href="https://github.com/catmanjan/jquery-dragster/blob/master/LICENSE">${i18n('license')}</a></li>
|
||||
<li>jQuery-menu-aim <a target="_blank" href="https://github.com/kamens/jQuery-menu-aim?tab=readme-ov-file#faq">${i18n('license')}</a></li>
|
||||
<li>jQuery UI <a target="_blank" href="https://jquery.org/license/">${i18n('license')}</a></li>
|
||||
<li>lodash <a target="_blank" href="https://lodash.com/license">${i18n('license')}</a></li>
|
||||
<li>mime <a target="_blank" href="https://github.com/broofa/mime/blob/main/LICENSE">${i18n('license')}</a></li>
|
||||
<li>qrcodejs <a target="_blank" href="https://github.com/davidshimjs/qrcodejs/blob/master/LICENSE">${i18n('license')}</a></li>
|
||||
<li>Selection <a target="_blank" href="https://github.com/simonwep/selection/blob/master/LICENSE">${i18n('license')}</a></li>
|
||||
<li>socket.io <a target="_blank" href="https://github.com/socketio/socket.io/blob/main/LICENSE">${i18n('license')}</a></li>
|
||||
<li>Wallpaper by <a target="_blank" href="https://unsplash.com/@fakurian?utm_content=creditCopyText&utm_medium=referral&utm_source=unsplash">Milad Fakurian</a> on <a target="_blank" href="https://unsplash.com/photos/blue-orange-and-yellow-wallpaper-E8Ufcyxz514?utm_content=creditCopyText&utm_medium=referral&utm_source=unsplash">Unsplash</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</dialog>
|
||||
`;
|
||||
h += `</div>`;
|
||||
h += `</div>`;
|
||||
|
||||
return h;
|
||||
}
|
||||
export default UITabAbout;
|
||||
@@ -1,374 +0,0 @@
|
||||
/**
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
import UIWindow from '../UIWindow.js'
|
||||
import UIWindowChangePassword from '../UIWindowChangePassword.js'
|
||||
// import UIWindowChangeEmail from './UIWindowChangeEmail.js'
|
||||
// import UIWindowDeleteAccount from './UIWindowDeleteAccount.js'
|
||||
import UIWindowChangeUsername from '../UIWindowChangeUsername.js'
|
||||
import changeLanguage from "../../i18n/i18nChangeLanguage.js"
|
||||
import UIWindowConfirmUserDeletion from './UIWindowConfirmUserDeletion.js';
|
||||
import UITabAbout from './UITabAbout.js';
|
||||
|
||||
async function UIWindowSettings(options){
|
||||
return new Promise(async (resolve) => {
|
||||
options = options ?? {};
|
||||
|
||||
let h = '';
|
||||
|
||||
h += `<div class="settings-container">`;
|
||||
h += `<div class="settings">`;
|
||||
// side bar
|
||||
h += `<div class="settings-sidebar disable-user-select">`;
|
||||
h += `<div class="settings-sidebar-item disable-user-select active" data-settings="about" style="background-image: url(${icons['logo-outline.svg']});">${i18n('about')}</div>`;
|
||||
h += `<div class="settings-sidebar-item disable-user-select" data-settings="usage" style="background-image: url(${icons['speedometer-outline.svg']});">${i18n('usage')}</div>`;
|
||||
h += `<div class="settings-sidebar-item disable-user-select" data-settings="account" style="background-image: url(${icons['user.svg']});">${i18n('account')}</div>`;
|
||||
h += `<div class="settings-sidebar-item disable-user-select" data-settings="language" style="background-image: url(${icons['language.svg']});">${i18n('language')}</div>`;
|
||||
h += `<div class="settings-sidebar-item disable-user-select" data-settings="clock" style="background-image: url(${icons['clock.svg']});">${i18n('clock')}</div>`;
|
||||
h += `</div>`;
|
||||
|
||||
// content
|
||||
h += `<div class="settings-content-container">`;
|
||||
|
||||
// About
|
||||
h += UITabAbout();
|
||||
|
||||
// Usage
|
||||
h += `<div class="settings-content" data-settings="usage">`;
|
||||
h += `<h1>Usage</h1>`;
|
||||
h += `<div class="driver-usage">
|
||||
<h3 style="margin-bottom: 5px; font-size: 14px;">${i18n('storage_usage')}</h3>
|
||||
<div style="font-size: 13px; margin-bottom: 3px;">
|
||||
<span id="storage-used"></span>
|
||||
<span> used of </span>
|
||||
<span id="storage-capacity"></span>
|
||||
</div>
|
||||
<div id="storage-bar-wrapper">
|
||||
<span id="storage-used-percent"></span>
|
||||
<div id="storage-bar"></div>
|
||||
</div>
|
||||
</div>`
|
||||
h += `</div>`;
|
||||
|
||||
// Account
|
||||
h += `<div class="settings-content" data-settings="account">`;
|
||||
h += `<h1>${i18n('account')}</h1>`;
|
||||
// change password button
|
||||
h += `<div class="settings-card">`;
|
||||
h += `<strong>${i18n('password')}</strong>`;
|
||||
h += `<div style="flex-grow:1;">`;
|
||||
h += `<button class="button change-password" style="float:right;">${i18n('change_password')}</button>`;
|
||||
h += `</div>`;
|
||||
h += `</div>`;
|
||||
|
||||
// change username button
|
||||
h += `<div class="settings-card">`;
|
||||
h += `<div>`;
|
||||
h += `<strong style="display:block;">${i18n('username')}</strong>`;
|
||||
h += `<span class="username" style="display:block; margin-top:5px;">${user.username}</span>`;
|
||||
h += `</div>`;
|
||||
h += `<div style="flex-grow:1;">`;
|
||||
h += `<button class="button change-username" style="float:right;">${i18n('change_username')}</button>`;
|
||||
h += `</div>`
|
||||
h += `</div>`;
|
||||
|
||||
// change email button
|
||||
if(user.email){
|
||||
h += `<div class="settings-card">`;
|
||||
h += `<div>`;
|
||||
h += `<strong style="display:block;">${i18n('email')}</strong>`;
|
||||
h += `<span style="display:block; margin-top:5px;">${user.email}</span>`;
|
||||
h += `</div>`;
|
||||
h += `<div style="flex-grow:1;">`;
|
||||
h += `<button class="button change-email" style="margin-bottom: 10px; float:right;">${i18n('change_email')}</button>`;
|
||||
h += `</div>`;
|
||||
h += `</div>`;
|
||||
}
|
||||
|
||||
// 'Delete Account' button
|
||||
h += `<div class="settings-card settings-card-danger">`;
|
||||
h += `<strong style="display: inline-block;">${i18n("delete_account")}</strong>`;
|
||||
h += `<div style="flex-grow:1;">`;
|
||||
h += `<button class="button button-danger delete-account" style="float:right;">${i18n("delete_account")}</button>`;
|
||||
h += `</div>`;
|
||||
h += `</div>`;
|
||||
|
||||
h += `</div>`;
|
||||
|
||||
// Language
|
||||
h += `<div class="settings-content" data-settings="language">`;
|
||||
h += `<h1>${i18n('language')}</h1>`;
|
||||
// search
|
||||
h += `<div class="search-container" style="margin-bottom: 10px;">`;
|
||||
h += `<input type="text" class="search" placeholder="Search">`;
|
||||
h += `</div>`;
|
||||
// list of languages
|
||||
const available_languages = listSupportedLanguages();
|
||||
h += `<div class="language-list">`;
|
||||
for (let lang of available_languages) {
|
||||
h += `<div class="language-item ${window.locale === lang.code ? 'active': ''}" data-lang="${lang.code}" data-english-name="${html_encode(lang.english_name)}">${lang.name}</div>`;
|
||||
}
|
||||
h += `</div>`;
|
||||
h += `</div>`;
|
||||
|
||||
// Clock
|
||||
h += `<div class="settings-content" data-settings="clock">`;
|
||||
h += `<h1>${i18n('clock')}</h1>`;
|
||||
h += `<div style="display: flex;align-items: center">`
|
||||
h += `<span>${i18n('visibility')}:</span>`
|
||||
h += `<select class="change-clock-visible" style="margin-left: 10px;flex: 1">`
|
||||
h += `<option value="auto">${i18n('clock_visible_auto')}</option>`
|
||||
h += `<option value="hide">${i18n('clock_visible_hide')}</option>`
|
||||
h += `<option value="show">${i18n('clock_visible_show')}</option>`
|
||||
h += `</select>`
|
||||
h += `</div>`
|
||||
h += `</div>`;
|
||||
|
||||
h += `</div>`;
|
||||
h += `</div>`;
|
||||
h += `</div>`;
|
||||
|
||||
h += ``;
|
||||
|
||||
const el_window = await UIWindow({
|
||||
title: 'Settings',
|
||||
app: 'settings',
|
||||
single_instance: true,
|
||||
icon: null,
|
||||
uid: null,
|
||||
is_dir: false,
|
||||
body_content: h,
|
||||
has_head: true,
|
||||
selectable_body: false,
|
||||
allow_context_menu: false,
|
||||
is_resizable: false,
|
||||
is_droppable: false,
|
||||
init_center: true,
|
||||
allow_native_ctxmenu: true,
|
||||
allow_user_select: true,
|
||||
backdrop: false,
|
||||
width: 800,
|
||||
height: 500,
|
||||
height: 'auto',
|
||||
dominant: true,
|
||||
show_in_taskbar: false,
|
||||
draggable_body: false,
|
||||
onAppend: function(this_window){
|
||||
},
|
||||
window_class: 'window-settings',
|
||||
body_css: {
|
||||
width: 'initial',
|
||||
height: '100%',
|
||||
overflow: 'auto'
|
||||
}
|
||||
});
|
||||
|
||||
$.ajax({
|
||||
url: api_origin + "/drivers/usage",
|
||||
type: 'GET',
|
||||
async: true,
|
||||
contentType: "application/json",
|
||||
headers: {
|
||||
"Authorization": "Bearer " + auth_token
|
||||
},
|
||||
statusCode: {
|
||||
401: function () {
|
||||
logout();
|
||||
},
|
||||
},
|
||||
success: function (res) {
|
||||
let h = ''; // Initialize HTML string for driver usage bars
|
||||
|
||||
// Loop through user services
|
||||
res.user.forEach(service => {
|
||||
const { monthly_limit, monthly_usage } = service;
|
||||
let usageDisplay = ``;
|
||||
|
||||
if (monthly_limit !== null) {
|
||||
let usage_percentage = (monthly_usage / monthly_limit * 100).toFixed(0);
|
||||
usage_percentage = usage_percentage > 100 ? 100 : usage_percentage; // Cap at 100%
|
||||
usageDisplay = `
|
||||
<div class="driver-usage" style="margin-bottom: 10px;">
|
||||
<h3 style="margin-bottom: 5px; font-size: 14px;">${service.service['driver.interface']} (${service.service['driver.method']}):</h3>
|
||||
<span style="font-size: 13px; margin-bottom: 3px;">${monthly_usage} used of ${monthly_limit}</span>
|
||||
<div class="usage-progbar-wrapper" style="width: 100%;">
|
||||
<div class="usage-progbar" style="width: ${usage_percentage}%;"><span class="usage-progbar-percent">${usage_percentage}%</span></div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
else {
|
||||
usageDisplay = `
|
||||
<div class="driver-usage" style="margin-bottom: 10px;">
|
||||
<h3 style="margin-bottom: 5px; font-size: 14px;">${service.service['driver.interface']} (${service.service['driver.method']}):</h3>
|
||||
<span style="font-size: 13px; margin-bottom: 3px;">${i18n('usage')}: ${monthly_usage} (${i18n('unlimited')})</span>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
h += usageDisplay;
|
||||
});
|
||||
|
||||
// Append driver usage bars to the container
|
||||
$('.settings-content[data-settings="usage"]').append(`<div class="driver-usage-container">${h}</div>`);
|
||||
}
|
||||
})
|
||||
|
||||
// df
|
||||
$.ajax({
|
||||
url: api_origin + "/df",
|
||||
type: 'GET',
|
||||
async: true,
|
||||
contentType: "application/json",
|
||||
headers: {
|
||||
"Authorization": "Bearer " + auth_token
|
||||
},
|
||||
statusCode: {
|
||||
401: function () {
|
||||
logout();
|
||||
},
|
||||
},
|
||||
success: function (res) {
|
||||
let usage_percentage = (res.used / res.capacity * 100).toFixed(0);
|
||||
usage_percentage = usage_percentage > 100 ? 100 : usage_percentage;
|
||||
|
||||
$('#storage-used').html(byte_format(res.used));
|
||||
$('#storage-capacity').html(byte_format(res.capacity));
|
||||
$('#storage-used-percent').html(usage_percentage + '%');
|
||||
$('#storage-bar').css('width', usage_percentage + '%');
|
||||
if (usage_percentage >= 100) {
|
||||
$('#storage-bar').css({
|
||||
'border-top-right-radius': '3px',
|
||||
'border-bottom-right-radius': '3px',
|
||||
});
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// version
|
||||
$.ajax({
|
||||
url: api_origin + "/version",
|
||||
type: 'GET',
|
||||
async: true,
|
||||
contentType: "application/json",
|
||||
headers: {
|
||||
"Authorization": "Bearer " + auth_token
|
||||
},
|
||||
statusCode: {
|
||||
401: function () {
|
||||
logout();
|
||||
},
|
||||
},
|
||||
success: function (res) {
|
||||
var d = new Date(0);
|
||||
$('.version').html('Version: ' + res.version + ' • ' + 'Server: ' + res.location + ' • ' + 'Deployed: ' + new Date(res.deploy_timestamp));
|
||||
}
|
||||
})
|
||||
|
||||
$(el_window).find('.credits').on('click', function (e) {
|
||||
if($(e.target).hasClass('credits')){
|
||||
$('.credits').get(0).close();
|
||||
}
|
||||
});
|
||||
|
||||
$(el_window).find('.show-credits').on('click', function (e) {
|
||||
$('.credits').get(0).showModal();
|
||||
})
|
||||
|
||||
$(el_window).find('.change-password').on('click', function (e) {
|
||||
UIWindowChangePassword();
|
||||
})
|
||||
|
||||
$(el_window).find('.change-email').on('click', function (e) {
|
||||
UIWindowChangeEmail();
|
||||
})
|
||||
|
||||
$(el_window).find('.delete-account').on('click', function (e) {
|
||||
UIWindowConfirmUserDeletion();
|
||||
})
|
||||
|
||||
$(el_window).find('.change-username').on('click', function (e) {
|
||||
UIWindowChangeUsername();
|
||||
})
|
||||
|
||||
$(el_window).on('click', '.settings-sidebar-item', function(){
|
||||
const $this = $(this);
|
||||
const settings = $this.attr('data-settings');
|
||||
const $container = $this.closest('.settings').find('.settings-content-container');
|
||||
const $content = $container.find(`.settings-content[data-settings="${settings}"]`);
|
||||
// add active class to sidebar item
|
||||
$this.siblings().removeClass('active');
|
||||
$this.addClass('active');
|
||||
// add active class to content
|
||||
$container.find('.settings-content').removeClass('active');
|
||||
$content.addClass('active');
|
||||
// if language, focus on search
|
||||
if(settings === 'language'){
|
||||
$content.find('.search').first().focus();
|
||||
// make sure all language items are visible
|
||||
$content.find('.language-item').show();
|
||||
// empty search
|
||||
$content.find('.search').val('');
|
||||
}
|
||||
})
|
||||
|
||||
$(el_window).on('click', '.language-item', function(){
|
||||
const $this = $(this);
|
||||
const lang = $this.attr('data-lang');
|
||||
changeLanguage(lang);
|
||||
$this.siblings().removeClass('active');
|
||||
$this.addClass('active');
|
||||
// make sure all other language items are visible
|
||||
$this.closest('.language-list').find('.language-item').show();
|
||||
})
|
||||
|
||||
$(el_window).on('input', '.search', function(){
|
||||
const $this = $(this);
|
||||
const search = $this.val().toLowerCase();
|
||||
const $container = $this.closest('.settings').find('.settings-content-container');
|
||||
const $content = $container.find('.settings-content.active');
|
||||
const $list = $content.find('.language-list');
|
||||
const $items = $list.find('.language-item');
|
||||
$items.each(function(){
|
||||
const $item = $(this);
|
||||
const lang = $item.attr('data-lang');
|
||||
const name = $item.text().toLowerCase();
|
||||
const english_name = $item.attr('data-english-name').toLowerCase();
|
||||
if(name.includes(search) || lang.includes(search) || english_name.includes(search)){
|
||||
$item.show();
|
||||
}else{
|
||||
$item.hide();
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
$(el_window).on('change', 'select.change-clock-visible', function(e){
|
||||
const $this = $(this);
|
||||
const value = $this.val();
|
||||
|
||||
window.change_clock_visible(value);
|
||||
})
|
||||
|
||||
window.change_clock_visible();
|
||||
|
||||
resolve(el_window);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
export default UIWindowSettings
|
||||
@@ -1,263 +0,0 @@
|
||||
/**
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
function UIContextMenu(options){
|
||||
$('.window-active .window-app-iframe').css('pointer-events', 'none');
|
||||
|
||||
const menu_id = global_element_id++;
|
||||
|
||||
let h = '';
|
||||
h += `<div
|
||||
id="context-menu-${menu_id}"
|
||||
data-is-submenu="${options.is_submenu ? 'true' : 'false'}"
|
||||
data-element-id="${menu_id}"
|
||||
data-id="${options.id ?? ''}"
|
||||
${options.parent_id ? `data-parent-id="${options.parent_id}"` : ``}
|
||||
${!options.parent_id && options.parent_element ? `data-parent-id="${$(options.parent_element).attr('data-element-id')}"` : ``}
|
||||
class="context-menu context-menu-active ${options.is_submenu ? 'context-menu-submenu-open' : ''}"
|
||||
>`;
|
||||
|
||||
for(let i=0; i < options.items.length; i++){
|
||||
// item
|
||||
if(!options.items[i].is_divider && options.items[i] !== '-'){
|
||||
// single item
|
||||
if(options.items[i].items === undefined){
|
||||
h += `<li data-action="${i}"
|
||||
class="context-menu-item ${options.items[i].disabled ? ' context-menu-item-disabled' : ''}"
|
||||
>`;
|
||||
// icon
|
||||
h += `<span class="context-menu-item-icon">${options.items[i].icon ?? ''}</span>`;
|
||||
h += `<span class="context-menu-item-icon-active">${options.items[i].icon_active ?? (options.items[i].icon ?? '')}</span>`;
|
||||
// label
|
||||
h += `<span class="contextmenu-label">${options.items[i].html}</span>`;
|
||||
h += `<span class="contextmenu-label-active">${options.items[i].html_active ?? options.items[i].html}</span>`;
|
||||
|
||||
h += `</li>`;
|
||||
}
|
||||
// submenu
|
||||
else{
|
||||
h += `<li data-action="${i}"
|
||||
data-menu-id="${menu_id}-${i}"
|
||||
data-has-submenu="true"
|
||||
data-parent-element-id="${menu_id}"
|
||||
class="context-menu-item-submenu context-menu-item${options.items[i].disabled ? ' context-menu-item-disabled' : ''}"
|
||||
>`;
|
||||
// icon
|
||||
h += `<span class="context-menu-item-icon">${options.items[i].icon ?? ''}</span>`;
|
||||
h += `<span class="context-menu-item-icon-active">${options.items[i].icon_active ?? (options.items[i].icon ?? '')}</span>`;
|
||||
// label
|
||||
h += `${html_encode(options.items[i].html)}`;
|
||||
// arrow
|
||||
h += `<img class="submenu-arrow" src="${html_encode(window.icons['chevron-right.svg'])}"><img class="submenu-arrow submenu-arrow-active" src="${html_encode(window.icons['chevron-right-active.svg'])}">`;
|
||||
h += `</li>`;
|
||||
}
|
||||
}
|
||||
// divider
|
||||
else if(options.items[i].is_divider || options.items[i] === '-')
|
||||
h += `<li class="context-menu-divider"><hr></li>`;
|
||||
}
|
||||
h += `</div>`
|
||||
$('body').append(h)
|
||||
|
||||
const contextMenu = document.getElementById(`context-menu-${menu_id}`);
|
||||
const menu_width = $(contextMenu).width();
|
||||
const menu_height = $(contextMenu).outerHeight();
|
||||
let start_x, start_y;
|
||||
//--------------------------------
|
||||
// Auto position
|
||||
//--------------------------------
|
||||
if(!options.position){
|
||||
if(isMobile.phone || isMobile.tablet){
|
||||
start_x = window.last_touch_x;
|
||||
start_y = window.last_touch_y;
|
||||
|
||||
}else{
|
||||
start_x = window.mouseX;
|
||||
start_y = window.mouseY;
|
||||
}
|
||||
}
|
||||
//--------------------------------
|
||||
// custom position
|
||||
//--------------------------------
|
||||
else{
|
||||
start_x = options.position.left;
|
||||
start_y = options.position.top;
|
||||
}
|
||||
|
||||
// X position
|
||||
let x_pos;
|
||||
if( start_x + menu_width > window.innerWidth){
|
||||
x_pos = start_x - menu_width;
|
||||
// if this is a child menu, the width of parent must be also considered
|
||||
if(options.parent_id){
|
||||
x_pos -= $(`.context-menu[data-element-id="${options.parent_id}"]`).width() + 30;
|
||||
}
|
||||
}else
|
||||
x_pos = start_x
|
||||
|
||||
// Y position
|
||||
let y_pos;
|
||||
// is the menu going to go out of the window from the bottom?
|
||||
if( (start_y + menu_height) > (window.innerHeight - taskbar_height - 10))
|
||||
y_pos = window.innerHeight - menu_height - taskbar_height - 10;
|
||||
else
|
||||
y_pos = start_y;
|
||||
|
||||
// Show ContextMenu
|
||||
$(contextMenu).delay(100).show(0)
|
||||
// In the right position (the mouse)
|
||||
.css({
|
||||
top: y_pos + "px",
|
||||
left: x_pos + "px"
|
||||
});
|
||||
|
||||
// mark other context menus as inactive
|
||||
$('.context-menu').not(contextMenu).removeClass('context-menu-active');
|
||||
|
||||
// An item is clicked
|
||||
$(`#context-menu-${menu_id} > li:not(.context-menu-item-disabled)`).on('click', function (e) {
|
||||
|
||||
// onClick
|
||||
if(options.items[$(this).attr("data-action")].onClick && typeof options.items[$(this).attr("data-action")].onClick === 'function'){
|
||||
let event = e;
|
||||
event.value = options.items[$(this).attr("data-action")]['val'] ?? undefined;
|
||||
options.items[$(this).attr("data-action")].onClick(event);
|
||||
}
|
||||
// close menu and, if exists, its parent
|
||||
if(!$(this).hasClass('context-menu-item-submenu')){
|
||||
$(`#context-menu-${menu_id}, .context-menu[data-element-id="${$(this).closest('.context-menu').attr('data-parent-id')}"]`).fadeOut(200, function(){
|
||||
$(contextMenu).remove();
|
||||
});
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
// Initialize the menuAim plugin (../libs/jquery.menu-aim.js)
|
||||
$(contextMenu).menuAim({
|
||||
submenuSelector: ".context-menu-item-submenu",
|
||||
submenuDirection: function(){
|
||||
// If not submenu
|
||||
if(!options.is_submenu){
|
||||
// if submenu's left postiton is greater than main menu's left position
|
||||
if($(contextMenu).offset().left + 2 * $(contextMenu).width() + 15 < window.innerWidth ){
|
||||
return "right";
|
||||
} else {
|
||||
return "left";
|
||||
}
|
||||
}
|
||||
},
|
||||
// activates item when mouse enters depending on mouse position and direction
|
||||
activate: function (e) {
|
||||
//activate items
|
||||
let item = $(e).closest('.context-menu-item');
|
||||
// mark other items as inactive
|
||||
$(contextMenu).find('.context-menu-item').removeClass('context-menu-item-active');
|
||||
// mark this item as active
|
||||
$(item).addClass('context-menu-item-active');
|
||||
// close any submenu that doesn't belong to this item
|
||||
$(`.context-menu[data-parent-id="${menu_id}"]`).remove();
|
||||
// mark this context menu as active
|
||||
$(contextMenu).addClass('context-menu-active');
|
||||
|
||||
// activate submenu
|
||||
// open submenu if applicable
|
||||
if($(e).hasClass('context-menu-item-submenu')){
|
||||
let item_rect_box = e.getBoundingClientRect();
|
||||
// open submenu only if it's not already open
|
||||
if($(`.context-menu[data-id="${menu_id}-${$(e).attr('data-action')}"]`).length === 0){
|
||||
// close other submenus
|
||||
$(`.context-menu[parent-element-id="${menu_id}"]`).remove();
|
||||
|
||||
// Calculate the position for the submenu
|
||||
let submenu_x_pos, submenu_y_pos;
|
||||
if (isMobile.phone || isMobile.tablet) {
|
||||
submenu_y_pos = y_pos;
|
||||
submenu_x_pos = x_pos;
|
||||
} else {
|
||||
submenu_y_pos = item_rect_box.top - 5;
|
||||
submenu_x_pos = x_pos + item_rect_box.width + 15;
|
||||
}
|
||||
|
||||
// open the new submenu
|
||||
UIContextMenu({
|
||||
items: options.items[parseInt($(e).attr('data-action'))].items,
|
||||
parent_id: menu_id,
|
||||
is_submenu: true,
|
||||
id: menu_id + '-' + $(e).attr('data-action'),
|
||||
position:{
|
||||
top: submenu_y_pos,
|
||||
left: submenu_x_pos,
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
//deactivates row when mouse leavess
|
||||
deactivate: function (e) {
|
||||
//deactivate submenu
|
||||
if($(e).hasClass('context-menu-item-submenu')){
|
||||
$(`.context-menu[data-id="${menu_id}-${$(e).attr('data-action')}"]`).remove();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// useful in cases such as where a menu item is over a window, this prevents from the mousedown event
|
||||
// reaching the window underneath
|
||||
$(`#context-menu-${menu_id} > li:not(.context-menu-item-disabled)`).on('mousedown', function (e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
return false;
|
||||
})
|
||||
|
||||
//disable parent scroll
|
||||
if(options.parent_element){
|
||||
$(options.parent_element).css('overflow', 'hidden');
|
||||
$(options.parent_element).parent().addClass('children-have-open-contextmenu');
|
||||
$(options.parent_element).addClass('has-open-contextmenu');
|
||||
}
|
||||
|
||||
$(contextMenu).on("remove", function () {
|
||||
// when removing, make parent scrollable again
|
||||
if(options.parent_element){
|
||||
$(options.parent_element).parent().removeClass('children-have-open-contextmenu');
|
||||
|
||||
$(options.parent_element).css('overflow', 'scroll');
|
||||
$(options.parent_element).removeClass('has-open-contextmenu');
|
||||
if($(options.parent_element).hasClass('taskbar-item')){
|
||||
make_taskbar_sortable()
|
||||
}
|
||||
}
|
||||
})
|
||||
$(contextMenu).on("contextmenu", function (e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
return false;
|
||||
})
|
||||
}
|
||||
|
||||
window.select_ctxmenu_item = function ($ctxmenu_item){
|
||||
// remove active class from other items
|
||||
$($ctxmenu_item).siblings('.context-menu-item').removeClass('context-menu-item-active');
|
||||
// add active class to the selected item
|
||||
$($ctxmenu_item).addClass('context-menu-item-active');
|
||||
}
|
||||
|
||||
export default UIContextMenu;
|
||||
|
||||
|
||||
@@ -1,76 +0,0 @@
|
||||
/**
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
function UINotification(options){
|
||||
global_element_id++;
|
||||
|
||||
options.content = options.content ?? '';
|
||||
|
||||
let h = '';
|
||||
h += `<div id="ui-notification__${global_element_id}" class="notification antialiased animate__animated animate__fadeInRight animate__slow">`;
|
||||
h += `<img class="notification-close" src="${html_encode(window.icons['close.svg'])}">`;
|
||||
h += options.content;
|
||||
h += `</div>`;
|
||||
|
||||
$('body').append(h);
|
||||
|
||||
|
||||
const el_notification = document.getElementById(`ui-notification__${global_element_id}`);
|
||||
|
||||
$(el_notification).show(0, function(e){
|
||||
// options.onAppend()
|
||||
if(options.onAppend && typeof options.onAppend === 'function'){
|
||||
options.onAppend(el_notification);
|
||||
}
|
||||
})
|
||||
|
||||
// Show Notification
|
||||
$(el_notification).delay(100).show(0).
|
||||
// In the right position (the mouse)
|
||||
css({
|
||||
top: toolbar_height + 15,
|
||||
});
|
||||
|
||||
return el_notification;
|
||||
}
|
||||
|
||||
$(document).on('click', '.notification', function(e){
|
||||
if($(e.target).hasClass('notification')){
|
||||
if(options.click && typeof options.click === 'function'){
|
||||
options.click(e);
|
||||
}
|
||||
window.close_notification(e.target);
|
||||
}else{
|
||||
window.close_notification($(e.target).closest('.notification'));
|
||||
}
|
||||
});
|
||||
|
||||
$(document).on('click', '.notification-close', function(e){
|
||||
window.close_notification($(e.target).closest('.notification'));
|
||||
});
|
||||
|
||||
|
||||
window.close_notification = function(el_notification){
|
||||
$(el_notification).addClass('animate__fadeOutRight');
|
||||
setTimeout(function(){
|
||||
$(el_notification).remove();
|
||||
}, 500);
|
||||
}
|
||||
|
||||
export default UINotification;
|
||||
@@ -1,91 +0,0 @@
|
||||
/**
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
import UIWindow from './UIWindow.js'
|
||||
|
||||
// todo do this using uid rather than item_path, since item_path is way mroe expensive on the DB
|
||||
async function UIWindowConfirmDownload(options){
|
||||
return new Promise(async (resolve) => {
|
||||
let h = '';
|
||||
h += `<div>`;
|
||||
// Confirm download
|
||||
h +=`<div style="margin-bottom:20px; float:left; padding-top:3px; font-size:15px; overflow: hidden; width: calc(100% - 40px); text-overflow: ellipsis; white-space: nowrap;">`;
|
||||
// Message
|
||||
h += `<p style="font-weight:bold;">Do you want to download this file?</p>`;
|
||||
h += `<div style="overflow:hidden; float:left; width: 100px; height: 100px; display:flex; display: flex; justify-content: center; align-items: center;">`;
|
||||
h += `<img style="float:left; margin-right: 7px; width: 60px; height: 60px; filter: drop-shadow(0px 0px 1px rgba(102, 102, 102, 1));" src="${html_encode((await item_icon({is_dir: options.is_dir === '1' || options.is_dir === 'true', type: options.type, name: options.name})).image)}" />`;
|
||||
h += `</div>`;
|
||||
// Item information
|
||||
h += `<div style="overflow:hidden;">`;
|
||||
// Name
|
||||
h += `<p style="text-overflow: ellipsis; overflow: hidden;"><span class="dl-conf-item-attr">${i18n('name')}:</span> ${options.name ?? options.url}</p>`;
|
||||
// Type
|
||||
h += `<p style="text-overflow: ellipsis; overflow: hidden;"><span class="dl-conf-item-attr">${i18n('type')}:</span> ${options.is_dir === '1' || options.is_dir === 'true' ? 'Folder' : options.type ?? 'Unknown File Type'}</p>`;
|
||||
// Source
|
||||
h += `<p style="text-overflow: ellipsis; overflow: hidden;"><span class="dl-conf-item-attr">${i18n('from')}:</span> ${options.source}</p>`;
|
||||
h += `</div>`;
|
||||
h += `</div>`;
|
||||
// Download
|
||||
h += `<button style="float:right; margin-top: 15px; margin-right: -2px; margin-left:10px;" class="button button-small button-primary btn-download-confirm">${i18n('download')}</button>`;
|
||||
// Cancel
|
||||
h += `<button style="float:right; margin-top: 15px;" class="button button-small btn-download-cancel">${i18n('cancel')}</button>`;
|
||||
h +=`</div>`;
|
||||
|
||||
const el_window = await UIWindow({
|
||||
title: `Upload`,
|
||||
icon: window.icons[`app-icon-uploader.svg`],
|
||||
uid: null,
|
||||
is_dir: false,
|
||||
body_content: h,
|
||||
has_head: false,
|
||||
selectable_body: false,
|
||||
draggable_body: true,
|
||||
allow_context_menu: false,
|
||||
is_resizable: false,
|
||||
is_droppable: false,
|
||||
init_center: true,
|
||||
allow_native_ctxmenu: false,
|
||||
allow_user_select: false,
|
||||
window_class: 'window-upload-progress',
|
||||
width: 450,
|
||||
dominant: true,
|
||||
window_css:{
|
||||
height: 'initial',
|
||||
},
|
||||
body_css: {
|
||||
padding: '22px',
|
||||
width: 'initial',
|
||||
'background-color': 'rgba(231, 238, 245, .95)',
|
||||
'backdrop-filter': 'blur(3px)',
|
||||
}
|
||||
});
|
||||
|
||||
$(el_window).find('.btn-download-confirm').on('click submit', function(e){
|
||||
$(el_window).close();
|
||||
resolve(true);
|
||||
})
|
||||
|
||||
$(el_window).find('.btn-download-cancel').on('click submit', function(e){
|
||||
$(el_window).close();
|
||||
resolve(false);
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
export default UIWindowConfirmDownload
|
||||
@@ -1,81 +0,0 @@
|
||||
/**
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
import UIWindow from './UIWindow.js'
|
||||
|
||||
// todo do this using uid rather than item_path, since item_path is way mroe expensive on the DB
|
||||
async function UIWindowCopyProgress(options){
|
||||
let h = '';
|
||||
h += `<div data-copy-operation-id="${options.operation_id}">`;
|
||||
h += `<div>`;
|
||||
// spinner
|
||||
h +=`<svg style="float:left; margin-right: 7px;" xmlns="http://www.w3.org/2000/svg" height="24" width="24" viewBox="0 0 24 24"><title>circle anim</title><g fill="#212121" class="nc-icon-wrapper"><g class="nc-loop-circle-24-icon-f"><path d="M12 24a12 12 0 1 1 12-12 12.013 12.013 0 0 1-12 12zm0-22a10 10 0 1 0 10 10A10.011 10.011 0 0 0 12 2z" fill="#212121" opacity=".4"></path><path d="M24 12h-2A10.011 10.011 0 0 0 12 2V0a12.013 12.013 0 0 1 12 12z" data-color="color-2"></path></g><style>.nc-loop-circle-24-icon-f{--animation-duration:0.5s;transform-origin:12px 12px;animation:nc-loop-circle-anim var(--animation-duration) infinite linear}@keyframes nc-loop-circle-anim{0%{transform:rotate(0)}100%{transform:rotate(360deg)}}</style></g></svg>`;
|
||||
// Progress report
|
||||
h +=`<div style="margin-bottom:20px; float:left; padding-top:3px; font-size:15px; overflow: hidden; width: calc(100% - 40px); text-overflow: ellipsis; white-space: nowrap;">`;
|
||||
// msg
|
||||
h += `<span class="copy-progress-msg">${i18n('copying')} </span>`;
|
||||
h += `<span class="copy-from" style="font-weight:strong;"></span>`;
|
||||
h += `</div>`;
|
||||
// progress
|
||||
h += `<div class="copy-progress-bar-container" style="clear:both; margin-top:20px; border-radius:3px;">`;
|
||||
h += `<div class="copy-progress-bar"></div>`;
|
||||
h += `</div>`;
|
||||
// cancel
|
||||
// h += `<button style="float:right; margin-top: 15px; margin-right: -2px;" class="button button-small copy-cancel-btn">Cancel</button>`;
|
||||
h +=`</div>`;
|
||||
h += `</div>`;
|
||||
|
||||
const el_window = await UIWindow({
|
||||
title: i18n('copying'),
|
||||
icon: window.icons[`app-icon-copying.svg`],
|
||||
uid: null,
|
||||
is_dir: false,
|
||||
body_content: h,
|
||||
has_head: false,
|
||||
selectable_body: false,
|
||||
draggable_body: true,
|
||||
allow_context_menu: false,
|
||||
is_resizable: false,
|
||||
is_droppable: false,
|
||||
init_center: true,
|
||||
allow_native_ctxmenu: false,
|
||||
allow_user_select: false,
|
||||
window_class: 'window-copy-progress',
|
||||
width: 450,
|
||||
dominant: true,
|
||||
window_css:{
|
||||
height: 'initial',
|
||||
},
|
||||
body_css: {
|
||||
padding: '22px',
|
||||
width: 'initial',
|
||||
'background-color': 'rgba(231, 238, 245, .95)',
|
||||
'backdrop-filter': 'blur(3px)',
|
||||
}
|
||||
});
|
||||
|
||||
$(el_window).find('.copy-cancel-btn').on('click', function(e){
|
||||
operation_cancelled[options.operation_id] = true;
|
||||
$(el_window).close();
|
||||
})
|
||||
|
||||
return el_window;
|
||||
}
|
||||
|
||||
export default UIWindowCopyProgress
|
||||
@@ -1,81 +0,0 @@
|
||||
/**
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
import UIWindow from './UIWindow.js'
|
||||
|
||||
// todo do this using uid rather than item_path, since item_path is way mroe expensive on the DB
|
||||
async function UIWindowDownloadProgress(options){
|
||||
let h = '';
|
||||
h += `<div data-download-operation-id="${options.operation_id}">`;
|
||||
h += `<div>`;
|
||||
// Spinner
|
||||
h +=`<svg style="float:left; margin-right: 7px;" xmlns="http://www.w3.org/2000/svg" height="24" width="24" viewBox="0 0 24 24"><title>circle anim</title><g fill="#212121" class="nc-icon-wrapper"><g class="nc-loop-circle-24-icon-f"><path d="M12 24a12 12 0 1 1 12-12 12.013 12.013 0 0 1-12 12zm0-22a10 10 0 1 0 10 10A10.011 10.011 0 0 0 12 2z" fill="#212121" opacity=".4"></path><path d="M24 12h-2A10.011 10.011 0 0 0 12 2V0a12.013 12.013 0 0 1 12 12z" data-color="color-2"></path></g><style>.nc-loop-circle-24-icon-f{--animation-duration:0.5s;transform-origin:12px 12px;animation:nc-loop-circle-anim var(--animation-duration) infinite linear}@keyframes nc-loop-circle-anim{0%{transform:rotate(0)}100%{transform:rotate(360deg)}}</style></g></svg>`;
|
||||
// Progress report
|
||||
h +=`<div style="margin-bottom:20px; float:left; padding-top:3px; font-size:15px; overflow: hidden; width: calc(100% - 40px); text-overflow: ellipsis; white-space: nowrap;">`;
|
||||
// msg
|
||||
h += `<span class="upload-progress-msg">${i18n('downloading')}...<strong>${options.item_name ?? ''}</strong></span>`;
|
||||
h += `</div>`;
|
||||
// Progress
|
||||
h += `<div class="download-progress-bar-container" style="clear:both; margin-top:20px; border-radius:3px;">`;
|
||||
h += `<div class="download-progress-bar"></div>`;
|
||||
h += `</div>`;
|
||||
// Cancel
|
||||
h += `<button style="float:right; margin-top: 15px; margin-right: -2px;" class="button button-small download-cancel-btn">Cancel</button>`;
|
||||
h +=`</div>`;
|
||||
h += `</div>`;
|
||||
|
||||
const el_window = await UIWindow({
|
||||
title: `Upload`,
|
||||
icon: window.icons[`app-icon-uploader.svg`],
|
||||
uid: null,
|
||||
is_dir: false,
|
||||
body_content: h,
|
||||
has_head: false,
|
||||
selectable_body: false,
|
||||
draggable_body: true,
|
||||
allow_context_menu: false,
|
||||
is_resizable: false,
|
||||
is_droppable: false,
|
||||
init_center: true,
|
||||
allow_native_ctxmenu: false,
|
||||
allow_user_select: false,
|
||||
window_class: 'window-upload-progress',
|
||||
width: 450,
|
||||
dominant: true,
|
||||
window_css:{
|
||||
height: 'initial',
|
||||
},
|
||||
body_css: {
|
||||
padding: '22px',
|
||||
width: 'initial',
|
||||
'background-color': 'rgba(231, 238, 245, .95)',
|
||||
'backdrop-filter': 'blur(3px)',
|
||||
}
|
||||
});
|
||||
|
||||
// cancel download button clicked
|
||||
$(el_window).find('.download-cancel-btn').on('click', function(){
|
||||
operation_cancelled[options.operation_id] = true;
|
||||
$(el_window).close();
|
||||
})
|
||||
|
||||
return el_window;
|
||||
}
|
||||
|
||||
export default UIWindowDownloadProgress
|
||||
@@ -1,121 +0,0 @@
|
||||
/**
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
import UIWindow from './UIWindow.js'
|
||||
import UIPopover from './UIPopover.js'
|
||||
|
||||
async function UIWindowGetCopyLink(options){
|
||||
let h = '';
|
||||
let copy_btn_text = 'Copy Link';
|
||||
let copied_btn_text = 'Copied!';
|
||||
const signature = await puter.fs.sign(null, {uid: options.uid, action: 'read'})
|
||||
const url = `${gui_origin}/?name=${encodeURIComponent(options.name)}&is_dir=${encodeURIComponent(options.is_dir)}&download=${encodeURIComponent(signature.items.read_url)}`;
|
||||
|
||||
h += `<div>`;
|
||||
h += `<p style="font-size: 15px; font-weight: 400; -webkit-font-smoothing: antialiased; color: #474a57;">Share the following link with anyone and they will be able to receive a copy of <strong>${html_encode(options.name)}</strong></p>`;
|
||||
h += `<input type="text" style="margin-bottom:10px;" class="downloadable-link" readonly />`;
|
||||
h += `<button class="button button-primary copy-downloadable-link" style="width:130px;">${copy_btn_text}</button>`
|
||||
h += `<img class="share-copy-link-on-social" src="${window.icons['share-outline.svg']}">`;
|
||||
h += `</div>`;
|
||||
|
||||
const el_window = await UIWindow({
|
||||
title: `Get Copy Link`,
|
||||
icon: null,
|
||||
uid: null,
|
||||
is_dir: false,
|
||||
body_content: h,
|
||||
has_head: true,
|
||||
selectable_body: false,
|
||||
draggable_body: false,
|
||||
allow_context_menu: false,
|
||||
is_resizable: false,
|
||||
is_droppable: false,
|
||||
init_center: true,
|
||||
allow_native_ctxmenu: true,
|
||||
allow_user_select: true,
|
||||
onAppend: function(el_window){
|
||||
},
|
||||
width: 500,
|
||||
dominant: true,
|
||||
window_css: {
|
||||
height: 'initial',
|
||||
},
|
||||
body_css: {
|
||||
width: 'initial',
|
||||
'max-height': 'calc(100vh - 200px)',
|
||||
'background-color': 'rgb(241 246 251)',
|
||||
'backdrop-filter': 'blur(3px)',
|
||||
'padding': '10px 20px 20px 20px',
|
||||
'height': 'initial',
|
||||
}
|
||||
});
|
||||
|
||||
$(el_window).find('.window-body .downloadable-link').val(url);
|
||||
|
||||
$(el_window).find('.window-body .share-copy-link-on-social').on('click', function(e){
|
||||
const social_links = socialLink({
|
||||
url: url,
|
||||
title: i18n('get_a_copy_of_on_puter', options.name, false),
|
||||
description: i18n('get_a_copy_of_on_puter', options.name, false),
|
||||
});
|
||||
|
||||
let social_links_html = ``;
|
||||
social_links_html += `<div style="padding: 10px;">`;
|
||||
social_links_html += `<p style="margin: 0; text-align: center; margin-bottom: 6px; color: #484a57; font-weight: bold; font-size: 14px;">Share to</p>`
|
||||
social_links_html += `<a class="copy-link-social-btn" target="_blank" href="${social_links.twitter}" style=""><svg viewBox="0 0 24 24" aria-hidden="true" style="opacity: 0.7;"><g><path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z"></path></g></svg></a>`
|
||||
social_links_html += `<a class="copy-link-social-btn" target="_blank" href="${social_links.whatsapp}" style=""><img src="${window.icons['logo-whatsapp.svg']}"></a>`
|
||||
social_links_html += `<a class="copy-link-social-btn" target="_blank" href="${social_links.facebook}" style=""><img src="${window.icons['logo-facebook.svg']}"></a>`
|
||||
social_links_html += `<a class="copy-link-social-btn" target="_blank" href="${social_links.linkedin}" style=""><img src="${window.icons['logo-linkedin.svg']}"></a>`
|
||||
social_links_html += `<a class="copy-link-social-btn" target="_blank" href="${social_links.reddit}" style=""><img src="${window.icons['logo-reddit.svg']}"></a>`
|
||||
social_links_html += `<a class="copy-link-social-btn" target="_blank" href="${social_links['telegram.me']}" style=""><img src="${window.icons['logo-telegram.svg']}"></a>`
|
||||
social_links_html += '</div>';
|
||||
|
||||
UIPopover({
|
||||
content: social_links_html,
|
||||
snapToElement: this,
|
||||
parent_element: this,
|
||||
// width: 300,
|
||||
height: 100,
|
||||
position: 'bottom',
|
||||
});
|
||||
})
|
||||
|
||||
$(el_window).find('.window-body .copy-downloadable-link').on('click', async function(e){
|
||||
var copy_btn = this;
|
||||
if (navigator.clipboard) {
|
||||
// Get link text
|
||||
const selected_text = $(el_window).find('.window-body .downloadable-link').val();
|
||||
// copy selected text to clipboard
|
||||
await navigator.clipboard.writeText(selected_text);
|
||||
}
|
||||
else{
|
||||
// Get the text field
|
||||
$(el_window).find('.window-body .downloadable-link').select();
|
||||
// Copy the text inside the text field
|
||||
document.execCommand('copy');
|
||||
}
|
||||
|
||||
$(this).html(copied_btn_text);
|
||||
setTimeout(function(){
|
||||
$(copy_btn).html(copy_btn_text);
|
||||
}, 1000);
|
||||
});
|
||||
}
|
||||
|
||||
export default UIWindowGetCopyLink
|
||||
@@ -1,202 +0,0 @@
|
||||
/**
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
import UIWindow from './UIWindow.js'
|
||||
import UIWindowSignup from './UIWindowSignup.js'
|
||||
import UIWindowRecoverPassword from './UIWindowRecoverPassword.js'
|
||||
|
||||
async function UIWindowLogin(options){
|
||||
options = options ?? {};
|
||||
options.reload_on_success = options.reload_on_success ?? false;
|
||||
options.has_head = options.has_head ?? true;
|
||||
options.send_confirmation_code = options.send_confirmation_code ?? false;
|
||||
options.show_password = options.show_password ?? false;
|
||||
|
||||
return new Promise(async (resolve) => {
|
||||
const internal_id = window.uuidv4();
|
||||
let h = ``;
|
||||
h += `<div style="max-width: 500px; min-width: 340px;">`;
|
||||
if(!options.has_head && options.show_close_button !== false)
|
||||
h += `<div class="generic-close-window-button"> × </div>`;
|
||||
h += `<div style="padding: 20px; border-bottom: 1px solid #ced7e1; width: 100%; box-sizing: border-box;">`;
|
||||
// title
|
||||
h += `<h1 class="login-form-title">${i18n('log_in')}</h1>`;
|
||||
// login form
|
||||
h += `<form class="login-form">`;
|
||||
// error msg
|
||||
h += `<div class="login-error-msg"></div>`;
|
||||
// username/email
|
||||
h += `<div style="overflow: hidden;">`;
|
||||
h += `<label for="email_or_username-${internal_id}">${i18n('email_or_username')}</label>`;
|
||||
h += `<input id="email_or_username-${internal_id}" class="email_or_username" type="text" name="email_or_username" spellcheck="false" autocorrect="off" autocapitalize="off" data-gramm_editor="false" autocomplete="username"/>`;
|
||||
h += `</div>`;
|
||||
// password with conditional type based based on options.show_password
|
||||
h += `<div style="overflow: hidden; margin-top: 20px; margin-bottom: 20px; position: relative;">`;
|
||||
h += `<label for="password-${internal_id}">${i18n('password')}</label>`;
|
||||
h += `<input id="password-${internal_id}" class="password" type="${options.show_password ? "text" : "password"}" name="password" autocomplete="current-password"/>`;
|
||||
// show/hide icon
|
||||
h += `<span style="position: absolute; right: 5%; top: 50%; cursor: pointer;" id="toggle-show-password-${internal_id}">
|
||||
<img class="toggle-show-password-icon" src="${options.show_password ? window.icons["eye-closed.svg"] : window.icons["eye-open.svg"]}" width="20" height="20">
|
||||
</span>`;
|
||||
h += `</div>`;
|
||||
// login
|
||||
h += `<button class="login-btn button button-primary button-block button-normal">${i18n('log_in')}</button>`;
|
||||
// password recovery
|
||||
h += `<p style="text-align:center; margin-bottom: 0;"><span class="forgot-password-link">${i18n('forgot_pass_c2a')}</span></p>`;
|
||||
h += `</form>`;
|
||||
h += `</div>`;
|
||||
// create account link
|
||||
if(options.show_signup_button === undefined || options.show_signup_button){
|
||||
h += `<div class="c2a-wrapper" style="padding:20px;">`;
|
||||
h += `<button class="signup-c2a-clickable">${i18n('create_free_account')}</button>`;
|
||||
h += `</div>`;
|
||||
}
|
||||
h += `</div>`;
|
||||
|
||||
const el_window = await UIWindow({
|
||||
title: null,
|
||||
app: 'login',
|
||||
single_instance: true,
|
||||
icon: null,
|
||||
uid: null,
|
||||
is_dir: false,
|
||||
body_content: h,
|
||||
has_head: true,
|
||||
selectable_body: false,
|
||||
draggable_body: false,
|
||||
allow_context_menu: false,
|
||||
is_draggable: options.is_draggable ?? true,
|
||||
is_droppable: false,
|
||||
is_resizable: false,
|
||||
stay_on_top: false,
|
||||
allow_native_ctxmenu: true,
|
||||
allow_user_select: true,
|
||||
...options.window_options,
|
||||
width: 350,
|
||||
dominant: true,
|
||||
on_close: ()=>{
|
||||
resolve(false)
|
||||
},
|
||||
onAppend: function(this_window){
|
||||
$(this_window).find(`.email_or_username`).get(0).focus({preventScroll:true});
|
||||
},
|
||||
window_class: 'window-login',
|
||||
window_css:{
|
||||
height: 'initial',
|
||||
},
|
||||
body_css: {
|
||||
width: 'initial',
|
||||
padding: '0',
|
||||
'background-color': 'rgb(255 255 255)',
|
||||
'backdrop-filter': 'blur(3px)',
|
||||
'display': 'flex',
|
||||
'flex-direction': 'column',
|
||||
'justify-content': 'center',
|
||||
'align-items': 'center',
|
||||
}
|
||||
})
|
||||
|
||||
$(el_window).find('.forgot-password-link').on('click', function(e){
|
||||
UIWindowRecoverPassword({
|
||||
window_options: {
|
||||
backdrop: true,
|
||||
close_on_backdrop_click: false,
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
$(el_window).find('.login-btn').on('click', function(e){
|
||||
const email_username = $(el_window).find('.email_or_username').val();
|
||||
const password = $(el_window).find('.password').val();
|
||||
let data;
|
||||
|
||||
if(is_email(email_username)){
|
||||
data = JSON.stringify({
|
||||
email: email_username,
|
||||
password: password
|
||||
})
|
||||
}else{
|
||||
data = JSON.stringify({
|
||||
username: email_username,
|
||||
password: password
|
||||
})
|
||||
}
|
||||
|
||||
$(el_window).find('.login-error-msg').hide();
|
||||
|
||||
let headers = {};
|
||||
if(window.custom_headers)
|
||||
headers = window.custom_headers;
|
||||
|
||||
$.ajax({
|
||||
url: gui_origin + "/login",
|
||||
type: 'POST',
|
||||
async: false,
|
||||
headers: headers,
|
||||
contentType: "application/json",
|
||||
data: data,
|
||||
success: function (data){
|
||||
update_auth_data(data.token, data.user);
|
||||
|
||||
if(options.reload_on_success){
|
||||
window.onbeforeunload = null;
|
||||
window.location.replace('/');
|
||||
}else
|
||||
resolve(true);
|
||||
$(el_window).close();
|
||||
},
|
||||
error: function (err){
|
||||
$(el_window).find('.login-error-msg').html(err.responseText);
|
||||
$(el_window).find('.login-error-msg').fadeIn();
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
$(el_window).find('.login-form').on('submit', function(e){
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
return false;
|
||||
})
|
||||
|
||||
$(el_window).find('.signup-c2a-clickable').on('click', async function(e){
|
||||
//destroy this window
|
||||
$(el_window).close();
|
||||
// create Signup window
|
||||
const signup = await UIWindowSignup({
|
||||
referrer: options.referrer,
|
||||
show_close_button: options.show_close_button,
|
||||
reload_on_success: options.reload_on_success,
|
||||
window_options: options.window_options,
|
||||
send_confirmation_code: options.send_confirmation_code,
|
||||
});
|
||||
if(signup)
|
||||
resolve(true);
|
||||
})
|
||||
|
||||
$(el_window).find(`#toggle-show-password-${internal_id}`).on("click", function (e) {
|
||||
options.show_password = !options.show_password;
|
||||
// hide/show password and update icon
|
||||
$(el_window).find(".password").attr("type", options.show_password ? "text" : "password");
|
||||
$(el_window).find(".toggle-show-password-icon").attr("src", options.show_password ? window.icons["eye-closed.svg"] : window.icons["eye-open.svg"],
|
||||
)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
export default UIWindowLogin
|
||||
@@ -1,81 +0,0 @@
|
||||
/**
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
import UIWindow from './UIWindow.js'
|
||||
|
||||
// todo do this using uid rather than item_path, since item_path is way mroe expensive on the DB
|
||||
async function UIWindowMoveProgress(options){
|
||||
let h = '';
|
||||
h += `<div data-move-operation-id="${options.operation_id}">`;
|
||||
h += `<div>`;
|
||||
// spinner
|
||||
h +=`<svg style="float:left; margin-right: 7px;" xmlns="http://www.w3.org/2000/svg" height="24" width="24" viewBox="0 0 24 24"><title>circle anim</title><g fill="#212121" class="nc-icon-wrapper"><g class="nc-loop-circle-24-icon-f"><path d="M12 24a12 12 0 1 1 12-12 12.013 12.013 0 0 1-12 12zm0-22a10 10 0 1 0 10 10A10.011 10.011 0 0 0 12 2z" fill="#212121" opacity=".4"></path><path d="M24 12h-2A10.011 10.011 0 0 0 12 2V0a12.013 12.013 0 0 1 12 12z" data-color="color-2"></path></g><style>.nc-loop-circle-24-icon-f{--animation-duration:0.5s;transform-origin:12px 12px;animation:nc-loop-circle-anim var(--animation-duration) infinite linear}@keyframes nc-loop-circle-anim{0%{transform:rotate(0)}100%{transform:rotate(360deg)}}</style></g></svg>`;
|
||||
// Progress report
|
||||
h +=`<div style="margin-bottom:20px; float:left; padding-top:3px; font-size:15px; overflow: hidden; width: calc(100% - 40px); text-overflow: ellipsis; white-space: nowrap;">`;
|
||||
// msg
|
||||
h += `<span class="move-progress-msg">${i18n('moving')} </span>`;
|
||||
h += `<span class="move-from" style="font-weight:strong;"></span>`;
|
||||
h += `</div>`;
|
||||
// progress
|
||||
h += `<div class="move-progress-bar-container" style="clear:both; margin-top:20px; border-radius:3px;">`;
|
||||
h += `<div class="move-progress-bar"></div>`;
|
||||
h += `</div>`;
|
||||
// cancel
|
||||
// h += `<button style="float:right; margin-top: 15px; margin-right: -2px;" class="button button-small move-cancel-btn">Cancel</button>`;
|
||||
h +=`</div>`;
|
||||
h += `</div>`;
|
||||
|
||||
const el_window = await UIWindow({
|
||||
title: `moveing`,
|
||||
icon: window.icons[`app-icon-moveing.svg`],
|
||||
uid: null,
|
||||
is_dir: false,
|
||||
body_content: h,
|
||||
has_head: false,
|
||||
selectable_body: false,
|
||||
draggable_body: true,
|
||||
allow_context_menu: false,
|
||||
is_resizable: false,
|
||||
is_droppable: false,
|
||||
init_center: true,
|
||||
allow_native_ctxmenu: false,
|
||||
allow_user_select: false,
|
||||
window_class: 'window-move-progress',
|
||||
width: 450,
|
||||
dominant: true,
|
||||
window_css:{
|
||||
height: 'initial',
|
||||
},
|
||||
body_css: {
|
||||
padding: '22px',
|
||||
width: 'initial',
|
||||
'background-color': 'rgba(231, 238, 245, .95)',
|
||||
'backdrop-filter': 'blur(3px)',
|
||||
}
|
||||
});
|
||||
|
||||
$(el_window).find('.move-cancel-btn').on('click', function(e){
|
||||
operation_cancelled[options.operation_id] = true;
|
||||
$(el_window).close();
|
||||
})
|
||||
|
||||
return el_window;
|
||||
}
|
||||
|
||||
export default UIWindowMoveProgress
|
||||
Loaded 100 of 1251 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user