1
0
mirror of https://shylinux.com/x/icebergs synced 2025-04-26 01:24:05 +08:00

Compare commits

...

343 Commits

Author SHA1 Message Date
shy
b0c7feb56e add some 2025-04-25 18:23:55 +08:00
shy
7e5cff6b81 add some 2025-03-22 12:54:06 +08:00
shy
6c0e3a0a58 add some 2025-03-15 20:27:05 +08:00
shy
08f2f1626d add some 2025-03-10 18:38:39 +08:00
shy
5260027c9f add some 2025-03-08 08:38:13 +08:00
shy
26e62a1b22 add some 2025-03-05 23:33:47 +08:00
shy
e008f4d417 add some 2025-03-05 08:55:30 +08:00
shy
5fc5ccd0ea add some 2025-03-04 14:52:57 +08:00
shy
35c1407d29 add some 2025-03-03 22:13:05 +08:00
shy
55a0c3d120 add some 2025-03-03 18:39:51 +08:00
shy
968d9389c9 opt some 2025-03-02 22:10:17 +08:00
shy
7fea8e88a4 add some 2025-03-01 11:36:50 +08:00
shy
8fa2f6e8b3 add some 2025-02-28 14:17:28 +08:00
shy
fe1a6d30aa opt some 2025-02-27 17:56:24 +08:00
shy
02962f9d20 add some 2025-02-27 16:39:54 +08:00
shy
612ecdf4a6 add some 2025-02-27 16:29:06 +08:00
shy
c3f37f626b add some 2025-02-27 16:27:42 +08:00
shy
b4627b2975 add some 2025-02-26 21:51:32 +08:00
shy
f3bc5eb1e1 opt some 2025-02-25 21:57:33 +08:00
shy
03990b839e add some 2025-02-25 21:54:41 +08:00
shy
473826664a add some 2025-02-25 12:14:41 +08:00
root
be66627287 add some 2025-02-25 10:52:06 +08:00
shy
030c018877 add some 2025-02-25 09:59:30 +08:00
root
0071ba89d9 add some 2025-02-25 07:32:49 +08:00
shy
c067576dd6 add some 2025-02-23 09:58:37 +08:00
shy
96d812612b add some 2025-02-23 08:03:37 +08:00
root
a33bc88dcc add some 2025-02-19 21:00:50 +08:00
shy
2f715c5233 opt some 2025-02-18 11:26:19 +08:00
root
8a27ce7d66 add some 2025-02-18 11:18:22 +08:00
root
da81284b37 add some 2025-02-17 19:54:36 +08:00
root
bbb0ae9de9 add some 2025-02-16 08:44:53 +08:00
shy
7bb197ed94 add some 2025-02-16 08:27:23 +08:00
shy
bc94d8e1e4 add some 2025-02-15 18:35:15 +08:00
shy
942606d750 add some 2025-02-15 12:32:06 +08:00
shy
c418c8c070 add some 2025-02-13 22:35:33 +08:00
shy
87c96c880d opt some 2025-02-10 23:03:10 +08:00
shy
cdaa2d7984 opt some 2025-02-10 10:11:34 +08:00
root
38b7942c1b add some 2025-02-10 08:30:04 +08:00
root
240a0c88bf add some 2025-02-08 15:00:09 +08:00
root
297c299694 add some 2025-02-08 12:02:50 +08:00
root
324cd9dc57 add some 2025-02-06 16:21:11 +08:00
shy
1829822e43 add some 2025-02-05 17:37:25 +08:00
shy
a8b365dc31 add some 2025-02-05 09:49:32 +08:00
root
b64a3b5725 add some 2025-02-05 09:44:27 +08:00
root
0ef29edbad add some 2025-02-04 14:10:16 +08:00
shy
6fc5cbde02 add publish 2025-02-04 12:01:02 +08:00
shy
85e1f1dcb6 add some 2025-02-04 10:26:51 +08:00
root
cd5882b2ee add some 2025-02-04 08:52:06 +08:00
shy
259aa7639a add some 2025-02-03 20:42:02 +08:00
shy
91f4578d63 add some 2025-02-02 23:54:43 +08:00
root
54211e220d add some 2025-02-02 23:53:03 +08:00
shy
00d0a3f449 add some 2025-01-31 10:26:51 +08:00
root
8782b192e3 add some 2025-01-30 10:49:34 +08:00
root
92a2fcac3c add some 2025-01-29 12:00:59 +08:00
shy
c045033e55 add some 2025-01-25 15:15:48 +08:00
shy
c022852de3 add some 2025-01-23 21:36:46 +08:00
shy
fa73c5c940 add some 2025-01-23 18:59:31 +08:00
shy
0be5c0f6f3 add some 2025-01-22 16:23:02 +08:00
shy
524bbf6430 add some 2025-01-22 16:12:23 +08:00
root
50ba5c3a3f add some 2025-01-22 15:32:30 +08:00
shy
d9fcacd679 opt some 2025-01-17 21:18:36 +08:00
root
c661ed4f12 add some 2025-01-14 08:42:01 +08:00
root
193a2ab917 add some 2025-01-13 18:02:50 +08:00
shy
aa756c2bc3 add some 2025-01-12 21:53:42 +08:00
shy
7551a8dfab add some 2025-01-10 15:04:47 +08:00
shy
be8c60d97c add some 2025-01-06 21:38:46 +08:00
root
61b81cf089 add some 2025-01-05 20:36:15 +08:00
shy
813ec2b17a add some 2025-01-05 12:45:21 +08:00
shy
d4c73ce195 add some 2025-01-05 12:01:27 +08:00
shy
472f72889a add some 2025-01-03 12:36:17 +08:00
shy
a3e4861989 add some 2025-01-02 20:48:29 +08:00
root
18d65c81e5 add some 2025-01-02 20:42:58 +08:00
root
f59b7cc461 add some 2025-01-02 18:29:31 +08:00
shy
ec961b40fb add some 2025-01-01 09:49:06 +08:00
shy
a075aa7975 add some 2025-01-01 09:23:30 +08:00
root
287083f9ca add some 2024-12-31 19:22:00 +08:00
shy
2e0131a331 add some 2024-12-31 12:33:48 +08:00
root
7dcf68b0d8 add some 2024-12-16 16:02:46 +08:00
shy
66033654c5 add some 2024-12-08 22:27:31 +08:00
shy
6540f3f3f1 add some 2024-12-03 22:45:07 +08:00
shy
37fe3b44b0 add some 2024-11-28 12:32:02 +08:00
shy
bcdce97856 add some 2024-11-26 23:12:53 +08:00
shy
ff0590852d add some 2024-11-25 10:02:13 +08:00
shy
a352374bb4 add some 2024-11-24 07:46:53 +08:00
shy
d30b4e2034 add some 2024-11-23 16:51:24 +08:00
shy
131858f4b1 opt some 2024-11-23 10:11:56 +08:00
shy
e042dc832c add some 2024-11-20 22:49:56 +08:00
shy
8f10a46fb5 add some 2024-11-19 09:32:17 +08:00
root
313b7d4c95 add some 2024-11-18 09:11:37 +08:00
shy
f8af90a71e add some 2024-11-15 20:09:08 +08:00
root
52b47dee2a add some 2024-11-15 09:56:30 +08:00
root
5776c42f7b add some 2024-11-10 13:07:07 +08:00
root
73c32ccc9b add some 2024-11-09 11:35:33 +08:00
root
f9932b5dba add some 2024-11-04 10:27:19 +08:00
root
5afc3781a6 add some 2024-10-25 17:49:24 +08:00
root
dc242dfa54 add some 2024-10-22 07:35:48 +08:00
root
e02517a57e add some 2024-10-20 22:55:19 +08:00
root
f6a009c7fa add some 2024-10-20 08:16:21 +08:00
root
be0a295b52 add some 2024-10-18 14:45:24 +08:00
root
39a5ce360e add some 2024-10-18 14:08:56 +08:00
root
928666d2c9 add some 2024-10-17 23:45:20 +08:00
root
51ae44aeb3 add some 2024-10-17 12:13:39 +08:00
root
d3ba62cc61 add some 2024-10-17 09:38:54 +08:00
root
07111495dd add some 2024-10-16 11:18:41 +08:00
shy
e34752141a opt some 2024-10-16 10:27:26 +08:00
root
95b45c2f15 add some 2024-10-15 18:25:37 +08:00
root
b2b4616ec1 add some 2024-10-13 18:25:36 +08:00
root
1060a60a5e add some 2024-10-12 11:06:29 +08:00
shy
4d892e03d3 add some 2024-10-10 22:23:51 +08:00
shy
ca734d3baf add some 2024-10-09 14:41:19 +08:00
shy
2deff32468 add some 2024-10-06 22:19:03 +08:00
shy
ed39ff23e7 add some 2024-10-04 12:23:39 +08:00
shy
d4f4754be8 add some 2024-10-02 22:24:09 +08:00
shy
80807ed1d2 add some 2024-10-01 00:12:59 +08:00
shy
c4b9641a5e add some 2024-09-27 23:58:19 +08:00
shy
0bff96f485 add some 2024-09-25 17:16:22 +08:00
shy
7ab38ec81f add some 2024-09-24 13:10:56 +08:00
shy
56b87e9e78 add some 2024-09-20 20:53:41 +08:00
shy
f174577bde opt some 2024-09-19 21:09:34 +08:00
shy
ed65d194e6 add some 2024-09-18 20:40:55 +08:00
shy
15a79273ac add some 2024-09-18 13:32:50 +08:00
shy
0eac777f6f add some 2024-09-14 00:36:42 +08:00
shy
0f8a77af25 add some 2024-09-10 08:06:53 +08:00
shy
9a192b012f add some 2024-09-07 17:11:52 +08:00
shy
4b27054210 add some 2024-09-05 20:02:56 +08:00
shy
8d1374149c add some 2024-09-04 07:54:59 +08:00
shy
768bca93b1 add some 2024-09-03 22:42:25 +08:00
shy
f45d784af7 add some 2024-09-03 18:29:15 +08:00
shy
329f963a38 add some 2024-09-03 07:35:53 +08:00
shy
53c5a80da6 add some 2024-09-02 17:34:07 +08:00
shy
b1d5d09a80 add some 2024-08-30 21:56:33 +08:00
shy
4a5256c19f add some 2024-08-29 11:09:33 +08:00
shy
e3fb897137 add some 2024-08-26 22:15:14 +08:00
shy
b1bd23cc26 add some 2024-08-24 20:22:51 +08:00
shy
67b1e41db9 add some 2024-08-18 02:26:42 +08:00
shy
ce0735856e add some 2024-08-16 07:53:33 +08:00
jingganjiaoyu
a0ef75490c opt some 2024-08-15 11:48:38 +08:00
jingganjiaoyu
5891f4f621 opt some 2024-08-15 11:38:51 +08:00
shy
d4a5e4df44 add some 2024-08-12 21:06:51 +08:00
shy
25df349028 add some 2024-08-09 17:58:17 +08:00
shy
618218247b add some 2024-08-09 00:04:14 +08:00
shy
15a4603a18 add some 2024-08-06 19:10:22 +08:00
shy
2f33ff38de add some 2024-08-06 01:35:21 +08:00
shy
972c9fc97f opt some 2024-08-05 23:47:16 +08:00
shy
41cea7f8b0 add some 2024-08-05 23:20:52 +08:00
shy
5a4b79b4eb add some 2024-08-05 02:10:09 +08:00
shy
a7014de914 add some 2024-08-04 14:55:09 +08:00
shy
eb73841a72 add some 2024-08-04 01:49:24 +08:00
shy
704519e336 add some 2024-08-02 18:41:44 +08:00
shy
2f4e941aa0 add some 2024-07-31 22:20:28 +08:00
shy
e29a4fa6b8 add some 2024-07-29 22:49:54 +08:00
shy
af1a9be68e opt portal 2024-07-28 23:21:54 +08:00
shy
a5cd77e87d add some 2024-07-26 21:38:07 +08:00
shy
ccfffd917c opt some 2024-07-24 20:04:32 +08:00
shy
fb99d27694 add some 2024-07-23 23:42:35 +08:00
shy
805cfbcc25 add some 2024-07-23 16:04:42 +08:00
shy
170365ddab add some 2024-07-22 22:45:41 +08:00
shy
271e743c3c add some 2024-07-21 14:50:43 +08:00
shy
d401e8ec2c add some 2024-07-20 20:50:25 +08:00
shy
daa740ffbe add some 2024-07-20 11:05:14 +08:00
shy
9ba006a1da add some 2024-07-19 18:11:03 +08:00
shy
97bdf84965 add some 2024-07-19 00:07:21 +08:00
shy
555be526e3 add some 2024-07-16 22:24:39 +08:00
shy
06a89de015 add some 2024-07-16 19:50:08 +08:00
shy
2fe571f9d6 add some 2024-07-16 18:44:31 +08:00
shy
36f1fe2a7b add some 2024-07-16 10:54:32 +08:00
shy
7214a38d52 add some 2024-07-15 22:26:35 +08:00
shy
0f87c5ac5e add some 2024-07-15 17:55:57 +08:00
shy
8328b4cb69 add some 2024-07-15 09:36:47 +08:00
shy
0742533ce6 add some 2024-07-14 21:51:14 +08:00
shy
889f221e4b add some 2024-07-14 19:23:14 +08:00
shy
77a2cb1a43 add some 2024-07-12 21:05:19 +08:00
shy
6ff235f13a add some 2024-07-12 16:30:09 +08:00
shy
906183a522 opt some 2024-07-11 20:08:39 +08:00
shy
38d74bc01f add web.team.corporation 2024-07-11 01:54:19 +08:00
shy
7b21b28b98 add some 2024-07-09 19:49:29 +08:00
shy
d3001524f2 add some 2024-07-09 12:23:37 +08:00
shy
b9a8678410 opt some 2024-07-09 10:09:53 +08:00
shy
7b8e933bb9 add some 2024-07-09 09:56:18 +08:00
shy
3e63a8c243 opt some 2024-07-08 19:46:17 +08:00
shy
af0d446abc opt some 2024-07-08 19:45:05 +08:00
shy
01bacc73a2 add some 2024-07-07 18:24:15 +08:00
shy
9bf29af91f add some 2024-07-06 02:04:30 +08:00
shy
8b23ad92e0 add some 2024-07-05 20:51:24 +08:00
shy
cc0a5de7a0 add some 2024-07-04 19:34:59 +08:00
shy
eb69a26017 add some 2024-07-04 03:02:13 +08:00
shy
4dcb03c9dc add some 2024-07-03 19:24:34 +08:00
shy
e6c64b7e1f opt some 2024-07-03 14:31:53 +08:00
shy
27064b6aa9 opt some 2024-07-01 20:46:21 +08:00
shy
178a73ae4f add some 2024-07-01 20:42:27 +08:00
shy
c18f363085 opt some 2024-07-01 10:59:26 +08:00
shy
67b4924b9a add some 2024-07-01 10:40:13 +08:00
shy
cfd5db37ca add some 2024-06-30 19:52:35 +08:00
shy
dd974b0980 add some 2024-06-29 23:57:15 +08:00
shy
6f4d324808 add some 2024-06-28 19:35:26 +08:00
shy
96dd7e96de add some 2024-06-28 18:39:11 +08:00
shy
82c0c14dea add some 2024-06-20 20:49:29 +08:00
shy
1aa04477c4 add some 2024-06-20 17:18:16 +08:00
shy
7862121a3c opt some 2024-06-20 15:41:36 +08:00
shy
755aaf72b0 add some 2024-06-19 09:11:43 +08:00
shy
a77f9207c0 add some 2024-06-18 10:11:45 +08:00
shy
adea456e67 add aaa.asign 2024-06-17 18:27:14 +08:00
shy
d69b895983 opt some 2024-06-15 18:48:26 +08:00
shy
35c8a1ca44 add some 2024-06-15 18:45:56 +08:00
shy
0959289870 add some 2024-06-14 19:33:49 +08:00
shy
d264cd3261 add some 2024-06-13 07:33:58 +08:00
shy
558bf677da add some 2024-06-11 22:02:49 +08:00
shy
57035a9fa5 add some 2024-06-11 11:04:23 +08:00
shy
ee32bd8346 add some 2024-06-09 23:32:10 +08:00
shy
bc6e12a6f0 add some 2024-06-09 22:58:23 +08:00
shy
95ba9fc6cd add some 2024-06-09 20:04:31 +08:00
shy
96713c1e75 add some 2024-06-08 23:06:35 +08:00
shy
74075002f1 add some 2024-06-08 10:19:54 +08:00
shy
fda6e6f969 add some 2024-06-08 08:49:02 +08:00
shy
f30bdb9696 add some 2024-06-08 08:01:15 +08:00
shy
4d8a21fd54 add some 2024-06-08 07:56:24 +08:00
shy
c129026c52 opt some 2024-06-06 00:04:07 +08:00
shy
f8ca54a85e add some 2024-06-06 00:02:01 +08:00
shy
5c63a4b467 add some 2024-06-05 15:32:41 +08:00
shy
9d72dd7890 add some 2024-06-04 23:15:28 +08:00
shy
b5d6f7a94c opt some 2024-06-04 11:42:54 +08:00
shy
24e9a8682f add some 2024-06-03 18:36:07 +08:00
shy
0587d4dd75 add some 2024-06-01 23:04:39 +08:00
shy
019f536248 add some 2024-05-31 19:57:53 +08:00
shy
194fd6f5bc add some 2024-05-30 19:56:43 +08:00
shy
22ccf77a66 add some 2024-05-28 22:42:53 +08:00
shy
745ea23b48 add some 2024-05-28 18:48:36 +08:00
shy
4e03450ce2 add some 2024-05-28 07:31:20 +08:00
shy
13afc46682 add some 2024-05-27 19:32:12 +08:00
shy
d4f9ea0f81 add some 2024-05-27 07:29:32 +08:00
shy
3f945f963a add some 2024-05-26 11:27:48 +08:00
shy
120e65bb92 add some 2024-05-26 08:28:03 +08:00
shy
bfaf7380e1 add some 2024-05-26 08:07:13 +08:00
shy
bd7d558208 add some 2024-05-25 20:47:58 +08:00
shy
ac151623c1 add some 2024-05-25 19:56:50 +08:00
shy
9e1ff8d564 add some 2024-05-24 19:27:27 +08:00
shy
598942a836 add some 2024-05-23 23:41:23 +08:00
shy
7830bf0bf7 add some 2024-05-23 19:16:33 +08:00
shy
8021138a80 add some 2024-05-22 23:07:14 +08:00
shy
41c157c6ed add some 2024-05-22 18:44:30 +08:00
shy
c27d82e83e add some 2024-05-21 23:46:04 +08:00
shy
af91084d59 add some 2024-05-21 19:22:43 +08:00
shy
a27fd93686 add some 2024-05-21 07:39:24 +08:00
shy
f7b4edde23 add some 2024-05-20 20:52:40 +08:00
shy
0bfb8673a5 add some 2024-05-20 01:32:07 +08:00
shy
e6607bcd17 add some 2024-05-19 23:49:45 +08:00
shy
f64b141930 add some 2024-05-19 17:02:57 +08:00
shy
ac3241b168 add some 2024-05-18 21:02:28 +08:00
shy
1bc8a05ca6 add some 2024-05-17 19:39:37 +08:00
shy
272c91f469 add some 2024-05-16 08:19:24 +08:00
shy
f359c438fc add some 2024-05-15 18:40:26 +08:00
shy
82415d742a add some 2024-05-15 15:58:50 +08:00
shy
bfa6ecefb2 add some 2024-05-14 23:27:38 +08:00
shy
6b6e20458b add some 2024-05-14 19:13:36 +08:00
shy
b499d09f37 add some 2024-05-14 00:02:33 +08:00
shy
fd324e5f14 add tutor 2024-05-13 20:33:19 +08:00
shy
95ef705c49 add some 2024-05-13 08:08:28 +08:00
shy
12c66f89bb add some 2024-05-12 23:40:58 +08:00
shy
b31a5f8286 add some 2024-05-12 20:37:10 +08:00
shy
73ecfc0cb6 add some 2024-05-12 15:03:57 +08:00
shy
8b0e3ebe55 add some 2024-05-11 18:21:13 +08:00
shy
bcbfb9aaed add some 2024-05-10 08:04:23 +08:00
shy
b5d3ecf103 add some 2024-05-09 23:14:34 +08:00
shy
209d911e25 add some 2024-05-09 13:25:27 +08:00
shy
960748e223 opt some 2024-05-09 07:46:15 +08:00
shy
eac98f23f5 add some 2024-05-09 07:25:24 +08:00
shy
baca546e49 add some 2024-05-08 00:14:16 +08:00
shy
63cbd6d4c0 add some 2024-05-07 15:21:25 +08:00
shy
d8c381a933 add studio 2024-05-06 23:05:57 +08:00
shy
b8c8d1603e add some 2024-05-05 23:24:50 +08:00
shy
555b91fa8f add some 2024-05-05 17:32:25 +08:00
shy
d71d72aa19 add some 2024-05-04 19:20:32 +08:00
shy
bb99205fdb add some 2024-05-04 00:31:52 +08:00
shy
f7e3dcd9ff add some 2024-05-01 18:25:56 +08:00
shy
582519d290 add some 2024-04-30 22:11:58 +08:00
shy
e2babe49a6 add some 2024-04-30 02:35:03 +08:00
shy
172e734f76 add some 2024-04-29 14:49:00 +08:00
shy
d0de69d086 add some 2024-04-28 23:26:46 +08:00
shy
9ecfc80f03 add some 2024-04-27 21:40:39 +08:00
shy
c39b138277 add some 2024-04-27 20:43:12 +08:00
shy
ed06078ce4 opt some 2024-04-27 18:58:24 +08:00
shy
4dfe6269c5 add some 2024-04-27 18:35:13 +08:00
shy
183faff9ce add some 2024-04-27 09:20:51 +08:00
shy
9bdc7af5e9 add some 2024-04-25 21:11:19 +08:00
shy
90469e941d add some 2024-04-25 12:38:15 +08:00
shy
b98b3052d4 add some 2024-04-24 18:10:13 +08:00
shy
e220f82568 add some 2024-04-24 16:26:42 +08:00
shy
fe89d6346c add some 2024-04-24 10:23:18 +08:00
shy
f0ad76fe71 add some 2024-04-22 18:53:28 +08:00
shy
aec9fcf977 add some 2024-04-22 17:15:39 +08:00
eea57c28a4 opt some 2024-04-22 15:37:39 +08:00
shy
30c457bb07 add some 2024-04-22 15:27:41 +08:00
shy
94c2979c93 add some 2024-04-22 08:27:21 +08:00
f79d9b23d7 add windows 2024-04-22 00:36:57 +08:00
b3959aa68d opt some 2024-04-21 16:27:38 +08:00
shy
b980d48390 add some 2024-04-20 22:42:58 +08:00
shy
cfec29c68d add some 2024-04-20 21:57:46 +08:00
shy
a404a7cb08 add some 2024-04-20 19:26:26 +08:00
shy
cc820576f0 add some 2024-04-20 15:56:24 +08:00
shy
5d95320d1e add some 2024-04-20 07:25:48 +08:00
shy
56d4775fed add some 2024-04-19 19:35:46 +08:00
shy
60602bb7a9 add some 2024-04-19 17:58:11 +08:00
shy
43646c5e3e add some 2024-04-19 12:34:12 +08:00
shy
c04c3f0d1d add some 2024-04-18 23:52:02 +08:00
shy
03e18c9325 add some 2024-04-18 23:35:46 +08:00
shy
0c62da9a08 add some 2024-04-18 22:47:39 +08:00
shy
00362e1197 opt border 2024-04-18 22:15:24 +08:00
shy
eea21aaad8 opt some 2024-04-18 13:54:34 +08:00
shy
08b89ece9f add some 2024-04-18 13:40:45 +08:00
shy
41064a2809 add some 2024-04-18 10:51:38 +08:00
shy
86251fb5b3 add some 2024-04-18 10:48:38 +08:00
shy
b56063a183 add some 2024-04-18 00:10:56 +08:00
shy
65697070f4 opt some 2024-04-17 04:15:19 +08:00
shy
4b4179bd04 opt some 2024-04-16 08:21:24 +08:00
shy
158c738970 add some 2024-04-15 12:25:16 +08:00
shy
1564bb6899 add some 2024-04-15 09:08:39 +08:00
shy
3a2fd6d3bb add some 2024-04-14 23:26:13 +08:00
shy
aff83532dd add some 2024-04-14 19:26:34 +08:00
root
ec780aa64c add some 2024-04-14 16:57:47 +08:00
shy
8d3dbc1dea add some 2024-04-14 12:47:31 +08:00
root
77f10bbe69 add some 2024-04-13 23:18:15 +08:00
shy
0d0718e9e8 add some 2024-04-12 22:21:27 +08:00
shy
0338ef7b46 add some 2024-04-11 23:59:37 +08:00
root
74e72d76b9 add some 2024-04-11 21:58:09 +08:00
root
7de837851e add some 2024-04-11 17:08:19 +08:00
shy
25ac2e3a1b opt some 2024-04-11 12:38:38 +08:00
root
29d7a98ec6 add some 2024-04-10 22:58:38 +08:00
root
f802bda23a add some 2024-04-10 22:38:38 +08:00
shy
2075f6e227 add some 2024-04-10 13:33:14 +08:00
shy
144bacc365 add some 2024-04-10 00:32:48 +08:00
shy
3fee88f2bf add some 2024-04-09 18:25:08 +08:00
shy
74358ff30d add some 2024-04-09 13:19:07 +08:00
shy
7bf5ba9d8e opt some 2024-04-08 23:15:56 +08:00
shy
0d6db1c35e add some 2024-04-08 23:00:33 +08:00
shy
21df7f027d add some 2024-04-08 21:05:36 +08:00
shy
5f3e62cf71 add some 2024-04-08 13:31:10 +08:00
shy
4b09f92531 add some 2024-04-08 11:20:17 +08:00
shy
708ed30f74 add some 2024-04-08 00:04:10 +08:00
shy
d0710dc9e2 add some 2024-04-07 23:14:08 +08:00
shy
6154aa93aa add some 2024-04-07 15:33:13 +08:00
shy
bae35d2ce3 add some 2024-04-07 13:28:38 +08:00
shy
603c5ffb0c opt some 2024-04-07 12:20:00 +08:00
shy
1757e0e524 add some 2024-04-07 12:16:47 +08:00
204 changed files with 4681 additions and 2334 deletions

View File

@ -1,6 +1,6 @@
MIT License
Copyright (c) 2020 shylinux
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

View File

@ -1,3 +1,3 @@
# icebergs
icebergs 是一个应用框架,通过模块化、集群化、自动化方式,在各种设备上,即可一键启动完整的云计算服务与云研发环境。
icebergs 是一个后端框架,通过集群化、模块化、自动化方式,在各种设备上,即可一键启动完整的云计算服务与云研发环境。

View File

@ -32,7 +32,7 @@ func init() {
)
Index.MergeCommands(ice.Commands{
EMAIL: {Help: "邮件", Actions: ice.MergeActions(ice.Actions{
mdb.CREATE: {Name: "create name*=admin service*='mail.shylinux.com:25' username*='shy@shylinux.com' password*"},
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)) {
@ -54,6 +54,19 @@ func init() {
}
}},
})
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])

View File

@ -78,9 +78,11 @@ func (s apply) Login(m *ice.Message, arg ...string) {
}
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).Append(mdb.LINK)
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.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 {

77
base/aaa/portal/asign.go Normal file
View 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{}) }

View File

@ -72,7 +72,7 @@ const ROLE = "role"
func init() {
Index.MergeCommands(ice.Commands{
ROLE: {Name: "role role key auto insert filter:text simple", Help: "角色", Actions: ice.MergeActions(ice.Actions{
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}
@ -87,6 +87,7 @@ func init() {
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 {
@ -107,26 +108,26 @@ 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) {
kit.If(_role_right(m, arg[0], kit.Split(_role_keys(arg[1:]...), ice.PT)...), func() { m.Echo(ice.OK) })
}},
"simple": {Hand: func(m *ice.Message, arg ...string) {
list := map[string][]string{}
m.Cmd("", func(value ice.Maps) {
if value[mdb.ZONE] == WHITE {
if strings.Contains(value[mdb.KEY], ".action.") {
ls := strings.Split(value[mdb.KEY], ".action.")
list[ls[0]] = append(list[ls[0]], ls[1])
} else {
list[value[mdb.KEY]] = []string{}
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
}
})
kit.For(list, func(cmd string, action []string) {
m.Push(ice.CMD, cmd).Push("actions", kit.Join(action))
})
}
}},
}, mdb.HashAction(mdb.SHORT, mdb.NAME)), Hand: func(m *ice.Message, arg ...string) {
_role_list(m, kit.Select("", arg, 0), kit.Slice(arg, 1)...).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)...)
}
}},
})
}
@ -134,6 +135,9 @@ 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) })
}
@ -142,6 +146,9 @@ func WhiteAction(role string, key ...string) ice.Actions {
return ice.Actions{ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) {
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) })
}}}

View File

@ -9,19 +9,9 @@ import (
func _sess_create(m *ice.Message, username string, arg ...string) {
if msg := m.Cmd(USER, username); msg.Length() > 0 {
mdb.HashCreate(m, msg.AppendSimple(
USERROLE,
USERNAME,
USERNICK,
AVATAR,
), arg)
mdb.HashCreate(m, msg.AppendSimple(USERROLE, USERNAME, USERNICK, AVATAR), arg)
} else {
mdb.HashCreate(m, m.OptionSimple(
USERROLE,
USERNAME,
USERNICK,
AVATAR,
), arg)
mdb.HashCreate(m, m.OptionSimple(USERROLE, USERNAME, USERNICK, AVATAR), arg)
}
}
func _sess_check(m *ice.Message, sessid string) {
@ -45,12 +35,12 @@ const SESS = "sess"
func init() {
Index.MergeCommands(ice.Commands{
SESS: {Name: "sess hash auto filter:text", 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(ice.MSG_SESSID)) }},
}, mdb.ImportantHashAction(mdb.EXPIRE, mdb.MONTH, mdb.SHORT, mdb.UNIQ, mdb.FIELD, "time,hash,userrole,username,usernick,avatar,ip,ua"))},
}, mdb.ImportantHashAction("checkbox", ice.TRUE, mdb.EXPIRE, mdb.MONTH, mdb.SHORT, mdb.UNIQ, mdb.FIELD, "time,hash,userrole,username,usernick,avatar,ip,ua"))},
})
}

View File

@ -58,8 +58,11 @@ func init() {
case USERNAME:
m.Push(arg[0], m.Option(ice.MSG_USERNAME))
}
if arg[0] == USERROLE {
m.Option(ice.TABLE_CHECKBOX, ice.TRUE)
}
}},
mdb.CREATE: {Name: "create userrole=void,tech username* usernick language userzone", Hand: func(m *ice.Message, arg ...string) {
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.REMOVE: {Hand: func(m *ice.Message, arg ...string) { _user_remove(m, m.Option(USERNAME)) }},
@ -85,6 +88,9 @@ func UserRole(m *ice.Message, username ice.Any) (role string) {
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)
}
@ -95,11 +101,12 @@ func UserRoot(m *ice.Message, arg ...string) *ice.Message {
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("", arg, 3)
userzone := kit.Select(ice.DEV, arg, 4)
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 {
ice.Info.Username = username
m.Cmd(USER, mdb.CREATE, userrole, username, usernick, language, userzone)
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(USERROLE, userrole, USERNAME, username, USERNICK, usernick))
}

View File

@ -11,4 +11,4 @@ var Index = &ice.Context{Name: CLI, Help: "命令模块"}
func Prefix(arg ...string) string { return kit.Keys(CLI, arg) }
func init() { ice.Index.Register(Index, nil, RUNTIME, SYSTEM, DAEMON, FOREVER, MIRRORS, QRCODE) }
func init() { ice.Index.Register(Index, nil, RUNTIME, SYSTEM, DAEMON, FOREVER, MIRRORS, QRCODE, SUDO) }

View File

@ -30,7 +30,7 @@ func _daemon_exec(m *ice.Message, cmd *exec.Cmd) {
cmd.Stderr = w
}
h := mdb.HashCreate(m.Spawn(), STATUS, START,
ice.CMD, kit.JoinWord(cmd.Args...), DIR, cmd.Dir, ENV, kit.Select("", cmd.Env),
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.WarnNotValid(e, cmd.Args, err.String()) {
@ -61,12 +61,13 @@ func _daemon_exec(m *ice.Message, cmd *exec.Cmd) {
}
const (
DIR = "dir"
ENV = "env"
API = "api"
MOD = "mod"
PID = "pid"
PWD = "pwd"
DIR = "dir"
ENV = "env"
API = "api"
MOD = "mod"
PWD = "pwd"
PID = "pid"
PPID = "ppid"
)
const (
BUILD = "build"
@ -87,6 +88,9 @@ const (
REBOOT = "reboot"
RESTART = "restart"
INTERVAL = "interval"
OPTS = "opts"
ARGS = "args"
LOGS = "logs"
BEGIN = "begin"
END = "end"
@ -148,7 +152,12 @@ func init() {
})
kit.If(len(arg) == 0, func() { m.Action(START, mdb.PRUNES) })
if len(arg) > 0 && m.Length() == 0 {
_daemon_exec(m, _system_cmd(m, kit.Simple(kit.Split(arg[0]), arg[1:])...))
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() })
}
}},
@ -157,9 +166,9 @@ func init() {
func Opens(m *ice.Message, arg ...string) {
if !tcp.IsLocalHost(m, m.Option(ice.MSG_USERIP)) {
return
// return
} else if len(arg) == 0 || arg[0] == "" {
return
// return
}
switch runtime.GOOS {
case DARWIN:

View File

@ -29,7 +29,7 @@ func init() {
}
})
m.Options(CMD_ENV, env, CMD_INPUT, os.Stdin, CMD_OUTPUT, os.Stdout, CMD_ERRPUT, os.Stderr)
kit.If(kit.Env(CTX_LOG), func(p string) { 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.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:])

View File

@ -17,6 +17,8 @@ const (
ADD = "add"
OSID = "osid"
REPOS = "repos"
UBUNTU = "ubuntu"
CENTOS = "centos"
ALPINE = "alpine"
BUSYBOX = "busybox"
RELEASE = "release"

View File

@ -49,11 +49,14 @@ const QRCODE = "qrcode"
func init() {
Index.MergeCommands(ice.Commands{
QRCODE: {Name: "qrcode text fg@key bg@key size auto", Help: "二维码", Role: aaa.VOID, Meta: kit.Dict(
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 {
if m.IsMobileUA() {
m.Option(SIZE, "280")
}
return m.Cmd(Prefix(QRCODE), kit.Simple(args...)).Result()
})
}},
@ -71,7 +74,7 @@ func init() {
// 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, "360"), arg, 3))
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)

View File

@ -43,8 +43,10 @@ func _runtime_init(m *ice.Message) {
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, "", ice.Info.Make.Username)
aaa.UserRoot(ice.Pulse, aaa.ROOT, ice.Info.Username, "", "", ice.OPS)
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 {
@ -133,6 +135,8 @@ const (
KERNEL = "kernel"
ARCH = "arch"
CPU = "cpu"
OS = "os"
)
const (
PATH = "PATH"
@ -147,11 +151,13 @@ const (
CTX_SHY = "ctx_shy"
CTX_DEV = "ctx_dev"
CTX_DEV_IP = "ctx_dev_ip"
CTX_REPOS = "ctx_repos"
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"
@ -180,8 +186,8 @@ const RUNTIME = "runtime"
func init() {
Index.MergeCommands(ice.Commands{
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); aaa.White(m, ice.LICENSE) }},
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) }},
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) }},

View File

@ -52,14 +52,21 @@ func _system_cmd(m *ice.Message, arg ...string) *exec.Cmd {
m.Logs(FIND, "mirrors cmd", bin)
}
}
cmd := exec.Command(kit.Select(arg[0], 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(EXEC, CMD_DIR, cmd.Dir); !nfs.Exists(m, cmd.Dir) {
file.MkdirAll(cmd.Dir, ice.MOD_DIR)
}
}
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 {
@ -92,6 +99,7 @@ func _system_exec(m *ice.Message, cmd *exec.Cmd) {
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())
}
}()
}
@ -150,10 +158,13 @@ const (
)
const (
SH = "sh"
LN = "ln"
MV = "mv"
RM = "rm"
SH = "sh"
LN = "ln"
CP = "cp"
MV = "mv"
RM = "rm"
CD = "cd"
CAT = "cat"
FIND = "find"
GREP = "grep"
@ -167,10 +178,11 @@ const (
ECHO = "echo"
KILL = "kill"
GO = "go"
GIT = "git"
MAN = "man"
YUM = "yum"
GO = "go"
GOTAGS = "gotags"
GIT = "git"
MAN = "man"
YUM = "yum"
)
const SYSTEM = "system"
@ -199,7 +211,10 @@ func init() {
}},
})
ice.Info.SystemCmd = func(m *ice.Message, arg ...ice.Any) *ice.Message {
return m.Cmd(append([]ice.Any{SYSTEM}, arg...)...)
msg := m.Cmd(append([]ice.Any{SYSTEM}, arg...)...)
if m.Warn(!IsSuccess(msg), msg.Append(CMD_ERR)) {
}
return msg
}
}

11
base/cli/system_darwin.go Normal file
View 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
View 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
}

View 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
}

View File

@ -9,6 +9,7 @@ import (
"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"
)
@ -16,12 +17,14 @@ func _command_list(m *ice.Message, name string) *ice.Message {
if strings.HasPrefix(name, "can.") {
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) {
icon := kit.Format(kit.Value(cmd.Meta, kit.Keys(ice.CTX_ICONS, key)))
m.Push(mdb.INDEX, kit.Keys(s.Prefix(), key))
m.Push(mdb.NAME, kit.Format(cmd.Name))
m.Push(mdb.HELP, kit.Format(cmd.Help))
m.Push(mdb.LIST, kit.Format(cmd.List))
m.Push(mdb.META, kit.Format(cmd.Meta))
m.Push(mdb.ICONS, kit.Select(cmd.Icon, icon, !kit.HasPrefix(icon, "bi ", "{")))
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))
@ -60,6 +63,7 @@ const (
ICONS = ice.CTX_ICONS
TRANS = ice.CTX_TRANS
TITLE = ice.CTX_TITLE
INPUT = html.INPUT
)
const COMMAND = "command"
@ -143,7 +147,7 @@ func FileCmd(dir string) string {
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.REQUIRE_USR, path.Base(_ls[0]), _ls[1])] = key
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
@ -153,9 +157,9 @@ func GetFileCmd(dir string) string {
if strings.HasPrefix(dir, ice.REQUIRE+nfs.PS) {
dir = nfs.PS + dir
} else if strings.HasPrefix(dir, ice.ISH_PLUGED) {
dir = path.Join(nfs.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(nfs.PS, ice.REQUIRE, ice.Info.Make.Module, dir), path.Join(nfs.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
}
@ -167,7 +171,7 @@ func GetFileCmd(dir string) string {
return ""
}
func GetCmdHelp(m *ice.Message, cmds string) (file string) {
file = strings.TrimPrefix(m.FileURI(kit.ExtChange(GetCmdFile(m, cmds), nfs.SHY)), nfs.REQUIRE)
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 = "" })
}
@ -175,8 +179,8 @@ func GetCmdHelp(m *ice.Message, cmds string) (file string) {
}
func GetCmdFile(m *ice.Message, cmds string) (file string) {
m.Search(kit.Select(m.PrefixKey(), cmds), func(key string, cmd *ice.Command) {
if file = strings.TrimPrefix(m.FileURI(kit.Split(cmd.FileLine(), nfs.DF)[0]), nfs.REQUIRE); !nfs.Exists(m, file) {
file = path.Join(nfs.REQUIRE, file)
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

View File

@ -33,13 +33,16 @@ 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 := mdb.Confv(msg, k); _config_only(v, mdb.META) && _config_only(kit.Value(v, mdb.META),
mdb.IMPORTANT, mdb.EXPIRE, mdb.SHORT, mdb.FIELD, mdb.FIELDS, mdb.ACTION, mdb.SORT, mdb.TOOLS,
nfs.SOURCE, nfs.SCRIPT,
lex.REGEXP, nfs.PATH, "link",
"linux", "darwin", "windows",
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 {
@ -58,6 +61,9 @@ func _config_save(m *ice.Message, name string, arg ...string) {
}
}
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())
@ -104,14 +110,28 @@ func init() {
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.Config(m, arg[0], nil, nil)
mdb.Conf(m, arg[0], mdb.HASH, "")
}},
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.EXPORT, mdb.IMPORT, nfs.TRASH)
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)
}
}},
@ -121,12 +141,12 @@ func init() { ice.Info.Save = Save; ice.Info.Load = Load }
func Save(m *ice.Message, arg ...string) *ice.Message {
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(CONFIG, nfs.SAVE, m.Prefix(nfs.JSON), arg)
return m.Cmd(prefix(CONFIG), nfs.SAVE, m.Prefix(nfs.JSON), arg)
}
func Load(m *ice.Message, arg ...string) *ice.Message {
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(CONFIG, nfs.LOAD, m.Prefix(nfs.JSON), arg)
return m.Cmd(prefix(CONFIG), nfs.LOAD, m.Prefix(nfs.JSON), arg)
}
func ConfAction(arg ...ice.Any) ice.Actions {
return ice.Actions{ice.CTX_INIT: mdb.AutoConfig(arg...)}

View File

@ -2,6 +2,7 @@ package ctx
import (
ice "shylinux.com/x/icebergs"
kit "shylinux.com/x/toolkits"
)
const CTX = "ctx"
@ -9,3 +10,5 @@ const CTX = "ctx"
var Index = &ice.Context{Name: CTX, Help: "标准模块"}
func init() { ice.Index.Register(Index, nil, CONTEXT, COMMAND, CONFIG) }
func prefix(arg ...string) string { return kit.Keys(CTX, arg) }

View File

@ -26,6 +26,11 @@ func DisplayStory(m *ice.Message, file string, arg ...ice.Any) *ice.Message {
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 {
@ -43,6 +48,15 @@ func DisplayStoryForm(m *ice.Message, arg ...ice.Any) *ice.Message {
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...)
}
@ -70,6 +84,10 @@ 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, 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) *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)))

View File

@ -25,7 +25,7 @@ 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("")), arg[1]).Table(func(value ice.Maps) {
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 })

View File

@ -19,10 +19,12 @@ 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) {
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()
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 {

View File

@ -1,6 +1,7 @@
package log
import (
"regexp"
"strings"
"time"
"unicode"
@ -23,7 +24,7 @@ func init() {
LEVEL = "level"
)
Index.MergeCommands(ice.Commands{
DEBUG: {Name: "debug level=error,bench,debug,error,watch offset limit filter auto reset app doc", Help: "后台日志", Actions: ice.Actions{
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) })
@ -32,6 +33,7 @@ func init() {
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:
@ -66,6 +68,10 @@ func init() {
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:

View File

@ -22,12 +22,11 @@ type Log struct {
type Frame struct{ p chan *Log }
func (f *Frame) Begin(m *ice.Message, arg ...string) {
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}
}
}
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
@ -37,6 +36,10 @@ func (f *Frame) Start(m *ice.Message, arg ...string) {
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:

View File

@ -23,7 +23,7 @@ func init() {
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.Action("filter:text").StatusTimeCount(stats)
m.StatusTimeCount(stats)
}},
})
}

View File

@ -4,7 +4,6 @@ import (
"encoding/json"
"io"
"net/http"
"os"
"path"
"strings"
@ -102,26 +101,27 @@ func _hash_prunes(m *ice.Message, prefix, chain string, arg ...string) {
})
}
func _hash_export(m *ice.Message, prefix, chain, file string) {
defer Lock(m, prefix)()
p := kit.Keys(file, JSON)
count := len(Confm(m, prefix, kit.Keys(chain, HASH)))
if count == 0 {
if s, e := os.Stat(p); e == nil && !s.IsDir() {
os.Remove(p)
}
if !ice.HasUsr() {
return
}
f, p, e := miss.CreateFile(p)
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, count)
m.Logs(EXPORT, KEY, path.Join(prefix, chain), FILE, p)
en := json.NewEncoder(f)
if en.SetIndent("", " "); !m.WarnNotValid(en.Encode(m.Confv(prefix, kit.Keys(chain, HASH))), EXPORT, prefix) {
m.Conf(prefix, kit.Keys(chain, HASH), "")
// m.Conf(prefix, kit.Keys(chain, HASH), "")
}
}
func _hash_import(m *ice.Message, prefix, chain, file string) {
if !ice.HasUsr() {
return
}
defer Lock(m, prefix)()
f, e := miss.OpenFile(kit.Keys(file, JSON))
if e != nil && !ice.Info.Important {
@ -131,7 +131,7 @@ func _hash_import(m *ice.Message, prefix, chain, file string) {
}
defer f.Close()
data := Map{}
m.Assert(json.NewDecoder(f).Decode(&data))
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) })
@ -261,7 +261,9 @@ func HashInputs(m *ice.Message, arg ...Any) *ice.Message {
return m.Cmdy(INPUTS, m.PrefixKey(), m.Option(SUBKEY), HASH, arg)
}
func HashCreate(m *ice.Message, arg ...Any) string {
kit.If(len(arg) == 0 || len(kit.Simple(arg...)) == 0, func() { arg = append(arg, m.OptionSimple(strings.Replace(HashField(m), "hash,", "", 1))) })
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()
}
@ -289,7 +291,7 @@ func HashSelect(m *ice.Message, arg ...string) *ice.Message {
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, PRUNES)
return m.Action(CREATE)
}
return sortByField(m, HashField(m), arg...)
}
@ -405,7 +407,7 @@ func Rich(m *ice.Message, prefix string, chain Any, data Any) string {
}
func sortByField(m *ice.Message, fields string, arg ...string) *ice.Message {
return m.Table(func(value ice.Maps) {
m.SetAppend().OptionFields(ice.FIELDS_DETAIL)
m.SetAppend().FieldsSetDetail()
kit.For(kit.Split(fields), func(key string) {
key = strings.TrimSuffix(key, "*")
if key == HASH {

View File

@ -18,8 +18,12 @@ func getLock(m *ice.Message, arg ...string) *task.Lock {
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 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 {

View File

@ -5,7 +5,6 @@ import (
"strings"
ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/web/html"
kit "shylinux.com/x/toolkits"
)
@ -98,11 +97,14 @@ const (
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"
@ -131,14 +133,17 @@ const (
WEIGHT = "weight"
SUBKEY = "mdb.sub"
ACTION = "action"
UPLOAD = "upload"
RECENT = "recent"
REPEAT = "repeat"
REVERT = "revert"
RENAME = "rename"
VENDOR = "vendor"
PRUNE = "prune"
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"
@ -222,26 +227,21 @@ var Index = &ice.Context{Name: MDB, Help: "数据模块", Commands: ice.Commands
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[STATUS] != DISABLE {
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[STATUS] != DISABLE {
if value[ENABLE] != ice.FALSE {
m.Cmd(EXPORT, value[INDEX], "", value[TYPE])
}
})
}},
ENABLE: {Hand: func(m *ice.Message, arg ...string) { HashModify(m, STATUS, ENABLE) }},
DISABLE: {Hand: func(m *ice.Message, arg ...string) { HashModify(m, STATUS, DISABLE) }},
}, ExportHashAction(SHORT, INDEX, FIELD, "time,index,type,status")), Hand: func(m *ice.Message, arg ...string) {
}, ExportHashAction(SHORT, INDEX, FIELD, "time,index,type,enable")), Hand: func(m *ice.Message, arg ...string) {
if len(arg) < 2 {
HashSelect(m, arg...).RewriteAppend(func(value, key string, index int) string {
kit.If(key == STATUS, func() { value = kit.Select(ENABLE, value) })
return value
}).PushAction().Action(html.FILTER)
HashSelect(m, arg...).PushAction(REMOVE)
return
}
m.OptionDefault(CACHE_LIMIT, "-1")
@ -290,12 +290,14 @@ func AutoConfig(arg ...Any) *ice.Action {
}
add := func(list []string) (inputs []Any) {
kit.For(list, func(k string) {
kit.If(!kit.IsIn(k, TIME, HASH, COUNT, ID), func() {
kit.If(!kit.IsIn(k, TIME, HASH, COUNT, ID, ENABLE, DISABLE), func() {
inputs = append(inputs, k+kit.Select("", FOREACH, strings.Contains(s, k)))
})
})
return
}
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)))...) })

View File

@ -59,7 +59,13 @@ func _zone_select(m *ice.Message, prefix, chain, zone string, id string) {
})
}
func _zone_export(m *ice.Message, prefix, chain, file string) {
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()
@ -88,6 +94,9 @@ func _zone_export(m *ice.Message, prefix, chain, file string) {
m.Logs(EXPORT, KEY, path.Join(prefix, chain), FILE, p, COUNT, count)
}
func _zone_import(m *ice.Message, prefix, chain, file string) {
if !ice.HasUsr() {
return
}
defer Lock(m, prefix)()
f, e := miss.OpenFile(kit.Keys(file, CSV))
if e != nil && !ice.Info.Important {

View File

@ -2,6 +2,7 @@ package nfs
import (
"bytes"
"encoding/csv"
"encoding/json"
"io"
"io/ioutil"
@ -30,7 +31,7 @@ func _cat_line(m *ice.Message, p string) (n int) {
return
}
func _cat_list(m *ice.Message, p string) {
if m.Option(CAT_CONTENT) == "" && !aaa.Right(m, path.Join(m.Option(DIR_ROOT), p)) {
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, p)
@ -75,6 +76,8 @@ const (
TARGET = "target"
BINARY = "binary"
SCRIPT = "script"
FORMAT = "format"
TRANS = "trans"
CLONE = "clone"
REPOS = "repos"
@ -96,6 +99,7 @@ const (
SHY = ice.SHY
CSV = ice.CSV
JSON = ice.JSON
MOD = "mod"
PROTO = "proto"
YAML = "yaml"
@ -207,3 +211,26 @@ func ReadFile(m *ice.Message, p string) (b []byte, e error) {
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)
}
}

View File

@ -116,7 +116,7 @@ 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(mdb.SHOW, TRASH)
m.PushButton(mdb.SHOW, "rename", TRASH)
default:
m.Push(field, "")
}
@ -144,10 +144,18 @@ const (
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
@ -155,6 +163,8 @@ const (
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/"
@ -167,6 +177,12 @@ const (
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/"
@ -178,6 +194,7 @@ const (
SHARE_LOCAL = "/share/local/"
PATHNAME = "pathname"
FILENAME = "filename"
CONTEXTS = "contexts"
TYPE_ALL = "all"
TYPE_BIN = "bin"
@ -186,8 +203,8 @@ const (
TYPE_BOTH = "both"
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"
@ -209,7 +226,9 @@ func init() {
Index.MergeCommands(ice.Commands{
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.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) {
@ -224,7 +243,12 @@ func init() {
SIZE: {Hand: func(m *ice.Message, arg ...string) {
m.Echo(kit.Select("", kit.Split(m.System("du", "-sh").Result()), 0))
}},
TRASH: {Hand: func(m *ice.Message, arg ...string) { m.Cmd(TRASH, mdb.CREATE, m.Option(PATH)) }},
"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)
kit.If(strings.HasPrefix(dir, PS), func() { root = "" })
@ -255,10 +279,12 @@ func SplitPath(m *ice.Message, p string) []string {
} 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.TrimPrefix(p, kit.Path("")+PS)
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 {
@ -285,7 +311,7 @@ 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:
case PNG, JPG, JPEG, "gif":
m.EchoImages(p)
case MP4, MOV:
m.EchoVideos(p)

View File

@ -4,7 +4,6 @@ import (
"path"
ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/web/html"
kit "shylinux.com/x/toolkits"
)
@ -14,7 +13,7 @@ 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).Action(html.FILTER).Option(ice.MSG_DISPLAY, "")
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) {

View File

@ -1,7 +1,6 @@
package nfs
import (
"path"
"strings"
ice "shylinux.com/x/icebergs"
@ -20,13 +19,15 @@ func init() {
Index.MergeCommands(ice.Commands{
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) })
m.Options(mdb.VALUE, arg[0], CMD_DIR, kit.Select("", arg, 2))
kit.For(strings.Split(m.System(GREP, "--exclude=.[a-z]*", "--exclude-dir=.[a-z]*", "-rni", arg[0], path.Join(kit.Select(SRC, arg, 1))).Result(), ice.NL), func(s string) {
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 {
m.Push(FILE, strings.TrimPrefix(ls[0], PWD)).Push(LINE, ls[1]).Push(mdb.TEXT, 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(kit.Dict(PATH, m.Option(CMD_DIR)))
m.Sort("path,file,line")
}},
})
}

View File

@ -10,6 +10,6 @@ const NFS = "nfs"
var Index = &ice.Context{Name: NFS, Help: "存储模块"}
func init() {
ice.Index.Register(Index, nil, ZIP, TAR, CAT, DIR, PACK, DEFS, SAVE, PUSH, COPY, LINK, GREP, FIND, MOVE, 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) }

View File

@ -74,6 +74,7 @@ const COPY = "copy"
const LINK = "link"
const LOAD = "load"
const MOVE = "move"
const MOVETO = "moveto"
func init() {
Index.MergeCommands(ice.Commands{
@ -100,9 +101,12 @@ func init() {
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) {
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) {
@ -114,6 +118,7 @@ func Create(m *ice.Message, p string, cb ice.Any) {
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) {

View File

@ -4,7 +4,6 @@ import (
"path"
ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/web/html"
kit "shylinux.com/x/toolkits"
)
@ -20,7 +19,7 @@ func init() {
}},
}), Hand: func(m *ice.Message, arg ...string) {
if len(arg) == 0 {
m.Cmdy(ice.COMMAND).Action(html.FILTER).Option(ice.MSG_DISPLAY, "")
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) {

View File

@ -14,10 +14,10 @@ func _trash_create(m *ice.Message, from string) {
return
}
s, e := StatFile(m, from)
defer Remove(m, from)
if m.WarnNotFound(e, from) {
return
}
defer Remove(m, from)
p := path.Join(ice.VAR_TRASH, path.Base(from))
kit.If(!s.IsDir(), func() { Open(m, from, func(r io.Reader) { p = path.Join(ice.VAR_TRASH, kit.HashsPath(r)) }) })
RemoveAll(m, p)

View File

@ -105,7 +105,7 @@ func (f *Frame) parse(m *ice.Message, h, line string) string {
return ""
}
func (f *Frame) scan(m *ice.Message, h, line string) *Frame {
// kit.If(f.source == STDIO, func() { m.Option(ice.LOG_DISABLE, ice.TRUE) })
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)

View File

@ -45,6 +45,7 @@ const (
SEND = "send"
RECV = "recv"
ECHO = "echo"
DONE = "done"
DIRECT = "direct"
)

View File

@ -24,6 +24,9 @@ func _host_domain(m *ice.Message) string {
}
return ""
},
func() string {
return LOCALHOST
},
)
}
func _host_list(m *ice.Message, name string) *ice.Message {
@ -68,6 +71,7 @@ func init() {
), 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 {
@ -101,7 +105,7 @@ func init() {
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) { mdb.Config(m, DOMAIN, p) })
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) {

View File

@ -3,6 +3,7 @@ package tcp
import (
"net"
"path"
"runtime"
"strconv"
"strings"
@ -61,6 +62,15 @@ func init() {
}
})
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":
@ -74,12 +84,24 @@ func init() {
parse := func(str string) int64 { port, _ := strconv.ParseInt(str, 16, 32); return port }
trans := func(str string) string {
switch str {
case "0A":
return "LISTEN"
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
}
@ -101,7 +123,7 @@ func init() {
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").StatusTimeCount(stats)
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) != "")
@ -132,9 +154,15 @@ func init() {
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 := mdb.Config(m, CURRENT), mdb.Config(m, BEGIN), mdb.Config(m, END)
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) {

View File

@ -56,6 +56,7 @@ const (
HOSTPORT = "hostport"
HOSTNAME = "hostname"
NODENAME = "nodename"
NODETYPE = "nodetype"
BANDWIDTH = "bandwidth"
ADDRESS = "address"
)

View File

@ -5,7 +5,6 @@ import (
ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/aaa"
"shylinux.com/x/icebergs/base/lex"
"shylinux.com/x/icebergs/base/mdb"
kit "shylinux.com/x/toolkits"
)
@ -18,22 +17,29 @@ const WIFI = "wifi"
func init() {
const (
NETWORKSETUP = "networksetup"
DISCOVER = "discover"
CONNECT = "connect"
)
Index.MergeCommands(ice.Commands{
WIFI: {Help: "无线", Actions: ice.MergeActions(ice.Actions{
DISCOVER: {Help: "查找", Hand: func(m *ice.Message, arg ...string) {
m.Push(SSID, strings.Split(m.System(NETWORKSETUP, "-listpreferredwirelessnetworks", "en0").Result(), lex.NL)[1:])
m.PushAction(CONNECT)
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))))
m.System(NETWORKSETUP, "-setairportnetwork", "en0", kit.Select(m.Option(SSID), msg.Append(SSID)), msg.Append(aaa.PASSWORD))
m.ProcessHold()
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.HashAction(mdb.SHORT, SSID, mdb.FIELD, "time,ssid,password")), Hand: func(m *ice.Message, arg ...string) {
if mdb.HashSelect(m, arg...).PushAction(CONNECT, mdb.REMOVE).Action(mdb.CREATE, DISCOVER); len(arg) > 0 {
}, 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)))
}
}},

View File

@ -73,7 +73,7 @@ func init() {
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) {
m.ProcessOpen(HostPort(m, m.Option(mdb.NAME), m.Option(tcp.PORT)))
m.ProcessOpen(HostPort(m, m.Option(tcp.HOST), m.Option(tcp.PORT)))
}},
tcp.SEND: {Hand: func(m *ice.Message, arg ...string) { _broad_send(m, "", "", "", "", arg...) }},
}, gdb.EventsAction(SERVE_START), mdb.HashAction(mdb.SHORT, "host,port",

View File

@ -5,8 +5,10 @@ import (
"net/http"
"os"
"path"
"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/tcp"
@ -70,6 +72,7 @@ func _cache_upload(m *ice.Message, r *http.Request) (mime, name, file, size stri
return "", "", "", "0"
}
func _cache_download(m *ice.Message, r *http.Response, file string, cb ice.Any) string {
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 {
@ -174,20 +177,35 @@ func init() {
action.Hand = ice.MergeHand(func(m *ice.Message, arg ...string) {
up := Upload(m)
m.Assert(len(up) > 1)
if m.Cmd(CACHE, m.Option(ice.MSG_UPLOAD)).Table(func(value ice.Maps) { m.Options(value) }).Length() == 0 {
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 {
m.Cmdy(CACHE, WATCH, m.Option(mdb.HASH), path.Join(m.Option(nfs.PATH), up[1]))
// 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)
}
})
}
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 {
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, tcp.PublishLocalhost(m, m.MergeLink(PP(SHARE, CACHE, m.Append(mdb.HASH)))))
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 {

View File

@ -47,7 +47,7 @@ const COUNT = "count"
func init() {
Index.MergeCommands(ice.Commands{
COUNT: &ice.Command{Name: "count hash auto group valid location filter", Help: "计数器", Meta: kit.Dict(
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) {

View File

@ -1,7 +1,6 @@
package web
import (
"net/http"
"os"
"path"
"regexp"
@ -22,92 +21,91 @@ import (
kit "shylinux.com/x/toolkits"
)
func _dream_list(m *ice.Message, simple bool) *ice.Message {
func _dream_list(m *ice.Message) *ice.Message {
list := m.CmdMap(SPACE, mdb.NAME)
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 {
value[ice.MAIN] = space[ice.MAIN]
value[mdb.ICONS] = space[mdb.ICONS]
m.Push("", value, kit.Slice(head, 0, -1))
if m.IsCliUA() || simple {
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]).Push(mdb.TEXT, DreamStat(m, value[mdb.NAME]))
kit.If(aaa.IsTechOrRoot(m), func() { m.PushButton(cli.STOP) }, func() { m.PushButton() })
} else {
msg := gdb.Event(m.Spawn(value, space), DREAM_TABLES)
kit.If(aaa.IsTechOrRoot(m), func() { msg.Copy(m.Spawn().PushButton(cli.STOP)) })
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]).Push(mdb.TEXT, msg.Append(mdb.TEXT))
m.PushButton(strings.Join(msg.Appendv(ctx.ACTION), ""))
}
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).Push(nfs.MODULE, "").Push(nfs.VERSION, "").Push(mdb.TEXT, "")
kit.If(aaa.IsTechOrRoot(m), func() { m.PushButton(cli.START, nfs.TRASH) }, func() { m.PushButton() })
m.Push(cli.STATUS, cli.STOP).PushButton(cli.START, nfs.TRASH)
} else {
m.Push(cli.STATUS, cli.BEGIN).Push(nfs.MODULE, "").Push(nfs.VERSION, "").Push(mdb.TEXT, "")
kit.If(aaa.IsTechOrRoot(m), func() { m.PushButton(cli.START, mdb.REMOVE) }, func() { m.PushButton() })
m.Push(cli.STATUS, cli.BEGIN).PushButton(cli.START, mdb.REMOVE)
}
}
})
m.RewriteAppend(func(value, key string, index int) string {
if key == mdb.TIME {
if space, ok := list[m.Appendv(mdb.NAME)[index]]; ok {
value = space[mdb.TIME]
return space[mdb.TIME]
}
}
return value
})
return m
}
func _dream_list_icon(m *ice.Message) {
m.RewriteAppend(func(value, key string, index int) string {
if key == mdb.ICONS {
} 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)
} else {
return m.FileURI(nfs.USR_ICONS_ICEBERGS)
}
}
return value
})
return m
}
func _dream_list_more(m *ice.Message, simple bool) *ice.Message {
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 SERVER:
value[mdb.TEXT] = kit.JoinLine(value[nfs.MODULE], value[mdb.TEXT])
if simple {
defer m.PushButton("")
} else {
msg := gdb.Event(m.Spawn(value), DREAM_TABLES)
defer m.PushButton(strings.Join(msg.Appendv(ctx.ACTION), ""))
}
case ORIGIN:
value[mdb.TEXT] = kit.JoinLine(value[nfs.MODULE], value[mdb.TEXT])
if simple {
defer m.PushButton("")
} else {
msg := gdb.Event(m.Spawn(value), DREAM_TABLES)
defer m.PushButton(strings.Join(msg.Appendv(ctx.ACTION), ""))
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:
value[mdb.TEXT] = kit.JoinWord(value[AGENT], value[cli.SYSTEM], value[aaa.IP])
defer m.PushButton(GRANT)
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, kit.Split(mdb.Config(m, mdb.FIELD)+",type,status,module,version,text"))
m.Push("", value, field)
m.PushButton(button...)
})
return m
}
@ -116,8 +114,7 @@ func _dream_start(m *ice.Message, name string) {
return
}
if !m.IsCliUA() {
defer m.ProcessOpenAndRefresh(m.MergePod(name))
defer ToastProcess(m, mdb.CREATE, name)()
defer m.ProcessRefresh()
}
defer mdb.Lock(m, m.PrefixKey(), cli.START, name)()
p := _dream_check(m, name)
@ -136,27 +133,40 @@ func _dream_start(m *ice.Message, name string) {
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, mdb.TYPE, WORKER, m.OptionSimple(mdb.NAME), cli.DAEMON, ice.OPS)) {
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++ {
if pid := m.Cmdx(nfs.CAT, pp, kit.Dict(ice.MSG_USERROLE, aaa.TECH)); pid != "" && nfs.Exists(m, "/proc/"+pid) {
m.Info("already exists %v", pid)
} else if gdb.SignalProcess(m, pid) {
m.Info("already exists %v", pid)
} else if m.Cmd(SPACE, name).Length() > 0 {
m.Info("already exists %v", name)
} else {
pid := msg.Cmdx(nfs.CAT, pp)
if pid == "" {
return p
}
m.Sleep300ms()
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 ""
}
return p
}
@ -164,7 +174,8 @@ 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, p)
// 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))
}
@ -193,6 +204,8 @@ const (
STOPALL = "stopall"
FOR_EACH = "forEach"
FOR_FLOW = "forFlow"
GETTOKEN = "gettoken"
SETTOKEN = "settoken"
DREAM_INPUTS = "dream.inputs"
DREAM_CREATE = "dream.create"
@ -202,7 +215,6 @@ const (
DREAM_STOP = "dream.stop"
DREAM_OPEN = "dream.open"
DREAM_CLOSE = "dream.close"
DREAM_TABLES = "dream.tables"
DREAM_ACTION = "dream.action"
@ -216,82 +228,50 @@ func init() {
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.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) {
m = m.Spawn()
m.GoSleep(cli.TIME_1s, func() {
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))
}
})
m.GoSleep(cli.TIME_3s, func() {
mdb.HashSelects(m).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]))
}
})
})
ice.AFTER_INIT: {Hand: func(m *ice.Message, arg ...string) {
AddPortalProduct(m, "云空间", `
比虚拟机和容器更加轻量每个空间都是一个完整的系统拥有各种软件与独立的环境
空间内所有的软件配置数据以源码库形式保存每个空间都可以随时启动停止上传下载分享
每个空间都自带软件开发工具也可以随时编程添加新的功能
`, 200.0)
}},
html.BUTTON: {Hand: func(m *ice.Message, arg ...string) { mdb.Config(m, html.BUTTON, kit.Join(arg)) }},
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 m.Option(ctx.ACTION) {
case mdb.CREATE:
switch arg[0] {
case mdb.NAME, nfs.TEMPLATE:
_dream_list(m, true).Cut("name,status,time")
return
case mdb.ICONS:
mdb.HashInputs(m, arg)
return
case nfs.BINARY:
m.Cmdy(nfs.DIR, ice.BIN, "path,size,time", kit.Dict(nfs.DIR_TYPE, nfs.TYPE_BIN))
m.Cmd(nfs.DIR, ice.USR_LOCAL_WORK, kit.Dict(nfs.DIR_TYPE, nfs.TYPE_BOTH), func(value ice.Maps) {
m.Cmdy(nfs.DIR, path.Join(value[nfs.PATH], ice.BIN), "path,size,time", kit.Dict(nfs.DIR_TYPE, nfs.TYPE_BIN))
})
m.RenameAppend(nfs.PATH, arg[0])
// mdb.HashInputs(m, arg)
DreamListSpide(m, []string{ice.DEV}, ORIGIN, func(dev, origin string) {
m.Spawn().SplitIndex(m.Cmdx(SPIDE, dev, SPIDE_RAW, http.MethodGet, S(), cli.GOOS, runtime.GOOS, cli.GOARCH, runtime.GOARCH)).Table(func(value ice.Maps) {
m.Push(arg[0], origin+S(value[mdb.NAME])).Push(nfs.SIZE, value[nfs.SIZE]).Push(mdb.TIME, value[mdb.TIME])
})
})
}
case STARTALL:
DreamEach(m, "", cli.STOP, func(name string) { m.Push(arg[0], name) })
return
case tcp.SEND:
m.Cmd(SPACE, func(value ice.Maps) {
kit.If(kit.IsIn(value[mdb.TYPE], SERVER), func() { m.Push(arg[0], value[mdb.NAME]) })
})
return
}
switch arg[0] {
case mdb.NAME:
DreamEach(m, "", cli.START, func(name string) { m.Push(arg[0], name) })
case ctx.CMDS:
m.Cmdy(ctx.COMMAND)
case nfs.FILE:
m.Options(nfs.DIR_TYPE, nfs.TYPE_CAT, ice.MSG_FIELDS, nfs.PATH)
m.Cmdy(nfs.DIR, nfs.SRC).Cmdy(nfs.DIR, nfs.ETC).Cmdy(nfs.DIR, "")
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, DREAM_INPUTS, arg)
}
}},
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)) })
kit.If(mdb.Config(m, nfs.BINARY), func(p string) { m.OptionDefault(nfs.BINARY, p+m.Option(mdb.NAME)) })
kit.If(mdb.Config(m, nfs.REPOS), func(p string) { m.OptionDefault(nfs.REPOS, p+m.Option(mdb.NAME)) })
m.Option(nfs.REPOS, kit.Select("", kit.Split(m.Option(nfs.REPOS)), -1))
m.OptionDefault(mdb.ICONS, nfs.USR_ICONS_CONTEXTS)
if mdb.HashCreate(m); ice.Info.Important == true {
_dream_start(m, m.Option(mdb.NAME))
StreamPushRefreshConfirm(m, m.Trans("refresh for new space ", "刷新列表查看新空间 ")+m.Option(mdb.NAME))
SpaceEvent(m, OPS_DREAM_CREATE, m.Option(mdb.NAME), m.OptionSimple(mdb.NAME, nfs.REPOS, nfs.BINARY)...)
}
}},
@ -299,15 +279,6 @@ func init() {
gdb.Event(m, DREAM_REMOVE, m.OptionSimple(mdb.NAME))
mdb.HashRemove(m)
}},
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)
}},
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: ""})
@ -328,37 +299,39 @@ func init() {
m.Cmd(SPACE, path.Base(p), cli.RUNTIME, UPGRADE)
return true
}
})
kit.If(m.Option(mdb.NAME) == "", func() { m.Sleep("5s").Cmdy(ROUTE, cli.BUILD).ProcessInner() })
}},
"gowork": {Name: "gowork name", Help: "工作区", Hand: func(m *ice.Message, arg ...string) {
m.Cmd(cli.SYSTEM, cli.GO, "work", "init")
m.Cmd(cli.SYSTEM, cli.GO, "work", "use", ".")
m.Cmd(cli.SYSTEM, cli.GO, "work", "use", nfs.USR_RELEASE)
m.Cmd(cli.SYSTEM, cli.GO, "work", "use", nfs.USR_ICEBERGS)
m.Cmd(cli.SYSTEM, cli.GO, "work", "use", nfs.USR_TOOLKITS)
DreamEach(m, m.Option(mdb.NAME), "", func(name string) { m.Cmd(cli.SYSTEM, cli.GO, "work", "use", path.Join(ice.USR_LOCAL_WORK, name)) })
}).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) {
PushNoticeRich(m, mdb.NAME, ice.Info.NodeName, msg.Cmd(COMPILE, goos, cli.AMD64).AppendSimple())
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) {
PushNoticeRich(m.Options(ice.MSG_COUNT, "0", ice.LOG_DISABLE, ice.TRUE), mdb.NAME, name, msg.Cmd(SPACE, name, COMPILE, goos, cli.AMD64, kit.Dict(ice.MSG_USERPOD, name)).AppendSimple())
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()
}},
VERSION: {Hand: func(m *ice.Message, arg ...string) { m.Cmdy("web.code.version") }},
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"))
@ -370,60 +343,63 @@ func init() {
if cb, ok := m.OptionCB("").(func(string) bool); ok && cb(p) {
return
}
defer PushNoticeGrow(msg, "\r\n\r\n\r\n")
PushNoticeGrow(msg, kit.Format("[%s]%s$ %s\r\n", time.Now().Format(ice.MOD_TIME_ONLY), name, m.Option(ice.CMD)))
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()
})
}},
ctx.CMDS: {Name: "cmds name cmds*", Help: "命令", Icon: "bi bi-terminal", Hand: func(m *ice.Message, arg ...string) {
DreamEach(m, m.Option(mdb.NAME), "", func(name string) {
m.Push(mdb.NAME, name).Push(mdb.TEXT, m.Cmdx(SPACE, name, kit.Split(m.Option(ctx.CMDS))))
}).StatusTimeCount(m.OptionSimple(ctx.CMDS))
}},
nfs.FILE: {Name: "file name file*", Help: "文件", Icon: "bi bi-file-earmark-code", Hand: func(m *ice.Message, arg ...string) {
DreamEach(m, m.Option(mdb.NAME), "", func(name string) {
m.Push(mdb.NAME, name).Push(mdb.TEXT, m.Cmdx(SPACE, name, nfs.CAT, m.Option(nfs.FILE)))
}).StatusTimeCount(m.OptionSimple(nfs.FILE))
}},
cli.START: {Hand: func(m *ice.Message, arg ...string) {
_dream_start(m, m.Option(mdb.NAME))
gdb.Event(m, DREAM_START, arg)
}},
cli.STOP: {Hand: func(m *ice.Message, arg ...string) {
defer ToastProcess(m)()
gdb.Event(m, DREAM_STOP, arg)
m.Cmd(SPACE, mdb.MODIFY, m.OptionSimple(mdb.NAME), mdb.STATUS, cli.STOP)
m.Cmd(SPACE, m.Option(mdb.NAME), ice.EXIT).Sleep3s()
}},
cli.RUNTIME: {Hand: func(m *ice.Message, arg ...string) {
ProcessPodCmd(m, m.Option(mdb.NAME), "", nil, arg...)
}},
tcp.SEND: {Name: "send space*", Hand: func(m *ice.Message, arg ...string) {
m.Cmd(SPACE, m.Option(SPACE), DREAM, mdb.CREATE, m.OptionSimple(mdb.NAME, mdb.ICONS, nfs.REPOS, nfs.BINARY))
m.Cmd(SPACE, m.Option(SPACE), DREAM, cli.START, m.OptionSimple(mdb.NAME))
ProcessIframe(m, "", m.MergePod(kit.Keys(m.Option(SPACE), m.Option(mdb.NAME))))
}},
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)))
}},
nfs.COPY: {Name: "copy to*", Help: "复制", Hand: func(m *ice.Message, arg ...string) {
m.Cmdy("", mdb.CREATE, mdb.NAME, m.Option("to"), nfs.BINARY, path.Join(ice.USR_LOCAL_WORK, m.Option(mdb.NAME), ice.BIN_ICE_BIN))
cli.RUNTIME: {Hand: func(m *ice.Message, arg ...string) {
ProcessPodCmd(m, m.Option(mdb.NAME), "", nil, arg...)
}},
OPEN: {Role: aaa.VOID, Hand: func(m *ice.Message, arg ...string) {
if m.Option(mdb.TYPE) == ORIGIN && m.IsLocalhost() {
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(m.Option(mdb.NAME)))
}
"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))
}
}},
GRANT: {Hand: func(m *ice.Message, arg ...string) {
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) {
@ -432,34 +408,34 @@ func init() {
}
})
}},
TOKEN: {Hand: func(m *ice.Message, arg ...string) {
m.Options(m.Cmd(SPIDE, m.Option(mdb.NAME)).AppendSimple()).Cmdy(SPIDE, mdb.DEV_REQUEST)
}},
DREAM_TABLES: {Hand: func(m *ice.Message, arg ...string) {
if !aaa.IsTechOrRoot(m) {
m.PushButton(OPEN)
return
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")
}
}
list := []ice.Any{}
kit.If(m.IsDebug(), func() { list = append(list, cli.RUNTIME) })
switch m.Option(mdb.TYPE) {
case WORKER:
list = append(list, "settings", "copy", tcp.SEND)
case SERVER:
list = append(list, DREAM)
default:
list = append(list, TOKEN, DREAM)
}
list = append(list, OPEN)
m.PushButton(list...)
m.PushButton(append(button, OPEN)...)
}},
"settings": {Name: "settings restart=manual,always access=public,private", Help: "设置", 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))
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(), true); msg.Length() > 0 {
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], "", "已启动空间")
@ -467,50 +443,72 @@ func init() {
PushStats(m, kit.Keys(m.CommandKey(), ORIGIN), stat[ORIGIN], "", "已连接主机")
}
}},
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,icons,repos,binary,template,restart,access",
html.BUTTON, kit.JoinWord(PORTAL, DESKTOP, MESSAGE, ADMIN, WORD, STATUS, VIMER, COMPILE, XTERM, DREAM),
ctx.TOOLS, kit.Simple(SPIDE, ROUTE, STATUS), ONLINE, ice.TRUE,
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 {
simple := m.Option(ice.DREAM_SIMPLE) == ice.TRUE
if ice.Info.NodeType != WORKER {
_dream_list(m, simple)
_dream_list_icon(m)
if m.Length() == 0 {
m.EchoInfoButton(m.Trans("please create new dream", "请创建新空间"), mdb.CREATE).Action(mdb.CREATE)
return
}
if ice.Info.NodeType == WORKER {
return
}
if !m.IsCliUA() && aaa.IsTechOrRoot(m) {
_dream_list_more(m, simple)
} else {
msg := m.Spawn(kit.Dict(ice.MSG_USERROLE, aaa.TECH))
m.Cmds(SPACE).Table(func(value ice.Maps) {
if value[mdb.TYPE] == SERVER {
if p := ProxyDomain(msg, value[mdb.NAME]); p != "" {
value[mdb.TEXT] = p
m.PushRecord(value, mdb.TIME, mdb.TYPE, mdb.NAME, mdb.ICONS, nfs.MODULE, nfs.VERSION, mdb.TEXT)
}
}
})
}
if ice.Info.NodeType == WORKER || !aaa.IsTechOrRoot(m) || m.IsCliUA() {
_dream_list(m)
if _dream_list_more(m); !aaa.IsTechOrRoot(m) || m.IsCliUA() {
m.Action()
} else if m.IsDebug() && cli.SystemFindGo(m) {
m.Action(html.FILTER, mdb.CREATE, STARTALL, STOPALL, cli.BUILD, PUBLISH)
m.Action(mdb.CREATE, STARTALL, STOPALL, cli.BUILD, PUBLISH)
} else {
m.Action(html.FILTER, mdb.CREATE, STARTALL, STOPALL)
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)
ctx.DisplayTableCard(m)
kit.If(!aaa.IsTechOrRoot(m), func() { m.Options(ice.MSG_TOOLKIT, "", ice.MSG_ONLINE, ice.FALSE) })
kit.If(!m.IsDebug(), func() { m.Options(ice.MSG_TOOLKIT, "") })
} else if arg[0] == ctx.ACTION {
gdb.Event(m, DREAM_ACTION, arg)
} else {
mdb.HashSelects(m, arg[0]).PushAction(PORTAL, DESKTOP, ADMIN, OPEN, mdb.REMOVE)
m.Cmdy(arg[1], DREAM_ACTION, arg)
// gdb.Event(m, DREAM_ACTION, arg)
}
}},
})
@ -526,8 +524,9 @@ func DreamTablesAction(arg ...string) ice.Actions {
}
func DreamAction() ice.Actions {
return gdb.EventsAction(
DREAM_INPUTS, DREAM_CREATE, DREAM_REMOVE, DREAM_TRASH, DREAM_OPEN, DREAM_CLOSE, SPACE_LOGIN, SERVE_START,
OPS_DREAM_CREATE, OPS_DREAM_REMOVE,
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) {
@ -539,10 +538,13 @@ func DreamProcessIframe(m *ice.Message, arg ...string) {
return
}
if len(arg) == 2 {
defer m.Push(TITLE, kit.Keys(m.Option(mdb.NAME), m.ShortKey()))
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 {
return kit.MergeURL(S(kit.Keys(m.Option(ice.MSG_USERPOD), m.Option(mdb.NAME)))+C(m.ShortKey()), ice.MSG_DEBUG, m.Option(ice.MSG_DEBUG))
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) {

View File

@ -7,6 +7,7 @@ import (
)
const (
FAVICON = "favicon"
Mozilla = "Mozilla"
Firefox = "Firefox"
Safari = "Safari"
@ -40,18 +41,28 @@ const (
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"
@ -75,13 +86,15 @@ const (
PROFILE = "profile"
DISPLAY = "display"
VIEW = "view"
VALUE = "value"
INPUT = "input"
OUTPUT = "output"
LAYOUT = "layout"
RESIZE = "resize"
FILTER = "filter"
VIEW = "view"
VALUE = "value"
INPUT = "input"
ICON = "icon"
ICONS = "icons"
OUTPUT = "output"
LAYOUT = "layout"
RESIZE = "resize"
// FILTER = "filter"
REFRESH = "refresh"
CONFIRM = "confirm"

View File

@ -22,24 +22,15 @@ fieldset.web.matrix>div.output>table.content div.item div.status div.item:hover
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(--notice-bg-color) solid 3px; }
fieldset.web.matrix>div.output:not(.process)>table.content div.item.origin { border:var(--danger-bg-color) solid 3px; }
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 { background-color:var(--plugin-bg-color);
box-shadow:var(--box-shadow);
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 td:first-child:hover {
box-shadow:var(--notice-box-shadow);
}
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; }

View File

@ -1,8 +1,6 @@
package web
import (
"strings"
ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/aaa"
"shylinux.com/x/icebergs/base/cli"
@ -16,18 +14,18 @@ import (
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, 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)
vimer := kit.Select("", VIMER, istech && isdebug)
button := []ice.Any{PORTAL, DESKTOP, DREAM, ADMIN, OPEN, compile, MESSAGE}
kit.If(istech, func() { button = append(button, WORD, STATUS) })
kit.If(istech && isdebug, func() { button = append(button, vimer, cli.RUNTIME, XTERM) })
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, MESSAGE, ADMIN, OPEN, compile}
kit.If(istech, func() { button = append(button, WORD, STATUS) })
kit.If(istech && isdebug, func() { button = append(button, vimer, cli.RUNTIME, XTERM, cli.STOP) })
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:
@ -35,7 +33,7 @@ func _matrix_list(m *ice.Message, domain, typ string, value ice.Maps, fields ...
break
}
value[DOMAIN] = domain
kit.If(value[mdb.STATUS] == cli.STOP, func() { value[mdb.ICONS] = nfs.USR_ICONS_ICEBERGS })
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:
@ -81,6 +79,7 @@ func _matrix_action(m *ice.Message, action string, arg ...string) {
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)
}
@ -113,14 +112,14 @@ func init() {
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, aaa.TECH, mdb.ICONS, nfs.USR_ICONS_VOLCANOS, TARGET, kit.Keys(nfs.FROM, m.Option(mdb.NAME)))
m.Cmd(SPACE, m.Option(mdb.NAME), MESSAGE, mdb.CREATE, mdb.TYPE, aaa.TECH, mdb.ICONS, nfs.USR_ICONS_ICEBERGS, TARGET, kit.Keys(ice.OPS, m.Option(DOMAIN), m.Option(mdb.NAME)))
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(SPIDE, VERSION, STATUS), ONLINE, ice.TRUE,
cli.TIMEOUT, "10s",
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:]...)
@ -132,7 +131,7 @@ func init() {
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: ice.SRC_MAIN_ICO,
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),
@ -148,14 +147,18 @@ func init() {
}, field...)
})
m.RewriteAppend(func(value, key string, index int) string {
if key == mdb.ICONS && strings.HasPrefix(value, nfs.REQUIRE) {
if domain := m.Appendv(DOMAIN)[index]; domain != "" {
value = kit.MergeURL2(space[domain][mdb.TEXT], value, ice.POD, m.Appendv(mdb.NAME)[index])
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(html.FILTER, mdb.CREATE, UPGRADE).StatusTimeCountStats(mdb.TYPE, mdb.STATUS).Display("")
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

View File

@ -3,19 +3,30 @@ Volcanos(chat.ONIMPORT, {
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.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) })
can.onmotion.orderShow(can, can.page.SelectOne(can, can._output, "table>tbody"), "tr")
can.db.list = list, can.db.domain = domain, can.db.server = server
}), 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) {
@ -27,32 +38,38 @@ Volcanos(chat.ONIMPORT, {
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: can.misc.Resource(can, item.icons, can.core.Keys(item.domain, item.name)), onclick: cb(web.DESKTOP)},
{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),
{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][""]
return !worker? html.NOTICE: (worker.status != cli.STOP && item.status != cli.STOP && (item.version != worker.version || item.time < worker.time))? html.DANGER: ""
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, "process")
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, "process")
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, "process")
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) })
})

View File

@ -15,12 +15,15 @@ import (
)
func UserWeb(m *ice.Message) *url.URL {
return kit.ParseURL(m.Option(ice.MSG_USERWEB))
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 {
return m.Option(ice.MSG_USERHOST, u.Scheme+"://"+u.Host)
@ -47,6 +50,9 @@ func ParseLink(m *ice.Message, url string) ice.Maps {
return list
}
func PushPodCmd(m *ice.Message, cmd string, arg ...string) *ice.Message {
if m.IsWorker() {
return m
}
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]) })
@ -55,7 +61,7 @@ func PushPodCmd(m *ice.Message, cmd string, arg ...string) *ice.Message {
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(value[SPACE], val[SPACE])
val[SPACE] = kit.Keys(m.Option(ice.MSG_USERPOD), value[SPACE], val[SPACE])
m.Push("", val, head)
})
})
@ -91,7 +97,8 @@ func PushNoticeRich(m *ice.Message, arg ...ice.Any) {
PushNotice(m.StatusTimeCount(), kit.Simple("rich", arg))
}
func PushStream(m *ice.Message) *ice.Message {
m.Options(cli.CMD_OUTPUT, file.NewWriteCloser(func(buf []byte) { PushNoticeGrow(m, string(buf)) }, nil)).ProcessHold(toastContent(m, ice.SUCCESS))
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 }

View File

@ -38,7 +38,7 @@ func ProcessHashPodCmd(m *ice.Message, arg ...string) (msg *ice.Message) {
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(ctx.ACTION, m.ActionKey(), ctx.RUN, arg)
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
View 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))
}

View File

@ -71,10 +71,31 @@ func Render(m *ice.Message, cmd string, args ...ice.Any) bool {
}
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:
@ -134,7 +155,10 @@ func RenderMain(m *ice.Message) *ice.Message {
return m.RenderDownload(path.Join(ice.USR_INTSHELL, ice.INDEX_SH))
}
m.Options(nfs.SCRIPT, ice.SRC_MAIN_JS, nfs.VERSION, RenderVersion(m))
m.OptionDefault(mdb.ICONS, "/require/"+ice.Info.NodeIcon)
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 RenderCmds(m *ice.Message, cmds ...ice.Any) {
@ -144,28 +168,38 @@ func RenderPodCmd(m *ice.Message, pod, cmd string, arg ...ice.Any) {
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)))
}
}
func RenderCmd(m *ice.Message, cmd string, arg ...ice.Any) { RenderPodCmd(m, "", cmd, arg...) }
func RenderVersion(m *ice.Message) string {
if ice.Info.Make.Hash == "" {
return ""
}
ls := []string{ice.Info.Make.Version, ice.Info.Make.Forword, ice.Info.Make.Hash[:6]}
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)))
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)))...)
}
const (
PLAY = "play"
SHOW = "show"
CHAT = "chat"
WORD = "word"
VIMER = "vimer"
XTERM = "xterm"
GRANT = "grant"
OAUTH = "oauth"
DESKTOP = "desktop"
MESSAGE = "message"
@ -177,32 +211,41 @@ const (
UPGRADE = "upgrade"
INSTALL = "install"
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_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"
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) {

View File

@ -69,7 +69,7 @@ const ROUTE = "route"
func init() {
Index.MergeCommands(ice.Commands{
ROUTE: {Name: "route space:text cmds:text auto build travel diagram prunes", Help: "路由表", Actions: ice.MergeActions(ice.Actions{
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] {

View File

@ -1,8 +1,10 @@
package web
import (
"io/ioutil"
"net/http"
"net/url"
"os"
"path"
"regexp"
"runtime"
@ -26,24 +28,31 @@ import (
func _serve_address(m *ice.Message) string { return HostPort(m, tcp.LOCALHOST, m.Option(tcp.PORT)) }
func _serve_start(m *ice.Message) {
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(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)) })
cli.NodeInfo(m, kit.Select(kit.Split(ice.Info.Hostname, nfs.PT)[0], m.Option(tcp.NODENAME)), SERVER, mdb.Config(m, mdb.ICONS))
m.Go(func() {
m.Cmd(SPIDE, ice.OPS, _serve_address(m)+"/exit", ice.Maps{CLIENT_TIMEOUT: cli.TIME_30ms, ice.LOG_DISABLE: ice.TRUE})
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)...)
m.Cmd(nfs.SAVE, ice.VAR_LOG_ICE_PORT, m.Option(tcp.PORT))
if m.Cmd(tcp.HOST).Length() == 0 {
return
}
kit.For(kit.Split(m.Option(ice.DEV)), func(dev string) {
if m.Cmds(SPIDE, dev).Append(TOKEN) == "" {
m.Sleep30ms(SPACE, tcp.DIAL, ice.DEV, dev, mdb.NAME, ice.Info.NodeName, m.OptionSimple(TOKEN))
}
})
}
func _serve_main(m *ice.Message, w http.ResponseWriter, r *http.Request) bool {
const (
@ -56,6 +65,10 @@ func _serve_main(m *ice.Message, w http.ResponseWriter, r *http.Request) bool {
} 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+nfs.DF+r.Header.Get(X_REAL_PORT))
@ -77,6 +90,7 @@ func _serve_main(m *ice.Message, w http.ResponseWriter, r *http.Request) bool {
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
}
@ -87,12 +101,48 @@ func _serve_main(m *ice.Message, w http.ResponseWriter, r *http.Request) bool {
return true
}
func _serve_static(msg *ice.Message, w http.ResponseWriter, r *http.Request) bool {
if p := path.Join(kit.Select(ice.USR_VOLCANOS, ice.USR_INTSHELL, msg.IsCliUA()), r.URL.Path); nfs.Exists(msg, p) {
// _serve_params(msg, r.Header.Get(html.Referer))
if strings.HasPrefix(r.URL.Path, "/.git/") {
return false
}
_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)
} else 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) {
ispod := kit.Contains(r.URL.String(), S(), "pod=") || kit.Contains(r.Header.Get(html.Referer), S(), "pod=")
}
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)
@ -100,6 +150,19 @@ func _serve_static(msg *ice.Message, w http.ResponseWriter, r *http.Request) boo
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))
@ -110,25 +173,16 @@ func _serve_handle(key string, cmd *ice.Command, m *ice.Message, w http.Response
return m
}
kit.If(r.Header.Get(html.Referer), func(p string) { _log("page", html.Referer, p) })
if u, e := url.Parse(r.Header.Get(html.Referer)); e == nil {
add := func(k, v string) { _log(nfs.PATH, k, m.Option(k, v)) }
switch arg := strings.Split(strings.TrimPrefix(u.Path, nfs.PS), nfs.PS); arg[0] {
case CHAT:
kit.For(arg[1:], func(k, v string) { add(k, v) })
case SHARE:
add(arg[0], arg[1])
case "s":
add(ice.POD, kit.Select("", arg, 1))
}
kit.For(u.Query(), func(k string, v []string) { m.Optionv(k, v) })
}
kit.For(kit.ParseQuery(r.URL.RawQuery), func(k string, v []string) { m.Optionv(k, v) })
_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:
kit.For(kit.UnMarshal(r.Body), func(k string, v ice.Any) { m.Optionv(k, v) })
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) })
@ -143,6 +197,10 @@ func _serve_handle(key string, cmd *ice.Command, m *ice.Message, w http.Response
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 {
@ -160,6 +218,20 @@ func _serve_handle(key string, cmd *ice.Command, m *ice.Message, w http.Response
} 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++
}
}()
}
}
func _serve_domain(m *ice.Message) string {
@ -177,12 +249,15 @@ func _serve_domain(m *ice.Message) string {
}
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
}
defer func() { m.Options(ice.MSG_CMDS, "") }()
if aaa.SessCheck(m, m.Option(ice.MSG_SESSID)); m.Option(ice.MSG_USERNAME) == "" {
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
@ -207,63 +282,66 @@ const (
BODY = "body"
HOME = "home"
OPS_SERVER_OPEN = "ops.server.open"
SERVE_START = "serve.start"
PROXY_CONF = "proxyConf"
PROXY_PATH = "usr/local/daemon/10000/"
PROXY_CMDS = "./sbin/nginx"
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{P(ice.EXIT): {Hand: func(m *ice.Message, arg ...string) { m.Cmd(ice.EXIT) }},
SERVE: {Name: "serve name auto main host system", Help: "服务器", Actions: ice.MergeActions(ice.Actions{
ice.MAIN: {Name: "main index", Help: "首页", Hand: func(m *ice.Message, arg ...string) {
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 {
} 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) {
Count(m, m.ActionKey(), m.Option(tcp.PORT))
m.Cmd(SPIDE, mdb.CREATE, HostPort(m, "localhost", m.Option(tcp.PORT)), ice.OPS, nfs.USR_ICONS_CONTEXTS, nfs.REPOS, "")
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)
})
})
kit.If(m.Option(ice.DEMO) == ice.TRUE, func() { m.Cmd(CHAT_HEADER, ice.DEMO) })
switch cb := m.Optionv(SERVE_START).(type) {
case func():
Count(m, m.ActionKey(), m.Option(tcp.PORT))
if cb, ok := m.Optionv(SERVE_START).(func()); ok {
cb()
}
m.Go(func() {
cli.Opens(m, mdb.Config(m, cli.OPEN))
ssh.PrintQRCode(m, tcp.PublishLocalhost(m, _serve_address(m)))
})
if runtime.GOOS == cli.LINUX {
m.Cmd("", PROXY_CONF, ice.Info.NodeName)
}
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, "9020"); nfs.Exists(m, dir) {
for _, p := range []string{"server.conf", "location.conf", "upstream.conf"} {
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)
}
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")
}
}},
}, gdb.EventsAction(SERVE_START), mdb.HashAction(
mdb.ICONS, ice.SRC_MAIN_ICO,
mdb.SHORT, mdb.NAME, mdb.FIELD, "time,status,name,proto,host,port"), mdb.ClearOnExitHashAction()), Hand: func(m *ice.Message, arg ...string) {
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)))
}},
})
@ -292,6 +370,22 @@ func ServeCmdAction() ice.Actions {
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))
@ -315,13 +409,16 @@ func ParseUA(m *ice.Message) (res []string) {
func ProxyDomain(m *ice.Message, name string) (domain string) {
p := path.Join(PROXY_PATH, "conf/portal", name, "server.conf")
if !nfs.Exists(m, p) {
return ""
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] }) })
if domain != "" {
return "https://" + domain
}
return
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...))
@ -330,10 +427,10 @@ 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) {
if strings.HasPrefix(file, nfs.PS) || strings.HasPrefix(file, ice.HTTP) || strings.Contains(file, "://") {
return file
} else if file != "" {
return nfs.REQUIRE + file
return nfs.P + file
}
return ""
}

View File

@ -70,7 +70,7 @@ const SHARE = "share"
func init() {
Index.MergeCommands(ice.Commands{
SHARE: {Name: "share hash auto login", Help: "共享链", Role: aaa.VOID, Actions: ice.MergeActions(ice.Actions{
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))
@ -91,7 +91,8 @@ func init() {
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), 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)))
}
}},
nfs.PS: {Hand: func(m *ice.Message, arg ...string) {
@ -118,7 +119,11 @@ func init() {
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:
RenderPodCmd(m, msg.Append(SPACE), msg.Append(mdb.NAME), kit.UnMarshal(msg.Append(mdb.TEXT)))
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:
@ -150,7 +155,7 @@ func IsNotValidFieldShare(m *ice.Message, msg *ice.Message) bool {
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.REQUIRE, p), ice.POD, m.Option(ice.MSG_USERPOD))
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))
}
@ -165,18 +170,39 @@ func ShareLocalFile(m *ice.Message, arg ...string) {
return
}
default:
if m.Option(ice.POD) == "" && !aaa.Right(m, ls) {
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) == "" || (strings.HasPrefix(p, ice.USR_ICONS) && nfs.Exists(m, p)) {
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, kit.Select("", kit.Split(m.Option(ice.POD), nfs.PT), -1), p); nfs.Exists(m, pp) {
} 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 if pp := kit.Path(ice.USR_LOCAL_WORK, m.Option(ice.POD)); nfs.Exists(m, pp) {
m.RenderDownload(p)
} else {
m.RenderDownload(ProxyUpload(m, m.Option(ice.POD), p))
m.RenderDownload(p)
}
}
func ShareLocal(m *ice.Message, p string) string {
@ -197,13 +223,13 @@ func ProxyUpload(m *ice.Message, pod string, p string) string {
size, cache = s.Size(), s.ModTime()
}
if m.Cmdv(SPACE, pod, mdb.TYPE) == ORIGIN {
m.Cmd(SPIDE, pod, SPIDE_SAVE, pp, p)
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)
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))
}

View File

@ -1,6 +1,7 @@
package web
import (
"io"
"math/rand"
"net"
"path"
@ -22,15 +23,34 @@ import (
"shylinux.com/x/icebergs/base/web/html"
"shylinux.com/x/icebergs/misc/websocket"
kit "shylinux.com/x/toolkits"
"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) {
origin := m.Cmdv(SPIDE, dev, CLIENT_ORIGIN)
u := kit.ParseURL(kit.MergeURL2(strings.Replace(origin, HTTP, "ws", 1), PP(SPACE), mdb.TYPE, ice.Info.NodeType, mdb.NAME, name, mdb.NAME, "", mdb.ICONS, ice.Info.NodeIcon,
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))
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{}
@ -40,12 +60,16 @@ func _space_dial(m *ice.Message, dev, name string, arg ...string) {
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 c, e := websocket.NewClient(c, u); !m.WarnNotValid(e, tcp.DIAL, dev, SPACE, u.String()) {
defer mdb.HashCreateDeferRemove(m, kit.SimpleKV("", ORIGIN, dev, origin), kit.Dict(mdb.TARGET, c))()
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(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))
}
@ -74,15 +98,14 @@ func _space_fork(m *ice.Message) {
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)
}
}
if m.Option(mdb.ICONS) != "" && !kit.HasPrefix(m.Option(mdb.ICONS), nfs.PS, HTTP) {
m.Option(mdb.ICONS, kit.MergeURL("/require/"+m.Option(mdb.ICONS), ice.POD, name))
}
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))
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() {
@ -95,22 +118,23 @@ func _space_fork(m *ice.Message) {
gdb.Event(m, SPACE_LOGIN, args)
defer gdb.Event(m, SPACE_LOGIN_CLOSE, args)
case PORTAL:
defer gdb.EventDeferEvent(m, PORTAL_OPEN, args)(PORTAL_CLOSE, args)
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)
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() {
m.Cmd(SPACE, name, cli.PWD, name, kit.Dict(
mdb.ICONS, ice.Info.NodeIcon, mdb.TIME, ice.Info.Make.Time, nfs.MODULE, ice.Info.Make.Module, nfs.VERSION, ice.Info.Make.Versions(),
AGENT, "Go-http-client", cli.SYSTEM, runtime.GOOS,
))
SpaceEvent(m, OPS_SERVER_OPEN, name, args...)
SpacePwd(m, name, "")
SpaceEvent(m.Spawn(ice.MSG_USERROLE, aaa.TECH), OPS_SERVER_OPEN, name, args...)
})
}
_space_handle(m, safe, name, c)
_space_handle(m.Spawn(), safe, name, c)
}, kit.JoinWord(SPACE, name))
}
}
@ -122,15 +146,23 @@ func _space_handle(m *ice.Message, safe bool, name string, c *websocket.Conn) {
if e != nil {
break
}
func() {
defer InfoLock.Lock()()
Info.SpaceReadCount++
Info.SpaceReadByte += len(b)
}()
msg := m.Spawn(b)
if safe && msg.Option(ice.MSG_UNSAFE) != ice.TRUE { // 下行权限
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))) })
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(tcp.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 {
msg.Go(func() {
if k := kit.Keys(msg.Option(ice.MSG_USERPOD), "_token"); msg.Option(k) != "" {
@ -155,6 +187,12 @@ func _space_handle(m *ice.Message, safe bool, name string, c *websocket.Conn) {
}), SPACE, next) {
break
}
if kit.HasPrefixList(msg.Detailv(), "toast") {
break
}
if msg.Option("space.noecho") == "true" {
break
}
m.Sleep3s()
}
}
@ -175,22 +213,31 @@ func _space_domain(m *ice.Message) (link string) {
)
}
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:
if m.Option(mdb.ICONS) != "" && !kit.HasPrefix(m.Option(mdb.ICONS), nfs.PS, HTTP) {
m.Option(mdb.ICONS, kit.MergeURL2(SpideOrigin(m, name), "/require/"+m.Option(mdb.ICONS)))
}
mdb.HashModify(m, mdb.HASH, name, ParseUA(m), m.OptionSimple(mdb.ICONS, mdb.TIME, nfs.MODULE, nfs.VERSION, AGENT, cli.SYSTEM))
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
}
m.OptionDefault(ice.MSG_COUNT, "0")
m.Option(ice.MSG_ARGS, "")
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))
@ -199,19 +246,26 @@ func _space_exec(m *ice.Message, name string, source, target []string, c *websoc
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))) })
}
m.Option(ice.MSG_HANDLE, ice.TRUE)
defer m.Cost(kit.Format("%v->%v %v %v", source, target, m.Detailv(), m.FormatSize()))
if m.Option(ice.SPACE_NOECHO) == ice.TRUE {
return
}
defer m.Cost(kit.Format("%v->%v %v %v", source, target, m.Detailv(), m.FormatSize()))
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()) }()
if m.Options(ice.MSG_SOURCE, source, ice.MSG_TARGET, target[1:]); !m.WarnNotValid(c.WriteMessage(1, []byte(m.FormatMeta()))) {
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.ECHO, m.Option(ice.MSG_HANDLE) == ice.TRUE), "%v->%v %v %v", source, target, kit.ReplaceAll(kit.Format("%v", m.Detailv()), "\r\n", "\\r\\n", "\t", "\\t", "\n", "\\n"), m.FormatMeta())
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)
}
}
}
@ -227,7 +281,7 @@ func _space_send(m *ice.Message, name string, arg ...string) (h string) {
}
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, func() {
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)
@ -267,6 +321,11 @@ const (
AGENT = "agent"
)
const (
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_LOGIN = "space.login"
SPACE_LOGIN_CLOSE = "space.login.close"
SPACE_GRANT = "space.grant"
@ -279,18 +338,53 @@ const SPACE = "space"
func init() {
Index.MergeCommands(ice.Commands{
"s": {Help: "空间", Actions: ApiWhiteAction(), Hand: func(m *ice.Message, arg ...string) { m.Cmdy(CHAT_POD, arg) }},
"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) { aaa.White(m, SPACE, ice.MAIN) }},
mdb.ICONS: {Hand: func(m *ice.Message, arg ...string) { cli.NodeInfo(m, ice.Info.Pathname, WORKER, arg[0]) }},
ice.MAIN: {Name: "main index", Help: "首页", Hand: func(m *ice.Message, arg ...string) {
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 {
mdb.Config(m, ice.MAIN, m.Option(ctx.INDEX))
ice.Info.NodeMain = m.Option(ctx.INDEX)
m.Cmd(SERVE, m.ActionKey(), arg)
return
}
kit.If(mdb.Config(m, ice.MAIN), func(cmd string) { RenderPodCmd(m, "", cmd) }, func() { RenderMain(m) })
m.Optionv(ice.MSG_ARGS, kit.Simple(m.Optionv(ice.MSG_ARGS)))
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)
@ -298,6 +392,8 @@ func init() {
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) {
@ -314,17 +410,21 @@ func init() {
}},
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), HTTP) {
m.Cmd(SPIDE, mdb.CREATE, m.Option(ice.DEV), 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 ToastProcess(m)()
mdb.HashModify(m, m.OptionSimple(mdb.NAME), mdb.STATUS, cli.STOP)
m.Cmd("", m.Option(mdb.NAME), ice.EXIT).Sleep3s()
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.Cmd("", m.Option(mdb.NAME), ice.EXIT).Sleep3s()
}
}},
DOMAIN: {Hand: func(m *ice.Message, arg ...string) { m.Echo(_space_domain(m)) }},
LOGIN: {Help: "授权", Hand: func(m *ice.Message, arg ...string) {
@ -345,8 +445,8 @@ func init() {
}},
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,icons,module,version,agent,system,ip,usernick,username,userrole",
ctx.ACTION, OPEN, REDIAL, kit.Dict("a", 1000, "b", 100, "c", 1000), mdb.ICONS, ice.SRC_MAIN_ICO,
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 {
if len(arg) == 1 && strings.Contains(arg[0], nfs.PT) {
@ -371,12 +471,38 @@ func init() {
}
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 {
if kit.IsIn(arg[0], "", ice.CONTEXTS) {
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
@ -401,19 +527,30 @@ func init() {
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_REG, kit.ExtReg(nfs.PNG, nfs.JPG, nfs.JPEG), nfs.DIR_DEEP, ice.TRUE)
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)
m.Cmdy(nfs.DIR, ice.USR_LOCAL_IMAGE, nfs.PATH)
m.Cmdy(nfs.DIR, ice.USR_ICONS, 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 != "" {
m.Options(SPACE, []string{}).Cmdy(SPACE, space, ctx.COMMAND)
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)
}
@ -425,20 +562,11 @@ func init() {
} else {
m.Cmdy(ctx.COMMAND, mdb.INPUTS, m.Option(ctx.INDEX))
}
case aaa.TO:
if m.Option(ctx.ACTION) != aaa.EMAIL {
break
}
fallthrough
case aaa.EMAIL:
m.Push(arg[0], "shy@shylinux.com", "shylinux@163.com")
case aaa.PASSWORD:
m.SetAppend()
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":
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])
@ -451,7 +579,7 @@ func init() {
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.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
@ -476,10 +604,20 @@ func PodCmd(m *ice.Message, key string, arg ...string) bool {
func SpaceName(name string) string {
return kit.ReplaceAll(name, nfs.DF, "_", nfs.PS, "_", nfs.PT, "_", "[", "_", "]", "_")
}
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))
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))

View File

@ -40,7 +40,7 @@ func _spide_create(m *ice.Message, link, types, name, icons, token string) {
}
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)
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)
@ -91,7 +91,7 @@ func _spide_show(m *ice.Message, name string, arg ...string) {
}
})
})
if m.WarnNotValid(res.StatusCode != http.StatusOK && res.StatusCode != http.StatusCreated, uri, cli.STATUS, res.Status) {
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
@ -113,8 +113,9 @@ func _spide_body(m *ice.Message, method string, arg ...string) (io.Reader, ice.M
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) })
// 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:
@ -201,13 +202,31 @@ func _spide_save(m *ice.Message, action, file, uri string, res *http.Response) {
case SPIDE_MSG:
var data map[string][]string
m.Assert(json.NewDecoder(res.Body).Decode(&data))
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(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.WarnNotFound(e) {
@ -226,6 +245,7 @@ const (
SPIDE_MSG = "msg"
SPIDE_SAVE = "save"
SPIDE_CACHE = "cache"
SPIDE_STREAM = "stream"
SPIDE_BODY = "body"
SPIDE_FORM = "form"
@ -279,20 +299,23 @@ 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: {Help: "蜘蛛侠", Meta: kit.Dict(ice.CTX_TRANS, kit.Dict(html.INPUT, kit.Dict(
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 := mdb.Confm(m, cli.RUNTIME, cli.CONF)
dev := kit.Select("https://2021.shylinux.com", ice.Info.Make.Domain, conf[cli.CTX_DEV])
m.Cmd("", mdb.CREATE, kit.Select("https://shylinux.com", conf[cli.CTX_SHY]), ice.SHY, "", nfs.REPOS)
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)
m.Cmd("", mdb.CREATE, kit.Select("http://localhost:9020", conf[cli.CTX_OPS]), ice.OPS, nfs.USR_ICONS_CONTEXTS, nfs.REPOS)
m.Cmd("", mdb.CREATE, kit.Select("http://localhost:20000", conf[cli.CTX_DEMO]), ice.DEMO, nfs.USR_ICONS_VOLCANOS)
m.Cmd("", mdb.CREATE, kit.Select("https://mail.shylinux.com", conf[cli.CTX_MAIL]), ice.MAIL, "usr/icons/Mail.png")
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.SEARCH: {Hand: func(m *ice.Message, arg ...string) {
if mdb.IsSearchPreview(m, arg) {
@ -322,30 +345,31 @@ func init() {
default:
switch arg[0] {
case mdb.NAME, mdb.ICONS:
m.SplitIndex(m.Cmdx(SPIDE, ice.DEV, kit.MergeURL2(m.Option(ORIGIN), C(SPACE, "info")))).Cut(arg[0])
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.NAME) == "" && m.Option(mdb.ICONS) == "" {
msg := m.Spawn().SplitIndex(m.Cmdx(SPIDE, ice.DEV, kit.MergeURL2(m.Option(ORIGIN), C(SPACE, "info"))))
m.Option(mdb.ICONS, m.Resource(msg.Append(mdb.ICONS), msg.Append(ORIGIN)))
m.Option(mdb.NAME, msg.Append(mdb.NAME))
m.OptionDefault(mdb.TYPE, nfs.REPOS)
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.Warn(e != nil || u.Host == "", ice.ErrNotValid, m.Option(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))
}
_spide_create(m, m.Option(ORIGIN), m.Option(mdb.TYPE), m.Option(mdb.NAME), m.OptionDefault(mdb.ICONS, nfs.USR_ICONS_VOLCANOS), 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))
@ -359,26 +383,23 @@ func init() {
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", Hand: func(m *ice.Message, arg ...string) {
"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_REQUEST_TEXT: {Hand: func(m *ice.Message, arg ...string) { m.Echo(SpaceName(ice.Info.NodeName)) }},
DEV_CREATE_TOKEN: {Hand: func(m *ice.Message, arg ...string) {
m.Cmd(SPACE, tcp.DIAL, ice.DEV, m.Option(CLIENT_NAME), m.OptionSimple(TOKEN)).Sleep300ms()
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] == "") {
list := m.CmdMap(SPACE, mdb.NAME)
mdb.HashSelect(m, kit.Slice(arg, 0, 1)...).Sort("client.type,client.name", []string{nfs.REPOS, ""})
m.RewriteAppend(func(value, key string, index int) string {
kit.If(key == CLIENT_URL, func() { value = kit.MergeURL(value, m.OptionSimple(ice.MSG_DEBUG)) })
return value
})
m.Table(func(value ice.Maps) {
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("disconn", mdb.DEV_REQUEST, mdb.REMOVE)
m.Push(mdb.STATUS, ONLINE).PushButton(mdb.DEV_REQUEST, "disconn", mdb.REMOVE)
} else {
m.Push(mdb.STATUS, "").PushButton(mdb.DEV_REQUEST, mdb.REMOVE)
}
@ -387,30 +408,40 @@ func init() {
}
})
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:]...)
}
}},
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, path.Base(p)), m.Option("_template")); kit.HasPrefix(p, "/require/", ice.HTTP) {
return m.Cmdx(SPIDE, ice.OPS, SPIDE_RAW, http.MethodGet, p)
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 {
} 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 {
@ -418,8 +449,8 @@ func init() {
return p + kit.Select("", nfs.PS, len(arg) == 0)
} else {
p := m.FileURI(ctx.GetCmdFile(m, m.PrefixKey()))
if p := strings.TrimPrefix(path.Join(path.Dir(p), path.Join(arg...)), "/require/"); nfs.Exists(m, p) {
return p
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...))
@ -435,7 +466,7 @@ func init() {
}
}
nfs.DocumentText = func(m *ice.Message, p string) string {
if p := nfs.DocumentPath(m, path.Base(p)); kit.HasPrefix(p, "/require/", ice.HTTP) {
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)
@ -443,27 +474,6 @@ func init() {
}
}
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() { host = kit.ParseURL(UserHost(m)).Hostname() })
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
}
}
func PublicIP(m *ice.Message) ice.Any {
return SpideGet(m, "http://ip-api.com/json")
}
func SpideGet(m *ice.Message, arg ...ice.Any) ice.Any {
return kit.UnMarshal(m.Cmdx(http.MethodGet, arg))
}
@ -476,6 +486,9 @@ 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 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)
@ -485,8 +498,47 @@ func SpideSave(m *ice.Message, file, link string, cb func(count, total, value in
}
return m
}
func SpideCache(m *ice.Message, link string) *ice.Message {
return m.Cmd(Prefix(SPIDE), ice.DEV_IP, SPIDE_CACHE, http.MethodGet, link)
}
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
}
}

View File

@ -1,5 +1,7 @@
/* fieldset.web.store>div.output>div.project { width:160px; flex:0 0 160px; } */
fieldset.web.store>div.output>div.project div.list { margin-left:25px; border-left:var(--notice-bg-color) solid 3px; }
fieldset.web.store>div.output>div.layout>div.layout>div.content>div.item div.title div.label { font-size:var(--status-font-size); font-weight:normal; margin-top:var(--input-margin); }
fieldset.web.store>div.output>div.layout>div.layout>div.content>div.item div.title div.label span { padding:var(--input-padding); padding-right:var(--input-margin); }
fieldset.web.store>div.output>div.layout>div.layout>div.content>div.item div.content { height:70px; }
$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; }

View File

@ -1,8 +1,6 @@
package web
import (
"strings"
ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/aaa"
"shylinux.com/x/icebergs/base/cli"
@ -10,7 +8,6 @@ import (
"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"
)
@ -18,21 +15,35 @@ const STORE = "store"
func init() {
Index.MergeCommands(ice.Commands{
STORE: {Name: "store refresh", Help: "商店", Role: aaa.VOID, Actions: ice.MergeActions(ice.Actions{
mdb.INPUTS: {Hand: func(m *ice.Message, arg ...string) { m.Cmdy(SPIDE, mdb.INPUTS, arg) }},
STORE: {Name: "store refresh", Help: "商店", Icon: "App Store.png", Role: aaa.VOID, Actions: ice.MergeActions(ice.Actions{
ice.AFTER_INIT: {Hand: func(m *ice.Message, arg ...string) {
AddPortalProduct(m, "云商店", `
每个用户都可以将自己的空间列表以系统商店的方式分享给其它用户
同样的每个用户也可以添加任意多个商店直接将空间下载到本机使用
`, 300.0)
}},
mdb.INPUTS: {Hand: func(m *ice.Message, arg ...string) {
switch arg[0] {
case ORIGIN:
m.Cmd(BROAD).Table(func(value ice.Maps) {
m.Push(arg[0], HostPort(m, value[tcp.HOST], value[tcp.PORT]))
})
}
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"), mdb.TYPE, nfs.REPOS)
}},
mdb.REMOVE: {Hand: func(m *ice.Message, arg ...string) {
m.Cmd(SPIDE, mdb.REMOVE, CLIENT_NAME, m.Option(mdb.NAME))
}},
INSTALL: {Hand: func(m *ice.Message, arg ...string) {
tcp.DIAL: {Hand: func(m *ice.Message, arg ...string) {
m.Options(m.Cmd(SPIDE, m.Option(mdb.NAME)).AppendSimple())
m.Cmdy(SPIDE, mdb.DEV_REQUEST)
}},
INSTALL: {Name: "install name*", Hand: func(m *ice.Message, arg ...string) {
if !kit.HasPrefixList(arg, ctx.RUN) {
if strings.HasPrefix(m.Option(mdb.ICON), nfs.REQUIRE) {
m.Option(mdb.ICON, strings.TrimSuffix(strings.TrimPrefix(m.Option(mdb.ICON), nfs.REQUIRE), "?pod="+m.Option(mdb.NAME)))
}
m.OptionDefault(nfs.BINARY, m.Option(ORIGIN)+S(m.Option(mdb.NAME)))
m.Cmdy(DREAM, mdb.CREATE, m.OptionSimple(mdb.NAME, mdb.ICON, nfs.REPOS, nfs.BINARY))
m.Cmdy(DREAM, mdb.CREATE, m.OptionSimple(mdb.NAME, nfs.REPOS, nfs.BINARY))
m.Cmdy(DREAM, cli.START, m.OptionSimple(mdb.NAME))
}
ProcessIframe(m, m.Option(mdb.NAME), S(m.Option(mdb.NAME)), arg...)
@ -40,30 +51,33 @@ func init() {
PORTAL: {Role: aaa.VOID, Hand: func(m *ice.Message, arg ...string) {
ProcessIframe(m, m.Option(mdb.NAME), m.Option(ORIGIN)+S(m.Option(mdb.NAME))+C(m.ActionKey()), arg...)
}},
DESKTOP: {Role: aaa.VOID, Hand: func(m *ice.Message, arg ...string) {
ProcessIframe(m, kit.Keys(m.Option(mdb.NAME), m.ActionKey()), S(m.Option(mdb.NAME))+C(m.ActionKey()), arg...)
OPEN: {Hand: func(m *ice.Message, arg ...string) {
if m.Option(mdb.TYPE) == ORIGIN {
m.ProcessOpen(m.Option(ORIGIN))
} else {
m.ProcessOpen(S(m.Option(mdb.NAME)))
}
}},
ADMIN: {Role: aaa.VOID, Hand: func(m *ice.Message, arg ...string) {
ProcessIframe(m, kit.Keys(m.Option(mdb.NAME), m.ActionKey()), S(m.Option(mdb.NAME))+C(m.ActionKey()), arg...)
}},
OPEN: {Hand: func(m *ice.Message, arg ...string) { m.ProcessOpen(S(m.Option(mdb.NAME))) }},
}, ctx.ConfAction(CLIENT_TIMEOUT, cli.TIME_3s), DREAM), Hand: func(m *ice.Message, arg ...string) {
if kit.HasPrefixList(arg, ctx.ACTION) {
m.Cmdy(DREAM, arg)
return
}
if m.Display(""); len(arg) == 0 {
list := []string{}
} else if m.Display("").DisplayCSS(""); len(arg) == 0 {
list := m.Spawn(ice.Maps{ice.MSG_FIELDS: ""}).CmdMap(SPACE, mdb.NAME)
m.Cmd(SPIDE, arg, kit.Dict(ice.MSG_FIELDS, "time,icons,client.type,client.name,client.origin")).Table(func(value ice.Maps) {
kit.If(value[CLIENT_TYPE] == nfs.REPOS, func() {
list = append(list, value[CLIENT_NAME])
m.Push(mdb.NAME, value[CLIENT_NAME]).Push(mdb.ICONS, value[mdb.ICONS]).Push(ORIGIN, value[CLIENT_ORIGIN])
kit.If(value[CLIENT_TYPE] == nfs.REPOS && value[CLIENT_NAME] != ice.SHY, func() {
kit.If(value[CLIENT_NAME] == ice.OPS, func() { value[CLIENT_ORIGIN] = UserHost(m) })
m.Push(mdb.TYPE, ORIGIN).Push(mdb.NAME, value[CLIENT_NAME]).Push(mdb.ICONS, value[mdb.ICONS]).Push(ORIGIN, value[CLIENT_ORIGIN])
if _, ok := list[value[CLIENT_NAME]]; ok || kit.IsIn(value[CLIENT_NAME], ice.OPS, ice.DEV) {
m.Push(mdb.STATUS, ice.TRUE)
} else {
m.Push(mdb.STATUS, ice.FALSE)
}
})
})
if ice.Info.NodeType == WORKER || !aaa.IsTechOrRoot(m) {
if m.SortStrR(mdb.NAME); ice.Info.NodeType == WORKER || !aaa.IsTechOrRoot(m) {
m.Action()
} else {
m.PushAction(mdb.REMOVE).Action(html.FILTER, mdb.CREATE)
m.PushAction(OPEN, tcp.DIAL, mdb.REMOVE).Action(mdb.CREATE)
}
} else {
defer ToastProcess(m, ice.LIST, arg[0])()
@ -74,29 +88,41 @@ func init() {
dream := C(DREAM)
origin := SpideOrigin(m, arg[0])
kit.If(origin == "", func() { arg[0], origin, dream = ice.DEV, arg[0], arg[0]+dream })
if kit.IsIn(kit.ParseURL(origin).Hostname(), append(m.Cmds(tcp.HOST).Appendv(aaa.IP), tcp.LOCALHOST)...) {
origin = m.Option(ice.MSG_USERHOST)
} else {
origin = tcp.PublishLocalhost(m, origin)
}
list := m.Spawn(ice.Maps{ice.MSG_FIELDS: ""}).CmdMap(DREAM, mdb.NAME)
// if kit.IsIn(kit.ParseURL(origin).Hostname(), append(m.Cmds(tcp.HOST).Appendv(aaa.IP), tcp.LOCALHOST)...) {
// if kit.IsIn(kit.ParseURL(origin).Hostname(), tcp.LOCALHOST) {
// origin = m.Option(ice.MSG_USERHOST)
// } else {
// origin = tcp.PublishLocalhost(m, origin)
// }
// origin = tcp.PublishLocalhost(m, origin)
stat := map[string]int{}
list := m.Spawn(ice.Maps{ice.MSG_FIELDS: ""}).CmdMap(SPACE, mdb.NAME)
m.SetAppend().Spawn().SplitIndex(m.Cmdx(SPIDE, arg[0], dream, kit.Dict(mdb.ConfigSimple(m, CLIENT_TIMEOUT)))).Table(func(value ice.Maps) {
if value[mdb.TYPE] == ORIGIN {
return
}
stat[value[mdb.TYPE]]++
if value[nfs.BINARY] == "" {
value[nfs.BINARY] = origin + S(value[mdb.NAME])
}
m.Push("", value, kit.Split("time,type,name,icons,repos,binary,module,version"))
if _, ok := list[value[mdb.NAME]]; ok {
m.Push(mdb.STATUS, ice.TRUE)
} else {
m.Push(mdb.STATUS, ice.FALSE)
}
if value[mdb.TYPE] == SERVER {
m.Push(mdb.TEXT, value[mdb.TEXT]).Push(ORIGIN, value[mdb.TEXT])
m.PushButton()
m.Push(mdb.TEXT, value[mdb.TEXT]).Push(ORIGIN, value[mdb.TEXT]).PushButton()
return
}
m.Push(mdb.TEXT, value[nfs.REPOS]).Push(ORIGIN, origin)
if _, ok := list[value[mdb.NAME]]; ok || arg[0] == ice.OPS {
m.PushButton(PORTAL, DESKTOP, ADMIN, OPEN)
} else if ice.Info.NodeType == WORKER || !aaa.IsTechOrRoot(m) {
m.PushButton(PORTAL)
} else {
m.PushButton(PORTAL, INSTALL)
button := []ice.Any{PORTAL}
if _, ok := list[value[mdb.NAME]]; ok {
button = append(button, OPEN)
} else if aaa.IsTechOrRoot(m) {
button = append(button, INSTALL)
}
m.PushButton(button...)
})
m.StatusTimeCount(ORIGIN, origin, stat)
}

View File

@ -1,26 +1,27 @@
Volcanos(chat.ONIMPORT, {
_init: function(can, msg) { can.ui = can.onappend.layout(can), can.onimport._project(can, msg) },
_project: function(can, msg) { var select, current = can.sup.db._zone||can.db.hash[0]||(can.user.info.nodetype == web.WORKER? ice.OPS: ice.DEV)
msg.Table(function(value) {
var _target = can.onimport.item(can, value, function(event, value) {
can.onimport.dream(event, can, value, _target)
}, null, can.ui.project); select = (value.name == current? _target: select)||_target
}), select && select.click(), can.onmotion.orderShow(can, can.ui.project)
can.onappend.style(can, "output card", can.ui.content), can.onmotion.delay(can, function() { can.onimport.layout(can) })
_init: function(can, msg, cb) {
can.db.hash[0] = can.db.hash[0]||(can.user.info.nodetype == web.WORKER? ice.OPS: ice.DEV)
can.ui = can.onappend.layout(can), can.onimport._project(can, msg, [])
cb && cb(msg), can.onappend._filter(can)
},
_content: function(can, msg, dev, target) { var list = []
can.onimport.card(can, msg, null, function(value) {
value.icons = can.misc.Resource(can, value.icons||"usr/icons/icebergs.png", "", value.origin); if (value.type == web.SERVER) { list.push(value); return true } })
can.onimport.itemlist(can, list, function(event, value) {
value.key = can.core.Keys(dev, value.name)
can.onimport.dream(event, can, value, event.currentTarget)
}, null, target)
},
dream: function(event, can, value, target) { can.isCmdMode()? can.misc.SearchHash(can, value.name): can.sup.db._zone = value.name
can.page.Select(can, can.ui.project, html.DIV_ITEM, function(_target) { can.page.ClassList.set(can, _target, html.SELECT, _target == target) })
if (can.onmotion.cache(can, function() { return value.key||value.name }, can.ui.content, can._status)) { return can.onimport.layout(can) }
can.run(can.request(event, {_toast: ice.PROCESS}), [value.origin], function(msg) {
can.onimport._content(can, msg, value.name, target), can.onappend._status(can, msg), can.onimport.layout(can)
_project: function(can, msg, dev, target) {
msg.Table(function(value) { if (value.type == web.WORKER) { return }
value.nick = [{text: value.name}, value.status == "true" && {text: ["●", "", "exists"]}]
value._hash = dev.concat([value.name]).join(":"), value._select = can.base.beginWith(can.db.hash.join(":"), value._hash)
value.icons = can.misc.Resource(can, value.icons||"usr/icons/icebergs.png", "", value.origin)
can.onimport.itemlist(can, [value], function(event, item, show, target) {
can.onimport.tabsCache(can, value, target, function(event) {
can.run(event, [value.origin], function(msg) {
can.onimport._project(can, msg, dev.concat([value.name]), target)
can.onimport._content(can, msg), can.onappend._status(can, msg)
})
})
}, null, target)
})
},
}, [""])
_content: function(can, msg) {
can.onimport.card(can, msg, null, function(value) { if (value.type == web.SERVER) { return true }
value.icons = can.misc.Resource(can, value.icons||"usr/icons/icebergs.png", "", value.origin)
}), can.onappend.style(can, "output card", can.ui.content), can.onimport.layout(can)
},
})

View File

@ -9,6 +9,7 @@ import (
"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/web/html"
kit "shylinux.com/x/toolkits"
)
@ -67,9 +68,9 @@ func StreamPush(m *ice.Message, arg ...string) {
AdminCmd(m, STREAM, PUSH, m.Option(ice.MSG_USERPOD), m.ShortKey(), arg)
}
func StreamPushRefresh(m *ice.Message, arg ...string) {
StreamPush(m.Spawn(ice.Maps{"space.noecho": ice.TRUE}), kit.Simple(html.REFRESH, arg)...)
if strings.Contains(m.Option(ice.MSG_USERPOD), ".") {
AdminCmd(m.Spawn(ice.Maps{"space.noecho": ice.TRUE}), SPACE, ice.DEV, STREAM, PUSH, m.Option(ice.MSG_USERPOD), m.ShortKey(), kit.Simple(html.REFRESH, arg))
StreamPush(m.Spawn(ice.Maps{ice.SPACE_NOECHO: ice.TRUE}), kit.Simple(html.REFRESH, arg)...)
if strings.Contains(m.Option(ice.MSG_USERPOD), nfs.PT) {
AdminCmd(m.Spawn(ice.Maps{ice.SPACE_NOECHO: ice.TRUE}), SPACE, ice.DEV, STREAM, PUSH, m.Option(ice.MSG_USERPOD), m.ShortKey(), kit.Simple(html.REFRESH, arg))
}
}
func StreamPushRefreshConfirm(m *ice.Message, arg ...string) {

View File

@ -12,7 +12,6 @@ import (
"shylinux.com/x/icebergs/base/nfs"
"shylinux.com/x/icebergs/base/web/html"
kit "shylinux.com/x/toolkits"
"shylinux.com/x/toolkits/logs"
)
const (
@ -29,7 +28,7 @@ func init() {
}, mdb.ClearOnExitHashAction(), mdb.StatusHashAction(html.CHECKBOX, ice.TRUE,
mdb.FIELD, "time,hash,type,name,text,cost,status,index,icons,agent,system,ip,ua",
)), Hand: func(m *ice.Message, arg ...string) {
mdb.HashSelect(m, arg...).PushAction(ctx.PREVIEW, mdb.REMOVE).Action(mdb.PRUNES, html.FILTER)
mdb.HashSelect(m, arg...).PushAction(ctx.PREVIEW, mdb.REMOVE).Action(mdb.PRUNES)
m.Sort("status,cost", []string{"", TOAST_INIT, TOAST_DONE}, func(value string) int { return -int(kit.Duration(value)) })
}},
})
@ -55,13 +54,13 @@ func toastTitle(m *ice.Message) string {
}
func toastContent(m *ice.Message, state string, arg ...ice.Any) string {
if len(arg) == 0 {
return kit.JoinWord(kit.Simple(Icons[state], kit.Select(ice.LIST, m.ActionKey()), state)...)
return kit.JoinWord(kit.Simple(Icons[state], m.Trans(kit.Select(ice.LIST, m.ActionKey()), ""), m.Trans(state, ""))...)
} else {
return kit.JoinWord(kit.Simple(Icons[state], arg)...)
}
}
func ToastSuccess(m *ice.Message, arg ...ice.Any) {
Toast(m, toastContent(m, ice.SUCCESS, arg...), "", cli.TIME_3s)
Toast(m, toastContent(m, ice.SUCCESS, arg...), "", cli.TIME_1s)
}
func ToastFailure(m *ice.Message, arg ...ice.Any) {
Toast(m, toastContent(m, ice.FAILURE, arg...), "", m.Option(ice.TOAST_DURATION, "-1")).Sleep(cli.TIME_3s)
@ -72,6 +71,9 @@ func ToastProcess(m *ice.Message, arg ...ice.Any) func(...ice.Any) {
Toast(m, text, "", "-1", "", h)
Count(m, kit.FuncName(1), toastTitle(m), text)
return func(_arg ...ice.Any) {
if m.IsErr() {
return
}
kit.If(len(_arg) == 0, func() { _arg = arg })
text := toastContent(m, ice.SUCCESS, _arg...)
toastUpdate(m, h, begin, mdb.TEXT, text, mdb.STATUS, TOAST_DONE)
@ -104,7 +106,7 @@ func GoToast(m *ice.Message, cb func(toast func(name string, count, total int))
m.Sleep(m.Option(ice.TOAST_DURATION))
} else {
icon = Icons[ice.SUCCESS]
m.Option(ice.TOAST_DURATION, cli.TIME_3s)
m.Option(ice.TOAST_DURATION, cli.TIME_1s)
toast(ice.SUCCESS, _total, _total)
}
Count(m, kit.FuncName(1), toastTitle(m), kit.FmtDuration(time.Now().Sub(begin)))
@ -121,15 +123,16 @@ func Toast(m *ice.Message, text string, arg ...ice.Any) *ice.Message { // [title
}
kit.If(len(arg) == 0, func() { arg = append(arg, "") })
kit.If(len(arg) > 0 && arg[0] == "", func() { arg[0] = toastTitle(m) })
if m.IsDebug() {
arg[0] = kit.Format(arg[0]) + "\t" + logs.FileLine(-1, "2")
}
PushNoticeToast(m, text, arg)
PushNoticeToast(m.Spawn("space.noecho", "true"), text, arg)
return m
}
func PushNoticeGrowXterm(m *ice.Message, title string, cmd ...ice.Any) {
PushCmdStream(m, title).Cmd(cli.SYSTEM, cmd)
}
func PushCmdStream(m *ice.Message, title string) *ice.Message {
m.Options(ctx.DISPLAY, html.PLUGIN_XTERM, cli.CMD_OUTPUT, nfs.NewWriteCloser(func(buf []byte) (int, error) {
PushNoticeGrow(m.Options(ice.MSG_TITLE, title, 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)).Cmd(cli.SYSTEM, cmd)
}, nil))
return m
}

View File

@ -17,22 +17,32 @@ const TOKEN = "token"
func init() {
Index.MergeCommands(ice.Commands{
TOKEN: {Help: "令牌桶", Actions: ice.MergeActions(ice.Actions{
mdb.PRUNES: {Hand: func(m *ice.Message, arg ...string) {
list := map[string]bool{}
TOKEN: {Help: "令牌桶", Icon: "Keychain.png", Actions: ice.MergeActions(ice.Actions{
mdb.PRUNES: {Name: "prunes", Hand: func(m *ice.Message, arg ...string) {
m.Cmds("").Table(func(value ice.Maps) {
key := kit.Fields(value[mdb.TYPE], value[mdb.NAME], value[mdb.TEXT])
if _, ok := list[key]; ok {
if value[mdb.STATUS] != "valid" {
m.Cmd("", mdb.REMOVE, value)
} else {
list[key] = true
}
})
}},
}, mdb.HashAction(mdb.SHORT, mdb.UNIQ, mdb.EXPIRE, mdb.MONTH, html.CHECKBOX, ice.TRUE)), Hand: func(m *ice.Message, arg ...string) {
if mdb.HashSelect(m, arg...); len(arg) > 0 {
m.EchoScript(kit.MergeURL2(m.Option(ice.MSG_USERWEB), nfs.PS, TOKEN, arg[0]))
} else {
now := m.Time()
list := map[string]bool{}
m.Table(func(value ice.Maps) {
key := kit.Keys(value[mdb.TYPE], value[mdb.TEXT])
if value[mdb.TIME] < now {
m.Push(mdb.STATUS, mdb.EXPIRED)
} else if list[key] {
m.Push(mdb.STATUS, mdb.INVALID)
} else {
m.Push(mdb.STATUS, mdb.VALID)
}
list[key] = true
})
m.Action(mdb.CREATE, mdb.PRUNES)
}
}},
})

View File

@ -62,7 +62,7 @@ func (f *Frame) Start(m *ice.Message, arg ...string) {
default:
m.Cmd(tcp.SERVER, tcp.LISTEN, mdb.TYPE, HTTP, mdb.NAME, logs.FileLine(1), m.OptionSimple(tcp.HOST, tcp.PORT), func(l net.Listener) {
defer mdb.HashCreateDeferRemove(m, m.OptionSimple(mdb.NAME, tcp.PROTO), arg, cli.STATUS, tcp.START)()
gdb.Event(m.Spawn(), SERVE_START, arg)
m.GoSleep("300ms", func() { gdb.Event(m.Spawn(), SERVE_START, arg) })
if m.Option(tcp.PORT) == tcp.PORT_443 {
m.WarnNotValid(f.Server.ServeTLS(l, nfs.ETC_CERT_PEM, nfs.ETC_CERT_KEY))
} else {

View File

@ -608,7 +608,7 @@ func StackHandler(m *ice.Message, arg ...string) {
if len(script) > 0 {
p := ice.USR_SCRIPT + m.PrefixKey() + nfs.PS + "list.js"
m.Cmd(nfs.SAVE, p, kit.Dict(nfs.CONTENT, strings.Join(script, lex.NL)))
s.value(m, "_script", "/require/"+p)
s.value(m, "_script", nfs.P+p)
}
cmd := m.Commands("")
kit.For(s.peekf().value, func(k string, v Any) {

34
conf.go
View File

@ -28,6 +28,7 @@ const (
MAIL = "mail"
HELP = "help"
INFO = "info"
SHOW = "show"
MAIN = "main"
AUTO = "auto"
LIST = "list"
@ -60,7 +61,8 @@ const (
INT = "int"
)
const ( // REPOS
CONTEXTS = "contexts"
CONTEXTOS = "ContextOS"
// CONTEXTS = "contexts"
INTSHELL = "intshell"
LEARNING = "learning"
VOLCANOS = "volcanos"
@ -174,6 +176,7 @@ const ( // DIR
SRC_BINPACK_GO = "src/binpack.go"
SRC_BINPACK_USR_GO = "src/binpack_usr.go"
SRC_TEMPLATE = "src/template/"
SRC_PRIVATE = "src/private/"
SRC_SCRIPT = "src/script/"
USR_SCRIPT = "usr/script/"
README_MD = "README.md"
@ -181,6 +184,8 @@ const ( // DIR
LICENSE = "LICENSE"
GO_MOD = "go.mod"
GO_SUM = "go.sum"
GO_WORK = "go.work"
GO_WORK_SUM = "go.work.sum"
ICE_BIN = "ice.bin"
CAN_PLUGIN = "can._plugin"
)
@ -210,9 +215,10 @@ const ( // MSG
MSG_OUTPUT = "_output"
MSG_ARGS = "_args"
MSG_PROCESS = "_process"
MSG_DISPLAY = "_display"
MSG_TOOLKIT = "_toolkit"
MSG_PROCESS = "_process"
MSG_DISPLAY = "_display"
MSG_DISPLAY_CSS = "_display_css"
MSG_TOOLKIT = "_toolkit"
MSG_USERIP = "user.ip"
MSG_USERUA = "user.ua"
@ -252,10 +258,13 @@ const ( // MSG
LOG_DISABLE = "log.disable"
LOG_TRACEID = "log.id"
MSG_NODEICON = "node.icon"
MSG_NODENAME = "node.name"
MSG_NODETYPE = "node.type"
MSG_FILES = "file.system"
FROM_SPACE = "from.space"
FROM_DAEMON = "from.daemon"
FIELD_OPTION = "field.option"
TABLE_CHECKBOX = "table.checkbox"
TOAST_DURATION = "toast.duration"
DREAM_SIMPLE = "dream.simple"
@ -315,12 +324,14 @@ const ( // CTX
CTX_SERVE = "serve"
CTX_CLOSE = "close"
CTX_INIT = "_init"
CTX_EXIT = "_exit"
CTX_OPEN = "_open"
CTX_TITLE = "_title"
CTX_TRANS = "_trans"
CTX_ICONS = "_icons"
CTX_INIT = "_init"
CTX_EXIT = "_exit"
CTX_OPEN = "_open"
CTX_TITLE = "_title"
CTX_TRANS = "_trans"
CTX_ICONS = "_icons"
CTX_STYLE = "_style"
AFTER_INIT = "afterInit"
)
const ( // LOG
LOG_CMDS = "cmds"
@ -341,8 +352,9 @@ const ( // Err
ErrNotValid = "not valid: "
ErrNotStart = "not start: "
ErrNotFoundSpace = "not found space: "
ErrNotFoundIndex = "not found index: "
ErrNotFoundSpide = "not found spide: "
ErrNotFoundSpace = "not found space: "
ErrAlreadyExists = "already exists: "
ErrNotImplement = "not implement: "
ErrTooDeepCount = "too deep count: "

View File

@ -76,6 +76,9 @@ func init() {
}
ctx.Command(m, arg...)
}},
ctx.RUN: {Hand: func(m *ice.Message, arg ...string) {
ctx.Run(m, arg...)
}},
}, web.ApiAction(""), aaa.WhiteAction("", web.SHARE)), Hand: func(m *ice.Message, arg ...string) {
if m.WarnNotLogin(m.Option(ice.MSG_USERNAME) == "", arg) {
return

View File

@ -0,0 +1,34 @@
package center
import (
"shylinux.com/x/ice"
"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 center struct {
list string `name:"list list" help:"云游"`
}
func (s center) List(m *ice.Message, arg ...string) {
if len(arg) == 0 {
m.Cmd(web.SPACE).Table(func(value ice.Maps) {
if value[mdb.TYPE] == web.SERVER {
m.PushRecord(value, mdb.NAME, mdb.ICONS, nfs.MODULE, nfs.VERSION)
}
})
m.Display("/plugin/story/spides.js?split=.").Option(nfs.DIR_ROOT, ice.Info.NodeName)
} else {
m.Cmdy(web.SPACE, arg[0], m.PrefixKey()).Table(func(value ice.Maps) {
m.Push(nfs.FILE, kit.Keys(arg[0], value[mdb.NAME]))
})
if m.Length() == 0 {
m.Push(web.SPACE, arg[0]).Push(ctx.INDEX, web.DESKTOP)
}
}
}
func init() { ice.Cmd("web.chat.center.center", center{}) }

View File

@ -0,0 +1,37 @@
package center
import (
"shylinux.com/x/ice"
"shylinux.com/x/icebergs/base/aaa"
"shylinux.com/x/icebergs/base/mdb"
"shylinux.com/x/icebergs/base/web"
)
type password struct {
change string `name:"change" help:"修改登录"`
login string `name:"login username* password*" help:"登录" role:"void"`
list string `name:"list refresh" help:"密码登录" role:"void"`
}
func (s password) Init(m *ice.Message, arg ...string) {
m.Cmd(web.HEADER, mdb.CREATE, mdb.TYPE, "qrcode", mdb.NAME, "qrcode", mdb.HELP, "扫码登录", mdb.ORDER, "10")
m.Cmd(web.HEADER, mdb.CREATE, mdb.TYPE, "plugin", mdb.NAME, m.CommandKey(), mdb.HELP, "密码登录", mdb.ORDER, "11", mdb.INDEX, m.PrefixKey())
}
func (s password) Change(m *ice.Message, arg ...string) {
m.Cmd(aaa.USER, mdb.MODIFY, aaa.USERNAME, m.Option(ice.MSG_USERNAME), aaa.PASSWORD, arg[1])
}
func (s password) Login(m *ice.Message, arg ...string) {
if m.WarnNotValid(m.Option(aaa.PASSWORD) != m.Cmd(aaa.USER, m.Option(aaa.USERNAME)).Append(aaa.PASSWORD), aaa.PASSWORD) {
return
}
web.RenderCookie(m.Message, aaa.SessCreate(m.Message, m.Option(aaa.USERNAME)))
}
func (s password) List(m *ice.Message, arg ...string) {
if m.Option(ice.MSG_USERNAME) == "" {
m.DisplayForm("username*", "password*", s.Login)
} else {
m.DisplayForm("password*", s.Change)
}
}
func init() { ice.Cmd("web.chat.password", password{}) }

View File

@ -14,6 +14,7 @@ func init() {
web.Index.Register(Index, &web.Frame{},
HEADER, FOOTER,
IFRAME, FAVOR,
TUTOR, FLOWS,
MESSAGE,
)
}

View File

@ -1,11 +1,24 @@
body { --web-flows-done:lightgreen; --web-flows-fail:var(--danger-bg-color); }
fieldset.web.flows>div.output>div.layout>div.layout>div.content svg line.fail { stroke:var(--web-flows-fail); }
fieldset.web.flows>div.output>div.layout>div.layout>div.content svg line.done { stroke:var(--web-flows-done); }
fieldset.web.flows>div.output>div.layout>div.layout>div.content svg line.select { stroke:var(--notice-bg-color); }
fieldset.web.flows>div.output>div.layout>div.layout>div.content svg rect.fail { stroke:var(--web-flows-fail); }
fieldset.web.flows>div.output>div.layout>div.layout>div.content svg rect.done { stroke:var(--web-flows-done); }
fieldset.web.flows>div.output>div.layout>div.layout>div.content svg rect.select { stroke:var(--notice-bg-color); }
fieldset.web.flows>div.output>div.layout>div.layout>div.content svg text { dominant-baseline:middle; }
fieldset.web.flows>div.output>div.layout>div.layout>div.content svg text.fail { stroke:var(--web-flows-fail); fill:var(--web-flows-fail); }
fieldset.web.flows>div.output>div.layout>div.layout>div.content svg text.done { stroke:var(--web-flows-done); fill:var(--web-flows-done); }
fieldset.web.flows>div.output>div.layout>div.layout>div.content svg text.select { stroke:var(--notice-bg-color); fill:var(--notice-bg-color); }
$content svg line.fail { stroke:var(--web-flows-fail); }
$content svg line.done { stroke:var(--web-flows-done); }
$content svg line.select { stroke:var(--notice-bg-color); }
$content svg rect.fail { stroke:var(--web-flows-fail); }
$content svg rect.done { stroke:var(--web-flows-done); }
$content svg rect.select { stroke:var(--notice-bg-color); }
$content svg text { dominant-baseline:middle; }
$content svg text.fail { stroke:var(--web-flows-fail); fill:var(--web-flows-fail); }
$content svg text.done { stroke:var(--web-flows-done); fill:var(--web-flows-done); }
$content svg text.select { stroke:var(--notice-bg-color); fill:var(--notice-bg-color); }
$content svg g.line0 line { stroke-width:8; }
$content svg g.line1 line { stroke-width:4; }
$content svg g.line2 line { stroke-width:2; }
$content fieldset.can._action { position:absolute; bottom:var(--action-height); }
$content fieldset.can._action>legend { display:none; }
$content fieldset.can._action>div.action { display:contents; }
$content fieldset.can._action>div.action br { clear:both; }
$content fieldset.can._action>div.action div.item.state { display:none; }
$content fieldset.can._action>div.status { display:none; }
$content fieldset.can._action:not(:hover) { background-color:transparent; }
$content fieldset.can._action:not(:hover)>form.option input { background-color:transparent; }
$content fieldset.can._action:not(:hover)>div.action input { background-color:transparent; }
$output>div.layout>div.layout:not(:hover) fieldset.can._action { visibility:hidden; }

View File

@ -10,15 +10,12 @@ const FLOWS = "flows"
func init() {
Index.MergeCommands(ice.Commands{
FLOWS: {Name: "flows zone hash auto", Help: "工作流", Icon: "Automator.png", Actions: ice.MergeActions(ice.Actions{
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.NAME, value[mdb.ZONE], value)
})
}
FLOWS: {Name: "flows refresh", Help: "工作流", Icon: "Automator.png", Actions: ice.MergeActions(ice.Actions{
mdb.CREATE: {Hand: func(m *ice.Message, arg ...string) {
m.Cmdy(mdb.INSERT, m.ShortKey(), "", mdb.HASH, m.OptionSimple(mdb.ZONE))
m.Cmd(FLOWS, mdb.INSERT, mdb.NAME, m.Option(mdb.ZONE))
}},
mdb.INSERT: {Name: "insert name space index* args", Hand: func(m *ice.Message, arg ...string) {
mdb.INSERT: {Name: "insert name space index args", Hand: func(m *ice.Message, arg ...string) {
m.Cmdy(mdb.INSERT, m.ShortKey(), kit.KeyHash(m.Option(mdb.ZONE)), mdb.HASH, m.OptionSimple(mdb.Config(m, mdb.FIELDS)))
}},
mdb.DELETE: {Hand: func(m *ice.Message, arg ...string) {
@ -28,14 +25,14 @@ func init() {
m.Cmdy(mdb.MODIFY, m.ShortKey(), kit.KeyHash(m.Option(mdb.ZONE)), mdb.HASH, m.OptionSimple(mdb.HASH), arg)
}},
}, mdb.ExportHashAction(mdb.SHORT, mdb.ZONE, mdb.FIELD, "time,zone", mdb.FIELDS, "time,hash,name,space,index,args,prev,from,status")), Hand: func(m *ice.Message, arg ...string) {
if arg = kit.Slice(arg, 0, 2); len(arg) == 0 || arg[0] == "" {
mdb.HashSelect(m).Option(ice.MSG_ACTION, "")
if len(arg) == 0 {
mdb.HashSelect(m).Action(mdb.CREATE)
} else {
m.Fields(len(arg)-1, mdb.Config(m, mdb.FIELDS), mdb.DETAIL)
m.Cmdy(mdb.SELECT, m.ShortKey(), kit.KeyHash(arg[0]), mdb.HASH, arg[1:])
m.PushAction(mdb.PLUGIN, mdb.DELETE)
m.PushAction("addnext", "addto", mdb.RENAME, mdb.PLUGIN, mdb.DELETE)
}
m.Display("")
m.Display("").DisplayCSS("")
}},
})
}

View File

@ -1,172 +1,227 @@
(function() { const ACTION_STORE = "web.flows:action:"
Volcanos(chat.ONIMPORT, {
_init: function(can, msg, cb) { can.ui = can.onappend.layout(can), cb && cb(msg)
can.core.Item(can.Action(), function(key) { can.onaction[key] = can.onaction[key]||can.onaction.refresh, can.Action(key, can.misc.localStorage(can, ACTION_STORE+key)) })
if (can.Option(mdb.ZONE)) { can.onmotion.hidden(can, can.ui.project), can.onimport._content(can, msg, can.Option(mdb.ZONE)) } else { can.onimport._project(can, msg) }
_init: function(can, msg) { msg.Push(mdb.ZONE, ctx.COMMAND)
can.ui = can.onappend.layout(can), can.onimport._project(can, msg), can.ui.toggle = can.onappend.toggle(can)
},
_project: function(can, msg) { var target; msg.Table(function(value) {
var item = can.onimport.item(can, value, function(event) { can.Option(mdb.ZONE, value.zone)
if (can.onmotion.cache(can, function(save, load) {
save({db: can.db, toggle: can.ui.toggle, _display_class: can.ui.display.className, _profile_class: can.ui.profile.className})
return load(value.zone, function(bak) { can.db = bak.db, can.ui.toggle = bak.toggle
can.ui.display.className = bak._display_class||can.ui.display.className
can.ui.profile.className = bak._profile_class||can.ui.profile.className
})
}, can.ui.content, can.ui.display, can._status)) { return can.page.isDisplay(can.ui.profile) && can.onimport._profile(can, can.db.current), can.onimport.layout(can) }
can.run(event, [value.zone], function(msg) { can.onimport._content(can, msg, can.Option(mdb.ZONE)) })
}, null, can.ui.project); target = value.zone == can.Option(mdb.ZONE)? item: target||item
}), target && target.click() },
_content: function(can, msg, zone) { if (msg.Length() == 0) { return can.Update(can.request({target: can._legend}, {title: mdb.INSERT, zone: zone}), [ctx.ACTION, mdb.INSERT]) }
can.db.list = {}; msg.Table(function(value) { can.db.list[value.hash] = value })
var root; can.core.Item(can.db.list, function(key, item) { if (!item.prev && !item.from) { return root = item }
try { if (item.prev) { can.db.list[item.prev].next = item } if (item.from) { can.db.list[item.from].to = item } } catch(e) { console.log(e) }
}), can.db.root = root, can.db.current = root
var _list = can.onexport.travel(can, can.db.root, true), _msg = can.request(); can.core.List(_list, function(item) { _msg.Push(item, msg.append) })
var table = can.onappend.table(can, _msg, null, can.ui.display); can.page.Select(can, table, "tbody>tr", function(target, index) { _list[index]._tr = target })
can.onappend._status(can, can.base.Obj(msg.Option(ice.MSG_STATUS)))
can.core.Item(can.db.list, function(key, item) { if (item.prev) { item.prev = can.db.list[item.prev] } if (item.from) { item.from = can.db.list[item.from] } })
can.onappend.plugin(can, {index: web.WIKI_DRAW, display: "/plugin/local/wiki/draw.js", style: html.OUTPUT}, function(sub) { can.ui.toggle = can.onappend.toggle(can, can.ui.content)
sub.onexport.output = function(_sub, _msg) { sub.Action(svg.GO, "manual"), sub.Action(ice.MODE, html.RESIZE), can.onmotion.hidden(can, _sub._action), can.db._content_plugin = _sub
can.onimport.layout(can), can.onimport._flows(can, _sub)
}, sub.run = function(event, cmds, cb) { cb(can.request(event)) }
}, can.ui.content)
},
_profile: function(can, item) { if (!item.index) { return can.onmotion.hidden(can, can.ui.profile), can.onimport.layout(can) }
if (can.onmotion.cache(can, function() { return can.core.Keys(can.Option(mdb.ZONE), item.hash) }, can.ui.profile)) { return can.onmotion.toggle(can, can.ui.profile, true), can.onimport.layout(can) }
can.onappend.plugin(can, {space: item.space, index: item.index, args: item.args, width: (can.ConfWidth()-can.ui.project.offsetWidth)/2-1}, function(sub) { can.db._profile_plugin = sub
sub.run = function(event, cmds, cb) { can.runActionCommand(can.request(event, {pod: item.space}), item.index, cmds, function(msg) { can.onmotion.toggle(can, can.ui.profile, true), cb(msg) }) }
sub.onexport.output = function() { can.onmotion.toggle(can, can.ui.profile, true), can.onimport.layout(can) }
sub.onaction._close = function() { can.onmotion.hidden(can, can.ui.profile), can.onimport.layout(can) }
}, can.ui.profile)
},
_flows: async function(can, _sub) { var margin = can.onexport.margin(can), height = can.onexport.height(can), width = can.onexport.width(can)
var matrix = {}, horizon = can.Action("direct") == "horizon"; can.onmotion.clear(can, _sub.ui.svg), can.db._height = 0, can.db._width = 0
async function sleep() { return new Promise(resolve => { setTimeout(resolve, can.Action("delay")) }) }
async function show(item, main) { var prev = "from", from = "prev"; if (horizon) { var prev = "prev", from = "from" }
while (matrix[can.core.Keys(item.x, item.y)]) {
if (horizon && main || !horizon && !main) { item.y++
for(var _item = item[prev]; _item; _item = _item[prev]) { _item.y++
if (!horizon && _item[prev]) {
_item._line.Val("y1", _item._line.Val("y1")+height)
} _item._line.Val("y2", _item._line.Val("y2")+height)
_item._rect.Val("y", _item._rect.Val("y")+height)
_item._text.Val("y", _item._text.Val("y")+height)
}
} else { item.x++
for(var _item = item[from]; _item; _item = _item[from]) { _item.x++
if (horizon && _item[from]) {
_item._line.Val("x1", _item._line.Val("x1")+width)
} _item._line.Val("x2", _item._line.Val("x2")+width)
_item._rect.Val("x", _item._rect.Val("x")+width)
_item._text.Val("x", _item._text.Val("x")+width)
}
_project: function(can, msg) { msg.Table(function(value) {
can.onimport.item(can, value, function(event, item, show, target) {
can.onimport.tabsCache(can, item, target, function() {
if (value.zone == ctx.COMMAND) {
can.onimport._command(can, value)
} else {
can.run(event, [value.zone], function(msg) { can.onimport._content(can, msg, value) })
}
} matrix[can.core.Keys(item.x, item.y)] = item
if (item.from || item.prev) { item._line = _sub.onimport.draw(_sub, {shape: svg.LINE, points:
horizon && item.from || !horizon && !item.from? [{x: item.x*width+width/2, y: item.y*height-margin}, {x: item.x*width+width/2, y: item.y*height+margin}]:
[{x: item.x*width-margin, y: item.y*height+height/2}, {x: item.x*width+margin, y: item.y*height+height/2}]
}) } can.onimport._block(can, _sub, item, item.x*width, item.y*height), await sleep()
var next = 0, to = 1; if (horizon) { var next = 1, to = 0 }
if (main) {
var _item = item.to; if (_item) { _item.x = item.x+to, _item.y = item.y+next, await show(_item) }
var _item = item.next; if (_item) { _item.x = item.x+next, _item.y = item.y+to, await show(_item, true) }
} else {
var _item = item.next; if (_item) { _item.x = item.x+next, _item.y = item.y+to, await show(_item, true) }
var _item = item.to; if (_item) { _item.x = item.x+to, _item.y = item.y+next, await show(_item) }
}
} can.db.root.x = 0, can.db.root.y = 0, await show(can.db.root, true)
},
_block: function(can, _sub, item, x, y) { var margin = can.onexport.margin(can), height = can.onexport.height(can), width = can.onexport.width(can)
var rect = _sub.onimport.draw(_sub, {shape: svg.RECT, points: [{x: x+margin, y: y+margin}, {x: x+width-margin, y: y+height-margin}]})
var text = _sub.onimport.draw(_sub, {shape: svg.TEXT, points: [{x: x+width/2, y: y+height/2}], style: {inner: item.name||item.index.split(nfs.PT).pop()}})
item._rect = rect, item._text = text, can.core.ItemCB(can.ondetail, function(key, cb) { text[key] = rect[key] = function(event) { cb(event, can, _sub, item) } })
if (item.status) { item._line && item._line.Value(html.CLASS, item.status), rect.Value(html.CLASS, item.status), text.Value(html.CLASS, item.status) }
if (can.db._height < y+height) { can.db._height = y+height, can.onimport.layout(can), can.isCmdMode() && rect.scrollIntoView() }
if (can.db._width < x+width) { can.db._width = x+width, can.onimport.layout(can), can.isCmdMode() && rect.scrollIntoView() }
},
layout: function(can) {
if (can.page.isDisplay(can.ui.profile)) { var profile = can.db._profile_plugin; can.page.styleWidth(can, can.ui.profile, (can.ConfWidth()-can.ui.project.offsetWidth)/2) }
can.page.isDisplay(can.ui.display) && can.page.SelectChild(can, can.ui.display, html.TABLE, function(target) { can.page.styleHeight(can, can.ui.display, can.base.Max(target.offsetHeight, can.ConfHeight()/2)+1) })
can.ui.layout(can.ConfHeight(), can.ConfWidth(), 0, function(height, width) { can.ui.toggle && can.ui.toggle.layout()
var _sub = can.db._content_plugin; if (_sub) { _sub.sup.onimport.size(_sub.sup, height, width), _sub.ui.svg.Val(html.HEIGHT, can.db._height), _sub.ui.svg.Val(html.WIDTH, can.db._width) }
profile && profile.onimport.size(profile, can.ui.profile.offsetHeight, can.ui.profile.offsetWidth-1, true)
}), value._current && can.onimport._profile(can, value._current, value)
})
}) },
_command: function(can, value) {
can.run(event, [ctx.RUN, ctx.COMMAND], function(msg) { var res = can.request(), cmds = {ice: []}
res.Push(mdb.HASH, "ice").Push(mdb.NAME, "ice").Push(ctx.INDEX, "").Push("prev", "").Push("from", "")
msg.Table(function(value) { can.core.List(value.index.split("."), function(cmd, index, list) { if (list[0] == "ice") { return }
var _mod = list.slice(0, index).join(".")||"ice", _cmd = list.slice(0, index+1).join(".")
var last = (cmds[_mod][cmds[_mod].length-1])||_mod; _cmd != last && cmds[_mod].push(_cmd)
var prev = "", from = ""; if (index % 2 == 0) { prev = last } else { from = last }
if (!cmds[_cmd]) { if (index < list.length-1) { cmds[_cmd] = [] }
res.Push(mdb.HASH, _cmd).Push(mdb.NAME, cmd).Push(ctx.INDEX, index < list.length-1? "": _cmd).Push("prev", prev).Push("from", from)
}
}) }), can.onimport._content(can, res, value)
})
},
}, [""])
_content: function(can, msg, value) {
can.onappend.plugin(can, {display: "/plugin/local/wiki/draw.js"}, function(sub) {
sub.onexport.output = function() { value._content_plugin = sub, can.onimport._toolkit(can, msg, value) }
}), can.onappend._status(can, msg)
},
_toolkit: function(can, msg, value) {
can.onappend.plugin(can, {index: "can._action"}, function(sub) { sub.ConfSpace(can.ConfSpace()), sub.ConfIndex([can.ConfIndex(), value.zone].join(":"))
sub.run = function(event, cmds, cb) { cmds[0] == ctx.ACTION? can.core.CallFunc(can.onaction[cmds[1]], [event, can, value]): cb && cb(can.request(event)) }
sub.onexport.output = function() { value._toolkit_plugin = sub, sub.onappend._action(sub, can.onaction._toolkit), sub.onaction._select(), can.onimport.layout(can) }
sub.onaction._select = function() { can.onimport._display(can, msg, value), can.onimport._flows(can, value) }
})
},
_display: function(can, msg, value) {
var list = {}; msg.Table(function(value) { list[value.hash] = value })
can.core.Item(list, function(key, item) { if (!item.prev && !item.from) { return value._root = item }
if (item.prev) { list[item.prev].next = item, item.prev = list[item.prev] }
if (item.from) { list[item.from].to = item, item.from = list[item.from] }
}), value._list = list
var _list = can.onexport.travel(can, value, value._root), _msg = can.request(); can.core.List(_list, function(item) {
_msg.Push(mdb.TIME, item.time), _msg.Push(mdb.HASH, item.hash), _msg.Push(mdb.NAME, item.name)
_msg.Push(web.SPACE, item.space), _msg.Push(ctx.INDEX, item.index||""), _msg.Push(ctx.ARGS, item.args||""), _msg.Push(ctx.ACTION, item.action||"")
}); var table = can.onappend.table(can, _msg, null, can.ui.display); can.page.Select(can, table, "tbody>tr", function(target, index) { _list[index]._tr = target })
},
_profile: function(can, item, value) { value._profile_plugin = item._profile_plugin, value._current = item
can.onmotion.toggle(can, can.ui.profile, true), can.onimport.layout(can)
can.onexport.hash(can, value.zone, item.hash), can.onexport.title(can, value.zone, item.name||item.index.split(".").pop())
if (can.onmotion.cache(can, function() { return can.core.Keys(value.zone, item.hash) }, can.ui.profile)) { return }
item.index && can.onappend.plugin(can, {pod: item.space, index: item.index, args: item.args}, function(sub) { value._profile_plugin = item._profile_plugin = sub
sub.onaction._close = function() { can.onmotion.hidden(can, can.ui.profile), can.onimport.layout(can) }
sub.onexport.output = function() { can.onimport.layout(can) }
}, can.ui.profile)
},
_flows: function(can, value) { var sub = value._toolkit_plugin.sub, _sub = value._content_plugin.sub
var margin = can.onexport.margin(sub), height = can.onexport.height(sub), width = can.onexport.width(sub)
var matrix = {}, lines = [], rects = [], horizon = sub.Action("direct") == "horizon"
can.onmotion.clear(can, _sub.ui.svg), _sub.ui.svg.Value("font-size", sub.Action("font-size")+"px")
function show(item, main, deep) { var prev = "from", from = "prev"; if (horizon) { var prev = "prev", from = "from" }
while (matrix[can.core.Keys(item.x, item.y)]) {
if (horizon && main || !horizon && !main) {
for(var _head = item[prev]; _head; _head = _head[prev]) { if (!_head[prev]) { var list = can.onexport.travel(can, value, _head, main)
can.core.List(list, function(_item) { if (!_item._rect) { return _item.y++ } delete(matrix[can.core.Keys(_item.x, _item.y)]), _item.y++
if ( _item._line) { _item != _head && _item._line.Val("y1", _item._line.Val("y1")+height), _item._line.Val("y2", _item._line.Val("y2")+height) }
_item._rect.Val("y", _item._rect.Val("y")+height), _item._text.Val("y", _item._text.Val("y")+height)
}), can.core.List(list, function(_item) { if (!_item._rect) { return } matrix[can.core.Keys(_item.x, _item.y)] = _item })
} }
} else {
for(var _head = item[from]; _head; _head = _head[from]) { if (!_head[from]) { var list = can.onexport.travel(can, value, _head, main)
can.core.List(list, function(_item) { if (!_item._rect) { return _item.x++ } delete(matrix[can.core.Keys(_item.x, _item.y)]), _item.x++
if ( _item._line) { _item != _head && _item._line.Val("x1", _item._line.Val("x1")+width), _item._line.Val("x2", _item._line.Val("x2")+width) }
_item._rect.Val("x", _item._rect.Val("x")+width), _item._text.Val("x", _item._text.Val("x")+width)
}), can.core.List(list, function(_item) { if (!_item._rect) { return } matrix[can.core.Keys(_item.x, _item.y)] = _item })
} }
}
} matrix[can.core.Keys(item.x, item.y)] = item
if (item.prev || item.from) { lines.length <= deep && lines.push(_sub.onimport.group(_sub, "line"+deep))
item._line = _sub.onimport.draw(_sub, {shape: svg.LINE, points:
horizon && item.from || !horizon && !item.from? [{x: item.x*width+width/2, y: item.y*height-margin}, {x: item.x*width+width/2, y: item.y*height+margin}]:
[{x: item.x*width-margin, y: item.y*height+height/2}, {x: item.x*width+margin, y: item.y*height+height/2}]
}, lines[deep])
} rects.length <= deep && rects.push(_sub.onimport.group(_sub, "rect"+deep)), can.onimport._block(can, value, item, item.x*width, item.y*height, rects[deep])
} value._root.x = 0, value._root.y = 0; var list = can.onexport.travel(can, value, value._root, true, 0)
can.core.Next(list, function(item, next, index) { can.user.toastProcess(can, index+" / "+list.length, "", index/list.length*100)
show(item, item._main, item._deep), can.onmotion.delay(can, function() { next() }, 30)
can.isCmdMode() && can.user.isChrome && item._rect.scrollIntoViewIfNeeded()
}, function() { can.user.toastSuccess(can) })
var max_x = 0, max_y = 0; can.core.List(list, function(item) { item.x > max_x && (max_x = item.x), item.y > max_y && (max_y = item.y) })
_sub.ui.svg.Value(html.HEIGHT, max_y*height), _sub.ui.svg.Value(html.WIDTH, max_x*width)
},
_block: function(can, value, item, x, y, group) { var sub = value._toolkit_plugin.sub, _sub = value._content_plugin.sub
var margin = can.onexport.margin(sub), height = can.onexport.height(sub), width = can.onexport.width(sub)
var rect = _sub.onimport.draw(_sub, {shape: svg.RECT, points: [{x: x+margin, y: y+margin}, {x: x+width-margin, y: y+height-margin}]}, group)
var text = _sub.onimport.draw(_sub, {shape: svg.TEXT, points: [{x: x+width/2, y: y+height/2}], style: {inner: item.name||item.index.split(nfs.PT).pop()}}, group)
var line = item._line||{}; item._rect = rect, item._text = text
can.core.ItemCB(can.ondetail, function(key, cb) { line[key] = rect[key] = text[key] = function(event) { can.request(event, item, value), cb(event, can, item, value) } })
if (item.status) { item._line && line.Value(html.CLASS, item.status), rect.Value(html.CLASS, item.status), text.Value(html.CLASS, item.status) }
if (value.zone == can.db.hash[0] && item.hash == can.db.hash[1] && can.onexport.session(can, "profile.show") != ice.FALSE) { can.onmotion.delay(can, function() { rect.onclick({target: rect}) }) }
},
layout: function(can) { can.ui.layout(can.ConfHeight(), can.ConfWidth(), 0, function(height, width) {
var sub = can.db.value && can.db.value._toolkit_plugin; if (sub) {
can.page.style(can, sub._target, html.LEFT, 0), sub.onimport.size(sub, html.ACTION_HEIGHT, width, true)
can.page.style(can, sub._target, html.LEFT, (can.ui.content.offsetWidth-sub._target.offsetWidth)/2)
}
}) },
})
Volcanos(chat.ONACTION, {
list: ["create", "play", "prev", "next",
_trans: {
style: {
addnext: "notice",
addto: "notice",
},
icons: {
addnext: "bi bi-arrow-down-square",
addto: "bi bi-arrow-right-square",
},
addnext: "添加下一步",
addto: "添加下一项",
},
_toolkit: [
"play", "prev", "next",
["travel", "deep", "wide"],
["delay", 1000, 3000, 5000],
"",
["direct", "vertical", "horizon"],
[html.HEIGHT, 80, 100, 120, 140, 200],
[html.WIDTH, 200, 240, 280, 400],
[html.MARGIN, 10, 20, 40, 60],
["delay", 100, 200, 500, 1000],
], _trans: {play: "播放", prev: "上一步", next: "下一步"},
refresh: function(event, can, button) { can.misc.localStorage(can, ACTION_STORE+button, can.Action(button)), can.onimport._flows(can, can.db._content_plugin) },
travel: function() {}, delay: function() {},
play: function(event, can) { var list = can.onexport.travel(can, can.db.root, true)
["font-size", 18, 14, 16, 18, 20, 22],
[html.MARGIN, 10, 5, 10, 20, 40, 60],
[html.HEIGHT, 60, 40, 60, 80, 100, 120, 140, 200],
[html.WIDTH, 180, 200, 240, 280, 400],
],
play: function(event, can, value) { var list = can.onexport.travel(can, value, value._root); var sub = value._toolkit_plugin.sub
can.core.List(list, function(item) { item._line && item._line.Value(html.CLASS, ""), item._rect.Value(html.CLASS, ""), item._text.Value(html.CLASS, "") })
can.core.Next(list, function(item, next, index, list) {
item._line && item._line.Value(html.CLASS, "done"), item._rect.Value(html.CLASS, "done"), item._text.Value(html.CLASS, "done")
can.user.toast(can, list[index].index), can.ondetail._select(event, can, item), can.onmotion.delay(can, next, 1000)
can.user.toast(can, list[index].index), can.ondetail._select(event, can, item, value), can.onmotion.delay(can, next, sub.Action("delay"))
}, function() { can.user.toastSuccess(can) })
},
prev: function(event, can) { var list = can.onexport.travel(can, can.db.root, true), prev
if (!can.db.current) { can.db.current = list.pop() } else {
can.core.List(list, function(item, index) { if (item == can.db.current) { prev = list[index-1] } }), can.db.current = prev
} can.ondetail._select(event, can, can.db.current)
prev: function(event, can, value) { if (!can.db.current) { can.db.current = value._root }
can.ondetail._select(event, can, can.db.current.prev || can.db.current.from, value)
},
next: function(event, can) {
if (!can.db.current) { can.db.current = can.db.root } else { var next, list = can.onexport.travel(can, can.db.root, true)
can.core.List(list, function(item, index) { if (item == can.db.current) { next = list[index+1] } }), can.db.current = next
} can.ondetail._select(event, can, can.db.current)
next: function(event, can, value) { if (!can.db.current) { can.db.current = value._root } var sub = value._toolkit_plugin.sub
can.ondetail._select(event, can, sub.Action("travel") == "wide" && can.db.current.next || can.db.current.to, value)
},
show: function(event, can) { can.onmotion.toggle(can, can.ui.profile), can.onimport.layout(can) },
exec: function(event, can) { can.onmotion.toggle(can, can.ui.display), can.onimport.layout(can) },
clear: function(event, can) { if (can.onmotion.clearFloat(can)) { return }
if (can.page.isDisplay(can.ui.profile)) { return can.onmotion.hidden(can, can.ui.profile), can.onimport.layout(can) }
if (can.page.isDisplay(can.ui.display)) { return can.onmotion.hidden(can, can.ui.display), can.onimport.layout(can) }
can.onmotion.toggle(can, can.ui.project), can.onimport.layout(can)
create: function(event, can) { can.user.input(event, can, can.Conf("feature.create"), function(data) {
can.runAction(can.request(event, data), mdb.CREATE, [], function(msg) { can.db.hash = can.onexport.hash(can, data.zone)
msg = can.request(), msg.Push(data), can.onimport._project(can, msg)
})
}) },
addnext: function(event, can) { can.onaction._insert(event, can, "prev") },
addto: function(event, can) { can.onaction._insert(event, can, "from") },
toggles: function(event, can) { var msg = can.request(event)
can.db.value._list[msg.Option(mdb.HASH)]._close = !can.db.value._list[msg.Option(mdb.HASH)]._close
can.onimport._flows(can, can.db.value)
},
rename: function(event, can) { can.onaction._modify(event, can, [mdb.NAME]) },
plugin: function(event, can) { can.onaction._modify(event, can, [ctx.INDEX, ctx.ARGS]) },
_insert: function(event, can, from) { var msg = can.request(event), zone = msg.Option(mdb.ZONE)
can.user.input(event, can, can.Conf("feature.insert"), function(data) {
can.runAction(can.request({}, data, kit.Dict(mdb.ZONE, zone, from, msg.Option(mdb.HASH))), mdb.INSERT, [], function(msg) {
can.db.hash = can.onexport.hash(can, zone, msg.Result())
can.run(event, [zone], function(msg) { can.onimport._content(can, msg, can.db.value) })
})
})
},
_modify: function(event, can, list) { var msg = can.request(event), zone = msg.Option(mdb.ZONE)
can.user.input(event, can, list, function(args) {
can.runAction(can.request({}, {zone: zone, hash: msg.Option(mdb.HASH)}), mdb.MODIFY, args, function() {
can.run(event, [zone], function(msg) { can.onimport._content(can, msg, can.db.value) })
})
})
},
plugin: function(event, can, msg) { can.ondetail._select(event, can, can.db.list[msg.Option(mdb.HASH)]) },
onkeydown: function(event, can) { can.db._key_list = can.onkeymap._parse(event, can, mdb.PLUGIN, can.db._key_list, can.ui.content) },
})
Volcanos(chat.ONDETAIL, {
_select: function(event, can, item) { if (!item) { return can.onmotion.hidden(can, can.ui.profile) }
can.isCmdMode() && item._rect.scrollIntoView(), can.db.current = item, can.onimport._profile(can, item)
can.page.Select(can, item._rect.parentNode, "", function(target) { var _class = (target.Value(html.CLASS)||"").split(lex.SP)
_select: function(event, can, item, value) { can.onimport._profile(can, item, value)
var sub = value._toolkit_plugin.sub, _sub = value._content_plugin.sub
can.page.Select(can, _sub.ui.svg, "rect", function(target) { var _class = (target.Value(html.CLASS)||"").split(lex.SP)
if (can.base.isIn(target, item._line, item._rect, item._text)) {
if (_class.indexOf(html.SELECT) == -1) { target.Value(html.CLASS, _class.concat([html.SELECT]).join(lex.SP).trim()) }
} else {
if (_class.indexOf(html.SELECT) > -1) { target.Value(html.CLASS, _class.filter(function(c) { return c != html.SELECT }).join(lex.SP).trim()) }
}
}), can.page.Select(can, item._tr.parentNode, "", function(target) { can.page.ClassList.set(can, target, html.SELECT, target == item._tr) })
})
can.page.Select(can, item._tr.parentNode, "", function(target) { can.page.ClassList.set(can, target, html.SELECT, target == item._tr)
can.onmotion.scrollIntoView(can, item._tr, 45, can.ui.display)
}), can.isCmdMode() && can.user.isChrome && item._rect.scrollIntoViewIfNeeded()
},
onclick: function(event, can, _sub, item) { switch (_sub.svg.style.cursor) {
case "e-resize":
can.Update(can.request(event, can.Action("direct") == "horizon"? {prev: item.hash}: {from: item.hash}), [ctx.ACTION, mdb.INSERT]); break
case "s-resize":
can.Update(can.request(event, can.Action("direct") == "horizon"? {from: item.hash}: {prev: item.hash}), [ctx.ACTION, mdb.INSERT]); break
default: can.ondetail._select(event, can, item)
} can.onkeymap.prevent(event) },
oncontextmenu: function(event, can, _sub, item) {
can.user.carteItem(event, can, can.base.CopyStr({action: item.action, zone: can.Option(mdb.ZONE)}, item))
onclick: function(event, can, item, value) { can.request(event, item, {zone: value.zone})
var sub = value._toolkit_plugin.sub, _sub = value._content_plugin.sub
switch (_sub.ui.svg.style.cursor) {
case "e-resize": if (sub.Action("direct") == "horizon") { can.onaction.addnext(event, can) } else { can.onaction.addto(event, can) } break
case "s-resize": if (sub.Action("direct") == "horizon") { can.onaction.addto(event, can) } else { can.onaction.addnext(event, can) } break
default: can.ondetail._select(event, can, item, value)
}
},
oncontextmenu: function(event, can, item, value) {
item.action? can.user.carteItem(event, can, can.base.CopyStr({action: item.action, zone: value.zone}, item)): can.user.carte(can.request(event, item, value), can, can.onaction, ["toggles"], function(event, button) {
can.request(event, item, value), can.onaction[button](event, can, button)
})
},
})
Volcanos(chat.ONEXPORT, {
margin: function(can) { var margin = can.Action(html.MARGIN); return parseFloat(margin) },
height: function(can) { var height = can.Action(html.HEIGHT); return parseFloat(height) },
width: function(can) { var width = can.Action(html.WIDTH); return parseFloat(width) },
travel: function(can, root, main) { if (!root) { return [] }
if (can.Action("travel") == "deep") { var list = [root]
margin: function(can) { var margin = can.Action(html.MARGIN); return parseFloat(margin)||10 },
height: function(can) { var height = can.Action(html.HEIGHT); return parseFloat(height)||60 },
width: function(can) { var width = can.Action(html.WIDTH); return parseFloat(width)||200 },
travel: function(can, value, root, main, deep) { if (!root) { return [] } root._deep = deep||0
var list = [root]; if (root._close) { return list } var sub = value._toolkit_plugin.sub
if (sub.Action("travel") == "deep") { main == undefined && (main = true), root._main = main
var horizon = sub.Action("direct") == "horizon"
var next = 0, to = 1; if (horizon) { var next = 1, to = 0 }
if (main) {
if (root.to) { list = list.concat(can.onexport.travel(can, root.to, false)) }
if (root.next) { list = list.concat(can.onexport.travel(can, root.next, true)) }
var _item = root.to; if (_item) { _item.x = root.x+to, _item.y = root.y+next, list = list.concat(can.onexport.travel(can, value, _item, false, deep+1)) }
var _item = root.next; if (_item) { _item.x = root.x+next, _item.y = root.y+to, list = list.concat(can.onexport.travel(can, value, _item, true, deep)) }
} else {
if (root.next) { list = list.concat(can.onexport.travel(can, root.next, true)) }
if (root.to) { list = list.concat(can.onexport.travel(can, root.to, false)) }
var _item = root.next; if (_item) { _item.x = root.x+next, _item.y = root.y+to, list = list.concat(can.onexport.travel(can, value, _item, true, deep+1)) }
var _item = root.to; if (_item) { _item.x = root.x+to, _item.y = root.y+next, list = list.concat(can.onexport.travel(can, value, _item, false, deep)) }
}
} else { var list = [root], i = 0
} else { var i = 0
while (i < list.length) { var count = list.length
for (i; i < count; i++) { for (var item = list[i].next; item; item = item.next) { list.push(item) } }
if (count == 1) { i = 0 } var count = list.length
@ -176,22 +231,3 @@ Volcanos(chat.ONEXPORT, {
return list
},
})
Volcanos(chat.ONKEYMAP, {
_mode: {plugin: {
Escape: shy("清屏", function(event, can) { can.onaction.clear(event, can) }),
g: shy("播放", function(event, can) { can.onaction.play(event, can) }),
v: shy("预览", function(event, can) { can.onaction.show(event, can) }),
r: shy("展示", function(event, can) { can.onaction.exec(event, can) }),
" ": shy("展示", function(event, can) { can.onaction.exec(event, can) }),
Enter: shy("预览", function(event, can) { can.onaction.show(event, can) }),
k: shy("上一步", function(event, can) { can.db.current && can.db.current.from? can.ondetail._select(event, can, can.db.current.from): can.onaction.prev(event, can) }),
h: shy("前一步", function(event, can) { can.db.current && can.db.current.prev? can.ondetail._select(event, can, can.db.current.prev): can.onaction.prev(event, can) }),
l: shy("后一步", function(event, can) { can.db.current && can.db.current.next? can.ondetail._select(event, can, can.db.current.next): can.onaction.next(event, can) }),
j: shy("下一步", function(event, can) { can.db.current && can.db.current.to? can.ondetail._select(event, can, can.db.current.to): can.onaction.next(event, can) }),
ArrowUp: shy("上一步", function(event, can) { can.db.current && can.db.current.from? can.ondetail._select(event, can, can.db.current.from): can.onaction.prev(event, can) }),
ArrowLeft: shy("前一步", function(event, can) { can.db.current && can.db.current.prev? can.ondetail._select(event, can, can.db.current.prev): can.onaction.prev(event, can) }),
ArrowRight: shy("后一步", function(event, can) { can.db.current && can.db.current.next? can.ondetail._select(event, can, can.db.current.next): can.onaction.next(event, can) }),
ArrowDown: shy("下一步", function(event, can) { can.db.current && can.db.current.to? can.ondetail._select(event, can, can.db.current.to): can.onaction.next(event, can) }),
}}, _engine: {},
})
})()

View File

@ -21,7 +21,8 @@ func init() {
GRANT: {Name: "grant space auto", Help: "授权", Role: aaa.VOID, Actions: ice.MergeActions(ice.Actions{
web.SPACE_LOGIN: {Hand: func(m *ice.Message, arg ...string) {
m.GoSleep30ms(func() {
p := m.Cmdx(web.SPACE, web.DOMAIN)
// p := m.Cmdx(web.SPACE, web.DOMAIN)
p := m.Option(ice.MSG_USERWEB)
link := tcp.PublishLocalhost(m, m.Options(ice.MSG_USERWEB, p).MergePodCmd("", "", web.SPACE, kit.Keys(web.ParseLink(m, p)[ice.POD], m.Option(mdb.NAME))))
m.Cmd(web.SPACE, m.Option(mdb.NAME), cli.PWD, m.Option(mdb.NAME), link, m.Cmdx(cli.QRCODE, link))
})
@ -61,6 +62,10 @@ func init() {
}
m.Options(tcp.HOSTNAME, ice.Info.Hostname, nfs.PATH, msg.Append(mdb.TEXT))
if !m.WarnNotValid(m.Option(nfs.PATH) == "", arg[0]) {
m.Option(aaa.IP, msg.Append(aaa.IP))
m.Option(ice.MSG_USERUA, msg.Append(aaa.UA))
m.Options(web.ParseUA(m))
m.Options("location", web.PublicIP(m, m.Option(aaa.IP)))
if m.EchoInfoButton(nfs.Template(m, "auth.html"), aaa.CONFIRM); m.IsWeixinUA() {
m.OptionFields(mdb.DETAIL)
m.Push(web.SPACE, arg[0])

View File

@ -1,7 +1,10 @@
package chat
import (
"net/http"
"path"
"strings"
"time"
ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/aaa"
@ -80,6 +83,14 @@ func init() {
aaa.USERNICK: {Hand: _header_users},
aaa.AVATAR: {Hand: _header_users},
aaa.BACKGROUND: {Hand: _header_users},
web.UPLOAD: {Role: aaa.VOID, Hand: func(m *ice.Message, arg ...string) {
if m.WarnNotLogin(m.Option(ice.MSG_USERNAME) == "") {
return
}
up := kit.Simple(m.Optionv(ice.MSG_UPLOAD))
m.Cmdy(web.CACHE, web.WATCH, m.Option(mdb.HASH), path.Join("usr/avatar/", m.Option(ice.MSG_USERNAME)+"."+kit.Ext(up[1])))
m.Echo("?_t=%d", time.Now().Unix())
}},
aaa.THEME: {Hand: func(m *ice.Message, arg ...string) {
if len(arg) > 0 && arg[0] != ice.AUTO && tcp.IsLocalHost(m, m.Option(ice.MSG_USERIP)) {
cli.TellApp(m, "System Events", `tell appearance preferences to set dark mode to `+
@ -100,13 +111,15 @@ func init() {
m.Cmdy(web.Space(m, m.Option(ice.POD)), MESSAGE, tcp.SEND, arg).ToastSuccess()
}
}},
aaa.LOGOUT: {Hand: aaa.SessLogout},
aaa.LOGOUT: {Role: aaa.VOID, Hand: aaa.SessLogout},
web.ONLINE: {Hand: func(m *ice.Message, arg ...string) { m.Cmdy(web.STREAM, web.ONLINE) }},
cli.QRCODE: {Hand: func(m *ice.Message, arg ...string) {
link := tcp.PublishLocalhost(m, m.Option(ice.MSG_USERWEB))
link := tcp.PublishLocalhost(m, m.OptionDefault(mdb.LINK, m.Option(ice.MSG_USERWEB)))
m.Push(mdb.NAME, link).PushQRCode(mdb.TEXT, kit.MergeURL(link, ice.FROM_DAEMON, m.Option(ice.MSG_DAEMON)))
}},
mdb.CREATE: {Name: "create type*=plugin,qrcode,oauth name* help icons link order space index args", Hand: func(m *ice.Message, arg ...string) { mdb.HashCreate(m, m.OptionSimple()) }},
mdb.CREATE: {Name: "create type*=plugin,qrcode,oauth name* help icons link order space index args"},
// Hand: func(m *ice.Message, arg ...string) { mdb.HashCreate(m, m.OptionSimple())},
mdb.REMOVE: {Hand: func(m *ice.Message, arg ...string) { mdb.HashRemove(m, m.OptionSimple(mdb.NAME)) }},
mdb.MODIFY: {Hand: func(m *ice.Message, arg ...string) { mdb.HashModify(m, m.OptionSimple(mdb.NAME), arg) }},
ice.DEMO: {Help: "体验", Icon: "bi bi-shield-fill-check", Hand: func(m *ice.Message, arg ...string) {
@ -120,45 +133,73 @@ func init() {
m.Echo("login failure")
}
}},
}, web.ApiAction(), mdb.ImportantHashAction(mdb.SHORT, mdb.NAME, mdb.FIELD, "time,name,help,icons,type,link,order,space,index,args")), Hand: func(m *ice.Message, arg ...string) {
ice.INFO: {Role: aaa.VOID, Hand: func(m *ice.Message, arg ...string) {}},
aaa.USER: {Role: aaa.VOID, Hand: func(m *ice.Message, arg ...string) {
msg := m.Cmd(web.SPIDE, aaa.USER, "msg", http.MethodPost, "/chat/header/action/info", ice.MSG_SESSID, kit.Select(m.Option(ice.MSG_SESSID), arg, 0))
if msg.Option(ice.MSG_USERNAME) != "" {
aaa.SessCheck(m, m.Option(ice.MSG_SESSID, aaa.SessCreate(m, msg.Option(ice.MSG_USERNAME))))
m.Echo(m.Option(ice.MSG_SESSID))
}
}},
}, web.ApiAction(), mdb.ImportantHashAction(mdb.SHORT, mdb.NAME, mdb.FIELD, "time,type,name,help,icons,order,link,space,index,args")), Hand: func(m *ice.Message, arg ...string) {
if kit.Contains(m.Option(ice.MSG_USERUA), "MicroMessenger") {
if m.Option(ice.MSG_USERNAME) == "" && m.Option("code") == "" && mdb.Config(m, "oauth") != "" {
m.ProcessOpen(mdb.Config(m, "oauth"))
// return
}
}
kit.If(kit.Select(m.Option(ice.POD), m.Option(ice.MSG_USERPOD)), func(p string) {
m.Cmdy(web.SPACE, p, m.PrefixKey(), ice.Maps{ice.MSG_USERPOD: "", ice.POD: ""})
}, func() {
m.Option(ice.MSG_NODETYPE, ice.Info.NodeType)
m.Option(ice.MSG_NODENAME, ice.Info.NodeName)
m.Option("favicon", ice.Info.NodeIcon)
if ice.Info.NodeType == web.WORKER && ice.Info.Titles == "ContextOS" {
return
}
m.Option("titles", ice.Info.Titles)
})
if ice.Info.NodeType == web.WORKER {
return
}
m.Option(ice.MSG_NODETYPE, ice.Info.NodeType)
kit.If(m.Option(ice.MSG_USERPOD), func(p string) {
m.Option(ice.MSG_NODETYPE, m.Cmdx(web.SPACE, p, cli.RUNTIME, ice.MSG_NODETYPE))
})
m.Option("favicon", "/require/"+m.Cmd(web.SPACE, m.Option(ice.MSG_USERPOD), web.SPACE, ice.INFO).Append(mdb.ICONS))
m.Option(aaa.LANGUAGE, strings.ReplaceAll(strings.ToLower(kit.Select("", kit.Split(kit.GetValid(
func() string { return kit.Select("", "zh-cn", strings.Contains(m.Option(ice.MSG_USERUA), "zh_CN")) },
func() string { return kit.Select("", kit.Split(m.R.Header.Get(html.AcceptLanguage), ",;"), 0) },
func() string {
if m.R != nil {
return kit.Select("", kit.Split(m.R.Header.Get(html.AcceptLanguage), ",;"), 0)
}
return ""
},
func() string { return ice.Info.Lang },
), " ."), 0)), "_", "-"))
m.Option("language.list", m.Cmd(nfs.DIR, nfs.TemplatePath(m, aaa.LANGUAGE)+nfs.PS, nfs.FILE).Appendv(nfs.FILE))
m.Option("theme.list", m.Cmd(nfs.DIR, nfs.TemplatePath(m, aaa.THEME)+nfs.PS, nfs.FILE).Appendv(nfs.FILE))
m.Option(nfs.REPOS, m.Cmdv(web.SPIDE, nfs.REPOS, web.CLIENT_URL))
m.Option("icon.lib", mdb.Conf(m, ICON, kit.Keym(nfs.PATH)))
m.Option("diy", mdb.Config(m, "diy"))
m.Echo(mdb.Config(m, TITLE))
mdb.HashSelect(m, arg...).Sort(mdb.ORDER, ice.INT)
m.Table(func(value ice.Maps) { m.Push(mdb.STATUS, kit.Select(mdb.ENABLE, mdb.DISABLE, value[mdb.ORDER] == "")) })
kit.If(m.Length() == 0, func() {
m.Push(mdb.TIME, m.Time()).Push(mdb.NAME, cli.QRCODE).Push(mdb.HELP, "扫码登录").Push(mdb.ICONS, nfs.USR_ICONS_VOLCANOS).Push(mdb.TYPE, cli.QRCODE).Push(web.LINK, "").Push(mdb.ORDER, "10")
})
kit.If(GetSSO(m), func(p string) {
m.Push(mdb.TIME, m.Time()).Push(mdb.NAME, web.SERVE).Push(mdb.ICONS, nfs.USR_ICONS_ICEBERGS).Push(mdb.TYPE, "oauth").Push(web.LINK, p)
})
m.StatusTimeCount(kit.Dict(mdb.ConfigSimple(m, ice.DEMO)))
kit.If(kit.IsIn(m.Option(ice.MSG_USERROLE), aaa.TECH, aaa.ROOT), func() { m.Action(mdb.CREATE, ice.DEMO) })
if gdb.Event(m, HEADER_AGENT); !_header_check(m, arg...) {
return
if m.Option(ice.MSG_USERNAME) == "" || kit.IsIn(m.Option(ice.MSG_INDEX), m.PrefixKey(), m.CommandKey()) {
mdb.HashSelect(m, arg...).Sort(mdb.ORDER, ice.INT)
m.Table(func(value ice.Maps) { m.Push(mdb.STATUS, kit.Select(mdb.ENABLE, mdb.DISABLE, value[mdb.ORDER] == "")) })
defer m.StatusTimeCount(kit.Dict(mdb.ConfigSimple(m, ice.DEMO)))
}
if gdb.Event(m, HEADER_AGENT); !_header_check(m, arg...) {
kit.If(m.Length() == 0, func() {
m.Push(mdb.TIME, m.Time()).Push(mdb.NAME, cli.QRCODE).Push(mdb.HELP, "扫码登录").Push(mdb.ICONS, nfs.USR_ICONS_VOLCANOS).Push(mdb.TYPE, cli.QRCODE).Push(web.LINK, "").Push(mdb.ORDER, "10")
})
kit.If(GetSSO(m), func(p string) {
m.Push(mdb.TIME, m.Time()).Push(mdb.NAME, web.SERVE).Push(mdb.ICONS, nfs.USR_ICONS_ICEBERGS).Push(mdb.TYPE, "oauth").Push(web.LINK, p).Push(mdb.ORDER, "100")
})
} else {
kit.If(kit.IsIn(m.Option(ice.MSG_USERROLE), aaa.TECH, aaa.ROOT), func() { m.Action(mdb.CREATE, ice.DEMO) })
msg := m.Cmd(aaa.USER, m.Option(ice.MSG_USERNAME))
if role := msg.Append(aaa.USERROLE); role != m.Option(ice.MSG_USERROLE) {
m.Cmd(aaa.SESS, mdb.MODIFY, mdb.HASH, m.Option(ice.MSG_SESSID), aaa.USERROLE, m.Option(ice.MSG_USERROLE, role))
}
kit.For([]string{aaa.USERNICK, aaa.LANGUAGE, aaa.EMAIL}, func(k string) { kit.If(msg.Append(k), func(v string) { m.Option(k, v) }) })
kit.For([]string{aaa.AVATAR, aaa.BACKGROUND}, func(k string) { m.Option(k, msg.Append(k)) })
}
msg := m.Cmd(aaa.USER, m.Option(ice.MSG_USERNAME))
kit.For([]string{aaa.EMAIL, aaa.LANGUAGE, aaa.USERNICK}, func(k string) { kit.If(msg.Append(k), func(v string) { m.Option(k, v) }) })
kit.For([]string{aaa.AVATAR, aaa.BACKGROUND}, func(k string) { m.Option(k, web.RequireFile(m, msg.Append(k))) })
}},
})
}
func AddHeaderLogin(m *ice.Message, types, name, help, order string, arg ...string) {
m.Cmd(web.CHAT_HEADER, mdb.CREATE, mdb.TYPE, types, mdb.NAME, name, mdb.HELP, help, mdb.ORDER, order, arg)
m.Cmd(web.SPACE, ice.OPS, web.CHAT_HEADER, mdb.CREATE, mdb.TYPE, types, mdb.NAME, name, mdb.HELP, help, mdb.ORDER, order,
web.SPACE, m.Option(ice.MSG_USERPOD), ctx.INDEX, m.PrefixKey(), arg,
)
}

View File

@ -65,7 +65,10 @@ func init() {
kit.If(m.Option(mdb.TYPE) == web.LINK, func() { ctx.ProcessField(m, m.ShortKey(), m.Option(mdb.TEXT)) })
}},
}, FavorAction(), mdb.HashAction(mdb.SHORT, web.LINK, mdb.FIELD, "time,hash,type,name,link")), Hand: func(m *ice.Message, arg ...string) {
list := []string{m.MergePodCmd("", web.PORTAL), m.MergePodCmd("", web.ADMIN)}
list := []string{m.MergePodCmd("", web.PORTAL), m.MergePodCmd("", web.ADMIN), m.MergePodCmd("", web.DESKTOP)}
m.Cmd(web.SPACE).Table(func(value ice.Maps) {
kit.If(kit.IsIn(value[mdb.TYPE], web.WORKER, web.SERVER), func() { list = append(list, m.MergePod(value[mdb.NAME])) })
})
if mdb.HashSelect(m, arg...); len(arg) == 0 {
for _, link := range list {
if u := kit.ParseURL(link); u != nil {

View File

@ -17,7 +17,9 @@ const AMAP = "amap"
func init() {
web.Index.MergeCommands(ice.Commands{
"/_AMapService/": {Hand: func(m *ice.Message, arg ...string) {
m.Cmdy(web.SPIDE, ice.DEV, web.SPIDE_RAW, m.R.Method, "https://restapi.amap.com/"+path.Join(arg...)+"?"+m.R.URL.RawQuery+"&jscode="+mdb.Conf(m, chat.Prefix(AMAP), kit.Keym(aaa.SECRET))).RenderResult()
m.Cmdy(web.SPIDE, ice.DEV, web.SPIDE_RAW, m.R.Method, kit.MergeURL("https://restapi.amap.com/"+path.Join(arg...)+"?"+m.R.URL.RawQuery,
"jscode", mdb.Conf(m, chat.Prefix(AMAP), kit.Keym(aaa.SECRET))),
).RenderResult()
}},
})
chat.Index.MergeCommands(ice.Commands{

View File

@ -2,55 +2,75 @@ Volcanos(chat.ONIMPORT, {
_init: function(can, msg, cb) { window._AMapSecurityConfig = {serviceHost: location.origin+"/_AMapService"}, can.require([can.Conf(nfs.SCRIPT)], function() {
can.require(["location.js"], function() { can.onimport._layout_init(can, msg, function() { cb && cb(msg)
can.page.style(can, can.ui.content, html.WIDTH, can.ConfWidth(can._fields.offsetWidth)-can.ui.project.offsetWidth)
can.onimport._content(can) })
})
can.onimport._content(can)
}) })
}) },
_content: function(can, item) {
var map = new AMap.Map(can.ui.content, {viewMode: '3D', lang: can.getHeaderLanguage().split("-")[0], zoom: can.Action("zoom"), pitch: can.Action("pitch"), rotation: can.Action("rotation")}); can.ui.map = map
can.onimport._style(can, can.getHeaderTheme()), can.onengine.listen(can, chat.ONTHEMECHANGE, function() { can.onimport._style(can, can.getHeaderTheme()) })
var map = new AMap.Map(can.ui.content, {viewMode: '3D', lang: can.getHeaderLanguage().split("-")[0], zoom: can.Action("zoom"), pitch: can.Action("pitch"), rotation: can.Action("rotation")})
can.ui.map = map, can.onimport._style(can, can.getHeaderTheme()), can.onengine.listen(can, chat.ONTHEMECHANGE, function() { can.onimport._style(can, can.getHeaderTheme()) })
map.on("moveend", function(event) { can.Action("pitch", map.getPitch().toFixed(2)), can.Action("rotation", map.getRotation()) })
map.on("zoomend", function(event) { can.Action("zoom", map.getZoom().toFixed(2)) })
map.on("click", function(event) { can.onexport.status(can, event.lnglat) })
map.plugin(['AMap.Scale', 'AMap.ToolBar', 'AMap.MapType', 'AMap.Geolocation', 'AMap.Geocoder', 'AMap.Weather'], function() {
map.plugin([
'AMap.Scale', 'AMap.ToolBar', 'AMap.MapType', 'AMap.Geolocation', 'AMap.Geocoder', 'AMap.Weather',
'AMap.Autocomplete',
'AMap.DistrictLayer',
], function() {
map.addControl(new AMap.Scale()), map.addControl(new AMap.ToolBar()), map.addControl(new AMap.MapType())
map.addControl(can.ui.geolocation = new AMap.Geolocation({buttonPosition: 'RB', enableHighAccuracy: true})), can.ui.geocoder = new AMap.Geocoder({})
AMap.event.addListener(can.ui.geolocation, 'error', function(res) { can.user.toastFailure(can, res.message) })
AMap.event.addListener(can.ui.geolocation, 'complete', function() {
can.ui.map.setZoom(can.Action("zoom", 16)), can.ui.map.setPitch(can.Action("pitch", 0)), can.ui.map.setRotation(can.Action("rotation", 0))
can.user.toastSuccess(can), can.onmotion.delay(can, function() { can.onexport.status(can)
var weather = new AMap.Weather(); weather.getLive(can.Status("city"), function(err, data) { can.Status(data) })
}, 500)
}), can.onmotion.delay(can, function() { can.onaction.current({}, can) })
AMap.event.addListener(can.ui.geolocation, 'error', function(res) {
can.user.toastFailure(can, res.message)
})
})
map.add(can.ui.favor = new AMap.OverlayGroup())
can.ui.layer = {}
map.add(can.ui.layer.favor = new AMap.OverlayGroup())
map.add(can.ui.layer.search = new AMap.OverlayGroup())
map.add(can.ui.marker = new AMap.Marker({position: [116.39, 39.9]}))
map.add(can.ui.circle = new AMap.CircleMarker({
center: new AMap.LngLat("116.403322", "39.920255"), radius: 100,
strokeColor: "#F33", strokeWeight: 1, fillColor: "#ee2200", fillOpacity: 0.35,
}))
},
_district: function(can, city) { can.ui._district = can.ui._district||{}; if (can.ui._district[city]) { return }
can.ui.map.add(can.ui._district[city] = new AMap.DistrictLayer.Province({
zIndex: 12, depth: 2, adcode: [city],
styles:{'fill': "transparent", 'city-stroke': 'blue', 'province-stroke': 'red'}
}))
if (can.ui._district.length > 1) { return }
can.ui.map.add(new AMap.DistrictLayer.Country({
zIndex: 10, depth: 2, SOC: 'CHN',
styles:{'fill': 'transparent', 'city-stroke': 'blue', 'province-stroke': 'red'}
}))
},
_style: function(can, style) {
style = {"light": "normal", "dark": "grey", "black": "blue", "white": "macaron", "silver": "grey", "blue": "graffiti", "red": "graffiti"}[style]||style
can.ui.map.setMapStyle("amap://styles/"+can.Action("style", style))
return style
},
_mark: function(can, item, target) {
var p = new AMap.Marker({position: [parseFloat(item.longitude), parseFloat(item.latitude)]})
p.on("click", function() { target.click() }), can.ui.favor.addOverlay(p)
_mark: function(can, item, target, layer) { layer = layer||can.ui.layer.favor
var p = new AMap.Marker({position: [parseFloat(item.longitude), parseFloat(item.latitude)], label: item.label && {content: item.label, direction: "bottom"}, title: item.name})
p.on("click", function() { target.click() }), layer.addOverlay(p)
},
})
Volcanos(chat.ONACTION, {
_trans: {
current: "定位", favor: "收藏",
favor: "收藏",
explore: "周边",
direction: "导航",
district: "行政",
current: "定位",
input: {
district: "区域", street: "街道",
zoom: "缩放", pitch: "倾斜", rotation: "旋转",
weather: "天气", temperature: "温度", humidity: "湿度", windPower: "风速",
},
},
current: function(event, can) {
can.user.toastProcess(can), can.ui.geolocation.getCurrentPosition()
icons: {
current: "bi bi-pin-map",
},
},
feature: function(event, can, button, value) {
if (value == "road") {
@ -59,17 +79,35 @@ Volcanos(chat.ONACTION, {
can.ui.map.setFeatures(["bg", "road", "building", "point"])
}
},
current: function(event, can) {
can.user.toastProcess(can), can.ui.geolocation.getCurrentPosition()
},
search: function(event, can) {
can.user.input(event, can, ["keyword"], function(data) {
can.ui.autoComplete = new AMap.Autocomplete({city: can.ui.city.citycode})
can.ui.autoComplete.search(data.keyword, function(status, result) { var _select
can.core.List(result.tips, function(value) { value = {name: value.name, label: value.name, longitude: value.location.lng, latitude: value.location.lat}
var item = can.onimport._item(can, value, can.ui.zone.search._target, can.ui.layer.search)
_select = _select||item._target
}), can.ui.zone.favor.toggle(false), can.ui.zone.search.toggle(true), _select.click()
// can.ui.map.setFitView([can.ui.layer.search], true, [10, 10, 10, 10], 15)
})
})
},
direction: function(event, can, button, item) {
can.user.isMobile && window.open(`https://uri.amap.com/marker?position=${item.longitude},${item.latitude}&name=${item.name||item.text}&callnative=1`)
},
center: function(can, item) { can.ui.marker.setTitle(item.name)
can.ui.map.setCenter(new AMap.LngLat(parseFloat(item.longitude), parseFloat(item.latitude)))
can.onmotion.delay(can, function() { can.onexport.status(can) }, 500)
},
direction: function(event, can, button, item) {
can.user.isMobile && window.open(`https://uri.amap.com/marker?position=${item.longitude},${item.latitude}&name=${item.name||item.text}&callnative=1`)
}
})
Volcanos(chat.ONEXPORT, {
status: function(can, p) { p = p||can.ui.map.getCenter(), can.ui.marker.setPosition(p), can.ui.circle.setCenter(p)
can.Status({longitude: p.getLng().toFixed(6), latitude: p.getLat().toFixed(6)}), can.ui.map.getCity(function(result) { can.Status(result) })
can.Status({longitude: p.getLng().toFixed(6), latitude: p.getLat().toFixed(6)}), can.ui.map.getCity(function(result) {
can.ui.city = result, can.Status(result)
can.onimport._district(can, can.ui.map.getAdcode())
})
can.ui.geocoder.getAddress(p, function(status, result) {
var info = result.regeocode.addressComponent, text = result.regeocode.formattedAddress
text = can.base.trimPrefix(text, info.province, info.city, info.district, info.township)

View File

@ -0,0 +1,6 @@
fieldset.web.chat.location div.output {
}
fieldset.web.chat.location div.action>div.item.text.zoom input { width:60px; }
fieldset.web.chat.location div.action>div.item.text.pitch input { width:60px; }
fieldset.web.chat.location div.action>div.item.text.rotation input { width:60px; }
div.amap-marker-label { background-color:var(--output-bg-color); }

View File

@ -5,7 +5,6 @@ import (
"shylinux.com/x/icebergs/base/ctx"
"shylinux.com/x/icebergs/base/mdb"
"shylinux.com/x/icebergs/base/web"
"shylinux.com/x/icebergs/base/web/html"
"shylinux.com/x/icebergs/core/chat"
kit "shylinux.com/x/toolkits"
)
@ -24,12 +23,7 @@ const LOCATION = "location"
func init() {
chat.Index.MergeCommands(ice.Commands{
LOCATION: {Help: "地图", Icon: "Maps.png", Meta: kit.Dict(
ice.CTX_TRANS, kit.Dict(EXPLORE, "周边", DIRECTION, "导航", DISTRICT, "地区", html.INPUT, kit.Dict(
LONGITUDE, "经度", LATITUDE, "纬度", PROVINCE, "省份", CITY, "城市", DISTRICT, "区域", STREET, "街路",
)),
), Actions: ice.MergeActions(ice.Actions{
"current": {Icon: "bi bi-pin-map"},
LOCATION: {Help: "地图", Icon: "Maps.png", Actions: ice.MergeActions(ice.Actions{
chat.FAVOR_INPUTS: {Hand: func(m *ice.Message, arg ...string) {
kit.If(arg[0] == mdb.TYPE, func() { m.Push(arg[0], LOCATION) })
}},

View File

@ -1,36 +1,35 @@
Volcanos(chat.ONIMPORT, {_init: function(can, msg) {},
Volcanos(chat.ONIMPORT, {
_init: function(can, msg) {},
_layout_init: function(can, msg, cb) {
can.db.list = {}, can.ui = can.onappend.layout(can), can.onimport._project(can)
can.onmotion.hidden(can, can.ui.project)
can.onmotion.hidden(can, can._action)
// can.core.Item(can.ui.zone, function(key, item) { key == "favor" || item._legend.click() })
can.onappend.style(can, "web.chat.location", can._fields)
if (can.user.isMobile) {
can.page.style(can, can.ui.project, "z-index", 2, "position", "absolute", html.MAX_HEIGHT, can.ConfHeight()-120)
can.page.style(can, can.ui.content, html.HEIGHT, can.ConfHeight(), html.WIDTH, can.ConfWidth())
can.onmotion.hidden(can, can._action), can.onmotion.hidden(can, can._status)
} else {
can.isCmdMode() || can.onmotion.hidden(can, can.ui.project), can.isCmdMode() || can.onmotion.hidden(can, can._action)
can.ui.layout(can.ConfHeight(), can.ConfWidth())
}
msg.Option(ice.MSG_ACTION, ""), cb && cb(msg)
if (msg.IsDetail()) { can.onaction.center(can, can.onimport._item(can, msg.TableDetail())) } else {
msg.Table(function(item) { can.onimport._item(can, item) }), can.ui.zone.favor._total(msg.Length()), can.ui.zone.favor.toggle(true)
var item = can.db.list[can.db.hash[0]]; item && item.click()
var item = can.db.list[can.db.hash[0]]; item && item.click()
}
},
_project: function(can) { can.onmotion.clear(can, can.ui.project), can.onimport.zone(can, [
{name: "search"}, {name: "explore"}, {name: "direction"},
{name: "favor", _menu: shy({"play": function(event, can, button) {
can.core.Next(can.page.Select(can, can.ui.zone.favor._target, html.DIV_ITEM), function(item, next) {
item.click(), can.onmotion.delay(can, next, 3000)
}, function() { can.user.toastSuccess(can) })
}})},
{name: "search"}, {name: "explore"}, {name: "direction"},
{name: "district", _delay_init: function(target, zone) { can.onimport._province(can, target) }},
], can.ui.project) },
_item: function(can, item, target) { if (!item.latitude || !item.longitude) { return item }
_item: function(can, item, target, layer) { if (!item.latitude || !item.longitude) { return item }
var _target = can.onimport.item(can, item, function(event) {
can.onaction.center(can, item), can.ui.map.setZoom(can.Action("zoom", 16)), can.misc.SearchHash(can, item.hash)
can.onimport.plugin(can, item) && can.onmotion.delay(can, function() {
var ls = can.ui.map.getBounds().path
can.onimport.plugin(can, item) && can.onmotion.delay(can, function() { var ls = can.ui.map.getBounds().path
ls && can.ui.map.setCenter([ls[1][0]-(ls[1][0]-ls[3][0])*3/8, ls[1][1]+(ls[3][1]-ls[1][1])*3/8])
}, 500)
}, function(event) {
@ -44,7 +43,7 @@ Volcanos(chat.ONIMPORT, {_init: function(can, msg) {},
remove: function(event, button) { can.runAction(event, mdb.REMOVE, [mdb.HASH, item.hash], function() { can.page.Remove(can, _target) }) },
})
}, target||can.ui.zone.favor._target); can.db.list[item.hash] = _target, can.ui.zone.favor._total()
return can.onimport._mark(can, item, _target), item
return can.onimport._mark(can, item, item._target = _target, layer), item
}, _mark: function(can, item) {}, _style: function(can, style) {},
plugin: function(can, item) { var extra = can.base.Obj(item.extra, {})
if (!extra.index) { return can.onmotion.toggle(can, can.ui.profile, false) } can.onmotion.toggle(can, can.ui.profile, true)
@ -59,15 +58,8 @@ Volcanos(chat.ONIMPORT, {_init: function(can, msg) {},
}, can.ui.profile)
return true
},
})
}, [""])
Volcanos(chat.ONACTION, {
_trans: {
current: "定位", favor: "收藏",
input: {
zoom: "缩放", pitch: "倾斜", rotation: "旋转",
weather: "天气", temperature: "温度", humidity: "湿度", windPower: "风速",
},
},
list: [
["style", "normal", "light", "whitesmoke", "fresh", "macaron", "graffiti", "darkblue", "blue", "grey", "dark"],
["feature", "point", "road"],
@ -75,11 +67,11 @@ Volcanos(chat.ONACTION, {
{type: html.TEXT, name: "pitch", value: 30, range: [0, 80, 5]},
{type: html.TEXT, name: "rotation", value: 0, range: [0, 360, 10]},
"current:button", "search", "explore", "direction", mdb.CREATE,
], _trans: {current: "定位", favor: "收藏"},
],
style: function(event, can, button, value) { can.onimport._style(can, value) },
zoom: function(event, can) { can.ui.map.setZoom(can.Action("zoom")) },
pitch: function(event, can) { can.ui.map.setPitch(can.Action("pitch")) },
rotation: function(event, can) { can.ui.map.setRotation(can.Action("rotation")) },
center: function(can, item) {},
})
Volcanos(chat.ONEXPORT, {list: ["province", "city", "district", "street", aaa.LONGITUDE, aaa.LATITUDE, "type", "name", "text", "space", "weather", "temperature", "humidity", "windPower"]})
Volcanos(chat.ONEXPORT, {list: ["province", "city", "district", "street", aaa.LONGITUDE, aaa.LATITUDE, mdb.TYPE, mdb.NAME, mdb.TEXT, web.SPACE, "weather", "temperature", "humidity", "windPower"]})

View File

@ -2,6 +2,7 @@ package macos
import (
"path"
"strings"
ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/aaa"
@ -24,14 +25,23 @@ func init() {
}, PodCmdAction(), CmdHashAction("space,index,args"), mdb.ClearOnExitHashAction())},
})
}
func install(m *ice.Message, cmd, icon, index string, arg ...string) {
func install(m *ice.Message, cmd, icon, index string, arg ...string) string {
if icon == "" {
return
return ""
} else if !kit.HasPrefix(icon, nfs.PS, web.HTTP) && !nfs.Exists(m, icon) && !nfs.Exists(m, ice.USR_ICONS+icon, func(p string) { icon = p }) {
if strings.Contains(kit.Path(""), nfs.USR_LOCAL_WORK) && nfs.Exists(m, path.Join(strings.Split(kit.Path(""), nfs.USR_LOCAL_WORK)[0], ice.USR_ICONS+icon)) {
icon = ice.USR_ICONS + icon
} else {
icon = path.Join(path.Dir(ctx.GetCmdFile(m, m.PrefixKey())), icon)
}
}
kit.If(!kit.HasPrefix(icon, nfs.PS, web.HTTP) && !nfs.Exists(m, icon), func() { icon = ice.USR_ICONS + icon })
name := kit.TrimExt(path.Base(icon), nfs.PNG, nfs.JPG, nfs.JPEG)
if !strings.HasPrefix(icon, nfs.USR_ICONS) {
name = kit.Select("", kit.Split(index, "."), -1)
}
m.Cmd(Prefix(cmd), mdb.CREATE, mdb.NAME, name, mdb.ICON, icon, ctx.INDEX, index, arg)
return icon
}
func AppInstall(m *ice.Message, icon, index string, arg ...string) {
install(m, APPLICATIONS, icon, index, arg...)
func AppInstall(m *ice.Message, icon, index string, arg ...string) string {
return install(m, APPLICATIONS, icon, index, arg...)
}

View File

@ -1,76 +1,85 @@
fieldset.macos.desktop { --desktop-menu-height:25px; }
fieldset.macos.desktop { background-size:cover; background-position:center; }
fieldset.macos.desktop>div.output { background-color:transparent; overflow:hidden; }
fieldset.macos.desktop>div.output>fieldset.macos { background-color:var(--plugin-bg-color); }
fieldset.macos.desktop>div.output>fieldset.macos>div.output { background-color:transparent; }
fieldset.macos.desktop>div.output>fieldset.macos.menu { line-height:var(--desktop-menu-height); border-radius:0; height:var(--desktop-menu-height); width:100%; position:sticky; top:0; overflow:hidden; z-index:10; }
fieldset.macos.desktop>div.output>fieldset.macos.menu div.menu:hover { background-color:var(--hover-bg-color); }
fieldset.macos.desktop>div.output>fieldset.macos.menu div.menu.icon { font-size:24px; line-height:22px; height:var(--desktop-menu-height); }
fieldset.macos.desktop>div.output>fieldset.macos.menu div.menu img { height:var(--desktop-menu-height); margin-right:var(--input-padding); }
fieldset.macos.desktop>div.output>fieldset.macos.menu div.menu { display:flex; align-items:flex-start; }
fieldset.macos.desktop>div.output>fieldset.macos.menu div.menu.title { font-style:italic; margin-left:10px; }
fieldset.macos.desktop>div.output>fieldset.macos.menu div.item.time { margin-right:10px; }
fieldset.macos.desktop>div.output>fieldset.macos.menu>div.output { overflow:hidden; }
fieldset.macos.desktop>div.output>fieldset.macos.dock { border:var(--box-border); border-radius:var(--plugin-radius); position:absolute; bottom:var(--input-margin); transition:margin-left 0.3s; z-index:10; }
fieldset.macos.desktop>div.output>fieldset.macos.searchs { position:absolute; z-index:10; }
fieldset.macos.desktop>div.output>fieldset.macos.notifications { height:calc(100% - 125px); width:320px; overflow:auto; position:absolute; top:var(--desktop-menu-height); left:calc(100% - 320px); z-index:10; }
fieldset.macos.desktop>div.output>fieldset.macos.notifications>div.action>div.item { padding:0; }
fieldset.macos.desktop>div.output>fieldset.macos.notifications>div.output>div.item { clear:both; display:flex; padding:var(--input-padding)}
fieldset.macos.desktop>div.output>fieldset.macos.notifications>div.output>div.item:not(:last-child) { border-bottom:var(--box-border); }
fieldset.macos.desktop>div.output>fieldset.macos.notifications>div.output>div.item.read { color:var(--disable-fg-color); }
fieldset.macos.desktop>div.output>fieldset.macos.notifications>div.output>div.item div.icon img { height:var(--header-height); margin:0 var(--input-margin); }
fieldset.macos.desktop>div.output>fieldset.macos.notifications>div.output>div.item>div.layout>div.layout { display:flex; align-items:center; }
fieldset.macos.desktop>div.output>fieldset.macos.notifications>div.output>div.item>div.layout { flex-grow:1; }
fieldset.macos.desktop>div.output>fieldset.macos.notifications>div.output>div.item div.title { font-family:var(--legend-font-family); flex-grow:1; word-break: break-all; }
fieldset.macos.desktop>div.output>fieldset.macos.notifications>div.output>div.item div.time { color:var(--disable-fg-color); font-size:var(--status-font-size); padding:var(--input-padding); }
fieldset.macos.desktop>div.output>fieldset.macos.notifications>div.output>div.item div.content { font-size:var(--status-font-size); }
fieldset.macos.desktop>div.output>div.desktop { display:flex; flex-direction:column; flex-wrap:wrap; align-content:start; gap:10px; height:calc(100% - 125px); overflow:auto; }
fieldset.macos.desktop>div.output>div.desktop:not(.select) { display:none; }
fieldset.macos.desktop>div.output>div.desktop>div.item { text-align:center; }
fieldset.macos.desktop>div.output>div.desktop>div.item img { object-fit:contain; height:var(--desktop-icon-size); width:var(--desktop-icon-size); }
fieldset.macos.desktop>div.output>div.desktop>div.item>div.name { font-size:var(--code-font-size); width:var(--desktop-icon-size); overflow:hidden; }
fieldset.macos.desktop>div.output>div.desktop>fieldset { border-radius:var(--plugin-radius); position:absolute; }
fieldset.macos.desktop>div.output>div.desktop>fieldset.select { z-index:9; }
fieldset.macos.desktop>div.output>div.desktop>fieldset>div.item.button { border-radius:var(--plugin-radius); box-shadow:var(--box-shadow); padding:8px; height:23px; width:23px; scale:0.7; position:absolute; top:15px; right:var(--plugin-padding); cursor:pointer; }
fieldset.macos.desktop>div.output>div.desktop>fieldset>div.item.button:not(:hover)>span { display:none; }
fieldset.macos.desktop>div.output>div.desktop>fieldset>legend { padding:0 var(--input-padding); margin:var(--button-margin); box-shadow:none; }
body.mobile fieldset.macos.desktop>div.output>div.desktop>fieldset>legend { float:none; }
body:not(.mobile) fieldset.macos.desktop>div.output>div.desktop>fieldset>legend:not(:hover) { background-color:transparent; }
fieldset.macos.desktop>div.output>div.desktop>fieldset div.item.button.window span { position:absolute; left:8px; top:2px; }
fieldset.macos.desktop>div.output>div.desktop>fieldset>form.option>*:not(.textarea) { margin:var(--button-margin) var(--input-margin); }
fieldset.macos.desktop>div.output>div.desktop>fieldset>form.option>div.icon { margin:var(--button-margin) 0; box-shadow:none; }
fieldset.macos.desktop>div.output>div.desktop>fieldset>form.option>div.list.icons { margin:var(--button-margin) 0; }
fieldset.macos.desktop>div.output>div.desktop>fieldset>form.option>div.back.icons { margin:var(--button-margin) 0; }
fieldset.macos.desktop>div.output>div.desktop>fieldset>div.action>div.item:last-child { margin-right:100px; }
body:not(.mobile) fieldset.macos.desktop>div.output>div.desktop>fieldset>div.action:not(.hide) { display:contents; }
fieldset.macos.desktop>div.output>div.desktop>fieldset>div.action>* { margin:var(--button-margin) var(--input-margin); }
fieldset.macos.desktop>div.output>div.desktop>fieldset>div.action>div.tabs { display:none; }
fieldset.macos.desktop>div.output>div.desktop>fieldset>div.output { min-height:240px; }
fieldset.macos.desktop>div.output>div.desktop>fieldset>div.output>table.content { width:100%; }
fieldset.macos.desktop>div.output>div.desktop>fieldset>div.output>table.content th { padding:var(--table-padding); }
fieldset.macos.desktop>div.output>div.desktop>fieldset>div.output>table.content td { padding:var(--table-padding); }
fieldset.macos.desktop>div.output>div.desktop>fieldset>div.output>table.content td>input { margin:var(--button-margin); }
fieldset.macos.desktop>div.output>div.desktop>fieldset.web.wiki.feel>div.status { display:none; }
fieldset.macos.desktop>div.output>div.desktop>fieldset.web.code.xterm>div.status { display:none; }
fieldset.macos.desktop>div.output>div.desktop>fieldset.web.chat.iframe>div.status { display:none; }
fieldset.macos.desktop>div.output>div.desktop>fieldset.iframe>form.option>div.item.hash input { width:var(--form-width); }
fieldset.macos.desktop>div.output>div.desktop>fieldset.xterm>form.option>div.item.hash input { width:var(--form-width); }
fieldset.macos.desktop>div.output>div.desktop>fieldset.web.chat.location>form.option>div.item:last-child { margin-right:unset; }
fieldset.macos.desktop>div.output>div.desktop>fieldset.web.chat.location>div.action>div.item.text { display:none; }
fieldset.macos.desktop>div.output>div.desktop>fieldset.web.chat.location>div.action>div.item.style select { width:80px; }
fieldset.macos.desktop>div.output>div.desktop>fieldset.web.chat.location>div.action>div.item.feature select { width:60px; }
fieldset.macos.desktop>div.output>div.desktop>fieldset.web.chat.macos.finder>div.action { display:none; }
fieldset.macos.desktop>div.output>div.desktop>fieldset.web.chat.macos.finder>div.status { display:none; }
fieldset.macos.desktop>div.output>div.desktop>fieldset.web.chat.macos.finder>div.output div.item.disable { display:none; }
fieldset.macos.desktop>div.output>fieldset.web.chat.macos.dock>div.output div.item.disable { display:none; }
fieldset.macos.desktop>div.output>div.desktop>div.item.disable { display:none; }
fieldset.desktop { background-size:cover; background-position:center; }
fieldset.desktop.output>div.output { border-radius:var(--plugin-radius); }
fieldset.desktop>div.output { background-color:transparent; overflow:hidden; }
fieldset.desktop>div.output>fieldset.macos { border:0; background-color:var(--plugin-bg-color); }
fieldset.desktop>div.output>fieldset.macos>div.output { background-color:transparent; }
fieldset.desktop>div.output>fieldset.macos.menu { border:0; border-radius:0; line-height:var(--desktop-menu-height); height:var(--desktop-menu-height); width:100%; position:sticky; top:0; overflow:hidden; z-index:10; }
fieldset.desktop>div.output>fieldset.macos.menu div.menu:hover { background-color:var(--hover-bg-color); }
fieldset.desktop>div.output>fieldset.macos.menu div.menu.icon { font-size:24px; line-height:22px; height:var(--desktop-menu-height); }
fieldset.desktop>div.output>fieldset.macos.menu div.menu img { height:var(--desktop-menu-height); margin-right:var(--input-padding); }
fieldset.desktop>div.output>fieldset.macos.menu div.menu { display:flex; align-items:flex-start; }
fieldset.desktop>div.output>fieldset.macos.menu div.menu.title { font-style:italic; }
fieldset.desktop>div.output>fieldset.macos.menu>div.output { overflow:hidden; }
fieldset.desktop>div.output>fieldset.macos.dock { border:var(--plugin-border); border-radius:var(--plugin-radius); position:absolute; bottom:var(--input-margin); transition:margin-left 0.3s; z-index:10; }
fieldset.desktop>div.output>fieldset.macos.searchs { position:absolute; z-index:10; }
fieldset.desktop>div.output>fieldset.macos.notifications { height:calc(100% - 125px); width:320px; overflow:auto; position:absolute; top:var(--desktop-menu-height); left:calc(100% - 320px); z-index:10; }
fieldset.desktop>div.output>fieldset.macos.notifications>div.action>div.item { padding:0; }
fieldset.desktop>div.output>fieldset.macos.notifications>div.output>div.item { clear:both; display:flex; padding:var(--input-padding)}
fieldset.desktop>div.output>fieldset.macos.notifications>div.output>div.item:not(:last-child) { border-bottom:var(--box-border); }
fieldset.desktop>div.output>fieldset.macos.notifications>div.output>div.item.read { color:var(--disable-fg-color); }
fieldset.desktop>div.output>fieldset.macos.notifications>div.output>div.item div.icon img { height:var(--header-height); margin:0 var(--input-margin); }
fieldset.desktop>div.output>fieldset.macos.notifications>div.output>div.item>div.layout>div.layout { display:flex; align-items:center; }
fieldset.desktop>div.output>fieldset.macos.notifications>div.output>div.item>div.layout { flex-grow:1; }
fieldset.desktop>div.output>fieldset.macos.notifications>div.output>div.item div.title { font-family:var(--legend-font-family); flex-grow:1; word-break: break-all; }
fieldset.desktop>div.output>fieldset.macos.notifications>div.output>div.item div.time { color:var(--disable-fg-color); font-size:var(--status-font-size); padding:var(--input-padding); }
fieldset.desktop>div.output>fieldset.macos.notifications>div.output>div.item div.content { font-size:var(--status-font-size); }
fieldset.desktop>div.output>div.desktop { display:flex; flex-direction:column; flex-wrap:wrap; align-content:start; gap:10px; height:calc(100% - 125px); overflow:auto; }
fieldset.desktop>div.output>div.desktop:not(.select) { display:none; }
fieldset.desktop>div.output>div.desktop>div.item { text-align:center; }
fieldset.desktop>div.output>div.desktop>div.item img { object-fit:contain; height:var(--desktop-icon-size); width:var(--desktop-icon-size); }
fieldset.desktop>div.output>div.desktop>div.item>div.name { color:white; white-space:pre; font-size:var(--code-font-size); width:var(--desktop-icon-size); overflow:hidden; }
fieldset.desktop>div.output>div.desktop>fieldset { border:0; position:absolute; }
fieldset.desktop>div.output>div.desktop>fieldset>legend { box-shadow:none; padding:0 var(--input-padding); margin:var(--button-margin); }
fieldset.desktop>div.output>div.desktop>fieldset>div.item.button { box-shadow:var(--box-shadow); border-radius:var(--plugin-radius); padding:8px; height:23px; width:23px;
transform:scale(0.7); position:absolute; top:15px; right:var(--plugin-padding); cursor:pointer; }
fieldset.desktop>div.output>div.desktop>fieldset>div.item.button:not(:hover)>span { display:none; }
fieldset.desktop>div.output>div.desktop>fieldset div.item.button.window span { position:absolute; left:8px; top:2px; }
fieldset.desktop>div.output>div.desktop>fieldset>form.option>*:not(.textarea) { box-shadow:none; margin:var(--button-margin) var(--input-margin); }
fieldset.desktop>div.output>div.desktop>fieldset>form.option>div.icon { box-shadow:none; margin:var(--button-margin) 0; }
fieldset.desktop>div.output>div.desktop>fieldset>form.option>div.icon.delete { display:none; }
fieldset.desktop>div.output>div.desktop>fieldset>form.option>div.list.icons { margin:var(--button-margin) 0; }
fieldset.desktop>div.output>div.desktop>fieldset>form.option>div.back.icons { margin:var(--button-margin) 0; }
fieldset.desktop>div.output>div.desktop>fieldset>form.option>div input:not(:hover):not(:focus) { border-top:var(--input-border); }
fieldset.desktop>div.output>div.desktop>fieldset>div.action>div input:not(:hover):not(:focus) { border-top:var(--input-border); }
fieldset.desktop>div.output>div.desktop>fieldset>div.action div.tabs:not(.select) { display:none; }
fieldset.desktop>div.output>div.desktop>fieldset>form.option>div.text input:hover { border-top:var(--box-notice); }
fieldset.desktop>div.output>div.desktop>fieldset>div.action>div.text input:hover { border-top:var(--box-notice); }
fieldset.desktop>div.output>div.desktop>fieldset>div.action>* { box-shadow:none; margin:var(--button-margin) var(--input-margin); }
fieldset.desktop>div.output>div.desktop>fieldset>div.action>div:last-child { margin-right:100px; }
fieldset.desktop>div.output>div.desktop>fieldset>div.output { min-height:240px; }
fieldset.desktop>div.output>div.desktop>fieldset>div.output>table.content { width:100%; }
fieldset.desktop>div.output>div.desktop>fieldset>div.output>table.content th { padding:var(--table-padding); }
fieldset.desktop>div.output>div.desktop>fieldset>div.output>table.content td { padding:var(--table-padding); }
fieldset.desktop>div.output>div.desktop>fieldset>div.output>table.content td>input { margin:var(--button-margin); }
fieldset.desktop>div.output>div.desktop>fieldset.iframe>div.status { display:none; }
fieldset.desktop>div.output>div.desktop>fieldset.iframe>form.option>div.item.hash input { width:var(--form-width); }
fieldset.desktop>div.output>div.desktop>fieldset.xterm>div.status { display:none; }
fieldset.desktop>div.output>div.desktop>fieldset.xterm>form.option>div.item.hash input { width:var(--form-width); }
fieldset.desktop>div.output>div.desktop>fieldset.vimer>form.option>div.item.path input { width:var(--input-width); }
fieldset.desktop>div.output>div.desktop>fieldset.vimer>div.action div.tabs { display:none; }
fieldset.desktop>div.output>div.desktop>fieldset.web.wiki.feel>div.status { display:none; }
fieldset.desktop>div.output>div.desktop>fieldset.web.chat.location>form.option>div.item:last-child { margin-right:unset; }
fieldset.desktop>div.output>div.desktop>fieldset.web.chat.location>div.action>div.item.text { display:none; }
fieldset.desktop>div.output>div.desktop>fieldset.web.chat.location>div.action>div.item.style select { width:80px; }
fieldset.desktop>div.output>div.desktop>fieldset.web.chat.location>div.action>div.item.feature select { width:60px; }
fieldset.desktop>div.output>div.desktop>fieldset.web.chat.macos.finder>div.action { display:none; }
fieldset.desktop>div.output>div.desktop>fieldset.web.chat.macos.finder>div.status { display:none; }
fieldset.desktop>div.output>div.desktop>fieldset.web.chat.macos.finder>div.output div.item.disable { display:none; }
fieldset.desktop>div.output>fieldset.web.chat.macos.dock>div.output div.item.disable { display:none; }
fieldset.desktop>div.output>div.desktop>div.item.disable { display:none; }
fieldset.macos.menu>div.output>div.item { padding:0 var(--button-padding); height:var(--desktop-menu-height); float:right; }
fieldset.macos.menu>div.output>div.item.avatar { padding:0; }
fieldset.macos.menu>div.output>div.item.avatar { margin-right:10px; }
body.mobile fieldset.macos.menu>div.output>div.item { padding:0 var(--input-padding); }
body.mobile fieldset.macos.menu>div.output>div.tabs { display:none; }
body.mobile fieldset.macos.menu>div.output>div.icon.create { display:none; }
body.mobile fieldset.macos.menu>div.output>div.item.search { display:none; }
body.mobile fieldset.macos.menu>div.output>div.item.notify { display:none; }
fieldset.macos.menu>div.output>div.item.avatar>img { padding:0; height:var(--desktop-menu-height); }
fieldset.macos.menu>div.output>div.menu { padding:0 var(--button-padding); float:left; }
fieldset.macos.menu>div.output>div.tabs { font-style:italic; padding:0 var(--button-padding); float:left; }
body.mobile fieldset.macos.menu>div.output>div.menu { padding:0 var(--input-padding); }
fieldset.macos.menu>div.output>div.tabs { font-style:italic; padding:0 var(--input-padding); float:left; }
fieldset.macos.menu.cmd>div.output>div.tabs { padding:0 var(--button-padding); }
fieldset.macos.menu>div.output>div.tabs.select { background-color:var(--panel-hover-bg-color); color:var(--panel-hover-fg-color); }
fieldset.macos.dock { transition:left 1s; }
fieldset.macos.dock>div.output { height:var(--desktop-icon-size); display:flex; overflow:auto; }
fieldset.macos.dock>div.output>div.space { background-color:#ececec36; margin:var(--button-margin); height:calc(100% - 20px); width:2px; }
fieldset.macos.dock>div.output>div.item { text-align:center; align-self:baseline; transition:margin-top 0.3s; }
@ -80,18 +89,24 @@ fieldset.macos.finder>div.output div.content>div.item { text-align:center; float
fieldset.macos.finder>div.output div.content>div.item img { object-fit:contain; width:var(--desktop-icon-size); }
fieldset.macos.finder>div.output div.content>div.item img { object-fit:contain; width:var(--desktop-icon-size); height:var(--desktop-icon-size); }
fieldset.macos.finder>div.output div.content>div.item div.name { font-size:var(--code-font-size); white-space:pre; text-align:center; overflow:hidden; }
body.dark fieldset.macos.desktop>div.output>fieldset.macos { background-color:#08234ad1; }
body.dark fieldset.macos.desktop>div.output>div.desktop fieldset table.content tbody tr:nth-child(odd):not(:hover) { background-color:#282B2F; }
body.dark fieldset.macos.desktop>div.output>div.desktop fieldset table.content tbody tr:nth-child(even):not(:hover) { background-color:#1a1d1e; }
body.light fieldset.macos.desktop>div.output>fieldset.macos { background-color:#daefff99; }
body.light fieldset.macos.desktop>div.output>div.desktop fieldset table.content tbody tr:nth-child(odd):not(:hover) { background-color:white; }
body.light fieldset.macos.desktop>div.output>div.desktop fieldset table.content tbody tr:nth-child(even):not(:hover) { background-color:#f4f5f5; }
fieldset.desktop>div.output>div.desktop fieldset table.content tbody tr:nth-child(odd):not(:hover) { background-color:var(--output-bg-color); }
fieldset.desktop>div.output>div.desktop fieldset table.content tbody tr:nth-child(even):not(:hover) { background-color:var(--plugin-bg-color); }
body:not(.mobile) fieldset.macos.dock>div.output { overflow:visible; }
body:not(.mobile) fieldset.macos.dock>div.output>div.item:hover { background-color:unset; margin-top:-80px; transition:margin-top 0.3s; }
body:not(.mobile) fieldset.macos.dock>div.output>div.item img:hover { width:160px; transition:width 0.3s; }
body:not(.mobile) fieldset.macos.desktop>div.output>fieldset.macos.dock:hover { margin-left:-40px; transition:margin-left 0.3s; }
body:not(.mobile) fieldset.macos.desktop>div.output>div.desktop>div.item { margin:var(--desktop-icon-margin); }
body.mobile fieldset.macos.desktop>div.output>div.desktop>fieldset>form.option>div.item.text>input { width:60px; }
body:not(.mobile) fieldset.desktop>div.output>fieldset.macos.dock:hover { margin-left:-40px; transition:margin-left 0.3s; }
body:not(.mobile) fieldset.desktop>div.output>div.desktop>div.item { margin:var(--desktop-icon-margin); }
body:not(.mobile) fieldset.desktop>div.output>fieldset.macos.searchs>form.option>div.item.keyword input { background-color:transparent; width:var(--river-width); }
body:not(.mobile) fieldset.desktop>div.output>fieldset.macos.searchs>div.action input { background-color:transparent; }
body:not(.mobile) fieldset.desktop>div.output>div.desktop>fieldset>legend:not(:hover) { background-color:transparent; }
fieldset.macos.menu.cmd>div.output>div.item { padding:0 var(--button-padding); }
fieldset.macos.menu.cmd>div.output>div.menu { padding:0 var(--button-padding); }
body.dark fieldset.desktop>div.output>fieldset.macos { background-color:#08234ad1; }
body.light fieldset.desktop>div.output>fieldset.macos { background-color:#daefff99; }
body.white fieldset.desktop>div.output>div.desktop>div.item>div.name { color:white; }
body.mobile fieldset.desktop>div.output>div.desktop>fieldset>legend { float:none; }
body.mobile fieldset.desktop>div.output>div.desktop>fieldset>form.option>div.item.text>input { width:60px; }
body.mobile fieldset.macos.dock>div.output { overflow-y:hidden; }
body:not(.mobile) fieldset.macos.desktop>div.output>fieldset.macos.searchs>form.option>div.item.keyword input { background-color:transparent; width:var(--river-width); }
body.windows fieldset.macos.desktop>div.output>fieldset.macos.notifications>div.action>div.item.refresh>span { font-size:24px; margin-top:0; }
body.windows fieldset.desktop>div.output>fieldset.macos.notifications>div.action>div.item.refresh>span { font-size:24px; margin-top:0; }
body.windows fieldset.desktop>div.output>div.desktop>fieldset div.item.button.window span { top:-2px; }
body.windows fieldset.desktop>div.output>fieldset.macos.menu div.menu.refresh { font-size:20px; }

View File

@ -1,9 +1,6 @@
package macos
import (
"path"
"strings"
ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/aaa"
"shylinux.com/x/icebergs/base/cli"
@ -25,7 +22,6 @@ func init() {
if m.Cmd(DESKTOP).Length() == 0 {
DeskAppend(m, "Books.png", web.WIKI_WORD)
DeskAppend(m, "Photos.png", web.WIKI_FEEL)
DeskAppend(m, "Grapher.png", web.WIKI_DRAW)
DeskAppend(m, "Calendar.png", web.TEAM_PLAN)
DeskAppend(m, "Messages.png", web.CHAT_MESSAGE)
}
@ -33,25 +29,28 @@ func init() {
DockAppend(m, "Finder.png", Prefix(FINDER))
DockAppend(m, "Safari.png", web.CHAT_IFRAME)
DockAppend(m, "Terminal.png", web.CODE_XTERM)
DockAppend(m, "go.png", web.CODE_COMPILE)
DockAppend(m, "git.png", web.CODE_GIT_STATUS)
DockAppend(m, "vimer.png", web.CODE_VIMER)
}
AppInstall(m, "App Store.png", web.STORE)
m.Travel(func(p *ice.Context, c *ice.Context, key string, cmd *ice.Command) {
kit.If(cmd.Icon, func() {
if !kit.HasPrefix(cmd.Icon, nfs.PS, web.HTTP) {
nfs.Exists(m, path.Join(path.Dir(strings.TrimPrefix(ctx.GetCmdFile(m, m.PrefixKey()), kit.Path(""))), cmd.Icon), func(p string) { cmd.Icon = p })
if kit.Contains(cmd.Icon, ".ico", ".png", ".jpg") {
cmd.Icon = AppInstall(m, cmd.Icon, m.PrefixKey())
}
AppInstall(m, cmd.Icon, m.PrefixKey())
})
})
Notify(m, "usr/icons/Infomation.png", cli.RUNTIME, "系统启动成功", ctx.INDEX, cli.RUNTIME)
}},
DESKTOP: {Help: "桌面", Role: aaa.VOID, Actions: ice.MergeActions(ice.Actions{
ice.AFTER_INIT: {Hand: func(m *ice.Message, arg ...string) {
web.AddPortalProduct(m, "云桌面", `
一款网页版的电脑桌面打开网页即可随时随地的使用各种软件
无论这些软件是运行在本机还是远程还是任何虚拟的空间无论是内存还是磁盘
`, 100.0)
}},
// web.DREAM_ACTION: {Hand: func(m *ice.Message, arg ...string) { web.DreamProcessIframe(m, arg...) }},
// web.DREAM_ACTION: {Hand: func(m *ice.Message, arg ...string) { web.DreamProcess(m, "", arg, arg...) }},
}, web.DreamTablesAction(), PodCmdAction(), CmdHashAction(), mdb.ExportHashAction())},
}, web.DreamTablesAction(), PodCmdAction(), CmdHashAction(ctx.INDEX), mdb.ExportHashAction())},
})
}

View File

@ -1,12 +1,12 @@
(function() {
Volcanos(chat.ONIMPORT, {
_init: function(can, msg) { can.isCmdMode() && can.onappend.style(can, html.OUTPUT)
can.onlayout.background(can, can.user.info.background||"/require/usr/icons/background.jpg", can._fields)
can.onlayout.background(can, can.misc.ResourceIcons(can, can.user.info.background||"usr/icons/background.png"), can._fields)
can.onimport._menu(can), can.onimport._notifications(can), can.onimport._searchs(can), can.onimport._dock(can)
can.sup.onexport.link = function() { return can.misc.MergeURL(can, {pod: can.ConfSpace()||can.misc.Search(can, ice.POD), cmd: web.DESKTOP}) }
can.onexport.title(can, can.ConfHelp(), can.user.titles)
},
_menu: function(can) { can.onappend.plugin(can, {index: "web.chat.macos.menu", style: html.OUTPUT}, function(sub) { can.ui.menu = sub
sub._desktop = can
_menu: function(can) { can.onappend.plugin(can, {index: "web.chat.macos.menu", style: html.OUTPUT, title: can.Conf("title")}, function(sub) { can.ui.menu = sub, sub._desktop = can
var tabs = can.misc.sessionStorage(can, [can.ConfIndex(), html.TABS])
sub.onexport.output = function() { can.onimport._desktop(can, can._msg)
var sess = can.misc.SearchHash(can)[0]||can.Conf("session")
@ -18,12 +18,10 @@ Volcanos(chat.ONIMPORT, {
switch (value) {
case "notifications": can.ui.notifications._output.innerHTML && can.onmotion.toggle(can, can.ui.notifications._target); break
case "searchs": can.onaction._search(can); break
case "reload": can.Update(); break
case cli.QRCODE: can.sup.onaction["生成链接"]({}, can.sup); break
case mdb.CREATE: can.onaction.create(event, can); break
case html.DESKTOP:
var carte = can.user.carte(event, can, {}, can.core.Item(can.onfigure), function(event, button, meta, carte) {
can.onfigure[button](event, can, carte); return true
}); break
case html.DESKTOP: var carte = can.user.carte(event, can, {}, can.core.Item(can.onfigure), function(event, button, meta, carte) { can.onfigure[button](event, can, carte); return true }); break
default: can.onimport._window(can, value)
}
}
@ -51,7 +49,13 @@ Volcanos(chat.ONIMPORT, {
} }
}) },
_dock: function(can) { can.onappend.plugin(can, {index: "web.chat.macos.dock", style: html.OUTPUT}, function(sub) { can.ui.dock = sub
sub.onexport.output = function(sub, msg) { can.onimport.layout(can) }
can.onimport.layout(can)
sub.onexport.output = function(sub, msg) {
can.onimport.layout(can)
can.onmotion.delay(can, function() {
can.onimport.layout(can)
})
}
sub.onexport.record = function(sub, value, key, item) { can.onimport._window(can, item) }
}) },
_desktop: function(can, msg, name) { var target = can.page.Append(can, can._output, [html.DESKTOP])._target; can.ui.desktop = target
@ -62,7 +66,7 @@ Volcanos(chat.ONIMPORT, {
can.onimport.__item(can, msg, target)
return target._tabs
},
_item: function(can, item) { can.runAction(can.request(event, item), mdb.CREATE, [], function() { can.run(event, [], function(msg) {
_item: function(can, item) { can.runAction(can.request(event, item), mdb.CREATE, [], function() { can.run({}, [], function(msg) {
can.page.SelectChild(can, can.ui.desktop, html.DIV_ITEM, function(target) { can.page.Remove(can, target) }), can.onimport.__item(can, msg, can.ui.desktop)
}) }) },
__item: function(can, msg, target) { var index = 0; can.onimport.icon(can, msg = msg||can._msg, target, function(target, item) { can.page.Modify(can, target, {
@ -72,16 +76,10 @@ Volcanos(chat.ONIMPORT, {
}); can.page.style(can, carte._target, html.TOP, event.y) },
}) }) },
_window: function(can, item, cb) { if (!item.index) { return }
item.height = can.ConfHeight()-125, item.width = can.ConfWidth()-200, item.left = (can.ConfWidth()-item.width)/2, item.top = 25
if (can.ConfWidth() > 1400) { item.width = can.base.Min(can.ConfWidth()-600, 640, 1400), item.left = (can.ConfWidth()-item.width)/2 }
if (can.ConfWidth() < 1000) { item.width = can.ConfWidth(), item.left = 0 }
if (can.ConfHeight() > 800) { item.height = can.base.Min(can.ConfHeight()-200, 320, 800), item.top = 50 }
if (can.user.isMobile) { item.height = can.ConfHeight()-125, item.top = 25, item.width = can.ConfWidth(), item.left = 0 }
item.height = can.base.Max(html.DESKTOP_HEIGHT, item.height), item.width = can.base.Max(html.DESKTOP_WIDTH, item.width)
if (can.base.isIn(item.index, web.CODE_VIMER)) { item.width = can.base.Max(1600, can.ConfWidth()), item.left = (can.ConfWidth()-item.width)/2 }
item.style = {left: item.left, top: item.top, height: item.height, width: item.width}
can.onappend.plugin(can, item, function(sub) { can.ondetail.select(can, sub._target)
can.page.style(can, sub._target, html.HEIGHT, item.height, html.WIDTH, item.width)
item.height = can.base.Max(html.DESKTOP_HEIGHT, can.ConfHeight()-125), item.width = can.base.Max(html.DESKTOP_WIDTH, can.ConfWidth())
item.left = (can.ConfWidth()-item.width)/2, item.top = (can.ConfHeight()-item.height-125)/4+25
item.type = html.PLUGIN, item.style = {left: item.left, top: item.top, height: item.height, width: item.width}
can.onappend.plugin(can, item, function(sub) {
var index = 0; can.core.Item({
close: {color: "#f95f57", inner: "x", onclick: function(event) { sub.onaction._close(event, sub) }},
small: {color: "#fcbc2f", inner: "-", onclick: function(event) { var dock = can.page.Append(can, can.ui.dock._output, [{view: html.ITEM, list: [{view: html.ICON, list: [{img: can.misc.PathJoin(item.icon)}]}], onclick: function() {
@ -91,24 +89,28 @@ Volcanos(chat.ONIMPORT, {
}, function(name, item) {
can.page.insertBefore(can, [{view: [[html.ITEM, html.BUTTON, "window", name], ""], title: name, list: [{text: item.inner}], style: {"background-color": item.color, right: 10+25*index++}, onclick: item.onclick}], sub._output)
})
sub.onimport._open = function(sub, msg, arg) { can.onimport._window(can, {title: msg.Option(html.TITLE), index: web.CHAT_IFRAME, args: [arg]}) }
sub.onimport._field = function(sub, msg) { msg.Table(function(item) { can.onimport._window(can, item) }) }
sub.onaction._close = function() { can.page.Remove(can, sub._target), can.onexport.tabs(can) }
sub.onappend.dock = function(item) { can.ui.dock.runAction(can.request(event, item), mdb.CREATE, [], function() { can.ui.dock.Update() }) }
sub.onappend.desktop = function(item) { can.onimport._item(can, item) }
sub.onexport.record = function(sub, value, key, item) { can.onimport._window(can, item) }
sub.onexport.marginTop = function() { return 25 }, sub.onexport.marginBottom = function() { return 100 }
sub.onexport.actionHeight = function(sub) { return can.page.ClassList.has(can, sub._target, html.OUTPUT)? 0: html.ACTION_HEIGHT+20 }
sub.onexport.output = function() { sub.onimport.size(sub, item.height, can.base.Min(sub._target.offsetWidth, item.width), false)
sub._target._meta.args = can.base.trim(can.page.SelectArgs(can, sub._option, "", function(target) { return target.value })), can.onexport.tabs(can)
}, sub.onimport.size(sub, item.height, can.base.Min(sub._target.offsetWidth, item.width), false)
sub.onexport.record = function(sub, value, key, item) { can.onimport._window(can, item) }
sub.onimport._open = function(sub, msg, arg) { can.onimport._window(can, {index: web.CHAT_IFRAME, args: [arg]}) }
sub.onimport._field = function(sub, msg) { msg.Table(function(item) { can.onimport._window(can, item) }) }
sub.onappend.dock = function(item) { can.ui.dock.runAction(can.request(event, item), mdb.CREATE, [], function() { can.ui.dock.Update() }) }
sub.onaction._close = function() { can.page.Remove(can, sub._target), can.onexport.tabs(can) }
sub.onappend.desktop = function(item) { can.onimport._item(can, item) }
}
can.onappend.style(can, html.FLOAT, sub._target), can.ondetail.select(can, sub._target, sub)
sub.onimport.size(sub, item.height, can.base.Min(sub._target.offsetWidth, item.width), false)
can.page.style(can, sub._target, html.HEIGHT, item.height, html.WIDTH, item.width)
can.onmotion.move(can, sub._target, {top: item.top, left: item.left})
sub.Conf("style.left", ""), sub.Conf("style.top", "")
sub.onmotion.resize(can, sub._target, function(height, width) {
sub.onimport.size(sub, item.height = height, item.width = width, false)
can.page.style(sub, sub._target, html.HEIGHT, height, html.WIDTH, width)
sub._target._meta.height = height, sub._target._meta.width = width, can.onexport.tabs(can)
}, 25)
sub._target.onclick = function(event) { can.ondetail.select(can, sub._target) }
}, 25, 0, can.ui.desktop)
sub._target.onclick = function(event) { can.ondetail.select(can, sub._target, sub) }
sub._target._meta = {index: sub.ConfIndex(), args: sub.Conf(ctx.ARGS)}, can.onexport.tabs(can)
cb && cb(sub)
}, can.ui.desktop)
@ -123,9 +125,11 @@ Volcanos(chat.ONIMPORT, {
}, function() { next() })
}, function() { _select && _select.click() })
},
layout: function(can) { can.page.style(can, can._output, html.HEIGHT, can.ConfHeight(), html.WIDTH, can.ConfWidth())
can.ui.dock && can.page.style(can, can.ui.dock._target, html.LEFT, can.base.Min((can.ConfWidth()-(can.ui.dock._target.offsetWidth||502))/2, 0))
can.ui.menu && can.ui.menu.onimport.size(can.ui.menu, 25, can.ConfWidth(), false)
layout: function(can) {
can.page.style(can, can._output, html.HEIGHT, can.ConfHeight(), html.WIDTH, can.ConfWidth())
can.ui.menu && can.ui.menu.onimport.size(can.ui.menu, html.DESKTOP_MENU_HEIHGT, can.ConfWidth(), false)
can.ui.dock && can.page.style(can, can.ui.dock._target, html.LEFT, can.base.Min((can.ConfWidth()-can.ui.dock._target.offsetWidth)/2, 0))
can.ui.dock && can.page.style(can, can.ui.dock._output, "position", "")
},
}, [""])
Volcanos(chat.ONACTION, {
@ -137,6 +141,21 @@ Volcanos(chat.ONACTION, {
} },
create: function(event, can) { can.onimport._desktop(can) },
})
Volcanos(chat.ONDETAIL, {
select: function(can, target, sub) {
can.onmotion.select(can, can.ui.desktop, html.FIELDSET, target)
can.onexport.title(can, sub.ConfHelp())
},
})
Volcanos(chat.ONEXPORT, {
tabs: function(can) {
var list = can.page.Select(can, can.ui.menu._output, html.DIV_TABS, function(target) { return {
select: can.page.ClassList.has(can, target, html.SELECT),
name: can.page.SelectOne(can, target, html.SPAN).innerHTML,
list: can.page.SelectChild(can, target._desktop, html.FIELDSET, function(target) { return target._meta })
} }); can.misc.sessionStorage(can, [can.ConfIndex(), html.TABS], JSON.stringify(list))
},
})
Volcanos(chat.ONKEYMAP, {
escape: function(event, can) { can.onmotion.hidden(can, can.ui.searchs._target) },
space: function(event, can) { can.onaction._search(can), can.onkeymap.prevent(event) },
@ -145,18 +164,6 @@ Volcanos(chat.ONKEYMAP, {
tabx: function(event, can) { can.page.Select(can, can.ui.menu._output, html.DIV_TABS_SELECT, function(target) { target._close() }) },
tabs: function(event, can) { can.onaction.create(event, can) },
})
Volcanos(chat.ONDETAIL, {
select: function(can, target) { can.onmotion.select(can, can.ui.desktop, html.FIELDSET, target) },
})
Volcanos(chat.ONEXPORT, {
tabs: function(can) {
var list = can.page.Select(can, can.ui.menu._output, html.DIV_TABS, function(target) { return {
select: can.page.ClassList.has(can, target, html.SELECT),
name: can.page.SelectOne(can, target, html.SPAN_NAME).innerHTML,
list: can.page.SelectChild(can, target._desktop, html.FIELDSET, function(target) { return target._meta })
} }); can.misc.sessionStorage(can, [can.ConfIndex(), html.TABS], JSON.stringify(list))
},
})
Volcanos(chat.ONFIGURE, {
"session\t>": function(event, can, carte) { can.runActionCommand(event, "session", [], function(msg) {
var hash = can.misc.SearchHash(can)

View File

@ -10,7 +10,7 @@ const DOCK = "dock"
func init() {
Index.MergeCommands(ice.Commands{
DOCK: {Help: "工具栏", Role: aaa.VOID, Actions: ice.MergeActions(ice.Actions{}, CmdHashAction(), mdb.ExportHashAction())},
DOCK: {Help: "工具栏", Role: aaa.VOID, Actions: ice.MergeActions(ice.Actions{}, CmdHashAction(mdb.NAME), mdb.ExportHashAction())},
})
}

View File

@ -1,8 +1,13 @@
Volcanos(chat.ONIMPORT, {_init: function(can, msg) { can.page.style(can, can._output, html.MAX_WIDTH, can.page.width())
can.onimport.icon(can, msg = msg||can._msg, can._output, function(target, item) { can.page.Modify(can, target, {
onclick: function(event) { can.sup.onexport.record(can, item.name, mdb.NAME, item) },
oncontextmenu: function(event) { var carte = can.user.carte(event, can, {
remove: function() { item.name != "Finder" && can.runAction(event, mdb.REMOVE, [item.hash]) },
}); can.page.style(can, carte._target, html.LEFT, event.x) },
}) }), can.page.Append(can, can._output, [{view: "space"}])
}})
Volcanos(chat.ONIMPORT, {
_init: function(can, msg) { can.page.style(can, can._output, html.MAX_WIDTH, can.page.width())
can.onimport.icon(can, msg = msg||can._msg, can._output, function(target, item) {
can.page.Modify(can, target, {
style: {"max-width": (can.page.width()-15)/msg.Length()},
onclick: function(event) { can.sup.onexport.record(can, item.name, mdb.NAME, item) },
oncontextmenu: function(event) { var carte = can.user.carte(event, can, {
remove: function() { item.name != "Finder" && can.runAction(event, mdb.REMOVE, [item.hash]) },
}); can.page.style(can, carte._target, html.LEFT, event.x) },
})
}), can.page.Append(can, can._output, [{view: "space"}])
},
})

View File

@ -1,6 +1,6 @@
Volcanos(chat.ONIMPORT, {
_init: function(can, msg) { can.ui = can.onappend.layout(can), msg.Table(function(value, index) {
var item = can.onimport.item(can, value, function(event) { if (can.onmotion.cache(can, function() { return value.name }, can.ui.content)) { return }
_init: function(can, msg) { can.ui = can.onappend.layout(can), msg.Table(function(value, index) { value._select = index == 0
can.onimport.item(can, value, function(event, item) { if (can.onmotion.cache(can, function() { return value.name }, can.ui.content)) { return }
can.runActionCommand(event, value.index, [], function(msg) {
switch (value.name) {
case ".":
@ -8,7 +8,7 @@ Volcanos(chat.ONIMPORT, {
default: can.onappend.table(can, msg, null, can.ui.content)
} can.onimport.layout(can)
})
}); index == 0 && item.click()
})
}), can.onmotion.hidden(can, can.ui.project) },
icons: function(can, msg, target) { can.onimport.icon(can, msg = msg||can._msg, target, function(target, item) { can.page.Modify(can, target, {
onclick: function(event) { can.sup.onexport.record(can.sup, item.name, mdb.NAME, item) },

View File

@ -8,6 +8,7 @@ import (
"shylinux.com/x/icebergs/base/mdb"
"shylinux.com/x/icebergs/base/nfs"
"shylinux.com/x/icebergs/base/web"
"shylinux.com/x/icebergs/base/web/html"
"shylinux.com/x/icebergs/core/chat"
kit "shylinux.com/x/toolkits"
)
@ -50,7 +51,7 @@ func disableApp(m *ice.Message) *ice.Message {
return m
}
func PodCmdAction(arg ...string) ice.Actions {
file := kit.FileLine(2, 100)
file := kit.FileLine(-1, 100)
return ice.Actions{
mdb.SELECT: {Name: "list hash auto create", Hand: func(m *ice.Message, arg ...string) {
defer m.Display(m.FileURI(file))
@ -64,7 +65,7 @@ func PodCmdAction(arg ...string) ice.Actions {
}
}
func CmdHashAction(arg ...string) ice.Actions {
file := kit.FileLine(2, 100)
file := kit.FileLine(-1, 100)
return ice.MergeActions(ice.Actions{
mdb.INPUTS: {Hand: func(m *ice.Message, arg ...string) {
switch mdb.HashInputs(m, arg); arg[0] {
@ -75,6 +76,7 @@ func CmdHashAction(arg ...string) ice.Actions {
}
}},
mdb.SELECT: {Hand: func(m *ice.Message, arg ...string) {
m.Option(html.FAVICON, m.Cmd(web.SPACE, ice.INFO).Append(mdb.ICONS))
disableApp(mdb.HashSelect(m, arg...).Sort(mdb.NAME).Display(m.FileURI(file)))
}},
}, mdb.HashAction(mdb.SHORT, kit.Select("", arg, 0), mdb.FIELD, kit.Select("time,hash,icon,name,text,space,index,args", arg, 1), kit.Slice(arg, 2)))

View File

@ -1,13 +1,21 @@
Volcanos(chat.ONIMPORT, {_init: function(can, msg) { can.page.style(can, can._output, html.MAX_WIDTH, "")
can.page.Append(can, can._output, can.user.header(can.sup._desktop)), can.page.Append(can, can._output, [
{view: [html.ITEM], list: [{icon: icon.notifications}], onclick: function(event) { can.sup.onexport.record(can, "notifications") }},
{view: [html.ITEM], list: [{icon: icon.search}], onclick: function(event) { can.sup.onexport.record(can, "searchs") }},
{view: [[html.ITEM, "state", "notify"]], list: [{icon: icon.notifications}], onclick: function(event) { can.sup.onexport.record(can, "notifications") }},
{view: [[html.ITEM, "state", "search"]], list: [{icon: icon.search}], onclick: function(event) { can.sup.onexport.record(can, "searchs") }},
].concat(msg.Table(function(item) {
return {view: [html.ITEM], list: [{img: can.page.drawText(can, item.name||item.index, 25, 0, 20)}], onclick: function(event) { can.sup.onexport.record(can, item) }}
return {view: [[html.ITEM, item.name]], list: [{img: can.page.drawText(can, item.name||item.index, 25, 0, 20)}], onclick: function(event) { can.sup.onexport.record(can, item) }}
}), [
{view: [[html.MENU, html.TITLE]], list: [{img: can.misc.ResourceFavicon(can)}, {text: decodeURIComponent(can.ConfSpace()||can.misc.Search(can, ice.POD)||location.host)}],
onclick: function(event) { can.sup.onexport.record(can, html.DESKTOP) }},
{view: [[html.MENU, mdb.ICON, web.REFRESH], "", can.page.unicode.refresh], onclick: function(event) { can.user.reload(true) }},
{view: [[html.MENU, html.TITLE]], list: [
{img: can.misc.ResourceFavicon(can, msg.Option(html.FAVICON), can.ConfSpace())},
{text: decodeURIComponent(
can.Conf("title")||
(window == top? can.user.info.titles: "")||can.ConfSpace()||can.misc.Search(can, ice.POD)||location.host
)},
], onclick: function(event) { can.sup.onexport.record(can, html.DESKTOP) }},
{view: [[html.MENU, mdb.ICON, web.REFRESH], "", can.page.unicode.refresh], onclick: function(event) {
can.sup.onexport.record(can, "reload")
// can.user.reload(true)
}},
{view: [[html.MENU, mdb.ICON, mdb.CREATE], "", can.page.unicode.create], onclick: function(event) { can.sup.onexport.record(can, mdb.CREATE) }},
]))
}})

View File

@ -1,4 +1,4 @@
Volcanos(chat.ONIMPORT, {_init: function(can, msg) {
Volcanos(chat.ONIMPORT, {_init: function(can, msg, cb) {
can.page.Appends(can, can._output, msg.Table(function(item) { return {view: [[html.ITEM, item.status]], _init: function(target) {
var ui = can.onappend.layout(can, [html.ICON, [[wiki.TITLE, mdb.TIME], wiki.CONTENT]], "", target)
can.page.Append(can, ui.icon, [{img: can.misc.PathJoin(item.icon||can.page.drawText(can, item.name||item.index, 60))}])

View File

@ -1,22 +1,28 @@
body.light fieldset.web.chat.message>div.output { background-color:white; }
body.light fieldset.web.chat.message>div.output>div.layout>div.layout>div.content>div.list { background-color:#e3e3e2; }
body.light fieldset.web.chat.message>div.output>div.layout>div.layout>div.content>div.list { background-color:#e3e3e2; overflow-x:hidden; }
body.light fieldset.web.chat.message>div.output>div.layout>div.layout>div.content>div.list>div.item:not(.plug).send div.content { background-color:#94ec69; }
fieldset.web.chat.message>div.output>div.project>div.title { background-color:var(--plugin-bg-color); padding:var(--button-padding); display:flex; justify-content:space-between; position:sticky; top:0; z-index:2; }
fieldset.web.chat.message>div.output>div.project>div.title i:hover { background-color:var(--hover-bg-color); cursor:pointer; }
fieldset.web.chat.message>div.output>div.project>div.title span:hover { background-color:var(--hover-bg-color); cursor:pointer; }
fieldset.web.chat.message>div.output>div.project>div.title span { padding:0 var(--input-padding); }
fieldset.web.chat.message>div.output>div.project>div.item.text.filter>i { left:var(--input-padding); }
fieldset.web.chat.message>div.output>div.project>div.item { border-left:var(--box-border3); cursor:pointer; }
fieldset.web.chat.message>div.output>div.project>div.item.select { border-right:var(--box-border3); }
fieldset.web.chat.message>div.output>div.project>div.item.server { border-left:var(--box-notice3); }
fieldset.web.chat.message>div.output>div.project>div.item.origin { border-left:var(--box-danger3); }
fieldset.web.chat.message>div.output>div.project>div.item.server.select { border-right:var(--box-notice3); }
fieldset.web.chat.message>div.output>div.project>div.item.origin.select { border-right:var(--box-danger3); }
fieldset.web.chat.message>div.output>div.project>div.item:not(.filter) { height:58px; padding:var(--input-padding); }
fieldset.web.chat.message>div.output>div.project>div.item.select { border-right:unset; }
fieldset.web.chat.message>div.output>div.project>div.item.text.filter>i { left:var(--input-padding); }
fieldset.web.chat.message>div.output>div.project>div.item img { height:var(--header-height); width:var(--header-height); display:block; float:left; }
body.mobile fieldset.web.chat.message>div.output>div.project { border-right:none; }
fieldset.web.chat.message>div.output>div.project>div.item span.time { color:var(--disable-fg-color); font-size:var(--status-font-size); }
fieldset.web.chat.message>div.output>div.project>div.item div.container { width:calc(100% - var(--header-height)); float:left; }
fieldset.web.chat.message>div.output>div.project>div.item div.title { display:flex; justify-content:space-between; }
fieldset.web.chat.message>div.output>div.project>div.item div.content { display:flex; justify-content:space-between; }
fieldset.web.chat.message>div.output>div.project>div.item div.title>span:first-child { margin-right:var(--input-margin); overflow:hidden; flex-shrink:1; }
fieldset.web.chat.message>div.output>div.project>div.item div.content { color:var(--disable-fg-color); font-size:var(--status-font-size); }
fieldset.web.chat.message>div.output>div.layout>div.layout>div.content { overflow:hidden; }
fieldset.web.chat.message>div.output>div.layout>div.layout>div.content>div.title { background-color:var(--plugin-bg-color); padding:var(--button-padding); display:flex; justify-content:space-between; position:sticky; top:0; z-index:2; }
fieldset.web.chat.message>div.output>div.layout>div.layout>div.content>div.title img { height:26px; }
fieldset.web.chat.message>div.output>div.layout>div.layout>div.content>div.title { background-color:var(--plugin-bg-color); padding:var(--button-padding); display:flex; justify-content:space-between; align-items:center; position:sticky; top:0; z-index:2; }
fieldset.web.chat.message>div.output>div.layout>div.layout>div.content>div.title i:hover { background-color:var(--hover-bg-color); cursor:pointer; }
fieldset.web.chat.message>div.output>div.layout>div.layout>div.content>div.title span:hover { background-color:var(--hover-bg-color); cursor:pointer; }
fieldset.web.chat.message>div.output>div.layout>div.layout>div.content>div.title span { padding:0 var(--input-padding); }
@ -31,10 +37,11 @@ fieldset.web.chat.message>div.output>div.layout>div.layout>div.content>div.list>
fieldset.web.chat.message>div.output>div.layout>div.layout>div.content>div.list>div.item.send div.container { display:flex; flex-direction:column; align-items:flex-end; }
fieldset.web.chat.message>div.output>div.layout>div.layout>div.content>div.list>div.item.text div.content { white-space:pre; padding:var(--input-padding) var(--button-padding); }
fieldset.web.chat.message>div.output>div.layout>div.layout>div.content>div.list>div.item>div.container>div.content fieldset.story>form.option>div.item.text input { width:var(--form-width); }
fieldset.web.chat.message>div.output>div.layout>div.layout>div.content>div.list>div.item>div.container>div.content fieldset.story>form.option>div.icon.delete { display:none; }
fieldset.web.chat.message>div.output>div.layout>div.layout>div.content>div.list>div.item.plug>div.container>div.content fieldset.story>div.action>div.item.chat.icons { display:none; }
fieldset.web.chat.message>div.output>div.layout>div.layout>div.content>div.list>div.item.plug>div.container>div.content { box-shadow:var(--box-shadow); }
fieldset.web.chat.message>div.output>div.layout>div.layout>div.content>div.list>div.item.plug>div.container>div.content:hover { box-shadow:var(--notice-box-shadow); }
fieldset.web.chat.message>div.output>div.layout>div.layout>div.content>div.list>div.item>div.container>div.content { display:flex; align-items:center; border-radius:var(--plugin-radius); min-height:var(--header-height); width:fit-content; }
fieldset.web.chat.message>div.output>div.layout>div.layout>div.content>div.list>div.item>div.container>div.content { border-radius:var(--plugin-radius); min-height:var(--header-height); width:fit-content; display:flex; align-items:center; }
fieldset.web.chat.message>div.output>div.layout>div.layout>div.content>div.list>div.item.plug { height:fit-content; }
fieldset.web.chat.message>div.output>div.layout>div.layout>div.content>div.list>div.item.plug div.content { padding:0; }
fieldset.web.chat.message>div.output>div.layout>div.layout>div.content>div.list>div.item.send { flex-direction:row-reverse; }
@ -43,3 +50,5 @@ fieldset.web.chat.message>div.output>div.layout>div.display div.toolkit { backgr
fieldset.web.chat.message>div.output>div.layout>div.display div.toolkit i { padding:var(--input-padding); }
fieldset.web.chat.message>div.output>div.layout>div.display div.toolkit i:hover { background-color:var(--hover-bg-color); }
fieldset.web.chat.message>div.output>div.layout>div.display textarea { height:calc(100% - var(--action-height)); }
fieldset.web.chat.message>div.output>div.layout>div.display textarea:not(:hover) { border-left:0; }
body.mobile fieldset.web.chat.message>div.output>div.project { border-right:0; }

View File

@ -32,7 +32,7 @@ func init() {
if m.OptionDefault(mdb.ZONE, m.Option(web.TARGET)) == "" {
m.Option(mdb.ZONE, kit.Hashs(mdb.UNIQ))
}
mdb.ZoneCreate(m, kit.Simple(arg, web.TARGET, m.Option(web.TARGET), mdb.ZONE, m.Option(mdb.ZONE)))
mdb.ZoneCreate(m, kit.Simple(m.OptionSimple(mdb.ICONS), arg, m.OptionSimple(web.TARGET, mdb.ZONE)))
}},
mdb.INSERT: {Hand: func(m *ice.Message, arg ...string) {
mdb.ZoneInsert(m, kit.Simple(arg[0], tcp.DIRECT, tcp.SEND, arg[1:], aaa.USERNAME, m.Option(ice.MSG_USERNAME), aaa.USERNICK, m.Option(ice.MSG_USERNICK), aaa.AVATAR, m.Option(ice.MSG_AVATAR)))
@ -47,22 +47,18 @@ func init() {
m.Cmd("", mdb.INSERT, m.Option(ice.FROM_SPACE), arg, tcp.DIRECT, tcp.RECV)
mdb.HashSelectUpdate(m, m.Option(ice.FROM_SPACE), func(value ice.Map) { kit.Value(value, web.TARGET, m.Option(ice.FROM_SPACE)) })
}},
cli.CLEAR: {Hand: func(m *ice.Message, arg ...string) {}},
web.OPEN: {Hand: func(m *ice.Message, arg ...string) { m.ProcessOpen(m.MergePod(m.Option(web.TARGET))) }},
cli.CLEAR: {Hand: func(m *ice.Message, arg ...string) {}},
web.OPEN: {Hand: func(m *ice.Message, arg ...string) { m.ProcessOpen(m.MergePod(m.Option(web.TARGET))) }},
web.OPS_ORIGIN_OPEN: {Hand: func(m *ice.Message, arg ...string) { messageCreateSpace(m, web.ORIGIN, "") }},
web.OPS_SERVER_OPEN: {Hand: func(m *ice.Message, arg ...string) { messageCreateSpace(m, web.SERVER, "") }},
web.OPS_DREAM_CREATE: {Hand: func(m *ice.Message, arg ...string) { messageCreateSpace(m, web.WORKER, "") }},
web.DREAM_CREATE: {Hand: func(m *ice.Message, arg ...string) {
if !m.IsCliUA() {
MessageInsertPlug(m, web.DREAM, "", "", web.DREAM, m.Option(mdb.NAME))
}
}},
web.OPS_DREAM_CREATE: {Hand: func(m *ice.Message, arg ...string) {
m.Cmd("", mdb.CREATE, mdb.TYPE, aaa.TECH, web.TARGET, kit.Keys(kit.Select("", ice.OPS, m.IsWorker()), m.Option(mdb.NAME)))
MessageInsertPlug(m, web.DREAM, "", "", web.DREAM, m.Option(mdb.NAME))
}},
web.DREAM_REMOVE: {Hand: func(m *ice.Message, arg ...string) {
MessageInsertPlug(m, web.DREAM, "", "", web.DREAM, m.Option(mdb.NAME))
}},
web.SPACE_LOGIN: {Hand: func(m *ice.Message, arg ...string) {
MessageInsertPlug(m, aaa.APPLY, "", "", web.CHAT_GRANT, m.Option(mdb.NAME))
}},
// web.SPACE_LOGIN: {Hand: func(m *ice.Message, arg ...string) { MessageInsertPlug(m, aaa.APPLY, "", "", web.CHAT_GRANT, m.Option(mdb.NAME)) }},
aaa.OFFER_CREATE: {Hand: func(m *ice.Message, arg ...string) {
MessageInsertPlug(m, aaa.APPLY, "", "", aaa.OFFER, m.Option(mdb.HASH))
}},
@ -114,6 +110,9 @@ func init() {
}},
})
}
func messageCreateSpace(m *ice.Message, kind, name string) {
m.Cmd("", mdb.CREATE, mdb.TYPE, kind, web.TARGET, kit.Keys(kit.Select("", ice.OPS, m.IsWorker()), kit.Select(m.Option(mdb.NAME), name)))
}
func MessageCreate(m *ice.Message, zone, icons string) {
if _, ok := m.CmdMap(MESSAGE, mdb.ZONE)[zone]; !ok {
m.Cmd(MESSAGE, mdb.CREATE, mdb.TYPE, aaa.TECH, mdb.ICONS, icons, mdb.ZONE, zone)

View File

@ -1,6 +1,5 @@
Volcanos(chat.ONIMPORT, {
_init: function(can, msg) {
// if (can.isCmdMode()) { can.onappend.style(can, html.OUTPUT) }
can.ui = can.onappend.layout(can), can.onimport._project(can, msg)
},
_project: function(can, msg) { var select, current = can.db.hash[0]||can.sup.db.current||ice.DEV
@ -10,12 +9,14 @@ Volcanos(chat.ONIMPORT, {
{icon: "bi bi-plus-lg", onclick: function(event) { can.Update(event, [ctx.ACTION, mdb.CREATE]) }},
]}], can.ui.project.firstChild, can.ui.project)
msg.Table(function(value) {
var _target = can.page.Append(can, can.ui.project, [{view: html.ITEM, list: [
var _target = can.page.Append(can, can.ui.project, [{view: [[html.ITEM, value.type]], list: [
{img: can.misc.Resource(can, value.icons||"usr/icons/Messages.png")}, {view: html.CONTAINER, list: [
{view: wiki.TITLE, list: [{text: value.title||can.base.trimPrefix(value.zone, "ops.")||"[未命名]"}, {text: [can.base.TimeTrim(value.time), "", mdb.TIME]}]},
{view: wiki.CONTENT, list: [{text: value.target||"[未知消息]"}]},
{view: wiki.TITLE, list: [{text: can.base.trimPrefix(value.title||value.zone, "ops.")||"[未命名]"}]},
{view: wiki.CONTENT, list: [{text: can.base.trimPrefix(value.target, "ops.")||"[未知消息]"}, {text: [can.base.TimeTrim(value.time), "", mdb.TIME]}]},
]},
], onclick: function(event) { can.isCmdMode() && can.misc.SearchHash(can, value.zone), can.onimport._switch(can, false)
], onclick: function(event) {
can.onexport.hash(can, value.zone), can.onexport.title(can, value.zone)
can.onimport._switch(can, false)
can.sup.db.current = value.zone
can.db.zone = value, can.db.hash = value.hash, can.onmotion.select(can, can.ui.project, html.DIV_ITEM, _target)
if (can.onmotion.cache(can, function(save, load) {
@ -38,7 +39,7 @@ Volcanos(chat.ONIMPORT, {
_content: function(can, msg) {
can.ui.title = can.page.Appends(can, can.ui.content, [{view: wiki.TITLE, list: [
{icon: "bi bi-chevron-left", onclick: function() { can.onimport._switch(can, true) }},
{text: can.db.zone.title||can.base.trimPrefix(can.db.zone.zone, "ops.")},
{text: can.base.trimPrefix(can.db.zone.title||can.db.zone.zone, "ops.")},
{icon: "bi bi-three-dots", onclick: function() { can.onmotion.toggle(can, can.ui.profile), can.onimport.layout(can) }},
]}])._target
can.ui.message = can.page.Append(can, can.ui.content, [{view: html.LIST}])._target, can.onimport._message(can, msg)
@ -88,7 +89,8 @@ Volcanos(chat.ONIMPORT, {
can.onmotion.toggle(can, can.ui.display, !project)
can.onimport.layout(can)
},
layout: function(can) { can.ui.layout(can.ConfHeight(), can.ConfWidth())
layout: function(can) { if (!can.ui.layout) { return }
can.ui.layout(can.ConfHeight(), can.ConfWidth())
can.ui.title && can.page.style(can, can.ui.message, html.HEIGHT, can.ui.content.offsetHeight-can.ui.title.offsetHeight)
can.page.style(can, can._output, html.HEIGHT, can.ConfHeight())
},

View File

@ -2,12 +2,12 @@ package oauth
import (
"path"
"strings"
"shylinux.com/x/ice"
"shylinux.com/x/icebergs/base/aaa"
"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/web"
"shylinux.com/x/icebergs/base/web/html"
@ -15,6 +15,7 @@ import (
)
const (
OAUTH = "oauth"
DOMAIN = "domain"
CLIENT_ID = "client_id"
CLIENT_SECRET = "client_secret"
@ -25,6 +26,9 @@ const (
USERS_URL = "users_url"
USER_KEY = "user_key"
NICK_KEY = "nick_key"
ICON_KEY = "icon_key"
SESS_CMD = "sess_cmd"
USER_CMD = "user_cmd"
REDIRECT_URI = "redirect_uri"
RESPONSE_TYPE = "response_type"
@ -42,15 +46,16 @@ const (
type Client struct {
ice.Hash
short string `data:"domain,client_id"`
field string `data:"time,hash,domain,client_id,client_secret,oauth_url,grant_url,token_url,users_url,scope,user_key,nick_key,api_prefix,token_prefix"`
sso string `name:"sso name* icons*" help:"登录"`
auth string `name:"auth" help:"授权" icon:"bi bi-person-check"`
user string `name:"user" help:"用户" icon:"bi bi-person-vcard"`
orgs string `name:"orgs" help:"组织"`
repo string `name:"repo" help:"资源"`
list string `name:"list hash auto" help:"授权" icon:"oauth.png"`
login string `name:"login" role:"void"`
short string `data:"domain,client_id"`
field string `data:"time,hash,domain,client_id,client_secret,oauth_url,grant_url,token_url,users_url,scope,login,user_key,user_cmd,sess_cmd,nick_key,icon_key,api_prefix,token_prefix"`
sso string `name:"sso name* help icons*" help:"登录"`
auth string `name:"auth" help:"授权" icon:"bi bi-person-check"`
user string `name:"user" help:"用户" icon:"bi bi-person-vcard"`
orgs string `name:"orgs" help:"组织"`
repo string `name:"repo" help:"资源"`
list string `name:"list hash auto" help:"授权" icon:"oauth.png"`
login string `name:"login" role:"void"`
login2 string `name:"login2" role:"void"`
}
var Inputs = map[string]map[string]string{}
@ -87,29 +92,51 @@ func (s Client) Inputs(m *ice.Message, arg ...string) {
}
}
}
func (s Client) List(m *ice.Message, arg ...string) {
s.Hash.List(m, arg...).PushAction(s.User, s.Auth, s.Sso, s.Remove).EchoScript(s.RedirectURI(m))
}
func (s Client) Sso(m *ice.Message, arg ...string) {
m.Cmd(web.CHAT_HEADER, mdb.CREATE, "oauth", m.Option(mdb.NAME), m.Option(mdb.ICONS), s.OAuthURL(m))
m.Cmd(web.CHAT_HEADER, mdb.CREATE, OAUTH, m.Option(mdb.NAME), m.Option(mdb.HELP), m.Option(mdb.ICONS), s.OAuthURL(m))
}
func (s Client) Auth(m *ice.Message, arg ...string) {
m.ProcessOpen(s.OAuthURL(m))
}
func (s Client) Link(m *ice.Message, arg ...string) {
m.Options(m.Cmd("", arg[0]).AppendSimple())
m.Echo(s.OAuthURL(m))
}
func (s Client) User(m *ice.Message, arg ...string) {
if res := s.Get(m, m.Option(mdb.HASH), m.Option(USERS_URL), arg...); res != nil {
m.Options(res).Cmd(aaa.USER, mdb.CREATE,
aaa.USERROLE, kit.Select(aaa.VOID, aaa.TECH, m.Option("is_admin") == ice.TRUE),
aaa.USERNAME, m.Option(aaa.USERNAME, m.Option(kit.Select(aaa.USERNAME, m.Option(USER_KEY)))),
aaa.USERNICK, m.Option(kit.Select("full_name", m.Option(NICK_KEY))),
aaa.USERZONE, m.Option(web.DOMAIN), aaa.AVATAR, m.Option(aaa.AVATAR_URL),
m.OptionSimple(aaa.LANGUAGE, aaa.EMAIL))
if m.Options(res); m.Warn(!kit.IsIn(m.Option("errcode"), "", "0"), m.Option("errmsg")) {
return
}
m.Info("user info %v", kit.Format(res))
if m.Option(USER_CMD) != "" {
m.Options("open_id", m.Option("openid"), aaa.USERNICK, m.Option("nickname"), aaa.AVATAR, m.Option("headimgurl"))
m.Cmdy(kit.Split(m.Option(USER_CMD)), m.OptionSimple("open_id"), kit.Simple(res))
return
}
username := m.Option(aaa.USERNAME, m.Option(kit.Select(aaa.USERNAME, m.Option(USER_KEY))))
if m.Cmd(aaa.USER, username).Length() > 0 {
m.Cmd(aaa.USER, mdb.MODIFY, aaa.USERNAME, username,
aaa.USERNICK, m.Option(kit.Select("full_name", m.Option(NICK_KEY))),
aaa.AVATAR, m.Option(kit.Select(aaa.AVATAR_URL, m.Option(ICON_KEY))),
)
} else {
m.Cmd(aaa.USER, mdb.CREATE,
aaa.USERROLE, kit.Select(aaa.VOID, aaa.TECH, m.Option("is_admin") == ice.TRUE),
aaa.USERNAME, username,
aaa.USERNICK, m.Option(kit.Select("full_name", m.Option(NICK_KEY))),
aaa.USERZONE, m.Option(web.DOMAIN),
aaa.AVATAR, m.Option(kit.Select(aaa.AVATAR_URL, m.Option(ICON_KEY))),
m.OptionSimple(aaa.LANGUAGE, aaa.EMAIL))
}
}
}
func (s Client) Orgs(m *ice.Message, arg ...string) {}
func (s Client) Repo(m *ice.Message, arg ...string) {}
func (s Client) List(m *ice.Message, arg ...string) {
s.Hash.List(m, arg...).PushAction(s.User, s.Auth, s.Sso, s.Remove).EchoScript(s.RedirectURI(m))
}
func init() { ice.ChatCtxCmd(Client{}) }
func init() { ice.Cmd("web.chat.oauth.client", Client{}) }
func (s Client) Login(m *ice.Message, arg ...string) {
if state, code := m.Option(STATE), m.Option(CODE); !m.WarnNotValid(state == "" || code == "") {
@ -130,17 +157,21 @@ func (s Client) Login(m *ice.Message, arg ...string) {
}
func (s Client) Login2(m *ice.Message, arg ...string) {
if state, code := m.Option(STATE), m.Option(CODE); !m.WarnNotValid(state == "" || code == "") {
s.Hash.List(m.Spawn(), m.Option(mdb.HASH, state)).Table(func(value ice.Maps) { m.Options(value) })
m.Options(GRANT_TYPE, AUTHORIZATION_CODE, REDIRECT_URI, s.RedirectURI(m))
if res := s.Get(m, m.Option(mdb.HASH), m.Option(GRANT_URL), m.OptionSimple(GRANT_TYPE, CODE, CLIENT_ID, CLIENT_SECRET, REDIRECT_URI)...); !m.WarnNotValid(res == nil) {
kit.Value(res, EXPIRES_IN, m.Time(kit.Format("%vs", kit.Int(kit.Value(res, EXPIRES_IN)))))
m.Options(res)
if s.User(m); !m.WarnNotValid(m.Option(aaa.USERNAME) == "") && m.R != nil {
m.Cmd(aaa.USER, mdb.MODIFY, m.OptionSimple(aaa.USERNAME), kit.Simple(res))
web.RenderCookie(m.Message, aaa.SessCreate(m.Message, m.Option(aaa.USERNAME)))
m.ProcessHistory()
} else {
m.ProcessClose()
msg := m.Spawn()
s.Hash.List(msg, m.Option(mdb.HASH, state)).Table(func(value ice.Maps) { msg.Options(value) })
msg.Options(GRANT_TYPE, AUTHORIZATION_CODE, REDIRECT_URI, s.RedirectURI(msg)).Option(ACCESS_TOKEN, "")
if res := s.Get(msg, msg.Option(mdb.HASH), msg.Option(GRANT_URL), kit.Simple(msg.OptionSimple(GRANT_TYPE, CODE), "appid", msg.Option(CLIENT_ID), "secret", msg.Option(CLIENT_SECRET))...); !m.WarnNotValid(res == nil) {
if msg.Options(res); m.Warn(!kit.IsIn(msg.Option("errcode"), "", "0"), msg.Option("errmsg")) {
return
}
m.Info("token info %v", kit.Format(res))
msg.Option(EXPIRES_IN, m.Time(kit.Format("%vs", kit.Int(msg.Option(EXPIRES_IN)))))
if s.User(msg, msg.OptionSimple("openid")...); !m.Warn(msg.Option(aaa.USERNAME) == "" && msg.Option("user_uid") == "") {
if msg.Option(SESS_CMD) != "" {
m.Cmdy(kit.Split(msg.Option(SESS_CMD)), kit.Dict("user_uid", msg.Option("user_uid")))
} else {
m.ProcessCookie(ice.MSG_SESSID, aaa.SessCreate(m.Message, msg.Option(aaa.USERNAME)), "-2")
}
}
}
}
@ -149,7 +180,7 @@ func (s Client) OAuthURL(m *ice.Message) string {
return kit.MergeURL2(m.Option(web.DOMAIN), m.Option(OAUTH_URL), RESPONSE_TYPE, CODE, m.OptionSimple(CLIENT_ID), REDIRECT_URI, s.RedirectURI(m), m.OptionSimple(SCOPE), STATE, m.Option(mdb.HASH))
}
func (s Client) RedirectURI(m *ice.Message) string {
return strings.Split(m.MergeLink(web.ChatCmdPath(m.Message, m.ShortKey(), ctx.ACTION, aaa.LOGIN)), web.QS)[0]
return m.MergeLink(web.ChatCmdPath(m.Message, m.ShortKey(), ctx.ACTION, kit.Select(aaa.LOGIN, m.Option(aaa.LOGIN))), log.DEBUG, m.Option(log.DEBUG))
}
func (s Client) Get(m *ice.Message, hash, api string, arg ...string) ice.Any {

Some files were not shown because too many files have changed in this diff Show More