mirror of
https://shylinux.com/x/icebergs
synced 2025-05-12 23:40:15 +08:00
Compare commits
1365 Commits
Author | SHA1 | Date | |
---|---|---|---|
7d26b0afb0 | |||
1f9e8d756f | |||
705f3d074e | |||
b0c7feb56e | |||
7e5cff6b81 | |||
6c0e3a0a58 | |||
08f2f1626d | |||
5260027c9f | |||
26e62a1b22 | |||
e008f4d417 | |||
5fc5ccd0ea | |||
35c1407d29 | |||
55a0c3d120 | |||
968d9389c9 | |||
7fea8e88a4 | |||
8fa2f6e8b3 | |||
fe1a6d30aa | |||
02962f9d20 | |||
612ecdf4a6 | |||
c3f37f626b | |||
b4627b2975 | |||
f3bc5eb1e1 | |||
03990b839e | |||
473826664a | |||
![]() |
be66627287 | ||
030c018877 | |||
![]() |
0071ba89d9 | ||
c067576dd6 | |||
96d812612b | |||
![]() |
a33bc88dcc | ||
2f715c5233 | |||
![]() |
8a27ce7d66 | ||
![]() |
da81284b37 | ||
![]() |
bbb0ae9de9 | ||
7bb197ed94 | |||
bc94d8e1e4 | |||
942606d750 | |||
c418c8c070 | |||
87c96c880d | |||
cdaa2d7984 | |||
![]() |
38b7942c1b | ||
![]() |
240a0c88bf | ||
![]() |
297c299694 | ||
![]() |
324cd9dc57 | ||
1829822e43 | |||
a8b365dc31 | |||
![]() |
b64a3b5725 | ||
![]() |
0ef29edbad | ||
6fc5cbde02 | |||
85e1f1dcb6 | |||
![]() |
cd5882b2ee | ||
259aa7639a | |||
91f4578d63 | |||
![]() |
54211e220d | ||
00d0a3f449 | |||
![]() |
8782b192e3 | ||
![]() |
92a2fcac3c | ||
c045033e55 | |||
c022852de3 | |||
fa73c5c940 | |||
0be5c0f6f3 | |||
524bbf6430 | |||
![]() |
50ba5c3a3f | ||
d9fcacd679 | |||
![]() |
c661ed4f12 | ||
![]() |
193a2ab917 | ||
aa756c2bc3 | |||
7551a8dfab | |||
be8c60d97c | |||
![]() |
61b81cf089 | ||
813ec2b17a | |||
d4c73ce195 | |||
472f72889a | |||
a3e4861989 | |||
![]() |
18d65c81e5 | ||
![]() |
f59b7cc461 | ||
ec961b40fb | |||
a075aa7975 | |||
![]() |
287083f9ca | ||
2e0131a331 | |||
![]() |
7dcf68b0d8 | ||
66033654c5 | |||
6540f3f3f1 | |||
37fe3b44b0 | |||
bcdce97856 | |||
ff0590852d | |||
a352374bb4 | |||
d30b4e2034 | |||
131858f4b1 | |||
e042dc832c | |||
8f10a46fb5 | |||
![]() |
313b7d4c95 | ||
f8af90a71e | |||
![]() |
52b47dee2a | ||
![]() |
5776c42f7b | ||
![]() |
73c32ccc9b | ||
![]() |
f9932b5dba | ||
![]() |
5afc3781a6 | ||
![]() |
dc242dfa54 | ||
![]() |
e02517a57e | ||
![]() |
f6a009c7fa | ||
![]() |
be0a295b52 | ||
![]() |
39a5ce360e | ||
![]() |
928666d2c9 | ||
![]() |
51ae44aeb3 | ||
![]() |
d3ba62cc61 | ||
![]() |
07111495dd | ||
e34752141a | |||
![]() |
95b45c2f15 | ||
![]() |
b2b4616ec1 | ||
![]() |
1060a60a5e | ||
4d892e03d3 | |||
ca734d3baf | |||
2deff32468 | |||
ed39ff23e7 | |||
d4f4754be8 | |||
80807ed1d2 | |||
c4b9641a5e | |||
0bff96f485 | |||
7ab38ec81f | |||
56b87e9e78 | |||
f174577bde | |||
ed65d194e6 | |||
15a79273ac | |||
0eac777f6f | |||
0f8a77af25 | |||
9a192b012f | |||
4b27054210 | |||
8d1374149c | |||
768bca93b1 | |||
f45d784af7 | |||
329f963a38 | |||
53c5a80da6 | |||
b1d5d09a80 | |||
4a5256c19f | |||
e3fb897137 | |||
b1bd23cc26 | |||
67b1e41db9 | |||
ce0735856e | |||
![]() |
a0ef75490c | ||
![]() |
5891f4f621 | ||
d4a5e4df44 | |||
25df349028 | |||
618218247b | |||
15a4603a18 | |||
2f33ff38de | |||
972c9fc97f | |||
41cea7f8b0 | |||
5a4b79b4eb | |||
a7014de914 | |||
eb73841a72 | |||
704519e336 | |||
2f4e941aa0 | |||
e29a4fa6b8 | |||
af1a9be68e | |||
a5cd77e87d | |||
ccfffd917c | |||
fb99d27694 | |||
805cfbcc25 | |||
170365ddab | |||
271e743c3c | |||
d401e8ec2c | |||
daa740ffbe | |||
9ba006a1da | |||
97bdf84965 | |||
555be526e3 | |||
06a89de015 | |||
2fe571f9d6 | |||
36f1fe2a7b | |||
7214a38d52 | |||
0f87c5ac5e | |||
8328b4cb69 | |||
0742533ce6 | |||
889f221e4b | |||
77a2cb1a43 | |||
6ff235f13a | |||
906183a522 | |||
38d74bc01f | |||
7b21b28b98 | |||
d3001524f2 | |||
b9a8678410 | |||
7b8e933bb9 | |||
3e63a8c243 | |||
af0d446abc | |||
01bacc73a2 | |||
9bf29af91f | |||
8b23ad92e0 | |||
cc0a5de7a0 | |||
eb69a26017 | |||
4dcb03c9dc | |||
e6c64b7e1f | |||
27064b6aa9 | |||
178a73ae4f | |||
c18f363085 | |||
67b4924b9a | |||
cfd5db37ca | |||
dd974b0980 | |||
6f4d324808 | |||
96dd7e96de | |||
82c0c14dea | |||
1aa04477c4 | |||
7862121a3c | |||
755aaf72b0 | |||
a77f9207c0 | |||
adea456e67 | |||
d69b895983 | |||
35c8a1ca44 | |||
0959289870 | |||
d264cd3261 | |||
558bf677da | |||
57035a9fa5 | |||
ee32bd8346 | |||
bc6e12a6f0 | |||
95ba9fc6cd | |||
96713c1e75 | |||
74075002f1 | |||
fda6e6f969 | |||
f30bdb9696 | |||
4d8a21fd54 | |||
c129026c52 | |||
f8ca54a85e | |||
5c63a4b467 | |||
9d72dd7890 | |||
b5d6f7a94c | |||
24e9a8682f | |||
0587d4dd75 | |||
019f536248 | |||
194fd6f5bc | |||
22ccf77a66 | |||
745ea23b48 | |||
4e03450ce2 | |||
13afc46682 | |||
d4f9ea0f81 | |||
3f945f963a | |||
120e65bb92 | |||
bfaf7380e1 | |||
bd7d558208 | |||
ac151623c1 | |||
9e1ff8d564 | |||
598942a836 | |||
7830bf0bf7 | |||
8021138a80 | |||
41c157c6ed | |||
c27d82e83e | |||
af91084d59 | |||
a27fd93686 | |||
f7b4edde23 | |||
0bfb8673a5 | |||
e6607bcd17 | |||
f64b141930 | |||
ac3241b168 | |||
1bc8a05ca6 | |||
272c91f469 | |||
f359c438fc | |||
82415d742a | |||
bfa6ecefb2 | |||
6b6e20458b | |||
b499d09f37 | |||
fd324e5f14 | |||
95ef705c49 | |||
12c66f89bb | |||
b31a5f8286 | |||
73ecfc0cb6 | |||
8b0e3ebe55 | |||
bcbfb9aaed | |||
b5d3ecf103 | |||
209d911e25 | |||
960748e223 | |||
eac98f23f5 | |||
baca546e49 | |||
63cbd6d4c0 | |||
d8c381a933 | |||
b8c8d1603e | |||
555b91fa8f | |||
d71d72aa19 | |||
bb99205fdb | |||
f7e3dcd9ff | |||
582519d290 | |||
e2babe49a6 | |||
172e734f76 | |||
d0de69d086 | |||
9ecfc80f03 | |||
c39b138277 | |||
ed06078ce4 | |||
4dfe6269c5 | |||
183faff9ce | |||
9bdc7af5e9 | |||
90469e941d | |||
b98b3052d4 | |||
e220f82568 | |||
fe89d6346c | |||
f0ad76fe71 | |||
aec9fcf977 | |||
eea57c28a4 | |||
30c457bb07 | |||
94c2979c93 | |||
f79d9b23d7 | |||
b3959aa68d | |||
b980d48390 | |||
cfec29c68d | |||
a404a7cb08 | |||
cc820576f0 | |||
5d95320d1e | |||
56d4775fed | |||
60602bb7a9 | |||
43646c5e3e | |||
c04c3f0d1d | |||
03e18c9325 | |||
0c62da9a08 | |||
00362e1197 | |||
eea21aaad8 | |||
08b89ece9f | |||
41064a2809 | |||
86251fb5b3 | |||
b56063a183 | |||
65697070f4 | |||
4b4179bd04 | |||
158c738970 | |||
1564bb6899 | |||
3a2fd6d3bb | |||
aff83532dd | |||
![]() |
ec780aa64c | ||
8d3dbc1dea | |||
![]() |
77f10bbe69 | ||
0d0718e9e8 | |||
0338ef7b46 | |||
![]() |
74e72d76b9 | ||
![]() |
7de837851e | ||
25ac2e3a1b | |||
![]() |
29d7a98ec6 | ||
![]() |
f802bda23a | ||
2075f6e227 | |||
144bacc365 | |||
3fee88f2bf | |||
74358ff30d | |||
7bf5ba9d8e | |||
0d6db1c35e | |||
21df7f027d | |||
5f3e62cf71 | |||
4b09f92531 | |||
708ed30f74 | |||
d0710dc9e2 | |||
6154aa93aa | |||
bae35d2ce3 | |||
603c5ffb0c | |||
1757e0e524 | |||
f310a782c4 | |||
03f3d4d8c3 | |||
feb337ba5b | |||
5bd4038d15 | |||
81f69d34f8 | |||
9a9e1b91fd | |||
ef7144c908 | |||
b00e5d8fb3 | |||
23abaae36b | |||
2c9cd04a41 | |||
da31659105 | |||
a840ff12ea | |||
e4d0d98702 | |||
fd319e30e4 | |||
045f57af43 | |||
4ea7d66862 | |||
5735299596 | |||
b63cdf740c | |||
8caf4ece67 | |||
f31e56cb10 | |||
a42eb5ac4a | |||
0028f79073 | |||
9ed01c06a9 | |||
d477733e23 | |||
ae5db88909 | |||
34210fb807 | |||
38824867b5 | |||
36f92bd9a5 | |||
8ed6e6df65 | |||
1dc5dbf547 | |||
37b26a8bfc | |||
4f181981df | |||
b1ac4e9b38 | |||
a281411239 | |||
d3e0e06831 | |||
b71cf092a2 | |||
bacfa95eed | |||
6fb1d394b2 | |||
96566bf29d | |||
46f57dbbb5 | |||
632cc3c276 | |||
3d9c99ae31 | |||
e0ca977ba1 | |||
d2613f1c16 | |||
a874d3b0cc | |||
1abaf50c40 | |||
06eb4a2582 | |||
06f8f8ebe1 | |||
06314eb331 | |||
b3a5b1052b | |||
6cac11467e | |||
80aba21fcd | |||
ae3c7b2656 | |||
45f7f5bc8e | |||
3b2299b51f | |||
ee93cfe5f4 | |||
59159a897a | |||
74b1019a1d | |||
832b58197a | |||
f5cbe0739c | |||
5aff286771 | |||
0a98abcc5f | |||
5cfe19e5b2 | |||
e4102f6c60 | |||
ae10996a7b | |||
30ac9411bf | |||
640b26b2cc | |||
dabdc6e11e | |||
2498693ee7 | |||
faa4dfb3cc | |||
bf91715f8f | |||
da8cc86e3a | |||
8d3cc5239e | |||
66a529cec0 | |||
420c3ed8aa | |||
ff4fc43c36 | |||
781db5caf2 | |||
e3bb0b774d | |||
ce5e499ce1 | |||
76a8c812b2 | |||
8f44941f25 | |||
6ecf44962d | |||
4bdc6c8347 | |||
f40dfeda4d | |||
c2a1e36bda | |||
1542a364eb | |||
b420249a1e | |||
e821a8a104 | |||
bd3660f02e | |||
340c1f15e3 | |||
3ef850c581 | |||
0d84e0c9ad | |||
082cf02461 | |||
290936eaff | |||
d8ad68c2ba | |||
a859e8f253 | |||
c8e1644cd2 | |||
aa531b17e2 | |||
5fce84de25 | |||
564d320c7e | |||
cae65f34e8 | |||
a446216c75 | |||
ca4e7aeb53 | |||
b91f83adb5 | |||
ec3a976337 | |||
0fa3965d6e | |||
abcddce974 | |||
939de032c1 | |||
84fe540a9a | |||
956f823558 | |||
253811a653 | |||
ee88456228 | |||
99c99955d5 | |||
4160041d01 | |||
f450f44088 | |||
a72045154d | |||
e6450ddc6c | |||
5676810436 | |||
0eaafa85ef | |||
661f77afc1 | |||
a8af5a6797 | |||
092a8533be | |||
53686b9c4b | |||
af80b9e2d4 | |||
3627f5f900 | |||
01f5f90c2a | |||
39518a878c | |||
476880c344 | |||
65dae15efb | |||
e8c68bac4b | |||
6d2992cf0b | |||
4a777bc166 | |||
32ca5c81df | |||
45493499e9 | |||
21fdda3335 | |||
1f0f934ec0 | |||
437ec06692 | |||
2c791bef93 | |||
89f39ae9a4 | |||
1460608658 | |||
e8aa547c22 | |||
3d845cc0b7 | |||
d41585e91c | |||
338a0a08c0 | |||
57b5fdfed1 | |||
a12978d028 | |||
72bbad483a | |||
fbb1fe4413 | |||
7fbeb2c15c | |||
04a842a1c8 | |||
d3221f5453 | |||
b6bcf08176 | |||
fb516872e9 | |||
3a7b04f1d3 | |||
53c925d0cc | |||
d89e143cb8 | |||
d7116def5b | |||
9bc165866f | |||
8a33ab3b09 | |||
432fecca49 | |||
76ea69c590 | |||
3e1d00f391 | |||
7f7a042951 | |||
0f5d9e6c8a | |||
ac54db626d | |||
b360e8a70a | |||
0fcf147873 | |||
b31c63989f | |||
6d13a280cd | |||
28792874d4 | |||
8abffce38c | |||
1cc9ad4108 | |||
8099e5893c | |||
644e80d040 | |||
437a01a4c9 | |||
ef50bef040 | |||
361f4ee8e9 | |||
f8880cdf4c | |||
2e7c086158 | |||
dec30e9ad7 | |||
47d01ecea9 | |||
a1c7c5307b | |||
c959706ba4 | |||
62fb71f333 | |||
5fd5cbf774 | |||
8f916dca23 | |||
a1e8ce22c8 | |||
15e1ada00d | |||
70dfec6da6 | |||
a7ca869a16 | |||
ae57fc0271 | |||
f052dcf296 | |||
b5a2a234f2 | |||
8c8238ceb9 | |||
880631418c | |||
fc61c4d320 | |||
deddfc9457 | |||
9568a8c215 | |||
8fe47b6ca7 | |||
5d386d63e2 | |||
94b2266982 | |||
377e165765 | |||
bfb9f99734 | |||
eb1e42295d | |||
48f2322d0c | |||
ef91a31480 | |||
88e3fef444 | |||
7831d5343e | |||
6b8e6e11f9 | |||
a63f5600b7 | |||
d33f38d7e7 | |||
83dc4bc12b | |||
bb783b794a | |||
d1c31ad7a7 | |||
d62af7bc90 | |||
e98b9848fe | |||
a2ca5fbecb | |||
bb673d80d7 | |||
e00dd72ae4 | |||
42b45ba0b7 | |||
712fe28952 | |||
586610ce64 | |||
4cc9da13c5 | |||
0fe6237649 | |||
8b55171ae5 | |||
1277c42256 | |||
22be04e823 | |||
be63e92893 | |||
516f91c8c2 | |||
e5b1f1cc97 | |||
acb9cc0eb0 | |||
d98a322d05 | |||
30a7ce39b4 | |||
248258d71d | |||
ca6dc0f3c0 | |||
e2e73ba7b3 | |||
04ad921dd8 | |||
29c1a023e3 | |||
dc9dd86bba | |||
df88fbf2b8 | |||
96671f03c8 | |||
a2a14be186 | |||
d4c197c737 | |||
69c2d29df7 | |||
ce833a87e3 | |||
78afcfeb60 | |||
1b0d0db770 | |||
27d8cbad48 | |||
e1a891fdc0 | |||
df4575cf2e | |||
83fdeae371 | |||
f11eebe099 | |||
bd3deec2f9 | |||
931ff8c428 | |||
299f3ea184 | |||
6ea1bd5a9d | |||
d7dc4693a2 | |||
3655662ad8 | |||
6a68dea00c | |||
ae7afafe13 | |||
4b6531a015 | |||
4eea30cc6e | |||
33d6bcc013 | |||
4e12b37e33 | |||
1a75e9a77e | |||
39908a29b1 | |||
ddf48abff8 | |||
c145f0cbc7 | |||
dc082e7dc5 | |||
1ca141e3dc | |||
727de55818 | |||
2f84ef4c0e | |||
70e91d3822 | |||
729a502161 | |||
d8115cbf3b | |||
2ebabe38dd | |||
4b1a228078 | |||
9dc442755d | |||
4057e30de7 | |||
05a29fc32e | |||
c1b9b86330 | |||
56bfde1aa5 | |||
0eeb02aa8c | |||
20d31f9a14 | |||
c15bd851ec | |||
67733cbfd2 | |||
fa79259c14 | |||
9563612448 | |||
6249d2584f | |||
cf10a5cf36 | |||
0ce48b54f4 | |||
b54ba9a300 | |||
59461dbba0 | |||
c6684e26f1 | |||
a4224e5178 | |||
5666ec8f1f | |||
ac04d6abd3 | |||
93be363ce2 | |||
e668707738 | |||
61b601c3c4 | |||
f462d5eca5 | |||
000804dd06 | |||
45e2bcfeb6 | |||
0fccf31d00 | |||
e1f72758df | |||
c56ca8d4e2 | |||
af481aec3b | |||
6023c1506d | |||
89518b3333 | |||
c869e1fed7 | |||
ec2c270301 | |||
2c5be00d12 | |||
f6d3c2821d | |||
c6791d78dc | |||
73731c898a | |||
2db2f39649 | |||
5d8cfa9138 | |||
aa9624d62e | |||
71f8117415 | |||
df1fbade2f | |||
6e05c8243e | |||
ceb2758c3e | |||
e7d136268d | |||
a598a58a01 | |||
9628216d0f | |||
e09f0eb9d9 | |||
4f817911cc | |||
aea7a148bc | |||
82423b9112 | |||
01329fe476 | |||
53b6706863 | |||
ac90f10b41 | |||
5bc1e480fa | |||
3f8462301f | |||
826cd54b79 | |||
aeea2a4bad | |||
e076a59eec | |||
6e1f498139 | |||
1b47f20dae | |||
8a36cbfe51 | |||
25016141bb | |||
a3328f8e83 | |||
ef822f0c5b | |||
f22a74210e | |||
70024b0baf | |||
dbac8e1380 | |||
e89e120523 | |||
4d117d1bbf | |||
62d86ee286 | |||
b559e6c92b | |||
be1bbfb2a4 | |||
c235a501b1 | |||
cbaebedd32 | |||
06e16b0e5c | |||
e3f99c3042 | |||
8fb70fa41d | |||
e6e89563ef | |||
e67d59d310 | |||
1f0a904767 | |||
bbb4994422 | |||
f3612ef710 | |||
4ba8bca6c9 | |||
ef97bf61ca | |||
a12a4836b9 | |||
dc9f44f90e | |||
7eb7d7b708 | |||
d5280d34c9 | |||
053d2e3bf9 | |||
9baed62ec9 | |||
cc503e37b9 | |||
fb3b822496 | |||
4d891fd380 | |||
3c9db97ffa | |||
e2acf4baf2 | |||
41ad9afa67 | |||
370420adff | |||
6e9b941c0b | |||
![]() |
165b57f23a | ||
e0fec66989 | |||
216941a389 | |||
3d20218b47 | |||
830da6b46c | |||
fa158fa9ac | |||
b0ac34c86b | |||
307c1edb5d | |||
1f86d5716d | |||
97bcf318c6 | |||
0223a40087 | |||
8264f902b8 | |||
a32a22b239 | |||
b7d3b9c976 | |||
480fe1d05d | |||
28d8c3a8e2 | |||
d400f80172 | |||
9ba57a0b6d | |||
ec60322330 | |||
d2e3cada57 | |||
da2b486b7c | |||
![]() |
d83dbb501e | ||
89129568e2 | |||
4e2d515c9e | |||
2727a198ae | |||
85c44706ae | |||
8e49c83780 | |||
![]() |
92e7416d82 | ||
08aa8cd8f6 | |||
8b184981b6 | |||
6bb29fed18 | |||
80aa4ce207 | |||
932002cf32 | |||
693ee73a82 | |||
67a1ffd4b3 | |||
35e635b3a9 | |||
![]() |
f7bfc31de1 | ||
b3aaae590f | |||
c95da31e37 | |||
feb4d49d63 | |||
f315c7d0e7 | |||
e16c803d87 | |||
4fb198f2d5 | |||
1810041116 | |||
7e958b03fb | |||
b122d1021c | |||
d60b1fc1a5 | |||
2d1c99af56 | |||
7bdc1bc380 | |||
bdb7177091 | |||
0ef623ae25 | |||
7c6cfde7ba | |||
ef18b21598 | |||
302a75485e | |||
7796bf4ce1 | |||
33a62d7f2d | |||
563cbec926 | |||
e152063510 | |||
3d2e964267 | |||
3b5659f124 | |||
9d24461de8 | |||
9a4e1a266a | |||
68dc8bc671 | |||
eed06ba25c | |||
9829b5c3ef | |||
038f419c8a | |||
ca501f7a12 | |||
c7e797e614 | |||
d3a7c38d5c | |||
c28a382295 | |||
7d28a1b93d | |||
6437fc6c05 | |||
e545b34306 | |||
f579ad868f | |||
4df3d2a5b4 | |||
c100727a95 | |||
37d2d84381 | |||
b54e6b0a01 | |||
0b042abfbe | |||
![]() |
a4573dd54a | ||
3ce839ecc9 | |||
4fd30e611d | |||
d94284c968 | |||
faefc3878b | |||
32e5ea4067 | |||
afdebbdc67 | |||
8684e804d3 | |||
149412b1a5 | |||
e18395626a | |||
93a9591cf7 | |||
beea49d5dd | |||
251d28ccc6 | |||
5051a7d2c1 | |||
aba012a20e | |||
8ff113403e | |||
072996863d | |||
e5e6f37e3e | |||
ee1ef94a72 | |||
8d9b4c7840 | |||
b2e8e5b28f | |||
c434e334a9 | |||
2832fe1819 | |||
a69a06dc5e | |||
d9574b3225 | |||
f5a4bbfe54 | |||
00c6e8e3e6 | |||
9d96365c66 | |||
9e129db29d | |||
5bf1c17cf0 | |||
a16b7e9c3a | |||
8dc2aaa35b | |||
aad9c09e96 | |||
e1bb4568d9 | |||
7d76a316b4 | |||
6166a5b0af | |||
d745552827 | |||
ec7f5eba8e | |||
35007a3e6e | |||
2939426a73 | |||
67cfeb5e04 | |||
37186f3cf4 | |||
591b405724 | |||
37cab25dc0 | |||
3fef266c10 | |||
23c601d309 | |||
67fdb0479a | |||
3a87341d26 | |||
9d3e1fa3fb | |||
3c63abbbe2 | |||
a7cc74c80b | |||
a530f62cc0 | |||
4ba34ff106 | |||
5b102c5d63 | |||
df2958c76e | |||
ecbcde55b2 | |||
fca822c569 | |||
592dff8a9e | |||
e63626b873 | |||
d2bb213a42 | |||
181b6b4650 | |||
7544359c5c | |||
74d74886f1 | |||
abf9afe3e8 | |||
e847189720 | |||
4679d5475a | |||
593c5a3313 | |||
1d88096d83 | |||
3909630331 | |||
b1d36d832c | |||
002995b483 | |||
982250df4f | |||
832f5f0a43 | |||
f28d046358 | |||
7b31a67335 | |||
dcad30341b | |||
61828d28f5 | |||
4d34d67ddd | |||
104c0752e3 | |||
08befa2f96 | |||
15066a6706 | |||
96553ee70c | |||
ea3d45e77b | |||
493702da14 | |||
859ff766b4 | |||
0cf8512bb4 | |||
3c680d6f88 | |||
f2c804167a | |||
57764d19ba | |||
6c2c10d307 | |||
c5190266c9 | |||
a77ddbe902 | |||
7d138f1030 | |||
ab8de9ba49 | |||
798dfd62aa | |||
338b56fcf8 | |||
d9f1ec7bfc | |||
409dd40848 | |||
db53a31bcf | |||
37b5d0cf13 | |||
6a6939fa6c | |||
96d30d7beb | |||
e8487da572 | |||
e5dad62c87 | |||
fc71adb56d | |||
1a02b3c0b9 | |||
c16a622aed | |||
e4fc6f7a8f | |||
cabecf6985 | |||
144f23cd8b | |||
532a2f8457 | |||
47f2092705 | |||
31a5be0e6f | |||
57297e28df | |||
52697a198f | |||
a1732e6292 | |||
eb5b405e8e | |||
99a42fe3a7 | |||
adbf04964e | |||
d9a44bedc5 | |||
3991619ad0 | |||
66d0aaf688 | |||
5d1f998cdd | |||
33194101bf | |||
b5f1c75ddc | |||
5f6cb250a1 | |||
fa44a6d370 | |||
001cbfd713 | |||
19382e1f28 | |||
bf95b4d87c | |||
cb3af35de1 | |||
2f8c081a38 | |||
d517ee6ebe | |||
2f6795a70e | |||
7deacdb671 | |||
8360cae3c9 | |||
1428dcd427 | |||
84109ec520 | |||
57b2aed386 | |||
1d9fd6a7f2 | |||
50e99b9fed | |||
15a3f015c7 | |||
5759eb31db | |||
b3024262ca | |||
2b4b3e16b2 | |||
a908aaaa72 | |||
a4eb75e5f5 | |||
8a8e06cd10 | |||
2794463664 | |||
914292f072 | |||
60c7b3d1ca | |||
1a4add15bb | |||
8ea2beab9d | |||
70f50b91c1 | |||
16889fefc9 | |||
154ec9cb70 | |||
e88ed2791d | |||
b68b76e9ec | |||
43af99a59b | |||
ce563e4fea | |||
776dc32431 | |||
8df263fceb | |||
26fe9b47f9 | |||
719decf59a | |||
8e2ccbaa12 | |||
c6e9d87477 | |||
f94cfdcc4c | |||
adcbdb8365 | |||
18d9f9f3e4 | |||
e84ecb049c | |||
d9dcd6480c | |||
b3520df582 | |||
c356669ff5 | |||
6e6041aa88 | |||
ac9335f46e | |||
299077b6f1 | |||
101002e269 | |||
dea7b707f6 | |||
df554384ef | |||
695284c469 | |||
ec4cc2b660 | |||
eab3c6c447 | |||
cc801911ec | |||
27f23e5dbf | |||
c6916cd152 | |||
fd1a1613a5 | |||
f9f4324bce | |||
c81980bd72 | |||
0a1a28f13e | |||
7f8e0c4d90 | |||
890c661782 | |||
56a4be9eec | |||
1c490a3e45 | |||
e70a4743ba | |||
a1d67a3cd9 | |||
501098a858 | |||
a6b48d55d8 | |||
da37a136e1 | |||
c9c5b87302 | |||
ec60e9dce1 | |||
a6bb5e7f4d | |||
83b7841e01 | |||
a220752657 | |||
6e8235346f | |||
ac660c4f04 | |||
8ad2fd8e32 | |||
c26e2030e8 | |||
94aab0a928 | |||
1956cc811f | |||
d0fe3fa473 | |||
ebaa3a0491 | |||
869318e7b2 | |||
99865b5459 | |||
58d94c80bb | |||
b33c98c634 | |||
c0a8cdc167 | |||
02b707e79f | |||
3534665b88 | |||
fc59317d85 | |||
c9a8bbbcf4 | |||
a3b915b34a | |||
1e485f9a46 | |||
f0aeaa6784 | |||
71624742e8 | |||
b76d5b7269 | |||
![]() |
d9477ee60b | ||
![]() |
b7840792b2 | ||
2602e421af | |||
5bdef43436 | |||
931adfcdc5 | |||
0441fad5e4 | |||
![]() |
4e8b1cf68d | ||
![]() |
1f0f42db7d | ||
9f7a0fe1e6 | |||
03c5e3108a | |||
8e58a5bcb8 | |||
0291b619d2 | |||
1197a56ced | |||
e6d0f561b6 | |||
0b7f4873f0 | |||
dae59b423c | |||
b3bc3b6a69 | |||
2b136906f7 | |||
72943d78a9 | |||
cb40e98104 | |||
a107674fb7 | |||
935621186b | |||
eba92ecf12 | |||
cd84800ac9 | |||
8a1c4ab943 | |||
03b074c909 | |||
8811c44c6a | |||
a82c81813b | |||
dad4c73808 | |||
ed8a417851 | |||
a23d14b11a | |||
6c2899868b | |||
4ef21b479e | |||
495083a249 | |||
65edaa6c17 | |||
4df6e70d73 | |||
0b610ba05b | |||
d173c0b5af | |||
6886c29355 | |||
53b2efc9fd | |||
7379a4e87a | |||
f36fa0d148 | |||
b9464d2b43 | |||
857baa7a27 | |||
8dbb121912 | |||
d00650bbb0 | |||
cf79f573e7 | |||
80edcfd1be | |||
7438f45e56 | |||
b131e6c61a | |||
63fb21f3ca | |||
fadc244701 | |||
3283cbc479 | |||
0a1f231ca3 | |||
19d6bb332e | |||
f2766ce969 | |||
44a6325559 | |||
e73f29d130 | |||
dffc592aa1 | |||
bd4f17865d | |||
![]() |
ab94f662b8 | ||
a361139f3c | |||
c8130ce062 | |||
d616744c2b | |||
2dbf032e02 | |||
d92dfd27bd | |||
5af0bee1c6 | |||
54e5ba6e79 | |||
6d7cf18dce | |||
b7726ae301 | |||
5bc8a0b470 | |||
477c368c78 | |||
1590112fba | |||
9db39a4abb | |||
87d36b4437 | |||
2969cf43f3 | |||
7d6b3a8763 | |||
2e0f074e20 | |||
0c1a0a2f06 | |||
3b2a741fdb | |||
b3f1fefedf | |||
f0e799c970 | |||
bd4b8e29c8 | |||
746fb79e7c | |||
5a1f38e7d9 | |||
0cc064db96 | |||
b7582ee7d4 | |||
ff498bbd8d | |||
30db24ab8b | |||
a86ca7b2d0 | |||
d61d524b89 | |||
c71b01e4bb | |||
ec40e9d9eb | |||
b1cfdccc28 | |||
921ceae2fb | |||
e6b0c6f7a1 | |||
8fd40a8fdb | |||
91b13b4bfd | |||
b4ed74a874 | |||
faf74492ef | |||
4548e3a62f | |||
ee6e5d4248 | |||
2c84b1f8fa | |||
1a74b3e936 | |||
2ee0367f96 | |||
faed551a35 | |||
2f031d6a2b | |||
bd15da5f40 | |||
b3b37b37d5 | |||
4ccf56a3d2 | |||
cd621f13c1 | |||
0abc171bf8 | |||
aa7fcaf472 | |||
3f745faa10 | |||
980fa1b4da | |||
6da848f005 | |||
442b740cbb | |||
b293cf553e | |||
d93687ee50 | |||
3a994cf287 | |||
119661a12e | |||
61a4032ac6 | |||
4ae646ba30 | |||
2d3adedc57 | |||
6ccffa64bc | |||
72afbd81ab | |||
6352d73905 | |||
281840b799 | |||
7a551aaa4b | |||
1a404786d6 | |||
6df3a8144c | |||
73d66b7c37 | |||
c2d4cea08a | |||
8d30b1c0bb | |||
7c2269d02d | |||
4f28389ff6 | |||
1095aee85c | |||
73a0cd7bbc | |||
678af1039c | |||
96e501d949 | |||
bb5fb5a908 | |||
4e4a9d80ba | |||
ddfac6f635 | |||
38b0e906a4 | |||
753c180947 | |||
fe97877a95 | |||
97e003f465 | |||
fa23808cba | |||
83c959a14e | |||
8fa1b390e5 | |||
79f31f49e2 | |||
6a7433f0e5 | |||
2864019132 | |||
4b37df12e3 | |||
ee2bde3732 | |||
df6c21da07 | |||
422e209dc3 | |||
d784aec625 | |||
2f77add671 | |||
c33ddf4795 | |||
40d48142b6 | |||
d582280b0a | |||
6e08e29b54 | |||
1545b142fd | |||
c8ca9c7c63 | |||
6f5e22631c | |||
883ec3c0f2 | |||
9e2bc71dff | |||
ec75142f96 | |||
3edc006f07 | |||
ca064bcc17 | |||
e1d3530226 | |||
80e3d06108 | |||
87c3467930 | |||
45ceab38a6 | |||
b50bfeccf8 | |||
1bc212f7f8 | |||
086c51d70c | |||
b1550871e7 | |||
617b6df05a | |||
efe0a13e06 | |||
a564821a6a | |||
356d3b1670 | |||
18ec7a9329 | |||
9860966b10 | |||
5ecd91626a | |||
92febcf848 | |||
0915eeb700 | |||
ae77de1a80 | |||
9eb655b0a1 | |||
0f6111bbea | |||
0adc958bc2 | |||
af6cc2fcf3 | |||
f0fd9ed204 | |||
fda4e3b889 | |||
1da4185842 | |||
cf184b384e | |||
860f79496a | |||
82f59f190b | |||
2473f3cf3e | |||
735ba5c7c2 | |||
f000c676d9 | |||
774cee0d0c | |||
7130dfa0b5 | |||
793d158479 | |||
be89a05922 | |||
096553967d | |||
e5eb0509fa | |||
5859d830b0 | |||
9ff9b4ddd7 | |||
7f7ab6d62e | |||
e92db537fa | |||
3fda66455c | |||
0d62c5cccc | |||
12758d813d | |||
2edcda85e8 | |||
6283d157ce | |||
62e4fa032d | |||
df16437a34 | |||
48f9ff3255 | |||
8144a4dc2a | |||
e7380dd981 | |||
405bd641f3 | |||
2bb2b168f8 | |||
68cc665d54 | |||
f4507d9a1a | |||
73ebb10b1e | |||
8215d26059 | |||
c843dd8ac9 | |||
94b7c4b4a1 | |||
4d8bf2ccd1 | |||
45c782207f | |||
f3e0b8bf58 | |||
96df24975d | |||
be829ce488 | |||
7c14a9735a | |||
9b8b7831fe | |||
e460316ede | |||
b15547d281 | |||
d86c6db791 | |||
93e32aa8a0 | |||
5b0a86f019 | |||
4d1f2256fc | |||
1ab91f08ba | |||
51f24bbc48 | |||
bd25fad239 | |||
529f957b87 | |||
481ac90d2c | |||
94e00335f7 | |||
d1c8339de2 | |||
![]() |
77d53af10f | ||
f75b554fe3 | |||
f5573b92f1 | |||
f95632b30a | |||
52d581c4b5 | |||
4cfa425690 | |||
9172b1d43c | |||
f508ad19b3 | |||
9a1c8c3eb7 | |||
cbd8d485de | |||
948cffed88 | |||
![]() |
fba8c1251b | ||
2eccc6c00a | |||
7a76758128 | |||
![]() |
9e3aacbb8d | ||
![]() |
c9b96e1312 | ||
![]() |
09d6ad4bce | ||
![]() |
09fc9c50ee | ||
2f9b12de83 | |||
85f3ab8503 | |||
00aea9d1c9 | |||
![]() |
01f43866c7 | ||
![]() |
351809f085 | ||
![]() |
ecf3d4d888 | ||
![]() |
87fd091e09 | ||
2fb38a05f9 | |||
1ce9dae8b8 | |||
![]() |
b825c83e3a | ||
![]() |
cf36511cc5 | ||
![]() |
d48225bfe6 | ||
![]() |
cb16cee60e | ||
![]() |
8d084c3c2d | ||
![]() |
80df68adf5 | ||
![]() |
4156fac09a | ||
![]() |
7def4f0f3f | ||
![]() |
05ce53dcc8 | ||
![]() |
6127d47aee | ||
![]() |
9207059fce | ||
![]() |
c936ec4401 | ||
![]() |
6cf4b75d5f | ||
a17a4ebfec | |||
![]() |
19524faa67 | ||
![]() |
baf9763256 | ||
![]() |
4121f60275 | ||
![]() |
42ddaeab2f | ||
![]() |
b3a0cb60e4 | ||
![]() |
aa2e020629 | ||
![]() |
eceea605ad | ||
![]() |
0ef5509ccf | ||
![]() |
bc93ec6fa0 | ||
![]() |
64e1de9a3e | ||
![]() |
3b6e9b4ea0 | ||
![]() |
04c9cb0062 | ||
![]() |
d823900ef4 | ||
![]() |
1d4cd0087e | ||
![]() |
3625742900 | ||
![]() |
b31a217baf | ||
![]() |
06bffb9218 | ||
![]() |
40f562ae7a | ||
![]() |
15da224680 | ||
![]() |
c07994d42b | ||
![]() |
0cd92ae347 | ||
![]() |
805fe37ec8 | ||
![]() |
7bf0bd877c | ||
![]() |
a350a17b69 | ||
![]() |
5ddc851aad | ||
![]() |
0f3eea8b43 | ||
![]() |
48c9e77cea | ||
![]() |
511204504c | ||
![]() |
d131489b19 | ||
![]() |
98c3461152 | ||
73e782e684 | |||
6509bb8290 | |||
98683cc779 | |||
![]() |
ae91a34c5a | ||
![]() |
0d9931c1fb | ||
![]() |
3a42c0aff2 | ||
![]() |
39d8d94a7a | ||
![]() |
66f7ec1b72 | ||
![]() |
3ad6a45ec6 | ||
![]() |
132dc7c758 | ||
![]() |
90037da808 | ||
![]() |
18b14bf393 | ||
![]() |
9855e122db | ||
![]() |
bb3b898dc7 | ||
![]() |
5f3c3e4b36 | ||
![]() |
24bc1861ab | ||
![]() |
80758f7259 |
2
LICENSE
2
LICENSE
@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2020 码神
|
||||
Copyright (c) 2017-2025 shylinux
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -1,3 +1,3 @@
|
||||
# icebergs
|
||||
|
||||
icebergs 是一个应用框架,通过模块化、集群化、自动化方式,在各种设备上,一键部署完整的个人云计算与云研发平台。
|
||||
icebergs 是一个后端框架,通过集群化、模块化、自动化方式,在各种设备上,即可一键启动完整的云计算服务与云研发环境。
|
||||
|
@ -3,10 +3,14 @@ package aaa
|
||||
import ice "shylinux.com/x/icebergs"
|
||||
|
||||
const (
|
||||
RSA = "rsa"
|
||||
RSA = "rsa"
|
||||
SIGN = "sign"
|
||||
CERT = "cert"
|
||||
VERIFY = "verify"
|
||||
BASE64 = "base64"
|
||||
)
|
||||
const AAA = "aaa"
|
||||
|
||||
var Index = &ice.Context{Name: AAA, Help: "认证模块"}
|
||||
|
||||
func init() { ice.Index.Register(Index, nil, ROLE, SESS, TOTP, USER, OFFER, EMAIL, RSA) }
|
||||
func init() { ice.Index.Register(Index, nil, APPLY, OFFER, EMAIL, USER, TOTP, SESS, ROLE, CERT, RSA) }
|
||||
|
@ -2,38 +2,76 @@ package aaa
|
||||
|
||||
import (
|
||||
"net/smtp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
ice "shylinux.com/x/icebergs"
|
||||
"shylinux.com/x/icebergs/base/mdb"
|
||||
"shylinux.com/x/icebergs/base/web/html"
|
||||
kit "shylinux.com/x/toolkits"
|
||||
)
|
||||
|
||||
const (
|
||||
SEND = "send"
|
||||
ADMIN = "admin"
|
||||
SEND = "send"
|
||||
DATE = "date"
|
||||
FROM = "from"
|
||||
TO = "to"
|
||||
CC = "cc"
|
||||
SUBJECT = "subject"
|
||||
CONTENT = "content"
|
||||
)
|
||||
const EMAIL = "email"
|
||||
|
||||
func init() {
|
||||
const (
|
||||
TO = "to"
|
||||
ADMIN = "admin"
|
||||
SUBJECT = "subject"
|
||||
CONTENT = "content"
|
||||
SERVICE = "service"
|
||||
NL = "\r\n"
|
||||
DF = ": "
|
||||
)
|
||||
Index.MergeCommands(ice.Commands{
|
||||
EMAIL: {Name: "email name auto create", Help: "邮件", Actions: ice.MergeActions(ice.Actions{
|
||||
SEND: {Name: "send to*='shylinux@163.com' subject*=hi content*:textarea=hello", Help: "发送", Hand: func(m *ice.Message, arg ...string) {
|
||||
if m.Option(SERVICE) == "" {
|
||||
m.Options(m.Cmd("", ADMIN).AppendSimple(SERVICE, USERNAME, PASSWORD))
|
||||
EMAIL: {Help: "邮件", Actions: ice.MergeActions(ice.Actions{
|
||||
mdb.CREATE: {Name: "create name*=admin service*='smtp.163.com:25' username* password*"},
|
||||
SEND: {Name: "send from=admin to*='shy@shylinux.com' cc subject*=hi content*:textarea=hello", Help: "发送", Icon: "bi bi-send-plus", Hand: func(m *ice.Message, arg ...string) {
|
||||
msg := mdb.HashSelects(m.Spawn(), m.OptionDefault(FROM, ADMIN))
|
||||
if m.WarnNotFound(msg.Append(SERVICE) == "", m.Option(FROM)) {
|
||||
return
|
||||
}
|
||||
m.ToastProcess()
|
||||
content := []byte(kit.JoinKV(DF, NL, kit.Simple(FROM, msg.Append(USERNAME), m.OptionSimple(TO, CC, SUBJECT), DATE, time.Now().Format(time.RFC1123Z), html.ContentType, "text/html; charset=UTF-8")...) + NL + NL + m.Option(CONTENT))
|
||||
auth := smtp.PlainAuth("", msg.Append(USERNAME), msg.Append(PASSWORD), kit.Split(msg.Append(SERVICE), ice.DF)[0])
|
||||
m.Logs(EMAIL, SEND, string(content))
|
||||
if !m.WarnNotValid(smtp.SendMail(msg.Append(SERVICE), auth, msg.Append(USERNAME), kit.Split(m.Option(TO)), content)) {
|
||||
m.ToastSuccess()
|
||||
}
|
||||
content := []byte(kit.JoinKV(DF, NL, "From", m.Option(USERNAME), "To", m.Option(TO), "Subject", m.Option(SUBJECT), "Content-Type", "text/html; charset=UTF-8") + NL + NL + m.Option(CONTENT))
|
||||
auth := smtp.PlainAuth("", m.Option(USERNAME), m.Option(PASSWORD), kit.Split(m.Option(SERVICE), ice.DF)[0])
|
||||
m.Warn(smtp.SendMail(m.Option(SERVICE), auth, m.Option(USERNAME), kit.Split(m.Option(TO)), content))
|
||||
m.Logs(mdb.EXPORT, EMAIL, string(content))
|
||||
}},
|
||||
}, mdb.HashAction(mdb.SHORT, mdb.NAME, mdb.FIELD, "time,name,service,username,password", ice.ACTION, SEND))},
|
||||
}, mdb.DevDataAction("name,service,username,password"), mdb.HashAction(mdb.SHORT, mdb.NAME, mdb.FIELD, "time,name,service,username", ice.ACTION, SEND)), Hand: func(m *ice.Message, arg ...string) {
|
||||
if mdb.HashSelect(m, arg...); len(arg) == 0 && m.Length() == 0 {
|
||||
m.EchoInfoButton(m.Trans("please add admin email", "请配置管理员邮箱"), mdb.CREATE, mdb.DEV_REQUEST)
|
||||
} else if len(arg) == 0 {
|
||||
m.Action(mdb.CREATE, mdb.DEV_REQUEST)
|
||||
}
|
||||
}},
|
||||
})
|
||||
ice.Info.Inputs = append(ice.Info.Inputs, func(m *ice.Message, arg ...string) {
|
||||
switch kit.TrimPrefix(arg[0], "extra.") {
|
||||
case TO:
|
||||
if m.Option(ice.ACTION) != EMAIL {
|
||||
break
|
||||
}
|
||||
fallthrough
|
||||
case EMAIL:
|
||||
m.Push(arg[0], "shy@shylinux.com", "shylinux@163.com")
|
||||
case PASSWORD:
|
||||
m.SetAppend()
|
||||
}
|
||||
})
|
||||
}
|
||||
func SendEmail(m *ice.Message, from, to, cc string, arg ...string) {
|
||||
m.Option(ice.MSG_USERHOST, strings.Split(m.Option(ice.MSG_USERHOST), "://")[1])
|
||||
m.Cmdy(EMAIL, SEND, kit.Select(mdb.Config(m, EMAIL), from), kit.Select(m.Option(EMAIL), to), cc,
|
||||
strings.TrimSpace(kit.Select(ice.Render(m, ice.RENDER_TEMPLATE, SUBJECT_HTML), arg, 0)),
|
||||
kit.Select(ice.Render(m, ice.RENDER_TEMPLATE, CONTENT_HTML), arg, 1),
|
||||
)
|
||||
}
|
||||
|
@ -1,45 +1,71 @@
|
||||
package aaa
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
ice "shylinux.com/x/icebergs"
|
||||
"shylinux.com/x/icebergs/base/gdb"
|
||||
"shylinux.com/x/icebergs/base/mdb"
|
||||
"shylinux.com/x/icebergs/base/web/html"
|
||||
kit "shylinux.com/x/toolkits"
|
||||
)
|
||||
|
||||
func _offer_create(m *ice.Message, arg ...string) {
|
||||
h := mdb.HashCreate(m.Spawn(), FROM, m.Option(ice.MSG_USERNAME), mdb.STATUS, INVITE, m.OptionSimple(EMAIL, SUBJECT, CONTENT))
|
||||
SendEmail(m.Options("link", m.Cmdx("host", "publish", m.MergePodCmd("", "", mdb.HASH, h))), m.Option(FROM), "", "")
|
||||
gdb.Event(m, OFFER_CREATE, mdb.HASH, h, EMAIL, m.Option(EMAIL))
|
||||
}
|
||||
func _offer_accept(m *ice.Message, arg ...string) {
|
||||
msg := mdb.HashSelect(m.Spawn(), m.Option(mdb.HASH))
|
||||
if ls := kit.Split(msg.Append(EMAIL), mdb.AT); !m.WarnNotFound(msg.Length() == 0 || len(ls) < 2, m.Option(mdb.HASH)) {
|
||||
m.Spawn().AdminCmd(USER, mdb.CREATE, USERROLE, VOID, USERNAME, msg.Append(EMAIL), USERNICK, ls[0], USERZONE, ls[1])
|
||||
mdb.HashModify(m, m.OptionSimple(mdb.HASH), mdb.STATUS, ACCEPT)
|
||||
gdb.Event(m, OFFER_ACCEPT, mdb.HASH, m.Option(mdb.HASH), EMAIL, msg.Append(EMAIL))
|
||||
m.ProcessLocation(m.MergePod("", ice.MSG_SESSID, SessValid(m.Options(ice.MSG_USERNAME, msg.Append(EMAIL)))))
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
INVITE = "invite"
|
||||
ACCEPT = "accept"
|
||||
INVITE = "invite"
|
||||
ACCEPT = "accept"
|
||||
SUBJECT_HTML = "subject.html"
|
||||
CONTENT_HTML = "content.html"
|
||||
|
||||
OFFER_CREATE = "offer.create"
|
||||
OFFER_ACCEPT = "offer.accept"
|
||||
)
|
||||
const APPLY = "apply"
|
||||
const OFFER = "offer"
|
||||
|
||||
func init() {
|
||||
Index.MergeCommands(ice.Commands{
|
||||
OFFER: {Name: "offer hash auto", Help: "邀请", Actions: ice.MergeActions(ice.Actions{
|
||||
INVITE: {Name: "invite email*='shylinux@163.com' content", Help: "邀请", Hand: func(m *ice.Message, arg ...string) {
|
||||
h := mdb.HashCreate(m, m.OptionSimple(EMAIL, "content"), "from", m.Option(ice.MSG_USERNAME), mdb.STATUS, INVITE)
|
||||
msg := m.Cmd("web.share", mdb.CREATE, mdb.TYPE, "field", mdb.NAME, m.PrefixKey(), mdb.TEXT, kit.Format(kit.List(h)),
|
||||
kit.Dict(ice.MSG_USERNAME, m.Option(EMAIL), ice.MSG_USERNICK, VOID, ice.MSG_USERROLE, VOID))
|
||||
m.Cmd(EMAIL, SEND, m.Option(EMAIL), "welcome to contents, please continue", ice.Render(m, ice.RENDER_ANCHOR, msg.Option(mdb.LINK)))
|
||||
OFFER: {Help: "邀请", Role: VOID, Meta: kit.Dict(
|
||||
ice.CTX_TRANS, kit.Dict(html.INPUT, kit.Dict("from", "发自")),
|
||||
), Actions: ice.MergeActions(ice.Actions{
|
||||
mdb.CREATE: {Name: "create from*=admin email*='shy@shylinux.com' subject content", Help: "邀请", Hand: func(m *ice.Message, arg ...string) {
|
||||
_offer_create(m, arg...)
|
||||
}},
|
||||
ACCEPT: {Help: "接受", Hand: func(m *ice.Message, arg ...string) {
|
||||
if m.Warn(m.Option(mdb.HASH) == "", ice.ErrNotValid, mdb.HASH) {
|
||||
return
|
||||
ACCEPT: {Help: "接受", Role: VOID, Hand: func(m *ice.Message, arg ...string) {
|
||||
if !m.WarnNotValid(m.Option(mdb.HASH), mdb.HASH) {
|
||||
_offer_accept(m, arg...)
|
||||
}
|
||||
msg := m.Cmd("", m.Option(mdb.HASH))
|
||||
ls := kit.Split(msg.Option(EMAIL), ice.AT)
|
||||
m.Cmd(USER, mdb.CREATE, USERNAME, msg.Option(EMAIL), USERNICK, ls[0], USERZONE, ls[1])
|
||||
m.ProcessOpen(kit.MergeURL2(m.Option(ice.MSG_USERWEB), ice.PS, ice.MSG_SESSID, SessCreate(m, msg.Option(EMAIL))))
|
||||
mdb.HashModify(m, m.OptionSimple(mdb.HASH), mdb.STATUS, ACCEPT)
|
||||
}},
|
||||
}, mdb.HashAction(mdb.SHORT, mdb.UNIQ, mdb.FIELD, "time,hash,status,from,email,content"), RoleAction(ACCEPT)), Hand: func(m *ice.Message, arg ...string) {
|
||||
if len(arg) == 0 && m.Option(ice.MSG_USERROLE) == VOID {
|
||||
}, mdb.ImportantHashAction(
|
||||
mdb.SHORT, mdb.UNIQ, mdb.FIELD, "time,hash,from,status,email,subject,content"), EMAIL, ADMIN,
|
||||
), Hand: func(m *ice.Message, arg ...string) {
|
||||
if m.WarnNotRight(len(arg) == 0 && !IsTechOrRoot(m)) {
|
||||
return
|
||||
}
|
||||
if mdb.HashSelect(m, arg...); len(arg) == 0 {
|
||||
m.Action(INVITE)
|
||||
} else {
|
||||
m.PushAction(ACCEPT)
|
||||
} else if mdb.HashSelect(m, arg...).FieldsIsDetail() {
|
||||
if m.Option(ice.MSG_USERNAME) == "" {
|
||||
m.Option(ice.MSG_USERHOST, strings.Split(m.Option(ice.MSG_USERHOST), "://")[1])
|
||||
m.SetAppend().EchoInfoButton(m.Template(SUBJECT_HTML), ACCEPT)
|
||||
} else if strings.Contains(m.Option(ice.MSG_USERWEB), "/c/offer") {
|
||||
m.ProcessLocation(m.MergePod(""))
|
||||
}
|
||||
}
|
||||
}},
|
||||
})
|
||||
}
|
||||
func OfferAction() ice.Actions {
|
||||
return gdb.EventsAction(OFFER_CREATE, OFFER_ACCEPT, USER_CREATE, USER_REMOVE)
|
||||
}
|
||||
|
124
base/aaa/portal/apply.go
Normal file
124
base/aaa/portal/apply.go
Normal file
@ -0,0 +1,124 @@
|
||||
package portal
|
||||
|
||||
import (
|
||||
"shylinux.com/x/ice"
|
||||
"shylinux.com/x/icebergs/base/aaa"
|
||||
"shylinux.com/x/icebergs/base/cli"
|
||||
"shylinux.com/x/icebergs/base/ctx"
|
||||
"shylinux.com/x/icebergs/base/mdb"
|
||||
"shylinux.com/x/icebergs/base/nfs"
|
||||
"shylinux.com/x/icebergs/base/web"
|
||||
kit "shylinux.com/x/toolkits"
|
||||
)
|
||||
|
||||
type apply struct {
|
||||
ice.Hash
|
||||
email string `data:"admin"`
|
||||
checkbox string `data:"true"`
|
||||
online string `data:"true"`
|
||||
field string `data:"time,hash,status,email,userrole,username,usernick,icons,agent,system,ip,ua"`
|
||||
apply string `name:"apply" help:"申请" role:"void"`
|
||||
agree string `name:"agree userrole=tech,void" help:"同意" icon:"bi bi-check2-square"`
|
||||
login string `name:"login" help:"登录" role:"void"`
|
||||
list string `name:"list hash auto sso" help:"注册"`
|
||||
}
|
||||
|
||||
func (s apply) Sso(m *ice.Message, arg ...string) {
|
||||
m.AddHeaderLogin(cli.QRCODE, cli.QRCODE, "扫码登录", "10")
|
||||
m.AddHeaderLogin(mdb.PLUGIN, aaa.EMAIL, "邮箱登录", "20", ctx.INDEX, m.ShortKey(), ctx.ARGS, kit.FuncName(s.Login))
|
||||
m.AddHeaderLogin(mdb.PLUGIN, aaa.APPLY, "注册用户", "30", ctx.INDEX, m.ShortKey(), ctx.ARGS, kit.FuncName(s.Apply))
|
||||
}
|
||||
func (s apply) Apply(m *ice.Message, arg ...string) {
|
||||
if m.IsGetMethod() {
|
||||
if k := _cookie_key(m); m.Option(k) == "" || s.List(m, m.Option(k)).Length() == 0 && m.Result() == "" {
|
||||
m.DisplayForm(m, "email*", aaa.USERNICK, s.Apply)
|
||||
}
|
||||
} else if !m.WarnAlreadyExists(m.Options(arg).Cmd(aaa.USER, m.Option(aaa.EMAIL)).Length() > 0, m.Option(aaa.EMAIL)) {
|
||||
m.Options(ice.MSG_USERNAME, m.Option(aaa.EMAIL), ice.MSG_USERNICK, kit.Split(m.Option(aaa.EMAIL), "@")[0])
|
||||
h := s.Hash.Create(m, kit.Simple(arg, mdb.STATUS, kit.FuncName(s.Apply), web.ParseUA(m.Message))...)
|
||||
m.ProcessCookie(_cookie_key(m), h)
|
||||
m.StreamPushRefreshConfirm()
|
||||
m.ChatMessageInsertPlug(aaa.APPLY, "user.signup", "", m.PrefixKey(), h)
|
||||
}
|
||||
}
|
||||
func (s apply) Agree(m *ice.Message, arg ...string) {
|
||||
if m.WarnNotValid(m.Option(mdb.HASH) == "", mdb.HASH) {
|
||||
return
|
||||
}
|
||||
msg := s.Hash.List(m.Spawn(), m.Option(mdb.HASH))
|
||||
if m.WarnNotFound(msg.Length() == 0, m.Option(mdb.HASH)) {
|
||||
return
|
||||
}
|
||||
s.Hash.Modify(m, kit.Simple(m.OptionSimple(mdb.HASH, aaa.USERROLE), mdb.STATUS, s.Agree)...)
|
||||
// m.UserCreate(m.Option(aaa.USERROLE), msg.Append(aaa.USERNAME), msg.Append(aaa.USERNICK))
|
||||
m.PushRefresh(msg.Append(cli.DAEMON))
|
||||
}
|
||||
func (s apply) Login(m *ice.Message, arg ...string) {
|
||||
kit.If(m.Option(mdb.HASH) == kit.FuncName(s.Apply), func() { m.Options(mdb.HASH, "") })
|
||||
if m.IsGetMethod() {
|
||||
m.DisplayForm("email*", s.Login)
|
||||
} else if m.Options(arg).Option(aaa.EMAIL) == "" {
|
||||
if m.WarnNotValid(m.OptionDefault(mdb.HASH, m.Option(_cookie_key(m))) == "", mdb.HASH) {
|
||||
m.ProcessCookie(_cookie_key(m), "")
|
||||
return
|
||||
}
|
||||
msg := s.Hash.List(m.Spawn(), m.Option(mdb.HASH))
|
||||
if m.WarnNotFound(msg.Length() == 0, m.Option(mdb.HASH)) {
|
||||
m.ProcessCookie(_cookie_key(m), "")
|
||||
return
|
||||
}
|
||||
m.UserCreate(m.Option(aaa.USERROLE), msg.Append(aaa.USERNAME), msg.Append(aaa.USERNICK))
|
||||
web.RenderCookie(m.Message, m.Cmdx(aaa.SESS, mdb.CREATE, msg.Append(aaa.USERNAME)))
|
||||
s.Hash.Modify(m, kit.Simple(m.OptionSimple(mdb.HASH), mdb.STATUS, s.Login)...)
|
||||
m.ProcessLocation(nfs.PS)
|
||||
m.StreamPushRefreshConfirm()
|
||||
} else {
|
||||
if m.WarnNotFound(m.Cmd(aaa.USER, m.Option(aaa.EMAIL)).Length() == 0, m.Option(aaa.EMAIL)) {
|
||||
return
|
||||
}
|
||||
m.Options(ice.MSG_USERNAME, m.Option(aaa.EMAIL))
|
||||
space := kit.Keys(kit.Slice(kit.Split(m.Option(ice.MSG_DAEMON), nfs.PT), 0, -1))
|
||||
share := m.Cmd(web.SHARE, mdb.CREATE, mdb.TYPE, web.FIELD, mdb.NAME, web.CHAT_GRANT, mdb.TEXT, space, web.SPACE, ice.OPS).Append(mdb.LINK)
|
||||
m.Options(web.LINK, share).SendEmail("", "", "")
|
||||
// m.ProcessHold(m.Trans("please auth login in mailbox", "请注意查收邮件"))
|
||||
m.Echo(m.Trans("please auth login in mailbox", "请注意查收邮件"))
|
||||
m.ProcessInner()
|
||||
}
|
||||
}
|
||||
func (s apply) List(m *ice.Message, arg ...string) *ice.Message {
|
||||
kit.If(m.Option(_cookie_key(m)), func(p string) { arg = []string{p} })
|
||||
kit.If(!m.IsTech(), func() { m.Option(ice.MSG_ONLINE, ice.FALSE) })
|
||||
if m.IsTech() || (len(arg) > 0 && arg[0] != "") {
|
||||
s.Hash.List(m, arg...).Table(func(value ice.Maps) {
|
||||
switch value[mdb.STATUS] {
|
||||
case kit.FuncName(s.Apply):
|
||||
m.PushButton(s.Agree, s.Remove)
|
||||
case kit.FuncName(s.Agree):
|
||||
m.PushButton(s.Login, s.Remove)
|
||||
default:
|
||||
m.PushButton(s.Remove)
|
||||
}
|
||||
})
|
||||
}
|
||||
if m.Option(_cookie_key(m)) != "" || m.ActionKey() != "" {
|
||||
switch m.Append(mdb.STATUS) {
|
||||
case kit.FuncName(s.Login):
|
||||
if m.ActionKey() == kit.FuncName(s.Apply) {
|
||||
m.ProcessCookie(_cookie_key(m), "")
|
||||
} else {
|
||||
m.SetAppend().ProcessLocation(nfs.PS)
|
||||
}
|
||||
case kit.FuncName(s.Agree):
|
||||
m.SetAppend().EchoInfoButton(m.Trans("please login", "请登录"), s.Login)
|
||||
case kit.FuncName(s.Apply):
|
||||
m.SetAppend().EchoInfoButton(m.Trans("please wait admin agree", "请等待管理员同意"), nil)
|
||||
}
|
||||
} else if len(arg) == 0 {
|
||||
m.EchoQRCode(m.MergePodCmd("", "", ctx.ACTION, s.Apply))
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
func init() { ice.Cmd("aaa.apply", apply{}) }
|
||||
|
||||
func _cookie_key(m *ice.Message) string { return kit.Keys(m.PrefixKey(), mdb.HASH) }
|
77
base/aaa/portal/asign.go
Normal file
77
base/aaa/portal/asign.go
Normal file
@ -0,0 +1,77 @@
|
||||
package portal
|
||||
|
||||
import (
|
||||
"shylinux.com/x/ice"
|
||||
"shylinux.com/x/icebergs/base/aaa"
|
||||
"shylinux.com/x/icebergs/base/ctx"
|
||||
"shylinux.com/x/icebergs/base/mdb"
|
||||
kit "shylinux.com/x/toolkits"
|
||||
)
|
||||
|
||||
type asign struct {
|
||||
ice.Hash
|
||||
export string `data:"true"`
|
||||
short string `data:"role"`
|
||||
field string `data:"time,role"`
|
||||
shorts string `data:"index"`
|
||||
fields string `data:"time,index,operate"`
|
||||
insert string `name:"insert index"`
|
||||
deploy string `name:"deploy" help:"部署"`
|
||||
list string `name:"list role auto" help:"分配"`
|
||||
confer string `name:"confer username" help:"授权"`
|
||||
}
|
||||
|
||||
func (s asign) Inputs(m *ice.Message, arg ...string) {
|
||||
if arg[0] == "operate" {
|
||||
m.Search(m.Option(ctx.INDEX), func(key string, cmd *ice.Command) {
|
||||
for sub, action := range cmd.Actions {
|
||||
if kit.HasPrefix(sub, "_", "/") {
|
||||
continue
|
||||
}
|
||||
m.Push(arg[0], sub)
|
||||
m.Push(mdb.NAME, action.Name)
|
||||
m.Push(mdb.HELP, action.Help)
|
||||
}
|
||||
m.Sort(arg[0])
|
||||
m.Option(ice.TABLE_CHECKBOX, ice.TRUE)
|
||||
})
|
||||
} else if arg[0] == aaa.USERNAME {
|
||||
m.Cmdy(aaa.USER).Cut(aaa.USERNAME, aaa.USERNICK, aaa.USERROLE)
|
||||
} else {
|
||||
s.Hash.Inputs(m, arg...)
|
||||
}
|
||||
}
|
||||
func (s asign) Modify(m *ice.Message, arg ...string) {
|
||||
if m.Option(ctx.INDEX) != "" {
|
||||
s.Update(m, arg...)
|
||||
} else {
|
||||
s.Modify(m, arg...)
|
||||
}
|
||||
}
|
||||
func (s asign) Deploy(m *ice.Message, arg ...string) {
|
||||
defer m.ToastProcess()()
|
||||
s.List(m.Spawn()).Table(func(val ice.Maps) {
|
||||
m.Cmd(aaa.ROLE, mdb.REMOVE, val[aaa.ROLE])
|
||||
m.Cmd(aaa.ROLE, mdb.CREATE, val[aaa.ROLE])
|
||||
s.List(m.Spawn(), val[aaa.ROLE]).Table(func(value ice.Maps) {
|
||||
m.Cmd(aaa.ROLE, aaa.WHITE, val[aaa.ROLE], value[ctx.INDEX])
|
||||
m.Cmd(aaa.ROLE, aaa.BLACK, val[aaa.ROLE], value[ctx.INDEX], ctx.ACTION)
|
||||
kit.For(kit.Split(value["operate"]), func(p string) {
|
||||
m.Cmd(aaa.ROLE, aaa.WHITE, val[aaa.ROLE], value[ctx.INDEX], ctx.ACTION, p)
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
func (s asign) List(m *ice.Message, arg ...string) *ice.Message {
|
||||
if len(arg) == 0 {
|
||||
s.Hash.List(m, arg...).Action(s.Create, s.Deploy).PushAction(s.Confer, s.Remove)
|
||||
} else {
|
||||
s.Hash.SubList(m, arg[0], arg[1:]...).Action(s.Insert, s.Deploy).PushAction(s.Delete)
|
||||
}
|
||||
return m
|
||||
}
|
||||
func (s asign) Confer(m *ice.Message, arg ...string) {
|
||||
m.Cmd(aaa.USER, mdb.MODIFY, aaa.USERNAME, m.Option(aaa.USERNAME), aaa.USERROLE, m.Option(aaa.ROLE))
|
||||
}
|
||||
|
||||
func init() { ice.Cmd("aaa.asign", asign{}) }
|
179
base/aaa/role.go
179
base/aaa/role.go
@ -11,10 +11,15 @@ import (
|
||||
)
|
||||
|
||||
func _role_keys(key ...string) string {
|
||||
return strings.TrimPrefix(strings.TrimSuffix(strings.ReplaceAll(path.Join(strings.ReplaceAll(kit.Keys(key), ice.PT, ice.PS)), ice.PS, ice.PT), ice.PT), ice.PT)
|
||||
if _key := kit.Select("", strings.Split(key[0], ice.PT), -1); _key != "" {
|
||||
if c, ok := ice.Info.Index[_key].(*ice.Context); ok && kit.Keys(c.Prefix(), _key) == key[0] {
|
||||
key[0] = _key
|
||||
}
|
||||
}
|
||||
return strings.TrimPrefix(strings.TrimPrefix(strings.TrimSuffix(strings.ReplaceAll(path.Join(strings.ReplaceAll(kit.Keys(key), ice.PT, ice.PS)), ice.PS, ice.PT), ice.PT), ice.PT), "web.")
|
||||
}
|
||||
func _role_set(m *ice.Message, role, zone, key string, status bool) {
|
||||
m.Logs(mdb.INSERT, mdb.KEY, "aaa.role", ROLE, role, zone, key)
|
||||
m.Logs(mdb.INSERT, mdb.KEY, ROLE, ROLE, role, zone, key)
|
||||
mdb.HashSelectUpdate(m, role, func(value ice.Map) { value[zone].(ice.Map)[key] = status })
|
||||
}
|
||||
func _role_white(m *ice.Message, role, key string) { _role_set(m, role, WHITE, key, true) }
|
||||
@ -22,40 +27,28 @@ func _role_black(m *ice.Message, role, key string) { _role_set(m, role, BLACK, k
|
||||
func _role_check(value ice.Map, key []string, ok bool) bool {
|
||||
white, black := value[WHITE].(ice.Map), value[BLACK].(ice.Map)
|
||||
for i := 0; i < len(key); i++ {
|
||||
if v, o := white[kit.Join(key[:i+1], ice.PT)]; o && v == true {
|
||||
ok = true
|
||||
}
|
||||
if v, o := black[kit.Join(key[:i+1], ice.PT)]; o && v == true {
|
||||
ok = false
|
||||
}
|
||||
kit.If(white[kit.Join(key[:i+1], ice.PT)], func() { ok = true })
|
||||
kit.If(black[kit.Join(key[:i+1], ice.PT)], func() { ok = false })
|
||||
}
|
||||
return ok
|
||||
}
|
||||
func _role_right(m *ice.Message, role string, key ...string) (ok bool) {
|
||||
if role == ROOT {
|
||||
return true
|
||||
}
|
||||
mdb.HashSelectDetail(m, kit.Select(VOID, role), func(value ice.Map) {
|
||||
ok = _role_check(value, key, role == TECH)
|
||||
})
|
||||
return
|
||||
return role == ROOT || len(mdb.HashSelectDetails(m, kit.Select(VOID, role), func(value ice.Map) bool { return _role_check(value, key, role == TECH) })) > 0
|
||||
}
|
||||
func _role_list(m *ice.Message, role string) *ice.Message {
|
||||
func _role_list(m *ice.Message, role string, arg ...string) *ice.Message {
|
||||
mdb.HashSelectDetail(m, kit.Select(VOID, role), func(value ice.Map) {
|
||||
kit.Fetch(value[WHITE], func(k string, v ice.Any) {
|
||||
m.Push(ROLE, kit.Value(value, mdb.NAME))
|
||||
m.Push(mdb.ZONE, WHITE)
|
||||
m.Push(mdb.KEY, k)
|
||||
m.Push(mdb.STATUS, v)
|
||||
kit.For(value[WHITE], func(k string, v ice.Any) {
|
||||
if len(arg) == 0 || k == arg[0] {
|
||||
m.Push(ROLE, kit.Value(value, mdb.NAME)).Push(mdb.ZONE, WHITE).Push(mdb.KEY, k).Push(mdb.STATUS, v)
|
||||
}
|
||||
})
|
||||
kit.Fetch(value[BLACK], func(k string, v ice.Any) {
|
||||
m.Push(ROLE, kit.Value(value, mdb.NAME))
|
||||
m.Push(mdb.ZONE, BLACK)
|
||||
m.Push(mdb.KEY, k)
|
||||
m.Push(mdb.STATUS, v)
|
||||
kit.For(value[BLACK], func(k string, v ice.Any) {
|
||||
if len(arg) == 0 || k == arg[0] {
|
||||
m.Push(ROLE, kit.Value(value, mdb.NAME)).Push(mdb.ZONE, BLACK).Push(mdb.KEY, k).Push(mdb.STATUS, v)
|
||||
}
|
||||
})
|
||||
})
|
||||
return m.Sort(mdb.KEY).StatusTimeCount()
|
||||
return m.Sort(mdb.KEY)
|
||||
}
|
||||
|
||||
const (
|
||||
@ -68,18 +61,45 @@ const (
|
||||
BLACK = "black"
|
||||
RIGHT = "right"
|
||||
)
|
||||
const (
|
||||
AUTH = "auth"
|
||||
ACCESS = "access"
|
||||
PUBLIC = "public"
|
||||
PRIVATE = "private"
|
||||
CONFIRM = "confirm"
|
||||
)
|
||||
const ROLE = "role"
|
||||
|
||||
func init() {
|
||||
Index.MergeCommands(ice.Commands{
|
||||
ROLE: {Name: "role role auto insert", Help: "角色", Actions: ice.MergeActions(ice.Actions{
|
||||
ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) { m.Cmd("", mdb.CREATE, TECH, VOID) }},
|
||||
mdb.CREATE: {Hand: func(m *ice.Message, arg ...string) {
|
||||
for _, role := range arg {
|
||||
mdb.Rich(m, ROLE, nil, kit.Dict(mdb.NAME, role, BLACK, kit.Dict(), WHITE, kit.Dict()))
|
||||
ROLE: {Name: "role name key auto", Help: "角色", Actions: ice.MergeActions(ice.Actions{
|
||||
ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) {
|
||||
m.Cmd(ROLE, mdb.CREATE, VOID, TECH)
|
||||
has := map[string]bool{VOID: true, TECH: true}
|
||||
m.Travel(func(p *ice.Context, c *ice.Context, key string, cmd *ice.Command) {
|
||||
role := map[string][]string{}
|
||||
kit.For(kit.Split(cmd.Role), func(k string) { role[k] = []string{} })
|
||||
for sub, action := range cmd.Actions {
|
||||
kit.For(kit.Split(action.Role), func(k string) { role[k] = append(role[k], sub) })
|
||||
}
|
||||
kit.For(role, func(role string, list []string) {
|
||||
kit.If(!has[role], func() { m.Cmd(ROLE, mdb.CREATE, role); has[role] = true })
|
||||
roleHandle(m, role, list...)
|
||||
})
|
||||
})
|
||||
m.Cmd(ROLE, WHITE, VOID, ROLE, "action", RIGHT)
|
||||
}},
|
||||
mdb.INPUTS: {Hand: func(m *ice.Message, arg ...string) {
|
||||
if arg[0] == mdb.KEY {
|
||||
mdb.HashInputs(m, ice.INDEX).CutTo(ice.INDEX, arg[0])
|
||||
}
|
||||
}},
|
||||
mdb.INSERT: {Name: "insert role*=void,tech zone*=white,black key*", Hand: func(m *ice.Message, arg ...string) {
|
||||
mdb.CREATE: {Hand: func(m *ice.Message, arg ...string) {
|
||||
kit.For(arg, func(role string) {
|
||||
mdb.Rich(m, ROLE, nil, kit.Dict(mdb.NAME, role, BLACK, kit.Dict(), WHITE, kit.Dict()))
|
||||
})
|
||||
}},
|
||||
mdb.INSERT: {Name: "insert role*=void zone*=white,black key*", Hand: func(m *ice.Message, arg ...string) {
|
||||
_role_set(m, m.Option(ROLE), m.Option(mdb.ZONE), m.Option(mdb.KEY), true)
|
||||
}},
|
||||
mdb.DELETE: {Hand: func(m *ice.Message, arg ...string) {
|
||||
@ -88,60 +108,65 @@ func init() {
|
||||
WHITE: {Hand: func(m *ice.Message, arg ...string) { _role_white(m, arg[0], _role_keys(arg[1:]...)) }},
|
||||
BLACK: {Hand: func(m *ice.Message, arg ...string) { _role_black(m, arg[0], _role_keys(arg[1:]...)) }},
|
||||
RIGHT: {Hand: func(m *ice.Message, arg ...string) {
|
||||
if _role_right(m, arg[0], kit.Split(_role_keys(arg[1:]...), ice.PT)...) {
|
||||
m.Echo(ice.OK)
|
||||
if len(arg) > 2 {
|
||||
m.Search(arg[1], func(key string, cmd *ice.Command) {
|
||||
if _, ok := cmd.Actions[arg[2]]; ok {
|
||||
arg = kit.Simple(arg[0], arg[1], ice.ACTION, arg[2:])
|
||||
}
|
||||
})
|
||||
}
|
||||
for _, role := range kit.AddUniq(kit.Split(arg[0]), VOID) {
|
||||
if _role_right(m, role, kit.Split(_role_keys(arg[1:]...), ice.PT)...) {
|
||||
m.Echo(ice.OK)
|
||||
break
|
||||
}
|
||||
}
|
||||
}},
|
||||
}, mdb.HashAction(mdb.SHORT, mdb.NAME)), Hand: func(m *ice.Message, arg ...string) {
|
||||
_role_list(m, kit.Select("", arg, 0)).PushAction(mdb.DELETE)
|
||||
}, mdb.HashAction(mdb.SHORT, mdb.NAME, mdb.FIELD, "time,name")), Hand: func(m *ice.Message, arg ...string) {
|
||||
if len(arg) == 0 {
|
||||
mdb.HashSelect(m, arg...)
|
||||
} else {
|
||||
_role_list(m, kit.Select("", arg, 0), kit.Slice(arg, 1)...)
|
||||
}
|
||||
}},
|
||||
})
|
||||
}
|
||||
|
||||
func RoleAction(key ...string) ice.Actions {
|
||||
func roleHandle(m *ice.Message, role string, key ...string) {
|
||||
cmd := m.ShortKey()
|
||||
role = kit.Select(VOID, role)
|
||||
m.Cmd(ROLE, WHITE, role, cmd)
|
||||
if cmd == "header" {
|
||||
return
|
||||
}
|
||||
m.Cmd(ROLE, BLACK, role, cmd, ice.ACTION)
|
||||
kit.For(key, func(key string) { m.Cmd(ROLE, WHITE, role, cmd, ice.ACTION, key) })
|
||||
}
|
||||
func WhiteAction(role string, key ...string) ice.Actions {
|
||||
role = kit.Select(VOID, role)
|
||||
return ice.Actions{ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) {
|
||||
if c, ok := ice.Info.Index[m.CommandKey()].(*ice.Context); ok && c == m.Target() {
|
||||
m.Cmd(ROLE, WHITE, VOID, m.CommandKey())
|
||||
m.Cmd(ROLE, BLACK, VOID, m.CommandKey(), ice.ACTION)
|
||||
}
|
||||
m.Cmd(ROLE, WHITE, VOID, m.PrefixKey())
|
||||
m.Cmd(ROLE, BLACK, VOID, m.PrefixKey(), ice.ACTION)
|
||||
for _, key := range key {
|
||||
m.Cmd(ROLE, WHITE, VOID, m.PrefixKey(), ice.ACTION, key)
|
||||
cmd := m.CommandKey()
|
||||
m.Cmd(ROLE, WHITE, role, cmd)
|
||||
if cmd == "header" {
|
||||
return
|
||||
}
|
||||
m.Cmd(ROLE, BLACK, role, cmd, ice.ACTION)
|
||||
kit.For(key, func(key string) { m.Cmd(ROLE, WHITE, role, cmd, ice.ACTION, key) })
|
||||
}}}
|
||||
}
|
||||
func WhiteAction(key ...string) ice.Actions {
|
||||
return ice.Actions{ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) {
|
||||
m.Cmd(ROLE, WHITE, VOID, m.CommandKey())
|
||||
m.Cmd(ROLE, BLACK, VOID, m.CommandKey(), ice.ACTION)
|
||||
for _, key := range key {
|
||||
m.Cmd(ROLE, WHITE, VOID, m.CommandKey(), ice.ACTION, key)
|
||||
}
|
||||
}}}
|
||||
}
|
||||
func BlackAction(key ...string) ice.Actions {
|
||||
return ice.Actions{ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) {
|
||||
m.Cmd(ROLE, WHITE, VOID, m.CommandKey())
|
||||
for _, key := range key {
|
||||
m.Cmd(ROLE, BLACK, VOID, m.CommandKey(), ice.ACTION, key)
|
||||
}
|
||||
}}}
|
||||
}
|
||||
func RoleRight(m *ice.Message, role string, key ...string) bool {
|
||||
return m.Cmdx(ROLE, RIGHT, role, key) == ice.OK
|
||||
}
|
||||
func Right(m *ice.Message, key ...ice.Any) bool {
|
||||
return m.Option(ice.MSG_USERROLE) == ROOT || !m.Warn(m.Cmdx(ROLE, RIGHT, m.Option(ice.MSG_USERROLE), key, logs.FileLineMeta(-1)) != ice.OK,
|
||||
ice.ErrNotRight, kit.Keys(key...), USERROLE, m.Option(ice.MSG_USERROLE), logs.FileLineMeta(-1))
|
||||
}
|
||||
func White(m *ice.Message, key ...string) {
|
||||
for _, key := range key {
|
||||
m.Cmd(ROLE, WHITE, VOID, key)
|
||||
}
|
||||
kit.For(key, func(key string) { m.Cmd(ROLE, WHITE, VOID, key) })
|
||||
}
|
||||
func Black(m *ice.Message, key ...string) {
|
||||
for _, key := range key {
|
||||
m.Cmd(ROLE, BLACK, VOID, key)
|
||||
}
|
||||
kit.For(key, func(key string) { m.Cmd(ROLE, BLACK, VOID, key) })
|
||||
}
|
||||
func Right(m *ice.Message, key ...ice.Any) bool {
|
||||
if key := kit.Simple(key); len(key) > 2 && key[1] == ice.ACTION && kit.IsIn(kit.Format(key[2]), ice.RUN, ice.COMMAND) {
|
||||
return true
|
||||
} else if len(key) > 0 && key[0] == ice.ETC_PATH {
|
||||
return true
|
||||
}
|
||||
// m.Option(ice.MSG_TITLE, kit.Keys(m.Option(ice.MSG_USERPOD), m.CommandKey(), m.ActionKey())+" "+logs.FileLine(-2))
|
||||
return !ice.Info.Important || m.Option(ice.MSG_USERROLE) == ROOT || !m.WarnNotRight(m.Cmdx(ROLE, RIGHT, m.Option(ice.MSG_USERROLE), key, logs.FileLineMeta(-1)) != ice.OK,
|
||||
kit.Keys(key...), USERROLE, m.Option(ice.MSG_USERROLE))
|
||||
}
|
||||
func IsTechOrRoot(m *ice.Message) bool { return kit.IsIn(m.Option(ice.MSG_USERROLE), TECH, ROOT) }
|
||||
|
@ -2,53 +2,45 @@ package aaa
|
||||
|
||||
import (
|
||||
ice "shylinux.com/x/icebergs"
|
||||
"shylinux.com/x/icebergs/base/gdb"
|
||||
"shylinux.com/x/icebergs/base/mdb"
|
||||
kit "shylinux.com/x/toolkits"
|
||||
"shylinux.com/x/toolkits/logs"
|
||||
)
|
||||
|
||||
func _sess_create(m *ice.Message, username string, arg ...string) (h string) {
|
||||
func _sess_create(m *ice.Message, username string, arg ...string) {
|
||||
if msg := m.Cmd(USER, username); msg.Length() > 0 {
|
||||
h = mdb.HashCreate(m, msg.AppendSimple(USERNAME, USERNICK, USERROLE), arg)
|
||||
mdb.HashCreate(m, msg.AppendSimple(USERROLE, USERNAME, USERNICK, AVATAR), arg)
|
||||
} else {
|
||||
h = mdb.HashCreate(m, m.OptionSimple(USERNAME, USERNICK, USERROLE), arg)
|
||||
mdb.HashCreate(m, m.OptionSimple(USERROLE, USERNAME, USERNICK, AVATAR), arg)
|
||||
}
|
||||
gdb.Event(m, SESS_CREATE, SESS, h, USERNAME, username)
|
||||
return
|
||||
}
|
||||
func _sess_check(m *ice.Message, sessid string) {
|
||||
if val := mdb.HashSelectDetails(m, sessid, func(value ice.Map) bool { return !m.WarnTimeNotValid(value[mdb.TIME], sessid) }); len(val) > 0 {
|
||||
if val := mdb.HashSelectDetails(m, sessid, func(value ice.Map) bool {
|
||||
return kit.Format(value[mdb.TIME]) > m.Time()
|
||||
}); len(val) > 0 {
|
||||
SessAuth(m, val)
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
UA = "ua"
|
||||
IP = "ip"
|
||||
UA = "ua"
|
||||
)
|
||||
const (
|
||||
CHECK = "check"
|
||||
GRANT = "grant"
|
||||
LOGIN = "login"
|
||||
LOGOUT = "logout"
|
||||
SESSID = "sessid"
|
||||
)
|
||||
const (
|
||||
SESS_CREATE = "sess.create"
|
||||
)
|
||||
const SESS = "sess"
|
||||
|
||||
func init() {
|
||||
Index.MergeCommands(ice.Commands{
|
||||
SESS: {Name: "sess hash auto prunes", Help: "会话", Actions: ice.MergeActions(ice.Actions{
|
||||
SESS: {Name: "sess hash auto", Help: "会话", Actions: ice.MergeActions(ice.Actions{
|
||||
mdb.CREATE: {Name: "create username*", Hand: func(m *ice.Message, arg ...string) {
|
||||
_sess_create(m, m.Option(USERNAME), UA, m.Option(ice.MSG_USERUA), IP, m.Option(ice.MSG_USERIP))
|
||||
}},
|
||||
CHECK: {Name: "check sessid*", Hand: func(m *ice.Message, arg ...string) {
|
||||
_sess_check(m, m.Option(SESSID))
|
||||
}},
|
||||
}, mdb.HashAction(mdb.SHORT, mdb.UNIQ, mdb.FIELD, "time,hash,username,usernick,userrole,ua,ip", mdb.EXPIRE, "720h"))},
|
||||
CHECK: {Name: "check sessid*", Hand: func(m *ice.Message, arg ...string) { _sess_check(m, m.Option(ice.MSG_SESSID)) }},
|
||||
}, mdb.ImportantHashAction("checkbox", ice.TRUE, mdb.EXPIRE, mdb.MONTH, mdb.SHORT, mdb.UNIQ, mdb.FIELD, "time,hash,userrole,username,usernick,avatar,ip,ua"))},
|
||||
})
|
||||
}
|
||||
|
||||
@ -56,20 +48,25 @@ func SessCreate(m *ice.Message, username string) string {
|
||||
return m.Option(ice.MSG_SESSID, m.Cmdx(SESS, mdb.CREATE, username))
|
||||
}
|
||||
func SessCheck(m *ice.Message, sessid string) bool {
|
||||
m.Options(ice.MSG_USERNAME, "", ice.MSG_USERNICK, "", ice.MSG_USERROLE, VOID, "aaa.checker", logs.FileLine(-1))
|
||||
m.Options(ice.MSG_USERNICK, "", ice.MSG_USERNAME, "", ice.MSG_USERROLE, VOID, ice.MSG_CHECKER, logs.FileLine(-1))
|
||||
return sessid != "" && m.Cmdy(SESS, CHECK, sessid, logs.FileLineMeta(-1)).Option(ice.MSG_USERNAME) != ""
|
||||
}
|
||||
func SessValid(m *ice.Message) string {
|
||||
if m.Option(ice.MSG_SESSID) == "" || m.Spawn().AdminCmd(SESS, m.Option(ice.MSG_SESSID)).Length() == 0 {
|
||||
return m.Option(ice.MSG_SESSID, m.Spawn().AdminCmd(SESS, mdb.CREATE, m.Option(ice.MSG_USERNAME)).Result())
|
||||
}
|
||||
return m.Option(ice.MSG_SESSID)
|
||||
}
|
||||
func SessAuth(m *ice.Message, value ice.Any, arg ...string) *ice.Message {
|
||||
return m.Auth(
|
||||
USERNAME, m.Option(ice.MSG_USERNAME, kit.Value(value, USERNAME)),
|
||||
USERNICK, m.Option(ice.MSG_USERNICK, kit.Value(value, USERNICK)),
|
||||
USERROLE, m.Option(ice.MSG_USERROLE, kit.Value(value, USERROLE)),
|
||||
USERROLE, m.Option(ice.MSG_USERROLE, kit.Format(kit.Value(value, USERROLE))),
|
||||
USERNAME, m.Option(ice.MSG_USERNAME, kit.Format(kit.Value(value, USERNAME))),
|
||||
USERNICK, m.Option(ice.MSG_USERNICK, kit.Format(kit.Value(value, USERNICK))),
|
||||
LANGUAGE, m.OptionDefault(ice.MSG_LANGUAGE, kit.Format(kit.Value(value, LANGUAGE))),
|
||||
AVATAR, m.Option(ice.MSG_AVATAR, kit.Format(kit.Value(value, AVATAR))),
|
||||
arg, logs.FileLineMeta(kit.Select(logs.FileLine(-1), m.Option("aaa.checker"))),
|
||||
)
|
||||
}
|
||||
func SessLogout(m *ice.Message, arg ...string) {
|
||||
if m.Option(ice.MSG_SESSID) == "" {
|
||||
return
|
||||
}
|
||||
m.Cmd(SESS, mdb.REMOVE, kit.Dict(mdb.HASH, m.Option(ice.MSG_SESSID)))
|
||||
kit.If(m.Option(ice.MSG_SESSID), func(sessid string) { m.Cmd(SESS, mdb.REMOVE, mdb.HASH, sessid) })
|
||||
}
|
||||
|
@ -23,12 +23,8 @@ func _totp_gen(per int64) string {
|
||||
}
|
||||
func _totp_get(key string, per int64, num int) string {
|
||||
buf, now := []byte{}, kit.Int64(time.Now().Unix()/per)
|
||||
for i := 0; i < 8; i++ {
|
||||
buf = append(buf, byte((uint64(now) >> uint64(((7 - i) * 8)))))
|
||||
}
|
||||
if l := len(key) % 8; l != 0 {
|
||||
key += strings.Repeat(ice.EQ, 8-l)
|
||||
}
|
||||
kit.For(8, func(i int) { buf = append(buf, byte((uint64(now) >> uint64(((7 - i) * 8))))) })
|
||||
kit.If(len(key)%8, func(l int) { key += strings.Repeat(mdb.EQ, 8-l) })
|
||||
s, _ := base32.StdEncoding.DecodeString(strings.ToUpper(key))
|
||||
hm := hmac.New(sha1.New, s)
|
||||
hm.Write(buf)
|
||||
@ -38,42 +34,33 @@ func _totp_get(key string, per int64, num int) string {
|
||||
return kit.Format(kit.Format("%%0%dd", num), res%int64(math.Pow10(num)))
|
||||
}
|
||||
|
||||
const (
|
||||
TOKEN = "token"
|
||||
)
|
||||
const TOTP = "totp"
|
||||
|
||||
func init() {
|
||||
const (
|
||||
SECRET = "secret"
|
||||
PERIOD = "period"
|
||||
NUMBER = "number"
|
||||
PERIOD = "period"
|
||||
SECRET = "secret"
|
||||
)
|
||||
Index.MergeCommands(ice.Commands{
|
||||
TOTP: {Name: "totp name auto create", Help: "令牌", Actions: ice.MergeActions(ice.Actions{
|
||||
mdb.CREATE: {Name: "create name*=hi secret period*=30 number*=6", Hand: func(m *ice.Message, arg ...string) {
|
||||
if m.Option(SECRET) == "" {
|
||||
m.Option(SECRET, _totp_gen(kit.Int64(m.Option(PERIOD))))
|
||||
}
|
||||
mdb.HashCreate(m, m.OptionSimple(mdb.NAME, SECRET, PERIOD, NUMBER))
|
||||
TOTP: {Help: "令牌", Actions: ice.MergeActions(ice.Actions{
|
||||
mdb.CREATE: {Name: "create name*=hi number*=6 period*=30 secret", Hand: func(m *ice.Message, arg ...string) {
|
||||
kit.If(m.Option(SECRET) == "", func() { m.Option(SECRET, _totp_gen(kit.Int64(m.Option(PERIOD)))) })
|
||||
mdb.HashCreate(m, m.OptionSimple(mdb.NAME, NUMBER, PERIOD, SECRET))
|
||||
}},
|
||||
}, mdb.HashAction(mdb.SHORT, mdb.NAME, mdb.FIELD, "time,name,secret,period,number", mdb.LINK, "otpauth://totp/%s?secret=%s")), Hand: func(m *ice.Message, arg ...string) {
|
||||
mdb.HashSelect(m.Spawn(), arg...).Tables(func(value ice.Maps) {
|
||||
if len(arg) > 0 {
|
||||
m.OptionFields(ice.FIELDS_DETAIL)
|
||||
}
|
||||
m.Push(mdb.TIME, m.Time())
|
||||
m.Push(mdb.NAME, value[mdb.NAME])
|
||||
}, mdb.HashAction(mdb.SHORT, mdb.NAME, mdb.FIELD, "time,name,number,period,secret", mdb.LINK, "otpauth://totp/%s?secret=%s")), Hand: func(m *ice.Message, arg ...string) {
|
||||
mdb.HashSelect(m.Spawn(), arg...).Table(func(value ice.Maps) {
|
||||
kit.If(len(arg) > 0, func() { m.OptionFields(ice.FIELDS_DETAIL) })
|
||||
m.Push(mdb.TIME, m.Time()).Push(mdb.NAME, value[mdb.NAME])
|
||||
period := kit.Int64(value[PERIOD])
|
||||
m.Push(mdb.EXPIRE, period-time.Now().Unix()%period)
|
||||
m.Push(mdb.VALUE, _totp_get(value[SECRET], period, kit.Int(value[NUMBER])))
|
||||
if len(arg) > 0 {
|
||||
m.PushQRCode(mdb.SCAN, kit.Format(m.Config(mdb.LINK), value[mdb.NAME], value[SECRET]))
|
||||
m.PushQRCode(mdb.SCAN, kit.Format(mdb.Config(m, mdb.LINK), value[mdb.NAME], value[SECRET]))
|
||||
m.Echo(m.Append(mdb.VALUE))
|
||||
} else {
|
||||
m.StatusTimeCount()
|
||||
}
|
||||
})
|
||||
kit.If(len(arg) == 0, func() { m.PushAction(mdb.REMOVE).Action(mdb.CREATE, mdb.PRUNES) })
|
||||
}},
|
||||
})
|
||||
}
|
||||
|
110
base/aaa/user.go
110
base/aaa/user.go
@ -4,93 +4,109 @@ import (
|
||||
ice "shylinux.com/x/icebergs"
|
||||
"shylinux.com/x/icebergs/base/gdb"
|
||||
"shylinux.com/x/icebergs/base/mdb"
|
||||
"shylinux.com/x/icebergs/base/web/html"
|
||||
kit "shylinux.com/x/toolkits"
|
||||
)
|
||||
|
||||
func _user_create(m *ice.Message, name, word string, arg ...string) {
|
||||
mdb.HashCreate(m, USERNAME, name, PASSWORD, kit.GetValid(
|
||||
func() string { return word },
|
||||
func() string { return m.CmdAppend(USER, name, PASSWORD) },
|
||||
func() string { return kit.Hashs() },
|
||||
), arg)
|
||||
func _user_create(m *ice.Message, name string, arg ...string) {
|
||||
mdb.HashCreate(m, USERNAME, name, arg)
|
||||
gdb.Event(m, USER_CREATE, USER, name)
|
||||
}
|
||||
func _user_login(m *ice.Message, name, word string) {
|
||||
if val := mdb.HashSelectDetails(m.Spawn(), name, func(value ice.Map) bool {
|
||||
return !m.Warn(word != "" && word != kit.Format(value[PASSWORD]), ice.ErrNotValid)
|
||||
}); len(val) > 0 {
|
||||
SessAuth(m, val)
|
||||
}
|
||||
func _user_remove(m *ice.Message, name string, arg ...string) {
|
||||
gdb.Event(m, USER_REMOVE, m.OptionSimple(USERNAME, USERNICK))
|
||||
mdb.HashRemove(m, m.OptionSimple(USERNAME))
|
||||
}
|
||||
|
||||
const (
|
||||
BACKGROUND = "background"
|
||||
AVATAR_URL = "avatar_url"
|
||||
AVATAR = "avatar"
|
||||
GENDER = "gender"
|
||||
MOBILE = "mobile"
|
||||
PHONE = "phone"
|
||||
SECRET = "secret"
|
||||
THEME = "theme"
|
||||
|
||||
AVATAR = "avatar"
|
||||
GENDER = "gender"
|
||||
MOBILE = "mobile"
|
||||
|
||||
CITY = "city"
|
||||
COUNTRY = "country"
|
||||
PROVINCE = "province"
|
||||
LANGUAGE = "language"
|
||||
LANGUAGE = "language"
|
||||
LOCATION = "location"
|
||||
LONGITUDE = "longitude"
|
||||
LATITUDE = "latitude"
|
||||
COMPANY = "company"
|
||||
PROVINCE = "province"
|
||||
COUNTRY = "country"
|
||||
CITY = "city"
|
||||
)
|
||||
const (
|
||||
USERNICK = "usernick"
|
||||
USERNAME = "username"
|
||||
PASSWORD = "password"
|
||||
USERNICK = "usernick"
|
||||
USERZONE = "userzone"
|
||||
USERROLE = "userrole"
|
||||
USERZONE = "userzone"
|
||||
|
||||
USER_CREATE = "user.create"
|
||||
USER_REMOVE = "user.remove"
|
||||
)
|
||||
const USER = "user"
|
||||
|
||||
func init() {
|
||||
Index.MergeCommands(ice.Commands{
|
||||
USER: {Name: "user username auto create", Help: "用户", Actions: ice.MergeActions(ice.Actions{
|
||||
mdb.CREATE: {Name: "create username* password usernick userzone userrole=void,tech", Hand: func(m *ice.Message, arg ...string) {
|
||||
_user_create(m, m.Option(USERNAME), m.Option(PASSWORD), m.OptionSimple(USERNICK, USERZONE, USERROLE)...)
|
||||
USER: {Help: "用户", Icon: "Contacts.png", Actions: ice.MergeActions(ice.Actions{
|
||||
mdb.INPUTS: {Hand: func(m *ice.Message, arg ...string) {
|
||||
switch mdb.HashInputs(m, arg); arg[0] {
|
||||
case USERNICK:
|
||||
m.Push(arg[0], m.Option(ice.MSG_USERNICK))
|
||||
case USERNAME:
|
||||
m.Push(arg[0], m.Option(ice.MSG_USERNAME))
|
||||
}
|
||||
if arg[0] == USERROLE {
|
||||
m.Option(ice.TABLE_CHECKBOX, ice.TRUE)
|
||||
}
|
||||
}},
|
||||
LOGIN: {Name: "login username* password", Hand: func(m *ice.Message, arg ...string) {
|
||||
_user_login(m, m.Option(USERNAME), m.Option(PASSWORD))
|
||||
mdb.CREATE: {Name: "create userrole=void,tech username* usernick language userzone email avatar", Hand: func(m *ice.Message, arg ...string) {
|
||||
_user_create(m, m.Option(USERNAME), m.OptionSimple(USERROLE, USERNICK, LANGUAGE, AVATAR, BACKGROUND, USERZONE, EMAIL)...)
|
||||
}},
|
||||
}, mdb.HashSearchAction(mdb.SHORT, USERNAME, mdb.FIELD, "time,username,usernick,userzone,userrole"))},
|
||||
mdb.REMOVE: {Hand: func(m *ice.Message, arg ...string) { _user_remove(m, m.Option(USERNAME)) }},
|
||||
}, mdb.ImportantHashAction(mdb.SHORT, USERNAME, mdb.FIELD, "time,userrole,username,usernick,language,avatar,background,userzone", html.CHECKBOX, ice.TRUE))},
|
||||
})
|
||||
}
|
||||
|
||||
func UserInfo(m *ice.Message, name ice.Any, key, meta string) (value string) {
|
||||
if m.Cmd(USER, name, func(val ice.Maps) { value = val[key] }).Length() == 0 && kit.Format(name) == m.Option(ice.MSG_USERNAME) {
|
||||
if m.Cmd(USER, kit.Select(m.Option(ice.MSG_USERNAME), name), func(val ice.Maps) { value = val[key] }).Length() == 0 || value == "" {
|
||||
return m.Option(meta)
|
||||
}
|
||||
return
|
||||
}
|
||||
func UserRole(m *ice.Message, username ice.Any) (role string) {
|
||||
if username == "" {
|
||||
return VOID
|
||||
} else if role = VOID; username == ice.Info.Username {
|
||||
return ROOT
|
||||
} else {
|
||||
return UserInfo(m, username, USERROLE, ice.MSG_USERROLE)
|
||||
}
|
||||
}
|
||||
func UserNick(m *ice.Message, username ice.Any) (nick string) {
|
||||
return UserInfo(m, username, USERNICK, ice.MSG_USERNICK)
|
||||
}
|
||||
func UserLang(m *ice.Message, username ice.Any) (nick string) {
|
||||
return UserInfo(m, username, LANGUAGE, ice.MSG_LANGUAGE)
|
||||
}
|
||||
func UserZone(m *ice.Message, username ice.Any) (zone string) {
|
||||
return UserInfo(m, username, USERZONE, ice.MSG_USERZONE)
|
||||
}
|
||||
func UserRole(m *ice.Message, username ice.Any) (role string) {
|
||||
if username == "" {
|
||||
return VOID
|
||||
}
|
||||
if role = VOID; username == ice.Info.Username {
|
||||
return ROOT
|
||||
}
|
||||
return UserInfo(m, username, USERROLE, ice.MSG_USERROLE)
|
||||
}
|
||||
func UserLogin(m *ice.Message, username, password string) bool {
|
||||
m.Options(ice.MSG_USERNAME, "", ice.MSG_USERNICK, "", ice.MSG_USERROLE, VOID)
|
||||
return m.Cmdy(USER, LOGIN, username, password).Option(ice.MSG_USERNAME) != ""
|
||||
func UserEmail(m *ice.Message, username ice.Any) (nick string) {
|
||||
return UserInfo(m, username, EMAIL, EMAIL)
|
||||
}
|
||||
func UserRoot(m *ice.Message, arg ...string) *ice.Message {
|
||||
username := kit.Select(ice.Info.Username, arg, 0)
|
||||
usernick := kit.Select(UserNick(m, username), arg, 1)
|
||||
userrole := kit.Select(ROOT, arg, 2)
|
||||
userrole := kit.Select(TECH, arg, 0)
|
||||
username := kit.Select(ice.Info.Username, arg, 1)
|
||||
usernick := kit.Select(UserNick(m, username), arg, 2)
|
||||
language := kit.Select(UserLang(m, username), arg, 3)
|
||||
userzone := kit.Select(ice.OPS, arg, 4)
|
||||
email := kit.Select(UserEmail(m, username), arg, 5)
|
||||
if len(arg) > 0 {
|
||||
m.Cmd(USER, mdb.CREATE, username, "", usernick, "", userrole)
|
||||
ice.Info.Username = username
|
||||
kit.If(username != ROOT, func() { ice.Info.Username = username })
|
||||
m.Cmd(USER, mdb.CREATE, userrole, username, usernick, language, userzone, email)
|
||||
}
|
||||
return SessAuth(m, kit.Dict(USERNAME, username, USERNICK, usernick, USERROLE, userrole))
|
||||
return SessAuth(m, kit.Dict(USERROLE, userrole, USERNAME, username, USERNICK, usernick))
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
package shy
|
||||
package base
|
||||
|
||||
import (
|
||||
_ "shylinux.com/x/icebergs/base/aaa"
|
||||
|
@ -1,5 +0,0 @@
|
||||
label `
|
||||
ctx mdb web aaa
|
||||
lex yac ssh gdb
|
||||
tcp nfs cli log
|
||||
`
|
@ -1,9 +1,14 @@
|
||||
package cli
|
||||
|
||||
import ice "shylinux.com/x/icebergs"
|
||||
import (
|
||||
ice "shylinux.com/x/icebergs"
|
||||
kit "shylinux.com/x/toolkits"
|
||||
)
|
||||
|
||||
const CLI = "cli"
|
||||
|
||||
var Index = &ice.Context{Name: CLI, Help: "命令模块"}
|
||||
|
||||
func init() { ice.Index.Register(Index, nil, RUNTIME, SYSTEM, DAEMON, FOREVER, MIRRORS, QRCODE) }
|
||||
func Prefix(arg ...string) string { return kit.Keys(CLI, arg) }
|
||||
|
||||
func init() { ice.Index.Register(Index, nil, RUNTIME, SYSTEM, DAEMON, FOREVER, MIRRORS, QRCODE, SUDO) }
|
||||
|
92
base/cli/color.go
Normal file
92
base/cli/color.go
Normal file
@ -0,0 +1,92 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"image/color"
|
||||
"math/rand"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
ice "shylinux.com/x/icebergs"
|
||||
kit "shylinux.com/x/toolkits"
|
||||
)
|
||||
|
||||
const (
|
||||
_DARK = 255
|
||||
_LIGHT = 127
|
||||
)
|
||||
|
||||
var _color_map = map[string]color.Color{
|
||||
BLACK: color.RGBA{0, 0, 0, _DARK},
|
||||
RED: color.RGBA{_DARK, 0, 0, _DARK},
|
||||
GREEN: color.RGBA{0, _DARK, 0, _DARK},
|
||||
YELLOW: color.RGBA{_DARK, _DARK, 0, _DARK},
|
||||
BLUE: color.RGBA{0, 0, _DARK, _DARK},
|
||||
PURPLE: color.RGBA{_DARK, 0, _DARK, _DARK},
|
||||
CYAN: color.RGBA{0, _DARK, _DARK, _DARK},
|
||||
WHITE: color.RGBA{_DARK, _DARK, _DARK, _DARK},
|
||||
SILVER: color.RGBA{0xC0, 0xC0, 0xC0, _DARK},
|
||||
}
|
||||
|
||||
var _color_list = map[string]string{
|
||||
"navy": "#000080",
|
||||
"aliceblue": "#f0f8ff",
|
||||
"firebrick": "#b22222",
|
||||
}
|
||||
|
||||
func _parse_color(str string) color.Color {
|
||||
if str == RANDOM {
|
||||
list := kit.SortedKey(_color_map)
|
||||
str = list[rand.Intn(len(list))]
|
||||
}
|
||||
str = kit.Select(str, _color_list[str])
|
||||
if strings.HasPrefix(str, "#") {
|
||||
kit.If(len(str) == 7, func() { str += "ff" })
|
||||
if u, e := strconv.ParseUint(str[1:], 16, 64); e == nil {
|
||||
return color.RGBA{uint8((u & 0xFF000000) >> 24), uint8((u & 0x00FF0000) >> 16), uint8((u & 0x0000FF00) >> 8), uint8((u & 0x000000FF) >> 0)}
|
||||
}
|
||||
}
|
||||
if color, ok := _color_map[str]; ok {
|
||||
return color
|
||||
}
|
||||
return _color_map[WHITE]
|
||||
}
|
||||
func _parse_cli_color(str string) string {
|
||||
res := 0
|
||||
r, g, b, _ := _parse_color(str).RGBA()
|
||||
kit.If(r > _LIGHT, func() { res += 1 })
|
||||
kit.If(g > _LIGHT, func() { res += 2 })
|
||||
kit.If(b > _LIGHT, func() { res += 4 })
|
||||
return kit.Format(res)
|
||||
}
|
||||
|
||||
const (
|
||||
BG = "bg"
|
||||
FG = "fg"
|
||||
COLOR = "color"
|
||||
BLACK = "black"
|
||||
WHITE = "white"
|
||||
BLUE = "blue"
|
||||
RED = "red"
|
||||
GRAY = "gray"
|
||||
CYAN = "cyan"
|
||||
GREEN = "green"
|
||||
SILVER = "silver"
|
||||
PURPLE = "purple"
|
||||
YELLOW = "yellow"
|
||||
RANDOM = "random"
|
||||
TRANS = "#0000"
|
||||
LIGHT = "light"
|
||||
DARK = "dark"
|
||||
)
|
||||
|
||||
func Color(m *ice.Message, c string, str ice.Any) string {
|
||||
wrap, color := `<span style="color:%s">%v</span>`, c
|
||||
kit.If(m.IsCliUA(), func() { wrap, color = "\033[3%sm%v\033[0m", _parse_cli_color(c) })
|
||||
return fmt.Sprintf(wrap, color, str)
|
||||
}
|
||||
func ColorRed(m *ice.Message, str ice.Any) string { return Color(m, RED, str) }
|
||||
func ColorGreen(m *ice.Message, str ice.Any) string { return Color(m, GREEN, str) }
|
||||
func ColorYellow(m *ice.Message, str ice.Any) string { return Color(m, YELLOW, str) }
|
||||
func ParseCliColor(color string) string { return _parse_cli_color(color) }
|
||||
func ParseColor(color string) color.Color { return _parse_color(color) }
|
@ -1,15 +1,19 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
ice "shylinux.com/x/icebergs"
|
||||
"shylinux.com/x/icebergs/base/ctx"
|
||||
"shylinux.com/x/icebergs/base/gdb"
|
||||
"shylinux.com/x/icebergs/base/lex"
|
||||
"shylinux.com/x/icebergs/base/mdb"
|
||||
"shylinux.com/x/icebergs/base/nfs"
|
||||
"shylinux.com/x/icebergs/base/tcp"
|
||||
kit "shylinux.com/x/toolkits"
|
||||
)
|
||||
|
||||
@ -17,39 +21,33 @@ func _daemon_exec(m *ice.Message, cmd *exec.Cmd) {
|
||||
if r, ok := m.Optionv(CMD_INPUT).(io.Reader); ok {
|
||||
cmd.Stdin = r
|
||||
}
|
||||
err := bytes.NewBuffer(make([]byte, 0, ice.MOD_BUFS))
|
||||
cmd.Stderr = err
|
||||
if w := _system_out(m, CMD_OUTPUT); w != nil {
|
||||
cmd.Stdout, cmd.Stderr = w, w
|
||||
}
|
||||
if w := _system_out(m, CMD_ERRPUT); w != nil {
|
||||
cmd.Stderr = w
|
||||
}
|
||||
h := mdb.HashCreate(m.Spawn(), ice.CMD, kit.Join(cmd.Args, ice.SP),
|
||||
STATUS, START, DIR, cmd.Dir, ENV, kit.Select("", cmd.Env),
|
||||
m.OptionSimple(CMD_INPUT, CMD_OUTPUT, CMD_ERRPUT, mdb.CACHE_CLEAR_ON_EXIT),
|
||||
h := mdb.HashCreate(m.Spawn(), STATUS, START,
|
||||
ice.CMD, strings.TrimPrefix(strings.TrimPrefix(kit.JoinWord(cmd.Args...), kit.Path("")+nfs.PS), cmd.Dir+nfs.PS), DIR, cmd.Dir, ENV, kit.Select("", cmd.Env),
|
||||
m.OptionSimple(CMD_INPUT, CMD_OUTPUT, CMD_ERRPUT, mdb.CACHE_CLEAR_ONEXIT),
|
||||
)
|
||||
if e := cmd.Start(); m.Warn(e, ice.ErrNotStart, cmd.Args) {
|
||||
if e := cmd.Start(); m.WarnNotValid(e, cmd.Args, err.String()) {
|
||||
mdb.HashModify(m, h, STATUS, ERROR, ERROR, e)
|
||||
return
|
||||
}
|
||||
mdb.HashSelectUpdate(m, h, func(value ice.Map) { value[PID] = cmd.Process.Pid })
|
||||
m.Echo("%d", cmd.Process.Pid)
|
||||
m.Go(func() {
|
||||
if e := cmd.Wait(); !m.Warn(e, ice.ErrNotStart, cmd.Args) && cmd.ProcessState.ExitCode() == 0 {
|
||||
m.Cost(CODE, cmd.ProcessState.ExitCode(), ctx.ARGS, cmd.Args)
|
||||
m.Echo("%d", cmd.Process.Pid).Go(func() {
|
||||
if e := cmd.Wait(); !m.WarnNotValid(e, cmd.Args, err.String()) && cmd.ProcessState != nil && cmd.ProcessState.Success() {
|
||||
mdb.HashModify(m, mdb.HASH, h, STATUS, STOP)
|
||||
m.Cost(CODE, "0", ctx.ARGS, cmd.Args)
|
||||
} else {
|
||||
mdb.HashSelectUpdate(m, h, func(value ice.Map) {
|
||||
if value[STATUS] == START {
|
||||
value[STATUS], value[ERROR] = ERROR, e
|
||||
}
|
||||
})
|
||||
mdb.HashSelectUpdate(m, h, func(value ice.Map) { value[STATUS], value[ERROR] = ERROR, e })
|
||||
}
|
||||
status := mdb.HashSelectField(m, h, STATUS)
|
||||
switch m.Sleep300ms(); cb := m.OptionCB("").(type) {
|
||||
switch status := mdb.HashSelectField(m.Sleep300ms(), h, STATUS); cb := m.OptionCB("").(type) {
|
||||
case func(string) bool:
|
||||
if !cb(status) {
|
||||
m.Cmdy(DAEMON, cmd.Path, cmd.Args)
|
||||
}
|
||||
kit.If(!cb(status), func() { m.Cmdy(DAEMON, cmd.Path, cmd.Args) })
|
||||
case func(string):
|
||||
cb(status)
|
||||
case func():
|
||||
@ -58,18 +56,18 @@ func _daemon_exec(m *ice.Message, cmd *exec.Cmd) {
|
||||
default:
|
||||
m.ErrorNotImplement(cb)
|
||||
}
|
||||
for _, p := range kit.Simple(CMD_INPUT, CMD_OUTPUT, CMD_ERRPUT) {
|
||||
nfs.CloseFile(m, m.Optionv(p))
|
||||
}
|
||||
kit.For(kit.Simple(CMD_INPUT, CMD_OUTPUT, CMD_ERRPUT), func(p string) { nfs.Close(m, m.Optionv(p)) })
|
||||
})
|
||||
}
|
||||
|
||||
const (
|
||||
DIR = "dir"
|
||||
ENV = "env"
|
||||
API = "api"
|
||||
PID = "pid"
|
||||
PWD = "pwd"
|
||||
DIR = "dir"
|
||||
ENV = "env"
|
||||
API = "api"
|
||||
MOD = "mod"
|
||||
PWD = "pwd"
|
||||
PID = "pid"
|
||||
PPID = "ppid"
|
||||
)
|
||||
const (
|
||||
BUILD = "build"
|
||||
@ -79,25 +77,34 @@ const (
|
||||
BENCH = "bench"
|
||||
PPROF = "pprof"
|
||||
|
||||
TIMEOUT = "timeout"
|
||||
STATUS = "status"
|
||||
ERROR = "error"
|
||||
CLEAR = "clear"
|
||||
RELOAD = "reload"
|
||||
RESTART = "restart"
|
||||
TIMEOUT = "timeout"
|
||||
STATUS = "status"
|
||||
ERROR = "error"
|
||||
CLEAR = "clear"
|
||||
STASH = "stash"
|
||||
DELAY = "delay"
|
||||
RECORD = "record"
|
||||
RELOAD = "reload"
|
||||
REBOOT = "reboot"
|
||||
RESTART = "restart"
|
||||
INTERVAL = "interval"
|
||||
OPTS = "opts"
|
||||
ARGS = "args"
|
||||
LOGS = "logs"
|
||||
|
||||
BEGIN = "begin"
|
||||
END = "end"
|
||||
START = "start"
|
||||
STOP = "stop"
|
||||
OPEN = "open"
|
||||
CLOSE = "close"
|
||||
STOP = "stop"
|
||||
END = "end"
|
||||
|
||||
PLAY = "play"
|
||||
MAIN = "main"
|
||||
CODE = "code"
|
||||
COST = "cost"
|
||||
BACK = "back"
|
||||
FROM = "from"
|
||||
BACK = "back"
|
||||
)
|
||||
|
||||
const DAEMON = "daemon"
|
||||
@ -106,7 +113,7 @@ func init() {
|
||||
Index.MergeCommands(ice.Commands{
|
||||
DAEMON: {Name: "daemon hash auto", Help: "守护进程", Actions: ice.MergeActions(ice.Actions{
|
||||
ice.CTX_EXIT: {Hand: func(m *ice.Message, arg ...string) {
|
||||
mdb.HashPrunesValue(m, mdb.CACHE_CLEAR_ON_EXIT, ice.TRUE)
|
||||
mdb.HashPrunesValue(m, mdb.CACHE_CLEAR_ONEXIT, ice.TRUE)
|
||||
}},
|
||||
START: {Name: "start cmd* dir env", Hand: func(m *ice.Message, arg ...string) {
|
||||
m.Options(CMD_DIR, m.Option(DIR), CMD_ENV, kit.Split(m.Option(ENV), " ="))
|
||||
@ -116,35 +123,82 @@ func init() {
|
||||
m.Cmdy("", STOP).Sleep3s().Cmdy("", START)
|
||||
}},
|
||||
STOP: {Hand: func(m *ice.Message, arg ...string) {
|
||||
m.OptionFields(mdb.HashField(m))
|
||||
h, pid := m.Option(mdb.HASH), m.Option(PID)
|
||||
mdb.HashSelect(m, m.Option(mdb.HASH)).Tables(func(value ice.Maps) {
|
||||
mdb.HashSelects(m.Spawn(), h).Table(func(value ice.Maps) {
|
||||
if h == "" && value[PID] != pid {
|
||||
return
|
||||
}
|
||||
mdb.HashModify(m, mdb.HASH, value[mdb.HASH], STATUS, STOP)
|
||||
m.Cmd(gdb.SIGNAL, gdb.KILL, value[PID])
|
||||
mdb.HashModify(m, mdb.HASH, kit.Select(h, value[mdb.HASH]), STATUS, STOP)
|
||||
kit.If(value[PID], func() { m.Cmd(gdb.SIGNAL, gdb.KILL, value[PID]) })
|
||||
})
|
||||
}},
|
||||
mdb.REMOVE: {Hand: func(m *ice.Message, arg ...string) {
|
||||
h, pid := m.Option(mdb.HASH), m.Option(PID)
|
||||
mdb.HashSelects(m.Spawn(), h).Table(func(value ice.Maps) {
|
||||
if h == "" && value[PID] != pid {
|
||||
return
|
||||
}
|
||||
mdb.HashRemove(m, kit.Select(h, value[mdb.HASH]))
|
||||
})
|
||||
}},
|
||||
}, mdb.StatusHashAction(mdb.FIELD, "time,hash,status,pid,cmd,dir,env")), Hand: func(m *ice.Message, arg ...string) {
|
||||
if len(arg) == 0 || !strings.Contains(arg[0], ice.PS) {
|
||||
if mdb.HashSelect(m, kit.Slice(arg, 0, 1)...).Tables(func(value ice.Maps) {
|
||||
switch value[STATUS] {
|
||||
case START:
|
||||
m.PushButton(RESTART, STOP)
|
||||
default:
|
||||
m.PushButton(START, mdb.REMOVE)
|
||||
}
|
||||
}); len(arg) == 0 || m.Length() > 0 {
|
||||
if len(arg) == 0 {
|
||||
m.Action(START, mdb.PRUNES)
|
||||
}
|
||||
return
|
||||
mdb.HashSelect(m, arg...).Table(func(value ice.Maps) {
|
||||
switch value[STATUS] {
|
||||
case START:
|
||||
m.PushButton(RESTART, STOP)
|
||||
default:
|
||||
m.PushButton(START, mdb.REMOVE)
|
||||
}
|
||||
}
|
||||
if _daemon_exec(m, _system_cmd(m, kit.Simple(kit.Split(arg[0]), arg[1:])...)); IsSuccess(m) && m.Append(CMD_ERR) == "" {
|
||||
m.SetAppend()
|
||||
})
|
||||
kit.If(len(arg) == 0, func() { m.Action(START, mdb.PRUNES) })
|
||||
if len(arg) > 0 && m.Length() == 0 {
|
||||
if runtime.GOOS == WINDOWS {
|
||||
_daemon_exec(m, _system_cmd(m, arg...))
|
||||
} else {
|
||||
_daemon_exec(m, _system_cmd(m, arg...))
|
||||
// _daemon_exec(m, _system_cmd(m, kit.Simple(kit.Split(arg[0]), arg[1:])...))
|
||||
}
|
||||
kit.If(IsSuccess(m) && m.Append(CMD_ERR) == "", func() { m.SetAppend() })
|
||||
}
|
||||
}},
|
||||
})
|
||||
}
|
||||
|
||||
func Opens(m *ice.Message, arg ...string) {
|
||||
if !tcp.IsLocalHost(m, m.Option(ice.MSG_USERIP)) {
|
||||
// return
|
||||
} else if len(arg) == 0 || arg[0] == "" {
|
||||
// return
|
||||
}
|
||||
switch runtime.GOOS {
|
||||
case DARWIN:
|
||||
if kit.Ext(arg[0]) == "app" {
|
||||
m.Cmdy(SYSTEM, OPEN, "-a", arg[0])
|
||||
} else {
|
||||
m.Cmdy(SYSTEM, OPEN, arg[0])
|
||||
}
|
||||
case WINDOWS:
|
||||
if kit.Ext(arg[0]) == "exe" {
|
||||
m.Cmdy(SYSTEM, arg[0])
|
||||
} else {
|
||||
m.Cmdy(SYSTEM, "explorer", arg[0])
|
||||
}
|
||||
}
|
||||
}
|
||||
func OpenCmds(m *ice.Message, arg ...string) *ice.Message {
|
||||
if !tcp.IsLocalHost(m, m.Option(ice.MSG_USERIP)) {
|
||||
return m
|
||||
} else if len(arg) == 0 || arg[0] == "" {
|
||||
return m
|
||||
}
|
||||
TellApp(m, "Terminal", kit.Format(`do script %q`, strings.Join(arg, "; ")), "activate")
|
||||
return m
|
||||
}
|
||||
func TellApp(m *ice.Message, app string, arg ...string) {
|
||||
OSAScript(m, kit.Format(`
|
||||
tell application "%s"
|
||||
%s
|
||||
end tell
|
||||
`, app, strings.Join(arg, lex.NL)))
|
||||
}
|
||||
func OSAScript(m *ice.Message, arg ...string) { m.Cmd(SYSTEM, "osascript", "-e", arg) }
|
||||
|
@ -2,65 +2,72 @@ package cli
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
ice "shylinux.com/x/icebergs"
|
||||
"shylinux.com/x/icebergs/base/gdb"
|
||||
"shylinux.com/x/icebergs/base/lex"
|
||||
"shylinux.com/x/icebergs/base/mdb"
|
||||
"shylinux.com/x/icebergs/base/nfs"
|
||||
kit "shylinux.com/x/toolkits"
|
||||
"shylinux.com/x/toolkits/logs"
|
||||
)
|
||||
|
||||
func BinPath(arg ...string) string {
|
||||
return kit.Join(kit.Simple(arg, kit.Path(ice.BIN), kit.Path(ice.USR_LOCAL_BIN), kit.Path(ice.USR_LOCAL_GO_BIN), kit.Env(PATH)), ice.DF)
|
||||
}
|
||||
func _path_sep() string { return kit.Select(nfs.DF, ";", strings.Contains(os.Getenv(PATH), ";")) }
|
||||
|
||||
const FOREVER = "forever"
|
||||
|
||||
func init() {
|
||||
Index.MergeCommands(ice.Commands{
|
||||
FOREVER: {Name: "forever auto", Help: "启动", Actions: ice.Actions{
|
||||
FOREVER: {Help: "启动", Actions: ice.Actions{
|
||||
START: {Hand: func(m *ice.Message, arg ...string) {
|
||||
env := []string{PATH, BinPath(), HOME, kit.Select(kit.Path(""), os.Getenv(HOME))}
|
||||
for _, k := range ENV_LIST {
|
||||
if kit.Env(k) != "" {
|
||||
env = append(env, k, kit.Env(k))
|
||||
}
|
||||
}
|
||||
for _, v := range os.Environ() {
|
||||
if ls := kit.Split(v, ice.EQ, ice.EQ); kit.IndexOf(env, ls[0]) == -1 && len(ls) > 1 {
|
||||
env := []string{PATH, BinPath(""), HOME, kit.Select(kit.Path(""), os.Getenv(HOME))}
|
||||
kit.For(ENV_LIST, func(k string) { kit.If(kit.Env(k) != "", func() { env = append(env, k, kit.Env(k)) }) })
|
||||
kit.For(os.Environ(), func(v string) {
|
||||
if ls := kit.Split(v, mdb.EQ, mdb.EQ); kit.IndexOf(env, ls[0]) == -1 && len(ls) > 1 {
|
||||
env = append(env, ls[0], ls[1])
|
||||
}
|
||||
}
|
||||
})
|
||||
m.Options(CMD_ENV, env, CMD_INPUT, os.Stdin, CMD_OUTPUT, os.Stdout, CMD_ERRPUT, os.Stderr)
|
||||
if p := kit.Env(CTX_LOG); p != "" {
|
||||
m.Optionv(CMD_ERRPUT, p)
|
||||
}
|
||||
kit.If(kit.Select("/dev/null", kit.Env(CTX_LOG)), func(p string) { m.Optionv(CMD_ERRPUT, p) })
|
||||
m.Cmd(FOREVER, STOP)
|
||||
if bin := kit.Select(os.Args[0], ice.BIN_ICE_BIN, nfs.ExistsFile(m, ice.BIN_ICE_BIN)); len(arg) > 0 && arg[0] == ice.SPACE {
|
||||
m.Cmdy(FOREVER, bin, ice.SPACE, "dial", ice.DEV, ice.OPS, arg[1:])
|
||||
if bin := kit.Select(os.Args[0], ice.BIN_ICE_BIN, nfs.Exists(m, ice.BIN_ICE_BIN)); len(arg) > 0 && arg[0] == ice.SPACE {
|
||||
m.Cmdy(FOREVER, bin, ice.SPACE, START, ice.DEV, ice.OPS, arg[1:])
|
||||
} else {
|
||||
m.Cmdy(FOREVER, bin, ice.SERVE, START, ice.DEV, "", arg)
|
||||
kit.If(len(arg) > 0 && arg[0] != ice.DEV, func() { arg = append([]string{ice.DEV, ""}, arg...) })
|
||||
m.Cmdy(FOREVER, bin, ice.SERVE, START, arg)
|
||||
}
|
||||
}},
|
||||
RESTART: {Hand: func(m *ice.Message, arg ...string) { m.Cmd(gdb.SIGNAL, gdb.RESTART) }},
|
||||
STOP: {Hand: func(m *ice.Message, arg ...string) { m.Cmd(gdb.SIGNAL, gdb.STOP) }},
|
||||
DELAY: {Hand: func(m *ice.Message, arg ...string) { m.Sleep(arg[0]).Cmdy(arg[1:]) }},
|
||||
}, Hand: func(m *ice.Message, arg ...string) {
|
||||
if len(arg) == 0 {
|
||||
m.Cmdy(RUNTIME, BOOTINFO)
|
||||
return
|
||||
}
|
||||
for {
|
||||
if logs.Println("run %s", kit.Join(arg, ice.SP)); IsSuccess(m.Cmd(SYSTEM, arg)) {
|
||||
if logs.Println("run %s", kit.Join(arg, lex.SP)); IsSuccess(m.Cmd(SYSTEM, arg)) {
|
||||
logs.Println(ice.EXIT)
|
||||
break
|
||||
}
|
||||
if logs.Println(); m.Config("log.save") == ice.TRUE {
|
||||
back := kit.Format("var/log.%s", logs.Now().Format("20060102_150405"))
|
||||
m.Cmd(SYSTEM, "cp", "-r", "var/log", back, ice.Maps{CMD_OUTPUT: ""})
|
||||
m.Cmd(SYSTEM, "cp", "bin/boot.log", path.Join(back, "boot.log"), ice.Maps{CMD_OUTPUT: ""})
|
||||
}
|
||||
logs.Println()
|
||||
}
|
||||
}},
|
||||
})
|
||||
}
|
||||
|
||||
func BinPath(arg ...string) string {
|
||||
list := []string{}
|
||||
push := func(p string) {
|
||||
kit.If(kit.IndexOf(list, p) == -1, func() { list = append(list, kit.ReplaceAll(p, "\\", nfs.PS)) })
|
||||
}
|
||||
kit.For(arg, func(p string) {
|
||||
list = append(list, kit.Path(p, ice.BIN), kit.Path(p, ice.USR_PUBLISH), kit.Path(p, ice.USR_LOCAL_BIN), kit.Path(p, ice.USR_LOCAL_GO_BIN))
|
||||
kit.For(kit.Reverse(EtcPath(ice.Pulse)), func(l string) {
|
||||
kit.If(strings.TrimSpace(l) != "" && !strings.HasPrefix(strings.TrimSpace(l), "#"), func() { push(kit.Path(p, l)) })
|
||||
})
|
||||
})
|
||||
kit.For(strings.Split(kit.Env(PATH), _path_sep()), func(p string) { push(p) })
|
||||
return kit.Join(list, _path_sep())
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import (
|
||||
|
||||
ice "shylinux.com/x/icebergs"
|
||||
"shylinux.com/x/icebergs/base/aaa"
|
||||
"shylinux.com/x/icebergs/base/lex"
|
||||
"shylinux.com/x/icebergs/base/mdb"
|
||||
"shylinux.com/x/icebergs/base/nfs"
|
||||
kit "shylinux.com/x/toolkits"
|
||||
@ -13,66 +14,109 @@ import (
|
||||
|
||||
const (
|
||||
CMD = "cmd"
|
||||
ADD = "add"
|
||||
OSID = "osid"
|
||||
REPOS = "repos"
|
||||
UBUNTU = "ubuntu"
|
||||
CENTOS = "centos"
|
||||
ALPINE = "alpine"
|
||||
BUSYBOX = "busybox"
|
||||
RELEASE = "release"
|
||||
RHEL = "rhel"
|
||||
|
||||
ETC_OS_RELEASE = "/etc/os-release"
|
||||
ETC_APK_REPOS = "/etc/apk/repositories"
|
||||
)
|
||||
|
||||
const MIRRORS = "mirrors"
|
||||
|
||||
func init() {
|
||||
Index.MergeCommands(ice.Commands{
|
||||
MIRRORS: {Name: "mirrors cli auto", Help: "软件镜像", Actions: ice.MergeActions(ice.Actions{
|
||||
MIRRORS: {Help: "软件镜像", Actions: ice.MergeActions(ice.Actions{
|
||||
mdb.INSERT: {Name: "insert cli* osid cmd*"},
|
||||
CMD: {Name: "cmd cli osid", Hand: func(m *ice.Message, arg ...string) {
|
||||
osid := kit.Select(m.Conf(RUNTIME, kit.Keys(HOST, OSID)), m.Option(OSID))
|
||||
osid := kit.Select(mdb.Conf(m, RUNTIME, kit.Keys(HOST, OSID)), m.Option(OSID))
|
||||
mdb.ZoneSelectCB(m, m.Option(CLI), func(value ice.Map) {
|
||||
if osid != "" && strings.Contains(osid, kit.Format(value[OSID])) {
|
||||
kit.If(strings.Contains(osid, kit.Format(value[OSID])), func() {
|
||||
m.Cmdy(kit.Split(kit.Format(value[CMD])))
|
||||
})
|
||||
})
|
||||
}},
|
||||
ADD: {Help: "安装", Hand: func(m *ice.Message, arg ...string) {
|
||||
ice.Info.PushStream(m)
|
||||
mdb.ZoneSelect(m, m.Option(CLI)).Table(func(value ice.Maps) {
|
||||
m.ToastProcess()
|
||||
if msg := m.Cmd(kit.Split(value[CMD])); IsSuccess(msg) {
|
||||
m.ToastSuccess()
|
||||
} else {
|
||||
m.ToastFailure()
|
||||
}
|
||||
})
|
||||
}},
|
||||
REPOS: {Name: "repos proxy=mirrors.tencent.com", Help: "镜像", Hand: func(m *ice.Message, arg ...string) {
|
||||
switch {
|
||||
case strings.Contains(_release, ALPINE):
|
||||
defer m.PushStream().ToastProcess()()
|
||||
kit.If(m.Option("proxy"), func(p string) {
|
||||
m.Cmd(nfs.SAVE, ETC_APK_REPOS, strings.ReplaceAll(m.Cmdx(nfs.CAT, ETC_APK_REPOS), "dl-cdn.alpinelinux.org", p))
|
||||
})
|
||||
m.Cmdy(SYSTEM, "apk", "update")
|
||||
}
|
||||
}},
|
||||
ALPINE: {Name: "alpine cli cmd", Hand: func(m *ice.Message, arg ...string) { IsAlpine(m, arg...) }},
|
||||
}, mdb.ZoneAction(mdb.SHORT, CLI, mdb.FIELD, "time,id,osid,cmd"), mdb.ClearHashOnExitAction())},
|
||||
}, mdb.ZoneAction(mdb.SHORT, CLI, mdb.FIELDS, "time,id,osid,cmd"), mdb.ClearOnExitHashAction()), Hand: func(m *ice.Message, arg ...string) {
|
||||
if mdb.ZoneSelect(m, arg...); len(arg) == 0 {
|
||||
m.Table(func(value ice.Maps) {
|
||||
p := SystemFind(m, value[CLI])
|
||||
if m.Push(nfs.PATH, p); p == "" {
|
||||
m.PushButton(ADD)
|
||||
} else {
|
||||
m.PushButton("")
|
||||
}
|
||||
}).Action(REPOS).StatusTimeCount("release", _release)
|
||||
}
|
||||
switch {
|
||||
case strings.Contains(_release, ALPINE):
|
||||
m.Cmdy(nfs.CAT, ETC_APK_REPOS)
|
||||
}
|
||||
// m.EchoScript(kit.Format("cd %s; %s", kit.Path(""), kit.JoinCmds(kit.Simple(kit.Path(os.Args[0]), os.Args[1:])...)))
|
||||
}},
|
||||
})
|
||||
}
|
||||
|
||||
var _release = ""
|
||||
|
||||
func release(m *ice.Message) string {
|
||||
osid := runtime.GOOS
|
||||
if osid != "linux" {
|
||||
return osid
|
||||
list := []string{runtime.GOOS}
|
||||
if list[0] != LINUX || !nfs.Exists(m, ETC_OS_RELEASE) {
|
||||
return list[0]
|
||||
}
|
||||
m.Option(nfs.CAT_CONTENT, _release)
|
||||
_release = m.Cmdx(nfs.CAT, "/etc/os-release", kit.Dict(ice.MSG_USERROLE, aaa.ROOT), func(text string, _ int) string {
|
||||
if ls := kit.Split(text, ice.EQ); len(ls) > 1 {
|
||||
switch ls[0] {
|
||||
case "ID", "ID_LIKE":
|
||||
osid = strings.TrimSpace(ls[1] + ice.SP + osid)
|
||||
}
|
||||
m.Cmd(nfs.CAT, ETC_OS_RELEASE, kit.Dict(ice.MSG_USERROLE, aaa.ROOT), func(text string, _ int) string {
|
||||
if ls := kit.Split(text, mdb.EQ); len(ls) > 1 {
|
||||
kit.Switch(ls[0], []string{"ID", "ID_LIKE"}, func() { list = append(list, strings.TrimSpace(ls[1])) })
|
||||
}
|
||||
return text
|
||||
})
|
||||
return osid
|
||||
_release = kit.JoinWord(list...)
|
||||
return _release
|
||||
}
|
||||
func insert(m *ice.Message, sys, cmd string, arg ...string) bool {
|
||||
if !strings.Contains(release(m), sys) {
|
||||
if !strings.Contains(_release, sys) {
|
||||
return false
|
||||
}
|
||||
if len(arg) > 0 {
|
||||
m.Go(func() {
|
||||
m.Sleep300ms().Cmd(mdb.INSERT, kit.Keys(CLI, MIRRORS), "", mdb.ZONE, arg[0], OSID, sys, CMD, cmd+ice.SP+kit.Select(arg[0], arg, 1))
|
||||
m.GoSleep300ms(func() {
|
||||
m.Cmd(mdb.INSERT, kit.Keys(CLI, MIRRORS), "", mdb.ZONE, arg[0], OSID, sys, CMD, cmd+lex.SP+kit.Select(arg[0], arg, 1))
|
||||
})
|
||||
}
|
||||
return true
|
||||
}
|
||||
func IsAlpine(m *ice.Message, arg ...string) bool { return insert(m, ALPINE, "system apk add", arg...) }
|
||||
func IsCentos(m *ice.Message, arg ...string) bool { return insert(m, CENTOS, "yum install -y", arg...) }
|
||||
func IsUbuntu(m *ice.Message, arg ...string) bool { return insert(m, UBUNTU, "apt get -y", arg...) }
|
||||
func IsSystem(m *ice.Message, arg ...string) bool {
|
||||
return IsAlpine(m, arg...) || IsCentos(m, arg...) || IsUbuntu(m, arg...)
|
||||
func IsAlpine(m *ice.Message, arg ...string) bool {
|
||||
return insert(m, ALPINE, "system apk add", arg...)
|
||||
}
|
||||
func IsRedhat(m *ice.Message, arg ...string) bool {
|
||||
return insert(m, RHEL, "system yum install -y", arg...)
|
||||
}
|
||||
func IsSystem(m *ice.Message, arg ...string) bool {
|
||||
return IsAlpine(m, arg...) || IsRedhat(m, arg...)
|
||||
}
|
||||
|
@ -2,69 +2,22 @@ package cli
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"image/color"
|
||||
"math/rand"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"shylinux.com/x/go-qrcode"
|
||||
ice "shylinux.com/x/icebergs"
|
||||
"shylinux.com/x/icebergs/base/aaa"
|
||||
"shylinux.com/x/icebergs/base/lex"
|
||||
"shylinux.com/x/icebergs/base/mdb"
|
||||
"shylinux.com/x/icebergs/base/nfs"
|
||||
"shylinux.com/x/icebergs/base/tcp"
|
||||
"shylinux.com/x/icebergs/base/web/html"
|
||||
"shylinux.com/x/icebergs/misc/qrcode"
|
||||
kit "shylinux.com/x/toolkits"
|
||||
)
|
||||
|
||||
var _color_map = map[string]color.Color{
|
||||
BLACK: color.RGBA{0, 0, 0, DARK},
|
||||
RED: color.RGBA{DARK, 0, 0, DARK},
|
||||
GREEN: color.RGBA{0, DARK, 0, DARK},
|
||||
YELLOW: color.RGBA{DARK, DARK, 0, DARK},
|
||||
BLUE: color.RGBA{0, 0, DARK, DARK},
|
||||
PURPLE: color.RGBA{DARK, 0, DARK, DARK},
|
||||
CYAN: color.RGBA{0, DARK, DARK, DARK},
|
||||
WHITE: color.RGBA{DARK, DARK, DARK, DARK},
|
||||
}
|
||||
|
||||
func _parse_color(str string) color.Color {
|
||||
if str == RANDOM {
|
||||
list := kit.SortedKey(_color_map)
|
||||
str = list[rand.Intn(len(list))]
|
||||
}
|
||||
if strings.HasPrefix(str, "#") {
|
||||
if len(str) == 7 {
|
||||
str += "ff"
|
||||
}
|
||||
if u, e := strconv.ParseUint(str[1:], 16, 64); e == nil {
|
||||
return color.RGBA{
|
||||
uint8((u & 0xFF000000) >> 24),
|
||||
uint8((u & 0x00FF0000) >> 16),
|
||||
uint8((u & 0x0000FF00) >> 8),
|
||||
uint8((u & 0x000000FF) >> 0),
|
||||
}
|
||||
}
|
||||
}
|
||||
return _color_map[str]
|
||||
}
|
||||
func _parse_cli_color(str string) string {
|
||||
res := 0
|
||||
r, g, b, _ := _parse_color(str).RGBA()
|
||||
if r > LIGHT {
|
||||
res += 1
|
||||
}
|
||||
if g > LIGHT {
|
||||
res += 2
|
||||
}
|
||||
if b > LIGHT {
|
||||
res += 4
|
||||
}
|
||||
return kit.Format(res)
|
||||
}
|
||||
func _qrcode_cli(m *ice.Message, text string) {
|
||||
qr, _ := qrcode.New(text, qrcode.Medium)
|
||||
fg := _parse_cli_color(m.Option(FG))
|
||||
bg := _parse_cli_color(m.Option(BG))
|
||||
data := qr.Bitmap()
|
||||
sc := qrcode.New(text)
|
||||
fg := ParseCliColor(m.Option(FG))
|
||||
bg := ParseCliColor(m.Option(BG))
|
||||
data := sc.Bitmap()
|
||||
for i, row := range data {
|
||||
if n := len(data); i < 3 || i >= n-3 {
|
||||
continue
|
||||
@ -75,86 +28,61 @@ func _qrcode_cli(m *ice.Message, text string) {
|
||||
}
|
||||
m.Echo("\033[4%sm \033[0m", kit.Select(bg, fg, col))
|
||||
}
|
||||
m.Echo(ice.NL)
|
||||
m.Echo(lex.NL)
|
||||
}
|
||||
m.Echo(text).Echo(ice.NL)
|
||||
m.Echo(text).Echo(lex.NL)
|
||||
}
|
||||
func _qrcode_web(m *ice.Message, text string) {
|
||||
qr, _ := qrcode.New(text, qrcode.Medium)
|
||||
qr.ForegroundColor = _parse_color(m.Option(FG))
|
||||
qr.BackgroundColor = _parse_color(m.Option(BG))
|
||||
if data, err := qr.PNG(kit.Int(m.Option(SIZE))); m.Assert(err) {
|
||||
m.Echo(`<img src="data:image/png;base64,%s" title='%s'>`, base64.StdEncoding.EncodeToString(data), text)
|
||||
func _qrcode_web(m *ice.Message, text string) string {
|
||||
sc := qrcode.New(text)
|
||||
sc.ForegroundColor = ParseColor(m.Option(FG))
|
||||
sc.BackgroundColor = ParseColor(m.Option(BG))
|
||||
if data, err := sc.PNG(kit.Int(m.Option(SIZE))); m.Assert(err) {
|
||||
m.Echo(`<img class="qrcode" src="data:image/png;base64,%s" title='%s'>`, base64.StdEncoding.EncodeToString(data), text)
|
||||
}
|
||||
return text
|
||||
}
|
||||
|
||||
const (
|
||||
FG = "fg"
|
||||
BG = "bg"
|
||||
DARK = 255
|
||||
LIGHT = 127
|
||||
SIZE = "size"
|
||||
)
|
||||
const (
|
||||
COLOR = "color"
|
||||
BLACK = "black"
|
||||
RED = "red"
|
||||
GREEN = "green"
|
||||
YELLOW = "yellow"
|
||||
BLUE = "blue"
|
||||
PURPLE = "purple"
|
||||
CYAN = "cyan"
|
||||
WHITE = "white"
|
||||
RANDOM = "random"
|
||||
GLASS = "#0000"
|
||||
GRAY = "gray"
|
||||
SIZE = "size"
|
||||
)
|
||||
const QRCODE = "qrcode"
|
||||
|
||||
func init() {
|
||||
Index.MergeCommands(ice.Commands{
|
||||
QRCODE: {Name: "qrcode text fg@key bg@key size auto", Help: "二维码", Actions: ice.Actions{
|
||||
QRCODE: {Name: "qrcode text fg@key bg@key size auto", Help: "二维码", Icon: "Chess.png", Role: aaa.VOID, Meta: kit.Dict(
|
||||
ice.CTX_TRANS, kit.Dict(html.INPUT, kit.Dict(mdb.TEXT, "文本", BG, "背景色", FG, "字体色")),
|
||||
), Actions: ice.MergeActions(ice.Actions{
|
||||
ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) {
|
||||
ice.AddRender(ice.RENDER_QRCODE, func(m *ice.Message, args ...ice.Any) string {
|
||||
return m.Cmd(QRCODE, kit.Simple(args...)).Result()
|
||||
if m.IsMobileUA() {
|
||||
m.Option(SIZE, "280")
|
||||
}
|
||||
return m.Cmd(Prefix(QRCODE), kit.Simple(args...)).Result()
|
||||
})
|
||||
}},
|
||||
mdb.INPUTS: {Hand: func(m *ice.Message, arg ...string) {
|
||||
switch arg[0] {
|
||||
case FG, BG:
|
||||
m.Push(arg[0], RED, GREEN, BLUE)
|
||||
m.Push(arg[0], kit.SortedKey(_color_map))
|
||||
}
|
||||
}},
|
||||
}, Hand: func(m *ice.Message, arg ...string) {
|
||||
m.Option(FG, kit.Select(kit.Select(BLUE, CYAN, m.Option(ice.TOPIC) == BLACK), arg, 1))
|
||||
m.Option(BG, kit.Select(kit.Select(WHITE, BLACK, m.Option(ice.TOPIC) == BLACK), arg, 2))
|
||||
}), Hand: func(m *ice.Message, arg ...string) {
|
||||
if m.IsCliUA() {
|
||||
m.OptionDefault(FG, BLACK, BG, WHITE)
|
||||
_qrcode_cli(m, kit.Select(kit.Select(ice.Info.Make.Domain, ice.Info.Domain), arg, 0))
|
||||
} else {
|
||||
m.Option(SIZE, kit.Select(kit.Format(kit.Min(480, kit.Int(m.Option(ice.HEIGHT)), kit.Int(m.Option(ice.WIDTH)))), arg, 3))
|
||||
_qrcode_web(m, kit.Select(m.Option(ice.MSG_USERWEB), arg, 0))
|
||||
m.StatusTime(mdb.LINK, kit.Select(m.Option(ice.MSG_USERWEB), arg, 0))
|
||||
// m.OptionDefault(SIZE, kit.Select("360", "280", m.IsMobileUA()))
|
||||
m.Option(FG, kit.Select(m.Option(ice.MSG_FG), arg, 1))
|
||||
m.Option(BG, kit.Select(m.Option(ice.MSG_BG), arg, 2))
|
||||
m.Option(SIZE, kit.Select(m.OptionDefault(SIZE, "320"), arg, 3))
|
||||
switch m.Option(ice.MSG_THEME) {
|
||||
case LIGHT, WHITE:
|
||||
m.OptionDefault(FG, BLACK, BG, WHITE)
|
||||
default:
|
||||
m.OptionDefault(FG, WHITE, BG, BLACK)
|
||||
}
|
||||
m.StatusTime(mdb.LINK, _qrcode_web(m, tcp.PublishLocalhost(m, kit.Select(m.Option(ice.MSG_USERWEB), arg, 0))))
|
||||
}
|
||||
}},
|
||||
})
|
||||
}
|
||||
|
||||
func Color(m *ice.Message, c string, str ice.Any) string {
|
||||
wrap, color := `<span style="color:%s">%v</span>`, c
|
||||
if m.IsCliUA() {
|
||||
wrap, color = "\033[3%sm%v\033[0m", _parse_cli_color(c)
|
||||
}
|
||||
return fmt.Sprintf(wrap, color, str)
|
||||
}
|
||||
func ColorRed(m *ice.Message, str ice.Any) string { return Color(m, RED, str) }
|
||||
func ColorGreen(m *ice.Message, str ice.Any) string { return Color(m, GREEN, str) }
|
||||
func ColorYellow(m *ice.Message, str ice.Any) string { return Color(m, YELLOW, str) }
|
||||
|
||||
func PushText(m *ice.Message, text string) {
|
||||
m.OptionFields(ice.MSG_DETAIL)
|
||||
if m.PushScript(nfs.SCRIPT, text); strings.HasPrefix(text, ice.HTTP) {
|
||||
m.PushQRCode(QRCODE, text)
|
||||
m.PushAnchor(text)
|
||||
}
|
||||
m.Echo(text)
|
||||
}
|
||||
|
@ -5,75 +5,104 @@ import (
|
||||
"path"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
ice "shylinux.com/x/icebergs"
|
||||
"shylinux.com/x/icebergs/base/aaa"
|
||||
"shylinux.com/x/icebergs/base/ctx"
|
||||
"shylinux.com/x/icebergs/base/gdb"
|
||||
"shylinux.com/x/icebergs/base/lex"
|
||||
"shylinux.com/x/icebergs/base/mdb"
|
||||
"shylinux.com/x/icebergs/base/nfs"
|
||||
"shylinux.com/x/icebergs/base/tcp"
|
||||
kit "shylinux.com/x/toolkits"
|
||||
)
|
||||
|
||||
func _runtime_init(m *ice.Message) {
|
||||
kit.Fetch(kit.UnMarshal(kit.Format(ice.Info.Make)), func(key string, value ice.Any) {
|
||||
m.Conf(RUNTIME, kit.Keys(MAKE, strings.ToLower(key)), value)
|
||||
})
|
||||
count := kit.Int(m.Conf(RUNTIME, kit.Keys(BOOT, mdb.COUNT)))
|
||||
defer m.Conf(RUNTIME, kit.Keys(BOOT, mdb.COUNT), count+1)
|
||||
kit.For(kit.UnMarshal(kit.Format(ice.Info.Make)), func(k string, v ice.Any) { m.Conf(RUNTIME, kit.Keys(MAKE, strings.ToLower(k)), v) })
|
||||
m.Conf(RUNTIME, kit.Keys(HOST, GOARCH), runtime.GOARCH)
|
||||
m.Conf(RUNTIME, kit.Keys(HOST, GOOS), runtime.GOOS)
|
||||
m.Conf(RUNTIME, kit.Keys(HOST, OSID), release(m))
|
||||
m.Conf(RUNTIME, kit.Keys(HOST, PID), os.Getpid())
|
||||
m.Conf(RUNTIME, kit.Keys(HOST, PWD), kit.Path(""))
|
||||
m.Conf(RUNTIME, kit.Keys(HOST, HOME), kit.Env(HOME))
|
||||
m.Conf(RUNTIME, kit.Keys(HOST, HOME), kit.HomePath(""))
|
||||
m.Conf(RUNTIME, kit.Keys(HOST, MAXPROCS), runtime.GOMAXPROCS(0))
|
||||
for _, k := range ENV_LIST {
|
||||
switch m.Conf(RUNTIME, kit.Keys(CONF, k), kit.Env(k)); k {
|
||||
case CTX_PID:
|
||||
ice.Info.PidPath = kit.Select(path.Join(ice.VAR_RUN, "ice.pid"), kit.Env(k))
|
||||
case CTX_SHARE:
|
||||
ice.Info.CtxShare = kit.Env(k)
|
||||
case CTX_RIVER:
|
||||
ice.Info.CtxRiver = kit.Env(k)
|
||||
}
|
||||
}
|
||||
ice.Info.System = m.Conf(RUNTIME, kit.Keys(HOST, OSID))
|
||||
kit.For(ENV_LIST, func(k string) { m.Conf(RUNTIME, kit.Keys(CONF, k), kit.Env(k)) })
|
||||
ice.Info.Lang = m.Conf(RUNTIME, kit.Keys(CONF, LANG))
|
||||
m.Conf(RUNTIME, kit.Keys(BOOT, USERNAME), kit.UserName())
|
||||
m.Conf(RUNTIME, kit.Keys(BOOT, HOSTNAME), kit.Env("HOSTNAME"))
|
||||
m.Conf(RUNTIME, kit.Keys(BOOT, PATHNAME), path.Base(kit.Path("")))
|
||||
if name, e := os.Hostname(); e == nil && name != "" {
|
||||
m.Conf(RUNTIME, kit.Keys(BOOT, HOSTNAME), name)
|
||||
}
|
||||
m.Conf(RUNTIME, kit.Keys(BOOT, PATHNAME), path.Base(kit.Env("PWD")))
|
||||
if name, e := os.Getwd(); e == nil && name != "" {
|
||||
m.Conf(RUNTIME, kit.Keys(BOOT, PATHNAME), path.Base(name))
|
||||
}
|
||||
m.Conf(RUNTIME, kit.Keys(BOOT, USERNAME), kit.Select(kit.UserName(), kit.Env(CTX_USER)))
|
||||
ice.Info.Username = m.Conf(RUNTIME, kit.Keys(BOOT, USERNAME))
|
||||
ice.Info.Hostname = m.Conf(RUNTIME, kit.Keys(BOOT, HOSTNAME))
|
||||
ice.Info.Pathname = m.Conf(RUNTIME, kit.Keys(BOOT, PATHNAME))
|
||||
ice.Info.Username = m.Conf(RUNTIME, kit.Keys(BOOT, USERNAME))
|
||||
aaa.UserRoot(ice.Pulse, ice.Info.Username)
|
||||
msg := m.Cmd(nfs.DIR, _system_find(m, os.Args[0]), "time,path,size,hash")
|
||||
m.Conf(RUNTIME, kit.Keys(BOOT, ice.BIN), msg.Append(nfs.PATH))
|
||||
m.Conf(RUNTIME, kit.Keys(BOOT, nfs.SIZE), msg.Append(nfs.SIZE))
|
||||
m.Conf(RUNTIME, kit.Keys(BOOT, mdb.HASH), msg.Append(mdb.HASH))
|
||||
m.Conf(RUNTIME, kit.Keys(BOOT, mdb.TIME), msg.Append(mdb.TIME))
|
||||
m.Conf(RUNTIME, kit.Keys(BOOT, mdb.COUNT), kit.Int(m.Conf(RUNTIME, kit.Keys(BOOT, mdb.COUNT)))+1)
|
||||
m.Conf(RUNTIME, mdb.META, "")
|
||||
m.Conf(RUNTIME, mdb.HASH, "")
|
||||
kit.HashSeed = append(kit.HashSeed, ice.Info.Username)
|
||||
kit.HashSeed = append(kit.HashSeed, ice.Info.Hostname)
|
||||
kit.HashSeed = append(kit.HashSeed, ice.Info.Pathname)
|
||||
aaa.UserRoot(ice.Pulse, aaa.TECH, ice.Info.Make.Author, "", "", ice.DEV, ice.Info.Make.Email)
|
||||
aaa.UserRoot(ice.Pulse, aaa.TECH, ice.Info.Make.Username, "", "", ice.DEV, ice.Info.Make.Email)
|
||||
aaa.UserRoot(ice.Pulse, aaa.ROOT, ice.Info.Username)
|
||||
aaa.UserRoot(ice.Pulse, aaa.ROOT, aaa.ROOT)
|
||||
ice.Info.Time = m.Time()
|
||||
m.Conf(RUNTIME, kit.Keys(BOOT, mdb.TIME), ice.Info.Time)
|
||||
if runtime.GOARCH != MIPSLE {
|
||||
msg := m.Cmd(nfs.DIR, _system_find(m, os.Args[0]), "time,path,size,hash")
|
||||
m.Conf(RUNTIME, kit.Keys(BOOT, mdb.HASH), msg.Append(mdb.HASH))
|
||||
m.Conf(RUNTIME, kit.Keys(BOOT, nfs.SIZE), msg.Append(nfs.SIZE))
|
||||
m.Conf(RUNTIME, kit.Keys(BOOT, ice.BIN), msg.Append(nfs.PATH))
|
||||
ice.Info.Hash = msg.Append(mdb.HASH)
|
||||
ice.Info.Size = msg.Append(nfs.SIZE)
|
||||
}
|
||||
nfs.Exists(m, "/proc/meminfo", func(p string) {
|
||||
kit.For(kit.SplitLine(m.Cmdx(nfs.CAT, p)), func(p string) {
|
||||
switch ls := kit.Split(p, ": "); kit.Select("", ls, 0) {
|
||||
case "MemTotal", "MemFree", "MemAvailable":
|
||||
m.Conf(RUNTIME, kit.Keys(HOST, ls[0]), kit.FmtSize(kit.Int(ls[1])*1024))
|
||||
}
|
||||
})
|
||||
})
|
||||
m.Conf(m.PrefixKey(), mdb.META, "")
|
||||
}
|
||||
func _runtime_hostinfo(m *ice.Message) {
|
||||
m.Push("nCPU", strings.Count(m.Cmdx(nfs.CAT, "/proc/cpuinfo"), "processor"))
|
||||
for i, ls := range strings.Split(m.Cmdx(nfs.CAT, "/proc/meminfo"), ice.NL) {
|
||||
if vs := kit.Split(ls, ": "); len(vs) > 1 {
|
||||
if m.Push(strings.TrimSpace(vs[0]), kit.FmtSize(kit.Int64(strings.TrimSpace(vs[1]))*1024)); i > 1 {
|
||||
break
|
||||
m.Push("time", ice.Info.Make.Time)
|
||||
m.Push("nCPU", runtime.NumCPU())
|
||||
m.Push("GOMAXPROCS", runtime.GOMAXPROCS(0))
|
||||
m.Push("NumGoroutine", runtime.NumGoroutine())
|
||||
var stats runtime.MemStats
|
||||
runtime.ReadMemStats(&stats)
|
||||
m.Push("Sys", kit.FmtSize(stats.Sys))
|
||||
m.Push("Alloc", kit.FmtSize(stats.Alloc))
|
||||
m.Push("TotalAlloc", kit.FmtSize(stats.TotalAlloc))
|
||||
m.Push("StackSys", kit.FmtSize(stats.StackSys))
|
||||
m.Push("StackInuse", kit.FmtSize(stats.StackInuse))
|
||||
m.Push("HeapSys", kit.FmtSize(stats.HeapSys))
|
||||
m.Push("HeapInuse", kit.FmtSize(stats.HeapInuse))
|
||||
m.Push("HeapIdle", kit.FmtSize(stats.HeapIdle))
|
||||
m.Push("HeapReleased", kit.FmtSize(stats.HeapReleased))
|
||||
m.Push("NumGC", stats.NumGC)
|
||||
m.Push("LastGC", time.Unix(int64(stats.LastGC)/int64(time.Second), int64(stats.LastGC)%int64(time.Second)))
|
||||
m.Push("uptime", kit.Split(m.Cmdx(SYSTEM, "uptime"), mdb.FS)[0])
|
||||
if runtime.GOOS == LINUX {
|
||||
for i, ls := range strings.Split(m.Cmdx(nfs.CAT, "/proc/meminfo"), lex.NL) {
|
||||
if vs := kit.Split(ls, ": "); len(vs) > 1 {
|
||||
if m.Push(strings.TrimSpace(vs[0]), kit.FmtSize(kit.Int64(strings.TrimSpace(vs[1]))*1024)); i > 1 {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
m.Push("MemAvailable", "")
|
||||
m.Push("MemTotal", "")
|
||||
m.Push("MemFree", "")
|
||||
}
|
||||
m.Push("uptime", kit.Split(m.Cmdx(SYSTEM, "uptime"), ice.FS)[0])
|
||||
}
|
||||
func _runtime_diskinfo(m *ice.Message) {
|
||||
m.Spawn().Split(kit.Replace(m.Cmdx(SYSTEM, "df", "-h"), "Mounted on", "Mountedon"), "", ice.SP, ice.NL).Table(func(index int, value ice.Maps, head []string) {
|
||||
if strings.HasPrefix(value["Filesystem"], "/dev") {
|
||||
m.Push("", value, head)
|
||||
}
|
||||
m.Spawn().Split(kit.Replace(m.Cmdx(SYSTEM, "df", "-h"), "Mounted on", "Mountedon"), "", lex.SP, lex.NL).Table(func(value ice.Maps, index int, head []string) {
|
||||
kit.If(strings.HasPrefix(value["Filesystem"], "/dev"), func() { m.Push("", value, head) })
|
||||
})
|
||||
m.RenameAppend("%iused", "piused", "Use%", "Usep")
|
||||
ctx.DisplayStory(m, "pie.js?field=Size")
|
||||
@ -88,60 +117,68 @@ const (
|
||||
NODE = "node"
|
||||
)
|
||||
const (
|
||||
GOARCH = "GOARCH"
|
||||
AMD64 = "amd64"
|
||||
X86 = "386"
|
||||
ARM = "arm"
|
||||
ARM64 = "arm64"
|
||||
MIPSLE = "mipsle"
|
||||
|
||||
GOARCH = "GOARCH"
|
||||
AMD64 = "amd64"
|
||||
X86 = "386"
|
||||
ARM = "arm"
|
||||
ARM64 = "arm64"
|
||||
MIPSLE = "mipsle"
|
||||
GOOS = "GOOS"
|
||||
LINUX = "linux"
|
||||
MACOS = "macos"
|
||||
DARWIN = "darwin"
|
||||
WINDOWS = "windows"
|
||||
|
||||
COMMIT_TIME = "commitTime"
|
||||
COMPILE_TIME = "compileTime"
|
||||
BOOT_TIME = "bootTime"
|
||||
|
||||
KERNEL = "kernel"
|
||||
ARCH = "arch"
|
||||
CPU = "cpu"
|
||||
OS = "os"
|
||||
)
|
||||
const (
|
||||
PATH = "PATH"
|
||||
USER = "USER"
|
||||
HOME = "HOME"
|
||||
USER = "USER"
|
||||
TERM = "TERM"
|
||||
SHELL = "SHELL"
|
||||
LANG = "LANG"
|
||||
TZ = "TZ"
|
||||
)
|
||||
const (
|
||||
CTX_SHY = "ctx_shy"
|
||||
CTX_COM = "ctx_com"
|
||||
CTX_DEV = "ctx_dev"
|
||||
CTX_OPS = "ctx_ops"
|
||||
CTX_POD = "ctx_pod"
|
||||
CTX_ARG = "ctx_arg"
|
||||
CTX_ENV = "ctx_env"
|
||||
CTX_SHY = "ctx_shy"
|
||||
CTX_DEV = "ctx_dev"
|
||||
CTX_DEV_IP = "ctx_dev_ip"
|
||||
CTX_OPS = "ctx_ops"
|
||||
CTX_REPOS = "ctx_repos"
|
||||
CTX_NAME = "ctx_name"
|
||||
CTX_DEMO = "ctx_demo"
|
||||
CTX_MAIL = "ctx_mail"
|
||||
CTX_ROOT = "ctx_root"
|
||||
CTX_DOMAIN = "ctx_domain"
|
||||
|
||||
CTX_PID = "ctx_pid"
|
||||
CTX_LOG = "ctx_log"
|
||||
|
||||
CTX_USER = "ctx_user"
|
||||
CTX_SHARE = "ctx_share"
|
||||
CTX_RIVER = "ctx_river"
|
||||
CTX_DAEMON = "ctx_daemon"
|
||||
|
||||
MAKE_DOMAIN = "make.domain"
|
||||
CTX_POD = "ctx_pod"
|
||||
CTX_ENV = "ctx_env"
|
||||
CTX_CLI = "ctx_cli"
|
||||
CTX_ARG = "ctx_arg"
|
||||
)
|
||||
|
||||
var ENV_LIST = []string{
|
||||
TERM, SHELL, CTX_SHY, CTX_COM, CTX_DEV, CTX_OPS, CTX_ARG, CTX_PID, CTX_USER, CTX_SHARE, CTX_RIVER, CTX_DAEMON,
|
||||
}
|
||||
var ENV_LIST = []string{TZ, LANG, TERM, SHELL, CTX_SHY, CTX_DEV, CTX_OPS, CTX_DEMO, CTX_MAIL, CTX_ROOT, CTX_PID}
|
||||
|
||||
const (
|
||||
USERNAME = "username"
|
||||
HOSTNAME = "hostname"
|
||||
PATHNAME = "pathname"
|
||||
USERNAME = "username"
|
||||
)
|
||||
const (
|
||||
IFCONFIG = "ifconfig"
|
||||
DISKINFO = "diskinfo"
|
||||
HOSTINFO = "hostinfo"
|
||||
USERINFO = "userinfo"
|
||||
PROCINFO = "procinfo"
|
||||
PROCKILL = "prockill"
|
||||
DISKINFO = "diskinfo"
|
||||
BOOTINFO = "bootinfo"
|
||||
MAXPROCS = "maxprocs"
|
||||
)
|
||||
@ -149,75 +186,122 @@ const RUNTIME = "runtime"
|
||||
|
||||
func init() {
|
||||
Index.MergeCommands(ice.Commands{
|
||||
RUNTIME: {Name: "runtime info=ifconfig,hostinfo,hostname,userinfo,procinfo,diskinfo,bootinfo,api,cli,cmd,env,chain auto", Help: "运行环境", Actions: ice.MergeActions(ice.Actions{
|
||||
RUNTIME: {Name: "runtime info=bootinfo,ifconfig,diskinfo,hostinfo,userinfo,bootinfo,role,api,cli,cmd,mod,env,path,chain auto upgrade reboot lock", Icon: "Infomation.png", Help: "环境", Actions: ice.MergeActions(ice.Actions{
|
||||
ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) { _runtime_init(m) }},
|
||||
ice.CTX_EXIT: {Hand: func(m *ice.Message, arg ...string) { m.Conf("", "", nil) }},
|
||||
IFCONFIG: {Hand: func(m *ice.Message, arg ...string) { m.Cmdy("tcp.host") }},
|
||||
IFCONFIG: {Hand: func(m *ice.Message, arg ...string) { m.Cmdy(tcp.HOST) }},
|
||||
DISKINFO: {Hand: func(m *ice.Message, arg ...string) { _runtime_diskinfo(m) }},
|
||||
HOSTINFO: {Hand: func(m *ice.Message, arg ...string) { _runtime_hostinfo(m) }},
|
||||
HOSTNAME: {Hand: func(m *ice.Message, arg ...string) {
|
||||
if len(arg) > 0 {
|
||||
ice.Info.Hostname = m.Conf(RUNTIME, kit.Keys(BOOT, HOSTNAME), m.Conf(RUNTIME, kit.Keys(NODE, mdb.NAME), arg[0]))
|
||||
ice.Info.Hostname = mdb.Conf(m, RUNTIME, kit.Keys(NODE, mdb.NAME), mdb.Conf(m, RUNTIME, kit.Keys(BOOT, HOSTNAME), arg[0]))
|
||||
}
|
||||
m.Echo(ice.Info.Hostname)
|
||||
}},
|
||||
USERINFO: {Hand: func(m *ice.Message, arg ...string) { m.Split(m.Cmdx(SYSTEM, "who"), "user term time") }},
|
||||
PROCINFO: {Hand: func(m *ice.Message, arg ...string) {
|
||||
msg := m.Cmd("", HOSTINFO)
|
||||
m.Split(m.Cmdx(SYSTEM, "ps", "u")).PushAction(PROCKILL).SortIntR("RSS")
|
||||
m.StatusTimeCount("nCPU", msg.Append("nCPU"), "MemTotal", msg.Append("MemTotal"), "MemFree", msg.Append("MemFree"))
|
||||
}},
|
||||
PROCKILL: {Hand: func(m *ice.Message, arg ...string) { m.Cmdy(gdb.SIGNAL, gdb.STOP, m.Option("PID")).ProcessRefresh() }},
|
||||
MAXPROCS: {Hand: func(m *ice.Message, arg ...string) {
|
||||
if len(arg) > 0 {
|
||||
runtime.GOMAXPROCS(kit.Int(m.Conf(RUNTIME, kit.Keys(HOST, MAXPROCS), arg[0])))
|
||||
}
|
||||
kit.If(len(arg) > 0, func() { runtime.GOMAXPROCS(kit.Int(mdb.Conf(m, RUNTIME, kit.Keys(HOST, MAXPROCS), arg[0]))) })
|
||||
m.Echo("%d", runtime.GOMAXPROCS(0))
|
||||
}},
|
||||
DISKINFO: {Hand: func(m *ice.Message, arg ...string) { _runtime_diskinfo(m) }},
|
||||
USERINFO: {Hand: func(m *ice.Message, arg ...string) { m.Split(m.Cmdx(SYSTEM, "who"), "user term time") }},
|
||||
aaa.ROLE: {Hand: func(m *ice.Message, arg ...string) {
|
||||
m.Cmd(aaa.ROLE, func(value ice.Maps) { m.Push(mdb.KEY, kit.Keys(value[aaa.ROLE], value[mdb.ZONE], value[mdb.KEY])) })
|
||||
ctx.DisplayStorySpide(m.Options(nfs.DIR_ROOT, "ice."), mdb.FIELD, mdb.KEY, lex.SPLIT, nfs.PT)
|
||||
}},
|
||||
API: {Hand: func(m *ice.Message, arg ...string) {
|
||||
for k, v := range ice.Info.Route {
|
||||
m.Push(nfs.PATH, k).Push(nfs.FILE, v)
|
||||
if len(arg) > 1 {
|
||||
m.Cmdy(ctx.COMMAND, "inner").Push(ctx.ARGS, kit.Format(nfs.SplitPath(m, m.Option(nfs.FILE))))
|
||||
return
|
||||
}
|
||||
m.Sort(nfs.PATH).StatusTimeCount()
|
||||
ctx.DisplayStorySpide(m.Options(nfs.DIR_ROOT, nfs.PS), lex.PREFIX, kit.Fields(ctx.ACTION, m.ActionKey()))
|
||||
kit.For(ice.Info.Route, func(k, v string) { m.Push(nfs.PATH, k).Push(nfs.FILE, v) })
|
||||
m.Sort(nfs.PATH)
|
||||
}},
|
||||
CLI: {Hand: func(m *ice.Message, arg ...string) {
|
||||
for k, v := range ice.Info.File {
|
||||
m.Push(nfs.FILE, k).Push(mdb.NAME, v)
|
||||
if len(arg) > 1 {
|
||||
m.Cmdy(ctx.COMMAND, "inner").Push(ctx.ARGS, kit.Format(nfs.SplitPath(m, m.Option(nfs.FILE))))
|
||||
return
|
||||
}
|
||||
m.Sort(nfs.FILE).StatusTimeCount()
|
||||
ctx.DisplayStorySpide(m.Options(nfs.DIR_ROOT, "ice."), lex.PREFIX, kit.Fields(ctx.ACTION, m.ActionKey()), mdb.FIELD, mdb.NAME, lex.SPLIT, nfs.PT)
|
||||
kit.For(ice.Info.File, func(k, v string) { m.Push(nfs.FILE, k).Push(mdb.NAME, v) })
|
||||
m.Sort(mdb.NAME)
|
||||
}},
|
||||
CMD: {Hand: func(m *ice.Message, arg ...string) {
|
||||
m.OptionFields(ctx.INDEX, mdb.NAME, mdb.HELP, nfs.FILE)
|
||||
m.Cmdy(ctx.COMMAND, mdb.SEARCH, ctx.COMMAND).StatusTimeCount()
|
||||
m.Cmdy(ctx.COMMAND, mdb.SEARCH, ctx.COMMAND)
|
||||
}},
|
||||
MOD: {Hand: func(m *ice.Message, arg ...string) {
|
||||
kit.For(ice.Info.Gomod, func(k string, v string) { m.Push(nfs.MODULE, k).Push(nfs.VERSION, v) })
|
||||
}},
|
||||
ENV: {Hand: func(m *ice.Message, arg ...string) {
|
||||
for _, v := range os.Environ() {
|
||||
ls := strings.SplitN(v, ice.EQ, 2)
|
||||
m.Push(mdb.NAME, ls[0]).Push(mdb.VALUE, ls[1])
|
||||
}
|
||||
m.StatusTimeCount()
|
||||
kit.For(os.Environ(), func(v string) { ls := strings.SplitN(v, mdb.EQ, 2); m.Push(mdb.NAME, ls[0]).Push(mdb.VALUE, ls[1]) })
|
||||
m.Sort(mdb.NAME)
|
||||
}},
|
||||
MAKE_DOMAIN: {Hand: func(m *ice.Message, arg ...string) {
|
||||
if os.Getenv(CTX_DEV) == "" || os.Getenv(CTX_POD) == "" {
|
||||
m.Echo(m.Conf(RUNTIME, MAKE_DOMAIN))
|
||||
nfs.PATH: {Hand: func(m *ice.Message, arg ...string) {
|
||||
kit.For(_path_split(os.Getenv(PATH)), func(p string) { m.Push(nfs.PATH, p) })
|
||||
}},
|
||||
"chain": {Hand: func(m *ice.Message, arg ...string) { m.Echo(m.FormatChain()) }},
|
||||
"upgrade": {Help: "升级", Hand: func(m *ice.Message, arg ...string) {
|
||||
if nfs.Exists(m, ice.SRC_MAIN_GO) && nfs.Exists(m, ".git") && SystemFind(m, "go") != "" {
|
||||
m.Cmdy("vimer", "compile")
|
||||
} else if nfs.Exists(m, ice.BIN_ICE_BIN) {
|
||||
m.Cmdy("upgrade")
|
||||
} else {
|
||||
m.Echo(kit.MergePOD(os.Getenv(CTX_DEV), os.Getenv(CTX_POD)))
|
||||
m.Cmdy("", REBOOT)
|
||||
}
|
||||
}},
|
||||
"chain": {Hand: func(m *ice.Message, arg ...string) {
|
||||
m.Echo(m.FormatChain())
|
||||
REBOOT: {Help: "重启", Hand: func(m *ice.Message, arg ...string) {
|
||||
m.Go(func() { m.Sleep30ms(ice.EXIT, 1) })
|
||||
}},
|
||||
"lock": {Help: "锁屏", Icon: "bi bi-file-lock", Hand: func(m *ice.Message, arg ...string) {
|
||||
switch runtime.GOOS {
|
||||
case DARWIN:
|
||||
TellApp(m, "System Events", `keystroke "q" using {control down, command down}`)
|
||||
}
|
||||
}},
|
||||
}, ctx.ConfAction("")), Hand: func(m *ice.Message, arg ...string) {
|
||||
if len(arg) > 0 && arg[0] == BOOTINFO {
|
||||
arg = arg[1:]
|
||||
}
|
||||
m.Cmdy(ctx.CONFIG, RUNTIME, arg)
|
||||
kit.If(len(arg) > 0 && arg[0] == BOOTINFO, func() { arg = arg[1:] })
|
||||
m.Cmdy(ctx.CONFIG, RUNTIME, arg).StatusTime(mdb.TIME, ice.Info.Make.Time,
|
||||
mdb.HASH, kit.Cut(ice.Info.Hash, 6), nfs.SIZE, ice.Info.Size,
|
||||
mdb.NAME, ice.Info.NodeName, nfs.VERSION, ice.Info.Make.Versions(),
|
||||
).Action()
|
||||
ctx.DisplayStoryJSON(m)
|
||||
}},
|
||||
})
|
||||
}
|
||||
func NodeInfo(m *ice.Message, arg ...string) {
|
||||
m.Conf(RUNTIME, kit.Keys(NODE, mdb.TIME), m.Time())
|
||||
ice.Info.NodeName = m.Conf(RUNTIME, kit.Keys(NODE, mdb.NAME), kit.Select(ice.Info.NodeName, arg, 0))
|
||||
ice.Info.NodeType = m.Conf(RUNTIME, kit.Keys(NODE, mdb.TYPE), kit.Select(ice.Info.NodeType, arg, 1))
|
||||
mdb.Conf(m, RUNTIME, kit.Keys(NODE, mdb.TIME), m.Time())
|
||||
ice.Info.NodeName = mdb.Conf(m, RUNTIME, kit.Keys(NODE, mdb.NAME), kit.Select(ice.Info.NodeName, arg, 0))
|
||||
ice.Info.NodeType = mdb.Conf(m, RUNTIME, kit.Keys(NODE, mdb.TYPE), kit.Select(ice.Info.NodeType, arg, 1))
|
||||
ice.Info.NodeIcon = mdb.Conf(m, RUNTIME, kit.Keys(NODE, mdb.ICON), kit.Select(ice.Info.NodeIcon, arg, 2))
|
||||
}
|
||||
func IsWindows() bool { return runtime.GOOS == WINDOWS }
|
||||
func ParseMake(str string) []string {
|
||||
res := kit.UnMarshal(str)
|
||||
data := kit.Value(res, MAKE)
|
||||
version := kit.Format(kit.Value(data, nfs.VERSION))
|
||||
if kit.Format(kit.Value(data, "forword")) != "0" {
|
||||
version = kit.Join(kit.TrimArg(kit.Simple(
|
||||
kit.Select("v0.0.0", kit.Format(kit.Value(data, nfs.VERSION))),
|
||||
kit.Select("0", kit.Format(kit.Value(data, "forword"))),
|
||||
kit.Cut(kit.Format(kit.Value(data, mdb.HASH)), 6),
|
||||
)...), "-")
|
||||
}
|
||||
return kit.Simple(
|
||||
mdb.TIME, kit.Format(kit.Value(data, mdb.TIME)),
|
||||
ice.SPACE, kit.Format(kit.Value(res, kit.Keys(NODE, mdb.NAME))),
|
||||
nfs.MODULE, kit.Format(kit.Value(data, nfs.MODULE)),
|
||||
nfs.VERSION, version,
|
||||
COMMIT_TIME, kit.Format(kit.Value(data, "when")),
|
||||
COMPILE_TIME, kit.Format(kit.Value(data, mdb.TIME)),
|
||||
BOOT_TIME, kit.Format(kit.Value(res, kit.Keys(BOOT, mdb.TIME))),
|
||||
SHELL, kit.Format(kit.Value(res, kit.Keys(CONF, SHELL))),
|
||||
KERNEL, kit.Format(kit.Value(res, kit.Keys(HOST, GOOS))),
|
||||
ARCH, kit.Format(kit.Value(res, kit.Keys(HOST, GOARCH))),
|
||||
)
|
||||
}
|
||||
func SimpleMake() []string {
|
||||
return []string{
|
||||
nfs.MODULE, ice.Info.Make.Module, nfs.VERSION, ice.Info.Make.Versions(),
|
||||
COMMIT_TIME, ice.Info.Make.When, COMPILE_TIME, ice.Info.Make.Time, BOOT_TIME, ice.Info.Time,
|
||||
KERNEL, runtime.GOOS, ARCH, runtime.GOARCH,
|
||||
}
|
||||
}
|
||||
|
12
base/cli/sudo.go
Normal file
12
base/cli/sudo.go
Normal file
@ -0,0 +1,12 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
ice "shylinux.com/x/icebergs"
|
||||
"shylinux.com/x/icebergs/base/mdb"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Index.MergeCommands(ice.Commands{
|
||||
SUDO: {Actions: mdb.HashAction(mdb.SHORT, "cmd", mdb.FIELD, "time,cmd")},
|
||||
})
|
||||
}
|
@ -3,67 +3,70 @@ package cli
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
ice "shylinux.com/x/icebergs"
|
||||
"shylinux.com/x/icebergs/base/ctx"
|
||||
"shylinux.com/x/icebergs/base/aaa"
|
||||
"shylinux.com/x/icebergs/base/lex"
|
||||
"shylinux.com/x/icebergs/base/mdb"
|
||||
"shylinux.com/x/icebergs/base/nfs"
|
||||
kit "shylinux.com/x/toolkits"
|
||||
"shylinux.com/x/toolkits/file"
|
||||
)
|
||||
|
||||
func _path_split(ps string) []string {
|
||||
ps = kit.ReplaceAll(ps, "\\", nfs.PS)
|
||||
return kit.Split(ps, lex.NL+kit.Select(nfs.DF, ";", strings.Contains(ps, ";")), lex.NL)
|
||||
}
|
||||
func _system_cmd(m *ice.Message, arg ...string) *exec.Cmd {
|
||||
bin, env := "", kit.Simple(m.Optionv(CMD_ENV))
|
||||
for i := 0; i < len(env)-1; i += 2 {
|
||||
if env[i] == PATH {
|
||||
if bin = _system_find(m, arg[0], strings.Split(env[i+1], ice.DF)...); bin != "" {
|
||||
m.Logs(mdb.SELECT, "envpath cmd", bin)
|
||||
kit.For(env, func(k, v string) {
|
||||
if k == PATH {
|
||||
if bin = _system_find(m, arg[0], _path_split(v)...); bin != "" {
|
||||
m.Logs(FIND, "envpath cmd", bin)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
if bin == "" {
|
||||
if text := kit.ReadFile(ice.ETC_PATH); len(text) > 0 {
|
||||
if bin = _system_find(m, arg[0], strings.Split(text, ice.NL)...); bin != "" {
|
||||
m.Logs(mdb.SELECT, "etcpath cmd", bin)
|
||||
}
|
||||
if bin = _system_find(m, arg[0], EtcPath(m)...); bin != "" {
|
||||
m.Logs(FIND, "etcpath cmd", bin)
|
||||
}
|
||||
}
|
||||
if bin == "" {
|
||||
if bin = _system_find(m, arg[0], ice.BIN, m.Option(CMD_DIR)); bin != "" {
|
||||
m.Logs(mdb.SELECT, "contexts cmd", bin)
|
||||
if bin = _system_find(m, arg[0], m.Option(CMD_DIR), ice.BIN, nfs.PWD); bin != "" {
|
||||
m.Logs(FIND, "contexts cmd", bin)
|
||||
}
|
||||
}
|
||||
if bin == "" {
|
||||
if bin = _system_find(m, arg[0], ice.BIN, nfs.PWD); bin != "" {
|
||||
m.Logs(mdb.SELECT, "contexts cmd", bin)
|
||||
}
|
||||
}
|
||||
if bin == "" && !strings.Contains(arg[0], ice.PS) {
|
||||
if bin == "" && !strings.Contains(arg[0], nfs.PS) {
|
||||
if bin = _system_find(m, arg[0]); bin != "" {
|
||||
m.Logs(mdb.SELECT, "systems cmd", bin)
|
||||
m.Logs(FIND, "systems cmd", bin)
|
||||
}
|
||||
}
|
||||
if bin == "" && !strings.Contains(arg[0], ice.PS) {
|
||||
if bin == "" && !strings.Contains(arg[0], nfs.PS) {
|
||||
m.Cmd(MIRRORS, CMD, arg[0])
|
||||
if bin = _system_find(m, arg[0]); bin != "" {
|
||||
m.Logs(mdb.SELECT, "mirrors cmd", bin)
|
||||
m.Logs(FIND, "mirrors cmd", bin)
|
||||
}
|
||||
}
|
||||
cmd := exec.Command(bin, arg[1:]...)
|
||||
arg[0] = kit.Select(arg[0], bin)
|
||||
if m.Cmd(SUDO, arg[0]).Length() > 0 {
|
||||
m.Logs(FIND, "sudo cmd", arg[0])
|
||||
arg = kit.Simple(SUDO, arg)
|
||||
}
|
||||
cmd := exec.Command(arg[0], arg[1:]...)
|
||||
if cmd.Dir = kit.TrimPath(m.Option(CMD_DIR)); len(cmd.Dir) > 0 {
|
||||
if m.Logs(mdb.PARAMS, CMD_DIR, cmd.Dir); !nfs.ExistsFile(m, cmd.Dir) {
|
||||
if m.Logs(EXEC, CMD_DIR, cmd.Dir); !nfs.Exists(m, cmd.Dir) {
|
||||
file.MkdirAll(cmd.Dir, ice.MOD_DIR)
|
||||
}
|
||||
}
|
||||
for i := 0; i < len(env)-1; i += 2 {
|
||||
cmd.Env = append(cmd.Env, kit.Format("%s=%s", env[i], env[i+1]))
|
||||
}
|
||||
if len(cmd.Env) > 0 {
|
||||
m.Logs(mdb.PARAMS, CMD_ENV, kit.Format(cmd.Env))
|
||||
}
|
||||
kit.For(env, func(k, v string) { cmd.Env = append(cmd.Env, kit.Format("%s=%s", k, v)) })
|
||||
kit.If(len(cmd.Env) > 0 && m.IsDebug(), func() { m.Logs(EXEC, CMD_ENV, kit.Format(cmd.Env)) })
|
||||
kit.If(len(cmd.Env) > 0, func() { m.Logs(EXEC, CMD_ENV, kit.Format(cmd.Env)) })
|
||||
_system_cmds(m, cmd, arg...)
|
||||
return cmd
|
||||
}
|
||||
func _system_out(m *ice.Message, out string) io.Writer {
|
||||
@ -72,8 +75,7 @@ func _system_out(m *ice.Message, out string) io.Writer {
|
||||
} else if m.Option(out) == "" {
|
||||
return nil
|
||||
} else if f, p, e := file.CreateFile(m.Option(out)); m.Assert(e) {
|
||||
m.Logs(mdb.EXPORT, out, p)
|
||||
m.Optionv(out, f)
|
||||
m.Logs(nfs.SAVE, out, p).Optionv(out, f)
|
||||
return f
|
||||
}
|
||||
return nil
|
||||
@ -93,36 +95,51 @@ func _system_exec(m *ice.Message, cmd *exec.Cmd) {
|
||||
cmd.Stdout, cmd.Stderr = out, err
|
||||
defer func() {
|
||||
m.Push(CMD_OUT, out.String()).Push(CMD_ERR, err.String())
|
||||
m.Echo(strings.TrimRight(out.String(), ice.NL))
|
||||
if m.Echo(out.String()).Echo(err.String()); m.IsErr() {
|
||||
m.Option(ice.MSG_ARGS, kit.Simple(http.StatusBadRequest, cmd.Args, err.String()))
|
||||
m.Echo(strings.TrimRight(err.String(), lex.NL))
|
||||
m.Info("err: %v", err.String())
|
||||
m.Info("out: %v", out.String())
|
||||
}
|
||||
}()
|
||||
}
|
||||
if e := cmd.Run(); !m.Warn(e, ice.ErrNotFound, cmd.Args) {
|
||||
m.Cost(CODE, cmd.ProcessState.ExitCode(), ctx.ARGS, cmd.Args)
|
||||
if e := cmd.Run(); !m.WarnNotValid(e, cmd.Args) {
|
||||
m.Cost(CODE, _system_code(cmd), EXEC, cmd.Args)
|
||||
}
|
||||
m.Push(mdb.TIME, m.Time()).Push(CODE, int(cmd.ProcessState.ExitCode()))
|
||||
m.Push(mdb.TIME, m.Time()).Push(CODE, _system_code(cmd)).StatusTime()
|
||||
}
|
||||
func _system_find(m Message, bin string, dir ...string) string {
|
||||
if strings.Contains(bin, ice.DF) {
|
||||
func _system_code(cmd *exec.Cmd) string {
|
||||
return kit.Select("1", "0", cmd.ProcessState != nil && cmd.ProcessState.Success())
|
||||
}
|
||||
func _system_find(m *ice.Message, bin string, dir ...string) string {
|
||||
if strings.Contains(bin, nfs.DF) {
|
||||
return bin
|
||||
} else if strings.HasPrefix(bin, nfs.PS) {
|
||||
return bin
|
||||
} else if strings.HasPrefix(bin, nfs.PWD) {
|
||||
return bin
|
||||
}
|
||||
if strings.HasPrefix(bin, ice.PS) {
|
||||
return bin
|
||||
}
|
||||
if strings.HasPrefix(bin, nfs.PWD) {
|
||||
return bin
|
||||
}
|
||||
if len(dir) == 0 {
|
||||
dir = append(dir, strings.Split(kit.Env(PATH), ice.DF)...)
|
||||
}
|
||||
kit.If(len(dir) == 0, func() { dir = append(dir, _path_split(kit.Env(PATH))...) })
|
||||
for _, p := range dir {
|
||||
if nfs.ExistsFile(m, path.Join(p, bin)) {
|
||||
if nfs.Exists(m, path.Join(p, bin)) {
|
||||
return kit.Path(p, bin)
|
||||
} else if IsWindows() && nfs.Exists(m, path.Join(p, bin)+".exe") {
|
||||
return kit.Path(p, bin) + ".exe"
|
||||
}
|
||||
}
|
||||
if nfs.Exists(m, bin) {
|
||||
return kit.Path(bin)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
const (
|
||||
TIME_300ms = "300ms"
|
||||
TIME_30ms = "30ms"
|
||||
TIME_30s = "30s"
|
||||
TIME_3s = "3s"
|
||||
TIME_1s = "1s"
|
||||
|
||||
CMD_DIR = "cmd_dir"
|
||||
CMD_ENV = "cmd_env"
|
||||
|
||||
@ -133,60 +150,100 @@ const (
|
||||
CMD_ERR = "cmd_err"
|
||||
CMD_OUT = "cmd_out"
|
||||
|
||||
MAN = "man"
|
||||
RUN = "run"
|
||||
REST = "rest"
|
||||
PARAM = "param"
|
||||
OPENS = "opens"
|
||||
RELAY = "relay"
|
||||
)
|
||||
|
||||
const (
|
||||
SH = "sh"
|
||||
LN = "ln"
|
||||
CP = "cp"
|
||||
MV = "mv"
|
||||
RM = "rm"
|
||||
CD = "cd"
|
||||
CAT = "cat"
|
||||
|
||||
FIND = "find"
|
||||
GREP = "grep"
|
||||
TAIL = "tail"
|
||||
WGET = "wget"
|
||||
CURL = "curl"
|
||||
|
||||
SUDO = "sudo"
|
||||
EXEC = "exec"
|
||||
EXIT = "exit"
|
||||
ECHO = "echo"
|
||||
KILL = "kill"
|
||||
|
||||
GO = "go"
|
||||
GOTAGS = "gotags"
|
||||
GIT = "git"
|
||||
MAN = "man"
|
||||
YUM = "yum"
|
||||
)
|
||||
|
||||
const SYSTEM = "system"
|
||||
|
||||
func init() {
|
||||
Index.MergeCommands(ice.Commands{
|
||||
SYSTEM: {Name: "system cmd auto", Help: "系统命令", Actions: ice.MergeActions(ice.Actions{
|
||||
SYSTEM: {Name: "system cmd", Help: "系统命令", Actions: ice.MergeActions(ice.Actions{
|
||||
nfs.PUSH: {Hand: func(m *ice.Message, arg ...string) {
|
||||
for _, p := range arg {
|
||||
if !strings.Contains(m.Cmdx(nfs.CAT, ice.ETC_PATH), p) {
|
||||
m.Cmd(nfs.PUSH, ice.ETC_PATH, strings.TrimSpace(p)+ice.NL)
|
||||
}
|
||||
}
|
||||
kit.For(arg, func(p string) {
|
||||
kit.If(!kit.IsIn(p, EtcPath(m)...), func() {
|
||||
m.Cmd(nfs.PUSH, ice.ETC_PATH, strings.TrimSpace(p)+lex.NL)
|
||||
})
|
||||
})
|
||||
m.Cmdy(nfs.CAT, ice.ETC_PATH)
|
||||
}},
|
||||
"find": {Hand: func(m *ice.Message, arg ...string) {
|
||||
m.Echo(_system_find(m, arg[0], arg[1:]...))
|
||||
}},
|
||||
FIND: {Hand: func(m *ice.Message, arg ...string) { m.Echo(_system_find(m, arg[0], arg[1:]...)) }},
|
||||
MAN: {Hand: func(m *ice.Message, arg ...string) {
|
||||
if len(arg) == 1 {
|
||||
arg = append(arg, "")
|
||||
}
|
||||
m.Option(CMD_ENV, "COLUMNS", kit.Int(kit.Select("1920", m.Option(ice.WIDTH)))/12)
|
||||
kit.If(len(arg) == 1, func() { arg = append(arg, "") })
|
||||
m.Echo(SystemCmds(m, "man %s %s|col -b", kit.Select("", arg[1], arg[1] != "1"), arg[0]))
|
||||
}},
|
||||
}, mdb.HashAction(mdb.SHORT, "cmd", mdb.FIELD, "time,cmd,arg")), Hand: func(m *ice.Message, arg ...string) {
|
||||
if len(arg) == 0 {
|
||||
mdb.HashSelect(m)
|
||||
return
|
||||
}
|
||||
// mdb.HashCreate(m.Spawn(), ice.CMD, arg[0], ice.ARG, kit.Join(arg[1:], ice.SP))
|
||||
if _system_exec(m, _system_cmd(m, kit.Simple(kit.Split(arg[0]), arg[1:])...)); IsSuccess(m) && m.Append(CMD_ERR) == "" {
|
||||
OPENS: {Hand: func(m *ice.Message, arg ...string) { Opens(m, arg...) }},
|
||||
}), Hand: func(m *ice.Message, arg ...string) {
|
||||
if _system_exec(m, _system_cmd(m, arg...)); IsSuccess(m) && m.Append(CMD_ERR) == "" {
|
||||
m.SetAppend()
|
||||
}
|
||||
}},
|
||||
})
|
||||
}
|
||||
|
||||
type Message interface {
|
||||
Append(key string, arg ...ice.Any) string
|
||||
Optionv(key string, arg ...ice.Any) ice.Any
|
||||
}
|
||||
|
||||
func SystemFind(m Message, bin string, dir ...string) string {
|
||||
if text := kit.ReadFile(ice.ETC_PATH); len(text) > 0 {
|
||||
dir = append(dir, strings.Split(text, ice.NL)...)
|
||||
ice.Info.SystemCmd = func(m *ice.Message, arg ...ice.Any) *ice.Message {
|
||||
msg := m.Cmd(append([]ice.Any{SYSTEM}, arg...)...)
|
||||
if m.Warn(!IsSuccess(msg), msg.Append(CMD_ERR)) {
|
||||
}
|
||||
return msg
|
||||
}
|
||||
dir = append(dir, strings.Split(kit.Env(PATH), ice.DF)...)
|
||||
return _system_find(m, bin, dir...)
|
||||
}
|
||||
func IsSuccess(m Message) bool { return m.Append(CODE) == "" || m.Append(CODE) == "0" }
|
||||
|
||||
func SystemFindGit(m *ice.Message) bool { return SystemFind(m, GIT) != "" }
|
||||
func SystemFindGo(m *ice.Message) bool { return SystemFind(m, GO) != "" }
|
||||
func SystemFind(m *ice.Message, bin string, dir ...string) string {
|
||||
dir = append(dir, EtcPath(m)...)
|
||||
return _system_find(m, bin, append(dir, _path_split(kit.Env(PATH))...)...)
|
||||
}
|
||||
func SystemExec(m *ice.Message, arg ...string) string { return strings.TrimSpace(m.Cmdx(SYSTEM, arg)) }
|
||||
func SystemCmds(m *ice.Message, cmds string, args ...ice.Any) string {
|
||||
return strings.TrimRight(m.Cmdx(SYSTEM, "sh", "-c", kit.Format(cmds, args...), ice.Option{CMD_OUTPUT, ""}), ice.NL)
|
||||
return strings.TrimRight(m.Cmdx(SYSTEM, SH, "-c", kit.Format(cmds, args...), ice.Option{CMD_OUTPUT, ""}), lex.NL)
|
||||
}
|
||||
func IsSuccess(m *ice.Message) bool { return m.Append(CODE) == "" || m.Append(CODE) == "0" }
|
||||
|
||||
var _cache_path []string
|
||||
|
||||
func Shell(m *ice.Message) string { return kit.Select(SH, os.Getenv(SHELL)) }
|
||||
func EtcPath(m *ice.Message) (res []string) {
|
||||
if len(_cache_path) > 0 {
|
||||
return _cache_path
|
||||
}
|
||||
nfs.Exists(m, ice.ETC_PATH, func(p string) {
|
||||
kit.For(strings.Split(m.Cmdx(nfs.CAT, p, kit.Dict(aaa.UserRole, aaa.ROOT)), lex.NL), func(p string) {
|
||||
kit.If(p != "" && !strings.HasPrefix(p, "# "), func() {
|
||||
res = append(res, p)
|
||||
})
|
||||
})
|
||||
})
|
||||
_cache_path = res
|
||||
return
|
||||
}
|
||||
|
11
base/cli/system_darwin.go
Normal file
11
base/cli/system_darwin.go
Normal file
@ -0,0 +1,11 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"os/exec"
|
||||
|
||||
ice "shylinux.com/x/icebergs"
|
||||
)
|
||||
|
||||
func _system_cmds(m *ice.Message, cmd *exec.Cmd, arg ...string) *exec.Cmd {
|
||||
return cmd
|
||||
}
|
11
base/cli/system_linux.go
Normal file
11
base/cli/system_linux.go
Normal file
@ -0,0 +1,11 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"os/exec"
|
||||
|
||||
ice "shylinux.com/x/icebergs"
|
||||
)
|
||||
|
||||
func _system_cmds(m *ice.Message, cmd *exec.Cmd, arg ...string) *exec.Cmd {
|
||||
return cmd
|
||||
}
|
11
base/cli/system_windows.go
Normal file
11
base/cli/system_windows.go
Normal file
@ -0,0 +1,11 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"os/exec"
|
||||
|
||||
ice "shylinux.com/x/icebergs"
|
||||
)
|
||||
|
||||
func _system_cmds(m *ice.Message, cmd *exec.Cmd, arg ...string) *exec.Cmd {
|
||||
return cmd
|
||||
}
|
@ -2,85 +2,90 @@ package ctx
|
||||
|
||||
import (
|
||||
"path"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
ice "shylinux.com/x/icebergs"
|
||||
"shylinux.com/x/icebergs/base/aaa"
|
||||
"shylinux.com/x/icebergs/base/mdb"
|
||||
"shylinux.com/x/icebergs/base/nfs"
|
||||
"shylinux.com/x/icebergs/base/web/html"
|
||||
kit "shylinux.com/x/toolkits"
|
||||
)
|
||||
|
||||
func _command_list(m *ice.Message, name string) *ice.Message {
|
||||
if name == "" {
|
||||
for k, v := range m.Source().Commands {
|
||||
if IsOrderCmd(k) {
|
||||
continue
|
||||
}
|
||||
m.Push(mdb.KEY, k).Push(mdb.NAME, v.Name).Push(mdb.HELP, v.Help)
|
||||
}
|
||||
return m.Sort(mdb.KEY)
|
||||
}
|
||||
if nfs.ExistsFile(m, path.Join(ice.SRC, name)) {
|
||||
switch kit.Ext(name) {
|
||||
case nfs.GO:
|
||||
name = GetFileCmd(name)
|
||||
case nfs.JS:
|
||||
m.Push(DISPLAY, FileURI(name))
|
||||
name = kit.Select(CAN_PLUGIN, GetFileCmd(name))
|
||||
default:
|
||||
if msg := m.Cmd(mdb.RENDER, kit.Ext(name)); msg.Length() > 0 {
|
||||
m.Push(ARGS, kit.Format(kit.List(name)))
|
||||
name = kit.Keys(msg.Append(mdb.TEXT), msg.Append(mdb.NAME))
|
||||
}
|
||||
}
|
||||
}
|
||||
if strings.HasPrefix(name, "can.") {
|
||||
return m.Push(mdb.INDEX, name)
|
||||
return m.Push(mdb.INDEX, name).Push(mdb.NAME, name).Push(mdb.HELP, "").Push(mdb.META, "").Push(mdb.LIST, "")
|
||||
}
|
||||
m.Option(ice.MSG_NODENAME, ice.Info.Titles)
|
||||
m.Option(ice.MSG_NODEICON, m.Resource(ice.Info.NodeIcon))
|
||||
m.Spawn(m.Source()).Search(name, func(p *ice.Context, s *ice.Context, key string, cmd *ice.Command) {
|
||||
m.Push(mdb.INDEX, kit.Keys(s.Cap(ice.CTX_FOLLOW), key))
|
||||
m.Push(mdb.NAME, kit.Format(cmd.Name))
|
||||
m.Push(mdb.HELP, kit.Format(cmd.Help))
|
||||
m.Push(mdb.META, kit.Format(cmd.Meta))
|
||||
m.Push(mdb.LIST, kit.Format(cmd.List))
|
||||
icon := kit.Format(kit.Value(cmd.Meta, kit.Keys(ice.CTX_ICONS, key)))
|
||||
icons := kit.Select(cmd.Icon, icon, !kit.HasPrefix(icon, "bi ", "{"))
|
||||
if icons != "" {
|
||||
icons = m.Resource(icons)
|
||||
}
|
||||
m.Push(mdb.INDEX, kit.Keys(s.Prefix(), key))
|
||||
m.Push(mdb.ICONS, icons)
|
||||
m.Push(mdb.NAME, kit.Format(cmd.Name)).Push(mdb.HELP, kit.Format(cmd.Help))
|
||||
m.Push(mdb.LIST, kit.Format(cmd.List)).Push(mdb.META, kit.Format(cmd.Meta))
|
||||
m.Push("_command", ShortCmd(kit.Keys(s.Prefix(), key)))
|
||||
if !nfs.Exists(m, kit.Split(cmd.FileLine(), nfs.DF)[0], func(p string) {
|
||||
m.Push("_fileline", m.FileURI(p))
|
||||
}) {
|
||||
m.Push("_fileline", "")
|
||||
}
|
||||
m.Push("_role", kit.Select("", ice.OK, aaa.Right(m.Spawn(), name)))
|
||||
m.Push("_help", GetCmdHelp(m, name))
|
||||
})
|
||||
return m
|
||||
}
|
||||
func _command_search(m *ice.Message, kind, name, text string) {
|
||||
m.Travel(func(p *ice.Context, s *ice.Context, key string, cmd *ice.Command) {
|
||||
if IsOrderCmd(key) {
|
||||
if IsOrderCmd(key) || !strings.Contains(s.Prefix(key), name) {
|
||||
return
|
||||
}
|
||||
if name != "" && !strings.HasPrefix(key, name) && !strings.Contains(s.Name, name) {
|
||||
return
|
||||
}
|
||||
m.PushSearch(ice.CTX, kit.PathName(1), ice.CMD, kit.FileName(1), kit.SimpleKV("", s.Cap(ice.CTX_FOLLOW), cmd.Name, cmd.Help),
|
||||
CONTEXT, s.Cap(ice.CTX_FOLLOW), COMMAND, key, INDEX, kit.Keys(s.Cap(ice.CTX_FOLLOW), key),
|
||||
mdb.HELP, cmd.Help, nfs.FILE, FileURI(cmd.GetFileLines()),
|
||||
)
|
||||
})
|
||||
m.PushSearch(ice.CTX, kit.PathName(1), ice.CMD, kit.FileName(1),
|
||||
kit.SimpleKV("", s.Prefix(), kit.Select(key, cmd.Name), cmd.Help),
|
||||
INDEX, kit.Keys(s.Prefix(), key))
|
||||
}).Sort(m.OptionFields())
|
||||
}
|
||||
|
||||
const (
|
||||
INDEX = "index"
|
||||
CMDS = "cmds"
|
||||
ARGS = "args"
|
||||
OPTS = "opts"
|
||||
STYLE = "style"
|
||||
DISPLAY = "display"
|
||||
PREVIEW = "preview"
|
||||
ACTION = "action"
|
||||
TRANS = "trans"
|
||||
TOOLS = "tools"
|
||||
RUN = "run"
|
||||
SHIP = "ship"
|
||||
|
||||
CAN_PLUGIN = "can.plugin"
|
||||
ICONS = ice.CTX_ICONS
|
||||
TRANS = ice.CTX_TRANS
|
||||
TITLE = ice.CTX_TITLE
|
||||
INPUT = html.INPUT
|
||||
)
|
||||
const COMMAND = "command"
|
||||
|
||||
func init() {
|
||||
Index.MergeCommands(ice.Commands{
|
||||
COMMAND: {Name: "command key auto", Help: "命令", Actions: ice.MergeActions(ice.Actions{
|
||||
COMMAND: {Name: "command key auto", Help: "命令", Role: aaa.VOID, Actions: ice.MergeActions(ice.Actions{
|
||||
ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) {
|
||||
TravelCmd(m, func(key, file, line string) {
|
||||
if strings.Contains(file, ice.ICEBERGS) {
|
||||
AddFileCmd(file, key)
|
||||
TravelCmd(m, func(key, file, line string) { AddFileCmd(file, key) })
|
||||
m.Travel(func(p *ice.Context, c *ice.Context, key string, cmd *ice.Command) {
|
||||
kit.If(cmd.Actions == nil, func() { cmd.Actions = ice.Actions{} })
|
||||
if _, ok := cmd.Actions[COMMAND]; !ok {
|
||||
cmd.Actions[COMMAND] = &ice.Action{Hand: Command}
|
||||
}
|
||||
if _, ok := cmd.Actions[RUN]; !ok {
|
||||
cmd.Actions[RUN] = &ice.Action{Hand: Run}
|
||||
}
|
||||
if _, ok := cmd.Actions[mdb.INPUTS]; !ok {
|
||||
cmd.Actions[mdb.INPUTS] = &ice.Action{Hand: func(m *ice.Message, arg ...string) { mdb.HashInputs(m, arg) }}
|
||||
}
|
||||
})
|
||||
}},
|
||||
@ -89,107 +94,97 @@ func init() {
|
||||
_command_search(m, arg[0], kit.Select("", arg, 1), kit.Select("", arg, 2))
|
||||
}
|
||||
}},
|
||||
mdb.EXPORT: {Hand: func(m *ice.Message, arg ...string) {
|
||||
TravelCmd(m, func(key, file, line string) {
|
||||
m.Push(mdb.NAME, key).Push(nfs.FILE, file).Push(nfs.LINE, line)
|
||||
}).Sort(mdb.NAME).Tables(func(value ice.Maps) {
|
||||
m.Echo(`%s %s %s;" f`+ice.NL, value[mdb.NAME], value[nfs.FILE], value[nfs.LINE])
|
||||
}).Cmd(nfs.SAVE, "tags", m.Result())
|
||||
mdb.INPUTS: {Hand: func(m *ice.Message, arg ...string) {
|
||||
if len(arg) > 0 && arg[0] != "" && arg[0] != ice.EXIT {
|
||||
m.Search(arg[0], func(key string, cmd *ice.Command) {
|
||||
field := kit.Format(kit.Value(cmd.List, kit.Format("%d.name", len(arg)-1)))
|
||||
if m.Cmdy(arg[0], mdb.INPUTS, field); m.Length() == 0 {
|
||||
m.Cmdy(arg).Cut(field)
|
||||
}
|
||||
})
|
||||
}
|
||||
}},
|
||||
}, aaa.RoleAction()), Hand: func(m *ice.Message, arg ...string) {
|
||||
"default": {Hand: func(m *ice.Message, arg ...string) {
|
||||
m.Spawn(m.Source()).Search(arg[0], func(key string, cmd *ice.Command) {
|
||||
if arg[1] == ACTION {
|
||||
list := kit.Value(cmd.Meta, arg[2])
|
||||
kit.For(arg[3:], func(k, v string) {
|
||||
kit.For(list, func(value ice.Map) {
|
||||
kit.If(value[mdb.NAME] == k, func() {
|
||||
value[mdb.VALUE] = v
|
||||
})
|
||||
})
|
||||
})
|
||||
return
|
||||
}
|
||||
for i, v := range arg[1:] {
|
||||
kit.Value(cmd.List, kit.Keys(i, mdb.VALUE), v)
|
||||
}
|
||||
})
|
||||
}},
|
||||
}), Hand: func(m *ice.Message, arg ...string) {
|
||||
if len(arg) == 0 {
|
||||
arg = append(arg, "")
|
||||
}
|
||||
for _, key := range arg {
|
||||
_command_list(m, key)
|
||||
m.OptionFields(INDEX)
|
||||
m.Cmdy("", mdb.SEARCH, COMMAND)
|
||||
} else {
|
||||
kit.For(arg, func(k string) { _command_list(m, k) })
|
||||
}
|
||||
}},
|
||||
})
|
||||
}
|
||||
|
||||
var runChecker = []func(*ice.Message, string, string, ...string) bool{}
|
||||
var PodCmd = func(m *ice.Message, arg ...ice.Any) bool { return false }
|
||||
|
||||
func AddRunChecker(cb func(*ice.Message, string, string, ...string) bool) {
|
||||
runChecker = append(runChecker, cb)
|
||||
}
|
||||
func Run(m *ice.Message, arg ...string) {
|
||||
if len(arg) > 3 && arg[1] == ACTION && arg[2] == CONFIG {
|
||||
for _, check := range runChecker {
|
||||
if check(m, arg[0], arg[3], arg...) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
if !PodCmd(m, arg) && aaa.Right(m, arg) {
|
||||
m.Cmdy(arg)
|
||||
}
|
||||
kit.If(!PodCmd(m, arg) && aaa.Right(m, arg), func() { m.Cmdy(arg) })
|
||||
}
|
||||
func Command(m *ice.Message, arg ...string) {
|
||||
kit.If(!PodCmd(m, COMMAND, arg), func() { m.Cmdy(COMMAND, arg) })
|
||||
}
|
||||
|
||||
var Upload = func(*ice.Message) []string { return nil }
|
||||
|
||||
func PodCmd(m *ice.Message, arg ...ice.Any) bool {
|
||||
Upload(m)
|
||||
if pod := m.Option(ice.POD); pod != "" {
|
||||
m.Option(ice.POD, "")
|
||||
m.Cmdy(append(kit.List(ice.SPACE, pod), arg...)...)
|
||||
return true
|
||||
func FileCmd(dir string) string {
|
||||
if strings.Index(dir, ":") == 1 {
|
||||
return ice.Pulse.FileURI(kit.ExtChange(strings.Join(kit.Slice(strings.Split(dir, ":"), 0, 2), ":"), nfs.GO))
|
||||
}
|
||||
return false
|
||||
return ice.Pulse.FileURI(kit.ExtChange(strings.Split(dir, nfs.DF)[0], nfs.GO))
|
||||
}
|
||||
func CmdHandler(args ...ice.Any) ice.Handler {
|
||||
return func(m *ice.Message, arg ...string) { m.Cmdy(args...) }
|
||||
}
|
||||
func CmdAction(args ...ice.Any) ice.Actions {
|
||||
return ice.Actions{ice.CTX_INIT: mdb.AutoConfig(args...),
|
||||
COMMAND: {Hand: func(m *ice.Message, arg ...string) {
|
||||
if !PodCmd(m, COMMAND, arg) {
|
||||
m.Cmdy(COMMAND, arg)
|
||||
}
|
||||
}}, ice.RUN: {Hand: Run},
|
||||
func AddFileCmd(dir, key string) {
|
||||
if ls := strings.SplitN(path.Join(kit.Slice(kit.Split(FileCmd(dir), nfs.PS), 1, 4)...), mdb.AT, 2); len(ls) > 1 {
|
||||
_ls := strings.Split(FileCmd(dir), mdb.AT+ls[1]+nfs.PS)
|
||||
ice.Info.File[path.Join(nfs.P, nfs.USR, path.Base(_ls[0]), _ls[1])] = key
|
||||
ice.Info.Gomod[ls[0]] = ls[1]
|
||||
} else {
|
||||
ice.Info.File[FileCmd(dir)] = key
|
||||
}
|
||||
}
|
||||
|
||||
func FileURI(dir string) string {
|
||||
if dir == "" {
|
||||
return ""
|
||||
} else if strings.Contains(dir, "/go/pkg/mod/") {
|
||||
return path.Join(ice.PS, ice.REQUIRE, strings.Split(dir, "/go/pkg/mod/")[1])
|
||||
}
|
||||
if path.IsAbs(dir) {
|
||||
if strings.HasPrefix(dir, kit.Path("")+ice.PS) {
|
||||
dir = strings.TrimPrefix(dir, kit.Path("")+ice.PS)
|
||||
} else if ice.Info.Make.Path != "" && strings.HasPrefix(dir, ice.Info.Make.Path+ice.PS) {
|
||||
dir = strings.TrimPrefix(dir, ice.Info.Make.Path+ice.PS)
|
||||
}
|
||||
} else if nfs.ExistsFile(ice.Pulse, path.Join(ice.SRC, dir)) {
|
||||
dir = path.Join(ice.SRC, dir)
|
||||
}
|
||||
return path.Join(ice.PS, ice.REQUIRE, dir)
|
||||
}
|
||||
func FileCmd(dir string) string { return FileURI(kit.ExtChange(strings.Split(dir, ice.DF)[0], nfs.GO)) }
|
||||
func AddFileCmd(dir, key string) { ice.Info.File[FileCmd(dir)] = key }
|
||||
func IsOrderCmd(key string) bool { return key[0] == '/' || key[0] == '_' }
|
||||
func GetFileCmd(dir string) string {
|
||||
if strings.HasPrefix(dir, ice.REQUIRE+ice.PS) {
|
||||
dir = ice.PS + dir
|
||||
if strings.HasPrefix(dir, ice.REQUIRE+nfs.PS) {
|
||||
dir = nfs.PS + dir
|
||||
} else if strings.HasPrefix(dir, ice.ISH_PLUGED) {
|
||||
dir = path.Join(ice.PS, ice.REQUIRE, strings.TrimPrefix(dir, ice.ISH_PLUGED))
|
||||
dir = path.Join(nfs.P, strings.TrimPrefix(dir, ice.ISH_PLUGED))
|
||||
}
|
||||
for _, dir := range []string{dir, path.Join(ice.PS, ice.REQUIRE, ice.Info.Make.Module, dir), path.Join(ice.PS, ice.REQUIRE, ice.Info.Make.Module, ice.SRC, dir)} {
|
||||
for _, dir := range []string{dir, path.Join(nfs.P, ice.Info.Make.Module, dir), path.Join(nfs.P, ice.Info.Make.Module, ice.SRC, dir)} {
|
||||
if cmd, ok := ice.Info.File[FileCmd(dir)]; ok {
|
||||
return cmd
|
||||
}
|
||||
p := path.Dir(dir)
|
||||
if cmd, ok := ice.Info.File[FileCmd(path.Join(p, path.Base(p)+ice.PT+nfs.GO))]; ok {
|
||||
if cmd, ok := ice.Info.File[FileCmd(path.Join(p, path.Base(p)+nfs.PT+nfs.GO))]; ok {
|
||||
return cmd
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
func GetCmdHelp(m *ice.Message, cmds string) (file string) {
|
||||
file = kit.TrimPrefix(m.FileURI(kit.ExtChange(GetCmdFile(m, cmds), nfs.SHY)), nfs.P, nfs.REQUIRE)
|
||||
if !nfs.Exists(m, path.Join(nfs.USR_LEARNING_PORTAL, "commands", strings.TrimPrefix(file, nfs.USR_ICEBERGS)), func(p string) { file = p }) {
|
||||
kit.If(!nfs.Exists(m, file), func() { file = "" })
|
||||
}
|
||||
return
|
||||
}
|
||||
func GetCmdFile(m *ice.Message, cmds string) (file string) {
|
||||
m.Search(cmds, func(key string, cmd *ice.Command) {
|
||||
if file = strings.TrimPrefix(FileURI(kit.Split(cmd.GetFileLines(), ice.DF)[0]), "/require/"); !nfs.ExistsFile(m, file) {
|
||||
file = path.Join(ice.ISH_PLUGED, file)
|
||||
m.Search(kit.Select(m.PrefixKey(), cmds), func(key string, cmd *ice.Command) {
|
||||
if file = kit.TrimPrefix(m.FileURI(kit.Split(cmd.FileLine(), nfs.DF)[0]), nfs.P); !nfs.Exists(m, file) {
|
||||
file = path.Join(nfs.P, file)
|
||||
}
|
||||
})
|
||||
return
|
||||
@ -199,12 +194,34 @@ func TravelCmd(m *ice.Message, cb func(key, file, line string)) *ice.Message {
|
||||
if IsOrderCmd(key) {
|
||||
return
|
||||
}
|
||||
if ls := kit.Split(cmd.GetFileLines(), ice.DF); len(ls) > 0 && cmd.Name != "" {
|
||||
cb(kit.Keys(s.Cap(ice.CTX_FOLLOW), key), strings.TrimPrefix(ls[0], kit.Path("")+ice.PS), kit.Select("1", ls, 1))
|
||||
if runtime.GOOS == ice.WINDOWS {
|
||||
if ls := kit.Split(cmd.FileLine(), nfs.DF); len(ls) > 2 {
|
||||
cb(kit.Keys(s.Prefix(), key), strings.TrimPrefix(strings.Join(kit.Slice(ls, 0, -1), nfs.DF), kit.Path("")+nfs.PS), kit.Select("1", ls, -1))
|
||||
return
|
||||
}
|
||||
}
|
||||
if ls := kit.Split(cmd.FileLine(), nfs.DF); len(ls) > 0 {
|
||||
cb(kit.Keys(s.Prefix(), key), strings.TrimPrefix(ls[0], kit.Path("")+nfs.PS), kit.Select("1", ls, 1))
|
||||
}
|
||||
})
|
||||
return m
|
||||
}
|
||||
func CmdList(m *ice.Message) *ice.Message {
|
||||
return m.Cmdy(COMMAND, mdb.SEARCH, COMMAND, ice.OptionFields(INDEX))
|
||||
func IsOrderCmd(key string) bool {
|
||||
return key[0] == '/' || key[0] == '_'
|
||||
}
|
||||
func ShortCmd(key string) string {
|
||||
_key := kit.Select("", kit.Split(key, nfs.PT), -1)
|
||||
if _p, ok := ice.Info.Index[_key].(*ice.Context); ok && _p.Prefix(_key) == key {
|
||||
return _key
|
||||
}
|
||||
return key
|
||||
}
|
||||
func ResourceFile(m *ice.Message, file string, arg ...string) string {
|
||||
if kit.HasPrefix(file, nfs.PS, ice.HTTP) {
|
||||
return file
|
||||
} else if nfs.Exists(m, file) {
|
||||
return file
|
||||
} else {
|
||||
return path.Join(path.Dir(GetCmdFile(m, m.PrefixKey())), file)
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import (
|
||||
"strings"
|
||||
|
||||
ice "shylinux.com/x/icebergs"
|
||||
"shylinux.com/x/icebergs/base/lex"
|
||||
"shylinux.com/x/icebergs/base/mdb"
|
||||
"shylinux.com/x/icebergs/base/nfs"
|
||||
kit "shylinux.com/x/toolkits"
|
||||
@ -20,8 +21,10 @@ func _config_only(v ice.Any, arg ...string) bool {
|
||||
if len(v) > len(arg) {
|
||||
return false
|
||||
}
|
||||
for k := range v {
|
||||
if kit.IndexOf(arg, k) == -1 {
|
||||
for k, v := range v {
|
||||
if v, ok := v.(ice.Map); ok && len(v) == 0 {
|
||||
continue
|
||||
} else if kit.IndexOf(arg, k) == -1 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
@ -30,9 +33,17 @@ func _config_only(v ice.Any, arg ...string) bool {
|
||||
return false
|
||||
}
|
||||
func _config_save(m *ice.Message, name string, arg ...string) {
|
||||
if !ice.HasVar() {
|
||||
return
|
||||
}
|
||||
data, msg := ice.Map{}, m.Spawn(m.Source())
|
||||
for _, k := range arg {
|
||||
if v := msg.Confv(k); _config_only(v, mdb.META) {
|
||||
if v := mdb.Confv(msg, k); _config_only(v, mdb.META) && _config_only(kit.Value(v, mdb.META),
|
||||
mdb.IMPORTANT, mdb.EXPIRE, mdb.VENDOR, nfs.SOURCE, nfs.SCRIPT, nfs.PATH, lex.REGEXP,
|
||||
mdb.SHORT, mdb.FIELD, mdb.SHORTS, mdb.FIELDS,
|
||||
mdb.ACTION, mdb.SORT, mdb.TOOLS,
|
||||
"link", "linux", "darwin", "windows",
|
||||
) {
|
||||
continue
|
||||
} else {
|
||||
data[k] = v
|
||||
@ -43,22 +54,23 @@ func _config_save(m *ice.Message, name string, arg ...string) {
|
||||
}
|
||||
if f, _, e := miss.CreateFile(path.Join(ice.VAR_CONF, name)); m.Assert(e) {
|
||||
defer f.Close()
|
||||
if s, e := json.MarshalIndent(data, "", " "); !m.Warn(e) {
|
||||
if _, e := f.Write(s); !m.Warn(e) {
|
||||
if s, e := json.MarshalIndent(data, "", " "); !m.WarnNotValid(e) {
|
||||
if _, e := f.Write(s); !m.WarnNotValid(e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
func _config_load(m *ice.Message, name string, arg ...string) {
|
||||
if !ice.HasVar() {
|
||||
return
|
||||
}
|
||||
if f, e := miss.OpenFile(path.Join(ice.VAR_CONF, name)); e == nil {
|
||||
defer f.Close()
|
||||
data, msg := ice.Map{}, m.Spawn(m.Source())
|
||||
json.NewDecoder(f).Decode(&data)
|
||||
for k, v := range data {
|
||||
msg.Search(k, func(p *ice.Context, s *ice.Context, key string) {
|
||||
if s.Configs[key] == nil {
|
||||
s.Configs[key] = &ice.Config{}
|
||||
}
|
||||
msg.Search(k, func(p *ice.Context, s *ice.Context, key string, conf *ice.Config) {
|
||||
kit.If(s.Configs[key] == nil, func() { s.Configs[key] = &ice.Config{} })
|
||||
s.Configs[key].Value = v
|
||||
})
|
||||
}
|
||||
@ -67,109 +79,87 @@ func _config_load(m *ice.Message, name string, arg ...string) {
|
||||
func _config_make(m *ice.Message, key string, arg ...string) {
|
||||
msg := m.Spawn(m.Source())
|
||||
if len(arg) > 1 {
|
||||
if strings.HasPrefix(arg[1], ice.AT) {
|
||||
arg[1] = msg.Cmdx(nfs.CAT, arg[1][1:])
|
||||
}
|
||||
msg.Confv(key, arg[0], kit.Parse(nil, "", arg[1:]...))
|
||||
kit.If(!kit.IsIn(strings.Split(arg[0], nfs.PT)[0], mdb.META, mdb.HASH, mdb.LIST), func() { arg[0] = kit.Keys(mdb.META, arg[0]) })
|
||||
kit.If(strings.HasPrefix(arg[1], mdb.AT), func() { arg[1] = msg.Cmdx(nfs.CAT, arg[1][1:]) })
|
||||
mdb.Confv(msg, key, arg[0], kit.Parse(nil, "", arg[1:]...))
|
||||
}
|
||||
if len(arg) > 0 {
|
||||
m.Echo(kit.Formats(msg.Confv(key, arg[0])))
|
||||
m.Echo(kit.Formats(mdb.Confv(msg, key, arg[0])))
|
||||
} else {
|
||||
m.Echo(kit.Formats(msg.Confv(key)))
|
||||
m.Echo(kit.Formats(mdb.Confv(msg, key))).StatusTime(mdb.COUNT, kit.Length(mdb.Confv(msg, key, mdb.HASH)))
|
||||
}
|
||||
}
|
||||
func _config_list(m *ice.Message) {
|
||||
for k, v := range m.Source().Configs {
|
||||
if IsOrderCmd(k) {
|
||||
continue
|
||||
if !IsOrderCmd(k) {
|
||||
m.Push(mdb.KEY, k).Push(mdb.NAME, v.Name).Push(mdb.VALUE, kit.Format(v.Value))
|
||||
}
|
||||
m.Push(mdb.KEY, k).Push(mdb.NAME, v.Name).Push(mdb.VALUE, kit.Format(v.Value))
|
||||
}
|
||||
m.Sort(mdb.KEY)
|
||||
}
|
||||
|
||||
const (
|
||||
SAVE = "save"
|
||||
LOAD = "load"
|
||||
)
|
||||
const CONFIG = "config"
|
||||
|
||||
func init() {
|
||||
Index.MergeCommands(ice.Commands{
|
||||
CONFIG: {Name: "config key auto", Help: "配置", Actions: ice.Actions{
|
||||
SAVE: {Hand: func(m *ice.Message, arg ...string) { _config_save(m, arg[0], arg[1:]...) }},
|
||||
LOAD: {Hand: func(m *ice.Message, arg ...string) { _config_load(m, arg[0], arg[1:]...) }},
|
||||
mdb.LIST: {Hand: func(m *ice.Message, arg ...string) {
|
||||
list := []ice.Any{}
|
||||
for _, v := range arg[2:] {
|
||||
list = append(list, v)
|
||||
}
|
||||
m.Confv(arg[0], arg[1], list)
|
||||
nfs.SAVE: {Hand: func(m *ice.Message, arg ...string) { _config_save(m, arg[0], arg[1:]...) }},
|
||||
nfs.LOAD: {Hand: func(m *ice.Message, arg ...string) { _config_load(m, arg[0], arg[1:]...) }},
|
||||
mdb.EXPORT: {Hand: func(m *ice.Message, arg ...string) { m.Cmdy(arg[0], mdb.EXPORT) }},
|
||||
mdb.IMPORT: {Hand: func(m *ice.Message, arg ...string) { m.Cmdy(arg[0], mdb.IMPORT) }},
|
||||
nfs.TRASH: {Hand: func(m *ice.Message, arg ...string) {
|
||||
nfs.Trash(m, path.Join(ice.VAR_DATA, arg[0]))
|
||||
nfs.Trash(m, m.Cmdx(arg[0], mdb.EXPORT))
|
||||
mdb.Conf(m, arg[0], mdb.HASH, "")
|
||||
}},
|
||||
mdb.REMOVE: {Name: "remove key sub", Hand: func(m *ice.Message, arg ...string) {
|
||||
m.Conf(m.Option("key"), m.Option("sub"), "")
|
||||
m.Go(func() { m.Cmd(ice.EXIT, 1) })
|
||||
mdb.CREATE: {Name: "create name value", Hand: func(m *ice.Message, arg ...string) {
|
||||
m.Confv(m.Option(mdb.KEY), kit.Keys(mdb.META, m.Option(mdb.NAME)), m.Option(mdb.VALUE))
|
||||
}},
|
||||
mdb.REMOVE: {Hand: func(m *ice.Message, arg ...string) {
|
||||
m.Confv(m.Option(mdb.KEY), kit.Keys(mdb.META, m.Option(mdb.NAME)), "")
|
||||
}},
|
||||
mdb.MODIFY: {Hand: func(m *ice.Message, arg ...string) {
|
||||
if arg[0] == mdb.VALUE {
|
||||
m.Confv(m.Option(mdb.KEY), kit.Keys(mdb.META, m.Option(mdb.NAME)), arg[1])
|
||||
}
|
||||
}},
|
||||
}, Hand: func(m *ice.Message, arg ...string) {
|
||||
if len(arg) == 0 {
|
||||
_config_list(m)
|
||||
} else {
|
||||
_config_make(m, arg[0], arg[1:]...)
|
||||
m.Action(mdb.CREATE, mdb.IMPORT, mdb.EXPORT, nfs.TRASH)
|
||||
kit.For(mdb.Confv(m, arg[0], mdb.META), func(k, v string) {
|
||||
m.Push(mdb.NAME, k).Push(mdb.VALUE, v).PushButton(mdb.REMOVE)
|
||||
})
|
||||
DisplayStoryJSON(m)
|
||||
}
|
||||
}},
|
||||
})
|
||||
}
|
||||
func init() {
|
||||
AddRunChecker(func(m *ice.Message, cmd, sub string, arg ...string) bool {
|
||||
switch sub {
|
||||
case mdb.SELECT:
|
||||
ProcessFloat(m, CONFIG, cmd)
|
||||
case mdb.REMOVE:
|
||||
m.Cmd(CONFIG, mdb.REMOVE, cmd)
|
||||
default:
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
}
|
||||
func init() {
|
||||
ice.Info.Save = Save
|
||||
ice.Info.Load = Load
|
||||
}
|
||||
func init() { ice.Info.Save = Save; ice.Info.Load = Load }
|
||||
func Save(m *ice.Message, arg ...string) *ice.Message {
|
||||
if len(arg) == 0 {
|
||||
for k := range m.Target().Configs {
|
||||
arg = append(arg, k)
|
||||
}
|
||||
}
|
||||
for i, k := range arg {
|
||||
arg[i] = m.Prefix(k)
|
||||
}
|
||||
return m.Cmd(CONFIG, SAVE, m.Prefix(nfs.JSON), arg)
|
||||
kit.If(len(arg) == 0, func() { arg = kit.SortedKey(m.Target().Configs) })
|
||||
kit.For(arg, func(i int, k string) { arg[i] = strings.Replace(m.Prefix(k), nfs.PS, "", 1) })
|
||||
return m.Cmd(prefix(CONFIG), nfs.SAVE, m.Prefix(nfs.JSON), arg)
|
||||
}
|
||||
func Load(m *ice.Message, arg ...string) *ice.Message {
|
||||
if len(arg) == 0 {
|
||||
for k := range m.Target().Configs {
|
||||
arg = append(arg, k)
|
||||
}
|
||||
}
|
||||
for i, k := range arg {
|
||||
arg[i] = m.Prefix(k)
|
||||
}
|
||||
return m.Cmd(CONFIG, LOAD, m.Prefix(nfs.JSON), arg)
|
||||
kit.If(len(arg) == 0, func() { arg = kit.SortedKey(m.Target().Configs) })
|
||||
kit.For(arg, func(i int, k string) { arg[i] = strings.Replace(m.Prefix(k), nfs.PS, "", 1) })
|
||||
return m.Cmd(prefix(CONFIG), nfs.LOAD, m.Prefix(nfs.JSON), arg)
|
||||
}
|
||||
func ConfAction(args ...ice.Any) ice.Actions {
|
||||
return ice.Actions{ice.CTX_INIT: mdb.AutoConfig(args...)}
|
||||
}
|
||||
func ConfigAuto(m *ice.Message, arg ...string) {
|
||||
if cs := m.Target().Configs; cs[m.CommandKey()] == nil {
|
||||
cs[m.CommandKey()] = &ice.Config{Value: kit.Data()}
|
||||
ice.Info.Load(m, m.CommandKey())
|
||||
}
|
||||
func ConfAction(arg ...ice.Any) ice.Actions {
|
||||
return ice.Actions{ice.CTX_INIT: mdb.AutoConfig(arg...)}
|
||||
}
|
||||
func ConfigFromOption(m *ice.Message, arg ...string) {
|
||||
for _, k := range arg {
|
||||
m.Config(k, kit.Select(m.Config(k), m.Option(k)))
|
||||
if len(arg) == 0 {
|
||||
kit.For(m.Target().Commands[m.CommandKey()].Actions[m.ActionKey()].List, func(value ice.Any) {
|
||||
arg = append(arg, kit.Format(kit.Value(value, mdb.NAME)))
|
||||
})
|
||||
}
|
||||
kit.For(arg, func(k string) { mdb.Config(m, k, kit.Select(mdb.Config(m, k), m.Option(k))) })
|
||||
}
|
||||
func OptionFromConfig(m *ice.Message, arg ...string) string {
|
||||
kit.For(arg, func(k string) { m.Option(k, mdb.Config(m, k)) })
|
||||
return m.Option(arg[0])
|
||||
}
|
||||
|
@ -5,18 +5,16 @@ import (
|
||||
|
||||
ice "shylinux.com/x/icebergs"
|
||||
"shylinux.com/x/icebergs/base/mdb"
|
||||
"shylinux.com/x/icebergs/base/nfs"
|
||||
kit "shylinux.com/x/toolkits"
|
||||
)
|
||||
|
||||
func _context_list(m *ice.Message, sub *ice.Context, name string) {
|
||||
m.Travel(func(p *ice.Context, s *ice.Context) {
|
||||
if name != "" && name != ice.ICE && !strings.HasPrefix(s.Cap(ice.CTX_FOLLOW), name+ice.PT) {
|
||||
if name != "" && name != ice.ICE && !strings.HasPrefix(s.Prefix(), name+nfs.PT) {
|
||||
return
|
||||
}
|
||||
m.Push(mdb.NAME, s.Cap(ice.CTX_FOLLOW))
|
||||
m.Push(mdb.STATUS, s.Cap(ice.CTX_STATUS))
|
||||
m.Push(mdb.STREAM, s.Cap(ice.CTX_STREAM))
|
||||
m.Push(mdb.HELP, s.Help)
|
||||
m.Push(mdb.NAME, s.Prefix()).Push(mdb.HELP, s.Help)
|
||||
})
|
||||
}
|
||||
|
||||
@ -24,11 +22,9 @@ const CONTEXT = "context"
|
||||
|
||||
func init() {
|
||||
Index.MergeCommands(ice.Commands{
|
||||
CONTEXT: {Name: "context name=web action=context,command,config key auto", Help: "模块", Hand: func(m *ice.Message, arg ...string) {
|
||||
if len(arg) == 0 {
|
||||
arg = append(arg, m.Source().Cap(ice.CTX_FOLLOW))
|
||||
}
|
||||
m.Search(arg[0]+ice.PT, func(p *ice.Context, s *ice.Context, key string) {
|
||||
CONTEXT: {Name: "context name=ice action=context,command,config key auto", Help: "模块", Hand: func(m *ice.Message, arg ...string) {
|
||||
kit.If(len(arg) == 0, func() { arg = append(arg, m.Source().Prefix()) })
|
||||
m.Search(arg[0]+nfs.PT, func(p *ice.Context, s *ice.Context) {
|
||||
msg := m.Spawn(s)
|
||||
defer m.Copy(msg)
|
||||
switch kit.Select(CONTEXT, arg, 1) {
|
||||
@ -43,17 +39,3 @@ func init() {
|
||||
}},
|
||||
})
|
||||
}
|
||||
func Inputs(m *ice.Message, field string) bool {
|
||||
switch strings.TrimPrefix(field, "extra.") {
|
||||
case ice.POD:
|
||||
m.Cmdy(ice.SPACE)
|
||||
case ice.CTX:
|
||||
m.Cmdy(CONTEXT)
|
||||
case ice.CMD:
|
||||
m.Cmdy(CONTEXT, kit.Select(m.Option(ice.CTX), m.Option(kit.Keys(mdb.EXTRA, ice.CTX))), COMMAND)
|
||||
case ice.ARG:
|
||||
default:
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
@ -1,9 +1,14 @@
|
||||
package ctx
|
||||
|
||||
import ice "shylinux.com/x/icebergs"
|
||||
import (
|
||||
ice "shylinux.com/x/icebergs"
|
||||
kit "shylinux.com/x/toolkits"
|
||||
)
|
||||
|
||||
const CTX = "ctx"
|
||||
|
||||
var Index = &ice.Context{Name: CTX, Help: "标准模块"}
|
||||
|
||||
func init() { ice.Index.Register(Index, nil, CONTEXT, COMMAND, CONFIG, MESSAGE, OPTION) }
|
||||
func init() { ice.Index.Register(Index, nil, CONTEXT, COMMAND, CONFIG) }
|
||||
|
||||
func prefix(arg ...string) string { return kit.Keys(CTX, arg) }
|
||||
|
@ -2,58 +2,93 @@ package ctx
|
||||
|
||||
import (
|
||||
"path"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
ice "shylinux.com/x/icebergs"
|
||||
"shylinux.com/x/icebergs/base/mdb"
|
||||
"shylinux.com/x/icebergs/base/nfs"
|
||||
"shylinux.com/x/icebergs/base/web/html"
|
||||
kit "shylinux.com/x/toolkits"
|
||||
"shylinux.com/x/toolkits/logs"
|
||||
)
|
||||
|
||||
func Display(m *ice.Message, file string, arg ...ice.Any) *ice.Message {
|
||||
if file == "" {
|
||||
file = kit.Keys(kit.FileName(2), nfs.JS)
|
||||
}
|
||||
if !strings.HasPrefix(file, ice.PS) && !strings.HasPrefix(file, ice.HTTP) {
|
||||
file = path.Join(ice.PS, path.Join(path.Dir(FileURI(logs.FileLines(2))), file))
|
||||
}
|
||||
return DisplayBase(m, file, arg...)
|
||||
func isLocalFile(p string) bool {
|
||||
return !strings.HasPrefix(p, nfs.PS) && !strings.HasPrefix(p, ice.HTTP)
|
||||
}
|
||||
func DisplayTable(m *ice.Message, arg ...ice.Any) *ice.Message {
|
||||
return DisplayBase(m, "/plugin/table.js", arg...)
|
||||
return DisplayBase(m, ice.PLUGIN_TABLE_JS, arg...)
|
||||
}
|
||||
func DisplayTableCard(m *ice.Message, arg ...ice.Any) *ice.Message {
|
||||
return DisplayTable(m, "style", "card")
|
||||
return DisplayTable(m, STYLE, "card")
|
||||
}
|
||||
func DisplayStory(m *ice.Message, file string, arg ...ice.Any) *ice.Message {
|
||||
if file == "" {
|
||||
file = kit.ExtChange(kit.FileName(2), nfs.JS)
|
||||
}
|
||||
if !strings.HasPrefix(file, ice.PS) && !strings.HasPrefix(file, ice.HTTP) {
|
||||
file = path.Join(ice.PLUGIN_STORY, file)
|
||||
}
|
||||
kit.If(file == "", func() { file = kit.Keys(m.CommandKey(), nfs.JS) })
|
||||
kit.If(isLocalFile(file), func() { file = path.Join(ice.PLUGIN_STORY, file) })
|
||||
return DisplayBase(m, file, arg...)
|
||||
}
|
||||
func DisplayInput(m *ice.Message, file string, arg ...ice.Any) *ice.Message {
|
||||
kit.If(file == "", func() { file = kit.Keys(m.CommandKey(), nfs.JS) })
|
||||
kit.If(isLocalFile(file), func() { file = path.Join(ice.PLUGIN_INPUT, file) })
|
||||
return DisplayBase(m, file, arg...)
|
||||
}
|
||||
func DisplayStoryForm(m *ice.Message, arg ...ice.Any) *ice.Message {
|
||||
args := kit.List()
|
||||
for i := range arg {
|
||||
switch v := arg[i].(type) {
|
||||
case string:
|
||||
args = append(args, ice.SplitCmd("list "+v, nil)...)
|
||||
default:
|
||||
trans := kit.Value(m.Commands(m.CommandKey()).Meta, ice.CTX_TRANS)
|
||||
if t := reflect.TypeOf(v); t.Kind() == reflect.Func {
|
||||
name := kit.FuncName(arg[i])
|
||||
args = append(args, kit.Dict(mdb.TYPE, html.BUTTON, mdb.NAME, name, mdb.VALUE, kit.Select(name, kit.Value(trans, name), !m.IsEnglish())))
|
||||
}
|
||||
}
|
||||
}
|
||||
kit.For(args, func(v ice.Map) { m.Push("", v, kit.Split("type,name,value,values,need,action")) })
|
||||
return DisplayStory(m, "form")
|
||||
}
|
||||
func DisplayInputKey(m *ice.Message, arg ...ice.Any) *ice.Message {
|
||||
return DisplayInput(m, "key", arg...)
|
||||
}
|
||||
func DisplayStoryWeight(m *ice.Message, arg ...ice.Any) *ice.Message {
|
||||
return DisplayStory(m, "weight", arg...)
|
||||
}
|
||||
func DisplayStoryPie(m *ice.Message, arg ...ice.Any) *ice.Message {
|
||||
return DisplayStory(m, "pie", arg...)
|
||||
}
|
||||
func DisplayStoryJSON(m *ice.Message, arg ...ice.Any) *ice.Message {
|
||||
return DisplayStory(m, "json", arg...)
|
||||
}
|
||||
func DisplayStorySpide(m *ice.Message, arg ...ice.Any) *ice.Message {
|
||||
return DisplayStory(m, "spide", arg...).StatusTimeCount()
|
||||
return DisplayStory(m, "spide", arg...)
|
||||
}
|
||||
func DisplayStoryChina(m *ice.Message, arg ...ice.Any) *ice.Message {
|
||||
return DisplayStory(m, "china", arg...)
|
||||
}
|
||||
func DisplayStudio(m *ice.Message, cmd ...string) *ice.Message {
|
||||
for i, k := range cmd {
|
||||
kit.If(!strings.Contains(cmd[i], nfs.PT), func() { cmd[i] = m.Prefix(k) })
|
||||
}
|
||||
return DisplayStory(m.Cmdy(COMMAND, cmd), "studio")
|
||||
}
|
||||
func DisplayLocal(m *ice.Message, file string, arg ...ice.Any) *ice.Message {
|
||||
if file == "" {
|
||||
file = path.Join(kit.PathName(2), kit.Keys(kit.FileName(2), ice.JS))
|
||||
}
|
||||
if !strings.HasPrefix(file, ice.PS) && !strings.HasPrefix(file, ice.HTTP) {
|
||||
file = path.Join(ice.PLUGIN_LOCAL, file)
|
||||
}
|
||||
kit.If(file == "", func() { file = strings.ReplaceAll(strings.TrimPrefix(m.PrefixKey(), "web."), nfs.PT, nfs.PS) })
|
||||
kit.If(isLocalFile(file), func() { file = path.Join(ice.PLUGIN_LOCAL, file) })
|
||||
return DisplayBase(m, file, arg...)
|
||||
}
|
||||
func DisplayLocalInner(m *ice.Message, arg ...ice.Any) *ice.Message {
|
||||
return DisplayLocal(m, "code/inner", arg...)
|
||||
}
|
||||
func DisplayBase(m *ice.Message, file string, arg ...ice.Any) *ice.Message {
|
||||
m.Option(ice.MSG_DISPLAY, kit.MergeURL(kit.Select(kit.ExtChange(file, nfs.JS), file, strings.Contains(file, "?")), arg...))
|
||||
m.Option(ice.MSG_DISPLAY, kit.MergeURL(kit.Select(kit.ExtChange(file, nfs.JS), file, strings.Contains(file, mdb.QS)), arg...))
|
||||
return Toolkit(m, "")
|
||||
}
|
||||
func DisplayBaseCSS(m *ice.Message, file string, arg ...ice.Any) *ice.Message {
|
||||
m.Option(ice.MSG_DISPLAY_CSS, kit.MergeURL(kit.Select(kit.ExtChange(file, nfs.CSS), file, strings.Contains(file, mdb.QS)), arg...))
|
||||
return m
|
||||
}
|
||||
func Toolkit(m *ice.Message, arg ...string) {
|
||||
m.Option(ice.MSG_TOOLKIT, kit.Select(m.Config(mdb.TOOLS), kit.Fields(arg)))
|
||||
func Toolkit(m *ice.Message, arg ...string) *ice.Message {
|
||||
m.OptionDefault(ice.MSG_ONLINE, mdb.Config(m, "online"))
|
||||
return m.Options(ice.MSG_TOOLKIT, kit.Select(mdb.Config(m, mdb.TOOLS), kit.Fields(arg)))
|
||||
}
|
||||
|
@ -1,34 +0,0 @@
|
||||
package ctx
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
ice "shylinux.com/x/icebergs"
|
||||
"shylinux.com/x/icebergs/base/mdb"
|
||||
"shylinux.com/x/toolkits/logs"
|
||||
)
|
||||
|
||||
const OPTION = "option"
|
||||
const MESSAGE = "message"
|
||||
|
||||
func init() {
|
||||
Index.MergeCommands(ice.Commands{
|
||||
OPTION: {Name: "option", Help: "选项", Hand: func(m *ice.Message, arg ...string) {
|
||||
if len(arg) > 1 {
|
||||
if msg, ok := m.Optionv("message").(*ice.Message); ok {
|
||||
msg.Option(arg[0], arg[1])
|
||||
}
|
||||
}
|
||||
}},
|
||||
MESSAGE: {Name: "message auto", Help: "消息", Hand: func(m *ice.Message, arg ...string) {
|
||||
t := reflect.TypeOf(m)
|
||||
for i := 0; i < t.NumMethod(); i++ {
|
||||
method := t.Method(i)
|
||||
p := logs.FileLine(method.Func.Interface())
|
||||
m.Push(mdb.NAME, method.Name)
|
||||
m.Push(mdb.TEXT, strings.Split(p, ice.ICEBERGS+ice.PS)[1])
|
||||
}
|
||||
}},
|
||||
})
|
||||
}
|
@ -1,71 +1,61 @@
|
||||
package ctx
|
||||
|
||||
import (
|
||||
"path"
|
||||
|
||||
ice "shylinux.com/x/icebergs"
|
||||
"shylinux.com/x/icebergs/base/aaa"
|
||||
"shylinux.com/x/icebergs/base/web/html"
|
||||
kit "shylinux.com/x/toolkits"
|
||||
)
|
||||
|
||||
const PROCESS = "process"
|
||||
|
||||
var _process = map[string]ice.Any{}
|
||||
|
||||
func AddProcess(key string, val ice.Any) { _process[key] = val }
|
||||
func Process(m *ice.Message, key string, args []string, arg ...string) {
|
||||
switch cb := _process[key].(type) {
|
||||
case func(*ice.Message, []string, ...string):
|
||||
cb(m, args, arg...)
|
||||
func _process_args(m *ice.Message, args ice.Any) []string {
|
||||
switch cb := args.(type) {
|
||||
case []string:
|
||||
return cb
|
||||
case string:
|
||||
if len(arg) == 0 || arg[0] != PROCESS {
|
||||
m.Cmdy(cb, PROCESS, args)
|
||||
m.Optionv(ice.FIELD_PREFIX, kit.Simple(m.ActionKey(), m.Optionv(ice.FIELD_PREFIX)))
|
||||
} else {
|
||||
m.Cmdy(cb, arg)
|
||||
}
|
||||
return []string{cb}
|
||||
case func() string:
|
||||
return []string{cb()}
|
||||
case func() []string:
|
||||
return cb()
|
||||
case func():
|
||||
cb()
|
||||
case nil:
|
||||
default:
|
||||
ProcessField(m, key, args, arg...)
|
||||
m.ErrorNotImplement(args)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func ProcessCommand(m *ice.Message, cmd string, val []string, arg ...string) {
|
||||
if len(arg) > 0 && arg[0] == ice.RUN {
|
||||
m.Cmdy(cmd, arg[1:])
|
||||
} else {
|
||||
m.Cmdy(COMMAND, cmd).Push(ice.ARG, kit.Format(val))
|
||||
m.ProcessField(cmd, ice.RUN)
|
||||
}
|
||||
}
|
||||
func ProcessCommandOpt(m *ice.Message, arg []string, args ...string) {
|
||||
if len(arg) > 0 && arg[0] == ice.RUN {
|
||||
return
|
||||
}
|
||||
m.Push("opt", kit.Format(m.OptionSimple(args...)))
|
||||
}
|
||||
func ProcessFloat(m *ice.Message, arg ...string) {
|
||||
m.Option(ice.MSG_PROCESS, ice.PROCESS_FLOAT)
|
||||
m.Option(ice.PROCESS_ARG, arg)
|
||||
m.Cmdy(COMMAND, arg[0])
|
||||
}
|
||||
func ProcessField(m *ice.Message, cmd string, args []string, arg ...string) {
|
||||
if cmd = kit.Select(m.ActionKey(), cmd); len(arg) == 0 || arg[0] != ice.RUN {
|
||||
m.Option("_index", m.PrefixKey())
|
||||
if m.Cmdy(COMMAND, cmd).ProcessField(ACTION, m.ActionKey(), ice.RUN); len(args) > 0 {
|
||||
m.Push(ARGS, kit.Format(args))
|
||||
}
|
||||
} else {
|
||||
if aaa.Right(m, cmd, arg[1:]) {
|
||||
func ProcessField(m *ice.Message, cmd string, args ice.Any, arg ...string) *ice.Message {
|
||||
if cmd = kit.Select(m.ActionKey(), cmd); kit.HasPrefixList(arg, RUN) {
|
||||
if !PodCmd(m, cmd, arg[1:]) && aaa.Right(m, cmd, arg[1:]) {
|
||||
m.Cmdy(cmd, arg[1:])
|
||||
}
|
||||
return m
|
||||
}
|
||||
}
|
||||
|
||||
func ProcessRefresh(m *ice.Message, arg ...string) { m.ProcessRefresh(arg...) }
|
||||
func ProcessRewrite(m *ice.Message, arg ...ice.Any) { m.ProcessRewrite(arg...) }
|
||||
func ProcessHold(m *ice.Message, text ...ice.Any) { m.Process(ice.PROCESS_HOLD, text...) }
|
||||
func ProcessOpen(m *ice.Message, url string) { m.Process(ice.PROCESS_OPEN, url) }
|
||||
|
||||
func ProcessAction() ice.Actions {
|
||||
return ice.Actions{
|
||||
ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) { AddProcess(m.CommandKey(), m.PrefixKey()) }},
|
||||
PROCESS: {Hand: func(m *ice.Message, arg ...string) { ProcessField(m, m.PrefixKey(), arg, arg...) }},
|
||||
args = kit.Format(_process_args(m, args))
|
||||
if PodCmd(m, COMMAND, cmd) {
|
||||
m.Push(ice.SPACE, m.Option(ice.MSG_USERPOD))
|
||||
} else {
|
||||
m.Cmdy(COMMAND, cmd)
|
||||
}
|
||||
if m.Push(ARGS, args); m.IsMetaKey() {
|
||||
m.Push(STYLE, html.FLOAT)
|
||||
}
|
||||
if m.ActionKey() == "" {
|
||||
m.ProcessField(ACTION, RUN, cmd)
|
||||
} else {
|
||||
m.ProcessField(ACTION, m.ActionKey(), RUN)
|
||||
}
|
||||
return m
|
||||
}
|
||||
func ProcessFloat(m *ice.Message, cmd string, args ice.Any, arg ...string) *ice.Message {
|
||||
if m.IsMetaKey() {
|
||||
m.ProcessOpen(path.Join("/c/", cmd, path.Join(_process_args(m, args)...)))
|
||||
return m
|
||||
} else if !kit.HasPrefixList(arg, RUN) {
|
||||
defer m.Push(STYLE, html.FLOAT)
|
||||
}
|
||||
return ProcessField(m, cmd, args, arg...)
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
package gdb
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
ice "shylinux.com/x/icebergs"
|
||||
"shylinux.com/x/icebergs/base/mdb"
|
||||
kit "shylinux.com/x/toolkits"
|
||||
@ -13,8 +15,6 @@ const (
|
||||
)
|
||||
const EVENT = "event"
|
||||
|
||||
var list map[string]int = map[string]int{}
|
||||
|
||||
func init() {
|
||||
Index.MergeCommands(ice.Commands{
|
||||
EVENT: {Name: "event event id auto listen happen", Help: "事件流", Actions: ice.MergeActions(ice.Actions{
|
||||
@ -25,45 +25,51 @@ func init() {
|
||||
HAPPEN: {Name: "happen event*", Help: "触发", Hand: func(m *ice.Message, arg ...string) {
|
||||
defer m.Cost()
|
||||
m.OptionCB(mdb.SELECT, "")
|
||||
mdb.ZoneSelect(m.Spawn(ice.OptionFields("")), m.Option(EVENT)).Tables(func(value ice.Maps) {
|
||||
m.Cmdy(kit.Split(value[ice.CMD]), m.Option(EVENT), arg[2:], ice.OptionFields(""))
|
||||
mdb.ZoneSelectAll(m.Spawn(ice.OptionFields("")), arg[1]).Table(func(value ice.Maps) {
|
||||
m.Cmdy(kit.Split(value[ice.CMD]), arg[1], arg[2:], ice.OptionFields(""))
|
||||
})
|
||||
_waitMap.Range(func(key, cb ice.Any) bool { cb.(func(*ice.Message, ...string))(m, arg...); return true })
|
||||
}},
|
||||
}, mdb.ZoneAction(mdb.SHORT, EVENT, mdb.FIELD, "time,id,cmd"))},
|
||||
}, mdb.ZoneAction(mdb.SHORT, EVENT, mdb.FIELDS, "time,id,cmd"), mdb.ClearOnExitHashAction())},
|
||||
})
|
||||
}
|
||||
func EventAction(arg ...string) ice.Actions {
|
||||
return ice.Actions{
|
||||
ice.CTX_INIT: {Hand: func(m *ice.Message, _ ...string) {
|
||||
for _, v := range arg {
|
||||
Watch(m, v)
|
||||
}
|
||||
}},
|
||||
}
|
||||
}
|
||||
|
||||
func EventsAction(arg ...string) ice.Actions {
|
||||
list := kit.DictList(arg...)
|
||||
return ice.Actions{ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) {
|
||||
for sub := range m.Target().Commands[m.CommandKey()].Actions {
|
||||
if list[sub] == ice.TRUE {
|
||||
Watch(m, sub)
|
||||
}
|
||||
kit.If(list[sub] == ice.TRUE, func() { Watch(m, sub) })
|
||||
}
|
||||
}}}
|
||||
}
|
||||
|
||||
var list map[string]int = map[string]int{}
|
||||
|
||||
func Watch(m *ice.Message, key string, arg ...string) *ice.Message {
|
||||
if len(arg) == 0 {
|
||||
arg = append(arg, m.PrefixKey())
|
||||
}
|
||||
return m.Cmd(EVENT, LISTEN, EVENT, key, ice.CMD, kit.Join(arg, ice.SP))
|
||||
kit.If(len(arg) == 0, func() { arg = append(arg, m.ShortKey()) })
|
||||
return m.Cmd(Prefix(EVENT), LISTEN, EVENT, key, ice.CMD, kit.Join(arg, ice.SP))
|
||||
}
|
||||
func Event(m *ice.Message, key string, arg ...ice.Any) *ice.Message {
|
||||
if list[key] == 0 {
|
||||
if key = kit.Select(kit.Keys(m.CommandKey(), m.ActionKey()), key); list[key] == 0 {
|
||||
return m
|
||||
}
|
||||
return m.Cmdy(EVENT, HAPPEN, EVENT, kit.Select(kit.Keys(m.CommandKey(), m.ActionKey()), key), arg, logs.FileLineMeta(-1))
|
||||
return m.Cmdy(Prefix(EVENT), HAPPEN, EVENT, key, arg, logs.FileLineMeta(-1))
|
||||
}
|
||||
func EventDeferEvent(m *ice.Message, key string, arg ...ice.Any) func(string, ...ice.Any) {
|
||||
Event(m, key, arg...)
|
||||
return func(key string, args ...ice.Any) { Event(m, key, args...) }
|
||||
}
|
||||
|
||||
var _waitMap = sync.Map{}
|
||||
|
||||
func WaitEvent(m *ice.Message, key string, cb func(*ice.Message, ...string) bool) {
|
||||
wg := sync.WaitGroup{}
|
||||
h := kit.HashsUniq()
|
||||
defer _waitMap.Delete(h)
|
||||
_waitMap.Store(h, func(m *ice.Message, arg ...string) {
|
||||
m.Info("WaitEvent %v %v", key, kit.FileLine(cb, 3))
|
||||
kit.If((key == "" || m.Option(EVENT) == key) && cb(m, arg...), func() { wg.Done() })
|
||||
})
|
||||
wg.Add(1)
|
||||
defer wg.Wait()
|
||||
}
|
||||
|
@ -1,50 +1,56 @@
|
||||
package gdb
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
ice "shylinux.com/x/icebergs"
|
||||
"shylinux.com/x/icebergs/base/mdb"
|
||||
kit "shylinux.com/x/toolkits"
|
||||
"shylinux.com/x/toolkits/logs"
|
||||
)
|
||||
|
||||
type Frame struct{ s chan os.Signal }
|
||||
|
||||
func (f *Frame) Begin(m *ice.Message, arg ...string) ice.Server {
|
||||
f.s = make(chan os.Signal, 3)
|
||||
return f
|
||||
func (f *Frame) Begin(m *ice.Message, arg ...string) {
|
||||
f.s = make(chan os.Signal, 10)
|
||||
}
|
||||
func (f *Frame) Start(m *ice.Message, arg ...string) bool {
|
||||
t := kit.Duration(m.Conf(TIMER, kit.Keym(TICK)))
|
||||
enable := m.Conf(TIMER, kit.Keym("enable")) == ice.TRUE
|
||||
func (f *Frame) Start(m *ice.Message, arg ...string) {
|
||||
if ice.HasVar() {
|
||||
if f, p, e := logs.CreateFile(ice.VAR_LOG_ICE_PID); e == nil {
|
||||
m.Logs("save", "file", p, PID, os.Getpid())
|
||||
fmt.Fprint(f, os.Getpid())
|
||||
f.Close()
|
||||
}
|
||||
}
|
||||
t := time.NewTicker(kit.Duration(mdb.Conf(m, TIMER, kit.Keym(TICK))))
|
||||
for {
|
||||
select {
|
||||
case <-time.Tick(t):
|
||||
if enable {
|
||||
m.Cmd(TIMER, HAPPEN)
|
||||
}
|
||||
case <-t.C:
|
||||
m.Options(ice.LOG_DISABLE, ice.TRUE).Cmd(TIMER, HAPPEN)
|
||||
case s, ok := <-f.s:
|
||||
if !ok {
|
||||
return true
|
||||
return
|
||||
}
|
||||
m.Cmd(SIGNAL, HAPPEN, SIGNAL, s)
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
func (f *Frame) Close(m *ice.Message, arg ...string) bool {
|
||||
func (f *Frame) Close(m *ice.Message, arg ...string) {
|
||||
close(f.s)
|
||||
return true
|
||||
}
|
||||
func (f *Frame) Spawn(m *ice.Message, c *ice.Context, arg ...string) ice.Server {
|
||||
return &Frame{}
|
||||
func (f *Frame) listen(m *ice.Message, s int, arg ...string) {
|
||||
signal.Notify(f.s, syscall.Signal(s))
|
||||
mdb.HashCreate(m, SIGNAL, s, arg)
|
||||
}
|
||||
|
||||
const GDB = "gdb"
|
||||
|
||||
var Index = &ice.Context{Name: GDB, Help: "事件模块", Commands: ice.Commands{
|
||||
ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) { ice.Info.Load(m, TIMER, ROUTINE) }},
|
||||
ice.CTX_EXIT: {Hand: func(m *ice.Message, arg ...string) { ice.Info.Save(m, TIMER, ROUTINE) }},
|
||||
}}
|
||||
var Index = &ice.Context{Name: GDB, Help: "事件模块"}
|
||||
|
||||
func Prefix(arg ...string) string { return kit.Keys(GDB, arg) }
|
||||
|
||||
func init() { ice.Index.Register(Index, &Frame{}, SIGNAL, EVENT, TIMER, ROUTINE) }
|
||||
|
@ -11,30 +11,36 @@ const ROUTINE = "routine"
|
||||
|
||||
func init() {
|
||||
Index.MergeCommands(ice.Commands{
|
||||
ROUTINE: {Name: "routine hash auto prunes", Help: "协程池", Actions: ice.MergeActions(ice.Actions{
|
||||
mdb.CREATE: {Name: "create name", Hand: func(m *ice.Message, arg ...string) {
|
||||
ROUTINE: {Help: "协程池", Actions: ice.MergeActions(ice.Actions{
|
||||
mdb.CREATE: {Name: "create name cmd", Hand: func(m *ice.Message, arg ...string) {
|
||||
m.Go(func() {
|
||||
cb := m.OptionCB("")
|
||||
h := mdb.HashCreate(m, m.OptionSimple(mdb.NAME), mdb.STATUS, START, ice.CMD, logs.FileLines(cb))
|
||||
m.OptionDefault(ice.CMD, logs.FileLine(cb))
|
||||
h := mdb.HashCreate(m, m.OptionSimple(mdb.NAME, ice.CMD), mdb.STATUS, START)
|
||||
defer func() {
|
||||
if e := recover(); e == nil {
|
||||
mdb.HashModify(m, mdb.HASH, h, mdb.STATUS, STOP)
|
||||
mdb.HashRemove(m, mdb.HASH, h)
|
||||
} else {
|
||||
mdb.HashModify(m, mdb.HASH, h, mdb.STATUS, ERROR, ERROR, e)
|
||||
}
|
||||
}()
|
||||
switch cb := cb.(type) {
|
||||
case []string:
|
||||
m.Cmd(kit.Split(kit.Join(cb)))
|
||||
case string:
|
||||
m.Cmd(kit.Split(cb))
|
||||
case []string:
|
||||
m.Cmd(kit.Split(kit.Join(cb)))
|
||||
case func(*ice.Message):
|
||||
cb(m.Spawn(m.Source()))
|
||||
case func():
|
||||
cb()
|
||||
default:
|
||||
m.ErrorNotImplement(cb)
|
||||
}
|
||||
})
|
||||
}, m.Option(mdb.NAME))
|
||||
}},
|
||||
}, mdb.StatusHashAction(mdb.FIELD, "time,hash,status,name,cmd"))},
|
||||
}, mdb.StatusHashAction(mdb.LIMIT, 1000, mdb.LEAST, 500, mdb.FIELD, "time,hash,status,name,cmd"), mdb.ClearOnExitHashAction())},
|
||||
})
|
||||
}
|
||||
func Go(m *ice.Message, cb ice.Any, arg ...string) {
|
||||
m.Cmd(ROUTINE, mdb.CREATE, kit.Select(m.ShortKey(), arg, 0), logs.FileLine(cb), cb)
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
package gdb
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
@ -10,23 +9,18 @@ import (
|
||||
"shylinux.com/x/icebergs/base/mdb"
|
||||
kit "shylinux.com/x/toolkits"
|
||||
"shylinux.com/x/toolkits/file"
|
||||
"shylinux.com/x/toolkits/logs"
|
||||
)
|
||||
|
||||
func _signal_listen(m *ice.Message, s int, arg ...string) {
|
||||
if f, ok := m.Target().Server().(*Frame); ok {
|
||||
signal.Notify(f.s, syscall.Signal(s))
|
||||
mdb.HashCreate(m, SIGNAL, s, arg)
|
||||
f.listen(m, s, arg...)
|
||||
}
|
||||
}
|
||||
func _signal_action(m *ice.Message, arg ...string) {
|
||||
mdb.HashSelect(m.Spawn(), arg...).Tables(func(value ice.Maps) { m.Cmdy(kit.Split(value[ice.CMD])) })
|
||||
mdb.HashSelect(m.Spawn(), arg...).Table(func(value ice.Maps) { m.Cmdy(kit.Split(value[ice.CMD])) })
|
||||
}
|
||||
func _signal_process(m *ice.Message, p string, s os.Signal) {
|
||||
if p == "" {
|
||||
b, _ := file.ReadFile(ice.Info.PidPath)
|
||||
p = string(b)
|
||||
}
|
||||
kit.If(p == "", func() { b, _ := file.ReadFile(ice.VAR_LOG_ICE_PID); p = string(b) })
|
||||
if p, e := os.FindProcess(kit.Int(kit.Select(kit.Format(os.Getpid()), p))); e == nil {
|
||||
p.Signal(s)
|
||||
}
|
||||
@ -47,33 +41,26 @@ const SIGNAL = "signal"
|
||||
|
||||
func init() {
|
||||
Index.MergeCommands(ice.Commands{
|
||||
SIGNAL: {Name: "signal signal auto listen", Help: "信号量", Actions: ice.MergeActions(ice.Actions{
|
||||
ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) {
|
||||
_signal_listen(m, 2, mdb.NAME, "重启", ice.CMD, "exit 1")
|
||||
_signal_listen(m, 3, mdb.NAME, "退出", ice.CMD, "exit 0")
|
||||
if f, p, e := logs.CreateFile(ice.Info.PidPath); e == nil {
|
||||
defer f.Close()
|
||||
fmt.Fprint(f, os.Getpid())
|
||||
m.Logs(mdb.CREATE, PID, p)
|
||||
}
|
||||
}},
|
||||
SIGNAL: {Help: "信号量", Actions: ice.MergeActions(ice.Actions{
|
||||
ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) { _signal_init(m, arg...) }},
|
||||
LISTEN: {Name: "listen signal name cmd", Help: "监听", Hand: func(m *ice.Message, arg ...string) {
|
||||
_signal_listen(m, kit.Int(m.Option(SIGNAL)), arg...)
|
||||
}},
|
||||
HAPPEN: {Name: "happen signal", Help: "触发", Hand: func(m *ice.Message, arg ...string) {
|
||||
_signal_action(m, m.Option(SIGNAL))
|
||||
}},
|
||||
RESTART: {Name: "restart pid", Help: "重启", Hand: func(m *ice.Message, arg ...string) {
|
||||
RESTART: {Name: "restart pid", Hand: func(m *ice.Message, arg ...string) {
|
||||
_signal_process(m, m.Option(PID), syscall.SIGINT)
|
||||
}},
|
||||
STOP: {Name: "stop pid", Help: "停止", Hand: func(m *ice.Message, arg ...string) {
|
||||
STOP: {Name: "stop pid", Hand: func(m *ice.Message, arg ...string) {
|
||||
_signal_process(m, m.Option(PID), syscall.SIGQUIT)
|
||||
}},
|
||||
KILL: {Name: "kill pid signal", Help: "结束", Hand: func(m *ice.Message, arg ...string) {
|
||||
KILL: {Name: "kill pid signal", Hand: func(m *ice.Message, arg ...string) {
|
||||
_signal_process(m, m.Option(PID), syscall.Signal(kit.Int(kit.Select("9", m.Option(SIGNAL)))))
|
||||
}},
|
||||
}, mdb.HashAction(mdb.SHORT, SIGNAL, mdb.FIELD, "time,signal,name,cmd", mdb.ACTION, HAPPEN)), Hand: func(m *ice.Message, arg ...string) {
|
||||
mdb.HashSelect(m, arg...).Sort(SIGNAL)
|
||||
}, mdb.HashAction(mdb.SHORT, SIGNAL, mdb.FIELD, "time,signal,name,cmd", mdb.ACTION, HAPPEN), mdb.ClearOnExitHashAction()), Hand: func(m *ice.Message, arg ...string) {
|
||||
defer kit.If(len(arg) == 0, func() { m.Action(LISTEN) })
|
||||
mdb.HashSelect(m, arg...)
|
||||
}},
|
||||
})
|
||||
}
|
||||
|
24
base/gdb/signal_darwin.go
Normal file
24
base/gdb/signal_darwin.go
Normal file
@ -0,0 +1,24 @@
|
||||
package gdb
|
||||
|
||||
import (
|
||||
"os"
|
||||
"syscall"
|
||||
|
||||
ice "shylinux.com/x/icebergs"
|
||||
"shylinux.com/x/icebergs/base/mdb"
|
||||
kit "shylinux.com/x/toolkits"
|
||||
)
|
||||
|
||||
func _signal_init(m *ice.Message, arg ...string) {
|
||||
_signal_listen(m, 1, mdb.NAME, START, ice.CMD, "runtime")
|
||||
_signal_listen(m, 2, mdb.NAME, RESTART, ice.CMD, "exit 1")
|
||||
_signal_listen(m, 3, mdb.NAME, STOP, ice.CMD, "exit 0")
|
||||
_signal_listen(m, int(syscall.SIGUSR1), mdb.NAME, "info", ice.CMD, "runtime")
|
||||
}
|
||||
func SignalProcess(m *ice.Message, pid string) bool {
|
||||
if proc, err := os.FindProcess(kit.Int(pid)); err == nil && proc.Signal(syscall.SIGUSR1) == nil {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
23
base/gdb/signal_linux.go
Normal file
23
base/gdb/signal_linux.go
Normal file
@ -0,0 +1,23 @@
|
||||
package gdb
|
||||
|
||||
import (
|
||||
"os"
|
||||
"syscall"
|
||||
|
||||
ice "shylinux.com/x/icebergs"
|
||||
"shylinux.com/x/icebergs/base/mdb"
|
||||
kit "shylinux.com/x/toolkits"
|
||||
)
|
||||
|
||||
func _signal_init(m *ice.Message, arg ...string) {
|
||||
_signal_listen(m, 1, mdb.NAME, START, ice.CMD, "runtime")
|
||||
_signal_listen(m, 2, mdb.NAME, RESTART, ice.CMD, "exit 1")
|
||||
_signal_listen(m, 3, mdb.NAME, STOP, ice.CMD, "exit 0")
|
||||
_signal_listen(m, int(syscall.SIGUSR1), mdb.NAME, "info", ice.CMD, "runtime")
|
||||
}
|
||||
func SignalProcess(m *ice.Message, pid string) bool {
|
||||
if proc, err := os.FindProcess(kit.Int(pid)); err == nil && proc.Signal(syscall.SIGUSR1) == nil {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
15
base/gdb/signal_windows.go
Normal file
15
base/gdb/signal_windows.go
Normal file
@ -0,0 +1,15 @@
|
||||
package gdb
|
||||
|
||||
import (
|
||||
ice "shylinux.com/x/icebergs"
|
||||
"shylinux.com/x/icebergs/base/mdb"
|
||||
)
|
||||
|
||||
func _signal_init(m *ice.Message, arg ...string) {
|
||||
_signal_listen(m, 1, mdb.NAME, START, ice.CMD, "runtime")
|
||||
_signal_listen(m, 2, mdb.NAME, RESTART, ice.CMD, "exit 1")
|
||||
_signal_listen(m, 3, mdb.NAME, STOP, ice.CMD, "exit 0")
|
||||
}
|
||||
func SignalProcess(m *ice.Message, pid string) bool {
|
||||
return false
|
||||
}
|
@ -5,19 +5,20 @@ import (
|
||||
|
||||
ice "shylinux.com/x/icebergs"
|
||||
"shylinux.com/x/icebergs/base/mdb"
|
||||
"shylinux.com/x/icebergs/base/web/html"
|
||||
kit "shylinux.com/x/toolkits"
|
||||
)
|
||||
|
||||
func _timer_action(m *ice.Message, now time.Time, arg ...string) {
|
||||
mdb.HashSelects(m).Tables(func(value ice.Maps) {
|
||||
if value[mdb.COUNT] == "0" {
|
||||
mdb.HashSelects(m).Table(func(value ice.Maps) {
|
||||
count := kit.Int(value[mdb.COUNT])
|
||||
if count == 0 || value[mdb.TIME] > now.Format(ice.MOD_TIME) {
|
||||
return
|
||||
}
|
||||
if value[mdb.TIME] > now.Format(ice.MOD_TIME) {
|
||||
return
|
||||
}
|
||||
m.Cmd(ROUTINE, mdb.CREATE, mdb.NAME, value[mdb.NAME], kit.Keycb(ROUTINE), value[ice.CMD])
|
||||
mdb.HashModify(m, mdb.HASH, value[mdb.HASH], mdb.COUNT, kit.Int(value[mdb.COUNT])-1, mdb.TIME, m.Time(value[INTERVAL]))
|
||||
m.Options(ice.LOG_DISABLE, ice.FALSE)
|
||||
m.Cmd(kit.Split(value[ice.CMD])).Cost()
|
||||
kit.If(count < 0, func() { count++ })
|
||||
mdb.HashModify(m, mdb.NAME, value[mdb.NAME], mdb.COUNT, count-1, mdb.TIME, m.Time(value[INTERVAL]))
|
||||
})
|
||||
}
|
||||
|
||||
@ -30,13 +31,22 @@ const TIMER = "timer"
|
||||
|
||||
func init() {
|
||||
Index.MergeCommands(ice.Commands{
|
||||
TIMER: {Name: "timer hash auto create prunes", Help: "定时器", Actions: ice.MergeActions(ice.Actions{
|
||||
TIMER: {Help: "定时器", Meta: kit.Dict(
|
||||
ice.CTX_TRANS, kit.Dict(html.INPUT, kit.Dict(DELAY, "延时", INTERVAL, "间隔", TICK, "周期")),
|
||||
), Actions: ice.MergeActions(ice.Actions{
|
||||
mdb.INPUTS: {Hand: func(m *ice.Message, arg ...string) {
|
||||
switch mdb.HashInputs(m, arg); arg[0] {
|
||||
case mdb.COUNT:
|
||||
m.Push(arg[0], "-1")
|
||||
case ice.CMD:
|
||||
m.Push(arg[0], "cli.procstat insert")
|
||||
}
|
||||
}},
|
||||
mdb.CREATE: {Name: "create name*=hi delay=10ms interval=10s count=3 cmd*=runtime"},
|
||||
mdb.PRUNES: {Hand: func(m *ice.Message, arg ...string) { mdb.HashPrunesValue(m, mdb.COUNT, "0") }},
|
||||
HAPPEN: {Hand: func(m *ice.Message, arg ...string) { _timer_action(m, time.Now(), arg...) }},
|
||||
RESTART: {Name: "restart count=3", Hand: func(m *ice.Message, arg ...string) {
|
||||
mdb.HashModify(m, m.OptionSimple(mdb.HashShort(m)), arg)
|
||||
}},
|
||||
}, mdb.HashAction(mdb.FIELD, "time,hash,name,delay,interval,count,cmd", TICK, "60s"))},
|
||||
}, mdb.HashAction(mdb.SHORT, mdb.NAME, mdb.FIELD, "time,name,delay,interval,count,cmd", TICK, "10s")), Hand: func(m *ice.Message, arg ...string) {
|
||||
mdb.HashSelect(m, arg...).StatusTimeCount(mdb.ConfigSimple(m, TICK))
|
||||
}},
|
||||
})
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package lex
|
||||
|
||||
const (
|
||||
PATTERN = "pattern"
|
||||
EXTREG = "extreg"
|
||||
REGEXP = "regexp"
|
||||
PREFIX = "prefix"
|
||||
SUFFIX = "suffix"
|
||||
|
@ -17,7 +17,7 @@ func _split_tab(text string) (tab int) {
|
||||
case ' ':
|
||||
tab++
|
||||
default:
|
||||
break
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
@ -25,17 +25,16 @@ func _split_tab(text string) (tab int) {
|
||||
func _split_deep(stack []int, text string) ([]int, int) {
|
||||
tab := _split_tab(text)
|
||||
for i := len(stack) - 1; i >= 0; i-- {
|
||||
if tab <= stack[i] {
|
||||
stack = stack[:len(stack)-1]
|
||||
}
|
||||
kit.If(tab <= stack[i], func() { stack = stack[:len(stack)-1] })
|
||||
}
|
||||
stack = append(stack, tab)
|
||||
return stack, len(stack)
|
||||
}
|
||||
func _split_list(m *ice.Message, file string, arg ...string) ice.Map {
|
||||
const DEEP = "_deep"
|
||||
stack, deep := []int{}, 0
|
||||
list, line := kit.List(kit.Data(DEEP, -1)), ""
|
||||
const INDENT = "_indent"
|
||||
stack, indent := []int{}, 0
|
||||
list, line := kit.List(kit.Data(INDENT, -1)), ""
|
||||
err := false
|
||||
m.Cmd(nfs.CAT, file, func(text string) {
|
||||
if strings.TrimSpace(text) == "" {
|
||||
return
|
||||
@ -46,39 +45,44 @@ func _split_list(m *ice.Message, file string, arg ...string) ice.Map {
|
||||
if strings.HasPrefix(strings.TrimSpace(text), "# ") {
|
||||
return
|
||||
}
|
||||
stack, deep = _split_deep(stack, text)
|
||||
data := kit.Data(DEEP, deep)
|
||||
stack, indent = _split_deep(stack, text)
|
||||
data := kit.Data(INDENT, indent)
|
||||
ls := kit.Split(text, m.Option(SPLIT_SPACE), m.Option(SPLIT_BLOCK), m.Option(SPLIT_QUOTE), m.Option(SPLIT_TRANS))
|
||||
if err {
|
||||
return
|
||||
}
|
||||
switch cb := m.OptionCB(SPLIT).(type) {
|
||||
case func(int, []string):
|
||||
cb(deep, ls)
|
||||
cb(indent, ls)
|
||||
case func(int, []string) []string:
|
||||
ls = cb(deep, ls)
|
||||
ls = cb(indent, ls)
|
||||
case func(int, []string, ice.Map, ice.Map):
|
||||
root, _ := kit.Value(list[0], "list.0").(ice.Map)
|
||||
cb(deep, ls, data, root)
|
||||
cb(indent, ls, data, root)
|
||||
case func(int, []string, ice.Map) []string:
|
||||
ls = cb(deep, ls, data)
|
||||
ls = cb(indent, ls, data)
|
||||
case func([]string, ice.Map) []string:
|
||||
ls = cb(ls, data)
|
||||
case func([]string) []string:
|
||||
ls = cb(ls)
|
||||
case func([]string):
|
||||
cb(ls)
|
||||
case func(string, []string):
|
||||
cb(text, ls)
|
||||
case func(int, string, []string):
|
||||
cb(indent, text, ls)
|
||||
case nil:
|
||||
default:
|
||||
err = true
|
||||
m.ErrorNotImplement(cb)
|
||||
}
|
||||
for _, k := range arg {
|
||||
if kit.Value(data, kit.Keym(k), kit.Select("", ls, 0)); len(ls) > 0 {
|
||||
ls = ls[1:]
|
||||
}
|
||||
}
|
||||
for i := 0; i < len(ls)-1; i += 2 {
|
||||
kit.Value(data, kit.Keym(ls[i]), ls[i+1])
|
||||
}
|
||||
kit.For(arg, func(k string) {
|
||||
kit.Value(data, kit.Keym(k), kit.Select("", ls, 0))
|
||||
kit.If(len(ls) > 0, func() { ls = ls[1:] })
|
||||
})
|
||||
kit.For(ls, func(k, v string) { kit.Value(data, kit.Keym(k), v) })
|
||||
for i := len(list) - 1; i >= 0; i-- {
|
||||
if deep > kit.Int(kit.Value(list[i], kit.Keym(DEEP))) {
|
||||
if indent > kit.Int(kit.Value(list[i], kit.Keym(INDENT))) {
|
||||
kit.Value(list[i], kit.Keys(mdb.LIST, "-2"), data)
|
||||
list = append(list, data)
|
||||
break
|
||||
@ -90,25 +94,28 @@ func _split_list(m *ice.Message, file string, arg ...string) ice.Map {
|
||||
return list[0].(ice.Map)
|
||||
}
|
||||
|
||||
const (
|
||||
TB = ice.TB
|
||||
SP = ice.SP
|
||||
NL = ice.NL
|
||||
)
|
||||
const (
|
||||
SPLIT_SPACE = "split.space"
|
||||
SPLIT_BLOCK = "split.block"
|
||||
SPLIT_QUOTE = "split.quote"
|
||||
SPLIT_TRANS = "split.trans"
|
||||
)
|
||||
const PARSE = "parse"
|
||||
const SPLIT = "split"
|
||||
|
||||
func init() {
|
||||
Index.MergeCommands(ice.Commands{
|
||||
SPLIT: {Name: "split path key auto", Help: "分词", Hand: func(m *ice.Message, arg ...string) {
|
||||
if len(arg) == 0 || strings.HasSuffix(arg[0], ice.PS) {
|
||||
if len(arg) == 0 || strings.HasSuffix(arg[0], nfs.PS) {
|
||||
m.Cmdy(nfs.DIR, arg)
|
||||
return
|
||||
} else {
|
||||
m.Echo(kit.Format(_split_list(m, arg[0], kit.Split(kit.Join(arg[1:]))...)))
|
||||
}
|
||||
m.Echo(kit.Format(_split_list(m, arg[0], kit.Split(kit.Join(arg[1:]))...)))
|
||||
}},
|
||||
})
|
||||
}
|
||||
func Split(m *ice.Message, arg ...string) ice.Map {
|
||||
return kit.Value(_split_list(m, arg[0], arg[1:]...), kit.Keys(mdb.LIST, "0")).(ice.Map)
|
||||
}
|
||||
|
13
base/log/bench.go
Normal file
13
base/log/bench.go
Normal file
@ -0,0 +1,13 @@
|
||||
package log
|
||||
|
||||
import (
|
||||
ice "shylinux.com/x/icebergs"
|
||||
)
|
||||
|
||||
const BENCH = "bench"
|
||||
|
||||
func init() {
|
||||
Index.MergeCommands(ice.Commands{
|
||||
BENCH: {Help: "记录", Hand: func(m *ice.Message, arg ...string) {}},
|
||||
})
|
||||
}
|
94
base/log/debug.go
Normal file
94
base/log/debug.go
Normal file
@ -0,0 +1,94 @@
|
||||
package log
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
"unicode"
|
||||
|
||||
ice "shylinux.com/x/icebergs"
|
||||
"shylinux.com/x/icebergs/base/cli"
|
||||
"shylinux.com/x/icebergs/base/ctx"
|
||||
"shylinux.com/x/icebergs/base/lex"
|
||||
"shylinux.com/x/icebergs/base/mdb"
|
||||
"shylinux.com/x/icebergs/base/nfs"
|
||||
kit "shylinux.com/x/toolkits"
|
||||
)
|
||||
|
||||
func _debug_file(k string) string { return ice.VAR_LOG + k + ".log" }
|
||||
|
||||
const DEBUG = "debug"
|
||||
|
||||
func init() {
|
||||
const (
|
||||
LEVEL = "level"
|
||||
)
|
||||
Index.MergeCommands(ice.Commands{
|
||||
DEBUG: {Name: "debug level=error,bench,debug,error,watch offset limit auto reset app doc", Help: "日志", Actions: ice.Actions{
|
||||
"doc": {Help: "文档", Hand: func(m *ice.Message, arg ...string) { m.ProcessOpen("https://pkg.go.dev/std") }},
|
||||
"reset": {Help: "重置", Hand: func(m *ice.Message, arg ...string) {
|
||||
m.Cmd(nfs.CAT, _debug_file(arg[0]), func(line string, index int) { m.ProcessRewrite(mdb.OFFSET, index+2, mdb.LIMIT, 1000) })
|
||||
}},
|
||||
"app": {Hand: func(m *ice.Message, arg ...string) {
|
||||
cli.OpenCmds(m, kit.Format("cd %s", kit.Path("")), "tail -f var/log/bench.log")
|
||||
}},
|
||||
}, Hand: func(m *ice.Message, arg ...string) {
|
||||
r := regexp.MustCompile("{.*}")
|
||||
offset, limit := kit.Int(kit.Select("0", arg, 1)), kit.Int(kit.Select("100", arg, 2))
|
||||
switch arg[0] {
|
||||
case BENCH, ERROR, DEBUG:
|
||||
m.Cmd(nfs.CAT, _debug_file(arg[0]), func(text string, index int) {
|
||||
if index < offset || index >= offset+limit || !strings.Contains(text, kit.Select("", arg, 3)) {
|
||||
return
|
||||
}
|
||||
ls := strings.SplitN(strings.ReplaceAll(strings.ReplaceAll(text, " ", " "), " ", " "), lex.SP, 8)
|
||||
if _, e := time.Parse(kit.Split(ice.MOD_TIMES)[0], ls[0]); e != nil || len(ls) < 8 {
|
||||
m.Push(mdb.TIME, "").Push(ice.LOG_TRACEID, "").Push(mdb.ID, "")
|
||||
m.Push(nfs.PATH, "").Push(nfs.FILE, "").Push(nfs.LINE, "")
|
||||
m.Push(ctx.SHIP, "").Push(LEVEL, "").Push(nfs.CONTENT, text)
|
||||
return
|
||||
}
|
||||
m.Push(mdb.TIME, ls[0]+lex.SP+ls[1]).Push(ice.LOG_TRACEID, ls[3]).Push(mdb.ID, ls[4])
|
||||
m.Push(nfs.PATH, ice.USR_ICEBERGS)
|
||||
if i := strings.LastIndex(ls[7], lex.SP); strings.HasPrefix(ls[7][i+1:], ice.BASE) || strings.HasPrefix(ls[7][i+1:], ice.CORE) || strings.HasPrefix(ls[7][i+1:], ice.MISC) {
|
||||
m.Push(nfs.FILE, strings.TrimSpace(strings.Split(ls[7][i:], nfs.DF)[0]))
|
||||
m.Push(nfs.LINE, strings.TrimSpace(strings.Split(ls[7][i:], nfs.DF)[1]))
|
||||
ls[7] = ls[7][:i]
|
||||
} else if strings.HasPrefix(ls[7][i+1:], ice.USR_ICEBERGS) {
|
||||
m.Push(nfs.FILE, strings.TrimPrefix(strings.TrimSpace(strings.Split(ls[7][i:], nfs.DF)[0]), ice.USR_ICEBERGS))
|
||||
m.Push(nfs.LINE, strings.TrimSpace(strings.Split(ls[7][i:], nfs.DF)[1]))
|
||||
ls[7] = ls[7][:i]
|
||||
} else {
|
||||
m.Push(nfs.FILE, "base/web/serve.go").Push(nfs.LINE, "62")
|
||||
}
|
||||
if ls[6] == ice.LOG_CMDS {
|
||||
_ls := strings.SplitN(ls[5], lex.SP, 2)
|
||||
if ls[6], ls[7] = _ls[0], _ls[1]; !unicode.IsDigit(rune(ls[7][0])) {
|
||||
_ls := strings.SplitN(ls[7], lex.SP, 2)
|
||||
ls[6], ls[7] = ls[6]+lex.SP+_ls[0], _ls[1]
|
||||
}
|
||||
}
|
||||
switch ls[6] {
|
||||
case "recv", "done", "send", "echo":
|
||||
ls[7] += "\n" + kit.Formats(kit.UnMarshal(r.FindString(ls[7])))
|
||||
}
|
||||
m.Push(ctx.SHIP, ls[5]).Push(LEVEL, ls[6]).Push(nfs.CONTENT, ls[7])
|
||||
})
|
||||
case WATCH:
|
||||
m.Cmd(nfs.CAT, ice.VAR_LOG+arg[0]+".log", func(text string, index int) {
|
||||
if index < offset || index >= offset+limit || !strings.Contains(text, kit.Select("", arg, 3)) {
|
||||
return
|
||||
}
|
||||
ls := strings.SplitN(strings.ReplaceAll(strings.ReplaceAll(text, " ", " "), " ", " "), lex.SP, 8)
|
||||
m.Push(mdb.TIME, ls[0]+lex.SP+ls[1]).Push(ice.LOG_TRACEID, ls[3]).Push(mdb.ID, ls[4])
|
||||
i := strings.LastIndex(ls[7], lex.SP)
|
||||
m.Push(nfs.PATH, ice.USR_ICEBERGS)
|
||||
m.Push(nfs.FILE, strings.TrimSpace(strings.Split(ls[7][i:], nfs.DF)[0]))
|
||||
m.Push(nfs.LINE, strings.TrimSpace(strings.Split(ls[7][i:], nfs.DF)[1]))
|
||||
m.Push(ctx.SHIP, ls[5]).Push(LEVEL, ls[6]).Push(nfs.CONTENT, ls[7][:i])
|
||||
})
|
||||
}
|
||||
m.StatusTimeCountStats(LEVEL)
|
||||
}},
|
||||
})
|
||||
}
|
@ -11,7 +11,7 @@ const ERROR = "error"
|
||||
|
||||
func init() {
|
||||
Index.MergeCommands(ice.Commands{
|
||||
ERROR: {Name: "error auto", Help: "错误", Hand: func(m *ice.Message, arg ...string) {
|
||||
ERROR: {Help: "错误", Hand: func(m *ice.Message, arg ...string) {
|
||||
m.Cmdy(nfs.CAT, path.Join(ice.VAR_LOG, "error.log"))
|
||||
}},
|
||||
})
|
||||
|
154
base/log/log.go
154
base/log/log.go
@ -2,9 +2,13 @@ package log
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"path"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
|
||||
ice "shylinux.com/x/icebergs"
|
||||
"shylinux.com/x/icebergs/base/lex"
|
||||
"shylinux.com/x/icebergs/base/mdb"
|
||||
"shylinux.com/x/icebergs/base/nfs"
|
||||
kit "shylinux.com/x/toolkits"
|
||||
@ -12,92 +16,87 @@ import (
|
||||
)
|
||||
|
||||
type Log struct {
|
||||
m *ice.Message
|
||||
p string
|
||||
l string
|
||||
s string
|
||||
c bool
|
||||
p, l, s string
|
||||
}
|
||||
|
||||
type Frame struct{ p chan *Log }
|
||||
|
||||
func (f *Frame) Begin(m *ice.Message, arg ...string) ice.Server {
|
||||
f.p = make(chan *Log, ice.MOD_BUFS)
|
||||
ice.Info.Log = func(m *ice.Message, p, l, s string) { f.p <- &Log{m: m, p: p, l: l, s: s} }
|
||||
return f
|
||||
func (f *Frame) Begin(m *ice.Message, arg ...string) {
|
||||
}
|
||||
func (f *Frame) Start(m *ice.Message, arg ...string) bool {
|
||||
func (f *Frame) Start(m *ice.Message, arg ...string) {
|
||||
if !ice.HasVar() {
|
||||
return
|
||||
}
|
||||
mdb.Confm(m, FILE, nil, func(k string, v ice.Map) {
|
||||
if mdb.Conf(m, k, kit.Keym(mdb.DISABLE)) == ice.TRUE {
|
||||
return
|
||||
}
|
||||
if f, p, e := logs.CreateFile(kit.Format(v[nfs.PATH])); e == nil {
|
||||
m.Logs(nfs.SAVE, nfs.FILE, p)
|
||||
v[FILE] = bufio.NewWriter(f)
|
||||
}
|
||||
})
|
||||
f.p = make(chan *Log, ice.MOD_BUFS)
|
||||
ice.Info.Log = func(m *ice.Message, p, l, s string) {
|
||||
f.p <- &Log{c: m.Option(ice.LOG_DEBUG) == ice.TRUE, p: p, l: l, s: s}
|
||||
}
|
||||
for {
|
||||
select {
|
||||
case l, ok := <-f.p:
|
||||
if !ok {
|
||||
return true
|
||||
return
|
||||
}
|
||||
for _, file := range []string{m.Conf(SHOW, kit.Keys(l.l, FILE)), BENCH} {
|
||||
kit.For([]string{m.Conf(SHOW, kit.Keys(l.l, FILE)), BENCH}, func(file string) {
|
||||
if file == "" {
|
||||
continue
|
||||
return
|
||||
}
|
||||
view := m.Confm(VIEW, m.Conf(SHOW, kit.Keys(l.l, VIEW)))
|
||||
bio := m.Confv(FILE, kit.Keys(file, FILE)).(*bufio.Writer)
|
||||
conf := m.Confv(FILE, file)
|
||||
bio := kit.Value(conf, FILE).(*bufio.Writer)
|
||||
if bio == nil {
|
||||
continue
|
||||
return
|
||||
}
|
||||
bio.WriteString(l.p)
|
||||
bio.WriteString(ice.SP)
|
||||
if ice.Info.Colors == true {
|
||||
if p, ok := view[PREFIX].(string); ok {
|
||||
bio.WriteString(p)
|
||||
}
|
||||
}
|
||||
bio.WriteString(l.l)
|
||||
bio.WriteString(ice.SP)
|
||||
bio.WriteString(l.s)
|
||||
if ice.Info.Colors == true {
|
||||
if p, ok := view[SUFFIX].(string); ok {
|
||||
bio.WriteString(p)
|
||||
}
|
||||
}
|
||||
bio.WriteString(ice.NL)
|
||||
bio.Flush()
|
||||
}
|
||||
defer bio.Flush()
|
||||
defer fmt.Fprintln(bio)
|
||||
fmt.Fprint(bio, l.p, lex.SP)
|
||||
view := mdb.Confm(m, VIEW, m.Conf(SHOW, kit.Keys(l.l, VIEW)))
|
||||
kit.If(ice.Info.Colors || l.c, func() { bio.WriteString(kit.Format(view[PREFIX])) })
|
||||
defer kit.If(ice.Info.Colors || l.c, func() { bio.WriteString(kit.Format(view[SUFFIX])) })
|
||||
fmt.Fprint(bio, l.l, lex.SP, l.s)
|
||||
})
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
func (f *Frame) Close(m *ice.Message, arg ...string) bool {
|
||||
ice.Info.Log = nil
|
||||
close(f.p)
|
||||
return true
|
||||
}
|
||||
func (f *Frame) Spawn(m *ice.Message, c *ice.Context, arg ...string) ice.Server { return &Frame{} }
|
||||
func (f *Frame) Close(m *ice.Message, arg ...string) { ice.Info.Log = nil; close(f.p) }
|
||||
|
||||
const (
|
||||
PREFIX = "prefix"
|
||||
SUFFIX = "suffix"
|
||||
PREFIX = "prefix"
|
||||
SUFFIX = "suffix"
|
||||
TRACEID = "traceid"
|
||||
)
|
||||
const (
|
||||
GREEN = "green"
|
||||
YELLOW = "yellow"
|
||||
RED = "red"
|
||||
)
|
||||
const (
|
||||
BENCH = "bench"
|
||||
TRACE = "trace"
|
||||
)
|
||||
const (
|
||||
FILE = "file"
|
||||
VIEW = "view"
|
||||
SHOW = "show"
|
||||
)
|
||||
const (
|
||||
BENCH_LOG = "bench.log"
|
||||
DEBUG_LOG = "debug.log"
|
||||
ERROR_LOG = "error.log"
|
||||
WATCH_LOG = "watch.log"
|
||||
)
|
||||
const LOG = "log"
|
||||
|
||||
var Index = &ice.Context{Name: LOG, Help: "日志模块", Configs: ice.Configs{
|
||||
FILE: {Name: FILE, Help: "日志文件", Value: kit.Dict(
|
||||
BENCH, kit.Dict(nfs.PATH, path.Join(ice.VAR_LOG, "bench.log"), mdb.LIST, []string{}),
|
||||
WATCH, kit.Dict(nfs.PATH, path.Join(ice.VAR_LOG, "watch.log"), mdb.LIST, []string{
|
||||
mdb.CREATE, mdb.REMOVE, mdb.INSERT, mdb.DELETE, mdb.MODIFY, mdb.SELECT, mdb.EXPORT, mdb.IMPORT,
|
||||
}),
|
||||
ERROR, kit.Dict(nfs.PATH, path.Join(ice.VAR_LOG, "error.log"), mdb.LIST, []string{ice.LOG_WARN, ice.LOG_ERROR}),
|
||||
TRACE, kit.Dict(nfs.PATH, path.Join(ice.VAR_LOG, "trace.log"), mdb.LIST, []string{ice.LOG_DEBUG}),
|
||||
BENCH, kit.Dict(nfs.PATH, path.Join(ice.VAR_LOG, BENCH_LOG), mdb.LIST, []string{}),
|
||||
DEBUG, kit.Dict(nfs.PATH, path.Join(ice.VAR_LOG, DEBUG_LOG), mdb.LIST, []string{ice.LOG_DEBUG}),
|
||||
ERROR, kit.Dict(nfs.PATH, path.Join(ice.VAR_LOG, ERROR_LOG), mdb.LIST, []string{ice.LOG_WARN, ice.LOG_ERROR}),
|
||||
WATCH, kit.Dict(nfs.PATH, path.Join(ice.VAR_LOG, WATCH_LOG), mdb.LIST, []string{mdb.CREATE, mdb.REMOVE, mdb.INSERT, mdb.DELETE, mdb.MODIFY, mdb.EXPORT, mdb.IMPORT}),
|
||||
)},
|
||||
VIEW: {Name: VIEW, Help: "日志格式", Value: kit.Dict(
|
||||
GREEN, kit.Dict(PREFIX, "\033[32m", SUFFIX, "\033[0m", mdb.LIST, []string{ice.CTX_START, ice.LOG_CMDS}),
|
||||
@ -107,19 +106,48 @@ var Index = &ice.Context{Name: LOG, Help: "日志模块", Configs: ice.Configs{
|
||||
SHOW: {Name: SHOW, Help: "日志分流", Value: kit.Dict()},
|
||||
}, Commands: ice.Commands{
|
||||
ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) {
|
||||
m.Confm(VIEW, nil, func(key string, value ice.Map) {
|
||||
kit.Fetch(value[mdb.LIST], func(index int, k string) { m.Conf(SHOW, kit.Keys(k, VIEW), key) })
|
||||
ice.Info.Load(m)
|
||||
mdb.Confm(m, FILE, nil, func(key string, value ice.Map) {
|
||||
kit.For(value[mdb.LIST], func(index int, k string) { m.Conf(SHOW, kit.Keys(k, FILE), key) })
|
||||
})
|
||||
m.Confm(FILE, nil, func(key string, value ice.Map) {
|
||||
kit.Fetch(value[mdb.LIST], func(index int, k string) { m.Conf(SHOW, kit.Keys(k, FILE), key) })
|
||||
if f, p, e := logs.CreateFile(kit.Format(value[nfs.PATH])); e == nil {
|
||||
m.Cap(ice.CTX_STREAM, path.Base(p))
|
||||
value[FILE] = bufio.NewWriter(f)
|
||||
m.Logs(mdb.CREATE, nfs.FILE, p)
|
||||
}
|
||||
mdb.Confm(m, VIEW, nil, func(key string, value ice.Map) {
|
||||
kit.For(value[mdb.LIST], func(index int, k string) { m.Conf(SHOW, kit.Keys(k, VIEW), key) })
|
||||
})
|
||||
}},
|
||||
ice.CTX_EXIT: {Hand: func(m *ice.Message, arg ...string) {}},
|
||||
ice.CTX_EXIT: {Hand: func(m *ice.Message, arg ...string) {
|
||||
ice.Info.Save(m)
|
||||
}},
|
||||
}}
|
||||
|
||||
func init() { ice.Index.Register(Index, &Frame{}, TAIL) }
|
||||
|
||||
func init() {
|
||||
ice.Info.Traceid = "short"
|
||||
ice.Pulse.Option("work.id", "0")
|
||||
ice.Pulse.Option("task.id", "0")
|
||||
ice.Pulse.Option(ice.LOG_TRACEID, Traceid(ice.Pulse))
|
||||
}
|
||||
|
||||
var _trace_count int64
|
||||
|
||||
func Traceid(m *ice.Message) (traceid string) {
|
||||
ls := []string{}
|
||||
kit.For(kit.Split(ice.Info.Traceid), func(key string) {
|
||||
switch key {
|
||||
case "short":
|
||||
if len(ls) == 0 {
|
||||
ls = append(ls, kit.Hashs(mdb.UNIQ)[:6])
|
||||
}
|
||||
case "long":
|
||||
if len(ls) == 0 {
|
||||
ls = append(ls, kit.Hashs(mdb.UNIQ))
|
||||
}
|
||||
case "node":
|
||||
ls = append(ls, ice.Info.NodeName)
|
||||
case "hide":
|
||||
ls = ls[:0]
|
||||
}
|
||||
})
|
||||
kit.If(len(ls) > 0, func() { ls = append(ls, kit.Format(atomic.AddInt64(&_trace_count, 1))) })
|
||||
return strings.Join(ls, "-")
|
||||
}
|
||||
|
@ -1,9 +1,6 @@
|
||||
package log
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"io"
|
||||
|
||||
ice "shylinux.com/x/icebergs"
|
||||
"shylinux.com/x/icebergs/base/cli"
|
||||
"shylinux.com/x/icebergs/base/mdb"
|
||||
@ -13,8 +10,8 @@ import (
|
||||
|
||||
func _tail_create(m *ice.Message, arg ...string) {
|
||||
h := mdb.HashCreate(m, arg)
|
||||
kit.Fetch(kit.Split(m.Option(FILE)), func(file string) {
|
||||
m.Options(cli.CMD_OUTPUT, Pipe(m, func(text string) { mdb.ZoneInsert(m, h, FILE, file, nfs.SIZE, len(text), mdb.TEXT, text) }), mdb.CACHE_CLEAR_ON_EXIT, ice.TRUE)
|
||||
kit.For(kit.Split(m.Option(nfs.FILE)), func(file string) {
|
||||
m.Options(cli.CMD_OUTPUT, nfs.Pipe(m, func(text string) { mdb.ZoneInsert(m, h, nfs.FILE, file, nfs.SIZE, len(text), mdb.TEXT, text) }), mdb.CACHE_CLEAR_ONEXIT, ice.TRUE)
|
||||
m.Cmd(cli.DAEMON, TAIL, "-n", "0", "-f", file)
|
||||
})
|
||||
}
|
||||
@ -23,30 +20,21 @@ const TAIL = "tail"
|
||||
|
||||
func init() {
|
||||
Index.MergeCommands(ice.Commands{
|
||||
TAIL: {Name: "tail name id auto page create", Help: "日志流", Actions: ice.MergeActions(ice.Actions{
|
||||
TAIL: {Name: "tail name id auto page", Help: "日志流", Actions: ice.MergeActions(ice.Actions{
|
||||
ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) {
|
||||
mdb.HashSelect(m.Spawn(ice.OptionFields("name,file"))).Tables(func(value ice.Maps) {
|
||||
mdb.HashSelect(m.Spawn(ice.OptionFields("name,file"))).Table(func(value ice.Maps) {
|
||||
m.Cmd("", mdb.CREATE, kit.SimpleKV("name,file", value))
|
||||
})
|
||||
}},
|
||||
mdb.INPUTS: {Hand: func(m *ice.Message, arg ...string) {
|
||||
switch arg[0] {
|
||||
case mdb.NAME:
|
||||
m.Push(arg[0], kit.Split(m.Option(FILE), ice.PS))
|
||||
case FILE:
|
||||
m.Cmdy(nfs.DIR, kit.Select(nfs.PWD, arg, 1), nfs.PATH).RenameAppend(nfs.PATH, FILE).ProcessAgain()
|
||||
m.Push(arg[0], kit.Split(m.Option(FILE), nfs.PS))
|
||||
case nfs.FILE:
|
||||
m.Cmdy(nfs.DIR, kit.Select(nfs.PWD, arg, 1), nfs.PATH).RenameAppend(nfs.PATH, nfs.FILE).ProcessAgain()
|
||||
}
|
||||
}},
|
||||
mdb.CREATE: {Hand: func(m *ice.Message, arg ...string) { _tail_create(m, arg...) }},
|
||||
}, mdb.PageZoneAction(mdb.SHORT, mdb.NAME, mdb.FIELDS, "time,name,file,count", mdb.FIELD, "time,id,file,size,text"))},
|
||||
}, mdb.PageZoneAction(mdb.SHORT, mdb.NAME, mdb.FIELD, "time,name,file,count", mdb.FIELDS, "time,id,file,size,text"))},
|
||||
})
|
||||
}
|
||||
func Pipe(m *ice.Message, cb func(string)) io.WriteCloser {
|
||||
r, w := io.Pipe()
|
||||
m.Go(func() {
|
||||
for bio := bufio.NewScanner(r); bio.Scan(); {
|
||||
cb(bio.Text())
|
||||
}
|
||||
})
|
||||
return w
|
||||
}
|
||||
|
@ -2,9 +2,10 @@ package log
|
||||
|
||||
import (
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
ice "shylinux.com/x/icebergs"
|
||||
"shylinux.com/x/icebergs/base/ctx"
|
||||
"shylinux.com/x/icebergs/base/lex"
|
||||
"shylinux.com/x/icebergs/base/mdb"
|
||||
"shylinux.com/x/icebergs/base/nfs"
|
||||
kit "shylinux.com/x/toolkits"
|
||||
@ -14,22 +15,15 @@ const WATCH = "watch"
|
||||
|
||||
func init() {
|
||||
Index.MergeCommands(ice.Commands{
|
||||
WATCH: {Name: "watch auto", Help: "记录", Hand: func(m *ice.Message, arg ...string) {
|
||||
operate := map[string]int{}
|
||||
for _, line := range strings.Split(m.Cmdx(nfs.CAT, path.Join(ice.VAR_LOG, "watch.log")), ice.NL) {
|
||||
ls := kit.Split(line, "", " ", " ")
|
||||
if len(ls) < 5 {
|
||||
continue
|
||||
}
|
||||
m.Push(mdb.TIME, ls[0]+ice.SP+ls[1])
|
||||
m.Push("order", ls[2])
|
||||
m.Push("ship", ls[3])
|
||||
m.Push("source", kit.Slice(ls, -1)[0])
|
||||
m.Push("operate", ls[4])
|
||||
m.Push("content", kit.Join(kit.Slice(ls, 5, -1), ice.SP))
|
||||
operate[ls[4]]++
|
||||
}
|
||||
m.StatusTimeCount(operate)
|
||||
WATCH: {Help: "记录", Hand: func(m *ice.Message, arg ...string) {
|
||||
stats := map[string]int{}
|
||||
m.Cmd(nfs.CAT, path.Join(ice.VAR_LOG, "watch.log"), func(text string) {
|
||||
ls := kit.Split(text)
|
||||
m.Push(mdb.TIME, ls[0]+lex.SP+ls[1]).Push(mdb.ID, ls[2]).Push(nfs.SOURCE, kit.Slice(ls, -1)[0])
|
||||
m.Push(ctx.SHIP, ls[3]).Push("operate", ls[4]).Push(nfs.CONTENT, kit.Join(kit.Slice(ls, 5, -1), lex.SP))
|
||||
stats[ls[4]]++
|
||||
})
|
||||
m.StatusTimeCount(stats)
|
||||
}},
|
||||
})
|
||||
}
|
||||
|
333
base/mdb/hash.go
333
base/mdb/hash.go
@ -3,9 +3,12 @@ package mdb
|
||||
import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
ice "shylinux.com/x/icebergs"
|
||||
"shylinux.com/x/icebergs/base/web/html"
|
||||
kit "shylinux.com/x/toolkits"
|
||||
"shylinux.com/x/toolkits/logs"
|
||||
"shylinux.com/x/toolkits/miss"
|
||||
@ -18,12 +21,10 @@ func _hash_inputs(m *ice.Message, prefix, chain string, field, value string) {
|
||||
list := map[string]int{}
|
||||
defer func() {
|
||||
delete(list, "")
|
||||
for k, i := range list {
|
||||
m.Push(field, k).Push(COUNT, i)
|
||||
}
|
||||
kit.For(list, func(k string, i int) { m.Push(field, k).Push(COUNT, i) })
|
||||
m.SortIntR(COUNT)
|
||||
}()
|
||||
defer RLock(m, prefix, chain)()
|
||||
defer RLock(m, prefix)()
|
||||
Richs(m, prefix, chain, FOREACH, func(key string, value Map) {
|
||||
value = kit.GetMeta(value)
|
||||
list[kit.Format(value[field])] += kit.Int(kit.Select("1", value[COUNT]))
|
||||
@ -31,97 +32,119 @@ func _hash_inputs(m *ice.Message, prefix, chain string, field, value string) {
|
||||
}
|
||||
func _hash_insert(m *ice.Message, prefix, chain string, arg ...string) string {
|
||||
m.Logs(INSERT, KEY, path.Join(prefix, chain), arg)
|
||||
defer Lock(m, prefix, chain)()
|
||||
if expire := m.Conf(prefix, kit.Keys(chain, kit.Keym(EXPIRE))); expire != "" {
|
||||
defer Lock(m, prefix)()
|
||||
if expire := m.Conf(prefix, kit.Keys(chain, kit.Keym(EXPIRE))); expire != "" && arg[0] != HASH {
|
||||
arg = kit.Simple(TIME, m.Time(expire), arg)
|
||||
}
|
||||
return m.Echo(Rich(m, prefix, chain, kit.Data(arg, TARGET, m.Optionv(TARGET)))).Result()
|
||||
if arg[0] == HASH {
|
||||
m.Echo(arg[1]).Conf(prefix, kit.Keys(chain, HASH, arg[1]), kit.Data(arg[2:]))
|
||||
} else {
|
||||
if target, ok := m.Optionv(TARGET).([]string); ok && len(target) == 0 {
|
||||
m.Echo(Rich(m, prefix, chain, kit.Data(arg)))
|
||||
} else {
|
||||
m.Echo(Rich(m, prefix, chain, kit.Data(arg, TARGET, m.Optionv(TARGET))))
|
||||
}
|
||||
}
|
||||
saveImportant(m, prefix, chain, kit.Simple(INSERT, prefix, chain, HASH, HASH, m.Result(), TIME, m.Time(), arg)...)
|
||||
return m.Result()
|
||||
}
|
||||
func _hash_delete(m *ice.Message, prefix, chain, field, value string) {
|
||||
defer Lock(m, prefix, chain)()
|
||||
defer Lock(m, prefix)()
|
||||
Richs(m, prefix, chain, value, func(key string, val Map) {
|
||||
if target, ok := kit.GetMeta(val)[TARGET].(io.Closer); ok {
|
||||
target.Close()
|
||||
}
|
||||
m.Logs(DELETE, KEY, path.Join(prefix, chain), field, value, VALUE, kit.Format(val))
|
||||
m.Conf(prefix, kit.Keys(chain, HASH, key), "")
|
||||
saveImportant(m, prefix, chain, kit.Simple(DELETE, prefix, chain, HASH, HASH, key)...)
|
||||
})
|
||||
}
|
||||
func _hash_modify(m *ice.Message, prefix, chain string, field, value string, arg ...string) {
|
||||
m.Logs(MODIFY, KEY, path.Join(prefix, chain), field, value, arg)
|
||||
defer Lock(m, prefix, chain)()
|
||||
Richs(m, prefix, chain, value, func(key string, val Map) { _mdb_modify(m, val, field, arg...) })
|
||||
defer Lock(m, prefix)()
|
||||
Richs(m, prefix, chain, value, func(key string, val Map) {
|
||||
_mdb_modify(m, val, field, arg...)
|
||||
saveImportant(m, prefix, chain, kit.Simple(MODIFY, prefix, chain, HASH, HASH, key, arg)...)
|
||||
})
|
||||
}
|
||||
func _hash_select(m *ice.Message, prefix, chain, field, value string) {
|
||||
if field == HASH && value == RANDOM {
|
||||
value = RANDOMS
|
||||
}
|
||||
defer m.SortTimeR(TIME)
|
||||
kit.If(field == HASH && value == RANDOM, func() { value = RANDOMS })
|
||||
defer m.SortStrR(TIME)
|
||||
fields := _hash_fields(m)
|
||||
defer RLock(m, prefix, chain)()
|
||||
Richs(m, prefix, chain, value, func(key string, value Map) { _mdb_select(m, m.OptionCB(""), key, value, fields, nil) })
|
||||
defer RLock(m, prefix)()
|
||||
if strings.Contains(value, ",") {
|
||||
kit.For(kit.Split(value), func(value string) {
|
||||
Richs(m, prefix, chain, value, func(key string, value Map) { _mdb_select(m, m.OptionCB(""), key, value, fields, nil) })
|
||||
})
|
||||
} else {
|
||||
Richs(m, prefix, chain, value, func(key string, value Map) { _mdb_select(m, m.OptionCB(""), key, value, fields, nil) })
|
||||
}
|
||||
}
|
||||
func _hash_select_field(m *ice.Message, prefix, chain string, key string, field string) (value string) {
|
||||
defer RLock(m, prefix, chain)()
|
||||
Richs(m, prefix, chain, key, func(key string, val Map) {
|
||||
if field == HASH {
|
||||
value = key
|
||||
} else {
|
||||
value = kit.Format(val[field])
|
||||
}
|
||||
})
|
||||
defer RLock(m, prefix)()
|
||||
Richs(m, prefix, chain, key, func(key string, val Map) { value = kit.Select(kit.Format(val[field]), key, field == HASH) })
|
||||
return
|
||||
}
|
||||
func _hash_prunes(m *ice.Message, prefix, chain string, arg ...string) {
|
||||
fields := _hash_fields(m)
|
||||
defer RLock(m, prefix, chain)()
|
||||
kit.If(kit.IndexOf(fields, HASH) == -1, func() { fields = append(fields, HASH) })
|
||||
defer RLock(m, prefix)()
|
||||
Richs(m, prefix, chain, FOREACH, func(key string, value Map) {
|
||||
switch value = kit.GetMeta(value); cb := m.OptionCB(PRUNES).(type) {
|
||||
switch value = kit.GetMeta(value); cb := m.OptionCB("").(type) {
|
||||
case func(string, Map) bool:
|
||||
if cb(key, value) {
|
||||
m.Push(key, value, fields)
|
||||
}
|
||||
kit.If(cb(key, value), func() { m.Push(key, value, fields) })
|
||||
default:
|
||||
kit.Fetch(arg, func(k, v string) {
|
||||
if value[k] == v || kit.Value(value, k) == v {
|
||||
m.Push(key, value, fields)
|
||||
}
|
||||
kit.For(arg, func(k, v string) {
|
||||
kit.If(value[k] == v || kit.Value(value, k) == v, func() { m.Push(key, value, fields) })
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
func _hash_export(m *ice.Message, prefix, chain, file string) {
|
||||
defer Lock(m, prefix, chain)()
|
||||
if !ice.HasUsr() {
|
||||
return
|
||||
}
|
||||
defer Lock(m, prefix)()
|
||||
if len(Confm(m, prefix, kit.Keys(chain, HASH))) == 0 {
|
||||
return
|
||||
}
|
||||
f, p, e := miss.CreateFile(kit.Keys(file, JSON))
|
||||
m.Assert(e)
|
||||
defer f.Close()
|
||||
defer m.Echo(p)
|
||||
m.Logs(EXPORT, KEY, path.Join(prefix, chain), FILE, p, COUNT, len(m.Confm(prefix, kit.Keys(chain, HASH))))
|
||||
m.Logs(EXPORT, KEY, path.Join(prefix, chain), FILE, p)
|
||||
en := json.NewEncoder(f)
|
||||
if en.SetIndent("", " "); !m.Warn(en.Encode(m.Confv(prefix, kit.Keys(chain, HASH))), EXPORT, prefix) {
|
||||
m.Conf(prefix, kit.Keys(chain, HASH), "")
|
||||
if en.SetIndent("", " "); !m.WarnNotValid(en.Encode(m.Confv(prefix, kit.Keys(chain, HASH))), EXPORT, prefix) {
|
||||
// m.Conf(prefix, kit.Keys(chain, HASH), "")
|
||||
}
|
||||
}
|
||||
func _hash_import(m *ice.Message, prefix, chain, file string) {
|
||||
defer Lock(m, prefix, chain)()
|
||||
if !ice.HasUsr() {
|
||||
return
|
||||
}
|
||||
defer Lock(m, prefix)()
|
||||
f, e := miss.OpenFile(kit.Keys(file, JSON))
|
||||
if m.Warn(e) {
|
||||
if e != nil && !ice.Info.Important {
|
||||
return
|
||||
} else if m.WarnNotFound(e) {
|
||||
return
|
||||
}
|
||||
defer f.Close()
|
||||
list := Map{}
|
||||
m.Assert(json.NewDecoder(f).Decode(&list))
|
||||
m.Logs(IMPORT, KEY, path.Join(prefix, chain), FILE, kit.Keys(file, JSON), COUNT, len(list))
|
||||
defer m.Echo("%d", len(list))
|
||||
for k, data := range list {
|
||||
if m.Confv(prefix, kit.Keys(chain, HASH, k)) == nil {
|
||||
m.Confv(prefix, kit.Keys(chain, HASH, k), data)
|
||||
} else {
|
||||
Rich(m, prefix, chain, data)
|
||||
}
|
||||
}
|
||||
data := Map{}
|
||||
m.Warn(json.NewDecoder(f).Decode(&data))
|
||||
m.Logs(IMPORT, KEY, path.Join(prefix, chain), FILE, kit.Keys(file, JSON), COUNT, len(data))
|
||||
kit.If(m.Confv(prefix, kit.Keys(chain, HASH)) == nil, func() { m.Confv(prefix, kit.Keys(chain, HASH), ice.Map{}) })
|
||||
kit.For(data, func(k string, v Any) { m.Confv(prefix, kit.Keys(chain, HASH, k), v) })
|
||||
m.Echo("%d", len(data))
|
||||
}
|
||||
|
||||
const (
|
||||
MONTH = "720h"
|
||||
DAYS = "72h"
|
||||
HOUR = "1h"
|
||||
|
||||
CACHE_CLEAR_ONEXIT = "cache.clear.onexit"
|
||||
)
|
||||
const (
|
||||
HASH_FIELD = "time,hash,type,name,text"
|
||||
)
|
||||
@ -136,7 +159,7 @@ func HashAction(arg ...Any) ice.Actions {
|
||||
CREATE: {Hand: func(m *ice.Message, arg ...string) { HashCreate(m, arg) }},
|
||||
REMOVE: {Hand: func(m *ice.Message, arg ...string) { HashRemove(m, arg) }},
|
||||
MODIFY: {Hand: func(m *ice.Message, arg ...string) { HashModify(m, arg) }},
|
||||
SELECT: {Name: "select hash auto create", Hand: func(m *ice.Message, arg ...string) { HashSelect(m, arg...) }},
|
||||
SELECT: {Hand: func(m *ice.Message, arg ...string) { HashSelect(m, arg...) }},
|
||||
PRUNES: {Name: "prunes before@date", Hand: func(m *ice.Message, arg ...string) { HashPrunes(m, nil) }},
|
||||
EXPORT: {Hand: func(m *ice.Message, arg ...string) { HashExport(m, arg) }},
|
||||
IMPORT: {Hand: func(m *ice.Message, arg ...string) { HashImport(m, arg) }},
|
||||
@ -144,13 +167,60 @@ func HashAction(arg ...Any) ice.Actions {
|
||||
}
|
||||
func StatusHashAction(arg ...Any) ice.Actions {
|
||||
return ice.MergeActions(ice.Actions{
|
||||
PRUNES: &ice.Action{Hand: func(m *ice.Message, arg ...string) {
|
||||
m.Cmdy(PRUNES, m.PrefixKey(), "", HASH, STATUS, "error", STATUS, "close", STATUS, "stop", STATUS, "end", ice.OptionFields(HashField(m)))
|
||||
PRUNES: &ice.Action{Name: "prunes status", Hand: func(m *ice.Message, arg ...string) {
|
||||
args := []string{}
|
||||
kit.For(kit.Split(m.OptionDefault(STATUS, "error,close,stop,end")), func(s string) { args = append(args, STATUS, s) })
|
||||
m.Cmdy(PRUNES, m.PrefixKey(), m.Option(SUBKEY), HASH, args, ice.OptionFields(HashField(m)))
|
||||
}},
|
||||
}, HashAction(arg...))
|
||||
}
|
||||
func ClearHashOnExitAction() ice.Actions {
|
||||
return ice.MergeActions(ice.Actions{ice.CTX_EXIT: {Hand: func(m *ice.Message, arg ...string) { m.Conf("", HASH, "") }}})
|
||||
func ClearOnExitHashAction() ice.Actions {
|
||||
return ice.Actions{ice.CTX_EXIT: {Hand: func(m *ice.Message, arg ...string) { Conf(m, m.PrefixKey(), HASH, "") }}}
|
||||
}
|
||||
func ExportHashAction(arg ...Any) ice.Actions {
|
||||
return ice.MergeActions(ice.Actions{
|
||||
ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) { Config(m, IMPORTANT, ice.TRUE); HashImport(m, arg) }},
|
||||
ice.CTX_EXIT: {Hand: func(m *ice.Message, arg ...string) { HashExport(m, arg) }},
|
||||
}, HashAction(arg...))
|
||||
}
|
||||
|
||||
const (
|
||||
DEV_REQUEST = "devRequest"
|
||||
DEV_CHOOSE = "devChoose"
|
||||
DEV_RESPONSE = "devResponse"
|
||||
DEV_CONFIRM = "devConfirm"
|
||||
DEV_CREATE = "devCreate"
|
||||
)
|
||||
|
||||
func DevDataAction(fields ...string) ice.Actions {
|
||||
const (
|
||||
DAEMON = "daemon"
|
||||
ORIGIN = "origin"
|
||||
BACK = "back"
|
||||
)
|
||||
return ice.Actions{
|
||||
DEV_REQUEST: {Name: "request origin*", Help: "请求", Icon: "bi bi-cloud-download", Hand: func(m *ice.Message, arg ...string) {
|
||||
back := m.Options(ice.MSG_USERWEB, m.Option(ice.MSG_USERHOST)).MergePod("")
|
||||
m.ProcessOpen(m.Options(ice.MSG_USERWEB, m.Option(ORIGIN), ice.MSG_USERPOD, "").MergePodCmd("", m.PrefixKey(), ACTION, DEV_CHOOSE, BACK, back, DAEMON, m.Option(ice.MSG_DAEMON)))
|
||||
}},
|
||||
DEV_CHOOSE: {Hand: func(m *ice.Message, arg ...string) {
|
||||
HashSelect(m.Options(ice.MSG_FIELDS, kit.Join(fields))).PushAction(DEV_RESPONSE).Options(ice.MSG_ACTION, "")
|
||||
}},
|
||||
DEV_RESPONSE: {Help: "选择", Hand: func(m *ice.Message, arg ...string) {
|
||||
if !m.WarnNotAllow(m.Option(ice.MSG_METHOD) != http.MethodPost) {
|
||||
m.ProcessReplace(m.ParseLink(m.Option(BACK)).MergePodCmd("", m.PrefixKey(), ACTION, DEV_CONFIRM, m.OptionSimple(DAEMON), m.OptionSimple(fields...)))
|
||||
}
|
||||
}},
|
||||
DEV_CONFIRM: {Hand: func(m *ice.Message, arg ...string) {
|
||||
m.EchoInfoButton(kit.JoinWord(m.PrefixKey(), m.Cmdx("nfs.cat", "src/template/mdb.hash/savefrom.html"), m.Option(kit.Split(fields[0])[0])), DEV_CREATE)
|
||||
}},
|
||||
DEV_CREATE: {Help: "创建", Hand: func(m *ice.Message, arg ...string) {
|
||||
if !m.WarnNotAllow(m.Option(ice.MSG_METHOD) != http.MethodPost) {
|
||||
defer kit.If(m.Option(DAEMON), func(p string) { m.Cmd("space", p, "refresh") })
|
||||
HashCreate(m.ProcessClose(), m.OptionSimple(fields...))
|
||||
}
|
||||
}},
|
||||
}
|
||||
}
|
||||
|
||||
func HashKey(m *ice.Message) string {
|
||||
@ -160,53 +230,75 @@ func HashKey(m *ice.Message) string {
|
||||
return HashShort(m)
|
||||
}
|
||||
func HashShort(m *ice.Message) string {
|
||||
return kit.Select(HASH, m.Config(SHORT), m.Config(SHORT) != UNIQ)
|
||||
if m.Option(SHORT) != "" {
|
||||
return m.Option(SHORT)
|
||||
}
|
||||
short := ""
|
||||
if m.Option(SUBKEY) != "" {
|
||||
if short = Conf(m, m.PrefixKey(), kit.Keys(m.Option(SUBKEY), META, SHORT)); short == "" {
|
||||
short = Config(m, SHORTS)
|
||||
}
|
||||
} else {
|
||||
short = Config(m, SHORT)
|
||||
}
|
||||
return kit.Select(HASH, short, short != UNIQ)
|
||||
}
|
||||
func HashField(m *ice.Message) string {
|
||||
if m.Option(FIELD) != "" {
|
||||
return m.Option(FIELD)
|
||||
}
|
||||
field := ""
|
||||
if m.Option(SUBKEY) != "" {
|
||||
if field = Conf(m, m.PrefixKey(), kit.Keys(m.Option(SUBKEY), META, FIELDS)); field == "" {
|
||||
field = Config(m, FIELDS)
|
||||
}
|
||||
} else {
|
||||
field = Config(m, FIELD)
|
||||
}
|
||||
return kit.Select(HASH_FIELD, field)
|
||||
}
|
||||
func HashField(m *ice.Message) string { return kit.Select(HASH_FIELD, m.Config(FIELD)) }
|
||||
func HashInputs(m *ice.Message, arg ...Any) *ice.Message {
|
||||
return m.Cmdy(INPUTS, m.PrefixKey(), "", HASH, arg)
|
||||
return m.Cmdy(INPUTS, m.PrefixKey(), m.Option(SUBKEY), HASH, arg)
|
||||
}
|
||||
func HashCreate(m *ice.Message, arg ...Any) string {
|
||||
if len(arg) == 0 {
|
||||
arg = append(arg, m.OptionSimple(HashField(m)))
|
||||
}
|
||||
return m.Echo(m.Cmdx(append(kit.List(INSERT, m.PrefixKey(), "", HASH, logs.FileLineMeta(-1)), arg...)...)).Result()
|
||||
kit.If(len(arg) == 0 || len(kit.Simple(arg...)) == 0, func() {
|
||||
arg = append(arg, m.OptionSimple(kit.Filters(kit.Split(HashField(m)), TIME, HASH)...))
|
||||
})
|
||||
kit.If(m.Option(SUBKEY) == "", func() { kit.If(Config(m, SHORTS), func(p string) { arg = append([]ice.Any{SHORT, p}, arg) }) })
|
||||
return m.Echo(m.Cmdx(append(kit.List(INSERT, m.PrefixKey(), m.Option(SUBKEY), HASH, logs.FileLineMeta(-1)), arg...)...)).Result()
|
||||
}
|
||||
func HashRemove(m *ice.Message, arg ...Any) *ice.Message {
|
||||
if args := kit.Simple(arg); len(args) == 0 {
|
||||
if args := kit.Simple(arg...); len(args) == 0 {
|
||||
arg = append(arg, m.OptionSimple(HashKey(m)))
|
||||
} else if len(args) == 1 {
|
||||
arg = kit.List(HashKey(m), args[0])
|
||||
}
|
||||
return m.Cmdy(DELETE, m.PrefixKey(), "", HASH, arg)
|
||||
return m.Cmdy(DELETE, m.PrefixKey(), m.Option(SUBKEY), HASH, arg)
|
||||
}
|
||||
func HashModify(m *ice.Message, arg ...Any) *ice.Message {
|
||||
if args := kit.Simple(arg...); args[0] != HASH && args[0] != HashShort(m) {
|
||||
arg = append(kit.List(m.OptionSimple(HashKey(m))), arg...)
|
||||
}
|
||||
return m.Cmd(MODIFY, m.PrefixKey(), "", HASH, arg)
|
||||
return m.Cmd(MODIFY, m.PrefixKey(), m.Option(SUBKEY), HASH, arg)
|
||||
}
|
||||
func HashSelect(m *ice.Message, arg ...string) *ice.Message {
|
||||
if len(arg) > 0 && arg[0] == FOREACH {
|
||||
if len(arg) > 0 && (arg[0] == FOREACH || strings.Contains(arg[0], ",")) {
|
||||
m.Fields(0, HashField(m))
|
||||
} else {
|
||||
m.Fields(len(kit.Slice(arg, 0, 1)), HashField(m))
|
||||
}
|
||||
m.Cmdy(SELECT, m.PrefixKey(), "", HASH, HashShort(m), arg, logs.FileLineMeta(-1))
|
||||
if m.PushAction(m.Config(ACTION), REMOVE); !m.FieldsIsDetail() {
|
||||
return m.StatusTimeCount()
|
||||
m.Cmdy(SELECT, m.PrefixKey(), m.Option(SUBKEY), HASH, HashShort(m), arg, logs.FileLineMeta(-1))
|
||||
kit.If(kit.Select(Config(m, SHORT), Config(m, SORT)), func(sort string) { kit.If(sort != UNIQ, func() { m.Sort(sort) }) })
|
||||
if m.PushAction(Config(m, ACTION), REMOVE); !m.FieldsIsDetail() {
|
||||
m.Options(ice.TABLE_CHECKBOX, Config(m, html.CHECKBOX))
|
||||
return m.Action(CREATE)
|
||||
}
|
||||
return m.StatusTime()
|
||||
return sortByField(m, HashField(m), arg...)
|
||||
}
|
||||
func HashPrunes(m *ice.Message, cb func(Map) bool) *ice.Message {
|
||||
expire := kit.Select(m.Time("-"+kit.Select("72h", m.Config(EXPIRE))), m.Option("before"))
|
||||
m.OptionCB(PRUNES, func(key string, value Map) bool {
|
||||
if kit.Format(value[TIME]) > expire {
|
||||
return false
|
||||
}
|
||||
return cb == nil || cb(value)
|
||||
})
|
||||
return m.Cmdy(PRUNES, m.PrefixKey(), "", HASH, ice.OptionFields(HashField(m))).StatusTimeCount()
|
||||
expire := kit.Select(m.Time("-"+kit.Select(DAYS, Config(m, EXPIRE))), m.Option("before"))
|
||||
m.OptionCB(PRUNES, func(key string, value Map) bool { return kit.Format(value[TIME]) < expire && (cb == nil || cb(value)) })
|
||||
return m.Cmdy(PRUNES, m.PrefixKey(), "", HASH, ice.OptionFields(HashField(m)))
|
||||
}
|
||||
func HashExport(m *ice.Message, arg ...Any) *ice.Message {
|
||||
return m.Cmdy(EXPORT, m.PrefixKey(), "", HASH, arg)
|
||||
@ -220,48 +312,39 @@ func HashSelects(m *ice.Message, arg ...string) *ice.Message {
|
||||
return HashSelect(m, arg...)
|
||||
}
|
||||
func HashSelectValue(m *ice.Message, cb Any) *ice.Message {
|
||||
m.OptionFields(m.Config(FIELD))
|
||||
defer RLock(m, m.PrefixKey(), "")()
|
||||
m.OptionFields(Config(m, FIELD))
|
||||
defer RLock(m, m.PrefixKey())()
|
||||
Richs(m, m.PrefixKey(), nil, FOREACH, func(key string, value Map) { _mdb_select(m, cb, key, value, nil, nil) })
|
||||
return m
|
||||
}
|
||||
func HashSelectUpdate(m *ice.Message, key string, cb Any) *ice.Message {
|
||||
defer Lock(m, m.PrefixKey(), "")()
|
||||
Richs(m, m.PrefixKey(), nil, key, func(key string, value Map) { _mdb_select(m, cb, key, value, nil, nil) })
|
||||
defer Lock(m, m.PrefixKey())()
|
||||
Richs(m, m.PrefixKey(), nil, kit.Select(FOREACH, key), func(key string, value Map) { _mdb_select(m, cb, key, value, nil, nil) })
|
||||
return m
|
||||
}
|
||||
func HashSelectDetail(m *ice.Message, key string, cb Any) (has bool) {
|
||||
defer RLock(m, m.PrefixKey(), "")()
|
||||
Richs(m, m.PrefixKey(), nil, key, func(key string, value Map) {
|
||||
_mdb_select(m, cb, key, value, nil, nil)
|
||||
has = true
|
||||
})
|
||||
defer RLock(m, m.PrefixKey())()
|
||||
Richs(m, m.PrefixKey(), nil, key, func(key string, value Map) { _mdb_select(m, cb, key, value, nil, nil); has = true })
|
||||
return
|
||||
}
|
||||
func HashSelectDetails(m *ice.Message, key string, cb func(ice.Map) bool) ice.Map {
|
||||
func HashSelectDetails(m *ice.Message, key string, cb func(Map) bool) Map {
|
||||
val := kit.Dict()
|
||||
HashSelectDetail(m, key, func(value ice.Map) {
|
||||
if cb(value) {
|
||||
for k, v := range value {
|
||||
val[k] = v
|
||||
}
|
||||
}
|
||||
})
|
||||
HashSelectDetail(m, key, func(value Map) { kit.If(cb(value), func() { kit.For(value, func(k string, v Any) { val[k] = v }) }) })
|
||||
return val
|
||||
}
|
||||
func HashSelectField(m *ice.Message, key string, field string) (value string) {
|
||||
HashSelectDetail(m, key, func(key string, val ice.Map) {
|
||||
if field == HASH {
|
||||
value = key
|
||||
} else {
|
||||
value = kit.Format(val[field])
|
||||
}
|
||||
})
|
||||
HashSelectDetail(m, key, func(key string, val Map) { value = kit.Select(kit.Format(kit.Value(val, field)), key, field == HASH) })
|
||||
return
|
||||
}
|
||||
func HashSelectTarget(m *ice.Message, key string, create Any) (target Any) {
|
||||
HashSelectUpdate(m, key, func(value ice.Map) {
|
||||
HashSelectUpdate(m, key, func(value Map) {
|
||||
target = value[TARGET]
|
||||
if _target, ok := target.([]string); ok && len(_target) == 0 {
|
||||
target = nil
|
||||
}
|
||||
if _target, ok := target.(List); ok && len(_target) == 0 {
|
||||
target = nil
|
||||
}
|
||||
if _target, ok := target.(Map); ok && len(_target) == 0 {
|
||||
target = nil
|
||||
}
|
||||
@ -269,22 +352,23 @@ func HashSelectTarget(m *ice.Message, key string, create Any) (target Any) {
|
||||
return
|
||||
}
|
||||
switch create := create.(type) {
|
||||
case func(ice.Map) ice.Any:
|
||||
case func(Maps) Any:
|
||||
target = create(kit.ToMaps(value))
|
||||
case func(Map) Any:
|
||||
target = create(value)
|
||||
case func() ice.Any:
|
||||
case func() Any:
|
||||
target = create()
|
||||
default:
|
||||
m.ErrorNotImplement(create)
|
||||
return
|
||||
}
|
||||
value[TARGET] = target
|
||||
})
|
||||
return
|
||||
}
|
||||
func HashSelectClose(m *ice.Message) *ice.Message {
|
||||
HashSelectValue(m, func(value ice.Map) {
|
||||
HashSelectValue(m, func(value Map) {
|
||||
if c, ok := value[TARGET].(io.Closer); ok {
|
||||
c.Close()
|
||||
m.WarnNotValid(c.Close())
|
||||
}
|
||||
delete(value, TARGET)
|
||||
})
|
||||
@ -303,21 +387,36 @@ func HashModifyDeferRemove(m *ice.Message, arg ...Any) func() {
|
||||
}
|
||||
|
||||
func Richs(m *ice.Message, prefix string, chain Any, raw Any, cb Any) (res Map) {
|
||||
cache := m.Confm(prefix, chain)
|
||||
cache := Confm(m, prefix, chain)
|
||||
if cache == nil {
|
||||
return nil
|
||||
}
|
||||
if value := kit.Format(raw); strings.Contains(value, ",") {
|
||||
kit.For(kit.Split(value), func(value string) {
|
||||
res = miss.Richs(path.Join(prefix, kit.Keys(chain)), cache, value, cb)
|
||||
})
|
||||
return
|
||||
}
|
||||
return miss.Richs(path.Join(prefix, kit.Keys(chain)), cache, raw, cb)
|
||||
|
||||
}
|
||||
func Rich(m *ice.Message, prefix string, chain Any, data Any) string {
|
||||
cache := m.Confm(prefix, chain)
|
||||
if cache == nil {
|
||||
cache = kit.Data()
|
||||
m.Confv(prefix, chain, cache)
|
||||
}
|
||||
if m.Option(SHORT) != "" {
|
||||
kit.Value(cache, kit.Keym(SHORT), m.Option(SHORT))
|
||||
}
|
||||
cache := Confm(m, prefix, chain)
|
||||
kit.If(cache == nil, func() { cache = kit.Data(); m.Confv(prefix, chain, cache) })
|
||||
return miss.Rich(path.Join(prefix, kit.Keys(chain)), cache, data)
|
||||
}
|
||||
func sortByField(m *ice.Message, fields string, arg ...string) *ice.Message {
|
||||
return m.Table(func(value ice.Maps) {
|
||||
m.SetAppend().FieldsSetDetail()
|
||||
kit.For(kit.Split(fields), func(key string) {
|
||||
key = strings.TrimSuffix(key, "*")
|
||||
if key == HASH {
|
||||
m.Push(key, kit.Select(value[key], arg, 0))
|
||||
} else {
|
||||
m.Push(key, value[key])
|
||||
}
|
||||
delete(value, key)
|
||||
})
|
||||
kit.For(kit.SortedKey(value), func(k string) { m.Push(k, value[k]) })
|
||||
})
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package mdb
|
||||
|
||||
import (
|
||||
"encoding/csv"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
@ -17,12 +18,10 @@ func _list_inputs(m *ice.Message, prefix, chain string, field, value string) {
|
||||
list := map[string]int{}
|
||||
defer func() {
|
||||
delete(list, "")
|
||||
for k, i := range list {
|
||||
m.Push(field, k).Push(COUNT, i)
|
||||
}
|
||||
kit.For(list, func(k string, i int) { m.Push(field, k).Push(COUNT, i) })
|
||||
m.SortIntR(COUNT)
|
||||
}()
|
||||
defer RLock(m, prefix, chain)()
|
||||
defer RLock(m, prefix)()
|
||||
Grows(m, prefix, chain, "", "", func(value ice.Map) {
|
||||
value = kit.GetMeta(value)
|
||||
list[kit.Format(value[field])] += kit.Int(kit.Select("1", value[COUNT]))
|
||||
@ -30,49 +29,60 @@ func _list_inputs(m *ice.Message, prefix, chain string, field, value string) {
|
||||
}
|
||||
func _list_insert(m *ice.Message, prefix, chain string, arg ...string) {
|
||||
m.Logs(INSERT, KEY, path.Join(prefix, chain), arg)
|
||||
defer Lock(m, prefix, chain)()
|
||||
defer Lock(m, prefix)()
|
||||
m.Echo("%d", Grow(m, prefix, chain, kit.Dict(arg, TARGET, m.Optionv(TARGET))))
|
||||
saveImportant(m, prefix, chain, kit.Simple(INSERT, prefix, chain, LIST, TIME, m.Time(), arg)...)
|
||||
}
|
||||
func _list_modify(m *ice.Message, prefix, chain string, field, value string, arg ...string) {
|
||||
m.Logs(MODIFY, KEY, path.Join(prefix, chain), field, value, arg)
|
||||
defer Lock(m, prefix, chain)()
|
||||
defer Lock(m, prefix)()
|
||||
Grows(m, prefix, chain, field, value, func(index int, val ice.Map) { _mdb_modify(m, val, field, arg...) })
|
||||
saveImportant(m, prefix, chain, kit.Simple(MODIFY, prefix, chain, LIST, field, value, arg)...)
|
||||
}
|
||||
func _list_select(m *ice.Message, prefix, chain, field, value string) {
|
||||
defer m.SortIntR(ID)
|
||||
fields := _list_fields(m)
|
||||
defer RLock(m, prefix, chain)()
|
||||
defer RLock(m, prefix)()
|
||||
Grows(m, prefix, chain, kit.Select(m.Option(CACHE_FIELD), field), kit.Select(m.Option(CACHE_VALUE), value), func(value ice.Map) {
|
||||
_mdb_select(m, m.OptionCB(""), "", value, fields, nil)
|
||||
})
|
||||
}
|
||||
func _list_export(m *ice.Message, prefix, chain, file string) {
|
||||
defer Lock(m, prefix, chain)()
|
||||
f, p, e := miss.CreateFile(kit.Keys(file, CSV))
|
||||
defer Lock(m, prefix)()
|
||||
p := kit.Keys(file, CSV)
|
||||
count := kit.Int(Conf(m, prefix, kit.Keys(chain, META, COUNT)))
|
||||
if count == 0 {
|
||||
if s, e := os.Stat(p); e == nil && !s.IsDir() {
|
||||
os.Remove(p)
|
||||
}
|
||||
return
|
||||
}
|
||||
f, p, e := miss.CreateFile(p)
|
||||
m.Assert(e)
|
||||
defer f.Close()
|
||||
defer m.Echo(p)
|
||||
m.Logs(EXPORT, KEY, path.Join(prefix, chain), FILE, p, COUNT, count)
|
||||
w := csv.NewWriter(f)
|
||||
defer w.Flush()
|
||||
count, head := 0, kit.Split(ListField(m))
|
||||
head := kit.Split(ListField(m))
|
||||
Grows(m, prefix, chain, "", "", func(index int, value ice.Map) {
|
||||
if value = kit.GetMeta(value); index == 0 {
|
||||
if len(head) == 0 || head[0] == ice.FIELDS_DETAIL {
|
||||
head = kit.SortedKey(value)
|
||||
}
|
||||
kit.If(len(head) == 0 || head[0] == ice.FIELDS_DETAIL, func() { head = kit.SortedKey(value) })
|
||||
w.Write(head)
|
||||
}
|
||||
w.Write(kit.Simple(head, func(k string) string { return kit.Format(value[k]) }))
|
||||
count++
|
||||
})
|
||||
m.Logs(EXPORT, KEY, path.Join(prefix, chain), FILE, p, COUNT, count)
|
||||
m.Conf(prefix, kit.Keys(chain, kit.Keym(COUNT)), 0)
|
||||
m.Conf(prefix, kit.Keys(chain, LIST), "")
|
||||
}
|
||||
func _list_import(m *ice.Message, prefix, chain, file string) {
|
||||
defer Lock(m, prefix, chain)()
|
||||
defer Lock(m, prefix)()
|
||||
f, e := miss.OpenFile(kit.Keys(file, CSV))
|
||||
m.Assert(e)
|
||||
if e != nil && !ice.Info.Important {
|
||||
return
|
||||
} else if m.WarnNotFound(e) {
|
||||
return
|
||||
}
|
||||
defer f.Close()
|
||||
r := csv.NewReader(f)
|
||||
head, _ := r.Read()
|
||||
@ -118,18 +128,18 @@ func PageListAction(arg ...ice.Any) ice.Actions {
|
||||
return ice.MergeActions(ice.Actions{
|
||||
SELECT: {Name: "select id auto insert page", Hand: func(m *ice.Message, arg ...string) { PageListSelect(m, arg...) }},
|
||||
NEXT: {Hand: func(m *ice.Message, arg ...string) {
|
||||
NextPage(m, kit.Select(m.Config(COUNT), arg, 0), kit.Slice(arg, 1)...)
|
||||
NextPage(m, kit.Select(Config(m, COUNT), arg, 0), kit.Slice(arg, 1)...)
|
||||
}},
|
||||
PREV: {Hand: func(m *ice.Message, arg ...string) {
|
||||
PrevPageLimit(m, kit.Select(m.Config(COUNT), arg, 0), kit.Slice(arg, 1)...)
|
||||
PrevPageLimit(m, kit.Select(Config(m, COUNT), arg, 0), kit.Slice(arg, 1)...)
|
||||
}},
|
||||
}, ListAction(arg...))
|
||||
}
|
||||
func ListField(m *ice.Message) string { return kit.Select(LIST_FIELD, m.Config(FIELD)) }
|
||||
func ListField(m *ice.Message) string { return kit.Select(LIST_FIELD, Config(m, FIELD)) }
|
||||
func ListSelect(m *ice.Message, arg ...string) *ice.Message {
|
||||
m.Fields(len(kit.Slice(arg, 0, 1)), ListField(m))
|
||||
if m.Cmdy(SELECT, m.PrefixKey(), "", LIST, ID, arg); !m.FieldsIsDetail() {
|
||||
return m.StatusTimeCountTotal(m.Config(COUNT))
|
||||
return m.StatusTimeCountTotal(Config(m, COUNT))
|
||||
}
|
||||
return m.StatusTime()
|
||||
}
|
||||
@ -173,11 +183,11 @@ func PrevPageLimit(m *ice.Message, total string, arg ...string) {
|
||||
}
|
||||
|
||||
func OptionPages(m *ice.Message, arg ...string) (page int, size int) {
|
||||
m.Option(CACHE_LIMIT, kit.Select(m.Option(CACHE_LIMIT), arg, 0))
|
||||
m.Option(CACHE_OFFEND, kit.Select(m.Option(CACHE_OFFEND), arg, 1))
|
||||
m.Option(CACHE_OFFEND, kit.Select(m.Option(CACHE_OFFEND), arg, 0))
|
||||
m.Option(CACHE_LIMIT, kit.Select(m.Option(CACHE_LIMIT), arg, 1))
|
||||
m.Option(CACHE_FILTER, kit.Select(m.Option(CACHE_FILTER), arg, 2))
|
||||
m.Option(LIMIT, kit.Select(m.Option(LIMIT), arg, 0))
|
||||
m.Option(OFFEND, kit.Select(m.Option(OFFEND), arg, 1))
|
||||
m.Option(OFFEND, kit.Select(m.Option(OFFEND), arg, 0))
|
||||
m.Option(LIMIT, kit.Select(m.Option(LIMIT), arg, 1))
|
||||
size = kit.Int(kit.Select("10", m.Option(LIMIT)))
|
||||
page = kit.Int(m.Option(OFFEND))/size + 1
|
||||
return
|
||||
@ -197,31 +207,23 @@ const (
|
||||
CACHE_FIELD = "cache.field"
|
||||
)
|
||||
|
||||
type Message interface {
|
||||
Confv(arg ...Any) (val Any)
|
||||
Option(key string, arg ...Any) string
|
||||
}
|
||||
|
||||
func Grows(m Message, prefix string, chain Any, match string, value string, cb Any) Map {
|
||||
func Grows(m *ice.Message, prefix string, chain Any, match string, value string, cb Any) Map {
|
||||
cache, ok := m.Confv(prefix, chain).(ice.Map)
|
||||
if cache == nil || !ok {
|
||||
return nil
|
||||
}
|
||||
limit := kit.Int(m.Option(CACHE_LIMIT))
|
||||
if begin := kit.Int(m.Option(CACHE_BEGIN)); begin != 0 && limit > 0 {
|
||||
count := kit.Int(m.Option(CACHE_COUNT, kit.Int(kit.Value(cache, kit.Keym("count")))))
|
||||
if begin > 0 {
|
||||
m.Option(CACHE_OFFEND, count-begin-limit)
|
||||
} else if begin, limit := kit.Int(m.Option(CACHE_BEGIN)), kit.Int(m.Option(CACHE_LIMIT)); begin != 0 && limit > 0 {
|
||||
if count := kit.Int(m.Option(CACHE_COUNT, kit.Int(kit.Value(cache, kit.Keym(COUNT))))); count-begin < limit {
|
||||
m.Option(CACHE_OFFEND, 0)
|
||||
m.Option(CACHE_LIMIT, count-begin+1)
|
||||
} else {
|
||||
m.Option(CACHE_OFFEND, -begin-limit)
|
||||
m.Option(CACHE_OFFEND, count-begin-limit+1)
|
||||
}
|
||||
}
|
||||
return miss.Grows(path.Join(prefix, kit.Keys(chain)), cache,
|
||||
kit.Int(kit.Select("0", strings.TrimPrefix(m.Option(CACHE_OFFEND), "-"))),
|
||||
kit.Int(kit.Select("10", m.Option(CACHE_LIMIT))),
|
||||
match, value, cb)
|
||||
kit.Int(kit.Select("10", m.Option(CACHE_LIMIT))), match, value, cb)
|
||||
}
|
||||
func Grow(m Message, prefix string, chain Any, data Any) int {
|
||||
func Grow(m *ice.Message, prefix string, chain Any, data Any) int {
|
||||
cache, ok := m.Confv(prefix, chain).(ice.Map)
|
||||
if cache == nil || !ok {
|
||||
cache = kit.Data()
|
||||
|
75
base/mdb/lock.go
Normal file
75
base/mdb/lock.go
Normal file
@ -0,0 +1,75 @@
|
||||
package mdb
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
ice "shylinux.com/x/icebergs"
|
||||
kit "shylinux.com/x/toolkits"
|
||||
"shylinux.com/x/toolkits/task"
|
||||
)
|
||||
|
||||
var _lock = task.Lock{}
|
||||
var _locks = map[string]*task.Lock{}
|
||||
|
||||
func getLock(m *ice.Message, arg ...string) *task.Lock {
|
||||
key := kit.Select(m.PrefixKey(), kit.Keys(arg))
|
||||
defer _lock.Lock()()
|
||||
l, ok := _locks[key]
|
||||
kit.If(!ok, func() { l = &task.Lock{}; _locks[key] = l })
|
||||
return l
|
||||
}
|
||||
func Lock(m *ice.Message, arg ...string) func() {
|
||||
return getLock(m, arg...).Lock()
|
||||
}
|
||||
func RLock(m *ice.Message, arg ...string) func() {
|
||||
return getLock(m, arg...).RLock()
|
||||
}
|
||||
|
||||
func ConfigSimple(m *ice.Message, key ...string) (res []string) {
|
||||
for _, key := range key {
|
||||
res = append(res, key, kit.Format(Configv(m, key)))
|
||||
}
|
||||
return
|
||||
}
|
||||
func Config(m *ice.Message, key string, arg ...Any) string {
|
||||
return kit.Format(Configv(m, key, arg...))
|
||||
}
|
||||
func Configv(m *ice.Message, key string, arg ...Any) Any {
|
||||
kit.If(len(arg) > 0, func() { Confv(m, m.PrefixKey(), kit.Keym(key), arg[0]) })
|
||||
return Confv(m, m.PrefixKey(), kit.Keym(key))
|
||||
}
|
||||
func Confv(m *ice.Message, arg ...Any) Any {
|
||||
key := kit.Select(m.PrefixKey(), kit.Format(arg[0]))
|
||||
if ctx, ok := ice.Info.Index[key].(*ice.Context); ok {
|
||||
key = ctx.Prefix(key)
|
||||
}
|
||||
if len(arg) > 2 {
|
||||
defer Lock(m, key)()
|
||||
} else {
|
||||
defer RLock(m, key)()
|
||||
}
|
||||
return m.Confv(arg...)
|
||||
}
|
||||
func Conf(m *ice.Message, arg ...Any) string { return kit.Format(Confv(m, arg...)) }
|
||||
func Confm(m *ice.Message, key string, sub Any, cbs ...Any) Map {
|
||||
val := m.Confv(key, sub)
|
||||
kit.If(len(cbs) > 0, func() { kit.For(val, cbs[0]) })
|
||||
value, _ := val.(Map)
|
||||
return value
|
||||
}
|
||||
|
||||
var cache = sync.Map{}
|
||||
|
||||
func Cache(m *ice.Message, key string, add func() Any) Any {
|
||||
if key = kit.Keys(m.PrefixKey(), key); add == nil {
|
||||
cache.Delete(key)
|
||||
return nil
|
||||
} else if val, ok := cache.Load(key); ok {
|
||||
return val
|
||||
} else if val := add(); val != nil {
|
||||
cache.Store(key, val)
|
||||
return val
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
400
base/mdb/mdb.go
400
base/mdb/mdb.go
@ -3,34 +3,19 @@ package mdb
|
||||
import (
|
||||
"path"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
ice "shylinux.com/x/icebergs"
|
||||
kit "shylinux.com/x/toolkits"
|
||||
"shylinux.com/x/toolkits/task"
|
||||
)
|
||||
|
||||
type Any = interface{}
|
||||
type Map = map[string]Any
|
||||
type Maps = map[string]string
|
||||
type Any = ice.Any
|
||||
type List = ice.List
|
||||
type Maps = ice.Maps
|
||||
type Map = ice.Map
|
||||
|
||||
func _file_name(m *ice.Message, arg ...string) string {
|
||||
if len(arg) > 3 && strings.Contains(arg[3], ice.PS) {
|
||||
return arg[3]
|
||||
}
|
||||
return path.Join(ice.USR_LOCAL_EXPORT, path.Join(arg[:2]...), arg[2])
|
||||
}
|
||||
func _mdb_getmeta(m *ice.Message, prefix, chain, key string) string {
|
||||
defer RLock(m, prefix, chain)()
|
||||
return m.Conf(prefix, kit.Keys(chain, kit.Keym(key)))
|
||||
}
|
||||
func _mdb_modify(m *ice.Message, value ice.Map, field string, arg ...string) {
|
||||
func _mdb_modify(m *ice.Message, value Map, field string, arg ...string) {
|
||||
value = kit.GetMeta(value)
|
||||
kit.Fetch(arg, func(k, v string) {
|
||||
if k != field {
|
||||
kit.Value(value, k, v)
|
||||
}
|
||||
})
|
||||
kit.For(arg, func(k, v string) { kit.If(k != field, func() { kit.Value(value, k, v) }) })
|
||||
}
|
||||
func _mdb_select(m *ice.Message, cb Any, key string, value Map, fields []string, val Map) {
|
||||
switch value, val = kit.GetMeta(value), kit.GetMeta(val); cb := cb.(type) {
|
||||
@ -47,13 +32,10 @@ func _mdb_select(m *ice.Message, cb Any, key string, value Map, fields []string,
|
||||
case func(Any):
|
||||
cb(value[TARGET])
|
||||
case func(Maps):
|
||||
res := Maps{}
|
||||
for k, v := range value {
|
||||
res[k] = kit.Format(v)
|
||||
}
|
||||
cb(res)
|
||||
case string, []string, []ice.Any, nil:
|
||||
cb(kit.ToMaps(value))
|
||||
case string, []string, []Any, nil:
|
||||
if m.FieldsIsDetail() {
|
||||
// m.Push(ice.FIELDS_DETAIL, value, nil, kit.Dict(HASH, key))
|
||||
m.Push(ice.FIELDS_DETAIL, value)
|
||||
} else {
|
||||
m.Push(key, value, fields, val)
|
||||
@ -62,63 +44,77 @@ func _mdb_select(m *ice.Message, cb Any, key string, value Map, fields []string,
|
||||
m.ErrorNotImplement(cb)
|
||||
}
|
||||
}
|
||||
func _mdb_export_file(m *ice.Message, arg ...string) string {
|
||||
if len(arg) > 3 && strings.Contains(arg[3], ice.PS) {
|
||||
return arg[3]
|
||||
}
|
||||
return path.Join(ice.USR_LOCAL_EXPORT, path.Join(arg[:2]...), arg[2])
|
||||
}
|
||||
|
||||
const (
|
||||
DICT = kit.MDB_DICT
|
||||
META = kit.MDB_META
|
||||
|
||||
SHORT = kit.MDB_SHORT
|
||||
FIELD = kit.MDB_FIELD
|
||||
COUNT = kit.MDB_COUNT
|
||||
TOTAL = kit.MDB_TOTAL
|
||||
LIMIT = kit.MDB_LIMIT
|
||||
LEAST = kit.MDB_LEAST
|
||||
STORE = kit.MDB_STORE
|
||||
FSIZE = kit.MDB_FSIZE
|
||||
|
||||
UNIQ = kit.MDB_UNIQ
|
||||
FOREACH = kit.MDB_FOREACH
|
||||
RANDOMS = kit.MDB_RANDOMS
|
||||
)
|
||||
const (
|
||||
ID = kit.MDB_ID
|
||||
KEY = kit.MDB_KEY
|
||||
TIME = kit.MDB_TIME
|
||||
TYPE = kit.MDB_TYPE
|
||||
NAME = kit.MDB_NAME
|
||||
TEXT = kit.MDB_TEXT
|
||||
DATA = kit.MDB_DATA
|
||||
|
||||
LINK = kit.MDB_LINK
|
||||
FILE = kit.MDB_FILE
|
||||
ICON = kit.MDB_ICON
|
||||
SCAN = kit.MDB_SCAN
|
||||
SHOW = kit.MDB_SHOW
|
||||
LINK = kit.MDB_LINK
|
||||
HELP = kit.MDB_HELP
|
||||
FILE = kit.MDB_FILE
|
||||
DATA = kit.MDB_DATA
|
||||
VIEW = kit.MDB_VIEW
|
||||
SHOW = kit.MDB_SHOW
|
||||
|
||||
INDEX = kit.MDB_INDEX
|
||||
KEY = kit.MDB_KEY
|
||||
VALUE = kit.MDB_VALUE
|
||||
INDEX = kit.MDB_INDEX
|
||||
EXTRA = kit.MDB_EXTRA
|
||||
ALIAS = kit.MDB_ALIAS
|
||||
EXPIRE = kit.MDB_EXPIRE
|
||||
STATUS = kit.MDB_STATUS
|
||||
STREAM = kit.MDB_STREAM
|
||||
|
||||
SHORT = kit.MDB_SHORT
|
||||
FIELD = kit.MDB_FIELD
|
||||
TOTAL = kit.MDB_TOTAL
|
||||
COUNT = kit.MDB_COUNT
|
||||
LIMIT = kit.MDB_LIMIT
|
||||
LEAST = kit.MDB_LEAST
|
||||
STORE = kit.MDB_STORE
|
||||
FSIZE = kit.MDB_FSIZE
|
||||
TOOLS = "tools"
|
||||
TOOLS = "tools"
|
||||
ICONS = "icons"
|
||||
UNITS = "units"
|
||||
ORDER = "order"
|
||||
SCORE = "score"
|
||||
GROUP = "group"
|
||||
VALID = "valid"
|
||||
ENABLE = "enable"
|
||||
MEMBER = "member"
|
||||
DISABLE = "disable"
|
||||
EXPIRED = "expired"
|
||||
INVALID = "invalid"
|
||||
|
||||
SOURCE = "_source"
|
||||
TARGET = "_target"
|
||||
|
||||
CACHE_CLEAR_ON_EXIT = "cache.clear.on.exit"
|
||||
SOURCE = "_source"
|
||||
TARGET = "_target"
|
||||
IMPORTANT = "important"
|
||||
)
|
||||
const (
|
||||
DETAIL = "detail"
|
||||
RANDOM = "random"
|
||||
ACTION = "action"
|
||||
FIELDS = "fields"
|
||||
PARAMS = "params"
|
||||
|
||||
INPUTS = "inputs"
|
||||
CREATE = "create"
|
||||
REMOVE = "remove"
|
||||
UPDATE = "update"
|
||||
INSERT = "insert"
|
||||
DELETE = "delete"
|
||||
MODIFY = "modify"
|
||||
@ -127,17 +123,42 @@ const (
|
||||
EXPORT = "export"
|
||||
IMPORT = "import"
|
||||
|
||||
UPLOAD = "upload"
|
||||
REVERT = "revert"
|
||||
REPEAT = "repeat"
|
||||
|
||||
NEXT = "next"
|
||||
PREV = "prev"
|
||||
PAGE = "page"
|
||||
DETAIL = "detail"
|
||||
FIELDS = "fields"
|
||||
SHORTS = "shorts"
|
||||
PARAMS = "params"
|
||||
OFFEND = "offend"
|
||||
OFFSET = "offset"
|
||||
RANDOM = "random"
|
||||
WEIGHT = "weight"
|
||||
SUBKEY = "mdb.sub"
|
||||
|
||||
ACTION = "action"
|
||||
UPLOAD = "upload"
|
||||
RECENT = "recent"
|
||||
REPEAT = "repeat"
|
||||
REVERT = "revert"
|
||||
RENAME = "rename"
|
||||
VENDOR = "vendor"
|
||||
PRUNE = "prune"
|
||||
TABLE = "table"
|
||||
CLASS = "class"
|
||||
DATABASE = "database"
|
||||
|
||||
PAGE = "page"
|
||||
NEXT = "next"
|
||||
PREV = "prev"
|
||||
PLAY = "play"
|
||||
|
||||
SORT = "sort"
|
||||
JSON = "json"
|
||||
CSV = "csv"
|
||||
SUB = "sub"
|
||||
|
||||
QS = ice.QS
|
||||
EQ = ice.EQ
|
||||
AT = ice.AT
|
||||
FS = ice.FS
|
||||
)
|
||||
|
||||
const MDB = "mdb"
|
||||
@ -146,178 +167,159 @@ var Index = &ice.Context{Name: MDB, Help: "数据模块", Commands: ice.Commands
|
||||
ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) {}},
|
||||
ice.CTX_EXIT: {Hand: func(m *ice.Message, arg ...string) {}},
|
||||
INPUTS: {Name: "inputs key sub type field value", Hand: func(m *ice.Message, arg ...string) {
|
||||
const (
|
||||
SPACE = "space"
|
||||
CONTEXT = "context"
|
||||
COMMAND = "command"
|
||||
INDEX = "index"
|
||||
kit.Switch(arg[2],
|
||||
HASH, func() { _hash_inputs(m, arg[0], arg[1], kit.Select(NAME, arg, 3), kit.Select("", arg, 4)) },
|
||||
ZONE, func() { _zone_inputs(m, arg[0], arg[1], arg[3], kit.Select(NAME, arg, 4), kit.Select("", arg, 5)) },
|
||||
LIST, func() { _list_inputs(m, arg[0], arg[1], kit.Select(NAME, arg, 3), kit.Select("", arg, 4)) },
|
||||
)
|
||||
switch arg[3] = strings.TrimPrefix(arg[3], EXTRA+ice.PT); arg[3] {
|
||||
case ice.POD:
|
||||
m.Cmdy(SPACE)
|
||||
case ice.CTX:
|
||||
m.Cmdy(CONTEXT)
|
||||
case ice.CMD:
|
||||
m.Cmdy(CONTEXT, kit.Select(m.Option(ice.CTX), m.Option(kit.Keys(EXTRA, ice.CTX))), COMMAND)
|
||||
case INDEX:
|
||||
m.Cmdy(COMMAND, SEARCH, COMMAND, kit.Select("", arg, 1), ice.OptionFields(arg[3]))
|
||||
default:
|
||||
switch arg[2] {
|
||||
case ZONE:
|
||||
_zone_inputs(m, arg[0], arg[1], arg[3], kit.Select(NAME, arg, 4), kit.Select("", arg, 5))
|
||||
case HASH:
|
||||
_hash_inputs(m, arg[0], arg[1], kit.Select(NAME, arg, 3), kit.Select("", arg, 4))
|
||||
case LIST:
|
||||
_list_inputs(m, arg[0], arg[1], kit.Select(NAME, arg, 3), kit.Select("", arg, 4))
|
||||
for _, inputs := range ice.Info.Inputs {
|
||||
if arg[2] == ZONE {
|
||||
inputs(m, arg[4])
|
||||
} else {
|
||||
inputs(m, arg[3])
|
||||
}
|
||||
}
|
||||
}},
|
||||
INSERT: {Name: "insert key sub type arg...", Hand: func(m *ice.Message, arg ...string) {
|
||||
defer m.ProcessRefresh()
|
||||
switch arg[2] {
|
||||
case ZONE:
|
||||
_zone_insert(m, arg[0], arg[1], arg[3], arg[4:]...)
|
||||
case HASH:
|
||||
_hash_insert(m, arg[0], arg[1], arg[3:]...)
|
||||
case LIST:
|
||||
_list_insert(m, arg[0], arg[1], arg[3:]...)
|
||||
}
|
||||
kit.Switch(arg[2],
|
||||
HASH, func() { _hash_insert(m, arg[0], arg[1], arg[3:]...) },
|
||||
ZONE, func() {
|
||||
if arg[3] == ZONE {
|
||||
_zone_insert(m, arg[0], arg[1], arg[4], arg[5:]...)
|
||||
} else {
|
||||
_zone_insert(m, arg[0], arg[1], arg[3], arg[4:]...)
|
||||
}
|
||||
},
|
||||
LIST, func() { _list_insert(m, arg[0], arg[1], arg[3:]...) },
|
||||
)
|
||||
}},
|
||||
DELETE: {Name: "delete key sub type field value", Hand: func(m *ice.Message, arg ...string) {
|
||||
defer m.ProcessRefresh()
|
||||
switch arg[2] {
|
||||
case ZONE:
|
||||
// _list_delete(m, arg[0], _domain_chain(m, kit.Keys(arg[1], kit.KeyHash(arg[3]))), arg[4], arg[5])
|
||||
case HASH:
|
||||
_hash_delete(m, arg[0], arg[1], arg[3], arg[4])
|
||||
case LIST:
|
||||
// _list_delete(m, arg[0], arg[1], arg[3], arg[4])
|
||||
}
|
||||
kit.Switch(arg[2],
|
||||
HASH, func() { _hash_delete(m, arg[0], arg[1], arg[3], arg[4]) },
|
||||
// ZONE, func() { _list_delete(m, arg[0], _domain_chain(m, kit.Keys(arg[1], kit.KeyHash(arg[3]))), arg[4], arg[5]) },
|
||||
// LIST, func() { _list_delete(m, arg[0], arg[1], arg[3], arg[4]) },
|
||||
)
|
||||
}},
|
||||
MODIFY: {Name: "modify key sub type field value arg...", Hand: func(m *ice.Message, arg ...string) {
|
||||
switch arg[2] {
|
||||
case ZONE:
|
||||
_zone_modify(m, arg[0], arg[1], arg[3], arg[4], arg[5:]...)
|
||||
case HASH:
|
||||
_hash_modify(m, arg[0], arg[1], arg[3], arg[4], arg[5:]...)
|
||||
case LIST:
|
||||
_list_modify(m, arg[0], arg[1], arg[3], arg[4], arg[5:]...)
|
||||
}
|
||||
kit.Switch(arg[2],
|
||||
HASH, func() { _hash_modify(m, arg[0], arg[1], arg[3], arg[4], arg[5:]...) },
|
||||
ZONE, func() { _zone_modify(m, arg[0], arg[1], arg[3], arg[4], arg[5:]...) },
|
||||
LIST, func() { _list_modify(m, arg[0], arg[1], arg[3], arg[4], arg[5:]...) },
|
||||
)
|
||||
}},
|
||||
SELECT: {Name: "select key sub type field value", Hand: func(m *ice.Message, arg ...string) {
|
||||
switch arg[2] {
|
||||
case ZONE:
|
||||
_zone_select(m, arg[0], arg[1], kit.Select("", arg, 3), kit.Select("", arg, 4))
|
||||
case HASH:
|
||||
_hash_select(m, arg[0], arg[1], kit.Select("", arg, 3), kit.Select(FOREACH, arg, 4))
|
||||
case LIST:
|
||||
_list_select(m, arg[0], arg[1], kit.Select("", arg, 3), kit.Select("", arg, 4))
|
||||
}
|
||||
kit.Switch(arg[2],
|
||||
HASH, func() { _hash_select(m, arg[0], arg[1], kit.Select("", arg, 3), kit.Select(FOREACH, arg, 4)) },
|
||||
ZONE, func() { _zone_select(m, arg[0], arg[1], kit.Select("", arg, 3), kit.Select("", arg, 4)) },
|
||||
LIST, func() { _list_select(m, arg[0], arg[1], kit.Select("", arg, 3), kit.Select("", arg, 4)) },
|
||||
)
|
||||
}},
|
||||
PRUNES: {Name: "prunes key sub type [field value]...", Hand: func(m *ice.Message, arg ...string) {
|
||||
switch arg[2] {
|
||||
case ZONE:
|
||||
// _list_prunes(m, arg[0], _domain_chain(m, kit.Keys(arg[1], kit.KeyHash(arg[3]))), arg[4:]...)
|
||||
case HASH:
|
||||
_hash_prunes(m, arg[0], arg[1], arg[3:]...)
|
||||
m.Tables(func(value ice.Maps) { _hash_delete(m, arg[0], arg[1], HASH, value[HASH]) })
|
||||
case LIST:
|
||||
// _list_prunes(m, arg[0], arg[1], arg[3:]...)
|
||||
}
|
||||
kit.Switch(arg[2],
|
||||
HASH, func() {
|
||||
_hash_prunes(m, arg[0], arg[1], arg[3:]...)
|
||||
m.Table(func(value Maps) { _hash_delete(m, arg[0], arg[1], HASH, value[HASH]) })
|
||||
},
|
||||
// ZONE, func() { _list_prunes(m, arg[0], _domain_chain(m, kit.Keys(arg[1], kit.KeyHash(arg[3]))), arg[4:]...) },
|
||||
// LIST, func() { _list_prunes(m, arg[0], arg[1], arg[3:]...) },
|
||||
)
|
||||
}},
|
||||
EXPORT: {Name: "export key sub type file", Hand: func(m *ice.Message, arg ...string) {
|
||||
m.OptionDefault(CACHE_LIMIT, "-1")
|
||||
switch file := _file_name(m, arg...); arg[2] {
|
||||
case ZONE:
|
||||
_zone_export(m, arg[0], arg[1], file)
|
||||
case HASH:
|
||||
_hash_export(m, arg[0], arg[1], file)
|
||||
case LIST:
|
||||
_list_export(m, arg[0], arg[1], file)
|
||||
EXPORT: {Name: "export index auto", Help: "导出数据", Actions: ice.MergeActions(ice.Actions{
|
||||
IMPORT: {Hand: func(m *ice.Message, arg ...string) {
|
||||
HashSelect(m).Table(func(value ice.Maps) {
|
||||
if value[ENABLE] != ice.FALSE {
|
||||
m.Cmd(IMPORT, value[INDEX], "", value[TYPE])
|
||||
}
|
||||
})
|
||||
}},
|
||||
EXPORT: {Hand: func(m *ice.Message, arg ...string) {
|
||||
HashSelect(m).Table(func(value ice.Maps) {
|
||||
if value[ENABLE] != ice.FALSE {
|
||||
m.Cmd(EXPORT, value[INDEX], "", value[TYPE])
|
||||
}
|
||||
})
|
||||
}},
|
||||
}, ExportHashAction(SHORT, INDEX, FIELD, "time,index,type,enable")), Hand: func(m *ice.Message, arg ...string) {
|
||||
if len(arg) < 2 {
|
||||
HashSelect(m, arg...).PushAction(REMOVE)
|
||||
return
|
||||
}
|
||||
m.StatusTime(LINK, "/share/local/"+m.Result()).Process("_clear")
|
||||
m.OptionDefault(CACHE_LIMIT, "-1")
|
||||
file := _mdb_export_file(m, arg...)
|
||||
kit.Switch(arg[2],
|
||||
HASH, func() { _hash_export(m, arg[0], arg[1], file) },
|
||||
ZONE, func() { _zone_export(m, arg[0], arg[1], file); _hash_export(m, arg[0], arg[1], file) },
|
||||
LIST, func() { _list_export(m, arg[0], arg[1], file) },
|
||||
)
|
||||
}},
|
||||
IMPORT: {Name: "import key sub type file", Hand: func(m *ice.Message, arg ...string) {
|
||||
switch file := _file_name(m, arg...); arg[2] {
|
||||
case ZONE:
|
||||
_zone_import(m, arg[0], arg[1], file)
|
||||
case HASH:
|
||||
_hash_import(m, arg[0], arg[1], file)
|
||||
case LIST:
|
||||
_list_import(m, arg[0], arg[1], file)
|
||||
}
|
||||
file := _mdb_export_file(m, arg...)
|
||||
kit.Switch(arg[2],
|
||||
HASH, func() { _hash_import(m, arg[0], arg[1], file) },
|
||||
ZONE, func() { _hash_import(m, arg[0], arg[1], file); _zone_import(m, arg[0], arg[1], file) },
|
||||
LIST, func() { _list_import(m, arg[0], arg[1], file) },
|
||||
)
|
||||
}},
|
||||
}}
|
||||
|
||||
func init() {
|
||||
ice.Index.Register(Index, nil, INSERT, DELETE, MODIFY, SELECT, INPUTS, PRUNES, EXPORT, IMPORT, PLUGIN, RENDER, ENGINE, SEARCH)
|
||||
ice.Index.Register(Index, nil, INPUTS, INSERT, DELETE, MODIFY, SELECT, PRUNES, EXPORT, IMPORT, PLUGIN, RENDER, ENGINE, SEARCH)
|
||||
}
|
||||
func AutoConfig(args ...ice.Any) *ice.Action {
|
||||
return &ice.Action{Hand: func(m *ice.Message, arg ...string) {
|
||||
if cs := m.Target().Configs; len(args) > 0 {
|
||||
cs[m.CommandKey()] = &ice.Config{Value: kit.Data(args...)}
|
||||
ice.Info.Load(m, m.CommandKey())
|
||||
func init() {
|
||||
ice.Module(MDB,
|
||||
HashInputs, HashCreate, HashRemove, func(m *ice.Message) { HashPrunes(m, nil) }, HashModify, HashSelect,
|
||||
ZoneInputs, ZoneCreate, ZoneRemove, ZoneInsert, ZoneModify, ZoneSelect,
|
||||
)
|
||||
}
|
||||
|
||||
func AutoConfig(arg ...Any) *ice.Action {
|
||||
return &ice.Action{Hand: func(m *ice.Message, args ...string) {
|
||||
if cs := m.Target().Configs; cs[m.CommandKey()] == nil {
|
||||
cs[m.CommandKey()] = &ice.Config{Value: kit.Data(arg...)}
|
||||
} else {
|
||||
kit.For(kit.Dict(arg...), func(k string, v Any) { Config(m, k, v) })
|
||||
}
|
||||
if cmd := m.Target().Commands[m.CommandKey()]; cmd == nil {
|
||||
return
|
||||
} else if cmd.Actions[INSERT] != nil {
|
||||
if inputs := []ice.Any{}; cmd.Meta[INSERT] == nil {
|
||||
kit.Fetch(kit.Filters(kit.Simple(m.Config(SHORT), kit.Split(ListField(m))), "", TIME, ID), func(k string) { inputs = append(inputs, k) })
|
||||
m.Design(INSERT, "添加", inputs...)
|
||||
} else {
|
||||
s := Config(m, SHORT)
|
||||
kit.If(s == "" || s == UNIQ || strings.Contains(s, ","), func() { s = HASH })
|
||||
if cmd.Name == "" {
|
||||
cmd.Name = kit.Format("%s %s auto", m.CommandKey(), s)
|
||||
cmd.List = ice.SplitCmd(cmd.Name, cmd.Actions)
|
||||
}
|
||||
if inputs := []ice.Any{}; cmd.Meta[CREATE] == nil {
|
||||
kit.Fetch(kit.Filters(kit.Split(kit.Select(m.Config(SHORT), m.Config(FIELDS))), TIME, HASH, COUNT), func(k string) { inputs = append(inputs, k) })
|
||||
m.Design(CREATE, "创建", inputs...)
|
||||
add := func(list []string) (inputs []Any) {
|
||||
kit.For(list, func(k string) {
|
||||
kit.If(!kit.IsIn(k, TIME, HASH, COUNT, ID, ENABLE, DISABLE), func() {
|
||||
inputs = append(inputs, k+kit.Select("", FOREACH, strings.Contains(s, k)))
|
||||
})
|
||||
})
|
||||
return
|
||||
}
|
||||
} else if cmd.Actions[CREATE] != nil {
|
||||
if inputs := []ice.Any{}; cmd.Meta[CREATE] == nil {
|
||||
kit.Fetch(kit.Filters(kit.Split(HashField(m)), TIME, HASH), func(k string) { inputs = append(inputs, k) })
|
||||
m.Design(CREATE, "创建", inputs...)
|
||||
kit.If(cmd.Meta[CREATE] == nil, func() { m.Design(CREATE, "", add(kit.Split(HashField(m)))...) })
|
||||
return
|
||||
if cmd.Actions[INSERT] != nil {
|
||||
kit.If(cmd.Meta[INSERT] == nil, func() { m.Design(INSERT, "", add(kit.Simple(Config(m, SHORT), kit.Split(ListField(m))))...) })
|
||||
kit.If(cmd.Meta[CREATE] == nil, func() { m.Design(CREATE, "", add(kit.Split(Config(m, SHORT)))...) })
|
||||
} else if cmd.Actions[CREATE] != nil {
|
||||
kit.If(cmd.Meta[CREATE] == nil, func() { m.Design(CREATE, "", add(kit.Split(HashField(m)))...) })
|
||||
}
|
||||
}
|
||||
}}
|
||||
}
|
||||
|
||||
var _lock = task.Lock{}
|
||||
var _locks = map[string]*task.Lock{}
|
||||
|
||||
func getLock(m *ice.Message, key string) *task.Lock {
|
||||
if key == "" {
|
||||
key = m.PrefixKey()
|
||||
}
|
||||
defer _lock.Lock()()
|
||||
l, ok := _locks[key]
|
||||
if !ok {
|
||||
l = &task.Lock{}
|
||||
_locks[key] = l
|
||||
}
|
||||
return l
|
||||
func ImportantZoneAction(arg ...Any) ice.Actions {
|
||||
return ice.MergeActions(ice.Actions{
|
||||
ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) { Config(m, IMPORTANT, ice.TRUE) }},
|
||||
}, ZoneAction(arg...))
|
||||
}
|
||||
func Lock(m *ice.Message, arg ...ice.Any) func() { return getLock(m, kit.Keys(arg...)).Lock() }
|
||||
func RLock(m *ice.Message, arg ...ice.Any) func() { return getLock(m, kit.Keys(arg...)).RLock() }
|
||||
|
||||
func Config(m *ice.Message, key string, arg ...ice.Any) string {
|
||||
if len(arg) > 0 {
|
||||
defer Lock(m, m.PrefixKey(), key)()
|
||||
} else {
|
||||
defer RLock(m, m.PrefixKey(), key)()
|
||||
}
|
||||
return m.Config(key, arg...)
|
||||
func ImportantHashAction(arg ...Any) ice.Actions {
|
||||
return ice.MergeActions(ice.Actions{
|
||||
ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) { Config(m, IMPORTANT, ice.TRUE) }},
|
||||
}, HashAction(arg...))
|
||||
}
|
||||
|
||||
var cache = sync.Map{}
|
||||
|
||||
func Cache(m *ice.Message, key string, add func() ice.Any) ice.Any {
|
||||
if add == nil {
|
||||
cache.Delete(key)
|
||||
return nil
|
||||
func saveImportant(m *ice.Message, key, sub string, arg ...string) {
|
||||
if m.Option("skip.important") == ice.TRUE {
|
||||
return
|
||||
}
|
||||
if val, ok := cache.Load(key); ok {
|
||||
return val
|
||||
}
|
||||
if val := add(); val != nil {
|
||||
cache.Store(key, val)
|
||||
return val
|
||||
}
|
||||
return nil
|
||||
kit.If(m.Conf(key, kit.Keys(META, IMPORTANT)) == ice.TRUE, func() { ice.SaveImportant(m, arg...) })
|
||||
}
|
||||
|
@ -9,34 +9,21 @@ const RENDER = "render"
|
||||
|
||||
func init() { Index.MergeCommands(ice.Commands{RENDER: {Help: "渲染", Actions: RenderAction()}}) }
|
||||
|
||||
func RenderAction(args ...ice.Any) ice.Actions {
|
||||
return ice.MergeActions(ice.Actions{
|
||||
ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) {
|
||||
if len(args) == 0 {
|
||||
args = append(args, SHORT, TYPE, FIELD, "time,type,name,text")
|
||||
}
|
||||
if cs := m.Target().Configs; cs[m.CommandKey()] == nil {
|
||||
cs[m.CommandKey()] = &ice.Config{Value: kit.Data(args...)}
|
||||
} else {
|
||||
kit.Fetch(kit.Simple(args), func(key, value string) { m.Config(key, value) })
|
||||
}
|
||||
}},
|
||||
CREATE: {Name: "create type name text", Hand: func(m *ice.Message, arg ...string) {
|
||||
m.Option(TYPE, kit.Ext(m.Option(TYPE)))
|
||||
m.OptionDefault(NAME, m.Option(TYPE))
|
||||
m.Cmdy(INSERT, m.PrefixKey(), "", HASH, m.OptionSimple(TYPE, NAME, TEXT))
|
||||
}},
|
||||
func RenderAction(arg ...ice.Any) ice.Actions {
|
||||
return ice.MergeActions(ice.Actions{ice.CTX_INIT: AutoConfig(SHORT, TYPE, FIELD, "time,type,name,text", arg),
|
||||
CREATE: {Name: "create type name text", Hand: func(m *ice.Message, arg ...string) { Config(m, SHORT, TYPE); HashCreate(m) }},
|
||||
SELECT: {Name: "select type name text auto create", Hand: func(m *ice.Message, arg ...string) {
|
||||
if len(arg) < 2 || arg[0] == "" {
|
||||
HashSelect(m, arg...)
|
||||
return
|
||||
}
|
||||
for _, k := range kit.Split(arg[0]) {
|
||||
HashSelect(m.Spawn(ice.OptionFields("")), k).Tables(func(value ice.Maps) {
|
||||
m.OptionDefault(ice.MSG_FIELDS, kit.Select("type,name,text", arg, 2))
|
||||
kit.For(kit.Split(arg[0]), func(k string) {
|
||||
HashSelects(m.Spawn(), k).Table(func(value ice.Maps) {
|
||||
m.Cmdy(kit.Keys(value[TEXT], value[NAME]), m.CommandKey(), k, arg[1], kit.Select("", arg, 2), kit.Slice(arg, 3))
|
||||
})
|
||||
}
|
||||
})
|
||||
m.Sort(m.OptionFields())
|
||||
}},
|
||||
ice.CTX_EXIT: {Hand: func(m *ice.Message, arg ...string) { m.Conf("", HASH, "") }},
|
||||
})
|
||||
}, ClearOnExitHashAction())
|
||||
}
|
||||
|
@ -9,31 +9,23 @@ const SEARCH = "search"
|
||||
|
||||
func init() {
|
||||
Index.MergeCommands(ice.Commands{SEARCH: {Help: "搜索", Actions: RenderAction()}})
|
||||
ice.AddMerges(func(c *ice.Context, key string, cmd *ice.Command, sub string, action *ice.Action) (ice.Handler, ice.Handler) {
|
||||
switch sub {
|
||||
case SEARCH:
|
||||
return func(m *ice.Message, arg ...string) { m.Cmd(sub, CREATE, m.CommandKey(), m.PrefixKey()) }, nil
|
||||
ice.AddMergeAction(func(c *ice.Context, key string, cmd *ice.Command, sub string, action *ice.Action) ice.Handler {
|
||||
if sub == SEARCH {
|
||||
return func(m *ice.Message, arg ...string) { m.Cmd(sub, CREATE, m.CommandKey(), m.PrefixKey()) }
|
||||
}
|
||||
return nil, nil
|
||||
return nil
|
||||
})
|
||||
}
|
||||
func SearchAction() ice.Actions {
|
||||
return ice.Actions{SEARCH: {Hand: func(m *ice.Message, arg ...string) { HashSelectSearch(m, arg) }}}
|
||||
}
|
||||
func HashSearchAction(arg ...Any) ice.Actions {
|
||||
return ice.MergeActions(HashAction(arg...), SearchAction())
|
||||
}
|
||||
func HashSelectSearch(m *ice.Message, args []string, keys ...string) *ice.Message {
|
||||
if args[0] != m.CommandKey() {
|
||||
return m
|
||||
}
|
||||
if len(keys) == 0 {
|
||||
keys = kit.Filters(kit.Split(HashField(m)), TIME, HASH)
|
||||
}
|
||||
HashSelectValue(m, func(value ice.Map) {
|
||||
if args[1] == "" || args[1] == value[keys[1]] {
|
||||
m.PushSearch(kit.SimpleKV("", value[keys[0]], value[keys[1]], value[keys[2]]), value)
|
||||
func IsSearchPreview(m *ice.Message, arg []string, cb ...func() []string) bool {
|
||||
if arg[0] == FOREACH && arg[1] == "" {
|
||||
for _, cb := range cb {
|
||||
if cb != nil {
|
||||
if args := cb(); len(args) > 0 {
|
||||
m.PushSearch(TYPE, kit.Select("", args, 0), NAME, kit.Select("", args, 1), TEXT, kit.Select("", args, 2))
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
return m
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
130
base/mdb/zone.go
130
base/mdb/zone.go
@ -2,7 +2,9 @@ package mdb
|
||||
|
||||
import (
|
||||
"encoding/csv"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
ice "shylinux.com/x/icebergs"
|
||||
kit "shylinux.com/x/toolkits"
|
||||
@ -10,31 +12,32 @@ import (
|
||||
"shylinux.com/x/toolkits/miss"
|
||||
)
|
||||
|
||||
func _zone_meta(m *ice.Message, prefix, chain, key string) string {
|
||||
defer RLock(m, prefix)()
|
||||
return m.Conf(prefix, kit.Keys(chain, kit.Keym(key)))
|
||||
}
|
||||
func _zone_fields(m *ice.Message) []string {
|
||||
return kit.Split(kit.Select(ZONE_FIELD, m.OptionFields()))
|
||||
}
|
||||
func _zone_inputs(m *ice.Message, prefix, chain, zone string, field, value string) {
|
||||
if field == _mdb_getmeta(m, prefix, chain, SHORT) {
|
||||
if field == _zone_meta(m, prefix, chain, SHORT) {
|
||||
_hash_inputs(m, prefix, chain, field, value)
|
||||
return
|
||||
}
|
||||
defer RLock(m, prefix, chain)()
|
||||
h := _hash_select_field(m, prefix, chain, zone, HASH)
|
||||
_list_inputs(m, prefix, kit.Keys(chain, HASH, h), field, value)
|
||||
}
|
||||
func _zone_insert(m *ice.Message, prefix, chain, zone string, arg ...string) {
|
||||
h := _hash_select_field(m, prefix, chain, zone, HASH)
|
||||
if h == "" {
|
||||
h = _hash_insert(m, prefix, chain, kit.Select(ZONE, _mdb_getmeta(m, prefix, chain, SHORT)), zone)
|
||||
h = _hash_insert(m, prefix, chain, kit.Select(ZONE, _zone_meta(m, prefix, chain, SHORT)), zone)
|
||||
}
|
||||
m.Assert(h != "")
|
||||
defer Lock(m, prefix, chain)()
|
||||
_list_insert(m, prefix, kit.Keys(chain, HASH, h), arg...)
|
||||
}
|
||||
func _zone_modify(m *ice.Message, prefix, chain, zone, id string, arg ...string) {
|
||||
h := _hash_select_field(m, prefix, chain, zone, HASH)
|
||||
m.Assert(h != "")
|
||||
defer Lock(m, prefix, chain)()
|
||||
_list_modify(m, prefix, kit.Keys(chain, HASH, h), ID, id, arg...)
|
||||
}
|
||||
func _zone_select(m *ice.Message, prefix, chain, zone string, id string) {
|
||||
@ -46,17 +49,23 @@ func _zone_select(m *ice.Message, prefix, chain, zone string, id string) {
|
||||
}
|
||||
defer m.SortIntR(ID)
|
||||
fields := _zone_fields(m)
|
||||
defer RLock(m, prefix, chain)()
|
||||
defer RLock(m, prefix)()
|
||||
Richs(m, prefix, chain, kit.Select(FOREACH, zone), func(key string, val Map) {
|
||||
chain := kit.Keys(chain, HASH, key)
|
||||
defer RLock(m, prefix, chain)()
|
||||
Grows(m, prefix, chain, ID, id, func(value ice.Map) {
|
||||
_mdb_select(m, m.OptionCB(""), key, value, fields, val)
|
||||
})
|
||||
m.StatusTimeCountTotal(kit.Value(val, "meta.count"), "step", "0")
|
||||
})
|
||||
}
|
||||
func _zone_export(m *ice.Message, prefix, chain, file string) {
|
||||
defer Lock(m, prefix, chain)()
|
||||
if !ice.HasUsr() {
|
||||
return
|
||||
}
|
||||
defer Lock(m, prefix)()
|
||||
if len(Confm(m, prefix, kit.Keys(chain, HASH))) == 0 {
|
||||
return
|
||||
}
|
||||
f, p, e := miss.CreateFile(kit.Keys(file, CSV))
|
||||
m.Assert(e)
|
||||
defer f.Close()
|
||||
@ -70,7 +79,6 @@ func _zone_export(m *ice.Message, prefix, chain, file string) {
|
||||
Richs(m, prefix, chain, key, func(key string, val ice.Map) {
|
||||
val = kit.GetMeta(val)
|
||||
chain := kit.Keys(chain, HASH, key)
|
||||
defer Lock(m, prefix, chain)()
|
||||
Grows(m, prefix, chain, "", "", func(value ice.Map) {
|
||||
value = kit.GetMeta(value)
|
||||
w.Write(kit.Simple(head, func(k string) string {
|
||||
@ -79,19 +87,32 @@ func _zone_export(m *ice.Message, prefix, chain, file string) {
|
||||
count++
|
||||
})
|
||||
})
|
||||
m.Conf(prefix, kit.Keys(chain, HASH, key, LIST), "")
|
||||
m.Conf(prefix, kit.Keys(chain, HASH, key, META, COUNT), "")
|
||||
}
|
||||
kit.If(count == 0, func() { os.Remove(p) })
|
||||
m.Logs(EXPORT, KEY, path.Join(prefix, chain), FILE, p, COUNT, count)
|
||||
m.Conf(prefix, kit.Keys(chain, HASH), "")
|
||||
}
|
||||
func _zone_import(m *ice.Message, prefix, chain, file string) {
|
||||
defer Lock(m, prefix, chain)()
|
||||
if !ice.HasUsr() {
|
||||
return
|
||||
}
|
||||
defer Lock(m, prefix)()
|
||||
f, e := miss.OpenFile(kit.Keys(file, CSV))
|
||||
m.Assert(e)
|
||||
if e != nil && !ice.Info.Important {
|
||||
return
|
||||
} else if m.WarnNotFound(e) {
|
||||
return
|
||||
}
|
||||
defer f.Close()
|
||||
r := csv.NewReader(f)
|
||||
head, _ := r.Read()
|
||||
zkey := kit.Select(head[0], m.OptionFields())
|
||||
list := ice.Maps{}
|
||||
times := ice.Maps{}
|
||||
kit.For(m.Confv(prefix, kit.Keys(chain, HASH)), func(key string, value ice.Any) {
|
||||
times[key] = kit.Format(kit.Value(value, kit.Keys(META, TIME)))
|
||||
})
|
||||
count := 0
|
||||
for {
|
||||
line, e := r.Read()
|
||||
@ -115,12 +136,9 @@ func _zone_import(m *ice.Message, prefix, chain, file string) {
|
||||
}
|
||||
if list[zone] == "" {
|
||||
list[zone] = Rich(m, prefix, chain, kit.Data(zkey, zone))
|
||||
kit.If(times[list[zone]], func(t string) { m.Confv(prefix, kit.Keys(chain, HASH, list[zone], META, TIME), t) })
|
||||
}
|
||||
func() {
|
||||
chain := kit.Keys(chain, HASH, list[zone])
|
||||
defer Lock(m, prefix, chain)()
|
||||
Grow(m, prefix, chain, data)
|
||||
}()
|
||||
func() { chain := kit.Keys(chain, HASH, list[zone]); Grow(m, prefix, chain, data) }()
|
||||
count++
|
||||
}
|
||||
m.Logs(IMPORT, KEY, path.Join(prefix, chain), FILE, kit.Keys(file, CSV), COUNT, count)
|
||||
@ -132,23 +150,58 @@ const (
|
||||
)
|
||||
const ZONE = "zone"
|
||||
|
||||
func ZoneConfig(arg ...Any) *ice.Action {
|
||||
return &ice.Action{Hand: func(m *ice.Message, args ...string) {
|
||||
if cs := m.Target().Configs; cs[m.CommandKey()] == nil {
|
||||
cs[m.CommandKey()] = &ice.Config{Value: kit.Data(arg...)}
|
||||
} else {
|
||||
kit.For(kit.Dict(arg...), func(k string, v Any) { Config(m, k, v) })
|
||||
}
|
||||
if cmd := m.Target().Commands[m.CommandKey()]; cmd == nil {
|
||||
return
|
||||
} else {
|
||||
s := kit.Select(ZONE, Config(m, SHORT))
|
||||
kit.If(s == UNIQ || strings.Contains(s, ","), func() { s = HASH })
|
||||
if cmd.Name == "" {
|
||||
cmd.Name = kit.Format("%s %s id auto", m.CommandKey(), s)
|
||||
cmd.List = ice.SplitCmd(cmd.Name, cmd.Actions)
|
||||
}
|
||||
add := func(list []string) (inputs []Any) {
|
||||
kit.For(list, func(k string) {
|
||||
kit.If(!kit.IsIn(k, TIME, HASH, COUNT, ID), func() {
|
||||
inputs = append(inputs, k+kit.Select("", FOREACH, strings.Contains(s, k)))
|
||||
})
|
||||
})
|
||||
return
|
||||
}
|
||||
kit.If(cmd.Meta[INSERT] == nil, func() { m.Design(INSERT, "", add(kit.Simple(kit.Split(s), kit.Split(ZoneField(m))))...) })
|
||||
kit.If(cmd.Meta[CREATE] == nil, func() { m.Design(CREATE, "", add(kit.Split(kit.Select(s, Config(m, FIELD))))...) })
|
||||
}
|
||||
}}
|
||||
}
|
||||
func ZoneAction(arg ...ice.Any) ice.Actions {
|
||||
return ice.Actions{ice.CTX_INIT: AutoConfig(append(kit.List(SHORT, ZONE, FIELD, ZONE_FIELD), arg...)...),
|
||||
return ice.Actions{ice.CTX_INIT: ZoneConfig(append(kit.List(SHORT, ZONE, FIELDS, ZONE_FIELD), arg...)...),
|
||||
INPUTS: {Hand: func(m *ice.Message, arg ...string) { ZoneInputs(m, arg) }},
|
||||
CREATE: {Hand: func(m *ice.Message, arg ...string) { ZoneCreate(m, arg) }},
|
||||
REMOVE: {Hand: func(m *ice.Message, arg ...string) { ZoneRemove(m, arg) }},
|
||||
INSERT: {Hand: func(m *ice.Message, arg ...string) { ZoneInsert(m, arg) }},
|
||||
MODIFY: {Hand: func(m *ice.Message, arg ...string) { ZoneModify(m, arg) }},
|
||||
SELECT: {Name: "select zone id auto insert", Hand: func(m *ice.Message, arg ...string) { ZoneSelect(m, arg...) }},
|
||||
SELECT: {Hand: func(m *ice.Message, arg ...string) { ZoneSelect(m, arg...) }},
|
||||
EXPORT: {Hand: func(m *ice.Message, arg ...string) { ZoneExport(m, arg) }},
|
||||
IMPORT: {Hand: func(m *ice.Message, arg ...string) { ZoneImport(m, arg) }},
|
||||
}
|
||||
}
|
||||
func ExportZoneAction(arg ...ice.Any) ice.Actions {
|
||||
return ice.MergeActions(ice.Actions{
|
||||
ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) { Config(m, IMPORTANT, ice.TRUE); ZoneImport(m, arg) }},
|
||||
ice.CTX_EXIT: {Hand: func(m *ice.Message, arg ...string) { m.OptionFields(""); ZoneExport(m, arg) }},
|
||||
}, ZoneAction(arg...))
|
||||
}
|
||||
func PageZoneAction(arg ...ice.Any) ice.Actions {
|
||||
return ice.MergeActions(ice.Actions{
|
||||
SELECT: {Name: "select zone id auto insert page", Hand: func(m *ice.Message, arg ...string) { PageZoneSelect(m, arg...) }},
|
||||
NEXT: {Hand: func(m *ice.Message, arg ...string) { NextPage(m, arg[0], arg[1:]...) }},
|
||||
SELECT: {Hand: func(m *ice.Message, arg ...string) { PageZoneSelect(m, arg...) }},
|
||||
PREV: {Hand: func(m *ice.Message, arg ...string) { PrevPageLimit(m, arg[0], arg[1:]...) }},
|
||||
NEXT: {Hand: func(m *ice.Message, arg ...string) { NextPage(m, arg[0], arg[1:]...) }},
|
||||
}, ZoneAction(arg...))
|
||||
}
|
||||
func ZoneKey(m *ice.Message) string {
|
||||
@ -158,15 +211,13 @@ func ZoneKey(m *ice.Message) string {
|
||||
return ZoneShort(m)
|
||||
}
|
||||
func ZoneShort(m *ice.Message) string {
|
||||
return kit.Select(ZONE, m.Config(SHORT), m.Config(SHORT) != UNIQ)
|
||||
return kit.Select(ZONE, Config(m, SHORT), Config(m, SHORT) != UNIQ)
|
||||
}
|
||||
func ZoneField(m *ice.Message) string { return kit.Select(ZONE_FIELD, m.Config(FIELD)) }
|
||||
func ZoneField(m *ice.Message) string { return kit.Select(ZONE_FIELD, Config(m, FIELDS)) }
|
||||
func ZoneInputs(m *ice.Message, arg ...Any) {
|
||||
m.Cmdy(INPUTS, m.PrefixKey(), "", ZONE, m.Option(ZoneKey(m)), arg)
|
||||
}
|
||||
func ZoneCreate(m *ice.Message, arg ...Any) {
|
||||
m.Cmdy(INSERT, m.PrefixKey(), "", HASH, arg)
|
||||
}
|
||||
func ZoneCreate(m *ice.Message, arg ...Any) { m.Cmdy(INSERT, m.PrefixKey(), "", HASH, arg) }
|
||||
func ZoneRemove(m *ice.Message, arg ...Any) {
|
||||
if args := kit.Simple(arg...); len(args) == 0 {
|
||||
arg = append(arg, m.OptionSimple(ZoneKey(m)))
|
||||
@ -185,26 +236,29 @@ func ZoneInsert(m *ice.Message, arg ...Any) {
|
||||
}
|
||||
}
|
||||
func ZoneModify(m *ice.Message, arg ...Any) {
|
||||
if args := kit.Simple(arg...); args[0] == HASH || args[0] == ZoneShort(m) {
|
||||
m.Cmdy(MODIFY, m.PrefixKey(), "", ZONE, args[1], args[3], arg[4:])
|
||||
if args := kit.Simple(arg...); m.Option(ID) == "" {
|
||||
HashModify(m, arg...)
|
||||
} else if args[0] == HASH || args[0] == ZoneShort(m) {
|
||||
m.Cmdy(MODIFY, m.PrefixKey(), "", ZONE, args[1], args[3], args[4:])
|
||||
} else {
|
||||
m.Cmdy(MODIFY, m.PrefixKey(), "", ZONE, m.Option(ZoneKey(m)), m.Option(ID), arg)
|
||||
}
|
||||
}
|
||||
func ZoneSelect(m *ice.Message, arg ...string) *ice.Message {
|
||||
arg = kit.Slice(arg, 0, 2)
|
||||
m.Fields(len(arg), kit.Select(kit.Fields(TIME, m.Config(SHORT), COUNT), m.Config(FIELDS)), ZoneField(m))
|
||||
short, field, fields := Config(m, SHORT), Config(m, FIELD), ZoneField(m)
|
||||
m.Fields(len(arg), kit.Select(kit.Fields(TIME, short, COUNT), field), fields)
|
||||
if m.Cmdy(SELECT, m.PrefixKey(), "", ZONE, arg, logs.FileLineMeta(-1)); len(arg) == 0 {
|
||||
m.PushAction(m.Config(ACTION), REMOVE).StatusTimeCount().Sort(ZoneShort(m))
|
||||
m.Sort(short).PushAction(REMOVE).Action(CREATE)
|
||||
} else if len(arg) == 1 {
|
||||
m.StatusTimeCountTotal(_mdb_getmeta(m, "", kit.Keys(HASH, HashSelectField(m, arg[0], HASH)), COUNT))
|
||||
m.Action(INSERT)
|
||||
} else {
|
||||
sortByField(m, fields)
|
||||
}
|
||||
return m
|
||||
}
|
||||
func ZoneExport(m *ice.Message, arg ...Any) {
|
||||
if m.OptionFields() == "" {
|
||||
m.OptionFields(m.Config(SHORT), ZoneField(m))
|
||||
}
|
||||
kit.If(m.OptionFields() == "", func() { m.OptionFields(Config(m, SHORT), ZoneField(m)) })
|
||||
m.Cmdy(EXPORT, m.PrefixKey(), "", ZONE, arg)
|
||||
}
|
||||
func ZoneImport(m *ice.Message, arg ...Any) {
|
||||
@ -225,5 +279,11 @@ func ZoneSelectCB(m *ice.Message, zone string, cb Any) *ice.Message {
|
||||
}
|
||||
func PageZoneSelect(m *ice.Message, arg ...string) *ice.Message {
|
||||
OptionPages(m, kit.Slice(arg, 2)...)
|
||||
return ZoneSelect(m, arg...)
|
||||
arg = kit.Slice(arg, 0, 2)
|
||||
if ZoneSelect(m, arg...); len(arg) == 0 {
|
||||
m.Action(CREATE)
|
||||
} else if len(arg) == 1 {
|
||||
m.Action(INSERT, PAGE)
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
255
base/nfs/cat.go
255
base/nfs/cat.go
@ -1,10 +1,12 @@
|
||||
package nfs
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"encoding/csv"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
@ -14,71 +16,50 @@ import (
|
||||
kit "shylinux.com/x/toolkits"
|
||||
)
|
||||
|
||||
func _cat_find(m *ice.Message, file string) (io.ReadCloser, error) {
|
||||
func _cat_find(m *ice.Message, p string) (io.ReadCloser, error) {
|
||||
if m.Option(CAT_CONTENT) != "" {
|
||||
return NewReadCloser(bytes.NewBufferString(m.Option(CAT_CONTENT))), nil
|
||||
}
|
||||
return OpenFile(m, path.Join(m.Option(DIR_ROOT), file))
|
||||
return OpenFile(m, path.Join(m.Option(DIR_ROOT), p))
|
||||
}
|
||||
func _cat_size(m *ice.Message, file string) (nline int) {
|
||||
if f, e := OpenFile(m, file); !m.Warn(e) {
|
||||
defer f.Close()
|
||||
for bio := bufio.NewScanner(f); bio.Scan(); nline++ {
|
||||
bio.Text()
|
||||
}
|
||||
}
|
||||
return nline
|
||||
func _cat_hash(m *ice.Message, p string) (h string) {
|
||||
Open(m, p, func(r io.Reader) { h = kit.Hashs(r) })
|
||||
return
|
||||
}
|
||||
func _cat_hash(m *ice.Message, file string) string {
|
||||
if f, e := OpenFile(m, file); !m.Warn(e) {
|
||||
defer f.Close()
|
||||
return kit.Hashs(f)
|
||||
}
|
||||
return ""
|
||||
func _cat_line(m *ice.Message, p string) (n int) {
|
||||
Open(m, p, func(r io.Reader) { kit.For(r, func(s string) { n++ }) })
|
||||
return
|
||||
}
|
||||
func _cat_list(m *ice.Message, file string) {
|
||||
if m.Option(CAT_CONTENT) == "" && !aaa.Right(m, file) {
|
||||
func _cat_list(m *ice.Message, p string) {
|
||||
if m.Option(CAT_CONTENT) == "" && !kit.IsIn(kit.Ext(p), "css", "js") && !aaa.Right(m, path.Join(m.Option(DIR_ROOT), p)) {
|
||||
return
|
||||
}
|
||||
f, e := _cat_find(m, file)
|
||||
if m.Warn(e, ice.ErrNotFound, file) {
|
||||
f, e := _cat_find(m, p)
|
||||
if m.WarnNotFound(e, FILE, p) {
|
||||
return
|
||||
}
|
||||
defer f.Close()
|
||||
switch cb := m.OptionCB("").(type) {
|
||||
case func(string, int) string:
|
||||
list := []string{}
|
||||
for bio, i := bufio.NewScanner(f), 0; bio.Scan(); i++ {
|
||||
list = append(list, cb(bio.Text(), i))
|
||||
}
|
||||
kit.For(f, func(s string, i int) { list = append(list, cb(s, i)) })
|
||||
m.Echo(strings.Join(list, ice.NL) + ice.NL)
|
||||
case func([]string, string) string:
|
||||
list := []string{}
|
||||
kit.For(f, func(s string, i int) { list = append(list, cb(kit.Split(s), s)) })
|
||||
m.Echo(strings.Join(list, ice.NL) + ice.NL)
|
||||
case func(string, int):
|
||||
for bio, i := bufio.NewScanner(f), 0; bio.Scan(); i++ {
|
||||
cb(bio.Text(), i)
|
||||
}
|
||||
kit.For(f, cb)
|
||||
case func(string):
|
||||
for bio := bufio.NewScanner(f); bio.Scan(); {
|
||||
cb(bio.Text())
|
||||
}
|
||||
kit.For(f, cb)
|
||||
case func([]string, string):
|
||||
for bio := bufio.NewScanner(f); bio.Scan(); {
|
||||
cb(kit.Split(bio.Text()), bio.Text())
|
||||
}
|
||||
kit.For(f, cb)
|
||||
case func([]string):
|
||||
kit.For(f, cb)
|
||||
case nil:
|
||||
buf, size := make([]byte, 10*ice.MOD_BUFS), 0
|
||||
for {
|
||||
if n, e := f.Read(buf[size:]); !m.Warn(e, ice.ErrNotValid, file) {
|
||||
m.Logs(mdb.IMPORT, FILE, file, SIZE, n)
|
||||
if size += n; size < len(buf) {
|
||||
buf = buf[:size]
|
||||
break
|
||||
}
|
||||
buf = append(buf, make([]byte, ice.MOD_BUFS)...)
|
||||
} else {
|
||||
break
|
||||
}
|
||||
if b, e := ioutil.ReadAll(f); !m.WarnNotFound(e) {
|
||||
m.Echo(string(b)).StatusTime(FILE, p, SIZE, len(b))
|
||||
}
|
||||
m.Echo(string(buf)).StatusTime(FILE, file, SIZE, size)
|
||||
default:
|
||||
m.ErrorNotImplement(cb)
|
||||
}
|
||||
@ -86,49 +67,60 @@ func _cat_list(m *ice.Message, file string) {
|
||||
|
||||
const (
|
||||
CAT_CONTENT = "cat_content"
|
||||
CONFIGURE = "configure"
|
||||
STDIO = "stdio"
|
||||
|
||||
STDIO = "stdio"
|
||||
TAGS = "tags"
|
||||
MODULE = "module"
|
||||
SOURCE = "source"
|
||||
SCRIPT = "script"
|
||||
BINARY = "binary"
|
||||
TARGET = "target"
|
||||
TAGS = "tags"
|
||||
BINARY = "binary"
|
||||
SCRIPT = "script"
|
||||
FORMAT = "format"
|
||||
TRANS = "trans"
|
||||
|
||||
TEMPLATE = "template"
|
||||
VERSION = "version"
|
||||
MASTER = "master"
|
||||
BRANCH = "branch"
|
||||
REMOTE = "remote"
|
||||
REPOS = "repos"
|
||||
CLONE = "clone"
|
||||
REPOS = "repos"
|
||||
REMOTE = "remote"
|
||||
ORIGIN = "origin"
|
||||
COMMIT = "commit"
|
||||
BRANCH = "branch"
|
||||
MASTER = "master"
|
||||
VERSION = "version"
|
||||
COMPILE = "compile"
|
||||
)
|
||||
const (
|
||||
SVG = ice.SVG
|
||||
HTML = ice.HTML
|
||||
CSS = ice.CSS
|
||||
SVG = ice.SVG
|
||||
JS = ice.JS
|
||||
GO = ice.GO
|
||||
SH = ice.SH
|
||||
SHY = ice.SHY
|
||||
CSV = ice.CSV
|
||||
JSON = ice.JSON
|
||||
MOD = "mod"
|
||||
|
||||
PY = "py"
|
||||
MD = "md"
|
||||
TXT = "txt"
|
||||
XML = "xml"
|
||||
YML = "yml"
|
||||
ZML = "zml"
|
||||
IML = "iml"
|
||||
PROTO = "proto"
|
||||
YAML = "yaml"
|
||||
CONF = "conf"
|
||||
XML = "xml"
|
||||
YML = "yml"
|
||||
TXT = "txt"
|
||||
MD = "md"
|
||||
PY = "py"
|
||||
|
||||
PNG = "png"
|
||||
JPG = "jpg"
|
||||
MP4 = "mp4"
|
||||
PDF = "pdf"
|
||||
IMAGE = "image"
|
||||
JPEG = "jpeg"
|
||||
JPG = "jpg"
|
||||
PNG = "png"
|
||||
MP4 = "mp4"
|
||||
MOV = "mov"
|
||||
PDF = "pdf"
|
||||
|
||||
PWD = "./"
|
||||
PS = ice.PS
|
||||
PT = ice.PT
|
||||
DF = ice.DF
|
||||
PS = ice.PS
|
||||
PT = ice.PT
|
||||
)
|
||||
|
||||
const CAT = "cat"
|
||||
@ -136,32 +128,109 @@ const CAT = "cat"
|
||||
func init() {
|
||||
Index.MergeCommands(ice.Commands{
|
||||
CAT: {Name: "cat path auto", Help: "文件", Actions: ice.MergeActions(ice.Actions{
|
||||
ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) { aaa.White(m, ice.SRC_MAIN_JS, ice.SRC_MAIN_GO, ice.SRC_MAIN_SHY) }},
|
||||
}, ice.Actions{ice.CTX_INIT: mdb.AutoConfig(SOURCE, kit.DictList(
|
||||
HTML, CSS, JS, GO, SH, SHY, CSV, JSON,
|
||||
PY, MD, TXT, XML, YML, ZML, IML,
|
||||
"license", "makefile", "configure", "conf",
|
||||
))}), Hand: func(m *ice.Message, arg ...string) {
|
||||
if len(arg) == 0 || strings.HasSuffix(arg[0], ice.PS) {
|
||||
m.Cmdy(DIR, arg)
|
||||
return
|
||||
ice.CTX_INIT: mdb.AutoConfig(SOURCE, kit.DictList(
|
||||
HTML, CSS, JS, GO, SH, PY, SHY, CSV, JSON, CONFIGURE, PROTO, YAML, CONF, XML, YML, TXT, MD, strings.ToLower(ice.LICENSE), strings.ToLower(ice.MAKEFILE),
|
||||
)),
|
||||
}, DIR), Hand: func(m *ice.Message, arg ...string) {
|
||||
if !DirList(m, arg...) {
|
||||
if arg[0] != "" {
|
||||
m.Logs(FIND, m.OptionSimple(DIR_ROOT), FILE, arg[0])
|
||||
}
|
||||
_cat_list(m, arg[0])
|
||||
}
|
||||
if m.Option(DIR_ROOT) != "" {
|
||||
m.Logs(mdb.SELECT, m.OptionSimple(DIR_ROOT))
|
||||
}
|
||||
_cat_list(m, arg[0])
|
||||
}},
|
||||
})
|
||||
}
|
||||
func IsSourceFile(m *ice.Message, ext string) bool {
|
||||
return m.Conf(CAT, kit.Keym(SOURCE, ext)) == ice.TRUE
|
||||
}
|
||||
func OptionLoad(m *ice.Message, file string) *ice.Message {
|
||||
if f, e := OpenFile(m, file); e == nil {
|
||||
defer f.Close()
|
||||
var data ice.Any
|
||||
m.Assert(json.NewDecoder(f).Decode(&data))
|
||||
kit.Fetch(data, func(key string, value ice.Any) { m.Option(key, kit.Simple(value)) })
|
||||
|
||||
func DirList(m *ice.Message, arg ...string) bool {
|
||||
if len(arg) == 0 || strings.HasSuffix(arg[0], PS) {
|
||||
m.Cmdy(DIR, kit.Slice(arg, 0, 1))
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func IsSourceFile(m *ice.Message, ext string) bool {
|
||||
return mdb.Conf(m, Prefix(CAT), kit.Keym(SOURCE, ext)) == ice.TRUE
|
||||
}
|
||||
func OptionLoad(m *ice.Message, p string) *ice.Message {
|
||||
Open(m, p, func(r io.Reader) {
|
||||
var data ice.Any
|
||||
m.Assert(json.NewDecoder(r).Decode(&data))
|
||||
kit.For(data, func(k string, v ice.Any) { m.Optionv(k, v) })
|
||||
})
|
||||
return m
|
||||
}
|
||||
func Open(m *ice.Message, p string, cb ice.Any) {
|
||||
if p == "" {
|
||||
return
|
||||
} else if strings.HasSuffix(p, PS) {
|
||||
kit.If(p == PS, func() { p = "" })
|
||||
if ls, e := ReadDir(m, p); !m.WarnNotFound(e) {
|
||||
switch cb := cb.(type) {
|
||||
case func([]os.FileInfo):
|
||||
cb(ls)
|
||||
case func(os.FileInfo):
|
||||
kit.For(ls, cb)
|
||||
case func(io.Reader, string):
|
||||
kit.For(ls, func(s os.FileInfo) { kit.If(!s.IsDir(), func() { Open(m, path.Join(p, s.Name()), cb) }) })
|
||||
default:
|
||||
m.ErrorNotImplement(cb)
|
||||
}
|
||||
}
|
||||
} else if f, e := OpenFile(m, p); !m.WarnNotFound(e, p) {
|
||||
defer f.Close()
|
||||
switch cb := cb.(type) {
|
||||
case func(io.Reader, os.FileInfo):
|
||||
s, _ := StatFile(m, p)
|
||||
cb(f, s)
|
||||
case func(io.Reader, string):
|
||||
cb(f, p)
|
||||
case func(io.Reader):
|
||||
cb(f)
|
||||
case func(string):
|
||||
if b, e := ioutil.ReadAll(f); !m.WarnNotFound(e) {
|
||||
cb(string(b))
|
||||
}
|
||||
default:
|
||||
m.ErrorNotImplement(cb)
|
||||
}
|
||||
}
|
||||
}
|
||||
func ReadAll(m *ice.Message, r io.Reader) []byte {
|
||||
if b, e := ioutil.ReadAll(r); !m.WarnNotFound(e) {
|
||||
return b
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func ReadFile(m *ice.Message, p string) (b []byte, e error) {
|
||||
Open(m, p, func(r io.Reader) { b, e = ioutil.ReadAll(r) })
|
||||
return
|
||||
}
|
||||
func Rewrite(m *ice.Message, p string, cb func(string) string) {
|
||||
m.Cmd(SAVE, p, m.Cmdx(CAT, p, func(s string, i int) string { return cb(s) }))
|
||||
}
|
||||
func ScanCSV(m *ice.Message, file string, cb func([]string), arg ...string) {
|
||||
f, e := OpenFile(m, file)
|
||||
if m.Warn(e) {
|
||||
return
|
||||
}
|
||||
r := csv.NewReader(f)
|
||||
head, err := r.Read()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
index := []int{}
|
||||
kit.If(len(arg) == 0, func() { arg = append(arg, head...) })
|
||||
kit.For(arg, func(h string) { index = append(index, kit.IndexOf(head, h)) })
|
||||
for {
|
||||
data, err := r.Read()
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
res := []string{}
|
||||
kit.For(index, func(i int) { res = append(res, data[i]) })
|
||||
cb(res)
|
||||
}
|
||||
}
|
||||
|
264
base/nfs/dir.go
264
base/nfs/dir.go
@ -4,7 +4,9 @@ import (
|
||||
"os"
|
||||
"path"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
ice "shylinux.com/x/icebergs"
|
||||
"shylinux.com/x/icebergs/base/aaa"
|
||||
@ -12,87 +14,76 @@ import (
|
||||
kit "shylinux.com/x/toolkits"
|
||||
)
|
||||
|
||||
func _dir_size(m *ice.Message, dir string) int {
|
||||
if ls, e := ReadDir(m, dir); !m.Warn(e) {
|
||||
return len(ls)
|
||||
}
|
||||
return 0
|
||||
func _dir_size(m *ice.Message, p string) (n int) {
|
||||
Open(m, p+PS, func(ls []os.FileInfo) { n = len(ls) })
|
||||
return
|
||||
}
|
||||
func _dir_hash(m *ice.Message, dir string) string {
|
||||
if ls, e := ReadDir(m, dir); !m.Warn(e) {
|
||||
meta := []string{}
|
||||
for _, s := range ls {
|
||||
meta = append(meta, kit.Format("%s%d%s", s.Name(), s.Size(), s.ModTime()))
|
||||
}
|
||||
return kit.Hashs(meta)
|
||||
}
|
||||
func _dir_hash(m *ice.Message, p string) (h string) {
|
||||
list := []string{}
|
||||
Open(m, p+PS, func(s os.FileInfo) { list = append(list, kit.Format("%s%d%s", s.Name(), s.Size(), s.ModTime())) })
|
||||
kit.If(len(list) > 0, func() { h = kit.Hashs(list) })
|
||||
return ""
|
||||
}
|
||||
func _dir_list(m *ice.Message, root string, dir string, level int, deep bool, dir_type string, dir_reg *regexp.Regexp, fields []string) *ice.Message {
|
||||
func _dir_list(m *ice.Message, root string, dir string, level int, deep bool, dir_type string, dir_reg *regexp.Regexp, fields []string) (total int64, last time.Time) {
|
||||
ls, _ := ReadDir(m, path.Join(root, dir))
|
||||
if len(ls) == 0 {
|
||||
if s, e := StatFile(m, path.Join(root, dir)); e == nil && !s.IsDir() {
|
||||
_ls, _ := ReadDir(m, path.Dir(path.Join(root, dir)))
|
||||
for _, s := range _ls {
|
||||
if s.Name() == path.Base(dir) {
|
||||
ls = append(ls, s)
|
||||
}
|
||||
}
|
||||
Open(m, path.Dir(path.Join(root, dir))+PS, func(s os.FileInfo) { kit.If(s.Name() == path.Base(dir), func() { ls = append(ls, s) }) })
|
||||
dir, deep = path.Dir(dir), false
|
||||
}
|
||||
}
|
||||
for _, f := range ls {
|
||||
if f.Name() == ice.PT || f.Name() == ".." {
|
||||
for _, s := range ls {
|
||||
if s.Name() == PT || s.Name() == ".." || strings.HasPrefix(s.Name(), PT) && dir_type != TYPE_ALL {
|
||||
continue
|
||||
}
|
||||
if strings.HasPrefix(f.Name(), ice.PT) && dir_type != TYPE_ALL {
|
||||
continue
|
||||
}
|
||||
p, _dir := path.Join(root, dir, f.Name()), path.Join(dir, f.Name())
|
||||
isDir := f.IsDir() || kit.IsDir(p)
|
||||
if !(dir_type == TYPE_CAT && isDir || dir_type == TYPE_DIR && !isDir) && (dir_reg == nil || dir_reg.MatchString(f.Name())) {
|
||||
p, pp := path.Join(root, dir, s.Name()), path.Join(dir, s.Name())
|
||||
isDir := s.IsDir() || kit.IsDir(p) && deep == false
|
||||
isBin := s.Mode().String()[3] == 'x' || kit.Ext(s.Name()) == "exe"
|
||||
if !(dir_type == TYPE_BIN && (!isBin || isDir) || dir_type == TYPE_CAT && isDir || dir_type == TYPE_DIR && !isDir) && (dir_reg == nil || dir_reg.MatchString(s.Name())) {
|
||||
switch cb := m.OptionCB("").(type) {
|
||||
case func(f os.FileInfo, p string):
|
||||
cb(f, p)
|
||||
case func(os.FileInfo, string):
|
||||
cb(s, p)
|
||||
continue
|
||||
case func(p string):
|
||||
case func(string):
|
||||
cb(p)
|
||||
continue
|
||||
case nil:
|
||||
default:
|
||||
m.ErrorNotImplement(cb)
|
||||
}
|
||||
kit.If(s.ModTime().After(last), func() { last = s.ModTime() })
|
||||
for _, field := range fields {
|
||||
switch field {
|
||||
case mdb.TIME:
|
||||
m.Push(field, f.ModTime().Format(ice.MOD_TIME))
|
||||
m.Push(field, s.ModTime().Format(ice.MOD_TIME))
|
||||
case mdb.TYPE:
|
||||
m.Push(field, kit.Select(CAT, DIR, isDir))
|
||||
case TREE:
|
||||
if level == 0 {
|
||||
m.Push(field, f.Name())
|
||||
m.Push(field, s.Name())
|
||||
} else {
|
||||
m.Push(field, strings.Repeat("| ", level-1)+"|-"+f.Name())
|
||||
m.Push(field, strings.Repeat("| ", level-1)+"|-"+s.Name())
|
||||
}
|
||||
case FULL:
|
||||
m.Push(field, p+kit.Select("", ice.PS, isDir))
|
||||
m.Push(field, p+kit.Select("", PS, isDir))
|
||||
case PATH:
|
||||
m.Push(field, _dir+kit.Select("", ice.PS, isDir))
|
||||
m.Push(field, pp+kit.Select("", PS, isDir))
|
||||
case FILE:
|
||||
m.Push(field, f.Name()+kit.Select("", ice.PS, isDir))
|
||||
m.Push(field, s.Name()+kit.Select("", PS, isDir))
|
||||
case NAME:
|
||||
m.Push(field, f.Name())
|
||||
m.Push(field, s.Name())
|
||||
case SIZE:
|
||||
if isDir {
|
||||
m.Push(field, _dir_size(m, p))
|
||||
} else {
|
||||
m.Push(field, kit.FmtSize(f.Size()))
|
||||
m.Push(field, kit.FmtSize(s.Size()))
|
||||
total += s.Size()
|
||||
}
|
||||
case LINE:
|
||||
if isDir {
|
||||
m.Push(field, _dir_size(m, p))
|
||||
} else {
|
||||
m.Push(field, _cat_size(m, p))
|
||||
m.Push(field, _cat_line(m, p))
|
||||
}
|
||||
case mdb.HASH, "hashs":
|
||||
h := ""
|
||||
@ -103,9 +94,17 @@ func _dir_list(m *ice.Message, root string, dir string, level int, deep bool, di
|
||||
}
|
||||
m.Push(mdb.HASH, kit.Select(h[:6], h[:], field == mdb.HASH))
|
||||
case mdb.LINK:
|
||||
m.PushDownload(mdb.LINK, kit.Select("", f.Name(), !isDir), p)
|
||||
if isDir {
|
||||
m.Push(mdb.LINK, "")
|
||||
} else {
|
||||
if strings.Contains(p, "ice.windows") {
|
||||
m.PushDownload(mdb.LINK, "ice.exe", p)
|
||||
} else {
|
||||
m.PushDownload(mdb.LINK, p)
|
||||
}
|
||||
}
|
||||
case mdb.SHOW:
|
||||
switch p := kit.MergeURL("/share/local/"+p, ice.POD, m.Option(ice.MSG_USERPOD)); kit.Ext(f.Name()) {
|
||||
switch p := m.MergeLink(SHARE_LOCAL+p, ice.POD, m.Option(ice.MSG_USERPOD)); kit.Ext(s.Name()) {
|
||||
case PNG, JPG:
|
||||
m.PushImages(field, p)
|
||||
case MP4:
|
||||
@ -117,40 +116,101 @@ func _dir_list(m *ice.Message, root string, dir string, level int, deep bool, di
|
||||
if m.IsCliUA() || m.Option(ice.MSG_USERROLE) == aaa.VOID {
|
||||
break
|
||||
}
|
||||
m.PushButton(TRASH)
|
||||
m.PushButton(mdb.SHOW, "rename", TRASH)
|
||||
default:
|
||||
m.Push(field, "")
|
||||
}
|
||||
}
|
||||
}
|
||||
if deep && isDir {
|
||||
switch f.Name() {
|
||||
case "node_modules", "pluged", "target", "trash":
|
||||
switch s.Name() {
|
||||
case "pluged", "node_modules":
|
||||
continue
|
||||
}
|
||||
_dir_list(m, root, _dir, level+1, deep, dir_type, dir_reg, fields)
|
||||
_total, _last := _dir_list(m, root, pp, level+1, deep, dir_type, dir_reg, fields)
|
||||
if total += _total; _last.After(last) {
|
||||
last = _last
|
||||
}
|
||||
}
|
||||
}
|
||||
return m
|
||||
return
|
||||
}
|
||||
|
||||
const (
|
||||
PWD = "./"
|
||||
SRC = "src/"
|
||||
ETC = "etc/"
|
||||
BIN = "bin/"
|
||||
VAR = "var/"
|
||||
USR = "usr/"
|
||||
|
||||
SCAN = "scan"
|
||||
GOWORK = "gowork"
|
||||
|
||||
PORTAL_GO = "portal.go"
|
||||
PORTAL_JSON = "portal.json"
|
||||
ETC_LOCAL_SH = "etc/local.sh"
|
||||
ETC_CERT_KEY = "etc/cert/cert.key"
|
||||
ETC_CERT_PEM = "etc/cert/cert.pem"
|
||||
SRC_DOCUMENT = "src/document/"
|
||||
SRC_PRIVATE = "src/private/"
|
||||
SRC_MAIN_PNG = "src/main.png"
|
||||
SRC_OPTION_GO = "src/option.go"
|
||||
SRC_TEMPLATE = ice.SRC_TEMPLATE
|
||||
USR_TOOLKITS = ice.USR_TOOLKITS
|
||||
USR_ICEBERGS = ice.USR_ICEBERGS
|
||||
USR_RELEASE = ice.USR_RELEASE
|
||||
USR_PUBLISH = ice.USR_PUBLISH
|
||||
USR_LOCAL = ice.USR_LOCAL
|
||||
USR_LOCAL_WORK = ice.USR_LOCAL_WORK
|
||||
USR_IMAGE = "usr/image/"
|
||||
USR_MATERIAL = "usr/material/"
|
||||
USR_LOCAL_IMAGE = "usr/local/image/"
|
||||
USR_LEARNING_PORTAL = "usr/learning/portal/"
|
||||
USR_MODULES = "usr/node_modules/"
|
||||
USR_PACKAGE = "usr/package.json"
|
||||
|
||||
VAR_LOG_BENCH_LOG = "var/log/bench.log"
|
||||
USR_ICONS_AVATAR = "usr/icons/avatar.jpg"
|
||||
USR_ICONS_CONTEXTS = "usr/icons/contexts.jpg"
|
||||
USR_ICONS_ICEBERGS = "usr/icons/icebergs.png"
|
||||
USR_ICONS_VOLCANOS = "usr/icons/volcanos.png"
|
||||
USR_ICONS = "usr/icons/"
|
||||
|
||||
V = "/v/"
|
||||
M = "/m/"
|
||||
P = "/p/"
|
||||
X = "/x/"
|
||||
S = "/s/"
|
||||
C = "/c/"
|
||||
INTSHELL = "/intshell/"
|
||||
VOLCANOS = "/volcanos/"
|
||||
VOLCANOS_PLUGIN = "/volcanos/plugin/"
|
||||
REQUIRE_MODULES = "/require/modules/"
|
||||
REQUIRE_USR = "/require/usr/"
|
||||
REQUIRE_SRC = "/require/src/"
|
||||
REQUIRE = "/require/"
|
||||
PLUGIN = "/plugin/"
|
||||
SHARE_LOCAL = "/share/local/"
|
||||
PATHNAME = "pathname"
|
||||
FILENAME = "filename"
|
||||
CONTEXTS = "contexts"
|
||||
|
||||
TYPE_ALL = "all"
|
||||
TYPE_BIN = "bin"
|
||||
TYPE_CAT = "cat"
|
||||
TYPE_DIR = "dir"
|
||||
TYPE_BOTH = "both"
|
||||
)
|
||||
const (
|
||||
|
||||
DIR_ROOT = "dir_root"
|
||||
DIR_TYPE = "dir_type"
|
||||
DIR_DEEP = "dir_deep"
|
||||
DIR_TYPE = "dir_type"
|
||||
DIR_REG = "dir_reg"
|
||||
|
||||
DIR_DEF_FIELDS = "time,path,size,action"
|
||||
DIR_WEB_FIELDS = "time,size,path,link,action"
|
||||
DIR_WEB_FIELDS = "time,path,size,link,action"
|
||||
DIR_CLI_FIELDS = "path,size,time"
|
||||
)
|
||||
const (
|
||||
|
||||
ROOT = "root"
|
||||
TREE = "tree"
|
||||
FULL = "full"
|
||||
@ -164,40 +224,104 @@ const DIR = "dir"
|
||||
|
||||
func init() {
|
||||
Index.MergeCommands(ice.Commands{
|
||||
DIR: {Name: "dir path field auto upload", Help: "目录", Actions: ice.Actions{
|
||||
DIR: {Name: "dir path auto upload app", Icon: "dir.png", Help: "文件夹", Actions: ice.Actions{
|
||||
ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) {
|
||||
aaa.White(m, ice.SRC, ice.BIN, ice.USR, ice.USR_PUBLISH, ice.USR_LOCAL_GO)
|
||||
aaa.Black(m, ice.BIN_BOOT_LOG, ice.USR_LOCAL)
|
||||
aaa.White(m, ice.MAKEFILE, ice.README_MD, ice.LICENSE)
|
||||
aaa.White(m, ice.SRC, ice.BIN, ice.USR)
|
||||
aaa.Black(m, ice.SRC_PRIVATE)
|
||||
aaa.Black(m, ice.USR_LOCAL)
|
||||
}},
|
||||
ice.APP: {Help: "本机", Hand: func(m *ice.Message, arg ...string) {
|
||||
switch runtime.GOOS {
|
||||
case "darwin":
|
||||
m.System("open", kit.Path(m.Option(PATH)))
|
||||
}
|
||||
}},
|
||||
mdb.SHOW: {Help: "预览", Hand: func(m *ice.Message, arg ...string) {
|
||||
Show(m.ProcessInner(), path.Join(m.Option(DIR_ROOT), m.Option(PATH)))
|
||||
}}, mdb.UPLOAD: {},
|
||||
TRASH: {Hand: func(m *ice.Message, arg ...string) { m.Cmd(TRASH, mdb.CREATE, m.Option(PATH)) }},
|
||||
SIZE: {Hand: func(m *ice.Message, arg ...string) {
|
||||
m.Echo(kit.Select("", kit.Split(m.System("du", "-sh").Result()), 0))
|
||||
}},
|
||||
"rename": {Name: "rename to", Hand: func(m *ice.Message, arg ...string) {
|
||||
m.Cmd(MOVE, path.Join(path.Dir(m.Option(PATH)), m.Option(TO)), m.Option(PATH))
|
||||
}},
|
||||
TRASH: {Hand: func(m *ice.Message, arg ...string) {
|
||||
m.Cmd(TRASH, mdb.CREATE, m.Option(PATH))
|
||||
}},
|
||||
}, Hand: func(m *ice.Message, arg ...string) {
|
||||
root, dir := kit.Select(PWD, m.Option(DIR_ROOT)), kit.Select(PWD, arg, 0)
|
||||
if strings.HasPrefix(dir, ice.PS) {
|
||||
root = ice.PS
|
||||
}
|
||||
kit.If(strings.HasPrefix(dir, PS), func() { root = "" })
|
||||
if !aaa.Right(m, path.Join(root, dir)) {
|
||||
return
|
||||
}
|
||||
m.Logs(FIND, DIR_ROOT, root, PATH, dir, m.OptionSimple(DIR_TYPE, DIR_REG))
|
||||
fields := kit.Split(kit.Select(kit.Select(DIR_DEF_FIELDS, m.OptionFields()), kit.Join(kit.Slice(arg, 1))))
|
||||
if root != "" {
|
||||
m.Logs(mdb.SELECT, DIR_ROOT, root)
|
||||
}
|
||||
_dir_list(m, root, dir, 0, m.Option(DIR_DEEP) == ice.TRUE, kit.Select(TYPE_BOTH, m.Option(DIR_TYPE)), kit.Regexp(m.Option(DIR_REG)), fields)
|
||||
m.StatusTimeCount()
|
||||
size, last := _dir_list(m, root, dir, 0, m.Option(DIR_DEEP) == ice.TRUE, kit.Select(TYPE_BOTH, m.Option(DIR_TYPE)), regexp.MustCompile(m.Option(DIR_REG)), fields)
|
||||
kit.If(m.Option(DIR_ROOT), func() { m.Option(DIR_ROOT, path.Join(m.Option(DIR_ROOT))+PS) })
|
||||
m.StatusTimeCount(mdb.TIME, last, SIZE, kit.FmtSize(size), m.OptionSimple(DIR_ROOT))
|
||||
}},
|
||||
})
|
||||
}
|
||||
|
||||
func Dir(m *ice.Message, sort string) *ice.Message {
|
||||
m.Copy(m.Cmd(DIR, PWD, kit.Dict(DIR_TYPE, TYPE_DIR)).Sort(sort))
|
||||
m.Copy(m.Cmd(DIR, PWD, kit.Dict(DIR_TYPE, TYPE_CAT)).Sort(sort))
|
||||
func Relative(m *ice.Message, p string) string {
|
||||
if _p := kit.ExtChange(p, JS); Exists(m, _p) {
|
||||
return _p
|
||||
} else if _p := kit.ExtChange(path.Join(ice.USR_VOLCANOS, ice.PLUGIN_LOCAL, path.Join(kit.Slice(kit.Split(p, PS), -2)...)), JS); Exists(m, kit.Split(_p, "?")[0]) {
|
||||
return _p
|
||||
} else {
|
||||
return p
|
||||
}
|
||||
}
|
||||
func SplitPath(m *ice.Message, p string) []string {
|
||||
if kit.HasPrefix(p, REQUIRE_SRC, REQUIRE_USR) {
|
||||
p = strings.TrimPrefix(p, REQUIRE)
|
||||
} else if kit.HasPrefix(p, REQUIRE) {
|
||||
ls := kit.Split(p, PS)
|
||||
return []string{ice.USR_REQUIRE + path.Join(ls[1:4]...) + PS, path.Join(ls[4:]...)}
|
||||
} else if kit.HasPrefix(p, P) {
|
||||
p = strings.TrimPrefix(p, P)
|
||||
}
|
||||
line := kit.Select("1", strings.Split(p, DF), 1)
|
||||
p = strings.Split(p, DF)[0]
|
||||
p = strings.Split(p, "?")[0]
|
||||
if ls := kit.Split(kit.Select(ice.SRC_MAIN_GO, p), PS); len(ls) == 1 {
|
||||
return []string{PWD, ls[0], line}
|
||||
} else if ls[0] == ice.USR {
|
||||
return []string{strings.Join(ls[:2], PS) + PS, strings.Join(ls[2:], PS), line}
|
||||
} else {
|
||||
return []string{strings.Join(ls[:1], PS) + PS, strings.Join(ls[1:], PS), line}
|
||||
}
|
||||
}
|
||||
func Dir(m *ice.Message, field string) *ice.Message {
|
||||
m.Copy(m.Cmd(DIR, PWD, kit.Dict(DIR_TYPE, TYPE_DIR)).Sort(field))
|
||||
m.Copy(m.Cmd(DIR, PWD, kit.Dict(DIR_TYPE, TYPE_CAT)).Sort(field))
|
||||
return m
|
||||
}
|
||||
func DirDeepAll(m *ice.Message, root, dir string, cb func(ice.Maps), arg ...string) *ice.Message {
|
||||
m.Options(DIR_TYPE, CAT, DIR_ROOT, root, DIR_DEEP, ice.TRUE)
|
||||
if msg := m.Cmd(DIR, dir, arg).Tables(cb); cb == nil {
|
||||
defer m.Options(DIR_TYPE, "", DIR_ROOT, "", DIR_DEEP, "")
|
||||
if msg := m.Cmd(DIR, dir, arg); cb == nil {
|
||||
return m.Copy(msg)
|
||||
} else {
|
||||
return msg
|
||||
return msg.Table(cb)
|
||||
}
|
||||
}
|
||||
func Show(m *ice.Message, file string) bool {
|
||||
p := SHARE_LOCAL + file
|
||||
kit.If(m.Option(ice.MSG_USERPOD), func(pod string) { p = kit.MergeURL(p, ice.POD, pod) })
|
||||
switch strings.ToLower(kit.Ext(file)) {
|
||||
case PNG, JPG, JPEG, "gif":
|
||||
m.EchoImages(p)
|
||||
case MP4, MOV:
|
||||
m.EchoVideos(p)
|
||||
default:
|
||||
if IsSourceFile(m, kit.Ext(file)) {
|
||||
m.Cmdy(CAT, file)
|
||||
} else {
|
||||
m.ProcessOpen(p)
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
40
base/nfs/document.go
Normal file
40
base/nfs/document.go
Normal file
@ -0,0 +1,40 @@
|
||||
package nfs
|
||||
|
||||
import (
|
||||
"path"
|
||||
|
||||
ice "shylinux.com/x/icebergs"
|
||||
kit "shylinux.com/x/toolkits"
|
||||
)
|
||||
|
||||
const DOCUMENT = "document"
|
||||
|
||||
func init() {
|
||||
Index.MergeCommands(ice.Commands{
|
||||
DOCUMENT: {Name: "document index path auto", Help: "文档", Hand: func(m *ice.Message, arg ...string) {
|
||||
if len(arg) == 0 {
|
||||
m.Cmdy(ice.COMMAND).Option(ice.MSG_DISPLAY, "")
|
||||
return
|
||||
}
|
||||
m.Search(arg[0], func(p *ice.Context, c *ice.Context, key string, cmd *ice.Command) {
|
||||
if p := DocumentPath(m); p != "" {
|
||||
if len(kit.Slice(arg, 0, 2)) == 1 {
|
||||
m.Cmdy(DIR, p)
|
||||
} else {
|
||||
m.Cmdy(CAT, arg[1])
|
||||
}
|
||||
}
|
||||
})
|
||||
}},
|
||||
})
|
||||
}
|
||||
func Document(m *ice.Message, p string, arg ...ice.Any) string {
|
||||
return kit.Renders(kit.Format(DocumentText(m, p), arg...), m)
|
||||
}
|
||||
|
||||
var DocumentText = func(m *ice.Message, p string) string {
|
||||
return m.Cmdx(CAT, DocumentPath(m, path.Base(p)))
|
||||
}
|
||||
var DocumentPath = func(m *ice.Message, arg ...string) string {
|
||||
return path.Join(USR_LEARNING_PORTAL, m.PrefixKey(), path.Join(arg...))
|
||||
}
|
25
base/nfs/find.go
Normal file
25
base/nfs/find.go
Normal file
@ -0,0 +1,25 @@
|
||||
package nfs
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
ice "shylinux.com/x/icebergs"
|
||||
"shylinux.com/x/icebergs/base/mdb"
|
||||
kit "shylinux.com/x/toolkits"
|
||||
)
|
||||
|
||||
const FIND = "find"
|
||||
|
||||
func init() {
|
||||
const CMD_DIR = "cmd_dir"
|
||||
Index.MergeCommands(ice.Commands{
|
||||
FIND: {Name: "find word file auto", Help: "搜索", Hand: func(m *ice.Message, arg ...string) {
|
||||
kit.If(len(arg) == 0, func() { arg = append(arg, "main.go") })
|
||||
m.Options(mdb.VALUE, arg[0], CMD_DIR, kit.Select("", arg, 2))
|
||||
msg := m.System(FIND, kit.Select(SRC, arg, 1), "-name", arg[0])
|
||||
m.Echo(msg.FormatsMeta(nil))
|
||||
kit.For(strings.Split(msg.Result(), ice.NL), func(s string) { m.Push(FILE, s) })
|
||||
m.StatusTimeCount(kit.Dict(PATH, m.Option(CMD_DIR)))
|
||||
}},
|
||||
})
|
||||
}
|
@ -8,18 +8,26 @@ import (
|
||||
kit "shylinux.com/x/toolkits"
|
||||
)
|
||||
|
||||
const (
|
||||
OPENS = "opens"
|
||||
)
|
||||
|
||||
const GREP = "grep"
|
||||
|
||||
func init() {
|
||||
const CMD_DIR = "cmd_dir"
|
||||
Index.MergeCommands(ice.Commands{
|
||||
GREP: {Name: "grep word path auto", Help: "搜索", Hand: func(m *ice.Message, arg ...string) {
|
||||
m.Option("cmd_dir", kit.Select(m.Option(PATH), arg, 1))
|
||||
for _, line := range strings.Split(m.Cmdx("cli.system", GREP, "--exclude=.[a-z]*", "--exclude-dir=.[a-z]*", "-rni", arg[0], ice.PT), ice.NL) {
|
||||
if ls := strings.SplitN(line, ice.DF, 3); len(ls) > 2 {
|
||||
m.Push(FILE, strings.TrimPrefix(ls[0], PWD)).Push(LINE, ls[1]).Push(mdb.TEXT, ls[2])
|
||||
GREP: {Name: "grep word file auto", Help: "搜索", Hand: func(m *ice.Message, arg ...string) {
|
||||
kit.If(len(arg) == 0, func() { arg = append(arg, ice.MAIN) })
|
||||
kit.If(len(arg) == 1, func() { arg = append(arg, ice.SRC) })
|
||||
m.Options(mdb.VALUE, arg[0])
|
||||
kit.For(kit.SplitLine(m.System(GREP, "--exclude=.[a-z]*", "--exclude-dir=.[a-z]*", "-rni", arg[0], kit.AddUniq([]string{}, arg[1:]...)).Result()), func(s string) {
|
||||
if ls := strings.SplitN(s, DF, 3); len(ls) > 2 {
|
||||
_ls := SplitPath(m, ls[0])
|
||||
m.Push(PATH, _ls[0]).Push(FILE, _ls[1]).Push(LINE, ls[1]).Push(mdb.TEXT, ls[2])
|
||||
}
|
||||
}
|
||||
m.StatusTimeCount(PATH, m.Option("cmd_dir"))
|
||||
})
|
||||
m.Sort("path,file,line")
|
||||
}},
|
||||
})
|
||||
}
|
||||
|
@ -6,7 +6,6 @@ import (
|
||||
"encoding/hex"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
ice "shylinux.com/x/icebergs"
|
||||
"shylinux.com/x/icebergs/base/mdb"
|
||||
@ -17,35 +16,28 @@ const HEX = "hex"
|
||||
|
||||
func init() {
|
||||
Index.MergeCommands(ice.Commands{HEX: {Name: "hex path compress=raw,gzip,zlib size auto", Help: "二进制", Hand: func(m *ice.Message, arg ...string) {
|
||||
if len(arg) == 0 || arg[0] == "" || strings.HasSuffix(arg[0], ice.PS) {
|
||||
m.Cmdy(DIR, kit.Slice(arg, 0, 1))
|
||||
if DirList(m, arg...) {
|
||||
return
|
||||
}
|
||||
if f, e := os.Open(arg[0]); !m.Warn(e, ice.ErrNotFound, arg[0]) {
|
||||
defer f.Close()
|
||||
s, _ := f.Stat()
|
||||
var r io.Reader = f
|
||||
Open(m, arg[0], func(r io.Reader, s os.FileInfo) {
|
||||
switch arg[1] {
|
||||
case "gzip":
|
||||
if g, e := gzip.NewReader(r); !m.Warn(e) {
|
||||
if g, e := gzip.NewReader(r); !m.WarnNotFound(e) {
|
||||
r = g
|
||||
}
|
||||
case "zlib":
|
||||
if z, e := zlib.NewReader(r); !m.Warn(e) {
|
||||
if z, e := zlib.NewReader(r); !m.WarnNotFound(e) {
|
||||
r = z
|
||||
}
|
||||
}
|
||||
buf := make([]byte, kit.Int(kit.Select("1024", arg, 2)))
|
||||
n, _ := r.Read(buf)
|
||||
for i := 0; i < n; i++ {
|
||||
if i%8 == 0 {
|
||||
m.Push("n", kit.Format("%04d", i))
|
||||
}
|
||||
if m.Push(kit.Format(i%8), hex.EncodeToString(buf[i:i+1])); i%8 == 7 {
|
||||
m.Push("text", string(buf[i-7:i+1]))
|
||||
}
|
||||
}
|
||||
m.Status(mdb.TIME, s.ModTime().Format(ice.MOD_TIME), FILE, arg[0], SIZE, kit.FmtSize(s.Size()))
|
||||
}
|
||||
kit.For(n, func(i int) {
|
||||
kit.If(i%8 == 0, func() { m.Push(OFFSET, kit.Format("%04d", i)) })
|
||||
m.Push(kit.Format(i%8), hex.EncodeToString(buf[i:i+1]))
|
||||
kit.If(i%8 == 7, func() { m.Push(mdb.TEXT, string(buf[i-7:i+1])) })
|
||||
})
|
||||
m.StatusTime(mdb.TIME, s.ModTime().Format(ice.MOD_TIME), FILE, arg[0], SIZE, kit.FmtSize(s.Size()))
|
||||
})
|
||||
}}})
|
||||
}
|
||||
|
@ -1,11 +1,15 @@
|
||||
package nfs
|
||||
|
||||
import ice "shylinux.com/x/icebergs"
|
||||
import (
|
||||
ice "shylinux.com/x/icebergs"
|
||||
kit "shylinux.com/x/toolkits"
|
||||
)
|
||||
|
||||
const NFS = "nfs"
|
||||
|
||||
var Index = &ice.Context{Name: NFS, Help: "存储模块"}
|
||||
|
||||
func init() {
|
||||
ice.Index.Register(Index, nil, TAR, CAT, DIR, PACK, DEFS, SAVE, PUSH, COPY, LINK, GREP, TRASH)
|
||||
ice.Index.Register(Index, nil, ZIP, TAR, CAT, DIR, PACK, DEFS, SAVE, PUSH, COPY, LINK, GREP, FIND, MOVE, MOVETO, TRASH)
|
||||
}
|
||||
func Prefix(arg ...string) string { return kit.Keys(NFS, arg) }
|
||||
|
178
base/nfs/pack.go
178
base/nfs/pack.go
@ -2,7 +2,6 @@ package nfs
|
||||
|
||||
import (
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
@ -16,57 +15,51 @@ import (
|
||||
const PACK = "pack"
|
||||
|
||||
func init() {
|
||||
pack := PackFile
|
||||
Index.MergeCommands(ice.Commands{
|
||||
PACK: {Name: "pack path auto upload create", Help: "文件系统", Actions: ice.Actions{
|
||||
mdb.UPLOAD: {Hand: func(m *ice.Message, arg ...string) {
|
||||
if c, e := DiskFile.OpenFile(m.Option(FILE)); m.Assert(e) {
|
||||
defer c.Close()
|
||||
if f, p, e := pack.CreateFile(path.Join(m.Option(PATH), m.Option(mdb.NAME))); m.Assert(e) {
|
||||
defer f.Close()
|
||||
if n, e := io.Copy(f, c); m.Assert(e) {
|
||||
m.Logs(mdb.EXPORT, FILE, p, SIZE, n)
|
||||
}
|
||||
}
|
||||
}
|
||||
}},
|
||||
PACK: {Name: "pack path auto create upload", Help: "文件系统", Actions: ice.Actions{
|
||||
mdb.CREATE: {Name: "create path*=src/hi/hi.txt text*=hello", Hand: func(m *ice.Message, arg ...string) {
|
||||
if f, p, e := pack.CreateFile(m.Option(PATH)); m.Assert(e) {
|
||||
defer f.Close()
|
||||
if n, e := f.Write([]byte(m.Option(mdb.TEXT))); m.Assert(e) {
|
||||
m.Logs(mdb.EXPORT, FILE, p, SIZE, n)
|
||||
}
|
||||
}
|
||||
OptionFiles(m, PackFile)
|
||||
Create(m, m.Option(PATH), func(w io.Writer, p string) {
|
||||
Save(m, w, m.Option(mdb.TEXT), func(n int) { m.Logs(LOAD, FILE, p, SIZE, n) })
|
||||
})
|
||||
}},
|
||||
mdb.REMOVE: {Hand: func(m *ice.Message, arg ...string) { PackFile.Remove(path.Clean(m.Option(PATH))) }},
|
||||
mdb.EXPORT: {Hand: func(m *ice.Message, arg ...string) {
|
||||
OptionFiles(m, PackFile)
|
||||
Open(m, path.Join(m.Option(PATH), m.Option(FILE)), func(r io.Reader, p string) {
|
||||
OptionFiles(m, DiskFile)
|
||||
Create(m, p, func(w io.Writer) { Copy(m, w, r, func(n int) { m.Logs(LOAD, FILE, p, SIZE, n) }) })
|
||||
})
|
||||
}},
|
||||
mdb.IMPORT: {Hand: func(m *ice.Message, arg ...string) {
|
||||
OptionFiles(m, DiskFile)
|
||||
Open(m, path.Join(m.Option(PATH), m.Option(FILE)), func(r io.Reader, p string) {
|
||||
OptionFiles(m, PackFile)
|
||||
Create(m, p, func(w io.Writer) { Copy(m, w, r, func(n int) { m.Logs(LOAD, FILE, p, SIZE, n) }) })
|
||||
})
|
||||
}},
|
||||
mdb.REMOVE: {Hand: func(m *ice.Message, arg ...string) { pack.Remove(path.Clean(m.Option(PATH))) }},
|
||||
}, Hand: func(m *ice.Message, arg ...string) {
|
||||
p := kit.Select("", arg, 0)
|
||||
if p != "" && !strings.HasSuffix(p, PS) {
|
||||
if f, e := pack.OpenFile(p); e == nil {
|
||||
defer f.Close()
|
||||
if b, e := ioutil.ReadAll(f); e == nil {
|
||||
m.Echo(string(b))
|
||||
}
|
||||
}
|
||||
return
|
||||
OptionFiles(m, PackFile)
|
||||
if p := kit.Select("", arg, 0); p != "" && !strings.HasSuffix(p, PS) {
|
||||
Open(m, p, func(r io.Reader) { m.Echo(string(ReadAll(m, r))) })
|
||||
} else {
|
||||
Open(m, path.Join(p)+PS, func(s os.FileInfo) {
|
||||
m.Push(mdb.TIME, s.ModTime().Format(ice.MOD_TIME))
|
||||
m.Push(PATH, path.Join(p, s.Name())+kit.Select("", PS, s.IsDir()))
|
||||
m.Push(SIZE, kit.FmtSize(s.Size()))
|
||||
})
|
||||
m.PushAction(mdb.REMOVE)
|
||||
}
|
||||
ls, _ := pack.ReadDir(p)
|
||||
for _, f := range ls {
|
||||
m.Push(mdb.TIME, f.ModTime().Format(ice.MOD_TIME))
|
||||
m.Push(PATH, path.Join(p, f.Name())+kit.Select("", PS, f.IsDir()))
|
||||
m.Push(SIZE, kit.FmtSize(f.Size()))
|
||||
}
|
||||
m.Sort(PATH).PushAction(mdb.REMOVE).StatusTimeCount()
|
||||
}},
|
||||
})
|
||||
}
|
||||
|
||||
var PackFile = file.NewPackFile()
|
||||
var DiskFile = file.NewDiskFile()
|
||||
var PackFile = file.NewPackFile()
|
||||
|
||||
func init() { file.Init(OptionFiles(ice.Pulse, DiskFile, PackFile)) }
|
||||
|
||||
func OptionFiles(m Message, f ...file.File) file.File {
|
||||
func OptionFiles(m *ice.Message, f ...file.File) file.File {
|
||||
if len(f) > 1 {
|
||||
m.Optionv(ice.MSG_FILES, file.NewMultiFile(f...))
|
||||
} else if len(f) > 0 {
|
||||
@ -74,113 +67,68 @@ func OptionFiles(m Message, f ...file.File) file.File {
|
||||
}
|
||||
return m.Optionv(ice.MSG_FILES).(file.File)
|
||||
}
|
||||
func StatFile(m Message, p string) (os.FileInfo, error) {
|
||||
return OptionFiles(m).StatFile(p)
|
||||
}
|
||||
func OpenFile(m Message, p string) (io.ReadCloser, error) {
|
||||
return OptionFiles(m).OpenFile(p)
|
||||
}
|
||||
func CreateFile(m Message, p string) (io.WriteCloser, string, error) {
|
||||
func StatFile(m *ice.Message, p string) (os.FileInfo, error) { return OptionFiles(m).StatFile(p) }
|
||||
func OpenFile(m *ice.Message, p string) (io.ReadCloser, error) { return OptionFiles(m).OpenFile(p) }
|
||||
func CreateFile(m *ice.Message, p string) (io.WriteCloser, string, error) {
|
||||
return OptionFiles(m).CreateFile(p)
|
||||
}
|
||||
func AppendFile(m Message, p string) (io.ReadWriteCloser, string, error) {
|
||||
file := OptionFiles(m)
|
||||
w, e := file.AppendFile(p)
|
||||
func AppendFile(m *ice.Message, p string) (io.ReadWriteCloser, string, error) {
|
||||
w, e := OptionFiles(m).AppendFile(p)
|
||||
return w, p, e
|
||||
}
|
||||
func WriteFile(m Message, p string, b []byte) error {
|
||||
return OptionFiles(m).WriteFile(p, b)
|
||||
}
|
||||
func WriteFile(m *ice.Message, p string, b []byte) error { return OptionFiles(m).WriteFile(p, b) }
|
||||
|
||||
func ReadDir(m Message, p string) ([]os.FileInfo, error) {
|
||||
func ReadDir(m *ice.Message, p string) ([]os.FileInfo, error) {
|
||||
list, e := OptionFiles(m).ReadDir(p)
|
||||
for i := 0; i < len(list)-1; i++ {
|
||||
for j := i + 1; j < len(list); j++ {
|
||||
if !list[i].IsDir() && list[j].IsDir() || list[i].Name() > list[j].Name() {
|
||||
if list[i].IsDir() && !list[j].IsDir() {
|
||||
continue
|
||||
} else if !list[i].IsDir() && list[j].IsDir() || list[i].Name() > list[j].Name() {
|
||||
list[i], list[j] = list[j], list[i]
|
||||
}
|
||||
}
|
||||
}
|
||||
return list, e
|
||||
}
|
||||
func MkdirAll(m Message, p string) error {
|
||||
return OptionFiles(m).MkdirAll(p, ice.MOD_DIR)
|
||||
func MkdirAll(m *ice.Message, p string) string {
|
||||
OptionFiles(m).MkdirAll(p, ice.MOD_DIR)
|
||||
return p
|
||||
}
|
||||
func RemoveAll(m Message, p string) error {
|
||||
return OptionFiles(m).RemoveAll(p)
|
||||
}
|
||||
func Remove(m Message, p string) error {
|
||||
return OptionFiles(m).Remove(p)
|
||||
}
|
||||
func Rename(m Message, oldname string, newname string) error {
|
||||
func RemoveAll(m *ice.Message, p string) error { return OptionFiles(m).RemoveAll(p) }
|
||||
func Remove(m *ice.Message, p string) error { return OptionFiles(m).Remove(p) }
|
||||
func Rename(m *ice.Message, oldname string, newname string) error {
|
||||
MkdirAll(m, path.Dir(newname))
|
||||
return OptionFiles(m).Rename(oldname, newname)
|
||||
}
|
||||
func Symlink(m Message, oldname string, newname string) error {
|
||||
func Symlink(m *ice.Message, oldname string, newname string) error {
|
||||
return OptionFiles(m).Symlink(oldname, newname)
|
||||
}
|
||||
func Link(m Message, oldname string, newname string) error {
|
||||
func Link(m *ice.Message, oldname string, newname string) error {
|
||||
return OptionFiles(m).Link(oldname, newname)
|
||||
}
|
||||
|
||||
type Message interface {
|
||||
Optionv(key string, arg ...ice.Any) ice.Any
|
||||
}
|
||||
|
||||
func ExistsFile(m Message, p string) bool {
|
||||
func Exists(m *ice.Message, p string, cb ...func(string)) bool {
|
||||
if _, e := OptionFiles(m).StatFile(p); e == nil {
|
||||
for _, cb := range cb {
|
||||
cb(p)
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
func ReadFile(m Message, p string) ([]byte, error) {
|
||||
if f, e := OptionFiles(m).OpenFile(p); e == nil {
|
||||
defer f.Close()
|
||||
return ioutil.ReadAll(f)
|
||||
} else {
|
||||
return nil, e
|
||||
func ExistsFile(m *ice.Message, p string) bool {
|
||||
if s, e := OptionFiles(m).StatFile(p); e == nil && !s.IsDir() {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
func CloseFile(m Message, p ice.Any) {
|
||||
func NewReadCloser(r io.Reader) io.ReadCloser { return file.NewReadCloser(r) }
|
||||
func NewWriteCloser(w func([]byte) (int, error), c func() error) io.WriteCloser {
|
||||
return file.NewWriteCloser(w, c)
|
||||
}
|
||||
func Close(m *ice.Message, p ice.Any) {
|
||||
if w, ok := p.(io.Closer); ok {
|
||||
w.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func CopyFile(m *ice.Message, to io.WriteCloser, from io.ReadCloser, bufs, total int, cb ice.Any) {
|
||||
size, buf := 0, make([]byte, bufs)
|
||||
for {
|
||||
n, e := from.Read(buf)
|
||||
to.Write(buf[0:n])
|
||||
if size += n; size > total {
|
||||
total = size
|
||||
}
|
||||
switch step := size * 100 / total; cb := cb.(type) {
|
||||
case func(int, int, int):
|
||||
cb(size, total, step)
|
||||
case func(int, int):
|
||||
cb(size, total)
|
||||
case nil:
|
||||
default:
|
||||
m.ErrorNotImplement(cb)
|
||||
}
|
||||
if e == io.EOF || m.Warn(e) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func NewWriteCloser(w func([]byte) (int, error), c func() error) io.WriteCloser {
|
||||
return file.NewWriteCloser(w, c)
|
||||
}
|
||||
func NewReadCloser(r io.Reader) io.ReadCloser {
|
||||
return file.NewReadCloser(r)
|
||||
}
|
||||
func NewCloser(c func() error) io.WriteCloser {
|
||||
return file.NewWriteCloser(func(buf []byte) (int, error) { return 0, nil }, c)
|
||||
}
|
||||
|
||||
func CatFile(m *ice.Message, p string) string {
|
||||
b, _ := ioutil.ReadFile(p)
|
||||
return strings.TrimSpace(string(b))
|
||||
}
|
||||
|
210
base/nfs/save.go
210
base/nfs/save.go
@ -3,6 +3,7 @@ package nfs
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path"
|
||||
|
||||
ice "shylinux.com/x/icebergs"
|
||||
@ -11,106 +12,217 @@ import (
|
||||
)
|
||||
|
||||
func _defs_file(m *ice.Message, name string, text ...string) {
|
||||
if ExistsFile(m, path.Join(m.Option(DIR_ROOT), name)) {
|
||||
if s, e := os.Stat(path.Join(m.Option(DIR_ROOT), name)); e == nil && s.Size() > 0 {
|
||||
return
|
||||
}
|
||||
for i, v := range text {
|
||||
b, _ := kit.Render(v, m)
|
||||
text[i] = string(b)
|
||||
if b, e := kit.Render(v, m); !m.WarnNotValid(e) {
|
||||
text[i] = string(b)
|
||||
}
|
||||
}
|
||||
_save_file(m, name, text...)
|
||||
}
|
||||
func _save_file(m *ice.Message, name string, text ...string) {
|
||||
if f, p, e := CreateFile(m, path.Join(m.Option(DIR_ROOT), name)); m.Assert(e) {
|
||||
defer f.Close()
|
||||
Create(m, path.Join(m.Option(DIR_ROOT), name), func(w io.Writer, p string) {
|
||||
defer m.Echo(p)
|
||||
for _, v := range text {
|
||||
if n, e := fmt.Fprint(f, v); m.Assert(e) {
|
||||
m.Logs(mdb.EXPORT, FILE, p, SIZE, n)
|
||||
}
|
||||
}
|
||||
}
|
||||
kit.For(text, func(s string) { Save(m, w, s, func(n int) { m.Logs(SAVE, FILE, p, SIZE, n) }) })
|
||||
})
|
||||
}
|
||||
func _push_file(m *ice.Message, name string, text ...string) {
|
||||
if f, p, e := AppendFile(m, path.Join(m.Option(DIR_ROOT), name)); m.Assert(e) {
|
||||
defer f.Close()
|
||||
Append(m, path.Join(m.Option(DIR_ROOT), name), func(w io.Writer, p string) {
|
||||
defer m.Echo(p)
|
||||
for _, k := range text {
|
||||
if n, e := fmt.Fprint(f, k); m.Assert(e) {
|
||||
m.Logs(mdb.EXPORT, FILE, p, SIZE, n)
|
||||
}
|
||||
}
|
||||
}
|
||||
kit.For(text, func(s string) { Save(m, w, s, func(n int) { m.Logs(SAVE, FILE, p, SIZE, n) }) })
|
||||
})
|
||||
}
|
||||
func _copy_file(m *ice.Message, name string, from ...string) {
|
||||
if f, p, e := CreateFile(m, path.Join(m.Option(DIR_ROOT), name)); m.Assert(e) {
|
||||
defer f.Close()
|
||||
Create(m, path.Join(m.Option(DIR_ROOT), name), func(w io.Writer, p string) {
|
||||
defer m.Echo(p)
|
||||
for _, v := range from {
|
||||
if s, e := OpenFile(m, path.Join(m.Option(DIR_ROOT), v)); !m.Warn(e, ice.ErrNotFound, v) {
|
||||
defer s.Close()
|
||||
if n, e := io.Copy(f, s); !m.Warn(e, ice.ErrNotValid, v) {
|
||||
m.Logs(mdb.IMPORT, FILE, v, SIZE, n)
|
||||
m.Logs(mdb.EXPORT, FILE, p, SIZE, n)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
kit.For(from, func(f string) {
|
||||
Open(m, path.Join(m.Option(DIR_ROOT), f), func(r io.Reader) {
|
||||
Copy(m, w, r, func(n int) { m.Logs(LOAD, FILE, f, SIZE, n).Logs(SAVE, FILE, p, SIZE, n) })
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
func _link_file(m *ice.Message, name string, from string) {
|
||||
if m.Warn(from == "", ice.ErrNotValid, FROM) {
|
||||
if m.WarnNotValid(from == "", FROM) {
|
||||
return
|
||||
}
|
||||
name = path.Join(m.Option(DIR_ROOT), name)
|
||||
from = path.Join(m.Option(DIR_ROOT), from)
|
||||
if m.Warn(!ExistsFile(m, from), ice.ErrNotFound, from) {
|
||||
if m.WarnNotFound(!Exists(m, from), from) {
|
||||
return
|
||||
}
|
||||
Remove(m, name)
|
||||
if MkdirAll(m, path.Dir(name)); m.Warn(Link(m, from, name)) && m.Warn(Symlink(m, from, name), ice.ErrWarn, from) {
|
||||
if MkdirAll(m, path.Dir(name)); m.WarnNotValid(Link(m, from, name)) && m.WarnNotValid(Symlink(m, from, name), from) {
|
||||
return
|
||||
}
|
||||
m.Logs(mdb.CREATE, FILE, name, FROM, from)
|
||||
m.Echo(name)
|
||||
m.Logs(SAVE, FILE, name, FROM, from).Echo(name)
|
||||
}
|
||||
|
||||
const (
|
||||
CONTENT = "content"
|
||||
OFFSET = "offset"
|
||||
ALIAS = "alias"
|
||||
FROM = "from"
|
||||
TO = "to"
|
||||
)
|
||||
const LOAD = "load"
|
||||
const DEFS = "defs"
|
||||
const SAVE = "save"
|
||||
const PUSH = "push"
|
||||
const COPY = "copy"
|
||||
const LINK = "link"
|
||||
const LOAD = "load"
|
||||
const MOVE = "move"
|
||||
const MOVETO = "moveto"
|
||||
|
||||
func init() {
|
||||
Index.MergeCommands(ice.Commands{
|
||||
DEFS: {Name: "defs file text run", Help: "默认", Hand: func(m *ice.Message, arg ...string) {
|
||||
OptionFiles(m, DiskFile)
|
||||
_defs_file(m, arg[0], arg[1:]...)
|
||||
}},
|
||||
SAVE: {Name: "save file text run", Help: "保存", Hand: func(m *ice.Message, arg ...string) {
|
||||
if len(arg) == 1 {
|
||||
arg = append(arg, m.Option(CONTENT))
|
||||
}
|
||||
kit.If(len(arg) == 1, func() { arg = append(arg, m.Option(CONTENT)) })
|
||||
_save_file(m, arg[0], arg[1:]...)
|
||||
}},
|
||||
PUSH: {Name: "push file text run", Help: "追加", Hand: func(m *ice.Message, arg ...string) {
|
||||
if len(arg) == 1 {
|
||||
arg = append(arg, m.Option(CONTENT))
|
||||
}
|
||||
kit.If(len(arg) == 1, func() { arg = append(arg, m.Option(CONTENT)) })
|
||||
_push_file(m, arg[0], arg[1:]...)
|
||||
}},
|
||||
COPY: {Name: "copy file from run", Help: "复制", Hand: func(m *ice.Message, arg ...string) {
|
||||
for _, file := range arg[1:] {
|
||||
if ExistsFile(m, file) {
|
||||
_copy_file(m, arg[0], arg[1:]...)
|
||||
return
|
||||
}
|
||||
}
|
||||
kit.If(len(arg) > 1 && Exists(m, arg[1]), func() { _copy_file(m, arg[0], arg[1:]...) })
|
||||
}},
|
||||
LINK: {Name: "link file from run", Help: "链接", Hand: func(m *ice.Message, arg ...string) {
|
||||
_link_file(m, arg[0], arg[1])
|
||||
}},
|
||||
MOVE: {Name: "move file from run", Help: "移动", Hand: func(m *ice.Message, arg ...string) {
|
||||
arg[1] = path.Join(m.Option(DIR_ROOT), arg[1])
|
||||
arg[0] = path.Join(m.Option(DIR_ROOT), arg[0])
|
||||
Rename(m, arg[1], arg[0])
|
||||
}},
|
||||
MOVETO: {Name: "moveto path from run", Help: "移动到", Hand: func(m *ice.Message, arg ...string) {
|
||||
kit.For(arg[1:], func(from string) { m.Cmd(MOVE, path.Join(arg[0], path.Base(from)), from) })
|
||||
}},
|
||||
})
|
||||
}
|
||||
func Create(m *ice.Message, p string, cb ice.Any) string {
|
||||
if f, p, e := CreateFile(m, p); !m.WarnNotValid(e) {
|
||||
defer f.Close()
|
||||
switch cb := cb.(type) {
|
||||
case func(io.Writer, string):
|
||||
cb(f, p)
|
||||
case func(io.Writer):
|
||||
cb(f)
|
||||
default:
|
||||
m.ErrorNotImplement(cb)
|
||||
}
|
||||
}
|
||||
return p
|
||||
}
|
||||
func Append(m *ice.Message, p string, cb ice.Any) {
|
||||
if f, p, e := AppendFile(m, p); !m.WarnNotValid(e) {
|
||||
defer f.Close()
|
||||
switch cb := cb.(type) {
|
||||
case func(io.Writer, string):
|
||||
cb(f, p)
|
||||
case func(io.Writer):
|
||||
cb(f)
|
||||
default:
|
||||
m.ErrorNotImplement(cb)
|
||||
}
|
||||
}
|
||||
}
|
||||
func Save(m *ice.Message, w io.Writer, s string, cb ice.Any) {
|
||||
switch content := m.Optionv(CONTENT).(type) {
|
||||
case io.Reader:
|
||||
io.Copy(w, content)
|
||||
return
|
||||
}
|
||||
if n, e := fmt.Fprint(w, s); !m.WarnNotValid(e) {
|
||||
switch cb := cb.(type) {
|
||||
case func(int):
|
||||
cb(n)
|
||||
default:
|
||||
m.ErrorNotImplement(cb)
|
||||
}
|
||||
}
|
||||
}
|
||||
func Copy(m *ice.Message, w io.Writer, r io.Reader, cb ice.Any) {
|
||||
if n, e := io.Copy(w, r); !m.WarnNotValid(e) {
|
||||
switch cb := cb.(type) {
|
||||
case func(int):
|
||||
cb(int(n))
|
||||
default:
|
||||
m.ErrorNotImplement(cb)
|
||||
}
|
||||
}
|
||||
}
|
||||
func CopyStream(m *ice.Message, to io.Writer, from io.Reader, cache, total int, cb ice.Any) {
|
||||
kit.If(total == 0, func() { total = 1 })
|
||||
count, buf := 0, make([]byte, cache)
|
||||
for {
|
||||
n, e := from.Read(buf)
|
||||
to.Write(buf[0:n])
|
||||
if count += n; count > total {
|
||||
total = count
|
||||
}
|
||||
switch value := count * 100 / total; cb := cb.(type) {
|
||||
case func(int, int, int):
|
||||
cb(count, total, value)
|
||||
case func(int, int):
|
||||
cb(count, total)
|
||||
case nil:
|
||||
default:
|
||||
m.ErrorNotImplement(cb)
|
||||
}
|
||||
if e == io.EOF || m.WarnNotValid(e) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
func CopyFile(m *ice.Message, to, from string, cb func([]byte, int) []byte) {
|
||||
Open(m, from, func(r io.Reader) {
|
||||
Create(m, to, func(w io.Writer) {
|
||||
offset, buf := 0, make([]byte, 1024*1024)
|
||||
for {
|
||||
n, _ := r.Read(buf)
|
||||
if n, _ = w.Write(cb(buf[:n], offset)); n == 0 {
|
||||
break
|
||||
}
|
||||
offset += n
|
||||
}
|
||||
m.Logs(SAVE, FILE, to, FROM, from, SIZE, offset)
|
||||
})
|
||||
})
|
||||
}
|
||||
func Pipe(m *ice.Message, cb ice.Any) io.WriteCloser {
|
||||
r, w := io.Pipe()
|
||||
switch cb := cb.(type) {
|
||||
case func(string):
|
||||
m.Go(func() { kit.For(r, cb) })
|
||||
case func([]byte):
|
||||
m.Go(func() {
|
||||
buf := make([]byte, ice.MOD_BUFS)
|
||||
for {
|
||||
n, e := r.Read(buf)
|
||||
if cb(buf[:n]); e != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
})
|
||||
default:
|
||||
}
|
||||
return w
|
||||
}
|
||||
|
||||
func TempName(m *ice.Message) string {
|
||||
return m.Cmdx(SAVE, path.Join(ice.VAR_TMP, kit.Hashs(mdb.UNIQ)), "")
|
||||
}
|
||||
func Temp(m *ice.Message, cb func(p string)) {
|
||||
p := TempName(m)
|
||||
defer os.Remove(p)
|
||||
cb(p)
|
||||
}
|
||||
|
||||
var ImageResize = func(m *ice.Message, p string, height, width uint) bool { return false }
|
||||
|
122
base/nfs/tar.go
122
base/nfs/tar.go
@ -4,7 +4,6 @@ import (
|
||||
"archive/tar"
|
||||
"compress/gzip"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
@ -14,49 +13,46 @@ import (
|
||||
kit "shylinux.com/x/toolkits"
|
||||
)
|
||||
|
||||
func _tar_list(m *ice.Message, p string, cb func(*tar.Header, *tar.Reader, int)) *ice.Message {
|
||||
const (
|
||||
GZ = "gz"
|
||||
)
|
||||
var r io.Reader
|
||||
if f, e := os.Open(p); m.Warn(e, ice.ErrNotValid, p) {
|
||||
return m
|
||||
} else {
|
||||
defer f.Close()
|
||||
r = f
|
||||
}
|
||||
for {
|
||||
switch kit.Ext(p) {
|
||||
case GZ:
|
||||
if f, e := gzip.NewReader(r); m.Warn(e, ice.ErrNotValid, p) {
|
||||
return m
|
||||
} else {
|
||||
defer f.Close()
|
||||
r = f
|
||||
}
|
||||
p = kit.TrimExt(p, GZ)
|
||||
case TAR:
|
||||
i := 0
|
||||
for r := tar.NewReader(r); ; i++ {
|
||||
h, e := r.Next()
|
||||
if m.Warn(e) {
|
||||
break
|
||||
func _tar_list(m *ice.Message, p string, cb func(*tar.Header, io.Reader, int)) {
|
||||
Open(m, p, func(r io.Reader) {
|
||||
for {
|
||||
switch kit.Ext(p) {
|
||||
case TGZ:
|
||||
p = kit.Keys(kit.TrimExt(p, kit.Ext(p)), TAR, GZ)
|
||||
case GZ:
|
||||
if f, e := gzip.NewReader(r); m.WarnNotValid(e, p) {
|
||||
return
|
||||
} else {
|
||||
defer f.Close()
|
||||
r, p = f, kit.TrimExt(p, GZ)
|
||||
}
|
||||
if h.Size == 0 {
|
||||
i--
|
||||
continue
|
||||
case TAR:
|
||||
i := 0
|
||||
for r := tar.NewReader(r); ; i++ {
|
||||
h, e := r.Next()
|
||||
if m.WarnNotValid(e) || e == io.EOF {
|
||||
break
|
||||
}
|
||||
if h.Size == 0 {
|
||||
i--
|
||||
continue
|
||||
}
|
||||
cb(h, r, i)
|
||||
}
|
||||
cb(h, r, i)
|
||||
m.StatusTimeCount(mdb.TOTAL, i)
|
||||
return
|
||||
default:
|
||||
return
|
||||
}
|
||||
m.StatusTimeCount(mdb.TOTAL, i)
|
||||
return m
|
||||
default:
|
||||
return m
|
||||
}
|
||||
}
|
||||
return m
|
||||
})
|
||||
}
|
||||
|
||||
const (
|
||||
XZ = "xz"
|
||||
GZ = "gz"
|
||||
TGZ = "tgz"
|
||||
)
|
||||
const TAR = "tar"
|
||||
|
||||
func init() {
|
||||
@ -65,40 +61,38 @@ func init() {
|
||||
mdb.NEXT: {Hand: func(m *ice.Message, arg ...string) { mdb.PrevPage(m, arg[0], kit.Slice(arg, 1)...) }},
|
||||
mdb.PREV: {Hand: func(m *ice.Message, arg ...string) { mdb.NextPageLimit(m, arg[0], kit.Slice(arg, 1)...) }},
|
||||
mdb.EXPORT: {Hand: func(m *ice.Message, arg ...string) {
|
||||
list, size := map[string]bool{}, int64(0)
|
||||
_tar_list(m, m.Option(PATH), func(h *tar.Header, r *tar.Reader, i int) {
|
||||
if kit.Ext(m.Option(PATH)) == ZIP {
|
||||
m.Cmdy(ZIP, mdb.EXPORT, arg)
|
||||
return
|
||||
}
|
||||
list, size := kit.Dict(), 0
|
||||
_tar_list(m, m.Option(PATH), func(h *tar.Header, r io.Reader, i int) {
|
||||
if h.Name == m.Option(FILE) || m.Option(FILE) == "" {
|
||||
p := path.Join(path.Dir(m.Option(PATH)), h.Name)
|
||||
if strings.HasSuffix(h.Name, ice.PS) {
|
||||
if strings.HasSuffix(h.Name, PS) {
|
||||
MkdirAll(m, p)
|
||||
return
|
||||
}
|
||||
if !list[path.Dir(p)] {
|
||||
list[path.Dir(p)] = true
|
||||
MkdirAll(m, path.Dir(p))
|
||||
}
|
||||
if f, p, e := CreateFile(m, p); !m.Warn(e) {
|
||||
defer f.Close()
|
||||
if m.Option(FILE) != "" {
|
||||
defer m.Cmdy(DIR, p, "time,path,size")
|
||||
defer m.Cmdy(CAT, p)
|
||||
}
|
||||
if n, e := io.Copy(f, r); !m.Warn(e) {
|
||||
size += n
|
||||
m.Logs(mdb.EXPORT, LINE, i, SIZE, kit.FmtSize(size), FILE, p, SIZE, kit.FmtSize(n))
|
||||
os.Chmod(p, os.FileMode(h.Mode))
|
||||
}
|
||||
}
|
||||
kit.IfNoKey(list, path.Dir(p), func(p string) { MkdirAll(m, p) })
|
||||
Create(m, p, func(w io.Writer) {
|
||||
os.Chmod(p, os.FileMode(h.Mode))
|
||||
Copy(m, w, r, func(n int) { size += n })
|
||||
kit.If(m.Option(FILE), func() { m.Cmdy(DIR, p).Cmdy(CAT, p) })
|
||||
})
|
||||
}
|
||||
})
|
||||
}},
|
||||
}, mdb.PageListAction()), Hand: func(m *ice.Message, arg ...string) {
|
||||
if len(arg) == 0 || strings.HasSuffix(arg[0], ice.PS) {
|
||||
if len(arg) == 0 || strings.HasSuffix(arg[0], PS) {
|
||||
m.Cmdy(DIR, arg)
|
||||
return
|
||||
}
|
||||
if kit.Ext(arg[0]) == ZIP {
|
||||
m.Cmdy(ZIP, arg)
|
||||
return
|
||||
}
|
||||
page, size := mdb.OptionPages(m, kit.Slice(arg, 2)...)
|
||||
_tar_list(m, arg[0], func(h *tar.Header, r *tar.Reader, i int) {
|
||||
_tar_list(m, arg[0], func(h *tar.Header, r io.Reader, i int) {
|
||||
if len(kit.Slice(arg, 0, 2)) > 1 {
|
||||
if h.Name != arg[1] {
|
||||
return
|
||||
@ -108,17 +102,11 @@ func init() {
|
||||
if i >= (page-1)*size && i < page*size {
|
||||
m.Push(mdb.TIME, h.ModTime.Format(ice.MOD_TIME)).Push(FILE, h.Name).Push(SIZE, kit.FmtSize(h.Size))
|
||||
}
|
||||
}).PushAction(mdb.EXPORT)
|
||||
})
|
||||
m.PushAction(mdb.EXPORT)
|
||||
}},
|
||||
})
|
||||
}
|
||||
func ReadAll(m *ice.Message, r io.Reader) []byte {
|
||||
if buf, e := ioutil.ReadAll(r); m.Warn(e) {
|
||||
return buf
|
||||
} else {
|
||||
return buf
|
||||
}
|
||||
}
|
||||
func TarExport(m *ice.Message, path string, file ...string) {
|
||||
m.Cmd(TAR, mdb.EXPORT, ice.Maps{PATH: path, FILE: kit.Select("", file, 0)})
|
||||
}
|
||||
|
55
base/nfs/template.go
Normal file
55
base/nfs/template.go
Normal file
@ -0,0 +1,55 @@
|
||||
package nfs
|
||||
|
||||
import (
|
||||
"path"
|
||||
|
||||
ice "shylinux.com/x/icebergs"
|
||||
kit "shylinux.com/x/toolkits"
|
||||
)
|
||||
|
||||
const TEMPLATE = "template"
|
||||
|
||||
func init() {
|
||||
Index.MergeCommands(ice.Commands{
|
||||
TEMPLATE: {Name: "template index path auto", Help: "模板", Actions: ice.MergeActions(ice.Actions{
|
||||
ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) {
|
||||
ice.AddRender(ice.RENDER_TEMPLATE, func(m *ice.Message, args ...ice.Any) string {
|
||||
return Template(m, kit.Format(args[0]), args[1:]...)
|
||||
})
|
||||
}},
|
||||
}), Hand: func(m *ice.Message, arg ...string) {
|
||||
if len(arg) == 0 {
|
||||
m.Cmdy(ice.COMMAND).Option(ice.MSG_DISPLAY, "")
|
||||
return
|
||||
}
|
||||
m.Search(arg[0], func(p *ice.Context, c *ice.Context, key string, cmd *ice.Command) {
|
||||
if p := TemplatePath(m); p != "" {
|
||||
if len(kit.Slice(arg, 0, 2)) == 1 {
|
||||
m.Cmdy(DIR, p)
|
||||
} else {
|
||||
m.Cmdy(CAT, arg[1])
|
||||
}
|
||||
}
|
||||
})
|
||||
}},
|
||||
})
|
||||
}
|
||||
|
||||
func init() { ice.Info.Template = Template }
|
||||
|
||||
func Template(m *ice.Message, p string, data ...ice.Any) string {
|
||||
if text := TemplateText(m, p); text == "" {
|
||||
return ""
|
||||
} else if len(data) == 0 {
|
||||
return kit.Renders(text, m)
|
||||
} else {
|
||||
return kit.Renders(text, data[0])
|
||||
}
|
||||
}
|
||||
|
||||
var TemplateText = func(m *ice.Message, p string) string {
|
||||
return m.Cmdx(CAT, kit.Select(TemplatePath(m, path.Base(p)), m.Option("_template")))
|
||||
}
|
||||
var TemplatePath = func(m *ice.Message, arg ...string) string {
|
||||
return path.Join(ice.SRC_TEMPLATE, m.PrefixKey(), path.Join(arg...))
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
package nfs
|
||||
|
||||
import (
|
||||
"io"
|
||||
"path"
|
||||
|
||||
ice "shylinux.com/x/icebergs"
|
||||
@ -9,51 +10,42 @@ import (
|
||||
)
|
||||
|
||||
func _trash_create(m *ice.Message, from string) {
|
||||
if m.Warn(from == "", ice.ErrNotValid, FROM) {
|
||||
if m.WarnNotValid(from == "", FROM) {
|
||||
return
|
||||
}
|
||||
s, e := StatFile(m, from)
|
||||
if m.Warn(e, ice.ErrNotFound, from) {
|
||||
if m.WarnNotFound(e, from) {
|
||||
return
|
||||
}
|
||||
defer Remove(m, from)
|
||||
p := path.Join(ice.VAR_TRASH, path.Base(from))
|
||||
if !s.IsDir() {
|
||||
if f, e := OpenFile(m, from); m.Assert(e) {
|
||||
defer f.Close()
|
||||
p = path.Join(ice.VAR_TRASH, kit.HashsPath(f))
|
||||
}
|
||||
}
|
||||
if RemoveAll(m, p); !m.Warn(Rename(m, from, p)) {
|
||||
mdb.HashCreate(m, FROM, from, FILE, p)
|
||||
}
|
||||
kit.If(!s.IsDir(), func() { Open(m, from, func(r io.Reader) { p = path.Join(ice.VAR_TRASH, kit.HashsPath(r)) }) })
|
||||
RemoveAll(m, p)
|
||||
kit.If(!m.WarnNotValid(Rename(m, from, p)), func() { mdb.HashCreate(m, FROM, kit.Paths(from), FILE, p) })
|
||||
}
|
||||
|
||||
const (
|
||||
FROM = "from"
|
||||
)
|
||||
const TRASH = "trash"
|
||||
|
||||
func init() {
|
||||
Index.MergeCommands(ice.Commands{
|
||||
TRASH: {Name: "trash hash auto prunes", Help: "回收站", Actions: ice.MergeActions(ice.Actions{
|
||||
mdb.REVERT: {Hand: func(m *ice.Message, arg ...string) {
|
||||
Rename(m, m.Option(FILE), m.Option(FROM))
|
||||
mdb.HashRemove(m, m.OptionSimple(mdb.HASH))
|
||||
}},
|
||||
TRASH: {Name: "trash hash auto", Help: "回收站", Actions: ice.MergeActions(ice.Actions{
|
||||
mdb.CREATE: {Hand: func(m *ice.Message, arg ...string) {
|
||||
_trash_create(m, m.Option(FROM))
|
||||
_trash_create(m, kit.Paths(m.Option(FROM)))
|
||||
}},
|
||||
mdb.REMOVE: {Hand: func(m *ice.Message, arg ...string) {
|
||||
Remove(m, m.Option(FILE))
|
||||
mdb.HashRemove(m, m.OptionSimple(mdb.HASH))
|
||||
}},
|
||||
mdb.REVERT: {Help: "恢复", Icon: "bi bi-folder-symlink", Hand: func(m *ice.Message, arg ...string) {
|
||||
msg := mdb.HashSelect(m.Spawn(), m.Option(mdb.HASH))
|
||||
Rename(m, msg.Append(FILE), msg.Append(FROM))
|
||||
mdb.HashRemove(m, m.OptionSimple(mdb.HASH))
|
||||
}},
|
||||
mdb.PRUNES: {Hand: func(m *ice.Message, arg ...string) {
|
||||
mdb.HashPrunes(m, nil).Tables(func(value ice.Maps) { Remove(m, value[FILE]) })
|
||||
mdb.HashPrunes(m, nil).Table(func(value ice.Maps) { Remove(m, value[FILE]) })
|
||||
}},
|
||||
}, mdb.HashAction(mdb.SHORT, FROM, mdb.FIELD, "time,hash,from,file", mdb.ACTION, mdb.REVERT))},
|
||||
})
|
||||
}
|
||||
|
||||
func Trash(m *ice.Message, p string) *ice.Message {
|
||||
return m.Cmd(TRASH, mdb.CREATE, p)
|
||||
}
|
||||
func Trash(m *ice.Message, p string, arg ...string) *ice.Message { return m.Cmd(TRASH, mdb.CREATE, p) }
|
||||
|
72
base/nfs/zip.go
Normal file
72
base/nfs/zip.go
Normal file
@ -0,0 +1,72 @@
|
||||
package nfs
|
||||
|
||||
import (
|
||||
"archive/zip"
|
||||
"io"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
ice "shylinux.com/x/icebergs"
|
||||
"shylinux.com/x/icebergs/base/mdb"
|
||||
kit "shylinux.com/x/toolkits"
|
||||
)
|
||||
|
||||
func _zip_list(m *ice.Message, p string, cb func(zip.FileHeader, io.Reader, int)) {
|
||||
if f, e := zip.OpenReader(p); m.WarnNotFound(e, p) {
|
||||
return
|
||||
} else {
|
||||
defer f.Close()
|
||||
for i, f := range f.File {
|
||||
if r, e := f.Open(); e == nil {
|
||||
defer r.Close()
|
||||
cb(f.FileHeader, r, i)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const ZIP = "zip"
|
||||
|
||||
func init() {
|
||||
Index.MergeCommands(ice.Commands{
|
||||
ZIP: {Name: "zip path file auto page", Help: "打包", Actions: ice.MergeActions(ice.Actions{
|
||||
mdb.NEXT: {Hand: func(m *ice.Message, arg ...string) { mdb.PrevPage(m, arg[0], kit.Slice(arg, 1)...) }},
|
||||
mdb.PREV: {Hand: func(m *ice.Message, arg ...string) { mdb.NextPageLimit(m, arg[0], kit.Slice(arg, 1)...) }},
|
||||
mdb.EXPORT: {Hand: func(m *ice.Message, arg ...string) {
|
||||
list, size := kit.Dict(), 0
|
||||
_zip_list(m, m.Option(PATH), func(h zip.FileHeader, r io.Reader, i int) {
|
||||
p := path.Join(path.Dir(m.Option(PATH)), kit.Split(path.Base(m.Option(PATH)), "_-.")[0], h.Name)
|
||||
if strings.HasSuffix(h.Name, PS) {
|
||||
MkdirAll(m, p)
|
||||
return
|
||||
}
|
||||
kit.IfNoKey(list, path.Dir(p), func(p string) { MkdirAll(m, p) })
|
||||
Create(m, p, func(w io.Writer) {
|
||||
os.Chmod(p, os.FileMode(h.Mode()))
|
||||
Copy(m, w, r, func(n int) { size += n })
|
||||
kit.If(m.Option(FILE), func() { m.Cmdy(DIR, p).Cmdy(CAT, p) })
|
||||
})
|
||||
})
|
||||
}},
|
||||
}, mdb.PageListAction()), Hand: func(m *ice.Message, arg ...string) {
|
||||
if len(arg) == 0 || strings.HasSuffix(arg[0], PS) {
|
||||
m.Cmdy(DIR, arg)
|
||||
return
|
||||
}
|
||||
page, size := mdb.OptionPages(m, kit.Slice(arg, 2)...)
|
||||
_zip_list(m, arg[0], func(h zip.FileHeader, r io.Reader, i int) {
|
||||
if len(kit.Slice(arg, 0, 2)) > 1 {
|
||||
if h.Name != arg[1] {
|
||||
return
|
||||
}
|
||||
m.Echo(string(ReadAll(m, r)[:]))
|
||||
}
|
||||
if i >= (page-1)*size && i < page*size {
|
||||
m.Push(mdb.TIME, h.ModTime().Format(ice.MOD_TIME)).Push(FILE, h.Name).Push(SIZE, kit.FmtSize(int64(h.UncompressedSize)))
|
||||
}
|
||||
})
|
||||
m.PushAction(mdb.EXPORT)
|
||||
}},
|
||||
})
|
||||
}
|
@ -5,25 +5,28 @@ import (
|
||||
"strings"
|
||||
|
||||
ice "shylinux.com/x/icebergs"
|
||||
"shylinux.com/x/icebergs/base/lex"
|
||||
kit "shylinux.com/x/toolkits"
|
||||
)
|
||||
|
||||
func Render(msg *ice.Message, cmd string, arg ...ice.Any) (res string) {
|
||||
func Render(m *ice.Message, cmd string, arg ...ice.Any) (res string) {
|
||||
switch args := kit.Simple(arg...); cmd {
|
||||
case ice.RENDER_RESULT:
|
||||
if len(args) > 0 {
|
||||
msg.Resultv(args)
|
||||
}
|
||||
res = msg.Result()
|
||||
kit.If(len(args) > 0, func() { m.Resultv(args) })
|
||||
res = m.Result()
|
||||
case ice.RENDER_VOID:
|
||||
return res
|
||||
default:
|
||||
if res = msg.Result(); res == "" {
|
||||
res = msg.Table().Result()
|
||||
if res = m.Result(); res == "" {
|
||||
if m.IsCliUA() {
|
||||
res = m.TableEchoWithStatus().Result()
|
||||
} else {
|
||||
res = m.TableEcho().Result()
|
||||
}
|
||||
}
|
||||
}
|
||||
if fmt.Fprint(msg.O, res); !strings.HasSuffix(res, ice.NL) {
|
||||
fmt.Fprint(msg.O, ice.NL)
|
||||
if fmt.Fprint(m.O, res); !strings.HasSuffix(res, lex.NL) {
|
||||
fmt.Fprint(m.O, lex.NL)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
@ -13,8 +13,11 @@ import (
|
||||
ice "shylinux.com/x/icebergs"
|
||||
"shylinux.com/x/icebergs/base/cli"
|
||||
"shylinux.com/x/icebergs/base/ctx"
|
||||
"shylinux.com/x/icebergs/base/lex"
|
||||
"shylinux.com/x/icebergs/base/log"
|
||||
"shylinux.com/x/icebergs/base/mdb"
|
||||
"shylinux.com/x/icebergs/base/nfs"
|
||||
"shylinux.com/x/icebergs/base/tcp"
|
||||
kit "shylinux.com/x/toolkits"
|
||||
)
|
||||
|
||||
@ -31,40 +34,32 @@ type Frame struct {
|
||||
count int
|
||||
}
|
||||
|
||||
func (f *Frame) prompt(m *ice.Message, list ...string) *Frame {
|
||||
func (f *Frame) prompt(m *ice.Message, arg ...string) *Frame {
|
||||
if f.source != STDIO {
|
||||
return f
|
||||
}
|
||||
if m.Target().Cap(ice.CTX_STATUS) == ice.CTX_CLOSE {
|
||||
return f
|
||||
}
|
||||
if len(list) == 0 {
|
||||
list = append(list, f.ps1...)
|
||||
}
|
||||
fmt.Fprintf(f.stdout, "\r\033[2K")
|
||||
for _, v := range list {
|
||||
switch v {
|
||||
kit.If(len(arg) == 0, func() { arg = append(arg, f.ps1...) })
|
||||
fmt.Fprintf(f.stdout, kit.Select("\r", "\r\033[2K", ice.Info.Colors))
|
||||
kit.For(arg, func(k string) {
|
||||
switch k {
|
||||
case mdb.COUNT:
|
||||
fmt.Fprintf(f.stdout, "%d", f.count)
|
||||
case tcp.HOSTNAME:
|
||||
fmt.Fprintf(f.stdout, ice.Info.NodeName)
|
||||
case mdb.TIME:
|
||||
fmt.Fprintf(f.stdout, time.Now().Format("15:04:05"))
|
||||
fmt.Fprintf(f.stdout, kit.Slice(kit.Split(time.Now().Format(ice.MOD_TIME)), -1)[0])
|
||||
case TARGET:
|
||||
fmt.Fprintf(f.stdout, f.target.Name)
|
||||
default:
|
||||
if ice.Info.Colors || v[0] != '\033' {
|
||||
fmt.Fprintf(f.stdout, v)
|
||||
}
|
||||
kit.If(ice.Info.Colors || k[0] != '\033', func() { fmt.Fprintf(f.stdout, k) })
|
||||
}
|
||||
}
|
||||
})
|
||||
return f
|
||||
}
|
||||
func (f *Frame) printf(m *ice.Message, str string, arg ...ice.Any) *Frame {
|
||||
if f.source != STDIO {
|
||||
return f
|
||||
}
|
||||
if m.Target().Cap(ice.CTX_STATUS) == ice.CTX_CLOSE {
|
||||
return f
|
||||
}
|
||||
fmt.Fprint(f.stdout, kit.Format(str, arg...))
|
||||
return f
|
||||
}
|
||||
@ -76,23 +71,20 @@ func (f *Frame) change(m *ice.Message, ls []string) []string {
|
||||
if ls = ls[1:]; len(target) == 0 && len(ls) > 0 {
|
||||
target, ls = ls[0], ls[1:]
|
||||
}
|
||||
if target == "~" {
|
||||
target = ""
|
||||
}
|
||||
m.Spawn(f.target).Search(target+ice.PT, func(p *ice.Context, s *ice.Context) { f.target = s })
|
||||
kit.If(target == "~", func() { target = "" })
|
||||
m.Spawn(f.target).Search(target+nfs.PT, func(p *ice.Context, s *ice.Context) { f.target = s })
|
||||
}
|
||||
return ls
|
||||
}
|
||||
func (f *Frame) alias(m *ice.Message, ls []string) []string {
|
||||
if len(ls) == 0 {
|
||||
return ls
|
||||
} else if alias := kit.Simple(kit.Value(m.Optionv(ice.MSG_ALIAS), ls[0])); len(alias) > 0 {
|
||||
} else if alias := kit.Simple(kit.Value(m.Optionv(ice.SSH_ALIAS), ls[0])); len(alias) > 0 {
|
||||
ls = append(alias, ls[1:]...)
|
||||
}
|
||||
return ls
|
||||
}
|
||||
func (f *Frame) parse(m *ice.Message, h, line string) string {
|
||||
msg := m.Spawn(f.target)
|
||||
ls := kit.Split(strings.TrimSpace(line))
|
||||
for i, v := range ls {
|
||||
if v == "#" {
|
||||
@ -100,41 +92,43 @@ func (f *Frame) parse(m *ice.Message, h, line string) string {
|
||||
break
|
||||
}
|
||||
}
|
||||
if ls = f.change(msg, f.alias(msg, ls)); len(ls) == 0 {
|
||||
if ls = f.change(m, f.alias(m, ls)); len(ls) == 0 {
|
||||
return ""
|
||||
}
|
||||
if msg.Cmdy(ls); h == STDIO && msg.IsErrNotFound() {
|
||||
msg := m.Spawn(f.target)
|
||||
kit.If(h == STDIO, func() { msg.Option(ice.LOG_TRACEID, log.Traceid(m)) })
|
||||
if msg.Cmdy(ls); h == STDIO && msg.IsErrNotFoundIndex() {
|
||||
msg.SetResult().Cmdy(cli.SYSTEM, ls)
|
||||
}
|
||||
kit.If(m.Option(ice.MSG_STATUS) == "", func() { m.StatusTimeCount() })
|
||||
f.res = Render(msg, msg.Option(ice.MSG_OUTPUT), kit.List(msg.Optionv(ice.MSG_ARGS))...)
|
||||
return ""
|
||||
}
|
||||
func (f *Frame) scan(m *ice.Message, h, line string) *Frame {
|
||||
f.ps1 = kit.Simple(m.Confv(PROMPT, kit.Keym(PS1)))
|
||||
f.ps2 = kit.Simple(m.Confv(PROMPT, kit.Keym(PS2)))
|
||||
m.I, m.O = f.stdin, f.stdout
|
||||
m.Optionv(MESSAGE, m)
|
||||
kit.If(f.source == STDIO, func() { m.Option(ice.LOG_DISABLE, ice.TRUE) })
|
||||
f.ps1 = kit.Simple(mdb.Confv(m, PROMPT, kit.Keym(PS1)))
|
||||
f.ps2 = kit.Simple(mdb.Confv(m, PROMPT, kit.Keym(PS2)))
|
||||
ps, bio := f.ps1, bufio.NewScanner(f.stdin)
|
||||
for f.prompt(m, ps...); f.stdin != nil && bio.Scan(); f.prompt(m, ps...) {
|
||||
m.I, m.O = f.stdin, f.stdout
|
||||
for f.prompt(m.Sleep300ms(), ps...); f.stdin != nil && bio.Scan(); f.prompt(m, ps...) {
|
||||
if len(bio.Text()) == 0 && h == STDIO {
|
||||
continue
|
||||
}
|
||||
f.count++
|
||||
if strings.HasSuffix(bio.Text(), "\\") {
|
||||
if line += bio.Text(); strings.Count(line, "`")%2 == 1 {
|
||||
line += lex.NL
|
||||
ps = f.ps2
|
||||
continue
|
||||
} else if len(bio.Text()) == 0 {
|
||||
continue
|
||||
} else if strings.HasSuffix(bio.Text(), "\\") {
|
||||
line += bio.Text()[:len(bio.Text())-1]
|
||||
ps = f.ps2
|
||||
continue
|
||||
}
|
||||
if line += bio.Text(); strings.Count(line, "`")%2 == 1 {
|
||||
line += ice.NL
|
||||
ps = f.ps2
|
||||
continue
|
||||
}
|
||||
if strings.HasPrefix(strings.TrimSpace(line), "#") {
|
||||
} else if strings.HasPrefix(strings.TrimSpace(line), "#") {
|
||||
line = ""
|
||||
continue
|
||||
}
|
||||
if ps = f.ps1; f.stdout == os.Stdout && ice.Info.Colors {
|
||||
} else if ps = f.ps1; f.stdout == os.Stdout && ice.Info.Colors {
|
||||
f.printf(m, "\033[0m")
|
||||
}
|
||||
line = f.parse(m, h, line)
|
||||
@ -142,66 +136,57 @@ func (f *Frame) scan(m *ice.Message, h, line string) *Frame {
|
||||
return f
|
||||
}
|
||||
|
||||
func (f *Frame) Begin(m *ice.Message, arg ...string) ice.Server {
|
||||
switch strings.Split(os.Getenv(cli.TERM), "-")[0] {
|
||||
case "xterm", "screen":
|
||||
ice.Info.Colors = true
|
||||
default:
|
||||
ice.Info.Colors = false
|
||||
}
|
||||
return f
|
||||
func (f *Frame) Begin(m *ice.Message, arg ...string) {
|
||||
ice.Info.Colors = kit.IsIn(strings.Split(os.Getenv(cli.TERM), "-")[0], "xterm", "screen")
|
||||
}
|
||||
func (f *Frame) Start(m *ice.Message, arg ...string) bool {
|
||||
func (f *Frame) Start(m *ice.Message, arg ...string) {
|
||||
m.Optionv(FRAME, f)
|
||||
switch f.source = kit.Select(STDIO, arg, 0); f.source {
|
||||
case STDIO:
|
||||
if m.Cap(ice.CTX_STREAM, f.source); f.target == nil {
|
||||
f.target = m.Target()
|
||||
}
|
||||
r, w, _ := os.Pipe()
|
||||
go func() { io.Copy(w, os.Stdin) }()
|
||||
f.pipe, f.stdin, f.stdout = w, r, os.Stdout
|
||||
kit.If(f.target == nil, func() { f.target = m.Target() })
|
||||
m.Optionv(ice.MSG_OPTS, ice.MSG_USERNAME, ice.MSG_USERROLE)
|
||||
m.Option(ice.MSG_USERWEB, "http://localhost:9020")
|
||||
f.scan(m, STDIO, "")
|
||||
default:
|
||||
if m.Option(ice.MSG_SCRIPT) != "" {
|
||||
ls := kit.Split(m.Option(ice.MSG_SCRIPT), ice.PS)
|
||||
ls := kit.Split(m.Option(ice.MSG_SCRIPT), nfs.PS)
|
||||
for i := len(ls) - 1; i > 0; i-- {
|
||||
if p := path.Join(path.Join(ls[:i]...), f.source); nfs.ExistsFile(m, p) {
|
||||
if p := path.Join(path.Join(ls[:i]...), f.source); nfs.Exists(m, p) {
|
||||
f.source = p
|
||||
}
|
||||
}
|
||||
}
|
||||
m.Option(ice.MSG_SCRIPT, f.source)
|
||||
f.target = m.Source()
|
||||
if msg := m.Cmd(nfs.CAT, f.source); msg.IsErr() {
|
||||
return true
|
||||
if msg := m.Cmd(nfs.CAT, m.Option(ice.MSG_SCRIPT, f.source)); msg.IsErr() {
|
||||
return
|
||||
} else {
|
||||
kit.If(m.Option(nfs.CAT_CONTENT), func() { m.Option(nfs.CAT_CONTENT, "") })
|
||||
buf := bytes.NewBuffer(make([]byte, 0, ice.MOD_BUFS))
|
||||
f.stdin, f.stdout = bytes.NewBufferString(msg.Result()), buf
|
||||
defer func() { m.Echo(buf.String()) }()
|
||||
}
|
||||
if target, ok := m.Optionv(ice.SSH_TARGET).(*ice.Context); ok {
|
||||
f.target = target
|
||||
} else {
|
||||
f.target = m.Source()
|
||||
}
|
||||
f.scan(m, "", "")
|
||||
}
|
||||
return true
|
||||
}
|
||||
func (f *Frame) Close(m *ice.Message, arg ...string) bool {
|
||||
if stdin, ok := f.stdin.(io.Closer); ok {
|
||||
stdin.Close()
|
||||
}
|
||||
func (f *Frame) Close(m *ice.Message, arg ...string) {
|
||||
nfs.Close(m, f.stdin)
|
||||
f.stdin = nil
|
||||
return true
|
||||
}
|
||||
func (f *Frame) Spawn(m *ice.Message, c *ice.Context, arg ...string) ice.Server {
|
||||
return &Frame{}
|
||||
}
|
||||
func (f *Frame) Spawn(m *ice.Message, c *ice.Context, arg ...string) ice.Server { return &Frame{} }
|
||||
|
||||
const (
|
||||
MESSAGE = "message"
|
||||
FRAME = "frame"
|
||||
STDIO = "stdio"
|
||||
PS1 = "PS1"
|
||||
PS2 = "PS2"
|
||||
FRAME = "frame"
|
||||
SHELL = "shell"
|
||||
STDIO = "stdio"
|
||||
PS1 = "PS1"
|
||||
PS2 = "PS2"
|
||||
)
|
||||
const (
|
||||
SOURCE = "source"
|
||||
@ -209,7 +194,6 @@ const (
|
||||
TARGET = "target"
|
||||
PROMPT = "prompt"
|
||||
PRINTF = "printf"
|
||||
SCREEN = "screen"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@ -226,13 +210,13 @@ func init() {
|
||||
}},
|
||||
TARGET: {Name: "target name run", Help: "当前模块", Hand: func(m *ice.Message, arg ...string) {
|
||||
if f, ok := m.Target().Server().(*Frame); ok {
|
||||
m.Search(arg[0]+ice.PT, func(p *ice.Context, s *ice.Context) { f.target = s })
|
||||
m.Search(arg[0]+nfs.PT, func(p *ice.Context, s *ice.Context) { f.target = s })
|
||||
f.prompt(m)
|
||||
}
|
||||
}},
|
||||
PROMPT: {Name: "prompt arg run", Help: "命令提示", Actions: ctx.ConfAction(
|
||||
PS1, []ice.Any{"\033[33;44m", mdb.COUNT, "[", mdb.TIME, "]", "\033[5m", TARGET, "\033[0m", "\033[44m", ">", "\033[0m ", "\033[?25h", "\033[32m"},
|
||||
PS2, []ice.Any{mdb.COUNT, " ", TARGET, "> "},
|
||||
PS1, ice.List{"\033[33;44m", mdb.COUNT, mdb.AT, tcp.HOSTNAME, "[", mdb.TIME, "]", "\033[5m", TARGET, "\033[0m", "\033[44m", ">", "\033[0m ", "\033[?25h", "\033[32m"},
|
||||
PS2, ice.List{mdb.COUNT, lex.SP, TARGET, "> "},
|
||||
), Hand: func(m *ice.Message, arg ...string) {
|
||||
if f, ok := m.Target().Server().(*Frame); ok {
|
||||
f.prompt(m, arg...)
|
||||
@ -243,15 +227,9 @@ func init() {
|
||||
f.printf(m, kit.Select(m.Option(nfs.CONTENT), arg, 0))
|
||||
}
|
||||
}},
|
||||
SCREEN: {Name: "screen run text", Help: "输出命令", Hand: func(m *ice.Message, arg ...string) {
|
||||
if f, ok := m.Target().Server().(*Frame); ok {
|
||||
for _, line := range kit.Split(arg[0], ice.NL, ice.NL) {
|
||||
fmt.Fprintf(f.pipe, line+ice.NL)
|
||||
f.printf(m, line+ice.NL)
|
||||
m.Sleep300ms()
|
||||
}
|
||||
m.Echo(f.res)
|
||||
}
|
||||
}},
|
||||
})
|
||||
}
|
||||
|
||||
func PrintQRCode(m *ice.Message, url string) {
|
||||
m.Spawn(ice.OptionSilent()).Cmd(PRINTF, kit.Dict(nfs.CONTENT, lex.NL+ice.Render(m, ice.RENDER_QRCODE, url))).Cmd(PROMPT)
|
||||
}
|
||||
|
@ -6,4 +6,4 @@ const SSH = "ssh"
|
||||
|
||||
var Index = &ice.Context{Name: SSH, Help: "终端模块"}
|
||||
|
||||
func init() { ice.Index.Register(Index, &Frame{}, SOURCE, RETURN, TARGET, PROMPT, PRINTF, SCREEN) }
|
||||
func init() { ice.Index.Register(Index, &Frame{}, SOURCE, RETURN, TARGET, PROMPT, PRINTF) }
|
||||
|
58
base/tcp/broad.go
Normal file
58
base/tcp/broad.go
Normal file
@ -0,0 +1,58 @@
|
||||
package tcp
|
||||
|
||||
import (
|
||||
"net"
|
||||
|
||||
ice "shylinux.com/x/icebergs"
|
||||
"shylinux.com/x/icebergs/base/mdb"
|
||||
"shylinux.com/x/icebergs/base/nfs"
|
||||
kit "shylinux.com/x/toolkits"
|
||||
"shylinux.com/x/toolkits/logs"
|
||||
)
|
||||
|
||||
func _server_udp(m *ice.Message, arg ...string) {
|
||||
l, e := net.ListenUDP(UDP4, UDPAddr(m, "0.0.0.0", m.Option(PORT)))
|
||||
defer kit.If(e == nil, func() { l.Close() })
|
||||
mdb.HashCreate(m, arg, kit.Dict(mdb.TARGET, l), STATUS, kit.Select(ERROR, OPEN, e == nil), ERROR, kit.Format(e))
|
||||
switch cb := m.OptionCB("").(type) {
|
||||
case func(*net.UDPAddr, []byte):
|
||||
m.Assert(e)
|
||||
buf := make([]byte, 2*ice.MOD_BUFS)
|
||||
for {
|
||||
if n, from, e := l.ReadFromUDP(buf[:]); !m.WarnNotValid(e) {
|
||||
cb(from, buf[:n])
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
default:
|
||||
m.ErrorNotImplement(cb)
|
||||
}
|
||||
}
|
||||
func _client_dial_udp4(m *ice.Message, arg ...string) {
|
||||
c, e := net.DialUDP(UDP4, nil, UDPAddr(m, kit.Select("255.255.255.255", m.Option(HOST)), m.Option(PORT)))
|
||||
defer kit.If(e == nil, func() { c.Close() })
|
||||
switch cb := m.OptionCB("").(type) {
|
||||
case func(*net.UDPConn):
|
||||
kit.If(!m.WarnNotValid(e), func() { cb(c) })
|
||||
default:
|
||||
m.ErrorNotImplement(cb)
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
UDP4 = "udp4"
|
||||
SEND = "send"
|
||||
RECV = "recv"
|
||||
ECHO = "echo"
|
||||
DONE = "done"
|
||||
DIRECT = "direct"
|
||||
)
|
||||
|
||||
func UDPAddr(m *ice.Message, host, port string) *net.UDPAddr {
|
||||
if addr, e := net.ResolveUDPAddr(UDP4, host+nfs.DF+port); !m.WarnNotValid(e, host, port, logs.FileLineMeta(2)) {
|
||||
return addr
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func HostPort(host, port string) string { return host + nfs.DF + port }
|
@ -2,21 +2,19 @@ package tcp
|
||||
|
||||
import (
|
||||
"net"
|
||||
"time"
|
||||
|
||||
ice "shylinux.com/x/icebergs"
|
||||
"shylinux.com/x/icebergs/base/mdb"
|
||||
"shylinux.com/x/icebergs/base/nfs"
|
||||
kit "shylinux.com/x/toolkits"
|
||||
)
|
||||
|
||||
type Stat struct {
|
||||
nc, nr, nw int
|
||||
}
|
||||
|
||||
type Conn struct {
|
||||
net.Conn
|
||||
m *ice.Message
|
||||
h string
|
||||
s *Stat
|
||||
|
||||
net.Conn
|
||||
}
|
||||
|
||||
func (c *Conn) Read(b []byte) (int, error) {
|
||||
@ -32,34 +30,17 @@ func (c *Conn) Write(b []byte) (int, error) {
|
||||
func (c *Conn) Close() error { return c.Conn.Close() }
|
||||
|
||||
func _client_dial(m *ice.Message, arg ...string) {
|
||||
c, e := net.Dial(TCP, m.Option(HOST)+ice.DF+m.Option(PORT))
|
||||
c = &Conn{m: m, s: &Stat{}, Conn: c}
|
||||
if e == nil {
|
||||
defer c.Close()
|
||||
}
|
||||
c, e := net.DialTimeout(TCP, m.Option(HOST)+nfs.DF+m.Option(PORT), 3*time.Second)
|
||||
c = &Conn{Conn: c, m: m, s: &Stat{}}
|
||||
defer kit.If(e == nil, func() { c.Close() })
|
||||
switch cb := m.OptionCB("").(type) {
|
||||
case func(*ice.Message, net.Conn):
|
||||
if !m.Warn(e) {
|
||||
cb(m, c)
|
||||
}
|
||||
case func(net.Conn):
|
||||
if !m.Warn(e) {
|
||||
cb(c)
|
||||
}
|
||||
kit.If(!m.WarnNotValid(e), func() { cb(c) })
|
||||
default:
|
||||
m.ErrorNotImplement(cb)
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
PROTO = "proto"
|
||||
STATUS = "status"
|
||||
ERROR = "error"
|
||||
START = "start"
|
||||
OPEN = "open"
|
||||
CLOSE = "close"
|
||||
STOP = "stop"
|
||||
)
|
||||
const (
|
||||
DIAL = "dial"
|
||||
)
|
||||
@ -67,10 +48,15 @@ const CLIENT = "client"
|
||||
|
||||
func init() {
|
||||
Index.MergeCommands(ice.Commands{
|
||||
CLIENT: {Name: "client hash auto prunes", Help: "客户端", Actions: ice.MergeActions(ice.Actions{
|
||||
CLIENT: {Help: "客户端", Actions: ice.MergeActions(ice.Actions{
|
||||
DIAL: {Name: "dial type name port=9010 host=", Help: "连接", Hand: func(m *ice.Message, arg ...string) {
|
||||
_client_dial(m, arg...)
|
||||
switch m.Option(mdb.TYPE) {
|
||||
case UDP4:
|
||||
_client_dial_udp4(m, arg...)
|
||||
default:
|
||||
_client_dial(m, arg...)
|
||||
}
|
||||
}},
|
||||
}, mdb.StatusHashAction(mdb.FIELD, "time,hash,status,type,name,host,port,error,nread,nwrite"), mdb.ClearHashOnExitAction())},
|
||||
}, mdb.StatusHashAction(mdb.FIELD, "time,hash,status,type,name,host,port,error"), mdb.ClearOnExitHashAction())},
|
||||
})
|
||||
}
|
||||
|
@ -2,51 +2,61 @@ package tcp
|
||||
|
||||
import (
|
||||
"net"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
ice "shylinux.com/x/icebergs"
|
||||
"shylinux.com/x/icebergs/base/aaa"
|
||||
"shylinux.com/x/icebergs/base/mdb"
|
||||
"shylinux.com/x/icebergs/base/nfs"
|
||||
"shylinux.com/x/icebergs/base/web/html"
|
||||
kit "shylinux.com/x/toolkits"
|
||||
)
|
||||
|
||||
func _host_list(m *ice.Message, name string) {
|
||||
func _host_domain(m *ice.Message) string {
|
||||
return kit.GetValid(
|
||||
func() string { return m.Option(ice.TCP_DOMAIN) },
|
||||
func() string { return mdb.Config(m, DOMAIN) },
|
||||
func() string { return os.Getenv(ice.TCP_DOMAIN) },
|
||||
func() string {
|
||||
if !kit.IsIn(m.ActionKey(), "", ice.LIST) {
|
||||
return m.Cmdv(HOST, mdb.Config(m, ice.MAIN), aaa.IP)
|
||||
}
|
||||
return ""
|
||||
},
|
||||
func() string {
|
||||
return LOCALHOST
|
||||
},
|
||||
)
|
||||
}
|
||||
func _host_list(m *ice.Message, name string) *ice.Message {
|
||||
if ifs, e := net.Interfaces(); m.Assert(e) {
|
||||
for _, v := range ifs {
|
||||
if name != "" && !strings.Contains(v.Name, name) {
|
||||
continue
|
||||
}
|
||||
if len(v.HardwareAddr.String()) == 0 {
|
||||
if !strings.Contains(v.Name, name) || len(v.HardwareAddr.String()) == 0 {
|
||||
continue
|
||||
}
|
||||
if ips, e := v.Addrs(); m.Assert(e) {
|
||||
for _, x := range ips {
|
||||
ip := strings.Split(x.String(), ice.PS)
|
||||
if strings.Contains(ip[0], ice.DF) || len(ip) == 0 {
|
||||
ip := strings.Split(x.String(), nfs.PS)
|
||||
if strings.Contains(ip[0], nfs.DF) || len(ip) == 0 {
|
||||
continue
|
||||
}
|
||||
m.Push(mdb.INDEX, v.Index)
|
||||
m.Push(mdb.NAME, v.Name)
|
||||
m.Push(aaa.IP, ip[0])
|
||||
m.Push("mask", ip[1])
|
||||
m.Push("hard", v.HardwareAddr.String())
|
||||
m.Push(mdb.INDEX, v.Index).Push(mdb.NAME, v.Name).Push(aaa.IP, ip[0]).Push(MASK, ip[1]).Push(MAC_ADDRESS, v.HardwareAddr.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(m.Appendv(aaa.IP)) == 0 {
|
||||
m.Push(mdb.INDEX, -1)
|
||||
m.Push(mdb.NAME, LOCALHOST)
|
||||
m.Push(aaa.IP, "127.0.0.1")
|
||||
m.Push("mask", "255.0.0.0")
|
||||
m.Push("hard", "")
|
||||
}
|
||||
m.StatusTimeCount()
|
||||
return m.SortInt(mdb.INDEX).StatusTimeCount(DOMAIN, _host_domain(m))
|
||||
}
|
||||
|
||||
const (
|
||||
LOCALHOST = "localhost"
|
||||
LOCALHOST = "localhost"
|
||||
MAC_ADDRESS = "mac-address"
|
||||
MASK = "mask"
|
||||
|
||||
DOMAIN = "domain"
|
||||
GATEWAY = "gateway"
|
||||
MACHINE = "machine"
|
||||
ISLOCAL = "islocal"
|
||||
PUBLISH = "publish"
|
||||
)
|
||||
@ -54,9 +64,20 @@ const HOST = "host"
|
||||
|
||||
func init() {
|
||||
Index.MergeCommands(ice.Commands{
|
||||
HOST: {Name: "host name auto", Help: "主机", Actions: ice.MergeActions(ice.Actions{
|
||||
HOST: {Name: "host name auto domain", Help: "主机", Meta: kit.Dict(
|
||||
ice.CTX_TRANS, kit.Dict(html.INPUT, kit.Dict(
|
||||
aaa.IP, "网络地址", MASK, "子网掩码", MAC_ADDRESS, "物理地址",
|
||||
)),
|
||||
), Actions: ice.MergeActions(ice.Actions{
|
||||
ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) {
|
||||
m.Cmd("", func(value ice.Maps) { m.Cmd("", aaa.WHITE, LOCALHOST, value[aaa.IP]) })
|
||||
ice.Info.Host = mdb.Config(m, DOMAIN)
|
||||
}},
|
||||
mdb.SEARCH: {Hand: func(m *ice.Message, arg ...string) {
|
||||
if mdb.IsSearchPreview(m, arg) && m.Cmd(HOST).Length() > 0 {
|
||||
ip := m.Cmdv(HOST, GATEWAY, aaa.IP)
|
||||
m.PushSearch(mdb.TYPE, GATEWAY, mdb.NAME, ip, mdb.TEXT, "http://"+ip)
|
||||
}
|
||||
}},
|
||||
aaa.WHITE: {Name: "white name text", Help: "白名单", Hand: func(m *ice.Message, arg ...string) {
|
||||
mdb.HashCreate(m, mdb.TYPE, m.ActionKey(), m.OptionSimple(mdb.NAME, mdb.TEXT))
|
||||
@ -65,22 +86,36 @@ func init() {
|
||||
mdb.HashCreate(m, mdb.TYPE, m.ActionKey(), m.OptionSimple(mdb.NAME, mdb.TEXT))
|
||||
}},
|
||||
ISLOCAL: {Hand: func(m *ice.Message, arg ...string) {
|
||||
if arg[0] = strings.Split(strings.TrimPrefix(arg[0], "["), "]")[0]; arg[0] == "::1" || strings.HasPrefix(arg[0], "127.") {
|
||||
if arg[0] = strings.Split(strings.TrimPrefix(arg[0], "["), "]")[0]; arg[0] == "::1" || strings.HasPrefix(arg[0], "127.") || arg[0] == LOCALHOST {
|
||||
m.Echo(ice.OK)
|
||||
} else if mdb.HashSelectField(m, arg[0], mdb.TYPE) == aaa.WHITE {
|
||||
} else if mdb.HashSelectField(m, strings.Split(arg[0], nfs.DF)[0], mdb.TYPE) == aaa.WHITE {
|
||||
m.Echo(ice.OK)
|
||||
}
|
||||
}},
|
||||
PUBLISH: {Hand: func(m *ice.Message, arg ...string) {
|
||||
if strings.Contains(arg[0], LOCALHOST) {
|
||||
arg[0] = strings.Replace(arg[0], LOCALHOST, m.Cmd("").Append(aaa.IP), 1)
|
||||
} else if strings.Contains(arg[0], "127.0.0.1") {
|
||||
arg[0] = strings.Replace(arg[0], "127.0.0.1", m.Cmd("").Append(aaa.IP), 1)
|
||||
for _, p := range []string{LOCALHOST, "127.0.0.1", m.Option("tcp_localhost")} {
|
||||
if p != "" && strings.Contains(arg[0], p) {
|
||||
arg[0] = strings.Replace(arg[0], p, _host_domain(m), 1)
|
||||
break
|
||||
}
|
||||
}
|
||||
m.Echo(arg[0])
|
||||
}},
|
||||
}, mdb.HashAction(mdb.SHORT, mdb.TEXT), mdb.ClearHashOnExitAction()), Hand: func(m *ice.Message, arg ...string) {
|
||||
_host_list(m, kit.Select("", arg, 0))
|
||||
GATEWAY: {Hand: func(m *ice.Message, arg ...string) {
|
||||
m.Push(aaa.IP, kit.Keys(kit.Slice(strings.Split(m.Cmdv(HOST, aaa.IP), nfs.PT), 0, 3), "1"))
|
||||
}},
|
||||
DOMAIN: {Name: "domain ip", Help: "主机", Icon: "bi bi-house-check", Hand: func(m *ice.Message, arg ...string) {
|
||||
kit.If(m.Option(aaa.IP), func(p string) { ice.Info.Host = p; mdb.Config(m, DOMAIN, p) })
|
||||
m.Echo(mdb.Config(m, DOMAIN))
|
||||
}},
|
||||
}, mdb.HashAction(mdb.SHORT, mdb.TEXT)), Hand: func(m *ice.Message, arg ...string) {
|
||||
_host_list(m, kit.Select("", arg, 0)).Table(func(value ice.Maps) {
|
||||
if value[aaa.IP] == mdb.Config(m, DOMAIN) {
|
||||
m.Push(mdb.STATUS, "current").PushButton("")
|
||||
} else {
|
||||
m.Push(mdb.STATUS, "").PushButton(DOMAIN)
|
||||
}
|
||||
})
|
||||
}},
|
||||
})
|
||||
}
|
||||
|
52
base/tcp/peek.go
Normal file
52
base/tcp/peek.go
Normal file
@ -0,0 +1,52 @@
|
||||
package tcp
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"net"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
kit "shylinux.com/x/toolkits"
|
||||
)
|
||||
|
||||
type Buf struct {
|
||||
buf []byte
|
||||
}
|
||||
type PeekConn struct {
|
||||
net.Conn
|
||||
*Buf
|
||||
}
|
||||
|
||||
func (s PeekConn) Read(b []byte) (n int, err error) {
|
||||
if len(s.buf) == 0 {
|
||||
return s.Conn.Read(b)
|
||||
}
|
||||
if len(s.buf) < len(b) {
|
||||
copy(b, s.buf)
|
||||
s.buf = s.buf[:0]
|
||||
return len(s.buf), nil
|
||||
}
|
||||
copy(b, s.buf)
|
||||
s.buf = s.buf[len(b):]
|
||||
return len(b), nil
|
||||
}
|
||||
func (s PeekConn) Peek(n int) (res []byte) {
|
||||
b := make([]byte, n)
|
||||
_n, _ := s.Conn.Read(b)
|
||||
s.Buf.buf = b[:_n]
|
||||
return b[:_n]
|
||||
}
|
||||
func (s PeekConn) IsHTTP() bool {
|
||||
if head := s.Peek(4); bytes.Equal(head, []byte("GET ")) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
func (s PeekConn) Redirect(status int, location string) {
|
||||
DF, NL := ": ", "\r\n"
|
||||
s.Conn.Write([]byte(strings.Join([]string{
|
||||
kit.Format("HTTP/1.1 %d %s", status, http.StatusText(status)),
|
||||
kit.JoinKV(DF, NL, "Location", location, "Content-Length", "0"),
|
||||
}, NL) + NL + NL))
|
||||
}
|
||||
func NewPeekConn(c net.Conn) PeekConn { return PeekConn{Conn: c, Buf: &Buf{}} }
|
145
base/tcp/port.go
145
base/tcp/port.go
@ -3,22 +3,22 @@ package tcp
|
||||
import (
|
||||
"net"
|
||||
"path"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
ice "shylinux.com/x/icebergs"
|
||||
"shylinux.com/x/icebergs/base/aaa"
|
||||
"shylinux.com/x/icebergs/base/ctx"
|
||||
"shylinux.com/x/icebergs/base/mdb"
|
||||
"shylinux.com/x/icebergs/base/nfs"
|
||||
kit "shylinux.com/x/toolkits"
|
||||
)
|
||||
|
||||
func _port_right(m *ice.Message, arg ...string) string {
|
||||
current, end := kit.Int(kit.Select(m.Config(CURRENT), arg, 0)), kit.Int(m.Config(END))
|
||||
if current >= end {
|
||||
current = kit.Int(m.Config(BEGIN))
|
||||
}
|
||||
func _port_right(m *ice.Message, current, begin, end int) string {
|
||||
kit.If(current >= end, func() { current = begin })
|
||||
for i := current; i < end; i++ {
|
||||
if p := path.Join(ice.USR_LOCAL_DAEMON, kit.Format(i)); nfs.ExistsFile(m, p) {
|
||||
if p := path.Join(ice.USR_LOCAL_DAEMON, kit.Format(i)); nfs.Exists(m, p) {
|
||||
|
||||
} else if c, e := net.Dial(TCP, kit.Format(":%d", i)); e == nil {
|
||||
m.Info("port exists %v", i)
|
||||
@ -26,50 +26,145 @@ func _port_right(m *ice.Message, arg ...string) string {
|
||||
} else {
|
||||
nfs.MkdirAll(m, p)
|
||||
m.Logs(mdb.SELECT, PORT, i)
|
||||
return m.Config(CURRENT, i)
|
||||
return mdb.Config(m, CURRENT, i)
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
const (
|
||||
PORT_22 = "22"
|
||||
PORT_80 = "80"
|
||||
PORT_443 = "443"
|
||||
PORT_9020 = "9020"
|
||||
PORT_9022 = "9022"
|
||||
|
||||
SOCKET = "socket"
|
||||
BEGIN = "begin"
|
||||
CURRENT = "current"
|
||||
RANDOM = "random"
|
||||
END = "end"
|
||||
PID = "pid"
|
||||
SPACE = "space"
|
||||
)
|
||||
const PORT = "port"
|
||||
|
||||
func init() {
|
||||
Index.MergeCommands(ice.Commands{
|
||||
PORT: {Name: "port port path auto", Help: "端口", Actions: ice.MergeActions(ice.Actions{
|
||||
CURRENT: {Hand: func(m *ice.Message, arg ...string) { m.Echo(m.Config(CURRENT)) }},
|
||||
aaa.RIGHT: {Hand: func(m *ice.Message, arg ...string) { m.Echo(_port_right(m, arg...)) }},
|
||||
PORT: {Name: "port port path auto socket", Help: "端口", Actions: ice.MergeActions(ice.Actions{
|
||||
mdb.INPUTS: {Hand: func(m *ice.Message, arg ...string) {
|
||||
switch arg[0] {
|
||||
case HOST, SERVER:
|
||||
m.Cmd(PORT, SOCKET, func(value ice.Maps) {
|
||||
switch value[mdb.STATUS] {
|
||||
case "LISTEN":
|
||||
m.Push(arg[0], strings.Replace(value["local"], "0.0.0.0", "127.0.0.1", 1))
|
||||
}
|
||||
})
|
||||
case PORT:
|
||||
if runtime.GOOS == "darwin" {
|
||||
ls := kit.SplitLine(m.Cmd("system", "sh", "-c", `lsof -nP -i4TCP | grep LISTEN | awk '{print $1 " " $9 }'`).Result())
|
||||
kit.For(ls, func(p string) {
|
||||
ls := kit.SplitWord(p)
|
||||
m.Push(arg[0], kit.Split(ls[1], ":")[1]).Push(SERVER, ls[0])
|
||||
})
|
||||
m.Sort(arg[0], ice.INT)
|
||||
return
|
||||
}
|
||||
m.Cmd(PORT, SOCKET, func(value ice.Maps) {
|
||||
switch value[mdb.STATUS] {
|
||||
case "LISTEN":
|
||||
m.Push(arg[0], strings.TrimPrefix(value["local"], "0.0.0.0:"))
|
||||
m.Push(mdb.NAME, "listen")
|
||||
}
|
||||
})
|
||||
}
|
||||
}},
|
||||
SOCKET: {Help: "端口", Hand: func(m *ice.Message, arg ...string) {
|
||||
parse := func(str string) int64 { port, _ := strconv.ParseInt(str, 16, 32); return port }
|
||||
trans := func(str string) string {
|
||||
switch str {
|
||||
case "01":
|
||||
return "ESTABLISHED"
|
||||
case "02":
|
||||
return "TCP_SYNC_SEND"
|
||||
case "03":
|
||||
return "TCP_SYNC_RECV"
|
||||
case "04":
|
||||
return "TCP_FIN_WAIT1"
|
||||
case "05":
|
||||
return "TCP_FIN_WAIT2"
|
||||
case "06":
|
||||
return "TIME_WAIT"
|
||||
case "07":
|
||||
return "TCP_CLOSE"
|
||||
case "08":
|
||||
return "TCP_CLOSE_WAIT"
|
||||
case "0A":
|
||||
return "LISTEN"
|
||||
default:
|
||||
return str
|
||||
}
|
||||
}
|
||||
stats := map[string]int{}
|
||||
m.Spawn().Split(m.Cmdx(nfs.CAT, "/proc/net/tcp")).Table(func(value ice.Maps) {
|
||||
stats[trans(value["st"])]++
|
||||
m.Push(mdb.STATUS, trans(value["st"]))
|
||||
ls := kit.Split(value["local_address"], ":")
|
||||
m.Push("local", kit.Format("%d.%d.%d.%d:%d", parse(ls[0][6:8]), parse(ls[0][4:6]), parse(ls[0][2:4]), parse(ls[0][:2]), parse(ls[1])))
|
||||
ls = kit.Split(value["rem_address"], ":")
|
||||
m.Push("remote", kit.Format("%d.%d.%d.%d:%d", parse(ls[0][6:8]), parse(ls[0][4:6]), parse(ls[0][2:4]), parse(ls[0][:2]), parse(ls[1])))
|
||||
})
|
||||
m.Spawn().Split(m.Cmdx(nfs.CAT, "/proc/net/tcp6")).Table(func(value ice.Maps) {
|
||||
stats[trans(value["st"])]++
|
||||
m.Push(mdb.STATUS, trans(value["st"]))
|
||||
ls := kit.Split(value["local_address"], ":")
|
||||
m.Push("local", kit.Format("%d.%d.%d.%d:%d", parse(ls[0][30:32]), parse(ls[0][28:30]), parse(ls[0][26:28]), parse(ls[0][24:26]), parse(ls[1])))
|
||||
ls = kit.Split(value["remote_address"], ":")
|
||||
m.Push("remote", kit.Format("%d.%d.%d.%d:%d", parse(ls[0][30:32]), parse(ls[0][28:30]), parse(ls[0][26:28]), parse(ls[0][24:26]), parse(ls[1])))
|
||||
})
|
||||
m.Sort("status,local", []string{"LISTEN", "ESTABLISHED", "TIME_WAIT"}).StatusTimeCount(stats)
|
||||
}},
|
||||
nfs.TRASH: {Hand: func(m *ice.Message, arg ...string) {
|
||||
m.Assert(m.Option(PORT) != "")
|
||||
nfs.Trash(m, path.Join(ice.USR_LOCAL_DAEMON, m.Option(PORT)))
|
||||
mdb.HashRemove(m)
|
||||
}},
|
||||
}, mdb.HashAction(BEGIN, 10000, CURRENT, 10000, END, 20000)), Hand: func(m *ice.Message, arg ...string) {
|
||||
aaa.RIGHT: {Hand: func(m *ice.Message, arg ...string) { m.Echo(PortRight(m, arg...)) }},
|
||||
CURRENT: {Hand: func(m *ice.Message, arg ...string) { m.Echo(mdb.Config(m, CURRENT)) }},
|
||||
STOP: {Hand: func(m *ice.Message, arg ...string) { PortCmds(m, arg...); mdb.HashModify(m, PID, "") }},
|
||||
START: {Hand: func(m *ice.Message, arg ...string) { PortCmds(m, arg...); mdb.HashModify(m, PID, m.Append(PID)) }},
|
||||
}, mdb.HashAction(BEGIN, 10000, END, 20000,
|
||||
mdb.SHORT, PORT, mdb.FIELD, "time,port,pid,cmd,name,text,icon,space,index",
|
||||
)), Hand: func(m *ice.Message, arg ...string) {
|
||||
if len(arg) > 0 {
|
||||
m.Cmdy(nfs.DIR, arg[1:], kit.Dict(nfs.DIR_ROOT, path.Join(ice.USR_LOCAL_DAEMON, arg[0])))
|
||||
return
|
||||
}
|
||||
current := kit.Int(m.Config(BEGIN))
|
||||
m.Option(nfs.DIR_ROOT, ice.USR_LOCAL_DAEMON)
|
||||
m.Cmd(nfs.DIR, nfs.PWD, func(value ice.Maps) {
|
||||
bin := m.CmdAppend(nfs.DIR, path.Join(value[nfs.PATH], ice.BIN), nfs.PATH)
|
||||
if bin == "" {
|
||||
bin = m.CmdAppend(nfs.DIR, path.Join(value[nfs.PATH], "sbin"), nfs.PATH)
|
||||
current := kit.Int(mdb.Config(m, BEGIN))
|
||||
mdb.HashSelect(m, arg...).Table(func(value ice.Maps) {
|
||||
current = kit.Max(current, kit.Int(value[PORT]))
|
||||
if value[PID] == "" {
|
||||
m.PushButton(START, nfs.TRASH)
|
||||
} else {
|
||||
m.PushButton(STOP)
|
||||
}
|
||||
port := kit.Int(path.Base(value[nfs.PATH]))
|
||||
m.Push(mdb.TIME, value[mdb.TIME])
|
||||
m.Push(PORT, port)
|
||||
m.Push(nfs.SIZE, value[nfs.SIZE])
|
||||
m.Push(ice.BIN, strings.TrimPrefix(bin, value[nfs.PATH]))
|
||||
current = kit.Max(current, port)
|
||||
})
|
||||
m.Config(CURRENT, current)
|
||||
m.PushAction(nfs.TRASH).StatusTimeCount(m.ConfigSimple(BEGIN, CURRENT, END)).SortInt(PORT)
|
||||
mdb.Config(m, CURRENT, current)
|
||||
m.StatusTimeCount(mdb.ConfigSimple(m, BEGIN, CURRENT, END)).SortInt(PORT)
|
||||
}},
|
||||
})
|
||||
ice.Info.Inputs = append(ice.Info.Inputs, func(m *ice.Message, arg ...string) {
|
||||
switch arg[0] {
|
||||
case PORT:
|
||||
m.SetAppend().Cmdy(PORT, mdb.INPUTS, arg)
|
||||
}
|
||||
})
|
||||
}
|
||||
func PortRight(m *ice.Message, arg ...string) string {
|
||||
current, begin, end := kit.Select("20000", mdb.Config(m, CURRENT)), kit.Select("20000", mdb.Config(m, BEGIN)), kit.Select("30000", mdb.Config(m, END))
|
||||
return _port_right(m, kit.Int(kit.Select(kit.Select(begin, current), arg, 0)), kit.Int(kit.Select(begin, arg, 1)), kit.Int(kit.Select(end, arg, 2)))
|
||||
}
|
||||
func PortCmds(m *ice.Message, arg ...string) {
|
||||
m.Cmdy(SPACE, m.Option(SPACE), m.Option(ctx.INDEX), m.ActionKey())
|
||||
}
|
||||
|
@ -5,15 +5,17 @@ import (
|
||||
|
||||
ice "shylinux.com/x/icebergs"
|
||||
"shylinux.com/x/icebergs/base/mdb"
|
||||
"shylinux.com/x/icebergs/base/nfs"
|
||||
kit "shylinux.com/x/toolkits"
|
||||
)
|
||||
|
||||
type Stat struct{ nc, nr, nw int }
|
||||
|
||||
type Listener struct {
|
||||
net.Listener
|
||||
m *ice.Message
|
||||
h string
|
||||
s *Stat
|
||||
|
||||
net.Listener
|
||||
}
|
||||
|
||||
func (l Listener) Accept() (net.Conn, error) {
|
||||
@ -27,18 +29,18 @@ func (l Listener) Close() error {
|
||||
}
|
||||
|
||||
func _server_listen(m *ice.Message, arg ...string) {
|
||||
l, e := net.Listen(TCP, m.Option(HOST)+":"+m.Option(PORT))
|
||||
l = &Listener{m: m, h: mdb.HashCreate(m, arg, kit.Dict(mdb.TARGET, l), STATUS, kit.Select(ERROR, OPEN, e == nil), ERROR, kit.Format(e)), s: &Stat{}, Listener: l}
|
||||
if e == nil {
|
||||
defer l.Close()
|
||||
l, e := net.Listen(TCP, m.Option(HOST)+nfs.DF+m.Option(PORT))
|
||||
if m.WarnNotValid(e) {
|
||||
return
|
||||
}
|
||||
l = &Listener{Listener: l, m: m, h: mdb.HashCreate(m, arg, kit.Dict(mdb.TARGET, l), STATUS, kit.Select(ERROR, OPEN, e == nil), ERROR, kit.Format(e)), s: &Stat{}}
|
||||
defer kit.If(e == nil, func() { l.Close() })
|
||||
switch cb := m.OptionCB("").(type) {
|
||||
case func(net.Listener):
|
||||
m.Assert(e)
|
||||
cb(l)
|
||||
case func(net.Conn):
|
||||
for {
|
||||
if c, e := l.Accept(); e == nil {
|
||||
if c, e := l.Accept(); !m.WarnNotValid(e) {
|
||||
cb(c)
|
||||
} else {
|
||||
break
|
||||
@ -50,21 +52,40 @@ func _server_listen(m *ice.Message, arg ...string) {
|
||||
}
|
||||
|
||||
const (
|
||||
PROTOCOL = "protocol"
|
||||
HOSTPORT = "hostport"
|
||||
HOSTNAME = "hostname"
|
||||
PROTOCOL = "protocol"
|
||||
HOSTPORT = "hostport"
|
||||
HOSTNAME = "hostname"
|
||||
NODENAME = "nodename"
|
||||
NODETYPE = "nodetype"
|
||||
BANDWIDTH = "bandwidth"
|
||||
ADDRESS = "address"
|
||||
)
|
||||
const (
|
||||
PROTO = "proto"
|
||||
STATUS = "status"
|
||||
ERROR = "error"
|
||||
START = "start"
|
||||
OPEN = "open"
|
||||
CLOSE = "close"
|
||||
STOP = "stop"
|
||||
)
|
||||
const (
|
||||
LISTEN = "listen"
|
||||
UNIX = "unix"
|
||||
)
|
||||
const SERVER = "server"
|
||||
|
||||
func init() {
|
||||
Index.MergeCommands(ice.Commands{
|
||||
SERVER: {Name: "server hash auto prunes", Help: "服务器", Actions: ice.MergeActions(ice.Actions{
|
||||
SERVER: {Help: "服务器", Actions: ice.MergeActions(ice.Actions{
|
||||
LISTEN: {Name: "listen type name port=9030 host=", Hand: func(m *ice.Message, arg ...string) {
|
||||
_server_listen(m, arg...)
|
||||
switch m.Option(mdb.TYPE) {
|
||||
case UDP4:
|
||||
_server_udp(m, arg...)
|
||||
default:
|
||||
_server_listen(m, arg...)
|
||||
}
|
||||
}},
|
||||
}, mdb.StatusHashAction(mdb.FIELD, "time,hash,status,type,name,host,port,error,nconn"), mdb.ClearHashOnExitAction())},
|
||||
}, mdb.StatusHashAction(mdb.FIELD, "time,hash,status,type,name,host,port,error"), mdb.ClearOnExitHashAction())},
|
||||
})
|
||||
}
|
||||
|
@ -1,9 +1,14 @@
|
||||
package tcp
|
||||
|
||||
import ice "shylinux.com/x/icebergs"
|
||||
import (
|
||||
ice "shylinux.com/x/icebergs"
|
||||
kit "shylinux.com/x/toolkits"
|
||||
)
|
||||
|
||||
const TCP = "tcp"
|
||||
|
||||
var Index = &ice.Context{Name: TCP, Help: "通信模块"}
|
||||
|
||||
func init() { ice.Index.Register(Index, nil, HOST, PORT, CLIENT, SERVER) }
|
||||
func init() { ice.Index.Register(Index, nil, WIFI, HOST, PORT, CLIENT, SERVER) }
|
||||
|
||||
func Prefix(arg ...ice.Any) string { return kit.Keys(TCP, kit.Keys(arg...)) }
|
||||
|
47
base/tcp/wifi.go
Normal file
47
base/tcp/wifi.go
Normal file
@ -0,0 +1,47 @@
|
||||
package tcp
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
ice "shylinux.com/x/icebergs"
|
||||
"shylinux.com/x/icebergs/base/aaa"
|
||||
"shylinux.com/x/icebergs/base/mdb"
|
||||
kit "shylinux.com/x/toolkits"
|
||||
)
|
||||
|
||||
const (
|
||||
SSID = "ssid"
|
||||
)
|
||||
const WIFI = "wifi"
|
||||
|
||||
func init() {
|
||||
const (
|
||||
NETWORKSETUP = "networksetup"
|
||||
CONNECT = "connect"
|
||||
)
|
||||
Index.MergeCommands(ice.Commands{
|
||||
WIFI: {Help: "无线", Icon: "AirPort Utility.png", Actions: ice.MergeActions(ice.Actions{
|
||||
mdb.INPUTS: {Hand: func(m *ice.Message, arg ...string) {
|
||||
switch arg[0] {
|
||||
case SSID:
|
||||
kit.For(kit.Slice(kit.SplitLine(m.System(NETWORKSETUP, "-listpreferredwirelessnetworks", "en0").Result()), 1), func(name string) {
|
||||
m.Push(arg[0], strings.TrimSpace(name))
|
||||
})
|
||||
}
|
||||
}},
|
||||
CONNECT: {Help: "连接", Hand: func(m *ice.Message, arg ...string) {
|
||||
m.ToastProcess()
|
||||
msg := mdb.HashSelect(m.Spawn(), m.Option(SSID, strings.TrimSpace(m.Option(SSID))))
|
||||
if res := m.System(NETWORKSETUP, "-setairportnetwork", "en0", kit.Select(m.Option(SSID), msg.Append(SSID)), msg.Append(aaa.PASSWORD)); res.Result() != "" {
|
||||
m.Echo(res.Result()).ToastFailure(res.Result())
|
||||
} else {
|
||||
m.ProcessHold()
|
||||
}
|
||||
}},
|
||||
}, mdb.ExportHashAction(mdb.SHORT, SSID, mdb.FIELD, "time,ssid,password")), Hand: func(m *ice.Message, arg ...string) {
|
||||
if mdb.HashSelect(m, arg...).PushAction(CONNECT, mdb.REMOVE); len(arg) > 0 {
|
||||
m.EchoQRCode(kit.Format("WIFI:T:WPA;S:%s;P:%s;H:false;;", m.Append(SSID), m.Append(aaa.PASSWORD)))
|
||||
}
|
||||
}},
|
||||
})
|
||||
}
|
67
base/web/admin.go
Normal file
67
base/web/admin.go
Normal file
@ -0,0 +1,67 @@
|
||||
package web
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
ice "shylinux.com/x/icebergs"
|
||||
"shylinux.com/x/icebergs/base/aaa"
|
||||
"shylinux.com/x/icebergs/base/cli"
|
||||
"shylinux.com/x/icebergs/base/mdb"
|
||||
"shylinux.com/x/icebergs/base/nfs"
|
||||
"shylinux.com/x/icebergs/base/tcp"
|
||||
"shylinux.com/x/icebergs/base/web/html"
|
||||
kit "shylinux.com/x/toolkits"
|
||||
)
|
||||
|
||||
const ADMIN = "admin"
|
||||
|
||||
func init() {
|
||||
Index.MergeCommands(ice.Commands{
|
||||
ADMIN: {Name: "admin index list", Help: "后台", Role: aaa.VOID, Actions: ice.MergeActions(ice.Actions{
|
||||
DREAM_ACTION: {Hand: func(m *ice.Message, arg ...string) { DreamProcessIframe(m, arg...) }},
|
||||
}, DreamTablesAction()), Hand: func(m *ice.Message, arg ...string) {
|
||||
if m.Option(ice.MSG_SOURCE) != "" {
|
||||
RenderMain(m)
|
||||
} else {
|
||||
kit.If(len(arg) == 0, func() { arg = append(arg, SPACE, DOMAIN) })
|
||||
m.Cmd(SPIDE, mdb.CREATE, HostPort(m, tcp.LOCALHOST, kit.GetValid(
|
||||
func() string { return m.Cmdx(nfs.CAT, ice.VAR_LOG_ICE_PORT) },
|
||||
func() string { return m.Cmdx(nfs.CAT, kit.Path(os.Args[0], "../", ice.VAR_LOG_ICE_PORT)) },
|
||||
func() string { return m.Cmdx(nfs.CAT, kit.Path(os.Args[0], "../../", ice.VAR_LOG_ICE_PORT)) },
|
||||
func() string { return tcp.PORT_9020 },
|
||||
)), ice.OPS)
|
||||
args := []string{}
|
||||
for i := range arg {
|
||||
if arg[i] == "--" {
|
||||
arg, args = arg[:i], arg[i+1:]
|
||||
break
|
||||
}
|
||||
}
|
||||
kit.If(os.Getenv(cli.CTX_OPS), func(p string) { m.Optionv(SPIDE_HEADER, html.XHost, p) })
|
||||
m.Cmdy(SPIDE, ice.OPS, SPIDE_RAW, http.MethodPost, C(arg...), cli.PWD, kit.Path(""), args)
|
||||
}
|
||||
}},
|
||||
})
|
||||
}
|
||||
func AdminCmd(m *ice.Message, cmd string, arg ...ice.Any) *ice.Message {
|
||||
if ice.Info.NodeType == WORKER {
|
||||
return m.Cmd(append([]ice.Any{SPACE, ice.OPS, cmd}, arg...)...)
|
||||
} else {
|
||||
return m.Cmd(append([]ice.Any{cmd}, arg...)...)
|
||||
}
|
||||
}
|
||||
func OpsCmd(m *ice.Message, cmd string, arg ...ice.Any) *ice.Message {
|
||||
if ice.Info.NodeType == WORKER {
|
||||
return m.Cmd(append([]ice.Any{SPACE, ice.OPS, cmd}, arg...)...)
|
||||
} else {
|
||||
return m.Cmd(append([]ice.Any{cmd}, arg...)...)
|
||||
}
|
||||
}
|
||||
func DevCmd(m *ice.Message, cmd string, arg ...ice.Any) *ice.Message {
|
||||
if ice.Info.NodeType == WORKER {
|
||||
return m.Cmd(append([]ice.Any{SPACE, ice.OPS, SPACE, ice.DEV, cmd}, arg...)...)
|
||||
} else {
|
||||
return m.Cmd(append([]ice.Any{SPACE, ice.DEV, cmd}, arg...)...)
|
||||
}
|
||||
}
|
52
base/web/basic.go
Normal file
52
base/web/basic.go
Normal file
@ -0,0 +1,52 @@
|
||||
package web
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"strings"
|
||||
|
||||
ice "shylinux.com/x/icebergs"
|
||||
"shylinux.com/x/icebergs/base/aaa"
|
||||
"shylinux.com/x/icebergs/base/mdb"
|
||||
"shylinux.com/x/icebergs/base/nfs"
|
||||
"shylinux.com/x/icebergs/base/web/html"
|
||||
kit "shylinux.com/x/toolkits"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Index.MergeCommands(ice.Commands{
|
||||
ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) { aaa.White(m, "basic") }},
|
||||
"/basic/check": {Hand: func(m *ice.Message, arg ...string) {
|
||||
kit.For(m.R.Header, func(key string, value []string) { m.Debug("what %v %v", key, value) })
|
||||
if BasicSess(m); m.Option(ice.MSG_USERNAME) == "" {
|
||||
BasicCheck(m, "请输入账号密码")
|
||||
}
|
||||
}},
|
||||
"/basic/login": {Hand: func(m *ice.Message, arg ...string) { RenderMain(m) }},
|
||||
"/basic/auths": {Hand: func(m *ice.Message, arg ...string) {
|
||||
kit.If(m.R.URL.Query().Get(ice.MSG_SESSID), func(p string) { RenderCookie(m, m.Option(ice.MSG_SESSID, p)) })
|
||||
RenderRedirect(m, kit.Select(nfs.PS, m.R.URL.Query().Get("redirect_uri")))
|
||||
}},
|
||||
})
|
||||
}
|
||||
func BasicSess(m *ice.Message) {
|
||||
m.Options(ice.MSG_USERWEB, _serve_domain(m))
|
||||
m.Options(ice.MSG_SESSID, kit.Select(m.Option(ice.MSG_SESSID), m.Option(CookieName(m.Option(ice.MSG_USERWEB)))))
|
||||
aaa.SessCheck(m, m.Option(ice.MSG_SESSID))
|
||||
}
|
||||
func BasicCheck(m *ice.Message, realm string, check ...func(*ice.Message) bool) bool {
|
||||
switch ls := kit.Split(m.R.Header.Get(html.Authorization)); kit.Select("", ls, 0) {
|
||||
case html.Basic:
|
||||
if buf, err := base64.StdEncoding.DecodeString(kit.Select("", ls, 1)); !m.WarnNotValid(err) {
|
||||
if ls := strings.SplitN(string(buf), ":", 2); !m.WarnNotValid(len(ls) < 2 || ls[1] == "", html.Basic) {
|
||||
if msg := m.Cmd(TOKEN, ls[1]); !m.WarnNotValid(msg.Time() > msg.Append(mdb.TIME)) {
|
||||
if len(check) == 0 || check[0](msg) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
m.W.Header().Add("WWW-Authenticate", kit.Format(`Basic realm="%s"`, realm))
|
||||
m.RenderStatusUnauthorized()
|
||||
return false
|
||||
}
|
@ -2,68 +2,88 @@ package web
|
||||
|
||||
import (
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
ice "shylinux.com/x/icebergs"
|
||||
"shylinux.com/x/icebergs/base/aaa"
|
||||
"shylinux.com/x/icebergs/base/ctx"
|
||||
"shylinux.com/x/icebergs/base/cli"
|
||||
"shylinux.com/x/icebergs/base/gdb"
|
||||
"shylinux.com/x/icebergs/base/mdb"
|
||||
"shylinux.com/x/icebergs/base/nfs"
|
||||
"shylinux.com/x/icebergs/base/tcp"
|
||||
kit "shylinux.com/x/toolkits"
|
||||
"shylinux.com/x/toolkits/logs"
|
||||
)
|
||||
|
||||
func _broad_addr(m *ice.Message, host, port string) *net.UDPAddr {
|
||||
if addr, e := net.ResolveUDPAddr("udp4", kit.Format("%s:%s", host, port)); !m.Warn(e, ice.ErrNotValid, host, port, logs.FileLineMeta(2)) {
|
||||
return addr
|
||||
}
|
||||
return nil
|
||||
func _broad_send(m *ice.Message, to_host, to_port string, host, port string, arg ...string) {
|
||||
m.Cmd(tcp.CLIENT, tcp.DIAL, mdb.TYPE, tcp.UDP4, tcp.HOST, to_host, tcp.PORT, kit.Select(tcp.PORT_9020, to_port), func(s *net.UDPConn) {
|
||||
msg := m.Spawn(kit.Dict(tcp.HOST, host, tcp.PORT, port, arg))
|
||||
msg.Logs(tcp.SEND, BROAD, msg.FormatsMeta(nil), nfs.TO, tcp.HostPort(to_host, to_port)).FormatsMeta(s)
|
||||
})
|
||||
}
|
||||
func _broad_send(m *ice.Message, host, port string, remote_host, remote_port string) {
|
||||
if s, e := net.DialUDP("udp4", nil, _broad_addr(m, remote_host, remote_port)); !m.Warn(e, ice.ErrNotValid) {
|
||||
defer s.Close()
|
||||
msg := m.Spawn(kit.Dict(tcp.HOST, host, tcp.PORT, port))
|
||||
m.Logs(mdb.EXPORT, BROAD, msg.FormatMeta(), "to", remote_host+ice.DF+remote_port)
|
||||
s.Write([]byte(msg.FormatMeta()))
|
||||
func _broad_serve(m *ice.Message) {
|
||||
if m.Cmd(tcp.HOST).Length() == 0 {
|
||||
return
|
||||
}
|
||||
}
|
||||
func _broad_serve(m *ice.Message, host, port string) {
|
||||
_broad_send(m, host, port, "255.255.255.255", "9020")
|
||||
if s, e := net.ListenUDP("udp4", _broad_addr(m, "0.0.0.0", port)); m.Assert(e) {
|
||||
defer s.Close()
|
||||
defer mdb.HashCreateDeferRemove(m, tcp.HOST, host, tcp.PORT, port, kit.Dict(mdb.TARGET, s))()
|
||||
buf := make([]byte, ice.MOD_BUFS)
|
||||
for {
|
||||
n, from, e := s.ReadFromUDP(buf[:])
|
||||
if e != nil {
|
||||
break
|
||||
}
|
||||
m.Logs(mdb.IMPORT, BROAD, string(buf[:n]), "from", from)
|
||||
msg := m.Spawn(buf[:n])
|
||||
if m.Cmd(BROAD, kit.Format("%s,%s", msg.Option(tcp.HOST), msg.Option(tcp.PORT))).Length() > 0 {
|
||||
continue
|
||||
}
|
||||
if remote := _broad_addr(m, msg.Option(tcp.HOST), msg.Option(tcp.PORT)); remote != nil {
|
||||
m.Cmd(BROAD, func(value ice.Maps) {
|
||||
m.Logs(mdb.EXPORT, BROAD, kit.Format(value), "to", kit.Format(remote))
|
||||
s.WriteToUDP([]byte(m.Spawn(value).FormatMeta()), remote)
|
||||
})
|
||||
mdb.HashCreate(m, msg.OptionSimple(tcp.HOST, tcp.PORT))
|
||||
}
|
||||
m.GoSleep300ms(func() {
|
||||
m.Cmd(tcp.HOST, func(value ice.Maps) {
|
||||
_broad_send(m, "", "", value[aaa.IP], m.Option(tcp.PORT), kit.Simple(gdb.EVENT, tcp.LISTEN, mdb.NAME, ice.Info.NodeName, mdb.TYPE, ice.Info.NodeType, mdb.TIME, m.Time(), cli.SimpleMake())...)
|
||||
})
|
||||
})
|
||||
m.Cmd(tcp.SERVER, tcp.LISTEN, mdb.TYPE, tcp.UDP4, mdb.NAME, logs.FileLine(1), m.OptionSimple(tcp.HOST, tcp.PORT), func(from *net.UDPAddr, buf []byte) {
|
||||
if m.WarnNotValid(len(buf) > 1024, "broad recv buf size too large") {
|
||||
return
|
||||
}
|
||||
}
|
||||
msg := m.Spawn(buf).Logs(tcp.RECV, BROAD, string(buf), nfs.FROM, from)
|
||||
if strings.HasPrefix(msg.Option(tcp.HOST), "169.254") {
|
||||
return
|
||||
}
|
||||
if m.Cmd(BROAD, mdb.CREATE, msg.OptionSimple(kit.Simple(msg.Optionv(ice.MSG_OPTION))...)); msg.Option(gdb.EVENT) == tcp.LISTEN {
|
||||
m.Cmds(BROAD, func(value ice.Maps) {
|
||||
_broad_send(m, msg.Option(tcp.HOST), msg.Option(tcp.PORT), value[tcp.HOST], value[tcp.PORT], kit.Simple(value)...)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const BROAD = "broad"
|
||||
|
||||
func init() {
|
||||
Index.MergeCommands(ice.Commands{
|
||||
BROAD: {Name: "broad hash auto", Help: "广播", Actions: ice.MergeActions(ice.Actions{
|
||||
SERVE: {Name: "serve port=9020", Hand: func(m *ice.Message, arg ...string) {
|
||||
_broad_serve(m, m.Cmd(tcp.HOST).Append(aaa.IP), m.Option(tcp.PORT))
|
||||
BROAD: {Help: "广播台", Icon: "Podcasts.png", Actions: ice.MergeActions(ice.Actions{
|
||||
SERVE_START: {Hand: func(m *ice.Message, arg ...string) { gdb.Go(m, _broad_serve) }},
|
||||
mdb.SEARCH: {Hand: func(m *ice.Message, arg ...string) {
|
||||
if mdb.IsSearchPreview(m, arg) {
|
||||
host, domain := m.Cmdv(tcp.HOST, aaa.IP), UserWeb(m).Hostname()
|
||||
m.Cmds("", func(value ice.Maps) {
|
||||
switch kit.If(value[tcp.HOST] == host, func() { value[tcp.HOST] = domain }); value[mdb.TYPE] {
|
||||
case "sshd":
|
||||
m.PushSearch(mdb.NAME, Script(m, "ssh -p %s %s@%s", value[tcp.PORT], m.Option(ice.MSG_USERNAME), value[tcp.HOST]), mdb.TEXT, HostPort(m, value[tcp.HOST], value[tcp.PORT]), value)
|
||||
default:
|
||||
m.PushSearch(mdb.TEXT, HostPort(m, value[tcp.HOST], value[tcp.PORT]), value)
|
||||
}
|
||||
})
|
||||
}
|
||||
}},
|
||||
SERVE: {Name: "serve port=9020 host", Hand: func(m *ice.Message, arg ...string) { gdb.Go(m, _broad_serve) }},
|
||||
ADMIN: {Hand: func(m *ice.Message, arg ...string) { broadOpen(m) }},
|
||||
DREAM: {Hand: func(m *ice.Message, arg ...string) { broadOpen(m) }},
|
||||
VIMER: {Hand: func(m *ice.Message, arg ...string) { broadOpen(m) }},
|
||||
SPIDE: {Name: "spide name type=repos", Icon: "bi bi-house-add", Hand: func(m *ice.Message, arg ...string) {
|
||||
m.Cmd(SPIDE, mdb.CREATE, HostPort(m, m.Option(tcp.HOST), m.Option(tcp.PORT)), m.Option(mdb.NAME))
|
||||
}},
|
||||
OPEN: {Hand: func(m *ice.Message, arg ...string) {
|
||||
ctx.ProcessOpen(m, kit.Format("http://%s:%s", m.Option(tcp.HOST), m.Option(tcp.PORT)))
|
||||
m.ProcessOpen(HostPort(m, m.Option(tcp.HOST), m.Option(tcp.PORT)))
|
||||
}},
|
||||
}, mdb.HashAction(mdb.SHORT, "host,port", mdb.FIELD, "time,hash,host,port", mdb.ACTION, OPEN), mdb.ClearHashOnExitAction())},
|
||||
tcp.SEND: {Hand: func(m *ice.Message, arg ...string) { _broad_send(m, "", "", "", "", arg...) }},
|
||||
}, gdb.EventsAction(SERVE_START), mdb.HashAction(mdb.SHORT, "host,port",
|
||||
mdb.FIELD, "time,hash,type,name,host,port,module,version,commitTime,compileTime,bootTime,kernel,arch",
|
||||
mdb.ACTION, "admin,dream,vimer,spide,open", mdb.SORT, "type,name,host,port"), mdb.ClearOnExitHashAction()), Hand: func(m *ice.Message, arg ...string) {
|
||||
mdb.HashSelect(m, arg...)
|
||||
m.StatusTimeCount("nodename", ice.Info.NodeName)
|
||||
}},
|
||||
})
|
||||
}
|
||||
func broadOpen(m *ice.Message) {
|
||||
m.ProcessOpen(HostPort(m, m.Option(mdb.NAME), m.Option(tcp.PORT)) + C(m.ActionKey()))
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
package web
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
@ -9,20 +8,22 @@ import (
|
||||
"strings"
|
||||
|
||||
ice "shylinux.com/x/icebergs"
|
||||
"shylinux.com/x/icebergs/base/ctx"
|
||||
"shylinux.com/x/icebergs/base/aaa"
|
||||
"shylinux.com/x/icebergs/base/mdb"
|
||||
"shylinux.com/x/icebergs/base/nfs"
|
||||
"shylinux.com/x/icebergs/base/tcp"
|
||||
"shylinux.com/x/icebergs/base/web/html"
|
||||
kit "shylinux.com/x/toolkits"
|
||||
"shylinux.com/x/toolkits/miss"
|
||||
)
|
||||
|
||||
func _cache_name(m *ice.Message, h string) string { return path.Join(ice.VAR_FILE, h[:2], h) }
|
||||
func _cache_mime(m *ice.Message, mime, name string) string {
|
||||
if mime == "application/octet-stream" {
|
||||
if mime == html.ApplicationOctet {
|
||||
if kit.ExtIsImage(name) {
|
||||
mime = "image/" + kit.Ext(name)
|
||||
mime = IMAGE + nfs.PS + kit.Ext(name)
|
||||
} else if kit.ExtIsVideo(name) {
|
||||
mime = "video/" + kit.Ext(name)
|
||||
mime = VIDEO + nfs.PS + kit.Ext(name)
|
||||
}
|
||||
} else if mime == "" {
|
||||
return kit.Ext(name)
|
||||
@ -30,10 +31,10 @@ func _cache_mime(m *ice.Message, mime, name string) string {
|
||||
return mime
|
||||
}
|
||||
func _cache_save(m *ice.Message, mime, name, text string, arg ...string) {
|
||||
if m.Warn(name == "", ice.ErrNotValid, mdb.NAME) {
|
||||
if m.WarnNotValid(name == "", mdb.NAME) {
|
||||
return
|
||||
} else if len(text) > 512 {
|
||||
p := m.Cmdx(nfs.SAVE, _cache_name(m, kit.Hashs(text)), text)
|
||||
p := m.Cmdx(nfs.SAVE, _cache_name(m, kit.Hashs(text)), kit.Dict(nfs.CONTENT, text))
|
||||
text, arg = p, kit.Simple(p, len(text))
|
||||
}
|
||||
file, size := kit.Select("", arg, 0), kit.Int(kit.Select(kit.Format(len(text)), arg, 1))
|
||||
@ -42,7 +43,7 @@ func _cache_save(m *ice.Message, mime, name, text string, arg ...string) {
|
||||
m.Push(mdb.TYPE, mime).Push(mdb.NAME, name).Push(mdb.TEXT, text).Push(nfs.FILE, file).Push(nfs.SIZE, size)
|
||||
}
|
||||
func _cache_watch(m *ice.Message, key, path string) {
|
||||
mdb.HashSelect(m.Spawn(), key).Tables(func(value ice.Maps) {
|
||||
mdb.HashSelect(m.Spawn(), key).Table(func(value ice.Maps) {
|
||||
if value[nfs.FILE] == "" {
|
||||
m.Cmdy(nfs.SAVE, path, value[mdb.TEXT])
|
||||
} else {
|
||||
@ -57,35 +58,41 @@ func _cache_catch(m *ice.Message, path string) (file string, size string) {
|
||||
return "", "0"
|
||||
}
|
||||
func _cache_upload(m *ice.Message, r *http.Request) (mime, name, file, size string) {
|
||||
if b, h, e := r.FormFile(UPLOAD); !m.Warn(e, ice.ErrNotValid, UPLOAD) {
|
||||
if b, h, e := r.FormFile(UPLOAD); !m.WarnNotValid(e, UPLOAD) {
|
||||
defer b.Close()
|
||||
if f, p, e := miss.CreateFile(_cache_name(m, kit.Hashs(b))); !m.Warn(e, ice.ErrNotValid, UPLOAD) {
|
||||
if f, p, e := miss.CreateFile(_cache_name(m, kit.Hashs(b))); !m.WarnNotValid(e, UPLOAD) {
|
||||
defer f.Close()
|
||||
b.Seek(0, os.SEEK_SET)
|
||||
if n, e := io.Copy(f, b); !m.Warn(e, ice.ErrNotValid, UPLOAD) {
|
||||
m.Logs(mdb.IMPORT, nfs.FILE, p, nfs.SIZE, kit.FmtSize(int64(n)))
|
||||
return h.Header.Get(ContentType), h.Filename, p, kit.Format(n)
|
||||
if n, e := io.Copy(f, b); !m.WarnNotValid(e, UPLOAD) {
|
||||
m.Logs(nfs.SAVE, nfs.FILE, p, nfs.SIZE, kit.FmtSize(int64(n)))
|
||||
return h.Header.Get(html.ContentType), h.Filename, p, kit.Format(n)
|
||||
}
|
||||
}
|
||||
}
|
||||
return "", "", "", "0"
|
||||
}
|
||||
func _cache_download(m *ice.Message, r *http.Response, file string, cb ice.Any) string {
|
||||
if f, p, e := miss.CreateFile(file); !m.Warn(e, ice.ErrNotValid, DOWNLOAD) {
|
||||
m.Option(ice.MSG_USERROLE, aaa.TECH)
|
||||
if f, p, e := miss.CreateFile(file); !m.WarnNotValid(e, DOWNLOAD) {
|
||||
defer func() {
|
||||
if s, e := os.Stat(file); e == nil && s.Size() == 0 {
|
||||
nfs.Remove(m, file)
|
||||
}
|
||||
}()
|
||||
defer f.Close()
|
||||
last, base := 0, 10
|
||||
nfs.CopyFile(m, f, r.Body, base*ice.MOD_BUFS, kit.Int(kit.Select("100", r.Header.Get(ContentLength))), func(count, total, step int) {
|
||||
if step/base != last {
|
||||
m.Logs(mdb.EXPORT, nfs.FILE, p, mdb.COUNT, count, mdb.TOTAL, total, mdb.VALUE, step)
|
||||
switch cb := cb.(type) {
|
||||
case func(int, int, int):
|
||||
cb(count, total, step)
|
||||
case nil:
|
||||
default:
|
||||
m.ErrorNotImplement(cb)
|
||||
}
|
||||
nfs.CopyStream(m, f, r.Body, base*ice.MOD_BUFS, kit.Int(kit.Select("100", r.Header.Get(html.ContentLength))), func(count, total, value int) {
|
||||
if value/base == last {
|
||||
return
|
||||
}
|
||||
last = value / base
|
||||
switch m.Logs(nfs.SAVE, nfs.FILE, p, mdb.COUNT, kit.FmtSize(int64(count)), mdb.TOTAL, kit.FmtSize(int64(total)), mdb.VALUE, value); cb := cb.(type) {
|
||||
case func(int, int, int):
|
||||
kit.If(cb != nil, func() { cb(count, total, value) })
|
||||
case nil:
|
||||
default:
|
||||
m.ErrorNotImplement(cb)
|
||||
}
|
||||
last = step / base
|
||||
})
|
||||
return p
|
||||
}
|
||||
@ -98,78 +105,126 @@ const (
|
||||
WRITE = "write"
|
||||
UPLOAD = "upload"
|
||||
DOWNLOAD = "download"
|
||||
DISPLAY = "display"
|
||||
PREVIEW = "preview"
|
||||
PAGES = "pages"
|
||||
|
||||
IMAGE = "image"
|
||||
VIDEO = "video"
|
||||
)
|
||||
const CACHE = "cache"
|
||||
|
||||
func init() {
|
||||
Index.MergeCommands(ice.Commands{
|
||||
CACHE: {Name: "cache hash auto write catch upload", Help: "缓存池", Actions: ice.MergeActions(ice.Actions{
|
||||
WATCH: {Name: "watch hash* path*", Help: "释放", Hand: func(m *ice.Message, arg ...string) {
|
||||
_cache_watch(m, m.Option(mdb.HASH), m.Option(nfs.PATH))
|
||||
CACHE: {Name: "cache hash auto upload", Help: "缓存池", Actions: ice.MergeActions(ice.Actions{
|
||||
ice.RENDER_DOWNLOAD: {Hand: func(m *ice.Message, arg ...string) {
|
||||
m.Echo(_share_link(m, kit.Select(arg[0], arg, 1), ice.POD, m.Option(ice.MSG_USERPOD), nfs.FILENAME, kit.Select("", arg[0], len(arg) > 1)))
|
||||
}},
|
||||
WRITE: {Name: "write type name* text*", Help: "创建", Hand: func(m *ice.Message, arg ...string) {
|
||||
WRITE: {Name: "write type name* text*", Help: "添加", Hand: func(m *ice.Message, arg ...string) {
|
||||
_cache_save(m, m.Option(mdb.TYPE), m.Option(mdb.NAME), m.Option(mdb.TEXT))
|
||||
}},
|
||||
CATCH: {Name: "catch path* type", Help: "添加", Hand: func(m *ice.Message, arg ...string) {
|
||||
CATCH: {Name: "catch path* type", Help: "导入", Hand: func(m *ice.Message, arg ...string) {
|
||||
file, size := _cache_catch(m, m.Option(nfs.PATH))
|
||||
_cache_save(m, m.Option(mdb.TYPE), m.Option(nfs.PATH), "", file, size)
|
||||
}},
|
||||
WATCH: {Name: "watch hash* path*", Help: "导出", Hand: func(m *ice.Message, arg ...string) {
|
||||
_cache_watch(m, m.Option(mdb.HASH), m.Option(nfs.PATH))
|
||||
}},
|
||||
UPLOAD: {Hand: func(m *ice.Message, arg ...string) {
|
||||
mime, name, file, size := _cache_upload(m, m.R)
|
||||
_cache_save(m, mime, name, "", file, size)
|
||||
}},
|
||||
DOWNLOAD: {Name: "download type name*", Hand: func(m *ice.Message, arg ...string) {
|
||||
if r, ok := m.Optionv(RESPONSE).(*http.Response); !m.Warn(!ok, ice.ErrNotValid, RESPONSE) {
|
||||
file, size := _cache_catch(m, _cache_download(m, r, path.Join(ice.VAR_TMP, kit.Hashs(mdb.UNIQ)), m.OptionCB("")))
|
||||
_cache_save(m, m.Option(mdb.TYPE), m.Option(mdb.NAME), "", file, size)
|
||||
if res, ok := m.Optionv(RESPONSE).(*http.Response); !m.WarnNotValid(!ok, RESPONSE) {
|
||||
nfs.Temp(m, func(p string) {
|
||||
file, size := _cache_catch(m, _cache_download(m, res, p, m.OptionCB("")))
|
||||
_cache_save(m, m.Option(mdb.TYPE), m.Option(mdb.NAME), "", file, size)
|
||||
})
|
||||
}
|
||||
}},
|
||||
ice.RENDER_DOWNLOAD: {Hand: func(m *ice.Message, arg ...string) {
|
||||
p := kit.Select(arg[0], arg, 1)
|
||||
p = kit.Select("", SHARE_LOCAL, !strings.HasPrefix(p, ice.PS) && !strings.HasPrefix(p, ice.HTTP)) + p
|
||||
args := []string{ice.POD, m.Option(ice.MSG_USERPOD), "filename", kit.Select("", arg[0], len(arg) > 1)}
|
||||
m.Echo(fmt.Sprintf(`<a href="%s" download="%s">%s</a>`, MergeURL2(m, p, args), path.Base(arg[0]), arg[0]))
|
||||
nfs.PS: {Hand: func(m *ice.Message, arg ...string) {
|
||||
if mdb.HashSelectDetail(m, arg[0], func(value ice.Map) {
|
||||
kit.If(kit.Format(value[nfs.FILE]), func() { m.RenderDownload(value[nfs.FILE]) }, func() { m.RenderResult(value[mdb.TEXT]) })
|
||||
}) {
|
||||
return
|
||||
}
|
||||
if pod := m.Option(ice.POD); pod != "" {
|
||||
msg := m.Options(ice.POD, "").Cmd(SPACE, pod, CACHE, arg[0])
|
||||
kit.If(kit.Format(msg.Append(nfs.FILE)), func() {
|
||||
m.RenderDownload(path.Join(ice.USR_LOCAL_WORK, pod, msg.Append(nfs.FILE)))
|
||||
}, func() { m.RenderResult(msg.Append(mdb.TEXT)) })
|
||||
}
|
||||
}},
|
||||
ice.PS: {Hand: func(m *ice.Message, arg ...string) {
|
||||
mdb.HashSelectDetail(m, arg[0], func(value ice.Map) {
|
||||
if kit.Format(value[nfs.FILE]) == "" {
|
||||
m.RenderResult(value[mdb.TEXT])
|
||||
} else {
|
||||
m.RenderDownload(value[nfs.FILE])
|
||||
}
|
||||
})
|
||||
}},
|
||||
}, mdb.HashAction(mdb.SHORT, mdb.TEXT, mdb.FIELD, "time,hash,size,type,name,text,file", ctx.ACTION, WATCH), ice.RenderAction(ice.RENDER_DOWNLOAD)), Hand: func(m *ice.Message, arg ...string) {
|
||||
if mdb.HashSelect(m, arg...); len(arg) == 0 || m.R.Method == http.MethodGet {
|
||||
}, mdb.HashAction(mdb.SHORT, mdb.TEXT, mdb.FIELD, "time,hash,size,type,name,text,file"), ice.RenderAction(ice.RENDER_DOWNLOAD)), Hand: func(m *ice.Message, arg ...string) {
|
||||
if mdb.HashSelect(m, arg...); len(arg) == 0 {
|
||||
return
|
||||
}
|
||||
if m.Append(nfs.FILE) == "" {
|
||||
if m.Length() == 0 {
|
||||
return
|
||||
} else if m.Append(nfs.FILE) == "" {
|
||||
m.PushScript(mdb.TEXT, m.Append(mdb.TEXT))
|
||||
} else {
|
||||
PushDisplay(m, m.Append(mdb.TYPE), m.Append(mdb.NAME), MergeURL2(m, SHARE_CACHE+arg[0]))
|
||||
PushDisplay(m, m.Append(mdb.TYPE), m.Append(mdb.NAME), m.MergeLink(P(SHARE, CACHE, arg[0])))
|
||||
}
|
||||
}},
|
||||
})
|
||||
ice.AddMerges(func(c *ice.Context, key string, cmd *ice.Command, sub string, action *ice.Action) (ice.Handler, ice.Handler) {
|
||||
ice.AddMergeAction(func(c *ice.Context, key string, cmd *ice.Command, sub string, action *ice.Action) {
|
||||
switch sub {
|
||||
case UPLOAD:
|
||||
if c.Name == WEB && key == CACHE {
|
||||
if kit.FileLines(action.Hand) == kit.FileLines(1) {
|
||||
break
|
||||
}
|
||||
watch := action.Hand == nil
|
||||
action.Hand = ice.MergeHand(func(m *ice.Message, arg ...string) {
|
||||
up := Upload(m)
|
||||
m.Assert(len(up) > 1)
|
||||
m.Cmd(CACHE, m.Option(ice.MSG_UPLOAD)).Tables(func(value ice.Maps) { m.Options(value) })
|
||||
if m.Options(mdb.HASH, up[0], mdb.NAME, up[1]); watch {
|
||||
m.Cmdy(CACHE, WATCH, m.Option(mdb.HASH), path.Join(m.Option(nfs.PATH), m.Option(mdb.NAME)))
|
||||
msg := m.Cmd(CACHE, m.Option(ice.MSG_UPLOAD))
|
||||
// if m.Cmd(CACHE, m.Option(ice.MSG_UPLOAD)).Table(func(value ice.Maps) { m.Options(value) }).Length() == 0 {
|
||||
if msg.Length() == 0 {
|
||||
SpideCache(m.Spawn(), m.MergeLink(SHARE_CACHE+up[0]))
|
||||
}
|
||||
// if m.Options(mdb.HASH, up[0], mdb.NAME, up[1]); watch {
|
||||
if watch {
|
||||
m.Cmdy(CACHE, WATCH, up[0], path.Join(msg.Append(nfs.PATH), up[1]))
|
||||
}
|
||||
}, action.Hand)
|
||||
}
|
||||
return nil, nil
|
||||
})
|
||||
ctx.Upload = Upload
|
||||
}
|
||||
func UploadSave(m *ice.Message, p string) string {
|
||||
up := kit.Simple(m.Optionv(ice.MSG_UPLOAD))
|
||||
kit.If(strings.HasSuffix(p, nfs.PS), func() { p = path.Join(p, up[1]) })
|
||||
m.Cmd(CACHE, WATCH, up[0], p)
|
||||
return p
|
||||
}
|
||||
func Upload(m *ice.Message) []string {
|
||||
if up := kit.Simple(m.Optionv(ice.MSG_UPLOAD)); len(up) == 1 {
|
||||
msg := m.Cmd(CACHE, UPLOAD)
|
||||
if m.Optionv(ice.MSG_UPLOAD, kit.Simple(msg.Append(mdb.HASH), msg.Append(mdb.NAME), msg.Append(nfs.SIZE))); m.Option(ice.MSG_USERPOD) != "" {
|
||||
if nfs.Exists(m, nfs.USR_LOCAL_WORK+m.Option(ice.MSG_USERPOD)) {
|
||||
m.Cmd(nfs.LINK, path.Join(nfs.USR_LOCAL_WORK+m.Option(ice.MSG_USERPOD), msg.Append(nfs.FILE)), msg.Append(nfs.FILE))
|
||||
m.Cmd(SPACE, m.Option(ice.MSG_USERPOD), CACHE, mdb.CREATE, msg.AppendSimple(mdb.NAME, mdb.TEXT, nfs.FILE, nfs.SIZE))
|
||||
} else {
|
||||
m.Cmd(SPACE, m.Option(ice.MSG_USERPOD), SPIDE, ice.DEV, SPIDE_CACHE, http.MethodGet, tcp.PublishLocalhost(m, m.MergeLink(PP(SHARE, CACHE, msg.Append(mdb.HASH)))))
|
||||
}
|
||||
}
|
||||
return kit.Simple(m.Optionv(ice.MSG_UPLOAD))
|
||||
} else {
|
||||
return up
|
||||
}
|
||||
}
|
||||
func Download(m *ice.Message, link string, cb func(count, total, value int)) *ice.Message {
|
||||
return m.Cmdy(Prefix(SPIDE), ice.DEV, SPIDE_CACHE, http.MethodGet, link, cb)
|
||||
}
|
||||
func PushDisplay(m *ice.Message, mime, name, link string) {
|
||||
if html.IsImage(name, mime) {
|
||||
m.PushImages(nfs.FILE, link)
|
||||
} else if html.IsVideo(name, mime) {
|
||||
m.PushVideos(nfs.FILE, link)
|
||||
} else if html.IsAudio(name, mime) {
|
||||
m.PushAudios(nfs.FILE, link)
|
||||
} else {
|
||||
m.PushDownload(nfs.FILE, name, link)
|
||||
}
|
||||
}
|
||||
func RenderCache(m *ice.Message, h string) {
|
||||
if msg := m.Cmd(CACHE, h); msg.Append(nfs.FILE) == "" {
|
||||
@ -178,25 +233,32 @@ func RenderCache(m *ice.Message, h string) {
|
||||
m.RenderDownload(msg.Append(mdb.FILE), msg.Append(mdb.TYPE), msg.Append(mdb.NAME))
|
||||
}
|
||||
}
|
||||
func Upload(m *ice.Message) []string {
|
||||
if up := kit.Simple(m.Optionv(ice.MSG_UPLOAD)); len(up) == 1 {
|
||||
if m.Cmdy(CACHE, UPLOAD).Optionv(ice.MSG_UPLOAD, kit.Simple(m.Append(mdb.HASH), m.Append(mdb.NAME), m.Append(nfs.SIZE))); m.Option(ice.MSG_USERPOD) != "" {
|
||||
m.Cmd(SPACE, m.Option(ice.MSG_USERPOD), SPIDE, ice.DEV, SPIDE_CACHE, http.MethodGet, MergeURL2(m, path.Join(SHARE_CACHE, m.Append(mdb.HASH))))
|
||||
}
|
||||
return kit.Simple(m.Optionv(ice.MSG_UPLOAD))
|
||||
} else {
|
||||
return up
|
||||
}
|
||||
}
|
||||
func Download(m *ice.Message, link string, cb func(count, total, value int)) *ice.Message {
|
||||
return m.Cmdy("web.spide", ice.DEV, SPIDE_CACHE, http.MethodGet, link, cb)
|
||||
}
|
||||
func PushDisplay(m *ice.Message, mime, name, link string) {
|
||||
if strings.HasPrefix(mime, "image/") || kit.ExtIsImage(name) {
|
||||
m.PushImages(nfs.FILE, link)
|
||||
} else if strings.HasPrefix(mime, "video/") || kit.ExtIsImage(name) {
|
||||
m.PushVideos(nfs.FILE, link)
|
||||
} else {
|
||||
m.PushDownload(nfs.FILE, name, link)
|
||||
func ExportCacheAction(field string) ice.Actions {
|
||||
return ice.Actions{
|
||||
ice.CTX_EXIT: {Hand: func(m *ice.Message, arg ...string) {
|
||||
mdb.HashSelect(m.Spawn(kit.Dict(ice.MSG_FIELDS, field))).Table(func(value ice.Maps) {
|
||||
kit.For(kit.Split(value[field]), func(h string) {
|
||||
msg := m.Cmd(CACHE, h)
|
||||
m.Cmd(nfs.LINK, kit.Keys(path.Join(ice.USR_LOCAL_EXPORT, m.PrefixKey(), field, h), kit.Select("", kit.Split(msg.Append(mdb.TYPE), nfs.PS), -1)), msg.Append(nfs.FILE))
|
||||
})
|
||||
})
|
||||
}},
|
||||
ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) {
|
||||
list := map[string]string{}
|
||||
m.Cmd(nfs.DIR, path.Join(ice.USR_LOCAL_EXPORT, m.PrefixKey(), field), func(value ice.Maps) {
|
||||
list[kit.TrimExt(value[nfs.PATH])] = m.Cmd(CACHE, CATCH, value[nfs.PATH]).Append(mdb.HASH)
|
||||
})
|
||||
mdb.HashSelectUpdate(m, "", func(value ice.Map) {
|
||||
value[field] = kit.Join(kit.Simple(kit.For(kit.Split(kit.Format(value[field])), func(p string) string { return kit.Select(p, list[p]) })))
|
||||
})
|
||||
}},
|
||||
UPLOAD: {Hand: func(m *ice.Message, arg ...string) {
|
||||
nfs.Temp(m, func(p string) {
|
||||
msg := m.Cmd(CACHE, Upload(m)[0])
|
||||
if os.Link(msg.Append(nfs.FILE), p); nfs.ImageResize(m, p, 390, 390) {
|
||||
m.Echo(m.Cmd(CACHE, CATCH, p, msg.Append(mdb.TYPE)).Append(mdb.HASH))
|
||||
}
|
||||
})
|
||||
}},
|
||||
}
|
||||
}
|
||||
|
114
base/web/count.go
Normal file
114
base/web/count.go
Normal file
@ -0,0 +1,114 @@
|
||||
package web
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
ice "shylinux.com/x/icebergs"
|
||||
"shylinux.com/x/icebergs/base/aaa"
|
||||
"shylinux.com/x/icebergs/base/mdb"
|
||||
"shylinux.com/x/icebergs/base/web/html"
|
||||
kit "shylinux.com/x/toolkits"
|
||||
)
|
||||
|
||||
func _count_stat(m *ice.Message, arg ...string) map[string]int {
|
||||
stat := map[string]int{}
|
||||
m.Table(func(value ice.Maps) {
|
||||
count := kit.Int(value[mdb.COUNT])
|
||||
stat[mdb.TOTAL] += count
|
||||
for _, agent := range []string{"美国", "电信", "联通", "移动", "阿里云", "腾讯云"} {
|
||||
if strings.Contains(value[aaa.LOCATION], agent) {
|
||||
stat[agent] += count
|
||||
break
|
||||
}
|
||||
}
|
||||
for _, agent := range []string{"GoModuleMirror", "Go-http-client", "git", "compatible"} {
|
||||
if strings.Contains(value[mdb.TEXT], agent) {
|
||||
stat[agent] += count
|
||||
return
|
||||
}
|
||||
}
|
||||
for _, agent := range html.AgentList {
|
||||
if strings.Contains(value[mdb.TEXT], agent) {
|
||||
stat[agent] += count
|
||||
break
|
||||
}
|
||||
}
|
||||
for _, agent := range html.SystemList {
|
||||
if strings.Contains(value[mdb.TEXT], agent) {
|
||||
stat[agent] += count
|
||||
break
|
||||
}
|
||||
}
|
||||
})
|
||||
return stat
|
||||
}
|
||||
|
||||
const COUNT = "count"
|
||||
|
||||
func init() {
|
||||
Index.MergeCommands(ice.Commands{
|
||||
COUNT: &ice.Command{Name: "count hash auto group valid location", Help: "计数器", Meta: kit.Dict(
|
||||
ice.CTX_TRANS, kit.Dict(html.INPUT, kit.Dict(aaa.LOCATION, "地理位置")),
|
||||
), Actions: ice.MergeActions(ice.Actions{
|
||||
mdb.CREATE: {Name: "create type name text", Hand: func(m *ice.Message, arg ...string) {
|
||||
mdb.HashSelectUpdate(m, mdb.HashCreate(m), func(value ice.Map) { value[mdb.COUNT] = kit.Int(value[mdb.COUNT]) + 1 })
|
||||
// m.Cmd("count", mdb.CREATE, OFFER, m.Option(FROM), kit.Dict(ice.LOG_DISABLE, ice.TRUE))
|
||||
}},
|
||||
mdb.VALID: {Hand: func(m *ice.Message, arg ...string) {
|
||||
mdb.HashSelect(m.Spawn(), arg...).Table(func(value ice.Maps) {
|
||||
if !strings.HasPrefix(value[mdb.TEXT], html.Mozilla) {
|
||||
return
|
||||
} else if count := kit.Int(value[mdb.COUNT]); count < 1 {
|
||||
return
|
||||
} else {
|
||||
m.Push("", value, kit.Split(mdb.Config(m, mdb.FIELD)))
|
||||
}
|
||||
})
|
||||
m.StatusTimeCount(_count_stat(m))
|
||||
}},
|
||||
mdb.GROUP: {Hand: func(m *ice.Message, arg ...string) {
|
||||
count := map[string]int{}
|
||||
list := map[string]map[string]string{}
|
||||
m.Cmd("", mdb.VALID).Table(func(value ice.Maps) {
|
||||
count[value[aaa.LOCATION]] += kit.Int(value[mdb.COUNT])
|
||||
list[value[aaa.LOCATION]] = value
|
||||
})
|
||||
stat := map[string]int{}
|
||||
for _, v := range list {
|
||||
func() {
|
||||
for _, agent := range []string{"美国", "电信", "联通", "移动", "阿里云", "腾讯云", "北京市", "香港"} {
|
||||
if strings.Contains(v[aaa.LOCATION], agent) {
|
||||
stat[agent] += kit.Int(v[mdb.COUNT])
|
||||
return
|
||||
}
|
||||
}
|
||||
m.Push("", v, kit.Split(mdb.Config(m, mdb.FIELD)))
|
||||
}()
|
||||
}
|
||||
m.StatusTimeCount(stat)
|
||||
}},
|
||||
aaa.LOCATION: {Hand: func(m *ice.Message, arg ...string) {
|
||||
GoToast(mdb.HashSelects(m).Sort(mdb.COUNT, ice.INT_R), func(toast func(string, int, int)) []string {
|
||||
m.Table(func(value ice.Maps, index, total int) {
|
||||
if value[aaa.LOCATION] == "" {
|
||||
location := kit.Format(kit.Value(SpideGet(m, "http://opendata.baidu.com/api.php?co=&resource_id=6006&oe=utf8", "query", value[mdb.NAME]), "data.0.location"))
|
||||
mdb.HashModify(m, mdb.HASH, value[mdb.HASH], aaa.LOCATION, location)
|
||||
toast(kit.Select(value[mdb.NAME], location), index, total)
|
||||
m.Sleep300ms()
|
||||
}
|
||||
})
|
||||
return nil
|
||||
})
|
||||
}},
|
||||
}, mdb.HashAction(mdb.LIMIT, 1000, mdb.LEAST, 500, mdb.SHORT, "type,name", mdb.FIELD, "time,hash,count,location,type,name,text")), Hand: func(m *ice.Message, arg ...string) {
|
||||
mdb.HashSelect(m, arg...).Sort(mdb.TIME, ice.STR_R).StatusTimeCount(_count_stat(m))
|
||||
}},
|
||||
})
|
||||
}
|
||||
|
||||
func Count(m *ice.Message, arg ...string) *ice.Message {
|
||||
kit.If(len(arg) > 0 && arg[0] == "", func() { arg[0] = m.ShortKey() })
|
||||
kit.If(len(arg) > 1 && arg[1] == "", func() { arg[1] = m.ActionKey() })
|
||||
m.Cmd(COUNT, mdb.CREATE, arg, kit.Dict(ice.LOG_DISABLE, ice.TRUE))
|
||||
return m
|
||||
}
|
@ -3,149 +3,599 @@ package web
|
||||
import (
|
||||
"os"
|
||||
"path"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
ice "shylinux.com/x/icebergs"
|
||||
"shylinux.com/x/icebergs/base/aaa"
|
||||
"shylinux.com/x/icebergs/base/cli"
|
||||
"shylinux.com/x/icebergs/base/ctx"
|
||||
"shylinux.com/x/icebergs/base/gdb"
|
||||
"shylinux.com/x/icebergs/base/lex"
|
||||
"shylinux.com/x/icebergs/base/mdb"
|
||||
"shylinux.com/x/icebergs/base/nfs"
|
||||
"shylinux.com/x/icebergs/base/tcp"
|
||||
"shylinux.com/x/icebergs/base/web/html"
|
||||
kit "shylinux.com/x/toolkits"
|
||||
)
|
||||
|
||||
func _dream_list(m *ice.Message) *ice.Message {
|
||||
list := m.CmdMap(SPACE, mdb.NAME)
|
||||
m.Cmdy(nfs.DIR, ice.USR_LOCAL_WORK, "time,size,name").Tables(func(value ice.Maps) {
|
||||
mdb.HashSelects(m.Spawn()).Table(func(value ice.Maps, index int, head []string) {
|
||||
if value[aaa.ACCESS] == aaa.PRIVATE && (m.Option(ice.FROM_SPACE) != "" || !aaa.IsTechOrRoot(m)) {
|
||||
return
|
||||
}
|
||||
if space, ok := list[value[mdb.NAME]]; ok {
|
||||
msg := gdb.Event(m.Spawn(value, space), DREAM_TABLES).Copy(m.Spawn().PushButton(cli.STOP))
|
||||
m.Push(mdb.TYPE, space[mdb.TYPE])
|
||||
m.Push(cli.STATUS, cli.START)
|
||||
m.Push(mdb.TEXT, msg.Append(mdb.TEXT))
|
||||
m.PushButton(strings.Join(msg.Appendv(ctx.ACTION), ""))
|
||||
} else {
|
||||
m.Push(mdb.TYPE, WORKER)
|
||||
m.Push(cli.STATUS, cli.STOP)
|
||||
m.Push(mdb.TEXT, "")
|
||||
m.PushButton(cli.START, nfs.TRASH)
|
||||
value[ice.MAIN] = space[ice.MAIN]
|
||||
value[mdb.ICONS] = space[mdb.ICONS]
|
||||
m.Push("", value, kit.Slice(head, 0, -1))
|
||||
m.Push(mdb.TYPE, space[mdb.TYPE]).Push(cli.STATUS, cli.START)
|
||||
m.Push(nfs.MODULE, space[nfs.MODULE]).Push(nfs.VERSION, space[nfs.VERSION])
|
||||
button := []ice.Any{PORTAL, DESKTOP, ADMIN, WORD}
|
||||
text := space[nfs.MODULE]
|
||||
kit.If(m.Option(ice.DREAM_SIMPLE) != ice.TRUE && aaa.IsTechOrRoot(m), func() {
|
||||
kit.If(m.IsDebug(), func() {
|
||||
button = append(button, VIMER, STATUS, COMPILE, cli.RUNTIME, XTERM)
|
||||
text += "\n" + DreamStat(m, value[mdb.NAME])
|
||||
})
|
||||
button = append(button, "settings", cli.STOP)
|
||||
})
|
||||
m.Push(mdb.TEXT, text)
|
||||
m.PushButton(append(button, OPEN)...)
|
||||
} else if aaa.IsTechOrRoot(m) {
|
||||
m.Push("", value, kit.Slice(head, 0, -1))
|
||||
m.Push(nfs.MODULE, "").Push(nfs.VERSION, "").Push(mdb.TEXT, "")
|
||||
if m.Push(mdb.TYPE, WORKER); nfs.Exists(m, path.Join(ice.USR_LOCAL_WORK, value[mdb.NAME])) {
|
||||
m.Push(cli.STATUS, cli.STOP).PushButton(cli.START, nfs.TRASH)
|
||||
} else {
|
||||
m.Push(cli.STATUS, cli.BEGIN).PushButton(cli.START, mdb.REMOVE)
|
||||
}
|
||||
}
|
||||
})
|
||||
return m.Sort("status,type,name", ice.STR, ice.STR, ice.STR_R).StatusTimeCount(cli.START, len(list))
|
||||
m.RewriteAppend(func(value, key string, index int) string {
|
||||
if key == mdb.TIME {
|
||||
if space, ok := list[m.Appendv(mdb.NAME)[index]]; ok {
|
||||
return space[mdb.TIME]
|
||||
}
|
||||
} else if key == mdb.ICONS {
|
||||
if kit.HasPrefix(value, HTTP, nfs.PS) {
|
||||
return value
|
||||
} else if nfs.ExistsFile(m, path.Join(ice.USR_LOCAL_WORK, m.Appendv(mdb.NAME)[index], value)) {
|
||||
return m.Spawn(kit.Dict(ice.MSG_USERPOD, m.Appendv(mdb.NAME)[index])).FileURI(value)
|
||||
} else if nfs.ExistsFile(m, value) {
|
||||
return m.FileURI(value)
|
||||
}
|
||||
}
|
||||
return value
|
||||
})
|
||||
return m
|
||||
}
|
||||
func _dream_show(m *ice.Message, name string) {
|
||||
if m.Warn(name == "", ice.ErrNotValid, mdb.NAME) {
|
||||
func _dream_list_more(m *ice.Message) *ice.Message {
|
||||
field := kit.Split(mdb.Config(m, mdb.FIELD) + ",type,status,module,version,text")
|
||||
m.Cmds(SPACE).Table(func(value ice.Maps) {
|
||||
value[nfs.REPOS] = "https://" + value[nfs.MODULE]
|
||||
value[aaa.ACCESS] = kit.Select("", value[aaa.USERROLE], value[aaa.USERROLE] != aaa.VOID)
|
||||
value[mdb.STATUS] = cli.START
|
||||
button := []ice.Any{PORTAL, DESKTOP, ADMIN, WORD}
|
||||
kit.If(m.IsDebug(), func() { button = append(button, VIMER, STATUS, COMPILE, cli.RUNTIME, XTERM) })
|
||||
switch value[mdb.TYPE] {
|
||||
case ORIGIN:
|
||||
if m.IsCliUA() {
|
||||
return
|
||||
}
|
||||
value[mdb.TEXT] = kit.JoinLine(value[nfs.MODULE], value[mdb.TEXT])
|
||||
button = append(button, GETTOKEN, OPEN)
|
||||
kit.If(value[aaa.ACCESS] == "", func() { button = []ice.Any{PORTAL, OPEN} })
|
||||
case SERVER:
|
||||
if !m.IsCliUA() {
|
||||
value[mdb.TEXT] = kit.JoinLine(value[nfs.MODULE], value[mdb.TEXT])
|
||||
} else if !strings.HasPrefix(value[mdb.TEXT], ice.HTTP) {
|
||||
return
|
||||
}
|
||||
button = append(button, SETTOKEN, OPEN)
|
||||
case aaa.LOGIN:
|
||||
if m.IsCliUA() {
|
||||
return
|
||||
}
|
||||
value[mdb.TEXT] = kit.JoinWord(value[AGENT], value[cli.SYSTEM], value[aaa.IP], kit.Format(PublicIP(m, value[aaa.IP])))
|
||||
button = []ice.Any{GRANT}
|
||||
default:
|
||||
return
|
||||
}
|
||||
m.Push("", value, field)
|
||||
m.PushButton(button...)
|
||||
})
|
||||
return m
|
||||
}
|
||||
func _dream_start(m *ice.Message, name string) {
|
||||
if m.WarnNotValid(name == "", mdb.NAME) {
|
||||
return
|
||||
}
|
||||
if !strings.Contains(name, "-") || !strings.HasPrefix(name, "20") {
|
||||
name = m.Time("20060102-") + name
|
||||
if !m.IsCliUA() {
|
||||
defer m.ProcessRefresh()
|
||||
}
|
||||
defer m.ProcessOpen(MergePod(m, m.Option(mdb.NAME, name)))
|
||||
p := path.Join(ice.USR_LOCAL_WORK, name)
|
||||
if pid := m.Cmdx(nfs.CAT, path.Join(p, ice.Info.PidPath), kit.Dict(ice.MSG_USERROLE, aaa.TECH)); pid != "" && nfs.ExistsFile(m, "/proc/"+pid) {
|
||||
m.Info("already exists %v", pid)
|
||||
return
|
||||
} else if m.Cmd(SPACE, name).Length() > 0 {
|
||||
m.Info("already exists %v", name)
|
||||
defer mdb.Lock(m, m.PrefixKey(), cli.START, name)()
|
||||
p := _dream_check(m, name)
|
||||
if p == "" {
|
||||
return
|
||||
}
|
||||
_dream_template(m, p)
|
||||
defer ToastProcess(m)()
|
||||
defer m.Sleep3s()
|
||||
m.Options(cli.CMD_DIR, kit.Path(p), cli.CMD_ENV, kit.Simple(
|
||||
cli.CTX_OPS, "http://localhost:"+m.CmdAppend(SERVE, tcp.PORT),
|
||||
cli.PATH, cli.BinPath(kit.Path(p, ice.BIN)), cli.USER, ice.Info.Username,
|
||||
kit.EnvSimple(cli.HOME, cli.TERM, cli.SHELL), m.Configv(cli.ENV),
|
||||
), cli.CMD_OUTPUT, path.Join(p, ice.BIN_BOOT_LOG))
|
||||
if !nfs.Exists(m, p) {
|
||||
gdb.Event(m, DREAM_CREATE, m.OptionSimple(mdb.NAME))
|
||||
}
|
||||
defer m.Options(cli.CMD_DIR, "", cli.CMD_ENV, "", cli.CMD_OUTPUT, "")
|
||||
gdb.Event(m, DREAM_CREATE, m.OptionSimple(mdb.NAME, mdb.TYPE))
|
||||
m.Cmd(cli.DAEMON, kit.Select(os.Args[0], cli.SystemFind(m, ice.ICE_BIN, nfs.PWD+path.Join(p, ice.BIN), nfs.PWD+ice.BIN)),
|
||||
SPACE, tcp.DIAL, ice.DEV, ice.OPS, mdb.TYPE, WORKER, m.OptionSimple(mdb.NAME, RIVER), cli.DAEMON, ice.OPS)
|
||||
m.Options(cli.CMD_DIR, kit.Path(p), cli.CMD_ENV, kit.EnvList(kit.Simple(m.OptionSimple(ice.TCP_DOMAIN),
|
||||
cli.CTX_OPS, HostPort(m, tcp.LOCALHOST, m.Cmdv(SERVE, tcp.PORT)), cli.CTX_LOG, ice.VAR_LOG_BOOT_LOG,
|
||||
cli.CTX_ROOT, kit.Path(""), cli.PATH, cli.BinPath(p, ""), cli.USER, ice.Info.Username,
|
||||
)...), cli.CMD_OUTPUT, path.Join(p, ice.VAR_LOG_BOOT_LOG), mdb.CACHE_CLEAR_ONEXIT, ice.TRUE)
|
||||
kit.If(m.Option(nfs.BINARY) == "" && !cli.SystemFindGo(m), func(p string) { m.Option(nfs.BINARY, S(name)) })
|
||||
kit.If(m.Option(nfs.BINARY), func(p string) { _dream_binary(m, p) })
|
||||
kit.If(m.Option(nfs.TEMPLATE), func(p string) { _dream_template(m, p) })
|
||||
bin := kit.Select(kit.Path(os.Args[0]), cli.SystemFind(m, ice.ICE_BIN, nfs.PWD+path.Join(p, ice.BIN), nfs.PWD+ice.BIN))
|
||||
if cli.IsSuccess(m.Cmd(cli.DAEMON, bin, SPACE, tcp.DIAL, ice.DEV, ice.OPS, cli.DAEMON, ice.OPS)) {
|
||||
gdb.WaitEvent(m, DREAM_OPEN, func(m *ice.Message, arg ...string) bool { return m.Option(mdb.NAME) == name })
|
||||
m.Sleep300ms()
|
||||
}
|
||||
}
|
||||
func _dream_check(m *ice.Message, name string) string {
|
||||
p := path.Join(ice.USR_LOCAL_WORK, name)
|
||||
msg := m.Spawn(kit.Dict(ice.MSG_USERROLE, aaa.ROOT))
|
||||
if pp := path.Join(p, ice.VAR_LOG_ICE_PID); nfs.Exists(m, pp) {
|
||||
for i := 0; i < 5; i++ {
|
||||
pid := msg.Cmdx(nfs.CAT, pp)
|
||||
if pid == "" {
|
||||
return p
|
||||
}
|
||||
m.Sleep("1s")
|
||||
if m.Cmd(SPACE, name).Length() > 0 {
|
||||
m.Info("already exists %v", name)
|
||||
return ""
|
||||
}
|
||||
if runtime.GOOS == cli.LINUX && !nfs.Exists(m, "/proc/"+pid) {
|
||||
return p
|
||||
}
|
||||
if nfs.Exists(m, "/proc/"+pid) && runtime.GOOS == cli.LINUX {
|
||||
if !kit.HasPrefix(msg.Cmdx(nfs.CAT, "/proc/"+pid+"/cmdline"), kit.Path(ice.BIN_ICE_BIN), kit.Path(p, ice.BIN_ICE_BIN)) {
|
||||
return p
|
||||
} else {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
if gdb.SignalProcess(m, pid) {
|
||||
m.Info("already exists %v", pid)
|
||||
return ""
|
||||
}
|
||||
}
|
||||
}
|
||||
return p
|
||||
}
|
||||
func _dream_binary(m *ice.Message, p string) {
|
||||
if bin := path.Join(m.Option(cli.CMD_DIR), ice.BIN_ICE_BIN); nfs.Exists(m, bin) {
|
||||
return
|
||||
} else if kit.IsUrl(p) || strings.HasPrefix(p, S()) {
|
||||
// m.Cmd(DREAM, DOWNLOAD, bin, kit.MergeURL2(p, kit.Format("/publish/ice.%s.%s", runtime.GOOS, runtime.GOARCH), ice.POD, m.Option(mdb.NAME)))
|
||||
m.Cmd(DREAM, DOWNLOAD, bin, kit.MergeURL(p, cli.GOOS, runtime.GOOS, cli.GOARCH, runtime.GOARCH))
|
||||
} else {
|
||||
m.Cmd(nfs.LINK, bin, kit.Path(p))
|
||||
}
|
||||
}
|
||||
func _dream_template(m *ice.Message, p string) {
|
||||
nfs.MkdirAll(m, p)
|
||||
if m.Option(nfs.TEMPLATE) == "" {
|
||||
return
|
||||
}
|
||||
for _, file := range []string{
|
||||
ice.ETC_MISS_SH, ice.SRC_MAIN_SHY, ice.SRC_MAIN_GO,
|
||||
ice.GO_MOD, ice.MAKEFILE, ice.README_MD,
|
||||
} {
|
||||
if nfs.ExistsFile(m, path.Join(p, file)) {
|
||||
continue
|
||||
kit.For([]string{
|
||||
ice.LICENSE, ice.README_MD, ice.MAKEFILE, ice.GO_MOD, ice.GO_SUM,
|
||||
ice.SRC_MAIN_SH, ice.SRC_MAIN_SHY, ice.SRC_MAIN_GO, ice.SRC_MAIN_JS,
|
||||
ice.ETC_MISS_SH, ice.ETC_INIT_SHY, ice.ETC_EXIT_SHY,
|
||||
}, func(file string) {
|
||||
if nfs.Exists(m, kit.Path(m.Option(cli.CMD_DIR), file)) {
|
||||
return
|
||||
}
|
||||
switch m.Cmdy(nfs.COPY, path.Join(p, file), path.Join(ice.USR_LOCAL_WORK, m.Option(nfs.TEMPLATE), file)); file {
|
||||
switch m.Cmdy(nfs.COPY, kit.Path(m.Option(cli.CMD_DIR), file), kit.Path(ice.USR_LOCAL_WORK, p, file)); file {
|
||||
case ice.GO_MOD:
|
||||
kit.Rewrite(path.Join(p, file), func(line string) string {
|
||||
return kit.Select(line, "module "+m.Option(mdb.NAME), strings.HasPrefix(line, "module"))
|
||||
nfs.Rewrite(m, path.Join(p, file), func(line string) string {
|
||||
return kit.Select(line, nfs.MODULE+lex.SP+m.Option(mdb.NAME), strings.HasPrefix(line, nfs.MODULE))
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const (
|
||||
DREAM_CREATE = "dream.create"
|
||||
DREAM_OPEN = "dream.open"
|
||||
DREAM_CLOSE = "dream.close"
|
||||
ALWAYS = "always"
|
||||
STARTALL = "startall"
|
||||
STOPALL = "stopall"
|
||||
FOR_EACH = "forEach"
|
||||
FOR_FLOW = "forFlow"
|
||||
GETTOKEN = "gettoken"
|
||||
SETTOKEN = "settoken"
|
||||
|
||||
DREAM_INPUTS = "dream.inputs"
|
||||
DREAM_CREATE = "dream.create"
|
||||
DREAM_REMOVE = "dream.remove"
|
||||
DREAM_TRASH = "dream.trash"
|
||||
DREAM_START = "dream.start"
|
||||
DREAM_STOP = "dream.stop"
|
||||
DREAM_OPEN = "dream.open"
|
||||
DREAM_CLOSE = "dream.close"
|
||||
DREAM_TABLES = "dream.tables"
|
||||
DREAM_ACTION = "dream.action"
|
||||
|
||||
OPS_DREAM_CREATE = "ops.dream.create"
|
||||
OPS_DREAM_REMOVE = "ops.dream.remove"
|
||||
)
|
||||
const DREAM = "dream"
|
||||
|
||||
func init() {
|
||||
Index.MergeCommands(ice.Commands{
|
||||
DREAM: {Name: "dream name path auto create", Help: "梦想家", Actions: ice.MergeActions(ice.Actions{
|
||||
DREAM: {Name: "dream refresh", Help: "梦想家", Icon: "Launchpad.png", Role: aaa.VOID, Meta: kit.Dict(
|
||||
ice.CTX_TRANS, kit.Dict(html.INPUT, kit.Dict(WORKER, "空间", SERVER, "门户", ORIGIN, "主机")),
|
||||
), Actions: ice.MergeActions(ice.Actions{
|
||||
ice.AFTER_INIT: {Hand: func(m *ice.Message, arg ...string) {
|
||||
AddPortalProduct(m, "云空间", `
|
||||
比虚拟机和容器,更加轻量,每个空间都是一个完整的系统,拥有各种软件与独立的环境。
|
||||
空间内所有的软件、配置、数据以源码库形式保存,每个空间都可以随时启动、停止、上传、下载、分享。
|
||||
每个空间都自带软件开发工具,也可以随时编程添加新的功能。
|
||||
`, 200.0)
|
||||
}},
|
||||
mdb.SEARCH: {Hand: func(m *ice.Message, arg ...string) {
|
||||
if mdb.IsSearchPreview(m, arg) {
|
||||
mdb.HashSelects(m.Spawn()).Table(func(value ice.Maps) { m.PushSearch(mdb.TYPE, WORKER, mdb.TEXT, m.MergePod(value[mdb.NAME]), value) })
|
||||
}
|
||||
}},
|
||||
mdb.INPUTS: {Hand: func(m *ice.Message, arg ...string) {
|
||||
switch arg[0] {
|
||||
case mdb.NAME, nfs.TEMPLATE:
|
||||
_dream_list(m).Cut("name,status,time")
|
||||
case mdb.NAME:
|
||||
DreamEach(m, "", kit.Select(cli.START, cli.STOP, m.Option(ctx.ACTION) == STARTALL), func(name string) { m.Push(arg[0], name) })
|
||||
case tcp.NODENAME:
|
||||
m.Cmdy(SPACE, m.Option(mdb.NAME), SPACE, ice.INFO).CutTo(mdb.NAME, arg[0])
|
||||
case aaa.USERNAME:
|
||||
if aaa.IsTechOrRoot(m) && m.Option(ctx.ACTION) == GRANT {
|
||||
m.Cmdy(aaa.USER).Cut(aaa.USERNAME, aaa.USERNICK).Option(ice.TABLE_CHECKBOX, ice.FALSE)
|
||||
} else {
|
||||
m.Push(arg[0], m.Option(tcp.NODENAME))
|
||||
m.Push(arg[0], m.Option(ice.MSG_USERNAME))
|
||||
}
|
||||
case nfs.REPOS:
|
||||
case nfs.BINARY:
|
||||
default:
|
||||
gdb.Event(m, "", arg)
|
||||
gdb.Event(m, DREAM_INPUTS, arg)
|
||||
}
|
||||
}},
|
||||
mdb.CREATE: {Name: "create name=hi repos template", Hand: func(m *ice.Message, arg ...string) {
|
||||
_dream_show(m, m.OptionDefault(mdb.NAME, path.Base(m.Option(nfs.REPOS))))
|
||||
nfs.SCAN: {Hand: func(m *ice.Message, arg ...string) {
|
||||
list := m.CmdMap(CODE_GIT_REPOS, nfs.REPOS)
|
||||
GoToastTable(m.Cmd(nfs.DIR, nfs.USR_LOCAL_WORK, mdb.NAME), mdb.NAME, func(value ice.Maps) {
|
||||
if repos, ok := list[value[mdb.NAME]]; ok {
|
||||
m.Cmd("", mdb.CREATE, value[mdb.NAME], repos[ORIGIN])
|
||||
}
|
||||
})
|
||||
}},
|
||||
mdb.CREATE: {Name: "create name*=hi repos binary", Hand: func(m *ice.Message, arg ...string) {
|
||||
kit.If(!strings.Contains(m.Option(mdb.NAME), "-") || !strings.HasPrefix(m.Option(mdb.NAME), "20"), func() { m.Option(mdb.NAME, m.Time("20060102-")+m.Option(mdb.NAME)) })
|
||||
m.Option(nfs.REPOS, kit.Select("", kit.Split(m.Option(nfs.REPOS)), -1))
|
||||
if mdb.HashCreate(m); ice.Info.Important == true {
|
||||
_dream_start(m, m.Option(mdb.NAME))
|
||||
SpaceEvent(m, OPS_DREAM_CREATE, m.Option(mdb.NAME), m.OptionSimple(mdb.NAME, nfs.REPOS, nfs.BINARY)...)
|
||||
}
|
||||
}},
|
||||
mdb.REMOVE: {Hand: func(m *ice.Message, arg ...string) {
|
||||
gdb.Event(m, DREAM_REMOVE, m.OptionSimple(mdb.NAME))
|
||||
mdb.HashRemove(m)
|
||||
}},
|
||||
STARTALL: {Name: "startall name", Help: "启动", Icon: "bi bi-play-circle", Hand: func(m *ice.Message, arg ...string) {
|
||||
DreamEach(m, m.Option(mdb.NAME), cli.STOP, func(name string) {
|
||||
m.Cmd("", cli.START, ice.Maps{mdb.NAME: name, ice.MSG_DAEMON: ""})
|
||||
})
|
||||
}},
|
||||
STOPALL: {Name: "stopall name", Help: "停止", Icon: "bi bi-stop-circle", Hand: func(m *ice.Message, arg ...string) {
|
||||
DreamEach(m, m.Option(mdb.NAME), cli.START, func(name string) {
|
||||
m.Cmd("", cli.STOP, ice.Maps{mdb.NAME: name, ice.MSG_DAEMON: ""})
|
||||
})
|
||||
}},
|
||||
cli.BUILD: {Name: "build name", Hand: func(m *ice.Message, arg ...string) {
|
||||
compile := cli.SystemFindGo(m)
|
||||
m.Option(ice.MSG_TITLE, kit.Keys(m.Option(ice.MSG_USERPOD0), m.Option(ice.MSG_USERPOD), m.CommandKey(), m.ActionKey()))
|
||||
m.Cmd("", FOR_FLOW, m.Option(mdb.NAME), kit.JoinWord(cli.SH, ice.ETC_MISS_SH), func(p string) bool {
|
||||
if compile && nfs.Exists(m, path.Join(p, ice.SRC_MAIN_GO)) {
|
||||
return false
|
||||
} else {
|
||||
m.Cmd(SPACE, path.Base(p), cli.RUNTIME, UPGRADE)
|
||||
return true
|
||||
}
|
||||
}).Sleep3s()
|
||||
m.ProcessHold()
|
||||
}},
|
||||
PUBLISH: {Name: "publish name", Hand: func(m *ice.Message, arg ...string) {
|
||||
m.Option(ice.MSG_TITLE, kit.Keys(m.Option(ice.MSG_USERPOD0), m.Option(ice.MSG_USERPOD), m.CommandKey(), m.ActionKey()))
|
||||
list := []string{cli.LINUX, cli.DARWIN, cli.WINDOWS}
|
||||
msg := m.Spawn(ice.Maps{ice.MSG_DAEMON: ""})
|
||||
func() {
|
||||
if m.Option(mdb.NAME) != "" {
|
||||
return
|
||||
}
|
||||
defer ToastProcess(m, PUBLISH, ice.Info.Pathname)()
|
||||
m.Cmd(AUTOGEN, BINPACK)
|
||||
kit.For(list, func(goos string) {
|
||||
list := []string{cli.AMD64}
|
||||
kit.If(goos == cli.DARWIN, func() { list = append(list, cli.ARM64) })
|
||||
kit.For(list, func(arch string) {
|
||||
PushNoticeRich(m, mdb.NAME, ice.Info.NodeName, msg.Cmd(COMPILE, goos, arch).AppendSimple())
|
||||
})
|
||||
})
|
||||
}()
|
||||
DreamEach(m, m.Option(mdb.NAME), "", func(name string) {
|
||||
m.Cmd(SPACE, name, AUTOGEN, BINPACK)
|
||||
kit.For(list, func(goos string) {
|
||||
list := []string{cli.AMD64}
|
||||
kit.If(goos == cli.DARWIN, func() { list = append(list, cli.ARM64) })
|
||||
kit.For(list, func(arch string) {
|
||||
PushNoticeRich(m.Options(ice.MSG_COUNT, "0", ice.LOG_DISABLE, ice.TRUE), mdb.NAME, name, msg.Cmd(SPACE, name, COMPILE, goos, arch, kit.Dict(ice.MSG_USERPOD, name)).AppendSimple())
|
||||
})
|
||||
})
|
||||
})
|
||||
m.ProcessHold()
|
||||
}},
|
||||
FOR_FLOW: {Name: "forFlow name cmd*='sh etc/miss.sh'", Help: "流程", Icon: "bi bi-terminal", Hand: func(m *ice.Message, arg ...string) {
|
||||
m.Options(ctx.DISPLAY, html.PLUGIN_XTERM, cli.CMD_OUTPUT, nfs.NewWriteCloser(func(buf []byte) (int, error) {
|
||||
PushNoticeGrow(m.Options(ice.MSG_COUNT, "0", ice.LOG_DEBUG, ice.FALSE, ice.LOG_DISABLE, ice.TRUE), strings.ReplaceAll(string(buf), lex.NL, "\r\n"))
|
||||
return len(buf), nil
|
||||
}, nil))
|
||||
msg := m.Spawn(ice.Maps{ice.MSG_DEBUG: ice.FALSE})
|
||||
DreamEach(m, m.Option(mdb.NAME), "", func(name string) {
|
||||
p := path.Join(ice.USR_LOCAL_WORK, name)
|
||||
if cb, ok := m.OptionCB("").(func(string) bool); ok && cb(p) {
|
||||
return
|
||||
}
|
||||
defer PushNoticeGrow(msg, "\r\n\r\n")
|
||||
PushNoticeGrow(msg, kit.Format("\033[33m[%s]%s$\033[0m %s\r\n", time.Now().Format(ice.MOD_TIME_ONLY), name, m.Option(ice.CMD)))
|
||||
m.Cmd(cli.SYSTEM, kit.Split(m.Option(ice.CMD)), kit.Dict(cli.CMD_DIR, p)).Sleep300ms()
|
||||
})
|
||||
}},
|
||||
cli.START: {Hand: func(m *ice.Message, arg ...string) {
|
||||
_dream_show(m, m.Option(mdb.NAME))
|
||||
_dream_start(m, m.Option(mdb.NAME))
|
||||
gdb.Event(m, DREAM_START, arg)
|
||||
}},
|
||||
cli.STOP: {Hand: func(m *ice.Message, arg ...string) {
|
||||
gdb.Event(m, DREAM_STOP, arg)
|
||||
m.Cmd(SPACE, mdb.MODIFY, m.OptionSimple(mdb.NAME), mdb.STATUS, cli.STOP)
|
||||
m.Go(func() { m.Cmd(SPACE, m.Option(mdb.NAME), ice.EXIT) })
|
||||
ctx.ProcessRefresh(m, "1s")
|
||||
m.Cmd(SPACE, m.Option(mdb.NAME), ice.EXIT).Sleep3s()
|
||||
}},
|
||||
nfs.TRASH: {Hand: func(m *ice.Message, arg ...string) {
|
||||
gdb.Event(m, DREAM_TRASH, arg)
|
||||
nfs.Trash(m, path.Join(ice.USR_LOCAL_WORK, m.Option(mdb.NAME)))
|
||||
}},
|
||||
DREAM_OPEN: {Hand: func(m *ice.Message, arg ...string) {
|
||||
if m.Option(cli.DAEMON) == ice.OPS {
|
||||
if m.CmdAppend(SPACE, m.Option(mdb.NAME), mdb.STATUS) != cli.STOP {
|
||||
m.Go(func() { m.Sleep3s(DREAM, cli.START, m.OptionSimple(mdb.NAME)) })
|
||||
}
|
||||
cli.RUNTIME: {Hand: func(m *ice.Message, arg ...string) {
|
||||
ProcessPodCmd(m, m.Option(mdb.NAME), "", nil, arg...)
|
||||
}},
|
||||
"settings": {Name: "settings restart=manual,always access=public,private", Help: "设置", Style: html.DANGER, Hand: func(m *ice.Message, arg ...string) {
|
||||
kit.If(m.Option(cli.RESTART) == "manual", func() { m.Option(cli.RESTART, "") })
|
||||
kit.If(m.Option(aaa.ACCESS) == aaa.PUBLIC, func() { m.Option(aaa.ACCESS, "") })
|
||||
mdb.HashModify(m, m.OptionSimple(mdb.NAME, cli.RESTART, aaa.ACCESS))
|
||||
}},
|
||||
SETTOKEN: {Name: "settoken nodename* username*", Help: "令牌", Style: html.DANGER, Hand: func(m *ice.Message, arg ...string) {
|
||||
token := m.Cmdx(TOKEN, mdb.CREATE, mdb.TYPE, SERVER, mdb.NAME, m.Option(aaa.USERNAME), mdb.TEXT, m.Option(tcp.NODENAME))
|
||||
m.Cmd(SPACE, m.Option(mdb.NAME), SPIDE, DEV_CREATE_TOKEN, ice.Maps{TOKEN: token})
|
||||
}},
|
||||
GETTOKEN: {Help: "令牌", Style: html.DANGER, Hand: func(m *ice.Message, arg ...string) {
|
||||
m.Options(m.Cmd(SPIDE, m.Option(mdb.NAME)).AppendSimple()).Cmdy(SPIDE, mdb.DEV_REQUEST)
|
||||
}},
|
||||
GRANT: {Name: "grant username", Role: aaa.VOID, Hand: func(m *ice.Message, arg ...string) {
|
||||
if aaa.IsTechOrRoot(m) && m.Option(aaa.USERNAME) != "" {
|
||||
m.Option(ice.MSG_USERNAME, m.Option(aaa.USERNAME))
|
||||
}
|
||||
m.Cmd(CHAT_GRANT, aaa.CONFIRM, kit.Dict(SPACE, m.Option(mdb.NAME)))
|
||||
}},
|
||||
OPEN: {Style: html.NOTICE, Role: aaa.VOID, Hand: func(m *ice.Message, arg ...string) {
|
||||
if strings.HasSuffix(m.Option(ice.MAIN), ".portal") || kit.HasPrefixList(arg, ctx.RUN) {
|
||||
if !kit.HasPrefixList(arg, ctx.RUN) {
|
||||
defer m.Push(TITLE, m.Option(mdb.NAME))
|
||||
defer m.Push("_icon", m.Option(mdb.ICON))
|
||||
defer m.Push("_style", "portal")
|
||||
defer m.Push("_height", "844")
|
||||
defer m.Push("_width", "390")
|
||||
}
|
||||
ctx.ProcessFloat(m, CHAT_IFRAME, S(m.Option(mdb.NAME)), arg...)
|
||||
} else if m.Option(mdb.TYPE) == ORIGIN {
|
||||
m.ProcessOpen(SpideOrigin(m, m.Option(mdb.NAME)))
|
||||
} else if p := ProxyDomain(m, m.Option(mdb.NAME)); p != "" {
|
||||
m.ProcessOpen(p)
|
||||
} else {
|
||||
m.ProcessOpen(S(kit.Keys(m.Option(ice.MSG_USERPOD), m.Option(mdb.NAME))))
|
||||
}
|
||||
}},
|
||||
DREAM_OPEN: {Hand: func(m *ice.Message, arg ...string) {}},
|
||||
DREAM_CLOSE: {Hand: func(m *ice.Message, arg ...string) {
|
||||
kit.For(arg, func(k, v string) {
|
||||
if k == cli.DAEMON && v == ice.OPS && m.Cmdv(SPACE, m.Option(mdb.NAME), mdb.STATUS) != cli.STOP {
|
||||
m.GoSleep300ms(func() { m.Cmd(DREAM, cli.START, m.OptionSimple(mdb.NAME)) })
|
||||
}
|
||||
})
|
||||
}},
|
||||
DREAM_TABLES: {Hand: func(m *ice.Message, arg ...string) {
|
||||
switch m.Option(mdb.TYPE) {
|
||||
case SERVER, WORKER:
|
||||
m.PushButton(OPEN)
|
||||
button := []ice.Any{}
|
||||
if aaa.IsTechOrRoot(m) {
|
||||
switch m.Option(mdb.TYPE) {
|
||||
case ORIGIN:
|
||||
button = append(button, DREAM, GETTOKEN)
|
||||
case SERVER:
|
||||
button = append(button, DREAM, SETTOKEN)
|
||||
case WORKER:
|
||||
button = append(button, "settings")
|
||||
}
|
||||
}
|
||||
m.PushButton(append(button, OPEN)...)
|
||||
}},
|
||||
SERVE_START: {Hand: func(m *ice.Message, arg ...string) {
|
||||
for _, cmd := range kit.Reverse(kit.Split(mdb.Config(m, html.BUTTON))) {
|
||||
m.Cmd(gdb.EVENT, gdb.LISTEN, gdb.EVENT, DREAM_TABLES, ice.CMD, cmd)
|
||||
m.Cmd(gdb.EVENT, gdb.LISTEN, gdb.EVENT, DREAM_ACTION, ice.CMD, cmd)
|
||||
aaa.White(m, kit.Keys(m.ShortKey(), ctx.ACTION, cmd))
|
||||
}
|
||||
mdb.HashSelects(m.Spawn()).SortStrR(mdb.NAME).Table(func(value ice.Maps) {
|
||||
if value[cli.RESTART] == ALWAYS && nfs.Exists(m, path.Join(ice.USR_LOCAL_WORK+value[mdb.NAME])) {
|
||||
m.Cmd(DREAM, cli.START, kit.Dict(mdb.NAME, value[mdb.NAME]))
|
||||
}
|
||||
})
|
||||
}},
|
||||
STATS_TABLES: {Hand: func(m *ice.Message, arg ...string) {
|
||||
if msg := _dream_list(m.Spawn()); msg.Length() > 0 {
|
||||
stat := map[string]int{}
|
||||
msg.Table(func(value ice.Maps) { stat[value[mdb.TYPE]]++; stat[value[mdb.STATUS]]++ })
|
||||
PushStats(m, kit.Keys(m.CommandKey(), cli.START), stat[cli.START], "", "已启动空间")
|
||||
PushStats(m, kit.Keys(m.CommandKey(), SERVER), stat[SERVER], "", "已连接机器")
|
||||
PushStats(m, kit.Keys(m.CommandKey(), ORIGIN), stat[ORIGIN], "", "已连接主机")
|
||||
}
|
||||
}},
|
||||
OPEN: {Hand: func(m *ice.Message, arg ...string) { ctx.ProcessOpen(m, MergePod(m, m.Option(mdb.NAME), arg)) }},
|
||||
}, ctx.CmdAction(), DreamAction()), Hand: func(m *ice.Message, arg ...string) {
|
||||
ORIGIN: {Hand: func(m *ice.Message, arg ...string) {
|
||||
m.Cmd(SPACE).Table(func(value ice.Maps, index int, head []string) {
|
||||
kit.If(value[mdb.TYPE] == m.ActionKey(), func() { m.PushRecord(value, head...) })
|
||||
})
|
||||
m.SortStrR(mdb.NAME)
|
||||
kit.If(len(arg) > 0, func() { m.Cut(arg...) })
|
||||
}},
|
||||
SERVER: {Hand: func(m *ice.Message, arg ...string) {
|
||||
m.Cmd(SPACE).Table(func(value ice.Maps, index int, head []string) {
|
||||
kit.If(value[mdb.TYPE] == m.ActionKey(), func() { m.PushRecord(value, head...) })
|
||||
})
|
||||
m.SortStrR(mdb.NAME)
|
||||
kit.If(len(arg) > 0, func() { m.Cut(arg...) })
|
||||
}},
|
||||
WORKER: {Hand: func(m *ice.Message, arg ...string) {
|
||||
m.Cmd(SPACE).Table(func(value ice.Maps, index int, head []string) {
|
||||
kit.If(value[mdb.TYPE] == m.ActionKey(), func() { m.PushRecord(value, head...) })
|
||||
})
|
||||
m.SortStrR(mdb.NAME)
|
||||
kit.If(len(arg) > 0, func() { m.Cut(arg...) })
|
||||
}},
|
||||
DOWNLOAD: {Name: "download path link", Hand: func(m *ice.Message, arg ...string) {
|
||||
GoToast(m, func(toast func(string, int, int)) []string {
|
||||
SpideSave(m, m.Option(nfs.PATH), kit.MergeURL(m.Option(mdb.LINK), cli.GOOS, runtime.GOOS, cli.GOARCH, runtime.GOARCH), func(count, total, value int) {
|
||||
toast(m.Option(mdb.NAME), count, total)
|
||||
})
|
||||
return nil
|
||||
})
|
||||
os.Chmod(m.Option(nfs.PATH), ice.MOD_DIR)
|
||||
}},
|
||||
VERSION: {Hand: func(m *ice.Message, arg ...string) {
|
||||
m.Cmdy("web.code.version")
|
||||
}},
|
||||
nfs.GOWORK: {Name: "gowork name", Help: "工作区", Icon: "bi bi-exclude", Hand: func(m *ice.Message, arg ...string) {
|
||||
m.Cmd(cli.SYSTEM, cli.GO, "work", "init")
|
||||
kit.For([]string{".", nfs.USR_RELEASE, nfs.USR_ICEBERGS, nfs.USR_TOOLKITS}, func(p string) { m.Cmd(cli.SYSTEM, cli.GO, "work", "use", p) })
|
||||
DreamEach(m, m.Option(mdb.NAME), "", func(name string) { m.Cmd(cli.SYSTEM, cli.GO, "work", "use", path.Join(ice.USR_LOCAL_WORK, name)) })
|
||||
m.Cmdy(nfs.CAT, "go.work")
|
||||
}},
|
||||
}, StatsAction(), DreamAction(), DreamTablesAction(), mdb.ImportantHashAction(
|
||||
mdb.SHORT, mdb.NAME, mdb.FIELD, "time,name,main,icons,repos,binary,template,restart,access",
|
||||
html.BUTTON, kit.JoinWord(PORTAL, DESKTOP, ADMIN, WORD, VIMER, STATUS, COMPILE, XTERM, DREAM),
|
||||
)), Hand: func(m *ice.Message, arg ...string) {
|
||||
if len(arg) == 0 {
|
||||
if ice.Info.NodeType == WORKER {
|
||||
return
|
||||
}
|
||||
_dream_list(m)
|
||||
if _dream_list_more(m); !aaa.IsTechOrRoot(m) || m.IsCliUA() {
|
||||
m.Action()
|
||||
} else if m.IsDebug() && cli.SystemFindGo(m) {
|
||||
m.Action(mdb.CREATE, STARTALL, STOPALL, cli.BUILD, PUBLISH)
|
||||
} else {
|
||||
m.Action(mdb.CREATE, STARTALL, STOPALL)
|
||||
}
|
||||
if m.Length() == 0 {
|
||||
m.EchoInfoButton(m.Trans("please scan or create new dream", "请扫描或创建新空间"), mdb.CREATE, nfs.SCAN)
|
||||
return
|
||||
}
|
||||
ctx.DisplayTableCard(m)
|
||||
m.Options(ice.MSG_TOOLKIT, "web.code.compose.insight")
|
||||
m.Sort("type,status,name", []string{aaa.LOGIN, WORKER, SERVER, ORIGIN}, []string{cli.START, cli.STOP, cli.BEGIN}, ice.STR_R)
|
||||
m.StatusTimeCountStats(mdb.TYPE, mdb.STATUS)
|
||||
} else if arg[0] == ctx.ACTION {
|
||||
gdb.Event(m, DREAM_ACTION, arg)
|
||||
} else {
|
||||
m.Cmdy(nfs.CAT, arg[1:], kit.Dict(nfs.DIR_ROOT, path.Join(ice.USR_LOCAL_WORK, arg[0])))
|
||||
m.Cmdy(arg[1], DREAM_ACTION, arg)
|
||||
// gdb.Event(m, DREAM_ACTION, arg)
|
||||
}
|
||||
}},
|
||||
})
|
||||
}
|
||||
|
||||
func DreamAction() ice.Actions {
|
||||
return gdb.EventsAction(DREAM_OPEN, DREAM_INPUTS, DREAM_TABLES, DREAM_ACTION)
|
||||
func DreamTablesAction(arg ...string) ice.Actions {
|
||||
return ice.Actions{ice.CTX_INIT: {Hand: DreamWhiteHandle},
|
||||
DREAM_TABLES: {Hand: func(m *ice.Message, _ ...string) {
|
||||
m.PushButton(kit.Dict(m.CommandKey(), kit.Select(m.Commands("").Help, arg, 0)))
|
||||
}},
|
||||
DREAM_ACTION: {Hand: func(m *ice.Message, arg ...string) { DreamProcess(m, "", nil, arg...) }},
|
||||
}
|
||||
}
|
||||
func DreamAction() ice.Actions {
|
||||
return gdb.EventsAction(
|
||||
DREAM_INPUTS, DREAM_CREATE, DREAM_REMOVE, DREAM_TRASH, DREAM_OPEN, DREAM_CLOSE,
|
||||
OPS_ORIGIN_OPEN, OPS_SERVER_OPEN, OPS_DREAM_CREATE, OPS_DREAM_REMOVE,
|
||||
SERVE_START, SPACE_LOGIN,
|
||||
)
|
||||
}
|
||||
func DreamWhiteHandle(m *ice.Message, arg ...string) {
|
||||
aaa.White(m, kit.Keys(DREAM, ctx.ACTION, m.ShortKey()))
|
||||
aaa.White(m, kit.Keys(m.ShortKey(), ctx.ACTION, DREAM_ACTION))
|
||||
}
|
||||
func DreamProcessIframe(m *ice.Message, arg ...string) {
|
||||
if !kit.HasPrefixList(arg, ctx.ACTION, m.ShortKey()) && !kit.HasPrefixList(arg, ctx.ACTION, m.CommandKey()) {
|
||||
return
|
||||
}
|
||||
if len(arg) == 2 {
|
||||
defer m.Push(TITLE, kit.Keys(m.Option(mdb.NAME), m.ShortKey())+kit.Format("(%s)", m.Command().Help))
|
||||
defer m.Push("_icon", m.Option(mdb.ICON))
|
||||
}
|
||||
DreamProcess(m, CHAT_IFRAME, func() string {
|
||||
p := S(kit.Keys(m.Option(ice.MSG_USERPOD), m.Option(mdb.NAME)))
|
||||
kit.If(m.Option(mdb.TYPE) == ORIGIN && m.CommandKey() == PORTAL, func() { p = SpideOrigin(m, m.Option(mdb.NAME)) })
|
||||
return kit.MergeURL(p+C(m.ShortKey()), ice.MSG_DEBUG, m.Option(ice.MSG_DEBUG))
|
||||
}, arg...)
|
||||
}
|
||||
func DreamProcess(m *ice.Message, cmd string, args ice.Any, arg ...string) {
|
||||
if !kit.HasPrefixList(arg, ctx.ACTION, m.ShortKey()) && !kit.HasPrefixList(arg, ctx.ACTION, m.CommandKey()) {
|
||||
return
|
||||
} else if arg = arg[2:]; len(arg) == 0 {
|
||||
arg = append(arg, m.Option(mdb.NAME))
|
||||
defer m.ProcessField(ctx.ACTION, m.ShortKey(), arg[0], ctx.RUN)
|
||||
defer processSpace(m, arg[0], arg[0], m.ShortKey())
|
||||
}
|
||||
ctx.ProcessFloat(m.Options(ice.POD, arg[0]), kit.Select(m.ShortKey(), cmd), args, arg[1:]...)
|
||||
}
|
||||
func DreamEach(m *ice.Message, name string, status string, cb func(string)) *ice.Message {
|
||||
reg, err := regexp.Compile(name)
|
||||
if m.WarnNotValid(err) {
|
||||
return m
|
||||
}
|
||||
msg := m.Spawn()
|
||||
m.Cmds(DREAM, kit.Dict(ice.DREAM_SIMPLE, ice.TRUE)).Table(func(value ice.Maps) {
|
||||
if value[mdb.STATUS] == kit.Select(cli.START, status) && value[mdb.TYPE] == WORKER && (value[mdb.NAME] == name || reg.MatchString(kit.Format("%s:%s=%s@%d", value[mdb.NAME], value[mdb.TYPE], value[nfs.MODULE], value[nfs.VERSION]))) {
|
||||
msg.Push(mdb.NAME, value[mdb.NAME])
|
||||
}
|
||||
})
|
||||
return GoToastTable(msg, mdb.NAME, func(value ice.Maps) { cb(value[mdb.NAME]) })
|
||||
}
|
||||
func DreamListSpide(m *ice.Message, list []string, types string, cb func(dev, origin string)) {
|
||||
msg := m.Spawn()
|
||||
kit.For(list, func(name string) { msg.Push(mdb.NAME, name) })
|
||||
m.Cmds(SPACE).Table(func(value ice.Maps) { kit.If(value[mdb.TYPE] == types, func() { msg.Push(mdb.NAME, value[mdb.NAME]) }) })
|
||||
has := map[string]bool{}
|
||||
GoToastTable(msg, mdb.NAME, func(value ice.Maps) {
|
||||
origin := SpideOrigin(m, value[mdb.NAME])
|
||||
kit.If(!has[origin], func() { has[origin] = true; cb(value[mdb.NAME], origin) })
|
||||
})
|
||||
}
|
||||
func DreamList(m *ice.Message) *ice.Message {
|
||||
return AdminCmd(m.Options(ice.DREAM_SIMPLE, ice.TRUE), DREAM)
|
||||
}
|
||||
func DreamStat(m *ice.Message, name string) (res string) {
|
||||
if cli.SystemFindGit(m) {
|
||||
text := []string{}
|
||||
for _, line := range kit.Split(m.Cmdx(cli.SYSTEM, cli.GIT, "diff", "--shortstat", kit.Dict(cli.CMD_DIR, path.Join(ice.USR_LOCAL_WORK, name))), mdb.FS, mdb.FS) {
|
||||
if list := kit.Split(line); strings.Contains(line, nfs.FILE) {
|
||||
text = append(text, kit.Format("<span class='files'>%s file</span>", list[0]))
|
||||
} else if strings.Contains(line, "ins") {
|
||||
text = append(text, kit.Format("<span class='add'>%s+++</span>", list[0]))
|
||||
} else if strings.Contains(line, "del") {
|
||||
text = append(text, kit.Format("<span class='del'>%s---</span>", list[0]))
|
||||
}
|
||||
}
|
||||
res = strings.Join(text, "")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
153
base/web/html/html.go
Normal file
153
base/web/html/html.go
Normal file
@ -0,0 +1,153 @@
|
||||
package html
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
kit "shylinux.com/x/toolkits"
|
||||
)
|
||||
|
||||
const (
|
||||
FAVICON = "favicon"
|
||||
Mozilla = "Mozilla"
|
||||
Firefox = "Firefox"
|
||||
Safari = "Safari"
|
||||
Chrome = "Chrome"
|
||||
Edg = "Edg"
|
||||
Mobile = "Mobile"
|
||||
Alipay = "Alipay"
|
||||
MicroMessenger = "MicroMessenger"
|
||||
Android = "Android"
|
||||
IPhone = "iPhone"
|
||||
Mac = "Mac"
|
||||
Linux = "Linux"
|
||||
Windows = "Windows"
|
||||
|
||||
UserAgent = "User-Agent"
|
||||
XForwardedFor = "X-Forwarded-For"
|
||||
XHost = "X-Host"
|
||||
Referer = "Referer"
|
||||
Authorization = "Authorization"
|
||||
Bearer = "Bearer"
|
||||
Basic = "Basic"
|
||||
Accept = "Accept"
|
||||
AcceptLanguage = "Accept-Language"
|
||||
ContentEncoding = "Content-Encoding"
|
||||
ContentLength = "Content-Length"
|
||||
ContentType = "Content-Type"
|
||||
|
||||
ApplicationForm = "application/x-www-form-urlencoded"
|
||||
ApplicationOctet = "application/octet-stream"
|
||||
ApplicationJSON = "application/json"
|
||||
TEXT_PLAIN = "text/plain"
|
||||
)
|
||||
const (
|
||||
LABEL = "label"
|
||||
TABLE = "table"
|
||||
TR = "tr"
|
||||
TH = "th"
|
||||
TD = "td"
|
||||
H1 = "h1"
|
||||
H2 = "h2"
|
||||
H3 = "h3"
|
||||
SPAN = "span"
|
||||
TEXT = "text"
|
||||
PLUG = "plug"
|
||||
FORM = "form"
|
||||
TEXTAREA = "textarea"
|
||||
PASSWORD = "password"
|
||||
CHECKBOX = "checkbox"
|
||||
SELECT = "select"
|
||||
BUTTON = "button"
|
||||
IMAGE = "image"
|
||||
SUBMIT = "submit"
|
||||
CHROME = "chrome"
|
||||
NEED = "need"
|
||||
MUST = "must"
|
||||
|
||||
STYLE = "style"
|
||||
FLOAT = "float"
|
||||
WIDTH = "width"
|
||||
HEIGHT = "height"
|
||||
|
||||
BG_COLOR = "background-color"
|
||||
FG_COLOR = "color"
|
||||
)
|
||||
const (
|
||||
DARK = "dark"
|
||||
LIGHT = "light"
|
||||
WHITE = "white"
|
||||
BLACK = "black"
|
||||
SILVER = "silver"
|
||||
DANGER = "danger"
|
||||
NOTICE = "notice"
|
||||
|
||||
PROJECT = "project"
|
||||
CONTENT = "content"
|
||||
PROFILE = "profile"
|
||||
DISPLAY = "display"
|
||||
|
||||
VIEW = "view"
|
||||
VALUE = "value"
|
||||
INPUT = "input"
|
||||
ICON = "icon"
|
||||
ICONS = "icons"
|
||||
OUTPUT = "output"
|
||||
LAYOUT = "layout"
|
||||
RESIZE = "resize"
|
||||
// FILTER = "filter"
|
||||
REFRESH = "refresh"
|
||||
CONFIRM = "confirm"
|
||||
|
||||
PLUGIN_JSON = "/plugin/story/json.js"
|
||||
PLUGIN_INNER = "/plugin/local/code/inner.js"
|
||||
PLUGIN_XTERM = "/plugin/local/code/xterm.js"
|
||||
ICONS_SSH = "usr/icons/ssh.png"
|
||||
ICONS_MAIL = "usr/icons/Mail.png"
|
||||
ICONS_DREAM = "usr/icons/Launchpad.png"
|
||||
ICONS_SETTINGS = "usr/icons/System Settings.png"
|
||||
|
||||
GetLocation = "getLocation"
|
||||
ConnectWifi = "ConnectWifi"
|
||||
GetClipboardData = "getClipboardData"
|
||||
ScanQRCode = "scanQRCode"
|
||||
ChooseImage = "chooseImage"
|
||||
Record1 = "record1"
|
||||
Record2 = "record2"
|
||||
)
|
||||
|
||||
func IsImage(name, mime string) bool {
|
||||
return strings.HasPrefix(mime, "image/") || kit.ExtIsImage(name)
|
||||
}
|
||||
func IsVideo(name, mime string) bool {
|
||||
return strings.HasPrefix(mime, "video/") || kit.ExtIsVideo(name)
|
||||
}
|
||||
func IsAudio(name, mime string) bool {
|
||||
return strings.HasPrefix(mime, "audio/")
|
||||
}
|
||||
|
||||
func Format(tag string, inner string, arg ...string) string {
|
||||
return kit.Format("<%s %s>%s</%s>", tag, kit.JoinProperty(arg...), inner, tag)
|
||||
}
|
||||
func FormatA(inner string, arg ...string) string {
|
||||
return kit.Format(`<a href="%s">%s</a>`, kit.Select(inner, arg, 0), inner)
|
||||
}
|
||||
func FormatDanger(value string) string {
|
||||
return Format(SPAN, value, STYLE, kit.JoinCSS(BG_COLOR, "var(--danger-bg-color)", FG_COLOR, "var(--danger-fg-color)"))
|
||||
}
|
||||
|
||||
var AgentList = []string{
|
||||
MicroMessenger,
|
||||
Alipay,
|
||||
Edg,
|
||||
Chrome,
|
||||
Safari,
|
||||
Firefox,
|
||||
"Go-http-client",
|
||||
}
|
||||
var SystemList = []string{
|
||||
Android,
|
||||
IPhone,
|
||||
Mac,
|
||||
Linux,
|
||||
Windows,
|
||||
}
|
36
base/web/matrix.css
Normal file
36
base/web/matrix.css
Normal file
@ -0,0 +1,36 @@
|
||||
fieldset.web.matrix>div.output>table.content th { padding:var(--input-padding); }
|
||||
fieldset.web.matrix>div.output>table.content th i { padding:var(--input-padding); }
|
||||
fieldset.web.matrix>div.output>table.content th i:hover { background-color:var(--hover-bg-color); color:var(--hover-fg-color); }
|
||||
fieldset.web.matrix>div.output>table.content td { padding:var(--input-padding); }
|
||||
fieldset.web.matrix>div.output>table.content td:hover { color:unset; }
|
||||
fieldset.web.matrix>div.output>table.content div.item { display:flex; align-items:center; cursor:default; }
|
||||
fieldset.web.matrix>div.output>table.content div.item img { height:var(--header-height); width:var(--header-height); cursor:pointer; }
|
||||
fieldset.web.matrix>div.output>table.content div.item img.jpg { padding:var(--input-padding); }
|
||||
fieldset.web.matrix>div.output>table.content div.item div.title { text-align:left; padding:var(--input-padding); }
|
||||
fieldset.web.matrix>div.output>table.content div.item div.title>span { cursor:pointer; }
|
||||
fieldset.web.matrix>div.output>table.content div.item div.title>span.status { font-size:var(--status-font-size); }
|
||||
fieldset.web.matrix>div.output>table.content div.item div.title>span.status>span { padding:0 var(--input-padding); }
|
||||
fieldset.web.matrix>div.output>table.content div.item div.title>span.status>span.files { background-color:purple; color:var(--notice-fg-color);}
|
||||
fieldset.web.matrix>div.output>table.content div.item div.title>span.status>span.add { background-color:var(--notice-bg-color); color:var(--notice-fg-color);}
|
||||
fieldset.web.matrix>div.output>table.content div.item div.title>span.status>span.del { background-color:var(--danger-bg-color); color:var(--danger-fg-color);}
|
||||
fieldset.web.matrix>div.output>table.content div.item div.status i { font-size:var(--status-font-size); padding:0; }
|
||||
fieldset.web.matrix>div.output>table.content div.item div.action { margin-top:var(--input-margin); overflow:hidden; }
|
||||
fieldset.web.matrix>div.output>table.content div.item div.action input.icons { display:none; }
|
||||
fieldset.web.matrix>div.output>table.content div.item div.title:hover { background-color:unset; }
|
||||
fieldset.web.matrix>div.output>table.content div.item div.title span:hover { background-color:var(--hover-bg-color); }
|
||||
fieldset.web.matrix>div.output>table.content div.item div.status div.item:hover { background-color:var(--hover-bg-color); }
|
||||
fieldset.web.matrix>div.output>table.content div.item:hover { background-color:unset; color:unset; }
|
||||
fieldset.web.matrix>div.output:not(.process)>table.content div.item.notice { background-color:var(--notice-bg-color); color:var(--notice-fg-color); }
|
||||
fieldset.web.matrix>div.output:not(.process)>table.content div.item.danger { background-color:var(--danger-bg-color); color:var(--danger-fg-color); }
|
||||
fieldset.web.matrix>div.output:not(.process)>table.content div.item.server { border:var(--box-notice); }
|
||||
fieldset.web.matrix>div.output:not(.process)>table.content div.item.origin { border:var(--box-danger); }
|
||||
fieldset.web.matrix>div.output:not(.process)>table.content div.item.danger div.status div.item { color:var(--danger-fg-color); }
|
||||
fieldset.web.matrix>div.output:not(.process)>table.content div.item.notice div.status div.item { color:var(--notice-fg-color); }
|
||||
fieldset.web.matrix>div.output:not(.process)>table.content div.item.stop div.title>span { color:var(--disable-fg-color); }
|
||||
fieldset.web.matrix>div.output.process>table.content div.item.process { background-color:blue; color:var(--notice-fg-color); }
|
||||
fieldset.web.matrix>div.output>table.content tr:not(:hover) div.action { visibility:hidden; }
|
||||
body:not(.mobile) fieldset.web.matrix>div.output>table.content th:first-child { position:sticky; left:2px; z-index:2; }
|
||||
body:not(.mobile) fieldset.web.matrix>div.output>table.content td:first-child { box-shadow:var(--th-box-shadow); background-color:var(--plugin-bg-color); position:sticky; left:2px; z-index:1; }
|
||||
body:not(.mobile) fieldset.web.matrix>div.output>table.content td:hover { box-shadow:var(--notice-box-shadow); }
|
||||
body:not(.mobile) fieldset.web.matrix>div.output>table.content th:hover { box-shadow:var(--notice-box-shadow); }
|
||||
body:not(.mobile) fieldset.web.matrix>div.output>table.content tr.danger td:first-child { background-color:transparent; }
|
168
base/web/matrix.go
Normal file
168
base/web/matrix.go
Normal file
@ -0,0 +1,168 @@
|
||||
package web
|
||||
|
||||
import (
|
||||
ice "shylinux.com/x/icebergs"
|
||||
"shylinux.com/x/icebergs/base/aaa"
|
||||
"shylinux.com/x/icebergs/base/cli"
|
||||
"shylinux.com/x/icebergs/base/ctx"
|
||||
"shylinux.com/x/icebergs/base/mdb"
|
||||
"shylinux.com/x/icebergs/base/nfs"
|
||||
"shylinux.com/x/icebergs/base/tcp"
|
||||
"shylinux.com/x/icebergs/base/web/html"
|
||||
kit "shylinux.com/x/toolkits"
|
||||
)
|
||||
|
||||
func _matrix_list(m *ice.Message, domain, typ string, value ice.Maps, fields ...string) (server, icons, types []string) {
|
||||
value[DOMAIN], value[mdb.TYPE] = domain, typ
|
||||
// istech, isdebug := typ == SERVER || kit.IsIn(value[aaa.ACCESS], aaa.TECH, aaa.ROOT), m.IsDebug()
|
||||
istech := typ == SERVER || kit.IsIn(value[aaa.ACCESS], aaa.TECH, aaa.ROOT)
|
||||
compile := kit.Select("", kit.Select(COMPILE, UPGRADE, typ == SERVER), istech)
|
||||
|
||||
button := []ice.Any{PORTAL, DESKTOP, ADMIN, WORD, OPEN, compile, DREAM}
|
||||
kit.If(istech, func() { button = append(button, STATUS) })
|
||||
kit.If(istech, func() { button = append(button, VIMER, COMPILE, cli.RUNTIME, XTERM) })
|
||||
m.PushRecord(value, fields...).PushButton(button...)
|
||||
|
||||
button = []ice.Any{PORTAL, DESKTOP, ADMIN, WORD, OPEN, compile}
|
||||
kit.If(istech, func() { button = append(button, STATUS) })
|
||||
kit.If(istech, func() { button = append(button, VIMER, COMPILE, cli.RUNTIME, XTERM, cli.STOP) })
|
||||
m.Cmd(Space(m, domain), DREAM).Table(func(value ice.Maps) {
|
||||
switch value[mdb.TYPE] {
|
||||
case WORKER:
|
||||
if value[aaa.ACCESS] == aaa.PRIVATE {
|
||||
break
|
||||
}
|
||||
value[DOMAIN] = domain
|
||||
kit.If(value[mdb.STATUS] == cli.STOP, func() { value[mdb.ICONS] = nfs.P + nfs.USR_ICONS_ICEBERGS })
|
||||
kit.If(value[mdb.STATUS] == cli.STOP && istech, func() { button = []ice.Any{cli.START, mdb.REMOVE} })
|
||||
m.PushRecord(value, fields...).PushButton(button...)
|
||||
case SERVER, ORIGIN:
|
||||
server = append(server, kit.Keys(domain, value[mdb.NAME]))
|
||||
icons = append(icons, value[mdb.ICONS])
|
||||
types = append(types, value[mdb.TYPE])
|
||||
}
|
||||
})
|
||||
return
|
||||
}
|
||||
func _matrix_action(m *ice.Message, action string, arg ...string) {
|
||||
switch domain := kit.Keys(m.Option(DOMAIN), m.Option(mdb.NAME)); action {
|
||||
case PORTAL, ADMIN:
|
||||
if kit.HasPrefixList(arg, ctx.RUN) {
|
||||
ProcessIframe(m, "", "", arg...)
|
||||
} else {
|
||||
title, link := kit.Keys(domain, action), kit.Select("", S(domain), domain != "")+C(action)
|
||||
if m.Option(mdb.TYPE) == ORIGIN {
|
||||
link = kit.MergeURL2(SpideOrigin(m, m.Option(DOMAIN)), C(action))
|
||||
if kit.IsIn(action, ADMIN) {
|
||||
m.ProcessOpen(link)
|
||||
break
|
||||
}
|
||||
}
|
||||
ProcessIframe(m, title, kit.Select(nfs.PS, link), arg...).ProcessField(ctx.ACTION, action, ctx.RUN)
|
||||
}
|
||||
case OPEN:
|
||||
link := kit.Select(nfs.PS, S(domain), domain != "")
|
||||
if m.Option(mdb.TYPE) == ORIGIN {
|
||||
link = SpideOrigin(m, m.Option(DOMAIN))
|
||||
} else if m.Option("server.type") == ORIGIN {
|
||||
link = kit.MergeURL2(SpideOrigin(m, m.Option(DOMAIN)), S(m.Option(mdb.NAME)))
|
||||
}
|
||||
m.ProcessOpen(link)
|
||||
default:
|
||||
if !kit.HasPrefixList(arg, ctx.RUN) {
|
||||
kit.If(action == XTERM, func() { arg = []string{cli.SH} })
|
||||
defer m.ProcessField(ctx.ACTION, action, ctx.RUN, domain, action)
|
||||
}
|
||||
ProcessPodCmd(m, domain, action, arg, arg...)
|
||||
}
|
||||
}
|
||||
func _matrix_dream(m *ice.Message, action string, arg ...string) {
|
||||
m.Cmd(Space(m, m.Option(DOMAIN)), DREAM, kit.Select(m.ActionKey(), action), m.OptionSimple(mdb.NAME), arg)
|
||||
}
|
||||
|
||||
func _matrix_cmd(m *ice.Message, cmd string, arg ...string) *ice.Message {
|
||||
return m.Cmdy(Space(m, kit.Keys(m.Option(DOMAIN), m.Option(mdb.NAME))), kit.Select(m.ActionKey(), cmd), arg)
|
||||
}
|
||||
|
||||
const (
|
||||
TARGET = "target"
|
||||
)
|
||||
const MATRIX = "matrix"
|
||||
|
||||
func init() {
|
||||
Index.MergeCommands(ice.Commands{
|
||||
MATRIX: {Name: "matrix refresh", Help: "矩阵", Icon: "Mission Control.png", Meta: kit.Dict(
|
||||
ice.CTX_ICONS, kit.Dict(STATUS, "bi bi-git"), ice.CTX_TRANS, kit.Dict(
|
||||
STATUS, "源码", html.INPUT, kit.Dict(MYSELF, "本机", ORIGIN, "主机"),
|
||||
),
|
||||
), Actions: ice.MergeActions(ice.Actions{
|
||||
mdb.INPUTS: {Hand: func(m *ice.Message, arg ...string) { m.Cmdy(SPIDE, mdb.INPUTS, arg) }},
|
||||
mdb.CREATE: {Name: "create origin* name icons", Hand: func(m *ice.Message, arg ...string) {
|
||||
m.Cmd(SPIDE, mdb.CREATE, m.OptionSimple("origin,name,icons,token"), mdb.TYPE, nfs.REPOS)
|
||||
m.Cmd(SPIDE, DEV_CREATE_TOKEN, ice.Maps{CLIENT_NAME: m.Option(mdb.NAME)})
|
||||
}},
|
||||
mdb.REMOVE: {Hand: func(m *ice.Message, arg ...string) { _matrix_dream(m, nfs.TRASH); _matrix_dream(m, "") }},
|
||||
cli.START: {Hand: func(m *ice.Message, arg ...string) { _matrix_dream(m, "") }},
|
||||
cli.STOP: {Hand: func(m *ice.Message, arg ...string) { _matrix_dream(m, "") }},
|
||||
UPGRADE: {Hand: func(m *ice.Message, arg ...string) { _matrix_cmd(m, "").Sleep3s(); m.ProcessRefresh() }},
|
||||
INSTALL: {Hand: func(m *ice.Message, arg ...string) {
|
||||
if kit.IsIn(m.Cmdv(Space(m, m.Option(DOMAIN)), SPIDE, ice.DEV_IP, CLIENT_HOSTNAME), m.Cmd(tcp.HOST).Appendv(aaa.IP)...) {
|
||||
m.Option(nfs.BINARY, S(m.Option(mdb.NAME)))
|
||||
} else {
|
||||
m.OptionDefault(nfs.BINARY, UserHost(m)+S(m.Option(mdb.NAME)))
|
||||
}
|
||||
_matrix_dream(m, mdb.CREATE, kit.Simple(m.OptionSimple(mdb.ICONS, nfs.REPOS, nfs.BINARY))...)
|
||||
m.Cmd(SPACE, kit.Keys(m.Option(DOMAIN), m.Option(mdb.NAME)), MESSAGE, mdb.CREATE, mdb.TYPE, ORIGIN, mdb.ICONS, m.Option(mdb.ICONS), TARGET, kit.Keys(nfs.FROM, m.Option(mdb.NAME)))
|
||||
m.Cmd(SPACE, m.Option(mdb.NAME), MESSAGE, mdb.CREATE, mdb.TYPE, SERVER, mdb.ICONS, m.Option(mdb.ICONS), TARGET, kit.Keys(ice.OPS, m.Option(DOMAIN), m.Option(mdb.NAME)))
|
||||
StreamPushRefreshConfirm(m, m.Trans("refresh for new space ", "刷新列表查看新空间 ")+kit.Keys(m.Option(DOMAIN), m.Option(mdb.NAME)))
|
||||
SpaceEvent(m, OPS_DREAM_SPAWN, "", m.OptionSimple(mdb.NAME, DOMAIN)...)
|
||||
}},
|
||||
}, ctx.ConfAction(
|
||||
mdb.FIELD, "time,domain,status,type,name,text,icons,repos,binary,module,version,access",
|
||||
ctx.TOOLS, kit.Simple("web.code.compose.insight", VERSION), ONLINE, ice.TRUE, cli.TIMEOUT, "10s",
|
||||
)), Hand: func(m *ice.Message, arg ...string) {
|
||||
if kit.HasPrefixList(arg, ctx.ACTION) {
|
||||
_matrix_action(m, arg[1], arg[2:]...)
|
||||
return
|
||||
}
|
||||
GoToast(m, func(toast func(name string, count, total int)) []string {
|
||||
field := kit.Split(mdb.Config(m, mdb.FIELD))
|
||||
space := m.CmdMap(SPACE, mdb.NAME)
|
||||
m.Options("space.timeout", mdb.Config(m, cli.TIMEOUT), "dream.simple", ice.TRUE)
|
||||
list, icons, types := _matrix_list(m, "", MYSELF, ice.Maps{
|
||||
mdb.TIME: ice.Info.Make.Time,
|
||||
mdb.ICONS: nfs.P + ice.SRC_MAIN_ICO,
|
||||
nfs.MODULE: ice.Info.Make.Module,
|
||||
nfs.VERSION: ice.Info.Make.Versions(),
|
||||
aaa.ACCESS: m.Option(ice.MSG_USERROLE),
|
||||
}, field...)
|
||||
kit.For(list, func(domain string, index int, total int) {
|
||||
toast(domain, index, total)
|
||||
_matrix_list(m, domain, types[index], ice.Maps{
|
||||
mdb.TIME: space[domain][mdb.TIME],
|
||||
mdb.ICONS: icons[index],
|
||||
nfs.MODULE: space[domain][nfs.MODULE],
|
||||
nfs.VERSION: space[domain][nfs.VERSION],
|
||||
aaa.ACCESS: kit.Format(kit.Value(space[domain], aaa.USERROLE)),
|
||||
}, field...)
|
||||
})
|
||||
m.RewriteAppend(func(value, key string, index int) string {
|
||||
if key == mdb.ICONS && kit.HasPrefix(value, nfs.P, nfs.REQUIRE) {
|
||||
if domain := m.Appendv(DOMAIN)[index]; domain != "" && space[domain][mdb.TYPE] == ORIGIN {
|
||||
value = kit.MergeURL2(space[domain][mdb.TEXT], value, m.Appendv(mdb.NAME)[index])
|
||||
} else if m.Appendv(mdb.TYPE)[index] == SERVER {
|
||||
value = kit.MergeURL(value, ice.POD, m.Appendv(DOMAIN)[index])
|
||||
} else if m.Appendv(mdb.TYPE)[index] == WORKER {
|
||||
value = kit.MergeURL(value, ice.POD, kit.Keys(m.Appendv(DOMAIN)[index], m.Appendv(mdb.NAME)[index]))
|
||||
}
|
||||
}
|
||||
return value
|
||||
})
|
||||
m.Action(mdb.CREATE, UPGRADE).StatusTimeCountStats(mdb.TYPE, mdb.STATUS).Display("")
|
||||
m.Sort("type,status,name,domain", []string{MYSELF, SERVER, ORIGIN, WORKER, ""}, []string{cli.START, cli.STOP, ""}, ice.STR_R, ice.STR_R)
|
||||
ctx.Toolkit(m)
|
||||
return nil
|
||||
})
|
||||
}},
|
||||
})
|
||||
}
|
77
base/web/matrix.js
Normal file
77
base/web/matrix.js
Normal file
@ -0,0 +1,77 @@
|
||||
Volcanos(chat.ONIMPORT, {
|
||||
_init: function(can, msg) { var list = {}, domain = [""], server = []
|
||||
msg.Table(function(value) { var name = value.name, _domain = value.domain
|
||||
list[name] = list[name]||{}, list[name][_domain] = value, domain.indexOf(_domain) == -1 && domain.push(_domain)
|
||||
value.type == web.SERVER && server.push(value.domain)
|
||||
}), can.db.list = list, can.db.domain = domain, can.db.server = server
|
||||
if (domain.length > can.core.Item(list).length) {
|
||||
can.ui = can.page.Appends(can, can._output, [{view: [wiki.CONTENT, html.TABLE], list: [
|
||||
{type: html.THEAD, list: [{type: html.TR, list: can.core.Item(list, function(name, value) {
|
||||
return {type: html.TH, list: [value[""]? can.onimport.item(can, value[""], list): can.onimport.void(can, name, domain, list)]}
|
||||
}) }]},
|
||||
{type: html.TBODY, list: can.core.List(domain, function(domain) { if (!domain) { return }
|
||||
return {type: html.TR, list: can.core.Item(list, function(name, value) { var item = value[domain]
|
||||
return {type: html.TD, list: [item? can.onimport.item(can, item, list): can.onimport.void(can, name, domain, list)]}
|
||||
})}
|
||||
})},
|
||||
] }]), can.onmotion.delay(can, function() { can.Status(mdb.COUNT, can.core.List(domain).length+"x"+can.core.Item(list).length) })
|
||||
} else {
|
||||
can.ui = can.page.Appends(can, can._output, [{view: [wiki.CONTENT, html.TABLE], list: [
|
||||
{type: html.THEAD, list: [{type: html.TR, list: can.core.List(domain, function(domain) {
|
||||
return {type: html.TH, list: [can.onimport.item(can, list[""][domain], list)]}
|
||||
}) }]},
|
||||
{type: html.TBODY, list: can.core.Item(list, function(name, value) { if (!name) { return }
|
||||
return {type: html.TR, list: can.core.List(domain, function(domain) { var item = value[domain]
|
||||
return {type: html.TD, list: [item? can.onimport.item(can, item, list): can.onimport.void(can, name, domain, list)]}
|
||||
})}
|
||||
})},
|
||||
] }]), can.onmotion.delay(can, function() { can.Status(mdb.COUNT, can.core.Item(list).length+"x"+can.core.List(domain).length) })
|
||||
}
|
||||
},
|
||||
void: function(can, name, domain, list) { var worker = list[name][""], server = list[""][domain]
|
||||
return {view: html.ACTION, _init: function(target) {
|
||||
worker && server.type != web.ORIGIN && can.onappend.input(can, {type: html.BUTTON, name: code.INSTALL, onclick: function(event) {
|
||||
can.Update(can.request(event, {name: name, domain: domain}, worker), [ctx.ACTION, code.INSTALL])
|
||||
}}, "", target)
|
||||
}}
|
||||
},
|
||||
item: function(can, item, list) { var name = item.name, domain = item.domain, worker = list[name][""], server = list[""][domain]; item["server.type"] = server.type
|
||||
function cb(action) { return function(event) { can.Update(can.request(event, item), [ctx.ACTION, action]) } }
|
||||
return {view: [[html.ITEM, item.type, item.status, can.onimport.style(can, item, list)]], list: [
|
||||
{img: item.icons, onclick: cb(web.DESKTOP)},
|
||||
{view: wiki.TITLE, list: [
|
||||
{text: item.name||item.domain||location.host, onclick: cb(web.OPEN)},
|
||||
item.status != cli.STOP && can.onappend.label(can, item, {version: icon.version, time: icon.compile, access: "bi bi-file-lock"}),
|
||||
{text: [item.text, "", mdb.STATUS]}, can.onappend.buttons(can, item),
|
||||
]},
|
||||
], _init: function(target) { item._target = target }}
|
||||
},
|
||||
style: function(can, item, list) { var name = item.name, domain = item.domain, worker = list[name][""]
|
||||
if (worker && worker.module != item.module) { return
|
||||
can.core.Item(list, function(key, value) { value = value[""]
|
||||
if (value.module == item.module) { worker = value }
|
||||
})
|
||||
}
|
||||
return !worker? html.NOTICE: (worker.status != cli.STOP && item.status != cli.STOP && (item.version != worker.version ||
|
||||
(item["server.type"] == "origin"? item.time > worker.time: item.time < worker.time)
|
||||
))? html.DANGER: ""
|
||||
},
|
||||
}, [""])
|
||||
Volcanos(chat.ONACTION, {
|
||||
upgrade: function(event, can) { var msg = can.request(event)
|
||||
if (msg.Option(mdb.NAME) || msg.Option(web.DOMAIN)) { return can.Update(event, [ctx.ACTION, code.UPGRADE]) }
|
||||
can.page.ClassList.add(can, can._output, ice.PROCESS)
|
||||
can.core.Next(can.db.server, function(server, next, index) {
|
||||
can.core.Next(can.core.Item(can.db.list, function(key, value) { return value }), function(list, next, i) {
|
||||
var item = list[server]; if (!item) { return next() } if (!item.name || item.status != cli.START) { return next() }
|
||||
can.page.ClassList.add(can, item._target, ice.PROCESS)
|
||||
can.Update(can.request({}, item, {_handle: ice.TRUE}), [ctx.ACTION, code.UPGRADE], function(msg) { next() })
|
||||
}, next)
|
||||
}, function() {
|
||||
can.core.Next(can.db.server, function(server, next, index) {
|
||||
var item = can.db.list[""][server]; can.page.ClassList.add(can, item._target, ice.PROCESS)
|
||||
can.Update(can.request({}, item, {_handle: ice.TRUE}), [ctx.ACTION, code.UPGRADE], function(msg) { next() })
|
||||
}, function() { can.onmotion.delay(can, function() {can.Update() }, 3000) })
|
||||
})
|
||||
},
|
||||
})
|
@ -2,121 +2,34 @@ package web
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"path"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
ice "shylinux.com/x/icebergs"
|
||||
"shylinux.com/x/icebergs/base/aaa"
|
||||
"shylinux.com/x/icebergs/base/cli"
|
||||
"shylinux.com/x/icebergs/base/ctx"
|
||||
"shylinux.com/x/icebergs/base/gdb"
|
||||
"shylinux.com/x/icebergs/base/mdb"
|
||||
"shylinux.com/x/icebergs/base/nfs"
|
||||
"shylinux.com/x/icebergs/base/tcp"
|
||||
kit "shylinux.com/x/toolkits"
|
||||
"shylinux.com/x/toolkits/file"
|
||||
)
|
||||
|
||||
func PushNotice(m *ice.Message, arg ...ice.Any) {
|
||||
if m.Option(ice.MSG_DAEMON) == "" {
|
||||
return
|
||||
}
|
||||
if m.Option(ice.MSG_USERPOD) == "" {
|
||||
msg := m.Spawn()
|
||||
msg.Optionv(ice.MSG_OPTS, msg.Optionv(ice.MSG_OPTION, []string{}))
|
||||
msg.Cmd(SPACE, m.Option(ice.MSG_DAEMON), arg)
|
||||
func UserWeb(m *ice.Message) *url.URL {
|
||||
return kit.ParseURL(m.OptionDefault(ice.MSG_USERWEB, "http://localhost:9020"))
|
||||
}
|
||||
func UserHost(m *ice.Message) string {
|
||||
if p := m.Option(ice.MSG_USERHOST); p != "" {
|
||||
return p
|
||||
} else if u := UserWeb(m); u.Hostname() == tcp.LOCALHOST {
|
||||
if ice.Info.Host != "" {
|
||||
return m.Option(ice.MSG_USERHOST, strings.ReplaceAll(u.Scheme+"://"+u.Host, tcp.LOCALHOST, ice.Info.Host))
|
||||
}
|
||||
return m.Option(ice.MSG_USERHOST, tcp.PublishLocalhost(m, u.Scheme+"://"+u.Host))
|
||||
} else {
|
||||
opts := kit.Dict(ice.POD, m.Option(ice.MSG_DAEMON), "cmds", kit.Simple(arg...))
|
||||
for _, k := range kit.Simple(m.Optionv(ice.MSG_OPTS)) {
|
||||
opts[k] = m.Option(k)
|
||||
}
|
||||
m.Cmd("web.spide", ice.OPS, MergeURL2(m, SHARE_TOAST), kit.Format(opts))
|
||||
return m.Option(ice.MSG_USERHOST, u.Scheme+"://"+u.Host)
|
||||
}
|
||||
}
|
||||
func PushNoticeGrow(m *ice.Message, arg ...ice.Any) {
|
||||
PushNotice(m, kit.List("grow", arg)...)
|
||||
}
|
||||
func PushNoticeToast(m *ice.Message, arg ...ice.Any) {
|
||||
PushNotice(m, kit.List("toast", arg)...)
|
||||
}
|
||||
func PushNoticeRefresh(m *ice.Message, arg ...ice.Any) {
|
||||
PushNotice(m, kit.List("refresh")...)
|
||||
}
|
||||
|
||||
func ToastProcess(m *ice.Message, arg ...ice.Any) func() {
|
||||
if len(arg) == 0 {
|
||||
arg = kit.List("", "-1")
|
||||
}
|
||||
if len(arg) == 1 {
|
||||
arg = append(arg, "-1")
|
||||
}
|
||||
Toast(m, ice.PROCESS, arg...)
|
||||
return func() { Toast(m, ice.SUCCESS) }
|
||||
}
|
||||
func ToastRestart(m *ice.Message, arg ...ice.Any) { Toast(m, gdb.RESTART, arg...) }
|
||||
func ToastFailure(m *ice.Message, arg ...ice.Any) { Toast(m, ice.FAILURE, arg...) }
|
||||
func ToastSuccess(m *ice.Message, arg ...ice.Any) { Toast(m, ice.SUCCESS, arg...) }
|
||||
func Toast(m *ice.Message, text string, arg ...ice.Any) { // [title [duration [progress]]]
|
||||
if len(arg) > 1 {
|
||||
switch val := arg[1].(type) {
|
||||
case string:
|
||||
if value, err := time.ParseDuration(val); err == nil {
|
||||
arg[1] = int(value / time.Millisecond)
|
||||
}
|
||||
}
|
||||
}
|
||||
PushNoticeToast(m, text, arg)
|
||||
}
|
||||
func Toast3s(m *ice.Message, text string, arg ...ice.Any) *ice.Message {
|
||||
Toast(m, text, kit.List(kit.Select("", arg, 0), kit.Select("3s", arg, 1))...)
|
||||
return m
|
||||
}
|
||||
func Toast30s(m *ice.Message, text string, arg ...ice.Any) {
|
||||
Toast(m, text, kit.List(kit.Select("", arg, 0), kit.Select("30s", arg, 1))...)
|
||||
}
|
||||
func GoToast(m *ice.Message, title string, cb func(toast func(string, int, int))) {
|
||||
cb(func(name string, count, total int) {
|
||||
Toast(m,
|
||||
kit.Format("%s %s/%s", name, strings.TrimSuffix(kit.FmtSize(int64(count)), "B"), strings.TrimSuffix(kit.FmtSize(int64(total)), "B")),
|
||||
kit.Format("%s %d%%", title, count*100/total),
|
||||
kit.Select("3000", "30000", count < total),
|
||||
count*100/total,
|
||||
)
|
||||
})
|
||||
}
|
||||
func PushStream(m *ice.Message, cmds ...ice.Any) *ice.Message {
|
||||
m.Option(cli.CMD_OUTPUT, file.NewWriteCloser(func(buf []byte) (int, error) {
|
||||
PushNoticeGrow(m, string(buf))
|
||||
return len(buf), nil
|
||||
}, func() error { PushNoticeToast(m, "done"); return nil }))
|
||||
m.ProcessHold()
|
||||
return m.Cmd(cmds...)
|
||||
}
|
||||
func PushPodCmd(m *ice.Message, cmd string, arg ...string) {
|
||||
if m.Length() > 0 && len(m.Appendv(ice.POD)) == 0 {
|
||||
m.Tables(func(value ice.Maps) { m.Push(ice.POD, m.Option(ice.MSG_USERPOD)) })
|
||||
}
|
||||
|
||||
m.Cmd(SPACE, ice.OptionFields(mdb.TYPE, mdb.NAME), func(value ice.Maps) {
|
||||
switch value[mdb.TYPE] {
|
||||
case SERVER, WORKER:
|
||||
if value[mdb.NAME] == ice.Info.Hostname {
|
||||
break
|
||||
}
|
||||
m.Cmd(SPACE, value[mdb.NAME], kit.Select(m.PrefixKey(), cmd), arg).Table(func(index int, val ice.Maps, head []string) {
|
||||
val[ice.POD] = kit.Keys(value[mdb.NAME], val[ice.POD])
|
||||
m.Push("", val, head)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
type Message interface {
|
||||
Option(key string, arg ...ice.Any) string
|
||||
PrefixKey(arg ...ice.Any) string
|
||||
}
|
||||
|
||||
func OptionAgentIs(m Message, arg ...string) bool {
|
||||
func AgentIs(m *ice.Message, arg ...string) bool {
|
||||
for _, k := range arg {
|
||||
if strings.HasPrefix(strings.ToLower(m.Option(ice.MSG_USERUA)), k) {
|
||||
return true
|
||||
@ -124,41 +37,69 @@ func OptionAgentIs(m Message, arg ...string) bool {
|
||||
}
|
||||
return false
|
||||
}
|
||||
func OptionUserWeb(m Message) *url.URL {
|
||||
return kit.ParseURL(m.Option(ice.MSG_USERWEB))
|
||||
}
|
||||
func MergeURL2(m Message, url string, arg ...ice.Any) string {
|
||||
if m.Option(ice.MSG_USERWEB) == "" {
|
||||
return kit.MergeURL2(ice.HTTP+"://"+ice.Pulse.Cmd(tcp.HOST).Append(aaa.IP)+":"+ice.Pulse.Cmd(SERVE).Append(tcp.PORT), url, arg...)
|
||||
func ParseLink(m *ice.Message, url string) ice.Maps {
|
||||
list := ice.Maps{}
|
||||
u := kit.ParseURL(url)
|
||||
switch arg := strings.Split(strings.TrimPrefix(u.Path, nfs.PS), nfs.PS); arg[0] {
|
||||
case CHAT:
|
||||
kit.For(arg[1:], func(k, v string) { list[k] = v })
|
||||
case SHARE:
|
||||
list[arg[0]] = arg[1]
|
||||
}
|
||||
return kit.MergeURL2(m.Option(ice.MSG_USERWEB), url, arg...)
|
||||
kit.For(u.Query(), func(k string, v []string) { list[k] = v[0] })
|
||||
return list
|
||||
}
|
||||
func MergeLink(m Message, url string, arg ...ice.Any) string {
|
||||
return strings.Split(MergeURL2(m, url, arg...), "?")[0]
|
||||
}
|
||||
func MergePod(m Message, pod string, arg ...ice.Any) string {
|
||||
return kit.MergePOD(kit.Select(ice.Info.Domain, m.Option(ice.MSG_USERWEB)), pod, arg...)
|
||||
}
|
||||
func MergePodCmd(m Message, pod, cmd string, arg ...ice.Any) string {
|
||||
p := "/chat"
|
||||
p += path.Join("/pod/", kit.Keys(m.Option(ice.MSG_USERPOD), pod))
|
||||
p = kit.Select(p, "/chat", p == "/chat/pod")
|
||||
p += path.Join("/cmd/", kit.Select(m.PrefixKey(), cmd))
|
||||
return kit.MergeURL2(kit.Select(ice.Info.Domain, m.Option(ice.MSG_USERWEB)), p, arg...)
|
||||
}
|
||||
func MergePodWebSite(m Message, pod, web string, arg ...ice.Any) string {
|
||||
p := "/chat"
|
||||
p += "/pod/" + kit.Keys(m.Option(ice.MSG_USERPOD), pod)
|
||||
p = kit.Select(p, "/chat/", p == "/chat/pod/")
|
||||
p += "/website/" + kit.Select("index.iml", web)
|
||||
return kit.MergeURL2(kit.Select(ice.Info.Domain, m.Option(ice.MSG_USERWEB)), p, arg...)
|
||||
}
|
||||
func ProcessWebsite(m *ice.Message, pod, cmd string, arg ...ice.Any) {
|
||||
m.ProcessOpen(MergePodCmd(m, pod, cmd, arg...))
|
||||
}
|
||||
func ProcessIframe(m *ice.Message, link string, arg ...string) {
|
||||
if len(arg) == 0 || arg[0] != ice.RUN {
|
||||
arg = []string{m.Cmdx("web.chat.iframe", mdb.CREATE, mdb.TYPE, LINK, mdb.NAME, "", LINK, link)}
|
||||
func PushPodCmd(m *ice.Message, cmd string, arg ...string) *ice.Message {
|
||||
if m.IsWorker() {
|
||||
return m
|
||||
}
|
||||
ctx.ProcessField(m, "web.chat.iframe", arg, arg...)
|
||||
msg := m.Spawn()
|
||||
m.Cmds(SPACE, func(value ice.Maps) {
|
||||
kit.If(kit.IsIn(value[mdb.TYPE], WORKER), func() { msg.Push(SPACE, value[mdb.NAME]) })
|
||||
})
|
||||
kit.If(m.Length() > 0 && len(m.Appendv(SPACE)) == 0, func() { m.Table(func(value ice.Maps) { m.Push(SPACE, "") }) })
|
||||
GoToastTable(msg, SPACE, func(value ice.Maps) {
|
||||
m.Cmd(SPACE, value[SPACE], kit.Dict(ice.MSG_USERPOD, value[SPACE]), kit.Select(m.ShortKey(), cmd), arg).Table(func(val ice.Maps, index int, head []string) {
|
||||
kit.If(!kit.IsIn(SPACE, head...), func() { head = append(head, SPACE) })
|
||||
val[SPACE] = kit.Keys(m.Option(ice.MSG_USERPOD), value[SPACE], val[SPACE])
|
||||
m.Push("", val, head)
|
||||
})
|
||||
})
|
||||
return m
|
||||
}
|
||||
func PushImages(m *ice.Message, name string) {
|
||||
if kit.ExtIsImage(name) {
|
||||
m.PushImages(IMAGE, name)
|
||||
} else if kit.ExtIsVideo(name) {
|
||||
m.PushVideos(VIDEO, name)
|
||||
}
|
||||
}
|
||||
func PushNotice(m *ice.Message, arg ...ice.Any) {
|
||||
if m.Option(ice.MSG_DAEMON) == "" {
|
||||
return
|
||||
}
|
||||
opts := ice.Map{ice.MSG_OPTION: []string{}, ice.MSG_OPTS: []string{}}
|
||||
kit.For([]string{ctx.DISPLAY, ctx.STYLE, cli.DELAY, ice.MSG_TITLE, ice.MSG_STATUS, ice.LOG_DEBUG, ice.LOG_TRACEID, ice.LOG_DISABLE}, func(key string) {
|
||||
opts[ice.MSG_OPTION], opts[key] = kit.Simple(opts[ice.MSG_OPTION], key), m.Option(key)
|
||||
})
|
||||
m.Cmd(SPACE, m.Option(ice.MSG_DAEMON), arg, opts)
|
||||
}
|
||||
func PushNoticeToast(m *ice.Message, arg ...ice.Any) {
|
||||
PushNotice(m, kit.List(TOAST, arg)...)
|
||||
}
|
||||
func PushNoticeRefresh(m *ice.Message, arg ...ice.Any) {
|
||||
PushNotice(m, kit.List("refresh", arg)...)
|
||||
}
|
||||
func PushNoticeGrow(m *ice.Message, arg ...ice.Any) {
|
||||
PushNotice(m.StatusTimeCount(), kit.List("grow", arg)...)
|
||||
}
|
||||
func PushNoticeRich(m *ice.Message, arg ...ice.Any) {
|
||||
PushNotice(m.StatusTimeCount(), kit.Simple("rich", arg))
|
||||
}
|
||||
func PushStream(m *ice.Message) *ice.Message {
|
||||
msg := m.SpawnSilent()
|
||||
m.Options(cli.CMD_OUTPUT, file.NewWriteCloser(func(buf []byte) { PushNoticeGrow(msg, string(buf)) }, nil)).ProcessHold(toastContent(m, ice.SUCCESS))
|
||||
return m
|
||||
}
|
||||
func init() { ice.Info.PushNotice = PushNotice }
|
||||
func init() { ice.Info.PushStream = PushStream }
|
||||
|
44
base/web/process.go
Normal file
44
base/web/process.go
Normal file
@ -0,0 +1,44 @@
|
||||
package web
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
ice "shylinux.com/x/icebergs"
|
||||
"shylinux.com/x/icebergs/base/ctx"
|
||||
"shylinux.com/x/icebergs/base/mdb"
|
||||
kit "shylinux.com/x/toolkits"
|
||||
)
|
||||
|
||||
func ProcessIframe(m *ice.Message, title, link string, arg ...string) *ice.Message {
|
||||
if m.IsMetaKey() {
|
||||
m.ProcessOpen(link)
|
||||
return m
|
||||
} else if !kit.HasPrefixList(arg, ctx.RUN) {
|
||||
defer m.Push(TITLE, title)
|
||||
}
|
||||
return ctx.ProcessFloat(m, CHAT_IFRAME, link, arg...)
|
||||
}
|
||||
func ProcessPodCmd(m *ice.Message, pod, cmd string, args ice.Any, arg ...string) *ice.Message {
|
||||
if kit.HasPrefixList(arg, ctx.RUN) {
|
||||
pod, cmd, arg = arg[1], arg[2], kit.Simple(arg[0], arg[3:])
|
||||
} else {
|
||||
cmd = kit.Select(m.ActionKey(), cmd)
|
||||
defer processSpace(m, pod, pod, cmd)
|
||||
}
|
||||
return ctx.ProcessFloat(m.Options(ice.POD, pod), cmd, args, arg...)
|
||||
}
|
||||
func ProcessHashPodCmd(m *ice.Message, arg ...string) (msg *ice.Message) {
|
||||
if kit.HasPrefixList(arg, ctx.RUN) {
|
||||
msg = mdb.HashSelects(m.Spawn(), arg[1])
|
||||
arg = kit.Simple(arg[0], arg[2:])
|
||||
} else {
|
||||
msg = mdb.HashSelects(m.Spawn(), m.Option(mdb.HASH))
|
||||
defer processSpace(m, msg.Append(SPACE), m.Option(mdb.HASH))
|
||||
}
|
||||
return ctx.ProcessFloat(m.Options(ice.POD, msg.Append(SPACE)), msg.Append(ctx.INDEX), kit.Split(msg.Append(ctx.ARGS)), arg...)
|
||||
}
|
||||
func processSpace(m *ice.Message, pod string, arg ...string) {
|
||||
m.ProcessField(kit.TransArgs(kit.Simple(ctx.ACTION, m.ActionKey(), ctx.RUN, arg))...)
|
||||
m.RewriteAppend(func(value, key string, index int) string { return kit.Select("", value, key != SPACE) })
|
||||
m.Push(ice.MSG_SPACE, strings.TrimPrefix(pod, "ops."))
|
||||
}
|
24
base/web/product.go
Normal file
24
base/web/product.go
Normal file
@ -0,0 +1,24 @@
|
||||
package web
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
ice "shylinux.com/x/icebergs"
|
||||
"shylinux.com/x/icebergs/base/ctx"
|
||||
"shylinux.com/x/icebergs/base/mdb"
|
||||
kit "shylinux.com/x/toolkits"
|
||||
)
|
||||
|
||||
const PRODUCT = "product"
|
||||
|
||||
func init() {
|
||||
Index.MergeCommands(ice.Commands{
|
||||
PRODUCT: {Name: "product refresh", Help: "产品展示", Actions: mdb.HashAction(mdb.SHORT, "index", mdb.FIELD, "time,name,text,order,disable,index,args"), Hand: func(m *ice.Message, arg ...string) {
|
||||
mdb.HashSelect(m, arg...).SortInt(mdb.ORDER)
|
||||
}},
|
||||
})
|
||||
}
|
||||
|
||||
func AddPortalProduct(m *ice.Message, name, text string, order float64, arg ...string) {
|
||||
m.Cmd("web.product", mdb.CREATE, mdb.NAME, name, mdb.TEXT, strings.TrimSpace(text), mdb.ORDER, order, ctx.INDEX, m.PrefixKey(), ctx.ARGS, kit.Format(arg))
|
||||
}
|
@ -9,92 +9,120 @@ import (
|
||||
"time"
|
||||
|
||||
ice "shylinux.com/x/icebergs"
|
||||
"shylinux.com/x/icebergs/base/aaa"
|
||||
"shylinux.com/x/icebergs/base/ctx"
|
||||
"shylinux.com/x/icebergs/base/log"
|
||||
"shylinux.com/x/icebergs/base/mdb"
|
||||
"shylinux.com/x/icebergs/base/nfs"
|
||||
"shylinux.com/x/icebergs/base/tcp"
|
||||
"shylinux.com/x/icebergs/base/web/html"
|
||||
kit "shylinux.com/x/toolkits"
|
||||
)
|
||||
|
||||
const (
|
||||
COOKIE = "cookie"
|
||||
STATUS = "status"
|
||||
)
|
||||
const (
|
||||
WEBSITE = "website"
|
||||
|
||||
CODE_INNER = "web.code.inner"
|
||||
WIKI_WORD = "web.wiki.word"
|
||||
STATUS = "status"
|
||||
HEADER = "header"
|
||||
COOKIE = "cookie"
|
||||
REQUEST = "request"
|
||||
RESPONSE = "response"
|
||||
CONTENT = "content"
|
||||
TITLE = "title"
|
||||
STYLE = "style"
|
||||
)
|
||||
|
||||
func renderMsg(m *ice.Message) {
|
||||
m.FormatsMeta(m.W,
|
||||
ice.MSG_USERIP, ice.MSG_USERUA, ice.MSG_METHOD, ice.MSG_REFERER, ice.MSG_DAEMON,
|
||||
ice.MSG_LANGUAGE, ice.MSG_THEME, ice.MSG_BG, ice.MSG_FG,
|
||||
ice.MSG_RIVER, ice.MSG_STORM, ice.MSG_INDEX, ice.MSG_FIELDS,
|
||||
ice.MSG_SOURCE, ice.MSG_TARGET,
|
||||
"task.id", "work.id", "space.timeout",
|
||||
ice.MSG_USERWEB0, ice.MSG_USERPOD0,
|
||||
)
|
||||
}
|
||||
func Render(m *ice.Message, cmd string, args ...ice.Any) bool {
|
||||
if cmd == ice.RENDER_VOID {
|
||||
return true
|
||||
}
|
||||
arg := kit.Simple(args...)
|
||||
if len(arg) == 0 {
|
||||
args = nil
|
||||
}
|
||||
if cmd != "" && cmd != ice.RENDER_DOWNLOAD {
|
||||
defer func() { m.Logs("Render", cmd, args) }()
|
||||
kit.If(len(arg) == 0, func() { args = nil })
|
||||
if cmd != "" {
|
||||
if cmd != ice.RENDER_DOWNLOAD || !kit.HasPrefix(arg[0], nfs.SRC, nfs.USR, ice.SRC_TEMPLATE, ice.USR_INTSHELL, ice.USR_VOLCANOS) {
|
||||
if !(cmd == ice.RENDER_RESULT && len(args) == 0) {
|
||||
defer func() { m.Logs("Render", cmd, args) }()
|
||||
}
|
||||
}
|
||||
}
|
||||
switch cmd {
|
||||
case COOKIE: // value [name [path [expire]]]
|
||||
RenderCookie(m, arg[0], arg[1:]...)
|
||||
|
||||
case STATUS, ice.RENDER_STATUS: // [code [text]]
|
||||
RenderStatus(m.W, kit.Int(kit.Select("200", arg, 0)), kit.Select("", arg, 1))
|
||||
|
||||
if m.IsCliUA() {
|
||||
RenderStatus(m.W, kit.Int(kit.Select("200", arg, 0)), kit.Select(m.Result(), strings.Join(kit.Slice(arg, 1), " ")))
|
||||
} else {
|
||||
m.W.WriteHeader(kit.Int(kit.Select("200", arg, 0)))
|
||||
renderMsg(m)
|
||||
}
|
||||
case ice.RENDER_REDIRECT: // url [arg...]
|
||||
http.Redirect(m.W, m.R, kit.MergeURL(arg[0], arg[1:]), http.StatusTemporaryRedirect)
|
||||
|
||||
http.Redirect(m.W, m.R, m.MergeLink(arg[0], arg[1:]), http.StatusTemporaryRedirect)
|
||||
case ice.RENDER_DOWNLOAD: // file [type [name]]
|
||||
if strings.HasPrefix(arg[0], ice.HTTP) {
|
||||
if strings.HasPrefix(arg[0], HTTP) {
|
||||
RenderRedirect(m, arg[0])
|
||||
break
|
||||
}
|
||||
RenderType(m.W, arg[0], kit.Select("", arg, 1))
|
||||
RenderHeader(m.W, "Content-Disposition", fmt.Sprintf("filename=%s", kit.Select(path.Base(kit.Select(arg[0], m.Option("filename"))), arg, 2)))
|
||||
if m.Option("render") == "replace" {
|
||||
res := m.Cmdx(nfs.CAT, arg[0])
|
||||
fieldset := "fieldset." + m.Option(ctx.INDEX)
|
||||
m.W.Write([]byte(kit.ReplaceAll(res,
|
||||
"$content", fieldset+">div.output>div.layout>div.layout>div.content",
|
||||
"$profile", fieldset+">div.output>div.layout>div.layout>div.profile",
|
||||
"$display", fieldset+">div.output>div.layout>div.display",
|
||||
"$project", fieldset+">div.output>div.project",
|
||||
"$option", fieldset+">form.option",
|
||||
"$action", fieldset+">div.action",
|
||||
"$output", fieldset+">div.output",
|
||||
"$status", fieldset+">div.status",
|
||||
"$fieldset", fieldset,
|
||||
"$body", "body.cmd."+m.Option(ctx.INDEX),
|
||||
"$index", m.Option(ctx.INDEX),
|
||||
"$input", "body>div.input.float."+m.Option(ctx.INDEX),
|
||||
)))
|
||||
break
|
||||
}
|
||||
if _, e := nfs.DiskFile.StatFile(arg[0]); e == nil {
|
||||
http.ServeFile(m.W, m.R, kit.Path(arg[0]))
|
||||
} else if f, e := nfs.PackFile.OpenFile(arg[0]); e == nil {
|
||||
defer f.Close()
|
||||
t, _ := time.ParseInLocation("2006-01-02 15:04:05", ice.Info.Make.When, time.Local)
|
||||
RenderHeader(m.W, "Last-Modified", t.UTC().Format(time.RFC1123))
|
||||
io.Copy(m.W, f)
|
||||
}
|
||||
|
||||
case ice.RENDER_RESULT:
|
||||
if len(arg) > 0 { // [str [arg...]]
|
||||
m.W.Write([]byte(kit.Format(arg[0], args[1:]...)))
|
||||
} else {
|
||||
if m.Result() == "" && m.Length() > 0 {
|
||||
m.Table()
|
||||
}
|
||||
kit.If(m.Result() == "" && m.Length() > 0, func() { m.TableEcho() })
|
||||
m.W.Write([]byte(m.Result()))
|
||||
}
|
||||
|
||||
case ice.RENDER_JSON:
|
||||
RenderType(m.W, nfs.JSON, "")
|
||||
m.W.Write([]byte(arg[0]))
|
||||
|
||||
default:
|
||||
for _, k := range kit.Simple(m.Optionv("option"), m.Optionv("_option")) {
|
||||
if m.Option(k) == "" {
|
||||
m.Set(k)
|
||||
}
|
||||
}
|
||||
for _, k := range []string{"sessid", "cmds", "fields", "_option", "_handle", "_output"} {
|
||||
m.Set(k)
|
||||
}
|
||||
if cmd != "" && cmd != ice.RENDER_RAW {
|
||||
m.Echo(kit.Format(cmd, args...))
|
||||
}
|
||||
kit.If(cmd != "" && cmd != ice.RENDER_RAW, func() { m.Echo(kit.Format(cmd, args...)) })
|
||||
RenderType(m.W, nfs.JSON, "")
|
||||
fmt.Fprint(m.W, m.FormatMeta())
|
||||
renderMsg(m)
|
||||
}
|
||||
m.Render(ice.RENDER_VOID)
|
||||
return true
|
||||
}
|
||||
|
||||
func CookieName(url string) string { return ice.MSG_SESSID + "_" + kit.ParseURLMap(url)[tcp.PORT] }
|
||||
func RenderCookie(m *ice.Message, value string, arg ...string) string { // name path expire
|
||||
http.SetCookie(m.W, &http.Cookie{Value: value, Name: kit.Select(CookieName(m.Option(ice.MSG_USERWEB)), arg, 0),
|
||||
Path: kit.Select(nfs.PS, arg, 1), Expires: time.Now().Add(kit.Duration(kit.Select(mdb.MONTH, arg, 2)))})
|
||||
return value
|
||||
}
|
||||
func RenderType(w http.ResponseWriter, name, mime string) {
|
||||
if mime == "" {
|
||||
switch kit.Ext(name) {
|
||||
@ -106,109 +134,124 @@ func RenderType(w http.ResponseWriter, name, mime string) {
|
||||
mime = "application/" + kit.Ext(name)
|
||||
}
|
||||
}
|
||||
RenderHeader(w, ContentType, mime)
|
||||
RenderHeader(w, html.ContentType, mime)
|
||||
}
|
||||
func RenderHeader(w http.ResponseWriter, key, value string) {
|
||||
w.Header().Set(key, value)
|
||||
}
|
||||
func RenderCookie(m *ice.Message, value string, arg ...string) { // name path expire
|
||||
expire := time.Now().Add(kit.Duration(kit.Select(m.Conf(aaa.SESS, kit.Keym(mdb.EXPIRE)), arg, 2)))
|
||||
http.SetCookie(m.W, &http.Cookie{Value: value,
|
||||
Name: kit.Select(CookieName(m.Option(ice.MSG_USERWEB)), arg, 0), Path: kit.Select(ice.PS, arg, 1), Expires: expire})
|
||||
func RenderOrigin(w http.ResponseWriter, origin string) {
|
||||
RenderHeader(w, "Access-Control-Allow-Origin", origin)
|
||||
}
|
||||
func RenderHeader(w http.ResponseWriter, key, value string) { w.Header().Set(key, value) }
|
||||
func RenderStatus(w http.ResponseWriter, code int, text string) {
|
||||
w.WriteHeader(code)
|
||||
w.Write([]byte(text))
|
||||
}
|
||||
func RenderRefresh(m *ice.Message, arg ...string) { // url text delay
|
||||
Render(m, ice.RENDER_RESULT, kit.Format(`
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="refresh" content="%s; url='%s'">
|
||||
</head>
|
||||
<body>
|
||||
%s
|
||||
</body>
|
||||
</html>
|
||||
`, kit.Select("3", arg, 2), kit.Select(m.Option(ice.MSG_USERWEB), arg, 0), kit.Select("loading...", arg, 1)))
|
||||
m.Render(ice.RENDER_VOID)
|
||||
func RenderRedirect(m *ice.Message, arg ...ice.Any) { Render(m, ice.RENDER_REDIRECT, arg...) }
|
||||
func RenderDownload(m *ice.Message, arg ...ice.Any) { Render(m, ice.RENDER_DOWNLOAD, arg...) }
|
||||
func RenderResult(m *ice.Message, arg ...ice.Any) { Render(m, ice.RENDER_RESULT, arg...) }
|
||||
func RenderTemplate(m *ice.Message, file string, arg ...ice.Any) *ice.Message {
|
||||
return m.RenderResult(kit.Renders(kit.Format(m.Cmdx(nfs.CAT, path.Join(ice.SRC_TEMPLATE, WEB, file)), arg...), m))
|
||||
}
|
||||
func RenderRedirect(m *ice.Message, arg ...ice.Any) {
|
||||
Render(m, ice.RENDER_REDIRECT, arg...)
|
||||
m.Render(ice.RENDER_VOID)
|
||||
}
|
||||
func RenderDownload(m *ice.Message, arg ...ice.Any) {
|
||||
Render(m, ice.RENDER_DOWNLOAD, arg...)
|
||||
m.Render(ice.RENDER_VOID)
|
||||
}
|
||||
func RenderResult(m *ice.Message, arg ...ice.Any) {
|
||||
Render(m, ice.RENDER_RESULT, arg...)
|
||||
m.Render(ice.RENDER_VOID)
|
||||
}
|
||||
|
||||
func CookieName(url string) string {
|
||||
return ice.MSG_SESSID + "_" + kit.ReplaceAll(kit.ParseURLMap(url)[tcp.PORT], ".", "_", ":", "_")
|
||||
return ice.MSG_SESSID + "_" + kit.ReplaceAll(kit.ParseURLMap(url)[tcp.HOST], ".", "_", ":", "_")
|
||||
}
|
||||
|
||||
func RenderIndex(m *ice.Message, repos string, file ...string) *ice.Message {
|
||||
if repos == "" {
|
||||
repos = kit.Select(ice.VOLCANOS, ice.INTSHELL, m.IsCliUA())
|
||||
func RenderMain(m *ice.Message) *ice.Message {
|
||||
if m.IsCliUA() {
|
||||
return m.RenderDownload(path.Join(ice.USR_INTSHELL, ice.INDEX_SH))
|
||||
}
|
||||
return m.RenderDownload(path.Join(m.Conf(SERVE, kit.Keym(repos, nfs.PATH)), kit.Select(m.Conf(SERVE, kit.Keym(repos, INDEX)), path.Join(file...))))
|
||||
m.Options(nfs.SCRIPT, ice.SRC_MAIN_JS, nfs.VERSION, RenderVersion(m))
|
||||
m.OptionDefault(mdb.ICONS, strings.Split(m.Resource(ice.Info.NodeIcon), "?")[0]+m.Option(nfs.VERSION))
|
||||
m.OptionDefault(TITLE, kit.Select("", ice.Info.Titles, ice.Info.Titles != "ContextOS"))
|
||||
kit.If(ice.Info.NodeType == WORKER, func() { m.OptionDefault(TITLE, m.Option(ice.MSG_USERPOD)) })
|
||||
m.OptionDefault(TITLE, kit.Select("ContextOS", UserWeb(m).Host))
|
||||
return m.RenderResult(kit.Renders(m.Cmdx(nfs.CAT, ice.SRC_MAIN_HTML), m))
|
||||
}
|
||||
func RenderMain(m *ice.Message, pod, index string, arg ...ice.Any) *ice.Message {
|
||||
if script := m.Cmdx(Space(m, pod), nfs.CAT, kit.Select(ice.SRC_MAIN_JS, index)); script != "" {
|
||||
return m.Echo(kit.Renders(_main_template, ice.Maps{
|
||||
"version": renderVersion(m), "script": script,
|
||||
})).RenderResult()
|
||||
}
|
||||
return RenderIndex(m, ice.VOLCANOS)
|
||||
}
|
||||
func RenderCmd(m *ice.Message, cmd string, arg ...ice.Any) {
|
||||
RenderPodCmd(m, "", cmd, arg...)
|
||||
func RenderCmds(m *ice.Message, cmds ...ice.Any) {
|
||||
RenderMain(m.Options(ctx.CMDS, kit.Format(cmds)))
|
||||
}
|
||||
func RenderPodCmd(m *ice.Message, pod, cmd string, arg ...ice.Any) {
|
||||
msg := m.Cmd(Space(m, pod), ctx.COMMAND, kit.Select("web.wiki.word", cmd))
|
||||
list := kit.Format(kit.List(kit.Dict(msg.AppendSimple(mdb.NAME, mdb.HELP),
|
||||
ctx.INDEX, cmd, ctx.ARGS, kit.Simple(arg), ctx.DISPLAY, m.Option(ice.MSG_DISPLAY),
|
||||
mdb.LIST, kit.UnMarshal(msg.Append(mdb.LIST)), mdb.META, kit.UnMarshal(msg.Append(mdb.META)),
|
||||
)))
|
||||
m.Echo(kit.Renders(_cmd_template, ice.Maps{
|
||||
"version": renderVersion(m), "list": list,
|
||||
})).RenderResult()
|
||||
}
|
||||
func renderVersion(m *ice.Message) string {
|
||||
if strings.Contains(m.R.URL.RawQuery, "debug=true") {
|
||||
return kit.Format("?_v=%v&_t=%d", ice.Info.Make.Version, time.Now().Unix())
|
||||
if msg := m.Cmd(Space(m, pod), ctx.COMMAND, kit.Select(m.ShortKey(), cmd)); msg.Length() == 0 {
|
||||
RenderResult(m, kit.Format("not found command %s", cmd))
|
||||
} else {
|
||||
if kit.IsIn(msg.Append(ctx.INDEX), "word", "vimer", "web.wiki.word", "web.code.vimer") {
|
||||
m.Option(mdb.ICONS, msg.Option(ice.MSG_NODEICON))
|
||||
}
|
||||
m.OptionDefault(mdb.ICONS, m.Resource(kit.Select(ice.Info.NodeIcon, msg.Option(ice.MSG_NODEICON), msg.Append(mdb.ICONS))))
|
||||
serve := strings.Split(UserHost(m), "://")[1]
|
||||
pod = kit.Select(pod, msg.Option(ice.MSG_NODENAME), m.Option(ice.MSG_USERPOD) != "")
|
||||
m.OptionDefault(TITLE, kit.Select(cmd, msg.Append(mdb.HELP), !m.IsEnglish())+" "+kit.Select(serve, pod))
|
||||
RenderCmds(m, kit.Dict(msg.AppendSimple(), ctx.ARGS, kit.Simple(arg), ctx.DISPLAY, m.Option(ice.MSG_DISPLAY)))
|
||||
}
|
||||
return ""
|
||||
}
|
||||
func RenderCmd(m *ice.Message, cmd string, arg ...ice.Any) { RenderPodCmd(m, "", cmd, arg...) }
|
||||
|
||||
func RenderVersion(m *ice.Message) string {
|
||||
ls := []string{ice.Info.Make.Versions()}
|
||||
if strings.Contains(ice.Info.Make.Domain, "debug=true") {
|
||||
if m.Option(log.DEBUG) == ice.TRUE || m.R != nil && strings.Contains(m.R.URL.RawQuery, "debug=true") {
|
||||
ls = append(ls, kit.Format("%d", time.Now().Unix()-kit.Time(ice.Info.Make.When)/int64(time.Second)))
|
||||
}
|
||||
}
|
||||
return "?" + kit.JoinQuery(kit.Simple(kit.Dict("_v", strings.Join(ls, "-"), ice.POD, m.Option(ice.MSG_USERPOD)))...)
|
||||
}
|
||||
|
||||
var _main_template = `<!DOCTYPE html>
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width,initial-scale=0.8,maximum-scale=0.8,user-scalable=no">
|
||||
<meta charset="utf-8"><title>volcanos</title>
|
||||
<link href="/favicon.ico" rel="shortcut icon" type="image/ico">
|
||||
<link href="/page/cache.css{{.version}}" rel="stylesheet">
|
||||
<link href="/page/index.css{{.version}}" rel="stylesheet">
|
||||
</head>
|
||||
<body>
|
||||
<script>_version = "{{.version}}"</script>
|
||||
<script src="/proto.js{{.version}}"></script>
|
||||
<script src="/page/cache.js{{.version}}"></script>
|
||||
<script>{{.script}}</script>
|
||||
</body>
|
||||
`
|
||||
const (
|
||||
PLAY = "play"
|
||||
SHOW = "show"
|
||||
|
||||
var _cmd_template = `<!DOCTYPE html>
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width,initial-scale=0.8,maximum-scale=0.8,user-scalable=no">
|
||||
<meta charset="utf-8"><title>volcanos</title>
|
||||
<link href="/page/can.css{{.version}}" rel="stylesheet">
|
||||
</head>
|
||||
<body>
|
||||
<script>_version = "{{.version}}"</script>
|
||||
<script src="/page/can.js{{.version}}"></script><script>Volcanos({{.list}})</script>
|
||||
</body>
|
||||
`
|
||||
CHAT = "chat"
|
||||
WORD = "word"
|
||||
VIMER = "vimer"
|
||||
XTERM = "xterm"
|
||||
GRANT = "grant"
|
||||
OAUTH = "oauth"
|
||||
DESKTOP = "desktop"
|
||||
MESSAGE = "message"
|
||||
|
||||
AUTOGEN = "autogen"
|
||||
BINPACK = "binpack"
|
||||
COMPILE = "compile"
|
||||
PUBLISH = "publish"
|
||||
VERSION = "version"
|
||||
UPGRADE = "upgrade"
|
||||
INSTALL = "install"
|
||||
|
||||
CODE_MYSQL_CLIENT = "web.code.mysql.client"
|
||||
CODE_MYSQL_QUERY = "web.code.mysql.query"
|
||||
CODE_GIT_SERVICE = "web.code.git.service"
|
||||
CODE_GIT_SEARCH = "web.code.git.search"
|
||||
CODE_GIT_STATUS = "web.code.git.status"
|
||||
CODE_GIT_REPOS = "web.code.git.repos"
|
||||
CODE_AUTOGEN = "web.code.autogen"
|
||||
CODE_COMPILE = "web.code.compile"
|
||||
CODE_PUBLISH = "web.code.publish"
|
||||
CODE_UPGRADE = "web.code.upgrade"
|
||||
CODE_VIMER = "web.code.vimer"
|
||||
CODE_INNER = "web.code.inner"
|
||||
CODE_XTERM = "web.code.xterm"
|
||||
CODE_MOD = "web.code.mod"
|
||||
WIKI_FEEL = "web.wiki.feel"
|
||||
WIKI_DRAW = "web.wiki.draw"
|
||||
WIKI_WORD = "web.wiki.word"
|
||||
WIKI_PORTAL = "web.wiki.portal"
|
||||
CHAT_OAUTH_CLIENT = "web.chat.oauth.client"
|
||||
CHAT_WX_ACCESS = "web.chat.wx.access"
|
||||
CHAT_WX_AGENT = "web.chat.wx.agent"
|
||||
CHAT_WX_TEMPLATE = "web.chat.wx.template"
|
||||
CHAT_WX_OCR = "web.chat.wx.ocr"
|
||||
CHAT_MESSAGE = "web.chat.message"
|
||||
CHAT_HEADER = "web.chat.header"
|
||||
CHAT_IFRAME = "web.chat.iframe"
|
||||
CHAT_FAVOR = "web.chat.favor"
|
||||
CHAT_FLOWS = "web.chat.flows"
|
||||
CHAT_GRANT = "web.chat.grant"
|
||||
CHAT_POD = "web.chat.pod"
|
||||
CHAT_CMD = "web.chat.cmd"
|
||||
TEAM_PLAN = "web.team.plan"
|
||||
TEAM_GONGANXITONG_USER = "web.team.gonganxitong.user"
|
||||
TEAM_GONGANXITONG_CITY = "web.team.gonganxitong.city"
|
||||
TEAM_GONGANXITONG_DOMAIN = "web.team.gonganxitong.domain"
|
||||
)
|
||||
|
||||
func MessageInsertJSON(m *ice.Message, zone, name, text string, arg ...string) {
|
||||
MessageInsert(m, zone, kit.Simple(mdb.TYPE, html.TEXT, mdb.NAME, kit.Select(m.CommandKey(), name),
|
||||
mdb.TEXT, text, ctx.DISPLAY, html.PLUGIN_JSON, arg)...)
|
||||
}
|
||||
func MessageInsert(m *ice.Message, zone string, arg ...string) {
|
||||
m.Cmd(MESSAGE, mdb.INSERT, zone, tcp.DIRECT, tcp.RECV, arg)
|
||||
}
|
||||
|
166
base/web/route.go
Normal file
166
base/web/route.go
Normal file
@ -0,0 +1,166 @@
|
||||
package web
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"runtime"
|
||||
|
||||
ice "shylinux.com/x/icebergs"
|
||||
"shylinux.com/x/icebergs/base/cli"
|
||||
"shylinux.com/x/icebergs/base/ctx"
|
||||
"shylinux.com/x/icebergs/base/lex"
|
||||
"shylinux.com/x/icebergs/base/mdb"
|
||||
"shylinux.com/x/icebergs/base/nfs"
|
||||
"shylinux.com/x/icebergs/base/tcp"
|
||||
"shylinux.com/x/icebergs/base/web/html"
|
||||
kit "shylinux.com/x/toolkits"
|
||||
)
|
||||
|
||||
func _route_push(m *ice.Message, space string, msg *ice.Message) *ice.Message {
|
||||
return msg.Table(func(value ice.Maps, index int, head []string) {
|
||||
value[SPACE], head = space, append(head, SPACE)
|
||||
m.Push("", value, head)
|
||||
})
|
||||
}
|
||||
func _route_match(m *ice.Message, space string, cb func(ice.Maps, int, []ice.Maps)) {
|
||||
reg, err := regexp.Compile(space)
|
||||
if m.WarnNotValid(err) {
|
||||
return
|
||||
}
|
||||
res := []ice.Maps{}
|
||||
list := kit.Split(space)
|
||||
m.Cmd("").Table(func(value ice.Maps) {
|
||||
if value[mdb.STATUS] == OFFLINE {
|
||||
|
||||
} else if value[SPACE] == space {
|
||||
res = append(res, value)
|
||||
} else if kit.IsIn(value[SPACE], list...) {
|
||||
res = append(res, value)
|
||||
} else if reg.MatchString(kit.Format("%s:%s=%s@%s", value[SPACE], value[mdb.TYPE], value[nfs.MODULE], value[nfs.VERSION])) {
|
||||
res = append(res, value)
|
||||
}
|
||||
})
|
||||
for i, item := range res {
|
||||
cb(item, i, res)
|
||||
}
|
||||
}
|
||||
func _route_toast(m *ice.Message, space string, args ...string) {
|
||||
GoToast(m, func(toast func(string, int, int)) (list []string) {
|
||||
count, total := 0, 1
|
||||
_route_match(m, space, func(value ice.Maps, i int, _list []ice.Maps) {
|
||||
count, total = i, len(_list)
|
||||
toast(value[SPACE], count, total)
|
||||
if msg := _route_push(m, value[SPACE], m.Cmd(SPACE, value[SPACE], args, ice.Maps{ice.MSG_DAEMON: ""})); msg.IsErr() || !cli.IsSuccess(msg) {
|
||||
list = append(list, value[SPACE]+": "+msg.Result())
|
||||
} else {
|
||||
kit.If(msg.Result() == "", func() { msg.TableEcho() })
|
||||
m.Push(SPACE, value[SPACE]).Push(ice.RES, msg.Result())
|
||||
}
|
||||
})
|
||||
m.StatusTimeCount(ice.CMD, kit.Join(args, lex.SP), ice.SUCCESS, kit.Format("%d/%d", total-len(list), total))
|
||||
return
|
||||
})
|
||||
}
|
||||
|
||||
const (
|
||||
ONLINE = "online"
|
||||
OFFLINE = "offline"
|
||||
)
|
||||
const ROUTE = "route"
|
||||
|
||||
func init() {
|
||||
Index.MergeCommands(ice.Commands{
|
||||
ROUTE: {Name: "route space:text cmds:text auto build travel diagram prunes", Help: "路由表", Icon: "Shortcuts.png", Actions: ice.MergeActions(ice.Actions{
|
||||
ice.MAIN: {Help: "首页", Hand: func(m *ice.Message, arg ...string) { ctx.ProcessField(m, CHAT_IFRAME, m.MergePod(""), arg...) }},
|
||||
mdb.INPUTS: {Hand: func(m *ice.Message, arg ...string) {
|
||||
switch mdb.HashInputs(m, arg); arg[0] {
|
||||
case SPACE:
|
||||
list := map[string]bool{}
|
||||
push := func(key string) { kit.If(!list[key], func() { m.Push(arg[0], key); list[key] = true }) }
|
||||
mdb.HashSelect(m.Spawn()).Table(func(value ice.Maps) { push(kit.Format("=%s@", value[nfs.MODULE])) })
|
||||
kit.For([]string{WORKER, SERVER}, func(key string) { push(kit.Format(":%s=", key)) })
|
||||
}
|
||||
}},
|
||||
ctx.CMDS: {Name: "cmds space index* args", Help: "命令", Hand: func(m *ice.Message, arg ...string) {
|
||||
_route_toast(m, m.Option(SPACE), append([]string{m.Option(ctx.INDEX)}, kit.Split(m.Option(ctx.ARGS))...)...)
|
||||
}},
|
||||
cli.BUILD: {Name: "build space", Help: "构建", Hand: func(m *ice.Message, arg ...string) {
|
||||
m.Option(ice.MSG_TITLE, kit.Keys(m.Option(ice.MSG_USERPOD0), m.Option(ice.MSG_USERPOD), m.CommandKey()))
|
||||
_route_toast(m, m.Option(SPACE), cli.RUNTIME, UPGRADE)
|
||||
m.SetAppend().Cmdy("", "travel")
|
||||
}},
|
||||
"travel": {Help: "遍历", Icon: "bi bi-card-list", Hand: func(m *ice.Message, arg ...string) {
|
||||
kit.For(kit.Split(m.OptionDefault(ice.MSG_FIELDS, mdb.Config(m, mdb.FIELD))), func(key string) {
|
||||
switch key {
|
||||
case mdb.TIME:
|
||||
m.Push(key, ice.Info.Make.Time)
|
||||
case mdb.TYPE:
|
||||
m.Push(key, ice.Info.NodeType)
|
||||
case nfs.MODULE:
|
||||
m.Push(key, ice.Info.Make.Module)
|
||||
case nfs.VERSION:
|
||||
m.Push(key, ice.Info.Make.Versions())
|
||||
case cli.COMMIT_TIME:
|
||||
m.Push(key, ice.Info.Make.When)
|
||||
case cli.COMPILE_TIME:
|
||||
m.Push(key, ice.Info.Make.Time)
|
||||
case cli.BOOT_TIME:
|
||||
m.Push(key, m.Cmdx(cli.RUNTIME, "boot.time"))
|
||||
case "md5":
|
||||
m.Push(key, ice.Info.Hash)
|
||||
case nfs.SIZE:
|
||||
var stats runtime.MemStats
|
||||
runtime.ReadMemStats(&stats)
|
||||
m.Push(key, kit.Format("%s/%s/%s", ice.Info.Size, kit.FmtSize(int64(stats.Sys)), m.Cmdx(nfs.DIR, nfs.SIZE)))
|
||||
case nfs.PATH:
|
||||
m.Push(key, kit.Path(""))
|
||||
case tcp.HOSTNAME:
|
||||
m.Push(key, ice.Info.Hostname)
|
||||
default:
|
||||
m.Push(key, "")
|
||||
}
|
||||
})
|
||||
defer m.ProcessRefresh()
|
||||
PushPodCmd(m, "", m.ActionKey())
|
||||
m.Table(func(value ice.Maps) { kit.If(value[SPACE], func() { mdb.HashCreate(m.Spawn(), kit.Simple(value)) }) })
|
||||
}},
|
||||
"diagram": {Help: "导图", Icon: "bi bi-diagram-3", Hand: func(m *ice.Message, arg ...string) {
|
||||
ctx.DisplayStorySpide(m.Cmdy(""), nfs.DIR_ROOT, ice.Info.NodeName, mdb.FIELD, SPACE, lex.SPLIT, nfs.PT, ctx.ACTION, ice.MAIN)
|
||||
}},
|
||||
mdb.PRUNES: &ice.Action{Name: "prunes status=offline", Hand: func(m *ice.Message, arg ...string) {
|
||||
m.Cmd("", func(value ice.Maps) {
|
||||
kit.If(value[mdb.STATUS] == OFFLINE, func() { mdb.HashRemove(m, SPACE, value[SPACE]) })
|
||||
})
|
||||
m.ProcessRefresh()
|
||||
}},
|
||||
}, mdb.HashAction(mdb.SHORT, SPACE, mdb.FIELD, "time,space,type,module,version,commitTime,compileTime,bootTime,md5,size,path,hostname", mdb.SORT, "type,space", html.CHECKBOX, ice.TRUE, mdb.ACTION, ice.MAIN)), Hand: func(m *ice.Message, arg ...string) {
|
||||
if len(arg) > 1 {
|
||||
_route_match(m, arg[0], func(value ice.Maps, i int, list []ice.Maps) {
|
||||
_route_push(m, value[SPACE], m.Cmd(SPACE, value[SPACE], arg[1:]))
|
||||
})
|
||||
} else if mdb.HashSelect(m, arg...); len(arg) > 0 {
|
||||
m.EchoIFrame(m.MergePod(arg[0]))
|
||||
} else {
|
||||
m.OptionFields("")
|
||||
list := m.CmdMap(SPACE, mdb.NAME)
|
||||
lists := m.CmdMap(DREAM, mdb.NAME)
|
||||
mem, disk, stat := 0, 0, map[string]int{}
|
||||
m.Table(func(value ice.Maps) {
|
||||
disk += kit.Int(kit.Select("", kit.Split(value[nfs.SIZE], nfs.PS), 2))
|
||||
mem += kit.Int(kit.Select("", kit.Split(value[nfs.SIZE], nfs.PS), 0))
|
||||
if _, ok := list[value[SPACE]]; ok {
|
||||
m.Push(mdb.STATUS, ONLINE)
|
||||
stat[ONLINE]++
|
||||
} else {
|
||||
m.Push(mdb.STATUS, OFFLINE)
|
||||
stat[OFFLINE]++
|
||||
}
|
||||
if v, ok := lists[value[SPACE]]; ok {
|
||||
m.Push(mdb.ICONS, v[mdb.ICONS])
|
||||
} else {
|
||||
m.Push(mdb.ICONS, "")
|
||||
}
|
||||
}).Sort("status,space", ice.STR_R, ice.STR).StatusTimeCount(stat, nfs.SIZE, kit.Format("%s/%s", kit.FmtSize(mem), kit.FmtSize(disk))).Options(ice.MSG_ACTION, "")
|
||||
}
|
||||
}},
|
||||
})
|
||||
}
|
@ -1,9 +1,13 @@
|
||||
package web
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
ice "shylinux.com/x/icebergs"
|
||||
@ -11,252 +15,422 @@ import (
|
||||
"shylinux.com/x/icebergs/base/cli"
|
||||
"shylinux.com/x/icebergs/base/ctx"
|
||||
"shylinux.com/x/icebergs/base/gdb"
|
||||
"shylinux.com/x/icebergs/base/lex"
|
||||
"shylinux.com/x/icebergs/base/log"
|
||||
"shylinux.com/x/icebergs/base/mdb"
|
||||
"shylinux.com/x/icebergs/base/nfs"
|
||||
"shylinux.com/x/icebergs/base/ssh"
|
||||
"shylinux.com/x/icebergs/base/tcp"
|
||||
"shylinux.com/x/icebergs/base/web/html"
|
||||
kit "shylinux.com/x/toolkits"
|
||||
"shylinux.com/x/toolkits/logs"
|
||||
)
|
||||
|
||||
func _serve_address(m *ice.Message) string { return HostPort(m, tcp.LOCALHOST, m.Option(tcp.PORT)) }
|
||||
func _serve_start(m *ice.Message) {
|
||||
if m.Option(aaa.USERNAME) != "" {
|
||||
aaa.UserRoot(m, m.Option(aaa.USERNAME), m.Option(aaa.USERNICK))
|
||||
}
|
||||
if cli.NodeInfo(m, kit.Select(ice.Info.Hostname, m.Option("nodename")), SERVER); m.Option(tcp.PORT) == tcp.RANDOM {
|
||||
m.Option(tcp.PORT, m.Cmdx(tcp.PORT, aaa.RIGHT))
|
||||
}
|
||||
m.Target().Start(m, m.OptionSimple(tcp.HOST, tcp.PORT)...)
|
||||
m.Sleep30ms().Go(func() { m.Cmd(BROAD, SERVE, m.OptionSimple(tcp.PORT)) })
|
||||
for _, v := range kit.Split(m.Option(ice.DEV)) {
|
||||
m.Cmd(SPACE, tcp.DIAL, ice.DEV, v, mdb.NAME, ice.Info.NodeName)
|
||||
kit.If(m.Option(aaa.USERNAME), func() { aaa.UserRoot(m, "", m.Option(aaa.USERNAME), m.Option(aaa.USERNICK), m.Option(aaa.LANGUAGE)) })
|
||||
kit.If(m.Option(tcp.PORT) == tcp.RANDOM, func() { m.Option(tcp.PORT, m.Cmdx(tcp.PORT, aaa.RIGHT)) })
|
||||
m.Go(func() {
|
||||
m.Cmd(SPIDE, ice.OPS, _serve_address(m)+nfs.PS+ice.EXIT, ice.Maps{CLIENT_TIMEOUT: cli.TIME_30ms, ice.LOG_DISABLE: ice.TRUE})
|
||||
}).Sleep(cli.TIME_1s)
|
||||
cli.NodeInfo(m, kit.Select(kit.Split(ice.Info.Hostname, nfs.PT)[0], m.Option(tcp.NODENAME)), SERVER, mdb.Config(m, mdb.ICONS))
|
||||
kit.If(ice.HasVar(), func() { m.Cmd(nfs.SAVE, ice.VAR_LOG_ICE_PORT, m.Option(tcp.PORT)) })
|
||||
kit.For(kit.Split(m.Option(ice.DEV)), func(dev string) {
|
||||
if strings.HasPrefix(dev, HTTP) {
|
||||
m.Cmd(SPIDE, mdb.CREATE, dev, ice.DEV, "", nfs.REPOS)
|
||||
m.Cmd(SPIDE, mdb.CREATE, dev, "dev_ip", "", "dev_ip")
|
||||
dev = ice.DEV
|
||||
}
|
||||
if msg := m.Cmd(SPIDE, dev); msg.Append(TOKEN) == "" {
|
||||
if m.Option(TOKEN) != "" {
|
||||
m.Cmd(SPACE, tcp.DIAL, ice.DEV, dev, TOKEN, m.Option(TOKEN))
|
||||
} else {
|
||||
m.Cmd(SPACE, tcp.DIAL, ice.DEV, dev)
|
||||
}
|
||||
}
|
||||
})
|
||||
m.Spawn(ice.Maps{TOKEN: ""}).Start("", m.OptionSimple(tcp.HOST, tcp.PORT)...)
|
||||
if m.Cmd(tcp.HOST).Length() == 0 {
|
||||
return
|
||||
}
|
||||
}
|
||||
func _serve_main(m *ice.Message, w http.ResponseWriter, r *http.Request) bool {
|
||||
const (
|
||||
X_REAL_IP = "X-Real-Ip"
|
||||
X_REAL_PORT = "X-Real-Port"
|
||||
X_FORWARDED_FOR = "X-Forwarded-For"
|
||||
INDEX_MODULE = "Index-Module"
|
||||
MOZILLA = "Mozilla/5.0"
|
||||
X_REAL_IP = "X-Real-Ip"
|
||||
X_REAL_PORT = "X-Real-Port"
|
||||
INDEX_MODULE = "Index-Module"
|
||||
)
|
||||
if r.Header.Get(INDEX_MODULE) == "" {
|
||||
r.Header.Set(INDEX_MODULE, m.Prefix())
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
func() {
|
||||
defer InfoLock.Lock()()
|
||||
Info.ServeMainCount++
|
||||
}()
|
||||
if ip := r.Header.Get(X_REAL_IP); ip != "" {
|
||||
if r.Header.Set(ice.MSG_USERIP, ip); r.Header.Get(X_REAL_PORT) != "" {
|
||||
r.Header.Set(ice.MSG_USERADDR, ip+ice.DF+r.Header.Get(X_REAL_PORT))
|
||||
r.Header.Set(ice.MSG_USERADDR, ip+nfs.DF+r.Header.Get(X_REAL_PORT))
|
||||
}
|
||||
} else if ip := r.Header.Get(X_FORWARDED_FOR); ip != "" {
|
||||
} else if ip := r.Header.Get(html.XForwardedFor); ip != "" {
|
||||
r.Header.Set(ice.MSG_USERIP, kit.Split(ip)[0])
|
||||
} else if strings.HasPrefix(r.RemoteAddr, "[") {
|
||||
r.Header.Set(ice.MSG_USERIP, strings.Split(r.RemoteAddr, "]")[0][1:])
|
||||
} else {
|
||||
r.Header.Set(ice.MSG_USERIP, strings.Split(r.RemoteAddr, ice.DF)[0])
|
||||
r.Header.Set(ice.MSG_USERIP, strings.Split(r.RemoteAddr, nfs.DF)[0])
|
||||
}
|
||||
if m.Logs(r.Header.Get(ice.MSG_USERIP), r.Method, r.URL.String()); m.Config(LOGHEADERS) == ice.TRUE {
|
||||
kit.Fetch(r.Header, func(k string, v []string) { m.Logs("Header", k, v) })
|
||||
if !kit.HasPrefix(r.URL.String(), nfs.VOLCANOS, nfs.REQUIRE_MODULES, nfs.INTSHELL) {
|
||||
r.Header.Set(ice.LOG_TRACEID, log.Traceid(m))
|
||||
m.Logs(r.Header.Get(ice.MSG_USERIP), r.Method, r.URL.String(), logs.TraceidMeta(r.Header.Get(ice.LOG_TRACEID)))
|
||||
}
|
||||
if r.Method == http.MethodGet && r.URL.Path != PP(SPACE) && !strings.HasPrefix(r.URL.Path, "/code/bash") {
|
||||
repos := kit.Select(ice.INTSHELL, ice.VOLCANOS, strings.Contains(r.Header.Get(UserAgent), MOZILLA))
|
||||
if p := path.Join(ice.USR, repos, r.URL.Path); r.URL.Path != ice.PS && nfs.ExistsFile(m, p) {
|
||||
Render(m.Spawn(w, r), ice.RENDER_DOWNLOAD, p)
|
||||
return false
|
||||
} else if msg := gdb.Event(m.Spawn(w, r), SERVE_REWRITE, r.Method, r.URL.Path, path.Join(m.Conf(SERVE, kit.Keym(repos, nfs.PATH)), r.URL.Path), repos); msg.Option(ice.MSG_OUTPUT) != "" {
|
||||
Render(msg, msg.Option(ice.MSG_OUTPUT), kit.List(msg.Optionv(ice.MSG_ARGS))...)
|
||||
if path.Join(r.URL.Path) == nfs.PS && strings.HasPrefix(r.UserAgent(), html.Mozilla) {
|
||||
r.URL.Path = kit.Select(nfs.PS, mdb.Config(m, ice.MAIN))
|
||||
}
|
||||
if r.Method == http.MethodGet {
|
||||
msg := m.Spawn(w, r).Options(ice.MSG_USERUA, r.UserAgent(), ice.LOG_TRACEID, r.Header.Get(ice.LOG_TRACEID), ParseLink(m, kit.Select(r.URL.String(), r.Referer())))
|
||||
if path.Join(r.URL.Path) == nfs.PS {
|
||||
msg.Options(ice.MSG_USERWEB, _serve_domain(msg))
|
||||
if Render(RenderMain(msg), msg.Option(ice.MSG_OUTPUT), kit.List(msg.Optionv(ice.MSG_ARGS))...) {
|
||||
return false
|
||||
}
|
||||
} else if _serve_static(msg, w, r) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
func _serve_handle(key string, cmd *ice.Command, m *ice.Message, w http.ResponseWriter, r *http.Request) {
|
||||
if u, e := url.Parse(r.Header.Get(Referer)); e == nil && r.URL.Path != PP(SPACE) {
|
||||
gdb.Event(m, SERVE_PARSE, strings.Split(strings.TrimPrefix(u.Path, ice.PS), ice.PS))
|
||||
kit.Fetch(u.Query(), func(k string, v []string) { m.Logs("Refer", k, v).Optionv(k, v) })
|
||||
func _serve_static(msg *ice.Message, w http.ResponseWriter, r *http.Request) bool {
|
||||
// _serve_params(msg, r.Header.Get(html.Referer))
|
||||
if strings.HasPrefix(r.URL.Path, "/.git/") {
|
||||
return false
|
||||
}
|
||||
m.Option(ice.MSG_USERUA, r.Header.Get(UserAgent))
|
||||
for k, v := range kit.ParseQuery(r.URL.RawQuery) {
|
||||
kit.If(m.IsCliUA(), func() { v = kit.Simple(v, func(v string) (string, error) { return url.QueryUnescape(v) }) })
|
||||
m.Optionv(k, v)
|
||||
}
|
||||
switch r.Header.Get(ContentType) {
|
||||
case ContentJSON:
|
||||
data := kit.UnMarshal(r.Body)
|
||||
m.Logs(mdb.IMPORT, mdb.VALUE, kit.Format(data)).Optionv(ice.MSG_USERDATA, data)
|
||||
kit.Fetch(data, func(k string, v ice.Any) { m.Optionv(k, v) })
|
||||
default:
|
||||
r.ParseMultipartForm(kit.Int64(kit.Select("4096", r.Header.Get(ContentLength))))
|
||||
kit.Fetch(r.PostForm, func(k string, v []string) {
|
||||
kit.If(m.IsCliUA(), func() { v = kit.Simple(v, func(v string) (string, error) { return url.QueryUnescape(v) }) })
|
||||
m.Logs("Form", k, kit.Join(v, ice.SP)).Optionv(k, v)
|
||||
})
|
||||
}
|
||||
kit.Fetch(r.Cookies(), func(k, v string) { m.Optionv(k, v) })
|
||||
m.OptionDefault(ice.HEIGHT, "480", ice.WIDTH, "320")
|
||||
m.Option(ice.MSG_USERUA, r.Header.Get(UserAgent))
|
||||
m.Option(ice.MSG_USERIP, r.Header.Get(ice.MSG_USERIP))
|
||||
m.Option(ice.MSG_USERADDR, kit.Select(r.RemoteAddr, r.Header.Get(ice.MSG_USERADDR)))
|
||||
if m.Option(ice.MSG_USERWEB, _serve_domain(m)); m.Option(ice.POD) != "" {
|
||||
m.Option(ice.MSG_USERPOD, m.Option(ice.POD))
|
||||
}
|
||||
u := OptionUserWeb(m)
|
||||
m.Option(ice.MSG_USERHOST, u.Scheme+"//"+u.Host)
|
||||
m.Option(ice.MSG_SESSID, m.Option(CookieName(m.Option(ice.MSG_USERWEB))))
|
||||
if m.Optionv(ice.MSG_CMDS) == nil {
|
||||
if p := strings.TrimPrefix(r.URL.Path, key); p != "" {
|
||||
m.Optionv(ice.MSG_CMDS, strings.Split(p, ice.PS))
|
||||
_serve_params(msg, r.URL.String())
|
||||
ispod := msg.Option(ice.POD) != ""
|
||||
if strings.HasPrefix(r.URL.Path, nfs.V) {
|
||||
return Render(msg, ice.RENDER_DOWNLOAD, path.Join(ice.USR_VOLCANOS, strings.TrimPrefix(r.URL.Path, nfs.V)))
|
||||
} else if kit.HasPrefix(r.URL.Path, nfs.P) {
|
||||
if kit.Contains(r.URL.String(), "render=replace") {
|
||||
return false
|
||||
}
|
||||
p := path.Join(strings.TrimPrefix(r.URL.Path, nfs.P))
|
||||
if pp := path.Join(nfs.USR_LOCAL_WORK, msg.Option(ice.POD)); ispod && nfs.Exists(msg, pp) && !strings.HasPrefix(p, "require/") {
|
||||
if kit.HasPrefix(p, "var/", "usr/local/") {
|
||||
return false
|
||||
}
|
||||
if pp = path.Join(pp, p); nfs.Exists(msg, pp) {
|
||||
return Render(msg, ice.RENDER_DOWNLOAD, pp)
|
||||
} else if nfs.Exists(msg, p) {
|
||||
return Render(msg, ice.RENDER_DOWNLOAD, p)
|
||||
}
|
||||
}
|
||||
if kit.HasPrefix(p, ice.USR_ICEBERGS, ice.USR_ICONS) && nfs.Exists(msg, p) {
|
||||
return Render(msg, ice.RENDER_DOWNLOAD, p)
|
||||
}
|
||||
if !ispod {
|
||||
return (kit.HasPrefix(p, nfs.SRC) && nfs.Exists(msg, p)) && Render(msg, ice.RENDER_DOWNLOAD, p)
|
||||
}
|
||||
} else if kit.HasPrefix(r.URL.Path, nfs.M) {
|
||||
p := nfs.USR_MODULES + strings.TrimPrefix(r.URL.Path, nfs.M)
|
||||
return nfs.Exists(msg, p) && Render(msg, ice.RENDER_DOWNLOAD, p)
|
||||
} else if kit.HasPrefix(path.Base(r.URL.Path), "MP_verify_") {
|
||||
return Render(msg, ice.RENDER_DOWNLOAD, nfs.ETC+path.Base(r.URL.Path))
|
||||
} else if p := path.Join(kit.Select(ice.USR_VOLCANOS, ice.USR_INTSHELL, msg.IsCliUA()), r.URL.Path); nfs.Exists(msg, p) {
|
||||
return Render(msg, ice.RENDER_DOWNLOAD, p)
|
||||
} else if p = path.Join(nfs.USR, r.URL.Path); kit.HasPrefix(r.URL.Path, nfs.VOLCANOS, nfs.INTSHELL) && nfs.Exists(msg, p) {
|
||||
return Render(msg, ice.RENDER_DOWNLOAD, p)
|
||||
}
|
||||
if cmds, ok := _serve_login(m, key, kit.Simple(m.Optionv(ice.MSG_CMDS)), w, r); ok {
|
||||
defer func() { m.Cost(kit.Format("%s %v %v", r.URL.Path, cmds, m.FormatSize())) }()
|
||||
return false
|
||||
p := ""
|
||||
if p = strings.TrimPrefix(r.URL.Path, nfs.REQUIRE); kit.HasPrefix(r.URL.Path, nfs.REQUIRE_SRC, nfs.REQUIRE+ice.USR_ICONS, nfs.REQUIRE+ice.USR_ICEBERGS) && nfs.Exists(msg, p) {
|
||||
return !ispod && Render(msg, ice.RENDER_DOWNLOAD, p)
|
||||
} else if p = path.Join(nfs.USR_MODULES, strings.TrimPrefix(r.URL.Path, nfs.REQUIRE_MODULES)); kit.HasPrefix(r.URL.Path, nfs.REQUIRE_MODULES) && nfs.Exists(msg, p) {
|
||||
return Render(msg, ice.RENDER_DOWNLOAD, p)
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
func _serve_params(m *ice.Message, p string) {
|
||||
if u, e := url.Parse(p); e == nil {
|
||||
switch arg := strings.Split(strings.TrimPrefix(u.Path, nfs.PS), nfs.PS); arg[0] {
|
||||
case CHAT:
|
||||
kit.For(arg[1:], func(k, v string) { m.Option(k, v) })
|
||||
case SHARE:
|
||||
m.Option(arg[0], arg[1])
|
||||
case "s":
|
||||
m.Option(ice.POD, kit.Select("", arg, 1))
|
||||
}
|
||||
kit.For(u.Query(), func(k string, v []string) { m.Optionv(k, v) })
|
||||
}
|
||||
}
|
||||
func _serve_handle(key string, cmd *ice.Command, m *ice.Message, w http.ResponseWriter, r *http.Request) {
|
||||
debug := strings.Contains(r.URL.String(), "debug=true") || strings.Contains(r.Header.Get(html.Referer), "debug=true")
|
||||
m.Options(ice.LOG_DEBUG, ice.FALSE, ice.LOG_TRACEID, r.Header.Get(ice.LOG_TRACEID))
|
||||
_log := func(level string, arg ...ice.Any) *ice.Message {
|
||||
if debug || arg[0] == ice.MSG_CMDS {
|
||||
return m.Logs(strings.Title(level), arg...)
|
||||
}
|
||||
return m
|
||||
}
|
||||
kit.If(r.Header.Get(html.Referer), func(p string) { _log("page", html.Referer, p) })
|
||||
_serve_params(m, r.Header.Get(html.Referer))
|
||||
_serve_params(m, r.URL.String())
|
||||
if r.Method == http.MethodGet && m.Option(ice.MSG_CMDS) != "" {
|
||||
_log(ctx.ARGS, ice.MSG_CMDS, m.Optionv(ice.MSG_CMDS))
|
||||
}
|
||||
switch kit.Select("", kit.Split(r.Header.Get(html.ContentType)), 0) {
|
||||
case html.ApplicationJSON:
|
||||
buf, _ := ioutil.ReadAll(r.Body)
|
||||
m.Option("request.data", string(buf))
|
||||
kit.For(kit.UnMarshal(string(buf)), func(k string, v ice.Any) { m.Optionv(k, v) })
|
||||
default:
|
||||
r.ParseMultipartForm(kit.Int64(kit.Select("4096", r.Header.Get(html.ContentLength))))
|
||||
kit.For(r.PostForm, func(k string, v []string) { _log(FORM, k, kit.Join(v, lex.SP)).Optionv(k, v) })
|
||||
}
|
||||
kit.For(r.Cookies(), func(k, v string) { m.Optionv(k, v) })
|
||||
m.Options(ice.MSG_METHOD, r.Method, ice.MSG_COUNT, "0")
|
||||
m.Options(ice.MSG_REFERER, r.Header.Get(html.Referer))
|
||||
m.Options(ice.MSG_USERWEB, _serve_domain(m), ice.MSG_USERPOD, m.Option(ice.POD))
|
||||
m.Options(ice.MSG_USERUA, r.Header.Get(html.UserAgent), ice.MSG_USERIP, r.Header.Get(ice.MSG_USERIP))
|
||||
m.Options(ice.MSG_SESSID, kit.Select(m.Option(ice.MSG_SESSID), m.Option(CookieName(m.Option(ice.MSG_USERWEB)))))
|
||||
kit.If(m.Optionv(ice.MSG_CMDS) == nil, func() {
|
||||
kit.If(strings.TrimPrefix(r.URL.Path, key), func(p string) { m.Optionv(ice.MSG_CMDS, strings.Split(p, nfs.PS)) })
|
||||
})
|
||||
UserHost(m)
|
||||
for k, v := range m.R.Header {
|
||||
// m.Info("what %v %v", k, v)
|
||||
kit.If(strings.HasPrefix(k, "Wechatpay"), func() { m.Option(k, v) })
|
||||
}
|
||||
m.W.Header().Add(strings.ReplaceAll(ice.LOG_TRACEID, ".", "-"), m.Option(ice.LOG_TRACEID))
|
||||
defer func() { Render(m, m.Option(ice.MSG_OUTPUT), kit.List(m.Optionv(ice.MSG_ARGS))...) }()
|
||||
if cmds, ok := _serve_auth(m, key, kit.Simple(m.Optionv(ice.MSG_CMDS)), w, r); ok {
|
||||
m.Option(ice.MSG_COST, "")
|
||||
defer func() {
|
||||
kit.If(m.Option(ice.MSG_STATUS) == "", func() { m.StatusTimeCount() })
|
||||
m.Cost(kit.Format("%s: %s %v", r.Method, r.URL.String(), m.FormatSize())).Options(ice.MSG_COST, m.FormatCost())
|
||||
}()
|
||||
m.Option(ice.MSG_OPTS, kit.Simple(m.Optionv(ice.MSG_OPTION), func(k string) bool { return !strings.HasPrefix(k, ice.MSG_SESSID) }))
|
||||
if m.Detailv(m.PrefixKey(), cmds); len(cmds) > 1 && cmds[0] == ctx.ACTION {
|
||||
if m.Detailv(m.ShortKey(), cmds); len(cmds) > 1 && cmds[0] == ctx.ACTION && cmds[1] != ctx.ACTION {
|
||||
if !kit.IsIn(cmds[1], aaa.LOGIN, ctx.RUN, ctx.COMMAND) && m.WarnNotAllow(r.Method == http.MethodGet) {
|
||||
return
|
||||
}
|
||||
m.ActionHand(cmd, key, cmds[1], cmds[2:]...)
|
||||
} else {
|
||||
m.CmdHand(cmd, key, cmds...)
|
||||
}
|
||||
func() {
|
||||
defer InfoLock.Lock()()
|
||||
Info.Commands[kit.Select(kit.Select("", cmds, 0), m.Option(ice.MSG_INDEX))]++
|
||||
switch r.Method {
|
||||
case http.MethodGet:
|
||||
Info.ServeGetCount++
|
||||
case http.MethodPut:
|
||||
Info.ServePutCount++
|
||||
case http.MethodPost:
|
||||
Info.ServePostCount++
|
||||
case http.MethodDelete:
|
||||
Info.ServeDeleteCount++
|
||||
}
|
||||
}()
|
||||
}
|
||||
Render(m, m.Option(ice.MSG_OUTPUT), m.Optionv(ice.MSG_ARGS))
|
||||
}
|
||||
func _serve_domain(m *ice.Message) string {
|
||||
return kit.GetValid(
|
||||
func() string { return kit.Select("", m.R.Header.Get(Referer), m.R.Method == http.MethodPost) },
|
||||
func() string { return m.R.Header.Get("X-Host") },
|
||||
func() string { return kit.Select("", m.R.Header.Get(html.Referer), m.R.Method == http.MethodPost) },
|
||||
func() string { return m.R.Header.Get(html.XHost) },
|
||||
func() string { return ice.Info.Domain },
|
||||
func() string { return kit.Format("%s://%s", kit.Select("https", ice.HTTP, m.R.TLS == nil), m.R.Host) },
|
||||
func() string {
|
||||
if b, e := regexp.MatchString("^[0-9.]+$", m.R.Host); b && e == nil {
|
||||
return kit.Format("%s://%s:%s", kit.Select(HTTPS, HTTP, m.R.TLS == nil), m.R.Host, m.Option(tcp.PORT))
|
||||
}
|
||||
return kit.Format("%s://%s", kit.Select(HTTPS, HTTP, m.R.TLS == nil), m.R.Host)
|
||||
},
|
||||
)
|
||||
}
|
||||
func _serve_login(m *ice.Message, key string, cmds []string, w http.ResponseWriter, r *http.Request) ([]string, bool) {
|
||||
if aaa.SessCheck(m, m.Option(ice.MSG_SESSID)); m.Option(ice.MSG_USERNAME) == "" && r.URL.Path != PP(SPACE) && !strings.HasPrefix(r.URL.Path, "/sync") {
|
||||
gdb.Event(m, SERVE_LOGIN)
|
||||
func _serve_auth(m *ice.Message, key string, cmds []string, w http.ResponseWriter, r *http.Request) ([]string, bool) {
|
||||
kit.If(len(cmds) > 0, func() { cmds = append(kit.Split(cmds[0], ","), cmds[1:]...) })
|
||||
kit.If(!aaa.IsTechOrRoot(m), func() { m.Option("user_uid", "") })
|
||||
if r.URL.Path == PP(SPACE) {
|
||||
aaa.SessCheck(m, m.Option(ice.MSG_SESSID))
|
||||
return cmds, true
|
||||
}
|
||||
if _, ok := m.Target().Commands[WEB_LOGIN]; ok {
|
||||
return cmds, !m.Target().Cmd(m, WEB_LOGIN, kit.Simple(key, cmds)...).IsErr()
|
||||
} else if gdb.Event(m, SERVE_CHECK, key, cmds); m.IsErr() {
|
||||
return cmds, false
|
||||
} else if m.IsOk() {
|
||||
return cmds, m.SetResult() != nil
|
||||
} else {
|
||||
return cmds, aaa.Right(m, key, cmds)
|
||||
defer func() { m.Options(ice.MSG_CMDS, "") }()
|
||||
if strings.Contains(m.Option(ice.MSG_SESSID), " ") {
|
||||
m.Cmdy(kit.Split(m.Option(ice.MSG_SESSID)))
|
||||
} else if aaa.SessCheck(m, m.Option(ice.MSG_SESSID)); m.Option(ice.MSG_USERNAME) == "" {
|
||||
if ls := kit.Simple(mdb.Cache(m, m.Option(ice.MSG_USERIP), func() ice.Any {
|
||||
if !IsLocalHost(m) {
|
||||
return nil
|
||||
}
|
||||
aaa.UserRoot(m)
|
||||
return kit.Simple(m.Time(), m.OptionSplit(ice.MSG_USERNICK, ice.MSG_USERNAME, ice.MSG_USERROLE))
|
||||
})); len(ls) > 0 {
|
||||
aaa.SessAuth(m, kit.Dict(aaa.USERNICK, ls[1], aaa.USERNAME, ls[2], aaa.USERROLE, ls[3]), CACHE, ls[0])
|
||||
}
|
||||
}
|
||||
Count(m, aaa.IP, m.Option(ice.MSG_USERIP), m.Option(ice.MSG_USERUA))
|
||||
return cmds, aaa.Right(m, key, cmds)
|
||||
}
|
||||
|
||||
const (
|
||||
SERVE_START = "serve.start"
|
||||
SERVE_REWRITE = "serve.rewrite"
|
||||
SERVE_PARSE = "serve.parse"
|
||||
SERVE_LOGIN = "serve.login"
|
||||
SERVE_CHECK = "serve.check"
|
||||
SERVE_STOP = "serve.stop"
|
||||
SSO = "sso"
|
||||
URL = "url"
|
||||
HTTP = "http"
|
||||
HTTPS = "https"
|
||||
DOMAIN = "domain"
|
||||
FORM = "form"
|
||||
BODY = "body"
|
||||
HOME = "home"
|
||||
|
||||
WEB_LOGIN = "_login"
|
||||
DOMAIN = "domain"
|
||||
INDEX = "index"
|
||||
SSO = "sso"
|
||||
SERVE_START = "serve.start"
|
||||
PROXY_CONF = "proxyConf"
|
||||
PROXY_PATH = "usr/local/daemon/10000/"
|
||||
PROXY_CMDS = "./sbin/nginx"
|
||||
)
|
||||
const SERVE = "serve"
|
||||
|
||||
func init() {
|
||||
Index.MergeCommands(ice.Commands{
|
||||
SERVE: {Name: "serve name auto start", Help: "服务器", Actions: ice.MergeActions(ice.Actions{
|
||||
ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) { cli.NodeInfo(m, ice.Info.Pathname, WORKER) }},
|
||||
cli.START: {Name: "start dev name=web proto=http host port=9020 nodename username usernick", Hand: func(m *ice.Message, arg ...string) {
|
||||
Index.MergeCommands(ice.Commands{P(ice.EXIT): {Hand: func(m *ice.Message, arg ...string) { m.Cmd(ice.EXIT) }},
|
||||
SERVE: {Name: "serve port auto main host system", Help: "服务器", Actions: ice.MergeActions(ice.Actions{
|
||||
ice.MAIN: {Name: "main index space", Help: "首页", Hand: func(m *ice.Message, arg ...string) {
|
||||
if m.Option(ctx.INDEX) == "" {
|
||||
mdb.Config(m, ice.MAIN, "")
|
||||
} else if m.Option(SPACE) == "" {
|
||||
mdb.Config(m, ice.MAIN, C(m.Option(ctx.INDEX)))
|
||||
} else {
|
||||
mdb.Config(m, ice.MAIN, S(m.Option(SPACE))+C(m.Option(ctx.INDEX)))
|
||||
}
|
||||
}},
|
||||
mdb.ICONS: {Hand: func(m *ice.Message, arg ...string) { mdb.Config(m, mdb.ICONS, arg[0]) }},
|
||||
tcp.HOST: {Help: "公网", Hand: func(m *ice.Message, arg ...string) { m.Echo(kit.Formats(PublicIP(m))) }},
|
||||
cli.SYSTEM: {Help: "系统", Hand: func(m *ice.Message, arg ...string) { cli.Opens(m, "System Settings.app") }},
|
||||
cli.START: {Name: "start dev proto host port=9020 nodename username usernick", Hand: func(m *ice.Message, arg ...string) {
|
||||
if runtime.GOOS == cli.LINUX {
|
||||
m.Cmd(nfs.SAVE, nfs.ETC_LOCAL_SH, m.Spawn(ice.Maps{cli.PWD: kit.Path(""), aaa.USER: kit.UserName(), ctx.ARGS: kit.JoinCmds(arg...)}).Template("local.sh")+lex.NL)
|
||||
m.GoSleep("3s", func() { m.Cmd("", PROXY_CONF, kit.Select(ice.Info.NodeName, m.Option("nodename"))) })
|
||||
} else if runtime.GOOS == cli.WINDOWS {
|
||||
m.Cmd(cli.SYSTEM, cli.ECHO, "-ne", kit.Format("\033]0;%s %s serve start %s\007",
|
||||
path.Base(kit.Path("")), strings.TrimPrefix(kit.Path(os.Args[0]), kit.Path("")+nfs.PS), kit.JoinCmdArgs(arg...)))
|
||||
}
|
||||
_serve_start(m)
|
||||
}},
|
||||
SERVE_START: {Hand: func(m *ice.Message, arg ...string) {
|
||||
m.Sleep30ms().Cmd(ssh.PRINTF, kit.Dict(nfs.CONTENT, "\r"+ice.Render(m, ice.RENDER_QRCODE, m.Cmdx(SPACE, DOMAIN))+ice.NL)).Cmd(ssh.PROMPT)
|
||||
}},
|
||||
SERVE_REWRITE: {Hand: func(m *ice.Message, arg ...string) {
|
||||
if arg[0] != http.MethodGet {
|
||||
return
|
||||
kit.If(m.Option(ice.DEMO) == ice.TRUE, func() { m.Cmd(CHAT_HEADER, ice.DEMO) })
|
||||
kit.If(os.Getenv(cli.TERM), func() { m.Go(func() { ssh.PrintQRCode(m, tcp.PublishLocalhost(m, _serve_address(m))) }) })
|
||||
m.Cmd(SPIDE, mdb.CREATE, HostPort(m, tcp.LOCALHOST, m.Option(tcp.PORT)), ice.OPS, ice.SRC_MAIN_ICO, nfs.REPOS, "")
|
||||
m.Cmds(SPIDE).Table(func(value ice.Maps) {
|
||||
kit.If(value[CLIENT_NAME] != ice.OPS && value[TOKEN] != "", func() {
|
||||
m.Cmd(SPACE, tcp.DIAL, ice.DEV, value[CLIENT_NAME], TOKEN, value[TOKEN], mdb.TYPE, SERVER)
|
||||
})
|
||||
})
|
||||
Count(m, m.ActionKey(), m.Option(tcp.PORT))
|
||||
if cb, ok := m.Optionv(SERVE_START).(func()); ok {
|
||||
cb()
|
||||
}
|
||||
switch arg[1] {
|
||||
case ice.PS:
|
||||
if arg[3] == ice.INTSHELL {
|
||||
RenderIndex(m, arg[3])
|
||||
} else {
|
||||
RenderMain(m, "", "")
|
||||
ice.Info.Important = ice.HasVar()
|
||||
}},
|
||||
PROXY_CONF: {Name: "proxyConf name* port host path", Hand: func(m *ice.Message, arg ...string) {
|
||||
if dir := m.OptionDefault(nfs.PATH, PROXY_PATH, tcp.HOST, "127.0.0.1", tcp.PORT, tcp.PORT_9020); nfs.Exists(m, dir) {
|
||||
for _, p := range []string{"upstream.conf"} {
|
||||
m.Cmd(nfs.SAVE, kit.Format("%s/conf/portal/%s/%s", dir, m.Option(mdb.NAME), p), m.Template(p)+lex.NL)
|
||||
}
|
||||
default:
|
||||
if nfs.ExistsFile(m, arg[2]) {
|
||||
m.RenderDownload(arg[2])
|
||||
for _, p := range []string{"server.conf", "location.conf"} {
|
||||
m.Cmd(nfs.DEFS, kit.Format("%s/conf/portal/%s/%s", dir, m.Option(mdb.NAME), p), m.Template(p)+lex.NL)
|
||||
}
|
||||
m.Cmd(cli.SYSTEM, cli.SUDO, kit.Path(dir, "sbin/nginx"), "-p", kit.Path(dir), "-s", "reload")
|
||||
}
|
||||
}},
|
||||
SERVE_LOGIN: {Hand: func(m *ice.Message, arg ...string) {
|
||||
if m.Option(ice.MSG_USERNAME) == "" && m.Config(tcp.LOCALHOST) == ice.TRUE && tcp.IsLocalHost(m, m.Option(ice.MSG_USERIP)) {
|
||||
aaa.UserRoot(m)
|
||||
}
|
||||
}},
|
||||
DOMAIN: {Hand: func(m *ice.Message, arg ...string) {
|
||||
if len(arg) > 0 {
|
||||
m.Config(tcp.LOCALHOST, ice.FALSE)
|
||||
ice.Info.Domain = arg[0]
|
||||
}
|
||||
m.Echo(ice.Info.Domain)
|
||||
}},
|
||||
}, mdb.HashAction(
|
||||
mdb.SHORT, mdb.NAME, mdb.FIELD, "time,status,name,proto,host,port", tcp.LOCALHOST, ice.TRUE, LOGHEADERS, ice.FALSE,
|
||||
ice.INTSHELL, kit.Dict(nfs.PATH, ice.USR_INTSHELL, INDEX, ice.INDEX_SH, nfs.REPOS, "https://shylinux.com/x/intshell", nfs.BRANCH, nfs.MASTER),
|
||||
ice.VOLCANOS, kit.Dict(nfs.PATH, ice.USR_VOLCANOS, INDEX, "page/index.html", nfs.REPOS, "https://shylinux.com/x/volcanos", nfs.BRANCH, nfs.MASTER),
|
||||
), mdb.ClearHashOnExitAction(), ServeAction())},
|
||||
PP(ice.INTSHELL): {Name: "/intshell/", Help: "命令行", Actions: aaa.WhiteAction(), Hand: func(m *ice.Message, arg ...string) {
|
||||
RenderIndex(m, ice.INTSHELL, arg...)
|
||||
}},
|
||||
PP(ice.VOLCANOS): {Name: "/volcanos/", Help: "浏览器", Actions: aaa.WhiteAction(), Hand: func(m *ice.Message, arg ...string) {
|
||||
RenderIndex(m, ice.VOLCANOS, arg...)
|
||||
}},
|
||||
PP(ice.PUBLISH): {Name: "/publish/", Help: "定制化", Actions: aaa.WhiteAction(), Hand: func(m *ice.Message, arg ...string) {
|
||||
_share_local(m, ice.USR_PUBLISH, path.Join(arg...))
|
||||
}},
|
||||
PP(ice.REQUIRE): {Name: "/require/shylinux.com/x/volcanos/proto.js", Help: "代码库", Hand: func(m *ice.Message, arg ...string) {
|
||||
p := path.Join(ice.ISH_PLUGED, path.Join(arg...))
|
||||
if !nfs.ExistsFile(m, p) {
|
||||
m.Cmd(cli.SYSTEM, "git", "clone", "https://"+path.Join(arg[:3]...), path.Join(ice.ISH_PLUGED, path.Join(arg[:3]...)))
|
||||
}
|
||||
m.RenderDownload(p)
|
||||
}},
|
||||
PP(ice.REQUIRE, ice.NODE_MODULES): {Name: "/require/node_modules/", Help: "依赖库", Hand: func(m *ice.Message, arg ...string) {
|
||||
p := path.Join(ice.SRC, ice.NODE_MODULES, path.Join(arg...))
|
||||
if !nfs.ExistsFile(m, p) {
|
||||
m.Cmd(cli.SYSTEM, "npm", "install", arg[0], kit.Dict(cli.CMD_DIR, path.Join(ice.SRC)))
|
||||
}
|
||||
m.RenderDownload(p)
|
||||
}},
|
||||
PP(ice.REQUIRE, ice.USR): {Name: "/require/usr/", Help: "代码库", Hand: func(m *ice.Message, arg ...string) {
|
||||
_share_local(m, ice.USR, path.Join(arg...))
|
||||
}},
|
||||
PP(ice.REQUIRE, ice.SRC): {Name: "/require/src/", Help: "源代码", Hand: func(m *ice.Message, arg ...string) {
|
||||
_share_local(m, ice.SRC, path.Join(arg...))
|
||||
}},
|
||||
PP(ice.HELP): {Name: "/help/", Help: "帮助", Actions: aaa.WhiteAction(), Hand: func(m *ice.Message, arg ...string) {
|
||||
if len(arg) == 0 {
|
||||
arg = append(arg, "tutor.shy")
|
||||
}
|
||||
if len(arg) > 0 && arg[0] != ctx.ACTION {
|
||||
arg[0] = path.Join(ice.SRC_HELP, arg[0])
|
||||
}
|
||||
m.Cmdy("web.chat./cmd/", arg)
|
||||
}, gdb.EventsAction(SERVE_START), mdb.HashAction(
|
||||
mdb.SHORT, tcp.PORT, mdb.FIELD, "time,status,port,host,proto"), mdb.ClearOnExitHashAction()), Hand: func(m *ice.Message, arg ...string) {
|
||||
mdb.HashSelect(m, arg...).Action().StatusTimeCount(kit.Dict(ice.MAIN, mdb.Config(m, ice.MAIN)))
|
||||
}},
|
||||
})
|
||||
ice.AddMerges(func(c *ice.Context, key string, cmd *ice.Command, sub string, action *ice.Action) (ice.Handler, ice.Handler) {
|
||||
if strings.HasPrefix(sub, ice.PS) {
|
||||
if sub = kit.Select(sub, PP(key), sub == ice.PS); action.Hand == nil {
|
||||
action.Hand = func(m *ice.Message, arg ...string) { m.Cmdy(key, arg) }
|
||||
}
|
||||
ice.AddMergeAction(func(c *ice.Context, key string, cmd *ice.Command, sub string, action *ice.Action) {
|
||||
if strings.HasPrefix(sub, nfs.PS) {
|
||||
actions := ice.Actions{}
|
||||
for k, v := range cmd.Actions {
|
||||
switch k {
|
||||
case ctx.COMMAND, ice.RUN:
|
||||
actions[k] = v
|
||||
}
|
||||
kit.If(!kit.IsIn(k, ice.CTX_INIT, ice.CTX_EXIT), func() { actions[k] = v })
|
||||
}
|
||||
c.Commands[sub] = &ice.Command{Name: sub, Help: cmd.Help, Actions: actions, Hand: action.Hand}
|
||||
kit.If(action.Hand == nil, func() { action.Hand = cmd.Hand })
|
||||
sub = kit.Select(P(key, sub), PP(key, sub), strings.HasSuffix(sub, nfs.PS))
|
||||
c.Commands[sub] = &ice.Command{Name: kit.Select(cmd.Name, action.Name), Actions: actions, Hand: func(m *ice.Message, arg ...string) {
|
||||
msg := m.Spawn(c, key, cmd)
|
||||
action.Hand(msg, arg...)
|
||||
m.Copy(msg)
|
||||
}, RawHand: action.Hand}
|
||||
}
|
||||
return nil, nil
|
||||
})
|
||||
}
|
||||
func ServeAction() ice.Actions {
|
||||
return gdb.EventsAction(SERVE_START, SERVE_REWRITE, SERVE_PARSE, SERVE_LOGIN, SERVE_CHECK, SERVE_STOP)
|
||||
|
||||
func ServeCmdAction() ice.Actions {
|
||||
return ice.MergeActions(ice.Actions{
|
||||
nfs.PS: {Hand: func(m *ice.Message, arg ...string) { RenderCmd(m, "", arg) }},
|
||||
})
|
||||
}
|
||||
func IsLocalHost(m *ice.Message) bool {
|
||||
return (m.R == nil || m.R.Header.Get(html.XForwardedFor) == "") && tcp.IsLocalHost(m, m.Option(ice.MSG_USERIP))
|
||||
}
|
||||
func ParseURL(m *ice.Message, p string) []string {
|
||||
if u, e := url.Parse(p); e == nil {
|
||||
arg := strings.Split(strings.TrimPrefix(u.Path, nfs.PS), nfs.PS)
|
||||
for i := 0; i < len(arg); i += 2 {
|
||||
switch arg[i] {
|
||||
case "s":
|
||||
m.Option(ice.POD, kit.Select("", arg, i+1))
|
||||
case "c":
|
||||
m.Option(ice.CMD, kit.Select("", arg, i+1))
|
||||
}
|
||||
}
|
||||
kit.For(u.Query(), func(k string, v []string) { m.Optionv(k, v) })
|
||||
return kit.Split(u.Fragment, ":")
|
||||
}
|
||||
return []string{}
|
||||
}
|
||||
func ParseUA(m *ice.Message) (res []string) {
|
||||
res = append(res, aaa.USERROLE, m.Option(ice.MSG_USERROLE))
|
||||
res = append(res, aaa.USERNAME, m.Option(ice.MSG_USERNAME))
|
||||
res = append(res, aaa.USERNICK, m.Option(ice.MSG_USERNICK))
|
||||
res = append(res, aaa.AVATAR, m.Option(ice.MSG_AVATAR))
|
||||
res = append(res, cli.DAEMON, m.Option(ice.MSG_DAEMON))
|
||||
for _, p := range html.AgentList {
|
||||
if strings.Contains(m.Option(ice.MSG_USERUA), p) {
|
||||
res = append(res, mdb.ICONS, kit.Select(agentIcons[p], m.Option(mdb.ICONS)), AGENT, p)
|
||||
break
|
||||
}
|
||||
}
|
||||
for _, p := range html.SystemList {
|
||||
if strings.Contains(m.Option(ice.MSG_USERUA), p) {
|
||||
res = append(res, cli.SYSTEM, p)
|
||||
break
|
||||
}
|
||||
}
|
||||
return append(res, aaa.IP, m.Option(ice.MSG_USERIP), aaa.UA, m.Option(ice.MSG_USERUA))
|
||||
}
|
||||
func ProxyDomain(m *ice.Message, name string) (domain string) {
|
||||
p := path.Join(PROXY_PATH, "conf/portal", name, "server.conf")
|
||||
if !nfs.Exists(m, p) {
|
||||
domain := UserWeb(m).Hostname()
|
||||
if domain == "localhost" {
|
||||
return ""
|
||||
}
|
||||
if p = path.Join(PROXY_PATH, "conf/server", kit.Keys(name, kit.Slice(kit.Split(UserWeb(m).Hostname(), "."), -2))) + ".conf"; !nfs.Exists(m, p) {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
m.Cmd(nfs.CAT, p, func(ls []string) { kit.If(ls[0] == "server_name", func() { domain = ls[1] }) })
|
||||
return kit.Select("", "https://"+domain, domain != "")
|
||||
}
|
||||
func Script(m *ice.Message, str string, arg ...ice.Any) string {
|
||||
return ice.Render(m, ice.RENDER_SCRIPT, kit.Format(str, arg...))
|
||||
}
|
||||
func ChatCmdPath(m *ice.Message, arg ...string) string {
|
||||
return m.MergePodCmd("", kit.Select(m.ShortKey(), path.Join(arg...)))
|
||||
}
|
||||
func RequireFile(m *ice.Message, file string) string {
|
||||
if strings.HasPrefix(file, nfs.PS) || strings.HasPrefix(file, ice.HTTP) || strings.Contains(file, "://") {
|
||||
return file
|
||||
} else if file != "" {
|
||||
return nfs.P + file
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
@ -1,14 +1,12 @@
|
||||
package web
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"path"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
ice "shylinux.com/x/icebergs"
|
||||
"shylinux.com/x/icebergs/base/aaa"
|
||||
"shylinux.com/x/icebergs/base/cli"
|
||||
"shylinux.com/x/icebergs/base/ctx"
|
||||
"shylinux.com/x/icebergs/base/mdb"
|
||||
"shylinux.com/x/icebergs/base/nfs"
|
||||
@ -18,148 +16,220 @@ import (
|
||||
"shylinux.com/x/toolkits/logs"
|
||||
)
|
||||
|
||||
func _share_link(m *ice.Message, p string) string {
|
||||
return tcp.PublishLocalhost(m, MergeLink(m, kit.Select("", SHARE_LOCAL, !strings.HasPrefix(p, ice.PS) && !strings.HasPrefix(p, ice.HTTP))+p))
|
||||
func _share_link(m *ice.Message, p string, arg ...ice.Any) string {
|
||||
if strings.HasPrefix(p, ice.USR_PUBLISH) {
|
||||
return kit.MergeURL2(UserHost(m), strings.TrimPrefix(p, ice.USR), arg...)
|
||||
}
|
||||
return kit.MergeURL2(UserHost(m), kit.Select("", PP(SHARE, LOCAL), !strings.HasPrefix(p, nfs.PS) && !strings.HasPrefix(p, HTTP))+p, arg...)
|
||||
}
|
||||
func _share_cache(m *ice.Message, arg ...string) {
|
||||
if pod := m.Option(ice.POD); ctx.PodCmd(m, CACHE, arg[0]) {
|
||||
if m.Append(nfs.FILE) == "" {
|
||||
m.RenderResult(m.Append(mdb.TEXT))
|
||||
} else {
|
||||
m.Option(ice.POD, pod)
|
||||
_share_local(m, m.Append(nfs.FILE))
|
||||
if m.Cmdy(CACHE, arg[0]); m.Length() == 0 {
|
||||
if pod := m.Option(ice.POD); pod != "" {
|
||||
msg := m.Options(ice.POD, "", ice.MSG_USERROLE, aaa.TECH).Cmd(SPACE, pod, CACHE, arg[0])
|
||||
kit.If(kit.Format(msg.Append(nfs.FILE)), func() {
|
||||
m.RenderDownload(path.Join(ice.USR_LOCAL_WORK, pod, msg.Append(nfs.FILE)))
|
||||
}, func() {
|
||||
m.RenderResult(msg.Append(mdb.TEXT))
|
||||
})
|
||||
}
|
||||
} else if m.Append(nfs.FILE) != "" {
|
||||
m.RenderDownload(m.Append(nfs.FILE), m.Append(mdb.TYPE), m.Append(mdb.NAME))
|
||||
} else {
|
||||
if m.Cmdy(CACHE, arg[0]); m.Append(nfs.FILE) == "" {
|
||||
m.RenderResult(m.Append(mdb.TEXT))
|
||||
} else {
|
||||
m.RenderDownload(m.Append(nfs.FILE), m.Append(mdb.TYPE), m.Append(mdb.NAME))
|
||||
}
|
||||
}
|
||||
}
|
||||
func _share_local(m *ice.Message, arg ...string) {
|
||||
p := path.Join(arg...)
|
||||
switch ls := strings.Split(p, ice.PS); ls[0] {
|
||||
case ice.ETC, ice.VAR:
|
||||
if m.Warn(m.Option(ice.MSG_USERROLE) == aaa.VOID, ice.ErrNotRight, p) {
|
||||
return
|
||||
}
|
||||
default:
|
||||
if m.Option(ice.POD) == "" && !aaa.Right(m, ls) {
|
||||
return
|
||||
}
|
||||
}
|
||||
if m.Option(ice.POD) == "" {
|
||||
m.RenderDownload(p)
|
||||
return
|
||||
}
|
||||
pp := path.Join(ice.VAR_PROXY, m.Option(ice.POD), p)
|
||||
cache, size := time.Now().Add(-time.Hour*24), int64(0)
|
||||
if s, e := file.StatFile(pp); e == nil {
|
||||
cache, size = s.ModTime(), s.Size()
|
||||
}
|
||||
if p == ice.BIN_ICE_BIN {
|
||||
m.Option(ice.MSG_USERROLE, aaa.TECH)
|
||||
}
|
||||
m.Cmd(SPACE, m.Option(ice.POD), SPIDE, ice.DEV, SPIDE_RAW, MergeLink(m, SHARE_PROXY), SPIDE_PART, m.OptionSimple(ice.POD), nfs.PATH, p, nfs.SIZE, size, CACHE, cache.Format(ice.MOD_TIME), UPLOAD, "@"+p)
|
||||
if file.ExistsFile(pp) {
|
||||
m.RenderDownload(pp)
|
||||
} else {
|
||||
m.RenderDownload(p)
|
||||
m.RenderResult(m.Append(mdb.TEXT))
|
||||
}
|
||||
}
|
||||
func _share_proxy(m *ice.Message) {
|
||||
switch p := path.Join(ice.VAR_PROXY, m.Option(ice.POD), m.Option(nfs.PATH)); m.R.Method {
|
||||
case http.MethodGet:
|
||||
m.RenderDownload(p, m.Option(mdb.TYPE), m.Option(mdb.NAME))
|
||||
case http.MethodPost:
|
||||
if _, _, e := m.R.FormFile(UPLOAD); e == nil {
|
||||
m.Cmdy(CACHE, UPLOAD).Cmdy(CACHE, WATCH, m.Option(mdb.HASH), p)
|
||||
}
|
||||
m.RenderResult(m.Option(nfs.PATH))
|
||||
if m.WarnNotValid(m.Option(SHARE) == "") {
|
||||
return
|
||||
}
|
||||
msg := m.Cmd(SHARE, m.Option(SHARE))
|
||||
defer m.Cmd(SHARE, mdb.REMOVE, mdb.HASH, m.Option(SHARE))
|
||||
if m.WarnNotValid(msg.Append(mdb.TEXT) == "") {
|
||||
return
|
||||
}
|
||||
p := path.Join(ice.VAR_PROXY, msg.Append(mdb.TEXT), msg.Append(mdb.NAME))
|
||||
if _, _, e := m.R.FormFile(UPLOAD); e == nil {
|
||||
m.Cmdy(CACHE, UPLOAD).Cmdy(CACHE, WATCH, m.Option(mdb.HASH), p)
|
||||
}
|
||||
m.RenderResult(m.Option(nfs.PATH))
|
||||
}
|
||||
|
||||
const (
|
||||
TOPIC = "topic"
|
||||
LOGIN = "login"
|
||||
RIVER = "river"
|
||||
STORM = "storm"
|
||||
FIELD = "field"
|
||||
|
||||
PROXY = "proxy"
|
||||
LOCAL = "local"
|
||||
|
||||
SHARE_CACHE = "/share/cache/"
|
||||
SHARE_LOCAL = "/share/local/"
|
||||
SHARE_PROXY = "/share/proxy/"
|
||||
SHARE_TOAST = "/share/toast/"
|
||||
|
||||
SHARE_LOCAL_AVATAR = "/share/local/avatar/"
|
||||
SHARE_LOCAL_BACKGROUND = "/share/local/background/"
|
||||
)
|
||||
const SHARE = "share"
|
||||
|
||||
func init() {
|
||||
Index.MergeCommands(ice.Commands{
|
||||
SHARE: {Name: "share hash auto login prunes", Help: "共享链", Actions: ice.MergeActions(ice.Actions{
|
||||
mdb.CREATE: {Name: "create type name text", Hand: func(m *ice.Message, arg ...string) {
|
||||
mdb.HashCreate(m, arg, aaa.USERNAME, m.Option(ice.MSG_USERNAME), aaa.USERNICK, m.Option(ice.MSG_USERNICK), aaa.USERROLE, m.Option(ice.MSG_USERROLE))
|
||||
m.Option(mdb.LINK, _share_link(m, P(SHARE, m.Result())))
|
||||
SHARE: {Name: "share hash auto login", Help: "共享链", Icon: "Freeform.png", Role: aaa.VOID, Actions: ice.MergeActions(ice.Actions{
|
||||
mdb.CREATE: {Name: "create type name text space", Hand: func(m *ice.Message, arg ...string) {
|
||||
kit.If(m.Option(mdb.TYPE) == LOGIN && m.Option(mdb.TEXT) == "", func() { arg = append(arg, mdb.TEXT, tcp.PublishLocalhost(m, m.Option(ice.MSG_USERWEB))) })
|
||||
mdb.HashCreate(m, m.OptionSimple("type,name,text,space"), arg, aaa.USERNICK, m.Option(ice.MSG_USERNICK), aaa.USERNAME, m.Option(ice.MSG_USERNAME), aaa.USERROLE, m.Option(ice.MSG_USERROLE))
|
||||
m.Option(mdb.LINK, tcp.PublishLocalhost(m, m.MergeLink(P(SHARE, m.Result()))))
|
||||
Count(m, "", m.Option(mdb.TYPE))
|
||||
}},
|
||||
LOGIN: {Hand: func(m *ice.Message, arg ...string) {
|
||||
LOGIN: {Help: "登录", Hand: func(m *ice.Message, arg ...string) {
|
||||
m.EchoQRCode(m.Cmd(SHARE, mdb.CREATE, mdb.TYPE, LOGIN).Option(mdb.LINK)).ProcessInner()
|
||||
}},
|
||||
SERVE_PARSE: {Hand: func(m *ice.Message, arg ...string) {
|
||||
if kit.Select("", arg, 0) == SHARE {
|
||||
m.Logs("Refer", arg[0], arg[1]).Option(arg[0], arg[1])
|
||||
OPEN: {Hand: func(m *ice.Message, arg ...string) {
|
||||
m.ProcessOpen(m.MergeLink(P(SHARE, m.Option(mdb.HASH))))
|
||||
}},
|
||||
ctx.COMMAND: {Hand: func(m *ice.Message, arg ...string) {
|
||||
if msg := mdb.HashSelects(m.Spawn(), m.Option(SHARE)); !IsNotValidFieldShare(m, msg) {
|
||||
m.Cmdy(Space(m, msg.Append(SPACE)), ctx.COMMAND, msg.Append(mdb.NAME), kit.Dict(ice.MSG_USERPOD, msg.Append(SPACE)))
|
||||
}
|
||||
}},
|
||||
SERVE_LOGIN: {Hand: func(m *ice.Message, arg ...string) {
|
||||
if m.Option(ice.MSG_USERNAME) == "" && m.Option(SHARE) != "" {
|
||||
switch msg := m.Cmd(SHARE, m.Option(SHARE)); msg.Append(mdb.TYPE) {
|
||||
case STORM, FIELD:
|
||||
msg.Tables(func(value ice.Maps) { aaa.SessAuth(m, value) })
|
||||
}
|
||||
ctx.RUN: {Hand: func(m *ice.Message, arg ...string) {
|
||||
if msg := mdb.HashSelects(m.Spawn(), m.Option(SHARE)); !IsNotValidFieldShare(m, msg) {
|
||||
aaa.SessAuth(m, kit.Dict(msg.AppendSimple(aaa.USERNICK, aaa.USERNAME, aaa.USERROLE)))
|
||||
// m.Cmdy(Space(m, msg.Append(SPACE)), msg.Append(mdb.NAME), kit.UnMarshal(msg.Append(mdb.TEXT)), arg[1:], kit.Dict(ice.MSG_USERPOD, msg.Append(SPACE)))
|
||||
m.Cmdy(Space(m, msg.Append(SPACE)), msg.Append(mdb.NAME), arg[1:], kit.Dict(ice.MSG_USERPOD, msg.Append(SPACE)))
|
||||
}
|
||||
}},
|
||||
ice.PS: {Hand: func(m *ice.Message, arg ...string) {
|
||||
if m.Warn(len(arg) == 0 || arg[0] == "", ice.ErrNotValid, SHARE) {
|
||||
nfs.PS: {Hand: func(m *ice.Message, arg ...string) {
|
||||
if m.WarnNotValid(len(arg) == 0 || arg[0] == "", SHARE) {
|
||||
return
|
||||
}
|
||||
msg := m.Cmd(SHARE, m.Option(SHARE, arg[0]))
|
||||
if IsNotValidShare(m, msg.Append(mdb.TIME)) {
|
||||
m.RenderResult(kit.Format("共享超时, 请联系 %s(%s), 重新分享 %s %s",
|
||||
msg.Append(aaa.USERNAME), msg.Append(aaa.USERNICK), msg.Append(mdb.TYPE), msg.Append(mdb.NAME)))
|
||||
m.RenderResult(kit.Format("共享超时, 请联系 %s(%s), 重新分享 %s %s", msg.Append(aaa.USERNICK), msg.Append(aaa.USERNAME), msg.Append(mdb.TYPE), msg.Append(mdb.NAME)))
|
||||
return
|
||||
}
|
||||
switch msg.Append(mdb.TYPE) {
|
||||
case LOGIN:
|
||||
m.RenderRedirect(ice.PS, ice.MSG_SESSID, aaa.SessCreate(m, msg.Append(aaa.USERNAME)))
|
||||
u := kit.ParseURL(m.Option(ice.MSG_USERHOST))
|
||||
m.RenderRedirect(kit.MergeURL(msg.Append(mdb.TEXT), ice.MSG_SESSID, aaa.SessCreate(m, msg.Append(aaa.USERNAME))))
|
||||
break
|
||||
if u.Scheme == ice.HTTP {
|
||||
m.RenderRedirect(kit.MergeURL(msg.Append(mdb.TEXT), ice.MSG_SESSID, aaa.SessCreate(m, msg.Append(aaa.USERNAME))))
|
||||
} else {
|
||||
RenderCookie(m, aaa.SessCreate(m, msg.Append(aaa.USERNAME)))
|
||||
m.RenderRedirect(msg.Append(mdb.TEXT))
|
||||
}
|
||||
case STORM:
|
||||
RenderCookie(m, aaa.SessCreate(m, msg.Append(aaa.USERNAME)))
|
||||
m.RenderRedirect(m.MergeLink(kit.Select(nfs.PS, msg.Append(mdb.TEXT)), msg.AppendSimple(RIVER, STORM)))
|
||||
case FIELD:
|
||||
if msg.Append(mdb.NAME) == "web.chat.grant" {
|
||||
RenderPodCmd(m, "", msg.Append(mdb.NAME), kit.UnMarshal(msg.Append(mdb.TEXT)))
|
||||
} else {
|
||||
RenderPodCmd(m, msg.Append(SPACE), msg.Append(mdb.NAME), kit.UnMarshal(msg.Append(mdb.TEXT)))
|
||||
}
|
||||
case DOWNLOAD:
|
||||
m.RenderDownload(msg.Append(mdb.TEXT))
|
||||
default:
|
||||
RenderIndex(m, "")
|
||||
RenderMain(m)
|
||||
}
|
||||
}},
|
||||
}, mdb.HashAction(mdb.FIELD, "time,hash,username,usernick,userrole,river,storm,type,name,text", mdb.EXPIRE, "72h"), ServeAction(), aaa.WhiteAction()), Hand: func(m *ice.Message, arg ...string) {
|
||||
if ctx.PodCmd(m, SHARE, arg) {
|
||||
return
|
||||
}
|
||||
if mdb.HashSelect(m, arg...); len(arg) > 0 {
|
||||
link := _share_link(m, P(SHARE, arg[0]))
|
||||
m.PushQRCode(cli.QRCODE, link)
|
||||
m.PushScript(nfs.SCRIPT, link)
|
||||
m.PushAnchor(link)
|
||||
}, mdb.HashAction(mdb.FIELD, "time,hash,type,name,text,space,usernick,username,userrole", mdb.EXPIRE, mdb.DAYS)), Hand: func(m *ice.Message, arg ...string) {
|
||||
if aaa.IsTechOrRoot(m) || len(arg) > 0 && arg[0] != "" {
|
||||
mdb.HashSelect(m, arg...).PushAction(OPEN, mdb.REMOVE)
|
||||
}
|
||||
}},
|
||||
SHARE_CACHE: {Hand: func(m *ice.Message, arg ...string) { _share_cache(m, arg...) }},
|
||||
SHARE_LOCAL: {Hand: func(m *ice.Message, arg ...string) { _share_local(m, arg...) }},
|
||||
SHARE_LOCAL_AVATAR: {Hand: func(m *ice.Message, arg ...string) {
|
||||
m.RenderDownload(strings.TrimPrefix(m.CmdAppend(aaa.USER, m.Option(ice.MSG_USERNAME), aaa.AVATAR), SHARE_LOCAL))
|
||||
}},
|
||||
SHARE_LOCAL_BACKGROUND: {Hand: func(m *ice.Message, arg ...string) {
|
||||
m.RenderDownload(strings.TrimPrefix(m.CmdAppend(aaa.USER, m.Option(ice.MSG_USERNAME), aaa.BACKGROUND), SHARE_LOCAL))
|
||||
}},
|
||||
SHARE_PROXY: {Hand: func(m *ice.Message, arg ...string) { _share_proxy(m) }},
|
||||
SHARE_TOAST: {Hand: func(m *ice.Message, arg ...string) { m.Cmdy(SPACE, m.Option(ice.POD), m.Optionv("cmds")) }},
|
||||
PP(SHARE, PROXY): {Hand: func(m *ice.Message, arg ...string) { _share_proxy(m) }},
|
||||
PP(SHARE, CACHE): {Hand: func(m *ice.Message, arg ...string) { _share_cache(m, arg...) }},
|
||||
PP(SHARE, LOCAL): {Hand: func(m *ice.Message, arg ...string) { ShareLocalFile(m, arg...) }},
|
||||
})
|
||||
}
|
||||
func IsNotValidShare(m *ice.Message, time string) bool {
|
||||
return m.Warn(time < m.Time(), ice.ErrNotValid, m.Option(SHARE), time, m.Time(), logs.FileLineMeta(2))
|
||||
return m.WarnNotValid(time < m.Time(), ice.ErrNotValid, m.Option(SHARE), time, m.Time(), logs.FileLineMeta(2))
|
||||
}
|
||||
func IsNotValidFieldShare(m *ice.Message, msg *ice.Message) bool {
|
||||
if m.Warn(IsNotValidShare(m, msg.Append(mdb.TIME)), kit.Format("共享超时, 请联系 %s(%s), 重新分享 %s %s %s", msg.Append(aaa.USERNICK), msg.Append(aaa.USERNAME), msg.Append(mdb.TYPE), msg.Append(mdb.NAME), msg.Append(mdb.TEXT))) {
|
||||
return true
|
||||
}
|
||||
if m.WarnNotValid(msg.Append(mdb.NAME) == "") {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
func SharePath(m *ice.Message, p string) string {
|
||||
kit.If(!kit.HasPrefix(p, nfs.PS, ice.HTTP), func() {
|
||||
if kit.HasPrefix(p, nfs.SRC, nfs.USR) && !kit.HasPrefix(p, nfs.USR_LOCAL) {
|
||||
p = m.MergeLink(path.Join(nfs.P, p), ice.POD, m.Option(ice.MSG_USERPOD))
|
||||
} else {
|
||||
p = m.MergeLink(path.Join(SHARE_LOCAL, p), ice.POD, m.Option(ice.MSG_USERPOD))
|
||||
}
|
||||
})
|
||||
return p
|
||||
}
|
||||
func ShareLocalFile(m *ice.Message, arg ...string) {
|
||||
p := path.Join(arg...)
|
||||
switch ls := strings.Split(p, nfs.PS); ls[0] {
|
||||
case ice.ETC, ice.VAR:
|
||||
if m.WarnNotRight(m.Option(ice.MSG_USERROLE) == aaa.VOID, p) {
|
||||
return
|
||||
}
|
||||
default:
|
||||
if m.Option(ice.MSG_USERNAME) != "" && strings.HasPrefix(p, nfs.USR_LOCAL_IMAGE+m.Option(ice.MSG_USERNAME)) {
|
||||
|
||||
} else if m.Option(ice.POD) == "" && !aaa.Right(m, ls) {
|
||||
return
|
||||
} else {
|
||||
if m.Option(ice.POD) != "" && !strings.Contains(p, "/src/") && !strings.HasPrefix(p, "src/") {
|
||||
if strings.HasPrefix(p, "usr/local/storage/") {
|
||||
if m.Cmd(SPACE, "20240903-operation", "web.team.storage.file", aaa.RIGHT, ls[3:]).IsErr() {
|
||||
return
|
||||
}
|
||||
} else if m.WarnNotRight(m.Cmdx(SPACE, m.Option(ice.POD), aaa.ROLE, aaa.RIGHT, aaa.VOID, p) != ice.OK) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if m.Option(ice.POD) != "" && nfs.Exists(m, path.Join(ice.USR_LOCAL_WORK, m.Option(ice.POD))) {
|
||||
if pp := kit.Path(ice.USR_LOCAL_WORK, m.Option(ice.POD), p); nfs.Exists(m, pp) {
|
||||
m.RenderDownload(pp)
|
||||
return
|
||||
} else if nfs.Exists(m, p) {
|
||||
m.RenderDownload(p)
|
||||
return
|
||||
}
|
||||
}
|
||||
if m.Option(ice.POD) == "" || (kit.HasPrefix(p, ice.USR_ICONS, ice.USR_VOLCANOS, ice.USR_ICEBERGS, ice.USR_INTSHELL) && nfs.Exists(m, p)) {
|
||||
m.RenderDownload(p)
|
||||
} else if pp := kit.Path(ice.USR_LOCAL_WORK, m.Option(ice.POD), p); nfs.Exists(m, pp) {
|
||||
m.RenderDownload(pp)
|
||||
} else if pp := ProxyUpload(m, m.Option(ice.POD), p); nfs.Exists(m, pp) {
|
||||
m.RenderDownload(pp)
|
||||
} else {
|
||||
m.RenderDownload(p)
|
||||
}
|
||||
}
|
||||
func ShareLocal(m *ice.Message, p string) string {
|
||||
if kit.HasPrefix(p, nfs.PS, HTTP) {
|
||||
return p
|
||||
}
|
||||
return m.MergeLink(PP(SHARE, LOCAL, p))
|
||||
}
|
||||
func ShareField(m *ice.Message, cmd string, arg ...ice.Any) *ice.Message {
|
||||
return m.EchoQRCode(tcp.PublishLocalhost(m, m.MergeLink(P(SHARE, AdminCmd(m, SHARE, mdb.CREATE, mdb.TYPE, FIELD, mdb.NAME, kit.Select(m.ShortKey(), cmd), mdb.TEXT, kit.Format(kit.Simple(arg...)), SPACE, m.Option(ice.MSG_USERPOD)).Result()))))
|
||||
}
|
||||
func ProxyUpload(m *ice.Message, pod string, p string) string {
|
||||
pp := path.Join(ice.VAR_PROXY, pod, p)
|
||||
size, cache := int64(0), time.Now().Add(-time.Hour*24)
|
||||
if s, e := file.StatFile(pp); e == nil {
|
||||
size, cache = s.Size(), s.ModTime()
|
||||
} else if s, e := file.StatFile(p); e == nil {
|
||||
size, cache = s.Size(), s.ModTime()
|
||||
}
|
||||
if m.Cmdv(SPACE, pod, mdb.TYPE) == ORIGIN {
|
||||
m.Cmd(SPIDE, pod, SPIDE_SAVE, pp, "/p/"+p)
|
||||
} else {
|
||||
kit.If(p == ice.BIN_ICE_BIN, func() { m.Option(ice.MSG_USERROLE, aaa.TECH) })
|
||||
share := m.Cmdx(SHARE, mdb.CREATE, mdb.TYPE, PROXY, mdb.NAME, p, mdb.TEXT, pod)
|
||||
defer m.Cmd(SHARE, mdb.REMOVE, mdb.HASH, share)
|
||||
url := tcp.PublishLocalhost(m, m.MergeLink(PP(SHARE, PROXY), SHARE, share))
|
||||
m.Cmd(SPACE, pod, SPIDE, PROXY, URL, url, nfs.SIZE, size, CACHE, cache.Format(ice.MOD_TIME), UPLOAD, mdb.AT+p, kit.Dict(ice.MSG_USERROLE, aaa.TECH))
|
||||
}
|
||||
return kit.Select(p, pp, file.ExistsFile(pp))
|
||||
}
|
||||
|
@ -1,9 +1,13 @@
|
||||
package web
|
||||
|
||||
import (
|
||||
"io"
|
||||
"math/rand"
|
||||
"net"
|
||||
"path"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
ice "shylinux.com/x/icebergs"
|
||||
@ -11,75 +15,186 @@ import (
|
||||
"shylinux.com/x/icebergs/base/cli"
|
||||
"shylinux.com/x/icebergs/base/ctx"
|
||||
"shylinux.com/x/icebergs/base/gdb"
|
||||
"shylinux.com/x/icebergs/base/lex"
|
||||
"shylinux.com/x/icebergs/base/mdb"
|
||||
"shylinux.com/x/icebergs/base/nfs"
|
||||
"shylinux.com/x/icebergs/base/ssh"
|
||||
"shylinux.com/x/icebergs/base/tcp"
|
||||
"shylinux.com/x/icebergs/base/web/html"
|
||||
"shylinux.com/x/icebergs/misc/websocket"
|
||||
kit "shylinux.com/x/toolkits"
|
||||
"shylinux.com/x/websocket"
|
||||
"shylinux.com/x/toolkits/task"
|
||||
)
|
||||
|
||||
var Info = struct {
|
||||
ServeMainCount int
|
||||
ServeGetCount int
|
||||
ServePutCount int
|
||||
ServePostCount int
|
||||
ServeDeleteCount int
|
||||
SpaceCmdCount int
|
||||
SpaceReadCount int
|
||||
SpaceReadByte int
|
||||
SpaceWriteCount int
|
||||
SpaceWriteByte int
|
||||
Commands map[string]int
|
||||
}{
|
||||
Commands: map[string]int{},
|
||||
}
|
||||
var InfoLock = &task.Lock{}
|
||||
|
||||
func _space_qrcode(m *ice.Message, dev string) {
|
||||
ssh.PrintQRCode(m, m.Cmdv(SPACE, dev, cli.PWD, mdb.LINK))
|
||||
}
|
||||
func _space_dial(m *ice.Message, dev, name string, arg ...string) {
|
||||
msg := m.Cmd(SPIDE, tcp.CLIENT, dev, PP(SPACE))
|
||||
uri := kit.ParseURL(strings.Replace(kit.MergeURL(msg.Append(DOMAIN), mdb.TYPE, ice.Info.NodeType, mdb.NAME, name, SHARE, ice.Info.CtxShare, RIVER, ice.Info.CtxRiver), ice.HTTP, "ws", 1))
|
||||
args := kit.SimpleKV("type,name,host,port", msg.Append(tcp.PROTOCOL), dev, msg.Append(tcp.HOST), msg.Append(tcp.PORT))
|
||||
m.Go(func() {
|
||||
redial := kit.Dict(m.Configv(REDIAL))
|
||||
a, b, c := kit.Int(redial["a"]), kit.Int(redial["b"]), kit.Int(redial["c"])
|
||||
for i := 1; i < c; i++ {
|
||||
next := time.Duration(rand.Intn(a*(i+1))+b*i) * time.Millisecond
|
||||
msg := m.Cmd(SPIDE, dev)
|
||||
origin := msg.Append(CLIENT_ORIGIN)
|
||||
u := kit.ParseURL(kit.MergeURL2(strings.Replace(origin, HTTP, "ws", 1), PP(SPACE), mdb.TYPE, ice.Info.NodeType, mdb.NAME, name, TOKEN, msg.Append(TOKEN), mdb.ICONS, ice.Info.NodeIcon,
|
||||
ice.MAIN, ice.Info.NodeMain, mdb.TIME, ice.Info.Make.Time, nfs.MODULE, ice.Info.Make.Module, nfs.VERSION, ice.Info.Make.Versions(), cli.GOOS, runtime.GOOS, cli.GOARCH, runtime.GOARCH, arg))
|
||||
args := kit.SimpleKV("type,name,host,port", u.Scheme, dev, u.Hostname(), kit.Select(kit.Select(tcp.PORT_443, tcp.PORT_80, u.Scheme == "ws"), u.Port()))
|
||||
gdb.Go(m, func() {
|
||||
once := sync.Once{}
|
||||
redial := kit.Dict(mdb.Configv(m, REDIAL))
|
||||
a, b, _c := kit.Int(redial["a"]), kit.Int(redial["b"]), kit.Int(redial["c"])
|
||||
for i := 1; i < _c; i++ {
|
||||
next := time.Duration(rand.Intn(a*i*i)+b*(i+1)) * time.Millisecond
|
||||
m.Cmd(tcp.CLIENT, tcp.DIAL, args, func(c net.Conn) {
|
||||
if conn, _, e := websocket.NewClient(c, uri, nil, kit.Int(redial["r"]), kit.Int(redial["w"])); !m.Warn(e, tcp.DIAL, dev, SPACE, uri.String()) {
|
||||
defer mdb.HashCreateDeferRemove(m, kit.SimpleKV("", MASTER, dev, msg.Append(tcp.HOSTNAME)), kit.Dict(mdb.TARGET, conn))()
|
||||
_space_handle(m.Spawn(), true, dev, conn)
|
||||
if c, e := websocket.NewClient(c, u); !m.WarnNotValid(e, tcp.DIAL, dev, SPACE, u.String()) {
|
||||
mdb.HashCreate(m, kit.SimpleKV("", ORIGIN, dev, origin), kit.Dict(mdb.TARGET, c))
|
||||
defer mdb.HashRemove(m, mdb.HASH, dev)
|
||||
kit.If(ice.Info.Colors, func() { once.Do(func() { m.Go(func() { _space_qrcode(m, dev) }) }) })
|
||||
_space_handle(m.Spawn(), true, dev, c)
|
||||
i = 0
|
||||
}
|
||||
}).Cost("order", i, "sleep", next, "redial", dev, "uri", uri.String()).Sleep(next)
|
||||
}).Cost(mdb.COUNT, i, mdb.NEXT, next, tcp.DIAL, dev, LINK, u.String()).Sleep(next)
|
||||
if mdb.HashSelect(m.Spawn(), name).Append(mdb.STATUS) == cli.STOP {
|
||||
break
|
||||
}
|
||||
}
|
||||
})
|
||||
}, kit.JoinWord(SPACE, dev))
|
||||
}
|
||||
func _space_fork(m *ice.Message) {
|
||||
buffer := kit.Dict(m.Configv(BUFFER))
|
||||
if conn, e := websocket.Upgrade(m.W, m.R, nil, kit.Int(buffer["r"]), kit.Int(buffer["w"])); m.Assert(e) {
|
||||
text := kit.Select(m.Option(ice.MSG_USERADDR), m.Option(mdb.TEXT))
|
||||
name := strings.ToLower(kit.ReplaceAll(kit.Select(m.Option(ice.MSG_USERADDR), m.Option(mdb.NAME)), ice.PT, "_", ice.DF, "_"))
|
||||
args := kit.Simple(mdb.TYPE, kit.Select(WORKER, m.Option(mdb.TYPE)), mdb.NAME, name, mdb.TEXT, text, m.OptionSimple(SHARE, RIVER, ice.MSG_USERUA))
|
||||
m.Go(func() {
|
||||
defer mdb.HashCreateDeferRemove(m, args, kit.Dict(mdb.TARGET, conn))()
|
||||
defer gdb.EventDeferEvent(m, SPACE_OPEN, args)(SPACE_CLOSE, args)
|
||||
addr := kit.Select(m.R.RemoteAddr, m.R.Header.Get(ice.MSG_USERADDR))
|
||||
text := strings.ReplaceAll(kit.Select(addr, m.Option(mdb.TEXT)), "%2F", nfs.PS)
|
||||
name := SpaceName(kit.Select(addr, m.Option(mdb.NAME)))
|
||||
if m.OptionDefault(mdb.TYPE, SERVER) == WORKER && (!nfs.Exists(m, path.Join(ice.USR_LOCAL_WORK, name)) || !tcp.IsLocalHost(m, m.Option(ice.MSG_USERIP))) {
|
||||
m.Option(mdb.TYPE, SERVER)
|
||||
}
|
||||
if kit.IsIn(m.Option(mdb.TYPE), PORTAL, aaa.LOGIN) && len(name) == 32 && kit.IsIn(mdb.HashSelects(m.Spawn(), name).Append(aaa.IP), "", m.Option(ice.MSG_USERIP)) {
|
||||
|
||||
} else if kit.IsIn(m.Option(mdb.TYPE), SERVER) && IsLocalHost(m) {
|
||||
|
||||
} else if kit.IsIn(m.Option(mdb.TYPE), WORKER) && IsLocalHost(m) {
|
||||
text = nfs.USR_LOCAL_WORK + name
|
||||
} else {
|
||||
name, text = kit.Hashs(name), kit.Select(addr, m.Option(mdb.TEXT))
|
||||
}
|
||||
safe := false
|
||||
if m.Option(ice.MSG_USERNAME, ""); kit.IsIn(m.Option(mdb.TYPE), WORKER, PORTAL) {
|
||||
if tcp.IsLocalHost(m, m.Option(ice.MSG_USERIP)) {
|
||||
aaa.SessAuth(m, kit.Dict(m.Cmd(aaa.USER, m.Option(ice.MSG_USERNAME, ice.Info.Username)).AppendSimple()))
|
||||
}
|
||||
} else if m.Option(TOKEN) != "" {
|
||||
if msg := m.Cmd(TOKEN, m.Option(TOKEN)); msg.Append(mdb.TIME) > m.Time() && kit.IsIn(msg.Append(mdb.TYPE), SERVER, SPIDE) {
|
||||
aaa.SessAuth(m, kit.Dict(m.Cmd(aaa.USER, m.Option(ice.MSG_USERNAME, msg.Append(mdb.NAME))).AppendSimple()))
|
||||
name = SpaceName(kit.Select(name, msg.Append(mdb.TEXT)))
|
||||
// kit.If(ProxyDomain(m.Spawn(kit.Dict(ice.MSG_USERROLE, aaa.TECH)), name), func(p string) { text = p })
|
||||
kit.If(ProxyDomain(m, name), func(p string) { text = p })
|
||||
safe = aaa.IsTechOrRoot(m)
|
||||
}
|
||||
}
|
||||
args := kit.Simple(mdb.TYPE, m.Option(mdb.TYPE), mdb.NAME, name, mdb.TEXT, text, m.OptionSimple(mdb.ICONS, mdb.TIME, nfs.MODULE, nfs.VERSION, cli.DAEMON, "main"))
|
||||
args = append(args, aaa.USERNICK, m.Option(ice.MSG_USERNICK), aaa.USERNAME, m.Option(ice.MSG_USERNAME), aaa.USERROLE, m.Option(ice.MSG_USERROLE))
|
||||
args = append(args, cli.SYSTEM, m.Option(cli.GOOS))
|
||||
args = append(args, ParseUA(m)...)
|
||||
if c, e := websocket.Upgrade(m.W, m.R); !m.WarnNotValid(e) {
|
||||
gdb.Go(m, func() {
|
||||
defer mdb.HashCreateDeferRemove(m, args, kit.Dict(mdb.TARGET, c))()
|
||||
switch m.Option(mdb.TYPE) {
|
||||
case LOGIN:
|
||||
if m.Option(ice.MSG_SESSID) != "" && m.Option(ice.MSG_USERNAME) != "" {
|
||||
m.Cmd(SPACE, name, ice.MSG_SESSID, m.Option(ice.MSG_SESSID))
|
||||
}
|
||||
gdb.Event(m, SPACE_LOGIN, args)
|
||||
defer gdb.Event(m, SPACE_LOGIN_CLOSE, args)
|
||||
case PORTAL:
|
||||
gdb.EventDeferEvent(m, PORTAL_OPEN, args)
|
||||
m.Go(func() { m.Cmd(SPACE, name, cli.PWD, name) })
|
||||
case WORKER:
|
||||
defer gdb.EventDeferEvent(m, DREAM_OPEN, args)(DREAM_CLOSE, args)
|
||||
case CHROME:
|
||||
m.Go(func() { m.Sleep30ms().Cmd(SPACE, name, cli.PWD, name) })
|
||||
safe = true
|
||||
m.Go(func() {
|
||||
SpacePwd(m, name, kit.Path(""))
|
||||
// SpaceEvent(m, OPS_DREAM_OPEN, name, args...)
|
||||
})
|
||||
case SERVER:
|
||||
defer gdb.EventDeferEvent(m, SPACE_OPEN, args)(SPACE_CLOSE, args)
|
||||
m.Go(func() {
|
||||
SpacePwd(m, name, "")
|
||||
SpaceEvent(m.Spawn(ice.MSG_USERROLE, aaa.TECH), OPS_SERVER_OPEN, name, args...)
|
||||
})
|
||||
}
|
||||
_space_handle(m, false, name, conn)
|
||||
})
|
||||
_space_handle(m.Spawn(), safe, name, c)
|
||||
}, kit.JoinWord(SPACE, name))
|
||||
}
|
||||
}
|
||||
func _space_handle(m *ice.Message, safe bool, name string, conn *websocket.Conn) {
|
||||
func _space_handle(m *ice.Message, safe bool, name string, c *websocket.Conn) {
|
||||
defer m.Cost(SPACE, name)
|
||||
m.Options(ice.MSG_USERROLE, "", mdb.TYPE, "", mdb.NAME, "", cli.DAEMON, "")
|
||||
for {
|
||||
_, b, e := conn.ReadMessage()
|
||||
_, b, e := c.ReadMessage()
|
||||
if e != nil {
|
||||
m.Cost(SPACE, name, e)
|
||||
break
|
||||
}
|
||||
func() {
|
||||
defer InfoLock.Lock()()
|
||||
Info.SpaceReadCount++
|
||||
Info.SpaceReadByte += len(b)
|
||||
}()
|
||||
msg := m.Spawn(b)
|
||||
if safe && msg.Option(ice.MSG_UNSAFE) != ice.TRUE { // 下行权限
|
||||
if !aaa.IsTechOrRoot(msg) && msg.Option(ice.MSG_HANDLE) != ice.TRUE {
|
||||
msg.Option(ice.MSG_USERROLE, kit.Select(msg.Option(ice.MSG_USERROLE), aaa.UserRole(msg, msg.Option(ice.MSG_USERNAME))))
|
||||
}
|
||||
// kit.If(kit.IsIn(msg.Option(ice.MSG_USERROLE), "", aaa.VOID), func() { msg.Option(ice.MSG_USERROLE, aaa.UserRole(msg, msg.Option(ice.MSG_USERNAME))) })
|
||||
} else { // 上行权限
|
||||
msg.Option(ice.MSG_UNSAFE, ice.TRUE)
|
||||
kit.If(msg.Option(ice.MSG_USERROLE), func() { msg.Option(ice.MSG_USERROLE, aaa.VOID) })
|
||||
}
|
||||
source, target := kit.Simple(msg.Optionv(ice.MSG_SOURCE), name), kit.Simple(msg.Optionv(ice.MSG_TARGET))
|
||||
msg.Log("recv", "%v->%v %v %v", source, target, msg.Detailv(), msg.FormatMeta())
|
||||
msg.Log(kit.Select(tcp.RECV, tcp.ECHO, msg.Option(ice.MSG_HANDLE) == ice.TRUE), "%d %v->%v %v %v", len(b), source, target, msg.Detailv(), msg.FormatMeta())
|
||||
if next := msg.Option(ice.MSG_TARGET); next == "" || len(target) == 0 {
|
||||
if msg.Optionv(ice.MSG_HANDLE, ice.TRUE); safe { // 下行命令
|
||||
gdb.Event(msg, SPACE_LOGIN)
|
||||
} else { // 上行请求
|
||||
msg.Option(ice.MSG_USERROLE, aaa.VOID)
|
||||
msg.Go(func() {
|
||||
if k := kit.Keys(msg.Option(ice.MSG_USERPOD), "_token"); msg.Option(k) != "" {
|
||||
aaa.SessCheck(msg, msg.Option(k))
|
||||
}
|
||||
msg.Option(ice.MSG_OPTS, kit.Simple(msg.Optionv(ice.MSG_OPTION), func(k string) bool { return !strings.HasPrefix(k, ice.MSG_SESSID) }))
|
||||
_space_exec(msg, name, source, target, c)
|
||||
}, strings.Join(kit.Simple(SPACE, name, msg.Detailv()), lex.SP))
|
||||
} else {
|
||||
for i := 0; i < 5; i++ {
|
||||
if !m.WarnNotFoundSpace(!mdb.HashSelectDetail(m, next, func(value ice.Map) {
|
||||
switch c := value[mdb.TARGET].(type) {
|
||||
case (*websocket.Conn): // 转发报文
|
||||
kit.If(value[mdb.TYPE] == ORIGIN && msg.Option(ice.MSG_HANDLE) == ice.FALSE, func() {
|
||||
msg.Optionv(ice.MSG_USERWEB, kit.Simple(value[mdb.TEXT], msg.Optionv(ice.MSG_USERWEB)))
|
||||
msg.Optionv(ice.MSG_USERPOD, kit.Simple(kit.Keys(target[1:]), msg.Optionv(ice.MSG_USERPOD)))
|
||||
})
|
||||
_space_echo(msg, source, target, c)
|
||||
case ice.Handler: // 接收响应
|
||||
msg.Go(func() { c(msg) })
|
||||
}
|
||||
}), SPACE, next) {
|
||||
break
|
||||
}
|
||||
if kit.HasPrefixList(msg.Detailv(), "toast") {
|
||||
break
|
||||
}
|
||||
if msg.Option("space.noecho") == "true" {
|
||||
break
|
||||
}
|
||||
m.Sleep3s()
|
||||
}
|
||||
msg.Go(func() { _space_exec(msg, source, target, conn) })
|
||||
} else if mdb.HashSelectDetail(msg, next, func(value ice.Map) {
|
||||
if conn, ok := value[mdb.TARGET].(*websocket.Conn); !m.Warn(!ok, ice.ErrNotValid, next) {
|
||||
_space_echo(msg, source, target, conn) // 转发报文
|
||||
}
|
||||
}) {
|
||||
} else if res := getSend(m, next); !m.Warn(res == nil || len(target) != 1, ice.ErrNotFound, next) {
|
||||
res.Cost(kit.Format("[%v]->%v %v %v", next, res.Optionv(ice.MSG_TARGET), res.Detailv(), msg.FormatSize()))
|
||||
back(res, msg.Sleep("10ms")) // 接收响应
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -87,155 +202,423 @@ func _space_domain(m *ice.Message) (link string) {
|
||||
return kit.GetValid(
|
||||
func() string { return ice.Info.Domain },
|
||||
func() string {
|
||||
return m.CmdAppend(SPACE, ice.OPS, cli.PWD, kit.Dict(ice.MSG_OPTS, ice.MSG_USERNAME), mdb.LINK)
|
||||
if dev := kit.Select(ice.DEV, ice.OPS, ice.Info.NodeType == WORKER); mdb.HashSelectDetail(m, dev, nil) {
|
||||
m.Options(ice.MSG_OPTION, ice.MSG_USERNAME, ice.MSG_OPTS, ice.MSG_USERNAME)
|
||||
return m.Cmdv(SPACE, dev, cli.PWD, mdb.LINK)
|
||||
}
|
||||
return ""
|
||||
},
|
||||
func() string { return m.CmdAppend(SPACE, ice.DEV, cli.PWD, mdb.LINK) },
|
||||
func() string { return m.CmdAppend(SPACE, ice.SHY, cli.PWD, mdb.LINK) },
|
||||
func() string { return tcp.PublishLocalhost(m, m.Option(ice.MSG_USERWEB)) },
|
||||
func() string {
|
||||
return kit.Format("http://%s:%s", m.CmdAppend(tcp.HOST, aaa.IP), kit.Select(m.Option(tcp.PORT), m.CmdAppend(SERVE, tcp.PORT)))
|
||||
})
|
||||
func() string { return HostPort(m, m.Cmdv(tcp.HOST, aaa.IP), m.Cmdv(SERVE, tcp.PORT)) },
|
||||
)
|
||||
}
|
||||
func _space_exec(msg *ice.Message, source, target []string, conn *websocket.Conn) {
|
||||
switch kit.Select(cli.PWD, msg.Detailv(), 0) {
|
||||
func _space_exec(m *ice.Message, name string, source, target []string, c *websocket.Conn) {
|
||||
m.Option(ice.MSG_HANDLE, ice.TRUE)
|
||||
switch kit.Select("", m.Detailv(), 0) {
|
||||
case "":
|
||||
m.Warn(true, ice.ErrNotValid)
|
||||
return
|
||||
case cli.PWD:
|
||||
msg.Push(mdb.LINK, kit.MergePOD(_space_domain(msg), kit.Select("", source, -1)))
|
||||
default:
|
||||
if aaa.Right(msg, msg.Detailv()) {
|
||||
msg = msg.Cmd()
|
||||
m.Push(mdb.LINK, m.MergePod(kit.Select("", source, -1)))
|
||||
if m.Option(cli.SYSTEM) == "" {
|
||||
m.Optionv(ice.MSG_OPTION, []string{})
|
||||
break
|
||||
}
|
||||
args := m.OptionSimple(mdb.ICONS, mdb.TIME, nfs.MODULE, nfs.VERSION, AGENT, cli.SYSTEM)
|
||||
kit.If(name == ice.OPS, func() { args = append(args, m.OptionSimple(mdb.TEXT)...) })
|
||||
mdb.HashModify(m, mdb.HASH, name, ParseUA(m), args)
|
||||
// SpaceEvent(m, OPS_ORIGIN_OPEN, name, kit.Simple(mdb.NAME, name, args)...)
|
||||
default:
|
||||
if m.IsErr() {
|
||||
return
|
||||
}
|
||||
func() {
|
||||
defer InfoLock.Lock()()
|
||||
Info.SpaceCmdCount++
|
||||
Info.Commands[kit.Select(kit.Select("", m.Detailv(), 0), m.Option(ice.MSG_INDEX))]++
|
||||
}()
|
||||
m.Options(ice.MSG_ARGS, "", ice.MSG_COUNT, "0")
|
||||
kit.If(m.Option(ice.MSG_DAEMON), func(p string) {
|
||||
m.Option(ice.MSG_DAEMON0, m.Option(ice.MSG_DAEMON))
|
||||
m.Option(ice.MSG_DAEMON, kit.Keys(kit.Slice(kit.Reverse(kit.Simple(source)), 0, -1), p))
|
||||
})
|
||||
m.Option(ice.FROM_SPACE, kit.Keys(kit.Reverse(kit.Simple(source[1:]))))
|
||||
kit.If(aaa.Right(m, m.Detailv()), func() { m.TryCatch(true, func(_ *ice.Message) { m = m.Cmd() }) })
|
||||
kit.If(m.Optionv(ice.MSG_ARGS) != nil, func() { m.Options(ice.MSG_ARGS, kit.Simple(m.Optionv(ice.MSG_ARGS))) })
|
||||
}
|
||||
defer msg.Cost(kit.Format("%v->%v %v %v", source, target, msg.Detailv(), msg.FormatSize()))
|
||||
_space_echo(msg.Set(ice.MSG_OPTS), []string{}, kit.Revert(kit.Simple(source)), conn)
|
||||
}
|
||||
func _space_echo(m *ice.Message, source, target []string, conn *websocket.Conn) {
|
||||
if m.Options(ice.MSG_SOURCE, source, ice.MSG_TARGET, target[1:]); m.Warn(conn.WriteMessage(1, []byte(m.FormatMeta()))) {
|
||||
mdb.HashRemove(m, mdb.NAME, target[0])
|
||||
} else {
|
||||
m.Log("send", "%v->%v %v %v", source, target, m.Detailv(), m.FormatMeta())
|
||||
}
|
||||
}
|
||||
func _space_send(m *ice.Message, space string, arg ...string) {
|
||||
if space == "" || space == ice.Info.NodeName {
|
||||
m.Cmdy(arg)
|
||||
defer m.Cost(kit.Format("%v->%v %v %v", source, target, m.Detailv(), m.FormatSize()))
|
||||
if m.Option(ice.SPACE_NOECHO) == ice.TRUE {
|
||||
return
|
||||
}
|
||||
kit.Simple(m.Optionv(ice.MSG_OPTS), func(k string) {
|
||||
switch k {
|
||||
case ice.MSG_DETAIL, ice.MSG_CMDS, ice.MSG_SESSID:
|
||||
default:
|
||||
m.Optionv(k, m.Optionv(k))
|
||||
m.Options(ice.MSG_USERWEB, m.Optionv(ice.MSG_USERWEB), ice.MSG_USERPOD, m.Optionv(ice.MSG_USERPOD))
|
||||
_space_echo(m.Set(ice.MSG_OPTS).Options(m.OptionSimple(ice.MSG_HANDLE, ice.LOG_DEBUG, ice.LOG_DISABLE, ice.LOG_TRACEID)), []string{}, kit.Reverse(kit.Simple(source)), c)
|
||||
}
|
||||
func _space_echo(m *ice.Message, source, target []string, c *websocket.Conn) {
|
||||
defer func() { m.WarnNotValid(recover()) }()
|
||||
m.Options(ice.MSG_SOURCE, source, ice.MSG_TARGET, target[1:])
|
||||
data := m.FormatMeta()
|
||||
if !m.WarnNotValid(c.WriteMessage(1, []byte(data))) {
|
||||
func() {
|
||||
defer InfoLock.Lock()()
|
||||
Info.SpaceWriteCount++
|
||||
Info.SpaceWriteByte += len(data)
|
||||
}()
|
||||
if source != nil {
|
||||
m.Log(kit.Select(tcp.SEND, tcp.DONE, m.Option(ice.MSG_HANDLE) == ice.TRUE), "%d %v->%v %v %v", len(data), source, target,
|
||||
kit.ReplaceAll(kit.Format("%v", m.Detailv()), "\r\n", "\\r\\n", "\t", "\\t", "\n", "\\n"), data)
|
||||
}
|
||||
}
|
||||
}
|
||||
func _space_send(m *ice.Message, name string, arg ...string) (h string) {
|
||||
withecho := m.Option(ice.SPACE_NOECHO) != ice.TRUE
|
||||
kit.If(len(arg) > 0 && arg[0] == TOAST, func() { withecho = false; m.Option(ice.MSG_DEBUG, ice.FALSE) })
|
||||
wait, done := m.Wait(kit.Select("", m.OptionDefault(ice.SPACE_TIMEOUT, "180s"), withecho), func(msg *ice.Message, arg ...string) {
|
||||
m.Cost(kit.Format("%v->[%v] %v %v", m.Optionv(ice.MSG_SOURCE), name, m.Detailv(), msg.FormatSize())).Copy(msg)
|
||||
})
|
||||
m.Set(ice.MSG_DETAIL, arg...).Optionv(ice.MSG_OPTION, m.Optionv(ice.MSG_OPTS, m.Optionv(ice.MSG_OPTS)))
|
||||
target := kit.Split(space, ice.PT, ice.PT)
|
||||
if mdb.HashSelectDetail(m, target[0], func(value ice.Map) {
|
||||
if conn, ok := value[mdb.TARGET].(*websocket.Conn); !m.Warn(!ok, ice.ErrNotValid, mdb.TARGET) {
|
||||
_space_echo(m, []string{addSend(m, m)}, target, conn)
|
||||
if withecho {
|
||||
h = mdb.HashCreate(m.SpawnSilent(), mdb.TYPE, tcp.SEND, mdb.NAME, kit.Keys(name, m.Target().ID()), mdb.TEXT, kit.Join(arg, lex.SP), kit.Dict(mdb.TARGET, done))
|
||||
defer mdb.HashRemove(m.SpawnSilent(), mdb.HASH, h)
|
||||
}
|
||||
if target := kit.Split(name, nfs.PT, nfs.PT); !mdb.HashSelectDetail(m, target[0], func(value ice.Map) {
|
||||
if c, ok := value[mdb.TARGET].(*websocket.Conn); !m.WarnNotValid(!ok, mdb.TARGET) {
|
||||
kit.If(kit.Format(value[mdb.TYPE]) == ORIGIN && target[0] != ice.OPS, func() {
|
||||
m.Optionv(ice.MSG_USERWEB, kit.Simple(value[mdb.TEXT], m.Optionv(ice.MSG_USERWEB)))
|
||||
m.Optionv(ice.MSG_USERPOD, kit.Simple(kit.Keys(target[1:]), m.Optionv(ice.MSG_USERPOD)))
|
||||
m.Options(ice.MSG_USERHOST, "", ice.MSG_USERWEB0, m.Option(ice.MSG_USERWEB), ice.MSG_USERPOD0, name)
|
||||
})
|
||||
m.Option(ice.MSG_HANDLE, ice.FALSE)
|
||||
kit.For([]string{ice.MSG_USERROLE, ice.LOG_TRACEID, ice.SPACE_NOECHO}, func(k string) { m.Optionv(k, m.Optionv(k)) })
|
||||
kit.For(kit.Filters(kit.Simple(m.Optionv(ice.MSG_OPTS)), "task.id", "work.id"), func(k string) { m.Optionv(k, m.Optionv(k)) })
|
||||
if withecho {
|
||||
_space_echo(m.Set(ice.MSG_DETAIL, arg...), []string{h}, target, c)
|
||||
} else {
|
||||
_space_echo(m.Set(ice.MSG_DETAIL, arg...), nil, target, c)
|
||||
}
|
||||
}
|
||||
}) {
|
||||
call(m, m.Config(kit.Keys(TIMEOUT, "c")), func(res *ice.Message) { m.Copy(res) })
|
||||
} else if kit.IndexOf([]string{ice.OPS, ice.DEV, ice.SHY}, target[0]) > -1 {
|
||||
return
|
||||
} else {
|
||||
m.Warn(true, ice.ErrNotFound, space)
|
||||
if name == ice.OPS && ice.Info.NodeType == SERVER {
|
||||
m.Cmdy(arg)
|
||||
return
|
||||
}
|
||||
kit.If(m.IsDebug(), func() {
|
||||
m.WarnNotFoundSpace(kit.IndexOf([]string{ice.OPS, ice.DEV}, target[0]) == -1, SPACE, name)
|
||||
})
|
||||
} else if withecho {
|
||||
m.Warn(!wait(), kit.Format("space %v %v time out", name, arg))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
const (
|
||||
CHROME = "chrome"
|
||||
FRIEND = "friend"
|
||||
MASTER = "master"
|
||||
MYSELF = "myself"
|
||||
SERVER = "server"
|
||||
WEIXIN = "weixin"
|
||||
PORTAL = "portal"
|
||||
WORKER = "worker"
|
||||
SERVER = "server"
|
||||
MYSELF = "myself"
|
||||
ORIGIN = "origin"
|
||||
|
||||
REDIAL = "redial"
|
||||
AGENT = "agent"
|
||||
)
|
||||
const (
|
||||
BUFFER = "buffer"
|
||||
REDIAL = "redial"
|
||||
TIMEOUT = "timeout"
|
||||
OPS_ORIGIN_OPEN = "ops.origin.open"
|
||||
OPS_SERVER_OPEN = "ops.server.open"
|
||||
OPS_DREAM_SPAWN = "ops.dream.spawn"
|
||||
OPS_DREAM_OPEN = "ops.dream.open"
|
||||
|
||||
SPACE_START = "space.start"
|
||||
SPACE_OPEN = "space.open"
|
||||
SPACE_LOGIN = "space.login"
|
||||
SPACE_CLOSE = "space.close"
|
||||
SPACE_STOP = "space.stop"
|
||||
SPACE_LOGIN = "space.login"
|
||||
SPACE_LOGIN_CLOSE = "space.login.close"
|
||||
SPACE_GRANT = "space.grant"
|
||||
SPACE_OPEN = "space.open"
|
||||
SPACE_CLOSE = "space.close"
|
||||
PORTAL_OPEN = "portal.open"
|
||||
PORTAL_CLOSE = "portal.close"
|
||||
)
|
||||
const SPACE = "space"
|
||||
|
||||
func init() {
|
||||
Index.MergeCommands(ice.Commands{
|
||||
SPACE: {Name: "space name cmd auto", Help: "空间站", Actions: ice.MergeActions(ice.Actions{
|
||||
"p": {Help: "资源", Actions: ApiWhiteAction(), Hand: func(m *ice.Message, arg ...string) {
|
||||
if arg[0] == "require" {
|
||||
m.Cmdy("/require/", arg[1:])
|
||||
return
|
||||
}
|
||||
if kit.IsIn(arg[0], ice.SRC, ice.USR) {
|
||||
ShareLocalFile(m, arg...)
|
||||
} else {
|
||||
m.Cmdy(PP(ice.REQUIRE), arg)
|
||||
}
|
||||
}},
|
||||
"m": {Help: "模块", Actions: ApiWhiteAction(), Hand: func(m *ice.Message, arg ...string) {
|
||||
p := path.Join(nfs.USR_MODULES, path.Join(arg...))
|
||||
kit.If(!nfs.Exists(m, p), func() {
|
||||
if kit.IsIn(m.Option(ice.MSG_USERROLE), aaa.TECH, aaa.ROOT) {
|
||||
kit.If(!nfs.Exists(m, nfs.USR_PACKAGE), func() {
|
||||
m.Cmd(nfs.SAVE, nfs.USR_PACKAGE, kit.Formats(kit.Dict(mdb.NAME, "usr", nfs.VERSION, "0.0.1")))
|
||||
})
|
||||
m.Cmd(cli.SYSTEM, "npm", "install", arg[0], kit.Dict(cli.CMD_DIR, ice.USR))
|
||||
}
|
||||
})
|
||||
m.RenderDownload(p)
|
||||
}},
|
||||
"c": {Help: "命令", Actions: ApiWhiteAction(), Hand: func(m *ice.Message, arg ...string) { m.Cmdy(CHAT_CMD, arg) }},
|
||||
"s": {Help: "空间", Actions: ApiWhiteAction(), Hand: func(m *ice.Message, arg ...string) { m.Cmdy(CHAT_POD, arg) }},
|
||||
SPACE: {Name: "space name cmds auto", Help: "空间站", Actions: ice.MergeActions(ice.Actions{
|
||||
ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) {
|
||||
cli.NodeInfo(m, ice.Info.Pathname, WORKER)
|
||||
aaa.White(m, SPACE, ice.MAIN)
|
||||
if kit.IsIn(ice.Info.NodeIcon, "src/main.ico", "") {
|
||||
nfs.Exists(m, "src/main.ico", func(p string) { ice.Info.NodeIcon = p })
|
||||
nfs.Exists(m, "src/main.jpg", func(p string) { ice.Info.NodeIcon = p })
|
||||
nfs.Exists(m, "src/main.png", func(p string) { ice.Info.NodeIcon = p })
|
||||
}
|
||||
}},
|
||||
mdb.ICONS: {Hand: func(m *ice.Message, arg ...string) {
|
||||
cli.NodeInfo(m, ice.Info.Pathname, WORKER, arg[0])
|
||||
m.Cmd(SERVE, m.ActionKey(), arg)
|
||||
}},
|
||||
ice.MAIN: {Name: "main index", Role: aaa.VOID, Hand: func(m *ice.Message, arg ...string) {
|
||||
if len(arg) > 0 {
|
||||
ice.Info.NodeMain = m.Option(ctx.INDEX)
|
||||
m.Cmd(SERVE, m.ActionKey(), arg)
|
||||
return
|
||||
}
|
||||
m.Options(mdb.ICONS, "")
|
||||
kit.If(ice.Info.NodeMain, func(cmd string) { RenderPodCmd(m, "", cmd) }, func() { RenderMain(m) })
|
||||
}},
|
||||
ice.INFO: {Role: aaa.VOID, Hand: func(m *ice.Message, arg ...string) {
|
||||
m.Push(mdb.TIME, ice.Info.Make.Time)
|
||||
m.Push(mdb.NAME, ice.Info.NodeName)
|
||||
m.Push(mdb.ICONS, ice.Info.NodeIcon)
|
||||
m.Push(nfs.MODULE, ice.Info.Make.Module)
|
||||
m.Push(nfs.VERSION, ice.Info.Make.Versions())
|
||||
m.Push(nfs.PATHNAME, ice.Info.Pathname)
|
||||
m.Push(tcp.HOSTPORT, HostPort(m, m.Cmd(tcp.HOST).Append(aaa.IP), m.Cmd(SERVER).Append(tcp.PORT)))
|
||||
m.Push(ORIGIN, m.Option(ice.MSG_USERHOST))
|
||||
}},
|
||||
mdb.SEARCH: {Hand: func(m *ice.Message, arg ...string) {
|
||||
if mdb.IsSearchPreview(m, arg) {
|
||||
m.Cmds("", func(value ice.Maps) {
|
||||
switch value[mdb.TYPE] {
|
||||
case SERVER:
|
||||
m.PushSearch(mdb.TEXT, m.MergePod(value[mdb.NAME]), value)
|
||||
case ORIGIN:
|
||||
m.PushSearch(mdb.TEXT, m.Cmdv(SPIDE, value[mdb.NAME], CLIENT_ORIGIN), value)
|
||||
}
|
||||
})
|
||||
}
|
||||
}},
|
||||
cli.START: {Hand: func(m *ice.Message, arg ...string) { m.Cmdy("", tcp.DIAL, arg) }},
|
||||
tcp.DIAL: {Name: "dial dev=ops name", Hand: func(m *ice.Message, arg ...string) {
|
||||
if strings.HasPrefix(m.Option(ice.DEV), ice.HTTP) {
|
||||
m.Cmd(SPIDE, mdb.CREATE, ice.DEV, m.Option(ice.DEV))
|
||||
m.Option(ice.DEV, ice.DEV)
|
||||
}
|
||||
_space_dial(m, m.Option(ice.DEV), kit.Select(ice.Info.NodeName, m.Option(mdb.NAME)), arg...)
|
||||
ice.Info.Important = ice.HasVar()
|
||||
}},
|
||||
cli.CLOSE: {Hand: func(m *ice.Message, arg ...string) { mdb.HashRemove(m, m.OptionSimple(mdb.NAME)) }},
|
||||
mdb.REMOVE: {Hand: func(m *ice.Message, arg ...string) {
|
||||
defer mdb.HashModifyDeferRemove(m, m.OptionSimple(mdb.NAME), mdb.STATUS, cli.STOP)()
|
||||
m.Cmd(SPACE, m.Option(mdb.NAME), ice.EXIT)
|
||||
}},
|
||||
SPACE_LOGIN: {Hand: func(m *ice.Message, arg ...string) {
|
||||
if ice.Info.Username == aaa.VOID {
|
||||
m.Option(ice.MSG_USERROLE, aaa.TECH)
|
||||
defer ToastProcess(m)()
|
||||
mdb.HashModify(m, m.OptionSimple(mdb.NAME), mdb.STATUS, cli.STOP)
|
||||
msg := mdb.HashSelect(m.Spawn(), m.Option(mdb.NAME))
|
||||
if msg.Append(mdb.TYPE) == ORIGIN {
|
||||
if target, ok := mdb.HashSelectTarget(m, m.Option(mdb.NAME), nil).(io.Closer); ok {
|
||||
target.Close()
|
||||
}
|
||||
} else {
|
||||
m.Option(ice.MSG_USERROLE, kit.Select(m.Option(ice.MSG_USERROLE), m.CmdAppend(aaa.USER, m.Option(ice.MSG_USERNAME), aaa.USERROLE)))
|
||||
m.Cmd("", m.Option(mdb.NAME), ice.EXIT).Sleep3s()
|
||||
}
|
||||
aaa.SessAuth(m, kit.Dict(aaa.USERNAME, m.Option(ice.MSG_USERNAME), aaa.USERNICK, m.Option(ice.MSG_USERNICK), aaa.USERROLE, m.Option(ice.MSG_USERROLE)))
|
||||
}},
|
||||
DOMAIN: {Hand: func(m *ice.Message, arg ...string) { m.Echo(_space_domain(m)) }},
|
||||
OPEN: {Hand: func(m *ice.Message, arg ...string) { ctx.ProcessOpen(m, MergePod(m, m.Option(mdb.NAME), arg)) }},
|
||||
ice.PS: {Hand: func(m *ice.Message, arg ...string) { _space_fork(m) }},
|
||||
}, mdb.HashAction(mdb.SHORT, mdb.NAME, mdb.FIELD, "time,type,name,text", ctx.ACTION, OPEN,
|
||||
REDIAL, kit.Dict("a", 3000, "b", 1000, "c", 1000), TIMEOUT, kit.Dict("c", "10s"),
|
||||
BUFFER, kit.Dict("r", ice.MOD_BUFS, "w", ice.MOD_BUFS),
|
||||
), mdb.ClearHashOnExitAction(), SpaceAction(), aaa.WhiteAction()), Hand: func(m *ice.Message, arg ...string) {
|
||||
LOGIN: {Help: "授权", Hand: func(m *ice.Message, arg ...string) {
|
||||
msg := m.Cmd("", kit.Select(m.Option(mdb.NAME), arg, 0))
|
||||
m.Options(ice.MSG_USERIP, msg.Append(aaa.IP), ice.MSG_USERUA, msg.Append(aaa.UA))
|
||||
m.Cmd("", kit.Select(m.Option(mdb.NAME), arg, 0), ice.MSG_SESSID, aaa.SessCreate(m, m.Option(ice.MSG_USERNAME)))
|
||||
}},
|
||||
SPACE_LOGIN: {Hand: func(m *ice.Message, arg ...string) {
|
||||
kit.If(m.Option(ice.FROM_DAEMON), func(p string) { m.Cmd("", p, GRANT, m.Option(mdb.NAME), -1) })
|
||||
}},
|
||||
OPEN: {Hand: func(m *ice.Message, arg ...string) {
|
||||
switch m.Option(mdb.TYPE) {
|
||||
case ORIGIN:
|
||||
ProcessIframe(m, m.Option(mdb.NAME), SpideOrigin(m, m.Option(mdb.NAME)), arg...)
|
||||
default:
|
||||
ProcessIframe(m, m.Option(mdb.NAME), m.MergePod(m.Option(mdb.NAME)), arg...)
|
||||
}
|
||||
}},
|
||||
nfs.PS: {Hand: func(m *ice.Message, arg ...string) { _space_fork(m) }},
|
||||
}, gdb.EventsAction(SPACE_LOGIN), mdb.HashAction(mdb.LIMIT, 1000, mdb.LEAST, 500,
|
||||
mdb.SHORT, mdb.NAME, mdb.FIELD, "time,type,name,text,main,icons,module,version,agent,system,ip,usernick,username,userrole",
|
||||
ctx.ACTION, OPEN, REDIAL, kit.Dict("a", 1000, "b", 100, "c", 1000),
|
||||
), mdb.ClearOnExitHashAction()), Hand: func(m *ice.Message, arg ...string) {
|
||||
if len(arg) < 2 {
|
||||
mdb.HashSelect(m, arg...).Sort("type,name,text")
|
||||
if len(arg) == 1 && strings.Contains(arg[0], nfs.PT) {
|
||||
ls := kit.Split(arg[0], nfs.PT)
|
||||
m.Cmdy(SPACE, ls[0], SPACE, kit.Keys(ls[1:]))
|
||||
return
|
||||
}
|
||||
defer m.StatusTimeCount(kit.Dict(ice.MAIN, mdb.Config(m, ice.MAIN)))
|
||||
kit.If(len(arg) > 0 && arg[0] != "", func() { m.OptionFields(ice.MSG_DETAIL) })
|
||||
mdb.HashSelect(m.Spawn(), arg...).Table(func(value ice.Maps) {
|
||||
if m.Push("", value, kit.Split(mdb.Config(m, mdb.FIELD))); len(arg) > 0 && arg[0] != "" {
|
||||
m.Push(mdb.STATUS, value[mdb.STATUS]).Push(aaa.UA, value[aaa.UA])
|
||||
}
|
||||
if kit.IsIn(value[mdb.TYPE], WEIXIN, PORTAL) && value[mdb.NAME] != html.CHROME {
|
||||
m.Push(mdb.LINK, m.MergeLink(value[mdb.TEXT]))
|
||||
} else if kit.IsIn(value[mdb.TYPE], WORKER, SERVER) {
|
||||
m.Push(mdb.LINK, m.MergePod(value[mdb.NAME]))
|
||||
} else if kit.IsIn(value[mdb.TYPE], ORIGIN) {
|
||||
m.Push(mdb.LINK, value[mdb.TEXT])
|
||||
} else {
|
||||
m.Push(mdb.LINK, "")
|
||||
}
|
||||
m.PushButton(kit.Select(OPEN, LOGIN, value[mdb.TYPE] == LOGIN), mdb.REMOVE)
|
||||
})
|
||||
m.RewriteAppend(func(value, key string, index int) string {
|
||||
if key == mdb.ICONS && !kit.HasPrefix(value, HTTP) {
|
||||
if m.Appendv(mdb.TYPE)[index] == ORIGIN {
|
||||
if !kit.HasPrefix(value, nfs.PS) {
|
||||
value = kit.MergeURL(nfs.P + value)
|
||||
}
|
||||
if m.Appendv(mdb.NAME)[index] == ice.OPS {
|
||||
value = kit.MergeURL2(m.Option(ice.MSG_USERWEB), value)
|
||||
} else {
|
||||
value = kit.MergeURL2(m.Appendv(mdb.TEXT)[index], value)
|
||||
}
|
||||
} else {
|
||||
if !kit.HasPrefix(value, nfs.PS) {
|
||||
value = kit.MergeURL(nfs.P+value, ice.POD, kit.Keys(m.Option(ice.MSG_USERPOD), m.Appendv(mdb.NAME)[index]))
|
||||
}
|
||||
}
|
||||
}
|
||||
return value
|
||||
})
|
||||
m.Sort("", kit.Simple(aaa.LOGIN, WEIXIN, PORTAL, WORKER, SERVER, ORIGIN))
|
||||
} else {
|
||||
_space_send(m, strings.ToLower(arg[0]), kit.Simple(kit.Split(arg[1]), arg[2:])...)
|
||||
if ice.Info.NodeType != WORKER && arg[0] == ice.OPS {
|
||||
m.Cmdy(arg[1:])
|
||||
return
|
||||
}
|
||||
if kit.IsIn(arg[0], "", ice.Info.NodeName) {
|
||||
m.Cmdy(arg[1:])
|
||||
return
|
||||
}
|
||||
if ice.Info.NodeType == WORKER && !strings.HasPrefix(arg[0], ice.OPS) {
|
||||
arg[0] = kit.Keys(ice.OPS, arg[0])
|
||||
}
|
||||
for i := 0; i < 5; i++ {
|
||||
if _space_send(m, arg[0], kit.Simple(kit.Split(arg[1]), arg[2:])...); !m.IsErrNotFoundSpace() {
|
||||
break
|
||||
} else if i < 4 {
|
||||
m.SetAppend().SetResult().Sleep3s()
|
||||
}
|
||||
}
|
||||
}
|
||||
}},
|
||||
})
|
||||
}
|
||||
|
||||
func SpaceAction() ice.Actions {
|
||||
return gdb.EventsAction(SPACE_START, SPACE_OPEN, SPACE_LOGIN, SPACE_CLOSE, SPACE_STOP)
|
||||
ice.Info.Inputs = append(ice.Info.Inputs, func(m *ice.Message, arg ...string) {
|
||||
switch kit.TrimPrefix(arg[0], "extra.") {
|
||||
case DREAM:
|
||||
m.SetAppend()
|
||||
AdminCmd(m, DREAM).Table(func(value ice.Maps) {
|
||||
kit.If(kit.IsIn(value[mdb.TYPE], WORKER), func() {
|
||||
m.Push(arg[0], value[mdb.NAME])
|
||||
m.PushRecord(value, nfs.VERSION, mdb.TIME, nfs.MODULE, mdb.ICONS)
|
||||
})
|
||||
})
|
||||
case SPACE:
|
||||
AdminCmd(m, SPACE).Table(func(value ice.Maps) {
|
||||
kit.If(kit.IsIn(value[mdb.TYPE], WORKER, SERVER), func() { m.Push(arg[0], value[mdb.NAME]) })
|
||||
})
|
||||
case SERVER:
|
||||
AdminCmd(m, SPACE).Table(func(value ice.Maps) {
|
||||
kit.If(kit.IsIn(value[mdb.TYPE], SERVER), func() { m.Push(arg[0], value[mdb.NAME]) })
|
||||
})
|
||||
case ORIGIN:
|
||||
m.SetAppend().Push(arg[0], SpideOrigin(m, ice.DEV))
|
||||
m.Copy(m.Cmd(SPIDE, kit.Dict(ice.MSG_FIELDS, CLIENT_ORIGIN)).CutTo(CLIENT_ORIGIN, arg[0]).Sort(arg[0]))
|
||||
case mdb.ICONS:
|
||||
m.Options(nfs.DIR_DEEP, ice.TRUE, nfs.DIR_REG, kit.ExtReg(nfs.PNG, nfs.JPG, nfs.JPEG))
|
||||
m.Cmdy(nfs.DIR, nfs.SRC, nfs.PATH)
|
||||
if aaa.IsTechOrRoot(m) {
|
||||
m.Cmdy(nfs.DIR, nfs.USR_LOCAL_IMAGE, nfs.PATH)
|
||||
}
|
||||
m.Cmdy(nfs.DIR, nfs.USR_IMAGE, nfs.PATH)
|
||||
m.Cmdy(nfs.DIR, nfs.USR_ICONS, nfs.PATH)
|
||||
m.CutTo(nfs.PATH, arg[0])
|
||||
case ctx.INDEX, ice.CMD:
|
||||
m.OptionFields(ctx.INDEX)
|
||||
if space := m.Option(SPACE); space != "" {
|
||||
if ice.Info.NodeType == WORKER {
|
||||
m.Options(SPACE, []string{}).Cmdy(SPACE, kit.Keys(ice.OPS, space), ctx.COMMAND)
|
||||
} else {
|
||||
m.Options(SPACE, []string{}).Cmdy(SPACE, space, ctx.COMMAND)
|
||||
}
|
||||
} else {
|
||||
m.Cmdy(ctx.COMMAND)
|
||||
}
|
||||
m.CutTo(ctx.INDEX, arg[0])
|
||||
case ctx.ARGS:
|
||||
m.OptionDefault(ctx.INDEX, m.Option("extra.index"))
|
||||
if space := m.Option(SPACE); space != "" {
|
||||
m.Options(SPACE, []string{}).Cmdy(SPACE, space, ctx.COMMAND, mdb.INPUTS, m.Option(ctx.INDEX))
|
||||
} else {
|
||||
m.Cmdy(ctx.COMMAND, mdb.INPUTS, m.Option(ctx.INDEX))
|
||||
}
|
||||
case tcp.WIFI:
|
||||
m.Cmdy(tcp.WIFI).CutTo(tcp.SSID, arg[0])
|
||||
case MESSAGE:
|
||||
m.Cmdy(MESSAGE).Cut(mdb.HASH, mdb.ZONE, mdb.ICONS)
|
||||
case TARGET:
|
||||
m.AdminCmd(MATRIX).Table(func(value ice.Maps) {
|
||||
m.Push(arg[0], kit.Keys(kit.Select("", ice.OPS, ice.Info.NodeType == WORKER), value[DOMAIN], value[mdb.NAME]))
|
||||
m.Push(mdb.TYPE, value[mdb.TYPE])
|
||||
})
|
||||
m.Sort("type,target", []string{MYSELF, SERVER, ORIGIN, WORKER}, ice.STR_R)
|
||||
}
|
||||
})
|
||||
ice.Info.AdminCmd = AdminCmd
|
||||
ctx.PodCmd = func(m *ice.Message, arg ...ice.Any) bool {
|
||||
Upload(m)
|
||||
if pod := m.Option(ice.POD); pod != "" {
|
||||
if ls := kit.Simple(m.Optionv(ice.MSG_UPLOAD)); len(ls) > 1 {
|
||||
// m.Cmd(SPACE, pod, SPIDE, ice.DEV, CACHE, SHARE_CACHE+ls[0])
|
||||
}
|
||||
m.Options(ice.POD, []string{}, ice.MSG_USERPOD, strings.TrimPrefix(pod, "ops.")).Cmdy(append(kit.List(ice.SPACE, pod), arg...)...)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
func Space(m *ice.Message, arg ice.Any) []string {
|
||||
if arg == nil || arg == "" || kit.Format(arg) == ice.Info.NodeName {
|
||||
if arg == nil || arg == "" {
|
||||
return nil
|
||||
}
|
||||
return []string{SPACE, kit.Format(arg)}
|
||||
}
|
||||
func call(m *ice.Message, timeout string, cb func(*ice.Message)) bool {
|
||||
wait := make(chan bool, 2)
|
||||
t := time.AfterFunc(kit.Duration(timeout), func() {
|
||||
m.Warn(true, ice.ErrNotValid, m.Detailv())
|
||||
m.Optionv("_cb", nil)
|
||||
cb(nil)
|
||||
wait <- false
|
||||
})
|
||||
m.Optionv("_cb", func(res *ice.Message) {
|
||||
t.Stop()
|
||||
cb(res)
|
||||
wait <- true
|
||||
})
|
||||
return <-wait
|
||||
}
|
||||
func back(m *ice.Message, res *ice.Message) bool {
|
||||
switch cb := m.Optionv("_cb").(type) {
|
||||
case func(*ice.Message):
|
||||
cb(res)
|
||||
func PodCmd(m *ice.Message, key string, arg ...string) bool {
|
||||
if pod := m.Option(key); pod != "" {
|
||||
m.Options(key, "", ice.MSG_USERPOD, strings.TrimPrefix(pod, "ops.")).Cmdy(SPACE, pod, m.ShortKey(), arg)
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
return false
|
||||
}
|
||||
func addSend(m *ice.Message, msg *ice.Message) string {
|
||||
return m.Target().Server().(*Frame).addSend(kit.Format(m.Target().ID()), msg)
|
||||
func SpaceName(name string) string {
|
||||
return kit.ReplaceAll(name, nfs.DF, "_", nfs.PS, "_", nfs.PT, "_", "[", "_", "]", "_")
|
||||
}
|
||||
func getSend(m *ice.Message, key string) *ice.Message {
|
||||
return m.Target().Server().(*Frame).getSend(key)
|
||||
func SpacePwd(m *ice.Message, name, text string) {
|
||||
m.Optionv(ice.MSG_OPTS, m.OptionSimple(ice.MSG_USERROLE, ice.MSG_USERNAME))
|
||||
m.Cmd(SPACE, name, cli.PWD, name, kit.Dict(ice.SPACE_NOECHO, ice.TRUE,
|
||||
mdb.ICONS, ice.Info.NodeIcon, mdb.TEXT, text, AGENT, "Go-http-client", cli.SYSTEM, runtime.GOOS,
|
||||
mdb.TIME, ice.Info.Make.Time, nfs.MODULE, ice.Info.Make.Module, nfs.VERSION, ice.Info.Make.Versions(),
|
||||
))
|
||||
}
|
||||
func SpaceEvent(m *ice.Message, event, skip string, arg ...string) {
|
||||
m.Optionv(ice.MSG_OPTS, m.OptionSimple(ice.MSG_USERROLE, ice.MSG_USERNAME))
|
||||
m.Cmds(SPACE).Table(func(value ice.Maps) {
|
||||
if kit.IsIn(value[mdb.TYPE], WORKER) && value[mdb.NAME] != skip {
|
||||
m.Cmd(SPACE, value[mdb.NAME], gdb.EVENT, gdb.HAPPEN, gdb.EVENT, event, arg, kit.Dict(
|
||||
ice.MSG_USERROLE, aaa.TECH, ice.SPACE_NOECHO, ice.TRUE,
|
||||
))
|
||||
}
|
||||
})
|
||||
m.Cmd(gdb.EVENT, gdb.HAPPEN, gdb.EVENT, event, arg, kit.Dict(ice.MSG_USERROLE, aaa.TECH))
|
||||
}
|
||||
|
@ -2,124 +2,138 @@ package web
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/tls"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
ice "shylinux.com/x/icebergs"
|
||||
"shylinux.com/x/icebergs/base/aaa"
|
||||
"shylinux.com/x/icebergs/base/cli"
|
||||
"shylinux.com/x/icebergs/base/ctx"
|
||||
"shylinux.com/x/icebergs/base/log"
|
||||
"shylinux.com/x/icebergs/base/mdb"
|
||||
"shylinux.com/x/icebergs/base/nfs"
|
||||
"shylinux.com/x/icebergs/base/tcp"
|
||||
"shylinux.com/x/icebergs/base/web/html"
|
||||
kit "shylinux.com/x/toolkits"
|
||||
)
|
||||
|
||||
func _spide_create(m *ice.Message, name, address string) {
|
||||
if uri, e := url.Parse(address); !m.Warn(e != nil || address == "", ice.ErrNotValid, address) {
|
||||
m.Logs(mdb.CREATE, SPIDE, name, ADDRESS, address)
|
||||
func _spide_create(m *ice.Message, link, types, name, icons, token string) {
|
||||
if u, e := url.Parse(link); !m.WarnNotValid(e != nil || link == "", link) {
|
||||
dir, file := path.Split(u.EscapedPath())
|
||||
m.Logs(mdb.INSERT, SPIDE, name, LINK, link)
|
||||
mdb.HashSelectUpdate(m, mdb.HashCreate(m, CLIENT_NAME, name), func(value ice.Map) {
|
||||
dir, file := path.Split(uri.EscapedPath())
|
||||
value[SPIDE_CLIENT] = kit.Dict(mdb.NAME, name, SPIDE_METHOD, http.MethodPost, "url", address,
|
||||
tcp.PROTOCOL, uri.Scheme, tcp.HOSTNAME, uri.Host, nfs.PATH, dir, nfs.FILE, file, "query", uri.RawQuery,
|
||||
cli.TIMEOUT, "30s", LOGHEADERS, ice.FALSE,
|
||||
value[mdb.ICONS], value[TOKEN] = icons, kit.Select(kit.Format(value[TOKEN]), token)
|
||||
value[SPIDE_CLIENT] = kit.Dict(mdb.NAME, name, mdb.TYPE, types,
|
||||
SPIDE_METHOD, http.MethodGet, URL, link, ORIGIN, u.Scheme+"://"+u.Host,
|
||||
tcp.PROTOCOL, u.Scheme, tcp.HOSTNAME, u.Hostname(), tcp.HOST, u.Host, nfs.PATH, dir, nfs.FILE, file, cli.TIMEOUT, "300s",
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
func _spide_show(m *ice.Message, name string, arg ...string) {
|
||||
file := ""
|
||||
action, arg := _spide_args(m, arg, SPIDE_RAW, SPIDE_DETAIL, SPIDE_MSG, SPIDE_SAVE, SPIDE_CACHE, SPIDE_STREAM)
|
||||
kit.If(action == SPIDE_SAVE, func() { file, arg = arg[0], arg[1:] })
|
||||
msg := mdb.HashSelects(m.Spawn(), name)
|
||||
method, arg := _spide_args(m, arg, http.MethodGet, http.MethodPut, http.MethodPost, http.MethodDelete)
|
||||
method = kit.Select(http.MethodGet, msg.Append(CLIENT_METHOD), method)
|
||||
uri, arg := arg[0], arg[1:]
|
||||
body, head, arg := _spide_body(m, method, arg...)
|
||||
if m.Option("spide.break") == ice.TRUE {
|
||||
return
|
||||
}
|
||||
if c, ok := body.(io.Closer); ok {
|
||||
defer c.Close()
|
||||
}
|
||||
_uri := kit.MergeURL2(msg.Append(CLIENT_URL), uri, arg)
|
||||
req, e := http.NewRequest(method, _uri, body)
|
||||
if m.WarnNotValid(e, uri) {
|
||||
return
|
||||
}
|
||||
mdb.HashSelectDetail(m, name, func(value ice.Map) { _spide_head(m, req, head, value) })
|
||||
if m.Option(log.DEBUG) == ice.TRUE {
|
||||
kit.For(req.Header, func(k string, v []string) { m.Logs(REQUEST, k, v) })
|
||||
}
|
||||
res, e := _spide_send(m, name, req, kit.Format(m.OptionDefault(CLIENT_TIMEOUT, msg.Append(CLIENT_TIMEOUT))))
|
||||
if m.WarnNotFound(e, SPIDE, uri) {
|
||||
return
|
||||
}
|
||||
defer res.Body.Close()
|
||||
m.Cost(cli.STATUS, res.Status, nfs.SIZE, kit.FmtSize(kit.Int64(res.Header.Get(html.ContentLength))), mdb.TYPE, res.Header.Get(html.ContentType))
|
||||
if action == SPIDE_DETAIL {
|
||||
m.Push(mdb.TYPE, STATUS).Push(mdb.NAME, res.StatusCode).Push(mdb.VALUE, res.Status)
|
||||
}
|
||||
m.Options(STATUS, res.Status)
|
||||
kit.For(res.Header, func(k string, v []string) {
|
||||
if m.Option(log.DEBUG) == ice.TRUE {
|
||||
m.Logs(RESPONSE, k, v)
|
||||
}
|
||||
if m.Options(k, v); action == SPIDE_DETAIL {
|
||||
m.Push(mdb.TYPE, SPIDE_HEADER).Push(mdb.NAME, k).Push(mdb.VALUE, v[0])
|
||||
}
|
||||
})
|
||||
mdb.HashSelectUpdate(m, name, func(value ice.Map) {
|
||||
kit.For(res.Cookies(), func(v *http.Cookie) {
|
||||
kit.Value(value, kit.Keys(SPIDE_COOKIE, v.Name), v.Value)
|
||||
if m.Option(log.DEBUG) == ice.TRUE {
|
||||
m.Logs(RESPONSE, v.Name, v.Value)
|
||||
}
|
||||
if action == SPIDE_DETAIL {
|
||||
m.Push(mdb.TYPE, COOKIE).Push(mdb.NAME, v.Name).Push(mdb.VALUE, v.Value)
|
||||
}
|
||||
})
|
||||
})
|
||||
if m.WarnNotValid(res.StatusCode != http.StatusOK && res.StatusCode != http.StatusCreated && res.StatusCode != http.StatusNoContent, uri, cli.STATUS, res.Status) {
|
||||
switch res.StatusCode {
|
||||
case http.StatusNotFound, http.StatusUnauthorized:
|
||||
return
|
||||
}
|
||||
}
|
||||
_spide_save(m, action, file, uri, res)
|
||||
}
|
||||
func _spide_args(m *ice.Message, arg []string, val ...string) (string, []string) {
|
||||
if kit.IndexOf(val, arg[0]) > -1 {
|
||||
return arg[0], arg[1:]
|
||||
}
|
||||
return "", arg
|
||||
}
|
||||
func _spide_show(m *ice.Message, name string, arg ...string) {
|
||||
msg := mdb.HashSelects(m.Spawn(), name)
|
||||
if len(arg) == 1 && msg.Append(arg[0]) != "" {
|
||||
m.Echo(msg.Append(arg[0]))
|
||||
return
|
||||
}
|
||||
format, arg := _spide_args(m, arg, SPIDE_RAW, SPIDE_MSG, SPIDE_CACHE, SPIDE_SAVE)
|
||||
file := ""
|
||||
if format == SPIDE_SAVE {
|
||||
file, arg = arg[0], arg[1:]
|
||||
}
|
||||
method, arg := _spide_args(m, arg, http.MethodGet, http.MethodPut, http.MethodPost, http.MethodDelete)
|
||||
method = kit.Select(http.MethodPost, kit.Select(msg.Append(CLIENT_METHOD), method))
|
||||
uri, arg := arg[0], arg[1:]
|
||||
body, head, arg := _spide_body(m, method, arg...)
|
||||
if c, ok := body.(io.Closer); ok {
|
||||
defer c.Close()
|
||||
}
|
||||
req, e := http.NewRequest(method, kit.MergeURL2(msg.Append(CLIENT_URL), uri, arg), body)
|
||||
if m.Warn(e, ice.ErrNotValid, uri) {
|
||||
return
|
||||
}
|
||||
mdb.HashSelectDetail(m, name, func(value ice.Map) { _spide_head(m, req, head, value) })
|
||||
res, e := _spide_send(m, name, req, kit.Format(msg.Append(CLIENT_TIMEOUT)))
|
||||
if m.Warn(e, ice.ErrNotFound, uri) {
|
||||
return
|
||||
}
|
||||
defer res.Body.Close()
|
||||
if m.Config(LOGHEADERS) == ice.TRUE {
|
||||
for k, v := range res.Header {
|
||||
m.Logs(mdb.IMPORT, k, v)
|
||||
}
|
||||
}
|
||||
m.Cost(cli.STATUS, res.Status, nfs.SIZE, res.Header.Get(ContentLength), mdb.TYPE, res.Header.Get(ContentType))
|
||||
mdb.HashSelectUpdate(m, name, func(value ice.Map) {
|
||||
for _, v := range res.Cookies() {
|
||||
kit.Value(value, kit.Keys(SPIDE_COOKIE, v.Name), v.Value)
|
||||
m.Logs(mdb.IMPORT, v.Name, v.Value)
|
||||
}
|
||||
})
|
||||
if m.Warn(res.StatusCode != http.StatusOK, ice.ErrNotValid, uri, cli.STATUS, res.Status) {
|
||||
switch res.StatusCode {
|
||||
case http.StatusNotFound, http.StatusUnauthorized:
|
||||
return
|
||||
}
|
||||
}
|
||||
_spide_save(m, format, file, uri, res)
|
||||
}
|
||||
func _spide_body(m *ice.Message, method string, arg ...string) (io.Reader, ice.Maps, []string) {
|
||||
head := ice.Maps{}
|
||||
body, ok := m.Optionv(SPIDE_BODY).(io.Reader)
|
||||
if !ok && len(arg) > 0 && method != http.MethodGet {
|
||||
if len(arg) == 1 {
|
||||
arg = []string{SPIDE_DATA, arg[0]}
|
||||
}
|
||||
switch arg[0] {
|
||||
case SPIDE_FORM:
|
||||
arg = kit.Simple(arg, func(v string) string { return url.QueryEscape(v) })
|
||||
head[ContentType], body = ContentFORM, bytes.NewBufferString(kit.JoinKV("=", "&", arg[1:]...))
|
||||
case SPIDE_PART:
|
||||
head[ContentType], body = _spide_part(m, arg...)
|
||||
case SPIDE_DATA:
|
||||
head[ContentType], body = ContentJSON, bytes.NewBufferString(kit.Select("{}", arg, 1))
|
||||
case SPIDE_FILE:
|
||||
if f, e := nfs.OpenFile(m, arg[1]); m.Assert(e) {
|
||||
m.Logs(mdb.IMPORT, nfs.FILE, arg[1])
|
||||
body = f
|
||||
}
|
||||
case SPIDE_JSON:
|
||||
arg = arg[1:]
|
||||
fallthrough
|
||||
default:
|
||||
data := ice.Map{}
|
||||
kit.Fetch(arg, func(k, v string) { kit.Value(data, k, v) })
|
||||
head[ContentType], body = ContentJSON, bytes.NewBufferString(kit.Format(data))
|
||||
}
|
||||
arg = arg[:0]
|
||||
} else {
|
||||
body = bytes.NewBuffer([]byte{})
|
||||
if ok || method == http.MethodGet || len(arg) == 0 {
|
||||
return body, nil, arg
|
||||
}
|
||||
return body, head, arg
|
||||
head := ice.Maps{}
|
||||
switch kit.If(len(arg) == 1, func() { arg = []string{SPIDE_DATA, arg[0]} }); arg[0] {
|
||||
case SPIDE_FORM:
|
||||
// arg = kit.Simple(arg, func(v string) string { return url.QueryEscape(v) })
|
||||
head[html.ContentType], body = html.ApplicationForm, bytes.NewBufferString(kit.JoinQuery(arg[1:]...))
|
||||
m.Info("debug what %v", kit.JoinQuery(arg[1:]...))
|
||||
case SPIDE_PART:
|
||||
head[html.ContentType], body = _spide_part(m, arg...)
|
||||
case SPIDE_FILE:
|
||||
if f, e := nfs.OpenFile(m, arg[1]); m.Assert(e) {
|
||||
m.Logs(nfs.LOAD, nfs.FILE, arg[1])
|
||||
body = f
|
||||
}
|
||||
case SPIDE_DATA:
|
||||
head[html.ContentType], body = html.ApplicationJSON, bytes.NewBufferString(kit.Select("{}", arg, 1))
|
||||
case SPIDE_JSON:
|
||||
arg = arg[1:]
|
||||
fallthrough
|
||||
default:
|
||||
data := ice.Map{}
|
||||
kit.For(arg, func(k, v string) { kit.Value(data, k, v) })
|
||||
head[html.ContentType], body = html.ApplicationJSON, bytes.NewBufferString(kit.Format(data))
|
||||
}
|
||||
return body, head, arg[:0]
|
||||
}
|
||||
func _spide_part(m *ice.Message, arg ...string) (string, io.Reader) {
|
||||
buf := &bytes.Buffer{}
|
||||
@ -130,21 +144,26 @@ func _spide_part(m *ice.Message, arg ...string) (string, io.Reader) {
|
||||
if arg[i] == nfs.SIZE {
|
||||
size = kit.Int64(arg[i+1])
|
||||
} else if arg[i] == SPIDE_CACHE {
|
||||
if t, e := time.ParseInLocation(ice.MOD_TIME, arg[i+1], time.Local); !m.Warn(e, ice.ErrNotValid) {
|
||||
if t, e := time.ParseInLocation(ice.MOD_TIME, arg[i+1], time.Local); !m.WarnNotValid(e) {
|
||||
cache = t
|
||||
}
|
||||
} else if strings.HasPrefix(arg[i+1], ice.AT) {
|
||||
if s, e := nfs.StatFile(m, arg[i+1][1:]); !m.Warn(e, ice.ErrNotValid) {
|
||||
} else if strings.HasPrefix(arg[i+1], mdb.AT) {
|
||||
p := arg[i+1][1:]
|
||||
if s, e := nfs.StatFile(m, p); !m.WarnNotValid(e) {
|
||||
if s.Size() == size && s.ModTime().Before(cache) {
|
||||
m.Option("spide.break", ice.TRUE)
|
||||
continue
|
||||
} else if s.Size() == size && !nfs.Exists(m.Spawn(kit.Dict(ice.MSG_FILES, nfs.DiskFile)), p) {
|
||||
m.Option("spide.break", ice.TRUE)
|
||||
continue
|
||||
}
|
||||
m.Logs(mdb.IMPORT, "local", s.ModTime(), nfs.SIZE, s.Size(), CACHE, cache, nfs.SIZE, size)
|
||||
m.Logs(nfs.FIND, LOCAL, s.ModTime(), nfs.SIZE, s.Size(), CACHE, cache, nfs.SIZE, size)
|
||||
}
|
||||
if f, e := nfs.OpenFile(m, arg[i+1][1:]); !m.Warn(e, ice.ErrNotValid, arg[i+1]) {
|
||||
if f, e := nfs.OpenFile(m, p); !m.WarnNotValid(e, arg[i+1]) {
|
||||
defer f.Close()
|
||||
if p, e := mp.CreateFormFile(arg[i], path.Base(arg[i+1][1:])); !m.Warn(e, ice.ErrNotValid, arg[i+1]) {
|
||||
if n, e := io.Copy(p, f); !m.Warn(e, ice.ErrNotValid, arg[i+1]) {
|
||||
m.Logs(mdb.EXPORT, nfs.FILE, arg[i+1], nfs.SIZE, n)
|
||||
if p, e := mp.CreateFormFile(arg[i], path.Base(p)); !m.WarnNotValid(e, arg[i+1]) {
|
||||
if n, e := io.Copy(p, f); !m.WarnNotValid(e, arg[i+1]) {
|
||||
m.Logs(nfs.LOAD, nfs.FILE, arg[i+1], nfs.SIZE, n)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -156,55 +175,61 @@ func _spide_part(m *ice.Message, arg ...string) (string, io.Reader) {
|
||||
}
|
||||
func _spide_head(m *ice.Message, req *http.Request, head ice.Maps, value ice.Map) {
|
||||
m.Logs(req.Method, req.URL.String())
|
||||
kit.Fetch(value[SPIDE_HEADER], func(k string, v string) {
|
||||
req.Header.Set(k, v)
|
||||
m.Logs("Header", k, v)
|
||||
kit.For(head, func(k, v string) { req.Header.Set(k, v) })
|
||||
kit.For(value[SPIDE_HEADER], func(k string, v string) { req.Header.Set(k, v) })
|
||||
kit.For(value[SPIDE_COOKIE], func(k string, v string) { req.AddCookie(&http.Cookie{Name: k, Value: v}) })
|
||||
kit.For(kit.Simple(m.Optionv(SPIDE_COOKIE)), func(k, v string) { req.AddCookie(&http.Cookie{Name: k, Value: v}) })
|
||||
kit.For(kit.Simple(m.Optionv(SPIDE_HEADER)), func(k, v string) { req.Header.Set(k, v) })
|
||||
kit.If(req.Method == http.MethodPost, func() {
|
||||
m.Logs(kit.Select(ice.AUTO, req.Header.Get(html.ContentLength)), req.Header.Get(html.ContentType))
|
||||
})
|
||||
kit.Fetch(value[SPIDE_COOKIE], func(k string, v string) {
|
||||
req.AddCookie(&http.Cookie{Name: k, Value: v})
|
||||
m.Logs("Cookie", k, v)
|
||||
})
|
||||
kit.Fetch(kit.Simple(m.Optionv(SPIDE_COOKIE)), func(k, v string) {
|
||||
req.AddCookie(&http.Cookie{Name: k, Value: v})
|
||||
m.Logs("Cookie", k, v)
|
||||
})
|
||||
kit.Fetch(kit.Simple(m.Optionv(SPIDE_HEADER)), func(k, v string) {
|
||||
req.Header.Set(k, v)
|
||||
m.Logs("Header", k, v)
|
||||
})
|
||||
kit.Fetch(head, func(k, v string) {
|
||||
req.Header.Set(k, v)
|
||||
m.Logs("Header", k, v)
|
||||
})
|
||||
if req.Method == http.MethodPost {
|
||||
m.Logs(kit.Select(ice.AUTO, req.Header.Get(ContentLength)), req.Header.Get(ContentType))
|
||||
}
|
||||
}
|
||||
func _spide_send(m *ice.Message, name string, req *http.Request, timeout string) (*http.Response, error) {
|
||||
client := mdb.HashSelectTarget(m, name, func() ice.Any { return &http.Client{Timeout: kit.Duration(timeout)} }).(*http.Client)
|
||||
client := mdb.HashSelectTarget(m, name, func() ice.Any {
|
||||
if name == ice.OPS {
|
||||
return &http.Client{Timeout: kit.Duration(timeout), Transport: &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}}}
|
||||
}
|
||||
return &http.Client{Timeout: kit.Duration(timeout)}
|
||||
}).(*http.Client)
|
||||
return client.Do(req)
|
||||
}
|
||||
func _spide_save(m *ice.Message, format, file, uri string, res *http.Response) {
|
||||
switch format {
|
||||
case SPIDE_RAW:
|
||||
if b, _ := ioutil.ReadAll(res.Body); strings.HasPrefix(res.Header.Get(ContentType), ContentJSON) {
|
||||
m.Echo(kit.Formats(kit.UnMarshal(string(b))))
|
||||
} else {
|
||||
m.Echo(string(b))
|
||||
}
|
||||
func _spide_save(m *ice.Message, action, file, uri string, res *http.Response) {
|
||||
m.SetResult()
|
||||
switch action {
|
||||
case SPIDE_RAW, SPIDE_DETAIL:
|
||||
b, _ := ioutil.ReadAll(res.Body)
|
||||
m.Echo(string(b))
|
||||
case SPIDE_MSG:
|
||||
var data map[string][]string
|
||||
m.Assert(json.NewDecoder(res.Body).Decode(&data))
|
||||
kit.Fetch(data[ice.MSG_APPEND], func(k string) { kit.Fetch(data[k], func(v string) { m.Push(k, v) }) })
|
||||
kit.For(data[ice.MSG_OPTION], func(k string) { m.Options(k, data[k]) })
|
||||
kit.For(data[ice.MSG_APPEND], func(k string) { kit.For(data[k], func(v string) { m.Push(k, v) }) })
|
||||
m.Resultv(data[ice.MSG_RESULT])
|
||||
case SPIDE_SAVE:
|
||||
_cache_download(m, res, file, m.OptionCB(SPIDE))
|
||||
if strings.HasSuffix(file, "/") {
|
||||
file += kit.Select("", kit.Split(m.Option("Content-Disposition"), ";="), -1)
|
||||
m.Info("save file %v", file)
|
||||
}
|
||||
m.Echo(_cache_download(m, res, file, m.OptionCB(SPIDE)))
|
||||
case SPIDE_CACHE:
|
||||
m.Cmdy(CACHE, DOWNLOAD, res.Header.Get(ContentType), uri, kit.Dict(RESPONSE, res), m.OptionCB(SPIDE))
|
||||
m.Cmdy(CACHE, DOWNLOAD, res.Header.Get(html.ContentType), uri, kit.Dict(RESPONSE, res), m.OptionCB(SPIDE))
|
||||
m.Echo(m.Append(mdb.HASH))
|
||||
case SPIDE_STREAM:
|
||||
cb, ok := m.Optionv(SPIDE_STREAM).(func(string))
|
||||
if !ok {
|
||||
cb = func(text string) { PushNoticeGrow(m, m.Option("which"), text) }
|
||||
}
|
||||
b := make([]byte, 1024)
|
||||
for {
|
||||
if n, e := res.Body.Read(b); e != nil {
|
||||
break
|
||||
} else {
|
||||
cb(string(b[:n]))
|
||||
}
|
||||
}
|
||||
default:
|
||||
var data ice.Any
|
||||
if b, e := ioutil.ReadAll(res.Body); !m.Warn(e) {
|
||||
if b, e := ioutil.ReadAll(res.Body); !m.WarnNotFound(e) {
|
||||
if json.Unmarshal(b, &data) == nil {
|
||||
m.Push("", kit.KeyValue(ice.Map{}, "", m.Optionv(SPIDE_RES, data)))
|
||||
} else {
|
||||
@ -215,105 +240,238 @@ func _spide_save(m *ice.Message, format, file, uri string, res *http.Response) {
|
||||
}
|
||||
|
||||
const (
|
||||
SPIDE_RAW = "raw"
|
||||
SPIDE_MSG = "msg"
|
||||
SPIDE_CACHE = "cache"
|
||||
SPIDE_SAVE = "save"
|
||||
SPIDE_RAW = "raw"
|
||||
SPIDE_DETAIL = "detail"
|
||||
SPIDE_MSG = "msg"
|
||||
SPIDE_SAVE = "save"
|
||||
SPIDE_CACHE = "cache"
|
||||
SPIDE_STREAM = "stream"
|
||||
|
||||
SPIDE_BODY = "body"
|
||||
SPIDE_FORM = "form"
|
||||
SPIDE_PART = "part"
|
||||
SPIDE_JSON = "json"
|
||||
SPIDE_DATA = "data"
|
||||
SPIDE_FILE = "file"
|
||||
SPIDE_DATA = "data"
|
||||
SPIDE_JSON = "json"
|
||||
SPIDE_RES = "content_data"
|
||||
|
||||
Bearer = "Bearer"
|
||||
Authorization = "Authorization"
|
||||
ContentType = "Content-Type"
|
||||
ContentLength = "Content-Length"
|
||||
UserAgent = "User-Agent"
|
||||
Referer = "Referer"
|
||||
Accept = "Accept"
|
||||
|
||||
ContentFORM = "application/x-www-form-urlencoded"
|
||||
ContentJSON = "application/json"
|
||||
ContentPNG = "image/png"
|
||||
ContentHTML = "text/html"
|
||||
ContentCSS = "text/css"
|
||||
IMAGE_JPEG = "image/jpeg"
|
||||
IMAGE_PNG = "image/png"
|
||||
TEXT_HTML = "text/html"
|
||||
TEXT_CSS = "text/css"
|
||||
)
|
||||
const (
|
||||
SPIDE_CLIENT = "client"
|
||||
SPIDE_METHOD = "method"
|
||||
SPIDE_HEADER = "header"
|
||||
SPIDE_COOKIE = "cookie"
|
||||
SPIDE_HEADER = "header"
|
||||
|
||||
CLIENT_URL = "client.url"
|
||||
CLIENT_NAME = "client.name"
|
||||
CLIENT_TYPE = "client.type"
|
||||
CLIENT_METHOD = "client.method"
|
||||
CLIENT_ORIGIN = "client.origin"
|
||||
CLIENT_TIMEOUT = "client.timeout"
|
||||
CLIENT_PROTOCOL = "client.protocol"
|
||||
CLIENT_HOSTNAME = "client.hostname"
|
||||
CLIENT_HOST = "client.host"
|
||||
|
||||
CLIENT_NAME = "client.name"
|
||||
CLIENT_METHOD = "client.method"
|
||||
CLIENT_TIMEOUT = "client.timeout"
|
||||
CLIENT_URL = "client.url"
|
||||
LOGHEADERS = "logheaders"
|
||||
OPEN = "open"
|
||||
MAIN = "main"
|
||||
FULL = "full"
|
||||
LINK = "link"
|
||||
MERGE = "merge"
|
||||
VENDOR = "vendor"
|
||||
|
||||
OPEN = "open"
|
||||
FULL = "full"
|
||||
LINK = "link"
|
||||
HTTP = "http"
|
||||
FORM = "form"
|
||||
MERGE = "merge"
|
||||
ADDRESS = "address"
|
||||
REQUEST = "request"
|
||||
RESPONSE = "response"
|
||||
QS = "?"
|
||||
)
|
||||
|
||||
var agentIcons = map[string]string{
|
||||
html.Safari: "usr/icons/Safari.png",
|
||||
html.Chrome: "usr/icons/Chrome.png",
|
||||
html.Edg: "usr/icons/Edg.png",
|
||||
html.MicroMessenger: "usr/icons/wechat.png",
|
||||
"Go-http-client": "usr/icons/go.png",
|
||||
}
|
||||
|
||||
const SPIDE = "spide"
|
||||
|
||||
func init() {
|
||||
Index.MergeCommands(ice.Commands{
|
||||
SPIDE: {Name: "spide client.name action=raw,msg,save,cache method=GET,PUT,POST,DELETE url format=form,part,json,data,file arg run create", Help: "蜘蛛侠", Actions: ice.MergeActions(ice.Actions{
|
||||
// SPIDE: {Name: "spide client.name action=raw,msg,save,cache method=GET,PUT,POST,DELETE url format=form,part,json,data,file arg run create", Help: "蜘蛛侠", Actions: ice.MergeActions(ice.Actions{
|
||||
SPIDE: {Help: "蜘蛛侠", Icon: "Find My.png", Meta: kit.Dict(ice.CTX_TRANS, kit.Dict(html.INPUT, kit.Dict(
|
||||
CLIENT_TYPE, "类型", CLIENT_NAME, "名称", CLIENT_URL, "地址",
|
||||
CLIENT_METHOD, "方法", CLIENT_ORIGIN, "服务", CLIENT_TIMEOUT, "超时",
|
||||
CLIENT_PROTOCOL, "协议", CLIENT_HOST, "主机", CLIENT_HOSTNAME, "机器",
|
||||
))), Actions: ice.MergeActions(ice.Actions{
|
||||
ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) {
|
||||
conf := m.Confm(cli.RUNTIME, cli.CONF)
|
||||
m.Cmd("", mdb.CREATE, ice.OPS, kit.Select("http://127.0.0.1:9020", conf[cli.CTX_OPS]))
|
||||
m.Cmd("", mdb.CREATE, ice.DEV, kit.Select("http://contexts.woa.com:80", conf[cli.CTX_DEV]))
|
||||
m.Cmd("", mdb.CREATE, ice.COM, kit.Select("https://contexts.com:443", conf[cli.CTX_COM]))
|
||||
m.Cmd("", mdb.CREATE, ice.SHY, kit.Select("https://shylinux.com:443", conf[cli.CTX_SHY]))
|
||||
conf := mdb.Confm(m, cli.RUNTIME, cli.CONF)
|
||||
dev := kit.Select("https://dev.shylinux.com", ice.Info.Make.Domain, conf[cli.CTX_DEV])
|
||||
m.Cmd("", mdb.CREATE, dev, ice.DEV, ice.SRC_MAIN_ICO, nfs.REPOS)
|
||||
m.Cmd("", mdb.CREATE, kit.Select(dev, os.Getenv("ctx_dev_ip")), ice.DEV_IP, ice.SRC_MAIN_ICO, "dev_ip")
|
||||
m.Cmd("", mdb.CREATE, kit.Select("http://localhost:9020", conf[cli.CTX_OPS]), ice.OPS, ice.SRC_MAIN_ICO, nfs.REPOS)
|
||||
m.Cmd("", mdb.CREATE, kit.Select("https://shylinux.com", conf[cli.CTX_SHY]), ice.SHY, ice.SRC_MAIN_ICO, nfs.REPOS)
|
||||
m.Cmd("", mdb.CREATE, kit.Select("https://mail.shylinux.com", conf[cli.CTX_MAIL]), ice.MAIL, "usr/icons/Mail.png", "mail")
|
||||
m.Cmd("", mdb.CREATE, kit.Select("https://demo.shylinux.com", conf[cli.CTX_DEMO]), ice.DEMO, ice.SRC_MAIN_ICO, "demo")
|
||||
m.Cmd("", mdb.CREATE, "https://2023.shylinux.com", "2023-ContextOS", ice.SRC_MAIN_ICO, nfs.REPOS)
|
||||
m.Cmd("", mdb.CREATE, "https://2024.shylinux.com", "2024-ContextOS", ice.SRC_MAIN_ICO, nfs.REPOS)
|
||||
m.Cmd("", mdb.CREATE, "https://2025.shylinux.com", "2025-ContextOS", ice.SRC_MAIN_ICO, nfs.REPOS)
|
||||
}},
|
||||
mdb.CREATE: {Name: "create name address", Hand: func(m *ice.Message, arg ...string) { _spide_create(m, m.Option(mdb.NAME), m.Option(ADDRESS)) }},
|
||||
tcp.CLIENT: {Hand: func(m *ice.Message, arg ...string) {
|
||||
msg := m.Cmd("", kit.Select(ice.DEV, arg, 0))
|
||||
ls := kit.Split(msg.Append(CLIENT_HOSTNAME), ice.DF)
|
||||
m.Push(tcp.HOST, ls[0]).Push(tcp.PORT, kit.Select(kit.Select("443", "80", msg.Append(CLIENT_PROTOCOL) == ice.HTTP), ls, 1))
|
||||
m.Push(DOMAIN, msg.Append(CLIENT_PROTOCOL)+"://"+msg.Append(CLIENT_HOSTNAME)+kit.Select("", arg, 1))
|
||||
m.Push(tcp.PROTOCOL, msg.Append(CLIENT_PROTOCOL)).Push(tcp.HOSTNAME, msg.Append(CLIENT_HOSTNAME))
|
||||
mdb.SEARCH: {Hand: func(m *ice.Message, arg ...string) {
|
||||
if mdb.IsSearchPreview(m, arg) {
|
||||
mdb.HashSelectValue(m.Spawn(), func(value ice.Map) {
|
||||
m.PushSearch(mdb.TYPE, LINK, mdb.NAME, kit.Value(value, CLIENT_NAME), mdb.TEXT, kit.Value(value, CLIENT_ORIGIN), value)
|
||||
})
|
||||
}
|
||||
}},
|
||||
mdb.INPUTS: {Hand: func(m *ice.Message, arg ...string) {
|
||||
switch m.Option(ctx.ACTION) {
|
||||
case COOKIE:
|
||||
switch arg[0] {
|
||||
case mdb.KEY:
|
||||
m.Push(arg[0], ice.MSG_SESSID)
|
||||
}
|
||||
case HEADER:
|
||||
switch arg[0] {
|
||||
case mdb.KEY:
|
||||
m.Push(arg[0], html.Authorization)
|
||||
}
|
||||
case CLIENT_NAME:
|
||||
mdb.HashSelectValue(m.Spawn(), func(value ice.Map) {
|
||||
m.Push(arg[0], kit.Value(value, CLIENT_NAME))
|
||||
m.Push(mdb.TYPE, kit.Value(value, CLIENT_TYPE))
|
||||
})
|
||||
m.Sort(arg[0])
|
||||
default:
|
||||
switch arg[0] {
|
||||
case mdb.NAME, mdb.ICONS:
|
||||
m.SplitIndex(m.Cmdx(SPIDE, ice.DEV, kit.MergeURL2(m.Option(ORIGIN), C(SPACE, ice.INFO)))).Cut(arg[0])
|
||||
mdb.HashInputs(m, arg)
|
||||
default:
|
||||
mdb.HashSelectValue(m.Spawn(), func(value ice.Map) {
|
||||
m.Push(kit.Select(ORIGIN, arg, 0), kit.Value(value, kit.Keys("client", arg[0])))
|
||||
})
|
||||
kit.If(arg[0] == mdb.TYPE, func() { m.Push(arg[0], nfs.REPOS) })
|
||||
m.Sort(arg[0])
|
||||
}
|
||||
}
|
||||
}},
|
||||
mdb.CREATE: {Name: "create origin* name icons type token", Hand: func(m *ice.Message, arg ...string) {
|
||||
if m.Option(mdb.TYPE) == nfs.REPOS && (m.Option(mdb.NAME) == "" || m.Option(mdb.ICONS) == "") {
|
||||
msg := m.Spawn().SplitIndex(m.Cmdx(SPIDE, ice.DEV, kit.MergeURL2(m.Option(ORIGIN), C(SPACE, ice.INFO))))
|
||||
if m.OptionDefault(mdb.NAME, msg.Append(mdb.NAME)); msg.Append(mdb.ICONS) != "" {
|
||||
m.OptionDefault(mdb.ICONS, m.Resource(msg.Append(mdb.ICONS), msg.Append(ORIGIN)))
|
||||
}
|
||||
}
|
||||
if u, e := url.Parse(m.Option(ORIGIN)); m.WarnNotValid(e != nil || u.Host == "", m.Option(ORIGIN)) {
|
||||
return
|
||||
} else {
|
||||
m.OptionDefault(mdb.NAME, kit.Split(u.Host, ".:")[0])
|
||||
kit.If(u.Query().Get(TOKEN), func(p string) { m.OptionDefault(TOKEN, p) })
|
||||
_spide_create(m, m.Option(ORIGIN), m.Option(mdb.TYPE), m.Option(mdb.NAME), m.Option(mdb.ICONS), m.Option(TOKEN))
|
||||
}
|
||||
}},
|
||||
COOKIE: {Name: "cookie key* value", Help: "状态量", Hand: func(m *ice.Message, arg ...string) {
|
||||
mdb.HashModify(m, m.OptionSimple(CLIENT_NAME), kit.Keys(COOKIE, m.Option(mdb.KEY)), m.Option(mdb.VALUE))
|
||||
}},
|
||||
HEADER: {Name: "header key* value", Help: "请求头", Hand: func(m *ice.Message, arg ...string) {
|
||||
mdb.HashModify(m, m.OptionSimple(CLIENT_NAME), kit.Keys(HEADER, m.Option(mdb.KEY)), m.Option(mdb.VALUE))
|
||||
}},
|
||||
MERGE: {Hand: func(m *ice.Message, arg ...string) {
|
||||
m.Echo(kit.MergeURL2(m.CmdAppend("", arg[0], CLIENT_URL), arg[1], arg[2:]))
|
||||
m.Echo(kit.MergeURL2(m.Cmdv("", arg[0], CLIENT_URL), arg[1], arg[2:]))
|
||||
}},
|
||||
}, mdb.HashAction(mdb.SHORT, CLIENT_NAME, mdb.FIELD, "time,client.name,client.url", LOGHEADERS, ice.FALSE), mdb.ClearHashOnExitAction()), Hand: func(m *ice.Message, arg ...string) {
|
||||
PROXY: {Name: "proxy url size cache upload", Hand: func(m *ice.Message, arg ...string) {
|
||||
m.Cmdy(SPIDE, ice.DEV, SPIDE_RAW, http.MethodPost, m.Option(URL), SPIDE_PART, arg[2:])
|
||||
}},
|
||||
"disconn": {Help: "断连", Icon: "bi bi-person-x", Style: "danger", Hand: func(m *ice.Message, arg ...string) {
|
||||
m.Cmd(SPACE, cli.CLOSE, kit.Dict(mdb.NAME, m.Option(CLIENT_NAME)))
|
||||
mdb.HashModify(m, mdb.NAME, m.Option(CLIENT_NAME), TOKEN, "")
|
||||
}},
|
||||
DEV_CREATE_TOKEN: {Hand: func(m *ice.Message, arg ...string) {
|
||||
m.OptionDefault(CLIENT_NAME, m.Option(ice.FROM_SPACE))
|
||||
mdb.HashModify(m, m.OptionSimple(CLIENT_NAME, TOKEN))
|
||||
m.Cmd(SPACE, tcp.DIAL, m.Option(CLIENT_NAME)).Sleep300ms()
|
||||
}},
|
||||
DEV_REQUEST_TEXT: {Hand: func(m *ice.Message, arg ...string) { m.Echo(SpaceName(ice.Info.NodeName)) }},
|
||||
}, DevTokenAction(CLIENT_NAME, CLIENT_URL), mdb.ImportantHashAction(mdb.SHORT, CLIENT_NAME, mdb.FIELD, "time,icons,client.name,client.url,client.type,token")), Hand: func(m *ice.Message, arg ...string) {
|
||||
if len(arg) < 2 || arg[0] == "" || (len(arg) > 3 && arg[3] == "") {
|
||||
mdb.HashSelect(m, kit.Slice(arg, 0, 1)...).Sort(CLIENT_NAME)
|
||||
list := m.CmdMap(SPACE, mdb.NAME)
|
||||
mdb.HashSelect(m, kit.Slice(arg, 0, 1)...).Table(func(value ice.Maps) {
|
||||
if value[CLIENT_TYPE] == nfs.REPOS {
|
||||
if _, ok := list[value[CLIENT_NAME]]; ok {
|
||||
m.Push(mdb.STATUS, ONLINE).PushButton(mdb.DEV_REQUEST, "disconn", mdb.REMOVE)
|
||||
} else {
|
||||
m.Push(mdb.STATUS, "").PushButton(mdb.DEV_REQUEST, mdb.REMOVE)
|
||||
}
|
||||
} else {
|
||||
m.Push(mdb.STATUS, "").PushButton(mdb.REMOVE)
|
||||
}
|
||||
})
|
||||
kit.If(len(arg) > 0 && arg[0] != "", func() { m.Action(COOKIE, HEADER) })
|
||||
m.Sort("client.type,client.name", []string{nfs.REPOS, "dev_ip", "demo", "mail"})
|
||||
} else {
|
||||
_spide_show(m, arg[0], arg[1:]...)
|
||||
}
|
||||
}},
|
||||
"/spide-demo/": {Actions: aaa.WhiteAction(), Hand: func(m *ice.Message, arg ...string) {
|
||||
m.Push("hi", "hello")
|
||||
m.Echo("hello world")
|
||||
}},
|
||||
http.MethodGet: {Name: "GET url key value run", Help: "蜘蛛侠", Hand: func(m *ice.Message, arg ...string) {
|
||||
http.MethodGet: {Name: "GET url key value run", Hand: func(m *ice.Message, arg ...string) {
|
||||
m.Echo(kit.Formats(kit.UnMarshal(m.Cmdx(SPIDE, ice.DEV, SPIDE_RAW, http.MethodGet, arg[0], arg[1:]))))
|
||||
}},
|
||||
http.MethodPut: {Name: "PUT url key value run", Help: "蜘蛛侠", Hand: func(m *ice.Message, arg ...string) {
|
||||
http.MethodPut: {Name: "PUT url key value run", Hand: func(m *ice.Message, arg ...string) {
|
||||
m.Echo(kit.Formats(kit.UnMarshal(m.Cmdx(SPIDE, ice.DEV, SPIDE_RAW, http.MethodPut, arg[0], arg[1:]))))
|
||||
}},
|
||||
http.MethodPost: {Name: "POST url key value run", Help: "蜘蛛侠", Hand: func(m *ice.Message, arg ...string) {
|
||||
http.MethodPost: {Name: "POST url key value run", Hand: func(m *ice.Message, arg ...string) {
|
||||
m.Echo(kit.Formats(kit.UnMarshal(m.Cmdx(SPIDE, ice.DEV, SPIDE_RAW, http.MethodPost, arg[0], arg[1:]))))
|
||||
}},
|
||||
http.MethodDelete: {Name: "DELETE url key value run", Help: "蜘蛛侠", Hand: func(m *ice.Message, arg ...string) {
|
||||
http.MethodDelete: {Name: "DELETE url key value run", Hand: func(m *ice.Message, arg ...string) {
|
||||
m.Echo(kit.Formats(kit.UnMarshal(m.Cmdx(SPIDE, ice.DEV, SPIDE_RAW, http.MethodDelete, arg[0], arg[1:]))))
|
||||
}},
|
||||
})
|
||||
nfs.TemplateText = func(m *ice.Message, p string) string {
|
||||
if p := kit.Select(nfs.TemplatePath(m, p), m.Option("_template")); kit.HasPrefix(p, nfs.P, nfs.REQUIRE, ice.HTTP) {
|
||||
return kit.Format(mdb.Cache(ice.Pulse, p, func() ice.Any { return m.Cmdx(SPIDE, ice.OPS, SPIDE_RAW, http.MethodGet, p) }))
|
||||
} else if p == "" {
|
||||
return ""
|
||||
} else if nfs.Exists(m, p) {
|
||||
return m.Cmdx(nfs.CAT, p)
|
||||
} else if strings.Contains(p, "/pkg/mod/") {
|
||||
ls := strings.Split(p, "/pkg/mod/")
|
||||
return kit.Format(mdb.Cache(ice.Pulse, p, func() ice.Any { return m.Cmdx(SPIDE, ice.OPS, SPIDE_RAW, http.MethodGet, nfs.REQUIRE+ls[1]) }))
|
||||
} else if strings.Contains(p, "/usr/local/work/") {
|
||||
ls := strings.Split(strings.Split(p, "/usr/local/work/")[1], "/src/")
|
||||
pp := kit.MergeURL2(ice.Info.Make.Domain, "/p/src/"+ls[1]+"?pod="+ls[0])
|
||||
return kit.Format(mdb.Cache(ice.Pulse, p, func() ice.Any { return m.Cmdx(SPIDE, ice.OPS, SPIDE_RAW, http.MethodGet, pp) }))
|
||||
} else {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
nfs.TemplatePath = func(m *ice.Message, arg ...string) string {
|
||||
if p := path.Join(ice.SRC_TEMPLATE, m.PrefixKey(), path.Join(arg...)); nfs.Exists(m, p) {
|
||||
return p + kit.Select("", nfs.PS, len(arg) == 0)
|
||||
} else {
|
||||
p := m.FileURI(ctx.GetCmdFile(m, m.PrefixKey()))
|
||||
if pp := kit.TrimPrefix(path.Join(path.Dir(p), path.Join(arg...)), nfs.P, nfs.REQUIRE); nfs.Exists(m, pp) {
|
||||
return pp
|
||||
}
|
||||
if ice.Info.Important {
|
||||
return kit.MergeURL2(SpideOrigin(m, ice.OPS)+p, path.Join(arg...))
|
||||
}
|
||||
return ""
|
||||
}
|
||||
}
|
||||
nfs.DocumentPath = func(m *ice.Message, arg ...string) string {
|
||||
if p := path.Join(nfs.USR_LEARNING_PORTAL, m.PrefixKey(), path.Join(arg...)); nfs.Exists(m, p) {
|
||||
return p + kit.Select("", nfs.PS, len(arg) == 0)
|
||||
} else {
|
||||
return kit.MergeURL2(UserHost(m)+ctx.GetCmdFile(m, m.PrefixKey()), path.Join(arg...))
|
||||
}
|
||||
}
|
||||
nfs.DocumentText = func(m *ice.Message, p string) string {
|
||||
if p := nfs.DocumentPath(m, path.Base(p)); kit.HasPrefix(p, nfs.P, nfs.REQUIRE, ice.HTTP) {
|
||||
return m.Cmdx(SPIDE, ice.DEV, SPIDE_RAW, http.MethodGet, p)
|
||||
} else {
|
||||
return m.Cmdx(nfs.CAT, p)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func SpideGet(m *ice.Message, arg ...ice.Any) ice.Any {
|
||||
@ -328,6 +486,59 @@ func SpidePost(m *ice.Message, arg ...ice.Any) ice.Any {
|
||||
func SpideDelete(m *ice.Message, arg ...ice.Any) ice.Any {
|
||||
return kit.UnMarshal(m.Cmdx(http.MethodDelete, arg))
|
||||
}
|
||||
func SpideSave(m *ice.Message, file, link string, cb func(int, int, int)) *ice.Message {
|
||||
return m.Cmd("web.spide", ice.DEV, SPIDE_SAVE, file, http.MethodGet, link, cb)
|
||||
func SpideCache(m *ice.Message, link string) *ice.Message {
|
||||
return m.Cmd(Prefix(SPIDE), ice.DEV_IP, SPIDE_CACHE, http.MethodGet, link)
|
||||
}
|
||||
func SpideSave(m *ice.Message, file, link string, cb func(count, total, value int)) *ice.Message {
|
||||
for _, p := range []string{ice.DEV_IP, ice.DEV} {
|
||||
msg := m.Cmd(Prefix(SPIDE), p, SPIDE_SAVE, file, http.MethodGet, link, cb)
|
||||
if !msg.IsErr() {
|
||||
return msg
|
||||
}
|
||||
}
|
||||
return m
|
||||
}
|
||||
func SpideOrigin(m *ice.Message, name string) string { return m.Cmdv(SPIDE, name, CLIENT_ORIGIN) }
|
||||
func SpideURL(m *ice.Message, name string) string { return m.Cmdv(SPIDE, name, CLIENT_URL) }
|
||||
func SpideList(m *ice.Message) *ice.Message { return m.Copy(AdminCmd(m, SPIDE)) }
|
||||
func SpideReposList(m *ice.Message) *ice.Message {
|
||||
AdminCmd(m, SPIDE).Table(func(value ice.Maps) {
|
||||
if value[CLIENT_TYPE] == nfs.REPOS {
|
||||
m.Push(mdb.NAME, value[CLIENT_NAME])
|
||||
m.Push(mdb.ICONS, value[mdb.ICONS])
|
||||
}
|
||||
})
|
||||
ctx.DisplayInputKey(m, "style", "_nameicon")
|
||||
return m
|
||||
}
|
||||
func PublicIP(m *ice.Message, arg ...string) ice.Any {
|
||||
if len(arg) == 0 {
|
||||
return SpideGet(m, "http://ip-api.com/json")
|
||||
}
|
||||
return mdb.Cache(m, "web.spide.location."+arg[0], func() ice.Any {
|
||||
return kit.Format(kit.Value(SpideGet(m, "http://opendata.baidu.com/api.php?co=&resource_id=6006&oe=utf8", "query", arg[0]), "data.0.location"))
|
||||
})
|
||||
}
|
||||
func HostPort(m *ice.Message, host, port string, arg ...string) string {
|
||||
p := ""
|
||||
if len(arg) > 0 {
|
||||
kit.If(kit.Select("", arg, 0), func(pod string) { p += S(pod) })
|
||||
kit.If(kit.Select("", arg, 1), func(cmd string) { p += C(cmd) })
|
||||
}
|
||||
kit.If(m.Option(ice.LOG_DEBUG) == ice.TRUE, func() { p += "?debug=true" })
|
||||
kit.If(host == "", func() {
|
||||
if u := kit.ParseURL(UserHost(m)); u != nil {
|
||||
host = u.Hostname()
|
||||
}
|
||||
})
|
||||
host = kit.Select("localhost", host)
|
||||
if port == tcp.PORT_443 {
|
||||
return kit.Format("https://%s", host) + p
|
||||
} else if port == tcp.PORT_80 {
|
||||
return kit.Format("http://%s", host) + p
|
||||
} else if port == "" {
|
||||
return kit.Format("%s://%s", UserWeb(m).Scheme, host) + p
|
||||
} else {
|
||||
return kit.Format("http://%s:%s", host, port) + p
|
||||
}
|
||||
}
|
||||
|
57
base/web/stats.go
Normal file
57
base/web/stats.go
Normal file
@ -0,0 +1,57 @@
|
||||
package web
|
||||
|
||||
import (
|
||||
ice "shylinux.com/x/icebergs"
|
||||
"shylinux.com/x/icebergs/base/aaa"
|
||||
"shylinux.com/x/icebergs/base/ctx"
|
||||
"shylinux.com/x/icebergs/base/gdb"
|
||||
"shylinux.com/x/icebergs/base/mdb"
|
||||
"shylinux.com/x/icebergs/base/nfs"
|
||||
kit "shylinux.com/x/toolkits"
|
||||
)
|
||||
|
||||
const (
|
||||
STATS_TABLES = "stats.tables"
|
||||
)
|
||||
const STATS = "stats"
|
||||
|
||||
func init() {
|
||||
Index.MergeCommands(ice.Commands{
|
||||
STATS: {Help: "汇总量", Hand: func(m *ice.Message, arg ...string) {
|
||||
defer ctx.DisplayStory(m, "")
|
||||
if m.Option(ice.MSG_USERPOD) == "" {
|
||||
PushStats(m, "", "", "", "共享总数", SHARE)
|
||||
PushStats(m, "", "", "", "令牌总数", TOKEN)
|
||||
PushStats(m, "", "", "", "注册总数", aaa.APPLY)
|
||||
PushStats(m, "", "", "", "邀请总数", aaa.OFFER)
|
||||
if ice.Info.Username == ice.Info.Make.Username {
|
||||
PushStats(m, "", m.Cmd(aaa.USER).Length()-1, "", "用户总数", aaa.USER)
|
||||
} else {
|
||||
PushStats(m, "", m.Cmd(aaa.USER).Length()-2, "", "用户总数", aaa.USER)
|
||||
}
|
||||
PushStats(m, "", "", "", "会话总数", aaa.SESS)
|
||||
PushStats(m, "", m.Cmd(mdb.SELECT, aaa.ROLE, "", mdb.HASH).Length(), "", "角色总数", aaa.ROLE)
|
||||
PushStats(m, "", "", "", "命令总数", ctx.COMMAND)
|
||||
}
|
||||
gdb.Event(m, STATS_TABLES)
|
||||
PushPodCmd(m, "", arg...)
|
||||
}},
|
||||
})
|
||||
}
|
||||
func StatsAction(arg ...string) ice.Actions {
|
||||
return ice.MergeActions(ice.Actions{
|
||||
STATS_TABLES: {Hand: func(m *ice.Message, _ ...string) {
|
||||
if msg := mdb.HashSelects(m.Spawn()); msg.Length() > 0 {
|
||||
PushStats(m, kit.Keys(m.CommandKey(), mdb.TOTAL), msg.Length(), arg...)
|
||||
}
|
||||
}},
|
||||
}, gdb.EventsAction(STATS_TABLES))
|
||||
}
|
||||
func PushStats(m *ice.Message, name string, value ice.Any, arg ...string) {
|
||||
index := kit.Select(m.ShortKey(), arg, 2)
|
||||
kit.If(name == "", func() { name = kit.Keys(kit.Select("", kit.Split(index, nfs.PT), -1), mdb.TOTAL) })
|
||||
kit.If(value == "", func() { value = m.Cmd(index).Length() })
|
||||
kit.If(value != 0, func() {
|
||||
m.Push(mdb.NAME, name).Push(mdb.VALUE, value).Push(mdb.UNITS, kit.Select("", arg, 0)).Push(ctx.TRANS, kit.Select("", arg, 1)).Push(ctx.INDEX, index)
|
||||
})
|
||||
}
|
7
base/web/store.css
Normal file
7
base/web/store.css
Normal file
@ -0,0 +1,7 @@
|
||||
$project div.list { margin-left:25px; }
|
||||
$project div.item span.exists { color:var(--notice-bg-color); padding:0 var(--input-padding); }
|
||||
$content>div.item { box-shadow:var(--th-box-shadow); border:var(--plugin-border); border-radius:var(--plugin-radius); }
|
||||
$content>div.item:hover { box-shadow:var(--notice-box-shadow); }
|
||||
$content>div.item div.title div.label { font-size:var(--status-font-size); font-weight:normal; margin-top:var(--input-margin); }
|
||||
$content>div.item div.title div.label span { padding:var(--input-padding); padding-right:var(--input-margin); }
|
||||
$content>div.item div.content { height:70px; }
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user