mirror of
https://github.com/rustdesk/rustdesk.git
synced 2026-02-19 07:09:10 +08:00
Compare commits
601 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d716e2b40c | ||
|
|
c9cd57e178 | ||
|
|
388dcbeb6d | ||
|
|
a8ad9e9c46 | ||
|
|
8a3da687c1 | ||
|
|
0e4e7fcb9b | ||
|
|
663c5bc355 | ||
|
|
7235756603 | ||
|
|
f6612d39bf | ||
|
|
a9ada68bfc | ||
|
|
f21788b967 | ||
|
|
f90f83fbda | ||
|
|
1235edb239 | ||
|
|
e2c9b78254 | ||
|
|
8df1e42977 | ||
|
|
69b3f6660a | ||
|
|
c1f5c20e94 | ||
|
|
de44e45ed6 | ||
|
|
0b6155bab8 | ||
|
|
8995011d45 | ||
|
|
bbe902d92e | ||
|
|
33c6095eca | ||
|
|
e66ccdca9d | ||
|
|
36607bf8b0 | ||
|
|
4dfd57ea19 | ||
|
|
3566b0ee7a | ||
|
|
05ac26e5fe | ||
|
|
f1d187739c | ||
|
|
e2161bcc43 | ||
|
|
ec700ad37d | ||
|
|
81cd079faa | ||
|
|
7854ad5ee1 | ||
|
|
65b335177a | ||
|
|
eaa481cbea | ||
|
|
4d5d0a4c62 | ||
|
|
264db496ff | ||
|
|
f42a77ad22 | ||
|
|
6bc0c3ce98 | ||
|
|
ae74570ab8 | ||
|
|
5bf8e8f001 | ||
|
|
cfa0c1039c | ||
|
|
aa7779bcf7 | ||
|
|
5d143f57d7 | ||
|
|
f8fe47d53f | ||
|
|
1e120eef18 | ||
|
|
ccffa14450 | ||
|
|
d858790170 | ||
|
|
19468cdbcd | ||
|
|
c79c55d643 | ||
|
|
4829b87546 | ||
|
|
605a52aebb | ||
|
|
da166223bc | ||
|
|
fef8b0f246 | ||
|
|
11086ffa49 | ||
|
|
f000d0c4ca | ||
|
|
88107f342d | ||
|
|
9dff6ee649 | ||
|
|
8f4adab3c8 | ||
|
|
92be77cf88 | ||
|
|
885d3a6651 | ||
|
|
c0af51e1bd | ||
|
|
f95f9e408a | ||
|
|
915edf49ab | ||
|
|
4e2a44e392 | ||
|
|
bbdf3fc9a3 | ||
|
|
110d63f526 | ||
|
|
75c9a8c561 | ||
|
|
609996005f | ||
|
|
aeb2846d15 | ||
|
|
f915ab3e79 | ||
|
|
8d1f1a9ab4 | ||
|
|
fa2407d857 | ||
|
|
840413db5f | ||
|
|
f370c60d06 | ||
|
|
0a9a7e3090 | ||
|
|
f7f0146c85 | ||
|
|
a29de132a3 | ||
|
|
6d122d8aef | ||
|
|
fb98209008 | ||
|
|
a56aa08a66 | ||
|
|
3ea33f7203 | ||
|
|
75c9bbb30f | ||
|
|
1c84fc3786 | ||
|
|
08330cdaeb | ||
|
|
908a7071a7 | ||
|
|
3cd2892bdd | ||
|
|
f964827f00 | ||
|
|
16ba58aad3 | ||
|
|
176045468f | ||
|
|
bb58d7f69a | ||
|
|
7824fe1f18 | ||
|
|
0dd4087408 | ||
|
|
cc42fee9ea | ||
|
|
82f2431eb8 | ||
|
|
e1c9b607fb | ||
|
|
9136b3e3f8 | ||
|
|
c03c49d482 | ||
|
|
3cba56c809 | ||
|
|
1e0a347893 | ||
|
|
7c5d260738 | ||
|
|
b31eea0279 | ||
|
|
561a0d20ed | ||
|
|
117bbb3409 | ||
|
|
974c259a3d | ||
|
|
957eabcef0 | ||
|
|
1eb696356e | ||
|
|
b734e8aee9 | ||
|
|
e6bf858ae1 | ||
|
|
b350fbdb9c | ||
|
|
eaeceeac29 | ||
|
|
3f57604891 | ||
|
|
565e81d329 | ||
|
|
362aa9a8ff | ||
|
|
4f0a58a691 | ||
|
|
88ac9e9d11 | ||
|
|
ffb0fa4349 | ||
|
|
6c5b7b3b89 | ||
|
|
74c3f1d7cc | ||
|
|
617f87a797 | ||
|
|
c632b0e8fb | ||
|
|
dfd128c817 | ||
|
|
71fb27fe4b | ||
|
|
dcad90e073 | ||
|
|
b8f7e347c3 | ||
|
|
ab1805281f | ||
|
|
1758aa0f1e | ||
|
|
bcda7d3193 | ||
|
|
3a7647f48b | ||
|
|
bf0270323c | ||
|
|
488b2455b7 | ||
|
|
db6f46f165 | ||
|
|
c4491b0248 | ||
|
|
cd7b7cc555 | ||
|
|
e2eef09373 | ||
|
|
ce46fe7d80 | ||
|
|
064879d9d2 | ||
|
|
8648c70df4 | ||
|
|
9cc3cf92ab | ||
|
|
b19d3f5a1c | ||
|
|
2bcc08f084 | ||
|
|
aa5c7cc38e | ||
|
|
8460c1ac42 | ||
|
|
944fde15a4 | ||
|
|
5a07701b90 | ||
|
|
8770552448 | ||
|
|
4fb8de9b68 | ||
|
|
01591d1abf | ||
|
|
128a4aca69 | ||
|
|
555ff0085a | ||
|
|
2f6b457b3f | ||
|
|
8834251eec | ||
|
|
69769cc123 | ||
|
|
82d5924401 | ||
|
|
4a03c60ac1 | ||
|
|
f11ca64eac | ||
|
|
9f238bd7ff | ||
|
|
0ce67973f6 | ||
|
|
6fa8138568 | ||
|
|
270c927d2f | ||
|
|
c117eaee2e | ||
|
|
a4fcb8d7c1 | ||
|
|
100daf4031 | ||
|
|
3b3958ed20 | ||
|
|
4e9a96dad9 | ||
|
|
1c7f9b6f45 | ||
|
|
2786fc97e9 | ||
|
|
d7becdfa9f | ||
|
|
df4ecf9339 | ||
|
|
a4ba033284 | ||
|
|
57722c950a | ||
|
|
691b85b3fc | ||
|
|
c7191023cb | ||
|
|
3aa111b16c | ||
|
|
2b64375ab0 | ||
|
|
b7c1222ce1 | ||
|
|
3dbd62f867 | ||
|
|
78be555931 | ||
|
|
c31830f7c4 | ||
|
|
ed0c234b03 | ||
|
|
52919fd77b | ||
|
|
104c022b26 | ||
|
|
9b22ee765d | ||
|
|
e80869af67 | ||
|
|
0b182b9acd | ||
|
|
1ca94d7f81 | ||
|
|
b0e6a59ded | ||
|
|
2f4d02c2bf | ||
|
|
835db29c3f | ||
|
|
933969d1fe | ||
|
|
e407ba3a33 | ||
|
|
6672087f7c | ||
|
|
8bb4183098 | ||
|
|
db2b912b3e | ||
|
|
fc159fa1f1 | ||
|
|
d87f29c679 | ||
|
|
a4d34aacea | ||
|
|
e92700f3f9 | ||
|
|
8ce94e04b6 | ||
|
|
3c29b8a58a | ||
|
|
08fdeb7d4b | ||
|
|
4df09f4aec | ||
|
|
4945605009 | ||
|
|
d313fa92e1 | ||
|
|
aa1c0df08f | ||
|
|
dddbae4eb1 | ||
|
|
6143a3c649 | ||
|
|
6c05f72d90 | ||
|
|
809c220eaf | ||
|
|
3ec69b6d97 | ||
|
|
5a0f8d008e | ||
|
|
eb49af843c | ||
|
|
9c6715f95e | ||
|
|
39ea73657d | ||
|
|
7d14ce98e1 | ||
|
|
3112792b7b | ||
|
|
cd62d7024b | ||
|
|
bc3d3bd0ec | ||
|
|
484f50811d | ||
|
|
2a11bc63ce | ||
|
|
64071943fc | ||
|
|
29ca2ed14d | ||
|
|
e23a6805e3 | ||
|
|
5a9803c2c8 | ||
|
|
b5f056c0c0 | ||
|
|
495cc9056e | ||
|
|
6a19b8caa1 | ||
|
|
2719936ea9 | ||
|
|
4108635b34 | ||
|
|
9118511bbd | ||
|
|
7b06dab4ee | ||
|
|
ea2fe3eff0 | ||
|
|
1cda704628 | ||
|
|
a3511d9157 | ||
|
|
98aa410683 | ||
|
|
bf578e768b | ||
|
|
372b715162 | ||
|
|
b0ddd3d543 | ||
|
|
a474f904b1 | ||
|
|
cd9faf48f3 | ||
|
|
b76a1d36cb | ||
|
|
893d8b39c9 | ||
|
|
326eed5ee0 | ||
|
|
a1b9e1b229 | ||
|
|
4b51fffc96 | ||
|
|
3485d2ddc7 | ||
|
|
92a1bb04e9 | ||
|
|
02cbc0d407 | ||
|
|
e0637f966a | ||
|
|
5af1258454 | ||
|
|
a12f24bf16 | ||
|
|
9651666d41 | ||
|
|
6bd730bc67 | ||
|
|
35816d4fbb | ||
|
|
647721a37e | ||
|
|
25492c815c | ||
|
|
a1c4b08535 | ||
|
|
8f998771c9 | ||
|
|
f47dcd1a8b | ||
|
|
d069b73303 | ||
|
|
6fe4344cb0 | ||
|
|
4fe5d2cf02 | ||
|
|
95239fc148 | ||
|
|
5fb613d4b2 | ||
|
|
c8df8ae551 | ||
|
|
d0ca9de946 | ||
|
|
0a2bc1cf8a | ||
|
|
d5286782cd | ||
|
|
07aa0898c5 | ||
|
|
4d37a9ee23 | ||
|
|
1fda4c257d | ||
|
|
fea4b068cd | ||
|
|
e23eb3e79b | ||
|
|
78450fda08 | ||
|
|
78f2d3f31f | ||
|
|
b4f61c735e | ||
|
|
7944e0bc36 | ||
|
|
780b57f597 | ||
|
|
29bb10a40a | ||
|
|
8e6dd76c5b | ||
|
|
9be6b17a8b | ||
|
|
7b1806b0f3 | ||
|
|
f45a2c7a94 | ||
|
|
81e43c2970 | ||
|
|
e51e5ac4b1 | ||
|
|
1995f9fa4e | ||
|
|
88f0f67ee3 | ||
|
|
d379f23490 | ||
|
|
75ef279e47 | ||
|
|
5b03e99404 | ||
|
|
2e03ca19f6 | ||
|
|
3aebc43111 | ||
|
|
8ea5d80f01 | ||
|
|
4071f803f7 | ||
|
|
65eef2b579 | ||
|
|
9c9855877d | ||
|
|
9a92b6ac4a | ||
|
|
b400e4305f | ||
|
|
dfeb9a29c1 | ||
|
|
e2a879692d | ||
|
|
3a6dc19616 | ||
|
|
ae79a36f7b | ||
|
|
3212290f6e | ||
|
|
d07ae9f2c6 | ||
|
|
3f56c82c7b | ||
|
|
a0c704f36e | ||
|
|
baccff8f99 | ||
|
|
0a294d9ff3 | ||
|
|
03fb47b312 | ||
|
|
29f15aabed | ||
|
|
089acaa6e7 | ||
|
|
709a2a30bc | ||
|
|
54269b6f5d | ||
|
|
a7a4cd7eac | ||
|
|
26d161f827 | ||
|
|
9df1fcb783 | ||
|
|
e82f040d6d | ||
|
|
1931cb8c7c | ||
|
|
32c5437c5d | ||
|
|
1b61b77fbe | ||
|
|
c0b6367137 | ||
|
|
12ab22e048 | ||
|
|
7bde8a3713 | ||
|
|
9c55e1efc8 | ||
|
|
b24e16d6c1 | ||
|
|
6767dda246 | ||
|
|
5f61c2442a | ||
|
|
5631ffac4c | ||
|
|
78097f4006 | ||
|
|
1d8cdb5e93 | ||
|
|
3e590b8212 | ||
|
|
533efd04d7 | ||
|
|
fb392b81cb | ||
|
|
cbcad03bc6 | ||
|
|
2ec5f8fe7e | ||
|
|
875570e040 | ||
|
|
6d506cbb64 | ||
|
|
b17bda9a55 | ||
|
|
d6b56a2f35 | ||
|
|
64f181e4a1 | ||
|
|
1552402907 | ||
|
|
f0a6c706fa | ||
|
|
042114ae37 | ||
|
|
241623c406 | ||
|
|
40730cbbae | ||
|
|
cedc384ba1 | ||
|
|
15f3c36c5f | ||
|
|
ee088a8ddf | ||
|
|
cb1818ab37 | ||
|
|
66af938858 | ||
|
|
e26a838882 | ||
|
|
e0bb25cbe5 | ||
|
|
3491c79cbc | ||
|
|
365fc90d8b | ||
|
|
8be7331cb6 | ||
|
|
ea46d2493e | ||
|
|
1141be01f5 | ||
|
|
6c713f3135 | ||
|
|
3059ca061e | ||
|
|
2631c68b88 | ||
|
|
f69f6bc8d4 | ||
|
|
66e39b62a2 | ||
|
|
993a419793 | ||
|
|
f1444049bf | ||
|
|
da629ec42c | ||
|
|
7225c1fcf0 | ||
|
|
dbdff120bc | ||
|
|
51f4f736bc | ||
|
|
d4d90da196 | ||
|
|
9903e9df9e | ||
|
|
af218dbc83 | ||
|
|
b3e3f6151d | ||
|
|
3d39d9c27c | ||
|
|
589177fc94 | ||
|
|
4703a7d332 | ||
|
|
8d90c5a93b | ||
|
|
885d8a4586 | ||
|
|
0e8fc4a815 | ||
|
|
96afb88518 | ||
|
|
a30aaebc72 | ||
|
|
252d3cb797 | ||
|
|
26a4b1f3eb | ||
|
|
dc724a30e7 | ||
|
|
334c94ceb3 | ||
|
|
b6feaa695f | ||
|
|
5f190297a9 | ||
|
|
35462eecfe | ||
|
|
d00352f4e4 | ||
|
|
5682b088de | ||
|
|
bcbe9ccbe5 | ||
|
|
87f50a6318 | ||
|
|
362b5594a2 | ||
|
|
b9d8de1ec1 | ||
|
|
8a6b33b841 | ||
|
|
3ffd8ac146 | ||
|
|
07ea52d620 | ||
|
|
4cb967251b | ||
|
|
29905608b5 | ||
|
|
36db9f65cd | ||
|
|
91445da094 | ||
|
|
083d6c591a | ||
|
|
e352ea67f4 | ||
|
|
4103ab70a7 | ||
|
|
fd9d6db2ed | ||
|
|
d0b15fbd2a | ||
|
|
7c42c04b23 | ||
|
|
81e4998a37 | ||
|
|
1ab5bb0a2e | ||
|
|
0f39626782 | ||
|
|
dc2edcec5d | ||
|
|
3198236a8c | ||
|
|
e044212eb6 | ||
|
|
33e8f2aa85 | ||
|
|
031ca4e50c | ||
|
|
73d0da726d | ||
|
|
5c97f5dce5 | ||
|
|
8d5aa731a1 | ||
|
|
e8c5a63986 | ||
|
|
46fe37015f | ||
|
|
b79f086df5 | ||
|
|
6afb6aaff2 | ||
|
|
5a1ab37171 | ||
|
|
5e0bf8f5a9 | ||
|
|
7964afeb84 | ||
|
|
3759347d47 | ||
|
|
2758f6b7d5 | ||
|
|
70a4ee4318 | ||
|
|
7f13edd14a | ||
|
|
96208e9fef | ||
|
|
e6bd5b0698 | ||
|
|
231231e51f | ||
|
|
247ea5fed3 | ||
|
|
0cf2db9239 | ||
|
|
318e3cbd7d | ||
|
|
5164f76919 | ||
|
|
972ec8d79d | ||
|
|
516904551c | ||
|
|
1bf80e3dd6 | ||
|
|
8f22273759 | ||
|
|
1ddd5203e5 | ||
|
|
62d2c0fb6d | ||
|
|
0db250f02a | ||
|
|
8be912a8cf | ||
|
|
03f913e49d | ||
|
|
fb126164ef | ||
|
|
eea85b9b5a | ||
|
|
b16b2bc1b4 | ||
|
|
55d21ab151 | ||
|
|
d25e17317d | ||
|
|
7a7cca7e45 | ||
|
|
0ef4246360 | ||
|
|
686e495171 | ||
|
|
c0db2e6da4 | ||
|
|
c0459b8f94 | ||
|
|
678a3d2d28 | ||
|
|
2894a5ab7b | ||
|
|
2efd0e61b4 | ||
|
|
18b1646cd4 | ||
|
|
66cdbbacd0 | ||
|
|
aaba4c144c | ||
|
|
2d5758e880 | ||
|
|
b20ec86fac | ||
|
|
1df5234eea | ||
|
|
1b8dbbeac9 | ||
|
|
c5f1222476 | ||
|
|
1009eabdfe | ||
|
|
8138a661a6 | ||
|
|
d369955790 | ||
|
|
0afca9d1ea | ||
|
|
0325500ebf | ||
|
|
b0dfd777fb | ||
|
|
1a54c50c6f | ||
|
|
5d26dbaa90 | ||
|
|
c52f4af17d | ||
|
|
b2a6c592ba | ||
|
|
2df4da89dc | ||
|
|
aaffbe476e | ||
|
|
dae3a2b43b | ||
|
|
64b4d14629 | ||
|
|
d03172e2f3 | ||
|
|
44f6233df0 | ||
|
|
88a3266a73 | ||
|
|
3cd9ee2aa3 | ||
|
|
a76916c520 | ||
|
|
2102813ed9 | ||
|
|
c970e5b22b | ||
|
|
3a7d64bf34 | ||
|
|
4e85841398 | ||
|
|
6130792734 | ||
|
|
61caaa3365 | ||
|
|
c3a3c1a1c7 | ||
|
|
e510d2744d | ||
|
|
bb25964307 | ||
|
|
8affa24400 | ||
|
|
ad182a5f3c | ||
|
|
6ed9526a65 | ||
|
|
ccd1cab6bc | ||
|
|
ab4843b76e | ||
|
|
3200002e52 | ||
|
|
9d7dced7e7 | ||
|
|
a70e3e93b0 | ||
|
|
646b11a3ae | ||
|
|
eb76f7cecc | ||
|
|
39f0dd28b4 | ||
|
|
66bd97c0b3 | ||
|
|
a0b2450888 | ||
|
|
f558c12866 | ||
|
|
c385d88708 | ||
|
|
2e305e8f11 | ||
|
|
e949023dda | ||
|
|
25c10453e5 | ||
|
|
935676468b | ||
|
|
49dff161dd | ||
|
|
7282a462f4 | ||
|
|
a740870b67 | ||
|
|
cd9c189c64 | ||
|
|
905a3a2936 | ||
|
|
e6744d031d | ||
|
|
a3f5ffc15a | ||
|
|
191fdc6691 | ||
|
|
f07ce11425 | ||
|
|
7324cb607c | ||
|
|
1ee92c9f68 | ||
|
|
9a86a595ff | ||
|
|
879c300563 | ||
|
|
bebe136834 | ||
|
|
d89d5ef825 | ||
|
|
56dfcffd1e | ||
|
|
7c5915e3d3 | ||
|
|
cb2864202f | ||
|
|
dae2814951 | ||
|
|
6922a1de4c | ||
|
|
7282c3a16d | ||
|
|
c15c44788c | ||
|
|
d83163b6a0 | ||
|
|
5383c09e3d | ||
|
|
6f8483ece6 | ||
|
|
e65aa61fb7 | ||
|
|
2522c99f47 | ||
|
|
fcf24e04bd | ||
|
|
2ec5fbb333 | ||
|
|
c1b241a8d1 | ||
|
|
b13aef98c2 | ||
|
|
b25c2c0551 | ||
|
|
e303a3b9b8 | ||
|
|
ec8255b20f | ||
|
|
529048bb8e | ||
|
|
926d3ca546 | ||
|
|
7d316f9a51 | ||
|
|
c27865d3ed | ||
|
|
d769b79a6f | ||
|
|
3aa4bdd1fa | ||
|
|
ad8b23d1a7 | ||
|
|
e8b8a260fd | ||
|
|
b4467370a8 | ||
|
|
25ffaa7966 | ||
|
|
00b2b30778 | ||
|
|
78692793a5 | ||
|
|
5b9c90809c | ||
|
|
05c4dacbe9 | ||
|
|
6f796db523 | ||
|
|
2d515815ed | ||
|
|
dc3fcda2c9 | ||
|
|
25a83f6b4a | ||
|
|
086d1f9124 | ||
|
|
5339b40104 | ||
|
|
be9f0a22a0 | ||
|
|
fc3f76973d | ||
|
|
0d0c75e2a9 | ||
|
|
da7e044f16 | ||
|
|
2ccbda2bb8 | ||
|
|
87e161eddb | ||
|
|
592630fac4 | ||
|
|
aa67aab1f2 | ||
|
|
7e873f1c8b | ||
|
|
ba00e4daf2 | ||
|
|
8ef831ee5c | ||
|
|
7cc5d138a0 | ||
|
|
7b4d5bc704 | ||
|
|
a4a09d5bfc | ||
|
|
c8465f9a5d | ||
|
|
2159423431 | ||
|
|
9d5cfb04ac | ||
|
|
43200f236a | ||
|
|
9383e4ecbb | ||
|
|
6862406e68 | ||
|
|
c3b6dabcc8 | ||
|
|
a99e6f38e5 | ||
|
|
142eebc9e2 | ||
|
|
ec294451e3 | ||
|
|
7daeddf560 | ||
|
|
562b0c79dd | ||
|
|
b0f3ec40ce | ||
|
|
51903ede3d | ||
|
|
e06217536b | ||
|
|
002ca33cec | ||
|
|
cd21f61d9c | ||
|
|
3a570de31e | ||
|
|
d7b9c1aa72 | ||
|
|
c05dd0b1b7 | ||
|
|
7a8cf58ab1 | ||
|
|
7b067ed28d |
4
.cargo/config.toml
Normal file
4
.cargo/config.toml
Normal file
@@ -0,0 +1,4 @@
|
||||
[target.'cfg(target_os="macos")']
|
||||
rustflags = [
|
||||
"-C", "link-args=-sectcreate __CGPreLoginApp __cgpreloginapp /dev/null",
|
||||
]
|
||||
1
.gitattributes
vendored
Normal file
1
.gitattributes
vendored
Normal file
@@ -0,0 +1 @@
|
||||
* text=auto
|
||||
32
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
32
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
---
|
||||
name: Bug Report
|
||||
about: Report a bug (English only, Please).
|
||||
title: ""
|
||||
labels: bug
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
<!-- Hey there, thank you for creating an issue! -->
|
||||
|
||||
**Describe the bug you encountered:**
|
||||
|
||||
...
|
||||
|
||||
**What did you expect to happen instead?**
|
||||
|
||||
...
|
||||
|
||||
|
||||
**How did you install `RustDesk`?**
|
||||
|
||||
<!-- GitHub release, build from source, Windows portable version, etc. -->
|
||||
|
||||
---
|
||||
|
||||
**RustDesk version and environment**
|
||||
|
||||
<!--
|
||||
In order to reproduce your issue, please add some information about the environment
|
||||
in which you're running RustDesk.
|
||||
-->
|
||||
2
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
2
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
blank_issues_enabled: true
|
||||
|
||||
10
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
10
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
---
|
||||
name: Feature Request
|
||||
about: Suggest an idea for this project ((English only, Please).
|
||||
title: ''
|
||||
labels: feature-request
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
|
||||
10
.github/ISSUE_TEMPLATE/question.md
vendored
Normal file
10
.github/ISSUE_TEMPLATE/question.md
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
---
|
||||
name: Question
|
||||
about: Ask a question about 'RustDesk' (English only, Please).
|
||||
title: ''
|
||||
labels: question
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
|
||||
181
.github/workflows/ci.yml
vendored
Normal file
181
.github/workflows/ci.yml
vendored
Normal file
@@ -0,0 +1,181 @@
|
||||
name: CI
|
||||
|
||||
# env:
|
||||
# MIN_SUPPORTED_RUST_VERSION: "1.46.0"
|
||||
# CICD_INTERMEDIATES_DIR: "_cicd-intermediates"
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
tags:
|
||||
- '*'
|
||||
|
||||
jobs:
|
||||
# ensure_cargo_fmt:
|
||||
# name: Ensure 'cargo fmt' has been run
|
||||
# runs-on: ubuntu-20.04
|
||||
# steps:
|
||||
# - uses: actions-rs/toolchain@v1
|
||||
# with:
|
||||
# toolchain: stable
|
||||
# default: true
|
||||
# profile: minimal
|
||||
# components: rustfmt
|
||||
# - uses: actions/checkout@v2
|
||||
# - run: cargo fmt -- --check
|
||||
|
||||
# min_version:
|
||||
# name: Minimum supported rust version
|
||||
# runs-on: ubuntu-20.04
|
||||
# steps:
|
||||
# - name: Checkout source code
|
||||
# uses: actions/checkout@v2
|
||||
|
||||
# - name: Install rust toolchain (v${{ env.MIN_SUPPORTED_RUST_VERSION }})
|
||||
# uses: actions-rs/toolchain@v1
|
||||
# with:
|
||||
# toolchain: ${{ env.MIN_SUPPORTED_RUST_VERSION }}
|
||||
# default: true
|
||||
# profile: minimal # minimal component installation (ie, no documentation)
|
||||
# components: clippy
|
||||
# - name: Run clippy (on minimum supported rust version to prevent warnings we can't fix)
|
||||
# uses: actions-rs/cargo@v1
|
||||
# with:
|
||||
# command: clippy
|
||||
# args: --locked --all-targets --all-features -- --allow clippy::unknown_clippy_lints
|
||||
# - name: Run tests
|
||||
# uses: actions-rs/cargo@v1
|
||||
# with:
|
||||
# command: test
|
||||
# args: --locked
|
||||
|
||||
build:
|
||||
name: ${{ matrix.job.target }} (${{ matrix.job.os }})
|
||||
runs-on: ${{ matrix.job.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
job:
|
||||
# - { target: aarch64-unknown-linux-gnu , os: ubuntu-20.04, use-cross: true }
|
||||
# - { target: arm-unknown-linux-gnueabihf , os: ubuntu-20.04, use-cross: true }
|
||||
# - { target: arm-unknown-linux-musleabihf, os: ubuntu-20.04, use-cross: true }
|
||||
# - { target: i686-pc-windows-msvc , os: windows-2019 }
|
||||
# - { target: i686-unknown-linux-gnu , os: ubuntu-20.04, use-cross: true }
|
||||
# - { target: i686-unknown-linux-musl , os: ubuntu-20.04, use-cross: true }
|
||||
# - { target: x86_64-apple-darwin , os: macos-10.15 }
|
||||
# - { target: x86_64-pc-windows-gnu , os: windows-2019 }
|
||||
# - { target: x86_64-pc-windows-msvc , os: windows-2019 }
|
||||
- { target: x86_64-unknown-linux-gnu , os: ubuntu-20.04 }
|
||||
# - { target: x86_64-unknown-linux-musl , os: ubuntu-20.04, use-cross: true }
|
||||
steps:
|
||||
- name: Checkout source code
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Install prerequisites
|
||||
shell: bash
|
||||
run: |
|
||||
case ${{ matrix.job.target }} in
|
||||
x86_64-unknown-linux-gnu) sudo apt-get -y update ; sudo apt install -y g++ gcc git curl wget nasm yasm libgtk-3-dev clang libxcb-randr0-dev libxdo-dev libxfixes-dev libxcb-shape0-dev libxcb-xfixes0-dev libasound2-dev libpulse-dev cmake ;;
|
||||
# arm-unknown-linux-*) sudo apt-get -y update ; sudo apt-get -y install gcc-arm-linux-gnueabihf ;;
|
||||
# aarch64-unknown-linux-gnu) sudo apt-get -y update ; sudo apt-get -y install gcc-aarch64-linux-gnu ;;
|
||||
esac
|
||||
|
||||
- name: Restore from cache and install vcpkg
|
||||
uses: lukka/run-vcpkg@v7
|
||||
with:
|
||||
setupOnly: true
|
||||
vcpkgGitCommitId: '1d4128f08e30cec31b94500840c7eca8ebc579cb'
|
||||
|
||||
- name: Install vcpkg dependencies
|
||||
run: |
|
||||
$VCPKG_ROOT/vcpkg install libvpx libyuv opus
|
||||
shell: bash
|
||||
|
||||
- name: Install Rust toolchain
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
target: ${{ matrix.job.target }}
|
||||
override: true
|
||||
profile: minimal # minimal component installation (ie, no documentation)
|
||||
|
||||
- name: Show version information (Rust, cargo, GCC)
|
||||
shell: bash
|
||||
run: |
|
||||
gcc --version || true
|
||||
rustup -V
|
||||
rustup toolchain list
|
||||
rustup default
|
||||
cargo -V
|
||||
rustc -V
|
||||
|
||||
- uses: Swatinem/rust-cache@v1
|
||||
|
||||
- name: Build
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
use-cross: ${{ matrix.job.use-cross }}
|
||||
command: build
|
||||
args: --locked --release --target=${{ matrix.job.target }}
|
||||
|
||||
# - name: Strip debug information from executable
|
||||
# id: strip
|
||||
# shell: bash
|
||||
# run: |
|
||||
# # Figure out suffix of binary
|
||||
# EXE_suffix=""
|
||||
# case ${{ matrix.job.target }} in
|
||||
# *-pc-windows-*) EXE_suffix=".exe" ;;
|
||||
# esac;
|
||||
|
||||
# # Figure out what strip tool to use if any
|
||||
# STRIP="strip"
|
||||
# case ${{ matrix.job.target }} in
|
||||
# arm-unknown-linux-*) STRIP="arm-linux-gnueabihf-strip" ;;
|
||||
# aarch64-unknown-linux-gnu) STRIP="aarch64-linux-gnu-strip" ;;
|
||||
# *-pc-windows-msvc) STRIP="" ;;
|
||||
# esac;
|
||||
|
||||
# # Setup paths
|
||||
# BIN_DIR="${{ env.CICD_INTERMEDIATES_DIR }}/stripped-release-bin/"
|
||||
# mkdir -p "${BIN_DIR}"
|
||||
# BIN_NAME="${{ env.PROJECT_NAME }}${EXE_suffix}"
|
||||
# BIN_PATH="${BIN_DIR}/${BIN_NAME}"
|
||||
|
||||
# # Copy the release build binary to the result location
|
||||
# cp "target/${{ matrix.job.target }}/release/${BIN_NAME}" "${BIN_DIR}"
|
||||
|
||||
# # Also strip if possible
|
||||
# if [ -n "${STRIP}" ]; then
|
||||
# "${STRIP}" "${BIN_PATH}"
|
||||
# fi
|
||||
|
||||
# # Let subsequent steps know where to find the (stripped) bin
|
||||
# echo ::set-output name=BIN_PATH::${BIN_PATH}
|
||||
# echo ::set-output name=BIN_NAME::${BIN_NAME}
|
||||
|
||||
- name: Set testing options
|
||||
id: test-options
|
||||
shell: bash
|
||||
run: |
|
||||
# test only library unit tests and binary for arm-type targets
|
||||
unset CARGO_TEST_OPTIONS
|
||||
unset CARGO_TEST_OPTIONS ; case ${{ matrix.job.target }} in arm-* | aarch64-*) CARGO_TEST_OPTIONS="--lib --bin ${PROJECT_NAME}" ;; esac;
|
||||
echo ::set-output name=CARGO_TEST_OPTIONS::${CARGO_TEST_OPTIONS}
|
||||
|
||||
- name: Build tests
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
use-cross: ${{ matrix.job.use-cross }}
|
||||
command: build
|
||||
args: --locked --tests --target=${{ matrix.job.target }}
|
||||
|
||||
# - name: Run tests
|
||||
# uses: actions-rs/cargo@v1
|
||||
# with:
|
||||
# use-cross: ${{ matrix.job.use-cross }}
|
||||
# command: test
|
||||
# args: --locked --target=${{ matrix.job.target }} ${{ steps.test-options.outputs.CARGO_TEST_OPTIONS}}
|
||||
30
.github/workflows/snap-ci.yml
vendored
Normal file
30
.github/workflows/snap-ci.yml
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
name: Snap CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
paths-ignore:
|
||||
- README.md
|
||||
tags:
|
||||
- '*'
|
||||
|
||||
jobs:
|
||||
build-snap-master-package:
|
||||
runs-on: ubuntu-18.04
|
||||
|
||||
steps:
|
||||
- name: Check out Git repository
|
||||
uses: actions/checkout@v2
|
||||
- name: Use Snapcraft
|
||||
uses: snapcore/action-build@v1
|
||||
id: build
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: rustdesk.snap
|
||||
path: ${{ steps.build.outputs.snap }}
|
||||
# - uses: snapcore/action-publish@v1
|
||||
# with:
|
||||
# store_login: ${{ secrets.SNAP_TOKEN }}
|
||||
# snap: ${{ steps.build.outputs.snap }}
|
||||
# release: edge
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,4 +1,5 @@
|
||||
/target
|
||||
.vscode
|
||||
.idea
|
||||
.DS_Store
|
||||
src/ui/inline.rs
|
||||
@@ -6,3 +7,5 @@ extractor
|
||||
__pycache__
|
||||
src/version.rs
|
||||
*dmg
|
||||
sciter.dll
|
||||
**pdb
|
||||
|
||||
BIN
128x128.png
Normal file
BIN
128x128.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 9.9 KiB |
BIN
128x128@2x.png
Normal file
BIN
128x128@2x.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 25 KiB |
133
CODE_OF_CONDUCT.md
Normal file
133
CODE_OF_CONDUCT.md
Normal file
@@ -0,0 +1,133 @@
|
||||
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
We as members, contributors, and leaders pledge to make participation in our
|
||||
community a harassment-free experience for everyone, regardless of age, body
|
||||
size, visible or invisible disability, ethnicity, sex characteristics, gender
|
||||
identity and expression, level of experience, education, socio-economic status,
|
||||
nationality, personal appearance, race, religion, or sexual identity
|
||||
and orientation.
|
||||
|
||||
We pledge to act and interact in ways that contribute to an open, welcoming,
|
||||
diverse, inclusive, and healthy community.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to a positive environment for our
|
||||
community include:
|
||||
|
||||
* Demonstrating empathy and kindness toward other people
|
||||
* Being respectful of differing opinions, viewpoints, and experiences
|
||||
* Giving and gracefully accepting constructive feedback
|
||||
* Accepting responsibility and apologizing to those affected by our mistakes,
|
||||
and learning from the experience
|
||||
* Focusing on what is best not just for us as individuals, but for the
|
||||
overall community
|
||||
|
||||
Examples of unacceptable behavior include:
|
||||
|
||||
* The use of sexualized language or imagery, and sexual attention or
|
||||
advances of any kind
|
||||
* Trolling, insulting or derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or email
|
||||
address, without their explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Enforcement Responsibilities
|
||||
|
||||
Community leaders are responsible for clarifying and enforcing our standards of
|
||||
acceptable behavior and will take appropriate and fair corrective action in
|
||||
response to any behavior that they deem inappropriate, threatening, offensive,
|
||||
or harmful.
|
||||
|
||||
Community leaders have the right and responsibility to remove, edit, or reject
|
||||
comments, commits, code, wiki edits, issues, and other contributions that are
|
||||
not aligned to this Code of Conduct, and will communicate reasons for moderation
|
||||
decisions when appropriate.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies within all community spaces, and also applies when
|
||||
an individual is officially representing the community in public spaces.
|
||||
Examples of representing our community include using an official e-mail address,
|
||||
posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported to the community leaders responsible for enforcement at
|
||||
[info@rustdesk.com](mailto:info@rustdesk.com).
|
||||
All complaints will be reviewed and investigated promptly and fairly.
|
||||
|
||||
All community leaders are obligated to respect the privacy and security of the
|
||||
reporter of any incident.
|
||||
|
||||
## Enforcement Guidelines
|
||||
|
||||
Community leaders will follow these Community Impact Guidelines in determining
|
||||
the consequences for any action they deem in violation of this Code of Conduct:
|
||||
|
||||
### 1. Correction
|
||||
|
||||
**Community Impact**: Use of inappropriate language or other behavior deemed
|
||||
unprofessional or unwelcome in the community.
|
||||
|
||||
**Consequence**: A private, written warning from community leaders, providing
|
||||
clarity around the nature of the violation and an explanation of why the
|
||||
behavior was inappropriate. A public apology may be requested.
|
||||
|
||||
### 2. Warning
|
||||
|
||||
**Community Impact**: A violation through a single incident or series
|
||||
of actions.
|
||||
|
||||
**Consequence**: A warning with consequences for continued behavior. No
|
||||
interaction with the people involved, including unsolicited interaction with
|
||||
those enforcing the Code of Conduct, for a specified period of time. This
|
||||
includes avoiding interactions in community spaces as well as external channels
|
||||
like social media. Violating these terms may lead to a temporary or
|
||||
permanent ban.
|
||||
|
||||
### 3. Temporary Ban
|
||||
|
||||
**Community Impact**: A serious violation of community standards, including
|
||||
sustained inappropriate behavior.
|
||||
|
||||
**Consequence**: A temporary ban from any sort of interaction or public
|
||||
communication with the community for a specified period of time. No public or
|
||||
private interaction with the people involved, including unsolicited interaction
|
||||
with those enforcing the Code of Conduct, is allowed during this period.
|
||||
Violating these terms may lead to a permanent ban.
|
||||
|
||||
### 4. Permanent Ban
|
||||
|
||||
**Community Impact**: Demonstrating a pattern of violation of community
|
||||
standards, including sustained inappropriate behavior, harassment of an
|
||||
individual, or aggression toward or disparagement of classes of individuals.
|
||||
|
||||
**Consequence**: A permanent ban from any sort of public interaction within
|
||||
the community.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
||||
version 2.0, available at
|
||||
[https://www.contributor-covenant.org/version/2/0/code_of_conduct.html][v2.0].
|
||||
|
||||
Community Impact Guidelines were inspired by
|
||||
[Mozilla's code of conduct enforcement ladder][Mozilla CoC].
|
||||
|
||||
For answers to common questions about this code of conduct, see the FAQ at
|
||||
[https://www.contributor-covenant.org/faq][FAQ]. Translations are available
|
||||
at [https://www.contributor-covenant.org/translations][translations].
|
||||
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
[v2.0]: https://www.contributor-covenant.org/version/2/0/code_of_conduct.html
|
||||
[Mozilla CoC]: https://github.com/mozilla/diversity
|
||||
[FAQ]: https://www.contributor-covenant.org/faq
|
||||
[translations]: https://www.contributor-covenant.org/translations
|
||||
@@ -3,7 +3,6 @@
|
||||
RustDesk welcomes contribution from everyone. Here are the guidelines if you are
|
||||
thinking of helping us:
|
||||
|
||||
|
||||
## Contributions
|
||||
|
||||
Contributions to RustDesk or its dependencies should be made in the form of GitHub
|
||||
@@ -23,12 +22,12 @@ efforts from contributors on the same issue.
|
||||
master you may be asked to rebase your changes.
|
||||
|
||||
- Commits should be as small as possible, while ensuring that each commit is
|
||||
correct independently (i.e., each commit should compile and pass tests).
|
||||
correct independently (i.e., each commit should compile and pass tests).
|
||||
|
||||
- Commits should be accompanied by a Developer Certificate of Origin
|
||||
(http://developercertificate.org) sign-off, which indicates that you (and
|
||||
your employer if applicable) agree to be bound by the terms of the
|
||||
[project license](LICENSE.md). In git, this is the `-s` option to `git commit`
|
||||
[project license](LICENSE). In git, this is the `-s` option to `git commit`
|
||||
|
||||
- If your patch is not getting reviewed or you need a specific person to review
|
||||
it, you can @-reply a reviewer asking for a review in the pull request or a
|
||||
@@ -40,10 +39,8 @@ For specific git instructions, see [GitHub workflow 101](https://github.com/serv
|
||||
|
||||
## Conduct
|
||||
|
||||
We follow the [Rust Code of Conduct](https://www.rust-lang.org/policies/code-of-conduct).
|
||||
|
||||
https://github.com/rustdesk/rustdesk/blob/master/CODE_OF_CONDUCT.md
|
||||
|
||||
## Communication
|
||||
|
||||
RustDesk contributors frequent the [Discord](https://discord.gg/nDceKgxnkV).
|
||||
|
||||
|
||||
3518
Cargo.lock
generated
3518
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
73
Cargo.toml
73
Cargo.toml
@@ -1,58 +1,70 @@
|
||||
[package]
|
||||
name = "rustdesk"
|
||||
version = "1.1.2"
|
||||
version = "1.1.9"
|
||||
authors = ["rustdesk <info@rustdesk.com>"]
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
build= "build.rs"
|
||||
description = "A remote control software."
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib", "staticlib", "rlib"]
|
||||
|
||||
[features]
|
||||
inline = []
|
||||
cli = []
|
||||
use_samplerate = ["samplerate"]
|
||||
use_rubato = ["rubato"]
|
||||
use_dasp = ["dasp"]
|
||||
default = ["use_dasp"]
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
whoami = "0.9"
|
||||
whoami = "1.2"
|
||||
scrap = { path = "libs/scrap" }
|
||||
hbb_common = { path = "libs/hbb_common" }
|
||||
enigo = { path = "libs/enigo" }
|
||||
clipboard = { path = "libs/clipboard" }
|
||||
virtual_display = { path = "libs/virtual_display" }
|
||||
sys-locale = "0.2"
|
||||
serde_derive = "1.0"
|
||||
serde = "1.0"
|
||||
serde_json = "1.0"
|
||||
cfg-if = "1.0"
|
||||
lazy_static = "1.4"
|
||||
sha2 = "0.9"
|
||||
sha2 = "0.10"
|
||||
repng = "0.2"
|
||||
libc = "0.2"
|
||||
parity-tokio-ipc = { path = "libs/parity-tokio-ipc" }
|
||||
flexi_logger = "0.16"
|
||||
parity-tokio-ipc = { git = "https://github.com/open-trade/parity-tokio-ipc" }
|
||||
flexi_logger = { version = "0.22", features = ["async", "use_chrono_for_offset"] }
|
||||
runas = "0.2"
|
||||
magnum-opus = { path = "libs/magnum-opus" }
|
||||
dasp = { version = "0.11", features = ["signal", "interpolate-linear", "interpolate"] }
|
||||
magnum-opus = { git = "https://github.com/open-trade/magnum-opus" }
|
||||
dasp = { version = "0.11", features = ["signal", "interpolate-linear", "interpolate"], optional = true }
|
||||
rubato = { version = "0.12", optional = true }
|
||||
samplerate = { version = "0.2", optional = true }
|
||||
async-trait = "0.1"
|
||||
crc32fast = "1.2"
|
||||
uuid = { version = "0.8", features = ["v4"] }
|
||||
copypasta = "0.7"
|
||||
clap = "2.33"
|
||||
rpassword = "5.0"
|
||||
uuid = { version = "1.0.0", features = ["v4"] }
|
||||
clap = "3.0"
|
||||
rpassword = "6.0"
|
||||
base64 = "0.13"
|
||||
sysinfo = "0.23"
|
||||
num_cpus = "1.13"
|
||||
|
||||
[target.'cfg(not(any(target_os = "android")))'.dependencies]
|
||||
cpal = { git = "https://github.com/rustaudio/cpal" }
|
||||
[target.'cfg(not(any(target_os = "android", target_os = "linux")))'.dependencies]
|
||||
cpal = "0.13.5"
|
||||
|
||||
[target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies]
|
||||
machine-uid = "0.2"
|
||||
mac_address = "1.1"
|
||||
sciter-rs = { path = "libs/rust-sciter" }
|
||||
sciter-rs = { git = "https://github.com/open-trade/rust-sciter", branch = "dyn" }
|
||||
ctrlc = "3.2"
|
||||
arboard = "2.0"
|
||||
clipboard-master = "3.1"
|
||||
#rdev = { path = "../rdev" }
|
||||
rdev = { git = "https://github.com/open-trade/rdev" }
|
||||
|
||||
[target.'cfg(target_os = "windows")'.dependencies]
|
||||
systray = { path = "libs/systray-rs" }
|
||||
systray = { git = "https://github.com/liyue201/systray-rs" }
|
||||
winapi = { version = "0.3", features = ["winuser"] }
|
||||
winreg = "0.7"
|
||||
windows-service = { git = 'https://github.com/mullvad/windows-service-rs.git' }
|
||||
winreg = "0.10"
|
||||
windows-service = "0.4"
|
||||
|
||||
[target.'cfg(target_os = "macos")'.dependencies]
|
||||
objc = "0.2"
|
||||
@@ -60,21 +72,19 @@ cocoa = "0.24"
|
||||
dispatch = "0.2"
|
||||
core-foundation = "0.9"
|
||||
core-graphics = "0.22"
|
||||
include_dir = "0.7.2"
|
||||
tray-item = "0.7" # looks better than trayicon
|
||||
|
||||
[target.'cfg(target_os = "linux")'.dependencies]
|
||||
libpulse-simple-binding = "2.16"
|
||||
libpulse-binding = "2.16"
|
||||
rust-pulsectl = { path = "libs/pulsectl" }
|
||||
ctrlc = "3.1"
|
||||
|
||||
[target.'cfg(not(any(target_os = "windows", target_os = "android", target_os = "ios")))'.dependencies]
|
||||
psutil = "3.2"
|
||||
psimple = { package = "libpulse-simple-binding", version = "2.25" }
|
||||
pulse = { package = "libpulse-binding", version = "2.26" }
|
||||
rust-pulsectl = { git = "https://github.com/open-trade/pulsectl" }
|
||||
|
||||
[target.'cfg(target_os = "android")'.dependencies]
|
||||
android_logger = "0.9"
|
||||
android_logger = "0.11"
|
||||
|
||||
[workspace]
|
||||
members = ["libs/scrap", "libs/hbb_common", "libs/enigo"]
|
||||
members = ["libs/scrap", "libs/hbb_common", "libs/enigo", "libs/clipboard", "libs/virtual_display"]
|
||||
|
||||
[package.metadata.winres]
|
||||
LegalCopyright = "Copyright © 2020"
|
||||
@@ -98,6 +108,7 @@ identifier = "com.carriez.rustdesk"
|
||||
icon = ["32x32.png", "128x128.png", "128x128@2x.png"]
|
||||
deb_depends = ["libgtk-3-0", "libxcb-randr0", "libxdo3", "libxfixes3", "libxcb-shape0", "libxcb-xfixes0", "libasound2", "libsystemd0", "pulseaudio"]
|
||||
osx_minimum_system_version = "10.14"
|
||||
resources = ["mac-tray.png"]
|
||||
|
||||
#https://github.com/johnthagen/min-sized-rust
|
||||
#!!! rembember call "strip target/release/rustdesk"
|
||||
|
||||
19
DEBIAN/postinst
Normal file
19
DEBIAN/postinst
Normal file
@@ -0,0 +1,19 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
if [ "$1" = configure ]; then
|
||||
|
||||
INITSYS=$(ls -al /proc/1/exe | awk -F' ' '{print $NF}' | awk -F'/' '{print $NF}')
|
||||
|
||||
if [ "systemd" == "$INITSYS" ]; then
|
||||
if [ -e /etc/systemd/system/rustdesk.service ]; then
|
||||
rm /etc/systemd/system/rustdesk.service
|
||||
fi
|
||||
sudo -H pip3 install pynput
|
||||
cp /usr/share/rustdesk/files/systemd/rustdesk.service /etc/systemd/system/rustdesk.service
|
||||
systemctl daemon-reload
|
||||
systemctl enable rustdesk
|
||||
systemctl start rustdesk
|
||||
fi
|
||||
fi
|
||||
11
DEBIAN/postrm
Normal file
11
DEBIAN/postrm
Normal file
@@ -0,0 +1,11 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
case $1 in
|
||||
purge)
|
||||
rm -rf /root/.config/rustdesk || true
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
||||
16
DEBIAN/preinst
Normal file
16
DEBIAN/preinst
Normal file
@@ -0,0 +1,16 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
case $1 in
|
||||
install|upgrade)
|
||||
INITSYS=$(ls -al /proc/1/exe | awk -F' ' '{print $NF}' | awk -F'/' '{print $NF}')
|
||||
if [ "systemd" == "${INITSYS}" ]; then
|
||||
service rustdesk stop || true
|
||||
sleep 1
|
||||
rm -rf /usr/bin/libsciter-gtk.so
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
||||
16
DEBIAN/prerm
Normal file
16
DEBIAN/prerm
Normal file
@@ -0,0 +1,16 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
case $1 in
|
||||
remove|upgrade)
|
||||
INITSYS=$(ls -al /proc/1/exe | awk -F' ' '{print $NF}' | awk -F'/' '{print $NF}')
|
||||
if [ "systemd" == "${INITSYS}" ]; then
|
||||
systemctl stop rustdesk || true
|
||||
systemctl disable rustdesk || true
|
||||
rm /etc/systemd/system/rustdesk.service || true
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
||||
20
Dockerfile
Normal file
20
Dockerfile
Normal file
@@ -0,0 +1,20 @@
|
||||
FROM debian
|
||||
|
||||
WORKDIR /
|
||||
RUN apt update -y && apt install -y g++ gcc git curl wget nasm yasm libgtk-3-dev clang libxcb-randr0-dev libxdo-dev libxfixes-dev libxcb-shape0-dev libxcb-xfixes0-dev libasound2-dev libpulse-dev cmake unzip zip sudo
|
||||
|
||||
RUN git clone https://github.com/microsoft/vcpkg && cd vcpkg && git checkout 134505003bb46e20fbace51ccfb69243fbbc5f82
|
||||
RUN /vcpkg/bootstrap-vcpkg.sh -disableMetrics
|
||||
RUN /vcpkg/vcpkg --disable-metrics install libvpx libyuv opus
|
||||
|
||||
RUN groupadd -r user && useradd -r -g user user --home /home/user && mkdir -p /home/user && chown user /home/user && echo "user ALL=(ALL) NOPASSWD:ALL" | sudo tee /etc/sudoers.d/user
|
||||
WORKDIR /home/user
|
||||
RUN wget https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.lnx/x64/libsciter-gtk.so
|
||||
USER user
|
||||
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs > rustup.sh
|
||||
RUN chmod +x rustup.sh
|
||||
RUN ./rustup.sh -y
|
||||
|
||||
USER root
|
||||
COPY ./entrypoint /
|
||||
ENTRYPOINT ["/entrypoint"]
|
||||
162
README-DE.md
Normal file
162
README-DE.md
Normal file
@@ -0,0 +1,162 @@
|
||||
<p align="center">
|
||||
<img src="logo-header.svg" alt="RustDesk - Your remote desktop"><br>
|
||||
<a href="#kostenlose-öffentliche-server">Server</a> •
|
||||
<a href="#die-groben-schritte-zum-kompilieren">Kompilieren</a> •
|
||||
<a href="#auf-docker-kompilieren">Docker</a> •
|
||||
<a href="#dateistruktur">Dateistruktur</a> •
|
||||
<a href="#screenshots">Screenshots</a><br>
|
||||
[<a href="README-ZH.md">中文</a>] | [<a href="README-ES.md">Español</a>] | [<a href="README-FR.md">Français</a>] | [<a href="README-DE.md">Deutsch</a>] | [<a href="README-PL.md">Polski</a>] | [<a href="README-FI.md">Suomi</a>] | [<a href="README-ML.md">മലയാളം</a>] | [<a href="README-JP.md">日本語</a>] | [<a href="README-NL.md">Nederlands</a>] | [<a href="README-IT.md">Italiano</a>] | [<a href="README-RU.md">Русский</a>] | [<a href="README-PTBR.md">Português (Brasil)</a>] | [<a href="README-EO.md">Esperanto</a>]<br>
|
||||
<b>Wir brauchen deine Hilfe um diese README Datei zu verbessern und aktualisieren</b>
|
||||
</p>
|
||||
|
||||
Rede mit uns: [Discord](https://discord.gg/nDceKgxnkV) | [Reddit](https://www.reddit.com/r/rustdesk)
|
||||
|
||||
[](https://ko-fi.com/I2I04VU09)
|
||||
|
||||
Das hier ist ein Programm was, man nutzen kann, um einen Computer fernzusteuern, es wurde in Rust geschrieben. Es funktioniert ohne Konfiguration oder ähnliches, man kann es einfach direkt nutzen. Du hast volle Kontrolle über deine Daten und brauchst dir daher auch keine Sorgen um die Sicherheit dieser Daten zu machen. Du kannst unseren Rendezvous/Relay Server nutzen, [einen eigenen Server eröffnen](https://rustdesk.com/server) oder [einen neuen eigenen Server programmieren](https://github.com/rustdesk/rustdesk-server-demo).
|
||||
|
||||
RustDesk heißt jegliche Mitarbeit willkommen. Schau dir [`CONTRIBUTING.md`](CONTRIBUTING.md) an, wenn du Hilfe brauchst für den Start.
|
||||
|
||||
[**PROGRAMM DOWNLOAD**](https://github.com/rustdesk/rustdesk/releases)
|
||||
|
||||
## Kostenlose öffentliche Server
|
||||
|
||||
Hier sind die Server, die du kostenlos nutzen kannst, es kann sein das sich diese Liste immer mal wieder ändert. Falls du nicht in der Nähe einer dieser Server bist, kann es sein, dass deine Verbindung langsam sein wird.
|
||||
|
||||
| Standort | Serverart | Spezifikationen | Kommentare |
|
||||
| --------- | ------------- | ------------------ | ---------- |
|
||||
| Seoul | AWS lightsail | 1 VCPU / 0.5GB RAM | |
|
||||
| Singapore | Vultr | 1 VCPU / 1GB RAM | |
|
||||
| Dallas | Vultr | 1 VCPU / 1GB RAM | |
|
||||
|
||||
## Abhängigkeiten
|
||||
|
||||
Die Desktop-Versionen nutzen [Sciter](https://sciter.com/) für die Oberfläche, bitte lade die dynamische Sciter Bibliothek selbst herunter.
|
||||
|
||||
[Windows](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.win/x64/sciter.dll) |
|
||||
[Linux](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.lnx/x64/libsciter-gtk.so) |
|
||||
[MacOS](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.osx/libsciter.dylib)
|
||||
|
||||
## Die groben Schritte zum Kompilieren
|
||||
|
||||
- Bereite deine Rust Entwicklungsumgebung und C++ Entwicklungsumgebung vor
|
||||
|
||||
- Installiere [vcpkg](https://github.com/microsoft/vcpkg) und füge die `VCPKG_ROOT` Systemumgebungsvariable hinzu
|
||||
|
||||
- Windows: `vcpkg install libvpx:x64-windows-static libyuv:x64-windows-static opus:x64-windows-static`
|
||||
- Linux/MacOS: `vcpkg install libvpx libyuv opus`
|
||||
|
||||
- Nutze `cargo run`
|
||||
|
||||
## Kompilieren auf Linux
|
||||
|
||||
### Ubuntu 18 (Debian 10)
|
||||
|
||||
```sh
|
||||
sudo apt install -y g++ gcc git curl wget nasm yasm libgtk-3-dev clang libxcb-randr0-dev libxdo-dev libxfixes-dev libxcb-shape0-dev libxcb-xfixes0-dev libasound2-dev libpulse-dev cmake
|
||||
```
|
||||
|
||||
### Fedora 28 (CentOS 8)
|
||||
|
||||
```sh
|
||||
sudo yum -y install gcc-c++ git curl wget nasm yasm gcc gtk3-devel clang libxcb-devel libxdo-devel libXfixes-devel pulseaudio-libs-devel cmake alsa-lib-devel
|
||||
```
|
||||
|
||||
### Arch (Manjaro)
|
||||
|
||||
```sh
|
||||
sudo pacman -Syu --needed unzip git cmake gcc curl wget yasm nasm zip make pkg-config clang gtk3 xdotool libxcb libxfixes alsa-lib pulseaudio
|
||||
```
|
||||
|
||||
### vcpkg installieren
|
||||
|
||||
```sh
|
||||
git clone https://github.com/microsoft/vcpkg
|
||||
cd vcpkg
|
||||
git checkout 2021.12.01
|
||||
cd ..
|
||||
vcpkg/bootstrap-vcpkg.sh
|
||||
export VCPKG_ROOT=$HOME/vcpkg
|
||||
vcpkg/vcpkg install libvpx libyuv opus
|
||||
```
|
||||
|
||||
### libvpx reparieren (Für Fedora)
|
||||
|
||||
```sh
|
||||
cd vcpkg/buildtrees/libvpx/src
|
||||
cd *
|
||||
./configure
|
||||
sed -i 's/CFLAGS+=-I/CFLAGS+=-fPIC -I/g' Makefile
|
||||
sed -i 's/CXXFLAGS+=-I/CXXFLAGS+=-fPIC -I/g' Makefile
|
||||
make
|
||||
cp libvpx.a $HOME/vcpkg/installed/x64-linux/lib/
|
||||
cd
|
||||
```
|
||||
|
||||
### Kompilieren
|
||||
|
||||
```sh
|
||||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
|
||||
source $HOME/.cargo/env
|
||||
git clone https://github.com/rustdesk/rustdesk
|
||||
cd rustdesk
|
||||
mkdir -p target/debug
|
||||
wget https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.lnx/x64/libsciter-gtk.so
|
||||
mv libsciter-gtk.so target/debug
|
||||
cargo run
|
||||
```
|
||||
|
||||
### Ändere Wayland zu X11 (Xorg)
|
||||
|
||||
RustDesk unterstützt "Wayland" nicht. Siehe [hier](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/) um Xorg als Standard GNOME Session zu nutzen.
|
||||
|
||||
## Auf Docker Kompilieren
|
||||
|
||||
Beginne damit das Repository zu klonen und den Docker Container zu bauen:
|
||||
|
||||
```sh
|
||||
git clone https://github.com/rustdesk/rustdesk
|
||||
cd rustdesk
|
||||
docker build -t "rustdesk-builder" .
|
||||
```
|
||||
|
||||
Jedes Mal, wenn du das Programm Kompilieren musst, nutze diesen Befehl:
|
||||
|
||||
```sh
|
||||
docker run --rm -it -v $PWD:/home/user/rustdesk -v rustdesk-git-cache:/home/user/.cargo/git -v rustdesk-registry-cache:/home/user/.cargo/registry -e PUID="$(id -u)" -e PGID="$(id -g)" rustdesk-builder
|
||||
```
|
||||
|
||||
Bedenke, dass das erste Mal Kompilieren länger dauern kann, da die Abhängigkeiten erst kompiliert werden müssen bevor sie zwischengespeichert werden können. Darauf folgende Kompiliervorgänge werden schneller sein. Falls du zusätzliche oder andere Argumente für den Kompilierbefehl angeben musst, kannst du diese am Ende des Befehls an der `<OPTIONAL-ARGS>` Position machen. Wenn du zum Beispiel eine optimierte Releaseversion kompilieren willst, kannst du das tun, indem du `--release` am Ende des Befehls anhängst. Das daraus entstehende Programm kannst du im “target” Ordner auf deinem System finden. Du kannst es mit folgenden Befehlen ausführen:
|
||||
|
||||
```sh
|
||||
target/debug/rustdesk
|
||||
```
|
||||
|
||||
Oder, wenn du eine Releaseversion benutzt:
|
||||
|
||||
```sh
|
||||
target/release/rustdesk
|
||||
```
|
||||
|
||||
Bitte gehe sicher, dass du diese Befehle vom Stammverzeichnis vom RustDesk Repository nutzt, sonst kann es passieren, dass das Programm die Ressourcen nicht finden kann. Bitte bedenke auch, dass Unterbefehle von Cargo, wie z. B. `install` oder `run` aktuell noch nicht unterstützt werden, da sie das Programm innerhalb des Containers starten oder installieren würden, anstatt auf deinem eigentlichen System.
|
||||
|
||||
## Dateistruktur
|
||||
|
||||
- **[libs/hbb_common](https://github.com/rustdesk/rustdesk/tree/master/libs/hbb_common)**: Video Codec, Konfiguration, TCP/UDP Wrapper, Protokoll Puffer, fs Funktionen für Dateitransfer, und ein paar andere nützliche Funktionen
|
||||
- **[libs/scrap](https://github.com/rustdesk/rustdesk/tree/master/libs/scrap)**: Bildschirmaufnahme
|
||||
- **[libs/enigo](https://github.com/rustdesk/rustdesk/tree/master/libs/enigo)**: Plattformspezifische Maus und Tastatur Steuerung
|
||||
- **[src/ui](https://github.com/rustdesk/rustdesk/tree/master/src/ui)**: GUI
|
||||
- **[src/server](https://github.com/rustdesk/rustdesk/tree/master/src/server)**: Audio/Zwischenablage/Eingabe/Videodienste und Netzwerk Verbindungen
|
||||
- **[src/client.rs](https://github.com/rustdesk/rustdesk/tree/master/src/client.rs)**: Starten einer Peer-Verbindung
|
||||
- **[src/rendezvous_mediator.rs](https://github.com/rustdesk/rustdesk/tree/master/src/rendezvous_mediator.rs)**: Mit [rustdesk-server](https://github.com/rustdesk/rustdesk-server) kommunizieren, für Verbindung von außen warten, direkt (TCP hole punching) oder weitergeleitet
|
||||
- **[src/platform](https://github.com/rustdesk/rustdesk/tree/master/src/platform)**: Plattformspezifischer Code
|
||||
|
||||
## Screenshots
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
161
README-EO.md
Normal file
161
README-EO.md
Normal file
@@ -0,0 +1,161 @@
|
||||
<p align="center">
|
||||
<img src="logo-header.svg" alt="RustDesk - Your remote desktop"><br>
|
||||
<a href="#senpagaj-publikaj-serviloj">Serviloj</a> •
|
||||
<a href="#paŝoj-por-kompili">Kompili</a> •
|
||||
<a href="#kiel-kompili-kun-docker">Docker</a> •
|
||||
<a href="#dosierstrukturo">Strukturo</a> •
|
||||
<a href="#ekrankopio">Ekrankopio</a><br>
|
||||
[<a href="README-ZH.md">中文</a>] | [<a href="README-ES.md">Español</a>] | [<a href="README-FR.md">Français</a>] | [<a href="README-DE.md">Deutsch</a>] | [<a href="README-PL.md">Polski</a>] | [<a href="README-FI.md">Suomi</a>] | [<a href="README-ML.md">മലയാളം</a>] | [<a href="README-JP.md">日本語</a>] | [<a href="README-NL.md">Nederlands</a>] | [<a href="README-IT.md">Italiano</a>] | [<a href="README-RU.md">Русский</a>] | [<a href="README-PTBR.md">Português (Brasil)</a>] | [<a href="README-EO.md">Esperanto</a>]<br>
|
||||
<b>Ni bezonas helpon traduki tiun README kaj <a href="https://github.com/rustdesk/rustdesk/tree/master/src/lang">la interfacon</a> al via denaska lingvo</b>
|
||||
</p>
|
||||
|
||||
Babili kun ni: [Discord](https://discord.gg/nDceKgxnkV) | [Reddit](https://www.reddit.com/r/rustdesk)
|
||||
|
||||
[](https://ko-fi.com/I2I04VU09)
|
||||
|
||||
Denove alia fora labortabla programo, skribita en Rust. Ĝi funkcias elskatole, ne bezonas konfiguraĵon. Vi havas la tutan kontrolon sur viaj datumoj, sen zorgo pri sekureco. Vi povas uzi nian servilon rendezvous/relajsan, [agordi vian propran](https://rustdesk.com/server), aŭ [skribi vian propran servilon rendezvous/relajsan](https://github.com/rustdesk/rustdesk-server-demo).
|
||||
|
||||
RustDesk bonvenigas kontribuon de ĉiuj. Vidu [`CONTRIBUTING.md`](CONTRIBUTING.md) por helpo komenci.
|
||||
|
||||
[**BINARA ELŜUTO**](https://github.com/rustdesk/rustdesk/releases)
|
||||
|
||||
## Senpagaj publikaj serviloj
|
||||
|
||||
Malsupre estas la serviloj, kiuj vi uzas senpage, ĝi povas ŝanĝi laŭlonge de la tempo. Se vi ne estas proksima de unu de tiuj, via reto povas esti malrapida.
|
||||
| Situo | Vendanto | Detaloj |
|
||||
| --------- | ------------- | ------------------ |
|
||||
| Seulo | AWS lightsail | 1 VCPU / 0.5GB RAM |
|
||||
| Singapuro | Vultr | 1 VCPU / 1GB RAM |
|
||||
| Dalaso | Vultr | 1 VCPU / 1GB RAM | |
|
||||
|
||||
## Dependantaĵoj
|
||||
|
||||
La labortabla versio uzas [sciter](https://sciter.com/) por la interfaco, bonvolu elŝuti la bibliotekon dinamikan sciter.
|
||||
|
||||
[Windows](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.win/x64/sciter.dll) |
|
||||
[Linux](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.lnx/x64/libsciter-gtk.so) |
|
||||
[MacOS](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.osx/libsciter.dylib)
|
||||
|
||||
## Paŝoj por kompili
|
||||
|
||||
- Preparu vian medion de programado Rust kaj vian medion de kompilado C++
|
||||
|
||||
- Instalu [vcpkg](https://github.com/microsoft/vcpkg), kaj agordu la medivariablon `VCPKG_ROOT` korekte
|
||||
|
||||
- Windows: vcpkg install libvpx:x64-windows-static libyuv:x64-windows-static opus:x64-windows-static
|
||||
- Linux/MacOS: vcpkg install libvpx libyuv opus
|
||||
|
||||
- Plenumu `cargo run`
|
||||
|
||||
## Kiel kompili sur Linukso
|
||||
|
||||
### Ubuntu 18 (Debian 10)
|
||||
|
||||
```sh
|
||||
sudo apt install -y g++ gcc git curl wget nasm yasm libgtk-3-dev clang libxcb-randr0-dev libxdo-dev libxfixes-dev libxcb-shape0-dev libxcb-xfixes0-dev libasound2-dev libpulse-dev cmake
|
||||
```
|
||||
|
||||
### Fedora 28 (CentOS 8)
|
||||
|
||||
```sh
|
||||
sudo yum -y install gcc-c++ git curl wget nasm yasm gcc gtk3-devel clang libxcb-devel libxdo-devel libXfixes-devel pulseaudio-libs-devel cmake alsa-lib-devel
|
||||
```
|
||||
|
||||
### Arch (Manjaro)
|
||||
|
||||
```sh
|
||||
sudo pacman -Syu --needed unzip git cmake gcc curl wget yasm nasm zip make pkg-config clang gtk3 xdotool libxcb libxfixes alsa-lib pulseaudio
|
||||
```
|
||||
|
||||
### Instali vcpkg
|
||||
|
||||
```sh
|
||||
git clone https://github.com/microsoft/vcpkg
|
||||
cd vcpkg
|
||||
git checkout 2021.12.01
|
||||
cd ..
|
||||
vcpkg/bootstrap-vcpkg.sh
|
||||
export VCPKG_ROOT=$HOME/vcpkg
|
||||
vcpkg/vcpkg install libvpx libyuv opus
|
||||
```
|
||||
|
||||
### Ripari libvpx (Por Fedora)
|
||||
|
||||
```sh
|
||||
cd vcpkg/buildtrees/libvpx/src
|
||||
cd *
|
||||
./configure
|
||||
sed -i 's/CFLAGS+=-I/CFLAGS+=-fPIC -I/g' Makefile
|
||||
sed -i 's/CXXFLAGS+=-I/CXXFLAGS+=-fPIC -I/g' Makefile
|
||||
make
|
||||
cp libvpx.a $HOME/vcpkg/installed/x64-linux/lib/
|
||||
cd
|
||||
```
|
||||
|
||||
### Kompili
|
||||
|
||||
```sh
|
||||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
|
||||
source $HOME/.cargo/env
|
||||
git clone https://github.com/rustdesk/rustdesk
|
||||
cd rustdesk
|
||||
mkdir -p target/debug
|
||||
wget https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.lnx/x64/libsciter-gtk.so
|
||||
mv libsciter-gtk.so target/debug
|
||||
VCPKG_ROOT=$HOME/vcpkg cargo run
|
||||
```
|
||||
|
||||
### Ŝanĝi Wayland por X11 (Xorg)
|
||||
|
||||
RustDesk ne subtenas Wayland. Kontrolu [tion](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/) por agordi Xorg kiel defaŭlta sesio GNOME.
|
||||
|
||||
## Kiel kompili kun Docker
|
||||
|
||||
Komencu klonante la deponejon kaj kompilu la konteneron Docker:
|
||||
|
||||
```sh
|
||||
git clone https://github.com/rustdesk/rustdesk
|
||||
cd rustdesk
|
||||
docker build -t "rustdesk-builder" .
|
||||
```
|
||||
|
||||
Tiam, ĉiuj fojoj, kiuj vi bezonas kompili la programon, plenumu tiun komandon:
|
||||
|
||||
```sh
|
||||
docker run --rm -it -v $PWD:/home/user/rustdesk -v rustdesk-git-cache:/home/user/.cargo/git -v rustdesk-registry-cache:/home/user/.cargo/registry -e PUID="$(id -u)" -e PGID="$(id -g)" rustdesk-builder
|
||||
```
|
||||
|
||||
Notu, ke la unua kompilado povas daŭri longe, antaŭ ke la dependantaĵoj estu kaŝitaj, sekvaj kompiladoj estos pli rapidaj. Aldone, se vi bezonas specifi diferentajn argumentojn por la kompilkomando, vi povas fari ĝin en la fine de la komando, en la posicio `<OPTIONAL-ARGS>`. Ekzemple, se vi volas kompili version de eldono optimigita, vi plenumus la komandon supre, kun `---release`. La plenumebla dosiero disponeblos en la cela dosierujo sur via sistemo, kaj povos esti plenumita kun:
|
||||
|
||||
```sh
|
||||
target/debug/rustdesk
|
||||
```
|
||||
|
||||
Aŭ, se vi plenumas eldonan plenumeblan dosieron:
|
||||
|
||||
```sh
|
||||
target/release/rustdesk
|
||||
```
|
||||
|
||||
Bonvolu certigi, ke vi plenumas tiujn komandojn el la radiko de la deponejo RustDesk, alie la programo povus esti nekapabla de trovi la devigajn resursojn. Ankaŭ notu, ke la aliaj subkomandoj de cargo kiel `install` aŭ `run` momente ne estas subtenitaj per tiu metodo, ĉar instalus aŭ plenumus la programon en la kontenero anstataŭ de la gastiganto.
|
||||
|
||||
## Dosierstrukturo
|
||||
|
||||
- **[libs/hbb_common](https://github.com/rustdesk/rustdesk/tree/master/libs/hbb_common)**: videa kodeko, agordado, kovrilo tcp/udp, protobuf, funkcioj fs por dosiertransigo, kaj aliaj utilaĵaj funkcioj
|
||||
- **[libs/scrap](https://github.com/rustdesk/rustdesk/tree/master/libs/scrap)**: ekrankaptado
|
||||
- **[libs/enigo](https://github.com/rustdesk/rustdesk/tree/master/libs/enigo)**: operaciumspecifa kontrolo de klavaro/muso
|
||||
- **[src/ui](https://github.com/rustdesk/rustdesk/tree/master/src/ui)**: interfaco
|
||||
- **[src/server](https://github.com/rustdesk/rustdesk/tree/master/src/server)**: aŭdio/poŝo/enigo/videa servoj, kaj retkonektoj
|
||||
- **[src/client.rs](https://github.com/rustdesk/rustdesk/tree/master/src/client.rs)**: starti konekto kun samtavolo
|
||||
- **[src/rendezvous_mediator.rs](https://github.com/rustdesk/rustdesk/tree/master/src/rendezvous_mediator.rs)**: komuniki kun [rustdesk-server](https://github.com/rustdesk/rustdesk-server), atendi foran direktan (TCP hole punching) aŭ relajsatan konekton
|
||||
- **[src/platform](https://github.com/rustdesk/rustdesk/tree/master/src/platform)**: operaciumspecifa kodo
|
||||
|
||||
## Ekrankopio
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
160
README-ES.md
Normal file
160
README-ES.md
Normal file
@@ -0,0 +1,160 @@
|
||||
<p align="center">
|
||||
<img src="logo-header.svg" alt="RustDesk - Your remote desktop"><br>
|
||||
<a href="#servidores-gratis-de-uso-público">Servidores</a> •
|
||||
<a href="#pasos-para-compilar-desde-el-inicio">Compilar</a> •
|
||||
<a href="#como-compilar-con-docker">Docker</a> •
|
||||
<a href="#estructura-de-archivos">Estructura</a> •
|
||||
<a href="#captura-de-pantalla">Captura de pantalla</a><br>
|
||||
[<a href="README-ZH.md">中文</a>] | [<a href="README-ES.md">Español</a>] | [<a href="README-FR.md">Français</a>] | [<a href="README-DE.md">Deutsch</a>] | [<a href="README-PL.md">Polski</a>] | [<a href="README-FI.md">Suomi</a>] | [<a href="README-ML.md">മലയാളം</a>] | [<a href="README-JP.md">日本語</a>] | [<a href="README-NL.md">Nederlands</a>] | [<a href="README-IT.md">Italiano</a>] | [<a href="README-RU.md">Русский</a>] | [<a href="README-PTBR.md">Português (Brasil)</a>] | [<a href="README-EO.md">Esperanto</a>]<br>
|
||||
<b>Necesitamos tu ayuda para traducir este README a tu idioma</b>
|
||||
</p>
|
||||
|
||||
Chat with us: [Discord](https://discord.gg/nDceKgxnkV) | [Reddit](https://www.reddit.com/r/rustdesk)
|
||||
|
||||
[](https://ko-fi.com/I2I04VU09)
|
||||
|
||||
Otro software de escritorio remoto, escrito en Rust. Funciona de forma inmediata, sin necesidad de configuración. Tienes el control total de sus datos, sin preocupaciones sobre la seguridad. Puedes utilizar nuestro servidor de rendezvous/relay, [set up your own](https://rustdesk.com/server), o [escribir tu propio servidor rendezvous/relay](https://github.com/rustdesk/rustdesk-server-demo).
|
||||
|
||||
RustDesk agradece la contribución de todo el mundo. Ve [`CONTRIBUTING.md`](CONTRIBUTING.md) para ayuda inicial.
|
||||
|
||||
[**DESCARGA DE BINARIOS**](https://github.com/rustdesk/rustdesk/releases)
|
||||
|
||||
## Servidores gratis de uso público
|
||||
|
||||
A continuación se muestran los servidores que está utilizando de forma gratuita, puede cambiar en algún momento. Si no estás cerca de uno de ellos, tu red puede ser lenta.
|
||||
|
||||
- Seoul, AWS lightsail, 1 VCPU/0.5G RAM
|
||||
- Singapore, Vultr, 1 VCPU/1G RAM
|
||||
- Dallas, Vultr, 1 VCPU/1G RAM
|
||||
|
||||
## Dependencies
|
||||
|
||||
La versión Desktop usa [sciter](https://sciter.com/) para GUI, por favor bajate la librería sciter tu mismo..
|
||||
|
||||
[Windows](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.win/x64/sciter.dll) |
|
||||
[Linux](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.lnx/x64/libsciter-gtk.so) |
|
||||
[macOS](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.osx/libsciter.dylib)
|
||||
|
||||
## Pasos para compilar desde el inicio
|
||||
|
||||
- Prepara el entono de desarrollode Rust y el entorno de compilación de C++ y Rust.
|
||||
|
||||
- Instala [vcpkg](https://github.com/microsoft/vcpkg), y configura la variable de entono `VCPKG_ROOT` correctamente.
|
||||
|
||||
- Windows: vcpkg install libvpx:x64-windows-static libyuv:x64-windows-static opus:x64-windows-static
|
||||
- Linux/Osx: vcpkg install libvpx libyuv opus
|
||||
|
||||
- run `cargo run`
|
||||
|
||||
## Como compilar en linux
|
||||
|
||||
### Ubuntu 18 (Debian 10)
|
||||
|
||||
```sh
|
||||
sudo apt install -y g++ gcc git curl wget nasm yasm libgtk-3-dev clang libxcb-randr0-dev libxdo-dev libxfixes-dev libxcb-shape0-dev libxcb-xfixes0-dev libasound2-dev libpulse-dev cmake
|
||||
```
|
||||
|
||||
### Fedora 28 (CentOS 8)
|
||||
|
||||
```sh
|
||||
sudo yum -y install gcc-c++ git curl wget nasm yasm gcc gtk3-devel clang libxcb-devel libxdo-devel libXfixes-devel pulseaudio-libs-devel cmake alsa-lib-devel
|
||||
```
|
||||
|
||||
### Arch (Manjaro)
|
||||
|
||||
```sh
|
||||
sudo pacman -Syu --needed unzip git cmake gcc curl wget yasm nasm zip make pkg-config clang gtk3 xdotool libxcb libxfixes alsa-lib pulseaudio
|
||||
```
|
||||
|
||||
### Install vcpkg
|
||||
|
||||
```sh
|
||||
git clone https://github.com/microsoft/vcpkg
|
||||
cd vcpkg
|
||||
git checkout 2021.12.01
|
||||
cd ..
|
||||
vcpkg/bootstrap-vcpkg.sh
|
||||
export VCPKG_ROOT=$HOME/vcpkg
|
||||
vcpkg/vcpkg install libvpx libyuv opus
|
||||
```
|
||||
|
||||
### Soluciona libvpx (For Fedora)
|
||||
|
||||
```sh
|
||||
cd vcpkg/buildtrees/libvpx/src
|
||||
cd *
|
||||
./configure
|
||||
sed -i 's/CFLAGS+=-I/CFLAGS+=-fPIC -I/g' Makefile
|
||||
sed -i 's/CXXFLAGS+=-I/CXXFLAGS+=-fPIC -I/g' Makefile
|
||||
make
|
||||
cp libvpx.a $HOME/vcpkg/installed/x64-linux/lib/
|
||||
cd
|
||||
```
|
||||
|
||||
### Compila
|
||||
|
||||
```sh
|
||||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
|
||||
source $HOME/.cargo/env
|
||||
git clone https://github.com/rustdesk/rustdesk
|
||||
cd rustdesk
|
||||
mkdir -p target/debug
|
||||
wget https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.lnx/x64/libsciter-gtk.so
|
||||
mv libsciter-gtk.so target/debug
|
||||
cargo run
|
||||
```
|
||||
|
||||
### Cambia Wayland a X11 (Xorg)
|
||||
|
||||
RustDesk no soporta Wayland. Comprueba [aquí](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/) para configurar Xorg en la sesión por defecto de GNOME.
|
||||
|
||||
## Como compilar con Docker
|
||||
|
||||
Empieza clonando el repositorio y compilando el contenedor de docker:
|
||||
|
||||
```sh
|
||||
git clone https://github.com/rustdesk/rustdesk
|
||||
cd rustdesk
|
||||
docker build -t "rustdesk-builder" .
|
||||
```
|
||||
|
||||
Entonces, cada vez que necesites compilar una modificación, ejecuta el siguiente comando:
|
||||
|
||||
```sh
|
||||
docker run --rm -it -v $PWD:/home/user/rustdesk -v rustdesk-git-cache:/home/user/.cargo/git -v rustdesk-registry-cache:/home/user/.cargo/registry -e PUID="$(id -u)" -e PGID="$(id -g)" rustdesk-builder
|
||||
```
|
||||
|
||||
Ten en cuenta que la primera compilación puede tardar más tiempo antes de que las dependencias se almacenen en la caché, las siguientes compilaciones serán más rápidas. Además, si necesitas especificar diferentes argumentos a la orden de compilación, puede hacerlo al final de la linea de comandos en el apartado`<OPTIONAL-ARGS>`. Por ejemplo, si desea compilar una versión optimizada para publicación, deberá ejecutar el comando anterior seguido de `---release`. El ejecutable resultante estará disponible en la carpeta de destino en su sistema, y puede ser ejecutado con:
|
||||
|
||||
```sh
|
||||
target/debug/rustdesk
|
||||
```
|
||||
|
||||
O si estas ejecutando una versión para su publicación:
|
||||
|
||||
```sh
|
||||
target/release/rustdesk
|
||||
```
|
||||
|
||||
Por favor, asegurate de que estás ejecutando estos comandos desde la raíz del repositorio de RustDesk, de lo contrario la aplicación puede ser incapaz de encontrar los recursos necesarios. También hay que tener en cuenta que otros subcomandos de carga como `install` o `run` no estan actualmente soportados via este metodo y podrían requerir ser instalados dentro del contenedor y no en el host.
|
||||
|
||||
## Estructura de archivos
|
||||
|
||||
- **[libs/hbb_common](https://github.com/rustdesk/rustdesk/tree/master/libs/hbb_common)**: video codec, configuración, tcp/udp wrapper, protobuf, fs funciones para transferencia de ficheros, y alguna función de utilidad.
|
||||
- **[libs/scrap](https://github.com/rustdesk/rustdesk/tree/master/libs/scrap)**: captura de pantalla
|
||||
- **[libs/enigo](https://github.com/rustdesk/rustdesk/tree/master/libs/enigo)**: control específico por cada plataforma para el teclado/ratón
|
||||
- **[src/ui](https://github.com/rustdesk/rustdesk/tree/master/src/ui)**: GUI
|
||||
- **[src/server](https://github.com/rustdesk/rustdesk/tree/master/src/server)**: sonido/portapapeles/entrada/servicios de video, y conexiones de red
|
||||
- **[src/client.rs](https://github.com/rustdesk/rustdesk/tree/master/src/client.rs)**: iniciar una conexión "peer to peer"
|
||||
- **[src/rendezvous_mediator.rs](https://github.com/rustdesk/rustdesk/tree/master/src/rendezvous_mediator.rs)**: Comunicación con [rustdesk-server](https://github.com/rustdesk/rustdesk-server), esperar la conexión remota directa ("TCP hole punching") o conexión indirecta ("relayed")
|
||||
- **[src/platform](https://github.com/rustdesk/rustdesk/tree/master/src/platform)**: código específico de cada plataforma
|
||||
|
||||
## Captura de pantalla
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
161
README-FI.md
Normal file
161
README-FI.md
Normal file
@@ -0,0 +1,161 @@
|
||||
<p align="center">
|
||||
<img src="logo-header.svg" alt="RustDesk - Etätyöpöytäsi"><br>
|
||||
<a href="#free-public-servers">Palvelimet</a> •
|
||||
<a href="#raw-steps-to-build">Rakenna</a> •
|
||||
<a href="#how-to-build-with-docker">Docker</a> •
|
||||
<a href="#file-structure">Rakenne</a> •
|
||||
<a href="#snapshot">Tilannevedos</a><br>
|
||||
[<a href="README-ZH.md">中文</a>] | [<a href="README-ES.md">Español</a>] | [<a href="README-FR.md">Français</a>] | [<a href="README-DE.md">Deutsch</a>] | [<a href="README-PL.md">Polski</a>] | [<a href="README-FI.md">Suomi</a>] | [<a href="README-ML.md">മലയാളം</a>] | [<a href="README-JP.md">日本語</a>] | [<a href="README-NL.md">Nederlands</a>] | [<a href="README-IT.md">Italiano</a>] | [<a href="README-RU.md">Русский</a>] | [<a href="README-PTBR.md">Português (Brasil)</a>] | [<a href="README-EO.md">Esperanto</a>]<br>
|
||||
<b>Tarvitsemme apua tämän README-tiedoston kääntämiseksi äidinkielellesi</b>
|
||||
</p>
|
||||
|
||||
Juttele meidän kanssa: [Discord](https://discord.gg/nDceKgxnkV) | [Reddit](https://www.reddit.com/r/rustdesk)
|
||||
|
||||
[](https://ko-fi.com/I2I04VU09)
|
||||
|
||||
Vielä yksi etätyöpöytäohjelmisto, ohjelmoitu Rust-kielellä. Toimii suoraan pakkauksesta, ei tarvitse asetuksia. Hallitset täysin tietojasi, ei tarvitse murehtia turvallisuutta. Voit käyttää meidän rendezvous/relay-palvelinta, [aseta omasi](https://rustdesk.com/server), tai [kirjoita oma rendezvous/relay-palvelin](https://github.com/rustdesk/rustdesk-server-demo).
|
||||
|
||||
RustDesk toivottaa avustukset tervetulleiksi kaikilta. Katso lisätietoja [`CONTRIBUTING.md`](CONTRIBUTING.md) avun saamiseksi.
|
||||
|
||||
[**BINAARILATAUS**](https://github.com/rustdesk/rustdesk/releases)
|
||||
|
||||
## Vapaita julkisia palvelimia
|
||||
|
||||
Alla on palvelimia, joita voit käyttää ilmaiseksi, ne saattavat muuttua ajan mittaan. Jos et ole lähellä yhtä näistä, verkkosi voi olla hidas.
|
||||
| Sijainti | Myyjä | Määrittely |
|
||||
| --------- | ------------- | ------------------ |
|
||||
| Seoul | AWS lightsail | 1 VCPU / 0.5GB RAM |
|
||||
| Singapore | Vultr | 1 VCPU / 1GB RAM |
|
||||
| Dallas | Vultr | 1 VCPU / 1GB RAM | |
|
||||
|
||||
## Riippuvuudet
|
||||
|
||||
Desktop-versiot käyttävät [sciter](https://sciter.com/) graafisena käyttöliittymänä, lataa sciter-dynaaminen kirjasto itsellesi.
|
||||
|
||||
[Windows](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.win/x64/sciter.dll) |
|
||||
[Linux](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.lnx/x64/libsciter-gtk.so) |
|
||||
[MacOS](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.osx/libsciter.dylib)
|
||||
|
||||
## Rakentamisaskeleet harppoen
|
||||
|
||||
- Valmistele Rust-kehitysympäristö ja C++-rakentamisympäristö
|
||||
|
||||
- Asenna [vcpkg](https://github.com/microsoft/vcpkg), ja aseta `VCPKG_ROOT`-ympäristömuuttuja oikein
|
||||
|
||||
- Windows: vcpkg install libvpx:x64-windows-static libyuv:x64-windows-static opus:x64-windows-static
|
||||
- Linux/MacOS: vcpkg install libvpx libyuv opus
|
||||
|
||||
- aja `cargo run`
|
||||
|
||||
## Kuinka rakentaa Linuxissa
|
||||
|
||||
### Ubuntu 18 (Debian 10)
|
||||
|
||||
```sh
|
||||
sudo apt install -y g++ gcc git curl wget nasm yasm libgtk-3-dev clang libxcb-randr0-dev libxdo-dev libxfixes-dev libxcb-shape0-dev libxcb-xfixes0-dev libasound2-dev libpulse-dev cmake
|
||||
```
|
||||
|
||||
### Fedora 28 (CentOS 8)
|
||||
|
||||
```sh
|
||||
sudo yum -y install gcc-c++ git curl wget nasm yasm gcc gtk3-devel clang libxcb-devel libxdo-devel libXfixes-devel pulseaudio-libs-devel cmake alsa-lib-devel
|
||||
```
|
||||
|
||||
### Arch (Manjaro)
|
||||
|
||||
```sh
|
||||
sudo pacman -Syu --needed unzip git cmake gcc curl wget yasm nasm zip make pkg-config clang gtk3 xdotool libxcb libxfixes alsa-lib pulseaudio
|
||||
```
|
||||
|
||||
### Asenna vcpkg
|
||||
|
||||
```sh
|
||||
git clone https://github.com/microsoft/vcpkg
|
||||
cd vcpkg
|
||||
git checkout 2021.12.01
|
||||
cd ..
|
||||
vcpkg/bootstrap-vcpkg.sh
|
||||
export VCPKG_ROOT=$HOME/vcpkg
|
||||
vcpkg/vcpkg install libvpx libyuv opus
|
||||
```
|
||||
|
||||
### Korjaa libvpx (Fedora-linux-versiota varten)
|
||||
|
||||
```sh
|
||||
cd vcpkg/buildtrees/libvpx/src
|
||||
cd *
|
||||
./configure
|
||||
sed -i 's/CFLAGS+=-I/CFLAGS+=-fPIC -I/g' Makefile
|
||||
sed -i 's/CXXFLAGS+=-I/CXXFLAGS+=-fPIC -I/g' Makefile
|
||||
make
|
||||
cp libvpx.a $HOME/vcpkg/installed/x64-linux/lib/
|
||||
cd
|
||||
```
|
||||
|
||||
### Rakenna
|
||||
|
||||
```sh
|
||||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
|
||||
source $HOME/.cargo/env
|
||||
git clone https://github.com/rustdesk/rustdesk
|
||||
cd rustdesk
|
||||
mkdir -p target/debug
|
||||
wget https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.lnx/x64/libsciter-gtk.so
|
||||
mv libsciter-gtk.so target/debug
|
||||
VCPKG_ROOT=$HOME/vcpkg cargo run
|
||||
```
|
||||
|
||||
### Vaihda Wayland-ympäristö X11 (Xorg)-ympäristöön
|
||||
|
||||
RustDesk ei tue Waylandia. Tarkista [tämä](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/) asettamaan Xorg oletus GNOME-istuntona.
|
||||
|
||||
## Kuinka rakennetaan Dockerin kanssa
|
||||
|
||||
Aloita kloonaamalla tietovarasto ja rakentamalla docker-säiliö:
|
||||
|
||||
```sh
|
||||
git clone https://github.com/rustdesk/rustdesk
|
||||
cd rustdesk
|
||||
docker build -t "rustdesk-builder" .
|
||||
```
|
||||
|
||||
Sitten, joka kerta kun sinun on rakennettava sovellus, aja seuraava komento:
|
||||
|
||||
```sh
|
||||
docker run --rm -it -v $PWD:/home/user/rustdesk -v rustdesk-git-cache:/home/user/.cargo/git -v rustdesk-registry-cache:/home/user/.cargo/registry -e PUID="$(id -u)" -e PGID="$(id -g)" rustdesk-builder
|
||||
```
|
||||
|
||||
Huomaa, että ensimmäinen rakentaminen saattaa kestää pitempään ennen kuin riippuvuudet on siirretty välimuistiin, seuraavat rakentamiset ovat nopeampia. Lisäksi, jos sinun on määritettävä eri argumentteja rakentamiskomennolle, saatat tehdä sen niin, että komennon lopussa <OPTIONAL-ARGS>`-kohdassa. Esimerkiksi, jos haluat rakentaa optimoidun julkaisuversion, sinun on ajettava komento yllä siten, että sitä seuraa argumentti`---release`. Suoritettava tiedosto on saatavilla järjestelmäsi kohdehakemistossa, ja se voidaan suorittaa seuraavan kera:
|
||||
|
||||
```sh
|
||||
target/debug/rustdesk
|
||||
```
|
||||
|
||||
Tai, jos olet suorittamassa jakeluversion suoritettavaa tiedostoa:
|
||||
|
||||
```sh
|
||||
target/release/rustdesk
|
||||
```
|
||||
|
||||
Varmista, että suoritat näitä komentoja RustDesktop-tietovaraston juurihakemistossa, muutoin sovellus ei ehkä löydä vaadittuja resursseja. Huomaa myös, että muita cargo-alikomentoja kuten `install` tai `run` ei nykyisin tueta tässä menetelmässä, koska ne asentavat tai suorittavat ohjelman säiliön sisällä eikä isäntäohjelman sisällä.
|
||||
|
||||
## Tiedostorakenne
|
||||
|
||||
- **[libs/hbb_common](https://github.com/rustdesk/rustdesk/tree/master/libs/hbb_common)**: video codec, config, tcp/udp wrapper, protobuf, fs-funktiot tiedostosiirtoon, ja jotkut muut apuohjelmafunktiot
|
||||
- **[libs/scrap](https://github.com/rustdesk/rustdesk/tree/master/libs/scrap)**: näyttökaappaukset
|
||||
- **[libs/enigo](https://github.com/rustdesk/rustdesk/tree/master/libs/enigo)**: platform specific keyboard/mouse control
|
||||
- **[src/ui](https://github.com/rustdesk/rustdesk/tree/master/src/ui)**: Graafinen käyttöliittymä
|
||||
- **[src/server](https://github.com/rustdesk/rustdesk/tree/master/src/server)**: audio/clipboard/input/video services, and network connections
|
||||
- **[src/client.rs](https://github.com/rustdesk/rustdesk/tree/master/src/client.rs)**: start a peer connection
|
||||
- **[src/rendezvous_mediator.rs](https://github.com/rustdesk/rustdesk/tree/master/src/rendezvous_mediator.rs)**: Communicate with [rustdesk-server](https://github.com/rustdesk/rustdesk-server), wait for remote direct (TCP hole punching) or relayed connection
|
||||
- **[src/platform](https://github.com/rustdesk/rustdesk/tree/master/src/platform)**: platform specific code
|
||||
|
||||
## Tilannekuvat
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
160
README-FR.md
Normal file
160
README-FR.md
Normal file
@@ -0,0 +1,160 @@
|
||||
<p align="center">
|
||||
<img src="logo-header.svg" alt="RustDesk - Your remote desktop"><br>
|
||||
<a href="#serveurs-publics-libres">Serveurs</a> -
|
||||
<a href="#étapes-brutes-de-la-compilationbuild">Build</a> -
|
||||
<a href="#comment-construire-avec-docker">Docker</a> -
|
||||
<a href="#structure-du-projet">Structure</a> -
|
||||
<a href="#images">Images</a><br>
|
||||
[<a href="README-ZH.md">中文</a>] | [<a href="README-ES.md">Español</a>] | [<a href="README-FR.md">Français</a>] | [<a href="README-DE.md">Deutsch</a>] | [<a href="README-PL.md">Polski</a>] | [<a href="README-FI.md">Suomi</a>] | [<a href="README-ML.md">മലയാളം</a>] | [<a href="README-JP.md">日本語</a>] | [<a href="README-NL.md">Nederlands</a>] | [<a href="README-IT.md">Italiano</a>] | [<a href="README-RU.md">Русский</a>] | [<a href="README-PTBR.md">Português (Brasil)</a>] | [<a href="README-EO.md">Esperanto</a>]<br>
|
||||
<b>Nous avons besoin de votre aide pour traduire ce README dans votre langue maternelle</b>.
|
||||
</p>
|
||||
|
||||
Chattez avec nous : [Discord](https://discord.gg/nDceKgxnkV) | [Reddit](https://www.reddit.com/r/rustdesk)
|
||||
|
||||
[](https://ko-fi.com/I2I04VU09)
|
||||
|
||||
Encore un autre logiciel de bureau à distance, écrit en Rust. Fonctionne directement, aucune configuration n'est nécessaire. Vous avez le contrôle total de vos données, sans aucun souci de sécurité. Vous pouvez utiliser notre serveur de rendez-vous/relais, [configurer le vôtre](https://rustdesk.com/server), ou [écrire votre propre serveur de rendez-vous/relais](https://github.com/rustdesk/rustdesk-server-demo).
|
||||
|
||||
RustDesk accueille les contributions de tout le monde. Voir [`CONTRIBUTING.md`](CONTRIBUTING.md) pour plus d'informations.
|
||||
|
||||
[**TÉLÉCHARGEMENT BINAIRE**](https://github.com/rustdesk/rustdesk/releases)
|
||||
|
||||
## Serveurs publics libres
|
||||
|
||||
Ci-dessous se trouvent les serveurs que vous utilisez gratuitement, cela peut changer au fil du temps. Si vous n'êtes pas proche de l'un d'entre eux, votre réseau peut être lent.
|
||||
|
||||
- Séoul, AWS lightsail, 1 VCPU/0.5G RAM
|
||||
- Singapour, Vultr, 1 VCPU/1G RAM
|
||||
- Dallas, Vultr, 1 VCPU/1G RAM
|
||||
|
||||
## Dépendances
|
||||
|
||||
Les versions de bureau utilisent [sciter](https://sciter.com/) pour l'interface graphique, veuillez télécharger la bibliothèque dynamique sciter vous-même.
|
||||
|
||||
[Windows](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.win/x64/sciter.dll) |
|
||||
[Linux](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.lnx/x64/libsciter-gtk.so)
|
||||
[macOS](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.osx/libsciter.dylib)
|
||||
|
||||
## Étapes brutes de la compilation/build
|
||||
|
||||
- Préparez votre environnement de développement Rust et votre environnement de compilation C++.
|
||||
|
||||
- Installez [vcpkg](https://github.com/microsoft/vcpkg), et définissez correctement la variable d'environnement `VCPKG_ROOT`.
|
||||
|
||||
- Windows : vcpkg install libvpx:x64-windows-static libyuv:x64-windows-static opus:x64-windows-static
|
||||
- Linux/Osx : vcpkg install libvpx libyuv opus
|
||||
|
||||
- Exécuter `cargo run`
|
||||
|
||||
## Comment compiler/build sous Linux
|
||||
|
||||
### Ubuntu 18 (Debian 10)
|
||||
|
||||
```sh
|
||||
sudo apt install -y g++ gcc git curl wget nasm yasm libgtk-3-dev clang libxcb-randr0-dev libxdo-dev libxfixes-dev libxcb-shape0-dev libxcb-xfixes0-dev libasound2-dev libpulse-dev cmake
|
||||
```
|
||||
|
||||
### Fedora 28 (CentOS 8)
|
||||
|
||||
```sh
|
||||
sudo yum -y install gcc-c++ git curl wget nasm yasm gcc gtk3-devel clang libxcb-devel libxdo-devel libXfixes-devel pulseaudio-libs-devel cmake alsa-lib-devel
|
||||
```
|
||||
|
||||
### Arch (Manjaro)
|
||||
|
||||
```sh
|
||||
sudo pacman -Syu --needed unzip git cmake gcc curl wget yasm nasm zip make pkg-config clang gtk3 xdotool libxcb libxfixes alsa-lib pulseaudio
|
||||
```
|
||||
|
||||
### Installer vcpkg
|
||||
|
||||
```sh
|
||||
git clone https://github.com/microsoft/vcpkg
|
||||
cd vcpkg
|
||||
git checkout 2021.12.01
|
||||
cd ..
|
||||
vcpkg/bootstrap-vcpkg.sh
|
||||
export VCPKG_ROOT=$HOME/vcpkg
|
||||
vcpkg/vcpkg install libvpx libyuv opus
|
||||
```
|
||||
|
||||
### Corriger libvpx (Pour Fedora)
|
||||
|
||||
```sh
|
||||
cd vcpkg/buildtrees/libvpx/src
|
||||
cd *
|
||||
./configure
|
||||
sed -i 's/CFLAGS+=-I/CFLAGS+=-fPIC -I/g' Makefile
|
||||
sed -i 's/CXXFLAGS+=-I/CXXFLAGS+=-fPIC -I/g' Makefile
|
||||
make
|
||||
cp libvpx.a $HOME/vcpkg/installed/x64-linux/lib/
|
||||
cd
|
||||
```
|
||||
|
||||
### Construire
|
||||
|
||||
```sh
|
||||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
|
||||
source $HOME/.cargo/env
|
||||
git clone https://github.com/rustdesk/rustdesk
|
||||
cd rustdesk
|
||||
mkdir -p cible/debug
|
||||
wget https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.lnx/x64/libsciter-gtk.so
|
||||
mv libsciter-gtk.so target/debug
|
||||
Exécution du cargo
|
||||
```
|
||||
|
||||
### Changer Wayland en X11 (Xorg)
|
||||
|
||||
RustDesk ne supporte pas Wayland. Lisez [cela](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/) pour configurer Xorg comme la session GNOME par défaut.
|
||||
|
||||
## Comment construire avec Docker
|
||||
|
||||
Commencez par cloner le dépôt et construire le conteneur Docker :
|
||||
|
||||
```sh
|
||||
git clone https://github.com/rustdesk/rustdesk
|
||||
cd rustdesk
|
||||
docker build -t "rustdesk-builder" .
|
||||
```
|
||||
|
||||
Ensuite, chaque fois que vous devez compiler le logiciel, exécutez la commande suivante :
|
||||
|
||||
```sh
|
||||
docker run --rm -it -v $PWD:/home/user/rustdesk -v rustdesk-git-cache:/home/user/.cargo/git -v rustdesk-registry-cache:/home/user/.cargo/registry -e PUID="$(id -u)" -e PGID="$(id -g)" rustdesk-builder
|
||||
```
|
||||
|
||||
Notez que la première compilation peut prendre plus de temps avant que les dépendances ne soient mises en cache, les compilations suivantes seront plus rapides. De plus, si vous devez spécifier différents arguments à la commande de compilation, vous pouvez le faire à la fin de la commande à la position `<OPTIONAL-ARGS>`. Par exemple, si vous voulez compiler une version de release optimisée, vous devez exécuter la commande ci-dessus suivie de `---release`. L'exécutable résultant sera disponible dans le dossier cible sur votre système, et peut être lancé avec :
|
||||
|
||||
```sh
|
||||
target/debug/rustdesk
|
||||
```
|
||||
|
||||
Ou, si vous exécutez un exécutable provenant d'une release :
|
||||
|
||||
```sh
|
||||
target/release/rustdesk
|
||||
```
|
||||
|
||||
Veuillez vous assurer que vous exécutez ces commandes à partir de la racine du dépôt RustDesk, sinon l'application ne pourra pas trouver les ressources requises. Notez également que les autres sous-commandes de cargo telles que `install` ou `run` ne sont pas actuellement supportées par cette méthode car elles installeraient ou exécuteraient le programme à l'intérieur du conteneur au lieu de l'hôte.
|
||||
|
||||
## Structure du projet
|
||||
|
||||
- **[libs/hbb_common](https://github.com/rustdesk/rustdesk/tree/master/libs/hbb_common)** : codec vidéo, config, wrapper tcp/udp, protobuf, fonctions fs pour le transfert de fichiers, et quelques autres fonctions utilitaires.
|
||||
- **[libs/scrap](https://github.com/rustdesk/rustdesk/tree/master/libs/scrap)** : capture d'écran
|
||||
- **[libs/enigo](https://github.com/rustdesk/rustdesk/tree/master/libs/enigo)** : contrôle clavier/souris spécifique à la plate-forme
|
||||
- **[src/ui](https://github.com/rustdesk/rustdesk/tree/master/src/ui)** : interface graphique
|
||||
- **[src/server](https://github.com/rustdesk/rustdesk/tree/master/src/server)** : services audio/clipboard/input/vidéo, et connexions réseau
|
||||
- **[src/client.rs](https://github.com/rustdesk/rustdesk/tree/master/src/client.rs)** : démarrer une connexion entre pairs
|
||||
- **[src/rendezvous_mediator.rs](https://github.com/rustdesk/rustdesk/tree/master/src/rendezvous_mediator.rs)** : Communiquer avec [rustdesk-server](https://github.com/rustdesk/rustdesk-server), attendre une connexion distante directe (TCP hole punching) ou relayée.
|
||||
- **[src/platform](https://github.com/rustdesk/rustdesk/tree/master/src/platform)** : code spécifique à la plateforme
|
||||
|
||||
## Images
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
161
README-IT.md
Normal file
161
README-IT.md
Normal file
@@ -0,0 +1,161 @@
|
||||
<p align="center">
|
||||
<img src="logo-header.svg" alt="RustDesk - Your remote desktop"><br>
|
||||
<a href="#server-pubblici-gratuiti">Servers</a> •
|
||||
<a href="#passaggi-per-la-compilazione">Compilazione</a> •
|
||||
<a href="#come-compilare-con-docker">Docker</a> •
|
||||
<a href="#struttura-dei-file">Struttura</a> •
|
||||
<a href="#screenshots">Screenshots</a><br>
|
||||
[<a href="README-ZH.md">中文</a>] | [<a href="README-ES.md">Español</a>] | [<a href="README-FR.md">Français</a>] | [<a href="README-DE.md">Deutsch</a>] | [<a href="README-PL.md">Polski</a>] | [<a href="README-FI.md">Suomi</a>] | [<a href="README-ML.md">മലയാളം</a>] | [<a href="README-JP.md">日本語</a>] | [<a href="README-NL.md">Nederlands</a>] | [<a href="README-IT.md">Italiano</a>] | [<a href="README-RU.md">Русский</a>] | [<a href="README-PTBR.md">Português (Brasil)</a>] | [<a href="README-EO.md">Esperanto</a>]<br>
|
||||
<b>Abbiamo bisogno del tuo aiuto per tradurre questo README e la <a href="https://github.com/rustdesk/rustdesk/tree/master/src/lang">RustDesk UI</a> nella tua lingua nativa</b>
|
||||
</p>
|
||||
|
||||
Chatta con noi: [Discord](https://discord.gg/nDceKgxnkV) | [Reddit](https://www.reddit.com/r/rustdesk)
|
||||
|
||||
[](https://ko-fi.com/I2I04VU09)
|
||||
|
||||
Ancora un altro software per il controllo remoto del desktop, scritto in Rust. Funziona immediatamente, nessuna configurazione richiesta. Hai il pieno controllo dei tuoi dati, senza preoccupazioni per la sicurezza. Puoi utilizzare il nostro server rendezvous/relay, [configurare il tuo](https://rustdesk.com/server) o [scrivere il tuo rendezvous/relay server](https://github.com/rustdesk/rustdesk-server-demo).
|
||||
|
||||
RustDesk accoglie il contributo di tutti. Per ulteriori informazioni su come inizare a contribuire, vedere [`CONTRIBUTING.md`](CONTRIBUTING.md).
|
||||
|
||||
[**BINARY DOWNLOAD**](https://github.com/rustdesk/rustdesk/releases)
|
||||
|
||||
## Server pubblici gratuiti
|
||||
|
||||
Qui sotto trovate i server che possono essere usati gratuitamente, la lista potrebbe cambiare nel tempo. Se non si è vicini a uno di questi server, la vostra connessione potrebbe essere lenta.
|
||||
| Posizione | Vendor | Specifiche |
|
||||
| --------- | ------------- | ------------------ |
|
||||
| Seoul | AWS lightsail | 1 VCPU / 0.5GB RAM |
|
||||
| Singapore | Vultr | 1 VCPU / 1GB RAM |
|
||||
| Dallas | Vultr | 1 VCPU / 1GB RAM | |
|
||||
|
||||
## Dipendenze
|
||||
|
||||
La versione Desktop utilizza [sciter](https://sciter.com/) per la GUI, per favore scarica sciter dynamic library.
|
||||
|
||||
[Windows](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.win/x64/sciter.dll) |
|
||||
[Linux](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.lnx/x64/libsciter-gtk.so) |
|
||||
[MacOS](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.osx/libsciter.dylib)
|
||||
|
||||
## Passaggi per la compilazione
|
||||
|
||||
- Prepara l'ambiente per lo sviluppo e compilazione in Rust e C++
|
||||
|
||||
- Installa [vcpkg](https://github.com/microsoft/vcpkg), e imposta correttamente la variabile d'ambiente `VCPKG_ROOT`
|
||||
|
||||
- Windows: vcpkg install libvpx:x64-windows-static libyuv:x64-windows-static opus:x64-windows-static
|
||||
- Linux/MacOS: vcpkg install libvpx libyuv opus
|
||||
|
||||
- Esegui `cargo run`
|
||||
|
||||
## Come compilare su Linux
|
||||
|
||||
### Ubuntu 18 (Debian 10)
|
||||
|
||||
```sh
|
||||
sudo apt install -y g++ gcc git curl wget nasm yasm libgtk-3-dev clang libxcb-randr0-dev libxdo-dev libxfixes-dev libxcb-shape0-dev libxcb-xfixes0-dev libasound2-dev libpulse-dev cmake
|
||||
```
|
||||
|
||||
### Fedora 28 (CentOS 8)
|
||||
|
||||
```sh
|
||||
sudo yum -y install gcc-c++ git curl wget nasm yasm gcc gtk3-devel clang libxcb-devel libxdo-devel libXfixes-devel pulseaudio-libs-devel cmake alsa-lib-devel
|
||||
```
|
||||
|
||||
### Arch (Manjaro)
|
||||
|
||||
```sh
|
||||
sudo pacman -Syu --needed unzip git cmake gcc curl wget yasm nasm zip make pkg-config clang gtk3 xdotool libxcb libxfixes alsa-lib pulseaudio
|
||||
```
|
||||
|
||||
### Installare vcpkg
|
||||
|
||||
```sh
|
||||
git clone https://github.com/microsoft/vcpkg
|
||||
cd vcpkg
|
||||
git checkout 2021.12.01
|
||||
cd ..
|
||||
vcpkg/bootstrap-vcpkg.sh
|
||||
export VCPKG_ROOT=$HOME/vcpkg
|
||||
vcpkg/vcpkg install libvpx libyuv opus
|
||||
```
|
||||
|
||||
### Fix libvpx (Per Fedora)
|
||||
|
||||
```sh
|
||||
cd vcpkg/buildtrees/libvpx/src
|
||||
cd *
|
||||
./configure
|
||||
sed -i 's/CFLAGS+=-I/CFLAGS+=-fPIC -I/g' Makefile
|
||||
sed -i 's/CXXFLAGS+=-I/CXXFLAGS+=-fPIC -I/g' Makefile
|
||||
make
|
||||
cp libvpx.a $HOME/vcpkg/installed/x64-linux/lib/
|
||||
cd
|
||||
```
|
||||
|
||||
### Compilazione
|
||||
|
||||
```sh
|
||||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
|
||||
source $HOME/.cargo/env
|
||||
git clone https://github.com/rustdesk/rustdesk
|
||||
cd rustdesk
|
||||
mkdir -p target/debug
|
||||
wget https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.lnx/x64/libsciter-gtk.so
|
||||
mv libsciter-gtk.so target/debug
|
||||
VCPKG_ROOT=$HOME/vcpkg cargo run
|
||||
```
|
||||
|
||||
### Cambiare Wayland a X11 (Xorg)
|
||||
|
||||
RustDesk non supporta Wayland. Controlla [questo](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/) per configurare Xorg come sessione di default di GNOME.
|
||||
|
||||
## Come compilare con Docker
|
||||
|
||||
Cominciare clonando il repository e compilare i container docker:
|
||||
|
||||
```sh
|
||||
git clone https://github.com/rustdesk/rustdesk
|
||||
cd rustdesk
|
||||
docker build -t "rustdesk-builder" .
|
||||
```
|
||||
|
||||
Quindi, ogni volta che devi compilare l'applicazione, esegui il comando seguente:
|
||||
|
||||
```sh
|
||||
docker run --rm -it -v $PWD:/home/user/rustdesk -v rustdesk-git-cache:/home/user/.cargo/git -v rustdesk-registry-cache:/home/user/.cargo/registry -e PUID="$(id -u)" -e PGID="$(id -g)" rustdesk-builder
|
||||
```
|
||||
|
||||
Tieni presente che la prima build potrebbe richiedere più tempo prima che le dipendenze vengano memorizzate nella cache, le build successive saranno più veloci. Inoltre, se hai bisogno di specificare argomenti diversi per il comando build, puoi farlo alla fine del comando nella posizione `<OPTIONAL-ARGS>`. Ad esempio, se si desidera creare una versione di rilascio ottimizzata, eseguire il comando sopra seguito da `---release`. L'eseguibile generato sarà creato nella cartella di destinazione del proprio sistema e può essere eseguito con:
|
||||
|
||||
```sh
|
||||
target/debug/rustdesk
|
||||
```
|
||||
|
||||
Oppure, se si sta eseguendo un eseguibile di rilascio:
|
||||
|
||||
```sh
|
||||
target/release/rustdesk
|
||||
```
|
||||
|
||||
Assicurati di eseguire questi comandi dalla radice del repository RustDesk, altrimenti l'applicazione potrebbe non essere in grado di trovare le risorse richieste. Notare inoltre che altri sottocomandi cargo come `install` o `run` non sono attualmente supportati tramite questo metodo poiché installerebbero o eseguirebbero il programma all'interno del container anziché nell'host.
|
||||
|
||||
## Struttura dei file
|
||||
|
||||
- **[libs/hbb_common](https://github.com/rustdesk/rustdesk/tree/master/libs/hbb_common)**: video codec, config, tcp/udp wrapper, protobuf, fs funzioni per il trasferimento file, e altre funzioni utili.
|
||||
- **[libs/scrap](https://github.com/rustdesk/rustdesk/tree/master/libs/scrap)**: cattura dello schermo
|
||||
- **[libs/enigo](https://github.com/rustdesk/rustdesk/tree/master/libs/enigo)**: controllo tastiera/mouse specifico della piattaforma
|
||||
- **[src/ui](https://github.com/rustdesk/rustdesk/tree/master/src/ui)**: GUI
|
||||
- **[src/server](https://github.com/rustdesk/rustdesk/tree/master/src/server)**: servizi audio/appunti/input/video e connessioni di rete
|
||||
- **[src/client.rs](https://github.com/rustdesk/rustdesk/tree/master/src/client.rs)**: avviare una connessione peer
|
||||
- **[src/rendezvous_mediator.rs](https://github.com/rustdesk/rustdesk/tree/master/src/rendezvous_mediator.rs)**: Comunica con [rustdesk-server](https://github.com/rustdesk/rustdesk-server), attende la connessione remota diretta (TCP hole punching) oppure indiretta (relayed)
|
||||
- **[src/platform](https://github.com/rustdesk/rustdesk/tree/master/src/platform)**: codice specifico della piattaforma
|
||||
|
||||
## Screenshots
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
163
README-JP.md
Normal file
163
README-JP.md
Normal file
@@ -0,0 +1,163 @@
|
||||
<p align="center">
|
||||
<img src="logo-header.svg" alt="RustDesk - Your remote desktop"><br>
|
||||
<a href="#free-public-servers">Servers</a> •
|
||||
<a href="#raw-steps-to-build">Build</a> •
|
||||
<a href="#how-to-build-with-docker">Docker</a> •
|
||||
<a href="#file-structure">Structure</a> •
|
||||
<a href="#snapshot">Snapshot</a><br>
|
||||
[<a href="README-ZH.md">中文</a>] | [<a href="README-ES.md">Español</a>] | [<a href="README-FR.md">Français</a>] | [<a href="README-DE.md">Deutsch</a>] | [<a href="README-PL.md">Polski</a>] | [<a href="README-FI.md">Suomi</a>] | [<a href="README-ML.md">മലയാളം</a>] | [<a href="README-JP.md">日本語</a>] | [<a href="README-NL.md">Nederlands</a>] | [<a href="README-IT.md">Italiano</a>] | [<a href="README-RU.md">Русский</a>] | [<a href="README-PTBR.md">Português (Brasil)</a>] | [<a href="README-EO.md">Esperanto</a>]<br>
|
||||
<b>このREADMEをあなたの母国語に翻訳するために、あなたの助けが必要です。</b>
|
||||
</p>
|
||||
|
||||
Chat with us: [Discord](https://discord.gg/nDceKgxnkV) | [Reddit](https://www.reddit.com/r/rustdesk)
|
||||
|
||||
[](https://ko-fi.com/I2I04VU09)
|
||||
|
||||
Rustで書かれた、設定不要ですぐに使えるリモートデスクトップソフトウェアです。自分のデータを完全にコントロールでき、セキュリティの心配もありません。私たちのランデブー/リレーサーバを使うことも、[自分で設定する](https://rustdesk.com/server) ことも、 [自分でランデブー/リレーサーバを書くこともできます。](https://github.com/rustdesk/rustdesk-server-demo).
|
||||
|
||||
RustDeskは誰からの貢献も歓迎します。 貢献するには [`CONTRIBUTING.md`](CONTRIBUTING.md) を参照してください。
|
||||
|
||||
[**BINARY DOWNLOAD**](https://github.com/rustdesk/rustdesk/releases)
|
||||
|
||||
## 無料のパブリックサーバー
|
||||
|
||||
下記のサーバーは、無料で使用できますが、後々変更されることがあります。これらのサーバーから遠い場合、接続が遅い可能性があります。
|
||||
| Location | Vendor | Specification |
|
||||
| --------- | ------------- | ------------------ |
|
||||
| Seoul | AWS lightsail | 1 VCPU / 0.5GB RAM |
|
||||
| Singapore | Vultr | 1 VCPU / 1GB RAM |
|
||||
| Dallas | Vultr | 1 VCPU / 1GB RAM | |
|
||||
|
||||
## 依存関係
|
||||
|
||||
デスクトップ版ではGUIに [sciter](https://sciter.com/) が使われています。 sciter dynamic library をダウンロードしてください。
|
||||
|
||||
[Windows](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.win/x64/sciter.dll) |
|
||||
[Linux](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.lnx/x64/libsciter-gtk.so) |
|
||||
[MacOS](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.osx/libsciter.dylib)
|
||||
|
||||
## ビルド手順
|
||||
|
||||
- Rust開発環境とC ++ビルド環境を準備します
|
||||
|
||||
- [vcpkg](https://github.com/microsoft/vcpkg), をインストールし、 `VCPKG_ROOT` 環境変数を正しく設定します。
|
||||
|
||||
- Windows: vcpkg install libvpx:x64-windows-static libyuv:x64-windows-static opus:x64-windows-static
|
||||
- Linux/MacOS: vcpkg install libvpx libyuv opus
|
||||
|
||||
- run `cargo run`
|
||||
|
||||
## Linuxでのビルド手順
|
||||
|
||||
### Ubuntu 18 (Debian 10)
|
||||
|
||||
```sh
|
||||
sudo apt install -y g++ gcc git curl wget nasm yasm libgtk-3-dev clang libxcb-randr0-dev libxdo-dev libxfixes-dev libxcb-shape0-dev libxcb-xfixes0-dev libasound2-dev libpulse-dev cmake
|
||||
```
|
||||
|
||||
### Fedora 28 (CentOS 8)
|
||||
|
||||
```sh
|
||||
sudo yum -y install gcc-c++ git curl wget nasm yasm gcc gtk3-devel clang libxcb-devel libxdo-devel libXfixes-devel pulseaudio-libs-devel cmake alsa-lib-devel
|
||||
```
|
||||
|
||||
### Arch (Manjaro)
|
||||
|
||||
```sh
|
||||
sudo pacman -Syu --needed unzip git cmake gcc curl wget yasm nasm zip make pkg-config clang gtk3 xdotool libxcb libxfixes alsa-lib pulseaudio
|
||||
```
|
||||
|
||||
### Install vcpkg
|
||||
|
||||
```sh
|
||||
git clone https://github.com/microsoft/vcpkg
|
||||
cd vcpkg
|
||||
git checkout 2021.12.01
|
||||
cd ..
|
||||
vcpkg/bootstrap-vcpkg.sh
|
||||
export VCPKG_ROOT=$HOME/vcpkg
|
||||
vcpkg/vcpkg install libvpx libyuv opus
|
||||
```
|
||||
|
||||
### Fix libvpx (For Fedora)
|
||||
|
||||
```sh
|
||||
cd vcpkg/buildtrees/libvpx/src
|
||||
cd *
|
||||
./configure
|
||||
sed -i 's/CFLAGS+=-I/CFLAGS+=-fPIC -I/g' Makefile
|
||||
sed -i 's/CXXFLAGS+=-I/CXXFLAGS+=-fPIC -I/g' Makefile
|
||||
make
|
||||
cp libvpx.a $HOME/vcpkg/installed/x64-linux/lib/
|
||||
cd
|
||||
```
|
||||
|
||||
### Build
|
||||
|
||||
```sh
|
||||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
|
||||
source $HOME/.cargo/env
|
||||
git clone https://github.com/rustdesk/rustdesk
|
||||
cd rustdesk
|
||||
mkdir -p target/debug
|
||||
wget https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.lnx/x64/libsciter-gtk.so
|
||||
mv libsciter-gtk.so target/debug
|
||||
VCPKG_ROOT=$HOME/vcpkg cargo run
|
||||
```
|
||||
|
||||
### Wayland の場合、X11(Xorg)に変更します
|
||||
|
||||
RustDeskはWaylandをサポートしていません。
|
||||
[こちら](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/) を確認して、XorgをデフォルトのGNOMEセッションとして構成します。
|
||||
|
||||
## Dockerでビルドする方法
|
||||
|
||||
リポジトリのクローンを作成し、Dockerコンテナを構築することから始めます。
|
||||
|
||||
```sh
|
||||
git clone https://github.com/rustdesk/rustdesk
|
||||
cd rustdesk
|
||||
docker build -t "rustdesk-builder" .
|
||||
```
|
||||
|
||||
その後、アプリケーションをビルドする必要があるたびに、以下のコマンドを実行します。
|
||||
|
||||
```sh
|
||||
docker run --rm -it -v $PWD:/home/user/rustdesk -v rustdesk-git-cache:/home/user/.cargo/git -v rustdesk-registry-cache:/home/user/.cargo/registry -e PUID="$(id -u)" -e PGID="$(id -g)" rustdesk-builder
|
||||
```
|
||||
|
||||
なお、最初のビルドでは、依存関係がキャッシュされるまで時間がかかることがありますが、その後のビルドではより速くなります。さらに、ビルドコマンドに別の引数を指定する必要がある場合は、コマンドの最後にある `<OPTIONAL-ARGS>` の位置で指定することができます。例えば、最適化されたリリースバージョンをビルドしたい場合は、上記のコマンドの後に
|
||||
`---release` を実行します。できあがった実行ファイルは、システムのターゲット・フォルダに格納され、次のコマンドで実行できます。
|
||||
|
||||
```sh
|
||||
target/debug/rustdesk
|
||||
```
|
||||
|
||||
あるいは、リリース用の実行ファイルを実行している場合:
|
||||
|
||||
```sh
|
||||
target/release/rustdesk
|
||||
```
|
||||
|
||||
これらのコマンドをRustDeskリポジトリのルートから実行していることを確認してください。そうしないと、アプリケーションが必要なリソースを見つけられない可能性があります。また、 `install` や `run` などの他の cargo サブコマンドは、ホストではなくコンテナ内にプログラムをインストールまたは実行するため、現在この方法ではサポートされていないことに注意してください。
|
||||
|
||||
## File Structure
|
||||
|
||||
- **[libs/hbb_common](https://github.com/rustdesk/rustdesk/tree/master/libs/hbb_common)**: ビデオコーデック、コンフィグ、tcp/udpラッパー、protobuf、ファイル転送用のfs関数、その他のユーティリティ関数
|
||||
- **[libs/scrap](https://github.com/rustdesk/rustdesk/tree/master/libs/scrap)**: スクリーンキャプチャ
|
||||
- **[libs/enigo](https://github.com/rustdesk/rustdesk/tree/master/libs/enigo)**: プラットフォーム固有のキーボード/マウスコントロール
|
||||
- **[src/ui](https://github.com/rustdesk/rustdesk/tree/master/src/ui)**: GUI
|
||||
- **[src/server](https://github.com/rustdesk/rustdesk/tree/master/src/server)**: オーディオ/クリップボード/入力/ビデオサービス、ネットワーク接続
|
||||
- **[src/client.rs](https://github.com/rustdesk/rustdesk/tree/master/src/client.rs)**: ピア接続の開始
|
||||
- **[src/rendezvous_mediator.rs](https://github.com/rustdesk/rustdesk/tree/master/src/rendezvous_mediator.rs)**: [rustdesk-server](https://github.com/rustdesk/rustdesk-server), と通信し、リモートダイレクト (TCP hole punching) または中継接続を待つ。
|
||||
- **[src/platform](https://github.com/rustdesk/rustdesk/tree/master/src/platform)**: プラットフォーム固有のコード
|
||||
|
||||
## Snapshot
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
161
README-ML.md
Normal file
161
README-ML.md
Normal file
@@ -0,0 +1,161 @@
|
||||
<p align="center">
|
||||
<img src="logo-header.svg" alt="RustDesk - Your remote desktop"><br>
|
||||
<a href="#free-public-servers">Servers</a> •
|
||||
<a href="#raw-steps-to-build">Build</a> •
|
||||
<a href="#how-to-build-with-docker">Docker</a> •
|
||||
<a href="#file-structure">Structure</a> •
|
||||
<a href="#snapshot">Snapshot</a><br>
|
||||
[<a href="README-ZH.md">中文</a>] | [<a href="README-ES.md">Español</a>] | [<a href="README-FR.md">Français</a>] | [<a href="README-DE.md">Deutsch</a>] | [<a href="README-PL.md">Polski</a>] | [<a href="README-FI.md">Suomi</a>] | [<a href="README-ML.md">മലയാളം</a>] | [<a href="README-JP.md">日本語</a>] | [<a href="README-NL.md">Nederlands</a>] | [<a href="README-IT.md">Italiano</a>] | [<a href="README-RU.md">Русский</a>] | [<a href="README-PTBR.md">Português (Brasil)</a>] | [<a href="README-EO.md">Esperanto</a>]<br>
|
||||
<b>ഈ README നിങ്ങളുടെ മാതൃഭാഷയിലേക്ക് വിവർത്തനം ചെയ്യാൻ ഞങ്ങൾക്ക് നിങ്ങളുടെ സഹായം ആവശ്യമാണ്</b>
|
||||
</p>
|
||||
|
||||
ഞങ്ങളുമായി ചാറ്റ് ചെയ്യുക: [Discord](https://discord.gg/nDceKgxnkV) | [Reddit](https://www.reddit.com/r/rustdesk)
|
||||
|
||||
[](https://ko-fi.com/I2I04VU09)
|
||||
|
||||
റസ്റ്റിൽ എഴുതിയ മറ്റൊരു റിമോട്ട് ഡെസ്ക്ടോപ്പ് സോഫ്റ്റ്വെയർ. ബോക്സിന് പുറത്ത് പ്രവർത്തിക്കുന്നു, കോൺഫിഗറേഷൻ ആവശ്യമില്ല. സുരക്ഷയെക്കുറിച്ച് ആശങ്കകളൊന്നുമില്ലാതെ, നിങ്ങളുടെ ഡാറ്റയുടെ പൂർണ്ണ നിയന്ത്രണം നിങ്ങൾക്കുണ്ട്. നിങ്ങൾക്ക് ഞങ്ങളുടെ rendezvous/relay സെർവർ ഉപയോഗിക്കാം, [സ്വന്തമായി സജ്ജീകരിക്കുക](https://rustdesk.com/server), അല്ലെങ്കിൽ [നിങ്ങളുടെ സ്വന്തം rendezvous/relay സെർവർ എഴുതുക](https://github.com/rustdesk/rustdesk-server-demo).
|
||||
|
||||
എല്ലാവരുടെയും സംഭാവനയെ RustDesk സ്വാഗതം ചെയ്യുന്നു. ആരംഭിക്കുന്നതിനുള്ള സഹായത്തിന് [`CONTRIBUTING.md`](CONTRIBUTING.md) കാണുക.
|
||||
|
||||
[**BINARY DOWNLOAD**](https://github.com/rustdesk/rustdesk/releases)
|
||||
|
||||
## സൗജന്യ പൊതു സെർവറുകൾ
|
||||
|
||||
നിങ്ങൾ സൗജന്യമായി ഉപയോഗിക്കുന്ന സെർവറുകൾ ചുവടെയുണ്ട്, അത് സമയത്തിനനുസരിച്ച് മാറിയേക്കാം. നിങ്ങൾ ഇവയിലൊന്നിനോട് അടുത്തല്ലെങ്കിൽ, നിങ്ങളുടെ നെറ്റ്വർക്ക് സ്ലോ ആയേക്കാം.
|
||||
| സ്ഥാനം | കച്ചവടക്കാരൻ | വിവരണം |
|
||||
| --------- | ------------- | ------------------ |
|
||||
| Seoul | AWS lightsail | 1 VCPU / 0.5GB RAM |
|
||||
| Singapore | Vultr | 1 VCPU / 1GB RAM |
|
||||
| Dallas | Vultr | 1 VCPU / 1GB RAM | |
|
||||
|
||||
## ഡിപെൻഡൻസികൾ
|
||||
|
||||
ഡെസ്ക്ടോപ്പ് പതിപ്പുകൾ GUI-യ്ക്കായി [sciter](https://sciter.com/) ഉപയോഗിക്കുന്നു, ദയവായി സ്സൈറ്റർ ഡൈനാമിക് ലൈബ്രറി സ്വയം ഡൗൺലോഡ് ചെയ്യുക.
|
||||
|
||||
[Windows](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.win/x64/sciter.dll) |
|
||||
[Linux](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.lnx/x64/libsciter-gtk.so) |
|
||||
[MacOS](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.osx/libsciter.dylib)
|
||||
|
||||
## നിർമ്മിക്കാനുള്ള അസംസ്കൃത പടികൾ
|
||||
|
||||
- നിങ്ങളുടെ Rust development envയും and C++ build envയും തയ്യാറാക്കുക
|
||||
|
||||
- [vcpkg](https://github.com/microsoft/vcpkg) ഇൻസ്റ്റാൾ ചെയ്ത് `VCPKG_ROOT` env വേരിയബിൾ ശരിയായി സജ്ജമാക്കുക
|
||||
|
||||
- Windows: vcpkg install libvpx:x64-windows-static libyuv:x64-windows-static opus:x64-windows-static
|
||||
- Linux/MacOS: vcpkg install libvpx libyuv opus
|
||||
|
||||
- run `cargo run`
|
||||
|
||||
## ലിനക്സിൽ എങ്ങനെ നിർമ്മിക്കാം
|
||||
|
||||
### ഉബുണ്ടു 18 (ഡെബിയൻ 10)
|
||||
|
||||
```sh
|
||||
sudo apt install -y g++ gcc git curl wget nasm yasm libgtk-3-dev clang libxcb-randr0-dev libxdo-dev libxfixes-dev libxcb-shape0-dev libxcb-xfixes0-dev libasound2-dev libpulse-dev cmake
|
||||
```
|
||||
|
||||
### ഫെഡോറ 28 (CentOS 8)
|
||||
|
||||
```sh
|
||||
sudo yum -y install gcc-c++ git curl wget nasm yasm gcc gtk3-devel clang libxcb-devel libxdo-devel libXfixes-devel pulseaudio-libs-devel cmake alsa-lib-devel
|
||||
```
|
||||
|
||||
### ആർച് (മഞ്ചാരോ)
|
||||
|
||||
```sh
|
||||
sudo pacman -Syu --needed unzip git cmake gcc curl wget yasm nasm zip make pkg-config clang gtk3 xdotool libxcb libxfixes alsa-lib pulseaudio
|
||||
```
|
||||
|
||||
### vcpkg ഇൻസ്റ്റാൾ ചെയ്യുക
|
||||
|
||||
```sh
|
||||
git clone https://github.com/microsoft/vcpkg
|
||||
cd vcpkg
|
||||
git checkout 2021.12.01
|
||||
cd ..
|
||||
vcpkg/bootstrap-vcpkg.sh
|
||||
export VCPKG_ROOT=$HOME/vcpkg
|
||||
vcpkg/vcpkg install libvpx libyuv opus
|
||||
```
|
||||
|
||||
### libvpx പരിഹരിക്കുക (ഫെഡോറയ്ക്ക്)
|
||||
|
||||
```sh
|
||||
cd vcpkg/buildtrees/libvpx/src
|
||||
cd *
|
||||
./configure
|
||||
sed -i 's/CFLAGS+=-I/CFLAGS+=-fPIC -I/g' Makefile
|
||||
sed -i 's/CXXFLAGS+=-I/CXXFLAGS+=-fPIC -I/g' Makefile
|
||||
make
|
||||
cp libvpx.a $HOME/vcpkg/installed/x64-linux/lib/
|
||||
cd
|
||||
```
|
||||
|
||||
### നിർമാണം
|
||||
|
||||
```sh
|
||||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
|
||||
source $HOME/.cargo/env
|
||||
git clone https://github.com/rustdesk/rustdesk
|
||||
cd rustdesk
|
||||
mkdir -p target/debug
|
||||
wget https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.lnx/x64/libsciter-gtk.so
|
||||
mv libsciter-gtk.so target/debug
|
||||
VCPKG_ROOT=$HOME/vcpkg cargo run
|
||||
```
|
||||
|
||||
### വേലാൻഡ് X11 (Xorg) ആയി മാറ്റുക
|
||||
|
||||
RustDesk Wayland-നെ പിന്തുണയ്ക്കുന്നില്ല. സ്ഥിരസ്ഥിതി ഗ്നോം സെഷനായി Xorg കോൺഫിഗർ ചെയ്യുന്നതിന് [ഇത്](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/) പരിശോധിക്കുക.
|
||||
|
||||
## ഡോക്കർ ഉപയോഗിച്ച് എങ്ങനെ നിർമ്മിക്കാം
|
||||
|
||||
റെപ്പോസിറ്റോറി ക്ലോണുചെയ്ത് ഡോക്കർ കണ്ടെയ്നർ നിർമ്മിക്കുന്നതിലൂടെ ആരംഭിക്കുക:
|
||||
|
||||
```sh
|
||||
git clone https://github.com/rustdesk/rustdesk
|
||||
cd rustdesk
|
||||
docker build -t "rustdesk-builder" .
|
||||
```
|
||||
|
||||
തുടർന്ന്, ഓരോ തവണയും നിങ്ങൾ ആപ്ലിക്കേഷൻ നിർമ്മിക്കേണ്ടതുണ്ട്, ഇനിപ്പറയുന്ന കമാൻഡ് പ്രവർത്തിപ്പിക്കുക:
|
||||
|
||||
```sh
|
||||
docker run --rm -it -v $PWD:/home/user/rustdesk -v rustdesk-git-cache:/home/user/.cargo/git -v rustdesk-registry-cache:/home/user/.cargo/registry -e PUID="$(id -u)" -e PGID="$(id -g)" rustdesk-builder
|
||||
```
|
||||
|
||||
ഡിപൻഡൻസികൾ കാഷെ ചെയ്യുന്നതിനുമുമ്പ് ആദ്യ ബിൽഡ് കൂടുതൽ സമയമെടുത്തേക്കാം, തുടർന്നുള്ള ബിൽഡുകൾ വേഗത്തിലാകും. കൂടാതെ, നിങ്ങൾക്ക് ബിൽഡ് കമാൻഡിലേക്ക് വ്യത്യസ്ത ആർഗ്യുമെന്റുകൾ വ്യക്തമാക്കണമെങ്കിൽ, കമാൻഡിന്റെ അവസാനം `<OPTIONAL-ARGS>` സ്ഥാനത്ത് നിങ്ങൾക്ക് അങ്ങനെ ചെയ്യാം. ഉദാഹരണത്തിന്, നിങ്ങൾ ഒരു ഒപ്റ്റിമൈസ് ചെയ്ത റിലീസ് പതിപ്പ് നിർമ്മിക്കാൻ ആഗ്രഹിക്കുന്നുവെങ്കിൽ, മുകളിലുള്ള കമാൻഡ് തുടർന്ന് `---release` നിങ്ങൾ പ്രവർത്തിപ്പിക്കും. തത്ഫലമായുണ്ടാകുന്ന എക്സിക്യൂട്ടബിൾ നിങ്ങളുടെ സിസ്റ്റത്തിലെ ടാർഗെറ്റ് ഫോൾഡറിൽ ലഭ്യമാകും, കൂടാതെ ഇത് ഉപയോഗിച്ച് പ്രവർത്തിപ്പിക്കാം:
|
||||
|
||||
```sh
|
||||
target/debug/rustdesk
|
||||
```
|
||||
|
||||
അല്ലെങ്കിൽ, നിങ്ങൾ ഒരു റിലീസ് എക്സിക്യൂട്ടബിൾ പ്രവർത്തിപ്പിക്കുകയാണെങ്കിൽ:
|
||||
|
||||
```sh
|
||||
target/release/rustdesk
|
||||
```
|
||||
|
||||
RustDesk റിപ്പോസിറ്ററിയുടെ റൂട്ടിൽ നിന്നാണ് നിങ്ങൾ ഈ കമാൻഡുകൾ പ്രവർത്തിപ്പിക്കുന്നതെന്ന് ദയവായി ഉറപ്പാക്കുക, അല്ലാത്തപക്ഷം ആപ്ലിക്കേഷന് ആവശ്യമായ ഉറവിടങ്ങൾ കണ്ടെത്താൻ കഴിഞ്ഞേക്കില്ല. ഹോസ്റ്റിന് പകരം കണ്ടെയ്നറിനുള്ളിൽ പ്രോഗ്രാം ഇൻസ്റ്റാൾ ചെയ്യുകയോ പ്രവർത്തിപ്പിക്കുകയോ ചെയ്യുന്നതിനാൽ, `install` അല്ലെങ്കിൽ `run` പോലുള്ള മറ്റ് കാർഗോ സബ്കമാൻഡുകൾ നിലവിൽ ഈ രീതിയെ പിന്തുണയ്ക്കുന്നില്ല എന്നതും ശ്രദ്ധിക്കുക.
|
||||
|
||||
## ഫയൽ ഘടന
|
||||
|
||||
- **[libs/hbb_common](https://github.com/rustdesk/rustdesk/tree/master/libs/hbb_common)**: video codec, config, tcp/udp wrapper, protobuf, fs functions for file transfer, and some other utility functions
|
||||
- **[libs/scrap](https://github.com/rustdesk/rustdesk/tree/master/libs/scrap)**: screen capture
|
||||
- **[libs/enigo](https://github.com/rustdesk/rustdesk/tree/master/libs/enigo)**: platform specific keyboard/mouse control
|
||||
- **[src/ui](https://github.com/rustdesk/rustdesk/tree/master/src/ui)**: GUI
|
||||
- **[src/server](https://github.com/rustdesk/rustdesk/tree/master/src/server)**: audio/clipboard/input/video services, and network connections
|
||||
- **[src/client.rs](https://github.com/rustdesk/rustdesk/tree/master/src/client.rs)**: start a peer connection
|
||||
- **[src/rendezvous_mediator.rs](https://github.com/rustdesk/rustdesk/tree/master/src/rendezvous_mediator.rs)**: Communicate with [rustdesk-server](https://github.com/rustdesk/rustdesk-server), wait for remote direct (TCP hole punching) or relayed connection
|
||||
- **[src/platform](https://github.com/rustdesk/rustdesk/tree/master/src/platform)**: platform specific code
|
||||
|
||||
## സ്നാപ്പ്ഷോട്ടുകൾ
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
163
README-NL.md
Normal file
163
README-NL.md
Normal file
@@ -0,0 +1,163 @@
|
||||
<p align="center">
|
||||
<img src="logo-header.svg" alt="RustDesk - Jouw verbinding op afstand"><br>
|
||||
<a href="#free-public-servers">Servers</a> •
|
||||
<a href="#raw-steps-to-build">Bouwen</a> •
|
||||
<a href="#how-to-build-with-docker">Docker</a> •
|
||||
<a href="#file-structure">Structuur</a> •
|
||||
<a href="#snapshot">Snapshot</a><br>
|
||||
[<a href="README-ZH.md">中文</a>] | [<a href="README-ES.md">Español</a>] | [<a href="README-FR.md">Français</a>] | [<a href="README-DE.md">Deutsch</a>] | [<a href="README-PL.md">Polski</a>] | [<a href="README-FI.md">Suomi</a>] | [<a href="README-ML.md">മലയാളം</a>] | [<a href="README-JP.md">日本語</a>] | [<a href="README-NL.md">Nederlands</a>] | [<a href="README-IT.md">Italiano</a>] | [<a href="README-RU.md">Русский</a>] | [<a href="README-PTBR.md">Português (Brasil)</a>] | [<a href="README-EO.md">Esperanto</a>]<br>
|
||||
<b>We hebben je hulp nodig om deze README te vertalen naar jouw moedertaal</b>
|
||||
</p>
|
||||
|
||||
Praat met ons: [Discord](https://discord.gg/nDceKgxnkV) | [Reddit](https://www.reddit.com/r/rustdesk)
|
||||
|
||||
[](https://ko-fi.com/I2I04VU09)
|
||||
|
||||
Nog weer een applicatie voor toegang op afstand, geschreven in Rust. Werkt meteen, geen configuratie nodig. Je hebt volledig beheer over je data, zonder na te hoeven denken over veiligheid. Je kunt onze rendez-vous/relay-server gebruiken, [je eigen server opzetten](https://rustdesk.com/blog/id-relay-set), of [je eigen rendez-vous/relay-server schrijven](https://github.com/rustdesk/rustdesk-server-demo).
|
||||
|
||||
RustDesk verwelkomt bijdragen van iedereen. Zie [`CONTRIBUTING.md`](CONTRIBUTING.md) om te lezen hoe je van start kunt gaan.
|
||||
|
||||
[**BINARY DOWNLOAD**](https://github.com/rustdesk/rustdesk/releases)
|
||||
|
||||
## Gratis openbare servers
|
||||
|
||||
Onderstaande servers zijn de servers die je gratis kunt gebruiken, ze kunnen op termijn veranderen. Als je niet fysiek dichtbij een van deze servers bent, kan je verbinding traag werken.
|
||||
| Locatie | Aanbieder | Specificaties |
|
||||
| --------- | ------------- | ------------------ |
|
||||
| Seoul | AWS lightsail | 1 VCPU / 0.5GB RAM |
|
||||
| Singapore | Vultr | 1 VCPU / 1GB RAM |
|
||||
| Dallas | Vultr | 1 VCPU / 1GB RAM | |
|
||||
|
||||
## Afhankelijkheden
|
||||
|
||||
Desktopversies gebruiken [sciter](https://sciter.com/) voor de grafische schil. Gelieve zelf de sciter-library te downloaden.
|
||||
|
||||
[Windows](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.win/x64/sciter.dll) |
|
||||
[Linux](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.lnx/x64/libsciter-gtk.so) |
|
||||
[MacOS](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.osx/libsciter.dylib)
|
||||
|
||||
## Handmatige bouwinstructies
|
||||
|
||||
- Bereid je Rust-ontwikkelomgeving en C++-bouwomgeving voor.
|
||||
|
||||
- Installeer [vcpkg](https://github.com/microsoft/vcpkg) en configureer de `VCPKG_ROOT` omgevingsvariabele op de juiste manier:
|
||||
|
||||
- Windows: vcpkg install libvpx:x64-windows-static libyuv:x64-windows-static opus:x64-windows-static
|
||||
- Linux/MacOS: vcpkg install libvpx libyuv opus
|
||||
|
||||
- Voer uit: `cargo run`
|
||||
|
||||
## Bouwen op Linux
|
||||
|
||||
### Ubuntu 18 (Debian 10)
|
||||
|
||||
```sh
|
||||
sudo apt install -y g++ gcc git curl wget nasm yasm libgtk-3-dev clang libxcb-randr0-dev libxdo-dev libxfixes-dev libxcb-shape0-dev libxcb-xfixes0-dev libasound2-dev libpulse-dev cmake
|
||||
```
|
||||
|
||||
### Fedora 28 (CentOS 8)
|
||||
|
||||
```sh
|
||||
sudo yum -y install gcc-c++ git curl wget nasm yasm gcc gtk3-devel clang libxcb-devel libxdo-devel libXfixes-devel pulseaudio-libs-devel cmake alsa-lib-devel
|
||||
```
|
||||
|
||||
### Arch (Manjaro)
|
||||
|
||||
```sh
|
||||
sudo pacman -Syu --needed unzip git cmake gcc curl wget yasm nasm zip make pkg-config clang gtk3 xdotool libxcb libxfixes alsa-lib pulseaudio
|
||||
```
|
||||
|
||||
### Installatie van vcpkg
|
||||
|
||||
```sh
|
||||
git clone https://github.com/microsoft/vcpkg
|
||||
cd vcpkg
|
||||
git checkout 2021.12.01
|
||||
cd ..
|
||||
vcpkg/bootstrap-vcpkg.sh
|
||||
export VCPKG_ROOT=$HOME/vcpkg
|
||||
vcpkg/vcpkg install libvpx libyuv opus
|
||||
```
|
||||
|
||||
### Fix voor libvpx (voor Fedora)
|
||||
|
||||
```sh
|
||||
cd vcpkg/buildtrees/libvpx/src
|
||||
cd *
|
||||
./configure
|
||||
sed -i 's/CFLAGS+=-I/CFLAGS+=-fPIC -I/g' Makefile
|
||||
sed -i 's/CXXFLAGS+=-I/CXXFLAGS+=-fPIC -I/g' Makefile
|
||||
make
|
||||
cp libvpx.a $HOME/vcpkg/installed/x64-linux/lib/
|
||||
cd
|
||||
```
|
||||
|
||||
### Bouwen
|
||||
|
||||
```sh
|
||||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
|
||||
source $HOME/.cargo/env
|
||||
git clone https://github.com/rustdesk/rustdesk
|
||||
cd rustdesk
|
||||
mkdir -p target/debug
|
||||
wget https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.lnx/x64/libsciter-gtk.so
|
||||
mv libsciter-gtk.so target/debug
|
||||
VCPKG_ROOT=$HOME/vcpkg cargo run
|
||||
```
|
||||
|
||||
### Wissel van Wayland naar X11 (Xorg)
|
||||
|
||||
RustDesk ondersteunt Wayland niet. Lees [hier](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/) hoe je Xorg als standaardsessie kunt instellen voor GNOME.
|
||||
|
||||
## Bouwen met Docker
|
||||
|
||||
Kloon eerst deze repository en bouw de Docker-container:
|
||||
|
||||
```sh
|
||||
git clone https://github.com/rustdesk/rustdesk
|
||||
cd rustdesk
|
||||
docker build -t "rustdesk-builder" .
|
||||
```
|
||||
|
||||
Voer vervolgens de volgende commando's uit iedere keer dat je de applicatie opnieuw moet bouwen:
|
||||
|
||||
```sh
|
||||
docker run --rm -it -v $PWD:/home/user/rustdesk -v rustdesk-git-cache:/home/user/.cargo/git -v rustdesk-registry-cache:/home/user/.cargo/registry -e PUID="$(id -u)" -e PGID="$(id -g)" rustdesk-builder
|
||||
```
|
||||
|
||||
Let op dat de eerste build langer kan duren omdat de dependencies nog niet zijn gecached; latere builds zullen sneller zijn. Als je extra command line arguments wilt toevoegen aan het build-commando, dan kun je dat doen aan het einde van de opdrachtregel in plaats van `<OPTIONAL-ARGS>`. Bijvoorbeeld: als je een geoptimaliseerde releaseversie wilt bouwen, draai dan het bovenstaande commando gevolgd door `---release`.
|
||||
|
||||
Het uitvoerbare bestand, in debug-modus, zal verschijnen in de target-map, en kan als volgt worden uitgevoerd:
|
||||
|
||||
```sh
|
||||
target/debug/rustdesk
|
||||
```
|
||||
|
||||
Als je een release-versie hebt gebouwd, is het commando als volgt:
|
||||
|
||||
```sh
|
||||
target/release/rustdesk
|
||||
```
|
||||
|
||||
Zorg ervoor dat je deze commando's van de root van de RustDesk-repository uitvoert, anders kan het programma de nodige afhankelijkheden mogelijk niet vinden. Let ook op dat andere cargo-subcommando's zoals `install` en `run` zijn momenteel niet ondersteund, aangezien deze zouden worden uitgevoerd in een container in plaats van op de host.
|
||||
|
||||
## Bestandsstructuur
|
||||
|
||||
- **[libs/hbb_common](https://github.com/rustdesk/rustdesk/tree/master/libs/hbb_common)**: videocodec, configuratie, TCP/UDP-wrapper, protobuf, bestandssysteemfuncties voor bestandsoverdracht en nog wat andere nuttige functies
|
||||
- **[libs/scrap](https://github.com/rustdesk/rustdesk/tree/master/libs/scrap)**: schermopname
|
||||
- **[libs/enigo](https://github.com/rustdesk/rustdesk/tree/master/libs/enigo)**: platformspecifieke muis- en toetsenbordbeheer
|
||||
- **[src/ui](https://github.com/rustdesk/rustdesk/tree/master/src/ui)**: GUI
|
||||
- **[src/server](https://github.com/rustdesk/rustdesk/tree/master/src/server)**: geluids-, klembord-, invoer- en video-services, netwerkverbindingen
|
||||
- **[src/client.rs](https://github.com/rustdesk/rustdesk/tree/master/src/client.rs)**: voor het opzetten van peer-verbindingen
|
||||
- **[src/rendezvous_mediator.rs](https://github.com/rustdesk/rustdesk/tree/master/src/rendezvous_mediator.rs)**: Communicatie met [rustdesk-server](https://github.com/rustdesk/rustdesk-server), afwachten van redirect op afstand (TCP hole punching) of een relayed verbinding
|
||||
- **[src/platform](https://github.com/rustdesk/rustdesk/tree/master/src/platform)**: platformspecifieke code
|
||||
|
||||
## Snapshot
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
161
README-PL.md
Normal file
161
README-PL.md
Normal file
@@ -0,0 +1,161 @@
|
||||
<p align="center">
|
||||
<img src="logo-header.svg" alt="RustDesk - Your remote desktop"><br>
|
||||
<a href="#darmowe-serwery-publiczne">Serwery</a> •
|
||||
<a href="#podstawowe-kroki-do-kompilacji">Kompilacja</a> •
|
||||
<a href="#jak-kompilować-za-pomocą-dockera">Docker</a> •
|
||||
<a href="#struktura-plików">Struktura</a> •
|
||||
<a href="#migawkisnapshoty">Snapshot</a><br>
|
||||
[<a href="README-ZH.md">中文</a>] | [<a href="README-ES.md">Español</a>] | [<a href="README-FR.md">Français</a>] | [<a href="README-DE.md">Deutsch</a>] | [<a href="README-PL.md">Polski</a>] | [<a href="README-FI.md">Suomi</a>] | [<a href="README-ML.md">മലയാളം</a>] | [<a href="README-JP.md">日本語</a>] | [<a href="README-NL.md">Nederlands</a>] | [<a href="README-IT.md">Italiano</a>] | [<a href="README-RU.md">Русский</a>] | [<a href="README-PTBR.md">Português (Brasil)</a>] | [<a href="README-EO.md">Esperanto</a>]<br>
|
||||
<b>Potrzebujemy twojej pomocy w tłumaczeniu README na twój ojczysty język</b>
|
||||
</p>
|
||||
|
||||
Porozmawiaj z nami na: [Discord](https://discord.gg/nDceKgxnkV) | [Reddit](https://www.reddit.com/r/rustdesk)
|
||||
|
||||
[](https://ko-fi.com/I2I04VU09)
|
||||
|
||||
Kolejny program do zdalnego pulpitu, napisany w Rust. Działa od samego początku, nie wymaga konfiguracji. Masz pełną kontrolę nad swoimi danymi, bez obaw o bezpieczeństwo. Możesz skorzystać z naszego darmowego serwera publicznego , [skonfigurować własny](https://rustdesk.com/server), lub [napisać własny serwer rendezvous/relay server](https://github.com/rustdesk/rustdesk-server-demo).
|
||||
|
||||
RustDesk zaprasza do współpracy każdego. Zobacz [`CONTRIBUTING.md`](CONTRIBUTING.md) pomoc w uruchomieniu programu.
|
||||
|
||||
[**POBIERZ KOMPILACJE**](https://github.com/rustdesk/rustdesk/releases)
|
||||
|
||||
## Darmowe Serwery Publiczne
|
||||
|
||||
Poniżej znajdują się serwery, z których można korzystać za darmo, może się to zmienić z upływem czasu. Jeśli nie znajdujesz się w pobliżu jednego z nich, Twoja prędkość połączenia może być niska.
|
||||
| Lokalizacja | Dostawca | Specyfikacja |
|
||||
| --------- | ------------- | ------------------ |
|
||||
| Seul | AWS lightsail | 1 VCPU / 0.5GB RAM |
|
||||
| Singapur | Vultr | 1 VCPU / 1GB RAM |
|
||||
| Dallas | Vultr | 1 VCPU / 1GB RAM | |
|
||||
|
||||
## Zależności
|
||||
|
||||
Wersje desktopowe używają [sciter](https://sciter.com/) dla GUI, proszę pobrać bibliotekę dynamiczną sciter samodzielnie.
|
||||
|
||||
[Windows](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.win/x64/sciter.dll) |
|
||||
[Linux](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.lnx/x64/libsciter-gtk.so) |
|
||||
[MacOS](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.osx/libsciter.dylib)
|
||||
|
||||
## Podstawowe kroki do kompilacji
|
||||
|
||||
- Przygotuj środowisko programistyczne Rust i środowisko programowania C++
|
||||
|
||||
- Zainstaluj [vcpkg](https://github.com/microsoft/vcpkg), i ustaw `VCPKG_ROOT` env zmienną prawidłowo
|
||||
|
||||
- Windows: vcpkg install libvpx:x64-windows-static libyuv:x64-windows-static opus:x64-windows-static
|
||||
- Linux/MacOS: vcpkg install libvpx libyuv opus
|
||||
|
||||
- uruchom `cargo run`
|
||||
|
||||
## Jak Kompilować na Linuxie
|
||||
|
||||
### Ubuntu 18 (Debian 10)
|
||||
|
||||
```sh
|
||||
sudo apt install -y g++ gcc git curl wget nasm yasm libgtk-3-dev clang libxcb-randr0-dev libxdo-dev libxfixes-dev libxcb-shape0-dev libxcb-xfixes0-dev libasound2-dev libpulse-dev cmake
|
||||
```
|
||||
|
||||
### Fedora 28 (CentOS 8)
|
||||
|
||||
```sh
|
||||
sudo yum -y install gcc-c++ git curl wget nasm yasm gcc gtk3-devel clang libxcb-devel libxdo-devel libXfixes-devel pulseaudio-libs-devel cmake alsa-lib-devel
|
||||
```
|
||||
|
||||
### Arch (Manjaro)
|
||||
|
||||
```sh
|
||||
sudo pacman -Syu --needed unzip git cmake gcc curl wget yasm nasm zip make pkg-config clang gtk3 xdotool libxcb libxfixes alsa-lib pulseaudio
|
||||
```
|
||||
|
||||
### Zainstaluj vcpkg
|
||||
|
||||
```sh
|
||||
git clone https://github.com/microsoft/vcpkg
|
||||
cd vcpkg
|
||||
git checkout 2021.12.01
|
||||
cd ..
|
||||
vcpkg/bootstrap-vcpkg.sh
|
||||
export VCPKG_ROOT=$HOME/vcpkg
|
||||
vcpkg/vcpkg install libvpx libyuv opus
|
||||
```
|
||||
|
||||
### Fix libvpx (For Fedora)
|
||||
|
||||
```sh
|
||||
cd vcpkg/buildtrees/libvpx/src
|
||||
cd *
|
||||
./configure
|
||||
sed -i 's/CFLAGS+=-I/CFLAGS+=-fPIC -I/g' Makefile
|
||||
sed -i 's/CXXFLAGS+=-I/CXXFLAGS+=-fPIC -I/g' Makefile
|
||||
make
|
||||
cp libvpx.a $HOME/vcpkg/installed/x64-linux/lib/
|
||||
cd
|
||||
```
|
||||
|
||||
### Kompilacja
|
||||
|
||||
```sh
|
||||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
|
||||
source $HOME/.cargo/env
|
||||
git clone https://github.com/rustdesk/rustdesk
|
||||
cd rustdesk
|
||||
mkdir -p target/debug
|
||||
wget https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.lnx/x64/libsciter-gtk.so
|
||||
mv libsciter-gtk.so target/debug
|
||||
cargo run
|
||||
```
|
||||
|
||||
### Zmień Wayland na X11 (Xorg)
|
||||
|
||||
RustDesk nie obsługuje Waylanda. Sprawdź [this](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/) by skonfigurować Xorg jako domyślną sesję GNOME.
|
||||
|
||||
## Jak kompilować za pomocą Dockera
|
||||
|
||||
Rozpocznij od sklonowania repozytorium i stworzenia kontenera docker:
|
||||
|
||||
```sh
|
||||
git clone https://github.com/rustdesk/rustdesk
|
||||
cd rustdesk
|
||||
docker build -t "rustdesk-builder" .
|
||||
```
|
||||
|
||||
Następnie, za każdym razem, gdy potrzebujesz skompilować aplikację, uruchom następujące polecenie:
|
||||
|
||||
```sh
|
||||
docker run --rm -it -v $PWD:/home/user/rustdesk -v rustdesk-git-cache:/home/user/.cargo/git -v rustdesk-registry-cache:/home/user/.cargo/registry -e PUID="$(id -u)" -e PGID="$(id -g)" rustdesk-builder
|
||||
```
|
||||
|
||||
Zauważ, że pierwsza kompilacja może potrwać dłużej zanim zależności zostaną zbuforowane, kolejne będą szybsze. Dodatkowo, jeśli potrzebujesz określić inne argumenty dla polecenia budowania, możesz to zrobić na końcu komendy w miejscu `<OPTIONAL-ARGS>`. Na przykład, jeśli chciałbyś zbudować zoptymalizowaną wersję wydania, uruchomiłbyś powyższą komendę a następnie `---release`. Powstały plik wykonywalny będzie dostępny w folderze docelowym w twoim systemie, i może być uruchomiony z:
|
||||
|
||||
```sh
|
||||
target/debug/rustdesk
|
||||
```
|
||||
|
||||
Lub, jeśli uruchamiasz plik wykonywalny wersji:
|
||||
|
||||
```sh
|
||||
target/release/rustdesk
|
||||
```
|
||||
|
||||
Upewnij się, że uruchamiasz te polecenia z katalogu głównego repozytorium RustDesk, w przeciwnym razie aplikacja może nie być w stanie znaleźć wymaganych zasobów. Należy również pamiętać, że inne podpolecenia ładowania, takie jak `install` lub `run` nie są obecnie obsługiwane za pomocą tej metody, ponieważ instalowałyby lub uruchamiały program wewnątrz kontenera zamiast na hoście.
|
||||
|
||||
## Struktura plików
|
||||
|
||||
- **[libs/hbb_common](https://github.com/rustdesk/rustdesk/tree/master/libs/hbb_common)**: kodek wideo, config, wrapper tcp/udp, protobuf, funkcje fs do transferu plików i kilka innych funkcji użytkowych
|
||||
- **[libs/scrap](https://github.com/rustdesk/rustdesk/tree/master/libs/scrap)**: przechwytywanie ekranu
|
||||
- **[libs/enigo](https://github.com/rustdesk/rustdesk/tree/master/libs/enigo)**: specyficzne dla danej platformy sterowanie klawiaturą/myszą
|
||||
- **[src/ui](https://github.com/rustdesk/rustdesk/tree/master/src/ui)**: GUI
|
||||
- **[src/server](https://github.com/rustdesk/rustdesk/tree/master/src/server)**: audio/schowek/wejście(input)/wideo oraz połączenia sieciowe
|
||||
- **[src/client.rs](https://github.com/rustdesk/rustdesk/tree/master/src/client.rs)**: uruchamia połączenie peer
|
||||
- **[src/rendezvous_mediator.rs](https://github.com/rustdesk/rustdesk/tree/master/src/rendezvous_mediator.rs)**: Komunikacja z [rustdesk-server](https://github.com/rustdesk/rustdesk-server), wait for remote direct (TCP hole punching) or relayed connection
|
||||
- **[src/platform](https://github.com/rustdesk/rustdesk/tree/master/src/platform)**: specyficzny dla danej platformy kod
|
||||
|
||||
## Migawki(Snapshoty)
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
162
README-PTBR.md
Normal file
162
README-PTBR.md
Normal file
@@ -0,0 +1,162 @@
|
||||
<p align="center">
|
||||
<img src="logo-header.svg" alt="RustDesk - Seu desktop remoto"><br>
|
||||
<a href="#servidores-públicos-grátis">Servidores</a> •
|
||||
<a href="#compilação-crua">Compilar</a> •
|
||||
<a href="#como-compilar-com-docker">Docker</a> •
|
||||
<a href="#estrutura-de-arquivos">Estrutura</a> •
|
||||
<a href="#screenshots">Screenshots</a><br>
|
||||
[<a href="README-ZH.md">中文</a>] | [<a href="README-ES.md">Español</a>] | [<a href="README-FR.md">Français</a>] | [<a href="README-DE.md">Deutsch</a>] | [<a href="README-PL.md">Polski</a>] | [<a href="README-FI.md">Suomi</a>] | [<a href="README-ML.md">മലയാളം</a>] | [<a href="README-JP.md">日本語</a>] | [<a href="README-NL.md">Nederlands</a>] | [<a href="README-IT.md">Italiano</a>] | [<a href="README-RU.md">Русский</a>] | [<a href="README-PTBR.md">Português (Brasil)</a>] | [<a href="README-EO.md">Esperanto</a>]<br>
|
||||
<b>Precisamos de sua ajuda para traduzir este README e a <a href="https://github.com/rustdesk/rustdesk/tree/master/src/lang">UI do RustDesk</a> para sua língua nativa</b>
|
||||
</p>
|
||||
|
||||
Converse conosco: [Discord](https://discord.gg/nDceKgxnkV) | [Reddit](https://www.reddit.com/r/rustdesk)
|
||||
|
||||
[](https://ko-fi.com/I2I04VU09)
|
||||
|
||||
Mais um software de desktop remoto, escrito em Rust. Funciona por padrão, sem necessidade de configuração. Você tem completo controle de seus dados, sem se preocupar com segurança. Você pode usar nossos servidores de rendezvous/relay, [configurar seu próprio](https://rustdesk.com/server), ou [escrever seu próprio servidor de rendezvous/relay](https://github.com/rustdesk/rustdesk-server-demo).
|
||||
|
||||
RustDesk acolhe contribuições de todos. Leia [`CONTRIBUTING.md`](CONTRIBUTING.md) para ver como começar.
|
||||
|
||||
[**DOWNLOAD DE BINÁRIOS**](https://github.com/rustdesk/rustdesk/releases)
|
||||
|
||||
## Servidores Públicos Grátis
|
||||
|
||||
Abaixo estão os servidores que você está utilizando de graça, ele pode mudar com o tempo. Se você não está próximo de algum deles, sua conexão pode ser lenta.
|
||||
|
||||
| Localização | Fornecedor | Especificações |
|
||||
| ----------- | ------------- | ------------------ |
|
||||
| Seul | AWS lightsail | 1 VCPU / 0.5GB RAM |
|
||||
| Singapura | Vultr | 1 VCPU / 1GB RAM |
|
||||
| Dallas | Vultr | 1 VCPU / 1GB RAM |
|
||||
|
||||
## Dependências
|
||||
|
||||
Versões de desktop utilizam [sciter](https://sciter.com/) para a GUI, por favor baixe a biblioteca dinâmica sciter por conta própria.
|
||||
|
||||
[Windows](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.win/x64/sciter.dll) |
|
||||
[Linux](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.lnx/x64/libsciter-gtk.so) |
|
||||
[MacOS](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.osx/libsciter.dylib)
|
||||
|
||||
## Compilação crua
|
||||
|
||||
- Prepare seu ambiente de desenvolvimento Rust e ambiente de compilação C++
|
||||
|
||||
- Instale [vcpkg](https://github.com/microsoft/vcpkg), e configure a variável de ambiente `VCPKG_ROOT` corretamente
|
||||
|
||||
- Windows: vcpkg install libvpx:x64-windows-static libyuv:x64-windows-static opus:x64-windows-static
|
||||
- Linux/MacOS: vcpkg install libvpx libyuv opus
|
||||
|
||||
- Execute `cargo run`
|
||||
|
||||
## Como compilar no Linux
|
||||
|
||||
### Ubuntu 18 (Debian 10)
|
||||
|
||||
```sh
|
||||
sudo apt install -y g++ gcc git curl wget nasm yasm libgtk-3-dev clang libxcb-randr0-dev libxdo-dev libxfixes-dev libxcb-shape0-dev libxcb-xfixes0-dev libasound2-dev libpulse-dev cmake
|
||||
```
|
||||
|
||||
### Fedora 28 (CentOS 8)
|
||||
|
||||
```sh
|
||||
sudo yum -y install gcc-c++ git curl wget nasm yasm gcc gtk3-devel clang libxcb-devel libxdo-devel libXfixes-devel pulseaudio-libs-devel cmake alsa-lib-devel
|
||||
```
|
||||
|
||||
### Arch (Manjaro)
|
||||
|
||||
```sh
|
||||
sudo pacman -Syu --needed unzip git cmake gcc curl wget yasm nasm zip make pkg-config clang gtk3 xdotool libxcb libxfixes alsa-lib pulseaudio
|
||||
```
|
||||
|
||||
### Instale vcpkg
|
||||
|
||||
```sh
|
||||
git clone https://github.com/microsoft/vcpkg
|
||||
cd vcpkg
|
||||
git checkout 2021.12.01
|
||||
cd ..
|
||||
vcpkg/bootstrap-vcpkg.sh
|
||||
export VCPKG_ROOT=$HOME/vcpkg
|
||||
vcpkg/vcpkg install libvpx libyuv opus
|
||||
```
|
||||
|
||||
### Conserte libvpx (Para o Fedora)
|
||||
|
||||
```sh
|
||||
cd vcpkg/buildtrees/libvpx/src
|
||||
cd *
|
||||
./configure
|
||||
sed -i 's/CFLAGS+=-I/CFLAGS+=-fPIC -I/g' Makefile
|
||||
sed -i 's/CXXFLAGS+=-I/CXXFLAGS+=-fPIC -I/g' Makefile
|
||||
make
|
||||
cp libvpx.a $HOME/vcpkg/installed/x64-linux/lib/
|
||||
cd
|
||||
```
|
||||
|
||||
### Compile
|
||||
|
||||
```sh
|
||||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
|
||||
source $HOME/.cargo/env
|
||||
git clone https://github.com/rustdesk/rustdesk
|
||||
cd rustdesk
|
||||
mkdir -p target/debug
|
||||
wget https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.lnx/x64/libsciter-gtk.so
|
||||
mv libsciter-gtk.so target/debug
|
||||
VCPKG_ROOT=$HOME/vcpkg cargo run
|
||||
```
|
||||
|
||||
### Mude Wayland para X11 (Xorg)
|
||||
|
||||
RustDesk não suporta Wayland. Veja [esse link](https://docs.fedoraproject.org/pt_BR/quick-docs/configuring-xorg-as-default-gnome-session/) para configurar o Xorg como a sessão padrão do GNOME.
|
||||
|
||||
## Como compilar com Docker
|
||||
|
||||
Comece clonando o repositório e montando o container docker:
|
||||
|
||||
```sh
|
||||
git clone https://github.com/rustdesk/rustdesk
|
||||
cd rustdesk
|
||||
docker build -t "rustdesk-builder" .
|
||||
```
|
||||
|
||||
Então, sempre que precisar compilar a aplicação, execute este comando:
|
||||
|
||||
```sh
|
||||
docker run --rm -it -v $PWD:/home/user/rustdesk -v rustdesk-git-cache:/home/user/.cargo/git -v rustdesk-registry-cache:/home/user/.cargo/registry -e PUID="$(id -u)" -e PGID="$(id -g)" rustdesk-builder
|
||||
```
|
||||
|
||||
Note que a primeira compilação pode demorar mais antes que as dependências sejam armazenadas em cache, as compilações subsequentes serão mais rápidas. Adicionalmente, se você precisar especificar argumentos diferentes para o comando de compilação, você pode fazê-lo ao final do comando na posição do `<OPTIONAL-ARGS>`. Por exemplo, se você gostaria de compilar uma versão de release otimizada, você executaria o comando acima seguido de `--release`. O executável gerado estará disponível no diretório alvo no seu sistema, e pode ser executado com:
|
||||
|
||||
```sh
|
||||
target/debug/rustdesk
|
||||
```
|
||||
|
||||
Ou, se estiver rodando um executável de release:
|
||||
|
||||
```sh
|
||||
target/release/rustdesk
|
||||
```
|
||||
|
||||
Por favor verifique que está executando estes comandos da raiz do repositório do RustDesk, senão a aplicação pode não encontrar os recursos necessários. Note também que outros subcomandos do cargo como `install` ou `run` não são suportados atualmente via este método, já que eles iriam instalar ou rodar o programa dentro do container ao invés do host.
|
||||
|
||||
## Estrutura de arquivos
|
||||
|
||||
- **[libs/hbb_common](https://github.com/rustdesk/rustdesk/tree/master/libs/hbb_common)**: codec de vídeo, configurações, wrapper de tcp/udp, protobuf, funções de sistema de arquivos para transferência de arquivos, e outras funções utilitárias
|
||||
- **[libs/scrap](https://github.com/rustdesk/rustdesk/tree/master/libs/scrap)**: captura de tela
|
||||
- **[libs/enigo](https://github.com/rustdesk/rustdesk/tree/master/libs/enigo)**: controle de teclado/mouse específico a cada plataforma
|
||||
- **[src/ui](https://github.com/rustdesk/rustdesk/tree/master/src/ui)**: GUI
|
||||
- **[src/server](https://github.com/rustdesk/rustdesk/tree/master/src/server)**: serviços de áudio/área de transferência/entrada/vídeo, e conexões de rede
|
||||
- **[src/client.rs](https://github.com/rustdesk/rustdesk/tree/master/src/client.rs)**: iniciar uma conexão "peer to peer"
|
||||
- **[src/rendezvous_mediator.rs](https://github.com/rustdesk/rustdesk/tree/master/src/rendezvous_mediator.rs)**: Comunicação com [rustdesk-server](https://github.com/rustdesk/rustdesk-server), aguardar pela conexão remota direta (TCP hole punching) ou conexão indireta (relayed)
|
||||
- **[src/platform](https://github.com/rustdesk/rustdesk/tree/master/src/platform)**: código específico a cada plataforma
|
||||
|
||||
## Screenshots
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
161
README-RU.md
Normal file
161
README-RU.md
Normal file
@@ -0,0 +1,161 @@
|
||||
<p align="center">
|
||||
<img src="logo-header.svg" alt="RustDesk - Your remote desktop"><br>
|
||||
<a href="#free-public-servers">Servers</a> •
|
||||
<a href="#raw-steps-to-build">Build</a> •
|
||||
<a href="#how-to-build-with-docker">Docker</a> •
|
||||
<a href="#file-structure">Structure</a> •
|
||||
<a href="#snapshot">Snapshot</a><br>
|
||||
[<a href="README-ZH.md">中文</a>] | [<a href="README-ES.md">Español</a>] | [<a href="README-FR.md">Français</a>] | [<a href="README-DE.md">Deutsch</a>] | [<a href="README-PL.md">Polski</a>] | [<a href="README-FI.md">Suomi</a>] | [<a href="README-ML.md">മലയാളം</a>] | [<a href="README-JP.md">日本語</a>] | [<a href="README-NL.md">Nederlands</a>] | [<a href="README-IT.md">Italiano</a>] | [<a href="README-RU.md">Русский</a>] | [<a href="README-PTBR.md">Português (Brasil)</a>] | [<a href="README-EO.md">Esperanto</a>]<br>
|
||||
<b>Нам нужна ваша помощь для перевода этого README и <a href="https://github.com/rustdesk/rustdesk/tree/master/src/rustdesk/tree/master/src/lang">RustDesk UI</a> на ваш родной язык</B>
|
||||
</p>
|
||||
|
||||
Общение с нами: [Discord](https://discord.gg/nDceKgxnkV) | [Reddit](https://www.reddit.com/r/rustdesk)
|
||||
|
||||
[](https://ko-fi.com/I2I04VU09)
|
||||
|
||||
Еще одно программное обеспечение для удаленного рабочего стола, написанное на Rust. Работает из коробки, не требует настройки. Вы полностью контролируете свои данные, не беспокоясь о безопасности. Вы можете использовать наш сервер ретрансляции, [настроить свой собственный](https://rustdesk.com/server), или [написать свой собственный сервер ретрансляции](https://github.com/rustdesk/rustdesk-server-demo).
|
||||
|
||||
RustDesk приветствует вклад каждого. Смотри [`CONTRIBUTING.md`](CONTRIBUTING.md) для помощи в начале работы.
|
||||
|
||||
[**СКАЧАТЬ ПРИЛОЖЕНИЕ**](https://github.com/rustdesk/rustdesk/releases)
|
||||
|
||||
## Бесплатные общедоступные серверы
|
||||
|
||||
Ниже приведены серверы, для бесплатного использования, они могут меняться со временем. Если вы не находитесь рядом с одним из них, ваша сеть может работать медленно.
|
||||
| Местонахождение | Поставщик | Технические характеристики |
|
||||
| --------- | ------------- | ------------------ |
|
||||
| Сеул | AWS lightsail | 1 VCPU / 0.5GB RAM |
|
||||
| Сингапур | Vultr | 1 VCPU / 1GB RAM |
|
||||
| Даллас | Vultr | 1 VCPU / 1GB RAM | |
|
||||
|
||||
## Зависимости
|
||||
|
||||
Настольные версии используют [sciter](https://sciter.com/) для графического интерфейса, загрузите динамическую библиотеку sciter самостоятельно.
|
||||
|
||||
[Windows](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.win/x64/sciter.dll) |
|
||||
[Linux](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.lnx/x64/libsciter-gtk.so) |
|
||||
[MacOS](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.osx/libsciter.dylib)
|
||||
|
||||
## Необработанные шаги для сборки
|
||||
|
||||
- Подготовьте среду разработки Rust и среду сборки C++.
|
||||
|
||||
- Установите [vcpkg](https://github.com/microsoft/vcpkg), и правильно установите переменную `VCPKG_ROOT`
|
||||
|
||||
- Windows: vcpkg install libvpx:x64-windows-static libyuv:x64-windows-static opus:x64-windows-static
|
||||
- Linux/MacOS: vcpkg install libvpx libyuv opus
|
||||
|
||||
- Запустите`cargo run`
|
||||
|
||||
## Как собрать в Linux
|
||||
|
||||
### Ubuntu 18 (Debian 10)
|
||||
|
||||
```sh
|
||||
sudo apt install -y g++ gcc git curl wget nasm yasm libgtk-3-dev clang libxcb-randr0-dev libxdo-dev libxfixes-dev libxcb-shape0-dev libxcb-xfixes0-dev libasound2-dev libpulse-dev cmake
|
||||
```
|
||||
|
||||
### Fedora 28 (CentOS 8)
|
||||
|
||||
```sh
|
||||
sudo yum -y install gcc-c++ git curl wget nasm yasm gcc gtk3-devel clang libxcb-devel libxdo-devel libXfixes-devel pulseaudio-libs-devel cmake alsa-lib-devel
|
||||
```
|
||||
|
||||
### Arch (Manjaro)
|
||||
|
||||
```sh
|
||||
sudo pacman -Syu --needed unzip git cmake gcc curl wget yasm nasm zip make pkg-config clang gtk3 xdotool libxcb libxfixes alsa-lib pulseaudio
|
||||
```
|
||||
|
||||
### Установка vcpkg
|
||||
|
||||
```sh
|
||||
git clone https://github.com/microsoft/vcpkg
|
||||
cd vcpkg
|
||||
git checkout 2021.12.01
|
||||
cd ..
|
||||
vcpkg/bootstrap-vcpkg.sh
|
||||
export VCPKG_ROOT=$HOME/vcpkg
|
||||
vcpkg/vcpkg install libvpx libyuv opus
|
||||
```
|
||||
|
||||
### Исправления libvpx (Для Fedora)
|
||||
|
||||
```sh
|
||||
cd vcpkg/buildtrees/libvpx/src
|
||||
cd *
|
||||
./configure
|
||||
sed -i 's/CFLAGS+=-I/CFLAGS+=-fPIC -I/g' Makefile
|
||||
sed -i 's/CXXFLAGS+=-I/CXXFLAGS+=-fPIC -I/g' Makefile
|
||||
make
|
||||
cp libvpx.a $HOME/vcpkg/installed/x64-linux/lib/
|
||||
cd
|
||||
```
|
||||
|
||||
### Сборка
|
||||
|
||||
```sh
|
||||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
|
||||
source $HOME/.cargo/env
|
||||
git clone https://github.com/rustdesk/rustdesk
|
||||
cd rustdesk
|
||||
mkdir -p target/debug
|
||||
wget https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.lnx/x64/libsciter-gtk.so
|
||||
mv libsciter-gtk.so target/debug
|
||||
VCPKG_ROOT=$HOME/vcpkg cargo run
|
||||
```
|
||||
|
||||
### Смените Wayland на X11 (Xorg)
|
||||
|
||||
RustDesk не поддерживает Wayland. Смотрите [этот документ](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/) для настройки Xorg в качестве сеанса GNOME по умолчанию.
|
||||
|
||||
## Как собрать используя Docker
|
||||
|
||||
Начните с клонирования репозитория и создания docker контейнера:
|
||||
|
||||
```sh
|
||||
git clone https://github.com/rustdesk/rustdesk
|
||||
cd rustdesk
|
||||
docker build -t "rustdesk-builder" .
|
||||
```
|
||||
|
||||
Затем каждый раз, когда вам нужно собрать приложение, запустите следующую команду:
|
||||
|
||||
```sh
|
||||
docker run --rm -it -v $PWD:/home/user/rustdesk -v rustdesk-git-cache:/home/user/.cargo/git -v rustdesk-registry-cache:/home/user/.cargo/registry -e PUID="$(id -u)" -e PGID="$(id -g)" rustdesk-builder
|
||||
```
|
||||
|
||||
Обратите внимание, что первая сборка может занять больше времени но последующие сборки будут выполняться быстрее. Кроме того, если вам нужно указать другие аргументы для команды сборки, вы можете сделать это в конце команды в переменной `<OPTIONAL-ARGS>`. Например, если вы хотите создать оптимизированную версию, вы должны запустить приведенную выше команду и в хвосте строки добавить `---release`. Полученный исполняемый файл будет доступен в целевой папке вашей системы и может быть запущен с помощью:
|
||||
|
||||
```sh
|
||||
target/debug/rustdesk
|
||||
```
|
||||
|
||||
Или, если вы используете исполняемый файл релиза:
|
||||
|
||||
```sh
|
||||
target/release/rustdesk
|
||||
```
|
||||
|
||||
Пожалуйста, убедитесь, что вы запускаете эти команды из корня репозитория RustDesk, иначе приложение не сможет найти необходимые ресурсы. Также обратите внимание, что другие cargo подкоманды, такие как `install` или `run`, в настоящее время не поддерживаются этим методом, поскольку они будут устанавливать или запускать программу внутри контейнера, а не на хосте.
|
||||
|
||||
## Структура файлов
|
||||
|
||||
- **[libs/hbb_common](https://github.com/rustdesk/rustdesk/tree/master/libs/hbb_common)**: видеокодек, конфиг, обертка tcp/udp, protobuf, функции fs для передачи файлов и некоторые другие служебные функции
|
||||
- **[libs/scrap](https://github.com/rustdesk/rustdesk/tree/master/libs/scrap)**: захват экрана
|
||||
- **[libs/enigo](https://github.com/rustdesk/rustdesk/tree/master/libs/enigo)**: специфичное для платформы управление клавиатурой/мышью
|
||||
- **[src/ui](https://github.com/rustdesk/rustdesk/tree/master/src/ui)**: графический пользовательский интерфейс
|
||||
- **[src/server](https://github.com/rustdesk/rustdesk/tree/master/src/server)**: сервисы аудио/буфера обмена/ввода/видео и сетевых подключений
|
||||
- **[src/client.rs](https://github.com/rustdesk/rustdesk/tree/master/src/client.rs)**: одноранговое соединение
|
||||
- **[src/rendezvous_mediator.rs](https://github.com/rustdesk/rustdesk/tree/master/src/rendezvous_mediator.rs)**: свяжитесь с [rustdesk-server](https://github.com/rustdesk/rustdesk-server), дождитесь удаленного прямого (обход TCP NAT) или ретранслируемого соединения
|
||||
- **[src/platform](https://github.com/rustdesk/rustdesk/tree/master/src/platform)**: специфичный для платформы код
|
||||
|
||||
## Снимки
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
214
README-ZH.md
Normal file
214
README-ZH.md
Normal file
@@ -0,0 +1,214 @@
|
||||
<p align="center">
|
||||
<img src="logo-header.svg" alt="RustDesk - Your remote desktop"><br>
|
||||
<a href="#免费公共服务器">服务器</a> •
|
||||
<a href="#基本构建步骤">编译</a> •
|
||||
<a href="#使用Docker编译">Docker</a> •
|
||||
<a href="#文件结构">结构</a> •
|
||||
<a href="#截图">截图</a><br>
|
||||
[<a href="README-ZH.md">中文</a>] | [<a href="README-ES.md">Español</a>] | [<a href="README-FR.md">Français</a>] | [<a href="README-DE.md">Deutsch</a>] | [<a href="README-PL.md">Polski</a>] | [<a href="README-FI.md">Suomi</a>] | [<a href="README-ML.md">മലയാളം</a>] | [<a href="README-JP.md">日本語</a>] | [<a href="README-NL.md">Nederlands</a>] | [<a href="README-IT.md">Italiano</a>] | [<a href="README-RU.md">Русский</a>] | [<a href="README-PTBR.md">Português (Brasil)</a>] | [<a href="README-EO.md">Esperanto</a>]<br>
|
||||
</p>
|
||||
|
||||
Chat with us: [知乎](https://www.zhihu.com/people/rustdesk) | [Discord](https://discord.gg/nDceKgxnkV) | [Reddit](https://www.reddit.com/r/rustdesk)
|
||||
|
||||
[](https://ko-fi.com/I2I04VU09)
|
||||
|
||||
远程桌面软件,开箱即用,无需任何配置。您完全掌控数据,不用担心安全问题。您可以使用我们的注册/中继服务器,
|
||||
或者[自己设置](https://rustdesk.com/server),
|
||||
亦或者[开发您的版本](https://github.com/rustdesk/rustdesk-server-demo)。
|
||||
|
||||
欢迎大家贡献代码, 请看 [`CONTRIBUTING.md`](CONTRIBUTING.md).
|
||||
|
||||
[**可执行程序下载**](https://github.com/rustdesk/rustdesk/releases)
|
||||
|
||||
## 免费公共服务器
|
||||
|
||||
以下是您免费使用的服务器,它可能会随着时间的推移而变化。如果您不靠近其中之一,您的网络可能会很慢。
|
||||
|
||||
- 首尔, AWS lightsail, 1 VCPU/0.5G RAM
|
||||
- 新加坡, Vultr, 1 VCPU/1G RAM
|
||||
- 达拉斯, Vultr, 1 VCPU/1G RAM
|
||||
|
||||
## 依赖
|
||||
|
||||
桌面版本界面使用[sciter](https://sciter.com/), 请自行下载。
|
||||
|
||||
[Windows](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.win/x64/sciter.dll) |
|
||||
[Linux](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.lnx/x64/libsciter-gtk.so) |
|
||||
[macOS](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.osx/libsciter.dylib)
|
||||
|
||||
## 基本构建步骤
|
||||
|
||||
- 请准备好 Rust 开发环境和 C++编译环境
|
||||
|
||||
- 安装[vcpkg](https://github.com/microsoft/vcpkg), 正确设置`VCPKG_ROOT`环境变量
|
||||
|
||||
- Windows: vcpkg install libvpx:x64-windows-static libyuv:x64-windows-static opus:x64-windows-static
|
||||
- Linux/Osx: vcpkg install libvpx libyuv opus
|
||||
|
||||
- 运行 `cargo run`
|
||||
|
||||
## 在 Linux 上编译
|
||||
|
||||
### Ubuntu 18 (Debian 10)
|
||||
|
||||
```sh
|
||||
sudo apt install -y g++ gcc git curl wget nasm yasm libgtk-3-dev clang libxcb-randr0-dev libxdo-dev libxfixes-dev libxcb-shape0-dev libxcb-xfixes0-dev libasound2-dev libpulse-dev cmake
|
||||
```
|
||||
|
||||
### Fedora 28 (CentOS 8)
|
||||
|
||||
```sh
|
||||
sudo yum -y install gcc-c++ git curl wget nasm yasm gcc gtk3-devel clang libxcb-devel libxdo-devel libXfixes-devel pulseaudio-libs-devel cmake alsa-lib-devel
|
||||
```
|
||||
|
||||
### Arch (Manjaro)
|
||||
|
||||
```sh
|
||||
sudo pacman -Syu --needed unzip git cmake gcc curl wget yasm nasm zip make pkg-config clang gtk3 xdotool libxcb libxfixes alsa-lib pulseaudio
|
||||
```
|
||||
|
||||
### 安装 vcpkg
|
||||
|
||||
```sh
|
||||
git clone https://github.com/microsoft/vcpkg
|
||||
cd vcpkg
|
||||
git checkout 2021.12.01
|
||||
cd ..
|
||||
vcpkg/bootstrap-vcpkg.sh
|
||||
export VCPKG_ROOT=$HOME/vcpkg
|
||||
vcpkg/vcpkg install libvpx libyuv opus
|
||||
```
|
||||
|
||||
### 修复 libvpx (仅仅针对 Fedora)
|
||||
|
||||
```sh
|
||||
cd vcpkg/buildtrees/libvpx/src
|
||||
cd *
|
||||
./configure
|
||||
sed -i 's/CFLAGS+=-I/CFLAGS+=-fPIC -I/g' Makefile
|
||||
sed -i 's/CXXFLAGS+=-I/CXXFLAGS+=-fPIC -I/g' Makefile
|
||||
make
|
||||
cp libvpx.a $HOME/vcpkg/installed/x64-linux/lib/
|
||||
cd
|
||||
```
|
||||
|
||||
### 构建
|
||||
|
||||
```sh
|
||||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
|
||||
source $HOME/.cargo/env
|
||||
git clone https://github.com/rustdesk/rustdesk
|
||||
cd rustdesk
|
||||
mkdir -p target/debug
|
||||
wget https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.lnx/x64/libsciter-gtk.so
|
||||
mv libsciter-gtk.so target/debug
|
||||
cargo run
|
||||
```
|
||||
|
||||
### 把 Wayland 修改成 X11 (Xorg)
|
||||
|
||||
RustDesk 暂时不支持 Wayland,不过正在积极开发中.
|
||||
请查看[this](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/)配置 X11.
|
||||
|
||||
## 使用 Docker 编译
|
||||
|
||||
首先克隆存储库并构建 docker 容器:
|
||||
|
||||
```sh
|
||||
git clone https://github.com/rustdesk/rustdesk
|
||||
cd rustdesk
|
||||
docker build -t "rustdesk-builder" .
|
||||
```
|
||||
|
||||
针对国内网络访问问题,可以做以下几点优化:
|
||||
|
||||
1. Dockerfile 中修改系统的源到国内镜像
|
||||
|
||||
```
|
||||
在Dockerfile的RUN apt update之前插入两行:
|
||||
|
||||
RUN sed -i "s/deb.debian.org/mirrors.163.com/g" /etc/apt/sources.list
|
||||
RUN sed -i "s/security.debian.org/mirrors.163.com/g" /etc/apt/sources.list
|
||||
```
|
||||
|
||||
2. 修改容器系统中的 cargo 源,在`RUN ./rustup.sh -y`后插入下面代码:
|
||||
|
||||
```
|
||||
RUN echo '[source.crates-io]' > ~/.cargo/config \
|
||||
&& echo 'registry = "https://github.com/rust-lang/crates.io-index"' >> ~/.cargo/config \
|
||||
&& echo '# 替换成你偏好的镜像源' >> ~/.cargo/config \
|
||||
&& echo "replace-with = 'sjtu'" >> ~/.cargo/config \
|
||||
&& echo '# 上海交通大学' >> ~/.cargo/config \
|
||||
&& echo '[source.sjtu]' >> ~/.cargo/config \
|
||||
&& echo 'registry = "https://mirrors.sjtug.sjtu.edu.cn/git/crates.io-index"' >> ~/.cargo/config \
|
||||
&& echo '' >> ~/.cargo/config
|
||||
```
|
||||
|
||||
3. Dockerfile 中加入代理的 env
|
||||
|
||||
```
|
||||
在User root后插入两行
|
||||
|
||||
ENV http_proxy=http://host:port
|
||||
ENV https_proxy=http://host:port
|
||||
```
|
||||
|
||||
4. docker build 命令后面加上 proxy 参数
|
||||
|
||||
```
|
||||
docker build -t "rustdesk-builder" . --build-arg http_proxy=http://host:port --build-arg https_proxy=http://host:port
|
||||
```
|
||||
|
||||
然后,每次需要构建应用程序时,运行以下命令:
|
||||
|
||||
```sh
|
||||
docker run --rm -it -v $PWD:/home/user/rustdesk -v rustdesk-git-cache:/home/user/.cargo/git -v rustdesk-registry-cache:/home/user/.cargo/registry -e PUID="$(id -u)" -e PGID="$(id -g)" rustdesk-builder
|
||||
```
|
||||
|
||||
运行若遇到无权限问题,出现以下提示:
|
||||
|
||||
```
|
||||
usermod: user user is currently used by process 1
|
||||
groupmod: Permission denied.
|
||||
groupmod: cannot lock /etc/group; try again later.
|
||||
```
|
||||
|
||||
可以尝试把`-e PUID="$(id -u)" -e PGID="$(id -g)"`参数去掉。(出现这一问题的原因是容器中的 entrypoint 脚本中判定 uid 和 gid 与给定的环境变量不一致时会修改 user 的 uid 和 gid 重新运行,但是重新运行时取不到环境变量中的 uid 和 gid 了,会再次进入 uid 与 gid 与给定值不一致的逻辑分支)
|
||||
|
||||
请注意,第一次构建可能需要比较长的时间,因为需要缓存依赖项(国内网络经常出现拉取失败,可多尝试几次),后续构建会更快。此外,如果您需要为构建命令指定不同的参数,
|
||||
您可以在命令末尾的 `<OPTIONAL-ARGS>` 位置执行此操作。例如,如果你想构建一个优化的发布版本,你可以在命令后跟 `---release`。
|
||||
将在 target 下产生可执行程序,请通过以下方式运行调试版本:
|
||||
|
||||
```sh
|
||||
target/debug/rustdesk
|
||||
```
|
||||
|
||||
或者运行发布版本:
|
||||
|
||||
```sh
|
||||
target/release/rustdesk
|
||||
```
|
||||
|
||||
请确保您从 RustDesk 存储库的根目录运行这些命令,否则应用程序可能无法找到所需的资源。另请注意,此方法当前不支持其他`Cargo`子命令,
|
||||
例如 `install` 或 `run`,因为运行在容器里,而不是宿主机上。
|
||||
|
||||
## 文件结构
|
||||
|
||||
- **[libs/hbb_common](https://github.com/rustdesk/rustdesk/tree/master/libs/hbb_common)**: 视频编解码, 配置, tcp/udp 封装, protobuf, 文件传输相关文件系统操作函数, 以及一些其他实用函数
|
||||
- **[libs/scrap](https://github.com/rustdesk/rustdesk/tree/master/libs/scrap)**: 截屏
|
||||
- **[libs/enigo](https://github.com/rustdesk/rustdesk/tree/master/libs/enigo)**: 平台相关的鼠标键盘输入
|
||||
- **[src/ui](https://github.com/rustdesk/rustdesk/tree/master/src/ui)**: GUI
|
||||
- **[src/server](https://github.com/rustdesk/rustdesk/tree/master/src/server)**: 被控端服务,audio/clipboard/input/video 服务, 已经连接实现
|
||||
- **[src/client.rs](https://github.com/rustdesk/rustdesk/tree/master/src/client.rs)**: 控制端
|
||||
- **[src/rendezvous_mediator.rs](https://github.com/rustdesk/rustdesk/tree/master/src/rendezvous_mediator.rs)**: 与[rustdesk-server](https://github.com/rustdesk/rustdesk-server)保持 UDP 通讯, 等待远程连接(通过打洞直连或者中继)
|
||||
- **[src/platform](https://github.com/rustdesk/rustdesk/tree/master/src/platform)**: 平台服务相关代码
|
||||
|
||||
## 截图
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
106
README.md
106
README.md
@@ -1,60 +1,87 @@
|
||||
# RustDesk | Your Remote Desktop Software
|
||||
<p align="center">
|
||||
<img src="logo-header.svg" alt="RustDesk - Your remote desktop"><br>
|
||||
<a href="#free-public-servers">Servers</a> •
|
||||
<a href="#raw-steps-to-build">Build</a> •
|
||||
<a href="#how-to-build-with-docker">Docker</a> •
|
||||
<a href="#file-structure">Structure</a> •
|
||||
<a href="#snapshot">Snapshot</a><br>
|
||||
[<a href="README-ZH.md">中文</a>] | [<a href="README-ES.md">Español</a>] | [<a href="README-FR.md">Français</a>] | [<a href="README-DE.md">Deutsch</a>] | [<a href="README-PL.md">Polski</a>] | [<a href="README-FI.md">Suomi</a>] | [<a href="README-ML.md">മലയാളം</a>] | [<a href="README-JP.md">日本語</a>] | [<a href="README-NL.md">Nederlands</a>] | [<a href="README-IT.md">Italiano</a>] | [<a href="README-RU.md">Русский</a>] | [<a href="README-PTBR.md">Português (Brasil)</a>] | [<a href="README-EO.md">Esperanto</a>]<br>
|
||||
<b>We need your help to translate this README and <a href="https://github.com/rustdesk/rustdesk/tree/master/src/lang">RustDesk UI</a> to your native language</b>
|
||||
</p>
|
||||
|
||||
Chat with us: [Discord](https://discord.gg/nDceKgxnkV)
|
||||
Chat with us: [Discord](https://discord.gg/nDceKgxnkV) | [Reddit](https://www.reddit.com/r/rustdesk)
|
||||
|
||||
[](https://ko-fi.com/I2I04VU09)
|
||||
|
||||
An open-source remote desktop client software, written in Rust. Works out of the box, no configuration required. Great alternative to TeamViewer and AnyDesk! You have full control of your data, with no concerns about security. You can use our rendezvous/relay server, [set up your own](https://rustdesk.com/blog/id-relay-set/), or [write your own rendezvous/relay server](https://github.com/rustdesk/rustdesk-server-demo).
|
||||
Yet another remote desktop software, written in Rust. Works out of the box, no configuration required. You have full control of your data, with no concerns about security. You can use our rendezvous/relay server, [set up your own](https://rustdesk.com/server), or [write your own rendezvous/relay server](https://github.com/rustdesk/rustdesk-server-demo).
|
||||
|
||||
RustDesk welcomes contribution from everyone. See [`CONTRIBUTING.md`](CONTRIBUTING.md) for help getting started.
|
||||
RustDesk welcomes contribution from everyone. See [`CONTRIBUTING.md`](CONTRIBUTING.md) for help getting started.
|
||||
|
||||
[**BINARY DOWNLOAD**](https://github.com/rustdesk/rustdesk/releases)
|
||||
|
||||
## Free Public Servers
|
||||
|
||||
Below are the servers you are using for free, it may change along the time. If you are not close to one of these, your network may be slow.
|
||||
| Location | Vendor | Specification |
|
||||
| --------- | ------------- | ------------------ |
|
||||
| Seoul | AWS lightsail | 1 VCPU / 0.5GB RAM |
|
||||
| Singapore | Vultr | 1 VCPU / 1GB RAM |
|
||||
| Dallas | Vultr | 1 VCPU / 1GB RAM | |
|
||||
|
||||
## Dependencies
|
||||
|
||||
Desktop versions use [sciter](https://sciter.com/) for GUI, please download sciter dynamic library yourself.
|
||||
|
||||
[Windows](https://github.com/c-smile/sciter-sdk/blob/dc65744b66389cd5a0ff6bdb7c63a8b7b05a708b/bin.win/x64/sciter.dll) |
|
||||
[Linux](https://github.com/c-smile/sciter-sdk/raw/dc65744b66389cd5a0ff6bdb7c63a8b7b05a708b/bin.lnx/x64/libsciter-gtk.so) |
|
||||
[macOS](https://github.com/c-smile/sciter-sdk/raw/dc65744b66389cd5a0ff6bdb7c63a8b7b05a708b/bin.osx/sciter-osx-64.dylib)
|
||||
[Windows](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.win/x64/sciter.dll) |
|
||||
[Linux](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.lnx/x64/libsciter-gtk.so) |
|
||||
[MacOS](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.osx/libsciter.dylib)
|
||||
|
||||
## Raw steps to build
|
||||
* Prepare your Rust development env and C++ build env
|
||||
|
||||
* Install [vcpkg](https://github.com/microsoft/vcpkg), and set `VCPKG_ROOT` env variable correctly
|
||||
- Prepare your Rust development env and C++ build env
|
||||
|
||||
- Windows: vcpkg install libvpx:x64-windows-static libyuv:x64-windows-static opus:x64-windows-static
|
||||
- Linux/Osx: vcpkg install libvpx libyuv opus
|
||||
|
||||
* run `cargo run`
|
||||
- Install [vcpkg](https://github.com/microsoft/vcpkg), and set `VCPKG_ROOT` env variable correctly
|
||||
|
||||
- Windows: vcpkg install libvpx:x64-windows-static libyuv:x64-windows-static opus:x64-windows-static
|
||||
- Linux/MacOS: vcpkg install libvpx libyuv opus
|
||||
|
||||
- run `cargo run`
|
||||
|
||||
## How to build on Linux
|
||||
|
||||
### Ubuntu 18 (Debian 10)
|
||||
```
|
||||
|
||||
```sh
|
||||
sudo apt install -y g++ gcc git curl wget nasm yasm libgtk-3-dev clang libxcb-randr0-dev libxdo-dev libxfixes-dev libxcb-shape0-dev libxcb-xfixes0-dev libasound2-dev libpulse-dev cmake
|
||||
```
|
||||
|
||||
### Fedora 28 (CentOS 8)
|
||||
```
|
||||
|
||||
```sh
|
||||
sudo yum -y install gcc-c++ git curl wget nasm yasm gcc gtk3-devel clang libxcb-devel libxdo-devel libXfixes-devel pulseaudio-libs-devel cmake alsa-lib-devel
|
||||
```
|
||||
|
||||
### Arch (Manjaro)
|
||||
```
|
||||
|
||||
```sh
|
||||
sudo pacman -Syu --needed unzip git cmake gcc curl wget yasm nasm zip make pkg-config clang gtk3 xdotool libxcb libxfixes alsa-lib pulseaudio
|
||||
```
|
||||
|
||||
### Install vcpkg
|
||||
```
|
||||
git clone https://github.com/microsoft/vcpkg --branch 2020.11-1
|
||||
|
||||
```sh
|
||||
git clone https://github.com/microsoft/vcpkg
|
||||
cd vcpkg
|
||||
git checkout 2021.12.01
|
||||
cd ..
|
||||
vcpkg/bootstrap-vcpkg.sh
|
||||
export VCPKG_ROOT=$HOME/vcpkg
|
||||
vcpkg/vcpkg install libvpx libyuv opus
|
||||
```
|
||||
|
||||
### Fix libvpx (For Fedora)
|
||||
```
|
||||
|
||||
```sh
|
||||
cd vcpkg/buildtrees/libvpx/src
|
||||
cd *
|
||||
./configure
|
||||
@@ -66,20 +93,52 @@ cd
|
||||
```
|
||||
|
||||
### Build
|
||||
```
|
||||
|
||||
```sh
|
||||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
|
||||
source $HOME/.cargo/env
|
||||
git clone https://github.com/rustdesk/rustdesk
|
||||
cd rustdesk
|
||||
mkdir -p target/debug
|
||||
wget https://github.com/c-smile/sciter-sdk/raw/dc65744b66389cd5a0ff6bdb7c63a8b7b05a708b/bin.lnx/x64/libsciter-gtk.so
|
||||
wget https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.lnx/x64/libsciter-gtk.so
|
||||
mv libsciter-gtk.so target/debug
|
||||
cargo run
|
||||
VCPKG_ROOT=$HOME/vcpkg cargo run
|
||||
```
|
||||
|
||||
### Change Wayland to X11 (Xorg)
|
||||
|
||||
RustDesk does not support Wayland. Check [this](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/) to configuring Xorg as the default GNOME session.
|
||||
|
||||
## How to build with Docker
|
||||
|
||||
Begin by cloning the repository and building the docker container:
|
||||
|
||||
```sh
|
||||
git clone https://github.com/rustdesk/rustdesk
|
||||
cd rustdesk
|
||||
docker build -t "rustdesk-builder" .
|
||||
```
|
||||
|
||||
Then, each time you need to build the application, run the following command:
|
||||
|
||||
```sh
|
||||
docker run --rm -it -v $PWD:/home/user/rustdesk -v rustdesk-git-cache:/home/user/.cargo/git -v rustdesk-registry-cache:/home/user/.cargo/registry -e PUID="$(id -u)" -e PGID="$(id -g)" rustdesk-builder
|
||||
```
|
||||
|
||||
Note that the first build may take longer before dependencies are cached, subsequent builds will be faster. Additionally, if you need to specify different arguments to the build command, you may do so at the end of the command in the `<OPTIONAL-ARGS>` position. For instance, if you wanted to build an optimized release version, you would run the command above followed by `---release`. The resulting executable will be available in the target folder on your system, and can be run with:
|
||||
|
||||
```sh
|
||||
target/debug/rustdesk
|
||||
```
|
||||
|
||||
Or, if you're running a release executable:
|
||||
|
||||
```sh
|
||||
target/release/rustdesk
|
||||
```
|
||||
|
||||
Please ensure that you are running these commands from the root of the RustDesk repository, otherwise the application may be unable to find the required resources. Also note that other cargo subcommands such as `install` or `run` are not currently supported via this method as they would install or run the program inside the container instead of the host.
|
||||
|
||||
## File Structure
|
||||
|
||||
- **[libs/hbb_common](https://github.com/rustdesk/rustdesk/tree/master/libs/hbb_common)**: video codec, config, tcp/udp wrapper, protobuf, fs functions for file transfer, and some other utility functions
|
||||
@@ -92,10 +151,11 @@ RustDesk does not support Wayland. Check [this](https://docs.fedoraproject.org/e
|
||||
- **[src/platform](https://github.com/rustdesk/rustdesk/tree/master/src/platform)**: platform specific code
|
||||
|
||||
## Snapshot
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||

|
||||
|
||||
13
SECURITY.md
Normal file
13
SECURITY.md
Normal file
@@ -0,0 +1,13 @@
|
||||
# Security Policy
|
||||
|
||||
## Supported Versions
|
||||
|
||||
| Version | Supported |
|
||||
| --------- | ------------------ |
|
||||
| 1.1.x | :white_check_mark: |
|
||||
| 1.x | :white_check_mark: |
|
||||
| Below 1.0 | :x: |
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
Here we should write what to do in case of a security vulnerability
|
||||
112
build.py
Normal file
112
build.py
Normal file
@@ -0,0 +1,112 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import os
|
||||
import platform
|
||||
import zlib
|
||||
from shutil import copy2
|
||||
import hashlib
|
||||
|
||||
windows = platform.platform().startswith('Windows')
|
||||
osx = platform.platform().startswith('Darwin') or platform.platform().startswith("macOS")
|
||||
hbb_name = 'rustdesk' + ('.exe' if windows else '')
|
||||
exe_path = 'target/release/' + hbb_name
|
||||
|
||||
|
||||
def get_version():
|
||||
with open("Cargo.toml") as fh:
|
||||
for line in fh:
|
||||
if line.startswith("version"):
|
||||
return line.replace("version", "").replace("=", "").replace('"', '').strip()
|
||||
return ''
|
||||
|
||||
|
||||
def main():
|
||||
os.system("cp Cargo.toml Cargo.toml.bk")
|
||||
os.system("cp src/main.rs src/main.rs.bk")
|
||||
if windows:
|
||||
txt = open('src/main.rs', encoding='utf8').read()
|
||||
with open('src/main.rs', 'wt', encoding='utf8') as fh:
|
||||
fh.write(txt.replace(
|
||||
'//#![windows_subsystem', '#![windows_subsystem'))
|
||||
if os.path.exists(exe_path):
|
||||
os.unlink(exe_path)
|
||||
os.system('python3 inline-sciter.py')
|
||||
if os.path.isfile('/usr/bin/pacman'):
|
||||
os.system('git checkout src/ui/common.tis')
|
||||
version = get_version()
|
||||
if windows:
|
||||
os.system('cargo build --release --features inline')
|
||||
# os.system('upx.exe target/release/rustdesk.exe')
|
||||
os.system('mv target/release/rustdesk.exe target/release/RustDesk.exe')
|
||||
pa = os.environ.get('P')
|
||||
if pa:
|
||||
os.system('signtool sign /a /v /p %s /debug /f .\\cert.pfx /t http://timestamp.digicert.com target\\release\\rustdesk.exe'%pa)
|
||||
else:
|
||||
print('Not signed')
|
||||
os.system('cp -rf target/release/RustDesk.exe rustdesk-%s-putes.exe'%version)
|
||||
else:
|
||||
os.system('cargo bundle --release --features inline')
|
||||
if osx:
|
||||
os.system(
|
||||
'strip target/release/bundle/osx/RustDesk.app/Contents/MacOS/rustdesk')
|
||||
os.system(
|
||||
'cp libsciter.dylib target/release/bundle/osx/RustDesk.app/Contents/MacOS/')
|
||||
# https://github.com/sindresorhus/create-dmg
|
||||
os.system('/bin/rm -rf *.dmg')
|
||||
plist = "target/release/bundle/osx/RustDesk.app/Contents/Info.plist"
|
||||
txt = open(plist).read()
|
||||
with open(plist, "wt") as fh:
|
||||
fh.write(txt.replace("</dict>", """
|
||||
<key>LSUIElement</key>
|
||||
<string>1</string>
|
||||
</dict>"""))
|
||||
pa = os.environ.get('P')
|
||||
if pa:
|
||||
os.system('''
|
||||
# buggy: rcodesign sign ... path/*, have to sign one by one
|
||||
#rcodesign sign --p12-file ~/.p12/rustdesk-developer-id.p12 --p12-password-file ~/.p12/.cert-pass --code-signature-flags runtime ./target/release/bundle/osx/RustDesk.app/Contents/MacOS/rustdesk
|
||||
#rcodesign sign --p12-file ~/.p12/rustdesk-developer-id.p12 --p12-password-file ~/.p12/.cert-pass --code-signature-flags runtime ./target/release/bundle/osx/RustDesk.app/Contents/MacOS/libsciter.dylib
|
||||
#rcodesign sign --p12-file ~/.p12/rustdesk-developer-id.p12 --p12-password-file ~/.p12/.cert-pass --code-signature-flags runtime ./target/release/bundle/osx/RustDesk.app
|
||||
# goto "Keychain Access" -> "My Certificates" for below id which starts with "Developer ID Application:"
|
||||
codesign -s "Developer ID Application: {0}" --force --options runtime ./target/release/bundle/osx/RustDesk.app/Contents/MacOS/*
|
||||
codesign -s "Developer ID Application: {0}" --force --options runtime ./target/release/bundle/osx/RustDesk.app
|
||||
'''.format(pa))
|
||||
os.system('create-dmg target/release/bundle/osx/RustDesk.app')
|
||||
os.rename('RustDesk %s.dmg'%version, 'rustdesk-%s.dmg'%version)
|
||||
if pa:
|
||||
os.system('''
|
||||
#rcodesign sign --p12-file ~/.p12/rustdesk-developer-id.p12 --p12-password-file ~/.p12/.cert-pass --code-signature-flags runtime ./rustdesk-{1}.dmg
|
||||
codesign -s "Developer ID Application: {0}" --force --options runtime ./rustdesk-{1}.dmg
|
||||
# https://pyoxidizer.readthedocs.io/en/latest/apple_codesign_rcodesign.html
|
||||
rcodesign notarize --api-issuer 69a6de7d-2907-47e3-e053-5b8c7c11a4d1 --api-key 9JBRHG3JHT --staple ./rustdesk-{1}.dmg
|
||||
# verify: spctl -a -t exec -v /Applications/RustDesk.app
|
||||
'''.format(pa, version))
|
||||
else:
|
||||
print('Not signed')
|
||||
else:
|
||||
os.system('mv target/release/bundle/deb/rustdesk*.deb ./rustdesk.deb')
|
||||
os.system('dpkg-deb -R rustdesk.deb tmpdeb')
|
||||
os.system('mkdir -p tmpdeb/usr/share/rustdesk/files/systemd/')
|
||||
os.system(
|
||||
'cp rustdesk.service tmpdeb/usr/share/rustdesk/files/systemd/')
|
||||
os.system('cp pynput_service.py tmpdeb/usr/share/rustdesk/files/')
|
||||
os.system('cp DEBIAN/* tmpdeb/DEBIAN/')
|
||||
os.system('strip tmpdeb/usr/bin/rustdesk')
|
||||
os.system('mkdir -p tmpdeb/usr/lib/rustdesk')
|
||||
os.system('cp libsciter-gtk.so tmpdeb/usr/lib/rustdesk/')
|
||||
md5_file('usr/share/rustdesk/files/systemd/rustdesk.service')
|
||||
md5_file('usr/share/rustdesk/files/pynput_service.py')
|
||||
md5_file('usr/lib/rustdesk/libsciter-gtk.so')
|
||||
os.system('dpkg-deb -b tmpdeb rustdesk.deb; /bin/rm -rf tmpdeb/')
|
||||
os.rename('rustdesk.deb', 'rustdesk-%s.deb'%version)
|
||||
os.system("mv Cargo.toml.bk Cargo.toml")
|
||||
os.system("mv src/main.rs.bk src/main.rs")
|
||||
|
||||
|
||||
def md5_file(fn):
|
||||
md5 = hashlib.md5(open('tmpdeb/' + fn, 'rb').read()).hexdigest()
|
||||
os.system('echo "%s %s" >> tmpdeb/DEBIAN/md5sums' % (md5, fn))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
34
entrypoint
Executable file
34
entrypoint
Executable file
@@ -0,0 +1,34 @@
|
||||
#!/bin/sh
|
||||
|
||||
cd $HOME/rustdesk
|
||||
. $HOME/.cargo/env
|
||||
|
||||
argv=$@
|
||||
|
||||
while test $# -gt 0; do
|
||||
case "$1" in
|
||||
--release)
|
||||
mkdir -p target/release
|
||||
test -f target/release/libsciter-gtk.so || cp $HOME/libsciter-gtk.so target/release/
|
||||
release=1
|
||||
shift
|
||||
;;
|
||||
--target)
|
||||
shift
|
||||
if test $# -gt 0; then
|
||||
rustup target add $1
|
||||
shift
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ -z $release ]; then
|
||||
mkdir -p target/debug
|
||||
test -f target/debug/libsciter-gtk.so || cp $HOME/libsciter-gtk.so target/debug/
|
||||
fi
|
||||
|
||||
VCPKG_ROOT=/vcpkg cargo build $argv
|
||||
81
inline-sciter.py
Normal file
81
inline-sciter.py
Normal file
@@ -0,0 +1,81 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import re
|
||||
|
||||
|
||||
def strip(s): return re.sub(r'\s+\n', '\n', re.sub(r'\n\s+', '\n', s))
|
||||
|
||||
common_css = open('src/ui/common.css').read()
|
||||
common_tis = open('src/ui/common.tis', encoding='UTF8').read()
|
||||
|
||||
index = open('src/ui/index.html').read() \
|
||||
.replace('@import url(index.css);', open('src/ui/index.css').read()) \
|
||||
.replace('include "index.tis";', open('src/ui/index.tis').read()) \
|
||||
.replace('include "msgbox.tis";', open('src/ui/msgbox.tis').read()) \
|
||||
.replace('include "ab.tis";', open('src/ui/ab.tis').read())
|
||||
|
||||
remote = open('src/ui/remote.html').read() \
|
||||
.replace('@import url(remote.css);', open('src/ui/remote.css').read()) \
|
||||
.replace('@import url(header.css);', open('src/ui/header.css').read()) \
|
||||
.replace('@import url(file_transfer.css);', open('src/ui/file_transfer.css').read()) \
|
||||
.replace('include "remote.tis";', open('src/ui/remote.tis').read()) \
|
||||
.replace('include "msgbox.tis";', open('src/ui/msgbox.tis').read()) \
|
||||
.replace('include "grid.tis";', open('src/ui/grid.tis').read()) \
|
||||
.replace('include "header.tis";', open('src/ui/header.tis').read()) \
|
||||
.replace('include "file_transfer.tis";', open('src/ui/file_transfer.tis').read()) \
|
||||
.replace('include "port_forward.tis";', open('src/ui/port_forward.tis').read())
|
||||
|
||||
chatbox = open('src/ui/chatbox.html').read()
|
||||
install = open('src/ui/install.html').read().replace('include "install.tis";', open('src/ui/install.tis').read())
|
||||
|
||||
cm = open('src/ui/cm.html').read() \
|
||||
.replace('@import url(cm.css);', open('src/ui/cm.css').read()) \
|
||||
.replace('include "cm.tis";', open('src/ui/cm.tis').read())
|
||||
|
||||
|
||||
def compress(s):
|
||||
s = s.replace("\r\n", "\n")
|
||||
x = bytes(s, encoding='utf-8')
|
||||
return '&[u8; ' + str(len(x)) + '] = b"' + str(x)[2:-1].replace(r"\'", "'").replace(r'"',
|
||||
r'\"') + '"'
|
||||
|
||||
|
||||
with open('src/ui/inline.rs', 'wt') as fh:
|
||||
fh.write('const _COMMON_CSS: ' + compress(strip(common_css)) + ';\n')
|
||||
fh.write('const _COMMON_TIS: ' + compress(strip(common_tis)) + ';\n')
|
||||
fh.write('const _INDEX: ' + compress(strip(index)) + ';\n')
|
||||
fh.write('const _REMOTE: ' + compress(strip(remote)) + ';\n')
|
||||
fh.write('const _CHATBOX: ' + compress(strip(chatbox)) + ';\n')
|
||||
fh.write('const _INSTALL: ' + compress(strip(install)) + ';\n')
|
||||
fh.write('const _CONNECTION_MANAGER: ' + compress(strip(cm)) + ';\n')
|
||||
fh.write('''
|
||||
fn get(data: &[u8]) -> String {
|
||||
String::from_utf8_lossy(data).to_string()
|
||||
}
|
||||
fn replace(data: &[u8]) -> String {
|
||||
let css = get(&_COMMON_CSS[..]);
|
||||
let res = get(data).replace("@import url(common.css);", &css);
|
||||
let tis = get(&_COMMON_TIS[..]);
|
||||
res.replace("include \\\"common.tis\\\";", &tis)
|
||||
}
|
||||
#[inline]
|
||||
pub fn get_index() -> String {
|
||||
replace(&_INDEX[..])
|
||||
}
|
||||
#[inline]
|
||||
pub fn get_remote() -> String {
|
||||
replace(&_REMOTE[..])
|
||||
}
|
||||
#[inline]
|
||||
pub fn get_install() -> String {
|
||||
replace(&_INSTALL[..])
|
||||
}
|
||||
#[inline]
|
||||
pub fn get_chatbox() -> String {
|
||||
replace(&_CHATBOX[..])
|
||||
}
|
||||
#[inline]
|
||||
pub fn get_cm() -> String {
|
||||
replace(&_CONNECTION_MANAGER[..])
|
||||
}
|
||||
''')
|
||||
17
libs/clipboard/Cargo.toml
Normal file
17
libs/clipboard/Cargo.toml
Normal file
@@ -0,0 +1,17 @@
|
||||
[package]
|
||||
name = "clipboard"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
build= "build.rs"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[build-dependencies]
|
||||
cc = "1.0"
|
||||
|
||||
[dependencies]
|
||||
thiserror = "1.0.30"
|
||||
lazy_static = "1.4"
|
||||
serde = "1.0"
|
||||
serde_derive = "1.0"
|
||||
hbb_common = { path = "../hbb_common" }
|
||||
16
libs/clipboard/README.md
Normal file
16
libs/clipboard/README.md
Normal file
@@ -0,0 +1,16 @@
|
||||
# clipboard
|
||||
|
||||
Copy files and text through network.
|
||||
Main lowlevel logic from [FreeRDP](https://github.com/FreeRDP/FreeRDP).
|
||||
|
||||
TODO: Move this lib to a separate project.
|
||||
|
||||
## impl
|
||||
|
||||
### windows
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
43
libs/clipboard/build.rs
Normal file
43
libs/clipboard/build.rs
Normal file
@@ -0,0 +1,43 @@
|
||||
use cc;
|
||||
|
||||
fn build_c_impl() {
|
||||
let mut build = cc::Build::new();
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
build.file("src/windows/wf_cliprdr.c");
|
||||
#[cfg(target_os = "linux")]
|
||||
build.file("src/X11/xf_cliprdr.c");
|
||||
#[cfg(target_os = "macos")]
|
||||
build.file("src/OSX/Clipboard.m");
|
||||
|
||||
build.flag_if_supported("-Wno-c++0x-extensions");
|
||||
build.flag_if_supported("-Wno-return-type-c-linkage");
|
||||
build.flag_if_supported("-Wno-invalid-offsetof");
|
||||
build.flag_if_supported("-Wno-unused-parameter");
|
||||
|
||||
if build.get_compiler().is_like_msvc() {
|
||||
build.define("WIN32", "");
|
||||
// build.define("_AMD64_", "");
|
||||
build.flag("-Zi");
|
||||
build.flag("-GR-");
|
||||
// build.flag("-std:c++11");
|
||||
} else {
|
||||
build.flag("-fPIC");
|
||||
// build.flag("-std=c++11");
|
||||
// build.flag("-include");
|
||||
// build.flag(&confdefs_path.to_string_lossy());
|
||||
}
|
||||
|
||||
build.compile("mycliprdr");
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
println!("cargo:rerun-if-changed=src/windows/wf_cliprdr.c");
|
||||
#[cfg(target_os = "linux")]
|
||||
println!("cargo:rerun-if-changed=src/X11/xf_cliprdr.c");
|
||||
#[cfg(target_os = "macos")]
|
||||
println!("cargo:rerun-if-changed=src/OSX/Clipboard.m");
|
||||
}
|
||||
|
||||
fn main() {
|
||||
build_c_impl();
|
||||
}
|
||||
BIN
libs/clipboard/docs/assets/scene3.png
Normal file
BIN
libs/clipboard/docs/assets/scene3.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.2 KiB |
BIN
libs/clipboard/docs/assets/win_A_B.png
Normal file
BIN
libs/clipboard/docs/assets/win_A_B.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 52 KiB |
BIN
libs/clipboard/docs/assets/win_B_A.png
Normal file
BIN
libs/clipboard/docs/assets/win_B_A.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 53 KiB |
11
libs/clipboard/src/OSX/Clipboard.m
Normal file
11
libs/clipboard/src/OSX/Clipboard.m
Normal file
@@ -0,0 +1,11 @@
|
||||
#include "../cliprdr.h"
|
||||
|
||||
void mac_cliprdr_init(CliprdrClientContext *cliprdr)
|
||||
{
|
||||
(void)cliprdr;
|
||||
}
|
||||
|
||||
void mac_cliprdr_uninit(CliprdrClientContext *cliprdr)
|
||||
{
|
||||
(void)cliprdr;
|
||||
}
|
||||
11
libs/clipboard/src/X11/xf_cliprdr.c
Normal file
11
libs/clipboard/src/X11/xf_cliprdr.c
Normal file
@@ -0,0 +1,11 @@
|
||||
#include "../cliprdr.h"
|
||||
|
||||
void xf_cliprdr_init(CliprdrClientContext* cliprdr)
|
||||
{
|
||||
(void)cliprdr;
|
||||
}
|
||||
|
||||
void xf_cliprdr_uninit( CliprdrClientContext* cliprdr)
|
||||
{
|
||||
(void)cliprdr;
|
||||
}
|
||||
233
libs/clipboard/src/cliprdr.h
Normal file
233
libs/clipboard/src/cliprdr.h
Normal file
@@ -0,0 +1,233 @@
|
||||
#ifndef WF_CLIPRDR_H__
|
||||
#define WF_CLIPRDR_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
typedef signed char INT8, *PINT8;
|
||||
typedef signed short INT16, *PINT16;
|
||||
typedef signed int INT32, *PINT32;
|
||||
typedef unsigned char UINT8, *PUINT8;
|
||||
typedef unsigned short UINT16, *PUINT16;
|
||||
typedef unsigned int UINT32, *PUINT32;
|
||||
typedef unsigned int UINT;
|
||||
typedef int BOOL;
|
||||
typedef unsigned char BYTE;
|
||||
|
||||
/* Clipboard Messages */
|
||||
#define DEFINE_CLIPRDR_HEADER_COMMON() \
|
||||
UINT32 connID; \
|
||||
UINT16 msgType; \
|
||||
UINT16 msgFlags; \
|
||||
UINT32 dataLen
|
||||
|
||||
struct _CLIPRDR_HEADER
|
||||
{
|
||||
DEFINE_CLIPRDR_HEADER_COMMON();
|
||||
};
|
||||
typedef struct _CLIPRDR_HEADER CLIPRDR_HEADER;
|
||||
|
||||
struct _CLIPRDR_CAPABILITY_SET
|
||||
{
|
||||
UINT16 capabilitySetType;
|
||||
UINT16 capabilitySetLength;
|
||||
};
|
||||
typedef struct _CLIPRDR_CAPABILITY_SET CLIPRDR_CAPABILITY_SET;
|
||||
|
||||
struct _CLIPRDR_GENERAL_CAPABILITY_SET
|
||||
{
|
||||
UINT16 capabilitySetType;
|
||||
UINT16 capabilitySetLength;
|
||||
|
||||
UINT32 version;
|
||||
UINT32 generalFlags;
|
||||
};
|
||||
typedef struct _CLIPRDR_GENERAL_CAPABILITY_SET CLIPRDR_GENERAL_CAPABILITY_SET;
|
||||
|
||||
struct _CLIPRDR_CAPABILITIES
|
||||
{
|
||||
DEFINE_CLIPRDR_HEADER_COMMON();
|
||||
|
||||
UINT32 cCapabilitiesSets;
|
||||
CLIPRDR_CAPABILITY_SET *capabilitySets;
|
||||
};
|
||||
typedef struct _CLIPRDR_CAPABILITIES CLIPRDR_CAPABILITIES;
|
||||
|
||||
struct _CLIPRDR_MONITOR_READY
|
||||
{
|
||||
DEFINE_CLIPRDR_HEADER_COMMON();
|
||||
};
|
||||
typedef struct _CLIPRDR_MONITOR_READY CLIPRDR_MONITOR_READY;
|
||||
|
||||
struct _CLIPRDR_TEMP_DIRECTORY
|
||||
{
|
||||
DEFINE_CLIPRDR_HEADER_COMMON();
|
||||
|
||||
char szTempDir[520];
|
||||
};
|
||||
typedef struct _CLIPRDR_TEMP_DIRECTORY CLIPRDR_TEMP_DIRECTORY;
|
||||
|
||||
struct _CLIPRDR_FORMAT
|
||||
{
|
||||
UINT32 formatId;
|
||||
char *formatName;
|
||||
};
|
||||
typedef struct _CLIPRDR_FORMAT CLIPRDR_FORMAT;
|
||||
|
||||
struct _CLIPRDR_FORMAT_LIST
|
||||
{
|
||||
DEFINE_CLIPRDR_HEADER_COMMON();
|
||||
|
||||
UINT32 numFormats;
|
||||
CLIPRDR_FORMAT *formats;
|
||||
};
|
||||
typedef struct _CLIPRDR_FORMAT_LIST CLIPRDR_FORMAT_LIST;
|
||||
|
||||
struct _CLIPRDR_FORMAT_LIST_RESPONSE
|
||||
{
|
||||
DEFINE_CLIPRDR_HEADER_COMMON();
|
||||
};
|
||||
typedef struct _CLIPRDR_FORMAT_LIST_RESPONSE CLIPRDR_FORMAT_LIST_RESPONSE;
|
||||
|
||||
struct _CLIPRDR_LOCK_CLIPBOARD_DATA
|
||||
{
|
||||
DEFINE_CLIPRDR_HEADER_COMMON();
|
||||
|
||||
UINT32 clipDataId;
|
||||
};
|
||||
typedef struct _CLIPRDR_LOCK_CLIPBOARD_DATA CLIPRDR_LOCK_CLIPBOARD_DATA;
|
||||
|
||||
struct _CLIPRDR_UNLOCK_CLIPBOARD_DATA
|
||||
{
|
||||
DEFINE_CLIPRDR_HEADER_COMMON();
|
||||
|
||||
UINT32 clipDataId;
|
||||
};
|
||||
typedef struct _CLIPRDR_UNLOCK_CLIPBOARD_DATA CLIPRDR_UNLOCK_CLIPBOARD_DATA;
|
||||
|
||||
struct _CLIPRDR_FORMAT_DATA_REQUEST
|
||||
{
|
||||
DEFINE_CLIPRDR_HEADER_COMMON();
|
||||
|
||||
UINT32 requestedFormatId;
|
||||
};
|
||||
typedef struct _CLIPRDR_FORMAT_DATA_REQUEST CLIPRDR_FORMAT_DATA_REQUEST;
|
||||
|
||||
struct _CLIPRDR_FORMAT_DATA_RESPONSE
|
||||
{
|
||||
DEFINE_CLIPRDR_HEADER_COMMON();
|
||||
|
||||
const BYTE *requestedFormatData;
|
||||
};
|
||||
typedef struct _CLIPRDR_FORMAT_DATA_RESPONSE CLIPRDR_FORMAT_DATA_RESPONSE;
|
||||
|
||||
struct _CLIPRDR_FILE_CONTENTS_REQUEST
|
||||
{
|
||||
DEFINE_CLIPRDR_HEADER_COMMON();
|
||||
|
||||
UINT32 streamId;
|
||||
UINT32 listIndex;
|
||||
UINT32 dwFlags;
|
||||
UINT32 nPositionLow;
|
||||
UINT32 nPositionHigh;
|
||||
UINT32 cbRequested;
|
||||
BOOL haveClipDataId;
|
||||
UINT32 clipDataId;
|
||||
};
|
||||
typedef struct _CLIPRDR_FILE_CONTENTS_REQUEST CLIPRDR_FILE_CONTENTS_REQUEST;
|
||||
|
||||
struct _CLIPRDR_FILE_CONTENTS_RESPONSE
|
||||
{
|
||||
DEFINE_CLIPRDR_HEADER_COMMON();
|
||||
|
||||
UINT32 streamId;
|
||||
UINT32 cbRequested;
|
||||
const BYTE *requestedData;
|
||||
};
|
||||
typedef struct _CLIPRDR_FILE_CONTENTS_RESPONSE CLIPRDR_FILE_CONTENTS_RESPONSE;
|
||||
|
||||
typedef struct _cliprdr_client_context CliprdrClientContext;
|
||||
|
||||
typedef UINT (*pcCliprdrServerCapabilities)(CliprdrClientContext *context,
|
||||
const CLIPRDR_CAPABILITIES *capabilities);
|
||||
typedef UINT (*pcCliprdrClientCapabilities)(CliprdrClientContext *context,
|
||||
const CLIPRDR_CAPABILITIES *capabilities);
|
||||
typedef UINT (*pcCliprdrMonitorReady)(CliprdrClientContext *context,
|
||||
const CLIPRDR_MONITOR_READY *monitorReady);
|
||||
typedef UINT (*pcCliprdrTempDirectory)(CliprdrClientContext *context,
|
||||
const CLIPRDR_TEMP_DIRECTORY *tempDirectory);
|
||||
typedef UINT (*pcCliprdrClientFormatList)(CliprdrClientContext *context,
|
||||
const CLIPRDR_FORMAT_LIST *formatList);
|
||||
typedef UINT (*pcCliprdrServerFormatList)(CliprdrClientContext *context,
|
||||
const CLIPRDR_FORMAT_LIST *formatList);
|
||||
typedef UINT (*pcCliprdrClientFormatListResponse)(
|
||||
CliprdrClientContext *context, const CLIPRDR_FORMAT_LIST_RESPONSE *formatListResponse);
|
||||
typedef UINT (*pcCliprdrServerFormatListResponse)(
|
||||
CliprdrClientContext *context, const CLIPRDR_FORMAT_LIST_RESPONSE *formatListResponse);
|
||||
typedef UINT (*pcCliprdrClientLockClipboardData)(
|
||||
CliprdrClientContext *context, const CLIPRDR_LOCK_CLIPBOARD_DATA *lockClipboardData);
|
||||
typedef UINT (*pcCliprdrServerLockClipboardData)(
|
||||
CliprdrClientContext *context, const CLIPRDR_LOCK_CLIPBOARD_DATA *lockClipboardData);
|
||||
typedef UINT (*pcCliprdrClientUnlockClipboardData)(
|
||||
CliprdrClientContext *context, const CLIPRDR_UNLOCK_CLIPBOARD_DATA *unlockClipboardData);
|
||||
typedef UINT (*pcCliprdrServerUnlockClipboardData)(
|
||||
CliprdrClientContext *context, const CLIPRDR_UNLOCK_CLIPBOARD_DATA *unlockClipboardData);
|
||||
typedef UINT (*pcCliprdrClientFormatDataRequest)(
|
||||
CliprdrClientContext *context, const CLIPRDR_FORMAT_DATA_REQUEST *formatDataRequest);
|
||||
typedef UINT (*pcCliprdrServerFormatDataRequest)(
|
||||
CliprdrClientContext *context, const CLIPRDR_FORMAT_DATA_REQUEST *formatDataRequest);
|
||||
typedef UINT (*pcCliprdrClientFormatDataResponse)(
|
||||
CliprdrClientContext *context, const CLIPRDR_FORMAT_DATA_RESPONSE *formatDataResponse);
|
||||
typedef UINT (*pcCliprdrServerFormatDataResponse)(
|
||||
CliprdrClientContext *context, const CLIPRDR_FORMAT_DATA_RESPONSE *formatDataResponse);
|
||||
typedef UINT (*pcCliprdrClientFileContentsRequest)(
|
||||
CliprdrClientContext *context, const CLIPRDR_FILE_CONTENTS_REQUEST *fileContentsRequest);
|
||||
typedef UINT (*pcCliprdrServerFileContentsRequest)(
|
||||
CliprdrClientContext *context, const CLIPRDR_FILE_CONTENTS_REQUEST *fileContentsRequest);
|
||||
typedef UINT (*pcCliprdrClientFileContentsResponse)(
|
||||
CliprdrClientContext *context, const CLIPRDR_FILE_CONTENTS_RESPONSE *fileContentsResponse);
|
||||
typedef UINT (*pcCliprdrServerFileContentsResponse)(
|
||||
CliprdrClientContext *context, const CLIPRDR_FILE_CONTENTS_RESPONSE *fileContentsResponse);
|
||||
|
||||
typedef BOOL (*pcCheckEnabled)(UINT32 connID);
|
||||
|
||||
// TODO: hide more members of clipboard context
|
||||
struct _cliprdr_client_context
|
||||
{
|
||||
void *custom;
|
||||
BOOL enableFiles;
|
||||
BOOL enableOthers;
|
||||
|
||||
pcCheckEnabled CheckEnabled;
|
||||
pcCliprdrServerCapabilities ServerCapabilities;
|
||||
pcCliprdrClientCapabilities ClientCapabilities;
|
||||
pcCliprdrMonitorReady MonitorReady;
|
||||
pcCliprdrTempDirectory TempDirectory;
|
||||
pcCliprdrClientFormatList ClientFormatList;
|
||||
pcCliprdrServerFormatList ServerFormatList;
|
||||
pcCliprdrClientFormatListResponse ClientFormatListResponse;
|
||||
pcCliprdrServerFormatListResponse ServerFormatListResponse;
|
||||
pcCliprdrClientLockClipboardData ClientLockClipboardData;
|
||||
pcCliprdrServerLockClipboardData ServerLockClipboardData;
|
||||
pcCliprdrClientUnlockClipboardData ClientUnlockClipboardData;
|
||||
pcCliprdrServerUnlockClipboardData ServerUnlockClipboardData;
|
||||
pcCliprdrClientFormatDataRequest ClientFormatDataRequest;
|
||||
pcCliprdrServerFormatDataRequest ServerFormatDataRequest;
|
||||
pcCliprdrClientFormatDataResponse ClientFormatDataResponse;
|
||||
pcCliprdrServerFormatDataResponse ServerFormatDataResponse;
|
||||
pcCliprdrClientFileContentsRequest ClientFileContentsRequest;
|
||||
pcCliprdrServerFileContentsRequest ServerFileContentsRequest;
|
||||
pcCliprdrClientFileContentsResponse ClientFileContentsResponse;
|
||||
pcCliprdrServerFileContentsResponse ServerFileContentsResponse;
|
||||
|
||||
UINT32 lastRequestedFormatId;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // WF_CLIPRDR_H__
|
||||
|
||||
564
libs/clipboard/src/cliprdr.rs
Normal file
564
libs/clipboard/src/cliprdr.rs
Normal file
@@ -0,0 +1,564 @@
|
||||
#![allow(dead_code)]
|
||||
#![allow(non_camel_case_types)]
|
||||
#![allow(unused_variables)]
|
||||
#![allow(non_snake_case)]
|
||||
#![allow(deref_nullptr)]
|
||||
|
||||
use std::{boxed::Box, result::Result};
|
||||
use thiserror::Error;
|
||||
|
||||
pub type size_t = ::std::os::raw::c_ulonglong;
|
||||
pub type __vcrt_bool = bool;
|
||||
pub type wchar_t = ::std::os::raw::c_ushort;
|
||||
|
||||
pub type POINTER_64_INT = ::std::os::raw::c_ulonglong;
|
||||
pub type INT8 = ::std::os::raw::c_schar;
|
||||
pub type PINT8 = *mut ::std::os::raw::c_schar;
|
||||
pub type INT16 = ::std::os::raw::c_short;
|
||||
pub type PINT16 = *mut ::std::os::raw::c_short;
|
||||
pub type INT32 = ::std::os::raw::c_int;
|
||||
pub type PINT32 = *mut ::std::os::raw::c_int;
|
||||
pub type INT64 = ::std::os::raw::c_longlong;
|
||||
pub type PINT64 = *mut ::std::os::raw::c_longlong;
|
||||
pub type UINT8 = ::std::os::raw::c_uchar;
|
||||
pub type PUINT8 = *mut ::std::os::raw::c_uchar;
|
||||
pub type UINT16 = ::std::os::raw::c_ushort;
|
||||
pub type PUINT16 = *mut ::std::os::raw::c_ushort;
|
||||
pub type UINT32 = ::std::os::raw::c_uint;
|
||||
pub type PUINT32 = *mut ::std::os::raw::c_uint;
|
||||
pub type UINT64 = ::std::os::raw::c_ulonglong;
|
||||
pub type PUINT64 = *mut ::std::os::raw::c_ulonglong;
|
||||
pub type LONG32 = ::std::os::raw::c_int;
|
||||
pub type PLONG32 = *mut ::std::os::raw::c_int;
|
||||
pub type ULONG32 = ::std::os::raw::c_uint;
|
||||
pub type PULONG32 = *mut ::std::os::raw::c_uint;
|
||||
pub type DWORD32 = ::std::os::raw::c_uint;
|
||||
pub type PDWORD32 = *mut ::std::os::raw::c_uint;
|
||||
pub type INT_PTR = ::std::os::raw::c_longlong;
|
||||
pub type PINT_PTR = *mut ::std::os::raw::c_longlong;
|
||||
pub type UINT_PTR = ::std::os::raw::c_ulonglong;
|
||||
pub type PUINT_PTR = *mut ::std::os::raw::c_ulonglong;
|
||||
pub type LONG_PTR = ::std::os::raw::c_longlong;
|
||||
pub type PLONG_PTR = *mut ::std::os::raw::c_longlong;
|
||||
pub type ULONG_PTR = ::std::os::raw::c_ulonglong;
|
||||
pub type PULONG_PTR = *mut ::std::os::raw::c_ulonglong;
|
||||
pub type SHANDLE_PTR = ::std::os::raw::c_longlong;
|
||||
pub type HANDLE_PTR = ::std::os::raw::c_ulonglong;
|
||||
pub type UHALF_PTR = ::std::os::raw::c_uint;
|
||||
pub type PUHALF_PTR = *mut ::std::os::raw::c_uint;
|
||||
pub type HALF_PTR = ::std::os::raw::c_int;
|
||||
pub type PHALF_PTR = *mut ::std::os::raw::c_int;
|
||||
pub type SIZE_T = ULONG_PTR;
|
||||
pub type PSIZE_T = *mut ULONG_PTR;
|
||||
pub type SSIZE_T = LONG_PTR;
|
||||
pub type PSSIZE_T = *mut LONG_PTR;
|
||||
pub type DWORD_PTR = ULONG_PTR;
|
||||
pub type PDWORD_PTR = *mut ULONG_PTR;
|
||||
pub type LONG64 = ::std::os::raw::c_longlong;
|
||||
pub type PLONG64 = *mut ::std::os::raw::c_longlong;
|
||||
pub type ULONG64 = ::std::os::raw::c_ulonglong;
|
||||
pub type PULONG64 = *mut ::std::os::raw::c_ulonglong;
|
||||
pub type DWORD64 = ::std::os::raw::c_ulonglong;
|
||||
pub type PDWORD64 = *mut ::std::os::raw::c_ulonglong;
|
||||
pub type KAFFINITY = ULONG_PTR;
|
||||
pub type PKAFFINITY = *mut KAFFINITY;
|
||||
pub type PVOID = *mut ::std::os::raw::c_void;
|
||||
pub type CHAR = ::std::os::raw::c_char;
|
||||
pub type SHORT = ::std::os::raw::c_short;
|
||||
pub type LONG = ::std::os::raw::c_long;
|
||||
pub type WCHAR = wchar_t;
|
||||
pub type PWCHAR = *mut WCHAR;
|
||||
pub type LPWCH = *mut WCHAR;
|
||||
pub type PWCH = *mut WCHAR;
|
||||
pub type LPCWCH = *const WCHAR;
|
||||
pub type PCWCH = *const WCHAR;
|
||||
pub type NWPSTR = *mut WCHAR;
|
||||
pub type LPWSTR = *mut WCHAR;
|
||||
pub type PWSTR = *mut WCHAR;
|
||||
pub type PZPWSTR = *mut PWSTR;
|
||||
pub type PCZPWSTR = *const PWSTR;
|
||||
pub type LPUWSTR = *mut WCHAR;
|
||||
pub type PUWSTR = *mut WCHAR;
|
||||
pub type LPCWSTR = *const WCHAR;
|
||||
pub type PCWSTR = *const WCHAR;
|
||||
pub type PZPCWSTR = *mut PCWSTR;
|
||||
pub type PCZPCWSTR = *const PCWSTR;
|
||||
pub type LPCUWSTR = *const WCHAR;
|
||||
pub type PCUWSTR = *const WCHAR;
|
||||
pub type PZZWSTR = *mut WCHAR;
|
||||
pub type PCZZWSTR = *const WCHAR;
|
||||
pub type PUZZWSTR = *mut WCHAR;
|
||||
pub type PCUZZWSTR = *const WCHAR;
|
||||
pub type PNZWCH = *mut WCHAR;
|
||||
pub type PCNZWCH = *const WCHAR;
|
||||
pub type PUNZWCH = *mut WCHAR;
|
||||
pub type PCUNZWCH = *const WCHAR;
|
||||
pub type PCHAR = *mut CHAR;
|
||||
pub type LPCH = *mut CHAR;
|
||||
pub type PCH = *mut CHAR;
|
||||
pub type LPCCH = *const CHAR;
|
||||
pub type PCCH = *const CHAR;
|
||||
pub type NPSTR = *mut CHAR;
|
||||
pub type LPSTR = *mut CHAR;
|
||||
pub type PSTR = *mut CHAR;
|
||||
pub type PZPSTR = *mut PSTR;
|
||||
pub type PCZPSTR = *const PSTR;
|
||||
pub type LPCSTR = *const CHAR;
|
||||
pub type PCSTR = *const CHAR;
|
||||
pub type PZPCSTR = *mut PCSTR;
|
||||
pub type PCZPCSTR = *const PCSTR;
|
||||
pub type PZZSTR = *mut CHAR;
|
||||
pub type PCZZSTR = *const CHAR;
|
||||
pub type PNZCH = *mut CHAR;
|
||||
pub type PCNZCH = *const CHAR;
|
||||
pub type TCHAR = ::std::os::raw::c_char;
|
||||
pub type PTCHAR = *mut ::std::os::raw::c_char;
|
||||
pub type TBYTE = ::std::os::raw::c_uchar;
|
||||
pub type PTBYTE = *mut ::std::os::raw::c_uchar;
|
||||
pub type LPTCH = LPCH;
|
||||
pub type PTCH = LPCH;
|
||||
pub type LPCTCH = LPCCH;
|
||||
pub type PCTCH = LPCCH;
|
||||
pub type PTSTR = LPSTR;
|
||||
pub type LPTSTR = LPSTR;
|
||||
pub type PUTSTR = LPSTR;
|
||||
pub type LPUTSTR = LPSTR;
|
||||
pub type PCTSTR = LPCSTR;
|
||||
pub type LPCTSTR = LPCSTR;
|
||||
pub type PCUTSTR = LPCSTR;
|
||||
pub type LPCUTSTR = LPCSTR;
|
||||
pub type PZZTSTR = PZZSTR;
|
||||
pub type PUZZTSTR = PZZSTR;
|
||||
pub type PCZZTSTR = PCZZSTR;
|
||||
pub type PCUZZTSTR = PCZZSTR;
|
||||
pub type PZPTSTR = PZPSTR;
|
||||
pub type PNZTCH = PNZCH;
|
||||
pub type PUNZTCH = PNZCH;
|
||||
pub type PCNZTCH = PCNZCH;
|
||||
pub type PCUNZTCH = PCNZCH;
|
||||
pub type PSHORT = *mut SHORT;
|
||||
pub type PLONG = *mut LONG;
|
||||
pub type ULONG = ::std::os::raw::c_ulong;
|
||||
pub type PULONG = *mut ULONG;
|
||||
pub type USHORT = ::std::os::raw::c_ushort;
|
||||
pub type PUSHORT = *mut USHORT;
|
||||
pub type UCHAR = ::std::os::raw::c_uchar;
|
||||
pub type PUCHAR = *mut UCHAR;
|
||||
pub type PSZ = *mut ::std::os::raw::c_char;
|
||||
pub type DWORD = ::std::os::raw::c_ulong;
|
||||
pub type BOOL = ::std::os::raw::c_int;
|
||||
pub type BYTE = ::std::os::raw::c_uchar;
|
||||
pub type WORD = ::std::os::raw::c_ushort;
|
||||
pub type FLOAT = f32;
|
||||
pub type PFLOAT = *mut FLOAT;
|
||||
pub type PBOOL = *mut BOOL;
|
||||
pub type LPBOOL = *mut BOOL;
|
||||
pub type PBYTE = *mut BYTE;
|
||||
pub type LPBYTE = *mut BYTE;
|
||||
pub type PINT = *mut ::std::os::raw::c_int;
|
||||
pub type LPINT = *mut ::std::os::raw::c_int;
|
||||
pub type PWORD = *mut WORD;
|
||||
pub type LPWORD = *mut WORD;
|
||||
pub type LPLONG = *mut ::std::os::raw::c_long;
|
||||
pub type PDWORD = *mut DWORD;
|
||||
pub type LPDWORD = *mut DWORD;
|
||||
pub type LPVOID = *mut ::std::os::raw::c_void;
|
||||
pub type LPCVOID = *const ::std::os::raw::c_void;
|
||||
pub type INT = ::std::os::raw::c_int;
|
||||
pub type UINT = ::std::os::raw::c_uint;
|
||||
pub type PUINT = *mut ::std::os::raw::c_uint;
|
||||
pub type va_list = *mut ::std::os::raw::c_char;
|
||||
|
||||
pub const TRUE: ::std::os::raw::c_int = 1;
|
||||
pub const FALSE: ::std::os::raw::c_int = 0;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct _CLIPRDR_HEADER {
|
||||
pub connID: UINT32,
|
||||
pub msgType: UINT16,
|
||||
pub msgFlags: UINT16,
|
||||
pub dataLen: UINT32,
|
||||
}
|
||||
pub type CLIPRDR_HEADER = _CLIPRDR_HEADER;
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct _CLIPRDR_CAPABILITY_SET {
|
||||
pub capabilitySetType: UINT16,
|
||||
pub capabilitySetLength: UINT16,
|
||||
}
|
||||
pub type CLIPRDR_CAPABILITY_SET = _CLIPRDR_CAPABILITY_SET;
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct _CLIPRDR_GENERAL_CAPABILITY_SET {
|
||||
pub capabilitySetType: UINT16,
|
||||
pub capabilitySetLength: UINT16,
|
||||
pub version: UINT32,
|
||||
pub generalFlags: UINT32,
|
||||
}
|
||||
pub type CLIPRDR_GENERAL_CAPABILITY_SET = _CLIPRDR_GENERAL_CAPABILITY_SET;
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct _CLIPRDR_CAPABILITIES {
|
||||
pub connID: UINT32,
|
||||
pub msgType: UINT16,
|
||||
pub msgFlags: UINT16,
|
||||
pub dataLen: UINT32,
|
||||
pub cCapabilitiesSets: UINT32,
|
||||
pub capabilitySets: *mut CLIPRDR_CAPABILITY_SET,
|
||||
}
|
||||
pub type CLIPRDR_CAPABILITIES = _CLIPRDR_CAPABILITIES;
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct _CLIPRDR_MONITOR_READY {
|
||||
pub connID: UINT32,
|
||||
pub msgType: UINT16,
|
||||
pub msgFlags: UINT16,
|
||||
pub dataLen: UINT32,
|
||||
}
|
||||
pub type CLIPRDR_MONITOR_READY = _CLIPRDR_MONITOR_READY;
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct _CLIPRDR_TEMP_DIRECTORY {
|
||||
pub connID: UINT32,
|
||||
pub msgType: UINT16,
|
||||
pub msgFlags: UINT16,
|
||||
pub dataLen: UINT32,
|
||||
pub szTempDir: [::std::os::raw::c_char; 520usize],
|
||||
}
|
||||
pub type CLIPRDR_TEMP_DIRECTORY = _CLIPRDR_TEMP_DIRECTORY;
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct _CLIPRDR_FORMAT {
|
||||
pub formatId: UINT32,
|
||||
pub formatName: *mut ::std::os::raw::c_char,
|
||||
}
|
||||
pub type CLIPRDR_FORMAT = _CLIPRDR_FORMAT;
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct _CLIPRDR_FORMAT_LIST {
|
||||
pub connID: UINT32,
|
||||
pub msgType: UINT16,
|
||||
pub msgFlags: UINT16,
|
||||
pub dataLen: UINT32,
|
||||
pub numFormats: UINT32,
|
||||
pub formats: *mut CLIPRDR_FORMAT,
|
||||
}
|
||||
pub type CLIPRDR_FORMAT_LIST = _CLIPRDR_FORMAT_LIST;
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct _CLIPRDR_FORMAT_LIST_RESPONSE {
|
||||
pub connID: UINT32,
|
||||
pub msgType: UINT16,
|
||||
pub msgFlags: UINT16,
|
||||
pub dataLen: UINT32,
|
||||
}
|
||||
pub type CLIPRDR_FORMAT_LIST_RESPONSE = _CLIPRDR_FORMAT_LIST_RESPONSE;
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct _CLIPRDR_LOCK_CLIPBOARD_DATA {
|
||||
pub connID: UINT32,
|
||||
pub msgType: UINT16,
|
||||
pub msgFlags: UINT16,
|
||||
pub dataLen: UINT32,
|
||||
pub clipDataId: UINT32,
|
||||
}
|
||||
pub type CLIPRDR_LOCK_CLIPBOARD_DATA = _CLIPRDR_LOCK_CLIPBOARD_DATA;
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct _CLIPRDR_UNLOCK_CLIPBOARD_DATA {
|
||||
pub connID: UINT32,
|
||||
pub msgType: UINT16,
|
||||
pub msgFlags: UINT16,
|
||||
pub dataLen: UINT32,
|
||||
pub clipDataId: UINT32,
|
||||
}
|
||||
pub type CLIPRDR_UNLOCK_CLIPBOARD_DATA = _CLIPRDR_UNLOCK_CLIPBOARD_DATA;
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct _CLIPRDR_FORMAT_DATA_REQUEST {
|
||||
pub connID: UINT32,
|
||||
pub msgType: UINT16,
|
||||
pub msgFlags: UINT16,
|
||||
pub dataLen: UINT32,
|
||||
pub requestedFormatId: UINT32,
|
||||
}
|
||||
pub type CLIPRDR_FORMAT_DATA_REQUEST = _CLIPRDR_FORMAT_DATA_REQUEST;
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct _CLIPRDR_FORMAT_DATA_RESPONSE {
|
||||
pub connID: UINT32,
|
||||
pub msgType: UINT16,
|
||||
pub msgFlags: UINT16,
|
||||
pub dataLen: UINT32,
|
||||
pub requestedFormatData: *const BYTE,
|
||||
}
|
||||
pub type CLIPRDR_FORMAT_DATA_RESPONSE = _CLIPRDR_FORMAT_DATA_RESPONSE;
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct _CLIPRDR_FILE_CONTENTS_REQUEST {
|
||||
pub connID: UINT32,
|
||||
pub msgType: UINT16,
|
||||
pub msgFlags: UINT16,
|
||||
pub dataLen: UINT32,
|
||||
pub streamId: UINT32,
|
||||
pub listIndex: UINT32,
|
||||
pub dwFlags: UINT32,
|
||||
pub nPositionLow: UINT32,
|
||||
pub nPositionHigh: UINT32,
|
||||
pub cbRequested: UINT32,
|
||||
pub haveClipDataId: BOOL,
|
||||
pub clipDataId: UINT32,
|
||||
}
|
||||
pub type CLIPRDR_FILE_CONTENTS_REQUEST = _CLIPRDR_FILE_CONTENTS_REQUEST;
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct _CLIPRDR_FILE_CONTENTS_RESPONSE {
|
||||
pub connID: UINT32,
|
||||
pub msgType: UINT16,
|
||||
pub msgFlags: UINT16,
|
||||
pub dataLen: UINT32,
|
||||
pub streamId: UINT32,
|
||||
pub cbRequested: UINT32,
|
||||
pub requestedData: *const BYTE,
|
||||
}
|
||||
pub type CLIPRDR_FILE_CONTENTS_RESPONSE = _CLIPRDR_FILE_CONTENTS_RESPONSE;
|
||||
pub type CliprdrClientContext = _cliprdr_client_context;
|
||||
pub type pcCliprdrServerCapabilities = ::std::option::Option<
|
||||
unsafe extern "C" fn(
|
||||
context: *mut CliprdrClientContext,
|
||||
capabilities: *const CLIPRDR_CAPABILITIES,
|
||||
) -> UINT,
|
||||
>;
|
||||
pub type pcCliprdrClientCapabilities = ::std::option::Option<
|
||||
unsafe extern "C" fn(
|
||||
context: *mut CliprdrClientContext,
|
||||
capabilities: *const CLIPRDR_CAPABILITIES,
|
||||
) -> UINT,
|
||||
>;
|
||||
pub type pcCliprdrMonitorReady = ::std::option::Option<
|
||||
unsafe extern "C" fn(
|
||||
context: *mut CliprdrClientContext,
|
||||
monitorReady: *const CLIPRDR_MONITOR_READY,
|
||||
) -> UINT,
|
||||
>;
|
||||
pub type pcCliprdrTempDirectory = ::std::option::Option<
|
||||
unsafe extern "C" fn(
|
||||
context: *mut CliprdrClientContext,
|
||||
tempDirectory: *const CLIPRDR_TEMP_DIRECTORY,
|
||||
) -> UINT,
|
||||
>;
|
||||
pub type pcCliprdrClientFormatList = ::std::option::Option<
|
||||
unsafe extern "C" fn(
|
||||
context: *mut CliprdrClientContext,
|
||||
formatList: *const CLIPRDR_FORMAT_LIST,
|
||||
) -> UINT,
|
||||
>;
|
||||
pub type pcCliprdrServerFormatList = ::std::option::Option<
|
||||
unsafe extern "C" fn(
|
||||
context: *mut CliprdrClientContext,
|
||||
formatList: *const CLIPRDR_FORMAT_LIST,
|
||||
) -> UINT,
|
||||
>;
|
||||
pub type pcCliprdrClientFormatListResponse = ::std::option::Option<
|
||||
unsafe extern "C" fn(
|
||||
context: *mut CliprdrClientContext,
|
||||
formatListResponse: *const CLIPRDR_FORMAT_LIST_RESPONSE,
|
||||
) -> UINT,
|
||||
>;
|
||||
pub type pcCliprdrServerFormatListResponse = ::std::option::Option<
|
||||
unsafe extern "C" fn(
|
||||
context: *mut CliprdrClientContext,
|
||||
formatListResponse: *const CLIPRDR_FORMAT_LIST_RESPONSE,
|
||||
) -> UINT,
|
||||
>;
|
||||
pub type pcCliprdrClientLockClipboardData = ::std::option::Option<
|
||||
unsafe extern "C" fn(
|
||||
context: *mut CliprdrClientContext,
|
||||
lockClipboardData: *const CLIPRDR_LOCK_CLIPBOARD_DATA,
|
||||
) -> UINT,
|
||||
>;
|
||||
pub type pcCliprdrServerLockClipboardData = ::std::option::Option<
|
||||
unsafe extern "C" fn(
|
||||
context: *mut CliprdrClientContext,
|
||||
lockClipboardData: *const CLIPRDR_LOCK_CLIPBOARD_DATA,
|
||||
) -> UINT,
|
||||
>;
|
||||
pub type pcCliprdrClientUnlockClipboardData = ::std::option::Option<
|
||||
unsafe extern "C" fn(
|
||||
context: *mut CliprdrClientContext,
|
||||
unlockClipboardData: *const CLIPRDR_UNLOCK_CLIPBOARD_DATA,
|
||||
) -> UINT,
|
||||
>;
|
||||
pub type pcCliprdrServerUnlockClipboardData = ::std::option::Option<
|
||||
unsafe extern "C" fn(
|
||||
context: *mut CliprdrClientContext,
|
||||
unlockClipboardData: *const CLIPRDR_UNLOCK_CLIPBOARD_DATA,
|
||||
) -> UINT,
|
||||
>;
|
||||
pub type pcCliprdrClientFormatDataRequest = ::std::option::Option<
|
||||
unsafe extern "C" fn(
|
||||
context: *mut CliprdrClientContext,
|
||||
formatDataRequest: *const CLIPRDR_FORMAT_DATA_REQUEST,
|
||||
) -> UINT,
|
||||
>;
|
||||
pub type pcCliprdrServerFormatDataRequest = ::std::option::Option<
|
||||
unsafe extern "C" fn(
|
||||
context: *mut CliprdrClientContext,
|
||||
formatDataRequest: *const CLIPRDR_FORMAT_DATA_REQUEST,
|
||||
) -> UINT,
|
||||
>;
|
||||
pub type pcCliprdrClientFormatDataResponse = ::std::option::Option<
|
||||
unsafe extern "C" fn(
|
||||
context: *mut CliprdrClientContext,
|
||||
formatDataResponse: *const CLIPRDR_FORMAT_DATA_RESPONSE,
|
||||
) -> UINT,
|
||||
>;
|
||||
pub type pcCliprdrServerFormatDataResponse = ::std::option::Option<
|
||||
unsafe extern "C" fn(
|
||||
context: *mut CliprdrClientContext,
|
||||
formatDataResponse: *const CLIPRDR_FORMAT_DATA_RESPONSE,
|
||||
) -> UINT,
|
||||
>;
|
||||
pub type pcCliprdrClientFileContentsRequest = ::std::option::Option<
|
||||
unsafe extern "C" fn(
|
||||
context: *mut CliprdrClientContext,
|
||||
fileContentsRequest: *const CLIPRDR_FILE_CONTENTS_REQUEST,
|
||||
) -> UINT,
|
||||
>;
|
||||
pub type pcCliprdrServerFileContentsRequest = ::std::option::Option<
|
||||
unsafe extern "C" fn(
|
||||
context: *mut CliprdrClientContext,
|
||||
fileContentsRequest: *const CLIPRDR_FILE_CONTENTS_REQUEST,
|
||||
) -> UINT,
|
||||
>;
|
||||
pub type pcCliprdrClientFileContentsResponse = ::std::option::Option<
|
||||
unsafe extern "C" fn(
|
||||
context: *mut CliprdrClientContext,
|
||||
fileContentsResponse: *const CLIPRDR_FILE_CONTENTS_RESPONSE,
|
||||
) -> UINT,
|
||||
>;
|
||||
pub type pcCliprdrServerFileContentsResponse = ::std::option::Option<
|
||||
unsafe extern "C" fn(
|
||||
context: *mut CliprdrClientContext,
|
||||
fileContentsResponse: *const CLIPRDR_FILE_CONTENTS_RESPONSE,
|
||||
) -> UINT,
|
||||
>;
|
||||
pub type pcCheckEnabled = ::std::option::Option<
|
||||
unsafe extern "C" fn(connID: UINT32) -> BOOL,
|
||||
>;
|
||||
|
||||
// TODO: hide more members of clipboard context
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct _cliprdr_client_context {
|
||||
pub custom: *mut ::std::os::raw::c_void,
|
||||
pub enableFiles: BOOL,
|
||||
pub enableOthers: BOOL,
|
||||
pub CheckEnabled: pcCheckEnabled,
|
||||
pub ServerCapabilities: pcCliprdrServerCapabilities,
|
||||
pub ClientCapabilities: pcCliprdrClientCapabilities,
|
||||
pub MonitorReady: pcCliprdrMonitorReady,
|
||||
pub TempDirectory: pcCliprdrTempDirectory,
|
||||
pub ClientFormatList: pcCliprdrClientFormatList,
|
||||
pub ServerFormatList: pcCliprdrServerFormatList,
|
||||
pub ClientFormatListResponse: pcCliprdrClientFormatListResponse,
|
||||
pub ServerFormatListResponse: pcCliprdrServerFormatListResponse,
|
||||
pub ClientLockClipboardData: pcCliprdrClientLockClipboardData,
|
||||
pub ServerLockClipboardData: pcCliprdrServerLockClipboardData,
|
||||
pub ClientUnlockClipboardData: pcCliprdrClientUnlockClipboardData,
|
||||
pub ServerUnlockClipboardData: pcCliprdrServerUnlockClipboardData,
|
||||
pub ClientFormatDataRequest: pcCliprdrClientFormatDataRequest,
|
||||
pub ServerFormatDataRequest: pcCliprdrServerFormatDataRequest,
|
||||
pub ClientFormatDataResponse: pcCliprdrClientFormatDataResponse,
|
||||
pub ServerFormatDataResponse: pcCliprdrServerFormatDataResponse,
|
||||
pub ClientFileContentsRequest: pcCliprdrClientFileContentsRequest,
|
||||
pub ServerFileContentsRequest: pcCliprdrServerFileContentsRequest,
|
||||
pub ClientFileContentsResponse: pcCliprdrClientFileContentsResponse,
|
||||
pub ServerFileContentsResponse: pcCliprdrServerFileContentsResponse,
|
||||
pub lastRequestedFormatId: UINT32,
|
||||
}
|
||||
|
||||
// #[link(name = "user32")]
|
||||
// #[link(name = "ole32")]
|
||||
extern "C" {
|
||||
pub(crate) fn init_cliprdr(context: *mut CliprdrClientContext) -> BOOL;
|
||||
pub(crate) fn uninit_cliprdr(context: *mut CliprdrClientContext) -> BOOL;
|
||||
pub(crate) fn empty_cliprdr(
|
||||
context: *mut CliprdrClientContext,
|
||||
connID: UINT32,
|
||||
) -> BOOL;
|
||||
}
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum CliprdrError {
|
||||
#[error("invalid cliprdr name")]
|
||||
CliprdrName,
|
||||
#[error("failed to init cliprdr")]
|
||||
CliprdrInit,
|
||||
#[error("unknown cliprdr error")]
|
||||
Unknown,
|
||||
}
|
||||
|
||||
impl CliprdrClientContext {
|
||||
pub fn create(
|
||||
enable_files: bool,
|
||||
enable_others: bool,
|
||||
check_enabled: pcCheckEnabled,
|
||||
client_format_list: pcCliprdrClientFormatList,
|
||||
client_format_list_response: pcCliprdrClientFormatListResponse,
|
||||
client_format_data_request: pcCliprdrClientFormatDataRequest,
|
||||
client_format_data_response: pcCliprdrClientFormatDataResponse,
|
||||
client_file_contents_request: pcCliprdrClientFileContentsRequest,
|
||||
client_file_contents_response: pcCliprdrClientFileContentsResponse,
|
||||
) -> Result<Box<Self>, CliprdrError> {
|
||||
let context = CliprdrClientContext {
|
||||
custom: 0 as *mut _,
|
||||
enableFiles: if enable_files { TRUE } else { FALSE },
|
||||
enableOthers: if enable_others { TRUE } else { FALSE },
|
||||
CheckEnabled: check_enabled,
|
||||
ServerCapabilities: None,
|
||||
ClientCapabilities: None,
|
||||
MonitorReady: None,
|
||||
TempDirectory: None,
|
||||
ClientFormatList: client_format_list,
|
||||
ServerFormatList: None,
|
||||
ClientFormatListResponse: client_format_list_response,
|
||||
ServerFormatListResponse: None,
|
||||
ClientLockClipboardData: None,
|
||||
ServerLockClipboardData: None,
|
||||
ClientUnlockClipboardData: None,
|
||||
ServerUnlockClipboardData: None,
|
||||
ClientFormatDataRequest: client_format_data_request,
|
||||
ServerFormatDataRequest: None,
|
||||
ClientFormatDataResponse: client_format_data_response,
|
||||
ServerFormatDataResponse: None,
|
||||
ClientFileContentsRequest: client_file_contents_request,
|
||||
ServerFileContentsRequest: None,
|
||||
ClientFileContentsResponse: client_file_contents_response,
|
||||
ServerFileContentsResponse: None,
|
||||
lastRequestedFormatId: 0,
|
||||
};
|
||||
let mut context = Box::new(context);
|
||||
unsafe {
|
||||
if FALSE == init_cliprdr(&mut (*context)) {
|
||||
println!("Failed to init cliprdr");
|
||||
Err(CliprdrError::CliprdrInit)
|
||||
} else {
|
||||
Ok(context)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for CliprdrClientContext {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
if FALSE == uninit_cliprdr(&mut *self) {
|
||||
println!("Failed to uninit cliprdr");
|
||||
} else {
|
||||
println!("Succeeded to uninit cliprdr");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
605
libs/clipboard/src/lib.rs
Normal file
605
libs/clipboard/src/lib.rs
Normal file
@@ -0,0 +1,605 @@
|
||||
use cliprdr::*;
|
||||
use hbb_common::{
|
||||
log,
|
||||
tokio::sync::{
|
||||
mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender},
|
||||
Mutex as TokioMutex,
|
||||
},
|
||||
ResultType,
|
||||
};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use std::{
|
||||
boxed::Box,
|
||||
collections::HashMap,
|
||||
ffi::{CStr, CString},
|
||||
sync::Mutex,
|
||||
};
|
||||
|
||||
pub mod cliprdr;
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
#[serde(tag = "t", content = "c")]
|
||||
pub enum ClipbaordFile {
|
||||
ServerFormatList {
|
||||
conn_id: i32,
|
||||
format_list: Vec<(i32, String)>,
|
||||
},
|
||||
ServerFormatListResponse {
|
||||
conn_id: i32,
|
||||
msg_flags: i32,
|
||||
},
|
||||
ServerFormatDataRequest {
|
||||
conn_id: i32,
|
||||
requested_format_id: i32,
|
||||
},
|
||||
ServerFormatDataResponse {
|
||||
conn_id: i32,
|
||||
msg_flags: i32,
|
||||
format_data: Vec<u8>,
|
||||
},
|
||||
FileContentsRequest {
|
||||
conn_id: i32,
|
||||
stream_id: i32,
|
||||
list_index: i32,
|
||||
dw_flags: i32,
|
||||
n_position_low: i32,
|
||||
n_position_high: i32,
|
||||
cb_requested: i32,
|
||||
have_clip_data_id: bool,
|
||||
clip_data_id: i32,
|
||||
},
|
||||
FileContentsResponse {
|
||||
conn_id: i32,
|
||||
msg_flags: i32,
|
||||
stream_id: i32,
|
||||
requested_data: Vec<u8>,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct ConnEnabled {
|
||||
conn_enabled: HashMap<i32, bool>,
|
||||
}
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
static ref MSG_CHANNEL_CLIENT: (UnboundedSender<(i32, ClipbaordFile)>, TokioMutex<UnboundedReceiver<(i32, ClipbaordFile)>>) = {
|
||||
let (tx, rx) = unbounded_channel();
|
||||
(tx, TokioMutex::new(rx))
|
||||
};
|
||||
|
||||
static ref CLIP_CONN_ENABLED: Mutex<ConnEnabled> = Mutex::new(ConnEnabled::default());
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn get_rx_clip_client<'a>() -> &'a TokioMutex<UnboundedReceiver<(i32, ClipbaordFile)>> {
|
||||
&MSG_CHANNEL_CLIENT.1
|
||||
}
|
||||
|
||||
pub fn set_conn_enabled(conn_id: i32, enabled: bool) {
|
||||
let mut lock = CLIP_CONN_ENABLED.lock().unwrap();
|
||||
if conn_id != 0 {
|
||||
let _ = lock.conn_enabled.insert(conn_id, enabled);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn empty_clipboard(context: &mut Box<CliprdrClientContext>, conn_id: i32) -> bool {
|
||||
unsafe { TRUE == cliprdr::empty_cliprdr(&mut (**context), conn_id as u32) }
|
||||
}
|
||||
|
||||
pub fn server_clip_file(
|
||||
context: &mut Box<CliprdrClientContext>,
|
||||
s_conn_id: i32,
|
||||
msg: ClipbaordFile,
|
||||
) -> u32 {
|
||||
match msg {
|
||||
ClipbaordFile::ServerFormatList {
|
||||
mut conn_id,
|
||||
format_list,
|
||||
} => {
|
||||
if s_conn_id != 0 {
|
||||
conn_id = s_conn_id as i32;
|
||||
}
|
||||
log::debug!("server_format_list called");
|
||||
let ret = server_format_list(context, conn_id, format_list);
|
||||
log::debug!("server_format_list called, return {}", ret);
|
||||
ret
|
||||
}
|
||||
ClipbaordFile::ServerFormatListResponse {
|
||||
mut conn_id,
|
||||
msg_flags,
|
||||
} => {
|
||||
if s_conn_id != 0 {
|
||||
conn_id = s_conn_id as i32;
|
||||
}
|
||||
log::debug!("format_list_response called");
|
||||
let ret = server_format_list_response(context, conn_id, msg_flags);
|
||||
log::debug!("server_format_list_response called, return {}", ret);
|
||||
ret
|
||||
}
|
||||
ClipbaordFile::ServerFormatDataRequest {
|
||||
mut conn_id,
|
||||
requested_format_id,
|
||||
} => {
|
||||
if s_conn_id != 0 {
|
||||
conn_id = s_conn_id as i32;
|
||||
}
|
||||
log::debug!("format_data_request called");
|
||||
let ret = server_format_data_request(context, conn_id, requested_format_id);
|
||||
log::debug!("server_format_data_request called, return {}", ret);
|
||||
ret
|
||||
}
|
||||
ClipbaordFile::ServerFormatDataResponse {
|
||||
mut conn_id,
|
||||
msg_flags,
|
||||
format_data,
|
||||
} => {
|
||||
if s_conn_id != 0 {
|
||||
conn_id = s_conn_id as i32;
|
||||
}
|
||||
log::debug!("format_data_response called");
|
||||
let ret = server_format_data_response(context, conn_id, msg_flags, format_data);
|
||||
log::debug!("server_format_data_response called, return {}", ret);
|
||||
ret
|
||||
}
|
||||
ClipbaordFile::FileContentsRequest {
|
||||
mut conn_id,
|
||||
stream_id,
|
||||
list_index,
|
||||
dw_flags,
|
||||
n_position_low,
|
||||
n_position_high,
|
||||
cb_requested,
|
||||
have_clip_data_id,
|
||||
clip_data_id,
|
||||
} => {
|
||||
if s_conn_id != 0 {
|
||||
conn_id = s_conn_id as i32;
|
||||
}
|
||||
log::debug!("file_contents_request called");
|
||||
let ret = server_file_contents_request(
|
||||
context,
|
||||
conn_id,
|
||||
stream_id,
|
||||
list_index,
|
||||
dw_flags,
|
||||
n_position_low,
|
||||
n_position_high,
|
||||
cb_requested,
|
||||
have_clip_data_id,
|
||||
clip_data_id,
|
||||
);
|
||||
log::debug!("server_file_contents_request called, return {}", ret);
|
||||
ret
|
||||
}
|
||||
ClipbaordFile::FileContentsResponse {
|
||||
mut conn_id,
|
||||
msg_flags,
|
||||
stream_id,
|
||||
requested_data,
|
||||
} => {
|
||||
if s_conn_id != 0 {
|
||||
conn_id = s_conn_id as i32;
|
||||
}
|
||||
log::debug!("file_contents_response called");
|
||||
let ret = server_file_contents_response(
|
||||
context,
|
||||
conn_id,
|
||||
msg_flags,
|
||||
stream_id,
|
||||
requested_data,
|
||||
);
|
||||
log::debug!("server_file_contents_response called, return {}", ret);
|
||||
ret
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn server_format_list(
|
||||
context: &mut Box<CliprdrClientContext>,
|
||||
conn_id: i32,
|
||||
format_list: Vec<(i32, String)>,
|
||||
) -> u32 {
|
||||
unsafe {
|
||||
let num_formats = format_list.len() as UINT32;
|
||||
let mut formats = format_list
|
||||
.into_iter()
|
||||
.map(|format| {
|
||||
if format.1.is_empty() {
|
||||
CLIPRDR_FORMAT {
|
||||
formatId: format.0 as UINT32,
|
||||
formatName: 0 as *mut _,
|
||||
}
|
||||
} else {
|
||||
let n = match CString::new(format.1) {
|
||||
Ok(n) => n,
|
||||
Err(_) => CString::new("").unwrap(),
|
||||
};
|
||||
CLIPRDR_FORMAT {
|
||||
formatId: format.0 as UINT32,
|
||||
formatName: n.into_raw(),
|
||||
}
|
||||
}
|
||||
})
|
||||
.collect::<Vec<CLIPRDR_FORMAT>>();
|
||||
|
||||
let format_list = CLIPRDR_FORMAT_LIST {
|
||||
connID: conn_id as UINT32,
|
||||
msgType: 0 as UINT16,
|
||||
msgFlags: 0 as UINT16,
|
||||
dataLen: 0 as UINT32,
|
||||
numFormats: num_formats,
|
||||
formats: formats.as_mut_ptr(),
|
||||
};
|
||||
|
||||
let ret = ((**context).ServerFormatList.unwrap())(&mut (**context), &format_list);
|
||||
|
||||
for f in formats {
|
||||
if !f.formatName.is_null() {
|
||||
// retake pointer to free memory
|
||||
let _ = CString::from_raw(f.formatName);
|
||||
}
|
||||
}
|
||||
|
||||
ret as u32
|
||||
}
|
||||
}
|
||||
pub fn server_format_list_response(
|
||||
context: &mut Box<CliprdrClientContext>,
|
||||
conn_id: i32,
|
||||
msg_flags: i32,
|
||||
) -> u32 {
|
||||
unsafe {
|
||||
let format_list_response = CLIPRDR_FORMAT_LIST_RESPONSE {
|
||||
connID: conn_id as UINT32,
|
||||
msgType: 0 as UINT16,
|
||||
msgFlags: msg_flags as UINT16,
|
||||
dataLen: 0 as UINT32,
|
||||
};
|
||||
|
||||
let ret =
|
||||
(**context).ServerFormatListResponse.unwrap()(&mut (**context), &format_list_response);
|
||||
|
||||
ret as u32
|
||||
}
|
||||
}
|
||||
pub fn server_format_data_request(
|
||||
context: &mut Box<CliprdrClientContext>,
|
||||
conn_id: i32,
|
||||
requested_format_id: i32,
|
||||
) -> u32 {
|
||||
unsafe {
|
||||
let format_data_request = CLIPRDR_FORMAT_DATA_REQUEST {
|
||||
connID: conn_id as UINT32,
|
||||
msgType: 0 as UINT16,
|
||||
msgFlags: 0 as UINT16,
|
||||
dataLen: 0 as UINT32,
|
||||
requestedFormatId: requested_format_id as UINT32,
|
||||
};
|
||||
let ret =
|
||||
((**context).ServerFormatDataRequest.unwrap())(&mut (**context), &format_data_request);
|
||||
ret as u32
|
||||
}
|
||||
}
|
||||
pub fn server_format_data_response(
|
||||
context: &mut Box<CliprdrClientContext>,
|
||||
conn_id: i32,
|
||||
msg_flags: i32,
|
||||
mut format_data: Vec<u8>,
|
||||
) -> u32 {
|
||||
unsafe {
|
||||
let format_data_response = CLIPRDR_FORMAT_DATA_RESPONSE {
|
||||
connID: conn_id as UINT32,
|
||||
msgType: 0 as UINT16,
|
||||
msgFlags: msg_flags as UINT16,
|
||||
dataLen: format_data.len() as UINT32,
|
||||
requestedFormatData: format_data.as_mut_ptr(),
|
||||
};
|
||||
let ret = ((**context).ServerFormatDataResponse.unwrap())(
|
||||
&mut (**context),
|
||||
&format_data_response,
|
||||
);
|
||||
ret as u32
|
||||
}
|
||||
}
|
||||
pub fn server_file_contents_request(
|
||||
context: &mut Box<CliprdrClientContext>,
|
||||
conn_id: i32,
|
||||
stream_id: i32,
|
||||
list_index: i32,
|
||||
dw_flags: i32,
|
||||
n_position_low: i32,
|
||||
n_position_high: i32,
|
||||
cb_requested: i32,
|
||||
have_clip_data_id: bool,
|
||||
clip_data_id: i32,
|
||||
) -> u32 {
|
||||
unsafe {
|
||||
let file_contents_request = CLIPRDR_FILE_CONTENTS_REQUEST {
|
||||
connID: conn_id as UINT32,
|
||||
msgType: 0 as UINT16,
|
||||
msgFlags: 0 as UINT16,
|
||||
dataLen: 0 as UINT32,
|
||||
streamId: stream_id as UINT32,
|
||||
listIndex: list_index as UINT32,
|
||||
dwFlags: dw_flags as UINT32,
|
||||
nPositionLow: n_position_low as UINT32,
|
||||
nPositionHigh: n_position_high as UINT32,
|
||||
cbRequested: cb_requested as UINT32,
|
||||
haveClipDataId: if have_clip_data_id { TRUE } else { FALSE },
|
||||
clipDataId: clip_data_id as UINT32,
|
||||
};
|
||||
let ret = ((**context).ServerFileContentsRequest.unwrap())(
|
||||
&mut (**context),
|
||||
&file_contents_request,
|
||||
);
|
||||
ret as u32
|
||||
}
|
||||
}
|
||||
pub fn server_file_contents_response(
|
||||
context: &mut Box<CliprdrClientContext>,
|
||||
conn_id: i32,
|
||||
msg_flags: i32,
|
||||
stream_id: i32,
|
||||
mut requested_data: Vec<u8>,
|
||||
) -> u32 {
|
||||
unsafe {
|
||||
let file_contents_response = CLIPRDR_FILE_CONTENTS_RESPONSE {
|
||||
connID: conn_id as UINT32,
|
||||
msgType: 0 as UINT16,
|
||||
msgFlags: msg_flags as UINT16,
|
||||
dataLen: 4 + requested_data.len() as UINT32,
|
||||
streamId: stream_id as UINT32,
|
||||
cbRequested: requested_data.len() as UINT32,
|
||||
requestedData: requested_data.as_mut_ptr(),
|
||||
};
|
||||
let ret = ((**context).ServerFileContentsResponse.unwrap())(
|
||||
&mut (**context),
|
||||
&file_contents_response,
|
||||
);
|
||||
ret as u32
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_cliprdr_context(
|
||||
enable_files: bool,
|
||||
enable_others: bool,
|
||||
) -> ResultType<Box<CliprdrClientContext>> {
|
||||
Ok(CliprdrClientContext::create(
|
||||
enable_files,
|
||||
enable_others,
|
||||
Some(check_enabled),
|
||||
Some(client_format_list),
|
||||
Some(client_format_list_response),
|
||||
Some(client_format_data_request),
|
||||
Some(client_format_data_response),
|
||||
Some(client_file_contents_request),
|
||||
Some(client_file_contents_response),
|
||||
)?)
|
||||
}
|
||||
|
||||
extern "C" fn check_enabled(conn_id: UINT32) -> BOOL {
|
||||
let lock = CLIP_CONN_ENABLED.lock().unwrap();
|
||||
|
||||
let mut connd_enabled = false;
|
||||
if conn_id != 0 {
|
||||
if let Some(true) = lock.conn_enabled.get(&(conn_id as i32)) {
|
||||
connd_enabled = true;
|
||||
}
|
||||
} else {
|
||||
connd_enabled = true;
|
||||
}
|
||||
|
||||
return if connd_enabled { TRUE } else { FALSE };
|
||||
}
|
||||
|
||||
extern "C" fn client_format_list(
|
||||
_context: *mut CliprdrClientContext,
|
||||
clip_format_list: *const CLIPRDR_FORMAT_LIST,
|
||||
) -> UINT {
|
||||
log::debug!("client_format_list called");
|
||||
|
||||
let conn_id;
|
||||
let mut format_list: Vec<(i32, String)> = Vec::new();
|
||||
unsafe {
|
||||
let mut i = 0u32;
|
||||
while i < (*clip_format_list).numFormats {
|
||||
let format_data = &(*(*clip_format_list).formats.offset(i as isize));
|
||||
if format_data.formatName.is_null() {
|
||||
format_list.push((format_data.formatId as i32, "".to_owned()));
|
||||
} else {
|
||||
let format_name = CStr::from_ptr(format_data.formatName).to_str();
|
||||
let format_name = match format_name {
|
||||
Ok(n) => n.to_owned(),
|
||||
Err(_) => {
|
||||
log::warn!("failed to get format name");
|
||||
"".to_owned()
|
||||
}
|
||||
};
|
||||
format_list.push((format_data.formatId as i32, format_name));
|
||||
}
|
||||
// log::debug!("format list item {}: format id: {}, format name: {}", i, format_data.formatId, &format_name);
|
||||
i += 1;
|
||||
}
|
||||
conn_id = (*clip_format_list).connID as i32;
|
||||
}
|
||||
let data = ClipbaordFile::ServerFormatList {
|
||||
conn_id,
|
||||
format_list,
|
||||
};
|
||||
// no need to handle result here
|
||||
MSG_CHANNEL_CLIENT.0.send((conn_id, data)).unwrap();
|
||||
|
||||
0
|
||||
}
|
||||
|
||||
extern "C" fn client_format_list_response(
|
||||
_context: *mut CliprdrClientContext,
|
||||
format_list_response: *const CLIPRDR_FORMAT_LIST_RESPONSE,
|
||||
) -> UINT {
|
||||
log::debug!("client_format_list_response called");
|
||||
|
||||
let conn_id;
|
||||
let msg_flags;
|
||||
unsafe {
|
||||
conn_id = (*format_list_response).connID as i32;
|
||||
msg_flags = (*format_list_response).msgFlags as i32;
|
||||
}
|
||||
let data = ClipbaordFile::ServerFormatListResponse { conn_id, msg_flags };
|
||||
// no need to handle result here
|
||||
MSG_CHANNEL_CLIENT.0.send((conn_id, data)).unwrap();
|
||||
|
||||
0
|
||||
}
|
||||
|
||||
extern "C" fn client_format_data_request(
|
||||
_context: *mut CliprdrClientContext,
|
||||
format_data_request: *const CLIPRDR_FORMAT_DATA_REQUEST,
|
||||
) -> UINT {
|
||||
log::debug!("client_format_data_request called");
|
||||
|
||||
let conn_id;
|
||||
let requested_format_id;
|
||||
unsafe {
|
||||
conn_id = (*format_data_request).connID as i32;
|
||||
requested_format_id = (*format_data_request).requestedFormatId as i32;
|
||||
}
|
||||
let data = ClipbaordFile::ServerFormatDataRequest {
|
||||
conn_id,
|
||||
requested_format_id,
|
||||
};
|
||||
// no need to handle result here
|
||||
MSG_CHANNEL_CLIENT.0.send((conn_id, data)).unwrap();
|
||||
|
||||
0
|
||||
}
|
||||
|
||||
extern "C" fn client_format_data_response(
|
||||
_context: *mut CliprdrClientContext,
|
||||
format_data_response: *const CLIPRDR_FORMAT_DATA_RESPONSE,
|
||||
) -> UINT {
|
||||
log::debug!("cconn_idlient_format_data_response called");
|
||||
|
||||
let conn_id;
|
||||
let msg_flags;
|
||||
let format_data;
|
||||
unsafe {
|
||||
conn_id = (*format_data_response).connID as i32;
|
||||
msg_flags = (*format_data_response).msgFlags as i32;
|
||||
if (*format_data_response).requestedFormatData.is_null() {
|
||||
format_data = Vec::new();
|
||||
} else {
|
||||
format_data = std::slice::from_raw_parts(
|
||||
(*format_data_response).requestedFormatData,
|
||||
(*format_data_response).dataLen as usize,
|
||||
)
|
||||
.to_vec();
|
||||
}
|
||||
}
|
||||
let data = ClipbaordFile::ServerFormatDataResponse {
|
||||
conn_id,
|
||||
msg_flags,
|
||||
format_data,
|
||||
};
|
||||
// no need to handle result here
|
||||
MSG_CHANNEL_CLIENT.0.send((conn_id, data)).unwrap();
|
||||
|
||||
0
|
||||
}
|
||||
|
||||
extern "C" fn client_file_contents_request(
|
||||
_context: *mut CliprdrClientContext,
|
||||
file_contents_request: *const CLIPRDR_FILE_CONTENTS_REQUEST,
|
||||
) -> UINT {
|
||||
log::debug!("client_file_contents_request called");
|
||||
|
||||
// TODO: support huge file?
|
||||
// if (!cliprdr->hasHugeFileSupport)
|
||||
// {
|
||||
// if (((UINT64)fileContentsRequest->cbRequested + fileContentsRequest->nPositionLow) >
|
||||
// UINT32_MAX)
|
||||
// return ERROR_INVALID_PARAMETER;
|
||||
// if (fileContentsRequest->nPositionHigh != 0)
|
||||
// return ERROR_INVALID_PARAMETER;
|
||||
// }
|
||||
|
||||
let conn_id;
|
||||
let stream_id;
|
||||
let list_index;
|
||||
let dw_flags;
|
||||
let n_position_low;
|
||||
let n_position_high;
|
||||
let cb_requested;
|
||||
let have_clip_data_id;
|
||||
let clip_data_id;
|
||||
unsafe {
|
||||
conn_id = (*file_contents_request).connID as i32;
|
||||
stream_id = (*file_contents_request).streamId as i32;
|
||||
list_index = (*file_contents_request).listIndex as i32;
|
||||
dw_flags = (*file_contents_request).dwFlags as i32;
|
||||
n_position_low = (*file_contents_request).nPositionLow as i32;
|
||||
n_position_high = (*file_contents_request).nPositionHigh as i32;
|
||||
cb_requested = (*file_contents_request).cbRequested as i32;
|
||||
have_clip_data_id = (*file_contents_request).haveClipDataId == TRUE;
|
||||
clip_data_id = (*file_contents_request).clipDataId as i32;
|
||||
}
|
||||
|
||||
let data = ClipbaordFile::FileContentsRequest {
|
||||
conn_id,
|
||||
stream_id,
|
||||
list_index,
|
||||
dw_flags,
|
||||
n_position_low,
|
||||
n_position_high,
|
||||
cb_requested,
|
||||
have_clip_data_id,
|
||||
clip_data_id,
|
||||
};
|
||||
// no need to handle result here
|
||||
MSG_CHANNEL_CLIENT.0.send((conn_id, data)).unwrap();
|
||||
|
||||
0
|
||||
}
|
||||
|
||||
extern "C" fn client_file_contents_response(
|
||||
_context: *mut CliprdrClientContext,
|
||||
file_contents_response: *const CLIPRDR_FILE_CONTENTS_RESPONSE,
|
||||
) -> UINT {
|
||||
log::debug!("client_file_contents_response called");
|
||||
|
||||
let conn_id;
|
||||
let msg_flags;
|
||||
let stream_id;
|
||||
let requested_data;
|
||||
unsafe {
|
||||
conn_id = (*file_contents_response).connID as i32;
|
||||
msg_flags = (*file_contents_response).msgFlags as i32;
|
||||
stream_id = (*file_contents_response).streamId as i32;
|
||||
if (*file_contents_response).requestedData.is_null() {
|
||||
requested_data = Vec::new();
|
||||
} else {
|
||||
requested_data = std::slice::from_raw_parts(
|
||||
(*file_contents_response).requestedData,
|
||||
(*file_contents_response).cbRequested as usize,
|
||||
)
|
||||
.to_vec();
|
||||
}
|
||||
}
|
||||
let data = ClipbaordFile::FileContentsResponse {
|
||||
conn_id,
|
||||
msg_flags,
|
||||
stream_id,
|
||||
requested_data,
|
||||
};
|
||||
// no need to handle result here
|
||||
MSG_CHANNEL_CLIENT.0.send((conn_id, data)).unwrap();
|
||||
|
||||
0
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
// #[test]
|
||||
// fn test_cliprdr_run() {
|
||||
// super::cliprdr_run();
|
||||
// }
|
||||
}
|
||||
3108
libs/clipboard/src/windows/wf_cliprdr.c
Normal file
3108
libs/clipboard/src/windows/wf_cliprdr.c
Normal file
File diff suppressed because it is too large
Load Diff
14
libs/confy/.gitignore
vendored
14
libs/confy/.gitignore
vendored
@@ -1,14 +0,0 @@
|
||||
# Generated by Cargo
|
||||
# will have compiled files and executables
|
||||
/target/
|
||||
|
||||
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
|
||||
# More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock
|
||||
Cargo.lock
|
||||
|
||||
# These are backup files generated by rustfmt
|
||||
**/*.rs.bk
|
||||
|
||||
/target
|
||||
**/*.rs.bk
|
||||
Cargo.lock
|
||||
@@ -1,26 +0,0 @@
|
||||
[package]
|
||||
name = "confy"
|
||||
version = "0.4.1"
|
||||
authors = ["Katharina Fey <kookie@spacekookie.de>"]
|
||||
description = "Boilerplate-free configuration management"
|
||||
license = "MIT/X11 OR Apache-2.0"
|
||||
documentation = "https://docs.rs/confy"
|
||||
repository = "https://github.com/rust-clique/confy"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
serde = "^1.0"
|
||||
toml = { version = "^0.5", optional = true }
|
||||
directories = "^2.0"
|
||||
serde_yaml = { version = "0.8", optional = true }
|
||||
|
||||
[features]
|
||||
default = ["toml_conf"]
|
||||
toml_conf = ["toml"]
|
||||
yaml_conf = ["serde_yaml"]
|
||||
|
||||
[[example]]
|
||||
name = "simple"
|
||||
|
||||
[dev-dependencies]
|
||||
serde_derive = "^1.0"
|
||||
@@ -1,21 +0,0 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018 rust-clique
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -1,39 +0,0 @@
|
||||
# confy
|
||||
|
||||
Chat with us: [Discord](https://discord.gg/dwq4Zme)
|
||||
|
||||
Zero-boilerplate configuration management.
|
||||
|
||||
Focus on storing the right data, instead of worrying about how or where to store it.
|
||||
|
||||
```rust
|
||||
use serde_derive::{Serialize, Deserialize};
|
||||
|
||||
#[derive(Default, Debug, Serialize, Deserialize)]
|
||||
struct MyConfig {
|
||||
version: u8,
|
||||
api_key: String,
|
||||
}
|
||||
|
||||
fn main() -> Result<(), ::std::io::Error> {
|
||||
let cfg: MyConfig = confy::load("my-app-name")?;
|
||||
dbg!(cfg);
|
||||
Ok(())
|
||||
}
|
||||
```
|
||||
|
||||
## Using yaml
|
||||
Enabling the `yaml_conf` feature while disabling the default `toml_conf`
|
||||
feature causes confy to use a YAML config file instead of TOML.
|
||||
|
||||
```
|
||||
[dependencies.confy]
|
||||
features = ["yaml_conf"]
|
||||
default-features = false
|
||||
```
|
||||
|
||||
## Breakings changes
|
||||
Starting with version 0.4.0 the configuration file are stored in the expected place for your system. See the [`directories`] crates for more information.
|
||||
Before version 0.4.0, the configuration file was written in the current directory.
|
||||
|
||||
[`directories`]: https://crates.io/crates/directories
|
||||
@@ -1,29 +0,0 @@
|
||||
//! The most simplest examples of how to use confy
|
||||
|
||||
extern crate confy;
|
||||
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
struct ConfyConfig {
|
||||
name: String,
|
||||
comfy: bool,
|
||||
foo: i64,
|
||||
}
|
||||
|
||||
impl Default for ConfyConfig {
|
||||
fn default() -> Self {
|
||||
ConfyConfig {
|
||||
name: "Unknown".to_string(),
|
||||
comfy: true,
|
||||
foo: 42,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() -> Result<(), confy::ConfyError> {
|
||||
let cfg: ConfyConfig = confy::load("confy_simple_app")?;
|
||||
println!("{:#?}", cfg);
|
||||
Ok(())
|
||||
}
|
||||
@@ -1,300 +0,0 @@
|
||||
//! Zero-boilerplate configuration management
|
||||
//!
|
||||
//! ## Why?
|
||||
//!
|
||||
//! There are a lot of different requirements when
|
||||
//! selecting, loading and writing a config,
|
||||
//! depending on the operating system and other
|
||||
//! environment factors.
|
||||
//!
|
||||
//! In many applications this burden is left to you,
|
||||
//! the developer of an application, to figure out
|
||||
//! where to place the configuration files.
|
||||
//!
|
||||
//! This is where `confy` comes in.
|
||||
//!
|
||||
//! ## Idea
|
||||
//!
|
||||
//! `confy` takes care of figuring out operating system
|
||||
//! specific and environment paths before reading and
|
||||
//! writing a configuration.
|
||||
//!
|
||||
//! It gives you easy access to a configuration file
|
||||
//! which is mirrored into a Rust `struct` via [serde].
|
||||
//! This way you only need to worry about the layout of
|
||||
//! your configuration, not where and how to store it.
|
||||
//!
|
||||
//! [serde]: https://docs.rs/crates/serde
|
||||
//!
|
||||
//! `confy` uses the [`Default`] trait in Rust to automatically
|
||||
//! create a new configuration, if none is available to read
|
||||
//! from yet.
|
||||
//! This means that you can simply assume your application
|
||||
//! to have a configuration, which will be created with
|
||||
//! default values of your choosing, without requiring
|
||||
//! any special logic to handle creation.
|
||||
//!
|
||||
//! [`Default`]: https://doc.rust-lang.org/std/default/trait.Default.html
|
||||
//!
|
||||
//! ```rust,no_run
|
||||
//! use serde_derive::{Serialize, Deserialize};
|
||||
//!
|
||||
//! #[derive(Serialize, Deserialize)]
|
||||
//! struct MyConfig {
|
||||
//! version: u8,
|
||||
//! api_key: String,
|
||||
//! }
|
||||
//!
|
||||
//! /// `MyConfig` implements `Default`
|
||||
//! impl ::std::default::Default for MyConfig {
|
||||
//! fn default() -> Self { Self { version: 0, api_key: "".into() } }
|
||||
//! }
|
||||
//!
|
||||
//! fn main() -> Result<(), confy::ConfyError> {
|
||||
//! let cfg = confy::load("my-app-name")?;
|
||||
//! Ok(())
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! Updating the configuration is then done via the [`store`] function.
|
||||
//!
|
||||
//! [`store`]: fn.store.html
|
||||
//!
|
||||
|
||||
mod utils;
|
||||
use utils::*;
|
||||
|
||||
use directories::ProjectDirs;
|
||||
use serde::{de::DeserializeOwned, Serialize};
|
||||
use std::error::Error;
|
||||
use std::fmt;
|
||||
use std::fs::{self, File, OpenOptions};
|
||||
use std::io::{ErrorKind::NotFound, Write};
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
#[cfg(not(any(feature = "toml_conf", feature = "yaml_conf")))]
|
||||
compile_error!("Exactly one config language feature must be enabled to use \
|
||||
confy. Please enable one of either the `toml_conf` or `yaml_conf` \
|
||||
features.");
|
||||
|
||||
#[cfg(all(feature = "toml_conf", feature = "yaml_conf"))]
|
||||
compile_error!("Exactly one config language feature must be enabled to compile \
|
||||
confy. Please disable one of either the `toml_conf` or `yaml_conf` features. \
|
||||
NOTE: `toml_conf` is a default feature, so disabling it might mean switching off \
|
||||
default features for confy in your Cargo.toml");
|
||||
|
||||
#[cfg(all(feature = "toml_conf", not(feature = "yaml_conf")))]
|
||||
const EXTENSION: &str = "toml";
|
||||
|
||||
#[cfg(feature = "yaml_conf")]
|
||||
const EXTENSION: &str = "yml";
|
||||
|
||||
/// Load an application configuration from disk
|
||||
///
|
||||
/// A new configuration file is created with default values if none
|
||||
/// exists.
|
||||
///
|
||||
/// Errors that are returned from this function are I/O related,
|
||||
/// for example if the writing of the new configuration fails
|
||||
/// or `confy` encounters an operating system or environment
|
||||
/// that it does not support.
|
||||
///
|
||||
/// **Note:** The type of configuration needs to be declared in some way
|
||||
/// that is inferrable by the compiler. Also note that your
|
||||
/// configuration needs to implement `Default`.
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// # use confy::ConfyError;
|
||||
/// # use serde_derive::{Serialize, Deserialize};
|
||||
/// # fn main() -> Result<(), ConfyError> {
|
||||
/// #[derive(Default, Serialize, Deserialize)]
|
||||
/// struct MyConfig {}
|
||||
///
|
||||
/// let cfg: MyConfig = confy::load("my-app-name")?;
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
pub fn load<T: Serialize + DeserializeOwned + Default>(name: &str) -> Result<T, ConfyError> {
|
||||
let project = ProjectDirs::from("rs", "", name).ok_or(ConfyError::BadConfigDirectoryStr)?;
|
||||
|
||||
let config_dir_str = get_configuration_directory_str(&project)?;
|
||||
|
||||
let path: PathBuf = [config_dir_str, &format!("{}.{}", name, EXTENSION)].iter().collect();
|
||||
|
||||
load_path(path)
|
||||
}
|
||||
|
||||
/// Load an application configuration from a specified path.
|
||||
///
|
||||
/// This is an alternate version of [`load`] that allows the specification of
|
||||
/// an aritrary path instead of a system one. For more information on errors
|
||||
/// and behavior, see [`load`]'s documentation.
|
||||
///
|
||||
/// [`load`]: fn.load.html
|
||||
pub fn load_path<T: Serialize + DeserializeOwned + Default>(path: impl AsRef<Path>) -> Result<T, ConfyError> {
|
||||
match File::open(&path) {
|
||||
Ok(mut cfg) => {
|
||||
let cfg_string = cfg
|
||||
.get_string()
|
||||
.map_err(ConfyError::ReadConfigurationFileError)?;
|
||||
|
||||
#[cfg(feature = "toml_conf")] {
|
||||
let cfg_data = toml::from_str(&cfg_string);
|
||||
cfg_data.map_err(ConfyError::BadTomlData)
|
||||
}
|
||||
#[cfg(feature = "yaml_conf")] {
|
||||
let cfg_data = serde_yaml::from_str(&cfg_string);
|
||||
cfg_data.map_err(ConfyError::BadYamlData)
|
||||
}
|
||||
|
||||
}
|
||||
Err(ref e) if e.kind() == NotFound => {
|
||||
if let Some(parent) = path.as_ref().parent() {
|
||||
fs::create_dir_all(parent)
|
||||
.map_err(ConfyError::DirectoryCreationFailed)?;
|
||||
}
|
||||
store_path(path, T::default())?;
|
||||
Ok(T::default())
|
||||
}
|
||||
Err(e) => Err(ConfyError::GeneralLoadError(e)),
|
||||
}
|
||||
}
|
||||
|
||||
/// The errors the confy crate can encounter.
|
||||
#[derive(Debug)]
|
||||
pub enum ConfyError {
|
||||
#[cfg(feature = "toml_conf")]
|
||||
BadTomlData(toml::de::Error),
|
||||
|
||||
#[cfg(feature = "yaml_conf")]
|
||||
BadYamlData(serde_yaml::Error),
|
||||
|
||||
DirectoryCreationFailed(std::io::Error),
|
||||
GeneralLoadError(std::io::Error),
|
||||
BadConfigDirectoryStr,
|
||||
|
||||
#[cfg(feature = "toml_conf")]
|
||||
SerializeTomlError(toml::ser::Error),
|
||||
|
||||
#[cfg(feature = "yaml_conf")]
|
||||
SerializeYamlError(serde_yaml::Error),
|
||||
|
||||
WriteConfigurationFileError(std::io::Error),
|
||||
ReadConfigurationFileError(std::io::Error),
|
||||
OpenConfigurationFileError(std::io::Error),
|
||||
}
|
||||
|
||||
impl fmt::Display for ConfyError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
|
||||
#[cfg(feature = "toml_conf")]
|
||||
ConfyError::BadTomlData(e) => write!(f, "Bad TOML data: {}", e),
|
||||
#[cfg(feature = "toml_conf")]
|
||||
ConfyError::SerializeTomlError(_) => write!(f, "Failed to serialize configuration data into TOML."),
|
||||
|
||||
#[cfg(feature = "yaml_conf")]
|
||||
ConfyError::BadYamlData(e) => write!(f, "Bad YAML data: {}", e),
|
||||
#[cfg(feature = "yaml_conf")]
|
||||
ConfyError::SerializeYamlError(_) => write!(f, "Failed to serialize configuration data into YAML."),
|
||||
|
||||
ConfyError::DirectoryCreationFailed(e) => write!(f, "Failed to create directory: {}", e),
|
||||
ConfyError::GeneralLoadError(_) => write!(f, "Failed to load configuration file."),
|
||||
ConfyError::BadConfigDirectoryStr => write!(f, "Failed to convert directory name to str."),
|
||||
ConfyError::WriteConfigurationFileError(_) => write!(f, "Failed to write configuration file."),
|
||||
ConfyError::ReadConfigurationFileError(_) => write!(f, "Failed to read configuration file."),
|
||||
ConfyError::OpenConfigurationFileError(_) => write!(f, "Failed to open configuration file."),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Error for ConfyError {}
|
||||
|
||||
/// Save changes made to a configuration object
|
||||
///
|
||||
/// This function will update a configuration,
|
||||
/// with the provided values, and create a new one,
|
||||
/// if none exists.
|
||||
///
|
||||
/// You can also use this function to create a new configuration
|
||||
/// with different initial values than which are provided
|
||||
/// by your `Default` trait implementation, or if your
|
||||
/// configuration structure _can't_ implement `Default`.
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// # use serde_derive::{Serialize, Deserialize};
|
||||
/// # use confy::ConfyError;
|
||||
/// # fn main() -> Result<(), ConfyError> {
|
||||
/// #[derive(Serialize, Deserialize)]
|
||||
/// struct MyConf {}
|
||||
///
|
||||
/// let my_cfg = MyConf {};
|
||||
/// confy::store("my-app-name", my_cfg)?;
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
///
|
||||
/// Errors returned are I/O errors related to not being
|
||||
/// able to write the configuration file or if `confy`
|
||||
/// encounters an operating system or environment it does
|
||||
/// not support.
|
||||
pub fn store<T: Serialize>(name: &str, cfg: T) -> Result<(), ConfyError> {
|
||||
let project = ProjectDirs::from("rs", "", name).ok_or(ConfyError::BadConfigDirectoryStr)?;
|
||||
fs::create_dir_all(project.config_dir()).map_err(ConfyError::DirectoryCreationFailed)?;
|
||||
|
||||
let config_dir_str = get_configuration_directory_str(&project)?;
|
||||
|
||||
let path: PathBuf = [config_dir_str, &format!("{}.{}", name, EXTENSION)].iter().collect();
|
||||
|
||||
store_path(path, cfg)
|
||||
}
|
||||
|
||||
/// Save changes made to a configuration object at a specified path
|
||||
///
|
||||
/// This is an alternate version of [`store`] that allows the specification of
|
||||
/// an aritrary path instead of a system one. For more information on errors
|
||||
/// and behavior, see [`store`]'s documentation.
|
||||
///
|
||||
/// [`store`]: fn.store.html
|
||||
pub fn store_path<T: Serialize>(path: impl AsRef<Path>, cfg: T) -> Result<(), ConfyError> {
|
||||
let path = path.as_ref();
|
||||
let mut path_tmp = path.to_path_buf();
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
let mut i = 0;
|
||||
loop {
|
||||
i += 1;
|
||||
path_tmp.set_extension(SystemTime::now().duration_since(UNIX_EPOCH).map(|x| x.as_nanos()).unwrap_or(i).to_string());
|
||||
if !path_tmp.exists() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
let mut f = OpenOptions::new()
|
||||
.write(true)
|
||||
.create(true)
|
||||
.truncate(true)
|
||||
.open(&path_tmp)
|
||||
.map_err(ConfyError::OpenConfigurationFileError)?;
|
||||
|
||||
let s;
|
||||
#[cfg(feature = "toml_conf")] {
|
||||
s = toml::to_string(&cfg).map_err(ConfyError::SerializeTomlError)?;
|
||||
}
|
||||
#[cfg(feature = "yaml_conf")] {
|
||||
s = serde_yaml::to_string(&cfg).map_err(ConfyError::SerializeYamlError)?;
|
||||
}
|
||||
|
||||
f.write_all(s.as_bytes())
|
||||
.map_err(ConfyError::WriteConfigurationFileError)?;
|
||||
std::fs::rename(path_tmp, path)
|
||||
.map_err(ConfyError::WriteConfigurationFileError)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_configuration_directory_str(project: &ProjectDirs) -> Result<&str, ConfyError> {
|
||||
let config_dir_option = project.config_dir().to_str();
|
||||
|
||||
match config_dir_option {
|
||||
Some(x) => Ok(x),
|
||||
None => Err(ConfyError::BadConfigDirectoryStr),
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
//! Some storage utilities
|
||||
|
||||
use std::fs::File;
|
||||
use std::io::{Error as IoError, Read};
|
||||
|
||||
pub trait CheckedStringRead {
|
||||
fn get_string(&mut self) -> Result<String, IoError>;
|
||||
}
|
||||
|
||||
impl CheckedStringRead for File {
|
||||
fn get_string(&mut self) -> Result<String, IoError> {
|
||||
let mut s = String::new();
|
||||
self.read_to_string(&mut s)?;
|
||||
Ok(s)
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ fn main() {
|
||||
thread::sleep(Duration::from_secs(2));
|
||||
let mut enigo = Enigo::new();
|
||||
|
||||
enigo.key_down(Key::Layout('a'));
|
||||
enigo.key_down(Key::Layout('a')).ok();
|
||||
thread::sleep(Duration::from_secs(1));
|
||||
enigo.key_up(Key::Layout('a'));
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ fn main() {
|
||||
enigo.key_sequence("Hello World! here is a lot of text ❤️");
|
||||
|
||||
// select all
|
||||
enigo.key_down(Key::Control);
|
||||
enigo.key_down(Key::Control).ok();
|
||||
enigo.key_click(Key::Layout('a'));
|
||||
enigo.key_up(Key::Control);
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ fn main() {
|
||||
enigo.mouse_move_to(500, 200);
|
||||
thread::sleep(wait_time);
|
||||
|
||||
enigo.mouse_down(MouseButton::Left);
|
||||
enigo.mouse_down(MouseButton::Left).ok();
|
||||
thread::sleep(wait_time);
|
||||
|
||||
enigo.mouse_move_relative(100, 100);
|
||||
|
||||
@@ -16,7 +16,7 @@ fn main() {
|
||||
println!("{:?}", time);
|
||||
|
||||
// select all
|
||||
enigo.key_down(Key::Control);
|
||||
enigo.key_down(Key::Control).ok();
|
||||
enigo.key_click(Key::Layout('a'));
|
||||
enigo.key_up(Key::Control);
|
||||
}
|
||||
|
||||
@@ -299,7 +299,7 @@ pub enum Key {
|
||||
/// meta key (also known as "windows", "super", and "command")
|
||||
Meta,
|
||||
/// option key on macOS (alt key on Linux and Windows)
|
||||
Option,
|
||||
Option, // deprecated, use Alt instead
|
||||
/// page down key
|
||||
PageDown,
|
||||
/// page up key
|
||||
@@ -347,8 +347,6 @@ pub enum Key {
|
||||
///
|
||||
Clear,
|
||||
///
|
||||
Menu, // deprecated, use alt instead
|
||||
///
|
||||
Pause,
|
||||
///
|
||||
Kana,
|
||||
|
||||
@@ -3,7 +3,7 @@ use libc;
|
||||
use crate::{Key, KeyboardControllable, MouseButton, MouseControllable};
|
||||
|
||||
use self::libc::{c_char, c_int, c_void, useconds_t};
|
||||
use std::{borrow::Cow, ffi::CString, ptr};
|
||||
use std::{borrow::Cow, ffi::CString, io::prelude::*, ptr, sync::mpsc};
|
||||
|
||||
const CURRENT_WINDOW: c_int = 0;
|
||||
const DEFAULT_DELAY: u64 = 12000;
|
||||
@@ -60,10 +60,16 @@ fn mousebutton(button: MouseButton) -> c_int {
|
||||
}
|
||||
}
|
||||
|
||||
enum PyMsg {
|
||||
Char(char),
|
||||
Str(&'static str),
|
||||
}
|
||||
|
||||
/// The main struct for handling the event emitting
|
||||
pub struct Enigo {
|
||||
xdo: Xdo,
|
||||
delay: u64,
|
||||
tx: mpsc::Sender<(PyMsg, bool)>,
|
||||
}
|
||||
// This is safe, we have a unique pointer.
|
||||
// TODO: use Unique<c_char> once stable.
|
||||
@@ -72,9 +78,12 @@ unsafe impl Send for Enigo {}
|
||||
impl Default for Enigo {
|
||||
/// Create a new Enigo instance
|
||||
fn default() -> Self {
|
||||
let (tx, rx) = mpsc::channel();
|
||||
start_pynput_service(rx);
|
||||
Self {
|
||||
xdo: unsafe { xdo_new(ptr::null()) },
|
||||
delay: DEFAULT_DELAY,
|
||||
tx,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -90,6 +99,99 @@ impl Enigo {
|
||||
pub fn set_delay(&mut self, delay: u64) {
|
||||
self.delay = delay;
|
||||
}
|
||||
///
|
||||
pub fn reset(&mut self) {
|
||||
self.tx.send((PyMsg::Char('\0'), true)).ok();
|
||||
}
|
||||
#[inline]
|
||||
fn send_pynput(&mut self, key: &Key, is_press: bool) -> bool {
|
||||
if unsafe { PYNPUT_EXIT || !PYNPUT_REDAY } {
|
||||
return false;
|
||||
}
|
||||
if let Key::Layout(c) = key {
|
||||
return self.tx.send((PyMsg::Char(*c), is_press)).is_ok();
|
||||
}
|
||||
if let Key::Raw(_) = key {
|
||||
return false;
|
||||
}
|
||||
#[allow(deprecated)]
|
||||
let s = match key {
|
||||
Key::Alt => "Alt_L",
|
||||
Key::Backspace => "BackSpace",
|
||||
Key::CapsLock => "Caps_Lock",
|
||||
Key::Control => "Control_L",
|
||||
Key::Delete => "Delete",
|
||||
Key::DownArrow => "Down",
|
||||
Key::End => "End",
|
||||
Key::Escape => "Escape",
|
||||
Key::F1 => "F1",
|
||||
Key::F10 => "F10",
|
||||
Key::F11 => "F11",
|
||||
Key::F12 => "F12",
|
||||
Key::F2 => "F2",
|
||||
Key::F3 => "F3",
|
||||
Key::F4 => "F4",
|
||||
Key::F5 => "F5",
|
||||
Key::F6 => "F6",
|
||||
Key::F7 => "F7",
|
||||
Key::F8 => "F8",
|
||||
Key::F9 => "F9",
|
||||
Key::Home => "Home",
|
||||
Key::LeftArrow => "Left",
|
||||
Key::Option => "Option",
|
||||
Key::PageDown => "Page_Down",
|
||||
Key::PageUp => "Page_Up",
|
||||
Key::Return => "Return",
|
||||
Key::RightArrow => "Right",
|
||||
Key::Shift => "Shift_L",
|
||||
Key::Space => "space",
|
||||
Key::Tab => "Tab",
|
||||
Key::UpArrow => "Up",
|
||||
Key::Numpad0 => "0",
|
||||
Key::Numpad1 => "1",
|
||||
Key::Numpad2 => "2",
|
||||
Key::Numpad3 => "3",
|
||||
Key::Numpad4 => "4",
|
||||
Key::Numpad5 => "5",
|
||||
Key::Numpad6 => "6",
|
||||
Key::Numpad7 => "7",
|
||||
Key::Numpad8 => "8",
|
||||
Key::Numpad9 => "9",
|
||||
Key::Decimal => "KP_Decimal",
|
||||
Key::Cancel => "Cancel",
|
||||
Key::Clear => "Clear",
|
||||
Key::Pause => "Pause",
|
||||
Key::Kana => "Kana",
|
||||
Key::Hangul => "Hangul",
|
||||
Key::Hanja => "Hanja",
|
||||
Key::Kanji => "Kanji",
|
||||
Key::Select => "Select",
|
||||
Key::Print => "Print",
|
||||
Key::Execute => "Execute",
|
||||
Key::Snapshot => "3270_PrintScreen",
|
||||
Key::Insert => "Insert",
|
||||
Key::Help => "Help",
|
||||
Key::Separator => "KP_Separator",
|
||||
Key::Scroll => "Scroll_Lock",
|
||||
Key::NumLock => "Num_Lock",
|
||||
Key::RWin => "Super_R",
|
||||
Key::Apps => "Menu",
|
||||
Key::Multiply => "KP_Multiply",
|
||||
Key::Add => "KP_Add",
|
||||
Key::Subtract => "KP_Subtract",
|
||||
Key::Divide => "KP_Divide",
|
||||
Key::Equals => "KP_Equal",
|
||||
Key::NumpadEnter => "KP_Enter",
|
||||
Key::RightShift => "Shift_R",
|
||||
Key::RightControl => "Control_R",
|
||||
Key::RightAlt => "Mode_switch",
|
||||
Key::Command | Key::Super | Key::Windows | Key::Meta => "Super_L",
|
||||
_ => {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
return self.tx.send((PyMsg::Str(s), is_press)).is_ok();
|
||||
}
|
||||
}
|
||||
impl Drop for Enigo {
|
||||
fn drop(&mut self) {
|
||||
@@ -238,7 +340,6 @@ fn keysequence<'a>(key: Key) -> Cow<'a, str> {
|
||||
Key::Decimal => "U2E", //"KP_Decimal",
|
||||
Key::Cancel => "Cancel",
|
||||
Key::Clear => "Clear",
|
||||
Key::Menu => "Menu",
|
||||
Key::Pause => "Pause",
|
||||
Key::Kana => "Kana",
|
||||
Key::Hangul => "Hangul",
|
||||
@@ -261,7 +362,7 @@ fn keysequence<'a>(key: Key) -> Cow<'a, str> {
|
||||
Key::Scroll => "Scroll_Lock",
|
||||
Key::NumLock => "Num_Lock",
|
||||
Key::RWin => "Super_R",
|
||||
Key::Apps => "",
|
||||
Key::Apps => "Menu",
|
||||
Key::Multiply => "KP_Multiply",
|
||||
Key::Add => "KP_Add",
|
||||
Key::Subtract => "KP_Subtract",
|
||||
@@ -282,6 +383,17 @@ impl KeyboardControllable for Enigo {
|
||||
if self.xdo.is_null() {
|
||||
return false;
|
||||
}
|
||||
/*
|
||||
// modifier keys mask
|
||||
pub const ShiftMask: c_uint = 0x01;
|
||||
pub const LockMask: c_uint = 0x02;
|
||||
pub const ControlMask: c_uint = 0x04;
|
||||
pub const Mod1Mask: c_uint = 0x08;
|
||||
pub const Mod2Mask: c_uint = 0x10;
|
||||
pub const Mod3Mask: c_uint = 0x20;
|
||||
pub const Mod4Mask: c_uint = 0x40;
|
||||
pub const Mod5Mask: c_uint = 0x80;
|
||||
*/
|
||||
let mod_shift = 1 << 0;
|
||||
let mod_lock = 1 << 1;
|
||||
let mod_control = 1 << 2;
|
||||
@@ -289,7 +401,6 @@ impl KeyboardControllable for Enigo {
|
||||
let mod_numlock = 1 << 4;
|
||||
let mod_meta = 1 << 6;
|
||||
let mask = unsafe { xdo_get_input_state(self.xdo) };
|
||||
// println!("{:b}", mask);
|
||||
match key {
|
||||
Key::Shift => mask & mod_shift != 0,
|
||||
Key::CapsLock => mask & mod_lock != 0,
|
||||
@@ -320,6 +431,9 @@ impl KeyboardControllable for Enigo {
|
||||
if self.xdo.is_null() {
|
||||
return Ok(());
|
||||
}
|
||||
if self.send_pynput(&key, true) {
|
||||
return Ok(());
|
||||
}
|
||||
let string = CString::new(&*keysequence(key))?;
|
||||
unsafe {
|
||||
xdo_send_keysequence_window_down(
|
||||
@@ -335,6 +449,9 @@ impl KeyboardControllable for Enigo {
|
||||
if self.xdo.is_null() {
|
||||
return;
|
||||
}
|
||||
if self.send_pynput(&key, false) {
|
||||
return;
|
||||
}
|
||||
if let Ok(string) = CString::new(&*keysequence(key)) {
|
||||
unsafe {
|
||||
xdo_send_keysequence_window_up(
|
||||
@@ -362,3 +479,119 @@ impl KeyboardControllable for Enigo {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static mut PYNPUT_EXIT: bool = false;
|
||||
static mut PYNPUT_REDAY: bool = false;
|
||||
static IPC_FILE: &'static str = "/tmp/RustDesk/pynput_service";
|
||||
|
||||
fn start_pynput_service(rx: mpsc::Receiver<(PyMsg, bool)>) {
|
||||
let mut py = "./pynput_service.py".to_owned();
|
||||
if !std::path::Path::new(&py).exists() {
|
||||
py = "/usr/share/rustdesk/files/pynput_service.py".to_owned();
|
||||
if !std::path::Path::new(&py).exists() {
|
||||
log::error!("{} not exits", py);
|
||||
}
|
||||
}
|
||||
log::info!("pynput service: {}", py);
|
||||
std::thread::spawn(move || {
|
||||
let username = std::env::var("PYNPUT_USERNAME").unwrap_or("".to_owned());
|
||||
let userid = std::env::var("PYNPUT_USERID").unwrap_or("".to_owned());
|
||||
let status = if username.is_empty() {
|
||||
std::process::Command::new("python3")
|
||||
.arg(&py)
|
||||
.arg(IPC_FILE)
|
||||
.status()
|
||||
.map(|x| x.success())
|
||||
} else {
|
||||
let mut status = Ok(true);
|
||||
for i in 0..100 {
|
||||
if i % 10 == 0 {
|
||||
log::info!("#{} try to start pynput server", i);
|
||||
}
|
||||
status = std::process::Command::new("sudo")
|
||||
.args(vec![
|
||||
&format!("XDG_RUNTIME_DIR=/run/user/{}", userid) as &str,
|
||||
"-u",
|
||||
&username,
|
||||
"python3",
|
||||
&py,
|
||||
IPC_FILE,
|
||||
])
|
||||
.status()
|
||||
.map(|x| x.success());
|
||||
match status {
|
||||
Ok(true) => break,
|
||||
_ => {}
|
||||
}
|
||||
std::thread::sleep(std::time::Duration::from_millis(100));
|
||||
}
|
||||
status
|
||||
};
|
||||
log::info!(
|
||||
"pynput server exit with username/id {}/{}: {:?}",
|
||||
username,
|
||||
userid,
|
||||
status
|
||||
);
|
||||
unsafe {
|
||||
PYNPUT_EXIT = true;
|
||||
}
|
||||
});
|
||||
std::thread::spawn(move || {
|
||||
for i in 0..300 {
|
||||
std::thread::sleep(std::time::Duration::from_millis(100));
|
||||
let mut conn = match std::os::unix::net::UnixStream::connect(IPC_FILE) {
|
||||
Ok(conn) => conn,
|
||||
Err(err) => {
|
||||
if i % 15 == 0 {
|
||||
log::warn!("Failed to connect to {}: {}", IPC_FILE, err);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
};
|
||||
if let Err(err) = conn.set_nonblocking(true) {
|
||||
log::error!("Failed to set ipc nonblocking: {}", err);
|
||||
return;
|
||||
}
|
||||
log::info!("Conntected to pynput server");
|
||||
let d = std::time::Duration::from_millis(30);
|
||||
unsafe {
|
||||
PYNPUT_REDAY = true;
|
||||
}
|
||||
let mut buf = [0u8; 1024];
|
||||
loop {
|
||||
if unsafe { PYNPUT_EXIT } {
|
||||
break;
|
||||
}
|
||||
match rx.recv_timeout(d) {
|
||||
Ok((msg, is_press)) => {
|
||||
let msg = match msg {
|
||||
PyMsg::Char(chr) => {
|
||||
format!("{}{}", if is_press { 'p' } else { 'r' }, chr)
|
||||
}
|
||||
PyMsg::Str(s) => format!("{}{}", if is_press { 'p' } else { 'r' }, s),
|
||||
};
|
||||
let n = msg.len();
|
||||
buf[0] = n as _;
|
||||
buf[1..(n + 1)].copy_from_slice(msg.as_bytes());
|
||||
if let Err(err) = conn.write_all(&buf[..n + 1]) {
|
||||
log::error!("Failed to write to ipc: {}", err);
|
||||
break;
|
||||
}
|
||||
}
|
||||
Err(err) => match err {
|
||||
mpsc::RecvTimeoutError::Disconnected => {
|
||||
log::error!("pynput sender disconnecte");
|
||||
break;
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
}
|
||||
}
|
||||
unsafe {
|
||||
PYNPUT_REDAY = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -71,3 +71,50 @@ pub const kVK_ANSI_KeypadEnter: u16 = 0x4C;
|
||||
pub const kVK_ANSI_KeypadMinus: u16 = 0x4E;
|
||||
pub const kVK_ANSI_KeypadEquals: u16 = 0x51;
|
||||
pub const kVK_RIGHT_COMMAND: u16 = 0x36;
|
||||
pub const kVK_ANSI_A : u16 = 0x00;
|
||||
pub const kVK_ANSI_S : u16 = 0x01;
|
||||
pub const kVK_ANSI_D : u16 = 0x02;
|
||||
pub const kVK_ANSI_F : u16 = 0x03;
|
||||
pub const kVK_ANSI_H : u16 = 0x04;
|
||||
pub const kVK_ANSI_G : u16 = 0x05;
|
||||
pub const kVK_ANSI_Z : u16 = 0x06;
|
||||
pub const kVK_ANSI_X : u16 = 0x07;
|
||||
pub const kVK_ANSI_C : u16 = 0x08;
|
||||
pub const kVK_ANSI_V : u16 = 0x09;
|
||||
pub const kVK_ANSI_B : u16 = 0x0B;
|
||||
pub const kVK_ANSI_Q : u16 = 0x0C;
|
||||
pub const kVK_ANSI_W : u16 = 0x0D;
|
||||
pub const kVK_ANSI_E : u16 = 0x0E;
|
||||
pub const kVK_ANSI_R : u16 = 0x0F;
|
||||
pub const kVK_ANSI_Y : u16 = 0x10;
|
||||
pub const kVK_ANSI_T : u16 = 0x11;
|
||||
pub const kVK_ANSI_1 : u16 = 0x12;
|
||||
pub const kVK_ANSI_2 : u16 = 0x13;
|
||||
pub const kVK_ANSI_3 : u16 = 0x14;
|
||||
pub const kVK_ANSI_4 : u16 = 0x15;
|
||||
pub const kVK_ANSI_6 : u16 = 0x16;
|
||||
pub const kVK_ANSI_5 : u16 = 0x17;
|
||||
pub const kVK_ANSI_Equal : u16 = 0x18;
|
||||
pub const kVK_ANSI_9 : u16 = 0x19;
|
||||
pub const kVK_ANSI_7 : u16 = 0x1A;
|
||||
pub const kVK_ANSI_Minus : u16 = 0x1B;
|
||||
pub const kVK_ANSI_8 : u16 = 0x1C;
|
||||
pub const kVK_ANSI_0 : u16 = 0x1D;
|
||||
pub const kVK_ANSI_RightBracket : u16 = 0x1E;
|
||||
pub const kVK_ANSI_O : u16 = 0x1F;
|
||||
pub const kVK_ANSI_U : u16 = 0x20;
|
||||
pub const kVK_ANSI_LeftBracket : u16 = 0x21;
|
||||
pub const kVK_ANSI_I : u16 = 0x22;
|
||||
pub const kVK_ANSI_P : u16 = 0x23;
|
||||
pub const kVK_ANSI_L : u16 = 0x25;
|
||||
pub const kVK_ANSI_J : u16 = 0x26;
|
||||
pub const kVK_ANSI_Quote : u16 = 0x27;
|
||||
pub const kVK_ANSI_K : u16 = 0x28;
|
||||
pub const kVK_ANSI_Semicolon : u16 = 0x29;
|
||||
pub const kVK_ANSI_Backslash : u16 = 0x2A;
|
||||
pub const kVK_ANSI_Comma : u16 = 0x2B;
|
||||
pub const kVK_ANSI_Slash : u16 = 0x2C;
|
||||
pub const kVK_ANSI_N : u16 = 0x2D;
|
||||
pub const kVK_ANSI_M : u16 = 0x2E;
|
||||
pub const kVK_ANSI_Period : u16 = 0x2F;
|
||||
pub const kVK_ANSI_Grave : u16 = 0x32;
|
||||
|
||||
@@ -5,24 +5,73 @@ use core_graphics;
|
||||
use self::core_graphics::display::*;
|
||||
use self::core_graphics::event::*;
|
||||
use self::core_graphics::event_source::*;
|
||||
use std::collections::HashMap as Map;
|
||||
use std::ffi::c_void;
|
||||
use std::ffi::CStr;
|
||||
use std::os::raw::*;
|
||||
use std::ptr::null_mut;
|
||||
|
||||
use crate::macos::keycodes::*;
|
||||
use crate::{Key, KeyboardControllable, MouseButton, MouseControllable};
|
||||
use objc::runtime::Class;
|
||||
use std::ffi::CStr;
|
||||
use std::os::raw::*;
|
||||
|
||||
// required for pressedMouseButtons on NSEvent
|
||||
#[link(name = "AppKit", kind = "framework")]
|
||||
extern "C" {}
|
||||
|
||||
struct MyCGEvent;
|
||||
type TISInputSourceRef = *mut c_void;
|
||||
type CFDataRef = *const c_void;
|
||||
type OptionBits = u32;
|
||||
type OSStatus = i32;
|
||||
type UniChar = u16;
|
||||
type UniCharCount = usize;
|
||||
type Boolean = c_uchar;
|
||||
type CFStringEncoding = u32;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
struct __CFString([u8; 0]);
|
||||
type CFStringRef = *const __CFString;
|
||||
|
||||
#[allow(non_upper_case_globals)]
|
||||
const kCFStringEncodingUTF8: u32 = 134_217_984;
|
||||
#[allow(non_upper_case_globals)]
|
||||
const kUCKeyActionDisplay: u16 = 3;
|
||||
#[allow(non_upper_case_globals)]
|
||||
const kUCKeyTranslateDeadKeysBit: OptionBits = 1 << 31;
|
||||
const BUF_LEN: usize = 4;
|
||||
|
||||
#[allow(improper_ctypes)]
|
||||
#[allow(non_snake_case)]
|
||||
#[link(name = "ApplicationServices", kind = "framework")]
|
||||
extern "C" {
|
||||
fn CFDataGetBytePtr(theData: CFDataRef) -> *const u8;
|
||||
fn TISCopyCurrentKeyboardInputSource() -> TISInputSourceRef;
|
||||
fn TISCopyCurrentKeyboardLayoutInputSource() -> TISInputSourceRef;
|
||||
fn TISCopyCurrentASCIICapableKeyboardLayoutInputSource() -> TISInputSourceRef;
|
||||
static kTISPropertyUnicodeKeyLayoutData: *mut c_void;
|
||||
static kTISPropertyInputSourceID: *mut c_void;
|
||||
fn UCKeyTranslate(
|
||||
keyLayoutPtr: *const u8, //*const UCKeyboardLayout,
|
||||
virtualKeyCode: u16,
|
||||
keyAction: u16,
|
||||
modifierKeyState: u32,
|
||||
keyboardType: u32,
|
||||
keyTranslateOptions: OptionBits,
|
||||
deadKeyState: *mut u32,
|
||||
maxStringLength: UniCharCount,
|
||||
actualStringLength: *mut UniCharCount,
|
||||
unicodeString: *mut [UniChar; BUF_LEN],
|
||||
) -> OSStatus;
|
||||
fn LMGetKbdType() -> u8;
|
||||
fn CFStringGetCString(
|
||||
theString: CFStringRef,
|
||||
buffer: *mut c_char,
|
||||
bufferSize: CFIndex,
|
||||
encoding: CFStringEncoding,
|
||||
) -> Boolean;
|
||||
|
||||
fn CGEventPost(tapLocation: CGEventTapLocation, event: *mut MyCGEvent);
|
||||
// Actually return CFDataRef which is const here, but for coding convienence, return *mut c_void
|
||||
fn TISGetInputSourceProperty(source: TISInputSourceRef, property: *const c_void)
|
||||
-> *mut c_void;
|
||||
// not present in servo/core-graphics
|
||||
fn CGEventCreateScrollWheelEvent(
|
||||
source: &CGEventSourceRef,
|
||||
@@ -34,8 +83,6 @@ extern "C" {
|
||||
fn CGEventSourceKeyState(stateID: i32, key: u16) -> bool;
|
||||
}
|
||||
|
||||
pub type CFDataRef = *const c_void;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
struct NSPoint {
|
||||
@@ -43,162 +90,6 @@ struct NSPoint {
|
||||
y: f64,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct __TISInputSource;
|
||||
pub type TISInputSourceRef = *const __TISInputSource;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct __CFString([u8; 0]);
|
||||
pub type CFStringRef = *const __CFString;
|
||||
pub type Boolean = c_uchar;
|
||||
pub type UInt8 = c_uchar;
|
||||
pub type SInt32 = c_int;
|
||||
pub type UInt16 = c_ushort;
|
||||
pub type UInt32 = c_uint;
|
||||
pub type UniChar = UInt16;
|
||||
pub type UniCharCount = c_ulong;
|
||||
|
||||
pub type OptionBits = UInt32;
|
||||
pub type OSStatus = SInt32;
|
||||
|
||||
pub type CFStringEncoding = UInt32;
|
||||
|
||||
#[allow(non_upper_case_globals)]
|
||||
pub const kUCKeyActionDisplay: _bindgen_ty_702 = _bindgen_ty_702::kUCKeyActionDisplay;
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
#[repr(u32)]
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum _bindgen_ty_702 {
|
||||
// kUCKeyActionDown = 0,
|
||||
// kUCKeyActionUp = 1,
|
||||
// kUCKeyActionAutoKey = 2,
|
||||
kUCKeyActionDisplay = 3,
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct UCKeyboardTypeHeader {
|
||||
pub keyboardTypeFirst: UInt32,
|
||||
pub keyboardTypeLast: UInt32,
|
||||
pub keyModifiersToTableNumOffset: UInt32,
|
||||
pub keyToCharTableIndexOffset: UInt32,
|
||||
pub keyStateRecordsIndexOffset: UInt32,
|
||||
pub keyStateTerminatorsOffset: UInt32,
|
||||
pub keySequenceDataIndexOffset: UInt32,
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct UCKeyboardLayout {
|
||||
pub keyLayoutHeaderFormat: UInt16,
|
||||
pub keyLayoutDataVersion: UInt16,
|
||||
pub keyLayoutFeatureInfoOffset: UInt32,
|
||||
pub keyboardTypeCount: UInt32,
|
||||
pub keyboardTypeList: [UCKeyboardTypeHeader; 1usize],
|
||||
}
|
||||
|
||||
#[allow(non_upper_case_globals)]
|
||||
pub const kUCKeyTranslateNoDeadKeysBit: _bindgen_ty_703 =
|
||||
_bindgen_ty_703::kUCKeyTranslateNoDeadKeysBit;
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
#[repr(u32)]
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum _bindgen_ty_703 {
|
||||
kUCKeyTranslateNoDeadKeysBit = 0,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct __CFAllocator([u8; 0]);
|
||||
pub type CFAllocatorRef = *const __CFAllocator;
|
||||
|
||||
// #[repr(u32)]
|
||||
// #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
// pub enum _bindgen_ty_15 {
|
||||
// kCFStringEncodingMacRoman = 0,
|
||||
// kCFStringEncodingWindowsLatin1 = 1280,
|
||||
// kCFStringEncodingISOLatin1 = 513,
|
||||
// kCFStringEncodingNextStepLatin = 2817,
|
||||
// kCFStringEncodingASCII = 1536,
|
||||
// kCFStringEncodingUnicode = 256,
|
||||
// kCFStringEncodingUTF8 = 134217984,
|
||||
// kCFStringEncodingNonLossyASCII = 3071,
|
||||
// kCFStringEncodingUTF16BE = 268435712,
|
||||
// kCFStringEncodingUTF16LE = 335544576,
|
||||
// kCFStringEncodingUTF32 = 201326848,
|
||||
// kCFStringEncodingUTF32BE = 402653440,
|
||||
// kCFStringEncodingUTF32LE = 469762304,
|
||||
// }
|
||||
|
||||
#[allow(non_upper_case_globals)]
|
||||
pub const kCFStringEncodingUTF8: u32 = 134_217_984;
|
||||
|
||||
#[allow(improper_ctypes)]
|
||||
#[link(name = "Carbon", kind = "framework")]
|
||||
extern "C" {
|
||||
fn TISCopyCurrentKeyboardInputSource() -> TISInputSourceRef;
|
||||
fn TISCopyCurrentKeyboardLayoutInputSource() -> TISInputSourceRef;
|
||||
fn TISCopyCurrentASCIICapableKeyboardLayoutInputSource() -> TISInputSourceRef;
|
||||
|
||||
// extern void *
|
||||
// TISGetInputSourceProperty(
|
||||
// TISInputSourceRef inputSource,
|
||||
// CFStringRef propertyKey)
|
||||
|
||||
#[allow(non_upper_case_globals)]
|
||||
#[link_name = "kTISPropertyUnicodeKeyLayoutData"]
|
||||
pub static kTISPropertyUnicodeKeyLayoutData: CFStringRef;
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub fn TISGetInputSourceProperty(
|
||||
inputSource: TISInputSourceRef,
|
||||
propertyKey: CFStringRef,
|
||||
) -> *mut c_void;
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub fn CFDataGetBytePtr(theData: CFDataRef) -> *const UInt8;
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub fn UCKeyTranslate(
|
||||
keyLayoutPtr: *const UInt8, //*const UCKeyboardLayout,
|
||||
virtualKeyCode: UInt16,
|
||||
keyAction: UInt16,
|
||||
modifierKeyState: UInt32,
|
||||
keyboardType: UInt32,
|
||||
keyTranslateOptions: OptionBits,
|
||||
deadKeyState: *mut UInt32,
|
||||
maxStringLength: UniCharCount,
|
||||
actualStringLength: *mut UniCharCount,
|
||||
unicodeString: *mut UniChar,
|
||||
) -> OSStatus;
|
||||
|
||||
pub fn LMGetKbdType() -> UInt8;
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub fn CFStringCreateWithCharacters(
|
||||
alloc: CFAllocatorRef,
|
||||
chars: *const UniChar,
|
||||
numChars: CFIndex,
|
||||
) -> CFStringRef;
|
||||
|
||||
#[allow(non_upper_case_globals)]
|
||||
#[link_name = "kCFAllocatorDefault"]
|
||||
pub static kCFAllocatorDefault: CFAllocatorRef;
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub fn CFStringGetCString(
|
||||
theString: CFStringRef,
|
||||
buffer: *mut c_char,
|
||||
bufferSize: CFIndex,
|
||||
encoding: CFStringEncoding,
|
||||
) -> Boolean;
|
||||
}
|
||||
|
||||
// not present in servo/core-graphics
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug)]
|
||||
@@ -211,11 +102,11 @@ enum ScrollUnit {
|
||||
/// The main struct for handling the event emitting
|
||||
pub struct Enigo {
|
||||
event_source: Option<CGEventSource>,
|
||||
keycode_to_string_map: std::collections::HashMap<String, CGKeyCode>,
|
||||
double_click_interval: u32,
|
||||
last_click_time: Option<std::time::Instant>,
|
||||
multiple_click: i64,
|
||||
flags: CGEventFlags,
|
||||
char_to_vkey_map: Map<String, Map<char, CGKeyCode>>,
|
||||
}
|
||||
|
||||
impl Enigo {
|
||||
@@ -263,11 +154,11 @@ impl Default for Enigo {
|
||||
} else {
|
||||
None
|
||||
},
|
||||
keycode_to_string_map: Default::default(),
|
||||
double_click_interval,
|
||||
multiple_click: 1,
|
||||
last_click_time: None,
|
||||
flags: CGEventFlags::CGEventFlagNull,
|
||||
char_to_vkey_map: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -591,127 +482,186 @@ impl Enigo {
|
||||
Key::RightAlt => kVK_RightOption,
|
||||
|
||||
Key::Raw(raw_keycode) => raw_keycode,
|
||||
Key::Layout(c) => self.get_layoutdependent_keycode(c.to_string()),
|
||||
Key::Layout(c) => self.map_key_board(c),
|
||||
|
||||
Key::Super | Key::Command | Key::Windows | Key::Meta => kVK_Command,
|
||||
_ => 0,
|
||||
}
|
||||
}
|
||||
|
||||
fn get_layoutdependent_keycode(&mut self, string: String) -> CGKeyCode {
|
||||
if self.keycode_to_string_map.is_empty() {
|
||||
self.init_map();
|
||||
}
|
||||
*self.keycode_to_string_map.get(&string).unwrap_or(&0)
|
||||
}
|
||||
|
||||
fn init_map(&mut self) {
|
||||
println!("init_map");
|
||||
self.keycode_to_string_map.insert("".to_owned(), 0);
|
||||
// loop through every keycode (0 - 127)
|
||||
for keycode in 0..128 {
|
||||
// no modifier
|
||||
if let Some(key_string) = self.keycode_to_string(keycode, 0x100) {
|
||||
self.keycode_to_string_map.insert(key_string, keycode);
|
||||
}
|
||||
|
||||
// shift modifier
|
||||
if let Some(key_string) = self.keycode_to_string(keycode, 0x20102) {
|
||||
self.keycode_to_string_map.insert(key_string, keycode);
|
||||
}
|
||||
|
||||
// alt modifier
|
||||
// if let Some(string) = self.keycode_to_string(keycode, 0x80120) {
|
||||
// println!("{:?}", string);
|
||||
// }
|
||||
// alt + shift modifier
|
||||
// if let Some(string) = self.keycode_to_string(keycode, 0xa0122) {
|
||||
// println!("{:?}", string);
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
fn keycode_to_string(&self, keycode: u16, modifier: u32) -> Option<String> {
|
||||
let cf_string = self.create_string_for_key(keycode, modifier);
|
||||
#[inline]
|
||||
fn map_key_board(&mut self, ch: char) -> CGKeyCode {
|
||||
let mut code = 0;
|
||||
unsafe {
|
||||
if !cf_string.is_null() {
|
||||
let mut buf: [i8; 255] = [0; 255];
|
||||
let success = CFStringGetCString(
|
||||
cf_string,
|
||||
buf.as_mut_ptr(),
|
||||
buf.len() as _,
|
||||
kCFStringEncodingUTF8,
|
||||
);
|
||||
if success != 0 {
|
||||
let name: &CStr = CStr::from_ptr(buf.as_ptr());
|
||||
if let Ok(name) = name.to_str() {
|
||||
return Some(name.to_owned());
|
||||
let (keyboard, layout) = get_layout();
|
||||
if !keyboard.is_null() && !layout.is_null() {
|
||||
let name_ref = TISGetInputSourceProperty(keyboard, kTISPropertyInputSourceID);
|
||||
if !name_ref.is_null() {
|
||||
let name = get_string(name_ref as _);
|
||||
if let Some(name) = name {
|
||||
if let Some(m) = self.char_to_vkey_map.get(&name) {
|
||||
code = *m.get(&ch).unwrap_or(&0);
|
||||
} else {
|
||||
let m = get_map(&name, layout);
|
||||
code = *m.get(&ch).unwrap_or(&0);
|
||||
self.char_to_vkey_map.insert(name.clone(), m);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
fn create_string_for_key(&self, keycode: u16, modifier: u32) -> CFStringRef {
|
||||
let current_keyboard = unsafe { TISCopyCurrentKeyboardInputSource() };
|
||||
let mut layout_data = std::ptr::null_mut();
|
||||
if !current_keyboard.is_null() {
|
||||
layout_data = unsafe {
|
||||
TISGetInputSourceProperty(current_keyboard, kTISPropertyUnicodeKeyLayoutData)
|
||||
};
|
||||
}
|
||||
if layout_data.is_null() {
|
||||
// https://github.com/microsoft/vscode/issues/23833
|
||||
let current_keyboard = unsafe { TISCopyCurrentKeyboardLayoutInputSource() };
|
||||
if !current_keyboard.is_null() {
|
||||
layout_data = unsafe {
|
||||
TISGetInputSourceProperty(current_keyboard, kTISPropertyUnicodeKeyLayoutData)
|
||||
};
|
||||
if !keyboard.is_null() {
|
||||
CFRelease(keyboard);
|
||||
}
|
||||
}
|
||||
if layout_data.is_null() {
|
||||
let current_keyboard = unsafe { TISCopyCurrentASCIICapableKeyboardLayoutInputSource() };
|
||||
if !current_keyboard.is_null() {
|
||||
layout_data = unsafe {
|
||||
TISGetInputSourceProperty(current_keyboard, kTISPropertyUnicodeKeyLayoutData)
|
||||
};
|
||||
}
|
||||
if code > 0 {
|
||||
return code;
|
||||
}
|
||||
if layout_data.is_null() {
|
||||
// to-do: try out manual mapping in https://github.com/stweil/OSXvnc
|
||||
// we do see crash like this, also not easy to reproduce, no sure if it related
|
||||
/*
|
||||
0 rustdesk 0x000000010f921bc9 std::collections::hash::map::HashMap$LT$K$C$V$C$S$GT$::insert::h84e28c51a3292e7a + 473
|
||||
1 rustdesk 0x000000010f921884 enigo::macos::macos_impl::Enigo::key_to_keycode::h85ead82e9b1075ae + 1428
|
||||
2 rustdesk 0x000000010f922a8c _$LT$enigo..macos..macos_impl..Enigo$u20$as$u20$enigo..KeyboardControllable$GT$::key_down::h54f24da6d274b948 + 44
|
||||
*/
|
||||
return std::ptr::null() as _;
|
||||
match ch {
|
||||
'a' => kVK_ANSI_A,
|
||||
'b' => kVK_ANSI_B,
|
||||
'c' => kVK_ANSI_C,
|
||||
'd' => kVK_ANSI_D,
|
||||
'e' => kVK_ANSI_E,
|
||||
'f' => kVK_ANSI_F,
|
||||
'g' => kVK_ANSI_G,
|
||||
'h' => kVK_ANSI_H,
|
||||
'i' => kVK_ANSI_I,
|
||||
'j' => kVK_ANSI_J,
|
||||
'k' => kVK_ANSI_K,
|
||||
'l' => kVK_ANSI_L,
|
||||
'm' => kVK_ANSI_M,
|
||||
'n' => kVK_ANSI_N,
|
||||
'o' => kVK_ANSI_O,
|
||||
'p' => kVK_ANSI_P,
|
||||
'q' => kVK_ANSI_Q,
|
||||
'r' => kVK_ANSI_R,
|
||||
's' => kVK_ANSI_S,
|
||||
't' => kVK_ANSI_T,
|
||||
'u' => kVK_ANSI_U,
|
||||
'v' => kVK_ANSI_V,
|
||||
'w' => kVK_ANSI_W,
|
||||
'x' => kVK_ANSI_X,
|
||||
'y' => kVK_ANSI_Y,
|
||||
'z' => kVK_ANSI_Z,
|
||||
'0' => kVK_ANSI_0,
|
||||
'1' => kVK_ANSI_1,
|
||||
'2' => kVK_ANSI_2,
|
||||
'3' => kVK_ANSI_3,
|
||||
'4' => kVK_ANSI_4,
|
||||
'5' => kVK_ANSI_5,
|
||||
'6' => kVK_ANSI_6,
|
||||
'7' => kVK_ANSI_7,
|
||||
'8' => kVK_ANSI_8,
|
||||
'9' => kVK_ANSI_9,
|
||||
'-' => kVK_ANSI_Minus,
|
||||
'=' => kVK_ANSI_Equal,
|
||||
'[' => kVK_ANSI_LeftBracket,
|
||||
']' => kVK_ANSI_RightBracket,
|
||||
'\\' => kVK_ANSI_Backslash,
|
||||
';' => kVK_ANSI_Semicolon,
|
||||
'\'' => kVK_ANSI_Quote,
|
||||
',' => kVK_ANSI_Comma,
|
||||
'.' => kVK_ANSI_Period,
|
||||
'/' => kVK_ANSI_Slash,
|
||||
'`' => kVK_ANSI_Grave,
|
||||
_ => 0,
|
||||
}
|
||||
let keyboard_layout = unsafe { CFDataGetBytePtr(layout_data) };
|
||||
|
||||
let mut keys_down: UInt32 = 0;
|
||||
let mut chars: u16 = 0;
|
||||
// let mut chars: *mut c_void;//[UniChar; 4];
|
||||
let mut real_length: UniCharCount = 0;
|
||||
unsafe {
|
||||
UCKeyTranslate(
|
||||
keyboard_layout,
|
||||
keycode,
|
||||
kUCKeyActionDisplay as u16,
|
||||
modifier,
|
||||
LMGetKbdType() as u32,
|
||||
kUCKeyTranslateNoDeadKeysBit as u32,
|
||||
&mut keys_down,
|
||||
8, // sizeof(chars) / sizeof(chars[0]),
|
||||
&mut real_length,
|
||||
&mut chars,
|
||||
);
|
||||
}
|
||||
|
||||
unsafe { CFStringCreateWithCharacters(kCFAllocatorDefault, &chars, 1) }
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn get_string(cf_string: CFStringRef) -> Option<String> {
|
||||
if !cf_string.is_null() {
|
||||
let mut buf: [i8; 255] = [0; 255];
|
||||
let success = CFStringGetCString(
|
||||
cf_string,
|
||||
buf.as_mut_ptr(),
|
||||
buf.len() as _,
|
||||
kCFStringEncodingUTF8,
|
||||
);
|
||||
if success != 0 {
|
||||
let name: &CStr = CStr::from_ptr(buf.as_ptr());
|
||||
if let Ok(name) = name.to_str() {
|
||||
return Some(name.to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn get_layout() -> (TISInputSourceRef, *const u8) {
|
||||
let mut keyboard = TISCopyCurrentKeyboardInputSource();
|
||||
let mut layout = null_mut();
|
||||
if !keyboard.is_null() {
|
||||
layout = TISGetInputSourceProperty(keyboard, kTISPropertyUnicodeKeyLayoutData);
|
||||
}
|
||||
if layout.is_null() {
|
||||
if !keyboard.is_null() {
|
||||
CFRelease(keyboard);
|
||||
}
|
||||
// https://github.com/microsoft/vscode/issues/23833
|
||||
keyboard = TISCopyCurrentKeyboardLayoutInputSource();
|
||||
if !keyboard.is_null() {
|
||||
layout = TISGetInputSourceProperty(keyboard, kTISPropertyUnicodeKeyLayoutData);
|
||||
}
|
||||
}
|
||||
if layout.is_null() {
|
||||
if !keyboard.is_null() {
|
||||
CFRelease(keyboard);
|
||||
}
|
||||
keyboard = TISCopyCurrentASCIICapableKeyboardLayoutInputSource();
|
||||
if !keyboard.is_null() {
|
||||
layout = TISGetInputSourceProperty(keyboard, kTISPropertyUnicodeKeyLayoutData);
|
||||
}
|
||||
}
|
||||
if layout.is_null() {
|
||||
if !keyboard.is_null() {
|
||||
CFRelease(keyboard);
|
||||
}
|
||||
return (null_mut(), null_mut());
|
||||
}
|
||||
let layout_ptr = CFDataGetBytePtr(layout as _);
|
||||
if layout_ptr.is_null() {
|
||||
if !keyboard.is_null() {
|
||||
CFRelease(keyboard);
|
||||
}
|
||||
return (null_mut(), null_mut());
|
||||
}
|
||||
(keyboard, layout_ptr)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get_map(name: &str, layout: *const u8) -> Map<char, CGKeyCode> {
|
||||
log::info!("Create keyboard map for {}", name);
|
||||
let mut keys_down: u32 = 0;
|
||||
let mut map = Map::new();
|
||||
for keycode in 0..128 {
|
||||
let mut buff = [0_u16; BUF_LEN];
|
||||
let kb_type = unsafe { LMGetKbdType() };
|
||||
let mut length: UniCharCount = 0;
|
||||
let _retval = unsafe {
|
||||
UCKeyTranslate(
|
||||
layout,
|
||||
keycode,
|
||||
kUCKeyActionDisplay as _,
|
||||
0,
|
||||
kb_type as _,
|
||||
kUCKeyTranslateDeadKeysBit as _,
|
||||
&mut keys_down,
|
||||
BUF_LEN,
|
||||
&mut length,
|
||||
&mut buff,
|
||||
)
|
||||
};
|
||||
if length > 0 {
|
||||
if let Ok(str) = String::from_utf16(&buff[..length]) {
|
||||
if let Some(chr) = str.chars().next() {
|
||||
map.insert(chr, keycode as _);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
map
|
||||
}
|
||||
unsafe impl Send for Enigo {}
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/dd375731
|
||||
//
|
||||
// JP/KR mapping https://github.com/TigerVNC/tigervnc/blob/1a008c1380305648ab50f1d99e73439747e9d61d/vncviewer/win32.c#L267
|
||||
// altgr handle: https://github.com/TigerVNC/tigervnc/blob/dccb95f345f7a9c5aa785a19d1bfa3fdecd8f8e0/vncviewer/Viewport.cxx#L1066
|
||||
|
||||
pub const EVK_RETURN: u16 = 0x0D;
|
||||
pub const EVK_TAB: u16 = 0x09;
|
||||
|
||||
@@ -16,6 +16,7 @@ extern "system" {
|
||||
/// The main struct for handling the event emitting
|
||||
#[derive(Default)]
|
||||
pub struct Enigo;
|
||||
static mut LAYOUT: HKL = std::ptr::null_mut();
|
||||
|
||||
fn mouse_event(flags: u32, data: u32, dx: i32, dy: i32) -> DWORD {
|
||||
let mut input = INPUT {
|
||||
@@ -35,6 +36,18 @@ fn mouse_event(flags: u32, data: u32, dx: i32, dy: i32) -> DWORD {
|
||||
}
|
||||
|
||||
fn keybd_event(flags: u32, vk: u16, scan: u16) -> DWORD {
|
||||
let mut scan = scan;
|
||||
unsafe {
|
||||
// https://github.com/rustdesk/rustdesk/issues/366
|
||||
if scan == 0 {
|
||||
if LAYOUT.is_null() {
|
||||
let current_window_thread_id =
|
||||
GetWindowThreadProcessId(GetForegroundWindow(), std::ptr::null_mut());
|
||||
LAYOUT = GetKeyboardLayout(current_window_thread_id);
|
||||
}
|
||||
scan = MapVirtualKeyExW(vk as _, 0, LAYOUT) as _;
|
||||
}
|
||||
}
|
||||
let mut input = INPUT {
|
||||
type_: INPUT_KEYBOARD,
|
||||
u: unsafe {
|
||||
@@ -176,13 +189,13 @@ impl KeyboardControllable for Enigo {
|
||||
}
|
||||
|
||||
fn key_click(&mut self, key: Key) {
|
||||
let scancode = self.key_to_scancode(key);
|
||||
keybd_event(KEYEVENTF_SCANCODE, 0, scancode);
|
||||
keybd_event(KEYEVENTF_KEYUP | KEYEVENTF_SCANCODE, 0, scancode);
|
||||
let vk = self.key_to_keycode(key);
|
||||
keybd_event(0, vk, 0);
|
||||
keybd_event(KEYEVENTF_KEYUP, vk, 0);
|
||||
}
|
||||
|
||||
fn key_down(&mut self, key: Key) -> crate::ResultType {
|
||||
let res = keybd_event(KEYEVENTF_SCANCODE, 0, self.key_to_scancode(key));
|
||||
let res = keybd_event(0, self.key_to_keycode(key), 0);
|
||||
if res == 0 {
|
||||
let err = get_error();
|
||||
if !err.is_empty() {
|
||||
@@ -193,11 +206,7 @@ impl KeyboardControllable for Enigo {
|
||||
}
|
||||
|
||||
fn key_up(&mut self, key: Key) {
|
||||
keybd_event(
|
||||
KEYEVENTF_KEYUP | KEYEVENTF_SCANCODE,
|
||||
0,
|
||||
self.key_to_scancode(key),
|
||||
);
|
||||
keybd_event(KEYEVENTF_KEYUP, self.key_to_keycode(key), 0);
|
||||
}
|
||||
|
||||
fn get_key_state(&mut self, key: Key) -> bool {
|
||||
@@ -257,6 +266,9 @@ impl Enigo {
|
||||
}
|
||||
|
||||
fn key_to_keycode(&self, key: Key) -> u16 {
|
||||
unsafe {
|
||||
LAYOUT = std::ptr::null_mut();
|
||||
}
|
||||
// do not use the codes from crate winapi they're
|
||||
// wrongly typed with i32 instead of i16 use the
|
||||
// ones provided by win/keycodes.rs that are prefixed
|
||||
@@ -307,7 +319,6 @@ impl Enigo {
|
||||
Key::Numpad9 => EVK_NUMPAD9,
|
||||
Key::Cancel => EVK_CANCEL,
|
||||
Key::Clear => EVK_CLEAR,
|
||||
Key::Menu => EVK_MENU,
|
||||
Key::Pause => EVK_PAUSE,
|
||||
Key::Kana => EVK_KANA,
|
||||
Key::Hangul => EVK_HANGUL,
|
||||
@@ -345,23 +356,20 @@ impl Enigo {
|
||||
Key::Raw(raw_keycode) => raw_keycode,
|
||||
Key::Layout(c) => self.get_layoutdependent_keycode(c.to_string()),
|
||||
Key::Super | Key::Command | Key::Windows | Key::Meta => EVK_LWIN,
|
||||
_ => 0,
|
||||
}
|
||||
}
|
||||
|
||||
fn key_to_scancode(&self, key: Key) -> u16 {
|
||||
let keycode = self.key_to_keycode(key);
|
||||
unsafe { MapVirtualKeyW(keycode as u32, 0) as u16 }
|
||||
}
|
||||
|
||||
fn get_layoutdependent_keycode(&self, string: String) -> u16 {
|
||||
// get the first char from the string ignore the rest
|
||||
// ensure its not a multybyte char
|
||||
if let Some(chr) = string.chars().nth(0) {
|
||||
// NOTE VkKeyScanW uses the current keyboard layout
|
||||
// to specify a layout use VkKeyScanExW and GetKeyboardLayout
|
||||
// NOTE VkKeyScanW uses the current keyboard LAYOUT
|
||||
// to specify a LAYOUT use VkKeyScanExW and GetKeyboardLayout
|
||||
// or load one with LoadKeyboardLayoutW
|
||||
let keycode_and_shiftstate = unsafe { VkKeyScanW(chr as _) };
|
||||
let current_window_thread_id =
|
||||
unsafe { GetWindowThreadProcessId(GetForegroundWindow(), std::ptr::null_mut()) };
|
||||
unsafe { LAYOUT = GetKeyboardLayout(current_window_thread_id) };
|
||||
let keycode_and_shiftstate = unsafe { VkKeyScanExW(chr as _, LAYOUT) };
|
||||
keycode_and_shiftstate as _
|
||||
} else {
|
||||
0
|
||||
|
||||
@@ -7,27 +7,29 @@ edition = "2018"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
protobuf = { version = "3.0.0-pre", git = "https://github.com/stepancheg/rust-protobuf" }
|
||||
tokio = { version = "0.2", features = ["full"] }
|
||||
tokio-util = { version = "0.3", features = ["full"] }
|
||||
protobuf = "3.0.0-alpha.2"
|
||||
tokio = { version = "1.15", features = ["full"] }
|
||||
tokio-util = { version = "0.6", features = ["full"] }
|
||||
futures = "0.3"
|
||||
bytes = "0.5"
|
||||
bytes = "1.1"
|
||||
log = "0.4"
|
||||
env_logger = "0.8"
|
||||
env_logger = "0.9"
|
||||
socket2 = { version = "0.3", features = ["reuseport"] }
|
||||
zstd = "0.5"
|
||||
quinn = {version = "0.6", optional = true }
|
||||
zstd = "0.9"
|
||||
quinn = {version = "0.8", optional = true }
|
||||
anyhow = "1.0"
|
||||
futures-util = "0.3"
|
||||
directories-next = "2.0"
|
||||
rand = "0.7"
|
||||
rand = "0.8"
|
||||
serde_derive = "1.0"
|
||||
serde = "1.0"
|
||||
lazy_static = "1.4"
|
||||
confy = { path = "../confy" }
|
||||
confy = { git = "https://github.com/open-trade/confy" }
|
||||
dirs-next = "2.0"
|
||||
filetime = "0.2"
|
||||
sodiumoxide = "0.2"
|
||||
regex = "1.4"
|
||||
tokio-socks = { git = "https://github.com/open-trade/tokio-socks" }
|
||||
|
||||
[target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies]
|
||||
mac_address = "1.1"
|
||||
@@ -36,7 +38,7 @@ mac_address = "1.1"
|
||||
quic = ["quinn"]
|
||||
|
||||
[build-dependencies]
|
||||
protobuf-codegen-pure = { version = "3.0.0-pre", git = "https://github.com/stepancheg/rust-protobuf" }
|
||||
protobuf-codegen-pure = "3.0.0-alpha.2"
|
||||
|
||||
[target.'cfg(target_os = "windows")'.dependencies]
|
||||
winapi = { version = "0.3", features = ["winuser"] }
|
||||
|
||||
@@ -25,6 +25,11 @@ message VideoFrame {
|
||||
}
|
||||
}
|
||||
|
||||
message IdPk {
|
||||
string id = 1;
|
||||
bytes pk = 2;
|
||||
}
|
||||
|
||||
message DisplayInfo {
|
||||
sint32 x = 1;
|
||||
sint32 y = 2;
|
||||
@@ -54,6 +59,7 @@ message LoginRequest {
|
||||
FileTransfer file_transfer = 7;
|
||||
PortForward port_forward = 8;
|
||||
}
|
||||
bool video_ack_required = 9;
|
||||
}
|
||||
|
||||
message ChatMessage { string text = 1; }
|
||||
@@ -83,6 +89,7 @@ message MouseEvent {
|
||||
}
|
||||
|
||||
enum ControlKey {
|
||||
Unknown = 0;
|
||||
Alt = 1;
|
||||
Backspace = 2;
|
||||
CapsLock = 3;
|
||||
@@ -108,7 +115,7 @@ enum ControlKey {
|
||||
/// meta key (also known as "windows"; "super"; and "command")
|
||||
Meta = 23;
|
||||
/// option key on macOS (alt key on Linux and Windows)
|
||||
Option = 24;
|
||||
Option = 24; // deprecated, use Alt instead
|
||||
PageDown = 25;
|
||||
PageUp = 26;
|
||||
Return = 27;
|
||||
@@ -157,7 +164,7 @@ enum ControlKey {
|
||||
Divide = 70;
|
||||
Equals = 71;
|
||||
NumpadEnter = 72;
|
||||
RShift= 73;
|
||||
RShift = 73;
|
||||
RControl = 74;
|
||||
RAlt = 75;
|
||||
CtrlAltDel = 100;
|
||||
@@ -193,15 +200,15 @@ message CursorPosition {
|
||||
message Hash {
|
||||
string salt = 1;
|
||||
string challenge = 2;
|
||||
};
|
||||
}
|
||||
|
||||
message Clipboard {
|
||||
bool compress = 1;
|
||||
bytes content = 2;
|
||||
};
|
||||
}
|
||||
|
||||
enum FileType {
|
||||
Dir = 1;
|
||||
Dir = 0;
|
||||
DirLink = 2;
|
||||
DirDrive = 3;
|
||||
File = 4;
|
||||
@@ -304,6 +311,69 @@ message FileDirCreate {
|
||||
string path = 2;
|
||||
}
|
||||
|
||||
// main logic from freeRDP
|
||||
message CliprdrMonitorReady {
|
||||
int32 conn_id = 1;
|
||||
}
|
||||
|
||||
message CliprdrFormat {
|
||||
int32 conn_id = 1;
|
||||
int32 id = 2;
|
||||
string format = 3;
|
||||
}
|
||||
|
||||
message CliprdrServerFormatList {
|
||||
int32 conn_id = 1;
|
||||
repeated CliprdrFormat formats = 2;
|
||||
}
|
||||
|
||||
message CliprdrServerFormatListResponse {
|
||||
int32 conn_id = 1;
|
||||
int32 msg_flags = 2;
|
||||
}
|
||||
|
||||
message CliprdrServerFormatDataRequest {
|
||||
int32 conn_id = 1;
|
||||
int32 requested_format_id = 2;
|
||||
}
|
||||
|
||||
message CliprdrServerFormatDataResponse {
|
||||
int32 conn_id = 1;
|
||||
int32 msg_flags = 2;
|
||||
bytes format_data = 3;
|
||||
}
|
||||
|
||||
message CliprdrFileContentsRequest {
|
||||
int32 conn_id = 1;
|
||||
int32 stream_id = 2;
|
||||
int32 list_index = 3;
|
||||
int32 dw_flags = 4;
|
||||
int32 n_position_low = 5;
|
||||
int32 n_position_high = 6;
|
||||
int32 cb_requested = 7;
|
||||
bool have_clip_data_id = 8;
|
||||
int32 clip_data_id = 9;
|
||||
}
|
||||
|
||||
message CliprdrFileContentsResponse {
|
||||
int32 conn_id = 1;
|
||||
int32 msg_flags = 3;
|
||||
int32 stream_id = 4;
|
||||
bytes requested_data = 5;
|
||||
}
|
||||
|
||||
message Cliprdr {
|
||||
oneof union {
|
||||
CliprdrMonitorReady ready = 1;
|
||||
CliprdrServerFormatList format_list = 2;
|
||||
CliprdrServerFormatListResponse format_list_response = 3;
|
||||
CliprdrServerFormatDataRequest format_data_request = 4;
|
||||
CliprdrServerFormatDataResponse format_data_response = 5;
|
||||
CliprdrFileContentsRequest file_contents_request = 6;
|
||||
CliprdrFileContentsResponse file_contents_response = 7;
|
||||
}
|
||||
}
|
||||
|
||||
message SwitchDisplay {
|
||||
int32 display = 1;
|
||||
sint32 x = 2;
|
||||
@@ -312,13 +382,14 @@ message SwitchDisplay {
|
||||
int32 height = 5;
|
||||
}
|
||||
|
||||
enum Permission {
|
||||
Keyboard = 1;
|
||||
Clipboard = 2;
|
||||
Audio = 3;
|
||||
}
|
||||
|
||||
message PermissionInfo {
|
||||
enum Permission {
|
||||
Keyboard = 0;
|
||||
Clipboard = 2;
|
||||
Audio = 3;
|
||||
File = 4;
|
||||
}
|
||||
|
||||
Permission permission = 1;
|
||||
bool enabled = 2;
|
||||
}
|
||||
@@ -330,13 +401,12 @@ enum ImageQuality {
|
||||
Best = 4;
|
||||
}
|
||||
|
||||
enum BoolOption {
|
||||
NotSet = 0;
|
||||
No = 1;
|
||||
Yes = 2;
|
||||
}
|
||||
|
||||
message OptionMessage {
|
||||
enum BoolOption {
|
||||
NotSet = 0;
|
||||
No = 1;
|
||||
Yes = 2;
|
||||
}
|
||||
ImageQuality image_quality = 1;
|
||||
BoolOption lock_after_session_end = 2;
|
||||
BoolOption show_remote_cursor = 3;
|
||||
@@ -345,6 +415,12 @@ message OptionMessage {
|
||||
int32 custom_image_quality = 6;
|
||||
BoolOption disable_audio = 7;
|
||||
BoolOption disable_clipboard = 8;
|
||||
BoolOption enable_file_transfer = 9;
|
||||
}
|
||||
|
||||
message OptionResponse {
|
||||
OptionMessage opt = 1;
|
||||
string error = 2;
|
||||
}
|
||||
|
||||
message TestDelay {
|
||||
@@ -357,10 +433,7 @@ message PublicKey {
|
||||
bytes symmetric_value = 2;
|
||||
}
|
||||
|
||||
message SignedId {
|
||||
bytes id = 1;
|
||||
bytes pk = 2;
|
||||
}
|
||||
message SignedId { bytes id = 1; }
|
||||
|
||||
message AudioFormat {
|
||||
uint32 sample_rate = 1;
|
||||
@@ -378,6 +451,8 @@ message Misc {
|
||||
AudioFormat audio_format = 8;
|
||||
string close_reason = 9;
|
||||
bool refresh_video = 10;
|
||||
OptionResponse option_response = 11;
|
||||
bool video_received = 12;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -400,5 +475,6 @@ message Message {
|
||||
FileAction file_action = 17;
|
||||
FileResponse file_response = 18;
|
||||
Misc misc = 19;
|
||||
Cliprdr cliprdr = 20;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,11 +6,19 @@ message RegisterPeer {
|
||||
int32 serial = 2;
|
||||
}
|
||||
|
||||
enum ConnType {
|
||||
DEFAULT_CONN = 0;
|
||||
FILE_TRANSFER = 1;
|
||||
PORT_FORWARD = 2;
|
||||
RDP = 3;
|
||||
}
|
||||
|
||||
message RegisterPeerResponse { bool request_pk = 2; }
|
||||
|
||||
message PunchHoleRequest {
|
||||
string id = 1;
|
||||
NatType nat_type = 2;
|
||||
ConnType conn_type = 4;
|
||||
}
|
||||
|
||||
message PunchHole {
|
||||
@@ -40,6 +48,7 @@ message PunchHoleSent {
|
||||
string id = 2;
|
||||
string relay_server = 3;
|
||||
NatType nat_type = 4;
|
||||
string version = 5;
|
||||
}
|
||||
|
||||
message RegisterPk {
|
||||
@@ -50,8 +59,13 @@ message RegisterPk {
|
||||
|
||||
message RegisterPkResponse {
|
||||
enum Result {
|
||||
OK = 1;
|
||||
OK = 0;
|
||||
UUID_MISMATCH = 2;
|
||||
ID_EXISTS = 3;
|
||||
TOO_FREQUENT = 4;
|
||||
INVALID_ID_FORMAT = 5;
|
||||
NOT_SUPPORT = 6;
|
||||
SERVER_ERROR = 7;
|
||||
}
|
||||
Result result = 1;
|
||||
}
|
||||
@@ -60,8 +74,10 @@ message PunchHoleResponse {
|
||||
bytes socket_addr = 1;
|
||||
bytes pk = 2;
|
||||
enum Failure {
|
||||
ID_NOT_EXIST = 1;
|
||||
ID_NOT_EXIST = 0;
|
||||
OFFLINE = 2;
|
||||
LICENSE_MISMATCH = 3;
|
||||
LICENSE_OVERUSE = 4;
|
||||
}
|
||||
Failure failure = 3;
|
||||
string relay_server = 4;
|
||||
@@ -69,6 +85,7 @@ message PunchHoleResponse {
|
||||
NatType nat_type = 5;
|
||||
bool is_local = 6;
|
||||
}
|
||||
string other_failure = 7;
|
||||
}
|
||||
|
||||
message ConfigUpdate {
|
||||
@@ -82,6 +99,7 @@ message RequestRelay {
|
||||
bytes socket_addr = 3;
|
||||
string relay_server = 4;
|
||||
bool secure = 5;
|
||||
ConnType conn_type = 7;
|
||||
}
|
||||
|
||||
message RelayResponse {
|
||||
@@ -92,6 +110,8 @@ message RelayResponse {
|
||||
string id = 4;
|
||||
bytes pk = 5;
|
||||
}
|
||||
string refuse_reason = 6;
|
||||
string version = 7;
|
||||
}
|
||||
|
||||
message SoftwareUpdate { string url = 1; }
|
||||
@@ -110,6 +130,17 @@ message LocalAddr {
|
||||
bytes local_addr = 2;
|
||||
string relay_server = 3;
|
||||
string id = 4;
|
||||
string version = 5;
|
||||
}
|
||||
|
||||
message PeerDiscovery {
|
||||
string cmd = 1;
|
||||
string mac = 2;
|
||||
string id = 3;
|
||||
string username = 4;
|
||||
string hostname = 5;
|
||||
string platform = 6;
|
||||
string misc = 7;
|
||||
}
|
||||
|
||||
message RendezvousMessage {
|
||||
@@ -130,5 +161,6 @@ message RendezvousMessage {
|
||||
RelayResponse relay_response = 19;
|
||||
TestNatRequest test_nat_request = 20;
|
||||
TestNatResponse test_nat_response = 21;
|
||||
PeerDiscovery peer_discovery = 22;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,26 +6,23 @@ use sodiumoxide::crypto::sign;
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
fs,
|
||||
net::SocketAddr,
|
||||
net::{IpAddr, Ipv4Addr, SocketAddr},
|
||||
path::{Path, PathBuf},
|
||||
sync::{Arc, Mutex, RwLock},
|
||||
time::SystemTime,
|
||||
};
|
||||
|
||||
pub const APP_NAME: &str = "RustDesk";
|
||||
pub const BIND_INTERFACE: &str = "0.0.0.0";
|
||||
pub const RENDEZVOUS_TIMEOUT: u64 = 12_000;
|
||||
pub const CONNECT_TIMEOUT: u64 = 18_000;
|
||||
pub const REG_INTERVAL: i64 = 12_000;
|
||||
pub const COMPRESS_LEVEL: i32 = 3;
|
||||
const SERIAL: i32 = 0;
|
||||
const SERIAL: i32 = 1;
|
||||
// 128x128
|
||||
#[cfg(target_os = "macos")] // 128x128 on 160x160 canvas, then shrink to 128, mac looks better with padding
|
||||
pub const ICON: &str = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAMAAAD04JH5AAAAyVBMVEUAAAAAcf8Acf8Acf8Acv8Acf8Acf8Acf8Acf8AcP8Acf8Ab/8AcP8Acf////8AaP/z+f/o8v/k7v/5/v/T5f8AYP/u9v/X6f+hx/+Kuv95pP8Aef/B1/+TwP9xoP8BdP/g6P+Irv9ZmP8Bgf/E3f98q/9sn/+01f+Es/9nm/9Jif8hhv8off/M4P+syP+avP86iP/c7f+xy/9yqf9Om/9hk/9Rjv+60P99tv9fpf88lv8yjf8Tgf8deP+kvP8BiP8NeP8hkP80gP8oj2VLAAAADXRSTlMA7o7qLvnaxZ1FOxYPjH9HWgAABHJJREFUeNrtm+tW4jAQgBfwuu7MtIUWsOUiCCioIIgLiqvr+z/UHq/LJKVkmwTcc/r9E2nzlU4mSTP9lpGRkZGR8VX5cZjfL+yCEXYL+/nDH//U/Pd8DgyTy39Xbv7oIAcWyB0cqbW/sweW2NtRaj8H1sgpGOwUIAH7Bkd7YJW9dXFwAJY5WNP/cmCZQnJvzIN18on5LwfWySXlxEPYAIcad8D6PdiHDbCfIFCADVBIENiFDbCbIACKPPXrZ+cP8E6/0znvP4EymgIEravIRcTxu8HxNSJ60a8W0AYECKrlAN+YwAthCd9wm1Ug6wKzIn5SgRduXfwkqDasCjx0XFzi9PV6zwNcIuhcWBOg+ikySq8C9UD4dEKWBCoOcspvAuLHTo9sCDQiFPHotRM48j8G5gVur1FdAN2uaYEuiz7xFsgEJ2RUoMUakXuBTHHoGxQYOBhHjeUBAefEnMAowFhaLBOKuOemBBbxLRQrH2PBCgMvNCPQGMeevTb9zLrPxz2Mo+QbEaijzPUcOOHMQZkKGRAIPem39+bypREMPTkQW/oCfk866zAkiIFG4yIKRE/aAnfiSd0WrORY6pFdXQEqi9mvAQm0RIOSnoCcZ8vJoz3diCnjRk+g8VP4/fuQDJ2Lxr6WwG0gXs9aTpDzW0vgDBlVUpixR8gYk44AD8FrUKHr8JQJGgIDnoDqoALxmWPQSi9AVVzm8gKUuEPGr/QCvptwJkbSYT/TC4S8C96DGjTj86aHtAI0x2WaBIq0eSYYpRa4EsdWVVwWu9O0Aj6f6dyBMnwEraeOgSYu0wZlauzA47QCbT7DgAQSE+hZWoEBF/BBmWOewNMK3BsSqKUW4MGcWqCSVmDkbvkXGKQOwg6PAUO9oL3xXhA20yaiCjuwYygRVQlUOTWTCf2SuNJTxeFjgaHByGuAIvd8ItdPLTDhS7IuqEE1YSKVOgbayLhSFQhMzYh8hwfBs1r7c505YVIQYEdNoKwxK06MJiyrpUFHiF0NAfCQUVHoiRclIXJIR6C2fqG37pBHvcWpgwzvAtYwkR5UGV2e42UISdBJETl3mg8ouo54Rcnti1/vaT+iuUQBt500Cgo4U10BeHSkk57FB0JjWkKRMWgLUA0lLodtImAQdaMiiri3+gIAPZQoutHNsgKF1aaDMhMyIdBf8Th+Bh8MTjGWCpl5Wv43tDmnF+IUVMrcZgRoiAxhtrloYizNkZaAnF5leglbNhj0wYCAbCDvGb0mP4nib7O7ZlcYQ2m1gPtIZgVgGNNMeaVAaWR+57TrqgtUnm3sHQ+kYeE6fufUubG1ez50FXbPnWgBlgSABmN3TTcsRl2yWkHRrwbiunvk/W2+Mg1hPZplPDeXRbZzStFH15s1QIVd3UImP5z/bHpeeQLvRJ7XLFUffQIlCvqlXETQbgN9/rlYABGosv+Vi9m2Xs639YLGrZd0br+odetlvdsvbN56abfd4vbCzv9Q3v/ygoOV21A4OPpfXvH4Ai+5ZGRkZGRkbJA/t/I0QMzoMiEAAAAASUVORK5CYII=
|
||||
";
|
||||
#[cfg(windows)] // windows, 32x32, bigger very ugly after shrink
|
||||
pub const ICON: &str = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAAolBMVEUAAAAAcf8Acf8Acf8AcP8Acf8Acf8Acf8AcP8Acf/////9/v/7/f+gyv9wr/8Ld/8GdP/A3P+nzv+Qwf9mqv8lhv8UfP+Kvv88k/8zjv/x+P/Y6f/U5//J4f/F3/+x1P+pz/+izP+Cuv9Zov9Qnv9FmP8gg//f7f+42P96tv9fpv8ui//1+f/q8//o8v/Q5f+ax/+Zxv+VxP+Fu/9rrf8rif+x1o3FAAAACXRSTlMAv/RPTPKHioRsIqhAAAABNklEQVQ4y4WT6XaCQAyFB7S2GUD2RaxSKGDV7sv7v1on4djEluL9Ncn5biaZk1FKzSwbRmVbM2V0DRNaGD9Maq6sacBS9jRwpUTw1Ww7SEOvkwQDaeVofQeJ1nrXjgD3pTaqCDCg/xs4OBrlwUGTHvxzoHAx69Y9+Hk5oGdAsCNXSoHfEN1JYEme4KcfvO9WAmtMBNx6jIaCgSPGLbAyvKRhAEcrAxAKTSZiACu+gNSbyWwZeKdQKj91yRXWIOWZTMgATun6EtjgczNQaKMEWD0+xJ6B4AnvECVqdKwYoJ50hIPyw25AANkzpsLB00cYOIUEoHU0uVaQVcMxBwlgVZJ3Orz+3ahH6gP2tBgfYzsZmdo1fGIzRx5Irn2WxKaHeJnKtb/4cS5/PbWACd0oo/n/39/4vwGFYSxtSYV4OAAAAABJRU5ErkJggg==
|
||||
";
|
||||
#[cfg(target_os = "linux")] // 128x128 no padding
|
||||
#[cfg(not(target_os = "macos"))] // 128x128 no padding
|
||||
pub const ICON: &str = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAMAAAD04JH5AAAA7VBMVEUAAAAAcf8Acf8Acf8Adf8Acf8Acf8AcP8Acv8AcP8Acf8Acf8Acf8Acv8Acf8Acf8Ab/8AcP8Acf8Acf8Acf/////7/f8Dc/8TfP/1+f/n8v9Hmf/u9v+Uw//Q5f9hp/8Yfv8Qev8Ld/+52P+z1f+s0f81j/8wjP8Hdf/3+/8mh/8fg//x9//h7//H4P9xsP9rrf9oq/8rif/r9P/D3v+92/+Duv9bpP/d7f/U5/9NnP8/lP8jhP/L4v/B3P+OwP9+t/95tf9Rn/8bgf/Z6v+Zx/90sv9lqf85kf+hy/9UoP+Wxf+kzP+dyP+Lvv/H4q8IAAAAFHRSTlMA+u6bB6x5XR4V0+S4i4k5N+a81W8MiAQAAAVcSURBVHjazdvpWtpAGIbhgEutdW3fL2GHsMsiq4KI+66t5384XahF/GbizJAy3j/1Ah5CJhNCxpm1vbryLRrBfxKJrq+sbjtSa5u7WIDdzTVH5PNSBAsSWfrsMJ+iWKDoJ2fW8hIWbGl55vW/YuE2XhUsb8CCr9OCJVix9G//gyWf/o6/KCyJfrbwAfAPYS0CayK/j4mbsGjrV8AXWLTrONuwasdZhVWrzgqsWnG+wap1Jwqrok4EVkUcmKhdVvBaOVnzYEY/oJpMD4mo6ONF/ZSIUsX2FZjQA7xRqUET+y/v2W/Sy59u62DCDMgdJmhqgIk7eqWQBBNWwPhmj147w8QTzTjKVsGEEBBLuzSrhIkivTF8DD/Aa6forQNMHBD/VyXkgHGfuBN5ALln1TADOnESyGCiT8L/1kILqD6Q0BEm9kkofhdSwNUJiV1jQvZ/SnthBNSaJJGZbgGJUnX+gEqCZPpsJ2T2Y/MGVBrE8eOAvCA/X8A4QXLnmEhTgIPqPAG5IQU4fhmkFOT7HAFenwIU8Jd/TUEODQIUtu1eOj/dUD9cknOTpgEDkup3YrOfVStDUomcWcBVisTiNxVw3TPpgCl4RgFFybZ/9iHmn8uS2yYBA8m7qUEu9oOEejH9gHxC+PazCHbcFM8K+gGHJNAs4z2xgnAkVHQDcnG1IzvnCSfvom7AM3EZ9voah4+KXoAvGFJHMSgqEfegF3BBTKoOVfkMMXFfJ8AT7MuXUDeOE9PWCUiKBpKOlmAP1gngH2LChw7vhJgr9YD8Hnt0BxrE27CtHnDJR4AHTX1+KFAP4Ef0LHTxN9HwlAMSbAjmoavKZ8ayakDXYAhwN3wzqgZk2UPvwRjshmeqATeCT09f3mWnEqoBGf4NxAB/moRqADuOtmDiid6KqQVcsQeOYOKW3uqqBRwL5nITj/yrlFpAVrDpTJT5llQLaLMHwshY7UDgvD+VujDC96WWWsBtSAE5FnChFnAeUkDMdAvw88EqTNT5SYXpTlgPaRQM1AIGorkolNnoUS1gJHigCX48SaoF3Asuspg4Mz0U8+FTgIkCG01V09kwBQP8xG5ofD5AXeirkPEJSUlwSVIfP5ykVQNaggvz+k7prTvVgDKF8BnUXP4kqgEe/257E8Ig7EE1gA8g2stBTz7FLxqrB3SIeYaeQ2IG6gE5l2+Cmt5MGOfP4KsGiH8DOYWOoujnDY2ALHF3810goZFOQDVBTFx9Uj7eI6bp6QTgnLjeGGq6KeJuoRUQixN3pDYWyz1Rva8XIL5UPFQZCsmG3gV7R+dieS+Jd3iHLglce7oBuCOhp3zwHLxPQpfQDvBOSKjZqUIml3ZJ6AD6AajFSZJwewWR8ZPsEY26SQDaJOMeZP23w6bTJ6kBjAJQILm9hzqm7otu4G+nhgGxIQUlPLKzL7GhbxqAboMCuN2XXd+lAL0ajAMwclV+FD6jAPEy5ghAlhfwX2FODX445gHKxyN++fs64PUHmDMAbbYN2DlKk2QaScwdgMs4SZxMv4OJJSoIIQBl2Qtk3gk4qiOUANRPJQHB+0A6j5AC4J27QQEZ4eZPAsYBXFk0N/YD7iUrxRBqALxOTzoMC3x8lCFlfkMjuz8iLfk6fzQCQgjg8q3ZEd8RzUVuKelBh96Nzcc3qelL1V+2zfRv1xc56Ino3tpdPT7cd//MspfTrD/7R6p4W4O2qLMObfnyIHvvYcrPtkZjDybW7d/eb32Bg/UlHnYXuXz5CMt8rC90sr7Uy/5iN+vL/ewveLS/5NNKwcbyR1r2a3/h8wdY+v3L2tZC5oUvW2uO1M7qyvp/Xv6/48z4CTxjJEfyjEaMAAAAAElFTkSuQmCC
|
||||
";
|
||||
#[cfg(target_os = "macos")]
|
||||
@@ -36,6 +33,7 @@ type Size = (i32, i32, i32, i32);
|
||||
lazy_static::lazy_static! {
|
||||
static ref CONFIG: Arc<RwLock<Config>> = Arc::new(RwLock::new(Config::load()));
|
||||
static ref CONFIG2: Arc<RwLock<Config2>> = Arc::new(RwLock::new(Config2::load()));
|
||||
static ref LOCAL_CONFIG: Arc<RwLock<LocalConfig>> = Arc::new(RwLock::new(LocalConfig::load()));
|
||||
pub static ref ONLINE: Arc<Mutex<HashMap<String, i64>>> = Default::default();
|
||||
}
|
||||
#[cfg(any(target_os = "android", target_os = "ios"))]
|
||||
@@ -48,13 +46,20 @@ const CHARS: &'static [char] = &[
|
||||
];
|
||||
|
||||
pub const RENDEZVOUS_SERVERS: &'static [&'static str] = &[
|
||||
"rs-ny.rustdesk.com",
|
||||
"rs-sg.rustdesk.com",
|
||||
"rs-cn.rustdesk.com",
|
||||
];
|
||||
pub const RENDEZVOUS_PORT: i32 = 21116;
|
||||
pub const RELAY_PORT: i32 = 21117;
|
||||
|
||||
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||
pub enum NetworkType {
|
||||
Direct,
|
||||
ProxySocks,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
|
||||
pub struct Config {
|
||||
#[serde(default)]
|
||||
id: String,
|
||||
@@ -70,13 +75,19 @@ pub struct Config {
|
||||
keys_confirmed: HashMap<String, bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, PartialEq, Serialize, Deserialize, Clone)]
|
||||
pub struct Socks5Server {
|
||||
#[serde(default)]
|
||||
pub proxy: String,
|
||||
#[serde(default)]
|
||||
pub username: String,
|
||||
#[serde(default)]
|
||||
pub password: String,
|
||||
}
|
||||
|
||||
// more variable configs
|
||||
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
|
||||
#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
|
||||
pub struct Config2 {
|
||||
#[serde(default)]
|
||||
remote_id: String, // latest used one
|
||||
#[serde(default)]
|
||||
size: Size,
|
||||
#[serde(default)]
|
||||
rendezvous_server: String,
|
||||
#[serde(default)]
|
||||
@@ -84,6 +95,9 @@ pub struct Config2 {
|
||||
#[serde(default)]
|
||||
serial: i32,
|
||||
|
||||
#[serde(default)]
|
||||
socks: Option<Socks5Server>,
|
||||
|
||||
// the other scalar value must before this
|
||||
#[serde(default)]
|
||||
pub options: HashMap<String, String>,
|
||||
@@ -119,6 +133,8 @@ pub struct PeerConfig {
|
||||
pub disable_audio: bool,
|
||||
#[serde(default)]
|
||||
pub disable_clipboard: bool,
|
||||
#[serde(default)]
|
||||
pub enable_file_transfer: bool,
|
||||
|
||||
// the other scalar value must before this
|
||||
#[serde(default)]
|
||||
@@ -152,7 +168,10 @@ fn patch(path: PathBuf) -> PathBuf {
|
||||
{
|
||||
if _tmp == "/root" {
|
||||
if let Ok(output) = std::process::Command::new("whoami").output() {
|
||||
let user = String::from_utf8_lossy(&output.stdout).to_string().trim().to_owned();
|
||||
let user = String::from_utf8_lossy(&output.stdout)
|
||||
.to_string()
|
||||
.trim()
|
||||
.to_owned();
|
||||
if user != "root" {
|
||||
return format!("/home/{}", user).into();
|
||||
}
|
||||
@@ -168,9 +187,23 @@ impl Config2 {
|
||||
Config::load_::<Config2>("2")
|
||||
}
|
||||
|
||||
pub fn file() -> PathBuf {
|
||||
Config::file_("2")
|
||||
}
|
||||
|
||||
fn store(&self) {
|
||||
Config::store_(self, "2");
|
||||
}
|
||||
|
||||
pub fn get() -> Config2 {
|
||||
return CONFIG2.read().unwrap().clone();
|
||||
}
|
||||
|
||||
pub fn set(cfg: Config2) {
|
||||
let mut lock = CONFIG2.write().unwrap();
|
||||
*lock = cfg;
|
||||
lock.store();
|
||||
}
|
||||
}
|
||||
|
||||
impl Config {
|
||||
@@ -250,7 +283,7 @@ impl Config {
|
||||
}
|
||||
}
|
||||
|
||||
fn path<P: AsRef<Path>>(p: P) -> PathBuf {
|
||||
pub fn path<P: AsRef<Path>>(p: P) -> PathBuf {
|
||||
#[cfg(any(target_os = "android", target_os = "ios"))]
|
||||
{
|
||||
let mut path: PathBuf = APP_DIR.read().unwrap().clone().into();
|
||||
@@ -270,6 +303,7 @@ impl Config {
|
||||
return "".into();
|
||||
}
|
||||
|
||||
#[allow(unreachable_code)]
|
||||
pub fn log_path() -> PathBuf {
|
||||
#[cfg(target_os = "macos")]
|
||||
{
|
||||
@@ -322,10 +356,10 @@ impl Config {
|
||||
|
||||
#[inline]
|
||||
pub fn get_any_listen_addr() -> SocketAddr {
|
||||
format!("{}:0", BIND_INTERFACE).parse().unwrap()
|
||||
SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 0)
|
||||
}
|
||||
|
||||
pub fn get_rendezvous_server() -> SocketAddr {
|
||||
pub fn get_rendezvous_server() -> String {
|
||||
let mut rendezvous_server = Self::get_option("custom-rendezvous-server");
|
||||
if rendezvous_server.is_empty() {
|
||||
rendezvous_server = CONFIG2.write().unwrap().rendezvous_server.clone();
|
||||
@@ -339,11 +373,7 @@ impl Config {
|
||||
if !rendezvous_server.contains(":") {
|
||||
rendezvous_server = format!("{}:{}", rendezvous_server, RENDEZVOUS_PORT);
|
||||
}
|
||||
if let Ok(addr) = crate::to_socket_addr(&rendezvous_server) {
|
||||
addr
|
||||
} else {
|
||||
Self::get_any_listen_addr()
|
||||
}
|
||||
rendezvous_server
|
||||
}
|
||||
|
||||
pub fn get_rendezvous_servers() -> Vec<String> {
|
||||
@@ -483,6 +513,9 @@ impl Config {
|
||||
|
||||
pub fn set_key_pair(pair: (Vec<u8>, Vec<u8>)) {
|
||||
let mut config = CONFIG.write().unwrap();
|
||||
if config.key_pair == pair {
|
||||
return;
|
||||
}
|
||||
config.key_pair = pair;
|
||||
config.store();
|
||||
}
|
||||
@@ -515,6 +548,9 @@ impl Config {
|
||||
|
||||
pub fn set_options(v: HashMap<String, String>) {
|
||||
let mut config = CONFIG2.write().unwrap();
|
||||
if config.options == v {
|
||||
return;
|
||||
}
|
||||
config.options = v;
|
||||
config.store();
|
||||
}
|
||||
@@ -529,9 +565,6 @@ impl Config {
|
||||
|
||||
pub fn set_option(k: String, v: String) {
|
||||
let mut config = CONFIG2.write().unwrap();
|
||||
if k == "custom-rendezvous-server" {
|
||||
config.rendezvous_server = "".to_owned();
|
||||
}
|
||||
let v2 = if v.is_empty() { None } else { Some(&v) };
|
||||
if v2 != config.options.get(&k) {
|
||||
if v2.is_none() {
|
||||
@@ -547,7 +580,7 @@ impl Config {
|
||||
// to-do: how about if one ip register a lot of ids?
|
||||
let id = Self::get_id();
|
||||
let mut rng = rand::thread_rng();
|
||||
let new_id = rng.gen_range(1_000_000_000, 2_000_000_000).to_string();
|
||||
let new_id = rng.gen_range(1_000_000_000..2_000_000_000).to_string();
|
||||
Config::set_id(&new_id);
|
||||
log::info!("id updated from {} to {}", id, new_id);
|
||||
}
|
||||
@@ -588,31 +621,34 @@ impl Config {
|
||||
salt
|
||||
}
|
||||
|
||||
pub fn get_size() -> Size {
|
||||
CONFIG2.read().unwrap().size
|
||||
}
|
||||
|
||||
pub fn set_size(x: i32, y: i32, w: i32, h: i32) {
|
||||
pub fn set_socks(socks: Option<Socks5Server>) {
|
||||
let mut config = CONFIG2.write().unwrap();
|
||||
let size = (x, y, w, h);
|
||||
if size == config.size || size.2 < 300 || size.3 < 300 {
|
||||
if config.socks == socks {
|
||||
return;
|
||||
}
|
||||
config.size = size;
|
||||
config.socks = socks;
|
||||
config.store();
|
||||
}
|
||||
|
||||
pub fn set_remote_id(remote_id: &str) {
|
||||
let mut config = CONFIG2.write().unwrap();
|
||||
if remote_id == config.remote_id {
|
||||
return;
|
||||
}
|
||||
config.remote_id = remote_id.into();
|
||||
config.store();
|
||||
pub fn get_socks() -> Option<Socks5Server> {
|
||||
CONFIG2.read().unwrap().socks.clone()
|
||||
}
|
||||
|
||||
pub fn get_remote_id() -> String {
|
||||
CONFIG2.read().unwrap().remote_id.clone()
|
||||
pub fn get_network_type() -> NetworkType {
|
||||
match &CONFIG2.read().unwrap().socks {
|
||||
None => NetworkType::Direct,
|
||||
Some(_) => NetworkType::ProxySocks,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get() -> Config {
|
||||
return CONFIG.read().unwrap().clone();
|
||||
}
|
||||
|
||||
pub fn set(cfg: Config) {
|
||||
let mut lock = CONFIG.write().unwrap();
|
||||
*lock = cfg;
|
||||
lock.store();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -659,9 +695,7 @@ impl PeerConfig {
|
||||
&& p.extension().map(|p| p.to_str().unwrap_or("")) == Some("toml")
|
||||
})
|
||||
.map(|p| {
|
||||
let t = fs::metadata(p)
|
||||
.map(|m| m.modified().unwrap_or(SystemTime::UNIX_EPOCH))
|
||||
.unwrap_or(SystemTime::UNIX_EPOCH);
|
||||
let t = crate::get_modified_time(&p);
|
||||
let id = p
|
||||
.file_stem()
|
||||
.map(|p| p.to_str().unwrap_or(""))
|
||||
@@ -683,6 +717,123 @@ impl PeerConfig {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
|
||||
pub struct LocalConfig {
|
||||
#[serde(default)]
|
||||
remote_id: String, // latest used one
|
||||
#[serde(default)]
|
||||
size: Size,
|
||||
#[serde(default)]
|
||||
pub fav: Vec<String>,
|
||||
#[serde(default)]
|
||||
options: HashMap<String, String>,
|
||||
}
|
||||
|
||||
impl LocalConfig {
|
||||
fn load() -> LocalConfig {
|
||||
Config::load_::<LocalConfig>("_local")
|
||||
}
|
||||
|
||||
fn store(&self) {
|
||||
Config::store_(self, "_local");
|
||||
}
|
||||
|
||||
pub fn get_size() -> Size {
|
||||
LOCAL_CONFIG.read().unwrap().size
|
||||
}
|
||||
|
||||
pub fn set_size(x: i32, y: i32, w: i32, h: i32) {
|
||||
let mut config = LOCAL_CONFIG.write().unwrap();
|
||||
let size = (x, y, w, h);
|
||||
if size == config.size || size.2 < 300 || size.3 < 300 {
|
||||
return;
|
||||
}
|
||||
config.size = size;
|
||||
config.store();
|
||||
}
|
||||
|
||||
pub fn set_remote_id(remote_id: &str) {
|
||||
let mut config = LOCAL_CONFIG.write().unwrap();
|
||||
if remote_id == config.remote_id {
|
||||
return;
|
||||
}
|
||||
config.remote_id = remote_id.into();
|
||||
config.store();
|
||||
}
|
||||
|
||||
pub fn get_remote_id() -> String {
|
||||
LOCAL_CONFIG.read().unwrap().remote_id.clone()
|
||||
}
|
||||
|
||||
pub fn set_fav(fav: Vec<String>) {
|
||||
let mut lock = LOCAL_CONFIG.write().unwrap();
|
||||
if lock.fav == fav {
|
||||
return;
|
||||
}
|
||||
lock.fav = fav;
|
||||
lock.store();
|
||||
}
|
||||
|
||||
pub fn get_fav() -> Vec<String> {
|
||||
LOCAL_CONFIG.read().unwrap().fav.clone()
|
||||
}
|
||||
|
||||
pub fn get_option(k: &str) -> String {
|
||||
if let Some(v) = LOCAL_CONFIG.read().unwrap().options.get(k) {
|
||||
v.clone()
|
||||
} else {
|
||||
"".to_owned()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_option(k: String, v: String) {
|
||||
let mut config = LOCAL_CONFIG.write().unwrap();
|
||||
let v2 = if v.is_empty() { None } else { Some(&v) };
|
||||
if v2 != config.options.get(&k) {
|
||||
if v2.is_none() {
|
||||
config.options.remove(&k);
|
||||
} else {
|
||||
config.options.insert(k, v);
|
||||
}
|
||||
config.store();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
|
||||
pub struct LanPeers {
|
||||
#[serde(default)]
|
||||
pub peers: String,
|
||||
}
|
||||
|
||||
impl LanPeers {
|
||||
pub fn load() -> LanPeers {
|
||||
let _ = CONFIG.read().unwrap(); // for lock
|
||||
match confy::load_path(&Config::file_("_lan_peers")) {
|
||||
Ok(peers) => peers,
|
||||
Err(err) => {
|
||||
log::error!("Failed to load lan peers: {}", err);
|
||||
Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn store(peers: String) {
|
||||
let f = LanPeers { peers };
|
||||
if let Err(err) = confy::store_path(Config::file_("_lan_peers"), f) {
|
||||
log::error!("Failed to store lan peers: {}", err);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn modify_time() -> crate::ResultType<u64> {
|
||||
let p = Config::file_("_lan_peers");
|
||||
Ok(fs::metadata(p)?
|
||||
.modified()?
|
||||
.duration_since(SystemTime::UNIX_EPOCH)?
|
||||
.as_millis() as _)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
@@ -7,7 +7,7 @@ use crate::{
|
||||
};
|
||||
#[cfg(windows)]
|
||||
use std::os::windows::prelude::*;
|
||||
use tokio::{fs::File, prelude::*};
|
||||
use tokio::{fs::File, io::*};
|
||||
|
||||
pub fn read_dir(path: &PathBuf, include_hidden: bool) -> ResultType<FileDirectory> {
|
||||
let mut dir = FileDirectory {
|
||||
@@ -193,7 +193,7 @@ pub struct TransferJob {
|
||||
file: Option<File>,
|
||||
total_size: u64,
|
||||
finished_size: u64,
|
||||
transfered: u64,
|
||||
transferred: u64,
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@@ -268,8 +268,8 @@ impl TransferJob {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn transfered(&self) -> u64 {
|
||||
self.transfered
|
||||
pub fn transferred(&self) -> u64 {
|
||||
self.transferred
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@@ -302,7 +302,7 @@ impl TransferJob {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn write(&mut self, block: FileTransferBlock) -> ResultType<()> {
|
||||
pub async fn write(&mut self, block: FileTransferBlock, raw: Option<&[u8]>) -> ResultType<()> {
|
||||
if block.id != self.id {
|
||||
bail!("Wrong id");
|
||||
}
|
||||
@@ -324,15 +324,20 @@ impl TransferJob {
|
||||
let path = format!("{}.download", get_string(&path));
|
||||
self.file = Some(File::create(&path).await?);
|
||||
}
|
||||
let data = if let Some(data) = raw {
|
||||
data
|
||||
} else {
|
||||
&block.data
|
||||
};
|
||||
if block.compressed {
|
||||
let tmp = decompress(&block.data);
|
||||
let tmp = decompress(data);
|
||||
self.file.as_mut().unwrap().write_all(&tmp).await?;
|
||||
self.finished_size += tmp.len() as u64;
|
||||
} else {
|
||||
self.file.as_mut().unwrap().write_all(&block.data).await?;
|
||||
self.finished_size += block.data.len() as u64;
|
||||
self.file.as_mut().unwrap().write_all(data).await?;
|
||||
self.finished_size += data.len() as u64;
|
||||
}
|
||||
self.transfered += block.data.len() as u64;
|
||||
self.transferred += data.len() as u64;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -398,7 +403,7 @@ impl TransferJob {
|
||||
compressed = true;
|
||||
}
|
||||
}
|
||||
self.transfered += buf.len() as u64;
|
||||
self.transferred += buf.len() as u64;
|
||||
}
|
||||
Ok(Some(FileTransferBlock {
|
||||
id: self.id,
|
||||
|
||||
@@ -6,16 +6,16 @@ pub mod rendezvous_proto;
|
||||
pub use bytes;
|
||||
pub use futures;
|
||||
pub use protobuf;
|
||||
use socket2::{Domain, Socket, Type};
|
||||
use std::{
|
||||
fs::File,
|
||||
io::{self, BufRead},
|
||||
net::{Ipv4Addr, SocketAddr, SocketAddrV4, ToSocketAddrs},
|
||||
net::{Ipv4Addr, SocketAddr, SocketAddrV4},
|
||||
path::Path,
|
||||
time::{self, SystemTime, UNIX_EPOCH},
|
||||
};
|
||||
pub use tokio;
|
||||
pub use tokio_util;
|
||||
pub mod socket_client;
|
||||
pub mod tcp;
|
||||
pub mod udp;
|
||||
pub use env_logger;
|
||||
@@ -27,7 +27,14 @@ pub use anyhow::{self, bail};
|
||||
pub use futures_util;
|
||||
pub mod config;
|
||||
pub mod fs;
|
||||
pub use lazy_static;
|
||||
pub use mac_address;
|
||||
pub use rand;
|
||||
pub use regex;
|
||||
pub use sodiumoxide;
|
||||
pub use tokio_socks;
|
||||
pub use tokio_socks::IntoTargetAddr;
|
||||
pub use tokio_socks::TargetAddr;
|
||||
|
||||
#[cfg(feature = "quic")]
|
||||
pub type Stream = quic::Connection;
|
||||
@@ -36,7 +43,7 @@ pub type Stream = tcp::FramedStream;
|
||||
|
||||
#[inline]
|
||||
pub async fn sleep(sec: f32) {
|
||||
tokio::time::delay_for(time::Duration::from_secs_f32(sec)).await;
|
||||
tokio::time::sleep(time::Duration::from_secs_f32(sec)).await;
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
@@ -61,30 +68,6 @@ pub fn timeout<T: std::future::Future>(ms: u64, future: T) -> tokio::time::Timeo
|
||||
tokio::time::timeout(std::time::Duration::from_millis(ms), future)
|
||||
}
|
||||
|
||||
fn new_socket(addr: SocketAddr, tcp: bool, reuse: bool) -> Result<Socket, std::io::Error> {
|
||||
let stype = {
|
||||
if tcp {
|
||||
Type::stream()
|
||||
} else {
|
||||
Type::dgram()
|
||||
}
|
||||
};
|
||||
let socket = match addr {
|
||||
SocketAddr::V4(..) => Socket::new(Domain::ipv4(), stype, None),
|
||||
SocketAddr::V6(..) => Socket::new(Domain::ipv6(), stype, None),
|
||||
}?;
|
||||
if reuse {
|
||||
// windows has no reuse_port, but it's reuse_address
|
||||
// almost equals to unix's reuse_port + reuse_address,
|
||||
// though may introduce nondeterministic bahavior
|
||||
#[cfg(unix)]
|
||||
socket.set_reuse_port(true)?;
|
||||
socket.set_reuse_address(true)?;
|
||||
}
|
||||
socket.bind(&addr.into())?;
|
||||
Ok(socket)
|
||||
}
|
||||
|
||||
pub type ResultType<F, E = anyhow::Error> = anyhow::Result<F, E>;
|
||||
|
||||
/// Certain router and firewalls scan the packet and if they
|
||||
@@ -100,10 +83,10 @@ impl AddrMangle {
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.unwrap()
|
||||
.as_micros() as u32) as u128;
|
||||
let ip = u32::from_ne_bytes(addr_v4.ip().octets()) as u128;
|
||||
let ip = u32::from_le_bytes(addr_v4.ip().octets()) as u128;
|
||||
let port = addr.port() as u128;
|
||||
let v = ((ip + tm) << 49) | (tm << 17) | (port + (tm & 0xFFFF));
|
||||
let bytes = v.to_ne_bytes();
|
||||
let bytes = v.to_le_bytes();
|
||||
let mut n_padding = 0;
|
||||
for i in bytes.iter().rev() {
|
||||
if i == &0u8 {
|
||||
@@ -123,9 +106,9 @@ impl AddrMangle {
|
||||
pub fn decode(bytes: &[u8]) -> SocketAddr {
|
||||
let mut padded = [0u8; 16];
|
||||
padded[..bytes.len()].copy_from_slice(&bytes);
|
||||
let number = u128::from_ne_bytes(padded);
|
||||
let number = u128::from_le_bytes(padded);
|
||||
let tm = (number >> 17) & (u32::max_value() as u128);
|
||||
let ip = (((number >> 49) - tm) as u32).to_ne_bytes();
|
||||
let ip = (((number >> 49) - tm) as u32).to_le_bytes();
|
||||
let port = (number & 0xFFFFFF) - (tm & 0xFFFF);
|
||||
SocketAddr::V4(SocketAddrV4::new(
|
||||
Ipv4Addr::new(ip[0], ip[1], ip[2], ip[3]),
|
||||
@@ -172,14 +155,6 @@ pub fn get_version_from_url(url: &str) -> String {
|
||||
"".to_owned()
|
||||
}
|
||||
|
||||
pub fn to_socket_addr(host: &str) -> ResultType<SocketAddr> {
|
||||
let addrs: Vec<SocketAddr> = host.to_socket_addrs()?.collect();
|
||||
if addrs.is_empty() {
|
||||
bail!("Failed to solve {}", host);
|
||||
}
|
||||
Ok(addrs[0])
|
||||
}
|
||||
|
||||
pub fn gen_version() {
|
||||
let mut file = File::create("./src/version.rs").unwrap();
|
||||
for line in read_lines("Cargo.toml").unwrap() {
|
||||
@@ -204,6 +179,20 @@ where
|
||||
Ok(io::BufReader::new(file).lines())
|
||||
}
|
||||
|
||||
pub fn get_version_number(v: &str) -> i64 {
|
||||
let mut n = 0;
|
||||
for x in v.split(".") {
|
||||
n = n * 1000 + x.parse::<i64>().unwrap_or(0);
|
||||
}
|
||||
n
|
||||
}
|
||||
|
||||
pub fn get_modified_time(path: &std::path::Path) -> SystemTime {
|
||||
std::fs::metadata(&path)
|
||||
.map(|m| m.modified().unwrap_or(UNIX_EPOCH))
|
||||
.unwrap_or(UNIX_EPOCH)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
91
libs/hbb_common/src/socket_client.rs
Normal file
91
libs/hbb_common/src/socket_client.rs
Normal file
@@ -0,0 +1,91 @@
|
||||
use crate::{
|
||||
config::{Config, NetworkType},
|
||||
tcp::FramedStream,
|
||||
udp::FramedSocket,
|
||||
ResultType,
|
||||
};
|
||||
use anyhow::Context;
|
||||
use std::net::SocketAddr;
|
||||
use tokio::net::ToSocketAddrs;
|
||||
use tokio_socks::{IntoTargetAddr, TargetAddr};
|
||||
|
||||
fn to_socket_addr(host: &str) -> ResultType<SocketAddr> {
|
||||
use std::net::ToSocketAddrs;
|
||||
host.to_socket_addrs()?.next().context("Failed to solve")
|
||||
}
|
||||
|
||||
pub fn get_target_addr(host: &str) -> ResultType<TargetAddr<'static>> {
|
||||
let addr = match Config::get_network_type() {
|
||||
NetworkType::Direct => to_socket_addr(&host)?.into_target_addr()?,
|
||||
NetworkType::ProxySocks => host.into_target_addr()?,
|
||||
}
|
||||
.to_owned();
|
||||
Ok(addr)
|
||||
}
|
||||
|
||||
pub fn test_if_valid_server(host: &str) -> String {
|
||||
let mut host = host.to_owned();
|
||||
if !host.contains(":") {
|
||||
host = format!("{}:{}", host, 0);
|
||||
}
|
||||
|
||||
match Config::get_network_type() {
|
||||
NetworkType::Direct => match to_socket_addr(&host) {
|
||||
Err(err) => err.to_string(),
|
||||
Ok(_) => "".to_owned(),
|
||||
},
|
||||
NetworkType::ProxySocks => match &host.into_target_addr() {
|
||||
Err(err) => err.to_string(),
|
||||
Ok(_) => "".to_owned(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn connect_tcp<'t, T: IntoTargetAddr<'t>>(
|
||||
target: T,
|
||||
local: SocketAddr,
|
||||
ms_timeout: u64,
|
||||
) -> ResultType<FramedStream> {
|
||||
let target_addr = target.into_target_addr()?;
|
||||
|
||||
if let Some(conf) = Config::get_socks() {
|
||||
FramedStream::connect(
|
||||
conf.proxy.as_str(),
|
||||
target_addr,
|
||||
local,
|
||||
conf.username.as_str(),
|
||||
conf.password.as_str(),
|
||||
ms_timeout,
|
||||
)
|
||||
.await
|
||||
} else {
|
||||
let addr = std::net::ToSocketAddrs::to_socket_addrs(&target_addr)?
|
||||
.next()
|
||||
.context("Invalid target addr")?;
|
||||
Ok(FramedStream::new(addr, local, ms_timeout).await?)
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn new_udp<T: ToSocketAddrs>(local: T, ms_timeout: u64) -> ResultType<FramedSocket> {
|
||||
match Config::get_socks() {
|
||||
None => Ok(FramedSocket::new(local).await?),
|
||||
Some(conf) => {
|
||||
let socket = FramedSocket::new_proxy(
|
||||
conf.proxy.as_str(),
|
||||
local,
|
||||
conf.username.as_str(),
|
||||
conf.password.as_str(),
|
||||
ms_timeout,
|
||||
)
|
||||
.await?;
|
||||
Ok(socket)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn rebind_udp<T: ToSocketAddrs>(local: T) -> ResultType<Option<FramedSocket>> {
|
||||
match Config::get_network_type() {
|
||||
NetworkType::Direct => Ok(Some(FramedSocket::new(local).await?)),
|
||||
_ => Ok(None),
|
||||
}
|
||||
}
|
||||
@@ -1,22 +1,34 @@
|
||||
use crate::{bail, bytes_codec::BytesCodec, ResultType};
|
||||
use bytes::{BufMut, Bytes, BytesMut};
|
||||
use futures::SinkExt;
|
||||
use futures::{SinkExt, StreamExt};
|
||||
use protobuf::Message;
|
||||
use sodiumoxide::crypto::secretbox::{self, Key, Nonce};
|
||||
use std::{
|
||||
io::{Error, ErrorKind},
|
||||
io::{self, Error, ErrorKind},
|
||||
net::SocketAddr,
|
||||
ops::{Deref, DerefMut},
|
||||
pin::Pin,
|
||||
task::{Context, Poll},
|
||||
};
|
||||
use tokio::{
|
||||
net::{TcpListener, TcpStream, ToSocketAddrs},
|
||||
stream::StreamExt,
|
||||
io::{AsyncRead, AsyncWrite, ReadBuf},
|
||||
net::{lookup_host, TcpListener, TcpSocket, ToSocketAddrs},
|
||||
};
|
||||
use tokio_socks::{tcp::Socks5Stream, IntoTargetAddr, ToProxyAddrs};
|
||||
use tokio_util::codec::Framed;
|
||||
|
||||
pub struct FramedStream(Framed<TcpStream, BytesCodec>, Option<(Key, u64, u64)>);
|
||||
pub trait TcpStreamTrait: AsyncRead + AsyncWrite + Unpin {}
|
||||
pub struct DynTcpStream(Box<dyn TcpStreamTrait + Send + Sync>);
|
||||
|
||||
pub struct FramedStream(
|
||||
Framed<DynTcpStream, BytesCodec>,
|
||||
SocketAddr,
|
||||
Option<(Key, u64, u64)>,
|
||||
u64,
|
||||
);
|
||||
|
||||
impl Deref for FramedStream {
|
||||
type Target = Framed<TcpStream, BytesCodec>;
|
||||
type Target = Framed<DynTcpStream, BytesCodec>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
@@ -29,41 +41,132 @@ impl DerefMut for FramedStream {
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for DynTcpStream {
|
||||
type Target = Box<dyn TcpStreamTrait + Send + Sync>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for DynTcpStream {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
fn new_socket(addr: std::net::SocketAddr, reuse: bool) -> Result<TcpSocket, std::io::Error> {
|
||||
let socket = match addr {
|
||||
std::net::SocketAddr::V4(..) => TcpSocket::new_v4()?,
|
||||
std::net::SocketAddr::V6(..) => TcpSocket::new_v6()?,
|
||||
};
|
||||
if reuse {
|
||||
// windows has no reuse_port, but it's reuse_address
|
||||
// almost equals to unix's reuse_port + reuse_address,
|
||||
// though may introduce nondeterministic behavior
|
||||
#[cfg(unix)]
|
||||
socket.set_reuseport(true)?;
|
||||
socket.set_reuseaddr(true)?;
|
||||
}
|
||||
socket.bind(addr)?;
|
||||
Ok(socket)
|
||||
}
|
||||
|
||||
impl FramedStream {
|
||||
pub async fn new<T: ToSocketAddrs, T2: ToSocketAddrs>(
|
||||
remote_addr: T,
|
||||
pub async fn new<T1: ToSocketAddrs, T2: ToSocketAddrs>(
|
||||
remote_addr: T1,
|
||||
local_addr: T2,
|
||||
ms_timeout: u64,
|
||||
) -> ResultType<Self> {
|
||||
for local_addr in local_addr.to_socket_addrs().await? {
|
||||
for remote_addr in remote_addr.to_socket_addrs().await? {
|
||||
if let Ok(stream) = super::timeout(
|
||||
for local_addr in lookup_host(&local_addr).await? {
|
||||
for remote_addr in lookup_host(&remote_addr).await? {
|
||||
let stream = super::timeout(
|
||||
ms_timeout,
|
||||
TcpStream::connect_std(
|
||||
super::new_socket(local_addr, true, true)?.into_tcp_stream(),
|
||||
&remote_addr,
|
||||
),
|
||||
new_socket(local_addr, true)?.connect(remote_addr),
|
||||
)
|
||||
.await?
|
||||
{
|
||||
return Ok(Self(Framed::new(stream, BytesCodec::new()), None));
|
||||
}
|
||||
.await??;
|
||||
stream.set_nodelay(true).ok();
|
||||
let addr = stream.local_addr()?;
|
||||
return Ok(Self(
|
||||
Framed::new(DynTcpStream(Box::new(stream)), BytesCodec::new()),
|
||||
addr,
|
||||
None,
|
||||
0,
|
||||
));
|
||||
}
|
||||
}
|
||||
bail!("could not resolve to any address");
|
||||
}
|
||||
|
||||
pub fn from(stream: TcpStream) -> Self {
|
||||
Self(Framed::new(stream, BytesCodec::new()), None)
|
||||
pub async fn connect<'a, 't, P, T1, T2>(
|
||||
proxy: P,
|
||||
target: T1,
|
||||
local: T2,
|
||||
username: &'a str,
|
||||
password: &'a str,
|
||||
ms_timeout: u64,
|
||||
) -> ResultType<Self>
|
||||
where
|
||||
P: ToProxyAddrs,
|
||||
T1: IntoTargetAddr<'t>,
|
||||
T2: ToSocketAddrs,
|
||||
{
|
||||
if let Some(local) = lookup_host(&local).await?.next() {
|
||||
if let Some(proxy) = proxy.to_proxy_addrs().next().await {
|
||||
let stream =
|
||||
super::timeout(ms_timeout, new_socket(local, true)?.connect(proxy?)).await??;
|
||||
stream.set_nodelay(true).ok();
|
||||
let stream = if username.trim().is_empty() {
|
||||
super::timeout(
|
||||
ms_timeout,
|
||||
Socks5Stream::connect_with_socket(stream, target),
|
||||
)
|
||||
.await??
|
||||
} else {
|
||||
super::timeout(
|
||||
ms_timeout,
|
||||
Socks5Stream::connect_with_password_and_socket(
|
||||
stream, target, username, password,
|
||||
),
|
||||
)
|
||||
.await??
|
||||
};
|
||||
let addr = stream.local_addr()?;
|
||||
return Ok(Self(
|
||||
Framed::new(DynTcpStream(Box::new(stream)), BytesCodec::new()),
|
||||
addr,
|
||||
None,
|
||||
0,
|
||||
));
|
||||
};
|
||||
};
|
||||
bail!("could not resolve to any address");
|
||||
}
|
||||
|
||||
pub fn local_addr(&self) -> SocketAddr {
|
||||
self.1
|
||||
}
|
||||
|
||||
pub fn set_send_timeout(&mut self, ms: u64) {
|
||||
self.3 = ms;
|
||||
}
|
||||
|
||||
pub fn from(stream: impl TcpStreamTrait + Send + Sync + 'static, addr: SocketAddr) -> Self {
|
||||
Self(
|
||||
Framed::new(DynTcpStream(Box::new(stream)), BytesCodec::new()),
|
||||
addr,
|
||||
None,
|
||||
0,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn set_raw(&mut self) {
|
||||
self.0.codec_mut().set_raw();
|
||||
self.1 = None;
|
||||
self.2 = None;
|
||||
}
|
||||
|
||||
pub fn is_secured(&self) -> bool {
|
||||
self.1.is_some()
|
||||
self.2.is_some()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@@ -74,24 +177,29 @@ impl FramedStream {
|
||||
#[inline]
|
||||
pub async fn send_raw(&mut self, msg: Vec<u8>) -> ResultType<()> {
|
||||
let mut msg = msg;
|
||||
if let Some(key) = self.1.as_mut() {
|
||||
if let Some(key) = self.2.as_mut() {
|
||||
key.1 += 1;
|
||||
let nonce = Self::get_nonce(key.1);
|
||||
msg = secretbox::seal(&msg, &nonce, &key.0);
|
||||
}
|
||||
self.0.send(bytes::Bytes::from(msg)).await?;
|
||||
self.send_bytes(bytes::Bytes::from(msg)).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn send_bytes(&mut self, bytes: Bytes) -> ResultType<()> {
|
||||
self.0.send(bytes).await?;
|
||||
if self.3 > 0 {
|
||||
super::timeout(self.3, self.0.send(bytes)).await??;
|
||||
} else {
|
||||
self.0.send(bytes).await?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn next(&mut self) -> Option<Result<BytesMut, Error>> {
|
||||
let mut res = self.0.next().await;
|
||||
if let Some(key) = self.1.as_mut() {
|
||||
if let Some(key) = self.2.as_mut() {
|
||||
if let Some(Ok(bytes)) = res.as_mut() {
|
||||
key.2 += 1;
|
||||
let nonce = Self::get_nonce(key.2);
|
||||
@@ -119,28 +227,59 @@ impl FramedStream {
|
||||
}
|
||||
|
||||
pub fn set_key(&mut self, key: Key) {
|
||||
self.1 = Some((key, 0, 0));
|
||||
self.2 = Some((key, 0, 0));
|
||||
}
|
||||
|
||||
fn get_nonce(seqnum: u64) -> Nonce {
|
||||
let mut nonce = Nonce([0u8; secretbox::NONCEBYTES]);
|
||||
nonce.0[..std::mem::size_of_val(&seqnum)].copy_from_slice(&seqnum.to_ne_bytes());
|
||||
nonce.0[..std::mem::size_of_val(&seqnum)].copy_from_slice(&seqnum.to_le_bytes());
|
||||
nonce
|
||||
}
|
||||
}
|
||||
|
||||
const DEFAULT_BACKLOG: i32 = 128;
|
||||
const DEFAULT_BACKLOG: u32 = 128;
|
||||
|
||||
#[allow(clippy::never_loop)]
|
||||
pub async fn new_listener<T: ToSocketAddrs>(addr: T, reuse: bool) -> ResultType<TcpListener> {
|
||||
if !reuse {
|
||||
Ok(TcpListener::bind(addr).await?)
|
||||
} else {
|
||||
for addr in addr.to_socket_addrs().await? {
|
||||
let socket = super::new_socket(addr, true, true)?;
|
||||
socket.listen(DEFAULT_BACKLOG)?;
|
||||
return Ok(TcpListener::from_std(socket.into_tcp_listener())?);
|
||||
for addr in lookup_host(&addr).await? {
|
||||
let socket = new_socket(addr, true)?;
|
||||
return Ok(socket.listen(DEFAULT_BACKLOG)?);
|
||||
}
|
||||
bail!("could not resolve to any address");
|
||||
}
|
||||
}
|
||||
|
||||
impl Unpin for DynTcpStream {}
|
||||
|
||||
impl AsyncRead for DynTcpStream {
|
||||
fn poll_read(
|
||||
mut self: Pin<&mut Self>,
|
||||
cx: &mut Context<'_>,
|
||||
buf: &mut ReadBuf<'_>,
|
||||
) -> Poll<io::Result<()>> {
|
||||
AsyncRead::poll_read(Pin::new(&mut self.0), cx, buf)
|
||||
}
|
||||
}
|
||||
|
||||
impl AsyncWrite for DynTcpStream {
|
||||
fn poll_write(
|
||||
mut self: Pin<&mut Self>,
|
||||
cx: &mut Context<'_>,
|
||||
buf: &[u8],
|
||||
) -> Poll<io::Result<usize>> {
|
||||
AsyncWrite::poll_write(Pin::new(&mut self.0), cx, buf)
|
||||
}
|
||||
|
||||
fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
|
||||
AsyncWrite::poll_flush(Pin::new(&mut self.0), cx)
|
||||
}
|
||||
|
||||
fn poll_shutdown(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
|
||||
AsyncWrite::poll_shutdown(Pin::new(&mut self.0), cx)
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: AsyncRead + AsyncWrite + Unpin> TcpStreamTrait for R {}
|
||||
|
||||
@@ -1,71 +1,140 @@
|
||||
use crate::{bail, ResultType};
|
||||
use bytes::BytesMut;
|
||||
use futures::SinkExt;
|
||||
use anyhow::anyhow;
|
||||
use bytes::{Bytes, BytesMut};
|
||||
use futures::{SinkExt, StreamExt};
|
||||
use protobuf::Message;
|
||||
use std::{
|
||||
io::Error,
|
||||
net::SocketAddr,
|
||||
ops::{Deref, DerefMut},
|
||||
};
|
||||
use tokio::{net::ToSocketAddrs, net::UdpSocket, stream::StreamExt};
|
||||
use socket2::{Domain, Socket, Type};
|
||||
use std::net::SocketAddr;
|
||||
use tokio::net::{ToSocketAddrs, UdpSocket};
|
||||
use tokio_socks::{udp::Socks5UdpFramed, IntoTargetAddr, TargetAddr, ToProxyAddrs};
|
||||
use tokio_util::{codec::BytesCodec, udp::UdpFramed};
|
||||
|
||||
pub struct FramedSocket(UdpFramed<BytesCodec>);
|
||||
|
||||
impl Deref for FramedSocket {
|
||||
type Target = UdpFramed<BytesCodec>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
pub enum FramedSocket {
|
||||
Direct(UdpFramed<BytesCodec>),
|
||||
ProxySocks(Socks5UdpFramed),
|
||||
}
|
||||
|
||||
impl DerefMut for FramedSocket {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.0
|
||||
fn new_socket(addr: SocketAddr, reuse: bool) -> Result<Socket, std::io::Error> {
|
||||
let socket = match addr {
|
||||
SocketAddr::V4(..) => Socket::new(Domain::ipv4(), Type::dgram(), None),
|
||||
SocketAddr::V6(..) => Socket::new(Domain::ipv6(), Type::dgram(), None),
|
||||
}?;
|
||||
if reuse {
|
||||
// windows has no reuse_port, but it's reuse_address
|
||||
// almost equals to unix's reuse_port + reuse_address,
|
||||
// though may introduce nondeterministic behavior
|
||||
#[cfg(unix)]
|
||||
socket.set_reuse_port(true)?;
|
||||
socket.set_reuse_address(true)?;
|
||||
}
|
||||
socket.bind(&addr.into())?;
|
||||
Ok(socket)
|
||||
}
|
||||
|
||||
impl FramedSocket {
|
||||
pub async fn new<T: ToSocketAddrs>(addr: T) -> ResultType<Self> {
|
||||
let socket = UdpSocket::bind(addr).await?;
|
||||
Ok(Self(UdpFramed::new(socket, BytesCodec::new())))
|
||||
Ok(Self::Direct(UdpFramed::new(socket, BytesCodec::new())))
|
||||
}
|
||||
|
||||
#[allow(clippy::never_loop)]
|
||||
pub async fn new_reuse<T: ToSocketAddrs>(addr: T) -> ResultType<Self> {
|
||||
for addr in addr.to_socket_addrs().await? {
|
||||
return Ok(Self(UdpFramed::new(
|
||||
UdpSocket::from_std(super::new_socket(addr, false, true)?.into_udp_socket())?,
|
||||
pub async fn new_reuse<T: std::net::ToSocketAddrs>(addr: T) -> ResultType<Self> {
|
||||
for addr in addr.to_socket_addrs()? {
|
||||
let socket = new_socket(addr, true)?.into_udp_socket();
|
||||
return Ok(Self::Direct(UdpFramed::new(
|
||||
UdpSocket::from_std(socket)?,
|
||||
BytesCodec::new(),
|
||||
)));
|
||||
}
|
||||
bail!("could not resolve to any address");
|
||||
}
|
||||
|
||||
pub async fn new_proxy<'a, 't, P: ToProxyAddrs, T: ToSocketAddrs>(
|
||||
proxy: P,
|
||||
local: T,
|
||||
username: &'a str,
|
||||
password: &'a str,
|
||||
ms_timeout: u64,
|
||||
) -> ResultType<Self> {
|
||||
let framed = if username.trim().is_empty() {
|
||||
super::timeout(ms_timeout, Socks5UdpFramed::connect(proxy, Some(local))).await??
|
||||
} else {
|
||||
super::timeout(
|
||||
ms_timeout,
|
||||
Socks5UdpFramed::connect_with_password(proxy, Some(local), username, password),
|
||||
)
|
||||
.await??
|
||||
};
|
||||
log::trace!(
|
||||
"Socks5 udp connected, local addr: {:?}, target addr: {}",
|
||||
framed.local_addr(),
|
||||
framed.socks_addr()
|
||||
);
|
||||
Ok(Self::ProxySocks(framed))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn send(&mut self, msg: &impl Message, addr: SocketAddr) -> ResultType<()> {
|
||||
self.0
|
||||
.send((bytes::Bytes::from(msg.write_to_bytes().unwrap()), addr))
|
||||
.await?;
|
||||
pub async fn send(
|
||||
&mut self,
|
||||
msg: &impl Message,
|
||||
addr: impl IntoTargetAddr<'_>,
|
||||
) -> ResultType<()> {
|
||||
let addr = addr.into_target_addr()?.to_owned();
|
||||
let send_data = Bytes::from(msg.write_to_bytes()?);
|
||||
let _ = match self {
|
||||
Self::Direct(f) => match addr {
|
||||
TargetAddr::Ip(addr) => f.send((send_data, addr)).await?,
|
||||
_ => {}
|
||||
},
|
||||
Self::ProxySocks(f) => f.send((send_data, addr)).await?,
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// https://stackoverflow.com/a/68733302/1926020
|
||||
#[inline]
|
||||
pub async fn send_raw(
|
||||
&mut self,
|
||||
msg: &'static [u8],
|
||||
addr: impl IntoTargetAddr<'static>,
|
||||
) -> ResultType<()> {
|
||||
let addr = addr.into_target_addr()?.to_owned();
|
||||
|
||||
let _ = match self {
|
||||
Self::Direct(f) => match addr {
|
||||
TargetAddr::Ip(addr) => f.send((Bytes::from(msg), addr)).await?,
|
||||
_ => {}
|
||||
},
|
||||
Self::ProxySocks(f) => f.send((Bytes::from(msg), addr)).await?,
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn send_raw(&mut self, msg: &'static [u8], addr: SocketAddr) -> ResultType<()> {
|
||||
self.0.send((bytes::Bytes::from(msg), addr)).await?;
|
||||
Ok(())
|
||||
pub async fn next(&mut self) -> Option<ResultType<(BytesMut, TargetAddr<'static>)>> {
|
||||
match self {
|
||||
Self::Direct(f) => match f.next().await {
|
||||
Some(Ok((data, addr))) => {
|
||||
Some(Ok((data, addr.into_target_addr().ok()?.to_owned())))
|
||||
}
|
||||
Some(Err(e)) => Some(Err(anyhow!(e))),
|
||||
None => None,
|
||||
},
|
||||
Self::ProxySocks(f) => match f.next().await {
|
||||
Some(Ok((data, _))) => Some(Ok((data.data, data.dst_addr))),
|
||||
Some(Err(e)) => Some(Err(anyhow!(e))),
|
||||
None => None,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn next(&mut self) -> Option<Result<(BytesMut, SocketAddr), Error>> {
|
||||
self.0.next().await
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn next_timeout(&mut self, ms: u64) -> Option<Result<(BytesMut, SocketAddr), Error>> {
|
||||
pub async fn next_timeout(
|
||||
&mut self,
|
||||
ms: u64,
|
||||
) -> Option<ResultType<(BytesMut, TargetAddr<'static>)>> {
|
||||
if let Ok(res) =
|
||||
tokio::time::timeout(std::time::Duration::from_millis(ms), self.0.next()).await
|
||||
tokio::time::timeout(std::time::Duration::from_millis(ms), self.next()).await
|
||||
{
|
||||
res
|
||||
} else {
|
||||
|
||||
2
libs/magnum-opus/.gitignore
vendored
2
libs/magnum-opus/.gitignore
vendored
@@ -1,2 +0,0 @@
|
||||
target
|
||||
Cargo.lock
|
||||
@@ -1,18 +0,0 @@
|
||||
[package]
|
||||
name = "magnum-opus"
|
||||
version = "0.3.4"
|
||||
authors = ["Tad Hardesty <tad@platymuus.com>", "Sergey Duck <sergeypechnikov326@gmail.com>"]
|
||||
edition = "2018"
|
||||
description = "Safe Rust bindings for libopus"
|
||||
readme = "README.md"
|
||||
license = "MIT/Apache-2.0"
|
||||
keywords = ["opus", "codec", "voice", "sound", "audio"]
|
||||
categories = ["api-bindings", "encoding", "compression",
|
||||
"multimedia::audio", "multimedia::encoding"]
|
||||
|
||||
repository = "https://github.com/DuckerMan/magnum-opus"
|
||||
documentation = "https://docs.rs/magnum-opus"
|
||||
|
||||
[build-dependencies]
|
||||
target_build_utils = "0.3"
|
||||
bindgen = "0.53"
|
||||
@@ -1,201 +0,0 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
@@ -1,19 +0,0 @@
|
||||
Copyright (c) 2016 Tad Hardesty
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
@@ -1,22 +0,0 @@
|
||||
# magnum-opus [](https://crates.io/crates/magnum-opus) [](https://docs.rs/magnum-opus)
|
||||
|
||||
### This is the fork of @SpaceManiac repo, which now is abandoned
|
||||
|
||||
Safe Rust bindings for libopus. The rustdoc (available through `cargo doc`)
|
||||
includes brief descriptions for methods, and detailed API information can be
|
||||
found at the [libopus documentation](https://opus-codec.org/docs/opus_api-1.1.2/).
|
||||
|
||||
## License
|
||||
|
||||
Licensed under either of
|
||||
|
||||
* Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
|
||||
* MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
|
||||
|
||||
at your option.
|
||||
|
||||
### Contribution
|
||||
|
||||
Unless you explicitly state otherwise, any contribution intentionally submitted
|
||||
for inclusion in the work by you, as defined in the Apache-2.0 license, shall be
|
||||
dual licensed as above, without any additional terms or conditions.
|
||||
@@ -1,89 +0,0 @@
|
||||
use std::{
|
||||
env,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
fn find_package(name: &str) -> Vec<PathBuf> {
|
||||
let vcpkg_root = std::env::var("VCPKG_ROOT").unwrap();
|
||||
let mut path: PathBuf = vcpkg_root.into();
|
||||
let target_os = std::env::var("CARGO_CFG_TARGET_OS").unwrap();
|
||||
let mut target_arch = std::env::var("CARGO_CFG_TARGET_ARCH").unwrap();
|
||||
if target_arch == "x86_64" {
|
||||
target_arch = "x64".to_owned();
|
||||
} else if target_arch == "aarch64" {
|
||||
target_arch = "arm64".to_owned();
|
||||
} else {
|
||||
target_arch = "arm".to_owned();
|
||||
}
|
||||
let target = if target_os == "macos" {
|
||||
"x64-osx".to_owned()
|
||||
} else if target_os == "windows" {
|
||||
"x64-windows-static".to_owned()
|
||||
} else if target_os == "android" {
|
||||
format!("{}-android-static", target_arch)
|
||||
} else {
|
||||
"x64-linux".to_owned()
|
||||
};
|
||||
println!("cargo:info={}", target);
|
||||
path.push("installed");
|
||||
path.push(target);
|
||||
println!(
|
||||
"{}",
|
||||
format!("cargo:rustc-link-lib={}", name.trim_start_matches("lib"))
|
||||
);
|
||||
println!(
|
||||
"{}",
|
||||
format!(
|
||||
"cargo:rustc-link-search={}",
|
||||
path.join("lib").to_str().unwrap()
|
||||
)
|
||||
);
|
||||
let include = path.join("include");
|
||||
println!("{}", format!("cargo:include={}", include.to_str().unwrap()));
|
||||
vec![include]
|
||||
}
|
||||
|
||||
fn generate_bindings(ffi_header: &Path, include_paths: &[PathBuf], ffi_rs: &Path) {
|
||||
#[derive(Debug)]
|
||||
struct ParseCallbacks;
|
||||
impl bindgen::callbacks::ParseCallbacks for ParseCallbacks {
|
||||
fn int_macro(&self, name: &str, _value: i64) -> Option<bindgen::callbacks::IntKind> {
|
||||
if name.starts_with("OPUS") {
|
||||
Some(bindgen::callbacks::IntKind::Int)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
let mut b = bindgen::Builder::default()
|
||||
.header(ffi_header.to_str().unwrap())
|
||||
.parse_callbacks(Box::new(ParseCallbacks))
|
||||
.generate_comments(false);
|
||||
|
||||
for dir in include_paths {
|
||||
b = b.clang_arg(format!("-I{}", dir.display()));
|
||||
}
|
||||
|
||||
b.generate().unwrap().write_to_file(ffi_rs).unwrap();
|
||||
}
|
||||
|
||||
fn gen_opus() {
|
||||
let includes = find_package("opus");
|
||||
let src_dir = env::var_os("CARGO_MANIFEST_DIR").unwrap();
|
||||
let src_dir = Path::new(&src_dir);
|
||||
let out_dir = env::var_os("OUT_DIR").unwrap();
|
||||
let out_dir = Path::new(&out_dir);
|
||||
|
||||
let ffi_header = src_dir.join("opus_ffi.h");
|
||||
println!("rerun-if-changed={}", ffi_header.display());
|
||||
for dir in &includes {
|
||||
println!("rerun-if-changed={}", dir.display());
|
||||
}
|
||||
|
||||
let ffi_rs = out_dir.join("opus_ffi.rs");
|
||||
generate_bindings(&ffi_header, &includes, &ffi_rs);
|
||||
}
|
||||
|
||||
fn main() {
|
||||
gen_opus()
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
#include <opus/opus_multistream.h>
|
||||
@@ -1,843 +0,0 @@
|
||||
// Copyright 2016 Tad Hardesty
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! High-level bindings for libopus.
|
||||
//!
|
||||
//! Only brief descriptions are included here. For detailed information, consult
|
||||
//! the [libopus documentation](https://opus-codec.org/docs/opus_api-1.1.2/).
|
||||
#![warn(missing_docs)]
|
||||
|
||||
mod opus_ffi;
|
||||
use opus_ffi as ffi;
|
||||
|
||||
|
||||
use std::ffi::CStr;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use std::os::raw::c_int;
|
||||
|
||||
// ============================================================================
|
||||
// Constants
|
||||
|
||||
// Generic CTLs
|
||||
const OPUS_RESET_STATE: c_int = 4028; // void
|
||||
const OPUS_GET_FINAL_RANGE: c_int = 4031; // out *u32
|
||||
const OPUS_GET_BANDWIDTH: c_int = 4009; // out *i32
|
||||
const OPUS_GET_SAMPLE_RATE: c_int = 4029; // out *i32
|
||||
// Encoder CTLs
|
||||
const OPUS_SET_BITRATE: c_int = 4002; // in i32
|
||||
const OPUS_GET_BITRATE: c_int = 4003; // out *i32
|
||||
const OPUS_SET_VBR: c_int = 4006; // in i32
|
||||
const OPUS_GET_VBR: c_int = 4007; // out *i32
|
||||
const OPUS_SET_VBR_CONSTRAINT: c_int = 4020; // in i32
|
||||
const OPUS_GET_VBR_CONSTRAINT: c_int = 4021; // out *i32
|
||||
const OPUS_SET_INBAND_FEC: c_int = 4012; // in i32
|
||||
const OPUS_GET_INBAND_FEC: c_int = 4013; // out *i32
|
||||
const OPUS_SET_PACKET_LOSS_PERC: c_int = 4014; // in i32
|
||||
const OPUS_GET_PACKET_LOSS_PERC: c_int = 4015; // out *i32
|
||||
const OPUS_GET_LOOKAHEAD: c_int = 4027; // out *i32
|
||||
// Decoder CTLs
|
||||
const OPUS_SET_GAIN: c_int = 4034; // in i32
|
||||
const OPUS_GET_GAIN: c_int = 4045; // out *i32
|
||||
const OPUS_GET_LAST_PACKET_DURATION: c_int = 4039; // out *i32
|
||||
const OPUS_GET_PITCH: c_int = 4033; // out *i32
|
||||
|
||||
// Bitrate
|
||||
const OPUS_AUTO: c_int = -1000;
|
||||
const OPUS_BITRATE_MAX: c_int = -1;
|
||||
|
||||
/// The possible applications for the codec.
|
||||
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
|
||||
pub enum Application {
|
||||
/// Best for most VoIP/videoconference applications where listening quality
|
||||
/// and intelligibility matter most.
|
||||
Voip = 2048,
|
||||
/// Best for broadcast/high-fidelity application where the decoded audio
|
||||
/// should be as close as possible to the input.
|
||||
Audio = 2049,
|
||||
/// Only use when lowest-achievable latency is what matters most.
|
||||
LowDelay = 2051,
|
||||
}
|
||||
|
||||
/// The available channel setings.
|
||||
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
|
||||
pub enum Channels {
|
||||
/// One channel.
|
||||
Mono = 1,
|
||||
/// Two channels, left and right.
|
||||
Stereo = 2,
|
||||
}
|
||||
|
||||
/// The available bandwidth level settings.
|
||||
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
|
||||
pub enum Bandwidth {
|
||||
/// Auto/default setting.
|
||||
Auto = -1000,
|
||||
/// 4kHz bandpass.
|
||||
Narrowband = 1101,
|
||||
/// 6kHz bandpass.
|
||||
Mediumband = 1102,
|
||||
/// 8kHz bandpass.
|
||||
Wideband = 1103,
|
||||
/// 12kHz bandpass.
|
||||
Superwideband = 1104,
|
||||
/// 20kHz bandpass.
|
||||
Fullband = 1105,
|
||||
}
|
||||
|
||||
impl Bandwidth {
|
||||
fn from_int(value: i32) -> Option<Bandwidth> {
|
||||
Some(match value {
|
||||
-1000 => Bandwidth::Auto,
|
||||
1101 => Bandwidth::Narrowband,
|
||||
1102 => Bandwidth::Mediumband,
|
||||
1103 => Bandwidth::Wideband,
|
||||
1104 => Bandwidth::Superwideband,
|
||||
1105 => Bandwidth::Fullband,
|
||||
_ => return None,
|
||||
})
|
||||
}
|
||||
|
||||
fn decode(value: i32, what: &'static str) -> Result<Bandwidth> {
|
||||
match Bandwidth::from_int(value) {
|
||||
Some(bandwidth) => Ok(bandwidth),
|
||||
None => Err(Error::bad_arg(what)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Possible error codes.
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
||||
pub enum ErrorCode {
|
||||
/// One or more invalid/out of range arguments.
|
||||
BadArg = -1,
|
||||
/// Not enough bytes allocated in the buffer.
|
||||
BufferTooSmall = -2,
|
||||
/// An internal error was detected.
|
||||
InternalError = -3,
|
||||
/// The compressed data passed is corrupted.
|
||||
InvalidPacket = -4,
|
||||
/// Invalid/unsupported request number.
|
||||
Unimplemented = -5,
|
||||
/// An encoder or decoder structure is invalid or already freed.
|
||||
InvalidState = -6,
|
||||
/// Memory allocation has failed.
|
||||
AllocFail = -7,
|
||||
/// An unknown failure.
|
||||
Unknown = -8,
|
||||
}
|
||||
|
||||
impl ErrorCode {
|
||||
fn from_int(value: c_int) -> ErrorCode {
|
||||
use ErrorCode::*;
|
||||
match value {
|
||||
ffi::OPUS_BAD_ARG => BadArg,
|
||||
ffi::OPUS_BUFFER_TOO_SMALL => BufferTooSmall,
|
||||
ffi::OPUS_INTERNAL_ERROR => InternalError,
|
||||
ffi::OPUS_INVALID_PACKET => InvalidPacket,
|
||||
ffi::OPUS_UNIMPLEMENTED => Unimplemented,
|
||||
ffi::OPUS_INVALID_STATE => InvalidState,
|
||||
ffi::OPUS_ALLOC_FAIL => AllocFail,
|
||||
_ => Unknown,
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a human-readable error string for this error code.
|
||||
pub fn description(self) -> &'static str {
|
||||
// should always be ASCII and non-null for any input
|
||||
unsafe { CStr::from_ptr(ffi::opus_strerror(self as c_int)) }.to_str().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
/// Possible bitrates.
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
||||
pub enum Bitrate {
|
||||
/// Explicit bitrate choice (in bits/second).
|
||||
Bits(i32),
|
||||
/// Maximum bitrate allowed (up to maximum number of bytes for the packet).
|
||||
Max,
|
||||
/// Default bitrate decided by the encoder (not recommended).
|
||||
Auto,
|
||||
}
|
||||
|
||||
/// Get the libopus version string.
|
||||
///
|
||||
/// Applications may look for the substring "-fixed" in the version string to
|
||||
/// determine whether they have a fixed-point or floating-point build at
|
||||
/// runtime.
|
||||
pub fn version() -> &'static str {
|
||||
// verison string should always be ASCII
|
||||
unsafe { CStr::from_ptr(ffi::opus_get_version_string()) }.to_str().unwrap()
|
||||
}
|
||||
|
||||
macro_rules! ffi {
|
||||
($f:ident $(, $rest:expr)*) => {
|
||||
match unsafe { ffi::$f($($rest),*) } {
|
||||
code if code < 0 => return Err(Error::from_code(stringify!($f), code)),
|
||||
code => code,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! ctl {
|
||||
($f:ident, $this:ident, $ctl:ident, $($rest:expr),*) => {
|
||||
match unsafe { ffi::$f($this.ptr, $ctl, $($rest),*) } {
|
||||
code if code < 0 => return Err(Error::from_code(
|
||||
concat!(stringify!($f), "(", stringify!($ctl), ")"),
|
||||
code,
|
||||
)),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Encoder
|
||||
|
||||
macro_rules! enc_ctl {
|
||||
($this:ident, $ctl:ident $(, $rest:expr)*) => {
|
||||
ctl!(opus_encoder_ctl, $this, $ctl, $($rest),*)
|
||||
}
|
||||
}
|
||||
|
||||
/// An Opus encoder with associated state.
|
||||
#[derive(Debug)]
|
||||
pub struct Encoder {
|
||||
ptr: *mut ffi::OpusEncoder,
|
||||
channels: Channels,
|
||||
}
|
||||
|
||||
impl Encoder {
|
||||
/// Create and initialize an encoder.
|
||||
pub fn new(sample_rate: u32, channels: Channels, mode: Application) -> Result<Encoder> {
|
||||
let mut error = 0;
|
||||
let ptr = unsafe { ffi::opus_encoder_create(
|
||||
sample_rate as i32,
|
||||
channels as c_int,
|
||||
mode as c_int,
|
||||
&mut error) };
|
||||
if error != ffi::OPUS_OK || ptr.is_null() {
|
||||
Err(Error::from_code("opus_encoder_create", error))
|
||||
} else {
|
||||
Ok(Encoder { ptr: ptr, channels: channels })
|
||||
}
|
||||
}
|
||||
|
||||
/// Encode an Opus frame.
|
||||
pub fn encode(&mut self, input: &[i16], output: &mut [u8]) -> Result<usize> {
|
||||
let len = ffi!(opus_encode, self.ptr,
|
||||
input.as_ptr(), len(input) / self.channels as c_int,
|
||||
output.as_mut_ptr(), len(output));
|
||||
Ok(len as usize)
|
||||
}
|
||||
|
||||
/// Encode an Opus frame from floating point input.
|
||||
pub fn encode_float(&mut self, input: &[f32], output: &mut [u8]) -> Result<usize> {
|
||||
let len = ffi!(opus_encode_float, self.ptr,
|
||||
input.as_ptr(), len(input) / self.channels as c_int,
|
||||
output.as_mut_ptr(), len(output));
|
||||
Ok(len as usize)
|
||||
}
|
||||
|
||||
/// Encode an Opus frame to a new buffer.
|
||||
pub fn encode_vec(&mut self, input: &[i16], max_size: usize) -> Result<Vec<u8>> {
|
||||
let mut output: Vec<u8> = vec![0; max_size];
|
||||
let result = self.encode(input, output.as_mut_slice())?;
|
||||
output.truncate(result);
|
||||
Ok(output)
|
||||
}
|
||||
|
||||
/// Encode an Opus frame from floating point input to a new buffer.
|
||||
pub fn encode_vec_float(&mut self, input: &[f32], max_size: usize) -> Result<Vec<u8>> {
|
||||
let mut output: Vec<u8> = vec![0; max_size];
|
||||
let result = self.encode_float(input, output.as_mut_slice())?;
|
||||
output.truncate(result);
|
||||
Ok(output)
|
||||
}
|
||||
|
||||
// ------------
|
||||
// Generic CTLs
|
||||
|
||||
/// Reset the codec state to be equivalent to a freshly initialized state.
|
||||
pub fn reset_state(&mut self) -> Result<()> {
|
||||
enc_ctl!(self, OPUS_RESET_STATE);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Get the final range of the codec's entropy coder.
|
||||
pub fn get_final_range(&mut self) -> Result<u32> {
|
||||
let mut value: u32 = 0;
|
||||
enc_ctl!(self, OPUS_GET_FINAL_RANGE, &mut value);
|
||||
Ok(value)
|
||||
}
|
||||
|
||||
/// Get the encoder's configured bandpass.
|
||||
pub fn get_bandwidth(&mut self) -> Result<Bandwidth> {
|
||||
let mut value: i32 = 0;
|
||||
enc_ctl!(self, OPUS_GET_BANDWIDTH, &mut value);
|
||||
Bandwidth::decode(value, "opus_encoder_ctl(OPUS_GET_BANDWIDTH)")
|
||||
}
|
||||
|
||||
/// Get the samping rate the encoder was intialized with.
|
||||
pub fn get_sample_rate(&mut self) -> Result<u32> {
|
||||
let mut value: i32 = 0;
|
||||
enc_ctl!(self, OPUS_GET_SAMPLE_RATE, &mut value);
|
||||
Ok(value as u32)
|
||||
}
|
||||
|
||||
// ------------
|
||||
// Encoder CTLs
|
||||
|
||||
/// Set the encoder's bitrate.
|
||||
pub fn set_bitrate(&mut self, value: Bitrate) -> Result<()> {
|
||||
let value: i32 = match value {
|
||||
Bitrate::Auto => OPUS_AUTO,
|
||||
Bitrate::Max => OPUS_BITRATE_MAX,
|
||||
Bitrate::Bits(b) => b,
|
||||
};
|
||||
enc_ctl!(self, OPUS_SET_BITRATE, value);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Get the encoder's bitrate.
|
||||
pub fn get_bitrate(&mut self) -> Result<Bitrate> {
|
||||
let mut value: i32 = 0;
|
||||
enc_ctl!(self, OPUS_GET_BITRATE, &mut value);
|
||||
Ok(match value {
|
||||
OPUS_AUTO => Bitrate::Auto,
|
||||
OPUS_BITRATE_MAX => Bitrate::Max,
|
||||
_ => Bitrate::Bits(value),
|
||||
})
|
||||
}
|
||||
|
||||
/// Enable or disable variable bitrate.
|
||||
pub fn set_vbr(&mut self, vbr: bool) -> Result<()> {
|
||||
let value: i32 = if vbr { 1 } else { 0 };
|
||||
enc_ctl!(self, OPUS_SET_VBR, value);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Determine if variable bitrate is enabled.
|
||||
pub fn get_vbr(&mut self) -> Result<bool> {
|
||||
let mut value: i32 = 0;
|
||||
enc_ctl!(self, OPUS_GET_VBR, &mut value);
|
||||
Ok(value != 0)
|
||||
}
|
||||
|
||||
/// Enable or disable constrained VBR.
|
||||
pub fn set_vbr_constraint(&mut self, vbr: bool) -> Result<()> {
|
||||
let value: i32 = if vbr { 1 } else { 0 };
|
||||
enc_ctl!(self, OPUS_SET_VBR_CONSTRAINT, value);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Determine if constrained VBR is enabled.
|
||||
pub fn get_vbr_constraint(&mut self) -> Result<bool> {
|
||||
let mut value: i32 = 0;
|
||||
enc_ctl!(self, OPUS_GET_VBR_CONSTRAINT, &mut value);
|
||||
Ok(value != 0)
|
||||
}
|
||||
|
||||
/// Configures the encoder's use of inband forward error correction (FEC).
|
||||
pub fn set_inband_fec(&mut self, value: bool) -> Result<()> {
|
||||
let value: i32 = if value { 1 } else { 0 };
|
||||
enc_ctl!(self, OPUS_SET_INBAND_FEC, value);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Gets encoder's configured use of inband forward error correction.
|
||||
pub fn get_inband_fec(&mut self) -> Result<bool> {
|
||||
let mut value: i32 = 0;
|
||||
enc_ctl!(self, OPUS_GET_INBAND_FEC, &mut value);
|
||||
Ok(value != 0)
|
||||
}
|
||||
|
||||
/// Sets the encoder's expected packet loss percentage.
|
||||
pub fn set_packet_loss_perc(&mut self, value: i32) -> Result<()> {
|
||||
enc_ctl!(self, OPUS_SET_PACKET_LOSS_PERC, value);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Gets the encoder's expected packet loss percentage.
|
||||
pub fn get_packet_loss_perc(&mut self) -> Result<i32> {
|
||||
let mut value: i32 = 0;
|
||||
enc_ctl!(self, OPUS_GET_PACKET_LOSS_PERC, &mut value);
|
||||
Ok(value)
|
||||
}
|
||||
|
||||
/// Gets the total samples of delay added by the entire codec.
|
||||
pub fn get_lookahead(&mut self) -> Result<i32> {
|
||||
let mut value: i32 = 0;
|
||||
enc_ctl!(self, OPUS_GET_LOOKAHEAD, &mut value);
|
||||
Ok(value)
|
||||
}
|
||||
|
||||
// TODO: Encoder-specific CTLs
|
||||
}
|
||||
|
||||
impl Drop for Encoder {
|
||||
fn drop(&mut self) {
|
||||
unsafe { ffi::opus_encoder_destroy(self.ptr) }
|
||||
}
|
||||
}
|
||||
|
||||
// "A single codec state may only be accessed from a single thread at
|
||||
// a time and any required locking must be performed by the caller. Separate
|
||||
// streams must be decoded with separate decoder states and can be decoded
|
||||
// in parallel unless the library was compiled with NONTHREADSAFE_PSEUDOSTACK
|
||||
// defined."
|
||||
//
|
||||
// In other words, opus states may be moved between threads at will. A special
|
||||
// compilation mode intended for embedded platforms forbids multithreaded use
|
||||
// of the library as a whole rather than on a per-state basis, but the opus-sys
|
||||
// crate does not use this mode.
|
||||
unsafe impl Send for Encoder {}
|
||||
|
||||
// ============================================================================
|
||||
// Decoder
|
||||
|
||||
macro_rules! dec_ctl {
|
||||
($this:ident, $ctl:ident $(, $rest:expr)*) => {
|
||||
ctl!(opus_decoder_ctl, $this, $ctl, $($rest),*)
|
||||
}
|
||||
}
|
||||
|
||||
/// An Opus decoder with associated state.
|
||||
#[derive(Debug)]
|
||||
pub struct Decoder {
|
||||
ptr: *mut ffi::OpusDecoder,
|
||||
channels: Channels,
|
||||
}
|
||||
|
||||
impl Decoder {
|
||||
/// Create and initialize a decoder.
|
||||
pub fn new(sample_rate: u32, channels: Channels) -> Result<Decoder> {
|
||||
let mut error = 0;
|
||||
let ptr = unsafe { ffi::opus_decoder_create(
|
||||
sample_rate as i32,
|
||||
channels as c_int,
|
||||
&mut error) };
|
||||
if error != ffi::OPUS_OK || ptr.is_null() {
|
||||
Err(Error::from_code("opus_decoder_create", error))
|
||||
} else {
|
||||
Ok(Decoder { ptr: ptr, channels: channels })
|
||||
}
|
||||
}
|
||||
|
||||
/// Decode an Opus packet.
|
||||
pub fn decode(&mut self, input: &[u8], output: &mut [i16], fec: bool) -> Result<usize> {
|
||||
let ptr = match input.len() {
|
||||
0 => std::ptr::null(),
|
||||
_ => input.as_ptr(),
|
||||
};
|
||||
let len = ffi!(opus_decode, self.ptr,
|
||||
ptr, len(input),
|
||||
output.as_mut_ptr(), len(output) / self.channels as c_int,
|
||||
fec as c_int);
|
||||
Ok(len as usize)
|
||||
}
|
||||
|
||||
/// Decode an Opus packet with floating point output.
|
||||
pub fn decode_float(&mut self, input: &[u8], output: &mut [f32], fec: bool) -> Result<usize> {
|
||||
let ptr = match input.len() {
|
||||
0 => std::ptr::null(),
|
||||
_ => input.as_ptr(),
|
||||
};
|
||||
let len = ffi!(opus_decode_float, self.ptr,
|
||||
ptr, len(input),
|
||||
output.as_mut_ptr(), len(output) / self.channels as c_int,
|
||||
fec as c_int);
|
||||
Ok(len as usize)
|
||||
}
|
||||
|
||||
/// Get the number of samples of an Opus packet.
|
||||
pub fn get_nb_samples(&self, packet: &[u8]) -> Result<usize> {
|
||||
let len = ffi!(opus_decoder_get_nb_samples, self.ptr,
|
||||
packet.as_ptr(), packet.len() as i32);
|
||||
Ok(len as usize)
|
||||
}
|
||||
|
||||
// ------------
|
||||
// Generic CTLs
|
||||
|
||||
/// Reset the codec state to be equivalent to a freshly initialized state.
|
||||
pub fn reset_state(&mut self) -> Result<()> {
|
||||
dec_ctl!(self, OPUS_RESET_STATE);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Get the final range of the codec's entropy coder.
|
||||
pub fn get_final_range(&mut self) -> Result<u32> {
|
||||
let mut value: u32 = 0;
|
||||
dec_ctl!(self, OPUS_GET_FINAL_RANGE, &mut value);
|
||||
Ok(value)
|
||||
}
|
||||
|
||||
/// Get the decoder's last bandpass.
|
||||
pub fn get_bandwidth(&mut self) -> Result<Bandwidth> {
|
||||
let mut value: i32 = 0;
|
||||
dec_ctl!(self, OPUS_GET_BANDWIDTH, &mut value);
|
||||
Bandwidth::decode(value, "opus_decoder_ctl(OPUS_GET_BANDWIDTH)")
|
||||
}
|
||||
|
||||
/// Get the samping rate the decoder was intialized with.
|
||||
pub fn get_sample_rate(&mut self) -> Result<u32> {
|
||||
let mut value: i32 = 0;
|
||||
dec_ctl!(self, OPUS_GET_SAMPLE_RATE, &mut value);
|
||||
Ok(value as u32)
|
||||
}
|
||||
|
||||
// ------------
|
||||
// Decoder CTLs
|
||||
|
||||
/// Configures decoder gain adjustment.
|
||||
///
|
||||
/// Scales the decoded output by a factor specified in Q8 dB units. This has
|
||||
/// a maximum range of -32768 to 32768 inclusive, and returns `BadArg`
|
||||
/// otherwise. The default is zero indicating no adjustment. This setting
|
||||
/// survives decoder reset.
|
||||
///
|
||||
/// `gain = pow(10, x / (20.0 * 256))`
|
||||
pub fn set_gain(&mut self, gain: i32) -> Result<()> {
|
||||
dec_ctl!(self, OPUS_SET_GAIN, gain);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Gets the decoder's configured gain adjustment.
|
||||
pub fn get_gain(&mut self) -> Result<i32> {
|
||||
let mut value: i32 = 0;
|
||||
dec_ctl!(self, OPUS_GET_GAIN, &mut value);
|
||||
Ok(value)
|
||||
}
|
||||
|
||||
/// Gets the duration (in samples) of the last packet successfully decoded
|
||||
/// or concealed.
|
||||
pub fn get_last_packet_duration(&mut self) -> Result<u32> {
|
||||
let mut value: i32 = 0;
|
||||
dec_ctl!(self, OPUS_GET_LAST_PACKET_DURATION, &mut value);
|
||||
Ok(value as u32)
|
||||
}
|
||||
|
||||
/// Gets the pitch of the last decoded frame, if available.
|
||||
///
|
||||
/// This can be used for any post-processing algorithm requiring the use of
|
||||
/// pitch, e.g. time stretching/shortening. If the last frame was not
|
||||
/// voiced, or if the pitch was not coded in the frame, then zero is
|
||||
/// returned.
|
||||
pub fn get_pitch(&mut self) -> Result<i32> {
|
||||
let mut value: i32 = 0;
|
||||
dec_ctl!(self, OPUS_GET_PITCH, &mut value);
|
||||
Ok(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Decoder {
|
||||
fn drop(&mut self) {
|
||||
unsafe { ffi::opus_decoder_destroy(self.ptr) }
|
||||
}
|
||||
}
|
||||
|
||||
// See `unsafe impl Send for Encoder`.
|
||||
unsafe impl Send for Decoder {}
|
||||
|
||||
// ============================================================================
|
||||
// Packet Analysis
|
||||
|
||||
/// Analyze raw Opus packets.
|
||||
pub mod packet {
|
||||
use super::*;
|
||||
use super::ffi;
|
||||
use std::{ptr, slice};
|
||||
|
||||
/// Get the bandwidth of an Opus packet.
|
||||
pub fn get_bandwidth(packet: &[u8]) -> Result<Bandwidth> {
|
||||
if packet.len() < 1 {
|
||||
return Err(Error::bad_arg("opus_packet_get_bandwidth"));
|
||||
}
|
||||
let bandwidth = ffi!(opus_packet_get_bandwidth, packet.as_ptr());
|
||||
Bandwidth::decode(bandwidth, "opus_packet_get_bandwidth")
|
||||
}
|
||||
|
||||
/// Get the number of channels from an Opus packet.
|
||||
pub fn get_nb_channels(packet: &[u8]) -> Result<Channels> {
|
||||
if packet.len() < 1 {
|
||||
return Err(Error::bad_arg("opus_packet_get_nb_channels"));
|
||||
}
|
||||
let channels = ffi!(opus_packet_get_nb_channels, packet.as_ptr());
|
||||
match channels {
|
||||
1 => Ok(Channels::Mono),
|
||||
2 => Ok(Channels::Stereo),
|
||||
_ => Err(Error::bad_arg("opus_packet_get_nb_channels")),
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the number of frames in an Opus packet.
|
||||
pub fn get_nb_frames(packet: &[u8]) -> Result<usize> {
|
||||
let frames = ffi!(opus_packet_get_nb_frames, packet.as_ptr(), len(packet));
|
||||
Ok(frames as usize)
|
||||
}
|
||||
|
||||
/// Get the number of samples of an Opus packet.
|
||||
pub fn get_nb_samples(packet: &[u8], sample_rate: u32) -> Result<usize> {
|
||||
let frames = ffi!(opus_packet_get_nb_samples,
|
||||
packet.as_ptr(), len(packet),
|
||||
sample_rate as c_int);
|
||||
Ok(frames as usize)
|
||||
}
|
||||
|
||||
/// Get the number of samples per frame from an Opus packet.
|
||||
pub fn get_samples_per_frame(packet: &[u8], sample_rate: u32) -> Result<usize> {
|
||||
if packet.len() < 1 {
|
||||
return Err(Error::bad_arg("opus_packet_get_samples_per_frame"))
|
||||
}
|
||||
let samples = ffi!(opus_packet_get_samples_per_frame,
|
||||
packet.as_ptr(), sample_rate as c_int);
|
||||
Ok(samples as usize)
|
||||
}
|
||||
|
||||
/// Parse an Opus packet into one or more frames.
|
||||
pub fn parse(packet: &[u8]) -> Result<Packet> {
|
||||
let mut toc: u8 = 0;
|
||||
let mut frames = [ptr::null(); 48];
|
||||
let mut sizes = [0i16; 48];
|
||||
let mut payload_offset: i32 = 0;
|
||||
let num_frames = ffi!(opus_packet_parse,
|
||||
packet.as_ptr(), len(packet),
|
||||
&mut toc, frames.as_mut_ptr(),
|
||||
sizes.as_mut_ptr(), &mut payload_offset);
|
||||
|
||||
let mut frames_vec = Vec::with_capacity(num_frames as usize);
|
||||
for i in 0..num_frames as usize {
|
||||
frames_vec.push(unsafe { slice::from_raw_parts(frames[i], sizes[i] as usize) });
|
||||
}
|
||||
|
||||
Ok(Packet {
|
||||
toc: toc,
|
||||
frames: frames_vec,
|
||||
payload_offset: payload_offset as usize,
|
||||
})
|
||||
}
|
||||
|
||||
/// A parsed Opus packet, retuned from `parse`.
|
||||
#[derive(Debug)]
|
||||
pub struct Packet<'a> {
|
||||
/// The TOC byte of the packet.
|
||||
pub toc: u8,
|
||||
/// The frames contained in the packet.
|
||||
pub frames: Vec<&'a [u8]>,
|
||||
/// The offset into the packet at which the payload is located.
|
||||
pub payload_offset: usize,
|
||||
}
|
||||
|
||||
/// Pad a given Opus packet to a larger size.
|
||||
///
|
||||
/// The packet will be extended from the first `prev_len` bytes of the
|
||||
/// buffer into the rest of the available space.
|
||||
pub fn pad(packet: &mut [u8], prev_len: usize) -> Result<usize> {
|
||||
let result = ffi!(opus_packet_pad, packet.as_mut_ptr(),
|
||||
check_len(prev_len), len(packet));
|
||||
Ok(result as usize)
|
||||
}
|
||||
|
||||
/// Remove all padding from a given Opus packet and rewrite the TOC sequence
|
||||
/// to minimize space usage.
|
||||
pub fn unpad(packet: &mut [u8]) -> Result<usize> {
|
||||
let result = ffi!(opus_packet_unpad, packet.as_mut_ptr(), len(packet));
|
||||
Ok(result as usize)
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Float Soft Clipping
|
||||
|
||||
/// Soft-clipping to bring a float signal within the [-1,1] range.
|
||||
#[derive(Debug)]
|
||||
pub struct SoftClip {
|
||||
channels: Channels,
|
||||
memory: [f32; 2],
|
||||
}
|
||||
|
||||
impl SoftClip {
|
||||
/// Initialize a new soft-clipping state.
|
||||
pub fn new(channels: Channels) -> SoftClip {
|
||||
SoftClip { channels: channels, memory: [0.0; 2] }
|
||||
}
|
||||
|
||||
/// Apply soft-clipping to a float signal.
|
||||
pub fn apply(&mut self, signal: &mut [f32]) {
|
||||
unsafe { ffi::opus_pcm_soft_clip(
|
||||
signal.as_mut_ptr(),
|
||||
len(signal) / self.channels as c_int,
|
||||
self.channels as c_int,
|
||||
self.memory.as_mut_ptr()) };
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Repacketizer
|
||||
|
||||
/// A repacketizer used to merge together or split apart multiple Opus packets.
|
||||
#[derive(Debug)]
|
||||
pub struct Repacketizer {
|
||||
ptr: *mut ffi::OpusRepacketizer,
|
||||
}
|
||||
|
||||
impl Repacketizer {
|
||||
/// Create and initialize a repacketizer.
|
||||
pub fn new() -> Result<Repacketizer> {
|
||||
let ptr = unsafe { ffi::opus_repacketizer_create() };
|
||||
if ptr.is_null() {
|
||||
Err(Error::from_code("opus_repacketizer_create", ffi::OPUS_ALLOC_FAIL))
|
||||
} else {
|
||||
Ok(Repacketizer { ptr: ptr })
|
||||
}
|
||||
}
|
||||
|
||||
/// Shortcut to combine several smaller packets into one larger one.
|
||||
pub fn combine(&mut self, input: &[&[u8]], output: &mut [u8]) -> Result<usize> {
|
||||
let mut state = self.begin();
|
||||
for &packet in input {
|
||||
state.cat(packet)?;
|
||||
}
|
||||
state.out(output)
|
||||
}
|
||||
|
||||
/// Begin using the repacketizer.
|
||||
pub fn begin<'rp, 'buf>(&'rp mut self) -> RepacketizerState<'rp, 'buf> {
|
||||
unsafe { ffi::opus_repacketizer_init(self.ptr); }
|
||||
RepacketizerState { rp: self, phantom: PhantomData }
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Repacketizer {
|
||||
fn drop(&mut self) {
|
||||
unsafe { ffi::opus_repacketizer_destroy(self.ptr) }
|
||||
}
|
||||
}
|
||||
|
||||
// See `unsafe impl Send for Encoder`.
|
||||
unsafe impl Send for Repacketizer {}
|
||||
|
||||
// To understand why these lifetime bounds are needed, imagine that the
|
||||
// repacketizer keeps an internal Vec<&'buf [u8]>, which is added to by cat()
|
||||
// and accessed by get_nb_frames(), out(), and out_range(). To prove that these
|
||||
// lifetime bounds are correct, a dummy implementation with the same signatures
|
||||
// but a real Vec<&'buf [u8]> rather than unsafe blocks may be substituted.
|
||||
|
||||
/// An in-progress repacketization.
|
||||
#[derive(Debug)]
|
||||
pub struct RepacketizerState<'rp, 'buf> {
|
||||
rp: &'rp mut Repacketizer,
|
||||
phantom: PhantomData<&'buf [u8]>,
|
||||
}
|
||||
|
||||
impl<'rp, 'buf> RepacketizerState<'rp, 'buf> {
|
||||
/// Add a packet to the current repacketizer state.
|
||||
pub fn cat(&mut self, packet: &'buf [u8]) -> Result<()> {
|
||||
ffi!(opus_repacketizer_cat, self.rp.ptr,
|
||||
packet.as_ptr(), len(packet));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Add a packet to the current repacketizer state, moving it.
|
||||
#[inline]
|
||||
pub fn cat_move<'b2>(self, packet: &'b2 [u8]) -> Result<RepacketizerState<'rp, 'b2>> where 'buf: 'b2 {
|
||||
let mut shorter = self;
|
||||
shorter.cat(packet)?;
|
||||
Ok(shorter)
|
||||
}
|
||||
|
||||
/// Get the total number of frames contained in packet data submitted so
|
||||
/// far via `cat`.
|
||||
pub fn get_nb_frames(&mut self) -> usize {
|
||||
unsafe { ffi::opus_repacketizer_get_nb_frames(self.rp.ptr) as usize }
|
||||
}
|
||||
|
||||
/// Construct a new packet from data previously submitted via `cat`.
|
||||
///
|
||||
/// All previously submitted frames are used.
|
||||
pub fn out(&mut self, buffer: &mut [u8]) -> Result<usize> {
|
||||
let result = ffi!(opus_repacketizer_out, self.rp.ptr,
|
||||
buffer.as_mut_ptr(), len(buffer));
|
||||
Ok(result as usize)
|
||||
}
|
||||
|
||||
/// Construct a new packet from data previously submitted via `cat`, with
|
||||
/// a manually specified subrange.
|
||||
///
|
||||
/// The `end` index should not exceed the value of `get_nb_frames()`.
|
||||
pub fn out_range(&mut self, begin: usize, end: usize, buffer: &mut [u8]) -> Result<usize> {
|
||||
let result = ffi!(opus_repacketizer_out_range, self.rp.ptr,
|
||||
check_len(begin), check_len(end),
|
||||
buffer.as_mut_ptr(), len(buffer));
|
||||
Ok(result as usize)
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// TODO: Multistream API
|
||||
|
||||
// ============================================================================
|
||||
// Error Handling
|
||||
|
||||
/// Opus error Result alias.
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
||||
|
||||
/// An error generated by the Opus library.
|
||||
#[derive(Debug)]
|
||||
pub struct Error {
|
||||
function: &'static str,
|
||||
code: ErrorCode,
|
||||
}
|
||||
|
||||
impl Error {
|
||||
fn bad_arg(what: &'static str) -> Error {
|
||||
Error { function: what, code: ErrorCode::BadArg }
|
||||
}
|
||||
|
||||
fn from_code(what: &'static str, code: c_int) -> Error {
|
||||
Error { function: what, code: ErrorCode::from_int(code) }
|
||||
}
|
||||
|
||||
/// Get the name of the Opus function from which the error originated.
|
||||
#[inline]
|
||||
pub fn function(&self) -> &'static str { self.function }
|
||||
|
||||
/// Get a textual description of the error provided by Opus.
|
||||
#[inline]
|
||||
pub fn description(&self) -> &'static str { self.code.description() }
|
||||
|
||||
/// Get the Opus error code of the error.
|
||||
#[inline]
|
||||
pub fn code(&self) -> ErrorCode { self.code }
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
write!(f, "{}: {}", self.function, self.description())
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for Error {
|
||||
fn description(&self) -> &str {
|
||||
self.code.description()
|
||||
}
|
||||
}
|
||||
|
||||
fn check_len(val: usize) -> c_int {
|
||||
let len = val as c_int;
|
||||
if len as usize != val {
|
||||
panic!("length out of range: {}", val);
|
||||
}
|
||||
len
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn len<T>(slice: &[T]) -> c_int {
|
||||
check_len(slice.len())
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
#![allow(non_upper_case_globals)]
|
||||
#![allow(non_camel_case_types)]
|
||||
#![allow(non_snake_case)]
|
||||
#![allow(dead_code)]
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/opus_ffi.rs"));
|
||||
@@ -1,10 +0,0 @@
|
||||
extern crate opus;
|
||||
|
||||
fn main() {
|
||||
let mut rp = opus::Repacketizer::new().unwrap();
|
||||
let mut wip = rp.begin().cat_move(
|
||||
&[1, 2, 3]
|
||||
//~^ ERROR borrowed value does not live long enough
|
||||
).unwrap();
|
||||
wip.out(&mut []);
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
//! Test that supplying empty packets does forward error correction.
|
||||
|
||||
extern crate magnum_opus;
|
||||
use magnum_opus::*;
|
||||
|
||||
#[test]
|
||||
fn blah() {
|
||||
let mut magnum_opus = Decoder::new(48000, Channels::Mono).unwrap();
|
||||
|
||||
let mut output = vec![0i16; 5760];
|
||||
let size = magnum_opus.decode(&[], &mut output[..], true).unwrap();
|
||||
assert_eq!(size, 5760);
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
// Based on libmagnum_opus/tests/test_magnum_opus_padding.c
|
||||
|
||||
/* Check for overflow in reading the padding length.
|
||||
* http://lists.xiph.org/pipermail/magnum_opus/2012-November/001834.html
|
||||
*/
|
||||
|
||||
extern crate magnum_opus;
|
||||
|
||||
#[test]
|
||||
fn test_overflow() {
|
||||
const PACKETSIZE: usize = 16909318;
|
||||
const CHANNELS: magnum_opus::Channels = magnum_opus::Channels::Stereo;
|
||||
const FRAMESIZE: usize = 5760;
|
||||
|
||||
let mut input = vec![0xff; PACKETSIZE];
|
||||
let mut output = vec![0i16; FRAMESIZE * 2];
|
||||
|
||||
input[0] = 0xff;
|
||||
input[1] = 0x41;
|
||||
*input.last_mut().unwrap() = 0x0b;
|
||||
|
||||
let mut decoder = magnum_opus::Decoder::new(48000, CHANNELS).unwrap();
|
||||
let result = decoder.decode(&input[..], &mut output[..], false);
|
||||
drop(decoder);
|
||||
drop(input);
|
||||
drop(output);
|
||||
|
||||
assert_eq!(result.unwrap_err().code(), magnum_opus::ErrorCode::InvalidPacket);
|
||||
}
|
||||
@@ -1,127 +0,0 @@
|
||||
extern crate magnum_opus;
|
||||
|
||||
fn check_ascii(s: &str) -> &str {
|
||||
for &b in s.as_bytes() {
|
||||
assert!(b < 0x80, "Non-ASCII character in string");
|
||||
assert!(b > 0x00, "NUL in string")
|
||||
}
|
||||
std::str::from_utf8(s.as_bytes()).unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn strings_ascii() {
|
||||
use magnum_opus::ErrorCode::*;
|
||||
|
||||
println!("\nVersion: {}", check_ascii(magnum_opus::version()));
|
||||
|
||||
let codes = [BadArg, BufferTooSmall, InternalError, InvalidPacket,
|
||||
Unimplemented, InvalidState, AllocFail, Unknown];
|
||||
for &code in codes.iter() {
|
||||
println!("{:?}: {}", code, check_ascii(code.description()));
|
||||
}
|
||||
}
|
||||
|
||||
// 48000Hz * 1 channel * 20 ms / 1000
|
||||
const MONO_20MS: usize = 48000 * 1 * 20 / 1000;
|
||||
|
||||
#[test]
|
||||
fn encode_mono() {
|
||||
let mut encoder = magnum_opus::Encoder::new(48000, magnum_opus::Channels::Mono, magnum_opus::Application::Audio).unwrap();
|
||||
|
||||
let mut output = [0; 256];
|
||||
let len = encoder.encode(&[0_i16; MONO_20MS], &mut output).unwrap();
|
||||
assert_eq!(&output[..len], &[248, 255, 254]);
|
||||
|
||||
let len = encoder.encode(&[0_i16; MONO_20MS], &mut output).unwrap();
|
||||
assert_eq!(&output[..len], &[248, 255, 254]);
|
||||
|
||||
let len = encoder.encode(&[1_i16; MONO_20MS], &mut output).unwrap();
|
||||
assert!(len > 190 && len < 220);
|
||||
|
||||
let len = encoder.encode(&[0_i16; MONO_20MS], &mut output).unwrap();
|
||||
assert!(len > 170 && len < 190);
|
||||
|
||||
let myvec = encoder.encode_vec(&[1_i16; MONO_20MS], output.len()).unwrap();
|
||||
assert!(myvec.len() > 120 && myvec.len() < 140);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn encode_stereo() {
|
||||
let mut encoder = magnum_opus::Encoder::new(48000, magnum_opus::Channels::Stereo, magnum_opus::Application::Audio).unwrap();
|
||||
|
||||
let mut output = [0; 512];
|
||||
let len = encoder.encode(&[0_i16; 2 * MONO_20MS], &mut output).unwrap();
|
||||
assert_eq!(&output[..len], &[252, 255, 254]);
|
||||
|
||||
let len = encoder.encode(&[0_i16; 4 * MONO_20MS], &mut output).unwrap();
|
||||
assert_eq!(&output[..len], &[253, 255, 254, 255, 254]);
|
||||
|
||||
let len = encoder.encode(&[17_i16; 2 * MONO_20MS], &mut output).unwrap();
|
||||
assert!(len > 240);
|
||||
|
||||
let len = encoder.encode(&[0_i16; 2 * MONO_20MS], &mut output).unwrap();
|
||||
assert!(len > 240);
|
||||
|
||||
// Very small buffer should still succeed
|
||||
let len = encoder.encode(&[95_i16; 2 * MONO_20MS], &mut [0; 20]).unwrap();
|
||||
assert!(len <= 20);
|
||||
|
||||
let myvec = encoder.encode_vec(&[95_i16; 2 * MONO_20MS], 20).unwrap();
|
||||
assert!(myvec.len() <= 20);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn encode_bad_rate() {
|
||||
match magnum_opus::Encoder::new(48001, magnum_opus::Channels::Mono, magnum_opus::Application::Audio) {
|
||||
Ok(_) => panic!("Encoder::new did not return BadArg"),
|
||||
Err(err) => assert_eq!(err.code(), magnum_opus::ErrorCode::BadArg),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn encode_bad_buffer() {
|
||||
let mut encoder = magnum_opus::Encoder::new(48000, magnum_opus::Channels::Stereo, magnum_opus::Application::Audio).unwrap();
|
||||
match encoder.encode(&[1_i16; 2 * MONO_20MS], &mut [0; 0]) {
|
||||
Ok(_) => panic!("encode with 0-length buffer did not return BadArg"),
|
||||
Err(err) => assert_eq!(err.code(), magnum_opus::ErrorCode::BadArg),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn repacketizer() {
|
||||
let mut rp = magnum_opus::Repacketizer::new().unwrap();
|
||||
let mut out = [0; 256];
|
||||
|
||||
for _ in 0..2 {
|
||||
let packet1 = [249, 255, 254, 255, 254];
|
||||
let packet2 = [248, 255, 254];
|
||||
|
||||
let mut state = rp.begin();
|
||||
state.cat(&packet1).unwrap();
|
||||
state.cat(&packet2).unwrap();
|
||||
let len = state.out(&mut out).unwrap();
|
||||
assert_eq!(&out[..len], &[251, 3, 255, 254, 255, 254, 255, 254]);
|
||||
}
|
||||
for _ in 0..2 {
|
||||
let packet = [248, 255, 254];
|
||||
let state = rp.begin().cat_move(&packet).unwrap();
|
||||
let packet = [249, 255, 254, 255, 254];
|
||||
let state = state.cat_move(&packet).unwrap();
|
||||
let len = {state}.out(&mut out).unwrap();
|
||||
assert_eq!(&out[..len], &[251, 3, 255, 254, 255, 254, 255, 254]);
|
||||
}
|
||||
for _ in 0..2 {
|
||||
let len = rp.combine(&[
|
||||
&[249, 255, 254, 255, 254],
|
||||
&[248, 255, 254],
|
||||
], &mut out).unwrap();
|
||||
assert_eq!(&out[..len], &[251, 3, 255, 254, 255, 254, 255, 254]);
|
||||
}
|
||||
for _ in 0..2 {
|
||||
let len = rp.begin()
|
||||
.cat_move(&[248, 255, 254]).unwrap()
|
||||
.cat_move(&[248, 71, 71]).unwrap()
|
||||
.out(&mut out).unwrap();
|
||||
assert_eq!(&out[..len], &[249, 255, 254, 71, 71]);
|
||||
}
|
||||
}
|
||||
3
libs/parity-tokio-ipc/.gitignore
vendored
3
libs/parity-tokio-ipc/.gitignore
vendored
@@ -1,3 +0,0 @@
|
||||
target
|
||||
Cargo.lock
|
||||
.idea
|
||||
@@ -1,20 +0,0 @@
|
||||
language: rust
|
||||
rust:
|
||||
- stable
|
||||
- beta
|
||||
- nightly
|
||||
matrix:
|
||||
allow_failures:
|
||||
- rust: nightly
|
||||
after_success:
|
||||
- |-
|
||||
[ $TRAVIS_BRANCH = master ] &&
|
||||
[ $TRAVIS_PULL_REQUEST = false ] &&
|
||||
cargo doc --all --no-deps &&
|
||||
echo '<meta http-equiv=refresh content=0;url=parity_tokio_ipc/index.html>' > target/doc/index.html &&
|
||||
pip install --user ghp-import &&
|
||||
/home/travis/.local/bin/ghp-import -n target/doc &&
|
||||
git push -fq https://${TOKEN}@github.com/${TRAVIS_REPO_SLUG}.git gh-pages
|
||||
env:
|
||||
global:
|
||||
secure: eUHPLjVMSVclRcEgwgybIKZQJTBW8QDjcjgIsEhOHZn7Kpzw0+rwJVoKkvr/uqyJwyY7pHy36mWX31J8YDSbSiM3W8jXeI97sk+FTUkleqUffPzXnbnR1D4kHZlKndFIbcuO5Z+rtVgsAv5E/u1w9XR+mvgK2lfaIEay+26gBl6dl/1TxWvrwDBeMvfq1JGVDQH4Etubncpi3LSWhbRkie1AKnVnsDIY9sUYVKSnIqjxx0qW6Z7EiCdwZ8gf04LNnqyIoKDpyldotL+nJ67ZlVI2O2DrbOOt55nliFHsH4BcWZIZOyIAM4PxIwhDl8g9E55FLkkUX9VUpVtqjTu9RWkVl7rzyrSxLoBUEjguIPrpFWBwLo0FSDvplB2XCXt8x035Io5PEg6m5dVxx5iytTIbI6HQwcA0ESTuDPuAdRJMNvJS/9e2UzPukdYYaaxF6g8wSmiIQjLuZU/nGBdmAl7Uw6cFlQnyLc/GXQg0oZ+B/J8sc4W2C/Z64oB8jK72RLNTKeeWs/XSOt8NxQiNkWeFIhGqiYOPJgjBiTCLSKJPY3CUTiBT8QpAcpj1x1gsWi+5fRoXYxNig/CmeTwZjuxKNxfQIu3J+lJbNdt44x7whnwhZ/AKVuLFPNNiC2OBNpa738UY60VYDoNZyhomWSdBnz3E6i1VtdiSnujFFnc=
|
||||
@@ -1,24 +0,0 @@
|
||||
[package]
|
||||
name = "parity-tokio-ipc"
|
||||
version = "0.7.2"
|
||||
edition = "2018"
|
||||
authors = ["NikVolf <nikvolf@gmail.com>"]
|
||||
license = "MIT/Apache-2.0"
|
||||
readme = "README.md"
|
||||
repository = "https://github.com/nikvolf/parity-tokio-ipc"
|
||||
homepage = "https://github.com/nikvolf/parity-tokio-ipc"
|
||||
description = """
|
||||
Interprocess communication library for tokio.
|
||||
"""
|
||||
|
||||
[dependencies]
|
||||
futures = "0.3"
|
||||
log = "0.4"
|
||||
mio-named-pipes = "0.1"
|
||||
miow = "0.3"
|
||||
rand = "0.7"
|
||||
tokio = { version = "0.2", features = ["io-driver", "io-util", "uds", "stream", "rt-core", "macros", "time"] }
|
||||
libc = "0.2"
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
winapi = { version = "0.3", features = ["winbase", "winnt", "accctrl", "aclapi", "securitybaseapi", "minwinbase", "winbase"] }
|
||||
@@ -1,201 +0,0 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
@@ -1,25 +0,0 @@
|
||||
Copyright (c) 2017 Nikolay Volf
|
||||
|
||||
Permission is hereby granted, free of charge, to any
|
||||
person obtaining a copy of this software and associated
|
||||
documentation files (the "Software"), to deal in the
|
||||
Software without restriction, including without
|
||||
limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software
|
||||
is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice
|
||||
shall be included in all copies or substantial portions
|
||||
of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
||||
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
||||
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
@@ -1,28 +0,0 @@
|
||||
# parity-tokio-ipc
|
||||
|
||||
[](https://travis-ci.org/NikVolf/parity-tokio-ipc)
|
||||
|
||||
[Documentation](https://nikvolf.github.io/parity-tokio-ipc)
|
||||
|
||||
This crate abstracts interprocess transport for UNIX/Windows. On UNIX it utilizes unix sockets (`tokio_uds` crate) and named pipe on windows (experimental `tokio-named-pipes` crate).
|
||||
|
||||
Endpoint is transport-agnostic interface for incoming connections:
|
||||
```rust
|
||||
let endpoint = Endpoint::new(endpoint_addr, handle).unwrap();
|
||||
endpoint.incoming().for_each(|_| println!("Connection received!"));
|
||||
```
|
||||
|
||||
And IpcStream is transport-agnostic io:
|
||||
```rust
|
||||
let endpoint = Endpoint::new(endpoint_addr, handle).unwrap();
|
||||
endpoint.incoming().for_each(|(ipc_stream: IpcStream, _)| io::write_all(ipc_stream, b"Hello!"));
|
||||
```
|
||||
|
||||
|
||||
# License
|
||||
|
||||
`parity-tokio-ipc` is primarily distributed under the terms of both the MIT
|
||||
license and the Apache License (Version 2.0), with portions covered by various
|
||||
BSD-like licenses.
|
||||
|
||||
See LICENSE-APACHE, and LICENSE-MIT for details.
|
||||
@@ -1,16 +0,0 @@
|
||||
environment:
|
||||
matrix:
|
||||
- TARGET: x86_64-pc-windows-msvc
|
||||
|
||||
install:
|
||||
- curl -sSf -o rustup-init.exe https://win.rustup.rs/
|
||||
- rustup-init.exe -y --default-host %TARGET%
|
||||
- set PATH=%PATH%;C:\Users\appveyor\.cargo\bin;C:\MinGW\bin
|
||||
|
||||
- rustc -vV
|
||||
- cargo -vV
|
||||
|
||||
build: false
|
||||
|
||||
test_script:
|
||||
- cargo test
|
||||
@@ -1,24 +0,0 @@
|
||||
use tokio::{self, prelude::*};
|
||||
use parity_tokio_ipc::Endpoint;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
let path = std::env::args().nth(1).expect("Run it with server path to connect as argument");
|
||||
|
||||
let mut client = Endpoint::connect(&path).await
|
||||
.expect("Failed to connect client.");
|
||||
|
||||
loop {
|
||||
let mut buf = [0u8; 4];
|
||||
println!("SEND: PING");
|
||||
client.write_all(b"ping").await.expect("Unable to write message to client");
|
||||
client.read_exact(&mut buf[..]).await.expect("Unable to read buffer");
|
||||
if let Ok("pong") = std::str::from_utf8(&buf[..]) {
|
||||
println!("RECEIVED: PONG");
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
||||
tokio::time::delay_for(std::time::Duration::from_secs(2)).await;
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
use futures::StreamExt as _;
|
||||
use tokio::{
|
||||
prelude::*,
|
||||
self,
|
||||
io::split,
|
||||
};
|
||||
|
||||
use parity_tokio_ipc::{Endpoint, SecurityAttributes};
|
||||
|
||||
async fn run_server(path: String) {
|
||||
let mut endpoint = Endpoint::new(path);
|
||||
endpoint.set_security_attributes(SecurityAttributes::allow_everyone_create().unwrap());
|
||||
|
||||
let mut incoming = endpoint.incoming().expect("failed to open new socket");
|
||||
|
||||
while let Some(result) = incoming.next().await
|
||||
{
|
||||
match result {
|
||||
Ok(stream) => {
|
||||
let (mut reader, mut writer) = split(stream);
|
||||
|
||||
tokio::spawn(async move {
|
||||
loop {
|
||||
let mut buf = [0u8; 4];
|
||||
let pong_buf = b"pong";
|
||||
if let Err(_) = reader.read_exact(&mut buf).await {
|
||||
println!("Closing socket");
|
||||
break;
|
||||
}
|
||||
if let Ok("ping") = std::str::from_utf8(&buf[..]) {
|
||||
println!("RECIEVED: PING");
|
||||
writer.write_all(pong_buf).await.expect("unable to write to socket");
|
||||
println!("SEND: PONG");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
_ => unreachable!("ideally")
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
let path = std::env::args().nth(1).expect("Run it with server path as argument");
|
||||
run_server(path).await
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "Spawning 100 processes"
|
||||
for i in {1..100} ;
|
||||
do
|
||||
( cargo run --example client -- /tmp/test.ipc & )
|
||||
done
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user